Actual source code: damgsnes.c
1: #define PETSCSNES_DLL
2:
3: #include petscda.h
4: #include petscmg.h
5: #include petscdmmg.h
7: /*
8: period of -1 indicates update only on zeroth iteration of SNES
9: */
10: #define ShouldUpdate(l,it) (((dmmg[l-1]->updatejacobianperiod == -1) && (it == 0)) || \
11: ((dmmg[l-1]->updatejacobianperiod > 0) && !(it % dmmg[l-1]->updatejacobianperiod)))
12: /*
13: Evaluates the Jacobian on all of the grids. It is used by DMMG to provide the
14: ComputeJacobian() function that SNESSetJacobian() requires.
15: */
18: PetscErrorCode DMMGComputeJacobian_Multigrid(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
19: {
20: DMMG *dmmg = (DMMG*)ptr;
22: PetscInt i,nlevels = dmmg[0]->nlevels,it;
23: KSP ksp,lksp;
24: PC pc;
25: PetscTruth ismg;
26: Vec W;
27: MatStructure flg;
30: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as user context which should contain DMMG");
31: SNESGetIterationNumber(snes,&it);
33: /* compute Jacobian on finest grid */
34: if (dmmg[nlevels-1]->updatejacobian && ShouldUpdate(nlevels,it)) {
35: (*DMMGGetFine(dmmg)->computejacobian)(snes,X,J,B,flag,DMMGGetFine(dmmg));
36: } else {
37: PetscLogInfo((0,"DMMGComputeJacobian_Multigrid:Skipping Jacobian, SNES iteration %D frequence %D level %D\n",it,dmmg[nlevels-1]->updatejacobianperiod,nlevels-1));
38: *flag = SAME_PRECONDITIONER;
39: }
40: MatSNESMFSetBase(DMMGGetFine(dmmg)->J,X);
42: /* create coarser grid Jacobians for preconditioner if multigrid is the preconditioner */
43: SNESGetKSP(snes,&ksp);
44: KSPGetPC(ksp,&pc);
45: PetscTypeCompare((PetscObject)pc,PCMG,&ismg);
46: if (ismg) {
48: PCMGGetSmoother(pc,nlevels-1,&lksp);
49: KSPSetOperators(lksp,DMMGGetFine(dmmg)->J,DMMGGetFine(dmmg)->B,*flag);
51: if (dmmg[0]->galerkin) {
52: for (i=nlevels-2; i>-1; i--) {
53: PetscTruth JeqB = (PetscTruth)( dmmg[i]->B == dmmg[i]->J);
54: MatDestroy(dmmg[i]->B);
55: MatPtAP(dmmg[i+1]->B,dmmg[i+1]->R,MAT_INITIAL_MATRIX,1.0,&dmmg[i]->B);
56: if (JeqB) dmmg[i]->J = dmmg[i]->B;
57: PCMGGetSmoother(pc,i,&lksp);
58: KSPSetOperators(lksp,dmmg[i]->J,dmmg[i]->B,*flag);
59: }
60: } else {
61: for (i=nlevels-1; i>0; i--) {
62: if (!dmmg[i-1]->w) {
63: VecDuplicate(dmmg[i-1]->x,&dmmg[i-1]->w);
64: }
65: W = dmmg[i-1]->w;
66: /* restrict X to coarser grid */
67: MatRestrict(dmmg[i]->R,X,W);
68: X = W;
69: /* scale to "natural" scaling for that grid */
70: VecPointwiseMult(X,X,dmmg[i]->Rscale);
71: /* tell the base vector for matrix free multiplies */
72: MatSNESMFSetBase(dmmg[i-1]->J,X);
73: /* compute Jacobian on coarse grid */
74: if (dmmg[i-1]->updatejacobian && ShouldUpdate(i,it)) {
75: (*dmmg[i-1]->computejacobian)(snes,X,&dmmg[i-1]->J,&dmmg[i-1]->B,&flg,dmmg[i-1]);
76: flg = SAME_NONZERO_PATTERN;
77: } else {
78: PetscLogInfo((0,"DMMGComputeJacobian_Multigrid:Skipping Jacobian, SNES iteration %D frequence %D level %D\n",it,dmmg[i-1]->updatejacobianperiod,i-1));
79: flg = SAME_PRECONDITIONER;
80: }
81: PCMGGetSmoother(pc,i-1,&lksp);
82: KSPSetOperators(lksp,dmmg[i-1]->J,dmmg[i-1]->B,flg);
83: }
84: }
85: }
86: return(0);
87: }
89: /* ---------------------------------------------------------------------------*/
93: /*
94: DMMGFormFunction - This is a universal global FormFunction used by the DMMG code
95: when the user provides a local function.
97: Input Parameters:
98: + snes - the SNES context
99: . X - input vector
100: - ptr - optional user-defined context, as set by SNESSetFunction()
102: Output Parameter:
103: . F - function vector
105: */
106: PetscErrorCode DMMGFormFunction(SNES snes,Vec X,Vec F,void *ptr)
107: {
108: DMMG dmmg = (DMMG)ptr;
110: Vec localX;
111: DA da = (DA)dmmg->dm;
114: DAGetLocalVector(da,&localX);
115: /*
116: Scatter ghost points to local vector, using the 2-step process
117: DAGlobalToLocalBegin(), DAGlobalToLocalEnd().
118: */
119: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
120: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
121: DAFormFunction1(da,localX,F,dmmg->user);
122: DARestoreLocalVector(da,&localX);
123: return(0);
124: }
128: /*@C
129: SNESDAFormFunction - This is a universal function evaluation routine that
130: may be used with SNESSetFunction() as long as the user context has a DA
131: as its first record and the user has called DASetLocalFunction().
133: Collective on SNES
135: Input Parameters:
136: + snes - the SNES context
137: . X - input vector
138: . F - function vector
139: - ptr - pointer to a structure that must have a DA as its first entry. For example this
140: could be a DMMG
142: Level: intermediate
144: .seealso: DASetLocalFunction(), DASetLocalJacobian(), DASetLocalAdicFunction(), DASetLocalAdicMFFunction(),
145: SNESSetFunction(), SNESSetJacobian()
147: @*/
148: PetscErrorCode PETSCSNES_DLLEXPORT SNESDAFormFunction(SNES snes,Vec X,Vec F,void *ptr)
149: {
151: Vec localX;
152: DA da = *(DA*)ptr;
155: DAGetLocalVector(da,&localX);
156: /*
157: Scatter ghost points to local vector, using the 2-step process
158: DAGlobalToLocalBegin(), DAGlobalToLocalEnd().
159: */
160: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
161: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
162: DAFormFunction1(da,localX,F,ptr);
163: if (PetscExceptionValue(ierr)) {
164: PetscErrorCode pDARestoreLocalVector(da,&localX);CHKERRQ(pierr);
165: }
166:
167: DARestoreLocalVector(da,&localX);
168: return(0);
169: }
171: /* ---------------------------------------------------------------------------------------------------------------------------*/
175: PetscErrorCode DMMGComputeJacobianWithFD(SNES snes,Vec x1,Mat *J,Mat *B,MatStructure *flag,void *ctx)
176: {
178: DMMG dmmg = (DMMG)ctx;
179:
181: SNESDefaultComputeJacobianColor(snes,x1,J,B,flag,dmmg->fdcoloring);
182: return(0);
183: }
187: PetscErrorCode DMMGComputeJacobianWithMF(SNES snes,Vec x1,Mat *J,Mat *B,MatStructure *flag,void *ctx)
188: {
190:
192: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
193: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
194: return(0);
195: }
197: #if defined(PETSC_HAVE_ADIC)
200: /*
201: DMMGComputeJacobianWithAdic - Evaluates the Jacobian via Adic when the user has provided
202: a local function evaluation routine.
203: */
204: PetscErrorCode DMMGComputeJacobianWithAdic(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
205: {
206: DMMG dmmg = (DMMG) ptr;
208: Vec localX;
209: DA da = (DA) dmmg->dm;
212: DAGetLocalVector(da,&localX);
213: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
214: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
215: DAComputeJacobian1WithAdic(da,localX,*B,dmmg->user);
216: DARestoreLocalVector(da,&localX);
217: /* Assemble true Jacobian; if it is different */
218: if (*J != *B) {
219: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
220: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
221: }
222: MatSetOption(*B,MAT_NEW_NONZERO_LOCATION_ERR);
223: *flag = SAME_NONZERO_PATTERN;
224: return(0);
225: }
226: #endif
230: /*
231: DMMGComputeJacobian - Evaluates the Jacobian when the user has provided
232: a local function evaluation routine.
233: */
234: PetscErrorCode DMMGComputeJacobian(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
235: {
236: DMMG dmmg = (DMMG) ptr;
238: Vec localX;
239: DA da = (DA) dmmg->dm;
242: DAGetLocalVector(da,&localX);
243: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
244: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
245: DAComputeJacobian1(da,localX,*B,dmmg->user);
246: DARestoreLocalVector(da,&localX);
247: /* Assemble true Jacobian; if it is different */
248: if (*J != *B) {
249: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
250: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
251: }
252: MatSetOption(*B,MAT_NEW_NONZERO_LOCATION_ERR);
253: *flag = SAME_NONZERO_PATTERN;
254: return(0);
255: }
257: #if defined(PETSC_HAVE_ADIC)
260: /*@
261: SNESDAComputeJacobianWithAdic - This is a universal Jacobian evaluation routine
262: that may be used with SNESSetJacobian() as long as the user context has a DA as
263: its first record and DASetLocalAdicFunction() has been called.
265: Collective on SNES
267: Input Parameters:
268: + snes - the SNES context
269: . X - input vector
270: . J - Jacobian
271: . B - Jacobian used in preconditioner (usally same as J)
272: . flag - indicates if the matrix changed its structure
273: - ptr - optional user-defined context, as set by SNESSetFunction()
275: Level: intermediate
277: .seealso: DASetLocalFunction(), DASetLocalAdicFunction(), SNESSetFunction(), SNESSetJacobian()
279: @*/
280: PetscErrorCode PETSCSNES_DLLEXPORT SNESDAComputeJacobianWithAdic(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
281: {
282: DA da = *(DA*) ptr;
284: Vec localX;
287: DAGetLocalVector(da,&localX);
288: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
289: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
290: DAComputeJacobian1WithAdic(da,localX,*B,ptr);
291: DARestoreLocalVector(da,&localX);
292: /* Assemble true Jacobian; if it is different */
293: if (*J != *B) {
294: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
295: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
296: }
297: MatSetOption(*B,MAT_NEW_NONZERO_LOCATION_ERR);
298: *flag = SAME_NONZERO_PATTERN;
299: return(0);
300: }
301: #endif
305: /*
306: SNESDAComputeJacobianWithAdifor - This is a universal Jacobian evaluation routine
307: that may be used with SNESSetJacobian() from Fortran as long as the user context has
308: a DA as its first record and DASetLocalAdiforFunction() has been called.
310: Collective on SNES
312: Input Parameters:
313: + snes - the SNES context
314: . X - input vector
315: . J - Jacobian
316: . B - Jacobian used in preconditioner (usally same as J)
317: . flag - indicates if the matrix changed its structure
318: - ptr - optional user-defined context, as set by SNESSetFunction()
320: Level: intermediate
322: .seealso: DASetLocalFunction(), DASetLocalAdicFunction(), SNESSetFunction(), SNESSetJacobian()
324: */
325: PetscErrorCode PETSCSNES_DLLEXPORT SNESDAComputeJacobianWithAdifor(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
326: {
327: DA da = *(DA*) ptr;
329: Vec localX;
332: DAGetLocalVector(da,&localX);
333: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
334: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
335: DAComputeJacobian1WithAdifor(da,localX,*B,ptr);
336: DARestoreLocalVector(da,&localX);
337: /* Assemble true Jacobian; if it is different */
338: if (*J != *B) {
339: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
340: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
341: }
342: MatSetOption(*B,MAT_NEW_NONZERO_LOCATION_ERR);
343: *flag = SAME_NONZERO_PATTERN;
344: return(0);
345: }
349: /*
350: SNESDAComputeJacobian - This is a universal Jacobian evaluation routine for a
351: locally provided Jacobian.
353: Collective on SNES
355: Input Parameters:
356: + snes - the SNES context
357: . X - input vector
358: . J - Jacobian
359: . B - Jacobian used in preconditioner (usally same as J)
360: . flag - indicates if the matrix changed its structure
361: - ptr - optional user-defined context, as set by SNESSetFunction()
363: Level: intermediate
365: .seealso: DASetLocalFunction(), DASetLocalJacobian(), SNESSetFunction(), SNESSetJacobian()
367: */
368: PetscErrorCode PETSCSNES_DLLEXPORT SNESDAComputeJacobian(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
369: {
370: DA da = *(DA*) ptr;
372: Vec localX;
375: DAGetLocalVector(da,&localX);
376: DAGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
377: DAGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
378: DAComputeJacobian1(da,localX,*B,ptr);
379: DARestoreLocalVector(da,&localX);
380: /* Assemble true Jacobian; if it is different */
381: if (*J != *B) {
382: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
383: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
384: }
385: MatSetOption(*B,MAT_NEW_NONZERO_LOCATION_ERR);
386: *flag = SAME_NONZERO_PATTERN;
387: return(0);
388: }
392: PetscErrorCode DMMGSolveSNES(DMMG *dmmg,PetscInt level)
393: {
395: PetscInt nlevels = dmmg[0]->nlevels;
398: dmmg[0]->nlevels = level+1;
399: SNESSolve(dmmg[level]->snes,PETSC_NULL,dmmg[level]->x);
400: dmmg[0]->nlevels = nlevels;
401: return(0);
402: }
405: EXTERN PetscErrorCode PETSCSNES_DLLEXPORT NLFCreate_DAAD(NLF*);
406: EXTERN PetscErrorCode PETSCSNES_DLLEXPORT NLFRelax_DAAD(NLF,MatSORType,PetscInt,Vec);
407: EXTERN PetscErrorCode PETSCSNES_DLLEXPORT NLFDAADSetDA_DAAD(NLF,DA);
408: EXTERN PetscErrorCode PETSCSNES_DLLEXPORT NLFDAADSetCtx_DAAD(NLF,void*);
409: EXTERN PetscErrorCode PETSCSNES_DLLEXPORT NLFDAADSetResidual_DAAD(NLF,Vec);
410: EXTERN PetscErrorCode PETSCSNES_DLLEXPORT NLFDAADSetNewtonIterations_DAAD(NLF,PetscInt);
413: #if defined(PETSC_HAVE_ADIC)
414: #include src/ksp/pc/impls/mg/mgimpl.h
415: /*
416: This is pre-beta FAS code. It's design should not be taken seriously!
417: */
420: PetscErrorCode DMMGSolveFAS(DMMG *dmmg,PetscInt level)
421: {
423: PetscInt i,j,k;
424: PetscReal norm;
425: PetscScalar zero = 0.0,mone = -1.0,one = 1.0;
426: MG *mg;
427: PC pc;
430: VecSet(dmmg[level]->r,zero);
431: for (j=1; j<=level; j++) {
432: if (!dmmg[j]->inject) {
433: DMGetInjection(dmmg[j-1]->dm,dmmg[j]->dm,&dmmg[j]->inject);
434: }
435: }
437: KSPGetPC(dmmg[level]->ksp,&pc);
438: mg = ((MG*)pc->data);
440: for (i=0; i<100; i++) {
442: for (j=level; j>0; j--) {
444: /* Relax residual_fine - F(x_fine) = 0 */
445: for (k=0; k<dmmg[j]->presmooth; k++) {
446: NLFRelax_DAAD(dmmg[j]->nlf,SOR_SYMMETRIC_SWEEP,1,dmmg[j]->x);
447: }
449: /* R*(residual_fine - F(x_fine)) */
450: DMMGFormFunction(0,dmmg[j]->x,dmmg[j]->w,dmmg[j]);
451: VecAYPX(dmmg[j]->w,mone,dmmg[j]->r);
453: if (j == level || dmmg[j]->monitorall) {
454: /* norm( residual_fine - f(x_fine) ) */
455: VecNorm(dmmg[j]->w,NORM_2,&norm);
456: if (j == level) {
457: if (norm < dmmg[level]->abstol) goto theend;
458: if (i == 0) {
459: dmmg[level]->rrtol = norm*dmmg[level]->rtol;
460: } else {
461: if (norm < dmmg[level]->rrtol) goto theend;
462: }
463: }
464: }
466: if (dmmg[j]->monitorall) {
467: for (k=0; k<level-j+1; k++) {PetscPrintf(dmmg[j]->comm," ");}
468: PetscPrintf(dmmg[j]->comm,"FAS function norm %g\n",norm);
469: }
470: MatRestrict(mg[j]->restrct,dmmg[j]->w,dmmg[j-1]->r);
471:
472: /* F(R*x_fine) */
473: VecScatterBegin(dmmg[j]->x,dmmg[j-1]->x,INSERT_VALUES,SCATTER_FORWARD,dmmg[j]->inject);
474: VecScatterEnd(dmmg[j]->x,dmmg[j-1]->x,INSERT_VALUES,SCATTER_FORWARD,dmmg[j]->inject);
475: DMMGFormFunction(0,dmmg[j-1]->x,dmmg[j-1]->w,dmmg[j-1]);
477: /* residual_coarse = F(R*x_fine) + R*(residual_fine - F(x_fine)) */
478: VecAYPX(dmmg[j-1]->r,one,dmmg[j-1]->w);
480: /* save R*x_fine into b (needed when interpolating compute x back up */
481: VecCopy(dmmg[j-1]->x,dmmg[j-1]->b);
482: }
484: for (j=0; j<dmmg[0]->presmooth; j++) {
485: NLFRelax_DAAD(dmmg[0]->nlf,SOR_SYMMETRIC_SWEEP,1,dmmg[0]->x);
486: }
487: if (dmmg[0]->monitorall){
488: DMMGFormFunction(0,dmmg[0]->x,dmmg[0]->w,dmmg[0]);
489: VecAXPY(dmmg[0]->w,mone,dmmg[0]->r);
490: VecNorm(dmmg[0]->w,NORM_2,&norm);
491: for (k=0; k<level+1; k++) {PetscPrintf(dmmg[0]->comm," ");}
492: PetscPrintf(dmmg[0]->comm,"FAS coarse grid function norm %g\n",norm);
493: }
495: for (j=1; j<=level; j++) {
496: /* x_fine = x_fine + R'*(x_coarse - R*x_fine) */
497: VecAXPY(dmmg[j-1]->x,mone,dmmg[j-1]->b);
498: MatInterpolateAdd(mg[j]->interpolate,dmmg[j-1]->x,dmmg[j]->x,dmmg[j]->x);
500: if (dmmg[j]->monitorall) {
501: /* norm( F(x_fine) - residual_fine ) */
502: DMMGFormFunction(0,dmmg[j]->x,dmmg[j]->w,dmmg[j]);
503: VecAXPY(dmmg[j]->w,mone,dmmg[j]->r);
504: VecNorm(dmmg[j]->w,NORM_2,&norm);
505: for (k=0; k<level-j+1; k++) {PetscPrintf(dmmg[j]->comm," ");}
506: PetscPrintf(dmmg[j]->comm,"FAS function norm %g\n",norm);
507: }
509: /* Relax residual_fine - F(x_fine) = 0 */
510: for (k=0; k<dmmg[j]->postsmooth; k++) {
511: NLFRelax_DAAD(dmmg[j]->nlf,SOR_SYMMETRIC_SWEEP,1,dmmg[j]->x);
512: }
514: if (dmmg[j]->monitorall) {
515: /* norm( F(x_fine) - residual_fine ) */
516: DMMGFormFunction(0,dmmg[j]->x,dmmg[j]->w,dmmg[j]);
517: VecAXPY(dmmg[j]->w,mone,dmmg[j]->r);
518: VecNorm(dmmg[j]->w,NORM_2,&norm);
519: for (k=0; k<level-j+1; k++) {PetscPrintf(dmmg[j]->comm," ");}
520: PetscPrintf(dmmg[j]->comm,"FAS function norm %g\n",norm);
521: }
522: }
524: if (dmmg[level]->monitor){
525: DMMGFormFunction(0,dmmg[level]->x,dmmg[level]->w,dmmg[level]);
526: VecNorm(dmmg[level]->w,NORM_2,&norm);
527: PetscPrintf(dmmg[level]->comm,"%D FAS function norm %g\n",i,norm);
528: }
529: }
530: theend:
531: return(0);
532: }
533: #endif
535: /* ===========================================================================================================*/
539: /*@C
540: DMMGSetSNES - Sets the nonlinear function that defines the nonlinear set of equations
541: to be solved using the grid hierarchy.
543: Collective on DMMG
545: Input Parameter:
546: + dmmg - the context
547: . function - the function that defines the nonlinear system
548: - jacobian - optional function to compute Jacobian
550: Options Database Keys:
551: + -dmmg_snes_monitor
552: . -dmmg_jacobian_fd
553: . -dmmg_jacobian_ad
554: . -dmmg_jacobian_mf_fd_operator
555: . -dmmg_jacobian_mf_fd
556: . -dmmg_jacobian_mf_ad_operator
557: . -dmmg_jacobian_mf_ad
558: - -dmmg_jacobian_period <p> - Indicates how often in the SNES solve the Jacobian is recomputed (on all levels)
559: as suggested by Florin Dobrian if p is -1 then Jacobian is computed only on first
560: SNES iteration (i.e. -1 is equivalent to infinity)
562: Level: advanced
564: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNESLocal()
566: @*/
567: PetscErrorCode PETSCSNES_DLLEXPORT DMMGSetSNES(DMMG *dmmg,PetscErrorCode (*function)(SNES,Vec,Vec,void*),PetscErrorCode (*jacobian)(SNES,Vec,Mat*,Mat*,MatStructure*,void*))
568: {
570: PetscMPIInt size;
571: PetscInt i,nlevels = dmmg[0]->nlevels,period = 1;
572: PetscTruth snesmonitor,mffdoperator,mffd,fdjacobian;
573: #if defined(PETSC_HAVE_ADIC)
574: PetscTruth mfadoperator,mfad,adjacobian;
575: #endif
576: PetscViewer ascii;
577: MPI_Comm comm;
580: if (!dmmg) SETERRQ(PETSC_ERR_ARG_NULL,"Passing null as DMMG");
581: if (!jacobian) jacobian = DMMGComputeJacobianWithFD;
583: PetscOptionsBegin(dmmg[0]->comm,PETSC_NULL,"DMMG Options","SNES");
584: PetscOptionsName("-dmmg_snes_monitor","Monitor nonlinear convergence","SNESSetMonitor",&snesmonitor);
587: PetscOptionsName("-dmmg_jacobian_fd","Compute sparse Jacobian explicitly with finite differencing","DMMGSetSNES",&fdjacobian);
588: if (fdjacobian) jacobian = DMMGComputeJacobianWithFD;
589: #if defined(PETSC_HAVE_ADIC)
590: PetscOptionsName("-dmmg_jacobian_ad","Compute sparse Jacobian explicitly with ADIC (automatic differentiation)","DMMGSetSNES",&adjacobian);
591: if (adjacobian) jacobian = DMMGComputeJacobianWithAdic;
592: #endif
594: PetscOptionsTruthGroupBegin("-dmmg_jacobian_mf_fd_operator","Apply Jacobian via matrix free finite differencing","DMMGSetSNES",&mffdoperator);
595: PetscOptionsTruthGroupEnd("-dmmg_jacobian_mf_fd","Apply Jacobian via matrix free finite differencing even in computing preconditioner","DMMGSetSNES",&mffd);
596: if (mffd) mffdoperator = PETSC_TRUE;
597: #if defined(PETSC_HAVE_ADIC)
598: PetscOptionsTruthGroupBegin("-dmmg_jacobian_mf_ad_operator","Apply Jacobian via matrix free ADIC (automatic differentiation)","DMMGSetSNES",&mfadoperator);
599: PetscOptionsTruthGroupEnd("-dmmg_jacobian_mf_ad","Apply Jacobian via matrix free ADIC (automatic differentiation) even in computing preconditioner","DMMGSetSNES",&mfad);
600: if (mfad) mfadoperator = PETSC_TRUE;
601: #endif
602: PetscOptionsEnd();
604: /* create solvers for each level */
605: for (i=0; i<nlevels; i++) {
606: SNESCreate(dmmg[i]->comm,&dmmg[i]->snes);
607: SNESGetKSP(dmmg[i]->snes,&dmmg[i]->ksp);
608: if (snesmonitor) {
609: PetscObjectGetComm((PetscObject)dmmg[i]->snes,&comm);
610: PetscViewerASCIIOpen(comm,"stdout",&ascii);
611: PetscViewerASCIISetTab(ascii,nlevels-i);
612: SNESSetMonitor(dmmg[i]->snes,SNESDefaultMonitor,ascii,(PetscErrorCode(*)(void*))PetscViewerDestroy);
613: }
615: if (mffdoperator) {
616: MatCreateSNESMF(dmmg[i]->snes,dmmg[i]->x,&dmmg[i]->J);
617: VecDuplicate(dmmg[i]->x,&dmmg[i]->work1);
618: VecDuplicate(dmmg[i]->x,&dmmg[i]->work2);
619: MatSNESMFSetFunction(dmmg[i]->J,dmmg[i]->work1,function,dmmg[i]);
620: if (mffd) {
621: dmmg[i]->B = dmmg[i]->J;
622: jacobian = DMMGComputeJacobianWithMF;
623: }
624: #if defined(PETSC_HAVE_ADIC)
625: } else if (mfadoperator) {
626: MatRegisterDAAD();
627: MatCreateDAAD((DA)dmmg[i]->dm,&dmmg[i]->J);
628: MatDAADSetCtx(dmmg[i]->J,dmmg[i]->user);
629: if (mfad) {
630: dmmg[i]->B = dmmg[i]->J;
631: jacobian = DMMGComputeJacobianWithMF;
632: }
633: #endif
634: }
635:
636: if (!dmmg[i]->B) {
637: MPI_Comm_size(dmmg[i]->comm,&size);
638: DMGetMatrix(dmmg[i]->dm,MATAIJ,&dmmg[i]->B);
639: }
640: if (!dmmg[i]->J) {
641: dmmg[i]->J = dmmg[i]->B;
642: }
644: DMMGSetUpLevel(dmmg,dmmg[i]->ksp,i+1);
645:
646: /*
647: if the number of levels is > 1 then we want the coarse solve in the grid sequencing to use LU
648: when possible
649: */
650: if (nlevels > 1 && i == 0) {
651: PC pc;
652: KSP cksp;
653: PetscTruth flg1,flg2,flg3;
655: KSPGetPC(dmmg[i]->ksp,&pc);
656: PCMGGetCoarseSolve(pc,&cksp);
657: KSPGetPC(cksp,&pc);
658: PetscTypeCompare((PetscObject)pc,PCILU,&flg1);
659: PetscTypeCompare((PetscObject)pc,PCSOR,&flg2);
660: PetscTypeCompare((PetscObject)pc,PETSC_NULL,&flg3);
661: if (flg1 || flg2 || flg3) {
662: PCSetType(pc,PCLU);
663: }
664: }
666: dmmg[i]->solve = DMMGSolveSNES;
667: dmmg[i]->computejacobian = jacobian;
668: dmmg[i]->computefunction = function;
669: }
671: if (jacobian == DMMGComputeJacobianWithFD) {
672: ISColoring iscoloring;
673: for (i=0; i<nlevels; i++) {
674: DMGetColoring(dmmg[i]->dm,IS_COLORING_LOCAL,&iscoloring);
675: MatFDColoringCreate(dmmg[i]->B,iscoloring,&dmmg[i]->fdcoloring);
676: ISColoringDestroy(iscoloring);
677: MatFDColoringSetFunction(dmmg[i]->fdcoloring,(PetscErrorCode(*)(void))function,dmmg[i]);
678: MatFDColoringSetFromOptions(dmmg[i]->fdcoloring);
679: }
680: #if defined(PETSC_HAVE_ADIC)
681: } else if (jacobian == DMMGComputeJacobianWithAdic) {
682: for (i=0; i<nlevels; i++) {
683: ISColoring iscoloring;
684: DMGetColoring(dmmg[i]->dm,IS_COLORING_GHOSTED,&iscoloring);
685: MatSetColoring(dmmg[i]->B,iscoloring);
686: ISColoringDestroy(iscoloring);
687: }
688: #endif
689: }
691: for (i=0; i<nlevels; i++) {
692: SNESSetJacobian(dmmg[i]->snes,dmmg[i]->J,dmmg[i]->B,DMMGComputeJacobian_Multigrid,dmmg);
693: SNESSetFunction(dmmg[i]->snes,dmmg[i]->b,function,dmmg[i]);
694: SNESSetFromOptions(dmmg[i]->snes);
695: }
697: /* Create interpolation scaling */
698: for (i=1; i<nlevels; i++) {
699: DMGetInterpolationScale(dmmg[i-1]->dm,dmmg[i]->dm,dmmg[i]->R,&dmmg[i]->Rscale);
700: }
702: PetscOptionsGetInt(PETSC_NULL,"-dmmg_jacobian_period",&period,PETSC_NULL);
703: for (i=0; i<nlevels; i++) {
704: dmmg[i]->updatejacobian = PETSC_TRUE;
705: dmmg[i]->updatejacobianperiod = period;
706: }
708: #if defined(PETSC_HAVE_ADIC)
709: {
710: PetscTruth flg;
711: PetscOptionsHasName(PETSC_NULL,"-dmmg_fas",&flg);
712: if (flg) {
713: PetscInt newton_its;
714: PetscOptionsHasName(0,"-dmmg_fas_view",&flg);
715: for (i=0; i<nlevels; i++) {
716: NLFCreate_DAAD(&dmmg[i]->nlf);
717: NLFDAADSetDA_DAAD(dmmg[i]->nlf,(DA)dmmg[i]->dm);
718: NLFDAADSetCtx_DAAD(dmmg[i]->nlf,dmmg[i]->user);
719: NLFDAADSetResidual_DAAD(dmmg[i]->nlf,dmmg[i]->r);
720: VecDuplicate(dmmg[i]->b,&dmmg[i]->w);
722: dmmg[i]->monitor = PETSC_FALSE;
723: PetscOptionsHasName(0,"-dmmg_fas_monitor",&dmmg[i]->monitor);
724: dmmg[i]->monitorall = PETSC_FALSE;
725: PetscOptionsHasName(0,"-dmmg_fas_monitor_all",&dmmg[i]->monitorall);
726: dmmg[i]->presmooth = 2;
727: PetscOptionsGetInt(0,"-dmmg_fas_presmooth",&dmmg[i]->presmooth,0);
728: dmmg[i]->postsmooth = 2;
729: PetscOptionsGetInt(0,"-dmmg_fas_postsmooth",&dmmg[i]->postsmooth,0);
730: dmmg[i]->coarsesmooth = 2;
731: PetscOptionsGetInt(0,"-dmmg_fas_coarsesmooth",&dmmg[i]->coarsesmooth,0);
733: dmmg[i]->rtol = 1.e-8;
734: PetscOptionsGetReal(0,"-dmmg_fas_rtol",&dmmg[i]->rtol,0);
735: dmmg[i]->abstol = 1.e-50;
736: PetscOptionsGetReal(0,"-dmmg_fas_atol",&dmmg[i]->abstol,0);
738: newton_its = 2;
739: PetscOptionsGetInt(0,"-dmmg_fas_newton_its",&newton_its,0);
740: NLFDAADSetNewtonIterations_DAAD(dmmg[i]->nlf,newton_its);
742: if (flg) {
743: if (i == 0) {
744: PetscPrintf(dmmg[i]->comm,"FAS Solver Parameters\n");
745: PetscPrintf(dmmg[i]->comm," rtol %g atol %g\n",dmmg[i]->rtol,dmmg[i]->abstol);
746: PetscPrintf(dmmg[i]->comm," coarsesmooths %D\n",dmmg[i]->coarsesmooth);
747: PetscPrintf(dmmg[i]->comm," Newton iterations %D\n",newton_its);
748: } else {
749: PetscPrintf(dmmg[i]->comm," level %D presmooths %D\n",i,dmmg[i]->presmooth);
750: PetscPrintf(dmmg[i]->comm," postsmooths %D\n",dmmg[i]->postsmooth);
751: PetscPrintf(dmmg[i]->comm," Newton iterations %D\n",newton_its);
752: }
753: }
754: dmmg[i]->solve = DMMGSolveFAS;
755: }
756: }
757: }
758: #endif
759:
760: return(0);
761: }
763: /*M
764: DMMGSetSNESLocal - Sets the local user function that defines the nonlinear set of equations
765: that will use the grid hierarchy and (optionally) its derivative.
767: Collective on DMMG
769: Synopsis:
770: PetscErrorCode DMMGSetSNESLocal(DMMG *dmmg,DALocalFunction1 function, DALocalFunction1 jacobian,
771: DALocalFunction1 ad_function, DALocalFunction1 admf_function);
773: Input Parameter:
774: + dmmg - the context
775: . function - the function that defines the nonlinear system
776: . jacobian - function defines the local part of the Jacobian
777: . ad_function - the name of the function with an ad_ prefix. This is ignored if ADIC is
778: not installed
779: - admf_function - the name of the function with an ad_ prefix. This is ignored if ADIC is
780: not installed
782: Options Database Keys:
783: + -dmmg_snes_monitor
784: . -dmmg_jacobian_fd
785: . -dmmg_jacobian_ad
786: . -dmmg_jacobian_mf_fd_operator
787: . -dmmg_jacobian_mf_fd
788: . -dmmg_jacobian_mf_ad_operator
789: . -dmmg_jacobian_mf_ad
790: - -dmmg_jacobian_period <p> - Indicates how often in the SNES solve the Jacobian is recomputed (on all levels)
791: as suggested by Florin Dobrian if p is -1 then Jacobian is computed only on first
792: SNES iteration (i.e. -1 is equivalent to infinity)
795: Level: intermediate
797: Notes:
798: If ADIC or ADIFOR have been installed, this routine can use ADIC or ADIFOR to compute
799: the derivative; however, that function cannot call other functions except those in
800: standard C math libraries.
802: If ADIC/ADIFOR have not been installed and the Jacobian is not provided, this routine
803: uses finite differencing to approximate the Jacobian.
805: .seealso DMMGCreate(), DMMGDestroy, DMMGSetKSP(), DMMGSetSNES()
807: M*/
811: PetscErrorCode DMMGSetSNESLocal_Private(DMMG *dmmg,DALocalFunction1 function,DALocalFunction1 jacobian,DALocalFunction1 ad_function,DALocalFunction1 admf_function)
812: {
814: PetscInt i,nlevels = dmmg[0]->nlevels;
815: PetscErrorCode (*computejacobian)(SNES,Vec,Mat*,Mat*,MatStructure*,void*) = 0;
819: if (jacobian) computejacobian = DMMGComputeJacobian;
820: #if defined(PETSC_HAVE_ADIC)
821: else if (ad_function) computejacobian = DMMGComputeJacobianWithAdic;
822: #endif
824: DMMGSetSNES(dmmg,DMMGFormFunction,computejacobian);
825: for (i=0; i<nlevels; i++) {
826: DASetLocalFunction((DA)dmmg[i]->dm,function);
827: DASetLocalJacobian((DA)dmmg[i]->dm,jacobian);
828: DASetLocalAdicFunction((DA)dmmg[i]->dm,ad_function);
829: DASetLocalAdicMFFunction((DA)dmmg[i]->dm,admf_function);
830: }
831: return(0);
832: }
836: static PetscErrorCode DMMGFunctioni(PetscInt i,Vec u,PetscScalar* r,void* ctx)
837: {
838: DMMG dmmg = (DMMG)ctx;
839: Vec U = dmmg->lwork1;
841: VecScatter gtol;
844: /* copy u into interior part of U */
845: DAGetScatter((DA)dmmg->dm,0,>ol,0);
846: VecScatterBegin(u,U,INSERT_VALUES,SCATTER_FORWARD_LOCAL,gtol);
847: VecScatterEnd(u,U,INSERT_VALUES,SCATTER_FORWARD_LOCAL,gtol);
848: DAFormFunctioni1((DA)dmmg->dm,i,U,r,dmmg->user);
849: return(0);
850: }
854: static PetscErrorCode DMMGFunctioniBase(Vec u,void* ctx)
855: {
856: DMMG dmmg = (DMMG)ctx;
857: Vec U = dmmg->lwork1;
861: DAGlobalToLocalBegin((DA)dmmg->dm,u,INSERT_VALUES,U);
862: DAGlobalToLocalEnd((DA)dmmg->dm,u,INSERT_VALUES,U);
863: return(0);
864: }
868: 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*))
869: {
871: PetscInt i,nlevels = dmmg[0]->nlevels;
874: for (i=0; i<nlevels; i++) {
875: DASetLocalFunctioni((DA)dmmg[i]->dm,functioni);
876: DASetLocalAdicFunctioni((DA)dmmg[i]->dm,adi);
877: DASetLocalAdicMFFunctioni((DA)dmmg[i]->dm,adimf);
878: MatSNESMFSetFunctioni(dmmg[i]->J,DMMGFunctioni);
879: MatSNESMFSetFunctioniBase(dmmg[i]->J,DMMGFunctioniBase);
880: DACreateLocalVector((DA)dmmg[i]->dm,&dmmg[i]->lwork1);
881: }
882: return(0);
883: }
886: #if defined(PETSC_HAVE_ADIC)
888: #include "adic/ad_utils.h"
893: PetscErrorCode PetscADView(PetscInt N,PetscInt nc,double *ptr,PetscViewer viewer)
894: {
895: PetscInt i,j,nlen = PetscADGetDerivTypeSize();
896: char *cptr = (char*)ptr;
897: double *values;
901: for (i=0; i<N; i++) {
902: PetscPrintf(PETSC_COMM_SELF,"Element %D value %g derivatives: ",i,*(double*)cptr);
903: values = PetscADGetGradArray(cptr);
904: for (j=0; j<nc; j++) {
905: PetscPrintf(PETSC_COMM_SELF,"%g ",*values++);
906: }
907: PetscPrintf(PETSC_COMM_SELF,"\n");
908: cptr += nlen;
909: }
911: return(0);
912: }
914: #endif