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