xref: /petsc/src/ksp/pc/impls/mg/mg.c (revision efd4aadf157bf1ba2d80c2be092fcf4247860003)
1dba47a55SKris Buschelman 
24b9ad928SBarry Smith /*
34b9ad928SBarry Smith     Defines the multigrid preconditioner interface.
44b9ad928SBarry Smith */
5af0996ceSBarry Smith #include <petsc/private/pcmgimpl.h>                    /*I "petscksp.h" I*/
61e25c274SJed Brown #include <petscdm.h>
74b9ad928SBarry Smith 
831567311SBarry Smith PetscErrorCode PCMGMCycle_Private(PC pc,PC_MG_Levels **mglevelsin,PCRichardsonConvergedReason *reason)
94b9ad928SBarry Smith {
1031567311SBarry Smith   PC_MG          *mg = (PC_MG*)pc->data;
1131567311SBarry Smith   PC_MG_Levels   *mgc,*mglevels = *mglevelsin;
126849ba73SBarry Smith   PetscErrorCode ierr;
1331567311SBarry Smith   PetscInt       cycles = (mglevels->level == 1) ? 1 : (PetscInt) mglevels->cycles;
14a0808db4SHong Zhang   PC             subpc;
15a0808db4SHong Zhang   PCFailedReason pcreason;
164b9ad928SBarry Smith 
174b9ad928SBarry Smith   PetscFunctionBegin;
1863e6d426SJed Brown   if (mglevels->eventsmoothsolve) {ierr = PetscLogEventBegin(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
1931567311SBarry Smith   ierr = KSPSolve(mglevels->smoothd,mglevels->b,mglevels->x);CHKERRQ(ierr);  /* pre-smooth */
20a0808db4SHong Zhang   ierr = KSPGetPC(mglevels->smoothd,&subpc);CHKERRQ(ierr);
21a0808db4SHong Zhang   ierr = PCGetSetUpFailedReason(subpc,&pcreason);CHKERRQ(ierr);
22a0808db4SHong Zhang   if (pcreason) {
23a0808db4SHong Zhang     pc->failedreason = PC_SUBPC_ERROR;
24a0808db4SHong Zhang   }
2563e6d426SJed Brown   if (mglevels->eventsmoothsolve) {ierr = PetscLogEventEnd(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
2631567311SBarry Smith   if (mglevels->level) {  /* not the coarsest grid */
2763e6d426SJed Brown     if (mglevels->eventresidual) {ierr = PetscLogEventBegin(mglevels->eventresidual,0,0,0,0);CHKERRQ(ierr);}
2831567311SBarry Smith     ierr = (*mglevels->residual)(mglevels->A,mglevels->b,mglevels->x,mglevels->r);CHKERRQ(ierr);
2963e6d426SJed Brown     if (mglevels->eventresidual) {ierr = PetscLogEventEnd(mglevels->eventresidual,0,0,0,0);CHKERRQ(ierr);}
304b9ad928SBarry Smith 
314b9ad928SBarry Smith     /* if on finest level and have convergence criteria set */
3231567311SBarry Smith     if (mglevels->level == mglevels->levels-1 && mg->ttol && reason) {
334b9ad928SBarry Smith       PetscReal rnorm;
3431567311SBarry Smith       ierr = VecNorm(mglevels->r,NORM_2,&rnorm);CHKERRQ(ierr);
354b9ad928SBarry Smith       if (rnorm <= mg->ttol) {
3670441072SBarry Smith         if (rnorm < mg->abstol) {
374d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_ATOL;
3857622a8eSBarry Smith           ierr    = PetscInfo2(pc,"Linear solver has converged. Residual norm %g is less than absolute tolerance %g\n",(double)rnorm,(double)mg->abstol);CHKERRQ(ierr);
394b9ad928SBarry Smith         } else {
404d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_RTOL;
4157622a8eSBarry Smith           ierr    = PetscInfo2(pc,"Linear solver has converged. Residual norm %g is less than relative tolerance times initial residual norm %g\n",(double)rnorm,(double)mg->ttol);CHKERRQ(ierr);
424b9ad928SBarry Smith         }
434b9ad928SBarry Smith         PetscFunctionReturn(0);
444b9ad928SBarry Smith       }
454b9ad928SBarry Smith     }
464b9ad928SBarry Smith 
4731567311SBarry Smith     mgc = *(mglevelsin - 1);
4863e6d426SJed Brown     if (mglevels->eventinterprestrict) {ierr = PetscLogEventBegin(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
4931567311SBarry Smith     ierr = MatRestrict(mglevels->restrct,mglevels->r,mgc->b);CHKERRQ(ierr);
5063e6d426SJed Brown     if (mglevels->eventinterprestrict) {ierr = PetscLogEventEnd(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
51efb30889SBarry Smith     ierr = VecSet(mgc->x,0.0);CHKERRQ(ierr);
524b9ad928SBarry Smith     while (cycles--) {
5331567311SBarry Smith       ierr = PCMGMCycle_Private(pc,mglevelsin-1,reason);CHKERRQ(ierr);
544b9ad928SBarry Smith     }
5563e6d426SJed Brown     if (mglevels->eventinterprestrict) {ierr = PetscLogEventBegin(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
5631567311SBarry Smith     ierr = MatInterpolateAdd(mglevels->interpolate,mgc->x,mglevels->x,mglevels->x);CHKERRQ(ierr);
5763e6d426SJed Brown     if (mglevels->eventinterprestrict) {ierr = PetscLogEventEnd(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
5863e6d426SJed Brown     if (mglevels->eventsmoothsolve) {ierr = PetscLogEventBegin(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
5931567311SBarry Smith     ierr = KSPSolve(mglevels->smoothu,mglevels->b,mglevels->x);CHKERRQ(ierr);    /* post smooth */
6063e6d426SJed Brown     if (mglevels->eventsmoothsolve) {ierr = PetscLogEventEnd(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
614b9ad928SBarry Smith   }
624b9ad928SBarry Smith   PetscFunctionReturn(0);
634b9ad928SBarry Smith }
644b9ad928SBarry Smith 
65ace3abfcSBarry Smith static PetscErrorCode PCApplyRichardson_MG(PC pc,Vec b,Vec x,Vec w,PetscReal rtol,PetscReal abstol, PetscReal dtol,PetscInt its,PetscBool zeroguess,PetscInt *outits,PCRichardsonConvergedReason *reason)
664b9ad928SBarry Smith {
67f3fbd535SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
68f3fbd535SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
69dfbe8321SBarry Smith   PetscErrorCode ierr;
70f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels,i;
714b9ad928SBarry Smith 
724b9ad928SBarry Smith   PetscFunctionBegin;
73a762d673SBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
74a762d673SBarry Smith   for (i=0; i<levels; i++) {
75a762d673SBarry Smith     if (!mglevels[i]->A) {
76a762d673SBarry Smith       ierr = KSPGetOperators(mglevels[i]->smoothu,&mglevels[i]->A,NULL);CHKERRQ(ierr);
77a762d673SBarry Smith       ierr = PetscObjectReference((PetscObject)mglevels[i]->A);CHKERRQ(ierr);
78a762d673SBarry Smith     }
79a762d673SBarry Smith   }
80f3fbd535SBarry Smith   mglevels[levels-1]->b = b;
81f3fbd535SBarry Smith   mglevels[levels-1]->x = x;
824b9ad928SBarry Smith 
8331567311SBarry Smith   mg->rtol   = rtol;
8431567311SBarry Smith   mg->abstol = abstol;
8531567311SBarry Smith   mg->dtol   = dtol;
864b9ad928SBarry Smith   if (rtol) {
874b9ad928SBarry Smith     /* compute initial residual norm for relative convergence test */
884b9ad928SBarry Smith     PetscReal rnorm;
897319c654SBarry Smith     if (zeroguess) {
907319c654SBarry Smith       ierr = VecNorm(b,NORM_2,&rnorm);CHKERRQ(ierr);
917319c654SBarry Smith     } else {
92f3fbd535SBarry Smith       ierr = (*mglevels[levels-1]->residual)(mglevels[levels-1]->A,b,x,w);CHKERRQ(ierr);
934b9ad928SBarry Smith       ierr = VecNorm(w,NORM_2,&rnorm);CHKERRQ(ierr);
947319c654SBarry Smith     }
9531567311SBarry Smith     mg->ttol = PetscMax(rtol*rnorm,abstol);
962fa5cd67SKarl Rupp   } else if (abstol) mg->ttol = abstol;
972fa5cd67SKarl Rupp   else mg->ttol = 0.0;
984b9ad928SBarry Smith 
994d0a8057SBarry Smith   /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't
100336babb1SJed Brown      stop prematurely due to small residual */
1014d0a8057SBarry Smith   for (i=1; i<levels; i++) {
102f3fbd535SBarry Smith     ierr = KSPSetTolerances(mglevels[i]->smoothu,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
103f3fbd535SBarry Smith     if (mglevels[i]->smoothu != mglevels[i]->smoothd) {
104f3fbd535SBarry Smith       ierr = KSPSetTolerances(mglevels[i]->smoothd,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
1054b9ad928SBarry Smith     }
1064d0a8057SBarry Smith   }
1074d0a8057SBarry Smith 
1084d0a8057SBarry Smith   *reason = (PCRichardsonConvergedReason)0;
1094d0a8057SBarry Smith   for (i=0; i<its; i++) {
110f3fbd535SBarry Smith     ierr = PCMGMCycle_Private(pc,mglevels+levels-1,reason);CHKERRQ(ierr);
1114d0a8057SBarry Smith     if (*reason) break;
1124d0a8057SBarry Smith   }
1134d0a8057SBarry Smith   if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS;
1144d0a8057SBarry Smith   *outits = i;
1154b9ad928SBarry Smith   PetscFunctionReturn(0);
1164b9ad928SBarry Smith }
1174b9ad928SBarry Smith 
1183aeaf226SBarry Smith PetscErrorCode PCReset_MG(PC pc)
1193aeaf226SBarry Smith {
1203aeaf226SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
1213aeaf226SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
1223aeaf226SBarry Smith   PetscErrorCode ierr;
1233aeaf226SBarry Smith   PetscInt       i,n;
1243aeaf226SBarry Smith 
1253aeaf226SBarry Smith   PetscFunctionBegin;
1263aeaf226SBarry Smith   if (mglevels) {
1273aeaf226SBarry Smith     n = mglevels[0]->levels;
1283aeaf226SBarry Smith     for (i=0; i<n-1; i++) {
1293aeaf226SBarry Smith       ierr = VecDestroy(&mglevels[i+1]->r);CHKERRQ(ierr);
1303aeaf226SBarry Smith       ierr = VecDestroy(&mglevels[i]->b);CHKERRQ(ierr);
1313aeaf226SBarry Smith       ierr = VecDestroy(&mglevels[i]->x);CHKERRQ(ierr);
1323aeaf226SBarry Smith       ierr = MatDestroy(&mglevels[i+1]->restrct);CHKERRQ(ierr);
1333aeaf226SBarry Smith       ierr = MatDestroy(&mglevels[i+1]->interpolate);CHKERRQ(ierr);
13473250ac0SBarry Smith       ierr = VecDestroy(&mglevels[i+1]->rscale);CHKERRQ(ierr);
1353aeaf226SBarry Smith     }
1363aeaf226SBarry Smith 
1373aeaf226SBarry Smith     for (i=0; i<n; i++) {
1383aeaf226SBarry Smith       ierr = MatDestroy(&mglevels[i]->A);CHKERRQ(ierr);
1393aeaf226SBarry Smith       if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
1403aeaf226SBarry Smith         ierr = KSPReset(mglevels[i]->smoothd);CHKERRQ(ierr);
1413aeaf226SBarry Smith       }
1423aeaf226SBarry Smith       ierr = KSPReset(mglevels[i]->smoothu);CHKERRQ(ierr);
1433aeaf226SBarry Smith     }
1443aeaf226SBarry Smith   }
1453aeaf226SBarry Smith   PetscFunctionReturn(0);
1463aeaf226SBarry Smith }
1473aeaf226SBarry Smith 
1484b9ad928SBarry Smith /*@C
14997177400SBarry Smith    PCMGSetLevels - Sets the number of levels to use with MG.
1504b9ad928SBarry Smith    Must be called before any other MG routine.
1514b9ad928SBarry Smith 
152ad4df100SBarry Smith    Logically Collective on PC
1534b9ad928SBarry Smith 
1544b9ad928SBarry Smith    Input Parameters:
1554b9ad928SBarry Smith +  pc - the preconditioner context
1564b9ad928SBarry Smith .  levels - the number of levels
1574b9ad928SBarry Smith -  comms - optional communicators for each level; this is to allow solving the coarser problems
1582bf68e3eSBarry Smith            on smaller sets of processors.
1594b9ad928SBarry Smith 
1604b9ad928SBarry Smith    Level: intermediate
1614b9ad928SBarry Smith 
1624b9ad928SBarry Smith    Notes:
1634b9ad928SBarry Smith      If the number of levels is one then the multigrid uses the -mg_levels prefix
1644b9ad928SBarry Smith   for setting the level options rather than the -mg_coarse prefix.
1654b9ad928SBarry Smith 
1664b9ad928SBarry Smith .keywords: MG, set, levels, multigrid
1674b9ad928SBarry Smith 
16897177400SBarry Smith .seealso: PCMGSetType(), PCMGGetLevels()
1694b9ad928SBarry Smith @*/
1707087cfbeSBarry Smith PetscErrorCode  PCMGSetLevels(PC pc,PetscInt levels,MPI_Comm *comms)
1714b9ad928SBarry Smith {
172dfbe8321SBarry Smith   PetscErrorCode ierr;
173f3fbd535SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
174ce94432eSBarry Smith   MPI_Comm       comm;
1753aeaf226SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
17610eca3edSLisandro Dalcin   PCMGType       mgtype     = mg->am;
17710167fecSBarry Smith   PetscInt       mgctype    = (PetscInt) PC_MG_CYCLE_V;
178f3fbd535SBarry Smith   PetscInt       i;
179f3fbd535SBarry Smith   PetscMPIInt    size;
180f3fbd535SBarry Smith   const char     *prefix;
181f3fbd535SBarry Smith   PC             ipc;
1823aeaf226SBarry Smith   PetscInt       n;
1834b9ad928SBarry Smith 
1844b9ad928SBarry Smith   PetscFunctionBegin;
1850700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
186548767e0SJed Brown   PetscValidLogicalCollectiveInt(pc,levels,2);
187ce94432eSBarry Smith   ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr);
188548767e0SJed Brown   if (mg->nlevels == levels) PetscFunctionReturn(0);
1893aeaf226SBarry Smith   if (mglevels) {
19010eca3edSLisandro Dalcin     mgctype = mglevels[0]->cycles;
1913aeaf226SBarry Smith     /* changing the number of levels so free up the previous stuff */
1923aeaf226SBarry Smith     ierr = PCReset_MG(pc);CHKERRQ(ierr);
1933aeaf226SBarry Smith     n    = mglevels[0]->levels;
1943aeaf226SBarry Smith     for (i=0; i<n; i++) {
1953aeaf226SBarry Smith       if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
1963aeaf226SBarry Smith         ierr = KSPDestroy(&mglevels[i]->smoothd);CHKERRQ(ierr);
1973aeaf226SBarry Smith       }
1983aeaf226SBarry Smith       ierr = KSPDestroy(&mglevels[i]->smoothu);CHKERRQ(ierr);
1993aeaf226SBarry Smith       ierr = PetscFree(mglevels[i]);CHKERRQ(ierr);
2003aeaf226SBarry Smith     }
2013aeaf226SBarry Smith     ierr = PetscFree(mg->levels);CHKERRQ(ierr);
2023aeaf226SBarry Smith   }
203f3fbd535SBarry Smith 
204f3fbd535SBarry Smith   mg->nlevels = levels;
205f3fbd535SBarry Smith 
206785e854fSJed Brown   ierr = PetscMalloc1(levels,&mglevels);CHKERRQ(ierr);
2073bb1ff40SBarry Smith   ierr = PetscLogObjectMemory((PetscObject)pc,levels*(sizeof(PC_MG*)));CHKERRQ(ierr);
208f3fbd535SBarry Smith 
209f3fbd535SBarry Smith   ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
210f3fbd535SBarry Smith 
211a9db87a2SMatthew G Knepley   mg->stageApply = 0;
212f3fbd535SBarry Smith   for (i=0; i<levels; i++) {
213b00a9115SJed Brown     ierr = PetscNewLog(pc,&mglevels[i]);CHKERRQ(ierr);
2142fa5cd67SKarl Rupp 
215f3fbd535SBarry Smith     mglevels[i]->level               = i;
216f3fbd535SBarry Smith     mglevels[i]->levels              = levels;
21710eca3edSLisandro Dalcin     mglevels[i]->cycles              = mgctype;
218336babb1SJed Brown     mg->default_smoothu              = 2;
219336babb1SJed Brown     mg->default_smoothd              = 2;
22063e6d426SJed Brown     mglevels[i]->eventsmoothsetup    = 0;
22163e6d426SJed Brown     mglevels[i]->eventsmoothsolve    = 0;
22263e6d426SJed Brown     mglevels[i]->eventresidual       = 0;
22363e6d426SJed Brown     mglevels[i]->eventinterprestrict = 0;
224f3fbd535SBarry Smith 
225f3fbd535SBarry Smith     if (comms) comm = comms[i];
226f3fbd535SBarry Smith     ierr = KSPCreate(comm,&mglevels[i]->smoothd);CHKERRQ(ierr);
227422a814eSBarry Smith     ierr = KSPSetErrorIfNotConverged(mglevels[i]->smoothd,pc->erroriffailure);CHKERRQ(ierr);
2280ee9a668SBarry Smith     ierr = PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd,(PetscObject)pc,levels-i);CHKERRQ(ierr);
2290ee9a668SBarry Smith     ierr = KSPSetOptionsPrefix(mglevels[i]->smoothd,prefix);CHKERRQ(ierr);
2300ee9a668SBarry Smith     ierr = PetscObjectComposedDataSetInt((PetscObject) mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level);CHKERRQ(ierr);
2310ee9a668SBarry Smith     if (i || levels == 1) {
2320ee9a668SBarry Smith       char tprefix[128];
2330ee9a668SBarry Smith 
234336babb1SJed Brown       ierr = KSPSetType(mglevels[i]->smoothd,KSPCHEBYSHEV);CHKERRQ(ierr);
2350059c7bdSJed Brown       ierr = KSPSetConvergenceTest(mglevels[i]->smoothd,KSPConvergedSkip,NULL,NULL);CHKERRQ(ierr);
236336babb1SJed Brown       ierr = KSPSetNormType(mglevels[i]->smoothd,KSP_NORM_NONE);CHKERRQ(ierr);
237336babb1SJed Brown       ierr = KSPGetPC(mglevels[i]->smoothd,&ipc);CHKERRQ(ierr);
238336babb1SJed Brown       ierr = PCSetType(ipc,PCSOR);CHKERRQ(ierr);
2390ee9a668SBarry Smith       ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, mg->default_smoothd);CHKERRQ(ierr);
240f3fbd535SBarry Smith 
2410ee9a668SBarry Smith       sprintf(tprefix,"mg_levels_%d_",(int)i);
2420ee9a668SBarry Smith       ierr = KSPAppendOptionsPrefix(mglevels[i]->smoothd,tprefix);CHKERRQ(ierr);
2430ee9a668SBarry Smith     } else {
244f3fbd535SBarry Smith       ierr = KSPAppendOptionsPrefix(mglevels[0]->smoothd,"mg_coarse_");CHKERRQ(ierr);
245f3fbd535SBarry Smith 
2469dbfc187SHong Zhang       /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */
247f3fbd535SBarry Smith       ierr = KSPSetType(mglevels[0]->smoothd,KSPPREONLY);CHKERRQ(ierr);
248f3fbd535SBarry Smith       ierr = KSPGetPC(mglevels[0]->smoothd,&ipc);CHKERRQ(ierr);
249f3fbd535SBarry Smith       ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
250f3fbd535SBarry Smith       if (size > 1) {
251f3fbd535SBarry Smith         ierr = PCSetType(ipc,PCREDUNDANT);CHKERRQ(ierr);
252f3fbd535SBarry Smith       } else {
253f3fbd535SBarry Smith         ierr = PCSetType(ipc,PCLU);CHKERRQ(ierr);
254f3fbd535SBarry Smith       }
255753b7fb9SBarry Smith       ierr = PCFactorSetShiftType(ipc,MAT_SHIFT_INBLOCKS);CHKERRQ(ierr);
256f3fbd535SBarry Smith     }
2573bb1ff40SBarry Smith     ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)mglevels[i]->smoothd);CHKERRQ(ierr);
2582fa5cd67SKarl Rupp 
259f3fbd535SBarry Smith     mglevels[i]->smoothu = mglevels[i]->smoothd;
26031567311SBarry Smith     mg->rtol             = 0.0;
26131567311SBarry Smith     mg->abstol           = 0.0;
26231567311SBarry Smith     mg->dtol             = 0.0;
26331567311SBarry Smith     mg->ttol             = 0.0;
26431567311SBarry Smith     mg->cyclesperpcapply = 1;
265f3fbd535SBarry Smith   }
266f3fbd535SBarry Smith   mg->levels = mglevels;
26710eca3edSLisandro Dalcin   ierr = PCMGSetType(pc,mgtype);CHKERRQ(ierr);
2684b9ad928SBarry Smith   PetscFunctionReturn(0);
2694b9ad928SBarry Smith }
2704b9ad928SBarry Smith 
271c07bf074SBarry Smith 
272c07bf074SBarry Smith PetscErrorCode PCDestroy_MG(PC pc)
273c07bf074SBarry Smith {
274c07bf074SBarry Smith   PetscErrorCode ierr;
275a06653b4SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
276a06653b4SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
277a06653b4SBarry Smith   PetscInt       i,n;
278c07bf074SBarry Smith 
279c07bf074SBarry Smith   PetscFunctionBegin;
280a06653b4SBarry Smith   ierr = PCReset_MG(pc);CHKERRQ(ierr);
281a06653b4SBarry Smith   if (mglevels) {
282a06653b4SBarry Smith     n = mglevels[0]->levels;
283a06653b4SBarry Smith     for (i=0; i<n; i++) {
284a06653b4SBarry Smith       if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
2856bf464f9SBarry Smith         ierr = KSPDestroy(&mglevels[i]->smoothd);CHKERRQ(ierr);
286a06653b4SBarry Smith       }
2876bf464f9SBarry Smith       ierr = KSPDestroy(&mglevels[i]->smoothu);CHKERRQ(ierr);
288a06653b4SBarry Smith       ierr = PetscFree(mglevels[i]);CHKERRQ(ierr);
289a06653b4SBarry Smith     }
290a06653b4SBarry Smith     ierr = PetscFree(mg->levels);CHKERRQ(ierr);
291a06653b4SBarry Smith   }
292c31cb41cSBarry Smith   ierr = PetscFree(pc->data);CHKERRQ(ierr);
293f3fbd535SBarry Smith   PetscFunctionReturn(0);
294f3fbd535SBarry Smith }
295f3fbd535SBarry Smith 
296f3fbd535SBarry Smith 
297f3fbd535SBarry Smith 
29809573ac7SBarry Smith extern PetscErrorCode PCMGACycle_Private(PC,PC_MG_Levels**);
29909573ac7SBarry Smith extern PetscErrorCode PCMGFCycle_Private(PC,PC_MG_Levels**);
30009573ac7SBarry Smith extern PetscErrorCode PCMGKCycle_Private(PC,PC_MG_Levels**);
301f3fbd535SBarry Smith 
302f3fbd535SBarry Smith /*
303f3fbd535SBarry Smith    PCApply_MG - Runs either an additive, multiplicative, Kaskadic
304f3fbd535SBarry Smith              or full cycle of multigrid.
305f3fbd535SBarry Smith 
306f3fbd535SBarry Smith   Note:
307f3fbd535SBarry Smith   A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
308f3fbd535SBarry Smith */
309f3fbd535SBarry Smith static PetscErrorCode PCApply_MG(PC pc,Vec b,Vec x)
310f3fbd535SBarry Smith {
311f3fbd535SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
312f3fbd535SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
313f3fbd535SBarry Smith   PetscErrorCode ierr;
314f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels,i;
315f3fbd535SBarry Smith 
316f3fbd535SBarry Smith   PetscFunctionBegin;
317a9db87a2SMatthew G Knepley   if (mg->stageApply) {ierr = PetscLogStagePush(mg->stageApply);CHKERRQ(ierr);}
318e1d8e5deSBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
319298cc208SBarry Smith   for (i=0; i<levels; i++) {
320e1d8e5deSBarry Smith     if (!mglevels[i]->A) {
32123ee1639SBarry Smith       ierr = KSPGetOperators(mglevels[i]->smoothu,&mglevels[i]->A,NULL);CHKERRQ(ierr);
322298cc208SBarry Smith       ierr = PetscObjectReference((PetscObject)mglevels[i]->A);CHKERRQ(ierr);
323e1d8e5deSBarry Smith     }
324e1d8e5deSBarry Smith   }
325e1d8e5deSBarry Smith 
326f3fbd535SBarry Smith   mglevels[levels-1]->b = b;
327f3fbd535SBarry Smith   mglevels[levels-1]->x = x;
32831567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
329f3fbd535SBarry Smith     ierr = VecSet(x,0.0);CHKERRQ(ierr);
33031567311SBarry Smith     for (i=0; i<mg->cyclesperpcapply; i++) {
3310298fd71SBarry Smith       ierr = PCMGMCycle_Private(pc,mglevels+levels-1,NULL);CHKERRQ(ierr);
332f3fbd535SBarry Smith     }
3332fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_ADDITIVE) {
33431567311SBarry Smith     ierr = PCMGACycle_Private(pc,mglevels);CHKERRQ(ierr);
3352fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_KASKADE) {
33631567311SBarry Smith     ierr = PCMGKCycle_Private(pc,mglevels);CHKERRQ(ierr);
3372fa5cd67SKarl Rupp   } else {
338f3fbd535SBarry Smith     ierr = PCMGFCycle_Private(pc,mglevels);CHKERRQ(ierr);
339f3fbd535SBarry Smith   }
340a9db87a2SMatthew G Knepley   if (mg->stageApply) {ierr = PetscLogStagePop();CHKERRQ(ierr);}
341f3fbd535SBarry Smith   PetscFunctionReturn(0);
342f3fbd535SBarry Smith }
343f3fbd535SBarry Smith 
344f3fbd535SBarry Smith 
3454416b707SBarry Smith PetscErrorCode PCSetFromOptions_MG(PetscOptionItems *PetscOptionsObject,PC pc)
346f3fbd535SBarry Smith {
347f3fbd535SBarry Smith   PetscErrorCode   ierr;
348f3fbd535SBarry Smith   PetscInt         m,levels = 1,cycles;
3492134b1e4SBarry Smith   PetscBool        flg;
350f3fbd535SBarry Smith   PC_MG            *mg        = (PC_MG*)pc->data;
3513d3eaba7SBarry Smith   PC_MG_Levels     **mglevels;
352f3fbd535SBarry Smith   PCMGType         mgtype;
353f3fbd535SBarry Smith   PCMGCycleType    mgctype;
3542134b1e4SBarry Smith   PCMGGalerkinType gtype;
355f3fbd535SBarry Smith 
356f3fbd535SBarry Smith   PetscFunctionBegin;
357e55864a3SBarry Smith   ierr = PetscOptionsHead(PetscOptionsObject,"Multigrid options");CHKERRQ(ierr);
3583aeaf226SBarry Smith   if (!mg->levels) {
359f3fbd535SBarry Smith     ierr = PetscOptionsInt("-pc_mg_levels","Number of Levels","PCMGSetLevels",levels,&levels,&flg);CHKERRQ(ierr);
360eb3f98d2SBarry Smith     if (!flg && pc->dm) {
361eb3f98d2SBarry Smith       ierr = DMGetRefineLevel(pc->dm,&levels);CHKERRQ(ierr);
362eb3f98d2SBarry Smith       levels++;
3633aeaf226SBarry Smith       mg->usedmfornumberoflevels = PETSC_TRUE;
364eb3f98d2SBarry Smith     }
3650298fd71SBarry Smith     ierr = PCMGSetLevels(pc,levels,NULL);CHKERRQ(ierr);
366f3fbd535SBarry Smith   }
3673aeaf226SBarry Smith   mglevels = mg->levels;
3683aeaf226SBarry Smith 
369f3fbd535SBarry Smith   mgctype = (PCMGCycleType) mglevels[0]->cycles;
370f3fbd535SBarry Smith   ierr    = PetscOptionsEnum("-pc_mg_cycle_type","V cycle or for W-cycle","PCMGSetCycleType",PCMGCycleTypes,(PetscEnum)mgctype,(PetscEnum*)&mgctype,&flg);CHKERRQ(ierr);
371f3fbd535SBarry Smith   if (flg) {
372f3fbd535SBarry Smith     ierr = PCMGSetCycleType(pc,mgctype);CHKERRQ(ierr);
3732fa5cd67SKarl Rupp   }
3742134b1e4SBarry Smith   gtype = mg->galerkin;
3752134b1e4SBarry Smith   ierr = PetscOptionsEnum("-pc_mg_galerkin","Use Galerkin process to compute coarser operators","PCMGSetGalerkin",PCMGGalerkinTypes,(PetscEnum)gtype,(PetscEnum*)&gtype,&flg);CHKERRQ(ierr);
3762134b1e4SBarry Smith   if (flg) {
3772134b1e4SBarry Smith     ierr = PCMGSetGalerkin(pc,gtype);CHKERRQ(ierr);
378f3fbd535SBarry Smith   }
37994ae4db5SBarry Smith   ierr = PetscOptionsInt("-pc_mg_smoothup","Number of post-smoothing steps","PCMGSetNumberSmoothUp",mg->default_smoothu,&m,&flg);CHKERRQ(ierr);
380f3fbd535SBarry Smith   if (flg) {
381f3fbd535SBarry Smith     ierr = PCMGSetNumberSmoothUp(pc,m);CHKERRQ(ierr);
382f3fbd535SBarry Smith   }
38394ae4db5SBarry Smith   ierr = PetscOptionsInt("-pc_mg_smoothdown","Number of pre-smoothing steps","PCMGSetNumberSmoothDown",mg->default_smoothd,&m,&flg);CHKERRQ(ierr);
384f3fbd535SBarry Smith   if (flg) {
385f3fbd535SBarry Smith     ierr = PCMGSetNumberSmoothDown(pc,m);CHKERRQ(ierr);
386f3fbd535SBarry Smith   }
38731567311SBarry Smith   mgtype = mg->am;
388f3fbd535SBarry Smith   ierr   = PetscOptionsEnum("-pc_mg_type","Multigrid type","PCMGSetType",PCMGTypes,(PetscEnum)mgtype,(PetscEnum*)&mgtype,&flg);CHKERRQ(ierr);
389f3fbd535SBarry Smith   if (flg) {
390f3fbd535SBarry Smith     ierr = PCMGSetType(pc,mgtype);CHKERRQ(ierr);
391f3fbd535SBarry Smith   }
39231567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
3935363c1e0SLisandro Dalcin     ierr = PetscOptionsInt("-pc_mg_multiplicative_cycles","Number of cycles for each preconditioner step","PCMGMultiplicativeSetCycles",mg->cyclesperpcapply,&cycles,&flg);CHKERRQ(ierr);
394f3fbd535SBarry Smith     if (flg) {
395f3fbd535SBarry Smith       ierr = PCMGMultiplicativeSetCycles(pc,cycles);CHKERRQ(ierr);
396f3fbd535SBarry Smith     }
397f3fbd535SBarry Smith   }
398f3fbd535SBarry Smith   flg  = PETSC_FALSE;
3990298fd71SBarry Smith   ierr = PetscOptionsBool("-pc_mg_log","Log times for each multigrid level","None",flg,&flg,NULL);CHKERRQ(ierr);
400f3fbd535SBarry Smith   if (flg) {
401f3fbd535SBarry Smith     PetscInt i;
402f3fbd535SBarry Smith     char     eventname[128];
403ce94432eSBarry Smith     if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
404f3fbd535SBarry Smith     levels = mglevels[0]->levels;
405f3fbd535SBarry Smith     for (i=0; i<levels; i++) {
406f3fbd535SBarry Smith       sprintf(eventname,"MGSetup Level %d",(int)i);
40763e6d426SJed Brown       ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventsmoothsetup);CHKERRQ(ierr);
408f3fbd535SBarry Smith       sprintf(eventname,"MGSmooth Level %d",(int)i);
40963e6d426SJed Brown       ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventsmoothsolve);CHKERRQ(ierr);
410f3fbd535SBarry Smith       if (i) {
411f3fbd535SBarry Smith         sprintf(eventname,"MGResid Level %d",(int)i);
41263e6d426SJed Brown         ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventresidual);CHKERRQ(ierr);
413f3fbd535SBarry Smith         sprintf(eventname,"MGInterp Level %d",(int)i);
41463e6d426SJed Brown         ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventinterprestrict);CHKERRQ(ierr);
415f3fbd535SBarry Smith       }
416f3fbd535SBarry Smith     }
417eec35531SMatthew G Knepley 
418ec60ca73SSatish Balay #if defined(PETSC_USE_LOG)
419eec35531SMatthew G Knepley     {
420eec35531SMatthew G Knepley       const char    *sname = "MG Apply";
421eec35531SMatthew G Knepley       PetscStageLog stageLog;
422eec35531SMatthew G Knepley       PetscInt      st;
423eec35531SMatthew G Knepley 
424eec35531SMatthew G Knepley       PetscFunctionBegin;
425eec35531SMatthew G Knepley       ierr = PetscLogGetStageLog(&stageLog);CHKERRQ(ierr);
426eec35531SMatthew G Knepley       for (st = 0; st < stageLog->numStages; ++st) {
427eec35531SMatthew G Knepley         PetscBool same;
428eec35531SMatthew G Knepley 
429eec35531SMatthew G Knepley         ierr = PetscStrcmp(stageLog->stageInfo[st].name, sname, &same);CHKERRQ(ierr);
4302fa5cd67SKarl Rupp         if (same) mg->stageApply = st;
431eec35531SMatthew G Knepley       }
432eec35531SMatthew G Knepley       if (!mg->stageApply) {
433eec35531SMatthew G Knepley         ierr = PetscLogStageRegister(sname, &mg->stageApply);CHKERRQ(ierr);
434eec35531SMatthew G Knepley       }
435eec35531SMatthew G Knepley     }
436ec60ca73SSatish Balay #endif
437f3fbd535SBarry Smith   }
438f3fbd535SBarry Smith   ierr = PetscOptionsTail();CHKERRQ(ierr);
439f3fbd535SBarry Smith   PetscFunctionReturn(0);
440f3fbd535SBarry Smith }
441f3fbd535SBarry Smith 
4426a6fc655SJed Brown const char *const PCMGTypes[] = {"MULTIPLICATIVE","ADDITIVE","FULL","KASKADE","PCMGType","PC_MG",0};
4436a6fc655SJed Brown const char *const PCMGCycleTypes[] = {"invalid","v","w","PCMGCycleType","PC_MG_CYCLE",0};
4442134b1e4SBarry Smith const char *const PCMGGalerkinTypes[] = {"both","pmat","mat","none","external","PCMGGalerkinType","PC_MG_GALERKIN",0};
445f3fbd535SBarry Smith 
4469804daf3SBarry Smith #include <petscdraw.h>
447f3fbd535SBarry Smith PetscErrorCode PCView_MG(PC pc,PetscViewer viewer)
448f3fbd535SBarry Smith {
449f3fbd535SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
450f3fbd535SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
451f3fbd535SBarry Smith   PetscErrorCode ierr;
452e3deeeafSJed Brown   PetscInt       levels = mglevels ? mglevels[0]->levels : 0,i;
453219b1045SBarry Smith   PetscBool      iascii,isbinary,isdraw;
454f3fbd535SBarry Smith 
455f3fbd535SBarry Smith   PetscFunctionBegin;
456251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
4575b0b0462SBarry Smith   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
458219b1045SBarry Smith   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr);
459f3fbd535SBarry Smith   if (iascii) {
460e3deeeafSJed Brown     const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown";
461*efd4aadfSBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  type is %s, levels=%D cycles=%s\n", PCMGTypes[mg->am],levels,cyclename);CHKERRQ(ierr);
46231567311SBarry Smith     if (mg->am == PC_MG_MULTIPLICATIVE) {
46331567311SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"    Cycles per PCApply=%d\n",mg->cyclesperpcapply);CHKERRQ(ierr);
464f3fbd535SBarry Smith     }
4652134b1e4SBarry Smith     if (mg->galerkin == PC_MG_GALERKIN_BOTH) {
466f3fbd535SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid matrices\n");CHKERRQ(ierr);
4672134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) {
4682134b1e4SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid matrices for pmat\n");CHKERRQ(ierr);
4692134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_MAT) {
4702134b1e4SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid matrices for mat\n");CHKERRQ(ierr);
4712134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) {
4722134b1e4SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"    Using externally compute Galerkin coarse grid matrices\n");CHKERRQ(ierr);
4734f66f45eSBarry Smith     } else {
4744f66f45eSBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"    Not using Galerkin computed coarse grid matrices\n");CHKERRQ(ierr);
475f3fbd535SBarry Smith     }
4765adeb434SBarry Smith     if (mg->view){
4775adeb434SBarry Smith       ierr = (*mg->view)(pc,viewer);CHKERRQ(ierr);
4785adeb434SBarry Smith     }
479f3fbd535SBarry Smith     for (i=0; i<levels; i++) {
480f3fbd535SBarry Smith       if (!i) {
48189cce641SBarry Smith         ierr = PetscViewerASCIIPrintf(viewer,"Coarse grid solver -- level -------------------------------\n",i);CHKERRQ(ierr);
482f3fbd535SBarry Smith       } else {
48389cce641SBarry Smith         ierr = PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
484f3fbd535SBarry Smith       }
485f3fbd535SBarry Smith       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
486f3fbd535SBarry Smith       ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr);
487f3fbd535SBarry Smith       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
488f3fbd535SBarry Smith       if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) {
489f3fbd535SBarry Smith         ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n");CHKERRQ(ierr);
490f3fbd535SBarry Smith       } else if (i) {
49189cce641SBarry Smith         ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
492f3fbd535SBarry Smith         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
493f3fbd535SBarry Smith         ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr);
494f3fbd535SBarry Smith         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
495f3fbd535SBarry Smith       }
496f3fbd535SBarry Smith     }
4975b0b0462SBarry Smith   } else if (isbinary) {
4985b0b0462SBarry Smith     for (i=levels-1; i>=0; i--) {
4995b0b0462SBarry Smith       ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr);
5005b0b0462SBarry Smith       if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) {
5015b0b0462SBarry Smith         ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr);
5025b0b0462SBarry Smith       }
5035b0b0462SBarry Smith     }
504219b1045SBarry Smith   } else if (isdraw) {
505219b1045SBarry Smith     PetscDraw draw;
506b4375e8dSPeter Brune     PetscReal x,w,y,bottom,th;
507219b1045SBarry Smith     ierr   = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr);
508219b1045SBarry Smith     ierr   = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr);
5090298fd71SBarry Smith     ierr   = PetscDrawStringGetSize(draw,NULL,&th);CHKERRQ(ierr);
510219b1045SBarry Smith     bottom = y - th;
511219b1045SBarry Smith     for (i=levels-1; i>=0; i--) {
512b4375e8dSPeter Brune       if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) {
513219b1045SBarry Smith         ierr = PetscDrawPushCurrentPoint(draw,x,bottom);CHKERRQ(ierr);
514219b1045SBarry Smith         ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr);
515219b1045SBarry Smith         ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr);
516b4375e8dSPeter Brune       } else {
517b4375e8dSPeter Brune         w    = 0.5*PetscMin(1.0-x,x);
518b4375e8dSPeter Brune         ierr = PetscDrawPushCurrentPoint(draw,x+w,bottom);CHKERRQ(ierr);
519b4375e8dSPeter Brune         ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr);
520b4375e8dSPeter Brune         ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr);
521b4375e8dSPeter Brune         ierr = PetscDrawPushCurrentPoint(draw,x-w,bottom);CHKERRQ(ierr);
522b4375e8dSPeter Brune         ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr);
523b4375e8dSPeter Brune         ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr);
524b4375e8dSPeter Brune       }
5250298fd71SBarry Smith       ierr    = PetscDrawGetBoundingBox(draw,NULL,&bottom,NULL,NULL);CHKERRQ(ierr);
5261cd381d6SBarry Smith       bottom -= th;
527219b1045SBarry Smith     }
5285b0b0462SBarry Smith   }
529f3fbd535SBarry Smith   PetscFunctionReturn(0);
530f3fbd535SBarry Smith }
531f3fbd535SBarry Smith 
532af0996ceSBarry Smith #include <petsc/private/dmimpl.h>
533af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
534cab2e9ccSBarry Smith 
535f3fbd535SBarry Smith /*
536f3fbd535SBarry Smith     Calls setup for the KSP on each level
537f3fbd535SBarry Smith */
538f3fbd535SBarry Smith PetscErrorCode PCSetUp_MG(PC pc)
539f3fbd535SBarry Smith {
540f3fbd535SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
541f3fbd535SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
542f3fbd535SBarry Smith   PetscErrorCode ierr;
543f3fbd535SBarry Smith   PetscInt       i,n = mglevels[0]->levels;
54498e04984SBarry Smith   PC             cpc;
5453db492dfSBarry Smith   PetscBool      dump = PETSC_FALSE,opsset,use_amat,missinginterpolate = PETSC_FALSE;
546f3fbd535SBarry Smith   Mat            dA,dB;
547f3fbd535SBarry Smith   Vec            tvec;
548218a07d4SBarry Smith   DM             *dms;
549649052a6SBarry Smith   PetscViewer    viewer = 0;
5502134b1e4SBarry Smith   PetscBool      dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE;
551f3fbd535SBarry Smith 
552f3fbd535SBarry Smith   PetscFunctionBegin;
55301bc414fSDmitry Karpeev   /* FIX: Move this to PCSetFromOptions_MG? */
5543aeaf226SBarry Smith   if (mg->usedmfornumberoflevels) {
5553aeaf226SBarry Smith     PetscInt levels;
5563aeaf226SBarry Smith     ierr = DMGetRefineLevel(pc->dm,&levels);CHKERRQ(ierr);
5573aeaf226SBarry Smith     levels++;
5583aeaf226SBarry Smith     if (levels > n) { /* the problem is now being solved on a finer grid */
5590298fd71SBarry Smith       ierr     = PCMGSetLevels(pc,levels,NULL);CHKERRQ(ierr);
5603aeaf226SBarry Smith       n        = levels;
5613aeaf226SBarry Smith       ierr     = PCSetFromOptions(pc);CHKERRQ(ierr); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */
5623aeaf226SBarry Smith       mglevels =  mg->levels;
5633aeaf226SBarry Smith     }
5643aeaf226SBarry Smith   }
56598e04984SBarry Smith   ierr = KSPGetPC(mglevels[0]->smoothd,&cpc);CHKERRQ(ierr);
5663aeaf226SBarry Smith 
567f3fbd535SBarry Smith 
568f3fbd535SBarry Smith   /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
569f3fbd535SBarry Smith   /* so use those from global PC */
570f3fbd535SBarry Smith   /* Is this what we always want? What if user wants to keep old one? */
5710298fd71SBarry Smith   ierr = KSPGetOperatorsSet(mglevels[n-1]->smoothd,NULL,&opsset);CHKERRQ(ierr);
57298e04984SBarry Smith   if (opsset) {
57398e04984SBarry Smith     Mat mmat;
57423ee1639SBarry Smith     ierr = KSPGetOperators(mglevels[n-1]->smoothd,NULL,&mmat);CHKERRQ(ierr);
57598e04984SBarry Smith     if (mmat == pc->pmat) opsset = PETSC_FALSE;
57698e04984SBarry Smith   }
5774a5f07a5SMark F. Adams 
5784a5f07a5SMark F. Adams   if (!opsset) {
57971b23a65SMark F. Adams     ierr = PCGetUseAmat(pc,&use_amat);CHKERRQ(ierr);
5804a5f07a5SMark F. Adams     if(use_amat){
581f3fbd535SBarry 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);
58223ee1639SBarry Smith       ierr = KSPSetOperators(mglevels[n-1]->smoothd,pc->mat,pc->pmat);CHKERRQ(ierr);
583f3fbd535SBarry Smith     }
5844a5f07a5SMark F. Adams     else {
5854a5f07a5SMark F. Adams       ierr = PetscInfo(pc,"Using matrix (pmat) operators to define finest grid operator \n  because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n");CHKERRQ(ierr);
58623ee1639SBarry Smith       ierr = KSPSetOperators(mglevels[n-1]->smoothd,pc->pmat,pc->pmat);CHKERRQ(ierr);
5874a5f07a5SMark F. Adams     }
5884a5f07a5SMark F. Adams   }
589f3fbd535SBarry Smith 
5909c7ffb39SBarry Smith   for (i=n-1; i>0; i--) {
5919c7ffb39SBarry Smith     if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) {
5929c7ffb39SBarry Smith       missinginterpolate = PETSC_TRUE;
5939c7ffb39SBarry Smith       continue;
5949c7ffb39SBarry Smith     }
5959c7ffb39SBarry Smith   }
5962134b1e4SBarry Smith 
5972134b1e4SBarry Smith   ierr = KSPGetOperators(mglevels[n-1]->smoothd,&dA,&dB);CHKERRQ(ierr);
5982134b1e4SBarry Smith   if (dA == dB) dAeqdB = PETSC_TRUE;
5992134b1e4SBarry Smith   if ((mg->galerkin == PC_MG_GALERKIN_NONE) || (((mg->galerkin == PC_MG_GALERKIN_PMAT) || (mg->galerkin == PC_MG_GALERKIN_MAT)) && !dAeqdB)) {
6002134b1e4SBarry Smith     needRestricts = PETSC_TRUE;  /* user must compute either mat, pmat, or both so must restrict x to coarser levels */
6012134b1e4SBarry Smith   }
6022134b1e4SBarry Smith 
6032134b1e4SBarry Smith 
6049c7ffb39SBarry Smith   /*
6059c7ffb39SBarry Smith    Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS)
6069c7ffb39SBarry Smith    Skipping for galerkin==2 (externally managed hierarchy such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs?
6079c7ffb39SBarry Smith   */
6082134b1e4SBarry Smith   if (missinginterpolate && pc->dm && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) {
6092d2b81a6SBarry Smith     /* construct the interpolation from the DMs */
6102e499ae9SBarry Smith     Mat p;
61173250ac0SBarry Smith     Vec rscale;
612785e854fSJed Brown     ierr     = PetscMalloc1(n,&dms);CHKERRQ(ierr);
613218a07d4SBarry Smith     dms[n-1] = pc->dm;
614ef1267afSMatthew G. Knepley     /* Separately create them so we do not get DMKSP interference between levels */
615ef1267afSMatthew G. Knepley     for (i=n-2; i>-1; i--) {ierr = DMCoarsen(dms[i+1],MPI_COMM_NULL,&dms[i]);CHKERRQ(ierr);}
616218a07d4SBarry Smith     for (i=n-2; i>-1; i--) {
617942e3340SBarry Smith       DMKSP     kdm;
6183ad4599aSBarry Smith       PetscBool dmhasrestrict;
6193c0c59f3SBarry Smith       ierr = KSPSetDM(mglevels[i]->smoothd,dms[i]);CHKERRQ(ierr);
6202134b1e4SBarry Smith       if (!needRestricts) {ierr = KSPSetDMActive(mglevels[i]->smoothd,PETSC_FALSE);CHKERRQ(ierr);}
621942e3340SBarry Smith       ierr = DMGetDMKSPWrite(dms[i],&kdm);CHKERRQ(ierr);
622d1a3e677SJed Brown       /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take
623d1a3e677SJed Brown        * a bitwise OR of computing the matrix, RHS, and initial iterate. */
6240298fd71SBarry Smith       kdm->ops->computerhs = NULL;
6250298fd71SBarry Smith       kdm->rhsctx          = NULL;
62624c3aa18SBarry Smith       if (!mglevels[i+1]->interpolate) {
627e727c939SJed Brown         ierr = DMCreateInterpolation(dms[i],dms[i+1],&p,&rscale);CHKERRQ(ierr);
6282d2b81a6SBarry Smith         ierr = PCMGSetInterpolation(pc,i+1,p);CHKERRQ(ierr);
62900ac8be1SBarry Smith         if (rscale) {ierr = PCMGSetRScale(pc,i+1,rscale);CHKERRQ(ierr);}
63073250ac0SBarry Smith         ierr = VecDestroy(&rscale);CHKERRQ(ierr);
6316bf464f9SBarry Smith         ierr = MatDestroy(&p);CHKERRQ(ierr);
632218a07d4SBarry Smith       }
6333ad4599aSBarry Smith       ierr = DMHasCreateRestriction(dms[i],&dmhasrestrict);CHKERRQ(ierr);
6343ad4599aSBarry Smith       if (dmhasrestrict && !mglevels[i+1]->restrct){
6353ad4599aSBarry Smith         ierr = DMCreateRestriction(dms[i],dms[i+1],&p);CHKERRQ(ierr);
6363ad4599aSBarry Smith         ierr = PCMGSetRestriction(pc,i+1,p);CHKERRQ(ierr);
6373ad4599aSBarry Smith         ierr = MatDestroy(&p);CHKERRQ(ierr);
6383ad4599aSBarry Smith       }
63924c3aa18SBarry Smith     }
6402d2b81a6SBarry Smith 
641ef1267afSMatthew G. Knepley     for (i=n-2; i>-1; i--) {ierr = DMDestroy(&dms[i]);CHKERRQ(ierr);}
6422d2b81a6SBarry Smith     ierr = PetscFree(dms);CHKERRQ(ierr);
643ce4cda84SJed Brown   }
644cab2e9ccSBarry Smith 
645ce4cda84SJed Brown   if (pc->dm && !pc->setupcalled) {
6462134b1e4SBarry Smith     /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */
647cab2e9ccSBarry Smith     ierr = KSPSetDM(mglevels[n-1]->smoothd,pc->dm);CHKERRQ(ierr);
648cab2e9ccSBarry Smith     ierr = KSPSetDMActive(mglevels[n-1]->smoothd,PETSC_FALSE);CHKERRQ(ierr);
649218a07d4SBarry Smith   }
650218a07d4SBarry Smith 
6512134b1e4SBarry Smith   if (mg->galerkin < PC_MG_GALERKIN_NONE) {
6522134b1e4SBarry Smith     Mat       A,B;
6532134b1e4SBarry Smith     PetscBool doA = PETSC_FALSE,doB = PETSC_FALSE;
6542134b1e4SBarry Smith     MatReuse  reuse = MAT_INITIAL_MATRIX;
6552134b1e4SBarry Smith 
6562134b1e4SBarry Smith     if ((mg->galerkin == PC_MG_GALERKIN_PMAT) || (mg->galerkin == PC_MG_GALERKIN_BOTH)) doB = PETSC_TRUE;
6572134b1e4SBarry Smith     if ((mg->galerkin == PC_MG_GALERKIN_MAT) || ((mg->galerkin == PC_MG_GALERKIN_BOTH) && (dA != dB))) doA = PETSC_TRUE;
6582134b1e4SBarry Smith     if (pc->setupcalled) reuse = MAT_REUSE_MATRIX;
659f3fbd535SBarry Smith     for (i=n-2; i>-1; i--) {
660b9367914SBarry Smith       if (!mglevels[i+1]->restrct && !mglevels[i+1]->interpolate) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must provide interpolation or restriction for each MG level except level 0");
661b9367914SBarry Smith       if (!mglevels[i+1]->interpolate) {
662b9367914SBarry Smith         ierr = PCMGSetInterpolation(pc,i+1,mglevels[i+1]->restrct);CHKERRQ(ierr);
663b9367914SBarry Smith       }
664b9367914SBarry Smith       if (!mglevels[i+1]->restrct) {
665b9367914SBarry Smith         ierr = PCMGSetRestriction(pc,i+1,mglevels[i+1]->interpolate);CHKERRQ(ierr);
666b9367914SBarry Smith       }
6672134b1e4SBarry Smith       if (reuse == MAT_REUSE_MATRIX) {
6682134b1e4SBarry Smith         ierr = KSPGetOperators(mglevels[i]->smoothd,&A,&B);CHKERRQ(ierr);
6692134b1e4SBarry Smith       }
6702134b1e4SBarry Smith       if (doA) {
6712df6c5c3SPatrick Farrell         ierr = MatGalerkin(mglevels[i+1]->restrct,dA,mglevels[i+1]->interpolate,reuse,1.0,&A);CHKERRQ(ierr);
6722134b1e4SBarry Smith       }
6732134b1e4SBarry Smith       if (doB) {
6742df6c5c3SPatrick Farrell         ierr = MatGalerkin(mglevels[i+1]->restrct,dB,mglevels[i+1]->interpolate,reuse,1.0,&B);CHKERRQ(ierr);
675b9367914SBarry Smith       }
6762134b1e4SBarry Smith       /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */
6772134b1e4SBarry Smith       if (!doA && dAeqdB) {
6782134b1e4SBarry Smith         if (reuse == MAT_INITIAL_MATRIX) {ierr = PetscObjectReference((PetscObject)B);CHKERRQ(ierr);}
6792134b1e4SBarry Smith         A = B;
6802134b1e4SBarry Smith       } else if (!doA && reuse == MAT_INITIAL_MATRIX ) {
6812134b1e4SBarry Smith         ierr = KSPGetOperators(mglevels[i]->smoothd,&A,NULL);CHKERRQ(ierr);
6822134b1e4SBarry Smith         ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr);
683b9367914SBarry Smith       }
6842134b1e4SBarry Smith       if (!doB && dAeqdB) {
6852134b1e4SBarry Smith         if (reuse == MAT_INITIAL_MATRIX) {ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr);}
6862134b1e4SBarry Smith         B = A;
6872134b1e4SBarry Smith       } else if (!doB && reuse == MAT_INITIAL_MATRIX) {
68823ee1639SBarry Smith         ierr = KSPGetOperators(mglevels[i]->smoothd,NULL,&B);CHKERRQ(ierr);
6892134b1e4SBarry Smith         ierr = PetscObjectReference((PetscObject)B);CHKERRQ(ierr);
6907d537d92SJed Brown       }
6912134b1e4SBarry Smith       if (reuse == MAT_INITIAL_MATRIX) {
6922134b1e4SBarry Smith         ierr = KSPSetOperators(mglevels[i]->smoothd,A,B);CHKERRQ(ierr);
6932134b1e4SBarry Smith         ierr = PetscObjectDereference((PetscObject)A);CHKERRQ(ierr);
6942134b1e4SBarry Smith         ierr = PetscObjectDereference((PetscObject)B);CHKERRQ(ierr);
6952134b1e4SBarry Smith       }
6962134b1e4SBarry Smith       dA = A;
697f3fbd535SBarry Smith       dB = B;
698f3fbd535SBarry Smith     }
699f3fbd535SBarry Smith   }
7002134b1e4SBarry Smith   if (needRestricts && pc->dm && pc->dm->x) {
701cab2e9ccSBarry Smith     /* need to restrict Jacobian location to coarser meshes for evaluation */
702cab2e9ccSBarry Smith     for (i=n-2; i>-1; i--) {
703c88c5224SJed Brown       Mat R;
704c88c5224SJed Brown       Vec rscale;
705cab2e9ccSBarry Smith       if (!mglevels[i]->smoothd->dm->x) {
706cab2e9ccSBarry Smith         Vec *vecs;
7072a7a6963SBarry Smith         ierr = KSPCreateVecs(mglevels[i]->smoothd,1,&vecs,0,NULL);CHKERRQ(ierr);
708cab2e9ccSBarry Smith         mglevels[i]->smoothd->dm->x = vecs[0];
709cab2e9ccSBarry Smith         ierr = PetscFree(vecs);CHKERRQ(ierr);
710cab2e9ccSBarry Smith       }
711c88c5224SJed Brown       ierr = PCMGGetRestriction(pc,i+1,&R);CHKERRQ(ierr);
712c88c5224SJed Brown       ierr = PCMGGetRScale(pc,i+1,&rscale);CHKERRQ(ierr);
713c88c5224SJed Brown       ierr = MatRestrict(R,mglevels[i+1]->smoothd->dm->x,mglevels[i]->smoothd->dm->x);CHKERRQ(ierr);
714c88c5224SJed Brown       ierr = VecPointwiseMult(mglevels[i]->smoothd->dm->x,mglevels[i]->smoothd->dm->x,rscale);CHKERRQ(ierr);
715cab2e9ccSBarry Smith     }
716f3fbd535SBarry Smith   }
7172134b1e4SBarry Smith   if (needRestricts && pc->dm) {
718caa4e7f2SJed Brown     for (i=n-2; i>=0; i--) {
719ccceb50cSJed Brown       DM  dmfine,dmcoarse;
720caa4e7f2SJed Brown       Mat Restrict,Inject;
721caa4e7f2SJed Brown       Vec rscale;
722ccceb50cSJed Brown       ierr   = KSPGetDM(mglevels[i+1]->smoothd,&dmfine);CHKERRQ(ierr);
723ccceb50cSJed Brown       ierr   = KSPGetDM(mglevels[i]->smoothd,&dmcoarse);CHKERRQ(ierr);
724caa4e7f2SJed Brown       ierr   = PCMGGetRestriction(pc,i+1,&Restrict);CHKERRQ(ierr);
725caa4e7f2SJed Brown       ierr   = PCMGGetRScale(pc,i+1,&rscale);CHKERRQ(ierr);
7260298fd71SBarry Smith       Inject = NULL;      /* Callback should create it if it needs Injection */
727caa4e7f2SJed Brown       ierr   = DMRestrict(dmfine,Restrict,rscale,Inject,dmcoarse);CHKERRQ(ierr);
728caa4e7f2SJed Brown     }
729caa4e7f2SJed Brown   }
730f3fbd535SBarry Smith 
731f3fbd535SBarry Smith   if (!pc->setupcalled) {
732f3fbd535SBarry Smith     for (i=0; i<n; i++) {
733f3fbd535SBarry Smith       ierr = KSPSetFromOptions(mglevels[i]->smoothd);CHKERRQ(ierr);
734f3fbd535SBarry Smith     }
735f3fbd535SBarry Smith     for (i=1; i<n; i++) {
736f3fbd535SBarry Smith       if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) {
737f3fbd535SBarry Smith         ierr = KSPSetFromOptions(mglevels[i]->smoothu);CHKERRQ(ierr);
738f3fbd535SBarry Smith       }
739f3fbd535SBarry Smith     }
7403ad4599aSBarry Smith     /* insure that if either interpolation or restriction is set the other other one is set */
741f3fbd535SBarry Smith     for (i=1; i<n; i++) {
7423ad4599aSBarry Smith       ierr = PCMGGetInterpolation(pc,i,NULL);CHKERRQ(ierr);
7433ad4599aSBarry Smith       ierr = PCMGGetRestriction(pc,i,NULL);CHKERRQ(ierr);
744f3fbd535SBarry Smith     }
745f3fbd535SBarry Smith     for (i=0; i<n-1; i++) {
746f3fbd535SBarry Smith       if (!mglevels[i]->b) {
747f3fbd535SBarry Smith         Vec *vec;
7482a7a6963SBarry Smith         ierr = KSPCreateVecs(mglevels[i]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr);
749f3fbd535SBarry Smith         ierr = PCMGSetRhs(pc,i,*vec);CHKERRQ(ierr);
7506bf464f9SBarry Smith         ierr = VecDestroy(vec);CHKERRQ(ierr);
751f3fbd535SBarry Smith         ierr = PetscFree(vec);CHKERRQ(ierr);
752f3fbd535SBarry Smith       }
753f3fbd535SBarry Smith       if (!mglevels[i]->r && i) {
754f3fbd535SBarry Smith         ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr);
755f3fbd535SBarry Smith         ierr = PCMGSetR(pc,i,tvec);CHKERRQ(ierr);
7566bf464f9SBarry Smith         ierr = VecDestroy(&tvec);CHKERRQ(ierr);
757f3fbd535SBarry Smith       }
758f3fbd535SBarry Smith       if (!mglevels[i]->x) {
759f3fbd535SBarry Smith         ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr);
760f3fbd535SBarry Smith         ierr = PCMGSetX(pc,i,tvec);CHKERRQ(ierr);
7616bf464f9SBarry Smith         ierr = VecDestroy(&tvec);CHKERRQ(ierr);
762f3fbd535SBarry Smith       }
763f3fbd535SBarry Smith     }
764f3fbd535SBarry Smith     if (n != 1 && !mglevels[n-1]->r) {
765f3fbd535SBarry Smith       /* PCMGSetR() on the finest level if user did not supply it */
766f3fbd535SBarry Smith       Vec *vec;
7672a7a6963SBarry Smith       ierr = KSPCreateVecs(mglevels[n-1]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr);
768f3fbd535SBarry Smith       ierr = PCMGSetR(pc,n-1,*vec);CHKERRQ(ierr);
7696bf464f9SBarry Smith       ierr = VecDestroy(vec);CHKERRQ(ierr);
770f3fbd535SBarry Smith       ierr = PetscFree(vec);CHKERRQ(ierr);
771f3fbd535SBarry Smith     }
772f3fbd535SBarry Smith   }
773f3fbd535SBarry Smith 
77498e04984SBarry Smith   if (pc->dm) {
77598e04984SBarry Smith     /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */
77698e04984SBarry Smith     for (i=0; i<n-1; i++) {
77798e04984SBarry Smith       if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
77898e04984SBarry Smith     }
77998e04984SBarry Smith   }
780f3fbd535SBarry Smith 
781f3fbd535SBarry Smith   for (i=1; i<n; i++) {
7822a21e185SBarry Smith     if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1){
783f3fbd535SBarry Smith       /* if doing only down then initial guess is zero */
784f3fbd535SBarry Smith       ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothd,PETSC_TRUE);CHKERRQ(ierr);
785f3fbd535SBarry Smith     }
78663e6d426SJed Brown     if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
787f3fbd535SBarry Smith     ierr = KSPSetUp(mglevels[i]->smoothd);CHKERRQ(ierr);
788899639b0SHong Zhang     if (mglevels[i]->smoothd->reason == KSP_DIVERGED_PCSETUP_FAILED) {
789899639b0SHong Zhang       pc->failedreason = PC_SUBPC_ERROR;
790899639b0SHong Zhang     }
79163e6d426SJed Brown     if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
792d42688cbSBarry Smith     if (!mglevels[i]->residual) {
793d42688cbSBarry Smith       Mat mat;
79413842ffbSBarry Smith       ierr = KSPGetOperators(mglevels[i]->smoothd,&mat,NULL);CHKERRQ(ierr);
79554b2cd4bSJed Brown       ierr = PCMGSetResidual(pc,i,PCMGResidualDefault,mat);CHKERRQ(ierr);
796d42688cbSBarry Smith     }
797f3fbd535SBarry Smith   }
798f3fbd535SBarry Smith   for (i=1; i<n; i++) {
799f3fbd535SBarry Smith     if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) {
800f3fbd535SBarry Smith       Mat downmat,downpmat;
801f3fbd535SBarry Smith 
802f3fbd535SBarry Smith       /* check if operators have been set for up, if not use down operators to set them */
8030298fd71SBarry Smith       ierr = KSPGetOperatorsSet(mglevels[i]->smoothu,&opsset,NULL);CHKERRQ(ierr);
804f3fbd535SBarry Smith       if (!opsset) {
80523ee1639SBarry Smith         ierr = KSPGetOperators(mglevels[i]->smoothd,&downmat,&downpmat);CHKERRQ(ierr);
80623ee1639SBarry Smith         ierr = KSPSetOperators(mglevels[i]->smoothu,downmat,downpmat);CHKERRQ(ierr);
807f3fbd535SBarry Smith       }
808f3fbd535SBarry Smith 
809f3fbd535SBarry Smith       ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothu,PETSC_TRUE);CHKERRQ(ierr);
81063e6d426SJed Brown       if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
811f3fbd535SBarry Smith       ierr = KSPSetUp(mglevels[i]->smoothu);CHKERRQ(ierr);
812899639b0SHong Zhang       if (mglevels[i]->smoothu->reason == KSP_DIVERGED_PCSETUP_FAILED) {
813899639b0SHong Zhang         pc->failedreason = PC_SUBPC_ERROR;
814899639b0SHong Zhang       }
81563e6d426SJed Brown       if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
816f3fbd535SBarry Smith     }
817f3fbd535SBarry Smith   }
818f3fbd535SBarry Smith 
81963e6d426SJed Brown   if (mglevels[0]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[0]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
820f3fbd535SBarry Smith   ierr = KSPSetUp(mglevels[0]->smoothd);CHKERRQ(ierr);
821899639b0SHong Zhang   if (mglevels[0]->smoothd->reason == KSP_DIVERGED_PCSETUP_FAILED) {
822899639b0SHong Zhang     pc->failedreason = PC_SUBPC_ERROR;
823899639b0SHong Zhang   }
82463e6d426SJed Brown   if (mglevels[0]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[0]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
825f3fbd535SBarry Smith 
826f3fbd535SBarry Smith   /*
827f3fbd535SBarry Smith      Dump the interpolation/restriction matrices plus the
828e3c5b3baSBarry Smith    Jacobian/stiffness on each level. This allows MATLAB users to
829f3fbd535SBarry Smith    easily check if the Galerkin condition A_c = R A_f R^T is satisfied.
830f3fbd535SBarry Smith 
831f3fbd535SBarry Smith    Only support one or the other at the same time.
832f3fbd535SBarry Smith   */
833f3fbd535SBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER)
834c5929fdfSBarry Smith   ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_mg_dump_matlab",&dump,NULL);CHKERRQ(ierr);
835ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc));
836f3fbd535SBarry Smith   dump = PETSC_FALSE;
837f3fbd535SBarry Smith #endif
838c5929fdfSBarry Smith   ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_mg_dump_binary",&dump,NULL);CHKERRQ(ierr);
839ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc));
840f3fbd535SBarry Smith 
841f3fbd535SBarry Smith   if (viewer) {
842f3fbd535SBarry Smith     for (i=1; i<n; i++) {
843f3fbd535SBarry Smith       ierr = MatView(mglevels[i]->restrct,viewer);CHKERRQ(ierr);
844f3fbd535SBarry Smith     }
845f3fbd535SBarry Smith     for (i=0; i<n; i++) {
846f3fbd535SBarry Smith       ierr = KSPGetPC(mglevels[i]->smoothd,&pc);CHKERRQ(ierr);
847f3fbd535SBarry Smith       ierr = MatView(pc->mat,viewer);CHKERRQ(ierr);
848f3fbd535SBarry Smith     }
849f3fbd535SBarry Smith   }
850f3fbd535SBarry Smith   PetscFunctionReturn(0);
851f3fbd535SBarry Smith }
852f3fbd535SBarry Smith 
853f3fbd535SBarry Smith /* -------------------------------------------------------------------------------------*/
854f3fbd535SBarry Smith 
8554b9ad928SBarry Smith /*@
85697177400SBarry Smith    PCMGGetLevels - Gets the number of levels to use with MG.
8574b9ad928SBarry Smith 
8584b9ad928SBarry Smith    Not Collective
8594b9ad928SBarry Smith 
8604b9ad928SBarry Smith    Input Parameter:
8614b9ad928SBarry Smith .  pc - the preconditioner context
8624b9ad928SBarry Smith 
8634b9ad928SBarry Smith    Output parameter:
8644b9ad928SBarry Smith .  levels - the number of levels
8654b9ad928SBarry Smith 
8664b9ad928SBarry Smith    Level: advanced
8674b9ad928SBarry Smith 
8684b9ad928SBarry Smith .keywords: MG, get, levels, multigrid
8694b9ad928SBarry Smith 
87097177400SBarry Smith .seealso: PCMGSetLevels()
8714b9ad928SBarry Smith @*/
8727087cfbeSBarry Smith PetscErrorCode  PCMGGetLevels(PC pc,PetscInt *levels)
8734b9ad928SBarry Smith {
874f3fbd535SBarry Smith   PC_MG *mg = (PC_MG*)pc->data;
8754b9ad928SBarry Smith 
8764b9ad928SBarry Smith   PetscFunctionBegin;
8770700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
8784482741eSBarry Smith   PetscValidIntPointer(levels,2);
879f3fbd535SBarry Smith   *levels = mg->nlevels;
8804b9ad928SBarry Smith   PetscFunctionReturn(0);
8814b9ad928SBarry Smith }
8824b9ad928SBarry Smith 
8834b9ad928SBarry Smith /*@
88497177400SBarry Smith    PCMGSetType - Determines the form of multigrid to use:
8854b9ad928SBarry Smith    multiplicative, additive, full, or the Kaskade algorithm.
8864b9ad928SBarry Smith 
887ad4df100SBarry Smith    Logically Collective on PC
8884b9ad928SBarry Smith 
8894b9ad928SBarry Smith    Input Parameters:
8904b9ad928SBarry Smith +  pc - the preconditioner context
8919dcbbd2bSBarry Smith -  form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,
8929dcbbd2bSBarry Smith    PC_MG_FULL, PC_MG_KASKADE
8934b9ad928SBarry Smith 
8944b9ad928SBarry Smith    Options Database Key:
8954b9ad928SBarry Smith .  -pc_mg_type <form> - Sets <form>, one of multiplicative,
8964b9ad928SBarry Smith    additive, full, kaskade
8974b9ad928SBarry Smith 
8984b9ad928SBarry Smith    Level: advanced
8994b9ad928SBarry Smith 
9004b9ad928SBarry Smith .keywords: MG, set, method, multiplicative, additive, full, Kaskade, multigrid
9014b9ad928SBarry Smith 
90297177400SBarry Smith .seealso: PCMGSetLevels()
9034b9ad928SBarry Smith @*/
9047087cfbeSBarry Smith PetscErrorCode  PCMGSetType(PC pc,PCMGType form)
9054b9ad928SBarry Smith {
906f3fbd535SBarry Smith   PC_MG *mg = (PC_MG*)pc->data;
9074b9ad928SBarry Smith 
9084b9ad928SBarry Smith   PetscFunctionBegin;
9090700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
910c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc,form,2);
91131567311SBarry Smith   mg->am = form;
9129dcbbd2bSBarry Smith   if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
913c60c7ad4SBarry Smith   else pc->ops->applyrichardson = NULL;
914c60c7ad4SBarry Smith   PetscFunctionReturn(0);
915c60c7ad4SBarry Smith }
916c60c7ad4SBarry Smith 
917c60c7ad4SBarry Smith /*@
918c60c7ad4SBarry Smith    PCMGGetType - Determines the form of multigrid to use:
919c60c7ad4SBarry Smith    multiplicative, additive, full, or the Kaskade algorithm.
920c60c7ad4SBarry Smith 
921c60c7ad4SBarry Smith    Logically Collective on PC
922c60c7ad4SBarry Smith 
923c60c7ad4SBarry Smith    Input Parameter:
924c60c7ad4SBarry Smith .  pc - the preconditioner context
925c60c7ad4SBarry Smith 
926c60c7ad4SBarry Smith    Output Parameter:
927c60c7ad4SBarry Smith .  type - one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,PC_MG_FULL, PC_MG_KASKADE
928c60c7ad4SBarry Smith 
929c60c7ad4SBarry Smith 
930c60c7ad4SBarry Smith    Level: advanced
931c60c7ad4SBarry Smith 
932c60c7ad4SBarry Smith .keywords: MG, set, method, multiplicative, additive, full, Kaskade, multigrid
933c60c7ad4SBarry Smith 
934c60c7ad4SBarry Smith .seealso: PCMGSetLevels()
935c60c7ad4SBarry Smith @*/
936c60c7ad4SBarry Smith PetscErrorCode  PCMGGetType(PC pc,PCMGType *type)
937c60c7ad4SBarry Smith {
938c60c7ad4SBarry Smith   PC_MG *mg = (PC_MG*)pc->data;
939c60c7ad4SBarry Smith 
940c60c7ad4SBarry Smith   PetscFunctionBegin;
941c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
942c60c7ad4SBarry Smith   *type = mg->am;
9434b9ad928SBarry Smith   PetscFunctionReturn(0);
9444b9ad928SBarry Smith }
9454b9ad928SBarry Smith 
9464b9ad928SBarry Smith /*@
9470d353602SBarry Smith    PCMGSetCycleType - Sets the type cycles to use.  Use PCMGSetCycleTypeOnLevel() for more
9484b9ad928SBarry Smith    complicated cycling.
9494b9ad928SBarry Smith 
950ad4df100SBarry Smith    Logically Collective on PC
9514b9ad928SBarry Smith 
9524b9ad928SBarry Smith    Input Parameters:
953c2be2410SBarry Smith +  pc - the multigrid context
9540d353602SBarry Smith -  PC_MG_CYCLE_V or PC_MG_CYCLE_W
9554b9ad928SBarry Smith 
9564b9ad928SBarry Smith    Options Database Key:
9574446f3b4SBarry Smith .  -pc_mg_cycle_type <v,w>
9584b9ad928SBarry Smith 
9594b9ad928SBarry Smith    Level: advanced
9604b9ad928SBarry Smith 
9614b9ad928SBarry Smith .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
9624b9ad928SBarry Smith 
9630d353602SBarry Smith .seealso: PCMGSetCycleTypeOnLevel()
9644b9ad928SBarry Smith @*/
9657087cfbeSBarry Smith PetscErrorCode  PCMGSetCycleType(PC pc,PCMGCycleType n)
9664b9ad928SBarry Smith {
967f3fbd535SBarry Smith   PC_MG        *mg        = (PC_MG*)pc->data;
968f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
96979416396SBarry Smith   PetscInt     i,levels;
9704b9ad928SBarry Smith 
9714b9ad928SBarry Smith   PetscFunctionBegin;
9720700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
973ce94432eSBarry Smith   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
97469fbec6eSBarry Smith   PetscValidLogicalCollectiveEnum(pc,n,2);
975f3fbd535SBarry Smith   levels = mglevels[0]->levels;
9764b9ad928SBarry Smith 
9772fa5cd67SKarl Rupp   for (i=0; i<levels; i++) mglevels[i]->cycles = n;
9784b9ad928SBarry Smith   PetscFunctionReturn(0);
9794b9ad928SBarry Smith }
9804b9ad928SBarry Smith 
9818cc2d5dfSBarry Smith /*@
9828cc2d5dfSBarry Smith    PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step
9838cc2d5dfSBarry Smith          of multigrid when PCMGType of PC_MG_MULTIPLICATIVE is used
9848cc2d5dfSBarry Smith 
985ad4df100SBarry Smith    Logically Collective on PC
9868cc2d5dfSBarry Smith 
9878cc2d5dfSBarry Smith    Input Parameters:
9888cc2d5dfSBarry Smith +  pc - the multigrid context
9898cc2d5dfSBarry Smith -  n - number of cycles (default is 1)
9908cc2d5dfSBarry Smith 
9918cc2d5dfSBarry Smith    Options Database Key:
992e1bc860dSBarry Smith .  -pc_mg_multiplicative_cycles n
9938cc2d5dfSBarry Smith 
9948cc2d5dfSBarry Smith    Level: advanced
9958cc2d5dfSBarry Smith 
9968cc2d5dfSBarry Smith    Notes: This is not associated with setting a v or w cycle, that is set with PCMGSetCycleType()
9978cc2d5dfSBarry Smith 
9988cc2d5dfSBarry Smith .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
9998cc2d5dfSBarry Smith 
10008cc2d5dfSBarry Smith .seealso: PCMGSetCycleTypeOnLevel(), PCMGSetCycleType()
10018cc2d5dfSBarry Smith @*/
10027087cfbeSBarry Smith PetscErrorCode  PCMGMultiplicativeSetCycles(PC pc,PetscInt n)
10038cc2d5dfSBarry Smith {
1004f3fbd535SBarry Smith   PC_MG        *mg        = (PC_MG*)pc->data;
10058cc2d5dfSBarry Smith 
10068cc2d5dfSBarry Smith   PetscFunctionBegin;
10070700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1008c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc,n,2);
10092a21e185SBarry Smith   mg->cyclesperpcapply = n;
10108cc2d5dfSBarry Smith   PetscFunctionReturn(0);
10118cc2d5dfSBarry Smith }
10128cc2d5dfSBarry Smith 
10132134b1e4SBarry Smith PetscErrorCode PCMGSetGalerkin_MG(PC pc,PCMGGalerkinType use)
1014fb15c04eSBarry Smith {
1015fb15c04eSBarry Smith   PC_MG *mg = (PC_MG*)pc->data;
1016fb15c04eSBarry Smith 
1017fb15c04eSBarry Smith   PetscFunctionBegin;
10182134b1e4SBarry Smith   mg->galerkin = use;
1019fb15c04eSBarry Smith   PetscFunctionReturn(0);
1020fb15c04eSBarry Smith }
1021fb15c04eSBarry Smith 
1022c2be2410SBarry Smith /*@
102397177400SBarry Smith    PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
102482b87d87SMatthew G. Knepley       finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i
1025c2be2410SBarry Smith 
1026ad4df100SBarry Smith    Logically Collective on PC
1027c2be2410SBarry Smith 
1028c2be2410SBarry Smith    Input Parameters:
1029c91913d3SJed Brown +  pc - the multigrid context
10302134b1e4SBarry Smith -  use - one of PC_MG_GALERKIN_BOTH,PC_MG_GALERKIN_PMAT,PC_MG_GALERKIN_MAT, or PC_MG_GALERKIN_NONE
1031c2be2410SBarry Smith 
1032c2be2410SBarry Smith    Options Database Key:
10332134b1e4SBarry Smith .  -pc_mg_galerkin <both,pmat,mat,none>
1034c2be2410SBarry Smith 
1035c2be2410SBarry Smith    Level: intermediate
1036c2be2410SBarry Smith 
10371c1aac46SBarry Smith    Notes: Some codes that use PCMG such as PCGAMG use Galerkin internally while constructing the hierarchy and thus do not
10381c1aac46SBarry Smith      use the PCMG construction of the coarser grids.
10391c1aac46SBarry Smith 
1040c2be2410SBarry Smith .keywords: MG, set, Galerkin
1041c2be2410SBarry Smith 
10422134b1e4SBarry Smith .seealso: PCMGGetGalerkin(), PCMGGalerkinType
10433fc8bf9cSBarry Smith 
1044c2be2410SBarry Smith @*/
10452134b1e4SBarry Smith PetscErrorCode PCMGSetGalerkin(PC pc,PCMGGalerkinType use)
1046c2be2410SBarry Smith {
1047fb15c04eSBarry Smith   PetscErrorCode ierr;
1048c2be2410SBarry Smith 
1049c2be2410SBarry Smith   PetscFunctionBegin;
10500700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
10512134b1e4SBarry Smith   ierr = PetscTryMethod(pc,"PCMGSetGalerkin_C",(PC,PCMGGalerkinType),(pc,use));CHKERRQ(ierr);
1052c2be2410SBarry Smith   PetscFunctionReturn(0);
1053c2be2410SBarry Smith }
1054c2be2410SBarry Smith 
10553fc8bf9cSBarry Smith /*@
10563fc8bf9cSBarry Smith    PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e.
105782b87d87SMatthew G. Knepley       A_i-1 = r_i * A_i * p_i
10583fc8bf9cSBarry Smith 
10593fc8bf9cSBarry Smith    Not Collective
10603fc8bf9cSBarry Smith 
10613fc8bf9cSBarry Smith    Input Parameter:
10623fc8bf9cSBarry Smith .  pc - the multigrid context
10633fc8bf9cSBarry Smith 
10643fc8bf9cSBarry Smith    Output Parameter:
10652134b1e4SBarry Smith .  galerkin - one of PC_MG_GALERKIN_BOTH,PC_MG_GALERKIN_PMAT,PC_MG_GALERKIN_MAT, PC_MG_GALERKIN_NONE, or PC_MG_GALERKIN_EXTERNAL
10663fc8bf9cSBarry Smith 
10673fc8bf9cSBarry Smith    Level: intermediate
10683fc8bf9cSBarry Smith 
10693fc8bf9cSBarry Smith .keywords: MG, set, Galerkin
10703fc8bf9cSBarry Smith 
10712134b1e4SBarry Smith .seealso: PCMGSetGalerkin(), PCMGGalerkinType
10723fc8bf9cSBarry Smith 
10733fc8bf9cSBarry Smith @*/
10742134b1e4SBarry Smith PetscErrorCode  PCMGGetGalerkin(PC pc,PCMGGalerkinType  *galerkin)
10753fc8bf9cSBarry Smith {
1076f3fbd535SBarry Smith   PC_MG *mg = (PC_MG*)pc->data;
10773fc8bf9cSBarry Smith 
10783fc8bf9cSBarry Smith   PetscFunctionBegin;
10790700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
10802134b1e4SBarry Smith   *galerkin = mg->galerkin;
10813fc8bf9cSBarry Smith   PetscFunctionReturn(0);
10823fc8bf9cSBarry Smith }
10833fc8bf9cSBarry Smith 
10844b9ad928SBarry Smith /*@
108597177400SBarry Smith    PCMGSetNumberSmoothDown - Sets the number of pre-smoothing steps to
108697177400SBarry Smith    use on all levels. Use PCMGGetSmootherDown() to set different
10874b9ad928SBarry Smith    pre-smoothing steps on different levels.
10884b9ad928SBarry Smith 
1089ad4df100SBarry Smith    Logically Collective on PC
10904b9ad928SBarry Smith 
10914b9ad928SBarry Smith    Input Parameters:
10924b9ad928SBarry Smith +  mg - the multigrid context
10934b9ad928SBarry Smith -  n - the number of smoothing steps
10944b9ad928SBarry Smith 
10954b9ad928SBarry Smith    Options Database Key:
10964b9ad928SBarry Smith .  -pc_mg_smoothdown <n> - Sets number of pre-smoothing steps
10974b9ad928SBarry Smith 
10984b9ad928SBarry Smith    Level: advanced
10998c75dd1cSBarry Smith     If the number of smoothing steps is changed in this call then the PCMGGetSmoothUp() will be called and now the
110006792cafSBarry Smith    up smoother will no longer share the same KSP object as the down smoother. Use PCMGSetNumberSmooth() to set the same
110106792cafSBarry Smith    number of smoothing steps for pre and post smoothing.
11024b9ad928SBarry Smith 
11034b9ad928SBarry Smith .keywords: MG, smooth, down, pre-smoothing, steps, multigrid
11044b9ad928SBarry Smith 
110506792cafSBarry Smith .seealso: PCMGSetNumberSmoothUp(), PCMGSetNumberSmooth()
11064b9ad928SBarry Smith @*/
11077087cfbeSBarry Smith PetscErrorCode  PCMGSetNumberSmoothDown(PC pc,PetscInt n)
11084b9ad928SBarry Smith {
1109f3fbd535SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
1110f3fbd535SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
11116849ba73SBarry Smith   PetscErrorCode ierr;
111279416396SBarry Smith   PetscInt       i,levels;
11134b9ad928SBarry Smith 
11144b9ad928SBarry Smith   PetscFunctionBegin;
11150700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1116ce94432eSBarry Smith   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
1117c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc,n,2);
1118f3fbd535SBarry Smith   levels = mglevels[0]->levels;
11194b9ad928SBarry Smith 
1120b05257ddSBarry Smith   for (i=1; i<levels; i++) {
11218c75dd1cSBarry Smith     PetscInt nc;
11228c75dd1cSBarry Smith     ierr = KSPGetTolerances(mglevels[i]->smoothd,NULL,NULL,NULL,&nc);CHKERRQ(ierr);
11238c75dd1cSBarry Smith     if (nc == n) continue;
11248c75dd1cSBarry Smith 
11254b9ad928SBarry Smith     /* make sure smoother up and down are different */
11260298fd71SBarry Smith     ierr = PCMGGetSmootherUp(pc,i,NULL);CHKERRQ(ierr);
1127f3fbd535SBarry Smith     ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr);
11282fa5cd67SKarl Rupp 
112931567311SBarry Smith     mg->default_smoothd = n;
11304b9ad928SBarry Smith   }
11314b9ad928SBarry Smith   PetscFunctionReturn(0);
11324b9ad928SBarry Smith }
11334b9ad928SBarry Smith 
11344b9ad928SBarry Smith /*@
113597177400SBarry Smith    PCMGSetNumberSmoothUp - Sets the number of post-smoothing steps to use
113697177400SBarry Smith    on all levels. Use PCMGGetSmootherUp() to set different numbers of
11374b9ad928SBarry Smith    post-smoothing steps on different levels.
11384b9ad928SBarry Smith 
1139ad4df100SBarry Smith    Logically Collective on PC
11404b9ad928SBarry Smith 
11414b9ad928SBarry Smith    Input Parameters:
11424b9ad928SBarry Smith +  mg - the multigrid context
11434b9ad928SBarry Smith -  n - the number of smoothing steps
11444b9ad928SBarry Smith 
11454b9ad928SBarry Smith    Options Database Key:
11464b9ad928SBarry Smith .  -pc_mg_smoothup <n> - Sets number of post-smoothing steps
11474b9ad928SBarry Smith 
11484b9ad928SBarry Smith    Level: advanced
11494b9ad928SBarry Smith 
11508c75dd1cSBarry Smith    Notes: this does not set a value on the coarsest grid, since we assume that
1151a8c7a070SBarry Smith     there is no separate smooth up on the coarsest grid.
11524b9ad928SBarry Smith 
11538c75dd1cSBarry Smith     If the number of smoothing steps is changed in this call then the PCMGGetSmoothUp() will be called and now the
115406792cafSBarry Smith    up smoother will no longer share the same KSP object as the down smoother. Use PCMGSetNumberSmooth() to set the same
115506792cafSBarry Smith    number of smoothing steps for pre and post smoothing.
115606792cafSBarry Smith 
11578c75dd1cSBarry Smith 
11584b9ad928SBarry Smith .keywords: MG, smooth, up, post-smoothing, steps, multigrid
11594b9ad928SBarry Smith 
116006792cafSBarry Smith .seealso: PCMGSetNumberSmoothDown(), PCMGSetNumberSmooth()
11614b9ad928SBarry Smith @*/
11627087cfbeSBarry Smith PetscErrorCode  PCMGSetNumberSmoothUp(PC pc,PetscInt n)
11634b9ad928SBarry Smith {
1164f3fbd535SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
1165f3fbd535SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
11666849ba73SBarry Smith   PetscErrorCode ierr;
116779416396SBarry Smith   PetscInt       i,levels;
11684b9ad928SBarry Smith 
11694b9ad928SBarry Smith   PetscFunctionBegin;
11700700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1171ce94432eSBarry Smith   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
1172c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc,n,2);
1173f3fbd535SBarry Smith   levels = mglevels[0]->levels;
11744b9ad928SBarry Smith 
11754b9ad928SBarry Smith   for (i=1; i<levels; i++) {
11768c75dd1cSBarry Smith     if (mglevels[i]->smoothu == mglevels[i]->smoothd) {
11778c75dd1cSBarry Smith       PetscInt nc;
11788c75dd1cSBarry Smith       ierr = KSPGetTolerances(mglevels[i]->smoothd,NULL,NULL,NULL,&nc);CHKERRQ(ierr);
11798c75dd1cSBarry Smith       if (nc == n) continue;
11808c75dd1cSBarry Smith     }
11818c75dd1cSBarry Smith 
11824b9ad928SBarry Smith     /* make sure smoother up and down are different */
11830298fd71SBarry Smith     ierr = PCMGGetSmootherUp(pc,i,NULL);CHKERRQ(ierr);
1184f3fbd535SBarry Smith     ierr = KSPSetTolerances(mglevels[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr);
11852fa5cd67SKarl Rupp 
118631567311SBarry Smith     mg->default_smoothu = n;
11874b9ad928SBarry Smith   }
11884b9ad928SBarry Smith   PetscFunctionReturn(0);
11894b9ad928SBarry Smith }
11904b9ad928SBarry Smith 
119106792cafSBarry Smith /*@
119206792cafSBarry Smith    PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use
119306792cafSBarry Smith    on all levels. Use PCMGSetSmoothUp() and PCMGSetSmoothDown() set different numbers of
119406792cafSBarry Smith    pre ad post-smoothing steps
119506792cafSBarry Smith 
119606792cafSBarry Smith    Logically Collective on PC
119706792cafSBarry Smith 
119806792cafSBarry Smith    Input Parameters:
119906792cafSBarry Smith +  mg - the multigrid context
120006792cafSBarry Smith -  n - the number of smoothing steps
120106792cafSBarry Smith 
120206792cafSBarry Smith    Options Database Key:
120306792cafSBarry Smith +  -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps
120406792cafSBarry Smith .  -pc_mg_smooth_down <n> - Sets number of pre-smoothing steps (if setting different pre and post amounts)
120506792cafSBarry Smith -  -pc_mg_smooth_up <n> - Sets number of post-smoothing steps (if setting different pre and post amounts)
120606792cafSBarry Smith 
120706792cafSBarry Smith    Level: advanced
120806792cafSBarry Smith 
120906792cafSBarry Smith    Notes: this does not set a value on the coarsest grid, since we assume that
121006792cafSBarry Smith     there is no separate smooth up on the coarsest grid.
121106792cafSBarry Smith 
121206792cafSBarry Smith .keywords: MG, smooth, up, post-smoothing, steps, multigrid
121306792cafSBarry Smith 
121406792cafSBarry Smith .seealso: PCMGSetNumberSmoothDown(), PCMGSetNumberSmoothUp()
121506792cafSBarry Smith @*/
121606792cafSBarry Smith PetscErrorCode  PCMGSetNumberSmooth(PC pc,PetscInt n)
121706792cafSBarry Smith {
121806792cafSBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
121906792cafSBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
122006792cafSBarry Smith   PetscErrorCode ierr;
122106792cafSBarry Smith   PetscInt       i,levels;
122206792cafSBarry Smith 
122306792cafSBarry Smith   PetscFunctionBegin;
122406792cafSBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
122506792cafSBarry Smith   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
122606792cafSBarry Smith   PetscValidLogicalCollectiveInt(pc,n,2);
122706792cafSBarry Smith   levels = mglevels[0]->levels;
122806792cafSBarry Smith 
122906792cafSBarry Smith   for (i=1; i<levels; i++) {
123006792cafSBarry Smith     ierr = KSPSetTolerances(mglevels[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr);
123106792cafSBarry Smith     ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr);
123206792cafSBarry Smith     mg->default_smoothu = n;
123306792cafSBarry Smith     mg->default_smoothd = n;
123406792cafSBarry Smith   }
123506792cafSBarry Smith   PetscFunctionReturn(0);
123606792cafSBarry Smith }
123706792cafSBarry Smith 
12384b9ad928SBarry Smith /* ----------------------------------------------------------------------------------------*/
12394b9ad928SBarry Smith 
12403b09bd56SBarry Smith /*MC
1241ccb205f8SBarry Smith    PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional
12423b09bd56SBarry Smith     information about the coarser grid matrices and restriction/interpolation operators.
12433b09bd56SBarry Smith 
12443b09bd56SBarry Smith    Options Database Keys:
12453b09bd56SBarry Smith +  -pc_mg_levels <nlevels> - number of levels including finest
12464afba7b0SPatrick Sanan .  -pc_mg_cycle_type <v,w> -
124779416396SBarry Smith .  -pc_mg_smoothup <n> - number of smoothing steps after interpolation
12483b09bd56SBarry Smith .  -pc_mg_smoothdown <n> - number of smoothing steps before applying restriction operator
12498c1c2452SJed Brown .  -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default
12503b09bd56SBarry Smith .  -pc_mg_log - log information about time spent on each level of the solver
12512134b1e4SBarry Smith .  -pc_mg_galerkin <both,pmat,mat,none> - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R'
12528cf6037eSBarry Smith .  -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1)
12538cf6037eSBarry Smith .  -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices
1254e3c5b3baSBarry Smith                         to the Socket viewer for reading from MATLAB.
12558cf6037eSBarry Smith -  -pc_mg_dump_binary - dumps the matrices for each level and the restriction/interpolation matrices
12568cf6037eSBarry Smith                         to the binary output file called binaryoutput
12573b09bd56SBarry Smith 
1258e941fc33SBarry Smith    Notes: If one uses a Krylov method such GMRES or CG as the smoother than one must use KSPFGMRES, KSPGCG, or KSPRICHARDSON as the outer Krylov method
12593b09bd56SBarry Smith 
12608cf6037eSBarry Smith        When run with a single level the smoother options are used on that level NOT the coarse grid solver options
12618cf6037eSBarry Smith 
12623b09bd56SBarry Smith    Level: intermediate
12633b09bd56SBarry Smith 
12648f87f92bSBarry Smith    Concepts: multigrid/multilevel
12653b09bd56SBarry Smith 
12668cf6037eSBarry Smith .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType, PCEXOTIC, PCGAMG, PCML, PCHYPRE
12670d353602SBarry Smith            PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), PCMGSetCycleType(), PCMGSetNumberSmoothDown(),
126897177400SBarry Smith            PCMGSetNumberSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(),
126997177400SBarry Smith            PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(),
12700d353602SBarry Smith            PCMGSetCycleTypeOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR()
12713b09bd56SBarry Smith M*/
12723b09bd56SBarry Smith 
12738cc058d9SJed Brown PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc)
12744b9ad928SBarry Smith {
1275f3fbd535SBarry Smith   PC_MG          *mg;
1276f3fbd535SBarry Smith   PetscErrorCode ierr;
1277f3fbd535SBarry Smith 
12784b9ad928SBarry Smith   PetscFunctionBegin;
1279b00a9115SJed Brown   ierr         = PetscNewLog(pc,&mg);CHKERRQ(ierr);
1280f3fbd535SBarry Smith   pc->data     = (void*)mg;
1281f3fbd535SBarry Smith   mg->nlevels  = -1;
128210eca3edSLisandro Dalcin   mg->am       = PC_MG_MULTIPLICATIVE;
12832134b1e4SBarry Smith   mg->galerkin = PC_MG_GALERKIN_NONE;
1284f3fbd535SBarry Smith 
128537a44384SMark Adams   pc->useAmat = PETSC_TRUE;
128637a44384SMark Adams 
12874b9ad928SBarry Smith   pc->ops->apply          = PCApply_MG;
12884b9ad928SBarry Smith   pc->ops->setup          = PCSetUp_MG;
1289a06653b4SBarry Smith   pc->ops->reset          = PCReset_MG;
12904b9ad928SBarry Smith   pc->ops->destroy        = PCDestroy_MG;
12914b9ad928SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_MG;
12924b9ad928SBarry Smith   pc->ops->view           = PCView_MG;
1293fb15c04eSBarry Smith 
1294fb15c04eSBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCMGSetGalerkin_C",PCMGSetGalerkin_MG);CHKERRQ(ierr);
12954b9ad928SBarry Smith   PetscFunctionReturn(0);
12964b9ad928SBarry Smith }
1297