xref: /petsc/src/snes/impls/fas/fas.c (revision 1aa26658c1f860783e952c8729bb854a56856eab)
1421d9b32SPeter Brune /* Defines the basic SNES object */
26038b46bSPeter Brune #include <../src/snes/impls/fas/fasimpls.h>    /*I  "petscsnesfas.h"  I*/
3421d9b32SPeter Brune 
46a6fc655SJed Brown const char *const SNESFASTypes[] = {"MULTIPLICATIVE","ADDITIVE","SNESFASType","SNES_FAS",0};
507144faaSPeter Brune 
6421d9b32SPeter Brune extern PetscErrorCode SNESDestroy_FAS(SNES snes);
7421d9b32SPeter Brune extern PetscErrorCode SNESSetUp_FAS(SNES snes);
8421d9b32SPeter Brune extern PetscErrorCode SNESSetFromOptions_FAS(SNES snes);
9421d9b32SPeter Brune extern PetscErrorCode SNESView_FAS(SNES snes, PetscViewer viewer);
10421d9b32SPeter Brune extern PetscErrorCode SNESSolve_FAS(SNES snes);
11421d9b32SPeter Brune extern PetscErrorCode SNESReset_FAS(SNES snes);
126273346dSPeter Brune extern PetscErrorCode SNESFASGalerkinDefaultFunction(SNES, Vec, Vec, void*);
13ab8d36c9SPeter Brune extern PetscErrorCode SNESFASCycleCreateSmoother_Private(SNES, SNES*);
14421d9b32SPeter Brune 
151fbfccc6SJed Brown /*MC
161fbfccc6SJed Brown 
171fbfccc6SJed Brown SNESFAS - Full Approximation Scheme nonlinear multigrid solver.
181fbfccc6SJed Brown 
19d3bc2379SPeter Brune    The nonlinear problem is solved by correction using coarse versions
20d3bc2379SPeter Brune    of the nonlinear problem.  This problem is perturbed so that a projected
21d3bc2379SPeter Brune    solution of the fine problem elicits no correction from the coarse problem.
22d3bc2379SPeter Brune 
23d3bc2379SPeter Brune Options Database:
24d3bc2379SPeter Brune +   -snes_fas_levels -  The number of levels
25d3bc2379SPeter Brune .   -snes_fas_cycles<1> -  The number of cycles -- 1 for V, 2 for W
26d3bc2379SPeter Brune .   -snes_fas_type<additive, multiplicative>  -  Additive or multiplicative cycle
27d3bc2379SPeter Brune .   -snes_fas_galerkin<PETSC_FALSE> -  Form coarse problems by projection back upon the fine problem
28d3bc2379SPeter Brune .   -snes_fas_smoothup<1> -  The number of iterations of the post-smoother
29d3bc2379SPeter Brune .   -snes_fas_smoothdown<1> -  The number of iterations of the pre-smoother
30d3bc2379SPeter Brune .   -snes_fas_monitor -  Monitor progress of all of the levels
31d3bc2379SPeter Brune .   -fas_levels_snes_ -  SNES options for all smoothers
327d84e935SPeter Brune .   -fas_levels_cycle_snes_ -  SNES options for all cycles
33d3bc2379SPeter Brune .   -fas_levels_i_snes_ -  SNES options for the smoothers on level i
347d84e935SPeter Brune .   -fas_levels_i_cycle_snes_ - SNES options for the cycle on level i
35d3bc2379SPeter Brune -   -fas_coarse_snes_ -  SNES options for the coarsest smoother
36d3bc2379SPeter Brune 
37d3bc2379SPeter Brune Notes:
38d3bc2379SPeter Brune    The organization of the FAS solver is slightly different from the organization of PCMG
39d3bc2379SPeter Brune    As each level has smoother SNES instances(down and potentially up) and a cycle SNES instance.
40d3bc2379SPeter Brune    The cycle SNES instance may be used for monitoring convergence on a particular level.
411fbfccc6SJed Brown 
427d84e935SPeter Brune Level: beginner
431fbfccc6SJed Brown 
44d3bc2379SPeter Brune .seealso: PCMG, SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
451fbfccc6SJed Brown M*/
46421d9b32SPeter Brune 
47421d9b32SPeter Brune #undef __FUNCT__
48421d9b32SPeter Brune #define __FUNCT__ "SNESCreate_FAS"
491fbfccc6SJed Brown PETSC_EXTERN_C PetscErrorCode SNESCreate_FAS(SNES snes)
50421d9b32SPeter Brune {
51421d9b32SPeter Brune   SNES_FAS       *fas;
52421d9b32SPeter Brune   PetscErrorCode ierr;
53421d9b32SPeter Brune 
54421d9b32SPeter Brune   PetscFunctionBegin;
55421d9b32SPeter Brune   snes->ops->destroy        = SNESDestroy_FAS;
56421d9b32SPeter Brune   snes->ops->setup          = SNESSetUp_FAS;
57421d9b32SPeter Brune   snes->ops->setfromoptions = SNESSetFromOptions_FAS;
58421d9b32SPeter Brune   snes->ops->view           = SNESView_FAS;
59421d9b32SPeter Brune   snes->ops->solve          = SNESSolve_FAS;
60421d9b32SPeter Brune   snes->ops->reset          = SNESReset_FAS;
61421d9b32SPeter Brune 
62ed020824SBarry Smith   snes->usesksp = PETSC_FALSE;
63ed020824SBarry Smith   snes->usespc  = PETSC_FALSE;
64ed020824SBarry Smith 
6588976e71SPeter Brune   if (!snes->tolerancesset) {
660e444f03SPeter Brune     snes->max_funcs = 30000;
670e444f03SPeter Brune     snes->max_its   = 10000;
6888976e71SPeter Brune   }
690e444f03SPeter Brune 
70421d9b32SPeter Brune   ierr = PetscNewLog(snes, SNES_FAS, &fas);CHKERRQ(ierr);
71*1aa26658SKarl Rupp 
72421d9b32SPeter Brune   snes->data                  = (void*) fas;
73421d9b32SPeter Brune   fas->level                  = 0;
74293a7e31SPeter Brune   fas->levels                 = 1;
75ee78dd50SPeter Brune   fas->n_cycles               = 1;
76ee78dd50SPeter Brune   fas->max_up_it              = 1;
77ee78dd50SPeter Brune   fas->max_down_it            = 1;
78ab8d36c9SPeter Brune   fas->smoothu                = PETSC_NULL;
79ab8d36c9SPeter Brune   fas->smoothd                = PETSC_NULL;
80421d9b32SPeter Brune   fas->next                   = PETSC_NULL;
816273346dSPeter Brune   fas->previous               = PETSC_NULL;
82ab8d36c9SPeter Brune   fas->fine                   = snes;
83421d9b32SPeter Brune   fas->interpolate            = PETSC_NULL;
84421d9b32SPeter Brune   fas->restrct                = PETSC_NULL;
85efe1f98aSPeter Brune   fas->inject                 = PETSC_NULL;
86cc05f883SPeter Brune   fas->monitor                = PETSC_NULL;
87cc05f883SPeter Brune   fas->usedmfornumberoflevels = PETSC_FALSE;
88ddebd997SPeter Brune   fas->fastype                = SNES_FAS_MULTIPLICATIVE;
890dd27c6cSPeter Brune 
900dd27c6cSPeter Brune   fas->eventsmoothsetup    = PETSC_FALSE;
910dd27c6cSPeter Brune   fas->eventsmoothsolve    = PETSC_FALSE;
920dd27c6cSPeter Brune   fas->eventresidual       = PETSC_FALSE;
930dd27c6cSPeter Brune   fas->eventinterprestrict = PETSC_FALSE;
94efe1f98aSPeter Brune   PetscFunctionReturn(0);
95efe1f98aSPeter Brune }
96efe1f98aSPeter Brune 
97421d9b32SPeter Brune #undef __FUNCT__
98421d9b32SPeter Brune #define __FUNCT__ "SNESReset_FAS"
99421d9b32SPeter Brune PetscErrorCode SNESReset_FAS(SNES snes)
100421d9b32SPeter Brune {
10177df8cc4SPeter Brune   PetscErrorCode ierr  = 0;
102421d9b32SPeter Brune   SNES_FAS       * fas = (SNES_FAS*)snes->data;
103421d9b32SPeter Brune 
104421d9b32SPeter Brune   PetscFunctionBegin;
105ab8d36c9SPeter Brune   ierr = SNESDestroy(&fas->smoothu);CHKERRQ(ierr);
106ab8d36c9SPeter Brune   ierr = SNESDestroy(&fas->smoothd);CHKERRQ(ierr);
1073dccd265SPeter Brune   ierr = MatDestroy(&fas->inject);CHKERRQ(ierr);
108bccf9bb3SJed Brown   ierr = MatDestroy(&fas->interpolate);CHKERRQ(ierr);
109bccf9bb3SJed Brown   ierr = MatDestroy(&fas->restrct);CHKERRQ(ierr);
110bccf9bb3SJed Brown   ierr = VecDestroy(&fas->rscale);CHKERRQ(ierr);
111742fe5e2SPeter Brune   if (fas->next) ierr = SNESReset(fas->next);CHKERRQ(ierr);
112421d9b32SPeter Brune   PetscFunctionReturn(0);
113421d9b32SPeter Brune }
114421d9b32SPeter Brune 
115421d9b32SPeter Brune #undef __FUNCT__
116421d9b32SPeter Brune #define __FUNCT__ "SNESDestroy_FAS"
117421d9b32SPeter Brune PetscErrorCode SNESDestroy_FAS(SNES snes)
118421d9b32SPeter Brune {
119421d9b32SPeter Brune   SNES_FAS       * fas = (SNES_FAS*)snes->data;
120742fe5e2SPeter Brune   PetscErrorCode ierr  = 0;
121421d9b32SPeter Brune 
122421d9b32SPeter Brune   PetscFunctionBegin;
123421d9b32SPeter Brune   /* recursively resets and then destroys */
12479d9a41aSPeter Brune   ierr = SNESReset(snes);CHKERRQ(ierr);
125*1aa26658SKarl Rupp   if (fas->next) {
126*1aa26658SKarl Rupp     ierr = SNESDestroy(&fas->next);CHKERRQ(ierr);
127*1aa26658SKarl Rupp   }
128421d9b32SPeter Brune   ierr = PetscFree(fas);CHKERRQ(ierr);
129421d9b32SPeter Brune   PetscFunctionReturn(0);
130421d9b32SPeter Brune }
131421d9b32SPeter Brune 
132421d9b32SPeter Brune #undef __FUNCT__
133421d9b32SPeter Brune #define __FUNCT__ "SNESSetUp_FAS"
134421d9b32SPeter Brune PetscErrorCode SNESSetUp_FAS(SNES snes)
135421d9b32SPeter Brune {
13648bfdf8aSPeter Brune   SNES_FAS       *fas = (SNES_FAS*) snes->data;
137421d9b32SPeter Brune   PetscErrorCode ierr;
138efe1f98aSPeter Brune   VecScatter     injscatter;
139d1adcc6fSPeter Brune   PetscInt       dm_levels;
1403dccd265SPeter Brune   Vec            vec_sol, vec_func, vec_sol_update, vec_rhs; /* preserve these if they're set through the reset */
141ab8d36c9SPeter Brune   SNES           next;
142ab8d36c9SPeter Brune   PetscBool      isFine;
143f89ba88eSPeter Brune   SNESLineSearch linesearch;
144f89ba88eSPeter Brune   SNESLineSearch slinesearch;
145f89ba88eSPeter Brune   void           *lsprectx,*lspostctx;
1466b2b7091SBarry Smith   PetscErrorCode (*precheck)(SNESLineSearch,Vec,Vec,PetscBool*,void*);
1476b2b7091SBarry Smith   PetscErrorCode (*postcheck)(SNESLineSearch,Vec,Vec,Vec,PetscBool*,PetscBool*,void*);
148eff52c0eSPeter Brune 
1496b2b7091SBarry Smith   PetscFunctionBegin;
150ab8d36c9SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
151ab8d36c9SPeter Brune   if (fas->usedmfornumberoflevels && isFine) {
152d1adcc6fSPeter Brune     ierr = DMGetRefineLevel(snes->dm,&dm_levels);CHKERRQ(ierr);
153d1adcc6fSPeter Brune     dm_levels++;
154cc05f883SPeter Brune     if (dm_levels > fas->levels) {
1552e8ce248SJed Brown       /* we don't want the solution and func vectors to be destroyed in the SNESReset when it's called in SNESFASSetLevels_FAS*/
1563dccd265SPeter Brune       vec_sol              = snes->vec_sol;
1573dccd265SPeter Brune       vec_func             = snes->vec_func;
1583dccd265SPeter Brune       vec_sol_update       = snes->vec_sol_update;
1593dccd265SPeter Brune       vec_rhs              = snes->vec_rhs;
1603dccd265SPeter Brune       snes->vec_sol        = PETSC_NULL;
1613dccd265SPeter Brune       snes->vec_func       = PETSC_NULL;
1623dccd265SPeter Brune       snes->vec_sol_update = PETSC_NULL;
1633dccd265SPeter Brune       snes->vec_rhs        = PETSC_NULL;
1643dccd265SPeter Brune 
1653dccd265SPeter Brune       /* reset the number of levels */
166d1adcc6fSPeter Brune       ierr = SNESFASSetLevels(snes,dm_levels,PETSC_NULL);CHKERRQ(ierr);
167cc05f883SPeter Brune       ierr = SNESSetFromOptions(snes);CHKERRQ(ierr);
1683dccd265SPeter Brune 
1693dccd265SPeter Brune       snes->vec_sol        = vec_sol;
1703dccd265SPeter Brune       snes->vec_func       = vec_func;
1713dccd265SPeter Brune       snes->vec_rhs        = vec_rhs;
1723dccd265SPeter Brune       snes->vec_sol_update = vec_sol_update;
173d1adcc6fSPeter Brune     }
174d1adcc6fSPeter Brune   }
175ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
176ab8d36c9SPeter Brune   if (!isFine) snes->gridsequence = 0; /* no grid sequencing inside the multigrid hierarchy! */
1773dccd265SPeter Brune 
17807144faaSPeter Brune   if (fas->fastype == SNES_FAS_MULTIPLICATIVE) {
179e4ed7901SPeter Brune     ierr = SNESDefaultGetWork(snes, 2);CHKERRQ(ierr); /* work vectors used for intergrid transfers */
18007144faaSPeter Brune   } else {
181e7f468e7SPeter Brune     ierr = SNESDefaultGetWork(snes, 2);CHKERRQ(ierr); /* work vectors used for intergrid transfers */
18207144faaSPeter Brune   }
183cc05f883SPeter Brune 
184ab8d36c9SPeter Brune   /* set up the smoothers if they haven't already been set up */
185ab8d36c9SPeter Brune   if (!fas->smoothd) {
186ab8d36c9SPeter Brune     ierr = SNESFASCycleCreateSmoother_Private(snes, &fas->smoothd);CHKERRQ(ierr);
187ab8d36c9SPeter Brune   }
188ab8d36c9SPeter Brune 
18979d9a41aSPeter Brune   if (snes->dm) {
190ab8d36c9SPeter Brune     /* set the smoother DMs properly */
191ab8d36c9SPeter Brune     if (fas->smoothu) ierr = SNESSetDM(fas->smoothu, snes->dm);CHKERRQ(ierr);
192ab8d36c9SPeter Brune     ierr = SNESSetDM(fas->smoothd, snes->dm);CHKERRQ(ierr);
19379d9a41aSPeter Brune     /* construct EVERYTHING from the DM -- including the progressive set of smoothers */
194ab8d36c9SPeter Brune     if (next) {
19579d9a41aSPeter Brune       /* for now -- assume the DM and the evaluation functions have been set externally */
196ab8d36c9SPeter Brune       if (!next->dm) {
197ab8d36c9SPeter Brune         ierr = DMCoarsen(snes->dm, ((PetscObject)next)->comm, &next->dm);CHKERRQ(ierr);
198ab8d36c9SPeter Brune         ierr = SNESSetDM(next, next->dm);CHKERRQ(ierr);
19979d9a41aSPeter Brune       }
20079d9a41aSPeter Brune       /* set the interpolation and restriction from the DM */
20179d9a41aSPeter Brune       if (!fas->interpolate) {
202ab8d36c9SPeter Brune         ierr = DMCreateInterpolation(next->dm, snes->dm, &fas->interpolate, &fas->rscale);CHKERRQ(ierr);
203bccf9bb3SJed Brown         if (!fas->restrct) {
204bccf9bb3SJed Brown           ierr         = PetscObjectReference((PetscObject)fas->interpolate);CHKERRQ(ierr);
20579d9a41aSPeter Brune           fas->restrct = fas->interpolate;
20679d9a41aSPeter Brune         }
207bccf9bb3SJed Brown       }
20879d9a41aSPeter Brune       /* set the injection from the DM */
20979d9a41aSPeter Brune       if (!fas->inject) {
210ab8d36c9SPeter Brune         ierr = DMCreateInjection(next->dm, snes->dm, &injscatter);CHKERRQ(ierr);
21179d9a41aSPeter Brune         ierr = MatCreateScatter(((PetscObject)snes)->comm, injscatter, &fas->inject);CHKERRQ(ierr);
21279d9a41aSPeter Brune         ierr = VecScatterDestroy(&injscatter);CHKERRQ(ierr);
21379d9a41aSPeter Brune       }
21479d9a41aSPeter Brune     }
21579d9a41aSPeter Brune   }
21679d9a41aSPeter Brune   /*pass the smoother, function, and jacobian up to the next level if it's not user set already */
21779d9a41aSPeter Brune   if (fas->galerkin) {
218*1aa26658SKarl Rupp     if (next) {
219ab8d36c9SPeter Brune       ierr = SNESSetFunction(next, PETSC_NULL, SNESFASGalerkinDefaultFunction, next);CHKERRQ(ierr);
220*1aa26658SKarl Rupp     }
221*1aa26658SKarl Rupp     if (fas->smoothd && fas->level != fas->levels - 1) {
222*1aa26658SKarl Rupp       ierr = SNESSetFunction(fas->smoothd, PETSC_NULL, SNESFASGalerkinDefaultFunction, snes);CHKERRQ(ierr);
223*1aa26658SKarl Rupp     }
224*1aa26658SKarl Rupp     if (fas->smoothu && fas->level != fas->levels - 1) {
225*1aa26658SKarl Rupp       ierr = SNESSetFunction(fas->smoothu, PETSC_NULL, SNESFASGalerkinDefaultFunction, snes);CHKERRQ(ierr);
226*1aa26658SKarl Rupp     }
22779d9a41aSPeter Brune   }
22879d9a41aSPeter Brune 
229534ebe21SPeter Brune   /* sets the down (pre) smoother's default norm and sets it from options */
230534ebe21SPeter Brune   if (fas->smoothd) {
231bc3f2f05SPeter Brune     if (fas->level == 0 && fas->levels != 1) {
232534ebe21SPeter Brune       ierr = SNESSetNormType(fas->smoothd, SNES_NORM_NONE);CHKERRQ(ierr);
233534ebe21SPeter Brune     } else {
234534ebe21SPeter Brune       ierr = SNESSetNormType(fas->smoothd, SNES_NORM_FINAL_ONLY);CHKERRQ(ierr);
235534ebe21SPeter Brune     }
2367fce8c19SPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)snes, (PetscObject)fas->smoothd);CHKERRQ(ierr);
237534ebe21SPeter Brune     ierr = SNESSetFromOptions(fas->smoothd);CHKERRQ(ierr);
238f89ba88eSPeter Brune     ierr = SNESGetSNESLineSearch(snes,&linesearch);CHKERRQ(ierr);
239f89ba88eSPeter Brune     ierr = SNESGetSNESLineSearch(fas->smoothd,&slinesearch);CHKERRQ(ierr);
2406b2b7091SBarry Smith     ierr = SNESLineSearchGetPreCheck(linesearch,&precheck,&lsprectx);CHKERRQ(ierr);
2416b2b7091SBarry Smith     ierr = SNESLineSearchGetPostCheck(linesearch,&postcheck,&lspostctx);CHKERRQ(ierr);
2426b2b7091SBarry Smith     ierr = SNESLineSearchSetPreCheck(slinesearch,precheck,lsprectx);CHKERRQ(ierr);
2436b2b7091SBarry Smith     ierr = SNESLineSearchSetPostCheck(slinesearch,postcheck,lspostctx);CHKERRQ(ierr);
244f89ba88eSPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)linesearch, (PetscObject)slinesearch);CHKERRQ(ierr);
2450dd27c6cSPeter Brune 
2460dd27c6cSPeter Brune     fas->smoothd->vec_sol        = snes->vec_sol;
2470dd27c6cSPeter Brune     ierr                         = PetscObjectReference((PetscObject)snes->vec_sol);CHKERRQ(ierr);
2480dd27c6cSPeter Brune     fas->smoothd->vec_sol_update = snes->vec_sol_update;
2490dd27c6cSPeter Brune     ierr                         = PetscObjectReference((PetscObject)snes->vec_sol_update);CHKERRQ(ierr);
2500dd27c6cSPeter Brune     fas->smoothd->vec_func       = snes->vec_func;
2510dd27c6cSPeter Brune     ierr                         = PetscObjectReference((PetscObject)snes->vec_func);CHKERRQ(ierr);
2520dd27c6cSPeter Brune 
2530dd27c6cSPeter Brune     if (fas->eventsmoothsetup) {ierr = PetscLogEventBegin(fas->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
2540dd27c6cSPeter Brune     ierr = SNESSetUp(fas->smoothd);CHKERRQ(ierr);
2550dd27c6cSPeter Brune     if (fas->eventsmoothsetup) {ierr = PetscLogEventEnd(fas->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
256534ebe21SPeter Brune   }
257534ebe21SPeter Brune 
258534ebe21SPeter Brune   /* sets the up (post) smoother's default norm and sets it from options */
259534ebe21SPeter Brune   if (fas->smoothu) {
260534ebe21SPeter Brune     if (fas->level != fas->levels - 1) {
261534ebe21SPeter Brune       ierr = SNESSetNormType(fas->smoothu, SNES_NORM_NONE);CHKERRQ(ierr);
262534ebe21SPeter Brune     } else {
263534ebe21SPeter Brune       ierr = SNESSetNormType(fas->smoothu, SNES_NORM_FINAL_ONLY);CHKERRQ(ierr);
264534ebe21SPeter Brune     }
2657fce8c19SPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)snes, (PetscObject)fas->smoothu);CHKERRQ(ierr);
266534ebe21SPeter Brune     ierr = SNESSetFromOptions(fas->smoothu);CHKERRQ(ierr);
267f89ba88eSPeter Brune     ierr = SNESGetSNESLineSearch(snes,&linesearch);CHKERRQ(ierr);
268f89ba88eSPeter Brune     ierr = SNESGetSNESLineSearch(fas->smoothu,&slinesearch);CHKERRQ(ierr);
2696b2b7091SBarry Smith     ierr = SNESLineSearchGetPreCheck(linesearch,&precheck,&lsprectx);CHKERRQ(ierr);
2706b2b7091SBarry Smith     ierr = SNESLineSearchGetPostCheck(linesearch,&postcheck,&lspostctx);CHKERRQ(ierr);
2716b2b7091SBarry Smith     ierr = SNESLineSearchSetPreCheck(slinesearch,precheck,lsprectx);CHKERRQ(ierr);
2726b2b7091SBarry Smith     ierr = SNESLineSearchSetPostCheck(slinesearch,postcheck,lspostctx);CHKERRQ(ierr);
273f89ba88eSPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)linesearch, (PetscObject)slinesearch);CHKERRQ(ierr);
2740dd27c6cSPeter Brune 
2750dd27c6cSPeter Brune     fas->smoothu->vec_sol        = snes->vec_sol;
2760dd27c6cSPeter Brune     ierr                         = PetscObjectReference((PetscObject)snes->vec_sol);CHKERRQ(ierr);
2770dd27c6cSPeter Brune     fas->smoothu->vec_sol_update = snes->vec_sol_update;
2780dd27c6cSPeter Brune     ierr                         = PetscObjectReference((PetscObject)snes->vec_sol_update);CHKERRQ(ierr);
2790dd27c6cSPeter Brune     fas->smoothu->vec_func       = snes->vec_func;
2800dd27c6cSPeter Brune     ierr                         = PetscObjectReference((PetscObject)snes->vec_func);CHKERRQ(ierr);
2810dd27c6cSPeter Brune 
2820dd27c6cSPeter Brune     if (fas->eventsmoothsetup) {ierr = PetscLogEventBegin(fas->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
2830dd27c6cSPeter Brune     ierr = SNESSetUp(fas->smoothu);CHKERRQ(ierr);
2840dd27c6cSPeter Brune     if (fas->eventsmoothsetup) {ierr = PetscLogEventEnd(fas->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
2850dd27c6cSPeter Brune 
286534ebe21SPeter Brune   }
287d06165b7SPeter Brune 
288ab8d36c9SPeter Brune   if (next) {
28979d9a41aSPeter Brune     /* gotta set up the solution vector for this to work */
290ab8d36c9SPeter Brune     if (!next->vec_sol) {ierr = SNESFASCreateCoarseVec(snes,&next->vec_sol);CHKERRQ(ierr);}
291ab8d36c9SPeter Brune     if (!next->vec_rhs) {ierr = SNESFASCreateCoarseVec(snes,&next->vec_rhs);CHKERRQ(ierr);}
2927fce8c19SPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)snes, (PetscObject)next);CHKERRQ(ierr);
293f89ba88eSPeter Brune     ierr = SNESGetSNESLineSearch(snes,&linesearch);CHKERRQ(ierr);
294f89ba88eSPeter Brune     ierr = SNESGetSNESLineSearch(fas->next,&slinesearch);CHKERRQ(ierr);
2956b2b7091SBarry Smith     ierr = SNESLineSearchGetPreCheck(linesearch,&precheck,&lsprectx);CHKERRQ(ierr);
2966b2b7091SBarry Smith     ierr = SNESLineSearchGetPostCheck(linesearch,&postcheck,&lspostctx);CHKERRQ(ierr);
2976b2b7091SBarry Smith     ierr = SNESLineSearchSetPreCheck(slinesearch,precheck,lsprectx);CHKERRQ(ierr);
2986b2b7091SBarry Smith     ierr = SNESLineSearchSetPostCheck(slinesearch,postcheck,lspostctx);CHKERRQ(ierr);
299f89ba88eSPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)linesearch, (PetscObject)slinesearch);CHKERRQ(ierr);
300ab8d36c9SPeter Brune     ierr = SNESSetUp(next);CHKERRQ(ierr);
30179d9a41aSPeter Brune   }
3026273346dSPeter Brune   /* setup FAS work vectors */
3036273346dSPeter Brune   if (fas->galerkin) {
3046273346dSPeter Brune     ierr = VecDuplicate(snes->vec_sol, &fas->Xg);CHKERRQ(ierr);
3056273346dSPeter Brune     ierr = VecDuplicate(snes->vec_sol, &fas->Fg);CHKERRQ(ierr);
3066273346dSPeter Brune   }
307421d9b32SPeter Brune   PetscFunctionReturn(0);
308421d9b32SPeter Brune }
309421d9b32SPeter Brune 
310421d9b32SPeter Brune #undef __FUNCT__
311421d9b32SPeter Brune #define __FUNCT__ "SNESSetFromOptions_FAS"
312421d9b32SPeter Brune PetscErrorCode SNESSetFromOptions_FAS(SNES snes)
313421d9b32SPeter Brune {
314ee78dd50SPeter Brune   SNES_FAS       *fas   = (SNES_FAS*) snes->data;
315ee78dd50SPeter Brune   PetscInt       levels = 1;
3164d26bfa5SPeter Brune   PetscBool      flg    = PETSC_FALSE, upflg = PETSC_FALSE, downflg = PETSC_FALSE, monflg = PETSC_FALSE, galerkinflg = PETSC_FALSE;
317421d9b32SPeter Brune   PetscErrorCode ierr;
318ee78dd50SPeter Brune   char           monfilename[PETSC_MAX_PATH_LEN];
31907144faaSPeter Brune   SNESFASType    fastype;
320fde0ff24SPeter Brune   const char     *optionsprefix;
321f1c6b773SPeter Brune   SNESLineSearch linesearch;
32266585501SPeter Brune   PetscInt       m, n_up, n_down;
323ab8d36c9SPeter Brune   SNES           next;
324ab8d36c9SPeter Brune   PetscBool      isFine;
325421d9b32SPeter Brune 
326421d9b32SPeter Brune   PetscFunctionBegin;
327ab8d36c9SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
328c90fad12SPeter Brune   ierr = PetscOptionsHead("SNESFAS Options-----------------------------------");CHKERRQ(ierr);
329ee78dd50SPeter Brune 
330ab8d36c9SPeter Brune   /* number of levels -- only process most options on the finest level */
331ab8d36c9SPeter Brune   if (isFine) {
332ee78dd50SPeter Brune     ierr = PetscOptionsInt("-snes_fas_levels", "Number of Levels", "SNESFASSetLevels", levels, &levels, &flg);CHKERRQ(ierr);
333c732cbdbSBarry Smith     if (!flg && snes->dm) {
334c732cbdbSBarry Smith       ierr = DMGetRefineLevel(snes->dm,&levels);CHKERRQ(ierr);
335c732cbdbSBarry Smith       levels++;
336d1adcc6fSPeter Brune       fas->usedmfornumberoflevels = PETSC_TRUE;
337c732cbdbSBarry Smith     }
338ee78dd50SPeter Brune     ierr    = SNESFASSetLevels(snes, levels, PETSC_NULL);CHKERRQ(ierr);
33907144faaSPeter Brune     fastype = fas->fastype;
34007144faaSPeter Brune     ierr    = PetscOptionsEnum("-snes_fas_type","FAS correction type","SNESFASSetType",SNESFASTypes,(PetscEnum)fastype,(PetscEnum*)&fastype,&flg);CHKERRQ(ierr);
34107144faaSPeter Brune     if (flg) {
34207144faaSPeter Brune       ierr = SNESFASSetType(snes, fastype);CHKERRQ(ierr);
34307144faaSPeter Brune     }
344ee78dd50SPeter Brune 
345fde0ff24SPeter Brune     ierr = SNESGetOptionsPrefix(snes, &optionsprefix);CHKERRQ(ierr);
346ab8d36c9SPeter Brune     ierr = PetscOptionsInt("-snes_fas_cycles","Number of cycles","SNESFASSetCycles",fas->n_cycles,&m,&flg);CHKERRQ(ierr);
347ab8d36c9SPeter Brune     if (flg) {
348ab8d36c9SPeter Brune       ierr = SNESFASSetCycles(snes, m);CHKERRQ(ierr);
349fde0ff24SPeter Brune     }
350fde0ff24SPeter Brune 
351ab8d36c9SPeter Brune     ierr = PetscOptionsBool("-snes_fas_galerkin", "Form coarse problems with Galerkin","SNESFASSetGalerkin",fas->galerkin,&galerkinflg,&flg);CHKERRQ(ierr);
352ab8d36c9SPeter Brune     if (flg) {
353ab8d36c9SPeter Brune       ierr = SNESFASSetGalerkin(snes, galerkinflg);CHKERRQ(ierr);
354ab8d36c9SPeter Brune     }
355ee78dd50SPeter Brune 
35666585501SPeter Brune     ierr = PetscOptionsInt("-snes_fas_smoothup","Number of post-smoothing steps","SNESFASSetNumberSmoothUp",fas->max_up_it,&n_up,&upflg);CHKERRQ(ierr);
357162d76ddSPeter Brune 
35866585501SPeter Brune     ierr = PetscOptionsInt("-snes_fas_smoothdown","Number of pre-smoothing steps","SNESFASSetNumberSmoothDown",fas->max_down_it,&n_down,&downflg);CHKERRQ(ierr);
359162d76ddSPeter Brune 
360c8c899caSPeter Brune     ierr = PetscOptionsString("-snes_fas_monitor","Monitor FAS progress","SNESFASSetMonitor","stdout",monfilename,PETSC_MAX_PATH_LEN,&monflg);CHKERRQ(ierr);
361c8c899caSPeter Brune     if (monflg) ierr = SNESFASSetMonitor(snes, PETSC_TRUE);CHKERRQ(ierr);
3620dd27c6cSPeter Brune 
3630dd27c6cSPeter Brune     flg    = PETSC_FALSE;
3640dd27c6cSPeter Brune     monflg = PETSC_TRUE;
3650dd27c6cSPeter Brune     ierr   = PetscOptionsBool("-snes_fas_log","Log times for each FAS level","SNESFASSetLog",monflg,&monflg,&flg);CHKERRQ(ierr);
3660dd27c6cSPeter Brune     if (flg) {ierr = SNESFASSetLog(snes,monflg);CHKERRQ(ierr);}
367ab8d36c9SPeter Brune   }
368ee78dd50SPeter Brune 
369421d9b32SPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
3708cc86e31SPeter Brune   /* setup from the determined types if there is no pointwise procedure or smoother defined */
371162d76ddSPeter Brune   if (upflg) {
37266585501SPeter Brune     ierr = SNESFASSetNumberSmoothUp(snes,n_up);CHKERRQ(ierr);
373162d76ddSPeter Brune   }
374162d76ddSPeter Brune   if (downflg) {
37566585501SPeter Brune     ierr = SNESFASSetNumberSmoothDown(snes,n_down);CHKERRQ(ierr);
376162d76ddSPeter Brune   }
377eff52c0eSPeter Brune 
3789e764e56SPeter Brune   /* set up the default line search for coarse grid corrections */
3799e764e56SPeter Brune   if (fas->fastype == SNES_FAS_ADDITIVE) {
3809e764e56SPeter Brune     if (!snes->linesearch) {
381f1c6b773SPeter Brune       ierr = SNESGetSNESLineSearch(snes, &linesearch);CHKERRQ(ierr);
3821a4f838cSPeter Brune       ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHL2);CHKERRQ(ierr);
3839e764e56SPeter Brune     }
3849e764e56SPeter Brune   }
3859e764e56SPeter Brune 
386ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
387ee78dd50SPeter Brune   /* recursive option setting for the smoothers */
388ab8d36c9SPeter Brune   if (next) {ierr = SNESSetFromOptions(next);CHKERRQ(ierr);}
389421d9b32SPeter Brune   PetscFunctionReturn(0);
390421d9b32SPeter Brune }
391421d9b32SPeter Brune 
392421d9b32SPeter Brune #undef __FUNCT__
393421d9b32SPeter Brune #define __FUNCT__ "SNESView_FAS"
394421d9b32SPeter Brune PetscErrorCode SNESView_FAS(SNES snes, PetscViewer viewer)
395421d9b32SPeter Brune {
396421d9b32SPeter Brune   SNES_FAS       *fas = (SNES_FAS*) snes->data;
397656ede7eSPeter Brune   PetscBool      isFine,iascii,isdraw;
398ab8d36c9SPeter Brune   PetscInt       i;
399421d9b32SPeter Brune   PetscErrorCode ierr;
400ab8d36c9SPeter Brune   SNES           smoothu, smoothd, levelsnes;
401421d9b32SPeter Brune 
402421d9b32SPeter Brune   PetscFunctionBegin;
403ab8d36c9SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
404ab8d36c9SPeter Brune   if (isFine) {
405251f4c67SDmitry Karpeev     ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
406656ede7eSPeter Brune     ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr);
407421d9b32SPeter Brune     if (iascii) {
408ab8d36c9SPeter Brune       ierr = PetscViewerASCIIPrintf(viewer, "FAS: type is %s, levels=%D, cycles=%D\n",  SNESFASTypes[fas->fastype], fas->levels, fas->n_cycles);CHKERRQ(ierr);
409ab8d36c9SPeter Brune       if (fas->galerkin) {
410ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid function evaluation\n");CHKERRQ(ierr);
411421d9b32SPeter Brune       } else {
412ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPrintf(viewer,"    Not using Galerkin computed coarse grid function evaluation\n");CHKERRQ(ierr);
413421d9b32SPeter Brune       }
414ab8d36c9SPeter Brune       for (i=0; i<fas->levels; i++) {
415ab8d36c9SPeter Brune         ierr = SNESFASGetCycleSNES(snes, i, &levelsnes);CHKERRQ(ierr);
416ab8d36c9SPeter Brune         ierr = SNESFASCycleGetSmootherUp(levelsnes, &smoothu);CHKERRQ(ierr);
417ab8d36c9SPeter Brune         ierr = SNESFASCycleGetSmootherDown(levelsnes, &smoothd);CHKERRQ(ierr);
418ab8d36c9SPeter Brune         if (!i) {
419ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Coarse grid solver -- level %D -------------------------------\n",i);CHKERRQ(ierr);
420421d9b32SPeter Brune         } else {
421ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
422421d9b32SPeter Brune         }
423ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
424ab8d36c9SPeter Brune         ierr = SNESView(smoothd,viewer);CHKERRQ(ierr);
425ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
426ab8d36c9SPeter Brune         if (i && (smoothd == smoothu)) {
427ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n");CHKERRQ(ierr);
428ab8d36c9SPeter Brune         } else if (i) {
429ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
430ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
431ab8d36c9SPeter Brune           ierr = SNESView(smoothu,viewer);CHKERRQ(ierr);
432ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
433ab8d36c9SPeter Brune         }
434ab8d36c9SPeter Brune       }
435656ede7eSPeter Brune     } else if (isdraw) {
436656ede7eSPeter Brune       PetscDraw draw;
437b4375e8dSPeter Brune       PetscReal x,w,y,bottom,th,wth;
438656ede7eSPeter Brune       SNES_FAS  *curfas = fas;
439656ede7eSPeter Brune       ierr   = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr);
440656ede7eSPeter Brune       ierr   = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr);
441656ede7eSPeter Brune       ierr   = PetscDrawStringGetSize(draw,&wth,&th);CHKERRQ(ierr);
442656ede7eSPeter Brune       bottom = y - th;
443656ede7eSPeter Brune       while (curfas) {
444b4375e8dSPeter Brune         if (!curfas->smoothu) {
445656ede7eSPeter Brune           ierr = PetscDrawPushCurrentPoint(draw,x,bottom);CHKERRQ(ierr);
446656ede7eSPeter Brune           if (curfas->smoothd) ierr = SNESView(curfas->smoothd,viewer);CHKERRQ(ierr);
447656ede7eSPeter Brune           ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr);
448b4375e8dSPeter Brune         } else {
449b4375e8dSPeter Brune           w    = 0.5*PetscMin(1.0-x,x);
450b4375e8dSPeter Brune           ierr = PetscDrawPushCurrentPoint(draw,x-w,bottom);CHKERRQ(ierr);
451b4375e8dSPeter Brune           if (curfas->smoothd) ierr = SNESView(curfas->smoothd,viewer);CHKERRQ(ierr);
452b4375e8dSPeter Brune           ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr);
453b4375e8dSPeter Brune           ierr = PetscDrawPushCurrentPoint(draw,x+w,bottom);CHKERRQ(ierr);
454b4375e8dSPeter Brune           if (curfas->smoothu) ierr = SNESView(curfas->smoothu,viewer);CHKERRQ(ierr);
455b4375e8dSPeter Brune           ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr);
456b4375e8dSPeter Brune         }
457656ede7eSPeter Brune         /* this is totally bogus but we have no way of knowing how low the previous one was draw to */
458656ede7eSPeter Brune         bottom -= 5*th;
459*1aa26658SKarl Rupp         if (curfas->next) curfas = (SNES_FAS*)curfas->next->data;
460*1aa26658SKarl Rupp         else curfas = PETSC_NULL;
461656ede7eSPeter Brune       }
462421d9b32SPeter Brune     }
463ab8d36c9SPeter Brune   }
464421d9b32SPeter Brune   PetscFunctionReturn(0);
465421d9b32SPeter Brune }
466421d9b32SPeter Brune 
467421d9b32SPeter Brune #undef __FUNCT__
46891f99d7cSPeter Brune #define __FUNCT__ "SNESFASDownSmooth_Private"
46939bd7f45SPeter Brune /*
47039bd7f45SPeter Brune Defines the action of the downsmoother
47139bd7f45SPeter Brune  */
47291f99d7cSPeter Brune PetscErrorCode SNESFASDownSmooth_Private(SNES snes, Vec B, Vec X, Vec F, PetscReal *fnorm)
473b9c2fdf1SPeter Brune {
47439bd7f45SPeter Brune   PetscErrorCode      ierr = 0;
475742fe5e2SPeter Brune   SNESConvergedReason reason;
476ab8d36c9SPeter Brune   Vec                 FPC;
477ab8d36c9SPeter Brune   SNES                smoothd;
4780dd27c6cSPeter Brune   SNES_FAS            *fas = (SNES_FAS*) snes->data;
4796e111a19SKarl Rupp 
480421d9b32SPeter Brune   PetscFunctionBegin;
481ab8d36c9SPeter Brune   ierr = SNESFASCycleGetSmootherDown(snes, &smoothd);CHKERRQ(ierr);
482e4ed7901SPeter Brune   ierr = SNESSetInitialFunction(smoothd, F);CHKERRQ(ierr);
483e4ed7901SPeter Brune   ierr = SNESSetInitialFunctionNorm(smoothd, *fnorm);CHKERRQ(ierr);
4840dd27c6cSPeter Brune   if (fas->eventsmoothsolve) {ierr = PetscLogEventBegin(fas->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
485ab8d36c9SPeter Brune   ierr = SNESSolve(smoothd, B, X);CHKERRQ(ierr);
4860dd27c6cSPeter Brune   if (fas->eventsmoothsolve) {ierr = PetscLogEventEnd(fas->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
487742fe5e2SPeter Brune   /* check convergence reason for the smoother */
488ab8d36c9SPeter Brune   ierr = SNESGetConvergedReason(smoothd,&reason);CHKERRQ(ierr);
489e70c42e5SPeter Brune   if (reason < 0 && !(reason == SNES_DIVERGED_MAX_IT || reason == SNES_DIVERGED_LOCAL_MIN)) {
490742fe5e2SPeter Brune     snes->reason = SNES_DIVERGED_INNER;
491742fe5e2SPeter Brune     PetscFunctionReturn(0);
492742fe5e2SPeter Brune   }
493ab8d36c9SPeter Brune   ierr = SNESGetFunction(smoothd, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
4944b32a720SPeter Brune   ierr = VecCopy(FPC, F);CHKERRQ(ierr);
495b9c2fdf1SPeter Brune   ierr = SNESGetFunctionNorm(smoothd, fnorm);CHKERRQ(ierr);
49639bd7f45SPeter Brune   PetscFunctionReturn(0);
49739bd7f45SPeter Brune }
49839bd7f45SPeter Brune 
49939bd7f45SPeter Brune 
50039bd7f45SPeter Brune #undef __FUNCT__
50191f99d7cSPeter Brune #define __FUNCT__ "SNESFASUpSmooth_Private"
50239bd7f45SPeter Brune /*
50307144faaSPeter Brune Defines the action of the upsmoother
50439bd7f45SPeter Brune  */
5050adebc6cSBarry Smith PetscErrorCode SNESFASUpSmooth_Private(SNES snes, Vec B, Vec X, Vec F, PetscReal *fnorm)
5060adebc6cSBarry Smith {
50739bd7f45SPeter Brune   PetscErrorCode      ierr = 0;
50839bd7f45SPeter Brune   SNESConvergedReason reason;
509ab8d36c9SPeter Brune   Vec                 FPC;
510ab8d36c9SPeter Brune   SNES                smoothu;
5110dd27c6cSPeter Brune   SNES_FAS            *fas = (SNES_FAS*) snes->data;
512ab8d36c9SPeter Brune 
5136e111a19SKarl Rupp   PetscFunctionBegin;
514ab8d36c9SPeter Brune   ierr = SNESFASCycleGetSmootherUp(snes, &smoothu);CHKERRQ(ierr);
5150dd27c6cSPeter Brune   if (fas->eventsmoothsolve) {ierr = PetscLogEventBegin(fas->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
516ab8d36c9SPeter Brune   ierr = SNESSolve(smoothu, B, X);CHKERRQ(ierr);
5170dd27c6cSPeter Brune   if (fas->eventsmoothsolve) {ierr = PetscLogEventEnd(fas->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
51839bd7f45SPeter Brune   /* check convergence reason for the smoother */
519ab8d36c9SPeter Brune   ierr = SNESGetConvergedReason(smoothu,&reason);CHKERRQ(ierr);
52039bd7f45SPeter Brune   if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
52139bd7f45SPeter Brune     snes->reason = SNES_DIVERGED_INNER;
52239bd7f45SPeter Brune     PetscFunctionReturn(0);
52339bd7f45SPeter Brune   }
524ab8d36c9SPeter Brune   ierr = SNESGetFunction(smoothu, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
5254b32a720SPeter Brune   ierr = VecCopy(FPC, F);CHKERRQ(ierr);
526b9c2fdf1SPeter Brune   ierr = SNESGetFunctionNorm(smoothu, fnorm);CHKERRQ(ierr);
52739bd7f45SPeter Brune   PetscFunctionReturn(0);
52839bd7f45SPeter Brune }
52939bd7f45SPeter Brune 
53039bd7f45SPeter Brune #undef __FUNCT__
531938e4a01SJed Brown #define __FUNCT__ "SNESFASCreateCoarseVec"
532938e4a01SJed Brown /*@
533938e4a01SJed Brown    SNESFASCreateCoarseVec - create Vec corresponding to a state vector on one level coarser than current level
534938e4a01SJed Brown 
535938e4a01SJed Brown    Collective
536938e4a01SJed Brown 
537938e4a01SJed Brown    Input Arguments:
538938e4a01SJed Brown .  snes - SNESFAS
539938e4a01SJed Brown 
540938e4a01SJed Brown    Output Arguments:
541938e4a01SJed Brown .  Xcoarse - vector on level one coarser than snes
542938e4a01SJed Brown 
543938e4a01SJed Brown    Level: developer
544938e4a01SJed Brown 
545938e4a01SJed Brown .seealso: SNESFASSetRestriction(), SNESFASRestrict()
546938e4a01SJed Brown @*/
547938e4a01SJed Brown PetscErrorCode SNESFASCreateCoarseVec(SNES snes,Vec *Xcoarse)
548938e4a01SJed Brown {
549938e4a01SJed Brown   PetscErrorCode ierr;
550938e4a01SJed Brown   SNES_FAS       *fas = (SNES_FAS*)snes->data;
551938e4a01SJed Brown 
552938e4a01SJed Brown   PetscFunctionBegin;
553*1aa26658SKarl Rupp   if (fas->rscale) {
554*1aa26658SKarl Rupp     ierr = VecDuplicate(fas->rscale,Xcoarse);CHKERRQ(ierr);
555*1aa26658SKarl Rupp   }
556*1aa26658SKarl Rupp   else if (fas->inject) {
557*1aa26658SKarl Rupp     ierr = MatGetVecs(fas->inject,Xcoarse,PETSC_NULL);CHKERRQ(ierr);
558*1aa26658SKarl Rupp   }
559938e4a01SJed Brown   else SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must set restriction or injection");CHKERRQ(ierr);
560938e4a01SJed Brown   PetscFunctionReturn(0);
561938e4a01SJed Brown }
562938e4a01SJed Brown 
563e9923e8dSJed Brown #undef __FUNCT__
564e9923e8dSJed Brown #define __FUNCT__ "SNESFASRestrict"
565e9923e8dSJed Brown /*@
566e9923e8dSJed Brown    SNESFASRestrict - restrict a Vec to the next coarser level
567e9923e8dSJed Brown 
568e9923e8dSJed Brown    Collective
569e9923e8dSJed Brown 
570e9923e8dSJed Brown    Input Arguments:
571e9923e8dSJed Brown +  fine - SNES from which to restrict
572e9923e8dSJed Brown -  Xfine - vector to restrict
573e9923e8dSJed Brown 
574e9923e8dSJed Brown    Output Arguments:
575e9923e8dSJed Brown .  Xcoarse - result of restriction
576e9923e8dSJed Brown 
577e9923e8dSJed Brown    Level: developer
578e9923e8dSJed Brown 
579e9923e8dSJed Brown .seealso: SNESFASSetRestriction(), SNESFASSetInjection()
580e9923e8dSJed Brown @*/
581e9923e8dSJed Brown PetscErrorCode SNESFASRestrict(SNES fine,Vec Xfine,Vec Xcoarse)
582e9923e8dSJed Brown {
583e9923e8dSJed Brown   PetscErrorCode ierr;
584e9923e8dSJed Brown   SNES_FAS       *fas = (SNES_FAS*)fine->data;
585e9923e8dSJed Brown 
586e9923e8dSJed Brown   PetscFunctionBegin;
587e9923e8dSJed Brown   PetscValidHeaderSpecific(fine,SNES_CLASSID,1);
588e9923e8dSJed Brown   PetscValidHeaderSpecific(Xfine,VEC_CLASSID,2);
589e9923e8dSJed Brown   PetscValidHeaderSpecific(Xcoarse,VEC_CLASSID,3);
590e9923e8dSJed Brown   if (fas->inject) {
591e9923e8dSJed Brown     ierr = MatRestrict(fas->inject,Xfine,Xcoarse);CHKERRQ(ierr);
592e9923e8dSJed Brown   } else {
593e9923e8dSJed Brown     ierr = MatRestrict(fas->restrct,Xfine,Xcoarse);CHKERRQ(ierr);
594e9923e8dSJed Brown     ierr = VecPointwiseMult(Xcoarse,fas->rscale,Xcoarse);CHKERRQ(ierr);
595e9923e8dSJed Brown   }
596e9923e8dSJed Brown   PetscFunctionReturn(0);
597e9923e8dSJed Brown }
598e9923e8dSJed Brown 
599e9923e8dSJed Brown #undef __FUNCT__
6008c40d5fbSBarry Smith #define __FUNCT__ "SNESFASCoarseCorrection"
60139bd7f45SPeter Brune /*
60239bd7f45SPeter Brune 
60339bd7f45SPeter Brune Performs the FAS coarse correction as:
60439bd7f45SPeter Brune 
60539bd7f45SPeter Brune fine problem: F(x) = 0
60639bd7f45SPeter Brune coarse problem: F^c(x) = b^c
60739bd7f45SPeter Brune 
60839bd7f45SPeter Brune b^c = F^c(I^c_fx^f - I^c_fF(x))
60939bd7f45SPeter Brune 
61039bd7f45SPeter Brune  */
6110adebc6cSBarry Smith PetscErrorCode SNESFASCoarseCorrection(SNES snes, Vec X, Vec F, Vec X_new)
6120adebc6cSBarry Smith {
61339bd7f45SPeter Brune   PetscErrorCode      ierr;
61439bd7f45SPeter Brune   Vec                 X_c, Xo_c, F_c, B_c;
61539bd7f45SPeter Brune   SNESConvergedReason reason;
616ab8d36c9SPeter Brune   SNES                next;
617ab8d36c9SPeter Brune   Mat                 restrct, interpolate;
6180dd27c6cSPeter Brune   SNES_FAS            *fasc;
6195fd66863SKarl Rupp 
62039bd7f45SPeter Brune   PetscFunctionBegin;
621ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
622ab8d36c9SPeter Brune   if (next) {
6230dd27c6cSPeter Brune     fasc = (SNES_FAS*)next->data;
6240dd27c6cSPeter Brune 
625ab8d36c9SPeter Brune     ierr = SNESFASCycleGetRestriction(snes, &restrct);CHKERRQ(ierr);
626ab8d36c9SPeter Brune     ierr = SNESFASCycleGetInterpolation(snes, &interpolate);CHKERRQ(ierr);
627ab8d36c9SPeter Brune 
628ab8d36c9SPeter Brune     X_c  = next->vec_sol;
629ab8d36c9SPeter Brune     Xo_c = next->work[0];
630ab8d36c9SPeter Brune     F_c  = next->vec_func;
631ab8d36c9SPeter Brune     B_c  = next->vec_rhs;
632efe1f98aSPeter Brune 
6330dd27c6cSPeter Brune     if (fasc->eventinterprestrict) {ierr = PetscLogEventBegin(fasc->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
634938e4a01SJed Brown     ierr = SNESFASRestrict(snes,X,Xo_c);CHKERRQ(ierr);
635293a7e31SPeter Brune     /* restrict the defect */
636ab8d36c9SPeter Brune     ierr = MatRestrict(restrct, F, B_c);CHKERRQ(ierr);
6370dd27c6cSPeter Brune     if (fasc->eventinterprestrict) {ierr = PetscLogEventEnd(fasc->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
6380dd27c6cSPeter Brune 
6390dd27c6cSPeter Brune     if (fasc->eventresidual) {ierr = PetscLogEventBegin(fasc->eventresidual,0,0,0,0);CHKERRQ(ierr);}
640ab8d36c9SPeter Brune     ierr = SNESComputeFunction(next, Xo_c, F_c);CHKERRQ(ierr);
6410dd27c6cSPeter Brune     if (fasc->eventresidual) {ierr = PetscLogEventEnd(fasc->eventresidual,0,0,0,0);CHKERRQ(ierr);}
6420dd27c6cSPeter Brune 
6430dd27c6cSPeter Brune     /* solve the coarse problem corresponding to F^c(x^c) = b^c = F^c(Rx) - R(F(x) - b) */
644e4ed7901SPeter Brune     ierr = VecCopy(B_c, X_c);CHKERRQ(ierr);
645b9c2fdf1SPeter Brune     ierr = VecCopy(F_c, B_c);CHKERRQ(ierr);
646e4ed7901SPeter Brune     ierr = VecCopy(X_c, F_c);CHKERRQ(ierr);
647ee78dd50SPeter Brune     /* set initial guess of the coarse problem to the projected fine solution */
648ee78dd50SPeter Brune     ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr);
649c90fad12SPeter Brune 
650c90fad12SPeter Brune     /* recurse to the next level */
651e4ed7901SPeter Brune     ierr = SNESSetInitialFunction(next, F_c);CHKERRQ(ierr);
652ab8d36c9SPeter Brune     ierr = SNESSolve(next, B_c, X_c);CHKERRQ(ierr);
653ab8d36c9SPeter Brune     ierr = SNESGetConvergedReason(next,&reason);CHKERRQ(ierr);
654742fe5e2SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
655742fe5e2SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
656742fe5e2SPeter Brune       PetscFunctionReturn(0);
657742fe5e2SPeter Brune     }
658fa9694d7SPeter Brune     /* correct as x <- x + I(x^c - Rx)*/
659fa9694d7SPeter Brune     ierr = VecAXPY(X_c, -1.0, Xo_c);CHKERRQ(ierr);
6600dd27c6cSPeter Brune 
6610dd27c6cSPeter Brune     if (fasc->eventinterprestrict) {ierr = PetscLogEventBegin(fasc->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
662ab8d36c9SPeter Brune     ierr = MatInterpolateAdd(interpolate, X_c, X, X_new);CHKERRQ(ierr);
6630dd27c6cSPeter Brune     if (fasc->eventinterprestrict) {ierr = PetscLogEventEnd(fasc->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
664293a7e31SPeter Brune   }
66539bd7f45SPeter Brune   PetscFunctionReturn(0);
66639bd7f45SPeter Brune }
66739bd7f45SPeter Brune 
66839bd7f45SPeter Brune #undef __FUNCT__
6692cf9d1e8SPeter Brune #define __FUNCT__ "SNESFASCycle_Additive"
67039bd7f45SPeter Brune /*
67139bd7f45SPeter Brune 
67239bd7f45SPeter Brune The additive cycle looks like:
67339bd7f45SPeter Brune 
67407144faaSPeter Brune xhat = x
67507144faaSPeter Brune xhat = dS(x, b)
67607144faaSPeter Brune x = coarsecorrection(xhat, b_d)
67707144faaSPeter Brune x = x + nu*(xhat - x);
67839bd7f45SPeter Brune (optional) x = uS(x, b)
67939bd7f45SPeter Brune 
68039bd7f45SPeter Brune With the coarse RHS (defect correction) as below.
68139bd7f45SPeter Brune 
68239bd7f45SPeter Brune  */
6830adebc6cSBarry Smith PetscErrorCode SNESFASCycle_Additive(SNES snes, Vec X)
6840adebc6cSBarry Smith {
68507144faaSPeter Brune   Vec                 F, B, Xhat;
68622c1e704SPeter Brune   Vec                 X_c, Xo_c, F_c, B_c;
68739bd7f45SPeter Brune   PetscErrorCode      ierr;
68807144faaSPeter Brune   SNESConvergedReason reason;
68922c1e704SPeter Brune   PetscReal           xnorm, fnorm, ynorm;
69022c1e704SPeter Brune   PetscBool           lssuccess;
691ab8d36c9SPeter Brune   SNES                next;
692ab8d36c9SPeter Brune   Mat                 restrct, interpolate;
6930dd27c6cSPeter Brune   SNES_FAS            *fas = (SNES_FAS*)snes->data,*fasc;
6940dd27c6cSPeter Brune 
69539bd7f45SPeter Brune   PetscFunctionBegin;
696ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
69739bd7f45SPeter Brune   F    = snes->vec_func;
69839bd7f45SPeter Brune   B    = snes->vec_rhs;
699e7f468e7SPeter Brune   Xhat = snes->work[1];
70007144faaSPeter Brune   ierr = VecCopy(X, Xhat);CHKERRQ(ierr);
70107144faaSPeter Brune   /* recurse first */
702ab8d36c9SPeter Brune   if (next) {
7030dd27c6cSPeter Brune     fasc = (SNES_FAS*)next->data;
704ab8d36c9SPeter Brune     ierr = SNESFASCycleGetRestriction(snes, &restrct);CHKERRQ(ierr);
705ab8d36c9SPeter Brune     ierr = SNESFASCycleGetInterpolation(snes, &interpolate);CHKERRQ(ierr);
7060dd27c6cSPeter Brune     if (fas->eventresidual) {ierr = PetscLogEventBegin(fas->eventresidual,0,0,0,0);CHKERRQ(ierr);}
70707144faaSPeter Brune     ierr = SNESComputeFunction(snes, Xhat, F);CHKERRQ(ierr);
7080dd27c6cSPeter Brune     if (fas->eventresidual) {ierr = PetscLogEventEnd(fas->eventresidual,0,0,0,0);CHKERRQ(ierr);}
709c2a02606SPeter Brune     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
710ab8d36c9SPeter Brune     X_c  = next->vec_sol;
711ab8d36c9SPeter Brune     Xo_c = next->work[0];
712ab8d36c9SPeter Brune     F_c  = next->vec_func;
713ab8d36c9SPeter Brune     B_c  = next->vec_rhs;
71439bd7f45SPeter Brune 
715938e4a01SJed Brown     ierr = SNESFASRestrict(snes,Xhat,Xo_c);CHKERRQ(ierr);
71607144faaSPeter Brune     /* restrict the defect */
717ab8d36c9SPeter Brune     ierr = MatRestrict(restrct, F, B_c);CHKERRQ(ierr);
71807144faaSPeter Brune 
71907144faaSPeter Brune     /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */
7200dd27c6cSPeter Brune     if (fasc->eventresidual) {ierr = PetscLogEventBegin(fasc->eventresidual,0,0,0,0);CHKERRQ(ierr);}
721ab8d36c9SPeter Brune     ierr = SNESComputeFunction(next, Xo_c, F_c);CHKERRQ(ierr);
7220dd27c6cSPeter Brune     if (fasc->eventresidual) {ierr = PetscLogEventEnd(fasc->eventresidual,0,0,0,0);CHKERRQ(ierr);}
723e4ed7901SPeter Brune     ierr = VecCopy(B_c, X_c);CHKERRQ(ierr);
724b9c2fdf1SPeter Brune     ierr = VecCopy(F_c, B_c);CHKERRQ(ierr);
725e4ed7901SPeter Brune     ierr = VecCopy(X_c, F_c);CHKERRQ(ierr);
72607144faaSPeter Brune     /* set initial guess of the coarse problem to the projected fine solution */
72707144faaSPeter Brune     ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr);
72807144faaSPeter Brune 
72907144faaSPeter Brune     /* recurse */
730e4ed7901SPeter Brune     ierr = SNESSetInitialFunction(next, F_c);CHKERRQ(ierr);
731ab8d36c9SPeter Brune     ierr = SNESSolve(next, B_c, X_c);CHKERRQ(ierr);
73207144faaSPeter Brune 
73307144faaSPeter Brune     /* smooth on this level */
73491f99d7cSPeter Brune     ierr = SNESFASDownSmooth_Private(snes, B, X, F, &fnorm);CHKERRQ(ierr);
73507144faaSPeter Brune 
736ab8d36c9SPeter Brune     ierr = SNESGetConvergedReason(next,&reason);CHKERRQ(ierr);
73707144faaSPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
73807144faaSPeter Brune       snes->reason = SNES_DIVERGED_INNER;
73907144faaSPeter Brune       PetscFunctionReturn(0);
74007144faaSPeter Brune     }
74107144faaSPeter Brune 
74207144faaSPeter Brune     /* correct as x <- x + I(x^c - Rx)*/
743c68acad4SPeter Brune     ierr = VecAYPX(X_c, -1.0, Xo_c);CHKERRQ(ierr);
744ab8d36c9SPeter Brune     ierr = MatInterpolate(interpolate, X_c, Xhat);CHKERRQ(ierr);
74507144faaSPeter Brune 
746ddebd997SPeter Brune     /* additive correction of the coarse direction*/
747f1c6b773SPeter Brune     ierr = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Xhat);CHKERRQ(ierr);
748f1c6b773SPeter Brune     ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssuccess);CHKERRQ(ierr);
7499e764e56SPeter Brune     if (!lssuccess) {
7509e764e56SPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
7519e764e56SPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
7529e764e56SPeter Brune         PetscFunctionReturn(0);
7539e764e56SPeter Brune       }
7549e764e56SPeter Brune     }
755b9c2fdf1SPeter Brune     ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &snes->norm, &ynorm);CHKERRQ(ierr);
75607144faaSPeter Brune   } else {
75791f99d7cSPeter Brune     ierr = SNESFASDownSmooth_Private(snes, B, X, F, &snes->norm);CHKERRQ(ierr);
75807144faaSPeter Brune   }
75939bd7f45SPeter Brune   PetscFunctionReturn(0);
76039bd7f45SPeter Brune }
76139bd7f45SPeter Brune 
76239bd7f45SPeter Brune #undef __FUNCT__
7632cf9d1e8SPeter Brune #define __FUNCT__ "SNESFASCycle_Multiplicative"
76439bd7f45SPeter Brune /*
76539bd7f45SPeter Brune 
76639bd7f45SPeter Brune Defines the FAS cycle as:
76739bd7f45SPeter Brune 
76839bd7f45SPeter Brune fine problem: F(x) = 0
76939bd7f45SPeter Brune coarse problem: F^c(x) = b^c
77039bd7f45SPeter Brune 
77139bd7f45SPeter Brune b^c = F^c(I^c_fx^f - I^c_fF(x))
77239bd7f45SPeter Brune 
77339bd7f45SPeter Brune correction:
77439bd7f45SPeter Brune 
77539bd7f45SPeter Brune x = x + I(x^c - Rx)
77639bd7f45SPeter Brune 
77739bd7f45SPeter Brune  */
7780adebc6cSBarry Smith PetscErrorCode SNESFASCycle_Multiplicative(SNES snes, Vec X)
7790adebc6cSBarry Smith {
78039bd7f45SPeter Brune 
78139bd7f45SPeter Brune   PetscErrorCode ierr;
78239bd7f45SPeter Brune   Vec            F,B;
78339bd7f45SPeter Brune   SNES_FAS       *fas = (SNES_FAS*)snes->data;
78439bd7f45SPeter Brune 
78539bd7f45SPeter Brune   PetscFunctionBegin;
78639bd7f45SPeter Brune   F = snes->vec_func;
78739bd7f45SPeter Brune   B = snes->vec_rhs;
78839bd7f45SPeter Brune   /* pre-smooth -- just update using the pre-smoother */
78991f99d7cSPeter Brune   ierr = SNESFASDownSmooth_Private(snes, B, X, F, &snes->norm);CHKERRQ(ierr);
790c90fad12SPeter Brune   if (fas->level != 0) {
7918c40d5fbSBarry Smith     ierr = SNESFASCoarseCorrection(snes, X, F, X);CHKERRQ(ierr);
79291f99d7cSPeter Brune     ierr = SNESFASUpSmooth_Private(snes, B, X, F, &snes->norm);CHKERRQ(ierr);
793fe6f9142SPeter Brune   }
794fa9694d7SPeter Brune   PetscFunctionReturn(0);
795421d9b32SPeter Brune }
796421d9b32SPeter Brune 
797421d9b32SPeter Brune #undef __FUNCT__
798421d9b32SPeter Brune #define __FUNCT__ "SNESSolve_FAS"
799421d9b32SPeter Brune 
800421d9b32SPeter Brune PetscErrorCode SNESSolve_FAS(SNES snes)
801421d9b32SPeter Brune {
802fa9694d7SPeter Brune   PetscErrorCode ierr;
803fe6f9142SPeter Brune   PetscInt       i, maxits;
804ddb5aff1SPeter Brune   Vec            X, F;
805fe6f9142SPeter Brune   PetscReal      fnorm;
806b17ce1afSJed Brown   SNES_FAS       *fas = (SNES_FAS*)snes->data,*ffas;
807b17ce1afSJed Brown   DM             dm;
808e70c42e5SPeter Brune   PetscBool      isFine;
809b17ce1afSJed Brown 
810421d9b32SPeter Brune   PetscFunctionBegin;
811fe6f9142SPeter Brune   maxits       = snes->max_its;      /* maximum number of iterations */
812fe6f9142SPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
813fa9694d7SPeter Brune   X            = snes->vec_sol;
814f5a6d4f9SBarry Smith   F            = snes->vec_func;
815293a7e31SPeter Brune 
81618a66777SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
817293a7e31SPeter Brune   /*norm setup */
818fe6f9142SPeter Brune   ierr       = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
819fe6f9142SPeter Brune   snes->iter = 0;
820fe6f9142SPeter Brune   snes->norm = 0.;
821fe6f9142SPeter Brune   ierr       = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
822e4ed7901SPeter Brune   if (!snes->vec_func_init_set) {
8230dd27c6cSPeter Brune     if (fas->eventresidual) {ierr = PetscLogEventBegin(fas->eventresidual,0,0,0,0);CHKERRQ(ierr);}
824fe6f9142SPeter Brune     ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
8250dd27c6cSPeter Brune     if (fas->eventresidual) {ierr = PetscLogEventEnd(fas->eventresidual,0,0,0,0);CHKERRQ(ierr);}
826fe6f9142SPeter Brune     if (snes->domainerror) {
827fe6f9142SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
828fe6f9142SPeter Brune       PetscFunctionReturn(0);
829fe6f9142SPeter Brune     }
830*1aa26658SKarl Rupp   } else snes->vec_func_init_set = PETSC_FALSE;
831e4ed7901SPeter Brune 
832e4ed7901SPeter Brune   if (!snes->norm_init_set) {
833fe6f9142SPeter Brune     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
834fe6f9142SPeter Brune     if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm");
835fe6f9142SPeter Brune     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
836e4ed7901SPeter Brune   } else {
837e4ed7901SPeter Brune     fnorm               = snes->norm_init;
838e4ed7901SPeter Brune     snes->norm_init_set = PETSC_FALSE;
839e4ed7901SPeter Brune   }
840e4ed7901SPeter Brune 
841fe6f9142SPeter Brune   snes->norm = fnorm;
842fe6f9142SPeter Brune   ierr       = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
843fe6f9142SPeter Brune   SNESLogConvHistory(snes,fnorm,0);
844fe6f9142SPeter Brune   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
845fe6f9142SPeter Brune 
846fe6f9142SPeter Brune   /* set parameter for default relative tolerance convergence test */
847fe6f9142SPeter Brune   snes->ttol = fnorm*snes->rtol;
848fe6f9142SPeter Brune   /* test convergence */
849fe6f9142SPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
850fe6f9142SPeter Brune   if (snes->reason) PetscFunctionReturn(0);
851e4ed7901SPeter Brune 
852b17ce1afSJed Brown 
853b9c2fdf1SPeter Brune   if (isFine) {
854b9c2fdf1SPeter Brune     /* propagate scale-dependent data up the hierarchy */
855b17ce1afSJed Brown     ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
856b17ce1afSJed Brown     for (ffas=fas; ffas->next; ffas=(SNES_FAS*)ffas->next->data) {
857b17ce1afSJed Brown       DM dmcoarse;
858b17ce1afSJed Brown       ierr = SNESGetDM(ffas->next,&dmcoarse);CHKERRQ(ierr);
859b17ce1afSJed Brown       ierr = DMRestrict(dm,ffas->restrct,ffas->rscale,ffas->inject,dmcoarse);CHKERRQ(ierr);
860b17ce1afSJed Brown       dm   = dmcoarse;
861b17ce1afSJed Brown     }
862b9c2fdf1SPeter Brune   }
863b17ce1afSJed Brown 
864fe6f9142SPeter Brune   for (i = 0; i < maxits; i++) {
865fe6f9142SPeter Brune     /* Call general purpose update function */
866646217ecSPeter Brune 
867fe6f9142SPeter Brune     if (snes->ops->update) {
868fe6f9142SPeter Brune       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
869fe6f9142SPeter Brune     }
87007144faaSPeter Brune     if (fas->fastype == SNES_FAS_MULTIPLICATIVE) {
87191f99d7cSPeter Brune       ierr = SNESFASCycle_Multiplicative(snes, X);CHKERRQ(ierr);
87207144faaSPeter Brune     } else {
87391f99d7cSPeter Brune       ierr = SNESFASCycle_Additive(snes, X);CHKERRQ(ierr);
87407144faaSPeter Brune     }
875742fe5e2SPeter Brune 
876742fe5e2SPeter Brune     /* check for FAS cycle divergence */
877*1aa26658SKarl Rupp     if (snes->reason != SNES_CONVERGED_ITERATING) PetscFunctionReturn(0);
878b9c2fdf1SPeter Brune 
879c90fad12SPeter Brune     /* Monitor convergence */
880c90fad12SPeter Brune     ierr       = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
881c90fad12SPeter Brune     snes->iter = i+1;
882c90fad12SPeter Brune     ierr       = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
883c90fad12SPeter Brune     SNESLogConvHistory(snes,snes->norm,0);
884c90fad12SPeter Brune     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
885c90fad12SPeter Brune     /* Test for convergence */
88666585501SPeter Brune     if (isFine) {
887b9c2fdf1SPeter Brune       ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,snes->norm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
888c90fad12SPeter Brune       if (snes->reason) break;
889fe6f9142SPeter Brune     }
89066585501SPeter Brune   }
891fe6f9142SPeter Brune   if (i == maxits) {
892fe6f9142SPeter Brune     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr);
893fe6f9142SPeter Brune     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
894fe6f9142SPeter Brune   }
895421d9b32SPeter Brune   PetscFunctionReturn(0);
896421d9b32SPeter Brune }
897