1421d9b32SPeter Brune /* Defines the basic SNES object */ 2a055c8caSBarry Smith #include <../src/snes/impls/fas/fasimpls.h> /*I "petscsnes.h" I*/ 3421d9b32SPeter Brune 49e5d0892SLisandro Dalcin const char *const SNESFASTypes[] = {"MULTIPLICATIVE", "ADDITIVE", "FULL", "KASKADE", "SNESFASType", "SNES_FAS", NULL}; 507144faaSPeter Brune 6d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESReset_FAS(SNES snes) 7d71ae5a4SJacob Faibussowitsch { 8421d9b32SPeter Brune SNES_FAS *fas = (SNES_FAS *)snes->data; 9421d9b32SPeter Brune 10421d9b32SPeter Brune PetscFunctionBegin; 119566063dSJacob Faibussowitsch PetscCall(SNESDestroy(&fas->smoothu)); 129566063dSJacob Faibussowitsch PetscCall(SNESDestroy(&fas->smoothd)); 139566063dSJacob Faibussowitsch PetscCall(MatDestroy(&fas->inject)); 149566063dSJacob Faibussowitsch PetscCall(MatDestroy(&fas->interpolate)); 159566063dSJacob Faibussowitsch PetscCall(MatDestroy(&fas->restrct)); 169566063dSJacob Faibussowitsch PetscCall(VecDestroy(&fas->rscale)); 179566063dSJacob Faibussowitsch PetscCall(VecDestroy(&fas->Xg)); 189566063dSJacob Faibussowitsch PetscCall(VecDestroy(&fas->Fg)); 199566063dSJacob Faibussowitsch if (fas->next) PetscCall(SNESReset(fas->next)); 203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 21421d9b32SPeter Brune } 22421d9b32SPeter Brune 23d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESDestroy_FAS(SNES snes) 24d71ae5a4SJacob Faibussowitsch { 25421d9b32SPeter Brune SNES_FAS *fas = (SNES_FAS *)snes->data; 26421d9b32SPeter Brune 27421d9b32SPeter Brune PetscFunctionBegin; 28421d9b32SPeter Brune /* recursively resets and then destroys */ 299566063dSJacob Faibussowitsch PetscCall(SNESReset_FAS(snes)); 309566063dSJacob Faibussowitsch PetscCall(SNESDestroy(&fas->next)); 319566063dSJacob Faibussowitsch PetscCall(PetscFree(fas)); 323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 33421d9b32SPeter Brune } 34421d9b32SPeter Brune 35d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESFASSetUpLineSearch_Private(SNES snes, SNES smooth) 36d71ae5a4SJacob Faibussowitsch { 37f833ba53SLisandro Dalcin SNESLineSearch linesearch; 38f833ba53SLisandro Dalcin SNESLineSearch slinesearch; 39f833ba53SLisandro Dalcin void *lsprectx, *lspostctx; 40f833ba53SLisandro Dalcin PetscErrorCode (*precheck)(SNESLineSearch, Vec, Vec, PetscBool *, void *); 41f833ba53SLisandro Dalcin PetscErrorCode (*postcheck)(SNESLineSearch, Vec, Vec, Vec, PetscBool *, PetscBool *, void *); 42f833ba53SLisandro Dalcin 43f833ba53SLisandro Dalcin PetscFunctionBegin; 443ba16761SJacob Faibussowitsch if (!snes->linesearch) PetscFunctionReturn(PETSC_SUCCESS); 459566063dSJacob Faibussowitsch PetscCall(SNESGetLineSearch(snes, &linesearch)); 469566063dSJacob Faibussowitsch PetscCall(SNESGetLineSearch(smooth, &slinesearch)); 479566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetPreCheck(linesearch, &precheck, &lsprectx)); 489566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetPostCheck(linesearch, &postcheck, &lspostctx)); 499566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetPreCheck(slinesearch, precheck, lsprectx)); 509566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetPostCheck(slinesearch, postcheck, lspostctx)); 519566063dSJacob Faibussowitsch PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)linesearch, (PetscObject)slinesearch)); 523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 53f833ba53SLisandro Dalcin } 54f833ba53SLisandro Dalcin 55d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESFASCycleSetUpSmoother_Private(SNES snes, SNES smooth) 56d71ae5a4SJacob Faibussowitsch { 57f833ba53SLisandro Dalcin SNES_FAS *fas = (SNES_FAS *)snes->data; 58f833ba53SLisandro Dalcin 59f833ba53SLisandro Dalcin PetscFunctionBegin; 609566063dSJacob Faibussowitsch PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)snes, (PetscObject)smooth)); 619566063dSJacob Faibussowitsch PetscCall(SNESSetFromOptions(smooth)); 629566063dSJacob Faibussowitsch PetscCall(SNESFASSetUpLineSearch_Private(snes, smooth)); 63f833ba53SLisandro Dalcin 649566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)snes->vec_sol)); 659566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)snes->vec_sol_update)); 669566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)snes->vec_func)); 67f833ba53SLisandro Dalcin smooth->vec_sol = snes->vec_sol; 68f833ba53SLisandro Dalcin smooth->vec_sol_update = snes->vec_sol_update; 69f833ba53SLisandro Dalcin smooth->vec_func = snes->vec_func; 70f833ba53SLisandro Dalcin 719566063dSJacob Faibussowitsch if (fas->eventsmoothsetup) PetscCall(PetscLogEventBegin(fas->eventsmoothsetup, smooth, 0, 0, 0)); 729566063dSJacob Faibussowitsch PetscCall(SNESSetUp(smooth)); 739566063dSJacob Faibussowitsch if (fas->eventsmoothsetup) PetscCall(PetscLogEventEnd(fas->eventsmoothsetup, smooth, 0, 0, 0)); 743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 75f833ba53SLisandro Dalcin } 76f833ba53SLisandro Dalcin 77d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESSetUp_FAS(SNES snes) 78d71ae5a4SJacob Faibussowitsch { 7948bfdf8aSPeter Brune SNES_FAS *fas = (SNES_FAS *)snes->data; 80d1adcc6fSPeter Brune PetscInt dm_levels; 81ab8d36c9SPeter Brune SNES next; 82f833ba53SLisandro Dalcin PetscBool isFine, hasCreateRestriction, hasCreateInjection; 83eff52c0eSPeter Brune 846b2b7091SBarry Smith PetscFunctionBegin; 859566063dSJacob Faibussowitsch PetscCall(SNESFASCycleIsFine(snes, &isFine)); 86ab8d36c9SPeter Brune if (fas->usedmfornumberoflevels && isFine) { 879566063dSJacob Faibussowitsch PetscCall(DMGetRefineLevel(snes->dm, &dm_levels)); 88d1adcc6fSPeter Brune dm_levels++; 89cc05f883SPeter Brune if (dm_levels > fas->levels) { 903dccd265SPeter Brune /* reset the number of levels */ 919566063dSJacob Faibussowitsch PetscCall(SNESFASSetLevels(snes, dm_levels, NULL)); 929566063dSJacob Faibussowitsch PetscCall(SNESSetFromOptions(snes)); 93d1adcc6fSPeter Brune } 94d1adcc6fSPeter Brune } 959566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetCorrection(snes, &next)); 96ab8d36c9SPeter Brune if (!isFine) snes->gridsequence = 0; /* no grid sequencing inside the multigrid hierarchy! */ 973dccd265SPeter Brune 989566063dSJacob Faibussowitsch PetscCall(SNESSetWorkVecs(snes, 2)); /* work vectors used for intergrid transfers */ 99cc05f883SPeter Brune 100ab8d36c9SPeter Brune /* set up the smoothers if they haven't already been set up */ 10148a46eb9SPierre Jolivet if (!fas->smoothd) PetscCall(SNESFASCycleCreateSmoother_Private(snes, &fas->smoothd)); 102ab8d36c9SPeter Brune 10379d9a41aSPeter Brune if (snes->dm) { 104ab8d36c9SPeter Brune /* set the smoother DMs properly */ 1059566063dSJacob Faibussowitsch if (fas->smoothu) PetscCall(SNESSetDM(fas->smoothu, snes->dm)); 1069566063dSJacob Faibussowitsch PetscCall(SNESSetDM(fas->smoothd, snes->dm)); 10779d9a41aSPeter Brune /* construct EVERYTHING from the DM -- including the progressive set of smoothers */ 108ab8d36c9SPeter Brune if (next) { 10979d9a41aSPeter Brune /* for now -- assume the DM and the evaluation functions have been set externally */ 110ab8d36c9SPeter Brune if (!next->dm) { 1119566063dSJacob Faibussowitsch PetscCall(DMCoarsen(snes->dm, PetscObjectComm((PetscObject)next), &next->dm)); 1129566063dSJacob Faibussowitsch PetscCall(SNESSetDM(next, next->dm)); 11379d9a41aSPeter Brune } 11479d9a41aSPeter Brune /* set the interpolation and restriction from the DM */ 11579d9a41aSPeter Brune if (!fas->interpolate) { 1169566063dSJacob Faibussowitsch PetscCall(DMCreateInterpolation(next->dm, snes->dm, &fas->interpolate, &fas->rscale)); 117bccf9bb3SJed Brown if (!fas->restrct) { 1189566063dSJacob Faibussowitsch PetscCall(DMHasCreateRestriction(next->dm, &hasCreateRestriction)); 1190a7266b2SPatrick Farrell /* DM can create restrictions, use that */ 1200a7266b2SPatrick Farrell if (hasCreateRestriction) { 1219566063dSJacob Faibussowitsch PetscCall(DMCreateRestriction(next->dm, snes->dm, &fas->restrct)); 1220a7266b2SPatrick Farrell } else { 1239566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)fas->interpolate)); 12479d9a41aSPeter Brune fas->restrct = fas->interpolate; 12579d9a41aSPeter Brune } 126bccf9bb3SJed Brown } 1270a7266b2SPatrick Farrell } 12879d9a41aSPeter Brune /* set the injection from the DM */ 12979d9a41aSPeter Brune if (!fas->inject) { 1309566063dSJacob Faibussowitsch PetscCall(DMHasCreateInjection(next->dm, &hasCreateInjection)); 13148a46eb9SPierre Jolivet if (hasCreateInjection) PetscCall(DMCreateInjection(next->dm, snes->dm, &fas->inject)); 13279d9a41aSPeter Brune } 13379d9a41aSPeter Brune } 13423e68893SLawrence Mitchell } 135f833ba53SLisandro Dalcin 13679d9a41aSPeter Brune /*pass the smoother, function, and jacobian up to the next level if it's not user set already */ 13779d9a41aSPeter Brune if (fas->galerkin) { 1381baa6e33SBarry Smith if (next) PetscCall(SNESSetFunction(next, NULL, SNESFASGalerkinFunctionDefault, next)); 13948a46eb9SPierre Jolivet if (fas->smoothd && fas->level != fas->levels - 1) PetscCall(SNESSetFunction(fas->smoothd, NULL, SNESFASGalerkinFunctionDefault, snes)); 14048a46eb9SPierre Jolivet if (fas->smoothu && fas->level != fas->levels - 1) PetscCall(SNESSetFunction(fas->smoothu, NULL, SNESFASGalerkinFunctionDefault, snes)); 14179d9a41aSPeter Brune } 14279d9a41aSPeter Brune 143534ebe21SPeter Brune /* sets the down (pre) smoother's default norm and sets it from options */ 144534ebe21SPeter Brune if (fas->smoothd) { 1452d157150SStefano Zampini if (fas->level == 0) { 1462d157150SStefano Zampini PetscCall(SNESSetNormSchedule(fas->smoothd, SNES_NORM_ALWAYS)); 147534ebe21SPeter Brune } else { 1489566063dSJacob Faibussowitsch PetscCall(SNESSetNormSchedule(fas->smoothd, SNES_NORM_FINAL_ONLY)); 149534ebe21SPeter Brune } 1509566063dSJacob Faibussowitsch PetscCall(SNESFASCycleSetUpSmoother_Private(snes, fas->smoothd)); 151534ebe21SPeter Brune } 152534ebe21SPeter Brune 153534ebe21SPeter Brune /* sets the up (post) smoother's default norm and sets it from options */ 154534ebe21SPeter Brune if (fas->smoothu) { 155534ebe21SPeter Brune if (fas->level != fas->levels - 1) { 1569566063dSJacob Faibussowitsch PetscCall(SNESSetNormSchedule(fas->smoothu, SNES_NORM_NONE)); 157534ebe21SPeter Brune } else { 1589566063dSJacob Faibussowitsch PetscCall(SNESSetNormSchedule(fas->smoothu, SNES_NORM_FINAL_ONLY)); 159534ebe21SPeter Brune } 1609566063dSJacob Faibussowitsch PetscCall(SNESFASCycleSetUpSmoother_Private(snes, fas->smoothu)); 161534ebe21SPeter Brune } 162d06165b7SPeter Brune 163ab8d36c9SPeter Brune if (next) { 16479d9a41aSPeter Brune /* gotta set up the solution vector for this to work */ 1659566063dSJacob Faibussowitsch if (!next->vec_sol) PetscCall(SNESFASCreateCoarseVec(snes, &next->vec_sol)); 1669566063dSJacob Faibussowitsch if (!next->vec_rhs) PetscCall(SNESFASCreateCoarseVec(snes, &next->vec_rhs)); 1679566063dSJacob Faibussowitsch PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)snes, (PetscObject)next)); 1689566063dSJacob Faibussowitsch PetscCall(SNESFASSetUpLineSearch_Private(snes, next)); 1699566063dSJacob Faibussowitsch PetscCall(SNESSetUp(next)); 17079d9a41aSPeter Brune } 171f833ba53SLisandro Dalcin 1726273346dSPeter Brune /* setup FAS work vectors */ 1736273346dSPeter Brune if (fas->galerkin) { 1749566063dSJacob Faibussowitsch PetscCall(VecDuplicate(snes->vec_sol, &fas->Xg)); 1759566063dSJacob Faibussowitsch PetscCall(VecDuplicate(snes->vec_sol, &fas->Fg)); 1766273346dSPeter Brune } 1773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 178421d9b32SPeter Brune } 179421d9b32SPeter Brune 180d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESSetFromOptions_FAS(SNES snes, PetscOptionItems *PetscOptionsObject) 181d71ae5a4SJacob Faibussowitsch { 182ee78dd50SPeter Brune SNES_FAS *fas = (SNES_FAS *)snes->data; 183ee78dd50SPeter Brune PetscInt levels = 1; 18487f44e3fSPeter Brune PetscBool flg = PETSC_FALSE, upflg = PETSC_FALSE, downflg = PETSC_FALSE, monflg = PETSC_FALSE, galerkinflg = PETSC_FALSE, continuationflg = PETSC_FALSE; 18507144faaSPeter Brune SNESFASType fastype; 186fde0ff24SPeter Brune const char *optionsprefix; 187f1c6b773SPeter Brune SNESLineSearch linesearch; 18866585501SPeter Brune PetscInt m, n_up, n_down; 189ab8d36c9SPeter Brune SNES next; 190ab8d36c9SPeter Brune PetscBool isFine; 191421d9b32SPeter Brune 192421d9b32SPeter Brune PetscFunctionBegin; 1939566063dSJacob Faibussowitsch PetscCall(SNESFASCycleIsFine(snes, &isFine)); 194d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "SNESFAS Options-----------------------------------"); 195ee78dd50SPeter Brune 196ab8d36c9SPeter Brune /* number of levels -- only process most options on the finest level */ 197ab8d36c9SPeter Brune if (isFine) { 1989566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-snes_fas_levels", "Number of Levels", "SNESFASSetLevels", levels, &levels, &flg)); 199c732cbdbSBarry Smith if (!flg && snes->dm) { 2009566063dSJacob Faibussowitsch PetscCall(DMGetRefineLevel(snes->dm, &levels)); 201c732cbdbSBarry Smith levels++; 202d1adcc6fSPeter Brune fas->usedmfornumberoflevels = PETSC_TRUE; 203c732cbdbSBarry Smith } 2049566063dSJacob Faibussowitsch PetscCall(SNESFASSetLevels(snes, levels, NULL)); 20507144faaSPeter Brune fastype = fas->fastype; 2069566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-snes_fas_type", "FAS correction type", "SNESFASSetType", SNESFASTypes, (PetscEnum)fastype, (PetscEnum *)&fastype, &flg)); 2071baa6e33SBarry Smith if (flg) PetscCall(SNESFASSetType(snes, fastype)); 208ee78dd50SPeter Brune 2099566063dSJacob Faibussowitsch PetscCall(SNESGetOptionsPrefix(snes, &optionsprefix)); 2109566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-snes_fas_cycles", "Number of cycles", "SNESFASSetCycles", fas->n_cycles, &m, &flg)); 2111baa6e33SBarry Smith if (flg) PetscCall(SNESFASSetCycles(snes, m)); 2129566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_fas_continuation", "Corrected grid-sequence continuation", "SNESFASSetContinuation", fas->continuation, &continuationflg, &flg)); 2131baa6e33SBarry Smith if (flg) PetscCall(SNESFASSetContinuation(snes, continuationflg)); 214fde0ff24SPeter Brune 2159566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_fas_galerkin", "Form coarse problems with Galerkin", "SNESFASSetGalerkin", fas->galerkin, &galerkinflg, &flg)); 2161baa6e33SBarry Smith if (flg) PetscCall(SNESFASSetGalerkin(snes, galerkinflg)); 217ee78dd50SPeter Brune 218928e959bSPeter Brune if (fas->fastype == SNES_FAS_FULL) { 2199566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_fas_full_downsweep", "Smooth on the initial down sweep for full FAS cycles", "SNESFASFullSetDownSweep", fas->full_downsweep, &fas->full_downsweep, &flg)); 2209566063dSJacob Faibussowitsch if (flg) PetscCall(SNESFASFullSetDownSweep(snes, fas->full_downsweep)); 2219566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_fas_full_total", "Use total restriction and interpolaton on the indial down and up sweeps for the full FAS cycle", "SNESFASFullSetUseTotal", fas->full_total, &fas->full_total, &flg)); 2229566063dSJacob Faibussowitsch if (flg) PetscCall(SNESFASFullSetTotal(snes, fas->full_total)); 223928e959bSPeter Brune } 224928e959bSPeter Brune 2259566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-snes_fas_smoothup", "Number of post-smoothing steps", "SNESFASSetNumberSmoothUp", fas->max_up_it, &n_up, &upflg)); 226162d76ddSPeter Brune 2279566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-snes_fas_smoothdown", "Number of pre-smoothing steps", "SNESFASSetNumberSmoothDown", fas->max_down_it, &n_down, &downflg)); 228162d76ddSPeter Brune 229d142ab34SLawrence Mitchell { 230d142ab34SLawrence Mitchell PetscViewer viewer; 231d142ab34SLawrence Mitchell PetscViewerFormat format; 2329566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)snes), ((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_fas_monitor", &viewer, &format, &monflg)); 233d142ab34SLawrence Mitchell if (monflg) { 234d142ab34SLawrence Mitchell PetscViewerAndFormat *vf; 2359566063dSJacob Faibussowitsch PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf)); 2369566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)viewer)); 2379566063dSJacob Faibussowitsch PetscCall(SNESFASSetMonitor(snes, vf, PETSC_TRUE)); 238d142ab34SLawrence Mitchell } 239d142ab34SLawrence Mitchell } 2400dd27c6cSPeter Brune flg = PETSC_FALSE; 2410dd27c6cSPeter Brune monflg = PETSC_TRUE; 2429566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_fas_log", "Log times for each FAS level", "SNESFASSetLog", monflg, &monflg, &flg)); 2439566063dSJacob Faibussowitsch if (flg) PetscCall(SNESFASSetLog(snes, monflg)); 244ab8d36c9SPeter Brune } 245ee78dd50SPeter Brune 246d0609cedSBarry Smith PetscOptionsHeadEnd(); 247f833ba53SLisandro Dalcin 2488cc86e31SPeter Brune /* setup from the determined types if there is no pointwise procedure or smoother defined */ 2491baa6e33SBarry Smith if (upflg) PetscCall(SNESFASSetNumberSmoothUp(snes, n_up)); 2501baa6e33SBarry Smith if (downflg) PetscCall(SNESFASSetNumberSmoothDown(snes, n_down)); 251eff52c0eSPeter Brune 2529e764e56SPeter Brune /* set up the default line search for coarse grid corrections */ 2539e764e56SPeter Brune if (fas->fastype == SNES_FAS_ADDITIVE) { 2549e764e56SPeter Brune if (!snes->linesearch) { 2559566063dSJacob Faibussowitsch PetscCall(SNESGetLineSearch(snes, &linesearch)); 2569566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHL2)); 2579e764e56SPeter Brune } 2589e764e56SPeter Brune } 2599e764e56SPeter Brune 260ee78dd50SPeter Brune /* recursive option setting for the smoothers */ 2619566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetCorrection(snes, &next)); 2629566063dSJacob Faibussowitsch if (next) PetscCall(SNESSetFromOptions(next)); 2633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 264421d9b32SPeter Brune } 265421d9b32SPeter Brune 2669804daf3SBarry Smith #include <petscdraw.h> 267d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESView_FAS(SNES snes, PetscViewer viewer) 268d71ae5a4SJacob Faibussowitsch { 269421d9b32SPeter Brune SNES_FAS *fas = (SNES_FAS *)snes->data; 270656ede7eSPeter Brune PetscBool isFine, iascii, isdraw; 271ab8d36c9SPeter Brune PetscInt i; 272ab8d36c9SPeter Brune SNES smoothu, smoothd, levelsnes; 273421d9b32SPeter Brune 274421d9b32SPeter Brune PetscFunctionBegin; 2759566063dSJacob Faibussowitsch PetscCall(SNESFASCycleIsFine(snes, &isFine)); 276ab8d36c9SPeter Brune if (isFine) { 2779566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 2789566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 279421d9b32SPeter Brune if (iascii) { 28063a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " type is %s, levels=%" PetscInt_FMT ", cycles=%" PetscInt_FMT "\n", SNESFASTypes[fas->fastype], fas->levels, fas->n_cycles)); 281ab8d36c9SPeter Brune if (fas->galerkin) { 2829566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Using Galerkin computed coarse grid function evaluation\n")); 283421d9b32SPeter Brune } else { 2849566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Not using Galerkin computed coarse grid function evaluation\n")); 285421d9b32SPeter Brune } 286ab8d36c9SPeter Brune for (i = 0; i < fas->levels; i++) { 2879566063dSJacob Faibussowitsch PetscCall(SNESFASGetCycleSNES(snes, i, &levelsnes)); 2889566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetSmootherUp(levelsnes, &smoothu)); 2899566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetSmootherDown(levelsnes, &smoothd)); 290ab8d36c9SPeter Brune if (!i) { 29163a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Coarse grid solver -- level %" PetscInt_FMT " -------------------------------\n", i)); 292421d9b32SPeter Brune } else { 29363a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Down solver (pre-smoother) on level %" PetscInt_FMT " -------------------------------\n", i)); 294421d9b32SPeter Brune } 2959566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 296166b3ea4SJed Brown if (smoothd) { 2979566063dSJacob Faibussowitsch PetscCall(SNESView(smoothd, viewer)); 298166b3ea4SJed Brown } else { 2999566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Not yet available\n")); 300166b3ea4SJed Brown } 3019566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 302ab8d36c9SPeter Brune if (i && (smoothd == smoothu)) { 3039566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Up solver (post-smoother) same as down solver (pre-smoother)\n")); 304ab8d36c9SPeter Brune } else if (i) { 30563a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Up solver (post-smoother) on level %" PetscInt_FMT " -------------------------------\n", i)); 3069566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 307166b3ea4SJed Brown if (smoothu) { 3089566063dSJacob Faibussowitsch PetscCall(SNESView(smoothu, viewer)); 309166b3ea4SJed Brown } else { 3109566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Not yet available\n")); 311166b3ea4SJed Brown } 3129566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 313ab8d36c9SPeter Brune } 314ab8d36c9SPeter Brune } 315656ede7eSPeter Brune } else if (isdraw) { 316656ede7eSPeter Brune PetscDraw draw; 317b4375e8dSPeter Brune PetscReal x, w, y, bottom, th, wth; 318656ede7eSPeter Brune SNES_FAS *curfas = fas; 3199566063dSJacob Faibussowitsch PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 3209566063dSJacob Faibussowitsch PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y)); 3219566063dSJacob Faibussowitsch PetscCall(PetscDrawStringGetSize(draw, &wth, &th)); 322656ede7eSPeter Brune bottom = y - th; 323656ede7eSPeter Brune while (curfas) { 324b4375e8dSPeter Brune if (!curfas->smoothu) { 3259566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom)); 3269566063dSJacob Faibussowitsch if (curfas->smoothd) PetscCall(SNESView(curfas->smoothd, viewer)); 3279566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw)); 328b4375e8dSPeter Brune } else { 329b4375e8dSPeter Brune w = 0.5 * PetscMin(1.0 - x, x); 3309566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x - w, bottom)); 3319566063dSJacob Faibussowitsch if (curfas->smoothd) PetscCall(SNESView(curfas->smoothd, viewer)); 3329566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw)); 3339566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x + w, bottom)); 3349566063dSJacob Faibussowitsch if (curfas->smoothu) PetscCall(SNESView(curfas->smoothu, viewer)); 3359566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw)); 336b4375e8dSPeter Brune } 337656ede7eSPeter Brune /* this is totally bogus but we have no way of knowing how low the previous one was draw to */ 338656ede7eSPeter Brune bottom -= 5 * th; 3391aa26658SKarl Rupp if (curfas->next) curfas = (SNES_FAS *)curfas->next->data; 3400298fd71SBarry Smith else curfas = NULL; 341656ede7eSPeter Brune } 342421d9b32SPeter Brune } 343ab8d36c9SPeter Brune } 3443ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 345421d9b32SPeter Brune } 346421d9b32SPeter Brune 34739bd7f45SPeter Brune /* 34839bd7f45SPeter Brune Defines the action of the downsmoother 34939bd7f45SPeter Brune */ 350d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESFASDownSmooth_Private(SNES snes, Vec B, Vec X, Vec F, PetscReal *fnorm) 351d71ae5a4SJacob Faibussowitsch { 352742fe5e2SPeter Brune SNESConvergedReason reason; 353ab8d36c9SPeter Brune Vec FPC; 354ab8d36c9SPeter Brune SNES smoothd; 3556cbb2f26SLawrence Mitchell PetscBool flg; 3560dd27c6cSPeter Brune SNES_FAS *fas = (SNES_FAS *)snes->data; 3576e111a19SKarl Rupp 358421d9b32SPeter Brune PetscFunctionBegin; 3599566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetSmootherDown(snes, &smoothd)); 3609566063dSJacob Faibussowitsch PetscCall(SNESSetInitialFunction(smoothd, F)); 3619566063dSJacob Faibussowitsch if (fas->eventsmoothsolve) PetscCall(PetscLogEventBegin(fas->eventsmoothsolve, smoothd, B, X, 0)); 3629566063dSJacob Faibussowitsch PetscCall(SNESSolve(smoothd, B, X)); 3639566063dSJacob Faibussowitsch if (fas->eventsmoothsolve) PetscCall(PetscLogEventEnd(fas->eventsmoothsolve, smoothd, B, X, 0)); 364742fe5e2SPeter Brune /* check convergence reason for the smoother */ 3659566063dSJacob Faibussowitsch PetscCall(SNESGetConvergedReason(smoothd, &reason)); 3661ff805c3SPeter Brune if (reason < 0 && !(reason == SNES_DIVERGED_MAX_IT || reason == SNES_DIVERGED_LOCAL_MIN || reason == SNES_DIVERGED_LINE_SEARCH)) { 367742fe5e2SPeter Brune snes->reason = SNES_DIVERGED_INNER; 3683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 369742fe5e2SPeter Brune } 3706cbb2f26SLawrence Mitchell 3719566063dSJacob Faibussowitsch PetscCall(SNESGetFunction(smoothd, &FPC, NULL, NULL)); 3729566063dSJacob Faibussowitsch PetscCall(SNESGetAlwaysComputesFinalResidual(smoothd, &flg)); 37348a46eb9SPierre Jolivet if (!flg) PetscCall(SNESComputeFunction(smoothd, X, FPC)); 3749566063dSJacob Faibussowitsch PetscCall(VecCopy(FPC, F)); 3759566063dSJacob Faibussowitsch if (fnorm) PetscCall(VecNorm(F, NORM_2, fnorm)); 3763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 37739bd7f45SPeter Brune } 37839bd7f45SPeter Brune 37939bd7f45SPeter Brune /* 38007144faaSPeter Brune Defines the action of the upsmoother 38139bd7f45SPeter Brune */ 382d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESFASUpSmooth_Private(SNES snes, Vec B, Vec X, Vec F, PetscReal *fnorm) 383d71ae5a4SJacob Faibussowitsch { 38439bd7f45SPeter Brune SNESConvergedReason reason; 385ab8d36c9SPeter Brune Vec FPC; 386ab8d36c9SPeter Brune SNES smoothu; 3876cbb2f26SLawrence Mitchell PetscBool flg; 3880dd27c6cSPeter Brune SNES_FAS *fas = (SNES_FAS *)snes->data; 389ab8d36c9SPeter Brune 3906e111a19SKarl Rupp PetscFunctionBegin; 3919566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetSmootherUp(snes, &smoothu)); 3929566063dSJacob Faibussowitsch if (fas->eventsmoothsolve) PetscCall(PetscLogEventBegin(fas->eventsmoothsolve, smoothu, 0, 0, 0)); 3939566063dSJacob Faibussowitsch PetscCall(SNESSolve(smoothu, B, X)); 3949566063dSJacob Faibussowitsch if (fas->eventsmoothsolve) PetscCall(PetscLogEventEnd(fas->eventsmoothsolve, smoothu, 0, 0, 0)); 39539bd7f45SPeter Brune /* check convergence reason for the smoother */ 3969566063dSJacob Faibussowitsch PetscCall(SNESGetConvergedReason(smoothu, &reason)); 3971ff805c3SPeter Brune if (reason < 0 && !(reason == SNES_DIVERGED_MAX_IT || reason == SNES_DIVERGED_LOCAL_MIN || reason == SNES_DIVERGED_LINE_SEARCH)) { 39839bd7f45SPeter Brune snes->reason = SNES_DIVERGED_INNER; 3993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 40039bd7f45SPeter Brune } 4019566063dSJacob Faibussowitsch PetscCall(SNESGetFunction(smoothu, &FPC, NULL, NULL)); 4029566063dSJacob Faibussowitsch PetscCall(SNESGetAlwaysComputesFinalResidual(smoothu, &flg)); 40348a46eb9SPierre Jolivet if (!flg) PetscCall(SNESComputeFunction(smoothu, X, FPC)); 4049566063dSJacob Faibussowitsch PetscCall(VecCopy(FPC, F)); 4059566063dSJacob Faibussowitsch if (fnorm) PetscCall(VecNorm(F, NORM_2, fnorm)); 4063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 40739bd7f45SPeter Brune } 40839bd7f45SPeter Brune 409938e4a01SJed Brown /*@ 410*420bcc1bSBarry Smith SNESFASCreateCoarseVec - create a `Vec` corresponding to a state vector on one level coarser than the current level 411938e4a01SJed Brown 412938e4a01SJed Brown Collective 413938e4a01SJed Brown 4144165533cSJose E. Roman Input Parameter: 415f6dfbefdSBarry Smith . snes - `SNESFAS` object 416938e4a01SJed Brown 4174165533cSJose E. Roman Output Parameter: 418*420bcc1bSBarry Smith . Xcoarse - vector on level one coarser than the current level 419938e4a01SJed Brown 420938e4a01SJed Brown Level: developer 421938e4a01SJed Brown 422*420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESFASSetRestriction()`, `SNESFASRestrict()`, `SNESFAS` 423938e4a01SJed Brown @*/ 424d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESFASCreateCoarseVec(SNES snes, Vec *Xcoarse) 425d71ae5a4SJacob Faibussowitsch { 426f833ba53SLisandro Dalcin SNES_FAS *fas; 427938e4a01SJed Brown 428938e4a01SJed Brown PetscFunctionBegin; 429f833ba53SLisandro Dalcin PetscValidHeaderSpecificType(snes, SNES_CLASSID, 1, SNESFAS); 4304f572ea9SToby Isaac PetscAssertPointer(Xcoarse, 2); 431f833ba53SLisandro Dalcin fas = (SNES_FAS *)snes->data; 4321aa26658SKarl Rupp if (fas->rscale) { 4339566063dSJacob Faibussowitsch PetscCall(VecDuplicate(fas->rscale, Xcoarse)); 43490b9e4c9SPablo Brubeck } else if (fas->interpolate) { 43590b9e4c9SPablo Brubeck PetscCall(MatCreateVecs(fas->interpolate, Xcoarse, NULL)); 43690b9e4c9SPablo Brubeck } else SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Must set rscale or interpolation"); 4373ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 438938e4a01SJed Brown } 439938e4a01SJed Brown 440e9923e8dSJed Brown /*@ 441f6dfbefdSBarry Smith SNESFASRestrict - restrict a `Vec` to the next coarser level 442e9923e8dSJed Brown 443e9923e8dSJed Brown Collective 444e9923e8dSJed Brown 4454165533cSJose E. Roman Input Parameters: 446f6dfbefdSBarry Smith + fine - `SNES` from which to restrict 447e9923e8dSJed Brown - Xfine - vector to restrict 448e9923e8dSJed Brown 4494165533cSJose E. Roman Output Parameter: 450e9923e8dSJed Brown . Xcoarse - result of restriction 451e9923e8dSJed Brown 452e9923e8dSJed Brown Level: developer 453e9923e8dSJed Brown 454*420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESFAS`, `SNESFASSetRestriction()`, `SNESFASSetInjection()`, `SNESFASCreateCoarseVec()` 455e9923e8dSJed Brown @*/ 456d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESFASRestrict(SNES fine, Vec Xfine, Vec Xcoarse) 457d71ae5a4SJacob Faibussowitsch { 458f833ba53SLisandro Dalcin SNES_FAS *fas; 459e9923e8dSJed Brown 460e9923e8dSJed Brown PetscFunctionBegin; 461f833ba53SLisandro Dalcin PetscValidHeaderSpecificType(fine, SNES_CLASSID, 1, SNESFAS); 462e9923e8dSJed Brown PetscValidHeaderSpecific(Xfine, VEC_CLASSID, 2); 463e9923e8dSJed Brown PetscValidHeaderSpecific(Xcoarse, VEC_CLASSID, 3); 464f833ba53SLisandro Dalcin fas = (SNES_FAS *)fine->data; 465e9923e8dSJed Brown if (fas->inject) { 4669566063dSJacob Faibussowitsch PetscCall(MatRestrict(fas->inject, Xfine, Xcoarse)); 467e9923e8dSJed Brown } else { 4689566063dSJacob Faibussowitsch PetscCall(MatRestrict(fas->restrct, Xfine, Xcoarse)); 4699566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(Xcoarse, fas->rscale, Xcoarse)); 470e9923e8dSJed Brown } 4713ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 472e9923e8dSJed Brown } 473e9923e8dSJed Brown 47439bd7f45SPeter Brune /* 4756dfbafefSToby Isaac Performs a variant of FAS using the interpolated total coarse solution 4766dfbafefSToby Isaac 4776dfbafefSToby Isaac fine problem: F(x) = b 4786dfbafefSToby Isaac coarse problem: F^c(x^c) = Rb, Initial guess Rx 4796dfbafefSToby Isaac interpolated solution: x^f = I x^c (total solution interpolation 4806dfbafefSToby Isaac */ 481d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESFASInterpolatedCoarseSolution(SNES snes, Vec X, Vec X_new) 482d71ae5a4SJacob Faibussowitsch { 4836dfbafefSToby Isaac Vec X_c, B_c; 4846dfbafefSToby Isaac SNESConvergedReason reason; 4856dfbafefSToby Isaac SNES next; 4866dfbafefSToby Isaac Mat restrct, interpolate; 4876dfbafefSToby Isaac SNES_FAS *fasc; 4886dfbafefSToby Isaac 4896dfbafefSToby Isaac PetscFunctionBegin; 4909566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetCorrection(snes, &next)); 4916dfbafefSToby Isaac if (next) { 4926dfbafefSToby Isaac fasc = (SNES_FAS *)next->data; 4936dfbafefSToby Isaac 4949566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetRestriction(snes, &restrct)); 4959566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetInterpolation(snes, &interpolate)); 4966dfbafefSToby Isaac 4976dfbafefSToby Isaac X_c = next->vec_sol; 4986dfbafefSToby Isaac 4999566063dSJacob Faibussowitsch if (fasc->eventinterprestrict) PetscCall(PetscLogEventBegin(fasc->eventinterprestrict, snes, 0, 0, 0)); 5006dfbafefSToby Isaac /* restrict the total solution: Rb */ 5019566063dSJacob Faibussowitsch PetscCall(SNESFASRestrict(snes, X, X_c)); 5026dfbafefSToby Isaac B_c = next->vec_rhs; 5036dfbafefSToby Isaac if (snes->vec_rhs) { 5046dfbafefSToby Isaac /* restrict the total rhs defect: Rb */ 5059566063dSJacob Faibussowitsch PetscCall(MatRestrict(restrct, snes->vec_rhs, B_c)); 5066dfbafefSToby Isaac } else { 5079566063dSJacob Faibussowitsch PetscCall(VecSet(B_c, 0.)); 5086dfbafefSToby Isaac } 5099566063dSJacob Faibussowitsch if (fasc->eventinterprestrict) PetscCall(PetscLogEventEnd(fasc->eventinterprestrict, snes, 0, 0, 0)); 5106dfbafefSToby Isaac 5119566063dSJacob Faibussowitsch PetscCall(SNESSolve(next, B_c, X_c)); 5129566063dSJacob Faibussowitsch PetscCall(SNESGetConvergedReason(next, &reason)); 5136dfbafefSToby Isaac if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 5146dfbafefSToby Isaac snes->reason = SNES_DIVERGED_INNER; 5153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 5166dfbafefSToby Isaac } 5176dfbafefSToby Isaac /* x^f <- Ix^c*/ 5186dfbafefSToby Isaac DM dmc, dmf; 5196dfbafefSToby Isaac 5209566063dSJacob Faibussowitsch PetscCall(SNESGetDM(next, &dmc)); 5219566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dmf)); 5229566063dSJacob Faibussowitsch if (fasc->eventinterprestrict) PetscCall(PetscLogEventBegin(fasc->eventinterprestrict, snes, 0, 0, 0)); 5239566063dSJacob Faibussowitsch PetscCall(DMInterpolateSolution(dmc, dmf, interpolate, X_c, X_new)); 5249566063dSJacob Faibussowitsch if (fasc->eventinterprestrict) PetscCall(PetscLogEventEnd(fasc->eventinterprestrict, snes, 0, 0, 0)); 5259566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)X_c, "Coarse solution")); 5269566063dSJacob Faibussowitsch PetscCall(VecViewFromOptions(X_c, NULL, "-fas_coarse_solution_view")); 5279566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)X_new, "Updated Fine solution")); 5289566063dSJacob Faibussowitsch PetscCall(VecViewFromOptions(X_new, NULL, "-fas_levels_1_solution_view")); 5296dfbafefSToby Isaac } 5303ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 5316dfbafefSToby Isaac } 5326dfbafefSToby Isaac 5336dfbafefSToby Isaac /* 53439bd7f45SPeter Brune Performs the FAS coarse correction as: 53539bd7f45SPeter Brune 536b5527d98SMatthew G. Knepley fine problem: F(x) = b 537b5527d98SMatthew G. Knepley coarse problem: F^c(x^c) = b^c 53839bd7f45SPeter Brune 539b5527d98SMatthew G. Knepley b^c = F^c(Rx) - R(F(x) - b) 54039bd7f45SPeter Brune */ 54166976f2fSJacob Faibussowitsch static PetscErrorCode SNESFASCoarseCorrection(SNES snes, Vec X, Vec F, Vec X_new) 542d71ae5a4SJacob Faibussowitsch { 54339bd7f45SPeter Brune Vec X_c, Xo_c, F_c, B_c; 54439bd7f45SPeter Brune SNESConvergedReason reason; 545ab8d36c9SPeter Brune SNES next; 546ab8d36c9SPeter Brune Mat restrct, interpolate; 5470dd27c6cSPeter Brune SNES_FAS *fasc; 5485fd66863SKarl Rupp 54939bd7f45SPeter Brune PetscFunctionBegin; 5509566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetCorrection(snes, &next)); 551ab8d36c9SPeter Brune if (next) { 5520dd27c6cSPeter Brune fasc = (SNES_FAS *)next->data; 5530dd27c6cSPeter Brune 5549566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetRestriction(snes, &restrct)); 5559566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetInterpolation(snes, &interpolate)); 556ab8d36c9SPeter Brune 557ab8d36c9SPeter Brune X_c = next->vec_sol; 558ab8d36c9SPeter Brune Xo_c = next->work[0]; 559ab8d36c9SPeter Brune F_c = next->vec_func; 560ab8d36c9SPeter Brune B_c = next->vec_rhs; 561efe1f98aSPeter Brune 5629566063dSJacob Faibussowitsch if (fasc->eventinterprestrict) PetscCall(PetscLogEventBegin(fasc->eventinterprestrict, snes, 0, 0, 0)); 5639566063dSJacob Faibussowitsch PetscCall(SNESFASRestrict(snes, X, Xo_c)); 5645609cbf2SMatthew G. Knepley /* restrict the defect: R(F(x) - b) */ 5659566063dSJacob Faibussowitsch PetscCall(MatRestrict(restrct, F, B_c)); 5669566063dSJacob Faibussowitsch if (fasc->eventinterprestrict) PetscCall(PetscLogEventEnd(fasc->eventinterprestrict, snes, 0, 0, 0)); 5670dd27c6cSPeter Brune 5689566063dSJacob Faibussowitsch if (fasc->eventresidual) PetscCall(PetscLogEventBegin(fasc->eventresidual, next, 0, 0, 0)); 5695609cbf2SMatthew G. Knepley /* F_c = F^c(Rx) - R(F(x) - b) since the second term was sitting in next->vec_rhs */ 5709566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(next, Xo_c, F_c)); 5719566063dSJacob Faibussowitsch if (fasc->eventresidual) PetscCall(PetscLogEventEnd(fasc->eventresidual, next, 0, 0, 0)); 5720dd27c6cSPeter Brune 5730dd27c6cSPeter Brune /* solve the coarse problem corresponding to F^c(x^c) = b^c = F^c(Rx) - R(F(x) - b) */ 5749566063dSJacob Faibussowitsch PetscCall(VecCopy(B_c, X_c)); 5759566063dSJacob Faibussowitsch PetscCall(VecCopy(F_c, B_c)); 5769566063dSJacob Faibussowitsch PetscCall(VecCopy(X_c, F_c)); 577ee78dd50SPeter Brune /* set initial guess of the coarse problem to the projected fine solution */ 5789566063dSJacob Faibussowitsch PetscCall(VecCopy(Xo_c, X_c)); 579c90fad12SPeter Brune 580c90fad12SPeter Brune /* recurse to the next level */ 5819566063dSJacob Faibussowitsch PetscCall(SNESSetInitialFunction(next, F_c)); 5829566063dSJacob Faibussowitsch PetscCall(SNESSolve(next, B_c, X_c)); 5839566063dSJacob Faibussowitsch PetscCall(SNESGetConvergedReason(next, &reason)); 584742fe5e2SPeter Brune if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 585742fe5e2SPeter Brune snes->reason = SNES_DIVERGED_INNER; 5863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 587742fe5e2SPeter Brune } 588fa9694d7SPeter Brune /* correct as x <- x + I(x^c - Rx)*/ 5899566063dSJacob Faibussowitsch PetscCall(VecAXPY(X_c, -1.0, Xo_c)); 5900dd27c6cSPeter Brune 5919566063dSJacob Faibussowitsch if (fasc->eventinterprestrict) PetscCall(PetscLogEventBegin(fasc->eventinterprestrict, snes, 0, 0, 0)); 5929566063dSJacob Faibussowitsch PetscCall(MatInterpolateAdd(interpolate, X_c, X, X_new)); 5939566063dSJacob Faibussowitsch if (fasc->eventinterprestrict) PetscCall(PetscLogEventEnd(fasc->eventinterprestrict, snes, 0, 0, 0)); 5949566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)X_c, "Coarse correction")); 5959566063dSJacob Faibussowitsch PetscCall(VecViewFromOptions(X_c, NULL, "-fas_coarse_solution_view")); 5969566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)X_new, "Updated Fine solution")); 5979566063dSJacob Faibussowitsch PetscCall(VecViewFromOptions(X_new, NULL, "-fas_levels_1_solution_view")); 598293a7e31SPeter Brune } 5993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 60039bd7f45SPeter Brune } 60139bd7f45SPeter Brune 60239bd7f45SPeter Brune /* 603*420bcc1bSBarry Smith The additive cycle is: 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 */ 613d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESFASCycle_Additive(SNES snes, Vec X) 614d71ae5a4SJacob Faibussowitsch { 61507144faaSPeter Brune Vec F, B, Xhat; 61622c1e704SPeter Brune Vec X_c, Xo_c, F_c, B_c; 61707144faaSPeter Brune SNESConvergedReason reason; 61822c1e704SPeter Brune PetscReal xnorm, fnorm, ynorm; 619422a814eSBarry Smith SNESLineSearchReason lsresult; 620ab8d36c9SPeter Brune SNES next; 621ab8d36c9SPeter Brune Mat restrct, interpolate; 6220dd27c6cSPeter Brune SNES_FAS *fas = (SNES_FAS *)snes->data, *fasc; 6230dd27c6cSPeter Brune 62439bd7f45SPeter Brune PetscFunctionBegin; 6259566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetCorrection(snes, &next)); 62639bd7f45SPeter Brune F = snes->vec_func; 62739bd7f45SPeter Brune B = snes->vec_rhs; 628e7f468e7SPeter Brune Xhat = snes->work[1]; 6299566063dSJacob Faibussowitsch PetscCall(VecCopy(X, Xhat)); 63007144faaSPeter Brune /* recurse first */ 631ab8d36c9SPeter Brune if (next) { 6320dd27c6cSPeter Brune fasc = (SNES_FAS *)next->data; 6339566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetRestriction(snes, &restrct)); 6349566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetInterpolation(snes, &interpolate)); 6359566063dSJacob Faibussowitsch if (fas->eventresidual) PetscCall(PetscLogEventBegin(fas->eventresidual, snes, 0, 0, 0)); 6369566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, Xhat, F)); 6379566063dSJacob Faibussowitsch if (fas->eventresidual) PetscCall(PetscLogEventEnd(fas->eventresidual, snes, 0, 0, 0)); 6389566063dSJacob Faibussowitsch PetscCall(VecNorm(F, NORM_2, &fnorm)); 639ab8d36c9SPeter Brune X_c = next->vec_sol; 640ab8d36c9SPeter Brune Xo_c = next->work[0]; 641ab8d36c9SPeter Brune F_c = next->vec_func; 642ab8d36c9SPeter Brune B_c = next->vec_rhs; 64339bd7f45SPeter Brune 6449566063dSJacob Faibussowitsch PetscCall(SNESFASRestrict(snes, Xhat, Xo_c)); 64507144faaSPeter Brune /* restrict the defect */ 6469566063dSJacob Faibussowitsch PetscCall(MatRestrict(restrct, F, B_c)); 64707144faaSPeter Brune 64807144faaSPeter Brune /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */ 6499566063dSJacob Faibussowitsch if (fasc->eventresidual) PetscCall(PetscLogEventBegin(fasc->eventresidual, next, 0, 0, 0)); 6509566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(next, Xo_c, F_c)); 6519566063dSJacob Faibussowitsch if (fasc->eventresidual) PetscCall(PetscLogEventEnd(fasc->eventresidual, next, 0, 0, 0)); 6529566063dSJacob Faibussowitsch PetscCall(VecCopy(B_c, X_c)); 6539566063dSJacob Faibussowitsch PetscCall(VecCopy(F_c, B_c)); 6549566063dSJacob Faibussowitsch PetscCall(VecCopy(X_c, F_c)); 65507144faaSPeter Brune /* set initial guess of the coarse problem to the projected fine solution */ 6569566063dSJacob Faibussowitsch PetscCall(VecCopy(Xo_c, X_c)); 65707144faaSPeter Brune 65807144faaSPeter Brune /* recurse */ 6599566063dSJacob Faibussowitsch PetscCall(SNESSetInitialFunction(next, F_c)); 6609566063dSJacob Faibussowitsch PetscCall(SNESSolve(next, B_c, X_c)); 66107144faaSPeter Brune 66207144faaSPeter Brune /* smooth on this level */ 6639566063dSJacob Faibussowitsch PetscCall(SNESFASDownSmooth_Private(snes, B, X, F, &fnorm)); 66407144faaSPeter Brune 6659566063dSJacob Faibussowitsch PetscCall(SNESGetConvergedReason(next, &reason)); 66607144faaSPeter Brune if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 66707144faaSPeter Brune snes->reason = SNES_DIVERGED_INNER; 6683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 66907144faaSPeter Brune } 67007144faaSPeter Brune 67107144faaSPeter Brune /* correct as x <- x + I(x^c - Rx)*/ 6729566063dSJacob Faibussowitsch PetscCall(VecAYPX(X_c, -1.0, Xo_c)); 6739566063dSJacob Faibussowitsch PetscCall(MatInterpolate(interpolate, X_c, Xhat)); 67407144faaSPeter Brune 675ddebd997SPeter Brune /* additive correction of the coarse direction*/ 6769566063dSJacob Faibussowitsch PetscCall(SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Xhat)); 6779566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetReason(snes->linesearch, &lsresult)); 6789566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetNorms(snes->linesearch, &xnorm, &snes->norm, &ynorm)); 679422a814eSBarry Smith if (lsresult) { 6809e764e56SPeter Brune if (++snes->numFailures >= snes->maxFailures) { 6819e764e56SPeter Brune snes->reason = SNES_DIVERGED_LINE_SEARCH; 6823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6839e764e56SPeter Brune } 6849e764e56SPeter Brune } 68507144faaSPeter Brune } else { 6869566063dSJacob Faibussowitsch PetscCall(SNESFASDownSmooth_Private(snes, B, X, F, &snes->norm)); 68707144faaSPeter Brune } 6883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 68939bd7f45SPeter Brune } 69039bd7f45SPeter Brune 69139bd7f45SPeter Brune /* 69239bd7f45SPeter Brune Defines the FAS cycle as: 69339bd7f45SPeter Brune 694b5527d98SMatthew G. Knepley fine problem: F(x) = b 69539bd7f45SPeter Brune coarse problem: F^c(x) = b^c 69639bd7f45SPeter Brune 697b5527d98SMatthew G. Knepley b^c = F^c(Rx) - R(F(x) - b) 69839bd7f45SPeter Brune 69939bd7f45SPeter Brune correction: 70039bd7f45SPeter Brune 70139bd7f45SPeter Brune x = x + I(x^c - Rx) 70239bd7f45SPeter Brune */ 703d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESFASCycle_Multiplicative(SNES snes, Vec X) 704d71ae5a4SJacob Faibussowitsch { 70539bd7f45SPeter Brune Vec F, B; 70634d65b3cSPeter Brune SNES next; 70739bd7f45SPeter Brune 70839bd7f45SPeter Brune PetscFunctionBegin; 70939bd7f45SPeter Brune F = snes->vec_func; 71039bd7f45SPeter Brune B = snes->vec_rhs; 71139bd7f45SPeter Brune /* pre-smooth -- just update using the pre-smoother */ 7129566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetCorrection(snes, &next)); 7139566063dSJacob Faibussowitsch PetscCall(SNESFASDownSmooth_Private(snes, B, X, F, &snes->norm)); 71434d65b3cSPeter Brune if (next) { 7159566063dSJacob Faibussowitsch PetscCall(SNESFASCoarseCorrection(snes, X, F, X)); 7169566063dSJacob Faibussowitsch PetscCall(SNESFASUpSmooth_Private(snes, B, X, F, &snes->norm)); 717fe6f9142SPeter Brune } 7183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 719421d9b32SPeter Brune } 720421d9b32SPeter Brune 721d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESFASCycleSetupPhase_Full(SNES snes) 722d71ae5a4SJacob Faibussowitsch { 7238c94862eSPeter Brune SNES next; 7248c94862eSPeter Brune SNES_FAS *fas = (SNES_FAS *)snes->data; 7258c94862eSPeter Brune PetscBool isFine; 7268c94862eSPeter Brune 7278c94862eSPeter Brune PetscFunctionBegin; 7288c94862eSPeter Brune /* pre-smooth -- just update using the pre-smoother */ 7299566063dSJacob Faibussowitsch PetscCall(SNESFASCycleIsFine(snes, &isFine)); 7309566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetCorrection(snes, &next)); 7318c94862eSPeter Brune fas->full_stage = 0; 7329566063dSJacob Faibussowitsch if (next) PetscCall(SNESFASCycleSetupPhase_Full(next)); 7333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 7348c94862eSPeter Brune } 7358c94862eSPeter Brune 736d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESFASCycle_Full(SNES snes, Vec X) 737d71ae5a4SJacob Faibussowitsch { 7388c94862eSPeter Brune Vec F, B; 7398c94862eSPeter Brune SNES_FAS *fas = (SNES_FAS *)snes->data; 7408c94862eSPeter Brune PetscBool isFine; 7418c94862eSPeter Brune SNES next; 7428c94862eSPeter Brune 7438c94862eSPeter Brune PetscFunctionBegin; 7448c94862eSPeter Brune F = snes->vec_func; 7458c94862eSPeter Brune B = snes->vec_rhs; 7469566063dSJacob Faibussowitsch PetscCall(SNESFASCycleIsFine(snes, &isFine)); 7479566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetCorrection(snes, &next)); 7488c94862eSPeter Brune 7491baa6e33SBarry Smith if (isFine) PetscCall(SNESFASCycleSetupPhase_Full(snes)); 7508c94862eSPeter Brune 7518c94862eSPeter Brune if (fas->full_stage == 0) { 752928e959bSPeter Brune /* downsweep */ 7538c94862eSPeter Brune if (next) { 7548c94862eSPeter Brune if (fas->level != 1) next->max_its += 1; 7559566063dSJacob Faibussowitsch if (fas->full_downsweep) PetscCall(SNESFASDownSmooth_Private(snes, B, X, F, &snes->norm)); 756e140b65aSPatrick Farrell fas->full_downsweep = PETSC_TRUE; 7579566063dSJacob Faibussowitsch if (fas->full_total) PetscCall(SNESFASInterpolatedCoarseSolution(snes, X, X)); 7589566063dSJacob Faibussowitsch else PetscCall(SNESFASCoarseCorrection(snes, X, F, X)); 7596dfbafefSToby Isaac fas->full_total = PETSC_FALSE; 7609566063dSJacob Faibussowitsch PetscCall(SNESFASUpSmooth_Private(snes, B, X, F, &snes->norm)); 7618c94862eSPeter Brune if (fas->level != 1) next->max_its -= 1; 7628c94862eSPeter Brune } else { 763a3a80b83SMatthew G. Knepley /* The smoother on the coarse level is the coarse solver */ 7649566063dSJacob Faibussowitsch PetscCall(SNESFASDownSmooth_Private(snes, B, X, F, &snes->norm)); 7658c94862eSPeter Brune } 7668c94862eSPeter Brune fas->full_stage = 1; 7678c94862eSPeter Brune } else if (fas->full_stage == 1) { 7689566063dSJacob Faibussowitsch if (snes->iter == 0) PetscCall(SNESFASDownSmooth_Private(snes, B, X, F, &snes->norm)); 7698c94862eSPeter Brune if (next) { 7709566063dSJacob Faibussowitsch PetscCall(SNESFASCoarseCorrection(snes, X, F, X)); 7719566063dSJacob Faibussowitsch PetscCall(SNESFASUpSmooth_Private(snes, B, X, F, &snes->norm)); 7728c94862eSPeter Brune } 7738c94862eSPeter Brune } 7748c94862eSPeter Brune /* final v-cycle */ 7758c94862eSPeter Brune if (isFine) { 7768c94862eSPeter Brune if (next) { 7779566063dSJacob Faibussowitsch PetscCall(SNESFASCoarseCorrection(snes, X, F, X)); 7789566063dSJacob Faibussowitsch PetscCall(SNESFASUpSmooth_Private(snes, B, X, F, &snes->norm)); 7798c94862eSPeter Brune } 7808c94862eSPeter Brune } 7813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 7828c94862eSPeter Brune } 7838c94862eSPeter Brune 784d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESFASCycle_Kaskade(SNES snes, Vec X) 785d71ae5a4SJacob Faibussowitsch { 78634d65b3cSPeter Brune Vec F, B; 78734d65b3cSPeter Brune SNES next; 78834d65b3cSPeter Brune 78934d65b3cSPeter Brune PetscFunctionBegin; 79034d65b3cSPeter Brune F = snes->vec_func; 79134d65b3cSPeter Brune B = snes->vec_rhs; 7929566063dSJacob Faibussowitsch PetscCall(SNESFASCycleGetCorrection(snes, &next)); 79334d65b3cSPeter Brune if (next) { 7949566063dSJacob Faibussowitsch PetscCall(SNESFASCoarseCorrection(snes, X, F, X)); 7959566063dSJacob Faibussowitsch PetscCall(SNESFASUpSmooth_Private(snes, B, X, F, &snes->norm)); 79634d65b3cSPeter Brune } else { 7979566063dSJacob Faibussowitsch PetscCall(SNESFASDownSmooth_Private(snes, B, X, F, &snes->norm)); 79834d65b3cSPeter Brune } 7993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 80034d65b3cSPeter Brune } 80134d65b3cSPeter Brune 802fffbeea8SBarry Smith PetscBool SNEScite = PETSC_FALSE; 803fffbeea8SBarry Smith const char SNESCitation[] = "@techreport{pbmkbsxt2012,\n" 804fffbeea8SBarry Smith " title = {Composing Scalable Nonlinear Algebraic Solvers},\n" 805fffbeea8SBarry Smith " author = {Peter Brune and Mathew Knepley and Barry Smith and Xuemin Tu},\n" 806fffbeea8SBarry Smith " year = 2013,\n" 807fffbeea8SBarry Smith " type = Preprint,\n" 808fffbeea8SBarry Smith " number = {ANL/MCS-P2010-0112},\n" 809fffbeea8SBarry Smith " institution = {Argonne National Laboratory}\n}\n"; 810fffbeea8SBarry Smith 811d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESSolve_FAS(SNES snes) 812d71ae5a4SJacob Faibussowitsch { 813f833ba53SLisandro Dalcin PetscInt i; 814ddb5aff1SPeter Brune Vec X, F; 815fe6f9142SPeter Brune PetscReal fnorm; 816b17ce1afSJed Brown SNES_FAS *fas = (SNES_FAS *)snes->data, *ffas; 817b17ce1afSJed Brown DM dm; 818e70c42e5SPeter Brune PetscBool isFine; 819b17ce1afSJed Brown 820421d9b32SPeter Brune PetscFunctionBegin; 8210b121fc5SBarry Smith PetscCheck(!snes->xl && !snes->xu && !snes->ops->computevariablebounds, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name); 822c579b300SPatrick Farrell 8239566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(SNESCitation, &SNEScite)); 824fe6f9142SPeter Brune snes->reason = SNES_CONVERGED_ITERATING; 825fa9694d7SPeter Brune X = snes->vec_sol; 826f5a6d4f9SBarry Smith F = snes->vec_func; 827293a7e31SPeter Brune 8289566063dSJacob Faibussowitsch PetscCall(SNESFASCycleIsFine(snes, &isFine)); 829293a7e31SPeter Brune /* norm setup */ 8309566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 831fe6f9142SPeter Brune snes->iter = 0; 832f833ba53SLisandro Dalcin snes->norm = 0; 8339566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 834e4ed7901SPeter Brune if (!snes->vec_func_init_set) { 8359566063dSJacob Faibussowitsch if (fas->eventresidual) PetscCall(PetscLogEventBegin(fas->eventresidual, snes, 0, 0, 0)); 8369566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, X, F)); 8379566063dSJacob Faibussowitsch if (fas->eventresidual) PetscCall(PetscLogEventEnd(fas->eventresidual, snes, 0, 0, 0)); 8381aa26658SKarl Rupp } else snes->vec_func_init_set = PETSC_FALSE; 839e4ed7901SPeter Brune 8409566063dSJacob Faibussowitsch PetscCall(VecNorm(F, NORM_2, &fnorm)); /* fnorm <- ||F|| */ 841422a814eSBarry Smith SNESCheckFunctionNorm(snes, fnorm); 8429566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 843fe6f9142SPeter Brune snes->norm = fnorm; 8449566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 8459566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes, fnorm, 0)); 846fe6f9142SPeter Brune 847fe6f9142SPeter Brune /* test convergence */ 8482d157150SStefano Zampini PetscCall(SNESConverged(snes, 0, 0.0, 0.0, fnorm)); 8492d157150SStefano Zampini PetscCall(SNESMonitor(snes, snes->iter, fnorm)); 8503ba16761SJacob Faibussowitsch if (snes->reason) PetscFunctionReturn(PETSC_SUCCESS); 851e4ed7901SPeter Brune 852b9c2fdf1SPeter Brune if (isFine) { 853b9c2fdf1SPeter Brune /* propagate scale-dependent data up the hierarchy */ 8549566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dm)); 855b17ce1afSJed Brown for (ffas = fas; ffas->next; ffas = (SNES_FAS *)ffas->next->data) { 856b17ce1afSJed Brown DM dmcoarse; 8579566063dSJacob Faibussowitsch PetscCall(SNESGetDM(ffas->next, &dmcoarse)); 8589566063dSJacob Faibussowitsch PetscCall(DMRestrict(dm, ffas->restrct, ffas->rscale, ffas->inject, dmcoarse)); 859b17ce1afSJed Brown dm = dmcoarse; 860b17ce1afSJed Brown } 861b9c2fdf1SPeter Brune } 862b17ce1afSJed Brown 863f833ba53SLisandro Dalcin for (i = 0; i < snes->max_its; i++) { 864fe6f9142SPeter Brune /* Call general purpose update function */ 865dbbe0bcdSBarry Smith PetscTryTypeMethod(snes, update, snes->iter); 866f833ba53SLisandro Dalcin 86707144faaSPeter Brune if (fas->fastype == SNES_FAS_MULTIPLICATIVE) { 8689566063dSJacob Faibussowitsch PetscCall(SNESFASCycle_Multiplicative(snes, X)); 8698c94862eSPeter Brune } else if (fas->fastype == SNES_FAS_ADDITIVE) { 8709566063dSJacob Faibussowitsch PetscCall(SNESFASCycle_Additive(snes, X)); 8718c94862eSPeter Brune } else if (fas->fastype == SNES_FAS_FULL) { 8729566063dSJacob Faibussowitsch PetscCall(SNESFASCycle_Full(snes, X)); 87334d65b3cSPeter Brune } else if (fas->fastype == SNES_FAS_KASKADE) { 8749566063dSJacob Faibussowitsch PetscCall(SNESFASCycle_Kaskade(snes, X)); 8756c4ed002SBarry Smith } else SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Unsupported FAS type"); 876742fe5e2SPeter Brune 877742fe5e2SPeter Brune /* check for FAS cycle divergence */ 8783ba16761SJacob Faibussowitsch if (snes->reason != SNES_CONVERGED_ITERATING) PetscFunctionReturn(PETSC_SUCCESS); 879b9c2fdf1SPeter Brune 880c90fad12SPeter Brune /* Monitor convergence */ 8819566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 882c90fad12SPeter Brune snes->iter = i + 1; 8839566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 8849566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes, snes->norm, 0)); 8852d157150SStefano Zampini PetscCall(SNESConverged(snes, snes->iter, 0.0, 0.0, snes->norm)); 8869566063dSJacob Faibussowitsch PetscCall(SNESMonitor(snes, snes->iter, snes->norm)); 887c90fad12SPeter Brune if (snes->reason) break; 888fe6f9142SPeter Brune } 8893ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 890421d9b32SPeter Brune } 89140244768SBarry Smith 89240244768SBarry Smith /*MC 89340244768SBarry Smith SNESFAS - Full Approximation Scheme nonlinear multigrid solver. 89440244768SBarry Smith 89540244768SBarry Smith The nonlinear problem is solved by correction using coarse versions 89640244768SBarry Smith of the nonlinear problem. This problem is perturbed so that a projected 89740244768SBarry Smith solution of the fine problem elicits no correction from the coarse problem. 89840244768SBarry Smith 899f6dfbefdSBarry Smith Options Database Keys and Prefixes: 90040244768SBarry Smith + -snes_fas_levels - The number of levels 90140244768SBarry Smith . -snes_fas_cycles<1> - The number of cycles -- 1 for V, 2 for W 90240244768SBarry Smith . -snes_fas_type<additive,multiplicative,full,kaskade> - Additive or multiplicative cycle 903f6dfbefdSBarry Smith . -snes_fas_galerkin<`PETSC_FALSE`> - Form coarse problems by projection back upon the fine problem 90440244768SBarry Smith . -snes_fas_smoothup<1> - The number of iterations of the post-smoother 90540244768SBarry Smith . -snes_fas_smoothdown<1> - The number of iterations of the pre-smoother 90640244768SBarry Smith . -snes_fas_monitor - Monitor progress of all of the levels 907f6dfbefdSBarry Smith . -snes_fas_full_downsweep<`PETSC_FALSE`> - call the downsmooth on the initial downsweep of full FAS 908f6dfbefdSBarry Smith . -fas_levels_snes_ - `SNES` options for all smoothers 909f6dfbefdSBarry Smith . -fas_levels_cycle_snes_ - `SNES` options for all cycles 910f6dfbefdSBarry Smith . -fas_levels_i_snes_ - `SNES` options for the smoothers on level i 911f6dfbefdSBarry Smith . -fas_levels_i_cycle_snes_ - `SNES` options for the cycle on level i 912f6dfbefdSBarry Smith - -fas_coarse_snes_ - `SNES` options for the coarsest smoother 91340244768SBarry Smith 914*420bcc1bSBarry Smith Level: beginner 915*420bcc1bSBarry Smith 916f6dfbefdSBarry Smith Note: 917f6dfbefdSBarry Smith The organization of the FAS solver is slightly different from the organization of `PCMG` 918f6dfbefdSBarry Smith As each level has smoother `SNES` instances(down and potentially up) and a cycle `SNES` instance. 919f6dfbefdSBarry Smith The cycle `SNES` instance may be used for monitoring convergence on a particular level. 92040244768SBarry Smith 92140244768SBarry Smith References: 922606c0280SSatish Balay . * - Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers", 92340244768SBarry Smith SIAM Review, 57(4), 2015 92440244768SBarry Smith 925*420bcc1bSBarry Smith .seealso: [](ch_snes), `PCMG`, `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESType`, `SNESFASSetRestriction()`, `SNESFASSetInjection()`, 926*420bcc1bSBarry Smith `SNESFASFullGetTotal()`, `SNESFASSetType()`, `SNESFASGetType()`, `SNESFASSetLevels()`, `SNESFASGetLevels()`, `SNESFASGetCycleSNES()`, 927*420bcc1bSBarry Smith `SNESFASSetNumberSmoothUp()`, `SNESFASSetNumberSmoothDown()`, `SNESFASSetContinuation()`, `SNESFASSetCycles()`, `SNESFASSetMonitor()`, 928*420bcc1bSBarry Smith `SNESFASSetLog()`, `SNESFASCycleSetCycles()`, `SNESFASCycleGetSmoother()`, `SNESFASCycleGetSmootherUp()`, `SNESFASCycleGetSmootherDown()`, 929*420bcc1bSBarry Smith `SNESFASCycleGetCorrection()`, `SNESFASCycleGetInterpolation()`, `SNESFASCycleGetRestriction()`, `SNESFASCycleGetInjection()`, 930*420bcc1bSBarry Smith `SNESFASCycleGetRScale()`, `SNESFASCycleIsFine()`, `SNESFASSetInterpolation()`, `SNESFASGetInterpolation()`, `SNESFASSetRestriction()`, 931*420bcc1bSBarry Smith `SNESFASGetRestriction()`, `SNESFASSetInjection()`, `SNESFASGetInjection()`, `SNESFASSetRScale()`,`SNESFASGetSmoother()`, 932*420bcc1bSBarry Smith `SNESFASGetSmootherDown()`, `SNESFASGetSmootherUp()`, `SNESFASGetCoarseSolve()`, `SNESFASFullSetDownSweep()`, `SNESFASFullSetTotal()`, `SNESFASFullGetTotal()` 93340244768SBarry Smith M*/ 93440244768SBarry Smith 935d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode SNESCreate_FAS(SNES snes) 936d71ae5a4SJacob Faibussowitsch { 93740244768SBarry Smith SNES_FAS *fas; 93840244768SBarry Smith 93940244768SBarry Smith PetscFunctionBegin; 94040244768SBarry Smith snes->ops->destroy = SNESDestroy_FAS; 94140244768SBarry Smith snes->ops->setup = SNESSetUp_FAS; 94240244768SBarry Smith snes->ops->setfromoptions = SNESSetFromOptions_FAS; 94340244768SBarry Smith snes->ops->view = SNESView_FAS; 94440244768SBarry Smith snes->ops->solve = SNESSolve_FAS; 94540244768SBarry Smith snes->ops->reset = SNESReset_FAS; 94640244768SBarry Smith 94740244768SBarry Smith snes->usesksp = PETSC_FALSE; 948efd4aadfSBarry Smith snes->usesnpc = PETSC_FALSE; 94940244768SBarry Smith 95040244768SBarry Smith if (!snes->tolerancesset) { 95140244768SBarry Smith snes->max_funcs = 30000; 95240244768SBarry Smith snes->max_its = 10000; 95340244768SBarry Smith } 95440244768SBarry Smith 9554fc747eaSLawrence Mitchell snes->alwayscomputesfinalresidual = PETSC_TRUE; 9564fc747eaSLawrence Mitchell 9574dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&fas)); 95840244768SBarry Smith 95940244768SBarry Smith snes->data = (void *)fas; 96040244768SBarry Smith fas->level = 0; 96140244768SBarry Smith fas->levels = 1; 96240244768SBarry Smith fas->n_cycles = 1; 96340244768SBarry Smith fas->max_up_it = 1; 96440244768SBarry Smith fas->max_down_it = 1; 96540244768SBarry Smith fas->smoothu = NULL; 96640244768SBarry Smith fas->smoothd = NULL; 96740244768SBarry Smith fas->next = NULL; 96840244768SBarry Smith fas->previous = NULL; 96940244768SBarry Smith fas->fine = snes; 97040244768SBarry Smith fas->interpolate = NULL; 97140244768SBarry Smith fas->restrct = NULL; 97240244768SBarry Smith fas->inject = NULL; 97340244768SBarry Smith fas->usedmfornumberoflevels = PETSC_FALSE; 97440244768SBarry Smith fas->fastype = SNES_FAS_MULTIPLICATIVE; 97540244768SBarry Smith fas->full_downsweep = PETSC_FALSE; 9766dfbafefSToby Isaac fas->full_total = PETSC_FALSE; 97740244768SBarry Smith 97840244768SBarry Smith fas->eventsmoothsetup = 0; 97940244768SBarry Smith fas->eventsmoothsolve = 0; 98040244768SBarry Smith fas->eventresidual = 0; 98140244768SBarry Smith fas->eventinterprestrict = 0; 9823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 98340244768SBarry Smith } 984