Actual source code: ms.c

      1: #include <petsc/private/snesimpl.h>

      3: static SNESMSType SNESMSDefault = SNESMSM62;
      4: static PetscBool  SNESMSRegisterAllCalled;
      5: static PetscBool  SNESMSPackageInitialized;

      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: };

     18: typedef struct _SNESMSTableauLink *SNESMSTableauLink;
     19: struct _SNESMSTableauLink {
     20:   struct _SNESMSTableau tab;
     21:   SNESMSTableauLink     next;
     22: };
     23: static SNESMSTableauLink SNESMSTableauList;

     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;

     31: /*@C
     32:   SNESMSRegisterAll - Registers all of the multi-stage methods in SNESMS

     34:   Not Collective, but should be called by all processes which will need the schemes to be registered

     36:   Level: advanced

     38: .seealso:  SNESMSRegisterDestroy()
     39: @*/
     40: PetscErrorCode SNESMSRegisterAll(void)
     41: {

     45:   if (SNESMSRegisterAllCalled) return(0);
     46:   SNESMSRegisterAllCalled = PETSC_TRUE;

     48:   {
     49:     PetscReal alpha[1] = {1.0};
     50:     SNESMSRegister(SNESMSEULER,1,1,1.0,NULL,NULL,alpha);
     51:   }

     53:   {
     54:     PetscReal gamma[3][6] = {
     55:       {0.0000000000000000E+00, -7.0304722367110606E-01, -1.9836719667506464E-01, -1.6023843981863788E+00,  9.4483822882855284E-02, -1.4204296130641869E-01},
     56:       {1.0000000000000000E+00,  1.1111025767083920E+00,  5.6150921583923230E-01,  7.4151723494934041E-01,  3.1714538168600587E-01,  4.6479276238548706E-01},
     57:       {0.0000000000000000E+00,  0.0000000000000000E+00,  0.0000000000000000E+00,  6.7968174970583317E-01, -4.1755042846051737E-03, -1.9115668129923846E-01}
     58:     };
     59:     PetscReal delta[6]   = {1.0000000000000000E+00, 5.3275427433201750E-01, 6.0143544663985238E-01, 4.5874077053842177E-01, 2.7544386906104651E-01, 0.0000000000000000E+00};
     60:     PetscReal betasub[6] = {8.4753115429481929E-01, 7.4018896368655618E-01, 6.5963574086583309E-03, 4.6747795645517759E-01, 1.3314545813643919E-01, 5.3260800028018784E-01};
     61:     SNESMSRegister(SNESMSM62,6,3,1.0,&gamma[0][0],delta,betasub);
     62:   }

     64:   { /* Jameson (1983) */
     65:     PetscReal alpha[4] = {0.25, 0.5, 0.55, 1.0};
     66:     SNESMSRegister(SNESMSJAMESON83,4,1,1.0,NULL,NULL,alpha);
     67:   }

     69:   { /* Van Leer, Tai, and Powell (1989) 1 stage, order 1 */
     70:     PetscReal alpha[1]  = {1.0};
     71:     SNESMSRegister(SNESMSVLTP11,1,1,0.5,NULL,NULL,alpha);
     72:   }
     73:   { /* Van Leer, Tai, and Powell (1989) 2 stage, order 1 */
     74:     PetscReal alpha[2] = {0.3333, 1.0};
     75:     SNESMSRegister(SNESMSVLTP21,2,1,1.0,NULL,NULL,alpha);
     76:   }
     77:   { /* Van Leer, Tai, and Powell (1989) 3 stage, order 1 */
     78:     PetscReal alpha[3] = {0.1481, 0.4000, 1.0};
     79:     SNESMSRegister(SNESMSVLTP31,3,1,1.5,NULL,NULL,alpha);
     80:   }
     81:   { /* Van Leer, Tai, and Powell (1989) 4 stage, order 1 */
     82:     PetscReal alpha[4] = {0.0833, 0.2069, 0.4265, 1.0};
     83:     SNESMSRegister(SNESMSVLTP41,4,1,2.0,NULL,NULL,alpha);
     84:   }
     85:   { /* Van Leer, Tai, and Powell (1989) 5 stage, order 1 */
     86:     PetscReal alpha[5] = {0.0533, 0.1263, 0.2375, 0.4414,1.0};
     87:     SNESMSRegister(SNESMSVLTP51,5,1,2.5,NULL,NULL,alpha);
     88:   }
     89:   { /* Van Leer, Tai, and Powell (1989) 6 stage, order 1 */
     90:     PetscReal alpha[6] = {0.0370, 0.0851, 0.1521, 0.2562, 0.4512, 1.0};
     91:     SNESMSRegister(SNESMSVLTP61,6,1,3.0,NULL,NULL,alpha);
     92:   }
     93:   return(0);
     94: }

     96: /*@C
     97:    SNESMSRegisterDestroy - Frees the list of schemes that were registered by SNESMSRegister().

     99:    Not Collective

    101:    Level: advanced

    103: .seealso: SNESMSRegister(), SNESMSRegisterAll()
    104: @*/
    105: PetscErrorCode SNESMSRegisterDestroy(void)
    106: {
    107:   PetscErrorCode    ierr;
    108:   SNESMSTableauLink link;

    111:   while ((link = SNESMSTableauList)) {
    112:     SNESMSTableau t = &link->tab;
    113:     SNESMSTableauList = link->next;

    115:     PetscFree(t->name);
    116:     PetscFree(t->gamma);
    117:     PetscFree(t->delta);
    118:     PetscFree(t->betasub);
    119:     PetscFree(link);
    120:   }
    121:   SNESMSRegisterAllCalled = PETSC_FALSE;
    122:   return(0);
    123: }

    125: /*@C
    126:   SNESMSInitializePackage - This function initializes everything in the SNESMS package. It is called
    127:   from SNESInitializePackage().

    129:   Level: developer

    131: .seealso: PetscInitialize()
    132: @*/
    133: PetscErrorCode SNESMSInitializePackage(void)
    134: {

    138:   if (SNESMSPackageInitialized) return(0);
    139:   SNESMSPackageInitialized = PETSC_TRUE;

    141:   SNESMSRegisterAll();
    142:   PetscRegisterFinalize(SNESMSFinalizePackage);
    143:   return(0);
    144: }

    146: /*@C
    147:   SNESMSFinalizePackage - This function destroys everything in the SNESMS package. It is
    148:   called from PetscFinalize().

    150:   Level: developer

    152: .seealso: PetscFinalize()
    153: @*/
    154: PetscErrorCode SNESMSFinalizePackage(void)
    155: {

    159:   SNESMSPackageInitialized = PETSC_FALSE;

    161:   SNESMSRegisterDestroy();
    162:   return(0);
    163: }

    165: /*@C
    166:    SNESMSRegister - register a multistage scheme

    168:    Not Collective, but the same schemes should be registered on all processes on which they will be used

    170:    Input Parameters:
    171: +  name - identifier for method
    172: .  nstages - number of stages
    173: .  nregisters - number of registers used by low-storage implementation
    174: .  stability - scaled stability region
    175: .  gamma - coefficients, see Ketcheson's paper
    176: .  delta - coefficients, see Ketcheson's paper
    177: -  betasub - subdiagonal of Shu-Osher form

    179:    Notes:
    180:    The notation is described in Ketcheson (2010) Runge-Kutta methods with minimum storage implementations.

    182:    Many multistage schemes are of the form
    183:    $ X_0 = X^{(n)}
    184:    $ X_k = X_0 + \alpha_k * F(X_{k-1}), k = 1,\ldots,s
    185:    $ X^{(n+1)} = X_s
    186:    These methods can be registered with
    187: .vb
    188:    SNESMSRegister("name",s,1,stability,NULL,NULL,alpha);
    189: .ve

    191:    Level: advanced

    193: .seealso: SNESMS
    194: @*/
    195: PetscErrorCode SNESMSRegister(SNESMSType name,PetscInt nstages,PetscInt nregisters,PetscReal stability,const PetscReal gamma[],const PetscReal delta[],const PetscReal betasub[])
    196: {
    197:   PetscErrorCode    ierr;
    198:   SNESMSTableauLink link;
    199:   SNESMSTableau     t;

    203:   if (nstages < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must have at least one stage");
    204:   if (gamma || delta) {
    205:     if (nregisters != 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only support for methods written in 3-register form");
    208:   } else {
    209:     if (nregisters != 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only support for methods written in 1-register form");
    210:   }

    213:   SNESMSInitializePackage();
    214:   PetscNew(&link);
    215:   t             = &link->tab;
    216:   PetscStrallocpy(name,&t->name);
    217:   t->nstages    = nstages;
    218:   t->nregisters = nregisters;
    219:   t->stability  = stability;

    221:   if (gamma && delta) {
    222:     PetscMalloc1(nstages*nregisters,&t->gamma);
    223:     PetscMalloc1(nstages,&t->delta);
    224:     PetscArraycpy(t->gamma,gamma,nstages*nregisters);
    225:     PetscArraycpy(t->delta,delta,nstages);
    226:   }
    227:   PetscMalloc1(nstages,&t->betasub);
    228:   PetscArraycpy(t->betasub,betasub,nstages);

    230:   link->next        = SNESMSTableauList;
    231:   SNESMSTableauList = link;
    232:   return(0);
    233: }

    235: /*
    236:   X - initial state, updated in-place.
    237:   F - residual, computed at the initial X on input
    238: */
    239: static PetscErrorCode SNESMSStep_3Sstar(SNES snes,Vec X,Vec F)
    240: {
    241:   PetscErrorCode  ierr;
    242:   SNES_MS         *ms    = (SNES_MS*)snes->data;
    243:   SNESMSTableau   t      = ms->tableau;
    244:   const PetscReal *gamma = t->gamma,*delta = t->delta,*betasub = t->betasub;
    245:   Vec             S1,S2,S3,Y;
    246:   PetscInt        i,nstages = t->nstages;

    249:   Y    = snes->work[0];
    250:   S1   = X;
    251:   S2   = snes->work[1];
    252:   S3   = snes->work[2];
    253:   VecZeroEntries(S2);
    254:   VecCopy(X,S3);
    255:   for (i = 0; i < nstages; i++) {
    256:     Vec         Ss[4];
    257:     PetscScalar scoeff[4];

    259:     Ss[0] = S1; Ss[1] = S2; Ss[2] = S3; Ss[3] = Y;

    261:     scoeff[0] = gamma[0*nstages+i] - 1;
    262:     scoeff[1] = gamma[1*nstages+i];
    263:     scoeff[2] = gamma[2*nstages+i];
    264:     scoeff[3] = -betasub[i]*ms->damping;

    266:     VecAXPY(S2,delta[i],S1);
    267:     if (i > 0) {
    268:       SNESComputeFunction(snes,S1,F);
    269:     }
    270:     KSPSolve(snes->ksp,F,Y);
    271:     VecMAXPY(S1,4,scoeff,Ss);
    272:   }
    273:   return(0);
    274: }

    276: /*
    277:   X - initial state, updated in-place.
    278:   F - residual, computed at the initial X on input
    279: */
    280: static PetscErrorCode SNESMSStep_Basic(SNES snes,Vec X,Vec F)
    281: {
    282:   PetscErrorCode  ierr;
    283:   SNES_MS         *ms    = (SNES_MS*)snes->data;
    284:   SNESMSTableau   tab    = ms->tableau;
    285:   const PetscReal *alpha = tab->betasub, h = ms->damping;
    286:   PetscInt        i,nstages = tab->nstages;
    287:   Vec             X0 = snes->work[0];

    290:   VecCopy(X,X0);
    291:   for (i = 0; i < nstages; i++) {
    292:     if (i > 0) {
    293:       SNESComputeFunction(snes,X,F);
    294:     }
    295:     KSPSolve(snes->ksp,F,X);
    296:     VecAYPX(X,-alpha[i]*h,X0);
    297:   }
    298:   return(0);
    299: }

    301: static PetscErrorCode SNESMSStep_Step(SNES snes,Vec X,Vec F)
    302: {
    303:   SNES_MS        *ms = (SNES_MS*)snes->data;
    304:   SNESMSTableau  tab = ms->tableau;

    308:   if (tab->gamma && tab->delta) {
    309:     SNESMSStep_3Sstar(snes,X,F);
    310:   } else {
    311:     SNESMSStep_Basic(snes,X,F);
    312:   }
    313:   return(0);
    314: }

    316: static PetscErrorCode SNESMSStep_Norms(SNES snes,PetscInt iter,Vec F)
    317: {
    318:   SNES_MS        *ms = (SNES_MS*)snes->data;
    319:   PetscReal      fnorm;

    323:   if (ms->norms) {
    324:     VecNorm(F,NORM_2,&fnorm); /* fnorm <- ||F||  */
    325:     SNESCheckFunctionNorm(snes,fnorm);
    326:     /* Monitor convergence */
    327:     PetscObjectSAWsTakeAccess((PetscObject)snes);
    328:     snes->iter = iter;
    329:     snes->norm = fnorm;
    330:     PetscObjectSAWsGrantAccess((PetscObject)snes);
    331:     SNESLogConvergenceHistory(snes,snes->norm,0);
    332:     SNESMonitor(snes,snes->iter,snes->norm);
    333:     /* Test for convergence */
    334:     (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
    335:   } else if (iter > 0) {
    336:     PetscObjectSAWsTakeAccess((PetscObject)snes);
    337:     snes->iter = iter;
    338:     PetscObjectSAWsGrantAccess((PetscObject)snes);
    339:   }
    340:   return(0);
    341: }

    343: static PetscErrorCode SNESSolve_MS(SNES snes)
    344: {
    345:   SNES_MS        *ms = (SNES_MS*)snes->data;
    346:   Vec            X   = snes->vec_sol,F = snes->vec_func;
    347:   PetscInt       i;

    351:   if (snes->xl || snes->xu || snes->ops->computevariablebounds) SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
    352:   PetscCitationsRegister(SNESCitation,&SNEScite);

    354:   snes->reason = SNES_CONVERGED_ITERATING;
    355:   PetscObjectSAWsTakeAccess((PetscObject)snes);
    356:   snes->iter   = 0;
    357:   snes->norm   = 0;
    358:   PetscObjectSAWsGrantAccess((PetscObject)snes);

    360:   if (!snes->vec_func_init_set) {
    361:     SNESComputeFunction(snes,X,F);
    362:   } else snes->vec_func_init_set = PETSC_FALSE;

    364:   SNESMSStep_Norms(snes,0,F);
    365:   if (snes->reason) return(0);

    367:   for (i = 0; i < snes->max_its; i++) {

    369:     /* Call general purpose update function */
    370:     if (snes->ops->update) {
    371:       (*snes->ops->update)(snes,snes->iter);
    372:     }

    374:     if (i == 0 && snes->jacobian) {
    375:       /* This method does not require a Jacobian, but it is usually preconditioned by PBJacobi */
    376:       SNESComputeJacobian(snes,snes->vec_sol,snes->jacobian,snes->jacobian_pre);
    377:       SNESCheckJacobianDomainerror(snes);
    378:       KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre);
    379:     }

    381:     SNESMSStep_Step(snes,X,F);

    383:     if (i < snes->max_its-1 || ms->norms) {
    384:       SNESComputeFunction(snes,X,F);
    385:     }

    387:     SNESMSStep_Norms(snes,i+1,F);
    388:     if (snes->reason) return(0);
    389:   }
    390:   if (!snes->reason) snes->reason = SNES_CONVERGED_ITS;
    391:   return(0);
    392: }

    394: static PetscErrorCode SNESSetUp_MS(SNES snes)
    395: {
    396:   SNES_MS        *ms   = (SNES_MS*)snes->data;
    397:   SNESMSTableau  tab   = ms->tableau;
    398:   PetscInt       nwork = tab->nregisters;

    402:   SNESSetWorkVecs(snes,nwork);
    403:   SNESSetUpMatrices(snes);
    404:   return(0);
    405: }

    407: static PetscErrorCode SNESReset_MS(SNES snes)
    408: {
    410:   return(0);
    411: }

    413: static PetscErrorCode SNESDestroy_MS(SNES snes)
    414: {

    418:   SNESReset_MS(snes);
    419:   PetscFree(snes->data);
    420:   PetscObjectComposeFunction((PetscObject)snes,"SNESMSGetType_C",NULL);
    421:   PetscObjectComposeFunction((PetscObject)snes,"SNESMSSetType_C",NULL);
    422:   PetscObjectComposeFunction((PetscObject)snes,"SNESMSGetDamping_C",NULL);
    423:   PetscObjectComposeFunction((PetscObject)snes,"SNESMSSetDamping_C",NULL);
    424:   return(0);
    425: }

    427: static PetscErrorCode SNESView_MS(SNES snes,PetscViewer viewer)
    428: {
    429:   PetscBool      iascii;
    431:   SNES_MS        *ms = (SNES_MS*)snes->data;
    432:   SNESMSTableau  tab = ms->tableau;

    435:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
    436:   if (iascii) {
    437:     PetscViewerASCIIPrintf(viewer,"  multi-stage method type: %s\n",tab->name);
    438:   }
    439:   return(0);
    440: }

    442: static PetscErrorCode SNESSetFromOptions_MS(PetscOptionItems *PetscOptionsObject,SNES snes)
    443: {
    444:   SNES_MS        *ms = (SNES_MS*)snes->data;

    448:   PetscOptionsHead(PetscOptionsObject,"SNES MS options");
    449:   {
    450:     SNESMSTableauLink link;
    451:     PetscInt          count,choice;
    452:     PetscBool         flg;
    453:     const char        **namelist;
    454:     SNESMSType        mstype;
    455:     PetscReal         damping;

    457:     SNESMSGetType(snes,&mstype);
    458:     for (link=SNESMSTableauList,count=0; link; link=link->next,count++) ;
    459:     PetscMalloc1(count,(char***)&namelist);
    460:     for (link=SNESMSTableauList,count=0; link; link=link->next,count++) namelist[count] = link->tab.name;
    461:     PetscOptionsEList("-snes_ms_type","Multistage smoother type","SNESMSSetType",(const char*const*)namelist,count,mstype,&choice,&flg);
    462:     if (flg) {SNESMSSetType(snes,namelist[choice]);}
    463:     PetscFree(namelist);
    464:     SNESMSGetDamping(snes,&damping);
    465:     PetscOptionsReal("-snes_ms_damping","Damping for multistage method","SNESMSSetDamping",damping,&damping,&flg);
    466:     if (flg) {SNESMSSetDamping(snes,damping);}
    467:     PetscOptionsBool("-snes_ms_norms","Compute norms for monitoring","none",ms->norms,&ms->norms,NULL);
    468:   }
    469:   PetscOptionsTail();
    470:   return(0);
    471: }

    473: static PetscErrorCode SNESMSGetType_MS(SNES snes,SNESMSType *mstype)
    474: {
    475:   SNES_MS        *ms = (SNES_MS*)snes->data;
    476:   SNESMSTableau  tab = ms->tableau;

    479:   *mstype = tab->name;
    480:   return(0);
    481: }

    483: static PetscErrorCode SNESMSSetType_MS(SNES snes,SNESMSType mstype)
    484: {
    485:   SNES_MS           *ms = (SNES_MS*)snes->data;
    486:   SNESMSTableauLink link;
    487:   PetscBool         match;
    488:   PetscErrorCode    ierr;

    491:   if (ms->tableau) {
    492:     PetscStrcmp(ms->tableau->name,mstype,&match);
    493:     if (match) return(0);
    494:   }
    495:   for (link = SNESMSTableauList; link; link=link->next) {
    496:     PetscStrcmp(link->tab.name,mstype,&match);
    497:     if (match) {
    498:       if (snes->setupcalled)  {SNESReset_MS(snes);}
    499:       ms->tableau = &link->tab;
    500:       if (snes->setupcalled)  {SNESSetUp_MS(snes);}
    501:       return(0);
    502:     }
    503:   }
    504:   SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_UNKNOWN_TYPE,"Could not find '%s'",mstype);
    505: }

    507: /*@C
    508:   SNESMSGetType - Get the type of multistage smoother

    510:   Not collective

    512:   Input Parameter:
    513: .  snes - nonlinear solver context

    515:   Output Parameter:
    516: .  mstype - type of multistage method

    518:   Level: beginner

    520: .seealso: SNESMSSetType(), SNESMSType, SNESMS
    521: @*/
    522: PetscErrorCode SNESMSGetType(SNES snes,SNESMSType *mstype)
    523: {

    529:   PetscUseMethod(snes,"SNESMSGetType_C",(SNES,SNESMSType*),(snes,mstype));
    530:   return(0);
    531: }

    533: /*@C
    534:   SNESMSSetType - Set the type of multistage smoother

    536:   Logically collective

    538:   Input Parameter:
    539: +  snes - nonlinear solver context
    540: -  mstype - type of multistage method

    542:   Level: beginner

    544: .seealso: SNESMSGetType(), SNESMSType, SNESMS
    545: @*/
    546: PetscErrorCode SNESMSSetType(SNES snes,SNESMSType mstype)
    547: {

    553:   PetscTryMethod(snes,"SNESMSSetType_C",(SNES,SNESMSType),(snes,mstype));
    554:   return(0);
    555: }

    557: static PetscErrorCode SNESMSGetDamping_MS(SNES snes,PetscReal *damping)
    558: {
    559:   SNES_MS        *ms = (SNES_MS*)snes->data;

    562:   *damping = ms->damping;
    563:   return(0);
    564: }

    566: static PetscErrorCode SNESMSSetDamping_MS(SNES snes,PetscReal damping)
    567: {
    568:   SNES_MS           *ms = (SNES_MS*)snes->data;

    571:   ms->damping = damping;
    572:   return(0);
    573: }

    575: /*@C
    576:   SNESMSGetDamping - Get the damping parameter

    578:   Not collective

    580:   Input Parameter:
    581: .  snes - nonlinear solver context

    583:   Output Parameter:
    584: .  damping - damping parameter

    586:   Level: advanced

    588: .seealso: SNESMSSetDamping(), SNESMS
    589: @*/
    590: PetscErrorCode SNESMSGetDamping(SNES snes,PetscReal *damping)
    591: {

    597:   PetscUseMethod(snes,"SNESMSGetDamping_C",(SNES,PetscReal*),(snes,damping));
    598:   return(0);
    599: }

    601: /*@C
    602:   SNESMSSetDamping - Set the damping parameter

    604:   Logically collective

    606:   Input Parameter:
    607: +  snes - nonlinear solver context
    608: -  damping - damping parameter

    610:   Level: advanced

    612: .seealso: SNESMSGetDamping(), SNESMS
    613: @*/
    614: PetscErrorCode SNESMSSetDamping(SNES snes,PetscReal damping)
    615: {

    621:   PetscTryMethod(snes,"SNESMSSetDamping_C",(SNES,PetscReal),(snes,damping));
    622:   return(0);
    623: }

    625: /* -------------------------------------------------------------------------- */
    626: /*MC
    627:       SNESMS - multi-stage smoothers

    629:       Options Database:

    631: +     -snes_ms_type - type of multi-stage smoother
    632: -     -snes_ms_damping - damping for multi-stage method

    634:       Notes:
    635:       These multistage methods are explicit Runge-Kutta methods that are often used as smoothers for
    636:       FAS multigrid for transport problems. In the linear case, these are equivalent to polynomial smoothers (such as Chebyshev).

    638:       Multi-stage smoothers should usually be preconditioned by point-block Jacobi to ensure proper scaling and to normalize the wave speeds.

    640:       The methods are specified in low storage form (Ketcheson 2010). New methods can be registered with SNESMSRegister().

    642:       References:
    643: +   1. -   Ketcheson (2010) Runge Kutta methods with minimum storage implementations (https://doi.org/10.1016/j.jcp.2009.11.006).
    644: .   2. -   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).
    645: .   3. -   Pierce and Giles (1997) Preconditioned multigrid methods for compressible flow calculations on stretched meshes (https://doi.org/10.1006/jcph.1997.5772).
    646: -   4. -   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).

    648:       Level: beginner

    650: .seealso:  SNESCreate(), SNES, SNESSetType(), SNESMS, SNESFAS, KSPCHEBYSHEV

    652: M*/
    653: PETSC_EXTERN PetscErrorCode SNESCreate_MS(SNES snes)
    654: {
    656:   SNES_MS        *ms;

    659:   SNESMSInitializePackage();

    661:   snes->ops->setup          = SNESSetUp_MS;
    662:   snes->ops->solve          = SNESSolve_MS;
    663:   snes->ops->destroy        = SNESDestroy_MS;
    664:   snes->ops->setfromoptions = SNESSetFromOptions_MS;
    665:   snes->ops->view           = SNESView_MS;
    666:   snes->ops->reset          = SNESReset_MS;

    668:   snes->usesnpc = PETSC_FALSE;
    669:   snes->usesksp = PETSC_TRUE;

    671:   snes->alwayscomputesfinalresidual = PETSC_FALSE;

    673:   PetscNewLog(snes,&ms);
    674:   snes->data  = (void*)ms;
    675:   ms->damping = 0.9;
    676:   ms->norms   = PETSC_FALSE;

    678:   PetscObjectComposeFunction((PetscObject)snes,"SNESMSGetType_C",SNESMSGetType_MS);
    679:   PetscObjectComposeFunction((PetscObject)snes,"SNESMSSetType_C",SNESMSSetType_MS);
    680:   PetscObjectComposeFunction((PetscObject)snes,"SNESMSGetDamping_C",SNESMSGetDamping_MS);
    681:   PetscObjectComposeFunction((PetscObject)snes,"SNESMSSetDamping_C",SNESMSSetDamping_MS);

    683:   SNESMSSetType(snes,SNESMSDefault);
    684:   return(0);
    685: }