xref: /petsc/src/ksp/pc/impls/mg/mg.c (revision 0d3536023ef1da070246654f40ac318d23f0df71)
1dba47a55SKris Buschelman #define PETSCKSP_DLL
2dba47a55SKris Buschelman 
34b9ad928SBarry Smith /*
44b9ad928SBarry Smith     Defines the multigrid preconditioner interface.
54b9ad928SBarry Smith */
64b9ad928SBarry 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"
119dcbbd2bSBarry Smith PetscErrorCode PCMGMCycle_Private(PC_MG **mglevels,PetscTruth *converged)
124b9ad928SBarry Smith {
139dcbbd2bSBarry Smith   PC_MG          *mg = *mglevels,*mgc;
146849ba73SBarry Smith   PetscErrorCode ierr;
15*0d353602SBarry Smith   PetscInt       cycles = (PetscInt) mg->cycles;
164b9ad928SBarry Smith 
174b9ad928SBarry Smith   PetscFunctionBegin;
184b9ad928SBarry Smith   if (converged) *converged = PETSC_FALSE;
194b9ad928SBarry Smith 
204b9ad928SBarry Smith   if (mg->eventsolve) {ierr = PetscLogEventBegin(mg->eventsolve,0,0,0,0);CHKERRQ(ierr);}
21*0d353602SBarry Smith   ierr = KSPSolve(mg->smoothd,mg->b,mg->x);CHKERRQ(ierr);  /* pre-smooth */
224b9ad928SBarry Smith   if (mg->eventsolve) {ierr = PetscLogEventEnd(mg->eventsolve,0,0,0,0);CHKERRQ(ierr);}
234b9ad928SBarry Smith   if (mg->level) {  /* not the coarsest grid */
244b9ad928SBarry Smith     ierr = (*mg->residual)(mg->A,mg->b,mg->x,mg->r);CHKERRQ(ierr);
254b9ad928SBarry Smith 
264b9ad928SBarry Smith     /* if on finest level and have convergence criteria set */
274b9ad928SBarry Smith     if (mg->level == mg->levels-1 && mg->ttol) {
284b9ad928SBarry Smith       PetscReal rnorm;
294b9ad928SBarry Smith       ierr = VecNorm(mg->r,NORM_2,&rnorm);CHKERRQ(ierr);
304b9ad928SBarry Smith       if (rnorm <= mg->ttol) {
314b9ad928SBarry Smith         *converged = PETSC_TRUE;
3270441072SBarry Smith         if (rnorm < mg->abstol) {
33ae15b995SBarry Smith           ierr = PetscInfo2(0,"Linear solver has converged. Residual norm %G is less than absolute tolerance %G\n",rnorm,mg->abstol);CHKERRQ(ierr);
344b9ad928SBarry Smith         } else {
35ae15b995SBarry Smith           ierr = PetscInfo2(0,"Linear solver has converged. Residual norm %G is less than relative tolerance times initial residual norm %G\n",rnorm,mg->ttol);CHKERRQ(ierr);
364b9ad928SBarry Smith         }
374b9ad928SBarry Smith         PetscFunctionReturn(0);
384b9ad928SBarry Smith       }
394b9ad928SBarry Smith     }
404b9ad928SBarry Smith 
414b9ad928SBarry Smith     mgc = *(mglevels - 1);
424b9ad928SBarry Smith     ierr = MatRestrict(mg->restrct,mg->r,mgc->b);CHKERRQ(ierr);
43efb30889SBarry Smith     ierr = VecSet(mgc->x,0.0);CHKERRQ(ierr);
444b9ad928SBarry Smith     while (cycles--) {
459dcbbd2bSBarry Smith       ierr = PCMGMCycle_Private(mglevels-1,converged);CHKERRQ(ierr);
464b9ad928SBarry Smith     }
474b9ad928SBarry Smith     ierr = MatInterpolateAdd(mg->interpolate,mgc->x,mg->x,mg->x);CHKERRQ(ierr);
484b9ad928SBarry Smith     if (mg->eventsolve) {ierr = PetscLogEventBegin(mg->eventsolve,0,0,0,0);CHKERRQ(ierr);}
49*0d353602SBarry Smith     ierr = KSPSolve(mg->smoothu,mg->b,mg->x);CHKERRQ(ierr);    /* post smooth */
504b9ad928SBarry Smith     if (mg->eventsolve) {ierr = PetscLogEventEnd(mg->eventsolve,0,0,0,0);CHKERRQ(ierr);}
514b9ad928SBarry Smith   }
524b9ad928SBarry Smith   PetscFunctionReturn(0);
534b9ad928SBarry Smith }
544b9ad928SBarry Smith 
554b9ad928SBarry Smith /*
569dcbbd2bSBarry Smith        PCMGCreate_Private - Creates a PC_MG structure for use with the
574b9ad928SBarry Smith                multigrid code. Level 0 is the coarsest. (But the
584b9ad928SBarry Smith                finest level is stored first in the array).
594b9ad928SBarry Smith 
604b9ad928SBarry Smith */
614b9ad928SBarry Smith #undef __FUNCT__
629dcbbd2bSBarry Smith #define __FUNCT__ "PCMGCreate_Private"
639dcbbd2bSBarry Smith static PetscErrorCode PCMGCreate_Private(MPI_Comm comm,PetscInt levels,PC pc,MPI_Comm *comms,PC_MG ***result)
644b9ad928SBarry Smith {
659dcbbd2bSBarry Smith   PC_MG          **mg;
666849ba73SBarry Smith   PetscErrorCode ierr;
6779416396SBarry Smith   PetscInt       i;
6879416396SBarry Smith   PetscMPIInt    size;
69f69a0ea3SMatthew Knepley   const char     *prefix;
704b9ad928SBarry Smith   PC             ipc;
714b9ad928SBarry Smith 
724b9ad928SBarry Smith   PetscFunctionBegin;
739dcbbd2bSBarry Smith   ierr = PetscMalloc(levels*sizeof(PC_MG*),&mg);CHKERRQ(ierr);
749dcbbd2bSBarry Smith   ierr = PetscLogObjectMemory(pc,levels*(sizeof(PC_MG*)+sizeof(PC_MG)));CHKERRQ(ierr);
754b9ad928SBarry Smith 
764b9ad928SBarry Smith   ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
774b9ad928SBarry Smith 
784b9ad928SBarry Smith   for (i=0; i<levels; i++) {
799dcbbd2bSBarry Smith     ierr = PetscNew(PC_MG,&mg[i]);CHKERRQ(ierr);
804b9ad928SBarry Smith     mg[i]->level           = i;
814b9ad928SBarry Smith     mg[i]->levels          = levels;
82*0d353602SBarry Smith     mg[i]->cycles          = PC_MG_CYCLE_V;
83c2be2410SBarry Smith     mg[i]->galerkin        = PETSC_FALSE;
84c2be2410SBarry Smith     mg[i]->galerkinused    = PETSC_FALSE;
8579416396SBarry Smith     mg[i]->default_smoothu = 1;
8679416396SBarry Smith     mg[i]->default_smoothd = 1;
874b9ad928SBarry Smith 
884b9ad928SBarry Smith     if (comms) comm = comms[i];
894b9ad928SBarry Smith     ierr = KSPCreate(comm,&mg[i]->smoothd);CHKERRQ(ierr);
9079416396SBarry Smith     ierr = KSPSetTolerances(mg[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, mg[i]->default_smoothd);CHKERRQ(ierr);
914b9ad928SBarry Smith     ierr = KSPSetOptionsPrefix(mg[i]->smoothd,prefix);CHKERRQ(ierr);
924b9ad928SBarry Smith 
934b9ad928SBarry Smith     /* do special stuff for coarse grid */
944b9ad928SBarry Smith     if (!i && levels > 1) {
954b9ad928SBarry Smith       ierr = KSPAppendOptionsPrefix(mg[0]->smoothd,"mg_coarse_");CHKERRQ(ierr);
964b9ad928SBarry Smith 
974b9ad928SBarry Smith       /* coarse solve is (redundant) LU by default */
984b9ad928SBarry Smith       ierr = KSPSetType(mg[0]->smoothd,KSPPREONLY);CHKERRQ(ierr);
994b9ad928SBarry Smith       ierr = KSPGetPC(mg[0]->smoothd,&ipc);CHKERRQ(ierr);
1004b9ad928SBarry Smith       ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1014b9ad928SBarry Smith       if (size > 1) {
1024b9ad928SBarry Smith         ierr = PCSetType(ipc,PCREDUNDANT);CHKERRQ(ierr);
1034b9ad928SBarry Smith         ierr = PCRedundantGetPC(ipc,&ipc);CHKERRQ(ierr);
1044b9ad928SBarry Smith       }
1054b9ad928SBarry Smith       ierr = PCSetType(ipc,PCLU);CHKERRQ(ierr);
1064b9ad928SBarry Smith 
1074b9ad928SBarry Smith     } else {
1082e70eadcSBarry Smith       char tprefix[128];
10913f74950SBarry Smith       sprintf(tprefix,"mg_levels_%d_",(int)i);
1102e70eadcSBarry Smith       ierr = KSPAppendOptionsPrefix(mg[i]->smoothd,tprefix);CHKERRQ(ierr);
1114b9ad928SBarry Smith     }
11252e6d16bSBarry Smith     ierr = PetscLogObjectParent(pc,mg[i]->smoothd);CHKERRQ(ierr);
1134b9ad928SBarry Smith     mg[i]->smoothu         = mg[i]->smoothd;
1144b9ad928SBarry Smith     mg[i]->rtol = 0.0;
11570441072SBarry Smith     mg[i]->abstol = 0.0;
1164b9ad928SBarry Smith     mg[i]->dtol = 0.0;
1174b9ad928SBarry Smith     mg[i]->ttol = 0.0;
1184b9ad928SBarry Smith     mg[i]->eventsetup = 0;
1194b9ad928SBarry Smith     mg[i]->eventsolve = 0;
1204b9ad928SBarry Smith   }
1214b9ad928SBarry Smith   *result = mg;
1224b9ad928SBarry Smith   PetscFunctionReturn(0);
1234b9ad928SBarry Smith }
1244b9ad928SBarry Smith 
1254b9ad928SBarry Smith #undef __FUNCT__
1264b9ad928SBarry Smith #define __FUNCT__ "PCDestroy_MG"
1276849ba73SBarry Smith static PetscErrorCode PCDestroy_MG(PC pc)
1284b9ad928SBarry Smith {
1299dcbbd2bSBarry Smith   PC_MG          **mg = (PC_MG**)pc->data;
1306849ba73SBarry Smith   PetscErrorCode ierr;
13179416396SBarry Smith   PetscInt       i,n = mg[0]->levels;
1324b9ad928SBarry Smith 
1334b9ad928SBarry Smith   PetscFunctionBegin;
134fccaa45eSBarry Smith   for (i=0; i<n-1; i++) {
135630ba2eeSBarry Smith     if (mg[i+1]->r) {ierr = VecDestroy(mg[i+1]->r);CHKERRQ(ierr);}
136fccaa45eSBarry Smith     if (mg[i]->b) {ierr = VecDestroy(mg[i]->b);CHKERRQ(ierr);}
137fccaa45eSBarry Smith     if (mg[i]->x) {ierr = VecDestroy(mg[i]->x);CHKERRQ(ierr);}
138fccaa45eSBarry Smith     if (mg[i+1]->restrct) {ierr = MatDestroy(mg[i+1]->restrct);CHKERRQ(ierr);}
139fccaa45eSBarry Smith     if (mg[i+1]->interpolate) {ierr = MatDestroy(mg[i+1]->interpolate);CHKERRQ(ierr);}
140fccaa45eSBarry Smith   }
141fccaa45eSBarry Smith 
1424b9ad928SBarry Smith   for (i=0; i<n; i++) {
1434b9ad928SBarry Smith     if (mg[i]->smoothd != mg[i]->smoothu) {
1444b9ad928SBarry Smith       ierr = KSPDestroy(mg[i]->smoothd);CHKERRQ(ierr);
1454b9ad928SBarry Smith     }
1464b9ad928SBarry Smith     ierr = KSPDestroy(mg[i]->smoothu);CHKERRQ(ierr);
1474b9ad928SBarry Smith     ierr = PetscFree(mg[i]);CHKERRQ(ierr);
1484b9ad928SBarry Smith   }
1494b9ad928SBarry Smith   ierr = PetscFree(mg);CHKERRQ(ierr);
1504b9ad928SBarry Smith   PetscFunctionReturn(0);
1514b9ad928SBarry Smith }
1524b9ad928SBarry Smith 
1534b9ad928SBarry Smith 
1544b9ad928SBarry Smith 
1559dcbbd2bSBarry Smith EXTERN PetscErrorCode PCMGACycle_Private(PC_MG**);
1569dcbbd2bSBarry Smith EXTERN PetscErrorCode PCMGFCycle_Private(PC_MG**);
1579dcbbd2bSBarry Smith EXTERN PetscErrorCode PCMGKCycle_Private(PC_MG**);
1584b9ad928SBarry Smith 
1594b9ad928SBarry Smith /*
1604b9ad928SBarry Smith    PCApply_MG - Runs either an additive, multiplicative, Kaskadic
1614b9ad928SBarry Smith              or full cycle of multigrid.
1624b9ad928SBarry Smith 
1634b9ad928SBarry Smith   Note:
1649dcbbd2bSBarry Smith   A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
1654b9ad928SBarry Smith */
1664b9ad928SBarry Smith #undef __FUNCT__
1674b9ad928SBarry Smith #define __FUNCT__ "PCApply_MG"
1686849ba73SBarry Smith static PetscErrorCode PCApply_MG(PC pc,Vec b,Vec x)
1694b9ad928SBarry Smith {
1709dcbbd2bSBarry Smith   PC_MG          **mg = (PC_MG**)pc->data;
1716849ba73SBarry Smith   PetscErrorCode ierr;
17279416396SBarry Smith   PetscInt       levels = mg[0]->levels;
1734b9ad928SBarry Smith 
1744b9ad928SBarry Smith   PetscFunctionBegin;
1754b9ad928SBarry Smith   mg[levels-1]->b = b;
1764b9ad928SBarry Smith   mg[levels-1]->x = x;
177ef70c39aSMatthew Knepley   if (!mg[levels-1]->r && mg[0]->am != PC_MG_ADDITIVE && levels > 1) {
1780a6bb862SBarry Smith     Vec tvec;
1790a6bb862SBarry Smith     ierr = VecDuplicate(mg[levels-1]->b,&tvec);CHKERRQ(ierr);
18097177400SBarry Smith     ierr = PCMGSetR(pc,levels-1,tvec);CHKERRQ(ierr);
1810a6bb862SBarry Smith     ierr = VecDestroy(tvec);CHKERRQ(ierr);
1820a6bb862SBarry Smith   }
1839dcbbd2bSBarry Smith   if (mg[0]->am == PC_MG_MULTIPLICATIVE) {
184efb30889SBarry Smith     ierr = VecSet(x,0.0);CHKERRQ(ierr);
1859dcbbd2bSBarry Smith     ierr = PCMGMCycle_Private(mg+levels-1,PETSC_NULL);CHKERRQ(ierr);
1864b9ad928SBarry Smith   }
1879dcbbd2bSBarry Smith   else if (mg[0]->am == PC_MG_ADDITIVE) {
1889dcbbd2bSBarry Smith     ierr = PCMGACycle_Private(mg);CHKERRQ(ierr);
1894b9ad928SBarry Smith   }
1909dcbbd2bSBarry Smith   else if (mg[0]->am == PC_MG_KASKADE) {
1919dcbbd2bSBarry Smith     ierr = PCMGKCycle_Private(mg);CHKERRQ(ierr);
1924b9ad928SBarry Smith   }
1934b9ad928SBarry Smith   else {
1949dcbbd2bSBarry Smith     ierr = PCMGFCycle_Private(mg);CHKERRQ(ierr);
1954b9ad928SBarry Smith   }
1964b9ad928SBarry Smith   PetscFunctionReturn(0);
1974b9ad928SBarry Smith }
1984b9ad928SBarry Smith 
1994b9ad928SBarry Smith #undef __FUNCT__
2004b9ad928SBarry Smith #define __FUNCT__ "PCApplyRichardson_MG"
20179416396SBarry Smith static PetscErrorCode PCApplyRichardson_MG(PC pc,Vec b,Vec x,Vec w,PetscReal rtol,PetscReal abstol, PetscReal dtol,PetscInt its)
2024b9ad928SBarry Smith {
2039dcbbd2bSBarry Smith   PC_MG          **mg = (PC_MG**)pc->data;
204dfbe8321SBarry Smith   PetscErrorCode ierr;
20579416396SBarry Smith   PetscInt       levels = mg[0]->levels;
2064b9ad928SBarry Smith   PetscTruth     converged = PETSC_FALSE;
2074b9ad928SBarry Smith 
2084b9ad928SBarry Smith   PetscFunctionBegin;
2094b9ad928SBarry Smith   mg[levels-1]->b    = b;
2104b9ad928SBarry Smith   mg[levels-1]->x    = x;
2114b9ad928SBarry Smith 
2124b9ad928SBarry Smith   mg[levels-1]->rtol = rtol;
21370441072SBarry Smith   mg[levels-1]->abstol = abstol;
2144b9ad928SBarry Smith   mg[levels-1]->dtol = dtol;
2154b9ad928SBarry Smith   if (rtol) {
2164b9ad928SBarry Smith     /* compute initial residual norm for relative convergence test */
2174b9ad928SBarry Smith     PetscReal rnorm;
2184b9ad928SBarry Smith     ierr               = (*mg[levels-1]->residual)(mg[levels-1]->A,b,x,w);CHKERRQ(ierr);
2194b9ad928SBarry Smith     ierr               = VecNorm(w,NORM_2,&rnorm);CHKERRQ(ierr);
22070441072SBarry Smith     mg[levels-1]->ttol = PetscMax(rtol*rnorm,abstol);
22170441072SBarry Smith   } else if (abstol) {
22270441072SBarry Smith     mg[levels-1]->ttol = abstol;
2234b9ad928SBarry Smith   } else {
2244b9ad928SBarry Smith     mg[levels-1]->ttol = 0.0;
2254b9ad928SBarry Smith   }
2264b9ad928SBarry Smith 
2274b9ad928SBarry Smith   while (its-- && !converged) {
2289dcbbd2bSBarry Smith     ierr = PCMGMCycle_Private(mg+levels-1,&converged);CHKERRQ(ierr);
2294b9ad928SBarry Smith   }
2304b9ad928SBarry Smith   PetscFunctionReturn(0);
2314b9ad928SBarry Smith }
2324b9ad928SBarry Smith 
2334b9ad928SBarry Smith #undef __FUNCT__
2344b9ad928SBarry Smith #define __FUNCT__ "PCSetFromOptions_MG"
2356ca4d86aSHong Zhang PetscErrorCode PCSetFromOptions_MG(PC pc)
2364b9ad928SBarry Smith {
237dfbe8321SBarry Smith   PetscErrorCode ierr;
2389dcbbd2bSBarry Smith   PetscInt       m,levels = 1;
2394b9ad928SBarry Smith   PetscTruth     flg;
2409dcbbd2bSBarry Smith   PC_MG          **mg = (PC_MG**)pc->data;
241cf502942SBarry Smith   PCMGType       mgtype;
242*0d353602SBarry Smith   PCMGCycleType  mgctype;
2434b9ad928SBarry Smith 
2444b9ad928SBarry Smith   PetscFunctionBegin;
2454b9ad928SBarry Smith   ierr = PetscOptionsHead("Multigrid options");CHKERRQ(ierr);
2464b9ad928SBarry Smith     if (!pc->data) {
2479dcbbd2bSBarry Smith       ierr = PetscOptionsInt("-pc_mg_levels","Number of Levels","PCMGSetLevels",levels,&levels,&flg);CHKERRQ(ierr);
24897177400SBarry Smith       ierr = PCMGSetLevels(pc,levels,PETSC_NULL);CHKERRQ(ierr);
249cf502942SBarry Smith       mg = (PC_MG**)pc->data;
2504b9ad928SBarry Smith     }
251*0d353602SBarry Smith     mgctype = mg[0]->cyclesperpcapply;
252*0d353602SBarry Smith     ierr = PetscOptionsEnum("-pc_mg_cycle_type","V cycle or for W-cycle","PCMGSetCycleType",PCMGCycleTypes,(PetscEnum)mgctype,(PetscEnum*)&mgctype,&flg);CHKERRQ(ierr);
2534b9ad928SBarry Smith     if (flg) {
254*0d353602SBarry Smith       ierr = PCMGSetCycleType(pc,mgctype);CHKERRQ(ierr);
255*0d353602SBarry Smith     };
2569dcbbd2bSBarry Smith     ierr = PetscOptionsName("-pc_mg_galerkin","Use Galerkin process to compute coarser operators","PCMGSetGalerkin",&flg);CHKERRQ(ierr);
257c2be2410SBarry Smith     if (flg) {
25897177400SBarry Smith       ierr = PCMGSetGalerkin(pc);CHKERRQ(ierr);
259c2be2410SBarry Smith     }
2609dcbbd2bSBarry Smith     ierr = PetscOptionsInt("-pc_mg_smoothup","Number of post-smoothing steps","PCMGSetNumberSmoothUp",1,&m,&flg);CHKERRQ(ierr);
2614b9ad928SBarry Smith     if (flg) {
26297177400SBarry Smith       ierr = PCMGSetNumberSmoothUp(pc,m);CHKERRQ(ierr);
2634b9ad928SBarry Smith     }
2649dcbbd2bSBarry Smith     ierr = PetscOptionsInt("-pc_mg_smoothdown","Number of pre-smoothing steps","PCMGSetNumberSmoothDown",1,&m,&flg);CHKERRQ(ierr);
2654b9ad928SBarry Smith     if (flg) {
26697177400SBarry Smith       ierr = PCMGSetNumberSmoothDown(pc,m);CHKERRQ(ierr);
2674b9ad928SBarry Smith     }
2689dcbbd2bSBarry Smith     ierr = PetscOptionsEnum("-pc_mg_type","Multigrid type","PCMGSetType",PCMGTypes,(PetscEnum)mgtype,(PetscEnum*)&mgtype,&flg);CHKERRQ(ierr);
2699dcbbd2bSBarry Smith     if (flg) {ierr = PCMGSetType(pc,mgtype);CHKERRQ(ierr);}
2704b9ad928SBarry Smith     ierr = PetscOptionsName("-pc_mg_log","Log times for each multigrid level","None",&flg);CHKERRQ(ierr);
2714b9ad928SBarry Smith     if (flg) {
2724f5ab15aSBarry Smith       PetscInt i;
2734b9ad928SBarry Smith       char     eventname[128];
2744b9ad928SBarry Smith       if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
2754b9ad928SBarry Smith       levels = mg[0]->levels;
2764b9ad928SBarry Smith       for (i=0; i<levels; i++) {
27777431f27SBarry Smith         sprintf(eventname,"MSetup Level %d",(int)i);
2784b9ad928SBarry Smith         ierr = PetscLogEventRegister(&mg[i]->eventsetup,eventname,pc->cookie);CHKERRQ(ierr);
27925a62d46SBarry Smith         sprintf(eventname,"MGSolve Level %d to 0",(int)i);
2804b9ad928SBarry Smith         ierr = PetscLogEventRegister(&mg[i]->eventsolve,eventname,pc->cookie);CHKERRQ(ierr);
2814b9ad928SBarry Smith       }
2824b9ad928SBarry Smith     }
2834b9ad928SBarry Smith   ierr = PetscOptionsTail();CHKERRQ(ierr);
2844b9ad928SBarry Smith   PetscFunctionReturn(0);
2854b9ad928SBarry Smith }
2864b9ad928SBarry Smith 
2879dcbbd2bSBarry Smith const char *PCMGTypes[] = {"MULTIPLICATIVE","ADDITIVE","FULL","KASKADE","PCMGType","PC_MG",0};
288*0d353602SBarry Smith const char *PCMGCycleTypes[] = {"invalid","v","w","PCMGCycleType","PC_MG_CYCLE",0};
2899dcbbd2bSBarry Smith 
2904b9ad928SBarry Smith #undef __FUNCT__
2914b9ad928SBarry Smith #define __FUNCT__ "PCView_MG"
2926849ba73SBarry Smith static PetscErrorCode PCView_MG(PC pc,PetscViewer viewer)
2934b9ad928SBarry Smith {
2949dcbbd2bSBarry Smith   PC_MG          **mg = (PC_MG**)pc->data;
295dfbe8321SBarry Smith   PetscErrorCode ierr;
29679416396SBarry Smith   PetscInt       levels = mg[0]->levels,i;
29732077d6dSBarry Smith   PetscTruth     iascii;
2984b9ad928SBarry Smith 
2994b9ad928SBarry Smith   PetscFunctionBegin;
30032077d6dSBarry Smith   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
30132077d6dSBarry Smith   if (iascii) {
302*0d353602SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  MG: type is %s, levels=%D cycles=%s, pre-smooths=%D, post-smooths=%D\n",
303*0d353602SBarry Smith 				  PCMGTypes[mg[0]->am],levels,(mg[0]->cycles == PC_MG_CYCLE_V) ? "v" : "w",
304*0d353602SBarry Smith                                   mg[0]->default_smoothd,mg[0]->default_smoothu);CHKERRQ(ierr);
305c2be2410SBarry Smith     if (mg[0]->galerkin) {
306c2be2410SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid matrices\n");CHKERRQ(ierr);
307c2be2410SBarry Smith     }
3084b9ad928SBarry Smith     for (i=0; i<levels; i++) {
309b03c7568SBarry Smith       if (!i) {
310b03c7568SBarry Smith         ierr = PetscViewerASCIIPrintf(viewer,"Coarse gride solver -- level %D -------------------------------\n",i);CHKERRQ(ierr);
311b03c7568SBarry Smith       } else {
31277431f27SBarry Smith         ierr = PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
313b03c7568SBarry Smith       }
3144b9ad928SBarry Smith       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
3154b9ad928SBarry Smith       ierr = KSPView(mg[i]->smoothd,viewer);CHKERRQ(ierr);
3164b9ad928SBarry Smith       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
317b03c7568SBarry Smith       if (i && mg[i]->smoothd == mg[i]->smoothu) {
3184b9ad928SBarry Smith         ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n");CHKERRQ(ierr);
319b03c7568SBarry Smith       } else if (i){
32077431f27SBarry Smith         ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
3214b9ad928SBarry Smith         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
3224b9ad928SBarry Smith         ierr = KSPView(mg[i]->smoothu,viewer);CHKERRQ(ierr);
3234b9ad928SBarry Smith         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
3244b9ad928SBarry Smith       }
3254b9ad928SBarry Smith     }
3264b9ad928SBarry Smith   } else {
32779a5c55eSBarry Smith     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCMG",((PetscObject)viewer)->type_name);
3284b9ad928SBarry Smith   }
3294b9ad928SBarry Smith   PetscFunctionReturn(0);
3304b9ad928SBarry Smith }
3314b9ad928SBarry Smith 
3324b9ad928SBarry Smith /*
3334b9ad928SBarry Smith     Calls setup for the KSP on each level
3344b9ad928SBarry Smith */
3354b9ad928SBarry Smith #undef __FUNCT__
3364b9ad928SBarry Smith #define __FUNCT__ "PCSetUp_MG"
3376849ba73SBarry Smith static PetscErrorCode PCSetUp_MG(PC pc)
3384b9ad928SBarry Smith {
3399dcbbd2bSBarry Smith   PC_MG                   **mg = (PC_MG**)pc->data;
340dfbe8321SBarry Smith   PetscErrorCode          ierr;
34179416396SBarry Smith   PetscInt                i,n = mg[0]->levels;
3424b9ad928SBarry Smith   PC                      cpc;
343906ed7ccSBarry Smith   PetscTruth              preonly,lu,redundant,cholesky,monitor = PETSC_FALSE,dump,opsset;
34423d894e5SBarry Smith   PetscViewerASCIIMonitor ascii;
34523d894e5SBarry Smith   PetscViewer             viewer = PETSC_NULL;
3464b9ad928SBarry Smith   MPI_Comm                comm;
347c2be2410SBarry Smith   Mat                     dA,dB;
348c2be2410SBarry Smith   MatStructure            uflag;
3490a6bb862SBarry Smith   Vec                     tvec;
3504b9ad928SBarry Smith 
3514b9ad928SBarry Smith   PetscFunctionBegin;
352852665d3SBarry Smith 
35343fb2f97SBarry Smith   /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
35443fb2f97SBarry Smith   /* so use those from global PC */
35543fb2f97SBarry Smith   /* Is this what we always want? What if user wants to keep old one? */
356906ed7ccSBarry Smith   ierr = KSPGetOperatorsSet(mg[n-1]->smoothd,PETSC_NULL,&opsset);CHKERRQ(ierr);
35743fb2f97SBarry Smith   ierr = KSPGetPC(mg[0]->smoothd,&cpc);CHKERRQ(ierr);
35843fb2f97SBarry Smith   if (!opsset || cpc->setupcalled == 2) {
359852665d3SBarry 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);
3601cfe3bddSBarry Smith     ierr = KSPSetOperators(mg[n-1]->smoothd,pc->mat,pc->pmat,pc->flag);CHKERRQ(ierr);
361852665d3SBarry Smith   }
362852665d3SBarry Smith 
363852665d3SBarry Smith   if (mg[0]->galerkin) {
364852665d3SBarry Smith     Mat B;
365852665d3SBarry Smith     mg[0]->galerkinused = PETSC_TRUE;
366852665d3SBarry Smith     /* currently only handle case where mat and pmat are the same on coarser levels */
367852665d3SBarry Smith     ierr = KSPGetOperators(mg[n-1]->smoothd,&dA,&dB,&uflag);CHKERRQ(ierr);
368852665d3SBarry Smith     if (!pc->setupcalled) {
369852665d3SBarry Smith       for (i=n-2; i>-1; i--) {
370852665d3SBarry Smith         ierr = MatPtAP(dB,mg[i+1]->interpolate,MAT_INITIAL_MATRIX,1.0,&B);CHKERRQ(ierr);
371852665d3SBarry Smith         ierr = KSPSetOperators(mg[i]->smoothd,B,B,uflag);CHKERRQ(ierr);
372906ed7ccSBarry Smith 	if (i != n-2) {ierr = PetscObjectDereference((PetscObject)dB);CHKERRQ(ierr);}
373852665d3SBarry Smith         dB   = B;
374852665d3SBarry Smith       }
375906ed7ccSBarry Smith       ierr = PetscObjectDereference((PetscObject)dB);CHKERRQ(ierr);
376852665d3SBarry Smith     } else {
377852665d3SBarry Smith       for (i=n-2; i>-1; i--) {
378906ed7ccSBarry Smith         ierr = KSPGetOperators(mg[i]->smoothd,PETSC_NULL,&B,PETSC_NULL);CHKERRQ(ierr);
379852665d3SBarry Smith         ierr = MatPtAP(dB,mg[i+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);CHKERRQ(ierr);
380852665d3SBarry Smith         ierr = KSPSetOperators(mg[i]->smoothd,B,B,uflag);CHKERRQ(ierr);
381852665d3SBarry Smith         dB   = B;
382852665d3SBarry Smith       }
383852665d3SBarry Smith     }
384852665d3SBarry Smith   }
385852665d3SBarry Smith 
386958c9bccSBarry Smith   if (!pc->setupcalled) {
3874b9ad928SBarry Smith     ierr = PetscOptionsHasName(0,"-pc_mg_monitor",&monitor);CHKERRQ(ierr);
3884b9ad928SBarry Smith 
389b03c7568SBarry Smith     for (i=0; i<n; i++) {
3904b9ad928SBarry Smith       if (monitor) {
3914b9ad928SBarry Smith         ierr = PetscObjectGetComm((PetscObject)mg[i]->smoothd,&comm);CHKERRQ(ierr);
39223d894e5SBarry Smith         ierr = PetscViewerASCIIMonitorCreate(comm,"stdout",n-i,&ascii);CHKERRQ(ierr);
39323d894e5SBarry Smith         ierr = KSPMonitorSet(mg[i]->smoothd,KSPMonitorDefault,ascii,(PetscErrorCode(*)(void*))PetscViewerASCIIMonitorDestroy);CHKERRQ(ierr);
3944b9ad928SBarry Smith       }
3954b9ad928SBarry Smith       ierr = KSPSetFromOptions(mg[i]->smoothd);CHKERRQ(ierr);
3964b9ad928SBarry Smith     }
397b03c7568SBarry Smith     for (i=1; i<n; i++) {
398a98fc643SBarry Smith       if (mg[i]->smoothu && (mg[i]->smoothu != mg[i]->smoothd)) {
3994b9ad928SBarry Smith         if (monitor) {
4004b9ad928SBarry Smith           ierr = PetscObjectGetComm((PetscObject)mg[i]->smoothu,&comm);CHKERRQ(ierr);
40123d894e5SBarry Smith           ierr = PetscViewerASCIIMonitorCreate(comm,"stdout",n-i,&ascii);CHKERRQ(ierr);
40223d894e5SBarry Smith           ierr = KSPMonitorSet(mg[i]->smoothu,KSPMonitorDefault,ascii,(PetscErrorCode(*)(void*))PetscViewerASCIIMonitorDestroy);CHKERRQ(ierr);
4034b9ad928SBarry Smith         }
4044b9ad928SBarry Smith         ierr = KSPSetFromOptions(mg[i]->smoothu);CHKERRQ(ierr);
4054b9ad928SBarry Smith       }
4064b9ad928SBarry Smith     }
407fccaa45eSBarry Smith     for (i=1; i<n; i++) {
4080cace4b0SBarry Smith       if (!mg[i]->residual) {
4090cace4b0SBarry Smith         Mat mat;
4100cace4b0SBarry Smith         ierr = KSPGetOperators(mg[i]->smoothd,PETSC_NULL,&mat,PETSC_NULL);CHKERRQ(ierr);
4110cace4b0SBarry Smith         ierr = PCMGSetResidual(pc,i,PCMGDefaultResidual,mat);CHKERRQ(ierr);
4120cace4b0SBarry Smith       }
413fccaa45eSBarry Smith       if (mg[i]->restrct && !mg[i]->interpolate) {
41497177400SBarry Smith         ierr = PCMGSetInterpolate(pc,i,mg[i]->restrct);CHKERRQ(ierr);
415fccaa45eSBarry Smith       }
416fccaa45eSBarry Smith       if (!mg[i]->restrct && mg[i]->interpolate) {
41797177400SBarry Smith         ierr = PCMGSetRestriction(pc,i,mg[i]->interpolate);CHKERRQ(ierr);
418fccaa45eSBarry Smith       }
419fccaa45eSBarry Smith #if defined(PETSC_USE_DEBUG)
420fccaa45eSBarry Smith       if (!mg[i]->restrct || !mg[i]->interpolate) {
421fccaa45eSBarry Smith         SETERRQ1(PETSC_ERR_ARG_WRONGSTATE,"Need to set restriction or interpolation on level %d",(int)i);
422fccaa45eSBarry Smith       }
423fccaa45eSBarry Smith #endif
424fccaa45eSBarry Smith     }
4250a6bb862SBarry Smith     for (i=0; i<n-1; i++) {
42637b0e6c0SBarry Smith       if (!mg[i]->b) {
427906ed7ccSBarry Smith         Vec *vec;
428906ed7ccSBarry Smith         ierr = KSPGetVecs(mg[i]->smoothd,1,&vec,0,PETSC_NULL);CHKERRQ(ierr);
429906ed7ccSBarry Smith         ierr = PCMGSetRhs(pc,i,*vec);CHKERRQ(ierr);
430906ed7ccSBarry Smith         ierr = PetscFree(vec);CHKERRQ(ierr);
43137b0e6c0SBarry Smith       }
4326ca4d86aSHong Zhang       if (!mg[i]->r && i) {
4330a6bb862SBarry Smith         ierr = VecDuplicate(mg[i]->b,&tvec);CHKERRQ(ierr);
43497177400SBarry Smith         ierr = PCMGSetR(pc,i,tvec);CHKERRQ(ierr);
4350a6bb862SBarry Smith         ierr = VecDestroy(tvec);CHKERRQ(ierr);
4360a6bb862SBarry Smith       }
4370a6bb862SBarry Smith       if (!mg[i]->x) {
4380a6bb862SBarry Smith         ierr = VecDuplicate(mg[i]->b,&tvec);CHKERRQ(ierr);
43997177400SBarry Smith         ierr = PCMGSetX(pc,i,tvec);CHKERRQ(ierr);
4400a6bb862SBarry Smith         ierr = VecDestroy(tvec);CHKERRQ(ierr);
4410a6bb862SBarry Smith       }
4420a6bb862SBarry Smith     }
4434b9ad928SBarry Smith   }
4444b9ad928SBarry Smith 
445c2be2410SBarry Smith 
4464b9ad928SBarry Smith   for (i=1; i<n; i++) {
447b03c7568SBarry Smith     if (mg[i]->smoothu == mg[i]->smoothd) {
448b03c7568SBarry Smith       /* if doing only down then initial guess is zero */
4494b9ad928SBarry Smith       ierr = KSPSetInitialGuessNonzero(mg[i]->smoothd,PETSC_TRUE);CHKERRQ(ierr);
450b03c7568SBarry Smith     }
4514b9ad928SBarry Smith     if (mg[i]->eventsetup) {ierr = PetscLogEventBegin(mg[i]->eventsetup,0,0,0,0);CHKERRQ(ierr);}
4524b9ad928SBarry Smith     ierr = KSPSetUp(mg[i]->smoothd);CHKERRQ(ierr);
4534b9ad928SBarry Smith     if (mg[i]->eventsetup) {ierr = PetscLogEventEnd(mg[i]->eventsetup,0,0,0,0);CHKERRQ(ierr);}
4544b9ad928SBarry Smith   }
455b03c7568SBarry Smith   for (i=1; i<n; i++) {
4564b9ad928SBarry Smith     if (mg[i]->smoothu && mg[i]->smoothu != mg[i]->smoothd) {
457906ed7ccSBarry Smith       Mat          downmat,downpmat;
45897f1f81fSBarry Smith       MatStructure matflag;
459906ed7ccSBarry Smith       PetscTruth   opsset;
46097f1f81fSBarry Smith 
46197f1f81fSBarry Smith       /* check if operators have been set for up, if not use down operators to set them */
462906ed7ccSBarry Smith       ierr = KSPGetOperatorsSet(mg[i]->smoothu,&opsset,PETSC_NULL);CHKERRQ(ierr);
463906ed7ccSBarry Smith       if (!opsset) {
464906ed7ccSBarry Smith         ierr = KSPGetOperators(mg[i]->smoothd,&downmat,&downpmat,&matflag);CHKERRQ(ierr);
46597f1f81fSBarry Smith         ierr = KSPSetOperators(mg[i]->smoothu,downmat,downpmat,matflag);CHKERRQ(ierr);
46697f1f81fSBarry Smith       }
46797f1f81fSBarry Smith 
4684b9ad928SBarry Smith       ierr = KSPSetInitialGuessNonzero(mg[i]->smoothu,PETSC_TRUE);CHKERRQ(ierr);
4694b9ad928SBarry Smith       if (mg[i]->eventsetup) {ierr = PetscLogEventBegin(mg[i]->eventsetup,0,0,0,0);CHKERRQ(ierr);}
4704b9ad928SBarry Smith       ierr = KSPSetUp(mg[i]->smoothu);CHKERRQ(ierr);
4714b9ad928SBarry Smith       if (mg[i]->eventsetup) {ierr = PetscLogEventEnd(mg[i]->eventsetup,0,0,0,0);CHKERRQ(ierr);}
4724b9ad928SBarry Smith     }
4734b9ad928SBarry Smith   }
4744b9ad928SBarry Smith 
4754b9ad928SBarry Smith   /*
4764b9ad928SBarry Smith       If coarse solver is not direct method then DO NOT USE preonly
4774b9ad928SBarry Smith   */
4784b9ad928SBarry Smith   ierr = PetscTypeCompare((PetscObject)mg[0]->smoothd,KSPPREONLY,&preonly);CHKERRQ(ierr);
4794b9ad928SBarry Smith   if (preonly) {
4804b9ad928SBarry Smith     ierr = PetscTypeCompare((PetscObject)cpc,PCLU,&lu);CHKERRQ(ierr);
4814b9ad928SBarry Smith     ierr = PetscTypeCompare((PetscObject)cpc,PCREDUNDANT,&redundant);CHKERRQ(ierr);
48268eff7e6SBarry Smith     ierr = PetscTypeCompare((PetscObject)cpc,PCCHOLESKY,&cholesky);CHKERRQ(ierr);
48368eff7e6SBarry Smith     if (!lu && !redundant && !cholesky) {
4844b9ad928SBarry Smith       ierr = KSPSetType(mg[0]->smoothd,KSPGMRES);CHKERRQ(ierr);
4854b9ad928SBarry Smith     }
4864b9ad928SBarry Smith   }
4874b9ad928SBarry Smith 
488958c9bccSBarry Smith   if (!pc->setupcalled) {
4894b9ad928SBarry Smith     if (monitor) {
4904b9ad928SBarry Smith       ierr = PetscObjectGetComm((PetscObject)mg[0]->smoothd,&comm);CHKERRQ(ierr);
49123d894e5SBarry Smith       ierr = PetscViewerASCIIMonitorCreate(comm,"stdout",n,&ascii);CHKERRQ(ierr);
49223d894e5SBarry Smith       ierr = KSPMonitorSet(mg[0]->smoothd,KSPMonitorDefault,ascii,(PetscErrorCode(*)(void*))PetscViewerASCIIMonitorDestroy);CHKERRQ(ierr);
4934b9ad928SBarry Smith     }
4944b9ad928SBarry Smith     ierr = KSPSetFromOptions(mg[0]->smoothd);CHKERRQ(ierr);
4954b9ad928SBarry Smith   }
4964b9ad928SBarry Smith 
4974b9ad928SBarry Smith   if (mg[0]->eventsetup) {ierr = PetscLogEventBegin(mg[0]->eventsetup,0,0,0,0);CHKERRQ(ierr);}
4984b9ad928SBarry Smith   ierr = KSPSetUp(mg[0]->smoothd);CHKERRQ(ierr);
4994b9ad928SBarry Smith   if (mg[0]->eventsetup) {ierr = PetscLogEventEnd(mg[0]->eventsetup,0,0,0,0);CHKERRQ(ierr);}
5004b9ad928SBarry Smith 
5014b9ad928SBarry Smith   /*
5026805f65bSBarry Smith      Dump the interpolation/restriction matrices plus the
5034b9ad928SBarry Smith    Jacobian/stiffness on each level. This allows Matlab users to
5046805f65bSBarry Smith    easily check if the Galerkin condition A_c = R A_f R^T is satisfied.
5056805f65bSBarry Smith 
5066805f65bSBarry Smith    Only support one or the other at the same time.
5076805f65bSBarry Smith   */
5086805f65bSBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER)
5094b9ad928SBarry Smith   ierr = PetscOptionsHasName(pc->prefix,"-pc_mg_dump_matlab",&dump);CHKERRQ(ierr);
5104b9ad928SBarry Smith   if (dump) {
5116805f65bSBarry Smith     viewer = PETSC_VIEWER_SOCKET_(pc->comm);
5124b9ad928SBarry Smith   }
513c45a1595SBarry Smith #endif
514c2be2410SBarry Smith   ierr = PetscOptionsHasName(pc->prefix,"-pc_mg_dump_binary",&dump);CHKERRQ(ierr);
515c2be2410SBarry Smith   if (dump) {
5166805f65bSBarry Smith     viewer = PETSC_VIEWER_BINARY_(pc->comm);
5176805f65bSBarry Smith   }
5186805f65bSBarry Smith 
5196805f65bSBarry Smith   if (viewer) {
520c2be2410SBarry Smith     for (i=1; i<n; i++) {
5216805f65bSBarry Smith       ierr = MatView(mg[i]->restrct,viewer);CHKERRQ(ierr);
522c2be2410SBarry Smith     }
523c2be2410SBarry Smith     for (i=0; i<n; i++) {
524c2be2410SBarry Smith       ierr = KSPGetPC(mg[i]->smoothd,&pc);CHKERRQ(ierr);
5256805f65bSBarry Smith       ierr = MatView(pc->mat,viewer);CHKERRQ(ierr);
526c2be2410SBarry Smith     }
527c2be2410SBarry Smith   }
5284b9ad928SBarry Smith   PetscFunctionReturn(0);
5294b9ad928SBarry Smith }
5304b9ad928SBarry Smith 
5314b9ad928SBarry Smith /* -------------------------------------------------------------------------------------*/
5324b9ad928SBarry Smith 
5334b9ad928SBarry Smith #undef __FUNCT__
5349dcbbd2bSBarry Smith #define __FUNCT__ "PCMGSetLevels"
5354b9ad928SBarry Smith /*@C
53697177400SBarry Smith    PCMGSetLevels - Sets the number of levels to use with MG.
5374b9ad928SBarry Smith    Must be called before any other MG routine.
5384b9ad928SBarry Smith 
5394b9ad928SBarry Smith    Collective on PC
5404b9ad928SBarry Smith 
5414b9ad928SBarry Smith    Input Parameters:
5424b9ad928SBarry Smith +  pc - the preconditioner context
5434b9ad928SBarry Smith .  levels - the number of levels
5444b9ad928SBarry Smith -  comms - optional communicators for each level; this is to allow solving the coarser problems
5454b9ad928SBarry Smith            on smaller sets of processors. Use PETSC_NULL_OBJECT for default in Fortran
5464b9ad928SBarry Smith 
5474b9ad928SBarry Smith    Level: intermediate
5484b9ad928SBarry Smith 
5494b9ad928SBarry Smith    Notes:
5504b9ad928SBarry Smith      If the number of levels is one then the multigrid uses the -mg_levels prefix
5514b9ad928SBarry Smith   for setting the level options rather than the -mg_coarse prefix.
5524b9ad928SBarry Smith 
5534b9ad928SBarry Smith .keywords: MG, set, levels, multigrid
5544b9ad928SBarry Smith 
55597177400SBarry Smith .seealso: PCMGSetType(), PCMGGetLevels()
5564b9ad928SBarry Smith @*/
55797177400SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetLevels(PC pc,PetscInt levels,MPI_Comm *comms)
5584b9ad928SBarry Smith {
559dfbe8321SBarry Smith   PetscErrorCode ierr;
560ada7143aSSatish Balay   PC_MG          **mg=0;
5614b9ad928SBarry Smith 
5624b9ad928SBarry Smith   PetscFunctionBegin;
5634482741eSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
5644b9ad928SBarry Smith 
5654b9ad928SBarry Smith   if (pc->data) {
5661302d50aSBarry Smith     SETERRQ(PETSC_ERR_ORDER,"Number levels already set for MG\n\
56797177400SBarry Smith     make sure that you call PCMGSetLevels() before KSPSetFromOptions()");
5684b9ad928SBarry Smith   }
5699dcbbd2bSBarry Smith   ierr                     = PCMGCreate_Private(pc->comm,levels,pc,comms,&mg);CHKERRQ(ierr);
5709dcbbd2bSBarry Smith   mg[0]->am                = PC_MG_MULTIPLICATIVE;
5714b9ad928SBarry Smith   pc->data                 = (void*)mg;
5724b9ad928SBarry Smith   pc->ops->applyrichardson = PCApplyRichardson_MG;
5734b9ad928SBarry Smith   PetscFunctionReturn(0);
5744b9ad928SBarry Smith }
5754b9ad928SBarry Smith 
5764b9ad928SBarry Smith #undef __FUNCT__
5779dcbbd2bSBarry Smith #define __FUNCT__ "PCMGGetLevels"
5784b9ad928SBarry Smith /*@
57997177400SBarry Smith    PCMGGetLevels - Gets the number of levels to use with MG.
5804b9ad928SBarry Smith 
5814b9ad928SBarry Smith    Not Collective
5824b9ad928SBarry Smith 
5834b9ad928SBarry Smith    Input Parameter:
5844b9ad928SBarry Smith .  pc - the preconditioner context
5854b9ad928SBarry Smith 
5864b9ad928SBarry Smith    Output parameter:
5874b9ad928SBarry Smith .  levels - the number of levels
5884b9ad928SBarry Smith 
5894b9ad928SBarry Smith    Level: advanced
5904b9ad928SBarry Smith 
5914b9ad928SBarry Smith .keywords: MG, get, levels, multigrid
5924b9ad928SBarry Smith 
59397177400SBarry Smith .seealso: PCMGSetLevels()
5944b9ad928SBarry Smith @*/
59597177400SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGGetLevels(PC pc,PetscInt *levels)
5964b9ad928SBarry Smith {
5979dcbbd2bSBarry Smith   PC_MG  **mg;
5984b9ad928SBarry Smith 
5994b9ad928SBarry Smith   PetscFunctionBegin;
6004482741eSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
6014482741eSBarry Smith   PetscValidIntPointer(levels,2);
6024b9ad928SBarry Smith 
6039dcbbd2bSBarry Smith   mg      = (PC_MG**)pc->data;
6044b9ad928SBarry Smith   *levels = mg[0]->levels;
6054b9ad928SBarry Smith   PetscFunctionReturn(0);
6064b9ad928SBarry Smith }
6074b9ad928SBarry Smith 
6084b9ad928SBarry Smith #undef __FUNCT__
6099dcbbd2bSBarry Smith #define __FUNCT__ "PCMGSetType"
6104b9ad928SBarry Smith /*@
61197177400SBarry Smith    PCMGSetType - Determines the form of multigrid to use:
6124b9ad928SBarry Smith    multiplicative, additive, full, or the Kaskade algorithm.
6134b9ad928SBarry Smith 
6144b9ad928SBarry Smith    Collective on PC
6154b9ad928SBarry Smith 
6164b9ad928SBarry Smith    Input Parameters:
6174b9ad928SBarry Smith +  pc - the preconditioner context
6189dcbbd2bSBarry Smith -  form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,
6199dcbbd2bSBarry Smith    PC_MG_FULL, PC_MG_KASKADE
6204b9ad928SBarry Smith 
6214b9ad928SBarry Smith    Options Database Key:
6224b9ad928SBarry Smith .  -pc_mg_type <form> - Sets <form>, one of multiplicative,
6234b9ad928SBarry Smith    additive, full, kaskade
6244b9ad928SBarry Smith 
6254b9ad928SBarry Smith    Level: advanced
6264b9ad928SBarry Smith 
6274b9ad928SBarry Smith .keywords: MG, set, method, multiplicative, additive, full, Kaskade, multigrid
6284b9ad928SBarry Smith 
62997177400SBarry Smith .seealso: PCMGSetLevels()
6304b9ad928SBarry Smith @*/
6319dcbbd2bSBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetType(PC pc,PCMGType form)
6324b9ad928SBarry Smith {
6339dcbbd2bSBarry Smith   PC_MG **mg;
6344b9ad928SBarry Smith 
6354b9ad928SBarry Smith   PetscFunctionBegin;
6364482741eSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
6379dcbbd2bSBarry Smith   mg = (PC_MG**)pc->data;
6384b9ad928SBarry Smith 
6394b9ad928SBarry Smith   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
6404b9ad928SBarry Smith   mg[0]->am = form;
6419dcbbd2bSBarry Smith   if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
6424b9ad928SBarry Smith   else pc->ops->applyrichardson = 0;
6434b9ad928SBarry Smith   PetscFunctionReturn(0);
6444b9ad928SBarry Smith }
6454b9ad928SBarry Smith 
6464b9ad928SBarry Smith #undef __FUNCT__
647*0d353602SBarry Smith #define __FUNCT__ "PCMGSetCycleType"
6484b9ad928SBarry Smith /*@
649*0d353602SBarry Smith    PCMGSetCycleType - Sets the type cycles to use.  Use PCMGSetCycleTypeOnLevel() for more
6504b9ad928SBarry Smith    complicated cycling.
6514b9ad928SBarry Smith 
6524b9ad928SBarry Smith    Collective on PC
6534b9ad928SBarry Smith 
6544b9ad928SBarry Smith    Input Parameters:
655c2be2410SBarry Smith +  pc - the multigrid context
656*0d353602SBarry Smith -  PC_MG_CYCLE_V or PC_MG_CYCLE_W
6574b9ad928SBarry Smith 
6584b9ad928SBarry Smith    Options Database Key:
659*0d353602SBarry Smith $  -pc_mg_cycle_type v or w
6604b9ad928SBarry Smith 
6614b9ad928SBarry Smith    Level: advanced
6624b9ad928SBarry Smith 
6634b9ad928SBarry Smith .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
6644b9ad928SBarry Smith 
665*0d353602SBarry Smith .seealso: PCMGSetCycleTypeOnLevel()
6664b9ad928SBarry Smith @*/
667*0d353602SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetCycleType(PC pc,PCMGCycleType n)
6684b9ad928SBarry Smith {
6699dcbbd2bSBarry Smith   PC_MG    **mg;
67079416396SBarry Smith   PetscInt i,levels;
6714b9ad928SBarry Smith 
6724b9ad928SBarry Smith   PetscFunctionBegin;
6734482741eSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
6749dcbbd2bSBarry Smith   mg     = (PC_MG**)pc->data;
6754b9ad928SBarry Smith   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
6764b9ad928SBarry Smith   levels = mg[0]->levels;
6774b9ad928SBarry Smith 
6784b9ad928SBarry Smith   for (i=0; i<levels; i++) {
6794b9ad928SBarry Smith     mg[i]->cycles  = n;
6804b9ad928SBarry Smith   }
6814b9ad928SBarry Smith   PetscFunctionReturn(0);
6824b9ad928SBarry Smith }
6834b9ad928SBarry Smith 
6844b9ad928SBarry Smith #undef __FUNCT__
6859dcbbd2bSBarry Smith #define __FUNCT__ "PCMGSetGalerkin"
686c2be2410SBarry Smith /*@
68797177400SBarry Smith    PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
688c2be2410SBarry Smith       finest grid via the Galerkin process: A_i-1 = r_i * A_i * r_i^t
689c2be2410SBarry Smith 
690c2be2410SBarry Smith    Collective on PC
691c2be2410SBarry Smith 
692c2be2410SBarry Smith    Input Parameters:
6933fc8bf9cSBarry Smith .  pc - the multigrid context
694c2be2410SBarry Smith 
695c2be2410SBarry Smith    Options Database Key:
696c2be2410SBarry Smith $  -pc_mg_galerkin
697c2be2410SBarry Smith 
698c2be2410SBarry Smith    Level: intermediate
699c2be2410SBarry Smith 
700c2be2410SBarry Smith .keywords: MG, set, Galerkin
701c2be2410SBarry Smith 
7023fc8bf9cSBarry Smith .seealso: PCMGGetGalerkin()
7033fc8bf9cSBarry Smith 
704c2be2410SBarry Smith @*/
70597177400SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetGalerkin(PC pc)
706c2be2410SBarry Smith {
7079dcbbd2bSBarry Smith   PC_MG    **mg;
708c2be2410SBarry Smith   PetscInt i,levels;
709c2be2410SBarry Smith 
710c2be2410SBarry Smith   PetscFunctionBegin;
711c2be2410SBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
7129dcbbd2bSBarry Smith   mg     = (PC_MG**)pc->data;
713c2be2410SBarry Smith   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
714c2be2410SBarry Smith   levels = mg[0]->levels;
715c2be2410SBarry Smith 
716c2be2410SBarry Smith   for (i=0; i<levels; i++) {
717c2be2410SBarry Smith     mg[i]->galerkin = PETSC_TRUE;
718c2be2410SBarry Smith   }
719c2be2410SBarry Smith   PetscFunctionReturn(0);
720c2be2410SBarry Smith }
721c2be2410SBarry Smith 
722c2be2410SBarry Smith #undef __FUNCT__
7233fc8bf9cSBarry Smith #define __FUNCT__ "PCMGGetGalerkin"
7243fc8bf9cSBarry Smith /*@
7253fc8bf9cSBarry Smith    PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e.
7263fc8bf9cSBarry Smith       A_i-1 = r_i * A_i * r_i^t
7273fc8bf9cSBarry Smith 
7283fc8bf9cSBarry Smith    Not Collective
7293fc8bf9cSBarry Smith 
7303fc8bf9cSBarry Smith    Input Parameter:
7313fc8bf9cSBarry Smith .  pc - the multigrid context
7323fc8bf9cSBarry Smith 
7333fc8bf9cSBarry Smith    Output Parameter:
7343fc8bf9cSBarry Smith .  gelerkin - PETSC_TRUE or PETSC_FALSE
7353fc8bf9cSBarry Smith 
7363fc8bf9cSBarry Smith    Options Database Key:
7373fc8bf9cSBarry Smith $  -pc_mg_galerkin
7383fc8bf9cSBarry Smith 
7393fc8bf9cSBarry Smith    Level: intermediate
7403fc8bf9cSBarry Smith 
7413fc8bf9cSBarry Smith .keywords: MG, set, Galerkin
7423fc8bf9cSBarry Smith 
7433fc8bf9cSBarry Smith .seealso: PCMGSetGalerkin()
7443fc8bf9cSBarry Smith 
7453fc8bf9cSBarry Smith @*/
7463fc8bf9cSBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGGetGalerkin(PC pc,PetscTruth *galerkin)
7473fc8bf9cSBarry Smith {
7483fc8bf9cSBarry Smith   PC_MG    **mg;
7493fc8bf9cSBarry Smith 
7503fc8bf9cSBarry Smith   PetscFunctionBegin;
7513fc8bf9cSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
7523fc8bf9cSBarry Smith   mg     = (PC_MG**)pc->data;
7533fc8bf9cSBarry Smith   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
7543fc8bf9cSBarry Smith   *galerkin = mg[0]->galerkin;
7553fc8bf9cSBarry Smith   PetscFunctionReturn(0);
7563fc8bf9cSBarry Smith }
7573fc8bf9cSBarry Smith 
7583fc8bf9cSBarry Smith #undef __FUNCT__
7599dcbbd2bSBarry Smith #define __FUNCT__ "PCMGSetNumberSmoothDown"
7604b9ad928SBarry Smith /*@
76197177400SBarry Smith    PCMGSetNumberSmoothDown - Sets the number of pre-smoothing steps to
76297177400SBarry Smith    use on all levels. Use PCMGGetSmootherDown() to set different
7634b9ad928SBarry Smith    pre-smoothing steps on different levels.
7644b9ad928SBarry Smith 
7654b9ad928SBarry Smith    Collective on PC
7664b9ad928SBarry Smith 
7674b9ad928SBarry Smith    Input Parameters:
7684b9ad928SBarry Smith +  mg - the multigrid context
7694b9ad928SBarry Smith -  n - the number of smoothing steps
7704b9ad928SBarry Smith 
7714b9ad928SBarry Smith    Options Database Key:
7724b9ad928SBarry Smith .  -pc_mg_smoothdown <n> - Sets number of pre-smoothing steps
7734b9ad928SBarry Smith 
7744b9ad928SBarry Smith    Level: advanced
7754b9ad928SBarry Smith 
7764b9ad928SBarry Smith .keywords: MG, smooth, down, pre-smoothing, steps, multigrid
7774b9ad928SBarry Smith 
77897177400SBarry Smith .seealso: PCMGSetNumberSmoothUp()
7794b9ad928SBarry Smith @*/
78097177400SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetNumberSmoothDown(PC pc,PetscInt n)
7814b9ad928SBarry Smith {
7829dcbbd2bSBarry Smith   PC_MG          **mg;
7836849ba73SBarry Smith   PetscErrorCode ierr;
78479416396SBarry Smith   PetscInt       i,levels;
7854b9ad928SBarry Smith 
7864b9ad928SBarry Smith   PetscFunctionBegin;
7874482741eSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
7889dcbbd2bSBarry Smith   mg     = (PC_MG**)pc->data;
7894b9ad928SBarry Smith   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
7904b9ad928SBarry Smith   levels = mg[0]->levels;
7914b9ad928SBarry Smith 
792b05257ddSBarry Smith   for (i=1; i<levels; i++) {
7934b9ad928SBarry Smith     /* make sure smoother up and down are different */
79497177400SBarry Smith     ierr = PCMGGetSmootherUp(pc,i,PETSC_NULL);CHKERRQ(ierr);
7954b9ad928SBarry Smith     ierr = KSPSetTolerances(mg[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr);
7964b9ad928SBarry Smith     mg[i]->default_smoothd = n;
7974b9ad928SBarry Smith   }
7984b9ad928SBarry Smith   PetscFunctionReturn(0);
7994b9ad928SBarry Smith }
8004b9ad928SBarry Smith 
8014b9ad928SBarry Smith #undef __FUNCT__
8029dcbbd2bSBarry Smith #define __FUNCT__ "PCMGSetNumberSmoothUp"
8034b9ad928SBarry Smith /*@
80497177400SBarry Smith    PCMGSetNumberSmoothUp - Sets the number of post-smoothing steps to use
80597177400SBarry Smith    on all levels. Use PCMGGetSmootherUp() to set different numbers of
8064b9ad928SBarry Smith    post-smoothing steps on different levels.
8074b9ad928SBarry Smith 
8084b9ad928SBarry Smith    Collective on PC
8094b9ad928SBarry Smith 
8104b9ad928SBarry Smith    Input Parameters:
8114b9ad928SBarry Smith +  mg - the multigrid context
8124b9ad928SBarry Smith -  n - the number of smoothing steps
8134b9ad928SBarry Smith 
8144b9ad928SBarry Smith    Options Database Key:
8154b9ad928SBarry Smith .  -pc_mg_smoothup <n> - Sets number of post-smoothing steps
8164b9ad928SBarry Smith 
8174b9ad928SBarry Smith    Level: advanced
8184b9ad928SBarry Smith 
8194b9ad928SBarry Smith    Note: this does not set a value on the coarsest grid, since we assume that
820a8c7a070SBarry Smith     there is no separate smooth up on the coarsest grid.
8214b9ad928SBarry Smith 
8224b9ad928SBarry Smith .keywords: MG, smooth, up, post-smoothing, steps, multigrid
8234b9ad928SBarry Smith 
82497177400SBarry Smith .seealso: PCMGSetNumberSmoothDown()
8254b9ad928SBarry Smith @*/
82697177400SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCMGSetNumberSmoothUp(PC pc,PetscInt n)
8274b9ad928SBarry Smith {
8289dcbbd2bSBarry Smith   PC_MG          **mg;
8296849ba73SBarry Smith   PetscErrorCode ierr;
83079416396SBarry Smith   PetscInt       i,levels;
8314b9ad928SBarry Smith 
8324b9ad928SBarry Smith   PetscFunctionBegin;
8334482741eSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
8349dcbbd2bSBarry Smith   mg     = (PC_MG**)pc->data;
8354b9ad928SBarry Smith   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
8364b9ad928SBarry Smith   levels = mg[0]->levels;
8374b9ad928SBarry Smith 
8384b9ad928SBarry Smith   for (i=1; i<levels; i++) {
8394b9ad928SBarry Smith     /* make sure smoother up and down are different */
84097177400SBarry Smith     ierr = PCMGGetSmootherUp(pc,i,PETSC_NULL);CHKERRQ(ierr);
8414b9ad928SBarry Smith     ierr = KSPSetTolerances(mg[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr);
8424b9ad928SBarry Smith     mg[i]->default_smoothu = n;
8434b9ad928SBarry Smith   }
8444b9ad928SBarry Smith   PetscFunctionReturn(0);
8454b9ad928SBarry Smith }
8464b9ad928SBarry Smith 
8474b9ad928SBarry Smith /* ----------------------------------------------------------------------------------------*/
8484b9ad928SBarry Smith 
8493b09bd56SBarry Smith /*MC
850ccb205f8SBarry Smith    PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional
8513b09bd56SBarry Smith     information about the coarser grid matrices and restriction/interpolation operators.
8523b09bd56SBarry Smith 
8533b09bd56SBarry Smith    Options Database Keys:
8543b09bd56SBarry Smith +  -pc_mg_levels <nlevels> - number of levels including finest
855*0d353602SBarry Smith .  -pc_mg_cycles v or w
85679416396SBarry Smith .  -pc_mg_smoothup <n> - number of smoothing steps after interpolation
8573b09bd56SBarry Smith .  -pc_mg_smoothdown <n> - number of smoothing steps before applying restriction operator
8583b09bd56SBarry Smith .  -pc_mg_type <additive,multiplicative,full,cascade> - multiplicative is the default
8593b09bd56SBarry Smith .  -pc_mg_log - log information about time spent on each level of the solver
8603b09bd56SBarry Smith .  -pc_mg_monitor - print information on the multigrid convergence
86168eff7e6SBarry Smith .  -pc_mg_galerkin - use Galerkin process to compute coarser operators
8623b09bd56SBarry Smith -  -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices
8633b09bd56SBarry Smith                         to the Socket viewer for reading from Matlab.
8643b09bd56SBarry Smith 
8653b09bd56SBarry Smith    Notes:
8663b09bd56SBarry Smith 
8673b09bd56SBarry Smith    Level: intermediate
8683b09bd56SBarry Smith 
8693b09bd56SBarry Smith    Concepts: multigrid
8703b09bd56SBarry Smith 
8713b09bd56SBarry Smith .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType,
872*0d353602SBarry Smith            PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), PCMGSetCycleType(), PCMGSetNumberSmoothDown(),
87397177400SBarry Smith            PCMGSetNumberSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(),
87497177400SBarry Smith            PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(),
875*0d353602SBarry Smith            PCMGSetCycleTypeOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR()
8763b09bd56SBarry Smith M*/
8773b09bd56SBarry Smith 
8784b9ad928SBarry Smith EXTERN_C_BEGIN
8794b9ad928SBarry Smith #undef __FUNCT__
8804b9ad928SBarry Smith #define __FUNCT__ "PCCreate_MG"
881dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_MG(PC pc)
8824b9ad928SBarry Smith {
8834b9ad928SBarry Smith   PetscFunctionBegin;
8844b9ad928SBarry Smith   pc->ops->apply          = PCApply_MG;
8854b9ad928SBarry Smith   pc->ops->setup          = PCSetUp_MG;
8864b9ad928SBarry Smith   pc->ops->destroy        = PCDestroy_MG;
8874b9ad928SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_MG;
8884b9ad928SBarry Smith   pc->ops->view           = PCView_MG;
8894b9ad928SBarry Smith 
8904b9ad928SBarry Smith   pc->data                = (void*)0;
8914b9ad928SBarry Smith   PetscFunctionReturn(0);
8924b9ad928SBarry Smith }
8934b9ad928SBarry Smith EXTERN_C_END
894