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 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 _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: .seealso DMMGCreate()
84: @*/
85: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetUseGalerkinCoarse(DMMG* dmmg)
86: {
87: PetscInt i,nlevels = dmmg[0]->nlevels;
90: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
92: for (i=0; i<nlevels-1; i++) {
93: dmmg[i]->galerkin = PETSC_TRUE;
94: }
95: return(0);
96: }
100: /*@C
101: DMMGDestroy - Destroys a DA based multigrid solver object.
103: Collective on DMMG
105: Input Parameter:
106: . - the context
108: Level: advanced
110: .seealso DMMGCreate()
112: @*/
113: PetscErrorCode PETSCSNES_DLLEXPORT DMMGDestroy(DMMG *dmmg)
114: {
116: PetscInt i,nlevels = dmmg[0]->nlevels;
119: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
121: for (i=1; i<nlevels; i++) {
122: if (dmmg[i]->R) {MatDestroy(dmmg[i]->R);}
123: }
124: for (i=0; i<nlevels; i++) {
125: if (dmmg[i]->dm) {DMDestroy(dmmg[i]->dm);}
126: if (dmmg[i]->x) {VecDestroy(dmmg[i]->x);}
127: if (dmmg[i]->b) {VecDestroy(dmmg[i]->b);}
128: if (dmmg[i]->r) {VecDestroy(dmmg[i]->r);}
129: if (dmmg[i]->work1) {VecDestroy(dmmg[i]->work1);}
130: if (dmmg[i]->w) {VecDestroy(dmmg[i]->w);}
131: if (dmmg[i]->work2) {VecDestroy(dmmg[i]->work2);}
132: if (dmmg[i]->lwork1) {VecDestroy(dmmg[i]->lwork1);}
133: if (dmmg[i]->B && dmmg[i]->B != dmmg[i]->J) {MatDestroy(dmmg[i]->B);}
134: if (dmmg[i]->J) {MatDestroy(dmmg[i]->J);}
135: if (dmmg[i]->Rscale) {VecDestroy(dmmg[i]->Rscale);}
136: if (dmmg[i]->fdcoloring){MatFDColoringDestroy(dmmg[i]->fdcoloring);}
137: if (dmmg[i]->ksp && !dmmg[i]->snes) {KSPDestroy(dmmg[i]->ksp);}
138: if (dmmg[i]->snes) {PetscObjectDestroy((PetscObject)dmmg[i]->snes);}
139: if (dmmg[i]->inject) {VecScatterDestroy(dmmg[i]->inject);}
140: PetscFree(dmmg[i]);
141: }
142: PetscFree(dmmg);
143: return(0);
144: }
148: /*@C
149: DMMGSetDM - Sets the coarse grid information for the grids
151: Collective on DMMG
153: Input Parameter:
154: + dmmg - the context
155: - dm - the DA or VecPack object
157: Level: advanced
159: .seealso DMMGCreate(), DMMGDestroy()
161: @*/
162: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetDM(DMMG *dmmg,DM dm)
163: {
165: PetscInt i,nlevels = dmmg[0]->nlevels;
168: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
170: /* Create DA data structure for all the levels */
171: dmmg[0]->dm = dm;
172: PetscObjectReference((PetscObject)dm);
173: for (i=1; i<nlevels; i++) {
174: DMRefine(dmmg[i-1]->dm,dmmg[i]->comm,&dmmg[i]->dm);
175: }
176: DMMGSetUp(dmmg);
177: return(0);
178: }
182: /*@C
183: DMMGSetUp - Prepares the DMMG to solve a system
185: Collective on DMMG
187: Input Parameter:
188: . dmmg - the context
190: Level: advanced
192: .seealso DMMGCreate(), DMMGDestroy(), DMMG, DMMGSetSNES(), DMMGSetKSP(), DMMGSolve()
194: @*/
195: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetUp(DMMG *dmmg)
196: {
198: PetscInt i,nlevels = dmmg[0]->nlevels;
202: /* Create work vectors and matrix for each level */
203: for (i=0; i<nlevels; i++) {
204: DMCreateGlobalVector(dmmg[i]->dm,&dmmg[i]->x);
205: VecDuplicate(dmmg[i]->x,&dmmg[i]->b);
206: VecDuplicate(dmmg[i]->x,&dmmg[i]->r);
207: }
209: /* Create interpolation/restriction between levels */
210: for (i=1; i<nlevels; i++) {
211: DMGetInterpolation(dmmg[i-1]->dm,dmmg[i]->dm,&dmmg[i]->R,PETSC_NULL);
212: }
214: return(0);
215: }
219: /*@C
220: DMMGSolve - Actually solves the (non)linear system defined with the DMMG
222: Collective on DMMG
224: Input Parameter:
225: . dmmg - the context
227: Level: advanced
229: Options Database:
230: + -dmmg_grid_sequence - use grid sequencing to get the initial solution for each level from the previous
231: - -dmmg_vecmonitor - display the solution at each iteration
233: Notes: For linear (KSP) problems may be called more than once, uses the same
234: matrices but recomputes the right hand side for each new solve. Call DMMGSetKSP()
235: to generate new matrices.
236:
237: .seealso DMMGCreate(), DMMGDestroy(), DMMG, DMMGSetSNES(), DMMGSetKSP(), DMMGSetUp()
239: @*/
240: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSolve(DMMG *dmmg)
241: {
243: PetscInt i,nlevels = dmmg[0]->nlevels;
244: PetscTruth gridseq,vecmonitor,flg;
247: PetscOptionsHasName(0,"-dmmg_grid_sequence",&gridseq);
248: PetscOptionsHasName(0,"-dmmg_vecmonitor",&vecmonitor);
249: if (gridseq) {
250: if (dmmg[0]->initialguess) {
251: (*dmmg[0]->initialguess)(dmmg[0],dmmg[0]->x);
252: if (dmmg[0]->ksp && !dmmg[0]->snes) {
253: KSPSetInitialGuessNonzero(dmmg[0]->ksp,PETSC_TRUE);
254: }
255: }
256: for (i=0; i<nlevels-1; i++) {
257: (*dmmg[i]->solve)(dmmg,i);
258: if (vecmonitor) {
259: VecView(dmmg[i]->x,PETSC_VIEWER_DRAW_(dmmg[i]->comm));
260: }
261: MatInterpolate(dmmg[i+1]->R,dmmg[i]->x,dmmg[i+1]->x);
262: if (dmmg[i+1]->ksp && !dmmg[i+1]->ksp) {
263: KSPSetInitialGuessNonzero(dmmg[i+1]->ksp,PETSC_TRUE);
264: }
265: }
266: } else {
267: if (dmmg[nlevels-1]->initialguess) {
268: (*dmmg[nlevels-1]->initialguess)(dmmg[nlevels-1],dmmg[nlevels-1]->x);
269: }
270: }
271: (*DMMGGetFine(dmmg)->solve)(dmmg,nlevels-1);
272: if (vecmonitor) {
273: VecView(dmmg[nlevels-1]->x,PETSC_VIEWER_DRAW_(dmmg[nlevels-1]->comm));
274: }
276: PetscOptionsHasName(PETSC_NULL,"-dmmg_view",&flg);
277: if (flg && !PetscPreLoadingOn) {
278: DMMGView(dmmg,PETSC_VIEWER_STDOUT_(dmmg[0]->comm));
279: }
280: PetscOptionsHasName(PETSC_NULL,"-dmmg_view_binary",&flg);
281: if (flg && !PetscPreLoadingOn) {
282: DMMGView(dmmg,PETSC_VIEWER_BINARY_(dmmg[0]->comm));
283: }
284: return(0);
285: }
289: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSolveKSP(DMMG *dmmg,PetscInt level)
290: {
294: if (dmmg[level]->rhs) {
295: (*dmmg[level]->rhs)(dmmg[level],dmmg[level]->b);
296: }
297: if (dmmg[level]->matricesset) {
298: KSPSetOperators(dmmg[level]->ksp,dmmg[level]->J,dmmg[level]->B,SAME_NONZERO_PATTERN);
299: dmmg[level]->matricesset = PETSC_FALSE;
300: }
301: KSPSolve(dmmg[level]->ksp,dmmg[level]->b,dmmg[level]->x);
302: return(0);
303: }
305: /*
306: Sets each of the linear solvers to use multigrid
307: */
310: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetUpLevel(DMMG *dmmg,KSP ksp,PetscInt nlevels)
311: {
313: PetscInt i;
314: PC pc;
315: PetscTruth ismg,monitor,ismf,isshell,ismffd;
316: KSP lksp; /* solver internal to the multigrid preconditioner */
317: MPI_Comm *comms,comm;
318: PetscViewer ascii;
321: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
323: PetscOptionsHasName(PETSC_NULL,"-dmmg_ksp_monitor",&monitor);
324: if (monitor) {
325: PetscObjectGetComm((PetscObject)ksp,&comm);
326: PetscViewerASCIIOpen(comm,"stdout",&ascii);
327: PetscViewerASCIISetTab(ascii,1+dmmg[0]->nlevels-nlevels);
328: KSPSetMonitor(ksp,KSPDefaultMonitor,ascii,(PetscErrorCode(*)(void*))PetscViewerDestroy);
329: }
331: /* use fgmres on outer iteration by default */
332: KSPSetType(ksp,KSPFGMRES);
333: KSPGetPC(ksp,&pc);
334: PCSetType(pc,PCMG);
335: PetscMalloc(nlevels*sizeof(MPI_Comm),&comms);
336: for (i=0; i<nlevels; i++) {
337: comms[i] = dmmg[i]->comm;
338: }
339: PCMGSetLevels(pc,nlevels,comms);
340: PetscFree(comms);
341: PCMGSetType(pc,PC_MG_FULL);
343: PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
344: if (ismg) {
345: if (dmmg[0]->galerkin) {
346: PCMGSetGalerkin(pc);
347: }
349: /* set solvers for each level */
350: for (i=0; i<nlevels; i++) {
351: PCMGGetSmoother(pc,i,&lksp);
352: if (i == nlevels-1 || !dmmg[0]->galerkin) {
353: KSPSetOperators(lksp,dmmg[i]->J,dmmg[i]->B,DIFFERENT_NONZERO_PATTERN);
354: }
355: if (i < nlevels-1) { /* don't set for finest level, they are set in PCApply_MG()*/
356: PCMGSetX(pc,i,dmmg[i]->x);
357: PCMGSetRhs(pc,i,dmmg[i]->b);
358: }
359: if (i > 0) {
360: PCMGSetR(pc,i,dmmg[i]->r);
361: PCMGSetResidual(pc,i,PCMGDefaultResidual,dmmg[i]->J);
362: }
363: if (monitor) {
364: PetscObjectGetComm((PetscObject)lksp,&comm);
365: PetscViewerASCIIOpen(comm,"stdout",&ascii);
366: PetscViewerASCIISetTab(ascii,1+dmmg[0]->nlevels-i);
367: KSPSetMonitor(lksp,KSPDefaultMonitor,ascii,(PetscErrorCode(*)(void*))PetscViewerDestroy);
368: }
369: /* If using a matrix free multiply and did not provide an explicit matrix to build
370: the preconditioner then must use no preconditioner
371: */
372: PetscTypeCompare((PetscObject)dmmg[i]->B,MATSHELL,&isshell);
373: PetscTypeCompare((PetscObject)dmmg[i]->B,MATDAAD,&ismf);
374: PetscTypeCompare((PetscObject)dmmg[i]->B,MATMFFD,&ismffd);
375: if (isshell || ismf || ismffd) {
376: PC lpc;
377: KSPGetPC(lksp,&lpc);
378: PCSetType(lpc,PCNONE);
379: }
380: }
382: /* Set interpolation/restriction between levels */
383: for (i=1; i<nlevels; i++) {
384: PCMGSetInterpolate(pc,i,dmmg[i]->R);
385: PCMGSetRestriction(pc,i,dmmg[i]->R);
386: }
387: }
388: return(0);
389: }
393: /*@C
394: DMMGSetKSP - Sets the linear solver object that will use the grid hierarchy
396: Collective on DMMG
398: Input Parameter:
399: + dmmg - the context
400: . func - function to compute linear system matrix on each grid level
401: - rhs - function to compute right hand side on each level (need only work on the finest grid
402: if you do not use grid sequencing)
404: Level: advanced
406: Notes: For linear problems my be called more than once, reevaluates the matrices if it is called more
407: than once. Call DMMGSolve() directly several times to solve with the same matrix but different
408: right hand sides.
409:
410: .seealso DMMGCreate(), DMMGDestroy, DMMGSetDM(), DMMGSolve()
412: @*/
413: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetKSP(DMMG *dmmg,PetscErrorCode (*rhs)(DMMG,Vec),PetscErrorCode (*func)(DMMG,Mat,Mat))
414: {
416: PetscInt i,nlevels = dmmg[0]->nlevels;
417: PetscTruth galerkin;
420: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
421: galerkin = dmmg[nlevels - 2 > 0 ? nlevels - 2 : 0]->galerkin;
423: if (galerkin) {
424: DMGetMatrix(dmmg[nlevels-1]->dm,MATAIJ,&dmmg[nlevels-1]->B);
425: if (!dmmg[nlevels-1]->J) {
426: dmmg[nlevels-1]->J = dmmg[nlevels-1]->B;
427: }
428: (*func)(dmmg[nlevels-1],dmmg[nlevels-1]->J,dmmg[nlevels-1]->B);
429: for (i=nlevels-2; i>-1; i--) {
430: if (dmmg[i]->galerkin) {
431: MatPtAP(dmmg[i+1]->B,dmmg[i+1]->R,MAT_INITIAL_MATRIX,1.0,&dmmg[i]->B);
432: if (!dmmg[i]->J) {
433: dmmg[i]->J = dmmg[i]->B;
434: }
435: }
436: }
437: }
439: if (!dmmg[0]->ksp) {
440: /* create solvers for each level if they don't already exist*/
441: for (i=0; i<nlevels; i++) {
443: if (!dmmg[i]->B && !dmmg[i]->galerkin) {
444: DMGetMatrix(dmmg[i]->dm,MATAIJ,&dmmg[i]->B);
445: }
446: if (!dmmg[i]->J) {
447: dmmg[i]->J = dmmg[i]->B;
448: }
450: KSPCreate(dmmg[i]->comm,&dmmg[i]->ksp);
451: DMMGSetUpLevel(dmmg,dmmg[i]->ksp,i+1);
452: KSPSetFromOptions(dmmg[i]->ksp);
453: dmmg[i]->solve = DMMGSolveKSP;
454: dmmg[i]->rhs = rhs;
455: }
456: }
458: /* evalute matrix on each level */
459: for (i=0; i<nlevels; i++) {
460: if (!dmmg[i]->galerkin) {
461: (*func)(dmmg[i],dmmg[i]->J,dmmg[i]->B);
462: }
463: dmmg[i]->matricesset = PETSC_TRUE;
464: }
466: for (i=0; i<nlevels-1; i++) {
467: KSPSetOptionsPrefix(dmmg[i]->ksp,"dmmg_");
468: }
470: return(0);
471: }
475: /*@C
476: DMMGView - prints information on a DA based multi-level preconditioner
478: Collective on DMMG and PetscViewer
480: Input Parameter:
481: + dmmg - the context
482: - viewer - the viewer
484: Level: advanced
486: .seealso DMMGCreate(), DMMGDestroy
488: @*/
489: PetscErrorCode PETSCSNES_DLLEXPORT DMMGView(DMMG *dmmg,PetscViewer viewer)
490: {
492: PetscInt i,nlevels = dmmg[0]->nlevels;
493: PetscMPIInt flag;
494: MPI_Comm comm;
495: PetscTruth iascii,isbinary;
500: PetscObjectGetComm((PetscObject)viewer,&comm);
501: MPI_Comm_compare(comm,dmmg[0]->comm,&flag);
502: if (flag != MPI_CONGRUENT && flag != MPI_IDENT) {
503: SETERRQ(PETSC_ERR_ARG_NOTSAMECOMM,"Different communicators in the DMMG and the PetscViewer");
504: }
506: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
507: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_BINARY,&isbinary);
508: if (isbinary) {
509: for (i=0; i<nlevels; i++) {
510: MatView(dmmg[i]->J,viewer);
511: }
512: for (i=1; i<nlevels; i++) {
513: MatView(dmmg[i]->R,viewer);
514: }
515: } else {
516: if (iascii) {
517: PetscViewerASCIIPrintf(viewer,"DMMG Object with %D levels\n",nlevels);
518: }
519: for (i=0; i<nlevels; i++) {
520: PetscViewerASCIIPushTab(viewer);
521: DMView(dmmg[i]->dm,viewer);
522: PetscViewerASCIIPopTab(viewer);
523: }
524: if (iascii) {
525: PetscViewerASCIIPrintf(viewer,"%s Object on finest level\n",dmmg[nlevels-1]->ksp ? "KSP" : "SNES");
526: if (dmmg[nlevels-2 > 0 ? nlevels-2 : 0]->galerkin) {
527: PetscViewerASCIIPrintf(viewer,"Using Galerkin R^T*A*R process to compute coarser matrices");
528: }
529: }
530: if (dmmg[nlevels-1]->ksp) {
531: KSPView(dmmg[nlevels-1]->ksp,viewer);
532: } else {
533: /* use of PetscObjectView() means we do not have to link with libpetscsnes if SNES is not being used */
534: PetscObjectView((PetscObject)dmmg[nlevels-1]->snes,viewer);
535: }
536: }
537: return(0);
538: }
542: /*@C
543: DMMGSetNullSpace - Indicates the null space in the linear operator (this is needed by the linear solver)
545: Collective on DMMG
547: Input Parameter:
548: + dmmg - the context
549: . has_cnst - is the constant vector in the null space
550: . n - number of null vectors (excluding the possible constant vector)
551: - func - a function that fills an array of vectors with the null vectors (must be orthonormal), may be PETSC_NULL
553: Level: advanced
555: .seealso DMMGCreate(), DMMGDestroy, DMMGSetDM(), DMMGSolve(), MatNullSpaceCreate(), KSPSetNullSpace()
557: @*/
558: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetNullSpace(DMMG *dmmg,PetscTruth has_cnst,PetscInt n,PetscErrorCode (*func)(DMMG,Vec[]))
559: {
561: PetscInt i,j,nlevels = dmmg[0]->nlevels;
562: Vec *nulls = 0;
563: MatNullSpace nullsp;
564: KSP iksp;
565: PC pc,ipc;
566: PetscTruth ismg,isred;
569: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
570: if (!dmmg[0]->ksp) SETERRQ(PETSC_ERR_ORDER,"Must call AFTER DMMGSetKSP() or DMMGSetSNES()");
571: if ((n && !func) || (!n && func)) SETERRQ(PETSC_ERR_ARG_INCOMP,"Both n and func() must be set together");
572: if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Cannot have negative number of vectors in null space n = %D",n)
574: for (i=0; i<nlevels; i++) {
575: if (n) {
576: VecDuplicateVecs(dmmg[i]->b,n,&nulls);
577: (*func)(dmmg[i],nulls);
578: }
579: MatNullSpaceCreate(dmmg[i]->comm,has_cnst,n,nulls,&nullsp);
580: KSPSetNullSpace(dmmg[i]->ksp,nullsp);
581: for (j=i; j<nlevels; j++) {
582: KSPGetPC(dmmg[j]->ksp,&pc);
583: PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
584: if (ismg) {
585: PCMGGetSmoother(pc,i,&iksp);
586: KSPSetNullSpace(iksp, nullsp);
587: }
588: }
589: MatNullSpaceDestroy(nullsp);
590: if (n) {
591: PetscFree(nulls);
592: }
593: }
594: /* make all the coarse grid solvers have LU shift since they are singular */
595: for (i=0; i<nlevels; i++) {
596: KSPGetPC(dmmg[i]->ksp,&pc);
597: PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
598: if (ismg) {
599: PCMGGetSmoother(pc,0,&iksp);
600: KSPGetPC(iksp,&ipc);
601: PetscTypeCompare((PetscObject)ipc,PCREDUNDANT,&isred);
602: if (isred) {
603: PCRedundantGetPC(ipc,&ipc);
604: }
605: PCFactorSetShiftPd(ipc,PETSC_TRUE);
606: }
607: }
608: return(0);
609: }
613: /*@C
614: DMMGInitialGuessCurrent - Use with DMMGSetInitialGuess() to use the current value in the
615: solution vector (obtainable with DMMGGetx() as the initial guess)
617: Collective on DMMG
619: Input Parameter:
620: + dmmg - the context
621: - vec - dummy argument
623: Level: intermediate
625: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGSetInitialGuess()
627: @*/
628: PetscErrorCode PETSCSNES_DLLEXPORT DMMGInitialGuessCurrent(DMMG dmmg,Vec vec)
629: {
631: return(0);
632: }
636: /*@C
637: DMMGSetInitialGuess - Sets the function that computes an initial guess.
639: Collective on DMMG
641: Input Parameter:
642: + dmmg - the context
643: - guess - the function
645: Notes: For nonlinear problems, if this is not set, then the current value in the
646: solution vector (obtained with DMMGGetX()) is used. Thus is if you doing 'time
647: stepping' it will use your current solution as the guess for the next timestep.
648: If grid sequencing is used (via -dmmg_grid_sequence) then the "guess" function
649: is used only on the coarsest grid.
650: For linear problems, if this is not set, then 0 is used as an initial guess.
651: If you would like the linear solver to also (like the nonlinear solver) use
652: the current solution vector as the initial guess then use DMMGInitialGuessCurrent()
653: as the function you pass in
655: Level: intermediate
658: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGInitialGuessCurrent()
660: @*/
661: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetInitialGuess(DMMG *dmmg,PetscErrorCode (*guess)(DMMG,Vec))
662: {
663: PetscInt i,nlevels = dmmg[0]->nlevels;
666: for (i=0; i<nlevels; i++) {
667: dmmg[i]->initialguess = guess;
668: }
669: return(0);
670: }