xref: /petsc/src/snes/impls/fas/fas.c (revision 23e688936a8b563ddcb7762e15d61227cc6035fc)
1421d9b32SPeter Brune /* Defines the basic SNES object */
2a055c8caSBarry Smith #include <../src/snes/impls/fas/fasimpls.h>    /*I  "petscsnes.h"  I*/
3421d9b32SPeter Brune 
434d65b3cSPeter Brune const char *const SNESFASTypes[] = {"MULTIPLICATIVE","ADDITIVE","FULL","KASKADE","SNESFASType","SNES_FAS",0};
507144faaSPeter Brune 
66273346dSPeter Brune extern PetscErrorCode SNESFASGalerkinDefaultFunction(SNES,Vec,Vec,void*);
7efe1f98aSPeter Brune 
840244768SBarry Smith static PetscErrorCode SNESReset_FAS(SNES snes)
9421d9b32SPeter Brune {
1077df8cc4SPeter Brune   PetscErrorCode ierr  = 0;
11421d9b32SPeter Brune   SNES_FAS       * fas = (SNES_FAS*)snes->data;
12421d9b32SPeter Brune 
13421d9b32SPeter Brune   PetscFunctionBegin;
14ab8d36c9SPeter Brune   ierr = SNESDestroy(&fas->smoothu);CHKERRQ(ierr);
15ab8d36c9SPeter Brune   ierr = SNESDestroy(&fas->smoothd);CHKERRQ(ierr);
163dccd265SPeter Brune   ierr = MatDestroy(&fas->inject);CHKERRQ(ierr);
17bccf9bb3SJed Brown   ierr = MatDestroy(&fas->interpolate);CHKERRQ(ierr);
18bccf9bb3SJed Brown   ierr = MatDestroy(&fas->restrct);CHKERRQ(ierr);
19bccf9bb3SJed Brown   ierr = VecDestroy(&fas->rscale);CHKERRQ(ierr);
207cd33a7bSPeter Brune   if (fas->galerkin) {
217cd33a7bSPeter Brune     ierr = VecDestroy(&fas->Xg);CHKERRQ(ierr);
227cd33a7bSPeter Brune     ierr = VecDestroy(&fas->Fg);CHKERRQ(ierr);
237cd33a7bSPeter Brune   }
24d477d801SPeter Brune   if (fas->next) {ierr = SNESReset(fas->next);CHKERRQ(ierr);}
25421d9b32SPeter Brune   PetscFunctionReturn(0);
26421d9b32SPeter Brune }
27421d9b32SPeter Brune 
2840244768SBarry Smith static PetscErrorCode SNESDestroy_FAS(SNES snes)
29421d9b32SPeter Brune {
30421d9b32SPeter Brune   SNES_FAS       * fas = (SNES_FAS*)snes->data;
31742fe5e2SPeter Brune   PetscErrorCode ierr  = 0;
32421d9b32SPeter Brune 
33421d9b32SPeter Brune   PetscFunctionBegin;
34421d9b32SPeter Brune   /* recursively resets and then destroys */
3579d9a41aSPeter Brune   ierr = SNESReset(snes);CHKERRQ(ierr);
361aa26658SKarl Rupp   if (fas->next) {
371aa26658SKarl Rupp     ierr = SNESDestroy(&fas->next);CHKERRQ(ierr);
381aa26658SKarl Rupp   }
39421d9b32SPeter Brune   ierr = PetscFree(fas);CHKERRQ(ierr);
40421d9b32SPeter Brune   PetscFunctionReturn(0);
41421d9b32SPeter Brune }
42421d9b32SPeter Brune 
4340244768SBarry Smith static PetscErrorCode SNESSetUp_FAS(SNES snes)
44421d9b32SPeter Brune {
4548bfdf8aSPeter Brune   SNES_FAS       *fas = (SNES_FAS*) snes->data;
46421d9b32SPeter Brune   PetscErrorCode ierr;
47d1adcc6fSPeter Brune   PetscInt       dm_levels;
483dccd265SPeter Brune   Vec            vec_sol, vec_func, vec_sol_update, vec_rhs; /* preserve these if they're set through the reset */
49ab8d36c9SPeter Brune   SNES           next;
500a7266b2SPatrick Farrell   PetscBool      isFine, hasCreateRestriction;
51f89ba88eSPeter Brune   SNESLineSearch linesearch;
52f89ba88eSPeter Brune   SNESLineSearch slinesearch;
53f89ba88eSPeter Brune   void           *lsprectx,*lspostctx;
546b2b7091SBarry Smith   PetscErrorCode (*precheck)(SNESLineSearch,Vec,Vec,PetscBool*,void*);
556b2b7091SBarry Smith   PetscErrorCode (*postcheck)(SNESLineSearch,Vec,Vec,Vec,PetscBool*,PetscBool*,void*);
56eff52c0eSPeter Brune 
576b2b7091SBarry Smith   PetscFunctionBegin;
58ab8d36c9SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
59ab8d36c9SPeter Brune   if (fas->usedmfornumberoflevels && isFine) {
60d1adcc6fSPeter Brune     ierr = DMGetRefineLevel(snes->dm,&dm_levels);CHKERRQ(ierr);
61d1adcc6fSPeter Brune     dm_levels++;
62cc05f883SPeter Brune     if (dm_levels > fas->levels) {
632e8ce248SJed Brown       /* we don't want the solution and func vectors to be destroyed in the SNESReset when it's called in SNESFASSetLevels_FAS*/
643dccd265SPeter Brune       vec_sol              = snes->vec_sol;
653dccd265SPeter Brune       vec_func             = snes->vec_func;
663dccd265SPeter Brune       vec_sol_update       = snes->vec_sol_update;
673dccd265SPeter Brune       vec_rhs              = snes->vec_rhs;
680298fd71SBarry Smith       snes->vec_sol        = NULL;
690298fd71SBarry Smith       snes->vec_func       = NULL;
700298fd71SBarry Smith       snes->vec_sol_update = NULL;
710298fd71SBarry Smith       snes->vec_rhs        = NULL;
723dccd265SPeter Brune 
733dccd265SPeter Brune       /* reset the number of levels */
740298fd71SBarry Smith       ierr = SNESFASSetLevels(snes,dm_levels,NULL);CHKERRQ(ierr);
75cc05f883SPeter Brune       ierr = SNESSetFromOptions(snes);CHKERRQ(ierr);
763dccd265SPeter Brune 
773dccd265SPeter Brune       snes->vec_sol        = vec_sol;
783dccd265SPeter Brune       snes->vec_func       = vec_func;
793dccd265SPeter Brune       snes->vec_rhs        = vec_rhs;
803dccd265SPeter Brune       snes->vec_sol_update = vec_sol_update;
81d1adcc6fSPeter Brune     }
82d1adcc6fSPeter Brune   }
83ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
84ab8d36c9SPeter Brune   if (!isFine) snes->gridsequence = 0; /* no grid sequencing inside the multigrid hierarchy! */
853dccd265SPeter Brune 
86fa0ddf94SBarry Smith   ierr = SNESSetWorkVecs(snes, 2);CHKERRQ(ierr); /* work vectors used for intergrid transfers */
87cc05f883SPeter Brune 
88ab8d36c9SPeter Brune   /* set up the smoothers if they haven't already been set up */
89ab8d36c9SPeter Brune   if (!fas->smoothd) {
90ab8d36c9SPeter Brune     ierr = SNESFASCycleCreateSmoother_Private(snes, &fas->smoothd);CHKERRQ(ierr);
91ab8d36c9SPeter Brune   }
92ab8d36c9SPeter Brune 
9379d9a41aSPeter Brune   if (snes->dm) {
94ab8d36c9SPeter Brune     /* set the smoother DMs properly */
95ab8d36c9SPeter Brune     if (fas->smoothu) ierr = SNESSetDM(fas->smoothu, snes->dm);CHKERRQ(ierr);
96ab8d36c9SPeter Brune     ierr = SNESSetDM(fas->smoothd, snes->dm);CHKERRQ(ierr);
9779d9a41aSPeter Brune     /* construct EVERYTHING from the DM -- including the progressive set of smoothers */
98ab8d36c9SPeter Brune     if (next) {
9979d9a41aSPeter Brune       /* for now -- assume the DM and the evaluation functions have been set externally */
100ab8d36c9SPeter Brune       if (!next->dm) {
101ce94432eSBarry Smith         ierr = DMCoarsen(snes->dm, PetscObjectComm((PetscObject)next), &next->dm);CHKERRQ(ierr);
102ab8d36c9SPeter Brune         ierr = SNESSetDM(next, next->dm);CHKERRQ(ierr);
10379d9a41aSPeter Brune       }
10479d9a41aSPeter Brune       /* set the interpolation and restriction from the DM */
10579d9a41aSPeter Brune       if (!fas->interpolate) {
106ab8d36c9SPeter Brune         ierr = DMCreateInterpolation(next->dm, snes->dm, &fas->interpolate, &fas->rscale);CHKERRQ(ierr);
107bccf9bb3SJed Brown         if (!fas->restrct) {
1080a7266b2SPatrick Farrell           ierr = DMHasCreateRestriction(next->dm, &hasCreateRestriction);CHKERRQ(ierr);
1090a7266b2SPatrick Farrell           /* DM can create restrictions, use that */
1100a7266b2SPatrick Farrell           if (hasCreateRestriction) {
1110a7266b2SPatrick Farrell             ierr = DMCreateRestriction(next->dm, snes->dm, &fas->restrct);CHKERRQ(ierr);
1120a7266b2SPatrick Farrell           } else {
113bccf9bb3SJed Brown             ierr         = PetscObjectReference((PetscObject)fas->interpolate);CHKERRQ(ierr);
11479d9a41aSPeter Brune             fas->restrct = fas->interpolate;
11579d9a41aSPeter Brune           }
116bccf9bb3SJed Brown         }
1170a7266b2SPatrick Farrell       }
11879d9a41aSPeter Brune       /* set the injection from the DM */
11979d9a41aSPeter Brune       if (!fas->inject) {
120*23e68893SLawrence Mitchell         PetscBool flg;
121*23e68893SLawrence Mitchell         ierr = DMHasCreateInjection(next->dm, &flg);CHKERRQ(ierr);
122*23e68893SLawrence Mitchell         if (flg) {
1236dbf9973SLawrence Mitchell           ierr = DMCreateInjection(next->dm, snes->dm, &fas->inject);CHKERRQ(ierr);
12479d9a41aSPeter Brune         }
12579d9a41aSPeter Brune       }
12679d9a41aSPeter Brune     }
127*23e68893SLawrence Mitchell   }
12879d9a41aSPeter Brune   /*pass the smoother, function, and jacobian up to the next level if it's not user set already */
12979d9a41aSPeter Brune   if (fas->galerkin) {
1301aa26658SKarl Rupp     if (next) {
1310298fd71SBarry Smith       ierr = SNESSetFunction(next, NULL, SNESFASGalerkinDefaultFunction, next);CHKERRQ(ierr);
1321aa26658SKarl Rupp     }
1331aa26658SKarl Rupp     if (fas->smoothd && fas->level != fas->levels - 1) {
1340298fd71SBarry Smith       ierr = SNESSetFunction(fas->smoothd, NULL, SNESFASGalerkinDefaultFunction, snes);CHKERRQ(ierr);
1351aa26658SKarl Rupp     }
1361aa26658SKarl Rupp     if (fas->smoothu && fas->level != fas->levels - 1) {
1370298fd71SBarry Smith       ierr = SNESSetFunction(fas->smoothu, NULL, SNESFASGalerkinDefaultFunction, snes);CHKERRQ(ierr);
1381aa26658SKarl Rupp     }
13979d9a41aSPeter Brune   }
14079d9a41aSPeter Brune 
141534ebe21SPeter Brune   /* sets the down (pre) smoother's default norm and sets it from options */
142534ebe21SPeter Brune   if (fas->smoothd) {
143bc3f2f05SPeter Brune     if (fas->level == 0 && fas->levels != 1) {
144365a6726SPeter Brune       ierr = SNESSetNormSchedule(fas->smoothd, SNES_NORM_NONE);CHKERRQ(ierr);
145534ebe21SPeter Brune     } else {
146365a6726SPeter Brune       ierr = SNESSetNormSchedule(fas->smoothd, SNES_NORM_FINAL_ONLY);CHKERRQ(ierr);
147534ebe21SPeter Brune     }
1487fce8c19SPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)snes, (PetscObject)fas->smoothd);CHKERRQ(ierr);
149534ebe21SPeter Brune     ierr = SNESSetFromOptions(fas->smoothd);CHKERRQ(ierr);
1507601faf0SJed Brown     ierr = SNESGetLineSearch(snes,&linesearch);CHKERRQ(ierr);
1517601faf0SJed Brown     ierr = SNESGetLineSearch(fas->smoothd,&slinesearch);CHKERRQ(ierr);
1526b2b7091SBarry Smith     ierr = SNESLineSearchGetPreCheck(linesearch,&precheck,&lsprectx);CHKERRQ(ierr);
1536b2b7091SBarry Smith     ierr = SNESLineSearchGetPostCheck(linesearch,&postcheck,&lspostctx);CHKERRQ(ierr);
1546b2b7091SBarry Smith     ierr = SNESLineSearchSetPreCheck(slinesearch,precheck,lsprectx);CHKERRQ(ierr);
1556b2b7091SBarry Smith     ierr = SNESLineSearchSetPostCheck(slinesearch,postcheck,lspostctx);CHKERRQ(ierr);
156f89ba88eSPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)linesearch, (PetscObject)slinesearch);CHKERRQ(ierr);
1570dd27c6cSPeter Brune 
1580dd27c6cSPeter Brune     fas->smoothd->vec_sol        = snes->vec_sol;
1590dd27c6cSPeter Brune     ierr                         = PetscObjectReference((PetscObject)snes->vec_sol);CHKERRQ(ierr);
1600dd27c6cSPeter Brune     fas->smoothd->vec_sol_update = snes->vec_sol_update;
1610dd27c6cSPeter Brune     ierr                         = PetscObjectReference((PetscObject)snes->vec_sol_update);CHKERRQ(ierr);
1620dd27c6cSPeter Brune     fas->smoothd->vec_func       = snes->vec_func;
1630dd27c6cSPeter Brune     ierr                         = PetscObjectReference((PetscObject)snes->vec_func);CHKERRQ(ierr);
1640dd27c6cSPeter Brune 
1650dd27c6cSPeter Brune     if (fas->eventsmoothsetup) {ierr = PetscLogEventBegin(fas->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
1660dd27c6cSPeter Brune     ierr = SNESSetUp(fas->smoothd);CHKERRQ(ierr);
1670dd27c6cSPeter Brune     if (fas->eventsmoothsetup) {ierr = PetscLogEventEnd(fas->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
168534ebe21SPeter Brune   }
169534ebe21SPeter Brune 
170534ebe21SPeter Brune   /* sets the up (post) smoother's default norm and sets it from options */
171534ebe21SPeter Brune   if (fas->smoothu) {
172534ebe21SPeter Brune     if (fas->level != fas->levels - 1) {
173365a6726SPeter Brune       ierr = SNESSetNormSchedule(fas->smoothu, SNES_NORM_NONE);CHKERRQ(ierr);
174534ebe21SPeter Brune     } else {
175365a6726SPeter Brune       ierr = SNESSetNormSchedule(fas->smoothu, SNES_NORM_FINAL_ONLY);CHKERRQ(ierr);
176534ebe21SPeter Brune     }
1777fce8c19SPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)snes, (PetscObject)fas->smoothu);CHKERRQ(ierr);
178534ebe21SPeter Brune     ierr = SNESSetFromOptions(fas->smoothu);CHKERRQ(ierr);
1797601faf0SJed Brown     ierr = SNESGetLineSearch(snes,&linesearch);CHKERRQ(ierr);
1807601faf0SJed Brown     ierr = SNESGetLineSearch(fas->smoothu,&slinesearch);CHKERRQ(ierr);
1816b2b7091SBarry Smith     ierr = SNESLineSearchGetPreCheck(linesearch,&precheck,&lsprectx);CHKERRQ(ierr);
1826b2b7091SBarry Smith     ierr = SNESLineSearchGetPostCheck(linesearch,&postcheck,&lspostctx);CHKERRQ(ierr);
1836b2b7091SBarry Smith     ierr = SNESLineSearchSetPreCheck(slinesearch,precheck,lsprectx);CHKERRQ(ierr);
1846b2b7091SBarry Smith     ierr = SNESLineSearchSetPostCheck(slinesearch,postcheck,lspostctx);CHKERRQ(ierr);
185f89ba88eSPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)linesearch, (PetscObject)slinesearch);CHKERRQ(ierr);
1860dd27c6cSPeter Brune 
1870dd27c6cSPeter Brune     fas->smoothu->vec_sol        = snes->vec_sol;
1880dd27c6cSPeter Brune     ierr                         = PetscObjectReference((PetscObject)snes->vec_sol);CHKERRQ(ierr);
1890dd27c6cSPeter Brune     fas->smoothu->vec_sol_update = snes->vec_sol_update;
1900dd27c6cSPeter Brune     ierr                         = PetscObjectReference((PetscObject)snes->vec_sol_update);CHKERRQ(ierr);
1910dd27c6cSPeter Brune     fas->smoothu->vec_func       = snes->vec_func;
1920dd27c6cSPeter Brune     ierr                         = PetscObjectReference((PetscObject)snes->vec_func);CHKERRQ(ierr);
1930dd27c6cSPeter Brune 
1940dd27c6cSPeter Brune     if (fas->eventsmoothsetup) {ierr = PetscLogEventBegin(fas->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
1950dd27c6cSPeter Brune     ierr = SNESSetUp(fas->smoothu);CHKERRQ(ierr);
1960dd27c6cSPeter Brune     if (fas->eventsmoothsetup) {ierr = PetscLogEventEnd(fas->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
1970dd27c6cSPeter Brune 
198534ebe21SPeter Brune   }
199d06165b7SPeter Brune 
200ab8d36c9SPeter Brune   if (next) {
20179d9a41aSPeter Brune     /* gotta set up the solution vector for this to work */
202ab8d36c9SPeter Brune     if (!next->vec_sol) {ierr = SNESFASCreateCoarseVec(snes,&next->vec_sol);CHKERRQ(ierr);}
203ab8d36c9SPeter Brune     if (!next->vec_rhs) {ierr = SNESFASCreateCoarseVec(snes,&next->vec_rhs);CHKERRQ(ierr);}
2047fce8c19SPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)snes, (PetscObject)next);CHKERRQ(ierr);
2057601faf0SJed Brown     ierr = SNESGetLineSearch(snes,&linesearch);CHKERRQ(ierr);
2067601faf0SJed Brown     ierr = SNESGetLineSearch(fas->next,&slinesearch);CHKERRQ(ierr);
2076b2b7091SBarry Smith     ierr = SNESLineSearchGetPreCheck(linesearch,&precheck,&lsprectx);CHKERRQ(ierr);
2086b2b7091SBarry Smith     ierr = SNESLineSearchGetPostCheck(linesearch,&postcheck,&lspostctx);CHKERRQ(ierr);
2096b2b7091SBarry Smith     ierr = SNESLineSearchSetPreCheck(slinesearch,precheck,lsprectx);CHKERRQ(ierr);
2106b2b7091SBarry Smith     ierr = SNESLineSearchSetPostCheck(slinesearch,postcheck,lspostctx);CHKERRQ(ierr);
211f89ba88eSPeter Brune     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)linesearch, (PetscObject)slinesearch);CHKERRQ(ierr);
212ab8d36c9SPeter Brune     ierr = SNESSetUp(next);CHKERRQ(ierr);
21379d9a41aSPeter Brune   }
2146273346dSPeter Brune   /* setup FAS work vectors */
2156273346dSPeter Brune   if (fas->galerkin) {
2166273346dSPeter Brune     ierr = VecDuplicate(snes->vec_sol, &fas->Xg);CHKERRQ(ierr);
2176273346dSPeter Brune     ierr = VecDuplicate(snes->vec_sol, &fas->Fg);CHKERRQ(ierr);
2186273346dSPeter Brune   }
219421d9b32SPeter Brune   PetscFunctionReturn(0);
220421d9b32SPeter Brune }
221421d9b32SPeter Brune 
22240244768SBarry Smith static PetscErrorCode SNESSetFromOptions_FAS(PetscOptionItems *PetscOptionsObject,SNES snes)
223421d9b32SPeter Brune {
224ee78dd50SPeter Brune   SNES_FAS       *fas   = (SNES_FAS*) snes->data;
225ee78dd50SPeter Brune   PetscInt       levels = 1;
22687f44e3fSPeter Brune   PetscBool      flg    = PETSC_FALSE, upflg = PETSC_FALSE, downflg = PETSC_FALSE, monflg = PETSC_FALSE, galerkinflg = PETSC_FALSE,continuationflg = PETSC_FALSE;
227421d9b32SPeter Brune   PetscErrorCode ierr;
22807144faaSPeter Brune   SNESFASType    fastype;
229fde0ff24SPeter Brune   const char     *optionsprefix;
230f1c6b773SPeter Brune   SNESLineSearch linesearch;
23166585501SPeter Brune   PetscInt       m, n_up, n_down;
232ab8d36c9SPeter Brune   SNES           next;
233ab8d36c9SPeter Brune   PetscBool      isFine;
234421d9b32SPeter Brune 
235421d9b32SPeter Brune   PetscFunctionBegin;
236ab8d36c9SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
237e55864a3SBarry Smith   ierr = PetscOptionsHead(PetscOptionsObject,"SNESFAS Options-----------------------------------");CHKERRQ(ierr);
238ee78dd50SPeter Brune 
239ab8d36c9SPeter Brune   /* number of levels -- only process most options on the finest level */
240ab8d36c9SPeter Brune   if (isFine) {
241ee78dd50SPeter Brune     ierr = PetscOptionsInt("-snes_fas_levels", "Number of Levels", "SNESFASSetLevels", levels, &levels, &flg);CHKERRQ(ierr);
242c732cbdbSBarry Smith     if (!flg && snes->dm) {
243c732cbdbSBarry Smith       ierr = DMGetRefineLevel(snes->dm,&levels);CHKERRQ(ierr);
244c732cbdbSBarry Smith       levels++;
245d1adcc6fSPeter Brune       fas->usedmfornumberoflevels = PETSC_TRUE;
246c732cbdbSBarry Smith     }
2470298fd71SBarry Smith     ierr    = SNESFASSetLevels(snes, levels, NULL);CHKERRQ(ierr);
24807144faaSPeter Brune     fastype = fas->fastype;
24907144faaSPeter Brune     ierr    = PetscOptionsEnum("-snes_fas_type","FAS correction type","SNESFASSetType",SNESFASTypes,(PetscEnum)fastype,(PetscEnum*)&fastype,&flg);CHKERRQ(ierr);
25007144faaSPeter Brune     if (flg) {
25107144faaSPeter Brune       ierr = SNESFASSetType(snes, fastype);CHKERRQ(ierr);
25207144faaSPeter Brune     }
253ee78dd50SPeter Brune 
254fde0ff24SPeter Brune     ierr = SNESGetOptionsPrefix(snes, &optionsprefix);CHKERRQ(ierr);
255ab8d36c9SPeter Brune     ierr = PetscOptionsInt("-snes_fas_cycles","Number of cycles","SNESFASSetCycles",fas->n_cycles,&m,&flg);CHKERRQ(ierr);
256ab8d36c9SPeter Brune     if (flg) {
257ab8d36c9SPeter Brune       ierr = SNESFASSetCycles(snes, m);CHKERRQ(ierr);
258fde0ff24SPeter Brune     }
25987f44e3fSPeter Brune     ierr = PetscOptionsBool("-snes_fas_continuation","Corrected grid-sequence continuation","SNESFASSetContinuation",fas->continuation,&continuationflg,&flg);CHKERRQ(ierr);
26087f44e3fSPeter Brune     if (flg) {
26187f44e3fSPeter Brune       ierr = SNESFASSetContinuation(snes,continuationflg);CHKERRQ(ierr);
26287f44e3fSPeter Brune     }
263fde0ff24SPeter Brune 
264ab8d36c9SPeter Brune     ierr = PetscOptionsBool("-snes_fas_galerkin", "Form coarse problems with Galerkin","SNESFASSetGalerkin",fas->galerkin,&galerkinflg,&flg);CHKERRQ(ierr);
265ab8d36c9SPeter Brune     if (flg) {
266ab8d36c9SPeter Brune       ierr = SNESFASSetGalerkin(snes, galerkinflg);CHKERRQ(ierr);
267ab8d36c9SPeter Brune     }
268ee78dd50SPeter Brune 
269928e959bSPeter Brune     if (fas->fastype == SNES_FAS_FULL) {
270928e959bSPeter Brune       ierr   = PetscOptionsBool("-snes_fas_full_downsweep","Smooth on the initial upsweep for full FAS cycles","SNESFASFullSetDownSweep",fas->full_downsweep,&fas->full_downsweep,&flg);CHKERRQ(ierr);
271928e959bSPeter Brune       if (flg) {SNESFASFullSetDownSweep(snes,fas->full_downsweep);CHKERRQ(ierr);}
272928e959bSPeter Brune     }
273928e959bSPeter Brune 
27466585501SPeter Brune     ierr = PetscOptionsInt("-snes_fas_smoothup","Number of post-smoothing steps","SNESFASSetNumberSmoothUp",fas->max_up_it,&n_up,&upflg);CHKERRQ(ierr);
275162d76ddSPeter Brune 
27666585501SPeter Brune     ierr = PetscOptionsInt("-snes_fas_smoothdown","Number of pre-smoothing steps","SNESFASSetNumberSmoothDown",fas->max_down_it,&n_down,&downflg);CHKERRQ(ierr);
277162d76ddSPeter Brune 
278d142ab34SLawrence Mitchell     {
279d142ab34SLawrence Mitchell       PetscViewer viewer;
280d142ab34SLawrence Mitchell       PetscViewerFormat format;
281d142ab34SLawrence Mitchell       ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject)snes),((PetscObject)snes)->prefix,
282d142ab34SLawrence Mitchell                                    "-snes_fas_monitor",&viewer,&format,&monflg);CHKERRQ(ierr);
283d142ab34SLawrence Mitchell       if (monflg) {
284d142ab34SLawrence Mitchell         PetscViewerAndFormat *vf;
285d142ab34SLawrence Mitchell         ierr = PetscViewerAndFormatCreate(viewer,format,&vf);CHKERRQ(ierr);
286d142ab34SLawrence Mitchell         ierr = PetscObjectDereference((PetscObject)viewer);CHKERRQ(ierr);
287d142ab34SLawrence Mitchell         ierr = SNESFASSetMonitor(snes,vf,PETSC_TRUE);CHKERRQ(ierr);
288d142ab34SLawrence Mitchell       }
289d142ab34SLawrence Mitchell     }
2900dd27c6cSPeter Brune     flg    = PETSC_FALSE;
2910dd27c6cSPeter Brune     monflg = PETSC_TRUE;
2920dd27c6cSPeter Brune     ierr   = PetscOptionsBool("-snes_fas_log","Log times for each FAS level","SNESFASSetLog",monflg,&monflg,&flg);CHKERRQ(ierr);
2930dd27c6cSPeter Brune     if (flg) {ierr = SNESFASSetLog(snes,monflg);CHKERRQ(ierr);}
294ab8d36c9SPeter Brune   }
295ee78dd50SPeter Brune 
296421d9b32SPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
2978cc86e31SPeter Brune   /* setup from the determined types if there is no pointwise procedure or smoother defined */
298162d76ddSPeter Brune   if (upflg) {
29966585501SPeter Brune     ierr = SNESFASSetNumberSmoothUp(snes,n_up);CHKERRQ(ierr);
300162d76ddSPeter Brune   }
301162d76ddSPeter Brune   if (downflg) {
30266585501SPeter Brune     ierr = SNESFASSetNumberSmoothDown(snes,n_down);CHKERRQ(ierr);
303162d76ddSPeter Brune   }
304eff52c0eSPeter Brune 
3059e764e56SPeter Brune   /* set up the default line search for coarse grid corrections */
3069e764e56SPeter Brune   if (fas->fastype == SNES_FAS_ADDITIVE) {
3079e764e56SPeter Brune     if (!snes->linesearch) {
3087601faf0SJed Brown       ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
3091a4f838cSPeter Brune       ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHL2);CHKERRQ(ierr);
3109e764e56SPeter Brune     }
3119e764e56SPeter Brune   }
3129e764e56SPeter Brune 
313ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
314ee78dd50SPeter Brune   /* recursive option setting for the smoothers */
315ab8d36c9SPeter Brune   if (next) {ierr = SNESSetFromOptions(next);CHKERRQ(ierr);}
316421d9b32SPeter Brune   PetscFunctionReturn(0);
317421d9b32SPeter Brune }
318421d9b32SPeter Brune 
3199804daf3SBarry Smith #include <petscdraw.h>
32040244768SBarry Smith static PetscErrorCode SNESView_FAS(SNES snes, PetscViewer viewer)
321421d9b32SPeter Brune {
322421d9b32SPeter Brune   SNES_FAS       *fas = (SNES_FAS*) snes->data;
323656ede7eSPeter Brune   PetscBool      isFine,iascii,isdraw;
324ab8d36c9SPeter Brune   PetscInt       i;
325421d9b32SPeter Brune   PetscErrorCode ierr;
326ab8d36c9SPeter Brune   SNES           smoothu, smoothd, levelsnes;
327421d9b32SPeter Brune 
328421d9b32SPeter Brune   PetscFunctionBegin;
329ab8d36c9SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
330ab8d36c9SPeter Brune   if (isFine) {
331251f4c67SDmitry Karpeev     ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
332656ede7eSPeter Brune     ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr);
333421d9b32SPeter Brune     if (iascii) {
334efd4aadfSBarry Smith       ierr = PetscViewerASCIIPrintf(viewer, "  type is %s, levels=%D, cycles=%D\n",  SNESFASTypes[fas->fastype], fas->levels, fas->n_cycles);CHKERRQ(ierr);
335ab8d36c9SPeter Brune       if (fas->galerkin) {
336ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPrintf(viewer,"  Using Galerkin computed coarse grid function evaluation\n");CHKERRQ(ierr);
337421d9b32SPeter Brune       } else {
338ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPrintf(viewer,"  Not using Galerkin computed coarse grid function evaluation\n");CHKERRQ(ierr);
339421d9b32SPeter Brune       }
340ab8d36c9SPeter Brune       for (i=0; i<fas->levels; i++) {
341ab8d36c9SPeter Brune         ierr = SNESFASGetCycleSNES(snes, i, &levelsnes);CHKERRQ(ierr);
342ab8d36c9SPeter Brune         ierr = SNESFASCycleGetSmootherUp(levelsnes, &smoothu);CHKERRQ(ierr);
343ab8d36c9SPeter Brune         ierr = SNESFASCycleGetSmootherDown(levelsnes, &smoothd);CHKERRQ(ierr);
344ab8d36c9SPeter Brune         if (!i) {
345ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"  Coarse grid solver -- level %D -------------------------------\n",i);CHKERRQ(ierr);
346421d9b32SPeter Brune         } else {
347ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"  Down solver (pre-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
348421d9b32SPeter Brune         }
349ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
350166b3ea4SJed Brown         if (smoothd) {
351ab8d36c9SPeter Brune           ierr = SNESView(smoothd,viewer);CHKERRQ(ierr);
352166b3ea4SJed Brown         } else {
353166b3ea4SJed Brown           ierr = PetscViewerASCIIPrintf(viewer,"Not yet available\n");CHKERRQ(ierr);
354166b3ea4SJed Brown         }
355ab8d36c9SPeter Brune         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
356ab8d36c9SPeter Brune         if (i && (smoothd == smoothu)) {
357ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"  Up solver (post-smoother) same as down solver (pre-smoother)\n");CHKERRQ(ierr);
358ab8d36c9SPeter Brune         } else if (i) {
359ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPrintf(viewer,"  Up solver (post-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
360ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
361166b3ea4SJed Brown           if (smoothu) {
362ab8d36c9SPeter Brune             ierr = SNESView(smoothu,viewer);CHKERRQ(ierr);
363166b3ea4SJed Brown           } else {
364166b3ea4SJed Brown             ierr = PetscViewerASCIIPrintf(viewer,"Not yet available\n");CHKERRQ(ierr);
365166b3ea4SJed Brown           }
366ab8d36c9SPeter Brune           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
367ab8d36c9SPeter Brune         }
368ab8d36c9SPeter Brune       }
369656ede7eSPeter Brune     } else if (isdraw) {
370656ede7eSPeter Brune       PetscDraw draw;
371b4375e8dSPeter Brune       PetscReal x,w,y,bottom,th,wth;
372656ede7eSPeter Brune       SNES_FAS  *curfas = fas;
373656ede7eSPeter Brune       ierr   = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr);
374656ede7eSPeter Brune       ierr   = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr);
375656ede7eSPeter Brune       ierr   = PetscDrawStringGetSize(draw,&wth,&th);CHKERRQ(ierr);
376656ede7eSPeter Brune       bottom = y - th;
377656ede7eSPeter Brune       while (curfas) {
378b4375e8dSPeter Brune         if (!curfas->smoothu) {
379656ede7eSPeter Brune           ierr = PetscDrawPushCurrentPoint(draw,x,bottom);CHKERRQ(ierr);
380656ede7eSPeter Brune           if (curfas->smoothd) ierr = SNESView(curfas->smoothd,viewer);CHKERRQ(ierr);
381656ede7eSPeter Brune           ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr);
382b4375e8dSPeter Brune         } else {
383b4375e8dSPeter Brune           w    = 0.5*PetscMin(1.0-x,x);
384b4375e8dSPeter Brune           ierr = PetscDrawPushCurrentPoint(draw,x-w,bottom);CHKERRQ(ierr);
385b4375e8dSPeter Brune           if (curfas->smoothd) ierr = SNESView(curfas->smoothd,viewer);CHKERRQ(ierr);
386b4375e8dSPeter Brune           ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr);
387b4375e8dSPeter Brune           ierr = PetscDrawPushCurrentPoint(draw,x+w,bottom);CHKERRQ(ierr);
388b4375e8dSPeter Brune           if (curfas->smoothu) ierr = SNESView(curfas->smoothu,viewer);CHKERRQ(ierr);
389b4375e8dSPeter Brune           ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr);
390b4375e8dSPeter Brune         }
391656ede7eSPeter Brune         /* this is totally bogus but we have no way of knowing how low the previous one was draw to */
392656ede7eSPeter Brune         bottom -= 5*th;
3931aa26658SKarl Rupp         if (curfas->next) curfas = (SNES_FAS*)curfas->next->data;
3940298fd71SBarry Smith         else curfas = NULL;
395656ede7eSPeter Brune       }
396421d9b32SPeter Brune     }
397ab8d36c9SPeter Brune   }
398421d9b32SPeter Brune   PetscFunctionReturn(0);
399421d9b32SPeter Brune }
400421d9b32SPeter Brune 
40139bd7f45SPeter Brune /*
40239bd7f45SPeter Brune Defines the action of the downsmoother
40339bd7f45SPeter Brune  */
40440244768SBarry Smith static PetscErrorCode SNESFASDownSmooth_Private(SNES snes, Vec B, Vec X, Vec F, PetscReal *fnorm)
405b9c2fdf1SPeter Brune {
40639bd7f45SPeter Brune   PetscErrorCode      ierr = 0;
407742fe5e2SPeter Brune   SNESConvergedReason reason;
408ab8d36c9SPeter Brune   Vec                 FPC;
409ab8d36c9SPeter Brune   SNES                smoothd;
4106cbb2f26SLawrence Mitchell   PetscBool           flg;
4110dd27c6cSPeter Brune   SNES_FAS            *fas = (SNES_FAS*) snes->data;
4126e111a19SKarl Rupp 
413421d9b32SPeter Brune   PetscFunctionBegin;
414ab8d36c9SPeter Brune   ierr = SNESFASCycleGetSmootherDown(snes, &smoothd);CHKERRQ(ierr);
415e4ed7901SPeter Brune   ierr = SNESSetInitialFunction(smoothd, F);CHKERRQ(ierr);
4160dd27c6cSPeter Brune   if (fas->eventsmoothsolve) {ierr = PetscLogEventBegin(fas->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
417ab8d36c9SPeter Brune   ierr = SNESSolve(smoothd, B, X);CHKERRQ(ierr);
4180dd27c6cSPeter Brune   if (fas->eventsmoothsolve) {ierr = PetscLogEventEnd(fas->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
419742fe5e2SPeter Brune   /* check convergence reason for the smoother */
420ab8d36c9SPeter Brune   ierr = SNESGetConvergedReason(smoothd,&reason);CHKERRQ(ierr);
4211ff805c3SPeter Brune   if (reason < 0 && !(reason == SNES_DIVERGED_MAX_IT || reason == SNES_DIVERGED_LOCAL_MIN || reason == SNES_DIVERGED_LINE_SEARCH)) {
422742fe5e2SPeter Brune     snes->reason = SNES_DIVERGED_INNER;
423742fe5e2SPeter Brune     PetscFunctionReturn(0);
424742fe5e2SPeter Brune   }
4256cbb2f26SLawrence Mitchell 
4260298fd71SBarry Smith   ierr = SNESGetFunction(smoothd, &FPC, NULL, NULL);CHKERRQ(ierr);
4276cbb2f26SLawrence Mitchell   ierr = SNESGetAlwaysComputesFinalResidual(smoothd, &flg);CHKERRQ(ierr);
4286cbb2f26SLawrence Mitchell   if (!flg) {
4296cbb2f26SLawrence Mitchell     ierr = SNESComputeFunction(smoothd, X, FPC);CHKERRQ(ierr);
4306cbb2f26SLawrence Mitchell   }
4314b32a720SPeter Brune   ierr = VecCopy(FPC, F);CHKERRQ(ierr);
43271dbe336SPeter Brune   if (fnorm) {ierr = VecNorm(F,NORM_2,fnorm);CHKERRQ(ierr);}
43339bd7f45SPeter Brune   PetscFunctionReturn(0);
43439bd7f45SPeter Brune }
43539bd7f45SPeter Brune 
43639bd7f45SPeter Brune 
43739bd7f45SPeter Brune /*
43807144faaSPeter Brune Defines the action of the upsmoother
43939bd7f45SPeter Brune  */
44040244768SBarry Smith static PetscErrorCode SNESFASUpSmooth_Private(SNES snes, Vec B, Vec X, Vec F, PetscReal *fnorm)
4410adebc6cSBarry Smith {
44239bd7f45SPeter Brune   PetscErrorCode      ierr = 0;
44339bd7f45SPeter Brune   SNESConvergedReason reason;
444ab8d36c9SPeter Brune   Vec                 FPC;
445ab8d36c9SPeter Brune   SNES                smoothu;
4466cbb2f26SLawrence Mitchell   PetscBool           flg;
4470dd27c6cSPeter Brune   SNES_FAS            *fas = (SNES_FAS*) snes->data;
448ab8d36c9SPeter Brune 
4496e111a19SKarl Rupp   PetscFunctionBegin;
450ab8d36c9SPeter Brune   ierr = SNESFASCycleGetSmootherUp(snes, &smoothu);CHKERRQ(ierr);
4510dd27c6cSPeter Brune   if (fas->eventsmoothsolve) {ierr = PetscLogEventBegin(fas->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
452ab8d36c9SPeter Brune   ierr = SNESSolve(smoothu, B, X);CHKERRQ(ierr);
4530dd27c6cSPeter Brune   if (fas->eventsmoothsolve) {ierr = PetscLogEventEnd(fas->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
45439bd7f45SPeter Brune   /* check convergence reason for the smoother */
455ab8d36c9SPeter Brune   ierr = SNESGetConvergedReason(smoothu,&reason);CHKERRQ(ierr);
4561ff805c3SPeter Brune   if (reason < 0 && !(reason == SNES_DIVERGED_MAX_IT || reason == SNES_DIVERGED_LOCAL_MIN || reason == SNES_DIVERGED_LINE_SEARCH)) {
45739bd7f45SPeter Brune     snes->reason = SNES_DIVERGED_INNER;
45839bd7f45SPeter Brune     PetscFunctionReturn(0);
45939bd7f45SPeter Brune   }
4600298fd71SBarry Smith   ierr = SNESGetFunction(smoothu, &FPC, NULL, NULL);CHKERRQ(ierr);
4616cbb2f26SLawrence Mitchell   ierr = SNESGetAlwaysComputesFinalResidual(smoothu, &flg);CHKERRQ(ierr);
4626cbb2f26SLawrence Mitchell   if (!flg) {
4636cbb2f26SLawrence Mitchell     ierr = SNESComputeFunction(smoothu, X, FPC);CHKERRQ(ierr);
4646cbb2f26SLawrence Mitchell   }
4654b32a720SPeter Brune   ierr = VecCopy(FPC, F);CHKERRQ(ierr);
46671dbe336SPeter Brune   if (fnorm) {ierr = VecNorm(F,NORM_2,fnorm);CHKERRQ(ierr);}
46739bd7f45SPeter Brune   PetscFunctionReturn(0);
46839bd7f45SPeter Brune }
46939bd7f45SPeter Brune 
470938e4a01SJed Brown /*@
471938e4a01SJed Brown    SNESFASCreateCoarseVec - create Vec corresponding to a state vector on one level coarser than current level
472938e4a01SJed Brown 
473938e4a01SJed Brown    Collective
474938e4a01SJed Brown 
475938e4a01SJed Brown    Input Arguments:
476938e4a01SJed Brown .  snes - SNESFAS
477938e4a01SJed Brown 
478938e4a01SJed Brown    Output Arguments:
479938e4a01SJed Brown .  Xcoarse - vector on level one coarser than snes
480938e4a01SJed Brown 
481938e4a01SJed Brown    Level: developer
482938e4a01SJed Brown 
483938e4a01SJed Brown .seealso: SNESFASSetRestriction(), SNESFASRestrict()
484938e4a01SJed Brown @*/
485938e4a01SJed Brown PetscErrorCode SNESFASCreateCoarseVec(SNES snes,Vec *Xcoarse)
486938e4a01SJed Brown {
487938e4a01SJed Brown   PetscErrorCode ierr;
488938e4a01SJed Brown   SNES_FAS       *fas = (SNES_FAS*)snes->data;
489938e4a01SJed Brown 
490938e4a01SJed Brown   PetscFunctionBegin;
4911aa26658SKarl Rupp   if (fas->rscale) {
4921aa26658SKarl Rupp     ierr = VecDuplicate(fas->rscale,Xcoarse);CHKERRQ(ierr);
493f5af7f23SKarl Rupp   } else if (fas->inject) {
4942a7a6963SBarry Smith     ierr = MatCreateVecs(fas->inject,Xcoarse,NULL);CHKERRQ(ierr);
49513903a91SSatish Balay   } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Must set restriction or injection");
496938e4a01SJed Brown   PetscFunctionReturn(0);
497938e4a01SJed Brown }
498938e4a01SJed Brown 
499e9923e8dSJed Brown /*@
500e9923e8dSJed Brown    SNESFASRestrict - restrict a Vec to the next coarser level
501e9923e8dSJed Brown 
502e9923e8dSJed Brown    Collective
503e9923e8dSJed Brown 
504e9923e8dSJed Brown    Input Arguments:
505e9923e8dSJed Brown +  fine - SNES from which to restrict
506e9923e8dSJed Brown -  Xfine - vector to restrict
507e9923e8dSJed Brown 
508e9923e8dSJed Brown    Output Arguments:
509e9923e8dSJed Brown .  Xcoarse - result of restriction
510e9923e8dSJed Brown 
511e9923e8dSJed Brown    Level: developer
512e9923e8dSJed Brown 
513e9923e8dSJed Brown .seealso: SNESFASSetRestriction(), SNESFASSetInjection()
514e9923e8dSJed Brown @*/
515e9923e8dSJed Brown PetscErrorCode SNESFASRestrict(SNES fine,Vec Xfine,Vec Xcoarse)
516e9923e8dSJed Brown {
517e9923e8dSJed Brown   PetscErrorCode ierr;
518e9923e8dSJed Brown   SNES_FAS       *fas = (SNES_FAS*)fine->data;
519e9923e8dSJed Brown 
520e9923e8dSJed Brown   PetscFunctionBegin;
521e9923e8dSJed Brown   PetscValidHeaderSpecific(fine,SNES_CLASSID,1);
522e9923e8dSJed Brown   PetscValidHeaderSpecific(Xfine,VEC_CLASSID,2);
523e9923e8dSJed Brown   PetscValidHeaderSpecific(Xcoarse,VEC_CLASSID,3);
524e9923e8dSJed Brown   if (fas->inject) {
525e9923e8dSJed Brown     ierr = MatRestrict(fas->inject,Xfine,Xcoarse);CHKERRQ(ierr);
526e9923e8dSJed Brown   } else {
527e9923e8dSJed Brown     ierr = MatRestrict(fas->restrct,Xfine,Xcoarse);CHKERRQ(ierr);
528e9923e8dSJed Brown     ierr = VecPointwiseMult(Xcoarse,fas->rscale,Xcoarse);CHKERRQ(ierr);
529e9923e8dSJed Brown   }
530e9923e8dSJed Brown   PetscFunctionReturn(0);
531e9923e8dSJed Brown }
532e9923e8dSJed Brown 
53339bd7f45SPeter Brune /*
53439bd7f45SPeter Brune 
53539bd7f45SPeter Brune Performs the FAS coarse correction as:
53639bd7f45SPeter Brune 
537b5527d98SMatthew G. Knepley fine problem:   F(x) = b
538b5527d98SMatthew G. Knepley coarse problem: F^c(x^c) = b^c
53939bd7f45SPeter Brune 
540b5527d98SMatthew G. Knepley b^c = F^c(Rx) - R(F(x) - b)
54139bd7f45SPeter Brune 
54239bd7f45SPeter Brune  */
5430adebc6cSBarry Smith PetscErrorCode SNESFASCoarseCorrection(SNES snes, Vec X, Vec F, Vec X_new)
5440adebc6cSBarry Smith {
54539bd7f45SPeter Brune   PetscErrorCode      ierr;
54639bd7f45SPeter Brune   Vec                 X_c, Xo_c, F_c, B_c;
54739bd7f45SPeter Brune   SNESConvergedReason reason;
548ab8d36c9SPeter Brune   SNES                next;
549ab8d36c9SPeter Brune   Mat                 restrct, interpolate;
5500dd27c6cSPeter Brune   SNES_FAS            *fasc;
5515fd66863SKarl Rupp 
55239bd7f45SPeter Brune   PetscFunctionBegin;
553ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
554ab8d36c9SPeter Brune   if (next) {
5550dd27c6cSPeter Brune     fasc = (SNES_FAS*)next->data;
5560dd27c6cSPeter Brune 
557ab8d36c9SPeter Brune     ierr = SNESFASCycleGetRestriction(snes, &restrct);CHKERRQ(ierr);
558ab8d36c9SPeter Brune     ierr = SNESFASCycleGetInterpolation(snes, &interpolate);CHKERRQ(ierr);
559ab8d36c9SPeter Brune 
560ab8d36c9SPeter Brune     X_c  = next->vec_sol;
561ab8d36c9SPeter Brune     Xo_c = next->work[0];
562ab8d36c9SPeter Brune     F_c  = next->vec_func;
563ab8d36c9SPeter Brune     B_c  = next->vec_rhs;
564efe1f98aSPeter Brune 
5650dd27c6cSPeter Brune     if (fasc->eventinterprestrict) {ierr = PetscLogEventBegin(fasc->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
566938e4a01SJed Brown     ierr = SNESFASRestrict(snes,X,Xo_c);CHKERRQ(ierr);
5675609cbf2SMatthew G. Knepley     /* restrict the defect: R(F(x) - b) */
568ab8d36c9SPeter Brune     ierr = MatRestrict(restrct, F, B_c);CHKERRQ(ierr);
5690dd27c6cSPeter Brune     if (fasc->eventinterprestrict) {ierr = PetscLogEventEnd(fasc->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
5700dd27c6cSPeter Brune 
5710dd27c6cSPeter Brune     if (fasc->eventresidual) {ierr = PetscLogEventBegin(fasc->eventresidual,0,0,0,0);CHKERRQ(ierr);}
5725609cbf2SMatthew G. Knepley     /* F_c = F^c(Rx) - R(F(x) - b) since the second term was sitting in next->vec_rhs */
573ab8d36c9SPeter Brune     ierr = SNESComputeFunction(next, Xo_c, F_c);CHKERRQ(ierr);
5740dd27c6cSPeter Brune     if (fasc->eventresidual) {ierr = PetscLogEventEnd(fasc->eventresidual,0,0,0,0);CHKERRQ(ierr);}
5750dd27c6cSPeter Brune 
5760dd27c6cSPeter Brune     /* solve the coarse problem corresponding to F^c(x^c) = b^c = F^c(Rx) - R(F(x) - b) */
577e4ed7901SPeter Brune     ierr = VecCopy(B_c, X_c);CHKERRQ(ierr);
578b9c2fdf1SPeter Brune     ierr = VecCopy(F_c, B_c);CHKERRQ(ierr);
579e4ed7901SPeter Brune     ierr = VecCopy(X_c, F_c);CHKERRQ(ierr);
580ee78dd50SPeter Brune     /* set initial guess of the coarse problem to the projected fine solution */
581ee78dd50SPeter Brune     ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr);
582c90fad12SPeter Brune 
583c90fad12SPeter Brune     /* recurse to the next level */
584e4ed7901SPeter Brune     ierr = SNESSetInitialFunction(next, F_c);CHKERRQ(ierr);
585ab8d36c9SPeter Brune     ierr = SNESSolve(next, B_c, X_c);CHKERRQ(ierr);
586ab8d36c9SPeter Brune     ierr = SNESGetConvergedReason(next,&reason);CHKERRQ(ierr);
587742fe5e2SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
588742fe5e2SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
589742fe5e2SPeter Brune       PetscFunctionReturn(0);
590742fe5e2SPeter Brune     }
591fa9694d7SPeter Brune     /* correct as x <- x + I(x^c - Rx)*/
592fa9694d7SPeter Brune     ierr = VecAXPY(X_c, -1.0, Xo_c);CHKERRQ(ierr);
5930dd27c6cSPeter Brune 
5940dd27c6cSPeter Brune     if (fasc->eventinterprestrict) {ierr = PetscLogEventBegin(fasc->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
595ab8d36c9SPeter Brune     ierr = MatInterpolateAdd(interpolate, X_c, X, X_new);CHKERRQ(ierr);
5960dd27c6cSPeter Brune     if (fasc->eventinterprestrict) {ierr = PetscLogEventEnd(fasc->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
597293a7e31SPeter Brune   }
59839bd7f45SPeter Brune   PetscFunctionReturn(0);
59939bd7f45SPeter Brune }
60039bd7f45SPeter Brune 
60139bd7f45SPeter Brune /*
60239bd7f45SPeter Brune 
60339bd7f45SPeter Brune The additive cycle looks like:
60439bd7f45SPeter Brune 
60507144faaSPeter Brune xhat = x
60607144faaSPeter Brune xhat = dS(x, b)
60707144faaSPeter Brune x = coarsecorrection(xhat, b_d)
60807144faaSPeter Brune x = x + nu*(xhat - x);
60939bd7f45SPeter Brune (optional) x = uS(x, b)
61039bd7f45SPeter Brune 
61139bd7f45SPeter Brune With the coarse RHS (defect correction) as below.
61239bd7f45SPeter Brune 
61339bd7f45SPeter Brune  */
61440244768SBarry Smith static PetscErrorCode SNESFASCycle_Additive(SNES snes, Vec X)
6150adebc6cSBarry Smith {
61607144faaSPeter Brune   Vec                  F, B, Xhat;
61722c1e704SPeter Brune   Vec                  X_c, Xo_c, F_c, B_c;
61839bd7f45SPeter Brune   PetscErrorCode       ierr;
61907144faaSPeter Brune   SNESConvergedReason  reason;
62022c1e704SPeter Brune   PetscReal            xnorm, fnorm, ynorm;
621422a814eSBarry Smith   SNESLineSearchReason lsresult;
622ab8d36c9SPeter Brune   SNES                 next;
623ab8d36c9SPeter Brune   Mat                  restrct, interpolate;
6240dd27c6cSPeter Brune   SNES_FAS             *fas = (SNES_FAS*)snes->data,*fasc;
6250dd27c6cSPeter Brune 
62639bd7f45SPeter Brune   PetscFunctionBegin;
627ab8d36c9SPeter Brune   ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr);
62839bd7f45SPeter Brune   F    = snes->vec_func;
62939bd7f45SPeter Brune   B    = snes->vec_rhs;
630e7f468e7SPeter Brune   Xhat = snes->work[1];
63107144faaSPeter Brune   ierr = VecCopy(X, Xhat);CHKERRQ(ierr);
63207144faaSPeter Brune   /* recurse first */
633ab8d36c9SPeter Brune   if (next) {
6340dd27c6cSPeter Brune     fasc = (SNES_FAS*)next->data;
635ab8d36c9SPeter Brune     ierr = SNESFASCycleGetRestriction(snes, &restrct);CHKERRQ(ierr);
636ab8d36c9SPeter Brune     ierr = SNESFASCycleGetInterpolation(snes, &interpolate);CHKERRQ(ierr);
6370dd27c6cSPeter Brune     if (fas->eventresidual) {ierr = PetscLogEventBegin(fas->eventresidual,0,0,0,0);CHKERRQ(ierr);}
63807144faaSPeter Brune     ierr = SNESComputeFunction(snes, Xhat, F);CHKERRQ(ierr);
6390dd27c6cSPeter Brune     if (fas->eventresidual) {ierr = PetscLogEventEnd(fas->eventresidual,0,0,0,0);CHKERRQ(ierr);}
640c2a02606SPeter Brune     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
641ab8d36c9SPeter Brune     X_c  = next->vec_sol;
642ab8d36c9SPeter Brune     Xo_c = next->work[0];
643ab8d36c9SPeter Brune     F_c  = next->vec_func;
644ab8d36c9SPeter Brune     B_c  = next->vec_rhs;
64539bd7f45SPeter Brune 
646938e4a01SJed Brown     ierr = SNESFASRestrict(snes,Xhat,Xo_c);CHKERRQ(ierr);
64707144faaSPeter Brune     /* restrict the defect */
648ab8d36c9SPeter Brune     ierr = MatRestrict(restrct, F, B_c);CHKERRQ(ierr);
64907144faaSPeter Brune 
65007144faaSPeter Brune     /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */
6510dd27c6cSPeter Brune     if (fasc->eventresidual) {ierr = PetscLogEventBegin(fasc->eventresidual,0,0,0,0);CHKERRQ(ierr);}
652ab8d36c9SPeter Brune     ierr = SNESComputeFunction(next, Xo_c, F_c);CHKERRQ(ierr);
6530dd27c6cSPeter Brune     if (fasc->eventresidual) {ierr = PetscLogEventEnd(fasc->eventresidual,0,0,0,0);CHKERRQ(ierr);}
654e4ed7901SPeter Brune     ierr = VecCopy(B_c, X_c);CHKERRQ(ierr);
655b9c2fdf1SPeter Brune     ierr = VecCopy(F_c, B_c);CHKERRQ(ierr);
656e4ed7901SPeter Brune     ierr = VecCopy(X_c, F_c);CHKERRQ(ierr);
65707144faaSPeter Brune     /* set initial guess of the coarse problem to the projected fine solution */
65807144faaSPeter Brune     ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr);
65907144faaSPeter Brune 
66007144faaSPeter Brune     /* recurse */
661e4ed7901SPeter Brune     ierr = SNESSetInitialFunction(next, F_c);CHKERRQ(ierr);
662ab8d36c9SPeter Brune     ierr = SNESSolve(next, B_c, X_c);CHKERRQ(ierr);
66307144faaSPeter Brune 
66407144faaSPeter Brune     /* smooth on this level */
66591f99d7cSPeter Brune     ierr = SNESFASDownSmooth_Private(snes, B, X, F, &fnorm);CHKERRQ(ierr);
66607144faaSPeter Brune 
667ab8d36c9SPeter Brune     ierr = SNESGetConvergedReason(next,&reason);CHKERRQ(ierr);
66807144faaSPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
66907144faaSPeter Brune       snes->reason = SNES_DIVERGED_INNER;
67007144faaSPeter Brune       PetscFunctionReturn(0);
67107144faaSPeter Brune     }
67207144faaSPeter Brune 
67307144faaSPeter Brune     /* correct as x <- x + I(x^c - Rx)*/
674c68acad4SPeter Brune     ierr = VecAYPX(X_c, -1.0, Xo_c);CHKERRQ(ierr);
675ab8d36c9SPeter Brune     ierr = MatInterpolate(interpolate, X_c, Xhat);CHKERRQ(ierr);
67607144faaSPeter Brune 
677ddebd997SPeter Brune     /* additive correction of the coarse direction*/
678f1c6b773SPeter Brune     ierr = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Xhat);CHKERRQ(ierr);
679422a814eSBarry Smith     ierr = SNESLineSearchGetReason(snes->linesearch, &lsresult);CHKERRQ(ierr);
680422a814eSBarry Smith     ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &snes->norm, &ynorm);CHKERRQ(ierr);
681422a814eSBarry Smith     if (lsresult) {
6829e764e56SPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
6839e764e56SPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
6849e764e56SPeter Brune         PetscFunctionReturn(0);
6859e764e56SPeter Brune       }
6869e764e56SPeter Brune     }
68707144faaSPeter Brune   } else {
68891f99d7cSPeter Brune     ierr = SNESFASDownSmooth_Private(snes, B, X, F, &snes->norm);CHKERRQ(ierr);
68907144faaSPeter Brune   }
69039bd7f45SPeter Brune   PetscFunctionReturn(0);
69139bd7f45SPeter Brune }
69239bd7f45SPeter Brune 
69339bd7f45SPeter Brune /*
69439bd7f45SPeter Brune 
69539bd7f45SPeter Brune Defines the FAS cycle as:
69639bd7f45SPeter Brune 
697b5527d98SMatthew G. Knepley fine problem: F(x) = b
69839bd7f45SPeter Brune coarse problem: F^c(x) = b^c
69939bd7f45SPeter Brune 
700b5527d98SMatthew G. Knepley b^c = F^c(Rx) - R(F(x) - b)
70139bd7f45SPeter Brune 
70239bd7f45SPeter Brune correction:
70339bd7f45SPeter Brune 
70439bd7f45SPeter Brune x = x + I(x^c - Rx)
70539bd7f45SPeter Brune 
70639bd7f45SPeter Brune  */
70740244768SBarry Smith static PetscErrorCode SNESFASCycle_Multiplicative(SNES snes, Vec X)
7080adebc6cSBarry Smith {
70939bd7f45SPeter Brune 
71039bd7f45SPeter Brune   PetscErrorCode ierr;
71139bd7f45SPeter Brune   Vec            F,B;
71234d65b3cSPeter Brune   SNES           next;
71339bd7f45SPeter Brune 
71439bd7f45SPeter Brune   PetscFunctionBegin;
71539bd7f45SPeter Brune   F = snes->vec_func;
71639bd7f45SPeter Brune   B = snes->vec_rhs;
71739bd7f45SPeter Brune   /* pre-smooth -- just update using the pre-smoother */
71834d65b3cSPeter Brune   ierr = SNESFASCycleGetCorrection(snes,&next);CHKERRQ(ierr);
71991f99d7cSPeter Brune   ierr = SNESFASDownSmooth_Private(snes, B, X, F, &snes->norm);CHKERRQ(ierr);
72034d65b3cSPeter Brune   if (next) {
7218c40d5fbSBarry Smith     ierr = SNESFASCoarseCorrection(snes, X, F, X);CHKERRQ(ierr);
72291f99d7cSPeter Brune     ierr = SNESFASUpSmooth_Private(snes, B, X, F, &snes->norm);CHKERRQ(ierr);
723fe6f9142SPeter Brune   }
724fa9694d7SPeter Brune   PetscFunctionReturn(0);
725421d9b32SPeter Brune }
726421d9b32SPeter Brune 
72740244768SBarry Smith static PetscErrorCode SNESFASCycleSetupPhase_Full(SNES snes)
7288c94862eSPeter Brune {
7298c94862eSPeter Brune   SNES           next;
7308c94862eSPeter Brune   SNES_FAS       *fas = (SNES_FAS*)snes->data;
7318c94862eSPeter Brune   PetscBool      isFine;
7328c94862eSPeter Brune   PetscErrorCode ierr;
7338c94862eSPeter Brune 
7348c94862eSPeter Brune   PetscFunctionBegin;
7358c94862eSPeter Brune   /* pre-smooth -- just update using the pre-smoother */
7368c94862eSPeter Brune   ierr = SNESFASCycleIsFine(snes,&isFine);CHKERRQ(ierr);
7378c94862eSPeter Brune   ierr = SNESFASCycleGetCorrection(snes,&next);CHKERRQ(ierr);
7388c94862eSPeter Brune   fas->full_stage = 0;
7398c94862eSPeter Brune   if (next) {ierr = SNESFASCycleSetupPhase_Full(next);CHKERRQ(ierr);}
7408c94862eSPeter Brune   PetscFunctionReturn(0);
7418c94862eSPeter Brune }
7428c94862eSPeter Brune 
74340244768SBarry Smith static PetscErrorCode SNESFASCycle_Full(SNES snes, Vec X)
7448c94862eSPeter Brune {
7458c94862eSPeter Brune   PetscErrorCode ierr;
7468c94862eSPeter Brune   Vec            F,B;
7478c94862eSPeter Brune   SNES_FAS       *fas = (SNES_FAS*)snes->data;
7488c94862eSPeter Brune   PetscBool      isFine;
7498c94862eSPeter Brune   SNES           next;
7508c94862eSPeter Brune 
7518c94862eSPeter Brune   PetscFunctionBegin;
7528c94862eSPeter Brune   F = snes->vec_func;
7538c94862eSPeter Brune   B = snes->vec_rhs;
7548c94862eSPeter Brune   ierr = SNESFASCycleIsFine(snes,&isFine);CHKERRQ(ierr);
7558c94862eSPeter Brune   ierr = SNESFASCycleGetCorrection(snes,&next);CHKERRQ(ierr);
7568c94862eSPeter Brune 
7578c94862eSPeter Brune   if (isFine) {
7588c94862eSPeter Brune     ierr = SNESFASCycleSetupPhase_Full(snes);CHKERRQ(ierr);
7598c94862eSPeter Brune   }
7608c94862eSPeter Brune 
7618c94862eSPeter Brune   if (fas->full_stage == 0) {
762928e959bSPeter Brune     /* downsweep */
7638c94862eSPeter Brune     if (next) {
7648c94862eSPeter Brune       if (fas->level != 1) next->max_its += 1;
765928e959bSPeter Brune       if (fas->full_downsweep||isFine) {ierr = SNESFASDownSmooth_Private(snes,B,X,F,&snes->norm);CHKERRQ(ierr);}
7668c94862eSPeter Brune       ierr = SNESFASCoarseCorrection(snes,X,F,X);CHKERRQ(ierr);
7678c94862eSPeter Brune       ierr = SNESFASUpSmooth_Private(snes,B,X,F,&snes->norm);CHKERRQ(ierr);
7688c94862eSPeter Brune       if (fas->level != 1) next->max_its -= 1;
7698c94862eSPeter Brune     } else {
770a3a80b83SMatthew G. Knepley       /* The smoother on the coarse level is the coarse solver */
7718c94862eSPeter Brune       ierr = SNESFASDownSmooth_Private(snes,B,X,F,&snes->norm);CHKERRQ(ierr);
7728c94862eSPeter Brune     }
7738c94862eSPeter Brune     fas->full_stage = 1;
7748c94862eSPeter Brune   } else if (fas->full_stage == 1) {
7758c94862eSPeter Brune     if (snes->iter == 0) {ierr = SNESFASDownSmooth_Private(snes,B,X,F,&snes->norm);CHKERRQ(ierr);}
7768c94862eSPeter Brune     if (next) {
7778c94862eSPeter Brune       ierr = SNESFASCoarseCorrection(snes,X,F,X);CHKERRQ(ierr);
7788c94862eSPeter Brune       ierr = SNESFASUpSmooth_Private(snes,B,X,F,&snes->norm);CHKERRQ(ierr);
7798c94862eSPeter Brune     }
7808c94862eSPeter Brune   }
7818c94862eSPeter Brune   /* final v-cycle */
7828c94862eSPeter Brune   if (isFine) {
7838c94862eSPeter Brune     if (next) {
7848c94862eSPeter Brune       ierr = SNESFASCoarseCorrection(snes,X,F,X);CHKERRQ(ierr);
7858c94862eSPeter Brune       ierr = SNESFASUpSmooth_Private(snes,B,X,F,&snes->norm);CHKERRQ(ierr);
7868c94862eSPeter Brune     }
7878c94862eSPeter Brune   }
7888c94862eSPeter Brune   PetscFunctionReturn(0);
7898c94862eSPeter Brune }
7908c94862eSPeter Brune 
79140244768SBarry Smith static PetscErrorCode SNESFASCycle_Kaskade(SNES snes, Vec X)
79234d65b3cSPeter Brune {
79334d65b3cSPeter Brune   PetscErrorCode ierr;
79434d65b3cSPeter Brune   Vec            F,B;
79534d65b3cSPeter Brune   SNES           next;
79634d65b3cSPeter Brune 
79734d65b3cSPeter Brune   PetscFunctionBegin;
79834d65b3cSPeter Brune   F = snes->vec_func;
79934d65b3cSPeter Brune   B = snes->vec_rhs;
80034d65b3cSPeter Brune   ierr = SNESFASCycleGetCorrection(snes,&next);CHKERRQ(ierr);
80134d65b3cSPeter Brune   if (next) {
80234d65b3cSPeter Brune     ierr = SNESFASCoarseCorrection(snes,X,F,X);CHKERRQ(ierr);
80334d65b3cSPeter Brune     ierr = SNESFASUpSmooth_Private(snes,B,X,F,&snes->norm);CHKERRQ(ierr);
80434d65b3cSPeter Brune   } else {
80534d65b3cSPeter Brune     ierr = SNESFASDownSmooth_Private(snes,B,X,F,&snes->norm);CHKERRQ(ierr);
80634d65b3cSPeter Brune   }
80734d65b3cSPeter Brune   PetscFunctionReturn(0);
80834d65b3cSPeter Brune }
80934d65b3cSPeter Brune 
810fffbeea8SBarry Smith PetscBool SNEScite = PETSC_FALSE;
811fffbeea8SBarry Smith const char SNESCitation[] = "@techreport{pbmkbsxt2012,\n"
812fffbeea8SBarry Smith                             "  title = {Composing Scalable Nonlinear Algebraic Solvers},\n"
813fffbeea8SBarry Smith                             "  author = {Peter Brune and Mathew Knepley and Barry Smith and Xuemin Tu},\n"
814fffbeea8SBarry Smith                             "  year = 2013,\n"
815fffbeea8SBarry Smith                             "  type = Preprint,\n"
816fffbeea8SBarry Smith                             "  number = {ANL/MCS-P2010-0112},\n"
817fffbeea8SBarry Smith                             "  institution = {Argonne National Laboratory}\n}\n";
818fffbeea8SBarry Smith 
81940244768SBarry Smith static PetscErrorCode SNESSolve_FAS(SNES snes)
820421d9b32SPeter Brune {
821fa9694d7SPeter Brune   PetscErrorCode ierr;
822fe6f9142SPeter Brune   PetscInt       i, maxits;
823ddb5aff1SPeter Brune   Vec            X, F;
824fe6f9142SPeter Brune   PetscReal      fnorm;
825b17ce1afSJed Brown   SNES_FAS       *fas = (SNES_FAS*)snes->data,*ffas;
826b17ce1afSJed Brown   DM             dm;
827e70c42e5SPeter Brune   PetscBool      isFine;
828b17ce1afSJed Brown 
829421d9b32SPeter Brune   PetscFunctionBegin;
830c579b300SPatrick Farrell 
8316c4ed002SBarry Smith   if (snes->xl || snes->xu || snes->ops->computevariablebounds) SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
832c579b300SPatrick Farrell 
833fffbeea8SBarry Smith   ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr);
834fe6f9142SPeter Brune   maxits       = snes->max_its;      /* maximum number of iterations */
835fe6f9142SPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
836fa9694d7SPeter Brune   X            = snes->vec_sol;
837f5a6d4f9SBarry Smith   F            = snes->vec_func;
838293a7e31SPeter Brune 
83918a66777SPeter Brune   ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr);
840293a7e31SPeter Brune   /*norm setup */
841e04113cfSBarry Smith   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
842fe6f9142SPeter Brune   snes->iter = 0;
843fe6f9142SPeter Brune   snes->norm = 0.;
844e04113cfSBarry Smith   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
845e4ed7901SPeter Brune   if (!snes->vec_func_init_set) {
8460dd27c6cSPeter Brune     if (fas->eventresidual) {ierr = PetscLogEventBegin(fas->eventresidual,0,0,0,0);CHKERRQ(ierr);}
847fe6f9142SPeter Brune     ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
8480dd27c6cSPeter Brune     if (fas->eventresidual) {ierr = PetscLogEventEnd(fas->eventresidual,0,0,0,0);CHKERRQ(ierr);}
8491aa26658SKarl Rupp   } else snes->vec_func_init_set = PETSC_FALSE;
850e4ed7901SPeter Brune 
851fe6f9142SPeter Brune   ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
852422a814eSBarry Smith   SNESCheckFunctionNorm(snes,fnorm);
853e04113cfSBarry Smith   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
854fe6f9142SPeter Brune   snes->norm = fnorm;
855e04113cfSBarry Smith   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
856a71f0d7dSBarry Smith   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
857fe6f9142SPeter Brune   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
858fe6f9142SPeter Brune 
859fe6f9142SPeter Brune   /* test convergence */
860fe6f9142SPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
861fe6f9142SPeter Brune   if (snes->reason) PetscFunctionReturn(0);
862e4ed7901SPeter Brune 
863b17ce1afSJed Brown 
864b9c2fdf1SPeter Brune   if (isFine) {
865b9c2fdf1SPeter Brune     /* propagate scale-dependent data up the hierarchy */
866b17ce1afSJed Brown     ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
867b17ce1afSJed Brown     for (ffas=fas; ffas->next; ffas=(SNES_FAS*)ffas->next->data) {
868b17ce1afSJed Brown       DM dmcoarse;
869b17ce1afSJed Brown       ierr = SNESGetDM(ffas->next,&dmcoarse);CHKERRQ(ierr);
870b17ce1afSJed Brown       ierr = DMRestrict(dm,ffas->restrct,ffas->rscale,ffas->inject,dmcoarse);CHKERRQ(ierr);
871b17ce1afSJed Brown       dm   = dmcoarse;
872b17ce1afSJed Brown     }
873b9c2fdf1SPeter Brune   }
874b17ce1afSJed Brown 
875fe6f9142SPeter Brune   for (i = 0; i < maxits; i++) {
876fe6f9142SPeter Brune     /* Call general purpose update function */
877646217ecSPeter Brune 
878fe6f9142SPeter Brune     if (snes->ops->update) {
879fe6f9142SPeter Brune       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
880fe6f9142SPeter Brune     }
88107144faaSPeter Brune     if (fas->fastype == SNES_FAS_MULTIPLICATIVE) {
88291f99d7cSPeter Brune       ierr = SNESFASCycle_Multiplicative(snes, X);CHKERRQ(ierr);
8838c94862eSPeter Brune     } else if (fas->fastype == SNES_FAS_ADDITIVE) {
88491f99d7cSPeter Brune       ierr = SNESFASCycle_Additive(snes, X);CHKERRQ(ierr);
8858c94862eSPeter Brune     } else if (fas->fastype == SNES_FAS_FULL) {
8868c94862eSPeter Brune       ierr = SNESFASCycle_Full(snes, X);CHKERRQ(ierr);
88734d65b3cSPeter Brune     } else if (fas->fastype ==SNES_FAS_KASKADE) {
88834d65b3cSPeter Brune       ierr = SNESFASCycle_Kaskade(snes, X);CHKERRQ(ierr);
8896c4ed002SBarry Smith     } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Unsupported FAS type");
890742fe5e2SPeter Brune 
891742fe5e2SPeter Brune     /* check for FAS cycle divergence */
8921aa26658SKarl Rupp     if (snes->reason != SNES_CONVERGED_ITERATING) PetscFunctionReturn(0);
893b9c2fdf1SPeter Brune 
894c90fad12SPeter Brune     /* Monitor convergence */
895e04113cfSBarry Smith     ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
896c90fad12SPeter Brune     snes->iter = i+1;
897e04113cfSBarry Smith     ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
898a71f0d7dSBarry Smith     ierr       = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr);
899c90fad12SPeter Brune     ierr       = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
900c90fad12SPeter Brune     /* Test for convergence */
90166585501SPeter Brune     if (isFine) {
902b9c2fdf1SPeter Brune       ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,snes->norm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
903c90fad12SPeter Brune       if (snes->reason) break;
904fe6f9142SPeter Brune     }
90566585501SPeter Brune   }
906fe6f9142SPeter Brune   if (i == maxits) {
907fe6f9142SPeter Brune     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr);
908fe6f9142SPeter Brune     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
909fe6f9142SPeter Brune   }
910421d9b32SPeter Brune   PetscFunctionReturn(0);
911421d9b32SPeter Brune }
91240244768SBarry Smith 
91340244768SBarry Smith /*MC
91440244768SBarry Smith 
91540244768SBarry Smith SNESFAS - Full Approximation Scheme nonlinear multigrid solver.
91640244768SBarry Smith 
91740244768SBarry Smith    The nonlinear problem is solved by correction using coarse versions
91840244768SBarry Smith    of the nonlinear problem.  This problem is perturbed so that a projected
91940244768SBarry Smith    solution of the fine problem elicits no correction from the coarse problem.
92040244768SBarry Smith 
92140244768SBarry Smith Options Database:
92240244768SBarry Smith +   -snes_fas_levels -  The number of levels
92340244768SBarry Smith .   -snes_fas_cycles<1> -  The number of cycles -- 1 for V, 2 for W
92440244768SBarry Smith .   -snes_fas_type<additive,multiplicative,full,kaskade>  -  Additive or multiplicative cycle
92540244768SBarry Smith .   -snes_fas_galerkin<PETSC_FALSE> -  Form coarse problems by projection back upon the fine problem
92640244768SBarry Smith .   -snes_fas_smoothup<1> -  The number of iterations of the post-smoother
92740244768SBarry Smith .   -snes_fas_smoothdown<1> -  The number of iterations of the pre-smoother
92840244768SBarry Smith .   -snes_fas_monitor -  Monitor progress of all of the levels
92940244768SBarry Smith .   -snes_fas_full_downsweep<PETSC_FALSE> - call the downsmooth on the initial downsweep of full FAS
93040244768SBarry Smith .   -fas_levels_snes_ -  SNES options for all smoothers
93140244768SBarry Smith .   -fas_levels_cycle_snes_ -  SNES options for all cycles
93240244768SBarry Smith .   -fas_levels_i_snes_ -  SNES options for the smoothers on level i
93340244768SBarry Smith .   -fas_levels_i_cycle_snes_ - SNES options for the cycle on level i
93440244768SBarry Smith -   -fas_coarse_snes_ -  SNES options for the coarsest smoother
93540244768SBarry Smith 
93640244768SBarry Smith Notes:
93740244768SBarry Smith    The organization of the FAS solver is slightly different from the organization of PCMG
93840244768SBarry Smith    As each level has smoother SNES instances(down and potentially up) and a cycle SNES instance.
93940244768SBarry Smith    The cycle SNES instance may be used for monitoring convergence on a particular level.
94040244768SBarry Smith 
94140244768SBarry Smith Level: beginner
94240244768SBarry Smith 
94340244768SBarry Smith    References:
94440244768SBarry Smith . 1. -  Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers",
94540244768SBarry Smith    SIAM Review, 57(4), 2015
94640244768SBarry Smith 
94740244768SBarry Smith .seealso: PCMG, SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
94840244768SBarry Smith M*/
94940244768SBarry Smith 
95040244768SBarry Smith PETSC_EXTERN PetscErrorCode SNESCreate_FAS(SNES snes)
95140244768SBarry Smith {
95240244768SBarry Smith   SNES_FAS       *fas;
95340244768SBarry Smith   PetscErrorCode ierr;
95440244768SBarry Smith 
95540244768SBarry Smith   PetscFunctionBegin;
95640244768SBarry Smith   snes->ops->destroy        = SNESDestroy_FAS;
95740244768SBarry Smith   snes->ops->setup          = SNESSetUp_FAS;
95840244768SBarry Smith   snes->ops->setfromoptions = SNESSetFromOptions_FAS;
95940244768SBarry Smith   snes->ops->view           = SNESView_FAS;
96040244768SBarry Smith   snes->ops->solve          = SNESSolve_FAS;
96140244768SBarry Smith   snes->ops->reset          = SNESReset_FAS;
96240244768SBarry Smith 
96340244768SBarry Smith   snes->usesksp = PETSC_FALSE;
964efd4aadfSBarry Smith   snes->usesnpc = PETSC_FALSE;
96540244768SBarry Smith 
96640244768SBarry Smith   if (!snes->tolerancesset) {
96740244768SBarry Smith     snes->max_funcs = 30000;
96840244768SBarry Smith     snes->max_its   = 10000;
96940244768SBarry Smith   }
97040244768SBarry Smith 
9714fc747eaSLawrence Mitchell   snes->alwayscomputesfinalresidual = PETSC_TRUE;
9724fc747eaSLawrence Mitchell 
97340244768SBarry Smith   ierr = PetscNewLog(snes,&fas);CHKERRQ(ierr);
97440244768SBarry Smith 
97540244768SBarry Smith   snes->data                  = (void*) fas;
97640244768SBarry Smith   fas->level                  = 0;
97740244768SBarry Smith   fas->levels                 = 1;
97840244768SBarry Smith   fas->n_cycles               = 1;
97940244768SBarry Smith   fas->max_up_it              = 1;
98040244768SBarry Smith   fas->max_down_it            = 1;
98140244768SBarry Smith   fas->smoothu                = NULL;
98240244768SBarry Smith   fas->smoothd                = NULL;
98340244768SBarry Smith   fas->next                   = NULL;
98440244768SBarry Smith   fas->previous               = NULL;
98540244768SBarry Smith   fas->fine                   = snes;
98640244768SBarry Smith   fas->interpolate            = NULL;
98740244768SBarry Smith   fas->restrct                = NULL;
98840244768SBarry Smith   fas->inject                 = NULL;
98940244768SBarry Smith   fas->usedmfornumberoflevels = PETSC_FALSE;
99040244768SBarry Smith   fas->fastype                = SNES_FAS_MULTIPLICATIVE;
99140244768SBarry Smith   fas->full_downsweep         = PETSC_FALSE;
99240244768SBarry Smith 
99340244768SBarry Smith   fas->eventsmoothsetup    = 0;
99440244768SBarry Smith   fas->eventsmoothsolve    = 0;
99540244768SBarry Smith   fas->eventresidual       = 0;
99640244768SBarry Smith   fas->eventinterprestrict = 0;
99740244768SBarry Smith   PetscFunctionReturn(0);
99840244768SBarry Smith }
999