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,&gtol,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,&gtol,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: }