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