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_Levels **mglevelsin,PCRichardsonConvergedReason *reason)
12: {
13: PC_MG *mg = (PC_MG*)pc->data;
14: PC_MG_Levels *mgc,*mglevels = *mglevelsin;
16: PetscInt cycles = (mglevels->level == 1) ? 1 : (PetscInt) mglevels->cycles;
20: if (mg->eventsmoothsolve) {PetscLogEventBegin(mg->eventsmoothsolve,0,0,0,0);}
21: KSPSolve(mglevels->smoothd,mglevels->b,mglevels->x); /* pre-smooth */
22: if (mg->eventsmoothsolve) {PetscLogEventEnd(mg->eventsmoothsolve,0,0,0,0);}
23: if (mglevels->level) { /* not the coarsest grid */
24: if (mg->eventresidual) {PetscLogEventBegin(mg->eventresidual,0,0,0,0);}
25: (*mglevels->residual)(mglevels->A,mglevels->b,mglevels->x,mglevels->r);
26: if (mg->eventresidual) {PetscLogEventEnd(mg->eventresidual,0,0,0,0);}
28: /* if on finest level and have convergence criteria set */
29: if (mglevels->level == mglevels->levels-1 && mg->ttol && reason) {
30: PetscReal rnorm;
31: VecNorm(mglevels->r,NORM_2,&rnorm);
32: if (rnorm <= mg->ttol) {
33: if (rnorm < mg->abstol) {
34: *reason = PCRICHARDSON_CONVERGED_ATOL;
35: PetscInfo2(pc,"Linear solver has converged. Residual norm %G is less than absolute tolerance %G\n",rnorm,mg->abstol);
36: } else {
37: *reason = PCRICHARDSON_CONVERGED_RTOL;
38: PetscInfo2(pc,"Linear solver has converged. Residual norm %G is less than relative tolerance times initial residual norm %G\n",rnorm,mg->ttol);
39: }
40: return(0);
41: }
42: }
44: mgc = *(mglevelsin - 1);
45: if (mg->eventinterprestrict) {PetscLogEventBegin(mg->eventinterprestrict,0,0,0,0);}
46: MatRestrict(mglevels->restrct,mglevels->r,mgc->b);
47: if (mg->eventinterprestrict) {PetscLogEventEnd(mg->eventinterprestrict,0,0,0,0);}
48: VecSet(mgc->x,0.0);
49: while (cycles--) {
50: PCMGMCycle_Private(pc,mglevelsin-1,reason);
51: }
52: if (mg->eventinterprestrict) {PetscLogEventBegin(mg->eventinterprestrict,0,0,0,0);}
53: MatInterpolateAdd(mglevels->interpolate,mgc->x,mglevels->x,mglevels->x);
54: if (mg->eventinterprestrict) {PetscLogEventEnd(mg->eventinterprestrict,0,0,0,0);}
55: if (mg->eventsmoothsolve) {PetscLogEventBegin(mg->eventsmoothsolve,0,0,0,0);}
56: KSPSolve(mglevels->smoothu,mglevels->b,mglevels->x); /* post smooth */
57: if (mg->eventsmoothsolve) {PetscLogEventEnd(mg->eventsmoothsolve,0,0,0,0);}
58: }
59: return(0);
60: }
64: static PetscErrorCode PCApplyRichardson_MG(PC pc,Vec b,Vec x,Vec w,PetscReal rtol,PetscReal abstol, PetscReal dtol,PetscInt its,PetscTruth zeroguess,PetscInt *outits,PCRichardsonConvergedReason *reason)
65: {
66: PC_MG *mg = (PC_MG*)pc->data;
67: PC_MG_Levels **mglevels = mg->levels;
69: PetscInt levels = mglevels[0]->levels,i;
72: mglevels[levels-1]->b = b;
73: mglevels[levels-1]->x = x;
75: mg->rtol = rtol;
76: mg->abstol = abstol;
77: mg->dtol = dtol;
78: if (rtol) {
79: /* compute initial residual norm for relative convergence test */
80: PetscReal rnorm;
81: if (zeroguess) {
82: VecNorm(b,NORM_2,&rnorm);
83: } else {
84: (*mglevels[levels-1]->residual)(mglevels[levels-1]->A,b,x,w);
85: VecNorm(w,NORM_2,&rnorm);
86: }
87: mg->ttol = PetscMax(rtol*rnorm,abstol);
88: } else if (abstol) {
89: mg->ttol = abstol;
90: } else {
91: mg->ttol = 0.0;
92: }
94: /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't
95: stop prematurely do to small residual */
96: for (i=1; i<levels; i++) {
97: KSPSetTolerances(mglevels[i]->smoothu,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
98: if (mglevels[i]->smoothu != mglevels[i]->smoothd) {
99: KSPSetTolerances(mglevels[i]->smoothd,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
100: }
101: }
103: *reason = (PCRichardsonConvergedReason)0;
104: for (i=0; i<its; i++) {
105: PCMGMCycle_Private(pc,mglevels+levels-1,reason);
106: if (*reason) break;
107: }
108: if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS;
109: *outits = i;
110: return(0);
111: }
115: /*@C
116: PCMGSetLevels - Sets the number of levels to use with MG.
117: Must be called before any other MG routine.
119: Collective on PC
121: Input Parameters:
122: + pc - the preconditioner context
123: . levels - the number of levels
124: - comms - optional communicators for each level; this is to allow solving the coarser problems
125: on smaller sets of processors. Use PETSC_NULL_OBJECT for default in Fortran
127: Level: intermediate
129: Notes:
130: If the number of levels is one then the multigrid uses the -mg_levels prefix
131: for setting the level options rather than the -mg_coarse prefix.
133: .keywords: MG, set, levels, multigrid
135: .seealso: PCMGSetType(), PCMGGetLevels()
136: @*/
137: PetscErrorCode PCMGSetLevels(PC pc,PetscInt levels,MPI_Comm *comms)
138: {
140: PC_MG *mg = (PC_MG*)pc->data;
141: MPI_Comm comm = ((PetscObject)pc)->comm;
142: PC_MG_Levels **mglevels;
143: PetscInt i;
144: PetscMPIInt size;
145: const char *prefix;
146: PC ipc;
150: if (mg->nlevels > -1) {
151: SETERRQ(PETSC_ERR_ORDER,"Number levels already set for MG\n make sure that you call PCMGSetLevels() before KSPSetFromOptions()");
152: }
153: if (mg->levels) SETERRQ(PETSC_ERR_PLIB,"Internal error in PETSc, this array should not yet exist");
155: mg->nlevels = levels;
157: PetscMalloc(levels*sizeof(PC_MG*),&mglevels);
158: PetscLogObjectMemory(pc,levels*(sizeof(PC_MG*)));
160: PCGetOptionsPrefix(pc,&prefix);
162: for (i=0; i<levels; i++) {
163: PetscNewLog(pc,PC_MG_Levels,&mglevels[i]);
164: mglevels[i]->level = i;
165: mglevels[i]->levels = levels;
166: mglevels[i]->cycles = PC_MG_CYCLE_V;
167: mglevels[i]->galerkin = PETSC_FALSE;
168: mglevels[i]->galerkinused = PETSC_FALSE;
169: mg->default_smoothu = 1;
170: mg->default_smoothd = 1;
172: if (comms) comm = comms[i];
173: KSPCreate(comm,&mglevels[i]->smoothd);
174: PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd,(PetscObject)pc,levels-i);
175: KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, mg->default_smoothd);
176: KSPSetOptionsPrefix(mglevels[i]->smoothd,prefix);
178: /* do special stuff for coarse grid */
179: if (!i && levels > 1) {
180: KSPAppendOptionsPrefix(mglevels[0]->smoothd,"mg_coarse_");
182: /* coarse solve is (redundant) LU by default */
183: KSPSetType(mglevels[0]->smoothd,KSPPREONLY);
184: KSPGetPC(mglevels[0]->smoothd,&ipc);
185: MPI_Comm_size(comm,&size);
186: if (size > 1) {
187: PCSetType(ipc,PCREDUNDANT);
188: } else {
189: PCSetType(ipc,PCLU);
190: }
192: } else {
193: char tprefix[128];
194: sprintf(tprefix,"mg_levels_%d_",(int)i);
195: KSPAppendOptionsPrefix(mglevels[i]->smoothd,tprefix);
196: }
197: PetscLogObjectParent(pc,mglevels[i]->smoothd);
198: mglevels[i]->smoothu = mglevels[i]->smoothd;
199: mg->rtol = 0.0;
200: mg->abstol = 0.0;
201: mg->dtol = 0.0;
202: mg->ttol = 0.0;
203: mg->eventsmoothsetup = 0;
204: mg->eventsmoothsolve = 0;
205: mg->eventresidual = 0;
206: mg->eventinterprestrict = 0;
207: mg->cyclesperpcapply = 1;
208: }
209: mg->am = PC_MG_MULTIPLICATIVE;
210: mg->levels = mglevels;
211: pc->ops->applyrichardson = PCApplyRichardson_MG;
212: return(0);
213: }
217: PetscErrorCode PCDestroy_MG_Private(PC pc)
218: {
219: PC_MG *mg = (PC_MG*)pc->data;
220: PC_MG_Levels **mglevels = mg->levels;
222: PetscInt i,n;
225: if (mglevels) {
226: n = mglevels[0]->levels;
227: for (i=0; i<n-1; i++) {
228: if (mglevels[i+1]->r) {VecDestroy(mglevels[i+1]->r);}
229: if (mglevels[i]->b) {VecDestroy(mglevels[i]->b);}
230: if (mglevels[i]->x) {VecDestroy(mglevels[i]->x);}
231: if (mglevels[i+1]->restrct) {MatDestroy(mglevels[i+1]->restrct);}
232: if (mglevels[i+1]->interpolate) {MatDestroy(mglevels[i+1]->interpolate);}
233: }
235: for (i=0; i<n; i++) {
236: if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
237: KSPDestroy(mglevels[i]->smoothd);
238: }
239: KSPDestroy(mglevels[i]->smoothu);
240: PetscFree(mglevels[i]);
241: }
242: PetscFree(mglevels);
243: }
244: mg->nlevels = -1;
245: mg->levels = PETSC_NULL;
246: return(0);
247: }
251: PetscErrorCode PCDestroy_MG(PC pc)
252: {
253: PC_MG *mg = (PC_MG*)pc->data;
257: PCDestroy_MG_Private(pc);
258: PetscFree(mg);
259: return(0);
260: }
264: EXTERN PetscErrorCode PCMGACycle_Private(PC,PC_MG_Levels**);
265: EXTERN PetscErrorCode PCMGFCycle_Private(PC,PC_MG_Levels**);
266: EXTERN PetscErrorCode PCMGKCycle_Private(PC,PC_MG_Levels**);
268: /*
269: PCApply_MG - Runs either an additive, multiplicative, Kaskadic
270: or full cycle of multigrid.
272: Note:
273: A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
274: */
277: static PetscErrorCode PCApply_MG(PC pc,Vec b,Vec x)
278: {
279: PC_MG *mg = (PC_MG*)pc->data;
280: PC_MG_Levels **mglevels = mg->levels;
282: PetscInt levels = mglevels[0]->levels,i;
285: mglevels[levels-1]->b = b;
286: mglevels[levels-1]->x = x;
287: if (mg->am == PC_MG_MULTIPLICATIVE) {
288: VecSet(x,0.0);
289: for (i=0; i<mg->cyclesperpcapply; i++) {
290: PCMGMCycle_Private(pc,mglevels+levels-1,PETSC_NULL);
291: }
292: }
293: else if (mg->am == PC_MG_ADDITIVE) {
294: PCMGACycle_Private(pc,mglevels);
295: }
296: else if (mg->am == PC_MG_KASKADE) {
297: PCMGKCycle_Private(pc,mglevels);
298: }
299: else {
300: PCMGFCycle_Private(pc,mglevels);
301: }
302: return(0);
303: }
308: PetscErrorCode PCSetFromOptions_MG(PC pc)
309: {
311: PetscInt m,levels = 1,cycles;
312: PetscTruth flg;
313: PC_MG *mg = (PC_MG*)pc->data;
314: PC_MG_Levels **mglevels = mg->levels;
315: PCMGType mgtype;
316: PCMGCycleType mgctype;
319: PetscOptionsHead("Multigrid options");
320: if (!pc->data) {
321: PetscOptionsInt("-pc_mg_levels","Number of Levels","PCMGSetLevels",levels,&levels,&flg);
322: PCMGSetLevels(pc,levels,PETSC_NULL);
323: mglevels = mg->levels;
324: }
325: mgctype = (PCMGCycleType) mglevels[0]->cycles;
326: PetscOptionsEnum("-pc_mg_cycle_type","V cycle or for W-cycle","PCMGSetCycleType",PCMGCycleTypes,(PetscEnum)mgctype,(PetscEnum*)&mgctype,&flg);
327: if (flg) {
328: PCMGSetCycleType(pc,mgctype);
329: };
330: flg = PETSC_FALSE;
331: PetscOptionsTruth("-pc_mg_galerkin","Use Galerkin process to compute coarser operators","PCMGSetGalerkin",flg,&flg,PETSC_NULL);
332: if (flg) {
333: PCMGSetGalerkin(pc);
334: }
335: PetscOptionsInt("-pc_mg_smoothup","Number of post-smoothing steps","PCMGSetNumberSmoothUp",1,&m,&flg);
336: if (flg) {
337: PCMGSetNumberSmoothUp(pc,m);
338: }
339: PetscOptionsInt("-pc_mg_smoothdown","Number of pre-smoothing steps","PCMGSetNumberSmoothDown",1,&m,&flg);
340: if (flg) {
341: PCMGSetNumberSmoothDown(pc,m);
342: }
343: mgtype = mg->am;
344: PetscOptionsEnum("-pc_mg_type","Multigrid type","PCMGSetType",PCMGTypes,(PetscEnum)mgtype,(PetscEnum*)&mgtype,&flg);
345: if (flg) {
346: PCMGSetType(pc,mgtype);
347: }
348: if (mg->am == PC_MG_MULTIPLICATIVE) {
349: PetscOptionsInt("-pc_mg_multiplicative_cycles","Number of cycles for each preconditioner step","PCMGSetLevels",mg->cyclesperpcapply,&cycles,&flg);
350: if (flg) {
351: PCMGMultiplicativeSetCycles(pc,cycles);
352: }
353: }
354: flg = PETSC_FALSE;
355: PetscOptionsTruth("-pc_mg_log","Log times for each multigrid level","None",flg,&flg,PETSC_NULL);
356: if (flg) {
357: PetscInt i;
358: char eventname[128];
359: if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
360: levels = mglevels[0]->levels;
361: for (i=0; i<levels; i++) {
362: sprintf(eventname,"MGSetup Level %d",(int)i);
363: PetscLogEventRegister(eventname,((PetscObject)pc)->cookie,&mg->eventsmoothsetup);
364: sprintf(eventname,"MGSmooth Level %d",(int)i);
365: PetscLogEventRegister(eventname,((PetscObject)pc)->cookie,&mg->eventsmoothsolve);
366: if (i) {
367: sprintf(eventname,"MGResid Level %d",(int)i);
368: PetscLogEventRegister(eventname,((PetscObject)pc)->cookie,&mg->eventresidual);
369: sprintf(eventname,"MGInterp Level %d",(int)i);
370: PetscLogEventRegister(eventname,((PetscObject)pc)->cookie,&mg->eventinterprestrict);
371: }
372: }
373: }
374: PetscOptionsTail();
375: return(0);
376: }
378: const char *PCMGTypes[] = {"MULTIPLICATIVE","ADDITIVE","FULL","KASKADE","PCMGType","PC_MG",0};
379: const char *PCMGCycleTypes[] = {"invalid","v","w","PCMGCycleType","PC_MG_CYCLE",0};
383: PetscErrorCode PCView_MG(PC pc,PetscViewer viewer)
384: {
385: PC_MG *mg = (PC_MG*)pc->data;
386: PC_MG_Levels **mglevels = mg->levels;
388: PetscInt levels = mglevels[0]->levels,i;
389: PetscTruth iascii;
392: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
393: if (iascii) {
394: PetscViewerASCIIPrintf(viewer," MG: type is %s, levels=%D cycles=%s\n", PCMGTypes[mg->am],levels,(mglevels[0]->cycles == PC_MG_CYCLE_V) ? "v" : "w");
395: if (mg->am == PC_MG_MULTIPLICATIVE) {
396: PetscViewerASCIIPrintf(viewer," Cycles per PCApply=%d\n",mg->cyclesperpcapply);
397: }
398: if (mglevels[0]->galerkin) {
399: PetscViewerASCIIPrintf(viewer," Using Galerkin computed coarse grid matrices\n");
400: }
401: for (i=0; i<levels; i++) {
402: if (!i) {
403: PetscViewerASCIIPrintf(viewer,"Coarse grid solver -- level %D presmooths=%D postsmooths=%D -----\n",i,mg->default_smoothd,mg->default_smoothu);
404: } else {
405: PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D smooths=%D --------------------\n",i,mg->default_smoothd);
406: }
407: PetscViewerASCIIPushTab(viewer);
408: KSPView(mglevels[i]->smoothd,viewer);
409: PetscViewerASCIIPopTab(viewer);
410: if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) {
411: PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n");
412: } else if (i){
413: PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D smooths=%D --------------------\n",i,mg->default_smoothu);
414: PetscViewerASCIIPushTab(viewer);
415: KSPView(mglevels[i]->smoothu,viewer);
416: PetscViewerASCIIPopTab(viewer);
417: }
418: }
419: } else {
420: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCMG",((PetscObject)viewer)->type_name);
421: }
422: return(0);
423: }
425: /*
426: Calls setup for the KSP on each level
427: */
430: PetscErrorCode PCSetUp_MG(PC pc)
431: {
432: PC_MG *mg = (PC_MG*)pc->data;
433: PC_MG_Levels **mglevels = mg->levels;
434: PetscErrorCode ierr;
435: PetscInt i,n = mglevels[0]->levels;
436: PC cpc,mpc;
437: PetscTruth preonly,lu,redundant,cholesky,monitor = PETSC_FALSE,dump = PETSC_FALSE,opsset;
438: PetscViewerASCIIMonitor ascii;
439: PetscViewer viewer = PETSC_NULL;
440: MPI_Comm comm;
441: Mat dA,dB;
442: MatStructure uflag;
443: Vec tvec;
447: /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
448: /* so use those from global PC */
449: /* Is this what we always want? What if user wants to keep old one? */
450: KSPGetOperatorsSet(mglevels[n-1]->smoothd,PETSC_NULL,&opsset);
451: KSPGetPC(mglevels[0]->smoothd,&cpc);
452: KSPGetPC(mglevels[n-1]->smoothd,&mpc);
453: if (!opsset || ((cpc->setupcalled == 1) && (mpc->setupcalled == 2)) || ((mpc == cpc) && (mpc->setupcalled == 2))) {
454: PetscInfo(pc,"Using outer operators to define finest grid operator \n because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n");
455: KSPSetOperators(mglevels[n-1]->smoothd,pc->mat,pc->pmat,pc->flag);
456: }
458: if (mglevels[0]->galerkin) {
459: Mat B;
460: mglevels[0]->galerkinused = PETSC_TRUE;
461: /* currently only handle case where mat and pmat are the same on coarser levels */
462: KSPGetOperators(mglevels[n-1]->smoothd,&dA,&dB,&uflag);
463: if (!pc->setupcalled) {
464: for (i=n-2; i>-1; i--) {
465: MatPtAP(dB,mglevels[i+1]->interpolate,MAT_INITIAL_MATRIX,1.0,&B);
466: KSPSetOperators(mglevels[i]->smoothd,B,B,uflag);
467: if (i != n-2) {PetscObjectDereference((PetscObject)dB);}
468: dB = B;
469: }
470: PetscObjectDereference((PetscObject)dB);
471: } else {
472: for (i=n-2; i>-1; i--) {
473: KSPGetOperators(mglevels[i]->smoothd,PETSC_NULL,&B,PETSC_NULL);
474: MatPtAP(dB,mglevels[i+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);
475: KSPSetOperators(mglevels[i]->smoothd,B,B,uflag);
476: dB = B;
477: }
478: }
479: }
481: if (!pc->setupcalled) {
482: PetscOptionsGetTruth(0,"-pc_mg_monitor",&monitor,PETSC_NULL);
483:
484: for (i=0; i<n; i++) {
485: if (monitor) {
486: PetscObjectGetComm((PetscObject)mglevels[i]->smoothd,&comm);
487: PetscViewerASCIIMonitorCreate(comm,"stdout",n-i,&ascii);
488: KSPMonitorSet(mglevels[i]->smoothd,KSPMonitorDefault,ascii,(PetscErrorCode(*)(void*))PetscViewerASCIIMonitorDestroy);
489: }
490: KSPSetFromOptions(mglevels[i]->smoothd);
491: }
492: for (i=1; i<n; i++) {
493: if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) {
494: if (monitor) {
495: PetscObjectGetComm((PetscObject)mglevels[i]->smoothu,&comm);
496: PetscViewerASCIIMonitorCreate(comm,"stdout",n-i,&ascii);
497: KSPMonitorSet(mglevels[i]->smoothu,KSPMonitorDefault,ascii,(PetscErrorCode(*)(void*))PetscViewerASCIIMonitorDestroy);
498: }
499: KSPSetFromOptions(mglevels[i]->smoothu);
500: }
501: }
502: for (i=1; i<n; i++) {
503: if (!mglevels[i]->residual) {
504: Mat mat;
505: KSPGetOperators(mglevels[i]->smoothd,PETSC_NULL,&mat,PETSC_NULL);
506: PCMGSetResidual(pc,i,PCMGDefaultResidual,mat);
507: }
508: if (mglevels[i]->restrct && !mglevels[i]->interpolate) {
509: PCMGSetInterpolation(pc,i,mglevels[i]->restrct);
510: }
511: if (!mglevels[i]->restrct && mglevels[i]->interpolate) {
512: PCMGSetRestriction(pc,i,mglevels[i]->interpolate);
513: }
514: #if defined(PETSC_USE_DEBUG)
515: if (!mglevels[i]->restrct || !mglevels[i]->interpolate) {
516: SETERRQ1(PETSC_ERR_ARG_WRONGSTATE,"Need to set restriction or interpolation on level %d",(int)i);
517: }
518: #endif
519: }
520: for (i=0; i<n-1; i++) {
521: if (!mglevels[i]->b) {
522: Vec *vec;
523: KSPGetVecs(mglevels[i]->smoothd,1,&vec,0,PETSC_NULL);
524: PCMGSetRhs(pc,i,*vec);
525: VecDestroy(*vec);
526: PetscFree(vec);
527: }
528: if (!mglevels[i]->r && i) {
529: VecDuplicate(mglevels[i]->b,&tvec);
530: PCMGSetR(pc,i,tvec);
531: VecDestroy(tvec);
532: }
533: if (!mglevels[i]->x) {
534: VecDuplicate(mglevels[i]->b,&tvec);
535: PCMGSetX(pc,i,tvec);
536: VecDestroy(tvec);
537: }
538: }
539: if (n != 1 && !mglevels[n-1]->r) {
540: /* PCMGSetR() on the finest level if user did not supply it */
541: Vec *vec;
542: KSPGetVecs(mglevels[n-1]->smoothd,1,&vec,0,PETSC_NULL);
543: PCMGSetR(pc,n-1,*vec);
544: VecDestroy(*vec);
545: PetscFree(vec);
546: }
547: }
550: for (i=1; i<n; i++) {
551: if (mglevels[i]->smoothu == mglevels[i]->smoothd) {
552: /* if doing only down then initial guess is zero */
553: KSPSetInitialGuessNonzero(mglevels[i]->smoothd,PETSC_TRUE);
554: }
555: if (mg->eventsmoothsetup) {PetscLogEventBegin(mg->eventsmoothsetup,0,0,0,0);}
556: KSPSetUp(mglevels[i]->smoothd);
557: if (mg->eventsmoothsetup) {PetscLogEventEnd(mg->eventsmoothsetup,0,0,0,0);}
558: }
559: for (i=1; i<n; i++) {
560: if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) {
561: Mat downmat,downpmat;
562: MatStructure matflag;
563: PetscTruth opsset;
565: /* check if operators have been set for up, if not use down operators to set them */
566: KSPGetOperatorsSet(mglevels[i]->smoothu,&opsset,PETSC_NULL);
567: if (!opsset) {
568: KSPGetOperators(mglevels[i]->smoothd,&downmat,&downpmat,&matflag);
569: KSPSetOperators(mglevels[i]->smoothu,downmat,downpmat,matflag);
570: }
572: KSPSetInitialGuessNonzero(mglevels[i]->smoothu,PETSC_TRUE);
573: if (mg->eventsmoothsetup) {PetscLogEventBegin(mg->eventsmoothsetup,0,0,0,0);}
574: KSPSetUp(mglevels[i]->smoothu);
575: if (mg->eventsmoothsetup) {PetscLogEventEnd(mg->eventsmoothsetup,0,0,0,0);}
576: }
577: }
579: /*
580: If coarse solver is not direct method then DO NOT USE preonly
581: */
582: PetscTypeCompare((PetscObject)mglevels[0]->smoothd,KSPPREONLY,&preonly);
583: if (preonly) {
584: PetscTypeCompare((PetscObject)cpc,PCLU,&lu);
585: PetscTypeCompare((PetscObject)cpc,PCREDUNDANT,&redundant);
586: PetscTypeCompare((PetscObject)cpc,PCCHOLESKY,&cholesky);
587: if (!lu && !redundant && !cholesky) {
588: KSPSetType(mglevels[0]->smoothd,KSPGMRES);
589: }
590: }
592: if (!pc->setupcalled) {
593: if (monitor) {
594: PetscObjectGetComm((PetscObject)mglevels[0]->smoothd,&comm);
595: PetscViewerASCIIMonitorCreate(comm,"stdout",n,&ascii);
596: KSPMonitorSet(mglevels[0]->smoothd,KSPMonitorDefault,ascii,(PetscErrorCode(*)(void*))PetscViewerASCIIMonitorDestroy);
597: }
598: KSPSetFromOptions(mglevels[0]->smoothd);
599: }
601: if (mg->eventsmoothsetup) {PetscLogEventBegin(mg->eventsmoothsetup,0,0,0,0);}
602: KSPSetUp(mglevels[0]->smoothd);
603: if (mg->eventsmoothsetup) {PetscLogEventEnd(mg->eventsmoothsetup,0,0,0,0);}
605: /*
606: Dump the interpolation/restriction matrices plus the
607: Jacobian/stiffness on each level. This allows Matlab users to
608: easily check if the Galerkin condition A_c = R A_f R^T is satisfied.
610: Only support one or the other at the same time.
611: */
612: #if defined(PETSC_USE_SOCKET_VIEWER)
613: PetscOptionsGetTruth(((PetscObject)pc)->prefix,"-pc_mg_dump_matlab",&dump,PETSC_NULL);
614: if (dump) {
615: viewer = PETSC_VIEWER_SOCKET_(((PetscObject)pc)->comm);
616: }
617: dump = PETSC_FALSE;
618: #endif
619: PetscOptionsGetTruth(((PetscObject)pc)->prefix,"-pc_mg_dump_binary",&dump,PETSC_NULL);
620: if (dump) {
621: viewer = PETSC_VIEWER_BINARY_(((PetscObject)pc)->comm);
622: }
624: if (viewer) {
625: for (i=1; i<n; i++) {
626: MatView(mglevels[i]->restrct,viewer);
627: }
628: for (i=0; i<n; i++) {
629: KSPGetPC(mglevels[i]->smoothd,&pc);
630: MatView(pc->mat,viewer);
631: }
632: }
633: return(0);
634: }
636: /* -------------------------------------------------------------------------------------*/
640: /*@
641: PCMGGetLevels - Gets the number of levels to use with MG.
643: Not Collective
645: Input Parameter:
646: . pc - the preconditioner context
648: Output parameter:
649: . levels - the number of levels
651: Level: advanced
653: .keywords: MG, get, levels, multigrid
655: .seealso: PCMGSetLevels()
656: @*/
657: PetscErrorCode PCMGGetLevels(PC pc,PetscInt *levels)
658: {
659: PC_MG *mg = (PC_MG*)pc->data;
664: *levels = mg->nlevels;
665: return(0);
666: }
670: /*@
671: PCMGSetType - Determines the form of multigrid to use:
672: multiplicative, additive, full, or the Kaskade algorithm.
674: Collective on PC
676: Input Parameters:
677: + pc - the preconditioner context
678: - form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,
679: PC_MG_FULL, PC_MG_KASKADE
681: Options Database Key:
682: . -pc_mg_type <form> - Sets <form>, one of multiplicative,
683: additive, full, kaskade
685: Level: advanced
687: .keywords: MG, set, method, multiplicative, additive, full, Kaskade, multigrid
689: .seealso: PCMGSetLevels()
690: @*/
691: PetscErrorCode PCMGSetType(PC pc,PCMGType form)
692: {
693: PC_MG *mg = (PC_MG*)pc->data;
697: mg->am = form;
698: if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
699: else pc->ops->applyrichardson = 0;
700: return(0);
701: }
705: /*@
706: PCMGSetCycleType - Sets the type cycles to use. Use PCMGSetCycleTypeOnLevel() for more
707: complicated cycling.
709: Collective on PC
711: Input Parameters:
712: + pc - the multigrid context
713: - PC_MG_CYCLE_V or PC_MG_CYCLE_W
715: Options Database Key:
716: $ -pc_mg_cycle_type v or w
718: Level: advanced
720: .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
722: .seealso: PCMGSetCycleTypeOnLevel()
723: @*/
724: PetscErrorCode PCMGSetCycleType(PC pc,PCMGCycleType n)
725: {
726: PC_MG *mg = (PC_MG*)pc->data;
727: PC_MG_Levels **mglevels = mg->levels;
728: PetscInt i,levels;
732: if (!mglevels) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
733: levels = mglevels[0]->levels;
735: for (i=0; i<levels; i++) {
736: mglevels[i]->cycles = n;
737: }
738: return(0);
739: }
743: /*@
744: PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step
745: of multigrid when PCMGType of PC_MG_MULTIPLICATIVE is used
747: Collective on PC
749: Input Parameters:
750: + pc - the multigrid context
751: - n - number of cycles (default is 1)
753: Options Database Key:
754: $ -pc_mg_multiplicative_cycles n
756: Level: advanced
758: Notes: This is not associated with setting a v or w cycle, that is set with PCMGSetCycleType()
760: .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
762: .seealso: PCMGSetCycleTypeOnLevel(), PCMGSetCycleType()
763: @*/
764: PetscErrorCode PCMGMultiplicativeSetCycles(PC pc,PetscInt n)
765: {
766: PC_MG *mg = (PC_MG*)pc->data;
767: PC_MG_Levels **mglevels = mg->levels;
768: PetscInt i,levels;
772: if (!mglevels) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
773: levels = mglevels[0]->levels;
775: for (i=0; i<levels; i++) {
776: mg->cyclesperpcapply = n;
777: }
778: return(0);
779: }
783: /*@
784: PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
785: finest grid via the Galerkin process: A_i-1 = r_i * A_i * r_i^t
787: Collective on PC
789: Input Parameters:
790: . pc - the multigrid context
792: Options Database Key:
793: $ -pc_mg_galerkin
795: Level: intermediate
797: .keywords: MG, set, Galerkin
799: .seealso: PCMGGetGalerkin()
801: @*/
802: PetscErrorCode PCMGSetGalerkin(PC pc)
803: {
804: PC_MG *mg = (PC_MG*)pc->data;
805: PC_MG_Levels **mglevels = mg->levels;
806: PetscInt i,levels;
810: if (!mglevels) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
811: levels = mglevels[0]->levels;
813: for (i=0; i<levels; i++) {
814: mglevels[i]->galerkin = PETSC_TRUE;
815: }
816: return(0);
817: }
821: /*@
822: PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e.
823: A_i-1 = r_i * A_i * r_i^t
825: Not Collective
827: Input Parameter:
828: . pc - the multigrid context
830: Output Parameter:
831: . gelerkin - PETSC_TRUE or PETSC_FALSE
833: Options Database Key:
834: $ -pc_mg_galerkin
836: Level: intermediate
838: .keywords: MG, set, Galerkin
840: .seealso: PCMGSetGalerkin()
842: @*/
843: PetscErrorCode PCMGGetGalerkin(PC pc,PetscTruth *galerkin)
844: {
845: PC_MG *mg = (PC_MG*)pc->data;
846: PC_MG_Levels **mglevels = mg->levels;
850: if (!mglevels) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
851: *galerkin = mglevels[0]->galerkin;
852: return(0);
853: }
857: /*@
858: PCMGSetNumberSmoothDown - Sets the number of pre-smoothing steps to
859: use on all levels. Use PCMGGetSmootherDown() to set different
860: pre-smoothing steps on different levels.
862: Collective on PC
864: Input Parameters:
865: + mg - the multigrid context
866: - n - the number of smoothing steps
868: Options Database Key:
869: . -pc_mg_smoothdown <n> - Sets number of pre-smoothing steps
871: Level: advanced
873: .keywords: MG, smooth, down, pre-smoothing, steps, multigrid
875: .seealso: PCMGSetNumberSmoothUp()
876: @*/
877: PetscErrorCode PCMGSetNumberSmoothDown(PC pc,PetscInt n)
878: {
879: PC_MG *mg = (PC_MG*)pc->data;
880: PC_MG_Levels **mglevels = mg->levels;
882: PetscInt i,levels;
886: if (!mglevels) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
887: levels = mglevels[0]->levels;
889: for (i=1; i<levels; i++) {
890: /* make sure smoother up and down are different */
891: PCMGGetSmootherUp(pc,i,PETSC_NULL);
892: KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);
893: mg->default_smoothd = n;
894: }
895: return(0);
896: }
900: /*@
901: PCMGSetNumberSmoothUp - Sets the number of post-smoothing steps to use
902: on all levels. Use PCMGGetSmootherUp() to set different numbers of
903: post-smoothing steps on different levels.
905: Collective on PC
907: Input Parameters:
908: + mg - the multigrid context
909: - n - the number of smoothing steps
911: Options Database Key:
912: . -pc_mg_smoothup <n> - Sets number of post-smoothing steps
914: Level: advanced
916: Note: this does not set a value on the coarsest grid, since we assume that
917: there is no separate smooth up on the coarsest grid.
919: .keywords: MG, smooth, up, post-smoothing, steps, multigrid
921: .seealso: PCMGSetNumberSmoothDown()
922: @*/
923: PetscErrorCode PCMGSetNumberSmoothUp(PC pc,PetscInt n)
924: {
925: PC_MG *mg = (PC_MG*)pc->data;
926: PC_MG_Levels **mglevels = mg->levels;
928: PetscInt i,levels;
932: if (!mglevels) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
933: levels = mglevels[0]->levels;
935: for (i=1; i<levels; i++) {
936: /* make sure smoother up and down are different */
937: PCMGGetSmootherUp(pc,i,PETSC_NULL);
938: KSPSetTolerances(mglevels[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);
939: mg->default_smoothu = n;
940: }
941: return(0);
942: }
944: /* ----------------------------------------------------------------------------------------*/
946: /*MC
947: PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional
948: information about the coarser grid matrices and restriction/interpolation operators.
950: Options Database Keys:
951: + -pc_mg_levels <nlevels> - number of levels including finest
952: . -pc_mg_cycles v or w
953: . -pc_mg_smoothup <n> - number of smoothing steps after interpolation
954: . -pc_mg_smoothdown <n> - number of smoothing steps before applying restriction operator
955: . -pc_mg_type <additive,multiplicative,full,cascade> - multiplicative is the default
956: . -pc_mg_log - log information about time spent on each level of the solver
957: . -pc_mg_monitor - print information on the multigrid convergence
958: . -pc_mg_galerkin - use Galerkin process to compute coarser operators
959: - -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices
960: to the Socket viewer for reading from Matlab.
962: Notes:
964: Level: intermediate
966: Concepts: multigrid/multilevel
968: .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType,
969: PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), PCMGSetCycleType(), PCMGSetNumberSmoothDown(),
970: PCMGSetNumberSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(),
971: PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(),
972: PCMGSetCycleTypeOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR()
973: M*/
978: PetscErrorCode PCCreate_MG(PC pc)
979: {
980: PC_MG *mg;
984: PetscNewLog(pc,PC_MG,&mg);
985: pc->data = (void*)mg;
986: mg->nlevels = -1;
988: pc->ops->apply = PCApply_MG;
989: pc->ops->setup = PCSetUp_MG;
990: pc->ops->destroy = PCDestroy_MG;
991: pc->ops->setfromoptions = PCSetFromOptions_MG;
992: pc->ops->view = PCView_MG;
993: return(0);
994: }