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_MG **mglevels,PetscTruth *converged)
12: {
13: PC_MG *mg = *mglevels,*mgc;
15: PetscInt cycles = mg->cycles;
18: if (converged) *converged = PETSC_FALSE;
21: KSPSolve(mg->smoothd,mg->b,mg->x);
23: if (mg->level) { /* not the coarsest grid */
24: (*mg->residual)(mg->A,mg->b,mg->x,mg->r);
26: /* if on finest level and have convergence criteria set */
27: if (mg->level == mg->levels-1 && mg->ttol) {
28: PetscReal rnorm;
29: VecNorm(mg->r,NORM_2,&rnorm);
30: if (rnorm <= mg->ttol) {
31: *converged = PETSC_TRUE;
32: if (rnorm < mg->abstol) {
33: PetscInfo2(0,"Linear solver has converged. Residual norm %G is less than absolute tolerance %G\n",rnorm,mg->abstol);
34: } else {
35: PetscInfo2(0,"Linear solver has converged. Residual norm %G is less than relative tolerance times initial residual norm %G\n",rnorm,mg->ttol);
36: }
37: return(0);
38: }
39: }
41: mgc = *(mglevels - 1);
42: MatRestrict(mg->restrct,mg->r,mgc->b);
43: VecSet(mgc->x,0.0);
44: while (cycles--) {
45: PCMGMCycle_Private(mglevels-1,converged);
46: }
47: MatInterpolateAdd(mg->interpolate,mgc->x,mg->x,mg->x);
49: KSPSolve(mg->smoothu,mg->b,mg->x);
51: }
52: return(0);
53: }
55: /*
56: PCMGCreate_Private - Creates a PC_MG structure for use with the
57: multigrid code. Level 0 is the coarsest. (But the
58: finest level is stored first in the array).
60: */
63: static PetscErrorCode PCMGCreate_Private(MPI_Comm comm,PetscInt levels,PC pc,MPI_Comm *comms,PC_MG ***result)
64: {
65: PC_MG **mg;
67: PetscInt i;
68: PetscMPIInt size;
69: const char *prefix;
70: PC ipc;
73: PetscMalloc(levels*sizeof(PC_MG*),&mg);
74: PetscLogObjectMemory(pc,levels*(sizeof(PC_MG*)+sizeof(PC_MG)));
76: PCGetOptionsPrefix(pc,&prefix);
78: for (i=0; i<levels; i++) {
79: PetscNew(PC_MG,&mg[i]);
80: mg[i]->level = i;
81: mg[i]->levels = levels;
82: mg[i]->cycles = 1;
83: mg[i]->galerkin = PETSC_FALSE;
84: mg[i]->galerkinused = PETSC_FALSE;
85: mg[i]->default_smoothu = 1;
86: mg[i]->default_smoothd = 1;
88: if (comms) comm = comms[i];
89: KSPCreate(comm,&mg[i]->smoothd);
90: KSPSetTolerances(mg[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, mg[i]->default_smoothd);
91: KSPSetOptionsPrefix(mg[i]->smoothd,prefix);
93: /* do special stuff for coarse grid */
94: if (!i && levels > 1) {
95: KSPAppendOptionsPrefix(mg[0]->smoothd,"mg_coarse_");
97: /* coarse solve is (redundant) LU by default */
98: KSPSetType(mg[0]->smoothd,KSPPREONLY);
99: KSPGetPC(mg[0]->smoothd,&ipc);
100: MPI_Comm_size(comm,&size);
101: if (size > 1) {
102: PCSetType(ipc,PCREDUNDANT);
103: PCRedundantGetPC(ipc,&ipc);
104: }
105: PCSetType(ipc,PCLU);
107: } else {
108: char tprefix[128];
109: sprintf(tprefix,"mg_levels_%d_",(int)i);
110: KSPAppendOptionsPrefix(mg[i]->smoothd,tprefix);
111: }
112: PetscLogObjectParent(pc,mg[i]->smoothd);
113: mg[i]->smoothu = mg[i]->smoothd;
114: mg[i]->rtol = 0.0;
115: mg[i]->abstol = 0.0;
116: mg[i]->dtol = 0.0;
117: mg[i]->ttol = 0.0;
118: mg[i]->eventsetup = 0;
119: mg[i]->eventsolve = 0;
120: }
121: *result = mg;
122: return(0);
123: }
127: static PetscErrorCode PCDestroy_MG(PC pc)
128: {
129: PC_MG **mg = (PC_MG**)pc->data;
131: PetscInt i,n = mg[0]->levels;
134: for (i=0; i<n-1; i++) {
135: if (mg[i+1]->r) {VecDestroy(mg[i+1]->r);}
136: if (mg[i]->b) {VecDestroy(mg[i]->b);}
137: if (mg[i]->x) {VecDestroy(mg[i]->x);}
138: if (mg[i+1]->restrct) {MatDestroy(mg[i+1]->restrct);}
139: if (mg[i+1]->interpolate) {MatDestroy(mg[i+1]->interpolate);}
140: }
142: for (i=0; i<n; i++) {
143: if (mg[i]->smoothd != mg[i]->smoothu) {
144: KSPDestroy(mg[i]->smoothd);
145: }
146: KSPDestroy(mg[i]->smoothu);
147: PetscFree(mg[i]);
148: }
149: PetscFree(mg);
150: return(0);
151: }
155: EXTERN PetscErrorCode PCMGACycle_Private(PC_MG**);
156: EXTERN PetscErrorCode PCMGFCycle_Private(PC_MG**);
157: EXTERN PetscErrorCode PCMGKCycle_Private(PC_MG**);
159: /*
160: PCApply_MG - Runs either an additive, multiplicative, Kaskadic
161: or full cycle of multigrid.
163: Note:
164: A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
165: */
168: static PetscErrorCode PCApply_MG(PC pc,Vec b,Vec x)
169: {
170: PC_MG **mg = (PC_MG**)pc->data;
172: PetscInt levels = mg[0]->levels;
175: mg[levels-1]->b = b;
176: mg[levels-1]->x = x;
177: if (!mg[levels-1]->r && mg[0]->am != PC_MG_ADDITIVE && levels > 1) {
178: Vec tvec;
179: VecDuplicate(mg[levels-1]->b,&tvec);
180: PCMGSetR(pc,levels-1,tvec);
181: VecDestroy(tvec);
182: }
183: if (mg[0]->am == PC_MG_MULTIPLICATIVE) {
184: VecSet(x,0.0);
185: PCMGMCycle_Private(mg+levels-1,PETSC_NULL);
186: }
187: else if (mg[0]->am == PC_MG_ADDITIVE) {
188: PCMGACycle_Private(mg);
189: }
190: else if (mg[0]->am == PC_MG_KASKADE) {
191: PCMGKCycle_Private(mg);
192: }
193: else {
194: PCMGFCycle_Private(mg);
195: }
196: return(0);
197: }
201: static PetscErrorCode PCApplyRichardson_MG(PC pc,Vec b,Vec x,Vec w,PetscReal rtol,PetscReal abstol, PetscReal dtol,PetscInt its)
202: {
203: PC_MG **mg = (PC_MG**)pc->data;
205: PetscInt levels = mg[0]->levels;
206: PetscTruth converged = PETSC_FALSE;
209: mg[levels-1]->b = b;
210: mg[levels-1]->x = x;
212: mg[levels-1]->rtol = rtol;
213: mg[levels-1]->abstol = abstol;
214: mg[levels-1]->dtol = dtol;
215: if (rtol) {
216: /* compute initial residual norm for relative convergence test */
217: PetscReal rnorm;
218: (*mg[levels-1]->residual)(mg[levels-1]->A,b,x,w);
219: VecNorm(w,NORM_2,&rnorm);
220: mg[levels-1]->ttol = PetscMax(rtol*rnorm,abstol);
221: } else if (abstol) {
222: mg[levels-1]->ttol = abstol;
223: } else {
224: mg[levels-1]->ttol = 0.0;
225: }
227: while (its-- && !converged) {
228: PCMGMCycle_Private(mg+levels-1,&converged);
229: }
230: return(0);
231: }
235: PetscErrorCode PCSetFromOptions_MG(PC pc)
236: {
238: PetscInt m,levels = 1;
239: PetscTruth flg;
240: PC_MG **mg = (PC_MG**)pc->data;
241: PCMGType mgtype;
245: PetscOptionsHead("Multigrid options");
246: if (!pc->data) {
247: PetscOptionsInt("-pc_mg_levels","Number of Levels","PCMGSetLevels",levels,&levels,&flg);
248: PCMGSetLevels(pc,levels,PETSC_NULL);
249: mg = (PC_MG**)pc->data;
250: }
251: mgtype = mg[0]->am;
252: PetscOptionsInt("-pc_mg_cycles","1 for V cycle, 2 for W-cycle","PCMGSetCycles",1,&m,&flg);
253: if (flg) {
254: PCMGSetCycles(pc,m);
255: }
256: PetscOptionsName("-pc_mg_galerkin","Use Galerkin process to compute coarser operators","PCMGSetGalerkin",&flg);
257: if (flg) {
258: PCMGSetGalerkin(pc);
259: }
260: PetscOptionsInt("-pc_mg_smoothup","Number of post-smoothing steps","PCMGSetNumberSmoothUp",1,&m,&flg);
261: if (flg) {
262: PCMGSetNumberSmoothUp(pc,m);
263: }
264: PetscOptionsInt("-pc_mg_smoothdown","Number of pre-smoothing steps","PCMGSetNumberSmoothDown",1,&m,&flg);
265: if (flg) {
266: PCMGSetNumberSmoothDown(pc,m);
267: }
268: PetscOptionsEnum("-pc_mg_type","Multigrid type","PCMGSetType",PCMGTypes,(PetscEnum)mgtype,(PetscEnum*)&mgtype,&flg);
269: if (flg) {PCMGSetType(pc,mgtype);}
270: PetscOptionsName("-pc_mg_log","Log times for each multigrid level","None",&flg);
271: if (flg) {
272: PetscInt i;
273: char eventname[128];
274: if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
275: levels = mg[0]->levels;
276: for (i=0; i<levels; i++) {
277: sprintf(eventname,"MSetup Level %d",(int)i);
279: sprintf(eventname,"MGSolve Level %d to 0",(int)i);
281: }
282: }
283: PetscOptionsTail();
284: return(0);
285: }
287: const char *PCMGTypes[] = {"MULTIPLICATIVE","ADDITIVE","FULL","KASKADE","PCMGType","PC_MG",0};
291: static PetscErrorCode PCView_MG(PC pc,PetscViewer viewer)
292: {
293: PC_MG **mg = (PC_MG**)pc->data;
295: PetscInt levels = mg[0]->levels,i;
296: PetscTruth iascii;
299: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
300: if (iascii) {
301: PetscViewerASCIIPrintf(viewer," MG: type is %s, levels=%D cycles=%D, pre-smooths=%D, post-smooths=%D\n",
302: PCMGTypes[mg[0]->am],levels,mg[0]->cycles,mg[0]->default_smoothd,mg[0]->default_smoothu);
303: if (mg[0]->galerkin) {
304: PetscViewerASCIIPrintf(viewer," Using Galerkin computed coarse grid matrices\n");
305: }
306: for (i=0; i<levels; i++) {
307: if (!i) {
308: PetscViewerASCIIPrintf(viewer,"Coarse gride solver -- level %D -------------------------------\n",i);
309: } else {
310: PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D -------------------------------\n",i);
311: }
312: PetscViewerASCIIPushTab(viewer);
313: KSPView(mg[i]->smoothd,viewer);
314: PetscViewerASCIIPopTab(viewer);
315: if (i && mg[i]->smoothd == mg[i]->smoothu) {
316: PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n");
317: } else if (i){
318: PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D -------------------------------\n",i);
319: PetscViewerASCIIPushTab(viewer);
320: KSPView(mg[i]->smoothu,viewer);
321: PetscViewerASCIIPopTab(viewer);
322: }
323: }
324: } else {
325: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCMG",((PetscObject)viewer)->type_name);
326: }
327: return(0);
328: }
330: /*
331: Calls setup for the KSP on each level
332: */
335: static PetscErrorCode PCSetUp_MG(PC pc)
336: {
337: PC_MG **mg = (PC_MG**)pc->data;
339: PetscInt i,n = mg[0]->levels;
340: PC cpc;
341: PetscTruth preonly,lu,redundant,cholesky,monitor = PETSC_FALSE,dump,opsset;
342: PetscViewer ascii;
343: MPI_Comm comm;
344: Mat dA,dB;
345: MatStructure uflag;
346: Vec tvec;
350: /* If user did not provide fine grid operators, use those from PC */
351: /* BUG BUG BUG This will work ONLY the first time called: hence if the user changes
352: the PC matrices between solves PCMG will continue to use first set provided */
353: KSPGetOperatorsSet(mg[n-1]->smoothd,PETSC_NULL,&opsset);
354: if (!opsset) {
355: PetscInfo(pc,"Using outer operators to define finest grid operator \n because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n");
356: KSPSetOperators(mg[n-1]->smoothd,pc->mat,pc->pmat,pc->flag);
357: }
359: if (mg[0]->galerkin) {
360: Mat B;
361: mg[0]->galerkinused = PETSC_TRUE;
362: /* currently only handle case where mat and pmat are the same on coarser levels */
363: KSPGetOperators(mg[n-1]->smoothd,&dA,&dB,&uflag);
364: if (!pc->setupcalled) {
365: for (i=n-2; i>-1; i--) {
366: MatPtAP(dB,mg[i+1]->interpolate,MAT_INITIAL_MATRIX,1.0,&B);
367: KSPSetOperators(mg[i]->smoothd,B,B,uflag);
368: if (i != n-2) {PetscObjectDereference((PetscObject)dB);}
369: dB = B;
370: }
371: PetscObjectDereference((PetscObject)dB);
372: } else {
373: for (i=n-2; i>-1; i--) {
374: KSPGetOperators(mg[i]->smoothd,PETSC_NULL,&B,PETSC_NULL);
375: MatPtAP(dB,mg[i+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);
376: KSPSetOperators(mg[i]->smoothd,B,B,uflag);
377: dB = B;
378: }
379: }
380: }
382: if (!pc->setupcalled) {
383: PetscOptionsHasName(0,"-pc_mg_monitor",&monitor);
384:
385: for (i=0; i<n; i++) {
386: if (monitor) {
387: PetscObjectGetComm((PetscObject)mg[i]->smoothd,&comm);
388: PetscViewerASCIIOpen(comm,"stdout",&ascii);
389: PetscViewerASCIISetTab(ascii,n-i);
390: KSPSetMonitor(mg[i]->smoothd,KSPDefaultMonitor,ascii,(PetscErrorCode(*)(void*))PetscViewerDestroy);
391: }
392: KSPSetFromOptions(mg[i]->smoothd);
393: }
394: for (i=1; i<n; i++) {
395: if (mg[i]->smoothu && (mg[i]->smoothu != mg[i]->smoothd)) {
396: if (monitor) {
397: PetscObjectGetComm((PetscObject)mg[i]->smoothu,&comm);
398: PetscViewerASCIIOpen(comm,"stdout",&ascii);
399: PetscViewerASCIISetTab(ascii,n-i);
400: KSPSetMonitor(mg[i]->smoothu,KSPDefaultMonitor,ascii,(PetscErrorCode(*)(void*))PetscViewerDestroy);
401: }
402: KSPSetFromOptions(mg[i]->smoothu);
403: }
404: }
405: for (i=1; i<n; i++) {
406: if (!mg[i]->residual) {
407: Mat mat;
408: KSPGetOperators(mg[i]->smoothd,PETSC_NULL,&mat,PETSC_NULL);
409: PCMGSetResidual(pc,i,PCMGDefaultResidual,mat);
410: }
411: if (mg[i]->restrct && !mg[i]->interpolate) {
412: PCMGSetInterpolate(pc,i,mg[i]->restrct);
413: }
414: if (!mg[i]->restrct && mg[i]->interpolate) {
415: PCMGSetRestriction(pc,i,mg[i]->interpolate);
416: }
417: #if defined(PETSC_USE_DEBUG)
418: if (!mg[i]->restrct || !mg[i]->interpolate) {
419: SETERRQ1(PETSC_ERR_ARG_WRONGSTATE,"Need to set restriction or interpolation on level %d",(int)i);
420: }
421: #endif
422: }
423: for (i=0; i<n-1; i++) {
424: if (!mg[i]->b) {
425: Vec *vec;
426: KSPGetVecs(mg[i]->smoothd,1,&vec,0,PETSC_NULL);
427: PCMGSetRhs(pc,i,*vec);
428: PetscFree(vec);
429: }
430: if (!mg[i]->r && i) {
431: VecDuplicate(mg[i]->b,&tvec);
432: PCMGSetR(pc,i,tvec);
433: VecDestroy(tvec);
434: }
435: if (!mg[i]->x) {
436: VecDuplicate(mg[i]->b,&tvec);
437: PCMGSetX(pc,i,tvec);
438: VecDestroy(tvec);
439: }
440: }
441: }
444: for (i=1; i<n; i++) {
445: if (mg[i]->smoothu == mg[i]->smoothd) {
446: /* if doing only down then initial guess is zero */
447: KSPSetInitialGuessNonzero(mg[i]->smoothd,PETSC_TRUE);
448: }
450: KSPSetUp(mg[i]->smoothd);
452: }
453: for (i=1; i<n; i++) {
454: if (mg[i]->smoothu && mg[i]->smoothu != mg[i]->smoothd) {
455: Mat downmat,downpmat;
456: MatStructure matflag;
457: PetscTruth opsset;
459: /* check if operators have been set for up, if not use down operators to set them */
460: KSPGetOperatorsSet(mg[i]->smoothu,&opsset,PETSC_NULL);
461: if (!opsset) {
462: KSPGetOperators(mg[i]->smoothd,&downmat,&downpmat,&matflag);
463: KSPSetOperators(mg[i]->smoothu,downmat,downpmat,matflag);
464: }
466: KSPSetInitialGuessNonzero(mg[i]->smoothu,PETSC_TRUE);
468: KSPSetUp(mg[i]->smoothu);
470: }
471: }
473: /*
474: If coarse solver is not direct method then DO NOT USE preonly
475: */
476: PetscTypeCompare((PetscObject)mg[0]->smoothd,KSPPREONLY,&preonly);
477: if (preonly) {
478: KSPGetPC(mg[0]->smoothd,&cpc);
479: PetscTypeCompare((PetscObject)cpc,PCLU,&lu);
480: PetscTypeCompare((PetscObject)cpc,PCREDUNDANT,&redundant);
481: PetscTypeCompare((PetscObject)cpc,PCCHOLESKY,&cholesky);
482: if (!lu && !redundant && !cholesky) {
483: KSPSetType(mg[0]->smoothd,KSPGMRES);
484: }
485: }
487: if (!pc->setupcalled) {
488: if (monitor) {
489: PetscObjectGetComm((PetscObject)mg[0]->smoothd,&comm);
490: PetscViewerASCIIOpen(comm,"stdout",&ascii);
491: PetscViewerASCIISetTab(ascii,n);
492: KSPSetMonitor(mg[0]->smoothd,KSPDefaultMonitor,ascii,(PetscErrorCode(*)(void*))PetscViewerDestroy);
493: }
494: KSPSetFromOptions(mg[0]->smoothd);
495: }
498: KSPSetUp(mg[0]->smoothd);
501: #if defined(PETSC_USE_SOCKET_VIEWER)
502: /*
503: Dump the interpolation/restriction matrices to matlab plus the
504: Jacobian/stiffness on each level. This allows Matlab users to
505: easily check if the Galerkin condition A_c = R A_f R^T is satisfied */
506: PetscOptionsHasName(pc->prefix,"-pc_mg_dump_matlab",&dump);
507: if (dump) {
508: for (i=1; i<n; i++) {
509: MatView(mg[i]->restrct,PETSC_VIEWER_SOCKET_(pc->comm));
510: }
511: for (i=0; i<n; i++) {
512: KSPGetPC(mg[i]->smoothd,&pc);
513: MatView(pc->mat,PETSC_VIEWER_SOCKET_(pc->comm));
514: }
515: }
516: #endif
518: PetscOptionsHasName(pc->prefix,"-pc_mg_dump_binary",&dump);
519: if (dump) {
520: for (i=1; i<n; i++) {
521: MatView(mg[i]->restrct,PETSC_VIEWER_BINARY_(pc->comm));
522: }
523: for (i=0; i<n; i++) {
524: KSPGetPC(mg[i]->smoothd,&pc);
525: MatView(pc->mat,PETSC_VIEWER_BINARY_(pc->comm));
526: }
527: }
528: return(0);
529: }
531: /* -------------------------------------------------------------------------------------*/
535: /*@C
536: PCMGSetLevels - Sets the number of levels to use with MG.
537: Must be called before any other MG routine.
539: Collective on PC
541: Input Parameters:
542: + pc - the preconditioner context
543: . levels - the number of levels
544: - comms - optional communicators for each level; this is to allow solving the coarser problems
545: on smaller sets of processors. Use PETSC_NULL_OBJECT for default in Fortran
547: Level: intermediate
549: Notes:
550: If the number of levels is one then the multigrid uses the -mg_levels prefix
551: for setting the level options rather than the -mg_coarse prefix.
553: .keywords: MG, set, levels, multigrid
555: .seealso: PCMGSetType(), PCMGGetLevels()
556: @*/
557: PetscErrorCode PCMGSetLevels(PC pc,PetscInt levels,MPI_Comm *comms)
558: {
560: PC_MG **mg=0;
565: if (pc->data) {
566: SETERRQ(PETSC_ERR_ORDER,"Number levels already set for MG\n\
567: make sure that you call PCMGSetLevels() before KSPSetFromOptions()");
568: }
569: PCMGCreate_Private(pc->comm,levels,pc,comms,&mg);
570: mg[0]->am = PC_MG_MULTIPLICATIVE;
571: pc->data = (void*)mg;
572: pc->ops->applyrichardson = PCApplyRichardson_MG;
573: return(0);
574: }
578: /*@
579: PCMGGetLevels - Gets the number of levels to use with MG.
581: Not Collective
583: Input Parameter:
584: . pc - the preconditioner context
586: Output parameter:
587: . levels - the number of levels
589: Level: advanced
591: .keywords: MG, get, levels, multigrid
593: .seealso: PCMGSetLevels()
594: @*/
595: PetscErrorCode PCMGGetLevels(PC pc,PetscInt *levels)
596: {
597: PC_MG **mg;
603: mg = (PC_MG**)pc->data;
604: *levels = mg[0]->levels;
605: return(0);
606: }
610: /*@
611: PCMGSetType - Determines the form of multigrid to use:
612: multiplicative, additive, full, or the Kaskade algorithm.
614: Collective on PC
616: Input Parameters:
617: + pc - the preconditioner context
618: - form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,
619: PC_MG_FULL, PC_MG_KASKADE
621: Options Database Key:
622: . -pc_mg_type <form> - Sets <form>, one of multiplicative,
623: additive, full, kaskade
625: Level: advanced
627: .keywords: MG, set, method, multiplicative, additive, full, Kaskade, multigrid
629: .seealso: PCMGSetLevels()
630: @*/
631: PetscErrorCode PCMGSetType(PC pc,PCMGType form)
632: {
633: PC_MG **mg;
637: mg = (PC_MG**)pc->data;
639: if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
640: mg[0]->am = form;
641: if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
642: else pc->ops->applyrichardson = 0;
643: return(0);
644: }
648: /*@
649: PCMGSetCycles - Sets the type cycles to use. Use PCMGSetCyclesOnLevel() for more
650: complicated cycling.
652: Collective on PC
654: Input Parameters:
655: + pc - the multigrid context
656: - n - the number of cycles
658: Options Database Key:
659: $ -pc_mg_cycles n - 1 denotes a V-cycle; 2 denotes a W-cycle.
661: Level: advanced
663: .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
665: .seealso: PCMGSetCyclesOnLevel()
666: @*/
667: PetscErrorCode PCMGSetCycles(PC pc,PetscInt n)
668: {
669: PC_MG **mg;
670: PetscInt i,levels;
674: mg = (PC_MG**)pc->data;
675: if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
676: levels = mg[0]->levels;
678: for (i=0; i<levels; i++) {
679: mg[i]->cycles = n;
680: }
681: return(0);
682: }
686: /*@
687: PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
688: finest grid via the Galerkin process: A_i-1 = r_i * A_i * r_i^t
690: Collective on PC
692: Input Parameters:
693: . pc - the multigrid context
695: Options Database Key:
696: $ -pc_mg_galerkin
698: Level: intermediate
700: .keywords: MG, set, Galerkin
702: .seealso: PCMGGetGalerkin()
704: @*/
705: PetscErrorCode PCMGSetGalerkin(PC pc)
706: {
707: PC_MG **mg;
708: PetscInt i,levels;
712: mg = (PC_MG**)pc->data;
713: if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
714: levels = mg[0]->levels;
716: for (i=0; i<levels; i++) {
717: mg[i]->galerkin = PETSC_TRUE;
718: }
719: return(0);
720: }
724: /*@
725: PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e.
726: A_i-1 = r_i * A_i * r_i^t
728: Not Collective
730: Input Parameter:
731: . pc - the multigrid context
733: Output Parameter:
734: . gelerkin - PETSC_TRUE or PETSC_FALSE
736: Options Database Key:
737: $ -pc_mg_galerkin
739: Level: intermediate
741: .keywords: MG, set, Galerkin
743: .seealso: PCMGSetGalerkin()
745: @*/
746: PetscErrorCode PCMGGetGalerkin(PC pc,PetscTruth *galerkin)
747: {
748: PC_MG **mg;
752: mg = (PC_MG**)pc->data;
753: if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
754: *galerkin = mg[0]->galerkin;
755: return(0);
756: }
760: /*@
761: PCMGSetNumberSmoothDown - Sets the number of pre-smoothing steps to
762: use on all levels. Use PCMGGetSmootherDown() to set different
763: pre-smoothing steps on different levels.
765: Collective on PC
767: Input Parameters:
768: + mg - the multigrid context
769: - n - the number of smoothing steps
771: Options Database Key:
772: . -pc_mg_smoothdown <n> - Sets number of pre-smoothing steps
774: Level: advanced
776: .keywords: MG, smooth, down, pre-smoothing, steps, multigrid
778: .seealso: PCMGSetNumberSmoothUp()
779: @*/
780: PetscErrorCode PCMGSetNumberSmoothDown(PC pc,PetscInt n)
781: {
782: PC_MG **mg;
784: PetscInt i,levels;
788: mg = (PC_MG**)pc->data;
789: if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
790: levels = mg[0]->levels;
792: for (i=1; i<levels; i++) {
793: /* make sure smoother up and down are different */
794: PCMGGetSmootherUp(pc,i,PETSC_NULL);
795: KSPSetTolerances(mg[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);
796: mg[i]->default_smoothd = n;
797: }
798: return(0);
799: }
803: /*@
804: PCMGSetNumberSmoothUp - Sets the number of post-smoothing steps to use
805: on all levels. Use PCMGGetSmootherUp() to set different numbers of
806: post-smoothing steps on different levels.
808: Collective on PC
810: Input Parameters:
811: + mg - the multigrid context
812: - n - the number of smoothing steps
814: Options Database Key:
815: . -pc_mg_smoothup <n> - Sets number of post-smoothing steps
817: Level: advanced
819: Note: this does not set a value on the coarsest grid, since we assume that
820: there is no separate smooth up on the coarsest grid.
822: .keywords: MG, smooth, up, post-smoothing, steps, multigrid
824: .seealso: PCMGSetNumberSmoothDown()
825: @*/
826: PetscErrorCode PCMGSetNumberSmoothUp(PC pc,PetscInt n)
827: {
828: PC_MG **mg;
830: PetscInt i,levels;
834: mg = (PC_MG**)pc->data;
835: if (!mg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
836: levels = mg[0]->levels;
838: for (i=1; i<levels; i++) {
839: /* make sure smoother up and down are different */
840: PCMGGetSmootherUp(pc,i,PETSC_NULL);
841: KSPSetTolerances(mg[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);
842: mg[i]->default_smoothu = n;
843: }
844: return(0);
845: }
847: /* ----------------------------------------------------------------------------------------*/
849: /*MC
850: PCMG - Use geometric multigrid preconditioning. This preconditioner requires you provide additional
851: information about the coarser grid matrices and restriction/interpolation operators.
853: Options Database Keys:
854: + -pc_mg_levels <nlevels> - number of levels including finest
855: . -pc_mg_cycles 1 or 2 - for V or W-cycle
856: . -pc_mg_smoothup <n> - number of smoothing steps after interpolation
857: . -pc_mg_smoothdown <n> - number of smoothing steps before applying restriction operator
858: . -pc_mg_type <additive,multiplicative,full,cascade> - multiplicative is the default
859: . -pc_mg_log - log information about time spent on each level of the solver
860: . -pc_mg_monitor - print information on the multigrid convergence
861: . -pc_mg_galerkin - use Galerkin process to compute coarser operators
862: - -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices
863: to the Socket viewer for reading from Matlab.
865: Notes:
867: Level: intermediate
869: Concepts: multigrid
871: .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType,
872: PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), PCMGSetCycles(), PCMGSetNumberSmoothDown(),
873: PCMGSetNumberSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(),
874: PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(),
875: PCMGSetCyclesOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR()
876: M*/
881: PetscErrorCode PCCreate_MG(PC pc)
882: {
884: pc->ops->apply = PCApply_MG;
885: pc->ops->setup = PCSetUp_MG;
886: pc->ops->destroy = PCDestroy_MG;
887: pc->ops->setfromoptions = PCSetFromOptions_MG;
888: pc->ops->view = PCView_MG;
890: pc->data = (void*)0;
891: return(0);
892: }