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 Not Collective, but should be called by all processes which will need the schemes to be registered 35 36 Level: advanced 37 38 .seealso: SNESMSRegisterDestroy() 39 @*/ 40 PetscErrorCode SNESMSRegisterAll(void) 41 { 42 PetscFunctionBegin; 43 if (SNESMSRegisterAllCalled) PetscFunctionReturn(0); 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(0); 92 } 93 94 /*@C 95 SNESMSRegisterDestroy - Frees the list of schemes that were registered by SNESMSRegister(). 96 97 Not Collective 98 99 Level: advanced 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(0); 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(0); 134 SNESMSPackageInitialized = PETSC_TRUE; 135 136 PetscCall(SNESMSRegisterAll()); 137 PetscCall(PetscRegisterFinalize(SNESMSFinalizePackage)); 138 PetscFunctionReturn(0); 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(0); 156 } 157 158 /*@C 159 SNESMSRegister - register a multistage scheme 160 161 Not Collective, but the same schemes should be registered on all processes on which they will be used 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 Notes: 173 The notation is described in Ketcheson (2010) Runge-Kutta methods with minimum storage implementations. 174 175 Many multistage schemes are of the form 176 $ X_0 = X^{(n)} 177 $ X_k = X_0 + \alpha_k * F(X_{k-1}), k = 1,\ldots,s 178 $ X^{(n+1)} = X_s 179 These methods can be registered with 180 .vb 181 SNESMSRegister("name",s,1,stability,NULL,NULL,alpha); 182 .ve 183 184 Level: advanced 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(0); 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 PetscReal *gamma = t->gamma,*delta = t->delta,*betasub = t->betasub; 236 Vec S1,S2,S3,Y; 237 PetscInt i,nstages = t->nstages; 238 239 PetscFunctionBegin; 240 Y = snes->work[0]; 241 S1 = X; 242 S2 = snes->work[1]; 243 S3 = snes->work[2]; 244 PetscCall(VecZeroEntries(S2)); 245 PetscCall(VecCopy(X,S3)); 246 for (i = 0; i < nstages; i++) { 247 Vec Ss[4]; 248 PetscScalar scoeff[4]; 249 250 Ss[0] = S1; Ss[1] = S2; Ss[2] = S3; Ss[3] = Y; 251 252 scoeff[0] = gamma[0*nstages+i] - 1; 253 scoeff[1] = gamma[1*nstages+i]; 254 scoeff[2] = gamma[2*nstages+i]; 255 scoeff[3] = -betasub[i]*ms->damping; 256 257 PetscCall(VecAXPY(S2,delta[i],S1)); 258 if (i > 0) { 259 PetscCall(SNESComputeFunction(snes,S1,F)); 260 } 261 PetscCall(KSPSolve(snes->ksp,F,Y)); 262 PetscCall(VecMAXPY(S1,4,scoeff,Ss)); 263 } 264 PetscFunctionReturn(0); 265 } 266 267 /* 268 X - initial state, updated in-place. 269 F - residual, computed at the initial X on input 270 */ 271 static PetscErrorCode SNESMSStep_Basic(SNES snes,Vec X,Vec F) 272 { 273 SNES_MS *ms = (SNES_MS*)snes->data; 274 SNESMSTableau tab = ms->tableau; 275 const PetscReal *alpha = tab->betasub, h = ms->damping; 276 PetscInt i,nstages = tab->nstages; 277 Vec X0 = snes->work[0]; 278 279 PetscFunctionBegin; 280 PetscCall(VecCopy(X,X0)); 281 for (i = 0; i < nstages; i++) { 282 if (i > 0) { 283 PetscCall(SNESComputeFunction(snes,X,F)); 284 } 285 PetscCall(KSPSolve(snes->ksp,F,X)); 286 PetscCall(VecAYPX(X,-alpha[i]*h,X0)); 287 } 288 PetscFunctionReturn(0); 289 } 290 291 static PetscErrorCode SNESMSStep_Step(SNES snes,Vec X,Vec F) 292 { 293 SNES_MS *ms = (SNES_MS*)snes->data; 294 SNESMSTableau tab = ms->tableau; 295 296 PetscFunctionBegin; 297 if (tab->gamma && tab->delta) { 298 PetscCall(SNESMSStep_3Sstar(snes,X,F)); 299 } else { 300 PetscCall(SNESMSStep_Basic(snes,X,F)); 301 } 302 PetscFunctionReturn(0); 303 } 304 305 static PetscErrorCode SNESMSStep_Norms(SNES snes,PetscInt iter,Vec F) 306 { 307 SNES_MS *ms = (SNES_MS*)snes->data; 308 PetscReal fnorm; 309 310 PetscFunctionBegin; 311 if (ms->norms) { 312 PetscCall(VecNorm(F,NORM_2,&fnorm)); /* fnorm <- ||F|| */ 313 SNESCheckFunctionNorm(snes,fnorm); 314 /* Monitor convergence */ 315 PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 316 snes->iter = iter; 317 snes->norm = fnorm; 318 PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 319 PetscCall(SNESLogConvergenceHistory(snes,snes->norm,0)); 320 PetscCall(SNESMonitor(snes,snes->iter,snes->norm)); 321 /* Test for convergence */ 322 PetscCall((*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP)); 323 } else if (iter > 0) { 324 PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 325 snes->iter = iter; 326 PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 327 } 328 PetscFunctionReturn(0); 329 } 330 331 static PetscErrorCode SNESSolve_MS(SNES snes) 332 { 333 SNES_MS *ms = (SNES_MS*)snes->data; 334 Vec X = snes->vec_sol,F = snes->vec_func; 335 PetscInt i; 336 337 PetscFunctionBegin; 338 PetscCheckFalse(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); 339 PetscCall(PetscCitationsRegister(SNESCitation,&SNEScite)); 340 341 snes->reason = SNES_CONVERGED_ITERATING; 342 PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 343 snes->iter = 0; 344 snes->norm = 0; 345 PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 346 347 if (!snes->vec_func_init_set) { 348 PetscCall(SNESComputeFunction(snes,X,F)); 349 } else snes->vec_func_init_set = PETSC_FALSE; 350 351 PetscCall(SNESMSStep_Norms(snes,0,F)); 352 if (snes->reason) PetscFunctionReturn(0); 353 354 for (i = 0; i < snes->max_its; i++) { 355 356 /* Call general purpose update function */ 357 if (snes->ops->update) { 358 PetscCall((*snes->ops->update)(snes,snes->iter)); 359 } 360 361 if (i == 0 && snes->jacobian) { 362 /* This method does not require a Jacobian, but it is usually preconditioned by PBJacobi */ 363 PetscCall(SNESComputeJacobian(snes,snes->vec_sol,snes->jacobian,snes->jacobian_pre)); 364 SNESCheckJacobianDomainerror(snes); 365 PetscCall(KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre)); 366 } 367 368 PetscCall(SNESMSStep_Step(snes,X,F)); 369 370 if (i < snes->max_its-1 || ms->norms) { 371 PetscCall(SNESComputeFunction(snes,X,F)); 372 } 373 374 PetscCall(SNESMSStep_Norms(snes,i+1,F)); 375 if (snes->reason) PetscFunctionReturn(0); 376 } 377 if (!snes->reason) snes->reason = SNES_CONVERGED_ITS; 378 PetscFunctionReturn(0); 379 } 380 381 static PetscErrorCode SNESSetUp_MS(SNES snes) 382 { 383 SNES_MS *ms = (SNES_MS*)snes->data; 384 SNESMSTableau tab = ms->tableau; 385 PetscInt nwork = tab->nregisters; 386 387 PetscFunctionBegin; 388 PetscCall(SNESSetWorkVecs(snes,nwork)); 389 PetscCall(SNESSetUpMatrices(snes)); 390 PetscFunctionReturn(0); 391 } 392 393 static PetscErrorCode SNESReset_MS(SNES snes) 394 { 395 PetscFunctionBegin; 396 PetscFunctionReturn(0); 397 } 398 399 static PetscErrorCode SNESDestroy_MS(SNES snes) 400 { 401 PetscFunctionBegin; 402 PetscCall(SNESReset_MS(snes)); 403 PetscCall(PetscFree(snes->data)); 404 PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESMSGetType_C",NULL)); 405 PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESMSSetType_C",NULL)); 406 PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESMSGetDamping_C",NULL)); 407 PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESMSSetDamping_C",NULL)); 408 PetscFunctionReturn(0); 409 } 410 411 static PetscErrorCode SNESView_MS(SNES snes,PetscViewer viewer) 412 { 413 PetscBool iascii; 414 SNES_MS *ms = (SNES_MS*)snes->data; 415 SNESMSTableau tab = ms->tableau; 416 417 PetscFunctionBegin; 418 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii)); 419 if (iascii) { 420 PetscCall(PetscViewerASCIIPrintf(viewer," multi-stage method type: %s\n",tab->name)); 421 } 422 PetscFunctionReturn(0); 423 } 424 425 static PetscErrorCode SNESSetFromOptions_MS(PetscOptionItems *PetscOptionsObject,SNES snes) 426 { 427 SNES_MS *ms = (SNES_MS*)snes->data; 428 429 PetscFunctionBegin; 430 PetscCall(PetscOptionsHead(PetscOptionsObject,"SNES MS options")); 431 { 432 SNESMSTableauLink link; 433 PetscInt count,choice; 434 PetscBool flg; 435 const char **namelist; 436 SNESMSType mstype; 437 PetscReal damping; 438 439 PetscCall(SNESMSGetType(snes,&mstype)); 440 for (link=SNESMSTableauList,count=0; link; link=link->next,count++) ; 441 PetscCall(PetscMalloc1(count,(char***)&namelist)); 442 for (link=SNESMSTableauList,count=0; link; link=link->next,count++) namelist[count] = link->tab.name; 443 PetscCall(PetscOptionsEList("-snes_ms_type","Multistage smoother type","SNESMSSetType",(const char*const*)namelist,count,mstype,&choice,&flg)); 444 if (flg) PetscCall(SNESMSSetType(snes,namelist[choice])); 445 PetscCall(PetscFree(namelist)); 446 PetscCall(SNESMSGetDamping(snes,&damping)); 447 PetscCall(PetscOptionsReal("-snes_ms_damping","Damping for multistage method","SNESMSSetDamping",damping,&damping,&flg)); 448 if (flg) PetscCall(SNESMSSetDamping(snes,damping)); 449 PetscCall(PetscOptionsBool("-snes_ms_norms","Compute norms for monitoring","none",ms->norms,&ms->norms,NULL)); 450 } 451 PetscCall(PetscOptionsTail()); 452 PetscFunctionReturn(0); 453 } 454 455 static PetscErrorCode SNESMSGetType_MS(SNES snes,SNESMSType *mstype) 456 { 457 SNES_MS *ms = (SNES_MS*)snes->data; 458 SNESMSTableau tab = ms->tableau; 459 460 PetscFunctionBegin; 461 *mstype = tab->name; 462 PetscFunctionReturn(0); 463 } 464 465 static PetscErrorCode SNESMSSetType_MS(SNES snes,SNESMSType mstype) 466 { 467 SNES_MS *ms = (SNES_MS*)snes->data; 468 SNESMSTableauLink link; 469 PetscBool match; 470 471 PetscFunctionBegin; 472 if (ms->tableau) { 473 PetscCall(PetscStrcmp(ms->tableau->name,mstype,&match)); 474 if (match) PetscFunctionReturn(0); 475 } 476 for (link = SNESMSTableauList; link; link=link->next) { 477 PetscCall(PetscStrcmp(link->tab.name,mstype,&match)); 478 if (match) { 479 if (snes->setupcalled) PetscCall(SNESReset_MS(snes)); 480 ms->tableau = &link->tab; 481 if (snes->setupcalled) PetscCall(SNESSetUp_MS(snes)); 482 PetscFunctionReturn(0); 483 } 484 } 485 SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_UNKNOWN_TYPE,"Could not find '%s'",mstype); 486 } 487 488 /*@C 489 SNESMSGetType - Get the type of multistage smoother 490 491 Not collective 492 493 Input Parameter: 494 . snes - nonlinear solver context 495 496 Output Parameter: 497 . mstype - type of multistage method 498 499 Level: beginner 500 501 .seealso: SNESMSSetType(), SNESMSType, SNESMS 502 @*/ 503 PetscErrorCode SNESMSGetType(SNES snes,SNESMSType *mstype) 504 { 505 PetscFunctionBegin; 506 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 507 PetscValidPointer(mstype,2); 508 PetscUseMethod(snes,"SNESMSGetType_C",(SNES,SNESMSType*),(snes,mstype)); 509 PetscFunctionReturn(0); 510 } 511 512 /*@C 513 SNESMSSetType - Set the type of multistage smoother 514 515 Logically collective 516 517 Input Parameters: 518 + snes - nonlinear solver context 519 - mstype - type of multistage method 520 521 Level: beginner 522 523 .seealso: SNESMSGetType(), SNESMSType, SNESMS 524 @*/ 525 PetscErrorCode SNESMSSetType(SNES snes,SNESMSType mstype) 526 { 527 PetscFunctionBegin; 528 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 529 PetscValidCharPointer(mstype,2); 530 PetscTryMethod(snes,"SNESMSSetType_C",(SNES,SNESMSType),(snes,mstype)); 531 PetscFunctionReturn(0); 532 } 533 534 static PetscErrorCode SNESMSGetDamping_MS(SNES snes,PetscReal *damping) 535 { 536 SNES_MS *ms = (SNES_MS*)snes->data; 537 538 PetscFunctionBegin; 539 *damping = ms->damping; 540 PetscFunctionReturn(0); 541 } 542 543 static PetscErrorCode SNESMSSetDamping_MS(SNES snes,PetscReal damping) 544 { 545 SNES_MS *ms = (SNES_MS*)snes->data; 546 547 PetscFunctionBegin; 548 ms->damping = damping; 549 PetscFunctionReturn(0); 550 } 551 552 /*@C 553 SNESMSGetDamping - Get the damping parameter 554 555 Not collective 556 557 Input Parameter: 558 . snes - nonlinear solver context 559 560 Output Parameter: 561 . damping - damping parameter 562 563 Level: advanced 564 565 .seealso: SNESMSSetDamping(), SNESMS 566 @*/ 567 PetscErrorCode SNESMSGetDamping(SNES snes,PetscReal *damping) 568 { 569 PetscFunctionBegin; 570 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 571 PetscValidRealPointer(damping,2); 572 PetscUseMethod(snes,"SNESMSGetDamping_C",(SNES,PetscReal*),(snes,damping)); 573 PetscFunctionReturn(0); 574 } 575 576 /*@C 577 SNESMSSetDamping - Set the damping parameter 578 579 Logically collective 580 581 Input Parameters: 582 + snes - nonlinear solver context 583 - damping - damping parameter 584 585 Level: advanced 586 587 .seealso: SNESMSGetDamping(), SNESMS 588 @*/ 589 PetscErrorCode SNESMSSetDamping(SNES snes,PetscReal damping) 590 { 591 PetscFunctionBegin; 592 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 593 PetscValidLogicalCollectiveReal(snes,damping,2); 594 PetscTryMethod(snes,"SNESMSSetDamping_C",(SNES,PetscReal),(snes,damping)); 595 PetscFunctionReturn(0); 596 } 597 598 /* -------------------------------------------------------------------------- */ 599 /*MC 600 SNESMS - multi-stage smoothers 601 602 Options Database: 603 604 + -snes_ms_type - type of multi-stage smoother 605 - -snes_ms_damping - damping for multi-stage method 606 607 Notes: 608 These multistage methods are explicit Runge-Kutta methods that are often used as smoothers for 609 FAS multigrid for transport problems. In the linear case, these are equivalent to polynomial smoothers (such as Chebyshev). 610 611 Multi-stage smoothers should usually be preconditioned by point-block Jacobi to ensure proper scaling and to normalize the wave speeds. 612 613 The methods are specified in low storage form (Ketcheson 2010). New methods can be registered with SNESMSRegister(). 614 615 References: 616 + * - Ketcheson (2010) Runge Kutta methods with minimum storage implementations (https://doi.org/10.1016/j.jcp.2009.11.006). 617 . * - 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). 618 . * - Pierce and Giles (1997) Preconditioned multigrid methods for compressible flow calculations on stretched meshes (https://doi.org/10.1006/jcph.1997.5772). 619 - * - 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). 620 621 Level: beginner 622 623 .seealso: SNESCreate(), SNES, SNESSetType(), SNESMS, SNESFAS, KSPCHEBYSHEV 624 625 M*/ 626 PETSC_EXTERN PetscErrorCode SNESCreate_MS(SNES snes) 627 { 628 SNES_MS *ms; 629 630 PetscFunctionBegin; 631 PetscCall(SNESMSInitializePackage()); 632 633 snes->ops->setup = SNESSetUp_MS; 634 snes->ops->solve = SNESSolve_MS; 635 snes->ops->destroy = SNESDestroy_MS; 636 snes->ops->setfromoptions = SNESSetFromOptions_MS; 637 snes->ops->view = SNESView_MS; 638 snes->ops->reset = SNESReset_MS; 639 640 snes->usesnpc = PETSC_FALSE; 641 snes->usesksp = PETSC_TRUE; 642 643 snes->alwayscomputesfinalresidual = PETSC_FALSE; 644 645 PetscCall(PetscNewLog(snes,&ms)); 646 snes->data = (void*)ms; 647 ms->damping = 0.9; 648 ms->norms = PETSC_FALSE; 649 650 PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESMSGetType_C",SNESMSGetType_MS)); 651 PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESMSSetType_C",SNESMSSetType_MS)); 652 PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESMSGetDamping_C",SNESMSGetDamping_MS)); 653 PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESMSSetDamping_C",SNESMSSetDamping_MS)); 654 655 PetscCall(SNESMSSetType(snes,SNESMSDefault)); 656 PetscFunctionReturn(0); 657 } 658