1 #include <petsc/private/snesimpl.h> /*I "petscsnes.h" I*/ 2 3 static SNESMSType SNESMSDefault = SNESMSM62; 4 static PetscBool SNESMSRegisterAllCalled; 5 static PetscBool SNESMSPackageInitialized; 6 7 typedef struct _SNESMSTableau *SNESMSTableau; 8 struct _SNESMSTableau { 9 char *name; 10 PetscInt nstages; /* Number of stages */ 11 PetscInt nregisters; /* Number of registers */ 12 PetscReal stability; /* Scaled stability region */ 13 PetscReal *gamma; /* Coefficients of 3S* method */ 14 PetscReal *delta; /* Coefficients of 3S* method */ 15 PetscReal *betasub; /* Subdiagonal of beta in Shu-Osher form */ 16 }; 17 18 typedef struct _SNESMSTableauLink *SNESMSTableauLink; 19 struct _SNESMSTableauLink { 20 struct _SNESMSTableau tab; 21 SNESMSTableauLink next; 22 }; 23 static SNESMSTableauLink SNESMSTableauList; 24 25 typedef struct { 26 SNESMSTableau tableau; /* Tableau in low-storage form */ 27 PetscReal damping; /* Damping parameter, like length of (pseudo) time step */ 28 PetscBool norms; /* Compute norms, usually only for monitoring purposes */ 29 } SNES_MS; 30 31 /*@C 32 SNESMSRegisterAll - Registers all of the multi-stage methods in `SNESMS` 33 34 Logically Collective 35 36 Level: developer 37 38 .seealso: `SNES`, `SNESMS`, `SNESMSRegisterDestroy()` 39 @*/ 40 PetscErrorCode SNESMSRegisterAll(void) 41 { 42 PetscFunctionBegin; 43 if (SNESMSRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS); 44 SNESMSRegisterAllCalled = PETSC_TRUE; 45 46 { 47 PetscReal alpha[1] = {1.0}; 48 PetscCall(SNESMSRegister(SNESMSEULER, 1, 1, 1.0, NULL, NULL, alpha)); 49 } 50 51 { 52 PetscReal gamma[3][6] = { 53 {0.0000000000000000E+00, -7.0304722367110606E-01, -1.9836719667506464E-01, -1.6023843981863788E+00, 9.4483822882855284E-02, -1.4204296130641869E-01}, 54 {1.0000000000000000E+00, 1.1111025767083920E+00, 5.6150921583923230E-01, 7.4151723494934041E-01, 3.1714538168600587E-01, 4.6479276238548706E-01 }, 55 {0.0000000000000000E+00, 0.0000000000000000E+00, 0.0000000000000000E+00, 6.7968174970583317E-01, -4.1755042846051737E-03, -1.9115668129923846E-01} 56 }; 57 PetscReal delta[6] = {1.0000000000000000E+00, 5.3275427433201750E-01, 6.0143544663985238E-01, 4.5874077053842177E-01, 2.7544386906104651E-01, 0.0000000000000000E+00}; 58 PetscReal betasub[6] = {8.4753115429481929E-01, 7.4018896368655618E-01, 6.5963574086583309E-03, 4.6747795645517759E-01, 1.3314545813643919E-01, 5.3260800028018784E-01}; 59 PetscCall(SNESMSRegister(SNESMSM62, 6, 3, 1.0, &gamma[0][0], delta, betasub)); 60 } 61 62 { /* Jameson (1983) */ 63 PetscReal alpha[4] = {0.25, 0.5, 0.55, 1.0}; 64 PetscCall(SNESMSRegister(SNESMSJAMESON83, 4, 1, 1.0, NULL, NULL, alpha)); 65 } 66 67 { /* Van Leer, Tai, and Powell (1989) 1 stage, order 1 */ 68 PetscReal alpha[1] = {1.0}; 69 PetscCall(SNESMSRegister(SNESMSVLTP11, 1, 1, 0.5, NULL, NULL, alpha)); 70 } 71 { /* Van Leer, Tai, and Powell (1989) 2 stage, order 1 */ 72 PetscReal alpha[2] = {0.3333, 1.0}; 73 PetscCall(SNESMSRegister(SNESMSVLTP21, 2, 1, 1.0, NULL, NULL, alpha)); 74 } 75 { /* Van Leer, Tai, and Powell (1989) 3 stage, order 1 */ 76 PetscReal alpha[3] = {0.1481, 0.4000, 1.0}; 77 PetscCall(SNESMSRegister(SNESMSVLTP31, 3, 1, 1.5, NULL, NULL, alpha)); 78 } 79 { /* Van Leer, Tai, and Powell (1989) 4 stage, order 1 */ 80 PetscReal alpha[4] = {0.0833, 0.2069, 0.4265, 1.0}; 81 PetscCall(SNESMSRegister(SNESMSVLTP41, 4, 1, 2.0, NULL, NULL, alpha)); 82 } 83 { /* Van Leer, Tai, and Powell (1989) 5 stage, order 1 */ 84 PetscReal alpha[5] = {0.0533, 0.1263, 0.2375, 0.4414, 1.0}; 85 PetscCall(SNESMSRegister(SNESMSVLTP51, 5, 1, 2.5, NULL, NULL, alpha)); 86 } 87 { /* Van Leer, Tai, and Powell (1989) 6 stage, order 1 */ 88 PetscReal alpha[6] = {0.0370, 0.0851, 0.1521, 0.2562, 0.4512, 1.0}; 89 PetscCall(SNESMSRegister(SNESMSVLTP61, 6, 1, 3.0, NULL, NULL, alpha)); 90 } 91 PetscFunctionReturn(PETSC_SUCCESS); 92 } 93 94 /*@C 95 SNESMSRegisterDestroy - Frees the list of schemes that were registered by `SNESMSRegister()`. 96 97 Not Collective 98 99 Level: developer 100 101 .seealso: `SNESMSRegister()`, `SNESMSRegisterAll()` 102 @*/ 103 PetscErrorCode SNESMSRegisterDestroy(void) 104 { 105 SNESMSTableauLink link; 106 107 PetscFunctionBegin; 108 while ((link = SNESMSTableauList)) { 109 SNESMSTableau t = &link->tab; 110 SNESMSTableauList = link->next; 111 112 PetscCall(PetscFree(t->name)); 113 PetscCall(PetscFree(t->gamma)); 114 PetscCall(PetscFree(t->delta)); 115 PetscCall(PetscFree(t->betasub)); 116 PetscCall(PetscFree(link)); 117 } 118 SNESMSRegisterAllCalled = PETSC_FALSE; 119 PetscFunctionReturn(PETSC_SUCCESS); 120 } 121 122 /*@C 123 SNESMSInitializePackage - This function initializes everything in the `SNESMS` package. It is called 124 from `SNESInitializePackage()`. 125 126 Level: developer 127 128 .seealso: `PetscInitialize()` 129 @*/ 130 PetscErrorCode SNESMSInitializePackage(void) 131 { 132 PetscFunctionBegin; 133 if (SNESMSPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS); 134 SNESMSPackageInitialized = PETSC_TRUE; 135 136 PetscCall(SNESMSRegisterAll()); 137 PetscCall(PetscRegisterFinalize(SNESMSFinalizePackage)); 138 PetscFunctionReturn(PETSC_SUCCESS); 139 } 140 141 /*@C 142 SNESMSFinalizePackage - This function destroys everything in the `SNESMS` package. It is 143 called from `PetscFinalize()`. 144 145 Level: developer 146 147 .seealso: `PetscFinalize()` 148 @*/ 149 PetscErrorCode SNESMSFinalizePackage(void) 150 { 151 PetscFunctionBegin; 152 SNESMSPackageInitialized = PETSC_FALSE; 153 154 PetscCall(SNESMSRegisterDestroy()); 155 PetscFunctionReturn(PETSC_SUCCESS); 156 } 157 158 /*@C 159 SNESMSRegister - register a multistage scheme for `SNESMS` 160 161 Logically Collective 162 163 Input Parameters: 164 + name - identifier for method 165 . nstages - number of stages 166 . nregisters - number of registers used by low-storage implementation 167 . stability - scaled stability region 168 . gamma - coefficients, see Ketcheson's paper 169 . delta - coefficients, see Ketcheson's paper 170 - betasub - subdiagonal of Shu-Osher form 171 172 Level: advanced 173 174 Notes: 175 The notation is described in Ketcheson (2010) Runge-Kutta methods with minimum storage implementations. 176 177 Many multistage schemes are of the form 178 $ X_0 = X^{(n)} 179 $ X_k = X_0 + \alpha_k * F(X_{k-1}), k = 1,\ldots,s 180 $ X^{(n+1)} = X_s 181 These methods can be registered with 182 .vb 183 SNESMSRegister("name",s,1,stability,NULL,NULL,alpha); 184 .ve 185 186 .seealso: `SNESMS` 187 @*/ 188 PetscErrorCode SNESMSRegister(SNESMSType name, PetscInt nstages, PetscInt nregisters, PetscReal stability, const PetscReal gamma[], const PetscReal delta[], const PetscReal betasub[]) 189 { 190 SNESMSTableauLink link; 191 SNESMSTableau t; 192 193 PetscFunctionBegin; 194 PetscValidCharPointer(name, 1); 195 PetscCheck(nstages >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have at least one stage"); 196 if (gamma || delta) { 197 PetscCheck(nregisters == 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only support for methods written in 3-register form"); 198 PetscValidRealPointer(gamma, 5); 199 PetscValidRealPointer(delta, 6); 200 } else { 201 PetscCheck(nregisters == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only support for methods written in 1-register form"); 202 } 203 PetscValidRealPointer(betasub, 7); 204 205 PetscCall(SNESMSInitializePackage()); 206 PetscCall(PetscNew(&link)); 207 t = &link->tab; 208 PetscCall(PetscStrallocpy(name, &t->name)); 209 t->nstages = nstages; 210 t->nregisters = nregisters; 211 t->stability = stability; 212 213 if (gamma && delta) { 214 PetscCall(PetscMalloc1(nstages * nregisters, &t->gamma)); 215 PetscCall(PetscMalloc1(nstages, &t->delta)); 216 PetscCall(PetscArraycpy(t->gamma, gamma, nstages * nregisters)); 217 PetscCall(PetscArraycpy(t->delta, delta, nstages)); 218 } 219 PetscCall(PetscMalloc1(nstages, &t->betasub)); 220 PetscCall(PetscArraycpy(t->betasub, betasub, nstages)); 221 222 link->next = SNESMSTableauList; 223 SNESMSTableauList = link; 224 PetscFunctionReturn(PETSC_SUCCESS); 225 } 226 227 /* 228 X - initial state, updated in-place. 229 F - residual, computed at the initial X on input 230 */ 231 static PetscErrorCode SNESMSStep_3Sstar(SNES snes, Vec X, Vec F) 232 { 233 SNES_MS *ms = (SNES_MS *)snes->data; 234 SNESMSTableau t = ms->tableau; 235 const PetscInt nstages = t->nstages; 236 const PetscReal *gamma = t->gamma, *delta = t->delta, *betasub = t->betasub; 237 Vec S1 = X, S2 = snes->work[1], S3 = snes->work[2], Y = snes->work[0], S1copy = snes->work[3]; 238 239 PetscFunctionBegin; 240 PetscCall(VecZeroEntries(S2)); 241 PetscCall(VecCopy(X, S3)); 242 for (PetscInt i = 0; i < nstages; i++) { 243 Vec Ss[] = {S1copy, S2, S3, Y}; 244 const PetscScalar scoeff[] = {gamma[0 * nstages + i] - 1, gamma[1 * nstages + i], gamma[2 * nstages + i], -betasub[i] * ms->damping}; 245 246 PetscCall(VecAXPY(S2, delta[i], S1)); 247 if (i > 0) PetscCall(SNESComputeFunction(snes, S1, F)); 248 PetscCall(KSPSolve(snes->ksp, F, Y)); 249 PetscCall(VecCopy(S1, S1copy)); 250 PetscCall(VecMAXPY(S1, 4, scoeff, Ss)); 251 } 252 PetscFunctionReturn(PETSC_SUCCESS); 253 } 254 255 /* 256 X - initial state, updated in-place. 257 F - residual, computed at the initial X on input 258 */ 259 static PetscErrorCode SNESMSStep_Basic(SNES snes, Vec X, Vec F) 260 { 261 SNES_MS *ms = (SNES_MS *)snes->data; 262 SNESMSTableau tab = ms->tableau; 263 const PetscReal *alpha = tab->betasub, h = ms->damping; 264 PetscInt i, nstages = tab->nstages; 265 Vec X0 = snes->work[0]; 266 267 PetscFunctionBegin; 268 PetscCall(VecCopy(X, X0)); 269 for (i = 0; i < nstages; i++) { 270 if (i > 0) PetscCall(SNESComputeFunction(snes, X, F)); 271 PetscCall(KSPSolve(snes->ksp, F, X)); 272 PetscCall(VecAYPX(X, -alpha[i] * h, X0)); 273 } 274 PetscFunctionReturn(PETSC_SUCCESS); 275 } 276 277 static PetscErrorCode SNESMSStep_Step(SNES snes, Vec X, Vec F) 278 { 279 SNES_MS *ms = (SNES_MS *)snes->data; 280 SNESMSTableau tab = ms->tableau; 281 282 PetscFunctionBegin; 283 if (tab->gamma && tab->delta) { 284 PetscCall(SNESMSStep_3Sstar(snes, X, F)); 285 } else { 286 PetscCall(SNESMSStep_Basic(snes, X, F)); 287 } 288 PetscFunctionReturn(PETSC_SUCCESS); 289 } 290 291 static PetscErrorCode SNESMSStep_Norms(SNES snes, PetscInt iter, Vec F) 292 { 293 SNES_MS *ms = (SNES_MS *)snes->data; 294 PetscReal fnorm; 295 296 PetscFunctionBegin; 297 if (ms->norms || (iter == snes->max_its && snes->normschedule >= SNES_NORM_FINAL_ONLY)) { 298 PetscCall(VecNorm(F, NORM_2, &fnorm)); /* fnorm <- ||F|| */ 299 SNESCheckFunctionNorm(snes, fnorm); 300 /* Monitor convergence */ 301 PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 302 snes->iter = iter; 303 snes->norm = fnorm; 304 PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 305 PetscCall(SNESLogConvergenceHistory(snes, snes->norm, 0)); 306 /* Test for convergence */ 307 PetscCall(SNESConverged(snes, snes->iter, 0.0, 0.0, fnorm)); 308 PetscCall(SNESMonitor(snes, snes->iter, snes->norm)); 309 } else if (iter > 0) { 310 PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 311 snes->iter = iter; 312 PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 313 } 314 PetscFunctionReturn(PETSC_SUCCESS); 315 } 316 317 static PetscErrorCode SNESSolve_MS(SNES snes) 318 { 319 SNES_MS *ms = (SNES_MS *)snes->data; 320 Vec X = snes->vec_sol, F = snes->vec_func; 321 PetscInt i; 322 323 PetscFunctionBegin; 324 PetscCheck(!snes->xl && !snes->xu && !snes->ops->computevariablebounds, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name); 325 PetscCall(PetscCitationsRegister(SNESCitation, &SNEScite)); 326 327 snes->reason = SNES_CONVERGED_ITERATING; 328 PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 329 snes->iter = 0; 330 snes->norm = 0; 331 PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 332 333 if (!snes->vec_func_init_set) { 334 PetscCall(SNESComputeFunction(snes, X, F)); 335 } else snes->vec_func_init_set = PETSC_FALSE; 336 337 PetscCall(SNESMSStep_Norms(snes, 0, F)); 338 if (snes->reason) PetscFunctionReturn(PETSC_SUCCESS); 339 340 for (i = 0; i < snes->max_its; i++) { 341 /* Call general purpose update function */ 342 PetscTryTypeMethod(snes, update, snes->iter); 343 344 if (i == 0 && snes->jacobian) { 345 /* This method does not require a Jacobian, but it is usually preconditioned by PBJacobi */ 346 PetscCall(SNESComputeJacobian(snes, snes->vec_sol, snes->jacobian, snes->jacobian_pre)); 347 SNESCheckJacobianDomainerror(snes); 348 PetscCall(KSPSetOperators(snes->ksp, snes->jacobian, snes->jacobian_pre)); 349 } 350 351 PetscCall(SNESMSStep_Step(snes, X, F)); 352 353 if (i < snes->max_its - 1 || ms->norms) PetscCall(SNESComputeFunction(snes, X, F)); 354 355 PetscCall(SNESMSStep_Norms(snes, i + 1, F)); 356 if (snes->reason) PetscFunctionReturn(PETSC_SUCCESS); 357 } 358 PetscFunctionReturn(PETSC_SUCCESS); 359 } 360 361 static PetscErrorCode SNESSetUp_MS(SNES snes) 362 { 363 SNES_MS *ms = (SNES_MS *)snes->data; 364 SNESMSTableau tab = ms->tableau; 365 PetscInt nwork = tab->nregisters + 1; // +1 because VecMAXPY() in SNESMSStep_3Sstar() 366 // needs an extra work vec 367 368 PetscFunctionBegin; 369 PetscCall(SNESSetWorkVecs(snes, nwork)); 370 PetscCall(SNESSetUpMatrices(snes)); 371 PetscFunctionReturn(PETSC_SUCCESS); 372 } 373 374 static PetscErrorCode SNESReset_MS(SNES snes) 375 { 376 PetscFunctionBegin; 377 PetscFunctionReturn(PETSC_SUCCESS); 378 } 379 380 static PetscErrorCode SNESDestroy_MS(SNES snes) 381 { 382 PetscFunctionBegin; 383 PetscCall(SNESReset_MS(snes)); 384 PetscCall(PetscFree(snes->data)); 385 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMSGetType_C", NULL)); 386 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMSSetType_C", NULL)); 387 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMSGetDamping_C", NULL)); 388 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMSSetDamping_C", NULL)); 389 PetscFunctionReturn(PETSC_SUCCESS); 390 } 391 392 static PetscErrorCode SNESView_MS(SNES snes, PetscViewer viewer) 393 { 394 PetscBool iascii; 395 SNES_MS *ms = (SNES_MS *)snes->data; 396 SNESMSTableau tab = ms->tableau; 397 398 PetscFunctionBegin; 399 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 400 if (iascii) PetscCall(PetscViewerASCIIPrintf(viewer, " multi-stage method type: %s\n", tab->name)); 401 PetscFunctionReturn(PETSC_SUCCESS); 402 } 403 404 static PetscErrorCode SNESSetFromOptions_MS(SNES snes, PetscOptionItems *PetscOptionsObject) 405 { 406 SNES_MS *ms = (SNES_MS *)snes->data; 407 408 PetscFunctionBegin; 409 PetscOptionsHeadBegin(PetscOptionsObject, "SNES MS options"); 410 { 411 SNESMSTableauLink link; 412 PetscInt count, choice; 413 PetscBool flg; 414 const char **namelist; 415 SNESMSType mstype; 416 PetscReal damping; 417 418 PetscCall(SNESMSGetType(snes, &mstype)); 419 for (link = SNESMSTableauList, count = 0; link; link = link->next, count++) 420 ; 421 PetscCall(PetscMalloc1(count, (char ***)&namelist)); 422 for (link = SNESMSTableauList, count = 0; link; link = link->next, count++) namelist[count] = link->tab.name; 423 PetscCall(PetscOptionsEList("-snes_ms_type", "Multistage smoother type", "SNESMSSetType", (const char *const *)namelist, count, mstype, &choice, &flg)); 424 if (flg) PetscCall(SNESMSSetType(snes, namelist[choice])); 425 PetscCall(PetscFree(namelist)); 426 PetscCall(SNESMSGetDamping(snes, &damping)); 427 PetscCall(PetscOptionsReal("-snes_ms_damping", "Damping for multistage method", "SNESMSSetDamping", damping, &damping, &flg)); 428 if (flg) PetscCall(SNESMSSetDamping(snes, damping)); 429 PetscCall(PetscOptionsBool("-snes_ms_norms", "Compute norms for monitoring", "none", ms->norms, &ms->norms, NULL)); 430 } 431 PetscOptionsHeadEnd(); 432 PetscFunctionReturn(PETSC_SUCCESS); 433 } 434 435 static PetscErrorCode SNESMSGetType_MS(SNES snes, SNESMSType *mstype) 436 { 437 SNES_MS *ms = (SNES_MS *)snes->data; 438 SNESMSTableau tab = ms->tableau; 439 440 PetscFunctionBegin; 441 *mstype = tab->name; 442 PetscFunctionReturn(PETSC_SUCCESS); 443 } 444 445 static PetscErrorCode SNESMSSetType_MS(SNES snes, SNESMSType mstype) 446 { 447 SNES_MS *ms = (SNES_MS *)snes->data; 448 SNESMSTableauLink link; 449 PetscBool match; 450 451 PetscFunctionBegin; 452 if (ms->tableau) { 453 PetscCall(PetscStrcmp(ms->tableau->name, mstype, &match)); 454 if (match) PetscFunctionReturn(PETSC_SUCCESS); 455 } 456 for (link = SNESMSTableauList; link; link = link->next) { 457 PetscCall(PetscStrcmp(link->tab.name, mstype, &match)); 458 if (match) { 459 if (snes->setupcalled) PetscCall(SNESReset_MS(snes)); 460 ms->tableau = &link->tab; 461 if (snes->setupcalled) PetscCall(SNESSetUp_MS(snes)); 462 PetscFunctionReturn(PETSC_SUCCESS); 463 } 464 } 465 SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_UNKNOWN_TYPE, "Could not find '%s'", mstype); 466 } 467 468 /*@C 469 SNESMSGetType - Get the type of multistage smoother `SNESMS` 470 471 Not Collective 472 473 Input Parameter: 474 . snes - nonlinear solver context 475 476 Output Parameter: 477 . mstype - type of multistage method 478 479 Level: advanced 480 481 .seealso: `SNESMS`, `SNESMSSetType()`, `SNESMSType`, `SNESMS` 482 @*/ 483 PetscErrorCode SNESMSGetType(SNES snes, SNESMSType *mstype) 484 { 485 PetscFunctionBegin; 486 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 487 PetscValidPointer(mstype, 2); 488 PetscUseMethod(snes, "SNESMSGetType_C", (SNES, SNESMSType *), (snes, mstype)); 489 PetscFunctionReturn(PETSC_SUCCESS); 490 } 491 492 /*@C 493 SNESMSSetType - Set the type of multistage smoother `SNESMS` 494 495 Logically Collective 496 497 Input Parameters: 498 + snes - nonlinear solver context 499 - mstype - type of multistage method 500 501 Level: advanced 502 503 .seealso: `SNESMS`, `SNESMSGetType()`, `SNESMSType`, `SNESMS` 504 @*/ 505 PetscErrorCode SNESMSSetType(SNES snes, SNESMSType mstype) 506 { 507 PetscFunctionBegin; 508 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 509 PetscValidCharPointer(mstype, 2); 510 PetscTryMethod(snes, "SNESMSSetType_C", (SNES, SNESMSType), (snes, mstype)); 511 PetscFunctionReturn(PETSC_SUCCESS); 512 } 513 514 static PetscErrorCode SNESMSGetDamping_MS(SNES snes, PetscReal *damping) 515 { 516 SNES_MS *ms = (SNES_MS *)snes->data; 517 518 PetscFunctionBegin; 519 *damping = ms->damping; 520 PetscFunctionReturn(PETSC_SUCCESS); 521 } 522 523 static PetscErrorCode SNESMSSetDamping_MS(SNES snes, PetscReal damping) 524 { 525 SNES_MS *ms = (SNES_MS *)snes->data; 526 527 PetscFunctionBegin; 528 ms->damping = damping; 529 PetscFunctionReturn(PETSC_SUCCESS); 530 } 531 532 /*@C 533 SNESMSGetDamping - Get the damping parameter of `SNESMS` multistage scheme 534 535 Not Collective 536 537 Input Parameter: 538 . snes - nonlinear solver context 539 540 Output Parameter: 541 . damping - damping parameter 542 543 Level: advanced 544 545 .seealso: `SNESMSSetDamping()`, `SNESMS` 546 @*/ 547 PetscErrorCode SNESMSGetDamping(SNES snes, PetscReal *damping) 548 { 549 PetscFunctionBegin; 550 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 551 PetscValidRealPointer(damping, 2); 552 PetscUseMethod(snes, "SNESMSGetDamping_C", (SNES, PetscReal *), (snes, damping)); 553 PetscFunctionReturn(PETSC_SUCCESS); 554 } 555 556 /*@C 557 SNESMSSetDamping - Set the damping parameter for a `SNESMS` multistage scheme 558 559 Logically Collective 560 561 Input Parameters: 562 + snes - nonlinear solver context 563 - damping - damping parameter 564 565 Level: advanced 566 567 .seealso: `SNESMSGetDamping()`, `SNESMS` 568 @*/ 569 PetscErrorCode SNESMSSetDamping(SNES snes, PetscReal damping) 570 { 571 PetscFunctionBegin; 572 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 573 PetscValidLogicalCollectiveReal(snes, damping, 2); 574 PetscTryMethod(snes, "SNESMSSetDamping_C", (SNES, PetscReal), (snes, damping)); 575 PetscFunctionReturn(PETSC_SUCCESS); 576 } 577 578 /*MC 579 SNESMS - multi-stage smoothers 580 581 Options Database Keys: 582 + -snes_ms_type - type of multi-stage smoother 583 - -snes_ms_damping - damping for multi-stage method 584 585 Notes: 586 These multistage methods are explicit Runge-Kutta methods that are often used as smoothers for 587 FAS multigrid for transport problems. In the linear case, these are equivalent to polynomial smoothers (such as Chebyshev). 588 589 Multi-stage smoothers should usually be preconditioned by point-block Jacobi to ensure proper scaling and to normalize the wave speeds. 590 591 The methods are specified in low storage form (Ketcheson 2010). New methods can be registered with `SNESMSRegister()`. 592 593 References: 594 + * - Ketcheson (2010) Runge Kutta methods with minimum storage implementations (https://doi.org/10.1016/j.jcp.2009.11.006). 595 . * - Jameson (1983) Solution of the Euler equations for two dimensional transonic flow by a multigrid method (https://doi.org/10.1016/0096-3003(83)90019-X). 596 . * - Pierce and Giles (1997) Preconditioned multigrid methods for compressible flow calculations on stretched meshes (https://doi.org/10.1006/jcph.1997.5772). 597 - * - Van Leer, Tai, and Powell (1989) Design of optimally smoothing multi-stage schemes for the Euler equations (https://doi.org/10.2514/6.1989-1933). 598 599 Level: advanced 600 601 .seealso: `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESMS`, `SNESFAS`, `KSPCHEBYSHEV` 602 603 M*/ 604 PETSC_EXTERN PetscErrorCode SNESCreate_MS(SNES snes) 605 { 606 SNES_MS *ms; 607 608 PetscFunctionBegin; 609 PetscCall(SNESMSInitializePackage()); 610 611 snes->ops->setup = SNESSetUp_MS; 612 snes->ops->solve = SNESSolve_MS; 613 snes->ops->destroy = SNESDestroy_MS; 614 snes->ops->setfromoptions = SNESSetFromOptions_MS; 615 snes->ops->view = SNESView_MS; 616 snes->ops->reset = SNESReset_MS; 617 618 snes->usesnpc = PETSC_FALSE; 619 snes->usesksp = PETSC_TRUE; 620 621 snes->alwayscomputesfinalresidual = PETSC_FALSE; 622 623 PetscCall(PetscNew(&ms)); 624 snes->data = (void *)ms; 625 ms->damping = 0.9; 626 ms->norms = PETSC_FALSE; 627 628 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMSGetType_C", SNESMSGetType_MS)); 629 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMSSetType_C", SNESMSSetType_MS)); 630 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMSGetDamping_C", SNESMSGetDamping_MS)); 631 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMSSetDamping_C", SNESMSSetDamping_MS)); 632 633 PetscCall(SNESMSSetType(snes, SNESMSDefault)); 634 PetscFunctionReturn(PETSC_SUCCESS); 635 } 636