Actual source code: damgsnes.c
1: #define PETSCSNES_DLL
2:
3: #include petscda.h
4: #include private/daimpl.h
5: /* It appears that preprocessor directives are not respected by bfort */
6: #ifdef PETSC_HAVE_SIEVE
7: #include petscmesh.h
8: #endif
9: #include petscmg.h
10: #include petscdmmg.h
12: #if defined(PETSC_HAVE_ADIC)
19: #endif
20: #if defined(PETSC_HAVE_SIEVE)
22: #endif
25: EXTERN PetscErrorCode NLFCreate_DAAD(NLF*);
26: EXTERN PetscErrorCode NLFDAADSetDA_DAAD(NLF,DA);
27: EXTERN PetscErrorCode NLFDAADSetCtx_DAAD(NLF,void*);
28: EXTERN PetscErrorCode NLFDAADSetResidual_DAAD(NLF,Vec);
29: EXTERN PetscErrorCode NLFDAADSetNewtonIterations_DAAD(NLF,PetscInt);
32: /*
33: period of -1 indicates update only on zeroth iteration of SNES
34: */
35: #define ShouldUpdate(l,it) (((dmmg[l-1]->updatejacobianperiod == -1) && (it == 0)) || \
36: ((dmmg[l-1]->updatejacobianperiod > 0) && !(it % dmmg[l-1]->updatejacobianperiod)))
37: /*
38: Evaluates the Jacobian on all of the grids. It is used by DMMG to provide the
39: ComputeJacobian() function that SNESSetJacobian() requires.
40: */
43: PetscErrorCode DMMGComputeJacobian_Multigrid(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
44: {
45: DMMG *dmmg = (DMMG*)ptr;
47: PetscInt i,nlevels = dmmg[0]->nlevels,it;
48: KSP ksp,lksp;
49: PC pc;
50: PetscTruth ismg,galerkin = PETSC_FALSE;
51: Vec W;
52: MatStructure flg;
55: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as user context which should contain DMMG");
56: SNESGetIterationNumber(snes,&it);
58: /* compute Jacobian on finest grid */
59: if (dmmg[nlevels-1]->updatejacobian && ShouldUpdate(nlevels,it)) {
60: (*DMMGGetFine(dmmg)->computejacobian)(snes,X,J,B,flag,DMMGGetFine(dmmg));
61: } else {
62: PetscInfo3(0,"Skipping Jacobian, SNES iteration %D frequence %D level %D\n",it,dmmg[nlevels-1]->updatejacobianperiod,nlevels-1);
63: *flag = SAME_PRECONDITIONER;
64: }
65: MatMFFDSetBase(DMMGGetFine(dmmg)->J,X,PETSC_NULL);
67: /* create coarser grid Jacobians for preconditioner if multigrid is the preconditioner */
68: SNESGetKSP(snes,&ksp);
69: KSPGetPC(ksp,&pc);
70: PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
71: if (ismg) {
72: PCMGGetGalerkin(pc,&galerkin);
73: }
75: if (!galerkin) {
76: for (i=nlevels-1; i>0; i--) {
77: if (!dmmg[i-1]->w) {
78: VecDuplicate(dmmg[i-1]->x,&dmmg[i-1]->w);
79: }
80: W = dmmg[i-1]->w;
81: /* restrict X to coarser grid */
82: MatRestrict(dmmg[i]->R,X,W);
83: X = W;
84: /* scale to "natural" scaling for that grid */
85: VecPointwiseMult(X,X,dmmg[i]->Rscale);
86: /* tell the base vector for matrix free multiplies */
87: MatMFFDSetBase(dmmg[i-1]->J,X,PETSC_NULL);
88: /* compute Jacobian on coarse grid */
89: if (dmmg[i-1]->updatejacobian && ShouldUpdate(i,it)) {
90: (*dmmg[i-1]->computejacobian)(snes,X,&dmmg[i-1]->J,&dmmg[i-1]->B,&flg,dmmg[i-1]);
91: flg = SAME_NONZERO_PATTERN;
92: } else {
93: PetscInfo3(0,"Skipping Jacobian, SNES iteration %D frequence %D level %D\n",it,dmmg[i-1]->updatejacobianperiod,i-1);
94: flg = SAME_PRECONDITIONER;
95: }
96: if (ismg) {
97: PCMGGetSmoother(pc,i-1,&lksp);
98: KSPSetOperators(lksp,dmmg[i-1]->J,dmmg[i-1]->B,flg);
99: }
100: }
101: }
102: return(0);
103: }
105: /* ---------------------------------------------------------------------------*/
110: /*
111: DMMGFormFunction - This is a universal global FormFunction used by the DMMG code
112: when the user provides a local function.
114: Input Parameters:
115: + snes - the SNES context
116: . X - input vector
117: - ptr - optional user-defined context, as set by SNESSetFunction()
119: Output Parameter:
120: . F - function vector
122: */
123: PetscErrorCode DMMGFormFunction(SNES snes,Vec X,Vec F,void *ptr)
124: {
125: DMMG dmmg = (DMMG)ptr;
127: Vec localX;
128: DA da = (DA)dmmg->dm;
131: DAGetLocalVector(da,&localX);
132: /*
133: Scatter ghost points to local vector, using the 2-step process
134: DAGlobalToLocalBegin(), DAGlobalToLocalEnd().
135: */
136: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
137: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
138: DAFormFunction1(da,localX,F,dmmg->user);
139: DARestoreLocalVector(da,&localX);
140: return(0);
141: }
145: PetscErrorCode DMMGFormFunctionGhost(SNES snes,Vec X,Vec F,void *ptr)
146: {
147: DMMG dmmg = (DMMG)ptr;
149: Vec localX, localF;
150: DA da = (DA)dmmg->dm;
153: DAGetLocalVector(da,&localX);
154: DAGetLocalVector(da,&localF);
155: /*
156: Scatter ghost points to local vector, using the 2-step process
157: DAGlobalToLocalBegin(), DAGlobalToLocalEnd().
158: */
159: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
160: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
161: VecSet(F, 0.0);
162: VecSet(localF, 0.0);
163: DAFormFunction1(da,localX,localF,dmmg->user);
164: DALocalToGlobalBegin(da,localF,F);
165: DALocalToGlobalEnd(da,localF,F);
166: DARestoreLocalVector(da,&localX);
167: DARestoreLocalVector(da,&localF);
168: return(0);
169: }
171: #ifdef PETSC_HAVE_SIEVE
174: /*
175: DMMGFormFunctionMesh - This is a universal global FormFunction used by the DMMG code
176: when the user provides a local function.
178: Input Parameters:
179: + snes - the SNES context
180: . X - input vector
181: - ptr - This is the DMMG object
183: Output Parameter:
184: . F - function vector
186: */
187: PetscErrorCode DMMGFormFunctionMesh(SNES snes, Vec X, Vec F, void *ptr)
188: {
189: DMMG dmmg = (DMMG) ptr;
190: Mesh mesh = (Mesh) dmmg->dm;
191: SectionReal sectionF, section;
195: MeshGetSectionReal(mesh, "default", §ion);
196: SectionRealDuplicate(section, §ionF);
197: SectionRealToVec(section, mesh, SCATTER_REVERSE, X);
198: MeshFormFunction(mesh, section, sectionF, dmmg->user);
199: SectionRealToVec(sectionF, mesh, SCATTER_FORWARD, F);
200: SectionRealDestroy(sectionF);
201: SectionRealDestroy(section);
202: return(0);
203: }
207: /*
208: DMMGComputeJacobianMesh - This is a universal global FormJacobian used by the DMMG code
209: when the user provides a local function.
211: Input Parameters:
212: + snes - the SNES context
213: . X - input vector
214: - ptr - This is the DMMG object
216: Output Parameter:
217: . F - function vector
219: */
220: PetscErrorCode DMMGComputeJacobianMesh(SNES snes, Vec X, Mat *J, Mat *B, MatStructure *flag, void *ptr)
221: {
222: DMMG dmmg = (DMMG) ptr;
223: Mesh mesh = (Mesh) dmmg->dm;
224: SectionReal sectionX;
228: MeshGetSectionReal(mesh, "default", §ionX);
229: SectionRealToVec(sectionX, mesh, SCATTER_REVERSE, X);
230: MeshFormJacobian(mesh, sectionX, *B, dmmg->user);
231: /* Assemble true Jacobian; if it is different */
232: if (*J != *B) {
233: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
234: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
235: }
236: MatSetOption(*B, MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);
237: *flag = SAME_NONZERO_PATTERN;
238: SectionRealDestroy(sectionX);
239: return(0);
240: }
241: #endif
245: /*
246: DMMGFormFunctionFD - This is a universal global FormFunction used by the DMMG code
247: when the user provides a local function used to compute the Jacobian via FD.
249: Input Parameters:
250: + snes - the SNES context
251: . X - input vector
252: - ptr - optional user-defined context, as set by SNESSetFunction()
254: Output Parameter:
255: . F - function vector
257: */
258: PetscErrorCode DMMGFormFunctionFD(SNES snes,Vec X,Vec F,void *ptr)
259: {
260: DMMG dmmg = (DMMG)ptr;
262: Vec localX;
263: DA da = (DA)dmmg->dm;
264: PetscInt N,n;
265:
267: /* determine whether X=localX */
268: DAGetLocalVector(da,&localX);
269: VecGetSize(X,&N);
270: VecGetSize(localX,&n);
272: if (n != N){ /* X != localX */
273: /* Scatter ghost points to local vector, using the 2-step process
274: DAGlobalToLocalBegin(), DAGlobalToLocalEnd().
275: */
276: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
277: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
278: } else {
279: DARestoreLocalVector(da,&localX);
280: localX = X;
281: }
282: DAFormFunction(da,dmmg->lfj,localX,F,dmmg->user);
283: if (n != N){
284: DARestoreLocalVector(da,&localX);
285: }
286: return(0);
287: }
291: /*@C
292: SNESDAFormFunction - This is a universal function evaluation routine that
293: may be used with SNESSetFunction() as long as the user context has a DA
294: as its first record and the user has called DASetLocalFunction().
296: Collective on SNES
298: Input Parameters:
299: + snes - the SNES context
300: . X - input vector
301: . F - function vector
302: - ptr - pointer to a structure that must have a DA as its first entry. For example this
303: could be a DMMG, this ptr must have been passed into SNESDAFormFunction() as the context
305: Level: intermediate
307: .seealso: DASetLocalFunction(), DASetLocalJacobian(), DASetLocalAdicFunction(), DASetLocalAdicMFFunction(),
308: SNESSetFunction(), SNESSetJacobian()
310: @*/
311: PetscErrorCode SNESDAFormFunction(SNES snes,Vec X,Vec F,void *ptr)
312: {
314: Vec localX;
315: DA da = *(DA*)ptr;
316: PetscInt N,n;
317:
319: if (!da) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Looks like you called SNESSetFromFuntion(snes,SNESDAFormFunction,) without the DA context");
321: /* determine whether X=localX */
322: DAGetLocalVector(da,&localX);
323: VecGetSize(X,&N);
324: VecGetSize(localX,&n);
325:
326:
327: if (n != N){ /* X != localX */
328: /* Scatter ghost points to local vector, using the 2-step process
329: DAGlobalToLocalBegin(), DAGlobalToLocalEnd().
330: */
331: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
332: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
333: } else {
334: DARestoreLocalVector(da,&localX);
335: localX = X;
336: }
337: DAFormFunction1(da,localX,F,ptr);
338: if (n != N){
339: if (PetscExceptionValue(ierr)) {
340: PetscErrorCode pDARestoreLocalVector(da,&localX);CHKERRQ(pierr);
341: }
342:
343: DARestoreLocalVector(da,&localX);
344: }
345: return(0);
346: }
348: /* ------------------------------------------------------------------------------*/
349: #include private/matimpl.h
352: PetscErrorCode DMMGComputeJacobianWithFD(SNES snes,Vec x1,Mat *J,Mat *B,MatStructure *flag,void *ctx)
353: {
355: DMMG dmmg = (DMMG)ctx;
356: MatFDColoring color = (MatFDColoring)dmmg->fdcoloring;
357:
359: if (color->ctype == IS_COLORING_GHOSTED){
360: DA da=(DA)dmmg->dm;
361: Vec x1_loc;
362: DAGetLocalVector(da,&x1_loc);
363: DAGlobalToLocalBegin(da,x1,INSERT_VALUES,x1_loc);
364: DAGlobalToLocalEnd(da,x1,INSERT_VALUES,x1_loc);
365: SNESDefaultComputeJacobianColor(snes,x1_loc,J,B,flag,dmmg->fdcoloring);
366: DARestoreLocalVector(da,&x1_loc);
367: } else {
368: SNESDefaultComputeJacobianColor(snes,x1,J,B,flag,dmmg->fdcoloring);
369: }
370: return(0);
371: }
375: PetscErrorCode DMMGComputeJacobianWithMF(SNES snes,Vec x1,Mat *J,Mat *B,MatStructure *flag,void *ctx)
376: {
378:
380: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
381: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
382: return(0);
383: }
387: /*
388: DMMGComputeJacobian - Evaluates the Jacobian when the user has provided
389: a local function evaluation routine.
390: */
391: PetscErrorCode DMMGComputeJacobian(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
392: {
393: DMMG dmmg = (DMMG) ptr;
395: Vec localX;
396: DA da = (DA) dmmg->dm;
399: DAGetLocalVector(da,&localX);
400: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
401: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
402: DAComputeJacobian1(da,localX,*B,dmmg->user);
403: DARestoreLocalVector(da,&localX);
404: /* Assemble true Jacobian; if it is different */
405: if (*J != *B) {
406: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
407: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
408: }
409: MatSetOption(*B,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);
410: *flag = SAME_NONZERO_PATTERN;
411: return(0);
412: }
416: /*
417: SNESDAComputeJacobianWithAdifor - This is a universal Jacobian evaluation routine
418: that may be used with SNESSetJacobian() from Fortran as long as the user context has
419: a DA as its first record and DASetLocalAdiforFunction() has been called.
421: Collective on SNES
423: Input Parameters:
424: + snes - the SNES context
425: . X - input vector
426: . J - Jacobian
427: . B - Jacobian used in preconditioner (usally same as J)
428: . flag - indicates if the matrix changed its structure
429: - ptr - optional user-defined context, as set by SNESSetFunction()
431: Level: intermediate
433: .seealso: DASetLocalFunction(), DASetLocalAdicFunction(), SNESSetFunction(), SNESSetJacobian()
435: */
436: PetscErrorCode SNESDAComputeJacobianWithAdifor(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
437: {
438: DA da = *(DA*) ptr;
440: Vec localX;
443: DAGetLocalVector(da,&localX);
444: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
445: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
446: DAComputeJacobian1WithAdifor(da,localX,*B,ptr);
447: DARestoreLocalVector(da,&localX);
448: /* Assemble true Jacobian; if it is different */
449: if (*J != *B) {
450: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
451: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
452: }
453: MatSetOption(*B,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);
454: *flag = SAME_NONZERO_PATTERN;
455: return(0);
456: }
460: /*
461: SNESDAComputeJacobian - This is a universal Jacobian evaluation routine for a
462: locally provided Jacobian.
464: Collective on SNES
466: Input Parameters:
467: + snes - the SNES context
468: . X - input vector
469: . J - Jacobian
470: . B - Jacobian used in preconditioner (usally same as J)
471: . flag - indicates if the matrix changed its structure
472: - ptr - optional user-defined context, as set by SNESSetFunction()
474: Level: intermediate
476: .seealso: DASetLocalFunction(), DASetLocalJacobian(), SNESSetFunction(), SNESSetJacobian()
478: */
479: PetscErrorCode SNESDAComputeJacobian(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
480: {
481: DA da = *(DA*) ptr;
483: Vec localX;
486: DAGetLocalVector(da,&localX);
487: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
488: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
489: DAComputeJacobian1(da,localX,*B,ptr);
490: DARestoreLocalVector(da,&localX);
491: /* Assemble true Jacobian; if it is different */
492: if (*J != *B) {
493: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
494: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
495: }
496: MatSetOption(*B,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);
497: *flag = SAME_NONZERO_PATTERN;
498: return(0);
499: }
503: PetscErrorCode DMMGSolveSNES(DMMG *dmmg,PetscInt level)
504: {
506: PetscInt nlevels = dmmg[0]->nlevels;
509: dmmg[0]->nlevels = level+1;
510: SNESSolve(dmmg[level]->snes,PETSC_NULL,dmmg[level]->x);
511: dmmg[0]->nlevels = nlevels;
512: return(0);
513: }
515: /* ===========================================================================================================*/
519: /*@C
520: DMMGSetSNES - Sets the nonlinear function that defines the nonlinear set of equations
521: to be solved using the grid hierarchy.
523: Collective on DMMG
525: Input Parameter:
526: + dmmg - the context
527: . function - the function that defines the nonlinear system
528: - jacobian - optional function to compute Jacobian
530: Options Database Keys:
531: + -snes_monitor
532: . -dmmg_coloring_from_mat - use graph coloring on the actual matrix nonzero structure instead of getting the coloring from the DM
533: . -dmmg_jacobian_fd
534: . -dmmg_jacobian_ad
535: . -dmmg_jacobian_mf_fd_operator
536: . -dmmg_jacobian_mf_fd
537: . -dmmg_jacobian_mf_ad_operator
538: . -dmmg_jacobian_mf_ad
539: . -dmmg_iscoloring_type
540: -
541: The period at which the Jacobian is recomputed can be set differently for different levels
542: of the Jacobian (for example lag all Jacobians except on the finest level).
543: There is no user interface currently for setting a different period on the different levels, one must set the
544: fields dmmg[i]->updatejacobian and dmmg[i]->updatejacobianperiod directly in the DMMG data structure.
545:
547: Level: advanced
549: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNESLocal(), DMMGSetFromOptions()
551: @*/
552: PetscErrorCode DMMGSetSNES(DMMG *dmmg,PetscErrorCode (*function)(SNES,Vec,Vec,void*),PetscErrorCode (*jacobian)(SNES,Vec,Mat*,Mat*,MatStructure*,void*))
553: {
554: PetscErrorCode ierr;
555: PetscInt i,nlevels = dmmg[0]->nlevels;
556: PetscTruth mffdoperator,mffd,fdjacobian;
557: PetscTruth useFAS = PETSC_FALSE, fasBlock=PETSC_FALSE, fasGMRES=PETSC_FALSE;
558: PetscTruth monitor, monitorAll;
559: PetscInt fasPresmooth = 1, fasPostsmooth = 1, fasCoarsesmooth = 1, fasMaxIter = 2;
560: PetscReal fasRtol = 1.0e-8, fasAbstol = 1.0e-50;
561: #if defined(PETSC_HAVE_ADIC)
562: PetscTruth mfadoperator,mfad,adjacobian;
563: #endif
564: PetscCookie cookie;
567: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
568: if (!jacobian) jacobian = DMMGComputeJacobianWithFD;
569: PetscObjectGetCookie((PetscObject) dmmg[0]->dm, &cookie);
571: PetscOptionsBegin(dmmg[0]->comm,dmmg[0]->prefix,"DMMG Options","SNES");
572: PetscOptionsName("-dmmg_monitor","Monitor DMMG iterations","DMMG",&monitor);
573: PetscOptionsName("-dmmg_monitor_all","Monitor DMMG iterations","DMMG",&monitorAll);
574: /*
575: PetscOptionsTruth("-dmmg_fas","Use the Full Approximation Scheme","DMMGSetSNES",useFAS,&useFAS,PETSC_NULL);
576: PetscOptionsName("-dmmg_fas_block","Use point-block smoothing","DMMG",&fasBlock);
577: PetscOptionsName("-dmmg_fas_ngmres","Use Nonlinear GMRES","DMMG",&fasGMRES);
578: PetscOptionsInt("-dmmg_fas_presmooth","Number of downward smoother iterates","DMMG",fasPresmooth,&fasPresmooth,PETSC_NULL);
579: PetscOptionsInt("-dmmg_fas_postsmooth","Number of upward smoother iterates","DMMG",fasPostsmooth,&fasPostsmooth,PETSC_NULL);
580: PetscOptionsInt("-dmmg_fas_coarsesmooth","Number of coarse smoother iterates","DMMG",fasCoarsesmooth,&fasCoarsesmooth,PETSC_NULL);
581: PetscOptionsReal("-dmmg_fas_rtol","Relative tolerance for FAS","DMMG",fasRtol,&fasRtol,PETSC_NULL);
582: PetscOptionsReal("-dmmg_fas_atol","Absolute tolerance for FAS","DMMG",fasAbstol,&fasAbstol,PETSC_NULL);
583: PetscOptionsInt("-dmmg_fas_max_its","Maximum number of iterates per smoother","DMMG",fasMaxIter,&fasMaxIter,PETSC_NULL);
584: */
586: PetscOptionsTruth("-dmmg_coloring_from_mat","Compute the coloring directly from the matrix nonzero structure","DMMGSetSNES",dmmg[0]->getcoloringfrommat,&dmmg[0]->getcoloringfrommat,PETSC_NULL);
588: PetscOptionsName("-dmmg_jacobian_fd","Compute sparse Jacobian explicitly with finite differencing","DMMGSetSNES",&fdjacobian);
589: if (fdjacobian) jacobian = DMMGComputeJacobianWithFD;
590: #if defined(PETSC_HAVE_ADIC)
591: PetscOptionsName("-dmmg_jacobian_ad","Compute sparse Jacobian explicitly with ADIC (automatic differentiation)","DMMGSetSNES",&adjacobian);
592: if (adjacobian) jacobian = DMMGComputeJacobianWithAdic;
593: #endif
595: PetscOptionsTruthGroupBegin("-dmmg_jacobian_mf_fd_operator","Apply Jacobian via matrix free finite differencing","DMMGSetSNES",&mffdoperator);
596: PetscOptionsTruthGroupEnd("-dmmg_jacobian_mf_fd","Apply Jacobian via matrix free finite differencing even in computing preconditioner","DMMGSetSNES",&mffd);
597: if (mffd) mffdoperator = PETSC_TRUE;
598: #if defined(PETSC_HAVE_ADIC)
599: PetscOptionsTruthGroupBegin("-dmmg_jacobian_mf_ad_operator","Apply Jacobian via matrix free ADIC (automatic differentiation)","DMMGSetSNES",&mfadoperator);
600: PetscOptionsTruthGroupEnd("-dmmg_jacobian_mf_ad","Apply Jacobian via matrix free ADIC (automatic differentiation) even in computing preconditioner","DMMGSetSNES",&mfad);
601: if (mfad) mfadoperator = PETSC_TRUE;
602: #endif
603: PetscOptionsEnum("-dmmg_iscoloring_type","Type of ISColoring","None",ISColoringTypes,(PetscEnum)dmmg[0]->isctype,(PetscEnum*)&dmmg[0]->isctype,PETSC_NULL);
604:
605: PetscOptionsEnd();
607: /* create solvers for each level */
608: for (i=0; i<nlevels; i++) {
609: SNESCreate(dmmg[i]->comm,&dmmg[i]->snes);
610: PetscObjectIncrementTabLevel((PetscObject)dmmg[i]->snes,PETSC_NULL,nlevels - i - 1);
611: SNESSetFunction(dmmg[i]->snes,dmmg[i]->b,function,dmmg[i]);
612: SNESSetOptionsPrefix(dmmg[i]->snes,dmmg[i]->prefix);
613: SNESGetKSP(dmmg[i]->snes,&dmmg[i]->ksp);
615: if (mffdoperator) {
616: MatCreateSNESMF(dmmg[i]->snes,&dmmg[i]->J);
617: VecDuplicate(dmmg[i]->x,&dmmg[i]->work1);
618: VecDuplicate(dmmg[i]->x,&dmmg[i]->work2);
619: MatMFFDSetFunction(dmmg[i]->J,(PetscErrorCode (*)(void*, Vec,Vec))SNESComputeFunction,dmmg[i]->snes);
620: if (mffd) {
621: dmmg[i]->B = dmmg[i]->J;
622: jacobian = DMMGComputeJacobianWithMF;
623: PetscObjectReference((PetscObject) dmmg[i]->B);
624: }
625: #if defined(PETSC_HAVE_ADIC)
626: } else if (mfadoperator) {
627: MatRegisterDAAD();
628: MatCreateDAAD((DA)dmmg[i]->dm,&dmmg[i]->J);
629: MatDAADSetCtx(dmmg[i]->J,dmmg[i]->user);
630: if (mfad) {
631: dmmg[i]->B = dmmg[i]->J;
632: jacobian = DMMGComputeJacobianWithMF;
633: PetscObjectReference((PetscObject) dmmg[i]->B);
634: }
635: #endif
636: }
637:
638: if (!useFAS) {
639: if (!dmmg[i]->B) {
640: DMGetMatrix(dmmg[i]->dm,dmmg[i]->mtype,&dmmg[i]->B);
641: }
642: if (!dmmg[i]->J) {
643: dmmg[i]->J = dmmg[i]->B;
644: PetscObjectReference((PetscObject) dmmg[i]->B);
645: }
646: }
648: DMMGSetUpLevel(dmmg,dmmg[i]->ksp,i+1);
649:
650: /*
651: if the number of levels is > 1 then we want the coarse solve in the grid sequencing to use LU
652: when possible
653: */
654: if (nlevels > 1 && i == 0) {
655: PC pc;
656: PetscMPIInt size;
657: MPI_Comm comm;
658: PetscTruth flg1,flg2,flg3;
659: KSP cksp;
661: KSPGetPC(dmmg[i]->ksp,&pc);
662: PCMGGetCoarseSolve(pc,&cksp);
663: KSPGetPC(cksp,&pc);
664: PetscTypeCompare((PetscObject)pc,PCILU,&flg1);
665: PetscTypeCompare((PetscObject)pc,PCSOR,&flg2);
666: PetscTypeCompare((PetscObject)pc,PETSC_NULL,&flg3);
667: if (flg1 || flg2 || flg3) {
668: KSPSetType(dmmg[i]->ksp,KSPPREONLY);
669: PetscObjectGetComm((PetscObject) pc,&comm);
670: MPI_Comm_size(comm,&size);
671: if (size > 1) {
672: PCSetType(pc,PCREDUNDANT);
673: } else {
674: PCSetType(pc,PCLU);
675: }
676: }
677: }
679: dmmg[i]->computejacobian = jacobian;
680: if (useFAS) {
681: if (cookie == DM_COOKIE) {
682: #if defined(PETSC_HAVE_ADIC)
683: if (fasBlock) {
684: dmmg[i]->solve = DMMGSolveFASb;
685: } else if(fasGMRES) {
686: dmmg[i]->solve = DMMGSolveFAS_NGMRES;
687: } else {
688: dmmg[i]->solve = DMMGSolveFAS4;
689: }
690: #else
691: SETERRQ(PETSC_ERR_SUP, "Must use ADIC for structured FAS.");
692: #endif
693: } else {
694: #if defined(PETSC_HAVE_SIEVE)
695: dmmg[i]->solve = DMMGSolveFAS_Mesh;
696: #endif
697: }
698: } else {
699: dmmg[i]->solve = DMMGSolveSNES;
700: }
701: }
703: if (jacobian == DMMGComputeJacobianWithFD) {
704: ISColoring iscoloring;
706: for (i=0; i<nlevels; i++) {
707: if (dmmg[0]->getcoloringfrommat) {
708: MatGetColoring(dmmg[i]->B,(MatColoringType)MATCOLORING_SL,&iscoloring);
709: } else {
710: DMGetColoring(dmmg[i]->dm,dmmg[0]->isctype,dmmg[i]->mtype,&iscoloring);
711: }
712: MatFDColoringCreate(dmmg[i]->B,iscoloring,&dmmg[i]->fdcoloring);
713: ISColoringDestroy(iscoloring);
714: if (function == DMMGFormFunction) function = DMMGFormFunctionFD;
715: MatFDColoringSetFunction(dmmg[i]->fdcoloring,(PetscErrorCode(*)(void))function,dmmg[i]);
716: MatFDColoringSetFromOptions(dmmg[i]->fdcoloring);
717: }
718: #if defined(PETSC_HAVE_ADIC)
719: } else if (jacobian == DMMGComputeJacobianWithAdic) {
720: for (i=0; i<nlevels; i++) {
721: ISColoring iscoloring;
722: DMGetColoring(dmmg[i]->dm,IS_COLORING_GHOSTED,dmmg[i]->mtype,&iscoloring);
723: MatSetColoring(dmmg[i]->B,iscoloring);
724: ISColoringDestroy(iscoloring);
725: }
726: #endif
727: }
728: if (!useFAS) {
729: for (i=0; i<nlevels; i++) {
730: SNESSetJacobian(dmmg[i]->snes,dmmg[i]->J,dmmg[i]->B,DMMGComputeJacobian_Multigrid,dmmg);
731: }
732: }
734: /* Create interpolation scaling */
735: for (i=1; i<nlevels; i++) {
736: DMGetInterpolationScale(dmmg[i-1]->dm,dmmg[i]->dm,dmmg[i]->R,&dmmg[i]->Rscale);
737: }
739: if (useFAS) {
740: PetscTruth flg;
742: for(i = 0; i < nlevels; i++) {
743: VecDuplicate(dmmg[i]->b,&dmmg[i]->w);
744: if (cookie == DM_COOKIE) {
745: #if defined(PETSC_HAVE_ADIC)
746: NLFCreate_DAAD(&dmmg[i]->nlf);
747: NLFDAADSetDA_DAAD(dmmg[i]->nlf,(DA)dmmg[i]->dm);
748: NLFDAADSetCtx_DAAD(dmmg[i]->nlf,dmmg[i]->user);
749: NLFDAADSetResidual_DAAD(dmmg[i]->nlf,dmmg[i]->r);
750: NLFDAADSetNewtonIterations_DAAD(dmmg[i]->nlf,fasMaxIter);
751: #endif
752: } else {
753: }
755: dmmg[i]->monitor = monitor;
756: dmmg[i]->monitorall = monitorAll;
757: dmmg[i]->presmooth = fasPresmooth;
758: dmmg[i]->postsmooth = fasPostsmooth;
759: dmmg[i]->coarsesmooth = fasCoarsesmooth;
760: dmmg[i]->rtol = fasRtol;
761: dmmg[i]->abstol = fasAbstol;
762: }
764: flg = PETSC_FALSE;
765: PetscOptionsGetTruth(0, "-dmmg_fas_view", &flg,PETSC_NULL);
766: if (flg) {
767: for(i = 0; i < nlevels; i++) {
768: if (i == 0) {
769: PetscPrintf(dmmg[i]->comm,"FAS Solver Parameters\n");
770: PetscPrintf(dmmg[i]->comm," rtol %G atol %G\n",dmmg[i]->rtol,dmmg[i]->abstol);
771: PetscPrintf(dmmg[i]->comm," coarsesmooths %D\n",dmmg[i]->coarsesmooth);
772: PetscPrintf(dmmg[i]->comm," Newton iterations %D\n",fasMaxIter);
773: } else {
774: PetscPrintf(dmmg[i]->comm," level %D presmooths %D\n",i,dmmg[i]->presmooth);
775: PetscPrintf(dmmg[i]->comm," postsmooths %D\n",dmmg[i]->postsmooth);
776: PetscPrintf(dmmg[i]->comm," Newton iterations %D\n",fasMaxIter);
777: }
778: if (fasBlock) {
779: PetscPrintf(dmmg[i]->comm," using point-block smoothing\n");
780: } else if(fasGMRES) {
781: PetscPrintf(dmmg[i]->comm," using non-linear gmres\n");
782: }
783: }
784: }
785: }
786: return(0);
787: }
791: /*@C
792: DMMGSetFromOptions - Sets various options associated with the DMMG object
794: Collective on DMMG
796: Input Parameter:
797: . dmmg - the context
800: Notes: this is currently only supported for use with DMMGSetSNES() NOT DMMGSetKSP()
802: Most options are checked in DMMGSetSNES(); this does call SNESSetFromOptions()
804: Level: advanced
806: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNESLocal(), DMMGSetSNES()
808: @*/
809: PetscErrorCode DMMGSetFromOptions(DMMG *dmmg)
810: {
811: PetscErrorCode ierr;
812: PetscInt i,nlevels = dmmg[0]->nlevels;
815: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
817: for (i=0; i<nlevels; i++) {
818: SNESSetFromOptions(dmmg[i]->snes);
819: }
820: return(0);
821: }
825: /*@C
826: DMMGSetSNESLocalFD - Sets the local user function that is used to approximately compute the Jacobian
827: via finite differences.
829: Collective on DMMG
831: Input Parameter:
832: + dmmg - the context
833: - function - the function that defines the nonlinear system
835: Level: intermediate
837: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGSetSNESLocal()
839: @*/
840: PetscErrorCode DMMGSetSNESLocalFD(DMMG *dmmg,DALocalFunction1 function)
841: {
842: PetscInt i,nlevels = dmmg[0]->nlevels;
845: for (i=0; i<nlevels; i++) {
846: dmmg[i]->lfj = (PetscErrorCode (*)(void))function;
847: }
848: return(0);
849: }
854: /*@C
855: DMMGGetSNESLocal - Returns the local functions for residual and Jacobian evaluation.
857: Collective on DMMG
859: Input Parameter:
860: . dmmg - the context
862: Output Parameters:
863: + function - the function that defines the nonlinear system
864: - jacobian - function defines the local part of the Jacobian
866: Level: intermediate
868: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGSetSNESLocal()
869: @*/
870: PetscErrorCode DMMGGetSNESLocal(DMMG *dmmg,DALocalFunction1 *function, DALocalFunction1 *jacobian)
871: {
872: PetscCookie cookie;
876: PetscObjectGetCookie((PetscObject) dmmg[0]->dm, &cookie);
877: if (cookie == DM_COOKIE) {
878: DAGetLocalFunction((DA) dmmg[0]->dm, function);
879: DAGetLocalJacobian((DA) dmmg[0]->dm, jacobian);
880: } else {
881: #ifdef PETSC_HAVE_SIEVE
882: MeshGetLocalFunction((Mesh) dmmg[0]->dm, (PetscErrorCode (**)(Mesh,SectionReal,SectionReal,void*)) function);
883: MeshGetLocalJacobian((Mesh) dmmg[0]->dm, (PetscErrorCode (**)(Mesh,SectionReal,Mat,void*)) jacobian);
884: #else
885: SETERRQ(PETSC_ERR_SUP, "Unstructured grids only supported when Sieve is enabled.\nReconfigure with --with-sieve.");
886: #endif
887: }
888: return(0);
889: }
891: /*MC
892: DMMGSetSNESLocal - Sets the local user function that defines the nonlinear set of equations
893: that will use the grid hierarchy and (optionally) its derivative.
895: Collective on DMMG
897: Synopsis:
898: PetscErrorCode DMMGSetSNESLocal(DMMG *dmmg,DALocalFunction1 function, DALocalFunction1 jacobian,
899: DALocalFunction1 ad_function, DALocalFunction1 admf_function);
901: Input Parameter:
902: + dmmg - the context
903: . function - the function that defines the nonlinear system
904: . jacobian - function defines the local part of the Jacobian
905: . ad_function - the name of the function with an ad_ prefix. This is ignored currently
906: - admf_function - the name of the function with an ad_ prefix. This is ignored currently
908: Options Database Keys:
909: + -dmmg_jacobian_fd
910: . -dmmg_jacobian_ad
911: . -dmmg_jacobian_mf_fd_operator
912: . -dmmg_jacobian_mf_fd
913: . -dmmg_jacobian_mf_ad_operator
914: - -dmmg_jacobian_mf_ad
917: Level: intermediate
919: Notes:
920: If the Jacobian is not provided, this routine
921: uses finite differencing to approximate the Jacobian.
923: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES()
925: M*/
929: PetscErrorCode DMMGSetSNESLocal_Private(DMMG *dmmg,DALocalFunction1 function,DALocalFunction1 jacobian,DALocalFunction1 ad_function,DALocalFunction1 admf_function)
930: {
932: PetscInt i,nlevels = dmmg[0]->nlevels;
933: PetscCookie cookie;
934: PetscErrorCode (*computejacobian)(SNES,Vec,Mat*,Mat*,MatStructure*,void*) = 0;
938: if (jacobian) computejacobian = DMMGComputeJacobian;
939: #if defined(PETSC_HAVE_ADIC)
940: else if (ad_function) computejacobian = DMMGComputeJacobianWithAdic;
941: #endif
942: CHKMEMQ;
943: PetscObjectGetCookie((PetscObject) dmmg[0]->dm,&cookie);
944: if (cookie == DM_COOKIE) {
945: PetscTruth flag;
946: /* it makes no sense to use an option to decide on ghost, it depends on whether the
947: formfunctionlocal computes ghost values in F or not. */
948: PetscOptionsHasName(PETSC_NULL, "-dmmg_form_function_ghost", &flag);
949: if (flag) {
950: DMMGSetSNES(dmmg,DMMGFormFunctionGhost,computejacobian);
951: } else {
952: DMMGSetSNES(dmmg,DMMGFormFunction,computejacobian);
953: }
954: for (i=0; i<nlevels; i++) {
955: dmmg[i]->isctype = IS_COLORING_GHOSTED; /* switch to faster version since have local function evaluation */
956: DASetLocalFunction((DA)dmmg[i]->dm,function);
957: dmmg[i]->lfj = (PetscErrorCode (*)(void))function;
958: DASetLocalJacobian((DA)dmmg[i]->dm,jacobian);
959: DASetLocalAdicFunction((DA)dmmg[i]->dm,ad_function);
960: DASetLocalAdicMFFunction((DA)dmmg[i]->dm,admf_function);
961: }
962: CHKMEMQ;
963: } else {
964: #ifdef PETSC_HAVE_SIEVE
965: DMMGSetSNES(dmmg, DMMGFormFunctionMesh, DMMGComputeJacobianMesh);
966: for (i=0; i<nlevels; i++) {
967: MeshSetLocalFunction((Mesh) dmmg[i]->dm, (PetscErrorCode (*)(Mesh,SectionReal,SectionReal,void*)) function);
968: dmmg[i]->lfj = (PetscErrorCode (*)(void)) function;
969: MeshSetLocalJacobian((Mesh) dmmg[i]->dm, (PetscErrorCode (*)(Mesh,SectionReal,Mat,void*)) jacobian);
970: // Setup a work section
971: SectionReal defaultSec, constantSec;
972: PetscTruth hasConstant;
974: MeshGetSectionReal((Mesh) dmmg[i]->dm, "default", &defaultSec);
975: MeshHasSectionReal((Mesh) dmmg[i]->dm, "constant", &hasConstant);
976: if (!hasConstant) {
977: SectionRealDuplicate(defaultSec, &constantSec);
978: PetscObjectSetName((PetscObject) constantSec, "constant");
979: MeshSetSectionReal((Mesh) dmmg[i]->dm, constantSec);
980: SectionRealDestroy(constantSec);
981: }
982: }
983: CHKMEMQ;
984: #else
985: SETERRQ(PETSC_ERR_SUP, "Unstructured grids only supported when Sieve is enabled.\nReconfigure with --with-sieve.");
986: #endif
987: }
988: CHKMEMQ;
989: return(0);
990: }
994: PetscErrorCode DMMGFunctioni(void* ctx,PetscInt i,Vec u,PetscScalar* r)
995: {
996: DMMG dmmg = (DMMG)ctx;
997: Vec U = dmmg->lwork1;
999: VecScatter gtol;
1002: /* copy u into interior part of U */
1003: DAGetScatter((DA)dmmg->dm,0,>ol,0);
1004: VecScatterBegin(gtol,u,U,INSERT_VALUES,SCATTER_FORWARD_LOCAL);
1005: VecScatterEnd(gtol,u,U,INSERT_VALUES,SCATTER_FORWARD_LOCAL);
1006: DAFormFunctioni1((DA)dmmg->dm,i,U,r,dmmg->user);
1007: return(0);
1008: }
1012: PetscErrorCode DMMGFunctionib(PetscInt i,Vec u,PetscScalar* r,void* ctx)
1013: {
1014: DMMG dmmg = (DMMG)ctx;
1015: Vec U = dmmg->lwork1;
1017: VecScatter gtol;
1020: /* copy u into interior part of U */
1021: DAGetScatter((DA)dmmg->dm,0,>ol,0);
1022: VecScatterBegin(gtol,u,U,INSERT_VALUES,SCATTER_FORWARD_LOCAL);
1023: VecScatterEnd(gtol,u,U,INSERT_VALUES,SCATTER_FORWARD_LOCAL);
1024: DAFormFunctionib1((DA)dmmg->dm,i,U,r,dmmg->user);
1025: return(0);
1026: }
1030: PetscErrorCode DMMGFunctioniBase(void* ctx,Vec u)
1031: {
1032: DMMG dmmg = (DMMG)ctx;
1033: Vec U = dmmg->lwork1;
1037: DAGlobalToLocalBegin((DA)dmmg->dm,u,INSERT_VALUES,U);
1038: DAGlobalToLocalEnd((DA)dmmg->dm,u,INSERT_VALUES,U);
1039: return(0);
1040: }
1044: PetscErrorCode DMMGSetSNESLocali_Private(DMMG *dmmg,PetscErrorCode (*functioni)(DALocalInfo*,MatStencil*,void*,PetscScalar*,void*),PetscErrorCode (*adi)(DALocalInfo*,MatStencil*,void*,void*,void*),PetscErrorCode (*adimf)(DALocalInfo*,MatStencil*,void*,void*,void*))
1045: {
1047: PetscInt i,nlevels = dmmg[0]->nlevels;
1050: for (i=0; i<nlevels; i++) {
1051: DASetLocalFunctioni((DA)dmmg[i]->dm,functioni);
1052: DASetLocalAdicFunctioni((DA)dmmg[i]->dm,adi);
1053: DASetLocalAdicMFFunctioni((DA)dmmg[i]->dm,adimf);
1054: MatMFFDSetFunctioni(dmmg[i]->J,DMMGFunctioni);
1055: MatMFFDSetFunctioniBase(dmmg[i]->J,DMMGFunctioniBase);
1056: if (!dmmg[i]->lwork1) {
1057: DACreateLocalVector((DA)dmmg[i]->dm,&dmmg[i]->lwork1);
1058: }
1059: }
1060: return(0);
1061: }
1065: PetscErrorCode DMMGSetSNESLocalib_Private(DMMG *dmmg,PetscErrorCode (*functioni)(DALocalInfo*,MatStencil*,void*,PetscScalar*,void*),PetscErrorCode (*adi)(DALocalInfo*,MatStencil*,void*,void*,void*),PetscErrorCode (*adimf)(DALocalInfo*,MatStencil*,void*,void*,void*))
1066: {
1068: PetscInt i,nlevels = dmmg[0]->nlevels;
1071: for (i=0; i<nlevels; i++) {
1072: DASetLocalFunctionib((DA)dmmg[i]->dm,functioni);
1073: DASetLocalAdicFunctionib((DA)dmmg[i]->dm,adi);
1074: DASetLocalAdicMFFunctionib((DA)dmmg[i]->dm,adimf);
1075: if (!dmmg[i]->lwork1) {
1076: DACreateLocalVector((DA)dmmg[i]->dm,&dmmg[i]->lwork1);
1077: }
1078: }
1079: return(0);
1080: }
1082: static PetscErrorCode (*localfunc)(void) = 0;
1086: /*
1087: Uses the DM object to call the user provided function with the correct calling
1088: sequence.
1089: */
1090: PetscErrorCode DMMGInitialGuess_Local(DMMG dmmg,Vec x)
1091: {
1095: (*dmmg->dm->ops->forminitialguess)(dmmg->dm,localfunc,x,0);
1096: return(0);
1097: }
1101: /*@C
1102: DMMGSetInitialGuessLocal - sets code to compute the initial guess for each level
1104: Collective on DMMG
1106: Input Parameter:
1107: + dmmg - the context
1108: - localguess - the function that computes the initial guess
1110: Level: intermediate
1112: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGSetInitialGuess(), DMMGSetSNESLocal()
1114: @*/
1115: PetscErrorCode DMMGSetInitialGuessLocal(DMMG *dmmg,PetscErrorCode (*localguess)(void))
1116: {
1120: localfunc = localguess; /* stash into ugly static for now */
1122: DMMGSetInitialGuess(dmmg,DMMGInitialGuess_Local);
1123: return(0);
1124: }
1128: /*@C
1129: DMMGSetISColoringType - type of coloring used to compute Jacobian via finite differencing
1131: Collective on DMMG
1133: Input Parameter:
1134: + dmmg - the context
1135: - isctype - IS_COLORING_GHOSTED (default) or IS_COLORING_GLOBAL
1137: Options Database:
1138: . -dmmg_iscoloring_type <ghosted or global>
1140: Notes: ghosted coloring requires using DMMGSetSNESLocal()
1142: Level: intermediate
1144: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES(), DMMGSetInitialGuess(), DMMGSetSNESLocal()
1146: @*/
1147: PetscErrorCode DMMGSetISColoringType(DMMG *dmmg,ISColoringType isctype)
1148: {
1150: dmmg[0]->isctype = isctype;
1151: return(0);
1152: }
1157: /*@C
1158: DMMGSetUp - Called after DMMGSetSNES() and (optionally) DMMGSetFromOptions()
1160: Collective on DMMG
1162: Input Parameter:
1163: . dmmg - the context
1165: Notes: Currently this must be called by the user (if they want to). It checks to see if fieldsplit preconditioner
1166: is being used and manages it.
1168: Level: advanced
1170: .seealso DMMGCreate(), DMMGDestroy(), DMMG, DMMGSetSNES(), DMMGSetKSP(), DMMGSolve(), DMMGSetMatType()
1172: @*/
1173: PetscErrorCode DMMGSetUp(DMMG *dmmg)
1174: {
1176: PetscInt i,nDM;
1177: PetscTruth fieldsplit,dmcomposite;
1178: KSP ksp;
1179: SNES snes;
1180: PC pc;
1181: IS *fields;
1184: snes = DMMGGetSNES(dmmg);
1185: if (snes) {
1186: SNESGetKSP(snes,&ksp);
1187: } else {
1188: ksp = DMMGGetKSP(dmmg);
1189: }
1190: KSPGetPC(ksp,&pc);
1191: PetscTypeCompare((PetscObject)pc,PCFIELDSPLIT,&fieldsplit);
1192: PetscTypeCompare((PetscObject)DMMGGetDM(dmmg),"DMComposite",&dmcomposite);
1193: if (fieldsplit && dmcomposite) {
1194: PetscInfo(ksp,"Setting up physics based fieldsplit preconditioner\n");
1195: DMCompositeGetNumberDM((DMComposite)DMMGGetDM(dmmg),&nDM);
1196: DMCompositeGetGlobalISs((DMComposite)DMMGGetDM(dmmg),&fields);
1197: for (i=0; i<nDM; i++) {
1198: PCFieldSplitSetIS(pc,fields[i]);
1199: ISDestroy(fields[i]);
1200: }
1201: PetscFree(fields);
1202: }
1203: PCSetDA(pc,(DA)DMMGGetDM(dmmg));
1205: return(0);
1206: }