xref: /petsc/src/snes/impls/ms/ms.c (revision 5b6bfdb9644f185dbf5e5a09b808ec241507e1e7)
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 PetscDLLibraryRegister() when using dynamic libraries, and on the first call to SNESCreate_MS()
137   when using static libraries.
138 
139   Level: developer
140 
141 .keywords: SNES, SNESMS, initialize, package
142 .seealso: PetscInitialize()
143 @*/
144 PetscErrorCode SNESMSInitializePackage(void)
145 {
146   PetscErrorCode ierr;
147 
148   PetscFunctionBegin;
149   if (SNESMSPackageInitialized) PetscFunctionReturn(0);
150   SNESMSPackageInitialized = PETSC_TRUE;
151 
152   ierr = SNESMSRegisterAll();CHKERRQ(ierr);
153   ierr = PetscRegisterFinalize(SNESMSFinalizePackage);CHKERRQ(ierr);
154   PetscFunctionReturn(0);
155 }
156 
157 /*@C
158   SNESMSFinalizePackage - This function destroys everything in the SNESMS package. It is
159   called from PetscFinalize().
160 
161   Level: developer
162 
163 .keywords: Petsc, destroy, package
164 .seealso: PetscFinalize()
165 @*/
166 PetscErrorCode SNESMSFinalizePackage(void)
167 {
168   PetscErrorCode ierr;
169 
170   PetscFunctionBegin;
171   SNESMSPackageInitialized = PETSC_FALSE;
172 
173   ierr = SNESMSRegisterDestroy();CHKERRQ(ierr);
174   PetscFunctionReturn(0);
175 }
176 
177 /*@C
178    SNESMSRegister - register a multistage scheme
179 
180    Not Collective, but the same schemes should be registered on all processes on which they will be used
181 
182    Input Parameters:
183 +  name - identifier for method
184 .  nstages - number of stages
185 .  nregisters - number of registers used by low-storage implementation
186 .  gamma - coefficients, see Ketcheson's paper
187 .  delta - coefficients, see Ketcheson's paper
188 -  betasub - subdiagonal of Shu-Osher form
189 
190    Notes:
191    The notation is described in Ketcheson (2010) Runge-Kutta methods with minimum storage implementations.
192 
193    Level: advanced
194 
195 .keywords: SNES, register
196 
197 .seealso: SNESMS
198 @*/
199 PetscErrorCode SNESMSRegister(SNESMSType name,PetscInt nstages,PetscInt nregisters,PetscReal stability,const PetscReal gamma[],const PetscReal delta[],const PetscReal betasub[])
200 {
201   PetscErrorCode    ierr;
202   SNESMSTableauLink link;
203   SNESMSTableau     t;
204 
205   PetscFunctionBegin;
206   PetscValidCharPointer(name,1);
207   if (nstages < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must have at least one stage");
208   if (nregisters != 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only support for methods written in 3-register form");
209   PetscValidPointer(gamma,4);
210   PetscValidPointer(delta,5);
211   PetscValidPointer(betasub,6);
212 
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   }
296   if (ms->norms) {
297     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
298     SNESCheckFunctionNorm(snes,fnorm);
299     /* Monitor convergence */
300     ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
301     snes->iter = 0;
302     snes->norm = fnorm;
303     ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
304     ierr       = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr);
305     ierr       = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
306 
307     /* Test for convergence */
308     ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
309     if (snes->reason) PetscFunctionReturn(0);
310   }
311 
312   /* Call general purpose update function */
313   if (snes->ops->update) {
314     ierr = (*snes->ops->update)(snes,snes->iter);CHKERRQ(ierr);
315   }
316   for (i = 0; i < snes->max_its; i++) {
317     ierr = SNESMSStep_3Sstar(snes,X,F);CHKERRQ(ierr);
318 
319     if (i+1 < snes->max_its || ms->norms) {
320       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
321     }
322 
323     if (ms->norms) {
324       ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
325       SNESCheckFunctionNorm(snes,fnorm);
326 
327       /* Monitor convergence */
328       ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
329       snes->iter = i+1;
330       snes->norm = fnorm;
331       ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
332       ierr       = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr);
333       ierr       = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
334 
335       /* Test for convergence */
336       ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
337       if (snes->reason) PetscFunctionReturn(0);
338     }
339 
340     /* Call general purpose update function */
341     if (snes->ops->update) {
342       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
343     }
344   }
345   if (!snes->reason) snes->reason = SNES_CONVERGED_ITS;
346   PetscFunctionReturn(0);
347 }
348 
349 static PetscErrorCode SNESSetUp_MS(SNES snes)
350 {
351   SNES_MS        *ms = (SNES_MS*)snes->data;
352   PetscErrorCode ierr;
353 
354   PetscFunctionBegin;
355   if (!ms->tableau) {ierr = SNESMSSetType(snes,SNESMSDefault);CHKERRQ(ierr);}
356   ierr = SNESSetWorkVecs(snes,3);CHKERRQ(ierr);
357   ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
358   PetscFunctionReturn(0);
359 }
360 
361 static PetscErrorCode SNESReset_MS(SNES snes)
362 {
363 
364   PetscFunctionBegin;
365   PetscFunctionReturn(0);
366 }
367 
368 static PetscErrorCode SNESDestroy_MS(SNES snes)
369 {
370   PetscErrorCode ierr;
371 
372   PetscFunctionBegin;
373   ierr = PetscFree(snes->data);CHKERRQ(ierr);
374   ierr = PetscObjectComposeFunction((PetscObject)snes,"",NULL);CHKERRQ(ierr);
375   PetscFunctionReturn(0);
376 }
377 
378 static PetscErrorCode SNESView_MS(SNES snes,PetscViewer viewer)
379 {
380   PetscBool      iascii;
381   PetscErrorCode ierr;
382   SNES_MS        *ms = (SNES_MS*)snes->data;
383 
384   PetscFunctionBegin;
385   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
386   if (iascii) {
387     SNESMSTableau tab = ms->tableau;
388     ierr = PetscViewerASCIIPrintf(viewer,"  multi-stage method type: %s\n",tab ? tab->name : "not yet set");CHKERRQ(ierr);
389   }
390   PetscFunctionReturn(0);
391 }
392 
393 static PetscErrorCode SNESSetFromOptions_MS(PetscOptionItems *PetscOptionsObject,SNES snes)
394 {
395   SNES_MS        *ms = (SNES_MS*)snes->data;
396   PetscErrorCode ierr;
397 
398   PetscFunctionBegin;
399   ierr = PetscOptionsHead(PetscOptionsObject,"SNES MS options");CHKERRQ(ierr);
400   {
401     SNESMSTableauLink link;
402     PetscInt          count,choice;
403     PetscBool         flg;
404     const char        **namelist;
405     char              mstype[256];
406 
407     ierr = PetscStrncpy(mstype,SNESMSDefault,sizeof(mstype));CHKERRQ(ierr);
408     for (link=SNESMSTableauList,count=0; link; link=link->next,count++) ;
409     ierr = PetscMalloc1(count,(char***)&namelist);CHKERRQ(ierr);
410     for (link=SNESMSTableauList,count=0; link; link=link->next,count++) namelist[count] = link->tab.name;
411     ierr = PetscOptionsEList("-snes_ms_type","Multistage smoother type","SNESMSSetType",(const char*const*)namelist,count,mstype,&choice,&flg);CHKERRQ(ierr);
412     ierr = SNESMSSetType(snes,flg ? namelist[choice] : mstype);CHKERRQ(ierr);
413     ierr = PetscFree(namelist);CHKERRQ(ierr);
414     ierr = PetscOptionsReal("-snes_ms_damping","Damping for multistage method","SNESMSSetDamping",ms->damping,&ms->damping,NULL);CHKERRQ(ierr);
415     ierr = PetscOptionsBool("-snes_ms_norms","Compute norms for monitoring","none",ms->norms,&ms->norms,NULL);CHKERRQ(ierr);
416   }
417   ierr = PetscOptionsTail();CHKERRQ(ierr);
418   PetscFunctionReturn(0);
419 }
420 
421 PetscErrorCode  SNESMSSetType_MS(SNES snes,SNESMSType mstype)
422 {
423   PetscErrorCode    ierr;
424   SNES_MS           *ms = (SNES_MS*)snes->data;
425   SNESMSTableauLink link;
426   PetscBool         match;
427 
428   PetscFunctionBegin;
429   if (ms->tableau) {
430     ierr = PetscStrcmp(ms->tableau->name,mstype,&match);CHKERRQ(ierr);
431     if (match) PetscFunctionReturn(0);
432   }
433   for (link = SNESMSTableauList; link; link=link->next) {
434     ierr = PetscStrcmp(link->tab.name,mstype,&match);CHKERRQ(ierr);
435     if (match) {
436       ierr        = SNESReset_MS(snes);CHKERRQ(ierr);
437       ms->tableau = &link->tab;
438       PetscFunctionReturn(0);
439     }
440   }
441   SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_UNKNOWN_TYPE,"Could not find '%s'",mstype);
442   PetscFunctionReturn(0);
443 }
444 
445 /*@C
446   SNESMSSetType - Set the type of multistage smoother
447 
448   Logically collective
449 
450   Input Parameter:
451 +  snes - nonlinear solver context
452 -  mstype - type of multistage method
453 
454   Level: beginner
455 
456 .seealso: SNESMSGetType(), SNESMS
457 @*/
458 PetscErrorCode SNESMSSetType(SNES snes,SNESMSType rostype)
459 {
460   PetscErrorCode ierr;
461 
462   PetscFunctionBegin;
463   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
464   ierr = PetscTryMethod(snes,"SNESMSSetType_C",(SNES,SNESMSType),(snes,rostype));CHKERRQ(ierr);
465   PetscFunctionReturn(0);
466 }
467 
468 /* -------------------------------------------------------------------------- */
469 /*MC
470       SNESMS - multi-stage smoothers
471 
472       Options Database:
473 
474 +     -snes_ms_type - type of multi-stage smoother
475 -     -snes_ms_damping - damping for multi-stage method
476 
477       Notes:
478       These multistage methods are explicit Runge-Kutta methods that are often used as smoothers for
479       FAS multigrid for transport problems. In the linear case, these are equivalent to polynomial smoothers (such as Chebyshev).
480 
481       Multi-stage smoothers should usually be preconditioned by point-block Jacobi to ensure proper scaling and to normalize the wave speeds.
482 
483       The methods are specified in low storage form (Ketcheson 2010). New methods can be registered with SNESMSRegister().
484 
485       References:
486 +   1. -   Ketcheson (2010) Runge Kutta methods with minimum storage implementations.
487 .   2. -   Jameson (1983) Solution of the Euler equations for two dimensional transonic flow by a multigrid method.
488 -   3. -   Pierce and Giles (1997) Preconditioned multigrid methods for compressible flow calculations on stretched meshes.
489 
490       Level: beginner
491 
492 .seealso:  SNESCreate(), SNES, SNESSetType(), SNESMS, SNESFAS, KSPCHEBYSHEV
493 
494 M*/
495 PETSC_EXTERN PetscErrorCode SNESCreate_MS(SNES snes)
496 {
497   PetscErrorCode ierr;
498   SNES_MS        *ms;
499 
500   PetscFunctionBegin;
501   ierr = SNESMSInitializePackage();CHKERRQ(ierr);
502 
503   snes->ops->setup          = SNESSetUp_MS;
504   snes->ops->solve          = SNESSolve_MS;
505   snes->ops->destroy        = SNESDestroy_MS;
506   snes->ops->setfromoptions = SNESSetFromOptions_MS;
507   snes->ops->view           = SNESView_MS;
508   snes->ops->reset          = SNESReset_MS;
509 
510   snes->usesnpc = PETSC_FALSE;
511   snes->usesksp = PETSC_TRUE;
512 
513   snes->alwayscomputesfinalresidual = PETSC_FALSE;
514 
515   ierr        = PetscNewLog(snes,&ms);CHKERRQ(ierr);
516   snes->data  = (void*)ms;
517   ms->damping = 0.9;
518   ms->norms   = PETSC_FALSE;
519 
520   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESMSSetType_C",SNESMSSetType_MS);CHKERRQ(ierr);
521   PetscFunctionReturn(0);
522 }
523 
524