Actual source code: damg.c
1: /*$Id: damg.c,v 1.32 2001/04/10 19:36:47 bsmith Exp $*/
2:
3: #include "petscda.h" /*I "petscda.h" I*/
4: #include "petscsles.h" /*I "petscsles.h" I*/
5: #include "petscmg.h" /*I "petscmg.h" I*/
7: /*
8: Code for almost fully managing multigrid/multi-level linear solvers for DA grids
9: */
11: /*@C
12: DMMGCreate - Creates a DA based multigrid solver object. This allows one to
13: easily implement MG methods on regular grids.
15: Collective on MPI_Comm
17: Input Parameter:
18: + comm - the processors that will share the grids and solution process
19: . nlevels - number of multigrid levels
20: - user - an optional user context
22: Output Parameters:
23: . - the context
25: Notes:
26: To provide a different user context for each level, or to change the
27: ratio in the grid spacing simply change the DMMG structure after calling this routine
29: Level: advanced
31: .seealso DMMGDestroy()
33: @*/
34: int DMMGCreate(MPI_Comm comm,int nlevels,void *user,DMMG **dmmg)
35: {
36: int ierr,i;
37: DMMG *p;
40: PetscOptionsGetInt(0,"-dmmg_nlevels",&nlevels,PETSC_IGNORE);
42: PetscMalloc(nlevels*sizeof(DMMG),&p);
43: for (i=0; i<nlevels; i++) {
44: ierr = PetscNew(struct _p_DMMG,&p[i]);
45: ierr = PetscMemzero(p[i],sizeof(struct _p_DMMG));
46: p[i]->nlevels = nlevels - i;
47: p[i]->comm = comm;
48: p[i]->user = user;
49: p[i]->matrixfree = PETSC_FALSE;
50: }
51: *dmmg = p;
52: return(0);
53: }
55: /*@C
56: DMMGSetUseMatrixFree - Use matrix-free version of operator
58: Collective on DMMG
60: Input Parameter:
61: . - the context
63: Level: advanced
65: .seealso DMMGCreate()
67: @*/
68: int DMMGSetUseMatrixFree(DMMG *dmmg)
69: {
70: int i,nlevels = dmmg[0]->nlevels;
73: if (!dmmg) SETERRQ(1,"Passing null as DMMG");
74: for (i=0; i<nlevels; i++) {
75: dmmg[i]->matrixfree = PETSC_TRUE;
76: }
77: return(0);
78: }
80: /*@C
81: DMMGDestroy - Destroys a DA based multigrid solver object.
83: Collective on DMMG
85: Input Parameter:
86: . - the context
88: Level: advanced
90: .seealso DMMGCreate()
92: @*/
93: int DMMGDestroy(DMMG *dmmg)
94: {
95: int ierr,i,nlevels = dmmg[0]->nlevels;
98: if (!dmmg) SETERRQ(1,"Passing null as DMMG");
100: for (i=1; i<nlevels; i++) {
101: if (dmmg[i]->R) {MatDestroy(dmmg[i]->R);}
102: }
103: for (i=0; i<nlevels; i++) {
104: if (dmmg[i]->dm) {DMDestroy(dmmg[i]->dm);}
105: if (dmmg[i]->x) {VecDestroy(dmmg[i]->x);}
106: if (dmmg[i]->b) {VecDestroy(dmmg[i]->b);}
107: if (dmmg[i]->r) {VecDestroy(dmmg[i]->r);}
108: if (dmmg[i]->work1) {VecDestroy(dmmg[i]->work1);}
109: if (dmmg[i]->work2) {VecDestroy(dmmg[i]->work2);}
110: if (dmmg[i]->B && dmmg[i]->B != dmmg[i]->J) {MatDestroy(dmmg[i]->B);}
111: if (dmmg[i]->J) {MatDestroy(dmmg[i]->J);}
112: if (dmmg[i]->Rscale) {VecDestroy(dmmg[i]->Rscale);}
113: if (dmmg[i]->fdcoloring) {MatFDColoringDestroy(dmmg[i]->fdcoloring);}
114: if (dmmg[i]->iscoloring) {ISColoringDestroy(dmmg[i]->iscoloring);}
115: if (dmmg[i]->sles) {SLESDestroy(dmmg[i]->sles);}
116: if (dmmg[i]->snes) {PetscObjectDestroy((PetscObject)dmmg[i]->snes);}
117: PetscFree(dmmg[i]);
118: }
119: PetscFree(dmmg);
120: return(0);
121: }
123: /*@C
124: DMMGSetDM - Sets the coarse grid information for the grids
126: Collective on DMMG
128: Input Parameter:
129: + dmmg - the context
130: - dm - the DA or VecPack object
132: Level: advanced
134: .seealso DMMGCreate(), DMMGDestroy()
136: @*/
137: int DMMGSetDM(DMMG *dmmg,DM dm)
138: {
139: int ierr,i,nlevels = dmmg[0]->nlevels;
142: if (!dmmg) SETERRQ(1,"Passing null as DMMG");
144: /* Create DA data structure for all the levels */
145: dmmg[0]->dm = dm;
146: PetscObjectReference((PetscObject)dm);
147: for (i=1; i<nlevels; i++) {
148: DMRefine(dmmg[i-1]->dm,dmmg[i]->comm,&dmmg[i]->dm);
149: }
150: DMMGSetUp(dmmg);
151: return(0);
152: }
154: /*@C
155: DMMGSetUp - Prepares the DMMG to solve a system
157: Collective on DMMG
159: Input Parameter:
160: . dmmg - the context
162: Level: advanced
164: .seealso DMMGCreate(), DMMGDestroy(), DMMG, DMMGSetSNES(), DMMGSetSLES(), DMMGSolve()
166: @*/
167: int DMMGSetUp(DMMG *dmmg)
168: {
169: int ierr,i,nlevels = dmmg[0]->nlevels;
170: PetscTruth flg;
173: PetscOptionsHasName(PETSC_NULL,"-dmmg_snes_mf",&flg);
174: if (flg) {
175: DMMGSetUseMatrixFree(dmmg);
176: }
178: /* Create work vectors and matrix for each level */
179: for (i=0; i<nlevels; i++) {
180: DMCreateGlobalVector(dmmg[i]->dm,&dmmg[i]->x);
181: VecDuplicate(dmmg[i]->x,&dmmg[i]->b);
182: VecDuplicate(dmmg[i]->x,&dmmg[i]->r);
183: if (!dmmg[i]->matrixfree) {
184: DMGetColoring(dmmg[i]->dm,IS_COLORING_GLOBAL,MATMPIAIJ,PETSC_NULL,&dmmg[i]->J);
185: }
186: dmmg[i]->B = dmmg[i]->J;
187: }
189: /* Create interpolation/restriction between levels */
190: for (i=1; i<nlevels; i++) {
191: DMGetInterpolation(dmmg[i-1]->dm,dmmg[i]->dm,&dmmg[i]->R,PETSC_NULL);
192: }
194: PetscOptionsHasName(PETSC_NULL,"-dmmg_view",&flg);
195: if (flg) {
196: DMMGView(dmmg,PETSC_VIEWER_STDOUT_(dmmg[0]->comm));
197: }
198: return(0);
199: }
201: /*@C
202: DMMGSolve - Actually solves the (non)linear system defined with the DMMG
204: Collective on DMMG
206: Input Parameter:
207: . dmmg - the context
209: Level: advanced
211: .seealso DMMGCreate(), DMMGDestroy(), DMMG, DMMGSetSNES(), DMMGSetSLES(), DMMGSetUp()
213: @*/
214: int DMMGSolve(DMMG *dmmg)
215: {
216: int i,ierr,nlevels = dmmg[0]->nlevels;
217: PetscTruth gridseq,vecmonitor;
218: KSP ksp;
221: PetscOptionsHasName(0,"-dmmg_grid_sequence",&gridseq);
222: PetscOptionsHasName(0,"-dmmg_vecmonitor",&vecmonitor);
223: if (gridseq) {
224: if (dmmg[0]->initialguess) {
225: (*dmmg[0]->initialguess)(dmmg[0]->snes,dmmg[0]->x,dmmg[0]);
226: if (dmmg[0]->sles) {
227: SLESGetKSP(dmmg[0]->sles,&ksp);
228: KSPSetInitialGuessNonzero(ksp);
229: }
230: }
231: for (i=0; i<nlevels-1; i++) {
232: (*dmmg[i]->solve)(dmmg,i);
233: if (vecmonitor) {
234: VecView(dmmg[i]->x,PETSC_VIEWER_DRAW_(dmmg[i]->comm));
235: }
236: MatInterpolate(dmmg[i+1]->R,dmmg[i]->x,dmmg[i+1]->x);
237: if (dmmg[i+1]->sles) {
238: SLESGetKSP(dmmg[i+1]->sles,&ksp);
239: KSPSetInitialGuessNonzero(ksp);
240: }
241: }
242: } else {
243: if (dmmg[nlevels-1]->initialguess) {
244: (*dmmg[nlevels-1]->initialguess)(dmmg[nlevels-1]->snes,dmmg[nlevels-1]->x,dmmg[nlevels-1]);
245: if (dmmg[nlevels-1]->sles) {
246: SLESGetKSP(dmmg[nlevels-1]->sles,&ksp);
247: KSPSetInitialGuessNonzero(ksp);
248: }
249: }
250: }
251: (*DMMGGetFine(dmmg)->solve)(dmmg,nlevels-1);
252: if (vecmonitor) {
253: VecView(dmmg[nlevels-1]->x,PETSC_VIEWER_DRAW_(dmmg[nlevels-1]->comm));
254: }
255: return(0);
256: }
258: int DMMGSolveSLES(DMMG *dmmg,int level)
259: {
260: int ierr,its;
263: (*dmmg[level]->rhs)(dmmg[level],dmmg[level]->b);
264: SLESSetOperators(dmmg[level]->sles,dmmg[level]->J,dmmg[level]->J,DIFFERENT_NONZERO_PATTERN);
265: SLESSolve(dmmg[level]->sles,dmmg[level]->b,dmmg[level]->x,&its);
266: return(0);
267: }
269: /*
270: Sets each of the linear solvers to use multigrid
271: */
272: int DMMGSetUpLevel(DMMG *dmmg,SLES sles,int nlevels)
273: {
274: int ierr,i;
275: PC pc;
276: PetscTruth ismg,monitor;
277: SLES lsles; /* solver internal to the multigrid preconditioner */
278: MPI_Comm *comms,comm;
279: PetscViewer ascii;
280: KSP ksp;
284: if (!dmmg) SETERRQ(1,"Passing null as DMMG");
286: PetscOptionsHasName(PETSC_NULL,"-dmmg_ksp_monitor",&monitor);
287: if (monitor) {
288: SLESGetKSP(sles,&ksp);
289: PetscObjectGetComm((PetscObject)ksp,&comm);
290: PetscViewerASCIIOpen(comm,"stdout",&ascii);
291: PetscViewerASCIISetTab(ascii,1+dmmg[0]->nlevels-nlevels);
292: KSPSetMonitor(ksp,KSPDefaultMonitor,ascii,(int(*)(void*))PetscViewerDestroy);
293: }
295: ierr = SLESGetPC(sles,&pc);
296: ierr = PCSetType(pc,PCMG);
297: ierr = PetscMalloc(nlevels*sizeof(MPI_Comm),&comms);
298: for (i=0; i<nlevels; i++) {
299: comms[i] = dmmg[i]->comm;
300: }
301: ierr = MGSetLevels(pc,nlevels,comms);
302: ierr = PetscFree(comms);
304: PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
305: if (ismg) {
307: /* set solvers for each level */
308: for (i=0; i<nlevels; i++) {
309: MGGetSmoother(pc,i,&lsles);
310: SLESSetOperators(lsles,dmmg[i]->J,dmmg[i]->J,DIFFERENT_NONZERO_PATTERN);
311: MGSetX(pc,i,dmmg[i]->x);
312: MGSetRhs(pc,i,dmmg[i]->b);
313: MGSetR(pc,i,dmmg[i]->r);
314: MGSetResidual(pc,i,MGDefaultResidual,dmmg[i]->J);
315: if (monitor) {
316: SLESGetKSP(lsles,&ksp);
317: PetscObjectGetComm((PetscObject)ksp,&comm);
318: PetscViewerASCIIOpen(comm,"stdout",&ascii);
319: PetscViewerASCIISetTab(ascii,1+dmmg[0]->nlevels-i);
320: KSPSetMonitor(ksp,KSPDefaultMonitor,ascii,(int(*)(void*))PetscViewerDestroy);
321: }
322: /* If using a matrix free multiply and did not provide an explicit matrix to build
323: the preconditioner then must use no preconditioner
324: */
325: if (dmmg[i]->matrixfree && dmmg[i]->J == dmmg[i]->B) {
326: PC lpc;
327: SLESGetPC(lsles,&lpc);
328: PCSetType(lpc,PCNONE);
329: }
330: }
332: /* Set interpolation/restriction between levels */
333: for (i=1; i<nlevels; i++) {
334: MGSetInterpolate(pc,i,dmmg[i]->R);
335: MGSetRestriction(pc,i,dmmg[i]->R);
336: }
337: }
338: return(0);
339: }
341: /*@C
342: DMMGSetSLES - Sets the linear solver object that will use the grid hierarchy
344: Collective on DMMG and SLES
346: Input Parameter:
347: + dmmg - the context
348: . func - function to compute linear system matrix on each grid level
349: - rhs - function to compute right hand side on each level
351: Level: advanced
353: .seealso DMMGCreate(), DMMGDestroy, DMMGSetDM()
355: @*/
356: int DMMGSetSLES(DMMG *dmmg,int (*rhs)(DMMG,Vec),int (*func)(DMMG,Mat))
357: {
358: int ierr,i,nlevels = dmmg[0]->nlevels;
361: if (!dmmg) SETERRQ(1,"Passing null as DMMG");
363: /* create solvers for each level */
364: for (i=0; i<nlevels; i++) {
365: SLESCreate(dmmg[i]->comm,&dmmg[i]->sles);
366: DMMGSetUpLevel(dmmg,dmmg[i]->sles,i+1);
367: SLESSetFromOptions(dmmg[i]->sles);
368: dmmg[i]->solve = DMMGSolveSLES;
369: dmmg[i]->rhs = rhs;
370: }
372: /* evalute matrix on each level */
373: for (i=0; i<nlevels; i++) {
374: (*func)(dmmg[i],dmmg[i]->J);
375: }
377: for (i=0; i<nlevels-1; i++) {
378: SLESSetOptionsPrefix(dmmg[i]->sles,"dmmg_");
379: }
381: return(0);
382: }
384: /*@C
385: DMMGView - prints information on a DA based multi-level preconditioner
387: Collective on DMMG and PetscViewer
389: Input Parameter:
390: + dmmg - the context
391: - viewer - the viewer
393: Level: advanced
395: .seealso DMMGCreate(), DMMGDestroy
397: @*/
398: int DMMGView(DMMG *dmmg,PetscViewer viewer)
399: {
400: int ierr,i,nlevels = dmmg[0]->nlevels,flag;
401: MPI_Comm comm;
402: PetscTruth isascii;
405: if (!dmmg) SETERRQ(1,"Passing null as DMMG");
407: PetscObjectGetComm((PetscObject)viewer,&comm);
408: MPI_Comm_compare(comm,dmmg[0]->comm,&flag);
409: if (flag != MPI_CONGRUENT && flag != MPI_IDENT) {
410: SETERRQ(PETSC_ERR_ARG_NOTSAMECOMM,"Different communicators in the DMMG and the PetscViewer");
411: }
413: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
414: if (isascii) {
415: PetscViewerASCIIPrintf(viewer,"DMMG Object with %d levelsn",nlevels);
416: for (i=0; i<nlevels; i++) {
417: PetscViewerASCIIPushTab(viewer);
418: DMView(dmmg[i]->dm,viewer);
419: PetscViewerASCIIPopTab(viewer);
420: }
421: } else {
422: SETERRQ1(1,"Viewer type %s not supported",*((PetscObject)viewer)->type_name);
423: }
424: return(0);
425: }