xref: /petsc/src/ts/impls/implicit/glle/glle.c (revision 1d27aa22b2f6148b2c4e3f06a75e0638d6493e09)
13d177a5cSEmil Constantinescu #include <../src/ts/impls/implicit/glle/glle.h> /*I   "petscts.h"   I*/
23d177a5cSEmil Constantinescu #include <petscdm.h>
33d177a5cSEmil Constantinescu #include <petscblaslapack.h>
43d177a5cSEmil Constantinescu 
5c793f718SLisandro Dalcin static const char       *TSGLLEErrorDirections[] = {"FORWARD", "BACKWARD", "TSGLLEErrorDirection", "TSGLLEERROR_", NULL};
63d177a5cSEmil Constantinescu static PetscFunctionList TSGLLEList;
73d177a5cSEmil Constantinescu static PetscFunctionList TSGLLEAcceptList;
83d177a5cSEmil Constantinescu static PetscBool         TSGLLEPackageInitialized;
93d177a5cSEmil Constantinescu static PetscBool         TSGLLERegisterAllCalled;
103d177a5cSEmil Constantinescu 
113d177a5cSEmil Constantinescu /* This function is pure */
12d71ae5a4SJacob Faibussowitsch static PetscScalar Factorial(PetscInt n)
13d71ae5a4SJacob Faibussowitsch {
143d177a5cSEmil Constantinescu   PetscInt i;
153d177a5cSEmil Constantinescu   if (n < 12) { /* Can compute with 32-bit integers */
163d177a5cSEmil Constantinescu     PetscInt f = 1;
173d177a5cSEmil Constantinescu     for (i = 2; i <= n; i++) f *= i;
183d177a5cSEmil Constantinescu     return (PetscScalar)f;
193d177a5cSEmil Constantinescu   } else {
203d177a5cSEmil Constantinescu     PetscScalar f = 1.;
213d177a5cSEmil Constantinescu     for (i = 2; i <= n; i++) f *= (PetscScalar)i;
223d177a5cSEmil Constantinescu     return f;
233d177a5cSEmil Constantinescu   }
243d177a5cSEmil Constantinescu }
253d177a5cSEmil Constantinescu 
263d177a5cSEmil Constantinescu /* This function is pure */
27d71ae5a4SJacob Faibussowitsch static PetscScalar CPowF(PetscScalar c, PetscInt p)
28d71ae5a4SJacob Faibussowitsch {
293d177a5cSEmil Constantinescu   return PetscPowRealInt(PetscRealPart(c), p) / Factorial(p);
303d177a5cSEmil Constantinescu }
313d177a5cSEmil Constantinescu 
32d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEGetVecs(TS ts, DM dm, Vec *Z, Vec *Ydotstage)
33d71ae5a4SJacob Faibussowitsch {
343d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
353d177a5cSEmil Constantinescu 
363d177a5cSEmil Constantinescu   PetscFunctionBegin;
373d177a5cSEmil Constantinescu   if (Z) {
383d177a5cSEmil Constantinescu     if (dm && dm != ts->dm) {
399566063dSJacob Faibussowitsch       PetscCall(DMGetNamedGlobalVector(dm, "TSGLLE_Z", Z));
403d177a5cSEmil Constantinescu     } else *Z = gl->Z;
413d177a5cSEmil Constantinescu   }
423d177a5cSEmil Constantinescu   if (Ydotstage) {
433d177a5cSEmil Constantinescu     if (dm && dm != ts->dm) {
449566063dSJacob Faibussowitsch       PetscCall(DMGetNamedGlobalVector(dm, "TSGLLE_Ydot", Ydotstage));
453d177a5cSEmil Constantinescu     } else *Ydotstage = gl->Ydot[gl->stage];
463d177a5cSEmil Constantinescu   }
473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
483d177a5cSEmil Constantinescu }
493d177a5cSEmil Constantinescu 
50d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLERestoreVecs(TS ts, DM dm, Vec *Z, Vec *Ydotstage)
51d71ae5a4SJacob Faibussowitsch {
523d177a5cSEmil Constantinescu   PetscFunctionBegin;
533d177a5cSEmil Constantinescu   if (Z) {
5448a46eb9SPierre Jolivet     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSGLLE_Z", Z));
553d177a5cSEmil Constantinescu   }
563d177a5cSEmil Constantinescu   if (Ydotstage) {
5748a46eb9SPierre Jolivet     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSGLLE_Ydot", Ydotstage));
583d177a5cSEmil Constantinescu   }
593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
603d177a5cSEmil Constantinescu }
613d177a5cSEmil Constantinescu 
62d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCoarsenHook_TSGLLE(DM fine, DM coarse, void *ctx)
63d71ae5a4SJacob Faibussowitsch {
643d177a5cSEmil Constantinescu   PetscFunctionBegin;
653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
663d177a5cSEmil Constantinescu }
673d177a5cSEmil Constantinescu 
68d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMRestrictHook_TSGLLE(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse, void *ctx)
69d71ae5a4SJacob Faibussowitsch {
703d177a5cSEmil Constantinescu   TS  ts = (TS)ctx;
713d177a5cSEmil Constantinescu   Vec Ydot, Ydot_c;
723d177a5cSEmil Constantinescu 
733d177a5cSEmil Constantinescu   PetscFunctionBegin;
749566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, fine, NULL, &Ydot));
759566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, coarse, NULL, &Ydot_c));
769566063dSJacob Faibussowitsch   PetscCall(MatRestrict(restrct, Ydot, Ydot_c));
779566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(Ydot_c, rscale, Ydot_c));
789566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, fine, NULL, &Ydot));
799566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, coarse, NULL, &Ydot_c));
803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
813d177a5cSEmil Constantinescu }
823d177a5cSEmil Constantinescu 
83d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSubDomainHook_TSGLLE(DM dm, DM subdm, void *ctx)
84d71ae5a4SJacob Faibussowitsch {
853d177a5cSEmil Constantinescu   PetscFunctionBegin;
863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
873d177a5cSEmil Constantinescu }
883d177a5cSEmil Constantinescu 
89d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSubDomainRestrictHook_TSGLLE(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx)
90d71ae5a4SJacob Faibussowitsch {
913d177a5cSEmil Constantinescu   TS  ts = (TS)ctx;
923d177a5cSEmil Constantinescu   Vec Ydot, Ydot_s;
933d177a5cSEmil Constantinescu 
943d177a5cSEmil Constantinescu   PetscFunctionBegin;
959566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, dm, NULL, &Ydot));
969566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, subdm, NULL, &Ydot_s));
973d177a5cSEmil Constantinescu 
989566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(gscat, Ydot, Ydot_s, INSERT_VALUES, SCATTER_FORWARD));
999566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(gscat, Ydot, Ydot_s, INSERT_VALUES, SCATTER_FORWARD));
1003d177a5cSEmil Constantinescu 
1019566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, dm, NULL, &Ydot));
1029566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, subdm, NULL, &Ydot_s));
1033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1043d177a5cSEmil Constantinescu }
1053d177a5cSEmil Constantinescu 
106d71ae5a4SJacob 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)
107d71ae5a4SJacob Faibussowitsch {
1083d177a5cSEmil Constantinescu   TSGLLEScheme scheme;
1093d177a5cSEmil Constantinescu   PetscInt     j;
1103d177a5cSEmil Constantinescu 
1113d177a5cSEmil Constantinescu   PetscFunctionBegin;
11208401ef6SPierre Jolivet   PetscCheck(p >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Scheme order must be positive");
11308401ef6SPierre Jolivet   PetscCheck(r >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "At least one item must be carried between steps");
11408401ef6SPierre Jolivet   PetscCheck(s >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "At least one stage is required");
1154f572ea9SToby Isaac   PetscAssertPointer(inscheme, 10);
116c793f718SLisandro Dalcin   *inscheme = NULL;
1179566063dSJacob Faibussowitsch   PetscCall(PetscNew(&scheme));
1183d177a5cSEmil Constantinescu   scheme->p = p;
1193d177a5cSEmil Constantinescu   scheme->q = q;
1203d177a5cSEmil Constantinescu   scheme->r = r;
1213d177a5cSEmil Constantinescu   scheme->s = s;
1223d177a5cSEmil Constantinescu 
1239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(s, &scheme->c, s * s, &scheme->a, r * s, &scheme->b, r * s, &scheme->u, r * r, &scheme->v));
1249566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(scheme->c, c, s));
1253d177a5cSEmil Constantinescu   for (j = 0; j < s * s; j++) scheme->a[j] = (PetscAbsScalar(a[j]) < 1e-12) ? 0 : a[j];
1263d177a5cSEmil Constantinescu   for (j = 0; j < r * s; j++) scheme->b[j] = (PetscAbsScalar(b[j]) < 1e-12) ? 0 : b[j];
1273d177a5cSEmil Constantinescu   for (j = 0; j < s * r; j++) scheme->u[j] = (PetscAbsScalar(u[j]) < 1e-12) ? 0 : u[j];
1283d177a5cSEmil Constantinescu   for (j = 0; j < r * r; j++) scheme->v[j] = (PetscAbsScalar(v[j]) < 1e-12) ? 0 : v[j];
1293d177a5cSEmil Constantinescu 
1309566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(r, &scheme->alpha, r, &scheme->beta, r, &scheme->gamma, 3 * s, &scheme->phi, 3 * r, &scheme->psi, r, &scheme->stage_error));
1313d177a5cSEmil Constantinescu   {
1323d177a5cSEmil Constantinescu     PetscInt     i, j, k, ss = s + 2;
1333d177a5cSEmil Constantinescu     PetscBLASInt m, n, one = 1, *ipiv, lwork = 4 * ((s + 3) * 3 + 3), info, ldb;
1343d177a5cSEmil Constantinescu     PetscReal    rcond, *sing, *workreal;
1353d177a5cSEmil Constantinescu     PetscScalar *ImV, *H, *bmat, *workscalar, *c = scheme->c, *a = scheme->a, *b = scheme->b, *u = scheme->u, *v = scheme->v;
1363d177a5cSEmil Constantinescu     PetscBLASInt rank;
1379566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(PetscSqr(r), &ImV, 3 * s, &H, 3 * ss, &bmat, lwork, &workscalar, 5 * (3 + r), &workreal, r + s, &sing, r + s, &ipiv));
1383d177a5cSEmil Constantinescu 
1393d177a5cSEmil Constantinescu     /* column-major input */
1403d177a5cSEmil Constantinescu     for (i = 0; i < r - 1; i++) {
1413d177a5cSEmil Constantinescu       for (j = 0; j < r - 1; j++) ImV[i + j * r] = 1.0 * (i == j) - v[(i + 1) * r + j + 1];
1423d177a5cSEmil Constantinescu     }
1433d177a5cSEmil Constantinescu     /* Build right hand side for alpha (tp - glm.B(2:end,:)*(glm.c.^(p)./factorial(p))) */
1443d177a5cSEmil Constantinescu     for (i = 1; i < r; i++) {
1453d177a5cSEmil Constantinescu       scheme->alpha[i] = 1. / Factorial(p + 1 - i);
1463d177a5cSEmil Constantinescu       for (j = 0; j < s; j++) scheme->alpha[i] -= b[i * s + j] * CPowF(c[j], p);
1473d177a5cSEmil Constantinescu     }
1489566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(r - 1, &m));
1499566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(r, &n));
150792fecdfSBarry Smith     PetscCallBLAS("LAPACKgesv", LAPACKgesv_(&m, &one, ImV, &n, ipiv, scheme->alpha + 1, &n, &info));
15108401ef6SPierre Jolivet     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GESV");
15208401ef6SPierre Jolivet     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_MAT_LU_ZRPVT, "Bad LU factorization");
1533d177a5cSEmil Constantinescu 
1543d177a5cSEmil Constantinescu     /* Build right hand side for beta (tp1 - glm.B(2:end,:)*(glm.c.^(p+1)./factorial(p+1)) - e.alpha) */
1553d177a5cSEmil Constantinescu     for (i = 1; i < r; i++) {
1563d177a5cSEmil Constantinescu       scheme->beta[i] = 1. / Factorial(p + 2 - i) - scheme->alpha[i];
1573d177a5cSEmil Constantinescu       for (j = 0; j < s; j++) scheme->beta[i] -= b[i * s + j] * CPowF(c[j], p + 1);
1583d177a5cSEmil Constantinescu     }
159792fecdfSBarry Smith     PetscCallBLAS("LAPACKgetrs", LAPACKgetrs_("No transpose", &m, &one, ImV, &n, ipiv, scheme->beta + 1, &n, &info));
16008401ef6SPierre Jolivet     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GETRS");
16108401ef6SPierre Jolivet     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Should not happen");
1623d177a5cSEmil Constantinescu 
1633d177a5cSEmil Constantinescu     /* Build stage_error vector
1643d177a5cSEmil Constantinescu            xi = glm.c.^(p+1)/factorial(p+1) - glm.A*glm.c.^p/factorial(p) + glm.U(:,2:end)*e.alpha;
1653d177a5cSEmil Constantinescu     */
1663d177a5cSEmil Constantinescu     for (i = 0; i < s; i++) {
1673d177a5cSEmil Constantinescu       scheme->stage_error[i] = CPowF(c[i], p + 1);
1683d177a5cSEmil Constantinescu       for (j = 0; j < s; j++) scheme->stage_error[i] -= a[i * s + j] * CPowF(c[j], p);
1693d177a5cSEmil Constantinescu       for (j = 1; j < r; j++) scheme->stage_error[i] += u[i * r + j] * scheme->alpha[j];
1703d177a5cSEmil Constantinescu     }
1713d177a5cSEmil Constantinescu 
1723d177a5cSEmil Constantinescu     /* alpha[0] (epsilon in B,J,W 2007)
1733d177a5cSEmil Constantinescu            epsilon = 1/factorial(p+1) - B(1,:)*c.^p/factorial(p) + V(1,2:end)*e.alpha;
1743d177a5cSEmil Constantinescu     */
1753d177a5cSEmil Constantinescu     scheme->alpha[0] = 1. / Factorial(p + 1);
1763d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) scheme->alpha[0] -= b[0 * s + j] * CPowF(c[j], p);
1773d177a5cSEmil Constantinescu     for (j = 1; j < r; j++) scheme->alpha[0] += v[0 * r + j] * scheme->alpha[j];
1783d177a5cSEmil Constantinescu 
1793d177a5cSEmil Constantinescu     /* right hand side for gamma (glm.B(2:end,:)*e.xi - e.epsilon*eye(s-1,1)) */
1803d177a5cSEmil Constantinescu     for (i = 1; i < r; i++) {
1813d177a5cSEmil Constantinescu       scheme->gamma[i] = (i == 1 ? -1. : 0) * scheme->alpha[0];
1823d177a5cSEmil Constantinescu       for (j = 0; j < s; j++) scheme->gamma[i] += b[i * s + j] * scheme->stage_error[j];
1833d177a5cSEmil Constantinescu     }
184792fecdfSBarry Smith     PetscCallBLAS("LAPACKgetrs", LAPACKgetrs_("No transpose", &m, &one, ImV, &n, ipiv, scheme->gamma + 1, &n, &info));
18508401ef6SPierre Jolivet     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GETRS");
18608401ef6SPierre Jolivet     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Should not happen");
1873d177a5cSEmil Constantinescu 
1883d177a5cSEmil Constantinescu     /* beta[0] (rho in B,J,W 2007)
1893d177a5cSEmil Constantinescu         e.rho = 1/factorial(p+2) - glm.B(1,:)*glm.c.^(p+1)/factorial(p+1) ...
1903d177a5cSEmil Constantinescu             + glm.V(1,2:end)*e.beta;% - e.epsilon;
1913d177a5cSEmil Constantinescu     % Note: The paper (B,J,W 2007) includes the last term in their definition
1923d177a5cSEmil Constantinescu     * */
1933d177a5cSEmil Constantinescu     scheme->beta[0] = 1. / Factorial(p + 2);
1943d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) scheme->beta[0] -= b[0 * s + j] * CPowF(c[j], p + 1);
1953d177a5cSEmil Constantinescu     for (j = 1; j < r; j++) scheme->beta[0] += v[0 * r + j] * scheme->beta[j];
1963d177a5cSEmil Constantinescu 
1973d177a5cSEmil Constantinescu     /* gamma[0] (sigma in B,J,W 2007)
1983d177a5cSEmil Constantinescu     *   e.sigma = glm.B(1,:)*e.xi + glm.V(1,2:end)*e.gamma;
1993d177a5cSEmil Constantinescu     * */
2003d177a5cSEmil Constantinescu     scheme->gamma[0] = 0.0;
2013d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) scheme->gamma[0] += b[0 * s + j] * scheme->stage_error[j];
2023d177a5cSEmil Constantinescu     for (j = 1; j < r; j++) scheme->gamma[0] += v[0 * s + j] * scheme->gamma[j];
2033d177a5cSEmil Constantinescu 
2043d177a5cSEmil Constantinescu     /* Assemble H
20563a3b9bcSJacob Faibussowitsch     *    % " PetscInt_FMT "etermine the error estimators phi
2063d177a5cSEmil Constantinescu        H = [[cpow(glm.c,p) + C*e.alpha] [cpow(glm.c,p+1) + C*e.beta] ...
2073d177a5cSEmil Constantinescu                [e.xi - C*(e.gamma + 0*e.epsilon*eye(s-1,1))]]';
2083d177a5cSEmil Constantinescu     % Paper has formula above without the 0, but that term must be left
2093d177a5cSEmil Constantinescu     % out to satisfy the conditions they propose and to make the
2103d177a5cSEmil Constantinescu     % example schemes work
2113d177a5cSEmil Constantinescu     e.H = H;
2123d177a5cSEmil Constantinescu     e.phi = (H \ [1 0 0;1 1 0;0 0 -1])';
2133d177a5cSEmil Constantinescu     e.psi = -e.phi*C;
2143d177a5cSEmil Constantinescu     * */
2153d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) {
2163d177a5cSEmil Constantinescu       H[0 + j * 3] = CPowF(c[j], p);
2173d177a5cSEmil Constantinescu       H[1 + j * 3] = CPowF(c[j], p + 1);
2183d177a5cSEmil Constantinescu       H[2 + j * 3] = scheme->stage_error[j];
2193d177a5cSEmil Constantinescu       for (k = 1; k < r; k++) {
2203d177a5cSEmil Constantinescu         H[0 + j * 3] += CPowF(c[j], k - 1) * scheme->alpha[k];
2213d177a5cSEmil Constantinescu         H[1 + j * 3] += CPowF(c[j], k - 1) * scheme->beta[k];
2223d177a5cSEmil Constantinescu         H[2 + j * 3] -= CPowF(c[j], k - 1) * scheme->gamma[k];
2233d177a5cSEmil Constantinescu       }
2243d177a5cSEmil Constantinescu     }
2259371c9d4SSatish Balay     bmat[0 + 0 * ss] = 1.;
2269371c9d4SSatish Balay     bmat[0 + 1 * ss] = 0.;
2279371c9d4SSatish Balay     bmat[0 + 2 * ss] = 0.;
2289371c9d4SSatish Balay     bmat[1 + 0 * ss] = 1.;
2299371c9d4SSatish Balay     bmat[1 + 1 * ss] = 1.;
2309371c9d4SSatish Balay     bmat[1 + 2 * ss] = 0.;
2319371c9d4SSatish Balay     bmat[2 + 0 * ss] = 0.;
2329371c9d4SSatish Balay     bmat[2 + 1 * ss] = 0.;
2339371c9d4SSatish Balay     bmat[2 + 2 * ss] = -1.;
2343d177a5cSEmil Constantinescu     m                = 3;
2359566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(s, &n));
2369566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(ss, &ldb));
2373d177a5cSEmil Constantinescu     rcond = 1e-12;
2383d177a5cSEmil Constantinescu #if defined(PETSC_USE_COMPLEX)
2393d177a5cSEmil Constantinescu     /* ZGELSS( M, N, NRHS, A, LDA, B, LDB, S, RCOND, RANK, WORK, LWORK, RWORK, INFO) */
240792fecdfSBarry Smith     PetscCallBLAS("LAPACKgelss", LAPACKgelss_(&m, &n, &m, H, &m, bmat, &ldb, sing, &rcond, &rank, workscalar, &lwork, workreal, &info));
2413d177a5cSEmil Constantinescu #else
2423d177a5cSEmil Constantinescu     /* DGELSS( M, N, NRHS, A, LDA, B, LDB, S, RCOND, RANK, WORK, LWORK, INFO) */
243792fecdfSBarry Smith     PetscCallBLAS("LAPACKgelss", LAPACKgelss_(&m, &n, &m, H, &m, bmat, &ldb, sing, &rcond, &rank, workscalar, &lwork, &info));
2443d177a5cSEmil Constantinescu #endif
24508401ef6SPierre Jolivet     PetscCheck(info >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GELSS");
24608401ef6SPierre Jolivet     PetscCheck(info <= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "SVD failed to converge");
2473d177a5cSEmil Constantinescu 
2483d177a5cSEmil Constantinescu     for (j = 0; j < 3; j++) {
2493d177a5cSEmil Constantinescu       for (k = 0; k < s; k++) scheme->phi[k + j * s] = bmat[k + j * ss];
2503d177a5cSEmil Constantinescu     }
2513d177a5cSEmil Constantinescu 
2523d177a5cSEmil Constantinescu     /* the other part of the error estimator, psi in B,J,W 2007 */
2533d177a5cSEmil Constantinescu     scheme->psi[0 * r + 0] = 0.;
2543d177a5cSEmil Constantinescu     scheme->psi[1 * r + 0] = 0.;
2553d177a5cSEmil Constantinescu     scheme->psi[2 * r + 0] = 0.;
2563d177a5cSEmil Constantinescu     for (j = 1; j < r; j++) {
2573d177a5cSEmil Constantinescu       scheme->psi[0 * r + j] = 0.;
2583d177a5cSEmil Constantinescu       scheme->psi[1 * r + j] = 0.;
2593d177a5cSEmil Constantinescu       scheme->psi[2 * r + j] = 0.;
2603d177a5cSEmil Constantinescu       for (k = 0; k < s; k++) {
2613d177a5cSEmil Constantinescu         scheme->psi[0 * r + j] -= CPowF(c[k], j - 1) * scheme->phi[0 * s + k];
2623d177a5cSEmil Constantinescu         scheme->psi[1 * r + j] -= CPowF(c[k], j - 1) * scheme->phi[1 * s + k];
2633d177a5cSEmil Constantinescu         scheme->psi[2 * r + j] -= CPowF(c[k], j - 1) * scheme->phi[2 * s + k];
2643d177a5cSEmil Constantinescu       }
2653d177a5cSEmil Constantinescu     }
2669566063dSJacob Faibussowitsch     PetscCall(PetscFree7(ImV, H, bmat, workscalar, workreal, sing, ipiv));
2673d177a5cSEmil Constantinescu   }
2683d177a5cSEmil Constantinescu   /* Check which properties are satisfied */
2693d177a5cSEmil Constantinescu   scheme->stiffly_accurate = PETSC_TRUE;
2703d177a5cSEmil Constantinescu   if (scheme->c[s - 1] != 1.) scheme->stiffly_accurate = PETSC_FALSE;
2719371c9d4SSatish Balay   for (j = 0; j < s; j++)
2729371c9d4SSatish Balay     if (a[(s - 1) * s + j] != b[j]) scheme->stiffly_accurate = PETSC_FALSE;
2739371c9d4SSatish Balay   for (j = 0; j < r; j++)
2749371c9d4SSatish Balay     if (u[(s - 1) * r + j] != v[j]) scheme->stiffly_accurate = PETSC_FALSE;
2753d177a5cSEmil Constantinescu   scheme->fsal = scheme->stiffly_accurate; /* FSAL is stronger */
2769371c9d4SSatish Balay   for (j = 0; j < s - 1; j++)
2779371c9d4SSatish Balay     if (r > 1 && b[1 * s + j] != 0.) scheme->fsal = PETSC_FALSE;
2783d177a5cSEmil Constantinescu   if (b[1 * s + r - 1] != 1.) scheme->fsal = PETSC_FALSE;
2799371c9d4SSatish Balay   for (j = 0; j < r; j++)
2809371c9d4SSatish Balay     if (r > 1 && v[1 * r + j] != 0.) scheme->fsal = PETSC_FALSE;
2813d177a5cSEmil Constantinescu 
2823d177a5cSEmil Constantinescu   *inscheme = scheme;
2833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2843d177a5cSEmil Constantinescu }
2853d177a5cSEmil Constantinescu 
286d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLESchemeDestroy(TSGLLEScheme sc)
287d71ae5a4SJacob Faibussowitsch {
2883d177a5cSEmil Constantinescu   PetscFunctionBegin;
2899566063dSJacob Faibussowitsch   PetscCall(PetscFree5(sc->c, sc->a, sc->b, sc->u, sc->v));
2909566063dSJacob Faibussowitsch   PetscCall(PetscFree6(sc->alpha, sc->beta, sc->gamma, sc->phi, sc->psi, sc->stage_error));
2919566063dSJacob Faibussowitsch   PetscCall(PetscFree(sc));
2923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2933d177a5cSEmil Constantinescu }
2943d177a5cSEmil Constantinescu 
295d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEDestroy_Default(TS_GLLE *gl)
296d71ae5a4SJacob Faibussowitsch {
2973d177a5cSEmil Constantinescu   PetscInt i;
2983d177a5cSEmil Constantinescu 
2993d177a5cSEmil Constantinescu   PetscFunctionBegin;
3003d177a5cSEmil Constantinescu   for (i = 0; i < gl->nschemes; i++) {
3019566063dSJacob Faibussowitsch     if (gl->schemes[i]) PetscCall(TSGLLESchemeDestroy(gl->schemes[i]));
3023d177a5cSEmil Constantinescu   }
3039566063dSJacob Faibussowitsch   PetscCall(PetscFree(gl->schemes));
3043d177a5cSEmil Constantinescu   gl->nschemes = 0;
3059566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(gl->type_name, sizeof(gl->type_name)));
3063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3073d177a5cSEmil Constantinescu }
3083d177a5cSEmil Constantinescu 
309d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEViewTable_Private(PetscViewer viewer, PetscInt m, PetscInt n, const PetscScalar a[], const char name[])
310d71ae5a4SJacob Faibussowitsch {
3113d177a5cSEmil Constantinescu   PetscBool iascii;
3123d177a5cSEmil Constantinescu   PetscInt  i, j;
3133d177a5cSEmil Constantinescu 
3143d177a5cSEmil Constantinescu   PetscFunctionBegin;
3159566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
3163d177a5cSEmil Constantinescu   if (iascii) {
3179566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "%30s = [", name));
3183d177a5cSEmil Constantinescu     for (i = 0; i < m; i++) {
3199566063dSJacob Faibussowitsch       if (i) PetscCall(PetscViewerASCIIPrintf(viewer, "%30s   [", ""));
3209566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
32148a46eb9SPierre Jolivet       for (j = 0; j < n; j++) PetscCall(PetscViewerASCIIPrintf(viewer, " %12.8g", (double)PetscRealPart(a[i * n + j])));
3229566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "]\n"));
3239566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
3243d177a5cSEmil Constantinescu     }
3253d177a5cSEmil Constantinescu   }
3263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3273d177a5cSEmil Constantinescu }
3283d177a5cSEmil Constantinescu 
329d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLESchemeView(TSGLLEScheme sc, PetscBool view_details, PetscViewer viewer)
330d71ae5a4SJacob Faibussowitsch {
3313d177a5cSEmil Constantinescu   PetscBool iascii;
3323d177a5cSEmil Constantinescu 
3333d177a5cSEmil Constantinescu   PetscFunctionBegin;
3349566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
3353d177a5cSEmil Constantinescu   if (iascii) {
33663a3b9bcSJacob 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));
3379566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
3389566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Stiffly accurate: %s,  FSAL: %s\n", sc->stiffly_accurate ? "yes" : "no", sc->fsal ? "yes" : "no"));
3399371c9d4SSatish 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])));
3409566063dSJacob Faibussowitsch     PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->s, sc->c, "Abscissas c"));
3413d177a5cSEmil Constantinescu     if (view_details) {
3429566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, sc->s, sc->s, sc->a, "A"));
3439566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, sc->r, sc->s, sc->b, "B"));
3449566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, sc->s, sc->r, sc->u, "U"));
3459566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, sc->r, sc->r, sc->v, "V"));
3463d177a5cSEmil Constantinescu 
3479566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 3, sc->s, sc->phi, "Error estimate phi"));
3489566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 3, sc->r, sc->psi, "Error estimate psi"));
3499566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->r, sc->alpha, "Modify alpha"));
3509566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->r, sc->beta, "Modify beta"));
3519566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->r, sc->gamma, "Modify gamma"));
3529566063dSJacob Faibussowitsch       PetscCall(TSGLLEViewTable_Private(viewer, 1, sc->s, sc->stage_error, "Stage error xi"));
3533d177a5cSEmil Constantinescu     }
3549566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
35598921bdaSJacob Faibussowitsch   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Viewer type %s not supported", ((PetscObject)viewer)->type_name);
3563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3573d177a5cSEmil Constantinescu }
3583d177a5cSEmil Constantinescu 
359d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEEstimateHigherMoments_Default(TSGLLEScheme sc, PetscReal h, Vec Ydot[], Vec Xold[], Vec hm[])
360d71ae5a4SJacob Faibussowitsch {
3613d177a5cSEmil Constantinescu   PetscInt i;
3623d177a5cSEmil Constantinescu 
3633d177a5cSEmil Constantinescu   PetscFunctionBegin;
364cad9d221SBarry Smith   PetscCheck(sc->r <= 64 && sc->s <= 64, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Ridiculous number of stages or items passed between stages");
3653d177a5cSEmil Constantinescu   /* build error vectors*/
3663d177a5cSEmil Constantinescu   for (i = 0; i < 3; i++) {
3673d177a5cSEmil Constantinescu     PetscScalar phih[64];
3683d177a5cSEmil Constantinescu     PetscInt    j;
3693d177a5cSEmil Constantinescu     for (j = 0; j < sc->s; j++) phih[j] = sc->phi[i * sc->s + j] * h;
3709566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(hm[i]));
3719566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(hm[i], sc->s, phih, Ydot));
3729566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(hm[i], sc->r, &sc->psi[i * sc->r], Xold));
3733d177a5cSEmil Constantinescu   }
3743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3753d177a5cSEmil Constantinescu }
3763d177a5cSEmil Constantinescu 
377d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLECompleteStep_Rescale(TSGLLEScheme sc, PetscReal h, TSGLLEScheme next_sc, PetscReal next_h, Vec Ydot[], Vec Xold[], Vec X[])
378d71ae5a4SJacob Faibussowitsch {
3793d177a5cSEmil Constantinescu   PetscScalar brow[32], vrow[32];
3803d177a5cSEmil Constantinescu   PetscInt    i, j, r, s;
3813d177a5cSEmil Constantinescu 
3823d177a5cSEmil Constantinescu   PetscFunctionBegin;
3833d177a5cSEmil Constantinescu   /* Build the new solution from (X,Ydot) */
3843d177a5cSEmil Constantinescu   r = sc->r;
3853d177a5cSEmil Constantinescu   s = sc->s;
3863d177a5cSEmil Constantinescu   for (i = 0; i < r; i++) {
3879566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(X[i]));
3883d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) brow[j] = h * sc->b[i * s + j];
3899566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[i], s, brow, Ydot));
3903d177a5cSEmil Constantinescu     for (j = 0; j < r; j++) vrow[j] = sc->v[i * r + j];
3919566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[i], r, vrow, Xold));
3923d177a5cSEmil Constantinescu   }
3933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3943d177a5cSEmil Constantinescu }
3953d177a5cSEmil Constantinescu 
396d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLECompleteStep_RescaleAndModify(TSGLLEScheme sc, PetscReal h, TSGLLEScheme next_sc, PetscReal next_h, Vec Ydot[], Vec Xold[], Vec X[])
397d71ae5a4SJacob Faibussowitsch {
3983d177a5cSEmil Constantinescu   PetscScalar brow[32], vrow[32];
3993d177a5cSEmil Constantinescu   PetscReal   ratio;
4003d177a5cSEmil Constantinescu   PetscInt    i, j, p, r, s;
4013d177a5cSEmil Constantinescu 
4023d177a5cSEmil Constantinescu   PetscFunctionBegin;
4033d177a5cSEmil Constantinescu   /* Build the new solution from (X,Ydot) */
4043d177a5cSEmil Constantinescu   p     = sc->p;
4053d177a5cSEmil Constantinescu   r     = sc->r;
4063d177a5cSEmil Constantinescu   s     = sc->s;
4073d177a5cSEmil Constantinescu   ratio = next_h / h;
4083d177a5cSEmil Constantinescu   for (i = 0; i < r; i++) {
4099566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(X[i]));
4103d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) {
4119371c9d4SSatish 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]));
4123d177a5cSEmil Constantinescu     }
4139566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[i], s, brow, Ydot));
4143d177a5cSEmil Constantinescu     for (j = 0; j < r; j++) {
4159371c9d4SSatish 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]));
4163d177a5cSEmil Constantinescu     }
4179566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[i], r, vrow, Xold));
4183d177a5cSEmil Constantinescu   }
4193d177a5cSEmil Constantinescu   if (r < next_sc->r) {
42008401ef6SPierre Jolivet     PetscCheck(r + 1 == next_sc->r, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot accommodate jump in r greater than 1");
4219566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(X[r]));
4223d177a5cSEmil Constantinescu     for (j = 0; j < s; j++) brow[j] = h * PetscPowRealInt(ratio, p + 1) * sc->phi[0 * s + j];
4239566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[r], s, brow, Ydot));
4243d177a5cSEmil Constantinescu     for (j = 0; j < r; j++) vrow[j] = PetscPowRealInt(ratio, p + 1) * sc->psi[0 * r + j];
4259566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(X[r], r, vrow, Xold));
4263d177a5cSEmil Constantinescu   }
4273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4283d177a5cSEmil Constantinescu }
4293d177a5cSEmil Constantinescu 
430d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLECreate_IRKS(TS ts)
431d71ae5a4SJacob Faibussowitsch {
4323d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
4333d177a5cSEmil Constantinescu 
4343d177a5cSEmil Constantinescu   PetscFunctionBegin;
4353d177a5cSEmil Constantinescu   gl->Destroy               = TSGLLEDestroy_Default;
4363d177a5cSEmil Constantinescu   gl->EstimateHigherMoments = TSGLLEEstimateHigherMoments_Default;
4373d177a5cSEmil Constantinescu   gl->CompleteStep          = TSGLLECompleteStep_RescaleAndModify;
4389566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(10, &gl->schemes));
4393d177a5cSEmil Constantinescu   gl->nschemes = 0;
4403d177a5cSEmil Constantinescu 
4413d177a5cSEmil Constantinescu   {
4423d177a5cSEmil Constantinescu     /* p=1,q=1, r=s=2, A- and L-stable with error estimates of order 2 and 3
4433d177a5cSEmil Constantinescu     * Listed in Butcher & Podhaisky 2006. On error estimation in general linear methods for stiff ODE.
4443d177a5cSEmil Constantinescu     * irks(0.3,0,[.3,1],[1],1)
4453d177a5cSEmil Constantinescu     * Note: can be made to have classical order (not stage order) 2 by replacing 0.3 with 1-sqrt(1/2)
4463d177a5cSEmil Constantinescu     * but doing so would sacrifice the error estimator.
4473d177a5cSEmil Constantinescu     */
4483d177a5cSEmil Constantinescu     const PetscScalar c[2]    = {3. / 10., 1.};
4499371c9d4SSatish Balay     const PetscScalar a[2][2] = {
4509371c9d4SSatish Balay       {3. / 10., 0       },
4519371c9d4SSatish Balay       {7. / 10., 3. / 10.}
4529371c9d4SSatish Balay     };
4539371c9d4SSatish Balay     const PetscScalar b[2][2] = {
4549371c9d4SSatish Balay       {7. / 10., 3. / 10.},
4559371c9d4SSatish Balay       {0,        1       }
4569371c9d4SSatish Balay     };
4579371c9d4SSatish Balay     const PetscScalar u[2][2] = {
4589371c9d4SSatish Balay       {1, 0},
4599371c9d4SSatish Balay       {1, 0}
4609371c9d4SSatish Balay     };
4619371c9d4SSatish Balay     const PetscScalar v[2][2] = {
4629371c9d4SSatish Balay       {1, 0},
4639371c9d4SSatish Balay       {0, 0}
4649371c9d4SSatish Balay     };
4659566063dSJacob Faibussowitsch     PetscCall(TSGLLESchemeCreate(1, 1, 2, 2, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
4663d177a5cSEmil Constantinescu   }
4673d177a5cSEmil Constantinescu 
4683d177a5cSEmil Constantinescu   {
4693d177a5cSEmil Constantinescu     /* p=q=2, r=s=3: irks(4/9,0,[1:3]/3,[0.33852],1) */
4703d177a5cSEmil Constantinescu     /* http://www.math.auckland.ac.nz/~hpod/atlas/i2a.html */
47197a1619fSSatish Balay     const PetscScalar c[3]    = {1. / 3., 2. / 3., 1};
47297a1619fSSatish Balay     const PetscScalar a[3][3] = {
47397a1619fSSatish Balay       {4. / 9.,              0,                     0      },
47497a1619fSSatish Balay       {1.03750643704090e+00, 4. / 9.,               0      },
47597a1619fSSatish Balay       {7.67024779410304e-01, -3.81140216918943e-01, 4. / 9.}
47697a1619fSSatish Balay     };
47797a1619fSSatish Balay     const PetscScalar b[3][3] = {
47897a1619fSSatish Balay       {0.767024779410304,  -0.381140216918943, 4. / 9.          },
47997a1619fSSatish Balay       {0.000000000000000,  0.000000000000000,  1.000000000000000},
48097a1619fSSatish Balay       {-2.075048385225385, 0.621728385225383,  1.277197204924873}
48197a1619fSSatish Balay     };
48297a1619fSSatish Balay     const PetscScalar u[3][3] = {
48397a1619fSSatish Balay       {1.0000000000000000, -0.1111111111111109, -0.0925925925925922},
48497a1619fSSatish Balay       {1.0000000000000000, -0.8152842148186744, -0.4199095530877056},
48597a1619fSSatish Balay       {1.0000000000000000, 0.1696709930641948,  0.0539741070314165 }
48697a1619fSSatish Balay     };
48797a1619fSSatish Balay     const PetscScalar v[3][3] = {
48897a1619fSSatish Balay       {1.0000000000000000, 0.1696709930641948, 0.0539741070314165},
48997a1619fSSatish Balay       {0.000000000000000,  0.000000000000000,  0.000000000000000 },
49097a1619fSSatish Balay       {0.000000000000000,  0.176122795075129,  0.000000000000000 }
49197a1619fSSatish Balay     };
4929566063dSJacob Faibussowitsch     PetscCall(TSGLLESchemeCreate(2, 2, 3, 3, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
4933d177a5cSEmil Constantinescu   }
4943d177a5cSEmil Constantinescu   {
4953d177a5cSEmil Constantinescu     /* p=q=3, r=s=4: irks(9/40,0,[1:4]/4,[0.3312 1.0050],[0.49541 1;1 0]) */
49697a1619fSSatish Balay     const PetscScalar c[4]    = {0.25, 0.5, 0.75, 1.0};
49797a1619fSSatish Balay     const PetscScalar a[4][4] = {
49897a1619fSSatish Balay       {9. / 40.,             0,                     0,                 0       },
49997a1619fSSatish Balay       {2.11286958887701e-01, 9. / 40.,              0,                 0       },
50097a1619fSSatish Balay       {9.46338294287584e-01, -3.42942861246094e-01, 9. / 40.,          0       },
50197a1619fSSatish Balay       {0.521490453970721,    -0.662474225622980,    0.490476425459734, 9. / 40.}
50297a1619fSSatish Balay     };
50397a1619fSSatish Balay     const PetscScalar b[4][4] = {
50497a1619fSSatish Balay       {0.521490453970721,  -0.662474225622980, 0.490476425459734,  9. / 40.         },
50597a1619fSSatish Balay       {0.000000000000000,  0.000000000000000,  0.000000000000000,  1.000000000000000},
50697a1619fSSatish Balay       {-0.084677029310348, 1.390757514776085,  -1.568157386206001, 2.023192696767826},
50797a1619fSSatish Balay       {0.465383797936408,  1.478273530625148,  -1.930836081010182, 1.644872111193354}
50897a1619fSSatish Balay     };
50997a1619fSSatish Balay     const PetscScalar u[4][4] = {
51097a1619fSSatish Balay       {1.00000000000000000, 0.02500000000001035,  -0.02499999999999053, -0.00442708333332865},
51197a1619fSSatish Balay       {1.00000000000000000, 0.06371304111232945,  -0.04032173972189845, -0.01389438413189452},
51297a1619fSSatish Balay       {1.00000000000000000, -0.07839543304147778, 0.04738685705116663,  0.02032603595928376 },
51397a1619fSSatish Balay       {1.00000000000000000, 0.42550734619251651,  0.10800718022400080,  -0.01726712647760034}
51497a1619fSSatish Balay     };
51597a1619fSSatish Balay     const PetscScalar v[4][4] = {
51697a1619fSSatish Balay       {1.00000000000000000, 0.42550734619251651, 0.10800718022400080, -0.01726712647760034},
51797a1619fSSatish Balay       {0.000000000000000,   0.000000000000000,   0.000000000000000,   0.000000000000000   },
51897a1619fSSatish Balay       {0.000000000000000,   -1.761115796027561,  -0.521284157173780,  0.258249384305463   },
51997a1619fSSatish Balay       {0.000000000000000,   -1.657693358744728,  -1.052227765232394,  0.521284157173780   }
52097a1619fSSatish Balay     };
5219566063dSJacob Faibussowitsch     PetscCall(TSGLLESchemeCreate(3, 3, 4, 4, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
5223d177a5cSEmil Constantinescu   }
5233d177a5cSEmil Constantinescu   {
5243d177a5cSEmil Constantinescu     /* p=q=4, r=s=5:
5253d177a5cSEmil Constantinescu           irks(3/11,0,[1:5]/5, [0.1715   -0.1238    0.6617],...
5263d177a5cSEmil Constantinescu           [ -0.0812    0.4079    1.0000
5273d177a5cSEmil Constantinescu              1.0000         0         0
5283d177a5cSEmil Constantinescu              0.8270    1.0000         0])
5293d177a5cSEmil Constantinescu     */
53097a1619fSSatish Balay     const PetscScalar c[5]    = {0.2, 0.4, 0.6, 0.8, 1.0};
53197a1619fSSatish Balay     const PetscScalar a[5][5] = {
53297a1619fSSatish Balay       {2.72727272727352e-01,  0.00000000000000e+00,  0.00000000000000e+00,  0.00000000000000e+00, 0.00000000000000e+00},
53397a1619fSSatish Balay       {-1.03980153733431e-01, 2.72727272727405e-01,  0.00000000000000e+00,  0.00000000000000e+00, 0.00000000000000e+00},
53497a1619fSSatish Balay       {-1.58615400341492e+00, 7.44168951881122e-01,  2.72727272727309e-01,  0.00000000000000e+00, 0.00000000000000e+00},
53597a1619fSSatish Balay       {-8.73658042865628e-01, 5.37884671894595e-01,  -1.63298538799523e-01, 2.72727272726996e-01, 0.00000000000000e+00},
53697a1619fSSatish Balay       {2.95489397443992e-01,  -1.18481693910097e+00, -6.68029812659953e-01, 1.00716687860943e+00, 2.72727272727288e-01}
53797a1619fSSatish Balay     };
53897a1619fSSatish Balay     const PetscScalar b[5][5] = {
53997a1619fSSatish Balay       {2.95489397443992e-01,  -1.18481693910097e+00, -6.68029812659953e-01, 1.00716687860943e+00,  2.72727272727288e-01},
54097a1619fSSatish Balay       {0.00000000000000e+00,  1.11022302462516e-16,  -2.22044604925031e-16, 0.00000000000000e+00,  1.00000000000000e+00},
54197a1619fSSatish Balay       {-4.05882503986005e+00, -4.00924006567769e+00, -1.38930610972481e+00, 4.45223930308488e+00,  6.32331093108427e-01},
54297a1619fSSatish Balay       {8.35690179937017e+00,  -2.26640927349732e+00, 6.86647884973826e+00,  -5.22595158025740e+00, 4.50893068837431e+00},
54397a1619fSSatish Balay       {1.27656267027479e+01,  2.80882153840821e+00,  8.91173096522890e+00,  -1.07936444078906e+01, 4.82534148988854e+00}
54497a1619fSSatish Balay     };
54597a1619fSSatish Balay     const PetscScalar u[5][5] = {
54697a1619fSSatish Balay       {1.00000000000000e+00, -7.27272727273551e-02, -3.45454545454419e-02, -4.12121212119565e-03, -2.96969696964014e-04},
54797a1619fSSatish Balay       {1.00000000000000e+00, 2.31252881006154e-01,  -8.29487834416481e-03, -9.07191207681020e-03, -1.70378403743473e-03},
54897a1619fSSatish Balay       {1.00000000000000e+00, 1.16925777880663e+00,  3.59268562942635e-02,  -4.09013451730615e-02, -1.02411119670164e-02},
54997a1619fSSatish Balay       {1.00000000000000e+00, 1.02634463704356e+00,  1.59375044913405e-01,  1.89673015035370e-03,  -4.89987231897569e-03},
55097a1619fSSatish Balay       {1.00000000000000e+00, 1.27746320298021e+00,  2.37186008132728e-01,  -8.28694373940065e-02, -5.34396510196430e-02}
55197a1619fSSatish Balay     };
55297a1619fSSatish Balay     const PetscScalar v[5][5] = {
55397a1619fSSatish Balay       {1.00000000000000e+00, 1.27746320298021e+00,  2.37186008132728e-01,  -8.28694373940065e-02, -5.34396510196430e-02},
55497a1619fSSatish Balay       {0.00000000000000e+00, -1.77635683940025e-15, -1.99840144432528e-15, -9.99200722162641e-16, -3.33066907387547e-16},
55597a1619fSSatish Balay       {0.00000000000000e+00, 4.37280081906924e+00,  5.49221645016377e-02,  -8.88913177394943e-02, 1.12879077989154e-01 },
55697a1619fSSatish Balay       {0.00000000000000e+00, -1.22399504837280e+01, -5.21287338448645e+00, -8.03952325565291e-01, 4.60298678047147e-01 },
55797a1619fSSatish Balay       {0.00000000000000e+00, -1.85178762883829e+01, -5.21411849862624e+00, -1.04283436528809e+00, 7.49030161063651e-01 }
55897a1619fSSatish Balay     };
5599566063dSJacob Faibussowitsch     PetscCall(TSGLLESchemeCreate(4, 4, 5, 5, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
5603d177a5cSEmil Constantinescu   }
5613d177a5cSEmil Constantinescu   {
5623d177a5cSEmil Constantinescu     /* p=q=5, r=s=6;
5633d177a5cSEmil Constantinescu        irks(1/3,0,[1:6]/6,...
5643d177a5cSEmil Constantinescu           [-0.0489    0.4228   -0.8814    0.9021],...
5653d177a5cSEmil Constantinescu           [-0.3474   -0.6617    0.6294    0.2129
5663d177a5cSEmil Constantinescu             0.0044   -0.4256   -0.1427   -0.8936
5673d177a5cSEmil Constantinescu            -0.8267    0.4821    0.1371   -0.2557
5683d177a5cSEmil Constantinescu            -0.4426   -0.3855   -0.7514    0.3014])
5693d177a5cSEmil Constantinescu     */
57097a1619fSSatish Balay     const PetscScalar c[6]    = {1. / 6, 2. / 6, 3. / 6, 4. / 6, 5. / 6, 1.};
57197a1619fSSatish Balay     const PetscScalar a[6][6] = {
57297a1619fSSatish Balay       {3.33333333333940e-01,  0,                     0,                     0,                     0,                    0                   },
57397a1619fSSatish Balay       {-8.64423857333350e-02, 3.33333333332888e-01,  0,                     0,                     0,                    0                   },
57497a1619fSSatish Balay       {-2.16850174258252e+00, -2.23619072028839e+00, 3.33333333335204e-01,  0,                     0,                    0                   },
57597a1619fSSatish Balay       {-4.73160970138997e+00, -3.89265344629268e+00, -2.76318716520933e-01, 3.33333333335759e-01,  0,                    0                   },
57697a1619fSSatish Balay       {-6.75187540297338e+00, -7.90756533769377e+00, 7.90245051802259e-01,  -4.48352364517632e-01, 3.33333333328483e-01, 0                   },
57797a1619fSSatish Balay       {-4.26488287921548e+00, -1.19320395589302e+01, 3.38924509887755e+00,  -2.23969848002481e+00, 6.62807710124007e-01, 3.33333333335440e-01}
57897a1619fSSatish Balay     };
57997a1619fSSatish Balay     const PetscScalar b[6][6] = {
58097a1619fSSatish Balay       {-4.26488287921548e+00, -1.19320395589302e+01, 3.38924509887755e+00,  -2.23969848002481e+00, 6.62807710124007e-01,  3.33333333335440e-01 },
58197a1619fSSatish Balay       {-8.88178419700125e-16, 4.44089209850063e-16,  -1.54737334057131e-15, -8.88178419700125e-16, 0.00000000000000e+00,  1.00000000000001e+00 },
58297a1619fSSatish Balay       {-2.87780425770651e+01, -1.13520448264971e+01, 2.62002318943161e+01,  2.56943874812797e+01,  -3.06702268304488e+01, 6.68067773510103e+00 },
58397a1619fSSatish Balay       {5.47971245256474e+01,  6.80366875868284e+01,  -6.50952588861999e+01, -8.28643975339097e+01, 8.17416943896414e+01,  -1.17819043489036e+01},
58497a1619fSSatish Balay       {-2.33332114788869e+02, 6.12942539462634e+01,  -4.91850135865944e+01, 1.82716844135480e+02,  -1.29788173979395e+02, 3.09968095651099e+01 },
58597a1619fSSatish Balay       {-1.72049132343751e+02, 8.60194713593999e+00,  7.98154219170200e-01,  1.50371386053218e+02,  -1.18515423962066e+02, 2.50898277784663e+01 }
58697a1619fSSatish Balay     };
58797a1619fSSatish Balay     const PetscScalar u[6][6] = {
58897a1619fSSatish Balay       {1.00000000000000e+00, -1.66666666666870e-01, -4.16666666664335e-02, -3.85802469124815e-03, -2.25051440302250e-04, -9.64506172339142e-06},
58997a1619fSSatish Balay       {1.00000000000000e+00, 8.64423857327162e-02,  -4.11484912671353e-02, -1.11450903217645e-02, -1.47651050487126e-03, -1.34395070766826e-04},
59097a1619fSSatish Balay       {1.00000000000000e+00, 4.57135912953434e+00,  1.06514719719137e+00,  1.33517564218007e-01,  1.11365952968659e-02,  6.12382756769504e-04 },
59197a1619fSSatish Balay       {1.00000000000000e+00, 9.23391519753404e+00,  2.22431212392095e+00,  2.91823807741891e-01,  2.52058456411084e-02,  1.22800542949647e-03 },
59297a1619fSSatish Balay       {1.00000000000000e+00, 1.48175480533865e+01,  3.73439117461835e+00,  5.14648336541804e-01,  4.76430038853402e-02,  2.56798515502156e-03 },
59397a1619fSSatish Balay       {1.00000000000000e+00, 1.50512347758335e+01,  4.10099701165164e+00,  5.66039141003603e-01,  3.91213893800891e-02,  -2.99136269067853e-03}
59497a1619fSSatish Balay     };
59597a1619fSSatish Balay     const PetscScalar v[6][6] = {
59697a1619fSSatish Balay       {1.00000000000000e+00, 1.50512347758335e+01,  4.10099701165164e+00,  5.66039141003603e-01,  3.91213893800891e-02,  -2.99136269067853e-03},
59797a1619fSSatish Balay       {0.00000000000000e+00, -4.88498130835069e-15, -6.43929354282591e-15, -3.55271367880050e-15, -1.22124532708767e-15, -3.12250225675825e-16},
59897a1619fSSatish Balay       {0.00000000000000e+00, 1.22250171233141e+01,  -1.77150760606169e+00, 3.54516769879390e-01,  6.22298845883398e-01,  2.31647447450276e-01 },
59997a1619fSSatish Balay       {0.00000000000000e+00, -4.48339457331040e+01, -3.57363126641880e-01, 5.18750173123425e-01,  6.55727990241799e-02,  1.63175368287079e-01 },
60097a1619fSSatish Balay       {0.00000000000000e+00, 1.37297394708005e+02,  -1.60145272991317e+00, -5.05319555199441e+00, 1.55328940390990e-01,  9.16629423682464e-01 },
60197a1619fSSatish Balay       {0.00000000000000e+00, 1.05703241119022e+02,  -1.16610260983038e+00, -2.99767252773859e+00, -1.13472315553890e-01, 1.09742849254729e+00 }
60297a1619fSSatish Balay     };
6039566063dSJacob Faibussowitsch     PetscCall(TSGLLESchemeCreate(5, 5, 6, 6, c, *a, *b, *u, *v, &gl->schemes[gl->nschemes++]));
6043d177a5cSEmil Constantinescu   }
6053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6063d177a5cSEmil Constantinescu }
6073d177a5cSEmil Constantinescu 
6083d177a5cSEmil Constantinescu /*@C
609bcf0153eSBarry Smith   TSGLLESetType - sets the class of general linear method, `TSGLLE` to use for time-stepping
6103d177a5cSEmil Constantinescu 
611c3339decSBarry Smith   Collective
6123d177a5cSEmil Constantinescu 
6133d177a5cSEmil Constantinescu   Input Parameters:
614bcf0153eSBarry Smith + ts   - the `TS` context
6153d177a5cSEmil Constantinescu - type - a method
6163d177a5cSEmil Constantinescu 
6173d177a5cSEmil Constantinescu   Options Database Key:
6183d177a5cSEmil Constantinescu . -ts_gl_type <type> - sets the method, use -help for a list of available method (e.g. irks)
6193d177a5cSEmil Constantinescu 
620bcf0153eSBarry Smith   Level: intermediate
621bcf0153eSBarry Smith 
6223d177a5cSEmil Constantinescu   Notes:
6233d177a5cSEmil Constantinescu   See "petsc/include/petscts.h" for available methods (for instance)
6243d177a5cSEmil Constantinescu .    TSGLLE_IRKS - Diagonally implicit methods with inherent Runge-Kutta stability (for stiff problems)
6253d177a5cSEmil Constantinescu 
62614d0ab18SJacob Faibussowitsch   Normally, it is best to use the `TSSetFromOptions()` command and then set the `TSGLLE` type
62714d0ab18SJacob Faibussowitsch   from the options database rather than by using this routine.  Using the options database
62814d0ab18SJacob Faibussowitsch   provides the user with maximum flexibility in evaluating the many different solvers.  The
62914d0ab18SJacob Faibussowitsch   `TSGLLESetType()` routine is provided for those situations where it is necessary to set the
63014d0ab18SJacob Faibussowitsch   timestepping solver independently of the command line or options database.  This might be the
63114d0ab18SJacob Faibussowitsch   case, for example, when the choice of solver changes during the execution of the program, and
63214d0ab18SJacob Faibussowitsch   the user's application is taking responsibility for choosing the appropriate method.
6333d177a5cSEmil Constantinescu 
6341cc06b55SBarry Smith .seealso: [](ch_ts), `TS`, `TSGLLEType`, `TSGLLE`
6353d177a5cSEmil Constantinescu @*/
636d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLESetType(TS ts, TSGLLEType type)
637d71ae5a4SJacob Faibussowitsch {
6383d177a5cSEmil Constantinescu   PetscFunctionBegin;
6393d177a5cSEmil Constantinescu   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
6404f572ea9SToby Isaac   PetscAssertPointer(type, 2);
641cac4c232SBarry Smith   PetscTryMethod(ts, "TSGLLESetType_C", (TS, TSGLLEType), (ts, type));
6423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6433d177a5cSEmil Constantinescu }
6443d177a5cSEmil Constantinescu 
6453d177a5cSEmil Constantinescu /*@C
646bcf0153eSBarry Smith   TSGLLESetAcceptType - sets the acceptance test for `TSGLLE`
6473d177a5cSEmil Constantinescu 
648c3339decSBarry Smith   Logically Collective
6493d177a5cSEmil Constantinescu 
6503d177a5cSEmil Constantinescu   Input Parameters:
651bcf0153eSBarry Smith + ts   - the `TS` context
6523d177a5cSEmil Constantinescu - type - the type
6533d177a5cSEmil Constantinescu 
6543d177a5cSEmil Constantinescu   Options Database Key:
6553d177a5cSEmil Constantinescu . -ts_gl_accept_type <type> - sets the method used to determine whether to accept or reject a step
6563d177a5cSEmil Constantinescu 
6573d177a5cSEmil Constantinescu   Level: intermediate
6583d177a5cSEmil Constantinescu 
65914d0ab18SJacob Faibussowitsch   Notes:
66014d0ab18SJacob Faibussowitsch   Time integrators that need to control error must have the option to reject a time step based
66114d0ab18SJacob Faibussowitsch   on local error estimates. This function allows different schemes to be set.
66214d0ab18SJacob Faibussowitsch 
6631cc06b55SBarry Smith .seealso: [](ch_ts), `TS`, `TSGLLE`, `TSGLLEAcceptRegister()`, `TSGLLEAdapt`
6643d177a5cSEmil Constantinescu @*/
665d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLESetAcceptType(TS ts, TSGLLEAcceptType type)
666d71ae5a4SJacob Faibussowitsch {
6673d177a5cSEmil Constantinescu   PetscFunctionBegin;
6683d177a5cSEmil Constantinescu   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
6694f572ea9SToby Isaac   PetscAssertPointer(type, 2);
670cac4c232SBarry Smith   PetscTryMethod(ts, "TSGLLESetAcceptType_C", (TS, TSGLLEAcceptType), (ts, type));
6713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6723d177a5cSEmil Constantinescu }
6733d177a5cSEmil Constantinescu 
6743d177a5cSEmil Constantinescu /*@C
675bcf0153eSBarry Smith   TSGLLEGetAdapt - gets the `TSGLLEAdapt` object from the `TS`
6763d177a5cSEmil Constantinescu 
6773d177a5cSEmil Constantinescu   Not Collective
6783d177a5cSEmil Constantinescu 
6793d177a5cSEmil Constantinescu   Input Parameter:
680bcf0153eSBarry Smith . ts - the `TS` context
6813d177a5cSEmil Constantinescu 
6823d177a5cSEmil Constantinescu   Output Parameter:
683bcf0153eSBarry Smith . adapt - the `TSGLLEAdapt` context
6843d177a5cSEmil Constantinescu 
6853d177a5cSEmil Constantinescu   Level: advanced
6863d177a5cSEmil Constantinescu 
687bcf0153eSBarry Smith   Note:
68814d0ab18SJacob Faibussowitsch   This allows the user set options on the `TSGLLEAdapt` object. Usually it is better to do this
68914d0ab18SJacob Faibussowitsch   using the options database, so this function is rarely needed.
690bcf0153eSBarry Smith 
6911cc06b55SBarry Smith .seealso: [](ch_ts), `TS`, `TSGLLE`, `TSGLLEAdapt`, `TSGLLEAdaptRegister()`
6923d177a5cSEmil Constantinescu @*/
693d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLEGetAdapt(TS ts, TSGLLEAdapt *adapt)
694d71ae5a4SJacob Faibussowitsch {
6953d177a5cSEmil Constantinescu   PetscFunctionBegin;
6963d177a5cSEmil Constantinescu   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
6974f572ea9SToby Isaac   PetscAssertPointer(adapt, 2);
698cac4c232SBarry Smith   PetscUseMethod(ts, "TSGLLEGetAdapt_C", (TS, TSGLLEAdapt *), (ts, adapt));
6993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7003d177a5cSEmil Constantinescu }
7013d177a5cSEmil Constantinescu 
702d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEAccept_Always(TS ts, PetscReal tleft, PetscReal h, const PetscReal enorms[], PetscBool *accept)
703d71ae5a4SJacob Faibussowitsch {
7043d177a5cSEmil Constantinescu   PetscFunctionBegin;
7053d177a5cSEmil Constantinescu   *accept = PETSC_TRUE;
7063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7073d177a5cSEmil Constantinescu }
7083d177a5cSEmil Constantinescu 
709d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEUpdateWRMS(TS ts)
710d71ae5a4SJacob Faibussowitsch {
7113d177a5cSEmil Constantinescu   TS_GLLE     *gl = (TS_GLLE *)ts->data;
7123d177a5cSEmil Constantinescu   PetscScalar *x, *w;
7133d177a5cSEmil Constantinescu   PetscInt     n, i;
7143d177a5cSEmil Constantinescu 
7153d177a5cSEmil Constantinescu   PetscFunctionBegin;
7169566063dSJacob Faibussowitsch   PetscCall(VecGetArray(gl->X[0], &x));
7179566063dSJacob Faibussowitsch   PetscCall(VecGetArray(gl->W, &w));
7189566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(gl->W, &n));
7193d177a5cSEmil Constantinescu   for (i = 0; i < n; i++) w[i] = 1. / (gl->wrms_atol + gl->wrms_rtol * PetscAbsScalar(x[i]));
7209566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(gl->X[0], &x));
7219566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(gl->W, &w));
7223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7233d177a5cSEmil Constantinescu }
7243d177a5cSEmil Constantinescu 
725d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEVecNormWRMS(TS ts, Vec X, PetscReal *nrm)
726d71ae5a4SJacob Faibussowitsch {
7273d177a5cSEmil Constantinescu   TS_GLLE     *gl = (TS_GLLE *)ts->data;
7283d177a5cSEmil Constantinescu   PetscScalar *x, *w;
7293d177a5cSEmil Constantinescu   PetscReal    sum = 0.0, gsum;
7303d177a5cSEmil Constantinescu   PetscInt     n, N, i;
7313d177a5cSEmil Constantinescu 
7323d177a5cSEmil Constantinescu   PetscFunctionBegin;
7339566063dSJacob Faibussowitsch   PetscCall(VecGetArray(X, &x));
7349566063dSJacob Faibussowitsch   PetscCall(VecGetArray(gl->W, &w));
7359566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(gl->W, &n));
7363d177a5cSEmil Constantinescu   for (i = 0; i < n; i++) sum += PetscAbsScalar(PetscSqr(x[i] * w[i]));
7379566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(X, &x));
7389566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(gl->W, &w));
7391c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&sum, &gsum, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)ts)));
7409566063dSJacob Faibussowitsch   PetscCall(VecGetSize(gl->W, &N));
7413d177a5cSEmil Constantinescu   *nrm = PetscSqrtReal(gsum / (1. * N));
7423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7433d177a5cSEmil Constantinescu }
7443d177a5cSEmil Constantinescu 
745d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLESetType_GLLE(TS ts, TSGLLEType type)
746d71ae5a4SJacob Faibussowitsch {
7473d177a5cSEmil Constantinescu   PetscBool same;
7483d177a5cSEmil Constantinescu   TS_GLLE  *gl = (TS_GLLE *)ts->data;
7495f80ce2aSJacob Faibussowitsch   PetscErrorCode (*r)(TS);
7503d177a5cSEmil Constantinescu 
7513d177a5cSEmil Constantinescu   PetscFunctionBegin;
7523d177a5cSEmil Constantinescu   if (gl->type_name[0]) {
7539566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(gl->type_name, type, &same));
7543ba16761SJacob Faibussowitsch     if (same) PetscFunctionReturn(PETSC_SUCCESS);
7559566063dSJacob Faibussowitsch     PetscCall((*gl->Destroy)(gl));
7563d177a5cSEmil Constantinescu   }
7573d177a5cSEmil Constantinescu 
7589566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(TSGLLEList, type, &r));
7596adde796SStefano Zampini   PetscCheck(r, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown TSGLLE type \"%s\" given", type);
7609566063dSJacob Faibussowitsch   PetscCall((*r)(ts));
761c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(gl->type_name, type, sizeof(gl->type_name)));
7623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7633d177a5cSEmil Constantinescu }
7643d177a5cSEmil Constantinescu 
765d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLESetAcceptType_GLLE(TS ts, TSGLLEAcceptType type)
766d71ae5a4SJacob Faibussowitsch {
7673d177a5cSEmil Constantinescu   TSGLLEAcceptFunction r;
7683d177a5cSEmil Constantinescu   TS_GLLE             *gl = (TS_GLLE *)ts->data;
7693d177a5cSEmil Constantinescu 
7703d177a5cSEmil Constantinescu   PetscFunctionBegin;
7719566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(TSGLLEAcceptList, type, &r));
7726adde796SStefano Zampini   PetscCheck(r, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown TSGLLEAccept type \"%s\" given", type);
7733d177a5cSEmil Constantinescu   gl->Accept = r;
7749566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(gl->accept_name, type, sizeof(gl->accept_name)));
7753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7763d177a5cSEmil Constantinescu }
7773d177a5cSEmil Constantinescu 
778d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEGetAdapt_GLLE(TS ts, TSGLLEAdapt *adapt)
779d71ae5a4SJacob Faibussowitsch {
7803d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
7813d177a5cSEmil Constantinescu 
7823d177a5cSEmil Constantinescu   PetscFunctionBegin;
7833d177a5cSEmil Constantinescu   if (!gl->adapt) {
7849566063dSJacob Faibussowitsch     PetscCall(TSGLLEAdaptCreate(PetscObjectComm((PetscObject)ts), &gl->adapt));
7859566063dSJacob Faibussowitsch     PetscCall(PetscObjectIncrementTabLevel((PetscObject)gl->adapt, (PetscObject)ts, 1));
7863d177a5cSEmil Constantinescu   }
7873d177a5cSEmil Constantinescu   *adapt = gl->adapt;
7883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7893d177a5cSEmil Constantinescu }
7903d177a5cSEmil Constantinescu 
791d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEChooseNextScheme(TS ts, PetscReal h, const PetscReal hmnorm[], PetscInt *next_scheme, PetscReal *next_h, PetscBool *finish)
792d71ae5a4SJacob Faibussowitsch {
7933d177a5cSEmil Constantinescu   TS_GLLE  *gl = (TS_GLLE *)ts->data;
7943d177a5cSEmil Constantinescu   PetscInt  i, n, cur_p, cur, next_sc, candidates[64], orders[64];
7953d177a5cSEmil Constantinescu   PetscReal errors[64], costs[64], tleft;
7963d177a5cSEmil Constantinescu 
7973d177a5cSEmil Constantinescu   PetscFunctionBegin;
7983d177a5cSEmil Constantinescu   cur   = -1;
7993d177a5cSEmil Constantinescu   cur_p = gl->schemes[gl->current_scheme]->p;
8003d177a5cSEmil Constantinescu   tleft = ts->max_time - (ts->ptime + ts->time_step);
8013d177a5cSEmil Constantinescu   for (i = 0, n = 0; i < gl->nschemes; i++) {
8023d177a5cSEmil Constantinescu     TSGLLEScheme sc = gl->schemes[i];
8033d177a5cSEmil Constantinescu     if (sc->p < gl->min_order || gl->max_order < sc->p) continue;
8043d177a5cSEmil Constantinescu     if (sc->p == cur_p - 1) errors[n] = PetscAbsScalar(sc->alpha[0]) * hmnorm[0];
8053d177a5cSEmil Constantinescu     else if (sc->p == cur_p) errors[n] = PetscAbsScalar(sc->alpha[0]) * hmnorm[1];
8063d177a5cSEmil Constantinescu     else if (sc->p == cur_p + 1) errors[n] = PetscAbsScalar(sc->alpha[0]) * (hmnorm[2] + hmnorm[3]);
8073d177a5cSEmil Constantinescu     else continue;
8083d177a5cSEmil Constantinescu     candidates[n] = i;
8093d177a5cSEmil Constantinescu     orders[n]     = PetscMin(sc->p, sc->q); /* order of global truncation error */
8103d177a5cSEmil Constantinescu     costs[n]      = sc->s;                  /* estimate the cost as the number of stages */
8113d177a5cSEmil Constantinescu     if (i == gl->current_scheme) cur = n;
8123d177a5cSEmil Constantinescu     n++;
8133d177a5cSEmil Constantinescu   }
814cad9d221SBarry Smith   PetscCheck(cur >= 0 && gl->nschemes > cur, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Current scheme not found in scheme list");
8159566063dSJacob Faibussowitsch   PetscCall(TSGLLEAdaptChoose(gl->adapt, n, orders, errors, costs, cur, h, tleft, &next_sc, next_h, finish));
8163d177a5cSEmil Constantinescu   *next_scheme = candidates[next_sc];
8179371c9d4SSatish 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,
8189371c9d4SSatish Balay                       gl->schemes[*next_scheme]->r, gl->schemes[*next_scheme]->s, (double)*next_h, PetscBools[*finish]));
8193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8203d177a5cSEmil Constantinescu }
8213d177a5cSEmil Constantinescu 
822d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGLLEGetMaxSizes(TS ts, PetscInt *max_r, PetscInt *max_s)
823d71ae5a4SJacob Faibussowitsch {
8243d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
8253d177a5cSEmil Constantinescu 
8263d177a5cSEmil Constantinescu   PetscFunctionBegin;
8273d177a5cSEmil Constantinescu   *max_r = gl->schemes[gl->nschemes - 1]->r;
8283d177a5cSEmil Constantinescu   *max_s = gl->schemes[gl->nschemes - 1]->s;
8293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8303d177a5cSEmil Constantinescu }
8313d177a5cSEmil Constantinescu 
832d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSolve_GLLE(TS ts)
833d71ae5a4SJacob Faibussowitsch {
8343d177a5cSEmil Constantinescu   TS_GLLE            *gl = (TS_GLLE *)ts->data;
8353d177a5cSEmil Constantinescu   PetscInt            i, k, its, lits, max_r, max_s;
8363d177a5cSEmil Constantinescu   PetscBool           final_step, finish;
8373d177a5cSEmil Constantinescu   SNESConvergedReason snesreason;
8383d177a5cSEmil Constantinescu 
8393d177a5cSEmil Constantinescu   PetscFunctionBegin;
8409566063dSJacob Faibussowitsch   PetscCall(TSMonitor(ts, ts->steps, ts->ptime, ts->vec_sol));
8413d177a5cSEmil Constantinescu 
8429566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetMaxSizes(ts, &max_r, &max_s));
8439566063dSJacob Faibussowitsch   PetscCall(VecCopy(ts->vec_sol, gl->X[0]));
84448a46eb9SPierre Jolivet   for (i = 1; i < max_r; i++) PetscCall(VecZeroEntries(gl->X[i]));
8459566063dSJacob Faibussowitsch   PetscCall(TSGLLEUpdateWRMS(ts));
8463d177a5cSEmil Constantinescu 
8473d177a5cSEmil Constantinescu   if (0) {
8483d177a5cSEmil Constantinescu     /* Find consistent initial data for DAE */
8493d177a5cSEmil Constantinescu     gl->stage_time = ts->ptime + ts->time_step;
8503d177a5cSEmil Constantinescu     gl->scoeff     = 1.;
8513d177a5cSEmil Constantinescu     gl->stage      = 0;
8523d177a5cSEmil Constantinescu 
8539566063dSJacob Faibussowitsch     PetscCall(VecCopy(ts->vec_sol, gl->Z));
8549566063dSJacob Faibussowitsch     PetscCall(VecCopy(ts->vec_sol, gl->Y));
8559566063dSJacob Faibussowitsch     PetscCall(SNESSolve(ts->snes, NULL, gl->Y));
8569566063dSJacob Faibussowitsch     PetscCall(SNESGetIterationNumber(ts->snes, &its));
8579566063dSJacob Faibussowitsch     PetscCall(SNESGetLinearSolveIterations(ts->snes, &lits));
8589566063dSJacob Faibussowitsch     PetscCall(SNESGetConvergedReason(ts->snes, &snesreason));
8593d177a5cSEmil Constantinescu 
8609371c9d4SSatish Balay     ts->snes_its += its;
8619371c9d4SSatish Balay     ts->ksp_its += lits;
8623d177a5cSEmil Constantinescu     if (snesreason < 0 && ts->max_snes_failures > 0 && ++ts->num_snes_failures >= ts->max_snes_failures) {
8633d177a5cSEmil Constantinescu       ts->reason = TS_DIVERGED_NONLINEAR_SOLVE;
86463a3b9bcSJacob 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));
8653ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
8663d177a5cSEmil Constantinescu     }
8673d177a5cSEmil Constantinescu   }
8683d177a5cSEmil Constantinescu 
86908401ef6SPierre Jolivet   PetscCheck(gl->current_scheme >= 0, PETSC_COMM_SELF, PETSC_ERR_ORDER, "A starting scheme has not been provided");
8703d177a5cSEmil Constantinescu 
8713d177a5cSEmil Constantinescu   for (k = 0, final_step = PETSC_FALSE, finish = PETSC_FALSE; k < ts->max_steps && !finish; k++) {
8723d177a5cSEmil Constantinescu     PetscInt           j, r, s, next_scheme = 0, rejections;
8733d177a5cSEmil Constantinescu     PetscReal          h, hmnorm[4], enorm[3], next_h;
8743d177a5cSEmil Constantinescu     PetscBool          accept;
8753d177a5cSEmil Constantinescu     const PetscScalar *c, *a, *u;
8763d177a5cSEmil Constantinescu     Vec               *X, *Ydot, Y;
8773d177a5cSEmil Constantinescu     TSGLLEScheme       scheme = gl->schemes[gl->current_scheme];
8783d177a5cSEmil Constantinescu 
8799371c9d4SSatish Balay     r    = scheme->r;
8809371c9d4SSatish Balay     s    = scheme->s;
8813d177a5cSEmil Constantinescu     c    = scheme->c;
8829371c9d4SSatish Balay     a    = scheme->a;
8839371c9d4SSatish Balay     u    = scheme->u;
8843d177a5cSEmil Constantinescu     h    = ts->time_step;
8859371c9d4SSatish Balay     X    = gl->X;
8869371c9d4SSatish Balay     Ydot = gl->Ydot;
8879371c9d4SSatish Balay     Y    = gl->Y;
8883d177a5cSEmil Constantinescu 
8893d177a5cSEmil Constantinescu     if (ts->ptime > ts->max_time) break;
8903d177a5cSEmil Constantinescu 
8913d177a5cSEmil Constantinescu     /*
8923d177a5cSEmil Constantinescu       We only call PreStep at the start of each STEP, not each STAGE.  This is because it is
8933d177a5cSEmil Constantinescu       possible to fail (have to restart a step) after multiple stages.
8943d177a5cSEmil Constantinescu     */
8959566063dSJacob Faibussowitsch     PetscCall(TSPreStep(ts));
8963d177a5cSEmil Constantinescu 
8973d177a5cSEmil Constantinescu     rejections = 0;
8983d177a5cSEmil Constantinescu     while (1) {
8993d177a5cSEmil Constantinescu       for (i = 0; i < s; i++) {
9003d177a5cSEmil Constantinescu         PetscScalar shift;
9013d177a5cSEmil Constantinescu         gl->scoeff     = 1. / PetscRealPart(a[i * s + i]);
9023d177a5cSEmil Constantinescu         shift          = gl->scoeff / ts->time_step;
9033d177a5cSEmil Constantinescu         gl->stage      = i;
9043d177a5cSEmil Constantinescu         gl->stage_time = ts->ptime + PetscRealPart(c[i]) * h;
9053d177a5cSEmil Constantinescu 
9063d177a5cSEmil Constantinescu         /*
9073d177a5cSEmil Constantinescu         * Stage equation: Y = h A Y' + U X
9083d177a5cSEmil Constantinescu         * We assume that A is lower-triangular so that we can solve the stages (Y,Y') sequentially
9093d177a5cSEmil Constantinescu         * Build the affine vector z_i = -[1/(h a_ii)](h sum_j a_ij y'_j + sum_j u_ij x_j)
9103d177a5cSEmil Constantinescu         * Then y'_i = z + 1/(h a_ii) y_i
9113d177a5cSEmil Constantinescu         */
9129566063dSJacob Faibussowitsch         PetscCall(VecZeroEntries(gl->Z));
91348a46eb9SPierre Jolivet         for (j = 0; j < r; j++) PetscCall(VecAXPY(gl->Z, -shift * u[i * r + j], X[j]));
91448a46eb9SPierre Jolivet         for (j = 0; j < i; j++) PetscCall(VecAXPY(gl->Z, -shift * h * a[i * s + j], Ydot[j]));
9153d177a5cSEmil Constantinescu         /* Note: Z is used within function evaluation, Ydot = Z + shift*Y */
9163d177a5cSEmil Constantinescu 
9173d177a5cSEmil Constantinescu         /* Compute an estimate of Y to start Newton iteration */
9183d177a5cSEmil Constantinescu         if (gl->extrapolate) {
9193d177a5cSEmil Constantinescu           if (i == 0) {
9203d177a5cSEmil Constantinescu             /* Linear extrapolation on the first stage */
9219566063dSJacob Faibussowitsch             PetscCall(VecWAXPY(Y, c[i] * h, X[1], X[0]));
9223d177a5cSEmil Constantinescu           } else {
9233d177a5cSEmil Constantinescu             /* Linear extrapolation from the last stage */
9249566063dSJacob Faibussowitsch             PetscCall(VecAXPY(Y, (c[i] - c[i - 1]) * h, Ydot[i - 1]));
9253d177a5cSEmil Constantinescu           }
9263d177a5cSEmil Constantinescu         } else if (i == 0) { /* Directly use solution from the last step, otherwise reuse the last stage (do nothing) */
9279566063dSJacob Faibussowitsch           PetscCall(VecCopy(X[0], Y));
9283d177a5cSEmil Constantinescu         }
9293d177a5cSEmil Constantinescu 
9303d177a5cSEmil Constantinescu         /* Solve this stage (Ydot[i] is computed during function evaluation) */
9319566063dSJacob Faibussowitsch         PetscCall(SNESSolve(ts->snes, NULL, Y));
9329566063dSJacob Faibussowitsch         PetscCall(SNESGetIterationNumber(ts->snes, &its));
9339566063dSJacob Faibussowitsch         PetscCall(SNESGetLinearSolveIterations(ts->snes, &lits));
9349566063dSJacob Faibussowitsch         PetscCall(SNESGetConvergedReason(ts->snes, &snesreason));
9359371c9d4SSatish Balay         ts->snes_its += its;
9369371c9d4SSatish Balay         ts->ksp_its += lits;
9373d177a5cSEmil Constantinescu         if (snesreason < 0 && ts->max_snes_failures > 0 && ++ts->num_snes_failures >= ts->max_snes_failures) {
9383d177a5cSEmil Constantinescu           ts->reason = TS_DIVERGED_NONLINEAR_SOLVE;
93963a3b9bcSJacob 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));
9403ba16761SJacob Faibussowitsch           PetscFunctionReturn(PETSC_SUCCESS);
9413d177a5cSEmil Constantinescu         }
9423d177a5cSEmil Constantinescu       }
9433d177a5cSEmil Constantinescu 
9443d177a5cSEmil Constantinescu       gl->stage_time = ts->ptime + ts->time_step;
9453d177a5cSEmil Constantinescu 
9469566063dSJacob Faibussowitsch       PetscCall((*gl->EstimateHigherMoments)(scheme, h, Ydot, gl->X, gl->himom));
9473d177a5cSEmil Constantinescu       /* hmnorm[i] = h^{p+i}x^{(p+i)} with i=0,1,2; hmnorm[3] = h^{p+2}(dx'/dx) x^{(p+1)} */
94848a46eb9SPierre Jolivet       for (i = 0; i < 3; i++) PetscCall(TSGLLEVecNormWRMS(ts, gl->himom[i], &hmnorm[i + 1]));
9493d177a5cSEmil Constantinescu       enorm[0] = PetscRealPart(scheme->alpha[0]) * hmnorm[1];
9503d177a5cSEmil Constantinescu       enorm[1] = PetscRealPart(scheme->beta[0]) * hmnorm[2];
9513d177a5cSEmil Constantinescu       enorm[2] = PetscRealPart(scheme->gamma[0]) * hmnorm[3];
9529566063dSJacob Faibussowitsch       PetscCall((*gl->Accept)(ts, ts->max_time - gl->stage_time, h, enorm, &accept));
9533d177a5cSEmil Constantinescu       if (accept) goto accepted;
9543d177a5cSEmil Constantinescu       rejections++;
95563a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(ts, "Step %" PetscInt_FMT " (t=%g) not accepted, rejections=%" PetscInt_FMT "\n", k, (double)gl->stage_time, rejections));
9563d177a5cSEmil Constantinescu       if (rejections > gl->max_step_rejections) break;
9573d177a5cSEmil Constantinescu       /*
9583d177a5cSEmil Constantinescu         There are lots of reasons why a step might be rejected, including solvers not converging and other factors that
9593d177a5cSEmil Constantinescu         TSGLLEChooseNextScheme does not support.  Additionally, the error estimates may be very screwed up, so I'm not
9603d177a5cSEmil Constantinescu         convinced that it's safe to just compute a new error estimate using the same interface as the current adaptor
9613d177a5cSEmil Constantinescu         (the adaptor interface probably has to change).  Here we make an arbitrary and naive choice.  This assumes that
9623d177a5cSEmil Constantinescu         steps were written in Nordsieck form.  The "correct" method would be to re-complete the previous time step with
9633d177a5cSEmil Constantinescu         the correct "next" step size.  It is unclear to me whether the present ad-hoc method of rescaling X is stable.
9643d177a5cSEmil Constantinescu       */
9653d177a5cSEmil Constantinescu       h *= 0.5;
96648a46eb9SPierre Jolivet       for (i = 1; i < scheme->r; i++) PetscCall(VecScale(X[i], PetscPowRealInt(0.5, i)));
9673d177a5cSEmil Constantinescu     }
96863a3b9bcSJacob 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);
9693d177a5cSEmil Constantinescu 
9703d177a5cSEmil Constantinescu   accepted:
9713d177a5cSEmil Constantinescu     /* This term is not error, but it *would* be the leading term for a lower order method */
9729566063dSJacob Faibussowitsch     PetscCall(TSGLLEVecNormWRMS(ts, gl->X[scheme->r - 1], &hmnorm[0]));
9733d177a5cSEmil Constantinescu     /* Correct scaling so that these are equivalent to norms of the Nordsieck vectors */
9743d177a5cSEmil Constantinescu 
97563a3b9bcSJacob 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]));
9763d177a5cSEmil Constantinescu     if (!final_step) {
9779566063dSJacob Faibussowitsch       PetscCall(TSGLLEChooseNextScheme(ts, h, hmnorm, &next_scheme, &next_h, &final_step));
9783d177a5cSEmil Constantinescu     } else {
9793d177a5cSEmil Constantinescu       /* Dummy values to complete the current step in a consistent manner */
9803d177a5cSEmil Constantinescu       next_scheme = gl->current_scheme;
9813d177a5cSEmil Constantinescu       next_h      = h;
9823d177a5cSEmil Constantinescu       finish      = PETSC_TRUE;
9833d177a5cSEmil Constantinescu     }
9843d177a5cSEmil Constantinescu 
9853d177a5cSEmil Constantinescu     X        = gl->Xold;
9863d177a5cSEmil Constantinescu     gl->Xold = gl->X;
9873d177a5cSEmil Constantinescu     gl->X    = X;
9889566063dSJacob Faibussowitsch     PetscCall((*gl->CompleteStep)(scheme, h, gl->schemes[next_scheme], next_h, Ydot, gl->Xold, gl->X));
9893d177a5cSEmil Constantinescu 
9909566063dSJacob Faibussowitsch     PetscCall(TSGLLEUpdateWRMS(ts));
9913d177a5cSEmil Constantinescu 
9923d177a5cSEmil Constantinescu     /* Post the solution for the user, we could avoid this copy with a small bit of cleverness */
9939566063dSJacob Faibussowitsch     PetscCall(VecCopy(gl->X[0], ts->vec_sol));
9943d177a5cSEmil Constantinescu     ts->ptime += h;
9953d177a5cSEmil Constantinescu     ts->steps++;
9963d177a5cSEmil Constantinescu 
9979566063dSJacob Faibussowitsch     PetscCall(TSPostEvaluate(ts));
9989566063dSJacob Faibussowitsch     PetscCall(TSPostStep(ts));
9999566063dSJacob Faibussowitsch     PetscCall(TSMonitor(ts, ts->steps, ts->ptime, ts->vec_sol));
10003d177a5cSEmil Constantinescu 
10013d177a5cSEmil Constantinescu     gl->current_scheme = next_scheme;
10023d177a5cSEmil Constantinescu     ts->time_step      = next_h;
10033d177a5cSEmil Constantinescu   }
10043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10053d177a5cSEmil Constantinescu }
10063d177a5cSEmil Constantinescu 
10073d177a5cSEmil Constantinescu /*------------------------------------------------------------*/
10083d177a5cSEmil Constantinescu 
1009d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSReset_GLLE(TS ts)
1010d71ae5a4SJacob Faibussowitsch {
10113d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
10123d177a5cSEmil Constantinescu   PetscInt max_r, max_s;
10133d177a5cSEmil Constantinescu 
10143d177a5cSEmil Constantinescu   PetscFunctionBegin;
10153d177a5cSEmil Constantinescu   if (gl->setupcalled) {
10169566063dSJacob Faibussowitsch     PetscCall(TSGLLEGetMaxSizes(ts, &max_r, &max_s));
10179566063dSJacob Faibussowitsch     PetscCall(VecDestroyVecs(max_r, &gl->Xold));
10189566063dSJacob Faibussowitsch     PetscCall(VecDestroyVecs(max_r, &gl->X));
10199566063dSJacob Faibussowitsch     PetscCall(VecDestroyVecs(max_s, &gl->Ydot));
10209566063dSJacob Faibussowitsch     PetscCall(VecDestroyVecs(3, &gl->himom));
10219566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gl->W));
10229566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gl->Y));
10239566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&gl->Z));
10243d177a5cSEmil Constantinescu   }
10253d177a5cSEmil Constantinescu   gl->setupcalled = PETSC_FALSE;
10263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10273d177a5cSEmil Constantinescu }
10283d177a5cSEmil Constantinescu 
1029d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSDestroy_GLLE(TS ts)
1030d71ae5a4SJacob Faibussowitsch {
10313d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
10323d177a5cSEmil Constantinescu 
10333d177a5cSEmil Constantinescu   PetscFunctionBegin;
10349566063dSJacob Faibussowitsch   PetscCall(TSReset_GLLE(ts));
1035b3a6b972SJed Brown   if (ts->dm) {
10369566063dSJacob Faibussowitsch     PetscCall(DMCoarsenHookRemove(ts->dm, DMCoarsenHook_TSGLLE, DMRestrictHook_TSGLLE, ts));
10379566063dSJacob Faibussowitsch     PetscCall(DMSubDomainHookRemove(ts->dm, DMSubDomainHook_TSGLLE, DMSubDomainRestrictHook_TSGLLE, ts));
1038b3a6b972SJed Brown   }
10399566063dSJacob Faibussowitsch   if (gl->adapt) PetscCall(TSGLLEAdaptDestroy(&gl->adapt));
10409566063dSJacob Faibussowitsch   if (gl->Destroy) PetscCall((*gl->Destroy)(gl));
10419566063dSJacob Faibussowitsch   PetscCall(PetscFree(ts->data));
10429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLESetType_C", NULL));
10439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLESetAcceptType_C", NULL));
10449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSGLLEGetAdapt_C", NULL));
10453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10463d177a5cSEmil Constantinescu }
10473d177a5cSEmil Constantinescu 
10483d177a5cSEmil Constantinescu /*
10493d177a5cSEmil Constantinescu     This defines the nonlinear equation that is to be solved with SNES
10503d177a5cSEmil Constantinescu     g(x) = f(t,x,z+shift*x) = 0
10513d177a5cSEmil Constantinescu */
1052d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTSFormFunction_GLLE(SNES snes, Vec x, Vec f, TS ts)
1053d71ae5a4SJacob Faibussowitsch {
10543d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
10553d177a5cSEmil Constantinescu   Vec      Z, Ydot;
10563d177a5cSEmil Constantinescu   DM       dm, dmsave;
10573d177a5cSEmil Constantinescu 
10583d177a5cSEmil Constantinescu   PetscFunctionBegin;
10599566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
10609566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, dm, &Z, &Ydot));
10619566063dSJacob Faibussowitsch   PetscCall(VecWAXPY(Ydot, gl->scoeff / ts->time_step, x, Z));
10623d177a5cSEmil Constantinescu   dmsave = ts->dm;
10633d177a5cSEmil Constantinescu   ts->dm = dm;
10649566063dSJacob Faibussowitsch   PetscCall(TSComputeIFunction(ts, gl->stage_time, x, Ydot, f, PETSC_FALSE));
10653d177a5cSEmil Constantinescu   ts->dm = dmsave;
10669566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, dm, &Z, &Ydot));
10673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10683d177a5cSEmil Constantinescu }
10693d177a5cSEmil Constantinescu 
1070d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTSFormJacobian_GLLE(SNES snes, Vec x, Mat A, Mat B, TS ts)
1071d71ae5a4SJacob Faibussowitsch {
10723d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
10733d177a5cSEmil Constantinescu   Vec      Z, Ydot;
10743d177a5cSEmil Constantinescu   DM       dm, dmsave;
10753d177a5cSEmil Constantinescu 
10763d177a5cSEmil Constantinescu   PetscFunctionBegin;
10779566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
10789566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetVecs(ts, dm, &Z, &Ydot));
10793d177a5cSEmil Constantinescu   dmsave = ts->dm;
10803d177a5cSEmil Constantinescu   ts->dm = dm;
10813d177a5cSEmil Constantinescu   /* gl->Xdot will have already been computed in SNESTSFormFunction_GLLE */
10829566063dSJacob Faibussowitsch   PetscCall(TSComputeIJacobian(ts, gl->stage_time, x, gl->Ydot[gl->stage], gl->scoeff / ts->time_step, A, B, PETSC_FALSE));
10833d177a5cSEmil Constantinescu   ts->dm = dmsave;
10849566063dSJacob Faibussowitsch   PetscCall(TSGLLERestoreVecs(ts, dm, &Z, &Ydot));
10853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10863d177a5cSEmil Constantinescu }
10873d177a5cSEmil Constantinescu 
1088d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_GLLE(TS ts)
1089d71ae5a4SJacob Faibussowitsch {
10903d177a5cSEmil Constantinescu   TS_GLLE *gl = (TS_GLLE *)ts->data;
10913d177a5cSEmil Constantinescu   PetscInt max_r, max_s;
10923d177a5cSEmil Constantinescu   DM       dm;
10933d177a5cSEmil Constantinescu 
10943d177a5cSEmil Constantinescu   PetscFunctionBegin;
10953d177a5cSEmil Constantinescu   gl->setupcalled = PETSC_TRUE;
10969566063dSJacob Faibussowitsch   PetscCall(TSGLLEGetMaxSizes(ts, &max_r, &max_s));
10979566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vec_sol, max_r, &gl->X));
10989566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vec_sol, max_r, &gl->Xold));
10999566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vec_sol, max_s, &gl->Ydot));
11009566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vec_sol, 3, &gl->himom));
11019566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &gl->W));
11029566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &gl->Y));
11039566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &gl->Z));
11043d177a5cSEmil Constantinescu 
11053d177a5cSEmil Constantinescu   /* Default acceptance tests and adaptivity */
11069566063dSJacob Faibussowitsch   if (!gl->Accept) PetscCall(TSGLLESetAcceptType(ts, TSGLLEACCEPT_ALWAYS));
11079566063dSJacob Faibussowitsch   if (!gl->adapt) PetscCall(TSGLLEGetAdapt(ts, &gl->adapt));
11083d177a5cSEmil Constantinescu 
11093d177a5cSEmil Constantinescu   if (gl->current_scheme < 0) {
11103d177a5cSEmil Constantinescu     PetscInt i;
11113d177a5cSEmil Constantinescu     for (i = 0;; i++) {
11123d177a5cSEmil Constantinescu       if (gl->schemes[i]->p == gl->start_order) break;
111363a3b9bcSJacob Faibussowitsch       PetscCheck(i + 1 != gl->nschemes, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No schemes available with requested start order %" PetscInt_FMT, i);
11143d177a5cSEmil Constantinescu     }
11153d177a5cSEmil Constantinescu     gl->current_scheme = i;
11163d177a5cSEmil Constantinescu   }
11179566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &dm));
11189566063dSJacob Faibussowitsch   PetscCall(DMCoarsenHookAdd(dm, DMCoarsenHook_TSGLLE, DMRestrictHook_TSGLLE, ts));
11199566063dSJacob Faibussowitsch   PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_TSGLLE, DMSubDomainRestrictHook_TSGLLE, ts));
11203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11213d177a5cSEmil Constantinescu }
11223d177a5cSEmil Constantinescu /*------------------------------------------------------------*/
11233d177a5cSEmil Constantinescu 
1124d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetFromOptions_GLLE(TS ts, PetscOptionItems *PetscOptionsObject)
1125d71ae5a4SJacob Faibussowitsch {
11263d177a5cSEmil Constantinescu   TS_GLLE *gl         = (TS_GLLE *)ts->data;
11273d177a5cSEmil Constantinescu   char     tname[256] = TSGLLE_IRKS, completef[256] = "rescale-and-modify";
11283d177a5cSEmil Constantinescu 
11293d177a5cSEmil Constantinescu   PetscFunctionBegin;
1130d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "General Linear ODE solver options");
11313d177a5cSEmil Constantinescu   {
11323d177a5cSEmil Constantinescu     PetscBool flg;
11339566063dSJacob Faibussowitsch     PetscCall(PetscOptionsFList("-ts_gl_type", "Type of GL method", "TSGLLESetType", TSGLLEList, gl->type_name[0] ? gl->type_name : tname, tname, sizeof(tname), &flg));
113448a46eb9SPierre Jolivet     if (flg || !gl->type_name[0]) PetscCall(TSGLLESetType(ts, tname));
11359566063dSJacob 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));
11369566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-ts_gl_max_order", "Maximum order to try", "TSGLLESetMaxOrder", gl->max_order, &gl->max_order, NULL));
11379566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-ts_gl_min_order", "Minimum order to try", "TSGLLESetMinOrder", gl->min_order, &gl->min_order, NULL));
11389566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-ts_gl_start_order", "Initial order to try", "TSGLLESetMinOrder", gl->start_order, &gl->start_order, NULL));
11399566063dSJacob 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));
11409566063dSJacob Faibussowitsch     PetscCall(PetscOptionsBool("-ts_gl_extrapolate", "Extrapolate stage solution from previous solution (sometimes unstable)", "TSGLLESetExtrapolate", gl->extrapolate, &gl->extrapolate, NULL));
11419566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_gl_atol", "Absolute tolerance", "TSGLLESetTolerances", gl->wrms_atol, &gl->wrms_atol, NULL));
11429566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_gl_rtol", "Relative tolerance", "TSGLLESetTolerances", gl->wrms_rtol, &gl->wrms_rtol, NULL));
11439566063dSJacob Faibussowitsch     PetscCall(PetscOptionsString("-ts_gl_complete", "Method to use for completing the step", "none", completef, completef, sizeof(completef), &flg));
11443d177a5cSEmil Constantinescu     if (flg) {
11453d177a5cSEmil Constantinescu       PetscBool match1, match2;
11469566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(completef, "rescale", &match1));
11479566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(completef, "rescale-and-modify", &match2));
11483d177a5cSEmil Constantinescu       if (match1) gl->CompleteStep = TSGLLECompleteStep_Rescale;
11493d177a5cSEmil Constantinescu       else if (match2) gl->CompleteStep = TSGLLECompleteStep_RescaleAndModify;
11506adde796SStefano Zampini       else SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_UNKNOWN_TYPE, "%s", completef);
11513d177a5cSEmil Constantinescu     }
11523d177a5cSEmil Constantinescu     {
11533d177a5cSEmil Constantinescu       char type[256] = TSGLLEACCEPT_ALWAYS;
11549566063dSJacob 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));
115548a46eb9SPierre Jolivet       if (flg || !gl->accept_name[0]) PetscCall(TSGLLESetAcceptType(ts, type));
11563d177a5cSEmil Constantinescu     }
11573d177a5cSEmil Constantinescu     {
11583d177a5cSEmil Constantinescu       TSGLLEAdapt adapt;
11599566063dSJacob Faibussowitsch       PetscCall(TSGLLEGetAdapt(ts, &adapt));
1160dbbe0bcdSBarry Smith       PetscCall(TSGLLEAdaptSetFromOptions(adapt, PetscOptionsObject));
11613d177a5cSEmil Constantinescu     }
11623d177a5cSEmil Constantinescu   }
1163d0609cedSBarry Smith   PetscOptionsHeadEnd();
11643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11653d177a5cSEmil Constantinescu }
11663d177a5cSEmil Constantinescu 
1167d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSView_GLLE(TS ts, PetscViewer viewer)
1168d71ae5a4SJacob Faibussowitsch {
11693d177a5cSEmil Constantinescu   TS_GLLE  *gl = (TS_GLLE *)ts->data;
11703d177a5cSEmil Constantinescu   PetscInt  i;
11713d177a5cSEmil Constantinescu   PetscBool iascii, details;
11723d177a5cSEmil Constantinescu 
11733d177a5cSEmil Constantinescu   PetscFunctionBegin;
11749566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
11753d177a5cSEmil Constantinescu   if (iascii) {
117663a3b9bcSJacob 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));
11779566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Error estimation: %s\n", TSGLLEErrorDirections[gl->error_direction]));
11789566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Extrapolation: %s\n", gl->extrapolate ? "yes" : "no"));
11799566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Acceptance test: %s\n", gl->accept_name[0] ? gl->accept_name : "(not yet set)"));
11809566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
11819566063dSJacob Faibussowitsch     PetscCall(TSGLLEAdaptView(gl->adapt, viewer));
11829566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
11839566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  type: %s\n", gl->type_name[0] ? gl->type_name : "(not yet set)"));
118463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Schemes within family (%" PetscInt_FMT "):\n", gl->nschemes));
11853d177a5cSEmil Constantinescu     details = PETSC_FALSE;
11869566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)ts)->options, ((PetscObject)ts)->prefix, "-ts_gl_view_detailed", &details, NULL));
11879566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
118848a46eb9SPierre Jolivet     for (i = 0; i < gl->nschemes; i++) PetscCall(TSGLLESchemeView(gl->schemes[i], details, viewer));
11891baa6e33SBarry Smith     if (gl->View) PetscCall((*gl->View)(gl, viewer));
11909566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
11913d177a5cSEmil Constantinescu   }
11923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11933d177a5cSEmil Constantinescu }
11943d177a5cSEmil Constantinescu 
11953d177a5cSEmil Constantinescu /*@C
1196bcf0153eSBarry Smith   TSGLLERegister -  adds a `TSGLLE` implementation
11973d177a5cSEmil Constantinescu 
11983d177a5cSEmil Constantinescu   Not Collective
11993d177a5cSEmil Constantinescu 
12003d177a5cSEmil Constantinescu   Input Parameters:
120120f4b53cSBarry Smith + sname    - name of user-defined general linear scheme
120220f4b53cSBarry Smith - function - routine to create method context
12033d177a5cSEmil Constantinescu 
1204bcf0153eSBarry Smith   Level: advanced
1205bcf0153eSBarry Smith 
1206bcf0153eSBarry Smith   Note:
1207bcf0153eSBarry Smith   `TSGLLERegister()` may be called multiple times to add several user-defined families.
12083d177a5cSEmil Constantinescu 
1209b43aa488SJacob Faibussowitsch   Example Usage:
12103d177a5cSEmil Constantinescu .vb
12113d177a5cSEmil Constantinescu   TSGLLERegister("my_scheme", MySchemeCreate);
12123d177a5cSEmil Constantinescu .ve
12133d177a5cSEmil Constantinescu 
12143d177a5cSEmil Constantinescu   Then, your scheme can be chosen with the procedural interface via
12153d177a5cSEmil Constantinescu $ TSGLLESetType(ts, "my_scheme")
12163d177a5cSEmil Constantinescu   or at runtime via the option
12173d177a5cSEmil Constantinescu $ -ts_gl_type my_scheme
12183d177a5cSEmil Constantinescu 
12191cc06b55SBarry Smith .seealso: [](ch_ts), `TSGLLE`, `TSGLLEType`, `TSGLLERegisterAll()`
12203d177a5cSEmil Constantinescu @*/
1221d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLERegister(const char sname[], PetscErrorCode (*function)(TS))
1222d71ae5a4SJacob Faibussowitsch {
12233d177a5cSEmil Constantinescu   PetscFunctionBegin;
12249566063dSJacob Faibussowitsch   PetscCall(TSGLLEInitializePackage());
12259566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&TSGLLEList, sname, function));
12263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12273d177a5cSEmil Constantinescu }
12283d177a5cSEmil Constantinescu 
12293d177a5cSEmil Constantinescu /*@C
1230bcf0153eSBarry Smith   TSGLLEAcceptRegister -  adds a `TSGLLE` acceptance scheme
12313d177a5cSEmil Constantinescu 
12323d177a5cSEmil Constantinescu   Not Collective
12333d177a5cSEmil Constantinescu 
12343d177a5cSEmil Constantinescu   Input Parameters:
123520f4b53cSBarry Smith + sname    - name of user-defined acceptance scheme
123620f4b53cSBarry Smith - function - routine to create method context
12373d177a5cSEmil Constantinescu 
1238bcf0153eSBarry Smith   Level: advanced
1239bcf0153eSBarry Smith 
1240bcf0153eSBarry Smith   Note:
1241bcf0153eSBarry Smith   `TSGLLEAcceptRegister()` may be called multiple times to add several user-defined families.
12423d177a5cSEmil Constantinescu 
1243b43aa488SJacob Faibussowitsch   Example Usage:
12443d177a5cSEmil Constantinescu .vb
12453d177a5cSEmil Constantinescu   TSGLLEAcceptRegister("my_scheme", MySchemeCreate);
12463d177a5cSEmil Constantinescu .ve
12473d177a5cSEmil Constantinescu 
12483d177a5cSEmil Constantinescu   Then, your scheme can be chosen with the procedural interface via
12493d177a5cSEmil Constantinescu $ TSGLLESetAcceptType(ts, "my_scheme")
12503d177a5cSEmil Constantinescu   or at runtime via the option
12513d177a5cSEmil Constantinescu $ -ts_gl_accept_type my_scheme
12523d177a5cSEmil Constantinescu 
12531cc06b55SBarry Smith .seealso: [](ch_ts), `TSGLLE`, `TSGLLEType`, `TSGLLERegisterAll()`, `TSGLLEAcceptFunction`
12543d177a5cSEmil Constantinescu @*/
1255d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLEAcceptRegister(const char sname[], TSGLLEAcceptFunction function)
1256d71ae5a4SJacob Faibussowitsch {
12573d177a5cSEmil Constantinescu   PetscFunctionBegin;
12589566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&TSGLLEAcceptList, sname, function));
12593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12603d177a5cSEmil Constantinescu }
12613d177a5cSEmil Constantinescu 
12623d177a5cSEmil Constantinescu /*@C
1263bcf0153eSBarry Smith   TSGLLERegisterAll - Registers all of the general linear methods in `TSGLLE`
12643d177a5cSEmil Constantinescu 
12653d177a5cSEmil Constantinescu   Not Collective
12663d177a5cSEmil Constantinescu 
12673d177a5cSEmil Constantinescu   Level: advanced
12683d177a5cSEmil Constantinescu 
12691cc06b55SBarry Smith .seealso: [](ch_ts), `TSGLLE`, `TSGLLERegisterDestroy()`
12703d177a5cSEmil Constantinescu @*/
1271d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLERegisterAll(void)
1272d71ae5a4SJacob Faibussowitsch {
12733d177a5cSEmil Constantinescu   PetscFunctionBegin;
12743ba16761SJacob Faibussowitsch   if (TSGLLERegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
12753d177a5cSEmil Constantinescu   TSGLLERegisterAllCalled = PETSC_TRUE;
12763d177a5cSEmil Constantinescu 
12779566063dSJacob Faibussowitsch   PetscCall(TSGLLERegister(TSGLLE_IRKS, TSGLLECreate_IRKS));
12789566063dSJacob Faibussowitsch   PetscCall(TSGLLEAcceptRegister(TSGLLEACCEPT_ALWAYS, TSGLLEAccept_Always));
12793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12803d177a5cSEmil Constantinescu }
12813d177a5cSEmil Constantinescu 
12823d177a5cSEmil Constantinescu /*@C
1283bcf0153eSBarry Smith   TSGLLEInitializePackage - This function initializes everything in the `TSGLLE` package. It is called
1284bcf0153eSBarry Smith   from `TSInitializePackage()`.
12853d177a5cSEmil Constantinescu 
12863d177a5cSEmil Constantinescu   Level: developer
12873d177a5cSEmil Constantinescu 
12881cc06b55SBarry Smith .seealso: [](ch_ts), `PetscInitialize()`, `TSInitializePackage()`, `TSGLLEFinalizePackage()`
12893d177a5cSEmil Constantinescu @*/
1290d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLEInitializePackage(void)
1291d71ae5a4SJacob Faibussowitsch {
12923d177a5cSEmil Constantinescu   PetscFunctionBegin;
12933ba16761SJacob Faibussowitsch   if (TSGLLEPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS);
12943d177a5cSEmil Constantinescu   TSGLLEPackageInitialized = PETSC_TRUE;
12959566063dSJacob Faibussowitsch   PetscCall(TSGLLERegisterAll());
12969566063dSJacob Faibussowitsch   PetscCall(PetscRegisterFinalize(TSGLLEFinalizePackage));
12973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12983d177a5cSEmil Constantinescu }
12993d177a5cSEmil Constantinescu 
13003d177a5cSEmil Constantinescu /*@C
1301bcf0153eSBarry Smith   TSGLLEFinalizePackage - This function destroys everything in the `TSGLLE` package. It is
1302bcf0153eSBarry Smith   called from `PetscFinalize()`.
13033d177a5cSEmil Constantinescu 
13043d177a5cSEmil Constantinescu   Level: developer
13053d177a5cSEmil Constantinescu 
13061cc06b55SBarry Smith .seealso: [](ch_ts), `PetscFinalize()`, `TSGLLEInitializePackage()`, `TSInitializePackage()`
13073d177a5cSEmil Constantinescu @*/
1308d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGLLEFinalizePackage(void)
1309d71ae5a4SJacob Faibussowitsch {
13103d177a5cSEmil Constantinescu   PetscFunctionBegin;
13119566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&TSGLLEList));
13129566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&TSGLLEAcceptList));
13133d177a5cSEmil Constantinescu   TSGLLEPackageInitialized = PETSC_FALSE;
13143d177a5cSEmil Constantinescu   TSGLLERegisterAllCalled  = PETSC_FALSE;
13153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13163d177a5cSEmil Constantinescu }
13173d177a5cSEmil Constantinescu 
13183d177a5cSEmil Constantinescu /* ------------------------------------------------------------ */
13193d177a5cSEmil Constantinescu /*MC
1320*1d27aa22SBarry Smith   TSGLLE - DAE solver using implicit General Linear methods {cite}`butcher_2007` {cite}`butcher2016numerical`
13213d177a5cSEmil Constantinescu 
1322bcf0153eSBarry Smith   Options Database Keys:
13233d177a5cSEmil Constantinescu +  -ts_gl_type <type> - the class of general linear method (irks)
13243d177a5cSEmil Constantinescu .  -ts_gl_rtol <tol>  - relative error
13253d177a5cSEmil Constantinescu .  -ts_gl_atol <tol>  - absolute error
13263d177a5cSEmil Constantinescu .  -ts_gl_min_order <p> - minimum order method to consider (default=1)
13273d177a5cSEmil Constantinescu .  -ts_gl_max_order <p> - maximum order method to consider (default=3)
13283d177a5cSEmil Constantinescu .  -ts_gl_start_order <p> - order of starting method (default=1)
13293d177a5cSEmil Constantinescu .  -ts_gl_complete <method> - method to use for completing the step (rescale-and-modify or rescale)
13303d177a5cSEmil Constantinescu -  -ts_adapt_type <method> - adaptive controller to use (none step both)
13313d177a5cSEmil Constantinescu 
1332bcf0153eSBarry Smith   Level: beginner
1333bcf0153eSBarry Smith 
13343d177a5cSEmil Constantinescu   Notes:
133514d0ab18SJacob Faibussowitsch   These methods contain Runge-Kutta and multistep schemes as special cases. These special cases
133614d0ab18SJacob Faibussowitsch   have some fundamental limitations. For example, diagonally implicit Runge-Kutta cannot have
133714d0ab18SJacob Faibussowitsch   stage order greater than 1 which limits their applicability to very stiff systems.
133814d0ab18SJacob Faibussowitsch   Meanwhile, multistep methods cannot be A-stable for order greater than 2 and BDF are not
133914d0ab18SJacob Faibussowitsch   0-stable for order greater than 6. GL methods can be A- and L-stable with arbitrarily high
134014d0ab18SJacob Faibussowitsch   stage order and reliable error estimates for both 1 and 2 orders higher to facilitate
134114d0ab18SJacob Faibussowitsch   adaptive step sizes and adaptive order schemes. All this is possible while preserving a
134214d0ab18SJacob Faibussowitsch   singly diagonally implicit structure.
134314d0ab18SJacob Faibussowitsch 
13443d177a5cSEmil Constantinescu   This integrator can be applied to DAE.
13453d177a5cSEmil Constantinescu 
134614d0ab18SJacob Faibussowitsch   Diagonally implicit general linear (DIGL) methods are a generalization of diagonally implicit
134714d0ab18SJacob Faibussowitsch   Runge-Kutta (DIRK). They are represented by the tableau
13483d177a5cSEmil Constantinescu 
13493d177a5cSEmil Constantinescu .vb
13503d177a5cSEmil Constantinescu   A  |  U
13513d177a5cSEmil Constantinescu   -------
13523d177a5cSEmil Constantinescu   B  |  V
13533d177a5cSEmil Constantinescu .ve
13543d177a5cSEmil Constantinescu 
1355562efe2eSBarry Smith   combined with a vector c of abscissa. "Diagonally implicit" means that $A$ is lower
135614d0ab18SJacob Faibussowitsch   triangular. A step of the general method reads
13573d177a5cSEmil Constantinescu 
135814d0ab18SJacob Faibussowitsch   $$
1359562efe2eSBarry Smith   \begin{align*}
1360562efe2eSBarry Smith   [ Y ] = [A  U] [  Y'   ] \\
13613d177a5cSEmil Constantinescu   [X^k] = [B  V] [X^{k-1}]
1362562efe2eSBarry Smith   \end{align*}
136314d0ab18SJacob Faibussowitsch   $$
13643d177a5cSEmil Constantinescu 
1365562efe2eSBarry Smith   where Y is the multivector of stage values, $Y'$ is the multivector of stage derivatives, $X^k$
1366562efe2eSBarry Smith   is the Nordsieck vector of the solution at step $k$. The Nordsieck vector consists of the first
1367562efe2eSBarry Smith   $r$ moments of the solution, given by
13683d177a5cSEmil Constantinescu 
136914d0ab18SJacob Faibussowitsch   $$
13703d177a5cSEmil Constantinescu   X = [x_0,x_1,...,x_{r-1}] = [x, h x', h^2 x'', ..., h^{r-1} x^{(r-1)} ]
137114d0ab18SJacob Faibussowitsch   $$
13723d177a5cSEmil Constantinescu 
1373562efe2eSBarry Smith   If $A$ is lower triangular, we can solve the stages $(Y, Y')$ sequentially
13743d177a5cSEmil Constantinescu 
137514d0ab18SJacob Faibussowitsch   $$
1376562efe2eSBarry Smith   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}
137714d0ab18SJacob Faibussowitsch   $$
13783d177a5cSEmil Constantinescu 
13793d177a5cSEmil Constantinescu   and then construct the pieces to carry to the next step
13803d177a5cSEmil Constantinescu 
138114d0ab18SJacob Faibussowitsch   $$
1382562efe2eSBarry Smith   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}
138314d0ab18SJacob Faibussowitsch   $$
13843d177a5cSEmil Constantinescu 
138514d0ab18SJacob Faibussowitsch   Note that when the equations are cast in implicit form, we are using the stage equation to
1386562efe2eSBarry Smith   define $y'_i$ in terms of $y_i$ and known stuff ($y_j$ for $j<i$ and $x_j$ for all $j$).
13873d177a5cSEmil Constantinescu 
13883d177a5cSEmil Constantinescu   Error estimation
13893d177a5cSEmil Constantinescu 
139014d0ab18SJacob Faibussowitsch   At present, the most attractive GL methods for stiff problems are singly diagonally implicit
1391562efe2eSBarry Smith   schemes which posses Inherent Runge-Kutta Stability (`TSIRKS`).  These methods have $r=s$, the
139214d0ab18SJacob Faibussowitsch   number of items passed between steps is equal to the number of stages.  The order and
139314d0ab18SJacob Faibussowitsch   stage-order are one less than the number of stages.  We use the error estimates in the 2007
139414d0ab18SJacob Faibussowitsch   paper which provide the following estimates
13953d177a5cSEmil Constantinescu 
139614d0ab18SJacob Faibussowitsch   $$
1397562efe2eSBarry Smith   \begin{align*}
1398562efe2eSBarry Smith   h^{p+1} X^{(p+1)}          = \phi_0^T Y' + [0 \psi_0^T] Xold \\
1399562efe2eSBarry Smith   h^{p+2} X^{(p+2)}          = \phi_1^T Y' + [0 \psi_1^T] Xold \\
1400562efe2eSBarry Smith   h^{p+2} (dx'/dx) X^{(p+1)} = \phi_2^T Y' + [0 \psi_2^T] Xold
1401562efe2eSBarry Smith   \end{align*}
140214d0ab18SJacob Faibussowitsch   $$
14033d177a5cSEmil Constantinescu 
1404562efe2eSBarry Smith   These estimates are accurate to $ O(h^{p+3})$.
14053d177a5cSEmil Constantinescu 
14063d177a5cSEmil Constantinescu   Changing the step size
14073d177a5cSEmil Constantinescu 
1408*1d27aa22SBarry Smith   Uses the generalized "rescale and modify" scheme, see equation (4.5) of {cite}`butcher_2007`.
14093d177a5cSEmil Constantinescu 
14101cc06b55SBarry 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