Actual source code: damg.c
1: /*$Id: damg.c,v 1.35 2001/07/20 21:25:12 bsmith Exp $*/
2:
3: #include petscda.h
4: #include petscsles.h
5: #include petscmg.h
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 call DMMGSetUser() after calling
27: 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;
38: PetscTruth galerkin;
41: PetscOptionsGetInt(0,"-dmmg_nlevels",&nlevels,PETSC_IGNORE);
42: PetscOptionsHasName(0,"-dmmg_galerkin",&galerkin);
44: PetscMalloc(nlevels*sizeof(DMMG),&p);
45: for (i=0; i<nlevels; i++) {
46: ierr = PetscNew(struct _p_DMMG,&p[i]);
47: ierr = PetscMemzero(p[i],sizeof(struct _p_DMMG));
48: p[i]->nlevels = nlevels - i;
49: p[i]->comm = comm;
50: p[i]->user = user;
51: p[i]->galerkin = galerkin;
52: }
53: *dmmg = p;
54: return(0);
55: }
57: /*@C
58: DMMGSetUseGalerkinCoarse - Courses the DMMG to use R*A_f*R^T to form
59: the coarser matrices from finest
61: Collective on DMMG
63: Input Parameter:
64: . - the context
66: Level: advanced
68: .seealso DMMGCreate()
70: @*/
71: int DMMGSetUseGalerkinCoarse(DMMG* dmmg)
72: {
73: int i,nlevels = dmmg[0]->nlevels;
76: if (!dmmg) SETERRQ(1,"Passing null as DMMG");
78: for (i=0; i<nlevels; i++) {
79: dmmg[i]->galerkin = PETSC_TRUE;
80: }
81: return(0);
82: }
84: /*@C
85: DMMGDestroy - Destroys a DA based multigrid solver object.
87: Collective on DMMG
89: Input Parameter:
90: . - the context
92: Level: advanced
94: .seealso DMMGCreate()
96: @*/
97: int DMMGDestroy(DMMG *dmmg)
98: {
99: int ierr,i,nlevels = dmmg[0]->nlevels;
102: if (!dmmg) SETERRQ(1,"Passing null as DMMG");
104: for (i=1; i<nlevels; i++) {
105: if (dmmg[i]->R) {MatDestroy(dmmg[i]->R);}
106: }
107: for (i=0; i<nlevels; i++) {
108: if (dmmg[i]->dm) {DMDestroy(dmmg[i]->dm);}
109: if (dmmg[i]->x) {VecDestroy(dmmg[i]->x);}
110: if (dmmg[i]->b) {VecDestroy(dmmg[i]->b);}
111: if (dmmg[i]->r) {VecDestroy(dmmg[i]->r);}
112: if (dmmg[i]->work1) {VecDestroy(dmmg[i]->work1);}
113: if (dmmg[i]->w) {VecDestroy(dmmg[i]->w);}
114: if (dmmg[i]->work2) {VecDestroy(dmmg[i]->work2);}
115: if (dmmg[i]->lwork1) {VecDestroy(dmmg[i]->lwork1);}
116: if (dmmg[i]->B && dmmg[i]->B != dmmg[i]->J) {MatDestroy(dmmg[i]->B);}
117: if (dmmg[i]->J) {MatDestroy(dmmg[i]->J);}
118: if (dmmg[i]->Rscale) {VecDestroy(dmmg[i]->Rscale);}
119: if (dmmg[i]->fdcoloring) {MatFDColoringDestroy(dmmg[i]->fdcoloring);}
120: if (dmmg[i]->sles) {SLESDestroy(dmmg[i]->sles);}
121: if (dmmg[i]->snes) {PetscObjectDestroy((PetscObject)dmmg[i]->snes);}
122: PetscFree(dmmg[i]);
123: }
124: PetscFree(dmmg);
125: return(0);
126: }
128: /*@C
129: DMMGSetDM - Sets the coarse grid information for the grids
131: Collective on DMMG
133: Input Parameter:
134: + dmmg - the context
135: - dm - the DA or VecPack object
137: Level: advanced
139: .seealso DMMGCreate(), DMMGDestroy()
141: @*/
142: int DMMGSetDM(DMMG *dmmg,DM dm)
143: {
144: int ierr,i,nlevels = dmmg[0]->nlevels;
147: if (!dmmg) SETERRQ(1,"Passing null as DMMG");
149: /* Create DA data structure for all the levels */
150: dmmg[0]->dm = dm;
151: PetscObjectReference((PetscObject)dm);
152: for (i=1; i<nlevels; i++) {
153: DMRefine(dmmg[i-1]->dm,dmmg[i]->comm,&dmmg[i]->dm);
154: }
155: DMMGSetUp(dmmg);
156: return(0);
157: }
159: /*@C
160: DMMGSetUp - Prepares the DMMG to solve a system
162: Collective on DMMG
164: Input Parameter:
165: . dmmg - the context
167: Level: advanced
169: .seealso DMMGCreate(), DMMGDestroy(), DMMG, DMMGSetSNES(), DMMGSetSLES(), DMMGSolve()
171: @*/
172: int DMMGSetUp(DMMG *dmmg)
173: {
174: int ierr,i,nlevels = dmmg[0]->nlevels;
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: }
185: /* Create interpolation/restriction between levels */
186: for (i=1; i<nlevels; i++) {
187: DMGetInterpolation(dmmg[i-1]->dm,dmmg[i]->dm,&dmmg[i]->R,PETSC_NULL);
188: }
190: return(0);
191: }
193: /*@C
194: DMMGSolve - Actually solves the (non)linear system defined with the DMMG
196: Collective on DMMG
198: Input Parameter:
199: . dmmg - the context
201: Level: advanced
203: Notes: For linear (SLES) problems may be called more than once, uses the same
204: matrices but recomputes the right hand side for each new solve. Call DMMGSetSLES()
205: to generate new matrices.
206:
207: .seealso DMMGCreate(), DMMGDestroy(), DMMG, DMMGSetSNES(), DMMGSetSLES(), DMMGSetUp()
209: @*/
210: int DMMGSolve(DMMG *dmmg)
211: {
212: int i,ierr,nlevels = dmmg[0]->nlevels;
213: PetscTruth gridseq,vecmonitor,flg;
214: KSP ksp;
217: PetscOptionsHasName(0,"-dmmg_grid_sequence",&gridseq);
218: PetscOptionsHasName(0,"-dmmg_vecmonitor",&vecmonitor);
219: if (gridseq) {
220: if (dmmg[0]->initialguess) {
221: (*dmmg[0]->initialguess)(dmmg[0]->snes,dmmg[0]->x,dmmg[0]);
222: if (dmmg[0]->sles) {
223: SLESGetKSP(dmmg[0]->sles,&ksp);
224: KSPSetInitialGuessNonzero(ksp,PETSC_TRUE);
225: }
226: }
227: for (i=0; i<nlevels-1; i++) {
228: (*dmmg[i]->solve)(dmmg,i);
229: if (vecmonitor) {
230: VecView(dmmg[i]->x,PETSC_VIEWER_DRAW_(dmmg[i]->comm));
231: }
232: MatInterpolate(dmmg[i+1]->R,dmmg[i]->x,dmmg[i+1]->x);
233: if (dmmg[i+1]->sles) {
234: SLESGetKSP(dmmg[i+1]->sles,&ksp);
235: KSPSetInitialGuessNonzero(ksp,PETSC_TRUE);
236: }
237: }
238: } else {
239: if (dmmg[nlevels-1]->initialguess) {
240: (*dmmg[nlevels-1]->initialguess)(dmmg[nlevels-1]->snes,dmmg[nlevels-1]->x,dmmg[nlevels-1]);
241: if (dmmg[nlevels-1]->sles) {
242: SLESGetKSP(dmmg[nlevels-1]->sles,&ksp);
243: KSPSetInitialGuessNonzero(ksp,PETSC_TRUE);
244: }
245: }
246: }
247: (*DMMGGetFine(dmmg)->solve)(dmmg,nlevels-1);
248: if (vecmonitor) {
249: VecView(dmmg[nlevels-1]->x,PETSC_VIEWER_DRAW_(dmmg[nlevels-1]->comm));
250: }
252: PetscOptionsHasName(PETSC_NULL,"-dmmg_view",&flg);
253: if (flg && !PetscPreLoadingOn) {
254: DMMGView(dmmg,PETSC_VIEWER_STDOUT_(dmmg[0]->comm));
255: }
256: return(0);
257: }
259: int DMMGSolveSLES(DMMG *dmmg,int level)
260: {
261: int ierr,its;
264: (*dmmg[level]->rhs)(dmmg[level],dmmg[level]->b);
265: if (dmmg[level]->matricesset) {
266: SLESSetOperators(dmmg[level]->sles,dmmg[level]->J,dmmg[level]->J,SAME_NONZERO_PATTERN);
267: dmmg[level]->matricesset = PETSC_FALSE;
268: }
269: SLESSolve(dmmg[level]->sles,dmmg[level]->b,dmmg[level]->x,&its);
270: return(0);
271: }
273: /*
274: Sets each of the linear solvers to use multigrid
275: */
276: int DMMGSetUpLevel(DMMG *dmmg,SLES sles,int nlevels)
277: {
278: int ierr,i;
279: PC pc;
280: PetscTruth ismg,monitor,ismf,isshell,ismffd;
281: SLES lsles; /* solver internal to the multigrid preconditioner */
282: MPI_Comm *comms,comm;
283: PetscViewer ascii;
284: KSP ksp;
288: if (!dmmg) SETERRQ(1,"Passing null as DMMG");
290: PetscOptionsHasName(PETSC_NULL,"-dmmg_ksp_monitor",&monitor);
291: if (monitor) {
292: SLESGetKSP(sles,&ksp);
293: PetscObjectGetComm((PetscObject)ksp,&comm);
294: PetscViewerASCIIOpen(comm,"stdout",&ascii);
295: PetscViewerASCIISetTab(ascii,1+dmmg[0]->nlevels-nlevels);
296: KSPSetMonitor(ksp,KSPDefaultMonitor,ascii,(int(*)(void*))PetscViewerDestroy);
297: }
299: /* use fgmres on outer iteration by default */
300: SLESGetKSP(sles,&ksp);
301: KSPSetType(ksp,KSPFGMRES);
303: ierr = SLESGetPC(sles,&pc);
304: ierr = PCSetType(pc,PCMG);
305: ierr = PetscMalloc(nlevels*sizeof(MPI_Comm),&comms);
306: for (i=0; i<nlevels; i++) {
307: comms[i] = dmmg[i]->comm;
308: }
309: ierr = MGSetLevels(pc,nlevels,comms);
310: ierr = PetscFree(comms);
311: MGSetType(pc,MGFULL);
313: PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
314: if (ismg) {
316: /* set solvers for each level */
317: for (i=0; i<nlevels; i++) {
318: MGGetSmoother(pc,i,&lsles);
319: SLESSetOperators(lsles,dmmg[i]->J,dmmg[i]->B,DIFFERENT_NONZERO_PATTERN);
320: MGSetX(pc,i,dmmg[i]->x);
321: MGSetRhs(pc,i,dmmg[i]->b);
322: MGSetR(pc,i,dmmg[i]->r);
323: MGSetResidual(pc,i,MGDefaultResidual,dmmg[i]->J);
324: if (monitor) {
325: SLESGetKSP(lsles,&ksp);
326: PetscObjectGetComm((PetscObject)ksp,&comm);
327: PetscViewerASCIIOpen(comm,"stdout",&ascii);
328: PetscViewerASCIISetTab(ascii,1+dmmg[0]->nlevels-i);
329: KSPSetMonitor(ksp,KSPDefaultMonitor,ascii,(int(*)(void*))PetscViewerDestroy);
330: }
331: /* If using a matrix free multiply and did not provide an explicit matrix to build
332: the preconditioner then must use no preconditioner
333: */
334: PetscTypeCompare((PetscObject)dmmg[i]->B,MATSHELL,&isshell);
335: PetscTypeCompare((PetscObject)dmmg[i]->B,MATDAAD,&ismf);
336: PetscTypeCompare((PetscObject)dmmg[i]->B,MATMFFD,&ismffd);
337: if (isshell || ismf || ismffd) {
338: PC lpc;
339: SLESGetPC(lsles,&lpc);
340: PCSetType(lpc,PCNONE);
341: }
342: }
344: /* Set interpolation/restriction between levels */
345: for (i=1; i<nlevels; i++) {
346: MGSetInterpolate(pc,i,dmmg[i]->R);
347: MGSetRestriction(pc,i,dmmg[i]->R);
348: }
349: }
350: return(0);
351: }
353: extern int MatSeqAIJPtAP(Mat,Mat,Mat*);
355: /*@C
356: DMMGSetSLES - Sets the linear solver object that will use the grid hierarchy
358: Collective on DMMG
360: Input Parameter:
361: + dmmg - the context
362: . func - function to compute linear system matrix on each grid level
363: - rhs - function to compute right hand side on each level (need only work on the finest grid
364: if you do not use grid sequencing
366: Level: advanced
368: Notes: For linear problems my be called more than once, reevaluates the matrices if it is called more
369: than once. Call DMMGSolve() directly several times to solve with the same matrix but different
370: right hand sides.
371:
372: .seealso DMMGCreate(), DMMGDestroy, DMMGSetDM(), DMMGSolve()
374: @*/
375: int DMMGSetSLES(DMMG *dmmg,int (*rhs)(DMMG,Vec),int (*func)(DMMG,Mat))
376: {
377: int ierr,i,nlevels = dmmg[0]->nlevels;
378: PetscTruth galerkin;
381: if (!dmmg) SETERRQ(1,"Passing null as DMMG");
382: galerkin = dmmg[0]->galerkin;
384: if (galerkin) {
385: DMGetMatrix(dmmg[nlevels-1]->dm,MATMPIAIJ,&dmmg[nlevels-1]->B);
386: (*func)(dmmg[nlevels-1],dmmg[nlevels-1]->B);
387: for (i=nlevels-2; i>-1; i--) {
388: MatSeqAIJPtAP(dmmg[i+1]->B,dmmg[i+1]->R,&dmmg[i]->B);
389: }
390: }
392: if (!dmmg[0]->sles) {
393: /* create solvers for each level */
394: for (i=0; i<nlevels; i++) {
396: if (!dmmg[i]->B && !galerkin) {
397: DMGetMatrix(dmmg[i]->dm,MATMPIAIJ,&dmmg[i]->B);
398: }
399: if (!dmmg[i]->J) {
400: dmmg[i]->J = dmmg[i]->B;
401: }
403: SLESCreate(dmmg[i]->comm,&dmmg[i]->sles);
404: DMMGSetUpLevel(dmmg,dmmg[i]->sles,i+1);
405: SLESSetFromOptions(dmmg[i]->sles);
406: dmmg[i]->solve = DMMGSolveSLES;
407: dmmg[i]->rhs = rhs;
408: }
409: }
411: /* evalute matrix on each level */
412: for (i=0; i<nlevels; i++) {
413: if (!galerkin) {
414: (*func)(dmmg[i],dmmg[i]->J);
415: }
416: dmmg[i]->matricesset = PETSC_TRUE;
417: }
419: for (i=0; i<nlevels-1; i++) {
420: SLESSetOptionsPrefix(dmmg[i]->sles,"dmmg_");
421: }
423: return(0);
424: }
426: /*@C
427: DMMGView - prints information on a DA based multi-level preconditioner
429: Collective on DMMG and PetscViewer
431: Input Parameter:
432: + dmmg - the context
433: - viewer - the viewer
435: Level: advanced
437: .seealso DMMGCreate(), DMMGDestroy
439: @*/
440: int DMMGView(DMMG *dmmg,PetscViewer viewer)
441: {
442: int ierr,i,nlevels = dmmg[0]->nlevels,flag;
443: MPI_Comm comm;
444: PetscTruth isascii;
447: if (!dmmg) SETERRQ(1,"Passing null as DMMG");
449: PetscObjectGetComm((PetscObject)viewer,&comm);
450: MPI_Comm_compare(comm,dmmg[0]->comm,&flag);
451: if (flag != MPI_CONGRUENT && flag != MPI_IDENT) {
452: SETERRQ(PETSC_ERR_ARG_NOTSAMECOMM,"Different communicators in the DMMG and the PetscViewer");
453: }
455: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
456: if (isascii) {
457: PetscViewerASCIIPrintf(viewer,"DMMG Object with %d levelsn",nlevels);
458: }
459: for (i=0; i<nlevels; i++) {
460: PetscViewerASCIIPushTab(viewer);
461: DMView(dmmg[i]->dm,viewer);
462: PetscViewerASCIIPopTab(viewer);
463: }
464: if (isascii) {
465: PetscViewerASCIIPrintf(viewer,"%s Object on finest leveln",dmmg[nlevels-1]->sles ? "SLES" : "SNES");
466: if (dmmg[nlevels-1]->galerkin) {
467: PetscViewerASCIIPrintf(viewer,"Using Galerkin R^T*A*R process to compute coarser matrices");
468: }
469: }
470: if (dmmg[nlevels-1]->sles) {
471: SLESView(dmmg[nlevels-1]->sles,viewer);
472: } else {
473: /* use of PetscObjectView() means we do not have to link with libpetscsnes if SNES is not being used */
474: PetscObjectView((PetscObject)dmmg[nlevels-1]->snes,viewer);
475: }
476: return(0);
477: }