xref: /petsc/src/ts/impls/implicit/glle/glle.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
13d177a5cSEmil Constantinescu 
23d177a5cSEmil Constantinescu #include <../src/ts/impls/implicit/glle/glle.h> /*I   "petscts.h"   I*/
33d177a5cSEmil Constantinescu #include <petscdm.h>
43d177a5cSEmil Constantinescu #include <petscblaslapack.h>
53d177a5cSEmil Constantinescu 
6c793f718SLisandro Dalcin static const char       *TSGLLEErrorDirections[] = {"FORWARD", "BACKWARD", "TSGLLEErrorDirection", "TSGLLEERROR_", NULL};
73d177a5cSEmil Constantinescu static PetscFunctionList TSGLLEList;
83d177a5cSEmil Constantinescu static PetscFunctionList TSGLLEAcceptList;
93d177a5cSEmil Constantinescu static PetscBool         TSGLLEPackageInitialized;
103d177a5cSEmil Constantinescu static PetscBool         TSGLLERegisterAllCalled;
113d177a5cSEmil Constantinescu 
123d177a5cSEmil Constantinescu /* This function is pure */
139371c9d4SSatish Balay static PetscScalar Factorial(PetscInt n) {
143d177a5cSEmil Constantinescu   PetscInt i;
153d177a5cSEmil Constantinescu   if (n < 12) { /* Can compute with 32-bit integers */
163d177a5cSEmil Constantinescu     PetscInt f = 1;
173d177a5cSEmil Constantinescu     for (i = 2; i <= n; i++) f *= i;
183d177a5cSEmil Constantinescu     return (PetscScalar)f;
193d177a5cSEmil Constantinescu   } else {
203d177a5cSEmil Constantinescu     PetscScalar f = 1.;
213d177a5cSEmil Constantinescu     for (i = 2; i <= n; i++) f *= (PetscScalar)i;
223d177a5cSEmil Constantinescu     return f;
233d177a5cSEmil Constantinescu   }
243d177a5cSEmil Constantinescu }
253d177a5cSEmil Constantinescu 
263d177a5cSEmil Constantinescu /* This function is pure */
279371c9d4SSatish Balay static PetscScalar CPowF(PetscScalar c, PetscInt p) {
283d177a5cSEmil Constantinescu   return PetscPowRealInt(PetscRealPart(c), p) / Factorial(p);
293d177a5cSEmil Constantinescu }
303d177a5cSEmil Constantinescu 
319371c9d4SSatish Balay static PetscErrorCode TSGLLEGetVecs(TS ts, DM dm, Vec *Z, Vec *Ydotstage) {
323d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
333d177a5cSEmil Constantinescu 
343d177a5cSEmil Constantinescu   PetscFunctionBegin;
353d177a5cSEmil Constantinescu   if (Z) {
363d177a5cSEmil Constantinescu     if (dm && dm != ts->dm) {
379566063dSJacob Faibussowitsch       PetscCall(DMGetNamedGlobalVector(dm, "TSGLLE_Z", Z));
383d177a5cSEmil Constantinescu     } else *Z = gl->Z;
393d177a5cSEmil Constantinescu   }
403d177a5cSEmil Constantinescu   if (Ydotstage) {
413d177a5cSEmil Constantinescu     if (dm && dm != ts->dm) {
429566063dSJacob Faibussowitsch       PetscCall(DMGetNamedGlobalVector(dm, "TSGLLE_Ydot", Ydotstage));
433d177a5cSEmil Constantinescu     } else *Ydotstage = gl->Ydot[gl->stage];
443d177a5cSEmil Constantinescu   }
453d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
463d177a5cSEmil Constantinescu }
473d177a5cSEmil Constantinescu 
489371c9d4SSatish Balay static PetscErrorCode TSGLLERestoreVecs(TS ts, DM dm, Vec *Z, Vec *Ydotstage) {
493d177a5cSEmil Constantinescu   PetscFunctionBegin;
503d177a5cSEmil Constantinescu   if (Z) {
51*48a46eb9SPierre Jolivet     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSGLLE_Z", Z));
523d177a5cSEmil Constantinescu   }
533d177a5cSEmil Constantinescu   if (Ydotstage) {
54*48a46eb9SPierre Jolivet     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSGLLE_Ydot", Ydotstage));
553d177a5cSEmil Constantinescu   }
563d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
573d177a5cSEmil Constantinescu }
583d177a5cSEmil Constantinescu 
599371c9d4SSatish Balay static PetscErrorCode DMCoarsenHook_TSGLLE(DM fine, DM coarse, void *ctx) {
603d177a5cSEmil Constantinescu   PetscFunctionBegin;
613d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
623d177a5cSEmil Constantinescu }
633d177a5cSEmil Constantinescu 
649371c9d4SSatish Balay static PetscErrorCode DMRestrictHook_TSGLLE(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse, void *ctx) {
653d177a5cSEmil Constantinescu   TS  ts = (TS)ctx;
663d177a5cSEmil Constantinescu   Vec Ydot, Ydot_c;
673d177a5cSEmil Constantinescu 
683d177a5cSEmil Constantinescu   PetscFunctionBegin;
699566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, fine, NULL, &Ydot));
709566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, coarse, NULL, &Ydot_c));
719566063dSJacob Faibussowitsch   PetscCall(MatRestrict(restrct, Ydot, Ydot_c));
729566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(Ydot_c, rscale, Ydot_c));
739566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, fine, NULL, &Ydot));
749566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, coarse, NULL, &Ydot_c));
753d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
763d177a5cSEmil Constantinescu }
773d177a5cSEmil Constantinescu 
789371c9d4SSatish Balay static PetscErrorCode DMSubDomainHook_TSGLLE(DM dm, DM subdm, void *ctx) {
793d177a5cSEmil Constantinescu   PetscFunctionBegin;
803d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
813d177a5cSEmil Constantinescu }
823d177a5cSEmil Constantinescu 
839371c9d4SSatish Balay static PetscErrorCode DMSubDomainRestrictHook_TSGLLE(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx) {
843d177a5cSEmil Constantinescu   TS  ts = (TS)ctx;
853d177a5cSEmil Constantinescu   Vec Ydot, Ydot_s;
863d177a5cSEmil Constantinescu 
873d177a5cSEmil Constantinescu   PetscFunctionBegin;
889566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, dm, NULL, &Ydot));
899566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, subdm, NULL, &Ydot_s));
903d177a5cSEmil Constantinescu 
919566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(gscat, Ydot, Ydot_s, INSERT_VALUES, SCATTER_FORWARD));
929566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(gscat, Ydot, Ydot_s, INSERT_VALUES, SCATTER_FORWARD));
933d177a5cSEmil Constantinescu 
949566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, dm, NULL, &Ydot));
959566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, subdm, NULL, &Ydot_s));
963d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
973d177a5cSEmil Constantinescu }
983d177a5cSEmil Constantinescu 
999371c9d4SSatish Balay 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) {
1003d177a5cSEmil Constantinescu   TSGLLEScheme scheme;
1013d177a5cSEmil Constantinescu   PetscInt     j;
1023d177a5cSEmil Constantinescu 
1033d177a5cSEmil Constantinescu   PetscFunctionBegin;
10408401ef6SPierre Jolivet   PetscCheck(p >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Scheme order must be positive");
10508401ef6SPierre Jolivet   PetscCheck(r >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "At least one item must be carried between steps");
10608401ef6SPierre Jolivet   PetscCheck(s >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "At least one stage is required");
107064a246eSJacob Faibussowitsch   PetscValidPointer(inscheme, 10);
108c793f718SLisandro Dalcin   *inscheme = NULL;
1099566063dSJacob Faibussowitsch   PetscCall(PetscNew(&scheme));
1103d177a5cSEmil Constantinescu   scheme->p = p;
1113d177a5cSEmil Constantinescu   scheme->q = q;
1123d177a5cSEmil Constantinescu   scheme->r = r;
1133d177a5cSEmil Constantinescu   scheme->s = s;
1143d177a5cSEmil Constantinescu 
1159566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(s, &scheme->c, s * s, &scheme->a, r * s, &scheme->b, r * s, &scheme->u, r * r, &scheme->v));
1169566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(scheme->c, c, s));
1173d177a5cSEmil Constantinescu   for (j = 0; j < s * s; j++) scheme->a[j] = (PetscAbsScalar(a[j]) < 1e-12) ? 0 : a[j];
1183d177a5cSEmil Constantinescu   for (j = 0; j < r * s; j++) scheme->b[j] = (PetscAbsScalar(b[j]) < 1e-12) ? 0 : b[j];
1193d177a5cSEmil Constantinescu   for (j = 0; j < s * r; j++) scheme->u[j] = (PetscAbsScalar(u[j]) < 1e-12) ? 0 : u[j];
1203d177a5cSEmil Constantinescu   for (j = 0; j < r * r; j++) scheme->v[j] = (PetscAbsScalar(v[j]) < 1e-12) ? 0 : v[j];
1213d177a5cSEmil Constantinescu 
1229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(r, &scheme->alpha, r, &scheme->beta, r, &scheme->gamma, 3 * s, &scheme->phi, 3 * r, &scheme->psi, r, &scheme->stage_error));
1233d177a5cSEmil Constantinescu   {
1243d177a5cSEmil Constantinescu     PetscInt     i, j, k, ss = s + 2;
1253d177a5cSEmil Constantinescu     PetscBLASInt m, n, one = 1, *ipiv, lwork = 4 * ((s + 3) * 3 + 3), info, ldb;
1263d177a5cSEmil Constantinescu     PetscReal    rcond, *sing, *workreal;
1273d177a5cSEmil Constantinescu     PetscScalar *ImV, *H, *bmat, *workscalar, *c = scheme->c, *a = scheme->a, *b = scheme->b, *u = scheme->u, *v = scheme->v;
1283d177a5cSEmil Constantinescu     PetscBLASInt rank;
1299566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(PetscSqr(r), &ImV, 3 * s, &H, 3 * ss, &bmat, lwork, &workscalar, 5 * (3 + r), &workreal, r + s, &sing, r + s, &ipiv));
1303d177a5cSEmil Constantinescu 
1313d177a5cSEmil Constantinescu     /* column-major input */
1323d177a5cSEmil Constantinescu     for (i = 0; i < r - 1; i++) {
1333d177a5cSEmil Constantinescu       for (j = 0; j < r - 1; j++) ImV[i + j * r] = 1.0 * (i == j) - v[(i + 1) * r + j + 1];
1343d177a5cSEmil Constantinescu     }
1353d177a5cSEmil Constantinescu     /* Build right hand side for alpha (tp - glm.B(2:end,:)*(glm.c.^(p)./factorial(p))) */
1363d177a5cSEmil Constantinescu     for (i = 1; i < r; i++) {
1373d177a5cSEmil Constantinescu       scheme->alpha[i] = 1. / Factorial(p + 1 - i);
1383d177a5cSEmil Constantinescu       for (j = 0; j < s; j++) scheme->alpha[i] -= b[i * s + j] * CPowF(c[j], p);
1393d177a5cSEmil Constantinescu     }
1409566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(r - 1, &m));
1419566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(r, &n));
142792fecdfSBarry Smith     PetscCallBLAS("LAPACKgesv", LAPACKgesv_(&m, &one, ImV, &n, ipiv, scheme->alpha + 1, &n, &info));
14308401ef6SPierre Jolivet     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GESV");
14408401ef6SPierre Jolivet     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_MAT_LU_ZRPVT, "Bad LU factorization");
1453d177a5cSEmil Constantinescu 
1463d177a5cSEmil Constantinescu     /* Build right hand side for beta (tp1 - glm.B(2:end,:)*(glm.c.^(p+1)./factorial(p+1)) - e.alpha) */
1473d177a5cSEmil Constantinescu     for (i = 1; i < r; i++) {
1483d177a5cSEmil Constantinescu       scheme->beta[i] = 1. / Factorial(p + 2 - i) - scheme->alpha[i];
1493d177a5cSEmil Constantinescu       for (j = 0; j < s; j++) scheme->beta[i] -= b[i * s + j] * CPowF(c[j], p + 1);
1503d177a5cSEmil Constantinescu     }
151792fecdfSBarry Smith     PetscCallBLAS("LAPACKgetrs", LAPACKgetrs_("No transpose", &m, &one, ImV, &n, ipiv, scheme->beta + 1, &n, &info));
15208401ef6SPierre Jolivet     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GETRS");
15308401ef6SPierre Jolivet     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Should not happen");
1543d177a5cSEmil Constantinescu 
1553d177a5cSEmil Constantinescu     /* Build stage_error vector
1563d177a5cSEmil Constantinescu            xi = glm.c.^(p+1)/factorial(p+1) - glm.A*glm.c.^p/factorial(p) + glm.U(:,2:end)*e.alpha;
1573d177a5cSEmil Constantinescu     */
1583d177a5cSEmil Constantinescu     for (i = 0; i < s; i++) {
1593d177a5cSEmil Constantinescu       scheme->stage_error[i] = CPowF(c[i], p + 1);
1603d177a5cSEmil Constantinescu       for (j = 0; j < s; j++) scheme->stage_error[i] -= a[i * s + j] * CPowF(c[j], p);
1613d177a5cSEmil Constantinescu       for (j = 1; j < r; j++) scheme->stage_error[i] += u[i * r + j] * scheme->alpha[j];
1623d177a5cSEmil Constantinescu     }
1633d177a5cSEmil Constantinescu 
1643d177a5cSEmil Constantinescu     /* alpha[0] (epsilon in B,J,W 2007)
1653d177a5cSEmil Constantinescu            epsilon = 1/factorial(p+1) - B(1,:)*c.^p/factorial(p) + V(1,2:end)*e.alpha;
1663d177a5cSEmil Constantinescu     */
1673d177a5cSEmil Constantinescu     scheme->alpha[0] = 1. / Factorial(p + 1);
1683d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) scheme->alpha[0] -= b[0 * s + j] * CPowF(c[j], p);
1693d177a5cSEmil Constantinescu     for (j = 1; j < r; j++) scheme->alpha[0] += v[0 * r + j] * scheme->alpha[j];
1703d177a5cSEmil Constantinescu 
1713d177a5cSEmil Constantinescu     /* right hand side for gamma (glm.B(2:end,:)*e.xi - e.epsilon*eye(s-1,1)) */
1723d177a5cSEmil Constantinescu     for (i = 1; i < r; i++) {
1733d177a5cSEmil Constantinescu       scheme->gamma[i] = (i == 1 ? -1. : 0) * scheme->alpha[0];
1743d177a5cSEmil Constantinescu       for (j = 0; j < s; j++) scheme->gamma[i] += b[i * s + j] * scheme->stage_error[j];
1753d177a5cSEmil Constantinescu     }
176792fecdfSBarry Smith     PetscCallBLAS("LAPACKgetrs", LAPACKgetrs_("No transpose", &m, &one, ImV, &n, ipiv, scheme->gamma + 1, &n, &info));
17708401ef6SPierre Jolivet     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GETRS");
17808401ef6SPierre Jolivet     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Should not happen");
1793d177a5cSEmil Constantinescu 
1803d177a5cSEmil Constantinescu     /* beta[0] (rho in B,J,W 2007)
1813d177a5cSEmil Constantinescu         e.rho = 1/factorial(p+2) - glm.B(1,:)*glm.c.^(p+1)/factorial(p+1) ...
1823d177a5cSEmil Constantinescu             + glm.V(1,2:end)*e.beta;% - e.epsilon;
1833d177a5cSEmil Constantinescu     % Note: The paper (B,J,W 2007) includes the last term in their definition
1843d177a5cSEmil Constantinescu     * */
1853d177a5cSEmil Constantinescu     scheme->beta[0] = 1. / Factorial(p + 2);
1863d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) scheme->beta[0] -= b[0 * s + j] * CPowF(c[j], p + 1);
1873d177a5cSEmil Constantinescu     for (j = 1; j < r; j++) scheme->beta[0] += v[0 * r + j] * scheme->beta[j];
1883d177a5cSEmil Constantinescu 
1893d177a5cSEmil Constantinescu     /* gamma[0] (sigma in B,J,W 2007)
1903d177a5cSEmil Constantinescu     *   e.sigma = glm.B(1,:)*e.xi + glm.V(1,2:end)*e.gamma;
1913d177a5cSEmil Constantinescu     * */
1923d177a5cSEmil Constantinescu     scheme->gamma[0] = 0.0;
1933d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) scheme->gamma[0] += b[0 * s + j] * scheme->stage_error[j];
1943d177a5cSEmil Constantinescu     for (j = 1; j < r; j++) scheme->gamma[0] += v[0 * s + j] * scheme->gamma[j];
1953d177a5cSEmil Constantinescu 
1963d177a5cSEmil Constantinescu     /* Assemble H
19763a3b9bcSJacob Faibussowitsch     *    % " PetscInt_FMT "etermine the error estimators phi
1983d177a5cSEmil Constantinescu        H = [[cpow(glm.c,p) + C*e.alpha] [cpow(glm.c,p+1) + C*e.beta] ...
1993d177a5cSEmil Constantinescu                [e.xi - C*(e.gamma + 0*e.epsilon*eye(s-1,1))]]';
2003d177a5cSEmil Constantinescu     % Paper has formula above without the 0, but that term must be left
2013d177a5cSEmil Constantinescu     % out to satisfy the conditions they propose and to make the
2023d177a5cSEmil Constantinescu     % example schemes work
2033d177a5cSEmil Constantinescu     e.H = H;
2043d177a5cSEmil Constantinescu     e.phi = (H \ [1 0 0;1 1 0;0 0 -1])';
2053d177a5cSEmil Constantinescu     e.psi = -e.phi*C;
2063d177a5cSEmil Constantinescu     * */
2073d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) {
2083d177a5cSEmil Constantinescu       H[0 + j * 3] = CPowF(c[j], p);
2093d177a5cSEmil Constantinescu       H[1 + j * 3] = CPowF(c[j], p + 1);
2103d177a5cSEmil Constantinescu       H[2 + j * 3] = scheme->stage_error[j];
2113d177a5cSEmil Constantinescu       for (k = 1; k < r; k++) {
2123d177a5cSEmil Constantinescu         H[0 + j * 3] += CPowF(c[j], k - 1) * scheme->alpha[k];
2133d177a5cSEmil Constantinescu         H[1 + j * 3] += CPowF(c[j], k - 1) * scheme->beta[k];
2143d177a5cSEmil Constantinescu         H[2 + j * 3] -= CPowF(c[j], k - 1) * scheme->gamma[k];
2153d177a5cSEmil Constantinescu       }
2163d177a5cSEmil Constantinescu     }
2179371c9d4SSatish Balay     bmat[0 + 0 * ss] = 1.;
2189371c9d4SSatish Balay     bmat[0 + 1 * ss] = 0.;
2199371c9d4SSatish Balay     bmat[0 + 2 * ss] = 0.;
2209371c9d4SSatish Balay     bmat[1 + 0 * ss] = 1.;
2219371c9d4SSatish Balay     bmat[1 + 1 * ss] = 1.;
2229371c9d4SSatish Balay     bmat[1 + 2 * ss] = 0.;
2239371c9d4SSatish Balay     bmat[2 + 0 * ss] = 0.;
2249371c9d4SSatish Balay     bmat[2 + 1 * ss] = 0.;
2259371c9d4SSatish Balay     bmat[2 + 2 * ss] = -1.;
2263d177a5cSEmil Constantinescu     m                = 3;
2279566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(s, &n));
2289566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(ss, &ldb));
2293d177a5cSEmil Constantinescu     rcond = 1e-12;
2303d177a5cSEmil Constantinescu #if defined(PETSC_USE_COMPLEX)
2313d177a5cSEmil Constantinescu     /* ZGELSS( M, N, NRHS, A, LDA, B, LDB, S, RCOND, RANK, WORK, LWORK, RWORK, INFO) */
232792fecdfSBarry Smith     PetscCallBLAS("LAPACKgelss", LAPACKgelss_(&m, &n, &m, H, &m, bmat, &ldb, sing, &rcond, &rank, workscalar, &lwork, workreal, &info));
2333d177a5cSEmil Constantinescu #else
2343d177a5cSEmil Constantinescu     /* DGELSS( M, N, NRHS, A, LDA, B, LDB, S, RCOND, RANK, WORK, LWORK, INFO) */
235792fecdfSBarry Smith     PetscCallBLAS("LAPACKgelss", LAPACKgelss_(&m, &n, &m, H, &m, bmat, &ldb, sing, &rcond, &rank, workscalar, &lwork, &info));
2363d177a5cSEmil Constantinescu #endif
23708401ef6SPierre Jolivet     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GELSS");
23808401ef6SPierre Jolivet     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "SVD failed to converge");
2393d177a5cSEmil Constantinescu 
2403d177a5cSEmil Constantinescu     for (j = 0; j < 3; j++) {
2413d177a5cSEmil Constantinescu       for (k = 0; k < s; k++) scheme->phi[k + j * s] = bmat[k + j * ss];
2423d177a5cSEmil Constantinescu     }
2433d177a5cSEmil Constantinescu 
2443d177a5cSEmil Constantinescu     /* the other part of the error estimator, psi in B,J,W 2007 */
2453d177a5cSEmil Constantinescu     scheme->psi[0 * r + 0] = 0.;
2463d177a5cSEmil Constantinescu     scheme->psi[1 * r + 0] = 0.;
2473d177a5cSEmil Constantinescu     scheme->psi[2 * r + 0] = 0.;
2483d177a5cSEmil Constantinescu     for (j = 1; j < r; j++) {
2493d177a5cSEmil Constantinescu       scheme->psi[0 * r + j] = 0.;
2503d177a5cSEmil Constantinescu       scheme->psi[1 * r + j] = 0.;
2513d177a5cSEmil Constantinescu       scheme->psi[2 * r + j] = 0.;
2523d177a5cSEmil Constantinescu       for (k = 0; k < s; k++) {
2533d177a5cSEmil Constantinescu         scheme->psi[0 * r + j] -= CPowF(c[k], j - 1) * scheme->phi[0 * s + k];
2543d177a5cSEmil Constantinescu         scheme->psi[1 * r + j] -= CPowF(c[k], j - 1) * scheme->phi[1 * s + k];
2553d177a5cSEmil Constantinescu         scheme->psi[2 * r + j] -= CPowF(c[k], j - 1) * scheme->phi[2 * s + k];
2563d177a5cSEmil Constantinescu       }
2573d177a5cSEmil Constantinescu     }
2589566063dSJacob Faibussowitsch     PetscCall(PetscFree7(ImV, H, bmat, workscalar, workreal, sing, ipiv));
2593d177a5cSEmil Constantinescu   }
2603d177a5cSEmil Constantinescu   /* Check which properties are satisfied */
2613d177a5cSEmil Constantinescu   scheme->stiffly_accurate = PETSC_TRUE;
2623d177a5cSEmil Constantinescu   if (scheme->c[s - 1] != 1.) scheme->stiffly_accurate = PETSC_FALSE;
2639371c9d4SSatish Balay   for (j = 0; j < s; j++)
2649371c9d4SSatish Balay     if (a[(s - 1) * s + j] != b[j]) scheme->stiffly_accurate = PETSC_FALSE;
2659371c9d4SSatish Balay   for (j = 0; j < r; j++)
2669371c9d4SSatish Balay     if (u[(s - 1) * r + j] != v[j]) scheme->stiffly_accurate = PETSC_FALSE;
2673d177a5cSEmil Constantinescu   scheme->fsal = scheme->stiffly_accurate; /* FSAL is stronger */
2689371c9d4SSatish Balay   for (j = 0; j < s - 1; j++)
2699371c9d4SSatish Balay     if (r > 1 && b[1 * s + j] != 0.) scheme->fsal = PETSC_FALSE;
2703d177a5cSEmil Constantinescu   if (b[1 * s + r - 1] != 1.) scheme->fsal = PETSC_FALSE;
2719371c9d4SSatish Balay   for (j = 0; j < r; j++)
2729371c9d4SSatish Balay     if (r > 1 && v[1 * r + j] != 0.) scheme->fsal = PETSC_FALSE;
2733d177a5cSEmil Constantinescu 
2743d177a5cSEmil Constantinescu   *inscheme = scheme;
2753d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
2763d177a5cSEmil Constantinescu }
2773d177a5cSEmil Constantinescu 
2789371c9d4SSatish Balay static PetscErrorCode TSGLLESchemeDestroy(TSGLLEScheme sc) {
2793d177a5cSEmil Constantinescu   PetscFunctionBegin;
2809566063dSJacob Faibussowitsch   PetscCall(PetscFree5(sc->c, sc->a, sc->b, sc->u, sc->v));
2819566063dSJacob Faibussowitsch   PetscCall(PetscFree6(sc->alpha, sc->beta, sc->gamma, sc->phi, sc->psi, sc->stage_error));
2829566063dSJacob Faibussowitsch   PetscCall(PetscFree(sc));
2833d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
2843d177a5cSEmil Constantinescu }
2853d177a5cSEmil Constantinescu 
2869371c9d4SSatish Balay static PetscErrorCode TSGLLEDestroy_Default(TS_GLLE *gl) {
2873d177a5cSEmil Constantinescu   PetscInt i;
2883d177a5cSEmil Constantinescu 
2893d177a5cSEmil Constantinescu   PetscFunctionBegin;
2903d177a5cSEmil Constantinescu   for (i = 0; i < gl->nschemes; i++) {
2919566063dSJacob Faibussowitsch     if (gl->schemes[i]) PetscCall(TSGLLESchemeDestroy(gl->schemes[i]));
2923d177a5cSEmil Constantinescu   }
2939566063dSJacob Faibussowitsch   PetscCall(PetscFree(gl->schemes));
2943d177a5cSEmil Constantinescu   gl->nschemes = 0;
2959566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(gl->type_name, sizeof(gl->type_name)));
2963d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
2973d177a5cSEmil Constantinescu }
2983d177a5cSEmil Constantinescu 
2999371c9d4SSatish Balay static PetscErrorCode TSGLLEViewTable_Private(PetscViewer viewer, PetscInt m, PetscInt n, const PetscScalar a[], const char name[]) {
3003d177a5cSEmil Constantinescu   PetscBool iascii;
3013d177a5cSEmil Constantinescu   PetscInt  i, j;
3023d177a5cSEmil Constantinescu 
3033d177a5cSEmil Constantinescu   PetscFunctionBegin;
3049566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
3053d177a5cSEmil Constantinescu   if (iascii) {
3069566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "%30s = [", name));
3073d177a5cSEmil Constantinescu     for (i = 0; i < m; i++) {
3089566063dSJacob Faibussowitsch       if (i) PetscCall(PetscViewerASCIIPrintf(viewer, "%30s   [", ""));
3099566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
310*48a46eb9SPierre Jolivet       for (j = 0; j < n; j++) PetscCall(PetscViewerASCIIPrintf(viewer, " %12.8g", (double)PetscRealPart(a[i * n + j])));
3119566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "]\n"));
3129566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
3133d177a5cSEmil Constantinescu     }
3143d177a5cSEmil Constantinescu   }
3153d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
3163d177a5cSEmil Constantinescu }
3173d177a5cSEmil Constantinescu 
3189371c9d4SSatish Balay static PetscErrorCode TSGLLESchemeView(TSGLLEScheme sc, PetscBool view_details, PetscViewer viewer) {
3193d177a5cSEmil Constantinescu   PetscBool iascii;
3203d177a5cSEmil Constantinescu 
3213d177a5cSEmil Constantinescu   PetscFunctionBegin;
3229566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
3233d177a5cSEmil Constantinescu   if (iascii) {
32463a3b9bcSJacob Faibussowitsch     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));
3259566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
3269566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Stiffly accurate: %s,  FSAL: %s\n", sc->stiffly_accurate ? "yes" : "no", sc->fsal ? "yes" : "no"));
3279371c9d4SSatish Balay     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])));
3289566063dSJacob Faibussowitsch     PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->s, sc->c, "Abscissas c"));
3293d177a5cSEmil Constantinescu     if (view_details) {
3309566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, sc->s, sc->s, sc->a, "A"));
3319566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, sc->r, sc->s, sc->b, "B"));
3329566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, sc->s, sc->r, sc->u, "U"));
3339566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, sc->r, sc->r, sc->v, "V"));
3343d177a5cSEmil Constantinescu 
3359566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 3, sc->s, sc->phi, "Error estimate phi"));
3369566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 3, sc->r, sc->psi, "Error estimate psi"));
3379566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->r, sc->alpha, "Modify alpha"));
3389566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->r, sc->beta, "Modify beta"));
3399566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->r, sc->gamma, "Modify gamma"));
3409566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->s, sc->stage_error, "Stage error xi"));
3413d177a5cSEmil Constantinescu     }
3429566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
34398921bdaSJacob Faibussowitsch   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Viewer type %s not supported", ((PetscObject)viewer)->type_name);
3443d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
3453d177a5cSEmil Constantinescu }
3463d177a5cSEmil Constantinescu 
3479371c9d4SSatish Balay static PetscErrorCode TSGLLEEstimateHigherMoments_Default(TSGLLEScheme sc, PetscReal h, Vec Ydot[], Vec Xold[], Vec hm[]) {
3483d177a5cSEmil Constantinescu   PetscInt i;
3493d177a5cSEmil Constantinescu 
3503d177a5cSEmil Constantinescu   PetscFunctionBegin;
351cad9d221SBarry Smith   PetscCheck(sc->r <= 64 && sc->s <= 64, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Ridiculous number of stages or items passed between stages");
3523d177a5cSEmil Constantinescu   /* build error vectors*/
3533d177a5cSEmil Constantinescu   for (i = 0; i < 3; i++) {
3543d177a5cSEmil Constantinescu     PetscScalar phih[64];
3553d177a5cSEmil Constantinescu     PetscInt    j;
3563d177a5cSEmil Constantinescu     for (j = 0; j < sc->s; j++) phih[j] = sc->phi[i * sc->s + j] * h;
3579566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(hm[i]));
3589566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(hm[i], sc->s, phih, Ydot));
3599566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(hm[i], sc->r, &sc->psi[i * sc->r], Xold));
3603d177a5cSEmil Constantinescu   }
3613d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
3623d177a5cSEmil Constantinescu }
3633d177a5cSEmil Constantinescu 
3649371c9d4SSatish Balay static PetscErrorCode TSGLLECompleteStep_Rescale(TSGLLEScheme sc, PetscReal h, TSGLLEScheme next_sc, PetscReal next_h, Vec Ydot[], Vec Xold[], Vec X[]) {
3653d177a5cSEmil Constantinescu   PetscScalar brow[32], vrow[32];
3663d177a5cSEmil Constantinescu   PetscInt    i, j, r, s;
3673d177a5cSEmil Constantinescu 
3683d177a5cSEmil Constantinescu   PetscFunctionBegin;
3693d177a5cSEmil Constantinescu   /* Build the new solution from (X,Ydot) */
3703d177a5cSEmil Constantinescu   r = sc->r;
3713d177a5cSEmil Constantinescu   s = sc->s;
3723d177a5cSEmil Constantinescu   for (i = 0; i < r; i++) {
3739566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(X[i]));
3743d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) brow[j] = h * sc->b[i * s + j];
3759566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[i], s, brow, Ydot));
3763d177a5cSEmil Constantinescu     for (j = 0; j < r; j++) vrow[j] = sc->v[i * r + j];
3779566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[i], r, vrow, Xold));
3783d177a5cSEmil Constantinescu   }
3793d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
3803d177a5cSEmil Constantinescu }
3813d177a5cSEmil Constantinescu 
3829371c9d4SSatish Balay static PetscErrorCode TSGLLECompleteStep_RescaleAndModify(TSGLLEScheme sc, PetscReal h, TSGLLEScheme next_sc, PetscReal next_h, Vec Ydot[], Vec Xold[], Vec X[]) {
3833d177a5cSEmil Constantinescu   PetscScalar brow[32], vrow[32];
3843d177a5cSEmil Constantinescu   PetscReal   ratio;
3853d177a5cSEmil Constantinescu   PetscInt    i, j, p, r, s;
3863d177a5cSEmil Constantinescu 
3873d177a5cSEmil Constantinescu   PetscFunctionBegin;
3883d177a5cSEmil Constantinescu   /* Build the new solution from (X,Ydot) */
3893d177a5cSEmil Constantinescu   p     = sc->p;
3903d177a5cSEmil Constantinescu   r     = sc->r;
3913d177a5cSEmil Constantinescu   s     = sc->s;
3923d177a5cSEmil Constantinescu   ratio = next_h / h;
3933d177a5cSEmil Constantinescu   for (i = 0; i < r; i++) {
3949566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(X[i]));
3953d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) {
3969371c9d4SSatish Balay       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]));
3973d177a5cSEmil Constantinescu     }
3989566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[i], s, brow, Ydot));
3993d177a5cSEmil Constantinescu     for (j = 0; j < r; j++) {
4009371c9d4SSatish Balay       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]));
4013d177a5cSEmil Constantinescu     }
4029566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[i], r, vrow, Xold));
4033d177a5cSEmil Constantinescu   }
4043d177a5cSEmil Constantinescu   if (r < next_sc->r) {
40508401ef6SPierre Jolivet     PetscCheck(r + 1 == next_sc->r, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot accommodate jump in r greater than 1");
4069566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(X[r]));
4073d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) brow[j] = h * PetscPowRealInt(ratio, p + 1) * sc->phi[0 * s + j];
4089566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[r], s, brow, Ydot));
4093d177a5cSEmil Constantinescu     for (j = 0; j < r; j++) vrow[j] = PetscPowRealInt(ratio, p + 1) * sc->psi[0 * r + j];
4109566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[r], r, vrow, Xold));
4113d177a5cSEmil Constantinescu   }
4123d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
4133d177a5cSEmil Constantinescu }
4143d177a5cSEmil Constantinescu 
4159371c9d4SSatish Balay static PetscErrorCode TSGLLECreate_IRKS(TS ts) {
4163d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
4173d177a5cSEmil Constantinescu 
4183d177a5cSEmil Constantinescu   PetscFunctionBegin;
4193d177a5cSEmil Constantinescu   gl->Destroy               = TSGLLEDestroy_Default;
4203d177a5cSEmil Constantinescu   gl->EstimateHigherMoments = TSGLLEEstimateHigherMoments_Default;
4213d177a5cSEmil Constantinescu   gl->CompleteStep          = TSGLLECompleteStep_RescaleAndModify;
4229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(10, &gl->schemes));
4233d177a5cSEmil Constantinescu   gl->nschemes = 0;
4243d177a5cSEmil Constantinescu 
4253d177a5cSEmil Constantinescu   {
4263d177a5cSEmil Constantinescu     /* p=1,q=1, r=s=2, A- and L-stable with error estimates of order 2 and 3
4273d177a5cSEmil Constantinescu     * Listed in Butcher & Podhaisky 2006. On error estimation in general linear methods for stiff ODE.
4283d177a5cSEmil Constantinescu     * irks(0.3,0,[.3,1],[1],1)
4293d177a5cSEmil Constantinescu     * Note: can be made to have classical order (not stage order) 2 by replacing 0.3 with 1-sqrt(1/2)
4303d177a5cSEmil Constantinescu     * but doing so would sacrifice the error estimator.
4313d177a5cSEmil Constantinescu     */
4323d177a5cSEmil Constantinescu     const PetscScalar c[2]    = {3. / 10., 1.};
4339371c9d4SSatish Balay     const PetscScalar a[2][2] = {
4349371c9d4SSatish Balay       {3. / 10., 0       },
4359371c9d4SSatish Balay       {7. / 10., 3. / 10.}
4369371c9d4SSatish Balay     };
4379371c9d4SSatish Balay     const PetscScalar b[2][2] = {
4389371c9d4SSatish Balay       {7. / 10., 3. / 10.},
4399371c9d4SSatish Balay       {0,        1       }
4409371c9d4SSatish Balay     };
4419371c9d4SSatish Balay     const PetscScalar u[2][2] = {
4429371c9d4SSatish Balay       {1, 0},
4439371c9d4SSatish Balay       {1, 0}
4449371c9d4SSatish Balay     };
4459371c9d4SSatish Balay     const PetscScalar v[2][2] = {
4469371c9d4SSatish Balay       {1, 0},
4479371c9d4SSatish Balay       {0, 0}
4489371c9d4SSatish Balay     };
4499566063dSJacob Faibussowitsch     PetscCall(TSGLLESchemeCreate(1, 1, 2, 2, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
4503d177a5cSEmil Constantinescu   }
4513d177a5cSEmil Constantinescu 
4523d177a5cSEmil Constantinescu   {
4533d177a5cSEmil Constantinescu     /* p=q=2, r=s=3: irks(4/9,0,[1:3]/3,[0.33852],1) */
4543d177a5cSEmil Constantinescu     /* http://www.math.auckland.ac.nz/~hpod/atlas/i2a.html */
45597a1619fSSatish Balay     const PetscScalar c[3]    = {1. / 3., 2. / 3., 1};
45697a1619fSSatish Balay     const PetscScalar a[3][3] = {
45797a1619fSSatish Balay       {4. / 9.,              0,                     0      },
45897a1619fSSatish Balay       {1.03750643704090e+00, 4. / 9.,               0      },
45997a1619fSSatish Balay       {7.67024779410304e-01, -3.81140216918943e-01, 4. / 9.}
46097a1619fSSatish Balay     };
46197a1619fSSatish Balay     const PetscScalar b[3][3] = {
46297a1619fSSatish Balay       {0.767024779410304,  -0.381140216918943, 4. / 9.          },
46397a1619fSSatish Balay       {0.000000000000000,  0.000000000000000,  1.000000000000000},
46497a1619fSSatish Balay       {-2.075048385225385, 0.621728385225383,  1.277197204924873}
46597a1619fSSatish Balay     };
46697a1619fSSatish Balay     const PetscScalar u[3][3] = {
46797a1619fSSatish Balay       {1.0000000000000000, -0.1111111111111109, -0.0925925925925922},
46897a1619fSSatish Balay       {1.0000000000000000, -0.8152842148186744, -0.4199095530877056},
46997a1619fSSatish Balay       {1.0000000000000000, 0.1696709930641948,  0.0539741070314165 }
47097a1619fSSatish Balay     };
47197a1619fSSatish Balay     const PetscScalar v[3][3] = {
47297a1619fSSatish Balay       {1.0000000000000000, 0.1696709930641948, 0.0539741070314165},
47397a1619fSSatish Balay       {0.000000000000000,  0.000000000000000,  0.000000000000000 },
47497a1619fSSatish Balay       {0.000000000000000,  0.176122795075129,  0.000000000000000 }
47597a1619fSSatish Balay     };
4769566063dSJacob Faibussowitsch     PetscCall(TSGLLESchemeCreate(2, 2, 3, 3, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
4773d177a5cSEmil Constantinescu   }
4783d177a5cSEmil Constantinescu   {
4793d177a5cSEmil Constantinescu     /* p=q=3, r=s=4: irks(9/40,0,[1:4]/4,[0.3312 1.0050],[0.49541 1;1 0]) */
48097a1619fSSatish Balay     const PetscScalar c[4]    = {0.25, 0.5, 0.75, 1.0};
48197a1619fSSatish Balay     const PetscScalar a[4][4] = {
48297a1619fSSatish Balay       {9. / 40.,             0,                     0,                 0       },
48397a1619fSSatish Balay       {2.11286958887701e-01, 9. / 40.,              0,                 0       },
48497a1619fSSatish Balay       {9.46338294287584e-01, -3.42942861246094e-01, 9. / 40.,          0       },
48597a1619fSSatish Balay       {0.521490453970721,    -0.662474225622980,    0.490476425459734, 9. / 40.}
48697a1619fSSatish Balay     };
48797a1619fSSatish Balay     const PetscScalar b[4][4] = {
48897a1619fSSatish Balay       {0.521490453970721,  -0.662474225622980, 0.490476425459734,  9. / 40.         },
48997a1619fSSatish Balay       {0.000000000000000,  0.000000000000000,  0.000000000000000,  1.000000000000000},
49097a1619fSSatish Balay       {-0.084677029310348, 1.390757514776085,  -1.568157386206001, 2.023192696767826},
49197a1619fSSatish Balay       {0.465383797936408,  1.478273530625148,  -1.930836081010182, 1.644872111193354}
49297a1619fSSatish Balay     };
49397a1619fSSatish Balay     const PetscScalar u[4][4] = {
49497a1619fSSatish Balay       {1.00000000000000000, 0.02500000000001035,  -0.02499999999999053, -0.00442708333332865},
49597a1619fSSatish Balay       {1.00000000000000000, 0.06371304111232945,  -0.04032173972189845, -0.01389438413189452},
49697a1619fSSatish Balay       {1.00000000000000000, -0.07839543304147778, 0.04738685705116663,  0.02032603595928376 },
49797a1619fSSatish Balay       {1.00000000000000000, 0.42550734619251651,  0.10800718022400080,  -0.01726712647760034}
49897a1619fSSatish Balay     };
49997a1619fSSatish Balay     const PetscScalar v[4][4] = {
50097a1619fSSatish Balay       {1.00000000000000000, 0.42550734619251651, 0.10800718022400080, -0.01726712647760034},
50197a1619fSSatish Balay       {0.000000000000000,   0.000000000000000,   0.000000000000000,   0.000000000000000   },
50297a1619fSSatish Balay       {0.000000000000000,   -1.761115796027561,  -0.521284157173780,  0.258249384305463   },
50397a1619fSSatish Balay       {0.000000000000000,   -1.657693358744728,  -1.052227765232394,  0.521284157173780   }
50497a1619fSSatish Balay     };
5059566063dSJacob Faibussowitsch     PetscCall(TSGLLESchemeCreate(3, 3, 4, 4, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
5063d177a5cSEmil Constantinescu   }
5073d177a5cSEmil Constantinescu   {
5083d177a5cSEmil Constantinescu     /* p=q=4, r=s=5:
5093d177a5cSEmil Constantinescu           irks(3/11,0,[1:5]/5, [0.1715   -0.1238    0.6617],...
5103d177a5cSEmil Constantinescu           [ -0.0812    0.4079    1.0000
5113d177a5cSEmil Constantinescu              1.0000         0         0
5123d177a5cSEmil Constantinescu              0.8270    1.0000         0])
5133d177a5cSEmil Constantinescu     */
51497a1619fSSatish Balay     const PetscScalar c[5]    = {0.2, 0.4, 0.6, 0.8, 1.0};
51597a1619fSSatish Balay     const PetscScalar a[5][5] = {
51697a1619fSSatish Balay       {2.72727272727352e-01,  0.00000000000000e+00,  0.00000000000000e+00,  0.00000000000000e+00, 0.00000000000000e+00},
51797a1619fSSatish Balay       {-1.03980153733431e-01, 2.72727272727405e-01,  0.00000000000000e+00,  0.00000000000000e+00, 0.00000000000000e+00},
51897a1619fSSatish Balay       {-1.58615400341492e+00, 7.44168951881122e-01,  2.72727272727309e-01,  0.00000000000000e+00, 0.00000000000000e+00},
51997a1619fSSatish Balay       {-8.73658042865628e-01, 5.37884671894595e-01,  -1.63298538799523e-01, 2.72727272726996e-01, 0.00000000000000e+00},
52097a1619fSSatish Balay       {2.95489397443992e-01,  -1.18481693910097e+00, -6.68029812659953e-01, 1.00716687860943e+00, 2.72727272727288e-01}
52197a1619fSSatish Balay     };
52297a1619fSSatish Balay     const PetscScalar b[5][5] = {
52397a1619fSSatish Balay       {2.95489397443992e-01,  -1.18481693910097e+00, -6.68029812659953e-01, 1.00716687860943e+00,  2.72727272727288e-01},
52497a1619fSSatish Balay       {0.00000000000000e+00,  1.11022302462516e-16,  -2.22044604925031e-16, 0.00000000000000e+00,  1.00000000000000e+00},
52597a1619fSSatish Balay       {-4.05882503986005e+00, -4.00924006567769e+00, -1.38930610972481e+00, 4.45223930308488e+00,  6.32331093108427e-01},
52697a1619fSSatish Balay       {8.35690179937017e+00,  -2.26640927349732e+00, 6.86647884973826e+00,  -5.22595158025740e+00, 4.50893068837431e+00},
52797a1619fSSatish Balay       {1.27656267027479e+01,  2.80882153840821e+00,  8.91173096522890e+00,  -1.07936444078906e+01, 4.82534148988854e+00}
52897a1619fSSatish Balay     };
52997a1619fSSatish Balay     const PetscScalar u[5][5] = {
53097a1619fSSatish Balay       {1.00000000000000e+00, -7.27272727273551e-02, -3.45454545454419e-02, -4.12121212119565e-03, -2.96969696964014e-04},
53197a1619fSSatish Balay       {1.00000000000000e+00, 2.31252881006154e-01,  -8.29487834416481e-03, -9.07191207681020e-03, -1.70378403743473e-03},
53297a1619fSSatish Balay       {1.00000000000000e+00, 1.16925777880663e+00,  3.59268562942635e-02,  -4.09013451730615e-02, -1.02411119670164e-02},
53397a1619fSSatish Balay       {1.00000000000000e+00, 1.02634463704356e+00,  1.59375044913405e-01,  1.89673015035370e-03,  -4.89987231897569e-03},
53497a1619fSSatish Balay       {1.00000000000000e+00, 1.27746320298021e+00,  2.37186008132728e-01,  -8.28694373940065e-02, -5.34396510196430e-02}
53597a1619fSSatish Balay     };
53697a1619fSSatish Balay     const PetscScalar v[5][5] = {
53797a1619fSSatish Balay       {1.00000000000000e+00, 1.27746320298021e+00,  2.37186008132728e-01,  -8.28694373940065e-02, -5.34396510196430e-02},
53897a1619fSSatish Balay       {0.00000000000000e+00, -1.77635683940025e-15, -1.99840144432528e-15, -9.99200722162641e-16, -3.33066907387547e-16},
53997a1619fSSatish Balay       {0.00000000000000e+00, 4.37280081906924e+00,  5.49221645016377e-02,  -8.88913177394943e-02, 1.12879077989154e-01 },
54097a1619fSSatish Balay       {0.00000000000000e+00, -1.22399504837280e+01, -5.21287338448645e+00, -8.03952325565291e-01, 4.60298678047147e-01 },
54197a1619fSSatish Balay       {0.00000000000000e+00, -1.85178762883829e+01, -5.21411849862624e+00, -1.04283436528809e+00, 7.49030161063651e-01 }
54297a1619fSSatish Balay     };
5439566063dSJacob Faibussowitsch     PetscCall(TSGLLESchemeCreate(4, 4, 5, 5, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
5443d177a5cSEmil Constantinescu   }
5453d177a5cSEmil Constantinescu   {
5463d177a5cSEmil Constantinescu     /* p=q=5, r=s=6;
5473d177a5cSEmil Constantinescu        irks(1/3,0,[1:6]/6,...
5483d177a5cSEmil Constantinescu           [-0.0489    0.4228   -0.8814    0.9021],...
5493d177a5cSEmil Constantinescu           [-0.3474   -0.6617    0.6294    0.2129
5503d177a5cSEmil Constantinescu             0.0044   -0.4256   -0.1427   -0.8936
5513d177a5cSEmil Constantinescu            -0.8267    0.4821    0.1371   -0.2557
5523d177a5cSEmil Constantinescu            -0.4426   -0.3855   -0.7514    0.3014])
5533d177a5cSEmil Constantinescu     */
55497a1619fSSatish Balay     const PetscScalar c[6]    = {1. / 6, 2. / 6, 3. / 6, 4. / 6, 5. / 6, 1.};
55597a1619fSSatish Balay     const PetscScalar a[6][6] = {
55697a1619fSSatish Balay       {3.33333333333940e-01,  0,                     0,                     0,                     0,                    0                   },
55797a1619fSSatish Balay       {-8.64423857333350e-02, 3.33333333332888e-01,  0,                     0,                     0,                    0                   },
55897a1619fSSatish Balay       {-2.16850174258252e+00, -2.23619072028839e+00, 3.33333333335204e-01,  0,                     0,                    0                   },
55997a1619fSSatish Balay       {-4.73160970138997e+00, -3.89265344629268e+00, -2.76318716520933e-01, 3.33333333335759e-01,  0,                    0                   },
56097a1619fSSatish Balay       {-6.75187540297338e+00, -7.90756533769377e+00, 7.90245051802259e-01,  -4.48352364517632e-01, 3.33333333328483e-01, 0                   },
56197a1619fSSatish Balay       {-4.26488287921548e+00, -1.19320395589302e+01, 3.38924509887755e+00,  -2.23969848002481e+00, 6.62807710124007e-01, 3.33333333335440e-01}
56297a1619fSSatish Balay     };
56397a1619fSSatish Balay     const PetscScalar b[6][6] = {
56497a1619fSSatish Balay       {-4.26488287921548e+00, -1.19320395589302e+01, 3.38924509887755e+00,  -2.23969848002481e+00, 6.62807710124007e-01,  3.33333333335440e-01 },
56597a1619fSSatish Balay       {-8.88178419700125e-16, 4.44089209850063e-16,  -1.54737334057131e-15, -8.88178419700125e-16, 0.00000000000000e+00,  1.00000000000001e+00 },
56697a1619fSSatish Balay       {-2.87780425770651e+01, -1.13520448264971e+01, 2.62002318943161e+01,  2.56943874812797e+01,  -3.06702268304488e+01, 6.68067773510103e+00 },
56797a1619fSSatish Balay       {5.47971245256474e+01,  6.80366875868284e+01,  -6.50952588861999e+01, -8.28643975339097e+01, 8.17416943896414e+01,  -1.17819043489036e+01},
56897a1619fSSatish Balay       {-2.33332114788869e+02, 6.12942539462634e+01,  -4.91850135865944e+01, 1.82716844135480e+02,  -1.29788173979395e+02, 3.09968095651099e+01 },
56997a1619fSSatish Balay       {-1.72049132343751e+02, 8.60194713593999e+00,  7.98154219170200e-01,  1.50371386053218e+02,  -1.18515423962066e+02, 2.50898277784663e+01 }
57097a1619fSSatish Balay     };
57197a1619fSSatish Balay     const PetscScalar u[6][6] = {
57297a1619fSSatish Balay       {1.00000000000000e+00, -1.66666666666870e-01, -4.16666666664335e-02, -3.85802469124815e-03, -2.25051440302250e-04, -9.64506172339142e-06},
57397a1619fSSatish Balay       {1.00000000000000e+00, 8.64423857327162e-02,  -4.11484912671353e-02, -1.11450903217645e-02, -1.47651050487126e-03, -1.34395070766826e-04},
57497a1619fSSatish Balay       {1.00000000000000e+00, 4.57135912953434e+00,  1.06514719719137e+00,  1.33517564218007e-01,  1.11365952968659e-02,  6.12382756769504e-04 },
57597a1619fSSatish Balay       {1.00000000000000e+00, 9.23391519753404e+00,  2.22431212392095e+00,  2.91823807741891e-01,  2.52058456411084e-02,  1.22800542949647e-03 },
57697a1619fSSatish Balay       {1.00000000000000e+00, 1.48175480533865e+01,  3.73439117461835e+00,  5.14648336541804e-01,  4.76430038853402e-02,  2.56798515502156e-03 },
57797a1619fSSatish Balay       {1.00000000000000e+00, 1.50512347758335e+01,  4.10099701165164e+00,  5.66039141003603e-01,  3.91213893800891e-02,  -2.99136269067853e-03}
57897a1619fSSatish Balay     };
57997a1619fSSatish Balay     const PetscScalar v[6][6] = {
58097a1619fSSatish Balay       {1.00000000000000e+00, 1.50512347758335e+01,  4.10099701165164e+00,  5.66039141003603e-01,  3.91213893800891e-02,  -2.99136269067853e-03},
58197a1619fSSatish Balay       {0.00000000000000e+00, -4.88498130835069e-15, -6.43929354282591e-15, -3.55271367880050e-15, -1.22124532708767e-15, -3.12250225675825e-16},
58297a1619fSSatish Balay       {0.00000000000000e+00, 1.22250171233141e+01,  -1.77150760606169e+00, 3.54516769879390e-01,  6.22298845883398e-01,  2.31647447450276e-01 },
58397a1619fSSatish Balay       {0.00000000000000e+00, -4.48339457331040e+01, -3.57363126641880e-01, 5.18750173123425e-01,  6.55727990241799e-02,  1.63175368287079e-01 },
58497a1619fSSatish Balay       {0.00000000000000e+00, 1.37297394708005e+02,  -1.60145272991317e+00, -5.05319555199441e+00, 1.55328940390990e-01,  9.16629423682464e-01 },
58597a1619fSSatish Balay       {0.00000000000000e+00, 1.05703241119022e+02,  -1.16610260983038e+00, -2.99767252773859e+00, -1.13472315553890e-01, 1.09742849254729e+00 }
58697a1619fSSatish Balay     };
5879566063dSJacob Faibussowitsch     PetscCall(TSGLLESchemeCreate(5, 5, 6, 6, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
5883d177a5cSEmil Constantinescu   }
5893d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
5903d177a5cSEmil Constantinescu }
5913d177a5cSEmil Constantinescu 
5923d177a5cSEmil Constantinescu /*@C
5933d177a5cSEmil Constantinescu    TSGLLESetType - sets the class of general linear method to use for time-stepping
5943d177a5cSEmil Constantinescu 
5953d177a5cSEmil Constantinescu    Collective on TS
5963d177a5cSEmil Constantinescu 
5973d177a5cSEmil Constantinescu    Input Parameters:
5983d177a5cSEmil Constantinescu +  ts - the TS context
5993d177a5cSEmil Constantinescu -  type - a method
6003d177a5cSEmil Constantinescu 
6013d177a5cSEmil Constantinescu    Options Database Key:
6023d177a5cSEmil Constantinescu .  -ts_gl_type <type> - sets the method, use -help for a list of available method (e.g. irks)
6033d177a5cSEmil Constantinescu 
6043d177a5cSEmil Constantinescu    Notes:
6053d177a5cSEmil Constantinescu    See "petsc/include/petscts.h" for available methods (for instance)
6063d177a5cSEmil Constantinescu .    TSGLLE_IRKS - Diagonally implicit methods with inherent Runge-Kutta stability (for stiff problems)
6073d177a5cSEmil Constantinescu 
6083d177a5cSEmil Constantinescu    Normally, it is best to use the TSSetFromOptions() command and
6093d177a5cSEmil Constantinescu    then set the TSGLLE type from the options database rather than by using
6103d177a5cSEmil Constantinescu    this routine.  Using the options database provides the user with
6113d177a5cSEmil Constantinescu    maximum flexibility in evaluating the many different solvers.
6123d177a5cSEmil Constantinescu    The TSGLLESetType() routine is provided for those situations where it
6133d177a5cSEmil Constantinescu    is necessary to set the timestepping solver independently of the
6143d177a5cSEmil Constantinescu    command line or options database.  This might be the case, for example,
6153d177a5cSEmil Constantinescu    when the choice of solver changes during the execution of the
6163d177a5cSEmil Constantinescu    program, and the user's application is taking responsibility for
6173d177a5cSEmil Constantinescu    choosing the appropriate method.
6183d177a5cSEmil Constantinescu 
6193d177a5cSEmil Constantinescu    Level: intermediate
6203d177a5cSEmil Constantinescu 
6213d177a5cSEmil Constantinescu @*/
6229371c9d4SSatish Balay PetscErrorCode TSGLLESetType(TS ts, TSGLLEType type) {
6233d177a5cSEmil Constantinescu   PetscFunctionBegin;
6243d177a5cSEmil Constantinescu   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
6253d177a5cSEmil Constantinescu   PetscValidCharPointer(type, 2);
626cac4c232SBarry Smith   PetscTryMethod(ts, "TSGLLESetType_C", (TS, TSGLLEType), (ts, type));
6273d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
6283d177a5cSEmil Constantinescu }
6293d177a5cSEmil Constantinescu 
6303d177a5cSEmil Constantinescu /*@C
6313d177a5cSEmil Constantinescu    TSGLLESetAcceptType - sets the acceptance test
6323d177a5cSEmil Constantinescu 
6333d177a5cSEmil Constantinescu    Time integrators that need to control error must have the option to reject a time step based on local error
6343d177a5cSEmil Constantinescu    estimates.  This function allows different schemes to be set.
6353d177a5cSEmil Constantinescu 
6363d177a5cSEmil Constantinescu    Logically Collective on TS
6373d177a5cSEmil Constantinescu 
6383d177a5cSEmil Constantinescu    Input Parameters:
6393d177a5cSEmil Constantinescu +  ts - the TS context
6403d177a5cSEmil Constantinescu -  type - the type
6413d177a5cSEmil Constantinescu 
6423d177a5cSEmil Constantinescu    Options Database Key:
6433d177a5cSEmil Constantinescu .  -ts_gl_accept_type <type> - sets the method used to determine whether to accept or reject a step
6443d177a5cSEmil Constantinescu 
6453d177a5cSEmil Constantinescu    Level: intermediate
6463d177a5cSEmil Constantinescu 
647db781477SPatrick Sanan .seealso: `TS`, `TSGLLE`, `TSGLLEAcceptRegister()`, `TSGLLEAdapt`, `set` `type`
6483d177a5cSEmil Constantinescu @*/
6499371c9d4SSatish Balay PetscErrorCode TSGLLESetAcceptType(TS ts, TSGLLEAcceptType type) {
6503d177a5cSEmil Constantinescu   PetscFunctionBegin;
6513d177a5cSEmil Constantinescu   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
6523d177a5cSEmil Constantinescu   PetscValidCharPointer(type, 2);
653cac4c232SBarry Smith   PetscTryMethod(ts, "TSGLLESetAcceptType_C", (TS, TSGLLEAcceptType), (ts, type));
6543d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
6553d177a5cSEmil Constantinescu }
6563d177a5cSEmil Constantinescu 
6573d177a5cSEmil Constantinescu /*@C
6583d177a5cSEmil Constantinescu    TSGLLEGetAdapt - gets the TSGLLEAdapt object from the TS
6593d177a5cSEmil Constantinescu 
6603d177a5cSEmil Constantinescu    Not Collective
6613d177a5cSEmil Constantinescu 
6623d177a5cSEmil Constantinescu    Input Parameter:
6633d177a5cSEmil Constantinescu .  ts - the TS context
6643d177a5cSEmil Constantinescu 
6653d177a5cSEmil Constantinescu    Output Parameter:
6663d177a5cSEmil Constantinescu .  adapt - the TSGLLEAdapt context
6673d177a5cSEmil Constantinescu 
6683d177a5cSEmil Constantinescu    Notes:
6693d177a5cSEmil Constantinescu    This allows the user set options on the TSGLLEAdapt object.  Usually it is better to do this using the options
6703d177a5cSEmil Constantinescu    database, so this function is rarely needed.
6713d177a5cSEmil Constantinescu 
6723d177a5cSEmil Constantinescu    Level: advanced
6733d177a5cSEmil Constantinescu 
674db781477SPatrick Sanan .seealso: `TSGLLEAdapt`, `TSGLLEAdaptRegister()`
6753d177a5cSEmil Constantinescu @*/
6769371c9d4SSatish Balay PetscErrorCode TSGLLEGetAdapt(TS ts, TSGLLEAdapt *adapt) {
6773d177a5cSEmil Constantinescu   PetscFunctionBegin;
6783d177a5cSEmil Constantinescu   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
6793d177a5cSEmil Constantinescu   PetscValidPointer(adapt, 2);
680cac4c232SBarry Smith   PetscUseMethod(ts, "TSGLLEGetAdapt_C", (TS, TSGLLEAdapt *), (ts, adapt));
6813d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
6823d177a5cSEmil Constantinescu }
6833d177a5cSEmil Constantinescu 
6849371c9d4SSatish Balay static PetscErrorCode TSGLLEAccept_Always(TS ts, PetscReal tleft, PetscReal h, const PetscReal enorms[], PetscBool *accept) {
6853d177a5cSEmil Constantinescu   PetscFunctionBegin;
6863d177a5cSEmil Constantinescu   *accept = PETSC_TRUE;
6873d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
6883d177a5cSEmil Constantinescu }
6893d177a5cSEmil Constantinescu 
6909371c9d4SSatish Balay static PetscErrorCode TSGLLEUpdateWRMS(TS ts) {
6913d177a5cSEmil Constantinescu   TS_GLLE     *gl = (TS_GLLE *)ts->data;
6923d177a5cSEmil Constantinescu   PetscScalar *x, *w;
6933d177a5cSEmil Constantinescu   PetscInt     n, i;
6943d177a5cSEmil Constantinescu 
6953d177a5cSEmil Constantinescu   PetscFunctionBegin;
6969566063dSJacob Faibussowitsch   PetscCall(VecGetArray(gl->X[0], &x));
6979566063dSJacob Faibussowitsch   PetscCall(VecGetArray(gl->W, &w));
6989566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(gl->W, &n));
6993d177a5cSEmil Constantinescu   for (i = 0; i < n; i++) w[i] = 1. / (gl->wrms_atol + gl->wrms_rtol * PetscAbsScalar(x[i]));
7009566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(gl->X[0], &x));
7019566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(gl->W, &w));
7023d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
7033d177a5cSEmil Constantinescu }
7043d177a5cSEmil Constantinescu 
7059371c9d4SSatish Balay static PetscErrorCode TSGLLEVecNormWRMS(TS ts, Vec X, PetscReal *nrm) {
7063d177a5cSEmil Constantinescu   TS_GLLE     *gl = (TS_GLLE *)ts->data;
7073d177a5cSEmil Constantinescu   PetscScalar *x, *w;
7083d177a5cSEmil Constantinescu   PetscReal    sum = 0.0, gsum;
7093d177a5cSEmil Constantinescu   PetscInt     n, N, i;
7103d177a5cSEmil Constantinescu 
7113d177a5cSEmil Constantinescu   PetscFunctionBegin;
7129566063dSJacob Faibussowitsch   PetscCall(VecGetArray(X, &x));
7139566063dSJacob Faibussowitsch   PetscCall(VecGetArray(gl->W, &w));
7149566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(gl->W, &n));
7153d177a5cSEmil Constantinescu   for (i = 0; i < n; i++) sum += PetscAbsScalar(PetscSqr(x[i] * w[i]));
7169566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(X, &x));
7179566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(gl->W, &w));
7181c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&sum, &gsum, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)ts)));
7199566063dSJacob Faibussowitsch   PetscCall(VecGetSize(gl->W, &N));
7203d177a5cSEmil Constantinescu   *nrm = PetscSqrtReal(gsum / (1. * N));
7213d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
7223d177a5cSEmil Constantinescu }
7233d177a5cSEmil Constantinescu 
7249371c9d4SSatish Balay static PetscErrorCode TSGLLESetType_GLLE(TS ts, TSGLLEType type) {
7253d177a5cSEmil Constantinescu   PetscBool same;
7263d177a5cSEmil Constantinescu   TS_GLLE  *gl = (TS_GLLE *)ts->data;
7275f80ce2aSJacob Faibussowitsch   PetscErrorCode (*r)(TS);
7283d177a5cSEmil Constantinescu 
7293d177a5cSEmil Constantinescu   PetscFunctionBegin;
7303d177a5cSEmil Constantinescu   if (gl->type_name[0]) {
7319566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(gl->type_name, type, &same));
7323d177a5cSEmil Constantinescu     if (same) PetscFunctionReturn(0);
7339566063dSJacob Faibussowitsch     PetscCall((*gl->Destroy)(gl));
7343d177a5cSEmil Constantinescu   }
7353d177a5cSEmil Constantinescu 
7369566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(TSGLLEList, type, &r));
7373c633725SBarry Smith   PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown TSGLLE type \"%s\" given", type);
7389566063dSJacob Faibussowitsch   PetscCall((*r)(ts));
7399566063dSJacob Faibussowitsch   PetscCall(PetscStrcpy(gl->type_name, type));
7403d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
7413d177a5cSEmil Constantinescu }
7423d177a5cSEmil Constantinescu 
7439371c9d4SSatish Balay static PetscErrorCode TSGLLESetAcceptType_GLLE(TS ts, TSGLLEAcceptType type) {
7443d177a5cSEmil Constantinescu   TSGLLEAcceptFunction r;
7453d177a5cSEmil Constantinescu   TS_GLLE             *gl = (TS_GLLE *)ts->data;
7463d177a5cSEmil Constantinescu 
7473d177a5cSEmil Constantinescu   PetscFunctionBegin;
7489566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(TSGLLEAcceptList, type, &r));
7493c633725SBarry Smith   PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown TSGLLEAccept type \"%s\" given", type);
7503d177a5cSEmil Constantinescu   gl->Accept = r;
7519566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(gl->accept_name, type, sizeof(gl->accept_name)));
7523d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
7533d177a5cSEmil Constantinescu }
7543d177a5cSEmil Constantinescu 
7559371c9d4SSatish Balay static PetscErrorCode TSGLLEGetAdapt_GLLE(TS ts, TSGLLEAdapt *adapt) {
7563d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
7573d177a5cSEmil Constantinescu 
7583d177a5cSEmil Constantinescu   PetscFunctionBegin;
7593d177a5cSEmil Constantinescu   if (!gl->adapt) {
7609566063dSJacob Faibussowitsch     PetscCall(TSGLLEAdaptCreate(PetscObjectComm((PetscObject)ts), &gl->adapt));
7619566063dSJacob Faibussowitsch     PetscCall(PetscObjectIncrementTabLevel((PetscObject)gl->adapt, (PetscObject)ts, 1));
7629566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)ts, (PetscObject)gl->adapt));
7633d177a5cSEmil Constantinescu   }
7643d177a5cSEmil Constantinescu   *adapt = gl->adapt;
7653d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
7663d177a5cSEmil Constantinescu }
7673d177a5cSEmil Constantinescu 
7689371c9d4SSatish Balay static PetscErrorCode TSGLLEChooseNextScheme(TS ts, PetscReal h, const PetscReal hmnorm[], PetscInt *next_scheme, PetscReal *next_h, PetscBool *finish) {
7693d177a5cSEmil Constantinescu   TS_GLLE  *gl = (TS_GLLE *)ts->data;
7703d177a5cSEmil Constantinescu   PetscInt  i, n, cur_p, cur, next_sc, candidates[64], orders[64];
7713d177a5cSEmil Constantinescu   PetscReal errors[64], costs[64], tleft;
7723d177a5cSEmil Constantinescu 
7733d177a5cSEmil Constantinescu   PetscFunctionBegin;
7743d177a5cSEmil Constantinescu   cur   = -1;
7753d177a5cSEmil Constantinescu   cur_p = gl->schemes[gl->current_scheme]->p;
7763d177a5cSEmil Constantinescu   tleft = ts->max_time - (ts->ptime + ts->time_step);
7773d177a5cSEmil Constantinescu   for (i = 0, n = 0; i < gl->nschemes; i++) {
7783d177a5cSEmil Constantinescu     TSGLLEScheme sc = gl->schemes[i];
7793d177a5cSEmil Constantinescu     if (sc->p < gl->min_order || gl->max_order < sc->p) continue;
7803d177a5cSEmil Constantinescu     if (sc->p == cur_p - 1) errors[n] = PetscAbsScalar(sc->alpha[0]) * hmnorm[0];
7813d177a5cSEmil Constantinescu     else if (sc->p == cur_p) errors[n] = PetscAbsScalar(sc->alpha[0]) * hmnorm[1];
7823d177a5cSEmil Constantinescu     else if (sc->p == cur_p + 1) errors[n] = PetscAbsScalar(sc->alpha[0]) * (hmnorm[2] + hmnorm[3]);
7833d177a5cSEmil Constantinescu     else continue;
7843d177a5cSEmil Constantinescu     candidates[n] = i;
7853d177a5cSEmil Constantinescu     orders[n]     = PetscMin(sc->p, sc->q); /* order of global truncation error */
7863d177a5cSEmil Constantinescu     costs[n]      = sc->s;                  /* estimate the cost as the number of stages */
7873d177a5cSEmil Constantinescu     if (i == gl->current_scheme) cur = n;
7883d177a5cSEmil Constantinescu     n++;
7893d177a5cSEmil Constantinescu   }
790cad9d221SBarry Smith   PetscCheck(cur >= 0 && gl->nschemes > cur, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Current scheme not found in scheme list");
7919566063dSJacob Faibussowitsch   PetscCall(TSGLLEAdaptChoose(gl->adapt, n, orders, errors, costs, cur, h, tleft, &next_sc, next_h, finish));
7923d177a5cSEmil Constantinescu   *next_scheme = candidates[next_sc];
7939371c9d4SSatish Balay   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,
7949371c9d4SSatish Balay                       gl->schemes[*next_scheme]->r, gl->schemes[*next_scheme]->s, (double)*next_h, PetscBools[*finish]));
7953d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
7963d177a5cSEmil Constantinescu }
7973d177a5cSEmil Constantinescu 
7989371c9d4SSatish Balay static PetscErrorCode TSGLLEGetMaxSizes(TS ts, PetscInt *max_r, PetscInt *max_s) {
7993d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
8003d177a5cSEmil Constantinescu 
8013d177a5cSEmil Constantinescu   PetscFunctionBegin;
8023d177a5cSEmil Constantinescu   *max_r = gl->schemes[gl->nschemes - 1]->r;
8033d177a5cSEmil Constantinescu   *max_s = gl->schemes[gl->nschemes - 1]->s;
8043d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
8053d177a5cSEmil Constantinescu }
8063d177a5cSEmil Constantinescu 
8079371c9d4SSatish Balay static PetscErrorCode TSSolve_GLLE(TS ts) {
8083d177a5cSEmil Constantinescu   TS_GLLE            *gl = (TS_GLLE *)ts->data;
8093d177a5cSEmil Constantinescu   PetscInt            i, k, its, lits, max_r, max_s;
8103d177a5cSEmil Constantinescu   PetscBool           final_step, finish;
8113d177a5cSEmil Constantinescu   SNESConvergedReason snesreason;
8123d177a5cSEmil Constantinescu 
8133d177a5cSEmil Constantinescu   PetscFunctionBegin;
8149566063dSJacob Faibussowitsch   PetscCall(TSMonitor(ts, ts->steps, ts->ptime, ts->vec_sol));
8153d177a5cSEmil Constantinescu 
8169566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetMaxSizes(ts, &max_r, &max_s));
8179566063dSJacob Faibussowitsch   PetscCall(VecCopy(ts->vec_sol, gl->X[0]));
818*48a46eb9SPierre Jolivet   for (i = 1; i < max_r; i++) PetscCall(VecZeroEntries(gl->X[i]));
8199566063dSJacob Faibussowitsch   PetscCall(TSGLLEUpdateWRMS(ts));
8203d177a5cSEmil Constantinescu 
8213d177a5cSEmil Constantinescu   if (0) {
8223d177a5cSEmil Constantinescu     /* Find consistent initial data for DAE */
8233d177a5cSEmil Constantinescu     gl->stage_time = ts->ptime + ts->time_step;
8243d177a5cSEmil Constantinescu     gl->scoeff     = 1.;
8253d177a5cSEmil Constantinescu     gl->stage      = 0;
8263d177a5cSEmil Constantinescu 
8279566063dSJacob Faibussowitsch     PetscCall(VecCopy(ts->vec_sol, gl->Z));
8289566063dSJacob Faibussowitsch     PetscCall(VecCopy(ts->vec_sol, gl->Y));
8299566063dSJacob Faibussowitsch     PetscCall(SNESSolve(ts->snes, NULL, gl->Y));
8309566063dSJacob Faibussowitsch     PetscCall(SNESGetIterationNumber(ts->snes, &its));
8319566063dSJacob Faibussowitsch     PetscCall(SNESGetLinearSolveIterations(ts->snes, &lits));
8329566063dSJacob Faibussowitsch     PetscCall(SNESGetConvergedReason(ts->snes, &snesreason));
8333d177a5cSEmil Constantinescu 
8349371c9d4SSatish Balay     ts->snes_its += its;
8359371c9d4SSatish Balay     ts->ksp_its += lits;
8363d177a5cSEmil Constantinescu     if (snesreason < 0 && ts->max_snes_failures > 0 && ++ts->num_snes_failures >= ts->max_snes_failures) {
8373d177a5cSEmil Constantinescu       ts->reason = TS_DIVERGED_NONLINEAR_SOLVE;
83863a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", nonlinear solve solve failures %" PetscInt_FMT " greater than current TS allowed, stopping solve\n", ts->steps, ts->num_snes_failures));
8393d177a5cSEmil Constantinescu       PetscFunctionReturn(0);
8403d177a5cSEmil Constantinescu     }
8413d177a5cSEmil Constantinescu   }
8423d177a5cSEmil Constantinescu 
84308401ef6SPierre Jolivet   PetscCheck(gl->current_scheme >= 0, PETSC_COMM_SELF, PETSC_ERR_ORDER, "A starting scheme has not been provided");
8443d177a5cSEmil Constantinescu 
8453d177a5cSEmil Constantinescu   for (k = 0, final_step = PETSC_FALSE, finish = PETSC_FALSE; k < ts->max_steps && !finish; k++) {
8463d177a5cSEmil Constantinescu     PetscInt           j, r, s, next_scheme = 0, rejections;
8473d177a5cSEmil Constantinescu     PetscReal          h, hmnorm[4], enorm[3], next_h;
8483d177a5cSEmil Constantinescu     PetscBool          accept;
8493d177a5cSEmil Constantinescu     const PetscScalar *c, *a, *u;
8503d177a5cSEmil Constantinescu     Vec               *X, *Ydot, Y;
8513d177a5cSEmil Constantinescu     TSGLLEScheme       scheme = gl->schemes[gl->current_scheme];
8523d177a5cSEmil Constantinescu 
8539371c9d4SSatish Balay     r    = scheme->r;
8549371c9d4SSatish Balay     s    = scheme->s;
8553d177a5cSEmil Constantinescu     c    = scheme->c;
8569371c9d4SSatish Balay     a    = scheme->a;
8579371c9d4SSatish Balay     u    = scheme->u;
8583d177a5cSEmil Constantinescu     h    = ts->time_step;
8599371c9d4SSatish Balay     X    = gl->X;
8609371c9d4SSatish Balay     Ydot = gl->Ydot;
8619371c9d4SSatish Balay     Y    = gl->Y;
8623d177a5cSEmil Constantinescu 
8633d177a5cSEmil Constantinescu     if (ts->ptime > ts->max_time) break;
8643d177a5cSEmil Constantinescu 
8653d177a5cSEmil Constantinescu     /*
8663d177a5cSEmil Constantinescu       We only call PreStep at the start of each STEP, not each STAGE.  This is because it is
8673d177a5cSEmil Constantinescu       possible to fail (have to restart a step) after multiple stages.
8683d177a5cSEmil Constantinescu     */
8699566063dSJacob Faibussowitsch     PetscCall(TSPreStep(ts));
8703d177a5cSEmil Constantinescu 
8713d177a5cSEmil Constantinescu     rejections = 0;
8723d177a5cSEmil Constantinescu     while (1) {
8733d177a5cSEmil Constantinescu       for (i = 0; i < s; i++) {
8743d177a5cSEmil Constantinescu         PetscScalar shift;
8753d177a5cSEmil Constantinescu         gl->scoeff     = 1. / PetscRealPart(a[i * s + i]);
8763d177a5cSEmil Constantinescu         shift          = gl->scoeff / ts->time_step;
8773d177a5cSEmil Constantinescu         gl->stage      = i;
8783d177a5cSEmil Constantinescu         gl->stage_time = ts->ptime + PetscRealPart(c[i]) * h;
8793d177a5cSEmil Constantinescu 
8803d177a5cSEmil Constantinescu         /*
8813d177a5cSEmil Constantinescu         * Stage equation: Y = h A Y' + U X
8823d177a5cSEmil Constantinescu         * We assume that A is lower-triangular so that we can solve the stages (Y,Y') sequentially
8833d177a5cSEmil Constantinescu         * Build the affine vector z_i = -[1/(h a_ii)](h sum_j a_ij y'_j + sum_j u_ij x_j)
8843d177a5cSEmil Constantinescu         * Then y'_i = z + 1/(h a_ii) y_i
8853d177a5cSEmil Constantinescu         */
8869566063dSJacob Faibussowitsch         PetscCall(VecZeroEntries(gl->Z));
887*48a46eb9SPierre Jolivet         for (j = 0; j < r; j++) PetscCall(VecAXPY(gl->Z, -shift * u[i * r + j], X[j]));
888*48a46eb9SPierre Jolivet         for (j = 0; j < i; j++) PetscCall(VecAXPY(gl->Z, -shift * h * a[i * s + j], Ydot[j]));
8893d177a5cSEmil Constantinescu         /* Note: Z is used within function evaluation, Ydot = Z + shift*Y */
8903d177a5cSEmil Constantinescu 
8913d177a5cSEmil Constantinescu         /* Compute an estimate of Y to start Newton iteration */
8923d177a5cSEmil Constantinescu         if (gl->extrapolate) {
8933d177a5cSEmil Constantinescu           if (i == 0) {
8943d177a5cSEmil Constantinescu             /* Linear extrapolation on the first stage */
8959566063dSJacob Faibussowitsch             PetscCall(VecWAXPY(Y, c[i] * h, X[1], X[0]));
8963d177a5cSEmil Constantinescu           } else {
8973d177a5cSEmil Constantinescu             /* Linear extrapolation from the last stage */
8989566063dSJacob Faibussowitsch             PetscCall(VecAXPY(Y, (c[i] - c[i - 1]) * h, Ydot[i - 1]));
8993d177a5cSEmil Constantinescu           }
9003d177a5cSEmil Constantinescu         } else if (i == 0) { /* Directly use solution from the last step, otherwise reuse the last stage (do nothing) */
9019566063dSJacob Faibussowitsch           PetscCall(VecCopy(X[0], Y));
9023d177a5cSEmil Constantinescu         }
9033d177a5cSEmil Constantinescu 
9043d177a5cSEmil Constantinescu         /* Solve this stage (Ydot[i] is computed during function evaluation) */
9059566063dSJacob Faibussowitsch         PetscCall(SNESSolve(ts->snes, NULL, Y));
9069566063dSJacob Faibussowitsch         PetscCall(SNESGetIterationNumber(ts->snes, &its));
9079566063dSJacob Faibussowitsch         PetscCall(SNESGetLinearSolveIterations(ts->snes, &lits));
9089566063dSJacob Faibussowitsch         PetscCall(SNESGetConvergedReason(ts->snes, &snesreason));
9099371c9d4SSatish Balay         ts->snes_its += its;
9109371c9d4SSatish Balay         ts->ksp_its += lits;
9113d177a5cSEmil Constantinescu         if (snesreason < 0 && ts->max_snes_failures > 0 && ++ts->num_snes_failures >= ts->max_snes_failures) {
9123d177a5cSEmil Constantinescu           ts->reason = TS_DIVERGED_NONLINEAR_SOLVE;
91363a3b9bcSJacob Faibussowitsch           PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", nonlinear solve solve failures %" PetscInt_FMT " greater than current TS allowed, stopping solve\n", ts->steps, ts->num_snes_failures));
9143d177a5cSEmil Constantinescu           PetscFunctionReturn(0);
9153d177a5cSEmil Constantinescu         }
9163d177a5cSEmil Constantinescu       }
9173d177a5cSEmil Constantinescu 
9183d177a5cSEmil Constantinescu       gl->stage_time = ts->ptime + ts->time_step;
9193d177a5cSEmil Constantinescu 
9209566063dSJacob Faibussowitsch       PetscCall((*gl->EstimateHigherMoments)(scheme, h, Ydot, gl->X, gl->himom));
9213d177a5cSEmil Constantinescu       /* hmnorm[i] = h^{p+i}x^{(p+i)} with i=0,1,2; hmnorm[3] = h^{p+2}(dx'/dx) x^{(p+1)} */
922*48a46eb9SPierre Jolivet       for (i = 0; i < 3; i++) PetscCall(TSGLLEVecNormWRMS(ts, gl->himom[i], &hmnorm[i + 1]));
9233d177a5cSEmil Constantinescu       enorm[0] = PetscRealPart(scheme->alpha[0]) * hmnorm[1];
9243d177a5cSEmil Constantinescu       enorm[1] = PetscRealPart(scheme->beta[0]) * hmnorm[2];
9253d177a5cSEmil Constantinescu       enorm[2] = PetscRealPart(scheme->gamma[0]) * hmnorm[3];
9269566063dSJacob Faibussowitsch       PetscCall((*gl->Accept)(ts, ts->max_time - gl->stage_time, h, enorm, &accept));
9273d177a5cSEmil Constantinescu       if (accept) goto accepted;
9283d177a5cSEmil Constantinescu       rejections++;
92963a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(ts, "Step %" PetscInt_FMT " (t=%g) not accepted, rejections=%" PetscInt_FMT "\n", k, (double)gl->stage_time, rejections));
9303d177a5cSEmil Constantinescu       if (rejections > gl->max_step_rejections) break;
9313d177a5cSEmil Constantinescu       /*
9323d177a5cSEmil Constantinescu         There are lots of reasons why a step might be rejected, including solvers not converging and other factors that
9333d177a5cSEmil Constantinescu         TSGLLEChooseNextScheme does not support.  Additionally, the error estimates may be very screwed up, so I'm not
9343d177a5cSEmil Constantinescu         convinced that it's safe to just compute a new error estimate using the same interface as the current adaptor
9353d177a5cSEmil Constantinescu         (the adaptor interface probably has to change).  Here we make an arbitrary and naive choice.  This assumes that
9363d177a5cSEmil Constantinescu         steps were written in Nordsieck form.  The "correct" method would be to re-complete the previous time step with
9373d177a5cSEmil Constantinescu         the correct "next" step size.  It is unclear to me whether the present ad-hoc method of rescaling X is stable.
9383d177a5cSEmil Constantinescu       */
9393d177a5cSEmil Constantinescu       h *= 0.5;
940*48a46eb9SPierre Jolivet       for (i = 1; i < scheme->r; i++) PetscCall(VecScale(X[i], PetscPowRealInt(0.5, i)));
9413d177a5cSEmil Constantinescu     }
94263a3b9bcSJacob Faibussowitsch     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);
9433d177a5cSEmil Constantinescu 
9443d177a5cSEmil Constantinescu   accepted:
9453d177a5cSEmil Constantinescu     /* This term is not error, but it *would* be the leading term for a lower order method */
9469566063dSJacob Faibussowitsch     PetscCall(TSGLLEVecNormWRMS(ts, gl->X[scheme->r - 1], &hmnorm[0]));
9473d177a5cSEmil Constantinescu     /* Correct scaling so that these are equivalent to norms of the Nordsieck vectors */
9483d177a5cSEmil Constantinescu 
94963a3b9bcSJacob Faibussowitsch     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]));
9503d177a5cSEmil Constantinescu     if (!final_step) {
9519566063dSJacob Faibussowitsch       PetscCall(TSGLLEChooseNextScheme(ts, h, hmnorm, &next_scheme, &next_h, &final_step));
9523d177a5cSEmil Constantinescu     } else {
9533d177a5cSEmil Constantinescu       /* Dummy values to complete the current step in a consistent manner */
9543d177a5cSEmil Constantinescu       next_scheme = gl->current_scheme;
9553d177a5cSEmil Constantinescu       next_h      = h;
9563d177a5cSEmil Constantinescu       finish      = PETSC_TRUE;
9573d177a5cSEmil Constantinescu     }
9583d177a5cSEmil Constantinescu 
9593d177a5cSEmil Constantinescu     X        = gl->Xold;
9603d177a5cSEmil Constantinescu     gl->Xold = gl->X;
9613d177a5cSEmil Constantinescu     gl->X    = X;
9629566063dSJacob Faibussowitsch     PetscCall((*gl->CompleteStep)(scheme, h, gl->schemes[next_scheme], next_h, Ydot, gl->Xold, gl->X));
9633d177a5cSEmil Constantinescu 
9649566063dSJacob Faibussowitsch     PetscCall(TSGLLEUpdateWRMS(ts));
9653d177a5cSEmil Constantinescu 
9663d177a5cSEmil Constantinescu     /* Post the solution for the user, we could avoid this copy with a small bit of cleverness */
9679566063dSJacob Faibussowitsch     PetscCall(VecCopy(gl->X[0], ts->vec_sol));
9683d177a5cSEmil Constantinescu     ts->ptime += h;
9693d177a5cSEmil Constantinescu     ts->steps++;
9703d177a5cSEmil Constantinescu 
9719566063dSJacob Faibussowitsch     PetscCall(TSPostEvaluate(ts));
9729566063dSJacob Faibussowitsch     PetscCall(TSPostStep(ts));
9739566063dSJacob Faibussowitsch     PetscCall(TSMonitor(ts, ts->steps, ts->ptime, ts->vec_sol));
9743d177a5cSEmil Constantinescu 
9753d177a5cSEmil Constantinescu     gl->current_scheme = next_scheme;
9763d177a5cSEmil Constantinescu     ts->time_step      = next_h;
9773d177a5cSEmil Constantinescu   }
9783d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
9793d177a5cSEmil Constantinescu }
9803d177a5cSEmil Constantinescu 
9813d177a5cSEmil Constantinescu /*------------------------------------------------------------*/
9823d177a5cSEmil Constantinescu 
9839371c9d4SSatish Balay static PetscErrorCode TSReset_GLLE(TS ts) {
9843d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
9853d177a5cSEmil Constantinescu   PetscInt max_r, max_s;
9863d177a5cSEmil Constantinescu 
9873d177a5cSEmil Constantinescu   PetscFunctionBegin;
9883d177a5cSEmil Constantinescu   if (gl->setupcalled) {
9899566063dSJacob Faibussowitsch     PetscCall(TSGLLEGetMaxSizes(ts, &max_r, &max_s));
9909566063dSJacob Faibussowitsch     PetscCall(VecDestroyVecs(max_r, &gl->Xold));
9919566063dSJacob Faibussowitsch     PetscCall(VecDestroyVecs(max_r, &gl->X));
9929566063dSJacob Faibussowitsch     PetscCall(VecDestroyVecs(max_s, &gl->Ydot));
9939566063dSJacob Faibussowitsch     PetscCall(VecDestroyVecs(3, &gl->himom));
9949566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gl->W));
9959566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gl->Y));
9969566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gl->Z));
9973d177a5cSEmil Constantinescu   }
9983d177a5cSEmil Constantinescu   gl->setupcalled = PETSC_FALSE;
9993d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
10003d177a5cSEmil Constantinescu }
10013d177a5cSEmil Constantinescu 
10029371c9d4SSatish Balay static PetscErrorCode TSDestroy_GLLE(TS ts) {
10033d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
10043d177a5cSEmil Constantinescu 
10053d177a5cSEmil Constantinescu   PetscFunctionBegin;
10069566063dSJacob Faibussowitsch   PetscCall(TSReset_GLLE(ts));
1007b3a6b972SJed Brown   if (ts->dm) {
10089566063dSJacob Faibussowitsch     PetscCall(DMCoarsenHookRemove(ts->dm, DMCoarsenHook_TSGLLE, DMRestrictHook_TSGLLE, ts));
10099566063dSJacob Faibussowitsch     PetscCall(DMSubDomainHookRemove(ts->dm, DMSubDomainHook_TSGLLE, DMSubDomainRestrictHook_TSGLLE, ts));
1010b3a6b972SJed Brown   }
10119566063dSJacob Faibussowitsch   if (gl->adapt) PetscCall(TSGLLEAdaptDestroy(&gl->adapt));
10129566063dSJacob Faibussowitsch   if (gl->Destroy) PetscCall((*gl->Destroy)(gl));
10139566063dSJacob Faibussowitsch   PetscCall(PetscFree(ts->data));
10149566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLESetType_C", NULL));
10159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLESetAcceptType_C", NULL));
10169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLEGetAdapt_C", NULL));
10173d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
10183d177a5cSEmil Constantinescu }
10193d177a5cSEmil Constantinescu 
10203d177a5cSEmil Constantinescu /*
10213d177a5cSEmil Constantinescu     This defines the nonlinear equation that is to be solved with SNES
10223d177a5cSEmil Constantinescu     g(x) = f(t,x,z+shift*x) = 0
10233d177a5cSEmil Constantinescu */
10249371c9d4SSatish Balay static PetscErrorCode SNESTSFormFunction_GLLE(SNES snes, Vec x, Vec f, TS ts) {
10253d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
10263d177a5cSEmil Constantinescu   Vec      Z, Ydot;
10273d177a5cSEmil Constantinescu   DM       dm, dmsave;
10283d177a5cSEmil Constantinescu 
10293d177a5cSEmil Constantinescu   PetscFunctionBegin;
10309566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
10319566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, dm, &Z, &Ydot));
10329566063dSJacob Faibussowitsch   PetscCall(VecWAXPY(Ydot, gl->scoeff / ts->time_step, x, Z));
10333d177a5cSEmil Constantinescu   dmsave = ts->dm;
10343d177a5cSEmil Constantinescu   ts->dm = dm;
10359566063dSJacob Faibussowitsch   PetscCall(TSComputeIFunction(ts, gl->stage_time, x, Ydot, f, PETSC_FALSE));
10363d177a5cSEmil Constantinescu   ts->dm = dmsave;
10379566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, dm, &Z, &Ydot));
10383d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
10393d177a5cSEmil Constantinescu }
10403d177a5cSEmil Constantinescu 
10419371c9d4SSatish Balay static PetscErrorCode SNESTSFormJacobian_GLLE(SNES snes, Vec x, Mat A, Mat B, TS ts) {
10423d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
10433d177a5cSEmil Constantinescu   Vec      Z, Ydot;
10443d177a5cSEmil Constantinescu   DM       dm, dmsave;
10453d177a5cSEmil Constantinescu 
10463d177a5cSEmil Constantinescu   PetscFunctionBegin;
10479566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
10489566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, dm, &Z, &Ydot));
10493d177a5cSEmil Constantinescu   dmsave = ts->dm;
10503d177a5cSEmil Constantinescu   ts->dm = dm;
10513d177a5cSEmil Constantinescu   /* gl->Xdot will have already been computed in SNESTSFormFunction_GLLE */
10529566063dSJacob Faibussowitsch   PetscCall(TSComputeIJacobian(ts, gl->stage_time, x, gl->Ydot[gl->stage], gl->scoeff / ts->time_step, A, B, PETSC_FALSE));
10533d177a5cSEmil Constantinescu   ts->dm = dmsave;
10549566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, dm, &Z, &Ydot));
10553d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
10563d177a5cSEmil Constantinescu }
10573d177a5cSEmil Constantinescu 
10589371c9d4SSatish Balay static PetscErrorCode TSSetUp_GLLE(TS ts) {
10593d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
10603d177a5cSEmil Constantinescu   PetscInt max_r, max_s;
10613d177a5cSEmil Constantinescu   DM       dm;
10623d177a5cSEmil Constantinescu 
10633d177a5cSEmil Constantinescu   PetscFunctionBegin;
10643d177a5cSEmil Constantinescu   gl->setupcalled = PETSC_TRUE;
10659566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetMaxSizes(ts, &max_r, &max_s));
10669566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vec_sol, max_r, &gl->X));
10679566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vec_sol, max_r, &gl->Xold));
10689566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vec_sol, max_s, &gl->Ydot));
10699566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vec_sol, 3, &gl->himom));
10709566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &gl->W));
10719566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &gl->Y));
10729566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &gl->Z));
10733d177a5cSEmil Constantinescu 
10743d177a5cSEmil Constantinescu   /* Default acceptance tests and adaptivity */
10759566063dSJacob Faibussowitsch   if (!gl->Accept) PetscCall(TSGLLESetAcceptType(ts, TSGLLEACCEPT_ALWAYS));
10769566063dSJacob Faibussowitsch   if (!gl->adapt) PetscCall(TSGLLEGetAdapt(ts, &gl->adapt));
10773d177a5cSEmil Constantinescu 
10783d177a5cSEmil Constantinescu   if (gl->current_scheme < 0) {
10793d177a5cSEmil Constantinescu     PetscInt i;
10803d177a5cSEmil Constantinescu     for (i = 0;; i++) {
10813d177a5cSEmil Constantinescu       if (gl->schemes[i]->p == gl->start_order) break;
108263a3b9bcSJacob Faibussowitsch       PetscCheck(i + 1 != gl->nschemes, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No schemes available with requested start order %" PetscInt_FMT, i);
10833d177a5cSEmil Constantinescu     }
10843d177a5cSEmil Constantinescu     gl->current_scheme = i;
10853d177a5cSEmil Constantinescu   }
10869566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &dm));
10879566063dSJacob Faibussowitsch   PetscCall(DMCoarsenHookAdd(dm, DMCoarsenHook_TSGLLE, DMRestrictHook_TSGLLE, ts));
10889566063dSJacob Faibussowitsch   PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_TSGLLE, DMSubDomainRestrictHook_TSGLLE, ts));
10893d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
10903d177a5cSEmil Constantinescu }
10913d177a5cSEmil Constantinescu /*------------------------------------------------------------*/
10923d177a5cSEmil Constantinescu 
10939371c9d4SSatish Balay static PetscErrorCode TSSetFromOptions_GLLE(TS ts, PetscOptionItems *PetscOptionsObject) {
10943d177a5cSEmil Constantinescu   TS_GLLE *gl         = (TS_GLLE *)ts->data;
10953d177a5cSEmil Constantinescu   char     tname[256] = TSGLLE_IRKS, completef[256] = "rescale-and-modify";
10963d177a5cSEmil Constantinescu 
10973d177a5cSEmil Constantinescu   PetscFunctionBegin;
1098d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "General Linear ODE solver options");
10993d177a5cSEmil Constantinescu   {
11003d177a5cSEmil Constantinescu     PetscBool flg;
11019566063dSJacob Faibussowitsch     PetscCall(PetscOptionsFList("-ts_gl_type", "Type of GL method", "TSGLLESetType", TSGLLEList, gl->type_name[0] ? gl->type_name : tname, tname, sizeof(tname), &flg));
1102*48a46eb9SPierre Jolivet     if (flg || !gl->type_name[0]) PetscCall(TSGLLESetType(ts, tname));
11039566063dSJacob Faibussowitsch     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));
11049566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-ts_gl_max_order", "Maximum order to try", "TSGLLESetMaxOrder", gl->max_order, &gl->max_order, NULL));
11059566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-ts_gl_min_order", "Minimum order to try", "TSGLLESetMinOrder", gl->min_order, &gl->min_order, NULL));
11069566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-ts_gl_start_order", "Initial order to try", "TSGLLESetMinOrder", gl->start_order, &gl->start_order, NULL));
11079566063dSJacob Faibussowitsch     PetscCall(PetscOptionsEnum("-ts_gl_error_direction", "Which direction to look when estimating error", "TSGLLESetErrorDirection", TSGLLEErrorDirections, (PetscEnum)gl->error_direction, (PetscEnum *)&gl->error_direction, NULL));
11089566063dSJacob Faibussowitsch     PetscCall(PetscOptionsBool("-ts_gl_extrapolate", "Extrapolate stage solution from previous solution (sometimes unstable)", "TSGLLESetExtrapolate", gl->extrapolate, &gl->extrapolate, NULL));
11099566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_gl_atol", "Absolute tolerance", "TSGLLESetTolerances", gl->wrms_atol, &gl->wrms_atol, NULL));
11109566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_gl_rtol", "Relative tolerance", "TSGLLESetTolerances", gl->wrms_rtol, &gl->wrms_rtol, NULL));
11119566063dSJacob Faibussowitsch     PetscCall(PetscOptionsString("-ts_gl_complete", "Method to use for completing the step", "none", completef, completef, sizeof(completef), &flg));
11123d177a5cSEmil Constantinescu     if (flg) {
11133d177a5cSEmil Constantinescu       PetscBool match1, match2;
11149566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(completef, "rescale", &match1));
11159566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(completef, "rescale-and-modify", &match2));
11163d177a5cSEmil Constantinescu       if (match1) gl->CompleteStep = TSGLLECompleteStep_Rescale;
11173d177a5cSEmil Constantinescu       else if (match2) gl->CompleteStep = TSGLLECompleteStep_RescaleAndModify;
111898921bdaSJacob Faibussowitsch       else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "%s", completef);
11193d177a5cSEmil Constantinescu     }
11203d177a5cSEmil Constantinescu     {
11213d177a5cSEmil Constantinescu       char type[256] = TSGLLEACCEPT_ALWAYS;
11229566063dSJacob Faibussowitsch       PetscCall(PetscOptionsFList("-ts_gl_accept_type", "Method to use for determining whether to accept a step", "TSGLLESetAcceptType", TSGLLEAcceptList, gl->accept_name[0] ? gl->accept_name : type, type, sizeof(type), &flg));
1123*48a46eb9SPierre Jolivet       if (flg || !gl->accept_name[0]) PetscCall(TSGLLESetAcceptType(ts, type));
11243d177a5cSEmil Constantinescu     }
11253d177a5cSEmil Constantinescu     {
11263d177a5cSEmil Constantinescu       TSGLLEAdapt adapt;
11279566063dSJacob Faibussowitsch       PetscCall(TSGLLEGetAdapt(ts, &adapt));
1128dbbe0bcdSBarry Smith       PetscCall(TSGLLEAdaptSetFromOptions(adapt, PetscOptionsObject));
11293d177a5cSEmil Constantinescu     }
11303d177a5cSEmil Constantinescu   }
1131d0609cedSBarry Smith   PetscOptionsHeadEnd();
11323d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
11333d177a5cSEmil Constantinescu }
11343d177a5cSEmil Constantinescu 
11359371c9d4SSatish Balay static PetscErrorCode TSView_GLLE(TS ts, PetscViewer viewer) {
11363d177a5cSEmil Constantinescu   TS_GLLE  *gl = (TS_GLLE *)ts->data;
11373d177a5cSEmil Constantinescu   PetscInt  i;
11383d177a5cSEmil Constantinescu   PetscBool iascii, details;
11393d177a5cSEmil Constantinescu 
11403d177a5cSEmil Constantinescu   PetscFunctionBegin;
11419566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
11423d177a5cSEmil Constantinescu   if (iascii) {
114363a3b9bcSJacob Faibussowitsch     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));
11449566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Error estimation: %s\n", TSGLLEErrorDirections[gl->error_direction]));
11459566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Extrapolation: %s\n", gl->extrapolate ? "yes" : "no"));
11469566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Acceptance test: %s\n", gl->accept_name[0] ? gl->accept_name : "(not yet set)"));
11479566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
11489566063dSJacob Faibussowitsch     PetscCall(TSGLLEAdaptView(gl->adapt, viewer));
11499566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
11509566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  type: %s\n", gl->type_name[0] ? gl->type_name : "(not yet set)"));
115163a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Schemes within family (%" PetscInt_FMT "):\n", gl->nschemes));
11523d177a5cSEmil Constantinescu     details = PETSC_FALSE;
11539566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)ts)->options, ((PetscObject)ts)->prefix, "-ts_gl_view_detailed", &details, NULL));
11549566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
1155*48a46eb9SPierre Jolivet     for (i = 0; i < gl->nschemes; i++) PetscCall(TSGLLESchemeView(gl->schemes[i], details, viewer));
11561baa6e33SBarry Smith     if (gl->View) PetscCall((*gl->View)(gl, viewer));
11579566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
11583d177a5cSEmil Constantinescu   }
11593d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
11603d177a5cSEmil Constantinescu }
11613d177a5cSEmil Constantinescu 
11623d177a5cSEmil Constantinescu /*@C
11633d177a5cSEmil Constantinescu    TSGLLERegister -  adds a TSGLLE implementation
11643d177a5cSEmil Constantinescu 
11653d177a5cSEmil Constantinescu    Not Collective
11663d177a5cSEmil Constantinescu 
11673d177a5cSEmil Constantinescu    Input Parameters:
11683d177a5cSEmil Constantinescu +  name_scheme - name of user-defined general linear scheme
11693d177a5cSEmil Constantinescu -  routine_create - routine to create method context
11703d177a5cSEmil Constantinescu 
11713d177a5cSEmil Constantinescu    Notes:
11723d177a5cSEmil Constantinescu    TSGLLERegister() may be called multiple times to add several user-defined families.
11733d177a5cSEmil Constantinescu 
11743d177a5cSEmil Constantinescu    Sample usage:
11753d177a5cSEmil Constantinescu .vb
11763d177a5cSEmil Constantinescu    TSGLLERegister("my_scheme",MySchemeCreate);
11773d177a5cSEmil Constantinescu .ve
11783d177a5cSEmil Constantinescu 
11793d177a5cSEmil Constantinescu    Then, your scheme can be chosen with the procedural interface via
11803d177a5cSEmil Constantinescu $     TSGLLESetType(ts,"my_scheme")
11813d177a5cSEmil Constantinescu    or at runtime via the option
11823d177a5cSEmil Constantinescu $     -ts_gl_type my_scheme
11833d177a5cSEmil Constantinescu 
11843d177a5cSEmil Constantinescu    Level: advanced
11853d177a5cSEmil Constantinescu 
1186db781477SPatrick Sanan .seealso: `TSGLLERegisterAll()`
11873d177a5cSEmil Constantinescu @*/
11889371c9d4SSatish Balay PetscErrorCode TSGLLERegister(const char sname[], PetscErrorCode (*function)(TS)) {
11893d177a5cSEmil Constantinescu   PetscFunctionBegin;
11909566063dSJacob Faibussowitsch   PetscCall(TSGLLEInitializePackage());
11919566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&TSGLLEList, sname, function));
11923d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
11933d177a5cSEmil Constantinescu }
11943d177a5cSEmil Constantinescu 
11953d177a5cSEmil Constantinescu /*@C
11963d177a5cSEmil Constantinescu    TSGLLEAcceptRegister -  adds a TSGLLE acceptance scheme
11973d177a5cSEmil Constantinescu 
11983d177a5cSEmil Constantinescu    Not Collective
11993d177a5cSEmil Constantinescu 
12003d177a5cSEmil Constantinescu    Input Parameters:
12013d177a5cSEmil Constantinescu +  name_scheme - name of user-defined acceptance scheme
12023d177a5cSEmil Constantinescu -  routine_create - routine to create method context
12033d177a5cSEmil Constantinescu 
12043d177a5cSEmil Constantinescu    Notes:
12053d177a5cSEmil Constantinescu    TSGLLEAcceptRegister() may be called multiple times to add several user-defined families.
12063d177a5cSEmil Constantinescu 
12073d177a5cSEmil Constantinescu    Sample usage:
12083d177a5cSEmil Constantinescu .vb
12093d177a5cSEmil Constantinescu    TSGLLEAcceptRegister("my_scheme",MySchemeCreate);
12103d177a5cSEmil Constantinescu .ve
12113d177a5cSEmil Constantinescu 
12123d177a5cSEmil Constantinescu    Then, your scheme can be chosen with the procedural interface via
12133d177a5cSEmil Constantinescu $     TSGLLESetAcceptType(ts,"my_scheme")
12143d177a5cSEmil Constantinescu    or at runtime via the option
12153d177a5cSEmil Constantinescu $     -ts_gl_accept_type my_scheme
12163d177a5cSEmil Constantinescu 
12173d177a5cSEmil Constantinescu    Level: advanced
12183d177a5cSEmil Constantinescu 
1219db781477SPatrick Sanan .seealso: `TSGLLERegisterAll()`
12203d177a5cSEmil Constantinescu @*/
12219371c9d4SSatish Balay PetscErrorCode TSGLLEAcceptRegister(const char sname[], TSGLLEAcceptFunction function) {
12223d177a5cSEmil Constantinescu   PetscFunctionBegin;
12239566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&TSGLLEAcceptList, sname, function));
12243d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
12253d177a5cSEmil Constantinescu }
12263d177a5cSEmil Constantinescu 
12273d177a5cSEmil Constantinescu /*@C
12283d177a5cSEmil Constantinescu   TSGLLERegisterAll - Registers all of the general linear methods in TSGLLE
12293d177a5cSEmil Constantinescu 
12303d177a5cSEmil Constantinescu   Not Collective
12313d177a5cSEmil Constantinescu 
12323d177a5cSEmil Constantinescu   Level: advanced
12333d177a5cSEmil Constantinescu 
1234db781477SPatrick Sanan .seealso: `TSGLLERegisterDestroy()`
12353d177a5cSEmil Constantinescu @*/
12369371c9d4SSatish Balay PetscErrorCode TSGLLERegisterAll(void) {
12373d177a5cSEmil Constantinescu   PetscFunctionBegin;
12383d177a5cSEmil Constantinescu   if (TSGLLERegisterAllCalled) PetscFunctionReturn(0);
12393d177a5cSEmil Constantinescu   TSGLLERegisterAllCalled = PETSC_TRUE;
12403d177a5cSEmil Constantinescu 
12419566063dSJacob Faibussowitsch   PetscCall(TSGLLERegister(TSGLLE_IRKS, TSGLLECreate_IRKS));
12429566063dSJacob Faibussowitsch   PetscCall(TSGLLEAcceptRegister(TSGLLEACCEPT_ALWAYS, TSGLLEAccept_Always));
12433d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
12443d177a5cSEmil Constantinescu }
12453d177a5cSEmil Constantinescu 
12463d177a5cSEmil Constantinescu /*@C
12473d177a5cSEmil Constantinescu   TSGLLEInitializePackage - This function initializes everything in the TSGLLE package. It is called
12488a690491SBarry Smith   from TSInitializePackage().
12493d177a5cSEmil Constantinescu 
12503d177a5cSEmil Constantinescu   Level: developer
12513d177a5cSEmil Constantinescu 
1252db781477SPatrick Sanan .seealso: `PetscInitialize()`
12533d177a5cSEmil Constantinescu @*/
12549371c9d4SSatish Balay PetscErrorCode TSGLLEInitializePackage(void) {
12553d177a5cSEmil Constantinescu   PetscFunctionBegin;
12563d177a5cSEmil Constantinescu   if (TSGLLEPackageInitialized) PetscFunctionReturn(0);
12573d177a5cSEmil Constantinescu   TSGLLEPackageInitialized = PETSC_TRUE;
12589566063dSJacob Faibussowitsch   PetscCall(TSGLLERegisterAll());
12599566063dSJacob Faibussowitsch   PetscCall(PetscRegisterFinalize(TSGLLEFinalizePackage));
12603d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
12613d177a5cSEmil Constantinescu }
12623d177a5cSEmil Constantinescu 
12633d177a5cSEmil Constantinescu /*@C
12643d177a5cSEmil Constantinescu   TSGLLEFinalizePackage - This function destroys everything in the TSGLLE package. It is
12653d177a5cSEmil Constantinescu   called from PetscFinalize().
12663d177a5cSEmil Constantinescu 
12673d177a5cSEmil Constantinescu   Level: developer
12683d177a5cSEmil Constantinescu 
1269db781477SPatrick Sanan .seealso: `PetscFinalize()`
12703d177a5cSEmil Constantinescu @*/
12719371c9d4SSatish Balay PetscErrorCode TSGLLEFinalizePackage(void) {
12723d177a5cSEmil Constantinescu   PetscFunctionBegin;
12739566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&TSGLLEList));
12749566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&TSGLLEAcceptList));
12753d177a5cSEmil Constantinescu   TSGLLEPackageInitialized = PETSC_FALSE;
12763d177a5cSEmil Constantinescu   TSGLLERegisterAllCalled  = PETSC_FALSE;
12773d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
12783d177a5cSEmil Constantinescu }
12793d177a5cSEmil Constantinescu 
12803d177a5cSEmil Constantinescu /* ------------------------------------------------------------ */
12813d177a5cSEmil Constantinescu /*MC
12823d177a5cSEmil Constantinescu       TSGLLE - DAE solver using implicit General Linear methods
12833d177a5cSEmil Constantinescu 
12843d177a5cSEmil Constantinescu   These methods contain Runge-Kutta and multistep schemes as special cases.  These special cases have some fundamental
12853d177a5cSEmil Constantinescu   limitations.  For example, diagonally implicit Runge-Kutta cannot have stage order greater than 1 which limits their
12863d177a5cSEmil Constantinescu   applicability to very stiff systems.  Meanwhile, multistep methods cannot be A-stable for order greater than 2 and BDF
12873d177a5cSEmil Constantinescu   are not 0-stable for order greater than 6.  GL methods can be A- and L-stable with arbitrarily high stage order and
12883d177a5cSEmil Constantinescu   reliable error estimates for both 1 and 2 orders higher to facilitate adaptive step sizes and adaptive order schemes.
12893d177a5cSEmil Constantinescu   All this is possible while preserving a singly diagonally implicit structure.
12903d177a5cSEmil Constantinescu 
12913d177a5cSEmil Constantinescu   Options database keys:
12923d177a5cSEmil Constantinescu +  -ts_gl_type <type> - the class of general linear method (irks)
12933d177a5cSEmil Constantinescu .  -ts_gl_rtol <tol>  - relative error
12943d177a5cSEmil Constantinescu .  -ts_gl_atol <tol>  - absolute error
12953d177a5cSEmil Constantinescu .  -ts_gl_min_order <p> - minimum order method to consider (default=1)
12963d177a5cSEmil Constantinescu .  -ts_gl_max_order <p> - maximum order method to consider (default=3)
12973d177a5cSEmil Constantinescu .  -ts_gl_start_order <p> - order of starting method (default=1)
12983d177a5cSEmil Constantinescu .  -ts_gl_complete <method> - method to use for completing the step (rescale-and-modify or rescale)
12993d177a5cSEmil Constantinescu -  -ts_adapt_type <method> - adaptive controller to use (none step both)
13003d177a5cSEmil Constantinescu 
13013d177a5cSEmil Constantinescu   Notes:
13023d177a5cSEmil Constantinescu   This integrator can be applied to DAE.
13033d177a5cSEmil Constantinescu 
13043d177a5cSEmil Constantinescu   Diagonally implicit general linear (DIGL) methods are a generalization of diagonally implicit Runge-Kutta (DIRK).
13053d177a5cSEmil Constantinescu   They are represented by the tableau
13063d177a5cSEmil Constantinescu 
13073d177a5cSEmil Constantinescu .vb
13083d177a5cSEmil Constantinescu   A  |  U
13093d177a5cSEmil Constantinescu   -------
13103d177a5cSEmil Constantinescu   B  |  V
13113d177a5cSEmil Constantinescu .ve
13123d177a5cSEmil Constantinescu 
13133d177a5cSEmil Constantinescu   combined with a vector c of abscissa.  "Diagonally implicit" means that A is lower triangular.
13143d177a5cSEmil Constantinescu   A step of the general method reads
13153d177a5cSEmil Constantinescu 
13163d177a5cSEmil Constantinescu .vb
13173d177a5cSEmil Constantinescu   [ Y ] = [A  U] [  Y'   ]
13183d177a5cSEmil Constantinescu   [X^k] = [B  V] [X^{k-1}]
13193d177a5cSEmil Constantinescu .ve
13203d177a5cSEmil Constantinescu 
13213d177a5cSEmil Constantinescu   where Y is the multivector of stage values, Y' is the multivector of stage derivatives, X^k is the Nordsieck vector of
13223d177a5cSEmil Constantinescu   the solution at step k.  The Nordsieck vector consists of the first r moments of the solution, given by
13233d177a5cSEmil Constantinescu 
13243d177a5cSEmil Constantinescu .vb
13253d177a5cSEmil Constantinescu   X = [x_0,x_1,...,x_{r-1}] = [x, h x', h^2 x'', ..., h^{r-1} x^{(r-1)} ]
13263d177a5cSEmil Constantinescu .ve
13273d177a5cSEmil Constantinescu 
13283d177a5cSEmil Constantinescu   If A is lower triangular, we can solve the stages (Y,Y') sequentially
13293d177a5cSEmil Constantinescu 
13303d177a5cSEmil Constantinescu .vb
13313d177a5cSEmil Constantinescu   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}
13323d177a5cSEmil Constantinescu .ve
13333d177a5cSEmil Constantinescu 
13343d177a5cSEmil Constantinescu   and then construct the pieces to carry to the next step
13353d177a5cSEmil Constantinescu 
13363d177a5cSEmil Constantinescu .vb
13373d177a5cSEmil Constantinescu   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}
13383d177a5cSEmil Constantinescu .ve
13393d177a5cSEmil Constantinescu 
13403d177a5cSEmil Constantinescu   Note that when the equations are cast in implicit form, we are using the stage equation to define y'_i
13413d177a5cSEmil Constantinescu   in terms of y_i and known stuff (y_j for j<i and x_j for all j).
13423d177a5cSEmil Constantinescu 
13433d177a5cSEmil Constantinescu   Error estimation
13443d177a5cSEmil Constantinescu 
13453d177a5cSEmil Constantinescu   At present, the most attractive GL methods for stiff problems are singly diagonally implicit schemes which posses
13463d177a5cSEmil Constantinescu   Inherent Runge-Kutta Stability (IRKS).  These methods have r=s, the number of items passed between steps is equal to
13473d177a5cSEmil Constantinescu   the number of stages.  The order and stage-order are one less than the number of stages.  We use the error estimates
13483d177a5cSEmil Constantinescu   in the 2007 paper which provide the following estimates
13493d177a5cSEmil Constantinescu 
13503d177a5cSEmil Constantinescu .vb
13513d177a5cSEmil Constantinescu   h^{p+1} X^{(p+1)}          = phi_0^T Y' + [0 psi_0^T] Xold
13523d177a5cSEmil Constantinescu   h^{p+2} X^{(p+2)}          = phi_1^T Y' + [0 psi_1^T] Xold
13533d177a5cSEmil Constantinescu   h^{p+2} (dx'/dx) X^{(p+1)} = phi_2^T Y' + [0 psi_2^T] Xold
13543d177a5cSEmil Constantinescu .ve
13553d177a5cSEmil Constantinescu 
13563d177a5cSEmil Constantinescu   These estimates are accurate to O(h^{p+3}).
13573d177a5cSEmil Constantinescu 
13583d177a5cSEmil Constantinescu   Changing the step size
13593d177a5cSEmil Constantinescu 
13603d177a5cSEmil Constantinescu   We use the generalized "rescale and modify" scheme, see equation (4.5) of the 2007 paper.
13613d177a5cSEmil Constantinescu 
13623d177a5cSEmil Constantinescu   Level: beginner
13633d177a5cSEmil Constantinescu 
13643d177a5cSEmil Constantinescu   References:
1365606c0280SSatish Balay + * - John Butcher and Z. Jackieweicz and W. Wright, On error propagation in general linear methods for
13663d177a5cSEmil Constantinescu   ordinary differential equations, Journal of Complexity, Vol 23, 2007.
1367606c0280SSatish Balay - * - John Butcher, Numerical methods for ordinary differential equations, second edition, Wiley, 2009.
13683d177a5cSEmil Constantinescu 
1369db781477SPatrick Sanan .seealso: `TSCreate()`, `TS`, `TSSetType()`
13703d177a5cSEmil Constantinescu 
13713d177a5cSEmil Constantinescu M*/
13729371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode TSCreate_GLLE(TS ts) {
13733d177a5cSEmil Constantinescu   TS_GLLE *gl;
13743d177a5cSEmil Constantinescu 
13753d177a5cSEmil Constantinescu   PetscFunctionBegin;
13769566063dSJacob Faibussowitsch   PetscCall(TSGLLEInitializePackage());
13773d177a5cSEmil Constantinescu 
13789566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(ts, &gl));
13793d177a5cSEmil Constantinescu   ts->data = (void *)gl;
13803d177a5cSEmil Constantinescu 
13813d177a5cSEmil Constantinescu   ts->ops->reset          = TSReset_GLLE;
13823d177a5cSEmil Constantinescu   ts->ops->destroy        = TSDestroy_GLLE;
13833d177a5cSEmil Constantinescu   ts->ops->view           = TSView_GLLE;
13843d177a5cSEmil Constantinescu   ts->ops->setup          = TSSetUp_GLLE;
13853d177a5cSEmil Constantinescu   ts->ops->solve          = TSSolve_GLLE;
13863d177a5cSEmil Constantinescu   ts->ops->setfromoptions = TSSetFromOptions_GLLE;
13873d177a5cSEmil Constantinescu   ts->ops->snesfunction   = SNESTSFormFunction_GLLE;
13883d177a5cSEmil Constantinescu   ts->ops->snesjacobian   = SNESTSFormJacobian_GLLE;
13893d177a5cSEmil Constantinescu 
1390efd4aadfSBarry Smith   ts->usessnes = PETSC_TRUE;
1391efd4aadfSBarry Smith 
13923d177a5cSEmil Constantinescu   gl->max_step_rejections = 1;
13933d177a5cSEmil Constantinescu   gl->min_order           = 1;
13943d177a5cSEmil Constantinescu   gl->max_order           = 3;
13953d177a5cSEmil Constantinescu   gl->start_order         = 1;
13963d177a5cSEmil Constantinescu   gl->current_scheme      = -1;
13973d177a5cSEmil Constantinescu   gl->extrapolate         = PETSC_FALSE;
13983d177a5cSEmil Constantinescu 
13993d177a5cSEmil Constantinescu   gl->wrms_atol = 1e-8;
14003d177a5cSEmil Constantinescu   gl->wrms_rtol = 1e-5;
14013d177a5cSEmil Constantinescu 
14029566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLESetType_C", &TSGLLESetType_GLLE));
14039566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLESetAcceptType_C", &TSGLLESetAcceptType_GLLE));
14049566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLEGetAdapt_C", &TSGLLEGetAdapt_GLLE));
14053d177a5cSEmil Constantinescu   PetscFunctionReturn(0);
14063d177a5cSEmil Constantinescu }
1407