Actual source code: mg.c

  1: #define PETSCKSP_DLL

  3: /*
  4:     Defines the multigrid preconditioner interface.
  5: */
 6:  #include ../src/ksp/pc/impls/mg/mgimpl.h


 11: PetscErrorCode PCMGMCycle_Private(PC pc,PC_MG **mglevels,PCRichardsonConvergedReason *reason)
 12: {
 13:   PC_MG          *mg = *mglevels,*mgc;
 15:   PetscInt       cycles = (mg->level == 1) ? 1 : (PetscInt) mg->cycles;


 19:   if (mg->eventsmoothsolve) {PetscLogEventBegin(mg->eventsmoothsolve,0,0,0,0);}
 20:   KSPSolve(mg->smoothd,mg->b,mg->x);  /* pre-smooth */
 21:   if (mg->eventsmoothsolve) {PetscLogEventEnd(mg->eventsmoothsolve,0,0,0,0);}
 22:   if (mg->level) {  /* not the coarsest grid */
 23:     if (mg->eventresidual) {PetscLogEventBegin(mg->eventresidual,0,0,0,0);}
 24:     (*mg->residual)(mg->A,mg->b,mg->x,mg->r);
 25:     if (mg->eventresidual) {PetscLogEventEnd(mg->eventresidual,0,0,0,0);}

 27:     /* if on finest level and have convergence criteria set */
 28:     if (mg->level == mg->levels-1 && mg->ttol && reason) {
 29:       PetscReal rnorm;
 30:       VecNorm(mg->r,NORM_2,&rnorm);
 31:       if (rnorm <= mg->ttol) {
 32:         if (rnorm < mg->abstol) {
 33:           *reason = PCRICHARDSON_CONVERGED_ATOL;
 34:           PetscInfo2(pc,"Linear solver has converged. Residual norm %G is less than absolute tolerance %G\n",rnorm,mg->abstol);
 35:         } else {
 36:           *reason = PCRICHARDSON_CONVERGED_RTOL;
 37:           PetscInfo2(pc,"Linear solver has converged. Residual norm %G is less than relative tolerance times initial residual norm %G\n",rnorm,mg->ttol);
 38:         }
 39:         return(0);
 40:       }
 41:     }

 43:     mgc = *(mglevels - 1);
 44:     if (mg->eventinterprestrict) {PetscLogEventBegin(mg->eventinterprestrict,0,0,0,0);}
 45:     MatRestrict(mg->restrct,mg->r,mgc->b);
 46:     if (mg->eventinterprestrict) {PetscLogEventEnd(mg->eventinterprestrict,0,0,0,0);}
 47:     VecSet(mgc->x,0.0);
 48:     while (cycles--) {
 49:       PCMGMCycle_Private(pc,mglevels-1,reason);
 50:     }
 51:     if (mg->eventinterprestrict) {PetscLogEventBegin(mg->eventinterprestrict,0,0,0,0);}
 52:     MatInterpolateAdd(mg->interpolate,mgc->x,mg->x,mg->x);
 53:     if (mg->eventinterprestrict) {PetscLogEventEnd(mg->eventinterprestrict,0,0,0,0);}
 54:     if (mg->eventsmoothsolve) {PetscLogEventBegin(mg->eventsmoothsolve,0,0,0,0);}
 55:     KSPSolve(mg->smoothu,mg->b,mg->x);    /* post smooth */
 56:     if (mg->eventsmoothsolve) {PetscLogEventEnd(mg->eventsmoothsolve,0,0,0,0);}
 57:   }
 58:   return(0);
 59: }

 61: /*
 62:        PCMGCreate_Private - Creates a PC_MG structure for use with the
 63:                multigrid code. Level 0 is the coarsest. (But the 
 64:                finest level is stored first in the array).

 66: */
 69: static PetscErrorCode PCMGCreate_Private(MPI_Comm comm,PetscInt levels,PC pc,MPI_Comm *comms,PC_MG ***result)
 70: {
 71:   PC_MG          **mg;
 73:   PetscInt       i;
 74:   PetscMPIInt    size;
 75:   const char     *prefix;
 76:   PC             ipc;

 79:   PetscMalloc(levels*sizeof(PC_MG*),&mg);
 80:   PetscLogObjectMemory(pc,levels*(sizeof(PC_MG*)));

 82:   PCGetOptionsPrefix(pc,&prefix);

 84:   for (i=0; i<levels; i++) {
 85:     PetscNewLog(pc,PC_MG,&mg[i]);
 86:     mg[i]->level           = i;
 87:     mg[i]->levels          = levels;
 88:     mg[i]->cycles          = PC_MG_CYCLE_V;
 89:     mg[i]->galerkin        = PETSC_FALSE;
 90:     mg[i]->galerkinused    = PETSC_FALSE;
 91:     mg[i]->default_smoothu = 1;
 92:     mg[i]->default_smoothd = 1;

 94:     if (comms) comm = comms[i];
 95:     KSPCreate(comm,&mg[i]->smoothd);
 96:     PetscObjectIncrementTabLevel((PetscObject)mg[i]->smoothd,(PetscObject)pc,levels-i);
 97:     KSPSetTolerances(mg[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, mg[i]->default_smoothd);
 98:     KSPSetOptionsPrefix(mg[i]->smoothd,prefix);

100:     /* do special stuff for coarse grid */
101:     if (!i && levels > 1) {
102:       KSPAppendOptionsPrefix(mg[0]->smoothd,"mg_coarse_");

104:       /* coarse solve is (redundant) LU by default */
105:       KSPSetType(mg[0]->smoothd,KSPPREONLY);
106:       KSPGetPC(mg[0]->smoothd,&ipc);
107:       MPI_Comm_size(comm,&size);
108:       if (size > 1) {
109:         PCSetType(ipc,PCREDUNDANT);
110:       } else {
111:         PCSetType(ipc,PCLU);
112:       }

114:     } else {
115:       char tprefix[128];
116:       sprintf(tprefix,"mg_levels_%d_",(int)i);
117:       KSPAppendOptionsPrefix(mg[i]->smoothd,tprefix);
118:     }
119:     PetscLogObjectParent(pc,mg[i]->smoothd);
120:     mg[i]->smoothu             = mg[i]->smoothd;
121:     mg[i]->rtol                = 0.0;
122:     mg[i]->abstol              = 0.0;
123:     mg[i]->dtol                = 0.0;
124:     mg[i]->ttol                = 0.0;
125:     mg[i]->eventsmoothsetup    = 0;
126:     mg[i]->eventsmoothsolve    = 0;
127:     mg[i]->eventresidual       = 0;
128:     mg[i]->eventinterprestrict = 0;
129:     mg[i]->cyclesperpcapply    = 1;
130:   }
131:   *result = mg;
132:   return(0);
133: }

137: PetscErrorCode PCDestroy_MG(PC pc)
138: {
139:   PC_MG          **mg = (PC_MG**)pc->data;
141:   PetscInt       i,n;

144:   if (!mg) return(0);

146:   n = mg[0]->levels;
147:   for (i=0; i<n-1; i++) {
148:     if (mg[i+1]->r) {VecDestroy(mg[i+1]->r);}
149:     if (mg[i]->b) {VecDestroy(mg[i]->b);}
150:     if (mg[i]->x) {VecDestroy(mg[i]->x);}
151:     if (mg[i+1]->restrct) {MatDestroy(mg[i+1]->restrct);}
152:     if (mg[i+1]->interpolate) {MatDestroy(mg[i+1]->interpolate);}
153:   }

155:   for (i=0; i<n; i++) {
156:     if (mg[i]->smoothd != mg[i]->smoothu) {
157:       KSPDestroy(mg[i]->smoothd);
158:     }
159:     KSPDestroy(mg[i]->smoothu);
160:     PetscFree(mg[i]);
161:   }
162:   PetscFree(mg);
163:   return(0);
164: }



168: EXTERN PetscErrorCode PCMGACycle_Private(PC_MG**);
169: EXTERN PetscErrorCode PCMGFCycle_Private(PC,PC_MG**);
170: EXTERN PetscErrorCode PCMGKCycle_Private(PC_MG**);

172: /*
173:    PCApply_MG - Runs either an additive, multiplicative, Kaskadic
174:              or full cycle of multigrid. 

176:   Note: 
177:   A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle(). 
178: */
181: static PetscErrorCode PCApply_MG(PC pc,Vec b,Vec x)
182: {
183:   PC_MG          **mg = (PC_MG**)pc->data;
185:   PetscInt       levels = mg[0]->levels,i;

188:   mg[levels-1]->b = b;
189:   mg[levels-1]->x = x;
190:   if (mg[0]->am == PC_MG_MULTIPLICATIVE) {
191:     VecSet(x,0.0);
192:     for (i=0; i<mg[0]->cyclesperpcapply; i++) {
193:       PCMGMCycle_Private(pc,mg+levels-1,PETSC_NULL);
194:     }
195:   }
196:   else if (mg[0]->am == PC_MG_ADDITIVE) {
197:     PCMGACycle_Private(mg);
198:   }
199:   else if (mg[0]->am == PC_MG_KASKADE) {
200:     PCMGKCycle_Private(mg);
201:   }
202:   else {
203:     PCMGFCycle_Private(pc,mg);
204:   }
205:   return(0);
206: }

210: static PetscErrorCode PCApplyRichardson_MG(PC pc,Vec b,Vec x,Vec w,PetscReal rtol,PetscReal abstol, PetscReal dtol,PetscInt its,PetscInt *outits,PCRichardsonConvergedReason *reason)
211: {
212:   PC_MG          **mg = (PC_MG**)pc->data;
214:   PetscInt       levels = mg[0]->levels,i;

217:   mg[levels-1]->b    = b;
218:   mg[levels-1]->x    = x;

220:   mg[levels-1]->rtol = rtol;
221:   mg[levels-1]->abstol = abstol;
222:   mg[levels-1]->dtol = dtol;
223:   if (rtol) {
224:     /* compute initial residual norm for relative convergence test */
225:     PetscReal rnorm;
226:     (*mg[levels-1]->residual)(mg[levels-1]->A,b,x,w);
227:     VecNorm(w,NORM_2,&rnorm);
228:     mg[levels-1]->ttol = PetscMax(rtol*rnorm,abstol);
229:   } else if (abstol) {
230:     mg[levels-1]->ttol = abstol;
231:   } else {
232:     mg[levels-1]->ttol = 0.0;
233:   }

235:   /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't 
236:      stop prematurely do to small residual */
237:   for (i=1; i<levels; i++) {
238:     KSPSetTolerances(mg[i]->smoothu,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
239:     if (mg[i]->smoothu != mg[i]->smoothd) {
240:       KSPSetTolerances(mg[i]->smoothd,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
241:     }
242:   }

244:   *reason = (PCRichardsonConvergedReason)0;
245:   for (i=0; i<its; i++) {
246:     PCMGMCycle_Private(pc,mg+levels-1,reason);
247:     if (*reason) break;
248:   }
249:   if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS;
250:   *outits = i;
251:   return(0);
252: }

256: PetscErrorCode PCSetFromOptions_MG(PC pc)
257: {
259:   PetscInt       m,levels = 1,cycles;
260:   PetscTruth     flg;
261:   PC_MG          **mg = (PC_MG**)pc->data;
262:   PCMGType       mgtype = PC_MG_ADDITIVE;
263:   PCMGCycleType  mgctype;

266:   PetscOptionsHead("Multigrid options");
267:     if (!pc->data) {
268:       PetscOptionsInt("-pc_mg_levels","Number of Levels","PCMGSetLevels",levels,&levels,&flg);
269:       PCMGSetLevels(pc,levels,PETSC_NULL);
270:       mg = (PC_MG**)pc->data;
271:     }
272:     mgctype = (PCMGCycleType) mg[0]->cycles;
273:     PetscOptionsEnum("-pc_mg_cycle_type","V cycle or for W-cycle","PCMGSetCycleType",PCMGCycleTypes,(PetscEnum)mgctype,(PetscEnum*)&mgctype,&flg);
274:     if (flg) {
275:       PCMGSetCycleType(pc,mgctype);
276:     };
277:     PetscOptionsName("-pc_mg_galerkin","Use Galerkin process to compute coarser operators","PCMGSetGalerkin",&flg);
278:     if (flg) {
279:       PCMGSetGalerkin(pc);
280:     }
281:     PetscOptionsInt("-pc_mg_smoothup","Number of post-smoothing steps","PCMGSetNumberSmoothUp",1,&m,&flg);
282:     if (flg) {
283:       PCMGSetNumberSmoothUp(pc,m);
284:     }
285:     PetscOptionsInt("-pc_mg_smoothdown","Number of pre-smoothing steps","PCMGSetNumberSmoothDown",1,&m,&flg);
286:     if (flg) {
287:       PCMGSetNumberSmoothDown(pc,m);
288:     }
289:     PetscOptionsEnum("-pc_mg_type","Multigrid type","PCMGSetType",PCMGTypes,(PetscEnum)mgtype,(PetscEnum*)&mgtype,&flg);
290:     if (flg) {
291:       PCMGSetType(pc,mgtype);
292:     }
293:     if (mg[0]->am == PC_MG_MULTIPLICATIVE) {
294:       PetscOptionsInt("-pc_mg_multiplicative_cycles","Number of cycles for each preconditioner step","PCMGSetLevels",mg[0]->cyclesperpcapply,&cycles,&flg);
295:       if (flg) {
296:         PCMGMultiplicativeSetCycles(pc,cycles);
297:       }
298:     }
299:     PetscOptionsName("-pc_mg_log","Log times for each multigrid level","None",&flg);
300:     if (flg) {
301:       PetscInt i;
302:       char     eventname[128];
303:       if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
304:       levels = mg[0]->levels;
305:       for (i=0; i<levels; i++) {
306:         sprintf(eventname,"MGSetup Level %d",(int)i);
307:         PetscLogEventRegister(eventname,((PetscObject)pc)->cookie,&mg[i]->eventsmoothsetup);
308:         sprintf(eventname,"MGSmooth Level %d",(int)i);
309:         PetscLogEventRegister(eventname,((PetscObject)pc)->cookie,&mg[i]->eventsmoothsolve);
310:         if (i) {
311:           sprintf(eventname,"MGResid Level %d",(int)i);
312:           PetscLogEventRegister(eventname,((PetscObject)pc)->cookie,&mg[i]->eventresidual);
313:           sprintf(eventname,"MGInterp Level %d",(int)i);
314:           PetscLogEventRegister(eventname,((PetscObject)pc)->cookie,&mg[i]->eventinterprestrict);
315:         }
316:       }
317:     }
318:   PetscOptionsTail();
319:   return(0);
320: }

322: const char *PCMGTypes[] = {"MULTIPLICATIVE","ADDITIVE","FULL","KASKADE","PCMGType","PC_MG",0};
323: const char *PCMGCycleTypes[] = {"invalid","v","w","PCMGCycleType","PC_MG_CYCLE",0};

327: PetscErrorCode PCView_MG(PC pc,PetscViewer viewer)
328: {
329:   PC_MG          **mg = (PC_MG**)pc->data;
331:   PetscInt       levels = mg[0]->levels,i;
332:   PetscTruth     iascii;

335:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
336:   if (iascii) {
337:     PetscViewerASCIIPrintf(viewer,"  MG: type is %s, levels=%D cycles=%s\n", PCMGTypes[mg[0]->am],levels,(mg[0]->cycles == PC_MG_CYCLE_V) ? "v" : "w");
338:     if (mg[0]->am == PC_MG_MULTIPLICATIVE) {
339:       PetscViewerASCIIPrintf(viewer,"    Cycles per PCApply=%d\n",mg[0]->cyclesperpcapply);
340:     }
341:     if (mg[0]->galerkin) {
342:       PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid matrices\n");
343:     }
344:     for (i=0; i<levels; i++) {
345:       if (!i) {
346:         PetscViewerASCIIPrintf(viewer,"Coarse gride solver -- level %D presmooths=%D postsmooths=%D -----\n",i,mg[0]->default_smoothd,mg[0]->default_smoothu);
347:       } else {
348:         PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D smooths=%D --------------------\n",i,mg[i]->default_smoothd);
349:       }
350:       PetscViewerASCIIPushTab(viewer);
351:       KSPView(mg[i]->smoothd,viewer);
352:       PetscViewerASCIIPopTab(viewer);
353:       if (i && mg[i]->smoothd == mg[i]->smoothu) {
354:         PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n");
355:       } else if (i){
356:         PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D smooths=%D --------------------\n",i,mg[i]->default_smoothu);
357:         PetscViewerASCIIPushTab(viewer);
358:         KSPView(mg[i]->smoothu,viewer);
359:         PetscViewerASCIIPopTab(viewer);
360:       }
361:     }
362:   } else {
363:     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCMG",((PetscObject)viewer)->type_name);
364:   }
365:   return(0);
366: }

368: /*
369:     Calls setup for the KSP on each level
370: */
373: PetscErrorCode PCSetUp_MG(PC pc)
374: {
375:   PC_MG                   **mg = (PC_MG**)pc->data;
376:   PetscErrorCode          ierr;
377:   PetscInt                i,n = mg[0]->levels;
378:   PC                      cpc,mpc;
379:   PetscTruth              preonly,lu,redundant,cholesky,monitor = PETSC_FALSE,dump,opsset;
380:   PetscViewerASCIIMonitor ascii;
381:   PetscViewer             viewer = PETSC_NULL;
382:   MPI_Comm                comm;
383:   Mat                     dA,dB;
384:   MatStructure            uflag;
385:   Vec                     tvec;


389:   /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
390:   /* so use those from global PC */
391:   /* Is this what we always want? What if user wants to keep old one? */
392:   KSPGetOperatorsSet(mg[n-1]->smoothd,PETSC_NULL,&opsset);
393:   KSPGetPC(mg[0]->smoothd,&cpc);
394:   KSPGetPC(mg[n-1]->smoothd,&mpc);
395:   if (!opsset || ((cpc->setupcalled == 1) && (mpc->setupcalled == 2))) {
396:     PetscInfo(pc,"Using outer operators to define finest grid operator \n  because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n");
397:     KSPSetOperators(mg[n-1]->smoothd,pc->mat,pc->pmat,pc->flag);
398:   }

400:   if (mg[0]->galerkin) {
401:     Mat B;
402:     mg[0]->galerkinused = PETSC_TRUE;
403:     /* currently only handle case where mat and pmat are the same on coarser levels */
404:     KSPGetOperators(mg[n-1]->smoothd,&dA,&dB,&uflag);
405:     if (!pc->setupcalled) {
406:       for (i=n-2; i>-1; i--) {
407:         MatPtAP(dB,mg[i+1]->interpolate,MAT_INITIAL_MATRIX,1.0,&B);
408:         KSPSetOperators(mg[i]->smoothd,B,B,uflag);
409:         if (i != n-2) {PetscObjectDereference((PetscObject)dB);}
410:         dB   = B;
411:       }
412:       PetscObjectDereference((PetscObject)dB);
413:     } else {
414:       for (i=n-2; i>-1; i--) {
415:         KSPGetOperators(mg[i]->smoothd,PETSC_NULL,&B,PETSC_NULL);
416:         MatPtAP(dB,mg[i+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);
417:         KSPSetOperators(mg[i]->smoothd,B,B,uflag);
418:         dB   = B;
419:       }
420:     }
421:   }

423:   if (!pc->setupcalled) {
424:     PetscOptionsHasName(0,"-pc_mg_monitor",&monitor);
425: 
426:     for (i=0; i<n; i++) {
427:       if (monitor) {
428:         PetscObjectGetComm((PetscObject)mg[i]->smoothd,&comm);
429:         PetscViewerASCIIMonitorCreate(comm,"stdout",n-i,&ascii);
430:         KSPMonitorSet(mg[i]->smoothd,KSPMonitorDefault,ascii,(PetscErrorCode(*)(void*))PetscViewerASCIIMonitorDestroy);
431:       }
432:       KSPSetFromOptions(mg[i]->smoothd);
433:     }
434:     for (i=1; i<n; i++) {
435:       if (mg[i]->smoothu && (mg[i]->smoothu != mg[i]->smoothd)) {
436:         if (monitor) {
437:           PetscObjectGetComm((PetscObject)mg[i]->smoothu,&comm);
438:           PetscViewerASCIIMonitorCreate(comm,"stdout",n-i,&ascii);
439:           KSPMonitorSet(mg[i]->smoothu,KSPMonitorDefault,ascii,(PetscErrorCode(*)(void*))PetscViewerASCIIMonitorDestroy);
440:         }
441:         KSPSetFromOptions(mg[i]->smoothu);
442:       }
443:     }
444:     for (i=1; i<n; i++) {
445:       if (!mg[i]->residual) {
446:         Mat mat;
447:         KSPGetOperators(mg[i]->smoothd,PETSC_NULL,&mat,PETSC_NULL);
448:         PCMGSetResidual(pc,i,PCMGDefaultResidual,mat);
449:       }
450:       if (mg[i]->restrct && !mg[i]->interpolate) {
451:         PCMGSetInterpolation(pc,i,mg[i]->restrct);
452:       }
453:       if (!mg[i]->restrct && mg[i]->interpolate) {
454:         PCMGSetRestriction(pc,i,mg[i]->interpolate);
455:       }
456: #if defined(PETSC_USE_DEBUG)
457:       if (!mg[i]->restrct || !mg[i]->interpolate) {
458:         SETERRQ1(PETSC_ERR_ARG_WRONGSTATE,"Need to set restriction or interpolation on level %d",(int)i);
459:       }
460: #endif
461:     }
462:     for (i=0; i<n-1; i++) {
463:       if (!mg[i]->b) {
464:         Vec *vec;
465:         KSPGetVecs(mg[i]->smoothd,1,&vec,0,PETSC_NULL);
466:         PCMGSetRhs(pc,i,*vec);
467:         VecDestroy(*vec);
468:         PetscFree(vec);
469:       }
470:       if (!mg[i]->r && i) {
471:         VecDuplicate(mg[i]->b,&tvec);
472:         PCMGSetR(pc,i,tvec);
473:         VecDestroy(tvec);
474:       }
475:       if (!mg[i]->x) {
476:         VecDuplicate(mg[i]->b,&tvec);
477:         PCMGSetX(pc,i,tvec);
478:         VecDestroy(tvec);
479:       }
480:     }
481:     if (n != 1 && !mg[n-1]->r) {
482:       /* PCMGSetR() on the finest level if user did not supply it */
483:       Vec *vec;
484:       KSPGetVecs(mg[n-1]->smoothd,1,&vec,0,PETSC_NULL);
485:       PCMGSetR(pc,n-1,*vec);
486:       VecDestroy(*vec);
487:       PetscFree(vec);
488:     }
489:   }


492:   for (i=1; i<n; i++) {
493:     if (mg[i]->smoothu == mg[i]->smoothd) {
494:       /* if doing only down then initial guess is zero */
495:       KSPSetInitialGuessNonzero(mg[i]->smoothd,PETSC_TRUE);
496:     }
497:     if (mg[i]->eventsmoothsetup) {PetscLogEventBegin(mg[i]->eventsmoothsetup,0,0,0,0);}
498:     KSPSetUp(mg[i]->smoothd);
499:     if (mg[i]->eventsmoothsetup) {PetscLogEventEnd(mg[i]->eventsmoothsetup,0,0,0,0);}
500:   }
501:   for (i=1; i<n; i++) {
502:     if (mg[i]->smoothu && mg[i]->smoothu != mg[i]->smoothd) {
503:       Mat          downmat,downpmat;
504:       MatStructure matflag;
505:       PetscTruth   opsset;

507:       /* check if operators have been set for up, if not use down operators to set them */
508:       KSPGetOperatorsSet(mg[i]->smoothu,&opsset,PETSC_NULL);
509:       if (!opsset) {
510:         KSPGetOperators(mg[i]->smoothd,&downmat,&downpmat,&matflag);
511:         KSPSetOperators(mg[i]->smoothu,downmat,downpmat,matflag);
512:       }

514:       KSPSetInitialGuessNonzero(mg[i]->smoothu,PETSC_TRUE);
515:       if (mg[i]->eventsmoothsetup) {PetscLogEventBegin(mg[i]->eventsmoothsetup,0,0,0,0);}
516:       KSPSetUp(mg[i]->smoothu);
517:       if (mg[i]->eventsmoothsetup) {PetscLogEventEnd(mg[i]->eventsmoothsetup,0,0,0,0);}
518:     }
519:   }

521:   /*
522:       If coarse solver is not direct method then DO NOT USE preonly 
523:   */
524:   PetscTypeCompare((PetscObject)mg[0]->smoothd,KSPPREONLY,&preonly);
525:   if (preonly) {
526:     PetscTypeCompare((PetscObject)cpc,PCLU,&lu);
527:     PetscTypeCompare((PetscObject)cpc,PCREDUNDANT,&redundant);
528:     PetscTypeCompare((PetscObject)cpc,PCCHOLESKY,&cholesky);
529:     if (!lu && !redundant && !cholesky) {
530:       KSPSetType(mg[0]->smoothd,KSPGMRES);
531:     }
532:   }

534:   if (!pc->setupcalled) {
535:     if (monitor) {
536:       PetscObjectGetComm((PetscObject)mg[0]->smoothd,&comm);
537:       PetscViewerASCIIMonitorCreate(comm,"stdout",n,&ascii);
538:       KSPMonitorSet(mg[0]->smoothd,KSPMonitorDefault,ascii,(PetscErrorCode(*)(void*))PetscViewerASCIIMonitorDestroy);
539:     }
540:     KSPSetFromOptions(mg[0]->smoothd);
541:   }

543:   if (mg[0]->eventsmoothsetup) {PetscLogEventBegin(mg[0]->eventsmoothsetup,0,0,0,0);}
544:   KSPSetUp(mg[0]->smoothd);
545:   if (mg[0]->eventsmoothsetup) {PetscLogEventEnd(mg[0]->eventsmoothsetup,0,0,0,0);}

547:   /*
548:      Dump the interpolation/restriction matrices plus the 
549:    Jacobian/stiffness on each level. This allows Matlab users to 
550:    easily check if the Galerkin condition A_c = R A_f R^T is satisfied.

552:    Only support one or the other at the same time.
553:   */
554: #if defined(PETSC_USE_SOCKET_VIEWER)
555:   PetscOptionsHasName(((PetscObject)pc)->prefix,"-pc_mg_dump_matlab",&dump);
556:   if (dump) {
557:     viewer = PETSC_VIEWER_SOCKET_(((PetscObject)pc)->comm);
558:   }
559: #endif
560:   PetscOptionsHasName(((PetscObject)pc)->prefix,"-pc_mg_dump_binary",&dump);
561:   if (dump) {
562:     viewer = PETSC_VIEWER_BINARY_(((PetscObject)pc)->comm);
563:   }

565:   if (viewer) {
566:     for (i=1; i<n; i++) {
567:       MatView(mg[i]->restrct,viewer);
568:     }
569:     for (i=0; i<n; i++) {
570:       KSPGetPC(mg[i]->smoothd,&pc);
571:       MatView(pc->mat,viewer);
572:     }
573:   }
574:   return(0);
575: }

577: /* -------------------------------------------------------------------------------------*/

581: /*@C
582:    PCMGSetLevels - Sets the number of levels to use with MG.
583:    Must be called before any other MG routine.

585:    Collective on PC

587:    Input Parameters:
588: +  pc - the preconditioner context
589: .  levels - the number of levels
590: -  comms - optional communicators for each level; this is to allow solving the coarser problems
591:            on smaller sets of processors. Use PETSC_NULL_OBJECT for default in Fortran

593:    Level: intermediate

595:    Notes:
596:      If the number of levels is one then the multigrid uses the -mg_levels prefix
597:   for setting the level options rather than the -mg_coarse prefix.

599: .keywords: MG, set, levels, multigrid

601: .seealso: PCMGSetType(), PCMGGetLevels()
602: @*/
603: PetscErrorCode  PCMGSetLevels(PC pc,PetscInt levels,MPI_Comm *comms)
604: {
606:   PC_MG          **mg=0;


611:   if (pc->data) {
612:     SETERRQ(PETSC_ERR_ORDER,"Number levels already set for MG\n\
613:     make sure that you call PCMGSetLevels() before KSPSetFromOptions()");
614:   }
615:   PCMGCreate_Private(((PetscObject)pc)->comm,levels,pc,comms,&mg);
616:   mg[0]->am                = PC_MG_MULTIPLICATIVE;
617:   pc->data                 = (void*)mg;
618:   pc->ops->applyrichardson = PCApplyRichardson_MG;
619:   return(0);
620: }

624: /*@
625:    PCMGGetLevels - Gets the number of levels to use with MG.

627:    Not Collective

629:    Input Parameter:
630: .  pc - the preconditioner context

632:    Output parameter:
633: .  levels - the number of levels

635:    Level: advanced

637: .keywords: MG, get, levels, multigrid

639: .seealso: PCMGSetLevels()
640: @*/
641: PetscErrorCode  PCMGGetLevels(PC pc,PetscInt *levels)
642: {
643:   PC_MG  **mg;


649:   mg      = (PC_MG**)pc->data;
650:   *levels = mg[0]->levels;
651:   return(0);
652: }

656: /*@
657:    PCMGSetType - Determines the form of multigrid to use:
658:    multiplicative, additive, full, or the Kaskade algorithm.

660:    Collective on PC

662:    Input Parameters:
663: +  pc - the preconditioner context
664: -  form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,
665:    PC_MG_FULL, PC_MG_KASKADE

667:    Options Database Key:
668: .  -pc_mg_type <form> - Sets <form>, one of multiplicative,
669:    additive, full, kaskade   

671:    Level: advanced

673: .keywords: MG, set, method, multiplicative, additive, full, Kaskade, multigrid

675: .seealso: PCMGSetLevels()
676: @*/
677: PetscErrorCode  PCMGSetType(PC pc,PCMGType form)
678: {
679:   PC_MG **mg;

683:   mg = (PC_MG**)pc->data;

685:   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
686:   mg[0]->am = form;
687:   if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
688:   else pc->ops->applyrichardson = 0;
689:   return(0);
690: }

694: /*@
695:    PCMGSetCycleType - Sets the type cycles to use.  Use PCMGSetCycleTypeOnLevel() for more 
696:    complicated cycling.

698:    Collective on PC

700:    Input Parameters:
701: +  pc - the multigrid context 
702: -  PC_MG_CYCLE_V or PC_MG_CYCLE_W

704:    Options Database Key:
705: $  -pc_mg_cycle_type v or w

707:    Level: advanced

709: .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid

711: .seealso: PCMGSetCycleTypeOnLevel()
712: @*/
713: PetscErrorCode  PCMGSetCycleType(PC pc,PCMGCycleType n)
714: {
715:   PC_MG    **mg;
716:   PetscInt i,levels;

720:   mg     = (PC_MG**)pc->data;
721:   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
722:   levels = mg[0]->levels;

724:   for (i=0; i<levels; i++) {
725:     mg[i]->cycles  = n;
726:   }
727:   return(0);
728: }

732: /*@
733:    PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step 
734:          of multigrid when PCMGType of PC_MG_MULTIPLICATIVE is used

736:    Collective on PC

738:    Input Parameters:
739: +  pc - the multigrid context 
740: -  n - number of cycles (default is 1)

742:    Options Database Key:
743: $  -pc_mg_multiplicative_cycles n

745:    Level: advanced

747:    Notes: This is not associated with setting a v or w cycle, that is set with PCMGSetCycleType()

749: .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid

751: .seealso: PCMGSetCycleTypeOnLevel(), PCMGSetCycleType()
752: @*/
753: PetscErrorCode  PCMGMultiplicativeSetCycles(PC pc,PetscInt n)
754: {
755:   PC_MG    **mg;
756:   PetscInt i,levels;

760:   mg     = (PC_MG**)pc->data;
761:   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
762:   levels = mg[0]->levels;

764:   for (i=0; i<levels; i++) {
765:     mg[i]->cyclesperpcapply  = n;
766:   }
767:   return(0);
768: }

772: /*@
773:    PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
774:       finest grid via the Galerkin process: A_i-1 = r_i * A_i * r_i^t

776:    Collective on PC

778:    Input Parameters:
779: .  pc - the multigrid context 

781:    Options Database Key:
782: $  -pc_mg_galerkin

784:    Level: intermediate

786: .keywords: MG, set, Galerkin

788: .seealso: PCMGGetGalerkin()

790: @*/
791: PetscErrorCode  PCMGSetGalerkin(PC pc)
792: {
793:   PC_MG    **mg;
794:   PetscInt i,levels;

798:   mg     = (PC_MG**)pc->data;
799:   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
800:   levels = mg[0]->levels;

802:   for (i=0; i<levels; i++) {
803:     mg[i]->galerkin = PETSC_TRUE;
804:   }
805:   return(0);
806: }

810: /*@
811:    PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e.
812:       A_i-1 = r_i * A_i * r_i^t

814:    Not Collective

816:    Input Parameter:
817: .  pc - the multigrid context 

819:    Output Parameter:
820: .  gelerkin - PETSC_TRUE or PETSC_FALSE

822:    Options Database Key:
823: $  -pc_mg_galerkin

825:    Level: intermediate

827: .keywords: MG, set, Galerkin

829: .seealso: PCMGSetGalerkin()

831: @*/
832: PetscErrorCode  PCMGGetGalerkin(PC pc,PetscTruth *galerkin)
833: {
834:   PC_MG    **mg;

838:   mg     = (PC_MG**)pc->data;
839:   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
840:   *galerkin = mg[0]->galerkin;
841:   return(0);
842: }

846: /*@
847:    PCMGSetNumberSmoothDown - Sets the number of pre-smoothing steps to
848:    use on all levels. Use PCMGGetSmootherDown() to set different 
849:    pre-smoothing steps on different levels.

851:    Collective on PC

853:    Input Parameters:
854: +  mg - the multigrid context 
855: -  n - the number of smoothing steps

857:    Options Database Key:
858: .  -pc_mg_smoothdown <n> - Sets number of pre-smoothing steps

860:    Level: advanced

862: .keywords: MG, smooth, down, pre-smoothing, steps, multigrid

864: .seealso: PCMGSetNumberSmoothUp()
865: @*/
866: PetscErrorCode  PCMGSetNumberSmoothDown(PC pc,PetscInt n)
867: {
868:   PC_MG          **mg;
870:   PetscInt       i,levels;

874:   mg     = (PC_MG**)pc->data;
875:   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
876:   levels = mg[0]->levels;

878:   for (i=1; i<levels; i++) {
879:     /* make sure smoother up and down are different */
880:     PCMGGetSmootherUp(pc,i,PETSC_NULL);
881:     KSPSetTolerances(mg[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);
882:     mg[i]->default_smoothd = n;
883:   }
884:   return(0);
885: }

889: /*@
890:    PCMGSetNumberSmoothUp - Sets the number of post-smoothing steps to use 
891:    on all levels. Use PCMGGetSmootherUp() to set different numbers of 
892:    post-smoothing steps on different levels.

894:    Collective on PC

896:    Input Parameters:
897: +  mg - the multigrid context 
898: -  n - the number of smoothing steps

900:    Options Database Key:
901: .  -pc_mg_smoothup <n> - Sets number of post-smoothing steps

903:    Level: advanced

905:    Note: this does not set a value on the coarsest grid, since we assume that
906:     there is no separate smooth up on the coarsest grid.

908: .keywords: MG, smooth, up, post-smoothing, steps, multigrid

910: .seealso: PCMGSetNumberSmoothDown()
911: @*/
912: PetscErrorCode  PCMGSetNumberSmoothUp(PC pc,PetscInt n)
913: {
914:   PC_MG          **mg;
916:   PetscInt       i,levels;

920:   mg     = (PC_MG**)pc->data;
921:   if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
922:   levels = mg[0]->levels;

924:   for (i=1; i<levels; i++) {
925:     /* make sure smoother up and down are different */
926:     PCMGGetSmootherUp(pc,i,PETSC_NULL);
927:     KSPSetTolerances(mg[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);
928:     mg[i]->default_smoothu = n;
929:   }
930:   return(0);
931: }

933: /* ----------------------------------------------------------------------------------------*/

935: /*MC
936:    PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional
937:     information about the coarser grid matrices and restriction/interpolation operators.

939:    Options Database Keys:
940: +  -pc_mg_levels <nlevels> - number of levels including finest
941: .  -pc_mg_cycles v or w
942: .  -pc_mg_smoothup <n> - number of smoothing steps after interpolation
943: .  -pc_mg_smoothdown <n> - number of smoothing steps before applying restriction operator
944: .  -pc_mg_type <additive,multiplicative,full,cascade> - multiplicative is the default
945: .  -pc_mg_log - log information about time spent on each level of the solver
946: .  -pc_mg_monitor - print information on the multigrid convergence
947: .  -pc_mg_galerkin - use Galerkin process to compute coarser operators
948: -  -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices
949:                         to the Socket viewer for reading from Matlab.

951:    Notes:

953:    Level: intermediate

955:    Concepts: multigrid/multilevel

957: .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType, 
958:            PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), PCMGSetCycleType(), PCMGSetNumberSmoothDown(),
959:            PCMGSetNumberSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(),
960:            PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(),
961:            PCMGSetCycleTypeOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR()           
962: M*/

967: PetscErrorCode  PCCreate_MG(PC pc)
968: {
970:   pc->ops->apply          = PCApply_MG;
971:   pc->ops->setup          = PCSetUp_MG;
972:   pc->ops->destroy        = PCDestroy_MG;
973:   pc->ops->setfromoptions = PCSetFromOptions_MG;
974:   pc->ops->view           = PCView_MG;

976:   pc->data                = (void*)0;
977:   return(0);
978: }