xref: /petsc/src/ts/impls/implicit/glle/glle.c (revision 1cc06b555e92f8ec64db10330b8bbd830e5bc876)
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 */
13d71ae5a4SJacob Faibussowitsch static PetscScalar Factorial(PetscInt n)
14d71ae5a4SJacob Faibussowitsch {
153d177a5cSEmil Constantinescu   PetscInt i;
163d177a5cSEmil Constantinescu   if (n < 12) { /* Can compute with 32-bit integers */
173d177a5cSEmil Constantinescu     PetscInt f = 1;
183d177a5cSEmil Constantinescu     for (i = 2; i <= n; i++) f *= i;
193d177a5cSEmil Constantinescu     return (PetscScalar)f;
203d177a5cSEmil Constantinescu   } else {
213d177a5cSEmil Constantinescu     PetscScalar f = 1.;
223d177a5cSEmil Constantinescu     for (i = 2; i <= n; i++) f *= (PetscScalar)i;
233d177a5cSEmil Constantinescu     return f;
243d177a5cSEmil Constantinescu   }
253d177a5cSEmil Constantinescu }
263d177a5cSEmil Constantinescu 
273d177a5cSEmil Constantinescu /* This function is pure */
28d71ae5a4SJacob Faibussowitsch static PetscScalar CPowF(PetscScalar c, PetscInt p)
29d71ae5a4SJacob Faibussowitsch {
303d177a5cSEmil Constantinescu   return PetscPowRealInt(PetscRealPart(c), p) / Factorial(p);
313d177a5cSEmil Constantinescu }
323d177a5cSEmil Constantinescu 
33d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEGetVecs(TS ts, DM dm, Vec *Z, Vec *Ydotstage)
34d71ae5a4SJacob Faibussowitsch {
353d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
363d177a5cSEmil Constantinescu 
373d177a5cSEmil Constantinescu   PetscFunctionBegin;
383d177a5cSEmil Constantinescu   if (Z) {
393d177a5cSEmil Constantinescu     if (dm && dm != ts->dm) {
409566063dSJacob Faibussowitsch       PetscCall(DMGetNamedGlobalVector(dm, "TSGLLE_Z", Z));
413d177a5cSEmil Constantinescu     } else *Z = gl->Z;
423d177a5cSEmil Constantinescu   }
433d177a5cSEmil Constantinescu   if (Ydotstage) {
443d177a5cSEmil Constantinescu     if (dm && dm != ts->dm) {
459566063dSJacob Faibussowitsch       PetscCall(DMGetNamedGlobalVector(dm, "TSGLLE_Ydot", Ydotstage));
463d177a5cSEmil Constantinescu     } else *Ydotstage = gl->Ydot[gl->stage];
473d177a5cSEmil Constantinescu   }
483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
493d177a5cSEmil Constantinescu }
503d177a5cSEmil Constantinescu 
51d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLERestoreVecs(TS ts, DM dm, Vec *Z, Vec *Ydotstage)
52d71ae5a4SJacob Faibussowitsch {
533d177a5cSEmil Constantinescu   PetscFunctionBegin;
543d177a5cSEmil Constantinescu   if (Z) {
5548a46eb9SPierre Jolivet     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSGLLE_Z", Z));
563d177a5cSEmil Constantinescu   }
573d177a5cSEmil Constantinescu   if (Ydotstage) {
5848a46eb9SPierre Jolivet     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSGLLE_Ydot", Ydotstage));
593d177a5cSEmil Constantinescu   }
603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
613d177a5cSEmil Constantinescu }
623d177a5cSEmil Constantinescu 
63d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCoarsenHook_TSGLLE(DM fine, DM coarse, void *ctx)
64d71ae5a4SJacob Faibussowitsch {
653d177a5cSEmil Constantinescu   PetscFunctionBegin;
663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
673d177a5cSEmil Constantinescu }
683d177a5cSEmil Constantinescu 
69d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMRestrictHook_TSGLLE(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse, void *ctx)
70d71ae5a4SJacob Faibussowitsch {
713d177a5cSEmil Constantinescu   TS  ts = (TS)ctx;
723d177a5cSEmil Constantinescu   Vec Ydot, Ydot_c;
733d177a5cSEmil Constantinescu 
743d177a5cSEmil Constantinescu   PetscFunctionBegin;
759566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, fine, NULL, &Ydot));
769566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, coarse, NULL, &Ydot_c));
779566063dSJacob Faibussowitsch   PetscCall(MatRestrict(restrct, Ydot, Ydot_c));
789566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(Ydot_c, rscale, Ydot_c));
799566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, fine, NULL, &Ydot));
809566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, coarse, NULL, &Ydot_c));
813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
823d177a5cSEmil Constantinescu }
833d177a5cSEmil Constantinescu 
84d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSubDomainHook_TSGLLE(DM dm, DM subdm, void *ctx)
85d71ae5a4SJacob Faibussowitsch {
863d177a5cSEmil Constantinescu   PetscFunctionBegin;
873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
883d177a5cSEmil Constantinescu }
893d177a5cSEmil Constantinescu 
90d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSubDomainRestrictHook_TSGLLE(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx)
91d71ae5a4SJacob Faibussowitsch {
923d177a5cSEmil Constantinescu   TS  ts = (TS)ctx;
933d177a5cSEmil Constantinescu   Vec Ydot, Ydot_s;
943d177a5cSEmil Constantinescu 
953d177a5cSEmil Constantinescu   PetscFunctionBegin;
969566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, dm, NULL, &Ydot));
979566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, subdm, NULL, &Ydot_s));
983d177a5cSEmil Constantinescu 
999566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(gscat, Ydot, Ydot_s, INSERT_VALUES, SCATTER_FORWARD));
1009566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(gscat, Ydot, Ydot_s, INSERT_VALUES, SCATTER_FORWARD));
1013d177a5cSEmil Constantinescu 
1029566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, dm, NULL, &Ydot));
1039566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, subdm, NULL, &Ydot_s));
1043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1053d177a5cSEmil Constantinescu }
1063d177a5cSEmil Constantinescu 
107d71ae5a4SJacob Faibussowitsch 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)
108d71ae5a4SJacob Faibussowitsch {
1093d177a5cSEmil Constantinescu   TSGLLEScheme scheme;
1103d177a5cSEmil Constantinescu   PetscInt     j;
1113d177a5cSEmil Constantinescu 
1123d177a5cSEmil Constantinescu   PetscFunctionBegin;
11308401ef6SPierre Jolivet   PetscCheck(p >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Scheme order must be positive");
11408401ef6SPierre Jolivet   PetscCheck(r >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "At least one item must be carried between steps");
11508401ef6SPierre Jolivet   PetscCheck(s >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "At least one stage is required");
116064a246eSJacob Faibussowitsch   PetscValidPointer(inscheme, 10);
117c793f718SLisandro Dalcin   *inscheme = NULL;
1189566063dSJacob Faibussowitsch   PetscCall(PetscNew(&scheme));
1193d177a5cSEmil Constantinescu   scheme->p = p;
1203d177a5cSEmil Constantinescu   scheme->q = q;
1213d177a5cSEmil Constantinescu   scheme->r = r;
1223d177a5cSEmil Constantinescu   scheme->s = s;
1233d177a5cSEmil Constantinescu 
1249566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(s, &scheme->c, s * s, &scheme->a, r * s, &scheme->b, r * s, &scheme->u, r * r, &scheme->v));
1259566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(scheme->c, c, s));
1263d177a5cSEmil Constantinescu   for (j = 0; j < s * s; j++) scheme->a[j] = (PetscAbsScalar(a[j]) < 1e-12) ? 0 : a[j];
1273d177a5cSEmil Constantinescu   for (j = 0; j < r * s; j++) scheme->b[j] = (PetscAbsScalar(b[j]) < 1e-12) ? 0 : b[j];
1283d177a5cSEmil Constantinescu   for (j = 0; j < s * r; j++) scheme->u[j] = (PetscAbsScalar(u[j]) < 1e-12) ? 0 : u[j];
1293d177a5cSEmil Constantinescu   for (j = 0; j < r * r; j++) scheme->v[j] = (PetscAbsScalar(v[j]) < 1e-12) ? 0 : v[j];
1303d177a5cSEmil Constantinescu 
1319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(r, &scheme->alpha, r, &scheme->beta, r, &scheme->gamma, 3 * s, &scheme->phi, 3 * r, &scheme->psi, r, &scheme->stage_error));
1323d177a5cSEmil Constantinescu   {
1333d177a5cSEmil Constantinescu     PetscInt     i, j, k, ss = s + 2;
1343d177a5cSEmil Constantinescu     PetscBLASInt m, n, one = 1, *ipiv, lwork = 4 * ((s + 3) * 3 + 3), info, ldb;
1353d177a5cSEmil Constantinescu     PetscReal    rcond, *sing, *workreal;
1363d177a5cSEmil Constantinescu     PetscScalar *ImV, *H, *bmat, *workscalar, *c = scheme->c, *a = scheme->a, *b = scheme->b, *u = scheme->u, *v = scheme->v;
1373d177a5cSEmil Constantinescu     PetscBLASInt rank;
1389566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(PetscSqr(r), &ImV, 3 * s, &H, 3 * ss, &bmat, lwork, &workscalar, 5 * (3 + r), &workreal, r + s, &sing, r + s, &ipiv));
1393d177a5cSEmil Constantinescu 
1403d177a5cSEmil Constantinescu     /* column-major input */
1413d177a5cSEmil Constantinescu     for (i = 0; i < r - 1; i++) {
1423d177a5cSEmil Constantinescu       for (j = 0; j < r - 1; j++) ImV[i + j * r] = 1.0 * (i == j) - v[(i + 1) * r + j + 1];
1433d177a5cSEmil Constantinescu     }
1443d177a5cSEmil Constantinescu     /* Build right hand side for alpha (tp - glm.B(2:end,:)*(glm.c.^(p)./factorial(p))) */
1453d177a5cSEmil Constantinescu     for (i = 1; i < r; i++) {
1463d177a5cSEmil Constantinescu       scheme->alpha[i] = 1. / Factorial(p + 1 - i);
1473d177a5cSEmil Constantinescu       for (j = 0; j < s; j++) scheme->alpha[i] -= b[i * s + j] * CPowF(c[j], p);
1483d177a5cSEmil Constantinescu     }
1499566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(r - 1, &m));
1509566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(r, &n));
151792fecdfSBarry Smith     PetscCallBLAS("LAPACKgesv", LAPACKgesv_(&m, &one, ImV, &n, ipiv, scheme->alpha + 1, &n, &info));
15208401ef6SPierre Jolivet     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GESV");
15308401ef6SPierre Jolivet     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_MAT_LU_ZRPVT, "Bad LU factorization");
1543d177a5cSEmil Constantinescu 
1553d177a5cSEmil Constantinescu     /* Build right hand side for beta (tp1 - glm.B(2:end,:)*(glm.c.^(p+1)./factorial(p+1)) - e.alpha) */
1563d177a5cSEmil Constantinescu     for (i = 1; i < r; i++) {
1573d177a5cSEmil Constantinescu       scheme->beta[i] = 1. / Factorial(p + 2 - i) - scheme->alpha[i];
1583d177a5cSEmil Constantinescu       for (j = 0; j < s; j++) scheme->beta[i] -= b[i * s + j] * CPowF(c[j], p + 1);
1593d177a5cSEmil Constantinescu     }
160792fecdfSBarry Smith     PetscCallBLAS("LAPACKgetrs", LAPACKgetrs_("No transpose", &m, &one, ImV, &n, ipiv, scheme->beta + 1, &n, &info));
16108401ef6SPierre Jolivet     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GETRS");
16208401ef6SPierre Jolivet     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Should not happen");
1633d177a5cSEmil Constantinescu 
1643d177a5cSEmil Constantinescu     /* Build stage_error vector
1653d177a5cSEmil Constantinescu            xi = glm.c.^(p+1)/factorial(p+1) - glm.A*glm.c.^p/factorial(p) + glm.U(:,2:end)*e.alpha;
1663d177a5cSEmil Constantinescu     */
1673d177a5cSEmil Constantinescu     for (i = 0; i < s; i++) {
1683d177a5cSEmil Constantinescu       scheme->stage_error[i] = CPowF(c[i], p + 1);
1693d177a5cSEmil Constantinescu       for (j = 0; j < s; j++) scheme->stage_error[i] -= a[i * s + j] * CPowF(c[j], p);
1703d177a5cSEmil Constantinescu       for (j = 1; j < r; j++) scheme->stage_error[i] += u[i * r + j] * scheme->alpha[j];
1713d177a5cSEmil Constantinescu     }
1723d177a5cSEmil Constantinescu 
1733d177a5cSEmil Constantinescu     /* alpha[0] (epsilon in B,J,W 2007)
1743d177a5cSEmil Constantinescu            epsilon = 1/factorial(p+1) - B(1,:)*c.^p/factorial(p) + V(1,2:end)*e.alpha;
1753d177a5cSEmil Constantinescu     */
1763d177a5cSEmil Constantinescu     scheme->alpha[0] = 1. / Factorial(p + 1);
1773d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) scheme->alpha[0] -= b[0 * s + j] * CPowF(c[j], p);
1783d177a5cSEmil Constantinescu     for (j = 1; j < r; j++) scheme->alpha[0] += v[0 * r + j] * scheme->alpha[j];
1793d177a5cSEmil Constantinescu 
1803d177a5cSEmil Constantinescu     /* right hand side for gamma (glm.B(2:end,:)*e.xi - e.epsilon*eye(s-1,1)) */
1813d177a5cSEmil Constantinescu     for (i = 1; i < r; i++) {
1823d177a5cSEmil Constantinescu       scheme->gamma[i] = (i == 1 ? -1. : 0) * scheme->alpha[0];
1833d177a5cSEmil Constantinescu       for (j = 0; j < s; j++) scheme->gamma[i] += b[i * s + j] * scheme->stage_error[j];
1843d177a5cSEmil Constantinescu     }
185792fecdfSBarry Smith     PetscCallBLAS("LAPACKgetrs", LAPACKgetrs_("No transpose", &m, &one, ImV, &n, ipiv, scheme->gamma + 1, &n, &info));
18608401ef6SPierre Jolivet     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GETRS");
18708401ef6SPierre Jolivet     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Should not happen");
1883d177a5cSEmil Constantinescu 
1893d177a5cSEmil Constantinescu     /* beta[0] (rho in B,J,W 2007)
1903d177a5cSEmil Constantinescu         e.rho = 1/factorial(p+2) - glm.B(1,:)*glm.c.^(p+1)/factorial(p+1) ...
1913d177a5cSEmil Constantinescu             + glm.V(1,2:end)*e.beta;% - e.epsilon;
1923d177a5cSEmil Constantinescu     % Note: The paper (B,J,W 2007) includes the last term in their definition
1933d177a5cSEmil Constantinescu     * */
1943d177a5cSEmil Constantinescu     scheme->beta[0] = 1. / Factorial(p + 2);
1953d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) scheme->beta[0] -= b[0 * s + j] * CPowF(c[j], p + 1);
1963d177a5cSEmil Constantinescu     for (j = 1; j < r; j++) scheme->beta[0] += v[0 * r + j] * scheme->beta[j];
1973d177a5cSEmil Constantinescu 
1983d177a5cSEmil Constantinescu     /* gamma[0] (sigma in B,J,W 2007)
1993d177a5cSEmil Constantinescu     *   e.sigma = glm.B(1,:)*e.xi + glm.V(1,2:end)*e.gamma;
2003d177a5cSEmil Constantinescu     * */
2013d177a5cSEmil Constantinescu     scheme->gamma[0] = 0.0;
2023d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) scheme->gamma[0] += b[0 * s + j] * scheme->stage_error[j];
2033d177a5cSEmil Constantinescu     for (j = 1; j < r; j++) scheme->gamma[0] += v[0 * s + j] * scheme->gamma[j];
2043d177a5cSEmil Constantinescu 
2053d177a5cSEmil Constantinescu     /* Assemble H
20663a3b9bcSJacob Faibussowitsch     *    % " PetscInt_FMT "etermine the error estimators phi
2073d177a5cSEmil Constantinescu        H = [[cpow(glm.c,p) + C*e.alpha] [cpow(glm.c,p+1) + C*e.beta] ...
2083d177a5cSEmil Constantinescu                [e.xi - C*(e.gamma + 0*e.epsilon*eye(s-1,1))]]';
2093d177a5cSEmil Constantinescu     % Paper has formula above without the 0, but that term must be left
2103d177a5cSEmil Constantinescu     % out to satisfy the conditions they propose and to make the
2113d177a5cSEmil Constantinescu     % example schemes work
2123d177a5cSEmil Constantinescu     e.H = H;
2133d177a5cSEmil Constantinescu     e.phi = (H \ [1 0 0;1 1 0;0 0 -1])';
2143d177a5cSEmil Constantinescu     e.psi = -e.phi*C;
2153d177a5cSEmil Constantinescu     * */
2163d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) {
2173d177a5cSEmil Constantinescu       H[0 + j * 3] = CPowF(c[j], p);
2183d177a5cSEmil Constantinescu       H[1 + j * 3] = CPowF(c[j], p + 1);
2193d177a5cSEmil Constantinescu       H[2 + j * 3] = scheme->stage_error[j];
2203d177a5cSEmil Constantinescu       for (k = 1; k < r; k++) {
2213d177a5cSEmil Constantinescu         H[0 + j * 3] += CPowF(c[j], k - 1) * scheme->alpha[k];
2223d177a5cSEmil Constantinescu         H[1 + j * 3] += CPowF(c[j], k - 1) * scheme->beta[k];
2233d177a5cSEmil Constantinescu         H[2 + j * 3] -= CPowF(c[j], k - 1) * scheme->gamma[k];
2243d177a5cSEmil Constantinescu       }
2253d177a5cSEmil Constantinescu     }
2269371c9d4SSatish Balay     bmat[0 + 0 * ss] = 1.;
2279371c9d4SSatish Balay     bmat[0 + 1 * ss] = 0.;
2289371c9d4SSatish Balay     bmat[0 + 2 * ss] = 0.;
2299371c9d4SSatish Balay     bmat[1 + 0 * ss] = 1.;
2309371c9d4SSatish Balay     bmat[1 + 1 * ss] = 1.;
2319371c9d4SSatish Balay     bmat[1 + 2 * ss] = 0.;
2329371c9d4SSatish Balay     bmat[2 + 0 * ss] = 0.;
2339371c9d4SSatish Balay     bmat[2 + 1 * ss] = 0.;
2349371c9d4SSatish Balay     bmat[2 + 2 * ss] = -1.;
2353d177a5cSEmil Constantinescu     m                = 3;
2369566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(s, &n));
2379566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(ss, &ldb));
2383d177a5cSEmil Constantinescu     rcond = 1e-12;
2393d177a5cSEmil Constantinescu #if defined(PETSC_USE_COMPLEX)
2403d177a5cSEmil Constantinescu     /* ZGELSS( M, N, NRHS, A, LDA, B, LDB, S, RCOND, RANK, WORK, LWORK, RWORK, INFO) */
241792fecdfSBarry Smith     PetscCallBLAS("LAPACKgelss", LAPACKgelss_(&m, &n, &m, H, &m, bmat, &ldb, sing, &rcond, &rank, workscalar, &lwork, workreal, &info));
2423d177a5cSEmil Constantinescu #else
2433d177a5cSEmil Constantinescu     /* DGELSS( M, N, NRHS, A, LDA, B, LDB, S, RCOND, RANK, WORK, LWORK, INFO) */
244792fecdfSBarry Smith     PetscCallBLAS("LAPACKgelss", LAPACKgelss_(&m, &n, &m, H, &m, bmat, &ldb, sing, &rcond, &rank, workscalar, &lwork, &info));
2453d177a5cSEmil Constantinescu #endif
24608401ef6SPierre Jolivet     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GELSS");
24708401ef6SPierre Jolivet     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "SVD failed to converge");
2483d177a5cSEmil Constantinescu 
2493d177a5cSEmil Constantinescu     for (j = 0; j < 3; j++) {
2503d177a5cSEmil Constantinescu       for (k = 0; k < s; k++) scheme->phi[k + j * s] = bmat[k + j * ss];
2513d177a5cSEmil Constantinescu     }
2523d177a5cSEmil Constantinescu 
2533d177a5cSEmil Constantinescu     /* the other part of the error estimator, psi in B,J,W 2007 */
2543d177a5cSEmil Constantinescu     scheme->psi[0 * r + 0] = 0.;
2553d177a5cSEmil Constantinescu     scheme->psi[1 * r + 0] = 0.;
2563d177a5cSEmil Constantinescu     scheme->psi[2 * r + 0] = 0.;
2573d177a5cSEmil Constantinescu     for (j = 1; j < r; j++) {
2583d177a5cSEmil Constantinescu       scheme->psi[0 * r + j] = 0.;
2593d177a5cSEmil Constantinescu       scheme->psi[1 * r + j] = 0.;
2603d177a5cSEmil Constantinescu       scheme->psi[2 * r + j] = 0.;
2613d177a5cSEmil Constantinescu       for (k = 0; k < s; k++) {
2623d177a5cSEmil Constantinescu         scheme->psi[0 * r + j] -= CPowF(c[k], j - 1) * scheme->phi[0 * s + k];
2633d177a5cSEmil Constantinescu         scheme->psi[1 * r + j] -= CPowF(c[k], j - 1) * scheme->phi[1 * s + k];
2643d177a5cSEmil Constantinescu         scheme->psi[2 * r + j] -= CPowF(c[k], j - 1) * scheme->phi[2 * s + k];
2653d177a5cSEmil Constantinescu       }
2663d177a5cSEmil Constantinescu     }
2679566063dSJacob Faibussowitsch     PetscCall(PetscFree7(ImV, H, bmat, workscalar, workreal, sing, ipiv));
2683d177a5cSEmil Constantinescu   }
2693d177a5cSEmil Constantinescu   /* Check which properties are satisfied */
2703d177a5cSEmil Constantinescu   scheme->stiffly_accurate = PETSC_TRUE;
2713d177a5cSEmil Constantinescu   if (scheme->c[s - 1] != 1.) scheme->stiffly_accurate = PETSC_FALSE;
2729371c9d4SSatish Balay   for (j = 0; j < s; j++)
2739371c9d4SSatish Balay     if (a[(s - 1) * s + j] != b[j]) scheme->stiffly_accurate = PETSC_FALSE;
2749371c9d4SSatish Balay   for (j = 0; j < r; j++)
2759371c9d4SSatish Balay     if (u[(s - 1) * r + j] != v[j]) scheme->stiffly_accurate = PETSC_FALSE;
2763d177a5cSEmil Constantinescu   scheme->fsal = scheme->stiffly_accurate; /* FSAL is stronger */
2779371c9d4SSatish Balay   for (j = 0; j < s - 1; j++)
2789371c9d4SSatish Balay     if (r > 1 && b[1 * s + j] != 0.) scheme->fsal = PETSC_FALSE;
2793d177a5cSEmil Constantinescu   if (b[1 * s + r - 1] != 1.) scheme->fsal = PETSC_FALSE;
2809371c9d4SSatish Balay   for (j = 0; j < r; j++)
2819371c9d4SSatish Balay     if (r > 1 && v[1 * r + j] != 0.) scheme->fsal = PETSC_FALSE;
2823d177a5cSEmil Constantinescu 
2833d177a5cSEmil Constantinescu   *inscheme = scheme;
2843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2853d177a5cSEmil Constantinescu }
2863d177a5cSEmil Constantinescu 
287d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLESchemeDestroy(TSGLLEScheme sc)
288d71ae5a4SJacob Faibussowitsch {
2893d177a5cSEmil Constantinescu   PetscFunctionBegin;
2909566063dSJacob Faibussowitsch   PetscCall(PetscFree5(sc->c, sc->a, sc->b, sc->u, sc->v));
2919566063dSJacob Faibussowitsch   PetscCall(PetscFree6(sc->alpha, sc->beta, sc->gamma, sc->phi, sc->psi, sc->stage_error));
2929566063dSJacob Faibussowitsch   PetscCall(PetscFree(sc));
2933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2943d177a5cSEmil Constantinescu }
2953d177a5cSEmil Constantinescu 
296d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEDestroy_Default(TS_GLLE *gl)
297d71ae5a4SJacob Faibussowitsch {
2983d177a5cSEmil Constantinescu   PetscInt i;
2993d177a5cSEmil Constantinescu 
3003d177a5cSEmil Constantinescu   PetscFunctionBegin;
3013d177a5cSEmil Constantinescu   for (i = 0; i < gl->nschemes; i++) {
3029566063dSJacob Faibussowitsch     if (gl->schemes[i]) PetscCall(TSGLLESchemeDestroy(gl->schemes[i]));
3033d177a5cSEmil Constantinescu   }
3049566063dSJacob Faibussowitsch   PetscCall(PetscFree(gl->schemes));
3053d177a5cSEmil Constantinescu   gl->nschemes = 0;
3069566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(gl->type_name, sizeof(gl->type_name)));
3073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3083d177a5cSEmil Constantinescu }
3093d177a5cSEmil Constantinescu 
310d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEViewTable_Private(PetscViewer viewer, PetscInt m, PetscInt n, const PetscScalar a[], const char name[])
311d71ae5a4SJacob Faibussowitsch {
3123d177a5cSEmil Constantinescu   PetscBool iascii;
3133d177a5cSEmil Constantinescu   PetscInt  i, j;
3143d177a5cSEmil Constantinescu 
3153d177a5cSEmil Constantinescu   PetscFunctionBegin;
3169566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
3173d177a5cSEmil Constantinescu   if (iascii) {
3189566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "%30s = [", name));
3193d177a5cSEmil Constantinescu     for (i = 0; i < m; i++) {
3209566063dSJacob Faibussowitsch       if (i) PetscCall(PetscViewerASCIIPrintf(viewer, "%30s   [", ""));
3219566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
32248a46eb9SPierre Jolivet       for (j = 0; j < n; j++) PetscCall(PetscViewerASCIIPrintf(viewer, " %12.8g", (double)PetscRealPart(a[i * n + j])));
3239566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "]\n"));
3249566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
3253d177a5cSEmil Constantinescu     }
3263d177a5cSEmil Constantinescu   }
3273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3283d177a5cSEmil Constantinescu }
3293d177a5cSEmil Constantinescu 
330d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLESchemeView(TSGLLEScheme sc, PetscBool view_details, PetscViewer viewer)
331d71ae5a4SJacob Faibussowitsch {
3323d177a5cSEmil Constantinescu   PetscBool iascii;
3333d177a5cSEmil Constantinescu 
3343d177a5cSEmil Constantinescu   PetscFunctionBegin;
3359566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
3363d177a5cSEmil Constantinescu   if (iascii) {
33763a3b9bcSJacob 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));
3389566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
3399566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Stiffly accurate: %s,  FSAL: %s\n", sc->stiffly_accurate ? "yes" : "no", sc->fsal ? "yes" : "no"));
3409371c9d4SSatish 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])));
3419566063dSJacob Faibussowitsch     PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->s, sc->c, "Abscissas c"));
3423d177a5cSEmil Constantinescu     if (view_details) {
3439566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, sc->s, sc->s, sc->a, "A"));
3449566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, sc->r, sc->s, sc->b, "B"));
3459566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, sc->s, sc->r, sc->u, "U"));
3469566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, sc->r, sc->r, sc->v, "V"));
3473d177a5cSEmil Constantinescu 
3489566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 3, sc->s, sc->phi, "Error estimate phi"));
3499566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 3, sc->r, sc->psi, "Error estimate psi"));
3509566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->r, sc->alpha, "Modify alpha"));
3519566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->r, sc->beta, "Modify beta"));
3529566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->r, sc->gamma, "Modify gamma"));
3539566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->s, sc->stage_error, "Stage error xi"));
3543d177a5cSEmil Constantinescu     }
3559566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
35698921bdaSJacob Faibussowitsch   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Viewer type %s not supported", ((PetscObject)viewer)->type_name);
3573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3583d177a5cSEmil Constantinescu }
3593d177a5cSEmil Constantinescu 
360d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEEstimateHigherMoments_Default(TSGLLEScheme sc, PetscReal h, Vec Ydot[], Vec Xold[], Vec hm[])
361d71ae5a4SJacob Faibussowitsch {
3623d177a5cSEmil Constantinescu   PetscInt i;
3633d177a5cSEmil Constantinescu 
3643d177a5cSEmil Constantinescu   PetscFunctionBegin;
365cad9d221SBarry Smith   PetscCheck(sc->r <= 64 && sc->s <= 64, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Ridiculous number of stages or items passed between stages");
3663d177a5cSEmil Constantinescu   /* build error vectors*/
3673d177a5cSEmil Constantinescu   for (i = 0; i < 3; i++) {
3683d177a5cSEmil Constantinescu     PetscScalar phih[64];
3693d177a5cSEmil Constantinescu     PetscInt    j;
3703d177a5cSEmil Constantinescu     for (j = 0; j < sc->s; j++) phih[j] = sc->phi[i * sc->s + j] * h;
3719566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(hm[i]));
3729566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(hm[i], sc->s, phih, Ydot));
3739566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(hm[i], sc->r, &sc->psi[i * sc->r], Xold));
3743d177a5cSEmil Constantinescu   }
3753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3763d177a5cSEmil Constantinescu }
3773d177a5cSEmil Constantinescu 
378d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLECompleteStep_Rescale(TSGLLEScheme sc, PetscReal h, TSGLLEScheme next_sc, PetscReal next_h, Vec Ydot[], Vec Xold[], Vec X[])
379d71ae5a4SJacob Faibussowitsch {
3803d177a5cSEmil Constantinescu   PetscScalar brow[32], vrow[32];
3813d177a5cSEmil Constantinescu   PetscInt    i, j, r, s;
3823d177a5cSEmil Constantinescu 
3833d177a5cSEmil Constantinescu   PetscFunctionBegin;
3843d177a5cSEmil Constantinescu   /* Build the new solution from (X,Ydot) */
3853d177a5cSEmil Constantinescu   r = sc->r;
3863d177a5cSEmil Constantinescu   s = sc->s;
3873d177a5cSEmil Constantinescu   for (i = 0; i < r; i++) {
3889566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(X[i]));
3893d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) brow[j] = h * sc->b[i * s + j];
3909566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[i], s, brow, Ydot));
3913d177a5cSEmil Constantinescu     for (j = 0; j < r; j++) vrow[j] = sc->v[i * r + j];
3929566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[i], r, vrow, Xold));
3933d177a5cSEmil Constantinescu   }
3943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3953d177a5cSEmil Constantinescu }
3963d177a5cSEmil Constantinescu 
397d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLECompleteStep_RescaleAndModify(TSGLLEScheme sc, PetscReal h, TSGLLEScheme next_sc, PetscReal next_h, Vec Ydot[], Vec Xold[], Vec X[])
398d71ae5a4SJacob Faibussowitsch {
3993d177a5cSEmil Constantinescu   PetscScalar brow[32], vrow[32];
4003d177a5cSEmil Constantinescu   PetscReal   ratio;
4013d177a5cSEmil Constantinescu   PetscInt    i, j, p, r, s;
4023d177a5cSEmil Constantinescu 
4033d177a5cSEmil Constantinescu   PetscFunctionBegin;
4043d177a5cSEmil Constantinescu   /* Build the new solution from (X,Ydot) */
4053d177a5cSEmil Constantinescu   p     = sc->p;
4063d177a5cSEmil Constantinescu   r     = sc->r;
4073d177a5cSEmil Constantinescu   s     = sc->s;
4083d177a5cSEmil Constantinescu   ratio = next_h / h;
4093d177a5cSEmil Constantinescu   for (i = 0; i < r; i++) {
4109566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(X[i]));
4113d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) {
4129371c9d4SSatish 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]));
4133d177a5cSEmil Constantinescu     }
4149566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[i], s, brow, Ydot));
4153d177a5cSEmil Constantinescu     for (j = 0; j < r; j++) {
4169371c9d4SSatish 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]));
4173d177a5cSEmil Constantinescu     }
4189566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[i], r, vrow, Xold));
4193d177a5cSEmil Constantinescu   }
4203d177a5cSEmil Constantinescu   if (r < next_sc->r) {
42108401ef6SPierre Jolivet     PetscCheck(r + 1 == next_sc->r, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot accommodate jump in r greater than 1");
4229566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(X[r]));
4233d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) brow[j] = h * PetscPowRealInt(ratio, p + 1) * sc->phi[0 * s + j];
4249566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[r], s, brow, Ydot));
4253d177a5cSEmil Constantinescu     for (j = 0; j < r; j++) vrow[j] = PetscPowRealInt(ratio, p + 1) * sc->psi[0 * r + j];
4269566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[r], r, vrow, Xold));
4273d177a5cSEmil Constantinescu   }
4283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4293d177a5cSEmil Constantinescu }
4303d177a5cSEmil Constantinescu 
431d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLECreate_IRKS(TS ts)
432d71ae5a4SJacob Faibussowitsch {
4333d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
4343d177a5cSEmil Constantinescu 
4353d177a5cSEmil Constantinescu   PetscFunctionBegin;
4363d177a5cSEmil Constantinescu   gl->Destroy               = TSGLLEDestroy_Default;
4373d177a5cSEmil Constantinescu   gl->EstimateHigherMoments = TSGLLEEstimateHigherMoments_Default;
4383d177a5cSEmil Constantinescu   gl->CompleteStep          = TSGLLECompleteStep_RescaleAndModify;
4399566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(10, &gl->schemes));
4403d177a5cSEmil Constantinescu   gl->nschemes = 0;
4413d177a5cSEmil Constantinescu 
4423d177a5cSEmil Constantinescu   {
4433d177a5cSEmil Constantinescu     /* p=1,q=1, r=s=2, A- and L-stable with error estimates of order 2 and 3
4443d177a5cSEmil Constantinescu     * Listed in Butcher & Podhaisky 2006. On error estimation in general linear methods for stiff ODE.
4453d177a5cSEmil Constantinescu     * irks(0.3,0,[.3,1],[1],1)
4463d177a5cSEmil Constantinescu     * Note: can be made to have classical order (not stage order) 2 by replacing 0.3 with 1-sqrt(1/2)
4473d177a5cSEmil Constantinescu     * but doing so would sacrifice the error estimator.
4483d177a5cSEmil Constantinescu     */
4493d177a5cSEmil Constantinescu     const PetscScalar c[2]    = {3. / 10., 1.};
4509371c9d4SSatish Balay     const PetscScalar a[2][2] = {
4519371c9d4SSatish Balay       {3. / 10., 0       },
4529371c9d4SSatish Balay       {7. / 10., 3. / 10.}
4539371c9d4SSatish Balay     };
4549371c9d4SSatish Balay     const PetscScalar b[2][2] = {
4559371c9d4SSatish Balay       {7. / 10., 3. / 10.},
4569371c9d4SSatish Balay       {0,        1       }
4579371c9d4SSatish Balay     };
4589371c9d4SSatish Balay     const PetscScalar u[2][2] = {
4599371c9d4SSatish Balay       {1, 0},
4609371c9d4SSatish Balay       {1, 0}
4619371c9d4SSatish Balay     };
4629371c9d4SSatish Balay     const PetscScalar v[2][2] = {
4639371c9d4SSatish Balay       {1, 0},
4649371c9d4SSatish Balay       {0, 0}
4659371c9d4SSatish Balay     };
4669566063dSJacob Faibussowitsch     PetscCall(TSGLLESchemeCreate(1, 1, 2, 2, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
4673d177a5cSEmil Constantinescu   }
4683d177a5cSEmil Constantinescu 
4693d177a5cSEmil Constantinescu   {
4703d177a5cSEmil Constantinescu     /* p=q=2, r=s=3: irks(4/9,0,[1:3]/3,[0.33852],1) */
4713d177a5cSEmil Constantinescu     /* http://www.math.auckland.ac.nz/~hpod/atlas/i2a.html */
47297a1619fSSatish Balay     const PetscScalar c[3]    = {1. / 3., 2. / 3., 1};
47397a1619fSSatish Balay     const PetscScalar a[3][3] = {
47497a1619fSSatish Balay       {4. / 9.,              0,                     0      },
47597a1619fSSatish Balay       {1.03750643704090e+00, 4. / 9.,               0      },
47697a1619fSSatish Balay       {7.67024779410304e-01, -3.81140216918943e-01, 4. / 9.}
47797a1619fSSatish Balay     };
47897a1619fSSatish Balay     const PetscScalar b[3][3] = {
47997a1619fSSatish Balay       {0.767024779410304,  -0.381140216918943, 4. / 9.          },
48097a1619fSSatish Balay       {0.000000000000000,  0.000000000000000,  1.000000000000000},
48197a1619fSSatish Balay       {-2.075048385225385, 0.621728385225383,  1.277197204924873}
48297a1619fSSatish Balay     };
48397a1619fSSatish Balay     const PetscScalar u[3][3] = {
48497a1619fSSatish Balay       {1.0000000000000000, -0.1111111111111109, -0.0925925925925922},
48597a1619fSSatish Balay       {1.0000000000000000, -0.8152842148186744, -0.4199095530877056},
48697a1619fSSatish Balay       {1.0000000000000000, 0.1696709930641948,  0.0539741070314165 }
48797a1619fSSatish Balay     };
48897a1619fSSatish Balay     const PetscScalar v[3][3] = {
48997a1619fSSatish Balay       {1.0000000000000000, 0.1696709930641948, 0.0539741070314165},
49097a1619fSSatish Balay       {0.000000000000000,  0.000000000000000,  0.000000000000000 },
49197a1619fSSatish Balay       {0.000000000000000,  0.176122795075129,  0.000000000000000 }
49297a1619fSSatish Balay     };
4939566063dSJacob Faibussowitsch     PetscCall(TSGLLESchemeCreate(2, 2, 3, 3, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
4943d177a5cSEmil Constantinescu   }
4953d177a5cSEmil Constantinescu   {
4963d177a5cSEmil Constantinescu     /* p=q=3, r=s=4: irks(9/40,0,[1:4]/4,[0.3312 1.0050],[0.49541 1;1 0]) */
49797a1619fSSatish Balay     const PetscScalar c[4]    = {0.25, 0.5, 0.75, 1.0};
49897a1619fSSatish Balay     const PetscScalar a[4][4] = {
49997a1619fSSatish Balay       {9. / 40.,             0,                     0,                 0       },
50097a1619fSSatish Balay       {2.11286958887701e-01, 9. / 40.,              0,                 0       },
50197a1619fSSatish Balay       {9.46338294287584e-01, -3.42942861246094e-01, 9. / 40.,          0       },
50297a1619fSSatish Balay       {0.521490453970721,    -0.662474225622980,    0.490476425459734, 9. / 40.}
50397a1619fSSatish Balay     };
50497a1619fSSatish Balay     const PetscScalar b[4][4] = {
50597a1619fSSatish Balay       {0.521490453970721,  -0.662474225622980, 0.490476425459734,  9. / 40.         },
50697a1619fSSatish Balay       {0.000000000000000,  0.000000000000000,  0.000000000000000,  1.000000000000000},
50797a1619fSSatish Balay       {-0.084677029310348, 1.390757514776085,  -1.568157386206001, 2.023192696767826},
50897a1619fSSatish Balay       {0.465383797936408,  1.478273530625148,  -1.930836081010182, 1.644872111193354}
50997a1619fSSatish Balay     };
51097a1619fSSatish Balay     const PetscScalar u[4][4] = {
51197a1619fSSatish Balay       {1.00000000000000000, 0.02500000000001035,  -0.02499999999999053, -0.00442708333332865},
51297a1619fSSatish Balay       {1.00000000000000000, 0.06371304111232945,  -0.04032173972189845, -0.01389438413189452},
51397a1619fSSatish Balay       {1.00000000000000000, -0.07839543304147778, 0.04738685705116663,  0.02032603595928376 },
51497a1619fSSatish Balay       {1.00000000000000000, 0.42550734619251651,  0.10800718022400080,  -0.01726712647760034}
51597a1619fSSatish Balay     };
51697a1619fSSatish Balay     const PetscScalar v[4][4] = {
51797a1619fSSatish Balay       {1.00000000000000000, 0.42550734619251651, 0.10800718022400080, -0.01726712647760034},
51897a1619fSSatish Balay       {0.000000000000000,   0.000000000000000,   0.000000000000000,   0.000000000000000   },
51997a1619fSSatish Balay       {0.000000000000000,   -1.761115796027561,  -0.521284157173780,  0.258249384305463   },
52097a1619fSSatish Balay       {0.000000000000000,   -1.657693358744728,  -1.052227765232394,  0.521284157173780   }
52197a1619fSSatish Balay     };
5229566063dSJacob Faibussowitsch     PetscCall(TSGLLESchemeCreate(3, 3, 4, 4, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
5233d177a5cSEmil Constantinescu   }
5243d177a5cSEmil Constantinescu   {
5253d177a5cSEmil Constantinescu     /* p=q=4, r=s=5:
5263d177a5cSEmil Constantinescu           irks(3/11,0,[1:5]/5, [0.1715   -0.1238    0.6617],...
5273d177a5cSEmil Constantinescu           [ -0.0812    0.4079    1.0000
5283d177a5cSEmil Constantinescu              1.0000         0         0
5293d177a5cSEmil Constantinescu              0.8270    1.0000         0])
5303d177a5cSEmil Constantinescu     */
53197a1619fSSatish Balay     const PetscScalar c[5]    = {0.2, 0.4, 0.6, 0.8, 1.0};
53297a1619fSSatish Balay     const PetscScalar a[5][5] = {
53397a1619fSSatish Balay       {2.72727272727352e-01,  0.00000000000000e+00,  0.00000000000000e+00,  0.00000000000000e+00, 0.00000000000000e+00},
53497a1619fSSatish Balay       {-1.03980153733431e-01, 2.72727272727405e-01,  0.00000000000000e+00,  0.00000000000000e+00, 0.00000000000000e+00},
53597a1619fSSatish Balay       {-1.58615400341492e+00, 7.44168951881122e-01,  2.72727272727309e-01,  0.00000000000000e+00, 0.00000000000000e+00},
53697a1619fSSatish Balay       {-8.73658042865628e-01, 5.37884671894595e-01,  -1.63298538799523e-01, 2.72727272726996e-01, 0.00000000000000e+00},
53797a1619fSSatish Balay       {2.95489397443992e-01,  -1.18481693910097e+00, -6.68029812659953e-01, 1.00716687860943e+00, 2.72727272727288e-01}
53897a1619fSSatish Balay     };
53997a1619fSSatish Balay     const PetscScalar b[5][5] = {
54097a1619fSSatish Balay       {2.95489397443992e-01,  -1.18481693910097e+00, -6.68029812659953e-01, 1.00716687860943e+00,  2.72727272727288e-01},
54197a1619fSSatish Balay       {0.00000000000000e+00,  1.11022302462516e-16,  -2.22044604925031e-16, 0.00000000000000e+00,  1.00000000000000e+00},
54297a1619fSSatish Balay       {-4.05882503986005e+00, -4.00924006567769e+00, -1.38930610972481e+00, 4.45223930308488e+00,  6.32331093108427e-01},
54397a1619fSSatish Balay       {8.35690179937017e+00,  -2.26640927349732e+00, 6.86647884973826e+00,  -5.22595158025740e+00, 4.50893068837431e+00},
54497a1619fSSatish Balay       {1.27656267027479e+01,  2.80882153840821e+00,  8.91173096522890e+00,  -1.07936444078906e+01, 4.82534148988854e+00}
54597a1619fSSatish Balay     };
54697a1619fSSatish Balay     const PetscScalar u[5][5] = {
54797a1619fSSatish Balay       {1.00000000000000e+00, -7.27272727273551e-02, -3.45454545454419e-02, -4.12121212119565e-03, -2.96969696964014e-04},
54897a1619fSSatish Balay       {1.00000000000000e+00, 2.31252881006154e-01,  -8.29487834416481e-03, -9.07191207681020e-03, -1.70378403743473e-03},
54997a1619fSSatish Balay       {1.00000000000000e+00, 1.16925777880663e+00,  3.59268562942635e-02,  -4.09013451730615e-02, -1.02411119670164e-02},
55097a1619fSSatish Balay       {1.00000000000000e+00, 1.02634463704356e+00,  1.59375044913405e-01,  1.89673015035370e-03,  -4.89987231897569e-03},
55197a1619fSSatish Balay       {1.00000000000000e+00, 1.27746320298021e+00,  2.37186008132728e-01,  -8.28694373940065e-02, -5.34396510196430e-02}
55297a1619fSSatish Balay     };
55397a1619fSSatish Balay     const PetscScalar v[5][5] = {
55497a1619fSSatish Balay       {1.00000000000000e+00, 1.27746320298021e+00,  2.37186008132728e-01,  -8.28694373940065e-02, -5.34396510196430e-02},
55597a1619fSSatish Balay       {0.00000000000000e+00, -1.77635683940025e-15, -1.99840144432528e-15, -9.99200722162641e-16, -3.33066907387547e-16},
55697a1619fSSatish Balay       {0.00000000000000e+00, 4.37280081906924e+00,  5.49221645016377e-02,  -8.88913177394943e-02, 1.12879077989154e-01 },
55797a1619fSSatish Balay       {0.00000000000000e+00, -1.22399504837280e+01, -5.21287338448645e+00, -8.03952325565291e-01, 4.60298678047147e-01 },
55897a1619fSSatish Balay       {0.00000000000000e+00, -1.85178762883829e+01, -5.21411849862624e+00, -1.04283436528809e+00, 7.49030161063651e-01 }
55997a1619fSSatish Balay     };
5609566063dSJacob Faibussowitsch     PetscCall(TSGLLESchemeCreate(4, 4, 5, 5, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
5613d177a5cSEmil Constantinescu   }
5623d177a5cSEmil Constantinescu   {
5633d177a5cSEmil Constantinescu     /* p=q=5, r=s=6;
5643d177a5cSEmil Constantinescu        irks(1/3,0,[1:6]/6,...
5653d177a5cSEmil Constantinescu           [-0.0489    0.4228   -0.8814    0.9021],...
5663d177a5cSEmil Constantinescu           [-0.3474   -0.6617    0.6294    0.2129
5673d177a5cSEmil Constantinescu             0.0044   -0.4256   -0.1427   -0.8936
5683d177a5cSEmil Constantinescu            -0.8267    0.4821    0.1371   -0.2557
5693d177a5cSEmil Constantinescu            -0.4426   -0.3855   -0.7514    0.3014])
5703d177a5cSEmil Constantinescu     */
57197a1619fSSatish Balay     const PetscScalar c[6]    = {1. / 6, 2. / 6, 3. / 6, 4. / 6, 5. / 6, 1.};
57297a1619fSSatish Balay     const PetscScalar a[6][6] = {
57397a1619fSSatish Balay       {3.33333333333940e-01,  0,                     0,                     0,                     0,                    0                   },
57497a1619fSSatish Balay       {-8.64423857333350e-02, 3.33333333332888e-01,  0,                     0,                     0,                    0                   },
57597a1619fSSatish Balay       {-2.16850174258252e+00, -2.23619072028839e+00, 3.33333333335204e-01,  0,                     0,                    0                   },
57697a1619fSSatish Balay       {-4.73160970138997e+00, -3.89265344629268e+00, -2.76318716520933e-01, 3.33333333335759e-01,  0,                    0                   },
57797a1619fSSatish Balay       {-6.75187540297338e+00, -7.90756533769377e+00, 7.90245051802259e-01,  -4.48352364517632e-01, 3.33333333328483e-01, 0                   },
57897a1619fSSatish Balay       {-4.26488287921548e+00, -1.19320395589302e+01, 3.38924509887755e+00,  -2.23969848002481e+00, 6.62807710124007e-01, 3.33333333335440e-01}
57997a1619fSSatish Balay     };
58097a1619fSSatish Balay     const PetscScalar b[6][6] = {
58197a1619fSSatish Balay       {-4.26488287921548e+00, -1.19320395589302e+01, 3.38924509887755e+00,  -2.23969848002481e+00, 6.62807710124007e-01,  3.33333333335440e-01 },
58297a1619fSSatish Balay       {-8.88178419700125e-16, 4.44089209850063e-16,  -1.54737334057131e-15, -8.88178419700125e-16, 0.00000000000000e+00,  1.00000000000001e+00 },
58397a1619fSSatish Balay       {-2.87780425770651e+01, -1.13520448264971e+01, 2.62002318943161e+01,  2.56943874812797e+01,  -3.06702268304488e+01, 6.68067773510103e+00 },
58497a1619fSSatish Balay       {5.47971245256474e+01,  6.80366875868284e+01,  -6.50952588861999e+01, -8.28643975339097e+01, 8.17416943896414e+01,  -1.17819043489036e+01},
58597a1619fSSatish Balay       {-2.33332114788869e+02, 6.12942539462634e+01,  -4.91850135865944e+01, 1.82716844135480e+02,  -1.29788173979395e+02, 3.09968095651099e+01 },
58697a1619fSSatish Balay       {-1.72049132343751e+02, 8.60194713593999e+00,  7.98154219170200e-01,  1.50371386053218e+02,  -1.18515423962066e+02, 2.50898277784663e+01 }
58797a1619fSSatish Balay     };
58897a1619fSSatish Balay     const PetscScalar u[6][6] = {
58997a1619fSSatish Balay       {1.00000000000000e+00, -1.66666666666870e-01, -4.16666666664335e-02, -3.85802469124815e-03, -2.25051440302250e-04, -9.64506172339142e-06},
59097a1619fSSatish Balay       {1.00000000000000e+00, 8.64423857327162e-02,  -4.11484912671353e-02, -1.11450903217645e-02, -1.47651050487126e-03, -1.34395070766826e-04},
59197a1619fSSatish Balay       {1.00000000000000e+00, 4.57135912953434e+00,  1.06514719719137e+00,  1.33517564218007e-01,  1.11365952968659e-02,  6.12382756769504e-04 },
59297a1619fSSatish Balay       {1.00000000000000e+00, 9.23391519753404e+00,  2.22431212392095e+00,  2.91823807741891e-01,  2.52058456411084e-02,  1.22800542949647e-03 },
59397a1619fSSatish Balay       {1.00000000000000e+00, 1.48175480533865e+01,  3.73439117461835e+00,  5.14648336541804e-01,  4.76430038853402e-02,  2.56798515502156e-03 },
59497a1619fSSatish Balay       {1.00000000000000e+00, 1.50512347758335e+01,  4.10099701165164e+00,  5.66039141003603e-01,  3.91213893800891e-02,  -2.99136269067853e-03}
59597a1619fSSatish Balay     };
59697a1619fSSatish Balay     const PetscScalar v[6][6] = {
59797a1619fSSatish Balay       {1.00000000000000e+00, 1.50512347758335e+01,  4.10099701165164e+00,  5.66039141003603e-01,  3.91213893800891e-02,  -2.99136269067853e-03},
59897a1619fSSatish Balay       {0.00000000000000e+00, -4.88498130835069e-15, -6.43929354282591e-15, -3.55271367880050e-15, -1.22124532708767e-15, -3.12250225675825e-16},
59997a1619fSSatish Balay       {0.00000000000000e+00, 1.22250171233141e+01,  -1.77150760606169e+00, 3.54516769879390e-01,  6.22298845883398e-01,  2.31647447450276e-01 },
60097a1619fSSatish Balay       {0.00000000000000e+00, -4.48339457331040e+01, -3.57363126641880e-01, 5.18750173123425e-01,  6.55727990241799e-02,  1.63175368287079e-01 },
60197a1619fSSatish Balay       {0.00000000000000e+00, 1.37297394708005e+02,  -1.60145272991317e+00, -5.05319555199441e+00, 1.55328940390990e-01,  9.16629423682464e-01 },
60297a1619fSSatish Balay       {0.00000000000000e+00, 1.05703241119022e+02,  -1.16610260983038e+00, -2.99767252773859e+00, -1.13472315553890e-01, 1.09742849254729e+00 }
60397a1619fSSatish Balay     };
6049566063dSJacob Faibussowitsch     PetscCall(TSGLLESchemeCreate(5, 5, 6, 6, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
6053d177a5cSEmil Constantinescu   }
6063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6073d177a5cSEmil Constantinescu }
6083d177a5cSEmil Constantinescu 
6093d177a5cSEmil Constantinescu /*@C
610bcf0153eSBarry Smith    TSGLLESetType - sets the class of general linear method, `TSGLLE` to use for time-stepping
6113d177a5cSEmil Constantinescu 
612c3339decSBarry Smith    Collective
6133d177a5cSEmil Constantinescu 
6143d177a5cSEmil Constantinescu    Input Parameters:
615bcf0153eSBarry Smith +  ts - the `TS` context
6163d177a5cSEmil Constantinescu -  type - a method
6173d177a5cSEmil Constantinescu 
6183d177a5cSEmil Constantinescu    Options Database Key:
6193d177a5cSEmil Constantinescu .  -ts_gl_type <type> - sets the method, use -help for a list of available method (e.g. irks)
6203d177a5cSEmil Constantinescu 
621bcf0153eSBarry Smith    Level: intermediate
622bcf0153eSBarry Smith 
6233d177a5cSEmil Constantinescu    Notes:
6243d177a5cSEmil Constantinescu    See "petsc/include/petscts.h" for available methods (for instance)
6253d177a5cSEmil Constantinescu .    TSGLLE_IRKS - Diagonally implicit methods with inherent Runge-Kutta stability (for stiff problems)
6263d177a5cSEmil Constantinescu 
627bcf0153eSBarry Smith    Normally, it is best to use the `TSSetFromOptions()` command and
628bcf0153eSBarry Smith    then set the `TSGLLE` type from the options database rather than by using
6293d177a5cSEmil Constantinescu    this routine.  Using the options database provides the user with
6303d177a5cSEmil Constantinescu    maximum flexibility in evaluating the many different solvers.
631bcf0153eSBarry Smith    The `TSGLLESetType()` routine is provided for those situations where it
6323d177a5cSEmil Constantinescu    is necessary to set the timestepping solver independently of the
6333d177a5cSEmil Constantinescu    command line or options database.  This might be the case, for example,
6343d177a5cSEmil Constantinescu    when the choice of solver changes during the execution of the
6353d177a5cSEmil Constantinescu    program, and the user's application is taking responsibility for
6363d177a5cSEmil Constantinescu    choosing the appropriate method.
6373d177a5cSEmil Constantinescu 
638*1cc06b55SBarry Smith .seealso: [](ch_ts), `TS`, `TSGLLEType`, `TSGLLE`
6393d177a5cSEmil Constantinescu @*/
640d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLESetType(TS ts, TSGLLEType type)
641d71ae5a4SJacob Faibussowitsch {
6423d177a5cSEmil Constantinescu   PetscFunctionBegin;
6433d177a5cSEmil Constantinescu   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
6443d177a5cSEmil Constantinescu   PetscValidCharPointer(type, 2);
645cac4c232SBarry Smith   PetscTryMethod(ts, "TSGLLESetType_C", (TS, TSGLLEType), (ts, type));
6463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6473d177a5cSEmil Constantinescu }
6483d177a5cSEmil Constantinescu 
6493d177a5cSEmil Constantinescu /*@C
650bcf0153eSBarry Smith    TSGLLESetAcceptType - sets the acceptance test for `TSGLLE`
6513d177a5cSEmil Constantinescu 
6523d177a5cSEmil Constantinescu    Time integrators that need to control error must have the option to reject a time step based on local error
6533d177a5cSEmil Constantinescu    estimates.  This function allows different schemes to be set.
6543d177a5cSEmil Constantinescu 
655c3339decSBarry Smith    Logically Collective
6563d177a5cSEmil Constantinescu 
6573d177a5cSEmil Constantinescu    Input Parameters:
658bcf0153eSBarry Smith +  ts - the `TS` context
6593d177a5cSEmil Constantinescu -  type - the type
6603d177a5cSEmil Constantinescu 
6613d177a5cSEmil Constantinescu    Options Database Key:
6623d177a5cSEmil Constantinescu .  -ts_gl_accept_type <type> - sets the method used to determine whether to accept or reject a step
6633d177a5cSEmil Constantinescu 
6643d177a5cSEmil Constantinescu    Level: intermediate
6653d177a5cSEmil Constantinescu 
666*1cc06b55SBarry Smith .seealso: [](ch_ts), `TS`, `TSGLLE`, `TSGLLEAcceptRegister()`, `TSGLLEAdapt`
6673d177a5cSEmil Constantinescu @*/
668d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLESetAcceptType(TS ts, TSGLLEAcceptType type)
669d71ae5a4SJacob Faibussowitsch {
6703d177a5cSEmil Constantinescu   PetscFunctionBegin;
6713d177a5cSEmil Constantinescu   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
6723d177a5cSEmil Constantinescu   PetscValidCharPointer(type, 2);
673cac4c232SBarry Smith   PetscTryMethod(ts, "TSGLLESetAcceptType_C", (TS, TSGLLEAcceptType), (ts, type));
6743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6753d177a5cSEmil Constantinescu }
6763d177a5cSEmil Constantinescu 
6773d177a5cSEmil Constantinescu /*@C
678bcf0153eSBarry Smith    TSGLLEGetAdapt - gets the `TSGLLEAdapt` object from the `TS`
6793d177a5cSEmil Constantinescu 
6803d177a5cSEmil Constantinescu    Not Collective
6813d177a5cSEmil Constantinescu 
6823d177a5cSEmil Constantinescu    Input Parameter:
683bcf0153eSBarry Smith .  ts - the `TS` context
6843d177a5cSEmil Constantinescu 
6853d177a5cSEmil Constantinescu    Output Parameter:
686bcf0153eSBarry Smith .  adapt - the `TSGLLEAdapt` context
6873d177a5cSEmil Constantinescu 
6883d177a5cSEmil Constantinescu    Level: advanced
6893d177a5cSEmil Constantinescu 
690bcf0153eSBarry Smith    Note:
691bcf0153eSBarry Smith    This allows the user set options on the `TSGLLEAdapt` object.  Usually it is better to do this using the options
692bcf0153eSBarry Smith    database, so this function is rarely needed.
693bcf0153eSBarry Smith 
694*1cc06b55SBarry Smith .seealso: [](ch_ts), `TS`, `TSGLLE`, `TSGLLEAdapt`, `TSGLLEAdaptRegister()`
6953d177a5cSEmil Constantinescu @*/
696d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLEGetAdapt(TS ts, TSGLLEAdapt *adapt)
697d71ae5a4SJacob Faibussowitsch {
6983d177a5cSEmil Constantinescu   PetscFunctionBegin;
6993d177a5cSEmil Constantinescu   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
7003d177a5cSEmil Constantinescu   PetscValidPointer(adapt, 2);
701cac4c232SBarry Smith   PetscUseMethod(ts, "TSGLLEGetAdapt_C", (TS, TSGLLEAdapt *), (ts, adapt));
7023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7033d177a5cSEmil Constantinescu }
7043d177a5cSEmil Constantinescu 
705d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEAccept_Always(TS ts, PetscReal tleft, PetscReal h, const PetscReal enorms[], PetscBool *accept)
706d71ae5a4SJacob Faibussowitsch {
7073d177a5cSEmil Constantinescu   PetscFunctionBegin;
7083d177a5cSEmil Constantinescu   *accept = PETSC_TRUE;
7093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7103d177a5cSEmil Constantinescu }
7113d177a5cSEmil Constantinescu 
712d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEUpdateWRMS(TS ts)
713d71ae5a4SJacob Faibussowitsch {
7143d177a5cSEmil Constantinescu   TS_GLLE     *gl = (TS_GLLE *)ts->data;
7153d177a5cSEmil Constantinescu   PetscScalar *x, *w;
7163d177a5cSEmil Constantinescu   PetscInt     n, i;
7173d177a5cSEmil Constantinescu 
7183d177a5cSEmil Constantinescu   PetscFunctionBegin;
7199566063dSJacob Faibussowitsch   PetscCall(VecGetArray(gl->X[0], &x));
7209566063dSJacob Faibussowitsch   PetscCall(VecGetArray(gl->W, &w));
7219566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(gl->W, &n));
7223d177a5cSEmil Constantinescu   for (i = 0; i < n; i++) w[i] = 1. / (gl->wrms_atol + gl->wrms_rtol * PetscAbsScalar(x[i]));
7239566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(gl->X[0], &x));
7249566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(gl->W, &w));
7253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7263d177a5cSEmil Constantinescu }
7273d177a5cSEmil Constantinescu 
728d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEVecNormWRMS(TS ts, Vec X, PetscReal *nrm)
729d71ae5a4SJacob Faibussowitsch {
7303d177a5cSEmil Constantinescu   TS_GLLE     *gl = (TS_GLLE *)ts->data;
7313d177a5cSEmil Constantinescu   PetscScalar *x, *w;
7323d177a5cSEmil Constantinescu   PetscReal    sum = 0.0, gsum;
7333d177a5cSEmil Constantinescu   PetscInt     n, N, i;
7343d177a5cSEmil Constantinescu 
7353d177a5cSEmil Constantinescu   PetscFunctionBegin;
7369566063dSJacob Faibussowitsch   PetscCall(VecGetArray(X, &x));
7379566063dSJacob Faibussowitsch   PetscCall(VecGetArray(gl->W, &w));
7389566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(gl->W, &n));
7393d177a5cSEmil Constantinescu   for (i = 0; i < n; i++) sum += PetscAbsScalar(PetscSqr(x[i] * w[i]));
7409566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(X, &x));
7419566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(gl->W, &w));
7421c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&sum, &gsum, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)ts)));
7439566063dSJacob Faibussowitsch   PetscCall(VecGetSize(gl->W, &N));
7443d177a5cSEmil Constantinescu   *nrm = PetscSqrtReal(gsum / (1. * N));
7453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7463d177a5cSEmil Constantinescu }
7473d177a5cSEmil Constantinescu 
748d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLESetType_GLLE(TS ts, TSGLLEType type)
749d71ae5a4SJacob Faibussowitsch {
7503d177a5cSEmil Constantinescu   PetscBool same;
7513d177a5cSEmil Constantinescu   TS_GLLE  *gl = (TS_GLLE *)ts->data;
7525f80ce2aSJacob Faibussowitsch   PetscErrorCode (*r)(TS);
7533d177a5cSEmil Constantinescu 
7543d177a5cSEmil Constantinescu   PetscFunctionBegin;
7553d177a5cSEmil Constantinescu   if (gl->type_name[0]) {
7569566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(gl->type_name, type, &same));
7573ba16761SJacob Faibussowitsch     if (same) PetscFunctionReturn(PETSC_SUCCESS);
7589566063dSJacob Faibussowitsch     PetscCall((*gl->Destroy)(gl));
7593d177a5cSEmil Constantinescu   }
7603d177a5cSEmil Constantinescu 
7619566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(TSGLLEList, type, &r));
7623c633725SBarry Smith   PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown TSGLLE type \"%s\" given", type);
7639566063dSJacob Faibussowitsch   PetscCall((*r)(ts));
764c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(gl->type_name, type, sizeof(gl->type_name)));
7653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7663d177a5cSEmil Constantinescu }
7673d177a5cSEmil Constantinescu 
768d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLESetAcceptType_GLLE(TS ts, TSGLLEAcceptType type)
769d71ae5a4SJacob Faibussowitsch {
7703d177a5cSEmil Constantinescu   TSGLLEAcceptFunction r;
7713d177a5cSEmil Constantinescu   TS_GLLE             *gl = (TS_GLLE *)ts->data;
7723d177a5cSEmil Constantinescu 
7733d177a5cSEmil Constantinescu   PetscFunctionBegin;
7749566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(TSGLLEAcceptList, type, &r));
7753c633725SBarry Smith   PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown TSGLLEAccept type \"%s\" given", type);
7763d177a5cSEmil Constantinescu   gl->Accept = r;
7779566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(gl->accept_name, type, sizeof(gl->accept_name)));
7783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7793d177a5cSEmil Constantinescu }
7803d177a5cSEmil Constantinescu 
781d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEGetAdapt_GLLE(TS ts, TSGLLEAdapt *adapt)
782d71ae5a4SJacob Faibussowitsch {
7833d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
7843d177a5cSEmil Constantinescu 
7853d177a5cSEmil Constantinescu   PetscFunctionBegin;
7863d177a5cSEmil Constantinescu   if (!gl->adapt) {
7879566063dSJacob Faibussowitsch     PetscCall(TSGLLEAdaptCreate(PetscObjectComm((PetscObject)ts), &gl->adapt));
7889566063dSJacob Faibussowitsch     PetscCall(PetscObjectIncrementTabLevel((PetscObject)gl->adapt, (PetscObject)ts, 1));
7893d177a5cSEmil Constantinescu   }
7903d177a5cSEmil Constantinescu   *adapt = gl->adapt;
7913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7923d177a5cSEmil Constantinescu }
7933d177a5cSEmil Constantinescu 
794d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEChooseNextScheme(TS ts, PetscReal h, const PetscReal hmnorm[], PetscInt *next_scheme, PetscReal *next_h, PetscBool *finish)
795d71ae5a4SJacob Faibussowitsch {
7963d177a5cSEmil Constantinescu   TS_GLLE  *gl = (TS_GLLE *)ts->data;
7973d177a5cSEmil Constantinescu   PetscInt  i, n, cur_p, cur, next_sc, candidates[64], orders[64];
7983d177a5cSEmil Constantinescu   PetscReal errors[64], costs[64], tleft;
7993d177a5cSEmil Constantinescu 
8003d177a5cSEmil Constantinescu   PetscFunctionBegin;
8013d177a5cSEmil Constantinescu   cur   = -1;
8023d177a5cSEmil Constantinescu   cur_p = gl->schemes[gl->current_scheme]->p;
8033d177a5cSEmil Constantinescu   tleft = ts->max_time - (ts->ptime + ts->time_step);
8043d177a5cSEmil Constantinescu   for (i = 0, n = 0; i < gl->nschemes; i++) {
8053d177a5cSEmil Constantinescu     TSGLLEScheme sc = gl->schemes[i];
8063d177a5cSEmil Constantinescu     if (sc->p < gl->min_order || gl->max_order < sc->p) continue;
8073d177a5cSEmil Constantinescu     if (sc->p == cur_p - 1) errors[n] = PetscAbsScalar(sc->alpha[0]) * hmnorm[0];
8083d177a5cSEmil Constantinescu     else if (sc->p == cur_p) errors[n] = PetscAbsScalar(sc->alpha[0]) * hmnorm[1];
8093d177a5cSEmil Constantinescu     else if (sc->p == cur_p + 1) errors[n] = PetscAbsScalar(sc->alpha[0]) * (hmnorm[2] + hmnorm[3]);
8103d177a5cSEmil Constantinescu     else continue;
8113d177a5cSEmil Constantinescu     candidates[n] = i;
8123d177a5cSEmil Constantinescu     orders[n]     = PetscMin(sc->p, sc->q); /* order of global truncation error */
8133d177a5cSEmil Constantinescu     costs[n]      = sc->s;                  /* estimate the cost as the number of stages */
8143d177a5cSEmil Constantinescu     if (i == gl->current_scheme) cur = n;
8153d177a5cSEmil Constantinescu     n++;
8163d177a5cSEmil Constantinescu   }
817cad9d221SBarry Smith   PetscCheck(cur >= 0 && gl->nschemes > cur, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Current scheme not found in scheme list");
8189566063dSJacob Faibussowitsch   PetscCall(TSGLLEAdaptChoose(gl->adapt, n, orders, errors, costs, cur, h, tleft, &next_sc, next_h, finish));
8193d177a5cSEmil Constantinescu   *next_scheme = candidates[next_sc];
8209371c9d4SSatish 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,
8219371c9d4SSatish Balay                       gl->schemes[*next_scheme]->r, gl->schemes[*next_scheme]->s, (double)*next_h, PetscBools[*finish]));
8223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8233d177a5cSEmil Constantinescu }
8243d177a5cSEmil Constantinescu 
825d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEGetMaxSizes(TS ts, PetscInt *max_r, PetscInt *max_s)
826d71ae5a4SJacob Faibussowitsch {
8273d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
8283d177a5cSEmil Constantinescu 
8293d177a5cSEmil Constantinescu   PetscFunctionBegin;
8303d177a5cSEmil Constantinescu   *max_r = gl->schemes[gl->nschemes - 1]->r;
8313d177a5cSEmil Constantinescu   *max_s = gl->schemes[gl->nschemes - 1]->s;
8323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8333d177a5cSEmil Constantinescu }
8343d177a5cSEmil Constantinescu 
835d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSolve_GLLE(TS ts)
836d71ae5a4SJacob Faibussowitsch {
8373d177a5cSEmil Constantinescu   TS_GLLE            *gl = (TS_GLLE *)ts->data;
8383d177a5cSEmil Constantinescu   PetscInt            i, k, its, lits, max_r, max_s;
8393d177a5cSEmil Constantinescu   PetscBool           final_step, finish;
8403d177a5cSEmil Constantinescu   SNESConvergedReason snesreason;
8413d177a5cSEmil Constantinescu 
8423d177a5cSEmil Constantinescu   PetscFunctionBegin;
8439566063dSJacob Faibussowitsch   PetscCall(TSMonitor(ts, ts->steps, ts->ptime, ts->vec_sol));
8443d177a5cSEmil Constantinescu 
8459566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetMaxSizes(ts, &max_r, &max_s));
8469566063dSJacob Faibussowitsch   PetscCall(VecCopy(ts->vec_sol, gl->X[0]));
84748a46eb9SPierre Jolivet   for (i = 1; i < max_r; i++) PetscCall(VecZeroEntries(gl->X[i]));
8489566063dSJacob Faibussowitsch   PetscCall(TSGLLEUpdateWRMS(ts));
8493d177a5cSEmil Constantinescu 
8503d177a5cSEmil Constantinescu   if (0) {
8513d177a5cSEmil Constantinescu     /* Find consistent initial data for DAE */
8523d177a5cSEmil Constantinescu     gl->stage_time = ts->ptime + ts->time_step;
8533d177a5cSEmil Constantinescu     gl->scoeff     = 1.;
8543d177a5cSEmil Constantinescu     gl->stage      = 0;
8553d177a5cSEmil Constantinescu 
8569566063dSJacob Faibussowitsch     PetscCall(VecCopy(ts->vec_sol, gl->Z));
8579566063dSJacob Faibussowitsch     PetscCall(VecCopy(ts->vec_sol, gl->Y));
8589566063dSJacob Faibussowitsch     PetscCall(SNESSolve(ts->snes, NULL, gl->Y));
8599566063dSJacob Faibussowitsch     PetscCall(SNESGetIterationNumber(ts->snes, &its));
8609566063dSJacob Faibussowitsch     PetscCall(SNESGetLinearSolveIterations(ts->snes, &lits));
8619566063dSJacob Faibussowitsch     PetscCall(SNESGetConvergedReason(ts->snes, &snesreason));
8623d177a5cSEmil Constantinescu 
8639371c9d4SSatish Balay     ts->snes_its += its;
8649371c9d4SSatish Balay     ts->ksp_its += lits;
8653d177a5cSEmil Constantinescu     if (snesreason < 0 && ts->max_snes_failures > 0 && ++ts->num_snes_failures >= ts->max_snes_failures) {
8663d177a5cSEmil Constantinescu       ts->reason = TS_DIVERGED_NONLINEAR_SOLVE;
86763a3b9bcSJacob 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));
8683ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
8693d177a5cSEmil Constantinescu     }
8703d177a5cSEmil Constantinescu   }
8713d177a5cSEmil Constantinescu 
87208401ef6SPierre Jolivet   PetscCheck(gl->current_scheme >= 0, PETSC_COMM_SELF, PETSC_ERR_ORDER, "A starting scheme has not been provided");
8733d177a5cSEmil Constantinescu 
8743d177a5cSEmil Constantinescu   for (k = 0, final_step = PETSC_FALSE, finish = PETSC_FALSE; k < ts->max_steps && !finish; k++) {
8753d177a5cSEmil Constantinescu     PetscInt           j, r, s, next_scheme = 0, rejections;
8763d177a5cSEmil Constantinescu     PetscReal          h, hmnorm[4], enorm[3], next_h;
8773d177a5cSEmil Constantinescu     PetscBool          accept;
8783d177a5cSEmil Constantinescu     const PetscScalar *c, *a, *u;
8793d177a5cSEmil Constantinescu     Vec               *X, *Ydot, Y;
8803d177a5cSEmil Constantinescu     TSGLLEScheme       scheme = gl->schemes[gl->current_scheme];
8813d177a5cSEmil Constantinescu 
8829371c9d4SSatish Balay     r    = scheme->r;
8839371c9d4SSatish Balay     s    = scheme->s;
8843d177a5cSEmil Constantinescu     c    = scheme->c;
8859371c9d4SSatish Balay     a    = scheme->a;
8869371c9d4SSatish Balay     u    = scheme->u;
8873d177a5cSEmil Constantinescu     h    = ts->time_step;
8889371c9d4SSatish Balay     X    = gl->X;
8899371c9d4SSatish Balay     Ydot = gl->Ydot;
8909371c9d4SSatish Balay     Y    = gl->Y;
8913d177a5cSEmil Constantinescu 
8923d177a5cSEmil Constantinescu     if (ts->ptime > ts->max_time) break;
8933d177a5cSEmil Constantinescu 
8943d177a5cSEmil Constantinescu     /*
8953d177a5cSEmil Constantinescu       We only call PreStep at the start of each STEP, not each STAGE.  This is because it is
8963d177a5cSEmil Constantinescu       possible to fail (have to restart a step) after multiple stages.
8973d177a5cSEmil Constantinescu     */
8989566063dSJacob Faibussowitsch     PetscCall(TSPreStep(ts));
8993d177a5cSEmil Constantinescu 
9003d177a5cSEmil Constantinescu     rejections = 0;
9013d177a5cSEmil Constantinescu     while (1) {
9023d177a5cSEmil Constantinescu       for (i = 0; i < s; i++) {
9033d177a5cSEmil Constantinescu         PetscScalar shift;
9043d177a5cSEmil Constantinescu         gl->scoeff     = 1. / PetscRealPart(a[i * s + i]);
9053d177a5cSEmil Constantinescu         shift          = gl->scoeff / ts->time_step;
9063d177a5cSEmil Constantinescu         gl->stage      = i;
9073d177a5cSEmil Constantinescu         gl->stage_time = ts->ptime + PetscRealPart(c[i]) * h;
9083d177a5cSEmil Constantinescu 
9093d177a5cSEmil Constantinescu         /*
9103d177a5cSEmil Constantinescu         * Stage equation: Y = h A Y' + U X
9113d177a5cSEmil Constantinescu         * We assume that A is lower-triangular so that we can solve the stages (Y,Y') sequentially
9123d177a5cSEmil Constantinescu         * Build the affine vector z_i = -[1/(h a_ii)](h sum_j a_ij y'_j + sum_j u_ij x_j)
9133d177a5cSEmil Constantinescu         * Then y'_i = z + 1/(h a_ii) y_i
9143d177a5cSEmil Constantinescu         */
9159566063dSJacob Faibussowitsch         PetscCall(VecZeroEntries(gl->Z));
91648a46eb9SPierre Jolivet         for (j = 0; j < r; j++) PetscCall(VecAXPY(gl->Z, -shift * u[i * r + j], X[j]));
91748a46eb9SPierre Jolivet         for (j = 0; j < i; j++) PetscCall(VecAXPY(gl->Z, -shift * h * a[i * s + j], Ydot[j]));
9183d177a5cSEmil Constantinescu         /* Note: Z is used within function evaluation, Ydot = Z + shift*Y */
9193d177a5cSEmil Constantinescu 
9203d177a5cSEmil Constantinescu         /* Compute an estimate of Y to start Newton iteration */
9213d177a5cSEmil Constantinescu         if (gl->extrapolate) {
9223d177a5cSEmil Constantinescu           if (i == 0) {
9233d177a5cSEmil Constantinescu             /* Linear extrapolation on the first stage */
9249566063dSJacob Faibussowitsch             PetscCall(VecWAXPY(Y, c[i] * h, X[1], X[0]));
9253d177a5cSEmil Constantinescu           } else {
9263d177a5cSEmil Constantinescu             /* Linear extrapolation from the last stage */
9279566063dSJacob Faibussowitsch             PetscCall(VecAXPY(Y, (c[i] - c[i - 1]) * h, Ydot[i - 1]));
9283d177a5cSEmil Constantinescu           }
9293d177a5cSEmil Constantinescu         } else if (i == 0) { /* Directly use solution from the last step, otherwise reuse the last stage (do nothing) */
9309566063dSJacob Faibussowitsch           PetscCall(VecCopy(X[0], Y));
9313d177a5cSEmil Constantinescu         }
9323d177a5cSEmil Constantinescu 
9333d177a5cSEmil Constantinescu         /* Solve this stage (Ydot[i] is computed during function evaluation) */
9349566063dSJacob Faibussowitsch         PetscCall(SNESSolve(ts->snes, NULL, Y));
9359566063dSJacob Faibussowitsch         PetscCall(SNESGetIterationNumber(ts->snes, &its));
9369566063dSJacob Faibussowitsch         PetscCall(SNESGetLinearSolveIterations(ts->snes, &lits));
9379566063dSJacob Faibussowitsch         PetscCall(SNESGetConvergedReason(ts->snes, &snesreason));
9389371c9d4SSatish Balay         ts->snes_its += its;
9399371c9d4SSatish Balay         ts->ksp_its += lits;
9403d177a5cSEmil Constantinescu         if (snesreason < 0 && ts->max_snes_failures > 0 && ++ts->num_snes_failures >= ts->max_snes_failures) {
9413d177a5cSEmil Constantinescu           ts->reason = TS_DIVERGED_NONLINEAR_SOLVE;
94263a3b9bcSJacob 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));
9433ba16761SJacob Faibussowitsch           PetscFunctionReturn(PETSC_SUCCESS);
9443d177a5cSEmil Constantinescu         }
9453d177a5cSEmil Constantinescu       }
9463d177a5cSEmil Constantinescu 
9473d177a5cSEmil Constantinescu       gl->stage_time = ts->ptime + ts->time_step;
9483d177a5cSEmil Constantinescu 
9499566063dSJacob Faibussowitsch       PetscCall((*gl->EstimateHigherMoments)(scheme, h, Ydot, gl->X, gl->himom));
9503d177a5cSEmil Constantinescu       /* hmnorm[i] = h^{p+i}x^{(p+i)} with i=0,1,2; hmnorm[3] = h^{p+2}(dx'/dx) x^{(p+1)} */
95148a46eb9SPierre Jolivet       for (i = 0; i < 3; i++) PetscCall(TSGLLEVecNormWRMS(ts, gl->himom[i], &hmnorm[i + 1]));
9523d177a5cSEmil Constantinescu       enorm[0] = PetscRealPart(scheme->alpha[0]) * hmnorm[1];
9533d177a5cSEmil Constantinescu       enorm[1] = PetscRealPart(scheme->beta[0]) * hmnorm[2];
9543d177a5cSEmil Constantinescu       enorm[2] = PetscRealPart(scheme->gamma[0]) * hmnorm[3];
9559566063dSJacob Faibussowitsch       PetscCall((*gl->Accept)(ts, ts->max_time - gl->stage_time, h, enorm, &accept));
9563d177a5cSEmil Constantinescu       if (accept) goto accepted;
9573d177a5cSEmil Constantinescu       rejections++;
95863a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(ts, "Step %" PetscInt_FMT " (t=%g) not accepted, rejections=%" PetscInt_FMT "\n", k, (double)gl->stage_time, rejections));
9593d177a5cSEmil Constantinescu       if (rejections > gl->max_step_rejections) break;
9603d177a5cSEmil Constantinescu       /*
9613d177a5cSEmil Constantinescu         There are lots of reasons why a step might be rejected, including solvers not converging and other factors that
9623d177a5cSEmil Constantinescu         TSGLLEChooseNextScheme does not support.  Additionally, the error estimates may be very screwed up, so I'm not
9633d177a5cSEmil Constantinescu         convinced that it's safe to just compute a new error estimate using the same interface as the current adaptor
9643d177a5cSEmil Constantinescu         (the adaptor interface probably has to change).  Here we make an arbitrary and naive choice.  This assumes that
9653d177a5cSEmil Constantinescu         steps were written in Nordsieck form.  The "correct" method would be to re-complete the previous time step with
9663d177a5cSEmil Constantinescu         the correct "next" step size.  It is unclear to me whether the present ad-hoc method of rescaling X is stable.
9673d177a5cSEmil Constantinescu       */
9683d177a5cSEmil Constantinescu       h *= 0.5;
96948a46eb9SPierre Jolivet       for (i = 1; i < scheme->r; i++) PetscCall(VecScale(X[i], PetscPowRealInt(0.5, i)));
9703d177a5cSEmil Constantinescu     }
97163a3b9bcSJacob 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);
9723d177a5cSEmil Constantinescu 
9733d177a5cSEmil Constantinescu   accepted:
9743d177a5cSEmil Constantinescu     /* This term is not error, but it *would* be the leading term for a lower order method */
9759566063dSJacob Faibussowitsch     PetscCall(TSGLLEVecNormWRMS(ts, gl->X[scheme->r - 1], &hmnorm[0]));
9763d177a5cSEmil Constantinescu     /* Correct scaling so that these are equivalent to norms of the Nordsieck vectors */
9773d177a5cSEmil Constantinescu 
97863a3b9bcSJacob 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]));
9793d177a5cSEmil Constantinescu     if (!final_step) {
9809566063dSJacob Faibussowitsch       PetscCall(TSGLLEChooseNextScheme(ts, h, hmnorm, &next_scheme, &next_h, &final_step));
9813d177a5cSEmil Constantinescu     } else {
9823d177a5cSEmil Constantinescu       /* Dummy values to complete the current step in a consistent manner */
9833d177a5cSEmil Constantinescu       next_scheme = gl->current_scheme;
9843d177a5cSEmil Constantinescu       next_h      = h;
9853d177a5cSEmil Constantinescu       finish      = PETSC_TRUE;
9863d177a5cSEmil Constantinescu     }
9873d177a5cSEmil Constantinescu 
9883d177a5cSEmil Constantinescu     X        = gl->Xold;
9893d177a5cSEmil Constantinescu     gl->Xold = gl->X;
9903d177a5cSEmil Constantinescu     gl->X    = X;
9919566063dSJacob Faibussowitsch     PetscCall((*gl->CompleteStep)(scheme, h, gl->schemes[next_scheme], next_h, Ydot, gl->Xold, gl->X));
9923d177a5cSEmil Constantinescu 
9939566063dSJacob Faibussowitsch     PetscCall(TSGLLEUpdateWRMS(ts));
9943d177a5cSEmil Constantinescu 
9953d177a5cSEmil Constantinescu     /* Post the solution for the user, we could avoid this copy with a small bit of cleverness */
9969566063dSJacob Faibussowitsch     PetscCall(VecCopy(gl->X[0], ts->vec_sol));
9973d177a5cSEmil Constantinescu     ts->ptime += h;
9983d177a5cSEmil Constantinescu     ts->steps++;
9993d177a5cSEmil Constantinescu 
10009566063dSJacob Faibussowitsch     PetscCall(TSPostEvaluate(ts));
10019566063dSJacob Faibussowitsch     PetscCall(TSPostStep(ts));
10029566063dSJacob Faibussowitsch     PetscCall(TSMonitor(ts, ts->steps, ts->ptime, ts->vec_sol));
10033d177a5cSEmil Constantinescu 
10043d177a5cSEmil Constantinescu     gl->current_scheme = next_scheme;
10053d177a5cSEmil Constantinescu     ts->time_step      = next_h;
10063d177a5cSEmil Constantinescu   }
10073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10083d177a5cSEmil Constantinescu }
10093d177a5cSEmil Constantinescu 
10103d177a5cSEmil Constantinescu /*------------------------------------------------------------*/
10113d177a5cSEmil Constantinescu 
1012d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSReset_GLLE(TS ts)
1013d71ae5a4SJacob Faibussowitsch {
10143d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
10153d177a5cSEmil Constantinescu   PetscInt max_r, max_s;
10163d177a5cSEmil Constantinescu 
10173d177a5cSEmil Constantinescu   PetscFunctionBegin;
10183d177a5cSEmil Constantinescu   if (gl->setupcalled) {
10199566063dSJacob Faibussowitsch     PetscCall(TSGLLEGetMaxSizes(ts, &max_r, &max_s));
10209566063dSJacob Faibussowitsch     PetscCall(VecDestroyVecs(max_r, &gl->Xold));
10219566063dSJacob Faibussowitsch     PetscCall(VecDestroyVecs(max_r, &gl->X));
10229566063dSJacob Faibussowitsch     PetscCall(VecDestroyVecs(max_s, &gl->Ydot));
10239566063dSJacob Faibussowitsch     PetscCall(VecDestroyVecs(3, &gl->himom));
10249566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gl->W));
10259566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gl->Y));
10269566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gl->Z));
10273d177a5cSEmil Constantinescu   }
10283d177a5cSEmil Constantinescu   gl->setupcalled = PETSC_FALSE;
10293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10303d177a5cSEmil Constantinescu }
10313d177a5cSEmil Constantinescu 
1032d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSDestroy_GLLE(TS ts)
1033d71ae5a4SJacob Faibussowitsch {
10343d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
10353d177a5cSEmil Constantinescu 
10363d177a5cSEmil Constantinescu   PetscFunctionBegin;
10379566063dSJacob Faibussowitsch   PetscCall(TSReset_GLLE(ts));
1038b3a6b972SJed Brown   if (ts->dm) {
10399566063dSJacob Faibussowitsch     PetscCall(DMCoarsenHookRemove(ts->dm, DMCoarsenHook_TSGLLE, DMRestrictHook_TSGLLE, ts));
10409566063dSJacob Faibussowitsch     PetscCall(DMSubDomainHookRemove(ts->dm, DMSubDomainHook_TSGLLE, DMSubDomainRestrictHook_TSGLLE, ts));
1041b3a6b972SJed Brown   }
10429566063dSJacob Faibussowitsch   if (gl->adapt) PetscCall(TSGLLEAdaptDestroy(&gl->adapt));
10439566063dSJacob Faibussowitsch   if (gl->Destroy) PetscCall((*gl->Destroy)(gl));
10449566063dSJacob Faibussowitsch   PetscCall(PetscFree(ts->data));
10459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLESetType_C", NULL));
10469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLESetAcceptType_C", NULL));
10479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLEGetAdapt_C", NULL));
10483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10493d177a5cSEmil Constantinescu }
10503d177a5cSEmil Constantinescu 
10513d177a5cSEmil Constantinescu /*
10523d177a5cSEmil Constantinescu     This defines the nonlinear equation that is to be solved with SNES
10533d177a5cSEmil Constantinescu     g(x) = f(t,x,z+shift*x) = 0
10543d177a5cSEmil Constantinescu */
1055d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTSFormFunction_GLLE(SNES snes, Vec x, Vec f, TS ts)
1056d71ae5a4SJacob Faibussowitsch {
10573d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
10583d177a5cSEmil Constantinescu   Vec      Z, Ydot;
10593d177a5cSEmil Constantinescu   DM       dm, dmsave;
10603d177a5cSEmil Constantinescu 
10613d177a5cSEmil Constantinescu   PetscFunctionBegin;
10629566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
10639566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, dm, &Z, &Ydot));
10649566063dSJacob Faibussowitsch   PetscCall(VecWAXPY(Ydot, gl->scoeff / ts->time_step, x, Z));
10653d177a5cSEmil Constantinescu   dmsave = ts->dm;
10663d177a5cSEmil Constantinescu   ts->dm = dm;
10679566063dSJacob Faibussowitsch   PetscCall(TSComputeIFunction(ts, gl->stage_time, x, Ydot, f, PETSC_FALSE));
10683d177a5cSEmil Constantinescu   ts->dm = dmsave;
10699566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, dm, &Z, &Ydot));
10703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10713d177a5cSEmil Constantinescu }
10723d177a5cSEmil Constantinescu 
1073d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTSFormJacobian_GLLE(SNES snes, Vec x, Mat A, Mat B, TS ts)
1074d71ae5a4SJacob Faibussowitsch {
10753d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
10763d177a5cSEmil Constantinescu   Vec      Z, Ydot;
10773d177a5cSEmil Constantinescu   DM       dm, dmsave;
10783d177a5cSEmil Constantinescu 
10793d177a5cSEmil Constantinescu   PetscFunctionBegin;
10809566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
10819566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, dm, &Z, &Ydot));
10823d177a5cSEmil Constantinescu   dmsave = ts->dm;
10833d177a5cSEmil Constantinescu   ts->dm = dm;
10843d177a5cSEmil Constantinescu   /* gl->Xdot will have already been computed in SNESTSFormFunction_GLLE */
10859566063dSJacob Faibussowitsch   PetscCall(TSComputeIJacobian(ts, gl->stage_time, x, gl->Ydot[gl->stage], gl->scoeff / ts->time_step, A, B, PETSC_FALSE));
10863d177a5cSEmil Constantinescu   ts->dm = dmsave;
10879566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, dm, &Z, &Ydot));
10883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10893d177a5cSEmil Constantinescu }
10903d177a5cSEmil Constantinescu 
1091d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_GLLE(TS ts)
1092d71ae5a4SJacob Faibussowitsch {
10933d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
10943d177a5cSEmil Constantinescu   PetscInt max_r, max_s;
10953d177a5cSEmil Constantinescu   DM       dm;
10963d177a5cSEmil Constantinescu 
10973d177a5cSEmil Constantinescu   PetscFunctionBegin;
10983d177a5cSEmil Constantinescu   gl->setupcalled = PETSC_TRUE;
10999566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetMaxSizes(ts, &max_r, &max_s));
11009566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vec_sol, max_r, &gl->X));
11019566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vec_sol, max_r, &gl->Xold));
11029566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vec_sol, max_s, &gl->Ydot));
11039566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vec_sol, 3, &gl->himom));
11049566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &gl->W));
11059566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &gl->Y));
11069566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &gl->Z));
11073d177a5cSEmil Constantinescu 
11083d177a5cSEmil Constantinescu   /* Default acceptance tests and adaptivity */
11099566063dSJacob Faibussowitsch   if (!gl->Accept) PetscCall(TSGLLESetAcceptType(ts, TSGLLEACCEPT_ALWAYS));
11109566063dSJacob Faibussowitsch   if (!gl->adapt) PetscCall(TSGLLEGetAdapt(ts, &gl->adapt));
11113d177a5cSEmil Constantinescu 
11123d177a5cSEmil Constantinescu   if (gl->current_scheme < 0) {
11133d177a5cSEmil Constantinescu     PetscInt i;
11143d177a5cSEmil Constantinescu     for (i = 0;; i++) {
11153d177a5cSEmil Constantinescu       if (gl->schemes[i]->p == gl->start_order) break;
111663a3b9bcSJacob Faibussowitsch       PetscCheck(i + 1 != gl->nschemes, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No schemes available with requested start order %" PetscInt_FMT, i);
11173d177a5cSEmil Constantinescu     }
11183d177a5cSEmil Constantinescu     gl->current_scheme = i;
11193d177a5cSEmil Constantinescu   }
11209566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &dm));
11219566063dSJacob Faibussowitsch   PetscCall(DMCoarsenHookAdd(dm, DMCoarsenHook_TSGLLE, DMRestrictHook_TSGLLE, ts));
11229566063dSJacob Faibussowitsch   PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_TSGLLE, DMSubDomainRestrictHook_TSGLLE, ts));
11233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11243d177a5cSEmil Constantinescu }
11253d177a5cSEmil Constantinescu /*------------------------------------------------------------*/
11263d177a5cSEmil Constantinescu 
1127d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetFromOptions_GLLE(TS ts, PetscOptionItems *PetscOptionsObject)
1128d71ae5a4SJacob Faibussowitsch {
11293d177a5cSEmil Constantinescu   TS_GLLE *gl         = (TS_GLLE *)ts->data;
11303d177a5cSEmil Constantinescu   char     tname[256] = TSGLLE_IRKS, completef[256] = "rescale-and-modify";
11313d177a5cSEmil Constantinescu 
11323d177a5cSEmil Constantinescu   PetscFunctionBegin;
1133d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "General Linear ODE solver options");
11343d177a5cSEmil Constantinescu   {
11353d177a5cSEmil Constantinescu     PetscBool flg;
11369566063dSJacob Faibussowitsch     PetscCall(PetscOptionsFList("-ts_gl_type", "Type of GL method", "TSGLLESetType", TSGLLEList, gl->type_name[0] ? gl->type_name : tname, tname, sizeof(tname), &flg));
113748a46eb9SPierre Jolivet     if (flg || !gl->type_name[0]) PetscCall(TSGLLESetType(ts, tname));
11389566063dSJacob 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));
11399566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-ts_gl_max_order", "Maximum order to try", "TSGLLESetMaxOrder", gl->max_order, &gl->max_order, NULL));
11409566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-ts_gl_min_order", "Minimum order to try", "TSGLLESetMinOrder", gl->min_order, &gl->min_order, NULL));
11419566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-ts_gl_start_order", "Initial order to try", "TSGLLESetMinOrder", gl->start_order, &gl->start_order, NULL));
11429566063dSJacob 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));
11439566063dSJacob Faibussowitsch     PetscCall(PetscOptionsBool("-ts_gl_extrapolate", "Extrapolate stage solution from previous solution (sometimes unstable)", "TSGLLESetExtrapolate", gl->extrapolate, &gl->extrapolate, NULL));
11449566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_gl_atol", "Absolute tolerance", "TSGLLESetTolerances", gl->wrms_atol, &gl->wrms_atol, NULL));
11459566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_gl_rtol", "Relative tolerance", "TSGLLESetTolerances", gl->wrms_rtol, &gl->wrms_rtol, NULL));
11469566063dSJacob Faibussowitsch     PetscCall(PetscOptionsString("-ts_gl_complete", "Method to use for completing the step", "none", completef, completef, sizeof(completef), &flg));
11473d177a5cSEmil Constantinescu     if (flg) {
11483d177a5cSEmil Constantinescu       PetscBool match1, match2;
11499566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(completef, "rescale", &match1));
11509566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(completef, "rescale-and-modify", &match2));
11513d177a5cSEmil Constantinescu       if (match1) gl->CompleteStep = TSGLLECompleteStep_Rescale;
11523d177a5cSEmil Constantinescu       else if (match2) gl->CompleteStep = TSGLLECompleteStep_RescaleAndModify;
115398921bdaSJacob Faibussowitsch       else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "%s", completef);
11543d177a5cSEmil Constantinescu     }
11553d177a5cSEmil Constantinescu     {
11563d177a5cSEmil Constantinescu       char type[256] = TSGLLEACCEPT_ALWAYS;
11579566063dSJacob 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));
115848a46eb9SPierre Jolivet       if (flg || !gl->accept_name[0]) PetscCall(TSGLLESetAcceptType(ts, type));
11593d177a5cSEmil Constantinescu     }
11603d177a5cSEmil Constantinescu     {
11613d177a5cSEmil Constantinescu       TSGLLEAdapt adapt;
11629566063dSJacob Faibussowitsch       PetscCall(TSGLLEGetAdapt(ts, &adapt));
1163dbbe0bcdSBarry Smith       PetscCall(TSGLLEAdaptSetFromOptions(adapt, PetscOptionsObject));
11643d177a5cSEmil Constantinescu     }
11653d177a5cSEmil Constantinescu   }
1166d0609cedSBarry Smith   PetscOptionsHeadEnd();
11673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11683d177a5cSEmil Constantinescu }
11693d177a5cSEmil Constantinescu 
1170d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSView_GLLE(TS ts, PetscViewer viewer)
1171d71ae5a4SJacob Faibussowitsch {
11723d177a5cSEmil Constantinescu   TS_GLLE  *gl = (TS_GLLE *)ts->data;
11733d177a5cSEmil Constantinescu   PetscInt  i;
11743d177a5cSEmil Constantinescu   PetscBool iascii, details;
11753d177a5cSEmil Constantinescu 
11763d177a5cSEmil Constantinescu   PetscFunctionBegin;
11779566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
11783d177a5cSEmil Constantinescu   if (iascii) {
117963a3b9bcSJacob 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));
11809566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Error estimation: %s\n", TSGLLEErrorDirections[gl->error_direction]));
11819566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Extrapolation: %s\n", gl->extrapolate ? "yes" : "no"));
11829566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Acceptance test: %s\n", gl->accept_name[0] ? gl->accept_name : "(not yet set)"));
11839566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
11849566063dSJacob Faibussowitsch     PetscCall(TSGLLEAdaptView(gl->adapt, viewer));
11859566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
11869566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  type: %s\n", gl->type_name[0] ? gl->type_name : "(not yet set)"));
118763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Schemes within family (%" PetscInt_FMT "):\n", gl->nschemes));
11883d177a5cSEmil Constantinescu     details = PETSC_FALSE;
11899566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)ts)->options, ((PetscObject)ts)->prefix, "-ts_gl_view_detailed", &details, NULL));
11909566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
119148a46eb9SPierre Jolivet     for (i = 0; i < gl->nschemes; i++) PetscCall(TSGLLESchemeView(gl->schemes[i], details, viewer));
11921baa6e33SBarry Smith     if (gl->View) PetscCall((*gl->View)(gl, viewer));
11939566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
11943d177a5cSEmil Constantinescu   }
11953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11963d177a5cSEmil Constantinescu }
11973d177a5cSEmil Constantinescu 
11983d177a5cSEmil Constantinescu /*@C
1199bcf0153eSBarry Smith    TSGLLERegister -  adds a `TSGLLE` implementation
12003d177a5cSEmil Constantinescu 
12013d177a5cSEmil Constantinescu    Not Collective
12023d177a5cSEmil Constantinescu 
12033d177a5cSEmil Constantinescu    Input Parameters:
120420f4b53cSBarry Smith +  sname - name of user-defined general linear scheme
120520f4b53cSBarry Smith -  function - routine to create method context
12063d177a5cSEmil Constantinescu 
1207bcf0153eSBarry Smith    Level: advanced
1208bcf0153eSBarry Smith 
1209bcf0153eSBarry Smith    Note:
1210bcf0153eSBarry Smith    `TSGLLERegister()` may be called multiple times to add several user-defined families.
12113d177a5cSEmil Constantinescu 
12123d177a5cSEmil Constantinescu    Sample usage:
12133d177a5cSEmil Constantinescu .vb
12143d177a5cSEmil Constantinescu    TSGLLERegister("my_scheme", MySchemeCreate);
12153d177a5cSEmil Constantinescu .ve
12163d177a5cSEmil Constantinescu 
12173d177a5cSEmil Constantinescu    Then, your scheme can be chosen with the procedural interface via
12183d177a5cSEmil Constantinescu $     TSGLLESetType(ts, "my_scheme")
12193d177a5cSEmil Constantinescu    or at runtime via the option
12203d177a5cSEmil Constantinescu $     -ts_gl_type my_scheme
12213d177a5cSEmil Constantinescu 
1222*1cc06b55SBarry Smith .seealso: [](ch_ts), `TSGLLE`, `TSGLLEType`, `TSGLLERegisterAll()`
12233d177a5cSEmil Constantinescu @*/
1224d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLERegister(const char sname[], PetscErrorCode (*function)(TS))
1225d71ae5a4SJacob Faibussowitsch {
12263d177a5cSEmil Constantinescu   PetscFunctionBegin;
12279566063dSJacob Faibussowitsch   PetscCall(TSGLLEInitializePackage());
12289566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&TSGLLEList, sname, function));
12293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12303d177a5cSEmil Constantinescu }
12313d177a5cSEmil Constantinescu 
12323d177a5cSEmil Constantinescu /*@C
1233bcf0153eSBarry Smith    TSGLLEAcceptRegister -  adds a `TSGLLE` acceptance scheme
12343d177a5cSEmil Constantinescu 
12353d177a5cSEmil Constantinescu    Not Collective
12363d177a5cSEmil Constantinescu 
12373d177a5cSEmil Constantinescu    Input Parameters:
123820f4b53cSBarry Smith +  sname - name of user-defined acceptance scheme
123920f4b53cSBarry Smith -  function - routine to create method context
12403d177a5cSEmil Constantinescu 
1241bcf0153eSBarry Smith    Level: advanced
1242bcf0153eSBarry Smith 
1243bcf0153eSBarry Smith    Note:
1244bcf0153eSBarry Smith    `TSGLLEAcceptRegister()` may be called multiple times to add several user-defined families.
12453d177a5cSEmil Constantinescu 
12463d177a5cSEmil Constantinescu    Sample usage:
12473d177a5cSEmil Constantinescu .vb
12483d177a5cSEmil Constantinescu    TSGLLEAcceptRegister("my_scheme", MySchemeCreate);
12493d177a5cSEmil Constantinescu .ve
12503d177a5cSEmil Constantinescu 
12513d177a5cSEmil Constantinescu    Then, your scheme can be chosen with the procedural interface via
12523d177a5cSEmil Constantinescu $     TSGLLESetAcceptType(ts, "my_scheme")
12533d177a5cSEmil Constantinescu    or at runtime via the option
12543d177a5cSEmil Constantinescu $     -ts_gl_accept_type my_scheme
12553d177a5cSEmil Constantinescu 
1256*1cc06b55SBarry Smith .seealso: [](ch_ts), `TSGLLE`, `TSGLLEType`, `TSGLLERegisterAll()`, `TSGLLEAcceptFunction`
12573d177a5cSEmil Constantinescu @*/
1258d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLEAcceptRegister(const char sname[], TSGLLEAcceptFunction function)
1259d71ae5a4SJacob Faibussowitsch {
12603d177a5cSEmil Constantinescu   PetscFunctionBegin;
12619566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&TSGLLEAcceptList, sname, function));
12623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12633d177a5cSEmil Constantinescu }
12643d177a5cSEmil Constantinescu 
12653d177a5cSEmil Constantinescu /*@C
1266bcf0153eSBarry Smith   TSGLLERegisterAll - Registers all of the general linear methods in `TSGLLE`
12673d177a5cSEmil Constantinescu 
12683d177a5cSEmil Constantinescu   Not Collective
12693d177a5cSEmil Constantinescu 
12703d177a5cSEmil Constantinescu   Level: advanced
12713d177a5cSEmil Constantinescu 
1272*1cc06b55SBarry Smith .seealso: [](ch_ts), `TSGLLE`, `TSGLLERegisterDestroy()`
12733d177a5cSEmil Constantinescu @*/
1274d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLERegisterAll(void)
1275d71ae5a4SJacob Faibussowitsch {
12763d177a5cSEmil Constantinescu   PetscFunctionBegin;
12773ba16761SJacob Faibussowitsch   if (TSGLLERegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
12783d177a5cSEmil Constantinescu   TSGLLERegisterAllCalled = PETSC_TRUE;
12793d177a5cSEmil Constantinescu 
12809566063dSJacob Faibussowitsch   PetscCall(TSGLLERegister(TSGLLE_IRKS, TSGLLECreate_IRKS));
12819566063dSJacob Faibussowitsch   PetscCall(TSGLLEAcceptRegister(TSGLLEACCEPT_ALWAYS, TSGLLEAccept_Always));
12823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12833d177a5cSEmil Constantinescu }
12843d177a5cSEmil Constantinescu 
12853d177a5cSEmil Constantinescu /*@C
1286bcf0153eSBarry Smith   TSGLLEInitializePackage - This function initializes everything in the `TSGLLE` package. It is called
1287bcf0153eSBarry Smith   from `TSInitializePackage()`.
12883d177a5cSEmil Constantinescu 
12893d177a5cSEmil Constantinescu   Level: developer
12903d177a5cSEmil Constantinescu 
1291*1cc06b55SBarry Smith .seealso: [](ch_ts), `PetscInitialize()`, `TSInitializePackage()`, `TSGLLEFinalizePackage()`
12923d177a5cSEmil Constantinescu @*/
1293d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLEInitializePackage(void)
1294d71ae5a4SJacob Faibussowitsch {
12953d177a5cSEmil Constantinescu   PetscFunctionBegin;
12963ba16761SJacob Faibussowitsch   if (TSGLLEPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS);
12973d177a5cSEmil Constantinescu   TSGLLEPackageInitialized = PETSC_TRUE;
12989566063dSJacob Faibussowitsch   PetscCall(TSGLLERegisterAll());
12999566063dSJacob Faibussowitsch   PetscCall(PetscRegisterFinalize(TSGLLEFinalizePackage));
13003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13013d177a5cSEmil Constantinescu }
13023d177a5cSEmil Constantinescu 
13033d177a5cSEmil Constantinescu /*@C
1304bcf0153eSBarry Smith   TSGLLEFinalizePackage - This function destroys everything in the `TSGLLE` package. It is
1305bcf0153eSBarry Smith   called from `PetscFinalize()`.
13063d177a5cSEmil Constantinescu 
13073d177a5cSEmil Constantinescu   Level: developer
13083d177a5cSEmil Constantinescu 
1309*1cc06b55SBarry Smith .seealso: [](ch_ts), `PetscFinalize()`, `TSGLLEInitializePackage()`, `TSInitializePackage()`
13103d177a5cSEmil Constantinescu @*/
1311d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLEFinalizePackage(void)
1312d71ae5a4SJacob Faibussowitsch {
13133d177a5cSEmil Constantinescu   PetscFunctionBegin;
13149566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&TSGLLEList));
13159566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&TSGLLEAcceptList));
13163d177a5cSEmil Constantinescu   TSGLLEPackageInitialized = PETSC_FALSE;
13173d177a5cSEmil Constantinescu   TSGLLERegisterAllCalled  = PETSC_FALSE;
13183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13193d177a5cSEmil Constantinescu }
13203d177a5cSEmil Constantinescu 
13213d177a5cSEmil Constantinescu /* ------------------------------------------------------------ */
13223d177a5cSEmil Constantinescu /*MC
13233d177a5cSEmil Constantinescu       TSGLLE - DAE solver using implicit General Linear methods
13243d177a5cSEmil Constantinescu 
13253d177a5cSEmil Constantinescu   These methods contain Runge-Kutta and multistep schemes as special cases.  These special cases have some fundamental
13263d177a5cSEmil Constantinescu   limitations.  For example, diagonally implicit Runge-Kutta cannot have stage order greater than 1 which limits their
13273d177a5cSEmil Constantinescu   applicability to very stiff systems.  Meanwhile, multistep methods cannot be A-stable for order greater than 2 and BDF
13283d177a5cSEmil Constantinescu   are not 0-stable for order greater than 6.  GL methods can be A- and L-stable with arbitrarily high stage order and
13293d177a5cSEmil Constantinescu   reliable error estimates for both 1 and 2 orders higher to facilitate adaptive step sizes and adaptive order schemes.
13303d177a5cSEmil Constantinescu   All this is possible while preserving a singly diagonally implicit structure.
13313d177a5cSEmil Constantinescu 
1332bcf0153eSBarry Smith   Options Database Keys:
13333d177a5cSEmil Constantinescu +  -ts_gl_type <type> - the class of general linear method (irks)
13343d177a5cSEmil Constantinescu .  -ts_gl_rtol <tol>  - relative error
13353d177a5cSEmil Constantinescu .  -ts_gl_atol <tol>  - absolute error
13363d177a5cSEmil Constantinescu .  -ts_gl_min_order <p> - minimum order method to consider (default=1)
13373d177a5cSEmil Constantinescu .  -ts_gl_max_order <p> - maximum order method to consider (default=3)
13383d177a5cSEmil Constantinescu .  -ts_gl_start_order <p> - order of starting method (default=1)
13393d177a5cSEmil Constantinescu .  -ts_gl_complete <method> - method to use for completing the step (rescale-and-modify or rescale)
13403d177a5cSEmil Constantinescu -  -ts_adapt_type <method> - adaptive controller to use (none step both)
13413d177a5cSEmil Constantinescu 
1342bcf0153eSBarry Smith   Level: beginner
1343bcf0153eSBarry Smith 
13443d177a5cSEmil Constantinescu   Notes:
13453d177a5cSEmil Constantinescu   This integrator can be applied to DAE.
13463d177a5cSEmil Constantinescu 
13473d177a5cSEmil Constantinescu   Diagonally implicit general linear (DIGL) methods are a generalization of diagonally implicit Runge-Kutta (DIRK).
13483d177a5cSEmil Constantinescu   They are represented by the tableau
13493d177a5cSEmil Constantinescu 
13503d177a5cSEmil Constantinescu .vb
13513d177a5cSEmil Constantinescu   A  |  U
13523d177a5cSEmil Constantinescu   -------
13533d177a5cSEmil Constantinescu   B  |  V
13543d177a5cSEmil Constantinescu .ve
13553d177a5cSEmil Constantinescu 
13563d177a5cSEmil Constantinescu   combined with a vector c of abscissa.  "Diagonally implicit" means that A is lower triangular.
13573d177a5cSEmil Constantinescu   A step of the general method reads
13583d177a5cSEmil Constantinescu 
13593d177a5cSEmil Constantinescu .vb
13603d177a5cSEmil Constantinescu   [ Y ] = [A  U] [  Y'   ]
13613d177a5cSEmil Constantinescu   [X^k] = [B  V] [X^{k-1}]
13623d177a5cSEmil Constantinescu .ve
13633d177a5cSEmil Constantinescu 
13643d177a5cSEmil Constantinescu   where Y is the multivector of stage values, Y' is the multivector of stage derivatives, X^k is the Nordsieck vector of
13653d177a5cSEmil Constantinescu   the solution at step k.  The Nordsieck vector consists of the first r moments of the solution, given by
13663d177a5cSEmil Constantinescu 
13673d177a5cSEmil Constantinescu .vb
13683d177a5cSEmil Constantinescu   X = [x_0,x_1,...,x_{r-1}] = [x, h x', h^2 x'', ..., h^{r-1} x^{(r-1)} ]
13693d177a5cSEmil Constantinescu .ve
13703d177a5cSEmil Constantinescu 
13713d177a5cSEmil Constantinescu   If A is lower triangular, we can solve the stages (Y,Y') sequentially
13723d177a5cSEmil Constantinescu 
13733d177a5cSEmil Constantinescu .vb
13743d177a5cSEmil 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}
13753d177a5cSEmil Constantinescu .ve
13763d177a5cSEmil Constantinescu 
13773d177a5cSEmil Constantinescu   and then construct the pieces to carry to the next step
13783d177a5cSEmil Constantinescu 
13793d177a5cSEmil Constantinescu .vb
13803d177a5cSEmil 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}
13813d177a5cSEmil Constantinescu .ve
13823d177a5cSEmil Constantinescu 
13833d177a5cSEmil Constantinescu   Note that when the equations are cast in implicit form, we are using the stage equation to define y'_i
13843d177a5cSEmil Constantinescu   in terms of y_i and known stuff (y_j for j<i and x_j for all j).
13853d177a5cSEmil Constantinescu 
13863d177a5cSEmil Constantinescu   Error estimation
13873d177a5cSEmil Constantinescu 
13883d177a5cSEmil Constantinescu   At present, the most attractive GL methods for stiff problems are singly diagonally implicit schemes which posses
1389bcf0153eSBarry Smith   Inherent Runge-Kutta Stability (`TSIRKS`).  These methods have r=s, the number of items passed between steps is equal to
13903d177a5cSEmil Constantinescu   the number of stages.  The order and stage-order are one less than the number of stages.  We use the error estimates
13913d177a5cSEmil Constantinescu   in the 2007 paper which provide the following estimates
13923d177a5cSEmil Constantinescu 
13933d177a5cSEmil Constantinescu .vb
13943d177a5cSEmil Constantinescu   h^{p+1} X^{(p+1)}          = phi_0^T Y' + [0 psi_0^T] Xold
13953d177a5cSEmil Constantinescu   h^{p+2} X^{(p+2)}          = phi_1^T Y' + [0 psi_1^T] Xold
13963d177a5cSEmil Constantinescu   h^{p+2} (dx'/dx) X^{(p+1)} = phi_2^T Y' + [0 psi_2^T] Xold
13973d177a5cSEmil Constantinescu .ve
13983d177a5cSEmil Constantinescu 
13993d177a5cSEmil Constantinescu   These estimates are accurate to O(h^{p+3}).
14003d177a5cSEmil Constantinescu 
14013d177a5cSEmil Constantinescu   Changing the step size
14023d177a5cSEmil Constantinescu 
14033d177a5cSEmil Constantinescu   We use the generalized "rescale and modify" scheme, see equation (4.5) of the 2007 paper.
14043d177a5cSEmil Constantinescu 
14053d177a5cSEmil Constantinescu   References:
1406606c0280SSatish Balay + * - John Butcher and Z. Jackieweicz and W. Wright, On error propagation in general linear methods for
14073d177a5cSEmil Constantinescu   ordinary differential equations, Journal of Complexity, Vol 23, 2007.
1408606c0280SSatish Balay - * - John Butcher, Numerical methods for ordinary differential equations, second edition, Wiley, 2009.
14093d177a5cSEmil Constantinescu 
1410*1cc06b55SBarry Smith .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSType`
14113d177a5cSEmil Constantinescu M*/
1412d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TSCreate_GLLE(TS ts)
1413d71ae5a4SJacob Faibussowitsch {
14143d177a5cSEmil Constantinescu   TS_GLLE *gl;
14153d177a5cSEmil Constantinescu 
14163d177a5cSEmil Constantinescu   PetscFunctionBegin;
14179566063dSJacob Faibussowitsch   PetscCall(TSGLLEInitializePackage());
14183d177a5cSEmil Constantinescu 
14194dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&gl));
14203d177a5cSEmil Constantinescu   ts->data = (void *)gl;
14213d177a5cSEmil Constantinescu 
14223d177a5cSEmil Constantinescu   ts->ops->reset          = TSReset_GLLE;
14233d177a5cSEmil Constantinescu   ts->ops->destroy        = TSDestroy_GLLE;
14243d177a5cSEmil Constantinescu   ts->ops->view           = TSView_GLLE;
14253d177a5cSEmil Constantinescu   ts->ops->setup          = TSSetUp_GLLE;
14263d177a5cSEmil Constantinescu   ts->ops->solve          = TSSolve_GLLE;
14273d177a5cSEmil Constantinescu   ts->ops->setfromoptions = TSSetFromOptions_GLLE;
14283d177a5cSEmil Constantinescu   ts->ops->snesfunction   = SNESTSFormFunction_GLLE;
14293d177a5cSEmil Constantinescu   ts->ops->snesjacobian   = SNESTSFormJacobian_GLLE;
14303d177a5cSEmil Constantinescu 
1431efd4aadfSBarry Smith   ts->usessnes = PETSC_TRUE;
1432efd4aadfSBarry Smith 
14333d177a5cSEmil Constantinescu   gl->max_step_rejections = 1;
14343d177a5cSEmil Constantinescu   gl->min_order           = 1;
14353d177a5cSEmil Constantinescu   gl->max_order           = 3;
14363d177a5cSEmil Constantinescu   gl->start_order         = 1;
14373d177a5cSEmil Constantinescu   gl->current_scheme      = -1;
14383d177a5cSEmil Constantinescu   gl->extrapolate         = PETSC_FALSE;
14393d177a5cSEmil Constantinescu 
14403d177a5cSEmil Constantinescu   gl->wrms_atol = 1e-8;
14413d177a5cSEmil Constantinescu   gl->wrms_rtol = 1e-5;
14423d177a5cSEmil Constantinescu 
14439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLESetType_C", &TSGLLESetType_GLLE));
14449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLESetAcceptType_C", &TSGLLESetAcceptType_GLLE));
14459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLEGetAdapt_C", &TSGLLEGetAdapt_GLLE));
14463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14473d177a5cSEmil Constantinescu }
1448