xref: /petsc/src/snes/impls/fas/fas.c (revision 9c44eddc3abd5ec499e19db53d7a9ea05dfa3e9e)
1 /* Defines the basic SNES object */
2 #include <../src/snes/impls/fas/fasimpls.h>    /*I  "petscsnesfas.h"  I*/
3 
4 const char *SNESFASTypes[] = {"MULTIPLICATIVE","ADDITIVE","SNESFASType","SNES_FAS",0};
5 
6 /*MC
7 
8 SNESFAS - Full Approximation Scheme nonlinear multigrid solver.
9 
10 The nonlinear problem is solved via the repeated application of nonlinear preconditioners and coarse-grid corrections
11 
12 .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
13 M*/
14 
15 extern PetscErrorCode SNESDestroy_FAS(SNES snes);
16 extern PetscErrorCode SNESSetUp_FAS(SNES snes);
17 extern PetscErrorCode SNESSetFromOptions_FAS(SNES snes);
18 extern PetscErrorCode SNESView_FAS(SNES snes, PetscViewer viewer);
19 extern PetscErrorCode SNESSolve_FAS(SNES snes);
20 extern PetscErrorCode SNESReset_FAS(SNES snes);
21 extern PetscErrorCode SNESFASGalerkinDefaultFunction(SNES, Vec, Vec, void *);
22 
23 EXTERN_C_BEGIN
24 #undef __FUNCT__
25 #define __FUNCT__ "SNESLineSearchSetType_FAS"
26 PetscErrorCode  SNESLineSearchSetType_FAS(SNES snes, SNESLineSearchType type)
27 {
28   PetscErrorCode ierr;
29   PetscFunctionBegin;
30 
31   switch (type) {
32   case SNES_LS_BASIC:
33     ierr = SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);CHKERRQ(ierr);
34     break;
35   case SNES_LS_BASIC_NONORMS:
36     ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr);
37     break;
38   case SNES_LS_QUADRATIC:
39     ierr = SNESLineSearchSet(snes,SNESLineSearchQuadraticSecant,PETSC_NULL);CHKERRQ(ierr);
40     break;
41   default:
42     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP,"Unknown line search type.");
43     break;
44   }
45   snes->ls_type = type;
46   PetscFunctionReturn(0);
47 }
48 EXTERN_C_END
49 
50 EXTERN_C_BEGIN
51 
52 #undef __FUNCT__
53 #define __FUNCT__ "SNESCreate_FAS"
54 PetscErrorCode SNESCreate_FAS(SNES snes)
55 {
56   SNES_FAS * fas;
57   PetscErrorCode ierr;
58 
59   PetscFunctionBegin;
60   snes->ops->destroy        = SNESDestroy_FAS;
61   snes->ops->setup          = SNESSetUp_FAS;
62   snes->ops->setfromoptions = SNESSetFromOptions_FAS;
63   snes->ops->view           = SNESView_FAS;
64   snes->ops->solve          = SNESSolve_FAS;
65   snes->ops->reset          = SNESReset_FAS;
66 
67   snes->usesksp             = PETSC_FALSE;
68   snes->usespc              = PETSC_FALSE;
69 
70   ierr = PetscNewLog(snes, SNES_FAS, &fas);CHKERRQ(ierr);
71   snes->data                  = (void*) fas;
72   fas->level                  = 0;
73   fas->levels                 = 1;
74   fas->n_cycles               = 1;
75   fas->max_up_it              = 1;
76   fas->max_down_it            = 1;
77   fas->upsmooth               = PETSC_NULL;
78   fas->downsmooth             = PETSC_NULL;
79   fas->next                   = PETSC_NULL;
80   fas->previous               = PETSC_NULL;
81   fas->interpolate            = PETSC_NULL;
82   fas->restrct                = PETSC_NULL;
83   fas->inject                 = PETSC_NULL;
84   fas->monitor                = PETSC_NULL;
85   fas->usedmfornumberoflevels = PETSC_FALSE;
86   fas->fastype                = SNES_FAS_MULTIPLICATIVE;
87 
88   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetType_C","SNESLineSearchSetType_FAS",SNESLineSearchSetType_FAS);CHKERRQ(ierr);
89   ierr = SNESLineSearchSetType(snes, SNES_LS_QUADRATIC);CHKERRQ(ierr);
90 
91   PetscFunctionReturn(0);
92 }
93 EXTERN_C_END
94 
95 #undef __FUNCT__
96 #define __FUNCT__ "SNESFASGetLevels"
97 /*@
98    SNESFASGetLevels - Gets the number of levels in a FAS.
99 
100    Input Parameter:
101 .  snes - the preconditioner context
102 
103    Output parameter:
104 .  levels - the number of levels
105 
106    Level: advanced
107 
108 .keywords: MG, get, levels, multigrid
109 
110 .seealso: SNESFASSetLevels(), PCMGGetLevels()
111 @*/
112 PetscErrorCode SNESFASGetLevels(SNES snes, PetscInt * levels) {
113   SNES_FAS * fas = (SNES_FAS *)snes->data;
114   PetscFunctionBegin;
115   *levels = fas->levels;
116   PetscFunctionReturn(0);
117 }
118 
119 #undef __FUNCT__
120 #define __FUNCT__ "SNESFASSetCycles"
121 /*@
122    SNESFASSetCycles - Sets the type cycles to use.  Use SNESFASSetCyclesOnLevel() for more
123    complicated cycling.
124 
125    Logically Collective on SNES
126 
127    Input Parameters:
128 +  snes   - the multigrid context
129 -  cycles - the number of cycles -- 1 for V-cycle, 2 for W-cycle
130 
131    Options Database Key:
132 $  -snes_fas_cycles 1 or 2
133 
134    Level: advanced
135 
136 .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
137 
138 .seealso: SNESFASSetCyclesOnLevel()
139 @*/
140 PetscErrorCode SNESFASSetCycles(SNES snes, PetscInt cycles) {
141   SNES_FAS * fas = (SNES_FAS *)snes->data;
142   PetscErrorCode ierr;
143   PetscFunctionBegin;
144   fas->n_cycles = cycles;
145   if (fas->next) {
146     ierr = SNESFASSetCycles(fas->next, cycles);CHKERRQ(ierr);
147   }
148   PetscFunctionReturn(0);
149 }
150 
151 #undef __FUNCT__
152 #define __FUNCT__ "SNESFASSetCyclesOnLevel"
153 /*@
154    SNESFASSetCyclesOnLevel - Sets the type cycles to use on a particular level.
155 
156    Logically Collective on SNES
157 
158    Input Parameters:
159 +  snes   - the multigrid context
160 .  level  - the level to set the number of cycles on
161 -  cycles - the number of cycles -- 1 for V-cycle, 2 for W-cycle
162 
163    Level: advanced
164 
165 .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
166 
167 .seealso: SNESFASSetCycles()
168 @*/
169 PetscErrorCode SNESFASSetCyclesOnLevel(SNES snes, PetscInt level, PetscInt cycles) {
170   SNES_FAS * fas =  (SNES_FAS *)snes->data;
171   PetscInt top_level = fas->level,i;
172 
173   PetscFunctionBegin;
174   if (level > top_level)
175     SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetCyclesOnLevel", level);
176   /* get to the correct level */
177   for (i = fas->level; i > level; i--) {
178     fas = (SNES_FAS *)fas->next->data;
179   }
180   if (fas->level != level)
181     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetCyclesOnLevel");
182   fas->n_cycles = cycles;
183   PetscFunctionReturn(0);
184 }
185 
186 #undef __FUNCT__
187 #define __FUNCT__ "SNESFASSetGS"
188 /*@C
189    SNESFASSetGS - Sets a nonlinear GS smoother and if it should be used.
190    Use SNESFASSetGSOnLevel() for more complicated staging of smoothers
191    and nonlinear preconditioners.
192 
193    Logically Collective on SNES
194 
195    Input Parameters:
196 +  snes    - the multigrid context
197 .  gsfunc  - the nonlinear smoother function
198 .  ctx     - the user context for the nonlinear smoother
199 -  use_gs  - whether to use the nonlinear smoother or not
200 
201    Level: advanced
202 
203 .keywords: FAS, MG, set, cycles, gauss-seidel, multigrid
204 
205 .seealso: SNESSetGS(), SNESFASSetGSOnLevel()
206 @*/
207 PetscErrorCode SNESFASSetGS(SNES snes, PetscErrorCode (*gsfunc)(SNES,Vec,Vec,void *), void * ctx, PetscBool use_gs) {
208   PetscErrorCode ierr = 0;
209   SNES_FAS       *fas = (SNES_FAS *)snes->data;
210   PetscFunctionBegin;
211 
212   /* use or don't use it according to user wishes*/
213   snes->usegs = use_gs;
214   if (gsfunc) {
215     ierr = SNESSetGS(snes, gsfunc, ctx);CHKERRQ(ierr);
216     /* push the provided GS up the tree */
217     if (fas->next) ierr = SNESFASSetGS(fas->next, gsfunc, ctx, use_gs);CHKERRQ(ierr);
218   } else if (snes->ops->computegs) {
219     /* assume that the user has set the GS solver at this level */
220     if (fas->next) ierr = SNESFASSetGS(fas->next, PETSC_NULL, PETSC_NULL, use_gs);CHKERRQ(ierr);
221   } else if (use_gs) {
222     SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "No user Gauss-Seidel function provided in SNESFASSetGS on level %d", fas->level);
223   }
224   PetscFunctionReturn(0);
225 }
226 
227 #undef __FUNCT__
228 #define __FUNCT__ "SNESFASSetGSOnLevel"
229 /*@C
230    SNESFASSetGSOnLevel - Sets the nonlinear smoother on a particular level.
231 
232    Logically Collective on SNES
233 
234    Input Parameters:
235 +  snes    - the multigrid context
236 .  level   - the level to set the nonlinear smoother on
237 .  gsfunc  - the nonlinear smoother function
238 .  ctx     - the user context for the nonlinear smoother
239 -  use_gs  - whether to use the nonlinear smoother or not
240 
241    Level: advanced
242 
243 .keywords: FAS, MG, set, cycles, Gauss-Seidel, multigrid
244 
245 .seealso: SNESSetGS(), SNESFASSetGS()
246 @*/
247 PetscErrorCode SNESFASSetGSOnLevel(SNES snes, PetscInt level, PetscErrorCode (*gsfunc)(SNES,Vec,Vec,void *), void * ctx, PetscBool use_gs) {
248   SNES_FAS       *fas =  (SNES_FAS *)snes->data;
249   PetscErrorCode ierr;
250   PetscInt       top_level = fas->level,i;
251   SNES           cur_snes = snes;
252   PetscFunctionBegin;
253   if (level > top_level)
254     SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetCyclesOnLevel", level);
255   /* get to the correct level */
256   for (i = fas->level; i > level; i--) {
257     fas = (SNES_FAS *)fas->next->data;
258     cur_snes = fas->next;
259   }
260   if (fas->level != level)
261     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetCyclesOnLevel");
262   snes->usegs = use_gs;
263   if (gsfunc) {
264     ierr = SNESSetGS(cur_snes, gsfunc, ctx);CHKERRQ(ierr);
265   }
266   PetscFunctionReturn(0);
267 }
268 
269 #undef __FUNCT__
270 #define __FUNCT__ "SNESFASGetSNES"
271 /*@
272    SNESFASGetSNES - Gets the SNES corresponding to a particular
273    level of the FAS hierarchy.
274 
275    Input Parameters:
276 +  snes    - the multigrid context
277    level   - the level to get
278 -  lsnes   - whether to use the nonlinear smoother or not
279 
280    Level: advanced
281 
282 .keywords: FAS, MG, set, cycles, Gauss-Seidel, multigrid
283 
284 .seealso: SNESFASSetLevels(), SNESFASGetLevels()
285 @*/
286 PetscErrorCode SNESFASGetSNES(SNES snes, PetscInt level, SNES * lsnes) {
287   SNES_FAS * fas = (SNES_FAS *)snes->data;
288   PetscInt levels = fas->level;
289   PetscInt i;
290   PetscFunctionBegin;
291   *lsnes = snes;
292   if (fas->level < level) {
293     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "SNESFASGetSNES should only be called on a finer SNESFAS instance than the level.");
294   }
295   if (level > levels - 1) {
296     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Level %d doesn't exist in the SNESFAS.");
297   }
298   for (i = fas->level; i > level; i--) {
299     *lsnes = fas->next;
300     fas = (SNES_FAS *)(*lsnes)->data;
301   }
302   if (fas->level != level) SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "SNESFASGetSNES didn't return the right level!");
303   PetscFunctionReturn(0);
304 }
305 
306 #undef __FUNCT__
307 #define __FUNCT__ "SNESFASSetType"
308 /*@
309 SNESFASSetType - Sets the update and correction type used for FAS.
310 e
311 
312 
313 @*/
314 PetscErrorCode  SNESFASSetType(SNES snes,SNESFASType fastype)
315 {
316   SNES_FAS                   *fas = (SNES_FAS*)snes->data;
317 
318   PetscFunctionBegin;
319   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
320   PetscValidLogicalCollectiveEnum(snes,fastype,2);
321   fas->fastype = fastype;
322   PetscFunctionReturn(0);
323 }
324 
325 
326 
327 #undef __FUNCT__
328 #define __FUNCT__ "SNESFASSetLevels"
329 /*@C
330    SNESFASSetLevels - Sets the number of levels to use with FAS.
331    Must be called before any other FAS routine.
332 
333    Input Parameters:
334 +  snes   - the snes context
335 .  levels - the number of levels
336 -  comms  - optional communicators for each level; this is to allow solving the coarser
337             problems on smaller sets of processors. Use PETSC_NULL_OBJECT for default in
338             Fortran.
339 
340    Level: intermediate
341 
342    Notes:
343      If the number of levels is one then the multigrid uses the -fas_levels prefix
344   for setting the level options rather than the -fas_coarse prefix.
345 
346 .keywords: FAS, MG, set, levels, multigrid
347 
348 .seealso: SNESFASGetLevels()
349 @*/
350 PetscErrorCode SNESFASSetLevels(SNES snes, PetscInt levels, MPI_Comm * comms) {
351   PetscErrorCode ierr;
352   PetscInt i;
353   SNES_FAS * fas = (SNES_FAS *)snes->data;
354   SNES prevsnes;
355   MPI_Comm comm;
356   PetscFunctionBegin;
357   comm = ((PetscObject)snes)->comm;
358   if (levels == fas->levels) {
359     if (!comms)
360       PetscFunctionReturn(0);
361   }
362   /* user has changed the number of levels; reset */
363   ierr = SNESReset(snes);CHKERRQ(ierr);
364   /* destroy any coarser levels if necessary */
365   if (fas->next) SNESDestroy(&fas->next);CHKERRQ(ierr);
366   fas->next = PETSC_NULL;
367   fas->previous = PETSC_NULL;
368   prevsnes = snes;
369   /* setup the finest level */
370   for (i = levels - 1; i >= 0; i--) {
371     if (comms) comm = comms[i];
372     fas->level = i;
373     fas->levels = levels;
374     fas->next = PETSC_NULL;
375     if (i > 0) {
376       ierr = SNESCreate(comm, &fas->next);CHKERRQ(ierr);
377       ierr = SNESSetOptionsPrefix(fas->next,((PetscObject)snes)->prefix);CHKERRQ(ierr);
378       ierr = SNESSetType(fas->next, SNESFAS);CHKERRQ(ierr);
379       ierr = PetscObjectIncrementTabLevel((PetscObject)fas->next, (PetscObject)snes, levels - i);CHKERRQ(ierr);
380       ((SNES_FAS *)fas->next->data)->previous = prevsnes;
381       prevsnes = fas->next;
382       fas = (SNES_FAS *)prevsnes->data;
383     }
384   }
385   PetscFunctionReturn(0);
386 }
387 
388 #undef __FUNCT__
389 #define __FUNCT__ "SNESFASSetNumberSmoothUp"
390 /*@
391    SNESFASSetNumberSmoothUp - Sets the number of post-smoothing steps to
392    use on all levels.
393 
394    Logically Collective on PC
395 
396    Input Parameters:
397 +  snes - the multigrid context
398 -  n    - the number of smoothing steps
399 
400    Options Database Key:
401 .  -snes_fas_smoothup <n> - Sets number of pre-smoothing steps
402 
403    Level: advanced
404 
405 .keywords: FAS, MG, smooth, down, pre-smoothing, steps, multigrid
406 
407 .seealso: SNESFASSetNumberSmoothDown()
408 @*/
409 PetscErrorCode SNESFASSetNumberSmoothUp(SNES snes, PetscInt n) {
410   SNES_FAS * fas =  (SNES_FAS *)snes->data;
411   PetscErrorCode ierr = 0;
412   PetscFunctionBegin;
413   fas->max_up_it = n;
414   if (fas->next) {
415     ierr = SNESFASSetNumberSmoothUp(fas->next, n);CHKERRQ(ierr);
416   }
417   PetscFunctionReturn(0);
418 }
419 
420 #undef __FUNCT__
421 #define __FUNCT__ "SNESFASSetNumberSmoothDown"
422 /*@
423    SNESFASSetNumberSmoothDown - Sets the number of pre-smoothing steps to
424    use on all levels.
425 
426    Logically Collective on PC
427 
428    Input Parameters:
429 +  snes - the multigrid context
430 -  n    - the number of smoothing steps
431 
432    Options Database Key:
433 .  -snes_fas_smoothdown <n> - Sets number of pre-smoothing steps
434 
435    Level: advanced
436 
437 .keywords: FAS, MG, smooth, down, pre-smoothing, steps, multigrid
438 
439 .seealso: SNESFASSetNumberSmoothUp()
440 @*/
441 PetscErrorCode SNESFASSetNumberSmoothDown(SNES snes, PetscInt n) {
442   SNES_FAS * fas =  (SNES_FAS *)snes->data;
443   PetscErrorCode ierr = 0;
444   PetscFunctionBegin;
445   fas->max_down_it = n;
446   if (fas->next) {
447     ierr = SNESFASSetNumberSmoothDown(fas->next, n);CHKERRQ(ierr);
448   }
449   PetscFunctionReturn(0);
450 }
451 
452 #undef __FUNCT__
453 #define __FUNCT__ "SNESFASSetInterpolation"
454 /*@
455    SNESFASSetInterpolation - Sets the function to be used to calculate the
456    interpolation from l-1 to the lth level
457 
458    Input Parameters:
459 +  snes      - the multigrid context
460 .  mat       - the interpolation operator
461 -  level     - the level (0 is coarsest) to supply [do not supply 0]
462 
463    Level: advanced
464 
465    Notes:
466           Usually this is the same matrix used also to set the restriction
467     for the same level.
468 
469           One can pass in the interpolation matrix or its transpose; PETSc figures
470     out from the matrix size which one it is.
471 
472 .keywords:  FAS, multigrid, set, interpolate, level
473 
474 .seealso: SNESFASSetInjection(), SNESFASSetRestriction(), SNESFASSetRscale()
475 @*/
476 PetscErrorCode SNESFASSetInterpolation(SNES snes, PetscInt level, Mat mat) {
477   SNES_FAS * fas =  (SNES_FAS *)snes->data;
478   PetscInt top_level = fas->level,i;
479 
480   PetscFunctionBegin;
481   if (level > top_level)
482     SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetInterpolation", level);
483   /* get to the correct level */
484   for (i = fas->level; i > level; i--) {
485     fas = (SNES_FAS *)fas->next->data;
486   }
487   if (fas->level != level)
488     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetInterpolation");
489   fas->interpolate = mat;
490   PetscFunctionReturn(0);
491 }
492 
493 #undef __FUNCT__
494 #define __FUNCT__ "SNESFASSetRestriction"
495 /*@
496    SNESFASSetRestriction - Sets the function to be used to restrict the defect
497    from level l to l-1.
498 
499    Input Parameters:
500 +  snes  - the multigrid context
501 .  mat   - the restriction matrix
502 -  level - the level (0 is coarsest) to supply [Do not supply 0]
503 
504    Level: advanced
505 
506    Notes:
507           Usually this is the same matrix used also to set the interpolation
508     for the same level.
509 
510           One can pass in the interpolation matrix or its transpose; PETSc figures
511     out from the matrix size which one it is.
512 
513          If you do not set this, the transpose of the Mat set with PCMGSetInterpolation()
514     is used.
515 
516 .keywords: FAS, MG, set, multigrid, restriction, level
517 
518 .seealso: SNESFASSetInterpolation(), SNESFASSetInjection()
519 @*/
520 PetscErrorCode SNESFASSetRestriction(SNES snes, PetscInt level, Mat mat) {
521   SNES_FAS * fas =  (SNES_FAS *)snes->data;
522   PetscInt top_level = fas->level,i;
523 
524   PetscFunctionBegin;
525   if (level > top_level)
526     SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetRestriction", level);
527   /* get to the correct level */
528   for (i = fas->level; i > level; i--) {
529     fas = (SNES_FAS *)fas->next->data;
530   }
531   if (fas->level != level)
532     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetRestriction");
533   fas->restrct = mat;
534   PetscFunctionReturn(0);
535 }
536 
537 
538 #undef __FUNCT__
539 #define __FUNCT__ "SNESFASSetRScale"
540 /*@
541    SNESFASSetRScale - Sets the scaling factor of the restriction
542    operator from level l to l-1.
543 
544    Input Parameters:
545 +  snes   - the multigrid context
546 .  rscale - the restriction scaling
547 -  level  - the level (0 is coarsest) to supply [Do not supply 0]
548 
549    Level: advanced
550 
551    Notes:
552          This is only used in the case that the injection is not set.
553 
554 .keywords: FAS, MG, set, multigrid, restriction, level
555 
556 .seealso: SNESFASSetInjection(), SNESFASSetRestriction()
557 @*/
558 PetscErrorCode SNESFASSetRScale(SNES snes, PetscInt level, Vec rscale) {
559   SNES_FAS * fas =  (SNES_FAS *)snes->data;
560   PetscInt top_level = fas->level,i;
561 
562   PetscFunctionBegin;
563   if (level > top_level)
564     SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetRestriction", level);
565   /* get to the correct level */
566   for (i = fas->level; i > level; i--) {
567     fas = (SNES_FAS *)fas->next->data;
568   }
569   if (fas->level != level)
570     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetRestriction");
571   fas->rscale = rscale;
572   PetscFunctionReturn(0);
573 }
574 
575 
576 #undef __FUNCT__
577 #define __FUNCT__ "SNESFASSetInjection"
578 /*@
579    SNESFASSetInjection - Sets the function to be used to inject the solution
580    from level l to l-1.
581 
582    Input Parameters:
583 +  snes  - the multigrid context
584 .  mat   - the restriction matrix
585 -  level - the level (0 is coarsest) to supply [Do not supply 0]
586 
587    Level: advanced
588 
589    Notes:
590          If you do not set this, the restriction and rscale is used to
591    project the solution instead.
592 
593 .keywords: FAS, MG, set, multigrid, restriction, level
594 
595 .seealso: SNESFASSetInterpolation(), SNESFASSetRestriction()
596 @*/
597 PetscErrorCode SNESFASSetInjection(SNES snes, PetscInt level, Mat mat) {
598   SNES_FAS * fas =  (SNES_FAS *)snes->data;
599   PetscInt top_level = fas->level,i;
600 
601   PetscFunctionBegin;
602   if (level > top_level)
603     SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetInjection", level);
604   /* get to the correct level */
605   for (i = fas->level; i > level; i--) {
606     fas = (SNES_FAS *)fas->next->data;
607   }
608   if (fas->level != level)
609     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetInjection");
610   fas->inject = mat;
611   PetscFunctionReturn(0);
612 }
613 
614 #undef __FUNCT__
615 #define __FUNCT__ "SNESReset_FAS"
616 PetscErrorCode SNESReset_FAS(SNES snes)
617 {
618   PetscErrorCode ierr = 0;
619   SNES_FAS * fas = (SNES_FAS *)snes->data;
620 
621   PetscFunctionBegin;
622   if (fas->upsmooth)   ierr = SNESReset(fas->upsmooth);CHKERRQ(ierr);
623   if (fas->downsmooth) ierr = SNESReset(fas->downsmooth);CHKERRQ(ierr);
624   if (fas->next)       ierr = SNESReset(fas->next);CHKERRQ(ierr);
625   PetscFunctionReturn(0);
626 }
627 
628 #undef __FUNCT__
629 #define __FUNCT__ "SNESDestroy_FAS"
630 PetscErrorCode SNESDestroy_FAS(SNES snes)
631 {
632   SNES_FAS * fas = (SNES_FAS *)snes->data;
633   PetscErrorCode ierr = 0;
634 
635   PetscFunctionBegin;
636   /* recursively resets and then destroys */
637   if (fas->upsmooth)     ierr = SNESDestroy(&fas->upsmooth);CHKERRQ(ierr);
638   if (fas->downsmooth)   ierr = SNESDestroy(&fas->downsmooth);CHKERRQ(ierr);
639   if (fas->inject) {
640     ierr = MatDestroy(&fas->inject);CHKERRQ(ierr);
641   }
642   if (fas->interpolate == fas->restrct) {
643     if (fas->interpolate)  ierr = MatDestroy(&fas->interpolate);CHKERRQ(ierr);
644     fas->restrct = PETSC_NULL;
645   } else {
646     if (fas->interpolate)  ierr = MatDestroy(&fas->interpolate);CHKERRQ(ierr);
647     if (fas->restrct)      ierr = MatDestroy(&fas->restrct);CHKERRQ(ierr);
648   }
649   if (fas->rscale)       ierr = VecDestroy(&fas->rscale);CHKERRQ(ierr);
650   if (fas->next)         ierr = SNESDestroy(&fas->next);CHKERRQ(ierr);
651   ierr = PetscFree(fas);CHKERRQ(ierr);
652 
653   PetscFunctionReturn(0);
654 }
655 
656 #undef __FUNCT__
657 #define __FUNCT__ "SNESSetUp_FAS"
658 PetscErrorCode SNESSetUp_FAS(SNES snes)
659 {
660   SNES_FAS       *fas = (SNES_FAS *) snes->data;
661   PetscErrorCode ierr;
662   VecScatter     injscatter;
663   PetscInt       dm_levels;
664 
665   PetscFunctionBegin;
666 
667   if (fas->usedmfornumberoflevels && (fas->level == fas->levels - 1)) {
668     ierr = DMGetRefineLevel(snes->dm,&dm_levels);CHKERRQ(ierr);
669     dm_levels++;
670     if (dm_levels > fas->levels) {
671       ierr = SNESFASSetLevels(snes,dm_levels,PETSC_NULL);CHKERRQ(ierr);
672       ierr = SNESSetFromOptions(snes);CHKERRQ(ierr);
673     }
674   }
675 
676   if (fas->fastype == SNES_FAS_MULTIPLICATIVE) {
677     ierr = SNESDefaultGetWork(snes, 1);CHKERRQ(ierr); /* work vectors used for intergrid transfers */
678   } else {
679     ierr = SNESDefaultGetWork(snes, 4);CHKERRQ(ierr); /* work vectors used for intergrid transfers */
680   }
681 
682   /* setup the pre and post smoothers and set their function, jacobian, and gs evaluation routines if the user has neglected this */
683   if (fas->upsmooth) {
684     ierr = SNESSetFromOptions(fas->upsmooth);CHKERRQ(ierr);
685     if (snes->ops->computefunction && !fas->upsmooth->ops->computefunction) {
686       ierr = SNESSetFunction(fas->upsmooth, PETSC_NULL, snes->ops->computefunction, snes->funP);CHKERRQ(ierr);
687     }
688     if (snes->ops->computejacobian && !fas->upsmooth->ops->computejacobian) {
689       ierr = SNESSetJacobian(fas->upsmooth, fas->upsmooth->jacobian, fas->upsmooth->jacobian_pre, snes->ops->computejacobian, snes->jacP);CHKERRQ(ierr);
690     }
691    if (snes->ops->computegs && !fas->upsmooth->ops->computegs) {
692       ierr = SNESSetGS(fas->upsmooth, snes->ops->computegs, snes->gsP);CHKERRQ(ierr);
693     }
694   }
695   if (fas->downsmooth) {
696     ierr = SNESSetFromOptions(fas->downsmooth);CHKERRQ(ierr);
697     if (snes->ops->computefunction && !fas->downsmooth->ops->computefunction) {
698       ierr = SNESSetFunction(fas->downsmooth, PETSC_NULL, snes->ops->computefunction, snes->funP);CHKERRQ(ierr);
699     }
700     if (snes->ops->computejacobian && !fas->downsmooth->ops->computejacobian) {
701       ierr = SNESSetJacobian(fas->downsmooth, fas->downsmooth->jacobian, fas->downsmooth->jacobian_pre, snes->ops->computejacobian, snes->jacP);CHKERRQ(ierr);
702     }
703    if (snes->ops->computegs && !fas->downsmooth->ops->computegs) {
704       ierr = SNESSetGS(fas->downsmooth, snes->ops->computegs, snes->gsP);CHKERRQ(ierr);
705     }
706   }
707   /*pass the smoother, function, and jacobian up to the next level if it's not user set already */
708   if (fas->next) {
709     if (fas->galerkin) {
710       ierr = SNESSetFunction(fas->next, PETSC_NULL, SNESFASGalerkinDefaultFunction, fas->next);CHKERRQ(ierr);
711     } else {
712       if (snes->ops->computefunction && !fas->next->ops->computefunction) {
713         ierr = SNESSetFunction(fas->next, PETSC_NULL, snes->ops->computefunction, snes->funP);CHKERRQ(ierr);
714       }
715       if (snes->ops->computejacobian && !fas->next->ops->computejacobian) {
716         ierr = SNESSetJacobian(fas->next, fas->next->jacobian, fas->next->jacobian_pre, snes->ops->computejacobian, snes->jacP);CHKERRQ(ierr);
717       }
718       if (snes->ops->computegs && !fas->next->ops->computegs) {
719         ierr = SNESSetGS(fas->next, snes->ops->computegs, snes->gsP);CHKERRQ(ierr);
720       }
721     }
722   }
723   if (snes->dm) {
724     /* construct EVERYTHING from the DM -- including the progressive set of smoothers */
725     if (fas->next) {
726       /* for now -- assume the DM and the evaluation functions have been set externally */
727       if (!fas->next->dm) {
728         ierr = DMCoarsen(snes->dm, ((PetscObject)fas->next)->comm, &fas->next->dm);CHKERRQ(ierr);
729         ierr = SNESSetDM(fas->next, fas->next->dm);CHKERRQ(ierr);
730       }
731       /* set the interpolation and restriction from the DM */
732       if (!fas->interpolate) {
733         ierr = DMCreateInterpolation(fas->next->dm, snes->dm, &fas->interpolate, &fas->rscale);CHKERRQ(ierr);
734         fas->restrct = fas->interpolate;
735       }
736       /* set the injection from the DM */
737       if (!fas->inject) {
738         ierr = DMCreateInjection(fas->next->dm, snes->dm, &injscatter);CHKERRQ(ierr);
739         ierr = MatCreateScatter(((PetscObject)snes)->comm, injscatter, &fas->inject);CHKERRQ(ierr);
740         ierr = VecScatterDestroy(&injscatter);CHKERRQ(ierr);
741       }
742     }
743     /* set the DMs of the pre and post-smoothers here */
744     if (fas->upsmooth)  {ierr = SNESSetDM(fas->upsmooth,   snes->dm);CHKERRQ(ierr);}
745     if (fas->downsmooth){ierr = SNESSetDM(fas->downsmooth, snes->dm);CHKERRQ(ierr);}
746   }
747 
748   /* setup FAS work vectors */
749   if (fas->galerkin) {
750     ierr = VecDuplicate(snes->vec_sol, &fas->Xg);CHKERRQ(ierr);
751     ierr = VecDuplicate(snes->vec_sol, &fas->Fg);CHKERRQ(ierr);
752   }
753 
754   if (fas->next) {
755    /* gotta set up the solution vector for this to work */
756     if (!fas->next->vec_sol) {ierr = VecDuplicate(fas->rscale, &fas->next->vec_sol);CHKERRQ(ierr);}
757     if (!fas->next->vec_rhs) {ierr = VecDuplicate(fas->rscale, &fas->next->vec_rhs);CHKERRQ(ierr);}
758     ierr = SNESSetUp(fas->next);CHKERRQ(ierr);
759   }
760   /* got to set them all up at once */
761   PetscFunctionReturn(0);
762 }
763 
764 #undef __FUNCT__
765 #define __FUNCT__ "SNESSetFromOptions_FAS"
766 PetscErrorCode SNESSetFromOptions_FAS(SNES snes)
767 {
768   SNES_FAS       *fas = (SNES_FAS *) snes->data;
769   PetscInt       levels = 1;
770   PetscBool      flg, smoothflg, smoothupflg, smoothdownflg, monflg;
771   PetscErrorCode ierr;
772   const char     *def_smooth = SNESNRICHARDSON;
773   char           pre_type[256];
774   char           post_type[256];
775   char           monfilename[PETSC_MAX_PATH_LEN];
776   SNESFASType    fastype;
777 
778   PetscFunctionBegin;
779   ierr = PetscOptionsHead("SNESFAS Options-----------------------------------");CHKERRQ(ierr);
780 
781   /* number of levels -- only process on the finest level */
782   if (fas->levels - 1 == fas->level) {
783     ierr = PetscOptionsInt("-snes_fas_levels", "Number of Levels", "SNESFASSetLevels", levels, &levels, &flg);CHKERRQ(ierr);
784     if (!flg && snes->dm) {
785       ierr = DMGetRefineLevel(snes->dm,&levels);CHKERRQ(ierr);
786       levels++;
787       fas->usedmfornumberoflevels = PETSC_TRUE;
788     }
789     ierr = SNESFASSetLevels(snes, levels, PETSC_NULL);CHKERRQ(ierr);
790   }
791 
792   /* type of pre and/or post smoothers -- set both at once */
793   ierr = PetscMemcpy(post_type, def_smooth, 256);CHKERRQ(ierr);
794   ierr = PetscMemcpy(pre_type, def_smooth, 256);CHKERRQ(ierr);
795   fastype = fas->fastype;
796   ierr = PetscOptionsEnum("-snes_fas_type","FAS correction type","SNESFASSetType",SNESFASTypes,(PetscEnum)fastype,(PetscEnum*)&fastype,&flg);CHKERRQ(ierr);
797   if (flg) {
798     ierr = SNESFASSetType(snes, fastype);CHKERRQ(ierr);
799   }
800   ierr = PetscOptionsList("-snes_fas_smoother_type","Nonlinear smoother method","SNESSetType",SNESList,def_smooth,pre_type,256,&smoothflg);CHKERRQ(ierr);
801   if (smoothflg) {
802     ierr = PetscMemcpy(post_type, pre_type, 256);CHKERRQ(ierr);
803   } else {
804     ierr = PetscOptionsList("-snes_fas_smoothup_type",  "Nonlinear smoother method","SNESSetType",SNESList,def_smooth,pre_type, 256,&smoothupflg);CHKERRQ(ierr);
805     ierr = PetscOptionsList("-snes_fas_smoothdown_type","Nonlinear smoother method","SNESSetType",SNESList,def_smooth,post_type,256,&smoothdownflg);CHKERRQ(ierr);
806   }
807 
808   /* options for the number of preconditioning cycles and cycle type */
809   ierr = PetscOptionsInt("-snes_fas_smoothup","Number of post-smooth iterations","SNESFASSetNumberSmoothUp",fas->max_up_it,&fas->max_up_it,&flg);CHKERRQ(ierr);
810   ierr = PetscOptionsInt("-snes_fas_smoothdown","Number of pre-smooth iterations","SNESFASSetNumberSmoothUp",fas->max_down_it,&fas->max_down_it,&flg);CHKERRQ(ierr);
811   ierr = PetscOptionsInt("-snes_fas_cycles","Number of cycles","SNESFASSetCycles",fas->n_cycles,&fas->n_cycles,&flg);CHKERRQ(ierr);
812 
813   ierr = PetscOptionsBool("-snes_fas_galerkin", "Form coarse problems with Galerkin","SNESFAS",fas->galerkin,&fas->galerkin,&flg);CHKERRQ(ierr);
814 
815   ierr = PetscOptionsString("-snes_fas_monitor","Monitor FAS progress","SNESMonitorSet","stdout",monfilename,PETSC_MAX_PATH_LEN,&monflg);CHKERRQ(ierr);
816 
817   /* other options for the coarsest level */
818   if (fas->level == 0) {
819     ierr = PetscOptionsList("-snes_fas_coarse_smoother_type","Coarsest smoother method","SNESSetType",SNESList,def_smooth,pre_type,256,&smoothflg);CHKERRQ(ierr);
820   }
821 
822   ierr = PetscOptionsTail();CHKERRQ(ierr);
823   /* setup from the determined types if there is no pointwise procedure or smoother defined */
824 
825   if ((!fas->downsmooth) && ((smoothdownflg || smoothflg) || !snes->usegs)) {
826     const char     *prefix;
827     ierr = SNESGetOptionsPrefix(snes,&prefix);CHKERRQ(ierr);
828     ierr = SNESCreate(((PetscObject)snes)->comm, &fas->downsmooth);CHKERRQ(ierr);
829     ierr = SNESSetOptionsPrefix(fas->downsmooth,prefix);CHKERRQ(ierr);
830     if (fas->level || (fas->levels == 1)) {
831       ierr = SNESAppendOptionsPrefix(fas->downsmooth,"fas_levels_down_");CHKERRQ(ierr);
832     } else {
833       ierr = SNESAppendOptionsPrefix(fas->downsmooth,"fas_coarse_");CHKERRQ(ierr);
834     }
835     ierr = PetscObjectIncrementTabLevel((PetscObject)fas->downsmooth, (PetscObject)snes, 1);CHKERRQ(ierr);
836     ierr = SNESSetType(fas->downsmooth, pre_type);CHKERRQ(ierr);
837   }
838 
839   if ((!fas->upsmooth) && (fas->level != 0) && ((smoothupflg || smoothflg) || !snes->usegs)) {
840     const char     *prefix;
841     ierr = SNESGetOptionsPrefix(snes,&prefix);CHKERRQ(ierr);
842     ierr = SNESCreate(((PetscObject)snes)->comm, &fas->upsmooth);CHKERRQ(ierr);
843     ierr = SNESSetOptionsPrefix(fas->upsmooth,prefix);CHKERRQ(ierr);
844     ierr = SNESAppendOptionsPrefix(fas->upsmooth,"fas_levels_up_");CHKERRQ(ierr);
845     ierr = PetscObjectIncrementTabLevel((PetscObject)fas->upsmooth, (PetscObject)snes, 1);CHKERRQ(ierr);
846     ierr = SNESSetType(fas->upsmooth, pre_type);CHKERRQ(ierr);
847   }
848   if (fas->upsmooth) {
849     ierr = SNESSetTolerances(fas->upsmooth, 0.0, 0.0, 0.0, fas->max_up_it, 1000);CHKERRQ(ierr);
850   }
851 
852   if (fas->downsmooth) {
853     ierr = SNESSetTolerances(fas->downsmooth, 0.0, 0.0, 0.0, fas->max_down_it, 1000);CHKERRQ(ierr);
854   }
855 
856   if (fas->level != fas->levels - 1) {
857     ierr = SNESSetTolerances(snes, 0.0, 0.0, 0.0, fas->n_cycles, 1000);CHKERRQ(ierr);
858   }
859 
860   if (monflg) {
861     fas->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr);
862     /* set the monitors for the upsmoother and downsmoother */
863     ierr = SNESMonitorCancel(snes);CHKERRQ(ierr);
864     ierr = SNESMonitorSet(snes,SNESMonitorDefault,PETSC_NULL,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr);
865     if (fas->upsmooth)   ierr = SNESMonitorSet(fas->upsmooth,SNESMonitorDefault,PETSC_NULL,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr);
866     if (fas->downsmooth) ierr = SNESMonitorSet(fas->downsmooth,SNESMonitorDefault,PETSC_NULL,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr);
867   } else {
868     /* unset the monitors on the coarse levels */
869     if (fas->level != fas->levels - 1) {
870       ierr = SNESMonitorCancel(snes);CHKERRQ(ierr);
871     }
872   }
873 
874   /* recursive option setting for the smoothers */
875   if (fas->next) {ierr = SNESSetFromOptions(fas->next);CHKERRQ(ierr);}
876   PetscFunctionReturn(0);
877 }
878 
879 #undef __FUNCT__
880 #define __FUNCT__ "SNESView_FAS"
881 PetscErrorCode SNESView_FAS(SNES snes, PetscViewer viewer)
882 {
883   SNES_FAS   *fas = (SNES_FAS *) snes->data;
884   PetscBool      iascii;
885   PetscErrorCode ierr;
886 
887   PetscFunctionBegin;
888   if (fas->level != fas->levels - 1) PetscFunctionReturn(0);
889   ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
890   if (iascii) {
891     ierr = PetscViewerASCIIPrintf(viewer, "FAS, levels = %d\n",  fas->levels);CHKERRQ(ierr);
892     ierr = PetscViewerASCIIPushTab(viewer);
893     ierr = PetscViewerASCIIPrintf(viewer, "level: %d\n",  fas->level);CHKERRQ(ierr);
894     if (fas->upsmooth) {
895       ierr = PetscViewerASCIIPrintf(viewer, "up-smoother on level %D:\n",  fas->level);CHKERRQ(ierr);
896       ierr = PetscViewerASCIIPushTab(viewer);
897       ierr = SNESView(fas->upsmooth, viewer);CHKERRQ(ierr);
898       ierr = PetscViewerASCIIPopTab(viewer);
899     } else {
900       ierr = PetscViewerASCIIPrintf(viewer, "no up-smoother on level %D\n",  fas->level);CHKERRQ(ierr);
901     }
902     if (fas->downsmooth) {
903       ierr = PetscViewerASCIIPrintf(viewer, "down-smoother on level %D:\n",  fas->level);CHKERRQ(ierr);
904       ierr = PetscViewerASCIIPushTab(viewer);
905       ierr = SNESView(fas->downsmooth, viewer);CHKERRQ(ierr);
906       ierr = PetscViewerASCIIPopTab(viewer);
907     } else {
908       ierr = PetscViewerASCIIPrintf(viewer, "no down-smoother on level %D\n",  fas->level);CHKERRQ(ierr);
909     }
910     if (snes->usegs) {
911       ierr = PetscViewerASCIIPrintf(viewer, "Using user Gauss-Seidel on level %D -- smoothdown=%D, smoothup=%D\n",
912                                     fas->level, fas->max_down_it, fas->max_up_it);CHKERRQ(ierr);
913     }
914     ierr = PetscViewerASCIIPopTab(viewer);
915   } else {
916     SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for SNESFAS",((PetscObject)viewer)->type_name);
917   }
918   PetscFunctionReturn(0);
919 }
920 
921 #undef __FUNCT__
922 #define __FUNCT__ "FASDownSmooth"
923 /*
924 Defines the action of the downsmoother
925  */
926 PetscErrorCode FASDownSmooth(SNES snes, Vec B, Vec X, Vec F){
927   PetscErrorCode      ierr = 0;
928   PetscReal           fnorm;
929   SNESConvergedReason reason;
930   SNES_FAS            *fas = (SNES_FAS *)snes->data;
931   PetscFunctionBegin;
932   if (fas->downsmooth) {
933     ierr = SNESSolve(fas->downsmooth, B, X);CHKERRQ(ierr);
934     /* check convergence reason for the smoother */
935     ierr = SNESGetConvergedReason(fas->downsmooth,&reason);CHKERRQ(ierr);
936     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
937       snes->reason = SNES_DIVERGED_INNER;
938       PetscFunctionReturn(0);
939     }
940   } else if (snes->usegs && snes->ops->computegs) {
941     if (fas->monitor) {
942       ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
943       ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
944       ierr = PetscViewerASCIIAddTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
945       ierr = PetscViewerASCIIPrintf(fas->monitor, "%d SNES GS Function norm %14.12e\n", 0, fnorm);CHKERRQ(ierr);
946       ierr = PetscViewerASCIISubtractTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
947     }
948     ierr = SNESSetGSSweeps(snes, fas->max_down_it);CHKERRQ(ierr);
949     ierr = SNESComputeGS(snes, B, X);CHKERRQ(ierr);
950     if (fas->monitor) {
951       ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
952       ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
953       ierr = PetscViewerASCIIAddTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
954       ierr = PetscViewerASCIIPrintf(fas->monitor, "1 SNES GS Function norm %14.12e\n", fnorm);CHKERRQ(ierr);
955       ierr = PetscViewerASCIISubtractTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
956     }
957   } else if (snes->pc) {
958     ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr);
959     ierr = SNESGetConvergedReason(fas->downsmooth,&reason);CHKERRQ(ierr);
960     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
961       snes->reason = SNES_DIVERGED_INNER;
962       PetscFunctionReturn(0);
963     }
964   }
965   PetscFunctionReturn(0);
966 }
967 
968 
969 #undef __FUNCT__
970 #define __FUNCT__ "FASUpSmooth"
971 /*
972 Defines the action of the upsmoother
973  */
974 PetscErrorCode FASUpSmooth (SNES snes, Vec B, Vec X, Vec F) {
975   PetscErrorCode      ierr = 0;
976   PetscReal           fnorm;
977   SNESConvergedReason reason;
978   SNES_FAS            *fas = (SNES_FAS *)snes->data;
979   PetscFunctionBegin;
980   if (fas->upsmooth) {
981     ierr = SNESSolve(fas->downsmooth, B, X);CHKERRQ(ierr);
982     /* check convergence reason for the smoother */
983     ierr = SNESGetConvergedReason(fas->downsmooth,&reason);CHKERRQ(ierr);
984     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
985       snes->reason = SNES_DIVERGED_INNER;
986       PetscFunctionReturn(0);
987     }
988   } else if (snes->usegs && snes->ops->computegs) {
989     if (fas->monitor) {
990       ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
991       ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
992       ierr = PetscViewerASCIIAddTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
993       ierr = PetscViewerASCIIPrintf(fas->monitor, "%d SNES GS Function norm %14.12e\n", 0, fnorm);CHKERRQ(ierr);
994       ierr = PetscViewerASCIISubtractTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
995     }
996     ierr = SNESSetGSSweeps(snes, fas->max_up_it);CHKERRQ(ierr);
997     ierr = SNESComputeGS(snes, B, X);CHKERRQ(ierr);
998     if (fas->monitor) {
999       ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
1000       ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
1001       ierr = PetscViewerASCIIAddTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
1002       ierr = PetscViewerASCIIPrintf(fas->monitor, "1 SNES GS Function norm %14.12e\n", fnorm);CHKERRQ(ierr);
1003       ierr = PetscViewerASCIISubtractTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
1004     }
1005   } else if (snes->pc) {
1006     ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr);
1007     ierr = SNESGetConvergedReason(fas->downsmooth,&reason);CHKERRQ(ierr);
1008     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
1009       snes->reason = SNES_DIVERGED_INNER;
1010       PetscFunctionReturn(0);
1011     }
1012   }
1013   PetscFunctionReturn(0);
1014 }
1015 
1016 #undef __FUNCT__
1017 #define __FUNCT__ "FASCoarseCorrection"
1018 /*
1019 
1020 Performs the FAS coarse correction as:
1021 
1022 fine problem: F(x) = 0
1023 coarse problem: F^c(x) = b^c
1024 
1025 b^c = F^c(I^c_fx^f - I^c_fF(x))
1026 
1027 with correction:
1028 
1029 
1030 
1031  */
1032 PetscErrorCode FASCoarseCorrection(SNES snes, Vec X, Vec F, Vec X_new) {
1033   PetscErrorCode      ierr;
1034   Vec                 X_c, Xo_c, F_c, B_c;
1035   SNES_FAS            *fas = (SNES_FAS *)snes->data;
1036   SNESConvergedReason reason;
1037   PetscFunctionBegin;
1038   if (fas->next) {
1039     ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
1040 
1041     X_c  = fas->next->vec_sol;
1042     Xo_c = fas->next->work[0];
1043     F_c  = fas->next->vec_func;
1044     B_c  = fas->next->vec_rhs;
1045 
1046     /* inject the solution */
1047     if (fas->inject) {
1048       ierr = MatRestrict(fas->inject, X, Xo_c);CHKERRQ(ierr);
1049     } else {
1050       ierr = MatRestrict(fas->restrct, X, Xo_c);CHKERRQ(ierr);
1051       ierr = VecPointwiseMult(Xo_c, fas->rscale, Xo_c);CHKERRQ(ierr);
1052     }
1053     ierr = VecScale(F, -1.0);CHKERRQ(ierr);
1054 
1055     /* restrict the defect */
1056     ierr = MatRestrict(fas->restrct, F, B_c);CHKERRQ(ierr);
1057 
1058     /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */
1059     fas->next->vec_rhs = PETSC_NULL;                                           /*unset the RHS to evaluate function instead of residual*/
1060     ierr = SNESComputeFunction(fas->next, Xo_c, F_c);CHKERRQ(ierr);
1061 
1062     ierr = VecAXPY(B_c, 1.0, F_c);CHKERRQ(ierr);                               /* add F_c(X) to the RHS */
1063 
1064     /* set initial guess of the coarse problem to the projected fine solution */
1065     ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr);
1066 
1067     /* recurse to the next level */
1068     fas->next->vec_rhs = B_c;
1069     /* ierr = FASCycle_Private(fas->next, X_c);CHKERRQ(ierr); */
1070     ierr = SNESSolve(fas->next, B_c, X_c);CHKERRQ(ierr);
1071     ierr = SNESGetConvergedReason(fas->next,&reason);CHKERRQ(ierr);
1072     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
1073       snes->reason = SNES_DIVERGED_INNER;
1074       PetscFunctionReturn(0);
1075     }
1076     /* fas->next->vec_rhs = PETSC_NULL; */
1077 
1078     /* correct as x <- x + I(x^c - Rx)*/
1079     ierr = VecAXPY(X_c, -1.0, Xo_c);CHKERRQ(ierr);
1080     ierr = MatInterpolateAdd(fas->interpolate, X_c, X, X_new);CHKERRQ(ierr);
1081   }
1082   PetscFunctionReturn(0);
1083 }
1084 
1085 #undef __FUNCT__
1086 #define __FUNCT__ "FASCycle_Additive"
1087 /*
1088 
1089 The additive cycle looks like:
1090 
1091 xhat = x
1092 xhat = dS(x, b)
1093 x = coarsecorrection(xhat, b_d)
1094 x = x + nu*(xhat - x);
1095 (optional) x = uS(x, b)
1096 
1097 With the coarse RHS (defect correction) as below.
1098 
1099  */
1100 PetscErrorCode FASCycle_Additive(SNES snes, Vec X) {
1101   Vec                 F, B, Xhat;
1102   Vec                 X_c, Xo_c, F_c, B_c, G, W;
1103   PetscErrorCode      ierr;
1104   SNES_FAS *          fas = (SNES_FAS *)snes->data;
1105   SNESConvergedReason reason;
1106   PetscReal           xnorm = 0., fnorm = 0., gnorm = 0., ynorm = 0.;
1107   PetscBool           lssucceed;
1108   PetscFunctionBegin;
1109 
1110   F = snes->vec_func;
1111   B = snes->vec_rhs;
1112   Xhat = snes->work[1];
1113   G    = snes->work[2];
1114   W    = snes->work[3];
1115   ierr = VecCopy(X, Xhat);CHKERRQ(ierr);
1116   /* recurse first */
1117   if (fas->next) {
1118     ierr = SNESComputeFunction(snes, Xhat, F);CHKERRQ(ierr);
1119 
1120     X_c  = fas->next->vec_sol;
1121     Xo_c = fas->next->work[0];
1122     F_c  = fas->next->vec_func;
1123     B_c  = fas->next->vec_rhs;
1124 
1125     /* inject the solution */
1126     if (fas->inject) {
1127       ierr = MatRestrict(fas->inject, Xhat, Xo_c);CHKERRQ(ierr);
1128     } else {
1129       ierr = MatRestrict(fas->restrct, Xhat, Xo_c);CHKERRQ(ierr);
1130       ierr = VecPointwiseMult(Xo_c, fas->rscale, Xo_c);CHKERRQ(ierr);
1131     }
1132     ierr = VecScale(F, -1.0);CHKERRQ(ierr);
1133 
1134     /* restrict the defect */
1135     ierr = MatRestrict(fas->restrct, F, B_c);CHKERRQ(ierr);
1136 
1137     /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */
1138     fas->next->vec_rhs = PETSC_NULL;                                           /*unset the RHS to evaluate function instead of residual*/
1139     ierr = SNESComputeFunction(fas->next, Xo_c, F_c);CHKERRQ(ierr);
1140 
1141     ierr = VecAXPY(B_c, 1.0, F_c);CHKERRQ(ierr);                               /* add F_c(X) to the RHS */
1142 
1143     /* set initial guess of the coarse problem to the projected fine solution */
1144     ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr);
1145 
1146     /* recurse */
1147     fas->next->vec_rhs = B_c;
1148     ierr = SNESSolve(fas->next, B_c, X_c);CHKERRQ(ierr);
1149 
1150     /* smooth on this level */
1151     ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr);
1152 
1153    ierr = SNESGetConvergedReason(fas->next,&reason);CHKERRQ(ierr);
1154     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
1155       snes->reason = SNES_DIVERGED_INNER;
1156       PetscFunctionReturn(0);
1157     }
1158 
1159     /* correct as x <- x + I(x^c - Rx)*/
1160     ierr = VecAXPY(X_c, -1.0, Xo_c);CHKERRQ(ierr);
1161     ierr = MatInterpolate(fas->interpolate, X_c, Xhat);CHKERRQ(ierr);
1162 
1163     /* additive correction of the coarse direction*/
1164     ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
1165     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
1166     ierr = VecScale(Xhat, -1.0);CHKERRQ(ierr);
1167     ierr = (*snes->ops->linesearch)(snes,snes->lsP,X,F,Xhat,fnorm,xnorm,G,W,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
1168     ierr = VecCopy(W, X);CHKERRQ(ierr);
1169     ierr = VecCopy(G, F);CHKERRQ(ierr);
1170     fnorm = gnorm;
1171   } else {
1172     ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr);
1173   }
1174   PetscFunctionReturn(0);
1175 }
1176 
1177 #undef __FUNCT__
1178 #define __FUNCT__ "FASCycle_Multiplicative"
1179 /*
1180 
1181 Defines the FAS cycle as:
1182 
1183 fine problem: F(x) = 0
1184 coarse problem: F^c(x) = b^c
1185 
1186 b^c = F^c(I^c_fx^f - I^c_fF(x))
1187 
1188 correction:
1189 
1190 x = x + I(x^c - Rx)
1191 
1192  */
1193 PetscErrorCode FASCycle_Multiplicative(SNES snes, Vec X) {
1194 
1195   PetscErrorCode      ierr;
1196   Vec                 F,B;
1197   SNES_FAS            *fas = (SNES_FAS *)snes->data;
1198 
1199   PetscFunctionBegin;
1200   F = snes->vec_func;
1201   B = snes->vec_rhs;
1202   /* pre-smooth -- just update using the pre-smoother */
1203   ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr);
1204 
1205   ierr = FASCoarseCorrection(snes, X, F, X);CHKERRQ(ierr);
1206 
1207   if (fas->level != 0) {
1208     ierr = FASUpSmooth(snes, B, X, F);CHKERRQ(ierr);
1209   }
1210   ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
1211 
1212   PetscFunctionReturn(0);
1213 }
1214 
1215 #undef __FUNCT__
1216 #define __FUNCT__ "SNESSolve_FAS"
1217 
1218 PetscErrorCode SNESSolve_FAS(SNES snes)
1219 {
1220   PetscErrorCode ierr;
1221   PetscInt       i, maxits;
1222   Vec            X, F;
1223   PetscReal      fnorm;
1224   SNES_FAS       *fas = (SNES_FAS *)snes->data;
1225   PetscFunctionBegin;
1226   maxits = snes->max_its;            /* maximum number of iterations */
1227   snes->reason = SNES_CONVERGED_ITERATING;
1228   X = snes->vec_sol;
1229   F = snes->vec_func;
1230 
1231   /*norm setup */
1232   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
1233   snes->iter = 0;
1234   snes->norm = 0.;
1235   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
1236   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
1237   if (snes->domainerror) {
1238     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
1239     PetscFunctionReturn(0);
1240   }
1241   ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
1242   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm");
1243   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
1244   snes->norm = fnorm;
1245   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
1246   SNESLogConvHistory(snes,fnorm,0);
1247   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
1248 
1249   /* set parameter for default relative tolerance convergence test */
1250   snes->ttol = fnorm*snes->rtol;
1251   /* test convergence */
1252   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
1253   if (snes->reason) PetscFunctionReturn(0);
1254   for (i = 0; i < maxits; i++) {
1255     /* Call general purpose update function */
1256 
1257     if (snes->ops->update) {
1258       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
1259     }
1260     if (fas->fastype == SNES_FAS_MULTIPLICATIVE) {
1261       ierr = FASCycle_Multiplicative(snes, X);CHKERRQ(ierr);
1262     } else {
1263       ierr = FASCycle_Additive(snes, X);CHKERRQ(ierr);
1264     }
1265 
1266     /* check for FAS cycle divergence */
1267     if (snes->reason != SNES_CONVERGED_ITERATING) {
1268       PetscFunctionReturn(0);
1269     }
1270     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
1271     /* Monitor convergence */
1272     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
1273     snes->iter = i+1;
1274     snes->norm = fnorm;
1275     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
1276     SNESLogConvHistory(snes,snes->norm,0);
1277     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
1278     /* Test for convergence */
1279     ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
1280     if (snes->reason) break;
1281   }
1282   if (i == maxits) {
1283     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr);
1284     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
1285   }
1286   PetscFunctionReturn(0);
1287 }
1288