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