Actual source code: damgsnes.c
1: #define PETSCSNES_DLL
2:
3: #include petscda.h
4: #include petscmg.h
5: #include petscdmmg.h
7: #if defined(PETSC_HAVE_ADIC)
12: #endif
15: EXTERN PetscErrorCode PETSCSNES_DLLEXPORT NLFCreate_DAAD(NLF*);
16: EXTERN PetscErrorCode PETSCSNES_DLLEXPORT NLFDAADSetDA_DAAD(NLF,DA);
17: EXTERN PetscErrorCode PETSCSNES_DLLEXPORT NLFDAADSetCtx_DAAD(NLF,void*);
18: EXTERN PetscErrorCode PETSCSNES_DLLEXPORT NLFDAADSetResidual_DAAD(NLF,Vec);
19: EXTERN PetscErrorCode PETSCSNES_DLLEXPORT NLFDAADSetNewtonIterations_DAAD(NLF,PetscInt);
22: /*
23: period of -1 indicates update only on zeroth iteration of SNES
24: */
25: #define ShouldUpdate(l,it) (((dmmg[l-1]->updatejacobianperiod == -1) && (it == 0)) || \
26: ((dmmg[l-1]->updatejacobianperiod > 0) && !(it % dmmg[l-1]->updatejacobianperiod)))
27: /*
28: Evaluates the Jacobian on all of the grids. It is used by DMMG to provide the
29: ComputeJacobian() function that SNESSetJacobian() requires.
30: */
33: PetscErrorCode DMMGComputeJacobian_Multigrid(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
34: {
35: DMMG *dmmg = (DMMG*)ptr;
37: PetscInt i,nlevels = dmmg[0]->nlevels,it;
38: KSP ksp,lksp;
39: PC pc;
40: PetscTruth ismg;
41: Vec W;
42: MatStructure flg;
45: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as user context which should contain DMMG");
46: SNESGetIterationNumber(snes,&it);
48: /* compute Jacobian on finest grid */
49: if (dmmg[nlevels-1]->updatejacobian && ShouldUpdate(nlevels,it)) {
50: (*DMMGGetFine(dmmg)->computejacobian)(snes,X,J,B,flag,DMMGGetFine(dmmg));
51: } else {
52: PetscInfo3(0,"Skipping Jacobian, SNES iteration %D frequence %D level %D\n",it,dmmg[nlevels-1]->updatejacobianperiod,nlevels-1);
53: *flag = SAME_PRECONDITIONER;
54: }
55: MatSNESMFSetBase(DMMGGetFine(dmmg)->J,X);
57: /* create coarser grid Jacobians for preconditioner if multigrid is the preconditioner */
58: SNESGetKSP(snes,&ksp);
59: KSPGetPC(ksp,&pc);
60: PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
61: if (ismg) {
62: PetscTruth galerkin;
64: PCMGGetGalerkin(pc,&galerkin);
65: PCMGGetSmoother(pc,nlevels-1,&lksp);
66: KSPSetOperators(lksp,DMMGGetFine(dmmg)->J,DMMGGetFine(dmmg)->B,*flag);
68: if (!galerkin) {
69: for (i=nlevels-1; i>0; i--) {
70: if (!dmmg[i-1]->w) {
71: VecDuplicate(dmmg[i-1]->x,&dmmg[i-1]->w);
72: }
73: W = dmmg[i-1]->w;
74: /* restrict X to coarser grid */
75: MatRestrict(dmmg[i]->R,X,W);
76: X = W;
77: /* scale to "natural" scaling for that grid */
78: VecPointwiseMult(X,X,dmmg[i]->Rscale);
79: /* tell the base vector for matrix free multiplies */
80: MatSNESMFSetBase(dmmg[i-1]->J,X);
81: /* compute Jacobian on coarse grid */
82: if (dmmg[i-1]->updatejacobian && ShouldUpdate(i,it)) {
83: (*dmmg[i-1]->computejacobian)(snes,X,&dmmg[i-1]->J,&dmmg[i-1]->B,&flg,dmmg[i-1]);
84: flg = SAME_NONZERO_PATTERN;
85: } else {
86: PetscInfo3(0,"Skipping Jacobian, SNES iteration %D frequence %D level %D\n",it,dmmg[i-1]->updatejacobianperiod,i-1);
87: flg = SAME_PRECONDITIONER;
88: }
89: PCMGGetSmoother(pc,i-1,&lksp);
90: KSPSetOperators(lksp,dmmg[i-1]->J,dmmg[i-1]->B,flg);
91: }
92: }
93: }
94: return(0);
95: }
97: /* ---------------------------------------------------------------------------*/
101: /*
102: DMMGFormFunction - This is a universal global FormFunction used by the DMMG code
103: when the user provides a local function.
105: Input Parameters:
106: + snes - the SNES context
107: . X - input vector
108: - ptr - optional user-defined context, as set by SNESSetFunction()
110: Output Parameter:
111: . F - function vector
113: */
114: PetscErrorCode DMMGFormFunction(SNES snes,Vec X,Vec F,void *ptr)
115: {
116: DMMG dmmg = (DMMG)ptr;
118: Vec localX;
119: DA da = (DA)dmmg->dm;
122: DAGetLocalVector(da,&localX);
123: /*
124: Scatter ghost points to local vector, using the 2-step process
125: DAGlobalToLocalBegin(), DAGlobalToLocalEnd().
126: */
127: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
128: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
129: DAFormFunction1(da,localX,F,dmmg->user);
130: DARestoreLocalVector(da,&localX);
131: return(0);
132: }
136: /*@C
137: SNESDAFormFunction - This is a universal function evaluation routine that
138: may be used with SNESSetFunction() as long as the user context has a DA
139: as its first record and the user has called DASetLocalFunction().
141: Collective on SNES
143: Input Parameters:
144: + snes - the SNES context
145: . X - input vector
146: . F - function vector
147: - ptr - pointer to a structure that must have a DA as its first entry. For example this
148: could be a DMMG
150: Level: intermediate
152: .seealso: DASetLocalFunction(), DASetLocalJacobian(), DASetLocalAdicFunction(), DASetLocalAdicMFFunction(),
153: SNESSetFunction(), SNESSetJacobian()
155: @*/
156: PetscErrorCode PETSCSNES_DLLEXPORT SNESDAFormFunction(SNES snes,Vec X,Vec F,void *ptr)
157: {
159: Vec localX;
160: DA da = *(DA*)ptr;
163: DAGetLocalVector(da,&localX);
164: /*
165: Scatter ghost points to local vector, using the 2-step process
166: DAGlobalToLocalBegin(), DAGlobalToLocalEnd().
167: */
168: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
169: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
170: DAFormFunction1(da,localX,F,ptr);
171: if (PetscExceptionValue(ierr)) {
172: PetscErrorCode pDARestoreLocalVector(da,&localX);CHKERRQ(pierr);
173: }
174:
175: DARestoreLocalVector(da,&localX);
176: return(0);
177: }
179: /* ---------------------------------------------------------------------------------------------------------------------------*/
183: PetscErrorCode DMMGComputeJacobianWithFD(SNES snes,Vec x1,Mat *J,Mat *B,MatStructure *flag,void *ctx)
184: {
186: DMMG dmmg = (DMMG)ctx;
187:
189: SNESDefaultComputeJacobianColor(snes,x1,J,B,flag,dmmg->fdcoloring);
190: return(0);
191: }
195: PetscErrorCode DMMGComputeJacobianWithMF(SNES snes,Vec x1,Mat *J,Mat *B,MatStructure *flag,void *ctx)
196: {
198:
200: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
201: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
202: return(0);
203: }
207: /*
208: DMMGComputeJacobian - Evaluates the Jacobian when the user has provided
209: a local function evaluation routine.
210: */
211: PetscErrorCode DMMGComputeJacobian(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
212: {
213: DMMG dmmg = (DMMG) ptr;
215: Vec localX;
216: DA da = (DA) dmmg->dm;
219: DAGetLocalVector(da,&localX);
220: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
221: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
222: DAComputeJacobian1(da,localX,*B,dmmg->user);
223: DARestoreLocalVector(da,&localX);
224: /* Assemble true Jacobian; if it is different */
225: if (*J != *B) {
226: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
227: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
228: }
229: MatSetOption(*B,MAT_NEW_NONZERO_LOCATION_ERR);
230: *flag = SAME_NONZERO_PATTERN;
231: return(0);
232: }
236: /*
237: SNESDAComputeJacobianWithAdifor - This is a universal Jacobian evaluation routine
238: that may be used with SNESSetJacobian() from Fortran as long as the user context has
239: a DA as its first record and DASetLocalAdiforFunction() has been called.
241: Collective on SNES
243: Input Parameters:
244: + snes - the SNES context
245: . X - input vector
246: . J - Jacobian
247: . B - Jacobian used in preconditioner (usally same as J)
248: . flag - indicates if the matrix changed its structure
249: - ptr - optional user-defined context, as set by SNESSetFunction()
251: Level: intermediate
253: .seealso: DASetLocalFunction(), DASetLocalAdicFunction(), SNESSetFunction(), SNESSetJacobian()
255: */
256: PetscErrorCode PETSCSNES_DLLEXPORT SNESDAComputeJacobianWithAdifor(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
257: {
258: DA da = *(DA*) ptr;
260: Vec localX;
263: DAGetLocalVector(da,&localX);
264: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
265: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
266: DAComputeJacobian1WithAdifor(da,localX,*B,ptr);
267: DARestoreLocalVector(da,&localX);
268: /* Assemble true Jacobian; if it is different */
269: if (*J != *B) {
270: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
271: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
272: }
273: MatSetOption(*B,MAT_NEW_NONZERO_LOCATION_ERR);
274: *flag = SAME_NONZERO_PATTERN;
275: return(0);
276: }
280: /*
281: SNESDAComputeJacobian - This is a universal Jacobian evaluation routine for a
282: locally provided Jacobian.
284: Collective on SNES
286: Input Parameters:
287: + snes - the SNES context
288: . X - input vector
289: . J - Jacobian
290: . B - Jacobian used in preconditioner (usally same as J)
291: . flag - indicates if the matrix changed its structure
292: - ptr - optional user-defined context, as set by SNESSetFunction()
294: Level: intermediate
296: .seealso: DASetLocalFunction(), DASetLocalJacobian(), SNESSetFunction(), SNESSetJacobian()
298: */
299: PetscErrorCode PETSCSNES_DLLEXPORT SNESDAComputeJacobian(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
300: {
301: DA da = *(DA*) ptr;
303: Vec localX;
306: DAGetLocalVector(da,&localX);
307: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
308: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
309: DAComputeJacobian1(da,localX,*B,ptr);
310: DARestoreLocalVector(da,&localX);
311: /* Assemble true Jacobian; if it is different */
312: if (*J != *B) {
313: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
314: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
315: }
316: MatSetOption(*B,MAT_NEW_NONZERO_LOCATION_ERR);
317: *flag = SAME_NONZERO_PATTERN;
318: return(0);
319: }
323: PetscErrorCode DMMGSolveSNES(DMMG *dmmg,PetscInt level)
324: {
326: PetscInt nlevels = dmmg[0]->nlevels;
329: dmmg[0]->nlevels = level+1;
330: SNESSolve(dmmg[level]->snes,PETSC_NULL,dmmg[level]->x);
331: dmmg[0]->nlevels = nlevels;
332: return(0);
333: }
335: /* ===========================================================================================================*/
339: /*@C
340: DMMGSetSNES - Sets the nonlinear function that defines the nonlinear set of equations
341: to be solved using the grid hierarchy.
343: Collective on DMMG
345: Input Parameter:
346: + dmmg - the context
347: . function - the function that defines the nonlinear system
348: - jacobian - optional function to compute Jacobian
350: Options Database Keys:
351: + -dmmg_snes_monitor
352: . -dmmg_jacobian_fd
353: . -dmmg_jacobian_ad
354: . -dmmg_jacobian_mf_fd_operator
355: . -dmmg_jacobian_mf_fd
356: . -dmmg_jacobian_mf_ad_operator
357: . -dmmg_jacobian_mf_ad
358: - -dmmg_jacobian_period <p> - Indicates how often in the SNES solve the Jacobian is recomputed (on all levels)
359: as suggested by Florin Dobrian if p is -1 then Jacobian is computed only on first
360: SNES iteration (i.e. -1 is equivalent to infinity)
362: Level: advanced
364: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNESLocal()
366: @*/
367: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetSNES(DMMG *dmmg,PetscErrorCode (*function)(SNES,Vec,Vec,void*),PetscErrorCode (*jacobian)(SNES,Vec,Mat*,Mat*,MatStructure*,void*))
368: {
370: PetscInt i,nlevels = dmmg[0]->nlevels,period = 1;
371: PetscTruth snesmonitor,mffdoperator,mffd,fdjacobian;
372: #if defined(PETSC_HAVE_ADIC)
373: PetscTruth mfadoperator,mfad,adjacobian;
374: #endif
375: PetscViewer ascii;
376: MPI_Comm comm;
379: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
380: if (!jacobian) jacobian = DMMGComputeJacobianWithFD;
382: PetscOptionsBegin(dmmg[0]->comm,PETSC_NULL,"DMMG Options","SNES");
383: PetscOptionsName("-dmmg_snes_monitor","Monitor nonlinear convergence","SNESSetMonitor",&snesmonitor);
386: PetscOptionsName("-dmmg_jacobian_fd","Compute sparse Jacobian explicitly with finite differencing","DMMGSetSNES",&fdjacobian);
387: if (fdjacobian) jacobian = DMMGComputeJacobianWithFD;
388: #if defined(PETSC_HAVE_ADIC)
389: PetscOptionsName("-dmmg_jacobian_ad","Compute sparse Jacobian explicitly with ADIC (automatic differentiation)","DMMGSetSNES",&adjacobian);
390: if (adjacobian) jacobian = DMMGComputeJacobianWithAdic;
391: #endif
393: PetscOptionsTruthGroupBegin("-dmmg_jacobian_mf_fd_operator","Apply Jacobian via matrix free finite differencing","DMMGSetSNES",&mffdoperator);
394: PetscOptionsTruthGroupEnd("-dmmg_jacobian_mf_fd","Apply Jacobian via matrix free finite differencing even in computing preconditioner","DMMGSetSNES",&mffd);
395: if (mffd) mffdoperator = PETSC_TRUE;
396: #if defined(PETSC_HAVE_ADIC)
397: PetscOptionsTruthGroupBegin("-dmmg_jacobian_mf_ad_operator","Apply Jacobian via matrix free ADIC (automatic differentiation)","DMMGSetSNES",&mfadoperator);
398: PetscOptionsTruthGroupEnd("-dmmg_jacobian_mf_ad","Apply Jacobian via matrix free ADIC (automatic differentiation) even in computing preconditioner","DMMGSetSNES",&mfad);
399: if (mfad) mfadoperator = PETSC_TRUE;
400: #endif
401: PetscOptionsEnd();
403: /* create solvers for each level */
404: for (i=0; i<nlevels; i++) {
405: SNESCreate(dmmg[i]->comm,&dmmg[i]->snes);
406: SNESGetKSP(dmmg[i]->snes,&dmmg[i]->ksp);
407: if (snesmonitor) {
408: PetscObjectGetComm((PetscObject)dmmg[i]->snes,&comm);
409: PetscViewerASCIIOpen(comm,"stdout",&ascii);
410: PetscViewerASCIISetTab(ascii,nlevels-i);
411: SNESSetMonitor(dmmg[i]->snes,SNESDefaultMonitor,ascii,(PetscErrorCode(*)(void*))PetscViewerDestroy);
412: }
414: if (mffdoperator) {
415: MatCreateSNESMF(dmmg[i]->snes,dmmg[i]->x,&dmmg[i]->J);
416: VecDuplicate(dmmg[i]->x,&dmmg[i]->work1);
417: VecDuplicate(dmmg[i]->x,&dmmg[i]->work2);
418: MatSNESMFSetFunction(dmmg[i]->J,dmmg[i]->work1,function,dmmg[i]);
419: if (mffd) {
420: dmmg[i]->B = dmmg[i]->J;
421: jacobian = DMMGComputeJacobianWithMF;
422: }
423: #if defined(PETSC_HAVE_ADIC)
424: } else if (mfadoperator) {
425: MatRegisterDAAD();
426: MatCreateDAAD((DA)dmmg[i]->dm,&dmmg[i]->J);
427: MatDAADSetCtx(dmmg[i]->J,dmmg[i]->user);
428: if (mfad) {
429: dmmg[i]->B = dmmg[i]->J;
430: jacobian = DMMGComputeJacobianWithMF;
431: }
432: #endif
433: }
434:
435: if (!dmmg[i]->B) {
436: DMGetMatrix(dmmg[i]->dm,MATAIJ,&dmmg[i]->B);
437: }
438: if (!dmmg[i]->J) {
439: dmmg[i]->J = dmmg[i]->B;
440: }
442: DMMGSetUpLevel(dmmg,dmmg[i]->ksp,i+1);
443:
444: /*
445: if the number of levels is > 1 then we want the coarse solve in the grid sequencing to use LU
446: when possible
447: */
448: if (nlevels > 1 && i == 0) {
449: PC pc;
450: KSP cksp;
451: PetscTruth flg1,flg2,flg3;
453: KSPGetPC(dmmg[i]->ksp,&pc);
454: PCMGGetCoarseSolve(pc,&cksp);
455: KSPGetPC(cksp,&pc);
456: PetscTypeCompare((PetscObject)pc,PCILU,&flg1);
457: PetscTypeCompare((PetscObject)pc,PCSOR,&flg2);
458: PetscTypeCompare((PetscObject)pc,PETSC_NULL,&flg3);
459: if (flg1 || flg2 || flg3) {
460: PCSetType(pc,PCLU);
461: }
462: }
464: dmmg[i]->solve = DMMGSolveSNES;
465: dmmg[i]->computejacobian = jacobian;
466: dmmg[i]->computefunction = function;
467: }
469: if (jacobian == DMMGComputeJacobianWithFD) {
470: ISColoring iscoloring;
471: for (i=0; i<nlevels; i++) {
472: DMGetColoring(dmmg[i]->dm,IS_COLORING_LOCAL,&iscoloring);
473: MatFDColoringCreate(dmmg[i]->B,iscoloring,&dmmg[i]->fdcoloring);
474: ISColoringDestroy(iscoloring);
475: MatFDColoringSetFunction(dmmg[i]->fdcoloring,(PetscErrorCode(*)(void))function,dmmg[i]);
476: MatFDColoringSetFromOptions(dmmg[i]->fdcoloring);
477: }
478: #if defined(PETSC_HAVE_ADIC)
479: } else if (jacobian == DMMGComputeJacobianWithAdic) {
480: for (i=0; i<nlevels; i++) {
481: ISColoring iscoloring;
482: DMGetColoring(dmmg[i]->dm,IS_COLORING_GHOSTED,&iscoloring);
483: MatSetColoring(dmmg[i]->B,iscoloring);
484: ISColoringDestroy(iscoloring);
485: }
486: #endif
487: }
489: for (i=0; i<nlevels; i++) {
490: SNESSetJacobian(dmmg[i]->snes,dmmg[i]->J,dmmg[i]->B,DMMGComputeJacobian_Multigrid,dmmg);
491: SNESSetFunction(dmmg[i]->snes,dmmg[i]->b,function,dmmg[i]);
492: SNESSetFromOptions(dmmg[i]->snes);
493: }
495: /* Create interpolation scaling */
496: for (i=1; i<nlevels; i++) {
497: DMGetInterpolationScale(dmmg[i-1]->dm,dmmg[i]->dm,dmmg[i]->R,&dmmg[i]->Rscale);
498: }
500: PetscOptionsGetInt(PETSC_NULL,"-dmmg_jacobian_period",&period,PETSC_NULL);
501: for (i=0; i<nlevels; i++) {
502: dmmg[i]->updatejacobian = PETSC_TRUE;
503: dmmg[i]->updatejacobianperiod = period;
504: }
506: #if defined(PETSC_HAVE_ADIC)
507: {
508: PetscTruth flg;
509: PetscOptionsHasName(PETSC_NULL,"-dmmg_fas",&flg);
510: if (flg) {
511: PetscTruth block = PETSC_FALSE;
512: PetscInt newton_its;
513: PetscOptionsHasName(0,"-dmmg_fas_view",&flg);
514: for (i=0; i<nlevels; i++) {
515: NLFCreate_DAAD(&dmmg[i]->nlf);
516: NLFDAADSetDA_DAAD(dmmg[i]->nlf,(DA)dmmg[i]->dm);
517: NLFDAADSetCtx_DAAD(dmmg[i]->nlf,dmmg[i]->user);
518: NLFDAADSetResidual_DAAD(dmmg[i]->nlf,dmmg[i]->r);
519: VecDuplicate(dmmg[i]->b,&dmmg[i]->w);
521: dmmg[i]->monitor = PETSC_FALSE;
522: PetscOptionsHasName(0,"-dmmg_fas_monitor",&dmmg[i]->monitor);
523: dmmg[i]->monitorall = PETSC_FALSE;
524: PetscOptionsHasName(0,"-dmmg_fas_monitor_all",&dmmg[i]->monitorall);
525: dmmg[i]->presmooth = 2;
526: PetscOptionsGetInt(0,"-dmmg_fas_presmooth",&dmmg[i]->presmooth,0);
527: dmmg[i]->postsmooth = 2;
528: PetscOptionsGetInt(0,"-dmmg_fas_postsmooth",&dmmg[i]->postsmooth,0);
529: dmmg[i]->coarsesmooth = 2;
530: PetscOptionsGetInt(0,"-dmmg_fas_coarsesmooth",&dmmg[i]->coarsesmooth,0);
532: dmmg[i]->rtol = 1.e-8;
533: PetscOptionsGetReal(0,"-dmmg_fas_rtol",&dmmg[i]->rtol,0);
534: dmmg[i]->abstol = 1.e-50;
535: PetscOptionsGetReal(0,"-dmmg_fas_atol",&dmmg[i]->abstol,0);
537: newton_its = 2;
538: PetscOptionsGetInt(0,"-dmmg_fas_newton_its",&newton_its,0);
539: NLFDAADSetNewtonIterations_DAAD(dmmg[i]->nlf,newton_its);
541: if (flg) {
542: if (i == 0) {
543: PetscPrintf(dmmg[i]->comm,"FAS Solver Parameters\n");
544: PetscPrintf(dmmg[i]->comm," rtol %G atol %G\n",dmmg[i]->rtol,dmmg[i]->abstol);
545: PetscPrintf(dmmg[i]->comm," coarsesmooths %D\n",dmmg[i]->coarsesmooth);
546: PetscPrintf(dmmg[i]->comm," Newton iterations %D\n",newton_its);
547: } else {
548: PetscPrintf(dmmg[i]->comm," level %D presmooths %D\n",i,dmmg[i]->presmooth);
549: PetscPrintf(dmmg[i]->comm," postsmooths %D\n",dmmg[i]->postsmooth);
550: PetscPrintf(dmmg[i]->comm," Newton iterations %D\n",newton_its);
551: }
552: }
553: PetscOptionsHasName(0,"-dmmg_fas_block",&block);
554: if (block) {
555: dmmg[i]->solve = DMMGSolveFASb;
556: if (flg) {
557: PetscPrintf(dmmg[i]->comm," using point-block smoothing\n");
558: }
559: } else {
560: dmmg[i]->solve = DMMGSolveFAS;
561: }
562: }
563: }
564: }
565: #endif
566:
567: return(0);
568: }
570: /*M
571: DMMGSetSNESLocal - Sets the local user function that defines the nonlinear set of equations
572: that will use the grid hierarchy and (optionally) its derivative.
574: Collective on DMMG
576: Synopsis:
577: PetscErrorCode DMMGSetSNESLocal(DMMG *dmmg,DALocalFunction1 function, DALocalFunction1 jacobian,
578: DALocalFunction1 ad_function, DALocalFunction1 admf_function);
580: Input Parameter:
581: + dmmg - the context
582: . function - the function that defines the nonlinear system
583: . jacobian - function defines the local part of the Jacobian
584: . ad_function - the name of the function with an ad_ prefix. This is ignored if ADIC is
585: not installed
586: - admf_function - the name of the function with an ad_ prefix. This is ignored if ADIC is
587: not installed
589: Options Database Keys:
590: + -dmmg_snes_monitor
591: . -dmmg_jacobian_fd
592: . -dmmg_jacobian_ad
593: . -dmmg_jacobian_mf_fd_operator
594: . -dmmg_jacobian_mf_fd
595: . -dmmg_jacobian_mf_ad_operator
596: . -dmmg_jacobian_mf_ad
597: - -dmmg_jacobian_period <p> - Indicates how often in the SNES solve the Jacobian is recomputed (on all levels)
598: as suggested by Florin Dobrian if p is -1 then Jacobian is computed only on first
599: SNES iteration (i.e. -1 is equivalent to infinity)
602: Level: intermediate
604: Notes:
605: If ADIC or ADIFOR have been installed, this routine can use ADIC or ADIFOR to compute
606: the derivative; however, that function cannot call other functions except those in
607: standard C math libraries.
609: If ADIC/ADIFOR have not been installed and the Jacobian is not provided, this routine
610: uses finite differencing to approximate the Jacobian.
612: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES()
614: M*/
618: PetscErrorCode DMMGSetSNESLocal_Private(DMMG *dmmg,DALocalFunction1 function,DALocalFunction1 jacobian,DALocalFunction1 ad_function,DALocalFunction1 admf_function)
619: {
621: PetscInt i,nlevels = dmmg[0]->nlevels;
622: PetscErrorCode (*computejacobian)(SNES,Vec,Mat*,Mat*,MatStructure*,void*) = 0;
626: if (jacobian) computejacobian = DMMGComputeJacobian;
627: #if defined(PETSC_HAVE_ADIC)
628: else if (ad_function) computejacobian = DMMGComputeJacobianWithAdic;
629: #endif
631: DMMGSetSNES(dmmg,DMMGFormFunction,computejacobian);
632: for (i=0; i<nlevels; i++) {
633: DASetLocalFunction((DA)dmmg[i]->dm,function);
634: DASetLocalJacobian((DA)dmmg[i]->dm,jacobian);
635: DASetLocalAdicFunction((DA)dmmg[i]->dm,ad_function);
636: DASetLocalAdicMFFunction((DA)dmmg[i]->dm,admf_function);
637: }
638: return(0);
639: }
643: PetscErrorCode DMMGFunctioni(PetscInt i,Vec u,PetscScalar* r,void* ctx)
644: {
645: DMMG dmmg = (DMMG)ctx;
646: Vec U = dmmg->lwork1;
648: VecScatter gtol;
651: /* copy u into interior part of U */
652: DAGetScatter((DA)dmmg->dm,0,>ol,0);
653: VecScatterBegin(u,U,INSERT_VALUES,SCATTER_FORWARD_LOCAL,gtol);
654: VecScatterEnd(u,U,INSERT_VALUES,SCATTER_FORWARD_LOCAL,gtol);
655: DAFormFunctioni1((DA)dmmg->dm,i,U,r,dmmg->user);
656: return(0);
657: }
661: PetscErrorCode DMMGFunctionib(PetscInt i,Vec u,PetscScalar* r,void* ctx)
662: {
663: DMMG dmmg = (DMMG)ctx;
664: Vec U = dmmg->lwork1;
666: VecScatter gtol;
669: /* copy u into interior part of U */
670: DAGetScatter((DA)dmmg->dm,0,>ol,0);
671: VecScatterBegin(u,U,INSERT_VALUES,SCATTER_FORWARD_LOCAL,gtol);
672: VecScatterEnd(u,U,INSERT_VALUES,SCATTER_FORWARD_LOCAL,gtol);
673: DAFormFunctionib1((DA)dmmg->dm,i,U,r,dmmg->user);
674: return(0);
675: }
679: PetscErrorCode DMMGFunctioniBase(Vec u,void* ctx)
680: {
681: DMMG dmmg = (DMMG)ctx;
682: Vec U = dmmg->lwork1;
686: DAGlobalToLocalBegin((DA)dmmg->dm,u,INSERT_VALUES,U);
687: DAGlobalToLocalEnd((DA)dmmg->dm,u,INSERT_VALUES,U);
688: return(0);
689: }
693: 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*))
694: {
696: PetscInt i,nlevels = dmmg[0]->nlevels;
699: for (i=0; i<nlevels; i++) {
700: DASetLocalFunctioni((DA)dmmg[i]->dm,functioni);
701: DASetLocalAdicFunctioni((DA)dmmg[i]->dm,adi);
702: DASetLocalAdicMFFunctioni((DA)dmmg[i]->dm,adimf);
703: MatSNESMFSetFunctioni(dmmg[i]->J,DMMGFunctioni);
704: MatSNESMFSetFunctioniBase(dmmg[i]->J,DMMGFunctioniBase);
705: if (!dmmg[i]->lwork1) {
706: DACreateLocalVector((DA)dmmg[i]->dm,&dmmg[i]->lwork1);
707: }
708: }
709: return(0);
710: }
714: 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*))
715: {
717: PetscInt i,nlevels = dmmg[0]->nlevels;
720: for (i=0; i<nlevels; i++) {
721: DASetLocalFunctionib((DA)dmmg[i]->dm,functioni);
722: DASetLocalAdicFunctionib((DA)dmmg[i]->dm,adi);
723: DASetLocalAdicMFFunctionib((DA)dmmg[i]->dm,adimf);
724: if (!dmmg[i]->lwork1) {
725: DACreateLocalVector((DA)dmmg[i]->dm,&dmmg[i]->lwork1);
726: }
727: }
728: return(0);
729: }