xref: /petsc/src/ksp/pc/impls/mg/mg.c (revision 7c4f633dc6bb6149cca88d301ead35a99e103cbb)
1dba47a55SKris Buschelman #define PETSCKSP_DLL
2dba47a55SKris Buschelman 
34b9ad928SBarry Smith /*
44b9ad928SBarry Smith     Defines the multigrid preconditioner interface.
54b9ad928SBarry Smith */
6*7c4f633dSBarry Smith #include "../src/ksp/pc/impls/mg/mgimpl.h"                    /*I "petscmg.h" I*/
74b9ad928SBarry Smith 
84b9ad928SBarry Smith 
94b9ad928SBarry Smith #undef __FUNCT__
109dcbbd2bSBarry Smith #define __FUNCT__ "PCMGMCycle_Private"
114d0a8057SBarry Smith PetscErrorCode PCMGMCycle_Private(PC pc,PC_MG **mglevels,PCRichardsonConvergedReason *reason)
124b9ad928SBarry Smith {
139dcbbd2bSBarry Smith   PC_MG          *mg = *mglevels,*mgc;
146849ba73SBarry Smith   PetscErrorCode ierr;
150d353602SBarry Smith   PetscInt       cycles = (PetscInt) mg->cycles;
164b9ad928SBarry Smith 
174b9ad928SBarry Smith   PetscFunctionBegin;
184b9ad928SBarry Smith 
1932cf1786SBarry Smith   if (mg->eventsmoothsolve) {ierr = PetscLogEventBegin(mg->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
200d353602SBarry Smith   ierr = KSPSolve(mg->smoothd,mg->b,mg->x);CHKERRQ(ierr);  /* pre-smooth */
2132cf1786SBarry Smith   if (mg->eventsmoothsolve) {ierr = PetscLogEventEnd(mg->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
224b9ad928SBarry Smith   if (mg->level) {  /* not the coarsest grid */
2332cf1786SBarry Smith     if (mg->eventresidual) {ierr = PetscLogEventBegin(mg->eventresidual,0,0,0,0);CHKERRQ(ierr);}
244b9ad928SBarry Smith     ierr = (*mg->residual)(mg->A,mg->b,mg->x,mg->r);CHKERRQ(ierr);
2532cf1786SBarry Smith     if (mg->eventresidual) {ierr = PetscLogEventEnd(mg->eventresidual,0,0,0,0);CHKERRQ(ierr);}
264b9ad928SBarry Smith 
274b9ad928SBarry Smith     /* if on finest level and have convergence criteria set */
284d0a8057SBarry Smith     if (mg->level == mg->levels-1 && mg->ttol && reason) {
294b9ad928SBarry Smith       PetscReal rnorm;
304b9ad928SBarry Smith       ierr = VecNorm(mg->r,NORM_2,&rnorm);CHKERRQ(ierr);
314b9ad928SBarry Smith       if (rnorm <= mg->ttol) {
3270441072SBarry Smith         if (rnorm < mg->abstol) {
334d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_ATOL;
341e2582c4SBarry Smith           ierr = PetscInfo2(pc,"Linear solver has converged. Residual norm %G is less than absolute tolerance %G\n",rnorm,mg->abstol);CHKERRQ(ierr);
354b9ad928SBarry Smith         } else {
364d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_RTOL;
371e2582c4SBarry Smith           ierr = PetscInfo2(pc,"Linear solver has converged. Residual norm %G is less than relative tolerance times initial residual norm %G\n",rnorm,mg->ttol);CHKERRQ(ierr);
384b9ad928SBarry Smith         }
394b9ad928SBarry Smith         PetscFunctionReturn(0);
404b9ad928SBarry Smith       }
414b9ad928SBarry Smith     }
424b9ad928SBarry Smith 
434b9ad928SBarry Smith     mgc = *(mglevels - 1);
4432cf1786SBarry Smith     if (mg->eventinterprestrict) {ierr = PetscLogEventBegin(mg->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
454b9ad928SBarry Smith     ierr = MatRestrict(mg->restrct,mg->r,mgc->b);CHKERRQ(ierr);
4632cf1786SBarry Smith     if (mg->eventinterprestrict) {ierr = PetscLogEventEnd(mg->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
47efb30889SBarry Smith     ierr = VecSet(mgc->x,0.0);CHKERRQ(ierr);
484b9ad928SBarry Smith     while (cycles--) {
494d0a8057SBarry Smith       ierr = PCMGMCycle_Private(pc,mglevels-1,reason);CHKERRQ(ierr);
504b9ad928SBarry Smith     }
5132cf1786SBarry Smith     if (mg->eventinterprestrict) {ierr = PetscLogEventBegin(mg->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
524b9ad928SBarry Smith     ierr = MatInterpolateAdd(mg->interpolate,mgc->x,mg->x,mg->x);CHKERRQ(ierr);
5332cf1786SBarry Smith     if (mg->eventinterprestrict) {ierr = PetscLogEventEnd(mg->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
5432cf1786SBarry Smith     if (mg->eventsmoothsolve) {ierr = PetscLogEventBegin(mg->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
550d353602SBarry Smith     ierr = KSPSolve(mg->smoothu,mg->b,mg->x);CHKERRQ(ierr);    /* post smooth */
5632cf1786SBarry Smith     if (mg->eventsmoothsolve) {ierr = PetscLogEventEnd(mg->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
574b9ad928SBarry Smith   }
584b9ad928SBarry Smith   PetscFunctionReturn(0);
594b9ad928SBarry Smith }
604b9ad928SBarry Smith 
614b9ad928SBarry Smith /*
629dcbbd2bSBarry Smith        PCMGCreate_Private - Creates a PC_MG structure for use with the
634b9ad928SBarry Smith                multigrid code. Level 0 is the coarsest. (But the
644b9ad928SBarry Smith                finest level is stored first in the array).
654b9ad928SBarry Smith 
664b9ad928SBarry Smith */
674b9ad928SBarry Smith #undef __FUNCT__
689dcbbd2bSBarry Smith #define __FUNCT__ "PCMGCreate_Private"
699dcbbd2bSBarry Smith static PetscErrorCode PCMGCreate_Private(MPI_Comm comm,PetscInt levels,PC pc,MPI_Comm *comms,PC_MG ***result)
704b9ad928SBarry Smith {
719dcbbd2bSBarry Smith   PC_MG          **mg;
726849ba73SBarry Smith   PetscErrorCode ierr;
7379416396SBarry Smith   PetscInt       i;
7479416396SBarry Smith   PetscMPIInt    size;
75f69a0ea3SMatthew Knepley   const char     *prefix;
764b9ad928SBarry Smith   PC             ipc;
774b9ad928SBarry Smith 
784b9ad928SBarry Smith   PetscFunctionBegin;
799dcbbd2bSBarry Smith   ierr = PetscMalloc(levels*sizeof(PC_MG*),&mg);CHKERRQ(ierr);
8038f2d2fdSLisandro Dalcin   ierr = PetscLogObjectMemory(pc,levels*(sizeof(PC_MG*)));CHKERRQ(ierr);
814b9ad928SBarry Smith 
824b9ad928SBarry Smith   ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
834b9ad928SBarry Smith 
844b9ad928SBarry Smith   for (i=0; i<levels; i++) {
8538f2d2fdSLisandro Dalcin     ierr = PetscNewLog(pc,PC_MG,&mg[i]);CHKERRQ(ierr);
864b9ad928SBarry Smith     mg[i]->level           = i;
874b9ad928SBarry Smith     mg[i]->levels          = levels;
880d353602SBarry Smith     mg[i]->cycles          = PC_MG_CYCLE_V;
89c2be2410SBarry Smith     mg[i]->galerkin        = PETSC_FALSE;
90c2be2410SBarry Smith     mg[i]->galerkinused    = PETSC_FALSE;
9179416396SBarry Smith     mg[i]->default_smoothu = 1;
9279416396SBarry Smith     mg[i]->default_smoothd = 1;
934b9ad928SBarry Smith 
944b9ad928SBarry Smith     if (comms) comm = comms[i];
954b9ad928SBarry Smith     ierr = KSPCreate(comm,&mg[i]->smoothd);CHKERRQ(ierr);
961cee3971SBarry Smith     ierr = PetscObjectIncrementTabLevel((PetscObject)mg[i]->smoothd,(PetscObject)pc,levels-i);CHKERRQ(ierr);
9779416396SBarry Smith     ierr = KSPSetTolerances(mg[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, mg[i]->default_smoothd);CHKERRQ(ierr);
984b9ad928SBarry Smith     ierr = KSPSetOptionsPrefix(mg[i]->smoothd,prefix);CHKERRQ(ierr);
994b9ad928SBarry Smith 
1004b9ad928SBarry Smith     /* do special stuff for coarse grid */
1014b9ad928SBarry Smith     if (!i && levels > 1) {
1024b9ad928SBarry Smith       ierr = KSPAppendOptionsPrefix(mg[0]->smoothd,"mg_coarse_");CHKERRQ(ierr);
1034b9ad928SBarry Smith 
1044b9ad928SBarry Smith       /* coarse solve is (redundant) LU by default */
1054b9ad928SBarry Smith       ierr = KSPSetType(mg[0]->smoothd,KSPPREONLY);CHKERRQ(ierr);
1064b9ad928SBarry Smith       ierr = KSPGetPC(mg[0]->smoothd,&ipc);CHKERRQ(ierr);
1074b9ad928SBarry Smith       ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1084b9ad928SBarry Smith       if (size > 1) {
1094b9ad928SBarry Smith         ierr = PCSetType(ipc,PCREDUNDANT);CHKERRQ(ierr);
1100d7810c8SBarry Smith       } else {
1114b9ad928SBarry Smith         ierr = PCSetType(ipc,PCLU);CHKERRQ(ierr);
1120d7810c8SBarry Smith       }
1134b9ad928SBarry Smith 
1144b9ad928SBarry Smith     } else {
1152e70eadcSBarry Smith       char tprefix[128];
11613f74950SBarry Smith       sprintf(tprefix,"mg_levels_%d_",(int)i);
1172e70eadcSBarry Smith       ierr = KSPAppendOptionsPrefix(mg[i]->smoothd,tprefix);CHKERRQ(ierr);
1184b9ad928SBarry Smith     }
11952e6d16bSBarry Smith     ierr = PetscLogObjectParent(pc,mg[i]->smoothd);CHKERRQ(ierr);
1204b9ad928SBarry Smith     mg[i]->smoothu             = mg[i]->smoothd;
1214b9ad928SBarry Smith     mg[i]->rtol                = 0.0;
12270441072SBarry Smith     mg[i]->abstol              = 0.0;
1234b9ad928SBarry Smith     mg[i]->dtol                = 0.0;
1244b9ad928SBarry Smith     mg[i]->ttol                = 0.0;
12532cf1786SBarry Smith     mg[i]->eventsmoothsetup    = 0;
12632cf1786SBarry Smith     mg[i]->eventsmoothsolve    = 0;
12732cf1786SBarry Smith     mg[i]->eventresidual       = 0;
12832cf1786SBarry Smith     mg[i]->eventinterprestrict = 0;
1298cc2d5dfSBarry Smith     mg[i]->cyclesperpcapply    = 1;
1304b9ad928SBarry Smith   }
1314b9ad928SBarry Smith   *result = mg;
1324b9ad928SBarry Smith   PetscFunctionReturn(0);
1334b9ad928SBarry Smith }
1344b9ad928SBarry Smith 
1354b9ad928SBarry Smith #undef __FUNCT__
1364b9ad928SBarry Smith #define __FUNCT__ "PCDestroy_MG"
1376849ba73SBarry Smith static PetscErrorCode PCDestroy_MG(PC pc)
1384b9ad928SBarry Smith {
1399dcbbd2bSBarry Smith   PC_MG          **mg = (PC_MG**)pc->data;
1406849ba73SBarry Smith   PetscErrorCode ierr;
14138f2d2fdSLisandro Dalcin   PetscInt       i,n;
1424b9ad928SBarry Smith 
1434b9ad928SBarry Smith   PetscFunctionBegin;
14438f2d2fdSLisandro Dalcin   if (!mg) PetscFunctionReturn(0);
14538f2d2fdSLisandro Dalcin   n = mg[0]->levels;
146fccaa45eSBarry Smith   for (i=0; i<n-1; i++) {
147630ba2eeSBarry Smith     if (mg[i+1]->r) {ierr = VecDestroy(mg[i+1]->r);CHKERRQ(ierr);}
148fccaa45eSBarry Smith     if (mg[i]->b) {ierr = VecDestroy(mg[i]->b);CHKERRQ(ierr);}
149fccaa45eSBarry Smith     if (mg[i]->x) {ierr = VecDestroy(mg[i]->x);CHKERRQ(ierr);}
150fccaa45eSBarry Smith     if (mg[i+1]->restrct) {ierr = MatDestroy(mg[i+1]->restrct);CHKERRQ(ierr);}
151fccaa45eSBarry Smith     if (mg[i+1]->interpolate) {ierr = MatDestroy(mg[i+1]->interpolate);CHKERRQ(ierr);}
152fccaa45eSBarry Smith   }
153fccaa45eSBarry Smith 
1544b9ad928SBarry Smith   for (i=0; i<n; i++) {
1554b9ad928SBarry Smith     if (mg[i]->smoothd != mg[i]->smoothu) {
1564b9ad928SBarry Smith       ierr = KSPDestroy(mg[i]->smoothd);CHKERRQ(ierr);
1574b9ad928SBarry Smith     }
1584b9ad928SBarry Smith     ierr = KSPDestroy(mg[i]->smoothu);CHKERRQ(ierr);
1594b9ad928SBarry Smith     ierr = PetscFree(mg[i]);CHKERRQ(ierr);
1604b9ad928SBarry Smith   }
1614b9ad928SBarry Smith   ierr = PetscFree(mg);CHKERRQ(ierr);
1624b9ad928SBarry Smith   PetscFunctionReturn(0);
1634b9ad928SBarry Smith }
1644b9ad928SBarry Smith 
1654b9ad928SBarry Smith 
1664b9ad928SBarry Smith 
1679dcbbd2bSBarry Smith EXTERN PetscErrorCode PCMGACycle_Private(PC_MG**);
1681e2582c4SBarry Smith EXTERN PetscErrorCode PCMGFCycle_Private(PC,PC_MG**);
1699dcbbd2bSBarry Smith EXTERN PetscErrorCode PCMGKCycle_Private(PC_MG**);
1704b9ad928SBarry Smith 
1714b9ad928SBarry Smith /*
1724b9ad928SBarry Smith    PCApply_MG - Runs either an additive, multiplicative, Kaskadic
1734b9ad928SBarry Smith              or full cycle of multigrid.
1744b9ad928SBarry Smith 
1754b9ad928SBarry Smith   Note:
1769dcbbd2bSBarry Smith   A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
1774b9ad928SBarry Smith */
1784b9ad928SBarry Smith #undef __FUNCT__
1794b9ad928SBarry Smith #define __FUNCT__ "PCApply_MG"
1806849ba73SBarry Smith static PetscErrorCode PCApply_MG(PC pc,Vec b,Vec x)
1814b9ad928SBarry Smith {
1829dcbbd2bSBarry Smith   PC_MG          **mg = (PC_MG**)pc->data;
1836849ba73SBarry Smith   PetscErrorCode ierr;
1848cc2d5dfSBarry Smith   PetscInt       levels = mg[0]->levels,i;
1854b9ad928SBarry Smith 
1864b9ad928SBarry Smith   PetscFunctionBegin;
1874b9ad928SBarry Smith   mg[levels-1]->b = b;
1884b9ad928SBarry Smith   mg[levels-1]->x = x;
1899dcbbd2bSBarry Smith   if (mg[0]->am == PC_MG_MULTIPLICATIVE) {
190efb30889SBarry Smith     ierr = VecSet(x,0.0);CHKERRQ(ierr);
1918cc2d5dfSBarry Smith     for (i=0; i<mg[0]->cyclesperpcapply; i++) {
1921e2582c4SBarry Smith       ierr = PCMGMCycle_Private(pc,mg+levels-1,PETSC_NULL);CHKERRQ(ierr);
1934b9ad928SBarry Smith     }
1948cc2d5dfSBarry Smith   }
1959dcbbd2bSBarry Smith   else if (mg[0]->am == PC_MG_ADDITIVE) {
1969dcbbd2bSBarry Smith     ierr = PCMGACycle_Private(mg);CHKERRQ(ierr);
1974b9ad928SBarry Smith   }
1989dcbbd2bSBarry Smith   else if (mg[0]->am == PC_MG_KASKADE) {
1999dcbbd2bSBarry Smith     ierr = PCMGKCycle_Private(mg);CHKERRQ(ierr);
2004b9ad928SBarry Smith   }
2014b9ad928SBarry Smith   else {
2021e2582c4SBarry Smith     ierr = PCMGFCycle_Private(pc,mg);CHKERRQ(ierr);
2034b9ad928SBarry Smith   }
2044b9ad928SBarry Smith   PetscFunctionReturn(0);
2054b9ad928SBarry Smith }
2064b9ad928SBarry Smith 
2074b9ad928SBarry Smith #undef __FUNCT__
2084b9ad928SBarry Smith #define __FUNCT__ "PCApplyRichardson_MG"
2094d0a8057SBarry Smith static PetscErrorCode PCApplyRichardson_MG(PC pc,Vec b,Vec x,Vec w,PetscReal rtol,PetscReal abstol, PetscReal dtol,PetscInt its,PetscInt *outits,PCRichardsonConvergedReason *reason)
2104b9ad928SBarry Smith {
2119dcbbd2bSBarry Smith   PC_MG          **mg = (PC_MG**)pc->data;
212dfbe8321SBarry Smith   PetscErrorCode ierr;
2134d0a8057SBarry Smith   PetscInt       levels = mg[0]->levels,i;
2144b9ad928SBarry Smith 
2154b9ad928SBarry Smith   PetscFunctionBegin;
2164b9ad928SBarry Smith   mg[levels-1]->b    = b;
2174b9ad928SBarry Smith   mg[levels-1]->x    = x;
2184b9ad928SBarry Smith 
2194b9ad928SBarry Smith   mg[levels-1]->rtol = rtol;
22070441072SBarry Smith   mg[levels-1]->abstol = abstol;
2214b9ad928SBarry Smith   mg[levels-1]->dtol = dtol;
2224b9ad928SBarry Smith   if (rtol) {
2234b9ad928SBarry Smith     /* compute initial residual norm for relative convergence test */
2244b9ad928SBarry Smith     PetscReal rnorm;
2254b9ad928SBarry Smith     ierr               = (*mg[levels-1]->residual)(mg[levels-1]->A,b,x,w);CHKERRQ(ierr);
2264b9ad928SBarry Smith     ierr               = VecNorm(w,NORM_2,&rnorm);CHKERRQ(ierr);
22770441072SBarry Smith     mg[levels-1]->ttol = PetscMax(rtol*rnorm,abstol);
22870441072SBarry Smith   } else if (abstol) {
22970441072SBarry Smith     mg[levels-1]->ttol = abstol;
2304b9ad928SBarry Smith   } else {
2314b9ad928SBarry Smith     mg[levels-1]->ttol = 0.0;
2324b9ad928SBarry Smith   }
2334b9ad928SBarry Smith 
2344d0a8057SBarry Smith   /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't
2354d0a8057SBarry Smith      stop prematurely do to small residual */
2364d0a8057SBarry Smith   for (i=1; i<levels; i++) {
2374d0a8057SBarry Smith     ierr = KSPSetTolerances(mg[i]->smoothu,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
2384d0a8057SBarry Smith     if (mg[i]->smoothu != mg[i]->smoothd) {
2394d0a8057SBarry Smith       ierr = KSPSetTolerances(mg[i]->smoothd,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
2404b9ad928SBarry Smith     }
2414d0a8057SBarry Smith   }
2424d0a8057SBarry Smith 
2434d0a8057SBarry Smith   *reason = (PCRichardsonConvergedReason)0;
2444d0a8057SBarry Smith   for (i=0; i<its; i++) {
2454d0a8057SBarry Smith     ierr = PCMGMCycle_Private(pc,mg+levels-1,reason);CHKERRQ(ierr);
2464d0a8057SBarry Smith     if (*reason) break;
2474d0a8057SBarry Smith   }
2484d0a8057SBarry Smith   if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS;
2494d0a8057SBarry Smith   *outits = i;
2504b9ad928SBarry Smith   PetscFunctionReturn(0);
2514b9ad928SBarry Smith }
2524b9ad928SBarry Smith 
2534b9ad928SBarry Smith #undef __FUNCT__
2544b9ad928SBarry Smith #define __FUNCT__ "PCSetFromOptions_MG"
2556ca4d86aSHong Zhang PetscErrorCode PCSetFromOptions_MG(PC pc)
2564b9ad928SBarry Smith {
257dfbe8321SBarry Smith   PetscErrorCode ierr;
2588cc2d5dfSBarry Smith   PetscInt       m,levels = 1,cycles;
2594b9ad928SBarry Smith   PetscTruth     flg;
2609dcbbd2bSBarry Smith   PC_MG          **mg = (PC_MG**)pc->data;
26190da95b0SMatthew Knepley   PCMGType       mgtype = PC_MG_ADDITIVE;
2621aa34eeaSBarry Smith   PCMGCycleType  mgctype;
2634b9ad928SBarry Smith 
2644b9ad928SBarry Smith   PetscFunctionBegin;
2654b9ad928SBarry Smith   ierr = PetscOptionsHead("Multigrid options");CHKERRQ(ierr);
2664b9ad928SBarry Smith     if (!pc->data) {
2679dcbbd2bSBarry Smith       ierr = PetscOptionsInt("-pc_mg_levels","Number of Levels","PCMGSetLevels",levels,&levels,&flg);CHKERRQ(ierr);
26897177400SBarry Smith       ierr = PCMGSetLevels(pc,levels,PETSC_NULL);CHKERRQ(ierr);
269cf502942SBarry Smith       mg = (PC_MG**)pc->data;
2704b9ad928SBarry Smith     }
271f2070a76SMatthew Knepley     mgctype = (PCMGCycleType) mg[0]->cycles;
2720d353602SBarry Smith     ierr = PetscOptionsEnum("-pc_mg_cycle_type","V cycle or for W-cycle","PCMGSetCycleType",PCMGCycleTypes,(PetscEnum)mgctype,(PetscEnum*)&mgctype,&flg);CHKERRQ(ierr);
2734b9ad928SBarry Smith     if (flg) {
2740d353602SBarry Smith       ierr = PCMGSetCycleType(pc,mgctype);CHKERRQ(ierr);
2750d353602SBarry Smith     };
2769dcbbd2bSBarry Smith     ierr = PetscOptionsName("-pc_mg_galerkin","Use Galerkin process to compute coarser operators","PCMGSetGalerkin",&flg);CHKERRQ(ierr);
277c2be2410SBarry Smith     if (flg) {
27897177400SBarry Smith       ierr = PCMGSetGalerkin(pc);CHKERRQ(ierr);
279c2be2410SBarry Smith     }
2809dcbbd2bSBarry Smith     ierr = PetscOptionsInt("-pc_mg_smoothup","Number of post-smoothing steps","PCMGSetNumberSmoothUp",1,&m,&flg);CHKERRQ(ierr);
2814b9ad928SBarry Smith     if (flg) {
28297177400SBarry Smith       ierr = PCMGSetNumberSmoothUp(pc,m);CHKERRQ(ierr);
2834b9ad928SBarry Smith     }
2849dcbbd2bSBarry Smith     ierr = PetscOptionsInt("-pc_mg_smoothdown","Number of pre-smoothing steps","PCMGSetNumberSmoothDown",1,&m,&flg);CHKERRQ(ierr);
2854b9ad928SBarry Smith     if (flg) {
28697177400SBarry Smith       ierr = PCMGSetNumberSmoothDown(pc,m);CHKERRQ(ierr);
2874b9ad928SBarry Smith     }
2889dcbbd2bSBarry Smith     ierr = PetscOptionsEnum("-pc_mg_type","Multigrid type","PCMGSetType",PCMGTypes,(PetscEnum)mgtype,(PetscEnum*)&mgtype,&flg);CHKERRQ(ierr);
2898cc2d5dfSBarry Smith     if (flg) {
2908cc2d5dfSBarry Smith       ierr = PCMGSetType(pc,mgtype);CHKERRQ(ierr);
2918cc2d5dfSBarry Smith     }
2928cc2d5dfSBarry Smith     if (mg[0]->am == PC_MG_MULTIPLICATIVE) {
2938cc2d5dfSBarry Smith       ierr = PetscOptionsInt("-pc_mg_multiplicative_cycles","Number of cycles for each preconditioner step","PCMGSetLevels",mg[0]->cyclesperpcapply,&cycles,&flg);CHKERRQ(ierr);
2948cc2d5dfSBarry Smith       if (flg) {
2958cc2d5dfSBarry Smith 	ierr = PCMGMultiplicativeSetCycles(pc,cycles);CHKERRQ(ierr);
2968cc2d5dfSBarry Smith       }
2978cc2d5dfSBarry Smith     }
2984b9ad928SBarry Smith     ierr = PetscOptionsName("-pc_mg_log","Log times for each multigrid level","None",&flg);CHKERRQ(ierr);
2994b9ad928SBarry Smith     if (flg) {
3004f5ab15aSBarry Smith       PetscInt i;
3014b9ad928SBarry Smith       char     eventname[128];
3024b9ad928SBarry Smith       if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
3034b9ad928SBarry Smith       levels = mg[0]->levels;
3044b9ad928SBarry Smith       for (i=0; i<levels; i++) {
30532cf1786SBarry Smith         sprintf(eventname,"MGSetup Level %d",(int)i);
3068cbcd9ccSBarry Smith         ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->cookie,&mg[i]->eventsmoothsetup);CHKERRQ(ierr);
30732cf1786SBarry Smith         sprintf(eventname,"MGSmooth Level %d",(int)i);
3088cbcd9ccSBarry Smith         ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->cookie,&mg[i]->eventsmoothsolve);CHKERRQ(ierr);
30932cf1786SBarry Smith         if (i) {
31032cf1786SBarry Smith           sprintf(eventname,"MGResid Level %d",(int)i);
311a3bc4eb9SBarry Smith           ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->cookie,&mg[i]->eventresidual);CHKERRQ(ierr);
31232cf1786SBarry Smith           sprintf(eventname,"MGInterp Level %d",(int)i);
3138cbcd9ccSBarry Smith           ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->cookie,&mg[i]->eventinterprestrict);CHKERRQ(ierr);
31432cf1786SBarry Smith         }
3154b9ad928SBarry Smith       }
3164b9ad928SBarry Smith     }
3174b9ad928SBarry Smith   ierr = PetscOptionsTail();CHKERRQ(ierr);
3184b9ad928SBarry Smith   PetscFunctionReturn(0);
3194b9ad928SBarry Smith }
3204b9ad928SBarry Smith 
3219dcbbd2bSBarry Smith const char *PCMGTypes[] = {"MULTIPLICATIVE","ADDITIVE","FULL","KASKADE","PCMGType","PC_MG",0};
3220d353602SBarry Smith const char *PCMGCycleTypes[] = {"invalid","v","w","PCMGCycleType","PC_MG_CYCLE",0};
3239dcbbd2bSBarry Smith 
3244b9ad928SBarry Smith #undef __FUNCT__
3254b9ad928SBarry Smith #define __FUNCT__ "PCView_MG"
3266849ba73SBarry Smith static PetscErrorCode PCView_MG(PC pc,PetscViewer viewer)
3274b9ad928SBarry Smith {
3289dcbbd2bSBarry Smith   PC_MG          **mg = (PC_MG**)pc->data;
329dfbe8321SBarry Smith   PetscErrorCode ierr;
33079416396SBarry Smith   PetscInt       levels = mg[0]->levels,i;
33132077d6dSBarry Smith   PetscTruth     iascii;
3324b9ad928SBarry Smith 
3334b9ad928SBarry Smith   PetscFunctionBegin;
33432077d6dSBarry Smith   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
33532077d6dSBarry Smith   if (iascii) {
336a8e6722dSMatthew Knepley     ierr = PetscViewerASCIIPrintf(viewer,"  MG: type is %s, levels=%D cycles=%s\n", PCMGTypes[mg[0]->am],levels,(mg[0]->cycles == PC_MG_CYCLE_V) ? "v" : "w");CHKERRQ(ierr);
337d792f543SMatthew Knepley     if (mg[0]->am == PC_MG_MULTIPLICATIVE) {
338d792f543SMatthew Knepley       ierr = PetscViewerASCIIPrintf(viewer,"    Cycles per PCApply=%d\n",mg[0]->cyclesperpcapply);CHKERRQ(ierr);
339d792f543SMatthew Knepley     }
340c2be2410SBarry Smith     if (mg[0]->galerkin) {
341c2be2410SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid matrices\n");CHKERRQ(ierr);
342c2be2410SBarry Smith     }
3434b9ad928SBarry Smith     for (i=0; i<levels; i++) {
344b03c7568SBarry Smith       if (!i) {
345a8e6722dSMatthew Knepley         ierr = PetscViewerASCIIPrintf(viewer,"Coarse gride solver -- level %D presmooths=%D postsmooths=%D -----\n",i,mg[0]->default_smoothd,mg[0]->default_smoothu);CHKERRQ(ierr);
346b03c7568SBarry Smith       } else {
347a8e6722dSMatthew Knepley         ierr = PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D smooths=%D --------------------\n",i,mg[i]->default_smoothd);CHKERRQ(ierr);
348b03c7568SBarry Smith       }
3494b9ad928SBarry Smith       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
3504b9ad928SBarry Smith       ierr = KSPView(mg[i]->smoothd,viewer);CHKERRQ(ierr);
3514b9ad928SBarry Smith       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
352b03c7568SBarry Smith       if (i && mg[i]->smoothd == mg[i]->smoothu) {
3534b9ad928SBarry Smith         ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n");CHKERRQ(ierr);
354b03c7568SBarry Smith       } else if (i){
355a8e6722dSMatthew Knepley         ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D smooths=%D --------------------\n",i,mg[i]->default_smoothu);CHKERRQ(ierr);
3564b9ad928SBarry Smith         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
3574b9ad928SBarry Smith         ierr = KSPView(mg[i]->smoothu,viewer);CHKERRQ(ierr);
3584b9ad928SBarry Smith         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
3594b9ad928SBarry Smith       }
3604b9ad928SBarry Smith     }
3614b9ad928SBarry Smith   } else {
36279a5c55eSBarry Smith     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCMG",((PetscObject)viewer)->type_name);
3634b9ad928SBarry Smith   }
3644b9ad928SBarry Smith   PetscFunctionReturn(0);
3654b9ad928SBarry Smith }
3664b9ad928SBarry Smith 
3674b9ad928SBarry Smith /*
3684b9ad928SBarry Smith     Calls setup for the KSP on each level
3694b9ad928SBarry Smith */
3704b9ad928SBarry Smith #undef __FUNCT__
3714b9ad928SBarry Smith #define __FUNCT__ "PCSetUp_MG"
3726849ba73SBarry Smith static PetscErrorCode PCSetUp_MG(PC pc)
3734b9ad928SBarry Smith {
3749dcbbd2bSBarry Smith   PC_MG                   **mg = (PC_MG**)pc->data;
375dfbe8321SBarry Smith   PetscErrorCode          ierr;
37679416396SBarry Smith   PetscInt                i,n = mg[0]->levels;
37777122347SBarry Smith   PC                      cpc,mpc;
378906ed7ccSBarry Smith   PetscTruth              preonly,lu,redundant,cholesky,monitor = PETSC_FALSE,dump,opsset;
37923d894e5SBarry Smith   PetscViewerASCIIMonitor ascii;
38023d894e5SBarry Smith   PetscViewer             viewer = PETSC_NULL;
3814b9ad928SBarry Smith   MPI_Comm                comm;
382c2be2410SBarry Smith   Mat                     dA,dB;
383c2be2410SBarry Smith   MatStructure            uflag;
3840a6bb862SBarry Smith   Vec                     tvec;
3854b9ad928SBarry Smith 
3864b9ad928SBarry Smith   PetscFunctionBegin;
387852665d3SBarry Smith 
38843fb2f97SBarry Smith   /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
38943fb2f97SBarry Smith   /* so use those from global PC */
39043fb2f97SBarry Smith   /* Is this what we always want? What if user wants to keep old one? */
391906ed7ccSBarry Smith   ierr = KSPGetOperatorsSet(mg[n-1]->smoothd,PETSC_NULL,&opsset);CHKERRQ(ierr);
39243fb2f97SBarry Smith   ierr = KSPGetPC(mg[0]->smoothd,&cpc);CHKERRQ(ierr);
39377122347SBarry Smith   ierr = KSPGetPC(mg[n-1]->smoothd,&mpc);CHKERRQ(ierr);
39477122347SBarry Smith   if (!opsset || ((cpc->setupcalled == 1) && (mpc->setupcalled == 2))) {
395852665d3SBarry Smith     ierr = PetscInfo(pc,"Using outer operators to define finest grid operator \n  because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n");CHKERRQ(ierr);
3961cfe3bddSBarry Smith     ierr = KSPSetOperators(mg[n-1]->smoothd,pc->mat,pc->pmat,pc->flag);CHKERRQ(ierr);
397852665d3SBarry Smith   }
398852665d3SBarry Smith 
399852665d3SBarry Smith   if (mg[0]->galerkin) {
400852665d3SBarry Smith     Mat B;
401852665d3SBarry Smith     mg[0]->galerkinused = PETSC_TRUE;
402852665d3SBarry Smith     /* currently only handle case where mat and pmat are the same on coarser levels */
403852665d3SBarry Smith     ierr = KSPGetOperators(mg[n-1]->smoothd,&dA,&dB,&uflag);CHKERRQ(ierr);
404852665d3SBarry Smith     if (!pc->setupcalled) {
405852665d3SBarry Smith       for (i=n-2; i>-1; i--) {
406852665d3SBarry Smith         ierr = MatPtAP(dB,mg[i+1]->interpolate,MAT_INITIAL_MATRIX,1.0,&B);CHKERRQ(ierr);
407852665d3SBarry Smith         ierr = KSPSetOperators(mg[i]->smoothd,B,B,uflag);CHKERRQ(ierr);
408906ed7ccSBarry Smith 	if (i != n-2) {ierr = PetscObjectDereference((PetscObject)dB);CHKERRQ(ierr);}
409852665d3SBarry Smith         dB   = B;
410852665d3SBarry Smith       }
411906ed7ccSBarry Smith       ierr = PetscObjectDereference((PetscObject)dB);CHKERRQ(ierr);
412852665d3SBarry Smith     } else {
413852665d3SBarry Smith       for (i=n-2; i>-1; i--) {
414906ed7ccSBarry Smith         ierr = KSPGetOperators(mg[i]->smoothd,PETSC_NULL,&B,PETSC_NULL);CHKERRQ(ierr);
415852665d3SBarry Smith         ierr = MatPtAP(dB,mg[i+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);CHKERRQ(ierr);
416852665d3SBarry Smith         ierr = KSPSetOperators(mg[i]->smoothd,B,B,uflag);CHKERRQ(ierr);
417852665d3SBarry Smith         dB   = B;
418852665d3SBarry Smith       }
419852665d3SBarry Smith     }
420852665d3SBarry Smith   }
421852665d3SBarry Smith 
422958c9bccSBarry Smith   if (!pc->setupcalled) {
4234b9ad928SBarry Smith     ierr = PetscOptionsHasName(0,"-pc_mg_monitor",&monitor);CHKERRQ(ierr);
4244b9ad928SBarry Smith 
425b03c7568SBarry Smith     for (i=0; i<n; i++) {
4264b9ad928SBarry Smith       if (monitor) {
4274b9ad928SBarry Smith         ierr = PetscObjectGetComm((PetscObject)mg[i]->smoothd,&comm);CHKERRQ(ierr);
42823d894e5SBarry Smith         ierr = PetscViewerASCIIMonitorCreate(comm,"stdout",n-i,&ascii);CHKERRQ(ierr);
42923d894e5SBarry Smith         ierr = KSPMonitorSet(mg[i]->smoothd,KSPMonitorDefault,ascii,(PetscErrorCode(*)(void*))PetscViewerASCIIMonitorDestroy);CHKERRQ(ierr);
4304b9ad928SBarry Smith       }
4314b9ad928SBarry Smith       ierr = KSPSetFromOptions(mg[i]->smoothd);CHKERRQ(ierr);
4324b9ad928SBarry Smith     }
433b03c7568SBarry Smith     for (i=1; i<n; i++) {
434a98fc643SBarry Smith       if (mg[i]->smoothu && (mg[i]->smoothu != mg[i]->smoothd)) {
4354b9ad928SBarry Smith         if (monitor) {
4364b9ad928SBarry Smith           ierr = PetscObjectGetComm((PetscObject)mg[i]->smoothu,&comm);CHKERRQ(ierr);
43723d894e5SBarry Smith           ierr = PetscViewerASCIIMonitorCreate(comm,"stdout",n-i,&ascii);CHKERRQ(ierr);
43823d894e5SBarry Smith           ierr = KSPMonitorSet(mg[i]->smoothu,KSPMonitorDefault,ascii,(PetscErrorCode(*)(void*))PetscViewerASCIIMonitorDestroy);CHKERRQ(ierr);
4394b9ad928SBarry Smith         }
4404b9ad928SBarry Smith         ierr = KSPSetFromOptions(mg[i]->smoothu);CHKERRQ(ierr);
4414b9ad928SBarry Smith       }
4424b9ad928SBarry Smith     }
443fccaa45eSBarry Smith     for (i=1; i<n; i++) {
4440cace4b0SBarry Smith       if (!mg[i]->residual) {
4450cace4b0SBarry Smith         Mat mat;
4460cace4b0SBarry Smith         ierr = KSPGetOperators(mg[i]->smoothd,PETSC_NULL,&mat,PETSC_NULL);CHKERRQ(ierr);
4470cace4b0SBarry Smith         ierr = PCMGSetResidual(pc,i,PCMGDefaultResidual,mat);CHKERRQ(ierr);
4480cace4b0SBarry Smith       }
449fccaa45eSBarry Smith       if (mg[i]->restrct && !mg[i]->interpolate) {
450aea2a34eSBarry Smith         ierr = PCMGSetInterpolation(pc,i,mg[i]->restrct);CHKERRQ(ierr);
451fccaa45eSBarry Smith       }
452fccaa45eSBarry Smith       if (!mg[i]->restrct && mg[i]->interpolate) {
45397177400SBarry Smith         ierr = PCMGSetRestriction(pc,i,mg[i]->interpolate);CHKERRQ(ierr);
454fccaa45eSBarry Smith       }
455fccaa45eSBarry Smith #if defined(PETSC_USE_DEBUG)
456fccaa45eSBarry Smith       if (!mg[i]->restrct || !mg[i]->interpolate) {
457fccaa45eSBarry Smith         SETERRQ1(PETSC_ERR_ARG_WRONGSTATE,"Need to set restriction or interpolation on level %d",(int)i);
458fccaa45eSBarry Smith       }
459fccaa45eSBarry Smith #endif
460fccaa45eSBarry Smith     }
4610a6bb862SBarry Smith     for (i=0; i<n-1; i++) {
46237b0e6c0SBarry Smith       if (!mg[i]->b) {
463906ed7ccSBarry Smith         Vec *vec;
464906ed7ccSBarry Smith         ierr = KSPGetVecs(mg[i]->smoothd,1,&vec,0,PETSC_NULL);CHKERRQ(ierr);
465906ed7ccSBarry Smith         ierr = PCMGSetRhs(pc,i,*vec);CHKERRQ(ierr);
4664fdc791cSSatish Balay         ierr = VecDestroy(*vec);CHKERRQ(ierr);
467906ed7ccSBarry Smith         ierr = PetscFree(vec);CHKERRQ(ierr);
46837b0e6c0SBarry Smith       }
4696ca4d86aSHong Zhang       if (!mg[i]->r && i) {
4700a6bb862SBarry Smith         ierr = VecDuplicate(mg[i]->b,&tvec);CHKERRQ(ierr);
47197177400SBarry Smith         ierr = PCMGSetR(pc,i,tvec);CHKERRQ(ierr);
4720a6bb862SBarry Smith         ierr = VecDestroy(tvec);CHKERRQ(ierr);
4730a6bb862SBarry Smith       }
4740a6bb862SBarry Smith       if (!mg[i]->x) {
4750a6bb862SBarry Smith         ierr = VecDuplicate(mg[i]->b,&tvec);CHKERRQ(ierr);
47697177400SBarry Smith         ierr = PCMGSetX(pc,i,tvec);CHKERRQ(ierr);
4770a6bb862SBarry Smith         ierr = VecDestroy(tvec);CHKERRQ(ierr);
4780a6bb862SBarry Smith       }
4790a6bb862SBarry Smith     }
480dfef70bdSHong Zhang     if (n != 1 && !mg[n-1]->r) {
481dfef70bdSHong Zhang       /* PCMGSetR() on the finest level if user did not supply it */
4820f77fa87SBarry Smith       Vec *vec;
4830f77fa87SBarry Smith       ierr = KSPGetVecs(mg[n-1]->smoothd,1,&vec,0,PETSC_NULL);CHKERRQ(ierr);
4840f77fa87SBarry Smith       ierr = PCMGSetR(pc,n-1,*vec);CHKERRQ(ierr);
485797d2ccbSBarry Smith       ierr = VecDestroy(*vec);CHKERRQ(ierr);
4860f77fa87SBarry Smith       ierr = PetscFree(vec);CHKERRQ(ierr);
4870f77fa87SBarry Smith     }
4884b9ad928SBarry Smith   }
4894b9ad928SBarry Smith 
490c2be2410SBarry Smith 
4914b9ad928SBarry Smith   for (i=1; i<n; i++) {
492b03c7568SBarry Smith     if (mg[i]->smoothu == mg[i]->smoothd) {
493b03c7568SBarry Smith       /* if doing only down then initial guess is zero */
4944b9ad928SBarry Smith       ierr = KSPSetInitialGuessNonzero(mg[i]->smoothd,PETSC_TRUE);CHKERRQ(ierr);
495b03c7568SBarry Smith     }
49632cf1786SBarry Smith     if (mg[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mg[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
4974b9ad928SBarry Smith     ierr = KSPSetUp(mg[i]->smoothd);CHKERRQ(ierr);
49832cf1786SBarry Smith     if (mg[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mg[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
4994b9ad928SBarry Smith   }
500b03c7568SBarry Smith   for (i=1; i<n; i++) {
5014b9ad928SBarry Smith     if (mg[i]->smoothu && mg[i]->smoothu != mg[i]->smoothd) {
502906ed7ccSBarry Smith       Mat          downmat,downpmat;
50397f1f81fSBarry Smith       MatStructure matflag;
504906ed7ccSBarry Smith       PetscTruth   opsset;
50597f1f81fSBarry Smith 
50697f1f81fSBarry Smith       /* check if operators have been set for up, if not use down operators to set them */
507906ed7ccSBarry Smith       ierr = KSPGetOperatorsSet(mg[i]->smoothu,&opsset,PETSC_NULL);CHKERRQ(ierr);
508906ed7ccSBarry Smith       if (!opsset) {
509906ed7ccSBarry Smith         ierr = KSPGetOperators(mg[i]->smoothd,&downmat,&downpmat,&matflag);CHKERRQ(ierr);
51097f1f81fSBarry Smith         ierr = KSPSetOperators(mg[i]->smoothu,downmat,downpmat,matflag);CHKERRQ(ierr);
51197f1f81fSBarry Smith       }
51297f1f81fSBarry Smith 
5134b9ad928SBarry Smith       ierr = KSPSetInitialGuessNonzero(mg[i]->smoothu,PETSC_TRUE);CHKERRQ(ierr);
51432cf1786SBarry Smith       if (mg[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mg[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
5154b9ad928SBarry Smith       ierr = KSPSetUp(mg[i]->smoothu);CHKERRQ(ierr);
51632cf1786SBarry Smith       if (mg[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mg[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
5174b9ad928SBarry Smith     }
5184b9ad928SBarry Smith   }
5194b9ad928SBarry Smith 
5204b9ad928SBarry Smith   /*
5214b9ad928SBarry Smith       If coarse solver is not direct method then DO NOT USE preonly
5224b9ad928SBarry Smith   */
5234b9ad928SBarry Smith   ierr = PetscTypeCompare((PetscObject)mg[0]->smoothd,KSPPREONLY,&preonly);CHKERRQ(ierr);
5244b9ad928SBarry Smith   if (preonly) {
5254b9ad928SBarry Smith     ierr = PetscTypeCompare((PetscObject)cpc,PCLU,&lu);CHKERRQ(ierr);
5264b9ad928SBarry Smith     ierr = PetscTypeCompare((PetscObject)cpc,PCREDUNDANT,&redundant);CHKERRQ(ierr);
52768eff7e6SBarry Smith     ierr = PetscTypeCompare((PetscObject)cpc,PCCHOLESKY,&cholesky);CHKERRQ(ierr);
52868eff7e6SBarry Smith     if (!lu && !redundant && !cholesky) {
5294b9ad928SBarry Smith       ierr = KSPSetType(mg[0]->smoothd,KSPGMRES);CHKERRQ(ierr);
5304b9ad928SBarry Smith     }
5314b9ad928SBarry Smith   }
5324b9ad928SBarry Smith 
533958c9bccSBarry Smith   if (!pc->setupcalled) {
5344b9ad928SBarry Smith     if (monitor) {
5354b9ad928SBarry Smith       ierr = PetscObjectGetComm((PetscObject)mg[0]->smoothd,&comm);CHKERRQ(ierr);
53623d894e5SBarry Smith       ierr = PetscViewerASCIIMonitorCreate(comm,"stdout",n,&ascii);CHKERRQ(ierr);
53723d894e5SBarry Smith       ierr = KSPMonitorSet(mg[0]->smoothd,KSPMonitorDefault,ascii,(PetscErrorCode(*)(void*))PetscViewerASCIIMonitorDestroy);CHKERRQ(ierr);
5384b9ad928SBarry Smith     }
5394b9ad928SBarry Smith     ierr = KSPSetFromOptions(mg[0]->smoothd);CHKERRQ(ierr);
5404b9ad928SBarry Smith   }
5414b9ad928SBarry Smith 
54232cf1786SBarry Smith   if (mg[0]->eventsmoothsetup) {ierr = PetscLogEventBegin(mg[0]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
5434b9ad928SBarry Smith   ierr = KSPSetUp(mg[0]->smoothd);CHKERRQ(ierr);
54432cf1786SBarry Smith   if (mg[0]->eventsmoothsetup) {ierr = PetscLogEventEnd(mg[0]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
5454b9ad928SBarry Smith 
5464b9ad928SBarry Smith   /*
5476805f65bSBarry Smith      Dump the interpolation/restriction matrices plus the
5484b9ad928SBarry Smith    Jacobian/stiffness on each level. This allows Matlab users to
5496805f65bSBarry Smith    easily check if the Galerkin condition A_c = R A_f R^T is satisfied.
5506805f65bSBarry Smith 
5516805f65bSBarry Smith    Only support one or the other at the same time.
5526805f65bSBarry Smith   */
5536805f65bSBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER)
5547adad957SLisandro Dalcin   ierr = PetscOptionsHasName(((PetscObject)pc)->prefix,"-pc_mg_dump_matlab",&dump);CHKERRQ(ierr);
5554b9ad928SBarry Smith   if (dump) {
5567adad957SLisandro Dalcin     viewer = PETSC_VIEWER_SOCKET_(((PetscObject)pc)->comm);
5574b9ad928SBarry Smith   }
558c45a1595SBarry Smith #endif
5597adad957SLisandro Dalcin   ierr = PetscOptionsHasName(((PetscObject)pc)->prefix,"-pc_mg_dump_binary",&dump);CHKERRQ(ierr);
560c2be2410SBarry Smith   if (dump) {
5617adad957SLisandro Dalcin     viewer = PETSC_VIEWER_BINARY_(((PetscObject)pc)->comm);
5626805f65bSBarry Smith   }
5636805f65bSBarry Smith 
5646805f65bSBarry Smith   if (viewer) {
565c2be2410SBarry Smith     for (i=1; i<n; i++) {
5666805f65bSBarry Smith       ierr = MatView(mg[i]->restrct,viewer);CHKERRQ(ierr);
567c2be2410SBarry Smith     }
568c2be2410SBarry Smith     for (i=0; i<n; i++) {
569c2be2410SBarry Smith       ierr = KSPGetPC(mg[i]->smoothd,&pc);CHKERRQ(ierr);
5706805f65bSBarry Smith       ierr = MatView(pc->mat,viewer);CHKERRQ(ierr);
571c2be2410SBarry Smith     }
572c2be2410SBarry Smith   }
5734b9ad928SBarry Smith   PetscFunctionReturn(0);
5744b9ad928SBarry Smith }
5754b9ad928SBarry Smith 
5764b9ad928SBarry Smith /* -------------------------------------------------------------------------------------*/
5774b9ad928SBarry Smith 
5784b9ad928SBarry Smith #undef __FUNCT__
5799dcbbd2bSBarry Smith #define __FUNCT__ "PCMGSetLevels"
5804b9ad928SBarry Smith /*@C
58197177400SBarry Smith    PCMGSetLevels - Sets the number of levels to use with MG.
5824b9ad928SBarry Smith    Must be called before any other MG routine.
5834b9ad928SBarry Smith 
5844b9ad928SBarry Smith    Collective on PC
5854b9ad928SBarry Smith 
5864b9ad928SBarry Smith    Input Parameters:
5874b9ad928SBarry Smith +  pc - the preconditioner context
5884b9ad928SBarry Smith .  levels - the number of levels
5894b9ad928SBarry Smith -  comms - optional communicators for each level; this is to allow solving the coarser problems
5904b9ad928SBarry Smith            on smaller sets of processors. Use PETSC_NULL_OBJECT for default in Fortran
5914b9ad928SBarry Smith 
5924b9ad928SBarry Smith    Level: intermediate
5934b9ad928SBarry Smith 
5944b9ad928SBarry Smith    Notes:
5954b9ad928SBarry Smith      If the number of levels is one then the multigrid uses the -mg_levels prefix
5964b9ad928SBarry Smith   for setting the level options rather than the -mg_coarse prefix.
5974b9ad928SBarry Smith 
5984b9ad928SBarry Smith .keywords: MG, set, levels, multigrid
5994b9ad928SBarry Smith 
60097177400SBarry Smith .seealso: PCMGSetType(), PCMGGetLevels()
6014b9ad928SBarry Smith @*/
60297177400SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetLevels(PC pc,PetscInt levels,MPI_Comm *comms)
6034b9ad928SBarry Smith {
604dfbe8321SBarry Smith   PetscErrorCode ierr;
605ada7143aSSatish Balay   PC_MG          **mg=0;
6064b9ad928SBarry Smith 
6074b9ad928SBarry Smith   PetscFunctionBegin;
6084482741eSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
6094b9ad928SBarry Smith 
6104b9ad928SBarry Smith   if (pc->data) {
6111302d50aSBarry Smith     SETERRQ(PETSC_ERR_ORDER,"Number levels already set for MG\n\
61297177400SBarry Smith     make sure that you call PCMGSetLevels() before KSPSetFromOptions()");
6134b9ad928SBarry Smith   }
6147adad957SLisandro Dalcin   ierr                     = PCMGCreate_Private(((PetscObject)pc)->comm,levels,pc,comms,&mg);CHKERRQ(ierr);
6159dcbbd2bSBarry Smith   mg[0]->am                = PC_MG_MULTIPLICATIVE;
6164b9ad928SBarry Smith   pc->data                 = (void*)mg;
6174b9ad928SBarry Smith   pc->ops->applyrichardson = PCApplyRichardson_MG;
6184b9ad928SBarry Smith   PetscFunctionReturn(0);
6194b9ad928SBarry Smith }
6204b9ad928SBarry Smith 
6214b9ad928SBarry Smith #undef __FUNCT__
6229dcbbd2bSBarry Smith #define __FUNCT__ "PCMGGetLevels"
6234b9ad928SBarry Smith /*@
62497177400SBarry Smith    PCMGGetLevels - Gets the number of levels to use with MG.
6254b9ad928SBarry Smith 
6264b9ad928SBarry Smith    Not Collective
6274b9ad928SBarry Smith 
6284b9ad928SBarry Smith    Input Parameter:
6294b9ad928SBarry Smith .  pc - the preconditioner context
6304b9ad928SBarry Smith 
6314b9ad928SBarry Smith    Output parameter:
6324b9ad928SBarry Smith .  levels - the number of levels
6334b9ad928SBarry Smith 
6344b9ad928SBarry Smith    Level: advanced
6354b9ad928SBarry Smith 
6364b9ad928SBarry Smith .keywords: MG, get, levels, multigrid
6374b9ad928SBarry Smith 
63897177400SBarry Smith .seealso: PCMGSetLevels()
6394b9ad928SBarry Smith @*/
64097177400SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGGetLevels(PC pc,PetscInt *levels)
6414b9ad928SBarry Smith {
6429dcbbd2bSBarry Smith   PC_MG  **mg;
6434b9ad928SBarry Smith 
6444b9ad928SBarry Smith   PetscFunctionBegin;
6454482741eSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
6464482741eSBarry Smith   PetscValidIntPointer(levels,2);
6474b9ad928SBarry Smith 
6489dcbbd2bSBarry Smith   mg      = (PC_MG**)pc->data;
6494b9ad928SBarry Smith   *levels = mg[0]->levels;
6504b9ad928SBarry Smith   PetscFunctionReturn(0);
6514b9ad928SBarry Smith }
6524b9ad928SBarry Smith 
6534b9ad928SBarry Smith #undef __FUNCT__
6549dcbbd2bSBarry Smith #define __FUNCT__ "PCMGSetType"
6554b9ad928SBarry Smith /*@
65697177400SBarry Smith    PCMGSetType - Determines the form of multigrid to use:
6574b9ad928SBarry Smith    multiplicative, additive, full, or the Kaskade algorithm.
6584b9ad928SBarry Smith 
6594b9ad928SBarry Smith    Collective on PC
6604b9ad928SBarry Smith 
6614b9ad928SBarry Smith    Input Parameters:
6624b9ad928SBarry Smith +  pc - the preconditioner context
6639dcbbd2bSBarry Smith -  form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,
6649dcbbd2bSBarry Smith    PC_MG_FULL, PC_MG_KASKADE
6654b9ad928SBarry Smith 
6664b9ad928SBarry Smith    Options Database Key:
6674b9ad928SBarry Smith .  -pc_mg_type <form> - Sets <form>, one of multiplicative,
6684b9ad928SBarry Smith    additive, full, kaskade
6694b9ad928SBarry Smith 
6704b9ad928SBarry Smith    Level: advanced
6714b9ad928SBarry Smith 
6724b9ad928SBarry Smith .keywords: MG, set, method, multiplicative, additive, full, Kaskade, multigrid
6734b9ad928SBarry Smith 
67497177400SBarry Smith .seealso: PCMGSetLevels()
6754b9ad928SBarry Smith @*/
6769dcbbd2bSBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetType(PC pc,PCMGType form)
6774b9ad928SBarry Smith {
6789dcbbd2bSBarry Smith   PC_MG **mg;
6794b9ad928SBarry Smith 
6804b9ad928SBarry Smith   PetscFunctionBegin;
6814482741eSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
6829dcbbd2bSBarry Smith   mg = (PC_MG**)pc->data;
6834b9ad928SBarry Smith 
6844b9ad928SBarry Smith   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
6854b9ad928SBarry Smith   mg[0]->am = form;
6869dcbbd2bSBarry Smith   if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
6874b9ad928SBarry Smith   else pc->ops->applyrichardson = 0;
6884b9ad928SBarry Smith   PetscFunctionReturn(0);
6894b9ad928SBarry Smith }
6904b9ad928SBarry Smith 
6914b9ad928SBarry Smith #undef __FUNCT__
6920d353602SBarry Smith #define __FUNCT__ "PCMGSetCycleType"
6934b9ad928SBarry Smith /*@
6940d353602SBarry Smith    PCMGSetCycleType - Sets the type cycles to use.  Use PCMGSetCycleTypeOnLevel() for more
6954b9ad928SBarry Smith    complicated cycling.
6964b9ad928SBarry Smith 
6974b9ad928SBarry Smith    Collective on PC
6984b9ad928SBarry Smith 
6994b9ad928SBarry Smith    Input Parameters:
700c2be2410SBarry Smith +  pc - the multigrid context
7010d353602SBarry Smith -  PC_MG_CYCLE_V or PC_MG_CYCLE_W
7024b9ad928SBarry Smith 
7034b9ad928SBarry Smith    Options Database Key:
7040d353602SBarry Smith $  -pc_mg_cycle_type v or w
7054b9ad928SBarry Smith 
7064b9ad928SBarry Smith    Level: advanced
7074b9ad928SBarry Smith 
7084b9ad928SBarry Smith .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
7094b9ad928SBarry Smith 
7100d353602SBarry Smith .seealso: PCMGSetCycleTypeOnLevel()
7114b9ad928SBarry Smith @*/
7120d353602SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetCycleType(PC pc,PCMGCycleType n)
7134b9ad928SBarry Smith {
7149dcbbd2bSBarry Smith   PC_MG    **mg;
71579416396SBarry Smith   PetscInt i,levels;
7164b9ad928SBarry Smith 
7174b9ad928SBarry Smith   PetscFunctionBegin;
7184482741eSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
7199dcbbd2bSBarry Smith   mg     = (PC_MG**)pc->data;
7204b9ad928SBarry Smith   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
7214b9ad928SBarry Smith   levels = mg[0]->levels;
7224b9ad928SBarry Smith 
7234b9ad928SBarry Smith   for (i=0; i<levels; i++) {
7244b9ad928SBarry Smith     mg[i]->cycles  = n;
7254b9ad928SBarry Smith   }
7264b9ad928SBarry Smith   PetscFunctionReturn(0);
7274b9ad928SBarry Smith }
7284b9ad928SBarry Smith 
7294b9ad928SBarry Smith #undef __FUNCT__
7308cc2d5dfSBarry Smith #define __FUNCT__ "PCMGMultiplicativeSetCycles"
7318cc2d5dfSBarry Smith /*@
7328cc2d5dfSBarry Smith    PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step
7338cc2d5dfSBarry Smith          of multigrid when PCMGType of PC_MG_MULTIPLICATIVE is used
7348cc2d5dfSBarry Smith 
7358cc2d5dfSBarry Smith    Collective on PC
7368cc2d5dfSBarry Smith 
7378cc2d5dfSBarry Smith    Input Parameters:
7388cc2d5dfSBarry Smith +  pc - the multigrid context
7398cc2d5dfSBarry Smith -  n - number of cycles (default is 1)
7408cc2d5dfSBarry Smith 
7418cc2d5dfSBarry Smith    Options Database Key:
7428cc2d5dfSBarry Smith $  -pc_mg_multiplicative_cycles n
7438cc2d5dfSBarry Smith 
7448cc2d5dfSBarry Smith    Level: advanced
7458cc2d5dfSBarry Smith 
7468cc2d5dfSBarry Smith    Notes: This is not associated with setting a v or w cycle, that is set with PCMGSetCycleType()
7478cc2d5dfSBarry Smith 
7488cc2d5dfSBarry Smith .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
7498cc2d5dfSBarry Smith 
7508cc2d5dfSBarry Smith .seealso: PCMGSetCycleTypeOnLevel(), PCMGSetCycleType()
7518cc2d5dfSBarry Smith @*/
7528cc2d5dfSBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGMultiplicativeSetCycles(PC pc,PetscInt n)
7538cc2d5dfSBarry Smith {
7548cc2d5dfSBarry Smith   PC_MG    **mg;
7558cc2d5dfSBarry Smith   PetscInt i,levels;
7568cc2d5dfSBarry Smith 
7578cc2d5dfSBarry Smith   PetscFunctionBegin;
7588cc2d5dfSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
7598cc2d5dfSBarry Smith   mg     = (PC_MG**)pc->data;
7608cc2d5dfSBarry Smith   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
7618cc2d5dfSBarry Smith   levels = mg[0]->levels;
7628cc2d5dfSBarry Smith 
7638cc2d5dfSBarry Smith   for (i=0; i<levels; i++) {
7648cc2d5dfSBarry Smith     mg[i]->cyclesperpcapply  = n;
7658cc2d5dfSBarry Smith   }
7668cc2d5dfSBarry Smith   PetscFunctionReturn(0);
7678cc2d5dfSBarry Smith }
7688cc2d5dfSBarry Smith 
7698cc2d5dfSBarry Smith #undef __FUNCT__
7709dcbbd2bSBarry Smith #define __FUNCT__ "PCMGSetGalerkin"
771c2be2410SBarry Smith /*@
77297177400SBarry Smith    PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
773c2be2410SBarry Smith       finest grid via the Galerkin process: A_i-1 = r_i * A_i * r_i^t
774c2be2410SBarry Smith 
775c2be2410SBarry Smith    Collective on PC
776c2be2410SBarry Smith 
777c2be2410SBarry Smith    Input Parameters:
7783fc8bf9cSBarry Smith .  pc - the multigrid context
779c2be2410SBarry Smith 
780c2be2410SBarry Smith    Options Database Key:
781c2be2410SBarry Smith $  -pc_mg_galerkin
782c2be2410SBarry Smith 
783c2be2410SBarry Smith    Level: intermediate
784c2be2410SBarry Smith 
785c2be2410SBarry Smith .keywords: MG, set, Galerkin
786c2be2410SBarry Smith 
7873fc8bf9cSBarry Smith .seealso: PCMGGetGalerkin()
7883fc8bf9cSBarry Smith 
789c2be2410SBarry Smith @*/
79097177400SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetGalerkin(PC pc)
791c2be2410SBarry Smith {
7929dcbbd2bSBarry Smith   PC_MG    **mg;
793c2be2410SBarry Smith   PetscInt i,levels;
794c2be2410SBarry Smith 
795c2be2410SBarry Smith   PetscFunctionBegin;
796c2be2410SBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
7979dcbbd2bSBarry Smith   mg     = (PC_MG**)pc->data;
798c2be2410SBarry Smith   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
799c2be2410SBarry Smith   levels = mg[0]->levels;
800c2be2410SBarry Smith 
801c2be2410SBarry Smith   for (i=0; i<levels; i++) {
802c2be2410SBarry Smith     mg[i]->galerkin = PETSC_TRUE;
803c2be2410SBarry Smith   }
804c2be2410SBarry Smith   PetscFunctionReturn(0);
805c2be2410SBarry Smith }
806c2be2410SBarry Smith 
807c2be2410SBarry Smith #undef __FUNCT__
8083fc8bf9cSBarry Smith #define __FUNCT__ "PCMGGetGalerkin"
8093fc8bf9cSBarry Smith /*@
8103fc8bf9cSBarry Smith    PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e.
8113fc8bf9cSBarry Smith       A_i-1 = r_i * A_i * r_i^t
8123fc8bf9cSBarry Smith 
8133fc8bf9cSBarry Smith    Not Collective
8143fc8bf9cSBarry Smith 
8153fc8bf9cSBarry Smith    Input Parameter:
8163fc8bf9cSBarry Smith .  pc - the multigrid context
8173fc8bf9cSBarry Smith 
8183fc8bf9cSBarry Smith    Output Parameter:
8193fc8bf9cSBarry Smith .  gelerkin - PETSC_TRUE or PETSC_FALSE
8203fc8bf9cSBarry Smith 
8213fc8bf9cSBarry Smith    Options Database Key:
8223fc8bf9cSBarry Smith $  -pc_mg_galerkin
8233fc8bf9cSBarry Smith 
8243fc8bf9cSBarry Smith    Level: intermediate
8253fc8bf9cSBarry Smith 
8263fc8bf9cSBarry Smith .keywords: MG, set, Galerkin
8273fc8bf9cSBarry Smith 
8283fc8bf9cSBarry Smith .seealso: PCMGSetGalerkin()
8293fc8bf9cSBarry Smith 
8303fc8bf9cSBarry Smith @*/
8313fc8bf9cSBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGGetGalerkin(PC pc,PetscTruth *galerkin)
8323fc8bf9cSBarry Smith {
8333fc8bf9cSBarry Smith   PC_MG    **mg;
8343fc8bf9cSBarry Smith 
8353fc8bf9cSBarry Smith   PetscFunctionBegin;
8363fc8bf9cSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
8373fc8bf9cSBarry Smith   mg     = (PC_MG**)pc->data;
8383fc8bf9cSBarry Smith   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
8393fc8bf9cSBarry Smith   *galerkin = mg[0]->galerkin;
8403fc8bf9cSBarry Smith   PetscFunctionReturn(0);
8413fc8bf9cSBarry Smith }
8423fc8bf9cSBarry Smith 
8433fc8bf9cSBarry Smith #undef __FUNCT__
8449dcbbd2bSBarry Smith #define __FUNCT__ "PCMGSetNumberSmoothDown"
8454b9ad928SBarry Smith /*@
84697177400SBarry Smith    PCMGSetNumberSmoothDown - Sets the number of pre-smoothing steps to
84797177400SBarry Smith    use on all levels. Use PCMGGetSmootherDown() to set different
8484b9ad928SBarry Smith    pre-smoothing steps on different levels.
8494b9ad928SBarry Smith 
8504b9ad928SBarry Smith    Collective on PC
8514b9ad928SBarry Smith 
8524b9ad928SBarry Smith    Input Parameters:
8534b9ad928SBarry Smith +  mg - the multigrid context
8544b9ad928SBarry Smith -  n - the number of smoothing steps
8554b9ad928SBarry Smith 
8564b9ad928SBarry Smith    Options Database Key:
8574b9ad928SBarry Smith .  -pc_mg_smoothdown <n> - Sets number of pre-smoothing steps
8584b9ad928SBarry Smith 
8594b9ad928SBarry Smith    Level: advanced
8604b9ad928SBarry Smith 
8614b9ad928SBarry Smith .keywords: MG, smooth, down, pre-smoothing, steps, multigrid
8624b9ad928SBarry Smith 
86397177400SBarry Smith .seealso: PCMGSetNumberSmoothUp()
8644b9ad928SBarry Smith @*/
86597177400SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetNumberSmoothDown(PC pc,PetscInt n)
8664b9ad928SBarry Smith {
8679dcbbd2bSBarry Smith   PC_MG          **mg;
8686849ba73SBarry Smith   PetscErrorCode ierr;
86979416396SBarry Smith   PetscInt       i,levels;
8704b9ad928SBarry Smith 
8714b9ad928SBarry Smith   PetscFunctionBegin;
8724482741eSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
8739dcbbd2bSBarry Smith   mg     = (PC_MG**)pc->data;
8744b9ad928SBarry Smith   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
8754b9ad928SBarry Smith   levels = mg[0]->levels;
8764b9ad928SBarry Smith 
877b05257ddSBarry Smith   for (i=1; i<levels; i++) {
8784b9ad928SBarry Smith     /* make sure smoother up and down are different */
87997177400SBarry Smith     ierr = PCMGGetSmootherUp(pc,i,PETSC_NULL);CHKERRQ(ierr);
8804b9ad928SBarry Smith     ierr = KSPSetTolerances(mg[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr);
8814b9ad928SBarry Smith     mg[i]->default_smoothd = n;
8824b9ad928SBarry Smith   }
8834b9ad928SBarry Smith   PetscFunctionReturn(0);
8844b9ad928SBarry Smith }
8854b9ad928SBarry Smith 
8864b9ad928SBarry Smith #undef __FUNCT__
8879dcbbd2bSBarry Smith #define __FUNCT__ "PCMGSetNumberSmoothUp"
8884b9ad928SBarry Smith /*@
88997177400SBarry Smith    PCMGSetNumberSmoothUp - Sets the number of post-smoothing steps to use
89097177400SBarry Smith    on all levels. Use PCMGGetSmootherUp() to set different numbers of
8914b9ad928SBarry Smith    post-smoothing steps on different levels.
8924b9ad928SBarry Smith 
8934b9ad928SBarry Smith    Collective on PC
8944b9ad928SBarry Smith 
8954b9ad928SBarry Smith    Input Parameters:
8964b9ad928SBarry Smith +  mg - the multigrid context
8974b9ad928SBarry Smith -  n - the number of smoothing steps
8984b9ad928SBarry Smith 
8994b9ad928SBarry Smith    Options Database Key:
9004b9ad928SBarry Smith .  -pc_mg_smoothup <n> - Sets number of post-smoothing steps
9014b9ad928SBarry Smith 
9024b9ad928SBarry Smith    Level: advanced
9034b9ad928SBarry Smith 
9044b9ad928SBarry Smith    Note: this does not set a value on the coarsest grid, since we assume that
905a8c7a070SBarry Smith     there is no separate smooth up on the coarsest grid.
9064b9ad928SBarry Smith 
9074b9ad928SBarry Smith .keywords: MG, smooth, up, post-smoothing, steps, multigrid
9084b9ad928SBarry Smith 
90997177400SBarry Smith .seealso: PCMGSetNumberSmoothDown()
9104b9ad928SBarry Smith @*/
91197177400SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetNumberSmoothUp(PC pc,PetscInt n)
9124b9ad928SBarry Smith {
9139dcbbd2bSBarry Smith   PC_MG          **mg;
9146849ba73SBarry Smith   PetscErrorCode ierr;
91579416396SBarry Smith   PetscInt       i,levels;
9164b9ad928SBarry Smith 
9174b9ad928SBarry Smith   PetscFunctionBegin;
9184482741eSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
9199dcbbd2bSBarry Smith   mg     = (PC_MG**)pc->data;
9204b9ad928SBarry Smith   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
9214b9ad928SBarry Smith   levels = mg[0]->levels;
9224b9ad928SBarry Smith 
9234b9ad928SBarry Smith   for (i=1; i<levels; i++) {
9244b9ad928SBarry Smith     /* make sure smoother up and down are different */
92597177400SBarry Smith     ierr = PCMGGetSmootherUp(pc,i,PETSC_NULL);CHKERRQ(ierr);
9264b9ad928SBarry Smith     ierr = KSPSetTolerances(mg[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr);
9274b9ad928SBarry Smith     mg[i]->default_smoothu = n;
9284b9ad928SBarry Smith   }
9294b9ad928SBarry Smith   PetscFunctionReturn(0);
9304b9ad928SBarry Smith }
9314b9ad928SBarry Smith 
9324b9ad928SBarry Smith /* ----------------------------------------------------------------------------------------*/
9334b9ad928SBarry Smith 
9343b09bd56SBarry Smith /*MC
935ccb205f8SBarry Smith    PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional
9363b09bd56SBarry Smith     information about the coarser grid matrices and restriction/interpolation operators.
9373b09bd56SBarry Smith 
9383b09bd56SBarry Smith    Options Database Keys:
9393b09bd56SBarry Smith +  -pc_mg_levels <nlevels> - number of levels including finest
9400d353602SBarry Smith .  -pc_mg_cycles v or w
94179416396SBarry Smith .  -pc_mg_smoothup <n> - number of smoothing steps after interpolation
9423b09bd56SBarry Smith .  -pc_mg_smoothdown <n> - number of smoothing steps before applying restriction operator
9433b09bd56SBarry Smith .  -pc_mg_type <additive,multiplicative,full,cascade> - multiplicative is the default
9443b09bd56SBarry Smith .  -pc_mg_log - log information about time spent on each level of the solver
9453b09bd56SBarry Smith .  -pc_mg_monitor - print information on the multigrid convergence
94668eff7e6SBarry Smith .  -pc_mg_galerkin - use Galerkin process to compute coarser operators
9473b09bd56SBarry Smith -  -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices
9483b09bd56SBarry Smith                         to the Socket viewer for reading from Matlab.
9493b09bd56SBarry Smith 
9503b09bd56SBarry Smith    Notes:
9513b09bd56SBarry Smith 
9523b09bd56SBarry Smith    Level: intermediate
9533b09bd56SBarry Smith 
9548f87f92bSBarry Smith    Concepts: multigrid/multilevel
9553b09bd56SBarry Smith 
9563b09bd56SBarry Smith .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType,
9570d353602SBarry Smith            PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), PCMGSetCycleType(), PCMGSetNumberSmoothDown(),
95897177400SBarry Smith            PCMGSetNumberSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(),
95997177400SBarry Smith            PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(),
9600d353602SBarry Smith            PCMGSetCycleTypeOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR()
9613b09bd56SBarry Smith M*/
9623b09bd56SBarry Smith 
9634b9ad928SBarry Smith EXTERN_C_BEGIN
9644b9ad928SBarry Smith #undef __FUNCT__
9654b9ad928SBarry Smith #define __FUNCT__ "PCCreate_MG"
966dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_MG(PC pc)
9674b9ad928SBarry Smith {
9684b9ad928SBarry Smith   PetscFunctionBegin;
9694b9ad928SBarry Smith   pc->ops->apply          = PCApply_MG;
9704b9ad928SBarry Smith   pc->ops->setup          = PCSetUp_MG;
9714b9ad928SBarry Smith   pc->ops->destroy        = PCDestroy_MG;
9724b9ad928SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_MG;
9734b9ad928SBarry Smith   pc->ops->view           = PCView_MG;
9744b9ad928SBarry Smith 
9754b9ad928SBarry Smith   pc->data                = (void*)0;
9764b9ad928SBarry Smith   PetscFunctionReturn(0);
9774b9ad928SBarry Smith }
9784b9ad928SBarry Smith EXTERN_C_END
979