xref: /petsc/src/snes/impls/fas/fas.c (revision d3bc2379953f61570eaba0ea7bf158e61e36f6e5)
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 
19*d3bc2379SPeter Brune    The nonlinear problem is solved by correction using coarse versions
20*d3bc2379SPeter Brune    of the nonlinear problem.  This problem is perturbed so that a projected
21*d3bc2379SPeter Brune    solution of the fine problem elicits no correction from the coarse problem.
22*d3bc2379SPeter Brune 
23*d3bc2379SPeter Brune Options Database:
24*d3bc2379SPeter Brune +   -snes_fas_levels -  The number of levels
25*d3bc2379SPeter Brune .   -snes_fas_cycles<1> -  The number of cycles -- 1 for V, 2 for W
26*d3bc2379SPeter Brune .   -snes_fas_type<additive, multiplicative>  -  Additive or multiplicative cycle
27*d3bc2379SPeter Brune .   -snes_fas_galerkin<PETSC_FALSE> -  Form coarse problems by projection back upon the fine problem
28*d3bc2379SPeter Brune .   -snes_fas_smoothup<1> -  The number of iterations of the post-smoother
29*d3bc2379SPeter Brune .   -snes_fas_smoothdown<1> -  The number of iterations of the pre-smoother
30*d3bc2379SPeter Brune .   -snes_fas_monitor -  Monitor progress of all of the levels
31*d3bc2379SPeter Brune .   -fas_levels_snes_ -  SNES options for all smoothers
32*d3bc2379SPeter Brune .   -fas_levels_cycle_snes -  SNES options for all cycles
33*d3bc2379SPeter Brune .   -fas_levels_i_snes_ -  SNES options for the smoothers on level i
34*d3bc2379SPeter Brune .   -fas_levels_i_cycle_snes - SNES options for the cycle on level i
35*d3bc2379SPeter Brune -   -fas_coarse_snes_ -  SNES options for the coarsest smoother
36*d3bc2379SPeter Brune 
37*d3bc2379SPeter Brune Notes:
38*d3bc2379SPeter Brune    The organization of the FAS solver is slightly different from the organization of PCMG
39*d3bc2379SPeter Brune    As each level has smoother SNES instances(down and potentially up) and a cycle SNES instance.
40*d3bc2379SPeter Brune    The cycle SNES instance may be used for monitoring convergence on a particular level.
411fbfccc6SJed Brown 
421fbfccc6SJed Brown Level: advanced
431fbfccc6SJed Brown 
44*d3bc2379SPeter 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   if (fas->smoothu != fas->smoothd) {
100ab8d36c9SPeter Brune     ierr = SNESDestroy(&fas->smoothu);CHKERRQ(ierr);
101ab8d36c9SPeter Brune     ierr = SNESDestroy(&fas->smoothd);CHKERRQ(ierr);
102ab8d36c9SPeter Brune   } else {
103ab8d36c9SPeter Brune     ierr = SNESDestroy(&fas->smoothd);CHKERRQ(ierr);
104ab8d36c9SPeter Brune     fas->smoothu = PETSC_NULL;
105ab8d36c9SPeter Brune   }
1063dccd265SPeter Brune   ierr = MatDestroy(&fas->inject);CHKERRQ(ierr);
107bccf9bb3SJed Brown   ierr = MatDestroy(&fas->interpolate);CHKERRQ(ierr);
108bccf9bb3SJed Brown   ierr = MatDestroy(&fas->restrct);CHKERRQ(ierr);
109bccf9bb3SJed Brown   ierr = VecDestroy(&fas->rscale);CHKERRQ(ierr);
110742fe5e2SPeter Brune   if (fas->next)      ierr = SNESReset(fas->next);CHKERRQ(ierr);
11122c1e704SPeter Brune 
112421d9b32SPeter Brune   PetscFunctionReturn(0);
113421d9b32SPeter Brune }
114421d9b32SPeter Brune 
115421d9b32SPeter Brune #undef __FUNCT__
116421d9b32SPeter Brune #define __FUNCT__ "SNESDestroy_FAS"
117421d9b32SPeter Brune PetscErrorCode SNESDestroy_FAS(SNES snes)
118421d9b32SPeter Brune {
119421d9b32SPeter Brune   SNES_FAS * fas = (SNES_FAS *)snes->data;
120742fe5e2SPeter Brune   PetscErrorCode ierr = 0;
121421d9b32SPeter Brune 
122421d9b32SPeter Brune   PetscFunctionBegin;
123421d9b32SPeter Brune   /* recursively resets and then destroys */
12479d9a41aSPeter Brune   ierr = SNESReset(snes);CHKERRQ(ierr);
125421d9b32SPeter Brune   if (fas->next)         ierr = SNESDestroy(&fas->next);CHKERRQ(ierr);
126421d9b32SPeter Brune   ierr = PetscFree(fas);CHKERRQ(ierr);
127ee1fd11aSPeter Brune 
128421d9b32SPeter Brune   PetscFunctionReturn(0);
129421d9b32SPeter Brune }
130421d9b32SPeter Brune 
131421d9b32SPeter Brune #undef __FUNCT__
132421d9b32SPeter Brune #define __FUNCT__ "SNESSetUp_FAS"
133421d9b32SPeter Brune PetscErrorCode SNESSetUp_FAS(SNES snes)
134421d9b32SPeter Brune {
13548bfdf8aSPeter Brune   SNES_FAS                *fas = (SNES_FAS *) snes->data;
136421d9b32SPeter Brune   PetscErrorCode          ierr;
137efe1f98aSPeter Brune   VecScatter              injscatter;
138d1adcc6fSPeter Brune   PetscInt                dm_levels;
1393dccd265SPeter Brune   Vec                     vec_sol, vec_func, vec_sol_update, vec_rhs; /* preserve these if they're set through the reset */
140ab8d36c9SPeter Brune   SNES                    next;
141ab8d36c9SPeter Brune   PetscBool               isFine;
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) {
173fde0ff24SPeter Brune     ierr = SNESDefaultGetWork(snes, 4);CHKERRQ(ierr); /* work vectors used for intergrid transfers */
17407144faaSPeter Brune   } else {
175ddebd997SPeter Brune     ierr = SNESDefaultGetWork(snes, 4);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   }
182ab8d36c9SPeter Brune 
18379d9a41aSPeter Brune   if (snes->dm) {
184ab8d36c9SPeter Brune     /* set the smoother DMs properly */
185ab8d36c9SPeter Brune     if (fas->smoothu) ierr = SNESSetDM(fas->smoothu, snes->dm);CHKERRQ(ierr);
186ab8d36c9SPeter Brune     ierr = SNESSetDM(fas->smoothd, snes->dm);CHKERRQ(ierr);
18779d9a41aSPeter Brune     /* construct EVERYTHING from the DM -- including the progressive set of smoothers */
188ab8d36c9SPeter Brune     if (next) {
18979d9a41aSPeter Brune       /* for now -- assume the DM and the evaluation functions have been set externally */
190ab8d36c9SPeter Brune       if (!next->dm) {
191ab8d36c9SPeter Brune         ierr = DMCoarsen(snes->dm, ((PetscObject)next)->comm, &next->dm);CHKERRQ(ierr);
192ab8d36c9SPeter Brune         ierr = SNESSetDM(next, next->dm);CHKERRQ(ierr);
19379d9a41aSPeter Brune       }
19479d9a41aSPeter Brune       /* set the interpolation and restriction from the DM */
19579d9a41aSPeter Brune       if (!fas->interpolate) {
196ab8d36c9SPeter Brune         ierr = DMCreateInterpolation(next->dm, snes->dm, &fas->interpolate, &fas->rscale);CHKERRQ(ierr);
197bccf9bb3SJed Brown         if (!fas->restrct) {
198bccf9bb3SJed Brown           ierr = PetscObjectReference((PetscObject)fas->interpolate);CHKERRQ(ierr);
19979d9a41aSPeter Brune           fas->restrct = fas->interpolate;
20079d9a41aSPeter Brune         }
201bccf9bb3SJed Brown       }
20279d9a41aSPeter Brune       /* set the injection from the DM */
20379d9a41aSPeter Brune       if (!fas->inject) {
204ab8d36c9SPeter Brune         ierr = DMCreateInjection(next->dm, snes->dm, &injscatter);CHKERRQ(ierr);
20579d9a41aSPeter Brune         ierr = MatCreateScatter(((PetscObject)snes)->comm, injscatter, &fas->inject);CHKERRQ(ierr);
20679d9a41aSPeter Brune         ierr = VecScatterDestroy(&injscatter);CHKERRQ(ierr);
20779d9a41aSPeter Brune       }
20879d9a41aSPeter Brune     }
20979d9a41aSPeter Brune   }
21079d9a41aSPeter Brune   /*pass the smoother, function, and jacobian up to the next level if it's not user set already */
21179d9a41aSPeter Brune 
21279d9a41aSPeter Brune   if (fas->galerkin) {
213ab8d36c9SPeter Brune     if (next)
214ab8d36c9SPeter Brune       ierr = SNESSetFunction(next, PETSC_NULL, SNESFASGalerkinDefaultFunction, next);CHKERRQ(ierr);
215ab8d36c9SPeter Brune     if (fas->smoothd && fas->level != fas->levels - 1) ierr = SNESSetFunction(fas->smoothd, PETSC_NULL, SNESFASGalerkinDefaultFunction, snes);CHKERRQ(ierr);
216ab8d36c9SPeter Brune     if (fas->smoothu && fas->level != fas->levels - 1) ierr = SNESSetFunction(fas->smoothu, PETSC_NULL, SNESFASGalerkinDefaultFunction, snes);CHKERRQ(ierr);
21779d9a41aSPeter Brune   }
21879d9a41aSPeter Brune 
219d06165b7SPeter Brune   /* set the smoothers up here so that precedence is taken for instance-specific options over the whole-solver options */
220d06165b7SPeter Brune   if(fas->smoothu) ierr = SNESSetFromOptions(fas->smoothu);CHKERRQ(ierr);
221d06165b7SPeter Brune   if(fas->smoothd) ierr = SNESSetFromOptions(fas->smoothd);CHKERRQ(ierr);
222d06165b7SPeter Brune 
223ab8d36c9SPeter Brune   if (next) {
22479d9a41aSPeter Brune     /* gotta set up the solution vector for this to work */
225ab8d36c9SPeter Brune     if (!next->vec_sol) {ierr = SNESFASCreateCoarseVec(snes,&next->vec_sol);CHKERRQ(ierr);}
226ab8d36c9SPeter Brune     if (!next->vec_rhs) {ierr = SNESFASCreateCoarseVec(snes,&next->vec_rhs);CHKERRQ(ierr);}
227ab8d36c9SPeter Brune     ierr = SNESSetUp(next);CHKERRQ(ierr);
22879d9a41aSPeter Brune   }
2296273346dSPeter Brune   /* setup FAS work vectors */
2306273346dSPeter Brune   if (fas->galerkin) {
2316273346dSPeter Brune     ierr = VecDuplicate(snes->vec_sol, &fas->Xg);CHKERRQ(ierr);
2326273346dSPeter Brune     ierr = VecDuplicate(snes->vec_sol, &fas->Fg);CHKERRQ(ierr);
2336273346dSPeter Brune   }
234421d9b32SPeter Brune   PetscFunctionReturn(0);
235421d9b32SPeter Brune }
236421d9b32SPeter Brune 
237421d9b32SPeter Brune #undef __FUNCT__
238421d9b32SPeter Brune #define __FUNCT__ "SNESSetFromOptions_FAS"
239421d9b32SPeter Brune PetscErrorCode SNESSetFromOptions_FAS(SNES snes)
240421d9b32SPeter Brune {
241ee78dd50SPeter Brune   SNES_FAS       *fas = (SNES_FAS *) snes->data;
242ee78dd50SPeter Brune   PetscInt       levels = 1;
243162d76ddSPeter Brune   PetscBool      flg, upflg, downflg, monflg, galerkinflg;
244421d9b32SPeter Brune   PetscErrorCode ierr;
245ee78dd50SPeter Brune   char           monfilename[PETSC_MAX_PATH_LEN];
24607144faaSPeter Brune   SNESFASType    fastype;
247fde0ff24SPeter Brune   const char     *optionsprefix;
248f1c6b773SPeter Brune   SNESLineSearch linesearch;
24966585501SPeter Brune   PetscInt       m, n_up, n_down;
250ab8d36c9SPeter Brune   SNES           next;
251ab8d36c9SPeter Brune   PetscBool      isFine;
252421d9b32SPeter Brune 
253421d9b32SPeter Brune   PetscFunctionBegin;
254ab8d36c9SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
255c90fad12SPeter Brune   ierr = PetscOptionsHead("SNESFAS Options-----------------------------------");CHKERRQ(ierr);
256ee78dd50SPeter Brune 
257ab8d36c9SPeter Brune   /* number of levels -- only process most options on the finest level */
258ab8d36c9SPeter Brune   if (isFine) {
259ee78dd50SPeter Brune     ierr = PetscOptionsInt("-snes_fas_levels", "Number of Levels", "SNESFASSetLevels", levels, &levels, &flg);CHKERRQ(ierr);
260c732cbdbSBarry Smith     if (!flg && snes->dm) {
261c732cbdbSBarry Smith       ierr = DMGetRefineLevel(snes->dm,&levels);CHKERRQ(ierr);
262c732cbdbSBarry Smith       levels++;
263d1adcc6fSPeter Brune       fas->usedmfornumberoflevels = PETSC_TRUE;
264c732cbdbSBarry Smith     }
265ee78dd50SPeter Brune     ierr = SNESFASSetLevels(snes, levels, PETSC_NULL);CHKERRQ(ierr);
26607144faaSPeter Brune     fastype = fas->fastype;
26707144faaSPeter Brune     ierr = PetscOptionsEnum("-snes_fas_type","FAS correction type","SNESFASSetType",SNESFASTypes,(PetscEnum)fastype,(PetscEnum*)&fastype,&flg);CHKERRQ(ierr);
26807144faaSPeter Brune     if (flg) {
26907144faaSPeter Brune       ierr = SNESFASSetType(snes, fastype);CHKERRQ(ierr);
27007144faaSPeter Brune     }
271ee78dd50SPeter Brune 
272fde0ff24SPeter Brune     ierr = SNESGetOptionsPrefix(snes, &optionsprefix);CHKERRQ(ierr);
273ab8d36c9SPeter Brune     ierr = PetscOptionsInt("-snes_fas_cycles","Number of cycles","SNESFASSetCycles",fas->n_cycles,&m,&flg);CHKERRQ(ierr);
274ab8d36c9SPeter Brune     if (flg) {
275ab8d36c9SPeter Brune       ierr = SNESFASSetCycles(snes, m);CHKERRQ(ierr);
276fde0ff24SPeter Brune     }
277fde0ff24SPeter Brune 
278ab8d36c9SPeter Brune     ierr = PetscOptionsBool("-snes_fas_galerkin", "Form coarse problems with Galerkin","SNESFASSetGalerkin",fas->galerkin,&galerkinflg,&flg);CHKERRQ(ierr);
279ab8d36c9SPeter Brune     if (flg) {
280ab8d36c9SPeter Brune       ierr = SNESFASSetGalerkin(snes, galerkinflg);CHKERRQ(ierr);
281ab8d36c9SPeter Brune     }
282ee78dd50SPeter Brune 
28366585501SPeter Brune     ierr = PetscOptionsInt("-snes_fas_smoothup","Number of post-smoothing steps","SNESFASSetNumberSmoothUp",fas->max_up_it,&n_up,&upflg);CHKERRQ(ierr);
284162d76ddSPeter Brune 
28566585501SPeter Brune     ierr = PetscOptionsInt("-snes_fas_smoothdown","Number of pre-smoothing steps","SNESFASSetNumberSmoothDown",fas->max_down_it,&n_down,&downflg);CHKERRQ(ierr);
286162d76ddSPeter Brune 
287c8c899caSPeter Brune     ierr = PetscOptionsString("-snes_fas_monitor","Monitor FAS progress","SNESFASSetMonitor","stdout",monfilename,PETSC_MAX_PATH_LEN,&monflg);CHKERRQ(ierr);
288c8c899caSPeter Brune     if (monflg) ierr = SNESFASSetMonitor(snes, PETSC_TRUE);CHKERRQ(ierr);
289ab8d36c9SPeter Brune   }
290ee78dd50SPeter Brune 
291421d9b32SPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
2928cc86e31SPeter Brune   /* setup from the determined types if there is no pointwise procedure or smoother defined */
293162d76ddSPeter Brune   if (upflg) {
29466585501SPeter Brune     ierr = SNESFASSetNumberSmoothUp(snes,n_up);CHKERRQ(ierr);
295162d76ddSPeter Brune   }
296162d76ddSPeter Brune   if (downflg) {
29766585501SPeter Brune     ierr = SNESFASSetNumberSmoothDown(snes,n_down);CHKERRQ(ierr);
298162d76ddSPeter Brune   }
299eff52c0eSPeter Brune 
3009e764e56SPeter Brune   /* set up the default line search for coarse grid corrections */
3019e764e56SPeter Brune   if (fas->fastype == SNES_FAS_ADDITIVE) {
3029e764e56SPeter Brune     if (!snes->linesearch) {
303f1c6b773SPeter Brune       ierr = SNESGetSNESLineSearch(snes, &linesearch);CHKERRQ(ierr);
304f1c6b773SPeter Brune       ierr = SNESLineSearchSetType(linesearch, SNES_LINESEARCH_L2);CHKERRQ(ierr);
3059e764e56SPeter Brune     }
3069e764e56SPeter Brune   }
3079e764e56SPeter Brune 
308ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
309ee78dd50SPeter Brune   /* recursive option setting for the smoothers */
310ab8d36c9SPeter Brune   if (next) {ierr = SNESSetFromOptions(next);CHKERRQ(ierr);}
311421d9b32SPeter Brune   PetscFunctionReturn(0);
312421d9b32SPeter Brune }
313421d9b32SPeter Brune 
314421d9b32SPeter Brune #undef __FUNCT__
315421d9b32SPeter Brune #define __FUNCT__ "SNESView_FAS"
316421d9b32SPeter Brune PetscErrorCode SNESView_FAS(SNES snes, PetscViewer viewer)
317421d9b32SPeter Brune {
318421d9b32SPeter Brune   SNES_FAS       *fas = (SNES_FAS *) snes->data;
319ab8d36c9SPeter Brune   PetscBool      isFine, iascii;
320ab8d36c9SPeter Brune   PetscInt       i;
321421d9b32SPeter Brune   PetscErrorCode ierr;
322ab8d36c9SPeter Brune   SNES           smoothu, smoothd, levelsnes;
323421d9b32SPeter Brune 
324421d9b32SPeter Brune   PetscFunctionBegin;
325ab8d36c9SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
326ab8d36c9SPeter Brune   if (isFine) {
327421d9b32SPeter Brune     ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
328421d9b32SPeter Brune     if (iascii) {
329ab8d36c9SPeter Brune       ierr = PetscViewerASCIIPrintf(viewer, "FAS: type is %s, levels=%D, cycles=%D\n",  SNESFASTypes[fas->fastype], fas->levels, fas->n_cycles);CHKERRQ(ierr);
330ab8d36c9SPeter Brune       if (fas->galerkin) {
331ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid function evaluation\n");CHKERRQ(ierr);
332421d9b32SPeter Brune       } else {
333ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPrintf(viewer,"    Not using Galerkin computed coarse grid function evaluation\n");CHKERRQ(ierr);
334421d9b32SPeter Brune       }
335ab8d36c9SPeter Brune       for (i=0; i<fas->levels; i++) {
336ab8d36c9SPeter Brune         ierr = SNESFASGetCycleSNES(snes, i, &levelsnes);CHKERRQ(ierr);
337ab8d36c9SPeter Brune         ierr = SNESFASCycleGetSmootherUp(levelsnes, &smoothu);CHKERRQ(ierr);
338ab8d36c9SPeter Brune         ierr = SNESFASCycleGetSmootherDown(levelsnes, &smoothd);CHKERRQ(ierr);
339ab8d36c9SPeter Brune         if (!i) {
340ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Coarse grid solver -- level %D -------------------------------\n",i);CHKERRQ(ierr);
341421d9b32SPeter Brune         } else {
342ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
343421d9b32SPeter Brune         }
344ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
345ab8d36c9SPeter Brune         ierr = SNESView(smoothd,viewer);CHKERRQ(ierr);
346ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
347ab8d36c9SPeter Brune         if (i && (smoothd == smoothu)) {
348ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n");CHKERRQ(ierr);
349ab8d36c9SPeter Brune         } else if (i) {
350ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
351ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
352ab8d36c9SPeter Brune           ierr = SNESView(smoothu,viewer);CHKERRQ(ierr);
353ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
354ab8d36c9SPeter Brune         }
355ab8d36c9SPeter Brune       }
356421d9b32SPeter Brune     } else {
357421d9b32SPeter Brune       SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for SNESFAS",((PetscObject)viewer)->type_name);
358421d9b32SPeter Brune     }
359ab8d36c9SPeter Brune   }
360421d9b32SPeter Brune   PetscFunctionReturn(0);
361421d9b32SPeter Brune }
362421d9b32SPeter Brune 
363421d9b32SPeter Brune #undef __FUNCT__
36439bd7f45SPeter Brune #define __FUNCT__ "FASDownSmooth"
36539bd7f45SPeter Brune /*
36639bd7f45SPeter Brune Defines the action of the downsmoother
36739bd7f45SPeter Brune  */
36839bd7f45SPeter Brune PetscErrorCode FASDownSmooth(SNES snes, Vec B, Vec X, Vec F){
36939bd7f45SPeter Brune   PetscErrorCode      ierr = 0;
370742fe5e2SPeter Brune   SNESConvergedReason reason;
371ab8d36c9SPeter Brune   Vec                 FPC;
372ab8d36c9SPeter Brune   SNES                smoothd;
373421d9b32SPeter Brune   PetscFunctionBegin;
374ab8d36c9SPeter Brune   ierr = SNESFASCycleGetSmootherDown(snes, &smoothd);CHKERRQ(ierr);
375ab8d36c9SPeter Brune   ierr = SNESSolve(smoothd, B, X);CHKERRQ(ierr);
376742fe5e2SPeter Brune   /* check convergence reason for the smoother */
377ab8d36c9SPeter Brune   ierr = SNESGetConvergedReason(smoothd,&reason);CHKERRQ(ierr);
378e70c42e5SPeter Brune   if (reason < 0 && !(reason == SNES_DIVERGED_MAX_IT || reason == SNES_DIVERGED_LOCAL_MIN)) {
379742fe5e2SPeter Brune     snes->reason = SNES_DIVERGED_INNER;
380742fe5e2SPeter Brune     PetscFunctionReturn(0);
381742fe5e2SPeter Brune   }
382ab8d36c9SPeter Brune   ierr = SNESGetFunction(smoothd, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
3834b32a720SPeter Brune   ierr = VecCopy(FPC, F);CHKERRQ(ierr);
38439bd7f45SPeter Brune   PetscFunctionReturn(0);
38539bd7f45SPeter Brune }
38639bd7f45SPeter Brune 
38739bd7f45SPeter Brune 
38839bd7f45SPeter Brune #undef __FUNCT__
38939bd7f45SPeter Brune #define __FUNCT__ "FASUpSmooth"
39039bd7f45SPeter Brune /*
39107144faaSPeter Brune Defines the action of the upsmoother
39239bd7f45SPeter Brune  */
39339bd7f45SPeter Brune PetscErrorCode FASUpSmooth (SNES snes, Vec B, Vec X, Vec F) {
39439bd7f45SPeter Brune   PetscErrorCode      ierr = 0;
39539bd7f45SPeter Brune   SNESConvergedReason reason;
396ab8d36c9SPeter Brune   Vec                 FPC;
397ab8d36c9SPeter Brune   SNES                smoothu;
39839bd7f45SPeter Brune   PetscFunctionBegin;
399ab8d36c9SPeter Brune 
400ab8d36c9SPeter Brune   ierr = SNESFASCycleGetSmootherUp(snes, &smoothu);CHKERRQ(ierr);
401ab8d36c9SPeter Brune   ierr = SNESSolve(smoothu, B, X);CHKERRQ(ierr);
40239bd7f45SPeter Brune   /* check convergence reason for the smoother */
403ab8d36c9SPeter Brune   ierr = SNESGetConvergedReason(smoothu,&reason);CHKERRQ(ierr);
40439bd7f45SPeter Brune   if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
40539bd7f45SPeter Brune     snes->reason = SNES_DIVERGED_INNER;
40639bd7f45SPeter Brune     PetscFunctionReturn(0);
40739bd7f45SPeter Brune   }
408ab8d36c9SPeter Brune   ierr = SNESGetFunction(smoothu, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
4094b32a720SPeter Brune   ierr = VecCopy(FPC, F);CHKERRQ(ierr);
41039bd7f45SPeter Brune   PetscFunctionReturn(0);
41139bd7f45SPeter Brune }
41239bd7f45SPeter Brune 
41339bd7f45SPeter Brune #undef __FUNCT__
414938e4a01SJed Brown #define __FUNCT__ "SNESFASCreateCoarseVec"
415938e4a01SJed Brown /*@
416938e4a01SJed Brown    SNESFASCreateCoarseVec - create Vec corresponding to a state vector on one level coarser than current level
417938e4a01SJed Brown 
418938e4a01SJed Brown    Collective
419938e4a01SJed Brown 
420938e4a01SJed Brown    Input Arguments:
421938e4a01SJed Brown .  snes - SNESFAS
422938e4a01SJed Brown 
423938e4a01SJed Brown    Output Arguments:
424938e4a01SJed Brown .  Xcoarse - vector on level one coarser than snes
425938e4a01SJed Brown 
426938e4a01SJed Brown    Level: developer
427938e4a01SJed Brown 
428938e4a01SJed Brown .seealso: SNESFASSetRestriction(), SNESFASRestrict()
429938e4a01SJed Brown @*/
430938e4a01SJed Brown PetscErrorCode SNESFASCreateCoarseVec(SNES snes,Vec *Xcoarse)
431938e4a01SJed Brown {
432938e4a01SJed Brown   PetscErrorCode ierr;
433938e4a01SJed Brown   SNES_FAS       *fas = (SNES_FAS*)snes->data;
434938e4a01SJed Brown 
435938e4a01SJed Brown   PetscFunctionBegin;
436938e4a01SJed Brown   if (fas->rscale) {ierr = VecDuplicate(fas->rscale,Xcoarse);CHKERRQ(ierr);}
437938e4a01SJed Brown   else if (fas->inject) {ierr = MatGetVecs(fas->inject,Xcoarse,PETSC_NULL);CHKERRQ(ierr);}
438938e4a01SJed Brown   else SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must set restriction or injection");CHKERRQ(ierr);
439938e4a01SJed Brown   PetscFunctionReturn(0);
440938e4a01SJed Brown }
441938e4a01SJed Brown 
442e9923e8dSJed Brown #undef __FUNCT__
443e9923e8dSJed Brown #define __FUNCT__ "SNESFASRestrict"
444e9923e8dSJed Brown /*@
445e9923e8dSJed Brown    SNESFASRestrict - restrict a Vec to the next coarser level
446e9923e8dSJed Brown 
447e9923e8dSJed Brown    Collective
448e9923e8dSJed Brown 
449e9923e8dSJed Brown    Input Arguments:
450e9923e8dSJed Brown +  fine - SNES from which to restrict
451e9923e8dSJed Brown -  Xfine - vector to restrict
452e9923e8dSJed Brown 
453e9923e8dSJed Brown    Output Arguments:
454e9923e8dSJed Brown .  Xcoarse - result of restriction
455e9923e8dSJed Brown 
456e9923e8dSJed Brown    Level: developer
457e9923e8dSJed Brown 
458e9923e8dSJed Brown .seealso: SNESFASSetRestriction(), SNESFASSetInjection()
459e9923e8dSJed Brown @*/
460e9923e8dSJed Brown PetscErrorCode SNESFASRestrict(SNES fine,Vec Xfine,Vec Xcoarse)
461e9923e8dSJed Brown {
462e9923e8dSJed Brown   PetscErrorCode ierr;
463e9923e8dSJed Brown   SNES_FAS       *fas = (SNES_FAS*)fine->data;
464e9923e8dSJed Brown 
465e9923e8dSJed Brown   PetscFunctionBegin;
466e9923e8dSJed Brown   PetscValidHeaderSpecific(fine,SNES_CLASSID,1);
467e9923e8dSJed Brown   PetscValidHeaderSpecific(Xfine,VEC_CLASSID,2);
468e9923e8dSJed Brown   PetscValidHeaderSpecific(Xcoarse,VEC_CLASSID,3);
469e9923e8dSJed Brown   if (fas->inject) {
470e9923e8dSJed Brown     ierr = MatRestrict(fas->inject,Xfine,Xcoarse);CHKERRQ(ierr);
471e9923e8dSJed Brown   } else {
472e9923e8dSJed Brown     ierr = MatRestrict(fas->restrct,Xfine,Xcoarse);CHKERRQ(ierr);
473e9923e8dSJed Brown     ierr = VecPointwiseMult(Xcoarse,fas->rscale,Xcoarse);CHKERRQ(ierr);
474e9923e8dSJed Brown   }
475e9923e8dSJed Brown   PetscFunctionReturn(0);
476e9923e8dSJed Brown }
477e9923e8dSJed Brown 
478e9923e8dSJed Brown #undef __FUNCT__
47939bd7f45SPeter Brune #define __FUNCT__ "FASCoarseCorrection"
48039bd7f45SPeter Brune /*
48139bd7f45SPeter Brune 
48239bd7f45SPeter Brune Performs the FAS coarse correction as:
48339bd7f45SPeter Brune 
48439bd7f45SPeter Brune fine problem: F(x) = 0
48539bd7f45SPeter Brune coarse problem: F^c(x) = b^c
48639bd7f45SPeter Brune 
48739bd7f45SPeter Brune b^c = F^c(I^c_fx^f - I^c_fF(x))
48839bd7f45SPeter Brune 
48939bd7f45SPeter Brune  */
49039a4b097SPeter Brune PetscErrorCode FASCoarseCorrection(SNES snes, Vec X, Vec F, Vec X_new) {
49139bd7f45SPeter Brune   PetscErrorCode      ierr;
49239bd7f45SPeter Brune   Vec                 X_c, Xo_c, F_c, B_c;
49339bd7f45SPeter Brune   SNESConvergedReason reason;
494ab8d36c9SPeter Brune   SNES                next;
495ab8d36c9SPeter Brune   Mat                 restrct, interpolate;
49639bd7f45SPeter Brune   PetscFunctionBegin;
497ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
498ab8d36c9SPeter Brune   if (next) {
499ab8d36c9SPeter Brune     ierr = SNESFASCycleGetRestriction(snes, &restrct);CHKERRQ(ierr);
500ab8d36c9SPeter Brune     ierr = SNESFASCycleGetInterpolation(snes, &interpolate);CHKERRQ(ierr);
501ab8d36c9SPeter Brune 
502ab8d36c9SPeter Brune     X_c  = next->vec_sol;
503ab8d36c9SPeter Brune     Xo_c = next->work[0];
504ab8d36c9SPeter Brune     F_c  = next->vec_func;
505ab8d36c9SPeter Brune     B_c  = next->vec_rhs;
506efe1f98aSPeter Brune 
507938e4a01SJed Brown     ierr = SNESFASRestrict(snes,X,Xo_c);CHKERRQ(ierr);
508293a7e31SPeter Brune     ierr = VecScale(F, -1.0);CHKERRQ(ierr);
509293a7e31SPeter Brune 
510293a7e31SPeter Brune     /* restrict the defect */
511ab8d36c9SPeter Brune     ierr = MatRestrict(restrct, F, B_c);CHKERRQ(ierr);
512293a7e31SPeter Brune 
513c90fad12SPeter Brune     /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */
514ab8d36c9SPeter Brune     next->vec_rhs = PETSC_NULL;                                           /*unset the RHS to evaluate function instead of residual*/
515ab8d36c9SPeter Brune     ierr = SNESComputeFunction(next, Xo_c, F_c);CHKERRQ(ierr);
516742fe5e2SPeter Brune 
517293a7e31SPeter Brune     ierr = VecAXPY(B_c, 1.0, F_c);CHKERRQ(ierr);                               /* add F_c(X) to the RHS */
518c90fad12SPeter Brune 
519ee78dd50SPeter Brune     /* set initial guess of the coarse problem to the projected fine solution */
520ee78dd50SPeter Brune     ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr);
521c90fad12SPeter Brune 
522c90fad12SPeter Brune     /* recurse to the next level */
523ab8d36c9SPeter Brune     next->vec_rhs = B_c;
524ab8d36c9SPeter Brune     ierr = SNESSolve(next, B_c, X_c);CHKERRQ(ierr);
525ab8d36c9SPeter Brune     ierr = SNESGetConvergedReason(next,&reason);CHKERRQ(ierr);
526742fe5e2SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
527742fe5e2SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
528742fe5e2SPeter Brune       PetscFunctionReturn(0);
529742fe5e2SPeter Brune     }
530ee78dd50SPeter Brune 
531fa9694d7SPeter Brune     /* correct as x <- x + I(x^c - Rx)*/
532fa9694d7SPeter Brune     ierr = VecAXPY(X_c, -1.0, Xo_c);CHKERRQ(ierr);
533ab8d36c9SPeter Brune     ierr = MatInterpolateAdd(interpolate, X_c, X, X_new);CHKERRQ(ierr);
534293a7e31SPeter Brune   }
53539bd7f45SPeter Brune   PetscFunctionReturn(0);
53639bd7f45SPeter Brune }
53739bd7f45SPeter Brune 
53839bd7f45SPeter Brune #undef __FUNCT__
53939bd7f45SPeter Brune #define __FUNCT__ "FASCycle_Additive"
54039bd7f45SPeter Brune /*
54139bd7f45SPeter Brune 
54239bd7f45SPeter Brune The additive cycle looks like:
54339bd7f45SPeter Brune 
54407144faaSPeter Brune xhat = x
54507144faaSPeter Brune xhat = dS(x, b)
54607144faaSPeter Brune x = coarsecorrection(xhat, b_d)
54707144faaSPeter Brune x = x + nu*(xhat - x);
54839bd7f45SPeter Brune (optional) x = uS(x, b)
54939bd7f45SPeter Brune 
55039bd7f45SPeter Brune With the coarse RHS (defect correction) as below.
55139bd7f45SPeter Brune 
55239bd7f45SPeter Brune  */
55339bd7f45SPeter Brune PetscErrorCode FASCycle_Additive(SNES snes, Vec X) {
55407144faaSPeter Brune   Vec                 F, B, Xhat;
55522c1e704SPeter Brune   Vec                 X_c, Xo_c, F_c, B_c;
55639bd7f45SPeter Brune   PetscErrorCode      ierr;
55707144faaSPeter Brune   SNESConvergedReason reason;
55822c1e704SPeter Brune   PetscReal           xnorm, fnorm, ynorm;
55922c1e704SPeter Brune   PetscBool           lssuccess;
560ab8d36c9SPeter Brune   SNES                next;
561ab8d36c9SPeter Brune   Mat                 restrct, interpolate;
56239bd7f45SPeter Brune   PetscFunctionBegin;
563ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
56439bd7f45SPeter Brune   F = snes->vec_func;
56539bd7f45SPeter Brune   B = snes->vec_rhs;
566fde0ff24SPeter Brune   Xhat = snes->work[3];
56707144faaSPeter Brune   ierr = VecCopy(X, Xhat);CHKERRQ(ierr);
56807144faaSPeter Brune   /* recurse first */
569ab8d36c9SPeter Brune   if (next) {
570ab8d36c9SPeter Brune     ierr = SNESFASCycleGetRestriction(snes, &restrct);CHKERRQ(ierr);
571ab8d36c9SPeter Brune     ierr = SNESFASCycleGetInterpolation(snes, &interpolate);CHKERRQ(ierr);
57207144faaSPeter Brune     ierr = SNESComputeFunction(snes, Xhat, F);CHKERRQ(ierr);
57339bd7f45SPeter Brune 
574ab8d36c9SPeter Brune     X_c  = next->vec_sol;
575ab8d36c9SPeter Brune     Xo_c = next->work[0];
576ab8d36c9SPeter Brune     F_c  = next->vec_func;
577ab8d36c9SPeter Brune     B_c  = next->vec_rhs;
57839bd7f45SPeter Brune 
579938e4a01SJed Brown     ierr = SNESFASRestrict(snes,Xhat,Xo_c);CHKERRQ(ierr);
58007144faaSPeter Brune     ierr = VecScale(F, -1.0);CHKERRQ(ierr);
58107144faaSPeter Brune 
58207144faaSPeter Brune     /* restrict the defect */
583ab8d36c9SPeter Brune     ierr = MatRestrict(restrct, F, B_c);CHKERRQ(ierr);
58407144faaSPeter Brune 
58507144faaSPeter Brune     /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */
586ab8d36c9SPeter Brune     next->vec_rhs = PETSC_NULL;                                           /*unset the RHS to evaluate function instead of residual*/
587ab8d36c9SPeter Brune     ierr = SNESComputeFunction(next, Xo_c, F_c);CHKERRQ(ierr);
58807144faaSPeter Brune 
58907144faaSPeter Brune     ierr = VecAXPY(B_c, 1.0, F_c);CHKERRQ(ierr);                               /* add F_c(X) to the RHS */
59007144faaSPeter Brune 
59107144faaSPeter Brune     /* set initial guess of the coarse problem to the projected fine solution */
59207144faaSPeter Brune     ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr);
59307144faaSPeter Brune 
59407144faaSPeter Brune     /* recurse */
595ab8d36c9SPeter Brune     next->vec_rhs = B_c;
596ab8d36c9SPeter Brune     ierr = SNESSolve(next, B_c, X_c);CHKERRQ(ierr);
59707144faaSPeter Brune 
59807144faaSPeter Brune     /* smooth on this level */
59907144faaSPeter Brune     ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr);
60007144faaSPeter Brune 
601ab8d36c9SPeter Brune     ierr = SNESGetConvergedReason(next,&reason);CHKERRQ(ierr);
60207144faaSPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
60307144faaSPeter Brune       snes->reason = SNES_DIVERGED_INNER;
60407144faaSPeter Brune       PetscFunctionReturn(0);
60507144faaSPeter Brune     }
60607144faaSPeter Brune 
60707144faaSPeter Brune     /* correct as x <- x + I(x^c - Rx)*/
608c68acad4SPeter Brune     ierr = VecAYPX(X_c, -1.0, Xo_c);CHKERRQ(ierr);
609ab8d36c9SPeter Brune     ierr = MatInterpolate(interpolate, X_c, Xhat);CHKERRQ(ierr);
61007144faaSPeter Brune 
611ddebd997SPeter Brune     /* additive correction of the coarse direction*/
612ddebd997SPeter Brune     ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
613ddebd997SPeter Brune     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
614f1c6b773SPeter Brune     ierr = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Xhat);CHKERRQ(ierr);
615f1c6b773SPeter Brune     ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssuccess);CHKERRQ(ierr);
6169e764e56SPeter Brune     if (!lssuccess) {
6179e764e56SPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
6189e764e56SPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
6199e764e56SPeter Brune         PetscFunctionReturn(0);
6209e764e56SPeter Brune       }
6219e764e56SPeter Brune     }
622f1c6b773SPeter Brune     ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
62307144faaSPeter Brune   } else {
62407144faaSPeter Brune     ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr);
62507144faaSPeter Brune   }
62639bd7f45SPeter Brune   PetscFunctionReturn(0);
62739bd7f45SPeter Brune }
62839bd7f45SPeter Brune 
62939bd7f45SPeter Brune #undef __FUNCT__
63039bd7f45SPeter Brune #define __FUNCT__ "FASCycle_Multiplicative"
63139bd7f45SPeter Brune /*
63239bd7f45SPeter Brune 
63339bd7f45SPeter Brune Defines the FAS cycle as:
63439bd7f45SPeter Brune 
63539bd7f45SPeter Brune fine problem: F(x) = 0
63639bd7f45SPeter Brune coarse problem: F^c(x) = b^c
63739bd7f45SPeter Brune 
63839bd7f45SPeter Brune b^c = F^c(I^c_fx^f - I^c_fF(x))
63939bd7f45SPeter Brune 
64039bd7f45SPeter Brune correction:
64139bd7f45SPeter Brune 
64239bd7f45SPeter Brune x = x + I(x^c - Rx)
64339bd7f45SPeter Brune 
64439bd7f45SPeter Brune  */
64539bd7f45SPeter Brune PetscErrorCode FASCycle_Multiplicative(SNES snes, Vec X) {
64639bd7f45SPeter Brune 
64739bd7f45SPeter Brune   PetscErrorCode      ierr;
64839bd7f45SPeter Brune   Vec                 F,B;
64939bd7f45SPeter Brune   SNES_FAS            *fas = (SNES_FAS *)snes->data;
65039bd7f45SPeter Brune 
65139bd7f45SPeter Brune   PetscFunctionBegin;
65239bd7f45SPeter Brune   F = snes->vec_func;
65339bd7f45SPeter Brune   B = snes->vec_rhs;
65439bd7f45SPeter Brune   /* pre-smooth -- just update using the pre-smoother */
65539bd7f45SPeter Brune   ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr);
65639bd7f45SPeter Brune 
657c90fad12SPeter Brune   if (fas->level != 0) {
658e70c42e5SPeter Brune     ierr = FASCoarseCorrection(snes, X, F, X);CHKERRQ(ierr);
65939bd7f45SPeter Brune     ierr = FASUpSmooth(snes, B, X, F);CHKERRQ(ierr);
660fe6f9142SPeter Brune   }
661fa9694d7SPeter Brune   PetscFunctionReturn(0);
662421d9b32SPeter Brune }
663421d9b32SPeter Brune 
664421d9b32SPeter Brune #undef __FUNCT__
665421d9b32SPeter Brune #define __FUNCT__ "SNESSolve_FAS"
666421d9b32SPeter Brune 
667421d9b32SPeter Brune PetscErrorCode SNESSolve_FAS(SNES snes)
668421d9b32SPeter Brune {
669fa9694d7SPeter Brune   PetscErrorCode ierr;
670fe6f9142SPeter Brune   PetscInt       i, maxits;
671ddb5aff1SPeter Brune   Vec            X, F;
672fe6f9142SPeter Brune   PetscReal      fnorm;
673b17ce1afSJed Brown   SNES_FAS       *fas = (SNES_FAS *)snes->data,*ffas;
674b17ce1afSJed Brown   DM             dm;
675e70c42e5SPeter Brune   PetscBool      isFine;
676b17ce1afSJed Brown 
677421d9b32SPeter Brune   PetscFunctionBegin;
678fe6f9142SPeter Brune   maxits = snes->max_its;            /* maximum number of iterations */
679fe6f9142SPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
680fa9694d7SPeter Brune   X = snes->vec_sol;
681f5a6d4f9SBarry Smith   F = snes->vec_func;
682293a7e31SPeter Brune 
68318a66777SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
684293a7e31SPeter Brune   /*norm setup */
685fe6f9142SPeter Brune   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
686fe6f9142SPeter Brune   snes->iter = 0;
687fe6f9142SPeter Brune   snes->norm = 0.;
688fe6f9142SPeter Brune   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
68918a66777SPeter Brune   if (isFine || fas->monitor) {
690fe6f9142SPeter Brune     ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
691fe6f9142SPeter Brune     if (snes->domainerror) {
692fe6f9142SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
693fe6f9142SPeter Brune       PetscFunctionReturn(0);
694fe6f9142SPeter Brune     }
695fe6f9142SPeter Brune     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
696fe6f9142SPeter Brune     if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm");
697fe6f9142SPeter Brune     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
698fe6f9142SPeter Brune     snes->norm = fnorm;
699fe6f9142SPeter Brune     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
700fe6f9142SPeter Brune     SNESLogConvHistory(snes,fnorm,0);
701fe6f9142SPeter Brune     ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
702fe6f9142SPeter Brune 
703fe6f9142SPeter Brune     /* set parameter for default relative tolerance convergence test */
704fe6f9142SPeter Brune     snes->ttol = fnorm*snes->rtol;
705fe6f9142SPeter Brune     /* test convergence */
706fe6f9142SPeter Brune     ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
707fe6f9142SPeter Brune     if (snes->reason) PetscFunctionReturn(0);
70866585501SPeter Brune   }
709b17ce1afSJed Brown 
710b17ce1afSJed Brown   ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
711b17ce1afSJed Brown   for (ffas=fas; ffas->next; ffas=(SNES_FAS*)ffas->next->data) {
712b17ce1afSJed Brown     DM dmcoarse;
713b17ce1afSJed Brown     ierr = SNESGetDM(ffas->next,&dmcoarse);CHKERRQ(ierr);
714b17ce1afSJed Brown     ierr = DMRestrict(dm,ffas->restrct,ffas->rscale,ffas->inject,dmcoarse);CHKERRQ(ierr);
715b17ce1afSJed Brown     dm = dmcoarse;
716b17ce1afSJed Brown   }
717b17ce1afSJed Brown 
718fe6f9142SPeter Brune   for (i = 0; i < maxits; i++) {
719fe6f9142SPeter Brune     /* Call general purpose update function */
720646217ecSPeter Brune 
721fe6f9142SPeter Brune     if (snes->ops->update) {
722fe6f9142SPeter Brune       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
723fe6f9142SPeter Brune     }
72407144faaSPeter Brune     if (fas->fastype == SNES_FAS_MULTIPLICATIVE) {
72539bd7f45SPeter Brune       ierr = FASCycle_Multiplicative(snes, X);CHKERRQ(ierr);
72607144faaSPeter Brune     } else {
72707144faaSPeter Brune       ierr = FASCycle_Additive(snes, X);CHKERRQ(ierr);
72807144faaSPeter Brune     }
729742fe5e2SPeter Brune 
730742fe5e2SPeter Brune     /* check for FAS cycle divergence */
731742fe5e2SPeter Brune     if (snes->reason != SNES_CONVERGED_ITERATING) {
732742fe5e2SPeter Brune       PetscFunctionReturn(0);
733742fe5e2SPeter Brune     }
734e70c42e5SPeter Brune     if (isFine || fas->monitor) {
735c90fad12SPeter Brune       ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
736e70c42e5SPeter Brune     }
737c90fad12SPeter Brune     /* Monitor convergence */
738c90fad12SPeter Brune     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
739c90fad12SPeter Brune     snes->iter = i+1;
740c90fad12SPeter Brune     snes->norm = fnorm;
741c90fad12SPeter Brune     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
742c90fad12SPeter Brune     SNESLogConvHistory(snes,snes->norm,0);
743c90fad12SPeter Brune     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
744c90fad12SPeter Brune     /* Test for convergence */
74566585501SPeter Brune     if (isFine) {
746c90fad12SPeter Brune       ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
747c90fad12SPeter Brune       if (snes->reason) break;
748fe6f9142SPeter Brune     }
74966585501SPeter Brune   }
750fe6f9142SPeter Brune   if (i == maxits) {
751fe6f9142SPeter Brune     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr);
752fe6f9142SPeter Brune     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
753fe6f9142SPeter Brune   }
754421d9b32SPeter Brune   PetscFunctionReturn(0);
755421d9b32SPeter Brune }
756