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