xref: /petsc/src/snes/impls/ms/ms.c (revision bebe2cf65d55febe21a5af8db2bd2e168caaa2e7)
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 #undef __FUNCT__
32 #define __FUNCT__ "SNESMSRegisterAll"
33 /*@C
34   SNESMSRegisterAll - Registers all of the multi-stage methods in SNESMS
35 
36   Not Collective, but should be called by all processes which will need the schemes to be registered
37 
38   Level: advanced
39 
40 .keywords: SNES, SNESMS, register, all
41 
42 .seealso:  SNESMSRegisterDestroy()
43 @*/
44 PetscErrorCode SNESMSRegisterAll(void)
45 {
46   PetscErrorCode ierr;
47 
48   PetscFunctionBegin;
49   if (SNESMSRegisterAllCalled) PetscFunctionReturn(0);
50   SNESMSRegisterAllCalled = PETSC_TRUE;
51 
52   {
53     PetscReal gamma[3][1] = {{1.0},{0.0},{0.0}};
54     PetscReal delta[1]    = {0.0};
55     PetscReal betasub[1]  = {1.0};
56     ierr = SNESMSRegister(SNESMSEULER,1,3,1.0,&gamma[0][0],delta,betasub);CHKERRQ(ierr);
57   }
58 
59   {
60     PetscReal gamma[3][6] = {
61       {0.0000000000000000E+00,  -7.0304722367110606E-01, -1.9836719667506464E-01, -1.6023843981863788E+00, 9.4483822882855284E-02,  -1.4204296130641869E-01},
62       {1.0000000000000000E+00,  1.1111025767083920E+00,  5.6150921583923230E-01,  7.4151723494934041E-01,  3.1714538168600587E-01,  4.6479276238548706E-01},
63       {0.0000000000000000E+00,  0.0000000000000000E+00,  0.0000000000000000E+00,  6.7968174970583317E-01,  -4.1755042846051737E-03, -1.9115668129923846E-01}
64     };
65     PetscReal delta[6]   = {1.0000000000000000E+00, 5.3275427433201750E-01, 6.0143544663985238E-01, 4.5874077053842177E-01, 2.7544386906104651E-01, 0.0000000000000000E+00};
66     PetscReal betasub[6] = {8.4753115429481929E-01, 7.4018896368655618E-01, 6.5963574086583309E-03, 4.6747795645517759E-01, 1.3314545813643919E-01, 5.3260800028018784E-01};
67     ierr = SNESMSRegister(SNESMSM62,6,3,1.0,&gamma[0][0],delta,betasub);CHKERRQ(ierr);
68   }
69   {
70     PetscReal gamma[3][4] = {{0,0,0,0},{0,0,0,0},{1,1,1,1}};
71     PetscReal delta[4]    = {0,0,0,0};
72     PetscReal betasub[4]  = {0.25, 0.5, 0.55, 1.0};
73     ierr = SNESMSRegister(SNESMSJAMESON83,4,3,1.0,&gamma[0][0],delta,betasub);CHKERRQ(ierr);
74   }
75   {                             /* Van Leer, Tai, and Powell (1989) 2 stage, order 1 */
76     PetscReal gamma[3][2] = {{0,0},{0,0},{1,1}};
77     PetscReal delta[2]    = {0,0};
78     PetscReal betasub[2]  = {0.3333,1.0};
79     ierr = SNESMSRegister(SNESMSVLTP21,2,3,1.0,&gamma[0][0],delta,betasub);CHKERRQ(ierr);
80   }
81   {                             /* Van Leer, Tai, and Powell (1989) 3 stage, order 1 */
82     PetscReal gamma[3][3] = {{0,0,0},{0,0,0},{1,1,1}};
83     PetscReal delta[3]    = {0,0,0};
84     PetscReal betasub[3]  = {0.1481,0.4000,1.0};
85     ierr = SNESMSRegister(SNESMSVLTP31,3,3,1.5,&gamma[0][0],delta,betasub);CHKERRQ(ierr);
86   }
87   {                             /* Van Leer, Tai, and Powell (1989) 4 stage, order 1 */
88     PetscReal gamma[3][4] = {{0,0,0,0},{0,0,0,0},{1,1,1,1}};
89     PetscReal delta[4]    = {0,0,0,0};
90     PetscReal betasub[4]  = {0.0833,0.2069,0.4265,1.0};
91     ierr = SNESMSRegister(SNESMSVLTP41,4,3,2.0,&gamma[0][0],delta,betasub);CHKERRQ(ierr);
92   }
93   {                             /* Van Leer, Tai, and Powell (1989) 5 stage, order 1 */
94     PetscReal gamma[3][5] = {{0,0,0,0,0},{0,0,0,0,0},{1,1,1,1,1}};
95     PetscReal delta[5]    = {0,0,0,0,0};
96     PetscReal betasub[5]  = {0.0533,0.1263,0.2375,0.4414,1.0};
97     ierr = SNESMSRegister(SNESMSVLTP51,5,3,2.5,&gamma[0][0],delta,betasub);CHKERRQ(ierr);
98   }
99   {                             /* Van Leer, Tai, and Powell (1989) 6 stage, order 1 */
100     PetscReal gamma[3][6] = {{0,0,0,0,0,0},{0,0,0,0,0,0},{1,1,1,1,1,1}};
101     PetscReal delta[6]    = {0,0,0,0,0,0};
102     PetscReal betasub[6]  = {0.0370,0.0851,0.1521,0.2562,0.4512,1.0};
103     ierr = SNESMSRegister(SNESMSVLTP61,6,3,3.0,&gamma[0][0],delta,betasub);CHKERRQ(ierr);
104   }
105   PetscFunctionReturn(0);
106 }
107 
108 #undef __FUNCT__
109 #define __FUNCT__ "SNESMSRegisterDestroy"
110 /*@C
111    SNESMSRegisterDestroy - Frees the list of schemes that were registered by TSRosWRegister().
112 
113    Not Collective
114 
115    Level: advanced
116 
117 .keywords: TSRosW, register, destroy
118 .seealso: TSRosWRegister(), TSRosWRegisterAll(), TSRosWRegister()
119 @*/
120 PetscErrorCode SNESMSRegisterDestroy(void)
121 {
122   PetscErrorCode    ierr;
123   SNESMSTableauLink link;
124 
125   PetscFunctionBegin;
126   while ((link = SNESMSTableauList)) {
127     SNESMSTableau t = &link->tab;
128     SNESMSTableauList = link->next;
129 
130     ierr = PetscFree3(t->gamma,t->delta,t->betasub);CHKERRQ(ierr);
131     ierr = PetscFree(t->name);CHKERRQ(ierr);
132     ierr = PetscFree(link);CHKERRQ(ierr);
133   }
134   SNESMSRegisterAllCalled = PETSC_FALSE;
135   PetscFunctionReturn(0);
136 }
137 
138 #undef __FUNCT__
139 #define __FUNCT__ "SNESMSInitializePackage"
140 /*@C
141   SNESMSInitializePackage - This function initializes everything in the SNESMS package. It is called
142   from PetscDLLibraryRegister() when using dynamic libraries, and on the first call to SNESCreate_MS()
143   when using static libraries.
144 
145   Level: developer
146 
147 .keywords: SNES, SNESMS, initialize, package
148 .seealso: PetscInitialize()
149 @*/
150 PetscErrorCode SNESMSInitializePackage(void)
151 {
152   PetscErrorCode ierr;
153 
154   PetscFunctionBegin;
155   if (SNESMSPackageInitialized) PetscFunctionReturn(0);
156   SNESMSPackageInitialized = PETSC_TRUE;
157 
158   ierr = SNESMSRegisterAll();CHKERRQ(ierr);
159   ierr = PetscRegisterFinalize(SNESMSFinalizePackage);CHKERRQ(ierr);
160   PetscFunctionReturn(0);
161 }
162 
163 #undef __FUNCT__
164 #define __FUNCT__ "SNESMSFinalizePackage"
165 /*@C
166   SNESMSFinalizePackage - This function destroys everything in the SNESMS package. It is
167   called from PetscFinalize().
168 
169   Level: developer
170 
171 .keywords: Petsc, destroy, package
172 .seealso: PetscFinalize()
173 @*/
174 PetscErrorCode SNESMSFinalizePackage(void)
175 {
176   PetscErrorCode ierr;
177 
178   PetscFunctionBegin;
179   SNESMSPackageInitialized = PETSC_FALSE;
180 
181   ierr = SNESMSRegisterDestroy();CHKERRQ(ierr);
182   PetscFunctionReturn(0);
183 }
184 
185 #undef __FUNCT__
186 #define __FUNCT__ "SNESMSRegister"
187 /*@C
188    SNESMSRegister - register a multistage scheme
189 
190    Not Collective, but the same schemes should be registered on all processes on which they will be used
191 
192    Input Parameters:
193 +  name - identifier for method
194 .  nstages - number of stages
195 .  nregisters - number of registers used by low-storage implementation
196 .  gamma - coefficients, see Ketcheson's paper
197 .  delta - coefficients, see Ketcheson's paper
198 -  betasub - subdiagonal of Shu-Osher form
199 
200    Notes:
201    The notation is described in Ketcheson (2010) Runge-Kutta methods with minimum storage implementations.
202 
203    Level: advanced
204 
205 .keywords: SNES, register
206 
207 .seealso: SNESMS
208 @*/
209 PetscErrorCode SNESMSRegister(SNESMSType name,PetscInt nstages,PetscInt nregisters,PetscReal stability,const PetscReal gamma[],const PetscReal delta[],const PetscReal betasub[])
210 {
211   PetscErrorCode    ierr;
212   SNESMSTableauLink link;
213   SNESMSTableau     t;
214 
215   PetscFunctionBegin;
216   PetscValidCharPointer(name,1);
217   if (nstages < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must have at least one stage");
218   if (nregisters != 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only support for methods written in 3-register form");
219   PetscValidPointer(gamma,4);
220   PetscValidPointer(delta,5);
221   PetscValidPointer(betasub,6);
222 
223   ierr          = PetscNew(&link);CHKERRQ(ierr);
224   t             = &link->tab;
225   ierr          = PetscStrallocpy(name,&t->name);CHKERRQ(ierr);
226   t->nstages    = nstages;
227   t->nregisters = nregisters;
228   t->stability  = stability;
229 
230   ierr = PetscMalloc3(nstages*nregisters,&t->gamma,nstages,&t->delta,nstages,&t->betasub);CHKERRQ(ierr);
231   ierr = PetscMemcpy(t->gamma,gamma,nstages*nregisters*sizeof(PetscReal));CHKERRQ(ierr);
232   ierr = PetscMemcpy(t->delta,delta,nstages*sizeof(PetscReal));CHKERRQ(ierr);
233   ierr = PetscMemcpy(t->betasub,betasub,nstages*sizeof(PetscReal));CHKERRQ(ierr);
234 
235   link->next        = SNESMSTableauList;
236   SNESMSTableauList = link;
237   PetscFunctionReturn(0);
238 }
239 
240 #undef __FUNCT__
241 #define __FUNCT__ "SNESMSStep_3Sstar"
242 /*
243   X - initial state, updated in-place.
244   F - residual, computed at the initial X on input
245 */
246 static PetscErrorCode SNESMSStep_3Sstar(SNES snes,Vec X,Vec F)
247 {
248   PetscErrorCode  ierr;
249   SNES_MS         *ms    = (SNES_MS*)snes->data;
250   SNESMSTableau   t      = ms->tableau;
251   const PetscReal *gamma = t->gamma,*delta = t->delta,*betasub = t->betasub;
252   Vec             S1,S2,S3,Y;
253   PetscInt        i,nstages = t->nstages;;
254 
255 
256   PetscFunctionBegin;
257   Y    = snes->work[0];
258   S1   = X;
259   S2   = snes->work[1];
260   S3   = snes->work[2];
261   ierr = VecZeroEntries(S2);CHKERRQ(ierr);
262   ierr = VecCopy(X,S3);CHKERRQ(ierr);
263   for (i=0; i<nstages; i++) {
264     Vec         Ss[4];
265     PetscScalar scoeff[4];
266 
267     Ss[0] = S1; Ss[1] = S2; Ss[2] = S3; Ss[3] = Y;
268 
269     scoeff[0] = gamma[0*nstages+i]-(PetscReal)1.0;
270     scoeff[1] = gamma[1*nstages+i];
271     scoeff[2] = gamma[2*nstages+i];
272     scoeff[3] = -betasub[i]*ms->damping;
273 
274     ierr = VecAXPY(S2,delta[i],S1);CHKERRQ(ierr);
275     if (i>0) {
276       ierr = SNESComputeFunction(snes,S1,F);CHKERRQ(ierr);
277     }
278     ierr = KSPSolve(snes->ksp,F,Y);CHKERRQ(ierr);
279     ierr = VecMAXPY(S1,4,scoeff,Ss);CHKERRQ(ierr);
280   }
281   PetscFunctionReturn(0);
282 }
283 
284 #undef __FUNCT__
285 #define __FUNCT__ "SNESSolve_MS"
286 static PetscErrorCode SNESSolve_MS(SNES snes)
287 {
288   SNES_MS        *ms = (SNES_MS*)snes->data;
289   Vec            X   = snes->vec_sol,F = snes->vec_func;
290   PetscReal      fnorm;
291   PetscInt       i;
292   PetscErrorCode ierr;
293 
294   PetscFunctionBegin;
295 
296   if (snes->xl || snes->xu || snes->ops->computevariablebounds) {
297     SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
298   }
299 
300   ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr);
301   snes->reason = SNES_CONVERGED_ITERATING;
302   ierr         = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
303   snes->iter   = 0;
304   snes->norm   = 0.;
305   ierr         = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
306   if (!snes->vec_func_init_set) {
307     ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
308   } else snes->vec_func_init_set = PETSC_FALSE;
309 
310   if (snes->jacobian) {         /* This method does not require a Jacobian, but it is usually preconditioned by PBJacobi */
311     ierr = SNESComputeJacobian(snes,snes->vec_sol,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr);
312   }
313   if (ms->norms) {
314     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
315     SNESCheckFunctionNorm(snes,fnorm);
316     /* Monitor convergence */
317     ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
318     snes->iter = 0;
319     snes->norm = fnorm;
320     ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
321     ierr       = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr);
322     ierr       = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
323 
324     /* Test for convergence */
325     ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
326     if (snes->reason) PetscFunctionReturn(0);
327   }
328 
329   /* Call general purpose update function */
330   if (snes->ops->update) {
331     ierr = (*snes->ops->update)(snes,snes->iter);CHKERRQ(ierr);
332   }
333   for (i = 0; i < snes->max_its; i++) {
334     ierr = SNESMSStep_3Sstar(snes,X,F);CHKERRQ(ierr);
335 
336     if (i+1 < snes->max_its || ms->norms) {
337       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
338     }
339 
340     if (ms->norms) {
341       ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
342       SNESCheckFunctionNorm(snes,fnorm);
343 
344       /* Monitor convergence */
345       ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
346       snes->iter = i+1;
347       snes->norm = fnorm;
348       ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
349       ierr       = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr);
350       ierr       = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
351 
352       /* Test for convergence */
353       ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
354       if (snes->reason) PetscFunctionReturn(0);
355     }
356 
357     /* Call general purpose update function */
358     if (snes->ops->update) {
359       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
360     }
361   }
362   if (!snes->reason) snes->reason = SNES_CONVERGED_ITS;
363   PetscFunctionReturn(0);
364 }
365 
366 #undef __FUNCT__
367 #define __FUNCT__ "SNESSetUp_MS"
368 static PetscErrorCode SNESSetUp_MS(SNES snes)
369 {
370   SNES_MS        *ms = (SNES_MS*)snes->data;
371   PetscErrorCode ierr;
372 
373   PetscFunctionBegin;
374   if (!ms->tableau) {ierr = SNESMSSetType(snes,SNESMSDefault);CHKERRQ(ierr);}
375   ierr = SNESSetWorkVecs(snes,3);CHKERRQ(ierr);
376   ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
377   PetscFunctionReturn(0);
378 }
379 
380 #undef __FUNCT__
381 #define __FUNCT__ "SNESReset_MS"
382 static PetscErrorCode SNESReset_MS(SNES snes)
383 {
384 
385   PetscFunctionBegin;
386   PetscFunctionReturn(0);
387 }
388 
389 #undef __FUNCT__
390 #define __FUNCT__ "SNESDestroy_MS"
391 static PetscErrorCode SNESDestroy_MS(SNES snes)
392 {
393   PetscErrorCode ierr;
394 
395   PetscFunctionBegin;
396   ierr = PetscFree(snes->data);CHKERRQ(ierr);
397   ierr = PetscObjectComposeFunction((PetscObject)snes,"",NULL);CHKERRQ(ierr);
398   PetscFunctionReturn(0);
399 }
400 
401 #undef __FUNCT__
402 #define __FUNCT__ "SNESView_MS"
403 static PetscErrorCode SNESView_MS(SNES snes,PetscViewer viewer)
404 {
405   PetscBool      iascii;
406   PetscErrorCode ierr;
407   SNES_MS        *ms = (SNES_MS*)snes->data;
408 
409   PetscFunctionBegin;
410   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
411   if (iascii) {
412     SNESMSTableau tab = ms->tableau;
413     ierr = PetscViewerASCIIPrintf(viewer,"  multi-stage method type: %s\n",tab ? tab->name : "not yet set");CHKERRQ(ierr);
414   }
415   PetscFunctionReturn(0);
416 }
417 
418 #undef __FUNCT__
419 #define __FUNCT__ "SNESSetFromOptions_MS"
420 static PetscErrorCode SNESSetFromOptions_MS(PetscOptions *PetscOptionsObject,SNES snes)
421 {
422   SNES_MS        *ms = (SNES_MS*)snes->data;
423   PetscErrorCode ierr;
424 
425   PetscFunctionBegin;
426   ierr = PetscOptionsHead(PetscOptionsObject,"SNES MS options");CHKERRQ(ierr);
427   {
428     SNESMSTableauLink link;
429     PetscInt          count,choice;
430     PetscBool         flg;
431     const char        **namelist;
432     char              mstype[256];
433 
434     ierr = PetscStrncpy(mstype,SNESMSDefault,sizeof(mstype));CHKERRQ(ierr);
435     for (link=SNESMSTableauList,count=0; link; link=link->next,count++) ;
436     ierr = PetscMalloc1(count,&namelist);CHKERRQ(ierr);
437     for (link=SNESMSTableauList,count=0; link; link=link->next,count++) namelist[count] = link->tab.name;
438     ierr = PetscOptionsEList("-snes_ms_type","Multistage smoother type","SNESMSSetType",(const char*const*)namelist,count,mstype,&choice,&flg);CHKERRQ(ierr);
439     ierr = SNESMSSetType(snes,flg ? namelist[choice] : mstype);CHKERRQ(ierr);
440     ierr = PetscFree(namelist);CHKERRQ(ierr);
441     ierr = PetscOptionsReal("-snes_ms_damping","Damping for multistage method","SNESMSSetDamping",ms->damping,&ms->damping,NULL);CHKERRQ(ierr);
442     ierr = PetscOptionsBool("-snes_ms_norms","Compute norms for monitoring","none",ms->norms,&ms->norms,NULL);CHKERRQ(ierr);
443   }
444   ierr = PetscOptionsTail();CHKERRQ(ierr);
445   PetscFunctionReturn(0);
446 }
447 
448 #undef __FUNCT__
449 #define __FUNCT__ "SNESMSSetType_MS"
450 PetscErrorCode  SNESMSSetType_MS(SNES snes,SNESMSType mstype)
451 {
452   PetscErrorCode    ierr;
453   SNES_MS           *ms = (SNES_MS*)snes->data;
454   SNESMSTableauLink link;
455   PetscBool         match;
456 
457   PetscFunctionBegin;
458   if (ms->tableau) {
459     ierr = PetscStrcmp(ms->tableau->name,mstype,&match);CHKERRQ(ierr);
460     if (match) PetscFunctionReturn(0);
461   }
462   for (link = SNESMSTableauList; link; link=link->next) {
463     ierr = PetscStrcmp(link->tab.name,mstype,&match);CHKERRQ(ierr);
464     if (match) {
465       ierr        = SNESReset_MS(snes);CHKERRQ(ierr);
466       ms->tableau = &link->tab;
467       PetscFunctionReturn(0);
468     }
469   }
470   SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_UNKNOWN_TYPE,"Could not find '%s'",mstype);
471   PetscFunctionReturn(0);
472 }
473 
474 #undef __FUNCT__
475 #define __FUNCT__ "SNESMSSetType"
476 /*@C
477   SNESMSSetType - Set the type of multistage smoother
478 
479   Logically collective
480 
481   Input Parameter:
482 +  snes - nonlinear solver context
483 -  mstype - type of multistage method
484 
485   Level: beginner
486 
487 .seealso: SNESMSGetType(), SNESMS
488 @*/
489 PetscErrorCode SNESMSSetType(SNES snes,SNESMSType rostype)
490 {
491   PetscErrorCode ierr;
492 
493   PetscFunctionBegin;
494   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
495   ierr = PetscTryMethod(snes,"SNESMSSetType_C",(SNES,SNESMSType),(snes,rostype));CHKERRQ(ierr);
496   PetscFunctionReturn(0);
497 }
498 
499 /* -------------------------------------------------------------------------- */
500 /*MC
501       SNESMS - multi-stage smoothers
502 
503       Options Database:
504 
505 +     -snes_ms_type - type of multi-stage smoother
506 -     -snes_ms_damping - damping for multi-stage method
507 
508       Notes:
509       These multistage methods are explicit Runge-Kutta methods that are often used as smoothers for
510       FAS multigrid for transport problems. In the linear case, these are equivalent to polynomial smoothers (such as Chebyshev).
511 
512       Multi-stage smoothers should usually be preconditioned by point-block Jacobi to ensure proper scaling and to normalize the wave speeds.
513 
514       The methods are specified in low storage form (Ketcheson 2010). New methods can be registered with SNESMSRegister().
515 
516       References:
517 
518       Ketcheson (2010) Runge-Kutta methods with minimum storage implementations.
519 
520       Jameson (1983) Solution of the Euler equations for two dimensional transonic flow by a multigrid method.
521 
522       Pierce and Giles (1997) Preconditioned multigrid methods for compressible flow calculations on stretched meshes.
523 
524       Level: beginner
525 
526 .seealso:  SNESCreate(), SNES, SNESSetType(), SNESMS, SNESFAS, KSPCHEBYSHEV
527 
528 M*/
529 #undef __FUNCT__
530 #define __FUNCT__ "SNESCreate_MS"
531 PETSC_EXTERN PetscErrorCode SNESCreate_MS(SNES snes)
532 {
533   PetscErrorCode ierr;
534   SNES_MS        *ms;
535 
536   PetscFunctionBegin;
537   ierr = SNESMSInitializePackage();CHKERRQ(ierr);
538 
539   snes->ops->setup          = SNESSetUp_MS;
540   snes->ops->solve          = SNESSolve_MS;
541   snes->ops->destroy        = SNESDestroy_MS;
542   snes->ops->setfromoptions = SNESSetFromOptions_MS;
543   snes->ops->view           = SNESView_MS;
544   snes->ops->reset          = SNESReset_MS;
545 
546   snes->usespc  = PETSC_FALSE;
547   snes->usesksp = PETSC_TRUE;
548 
549   ierr        = PetscNewLog(snes,&ms);CHKERRQ(ierr);
550   snes->data  = (void*)ms;
551   ms->damping = 0.9;
552   ms->norms   = PETSC_FALSE;
553 
554   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESMSSetType_C",SNESMSSetType_MS);CHKERRQ(ierr);
555   PetscFunctionReturn(0);
556 }
557 
558