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