Actual source code: finitevolume1d.c
1: #include "finitevolume1d.h"
2: #include <petscdmda.h>
3: #include <petscdraw.h>
4: #include <petsc/private/tsimpl.h>
6: #include <petsc/private/kernels/blockinvert.h>
7: const char *FVBCTypes[] = {"PERIODIC", "OUTFLOW", "INFLOW", "FVBCType", "FVBC_", 0};
9: static inline PetscReal Sgn(PetscReal a)
10: {
11: return (a < 0) ? -1 : 1;
12: }
13: static inline PetscReal Abs(PetscReal a)
14: {
15: return (a < 0) ? 0 : a;
16: }
17: static inline PetscReal Sqr(PetscReal a)
18: {
19: return a * a;
20: }
22: PETSC_UNUSED static inline PetscReal MinAbs(PetscReal a, PetscReal b)
23: {
24: return (PetscAbs(a) < PetscAbs(b)) ? a : b;
25: }
26: static inline PetscReal MinMod2(PetscReal a, PetscReal b)
27: {
28: return (a * b < 0) ? 0 : Sgn(a) * PetscMin(PetscAbs(a), PetscAbs(b));
29: }
30: static inline PetscReal MaxMod2(PetscReal a, PetscReal b)
31: {
32: return (a * b < 0) ? 0 : Sgn(a) * PetscMax(PetscAbs(a), PetscAbs(b));
33: }
34: static inline PetscReal MinMod3(PetscReal a, PetscReal b, PetscReal c)
35: {
36: return (a * b < 0 || a * c < 0) ? 0 : Sgn(a) * PetscMin(PetscAbs(a), PetscMin(PetscAbs(b), PetscAbs(c)));
37: }
39: /* ----------------------- Lots of limiters, these could go in a separate library ------------------------- */
40: void Limit_Upwind(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
41: {
42: PetscInt i;
43: for (i = 0; i < info->m; i++) lmt[i] = 0;
44: }
45: void Limit_LaxWendroff(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
46: {
47: PetscInt i;
48: for (i = 0; i < info->m; i++) lmt[i] = jR[i];
49: }
50: void Limit_BeamWarming(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
51: {
52: PetscInt i;
53: for (i = 0; i < info->m; i++) lmt[i] = jL[i];
54: }
55: void Limit_Fromm(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
56: {
57: PetscInt i;
58: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] + jR[i]);
59: }
60: void Limit_Minmod(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
61: {
62: PetscInt i;
63: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i], jR[i]);
64: }
65: void Limit_Superbee(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
66: {
67: PetscInt i;
68: for (i = 0; i < info->m; i++) lmt[i] = MaxMod2(MinMod2(jL[i], 2 * jR[i]), MinMod2(2 * jL[i], jR[i]));
69: }
70: void Limit_MC(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
71: {
72: PetscInt i;
73: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], 0.5 * (jL[i] + jR[i]), 2 * jR[i]);
74: }
75: void Limit_VanLeer(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
76: { /* phi = (t + abs(t)) / (1 + abs(t)) */
77: PetscInt i;
78: 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);
79: }
80: void Limit_VanAlbada(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt) /* differentiable */
81: { /* phi = (t + t^2) / (1 + t^2) */
82: PetscInt i;
83: 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);
84: }
85: void Limit_VanAlbadaTVD(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
86: { /* phi = (t + t^2) / (1 + t^2) */
87: PetscInt i;
88: 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);
89: }
90: void Limit_Koren(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt) /* differentiable */
91: { /* phi = (t + 2*t^2) / (2 - t + 2*t^2) */
92: PetscInt i;
93: 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));
94: }
95: void Limit_KorenSym(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt) /* differentiable */
96: { /* Symmetric version of above */
97: PetscInt i;
98: 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));
99: }
100: void Limit_Koren3(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
101: { /* Eq 11 of Cada-Torrilhon 2009 */
102: PetscInt i;
103: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], (jL[i] + 2 * jR[i]) / 3, 2 * jR[i]);
104: }
105: static PetscReal CadaTorrilhonPhiHatR_Eq13(PetscReal L, PetscReal R)
106: {
107: return PetscMax(0, PetscMin((L + 2 * R) / 3, PetscMax(-0.5 * L, PetscMin(2 * L, PetscMin((L + 2 * R) / 3, 1.6 * R)))));
108: }
109: void Limit_CadaTorrilhon2(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
110: { /* Cada-Torrilhon 2009, Eq 13 */
111: PetscInt i;
112: for (i = 0; i < info->m; i++) lmt[i] = CadaTorrilhonPhiHatR_Eq13(jL[i], jR[i]);
113: }
114: void Limit_CadaTorrilhon3R(PetscReal r, LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
115: { /* Cada-Torrilhon 2009, Eq 22 */
116: /* They recommend 0.001 < r < 1, but larger values are more accurate in smooth regions */
117: const PetscReal eps = 1e-7, hx = info->hx;
118: PetscInt i;
119: for (i = 0; i < info->m; i++) {
120: const PetscReal eta = (Sqr(jL[i]) + Sqr(jR[i])) / Sqr(r * hx);
121: 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]))));
122: }
123: }
124: void Limit_CadaTorrilhon3R0p1(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
125: {
126: Limit_CadaTorrilhon3R(0.1, info, jL, jR, lmt);
127: }
128: void Limit_CadaTorrilhon3R1(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
129: {
130: Limit_CadaTorrilhon3R(1, info, jL, jR, lmt);
131: }
132: void Limit_CadaTorrilhon3R10(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
133: {
134: Limit_CadaTorrilhon3R(10, info, jL, jR, lmt);
135: }
136: void Limit_CadaTorrilhon3R100(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
137: {
138: Limit_CadaTorrilhon3R(100, info, jL, jR, lmt);
139: }
141: /* ----------------------- Limiters for split systems ------------------------- */
143: void Limit2_Upwind(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sf, const PetscInt fs, PetscInt n, PetscScalar *lmt)
144: {
145: PetscInt i;
146: for (i = 0; i < info->m; i++) lmt[i] = 0;
147: }
148: void Limit2_LaxWendroff(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sf, const PetscInt fs, PetscInt n, PetscScalar *lmt)
149: {
150: PetscInt i;
151: if (n < sf - 1) { /* slow components */
152: for (i = 0; i < info->m; i++) lmt[i] = jR[i] / info->hxs;
153: } else if (n == sf - 1) { /* slow component which is next to fast components */
154: for (i = 0; i < info->m; i++) lmt[i] = jR[i] / (info->hxs / 2.0 + info->hxf / 2.0);
155: } else if (n == sf) { /* fast component which is next to slow components */
156: for (i = 0; i < info->m; i++) lmt[i] = jR[i] / info->hxf;
157: } else if (n > sf && n < fs - 1) { /* fast components */
158: for (i = 0; i < info->m; i++) lmt[i] = jR[i] / info->hxf;
159: } else if (n == fs - 1) { /* fast component next to slow components */
160: for (i = 0; i < info->m; i++) lmt[i] = jR[i] / (info->hxf / 2.0 + info->hxs / 2.0);
161: } else if (n == fs) { /* slow component next to fast components */
162: for (i = 0; i < info->m; i++) lmt[i] = jR[i] / info->hxs;
163: } else { /* slow components */
164: for (i = 0; i < info->m; i++) lmt[i] = jR[i] / info->hxs;
165: }
166: }
167: void Limit2_BeamWarming(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sf, const PetscInt fs, PetscInt n, PetscScalar *lmt)
168: {
169: PetscInt i;
170: if (n < sf - 1) {
171: for (i = 0; i < info->m; i++) lmt[i] = jL[i] / info->hxs;
172: } else if (n == sf - 1) {
173: for (i = 0; i < info->m; i++) lmt[i] = jL[i] / info->hxs;
174: } else if (n == sf) {
175: for (i = 0; i < info->m; i++) lmt[i] = jL[i] / (info->hxs / 2.0 + info->hxf / 2.0);
176: } else if (n > sf && n < fs - 1) {
177: for (i = 0; i < info->m; i++) lmt[i] = jL[i] / info->hxf;
178: } else if (n == fs - 1) {
179: for (i = 0; i < info->m; i++) lmt[i] = jL[i] / info->hxf;
180: } else if (n == fs) {
181: for (i = 0; i < info->m; i++) lmt[i] = jL[i] / (info->hxf / 2.0 + info->hxs / 2.0);
182: } else {
183: for (i = 0; i < info->m; i++) lmt[i] = jL[i] / info->hxs;
184: }
185: }
186: void Limit2_Fromm(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sf, const PetscInt fs, PetscInt n, PetscScalar *lmt)
187: {
188: PetscInt i;
189: if (n < sf - 1) {
190: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] + jR[i]) / info->hxs;
191: } else if (n == sf - 1) {
192: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] / info->hxs + jR[i] / (info->hxs / 2.0 + info->hxf / 2.0));
193: } else if (n == sf) {
194: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] / (info->hxs / 2.0 + info->hxf / 2.0) + jR[i] / info->hxf);
195: } else if (n > sf && n < fs - 1) {
196: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] + jR[i]) / info->hxf;
197: } else if (n == fs - 1) {
198: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] / info->hxf + jR[i] / (info->hxf / 2.0 + info->hxs / 2.0));
199: } else if (n == fs) {
200: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] / (info->hxf / 2.0 + info->hxs / 2.0) + jR[i] / info->hxs);
201: } else {
202: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] + jR[i]) / info->hxs;
203: }
204: }
205: void Limit2_Minmod(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sf, const PetscInt fs, PetscInt n, PetscScalar *lmt)
206: {
207: PetscInt i;
208: if (n < sf - 1) {
209: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i], jR[i]) / info->hxs;
210: } else if (n == sf - 1) {
211: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i] / info->hxs, jR[i] / (info->hxs / 2.0 + info->hxf / 2.0));
212: } else if (n == sf) {
213: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i] / (info->hxs / 2.0 + info->hxf / 2.0), jR[i] / info->hxf);
214: } else if (n > sf && n < fs - 1) {
215: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i], jR[i]) / info->hxf;
216: } else if (n == fs - 1) {
217: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i] / info->hxf, jR[i] / (info->hxf / 2.0 + info->hxs / 2.0));
218: } else if (n == fs) {
219: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i] / (info->hxf / 2.0 + info->hxs / 2.0), jR[i] / info->hxs);
220: } else {
221: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i], jR[i]) / info->hxs;
222: }
223: }
224: void Limit2_Superbee(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sf, const PetscInt fs, PetscInt n, PetscScalar *lmt)
225: {
226: PetscInt i;
227: if (n < sf - 1) {
228: for (i = 0; i < info->m; i++) lmt[i] = MaxMod2(MinMod2(jL[i], 2 * jR[i]), MinMod2(2 * jL[i], jR[i])) / info->hxs;
229: } else if (n == sf - 1) {
230: for (i = 0; i < info->m; i++) lmt[i] = MaxMod2(MinMod2(jL[i] / info->hxs, 2 * jR[i] / (info->hxs / 2.0 + info->hxf / 2.0)), MinMod2(2 * jL[i] / info->hxs, jR[i] / (info->hxs / 2.0 + info->hxf / 2.0)));
231: } else if (n == sf) {
232: for (i = 0; i < info->m; i++) lmt[i] = MaxMod2(MinMod2(jL[i] / (info->hxs / 2.0 + info->hxf / 2.0), 2 * jR[i] / info->hxf), MinMod2(2 * jL[i] / (info->hxs / 2.0 + info->hxf / 2.0), jR[i] / info->hxf));
233: } else if (n > sf && n < fs - 1) {
234: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(MinMod2(jL[i], 2 * jR[i]), MinMod2(2 * jL[i], jR[i])) / info->hxf;
235: } else if (n == fs - 1) {
236: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(MinMod2(jL[i] / info->hxf, 2 * jR[i] / (info->hxf / 2.0 + info->hxs / 2.0)), MinMod2(2 * jL[i] / info->hxf, jR[i] / (info->hxf / 2.0 + info->hxs / 2.0)));
237: } else if (n == fs) {
238: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(MinMod2(jL[i] / (info->hxf / 2.0 + info->hxs / 2.0), 2 * jR[i] / info->hxs), MinMod2(2 * jL[i] / (info->hxf / 2.0 + info->hxs / 2.0), jR[i] / info->hxs));
239: } else {
240: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(MinMod2(jL[i], 2 * jR[i]), MinMod2(2 * jL[i], jR[i])) / info->hxs;
241: }
242: }
243: void Limit2_MC(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sf, const PetscInt fs, PetscInt n, PetscScalar *lmt)
244: {
245: PetscInt i;
246: if (n < sf - 1) {
247: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], 0.5 * (jL[i] + jR[i]), 2 * jR[i]) / info->hxs;
248: } else if (n == sf - 1) {
249: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / info->hxs, 0.5 * (jL[i] / info->hxs + jR[i] / (info->hxf / 2.0 + info->hxs / 2.0)), 2 * jR[i] / (info->hxf / 2.0 + info->hxs / 2.0));
250: } else if (n == sf) {
251: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / (info->hxs / 2.0 + info->hxf / 2.0), 0.5 * (jL[i] / (info->hxs / 2.0 + info->hxf / 2.0) + jR[i] / info->hxf), 2 * jR[i] / info->hxf);
252: } else if (n > sf && n < fs - 1) {
253: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], 0.5 * (jL[i] + jR[i]), 2 * jR[i]) / info->hxf;
254: } else if (n == fs - 1) {
255: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / info->hxf, 0.5 * (jL[i] / info->hxf + jR[i] / (info->hxf / 2.0 + info->hxs / 2.0)), 2 * jR[i] / (info->hxf / 2.0 + info->hxs / 2.0));
256: } else if (n == fs) {
257: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / (info->hxf / 2.0 + info->hxs / 2.0), 0.5 * (jL[i] / (info->hxf / 2.0 + info->hxs / 2.0) + jR[i] / info->hxs), 2 * jR[i] / info->hxs);
258: } else {
259: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], 0.5 * (jL[i] + jR[i]), 2 * jR[i]) / info->hxs;
260: }
261: }
262: void Limit2_Koren3(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sf, const PetscInt fs, PetscInt n, PetscScalar *lmt)
263: { /* Eq 11 of Cada-Torrilhon 2009 */
264: PetscInt i;
265: if (n < sf - 1) {
266: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], (jL[i] + 2 * jR[i]) / 3, 2 * jR[i]) / info->hxs;
267: } else if (n == sf - 1) {
268: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / info->hxs, (jL[i] / info->hxs + 2 * jR[i] / (info->hxf / 2.0 + info->hxs / 2.0)) / 3, 2 * jR[i] / (info->hxf / 2.0 + info->hxs / 2.0));
269: } else if (n == sf) {
270: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / (info->hxs / 2.0 + info->hxf / 2.0), (jL[i] / (info->hxs / 2.0 + info->hxf / 2.0) + 2 * jR[i] / info->hxf) / 3, 2 * jR[i] / info->hxf);
271: } else if (n > sf && n < fs - 1) {
272: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], (jL[i] + 2 * jR[i]) / 3, 2 * jR[i]) / info->hxf;
273: } else if (n == fs - 1) {
274: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / info->hxf, (jL[i] / info->hxf + 2 * jR[i] / (info->hxf / 2.0 + info->hxs / 2.0)) / 3, 2 * jR[i] / (info->hxf / 2.0 + info->hxs / 2.0));
275: } else if (n == fs) {
276: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / (info->hxf / 2.0 + info->hxs / 2.0), (jL[i] / (info->hxf / 2.0 + info->hxs / 2.0) + 2 * jR[i] / info->hxs) / 3, 2 * jR[i] / info->hxs);
277: } else {
278: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], (jL[i] + 2 * jR[i]) / 3, 2 * jR[i]) / info->hxs;
279: }
280: }
282: /* ---- Three-way splitting ---- */
283: void Limit3_Upwind(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sm, const PetscInt mf, const PetscInt fm, const PetscInt ms, PetscInt n, PetscScalar *lmt)
284: {
285: PetscInt i;
286: for (i = 0; i < info->m; i++) lmt[i] = 0;
287: }
288: void Limit3_LaxWendroff(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sm, const PetscInt mf, const PetscInt fm, const PetscInt ms, PetscInt n, PetscScalar *lmt)
289: {
290: PetscInt i;
291: if (n < sm - 1 || n > ms) { /* slow components */
292: for (i = 0; i < info->m; i++) lmt[i] = jR[i] / info->hxs;
293: } else if (n == sm - 1 || n == ms - 1) { /* slow component which is next to medium components */
294: for (i = 0; i < info->m; i++) lmt[i] = jR[i] / (info->hxs / 2.0 + info->hxm / 2.0);
295: } else if (n < mf - 1 || n > fm) { /* medium components */
296: for (i = 0; i < info->m; i++) lmt[i] = jR[i] / info->hxm;
297: } else if (n == mf - 1 || n == fm) { /* medium component next to fast components */
298: for (i = 0; i < info->m; i++) lmt[i] = jR[i] / (info->hxm / 2.0 + info->hxf / 2.0);
299: } else { /* fast components */
300: for (i = 0; i < info->m; i++) lmt[i] = jR[i] / info->hxf;
301: }
302: }
303: void Limit3_BeamWarming(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sm, const PetscInt mf, const PetscInt fm, const PetscInt ms, PetscInt n, PetscScalar *lmt)
304: {
305: PetscInt i;
306: if (n < sm || n > ms) {
307: for (i = 0; i < info->m; i++) lmt[i] = jL[i] / info->hxs;
308: } else if (n == sm || n == ms) {
309: for (i = 0; i < info->m; i++) lmt[i] = jL[i] / (info->hxs / 2.0 + info->hxf / 2.0);
310: } else if (n < mf || n > fm) {
311: for (i = 0; i < info->m; i++) lmt[i] = jL[i] / info->hxm;
312: } else if (n == mf || n == fm) {
313: for (i = 0; i < info->m; i++) lmt[i] = jL[i] / (info->hxm / 2.0 + info->hxf / 2.0);
314: } else {
315: for (i = 0; i < info->m; i++) lmt[i] = jL[i] / info->hxf;
316: }
317: }
318: void Limit3_Fromm(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sm, const PetscInt mf, const PetscInt fm, const PetscInt ms, PetscInt n, PetscScalar *lmt)
319: {
320: PetscInt i;
321: if (n < sm - 1 || n > ms) {
322: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] + jR[i]) / info->hxs;
323: } else if (n == sm - 1) {
324: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] / info->hxs + jR[i] / (info->hxs / 2.0 + info->hxf / 2.0));
325: } else if (n == sm) {
326: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] / (info->hxs / 2.0 + info->hxm / 2.0) + jR[i] / info->hxm);
327: } else if (n == ms - 1) {
328: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] / info->hxm + jR[i] / (info->hxs / 2.0 + info->hxf / 2.0));
329: } else if (n == ms) {
330: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] / (info->hxm / 2.0 + info->hxs / 2.0) + jR[i] / info->hxs);
331: } else if (n < mf - 1 || n > fm) {
332: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] + jR[i]) / info->hxm;
333: } else if (n == mf - 1) {
334: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] / info->hxm + jR[i] / (info->hxm / 2.0 + info->hxf / 2.0));
335: } else if (n == mf) {
336: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] / (info->hxm / 2.0 + info->hxf / 2.0) + jR[i] / info->hxf);
337: } else if (n == fm - 1) {
338: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] / info->hxf + jR[i] / (info->hxf / 2.0 + info->hxm / 2.0));
339: } else if (n == fm) {
340: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] / (info->hxf / 2.0 + info->hxm / 2.0) + jR[i] / info->hxm);
341: } else {
342: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] + jR[i]) / info->hxf;
343: }
344: }
345: void Limit3_Minmod(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sm, const PetscInt mf, const PetscInt fm, const PetscInt ms, PetscInt n, PetscScalar *lmt)
346: {
347: PetscInt i;
348: if (n < sm - 1 || n > ms) {
349: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i], jR[i]) / info->hxs;
350: } else if (n == sm - 1) {
351: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i] / info->hxs, jR[i] / (info->hxs / 2.0 + info->hxf / 2.0));
352: } else if (n == sm) {
353: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i] / (info->hxs / 2.0 + info->hxf / 2.0), jR[i] / info->hxf);
354: } else if (n == ms - 1) {
355: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i] / info->hxm, jR[i] / (info->hxm / 2.0 + info->hxs / 2.0));
356: } else if (n == ms) {
357: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i] / (info->hxm / 2.0 + info->hxs / 2.0), jR[i] / info->hxs);
358: } else if (n < mf - 1 || n > fm) {
359: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i], jR[i]) / info->hxm;
360: } else if (n == mf - 1) {
361: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i] / info->hxm, jR[i] / (info->hxm / 2.0 + info->hxf / 2.0));
362: } else if (n == mf) {
363: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i] / (info->hxm / 2.0 + info->hxf / 2.0), jR[i] / info->hxf);
364: } else if (n == fm - 1) {
365: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i] / info->hxf, jR[i] / (info->hxf / 2.0 + info->hxm / 2.0));
366: } else if (n == fm) {
367: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i] / (info->hxf / 2.0 + info->hxm / 2.0), jR[i] / info->hxm);
368: } else {
369: for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] + jR[i]) / info->hxf;
370: }
371: }
372: void Limit3_Superbee(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sm, const PetscInt mf, const PetscInt fm, const PetscInt ms, PetscInt n, PetscScalar *lmt)
373: {
374: PetscInt i;
375: if (n < sm - 1 || n > ms) {
376: for (i = 0; i < info->m; i++) lmt[i] = MaxMod2(MinMod2(jL[i], 2 * jR[i]), MinMod2(2 * jL[i], jR[i])) / info->hxs;
377: } else if (n == sm - 1) {
378: for (i = 0; i < info->m; i++) lmt[i] = MaxMod2(MinMod2(jL[i] / info->hxs, 2 * jR[i] / (info->hxs / 2.0 + info->hxm / 2.0)), MinMod2(2 * jL[i] / info->hxs, jR[i] / (info->hxs / 2.0 + info->hxm / 2.0)));
379: } else if (n == sm) {
380: for (i = 0; i < info->m; i++) lmt[i] = MaxMod2(MinMod2(jL[i] / (info->hxs / 2.0 + info->hxm / 2.0), 2 * jR[i] / info->hxm), MinMod2(2 * jL[i] / (info->hxs / 2.0 + info->hxm / 2.0), jR[i] / info->hxm));
381: } else if (n == ms - 1) {
382: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(MinMod2(jL[i] / info->hxm, 2 * jR[i] / (info->hxm / 2.0 + info->hxs / 2.0)), MinMod2(2 * jL[i] / info->hxm, jR[i] / (info->hxm / 2.0 + info->hxs / 2.0)));
383: } else if (n == ms) {
384: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(MinMod2(jL[i] / (info->hxm / 2.0 + info->hxs / 2.0), 2 * jR[i] / info->hxs), MinMod2(2 * jL[i] / (info->hxm / 2.0 + info->hxs / 2.0), jR[i] / info->hxs));
385: } else if (n < mf - 1 || n > fm) {
386: for (i = 0; i < info->m; i++) lmt[i] = MaxMod2(MinMod2(jL[i], 2 * jR[i]), MinMod2(2 * jL[i], jR[i])) / info->hxm;
387: } else if (n == mf - 1) {
388: for (i = 0; i < info->m; i++) lmt[i] = MaxMod2(MinMod2(jL[i] / info->hxm, 2 * jR[i] / (info->hxm / 2.0 + info->hxf / 2.0)), MinMod2(2 * jL[i] / info->hxm, jR[i] / (info->hxm / 2.0 + info->hxf / 2.0)));
389: } else if (n == mf) {
390: for (i = 0; i < info->m; i++) lmt[i] = MaxMod2(MinMod2(jL[i] / (info->hxm / 2.0 + info->hxf / 2.0), 2 * jR[i] / info->hxf), MinMod2(2 * jL[i] / (info->hxm / 2.0 + info->hxf / 2.0), jR[i] / info->hxf));
391: } else if (n == fm - 1) {
392: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(MinMod2(jL[i] / info->hxf, 2 * jR[i] / (info->hxf / 2.0 + info->hxm / 2.0)), MinMod2(2 * jL[i] / info->hxf, jR[i] / (info->hxf / 2.0 + info->hxm / 2.0)));
393: } else if (n == fm) {
394: for (i = 0; i < info->m; i++) lmt[i] = MinMod2(MinMod2(jL[i] / (info->hxf / 2.0 + info->hxm / 2.0), 2 * jR[i] / info->hxm), MinMod2(2 * jL[i] / (info->hxf / 2.0 + info->hxm / 2.0), jR[i] / info->hxm));
395: } else {
396: for (i = 0; i < info->m; i++) lmt[i] = MaxMod2(MinMod2(jL[i], 2 * jR[i]), MinMod2(2 * jL[i], jR[i])) / info->hxf;
397: }
398: }
399: void Limit3_MC(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sm, const PetscInt mf, const PetscInt fm, const PetscInt ms, PetscInt n, PetscScalar *lmt)
400: {
401: PetscInt i;
402: if (n < sm - 1 || n > ms) {
403: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], 0.5 * (jL[i] + jR[i]), 2 * jR[i]) / info->hxs;
404: } else if (n == sm - 1) {
405: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / info->hxs, 0.5 * (jL[i] / info->hxs + jR[i] / (info->hxs / 2.0 + info->hxm / 2.0)), 2 * jR[i] / (info->hxs / 2.0 + info->hxm / 2.0));
406: } else if (n == sm) {
407: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / (info->hxs / 2.0 + info->hxm / 2.0), 0.5 * (jL[i] / (info->hxs / 2.0 + info->hxm / 2.0) + jR[i] / info->hxm), 2 * jR[i] / info->hxm);
408: } else if (n == ms - 1) {
409: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / info->hxm, 0.5 * (jL[i] / info->hxm + jR[i] / (info->hxm / 2.0 + info->hxs / 2.0)), 2 * jR[i] / (info->hxm / 2.0 + info->hxs / 2.0));
410: } else if (n == ms) {
411: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / (info->hxm / 2.0 + info->hxs / 2.0), 0.5 * (jL[i] / (info->hxm / 2.0 + info->hxs / 2.0) + jR[i] / info->hxs), 2 * jR[i] / info->hxs);
412: } else if (n < mf - 1 || n > fm) {
413: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], 0.5 * (jL[i] + jR[i]), 2 * jR[i]) / info->hxm;
414: } else if (n == mf - 1) {
415: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / info->hxm, 0.5 * (jL[i] / info->hxm + jR[i] / (info->hxm / 2.0 + info->hxf / 2.0)), 2 * jR[i] / (info->hxm / 2.0 + info->hxf / 2.0));
416: } else if (n == mf) {
417: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / (info->hxm / 2.0 + info->hxf / 2.0), 0.5 * (jL[i] / (info->hxm / 2.0 + info->hxf / 2.0) + jR[i] / info->hxf), 2 * jR[i] / info->hxf);
418: } else if (n == fm - 1) {
419: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / info->hxf, 0.5 * (jL[i] / info->hxf + jR[i] / (info->hxf / 2.0 + info->hxm / 2.0)), 2 * jR[i] / (info->hxf / 2.0 + info->hxm / 2.0));
420: } else if (n == fm) {
421: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / (info->hxf / 2.0 + info->hxm / 2.0), 0.5 * (jL[i] / (info->hxf / 2.0 + info->hxm / 2.0) + jR[i] / info->hxm), 2 * jR[i] / info->hxm);
422: } else {
423: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], 0.5 * (jL[i] + jR[i]), 2 * jR[i]) / info->hxf;
424: }
425: }
426: void Limit3_Koren3(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, const PetscInt sm, const PetscInt mf, const PetscInt fm, const PetscInt ms, PetscInt n, PetscScalar *lmt)
427: { /* Eq 11 of Cada-Torrilhon 2009 */
428: PetscInt i;
429: if (n < sm - 1 || n > ms) {
430: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], (jL[i] + 2 * jR[i]) / 3, 2 * jR[i]) / info->hxs;
431: } else if (n == sm - 1) {
432: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / info->hxs, (jL[i] / info->hxs + 2 * jR[i] / (info->hxm / 2.0 + info->hxs / 2.0)) / 3, 2 * jR[i] / (info->hxm / 2.0 + info->hxs / 2.0));
433: } else if (n == sm) {
434: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / (info->hxs / 2.0 + info->hxm / 2.0), (jL[i] / (info->hxs / 2.0 + info->hxm / 2.0) + 2 * jR[i] / info->hxm) / 3, 2 * jR[i] / info->hxm);
435: } else if (n == ms - 1) {
436: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / info->hxm, (jL[i] / info->hxm + 2 * jR[i] / (info->hxm / 2.0 + info->hxs / 2.0)) / 3, 2 * jR[i] / (info->hxm / 2.0 + info->hxs / 2.0));
437: } else if (n == ms) {
438: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / (info->hxm / 2.0 + info->hxs / 2.0), (jL[i] / (info->hxm / 2.0 + info->hxs / 2.0) + 2 * jR[i] / info->hxs) / 3, 2 * jR[i] / info->hxs);
439: } else if (n < mf - 1 || n > fm) {
440: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], (jL[i] + 2 * jR[i]) / 3, 2 * jR[i]) / info->hxm;
441: } else if (n == mf - 1) {
442: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / info->hxm, (jL[i] / info->hxm + 2 * jR[i] / (info->hxm / 2.0 + info->hxf / 2.0)) / 3, 2 * jR[i] / (info->hxm / 2.0 + info->hxf / 2.0));
443: } else if (n == mf) {
444: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / (info->hxm / 2.0 + info->hxf / 2.0), (jL[i] / (info->hxm / 2.0 + info->hxf / 2.0) + 2 * jR[i] / info->hxf) / 3, 2 * jR[i] / info->hxf);
445: } else if (n == fm - 1) {
446: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / info->hxf, (jL[i] / info->hxf + 2 * jR[i] / (info->hxf / 2.0 + info->hxm / 2.0)) / 3, 2 * jR[i] / (info->hxf / 2.0 + info->hxm / 2.0));
447: } else if (n == fm) {
448: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i] / (info->hxf / 2.0 + info->hxm / 2.0), (jL[i] / (info->hxf / 2.0 + info->hxm / 2.0) + 2 * jR[i] / info->hxm) / 3, 2 * jR[i] / info->hxm);
449: } else {
450: for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], (jL[i] + 2 * jR[i]) / 3, 2 * jR[i]) / info->hxs;
451: }
452: }
454: PetscErrorCode RiemannListAdd(PetscFunctionList *flist, const char *name, RiemannFunction rsolve)
455: {
456: PetscFunctionBeginUser;
457: PetscCall(PetscFunctionListAdd(flist, name, rsolve));
458: PetscFunctionReturn(PETSC_SUCCESS);
459: }
461: PetscErrorCode RiemannListFind(PetscFunctionList flist, const char *name, RiemannFunction *rsolve)
462: {
463: PetscFunctionBeginUser;
464: PetscCall(PetscFunctionListFind(flist, name, rsolve));
465: PetscCheck(*rsolve, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Riemann solver \"%s\" could not be found", name);
466: PetscFunctionReturn(PETSC_SUCCESS);
467: }
469: PetscErrorCode ReconstructListAdd(PetscFunctionList *flist, const char *name, ReconstructFunction r)
470: {
471: PetscFunctionBeginUser;
472: PetscCall(PetscFunctionListAdd(flist, name, r));
473: PetscFunctionReturn(PETSC_SUCCESS);
474: }
476: PetscErrorCode ReconstructListFind(PetscFunctionList flist, const char *name, ReconstructFunction *r)
477: {
478: PetscFunctionBeginUser;
479: PetscCall(PetscFunctionListFind(flist, name, r));
480: PetscCheck(*r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Reconstruction \"%s\" could not be found", name);
481: PetscFunctionReturn(PETSC_SUCCESS);
482: }
484: PetscErrorCode RiemannListAdd_2WaySplit(PetscFunctionList *flist, const char *name, RiemannFunction_2WaySplit rsolve)
485: {
486: PetscFunctionBeginUser;
487: PetscCall(PetscFunctionListAdd(flist, name, rsolve));
488: PetscFunctionReturn(PETSC_SUCCESS);
489: }
491: PetscErrorCode RiemannListFind_2WaySplit(PetscFunctionList flist, const char *name, RiemannFunction_2WaySplit *rsolve)
492: {
493: PetscFunctionBeginUser;
494: PetscCall(PetscFunctionListFind(flist, name, rsolve));
495: PetscCheck(*rsolve, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Riemann solver \"%s\" could not be found", name);
496: PetscFunctionReturn(PETSC_SUCCESS);
497: }
499: PetscErrorCode ReconstructListAdd_2WaySplit(PetscFunctionList *flist, const char *name, ReconstructFunction_2WaySplit r)
500: {
501: PetscFunctionBeginUser;
502: PetscCall(PetscFunctionListAdd(flist, name, r));
503: PetscFunctionReturn(PETSC_SUCCESS);
504: }
506: PetscErrorCode ReconstructListFind_2WaySplit(PetscFunctionList flist, const char *name, ReconstructFunction_2WaySplit *r)
507: {
508: PetscFunctionBeginUser;
509: PetscCall(PetscFunctionListFind(flist, name, r));
510: PetscCheck(*r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Reconstruction \"%s\" could not be found", name);
511: PetscFunctionReturn(PETSC_SUCCESS);
512: }
514: /* --------------------------------- Physics ------- */
515: PetscErrorCode PhysicsDestroy_SimpleFree(void *vctx)
516: {
517: PetscFunctionBeginUser;
518: PetscCall(PetscFree(vctx));
519: PetscFunctionReturn(PETSC_SUCCESS);
520: }
522: /* --------------------------------- Finite Volume Solver --------------- */
523: PetscErrorCode FVRHSFunction(TS ts, PetscReal time, Vec X, Vec F, void *vctx)
524: {
525: FVCtx *ctx = (FVCtx *)vctx;
526: PetscInt i, j, k, Mx, dof, xs, xm;
527: PetscReal hx, cfl_idt = 0;
528: PetscScalar *x, *f, *slope;
529: Vec Xloc;
530: DM da;
532: PetscFunctionBeginUser;
533: PetscCall(TSGetDM(ts, &da));
534: PetscCall(DMGetLocalVector(da, &Xloc)); /* Xloc contains ghost points */
535: PetscCall(DMDAGetInfo(da, 0, &Mx, 0, 0, 0, 0, 0, &dof, 0, 0, 0, 0, 0)); /* Mx is the number of center points */
536: hx = (ctx->xmax - ctx->xmin) / Mx;
537: PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, Xloc)); /* X is solution vector which does not contain ghost points */
538: PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, Xloc));
539: PetscCall(VecZeroEntries(F)); /* F is the right-hand side function corresponds to center points */
540: PetscCall(DMDAVecGetArray(da, Xloc, &x));
541: PetscCall(DMDAVecGetArray(da, F, &f));
542: PetscCall(DMDAGetArray(da, PETSC_TRUE, &slope)); /* contains ghost points */
543: PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));
545: if (ctx->bctype == FVBC_OUTFLOW) {
546: for (i = xs - 2; i < 0; i++) {
547: for (j = 0; j < dof; j++) x[i * dof + j] = x[j];
548: }
549: for (i = Mx; i < xs + xm + 2; i++) {
550: for (j = 0; j < dof; j++) x[i * dof + j] = x[(xs + xm - 1) * dof + j];
551: }
552: }
554: for (i = xs - 1; i < xs + xm + 1; i++) {
555: struct _LimitInfo info;
556: PetscScalar *cjmpL, *cjmpR;
557: /* Determine the right eigenvectors R, where A = R \Lambda R^{-1} */
558: PetscCall((*ctx->physics.characteristic)(ctx->physics.user, dof, &x[i * dof], ctx->R, ctx->Rinv, ctx->speeds, ctx->xmin + hx * i));
559: /* Evaluate jumps across interfaces (i-1, i) and (i, i+1), put in characteristic basis */
560: PetscCall(PetscArrayzero(ctx->cjmpLR, 2 * dof));
561: cjmpL = &ctx->cjmpLR[0];
562: cjmpR = &ctx->cjmpLR[dof];
563: for (j = 0; j < dof; j++) {
564: PetscScalar jmpL, jmpR;
565: jmpL = x[(i + 0) * dof + j] - x[(i - 1) * dof + j];
566: jmpR = x[(i + 1) * dof + j] - x[(i + 0) * dof + j];
567: for (k = 0; k < dof; k++) {
568: cjmpL[k] += ctx->Rinv[k + j * dof] * jmpL;
569: cjmpR[k] += ctx->Rinv[k + j * dof] * jmpR;
570: }
571: }
572: /* Apply limiter to the left and right characteristic jumps */
573: info.m = dof;
574: info.hx = hx;
575: (*ctx->limit)(&info, cjmpL, cjmpR, ctx->cslope);
576: for (j = 0; j < dof; j++) ctx->cslope[j] /= hx; /* rescale to a slope */
577: for (j = 0; j < dof; j++) {
578: PetscScalar tmp = 0;
579: for (k = 0; k < dof; k++) tmp += ctx->R[j + k * dof] * ctx->cslope[k];
580: slope[i * dof + j] = tmp;
581: }
582: }
584: for (i = xs; i < xs + xm + 1; i++) {
585: PetscReal maxspeed;
586: PetscScalar *uL, *uR;
587: uL = &ctx->uLR[0];
588: uR = &ctx->uLR[dof];
589: for (j = 0; j < dof; j++) {
590: uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hx / 2;
591: uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hx / 2;
592: }
593: PetscCall((*ctx->physics.riemann)(ctx->physics.user, dof, uL, uR, ctx->flux, &maxspeed, ctx->xmin + hx * i, ctx->xmin, ctx->xmax));
594: cfl_idt = PetscMax(cfl_idt, PetscAbsScalar(maxspeed / hx)); /* Max allowable value of 1/Delta t */
595: if (i > xs) {
596: for (j = 0; j < dof; j++) f[(i - 1) * dof + j] -= ctx->flux[j] / hx;
597: }
598: if (i < xs + xm) {
599: for (j = 0; j < dof; j++) f[i * dof + j] += ctx->flux[j] / hx;
600: }
601: }
602: PetscCall(DMDAVecRestoreArray(da, Xloc, &x));
603: PetscCall(DMDAVecRestoreArray(da, F, &f));
604: PetscCall(DMDARestoreArray(da, PETSC_TRUE, &slope));
605: PetscCall(DMRestoreLocalVector(da, &Xloc));
606: PetscCallMPI(MPIU_Allreduce(&cfl_idt, &ctx->cfl_idt, 1, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)da)));
607: if (0) {
608: /* We need to a way to inform the TS of a CFL constraint, this is a debugging fragment */
609: PetscReal dt, tnow;
610: PetscCall(TSGetTimeStep(ts, &dt));
611: PetscCall(TSGetTime(ts, &tnow));
612: if (dt > 0.5 / ctx->cfl_idt) {
613: if (1) {
614: PetscCall(PetscPrintf(ctx->comm, "Stability constraint exceeded at t=%g, dt %g > %g\n", (double)tnow, (double)dt, (double)(1 / (2 * ctx->cfl_idt))));
615: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Stability constraint exceeded, %g > %g", (double)dt, (double)(ctx->cfl / ctx->cfl_idt));
616: }
617: }
618: PetscFunctionReturn(PETSC_SUCCESS);
619: }
621: PetscErrorCode FVSample(FVCtx *ctx, DM da, PetscReal time, Vec U)
622: {
623: PetscScalar *u, *uj;
624: PetscInt i, j, k, dof, xs, xm, Mx;
626: PetscFunctionBeginUser;
627: PetscCheck(ctx->physics.sample, PETSC_COMM_SELF, PETSC_ERR_SUP, "Physics has not provided a sampling function");
628: PetscCall(DMDAGetInfo(da, 0, &Mx, 0, 0, 0, 0, 0, &dof, 0, 0, 0, 0, 0));
629: PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));
630: PetscCall(DMDAVecGetArray(da, U, &u));
631: PetscCall(PetscMalloc1(dof, &uj));
632: for (i = xs; i < xs + xm; i++) {
633: const PetscReal h = (ctx->xmax - ctx->xmin) / Mx, xi = ctx->xmin + h / 2 + i * h;
634: const PetscInt N = 200;
635: /* Integrate over cell i using trapezoid rule with N points. */
636: for (k = 0; k < dof; k++) u[i * dof + k] = 0;
637: for (j = 0; j < N + 1; j++) {
638: PetscScalar xj = xi + h * (j - N / 2) / (PetscReal)N;
639: PetscCall((*ctx->physics.sample)(ctx->physics.user, ctx->initial, ctx->bctype, ctx->xmin, ctx->xmax, time, xj, uj));
640: for (k = 0; k < dof; k++) u[i * dof + k] += ((j == 0 || j == N) ? 0.5 : 1.0) * uj[k] / N;
641: }
642: }
643: PetscCall(DMDAVecRestoreArray(da, U, &u));
644: PetscCall(PetscFree(uj));
645: PetscFunctionReturn(PETSC_SUCCESS);
646: }
648: PetscErrorCode SolutionStatsView(DM da, Vec X, PetscViewer viewer)
649: {
650: PetscReal xmin, xmax;
651: PetscScalar sum, tvsum, tvgsum;
652: const PetscScalar *x;
653: PetscInt imin, imax, Mx, i, j, xs, xm, dof;
654: Vec Xloc;
655: PetscBool iascii;
657: PetscFunctionBeginUser;
658: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
659: if (iascii) {
660: /* PETSc lacks a function to compute total variation norm (difficult in multiple dimensions), we do it here */
661: PetscCall(DMGetLocalVector(da, &Xloc));
662: PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, Xloc));
663: PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, Xloc));
664: PetscCall(DMDAVecGetArrayRead(da, Xloc, (void *)&x));
665: PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));
666: PetscCall(DMDAGetInfo(da, 0, &Mx, 0, 0, 0, 0, 0, &dof, 0, 0, 0, 0, 0));
667: tvsum = 0;
668: for (i = xs; i < xs + xm; i++) {
669: for (j = 0; j < dof; j++) tvsum += PetscAbsScalar(x[i * dof + j] - x[(i - 1) * dof + j]);
670: }
671: PetscCallMPI(MPIU_Allreduce(&tvsum, &tvgsum, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)da)));
672: PetscCall(DMDAVecRestoreArrayRead(da, Xloc, (void *)&x));
673: PetscCall(DMRestoreLocalVector(da, &Xloc));
674: PetscCall(VecMin(X, &imin, &xmin));
675: PetscCall(VecMax(X, &imax, &xmax));
676: PetscCall(VecSum(X, &sum));
677: PetscCall(PetscViewerASCIIPrintf(viewer, "Solution range [%8.5f,%8.5f] with minimum at %" PetscInt_FMT ", mean %8.5f, ||x||_TV %8.5f\n", (double)xmin, (double)xmax, imin, (double)(sum / Mx), (double)(tvgsum / Mx)));
678: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Viewer type not supported");
679: PetscFunctionReturn(PETSC_SUCCESS);
680: }