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