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