Actual source code: damg.c

  1: #define PETSCSNES_DLL
  2: 
 3:  #include petscda.h
 4:  #include petscksp.h
 5:  #include petscmg.h
 6:  #include petscdmmg.h
 7:  #include private/pcimpl.h

  9: /*
 10:    Code for almost fully managing multigrid/multi-level linear solvers for DA grids
 11: */

 15: /*@C
 16:     DMMGCreate - Creates a DA based multigrid solver object. This allows one to 
 17:       easily implement MG methods on regular grids.

 19:     Collective on MPI_Comm

 21:     Input Parameter:
 22: +   comm - the processors that will share the grids and solution process
 23: .   nlevels - number of multigrid levels 
 24: -   user - an optional user context

 26:     Output Parameters:
 27: .    - the context

 29:     Options Database:
 30: +     -dmmg_nlevels <levels> - number of levels to use
 31: .     -dmmg_galerkin - use Galerkin approach to compute coarser matrices
 32: -     -dmmg_mat_type <type> - matrix type that DMMG should create, defaults to MATAIJ

 34:     Notes:
 35:       To provide a different user context for each level call DMMGSetUser() after calling
 36:       this routine

 38:     Level: advanced

 40: .seealso DMMGDestroy(), DMMGSetUser(), DMMGGetUser(), DMMGSetMatType(), DMMGSetUseGalerkin(), DMMGSetNullSpace(), DMMGSetInitialGuess(),
 41:          DMMGSetISColoringType()

 43: @*/
 44: PetscErrorCode  DMMGCreate(MPI_Comm comm,PetscInt nlevels,void *user,DMMG **dmmg)
 45: {
 47:   PetscInt       i;
 48:   DMMG           *p;
 49:   PetscTruth     galerkin,ftype;
 50:   char           mtype[256];

 53:   if (nlevels < 0) {
 54:     nlevels = -nlevels;
 55:   } else {
 56:     PetscOptionsGetInt(0,"-dmmg_nlevels",&nlevels,PETSC_IGNORE);
 57:   }
 58:   PetscOptionsHasName(0,"-dmmg_galerkin",&galerkin);

 60:   PetscMalloc(nlevels*sizeof(DMMG),&p);
 61:   for (i=0; i<nlevels; i++) {
 62:     PetscNew(struct _n_DMMG,&p[i]);
 63:     p[i]->nlevels  = nlevels - i;
 64:     p[i]->comm     = comm;
 65:     p[i]->user     = user;
 66:     p[i]->galerkin = galerkin;
 67:     p[i]->updatejacobianperiod = 1;
 68:     p[i]->updatejacobian       = PETSC_TRUE;
 69:     p[i]->isctype  = IS_COLORING_GHOSTED;   /* default to faster version, requires DMMGSetSNESLocal() */
 70:     PetscStrallocpy(MATAIJ,&p[i]->mtype);
 71:   }
 72:   p[nlevels-1]->galerkin = PETSC_FALSE;
 73:   *dmmg = p;

 75:   PetscOptionsGetString(PETSC_NULL,"-dmmg_mat_type",mtype,256,&ftype);
 76:   if (ftype) {
 77:     DMMGSetMatType(*dmmg,mtype);
 78:   }
 79:   return(0);
 80: }

 84: /*@C
 85:     DMMGSetMatType - Sets the type of matrices that DMMG will create for its solvers.

 87:     Collective on MPI_Comm 

 89:     Input Parameters:
 90: +    dmmg - the DMMG object created with DMMGCreate()
 91: -    mtype - the matrix type, defaults to MATAIJ

 93:     Level: intermediate

 95: .seealso DMMGDestroy(), DMMGSetUser(), DMMGGetUser(), DMMGCreate(), DMMGSetNullSpace()

 97: @*/
 98: PetscErrorCode  DMMGSetMatType(DMMG *dmmg,const MatType mtype)
 99: {
100:   PetscInt       i;

104:   for (i=0; i<dmmg[0]->nlevels; i++) {
105:     PetscStrallocpy(mtype,&dmmg[i]->mtype);
106:   }
107:   return(0);
108: }

112: /*@C
113:     DMMGSetOptionsPrefix - Sets the prefix used for the solvers inside a DMMG

115:     Collective on MPI_Comm 

117:     Input Parameters:
118: +    dmmg - the DMMG object created with DMMGCreate()
119: -    prefix - the prefix string

121:     Level: intermediate

123: .seealso DMMGDestroy(), DMMGSetUser(), DMMGGetUser(), DMMGCreate(), DMMGSetNullSpace()

125: @*/
126: PetscErrorCode  DMMGSetOptionsPrefix(DMMG *dmmg,const char prefix[])
127: {
128:   PetscInt       i;
130: 
132:   for (i=0; i<dmmg[0]->nlevels; i++) {
133:     PetscStrallocpy(prefix,&dmmg[i]->prefix);
134:   }
135:   return(0);
136: }

140: /*@C
141:     DMMGSetUseGalerkinCoarse - Courses the DMMG to use R*A_f*R^T to form
142:        the coarser matrices from finest 

144:     Collective on DMMG

146:     Input Parameter:
147: .    dmmg - the context

149:     Options Database Keys:
150: .    -dmmg_galerkin 

152:     Level: advanced

154:     Notes: After you have called this you can manually set dmmg[0]->galerkin = PETSC_FALSE
155:        to have the coarsest grid not compute via Galerkin but still have the intermediate
156:        grids computed via Galerkin.

158:        The default behavior of this should be idential to using -pc_mg_galerkin; this offers
159:        more potential flexibility since you can select exactly which levels are done via
160:        Galerkin and which are done via user provided function.

162: .seealso DMMGCreate(), PCMGSetUseGalerkin(), DMMGSetMatType(), DMMGSetNullSpace()

164: @*/
165: PetscErrorCode  DMMGSetUseGalerkinCoarse(DMMG* dmmg)
166: {
167:   PetscInt  i,nlevels = dmmg[0]->nlevels;

170:   if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");

172:   for (i=0; i<nlevels-1; i++) {
173:     dmmg[i]->galerkin = PETSC_TRUE;
174:   }
175:   return(0);
176: }

180: /*@C
181:     DMMGDestroy - Destroys a DA based multigrid solver object. 

183:     Collective on DMMG

185:     Input Parameter:
186: .    - the context

188:     Level: advanced

190: .seealso DMMGCreate()

192: @*/
193: PetscErrorCode  DMMGDestroy(DMMG *dmmg)
194: {
196:   PetscInt       i,nlevels = dmmg[0]->nlevels;

199:   if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");

201:   for (i=1; i<nlevels; i++) {
202:     if (dmmg[i]->R) {MatDestroy(dmmg[i]->R);}
203:   }
204:   for (i=0; i<nlevels; i++) {
205:     PetscStrfree(dmmg[i]->prefix);
206:     PetscStrfree(dmmg[i]->mtype);
207:     if (dmmg[i]->dm)      {DMDestroy(dmmg[i]->dm);}
208:     if (dmmg[i]->x)       {VecDestroy(dmmg[i]->x);}
209:     if (dmmg[i]->b)       {VecDestroy(dmmg[i]->b);}
210:     if (dmmg[i]->r)       {VecDestroy(dmmg[i]->r);}
211:     if (dmmg[i]->work1)   {VecDestroy(dmmg[i]->work1);}
212:     if (dmmg[i]->w)       {VecDestroy(dmmg[i]->w);}
213:     if (dmmg[i]->work2)   {VecDestroy(dmmg[i]->work2);}
214:     if (dmmg[i]->lwork1)  {VecDestroy(dmmg[i]->lwork1);}
215:     if (dmmg[i]->B)         {MatDestroy(dmmg[i]->B);}
216:     if (dmmg[i]->J)         {MatDestroy(dmmg[i]->J);}
217:     if (dmmg[i]->Rscale)    {VecDestroy(dmmg[i]->Rscale);}
218:     if (dmmg[i]->fdcoloring){MatFDColoringDestroy(dmmg[i]->fdcoloring);}
219:     if (dmmg[i]->ksp && !dmmg[i]->snes) {KSPDestroy(dmmg[i]->ksp);}
220:     if (dmmg[i]->snes)      {PetscObjectDestroy((PetscObject)dmmg[i]->snes);}
221:     if (dmmg[i]->inject)    {VecScatterDestroy(dmmg[i]->inject);}
222:     PetscFree(dmmg[i]);
223:   }
224:   PetscFree(dmmg);
225:   return(0);
226: }

230: /*@C
231:     DMMGSetDM - Sets the coarse grid information for the grids

233:     Collective on DMMG

235:     Input Parameter:
236: +   dmmg - the context
237: -   dm - the DA or DMComposite object

239:     Options Database Keys:
240: +   -dmmg_refine: Use the input problem as the coarse level and refine. Otherwise, use it as the fine level and coarsen.
241: -   -dmmg_hierarchy: Construct all grids at once

243:     Level: advanced

245: .seealso DMMGCreate(), DMMGDestroy(), DMMGSetUseGalerkin(), DMMGSetMatType()

247: @*/
248: PetscErrorCode  DMMGSetDM(DMMG *dmmg, DM dm)
249: {
250:   PetscInt       nlevels     = dmmg[0]->nlevels;
251:   PetscTruth     doRefine    = PETSC_TRUE;
252:   PetscTruth     doHierarchy = PETSC_FALSE;
253:   PetscInt       i;

257:   if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");

259:   /* Create DM data structure for all the levels */
260:   PetscOptionsGetTruth(PETSC_NULL, "-dmmg_refine", &doRefine, PETSC_IGNORE);
261:   PetscOptionsHasName(PETSC_NULL, "-dmmg_hierarchy", &doHierarchy);
262:   PetscObjectReference((PetscObject) dm);
263:   if (doRefine) {
264:     dmmg[0]->dm = dm;
265:     if (doHierarchy) {
266: /*       DM *hierarchy; */

268: /*       DMRefineHierarchy(dm, nlevels-1, &hierarchy); */
269: /*       for(i = 1; i < nlevels; ++i) { */
270: /*         dmmg[i]->dm = hierarchy[i-1]; */
271: /*       } */
272:       SETERRQ(PETSC_ERR_SUP, "Refinement hierarchy not yet implemented");
273:     } else {
274:       for(i = 1; i < nlevels; ++i) {
275:         DMRefine(dmmg[i-1]->dm, dmmg[i]->comm, &dmmg[i]->dm);
276:       }
277:     }
278:   } else {
279:     dmmg[nlevels-1]->dm = dm;
280:     if (doHierarchy) {
281:       DM *hierarchy;

283:       DMCoarsenHierarchy(dm, nlevels-1, &hierarchy);
284:       for(i = 0; i < nlevels-1; ++i) {
285:         dmmg[nlevels-2-i]->dm = hierarchy[i];
286:       }
287:     } else {
288: /*       for(i = nlevels-2; i >= 0; --i) { */
289: /*         DMCoarsen(dmmg[i+1]->dm, dmmg[i]->comm, &dmmg[i]->dm); */
290: /*       } */
291:       SETERRQ(PETSC_ERR_SUP, "Sequential coarsening not yet implemented");
292:     }
293:   }
294:   /* Cleanup old structures (should use some private Destroy() instead) */
295:   for(i = 0; i < nlevels; ++i) {
296:     if (dmmg[i]->B) {MatDestroy(dmmg[i]->B); dmmg[i]->B = PETSC_NULL;}
297:     if (dmmg[i]->J) {MatDestroy(dmmg[i]->J); dmmg[i]->J = PETSC_NULL;}
298:   }

300:   /* Create work vectors and matrix for each level */
301:   for (i=0; i<nlevels; i++) {
302:     DMCreateGlobalVector(dmmg[i]->dm,&dmmg[i]->x);
303:     VecDuplicate(dmmg[i]->x,&dmmg[i]->b);
304:     VecDuplicate(dmmg[i]->x,&dmmg[i]->r);
305:   }

307:   /* Create interpolation/restriction between levels */
308:   for (i=1; i<nlevels; i++) {
309:     DMGetInterpolation(dmmg[i-1]->dm,dmmg[i]->dm,&dmmg[i]->R,PETSC_NULL);
310:   }
311:   return(0);
312: }


317: /*@C
318:     DMMGSolve - Actually solves the (non)linear system defined with the DMMG

320:     Collective on DMMG

322:     Input Parameter:
323: .   dmmg - the context

325:     Level: advanced

327:     Options Database:
328: +   -dmmg_grid_sequence - use grid sequencing to get the initial solution for each level from the previous
329: -   -dmmg_monitor_solution - display the solution at each iteration

331:      Notes: For linear (KSP) problems may be called more than once, uses the same 
332:     matrices but recomputes the right hand side for each new solve. Call DMMGSetKSP()
333:     to generate new matrices.
334:  
335: .seealso DMMGCreate(), DMMGDestroy(), DMMG, DMMGSetSNES(), DMMGSetKSP(), DMMGSetUp(), DMMGSetMatType()

337: @*/
338: PetscErrorCode  DMMGSolve(DMMG *dmmg)
339: {
341:   PetscInt       i,nlevels = dmmg[0]->nlevels;
342:   PetscTruth     gridseq,vecmonitor,flg;

345:   PetscOptionsHasName(0,"-dmmg_grid_sequence",&gridseq);
346:   PetscOptionsHasName(0,"-dmmg_monitor_solution",&vecmonitor);
347:   if (gridseq) {
348:     if (dmmg[0]->initialguess) {
349:       (*dmmg[0]->initialguess)(dmmg[0],dmmg[0]->x);
350:       if (dmmg[0]->ksp && !dmmg[0]->snes) {
351:         KSPSetInitialGuessNonzero(dmmg[0]->ksp,PETSC_TRUE);
352:       }
353:     }
354:     for (i=0; i<nlevels-1; i++) {
355:       (*dmmg[i]->solve)(dmmg,i);
356:       if (vecmonitor) {
357:         VecView(dmmg[i]->x,PETSC_VIEWER_DRAW_(dmmg[i]->comm));
358:       }
359:       MatInterpolate(dmmg[i+1]->R,dmmg[i]->x,dmmg[i+1]->x);
360:       if (dmmg[i+1]->ksp && !dmmg[i+1]->snes) {
361:         KSPSetInitialGuessNonzero(dmmg[i+1]->ksp,PETSC_TRUE);
362:      }
363:     }
364:   } else {
365:     if (dmmg[nlevels-1]->initialguess) {
366:       (*dmmg[nlevels-1]->initialguess)(dmmg[nlevels-1],dmmg[nlevels-1]->x);
367:     }
368:   }

370:   /*VecView(dmmg[nlevels-1]->x,PETSC_VIEWER_DRAW_WORLD);*/

372:   (*DMMGGetFine(dmmg)->solve)(dmmg,nlevels-1);
373:   if (vecmonitor) {
374:      VecView(dmmg[nlevels-1]->x,PETSC_VIEWER_DRAW_(dmmg[nlevels-1]->comm));
375:   }

377:   PetscOptionsHasName(PETSC_NULL,"-dmmg_view",&flg);
378:   if (flg && !PetscPreLoadingOn) {
379:     PetscViewer viewer;
380:     PetscViewerASCIIGetStdout(dmmg[0]->comm,&viewer);
381:     DMMGView(dmmg,viewer);
382:   }
383:   PetscOptionsHasName(PETSC_NULL,"-dmmg_view_binary",&flg);
384:   if (flg && !PetscPreLoadingOn) {
385:     DMMGView(dmmg,PETSC_VIEWER_BINARY_(dmmg[0]->comm));
386:   }
387:   return(0);
388: }

392: PetscErrorCode  DMMGSolveKSP(DMMG *dmmg,PetscInt level)
393: {

397:   if (dmmg[level]->rhs) {
398:     CHKMEMQ;
399:     (*dmmg[level]->rhs)(dmmg[level],dmmg[level]->b);
400:     CHKMEMQ;
401:   }
402:   KSPSolve(dmmg[level]->ksp,dmmg[level]->b,dmmg[level]->x);
403:   return(0);
404: }

406: /*
407:     For each level (of grid sequencing) this sets the interpolation/restriction and 
408:     work vectors needed by the multigrid preconditioner within the KSP 
409:     (for nonlinear problems the KSP inside the SNES) of that level.

411:     Also sets the KSP monitoring on all the levels if requested by user.

413: */
416: PetscErrorCode  DMMGSetUpLevel(DMMG *dmmg,KSP ksp,PetscInt nlevels)
417: {
418:   PetscErrorCode          ierr;
419:   PetscInt                i;
420:   PC                      pc;
421:   PetscTruth              ismg,ismf,isshell,ismffd;
422:   KSP                     lksp; /* solver internal to the multigrid preconditioner */
423:   MPI_Comm                *comms;

426:   if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");

428:   /* use fgmres on outer iteration by default */
429:   KSPSetType(ksp,KSPFGMRES);
430:   KSPGetPC(ksp,&pc);
431:   PCSetType(pc,PCMG);
432:   PetscMalloc(nlevels*sizeof(MPI_Comm),&comms);
433:   for (i=0; i<nlevels; i++) {
434:     comms[i] = dmmg[i]->comm;
435:   }
436:   PCMGSetLevels(pc,nlevels,comms);
437:   PetscFree(comms);
438:    PCMGSetType(pc,PC_MG_FULL);

440:   PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
441:   if (ismg) {
442:     /* set solvers for each level */
443:     for (i=0; i<nlevels; i++) {
444:       if (i < nlevels-1) { /* don't set for finest level, they are set in PCApply_MG()*/
445:         PCMGSetX(pc,i,dmmg[i]->x);
446:         PCMGSetRhs(pc,i,dmmg[i]->b);
447:       }
448:       if (i > 0) {
449:         PCMGSetR(pc,i,dmmg[i]->r);
450:       }
451:       /* If using a matrix free multiply and did not provide an explicit matrix to build
452:          the preconditioner then must use no preconditioner 
453:       */
454:       PetscTypeCompare((PetscObject)dmmg[i]->B,MATSHELL,&isshell);
455:       PetscTypeCompare((PetscObject)dmmg[i]->B,MATDAAD,&ismf);
456:       PetscTypeCompare((PetscObject)dmmg[i]->B,MATMFFD,&ismffd);
457:       if (isshell || ismf || ismffd) {
458:         PC  lpc;
459:         PCMGGetSmoother(pc,i,&lksp);
460:         KSPGetPC(lksp,&lpc);
461:         PCSetType(lpc,PCNONE);
462:       }
463:     }

465:     /* Set interpolation/restriction between levels */
466:     for (i=1; i<nlevels; i++) {
467:       PCMGSetInterpolation(pc,i,dmmg[i]->R);
468:       PCMGSetRestriction(pc,i,dmmg[i]->R);
469:     }
470:   }
471:   return(0);
472: }

476: /*@C
477:     DMMGSetKSP - Sets the linear solver object that will use the grid hierarchy

479:     Collective on DMMG

481:     Input Parameter:
482: +   dmmg - the context
483: .   func - function to compute linear system matrix on each grid level
484: -   rhs - function to compute right hand side on each level (need only work on the finest grid
485:           if you do not use grid sequencing)

487:     Level: advanced

489:     Notes: For linear problems my be called more than once, reevaluates the matrices if it is called more
490:        than once. Call DMMGSolve() directly several times to solve with the same matrix but different 
491:        right hand sides.
492:    
493: .seealso DMMGCreate(), DMMGDestroy, DMMGSetDM(), DMMGSolve(), DMMGSetMatType()

495: @*/
496: PetscErrorCode  DMMGSetKSP(DMMG *dmmg,PetscErrorCode (*rhs)(DMMG,Vec),PetscErrorCode (*func)(DMMG,Mat,Mat))
497: {
499:   PetscInt       i,nlevels = dmmg[0]->nlevels,level;
500:   PetscTruth     galerkin,ismg;
501:   PC             pc;
502:   KSP            lksp;

505:   if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
506:   galerkin = dmmg[nlevels - 2 > 0 ? nlevels - 2 : 0]->galerkin;

508:   if (galerkin) {
509:     DMGetMatrix(dmmg[nlevels-1]->dm,dmmg[nlevels-1]->mtype,&dmmg[nlevels-1]->B);
510:     if (!dmmg[nlevels-1]->J) {
511:       dmmg[nlevels-1]->J = dmmg[nlevels-1]->B;
512:       PetscObjectReference((PetscObject) dmmg[nlevels-1]->J);
513:     }
514:     if (func) {
515:       (*func)(dmmg[nlevels-1],dmmg[nlevels-1]->J,dmmg[nlevels-1]->B);
516:     }
517:     for (i=nlevels-2; i>-1; i--) {
518:       if (dmmg[i]->galerkin) {
519:         MatPtAP(dmmg[i+1]->B,dmmg[i+1]->R,MAT_INITIAL_MATRIX,1.0,&dmmg[i]->B);
520:         if (!dmmg[i]->J) {
521:           dmmg[i]->J = dmmg[i]->B;
522:           PetscObjectReference((PetscObject) dmmg[i]->J);
523:         }
524:       }
525:     }
526:   }

528:   if (!dmmg[0]->ksp) {
529:     /* create solvers for each level if they don't already exist*/
530:     for (i=0; i<nlevels; i++) {

532:       if (!dmmg[i]->B && !dmmg[i]->galerkin) {
533:         DMGetMatrix(dmmg[i]->dm,dmmg[nlevels-1]->mtype,&dmmg[i]->B);
534:       }
535:       if (!dmmg[i]->J) {
536:         dmmg[i]->J = dmmg[i]->B;
537:         PetscObjectReference((PetscObject) dmmg[i]->J);
538:       }

540:       KSPCreate(dmmg[i]->comm,&dmmg[i]->ksp);
541:       PetscObjectIncrementTabLevel((PetscObject)dmmg[i]->ksp,PETSC_NULL,nlevels-i);
542:       KSPSetOptionsPrefix(dmmg[i]->ksp,dmmg[i]->prefix);
543:       DMMGSetUpLevel(dmmg,dmmg[i]->ksp,i+1);
544:       KSPSetFromOptions(dmmg[i]->ksp);
545:       dmmg[i]->solve = DMMGSolveKSP;
546:       dmmg[i]->rhs   = rhs;
547:     }
548:   }

550:   /* evalute matrix on each level */
551:   for (i=0; i<nlevels; i++) {
552:     if (!dmmg[i]->galerkin) {
553:       if (func) {
554:         (*func)(dmmg[i],dmmg[i]->J,dmmg[i]->B);
555:       }
556:     }
557:   }

559:   for (i=0; i<nlevels-1; i++) {
560:     KSPSetOptionsPrefix(dmmg[i]->ksp,"dmmg_");
561:   }

563:   for (level=0; level<nlevels; level++) {
564:     KSPSetOperators(dmmg[level]->ksp,dmmg[level]->J,dmmg[level]->B,SAME_NONZERO_PATTERN);
565:     KSPGetPC(dmmg[level]->ksp,&pc);
566:     PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
567:     if (ismg) {
568:       for (i=0; i<=level; i++) {
569:         PCMGGetSmoother(pc,i,&lksp);
570:         KSPSetOperators(lksp,dmmg[i]->J,dmmg[i]->B,SAME_NONZERO_PATTERN);
571:       }
572:     }
573:   }

575:   return(0);
576: }

580: /*@C
581:     DMMGView - prints information on a DA based multi-level preconditioner

583:     Collective on DMMG and PetscViewer

585:     Input Parameter:
586: +   dmmg - the context
587: -   viewer - the viewer

589:     Level: advanced

591: .seealso DMMGCreate(), DMMGDestroy(), DMMGSetMatType(), DMMGSetUseGalerkin()

593: @*/
594: PetscErrorCode  DMMGView(DMMG *dmmg,PetscViewer viewer)
595: {
597:   PetscInt       i,nlevels = dmmg[0]->nlevels;
598:   PetscMPIInt    flag;
599:   MPI_Comm       comm;
600:   PetscTruth     iascii,isbinary;

605:   PetscObjectGetComm((PetscObject)viewer,&comm);
606:   MPI_Comm_compare(comm,dmmg[0]->comm,&flag);
607:   if (flag != MPI_CONGRUENT && flag != MPI_IDENT) {
608:     SETERRQ(PETSC_ERR_ARG_NOTSAMECOMM,"Different communicators in the DMMG and the PetscViewer");
609:   }

611:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
612:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_BINARY,&isbinary);
613:   if (isbinary) {
614:     for (i=0; i<nlevels; i++) {
615:       MatView(dmmg[i]->J,viewer);
616:     }
617:     for (i=1; i<nlevels; i++) {
618:       MatView(dmmg[i]->R,viewer);
619:     }
620:   } else {
621:     if (iascii) {
622:       PetscViewerASCIIPrintf(viewer,"DMMG Object with %D levels\n",nlevels);
623:     }
624:     for (i=0; i<nlevels; i++) {
625:       PetscViewerASCIIPushTab(viewer);
626:       DMView(dmmg[i]->dm,viewer);
627:       PetscViewerASCIIPopTab(viewer);
628:     }
629:     if (iascii) {
630:       PetscViewerASCIIPrintf(viewer,"%s Object on finest level\n",dmmg[nlevels-1]->ksp ? "KSP" : "SNES");
631:       if (dmmg[nlevels-2 > 0 ? nlevels-2 : 0]->galerkin) {
632:         PetscViewerASCIIPrintf(viewer,"Using Galerkin R^T*A*R process to compute coarser matrices\n");
633:       }
634:       PetscViewerASCIIPrintf(viewer,"Using matrix type %s\n",dmmg[nlevels-1]->mtype);
635:     }
636:     if (dmmg[nlevels-1]->ksp) {
637:       KSPView(dmmg[nlevels-1]->ksp,viewer);
638:     } else {
639:       /* use of PetscObjectView() means we do not have to link with libpetscsnes if SNES is not being used */
640:       PetscObjectView((PetscObject)dmmg[nlevels-1]->snes,viewer);
641:     }
642:   }
643:   return(0);
644: }

648: /*@C
649:     DMMGSetNullSpace - Indicates the null space in the linear operator (this is needed by the linear solver)

651:     Collective on DMMG

653:     Input Parameter:
654: +   dmmg - the context
655: .   has_cnst - is the constant vector in the null space
656: .   n - number of null vectors (excluding the possible constant vector)
657: -   func - a function that fills an array of vectors with the null vectors (must be orthonormal), may be PETSC_NULL

659:     Level: advanced

661: .seealso DMMGCreate(), DMMGDestroy, DMMGSetDM(), DMMGSolve(), MatNullSpaceCreate(), KSPSetNullSpace(), DMMGSetUseGalerkin(), DMMGSetMatType()

663: @*/
664: PetscErrorCode  DMMGSetNullSpace(DMMG *dmmg,PetscTruth has_cnst,PetscInt n,PetscErrorCode (*func)(DMMG,Vec[]))
665: {
667:   PetscInt       i,j,nlevels = dmmg[0]->nlevels;
668:   Vec            *nulls = 0;
669:   MatNullSpace   nullsp;
670:   KSP            iksp;
671:   PC             pc,ipc;
672:   PetscTruth     ismg,isred;

675:   if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
676:   if (!dmmg[0]->ksp) SETERRQ(PETSC_ERR_ORDER,"Must call AFTER DMMGSetKSP() or DMMGSetSNES()");
677:   if ((n && !func) || (!n && func)) SETERRQ(PETSC_ERR_ARG_INCOMP,"Both n and func() must be set together");
678:   if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Cannot have negative number of vectors in null space n = %D",n)

680:   for (i=0; i<nlevels; i++) {
681:     if (n) {
682:       VecDuplicateVecs(dmmg[i]->b,n,&nulls);
683:       (*func)(dmmg[i],nulls);
684:     }
685:     MatNullSpaceCreate(dmmg[i]->comm,has_cnst,n,nulls,&nullsp);
686:     KSPSetNullSpace(dmmg[i]->ksp,nullsp);
687:     for (j=i; j<nlevels; j++) {
688:       KSPGetPC(dmmg[j]->ksp,&pc);
689:       PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
690:       if (ismg) {
691:         PCMGGetSmoother(pc,i,&iksp);
692:         KSPSetNullSpace(iksp, nullsp);
693:       }
694:     }
695:     MatNullSpaceDestroy(nullsp);
696:     if (n) {
697:       PetscFree(nulls);
698:     }
699:   }
700:   /* make all the coarse grid solvers have LU shift since they are singular */
701:   for (i=0; i<nlevels; i++) {
702:     KSPGetPC(dmmg[i]->ksp,&pc);
703:     PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
704:     if (ismg) {
705:       PCMGGetSmoother(pc,0,&iksp);
706:       KSPGetPC(iksp,&ipc);
707:       PetscTypeCompare((PetscObject)ipc,PCREDUNDANT,&isred);
708:       if (isred) {
709:         PCRedundantGetPC(ipc,&ipc);
710:       }
711:       PCFactorSetShiftPd(ipc,PETSC_TRUE);
712:     }
713:   }
714:   return(0);
715: }

719: /*@C
720:     DMMGInitialGuessCurrent - Use with DMMGSetInitialGuess() to use the current value in the 
721:        solution vector (obtainable with DMMGGetx()) as the initial guess. Otherwise for linear
722:        problems zero is used for the initial guess (unless grid sequencing is used). For nonlinear 
723:        problems this is not needed; it always uses the previous solution as the initial guess.

725:     Collective on DMMG

727:     Input Parameter:
728: +   dmmg - the context
729: -   vec - dummy argument

731:     Level: intermediate

733: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGSetInitialGuess()

735: @*/
736: PetscErrorCode  DMMGInitialGuessCurrent(DMMG dmmg,Vec vec)
737: {
739:   return(0);
740: }

744: /*@C
745:     DMMGSetInitialGuess - Sets the function that computes an initial guess.

747:     Collective on DMMG

749:     Input Parameter:
750: +   dmmg - the context
751: -   guess - the function

753:     Notes: For nonlinear problems, if this is not set, then the current value in the 
754:              solution vector (obtained with DMMGGetX()) is used. Thus is if you doing 'time
755:              stepping' it will use your current solution as the guess for the next timestep.
756:            If grid sequencing is used (via -dmmg_grid_sequence) then the "guess" function
757:              is used only on the coarsest grid.
758:            For linear problems, if this is not set, then 0 is used as an initial guess.
759:              If you would like the linear solver to also (like the nonlinear solver) use
760:              the current solution vector as the initial guess then use DMMGInitialGuessCurrent()
761:              as the function you pass in

763:     Level: intermediate


766: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGInitialGuessCurrent(), DMMGSetGalekin(), DMMGSetMatType(), DMMGSetNullSpace()

768: @*/
769: PetscErrorCode  DMMGSetInitialGuess(DMMG *dmmg,PetscErrorCode (*guess)(DMMG,Vec))
770: {
771:   PetscInt       i,nlevels = dmmg[0]->nlevels;

775:   for (i=0; i<nlevels; i++) {
776:     if (dmmg[i]->ksp && !dmmg[i]->snes) {
777:       KSPSetInitialGuessNonzero(dmmg[i]->ksp,PETSC_TRUE);
778:     }
779:     dmmg[i]->initialguess = guess;
780:   }
781:   return(0);
782: }