xref: /petsc/src/snes/impls/fas/fas.c (revision 7fce8c19cd33f9feba8600a5c3d25d1abb6d7cab)
1421d9b32SPeter Brune /* Defines the basic SNES object */
26038b46bSPeter Brune #include <../src/snes/impls/fas/fasimpls.h>    /*I  "petscsnesfas.h"  I*/
3421d9b32SPeter Brune 
407144faaSPeter Brune const char *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);
71421d9b32SPeter Brune   snes->data                  = (void*) fas;
72421d9b32SPeter Brune   fas->level                  = 0;
73293a7e31SPeter Brune   fas->levels                 = 1;
74ee78dd50SPeter Brune   fas->n_cycles               = 1;
75ee78dd50SPeter Brune   fas->max_up_it              = 1;
76ee78dd50SPeter Brune   fas->max_down_it            = 1;
77ab8d36c9SPeter Brune   fas->smoothu                = PETSC_NULL;
78ab8d36c9SPeter Brune   fas->smoothd                = PETSC_NULL;
79421d9b32SPeter Brune   fas->next                   = PETSC_NULL;
806273346dSPeter Brune   fas->previous               = PETSC_NULL;
81ab8d36c9SPeter Brune   fas->fine                   = snes;
82421d9b32SPeter Brune   fas->interpolate            = PETSC_NULL;
83421d9b32SPeter Brune   fas->restrct                = PETSC_NULL;
84efe1f98aSPeter Brune   fas->inject                 = PETSC_NULL;
85cc05f883SPeter Brune   fas->monitor                = PETSC_NULL;
86cc05f883SPeter Brune   fas->usedmfornumberoflevels = PETSC_FALSE;
87ddebd997SPeter Brune   fas->fastype                = SNES_FAS_MULTIPLICATIVE;
88efe1f98aSPeter Brune   PetscFunctionReturn(0);
89efe1f98aSPeter Brune }
90efe1f98aSPeter Brune 
91421d9b32SPeter Brune #undef __FUNCT__
92421d9b32SPeter Brune #define __FUNCT__ "SNESReset_FAS"
93421d9b32SPeter Brune PetscErrorCode SNESReset_FAS(SNES snes)
94421d9b32SPeter Brune {
9577df8cc4SPeter Brune   PetscErrorCode ierr = 0;
96421d9b32SPeter Brune   SNES_FAS * fas = (SNES_FAS *)snes->data;
97421d9b32SPeter Brune 
98421d9b32SPeter Brune   PetscFunctionBegin;
99ab8d36c9SPeter Brune   ierr = SNESDestroy(&fas->smoothu);CHKERRQ(ierr);
100ab8d36c9SPeter Brune   ierr = SNESDestroy(&fas->smoothd);CHKERRQ(ierr);
1013dccd265SPeter Brune   ierr = MatDestroy(&fas->inject);CHKERRQ(ierr);
102bccf9bb3SJed Brown   ierr = MatDestroy(&fas->interpolate);CHKERRQ(ierr);
103bccf9bb3SJed Brown   ierr = MatDestroy(&fas->restrct);CHKERRQ(ierr);
104bccf9bb3SJed Brown   ierr = VecDestroy(&fas->rscale);CHKERRQ(ierr);
105742fe5e2SPeter Brune   if (fas->next)      ierr = SNESReset(fas->next);CHKERRQ(ierr);
10622c1e704SPeter Brune 
107421d9b32SPeter Brune   PetscFunctionReturn(0);
108421d9b32SPeter Brune }
109421d9b32SPeter Brune 
110421d9b32SPeter Brune #undef __FUNCT__
111421d9b32SPeter Brune #define __FUNCT__ "SNESDestroy_FAS"
112421d9b32SPeter Brune PetscErrorCode SNESDestroy_FAS(SNES snes)
113421d9b32SPeter Brune {
114421d9b32SPeter Brune   SNES_FAS * fas = (SNES_FAS *)snes->data;
115742fe5e2SPeter Brune   PetscErrorCode ierr = 0;
116421d9b32SPeter Brune 
117421d9b32SPeter Brune   PetscFunctionBegin;
118421d9b32SPeter Brune   /* recursively resets and then destroys */
11979d9a41aSPeter Brune   ierr = SNESReset(snes);CHKERRQ(ierr);
120421d9b32SPeter Brune   if (fas->next)         ierr = SNESDestroy(&fas->next);CHKERRQ(ierr);
121421d9b32SPeter Brune   ierr = PetscFree(fas);CHKERRQ(ierr);
122ee1fd11aSPeter Brune 
123421d9b32SPeter Brune   PetscFunctionReturn(0);
124421d9b32SPeter Brune }
125421d9b32SPeter Brune 
126421d9b32SPeter Brune #undef __FUNCT__
127421d9b32SPeter Brune #define __FUNCT__ "SNESSetUp_FAS"
128421d9b32SPeter Brune PetscErrorCode SNESSetUp_FAS(SNES snes)
129421d9b32SPeter Brune {
13048bfdf8aSPeter Brune   SNES_FAS                    *fas = (SNES_FAS *) snes->data;
131421d9b32SPeter Brune   PetscErrorCode              ierr;
132efe1f98aSPeter Brune   VecScatter                  injscatter;
133d1adcc6fSPeter Brune   PetscInt                    dm_levels;
1343dccd265SPeter Brune   Vec                         vec_sol, vec_func, vec_sol_update, vec_rhs; /* preserve these if they're set through the reset */
135ab8d36c9SPeter Brune   SNES                        next;
136ab8d36c9SPeter Brune   PetscBool                   isFine;
137f89ba88eSPeter Brune   SNESLineSearch              linesearch;
138f89ba88eSPeter Brune   SNESLineSearch              slinesearch;
139f89ba88eSPeter Brune   void                        *lsprectx,*lspostctx;
140f89ba88eSPeter Brune   SNESLineSearchPreCheckFunc  lsprefunc;
141f89ba88eSPeter Brune   SNESLineSearchPostCheckFunc lspostfunc;
142421d9b32SPeter Brune   PetscFunctionBegin;
143eff52c0eSPeter Brune 
144ab8d36c9SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
145ab8d36c9SPeter Brune   if (fas->usedmfornumberoflevels && isFine) {
146d1adcc6fSPeter Brune     ierr = DMGetRefineLevel(snes->dm,&dm_levels);CHKERRQ(ierr);
147d1adcc6fSPeter Brune     dm_levels++;
148cc05f883SPeter Brune     if (dm_levels > fas->levels) {
1492e8ce248SJed Brown       /* we don't want the solution and func vectors to be destroyed in the SNESReset when it's called in SNESFASSetLevels_FAS*/
1503dccd265SPeter Brune       vec_sol = snes->vec_sol;
1513dccd265SPeter Brune       vec_func = snes->vec_func;
1523dccd265SPeter Brune       vec_sol_update = snes->vec_sol_update;
1533dccd265SPeter Brune       vec_rhs = snes->vec_rhs;
1543dccd265SPeter Brune       snes->vec_sol = PETSC_NULL;
1553dccd265SPeter Brune       snes->vec_func = PETSC_NULL;
1563dccd265SPeter Brune       snes->vec_sol_update = PETSC_NULL;
1573dccd265SPeter Brune       snes->vec_rhs = PETSC_NULL;
1583dccd265SPeter Brune 
1593dccd265SPeter Brune       /* reset the number of levels */
160d1adcc6fSPeter Brune       ierr = SNESFASSetLevels(snes,dm_levels,PETSC_NULL);CHKERRQ(ierr);
161cc05f883SPeter Brune       ierr = SNESSetFromOptions(snes);CHKERRQ(ierr);
1623dccd265SPeter Brune 
1633dccd265SPeter Brune       snes->vec_sol = vec_sol;
1643dccd265SPeter Brune       snes->vec_func = vec_func;
1653dccd265SPeter Brune       snes->vec_rhs = vec_rhs;
1663dccd265SPeter Brune       snes->vec_sol_update = vec_sol_update;
167d1adcc6fSPeter Brune     }
168d1adcc6fSPeter Brune   }
169ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
170ab8d36c9SPeter Brune   if (!isFine) snes->gridsequence = 0; /* no grid sequencing inside the multigrid hierarchy! */
1713dccd265SPeter Brune 
17207144faaSPeter Brune   if (fas->fastype == SNES_FAS_MULTIPLICATIVE) {
173e4ed7901SPeter Brune     ierr = SNESDefaultGetWork(snes, 2);CHKERRQ(ierr); /* work vectors used for intergrid transfers */
17407144faaSPeter Brune   } else {
175e7f468e7SPeter Brune     ierr = SNESDefaultGetWork(snes, 2);CHKERRQ(ierr); /* work vectors used for intergrid transfers */
17607144faaSPeter Brune   }
177cc05f883SPeter Brune 
178ab8d36c9SPeter Brune   /* set up the smoothers if they haven't already been set up */
179ab8d36c9SPeter Brune   if (!fas->smoothd) {
180ab8d36c9SPeter Brune     ierr = SNESFASCycleCreateSmoother_Private(snes, &fas->smoothd);CHKERRQ(ierr);
181ab8d36c9SPeter Brune   }
182534ebe21SPeter Brune   if (!fas->smoothu && fas->level != fas->levels - 1) {
183534ebe21SPeter Brune     ierr = SNESFASCycleCreateSmoother_Private(snes, &fas->smoothu);CHKERRQ(ierr);
184534ebe21SPeter Brune   }
185ab8d36c9SPeter Brune 
18679d9a41aSPeter Brune   if (snes->dm) {
187ab8d36c9SPeter Brune     /* set the smoother DMs properly */
188ab8d36c9SPeter Brune     if (fas->smoothu) ierr = SNESSetDM(fas->smoothu, snes->dm);CHKERRQ(ierr);
189ab8d36c9SPeter Brune     ierr = SNESSetDM(fas->smoothd, snes->dm);CHKERRQ(ierr);
19079d9a41aSPeter Brune     /* construct EVERYTHING from the DM -- including the progressive set of smoothers */
191ab8d36c9SPeter Brune     if (next) {
19279d9a41aSPeter Brune       /* for now -- assume the DM and the evaluation functions have been set externally */
193ab8d36c9SPeter Brune       if (!next->dm) {
194ab8d36c9SPeter Brune         ierr = DMCoarsen(snes->dm, ((PetscObject)next)->comm, &next->dm);CHKERRQ(ierr);
195ab8d36c9SPeter Brune         ierr = SNESSetDM(next, next->dm);CHKERRQ(ierr);
19679d9a41aSPeter Brune       }
19779d9a41aSPeter Brune       /* set the interpolation and restriction from the DM */
19879d9a41aSPeter Brune       if (!fas->interpolate) {
199ab8d36c9SPeter Brune         ierr = DMCreateInterpolation(next->dm, snes->dm, &fas->interpolate, &fas->rscale);CHKERRQ(ierr);
200bccf9bb3SJed Brown         if (!fas->restrct) {
201bccf9bb3SJed Brown           ierr = PetscObjectReference((PetscObject)fas->interpolate);CHKERRQ(ierr);
20279d9a41aSPeter Brune           fas->restrct = fas->interpolate;
20379d9a41aSPeter Brune         }
204bccf9bb3SJed Brown       }
20579d9a41aSPeter Brune       /* set the injection from the DM */
20679d9a41aSPeter Brune       if (!fas->inject) {
207ab8d36c9SPeter Brune         ierr = DMCreateInjection(next->dm, snes->dm, &injscatter);CHKERRQ(ierr);
20879d9a41aSPeter Brune         ierr = MatCreateScatter(((PetscObject)snes)->comm, injscatter, &fas->inject);CHKERRQ(ierr);
20979d9a41aSPeter Brune         ierr = VecScatterDestroy(&injscatter);CHKERRQ(ierr);
21079d9a41aSPeter Brune       }
21179d9a41aSPeter Brune     }
21279d9a41aSPeter Brune   }
21379d9a41aSPeter Brune   /*pass the smoother, function, and jacobian up to the next level if it's not user set already */
21479d9a41aSPeter Brune   if (fas->galerkin) {
215ab8d36c9SPeter Brune     if (next)
216ab8d36c9SPeter Brune       ierr = SNESSetFunction(next, PETSC_NULL, SNESFASGalerkinDefaultFunction, next);CHKERRQ(ierr);
217ab8d36c9SPeter Brune     if (fas->smoothd && fas->level != fas->levels - 1) ierr = SNESSetFunction(fas->smoothd, PETSC_NULL, SNESFASGalerkinDefaultFunction, snes);CHKERRQ(ierr);
218ab8d36c9SPeter Brune     if (fas->smoothu && fas->level != fas->levels - 1) ierr = SNESSetFunction(fas->smoothu, PETSC_NULL, SNESFASGalerkinDefaultFunction, snes);CHKERRQ(ierr);
21979d9a41aSPeter Brune   }
22079d9a41aSPeter Brune 
221534ebe21SPeter Brune   /* sets the down (pre) smoother's default norm and sets it from options */
222534ebe21SPeter Brune   if(fas->smoothd){
223534ebe21SPeter Brune     if (fas->level == 0) {
224534ebe21SPeter Brune       ierr = SNESSetNormType(fas->smoothd, SNES_NORM_NONE);CHKERRQ(ierr);
225534ebe21SPeter Brune      } else {
226534ebe21SPeter Brune       ierr = SNESSetNormType(fas->smoothd, SNES_NORM_FINAL_ONLY);CHKERRQ(ierr);
227534ebe21SPeter Brune     }
228*7fce8c19SPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)snes, (PetscObject)fas->smoothd);CHKERRQ(ierr);
229534ebe21SPeter Brune     ierr = SNESSetFromOptions(fas->smoothd);CHKERRQ(ierr);
230f89ba88eSPeter Brune     ierr = SNESGetSNESLineSearch(snes,&linesearch);CHKERRQ(ierr);
231f89ba88eSPeter Brune     ierr = SNESGetSNESLineSearch(fas->smoothd,&slinesearch);CHKERRQ(ierr);
232f89ba88eSPeter Brune     ierr = SNESLineSearchGetPreCheck(linesearch,&lsprefunc,&lsprectx);CHKERRQ(ierr);
233f89ba88eSPeter Brune     ierr = SNESLineSearchGetPostCheck(linesearch,&lspostfunc,&lspostctx);CHKERRQ(ierr);
234f89ba88eSPeter Brune     ierr = SNESLineSearchSetPreCheck(slinesearch,lsprefunc,lsprectx);CHKERRQ(ierr);
235f89ba88eSPeter Brune     ierr = SNESLineSearchSetPostCheck(slinesearch,lspostfunc,lspostctx);CHKERRQ(ierr);
236f89ba88eSPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)linesearch, (PetscObject)slinesearch);CHKERRQ(ierr);
237534ebe21SPeter Brune   }
238534ebe21SPeter Brune 
239534ebe21SPeter Brune   /* sets the up (post) smoother's default norm and sets it from options */
240534ebe21SPeter Brune   if(fas->smoothu){
241534ebe21SPeter Brune     if (fas->level != fas->levels - 1) {
242534ebe21SPeter Brune       ierr = SNESSetNormType(fas->smoothu, SNES_NORM_NONE);CHKERRQ(ierr);
243534ebe21SPeter Brune     } else {
244534ebe21SPeter Brune       ierr = SNESSetNormType(fas->smoothu, SNES_NORM_FINAL_ONLY);CHKERRQ(ierr);
245534ebe21SPeter Brune     }
246*7fce8c19SPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)snes, (PetscObject)fas->smoothu);CHKERRQ(ierr);
247534ebe21SPeter Brune     ierr = SNESSetFromOptions(fas->smoothu);CHKERRQ(ierr);
248f89ba88eSPeter Brune     ierr = SNESGetSNESLineSearch(snes,&linesearch);CHKERRQ(ierr);
249f89ba88eSPeter Brune     ierr = SNESGetSNESLineSearch(fas->smoothu,&slinesearch);CHKERRQ(ierr);
250f89ba88eSPeter Brune     ierr = SNESLineSearchGetPreCheck(linesearch,&lsprefunc,&lsprectx);CHKERRQ(ierr);
251f89ba88eSPeter Brune     ierr = SNESLineSearchGetPostCheck(linesearch,&lspostfunc,&lspostctx);CHKERRQ(ierr);
252f89ba88eSPeter Brune     ierr = SNESLineSearchSetPreCheck(slinesearch,lsprefunc,lsprectx);CHKERRQ(ierr);
253f89ba88eSPeter Brune     ierr = SNESLineSearchSetPostCheck(slinesearch,lspostfunc,lspostctx);CHKERRQ(ierr);
254f89ba88eSPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)linesearch, (PetscObject)slinesearch);CHKERRQ(ierr);
255534ebe21SPeter Brune   }
256d06165b7SPeter Brune 
257ab8d36c9SPeter Brune   if (next) {
25879d9a41aSPeter Brune     /* gotta set up the solution vector for this to work */
259ab8d36c9SPeter Brune     if (!next->vec_sol) {ierr = SNESFASCreateCoarseVec(snes,&next->vec_sol);CHKERRQ(ierr);}
260ab8d36c9SPeter Brune     if (!next->vec_rhs) {ierr = SNESFASCreateCoarseVec(snes,&next->vec_rhs);CHKERRQ(ierr);}
261*7fce8c19SPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)snes, (PetscObject)next);CHKERRQ(ierr);
262f89ba88eSPeter Brune     ierr = SNESGetSNESLineSearch(snes,&linesearch);CHKERRQ(ierr);
263f89ba88eSPeter Brune     ierr = SNESGetSNESLineSearch(fas->next,&slinesearch);CHKERRQ(ierr);
264f89ba88eSPeter Brune     ierr = SNESLineSearchGetPreCheck(linesearch,&lsprefunc,&lsprectx);CHKERRQ(ierr);
265f89ba88eSPeter Brune     ierr = SNESLineSearchGetPostCheck(linesearch,&lspostfunc,&lspostctx);CHKERRQ(ierr);
266f89ba88eSPeter Brune     ierr = SNESLineSearchSetPreCheck(slinesearch,lsprefunc,lsprectx);CHKERRQ(ierr);
267f89ba88eSPeter Brune     ierr = SNESLineSearchSetPostCheck(slinesearch,lspostfunc,lspostctx);CHKERRQ(ierr);
268f89ba88eSPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)linesearch, (PetscObject)slinesearch);CHKERRQ(ierr);
269ab8d36c9SPeter Brune     ierr = SNESSetUp(next);CHKERRQ(ierr);
27079d9a41aSPeter Brune   }
2716273346dSPeter Brune   /* setup FAS work vectors */
2726273346dSPeter Brune   if (fas->galerkin) {
2736273346dSPeter Brune     ierr = VecDuplicate(snes->vec_sol, &fas->Xg);CHKERRQ(ierr);
2746273346dSPeter Brune     ierr = VecDuplicate(snes->vec_sol, &fas->Fg);CHKERRQ(ierr);
2756273346dSPeter Brune   }
276421d9b32SPeter Brune   PetscFunctionReturn(0);
277421d9b32SPeter Brune }
278421d9b32SPeter Brune 
279421d9b32SPeter Brune #undef __FUNCT__
280421d9b32SPeter Brune #define __FUNCT__ "SNESSetFromOptions_FAS"
281421d9b32SPeter Brune PetscErrorCode SNESSetFromOptions_FAS(SNES snes)
282421d9b32SPeter Brune {
283ee78dd50SPeter Brune   SNES_FAS       *fas = (SNES_FAS *) snes->data;
284ee78dd50SPeter Brune   PetscInt       levels = 1;
2854d26bfa5SPeter Brune   PetscBool      flg = PETSC_FALSE, upflg = PETSC_FALSE, downflg = PETSC_FALSE, monflg = PETSC_FALSE, galerkinflg = PETSC_FALSE;
286421d9b32SPeter Brune   PetscErrorCode ierr;
287ee78dd50SPeter Brune   char           monfilename[PETSC_MAX_PATH_LEN];
28807144faaSPeter Brune   SNESFASType    fastype;
289fde0ff24SPeter Brune   const char     *optionsprefix;
290f1c6b773SPeter Brune   SNESLineSearch linesearch;
29166585501SPeter Brune   PetscInt       m, n_up, n_down;
292ab8d36c9SPeter Brune   SNES           next;
293ab8d36c9SPeter Brune   PetscBool      isFine;
294421d9b32SPeter Brune 
295421d9b32SPeter Brune   PetscFunctionBegin;
296ab8d36c9SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
297c90fad12SPeter Brune   ierr = PetscOptionsHead("SNESFAS Options-----------------------------------");CHKERRQ(ierr);
298ee78dd50SPeter Brune 
299ab8d36c9SPeter Brune   /* number of levels -- only process most options on the finest level */
300ab8d36c9SPeter Brune   if (isFine) {
301ee78dd50SPeter Brune     ierr = PetscOptionsInt("-snes_fas_levels", "Number of Levels", "SNESFASSetLevels", levels, &levels, &flg);CHKERRQ(ierr);
302c732cbdbSBarry Smith     if (!flg && snes->dm) {
303c732cbdbSBarry Smith       ierr = DMGetRefineLevel(snes->dm,&levels);CHKERRQ(ierr);
304c732cbdbSBarry Smith       levels++;
305d1adcc6fSPeter Brune       fas->usedmfornumberoflevels = PETSC_TRUE;
306c732cbdbSBarry Smith     }
307ee78dd50SPeter Brune     ierr = SNESFASSetLevels(snes, levels, PETSC_NULL);CHKERRQ(ierr);
30807144faaSPeter Brune     fastype = fas->fastype;
30907144faaSPeter Brune     ierr = PetscOptionsEnum("-snes_fas_type","FAS correction type","SNESFASSetType",SNESFASTypes,(PetscEnum)fastype,(PetscEnum*)&fastype,&flg);CHKERRQ(ierr);
31007144faaSPeter Brune     if (flg) {
31107144faaSPeter Brune       ierr = SNESFASSetType(snes, fastype);CHKERRQ(ierr);
31207144faaSPeter Brune     }
313ee78dd50SPeter Brune 
314fde0ff24SPeter Brune     ierr = SNESGetOptionsPrefix(snes, &optionsprefix);CHKERRQ(ierr);
315ab8d36c9SPeter Brune     ierr = PetscOptionsInt("-snes_fas_cycles","Number of cycles","SNESFASSetCycles",fas->n_cycles,&m,&flg);CHKERRQ(ierr);
316ab8d36c9SPeter Brune     if (flg) {
317ab8d36c9SPeter Brune       ierr = SNESFASSetCycles(snes, m);CHKERRQ(ierr);
318fde0ff24SPeter Brune     }
319fde0ff24SPeter Brune 
320ab8d36c9SPeter Brune     ierr = PetscOptionsBool("-snes_fas_galerkin", "Form coarse problems with Galerkin","SNESFASSetGalerkin",fas->galerkin,&galerkinflg,&flg);CHKERRQ(ierr);
321ab8d36c9SPeter Brune     if (flg) {
322ab8d36c9SPeter Brune       ierr = SNESFASSetGalerkin(snes, galerkinflg);CHKERRQ(ierr);
323ab8d36c9SPeter Brune     }
324ee78dd50SPeter Brune 
32566585501SPeter Brune     ierr = PetscOptionsInt("-snes_fas_smoothup","Number of post-smoothing steps","SNESFASSetNumberSmoothUp",fas->max_up_it,&n_up,&upflg);CHKERRQ(ierr);
326162d76ddSPeter Brune 
32766585501SPeter Brune     ierr = PetscOptionsInt("-snes_fas_smoothdown","Number of pre-smoothing steps","SNESFASSetNumberSmoothDown",fas->max_down_it,&n_down,&downflg);CHKERRQ(ierr);
328162d76ddSPeter Brune 
329c8c899caSPeter Brune     ierr = PetscOptionsString("-snes_fas_monitor","Monitor FAS progress","SNESFASSetMonitor","stdout",monfilename,PETSC_MAX_PATH_LEN,&monflg);CHKERRQ(ierr);
330c8c899caSPeter Brune     if (monflg) ierr = SNESFASSetMonitor(snes, PETSC_TRUE);CHKERRQ(ierr);
331ab8d36c9SPeter Brune   }
332ee78dd50SPeter Brune 
333421d9b32SPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
3348cc86e31SPeter Brune   /* setup from the determined types if there is no pointwise procedure or smoother defined */
335162d76ddSPeter Brune   if (upflg) {
33666585501SPeter Brune     ierr = SNESFASSetNumberSmoothUp(snes,n_up);CHKERRQ(ierr);
337162d76ddSPeter Brune   }
338162d76ddSPeter Brune   if (downflg) {
33966585501SPeter Brune     ierr = SNESFASSetNumberSmoothDown(snes,n_down);CHKERRQ(ierr);
340162d76ddSPeter Brune   }
341eff52c0eSPeter Brune 
3429e764e56SPeter Brune   /* set up the default line search for coarse grid corrections */
3439e764e56SPeter Brune   if (fas->fastype == SNES_FAS_ADDITIVE) {
3449e764e56SPeter Brune     if (!snes->linesearch) {
345f1c6b773SPeter Brune       ierr = SNESGetSNESLineSearch(snes, &linesearch);CHKERRQ(ierr);
3461a4f838cSPeter Brune       ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHL2);CHKERRQ(ierr);
3479e764e56SPeter Brune     }
3489e764e56SPeter Brune   }
3499e764e56SPeter Brune 
350ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
351ee78dd50SPeter Brune   /* recursive option setting for the smoothers */
352ab8d36c9SPeter Brune   if (next) {ierr = SNESSetFromOptions(next);CHKERRQ(ierr);}
353421d9b32SPeter Brune   PetscFunctionReturn(0);
354421d9b32SPeter Brune }
355421d9b32SPeter Brune 
356421d9b32SPeter Brune #undef __FUNCT__
357421d9b32SPeter Brune #define __FUNCT__ "SNESView_FAS"
358421d9b32SPeter Brune PetscErrorCode SNESView_FAS(SNES snes, PetscViewer viewer)
359421d9b32SPeter Brune {
360421d9b32SPeter Brune   SNES_FAS       *fas = (SNES_FAS *) snes->data;
361ab8d36c9SPeter Brune   PetscBool      isFine, iascii;
362ab8d36c9SPeter Brune   PetscInt       i;
363421d9b32SPeter Brune   PetscErrorCode ierr;
364ab8d36c9SPeter Brune   SNES           smoothu, smoothd, levelsnes;
365421d9b32SPeter Brune 
366421d9b32SPeter Brune   PetscFunctionBegin;
367ab8d36c9SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
368ab8d36c9SPeter Brune   if (isFine) {
369251f4c67SDmitry Karpeev     ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
370421d9b32SPeter Brune     if (iascii) {
371ab8d36c9SPeter Brune       ierr = PetscViewerASCIIPrintf(viewer, "FAS: type is %s, levels=%D, cycles=%D\n",  SNESFASTypes[fas->fastype], fas->levels, fas->n_cycles);CHKERRQ(ierr);
372ab8d36c9SPeter Brune       if (fas->galerkin) {
373ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid function evaluation\n");CHKERRQ(ierr);
374421d9b32SPeter Brune       } else {
375ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPrintf(viewer,"    Not using Galerkin computed coarse grid function evaluation\n");CHKERRQ(ierr);
376421d9b32SPeter Brune       }
377ab8d36c9SPeter Brune       for (i=0; i<fas->levels; i++) {
378ab8d36c9SPeter Brune         ierr = SNESFASGetCycleSNES(snes, i, &levelsnes);CHKERRQ(ierr);
379ab8d36c9SPeter Brune         ierr = SNESFASCycleGetSmootherUp(levelsnes, &smoothu);CHKERRQ(ierr);
380ab8d36c9SPeter Brune         ierr = SNESFASCycleGetSmootherDown(levelsnes, &smoothd);CHKERRQ(ierr);
381ab8d36c9SPeter Brune         if (!i) {
382ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Coarse grid solver -- level %D -------------------------------\n",i);CHKERRQ(ierr);
383421d9b32SPeter Brune         } else {
384ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
385421d9b32SPeter Brune         }
386ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
387ab8d36c9SPeter Brune         ierr = SNESView(smoothd,viewer);CHKERRQ(ierr);
388ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
389ab8d36c9SPeter Brune         if (i && (smoothd == smoothu)) {
390ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n");CHKERRQ(ierr);
391ab8d36c9SPeter Brune         } else if (i) {
392ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
393ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
394ab8d36c9SPeter Brune           ierr = SNESView(smoothu,viewer);CHKERRQ(ierr);
395ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
396ab8d36c9SPeter Brune         }
397ab8d36c9SPeter Brune       }
398421d9b32SPeter Brune     } else {
399421d9b32SPeter Brune       SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for SNESFAS",((PetscObject)viewer)->type_name);
400421d9b32SPeter Brune     }
401ab8d36c9SPeter Brune   }
402421d9b32SPeter Brune   PetscFunctionReturn(0);
403421d9b32SPeter Brune }
404421d9b32SPeter Brune 
405421d9b32SPeter Brune #undef __FUNCT__
40691f99d7cSPeter Brune #define __FUNCT__ "SNESFASDownSmooth_Private"
40739bd7f45SPeter Brune /*
40839bd7f45SPeter Brune Defines the action of the downsmoother
40939bd7f45SPeter Brune  */
41091f99d7cSPeter Brune PetscErrorCode SNESFASDownSmooth_Private(SNES snes, Vec B, Vec X, Vec F, PetscReal *fnorm)
411b9c2fdf1SPeter Brune {
41239bd7f45SPeter Brune   PetscErrorCode      ierr = 0;
413742fe5e2SPeter Brune   SNESConvergedReason reason;
414ab8d36c9SPeter Brune   Vec                 FPC;
415ab8d36c9SPeter Brune   SNES                smoothd;
416421d9b32SPeter Brune   PetscFunctionBegin;
417ab8d36c9SPeter Brune   ierr = SNESFASCycleGetSmootherDown(snes, &smoothd);CHKERRQ(ierr);
418e4ed7901SPeter Brune   ierr = SNESSetInitialFunction(smoothd, F);CHKERRQ(ierr);
419e4ed7901SPeter Brune   ierr = SNESSetInitialFunctionNorm(smoothd, *fnorm);CHKERRQ(ierr);
420ab8d36c9SPeter Brune   ierr = SNESSolve(smoothd, B, X);CHKERRQ(ierr);
421742fe5e2SPeter Brune   /* check convergence reason for the smoother */
422ab8d36c9SPeter Brune   ierr = SNESGetConvergedReason(smoothd,&reason);CHKERRQ(ierr);
423e70c42e5SPeter Brune   if (reason < 0 && !(reason == SNES_DIVERGED_MAX_IT || reason == SNES_DIVERGED_LOCAL_MIN)) {
424742fe5e2SPeter Brune     snes->reason = SNES_DIVERGED_INNER;
425742fe5e2SPeter Brune     PetscFunctionReturn(0);
426742fe5e2SPeter Brune   }
427ab8d36c9SPeter Brune   ierr = SNESGetFunction(smoothd, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
4284b32a720SPeter Brune   ierr = VecCopy(FPC, F);CHKERRQ(ierr);
429b9c2fdf1SPeter Brune   ierr = SNESGetFunctionNorm(smoothd, fnorm);CHKERRQ(ierr);
43039bd7f45SPeter Brune   PetscFunctionReturn(0);
43139bd7f45SPeter Brune }
43239bd7f45SPeter Brune 
43339bd7f45SPeter Brune 
43439bd7f45SPeter Brune #undef __FUNCT__
43591f99d7cSPeter Brune #define __FUNCT__ "SNESFASUpSmooth_Private"
43639bd7f45SPeter Brune /*
43707144faaSPeter Brune Defines the action of the upsmoother
43839bd7f45SPeter Brune  */
43991f99d7cSPeter Brune PetscErrorCode SNESFASUpSmooth_Private (SNES snes, Vec B, Vec X, Vec F, PetscReal *fnorm) {
44039bd7f45SPeter Brune   PetscErrorCode      ierr = 0;
44139bd7f45SPeter Brune   SNESConvergedReason reason;
442ab8d36c9SPeter Brune   Vec                 FPC;
443ab8d36c9SPeter Brune   SNES                smoothu;
44439bd7f45SPeter Brune   PetscFunctionBegin;
445ab8d36c9SPeter Brune 
446ab8d36c9SPeter Brune   ierr = SNESFASCycleGetSmootherUp(snes, &smoothu);CHKERRQ(ierr);
447ab8d36c9SPeter Brune   ierr = SNESSolve(smoothu, B, X);CHKERRQ(ierr);
44839bd7f45SPeter Brune   /* check convergence reason for the smoother */
449ab8d36c9SPeter Brune   ierr = SNESGetConvergedReason(smoothu,&reason);CHKERRQ(ierr);
45039bd7f45SPeter Brune   if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
45139bd7f45SPeter Brune     snes->reason = SNES_DIVERGED_INNER;
45239bd7f45SPeter Brune     PetscFunctionReturn(0);
45339bd7f45SPeter Brune   }
454ab8d36c9SPeter Brune   ierr = SNESGetFunction(smoothu, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
4554b32a720SPeter Brune   ierr = VecCopy(FPC, F);CHKERRQ(ierr);
456b9c2fdf1SPeter Brune   ierr = SNESGetFunctionNorm(smoothu, fnorm);CHKERRQ(ierr);
45739bd7f45SPeter Brune   PetscFunctionReturn(0);
45839bd7f45SPeter Brune }
45939bd7f45SPeter Brune 
46039bd7f45SPeter Brune #undef __FUNCT__
461938e4a01SJed Brown #define __FUNCT__ "SNESFASCreateCoarseVec"
462938e4a01SJed Brown /*@
463938e4a01SJed Brown    SNESFASCreateCoarseVec - create Vec corresponding to a state vector on one level coarser than current level
464938e4a01SJed Brown 
465938e4a01SJed Brown    Collective
466938e4a01SJed Brown 
467938e4a01SJed Brown    Input Arguments:
468938e4a01SJed Brown .  snes - SNESFAS
469938e4a01SJed Brown 
470938e4a01SJed Brown    Output Arguments:
471938e4a01SJed Brown .  Xcoarse - vector on level one coarser than snes
472938e4a01SJed Brown 
473938e4a01SJed Brown    Level: developer
474938e4a01SJed Brown 
475938e4a01SJed Brown .seealso: SNESFASSetRestriction(), SNESFASRestrict()
476938e4a01SJed Brown @*/
477938e4a01SJed Brown PetscErrorCode SNESFASCreateCoarseVec(SNES snes,Vec *Xcoarse)
478938e4a01SJed Brown {
479938e4a01SJed Brown   PetscErrorCode ierr;
480938e4a01SJed Brown   SNES_FAS       *fas = (SNES_FAS*)snes->data;
481938e4a01SJed Brown 
482938e4a01SJed Brown   PetscFunctionBegin;
483938e4a01SJed Brown   if (fas->rscale) {ierr = VecDuplicate(fas->rscale,Xcoarse);CHKERRQ(ierr);}
484938e4a01SJed Brown   else if (fas->inject) {ierr = MatGetVecs(fas->inject,Xcoarse,PETSC_NULL);CHKERRQ(ierr);}
485938e4a01SJed Brown   else SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must set restriction or injection");CHKERRQ(ierr);
486938e4a01SJed Brown   PetscFunctionReturn(0);
487938e4a01SJed Brown }
488938e4a01SJed Brown 
489e9923e8dSJed Brown #undef __FUNCT__
490e9923e8dSJed Brown #define __FUNCT__ "SNESFASRestrict"
491e9923e8dSJed Brown /*@
492e9923e8dSJed Brown    SNESFASRestrict - restrict a Vec to the next coarser level
493e9923e8dSJed Brown 
494e9923e8dSJed Brown    Collective
495e9923e8dSJed Brown 
496e9923e8dSJed Brown    Input Arguments:
497e9923e8dSJed Brown +  fine - SNES from which to restrict
498e9923e8dSJed Brown -  Xfine - vector to restrict
499e9923e8dSJed Brown 
500e9923e8dSJed Brown    Output Arguments:
501e9923e8dSJed Brown .  Xcoarse - result of restriction
502e9923e8dSJed Brown 
503e9923e8dSJed Brown    Level: developer
504e9923e8dSJed Brown 
505e9923e8dSJed Brown .seealso: SNESFASSetRestriction(), SNESFASSetInjection()
506e9923e8dSJed Brown @*/
507e9923e8dSJed Brown PetscErrorCode SNESFASRestrict(SNES fine,Vec Xfine,Vec Xcoarse)
508e9923e8dSJed Brown {
509e9923e8dSJed Brown   PetscErrorCode ierr;
510e9923e8dSJed Brown   SNES_FAS       *fas = (SNES_FAS*)fine->data;
511e9923e8dSJed Brown 
512e9923e8dSJed Brown   PetscFunctionBegin;
513e9923e8dSJed Brown   PetscValidHeaderSpecific(fine,SNES_CLASSID,1);
514e9923e8dSJed Brown   PetscValidHeaderSpecific(Xfine,VEC_CLASSID,2);
515e9923e8dSJed Brown   PetscValidHeaderSpecific(Xcoarse,VEC_CLASSID,3);
516e9923e8dSJed Brown   if (fas->inject) {
517e9923e8dSJed Brown     ierr = MatRestrict(fas->inject,Xfine,Xcoarse);CHKERRQ(ierr);
518e9923e8dSJed Brown   } else {
519e9923e8dSJed Brown     ierr = MatRestrict(fas->restrct,Xfine,Xcoarse);CHKERRQ(ierr);
520e9923e8dSJed Brown     ierr = VecPointwiseMult(Xcoarse,fas->rscale,Xcoarse);CHKERRQ(ierr);
521e9923e8dSJed Brown   }
522e9923e8dSJed Brown   PetscFunctionReturn(0);
523e9923e8dSJed Brown }
524e9923e8dSJed Brown 
525e9923e8dSJed Brown #undef __FUNCT__
5268c40d5fbSBarry Smith #define __FUNCT__ "SNESFASCoarseCorrection"
52739bd7f45SPeter Brune /*
52839bd7f45SPeter Brune 
52939bd7f45SPeter Brune Performs the FAS coarse correction as:
53039bd7f45SPeter Brune 
53139bd7f45SPeter Brune fine problem: F(x) = 0
53239bd7f45SPeter Brune coarse problem: F^c(x) = b^c
53339bd7f45SPeter Brune 
53439bd7f45SPeter Brune b^c = F^c(I^c_fx^f - I^c_fF(x))
53539bd7f45SPeter Brune 
53639bd7f45SPeter Brune  */
5378c40d5fbSBarry Smith PetscErrorCode SNESFASCoarseCorrection(SNES snes, Vec X, Vec F, Vec X_new) {
53839bd7f45SPeter Brune   PetscErrorCode      ierr;
53939bd7f45SPeter Brune   Vec                 X_c, Xo_c, F_c, B_c;
54039bd7f45SPeter Brune   SNESConvergedReason reason;
541ab8d36c9SPeter Brune   SNES                next;
542ab8d36c9SPeter Brune   Mat                 restrct, interpolate;
54339bd7f45SPeter Brune   PetscFunctionBegin;
544ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
545ab8d36c9SPeter Brune   if (next) {
546ab8d36c9SPeter Brune     ierr = SNESFASCycleGetRestriction(snes, &restrct);CHKERRQ(ierr);
547ab8d36c9SPeter Brune     ierr = SNESFASCycleGetInterpolation(snes, &interpolate);CHKERRQ(ierr);
548ab8d36c9SPeter Brune 
549ab8d36c9SPeter Brune     X_c  = next->vec_sol;
550ab8d36c9SPeter Brune     Xo_c = next->work[0];
551ab8d36c9SPeter Brune     F_c  = next->vec_func;
552ab8d36c9SPeter Brune     B_c  = next->vec_rhs;
553efe1f98aSPeter Brune 
554938e4a01SJed Brown     ierr = SNESFASRestrict(snes,X,Xo_c);CHKERRQ(ierr);
555293a7e31SPeter Brune     /* restrict the defect */
556ab8d36c9SPeter Brune     ierr = MatRestrict(restrct, F, B_c);CHKERRQ(ierr);
557b9c2fdf1SPeter Brune     /* solve the coarse problem corresponding to F^c(x^c) = b^c = F^c(Rx) - R(F(x) - b) */
558ab8d36c9SPeter Brune     ierr = SNESComputeFunction(next, Xo_c, F_c);CHKERRQ(ierr);
559e4ed7901SPeter Brune     ierr = VecCopy(B_c, X_c);CHKERRQ(ierr);
560b9c2fdf1SPeter Brune     ierr = VecCopy(F_c, B_c);CHKERRQ(ierr);
561e4ed7901SPeter Brune     ierr = VecCopy(X_c, F_c);CHKERRQ(ierr);
562ee78dd50SPeter Brune     /* set initial guess of the coarse problem to the projected fine solution */
563ee78dd50SPeter Brune     ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr);
564c90fad12SPeter Brune 
565c90fad12SPeter Brune     /* recurse to the next level */
566e4ed7901SPeter Brune     ierr = SNESSetInitialFunction(next, F_c);CHKERRQ(ierr);
567ab8d36c9SPeter Brune     ierr = SNESSolve(next, B_c, X_c);CHKERRQ(ierr);
568ab8d36c9SPeter Brune     ierr = SNESGetConvergedReason(next,&reason);CHKERRQ(ierr);
569742fe5e2SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
570742fe5e2SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
571742fe5e2SPeter Brune       PetscFunctionReturn(0);
572742fe5e2SPeter Brune     }
573fa9694d7SPeter Brune     /* correct as x <- x + I(x^c - Rx)*/
574fa9694d7SPeter Brune     ierr = VecAXPY(X_c, -1.0, Xo_c);CHKERRQ(ierr);
575ab8d36c9SPeter Brune     ierr = MatInterpolateAdd(interpolate, X_c, X, X_new);CHKERRQ(ierr);
576293a7e31SPeter Brune   }
57739bd7f45SPeter Brune   PetscFunctionReturn(0);
57839bd7f45SPeter Brune }
57939bd7f45SPeter Brune 
58039bd7f45SPeter Brune #undef __FUNCT__
5812cf9d1e8SPeter Brune #define __FUNCT__ "SNESFASCycle_Additive"
58239bd7f45SPeter Brune /*
58339bd7f45SPeter Brune 
58439bd7f45SPeter Brune The additive cycle looks like:
58539bd7f45SPeter Brune 
58607144faaSPeter Brune xhat = x
58707144faaSPeter Brune xhat = dS(x, b)
58807144faaSPeter Brune x = coarsecorrection(xhat, b_d)
58907144faaSPeter Brune x = x + nu*(xhat - x);
59039bd7f45SPeter Brune (optional) x = uS(x, b)
59139bd7f45SPeter Brune 
59239bd7f45SPeter Brune With the coarse RHS (defect correction) as below.
59339bd7f45SPeter Brune 
59439bd7f45SPeter Brune  */
59591f99d7cSPeter Brune PetscErrorCode SNESFASCycle_Additive(SNES snes, Vec X) {
59607144faaSPeter Brune   Vec                 F, B, Xhat;
59722c1e704SPeter Brune   Vec                 X_c, Xo_c, F_c, B_c;
59839bd7f45SPeter Brune   PetscErrorCode      ierr;
59907144faaSPeter Brune   SNESConvergedReason reason;
60022c1e704SPeter Brune   PetscReal           xnorm, fnorm, ynorm;
60122c1e704SPeter Brune   PetscBool           lssuccess;
602ab8d36c9SPeter Brune   SNES                next;
603ab8d36c9SPeter Brune   Mat                 restrct, interpolate;
60439bd7f45SPeter Brune   PetscFunctionBegin;
605ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
60639bd7f45SPeter Brune   F = snes->vec_func;
60739bd7f45SPeter Brune   B = snes->vec_rhs;
608e7f468e7SPeter Brune   Xhat = snes->work[1];
60907144faaSPeter Brune   ierr = VecCopy(X, Xhat);CHKERRQ(ierr);
61007144faaSPeter Brune   /* recurse first */
611ab8d36c9SPeter Brune   if (next) {
612ab8d36c9SPeter Brune     ierr = SNESFASCycleGetRestriction(snes, &restrct);CHKERRQ(ierr);
613ab8d36c9SPeter Brune     ierr = SNESFASCycleGetInterpolation(snes, &interpolate);CHKERRQ(ierr);
61407144faaSPeter Brune     ierr = SNESComputeFunction(snes, Xhat, F);CHKERRQ(ierr);
615c2a02606SPeter Brune     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
616ab8d36c9SPeter Brune     X_c  = next->vec_sol;
617ab8d36c9SPeter Brune     Xo_c = next->work[0];
618ab8d36c9SPeter Brune     F_c  = next->vec_func;
619ab8d36c9SPeter Brune     B_c  = next->vec_rhs;
62039bd7f45SPeter Brune 
621938e4a01SJed Brown     ierr = SNESFASRestrict(snes,Xhat,Xo_c);CHKERRQ(ierr);
62207144faaSPeter Brune     /* restrict the defect */
623ab8d36c9SPeter Brune     ierr = MatRestrict(restrct, F, B_c);CHKERRQ(ierr);
62407144faaSPeter Brune 
62507144faaSPeter Brune     /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */
626ab8d36c9SPeter Brune     ierr = SNESComputeFunction(next, Xo_c, F_c);CHKERRQ(ierr);
627e4ed7901SPeter Brune     ierr = VecCopy(B_c, X_c);CHKERRQ(ierr);
628b9c2fdf1SPeter Brune     ierr = VecCopy(F_c, B_c);CHKERRQ(ierr);
629e4ed7901SPeter Brune     ierr = VecCopy(X_c, F_c);CHKERRQ(ierr);
63007144faaSPeter Brune     /* set initial guess of the coarse problem to the projected fine solution */
63107144faaSPeter Brune     ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr);
63207144faaSPeter Brune 
63307144faaSPeter Brune     /* recurse */
634e4ed7901SPeter Brune     ierr = SNESSetInitialFunction(next, F_c);CHKERRQ(ierr);
635ab8d36c9SPeter Brune     ierr = SNESSolve(next, B_c, X_c);CHKERRQ(ierr);
63607144faaSPeter Brune 
63707144faaSPeter Brune     /* smooth on this level */
63891f99d7cSPeter Brune     ierr = SNESFASDownSmooth_Private(snes, B, X, F, &fnorm);CHKERRQ(ierr);
63907144faaSPeter Brune 
640ab8d36c9SPeter Brune     ierr = SNESGetConvergedReason(next,&reason);CHKERRQ(ierr);
64107144faaSPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
64207144faaSPeter Brune       snes->reason = SNES_DIVERGED_INNER;
64307144faaSPeter Brune       PetscFunctionReturn(0);
64407144faaSPeter Brune     }
64507144faaSPeter Brune 
64607144faaSPeter Brune     /* correct as x <- x + I(x^c - Rx)*/
647c68acad4SPeter Brune     ierr = VecAYPX(X_c, -1.0, Xo_c);CHKERRQ(ierr);
648ab8d36c9SPeter Brune     ierr = MatInterpolate(interpolate, X_c, Xhat);CHKERRQ(ierr);
64907144faaSPeter Brune 
650ddebd997SPeter Brune     /* additive correction of the coarse direction*/
651f1c6b773SPeter Brune     ierr = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Xhat);CHKERRQ(ierr);
652f1c6b773SPeter Brune     ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssuccess);CHKERRQ(ierr);
6539e764e56SPeter Brune     if (!lssuccess) {
6549e764e56SPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
6559e764e56SPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
6569e764e56SPeter Brune         PetscFunctionReturn(0);
6579e764e56SPeter Brune       }
6589e764e56SPeter Brune     }
659b9c2fdf1SPeter Brune     ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &snes->norm, &ynorm);CHKERRQ(ierr);
66007144faaSPeter Brune   } else {
66191f99d7cSPeter Brune     ierr = SNESFASDownSmooth_Private(snes, B, X, F, &snes->norm);CHKERRQ(ierr);
66207144faaSPeter Brune   }
66339bd7f45SPeter Brune   PetscFunctionReturn(0);
66439bd7f45SPeter Brune }
66539bd7f45SPeter Brune 
66639bd7f45SPeter Brune #undef __FUNCT__
6672cf9d1e8SPeter Brune #define __FUNCT__ "SNESFASCycle_Multiplicative"
66839bd7f45SPeter Brune /*
66939bd7f45SPeter Brune 
67039bd7f45SPeter Brune Defines the FAS cycle as:
67139bd7f45SPeter Brune 
67239bd7f45SPeter Brune fine problem: F(x) = 0
67339bd7f45SPeter Brune coarse problem: F^c(x) = b^c
67439bd7f45SPeter Brune 
67539bd7f45SPeter Brune b^c = F^c(I^c_fx^f - I^c_fF(x))
67639bd7f45SPeter Brune 
67739bd7f45SPeter Brune correction:
67839bd7f45SPeter Brune 
67939bd7f45SPeter Brune x = x + I(x^c - Rx)
68039bd7f45SPeter Brune 
68139bd7f45SPeter Brune  */
68291f99d7cSPeter Brune PetscErrorCode SNESFASCycle_Multiplicative(SNES snes, Vec X) {
68339bd7f45SPeter Brune 
68439bd7f45SPeter Brune   PetscErrorCode      ierr;
68539bd7f45SPeter Brune   Vec                 F,B;
68639bd7f45SPeter Brune   SNES_FAS            *fas = (SNES_FAS *)snes->data;
68739bd7f45SPeter Brune 
68839bd7f45SPeter Brune   PetscFunctionBegin;
68939bd7f45SPeter Brune   F = snes->vec_func;
69039bd7f45SPeter Brune   B = snes->vec_rhs;
69139bd7f45SPeter Brune   /* pre-smooth -- just update using the pre-smoother */
69291f99d7cSPeter Brune   ierr = SNESFASDownSmooth_Private(snes, B, X, F, &snes->norm);CHKERRQ(ierr);
693c90fad12SPeter Brune   if (fas->level != 0) {
6948c40d5fbSBarry Smith     ierr = SNESFASCoarseCorrection(snes, X, F, X);CHKERRQ(ierr);
69591f99d7cSPeter Brune     ierr = SNESFASUpSmooth_Private(snes, B, X, F, &snes->norm);CHKERRQ(ierr);
696fe6f9142SPeter Brune   }
697fa9694d7SPeter Brune   PetscFunctionReturn(0);
698421d9b32SPeter Brune }
699421d9b32SPeter Brune 
700421d9b32SPeter Brune #undef __FUNCT__
701421d9b32SPeter Brune #define __FUNCT__ "SNESSolve_FAS"
702421d9b32SPeter Brune 
703421d9b32SPeter Brune PetscErrorCode SNESSolve_FAS(SNES snes)
704421d9b32SPeter Brune {
705fa9694d7SPeter Brune   PetscErrorCode ierr;
706fe6f9142SPeter Brune   PetscInt       i, maxits;
707ddb5aff1SPeter Brune   Vec            X, F;
708fe6f9142SPeter Brune   PetscReal      fnorm;
709b17ce1afSJed Brown   SNES_FAS       *fas = (SNES_FAS *)snes->data,*ffas;
710b17ce1afSJed Brown   DM             dm;
711e70c42e5SPeter Brune   PetscBool      isFine;
712b17ce1afSJed Brown 
713421d9b32SPeter Brune   PetscFunctionBegin;
714fe6f9142SPeter Brune   maxits = snes->max_its;            /* maximum number of iterations */
715fe6f9142SPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
716fa9694d7SPeter Brune   X = snes->vec_sol;
717f5a6d4f9SBarry Smith   F = snes->vec_func;
718293a7e31SPeter Brune 
71918a66777SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
720293a7e31SPeter Brune   /*norm setup */
721fe6f9142SPeter Brune   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
722fe6f9142SPeter Brune   snes->iter = 0;
723fe6f9142SPeter Brune   snes->norm = 0.;
724fe6f9142SPeter Brune   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
725e4ed7901SPeter Brune   if (!snes->vec_func_init_set) {
726fe6f9142SPeter Brune     ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
727fe6f9142SPeter Brune     if (snes->domainerror) {
728fe6f9142SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
729fe6f9142SPeter Brune       PetscFunctionReturn(0);
730fe6f9142SPeter Brune     }
731e4ed7901SPeter Brune   } else {
732e4ed7901SPeter Brune     snes->vec_func_init_set = PETSC_FALSE;
733e4ed7901SPeter Brune   }
734e4ed7901SPeter Brune 
735e4ed7901SPeter Brune   if (!snes->norm_init_set) {
736fe6f9142SPeter Brune     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
737fe6f9142SPeter Brune     if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm");
738fe6f9142SPeter Brune     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
739e4ed7901SPeter Brune   } else {
740e4ed7901SPeter Brune     fnorm = snes->norm_init;
741e4ed7901SPeter Brune     snes->norm_init_set = PETSC_FALSE;
742e4ed7901SPeter Brune   }
743e4ed7901SPeter Brune 
744fe6f9142SPeter Brune   snes->norm = fnorm;
745fe6f9142SPeter Brune   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
746fe6f9142SPeter Brune   SNESLogConvHistory(snes,fnorm,0);
747fe6f9142SPeter Brune   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
748fe6f9142SPeter Brune 
749fe6f9142SPeter Brune   /* set parameter for default relative tolerance convergence test */
750fe6f9142SPeter Brune   snes->ttol = fnorm*snes->rtol;
751fe6f9142SPeter Brune   /* test convergence */
752fe6f9142SPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
753fe6f9142SPeter Brune   if (snes->reason) PetscFunctionReturn(0);
754e4ed7901SPeter Brune 
755b17ce1afSJed Brown 
756b9c2fdf1SPeter Brune   if (isFine) {
757b9c2fdf1SPeter Brune     /* propagate scale-dependent data up the hierarchy */
758b17ce1afSJed Brown     ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
759b17ce1afSJed Brown     for (ffas=fas; ffas->next; ffas=(SNES_FAS*)ffas->next->data) {
760b17ce1afSJed Brown       DM dmcoarse;
761b17ce1afSJed Brown       ierr = SNESGetDM(ffas->next,&dmcoarse);CHKERRQ(ierr);
762b17ce1afSJed Brown       ierr = DMRestrict(dm,ffas->restrct,ffas->rscale,ffas->inject,dmcoarse);CHKERRQ(ierr);
763b17ce1afSJed Brown       dm = dmcoarse;
764b17ce1afSJed Brown     }
765b9c2fdf1SPeter Brune   }
766b17ce1afSJed Brown 
767fe6f9142SPeter Brune   for (i = 0; i < maxits; i++) {
768fe6f9142SPeter Brune     /* Call general purpose update function */
769646217ecSPeter Brune 
770fe6f9142SPeter Brune     if (snes->ops->update) {
771fe6f9142SPeter Brune       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
772fe6f9142SPeter Brune     }
77307144faaSPeter Brune     if (fas->fastype == SNES_FAS_MULTIPLICATIVE) {
77491f99d7cSPeter Brune       ierr = SNESFASCycle_Multiplicative(snes, X);CHKERRQ(ierr);
77507144faaSPeter Brune     } else {
77691f99d7cSPeter Brune       ierr = SNESFASCycle_Additive(snes, X);CHKERRQ(ierr);
77707144faaSPeter Brune     }
778742fe5e2SPeter Brune 
779742fe5e2SPeter Brune     /* check for FAS cycle divergence */
780742fe5e2SPeter Brune     if (snes->reason != SNES_CONVERGED_ITERATING) {
781742fe5e2SPeter Brune       PetscFunctionReturn(0);
782742fe5e2SPeter Brune     }
783b9c2fdf1SPeter Brune 
784c90fad12SPeter Brune     /* Monitor convergence */
785c90fad12SPeter Brune     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
786c90fad12SPeter Brune     snes->iter = i+1;
787c90fad12SPeter Brune     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
788c90fad12SPeter Brune     SNESLogConvHistory(snes,snes->norm,0);
789c90fad12SPeter Brune     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
790c90fad12SPeter Brune     /* Test for convergence */
79166585501SPeter Brune     if (isFine) {
792b9c2fdf1SPeter Brune       ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,snes->norm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
793c90fad12SPeter Brune       if (snes->reason) break;
794fe6f9142SPeter Brune     }
79566585501SPeter Brune   }
796fe6f9142SPeter Brune   if (i == maxits) {
797fe6f9142SPeter Brune     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr);
798fe6f9142SPeter Brune     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
799fe6f9142SPeter Brune   }
800421d9b32SPeter Brune   PetscFunctionReturn(0);
801421d9b32SPeter Brune }
802