xref: /petsc/src/snes/impls/ms/ms.c (revision 030f984af8d8bb4c203755d35bded3c05b3d83ce)
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   PetscErrorCode ierr;
43 
44   PetscFunctionBegin;
45   if (SNESMSRegisterAllCalled) PetscFunctionReturn(0);
46   SNESMSRegisterAllCalled = PETSC_TRUE;
47 
48   {
49     PetscReal alpha[1] = {1.0};
50     ierr = SNESMSRegister(SNESMSEULER,1,1,1.0,NULL,NULL,alpha);CHKERRQ(ierr);
51   }
52 
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     ierr = SNESMSRegister(SNESMSM62,6,3,1.0,&gamma[0][0],delta,betasub);CHKERRQ(ierr);
62   }
63 
64   { /* Jameson (1983) */
65     PetscReal alpha[4] = {0.25, 0.5, 0.55, 1.0};
66     ierr = SNESMSRegister(SNESMSJAMESON83,4,1,1.0,NULL,NULL,alpha);CHKERRQ(ierr);
67   }
68 
69   { /* Van Leer, Tai, and Powell (1989) 1 stage, order 1 */
70     PetscReal alpha[1]  = {1.0};
71     ierr = SNESMSRegister(SNESMSVLTP11,1,1,0.5,NULL,NULL,alpha);CHKERRQ(ierr);
72   }
73   { /* Van Leer, Tai, and Powell (1989) 2 stage, order 1 */
74     PetscReal alpha[2] = {0.3333, 1.0};
75     ierr = SNESMSRegister(SNESMSVLTP21,2,1,1.0,NULL,NULL,alpha);CHKERRQ(ierr);
76   }
77   { /* Van Leer, Tai, and Powell (1989) 3 stage, order 1 */
78     PetscReal alpha[3] = {0.1481, 0.4000, 1.0};
79     ierr = SNESMSRegister(SNESMSVLTP31,3,1,1.5,NULL,NULL,alpha);CHKERRQ(ierr);
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     ierr = SNESMSRegister(SNESMSVLTP41,4,1,2.0,NULL,NULL,alpha);CHKERRQ(ierr);
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     ierr = SNESMSRegister(SNESMSVLTP51,5,1,2.5,NULL,NULL,alpha);CHKERRQ(ierr);
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     ierr = SNESMSRegister(SNESMSVLTP61,6,1,3.0,NULL,NULL,alpha);CHKERRQ(ierr);
92   }
93   PetscFunctionReturn(0);
94 }
95 
96 /*@C
97    SNESMSRegisterDestroy - Frees the list of schemes that were registered by SNESMSRegister().
98 
99    Not Collective
100 
101    Level: advanced
102 
103 .seealso: SNESMSRegister(), SNESMSRegisterAll()
104 @*/
105 PetscErrorCode SNESMSRegisterDestroy(void)
106 {
107   PetscErrorCode    ierr;
108   SNESMSTableauLink link;
109 
110   PetscFunctionBegin;
111   while ((link = SNESMSTableauList)) {
112     SNESMSTableau t = &link->tab;
113     SNESMSTableauList = link->next;
114 
115     ierr = PetscFree(t->name);CHKERRQ(ierr);
116     ierr = PetscFree(t->gamma);CHKERRQ(ierr);
117     ierr = PetscFree(t->delta);CHKERRQ(ierr);
118     ierr = PetscFree(t->betasub);CHKERRQ(ierr);
119     ierr = PetscFree(link);CHKERRQ(ierr);
120   }
121   SNESMSRegisterAllCalled = PETSC_FALSE;
122   PetscFunctionReturn(0);
123 }
124 
125 /*@C
126   SNESMSInitializePackage - This function initializes everything in the SNESMS package. It is called
127   from SNESInitializePackage().
128 
129   Level: developer
130 
131 .seealso: PetscInitialize()
132 @*/
133 PetscErrorCode SNESMSInitializePackage(void)
134 {
135   PetscErrorCode ierr;
136 
137   PetscFunctionBegin;
138   if (SNESMSPackageInitialized) PetscFunctionReturn(0);
139   SNESMSPackageInitialized = PETSC_TRUE;
140 
141   ierr = SNESMSRegisterAll();CHKERRQ(ierr);
142   ierr = PetscRegisterFinalize(SNESMSFinalizePackage);CHKERRQ(ierr);
143   PetscFunctionReturn(0);
144 }
145 
146 /*@C
147   SNESMSFinalizePackage - This function destroys everything in the SNESMS package. It is
148   called from PetscFinalize().
149 
150   Level: developer
151 
152 .seealso: PetscFinalize()
153 @*/
154 PetscErrorCode SNESMSFinalizePackage(void)
155 {
156   PetscErrorCode ierr;
157 
158   PetscFunctionBegin;
159   SNESMSPackageInitialized = PETSC_FALSE;
160 
161   ierr = SNESMSRegisterDestroy();CHKERRQ(ierr);
162   PetscFunctionReturn(0);
163 }
164 
165 /*@C
166    SNESMSRegister - register a multistage scheme
167 
168    Not Collective, but the same schemes should be registered on all processes on which they will be used
169 
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
178 
179    Notes:
180    The notation is described in Ketcheson (2010) Runge-Kutta methods with minimum storage implementations.
181 
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
190 
191    Level: advanced
192 
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;
200 
201   PetscFunctionBegin;
202   PetscValidCharPointer(name,1);
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");
206     PetscValidRealPointer(gamma,5);
207     PetscValidRealPointer(delta,6);
208   } else {
209     if (nregisters != 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only support for methods written in 1-register form");
210   }
211   PetscValidRealPointer(betasub,7);
212 
213   ierr          = SNESMSInitializePackage();CHKERRQ(ierr);
214   ierr          = PetscNew(&link);CHKERRQ(ierr);
215   t             = &link->tab;
216   ierr          = PetscStrallocpy(name,&t->name);CHKERRQ(ierr);
217   t->nstages    = nstages;
218   t->nregisters = nregisters;
219   t->stability  = stability;
220 
221   if (gamma && delta) {
222     ierr = PetscMalloc1(nstages*nregisters,&t->gamma);CHKERRQ(ierr);
223     ierr = PetscMalloc1(nstages,&t->delta);CHKERRQ(ierr);
224     ierr = PetscArraycpy(t->gamma,gamma,nstages*nregisters);CHKERRQ(ierr);
225     ierr = PetscArraycpy(t->delta,delta,nstages);CHKERRQ(ierr);
226   }
227   ierr = PetscMalloc1(nstages,&t->betasub);CHKERRQ(ierr);
228   ierr = PetscArraycpy(t->betasub,betasub,nstages);CHKERRQ(ierr);
229 
230   link->next        = SNESMSTableauList;
231   SNESMSTableauList = link;
232   PetscFunctionReturn(0);
233 }
234 
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;
247 
248   PetscFunctionBegin;
249   Y    = snes->work[0];
250   S1   = X;
251   S2   = snes->work[1];
252   S3   = snes->work[2];
253   ierr = VecZeroEntries(S2);CHKERRQ(ierr);
254   ierr = VecCopy(X,S3);CHKERRQ(ierr);
255   for (i = 0; i < nstages; i++) {
256     Vec         Ss[4];
257     PetscScalar scoeff[4];
258 
259     Ss[0] = S1; Ss[1] = S2; Ss[2] = S3; Ss[3] = Y;
260 
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;
265 
266     ierr = VecAXPY(S2,delta[i],S1);CHKERRQ(ierr);
267     if (i > 0) {
268       ierr = SNESComputeFunction(snes,S1,F);CHKERRQ(ierr);
269     }
270     ierr = KSPSolve(snes->ksp,F,Y);CHKERRQ(ierr);
271     ierr = VecMAXPY(S1,4,scoeff,Ss);CHKERRQ(ierr);
272   }
273   PetscFunctionReturn(0);
274 }
275 
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];
288 
289   PetscFunctionBegin;
290   ierr = VecCopy(X,X0);CHKERRQ(ierr);
291   for (i = 0; i < nstages; i++) {
292     if (i > 0) {
293       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
294     }
295     ierr = KSPSolve(snes->ksp,F,X);CHKERRQ(ierr);
296     ierr = VecAYPX(X,-alpha[i]*h,X0);CHKERRQ(ierr);
297   }
298   PetscFunctionReturn(0);
299 }
300 
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;
305   PetscErrorCode ierr;
306 
307   PetscFunctionBegin;
308   if (tab->gamma && tab->delta) {
309     ierr = SNESMSStep_3Sstar(snes,X,F);CHKERRQ(ierr);
310   } else {
311     ierr = SNESMSStep_Basic(snes,X,F);CHKERRQ(ierr);
312   }
313   PetscFunctionReturn(0);
314 }
315 
316 static PetscErrorCode SNESMSStep_Norms(SNES snes,PetscInt iter,Vec F)
317 {
318   SNES_MS        *ms = (SNES_MS*)snes->data;
319   PetscReal      fnorm;
320   PetscErrorCode ierr;
321 
322   PetscFunctionBegin;
323   if (ms->norms) {
324     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
325     SNESCheckFunctionNorm(snes,fnorm);
326     /* Monitor convergence */
327     ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
328     snes->iter = iter;
329     snes->norm = fnorm;
330     ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
331     ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr);
332     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
333     /* Test for convergence */
334     ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
335   } else if (iter > 0) {
336     ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
337     snes->iter = iter;
338     ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
339   }
340   PetscFunctionReturn(0);
341 }
342 
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;
348   PetscErrorCode ierr;
349 
350   PetscFunctionBegin;
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   ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr);
353 
354   snes->reason = SNES_CONVERGED_ITERATING;
355   ierr         = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
356   snes->iter   = 0;
357   snes->norm   = 0;
358   ierr         = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
359 
360   if (!snes->vec_func_init_set) {
361     ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
362   } else snes->vec_func_init_set = PETSC_FALSE;
363 
364   ierr = SNESMSStep_Norms(snes,0,F);CHKERRQ(ierr);
365   if (snes->reason) PetscFunctionReturn(0);
366 
367   for (i = 0; i < snes->max_its; i++) {
368 
369     /* Call general purpose update function */
370     if (snes->ops->update) {
371       ierr = (*snes->ops->update)(snes,snes->iter);CHKERRQ(ierr);
372     }
373 
374     if (i == 0 && snes->jacobian) {
375       /* This method does not require a Jacobian, but it is usually preconditioned by PBJacobi */
376       ierr = SNESComputeJacobian(snes,snes->vec_sol,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr);
377       SNESCheckJacobianDomainerror(snes);
378       ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr);
379     }
380 
381     ierr = SNESMSStep_Step(snes,X,F);CHKERRQ(ierr);
382 
383     if (i < snes->max_its-1 || ms->norms) {
384       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
385     }
386 
387     ierr = SNESMSStep_Norms(snes,i+1,F);CHKERRQ(ierr);
388     if (snes->reason) PetscFunctionReturn(0);
389   }
390   if (!snes->reason) snes->reason = SNES_CONVERGED_ITS;
391   PetscFunctionReturn(0);
392 }
393 
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;
399   PetscErrorCode ierr;
400 
401   PetscFunctionBegin;
402   ierr = SNESSetWorkVecs(snes,nwork);CHKERRQ(ierr);
403   ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
404   PetscFunctionReturn(0);
405 }
406 
407 static PetscErrorCode SNESReset_MS(SNES snes)
408 {
409   PetscFunctionBegin;
410   PetscFunctionReturn(0);
411 }
412 
413 static PetscErrorCode SNESDestroy_MS(SNES snes)
414 {
415   PetscErrorCode ierr;
416 
417   PetscFunctionBegin;
418   ierr = SNESReset_MS(snes);CHKERRQ(ierr);
419   ierr = PetscFree(snes->data);CHKERRQ(ierr);
420   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESMSGetType_C",NULL);CHKERRQ(ierr);
421   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESMSSetType_C",NULL);CHKERRQ(ierr);
422   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESMSGetDamping_C",NULL);CHKERRQ(ierr);
423   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESMSSetDamping_C",NULL);CHKERRQ(ierr);
424   PetscFunctionReturn(0);
425 }
426 
427 static PetscErrorCode SNESView_MS(SNES snes,PetscViewer viewer)
428 {
429   PetscBool      iascii;
430   PetscErrorCode ierr;
431   SNES_MS        *ms = (SNES_MS*)snes->data;
432   SNESMSTableau  tab = ms->tableau;
433 
434   PetscFunctionBegin;
435   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
436   if (iascii) {
437     ierr = PetscViewerASCIIPrintf(viewer,"  multi-stage method type: %s\n",tab->name);CHKERRQ(ierr);
438   }
439   PetscFunctionReturn(0);
440 }
441 
442 static PetscErrorCode SNESSetFromOptions_MS(PetscOptionItems *PetscOptionsObject,SNES snes)
443 {
444   SNES_MS        *ms = (SNES_MS*)snes->data;
445   PetscErrorCode ierr;
446 
447   PetscFunctionBegin;
448   ierr = PetscOptionsHead(PetscOptionsObject,"SNES MS options");CHKERRQ(ierr);
449   {
450     SNESMSTableauLink link;
451     PetscInt          count,choice;
452     PetscBool         flg;
453     const char        **namelist;
454     SNESMSType        mstype;
455     PetscReal         damping;
456 
457     ierr = SNESMSGetType(snes,&mstype);CHKERRQ(ierr);
458     for (link=SNESMSTableauList,count=0; link; link=link->next,count++) ;
459     ierr = PetscMalloc1(count,(char***)&namelist);CHKERRQ(ierr);
460     for (link=SNESMSTableauList,count=0; link; link=link->next,count++) namelist[count] = link->tab.name;
461     ierr = PetscOptionsEList("-snes_ms_type","Multistage smoother type","SNESMSSetType",(const char*const*)namelist,count,mstype,&choice,&flg);CHKERRQ(ierr);
462     if (flg) {ierr = SNESMSSetType(snes,namelist[choice]);CHKERRQ(ierr);}
463     ierr = PetscFree(namelist);CHKERRQ(ierr);
464     ierr = SNESMSGetDamping(snes,&damping);CHKERRQ(ierr);
465     ierr = PetscOptionsReal("-snes_ms_damping","Damping for multistage method","SNESMSSetDamping",damping,&damping,&flg);CHKERRQ(ierr);
466     if (flg) {ierr = SNESMSSetDamping(snes,damping);CHKERRQ(ierr);}
467     ierr = PetscOptionsBool("-snes_ms_norms","Compute norms for monitoring","none",ms->norms,&ms->norms,NULL);CHKERRQ(ierr);
468   }
469   ierr = PetscOptionsTail();CHKERRQ(ierr);
470   PetscFunctionReturn(0);
471 }
472 
473 static PetscErrorCode SNESMSGetType_MS(SNES snes,SNESMSType *mstype)
474 {
475   SNES_MS        *ms = (SNES_MS*)snes->data;
476   SNESMSTableau  tab = ms->tableau;
477 
478   PetscFunctionBegin;
479   *mstype = tab->name;
480   PetscFunctionReturn(0);
481 }
482 
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;
489 
490   PetscFunctionBegin;
491   if (ms->tableau) {
492     ierr = PetscStrcmp(ms->tableau->name,mstype,&match);CHKERRQ(ierr);
493     if (match) PetscFunctionReturn(0);
494   }
495   for (link = SNESMSTableauList; link; link=link->next) {
496     ierr = PetscStrcmp(link->tab.name,mstype,&match);CHKERRQ(ierr);
497     if (match) {
498       if (snes->setupcalled)  {ierr = SNESReset_MS(snes);CHKERRQ(ierr);}
499       ms->tableau = &link->tab;
500       if (snes->setupcalled)  {ierr = SNESSetUp_MS(snes);CHKERRQ(ierr);}
501       PetscFunctionReturn(0);
502     }
503   }
504   SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_UNKNOWN_TYPE,"Could not find '%s'",mstype);
505 }
506 
507 /*@C
508   SNESMSGetType - Get the type of multistage smoother
509 
510   Not collective
511 
512   Input Parameter:
513 .  snes - nonlinear solver context
514 
515   Output Parameter:
516 .  mstype - type of multistage method
517 
518   Level: beginner
519 
520 .seealso: SNESMSSetType(), SNESMSType, SNESMS
521 @*/
522 PetscErrorCode SNESMSGetType(SNES snes,SNESMSType *mstype)
523 {
524   PetscErrorCode ierr;
525 
526   PetscFunctionBegin;
527   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
528   PetscValidPointer(mstype,2);
529   ierr = PetscUseMethod(snes,"SNESMSGetType_C",(SNES,SNESMSType*),(snes,mstype));CHKERRQ(ierr);
530   PetscFunctionReturn(0);
531 }
532 
533 /*@C
534   SNESMSSetType - Set the type of multistage smoother
535 
536   Logically collective
537 
538   Input Parameter:
539 +  snes - nonlinear solver context
540 -  mstype - type of multistage method
541 
542   Level: beginner
543 
544 .seealso: SNESMSGetType(), SNESMSType, SNESMS
545 @*/
546 PetscErrorCode SNESMSSetType(SNES snes,SNESMSType mstype)
547 {
548   PetscErrorCode ierr;
549 
550   PetscFunctionBegin;
551   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
552   PetscValidPointer(mstype,2);
553   ierr = PetscTryMethod(snes,"SNESMSSetType_C",(SNES,SNESMSType),(snes,mstype));CHKERRQ(ierr);
554   PetscFunctionReturn(0);
555 }
556 
557 static PetscErrorCode SNESMSGetDamping_MS(SNES snes,PetscReal *damping)
558 {
559   SNES_MS        *ms = (SNES_MS*)snes->data;
560 
561   PetscFunctionBegin;
562   *damping = ms->damping;
563   PetscFunctionReturn(0);
564 }
565 
566 static PetscErrorCode SNESMSSetDamping_MS(SNES snes,PetscReal damping)
567 {
568   SNES_MS           *ms = (SNES_MS*)snes->data;
569 
570   PetscFunctionBegin;
571   ms->damping = damping;
572   PetscFunctionReturn(0);
573 }
574 
575 /*@C
576   SNESMSGetDamping - Get the damping parameter
577 
578   Not collective
579 
580   Input Parameter:
581 .  snes - nonlinear solver context
582 
583   Output Parameter:
584 .  damping - damping parameter
585 
586   Level: advanced
587 
588 .seealso: SNESMSSetDamping(), SNESMS
589 @*/
590 PetscErrorCode SNESMSGetDamping(SNES snes,PetscReal *damping)
591 {
592   PetscErrorCode ierr;
593 
594   PetscFunctionBegin;
595   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
596   PetscValidPointer(damping,2);
597   ierr = PetscUseMethod(snes,"SNESMSGetDamping_C",(SNES,PetscReal*),(snes,damping));CHKERRQ(ierr);
598   PetscFunctionReturn(0);
599 }
600 
601 /*@C
602   SNESMSSetDamping - Set the damping parameter
603 
604   Logically collective
605 
606   Input Parameter:
607 +  snes - nonlinear solver context
608 -  damping - damping parameter
609 
610   Level: advanced
611 
612 .seealso: SNESMSGetDamping(), SNESMS
613 @*/
614 PetscErrorCode SNESMSSetDamping(SNES snes,PetscReal damping)
615 {
616   PetscErrorCode ierr;
617 
618   PetscFunctionBegin;
619   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
620   PetscValidLogicalCollectiveReal(snes,damping,2);
621   ierr = PetscTryMethod(snes,"SNESMSSetDamping_C",(SNES,PetscReal),(snes,damping));CHKERRQ(ierr);
622   PetscFunctionReturn(0);
623 }
624 
625 /* -------------------------------------------------------------------------- */
626 /*MC
627       SNESMS - multi-stage smoothers
628 
629       Options Database:
630 
631 +     -snes_ms_type - type of multi-stage smoother
632 -     -snes_ms_damping - damping for multi-stage method
633 
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).
637 
638       Multi-stage smoothers should usually be preconditioned by point-block Jacobi to ensure proper scaling and to normalize the wave speeds.
639 
640       The methods are specified in low storage form (Ketcheson 2010). New methods can be registered with SNESMSRegister().
641 
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).
647 
648       Level: beginner
649 
650 .seealso:  SNESCreate(), SNES, SNESSetType(), SNESMS, SNESFAS, KSPCHEBYSHEV
651 
652 M*/
653 PETSC_EXTERN PetscErrorCode SNESCreate_MS(SNES snes)
654 {
655   PetscErrorCode ierr;
656   SNES_MS        *ms;
657 
658   PetscFunctionBegin;
659   ierr = SNESMSInitializePackage();CHKERRQ(ierr);
660 
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;
667 
668   snes->usesnpc = PETSC_FALSE;
669   snes->usesksp = PETSC_TRUE;
670 
671   snes->alwayscomputesfinalresidual = PETSC_FALSE;
672 
673   ierr        = PetscNewLog(snes,&ms);CHKERRQ(ierr);
674   snes->data  = (void*)ms;
675   ms->damping = 0.9;
676   ms->norms   = PETSC_FALSE;
677 
678   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESMSGetType_C",SNESMSGetType_MS);CHKERRQ(ierr);
679   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESMSSetType_C",SNESMSSetType_MS);CHKERRQ(ierr);
680   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESMSGetDamping_C",SNESMSGetDamping_MS);CHKERRQ(ierr);
681   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESMSSetDamping_C",SNESMSSetDamping_MS);CHKERRQ(ierr);
682 
683   ierr = SNESMSSetType(snes,SNESMSDefault);CHKERRQ(ierr);
684   PetscFunctionReturn(0);
685 }
686