xref: /petsc/src/ts/impls/implicit/glle/glle.c (revision a16fd2c93c02146fccd68469496ac02ca99b9ebe)
1 
2 #include <../src/ts/impls/implicit/glle/glle.h> /*I   "petscts.h"   I*/
3 #include <petscdm.h>
4 #include <petscblaslapack.h>
5 
6 static const char       *TSGLLEErrorDirections[] = {"FORWARD", "BACKWARD", "TSGLLEErrorDirection", "TSGLLEERROR_", NULL};
7 static PetscFunctionList TSGLLEList;
8 static PetscFunctionList TSGLLEAcceptList;
9 static PetscBool         TSGLLEPackageInitialized;
10 static PetscBool         TSGLLERegisterAllCalled;
11 
12 /* This function is pure */
13 static PetscScalar Factorial(PetscInt n) {
14   PetscInt i;
15   if (n < 12) { /* Can compute with 32-bit integers */
16     PetscInt f = 1;
17     for (i = 2; i <= n; i++) f *= i;
18     return (PetscScalar)f;
19   } else {
20     PetscScalar f = 1.;
21     for (i = 2; i <= n; i++) f *= (PetscScalar)i;
22     return f;
23   }
24 }
25 
26 /* This function is pure */
27 static PetscScalar CPowF(PetscScalar c, PetscInt p) {
28   return PetscPowRealInt(PetscRealPart(c), p) / Factorial(p);
29 }
30 
31 static PetscErrorCode TSGLLEGetVecs(TS ts, DM dm, Vec *Z, Vec *Ydotstage) {
32   TS_GLLE *gl = (TS_GLLE *)ts->data;
33 
34   PetscFunctionBegin;
35   if (Z) {
36     if (dm && dm != ts->dm) {
37       PetscCall(DMGetNamedGlobalVector(dm, "TSGLLE_Z", Z));
38     } else *Z = gl->Z;
39   }
40   if (Ydotstage) {
41     if (dm && dm != ts->dm) {
42       PetscCall(DMGetNamedGlobalVector(dm, "TSGLLE_Ydot", Ydotstage));
43     } else *Ydotstage = gl->Ydot[gl->stage];
44   }
45   PetscFunctionReturn(0);
46 }
47 
48 static PetscErrorCode TSGLLERestoreVecs(TS ts, DM dm, Vec *Z, Vec *Ydotstage) {
49   PetscFunctionBegin;
50   if (Z) {
51     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSGLLE_Z", Z));
52   }
53   if (Ydotstage) {
54     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSGLLE_Ydot", Ydotstage));
55   }
56   PetscFunctionReturn(0);
57 }
58 
59 static PetscErrorCode DMCoarsenHook_TSGLLE(DM fine, DM coarse, void *ctx) {
60   PetscFunctionBegin;
61   PetscFunctionReturn(0);
62 }
63 
64 static PetscErrorCode DMRestrictHook_TSGLLE(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse, void *ctx) {
65   TS  ts = (TS)ctx;
66   Vec Ydot, Ydot_c;
67 
68   PetscFunctionBegin;
69   PetscCall(TSGLLEGetVecs(ts, fine, NULL, &Ydot));
70   PetscCall(TSGLLEGetVecs(ts, coarse, NULL, &Ydot_c));
71   PetscCall(MatRestrict(restrct, Ydot, Ydot_c));
72   PetscCall(VecPointwiseMult(Ydot_c, rscale, Ydot_c));
73   PetscCall(TSGLLERestoreVecs(ts, fine, NULL, &Ydot));
74   PetscCall(TSGLLERestoreVecs(ts, coarse, NULL, &Ydot_c));
75   PetscFunctionReturn(0);
76 }
77 
78 static PetscErrorCode DMSubDomainHook_TSGLLE(DM dm, DM subdm, void *ctx) {
79   PetscFunctionBegin;
80   PetscFunctionReturn(0);
81 }
82 
83 static PetscErrorCode DMSubDomainRestrictHook_TSGLLE(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx) {
84   TS  ts = (TS)ctx;
85   Vec Ydot, Ydot_s;
86 
87   PetscFunctionBegin;
88   PetscCall(TSGLLEGetVecs(ts, dm, NULL, &Ydot));
89   PetscCall(TSGLLEGetVecs(ts, subdm, NULL, &Ydot_s));
90 
91   PetscCall(VecScatterBegin(gscat, Ydot, Ydot_s, INSERT_VALUES, SCATTER_FORWARD));
92   PetscCall(VecScatterEnd(gscat, Ydot, Ydot_s, INSERT_VALUES, SCATTER_FORWARD));
93 
94   PetscCall(TSGLLERestoreVecs(ts, dm, NULL, &Ydot));
95   PetscCall(TSGLLERestoreVecs(ts, subdm, NULL, &Ydot_s));
96   PetscFunctionReturn(0);
97 }
98 
99 static PetscErrorCode TSGLLESchemeCreate(PetscInt p, PetscInt q, PetscInt r, PetscInt s, const PetscScalar *c, const PetscScalar *a, const PetscScalar *b, const PetscScalar *u, const PetscScalar *v, TSGLLEScheme *inscheme) {
100   TSGLLEScheme scheme;
101   PetscInt     j;
102 
103   PetscFunctionBegin;
104   PetscCheck(p >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Scheme order must be positive");
105   PetscCheck(r >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "At least one item must be carried between steps");
106   PetscCheck(s >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "At least one stage is required");
107   PetscValidPointer(inscheme, 10);
108   *inscheme = NULL;
109   PetscCall(PetscNew(&scheme));
110   scheme->p = p;
111   scheme->q = q;
112   scheme->r = r;
113   scheme->s = s;
114 
115   PetscCall(PetscMalloc5(s, &scheme->c, s * s, &scheme->a, r * s, &scheme->b, r * s, &scheme->u, r * r, &scheme->v));
116   PetscCall(PetscArraycpy(scheme->c, c, s));
117   for (j = 0; j < s * s; j++) scheme->a[j] = (PetscAbsScalar(a[j]) < 1e-12) ? 0 : a[j];
118   for (j = 0; j < r * s; j++) scheme->b[j] = (PetscAbsScalar(b[j]) < 1e-12) ? 0 : b[j];
119   for (j = 0; j < s * r; j++) scheme->u[j] = (PetscAbsScalar(u[j]) < 1e-12) ? 0 : u[j];
120   for (j = 0; j < r * r; j++) scheme->v[j] = (PetscAbsScalar(v[j]) < 1e-12) ? 0 : v[j];
121 
122   PetscCall(PetscMalloc6(r, &scheme->alpha, r, &scheme->beta, r, &scheme->gamma, 3 * s, &scheme->phi, 3 * r, &scheme->psi, r, &scheme->stage_error));
123   {
124     PetscInt     i, j, k, ss = s + 2;
125     PetscBLASInt m, n, one = 1, *ipiv, lwork = 4 * ((s + 3) * 3 + 3), info, ldb;
126     PetscReal    rcond, *sing, *workreal;
127     PetscScalar *ImV, *H, *bmat, *workscalar, *c = scheme->c, *a = scheme->a, *b = scheme->b, *u = scheme->u, *v = scheme->v;
128     PetscBLASInt rank;
129     PetscCall(PetscMalloc7(PetscSqr(r), &ImV, 3 * s, &H, 3 * ss, &bmat, lwork, &workscalar, 5 * (3 + r), &workreal, r + s, &sing, r + s, &ipiv));
130 
131     /* column-major input */
132     for (i = 0; i < r - 1; i++) {
133       for (j = 0; j < r - 1; j++) ImV[i + j * r] = 1.0 * (i == j) - v[(i + 1) * r + j + 1];
134     }
135     /* Build right hand side for alpha (tp - glm.B(2:end,:)*(glm.c.^(p)./factorial(p))) */
136     for (i = 1; i < r; i++) {
137       scheme->alpha[i] = 1. / Factorial(p + 1 - i);
138       for (j = 0; j < s; j++) scheme->alpha[i] -= b[i * s + j] * CPowF(c[j], p);
139     }
140     PetscCall(PetscBLASIntCast(r - 1, &m));
141     PetscCall(PetscBLASIntCast(r, &n));
142     PetscCallBLAS("LAPACKgesv", LAPACKgesv_(&m, &one, ImV, &n, ipiv, scheme->alpha + 1, &n, &info));
143     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GESV");
144     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_MAT_LU_ZRPVT, "Bad LU factorization");
145 
146     /* Build right hand side for beta (tp1 - glm.B(2:end,:)*(glm.c.^(p+1)./factorial(p+1)) - e.alpha) */
147     for (i = 1; i < r; i++) {
148       scheme->beta[i] = 1. / Factorial(p + 2 - i) - scheme->alpha[i];
149       for (j = 0; j < s; j++) scheme->beta[i] -= b[i * s + j] * CPowF(c[j], p + 1);
150     }
151     PetscCallBLAS("LAPACKgetrs", LAPACKgetrs_("No transpose", &m, &one, ImV, &n, ipiv, scheme->beta + 1, &n, &info));
152     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GETRS");
153     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Should not happen");
154 
155     /* Build stage_error vector
156            xi = glm.c.^(p+1)/factorial(p+1) - glm.A*glm.c.^p/factorial(p) + glm.U(:,2:end)*e.alpha;
157     */
158     for (i = 0; i < s; i++) {
159       scheme->stage_error[i] = CPowF(c[i], p + 1);
160       for (j = 0; j < s; j++) scheme->stage_error[i] -= a[i * s + j] * CPowF(c[j], p);
161       for (j = 1; j < r; j++) scheme->stage_error[i] += u[i * r + j] * scheme->alpha[j];
162     }
163 
164     /* alpha[0] (epsilon in B,J,W 2007)
165            epsilon = 1/factorial(p+1) - B(1,:)*c.^p/factorial(p) + V(1,2:end)*e.alpha;
166     */
167     scheme->alpha[0] = 1. / Factorial(p + 1);
168     for (j = 0; j < s; j++) scheme->alpha[0] -= b[0 * s + j] * CPowF(c[j], p);
169     for (j = 1; j < r; j++) scheme->alpha[0] += v[0 * r + j] * scheme->alpha[j];
170 
171     /* right hand side for gamma (glm.B(2:end,:)*e.xi - e.epsilon*eye(s-1,1)) */
172     for (i = 1; i < r; i++) {
173       scheme->gamma[i] = (i == 1 ? -1. : 0) * scheme->alpha[0];
174       for (j = 0; j < s; j++) scheme->gamma[i] += b[i * s + j] * scheme->stage_error[j];
175     }
176     PetscCallBLAS("LAPACKgetrs", LAPACKgetrs_("No transpose", &m, &one, ImV, &n, ipiv, scheme->gamma + 1, &n, &info));
177     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GETRS");
178     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Should not happen");
179 
180     /* beta[0] (rho in B,J,W 2007)
181         e.rho = 1/factorial(p+2) - glm.B(1,:)*glm.c.^(p+1)/factorial(p+1) ...
182             + glm.V(1,2:end)*e.beta;% - e.epsilon;
183     % Note: The paper (B,J,W 2007) includes the last term in their definition
184     * */
185     scheme->beta[0] = 1. / Factorial(p + 2);
186     for (j = 0; j < s; j++) scheme->beta[0] -= b[0 * s + j] * CPowF(c[j], p + 1);
187     for (j = 1; j < r; j++) scheme->beta[0] += v[0 * r + j] * scheme->beta[j];
188 
189     /* gamma[0] (sigma in B,J,W 2007)
190     *   e.sigma = glm.B(1,:)*e.xi + glm.V(1,2:end)*e.gamma;
191     * */
192     scheme->gamma[0] = 0.0;
193     for (j = 0; j < s; j++) scheme->gamma[0] += b[0 * s + j] * scheme->stage_error[j];
194     for (j = 1; j < r; j++) scheme->gamma[0] += v[0 * s + j] * scheme->gamma[j];
195 
196     /* Assemble H
197     *    % " PetscInt_FMT "etermine the error estimators phi
198        H = [[cpow(glm.c,p) + C*e.alpha] [cpow(glm.c,p+1) + C*e.beta] ...
199                [e.xi - C*(e.gamma + 0*e.epsilon*eye(s-1,1))]]';
200     % Paper has formula above without the 0, but that term must be left
201     % out to satisfy the conditions they propose and to make the
202     % example schemes work
203     e.H = H;
204     e.phi = (H \ [1 0 0;1 1 0;0 0 -1])';
205     e.psi = -e.phi*C;
206     * */
207     for (j = 0; j < s; j++) {
208       H[0 + j * 3] = CPowF(c[j], p);
209       H[1 + j * 3] = CPowF(c[j], p + 1);
210       H[2 + j * 3] = scheme->stage_error[j];
211       for (k = 1; k < r; k++) {
212         H[0 + j * 3] += CPowF(c[j], k - 1) * scheme->alpha[k];
213         H[1 + j * 3] += CPowF(c[j], k - 1) * scheme->beta[k];
214         H[2 + j * 3] -= CPowF(c[j], k - 1) * scheme->gamma[k];
215       }
216     }
217     bmat[0 + 0 * ss] = 1.;
218     bmat[0 + 1 * ss] = 0.;
219     bmat[0 + 2 * ss] = 0.;
220     bmat[1 + 0 * ss] = 1.;
221     bmat[1 + 1 * ss] = 1.;
222     bmat[1 + 2 * ss] = 0.;
223     bmat[2 + 0 * ss] = 0.;
224     bmat[2 + 1 * ss] = 0.;
225     bmat[2 + 2 * ss] = -1.;
226     m                = 3;
227     PetscCall(PetscBLASIntCast(s, &n));
228     PetscCall(PetscBLASIntCast(ss, &ldb));
229     rcond = 1e-12;
230 #if defined(PETSC_USE_COMPLEX)
231     /* ZGELSS( M, N, NRHS, A, LDA, B, LDB, S, RCOND, RANK, WORK, LWORK, RWORK, INFO) */
232     PetscCallBLAS("LAPACKgelss", LAPACKgelss_(&m, &n, &m, H, &m, bmat, &ldb, sing, &rcond, &rank, workscalar, &lwork, workreal, &info));
233 #else
234     /* DGELSS( M, N, NRHS, A, LDA, B, LDB, S, RCOND, RANK, WORK, LWORK, INFO) */
235     PetscCallBLAS("LAPACKgelss", LAPACKgelss_(&m, &n, &m, H, &m, bmat, &ldb, sing, &rcond, &rank, workscalar, &lwork, &info));
236 #endif
237     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GELSS");
238     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "SVD failed to converge");
239 
240     for (j = 0; j < 3; j++) {
241       for (k = 0; k < s; k++) scheme->phi[k + j * s] = bmat[k + j * ss];
242     }
243 
244     /* the other part of the error estimator, psi in B,J,W 2007 */
245     scheme->psi[0 * r + 0] = 0.;
246     scheme->psi[1 * r + 0] = 0.;
247     scheme->psi[2 * r + 0] = 0.;
248     for (j = 1; j < r; j++) {
249       scheme->psi[0 * r + j] = 0.;
250       scheme->psi[1 * r + j] = 0.;
251       scheme->psi[2 * r + j] = 0.;
252       for (k = 0; k < s; k++) {
253         scheme->psi[0 * r + j] -= CPowF(c[k], j - 1) * scheme->phi[0 * s + k];
254         scheme->psi[1 * r + j] -= CPowF(c[k], j - 1) * scheme->phi[1 * s + k];
255         scheme->psi[2 * r + j] -= CPowF(c[k], j - 1) * scheme->phi[2 * s + k];
256       }
257     }
258     PetscCall(PetscFree7(ImV, H, bmat, workscalar, workreal, sing, ipiv));
259   }
260   /* Check which properties are satisfied */
261   scheme->stiffly_accurate = PETSC_TRUE;
262   if (scheme->c[s - 1] != 1.) scheme->stiffly_accurate = PETSC_FALSE;
263   for (j = 0; j < s; j++)
264     if (a[(s - 1) * s + j] != b[j]) scheme->stiffly_accurate = PETSC_FALSE;
265   for (j = 0; j < r; j++)
266     if (u[(s - 1) * r + j] != v[j]) scheme->stiffly_accurate = PETSC_FALSE;
267   scheme->fsal = scheme->stiffly_accurate; /* FSAL is stronger */
268   for (j = 0; j < s - 1; j++)
269     if (r > 1 && b[1 * s + j] != 0.) scheme->fsal = PETSC_FALSE;
270   if (b[1 * s + r - 1] != 1.) scheme->fsal = PETSC_FALSE;
271   for (j = 0; j < r; j++)
272     if (r > 1 && v[1 * r + j] != 0.) scheme->fsal = PETSC_FALSE;
273 
274   *inscheme = scheme;
275   PetscFunctionReturn(0);
276 }
277 
278 static PetscErrorCode TSGLLESchemeDestroy(TSGLLEScheme sc) {
279   PetscFunctionBegin;
280   PetscCall(PetscFree5(sc->c, sc->a, sc->b, sc->u, sc->v));
281   PetscCall(PetscFree6(sc->alpha, sc->beta, sc->gamma, sc->phi, sc->psi, sc->stage_error));
282   PetscCall(PetscFree(sc));
283   PetscFunctionReturn(0);
284 }
285 
286 static PetscErrorCode TSGLLEDestroy_Default(TS_GLLE *gl) {
287   PetscInt i;
288 
289   PetscFunctionBegin;
290   for (i = 0; i < gl->nschemes; i++) {
291     if (gl->schemes[i]) PetscCall(TSGLLESchemeDestroy(gl->schemes[i]));
292   }
293   PetscCall(PetscFree(gl->schemes));
294   gl->nschemes = 0;
295   PetscCall(PetscMemzero(gl->type_name, sizeof(gl->type_name)));
296   PetscFunctionReturn(0);
297 }
298 
299 static PetscErrorCode TSGLLEViewTable_Private(PetscViewer viewer, PetscInt m, PetscInt n, const PetscScalar a[], const char name[]) {
300   PetscBool iascii;
301   PetscInt  i, j;
302 
303   PetscFunctionBegin;
304   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
305   if (iascii) {
306     PetscCall(PetscViewerASCIIPrintf(viewer, "%30s = [", name));
307     for (i = 0; i < m; i++) {
308       if (i) PetscCall(PetscViewerASCIIPrintf(viewer, "%30s   [", ""));
309       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
310       for (j = 0; j < n; j++) PetscCall(PetscViewerASCIIPrintf(viewer, " %12.8g", (double)PetscRealPart(a[i * n + j])));
311       PetscCall(PetscViewerASCIIPrintf(viewer, "]\n"));
312       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
313     }
314   }
315   PetscFunctionReturn(0);
316 }
317 
318 static PetscErrorCode TSGLLESchemeView(TSGLLEScheme sc, PetscBool view_details, PetscViewer viewer) {
319   PetscBool iascii;
320 
321   PetscFunctionBegin;
322   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
323   if (iascii) {
324     PetscCall(PetscViewerASCIIPrintf(viewer, "GL scheme p,q,r,s = %" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT "\n", sc->p, sc->q, sc->r, sc->s));
325     PetscCall(PetscViewerASCIIPushTab(viewer));
326     PetscCall(PetscViewerASCIIPrintf(viewer, "Stiffly accurate: %s,  FSAL: %s\n", sc->stiffly_accurate ? "yes" : "no", sc->fsal ? "yes" : "no"));
327     PetscCall(PetscViewerASCIIPrintf(viewer, "Leading error constants: %10.3e  %10.3e  %10.3e\n", (double)PetscRealPart(sc->alpha[0]), (double)PetscRealPart(sc->beta[0]), (double)PetscRealPart(sc->gamma[0])));
328     PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->s, sc->c, "Abscissas c"));
329     if (view_details) {
330       PetscCall(TSGLLEViewTable_Private(viewer, sc->s, sc->s, sc->a, "A"));
331       PetscCall(TSGLLEViewTable_Private(viewer, sc->r, sc->s, sc->b, "B"));
332       PetscCall(TSGLLEViewTable_Private(viewer, sc->s, sc->r, sc->u, "U"));
333       PetscCall(TSGLLEViewTable_Private(viewer, sc->r, sc->r, sc->v, "V"));
334 
335       PetscCall(TSGLLEViewTable_Private(viewer, 3, sc->s, sc->phi, "Error estimate phi"));
336       PetscCall(TSGLLEViewTable_Private(viewer, 3, sc->r, sc->psi, "Error estimate psi"));
337       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->r, sc->alpha, "Modify alpha"));
338       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->r, sc->beta, "Modify beta"));
339       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->r, sc->gamma, "Modify gamma"));
340       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->s, sc->stage_error, "Stage error xi"));
341     }
342     PetscCall(PetscViewerASCIIPopTab(viewer));
343   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Viewer type %s not supported", ((PetscObject)viewer)->type_name);
344   PetscFunctionReturn(0);
345 }
346 
347 static PetscErrorCode TSGLLEEstimateHigherMoments_Default(TSGLLEScheme sc, PetscReal h, Vec Ydot[], Vec Xold[], Vec hm[]) {
348   PetscInt i;
349 
350   PetscFunctionBegin;
351   PetscCheck(sc->r <= 64 && sc->s <= 64, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Ridiculous number of stages or items passed between stages");
352   /* build error vectors*/
353   for (i = 0; i < 3; i++) {
354     PetscScalar phih[64];
355     PetscInt    j;
356     for (j = 0; j < sc->s; j++) phih[j] = sc->phi[i * sc->s + j] * h;
357     PetscCall(VecZeroEntries(hm[i]));
358     PetscCall(VecMAXPY(hm[i], sc->s, phih, Ydot));
359     PetscCall(VecMAXPY(hm[i], sc->r, &sc->psi[i * sc->r], Xold));
360   }
361   PetscFunctionReturn(0);
362 }
363 
364 static PetscErrorCode TSGLLECompleteStep_Rescale(TSGLLEScheme sc, PetscReal h, TSGLLEScheme next_sc, PetscReal next_h, Vec Ydot[], Vec Xold[], Vec X[]) {
365   PetscScalar brow[32], vrow[32];
366   PetscInt    i, j, r, s;
367 
368   PetscFunctionBegin;
369   /* Build the new solution from (X,Ydot) */
370   r = sc->r;
371   s = sc->s;
372   for (i = 0; i < r; i++) {
373     PetscCall(VecZeroEntries(X[i]));
374     for (j = 0; j < s; j++) brow[j] = h * sc->b[i * s + j];
375     PetscCall(VecMAXPY(X[i], s, brow, Ydot));
376     for (j = 0; j < r; j++) vrow[j] = sc->v[i * r + j];
377     PetscCall(VecMAXPY(X[i], r, vrow, Xold));
378   }
379   PetscFunctionReturn(0);
380 }
381 
382 static PetscErrorCode TSGLLECompleteStep_RescaleAndModify(TSGLLEScheme sc, PetscReal h, TSGLLEScheme next_sc, PetscReal next_h, Vec Ydot[], Vec Xold[], Vec X[]) {
383   PetscScalar brow[32], vrow[32];
384   PetscReal   ratio;
385   PetscInt    i, j, p, r, s;
386 
387   PetscFunctionBegin;
388   /* Build the new solution from (X,Ydot) */
389   p     = sc->p;
390   r     = sc->r;
391   s     = sc->s;
392   ratio = next_h / h;
393   for (i = 0; i < r; i++) {
394     PetscCall(VecZeroEntries(X[i]));
395     for (j = 0; j < s; j++) {
396       brow[j] = h * (PetscPowRealInt(ratio, i) * sc->b[i * s + j] + (PetscPowRealInt(ratio, i) - PetscPowRealInt(ratio, p + 1)) * (+sc->alpha[i] * sc->phi[0 * s + j]) + (PetscPowRealInt(ratio, i) - PetscPowRealInt(ratio, p + 2)) * (+sc->beta[i] * sc->phi[1 * s + j] + sc->gamma[i] * sc->phi[2 * s + j]));
397     }
398     PetscCall(VecMAXPY(X[i], s, brow, Ydot));
399     for (j = 0; j < r; j++) {
400       vrow[j] = (PetscPowRealInt(ratio, i) * sc->v[i * r + j] + (PetscPowRealInt(ratio, i) - PetscPowRealInt(ratio, p + 1)) * (+sc->alpha[i] * sc->psi[0 * r + j]) + (PetscPowRealInt(ratio, i) - PetscPowRealInt(ratio, p + 2)) * (+sc->beta[i] * sc->psi[1 * r + j] + sc->gamma[i] * sc->psi[2 * r + j]));
401     }
402     PetscCall(VecMAXPY(X[i], r, vrow, Xold));
403   }
404   if (r < next_sc->r) {
405     PetscCheck(r + 1 == next_sc->r, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot accommodate jump in r greater than 1");
406     PetscCall(VecZeroEntries(X[r]));
407     for (j = 0; j < s; j++) brow[j] = h * PetscPowRealInt(ratio, p + 1) * sc->phi[0 * s + j];
408     PetscCall(VecMAXPY(X[r], s, brow, Ydot));
409     for (j = 0; j < r; j++) vrow[j] = PetscPowRealInt(ratio, p + 1) * sc->psi[0 * r + j];
410     PetscCall(VecMAXPY(X[r], r, vrow, Xold));
411   }
412   PetscFunctionReturn(0);
413 }
414 
415 static PetscErrorCode TSGLLECreate_IRKS(TS ts) {
416   TS_GLLE *gl = (TS_GLLE *)ts->data;
417 
418   PetscFunctionBegin;
419   gl->Destroy               = TSGLLEDestroy_Default;
420   gl->EstimateHigherMoments = TSGLLEEstimateHigherMoments_Default;
421   gl->CompleteStep          = TSGLLECompleteStep_RescaleAndModify;
422   PetscCall(PetscMalloc1(10, &gl->schemes));
423   gl->nschemes = 0;
424 
425   {
426     /* p=1,q=1, r=s=2, A- and L-stable with error estimates of order 2 and 3
427     * Listed in Butcher & Podhaisky 2006. On error estimation in general linear methods for stiff ODE.
428     * irks(0.3,0,[.3,1],[1],1)
429     * Note: can be made to have classical order (not stage order) 2 by replacing 0.3 with 1-sqrt(1/2)
430     * but doing so would sacrifice the error estimator.
431     */
432     const PetscScalar c[2]    = {3. / 10., 1.};
433     const PetscScalar a[2][2] = {
434       {3. / 10., 0       },
435       {7. / 10., 3. / 10.}
436     };
437     const PetscScalar b[2][2] = {
438       {7. / 10., 3. / 10.},
439       {0,        1       }
440     };
441     const PetscScalar u[2][2] = {
442       {1, 0},
443       {1, 0}
444     };
445     const PetscScalar v[2][2] = {
446       {1, 0},
447       {0, 0}
448     };
449     PetscCall(TSGLLESchemeCreate(1, 1, 2, 2, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
450   }
451 
452   {
453     /* p=q=2, r=s=3: irks(4/9,0,[1:3]/3,[0.33852],1) */
454     /* http://www.math.auckland.ac.nz/~hpod/atlas/i2a.html */
455     const PetscScalar c[3]    = {1. / 3., 2. / 3., 1};
456     const PetscScalar a[3][3] = {
457       {4. / 9.,              0,                     0      },
458       {1.03750643704090e+00, 4. / 9.,               0      },
459       {7.67024779410304e-01, -3.81140216918943e-01, 4. / 9.}
460     };
461     const PetscScalar b[3][3] = {
462       {0.767024779410304,  -0.381140216918943, 4. / 9.          },
463       {0.000000000000000,  0.000000000000000,  1.000000000000000},
464       {-2.075048385225385, 0.621728385225383,  1.277197204924873}
465     };
466     const PetscScalar u[3][3] = {
467       {1.0000000000000000, -0.1111111111111109, -0.0925925925925922},
468       {1.0000000000000000, -0.8152842148186744, -0.4199095530877056},
469       {1.0000000000000000, 0.1696709930641948,  0.0539741070314165 }
470     };
471     const PetscScalar v[3][3] = {
472       {1.0000000000000000, 0.1696709930641948, 0.0539741070314165},
473       {0.000000000000000,  0.000000000000000,  0.000000000000000 },
474       {0.000000000000000,  0.176122795075129,  0.000000000000000 }
475     };
476     PetscCall(TSGLLESchemeCreate(2, 2, 3, 3, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
477   }
478   {
479     /* p=q=3, r=s=4: irks(9/40,0,[1:4]/4,[0.3312 1.0050],[0.49541 1;1 0]) */
480     const PetscScalar c[4]    = {0.25, 0.5, 0.75, 1.0};
481     const PetscScalar a[4][4] = {
482       {9. / 40.,             0,                     0,                 0       },
483       {2.11286958887701e-01, 9. / 40.,              0,                 0       },
484       {9.46338294287584e-01, -3.42942861246094e-01, 9. / 40.,          0       },
485       {0.521490453970721,    -0.662474225622980,    0.490476425459734, 9. / 40.}
486     };
487     const PetscScalar b[4][4] = {
488       {0.521490453970721,  -0.662474225622980, 0.490476425459734,  9. / 40.         },
489       {0.000000000000000,  0.000000000000000,  0.000000000000000,  1.000000000000000},
490       {-0.084677029310348, 1.390757514776085,  -1.568157386206001, 2.023192696767826},
491       {0.465383797936408,  1.478273530625148,  -1.930836081010182, 1.644872111193354}
492     };
493     const PetscScalar u[4][4] = {
494       {1.00000000000000000, 0.02500000000001035,  -0.02499999999999053, -0.00442708333332865},
495       {1.00000000000000000, 0.06371304111232945,  -0.04032173972189845, -0.01389438413189452},
496       {1.00000000000000000, -0.07839543304147778, 0.04738685705116663,  0.02032603595928376 },
497       {1.00000000000000000, 0.42550734619251651,  0.10800718022400080,  -0.01726712647760034}
498     };
499     const PetscScalar v[4][4] = {
500       {1.00000000000000000, 0.42550734619251651, 0.10800718022400080, -0.01726712647760034},
501       {0.000000000000000,   0.000000000000000,   0.000000000000000,   0.000000000000000   },
502       {0.000000000000000,   -1.761115796027561,  -0.521284157173780,  0.258249384305463   },
503       {0.000000000000000,   -1.657693358744728,  -1.052227765232394,  0.521284157173780   }
504     };
505     PetscCall(TSGLLESchemeCreate(3, 3, 4, 4, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
506   }
507   {
508     /* p=q=4, r=s=5:
509           irks(3/11,0,[1:5]/5, [0.1715   -0.1238    0.6617],...
510           [ -0.0812    0.4079    1.0000
511              1.0000         0         0
512              0.8270    1.0000         0])
513     */
514     const PetscScalar c[5]    = {0.2, 0.4, 0.6, 0.8, 1.0};
515     const PetscScalar a[5][5] = {
516       {2.72727272727352e-01,  0.00000000000000e+00,  0.00000000000000e+00,  0.00000000000000e+00, 0.00000000000000e+00},
517       {-1.03980153733431e-01, 2.72727272727405e-01,  0.00000000000000e+00,  0.00000000000000e+00, 0.00000000000000e+00},
518       {-1.58615400341492e+00, 7.44168951881122e-01,  2.72727272727309e-01,  0.00000000000000e+00, 0.00000000000000e+00},
519       {-8.73658042865628e-01, 5.37884671894595e-01,  -1.63298538799523e-01, 2.72727272726996e-01, 0.00000000000000e+00},
520       {2.95489397443992e-01,  -1.18481693910097e+00, -6.68029812659953e-01, 1.00716687860943e+00, 2.72727272727288e-01}
521     };
522     const PetscScalar b[5][5] = {
523       {2.95489397443992e-01,  -1.18481693910097e+00, -6.68029812659953e-01, 1.00716687860943e+00,  2.72727272727288e-01},
524       {0.00000000000000e+00,  1.11022302462516e-16,  -2.22044604925031e-16, 0.00000000000000e+00,  1.00000000000000e+00},
525       {-4.05882503986005e+00, -4.00924006567769e+00, -1.38930610972481e+00, 4.45223930308488e+00,  6.32331093108427e-01},
526       {8.35690179937017e+00,  -2.26640927349732e+00, 6.86647884973826e+00,  -5.22595158025740e+00, 4.50893068837431e+00},
527       {1.27656267027479e+01,  2.80882153840821e+00,  8.91173096522890e+00,  -1.07936444078906e+01, 4.82534148988854e+00}
528     };
529     const PetscScalar u[5][5] = {
530       {1.00000000000000e+00, -7.27272727273551e-02, -3.45454545454419e-02, -4.12121212119565e-03, -2.96969696964014e-04},
531       {1.00000000000000e+00, 2.31252881006154e-01,  -8.29487834416481e-03, -9.07191207681020e-03, -1.70378403743473e-03},
532       {1.00000000000000e+00, 1.16925777880663e+00,  3.59268562942635e-02,  -4.09013451730615e-02, -1.02411119670164e-02},
533       {1.00000000000000e+00, 1.02634463704356e+00,  1.59375044913405e-01,  1.89673015035370e-03,  -4.89987231897569e-03},
534       {1.00000000000000e+00, 1.27746320298021e+00,  2.37186008132728e-01,  -8.28694373940065e-02, -5.34396510196430e-02}
535     };
536     const PetscScalar v[5][5] = {
537       {1.00000000000000e+00, 1.27746320298021e+00,  2.37186008132728e-01,  -8.28694373940065e-02, -5.34396510196430e-02},
538       {0.00000000000000e+00, -1.77635683940025e-15, -1.99840144432528e-15, -9.99200722162641e-16, -3.33066907387547e-16},
539       {0.00000000000000e+00, 4.37280081906924e+00,  5.49221645016377e-02,  -8.88913177394943e-02, 1.12879077989154e-01 },
540       {0.00000000000000e+00, -1.22399504837280e+01, -5.21287338448645e+00, -8.03952325565291e-01, 4.60298678047147e-01 },
541       {0.00000000000000e+00, -1.85178762883829e+01, -5.21411849862624e+00, -1.04283436528809e+00, 7.49030161063651e-01 }
542     };
543     PetscCall(TSGLLESchemeCreate(4, 4, 5, 5, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
544   }
545   {
546     /* p=q=5, r=s=6;
547        irks(1/3,0,[1:6]/6,...
548           [-0.0489    0.4228   -0.8814    0.9021],...
549           [-0.3474   -0.6617    0.6294    0.2129
550             0.0044   -0.4256   -0.1427   -0.8936
551            -0.8267    0.4821    0.1371   -0.2557
552            -0.4426   -0.3855   -0.7514    0.3014])
553     */
554     const PetscScalar c[6]    = {1. / 6, 2. / 6, 3. / 6, 4. / 6, 5. / 6, 1.};
555     const PetscScalar a[6][6] = {
556       {3.33333333333940e-01,  0,                     0,                     0,                     0,                    0                   },
557       {-8.64423857333350e-02, 3.33333333332888e-01,  0,                     0,                     0,                    0                   },
558       {-2.16850174258252e+00, -2.23619072028839e+00, 3.33333333335204e-01,  0,                     0,                    0                   },
559       {-4.73160970138997e+00, -3.89265344629268e+00, -2.76318716520933e-01, 3.33333333335759e-01,  0,                    0                   },
560       {-6.75187540297338e+00, -7.90756533769377e+00, 7.90245051802259e-01,  -4.48352364517632e-01, 3.33333333328483e-01, 0                   },
561       {-4.26488287921548e+00, -1.19320395589302e+01, 3.38924509887755e+00,  -2.23969848002481e+00, 6.62807710124007e-01, 3.33333333335440e-01}
562     };
563     const PetscScalar b[6][6] = {
564       {-4.26488287921548e+00, -1.19320395589302e+01, 3.38924509887755e+00,  -2.23969848002481e+00, 6.62807710124007e-01,  3.33333333335440e-01 },
565       {-8.88178419700125e-16, 4.44089209850063e-16,  -1.54737334057131e-15, -8.88178419700125e-16, 0.00000000000000e+00,  1.00000000000001e+00 },
566       {-2.87780425770651e+01, -1.13520448264971e+01, 2.62002318943161e+01,  2.56943874812797e+01,  -3.06702268304488e+01, 6.68067773510103e+00 },
567       {5.47971245256474e+01,  6.80366875868284e+01,  -6.50952588861999e+01, -8.28643975339097e+01, 8.17416943896414e+01,  -1.17819043489036e+01},
568       {-2.33332114788869e+02, 6.12942539462634e+01,  -4.91850135865944e+01, 1.82716844135480e+02,  -1.29788173979395e+02, 3.09968095651099e+01 },
569       {-1.72049132343751e+02, 8.60194713593999e+00,  7.98154219170200e-01,  1.50371386053218e+02,  -1.18515423962066e+02, 2.50898277784663e+01 }
570     };
571     const PetscScalar u[6][6] = {
572       {1.00000000000000e+00, -1.66666666666870e-01, -4.16666666664335e-02, -3.85802469124815e-03, -2.25051440302250e-04, -9.64506172339142e-06},
573       {1.00000000000000e+00, 8.64423857327162e-02,  -4.11484912671353e-02, -1.11450903217645e-02, -1.47651050487126e-03, -1.34395070766826e-04},
574       {1.00000000000000e+00, 4.57135912953434e+00,  1.06514719719137e+00,  1.33517564218007e-01,  1.11365952968659e-02,  6.12382756769504e-04 },
575       {1.00000000000000e+00, 9.23391519753404e+00,  2.22431212392095e+00,  2.91823807741891e-01,  2.52058456411084e-02,  1.22800542949647e-03 },
576       {1.00000000000000e+00, 1.48175480533865e+01,  3.73439117461835e+00,  5.14648336541804e-01,  4.76430038853402e-02,  2.56798515502156e-03 },
577       {1.00000000000000e+00, 1.50512347758335e+01,  4.10099701165164e+00,  5.66039141003603e-01,  3.91213893800891e-02,  -2.99136269067853e-03}
578     };
579     const PetscScalar v[6][6] = {
580       {1.00000000000000e+00, 1.50512347758335e+01,  4.10099701165164e+00,  5.66039141003603e-01,  3.91213893800891e-02,  -2.99136269067853e-03},
581       {0.00000000000000e+00, -4.88498130835069e-15, -6.43929354282591e-15, -3.55271367880050e-15, -1.22124532708767e-15, -3.12250225675825e-16},
582       {0.00000000000000e+00, 1.22250171233141e+01,  -1.77150760606169e+00, 3.54516769879390e-01,  6.22298845883398e-01,  2.31647447450276e-01 },
583       {0.00000000000000e+00, -4.48339457331040e+01, -3.57363126641880e-01, 5.18750173123425e-01,  6.55727990241799e-02,  1.63175368287079e-01 },
584       {0.00000000000000e+00, 1.37297394708005e+02,  -1.60145272991317e+00, -5.05319555199441e+00, 1.55328940390990e-01,  9.16629423682464e-01 },
585       {0.00000000000000e+00, 1.05703241119022e+02,  -1.16610260983038e+00, -2.99767252773859e+00, -1.13472315553890e-01, 1.09742849254729e+00 }
586     };
587     PetscCall(TSGLLESchemeCreate(5, 5, 6, 6, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
588   }
589   PetscFunctionReturn(0);
590 }
591 
592 /*@C
593    TSGLLESetType - sets the class of general linear method to use for time-stepping
594 
595    Collective on TS
596 
597    Input Parameters:
598 +  ts - the TS context
599 -  type - a method
600 
601    Options Database Key:
602 .  -ts_gl_type <type> - sets the method, use -help for a list of available method (e.g. irks)
603 
604    Notes:
605    See "petsc/include/petscts.h" for available methods (for instance)
606 .    TSGLLE_IRKS - Diagonally implicit methods with inherent Runge-Kutta stability (for stiff problems)
607 
608    Normally, it is best to use the TSSetFromOptions() command and
609    then set the TSGLLE type from the options database rather than by using
610    this routine.  Using the options database provides the user with
611    maximum flexibility in evaluating the many different solvers.
612    The TSGLLESetType() routine is provided for those situations where it
613    is necessary to set the timestepping solver independently of the
614    command line or options database.  This might be the case, for example,
615    when the choice of solver changes during the execution of the
616    program, and the user's application is taking responsibility for
617    choosing the appropriate method.
618 
619    Level: intermediate
620 
621 @*/
622 PetscErrorCode TSGLLESetType(TS ts, TSGLLEType type) {
623   PetscFunctionBegin;
624   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
625   PetscValidCharPointer(type, 2);
626   PetscTryMethod(ts, "TSGLLESetType_C", (TS, TSGLLEType), (ts, type));
627   PetscFunctionReturn(0);
628 }
629 
630 /*@C
631    TSGLLESetAcceptType - sets the acceptance test
632 
633    Time integrators that need to control error must have the option to reject a time step based on local error
634    estimates.  This function allows different schemes to be set.
635 
636    Logically Collective on TS
637 
638    Input Parameters:
639 +  ts - the TS context
640 -  type - the type
641 
642    Options Database Key:
643 .  -ts_gl_accept_type <type> - sets the method used to determine whether to accept or reject a step
644 
645    Level: intermediate
646 
647 .seealso: `TS`, `TSGLLE`, `TSGLLEAcceptRegister()`, `TSGLLEAdapt`, `set` `type`
648 @*/
649 PetscErrorCode TSGLLESetAcceptType(TS ts, TSGLLEAcceptType type) {
650   PetscFunctionBegin;
651   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
652   PetscValidCharPointer(type, 2);
653   PetscTryMethod(ts, "TSGLLESetAcceptType_C", (TS, TSGLLEAcceptType), (ts, type));
654   PetscFunctionReturn(0);
655 }
656 
657 /*@C
658    TSGLLEGetAdapt - gets the TSGLLEAdapt object from the TS
659 
660    Not Collective
661 
662    Input Parameter:
663 .  ts - the TS context
664 
665    Output Parameter:
666 .  adapt - the TSGLLEAdapt context
667 
668    Notes:
669    This allows the user set options on the TSGLLEAdapt object.  Usually it is better to do this using the options
670    database, so this function is rarely needed.
671 
672    Level: advanced
673 
674 .seealso: `TSGLLEAdapt`, `TSGLLEAdaptRegister()`
675 @*/
676 PetscErrorCode TSGLLEGetAdapt(TS ts, TSGLLEAdapt *adapt) {
677   PetscFunctionBegin;
678   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
679   PetscValidPointer(adapt, 2);
680   PetscUseMethod(ts, "TSGLLEGetAdapt_C", (TS, TSGLLEAdapt *), (ts, adapt));
681   PetscFunctionReturn(0);
682 }
683 
684 static PetscErrorCode TSGLLEAccept_Always(TS ts, PetscReal tleft, PetscReal h, const PetscReal enorms[], PetscBool *accept) {
685   PetscFunctionBegin;
686   *accept = PETSC_TRUE;
687   PetscFunctionReturn(0);
688 }
689 
690 static PetscErrorCode TSGLLEUpdateWRMS(TS ts) {
691   TS_GLLE     *gl = (TS_GLLE *)ts->data;
692   PetscScalar *x, *w;
693   PetscInt     n, i;
694 
695   PetscFunctionBegin;
696   PetscCall(VecGetArray(gl->X[0], &x));
697   PetscCall(VecGetArray(gl->W, &w));
698   PetscCall(VecGetLocalSize(gl->W, &n));
699   for (i = 0; i < n; i++) w[i] = 1. / (gl->wrms_atol + gl->wrms_rtol * PetscAbsScalar(x[i]));
700   PetscCall(VecRestoreArray(gl->X[0], &x));
701   PetscCall(VecRestoreArray(gl->W, &w));
702   PetscFunctionReturn(0);
703 }
704 
705 static PetscErrorCode TSGLLEVecNormWRMS(TS ts, Vec X, PetscReal *nrm) {
706   TS_GLLE     *gl = (TS_GLLE *)ts->data;
707   PetscScalar *x, *w;
708   PetscReal    sum = 0.0, gsum;
709   PetscInt     n, N, i;
710 
711   PetscFunctionBegin;
712   PetscCall(VecGetArray(X, &x));
713   PetscCall(VecGetArray(gl->W, &w));
714   PetscCall(VecGetLocalSize(gl->W, &n));
715   for (i = 0; i < n; i++) sum += PetscAbsScalar(PetscSqr(x[i] * w[i]));
716   PetscCall(VecRestoreArray(X, &x));
717   PetscCall(VecRestoreArray(gl->W, &w));
718   PetscCall(MPIU_Allreduce(&sum, &gsum, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)ts)));
719   PetscCall(VecGetSize(gl->W, &N));
720   *nrm = PetscSqrtReal(gsum / (1. * N));
721   PetscFunctionReturn(0);
722 }
723 
724 static PetscErrorCode TSGLLESetType_GLLE(TS ts, TSGLLEType type) {
725   PetscBool same;
726   TS_GLLE  *gl = (TS_GLLE *)ts->data;
727   PetscErrorCode (*r)(TS);
728 
729   PetscFunctionBegin;
730   if (gl->type_name[0]) {
731     PetscCall(PetscStrcmp(gl->type_name, type, &same));
732     if (same) PetscFunctionReturn(0);
733     PetscCall((*gl->Destroy)(gl));
734   }
735 
736   PetscCall(PetscFunctionListFind(TSGLLEList, type, &r));
737   PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown TSGLLE type \"%s\" given", type);
738   PetscCall((*r)(ts));
739   PetscCall(PetscStrcpy(gl->type_name, type));
740   PetscFunctionReturn(0);
741 }
742 
743 static PetscErrorCode TSGLLESetAcceptType_GLLE(TS ts, TSGLLEAcceptType type) {
744   TSGLLEAcceptFunction r;
745   TS_GLLE             *gl = (TS_GLLE *)ts->data;
746 
747   PetscFunctionBegin;
748   PetscCall(PetscFunctionListFind(TSGLLEAcceptList, type, &r));
749   PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown TSGLLEAccept type \"%s\" given", type);
750   gl->Accept = r;
751   PetscCall(PetscStrncpy(gl->accept_name, type, sizeof(gl->accept_name)));
752   PetscFunctionReturn(0);
753 }
754 
755 static PetscErrorCode TSGLLEGetAdapt_GLLE(TS ts, TSGLLEAdapt *adapt) {
756   TS_GLLE *gl = (TS_GLLE *)ts->data;
757 
758   PetscFunctionBegin;
759   if (!gl->adapt) {
760     PetscCall(TSGLLEAdaptCreate(PetscObjectComm((PetscObject)ts), &gl->adapt));
761     PetscCall(PetscObjectIncrementTabLevel((PetscObject)gl->adapt, (PetscObject)ts, 1));
762     PetscCall(PetscLogObjectParent((PetscObject)ts, (PetscObject)gl->adapt));
763   }
764   *adapt = gl->adapt;
765   PetscFunctionReturn(0);
766 }
767 
768 static PetscErrorCode TSGLLEChooseNextScheme(TS ts, PetscReal h, const PetscReal hmnorm[], PetscInt *next_scheme, PetscReal *next_h, PetscBool *finish) {
769   TS_GLLE  *gl = (TS_GLLE *)ts->data;
770   PetscInt  i, n, cur_p, cur, next_sc, candidates[64], orders[64];
771   PetscReal errors[64], costs[64], tleft;
772 
773   PetscFunctionBegin;
774   cur   = -1;
775   cur_p = gl->schemes[gl->current_scheme]->p;
776   tleft = ts->max_time - (ts->ptime + ts->time_step);
777   for (i = 0, n = 0; i < gl->nschemes; i++) {
778     TSGLLEScheme sc = gl->schemes[i];
779     if (sc->p < gl->min_order || gl->max_order < sc->p) continue;
780     if (sc->p == cur_p - 1) errors[n] = PetscAbsScalar(sc->alpha[0]) * hmnorm[0];
781     else if (sc->p == cur_p) errors[n] = PetscAbsScalar(sc->alpha[0]) * hmnorm[1];
782     else if (sc->p == cur_p + 1) errors[n] = PetscAbsScalar(sc->alpha[0]) * (hmnorm[2] + hmnorm[3]);
783     else continue;
784     candidates[n] = i;
785     orders[n]     = PetscMin(sc->p, sc->q); /* order of global truncation error */
786     costs[n]      = sc->s;                  /* estimate the cost as the number of stages */
787     if (i == gl->current_scheme) cur = n;
788     n++;
789   }
790   PetscCheck(cur >= 0 && gl->nschemes > cur, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Current scheme not found in scheme list");
791   PetscCall(TSGLLEAdaptChoose(gl->adapt, n, orders, errors, costs, cur, h, tleft, &next_sc, next_h, finish));
792   *next_scheme = candidates[next_sc];
793   PetscCall(PetscInfo(ts, "Adapt chose scheme %" PetscInt_FMT " (%" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT ") with step size %6.2e, finish=%s\n", *next_scheme, gl->schemes[*next_scheme]->p, gl->schemes[*next_scheme]->q,
794                       gl->schemes[*next_scheme]->r, gl->schemes[*next_scheme]->s, (double)*next_h, PetscBools[*finish]));
795   PetscFunctionReturn(0);
796 }
797 
798 static PetscErrorCode TSGLLEGetMaxSizes(TS ts, PetscInt *max_r, PetscInt *max_s) {
799   TS_GLLE *gl = (TS_GLLE *)ts->data;
800 
801   PetscFunctionBegin;
802   *max_r = gl->schemes[gl->nschemes - 1]->r;
803   *max_s = gl->schemes[gl->nschemes - 1]->s;
804   PetscFunctionReturn(0);
805 }
806 
807 static PetscErrorCode TSSolve_GLLE(TS ts) {
808   TS_GLLE            *gl = (TS_GLLE *)ts->data;
809   PetscInt            i, k, its, lits, max_r, max_s;
810   PetscBool           final_step, finish;
811   SNESConvergedReason snesreason;
812 
813   PetscFunctionBegin;
814   PetscCall(TSMonitor(ts, ts->steps, ts->ptime, ts->vec_sol));
815 
816   PetscCall(TSGLLEGetMaxSizes(ts, &max_r, &max_s));
817   PetscCall(VecCopy(ts->vec_sol, gl->X[0]));
818   for (i = 1; i < max_r; i++) PetscCall(VecZeroEntries(gl->X[i]));
819   PetscCall(TSGLLEUpdateWRMS(ts));
820 
821   if (0) {
822     /* Find consistent initial data for DAE */
823     gl->stage_time = ts->ptime + ts->time_step;
824     gl->scoeff     = 1.;
825     gl->stage      = 0;
826 
827     PetscCall(VecCopy(ts->vec_sol, gl->Z));
828     PetscCall(VecCopy(ts->vec_sol, gl->Y));
829     PetscCall(SNESSolve(ts->snes, NULL, gl->Y));
830     PetscCall(SNESGetIterationNumber(ts->snes, &its));
831     PetscCall(SNESGetLinearSolveIterations(ts->snes, &lits));
832     PetscCall(SNESGetConvergedReason(ts->snes, &snesreason));
833 
834     ts->snes_its += its;
835     ts->ksp_its += lits;
836     if (snesreason < 0 && ts->max_snes_failures > 0 && ++ts->num_snes_failures >= ts->max_snes_failures) {
837       ts->reason = TS_DIVERGED_NONLINEAR_SOLVE;
838       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", nonlinear solve solve failures %" PetscInt_FMT " greater than current TS allowed, stopping solve\n", ts->steps, ts->num_snes_failures));
839       PetscFunctionReturn(0);
840     }
841   }
842 
843   PetscCheck(gl->current_scheme >= 0, PETSC_COMM_SELF, PETSC_ERR_ORDER, "A starting scheme has not been provided");
844 
845   for (k = 0, final_step = PETSC_FALSE, finish = PETSC_FALSE; k < ts->max_steps && !finish; k++) {
846     PetscInt           j, r, s, next_scheme = 0, rejections;
847     PetscReal          h, hmnorm[4], enorm[3], next_h;
848     PetscBool          accept;
849     const PetscScalar *c, *a, *u;
850     Vec               *X, *Ydot, Y;
851     TSGLLEScheme       scheme = gl->schemes[gl->current_scheme];
852 
853     r    = scheme->r;
854     s    = scheme->s;
855     c    = scheme->c;
856     a    = scheme->a;
857     u    = scheme->u;
858     h    = ts->time_step;
859     X    = gl->X;
860     Ydot = gl->Ydot;
861     Y    = gl->Y;
862 
863     if (ts->ptime > ts->max_time) break;
864 
865     /*
866       We only call PreStep at the start of each STEP, not each STAGE.  This is because it is
867       possible to fail (have to restart a step) after multiple stages.
868     */
869     PetscCall(TSPreStep(ts));
870 
871     rejections = 0;
872     while (1) {
873       for (i = 0; i < s; i++) {
874         PetscScalar shift;
875         gl->scoeff     = 1. / PetscRealPart(a[i * s + i]);
876         shift          = gl->scoeff / ts->time_step;
877         gl->stage      = i;
878         gl->stage_time = ts->ptime + PetscRealPart(c[i]) * h;
879 
880         /*
881         * Stage equation: Y = h A Y' + U X
882         * We assume that A is lower-triangular so that we can solve the stages (Y,Y') sequentially
883         * Build the affine vector z_i = -[1/(h a_ii)](h sum_j a_ij y'_j + sum_j u_ij x_j)
884         * Then y'_i = z + 1/(h a_ii) y_i
885         */
886         PetscCall(VecZeroEntries(gl->Z));
887         for (j = 0; j < r; j++) PetscCall(VecAXPY(gl->Z, -shift * u[i * r + j], X[j]));
888         for (j = 0; j < i; j++) PetscCall(VecAXPY(gl->Z, -shift * h * a[i * s + j], Ydot[j]));
889         /* Note: Z is used within function evaluation, Ydot = Z + shift*Y */
890 
891         /* Compute an estimate of Y to start Newton iteration */
892         if (gl->extrapolate) {
893           if (i == 0) {
894             /* Linear extrapolation on the first stage */
895             PetscCall(VecWAXPY(Y, c[i] * h, X[1], X[0]));
896           } else {
897             /* Linear extrapolation from the last stage */
898             PetscCall(VecAXPY(Y, (c[i] - c[i - 1]) * h, Ydot[i - 1]));
899           }
900         } else if (i == 0) { /* Directly use solution from the last step, otherwise reuse the last stage (do nothing) */
901           PetscCall(VecCopy(X[0], Y));
902         }
903 
904         /* Solve this stage (Ydot[i] is computed during function evaluation) */
905         PetscCall(SNESSolve(ts->snes, NULL, Y));
906         PetscCall(SNESGetIterationNumber(ts->snes, &its));
907         PetscCall(SNESGetLinearSolveIterations(ts->snes, &lits));
908         PetscCall(SNESGetConvergedReason(ts->snes, &snesreason));
909         ts->snes_its += its;
910         ts->ksp_its += lits;
911         if (snesreason < 0 && ts->max_snes_failures > 0 && ++ts->num_snes_failures >= ts->max_snes_failures) {
912           ts->reason = TS_DIVERGED_NONLINEAR_SOLVE;
913           PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", nonlinear solve solve failures %" PetscInt_FMT " greater than current TS allowed, stopping solve\n", ts->steps, ts->num_snes_failures));
914           PetscFunctionReturn(0);
915         }
916       }
917 
918       gl->stage_time = ts->ptime + ts->time_step;
919 
920       PetscCall((*gl->EstimateHigherMoments)(scheme, h, Ydot, gl->X, gl->himom));
921       /* hmnorm[i] = h^{p+i}x^{(p+i)} with i=0,1,2; hmnorm[3] = h^{p+2}(dx'/dx) x^{(p+1)} */
922       for (i = 0; i < 3; i++) PetscCall(TSGLLEVecNormWRMS(ts, gl->himom[i], &hmnorm[i + 1]));
923       enorm[0] = PetscRealPart(scheme->alpha[0]) * hmnorm[1];
924       enorm[1] = PetscRealPart(scheme->beta[0]) * hmnorm[2];
925       enorm[2] = PetscRealPart(scheme->gamma[0]) * hmnorm[3];
926       PetscCall((*gl->Accept)(ts, ts->max_time - gl->stage_time, h, enorm, &accept));
927       if (accept) goto accepted;
928       rejections++;
929       PetscCall(PetscInfo(ts, "Step %" PetscInt_FMT " (t=%g) not accepted, rejections=%" PetscInt_FMT "\n", k, (double)gl->stage_time, rejections));
930       if (rejections > gl->max_step_rejections) break;
931       /*
932         There are lots of reasons why a step might be rejected, including solvers not converging and other factors that
933         TSGLLEChooseNextScheme does not support.  Additionally, the error estimates may be very screwed up, so I'm not
934         convinced that it's safe to just compute a new error estimate using the same interface as the current adaptor
935         (the adaptor interface probably has to change).  Here we make an arbitrary and naive choice.  This assumes that
936         steps were written in Nordsieck form.  The "correct" method would be to re-complete the previous time step with
937         the correct "next" step size.  It is unclear to me whether the present ad-hoc method of rescaling X is stable.
938       */
939       h *= 0.5;
940       for (i = 1; i < scheme->r; i++) PetscCall(VecScale(X[i], PetscPowRealInt(0.5, i)));
941     }
942     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_CONV_FAILED, "Time step %" PetscInt_FMT " (t=%g) not accepted after %" PetscInt_FMT " failures", k, (double)gl->stage_time, rejections);
943 
944   accepted:
945     /* This term is not error, but it *would* be the leading term for a lower order method */
946     PetscCall(TSGLLEVecNormWRMS(ts, gl->X[scheme->r - 1], &hmnorm[0]));
947     /* Correct scaling so that these are equivalent to norms of the Nordsieck vectors */
948 
949     PetscCall(PetscInfo(ts, "Last moment norm %10.2e, estimated error norms %10.2e %10.2e %10.2e\n", (double)hmnorm[0], (double)enorm[0], (double)enorm[1], (double)enorm[2]));
950     if (!final_step) {
951       PetscCall(TSGLLEChooseNextScheme(ts, h, hmnorm, &next_scheme, &next_h, &final_step));
952     } else {
953       /* Dummy values to complete the current step in a consistent manner */
954       next_scheme = gl->current_scheme;
955       next_h      = h;
956       finish      = PETSC_TRUE;
957     }
958 
959     X        = gl->Xold;
960     gl->Xold = gl->X;
961     gl->X    = X;
962     PetscCall((*gl->CompleteStep)(scheme, h, gl->schemes[next_scheme], next_h, Ydot, gl->Xold, gl->X));
963 
964     PetscCall(TSGLLEUpdateWRMS(ts));
965 
966     /* Post the solution for the user, we could avoid this copy with a small bit of cleverness */
967     PetscCall(VecCopy(gl->X[0], ts->vec_sol));
968     ts->ptime += h;
969     ts->steps++;
970 
971     PetscCall(TSPostEvaluate(ts));
972     PetscCall(TSPostStep(ts));
973     PetscCall(TSMonitor(ts, ts->steps, ts->ptime, ts->vec_sol));
974 
975     gl->current_scheme = next_scheme;
976     ts->time_step      = next_h;
977   }
978   PetscFunctionReturn(0);
979 }
980 
981 /*------------------------------------------------------------*/
982 
983 static PetscErrorCode TSReset_GLLE(TS ts) {
984   TS_GLLE *gl = (TS_GLLE *)ts->data;
985   PetscInt max_r, max_s;
986 
987   PetscFunctionBegin;
988   if (gl->setupcalled) {
989     PetscCall(TSGLLEGetMaxSizes(ts, &max_r, &max_s));
990     PetscCall(VecDestroyVecs(max_r, &gl->Xold));
991     PetscCall(VecDestroyVecs(max_r, &gl->X));
992     PetscCall(VecDestroyVecs(max_s, &gl->Ydot));
993     PetscCall(VecDestroyVecs(3, &gl->himom));
994     PetscCall(VecDestroy(&gl->W));
995     PetscCall(VecDestroy(&gl->Y));
996     PetscCall(VecDestroy(&gl->Z));
997   }
998   gl->setupcalled = PETSC_FALSE;
999   PetscFunctionReturn(0);
1000 }
1001 
1002 static PetscErrorCode TSDestroy_GLLE(TS ts) {
1003   TS_GLLE *gl = (TS_GLLE *)ts->data;
1004 
1005   PetscFunctionBegin;
1006   PetscCall(TSReset_GLLE(ts));
1007   if (ts->dm) {
1008     PetscCall(DMCoarsenHookRemove(ts->dm, DMCoarsenHook_TSGLLE, DMRestrictHook_TSGLLE, ts));
1009     PetscCall(DMSubDomainHookRemove(ts->dm, DMSubDomainHook_TSGLLE, DMSubDomainRestrictHook_TSGLLE, ts));
1010   }
1011   if (gl->adapt) PetscCall(TSGLLEAdaptDestroy(&gl->adapt));
1012   if (gl->Destroy) PetscCall((*gl->Destroy)(gl));
1013   PetscCall(PetscFree(ts->data));
1014   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLESetType_C", NULL));
1015   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLESetAcceptType_C", NULL));
1016   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLEGetAdapt_C", NULL));
1017   PetscFunctionReturn(0);
1018 }
1019 
1020 /*
1021     This defines the nonlinear equation that is to be solved with SNES
1022     g(x) = f(t,x,z+shift*x) = 0
1023 */
1024 static PetscErrorCode SNESTSFormFunction_GLLE(SNES snes, Vec x, Vec f, TS ts) {
1025   TS_GLLE *gl = (TS_GLLE *)ts->data;
1026   Vec      Z, Ydot;
1027   DM       dm, dmsave;
1028 
1029   PetscFunctionBegin;
1030   PetscCall(SNESGetDM(snes, &dm));
1031   PetscCall(TSGLLEGetVecs(ts, dm, &Z, &Ydot));
1032   PetscCall(VecWAXPY(Ydot, gl->scoeff / ts->time_step, x, Z));
1033   dmsave = ts->dm;
1034   ts->dm = dm;
1035   PetscCall(TSComputeIFunction(ts, gl->stage_time, x, Ydot, f, PETSC_FALSE));
1036   ts->dm = dmsave;
1037   PetscCall(TSGLLERestoreVecs(ts, dm, &Z, &Ydot));
1038   PetscFunctionReturn(0);
1039 }
1040 
1041 static PetscErrorCode SNESTSFormJacobian_GLLE(SNES snes, Vec x, Mat A, Mat B, TS ts) {
1042   TS_GLLE *gl = (TS_GLLE *)ts->data;
1043   Vec      Z, Ydot;
1044   DM       dm, dmsave;
1045 
1046   PetscFunctionBegin;
1047   PetscCall(SNESGetDM(snes, &dm));
1048   PetscCall(TSGLLEGetVecs(ts, dm, &Z, &Ydot));
1049   dmsave = ts->dm;
1050   ts->dm = dm;
1051   /* gl->Xdot will have already been computed in SNESTSFormFunction_GLLE */
1052   PetscCall(TSComputeIJacobian(ts, gl->stage_time, x, gl->Ydot[gl->stage], gl->scoeff / ts->time_step, A, B, PETSC_FALSE));
1053   ts->dm = dmsave;
1054   PetscCall(TSGLLERestoreVecs(ts, dm, &Z, &Ydot));
1055   PetscFunctionReturn(0);
1056 }
1057 
1058 static PetscErrorCode TSSetUp_GLLE(TS ts) {
1059   TS_GLLE *gl = (TS_GLLE *)ts->data;
1060   PetscInt max_r, max_s;
1061   DM       dm;
1062 
1063   PetscFunctionBegin;
1064   gl->setupcalled = PETSC_TRUE;
1065   PetscCall(TSGLLEGetMaxSizes(ts, &max_r, &max_s));
1066   PetscCall(VecDuplicateVecs(ts->vec_sol, max_r, &gl->X));
1067   PetscCall(VecDuplicateVecs(ts->vec_sol, max_r, &gl->Xold));
1068   PetscCall(VecDuplicateVecs(ts->vec_sol, max_s, &gl->Ydot));
1069   PetscCall(VecDuplicateVecs(ts->vec_sol, 3, &gl->himom));
1070   PetscCall(VecDuplicate(ts->vec_sol, &gl->W));
1071   PetscCall(VecDuplicate(ts->vec_sol, &gl->Y));
1072   PetscCall(VecDuplicate(ts->vec_sol, &gl->Z));
1073 
1074   /* Default acceptance tests and adaptivity */
1075   if (!gl->Accept) PetscCall(TSGLLESetAcceptType(ts, TSGLLEACCEPT_ALWAYS));
1076   if (!gl->adapt) PetscCall(TSGLLEGetAdapt(ts, &gl->adapt));
1077 
1078   if (gl->current_scheme < 0) {
1079     PetscInt i;
1080     for (i = 0;; i++) {
1081       if (gl->schemes[i]->p == gl->start_order) break;
1082       PetscCheck(i + 1 != gl->nschemes, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No schemes available with requested start order %" PetscInt_FMT, i);
1083     }
1084     gl->current_scheme = i;
1085   }
1086   PetscCall(TSGetDM(ts, &dm));
1087   PetscCall(DMCoarsenHookAdd(dm, DMCoarsenHook_TSGLLE, DMRestrictHook_TSGLLE, ts));
1088   PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_TSGLLE, DMSubDomainRestrictHook_TSGLLE, ts));
1089   PetscFunctionReturn(0);
1090 }
1091 /*------------------------------------------------------------*/
1092 
1093 static PetscErrorCode TSSetFromOptions_GLLE(TS ts, PetscOptionItems *PetscOptionsObject) {
1094   TS_GLLE *gl         = (TS_GLLE *)ts->data;
1095   char     tname[256] = TSGLLE_IRKS, completef[256] = "rescale-and-modify";
1096 
1097   PetscFunctionBegin;
1098   PetscOptionsHeadBegin(PetscOptionsObject, "General Linear ODE solver options");
1099   {
1100     PetscBool flg;
1101     PetscCall(PetscOptionsFList("-ts_gl_type", "Type of GL method", "TSGLLESetType", TSGLLEList, gl->type_name[0] ? gl->type_name : tname, tname, sizeof(tname), &flg));
1102     if (flg || !gl->type_name[0]) PetscCall(TSGLLESetType(ts, tname));
1103     PetscCall(PetscOptionsInt("-ts_gl_max_step_rejections", "Maximum number of times to attempt a step", "None", gl->max_step_rejections, &gl->max_step_rejections, NULL));
1104     PetscCall(PetscOptionsInt("-ts_gl_max_order", "Maximum order to try", "TSGLLESetMaxOrder", gl->max_order, &gl->max_order, NULL));
1105     PetscCall(PetscOptionsInt("-ts_gl_min_order", "Minimum order to try", "TSGLLESetMinOrder", gl->min_order, &gl->min_order, NULL));
1106     PetscCall(PetscOptionsInt("-ts_gl_start_order", "Initial order to try", "TSGLLESetMinOrder", gl->start_order, &gl->start_order, NULL));
1107     PetscCall(PetscOptionsEnum("-ts_gl_error_direction", "Which direction to look when estimating error", "TSGLLESetErrorDirection", TSGLLEErrorDirections, (PetscEnum)gl->error_direction, (PetscEnum *)&gl->error_direction, NULL));
1108     PetscCall(PetscOptionsBool("-ts_gl_extrapolate", "Extrapolate stage solution from previous solution (sometimes unstable)", "TSGLLESetExtrapolate", gl->extrapolate, &gl->extrapolate, NULL));
1109     PetscCall(PetscOptionsReal("-ts_gl_atol", "Absolute tolerance", "TSGLLESetTolerances", gl->wrms_atol, &gl->wrms_atol, NULL));
1110     PetscCall(PetscOptionsReal("-ts_gl_rtol", "Relative tolerance", "TSGLLESetTolerances", gl->wrms_rtol, &gl->wrms_rtol, NULL));
1111     PetscCall(PetscOptionsString("-ts_gl_complete", "Method to use for completing the step", "none", completef, completef, sizeof(completef), &flg));
1112     if (flg) {
1113       PetscBool match1, match2;
1114       PetscCall(PetscStrcmp(completef, "rescale", &match1));
1115       PetscCall(PetscStrcmp(completef, "rescale-and-modify", &match2));
1116       if (match1) gl->CompleteStep = TSGLLECompleteStep_Rescale;
1117       else if (match2) gl->CompleteStep = TSGLLECompleteStep_RescaleAndModify;
1118       else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "%s", completef);
1119     }
1120     {
1121       char type[256] = TSGLLEACCEPT_ALWAYS;
1122       PetscCall(PetscOptionsFList("-ts_gl_accept_type", "Method to use for determining whether to accept a step", "TSGLLESetAcceptType", TSGLLEAcceptList, gl->accept_name[0] ? gl->accept_name : type, type, sizeof(type), &flg));
1123       if (flg || !gl->accept_name[0]) PetscCall(TSGLLESetAcceptType(ts, type));
1124     }
1125     {
1126       TSGLLEAdapt adapt;
1127       PetscCall(TSGLLEGetAdapt(ts, &adapt));
1128       PetscCall(TSGLLEAdaptSetFromOptions(adapt, PetscOptionsObject));
1129     }
1130   }
1131   PetscOptionsHeadEnd();
1132   PetscFunctionReturn(0);
1133 }
1134 
1135 static PetscErrorCode TSView_GLLE(TS ts, PetscViewer viewer) {
1136   TS_GLLE  *gl = (TS_GLLE *)ts->data;
1137   PetscInt  i;
1138   PetscBool iascii, details;
1139 
1140   PetscFunctionBegin;
1141   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1142   if (iascii) {
1143     PetscCall(PetscViewerASCIIPrintf(viewer, "  min order %" PetscInt_FMT ", max order %" PetscInt_FMT ", current order %" PetscInt_FMT "\n", gl->min_order, gl->max_order, gl->schemes[gl->current_scheme]->p));
1144     PetscCall(PetscViewerASCIIPrintf(viewer, "  Error estimation: %s\n", TSGLLEErrorDirections[gl->error_direction]));
1145     PetscCall(PetscViewerASCIIPrintf(viewer, "  Extrapolation: %s\n", gl->extrapolate ? "yes" : "no"));
1146     PetscCall(PetscViewerASCIIPrintf(viewer, "  Acceptance test: %s\n", gl->accept_name[0] ? gl->accept_name : "(not yet set)"));
1147     PetscCall(PetscViewerASCIIPushTab(viewer));
1148     PetscCall(TSGLLEAdaptView(gl->adapt, viewer));
1149     PetscCall(PetscViewerASCIIPopTab(viewer));
1150     PetscCall(PetscViewerASCIIPrintf(viewer, "  type: %s\n", gl->type_name[0] ? gl->type_name : "(not yet set)"));
1151     PetscCall(PetscViewerASCIIPrintf(viewer, "Schemes within family (%" PetscInt_FMT "):\n", gl->nschemes));
1152     details = PETSC_FALSE;
1153     PetscCall(PetscOptionsGetBool(((PetscObject)ts)->options, ((PetscObject)ts)->prefix, "-ts_gl_view_detailed", &details, NULL));
1154     PetscCall(PetscViewerASCIIPushTab(viewer));
1155     for (i = 0; i < gl->nschemes; i++) PetscCall(TSGLLESchemeView(gl->schemes[i], details, viewer));
1156     if (gl->View) PetscCall((*gl->View)(gl, viewer));
1157     PetscCall(PetscViewerASCIIPopTab(viewer));
1158   }
1159   PetscFunctionReturn(0);
1160 }
1161 
1162 /*@C
1163    TSGLLERegister -  adds a TSGLLE implementation
1164 
1165    Not Collective
1166 
1167    Input Parameters:
1168 +  name_scheme - name of user-defined general linear scheme
1169 -  routine_create - routine to create method context
1170 
1171    Notes:
1172    TSGLLERegister() may be called multiple times to add several user-defined families.
1173 
1174    Sample usage:
1175 .vb
1176    TSGLLERegister("my_scheme",MySchemeCreate);
1177 .ve
1178 
1179    Then, your scheme can be chosen with the procedural interface via
1180 $     TSGLLESetType(ts,"my_scheme")
1181    or at runtime via the option
1182 $     -ts_gl_type my_scheme
1183 
1184    Level: advanced
1185 
1186 .seealso: `TSGLLERegisterAll()`
1187 @*/
1188 PetscErrorCode TSGLLERegister(const char sname[], PetscErrorCode (*function)(TS)) {
1189   PetscFunctionBegin;
1190   PetscCall(TSGLLEInitializePackage());
1191   PetscCall(PetscFunctionListAdd(&TSGLLEList, sname, function));
1192   PetscFunctionReturn(0);
1193 }
1194 
1195 /*@C
1196    TSGLLEAcceptRegister -  adds a TSGLLE acceptance scheme
1197 
1198    Not Collective
1199 
1200    Input Parameters:
1201 +  name_scheme - name of user-defined acceptance scheme
1202 -  routine_create - routine to create method context
1203 
1204    Notes:
1205    TSGLLEAcceptRegister() may be called multiple times to add several user-defined families.
1206 
1207    Sample usage:
1208 .vb
1209    TSGLLEAcceptRegister("my_scheme",MySchemeCreate);
1210 .ve
1211 
1212    Then, your scheme can be chosen with the procedural interface via
1213 $     TSGLLESetAcceptType(ts,"my_scheme")
1214    or at runtime via the option
1215 $     -ts_gl_accept_type my_scheme
1216 
1217    Level: advanced
1218 
1219 .seealso: `TSGLLERegisterAll()`
1220 @*/
1221 PetscErrorCode TSGLLEAcceptRegister(const char sname[], TSGLLEAcceptFunction function) {
1222   PetscFunctionBegin;
1223   PetscCall(PetscFunctionListAdd(&TSGLLEAcceptList, sname, function));
1224   PetscFunctionReturn(0);
1225 }
1226 
1227 /*@C
1228   TSGLLERegisterAll - Registers all of the general linear methods in TSGLLE
1229 
1230   Not Collective
1231 
1232   Level: advanced
1233 
1234 .seealso: `TSGLLERegisterDestroy()`
1235 @*/
1236 PetscErrorCode TSGLLERegisterAll(void) {
1237   PetscFunctionBegin;
1238   if (TSGLLERegisterAllCalled) PetscFunctionReturn(0);
1239   TSGLLERegisterAllCalled = PETSC_TRUE;
1240 
1241   PetscCall(TSGLLERegister(TSGLLE_IRKS, TSGLLECreate_IRKS));
1242   PetscCall(TSGLLEAcceptRegister(TSGLLEACCEPT_ALWAYS, TSGLLEAccept_Always));
1243   PetscFunctionReturn(0);
1244 }
1245 
1246 /*@C
1247   TSGLLEInitializePackage - This function initializes everything in the TSGLLE package. It is called
1248   from TSInitializePackage().
1249 
1250   Level: developer
1251 
1252 .seealso: `PetscInitialize()`
1253 @*/
1254 PetscErrorCode TSGLLEInitializePackage(void) {
1255   PetscFunctionBegin;
1256   if (TSGLLEPackageInitialized) PetscFunctionReturn(0);
1257   TSGLLEPackageInitialized = PETSC_TRUE;
1258   PetscCall(TSGLLERegisterAll());
1259   PetscCall(PetscRegisterFinalize(TSGLLEFinalizePackage));
1260   PetscFunctionReturn(0);
1261 }
1262 
1263 /*@C
1264   TSGLLEFinalizePackage - This function destroys everything in the TSGLLE package. It is
1265   called from PetscFinalize().
1266 
1267   Level: developer
1268 
1269 .seealso: `PetscFinalize()`
1270 @*/
1271 PetscErrorCode TSGLLEFinalizePackage(void) {
1272   PetscFunctionBegin;
1273   PetscCall(PetscFunctionListDestroy(&TSGLLEList));
1274   PetscCall(PetscFunctionListDestroy(&TSGLLEAcceptList));
1275   TSGLLEPackageInitialized = PETSC_FALSE;
1276   TSGLLERegisterAllCalled  = PETSC_FALSE;
1277   PetscFunctionReturn(0);
1278 }
1279 
1280 /* ------------------------------------------------------------ */
1281 /*MC
1282       TSGLLE - DAE solver using implicit General Linear methods
1283 
1284   These methods contain Runge-Kutta and multistep schemes as special cases.  These special cases have some fundamental
1285   limitations.  For example, diagonally implicit Runge-Kutta cannot have stage order greater than 1 which limits their
1286   applicability to very stiff systems.  Meanwhile, multistep methods cannot be A-stable for order greater than 2 and BDF
1287   are not 0-stable for order greater than 6.  GL methods can be A- and L-stable with arbitrarily high stage order and
1288   reliable error estimates for both 1 and 2 orders higher to facilitate adaptive step sizes and adaptive order schemes.
1289   All this is possible while preserving a singly diagonally implicit structure.
1290 
1291   Options database keys:
1292 +  -ts_gl_type <type> - the class of general linear method (irks)
1293 .  -ts_gl_rtol <tol>  - relative error
1294 .  -ts_gl_atol <tol>  - absolute error
1295 .  -ts_gl_min_order <p> - minimum order method to consider (default=1)
1296 .  -ts_gl_max_order <p> - maximum order method to consider (default=3)
1297 .  -ts_gl_start_order <p> - order of starting method (default=1)
1298 .  -ts_gl_complete <method> - method to use for completing the step (rescale-and-modify or rescale)
1299 -  -ts_adapt_type <method> - adaptive controller to use (none step both)
1300 
1301   Notes:
1302   This integrator can be applied to DAE.
1303 
1304   Diagonally implicit general linear (DIGL) methods are a generalization of diagonally implicit Runge-Kutta (DIRK).
1305   They are represented by the tableau
1306 
1307 .vb
1308   A  |  U
1309   -------
1310   B  |  V
1311 .ve
1312 
1313   combined with a vector c of abscissa.  "Diagonally implicit" means that A is lower triangular.
1314   A step of the general method reads
1315 
1316 .vb
1317   [ Y ] = [A  U] [  Y'   ]
1318   [X^k] = [B  V] [X^{k-1}]
1319 .ve
1320 
1321   where Y is the multivector of stage values, Y' is the multivector of stage derivatives, X^k is the Nordsieck vector of
1322   the solution at step k.  The Nordsieck vector consists of the first r moments of the solution, given by
1323 
1324 .vb
1325   X = [x_0,x_1,...,x_{r-1}] = [x, h x', h^2 x'', ..., h^{r-1} x^{(r-1)} ]
1326 .ve
1327 
1328   If A is lower triangular, we can solve the stages (Y,Y') sequentially
1329 
1330 .vb
1331   y_i = h sum_{j=0}^{s-1} (a_ij y'_j) + sum_{j=0}^{r-1} u_ij x_j,    i=0,...,{s-1}
1332 .ve
1333 
1334   and then construct the pieces to carry to the next step
1335 
1336 .vb
1337   xx_i = h sum_{j=0}^{s-1} b_ij y'_j  + sum_{j=0}^{r-1} v_ij x_j,    i=0,...,{r-1}
1338 .ve
1339 
1340   Note that when the equations are cast in implicit form, we are using the stage equation to define y'_i
1341   in terms of y_i and known stuff (y_j for j<i and x_j for all j).
1342 
1343   Error estimation
1344 
1345   At present, the most attractive GL methods for stiff problems are singly diagonally implicit schemes which posses
1346   Inherent Runge-Kutta Stability (IRKS).  These methods have r=s, the number of items passed between steps is equal to
1347   the number of stages.  The order and stage-order are one less than the number of stages.  We use the error estimates
1348   in the 2007 paper which provide the following estimates
1349 
1350 .vb
1351   h^{p+1} X^{(p+1)}          = phi_0^T Y' + [0 psi_0^T] Xold
1352   h^{p+2} X^{(p+2)}          = phi_1^T Y' + [0 psi_1^T] Xold
1353   h^{p+2} (dx'/dx) X^{(p+1)} = phi_2^T Y' + [0 psi_2^T] Xold
1354 .ve
1355 
1356   These estimates are accurate to O(h^{p+3}).
1357 
1358   Changing the step size
1359 
1360   We use the generalized "rescale and modify" scheme, see equation (4.5) of the 2007 paper.
1361 
1362   Level: beginner
1363 
1364   References:
1365 + * - John Butcher and Z. Jackieweicz and W. Wright, On error propagation in general linear methods for
1366   ordinary differential equations, Journal of Complexity, Vol 23, 2007.
1367 - * - John Butcher, Numerical methods for ordinary differential equations, second edition, Wiley, 2009.
1368 
1369 .seealso: `TSCreate()`, `TS`, `TSSetType()`
1370 
1371 M*/
1372 PETSC_EXTERN PetscErrorCode TSCreate_GLLE(TS ts) {
1373   TS_GLLE *gl;
1374 
1375   PetscFunctionBegin;
1376   PetscCall(TSGLLEInitializePackage());
1377 
1378   PetscCall(PetscNewLog(ts, &gl));
1379   ts->data = (void *)gl;
1380 
1381   ts->ops->reset          = TSReset_GLLE;
1382   ts->ops->destroy        = TSDestroy_GLLE;
1383   ts->ops->view           = TSView_GLLE;
1384   ts->ops->setup          = TSSetUp_GLLE;
1385   ts->ops->solve          = TSSolve_GLLE;
1386   ts->ops->setfromoptions = TSSetFromOptions_GLLE;
1387   ts->ops->snesfunction   = SNESTSFormFunction_GLLE;
1388   ts->ops->snesjacobian   = SNESTSFormJacobian_GLLE;
1389 
1390   ts->usessnes = PETSC_TRUE;
1391 
1392   gl->max_step_rejections = 1;
1393   gl->min_order           = 1;
1394   gl->max_order           = 3;
1395   gl->start_order         = 1;
1396   gl->current_scheme      = -1;
1397   gl->extrapolate         = PETSC_FALSE;
1398 
1399   gl->wrms_atol = 1e-8;
1400   gl->wrms_rtol = 1e-5;
1401 
1402   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLESetType_C", &TSGLLESetType_GLLE));
1403   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLESetAcceptType_C", &TSGLLESetAcceptType_GLLE));
1404   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLEGetAdapt_C", &TSGLLEGetAdapt_GLLE));
1405   PetscFunctionReturn(0);
1406 }
1407