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: Notes:
30: To provide a different user context for each level call DMMGSetUser() after calling
31: this routine
33: Level: advanced
35: .seealso DMMGDestroy(), DMMGSetUser(), DMMGGetUser()
37: @*/
38: PetscErrorCode DMMGCreate(MPI_Comm comm,PetscInt nlevels,void *user,DMMG **dmmg)
39: {
41: PetscInt i;
42: DMMG *p;
43: PetscTruth galerkin;
46: PetscOptionsGetInt(0,"-dmmg_nlevels",&nlevels,PETSC_IGNORE);
47: PetscOptionsHasName(0,"-dmmg_galerkin",&galerkin);
49: PetscMalloc(nlevels*sizeof(DMMG),&p);
50: for (i=0; i<nlevels; i++) {
51: PetscNew(struct _n_DMMG,&p[i]);
52: p[i]->nlevels = nlevels - i;
53: p[i]->comm = comm;
54: p[i]->user = user;
55: p[i]->galerkin = galerkin;
56: }
57: p[nlevels-1]->galerkin = PETSC_FALSE;
58: *dmmg = p;
59: return(0);
60: }
64: /*@C
65: DMMGSetUseGalerkinCoarse - Courses the DMMG to use R*A_f*R^T to form
66: the coarser matrices from finest
68: Collective on DMMG
70: Input Parameter:
71: . - the context
73: Options Database Keys:
74: . -dmmg_galerkin
76: Level: advanced
78: Notes: After you have called this you can manually set dmmg[0]->galerkin = PETSC_FALSE
79: to have the coarsest grid not compute via Galerkin but still have the intermediate
80: grids computed via Galerkin.
82: The default behavior of this should be idential to using -pc_mg_galerkin; this offers
83: more potential flexibility since you can select exactly which levels are done via
84: Galerkin and which are done via user provided function.
86: .seealso DMMGCreate(), PCMGSetGalerkin()
88: @*/
89: PetscErrorCode DMMGSetUseGalerkinCoarse(DMMG* dmmg)
90: {
91: PetscInt i,nlevels = dmmg[0]->nlevels;
94: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
96: for (i=0; i<nlevels-1; i++) {
97: dmmg[i]->galerkin = PETSC_TRUE;
98: }
99: return(0);
100: }
104: /*@C
105: DMMGDestroy - Destroys a DA based multigrid solver object.
107: Collective on DMMG
109: Input Parameter:
110: . - the context
112: Level: advanced
114: .seealso DMMGCreate()
116: @*/
117: PetscErrorCode DMMGDestroy(DMMG *dmmg)
118: {
120: PetscInt i,nlevels = dmmg[0]->nlevels;
123: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
125: for (i=1; i<nlevels; i++) {
126: if (dmmg[i]->R) {MatDestroy(dmmg[i]->R);}
127: }
128: for (i=0; i<nlevels; i++) {
129: if (dmmg[i]->dm) {DMDestroy(dmmg[i]->dm);}
130: if (dmmg[i]->x) {VecDestroy(dmmg[i]->x);}
131: if (dmmg[i]->b) {VecDestroy(dmmg[i]->b);}
132: if (dmmg[i]->r) {VecDestroy(dmmg[i]->r);}
133: if (dmmg[i]->work1) {VecDestroy(dmmg[i]->work1);}
134: if (dmmg[i]->w) {VecDestroy(dmmg[i]->w);}
135: if (dmmg[i]->work2) {VecDestroy(dmmg[i]->work2);}
136: if (dmmg[i]->lwork1) {VecDestroy(dmmg[i]->lwork1);}
137: if (dmmg[i]->B && dmmg[i]->B != dmmg[i]->J) {MatDestroy(dmmg[i]->B);}
138: if (dmmg[i]->J) {MatDestroy(dmmg[i]->J);}
139: if (dmmg[i]->Rscale) {VecDestroy(dmmg[i]->Rscale);}
140: if (dmmg[i]->fdcoloring){MatFDColoringDestroy(dmmg[i]->fdcoloring);}
141: if (dmmg[i]->ksp && !dmmg[i]->snes) {KSPDestroy(dmmg[i]->ksp);}
142: if (dmmg[i]->snes) {PetscObjectDestroy((PetscObject)dmmg[i]->snes);}
143: if (dmmg[i]->inject) {VecScatterDestroy(dmmg[i]->inject);}
144: PetscFree(dmmg[i]);
145: }
146: PetscFree(dmmg);
147: return(0);
148: }
152: /*@C
153: DMMGSetDM - Sets the coarse grid information for the grids
155: Collective on DMMG
157: Input Parameter:
158: + dmmg - the context
159: - dm - the DA or VecPack object
161: Level: advanced
163: .seealso DMMGCreate(), DMMGDestroy()
165: @*/
166: PetscErrorCode DMMGSetDM(DMMG *dmmg,DM dm)
167: {
169: PetscInt i,nlevels = dmmg[0]->nlevels;
172: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
174: /* Create DA data structure for all the levels */
175: dmmg[0]->dm = dm;
176: PetscObjectReference((PetscObject)dm);
177: for (i=1; i<nlevels; i++) {
178: DMRefine(dmmg[i-1]->dm,dmmg[i]->comm,&dmmg[i]->dm);
179: }
180: DMMGSetUp(dmmg);
181: return(0);
182: }
186: /*@C
187: DMMGSetUp - Prepares the DMMG to solve a system
189: Collective on DMMG
191: Input Parameter:
192: . dmmg - the context
194: Level: advanced
196: .seealso DMMGCreate(), DMMGDestroy(), DMMG, DMMGSetSNES(), DMMGSetKSP(), DMMGSolve()
198: @*/
199: PetscErrorCode DMMGSetUp(DMMG *dmmg)
200: {
202: PetscInt i,nlevels = dmmg[0]->nlevels;
206: /* Create work vectors and matrix for each level */
207: for (i=0; i<nlevels; i++) {
208: DMCreateGlobalVector(dmmg[i]->dm,&dmmg[i]->x);
209: VecDuplicate(dmmg[i]->x,&dmmg[i]->b);
210: VecDuplicate(dmmg[i]->x,&dmmg[i]->r);
211: }
213: /* Create interpolation/restriction between levels */
214: for (i=1; i<nlevels; i++) {
215: DMGetInterpolation(dmmg[i-1]->dm,dmmg[i]->dm,&dmmg[i]->R,PETSC_NULL);
216: }
218: return(0);
219: }
223: /*@C
224: DMMGSolve - Actually solves the (non)linear system defined with the DMMG
226: Collective on DMMG
228: Input Parameter:
229: . dmmg - the context
231: Level: advanced
233: Options Database:
234: + -dmmg_grid_sequence - use grid sequencing to get the initial solution for each level from the previous
235: - -dmmg_vecmonitor - display the solution at each iteration
237: Notes: For linear (KSP) problems may be called more than once, uses the same
238: matrices but recomputes the right hand side for each new solve. Call DMMGSetKSP()
239: to generate new matrices.
240:
241: .seealso DMMGCreate(), DMMGDestroy(), DMMG, DMMGSetSNES(), DMMGSetKSP(), DMMGSetUp()
243: @*/
244: PetscErrorCode DMMGSolve(DMMG *dmmg)
245: {
247: PetscInt i,nlevels = dmmg[0]->nlevels;
248: PetscTruth gridseq,vecmonitor,flg;
251: PetscOptionsHasName(0,"-dmmg_grid_sequence",&gridseq);
252: PetscOptionsHasName(0,"-dmmg_vecmonitor",&vecmonitor);
253: if (gridseq) {
254: if (dmmg[0]->initialguess) {
255: (*dmmg[0]->initialguess)(dmmg[0],dmmg[0]->x);
256: if (dmmg[0]->ksp && !dmmg[0]->snes) {
257: KSPSetInitialGuessNonzero(dmmg[0]->ksp,PETSC_TRUE);
258: }
259: }
260: for (i=0; i<nlevels-1; i++) {
261: (*dmmg[i]->solve)(dmmg,i);
262: if (vecmonitor) {
263: VecView(dmmg[i]->x,PETSC_VIEWER_DRAW_(dmmg[i]->comm));
264: }
265: MatInterpolate(dmmg[i+1]->R,dmmg[i]->x,dmmg[i+1]->x);
266: if (dmmg[i+1]->ksp && !dmmg[i+1]->ksp) {
267: KSPSetInitialGuessNonzero(dmmg[i+1]->ksp,PETSC_TRUE);
268: }
269: }
270: } else {
271: if (dmmg[nlevels-1]->initialguess) {
272: (*dmmg[nlevels-1]->initialguess)(dmmg[nlevels-1],dmmg[nlevels-1]->x);
273: }
274: }
275: (*DMMGGetFine(dmmg)->solve)(dmmg,nlevels-1);
276: if (vecmonitor) {
277: VecView(dmmg[nlevels-1]->x,PETSC_VIEWER_DRAW_(dmmg[nlevels-1]->comm));
278: }
280: PetscOptionsHasName(PETSC_NULL,"-dmmg_view",&flg);
281: if (flg && !PetscPreLoadingOn) {
282: DMMGView(dmmg,PETSC_VIEWER_STDOUT_(dmmg[0]->comm));
283: }
284: PetscOptionsHasName(PETSC_NULL,"-dmmg_view_binary",&flg);
285: if (flg && !PetscPreLoadingOn) {
286: DMMGView(dmmg,PETSC_VIEWER_BINARY_(dmmg[0]->comm));
287: }
288: return(0);
289: }
293: PetscErrorCode DMMGSolveKSP(DMMG *dmmg,PetscInt level)
294: {
298: if (dmmg[level]->rhs) {
299: CHKMEMQ;
300: (*dmmg[level]->rhs)(dmmg[level],dmmg[level]->b);
301: CHKMEMQ;
302: }
303: if (dmmg[level]->matricesset) {
304: KSPSetOperators(dmmg[level]->ksp,dmmg[level]->J,dmmg[level]->B,SAME_NONZERO_PATTERN);
305: dmmg[level]->matricesset = PETSC_FALSE;
306: }
307: KSPSolve(dmmg[level]->ksp,dmmg[level]->b,dmmg[level]->x);
308: return(0);
309: }
311: /*
312: Sets each of the linear solvers to use multigrid
313: */
316: PetscErrorCode DMMGSetUpLevel(DMMG *dmmg,KSP ksp,PetscInt nlevels)
317: {
319: PetscInt i;
320: PC pc;
321: PetscTruth ismg,monitor,ismf,isshell,ismffd;
322: KSP lksp; /* solver internal to the multigrid preconditioner */
323: MPI_Comm *comms,comm;
324: PetscViewer ascii;
327: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
329: PetscOptionsHasName(PETSC_NULL,"-dmmg_ksp_monitor",&monitor);
330: if (monitor) {
331: PetscObjectGetComm((PetscObject)ksp,&comm);
332: PetscViewerASCIIOpen(comm,"stdout",&ascii);
333: PetscViewerASCIISetTab(ascii,1+dmmg[0]->nlevels-nlevels);
334: KSPSetMonitor(ksp,KSPDefaultMonitor,ascii,(PetscErrorCode(*)(void*))PetscViewerDestroy);
335: }
337: /* use fgmres on outer iteration by default */
338: KSPSetType(ksp,KSPFGMRES);
339: KSPGetPC(ksp,&pc);
340: PCSetType(pc,PCMG);
341: PetscMalloc(nlevels*sizeof(MPI_Comm),&comms);
342: for (i=0; i<nlevels; i++) {
343: comms[i] = dmmg[i]->comm;
344: }
345: PCMGSetLevels(pc,nlevels,comms);
346: PetscFree(comms);
347: PCMGSetType(pc,PC_MG_FULL);
349: PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
350: if (ismg) {
351: /* set solvers for each level */
352: for (i=0; i<nlevels; i++) {
353: PCMGGetSmoother(pc,i,&lksp);
354: if (1) {
355: KSPSetOperators(lksp,dmmg[i]->J,dmmg[i]->B,DIFFERENT_NONZERO_PATTERN);
356: }
357: if (i < nlevels-1) { /* don't set for finest level, they are set in PCApply_MG()*/
358: PCMGSetX(pc,i,dmmg[i]->x);
359: PCMGSetRhs(pc,i,dmmg[i]->b);
360: }
361: if (i > 0) {
362: PCMGSetR(pc,i,dmmg[i]->r);
363: }
364: if (monitor) {
365: PetscObjectGetComm((PetscObject)lksp,&comm);
366: PetscViewerASCIIOpen(comm,"stdout",&ascii);
367: PetscViewerASCIISetTab(ascii,1+dmmg[0]->nlevels-i);
368: KSPSetMonitor(lksp,KSPDefaultMonitor,ascii,(PetscErrorCode(*)(void*))PetscViewerDestroy);
369: }
370: /* If using a matrix free multiply and did not provide an explicit matrix to build
371: the preconditioner then must use no preconditioner
372: */
373: PetscTypeCompare((PetscObject)dmmg[i]->B,MATSHELL,&isshell);
374: PetscTypeCompare((PetscObject)dmmg[i]->B,MATDAAD,&ismf);
375: PetscTypeCompare((PetscObject)dmmg[i]->B,MATMFFD,&ismffd);
376: if (isshell || ismf || ismffd) {
377: PC lpc;
378: KSPGetPC(lksp,&lpc);
379: PCSetType(lpc,PCNONE);
380: }
381: }
383: /* Set interpolation/restriction between levels */
384: for (i=1; i<nlevels; i++) {
385: PCMGSetInterpolate(pc,i,dmmg[i]->R);
386: PCMGSetRestriction(pc,i,dmmg[i]->R);
387: }
388: }
389: return(0);
390: }
394: /*@C
395: DMMGSetKSP - Sets the linear solver object that will use the grid hierarchy
397: Collective on DMMG
399: Input Parameter:
400: + dmmg - the context
401: . func - function to compute linear system matrix on each grid level
402: - rhs - function to compute right hand side on each level (need only work on the finest grid
403: if you do not use grid sequencing)
405: Level: advanced
407: Notes: For linear problems my be called more than once, reevaluates the matrices if it is called more
408: than once. Call DMMGSolve() directly several times to solve with the same matrix but different
409: right hand sides.
410:
411: .seealso DMMGCreate(), DMMGDestroy, DMMGSetDM(), DMMGSolve()
413: @*/
414: PetscErrorCode DMMGSetKSP(DMMG *dmmg,PetscErrorCode (*rhs)(DMMG,Vec),PetscErrorCode (*func)(DMMG,Mat,Mat))
415: {
417: PetscInt i,nlevels = dmmg[0]->nlevels;
418: PetscTruth galerkin;
421: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
422: galerkin = dmmg[nlevels - 2 > 0 ? nlevels - 2 : 0]->galerkin;
424: if (galerkin) {
425: DMGetMatrix(dmmg[nlevels-1]->dm,MATAIJ,&dmmg[nlevels-1]->B);
426: if (!dmmg[nlevels-1]->J) {
427: dmmg[nlevels-1]->J = dmmg[nlevels-1]->B;
428: }
429: (*func)(dmmg[nlevels-1],dmmg[nlevels-1]->J,dmmg[nlevels-1]->B);
430: for (i=nlevels-2; i>-1; i--) {
431: if (dmmg[i]->galerkin) {
432: MatPtAP(dmmg[i+1]->B,dmmg[i+1]->R,MAT_INITIAL_MATRIX,1.0,&dmmg[i]->B);
433: if (!dmmg[i]->J) {
434: dmmg[i]->J = dmmg[i]->B;
435: }
436: }
437: }
438: }
440: if (!dmmg[0]->ksp) {
441: /* create solvers for each level if they don't already exist*/
442: for (i=0; i<nlevels; i++) {
444: if (!dmmg[i]->B && !dmmg[i]->galerkin) {
445: DMGetMatrix(dmmg[i]->dm,MATAIJ,&dmmg[i]->B);
446: }
447: if (!dmmg[i]->J) {
448: dmmg[i]->J = dmmg[i]->B;
449: }
451: KSPCreate(dmmg[i]->comm,&dmmg[i]->ksp);
452: DMMGSetUpLevel(dmmg,dmmg[i]->ksp,i+1);
453: KSPSetFromOptions(dmmg[i]->ksp);
454: dmmg[i]->solve = DMMGSolveKSP;
455: dmmg[i]->rhs = rhs;
456: }
457: }
459: /* evalute matrix on each level */
460: for (i=0; i<nlevels; i++) {
461: if (!dmmg[i]->galerkin) {
462: (*func)(dmmg[i],dmmg[i]->J,dmmg[i]->B);
463: }
464: dmmg[i]->matricesset = PETSC_TRUE;
465: }
467: for (i=0; i<nlevels-1; i++) {
468: KSPSetOptionsPrefix(dmmg[i]->ksp,"dmmg_");
469: }
471: return(0);
472: }
476: /*@C
477: DMMGView - prints information on a DA based multi-level preconditioner
479: Collective on DMMG and PetscViewer
481: Input Parameter:
482: + dmmg - the context
483: - viewer - the viewer
485: Level: advanced
487: .seealso DMMGCreate(), DMMGDestroy
489: @*/
490: PetscErrorCode DMMGView(DMMG *dmmg,PetscViewer viewer)
491: {
493: PetscInt i,nlevels = dmmg[0]->nlevels;
494: PetscMPIInt flag;
495: MPI_Comm comm;
496: PetscTruth iascii,isbinary;
501: PetscObjectGetComm((PetscObject)viewer,&comm);
502: MPI_Comm_compare(comm,dmmg[0]->comm,&flag);
503: if (flag != MPI_CONGRUENT && flag != MPI_IDENT) {
504: SETERRQ(PETSC_ERR_ARG_NOTSAMECOMM,"Different communicators in the DMMG and the PetscViewer");
505: }
507: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
508: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_BINARY,&isbinary);
509: if (isbinary) {
510: for (i=0; i<nlevels; i++) {
511: MatView(dmmg[i]->J,viewer);
512: }
513: for (i=1; i<nlevels; i++) {
514: MatView(dmmg[i]->R,viewer);
515: }
516: } else {
517: if (iascii) {
518: PetscViewerASCIIPrintf(viewer,"DMMG Object with %D levels\n",nlevels);
519: }
520: for (i=0; i<nlevels; i++) {
521: PetscViewerASCIIPushTab(viewer);
522: DMView(dmmg[i]->dm,viewer);
523: PetscViewerASCIIPopTab(viewer);
524: }
525: if (iascii) {
526: PetscViewerASCIIPrintf(viewer,"%s Object on finest level\n",dmmg[nlevels-1]->ksp ? "KSP" : "SNES");
527: if (dmmg[nlevels-2 > 0 ? nlevels-2 : 0]->galerkin) {
528: PetscViewerASCIIPrintf(viewer,"Using Galerkin R^T*A*R process to compute coarser matrices\n");
529: }
530: }
531: if (dmmg[nlevels-1]->ksp) {
532: KSPView(dmmg[nlevels-1]->ksp,viewer);
533: } else {
534: /* use of PetscObjectView() means we do not have to link with libpetscsnes if SNES is not being used */
535: PetscObjectView((PetscObject)dmmg[nlevels-1]->snes,viewer);
536: }
537: }
538: return(0);
539: }
543: /*@C
544: DMMGSetNullSpace - Indicates the null space in the linear operator (this is needed by the linear solver)
546: Collective on DMMG
548: Input Parameter:
549: + dmmg - the context
550: . has_cnst - is the constant vector in the null space
551: . n - number of null vectors (excluding the possible constant vector)
552: - func - a function that fills an array of vectors with the null vectors (must be orthonormal), may be PETSC_NULL
554: Level: advanced
556: .seealso DMMGCreate(), DMMGDestroy, DMMGSetDM(), DMMGSolve(), MatNullSpaceCreate(), KSPSetNullSpace()
558: @*/
559: PetscErrorCode DMMGSetNullSpace(DMMG *dmmg,PetscTruth has_cnst,PetscInt n,PetscErrorCode (*func)(DMMG,Vec[]))
560: {
562: PetscInt i,j,nlevels = dmmg[0]->nlevels;
563: Vec *nulls = 0;
564: MatNullSpace nullsp;
565: KSP iksp;
566: PC pc,ipc;
567: PetscTruth ismg,isred;
570: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
571: if (!dmmg[0]->ksp) SETERRQ(PETSC_ERR_ORDER,"Must call AFTER DMMGSetKSP() or DMMGSetSNES()");
572: if ((n && !func) || (!n && func)) SETERRQ(PETSC_ERR_ARG_INCOMP,"Both n and func() must be set together");
573: if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Cannot have negative number of vectors in null space n = %D",n)
575: for (i=0; i<nlevels; i++) {
576: if (n) {
577: VecDuplicateVecs(dmmg[i]->b,n,&nulls);
578: (*func)(dmmg[i],nulls);
579: }
580: MatNullSpaceCreate(dmmg[i]->comm,has_cnst,n,nulls,&nullsp);
581: KSPSetNullSpace(dmmg[i]->ksp,nullsp);
582: for (j=i; j<nlevels; j++) {
583: KSPGetPC(dmmg[j]->ksp,&pc);
584: PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
585: if (ismg) {
586: PCMGGetSmoother(pc,i,&iksp);
587: KSPSetNullSpace(iksp, nullsp);
588: }
589: }
590: MatNullSpaceDestroy(nullsp);
591: if (n) {
592: PetscFree(nulls);
593: }
594: }
595: /* make all the coarse grid solvers have LU shift since they are singular */
596: for (i=0; i<nlevels; i++) {
597: KSPGetPC(dmmg[i]->ksp,&pc);
598: PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
599: if (ismg) {
600: PCMGGetSmoother(pc,0,&iksp);
601: KSPGetPC(iksp,&ipc);
602: PetscTypeCompare((PetscObject)ipc,PCREDUNDANT,&isred);
603: if (isred) {
604: PCRedundantGetPC(ipc,&ipc);
605: }
606: PCFactorSetShiftPd(ipc,PETSC_TRUE);
607: }
608: }
609: return(0);
610: }
614: /*@C
615: DMMGInitialGuessCurrent - Use with DMMGSetInitialGuess() to use the current value in the
616: solution vector (obtainable with DMMGGetx() as the initial guess)
618: Collective on DMMG
620: Input Parameter:
621: + dmmg - the context
622: - vec - dummy argument
624: Level: intermediate
626: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGSetInitialGuess()
628: @*/
629: PetscErrorCode DMMGInitialGuessCurrent(DMMG dmmg,Vec vec)
630: {
632: return(0);
633: }
637: /*@C
638: DMMGSetInitialGuess - Sets the function that computes an initial guess.
640: Collective on DMMG
642: Input Parameter:
643: + dmmg - the context
644: - guess - the function
646: Notes: For nonlinear problems, if this is not set, then the current value in the
647: solution vector (obtained with DMMGGetX()) is used. Thus is if you doing 'time
648: stepping' it will use your current solution as the guess for the next timestep.
649: If grid sequencing is used (via -dmmg_grid_sequence) then the "guess" function
650: is used only on the coarsest grid.
651: For linear problems, if this is not set, then 0 is used as an initial guess.
652: If you would like the linear solver to also (like the nonlinear solver) use
653: the current solution vector as the initial guess then use DMMGInitialGuessCurrent()
654: as the function you pass in
656: Level: intermediate
659: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGInitialGuessCurrent()
661: @*/
662: PetscErrorCode DMMGSetInitialGuess(DMMG *dmmg,PetscErrorCode (*guess)(DMMG,Vec))
663: {
664: PetscInt i,nlevels = dmmg[0]->nlevels;
667: for (i=0; i<nlevels; i++) {
668: dmmg[i]->initialguess = guess;
669: }
670: return(0);
671: }