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