Actual source code: damgsnes.c
2: #include <petscdmda.h> /*I "petscdmda.h" I*/
3: #include <petscdmmesh.h> /*I "petscdmmesh.h" I*/
4: #include <private/daimpl.h>
5: /* It appears that preprocessor directives are not respected by bfort */
6: #include <petscpcmg.h> /*I "petscpcmg.h" I*/
7: #include <petscdmmg.h> /*I "petscdmmg.h" I*/
9: #if defined(PETSC_HAVE_ADIC)
16: #endif
26: /*
27: period of -1 indicates update only on zeroth iteration of SNES
28: */
29: #define ShouldUpdate(l,it) (((dmmg[l-1]->updatejacobianperiod == -1) && (it == 0)) || \
30: ((dmmg[l-1]->updatejacobianperiod > 0) && !(it % dmmg[l-1]->updatejacobianperiod)))
31: /*
32: Evaluates the Jacobian on all of the grids. It is used by DMMG to provide the
33: ComputeJacobian() function that SNESSetJacobian() requires.
34: */
37: PetscErrorCode DMMGComputeJacobian_Multigrid(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
38: {
39: DMMG *dmmg = (DMMG*)ptr;
41: PetscInt i,nlevels = dmmg[0]->nlevels,it;
42: KSP ksp,lksp;
43: PC pc;
44: PetscBool ismg,galerkin = PETSC_FALSE;
45: Vec W;
46: MatStructure flg;
49: if (!dmmg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Passing null as user context which should contain DMMG");
50: SNESGetIterationNumber(snes,&it);
52: /* compute Jacobian on finest grid */
53: if (dmmg[nlevels-1]->updatejacobian && ShouldUpdate(nlevels,it)) {
54: (*DMMGGetFine(dmmg)->computejacobian)(snes,X,J,B,flag,DMMGGetFine(dmmg));
55: } else {
56: PetscInfo3(0,"Skipping Jacobian, SNES iteration %D frequence %D level %D\n",it,dmmg[nlevels-1]->updatejacobianperiod,nlevels-1);
57: *flag = SAME_PRECONDITIONER;
58: }
59: MatMFFDSetBase(DMMGGetFine(dmmg)->J,X,PETSC_NULL);
61: /* create coarser grid Jacobians for preconditioner if multigrid is the preconditioner */
62: SNESGetKSP(snes,&ksp);
63: KSPGetPC(ksp,&pc);
64: PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
65: if (ismg) {
66: PCMGGetGalerkin(pc,&galerkin);
67: }
69: if (!galerkin) {
70: for (i=nlevels-1; i>0; i--) {
71: if (!dmmg[i-1]->w) {
72: VecDuplicate(dmmg[i-1]->x,&dmmg[i-1]->w);
73: }
74: W = dmmg[i-1]->w;
75: /* restrict X to coarser grid */
76: MatRestrict(dmmg[i]->R,X,W);
77: X = W;
78: /* scale to "natural" scaling for that grid */
79: VecPointwiseMult(X,X,dmmg[i]->Rscale);
80: /* tell the base vector for matrix free multiplies */
81: MatMFFDSetBase(dmmg[i-1]->J,X,PETSC_NULL);
82: /* compute Jacobian on coarse grid */
83: if (dmmg[i-1]->updatejacobian && ShouldUpdate(i,it)) {
84: (*dmmg[i-1]->computejacobian)(snes,X,&dmmg[i-1]->J,&dmmg[i-1]->B,&flg,dmmg[i-1]);
85: flg = SAME_NONZERO_PATTERN;
86: } else {
87: PetscInfo3(0,"Skipping Jacobian, SNES iteration %D frequence %D level %D\n",it,dmmg[i-1]->updatejacobianperiod,i-1);
88: flg = SAME_PRECONDITIONER;
89: }
90: if (ismg) {
91: PCMGGetSmoother(pc,i-1,&lksp);
92: KSPSetOperators(lksp,dmmg[i-1]->J,dmmg[i-1]->B,flg);
93: }
94: }
95: }
96: return(0);
97: }
99: /* ---------------------------------------------------------------------------*/
104: /*
105: DMMGFormFunction - This is a universal global FormFunction used by the DMMG code
106: when the user provides a local function.
108: Input Parameters:
109: + snes - the SNES context
110: . X - input vector
111: - ptr - optional user-defined context, as set by SNESSetFunction()
113: Output Parameter:
114: . F - function vector
116: */
117: PetscErrorCode DMMGFormFunction(SNES snes,Vec X,Vec F,void *ptr)
118: {
119: DMMG dmmg = (DMMG)ptr;
121: Vec localX;
122: DM da = dmmg->dm;
125: DMGetLocalVector(da,&localX);
126: /*
127: Scatter ghost points to local vector, using the 2-step process
128: DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
129: */
130: DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
131: DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
132: DMDAFormFunction1(da,localX,F,dmmg->user);
133: DMRestoreLocalVector(da,&localX);
134: return(0);
135: }
139: PetscErrorCode DMMGFormFunctionGhost(SNES snes,Vec X,Vec F,void *ptr)
140: {
141: DMMG dmmg = (DMMG)ptr;
143: Vec localX, localF;
144: DM da = dmmg->dm;
147: DMGetLocalVector(da,&localX);
148: DMGetLocalVector(da,&localF);
149: /*
150: Scatter ghost points to local vector, using the 2-step process
151: DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
152: */
153: DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
154: DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
155: VecSet(F, 0.0);
156: VecSet(localF, 0.0);
157: DMDAFormFunction1(da,localX,localF,dmmg->user);
158: DMLocalToGlobalBegin(da,localF,ADD_VALUES,F);
159: DMLocalToGlobalEnd(da,localF,ADD_VALUES,F);
160: DMRestoreLocalVector(da,&localX);
161: DMRestoreLocalVector(da,&localF);
162: return(0);
163: }
167: /*
168: DMMGFormFunctionFD - This is a universal global FormFunction used by the DMMG code
169: when the user provides a local function used to compute the Jacobian via FD.
171: Input Parameters:
172: + snes - the SNES context
173: . X - input vector
174: - ptr - optional user-defined context, as set by SNESSetFunction()
176: Output Parameter:
177: . F - function vector
179: */
180: PetscErrorCode DMMGFormFunctionFD(SNES snes,Vec X,Vec F,void *ptr)
181: {
182: DMMG dmmg = (DMMG)ptr;
184: Vec localX;
185: DM da = dmmg->dm;
186: PetscInt N,n;
187:
189: /* determine whether X=localX */
190: DMGetLocalVector(da,&localX);
191: VecGetSize(X,&N);
192: VecGetSize(localX,&n);
194: if (n != N){ /* X != localX */
195: /* Scatter ghost points to local vector, using the 2-step process
196: DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
197: */
198: DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
199: DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
200: } else {
201: DMRestoreLocalVector(da,&localX);
202: localX = X;
203: }
204: DMDAFormFunction(da,dmmg->lfj,localX,F,dmmg->user);
205: if (n != N){
206: DMRestoreLocalVector(da,&localX);
207: }
208: return(0);
209: }
211: #include <private/snesimpl.h>
215: /*@C
216: SNESDAFormFunction - This is a universal function evaluation routine that
217: may be used with SNESSetFunction(). Must be used with SNESSetDM().
219: Collective on SNES
221: Input Parameters:
222: + snes - the SNES context
223: . X - input vector
224: . F - function vector
225: - ptr - pointer to a user context containing problem specific information used by application function
227: Level: intermediate
229: .seealso: DMDASetLocalFunction(), DMDASetLocalJacobian(), DMDASetLocalAdicFunction(), DMDASetLocalAdicMFFunction(),
230: SNESSetFunction(), SNESSetJacobian(), SNESSetDM()
232: @*/
233: PetscErrorCode SNESDAFormFunction(SNES snes,Vec X,Vec F,void *ptr)
234: {
236: Vec localX;
237: DM da = snes->dm;
238: PetscInt N,n;
239:
241: if (!da) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Looks like you called SNESSetFuntion(snes,SNESDAFormFunction,) without also calling SNESSetDM() to set the DMDA context");
243: /* determine whether X=localX */
244: DMGetLocalVector(da,&localX);
245: VecGetSize(X,&N);
246: VecGetSize(localX,&n);
247:
248:
249: if (n != N){ /* X != localX */
250: /* Scatter ghost points to local vector, using the 2-step process
251: DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
252: */
253: DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
254: DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
255: } else {
256: DMRestoreLocalVector(da,&localX);
257: localX = X;
258: }
259: DMDAFormFunction1(da,localX,F,ptr);
260: if (n != N){
261: DMRestoreLocalVector(da,&localX);
262: }
263: return(0);
264: }
266: #if defined(PETSC_HAVE_SIEVE)
269: /*@C
270: SNESMeshFormFunction - This is a universal function evaluation routine that
271: may be used with SNESSetFunction() as long as the user context has a DMMesh
272: as its first record and the user has called DMMeshSetLocalFunction().
274: Collective on SNES
276: Input Parameters:
277: + snes - the SNES context
278: . X - input vector
279: . F - function vector
280: - ptr - pointer to a structure that must have a DMMesh as its first entry.
281: This ptr must have been passed into SNESMeshFormFunction() as the context.
283: Level: intermediate
285: .seealso: DMMeshSetLocalFunction(), DMMeshSetLocalJacobian(), SNESSetFunction(), SNESSetJacobian()
286: @*/
287: PetscErrorCode SNESMeshFormFunction(SNES snes, Vec X, Vec F, void *ptr)
288: {
289: DM dm = *(DM*) ptr;
290: PetscErrorCode (*lf)(DM, Vec, Vec, void *);
291: Vec localX, localF;
292: PetscInt N, n;
293: PetscErrorCode ierr;
299: if (!dm) SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONGSTATE, "Looks like you called SNESSetFromFuntion(snes,SNESMeshFormFunction,) without the DMMesh context");
302: /* determine whether X = localX */
303: DMGetLocalVector(dm, &localX);
304: DMGetLocalVector(dm, &localF);
305: VecGetSize(X, &N);
306: VecGetSize(localX, &n);
308: if (n != N){ /* X != localX */
309: /* Scatter ghost points to local vector, using the 2-step process
310: DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
311: */
312: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
313: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
314: } else {
315: DMRestoreLocalVector(dm, &localX);
316: localX = X;
317: }
318: DMMeshGetLocalFunction(dm, &lf);
319: (*lf)(dm, localX, localF, ptr);
320: if (n != N){
321: DMRestoreLocalVector(dm, &localX);
322: }
323: DMLocalToGlobalBegin(dm, localF, ADD_VALUES, F);
324: DMLocalToGlobalEnd(dm, localF, ADD_VALUES, F);
325: DMRestoreLocalVector(dm, &localF);
326: return(0);
327: }
328: #endif
330: #if defined(PETSC_HAVE_SIEVE)
333: /*
334: SNESMeshFormJacobian - This is a universal Jacobian evaluation routine that
335: may be used with SNESSetJacobian() as long as the user context has a DMMesh
336: as its first record and the user has called DMMeshSetLocalJacobian().
338: Collective on SNES
340: Input Parameters:
341: + snes - the SNES context
342: . X - input vector
343: . J - Jacobian
344: . B - Jacobian used in preconditioner (usally same as J)
345: . flag - indicates if the matrix changed its structure
346: - ptr - pointer to a structure that must have a DMMesh as its first entry.
347: This ptr must have been passed into SNESMeshFormFunction() as the context.
349: Level: intermediate
351: .seealso: DMMeshSetLocalFunction(), DMMeshSetLocalJacobian(), SNESSetFunction(), SNESSetJacobian()
352: */
353: PetscErrorCode SNESMeshFormJacobian(SNES snes, Vec X, Mat *J, Mat *B, MatStructure *flag, void *ptr)
354: {
355: DM dm = *(DM*) ptr;
356: PetscErrorCode (*lj)(DM, Vec, Mat, void *);
357: Vec localX;
358: PetscErrorCode ierr;
361: DMGetLocalVector(dm, &localX);
362: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
363: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
364: DMMeshGetLocalJacobian(dm, &lj);
365: (*lj)(dm, localX, *B, ptr);
366: DMRestoreLocalVector(dm, &localX);
367: /* Assemble true Jacobian; if it is different */
368: if (*J != *B) {
369: MatAssemblyBegin(*J, MAT_FINAL_ASSEMBLY);
370: MatAssemblyEnd(*J, MAT_FINAL_ASSEMBLY);
371: }
372: MatSetOption(*B, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE);
373: *flag = SAME_NONZERO_PATTERN;
374: return(0);
375: }
376: #endif
378: /* ------------------------------------------------------------------------------*/
379: #include <private/matimpl.h> /*I "petscmat.h" I*/
382: PetscErrorCode DMMGComputeJacobianWithFD(SNES snes,Vec x1,Mat *J,Mat *B,MatStructure *flag,void *ctx)
383: {
385: DMMG dmmg = (DMMG)ctx;
386: MatFDColoring color = (MatFDColoring)dmmg->fdcoloring;
387:
389: if (color->ctype == IS_COLORING_GHOSTED){
390: DM da=dmmg->dm;
391: Vec x1_loc;
392: DMGetLocalVector(da,&x1_loc);
393: DMGlobalToLocalBegin(da,x1,INSERT_VALUES,x1_loc);
394: DMGlobalToLocalEnd(da,x1,INSERT_VALUES,x1_loc);
395: SNESDefaultComputeJacobianColor(snes,x1_loc,J,B,flag,dmmg->fdcoloring);
396: DMRestoreLocalVector(da,&x1_loc);
397: } else {
398: SNESDefaultComputeJacobianColor(snes,x1,J,B,flag,dmmg->fdcoloring);
399: }
400: return(0);
401: }
405: PetscErrorCode DMMGComputeJacobianWithMF(SNES snes,Vec x1,Mat *J,Mat *B,MatStructure *flag,void *ctx)
406: {
408:
410: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
411: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
412: return(0);
413: }
417: /*
418: DMMGComputeJacobian - Evaluates the Jacobian when the user has provided
419: a local function evaluation routine.
420: */
421: PetscErrorCode DMMGComputeJacobian(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
422: {
423: DMMG dmmg = (DMMG) ptr;
425: Vec localX;
426: DM da = dmmg->dm;
429: DMGetLocalVector(da,&localX);
430: DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
431: DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
432: DMDAComputeJacobian1(da,localX,*B,dmmg->user);
433: DMRestoreLocalVector(da,&localX);
434: /* Assemble true Jacobian; if it is different */
435: if (*J != *B) {
436: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
437: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
438: }
439: MatSetOption(*B,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);
440: *flag = SAME_NONZERO_PATTERN;
441: return(0);
442: }
446: /*
447: SNESDAComputeJacobianWithAdifor - This is a universal Jacobian evaluation routine
448: that may be used with SNESSetJacobian() from Fortran as long as the user context has
449: a DMDA as its first record and DMDASetLocalAdiforFunction() has been called.
451: Collective on SNES
453: Input Parameters:
454: + snes - the SNES context
455: . X - input vector
456: . J - Jacobian
457: . B - Jacobian used in preconditioner (usally same as J)
458: . flag - indicates if the matrix changed its structure
459: - ptr - optional user-defined context, as set by SNESSetFunction()
461: Level: intermediate
463: .seealso: DMDASetLocalFunction(), DMDASetLocalAdicFunction(), SNESSetFunction(), SNESSetJacobian()
465: */
466: PetscErrorCode SNESDAComputeJacobianWithAdifor(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
467: {
468: DM da = *(DM*) ptr;
470: Vec localX;
473: DMGetLocalVector(da,&localX);
474: DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
475: DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
476: DMDAComputeJacobian1WithAdifor(da,localX,*B,ptr);
477: DMRestoreLocalVector(da,&localX);
478: /* Assemble true Jacobian; if it is different */
479: if (*J != *B) {
480: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
481: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
482: }
483: MatSetOption(*B,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);
484: *flag = SAME_NONZERO_PATTERN;
485: return(0);
486: }
490: /*
491: SNESDAComputeJacobian - This is a universal Jacobian evaluation routine for a
492: locally provided Jacobian. Must be used with SNESSetDM().
494: Collective on SNES
496: Input Parameters:
497: + snes - the SNES context
498: . X - input vector
499: . J - Jacobian
500: . B - Jacobian used in preconditioner (usally same as J)
501: . flag - indicates if the matrix changed its structure
502: - ptr - optional user-defined context, as set by SNESSetFunction()
504: Level: intermediate
506: .seealso: DMDASetLocalFunction(), DMDASetLocalJacobian(), SNESSetFunction(), SNESSetJacobian(), SNESSetDM()
508: */
509: PetscErrorCode SNESDAComputeJacobian(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
510: {
511: DM da = snes->dm;
513: Vec localX;
516: DMGetLocalVector(da,&localX);
517: DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
518: DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
519: DMDAComputeJacobian1(da,localX,*B,ptr);
520: DMRestoreLocalVector(da,&localX);
521: /* Assemble true Jacobian; if it is different */
522: if (*J != *B) {
523: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
524: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
525: }
526: MatSetOption(*B,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);
527: *flag = SAME_NONZERO_PATTERN;
528: return(0);
529: }
533: PetscErrorCode DMMGSolveSNES(DMMG *dmmg,PetscInt level)
534: {
536: PetscInt nlevels = dmmg[0]->nlevels;
539: dmmg[0]->nlevels = level+1;
540: SNESSolve(dmmg[level]->snes,PETSC_NULL,dmmg[level]->x);
541: dmmg[0]->nlevels = nlevels;
542: return(0);
543: }
545: /* ===========================================================================================================*/
549: /*@C
550: DMMGSetSNES - Sets the nonlinear function that defines the nonlinear set of equations
551: to be solved using the grid hierarchy.
553: This is being deprecated. Use KSPSetDM() for linear problems and SNESSetDM() for nonlinear problems.
554: See src/ksp/ksp/examples/tutorials/ex45.c and src/snes/examples/tutorials/ex57.c
556: Collective on DMMG
558: Input Parameter:
559: + dmmg - the context
560: . function - the function that defines the nonlinear system
561: - jacobian - optional function to compute Jacobian
563: Options Database Keys:
564: + -snes_monitor
565: . -dmmg_coloring_from_mat - use graph coloring on the actual matrix nonzero structure instead of getting the coloring from the DM
566: . -dmmg_jacobian_fd
567: . -dmmg_jacobian_ad
568: . -dmmg_jacobian_mf_fd_operator
569: . -dmmg_jacobian_mf_fd
570: . -dmmg_jacobian_mf_ad_operator
571: . -dmmg_jacobian_mf_ad
572: . -dmmg_iscoloring_type
573: -
574: The period at which the Jacobian is recomputed can be set differently for different levels
575: of the Jacobian (for example lag all Jacobians except on the finest level).
576: There is no user interface currently for setting a different period on the different levels, one must set the
577: fields dmmg[i]->updatejacobian and dmmg[i]->updatejacobianperiod directly in the DMMG data structure.
578:
580: Level: advanced
582: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNESLocal(), DMMGSetFromOptions()
584: @*/
585: PetscErrorCode DMMGSetSNES(DMMG *dmmg,PetscErrorCode (*function)(SNES,Vec,Vec,void*),PetscErrorCode (*jacobian)(SNES,Vec,Mat*,Mat*,MatStructure*,void*))
586: {
587: PetscErrorCode ierr;
588: PetscInt i,nlevels = dmmg[0]->nlevels;
589: PetscBool mffdoperator,mffd,fdjacobian;
590: PetscBool useFAS = PETSC_FALSE, fasBlock=PETSC_FALSE, fasGMRES=PETSC_FALSE;
591: PetscBool monitor, monitorAll;
592: PetscInt fasPresmooth = 1, fasPostsmooth = 1, fasCoarsesmooth = 1, fasMaxIter = 2;
593: PetscReal fasRtol = 1.0e-8, fasAbstol = 1.0e-50;
594: #if defined(PETSC_HAVE_ADIC)
595: PetscBool mfadoperator,mfad,adjacobian;
596: #endif
597: PetscClassId classid;
600: if (!dmmg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Passing null as DMMG");
601: if (!jacobian) jacobian = DMMGComputeJacobianWithFD;
602: PetscObjectGetClassId((PetscObject) dmmg[0]->dm, &classid);
604: PetscOptionsBegin(dmmg[0]->comm,dmmg[0]->prefix,"DMMG Options","SNES");
605: PetscOptionsName("-dmmg_monitor","Monitor DMMG iterations","DMMG",&monitor);
606: PetscOptionsName("-dmmg_monitor_all","Monitor all DMMG iterations","DMMG",&monitorAll);
607: /*
608: PetscOptionsBool("-dmmg_fas","Use the Full Approximation Scheme","DMMGSetSNES",useFAS,&useFAS,PETSC_NULL);
609: PetscOptionsName("-dmmg_fas_block","Use point-block smoothing","DMMG",&fasBlock);
610: PetscOptionsName("-dmmg_fas_ngmres","Use Nonlinear GMRES","DMMG",&fasGMRES);
611: PetscOptionsInt("-dmmg_fas_presmooth","Number of downward smoother iterates","DMMG",fasPresmooth,&fasPresmooth,PETSC_NULL);
612: PetscOptionsInt("-dmmg_fas_postsmooth","Number of upward smoother iterates","DMMG",fasPostsmooth,&fasPostsmooth,PETSC_NULL);
613: PetscOptionsInt("-dmmg_fas_coarsesmooth","Number of coarse smoother iterates","DMMG",fasCoarsesmooth,&fasCoarsesmooth,PETSC_NULL);
614: PetscOptionsReal("-dmmg_fas_rtol","Relative tolerance for FAS","DMMG",fasRtol,&fasRtol,PETSC_NULL);
615: PetscOptionsReal("-dmmg_fas_atol","Absolute tolerance for FAS","DMMG",fasAbstol,&fasAbstol,PETSC_NULL);
616: PetscOptionsInt("-dmmg_fas_max_its","Maximum number of iterates per smoother","DMMG",fasMaxIter,&fasMaxIter,PETSC_NULL);
617: */
619: PetscOptionsBool("-dmmg_coloring_from_mat","Compute the coloring directly from the matrix nonzero structure","DMMGSetSNES",dmmg[0]->getcoloringfrommat,&dmmg[0]->getcoloringfrommat,PETSC_NULL);
621: PetscOptionsName("-dmmg_jacobian_fd","Compute sparse Jacobian explicitly with finite differencing","DMMGSetSNES",&fdjacobian);
622: if (fdjacobian) jacobian = DMMGComputeJacobianWithFD;
623: #if defined(PETSC_HAVE_ADIC)
624: PetscOptionsName("-dmmg_jacobian_ad","Compute sparse Jacobian explicitly with ADIC (automatic differentiation)","DMMGSetSNES",&adjacobian);
625: if (adjacobian) jacobian = DMMGComputeJacobianWithAdic;
626: #endif
628: PetscOptionsBoolGroupBegin("-dmmg_jacobian_mf_fd_operator","Apply Jacobian via matrix free finite differencing","DMMGSetSNES",&mffdoperator);
629: PetscOptionsBoolGroupEnd("-dmmg_jacobian_mf_fd","Apply Jacobian via matrix free finite differencing even in computing preconditioner","DMMGSetSNES",&mffd);
630: if (mffd) mffdoperator = PETSC_TRUE;
631: #if defined(PETSC_HAVE_ADIC)
632: PetscOptionsBoolGroupBegin("-dmmg_jacobian_mf_ad_operator","Apply Jacobian via matrix free ADIC (automatic differentiation)","DMMGSetSNES",&mfadoperator);
633: PetscOptionsBoolGroupEnd("-dmmg_jacobian_mf_ad","Apply Jacobian via matrix free ADIC (automatic differentiation) even in computing preconditioner","DMMGSetSNES",&mfad);
634: if (mfad) mfadoperator = PETSC_TRUE;
635: #endif
636: PetscOptionsEnum("-dmmg_iscoloring_type","Type of ISColoring","None",ISColoringTypes,(PetscEnum)dmmg[0]->isctype,(PetscEnum*)&dmmg[0]->isctype,PETSC_NULL);
637:
638: PetscOptionsEnd();
640: /* create solvers for each level */
641: for (i=0; i<nlevels; i++) {
642: SNESCreate(dmmg[i]->comm,&dmmg[i]->snes);
643: PetscObjectIncrementTabLevel((PetscObject)dmmg[i]->snes,PETSC_NULL,nlevels - i - 1);
644: SNESSetFunction(dmmg[i]->snes,dmmg[i]->b,function,dmmg[i]);
645: SNESSetOptionsPrefix(dmmg[i]->snes,dmmg[i]->prefix);
646: SNESGetKSP(dmmg[i]->snes,&dmmg[i]->ksp);
648: if (mffdoperator) {
649: MatCreateSNESMF(dmmg[i]->snes,&dmmg[i]->J);
650: VecDuplicate(dmmg[i]->x,&dmmg[i]->work1);
651: VecDuplicate(dmmg[i]->x,&dmmg[i]->work2);
652: MatMFFDSetFunction(dmmg[i]->J,(PetscErrorCode (*)(void*, Vec,Vec))SNESComputeFunction,dmmg[i]->snes);
653: if (mffd) {
654: dmmg[i]->B = dmmg[i]->J;
655: jacobian = DMMGComputeJacobianWithMF;
656: PetscObjectReference((PetscObject) dmmg[i]->B);
657: }
658: #if defined(PETSC_HAVE_ADIC)
659: } else if (mfadoperator) {
660: MatRegisterDAAD();
661: MatCreateDAAD(dmmg[i]->dm,&dmmg[i]->J);
662: MatDAADSetCtx(dmmg[i]->J,dmmg[i]->user);
663: if (mfad) {
664: dmmg[i]->B = dmmg[i]->J;
665: jacobian = DMMGComputeJacobianWithMF;
666: PetscObjectReference((PetscObject) dmmg[i]->B);
667: }
668: #endif
669: }
670:
671: if (!useFAS) {
672: if (!dmmg[i]->B) {
673: DMGetMatrix(dmmg[i]->dm,dmmg[i]->mtype,&dmmg[i]->B);
674: }
675: if (!dmmg[i]->J) {
676: dmmg[i]->J = dmmg[i]->B;
677: PetscObjectReference((PetscObject) dmmg[i]->B);
678: }
679: }
681: DMMGSetUpLevel(dmmg,dmmg[i]->ksp,i+1);
682:
683: /*
684: if the number of levels is > 1 then we want the coarse solve in the grid sequencing to use LU
685: when possible
686: */
687: if (nlevels > 1 && i == 0) {
688: PC pc;
689: PetscMPIInt size;
690: MPI_Comm comm;
691: PetscBool flg1,flg2,flg3;
692: KSP cksp;
694: KSPGetPC(dmmg[i]->ksp,&pc);
695: PCMGGetCoarseSolve(pc,&cksp);
696: KSPGetPC(cksp,&pc);
697: PetscTypeCompare((PetscObject)pc,PCILU,&flg1);
698: PetscTypeCompare((PetscObject)pc,PCSOR,&flg2);
699: PetscTypeCompare((PetscObject)pc,PETSC_NULL,&flg3);
700: if (flg1 || flg2 || flg3) {
701: KSPSetType(dmmg[i]->ksp,KSPPREONLY);
702: PetscObjectGetComm((PetscObject) pc,&comm);
703: MPI_Comm_size(comm,&size);
704: if (size > 1) {
705: PCSetType(pc,PCREDUNDANT);
706: } else {
707: PCSetType(pc,PCLU);
708: }
709: }
710: }
712: dmmg[i]->computejacobian = jacobian;
713: if (useFAS) {
714: #if defined(PETSC_HAVE_ADIC)
715: if (fasBlock) {
716: dmmg[i]->solve = DMMGSolveFASb;
717: } else if(fasGMRES) {
718: dmmg[i]->solve = DMMGSolveFAS_NGMRES;
719: } else {
720: dmmg[i]->solve = DMMGSolveFAS4;
721: }
722: #else
723: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP, "Must use ADIC for structured FAS.");
724: #endif
725: } else {
726: dmmg[i]->solve = DMMGSolveSNES;
727: }
728: }
730: if (jacobian == DMMGComputeJacobianWithFD) {
731: ISColoring iscoloring;
733: for (i=0; i<nlevels; i++) {
734: if (dmmg[0]->getcoloringfrommat) {
735: MatGetColoring(dmmg[i]->B,(MatColoringType)MATCOLORINGSL,&iscoloring);
736: } else {
737: DMGetColoring(dmmg[i]->dm,dmmg[0]->isctype,dmmg[i]->mtype,&iscoloring);
738: }
739: MatFDColoringCreate(dmmg[i]->B,iscoloring,&dmmg[i]->fdcoloring);
740: ISColoringDestroy(&iscoloring);
741: if (function == DMMGFormFunction) function = DMMGFormFunctionFD;
742: MatFDColoringSetFunction(dmmg[i]->fdcoloring,(PetscErrorCode(*)(void))function,dmmg[i]);
743: MatFDColoringSetFromOptions(dmmg[i]->fdcoloring);
744: }
745: #if defined(PETSC_HAVE_ADIC)
746: } else if (jacobian == DMMGComputeJacobianWithAdic) {
747: for (i=0; i<nlevels; i++) {
748: ISColoring iscoloring;
749: DMGetColoring(dmmg[i]->dm,IS_COLORING_GHOSTED,dmmg[i]->mtype,&iscoloring);
750: MatSetColoring(dmmg[i]->B,iscoloring);
751: ISColoringDestroy(&iscoloring);
752: }
753: #endif
754: }
755: if (!useFAS) {
756: for (i=0; i<nlevels; i++) {
757: SNESSetJacobian(dmmg[i]->snes,dmmg[i]->J,dmmg[i]->B,DMMGComputeJacobian_Multigrid,dmmg);
758: }
759: }
761: /* Create interpolation scaling */
762: for (i=1; i<nlevels; i++) {
763: DMGetInterpolationScale(dmmg[i-1]->dm,dmmg[i]->dm,dmmg[i]->R,&dmmg[i]->Rscale);
764: }
766: if (useFAS) {
767: PetscBool flg;
769: for(i = 0; i < nlevels; i++) {
770: VecDuplicate(dmmg[i]->b,&dmmg[i]->w);
771: if (classid == DM_CLASSID) {
772: #if defined(PETSC_HAVE_ADIC)
773: NLFCreate_DAAD(&dmmg[i]->nlf);
774: NLFDAADSetDA_DAAD(dmmg[i]->nlf,dmmg[i]->dm);
775: NLFDAADSetCtx_DAAD(dmmg[i]->nlf,dmmg[i]->user);
776: NLFDAADSetResidual_DAAD(dmmg[i]->nlf,dmmg[i]->r);
777: NLFDAADSetNewtonIterations_DAAD(dmmg[i]->nlf,fasMaxIter);
778: #endif
779: } else {
780: }
782: dmmg[i]->monitor = monitor;
783: dmmg[i]->monitorall = monitorAll;
784: dmmg[i]->presmooth = fasPresmooth;
785: dmmg[i]->postsmooth = fasPostsmooth;
786: dmmg[i]->coarsesmooth = fasCoarsesmooth;
787: dmmg[i]->rtol = fasRtol;
788: dmmg[i]->abstol = fasAbstol;
789: }
791: flg = PETSC_FALSE;
792: PetscOptionsGetBool(0, "-dmmg_fas_view", &flg,PETSC_NULL);
793: if (flg) {
794: for(i = 0; i < nlevels; i++) {
795: if (i == 0) {
796: PetscPrintf(dmmg[i]->comm,"FAS Solver Parameters\n");
797: PetscPrintf(dmmg[i]->comm," rtol %G atol %G\n",dmmg[i]->rtol,dmmg[i]->abstol);
798: PetscPrintf(dmmg[i]->comm," coarsesmooths %D\n",dmmg[i]->coarsesmooth);
799: PetscPrintf(dmmg[i]->comm," Newton iterations %D\n",fasMaxIter);
800: } else {
801: PetscPrintf(dmmg[i]->comm," level %D presmooths %D\n",i,dmmg[i]->presmooth);
802: PetscPrintf(dmmg[i]->comm," postsmooths %D\n",dmmg[i]->postsmooth);
803: PetscPrintf(dmmg[i]->comm," Newton iterations %D\n",fasMaxIter);
804: }
805: if (fasBlock) {
806: PetscPrintf(dmmg[i]->comm," using point-block smoothing\n");
807: } else if(fasGMRES) {
808: PetscPrintf(dmmg[i]->comm," using non-linear gmres\n");
809: }
810: }
811: }
812: }
813: return(0);
814: }
818: /*@C
819: DMMGSetFromOptions - Sets various options associated with the DMMG object
821: This is being deprecated. Use KSPSetDM() for linear problems and SNESSetDM() for nonlinear problems.
822: See src/ksp/ksp/examples/tutorials/ex45.c and src/snes/examples/tutorials/ex57.c
824: Collective on DMMG
826: Input Parameter:
827: . dmmg - the context
830: Notes: this is currently only supported for use with DMMGSetSNES() NOT DMMGSetKSP()
832: Most options are checked in DMMGSetSNES(); this does call SNESSetFromOptions()
834: Level: advanced
836: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNESLocal(), DMMGSetSNES()
838: @*/
839: PetscErrorCode DMMGSetFromOptions(DMMG *dmmg)
840: {
841: PetscErrorCode ierr;
842: PetscInt i,nlevels = dmmg[0]->nlevels;
845: if (!dmmg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Passing null as DMMG");
847: for (i=0; i<nlevels; i++) {
848: SNESSetFromOptions(dmmg[i]->snes);
849: }
850: return(0);
851: }
855: /*@C
856: DMMGSetSNESLocalFD - Sets the local user function that is used to approximately compute the Jacobian
857: via finite differences.
859: This is being deprecated. Use KSPSetDM() for linear problems and SNESSetDM() for nonlinear problems.
860: See src/ksp/ksp/examples/tutorials/ex45.c and src/snes/examples/tutorials/ex57.c
862: Logically Collective on DMMG
864: Input Parameter:
865: + dmmg - the context
866: - function - the function that defines the nonlinear system
868: Level: intermediate
870: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGSetSNESLocal()
872: @*/
873: PetscErrorCode DMMGSetSNESLocalFD(DMMG *dmmg,DMDALocalFunction1 function)
874: {
875: PetscInt i,nlevels = dmmg[0]->nlevels;
878: for (i=0; i<nlevels; i++) {
879: dmmg[i]->lfj = (PetscErrorCode (*)(void))function;
880: }
881: return(0);
882: }
887: /*@C
888: DMMGGetSNESLocal - Returns the local functions for residual and Jacobian evaluation.
890: This is being deprecated. Use KSPSetDM() for linear problems and SNESSetDM() for nonlinear problems.
891: See src/ksp/ksp/examples/tutorials/ex45.c and src/snes/examples/tutorials/ex57.c
893: Not Collective
895: Input Parameter:
896: . dmmg - the context
898: Output Parameters:
899: + function - the function that defines the nonlinear system
900: - jacobian - function defines the local part of the Jacobian
902: Level: intermediate
904: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGSetSNESLocal()
905: @*/
906: PetscErrorCode DMMGGetSNESLocal(DMMG *dmmg,DMDALocalFunction1 *function, DMDALocalFunction1 *jacobian)
907: {
911: DMDAGetLocalFunction(dmmg[0]->dm, function);
912: DMDAGetLocalJacobian(dmmg[0]->dm, jacobian);
913: return(0);
914: }
916: /*MC
917: DMMGSetSNESLocal - Sets the local user function that defines the nonlinear set of equations
918: that will use the grid hierarchy and (optionally) its derivative.
920: Synopsis:
921: PetscErrorCode DMMGSetSNESLocal(DMMG *dmmg,DMDALocalFunction1 function, DMDALocalFunction1 jacobian,
922: DMDALocalFunction1 ad_function, DMDALocalFunction1 admf_function);
924: Logically Collective on DMMG
926: Input Parameter:
927: + dmmg - the context
928: . function - the function that defines the nonlinear system
929: . jacobian - function defines the local part of the Jacobian
930: . ad_function - the name of the function with an ad_ prefix. This is ignored currently
931: - admf_function - the name of the function with an ad_ prefix. This is ignored currently
933: Options Database Keys:
934: + -dmmg_jacobian_fd
935: . -dmmg_jacobian_ad
936: . -dmmg_jacobian_mf_fd_operator
937: . -dmmg_jacobian_mf_fd
938: . -dmmg_jacobian_mf_ad_operator
939: - -dmmg_jacobian_mf_ad
942: Level: intermediate
944: Notes:
945: If the Jacobian is not provided, this routine
946: uses finite differencing to approximate the Jacobian.
948: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES()
950: M*/
954: PetscErrorCode DMMGSetSNESLocal_Private(DMMG *dmmg,DMDALocalFunction1 function,DMDALocalFunction1 jacobian,DMDALocalFunction1 ad_function,DMDALocalFunction1 admf_function)
955: {
957: PetscInt i,nlevels = dmmg[0]->nlevels;
958: const char *typeName;
959: PetscBool ismesh;
960: PetscErrorCode (*computejacobian)(SNES,Vec,Mat*,Mat*,MatStructure*,void*) = 0;
964: if (jacobian) computejacobian = DMMGComputeJacobian;
965: #if defined(PETSC_HAVE_ADIC)
966: else if (ad_function) computejacobian = DMMGComputeJacobianWithAdic;
967: #endif
968: CHKMEMQ;
969: PetscObjectGetType((PetscObject) dmmg[0]->dm, &typeName);
970: PetscStrcmp(typeName, DMMESH, &ismesh);
971: if (ismesh) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP, "Unstructured grids no longer supported since DMMG will be phased out");
972: else {
973: PetscBool flag;
974: /* it makes no sense to use an option to decide on ghost, it depends on whether the
975: formfunctionlocal computes ghost values in F or not. */
976: PetscOptionsHasName(PETSC_NULL, "-dmmg_form_function_ghost", &flag);
977: if (flag) {
978: DMMGSetSNES(dmmg,DMMGFormFunctionGhost,computejacobian);
979: } else {
980: DMMGSetSNES(dmmg,DMMGFormFunction,computejacobian);
981: }
982: for (i=0; i<nlevels; i++) {
983: dmmg[i]->isctype = IS_COLORING_GHOSTED; /* switch to faster version since have local function evaluation */
984: DMDASetLocalFunction(dmmg[i]->dm,function);
985: dmmg[i]->lfj = (PetscErrorCode (*)(void))function;
986: DMDASetLocalJacobian(dmmg[i]->dm,jacobian);
987: DMDASetLocalAdicFunction(dmmg[i]->dm,ad_function);
988: DMDASetLocalAdicMFFunction(dmmg[i]->dm,admf_function);
989: }
990: }
991: CHKMEMQ;
992: return(0);
993: }
997: PetscErrorCode DMMGFunctioni(void* ctx,PetscInt i,Vec u,PetscScalar* r)
998: {
999: DMMG dmmg = (DMMG)ctx;
1000: Vec U = dmmg->lwork1;
1002: VecScatter gtol;
1005: /* copy u into interior part of U */
1006: DMDAGetScatter(dmmg->dm,0,>ol,0);
1007: VecScatterBegin(gtol,u,U,INSERT_VALUES,SCATTER_FORWARD_LOCAL);
1008: VecScatterEnd(gtol,u,U,INSERT_VALUES,SCATTER_FORWARD_LOCAL);
1009: DMDAFormFunctioni1(dmmg->dm,i,U,r,dmmg->user);
1010: return(0);
1011: }
1015: PetscErrorCode DMMGFunctionib(PetscInt i,Vec u,PetscScalar* r,void* ctx)
1016: {
1017: DMMG dmmg = (DMMG)ctx;
1018: Vec U = dmmg->lwork1;
1020: VecScatter gtol;
1023: /* copy u into interior part of U */
1024: DMDAGetScatter(dmmg->dm,0,>ol,0);
1025: VecScatterBegin(gtol,u,U,INSERT_VALUES,SCATTER_FORWARD_LOCAL);
1026: VecScatterEnd(gtol,u,U,INSERT_VALUES,SCATTER_FORWARD_LOCAL);
1027: DMDAFormFunctionib1(dmmg->dm,i,U,r,dmmg->user);
1028: return(0);
1029: }
1033: PetscErrorCode DMMGFunctioniBase(void* ctx,Vec u)
1034: {
1035: DMMG dmmg = (DMMG)ctx;
1036: Vec U = dmmg->lwork1;
1040: DMGlobalToLocalBegin(dmmg->dm,u,INSERT_VALUES,U);
1041: DMGlobalToLocalEnd(dmmg->dm,u,INSERT_VALUES,U);
1042: return(0);
1043: }
1047: PetscErrorCode DMMGSetSNESLocali_Private(DMMG *dmmg,PetscErrorCode (*functioni)(DMDALocalInfo*,MatStencil*,void*,PetscScalar*,void*),PetscErrorCode (*adi)(DMDALocalInfo*,MatStencil*,void*,void*,void*),PetscErrorCode (*adimf)(DMDALocalInfo*,MatStencil*,void*,void*,void*))
1048: {
1050: PetscInt i,nlevels = dmmg[0]->nlevels;
1053: for (i=0; i<nlevels; i++) {
1054: DMDASetLocalFunctioni(dmmg[i]->dm,functioni);
1055: DMDASetLocalAdicFunctioni(dmmg[i]->dm,adi);
1056: DMDASetLocalAdicMFFunctioni(dmmg[i]->dm,adimf);
1057: MatMFFDSetFunctioni(dmmg[i]->J,DMMGFunctioni);
1058: MatMFFDSetFunctioniBase(dmmg[i]->J,DMMGFunctioniBase);
1059: if (!dmmg[i]->lwork1) {
1060: DMCreateLocalVector(dmmg[i]->dm,&dmmg[i]->lwork1);
1061: }
1062: }
1063: return(0);
1064: }
1068: PetscErrorCode DMMGSetSNESLocalib_Private(DMMG *dmmg,PetscErrorCode (*functioni)(DMDALocalInfo*,MatStencil*,void*,PetscScalar*,void*),PetscErrorCode (*adi)(DMDALocalInfo*,MatStencil*,void*,void*,void*),PetscErrorCode (*adimf)(DMDALocalInfo*,MatStencil*,void*,void*,void*))
1069: {
1071: PetscInt i,nlevels = dmmg[0]->nlevels;
1074: for (i=0; i<nlevels; i++) {
1075: DMDASetLocalFunctionib(dmmg[i]->dm,functioni);
1076: DMDASetLocalAdicFunctionib(dmmg[i]->dm,adi);
1077: DMDASetLocalAdicMFFunctionib(dmmg[i]->dm,adimf);
1078: if (!dmmg[i]->lwork1) {
1079: DMCreateLocalVector(dmmg[i]->dm,&dmmg[i]->lwork1);
1080: }
1081: }
1082: return(0);
1083: }
1085: static PetscErrorCode (*localfunc)(void) = 0;
1089: /*
1090: Uses the DM object to call the user provided function with the correct calling
1091: sequence.
1092: */
1093: PetscErrorCode DMMGInitialGuess_Local(DMMG dmmg,Vec x)
1094: {
1098: (*dmmg->dm->ops->forminitialguess)(dmmg->dm,localfunc,x,0);
1099: return(0);
1100: }
1104: /*@C
1105: DMMGSetInitialGuessLocal - sets code to compute the initial guess for each level
1107: This is being deprecated. Use KSPSetDM() for linear problems and SNESSetDM() for nonlinear problems.
1108: See src/ksp/ksp/examples/tutorials/ex45.c and src/snes/examples/tutorials/ex57.c
1110: Logically Collective on DMMG
1112: Input Parameter:
1113: + dmmg - the context
1114: - localguess - the function that computes the initial guess
1116: Level: intermediate
1118: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGSetInitialGuess(), DMMGSetSNESLocal()
1120: @*/
1121: PetscErrorCode DMMGSetInitialGuessLocal(DMMG *dmmg,PetscErrorCode (*localguess)(void))
1122: {
1126: localfunc = localguess; /* stash into ugly static for now */
1128: DMMGSetInitialGuess(dmmg,DMMGInitialGuess_Local);
1129: return(0);
1130: }
1134: /*@C
1135: DMMGSetISColoringType - type of coloring used to compute Jacobian via finite differencing
1137: This is being deprecated. Use KSPSetDM() for linear problems and SNESSetDM() for nonlinear problems.
1138: See src/ksp/ksp/examples/tutorials/ex45.c and src/snes/examples/tutorials/ex57.c
1140: Logically Collective on DMMG
1142: Input Parameter:
1143: + dmmg - the context
1144: - isctype - IS_COLORING_GHOSTED (default) or IS_COLORING_GLOBAL
1146: Options Database:
1147: . -dmmg_iscoloring_type <ghosted or global>
1149: Notes: ghosted coloring requires using DMMGSetSNESLocal()
1151: Level: intermediate
1153: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGSetInitialGuess(), DMMGSetSNESLocal()
1155: @*/
1156: PetscErrorCode DMMGSetISColoringType(DMMG *dmmg,ISColoringType isctype)
1157: {
1159: dmmg[0]->isctype = isctype;
1160: return(0);
1161: }
1166: /*@C
1167: DMMGSetUp - Called after DMMGSetSNES() and (optionally) DMMGSetFromOptions()
1169: This is being deprecated. Use KSPSetDM() for linear problems and SNESSetDM() for nonlinear problems.
1170: See src/ksp/ksp/examples/tutorials/ex45.c and src/snes/examples/tutorials/ex57.c
1172: Collective on DMMG
1174: Input Parameter:
1175: . dmmg - the context
1177: Notes: Currently this must be called by the user (if they want to).
1179: Level: advanced
1181: .seealso DMMGCreate(), DMMGDestroy(), DMMG, DMMGSetSNES(), DMMGSetKSP(), DMMGSolve(), DMMGSetMatType()
1183: @*/
1184: PetscErrorCode DMMGSetUp(DMMG *dmmg)
1185: {
1187: KSP ksp;
1188: SNES snes;
1189: PC pc;
1192: snes = DMMGGetSNES(dmmg);
1193: if (snes) {
1194: SNESGetKSP(snes,&ksp);
1195: } else {
1196: ksp = DMMGGetKSP(dmmg);
1197: }
1198: KSPGetPC(ksp,&pc);
1199: PCSetDM(pc,DMMGGetDM(dmmg));
1200: return(0);
1201: }