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 src/ksp/pc/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 PETSCSNES_DLLEXPORT 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 _p_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: *dmmg = p;
58: return(0);
59: }
63: /*@C
64: DMMGSetUseGalerkinCoarse - Courses the DMMG to use R*A_f*R^T to form
65: the coarser matrices from finest
67: Collective on DMMG
69: Input Parameter:
70: . - the context
72: Options Database Keys:
73: . -dmmg_galerkin
75: Level: advanced
77: .seealso DMMGCreate()
79: @*/
80: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetUseGalerkinCoarse(DMMG* dmmg)
81: {
82: PetscInt i,nlevels = dmmg[0]->nlevels;
85: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
87: for (i=0; i<nlevels; i++) {
88: dmmg[i]->galerkin = PETSC_TRUE;
89: }
90: return(0);
91: }
95: /*@C
96: DMMGDestroy - Destroys a DA based multigrid solver object.
98: Collective on DMMG
100: Input Parameter:
101: . - the context
103: Level: advanced
105: .seealso DMMGCreate()
107: @*/
108: PetscErrorCode PETSCSNES_DLLEXPORT DMMGDestroy(DMMG *dmmg)
109: {
111: PetscInt i,nlevels = dmmg[0]->nlevels;
114: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
116: for (i=1; i<nlevels; i++) {
117: if (dmmg[i]->R) {MatDestroy(dmmg[i]->R);}
118: }
119: for (i=0; i<nlevels; i++) {
120: if (dmmg[i]->dm) {DMDestroy(dmmg[i]->dm);}
121: if (dmmg[i]->x) {VecDestroy(dmmg[i]->x);}
122: if (dmmg[i]->b) {VecDestroy(dmmg[i]->b);}
123: if (dmmg[i]->r) {VecDestroy(dmmg[i]->r);}
124: if (dmmg[i]->work1) {VecDestroy(dmmg[i]->work1);}
125: if (dmmg[i]->w) {VecDestroy(dmmg[i]->w);}
126: if (dmmg[i]->work2) {VecDestroy(dmmg[i]->work2);}
127: if (dmmg[i]->lwork1) {VecDestroy(dmmg[i]->lwork1);}
128: if (dmmg[i]->B && dmmg[i]->B != dmmg[i]->J) {MatDestroy(dmmg[i]->B);}
129: if (dmmg[i]->J) {MatDestroy(dmmg[i]->J);}
130: if (dmmg[i]->Rscale) {VecDestroy(dmmg[i]->Rscale);}
131: if (dmmg[i]->fdcoloring){MatFDColoringDestroy(dmmg[i]->fdcoloring);}
132: if (dmmg[i]->ksp && !dmmg[i]->snes) {KSPDestroy(dmmg[i]->ksp);}
133: if (dmmg[i]->snes) {PetscObjectDestroy((PetscObject)dmmg[i]->snes);}
134: if (dmmg[i]->inject) {VecScatterDestroy(dmmg[i]->inject);}
135: PetscFree(dmmg[i]);
136: }
137: PetscFree(dmmg);
138: return(0);
139: }
143: /*@C
144: DMMGSetDM - Sets the coarse grid information for the grids
146: Collective on DMMG
148: Input Parameter:
149: + dmmg - the context
150: - dm - the DA or VecPack object
152: Level: advanced
154: .seealso DMMGCreate(), DMMGDestroy()
156: @*/
157: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetDM(DMMG *dmmg,DM dm)
158: {
160: PetscInt i,nlevels = dmmg[0]->nlevels;
163: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
165: /* Create DA data structure for all the levels */
166: dmmg[0]->dm = dm;
167: PetscObjectReference((PetscObject)dm);
168: for (i=1; i<nlevels; i++) {
169: DMRefine(dmmg[i-1]->dm,dmmg[i]->comm,&dmmg[i]->dm);
170: }
171: DMMGSetUp(dmmg);
172: return(0);
173: }
177: /*@C
178: DMMGSetUp - Prepares the DMMG to solve a system
180: Collective on DMMG
182: Input Parameter:
183: . dmmg - the context
185: Level: advanced
187: .seealso DMMGCreate(), DMMGDestroy(), DMMG, DMMGSetSNES(), DMMGSetKSP(), DMMGSolve()
189: @*/
190: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetUp(DMMG *dmmg)
191: {
193: PetscInt i,nlevels = dmmg[0]->nlevels;
197: /* Create work vectors and matrix for each level */
198: for (i=0; i<nlevels; i++) {
199: DMCreateGlobalVector(dmmg[i]->dm,&dmmg[i]->x);
200: VecDuplicate(dmmg[i]->x,&dmmg[i]->b);
201: VecDuplicate(dmmg[i]->x,&dmmg[i]->r);
202: }
204: /* Create interpolation/restriction between levels */
205: for (i=1; i<nlevels; i++) {
206: DMGetInterpolation(dmmg[i-1]->dm,dmmg[i]->dm,&dmmg[i]->R,PETSC_NULL);
207: }
209: return(0);
210: }
214: /*@C
215: DMMGSolve - Actually solves the (non)linear system defined with the DMMG
217: Collective on DMMG
219: Input Parameter:
220: . dmmg - the context
222: Level: advanced
224: Options Database:
225: + -dmmg_grid_sequence - use grid sequencing to get the initial solution for each level from the previous
226: - -dmmg_vecmonitor - display the solution at each iteration
228: Notes: For linear (KSP) problems may be called more than once, uses the same
229: matrices but recomputes the right hand side for each new solve. Call DMMGSetKSP()
230: to generate new matrices.
231:
232: .seealso DMMGCreate(), DMMGDestroy(), DMMG, DMMGSetSNES(), DMMGSetKSP(), DMMGSetUp()
234: @*/
235: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSolve(DMMG *dmmg)
236: {
238: PetscInt i,nlevels = dmmg[0]->nlevels;
239: PetscTruth gridseq,vecmonitor,flg;
242: PetscOptionsHasName(0,"-dmmg_grid_sequence",&gridseq);
243: PetscOptionsHasName(0,"-dmmg_vecmonitor",&vecmonitor);
244: if (gridseq) {
245: if (dmmg[0]->initialguess) {
246: (*dmmg[0]->initialguess)(dmmg[0],dmmg[0]->x);
247: if (dmmg[0]->ksp && !dmmg[0]->snes) {
248: KSPSetInitialGuessNonzero(dmmg[0]->ksp,PETSC_TRUE);
249: }
250: }
251: for (i=0; i<nlevels-1; i++) {
252: (*dmmg[i]->solve)(dmmg,i);
253: if (vecmonitor) {
254: VecView(dmmg[i]->x,PETSC_VIEWER_DRAW_(dmmg[i]->comm));
255: }
256: MatInterpolate(dmmg[i+1]->R,dmmg[i]->x,dmmg[i+1]->x);
257: if (dmmg[i+1]->ksp && !dmmg[i+1]->ksp) {
258: KSPSetInitialGuessNonzero(dmmg[i+1]->ksp,PETSC_TRUE);
259: }
260: }
261: } else {
262: if (dmmg[nlevels-1]->initialguess) {
263: (*dmmg[nlevels-1]->initialguess)(dmmg[nlevels-1],dmmg[nlevels-1]->x);
264: }
265: }
266: (*DMMGGetFine(dmmg)->solve)(dmmg,nlevels-1);
267: if (vecmonitor) {
268: VecView(dmmg[nlevels-1]->x,PETSC_VIEWER_DRAW_(dmmg[nlevels-1]->comm));
269: }
271: PetscOptionsHasName(PETSC_NULL,"-dmmg_view",&flg);
272: if (flg && !PetscPreLoadingOn) {
273: DMMGView(dmmg,PETSC_VIEWER_STDOUT_(dmmg[0]->comm));
274: }
275: PetscOptionsHasName(PETSC_NULL,"-dmmg_view_binary",&flg);
276: if (flg && !PetscPreLoadingOn) {
277: DMMGView(dmmg,PETSC_VIEWER_BINARY_(dmmg[0]->comm));
278: }
279: return(0);
280: }
284: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSolveKSP(DMMG *dmmg,PetscInt level)
285: {
289: if (dmmg[level]->rhs) {
290: (*dmmg[level]->rhs)(dmmg[level],dmmg[level]->b);
291: }
292: if (dmmg[level]->matricesset) {
293: KSPSetOperators(dmmg[level]->ksp,dmmg[level]->J,dmmg[level]->J,SAME_NONZERO_PATTERN);
294: dmmg[level]->matricesset = PETSC_FALSE;
295: }
296: KSPSolve(dmmg[level]->ksp,dmmg[level]->b,dmmg[level]->x);
297: return(0);
298: }
300: /*
301: Sets each of the linear solvers to use multigrid
302: */
305: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetUpLevel(DMMG *dmmg,KSP ksp,PetscInt nlevels)
306: {
308: PetscInt i;
309: PC pc;
310: PetscTruth ismg,monitor,ismf,isshell,ismffd;
311: KSP lksp; /* solver internal to the multigrid preconditioner */
312: MPI_Comm *comms,comm;
313: PetscViewer ascii;
316: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
318: PetscOptionsHasName(PETSC_NULL,"-dmmg_ksp_monitor",&monitor);
319: if (monitor) {
320: PetscObjectGetComm((PetscObject)ksp,&comm);
321: PetscViewerASCIIOpen(comm,"stdout",&ascii);
322: PetscViewerASCIISetTab(ascii,1+dmmg[0]->nlevels-nlevels);
323: KSPSetMonitor(ksp,KSPDefaultMonitor,ascii,(PetscErrorCode(*)(void*))PetscViewerDestroy);
324: }
326: /* use fgmres on outer iteration by default */
327: KSPSetType(ksp,KSPFGMRES);
328: KSPGetPC(ksp,&pc);
329: PCSetType(pc,PCMG);
330: PetscMalloc(nlevels*sizeof(MPI_Comm),&comms);
331: for (i=0; i<nlevels; i++) {
332: comms[i] = dmmg[i]->comm;
333: }
334: PCMGSetLevels(pc,nlevels,comms);
335: PetscFree(comms);
336: PCMGSetType(pc,PC_MG_FULL);
338: PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
339: if (ismg) {
341: /* set solvers for each level */
342: for (i=0; i<nlevels; i++) {
343: PCMGGetSmoother(pc,i,&lksp);
344: KSPSetOperators(lksp,dmmg[i]->J,dmmg[i]->B,DIFFERENT_NONZERO_PATTERN);
345: if (i < nlevels-1) { /* don't set for finest level, they are set in PCApply_MG()*/
346: PCMGSetX(pc,i,dmmg[i]->x);
347: PCMGSetRhs(pc,i,dmmg[i]->b);
348: }
349: if (i > 0) {
350: PCMGSetR(pc,i,dmmg[i]->r);
351: PCMGSetResidual(pc,i,PCMGDefaultResidual,dmmg[i]->J);
352: }
353: if (monitor) {
354: PetscObjectGetComm((PetscObject)lksp,&comm);
355: PetscViewerASCIIOpen(comm,"stdout",&ascii);
356: PetscViewerASCIISetTab(ascii,1+dmmg[0]->nlevels-i);
357: KSPSetMonitor(lksp,KSPDefaultMonitor,ascii,(PetscErrorCode(*)(void*))PetscViewerDestroy);
358: }
359: /* If using a matrix free multiply and did not provide an explicit matrix to build
360: the preconditioner then must use no preconditioner
361: */
362: PetscTypeCompare((PetscObject)dmmg[i]->B,MATSHELL,&isshell);
363: PetscTypeCompare((PetscObject)dmmg[i]->B,MATDAAD,&ismf);
364: PetscTypeCompare((PetscObject)dmmg[i]->B,MATMFFD,&ismffd);
365: if (isshell || ismf || ismffd) {
366: PC lpc;
367: KSPGetPC(lksp,&lpc);
368: PCSetType(lpc,PCNONE);
369: }
370: }
372: /* Set interpolation/restriction between levels */
373: for (i=1; i<nlevels; i++) {
374: PCMGSetInterpolate(pc,i,dmmg[i]->R);
375: PCMGSetRestriction(pc,i,dmmg[i]->R);
376: }
377: }
378: return(0);
379: }
383: /*@C
384: DMMGSetKSP - Sets the linear solver object that will use the grid hierarchy
386: Collective on DMMG
388: Input Parameter:
389: + dmmg - the context
390: . func - function to compute linear system matrix on each grid level
391: - rhs - function to compute right hand side on each level (need only work on the finest grid
392: if you do not use grid sequencing)
394: Level: advanced
396: Notes: For linear problems my be called more than once, reevaluates the matrices if it is called more
397: than once. Call DMMGSolve() directly several times to solve with the same matrix but different
398: right hand sides.
399:
400: .seealso DMMGCreate(), DMMGDestroy, DMMGSetDM(), DMMGSolve()
402: @*/
403: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetKSP(DMMG *dmmg,PetscErrorCode (*rhs)(DMMG,Vec),PetscErrorCode (*func)(DMMG,Mat))
404: {
406: PetscInt i,nlevels = dmmg[0]->nlevels;
407: PetscTruth galerkin;
410: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
411: galerkin = dmmg[0]->galerkin;
413: if (galerkin) {
414: DMGetMatrix(dmmg[nlevels-1]->dm,MATAIJ,&dmmg[nlevels-1]->B);
415: (*func)(dmmg[nlevels-1],dmmg[nlevels-1]->B);
416: for (i=nlevels-2; i>-1; i--) {
417: MatPtAP(dmmg[i+1]->B,dmmg[i+1]->R,MAT_INITIAL_MATRIX,1.0,&dmmg[i]->B);
418: }
419: }
421: if (!dmmg[0]->ksp) {
422: /* create solvers for each level if they don't already exist*/
423: for (i=0; i<nlevels; i++) {
425: if (!dmmg[i]->B && !galerkin) {
426: DMGetMatrix(dmmg[i]->dm,MATAIJ,&dmmg[i]->B);
427: }
428: if (!dmmg[i]->J) {
429: dmmg[i]->J = dmmg[i]->B;
430: }
432: KSPCreate(dmmg[i]->comm,&dmmg[i]->ksp);
433: DMMGSetUpLevel(dmmg,dmmg[i]->ksp,i+1);
434: KSPSetFromOptions(dmmg[i]->ksp);
435: dmmg[i]->solve = DMMGSolveKSP;
436: dmmg[i]->rhs = rhs;
437: }
438: }
440: /* evalute matrix on each level */
441: for (i=0; i<nlevels; i++) {
442: if (!galerkin) {
443: (*func)(dmmg[i],dmmg[i]->J);
444: }
445: dmmg[i]->matricesset = PETSC_TRUE;
446: }
448: for (i=0; i<nlevels-1; i++) {
449: KSPSetOptionsPrefix(dmmg[i]->ksp,"dmmg_");
450: }
452: return(0);
453: }
457: /*@C
458: DMMGView - prints information on a DA based multi-level preconditioner
460: Collective on DMMG and PetscViewer
462: Input Parameter:
463: + dmmg - the context
464: - viewer - the viewer
466: Level: advanced
468: .seealso DMMGCreate(), DMMGDestroy
470: @*/
471: PetscErrorCode PETSCSNES_DLLEXPORT DMMGView(DMMG *dmmg,PetscViewer viewer)
472: {
474: PetscInt i,nlevels = dmmg[0]->nlevels;
475: PetscMPIInt flag;
476: MPI_Comm comm;
477: PetscTruth iascii,isbinary;
482: PetscObjectGetComm((PetscObject)viewer,&comm);
483: MPI_Comm_compare(comm,dmmg[0]->comm,&flag);
484: if (flag != MPI_CONGRUENT && flag != MPI_IDENT) {
485: SETERRQ(PETSC_ERR_ARG_NOTSAMECOMM,"Different communicators in the DMMG and the PetscViewer");
486: }
488: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
489: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_BINARY,&isbinary);
490: if (isbinary) {
491: for (i=0; i<nlevels; i++) {
492: MatView(dmmg[i]->J,viewer);
493: }
494: for (i=1; i<nlevels; i++) {
495: MatView(dmmg[i]->R,viewer);
496: }
497: } else {
498: if (iascii) {
499: PetscViewerASCIIPrintf(viewer,"DMMG Object with %D levels\n",nlevels);
500: }
501: for (i=0; i<nlevels; i++) {
502: PetscViewerASCIIPushTab(viewer);
503: DMView(dmmg[i]->dm,viewer);
504: PetscViewerASCIIPopTab(viewer);
505: }
506: if (iascii) {
507: PetscViewerASCIIPrintf(viewer,"%s Object on finest level\n",dmmg[nlevels-1]->ksp ? "KSP" : "SNES");
508: if (dmmg[nlevels-1]->galerkin) {
509: PetscViewerASCIIPrintf(viewer,"Using Galerkin R^T*A*R process to compute coarser matrices");
510: }
511: }
512: if (dmmg[nlevels-1]->ksp) {
513: KSPView(dmmg[nlevels-1]->ksp,viewer);
514: } else {
515: /* use of PetscObjectView() means we do not have to link with libpetscsnes if SNES is not being used */
516: PetscObjectView((PetscObject)dmmg[nlevels-1]->snes,viewer);
517: }
518: }
519: return(0);
520: }
524: /*@C
525: DMMGSetNullSpace - Indicates the null space in the linear operator (this is needed by the linear solver)
527: Collective on DMMG
529: Input Parameter:
530: + dmmg - the context
531: . has_cnst - is the constant vector in the null space
532: . n - number of null vectors (excluding the possible constant vector)
533: - func - a function that fills an array of vectors with the null vectors (must be orthonormal), may be PETSC_NULL
535: Level: advanced
537: .seealso DMMGCreate(), DMMGDestroy, DMMGSetDM(), DMMGSolve(), MatNullSpaceCreate(), KSPSetNullSpace()
539: @*/
540: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetNullSpace(DMMG *dmmg,PetscTruth has_cnst,PetscInt n,PetscErrorCode (*func)(DMMG,Vec[]))
541: {
543: PetscInt i,j,nlevels = dmmg[0]->nlevels;
544: Vec *nulls = 0;
545: MatNullSpace nullsp;
546: KSP iksp;
547: PC pc,ipc;
548: PetscTruth ismg,isred;
551: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
552: if (!dmmg[0]->ksp) SETERRQ(PETSC_ERR_ORDER,"Must call AFTER DMMGSetKSP() or DMMGSetSNES()");
553: if ((n && !func) || (!n && func)) SETERRQ(PETSC_ERR_ARG_INCOMP,"Both n and func() must be set together");
554: if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Cannot have negative number of vectors in null space n = %D",n)
556: for (i=0; i<nlevels; i++) {
557: if (n) {
558: VecDuplicateVecs(dmmg[i]->b,n,&nulls);
559: (*func)(dmmg[i],nulls);
560: }
561: MatNullSpaceCreate(dmmg[i]->comm,has_cnst,n,nulls,&nullsp);
562: KSPSetNullSpace(dmmg[i]->ksp,nullsp);
563: for (j=i; j<nlevels; j++) {
564: KSPGetPC(dmmg[j]->ksp,&pc);
565: PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
566: if (ismg) {
567: PCMGGetSmoother(pc,i,&iksp);
568: KSPSetNullSpace(iksp, nullsp);
569: }
570: }
571: MatNullSpaceDestroy(nullsp);
572: if (n) {
573: PetscFree(nulls);
574: }
575: }
576: /* make all the coarse grid solvers have LU shift since they are singular */
577: for (i=0; i<nlevels; i++) {
578: KSPGetPC(dmmg[i]->ksp,&pc);
579: PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
580: if (ismg) {
581: PCMGGetSmoother(pc,0,&iksp);
582: KSPGetPC(iksp,&ipc);
583: PetscTypeCompare((PetscObject)ipc,PCREDUNDANT,&isred);
584: if (isred) {
585: PCRedundantGetPC(ipc,&ipc);
586: }
587: PCFactorSetShiftPd(ipc,PETSC_TRUE);
588: }
589: }
590: return(0);
591: }
595: /*@C
596: DMMGInitialGuessCurrent - Use with DMMGSetInitialGuess() to use the current value in the
597: solution vector (obtainable with DMMGGetx() as the initial guess)
599: Collective on DMMG
601: Input Parameter:
602: + dmmg - the context
603: - vec - dummy argument
605: Level: intermediate
607: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGSetInitialGuess()
609: @*/
610: PetscErrorCode PETSCSNES_DLLEXPORT DMMGInitialGuessCurrent(DMMG dmmg,Vec vec)
611: {
613: return(0);
614: }
618: /*@C
619: DMMGSetInitialGuess - Sets the function that computes an initial guess.
621: Collective on DMMG
623: Input Parameter:
624: + dmmg - the context
625: - guess - the function
627: Notes: For nonlinear problems, if this is not set, then the current value in the
628: solution vector (obtained with DMMGGetX()) is used. Thus is if you doing 'time
629: stepping' it will use your current solution as the guess for the next timestep.
630: If grid sequencing is used (via -dmmg_grid_sequence) then the "guess" function
631: is used only on the coarsest grid.
632: For linear problems, if this is not set, then 0 is used as an initial guess.
633: If you would like the linear solver to also (like the nonlinear solver) use
634: the current solution vector as the initial guess then use DMMGInitialGuessCurrent()
635: as the function you pass in
637: Level: intermediate
640: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGInitialGuessCurrent()
642: @*/
643: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetInitialGuess(DMMG *dmmg,PetscErrorCode (*guess)(DMMG,Vec))
644: {
645: PetscInt i,nlevels = dmmg[0]->nlevels;
648: for (i=0; i<nlevels; i++) {
649: dmmg[i]->initialguess = guess;
650: }
651: return(0);
652: }