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: }