xref: /petsc/src/snes/impls/fas/fas.c (revision d06165b78620b12db54186a6278c94b8028b272a)
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 
191fbfccc6SJed Brown The nonlinear problem is solved via the repeated application of nonlinear preconditioners and coarse-grid corrections
201fbfccc6SJed Brown 
211fbfccc6SJed Brown Level: advanced
221fbfccc6SJed Brown 
231fbfccc6SJed Brown .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
241fbfccc6SJed Brown M*/
25421d9b32SPeter Brune 
26421d9b32SPeter Brune #undef __FUNCT__
27421d9b32SPeter Brune #define __FUNCT__ "SNESCreate_FAS"
281fbfccc6SJed Brown PETSC_EXTERN_C PetscErrorCode SNESCreate_FAS(SNES snes)
29421d9b32SPeter Brune {
30421d9b32SPeter Brune   SNES_FAS * fas;
31421d9b32SPeter Brune   PetscErrorCode ierr;
32421d9b32SPeter Brune 
33421d9b32SPeter Brune   PetscFunctionBegin;
34421d9b32SPeter Brune   snes->ops->destroy        = SNESDestroy_FAS;
35421d9b32SPeter Brune   snes->ops->setup          = SNESSetUp_FAS;
36421d9b32SPeter Brune   snes->ops->setfromoptions = SNESSetFromOptions_FAS;
37421d9b32SPeter Brune   snes->ops->view           = SNESView_FAS;
38421d9b32SPeter Brune   snes->ops->solve          = SNESSolve_FAS;
39421d9b32SPeter Brune   snes->ops->reset          = SNESReset_FAS;
40421d9b32SPeter Brune 
41ed020824SBarry Smith   snes->usesksp             = PETSC_FALSE;
42ed020824SBarry Smith   snes->usespc              = PETSC_FALSE;
43ed020824SBarry Smith 
4488976e71SPeter Brune   if (!snes->tolerancesset) {
450e444f03SPeter Brune     snes->max_funcs = 30000;
460e444f03SPeter Brune     snes->max_its   = 10000;
4788976e71SPeter Brune   }
480e444f03SPeter Brune 
49421d9b32SPeter Brune   ierr = PetscNewLog(snes, SNES_FAS, &fas);CHKERRQ(ierr);
50421d9b32SPeter Brune   snes->data                  = (void*) fas;
51421d9b32SPeter Brune   fas->level                  = 0;
52293a7e31SPeter Brune   fas->levels                 = 1;
53ee78dd50SPeter Brune   fas->n_cycles               = 1;
54ee78dd50SPeter Brune   fas->max_up_it              = 1;
55ee78dd50SPeter Brune   fas->max_down_it            = 1;
56ab8d36c9SPeter Brune   fas->smoothu                = PETSC_NULL;
57ab8d36c9SPeter Brune   fas->smoothd                = PETSC_NULL;
58421d9b32SPeter Brune   fas->next                   = PETSC_NULL;
596273346dSPeter Brune   fas->previous               = PETSC_NULL;
60ab8d36c9SPeter Brune   fas->fine                   = snes;
61421d9b32SPeter Brune   fas->interpolate            = PETSC_NULL;
62421d9b32SPeter Brune   fas->restrct                = PETSC_NULL;
63efe1f98aSPeter Brune   fas->inject                 = PETSC_NULL;
64cc05f883SPeter Brune   fas->monitor                = PETSC_NULL;
65cc05f883SPeter Brune   fas->usedmfornumberoflevels = PETSC_FALSE;
66ddebd997SPeter Brune   fas->fastype                = SNES_FAS_MULTIPLICATIVE;
67efe1f98aSPeter Brune   PetscFunctionReturn(0);
68efe1f98aSPeter Brune }
69efe1f98aSPeter Brune 
70421d9b32SPeter Brune #undef __FUNCT__
71421d9b32SPeter Brune #define __FUNCT__ "SNESReset_FAS"
72421d9b32SPeter Brune PetscErrorCode SNESReset_FAS(SNES snes)
73421d9b32SPeter Brune {
7477df8cc4SPeter Brune   PetscErrorCode ierr = 0;
75421d9b32SPeter Brune   SNES_FAS * fas = (SNES_FAS *)snes->data;
76421d9b32SPeter Brune 
77421d9b32SPeter Brune   PetscFunctionBegin;
78ab8d36c9SPeter Brune   if (fas->smoothu != fas->smoothd) {
79ab8d36c9SPeter Brune     ierr = SNESDestroy(&fas->smoothu);CHKERRQ(ierr);
80ab8d36c9SPeter Brune     ierr = SNESDestroy(&fas->smoothd);CHKERRQ(ierr);
81ab8d36c9SPeter Brune   } else {
82ab8d36c9SPeter Brune     ierr = SNESDestroy(&fas->smoothd);CHKERRQ(ierr);
83ab8d36c9SPeter Brune     fas->smoothu = PETSC_NULL;
84ab8d36c9SPeter Brune   }
853dccd265SPeter Brune   ierr = MatDestroy(&fas->inject);CHKERRQ(ierr);
86bccf9bb3SJed Brown   ierr = MatDestroy(&fas->interpolate);CHKERRQ(ierr);
87bccf9bb3SJed Brown   ierr = MatDestroy(&fas->restrct);CHKERRQ(ierr);
88bccf9bb3SJed Brown   ierr = VecDestroy(&fas->rscale);CHKERRQ(ierr);
89742fe5e2SPeter Brune   if (fas->next)      ierr = SNESReset(fas->next);CHKERRQ(ierr);
9022c1e704SPeter Brune 
91421d9b32SPeter Brune   PetscFunctionReturn(0);
92421d9b32SPeter Brune }
93421d9b32SPeter Brune 
94421d9b32SPeter Brune #undef __FUNCT__
95421d9b32SPeter Brune #define __FUNCT__ "SNESDestroy_FAS"
96421d9b32SPeter Brune PetscErrorCode SNESDestroy_FAS(SNES snes)
97421d9b32SPeter Brune {
98421d9b32SPeter Brune   SNES_FAS * fas = (SNES_FAS *)snes->data;
99742fe5e2SPeter Brune   PetscErrorCode ierr = 0;
100421d9b32SPeter Brune 
101421d9b32SPeter Brune   PetscFunctionBegin;
102421d9b32SPeter Brune   /* recursively resets and then destroys */
10379d9a41aSPeter Brune   ierr = SNESReset(snes);CHKERRQ(ierr);
104421d9b32SPeter Brune   if (fas->next)         ierr = SNESDestroy(&fas->next);CHKERRQ(ierr);
105421d9b32SPeter Brune   ierr = PetscFree(fas);CHKERRQ(ierr);
106ee1fd11aSPeter Brune 
107421d9b32SPeter Brune   PetscFunctionReturn(0);
108421d9b32SPeter Brune }
109421d9b32SPeter Brune 
110421d9b32SPeter Brune #undef __FUNCT__
111421d9b32SPeter Brune #define __FUNCT__ "SNESSetUp_FAS"
112421d9b32SPeter Brune PetscErrorCode SNESSetUp_FAS(SNES snes)
113421d9b32SPeter Brune {
11448bfdf8aSPeter Brune   SNES_FAS                *fas = (SNES_FAS *) snes->data;
115421d9b32SPeter Brune   PetscErrorCode          ierr;
116efe1f98aSPeter Brune   VecScatter              injscatter;
117d1adcc6fSPeter Brune   PetscInt                dm_levels;
1183dccd265SPeter Brune   Vec                     vec_sol, vec_func, vec_sol_update, vec_rhs; /* preserve these if they're set through the reset */
119ab8d36c9SPeter Brune   SNES                    next;
120ab8d36c9SPeter Brune   PetscBool               isFine;
121421d9b32SPeter Brune   PetscFunctionBegin;
122eff52c0eSPeter Brune 
123ab8d36c9SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
124ab8d36c9SPeter Brune   if (fas->usedmfornumberoflevels && isFine) {
125d1adcc6fSPeter Brune     ierr = DMGetRefineLevel(snes->dm,&dm_levels);CHKERRQ(ierr);
126d1adcc6fSPeter Brune     dm_levels++;
127cc05f883SPeter Brune     if (dm_levels > fas->levels) {
1282e8ce248SJed Brown       /* we don't want the solution and func vectors to be destroyed in the SNESReset when it's called in SNESFASSetLevels_FAS*/
1293dccd265SPeter Brune       vec_sol = snes->vec_sol;
1303dccd265SPeter Brune       vec_func = snes->vec_func;
1313dccd265SPeter Brune       vec_sol_update = snes->vec_sol_update;
1323dccd265SPeter Brune       vec_rhs = snes->vec_rhs;
1333dccd265SPeter Brune       snes->vec_sol = PETSC_NULL;
1343dccd265SPeter Brune       snes->vec_func = PETSC_NULL;
1353dccd265SPeter Brune       snes->vec_sol_update = PETSC_NULL;
1363dccd265SPeter Brune       snes->vec_rhs = PETSC_NULL;
1373dccd265SPeter Brune 
1383dccd265SPeter Brune       /* reset the number of levels */
139d1adcc6fSPeter Brune       ierr = SNESFASSetLevels(snes,dm_levels,PETSC_NULL);CHKERRQ(ierr);
140cc05f883SPeter Brune       ierr = SNESSetFromOptions(snes);CHKERRQ(ierr);
1413dccd265SPeter Brune 
1423dccd265SPeter Brune       snes->vec_sol = vec_sol;
1433dccd265SPeter Brune       snes->vec_func = vec_func;
1443dccd265SPeter Brune       snes->vec_rhs = vec_rhs;
1453dccd265SPeter Brune       snes->vec_sol_update = vec_sol_update;
146d1adcc6fSPeter Brune     }
147d1adcc6fSPeter Brune   }
148ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
149ab8d36c9SPeter Brune   if (!isFine) snes->gridsequence = 0; /* no grid sequencing inside the multigrid hierarchy! */
1503dccd265SPeter Brune 
15107144faaSPeter Brune   if (fas->fastype == SNES_FAS_MULTIPLICATIVE) {
152fde0ff24SPeter Brune     ierr = SNESDefaultGetWork(snes, 4);CHKERRQ(ierr); /* work vectors used for intergrid transfers */
15307144faaSPeter Brune   } else {
154ddebd997SPeter Brune     ierr = SNESDefaultGetWork(snes, 4);CHKERRQ(ierr); /* work vectors used for intergrid transfers */
15507144faaSPeter Brune   }
156cc05f883SPeter Brune 
157ab8d36c9SPeter Brune   /* set up the smoothers if they haven't already been set up */
158ab8d36c9SPeter Brune   if (!fas->smoothd) {
159ab8d36c9SPeter Brune     ierr = SNESFASCycleCreateSmoother_Private(snes, &fas->smoothd);CHKERRQ(ierr);
160ab8d36c9SPeter Brune   }
161ab8d36c9SPeter Brune 
16279d9a41aSPeter Brune   if (snes->dm) {
163ab8d36c9SPeter Brune     /* set the smoother DMs properly */
164ab8d36c9SPeter Brune     if (fas->smoothu) ierr = SNESSetDM(fas->smoothu, snes->dm);CHKERRQ(ierr);
165ab8d36c9SPeter Brune     ierr = SNESSetDM(fas->smoothd, snes->dm);CHKERRQ(ierr);
16679d9a41aSPeter Brune     /* construct EVERYTHING from the DM -- including the progressive set of smoothers */
167ab8d36c9SPeter Brune     if (next) {
16879d9a41aSPeter Brune       /* for now -- assume the DM and the evaluation functions have been set externally */
169ab8d36c9SPeter Brune       if (!next->dm) {
170ab8d36c9SPeter Brune         ierr = DMCoarsen(snes->dm, ((PetscObject)next)->comm, &next->dm);CHKERRQ(ierr);
171ab8d36c9SPeter Brune         ierr = SNESSetDM(next, next->dm);CHKERRQ(ierr);
17279d9a41aSPeter Brune       }
17379d9a41aSPeter Brune       /* set the interpolation and restriction from the DM */
17479d9a41aSPeter Brune       if (!fas->interpolate) {
175ab8d36c9SPeter Brune         ierr = DMCreateInterpolation(next->dm, snes->dm, &fas->interpolate, &fas->rscale);CHKERRQ(ierr);
176bccf9bb3SJed Brown         if (!fas->restrct) {
177bccf9bb3SJed Brown           ierr = PetscObjectReference((PetscObject)fas->interpolate);CHKERRQ(ierr);
17879d9a41aSPeter Brune           fas->restrct = fas->interpolate;
17979d9a41aSPeter Brune         }
180bccf9bb3SJed Brown       }
18179d9a41aSPeter Brune       /* set the injection from the DM */
18279d9a41aSPeter Brune       if (!fas->inject) {
183ab8d36c9SPeter Brune         ierr = DMCreateInjection(next->dm, snes->dm, &injscatter);CHKERRQ(ierr);
18479d9a41aSPeter Brune         ierr = MatCreateScatter(((PetscObject)snes)->comm, injscatter, &fas->inject);CHKERRQ(ierr);
18579d9a41aSPeter Brune         ierr = VecScatterDestroy(&injscatter);CHKERRQ(ierr);
18679d9a41aSPeter Brune       }
18779d9a41aSPeter Brune     }
18879d9a41aSPeter Brune   }
18979d9a41aSPeter Brune   /*pass the smoother, function, and jacobian up to the next level if it's not user set already */
19079d9a41aSPeter Brune 
19179d9a41aSPeter Brune   if (fas->galerkin) {
192ab8d36c9SPeter Brune     if (next)
193ab8d36c9SPeter Brune       ierr = SNESSetFunction(next, PETSC_NULL, SNESFASGalerkinDefaultFunction, next);CHKERRQ(ierr);
194ab8d36c9SPeter Brune     if (fas->smoothd && fas->level != fas->levels - 1) ierr = SNESSetFunction(fas->smoothd, PETSC_NULL, SNESFASGalerkinDefaultFunction, snes);CHKERRQ(ierr);
195ab8d36c9SPeter Brune     if (fas->smoothu && fas->level != fas->levels - 1) ierr = SNESSetFunction(fas->smoothu, PETSC_NULL, SNESFASGalerkinDefaultFunction, snes);CHKERRQ(ierr);
19679d9a41aSPeter Brune   }
19779d9a41aSPeter Brune 
198*d06165b7SPeter Brune   /* set the smoothers up here so that precedence is taken for instance-specific options over the whole-solver options */
199*d06165b7SPeter Brune   if(fas->smoothu) ierr = SNESSetFromOptions(fas->smoothu);CHKERRQ(ierr);
200*d06165b7SPeter Brune   if(fas->smoothd) ierr = SNESSetFromOptions(fas->smoothd);CHKERRQ(ierr);
201*d06165b7SPeter Brune 
202ab8d36c9SPeter Brune   if (next) {
20379d9a41aSPeter Brune     /* gotta set up the solution vector for this to work */
204ab8d36c9SPeter Brune     if (!next->vec_sol) {ierr = SNESFASCreateCoarseVec(snes,&next->vec_sol);CHKERRQ(ierr);}
205ab8d36c9SPeter Brune     if (!next->vec_rhs) {ierr = SNESFASCreateCoarseVec(snes,&next->vec_rhs);CHKERRQ(ierr);}
206ab8d36c9SPeter Brune     ierr = SNESSetUp(next);CHKERRQ(ierr);
20779d9a41aSPeter Brune   }
2086273346dSPeter Brune   /* setup FAS work vectors */
2096273346dSPeter Brune   if (fas->galerkin) {
2106273346dSPeter Brune     ierr = VecDuplicate(snes->vec_sol, &fas->Xg);CHKERRQ(ierr);
2116273346dSPeter Brune     ierr = VecDuplicate(snes->vec_sol, &fas->Fg);CHKERRQ(ierr);
2126273346dSPeter Brune   }
213421d9b32SPeter Brune   PetscFunctionReturn(0);
214421d9b32SPeter Brune }
215421d9b32SPeter Brune 
216421d9b32SPeter Brune #undef __FUNCT__
217421d9b32SPeter Brune #define __FUNCT__ "SNESSetFromOptions_FAS"
218421d9b32SPeter Brune PetscErrorCode SNESSetFromOptions_FAS(SNES snes)
219421d9b32SPeter Brune {
220ee78dd50SPeter Brune   SNES_FAS       *fas = (SNES_FAS *) snes->data;
221ee78dd50SPeter Brune   PetscInt       levels = 1;
222162d76ddSPeter Brune   PetscBool      flg, upflg, downflg, monflg, galerkinflg;
223421d9b32SPeter Brune   PetscErrorCode ierr;
224ee78dd50SPeter Brune   char           monfilename[PETSC_MAX_PATH_LEN];
22507144faaSPeter Brune   SNESFASType    fastype;
226fde0ff24SPeter Brune   const char     *optionsprefix;
227f1c6b773SPeter Brune   SNESLineSearch linesearch;
22866585501SPeter Brune   PetscInt       m, n_up, n_down;
229ab8d36c9SPeter Brune   SNES           next;
230ab8d36c9SPeter Brune   PetscBool      isFine;
231421d9b32SPeter Brune 
232421d9b32SPeter Brune   PetscFunctionBegin;
233ab8d36c9SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
234c90fad12SPeter Brune   ierr = PetscOptionsHead("SNESFAS Options-----------------------------------");CHKERRQ(ierr);
235ee78dd50SPeter Brune 
236ab8d36c9SPeter Brune   /* number of levels -- only process most options on the finest level */
237ab8d36c9SPeter Brune   if (isFine) {
238ee78dd50SPeter Brune     ierr = PetscOptionsInt("-snes_fas_levels", "Number of Levels", "SNESFASSetLevels", levels, &levels, &flg);CHKERRQ(ierr);
239c732cbdbSBarry Smith     if (!flg && snes->dm) {
240c732cbdbSBarry Smith       ierr = DMGetRefineLevel(snes->dm,&levels);CHKERRQ(ierr);
241c732cbdbSBarry Smith       levels++;
242d1adcc6fSPeter Brune       fas->usedmfornumberoflevels = PETSC_TRUE;
243c732cbdbSBarry Smith     }
244ee78dd50SPeter Brune     ierr = SNESFASSetLevels(snes, levels, PETSC_NULL);CHKERRQ(ierr);
24507144faaSPeter Brune     fastype = fas->fastype;
24607144faaSPeter Brune     ierr = PetscOptionsEnum("-snes_fas_type","FAS correction type","SNESFASSetType",SNESFASTypes,(PetscEnum)fastype,(PetscEnum*)&fastype,&flg);CHKERRQ(ierr);
24707144faaSPeter Brune     if (flg) {
24807144faaSPeter Brune       ierr = SNESFASSetType(snes, fastype);CHKERRQ(ierr);
24907144faaSPeter Brune     }
250ee78dd50SPeter Brune 
251fde0ff24SPeter Brune     ierr = SNESGetOptionsPrefix(snes, &optionsprefix);CHKERRQ(ierr);
252ab8d36c9SPeter Brune     ierr = PetscOptionsInt("-snes_fas_cycles","Number of cycles","SNESFASSetCycles",fas->n_cycles,&m,&flg);CHKERRQ(ierr);
253ab8d36c9SPeter Brune     if (flg) {
254ab8d36c9SPeter Brune       ierr = SNESFASSetCycles(snes, m);CHKERRQ(ierr);
255fde0ff24SPeter Brune     }
256fde0ff24SPeter Brune 
257ab8d36c9SPeter Brune     ierr = PetscOptionsBool("-snes_fas_galerkin", "Form coarse problems with Galerkin","SNESFASSetGalerkin",fas->galerkin,&galerkinflg,&flg);CHKERRQ(ierr);
258ab8d36c9SPeter Brune     if (flg) {
259ab8d36c9SPeter Brune       ierr = SNESFASSetGalerkin(snes, galerkinflg);CHKERRQ(ierr);
260ab8d36c9SPeter Brune     }
261ee78dd50SPeter Brune 
26266585501SPeter Brune     ierr = PetscOptionsInt("-snes_fas_smoothup","Number of post-smoothing steps","SNESFASSetNumberSmoothUp",fas->max_up_it,&n_up,&upflg);CHKERRQ(ierr);
263162d76ddSPeter Brune 
26466585501SPeter Brune     ierr = PetscOptionsInt("-snes_fas_smoothdown","Number of pre-smoothing steps","SNESFASSetNumberSmoothDown",fas->max_down_it,&n_down,&downflg);CHKERRQ(ierr);
265162d76ddSPeter Brune 
266c8c899caSPeter Brune     ierr = PetscOptionsString("-snes_fas_monitor","Monitor FAS progress","SNESFASSetMonitor","stdout",monfilename,PETSC_MAX_PATH_LEN,&monflg);CHKERRQ(ierr);
267c8c899caSPeter Brune     if (monflg) ierr = SNESFASSetMonitor(snes, PETSC_TRUE);CHKERRQ(ierr);
268ab8d36c9SPeter Brune   }
269ee78dd50SPeter Brune 
270421d9b32SPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
2718cc86e31SPeter Brune   /* setup from the determined types if there is no pointwise procedure or smoother defined */
272162d76ddSPeter Brune   if (upflg) {
27366585501SPeter Brune     ierr = SNESFASSetNumberSmoothUp(snes,n_up);CHKERRQ(ierr);
274162d76ddSPeter Brune   }
275162d76ddSPeter Brune   if (downflg) {
27666585501SPeter Brune     ierr = SNESFASSetNumberSmoothDown(snes,n_down);CHKERRQ(ierr);
277162d76ddSPeter Brune   }
278eff52c0eSPeter Brune 
2799e764e56SPeter Brune   /* set up the default line search for coarse grid corrections */
2809e764e56SPeter Brune   if (fas->fastype == SNES_FAS_ADDITIVE) {
2819e764e56SPeter Brune     if (!snes->linesearch) {
282f1c6b773SPeter Brune       ierr = SNESGetSNESLineSearch(snes, &linesearch);CHKERRQ(ierr);
283f1c6b773SPeter Brune       ierr = SNESLineSearchSetType(linesearch, SNES_LINESEARCH_L2);CHKERRQ(ierr);
2849e764e56SPeter Brune     }
2859e764e56SPeter Brune   }
2869e764e56SPeter Brune 
287ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
288ee78dd50SPeter Brune   /* recursive option setting for the smoothers */
289ab8d36c9SPeter Brune   if (next) {ierr = SNESSetFromOptions(next);CHKERRQ(ierr);}
290421d9b32SPeter Brune   PetscFunctionReturn(0);
291421d9b32SPeter Brune }
292421d9b32SPeter Brune 
293421d9b32SPeter Brune #undef __FUNCT__
294421d9b32SPeter Brune #define __FUNCT__ "SNESView_FAS"
295421d9b32SPeter Brune PetscErrorCode SNESView_FAS(SNES snes, PetscViewer viewer)
296421d9b32SPeter Brune {
297421d9b32SPeter Brune   SNES_FAS       *fas = (SNES_FAS *) snes->data;
298ab8d36c9SPeter Brune   PetscBool      isFine, iascii;
299ab8d36c9SPeter Brune   PetscInt       i;
300421d9b32SPeter Brune   PetscErrorCode ierr;
301ab8d36c9SPeter Brune   SNES           smoothu, smoothd, levelsnes;
302421d9b32SPeter Brune 
303421d9b32SPeter Brune   PetscFunctionBegin;
304ab8d36c9SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
305ab8d36c9SPeter Brune   if (isFine) {
306421d9b32SPeter Brune     ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
307421d9b32SPeter Brune     if (iascii) {
308ab8d36c9SPeter Brune       ierr = PetscViewerASCIIPrintf(viewer, "FAS: type is %s, levels=%D, cycles=%D\n",  SNESFASTypes[fas->fastype], fas->levels, fas->n_cycles);CHKERRQ(ierr);
309ab8d36c9SPeter Brune       if (fas->galerkin) {
310ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid function evaluation\n");CHKERRQ(ierr);
311421d9b32SPeter Brune       } else {
312ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPrintf(viewer,"    Not using Galerkin computed coarse grid function evaluation\n");CHKERRQ(ierr);
313421d9b32SPeter Brune       }
314ab8d36c9SPeter Brune       for (i=0; i<fas->levels; i++) {
315ab8d36c9SPeter Brune         ierr = SNESFASGetCycleSNES(snes, i, &levelsnes);CHKERRQ(ierr);
316ab8d36c9SPeter Brune         ierr = SNESFASCycleGetSmootherUp(levelsnes, &smoothu);CHKERRQ(ierr);
317ab8d36c9SPeter Brune         ierr = SNESFASCycleGetSmootherDown(levelsnes, &smoothd);CHKERRQ(ierr);
318ab8d36c9SPeter Brune         if (!i) {
319ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Coarse grid solver -- level %D -------------------------------\n",i);CHKERRQ(ierr);
320421d9b32SPeter Brune         } else {
321ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
322421d9b32SPeter Brune         }
323ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
324ab8d36c9SPeter Brune         ierr = SNESView(smoothd,viewer);CHKERRQ(ierr);
325ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
326ab8d36c9SPeter Brune         if (i && (smoothd == smoothu)) {
327ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n");CHKERRQ(ierr);
328ab8d36c9SPeter Brune         } else if (i) {
329ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
330ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
331ab8d36c9SPeter Brune           ierr = SNESView(smoothu,viewer);CHKERRQ(ierr);
332ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
333ab8d36c9SPeter Brune         }
334ab8d36c9SPeter Brune       }
335421d9b32SPeter Brune     } else {
336421d9b32SPeter Brune       SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for SNESFAS",((PetscObject)viewer)->type_name);
337421d9b32SPeter Brune     }
338ab8d36c9SPeter Brune   }
339421d9b32SPeter Brune   PetscFunctionReturn(0);
340421d9b32SPeter Brune }
341421d9b32SPeter Brune 
342421d9b32SPeter Brune #undef __FUNCT__
34339bd7f45SPeter Brune #define __FUNCT__ "FASDownSmooth"
34439bd7f45SPeter Brune /*
34539bd7f45SPeter Brune Defines the action of the downsmoother
34639bd7f45SPeter Brune  */
34739bd7f45SPeter Brune PetscErrorCode FASDownSmooth(SNES snes, Vec B, Vec X, Vec F){
34839bd7f45SPeter Brune   PetscErrorCode      ierr = 0;
349742fe5e2SPeter Brune   SNESConvergedReason reason;
350ab8d36c9SPeter Brune   Vec                 FPC;
351ab8d36c9SPeter Brune   SNES                smoothd;
352421d9b32SPeter Brune   PetscFunctionBegin;
353ab8d36c9SPeter Brune   ierr = SNESFASCycleGetSmootherDown(snes, &smoothd);CHKERRQ(ierr);
354ab8d36c9SPeter Brune   ierr = SNESSolve(smoothd, B, X);CHKERRQ(ierr);
355742fe5e2SPeter Brune   /* check convergence reason for the smoother */
356ab8d36c9SPeter Brune   ierr = SNESGetConvergedReason(smoothd,&reason);CHKERRQ(ierr);
357e70c42e5SPeter Brune   if (reason < 0 && !(reason == SNES_DIVERGED_MAX_IT || reason == SNES_DIVERGED_LOCAL_MIN)) {
358742fe5e2SPeter Brune     snes->reason = SNES_DIVERGED_INNER;
359742fe5e2SPeter Brune     PetscFunctionReturn(0);
360742fe5e2SPeter Brune   }
361ab8d36c9SPeter Brune   ierr = SNESGetFunction(smoothd, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
3624b32a720SPeter Brune   ierr = VecCopy(FPC, F);CHKERRQ(ierr);
36339bd7f45SPeter Brune   PetscFunctionReturn(0);
36439bd7f45SPeter Brune }
36539bd7f45SPeter Brune 
36639bd7f45SPeter Brune 
36739bd7f45SPeter Brune #undef __FUNCT__
36839bd7f45SPeter Brune #define __FUNCT__ "FASUpSmooth"
36939bd7f45SPeter Brune /*
37007144faaSPeter Brune Defines the action of the upsmoother
37139bd7f45SPeter Brune  */
37239bd7f45SPeter Brune PetscErrorCode FASUpSmooth (SNES snes, Vec B, Vec X, Vec F) {
37339bd7f45SPeter Brune   PetscErrorCode      ierr = 0;
37439bd7f45SPeter Brune   SNESConvergedReason reason;
375ab8d36c9SPeter Brune   Vec                 FPC;
376ab8d36c9SPeter Brune   SNES                smoothu;
37739bd7f45SPeter Brune   PetscFunctionBegin;
378ab8d36c9SPeter Brune 
379ab8d36c9SPeter Brune   ierr = SNESFASCycleGetSmootherUp(snes, &smoothu);CHKERRQ(ierr);
380ab8d36c9SPeter Brune   ierr = SNESSolve(smoothu, B, X);CHKERRQ(ierr);
38139bd7f45SPeter Brune   /* check convergence reason for the smoother */
382ab8d36c9SPeter Brune   ierr = SNESGetConvergedReason(smoothu,&reason);CHKERRQ(ierr);
38339bd7f45SPeter Brune   if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
38439bd7f45SPeter Brune     snes->reason = SNES_DIVERGED_INNER;
38539bd7f45SPeter Brune     PetscFunctionReturn(0);
38639bd7f45SPeter Brune   }
387ab8d36c9SPeter Brune   ierr = SNESGetFunction(smoothu, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
3884b32a720SPeter Brune   ierr = VecCopy(FPC, F);CHKERRQ(ierr);
38939bd7f45SPeter Brune   PetscFunctionReturn(0);
39039bd7f45SPeter Brune }
39139bd7f45SPeter Brune 
39239bd7f45SPeter Brune #undef __FUNCT__
393938e4a01SJed Brown #define __FUNCT__ "SNESFASCreateCoarseVec"
394938e4a01SJed Brown /*@
395938e4a01SJed Brown    SNESFASCreateCoarseVec - create Vec corresponding to a state vector on one level coarser than current level
396938e4a01SJed Brown 
397938e4a01SJed Brown    Collective
398938e4a01SJed Brown 
399938e4a01SJed Brown    Input Arguments:
400938e4a01SJed Brown .  snes - SNESFAS
401938e4a01SJed Brown 
402938e4a01SJed Brown    Output Arguments:
403938e4a01SJed Brown .  Xcoarse - vector on level one coarser than snes
404938e4a01SJed Brown 
405938e4a01SJed Brown    Level: developer
406938e4a01SJed Brown 
407938e4a01SJed Brown .seealso: SNESFASSetRestriction(), SNESFASRestrict()
408938e4a01SJed Brown @*/
409938e4a01SJed Brown PetscErrorCode SNESFASCreateCoarseVec(SNES snes,Vec *Xcoarse)
410938e4a01SJed Brown {
411938e4a01SJed Brown   PetscErrorCode ierr;
412938e4a01SJed Brown   SNES_FAS       *fas = (SNES_FAS*)snes->data;
413938e4a01SJed Brown 
414938e4a01SJed Brown   PetscFunctionBegin;
415938e4a01SJed Brown   if (fas->rscale) {ierr = VecDuplicate(fas->rscale,Xcoarse);CHKERRQ(ierr);}
416938e4a01SJed Brown   else if (fas->inject) {ierr = MatGetVecs(fas->inject,Xcoarse,PETSC_NULL);CHKERRQ(ierr);}
417938e4a01SJed Brown   else SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must set restriction or injection");CHKERRQ(ierr);
418938e4a01SJed Brown   PetscFunctionReturn(0);
419938e4a01SJed Brown }
420938e4a01SJed Brown 
421e9923e8dSJed Brown #undef __FUNCT__
422e9923e8dSJed Brown #define __FUNCT__ "SNESFASRestrict"
423e9923e8dSJed Brown /*@
424e9923e8dSJed Brown    SNESFASRestrict - restrict a Vec to the next coarser level
425e9923e8dSJed Brown 
426e9923e8dSJed Brown    Collective
427e9923e8dSJed Brown 
428e9923e8dSJed Brown    Input Arguments:
429e9923e8dSJed Brown +  fine - SNES from which to restrict
430e9923e8dSJed Brown -  Xfine - vector to restrict
431e9923e8dSJed Brown 
432e9923e8dSJed Brown    Output Arguments:
433e9923e8dSJed Brown .  Xcoarse - result of restriction
434e9923e8dSJed Brown 
435e9923e8dSJed Brown    Level: developer
436e9923e8dSJed Brown 
437e9923e8dSJed Brown .seealso: SNESFASSetRestriction(), SNESFASSetInjection()
438e9923e8dSJed Brown @*/
439e9923e8dSJed Brown PetscErrorCode SNESFASRestrict(SNES fine,Vec Xfine,Vec Xcoarse)
440e9923e8dSJed Brown {
441e9923e8dSJed Brown   PetscErrorCode ierr;
442e9923e8dSJed Brown   SNES_FAS       *fas = (SNES_FAS*)fine->data;
443e9923e8dSJed Brown 
444e9923e8dSJed Brown   PetscFunctionBegin;
445e9923e8dSJed Brown   PetscValidHeaderSpecific(fine,SNES_CLASSID,1);
446e9923e8dSJed Brown   PetscValidHeaderSpecific(Xfine,VEC_CLASSID,2);
447e9923e8dSJed Brown   PetscValidHeaderSpecific(Xcoarse,VEC_CLASSID,3);
448e9923e8dSJed Brown   if (fas->inject) {
449e9923e8dSJed Brown     ierr = MatRestrict(fas->inject,Xfine,Xcoarse);CHKERRQ(ierr);
450e9923e8dSJed Brown   } else {
451e9923e8dSJed Brown     ierr = MatRestrict(fas->restrct,Xfine,Xcoarse);CHKERRQ(ierr);
452e9923e8dSJed Brown     ierr = VecPointwiseMult(Xcoarse,fas->rscale,Xcoarse);CHKERRQ(ierr);
453e9923e8dSJed Brown   }
454e9923e8dSJed Brown   PetscFunctionReturn(0);
455e9923e8dSJed Brown }
456e9923e8dSJed Brown 
457e9923e8dSJed Brown #undef __FUNCT__
45839bd7f45SPeter Brune #define __FUNCT__ "FASCoarseCorrection"
45939bd7f45SPeter Brune /*
46039bd7f45SPeter Brune 
46139bd7f45SPeter Brune Performs the FAS coarse correction as:
46239bd7f45SPeter Brune 
46339bd7f45SPeter Brune fine problem: F(x) = 0
46439bd7f45SPeter Brune coarse problem: F^c(x) = b^c
46539bd7f45SPeter Brune 
46639bd7f45SPeter Brune b^c = F^c(I^c_fx^f - I^c_fF(x))
46739bd7f45SPeter Brune 
46839bd7f45SPeter Brune  */
46939a4b097SPeter Brune PetscErrorCode FASCoarseCorrection(SNES snes, Vec X, Vec F, Vec X_new) {
47039bd7f45SPeter Brune   PetscErrorCode      ierr;
47139bd7f45SPeter Brune   Vec                 X_c, Xo_c, F_c, B_c;
47239bd7f45SPeter Brune   SNESConvergedReason reason;
473ab8d36c9SPeter Brune   SNES                next;
474ab8d36c9SPeter Brune   Mat                 restrct, interpolate;
47539bd7f45SPeter Brune   PetscFunctionBegin;
476ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
477ab8d36c9SPeter Brune   if (next) {
478ab8d36c9SPeter Brune     ierr = SNESFASCycleGetRestriction(snes, &restrct);CHKERRQ(ierr);
479ab8d36c9SPeter Brune     ierr = SNESFASCycleGetInterpolation(snes, &interpolate);CHKERRQ(ierr);
480ab8d36c9SPeter Brune 
481ab8d36c9SPeter Brune     X_c  = next->vec_sol;
482ab8d36c9SPeter Brune     Xo_c = next->work[0];
483ab8d36c9SPeter Brune     F_c  = next->vec_func;
484ab8d36c9SPeter Brune     B_c  = next->vec_rhs;
485efe1f98aSPeter Brune 
486938e4a01SJed Brown     ierr = SNESFASRestrict(snes,X,Xo_c);CHKERRQ(ierr);
487293a7e31SPeter Brune     ierr = VecScale(F, -1.0);CHKERRQ(ierr);
488293a7e31SPeter Brune 
489293a7e31SPeter Brune     /* restrict the defect */
490ab8d36c9SPeter Brune     ierr = MatRestrict(restrct, F, B_c);CHKERRQ(ierr);
491293a7e31SPeter Brune 
492c90fad12SPeter Brune     /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */
493ab8d36c9SPeter Brune     next->vec_rhs = PETSC_NULL;                                           /*unset the RHS to evaluate function instead of residual*/
494ab8d36c9SPeter Brune     ierr = SNESComputeFunction(next, Xo_c, F_c);CHKERRQ(ierr);
495742fe5e2SPeter Brune 
496293a7e31SPeter Brune     ierr = VecAXPY(B_c, 1.0, F_c);CHKERRQ(ierr);                               /* add F_c(X) to the RHS */
497c90fad12SPeter Brune 
498ee78dd50SPeter Brune     /* set initial guess of the coarse problem to the projected fine solution */
499ee78dd50SPeter Brune     ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr);
500c90fad12SPeter Brune 
501c90fad12SPeter Brune     /* recurse to the next level */
502ab8d36c9SPeter Brune     next->vec_rhs = B_c;
503ab8d36c9SPeter Brune     ierr = SNESSolve(next, B_c, X_c);CHKERRQ(ierr);
504ab8d36c9SPeter Brune     ierr = SNESGetConvergedReason(next,&reason);CHKERRQ(ierr);
505742fe5e2SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
506742fe5e2SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
507742fe5e2SPeter Brune       PetscFunctionReturn(0);
508742fe5e2SPeter Brune     }
509ee78dd50SPeter Brune 
510fa9694d7SPeter Brune     /* correct as x <- x + I(x^c - Rx)*/
511fa9694d7SPeter Brune     ierr = VecAXPY(X_c, -1.0, Xo_c);CHKERRQ(ierr);
512ab8d36c9SPeter Brune     ierr = MatInterpolateAdd(interpolate, X_c, X, X_new);CHKERRQ(ierr);
513293a7e31SPeter Brune   }
51439bd7f45SPeter Brune   PetscFunctionReturn(0);
51539bd7f45SPeter Brune }
51639bd7f45SPeter Brune 
51739bd7f45SPeter Brune #undef __FUNCT__
51839bd7f45SPeter Brune #define __FUNCT__ "FASCycle_Additive"
51939bd7f45SPeter Brune /*
52039bd7f45SPeter Brune 
52139bd7f45SPeter Brune The additive cycle looks like:
52239bd7f45SPeter Brune 
52307144faaSPeter Brune xhat = x
52407144faaSPeter Brune xhat = dS(x, b)
52507144faaSPeter Brune x = coarsecorrection(xhat, b_d)
52607144faaSPeter Brune x = x + nu*(xhat - x);
52739bd7f45SPeter Brune (optional) x = uS(x, b)
52839bd7f45SPeter Brune 
52939bd7f45SPeter Brune With the coarse RHS (defect correction) as below.
53039bd7f45SPeter Brune 
53139bd7f45SPeter Brune  */
53239bd7f45SPeter Brune PetscErrorCode FASCycle_Additive(SNES snes, Vec X) {
53307144faaSPeter Brune   Vec                 F, B, Xhat;
53422c1e704SPeter Brune   Vec                 X_c, Xo_c, F_c, B_c;
53539bd7f45SPeter Brune   PetscErrorCode      ierr;
53607144faaSPeter Brune   SNESConvergedReason reason;
53722c1e704SPeter Brune   PetscReal           xnorm, fnorm, ynorm;
53822c1e704SPeter Brune   PetscBool           lssuccess;
539ab8d36c9SPeter Brune   SNES                next;
540ab8d36c9SPeter Brune   Mat                 restrct, interpolate;
54139bd7f45SPeter Brune   PetscFunctionBegin;
542ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
54339bd7f45SPeter Brune   F = snes->vec_func;
54439bd7f45SPeter Brune   B = snes->vec_rhs;
545fde0ff24SPeter Brune   Xhat = snes->work[3];
54607144faaSPeter Brune   ierr = VecCopy(X, Xhat);CHKERRQ(ierr);
54707144faaSPeter Brune   /* recurse first */
548ab8d36c9SPeter Brune   if (next) {
549ab8d36c9SPeter Brune     ierr = SNESFASCycleGetRestriction(snes, &restrct);CHKERRQ(ierr);
550ab8d36c9SPeter Brune     ierr = SNESFASCycleGetInterpolation(snes, &interpolate);CHKERRQ(ierr);
55107144faaSPeter Brune     ierr = SNESComputeFunction(snes, Xhat, F);CHKERRQ(ierr);
55239bd7f45SPeter Brune 
553ab8d36c9SPeter Brune     X_c  = next->vec_sol;
554ab8d36c9SPeter Brune     Xo_c = next->work[0];
555ab8d36c9SPeter Brune     F_c  = next->vec_func;
556ab8d36c9SPeter Brune     B_c  = next->vec_rhs;
55739bd7f45SPeter Brune 
558938e4a01SJed Brown     ierr = SNESFASRestrict(snes,Xhat,Xo_c);CHKERRQ(ierr);
55907144faaSPeter Brune     ierr = VecScale(F, -1.0);CHKERRQ(ierr);
56007144faaSPeter Brune 
56107144faaSPeter Brune     /* restrict the defect */
562ab8d36c9SPeter Brune     ierr = MatRestrict(restrct, F, B_c);CHKERRQ(ierr);
56307144faaSPeter Brune 
56407144faaSPeter Brune     /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */
565ab8d36c9SPeter Brune     next->vec_rhs = PETSC_NULL;                                           /*unset the RHS to evaluate function instead of residual*/
566ab8d36c9SPeter Brune     ierr = SNESComputeFunction(next, Xo_c, F_c);CHKERRQ(ierr);
56707144faaSPeter Brune 
56807144faaSPeter Brune     ierr = VecAXPY(B_c, 1.0, F_c);CHKERRQ(ierr);                               /* add F_c(X) to the RHS */
56907144faaSPeter Brune 
57007144faaSPeter Brune     /* set initial guess of the coarse problem to the projected fine solution */
57107144faaSPeter Brune     ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr);
57207144faaSPeter Brune 
57307144faaSPeter Brune     /* recurse */
574ab8d36c9SPeter Brune     next->vec_rhs = B_c;
575ab8d36c9SPeter Brune     ierr = SNESSolve(next, B_c, X_c);CHKERRQ(ierr);
57607144faaSPeter Brune 
57707144faaSPeter Brune     /* smooth on this level */
57807144faaSPeter Brune     ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr);
57907144faaSPeter Brune 
580ab8d36c9SPeter Brune     ierr = SNESGetConvergedReason(next,&reason);CHKERRQ(ierr);
58107144faaSPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
58207144faaSPeter Brune       snes->reason = SNES_DIVERGED_INNER;
58307144faaSPeter Brune       PetscFunctionReturn(0);
58407144faaSPeter Brune     }
58507144faaSPeter Brune 
58607144faaSPeter Brune     /* correct as x <- x + I(x^c - Rx)*/
587c68acad4SPeter Brune     ierr = VecAYPX(X_c, -1.0, Xo_c);CHKERRQ(ierr);
588ab8d36c9SPeter Brune     ierr = MatInterpolate(interpolate, X_c, Xhat);CHKERRQ(ierr);
58907144faaSPeter Brune 
590ddebd997SPeter Brune     /* additive correction of the coarse direction*/
591ddebd997SPeter Brune     ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
592ddebd997SPeter Brune     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
593f1c6b773SPeter Brune     ierr = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Xhat);CHKERRQ(ierr);
594f1c6b773SPeter Brune     ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssuccess);CHKERRQ(ierr);
5959e764e56SPeter Brune     if (!lssuccess) {
5969e764e56SPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
5979e764e56SPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
5989e764e56SPeter Brune         PetscFunctionReturn(0);
5999e764e56SPeter Brune       }
6009e764e56SPeter Brune     }
601f1c6b773SPeter Brune     ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
60207144faaSPeter Brune   } else {
60307144faaSPeter Brune     ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr);
60407144faaSPeter Brune   }
60539bd7f45SPeter Brune   PetscFunctionReturn(0);
60639bd7f45SPeter Brune }
60739bd7f45SPeter Brune 
60839bd7f45SPeter Brune #undef __FUNCT__
60939bd7f45SPeter Brune #define __FUNCT__ "FASCycle_Multiplicative"
61039bd7f45SPeter Brune /*
61139bd7f45SPeter Brune 
61239bd7f45SPeter Brune Defines the FAS cycle as:
61339bd7f45SPeter Brune 
61439bd7f45SPeter Brune fine problem: F(x) = 0
61539bd7f45SPeter Brune coarse problem: F^c(x) = b^c
61639bd7f45SPeter Brune 
61739bd7f45SPeter Brune b^c = F^c(I^c_fx^f - I^c_fF(x))
61839bd7f45SPeter Brune 
61939bd7f45SPeter Brune correction:
62039bd7f45SPeter Brune 
62139bd7f45SPeter Brune x = x + I(x^c - Rx)
62239bd7f45SPeter Brune 
62339bd7f45SPeter Brune  */
62439bd7f45SPeter Brune PetscErrorCode FASCycle_Multiplicative(SNES snes, Vec X) {
62539bd7f45SPeter Brune 
62639bd7f45SPeter Brune   PetscErrorCode      ierr;
62739bd7f45SPeter Brune   Vec                 F,B;
62839bd7f45SPeter Brune   SNES_FAS            *fas = (SNES_FAS *)snes->data;
62939bd7f45SPeter Brune 
63039bd7f45SPeter Brune   PetscFunctionBegin;
63139bd7f45SPeter Brune   F = snes->vec_func;
63239bd7f45SPeter Brune   B = snes->vec_rhs;
63339bd7f45SPeter Brune   /* pre-smooth -- just update using the pre-smoother */
63439bd7f45SPeter Brune   ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr);
63539bd7f45SPeter Brune 
636c90fad12SPeter Brune   if (fas->level != 0) {
637e70c42e5SPeter Brune     ierr = FASCoarseCorrection(snes, X, F, X);CHKERRQ(ierr);
63839bd7f45SPeter Brune     ierr = FASUpSmooth(snes, B, X, F);CHKERRQ(ierr);
639fe6f9142SPeter Brune   }
640fa9694d7SPeter Brune   PetscFunctionReturn(0);
641421d9b32SPeter Brune }
642421d9b32SPeter Brune 
643421d9b32SPeter Brune #undef __FUNCT__
644421d9b32SPeter Brune #define __FUNCT__ "SNESSolve_FAS"
645421d9b32SPeter Brune 
646421d9b32SPeter Brune PetscErrorCode SNESSolve_FAS(SNES snes)
647421d9b32SPeter Brune {
648fa9694d7SPeter Brune   PetscErrorCode ierr;
649fe6f9142SPeter Brune   PetscInt       i, maxits;
650ddb5aff1SPeter Brune   Vec            X, F;
651fe6f9142SPeter Brune   PetscReal      fnorm;
652b17ce1afSJed Brown   SNES_FAS       *fas = (SNES_FAS *)snes->data,*ffas;
653b17ce1afSJed Brown   DM             dm;
654e70c42e5SPeter Brune   PetscBool      isFine;
655b17ce1afSJed Brown 
656421d9b32SPeter Brune   PetscFunctionBegin;
657fe6f9142SPeter Brune   maxits = snes->max_its;            /* maximum number of iterations */
658fe6f9142SPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
659fa9694d7SPeter Brune   X = snes->vec_sol;
660f5a6d4f9SBarry Smith   F = snes->vec_func;
661293a7e31SPeter Brune 
66218a66777SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
663293a7e31SPeter Brune   /*norm setup */
664fe6f9142SPeter Brune   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
665fe6f9142SPeter Brune   snes->iter = 0;
666fe6f9142SPeter Brune   snes->norm = 0.;
667fe6f9142SPeter Brune   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
66818a66777SPeter Brune   if (isFine || fas->monitor) {
669fe6f9142SPeter Brune     ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
670fe6f9142SPeter Brune     if (snes->domainerror) {
671fe6f9142SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
672fe6f9142SPeter Brune       PetscFunctionReturn(0);
673fe6f9142SPeter Brune     }
674fe6f9142SPeter Brune     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
675fe6f9142SPeter Brune     if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm");
676fe6f9142SPeter Brune     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
677fe6f9142SPeter Brune     snes->norm = fnorm;
678fe6f9142SPeter Brune     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
679fe6f9142SPeter Brune     SNESLogConvHistory(snes,fnorm,0);
680fe6f9142SPeter Brune     ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
681fe6f9142SPeter Brune 
682fe6f9142SPeter Brune     /* set parameter for default relative tolerance convergence test */
683fe6f9142SPeter Brune     snes->ttol = fnorm*snes->rtol;
684fe6f9142SPeter Brune     /* test convergence */
685fe6f9142SPeter Brune     ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
686fe6f9142SPeter Brune     if (snes->reason) PetscFunctionReturn(0);
68766585501SPeter Brune   }
688b17ce1afSJed Brown 
689b17ce1afSJed Brown   ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
690b17ce1afSJed Brown   for (ffas=fas; ffas->next; ffas=(SNES_FAS*)ffas->next->data) {
691b17ce1afSJed Brown     DM dmcoarse;
692b17ce1afSJed Brown     ierr = SNESGetDM(ffas->next,&dmcoarse);CHKERRQ(ierr);
693b17ce1afSJed Brown     ierr = DMRestrict(dm,ffas->restrct,ffas->rscale,ffas->inject,dmcoarse);CHKERRQ(ierr);
694b17ce1afSJed Brown     dm = dmcoarse;
695b17ce1afSJed Brown   }
696b17ce1afSJed Brown 
697fe6f9142SPeter Brune   for (i = 0; i < maxits; i++) {
698fe6f9142SPeter Brune     /* Call general purpose update function */
699646217ecSPeter Brune 
700fe6f9142SPeter Brune     if (snes->ops->update) {
701fe6f9142SPeter Brune       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
702fe6f9142SPeter Brune     }
70307144faaSPeter Brune     if (fas->fastype == SNES_FAS_MULTIPLICATIVE) {
70439bd7f45SPeter Brune       ierr = FASCycle_Multiplicative(snes, X);CHKERRQ(ierr);
70507144faaSPeter Brune     } else {
70607144faaSPeter Brune       ierr = FASCycle_Additive(snes, X);CHKERRQ(ierr);
70707144faaSPeter Brune     }
708742fe5e2SPeter Brune 
709742fe5e2SPeter Brune     /* check for FAS cycle divergence */
710742fe5e2SPeter Brune     if (snes->reason != SNES_CONVERGED_ITERATING) {
711742fe5e2SPeter Brune       PetscFunctionReturn(0);
712742fe5e2SPeter Brune     }
713e70c42e5SPeter Brune     if (isFine || fas->monitor) {
714c90fad12SPeter Brune       ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
715e70c42e5SPeter Brune     }
716c90fad12SPeter Brune     /* Monitor convergence */
717c90fad12SPeter Brune     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
718c90fad12SPeter Brune     snes->iter = i+1;
719c90fad12SPeter Brune     snes->norm = fnorm;
720c90fad12SPeter Brune     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
721c90fad12SPeter Brune     SNESLogConvHistory(snes,snes->norm,0);
722c90fad12SPeter Brune     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
723c90fad12SPeter Brune     /* Test for convergence */
72466585501SPeter Brune     if (isFine) {
725c90fad12SPeter Brune       ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
726c90fad12SPeter Brune       if (snes->reason) break;
727fe6f9142SPeter Brune     }
72866585501SPeter Brune   }
729fe6f9142SPeter Brune   if (i == maxits) {
730fe6f9142SPeter Brune     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr);
731fe6f9142SPeter Brune     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
732fe6f9142SPeter Brune   }
733421d9b32SPeter Brune   PetscFunctionReturn(0);
734421d9b32SPeter Brune }
735