xref: /petsc/src/snes/impls/ms/ms.c (revision 245f004be2b2fca55a62739415aedaade1b4b42e)
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(), TSRosWRegisterDynamic()
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   Input Parameter:
146   path - The dynamic library path, or NULL
147 
148   Level: developer
149 
150 .keywords: SNES, SNESMS, initialize, package
151 .seealso: PetscInitialize()
152 @*/
153 PetscErrorCode SNESMSInitializePackage(const char path[])
154 {
155   PetscErrorCode ierr;
156 
157   PetscFunctionBegin;
158   if (SNESMSPackageInitialized) PetscFunctionReturn(0);
159   SNESMSPackageInitialized = PETSC_TRUE;
160 
161   ierr = SNESMSRegisterAll();CHKERRQ(ierr);
162   ierr = PetscRegisterFinalize(SNESMSFinalizePackage);CHKERRQ(ierr);
163   PetscFunctionReturn(0);
164 }
165 
166 #undef __FUNCT__
167 #define __FUNCT__ "SNESMSFinalizePackage"
168 /*@C
169   SNESMSFinalizePackage - This function destroys everything in the SNESMS package. It is
170   called from PetscFinalize().
171 
172   Level: developer
173 
174 .keywords: Petsc, destroy, package
175 .seealso: PetscFinalize()
176 @*/
177 PetscErrorCode SNESMSFinalizePackage(void)
178 {
179   PetscErrorCode ierr;
180 
181   PetscFunctionBegin;
182   SNESMSPackageInitialized = PETSC_FALSE;
183 
184   ierr = SNESMSRegisterDestroy();CHKERRQ(ierr);
185   PetscFunctionReturn(0);
186 }
187 
188 #undef __FUNCT__
189 #define __FUNCT__ "SNESMSRegister"
190 /*@C
191    SNESMSRegister - register a multistage scheme
192 
193    Not Collective, but the same schemes should be registered on all processes on which they will be used
194 
195    Input Parameters:
196 +  name - identifier for method
197 .  nstages - number of stages
198 .  nregisters - number of registers used by low-storage implementation
199 .  gamma - coefficients, see Ketcheson's paper
200 .  delta - coefficients, see Ketcheson's paper
201 -  betasub - subdiagonal of Shu-Osher form
202 
203    Notes:
204    The notation is described in Ketcheson (2010) Runge-Kutta methods with minimum storage implementations.
205 
206    Level: advanced
207 
208 .keywords: SNES, register
209 
210 .seealso: SNESMS
211 @*/
212 PetscErrorCode SNESMSRegister(SNESMSType name,PetscInt nstages,PetscInt nregisters,PetscReal stability,const PetscReal gamma[],const PetscReal delta[],const PetscReal betasub[])
213 {
214   PetscErrorCode    ierr;
215   SNESMSTableauLink link;
216   SNESMSTableau     t;
217 
218   PetscFunctionBegin;
219   PetscValidCharPointer(name,1);
220   if (nstages < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must have at least one stage");
221   if (nregisters != 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only support for methods written in 3-register form");
222   PetscValidPointer(gamma,4);
223   PetscValidPointer(delta,5);
224   PetscValidPointer(betasub,6);
225 
226   ierr          = PetscMalloc(sizeof(*link),&link);CHKERRQ(ierr);
227   ierr          = PetscMemzero(link,sizeof(*link));CHKERRQ(ierr);
228   t             = &link->tab;
229   ierr          = PetscStrallocpy(name,&t->name);CHKERRQ(ierr);
230   t->nstages    = nstages;
231   t->nregisters = nregisters;
232   t->stability  = stability;
233 
234   ierr = PetscMalloc3(nstages*nregisters,PetscReal,&t->gamma,nstages,PetscReal,&t->delta,nstages,PetscReal,&t->betasub);CHKERRQ(ierr);
235   ierr = PetscMemcpy(t->gamma,gamma,nstages*nregisters*sizeof(PetscReal));CHKERRQ(ierr);
236   ierr = PetscMemcpy(t->delta,delta,nstages*sizeof(PetscReal));CHKERRQ(ierr);
237   ierr = PetscMemcpy(t->betasub,betasub,nstages*sizeof(PetscReal));CHKERRQ(ierr);
238 
239   link->next        = SNESMSTableauList;
240   SNESMSTableauList = link;
241   PetscFunctionReturn(0);
242 }
243 
244 #undef __FUNCT__
245 #define __FUNCT__ "SNESMSStep_3Sstar"
246 /*
247   X - initial state, updated in-place.
248   F - residual, computed at the initial X on input
249 */
250 static PetscErrorCode SNESMSStep_3Sstar(SNES snes,Vec X,Vec F)
251 {
252   PetscErrorCode  ierr;
253   SNES_MS         *ms    = (SNES_MS*)snes->data;
254   SNESMSTableau   t      = ms->tableau;
255   const PetscReal *gamma = t->gamma,*delta = t->delta,*betasub = t->betasub;
256   Vec             S1,S2,S3,Y;
257   PetscInt        i,nstages = t->nstages;;
258 
259 
260   PetscFunctionBegin;
261   Y    = snes->work[0];
262   S1   = X;
263   S2   = snes->work[1];
264   S3   = snes->work[2];
265   ierr = VecZeroEntries(S2);CHKERRQ(ierr);
266   ierr = VecCopy(X,S3);CHKERRQ(ierr);
267   for (i=0; i<nstages; i++) {
268     Vec         Ss[4];
269     PetscScalar scoeff[4];
270 
271     Ss[0] = S1; Ss[1] = S2; Ss[2] = S3; Ss[3] = Y;
272 
273     scoeff[0] = gamma[0*nstages+i]-(PetscReal)1.0;
274     scoeff[1] = gamma[1*nstages+i];
275     scoeff[2] = gamma[2*nstages+i];
276     scoeff[3] = -betasub[i]*ms->damping;
277 
278     ierr = VecAXPY(S2,delta[i],S1);CHKERRQ(ierr);
279     if (i>0) {
280       ierr = SNESComputeFunction(snes,S1,F);CHKERRQ(ierr);
281       if (snes->domainerror) {
282         snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
283         PetscFunctionReturn(0);
284       }
285     }
286     ierr = SNES_KSPSolve(snes,snes->ksp,F,Y);CHKERRQ(ierr);
287     ierr = VecMAXPY(S1,4,scoeff,Ss);CHKERRQ(ierr);
288   }
289   PetscFunctionReturn(0);
290 }
291 
292 #undef __FUNCT__
293 #define __FUNCT__ "SNESSolve_MS"
294 static PetscErrorCode SNESSolve_MS(SNES snes)
295 {
296   SNES_MS        *ms = (SNES_MS*)snes->data;
297   Vec            X   = snes->vec_sol,F = snes->vec_func;
298   PetscReal      fnorm;
299   MatStructure   mstruct;
300   PetscInt       i;
301   PetscErrorCode ierr;
302 
303   PetscFunctionBegin;
304   snes->reason = SNES_CONVERGED_ITERATING;
305   ierr         = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
306   snes->iter   = 0;
307   snes->norm   = 0.;
308   ierr         = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
309   if (!snes->vec_func_init_set) {
310     ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
311     if (snes->domainerror) {
312       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
313       PetscFunctionReturn(0);
314     }
315   } else snes->vec_func_init_set = PETSC_FALSE;
316 
317   if (snes->jacobian) {         /* This method does not require a Jacobian, but it is usually preconditioned by PBJacobi */
318     ierr = SNESComputeJacobian(snes,snes->vec_sol,&snes->jacobian,&snes->jacobian_pre,&mstruct);CHKERRQ(ierr);
319     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,mstruct);CHKERRQ(ierr);
320   }
321   if (ms->norms) {
322     if (!snes->norm_init_set) {
323       ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
324       if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm");
325     } else {
326       fnorm               = snes->norm_init;
327       snes->norm_init_set = PETSC_FALSE;
328     }
329     /* Monitor convergence */
330     ierr       = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
331     snes->iter = 0;
332     snes->norm = fnorm;
333     ierr       = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
334     ierr       = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr);
335     ierr       = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
336 
337     /* set parameter for default relative tolerance convergence test */
338     snes->ttol = fnorm*snes->rtol;
339     /* Test for convergence */
340     ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
341     if (snes->reason) PetscFunctionReturn(0);
342   }
343 
344   /* Call general purpose update function */
345   if (snes->ops->update) {
346     ierr = (*snes->ops->update)(snes,snes->iter);CHKERRQ(ierr);
347   }
348   for (i = 0; i < snes->max_its; i++) {
349     ierr = SNESMSStep_3Sstar(snes,X,F);CHKERRQ(ierr);
350 
351     if (i+1 < snes->max_its || ms->norms) {
352       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
353       if (snes->domainerror) {
354         snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
355         PetscFunctionReturn(0);
356       }
357     }
358 
359     if (ms->norms) {
360       ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
361       if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm");
362       /* Monitor convergence */
363       ierr       = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
364       snes->iter = i+1;
365       snes->norm = fnorm;
366       ierr       = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
367       ierr       = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr);
368       ierr       = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
369 
370       /* Test for convergence */
371       ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
372       if (snes->reason) PetscFunctionReturn(0);
373     }
374 
375     /* Call general purpose update function */
376     if (snes->ops->update) {
377       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
378     }
379   }
380   if (!snes->reason) snes->reason = SNES_CONVERGED_ITS;
381   PetscFunctionReturn(0);
382 }
383 
384 #undef __FUNCT__
385 #define __FUNCT__ "SNESSetUp_MS"
386 static PetscErrorCode SNESSetUp_MS(SNES snes)
387 {
388   SNES_MS        *ms = (SNES_MS*)snes->data;
389   PetscErrorCode ierr;
390 
391   PetscFunctionBegin;
392   if (!ms->tableau) {ierr = SNESMSSetType(snes,SNESMSDefault);CHKERRQ(ierr);}
393   ierr = SNESDefaultGetWork(snes,3);CHKERRQ(ierr);
394   ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
395   PetscFunctionReturn(0);
396 }
397 
398 #undef __FUNCT__
399 #define __FUNCT__ "SNESReset_MS"
400 static PetscErrorCode SNESReset_MS(SNES snes)
401 {
402 
403   PetscFunctionBegin;
404   PetscFunctionReturn(0);
405 }
406 
407 #undef __FUNCT__
408 #define __FUNCT__ "SNESDestroy_MS"
409 static PetscErrorCode SNESDestroy_MS(SNES snes)
410 {
411   PetscErrorCode ierr;
412 
413   PetscFunctionBegin;
414   ierr = PetscFree(snes->data);CHKERRQ(ierr);
415   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"","",NULL);CHKERRQ(ierr);
416   PetscFunctionReturn(0);
417 }
418 
419 #undef __FUNCT__
420 #define __FUNCT__ "SNESView_MS"
421 static PetscErrorCode SNESView_MS(SNES snes,PetscViewer viewer)
422 {
423   PetscBool      iascii;
424   PetscErrorCode ierr;
425   SNES_MS        *ms = (SNES_MS*)snes->data;
426 
427   PetscFunctionBegin;
428   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
429   if (iascii) {
430     SNESMSTableau tab = ms->tableau;
431     ierr = PetscViewerASCIIPrintf(viewer,"  multi-stage method type: %s\n",tab ? tab->name : "not yet set");CHKERRQ(ierr);
432   }
433   PetscFunctionReturn(0);
434 }
435 
436 #undef __FUNCT__
437 #define __FUNCT__ "SNESSetFromOptions_MS"
438 static PetscErrorCode SNESSetFromOptions_MS(SNES snes)
439 {
440   SNES_MS        *ms = (SNES_MS*)snes->data;
441   PetscErrorCode ierr;
442 
443   PetscFunctionBegin;
444   ierr = PetscOptionsHead("SNES MS options");CHKERRQ(ierr);
445   {
446     SNESMSTableauLink link;
447     PetscInt          count,choice;
448     PetscBool         flg;
449     const char        **namelist;
450     char              mstype[256];
451 
452     ierr = PetscStrncpy(mstype,SNESMSDefault,sizeof(mstype));CHKERRQ(ierr);
453     for (link=SNESMSTableauList,count=0; link; link=link->next,count++) ;
454     ierr = PetscMalloc(count*sizeof(char*),&namelist);CHKERRQ(ierr);
455     for (link=SNESMSTableauList,count=0; link; link=link->next,count++) namelist[count] = link->tab.name;
456     ierr = PetscOptionsEList("-snes_ms_type","Multistage smoother type","SNESMSSetType",(const char*const*)namelist,count,mstype,&choice,&flg);CHKERRQ(ierr);
457     ierr = SNESMSSetType(snes,flg ? namelist[choice] : mstype);CHKERRQ(ierr);
458     ierr = PetscFree(namelist);CHKERRQ(ierr);
459     ierr = PetscOptionsReal("-snes_ms_damping","Damping for multistage method","SNESMSSetDamping",ms->damping,&ms->damping,NULL);CHKERRQ(ierr);
460     ierr = PetscOptionsBool("-snes_ms_norms","Compute norms for monitoring","none",ms->norms,&ms->norms,NULL);CHKERRQ(ierr);
461   }
462   ierr = PetscOptionsTail();CHKERRQ(ierr);
463   PetscFunctionReturn(0);
464 }
465 
466 EXTERN_C_BEGIN
467 #undef __FUNCT__
468 #define __FUNCT__ "SNESMSSetType_MS"
469 PetscErrorCode  SNESMSSetType_MS(SNES snes,SNESMSType mstype)
470 {
471   PetscErrorCode    ierr;
472   SNES_MS           *ms = (SNES_MS*)snes->data;
473   SNESMSTableauLink link;
474   PetscBool         match;
475 
476   PetscFunctionBegin;
477   if (ms->tableau) {
478     ierr = PetscStrcmp(ms->tableau->name,mstype,&match);CHKERRQ(ierr);
479     if (match) PetscFunctionReturn(0);
480   }
481   for (link = SNESMSTableauList; link; link=link->next) {
482     ierr = PetscStrcmp(link->tab.name,mstype,&match);CHKERRQ(ierr);
483     if (match) {
484       ierr        = SNESReset_MS(snes);CHKERRQ(ierr);
485       ms->tableau = &link->tab;
486       PetscFunctionReturn(0);
487     }
488   }
489   SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_ARG_UNKNOWN_TYPE,"Could not find '%s'",mstype);
490   PetscFunctionReturn(0);
491 }
492 EXTERN_C_END
493 
494 
495 #undef __FUNCT__
496 #define __FUNCT__ "SNESMSSetType"
497 /*@C
498   SNESMSSetType - Set the type of multistage smoother
499 
500   Logically collective
501 
502   Input Parameter:
503 +  snes - nonlinear solver context
504 -  mstype - type of multistage method
505 
506   Level: beginner
507 
508 .seealso: SNESMSGetType(), SNESMS
509 @*/
510 PetscErrorCode SNESMSSetType(SNES snes,SNESMSType rostype)
511 {
512   PetscErrorCode ierr;
513 
514   PetscFunctionBegin;
515   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
516   ierr = PetscTryMethod(snes,"SNESMSSetType_C",(SNES,SNESMSType),(snes,rostype));CHKERRQ(ierr);
517   PetscFunctionReturn(0);
518 }
519 
520 /* -------------------------------------------------------------------------- */
521 /*MC
522       SNESMS - multi-stage smoothers
523 
524       Options Database:
525 
526 +     -snes_ms_type - type of multi-stage smoother
527 -     -snes_ms_damping - damping for multi-stage method
528 
529       Notes:
530       These multistage methods are explicit Runge-Kutta methods that are often used as smoothers for
531       FAS multigrid for transport problems. In the linear case, these are equivalent to polynomial smoothers (such as Chebyshev).
532 
533       Multi-stage smoothers should usually be preconditioned by point-block Jacobi to ensure proper scaling and to normalize the wave speeds.
534 
535       The methods are specified in low storage form (Ketcheson 2010). New methods can be registered with SNESMSRegister().
536 
537       References:
538 
539       Ketcheson (2010) Runge-Kutta methods with minimum storage implementations.
540 
541       Jameson (1983) Solution of the Euler equations for two dimensional transonic flow by a multigrid method.
542 
543       Pierce and Giles (1997) Preconditioned multigrid methods for compressible flow calculations on stretched meshes.
544 
545       Level: beginner
546 
547 .seealso:  SNESCreate(), SNES, SNESSetType(), SNESMS, SNESFAS, KSPCHEBYSHEV
548 
549 M*/
550 EXTERN_C_BEGIN
551 #undef __FUNCT__
552 #define __FUNCT__ "SNESCreate_MS"
553 PetscErrorCode  SNESCreate_MS(SNES snes)
554 {
555   PetscErrorCode ierr;
556   SNES_MS        *ms;
557 
558   PetscFunctionBegin;
559 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
560   ierr = SNESMSInitializePackage(NULL);CHKERRQ(ierr);
561 #endif
562 
563   snes->ops->setup          = SNESSetUp_MS;
564   snes->ops->solve          = SNESSolve_MS;
565   snes->ops->destroy        = SNESDestroy_MS;
566   snes->ops->setfromoptions = SNESSetFromOptions_MS;
567   snes->ops->view           = SNESView_MS;
568   snes->ops->reset          = SNESReset_MS;
569 
570   snes->usespc  = PETSC_FALSE;
571   snes->usesksp = PETSC_TRUE;
572 
573   ierr        = PetscNewLog(snes,SNES_MS,&ms);CHKERRQ(ierr);
574   snes->data  = (void*)ms;
575   ms->damping = 0.9;
576   ms->norms   = PETSC_FALSE;
577 
578   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESMSSetType_C","SNESMSSetType_MS",SNESMSSetType_MS);CHKERRQ(ierr);
579   PetscFunctionReturn(0);
580 }
581 EXTERN_C_END
582