xref: /petsc/src/snes/impls/fas/fas.c (revision 3dccd265b4a2bee9c2b3da7cb6ddba34177af58c)
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 /*MC
7ef536925SPeter Brune 
8ef536925SPeter Brune SNESFAS - Full Approximation Scheme nonlinear multigrid solver.
9421d9b32SPeter Brune 
10421d9b32SPeter Brune The nonlinear problem is solved via the repeated application of nonlinear preconditioners and coarse-grid corrections
11421d9b32SPeter Brune 
12421d9b32SPeter Brune .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
13421d9b32SPeter Brune M*/
14421d9b32SPeter Brune 
15421d9b32SPeter Brune extern PetscErrorCode SNESDestroy_FAS(SNES snes);
16421d9b32SPeter Brune extern PetscErrorCode SNESSetUp_FAS(SNES snes);
17421d9b32SPeter Brune extern PetscErrorCode SNESSetFromOptions_FAS(SNES snes);
18421d9b32SPeter Brune extern PetscErrorCode SNESView_FAS(SNES snes, PetscViewer viewer);
19421d9b32SPeter Brune extern PetscErrorCode SNESSolve_FAS(SNES snes);
20421d9b32SPeter Brune extern PetscErrorCode SNESReset_FAS(SNES snes);
216273346dSPeter Brune extern PetscErrorCode SNESFASGalerkinDefaultFunction(SNES, Vec, Vec, void *);
22421d9b32SPeter Brune 
23421d9b32SPeter Brune EXTERN_C_BEGIN
24ddebd997SPeter Brune #undef __FUNCT__
25ddebd997SPeter Brune #define __FUNCT__ "SNESLineSearchSetType_FAS"
26ddebd997SPeter Brune PetscErrorCode  SNESLineSearchSetType_FAS(SNES snes, SNESLineSearchType type)
27ddebd997SPeter Brune {
28ddebd997SPeter Brune   PetscErrorCode ierr;
29ddebd997SPeter Brune   PetscFunctionBegin;
30ddebd997SPeter Brune 
31ddebd997SPeter Brune   switch (type) {
32ddebd997SPeter Brune   case SNES_LS_BASIC:
33ddebd997SPeter Brune     ierr = SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);CHKERRQ(ierr);
34ddebd997SPeter Brune     break;
35ddebd997SPeter Brune   case SNES_LS_BASIC_NONORMS:
36ddebd997SPeter Brune     ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr);
37ddebd997SPeter Brune     break;
38ddebd997SPeter Brune   case SNES_LS_QUADRATIC:
39ddebd997SPeter Brune     ierr = SNESLineSearchSet(snes,SNESLineSearchQuadraticSecant,PETSC_NULL);CHKERRQ(ierr);
40ddebd997SPeter Brune     break;
41ddebd997SPeter Brune   default:
42ddebd997SPeter Brune     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP,"Unknown line search type.");
43ddebd997SPeter Brune     break;
44ddebd997SPeter Brune   }
45ddebd997SPeter Brune   snes->ls_type = type;
46ddebd997SPeter Brune   PetscFunctionReturn(0);
47ddebd997SPeter Brune }
48ddebd997SPeter Brune EXTERN_C_END
49ddebd997SPeter Brune 
50ddebd997SPeter Brune EXTERN_C_BEGIN
51421d9b32SPeter Brune 
52421d9b32SPeter Brune #undef __FUNCT__
53421d9b32SPeter Brune #define __FUNCT__ "SNESCreate_FAS"
54421d9b32SPeter Brune PetscErrorCode SNESCreate_FAS(SNES snes)
55421d9b32SPeter Brune {
56421d9b32SPeter Brune   SNES_FAS * fas;
57421d9b32SPeter Brune   PetscErrorCode ierr;
58421d9b32SPeter Brune 
59421d9b32SPeter Brune   PetscFunctionBegin;
60421d9b32SPeter Brune   snes->ops->destroy        = SNESDestroy_FAS;
61421d9b32SPeter Brune   snes->ops->setup          = SNESSetUp_FAS;
62421d9b32SPeter Brune   snes->ops->setfromoptions = SNESSetFromOptions_FAS;
63421d9b32SPeter Brune   snes->ops->view           = SNESView_FAS;
64421d9b32SPeter Brune   snes->ops->solve          = SNESSolve_FAS;
65421d9b32SPeter Brune   snes->ops->reset          = SNESReset_FAS;
66421d9b32SPeter Brune 
67ed020824SBarry Smith   snes->usesksp             = PETSC_FALSE;
68ed020824SBarry Smith   snes->usespc              = PETSC_FALSE;
69ed020824SBarry Smith 
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;
77ee78dd50SPeter Brune   fas->upsmooth               = PETSC_NULL;
78ee78dd50SPeter Brune   fas->downsmooth             = PETSC_NULL;
79421d9b32SPeter Brune   fas->next                   = PETSC_NULL;
806273346dSPeter Brune   fas->previous               = PETSC_NULL;
81421d9b32SPeter Brune   fas->interpolate            = PETSC_NULL;
82421d9b32SPeter Brune   fas->restrct                = PETSC_NULL;
83efe1f98aSPeter Brune   fas->inject                 = PETSC_NULL;
84cc05f883SPeter Brune   fas->monitor                = PETSC_NULL;
85cc05f883SPeter Brune   fas->usedmfornumberoflevels = PETSC_FALSE;
86ddebd997SPeter Brune   fas->fastype                = SNES_FAS_MULTIPLICATIVE;
87ddebd997SPeter Brune 
88ddebd997SPeter Brune   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetType_C","SNESLineSearchSetType_FAS",SNESLineSearchSetType_FAS);CHKERRQ(ierr);
89ddebd997SPeter Brune   ierr = SNESLineSearchSetType(snes, SNES_LS_QUADRATIC);CHKERRQ(ierr);
90ddebd997SPeter Brune 
91421d9b32SPeter Brune   PetscFunctionReturn(0);
92421d9b32SPeter Brune }
93421d9b32SPeter Brune EXTERN_C_END
94421d9b32SPeter Brune 
95421d9b32SPeter Brune #undef __FUNCT__
96421d9b32SPeter Brune #define __FUNCT__ "SNESFASGetLevels"
97c79ef259SPeter Brune /*@
98722262beSPeter Brune    SNESFASGetLevels - Gets the number of levels in a FAS.
99c79ef259SPeter Brune 
100c79ef259SPeter Brune    Input Parameter:
101c79ef259SPeter Brune .  snes - the preconditioner context
102c79ef259SPeter Brune 
103c79ef259SPeter Brune    Output parameter:
104c79ef259SPeter Brune .  levels - the number of levels
105c79ef259SPeter Brune 
106c79ef259SPeter Brune    Level: advanced
107c79ef259SPeter Brune 
108c79ef259SPeter Brune .keywords: MG, get, levels, multigrid
109c79ef259SPeter Brune 
110c79ef259SPeter Brune .seealso: SNESFASSetLevels(), PCMGGetLevels()
111c79ef259SPeter Brune @*/
112421d9b32SPeter Brune PetscErrorCode SNESFASGetLevels(SNES snes, PetscInt * levels) {
113421d9b32SPeter Brune   SNES_FAS * fas = (SNES_FAS *)snes->data;
114421d9b32SPeter Brune   PetscFunctionBegin;
115ee1fd11aSPeter Brune   *levels = fas->levels;
116421d9b32SPeter Brune   PetscFunctionReturn(0);
117421d9b32SPeter Brune }
118421d9b32SPeter Brune 
119421d9b32SPeter Brune #undef __FUNCT__
120646217ecSPeter Brune #define __FUNCT__ "SNESFASSetCycles"
121c79ef259SPeter Brune /*@
122c79ef259SPeter Brune    SNESFASSetCycles - Sets the type cycles to use.  Use SNESFASSetCyclesOnLevel() for more
123c79ef259SPeter Brune    complicated cycling.
124c79ef259SPeter Brune 
125c79ef259SPeter Brune    Logically Collective on SNES
126c79ef259SPeter Brune 
127c79ef259SPeter Brune    Input Parameters:
128c79ef259SPeter Brune +  snes   - the multigrid context
129c79ef259SPeter Brune -  cycles - the number of cycles -- 1 for V-cycle, 2 for W-cycle
130c79ef259SPeter Brune 
131c79ef259SPeter Brune    Options Database Key:
132c79ef259SPeter Brune $  -snes_fas_cycles 1 or 2
133c79ef259SPeter Brune 
134c79ef259SPeter Brune    Level: advanced
135c79ef259SPeter Brune 
136c79ef259SPeter Brune .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
137c79ef259SPeter Brune 
138c79ef259SPeter Brune .seealso: SNESFASSetCyclesOnLevel()
139c79ef259SPeter Brune @*/
140646217ecSPeter Brune PetscErrorCode SNESFASSetCycles(SNES snes, PetscInt cycles) {
141646217ecSPeter Brune   SNES_FAS * fas = (SNES_FAS *)snes->data;
142646217ecSPeter Brune   PetscErrorCode ierr;
143646217ecSPeter Brune   PetscFunctionBegin;
144646217ecSPeter Brune   fas->n_cycles = cycles;
145646217ecSPeter Brune   if (fas->next) {
146646217ecSPeter Brune     ierr = SNESFASSetCycles(fas->next, cycles);CHKERRQ(ierr);
147646217ecSPeter Brune   }
148646217ecSPeter Brune   PetscFunctionReturn(0);
149646217ecSPeter Brune }
150646217ecSPeter Brune 
151eff52c0eSPeter Brune #undef __FUNCT__
152c79ef259SPeter Brune #define __FUNCT__ "SNESFASSetCyclesOnLevel"
153c79ef259SPeter Brune /*@
154722262beSPeter Brune    SNESFASSetCyclesOnLevel - Sets the type cycles to use on a particular level.
155c79ef259SPeter Brune 
156c79ef259SPeter Brune    Logically Collective on SNES
157c79ef259SPeter Brune 
158c79ef259SPeter Brune    Input Parameters:
159c79ef259SPeter Brune +  snes   - the multigrid context
160c79ef259SPeter Brune .  level  - the level to set the number of cycles on
161c79ef259SPeter Brune -  cycles - the number of cycles -- 1 for V-cycle, 2 for W-cycle
162c79ef259SPeter Brune 
163c79ef259SPeter Brune    Level: advanced
164c79ef259SPeter Brune 
165c79ef259SPeter Brune .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
166c79ef259SPeter Brune 
167c79ef259SPeter Brune .seealso: SNESFASSetCycles()
168c79ef259SPeter Brune @*/
169c79ef259SPeter Brune PetscErrorCode SNESFASSetCyclesOnLevel(SNES snes, PetscInt level, PetscInt cycles) {
170c79ef259SPeter Brune   SNES_FAS * fas =  (SNES_FAS *)snes->data;
171c79ef259SPeter Brune   PetscInt top_level = fas->level,i;
172c79ef259SPeter Brune 
173c79ef259SPeter Brune   PetscFunctionBegin;
174c79ef259SPeter Brune   if (level > top_level)
175c79ef259SPeter Brune     SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetCyclesOnLevel", level);
176c79ef259SPeter Brune   /* get to the correct level */
177c79ef259SPeter Brune   for (i = fas->level; i > level; i--) {
178c79ef259SPeter Brune     fas = (SNES_FAS *)fas->next->data;
179c79ef259SPeter Brune   }
180c79ef259SPeter Brune   if (fas->level != level)
181c79ef259SPeter Brune     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetCyclesOnLevel");
182c79ef259SPeter Brune   fas->n_cycles = cycles;
183c79ef259SPeter Brune   PetscFunctionReturn(0);
184c79ef259SPeter Brune }
185c79ef259SPeter Brune 
186c79ef259SPeter Brune #undef __FUNCT__
187eff52c0eSPeter Brune #define __FUNCT__ "SNESFASSetGS"
188aeed3662SMatthew G Knepley /*@C
189c79ef259SPeter Brune    SNESFASSetGS - Sets a nonlinear GS smoother and if it should be used.
190c79ef259SPeter Brune    Use SNESFASSetGSOnLevel() for more complicated staging of smoothers
191c79ef259SPeter Brune    and nonlinear preconditioners.
192c79ef259SPeter Brune 
193c79ef259SPeter Brune    Logically Collective on SNES
194c79ef259SPeter Brune 
195c79ef259SPeter Brune    Input Parameters:
196c79ef259SPeter Brune +  snes    - the multigrid context
197c79ef259SPeter Brune .  gsfunc  - the nonlinear smoother function
198c79ef259SPeter Brune .  ctx     - the user context for the nonlinear smoother
199c79ef259SPeter Brune -  use_gs  - whether to use the nonlinear smoother or not
200c79ef259SPeter Brune 
201c79ef259SPeter Brune    Level: advanced
202c79ef259SPeter Brune 
203c79ef259SPeter Brune .keywords: FAS, MG, set, cycles, gauss-seidel, multigrid
204c79ef259SPeter Brune 
205c79ef259SPeter Brune .seealso: SNESSetGS(), SNESFASSetGSOnLevel()
206c79ef259SPeter Brune @*/
207eff52c0eSPeter Brune PetscErrorCode SNESFASSetGS(SNES snes, PetscErrorCode (*gsfunc)(SNES,Vec,Vec,void *), void * ctx, PetscBool use_gs) {
208eff52c0eSPeter Brune   PetscErrorCode ierr = 0;
209eff52c0eSPeter Brune   SNES_FAS       *fas = (SNES_FAS *)snes->data;
210eff52c0eSPeter Brune   PetscFunctionBegin;
211eff52c0eSPeter Brune 
212eff52c0eSPeter Brune   /* use or don't use it according to user wishes*/
213d28543b3SPeter Brune   snes->usegs = use_gs;
214eff52c0eSPeter Brune   if (gsfunc) {
215eff52c0eSPeter Brune     ierr = SNESSetGS(snes, gsfunc, ctx);CHKERRQ(ierr);
216eff52c0eSPeter Brune     /* push the provided GS up the tree */
217eff52c0eSPeter Brune     if (fas->next) ierr = SNESFASSetGS(fas->next, gsfunc, ctx, use_gs);CHKERRQ(ierr);
218eff52c0eSPeter Brune   } else if (snes->ops->computegs) {
219eff52c0eSPeter Brune     /* assume that the user has set the GS solver at this level */
220eff52c0eSPeter Brune     if (fas->next) ierr = SNESFASSetGS(fas->next, PETSC_NULL, PETSC_NULL, use_gs);CHKERRQ(ierr);
221eff52c0eSPeter Brune   } else if (use_gs) {
222eff52c0eSPeter Brune     SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "No user Gauss-Seidel function provided in SNESFASSetGS on level %d", fas->level);
223eff52c0eSPeter Brune   }
224eff52c0eSPeter Brune   PetscFunctionReturn(0);
225eff52c0eSPeter Brune }
226eff52c0eSPeter Brune 
227eff52c0eSPeter Brune #undef __FUNCT__
228eff52c0eSPeter Brune #define __FUNCT__ "SNESFASSetGSOnLevel"
229aeed3662SMatthew G Knepley /*@C
230c79ef259SPeter Brune    SNESFASSetGSOnLevel - Sets the nonlinear smoother on a particular level.
231c79ef259SPeter Brune 
232c79ef259SPeter Brune    Logically Collective on SNES
233c79ef259SPeter Brune 
234c79ef259SPeter Brune    Input Parameters:
235c79ef259SPeter Brune +  snes    - the multigrid context
236c79ef259SPeter Brune .  level   - the level to set the nonlinear smoother on
237c79ef259SPeter Brune .  gsfunc  - the nonlinear smoother function
238c79ef259SPeter Brune .  ctx     - the user context for the nonlinear smoother
239c79ef259SPeter Brune -  use_gs  - whether to use the nonlinear smoother or not
240c79ef259SPeter Brune 
241c79ef259SPeter Brune    Level: advanced
242c79ef259SPeter Brune 
243c79ef259SPeter Brune .keywords: FAS, MG, set, cycles, Gauss-Seidel, multigrid
244c79ef259SPeter Brune 
245c79ef259SPeter Brune .seealso: SNESSetGS(), SNESFASSetGS()
246c79ef259SPeter Brune @*/
247eff52c0eSPeter Brune PetscErrorCode SNESFASSetGSOnLevel(SNES snes, PetscInt level, PetscErrorCode (*gsfunc)(SNES,Vec,Vec,void *), void * ctx, PetscBool use_gs) {
248eff52c0eSPeter Brune   SNES_FAS       *fas =  (SNES_FAS *)snes->data;
249eff52c0eSPeter Brune   PetscErrorCode ierr;
250eff52c0eSPeter Brune   PetscInt       top_level = fas->level,i;
251eff52c0eSPeter Brune   SNES           cur_snes = snes;
252eff52c0eSPeter Brune   PetscFunctionBegin;
253eff52c0eSPeter Brune   if (level > top_level)
254eff52c0eSPeter Brune     SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetCyclesOnLevel", level);
255eff52c0eSPeter Brune   /* get to the correct level */
256eff52c0eSPeter Brune   for (i = fas->level; i > level; i--) {
257eff52c0eSPeter Brune     fas = (SNES_FAS *)fas->next->data;
258eff52c0eSPeter Brune     cur_snes = fas->next;
259eff52c0eSPeter Brune   }
260eff52c0eSPeter Brune   if (fas->level != level)
261eff52c0eSPeter Brune     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetCyclesOnLevel");
262d28543b3SPeter Brune   snes->usegs = use_gs;
263eff52c0eSPeter Brune   if (gsfunc) {
2646273346dSPeter Brune     ierr = SNESSetGS(cur_snes, gsfunc, ctx);CHKERRQ(ierr);
265eff52c0eSPeter Brune   }
266eff52c0eSPeter Brune   PetscFunctionReturn(0);
267eff52c0eSPeter Brune }
268eff52c0eSPeter Brune 
269646217ecSPeter Brune #undef __FUNCT__
270421d9b32SPeter Brune #define __FUNCT__ "SNESFASGetSNES"
271c79ef259SPeter Brune /*@
272c79ef259SPeter Brune    SNESFASGetSNES - Gets the SNES corresponding to a particular
273c79ef259SPeter Brune    level of the FAS hierarchy.
274c79ef259SPeter Brune 
275c79ef259SPeter Brune    Input Parameters:
276c79ef259SPeter Brune +  snes    - the multigrid context
277c79ef259SPeter Brune    level   - the level to get
278c79ef259SPeter Brune -  lsnes   - whether to use the nonlinear smoother or not
279c79ef259SPeter Brune 
280c79ef259SPeter Brune    Level: advanced
281c79ef259SPeter Brune 
282c79ef259SPeter Brune .keywords: FAS, MG, set, cycles, Gauss-Seidel, multigrid
283c79ef259SPeter Brune 
284c79ef259SPeter Brune .seealso: SNESFASSetLevels(), SNESFASGetLevels()
285c79ef259SPeter Brune @*/
286421d9b32SPeter Brune PetscErrorCode SNESFASGetSNES(SNES snes, PetscInt level, SNES * lsnes) {
287421d9b32SPeter Brune   SNES_FAS * fas = (SNES_FAS *)snes->data;
288421d9b32SPeter Brune   PetscInt levels = fas->level;
289421d9b32SPeter Brune   PetscInt i;
290421d9b32SPeter Brune   PetscFunctionBegin;
291421d9b32SPeter Brune   *lsnes = snes;
292421d9b32SPeter Brune   if (fas->level < level) {
293421d9b32SPeter Brune     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "SNESFASGetSNES should only be called on a finer SNESFAS instance than the level.");
294421d9b32SPeter Brune   }
295421d9b32SPeter Brune   if (level > levels - 1) {
296421d9b32SPeter Brune     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Level %d doesn't exist in the SNESFAS.");
297421d9b32SPeter Brune   }
298421d9b32SPeter Brune   for (i = fas->level; i > level; i--) {
299421d9b32SPeter Brune     *lsnes = fas->next;
300421d9b32SPeter Brune     fas = (SNES_FAS *)(*lsnes)->data;
301421d9b32SPeter Brune   }
302421d9b32SPeter Brune   if (fas->level != level) SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "SNESFASGetSNES didn't return the right level!");
303421d9b32SPeter Brune   PetscFunctionReturn(0);
304421d9b32SPeter Brune }
305421d9b32SPeter Brune 
306421d9b32SPeter Brune #undef __FUNCT__
30707144faaSPeter Brune #define __FUNCT__ "SNESFASSetType"
30807144faaSPeter Brune /*@
30907144faaSPeter Brune SNESFASSetType - Sets the update and correction type used for FAS.
31007144faaSPeter Brune e
31107144faaSPeter Brune 
31207144faaSPeter Brune 
31307144faaSPeter Brune @*/
31407144faaSPeter Brune PetscErrorCode  SNESFASSetType(SNES snes,SNESFASType fastype)
31507144faaSPeter Brune {
31607144faaSPeter Brune   SNES_FAS                   *fas = (SNES_FAS*)snes->data;
31707144faaSPeter Brune 
31807144faaSPeter Brune   PetscFunctionBegin;
31907144faaSPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
32007144faaSPeter Brune   PetscValidLogicalCollectiveEnum(snes,fastype,2);
32107144faaSPeter Brune   fas->fastype = fastype;
32207144faaSPeter Brune   PetscFunctionReturn(0);
32307144faaSPeter Brune }
32407144faaSPeter Brune 
32507144faaSPeter Brune 
32607144faaSPeter Brune 
32707144faaSPeter Brune #undef __FUNCT__
328421d9b32SPeter Brune #define __FUNCT__ "SNESFASSetLevels"
329aeed3662SMatthew G Knepley /*@C
330c79ef259SPeter Brune    SNESFASSetLevels - Sets the number of levels to use with FAS.
331c79ef259SPeter Brune    Must be called before any other FAS routine.
332c79ef259SPeter Brune 
333c79ef259SPeter Brune    Input Parameters:
334c79ef259SPeter Brune +  snes   - the snes context
335c79ef259SPeter Brune .  levels - the number of levels
336c79ef259SPeter Brune -  comms  - optional communicators for each level; this is to allow solving the coarser
337c79ef259SPeter Brune             problems on smaller sets of processors. Use PETSC_NULL_OBJECT for default in
338c79ef259SPeter Brune             Fortran.
339c79ef259SPeter Brune 
340c79ef259SPeter Brune    Level: intermediate
341c79ef259SPeter Brune 
342c79ef259SPeter Brune    Notes:
343c79ef259SPeter Brune      If the number of levels is one then the multigrid uses the -fas_levels prefix
344c79ef259SPeter Brune   for setting the level options rather than the -fas_coarse prefix.
345c79ef259SPeter Brune 
346c79ef259SPeter Brune .keywords: FAS, MG, set, levels, multigrid
347c79ef259SPeter Brune 
348c79ef259SPeter Brune .seealso: SNESFASGetLevels()
349c79ef259SPeter Brune @*/
350421d9b32SPeter Brune PetscErrorCode SNESFASSetLevels(SNES snes, PetscInt levels, MPI_Comm * comms) {
351421d9b32SPeter Brune   PetscErrorCode ierr;
352421d9b32SPeter Brune   PetscInt i;
353421d9b32SPeter Brune   SNES_FAS * fas = (SNES_FAS *)snes->data;
3546273346dSPeter Brune   SNES prevsnes;
355421d9b32SPeter Brune   MPI_Comm comm;
356421d9b32SPeter Brune   PetscFunctionBegin;
357ee1fd11aSPeter Brune   comm = ((PetscObject)snes)->comm;
358ee1fd11aSPeter Brune   if (levels == fas->levels) {
359ee1fd11aSPeter Brune     if (!comms)
360ee1fd11aSPeter Brune       PetscFunctionReturn(0);
361ee1fd11aSPeter Brune   }
362421d9b32SPeter Brune   /* user has changed the number of levels; reset */
363421d9b32SPeter Brune   ierr = SNESReset(snes);CHKERRQ(ierr);
364421d9b32SPeter Brune   /* destroy any coarser levels if necessary */
365421d9b32SPeter Brune   if (fas->next) SNESDestroy(&fas->next);CHKERRQ(ierr);
366ee1fd11aSPeter Brune   fas->next = PETSC_NULL;
3676273346dSPeter Brune   fas->previous = PETSC_NULL;
3686273346dSPeter Brune   prevsnes = snes;
369421d9b32SPeter Brune   /* setup the finest level */
370421d9b32SPeter Brune   for (i = levels - 1; i >= 0; i--) {
371421d9b32SPeter Brune     if (comms) comm = comms[i];
372421d9b32SPeter Brune     fas->level = i;
373421d9b32SPeter Brune     fas->levels = levels;
374ee1fd11aSPeter Brune     fas->next = PETSC_NULL;
375421d9b32SPeter Brune     if (i > 0) {
376421d9b32SPeter Brune       ierr = SNESCreate(comm, &fas->next);CHKERRQ(ierr);
3774a6b3fb8SBarry Smith       ierr = SNESSetOptionsPrefix(fas->next,((PetscObject)snes)->prefix);CHKERRQ(ierr);
378421d9b32SPeter Brune       ierr = SNESSetType(fas->next, SNESFAS);CHKERRQ(ierr);
379794bee33SPeter Brune       ierr = PetscObjectIncrementTabLevel((PetscObject)fas->next, (PetscObject)snes, levels - i);CHKERRQ(ierr);
3806273346dSPeter Brune       ((SNES_FAS *)fas->next->data)->previous = prevsnes;
3816273346dSPeter Brune       prevsnes = fas->next;
3826273346dSPeter Brune       fas = (SNES_FAS *)prevsnes->data;
383421d9b32SPeter Brune     }
384421d9b32SPeter Brune   }
385421d9b32SPeter Brune   PetscFunctionReturn(0);
386421d9b32SPeter Brune }
387421d9b32SPeter Brune 
388421d9b32SPeter Brune #undef __FUNCT__
389c79ef259SPeter Brune #define __FUNCT__ "SNESFASSetNumberSmoothUp"
390c79ef259SPeter Brune /*@
391c79ef259SPeter Brune    SNESFASSetNumberSmoothUp - Sets the number of post-smoothing steps to
392c79ef259SPeter Brune    use on all levels.
393c79ef259SPeter Brune 
394c79ef259SPeter Brune    Logically Collective on PC
395c79ef259SPeter Brune 
396c79ef259SPeter Brune    Input Parameters:
397c79ef259SPeter Brune +  snes - the multigrid context
398c79ef259SPeter Brune -  n    - the number of smoothing steps
399c79ef259SPeter Brune 
400c79ef259SPeter Brune    Options Database Key:
401d28543b3SPeter Brune .  -snes_fas_smoothup <n> - Sets number of pre-smoothing steps
402c79ef259SPeter Brune 
403c79ef259SPeter Brune    Level: advanced
404c79ef259SPeter Brune 
405c79ef259SPeter Brune .keywords: FAS, MG, smooth, down, pre-smoothing, steps, multigrid
406c79ef259SPeter Brune 
407c79ef259SPeter Brune .seealso: SNESFASSetNumberSmoothDown()
408c79ef259SPeter Brune @*/
409c79ef259SPeter Brune PetscErrorCode SNESFASSetNumberSmoothUp(SNES snes, PetscInt n) {
410c79ef259SPeter Brune   SNES_FAS * fas =  (SNES_FAS *)snes->data;
411c79ef259SPeter Brune   PetscErrorCode ierr = 0;
412c79ef259SPeter Brune   PetscFunctionBegin;
413c79ef259SPeter Brune   fas->max_up_it = n;
414c79ef259SPeter Brune   if (fas->next) {
415c79ef259SPeter Brune     ierr = SNESFASSetNumberSmoothUp(fas->next, n);CHKERRQ(ierr);
416c79ef259SPeter Brune   }
417c79ef259SPeter Brune   PetscFunctionReturn(0);
418c79ef259SPeter Brune }
419c79ef259SPeter Brune 
420c79ef259SPeter Brune #undef __FUNCT__
421c79ef259SPeter Brune #define __FUNCT__ "SNESFASSetNumberSmoothDown"
422c79ef259SPeter Brune /*@
423c79ef259SPeter Brune    SNESFASSetNumberSmoothDown - Sets the number of pre-smoothing steps to
424c79ef259SPeter Brune    use on all levels.
425c79ef259SPeter Brune 
426c79ef259SPeter Brune    Logically Collective on PC
427c79ef259SPeter Brune 
428c79ef259SPeter Brune    Input Parameters:
429c79ef259SPeter Brune +  snes - the multigrid context
430c79ef259SPeter Brune -  n    - the number of smoothing steps
431c79ef259SPeter Brune 
432c79ef259SPeter Brune    Options Database Key:
433d28543b3SPeter Brune .  -snes_fas_smoothdown <n> - Sets number of pre-smoothing steps
434c79ef259SPeter Brune 
435c79ef259SPeter Brune    Level: advanced
436c79ef259SPeter Brune 
437c79ef259SPeter Brune .keywords: FAS, MG, smooth, down, pre-smoothing, steps, multigrid
438c79ef259SPeter Brune 
439c79ef259SPeter Brune .seealso: SNESFASSetNumberSmoothUp()
440c79ef259SPeter Brune @*/
441c79ef259SPeter Brune PetscErrorCode SNESFASSetNumberSmoothDown(SNES snes, PetscInt n) {
442c79ef259SPeter Brune   SNES_FAS * fas =  (SNES_FAS *)snes->data;
443c79ef259SPeter Brune   PetscErrorCode ierr = 0;
444c79ef259SPeter Brune   PetscFunctionBegin;
445c79ef259SPeter Brune   fas->max_down_it = n;
446c79ef259SPeter Brune   if (fas->next) {
447c79ef259SPeter Brune     ierr = SNESFASSetNumberSmoothDown(fas->next, n);CHKERRQ(ierr);
448c79ef259SPeter Brune   }
449c79ef259SPeter Brune   PetscFunctionReturn(0);
450c79ef259SPeter Brune }
451c79ef259SPeter Brune 
452c79ef259SPeter Brune #undef __FUNCT__
453421d9b32SPeter Brune #define __FUNCT__ "SNESFASSetInterpolation"
454c79ef259SPeter Brune /*@
455c79ef259SPeter Brune    SNESFASSetInterpolation - Sets the function to be used to calculate the
456c79ef259SPeter Brune    interpolation from l-1 to the lth level
457c79ef259SPeter Brune 
458c79ef259SPeter Brune    Input Parameters:
459c79ef259SPeter Brune +  snes      - the multigrid context
460c79ef259SPeter Brune .  mat       - the interpolation operator
461c79ef259SPeter Brune -  level     - the level (0 is coarsest) to supply [do not supply 0]
462c79ef259SPeter Brune 
463c79ef259SPeter Brune    Level: advanced
464c79ef259SPeter Brune 
465c79ef259SPeter Brune    Notes:
466c79ef259SPeter Brune           Usually this is the same matrix used also to set the restriction
467c79ef259SPeter Brune     for the same level.
468c79ef259SPeter Brune 
469c79ef259SPeter Brune           One can pass in the interpolation matrix or its transpose; PETSc figures
470c79ef259SPeter Brune     out from the matrix size which one it is.
471c79ef259SPeter Brune 
472c79ef259SPeter Brune .keywords:  FAS, multigrid, set, interpolate, level
473c79ef259SPeter Brune 
474c79ef259SPeter Brune .seealso: SNESFASSetInjection(), SNESFASSetRestriction(), SNESFASSetRscale()
475c79ef259SPeter Brune @*/
476421d9b32SPeter Brune PetscErrorCode SNESFASSetInterpolation(SNES snes, PetscInt level, Mat mat) {
477421d9b32SPeter Brune   SNES_FAS * fas =  (SNES_FAS *)snes->data;
478d9ce41dcSBarry Smith   PetscInt top_level = fas->level,i;
479421d9b32SPeter Brune 
480421d9b32SPeter Brune   PetscFunctionBegin;
481421d9b32SPeter Brune   if (level > top_level)
482421d9b32SPeter Brune     SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetInterpolation", level);
483421d9b32SPeter Brune   /* get to the correct level */
484d9ce41dcSBarry Smith   for (i = fas->level; i > level; i--) {
485421d9b32SPeter Brune     fas = (SNES_FAS *)fas->next->data;
486421d9b32SPeter Brune   }
487421d9b32SPeter Brune   if (fas->level != level)
488421d9b32SPeter Brune     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetInterpolation");
489421d9b32SPeter Brune   fas->interpolate = mat;
490421d9b32SPeter Brune   PetscFunctionReturn(0);
491421d9b32SPeter Brune }
492421d9b32SPeter Brune 
493421d9b32SPeter Brune #undef __FUNCT__
494421d9b32SPeter Brune #define __FUNCT__ "SNESFASSetRestriction"
495c79ef259SPeter Brune /*@
496c79ef259SPeter Brune    SNESFASSetRestriction - Sets the function to be used to restrict the defect
497c79ef259SPeter Brune    from level l to l-1.
498c79ef259SPeter Brune 
499c79ef259SPeter Brune    Input Parameters:
500c79ef259SPeter Brune +  snes  - the multigrid context
501c79ef259SPeter Brune .  mat   - the restriction matrix
502c79ef259SPeter Brune -  level - the level (0 is coarsest) to supply [Do not supply 0]
503c79ef259SPeter Brune 
504c79ef259SPeter Brune    Level: advanced
505c79ef259SPeter Brune 
506c79ef259SPeter Brune    Notes:
507c79ef259SPeter Brune           Usually this is the same matrix used also to set the interpolation
508c79ef259SPeter Brune     for the same level.
509c79ef259SPeter Brune 
510c79ef259SPeter Brune           One can pass in the interpolation matrix or its transpose; PETSc figures
511c79ef259SPeter Brune     out from the matrix size which one it is.
512c79ef259SPeter Brune 
513c79ef259SPeter Brune          If you do not set this, the transpose of the Mat set with PCMGSetInterpolation()
514c79ef259SPeter Brune     is used.
515c79ef259SPeter Brune 
516c79ef259SPeter Brune .keywords: FAS, MG, set, multigrid, restriction, level
517c79ef259SPeter Brune 
518c79ef259SPeter Brune .seealso: SNESFASSetInterpolation(), SNESFASSetInjection()
519c79ef259SPeter Brune @*/
520421d9b32SPeter Brune PetscErrorCode SNESFASSetRestriction(SNES snes, PetscInt level, Mat mat) {
521421d9b32SPeter Brune   SNES_FAS * fas =  (SNES_FAS *)snes->data;
522d9ce41dcSBarry Smith   PetscInt top_level = fas->level,i;
523421d9b32SPeter Brune 
524421d9b32SPeter Brune   PetscFunctionBegin;
525421d9b32SPeter Brune   if (level > top_level)
526421d9b32SPeter Brune     SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetRestriction", level);
527421d9b32SPeter Brune   /* get to the correct level */
528d9ce41dcSBarry Smith   for (i = fas->level; i > level; i--) {
529421d9b32SPeter Brune     fas = (SNES_FAS *)fas->next->data;
530421d9b32SPeter Brune   }
531421d9b32SPeter Brune   if (fas->level != level)
532421d9b32SPeter Brune     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetRestriction");
533421d9b32SPeter Brune   fas->restrct = mat;
534421d9b32SPeter Brune   PetscFunctionReturn(0);
535421d9b32SPeter Brune }
536421d9b32SPeter Brune 
537efe1f98aSPeter Brune 
538421d9b32SPeter Brune #undef __FUNCT__
539421d9b32SPeter Brune #define __FUNCT__ "SNESFASSetRScale"
540c79ef259SPeter Brune /*@
541c79ef259SPeter Brune    SNESFASSetRScale - Sets the scaling factor of the restriction
542c79ef259SPeter Brune    operator from level l to l-1.
543c79ef259SPeter Brune 
544c79ef259SPeter Brune    Input Parameters:
545c79ef259SPeter Brune +  snes   - the multigrid context
546c79ef259SPeter Brune .  rscale - the restriction scaling
547c79ef259SPeter Brune -  level  - the level (0 is coarsest) to supply [Do not supply 0]
548c79ef259SPeter Brune 
549c79ef259SPeter Brune    Level: advanced
550c79ef259SPeter Brune 
551c79ef259SPeter Brune    Notes:
552c79ef259SPeter Brune          This is only used in the case that the injection is not set.
553c79ef259SPeter Brune 
554c79ef259SPeter Brune .keywords: FAS, MG, set, multigrid, restriction, level
555c79ef259SPeter Brune 
556c79ef259SPeter Brune .seealso: SNESFASSetInjection(), SNESFASSetRestriction()
557c79ef259SPeter Brune @*/
558421d9b32SPeter Brune PetscErrorCode SNESFASSetRScale(SNES snes, PetscInt level, Vec rscale) {
559421d9b32SPeter Brune   SNES_FAS * fas =  (SNES_FAS *)snes->data;
560d9ce41dcSBarry Smith   PetscInt top_level = fas->level,i;
561421d9b32SPeter Brune 
562421d9b32SPeter Brune   PetscFunctionBegin;
563421d9b32SPeter Brune   if (level > top_level)
564421d9b32SPeter Brune     SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetRestriction", level);
565421d9b32SPeter Brune   /* get to the correct level */
566d9ce41dcSBarry Smith   for (i = fas->level; i > level; i--) {
567421d9b32SPeter Brune     fas = (SNES_FAS *)fas->next->data;
568421d9b32SPeter Brune   }
569421d9b32SPeter Brune   if (fas->level != level)
570421d9b32SPeter Brune     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetRestriction");
571421d9b32SPeter Brune   fas->rscale = rscale;
572421d9b32SPeter Brune   PetscFunctionReturn(0);
573421d9b32SPeter Brune }
574421d9b32SPeter Brune 
575efe1f98aSPeter Brune 
576efe1f98aSPeter Brune #undef __FUNCT__
577efe1f98aSPeter Brune #define __FUNCT__ "SNESFASSetInjection"
578c79ef259SPeter Brune /*@
579c79ef259SPeter Brune    SNESFASSetInjection - Sets the function to be used to inject the solution
580c79ef259SPeter Brune    from level l to l-1.
581c79ef259SPeter Brune 
582c79ef259SPeter Brune    Input Parameters:
583c79ef259SPeter Brune +  snes  - the multigrid context
584c79ef259SPeter Brune .  mat   - the restriction matrix
585c79ef259SPeter Brune -  level - the level (0 is coarsest) to supply [Do not supply 0]
586c79ef259SPeter Brune 
587c79ef259SPeter Brune    Level: advanced
588c79ef259SPeter Brune 
589c79ef259SPeter Brune    Notes:
590c79ef259SPeter Brune          If you do not set this, the restriction and rscale is used to
591c79ef259SPeter Brune    project the solution instead.
592c79ef259SPeter Brune 
593c79ef259SPeter Brune .keywords: FAS, MG, set, multigrid, restriction, level
594c79ef259SPeter Brune 
595c79ef259SPeter Brune .seealso: SNESFASSetInterpolation(), SNESFASSetRestriction()
596c79ef259SPeter Brune @*/
597efe1f98aSPeter Brune PetscErrorCode SNESFASSetInjection(SNES snes, PetscInt level, Mat mat) {
598efe1f98aSPeter Brune   SNES_FAS * fas =  (SNES_FAS *)snes->data;
599efe1f98aSPeter Brune   PetscInt top_level = fas->level,i;
600efe1f98aSPeter Brune 
601efe1f98aSPeter Brune   PetscFunctionBegin;
602efe1f98aSPeter Brune   if (level > top_level)
603efe1f98aSPeter Brune     SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetInjection", level);
604efe1f98aSPeter Brune   /* get to the correct level */
605efe1f98aSPeter Brune   for (i = fas->level; i > level; i--) {
606efe1f98aSPeter Brune     fas = (SNES_FAS *)fas->next->data;
607efe1f98aSPeter Brune   }
608efe1f98aSPeter Brune   if (fas->level != level)
609efe1f98aSPeter Brune     SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetInjection");
610efe1f98aSPeter Brune   fas->inject = mat;
611efe1f98aSPeter Brune   PetscFunctionReturn(0);
612efe1f98aSPeter Brune }
613efe1f98aSPeter Brune 
614421d9b32SPeter Brune #undef __FUNCT__
615421d9b32SPeter Brune #define __FUNCT__ "SNESReset_FAS"
616421d9b32SPeter Brune PetscErrorCode SNESReset_FAS(SNES snes)
617421d9b32SPeter Brune {
61877df8cc4SPeter Brune   PetscErrorCode ierr = 0;
619421d9b32SPeter Brune   SNES_FAS * fas = (SNES_FAS *)snes->data;
620421d9b32SPeter Brune 
621421d9b32SPeter Brune   PetscFunctionBegin;
622742fe5e2SPeter Brune   if (fas->upsmooth)     ierr = SNESReset(fas->upsmooth);CHKERRQ(ierr);
623742fe5e2SPeter Brune   if (fas->downsmooth)   ierr = SNESReset(fas->downsmooth);CHKERRQ(ierr);
6243dccd265SPeter Brune   if (fas->inject) {
6253dccd265SPeter Brune     ierr = MatDestroy(&fas->inject);CHKERRQ(ierr);
6263dccd265SPeter Brune   }
6273dccd265SPeter Brune   if (fas->interpolate == fas->restrct) {
6283dccd265SPeter Brune     if (fas->interpolate)  ierr = MatDestroy(&fas->interpolate);CHKERRQ(ierr);
6293dccd265SPeter Brune     fas->restrct = PETSC_NULL;
6303dccd265SPeter Brune   } else {
6313dccd265SPeter Brune     if (fas->interpolate)  ierr = MatDestroy(&fas->interpolate);CHKERRQ(ierr);
6323dccd265SPeter Brune     if (fas->restrct)      ierr = MatDestroy(&fas->restrct);CHKERRQ(ierr);
6333dccd265SPeter Brune   }
6343dccd265SPeter Brune   if (fas->rscale)       ierr = VecDestroy(&fas->rscale);CHKERRQ(ierr);
6353dccd265SPeter Brune 
6363dccd265SPeter Brune   if (fas->upsmooth)   ierr = SNESReset(fas->upsmooth);CHKERRQ(ierr);
6373dccd265SPeter Brune   if (fas->downsmooth) ierr = SNESReset(fas->downsmooth);CHKERRQ(ierr);
638742fe5e2SPeter Brune   if (fas->next)       ierr = SNESReset(fas->next);CHKERRQ(ierr);
639421d9b32SPeter Brune   PetscFunctionReturn(0);
640421d9b32SPeter Brune }
641421d9b32SPeter Brune 
642421d9b32SPeter Brune #undef __FUNCT__
643421d9b32SPeter Brune #define __FUNCT__ "SNESDestroy_FAS"
644421d9b32SPeter Brune PetscErrorCode SNESDestroy_FAS(SNES snes)
645421d9b32SPeter Brune {
646421d9b32SPeter Brune   SNES_FAS * fas = (SNES_FAS *)snes->data;
647742fe5e2SPeter Brune   PetscErrorCode ierr = 0;
648421d9b32SPeter Brune 
649421d9b32SPeter Brune   PetscFunctionBegin;
650421d9b32SPeter Brune   /* recursively resets and then destroys */
65151e86f29SPeter Brune   if (fas->upsmooth)     ierr = SNESDestroy(&fas->upsmooth);CHKERRQ(ierr);
65251e86f29SPeter Brune   if (fas->downsmooth)   ierr = SNESDestroy(&fas->downsmooth);CHKERRQ(ierr);
653421d9b32SPeter Brune   if (fas->next)         ierr = SNESDestroy(&fas->next);CHKERRQ(ierr);
654421d9b32SPeter Brune   ierr = PetscFree(fas);CHKERRQ(ierr);
655ee1fd11aSPeter Brune 
656421d9b32SPeter Brune   PetscFunctionReturn(0);
657421d9b32SPeter Brune }
658421d9b32SPeter Brune 
659421d9b32SPeter Brune #undef __FUNCT__
660421d9b32SPeter Brune #define __FUNCT__ "SNESSetUp_FAS"
661421d9b32SPeter Brune PetscErrorCode SNESSetUp_FAS(SNES snes)
662421d9b32SPeter Brune {
66348bfdf8aSPeter Brune   SNES_FAS       *fas = (SNES_FAS *) snes->data;
664421d9b32SPeter Brune   PetscErrorCode ierr;
665efe1f98aSPeter Brune   VecScatter     injscatter;
666d1adcc6fSPeter Brune   PetscInt       dm_levels;
6673dccd265SPeter Brune   Vec            vec_sol, vec_func, vec_sol_update, vec_rhs; /* preserve these if they're set through the reset */
668d1adcc6fSPeter Brune 
669421d9b32SPeter Brune   PetscFunctionBegin;
670eff52c0eSPeter Brune 
671cc05f883SPeter Brune   if (fas->usedmfornumberoflevels && (fas->level == fas->levels - 1)) {
672d1adcc6fSPeter Brune     ierr = DMGetRefineLevel(snes->dm,&dm_levels);CHKERRQ(ierr);
673d1adcc6fSPeter Brune     dm_levels++;
674cc05f883SPeter Brune     if (dm_levels > fas->levels) {
6753dccd265SPeter Brune 
6763dccd265SPeter Brune       /* we don't want the solution and func vectors to be destroyed in the SNESReset when it's called in SNESSetUp_FAS*/
6773dccd265SPeter Brune       vec_sol = snes->vec_sol;
6783dccd265SPeter Brune       vec_func = snes->vec_func;
6793dccd265SPeter Brune       vec_sol_update = snes->vec_sol_update;
6803dccd265SPeter Brune       vec_rhs = snes->vec_rhs;
6813dccd265SPeter Brune       snes->vec_sol = PETSC_NULL;
6823dccd265SPeter Brune       snes->vec_func = PETSC_NULL;
6833dccd265SPeter Brune       snes->vec_sol_update = PETSC_NULL;
6843dccd265SPeter Brune       snes->vec_rhs = PETSC_NULL;
6853dccd265SPeter Brune 
6863dccd265SPeter Brune       /* reset the number of levels */
687d1adcc6fSPeter Brune       ierr = SNESFASSetLevels(snes,dm_levels,PETSC_NULL);CHKERRQ(ierr);
688cc05f883SPeter Brune       ierr = SNESSetFromOptions(snes);CHKERRQ(ierr);
6893dccd265SPeter Brune 
6903dccd265SPeter Brune       snes->vec_sol = vec_sol;
6913dccd265SPeter Brune       snes->vec_func = vec_func;
6923dccd265SPeter Brune       snes->vec_rhs = vec_rhs;
6933dccd265SPeter Brune       snes->vec_sol_update = vec_sol_update;
694d1adcc6fSPeter Brune     }
695d1adcc6fSPeter Brune   }
696d1adcc6fSPeter Brune 
6973dccd265SPeter Brune   if (fas->level != fas->levels - 1) snes->gridsequence = 0; /* no grid sequencing inside the multigrid hierarchy! */
6983dccd265SPeter Brune 
69907144faaSPeter Brune   if (fas->fastype == SNES_FAS_MULTIPLICATIVE) {
7002f7ea302SPeter Brune     ierr = SNESDefaultGetWork(snes, 1);CHKERRQ(ierr); /* work vectors used for intergrid transfers */
70107144faaSPeter Brune   } else {
702ddebd997SPeter Brune     ierr = SNESDefaultGetWork(snes, 4);CHKERRQ(ierr); /* work vectors used for intergrid transfers */
70307144faaSPeter Brune   }
704cc05f883SPeter Brune 
70548bfdf8aSPeter Brune   /* setup the pre and post smoothers and set their function, jacobian, and gs evaluation routines if the user has neglected this */
70648bfdf8aSPeter Brune   if (fas->upsmooth) {
70748bfdf8aSPeter Brune     ierr = SNESSetFromOptions(fas->upsmooth);CHKERRQ(ierr);
70848bfdf8aSPeter Brune     if (snes->ops->computefunction && !fas->upsmooth->ops->computefunction) {
70948bfdf8aSPeter Brune       ierr = SNESSetFunction(fas->upsmooth, PETSC_NULL, snes->ops->computefunction, snes->funP);CHKERRQ(ierr);
71048bfdf8aSPeter Brune     }
71148bfdf8aSPeter Brune     if (snes->ops->computejacobian && !fas->upsmooth->ops->computejacobian) {
71248bfdf8aSPeter Brune       ierr = SNESSetJacobian(fas->upsmooth, fas->upsmooth->jacobian, fas->upsmooth->jacobian_pre, snes->ops->computejacobian, snes->jacP);CHKERRQ(ierr);
71348bfdf8aSPeter Brune     }
71448bfdf8aSPeter Brune    if (snes->ops->computegs && !fas->upsmooth->ops->computegs) {
71548bfdf8aSPeter Brune       ierr = SNESSetGS(fas->upsmooth, snes->ops->computegs, snes->gsP);CHKERRQ(ierr);
71648bfdf8aSPeter Brune     }
71748bfdf8aSPeter Brune   }
71848bfdf8aSPeter Brune   if (fas->downsmooth) {
71948bfdf8aSPeter Brune     ierr = SNESSetFromOptions(fas->downsmooth);CHKERRQ(ierr);
72048bfdf8aSPeter Brune     if (snes->ops->computefunction && !fas->downsmooth->ops->computefunction) {
72148bfdf8aSPeter Brune       ierr = SNESSetFunction(fas->downsmooth, PETSC_NULL, snes->ops->computefunction, snes->funP);CHKERRQ(ierr);
72248bfdf8aSPeter Brune     }
72348bfdf8aSPeter Brune     if (snes->ops->computejacobian && !fas->downsmooth->ops->computejacobian) {
72448bfdf8aSPeter Brune       ierr = SNESSetJacobian(fas->downsmooth, fas->downsmooth->jacobian, fas->downsmooth->jacobian_pre, snes->ops->computejacobian, snes->jacP);CHKERRQ(ierr);
72548bfdf8aSPeter Brune     }
72648bfdf8aSPeter Brune    if (snes->ops->computegs && !fas->downsmooth->ops->computegs) {
72748bfdf8aSPeter Brune       ierr = SNESSetGS(fas->downsmooth, snes->ops->computegs, snes->gsP);CHKERRQ(ierr);
72848bfdf8aSPeter Brune     }
7291a266240SBarry Smith   }
73048bfdf8aSPeter Brune   /*pass the smoother, function, and jacobian up to the next level if it's not user set already */
731646217ecSPeter Brune   if (fas->next) {
7326273346dSPeter Brune     if (fas->galerkin) {
7336273346dSPeter Brune       ierr = SNESSetFunction(fas->next, PETSC_NULL, SNESFASGalerkinDefaultFunction, fas->next);CHKERRQ(ierr);
7346273346dSPeter Brune     } else {
73548bfdf8aSPeter Brune       if (snes->ops->computefunction && !fas->next->ops->computefunction) {
73648bfdf8aSPeter Brune         ierr = SNESSetFunction(fas->next, PETSC_NULL, snes->ops->computefunction, snes->funP);CHKERRQ(ierr);
73748bfdf8aSPeter Brune       }
73848bfdf8aSPeter Brune       if (snes->ops->computejacobian && !fas->next->ops->computejacobian) {
73948bfdf8aSPeter Brune         ierr = SNESSetJacobian(fas->next, fas->next->jacobian, fas->next->jacobian_pre, snes->ops->computejacobian, snes->jacP);CHKERRQ(ierr);
74048bfdf8aSPeter Brune       }
74148bfdf8aSPeter Brune       if (snes->ops->computegs && !fas->next->ops->computegs) {
742646217ecSPeter Brune         ierr = SNESSetGS(fas->next, snes->ops->computegs, snes->gsP);CHKERRQ(ierr);
743646217ecSPeter Brune       }
744646217ecSPeter Brune     }
7456273346dSPeter Brune   }
746421d9b32SPeter Brune   if (snes->dm) {
747421d9b32SPeter Brune     /* construct EVERYTHING from the DM -- including the progressive set of smoothers */
748421d9b32SPeter Brune     if (fas->next) {
749421d9b32SPeter Brune       /* for now -- assume the DM and the evaluation functions have been set externally */
750ee78dd50SPeter Brune       if (!fas->next->dm) {
751ee78dd50SPeter Brune         ierr = DMCoarsen(snes->dm, ((PetscObject)fas->next)->comm, &fas->next->dm);CHKERRQ(ierr);
752ee78dd50SPeter Brune         ierr = SNESSetDM(fas->next, fas->next->dm);CHKERRQ(ierr);
753ee78dd50SPeter Brune       }
754421d9b32SPeter Brune       /* set the interpolation and restriction from the DM */
755ee78dd50SPeter Brune       if (!fas->interpolate) {
756e727c939SJed Brown         ierr = DMCreateInterpolation(fas->next->dm, snes->dm, &fas->interpolate, &fas->rscale);CHKERRQ(ierr);
757421d9b32SPeter Brune         fas->restrct = fas->interpolate;
758421d9b32SPeter Brune       }
759efe1f98aSPeter Brune       /* set the injection from the DM */
760efe1f98aSPeter Brune       if (!fas->inject) {
761e727c939SJed Brown         ierr = DMCreateInjection(fas->next->dm, snes->dm, &injscatter);CHKERRQ(ierr);
762efe1f98aSPeter Brune         ierr = MatCreateScatter(((PetscObject)snes)->comm, injscatter, &fas->inject);CHKERRQ(ierr);
763efe1f98aSPeter Brune         ierr = VecScatterDestroy(&injscatter);CHKERRQ(ierr);
764efe1f98aSPeter Brune       }
765421d9b32SPeter Brune     }
766ee78dd50SPeter Brune     /* set the DMs of the pre and post-smoothers here */
767*6bed07a3SBarry Smith     if (fas->upsmooth)  {ierr = SNESSetDM(fas->upsmooth,   snes->dm);CHKERRQ(ierr);}
768*6bed07a3SBarry Smith     if (fas->downsmooth){ierr = SNESSetDM(fas->downsmooth, snes->dm);CHKERRQ(ierr);}
769421d9b32SPeter Brune   }
770cc05f883SPeter Brune 
7716273346dSPeter Brune   /* setup FAS work vectors */
7726273346dSPeter Brune   if (fas->galerkin) {
7736273346dSPeter Brune     ierr = VecDuplicate(snes->vec_sol, &fas->Xg);CHKERRQ(ierr);
7746273346dSPeter Brune     ierr = VecDuplicate(snes->vec_sol, &fas->Fg);CHKERRQ(ierr);
7756273346dSPeter Brune   }
7766273346dSPeter Brune 
777fa9694d7SPeter Brune   if (fas->next) {
778fa9694d7SPeter Brune    /* gotta set up the solution vector for this to work */
779*6bed07a3SBarry Smith     if (!fas->next->vec_sol) {ierr = VecDuplicate(fas->rscale, &fas->next->vec_sol);CHKERRQ(ierr);}
780742fe5e2SPeter Brune     if (!fas->next->vec_rhs) {ierr = VecDuplicate(fas->rscale, &fas->next->vec_rhs);CHKERRQ(ierr);}
781fa9694d7SPeter Brune     ierr = SNESSetUp(fas->next);CHKERRQ(ierr);
782fa9694d7SPeter Brune   }
783fa9694d7SPeter Brune   /* got to set them all up at once */
784421d9b32SPeter Brune   PetscFunctionReturn(0);
785421d9b32SPeter Brune }
786421d9b32SPeter Brune 
787421d9b32SPeter Brune #undef __FUNCT__
788421d9b32SPeter Brune #define __FUNCT__ "SNESSetFromOptions_FAS"
789421d9b32SPeter Brune PetscErrorCode SNESSetFromOptions_FAS(SNES snes)
790421d9b32SPeter Brune {
791ee78dd50SPeter Brune   SNES_FAS       *fas = (SNES_FAS *) snes->data;
792ee78dd50SPeter Brune   PetscInt       levels = 1;
793d1adcc6fSPeter Brune   PetscBool      flg, smoothflg, smoothupflg, smoothdownflg, monflg;
794421d9b32SPeter Brune   PetscErrorCode ierr;
795ee78dd50SPeter Brune   const char     *def_smooth = SNESNRICHARDSON;
796ee78dd50SPeter Brune   char           pre_type[256];
797ee78dd50SPeter Brune   char           post_type[256];
798ee78dd50SPeter Brune   char           monfilename[PETSC_MAX_PATH_LEN];
79907144faaSPeter Brune   SNESFASType    fastype;
800421d9b32SPeter Brune 
801421d9b32SPeter Brune   PetscFunctionBegin;
802c90fad12SPeter Brune   ierr = PetscOptionsHead("SNESFAS Options-----------------------------------");CHKERRQ(ierr);
803ee78dd50SPeter Brune 
804ee78dd50SPeter Brune   /* number of levels -- only process on the finest level */
805ee78dd50SPeter Brune   if (fas->levels - 1 == fas->level) {
806ee78dd50SPeter Brune     ierr = PetscOptionsInt("-snes_fas_levels", "Number of Levels", "SNESFASSetLevels", levels, &levels, &flg);CHKERRQ(ierr);
807c732cbdbSBarry Smith     if (!flg && snes->dm) {
808c732cbdbSBarry Smith       ierr = DMGetRefineLevel(snes->dm,&levels);CHKERRQ(ierr);
809c732cbdbSBarry Smith       levels++;
810d1adcc6fSPeter Brune       fas->usedmfornumberoflevels = PETSC_TRUE;
811c732cbdbSBarry Smith     }
812ee78dd50SPeter Brune     ierr = SNESFASSetLevels(snes, levels, PETSC_NULL);CHKERRQ(ierr);
813ee78dd50SPeter Brune   }
814ee78dd50SPeter Brune 
815ee78dd50SPeter Brune   /* type of pre and/or post smoothers -- set both at once */
816ee78dd50SPeter Brune   ierr = PetscMemcpy(post_type, def_smooth, 256);CHKERRQ(ierr);
817ee78dd50SPeter Brune   ierr = PetscMemcpy(pre_type, def_smooth, 256);CHKERRQ(ierr);
81807144faaSPeter Brune   fastype = fas->fastype;
81907144faaSPeter Brune   ierr = PetscOptionsEnum("-snes_fas_type","FAS correction type","SNESFASSetType",SNESFASTypes,(PetscEnum)fastype,(PetscEnum*)&fastype,&flg);CHKERRQ(ierr);
82007144faaSPeter Brune   if (flg) {
82107144faaSPeter Brune     ierr = SNESFASSetType(snes, fastype);CHKERRQ(ierr);
82207144faaSPeter Brune   }
823d1adcc6fSPeter Brune   ierr = PetscOptionsList("-snes_fas_smoother_type","Nonlinear smoother method","SNESSetType",SNESList,def_smooth,pre_type,256,&smoothflg);CHKERRQ(ierr);
824d1adcc6fSPeter Brune   if (smoothflg) {
825ee78dd50SPeter Brune     ierr = PetscMemcpy(post_type, pre_type, 256);CHKERRQ(ierr);
826ee78dd50SPeter Brune   } else {
827d1adcc6fSPeter Brune     ierr = PetscOptionsList("-snes_fas_smoothup_type",  "Nonlinear smoother method","SNESSetType",SNESList,def_smooth,pre_type, 256,&smoothupflg);CHKERRQ(ierr);
828d1adcc6fSPeter Brune     ierr = PetscOptionsList("-snes_fas_smoothdown_type","Nonlinear smoother method","SNESSetType",SNESList,def_smooth,post_type,256,&smoothdownflg);CHKERRQ(ierr);
829ee78dd50SPeter Brune   }
830ee78dd50SPeter Brune 
831ee78dd50SPeter Brune   /* options for the number of preconditioning cycles and cycle type */
832d1adcc6fSPeter Brune   ierr = PetscOptionsInt("-snes_fas_smoothup","Number of post-smooth iterations","SNESFASSetNumberSmoothUp",fas->max_up_it,&fas->max_up_it,&flg);CHKERRQ(ierr);
833d1adcc6fSPeter Brune   ierr = PetscOptionsInt("-snes_fas_smoothdown","Number of pre-smooth iterations","SNESFASSetNumberSmoothUp",fas->max_down_it,&fas->max_down_it,&flg);CHKERRQ(ierr);
834d1adcc6fSPeter Brune   ierr = PetscOptionsInt("-snes_fas_cycles","Number of cycles","SNESFASSetCycles",fas->n_cycles,&fas->n_cycles,&flg);CHKERRQ(ierr);
835ee78dd50SPeter Brune 
8366273346dSPeter Brune   ierr = PetscOptionsBool("-snes_fas_galerkin", "Form coarse problems with Galerkin","SNESFAS",fas->galerkin,&fas->galerkin,&flg);CHKERRQ(ierr);
8376273346dSPeter Brune 
838646217ecSPeter Brune   ierr = PetscOptionsString("-snes_fas_monitor","Monitor FAS progress","SNESMonitorSet","stdout",monfilename,PETSC_MAX_PATH_LEN,&monflg);CHKERRQ(ierr);
839ee78dd50SPeter Brune 
840ee78dd50SPeter Brune   /* other options for the coarsest level */
841ee78dd50SPeter Brune   if (fas->level == 0) {
842d1adcc6fSPeter Brune     ierr = PetscOptionsList("-snes_fas_coarse_smoother_type","Coarsest smoother method","SNESSetType",SNESList,def_smooth,pre_type,256,&smoothflg);CHKERRQ(ierr);
843ee78dd50SPeter Brune   }
844ee78dd50SPeter Brune 
845421d9b32SPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
8468cc86e31SPeter Brune   /* setup from the determined types if there is no pointwise procedure or smoother defined */
847eff52c0eSPeter Brune 
848d28543b3SPeter Brune   if ((!fas->downsmooth) && ((smoothdownflg || smoothflg) || !snes->usegs)) {
8498cc86e31SPeter Brune     const char     *prefix;
8508cc86e31SPeter Brune     ierr = SNESGetOptionsPrefix(snes,&prefix);CHKERRQ(ierr);
8518cc86e31SPeter Brune     ierr = SNESCreate(((PetscObject)snes)->comm, &fas->downsmooth);CHKERRQ(ierr);
8528cc86e31SPeter Brune     ierr = SNESSetOptionsPrefix(fas->downsmooth,prefix);CHKERRQ(ierr);
8538cc86e31SPeter Brune     if (fas->level || (fas->levels == 1)) {
854eff52c0eSPeter Brune       ierr = SNESAppendOptionsPrefix(fas->downsmooth,"fas_levels_down_");CHKERRQ(ierr);
8558cc86e31SPeter Brune     } else {
8568cc86e31SPeter Brune       ierr = SNESAppendOptionsPrefix(fas->downsmooth,"fas_coarse_");CHKERRQ(ierr);
8578cc86e31SPeter Brune     }
8588cc86e31SPeter Brune     ierr = PetscObjectIncrementTabLevel((PetscObject)fas->downsmooth, (PetscObject)snes, 1);CHKERRQ(ierr);
8598cc86e31SPeter Brune     ierr = SNESSetType(fas->downsmooth, pre_type);CHKERRQ(ierr);
8608cc86e31SPeter Brune   }
8618cc86e31SPeter Brune 
862d28543b3SPeter Brune   if ((!fas->upsmooth) && (fas->level != 0) && ((smoothupflg || smoothflg) || !snes->usegs)) {
86367339d5cSBarry Smith     const char     *prefix;
86467339d5cSBarry Smith     ierr = SNESGetOptionsPrefix(snes,&prefix);CHKERRQ(ierr);
865ee78dd50SPeter Brune     ierr = SNESCreate(((PetscObject)snes)->comm, &fas->upsmooth);CHKERRQ(ierr);
86667339d5cSBarry Smith     ierr = SNESSetOptionsPrefix(fas->upsmooth,prefix);CHKERRQ(ierr);
867eff52c0eSPeter Brune     ierr = SNESAppendOptionsPrefix(fas->upsmooth,"fas_levels_up_");CHKERRQ(ierr);
868293a7e31SPeter Brune     ierr = PetscObjectIncrementTabLevel((PetscObject)fas->upsmooth, (PetscObject)snes, 1);CHKERRQ(ierr);
869ee78dd50SPeter Brune     ierr = SNESSetType(fas->upsmooth, pre_type);CHKERRQ(ierr);
870ee78dd50SPeter Brune   }
8711a266240SBarry Smith   if (fas->upsmooth) {
8721a266240SBarry Smith     ierr = SNESSetTolerances(fas->upsmooth, 0.0, 0.0, 0.0, fas->max_up_it, 1000);CHKERRQ(ierr);
8731a266240SBarry Smith   }
8741a266240SBarry Smith 
8751a266240SBarry Smith   if (fas->downsmooth) {
8761a266240SBarry Smith     ierr = SNESSetTolerances(fas->downsmooth, 0.0, 0.0, 0.0, fas->max_down_it, 1000);CHKERRQ(ierr);
8771a266240SBarry Smith   }
878ee78dd50SPeter Brune 
879742fe5e2SPeter Brune   if (fas->level != fas->levels - 1) {
880742fe5e2SPeter Brune     ierr = SNESSetTolerances(snes, 0.0, 0.0, 0.0, fas->n_cycles, 1000);CHKERRQ(ierr);
881742fe5e2SPeter Brune   }
882742fe5e2SPeter Brune 
883ee78dd50SPeter Brune   if (monflg) {
884646217ecSPeter Brune     fas->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr);
885794bee33SPeter Brune     /* set the monitors for the upsmoother and downsmoother */
8862f7ea302SPeter Brune     ierr = SNESMonitorCancel(snes);CHKERRQ(ierr);
887742fe5e2SPeter Brune     ierr = SNESMonitorSet(snes,SNESMonitorDefault,PETSC_NULL,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr);
888293a7e31SPeter Brune     if (fas->upsmooth)   ierr = SNESMonitorSet(fas->upsmooth,SNESMonitorDefault,PETSC_NULL,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr);
889293a7e31SPeter Brune     if (fas->downsmooth) ierr = SNESMonitorSet(fas->downsmooth,SNESMonitorDefault,PETSC_NULL,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr);
890d28543b3SPeter Brune   } else {
891d28543b3SPeter Brune     /* unset the monitors on the coarse levels */
892d28543b3SPeter Brune     if (fas->level != fas->levels - 1) {
893d28543b3SPeter Brune       ierr = SNESMonitorCancel(snes);CHKERRQ(ierr);
894d28543b3SPeter Brune     }
895ee78dd50SPeter Brune   }
896ee78dd50SPeter Brune 
897ee78dd50SPeter Brune   /* recursive option setting for the smoothers */
898d28543b3SPeter Brune   if (fas->next) {ierr = SNESSetFromOptions(fas->next);CHKERRQ(ierr);}
899421d9b32SPeter Brune   PetscFunctionReturn(0);
900421d9b32SPeter Brune }
901421d9b32SPeter Brune 
902421d9b32SPeter Brune #undef __FUNCT__
903421d9b32SPeter Brune #define __FUNCT__ "SNESView_FAS"
904421d9b32SPeter Brune PetscErrorCode SNESView_FAS(SNES snes, PetscViewer viewer)
905421d9b32SPeter Brune {
906421d9b32SPeter Brune   SNES_FAS   *fas = (SNES_FAS *) snes->data;
907421d9b32SPeter Brune   PetscBool      iascii;
908421d9b32SPeter Brune   PetscErrorCode ierr;
909421d9b32SPeter Brune 
910421d9b32SPeter Brune   PetscFunctionBegin;
91139a4b097SPeter Brune   if (fas->level != fas->levels - 1) PetscFunctionReturn(0);
912421d9b32SPeter Brune   ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
913421d9b32SPeter Brune   if (iascii) {
914421d9b32SPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "FAS, levels = %d\n",  fas->levels);CHKERRQ(ierr);
915421d9b32SPeter Brune     ierr = PetscViewerASCIIPushTab(viewer);
916421d9b32SPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "level: %d\n",  fas->level);CHKERRQ(ierr);
917ee78dd50SPeter Brune     if (fas->upsmooth) {
91839a4b097SPeter Brune       ierr = PetscViewerASCIIPrintf(viewer, "up-smoother on level %D:\n",  fas->level);CHKERRQ(ierr);
919421d9b32SPeter Brune       ierr = PetscViewerASCIIPushTab(viewer);
920ee78dd50SPeter Brune       ierr = SNESView(fas->upsmooth, viewer);CHKERRQ(ierr);
921421d9b32SPeter Brune       ierr = PetscViewerASCIIPopTab(viewer);
922421d9b32SPeter Brune     } else {
923ee78dd50SPeter Brune       ierr = PetscViewerASCIIPrintf(viewer, "no up-smoother on level %D\n",  fas->level);CHKERRQ(ierr);
924421d9b32SPeter Brune     }
925ee78dd50SPeter Brune     if (fas->downsmooth) {
92639a4b097SPeter Brune       ierr = PetscViewerASCIIPrintf(viewer, "down-smoother on level %D:\n",  fas->level);CHKERRQ(ierr);
927421d9b32SPeter Brune       ierr = PetscViewerASCIIPushTab(viewer);
928ee78dd50SPeter Brune       ierr = SNESView(fas->downsmooth, viewer);CHKERRQ(ierr);
929421d9b32SPeter Brune       ierr = PetscViewerASCIIPopTab(viewer);
930421d9b32SPeter Brune     } else {
931ee78dd50SPeter Brune       ierr = PetscViewerASCIIPrintf(viewer, "no down-smoother on level %D\n",  fas->level);CHKERRQ(ierr);
932421d9b32SPeter Brune     }
933d28543b3SPeter Brune     if (snes->usegs) {
93439a4b097SPeter Brune       ierr = PetscViewerASCIIPrintf(viewer, "Using user Gauss-Seidel on level %D -- smoothdown=%D, smoothup=%D\n",
93539a4b097SPeter Brune                                     fas->level, fas->max_down_it, fas->max_up_it);CHKERRQ(ierr);
936421d9b32SPeter Brune     }
937421d9b32SPeter Brune     ierr = PetscViewerASCIIPopTab(viewer);
938421d9b32SPeter Brune   } else {
939421d9b32SPeter Brune     SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for SNESFAS",((PetscObject)viewer)->type_name);
940421d9b32SPeter Brune   }
941421d9b32SPeter Brune   PetscFunctionReturn(0);
942421d9b32SPeter Brune }
943421d9b32SPeter Brune 
944421d9b32SPeter Brune #undef __FUNCT__
94539bd7f45SPeter Brune #define __FUNCT__ "FASDownSmooth"
94639bd7f45SPeter Brune /*
94739bd7f45SPeter Brune Defines the action of the downsmoother
94839bd7f45SPeter Brune  */
94939bd7f45SPeter Brune PetscErrorCode FASDownSmooth(SNES snes, Vec B, Vec X, Vec F){
95039bd7f45SPeter Brune   PetscErrorCode      ierr = 0;
9512d15c84fSPeter Brune   PetscReal           fnorm;
952742fe5e2SPeter Brune   SNESConvergedReason reason;
95339bd7f45SPeter Brune   SNES_FAS            *fas = (SNES_FAS *)snes->data;
954421d9b32SPeter Brune   PetscFunctionBegin;
955d1adcc6fSPeter Brune   if (fas->downsmooth) {
956d1adcc6fSPeter Brune     ierr = SNESSolve(fas->downsmooth, B, X);CHKERRQ(ierr);
957742fe5e2SPeter Brune     /* check convergence reason for the smoother */
958742fe5e2SPeter Brune     ierr = SNESGetConvergedReason(fas->downsmooth,&reason);CHKERRQ(ierr);
959742fe5e2SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
960742fe5e2SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
961742fe5e2SPeter Brune       PetscFunctionReturn(0);
962742fe5e2SPeter Brune     }
963d28543b3SPeter Brune   } else if (snes->usegs && snes->ops->computegs) {
964794bee33SPeter Brune     if (fas->monitor) {
965794bee33SPeter Brune       ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
966794bee33SPeter Brune       ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
967d1adcc6fSPeter Brune       ierr = PetscViewerASCIIAddTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
968eff52c0eSPeter Brune       ierr = PetscViewerASCIIPrintf(fas->monitor, "%d SNES GS Function norm %14.12e\n", 0, fnorm);CHKERRQ(ierr);
969d1adcc6fSPeter Brune       ierr = PetscViewerASCIISubtractTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
970794bee33SPeter Brune     }
9719c44eddcSPeter Brune     ierr = SNESSetGSSweeps(snes, fas->max_down_it);CHKERRQ(ierr);
972646217ecSPeter Brune     ierr = SNESComputeGS(snes, B, X);CHKERRQ(ierr);
973cc05f883SPeter Brune     if (fas->monitor) {
974794bee33SPeter Brune       ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
975794bee33SPeter Brune       ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
976d1adcc6fSPeter Brune       ierr = PetscViewerASCIIAddTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
9779c44eddcSPeter Brune       ierr = PetscViewerASCIIPrintf(fas->monitor, "1 SNES GS Function norm %14.12e\n", fnorm);CHKERRQ(ierr);
978d1adcc6fSPeter Brune       ierr = PetscViewerASCIISubtractTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
979794bee33SPeter Brune     }
980c90fad12SPeter Brune   } else if (snes->pc) {
981c90fad12SPeter Brune     ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr);
9822f7ea302SPeter Brune     ierr = SNESGetConvergedReason(fas->downsmooth,&reason);CHKERRQ(ierr);
9832f7ea302SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
9842f7ea302SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
9852f7ea302SPeter Brune       PetscFunctionReturn(0);
9862f7ea302SPeter Brune     }
987fe6f9142SPeter Brune   }
98839bd7f45SPeter Brune   PetscFunctionReturn(0);
98939bd7f45SPeter Brune }
99039bd7f45SPeter Brune 
99139bd7f45SPeter Brune 
99239bd7f45SPeter Brune #undef __FUNCT__
99339bd7f45SPeter Brune #define __FUNCT__ "FASUpSmooth"
99439bd7f45SPeter Brune /*
99507144faaSPeter Brune Defines the action of the upsmoother
99639bd7f45SPeter Brune  */
99739bd7f45SPeter Brune PetscErrorCode FASUpSmooth (SNES snes, Vec B, Vec X, Vec F) {
99839bd7f45SPeter Brune   PetscErrorCode      ierr = 0;
99939bd7f45SPeter Brune   PetscReal           fnorm;
100039bd7f45SPeter Brune   SNESConvergedReason reason;
100139bd7f45SPeter Brune   SNES_FAS            *fas = (SNES_FAS *)snes->data;
100239bd7f45SPeter Brune   PetscFunctionBegin;
100339bd7f45SPeter Brune   if (fas->upsmooth) {
100439bd7f45SPeter Brune     ierr = SNESSolve(fas->downsmooth, B, X);CHKERRQ(ierr);
100539bd7f45SPeter Brune     /* check convergence reason for the smoother */
100639bd7f45SPeter Brune     ierr = SNESGetConvergedReason(fas->downsmooth,&reason);CHKERRQ(ierr);
100739bd7f45SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
100839bd7f45SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
100939bd7f45SPeter Brune       PetscFunctionReturn(0);
101039bd7f45SPeter Brune     }
101139bd7f45SPeter Brune   } else if (snes->usegs && snes->ops->computegs) {
101239bd7f45SPeter Brune     if (fas->monitor) {
101339bd7f45SPeter Brune       ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
101439bd7f45SPeter Brune       ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
101539bd7f45SPeter Brune       ierr = PetscViewerASCIIAddTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
101639bd7f45SPeter Brune       ierr = PetscViewerASCIIPrintf(fas->monitor, "%d SNES GS Function norm %14.12e\n", 0, fnorm);CHKERRQ(ierr);
101739bd7f45SPeter Brune       ierr = PetscViewerASCIISubtractTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
101839bd7f45SPeter Brune     }
10199c44eddcSPeter Brune     ierr = SNESSetGSSweeps(snes, fas->max_up_it);CHKERRQ(ierr);
102039bd7f45SPeter Brune     ierr = SNESComputeGS(snes, B, X);CHKERRQ(ierr);
102139bd7f45SPeter Brune     if (fas->monitor) {
102239bd7f45SPeter Brune       ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
102339bd7f45SPeter Brune       ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
102439bd7f45SPeter Brune       ierr = PetscViewerASCIIAddTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
10259c44eddcSPeter Brune       ierr = PetscViewerASCIIPrintf(fas->monitor, "1 SNES GS Function norm %14.12e\n", fnorm);CHKERRQ(ierr);
102639bd7f45SPeter Brune       ierr = PetscViewerASCIISubtractTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr);
102739bd7f45SPeter Brune     }
102839bd7f45SPeter Brune   } else if (snes->pc) {
102939bd7f45SPeter Brune     ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr);
103039bd7f45SPeter Brune     ierr = SNESGetConvergedReason(fas->downsmooth,&reason);CHKERRQ(ierr);
103139bd7f45SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
103239bd7f45SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
103339bd7f45SPeter Brune       PetscFunctionReturn(0);
103439bd7f45SPeter Brune     }
103539bd7f45SPeter Brune   }
103639bd7f45SPeter Brune   PetscFunctionReturn(0);
103739bd7f45SPeter Brune }
103839bd7f45SPeter Brune 
103939bd7f45SPeter Brune #undef __FUNCT__
104039bd7f45SPeter Brune #define __FUNCT__ "FASCoarseCorrection"
104139bd7f45SPeter Brune /*
104239bd7f45SPeter Brune 
104339bd7f45SPeter Brune Performs the FAS coarse correction as:
104439bd7f45SPeter Brune 
104539bd7f45SPeter Brune fine problem: F(x) = 0
104639bd7f45SPeter Brune coarse problem: F^c(x) = b^c
104739bd7f45SPeter Brune 
104839bd7f45SPeter Brune b^c = F^c(I^c_fx^f - I^c_fF(x))
104939bd7f45SPeter Brune 
105039bd7f45SPeter Brune with correction:
105139bd7f45SPeter Brune 
105239bd7f45SPeter Brune 
105339bd7f45SPeter Brune 
105439bd7f45SPeter Brune  */
105539a4b097SPeter Brune PetscErrorCode FASCoarseCorrection(SNES snes, Vec X, Vec F, Vec X_new) {
105639bd7f45SPeter Brune   PetscErrorCode      ierr;
105739bd7f45SPeter Brune   Vec                 X_c, Xo_c, F_c, B_c;
105839bd7f45SPeter Brune   SNES_FAS            *fas = (SNES_FAS *)snes->data;
105939bd7f45SPeter Brune   SNESConvergedReason reason;
106039bd7f45SPeter Brune   PetscFunctionBegin;
1061fa9694d7SPeter Brune   if (fas->next) {
1062ee78dd50SPeter Brune     ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
1063794bee33SPeter Brune 
1064c90fad12SPeter Brune     X_c  = fas->next->vec_sol;
1065293a7e31SPeter Brune     Xo_c = fas->next->work[0];
1066c90fad12SPeter Brune     F_c  = fas->next->vec_func;
1067742fe5e2SPeter Brune     B_c  = fas->next->vec_rhs;
1068efe1f98aSPeter Brune 
1069efe1f98aSPeter Brune     /* inject the solution */
1070efe1f98aSPeter Brune     if (fas->inject) {
1071a3cb90a9SPeter Brune       ierr = MatRestrict(fas->inject, X, Xo_c);CHKERRQ(ierr);
1072efe1f98aSPeter Brune     } else {
1073a3cb90a9SPeter Brune       ierr = MatRestrict(fas->restrct, X, Xo_c);CHKERRQ(ierr);
1074a3cb90a9SPeter Brune       ierr = VecPointwiseMult(Xo_c, fas->rscale, Xo_c);CHKERRQ(ierr);
1075efe1f98aSPeter Brune     }
1076293a7e31SPeter Brune     ierr = VecScale(F, -1.0);CHKERRQ(ierr);
1077293a7e31SPeter Brune 
1078293a7e31SPeter Brune     /* restrict the defect */
1079293a7e31SPeter Brune     ierr = MatRestrict(fas->restrct, F, B_c);CHKERRQ(ierr);
1080293a7e31SPeter Brune 
1081c90fad12SPeter Brune     /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */
1082ee78dd50SPeter Brune     fas->next->vec_rhs = PETSC_NULL;                                           /*unset the RHS to evaluate function instead of residual*/
1083c90fad12SPeter Brune     ierr = SNESComputeFunction(fas->next, Xo_c, F_c);CHKERRQ(ierr);
1084742fe5e2SPeter Brune 
1085293a7e31SPeter Brune     ierr = VecAXPY(B_c, 1.0, F_c);CHKERRQ(ierr);                               /* add F_c(X) to the RHS */
1086c90fad12SPeter Brune 
1087ee78dd50SPeter Brune     /* set initial guess of the coarse problem to the projected fine solution */
1088ee78dd50SPeter Brune     ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr);
1089c90fad12SPeter Brune 
1090c90fad12SPeter Brune     /* recurse to the next level */
1091f5a6d4f9SBarry Smith     fas->next->vec_rhs = B_c;
1092742fe5e2SPeter Brune     /* ierr = FASCycle_Private(fas->next, X_c);CHKERRQ(ierr); */
1093742fe5e2SPeter Brune     ierr = SNESSolve(fas->next, B_c, X_c);CHKERRQ(ierr);
1094742fe5e2SPeter Brune     ierr = SNESGetConvergedReason(fas->next,&reason);CHKERRQ(ierr);
1095742fe5e2SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
1096742fe5e2SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
1097742fe5e2SPeter Brune       PetscFunctionReturn(0);
1098742fe5e2SPeter Brune     }
1099742fe5e2SPeter Brune     /* fas->next->vec_rhs = PETSC_NULL; */
1100ee78dd50SPeter Brune 
1101fa9694d7SPeter Brune     /* correct as x <- x + I(x^c - Rx)*/
1102fa9694d7SPeter Brune     ierr = VecAXPY(X_c, -1.0, Xo_c);CHKERRQ(ierr);
110339bd7f45SPeter Brune     ierr = MatInterpolateAdd(fas->interpolate, X_c, X, X_new);CHKERRQ(ierr);
1104293a7e31SPeter Brune   }
110539bd7f45SPeter Brune   PetscFunctionReturn(0);
110639bd7f45SPeter Brune }
110739bd7f45SPeter Brune 
110839bd7f45SPeter Brune #undef __FUNCT__
110939bd7f45SPeter Brune #define __FUNCT__ "FASCycle_Additive"
111039bd7f45SPeter Brune /*
111139bd7f45SPeter Brune 
111239bd7f45SPeter Brune The additive cycle looks like:
111339bd7f45SPeter Brune 
111407144faaSPeter Brune xhat = x
111507144faaSPeter Brune xhat = dS(x, b)
111607144faaSPeter Brune x = coarsecorrection(xhat, b_d)
111707144faaSPeter Brune x = x + nu*(xhat - x);
111839bd7f45SPeter Brune (optional) x = uS(x, b)
111939bd7f45SPeter Brune 
112039bd7f45SPeter Brune With the coarse RHS (defect correction) as below.
112139bd7f45SPeter Brune 
112239bd7f45SPeter Brune  */
112339bd7f45SPeter Brune PetscErrorCode FASCycle_Additive(SNES snes, Vec X) {
112407144faaSPeter Brune   Vec                 F, B, Xhat;
1125ddebd997SPeter Brune   Vec                 X_c, Xo_c, F_c, B_c, G, W;
112639bd7f45SPeter Brune   PetscErrorCode      ierr;
112707144faaSPeter Brune   SNES_FAS *          fas = (SNES_FAS *)snes->data;
112807144faaSPeter Brune   SNESConvergedReason reason;
1129ddebd997SPeter Brune   PetscReal           xnorm = 0., fnorm = 0., gnorm = 0., ynorm = 0.;
1130ddebd997SPeter Brune   PetscBool           lssucceed;
113139bd7f45SPeter Brune   PetscFunctionBegin;
113239bd7f45SPeter Brune 
113339bd7f45SPeter Brune   F = snes->vec_func;
113439bd7f45SPeter Brune   B = snes->vec_rhs;
113507144faaSPeter Brune   Xhat = snes->work[1];
1136ddebd997SPeter Brune   G    = snes->work[2];
1137ddebd997SPeter Brune   W    = snes->work[3];
113807144faaSPeter Brune   ierr = VecCopy(X, Xhat);CHKERRQ(ierr);
113907144faaSPeter Brune   /* recurse first */
114007144faaSPeter Brune   if (fas->next) {
114107144faaSPeter Brune     ierr = SNESComputeFunction(snes, Xhat, F);CHKERRQ(ierr);
114239bd7f45SPeter Brune 
114307144faaSPeter Brune     X_c  = fas->next->vec_sol;
114407144faaSPeter Brune     Xo_c = fas->next->work[0];
114507144faaSPeter Brune     F_c  = fas->next->vec_func;
114607144faaSPeter Brune     B_c  = fas->next->vec_rhs;
114739bd7f45SPeter Brune 
114807144faaSPeter Brune     /* inject the solution */
114907144faaSPeter Brune     if (fas->inject) {
115007144faaSPeter Brune       ierr = MatRestrict(fas->inject, Xhat, Xo_c);CHKERRQ(ierr);
115107144faaSPeter Brune     } else {
115207144faaSPeter Brune       ierr = MatRestrict(fas->restrct, Xhat, Xo_c);CHKERRQ(ierr);
115307144faaSPeter Brune       ierr = VecPointwiseMult(Xo_c, fas->rscale, Xo_c);CHKERRQ(ierr);
115407144faaSPeter Brune     }
115507144faaSPeter Brune     ierr = VecScale(F, -1.0);CHKERRQ(ierr);
115607144faaSPeter Brune 
115707144faaSPeter Brune     /* restrict the defect */
115807144faaSPeter Brune     ierr = MatRestrict(fas->restrct, F, B_c);CHKERRQ(ierr);
115907144faaSPeter Brune 
116007144faaSPeter Brune     /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */
116107144faaSPeter Brune     fas->next->vec_rhs = PETSC_NULL;                                           /*unset the RHS to evaluate function instead of residual*/
116207144faaSPeter Brune     ierr = SNESComputeFunction(fas->next, Xo_c, F_c);CHKERRQ(ierr);
116307144faaSPeter Brune 
116407144faaSPeter Brune     ierr = VecAXPY(B_c, 1.0, F_c);CHKERRQ(ierr);                               /* add F_c(X) to the RHS */
116507144faaSPeter Brune 
116607144faaSPeter Brune     /* set initial guess of the coarse problem to the projected fine solution */
116707144faaSPeter Brune     ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr);
116807144faaSPeter Brune 
116907144faaSPeter Brune     /* recurse */
117007144faaSPeter Brune     fas->next->vec_rhs = B_c;
117107144faaSPeter Brune     ierr = SNESSolve(fas->next, B_c, X_c);CHKERRQ(ierr);
117207144faaSPeter Brune 
117307144faaSPeter Brune     /* smooth on this level */
117407144faaSPeter Brune     ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr);
117507144faaSPeter Brune 
117607144faaSPeter Brune    ierr = SNESGetConvergedReason(fas->next,&reason);CHKERRQ(ierr);
117707144faaSPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
117807144faaSPeter Brune       snes->reason = SNES_DIVERGED_INNER;
117907144faaSPeter Brune       PetscFunctionReturn(0);
118007144faaSPeter Brune     }
118107144faaSPeter Brune 
118207144faaSPeter Brune     /* correct as x <- x + I(x^c - Rx)*/
118307144faaSPeter Brune     ierr = VecAXPY(X_c, -1.0, Xo_c);CHKERRQ(ierr);
1184ddebd997SPeter Brune     ierr = MatInterpolate(fas->interpolate, X_c, Xhat);CHKERRQ(ierr);
118507144faaSPeter Brune 
1186ddebd997SPeter Brune     /* additive correction of the coarse direction*/
1187ddebd997SPeter Brune     ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
1188ddebd997SPeter Brune     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
1189eb1825c3SPeter Brune     ierr = VecScale(Xhat, -1.0);CHKERRQ(ierr);
1190ddebd997SPeter Brune     ierr = (*snes->ops->linesearch)(snes,snes->lsP,X,F,Xhat,fnorm,xnorm,G,W,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
1191ddebd997SPeter Brune     ierr = VecCopy(W, X);CHKERRQ(ierr);
1192ddebd997SPeter Brune     ierr = VecCopy(G, F);CHKERRQ(ierr);
1193ddebd997SPeter Brune     fnorm = gnorm;
119407144faaSPeter Brune   } else {
119507144faaSPeter Brune     ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr);
119607144faaSPeter Brune   }
119739bd7f45SPeter Brune   PetscFunctionReturn(0);
119839bd7f45SPeter Brune }
119939bd7f45SPeter Brune 
120039bd7f45SPeter Brune #undef __FUNCT__
120139bd7f45SPeter Brune #define __FUNCT__ "FASCycle_Multiplicative"
120239bd7f45SPeter Brune /*
120339bd7f45SPeter Brune 
120439bd7f45SPeter Brune Defines the FAS cycle as:
120539bd7f45SPeter Brune 
120639bd7f45SPeter Brune fine problem: F(x) = 0
120739bd7f45SPeter Brune coarse problem: F^c(x) = b^c
120839bd7f45SPeter Brune 
120939bd7f45SPeter Brune b^c = F^c(I^c_fx^f - I^c_fF(x))
121039bd7f45SPeter Brune 
121139bd7f45SPeter Brune correction:
121239bd7f45SPeter Brune 
121339bd7f45SPeter Brune x = x + I(x^c - Rx)
121439bd7f45SPeter Brune 
121539bd7f45SPeter Brune  */
121639bd7f45SPeter Brune PetscErrorCode FASCycle_Multiplicative(SNES snes, Vec X) {
121739bd7f45SPeter Brune 
121839bd7f45SPeter Brune   PetscErrorCode      ierr;
121939bd7f45SPeter Brune   Vec                 F,B;
122039bd7f45SPeter Brune   SNES_FAS            *fas = (SNES_FAS *)snes->data;
122139bd7f45SPeter Brune 
122239bd7f45SPeter Brune   PetscFunctionBegin;
122339bd7f45SPeter Brune   F = snes->vec_func;
122439bd7f45SPeter Brune   B = snes->vec_rhs;
122539bd7f45SPeter Brune   /* pre-smooth -- just update using the pre-smoother */
122639bd7f45SPeter Brune   ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr);
122739bd7f45SPeter Brune 
122839a4b097SPeter Brune   ierr = FASCoarseCorrection(snes, X, F, X);CHKERRQ(ierr);
122939bd7f45SPeter Brune 
1230c90fad12SPeter Brune   if (fas->level != 0) {
123139bd7f45SPeter Brune     ierr = FASUpSmooth(snes, B, X, F);CHKERRQ(ierr);
1232fe6f9142SPeter Brune   }
1233fe6f9142SPeter Brune   ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
1234fa9694d7SPeter Brune 
1235fa9694d7SPeter Brune   PetscFunctionReturn(0);
1236421d9b32SPeter Brune }
1237421d9b32SPeter Brune 
1238421d9b32SPeter Brune #undef __FUNCT__
1239421d9b32SPeter Brune #define __FUNCT__ "SNESSolve_FAS"
1240421d9b32SPeter Brune 
1241421d9b32SPeter Brune PetscErrorCode SNESSolve_FAS(SNES snes)
1242421d9b32SPeter Brune {
1243fa9694d7SPeter Brune   PetscErrorCode ierr;
1244fe6f9142SPeter Brune   PetscInt       i, maxits;
1245ddb5aff1SPeter Brune   Vec            X, F;
1246fe6f9142SPeter Brune   PetscReal      fnorm;
124707144faaSPeter Brune   SNES_FAS       *fas = (SNES_FAS *)snes->data;
1248421d9b32SPeter Brune   PetscFunctionBegin;
1249fe6f9142SPeter Brune   maxits = snes->max_its;            /* maximum number of iterations */
1250fe6f9142SPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
1251fa9694d7SPeter Brune   X = snes->vec_sol;
1252f5a6d4f9SBarry Smith   F = snes->vec_func;
1253293a7e31SPeter Brune 
1254293a7e31SPeter Brune   /*norm setup */
1255fe6f9142SPeter Brune   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
1256fe6f9142SPeter Brune   snes->iter = 0;
1257fe6f9142SPeter Brune   snes->norm = 0.;
1258fe6f9142SPeter Brune   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
1259fe6f9142SPeter Brune   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
1260fe6f9142SPeter Brune   if (snes->domainerror) {
1261fe6f9142SPeter Brune     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
1262fe6f9142SPeter Brune     PetscFunctionReturn(0);
1263fe6f9142SPeter Brune   }
1264fe6f9142SPeter Brune   ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
1265fe6f9142SPeter Brune   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm");
1266fe6f9142SPeter Brune   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
1267fe6f9142SPeter Brune   snes->norm = fnorm;
1268fe6f9142SPeter Brune   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
1269fe6f9142SPeter Brune   SNESLogConvHistory(snes,fnorm,0);
1270fe6f9142SPeter Brune   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
1271fe6f9142SPeter Brune 
1272fe6f9142SPeter Brune   /* set parameter for default relative tolerance convergence test */
1273fe6f9142SPeter Brune   snes->ttol = fnorm*snes->rtol;
1274fe6f9142SPeter Brune   /* test convergence */
1275fe6f9142SPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
1276fe6f9142SPeter Brune   if (snes->reason) PetscFunctionReturn(0);
1277fe6f9142SPeter Brune   for (i = 0; i < maxits; i++) {
1278fe6f9142SPeter Brune     /* Call general purpose update function */
1279646217ecSPeter Brune 
1280fe6f9142SPeter Brune     if (snes->ops->update) {
1281fe6f9142SPeter Brune       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
1282fe6f9142SPeter Brune     }
128307144faaSPeter Brune     if (fas->fastype == SNES_FAS_MULTIPLICATIVE) {
128439bd7f45SPeter Brune       ierr = FASCycle_Multiplicative(snes, X);CHKERRQ(ierr);
128507144faaSPeter Brune     } else {
128607144faaSPeter Brune       ierr = FASCycle_Additive(snes, X);CHKERRQ(ierr);
128707144faaSPeter Brune     }
1288742fe5e2SPeter Brune 
1289742fe5e2SPeter Brune     /* check for FAS cycle divergence */
1290742fe5e2SPeter Brune     if (snes->reason != SNES_CONVERGED_ITERATING) {
1291742fe5e2SPeter Brune       PetscFunctionReturn(0);
1292742fe5e2SPeter Brune     }
1293c90fad12SPeter Brune     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
1294c90fad12SPeter Brune     /* Monitor convergence */
1295c90fad12SPeter Brune     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
1296c90fad12SPeter Brune     snes->iter = i+1;
1297c90fad12SPeter Brune     snes->norm = fnorm;
1298c90fad12SPeter Brune     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
1299c90fad12SPeter Brune     SNESLogConvHistory(snes,snes->norm,0);
1300c90fad12SPeter Brune     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
1301c90fad12SPeter Brune     /* Test for convergence */
1302c90fad12SPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
1303c90fad12SPeter Brune     if (snes->reason) break;
1304fe6f9142SPeter Brune   }
1305fe6f9142SPeter Brune   if (i == maxits) {
1306fe6f9142SPeter Brune     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr);
1307fe6f9142SPeter Brune     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
1308fe6f9142SPeter Brune   }
1309421d9b32SPeter Brune   PetscFunctionReturn(0);
1310421d9b32SPeter Brune }
1311