Actual source code: mgfunc.c
petsc-3.7.7 2017-09-25
2: #include <petsc/private/pcmgimpl.h> /*I "petscksp.h" I*/
4: /* ---------------------------------------------------------------------------*/
7: /*@C
8: PCMGResidualDefault - Default routine to calculate the residual.
10: Collective on Mat and Vec
12: Input Parameters:
13: + mat - the matrix
14: . b - the right-hand-side
15: - x - the approximate solution
17: Output Parameter:
18: . r - location to store the residual
20: Level: developer
22: .keywords: MG, default, multigrid, residual
24: .seealso: PCMGSetResidual()
25: @*/
26: PetscErrorCode PCMGResidualDefault(Mat mat,Vec b,Vec x,Vec r)
27: {
31: MatResidual(mat,b,x,r);
32: return(0);
33: }
37: /*@
38: PCMGGetCoarseSolve - Gets the solver context to be used on the coarse grid.
40: Not Collective
42: Input Parameter:
43: . pc - the multigrid context
45: Output Parameter:
46: . ksp - the coarse grid solver context
48: Level: advanced
50: .keywords: MG, multigrid, get, coarse grid
51: @*/
52: PetscErrorCode PCMGGetCoarseSolve(PC pc,KSP *ksp)
53: {
54: PC_MG *mg = (PC_MG*)pc->data;
55: PC_MG_Levels **mglevels = mg->levels;
59: *ksp = mglevels[0]->smoothd;
60: return(0);
61: }
65: /*@C
66: PCMGSetResidual - Sets the function to be used to calculate the residual
67: on the lth level.
69: Logically Collective on PC and Mat
71: Input Parameters:
72: + pc - the multigrid context
73: . l - the level (0 is coarsest) to supply
74: . residual - function used to form residual, if none is provided the previously provide one is used, if no
75: previous one were provided then a default is used
76: - mat - matrix associated with residual
78: Level: advanced
80: .keywords: MG, set, multigrid, residual, level
82: .seealso: PCMGResidualDefault()
83: @*/
84: PetscErrorCode PCMGSetResidual(PC pc,PetscInt l,PetscErrorCode (*residual)(Mat,Vec,Vec,Vec),Mat mat)
85: {
86: PC_MG *mg = (PC_MG*)pc->data;
87: PC_MG_Levels **mglevels = mg->levels;
92: if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
93: if (residual) mglevels[l]->residual = residual;
94: if (!mglevels[l]->residual) mglevels[l]->residual = PCMGResidualDefault;
95: if (mat) {PetscObjectReference((PetscObject)mat);}
96: MatDestroy(&mglevels[l]->A);
97: mglevels[l]->A = mat;
98: return(0);
99: }
103: /*@
104: PCMGSetInterpolation - Sets the function to be used to calculate the
105: interpolation from l-1 to the lth level
107: Logically Collective on PC and Mat
109: Input Parameters:
110: + pc - the multigrid context
111: . mat - the interpolation operator
112: - l - the level (0 is coarsest) to supply [do not supply 0]
114: Level: advanced
116: Notes:
117: Usually this is the same matrix used also to set the restriction
118: for the same level.
120: One can pass in the interpolation matrix or its transpose; PETSc figures
121: out from the matrix size which one it is.
123: .keywords: multigrid, set, interpolate, level
125: .seealso: PCMGSetRestriction()
126: @*/
127: PetscErrorCode PCMGSetInterpolation(PC pc,PetscInt l,Mat mat)
128: {
129: PC_MG *mg = (PC_MG*)pc->data;
130: PC_MG_Levels **mglevels = mg->levels;
135: if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
136: if (!l) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Do not set interpolation routine for coarsest level");
137: PetscObjectReference((PetscObject)mat);
138: MatDestroy(&mglevels[l]->interpolate);
140: mglevels[l]->interpolate = mat;
141: return(0);
142: }
146: /*@
147: PCMGGetInterpolation - Gets the function to be used to calculate the
148: interpolation from l-1 to the lth level
150: Logically Collective on PC
152: Input Parameters:
153: + pc - the multigrid context
154: - l - the level (0 is coarsest) to supply [Do not supply 0]
156: Output Parameter:
157: . mat - the interpolation matrix, can be NULL
159: Level: advanced
161: .keywords: MG, get, multigrid, interpolation, level
163: .seealso: PCMGGetRestriction(), PCMGSetInterpolation(), PCMGGetRScale()
164: @*/
165: PetscErrorCode PCMGGetInterpolation(PC pc,PetscInt l,Mat *mat)
166: {
167: PC_MG *mg = (PC_MG*)pc->data;
168: PC_MG_Levels **mglevels = mg->levels;
174: if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
175: if (l <= 0 || mg->nlevels <= l) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Level %D must be in range {1,...,%D}",l,mg->nlevels-1);
176: if (!mglevels[l]->interpolate) {
177: if (!mglevels[l]->restrct) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must call PCMGSetInterpolation() or PCMGSetRestriction()");
178: PCMGSetInterpolation(pc,l,mglevels[l]->restrct);
179: }
180: if (mat) *mat = mglevels[l]->interpolate;
181: return(0);
182: }
186: /*@
187: PCMGSetRestriction - Sets the function to be used to restrict vector
188: from level l to l-1.
190: Logically Collective on PC and Mat
192: Input Parameters:
193: + pc - the multigrid context
194: . l - the level (0 is coarsest) to supply [Do not supply 0]
195: - mat - the restriction matrix
197: Level: advanced
199: Notes:
200: Usually this is the same matrix used also to set the interpolation
201: for the same level.
203: One can pass in the interpolation matrix or its transpose; PETSc figures
204: out from the matrix size which one it is.
206: If you do not set this, the transpose of the Mat set with PCMGSetInterpolation()
207: is used.
209: .keywords: MG, set, multigrid, restriction, level
211: .seealso: PCMGSetInterpolation()
212: @*/
213: PetscErrorCode PCMGSetRestriction(PC pc,PetscInt l,Mat mat)
214: {
216: PC_MG *mg = (PC_MG*)pc->data;
217: PC_MG_Levels **mglevels = mg->levels;
222: if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
223: if (!l) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Do not set restriction routine for coarsest level");
224: PetscObjectReference((PetscObject)mat);
225: MatDestroy(&mglevels[l]->restrct);
227: mglevels[l]->restrct = mat;
228: return(0);
229: }
233: /*@
234: PCMGGetRestriction - Gets the function to be used to restrict vector
235: from level l to l-1.
237: Logically Collective on PC and Mat
239: Input Parameters:
240: + pc - the multigrid context
241: - l - the level (0 is coarsest) to supply [Do not supply 0]
243: Output Parameter:
244: . mat - the restriction matrix
246: Level: advanced
248: .keywords: MG, get, multigrid, restriction, level
250: .seealso: PCMGGetInterpolation(), PCMGSetRestriction(), PCMGGetRScale()
251: @*/
252: PetscErrorCode PCMGGetRestriction(PC pc,PetscInt l,Mat *mat)
253: {
254: PC_MG *mg = (PC_MG*)pc->data;
255: PC_MG_Levels **mglevels = mg->levels;
261: if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
262: if (l <= 0 || mg->nlevels <= l) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Level %D must be in range {1,...,%D}",l,mg->nlevels-1);
263: if (!mglevels[l]->restrct) {
264: if (!mglevels[l]->interpolate) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must call PCMGSetRestriction() or PCMGSetInterpolation()");
265: PCMGSetRestriction(pc,l,mglevels[l]->interpolate);
266: }
267: if (mat) *mat = mglevels[l]->restrct;
268: return(0);
269: }
273: /*@
274: PCMGSetRScale - Sets the pointwise scaling for the restriction operator from level l to l-1.
276: Logically Collective on PC and Vec
278: Input Parameters:
279: + pc - the multigrid context
280: - l - the level (0 is coarsest) to supply [Do not supply 0]
281: . rscale - the scaling
283: Level: advanced
285: Notes:
286: When evaluating a function on a coarse level one does not want to do F(R * x) one does F(rscale * R * x) where rscale is 1 over the row sums of R.
288: .keywords: MG, set, multigrid, restriction, level
290: .seealso: PCMGSetInterpolation(), PCMGSetRestriction(), PCMGGetRScale()
291: @*/
292: PetscErrorCode PCMGSetRScale(PC pc,PetscInt l,Vec rscale)
293: {
295: PC_MG *mg = (PC_MG*)pc->data;
296: PC_MG_Levels **mglevels = mg->levels;
300: if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
301: if (l <= 0 || mg->nlevels <= l) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Level %D must be in range {1,...,%D}",l,mg->nlevels-1);
302: PetscObjectReference((PetscObject)rscale);
303: VecDestroy(&mglevels[l]->rscale);
305: mglevels[l]->rscale = rscale;
306: return(0);
307: }
311: /*@
312: PCMGGetRScale - Gets the pointwise scaling for the restriction operator from level l to l-1.
314: Collective on PC
316: Input Parameters:
317: + pc - the multigrid context
318: . rscale - the scaling
319: - l - the level (0 is coarsest) to supply [Do not supply 0]
321: Level: advanced
323: Notes:
324: When evaluating a function on a coarse level one does not want to do F(R * x) one does F(rscale * R * x) where rscale is 1 over the row sums of R.
326: .keywords: MG, set, multigrid, restriction, level
328: .seealso: PCMGSetInterpolation(), PCMGGetRestriction()
329: @*/
330: PetscErrorCode PCMGGetRScale(PC pc,PetscInt l,Vec *rscale)
331: {
333: PC_MG *mg = (PC_MG*)pc->data;
334: PC_MG_Levels **mglevels = mg->levels;
338: if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
339: if (l <= 0 || mg->nlevels <= l) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Level %D must be in range {1,...,%D}",l,mg->nlevels-1);
340: if (!mglevels[l]->rscale) {
341: Mat R;
342: Vec X,Y,coarse,fine;
343: PetscInt M,N;
344: PCMGGetRestriction(pc,l,&R);
345: MatCreateVecs(R,&X,&Y);
346: MatGetSize(R,&M,&N);
347: if (M < N) {
348: fine = X;
349: coarse = Y;
350: } else if (N < M) {
351: fine = Y; coarse = X;
352: } else SETERRQ(PetscObjectComm((PetscObject)R),PETSC_ERR_SUP,"Restriction matrix is square, cannot determine which Vec is coarser");
353: VecSet(fine,1.);
354: MatRestrict(R,fine,coarse);
355: VecDestroy(&fine);
356: VecReciprocal(coarse);
357: mglevels[l]->rscale = coarse;
358: }
359: *rscale = mglevels[l]->rscale;
360: return(0);
361: }
365: /*@
366: PCMGGetSmoother - Gets the KSP context to be used as smoother for
367: both pre- and post-smoothing. Call both PCMGGetSmootherUp() and
368: PCMGGetSmootherDown() to use different functions for pre- and
369: post-smoothing.
371: Not Collective, KSP returned is parallel if PC is
373: Input Parameters:
374: + pc - the multigrid context
375: - l - the level (0 is coarsest) to supply
377: Ouput Parameters:
378: . ksp - the smoother
380: Notes:
381: Once you have called this routine, you can call KSPSetOperators(ksp,...) on the resulting ksp to provide the operators for the smoother for this level.
382: You can also modify smoother options by calling the various KSPSetXXX() options on this ksp. In addition you can call KSPGetPC(ksp,&pc)
383: and modify PC options for the smoother; for example PCSetType(pc,PCSOR); to use SOR smoothing.
385: Level: advanced
387: .keywords: MG, get, multigrid, level, smoother, pre-smoother, post-smoother
389: .seealso: PCMGGetSmootherUp(), PCMGGetSmootherDown()
390: @*/
391: PetscErrorCode PCMGGetSmoother(PC pc,PetscInt l,KSP *ksp)
392: {
393: PC_MG *mg = (PC_MG*)pc->data;
394: PC_MG_Levels **mglevels = mg->levels;
398: *ksp = mglevels[l]->smoothd;
399: return(0);
400: }
404: /*@
405: PCMGGetSmootherUp - Gets the KSP context to be used as smoother after
406: coarse grid correction (post-smoother).
408: Not Collective, KSP returned is parallel if PC is
410: Input Parameters:
411: + pc - the multigrid context
412: - l - the level (0 is coarsest) to supply
414: Ouput Parameters:
415: . ksp - the smoother
417: Level: advanced
419: Notes: calling this will result in a different pre and post smoother so you may need to
420: set options on the pre smoother also
422: .keywords: MG, multigrid, get, smoother, up, post-smoother, level
424: .seealso: PCMGGetSmootherUp(), PCMGGetSmootherDown()
425: @*/
426: PetscErrorCode PCMGGetSmootherUp(PC pc,PetscInt l,KSP *ksp)
427: {
428: PC_MG *mg = (PC_MG*)pc->data;
429: PC_MG_Levels **mglevels = mg->levels;
431: const char *prefix;
432: MPI_Comm comm;
436: /*
437: This is called only if user wants a different pre-smoother from post.
438: Thus we check if a different one has already been allocated,
439: if not we allocate it.
440: */
441: if (!l) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"There is no such thing as a up smoother on the coarse grid");
442: if (mglevels[l]->smoothu == mglevels[l]->smoothd) {
443: KSPType ksptype;
444: PCType pctype;
445: PC ipc;
446: PetscReal rtol,abstol,dtol;
447: PetscInt maxits;
448: KSPNormType normtype;
449: PetscObjectGetComm((PetscObject)mglevels[l]->smoothd,&comm);
450: KSPGetOptionsPrefix(mglevels[l]->smoothd,&prefix);
451: KSPGetTolerances(mglevels[l]->smoothd,&rtol,&abstol,&dtol,&maxits);
452: KSPGetType(mglevels[l]->smoothd,&ksptype);
453: KSPGetNormType(mglevels[l]->smoothd,&normtype);
454: KSPGetPC(mglevels[l]->smoothd,&ipc);
455: PCGetType(ipc,&pctype);
457: KSPCreate(comm,&mglevels[l]->smoothu);
458: KSPSetErrorIfNotConverged(mglevels[l]->smoothu,pc->erroriffailure);
459: PetscObjectIncrementTabLevel((PetscObject)mglevels[l]->smoothu,(PetscObject)pc,mglevels[0]->levels-l);
460: KSPSetOptionsPrefix(mglevels[l]->smoothu,prefix);
461: KSPSetTolerances(mglevels[l]->smoothu,rtol,abstol,dtol,maxits);
462: KSPSetType(mglevels[l]->smoothu,ksptype);
463: KSPSetNormType(mglevels[l]->smoothu,normtype);
464: KSPSetConvergenceTest(mglevels[l]->smoothu,KSPConvergedSkip,NULL,NULL);
465: KSPGetPC(mglevels[l]->smoothu,&ipc);
466: PCSetType(ipc,pctype);
467: PetscLogObjectParent((PetscObject)pc,(PetscObject)mglevels[l]->smoothu);
468: PetscObjectComposedDataSetInt((PetscObject) mglevels[l]->smoothu, PetscMGLevelId, mglevels[l]->level);
469: }
470: if (ksp) *ksp = mglevels[l]->smoothu;
471: return(0);
472: }
476: /*@
477: PCMGGetSmootherDown - Gets the KSP context to be used as smoother before
478: coarse grid correction (pre-smoother).
480: Not Collective, KSP returned is parallel if PC is
482: Input Parameters:
483: + pc - the multigrid context
484: - l - the level (0 is coarsest) to supply
486: Ouput Parameters:
487: . ksp - the smoother
489: Level: advanced
491: Notes: calling this will result in a different pre and post smoother so you may need to
492: set options on the post smoother also
494: .keywords: MG, multigrid, get, smoother, down, pre-smoother, level
496: .seealso: PCMGGetSmootherUp(), PCMGGetSmoother()
497: @*/
498: PetscErrorCode PCMGGetSmootherDown(PC pc,PetscInt l,KSP *ksp)
499: {
501: PC_MG *mg = (PC_MG*)pc->data;
502: PC_MG_Levels **mglevels = mg->levels;
506: /* make sure smoother up and down are different */
507: if (l) {
508: PCMGGetSmootherUp(pc,l,NULL);
509: }
510: *ksp = mglevels[l]->smoothd;
511: return(0);
512: }
516: /*@
517: PCMGSetCyclesOnLevel - Sets the number of cycles to run on this level.
519: Logically Collective on PC
521: Input Parameters:
522: + pc - the multigrid context
523: . l - the level (0 is coarsest) this is to be used for
524: - n - the number of cycles
526: Level: advanced
528: .keywords: MG, multigrid, set, cycles, V-cycle, W-cycle, level
530: .seealso: PCMGSetCycles()
531: @*/
532: PetscErrorCode PCMGSetCyclesOnLevel(PC pc,PetscInt l,PetscInt c)
533: {
534: PC_MG *mg = (PC_MG*)pc->data;
535: PC_MG_Levels **mglevels = mg->levels;
539: if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
542: mglevels[l]->cycles = c;
543: return(0);
544: }
548: /*@
549: PCMGSetRhs - Sets the vector space to be used to store the right-hand side
550: on a particular level.
552: Logically Collective on PC and Vec
554: Input Parameters:
555: + pc - the multigrid context
556: . l - the level (0 is coarsest) this is to be used for
557: - c - the space
559: Level: advanced
561: Notes: If this is not provided PETSc will automatically generate one.
563: You do not need to keep a reference to this vector if you do
564: not need it PCDestroy() will properly free it.
566: .keywords: MG, multigrid, set, right-hand-side, rhs, level
568: .seealso: PCMGSetX(), PCMGSetR()
569: @*/
570: PetscErrorCode PCMGSetRhs(PC pc,PetscInt l,Vec c)
571: {
573: PC_MG *mg = (PC_MG*)pc->data;
574: PC_MG_Levels **mglevels = mg->levels;
578: if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
579: if (l == mglevels[0]->levels-1) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Do not set rhs for finest level");
580: PetscObjectReference((PetscObject)c);
581: VecDestroy(&mglevels[l]->b);
583: mglevels[l]->b = c;
584: return(0);
585: }
589: /*@
590: PCMGSetX - Sets the vector space to be used to store the solution on a
591: particular level.
593: Logically Collective on PC and Vec
595: Input Parameters:
596: + pc - the multigrid context
597: . l - the level (0 is coarsest) this is to be used for (do not supply the finest level)
598: - c - the space
600: Level: advanced
602: Notes: If this is not provided PETSc will automatically generate one.
604: You do not need to keep a reference to this vector if you do
605: not need it PCDestroy() will properly free it.
607: .keywords: MG, multigrid, set, solution, level
609: .seealso: PCMGSetRhs(), PCMGSetR()
610: @*/
611: PetscErrorCode PCMGSetX(PC pc,PetscInt l,Vec c)
612: {
614: PC_MG *mg = (PC_MG*)pc->data;
615: PC_MG_Levels **mglevels = mg->levels;
619: if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
620: if (l == mglevels[0]->levels-1) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Do not set x for finest level");
621: PetscObjectReference((PetscObject)c);
622: VecDestroy(&mglevels[l]->x);
624: mglevels[l]->x = c;
625: return(0);
626: }
630: /*@
631: PCMGSetR - Sets the vector space to be used to store the residual on a
632: particular level.
634: Logically Collective on PC and Vec
636: Input Parameters:
637: + pc - the multigrid context
638: . l - the level (0 is coarsest) this is to be used for
639: - c - the space
641: Level: advanced
643: Notes: If this is not provided PETSc will automatically generate one.
645: You do not need to keep a reference to this vector if you do
646: not need it PCDestroy() will properly free it.
648: .keywords: MG, multigrid, set, residual, level
649: @*/
650: PetscErrorCode PCMGSetR(PC pc,PetscInt l,Vec c)
651: {
653: PC_MG *mg = (PC_MG*)pc->data;
654: PC_MG_Levels **mglevels = mg->levels;
658: if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
659: if (!l) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Need not set residual vector for coarse grid");
660: PetscObjectReference((PetscObject)c);
661: VecDestroy(&mglevels[l]->r);
663: mglevels[l]->r = c;
664: return(0);
665: }