Actual source code: snesmfj.c

 2:  #include src/mat/matimpl.h
 3:  #include src/snes/mf/snesmfj.h

  5: PetscFList MatSNESMPetscFList         = 0;
  6: PetscTruth MatSNESMFRegisterAllCalled = PETSC_FALSE;

 10: /*@C
 11:     MatSNESMFSetType - Sets the method that is used to compute the 
 12:     differencing parameter for finite differene matrix-free formulations. 

 14:     Input Parameters:
 15: +   mat - the "matrix-free" matrix created via MatCreateSNESMF(), or MatCreateMF()
 16:           or MatSetType(mat,MATMFFD);
 17: -   ftype - the type requested

 19:     Level: advanced

 21:     Notes:
 22:     For example, such routines can compute h for use in
 23:     Jacobian-vector products of the form

 25:                         F(x+ha) - F(x)
 26:           F'(u)a  ~=  ----------------
 27:                               h

 29: .seealso: MatCreateSNESMF(), MatSNESMFRegisterDynamic)
 30: @*/
 31: PetscErrorCode MatSNESMFSetType(Mat mat,const MatSNESMFType ftype)
 32: {
 33:   PetscErrorCode ierr,(*r)(MatSNESMFCtx);
 34:   MatSNESMFCtx   ctx = (MatSNESMFCtx)mat->data;
 35:   PetscTruth     match;
 36: 

 41:   /* already set, so just return */
 42:   PetscTypeCompare((PetscObject)ctx,ftype,&match);
 43:   if (match) return(0);

 45:   /* destroy the old one if it exists */
 46:   if (ctx->ops->destroy) {
 47:     (*ctx->ops->destroy)(ctx);
 48:   }

 50:   /* Get the function pointers for the requrested method */
 51:   if (!MatSNESMFRegisterAllCalled) {MatSNESMFRegisterAll(PETSC_NULL);}
 52:    PetscFListFind(ctx->comm,MatSNESMPetscFList,ftype,(void (**)(void)) &r);
 53:   if (!r) SETERRQ1(PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown MatSNESMF type %s given",ftype);
 54:   (*r)(ctx);
 55:   PetscObjectChangeTypeName((PetscObject)ctx,ftype);
 56:   return(0);
 57: }

 63: PetscErrorCode MatSNESMFSetFunctioniBase_FD(Mat mat,FCN1 func)
 64: {
 65:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

 68:   ctx->funcisetbase = func;
 69:   return(0);
 70: }

 77: PetscErrorCode MatSNESMFSetFunctioni_FD(Mat mat,FCN2 funci)
 78: {
 79:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

 82:   ctx->funci = funci;
 83:   return(0);
 84: }


 90: PetscErrorCode MatSNESMFRegister(const char sname[],const char path[],const char name[],PetscErrorCode (*function)(MatSNESMFCtx))
 91: {
 93:   char           fullname[PETSC_MAX_PATH_LEN];

 96:   PetscFListConcat(path,name,fullname);
 97:   PetscFListAdd(&MatSNESMPetscFList,sname,fullname,(void (*)(void))function);
 98:   return(0);
 99: }


104: /*@C
105:    MatSNESMFRegisterDestroy - Frees the list of MatSNESMF methods that were
106:    registered by MatSNESMFRegisterDynamic).

108:    Not Collective

110:    Level: developer

112: .keywords: MatSNESMF, register, destroy

114: .seealso: MatSNESMFRegisterDynamic), MatSNESMFRegisterAll()
115: @*/
116: PetscErrorCode MatSNESMFRegisterDestroy(void)
117: {

121:   if (MatSNESMPetscFList) {
122:     PetscFListDestroy(&MatSNESMPetscFList);
123:     MatSNESMPetscFList = 0;
124:   }
125:   MatSNESMFRegisterAllCalled = PETSC_FALSE;
126:   return(0);
127: }

129: /* ----------------------------------------------------------------------------------------*/
132: PetscErrorCode MatDestroy_MFFD(Mat mat)
133: {
135:   MatSNESMFCtx   ctx = (MatSNESMFCtx)mat->data;

138:   if (ctx->w != PETSC_NULL) {
139:     VecDestroy(ctx->w);
140:   }
141:   if (ctx->ops->destroy) {(*ctx->ops->destroy)(ctx);}
142:   if (ctx->sp) {MatNullSpaceDestroy(ctx->sp);}
143:   PetscHeaderDestroy(ctx);

145:   PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetBase_C","",PETSC_NULL);
146:   PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetFunctioniBase_C","",PETSC_NULL);
147:   PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetFunctioni_C","",PETSC_NULL);
148:   PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetCheckh_C","",PETSC_NULL);

150:   return(0);
151: }

155: /*
156:    MatSNESMFView_MFFD - Views matrix-free parameters.

158: */
159: PetscErrorCode MatView_MFFD(Mat J,PetscViewer viewer)
160: {
162:   MatSNESMFCtx   ctx = (MatSNESMFCtx)J->data;
163:   PetscTruth     iascii;

166:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
167:   if (iascii) {
168:      PetscViewerASCIIPrintf(viewer,"  SNES matrix-free approximation:\n");
169:      PetscViewerASCIIPrintf(viewer,"    err=%g (relative error in function evaluation)\n",ctx->error_rel);
170:      if (!ctx->type_name) {
171:        PetscViewerASCIIPrintf(viewer,"    The compute h routine has not yet been set\n");
172:      } else {
173:        PetscViewerASCIIPrintf(viewer,"    Using %s compute h routine\n",ctx->type_name);
174:      }
175:      if (ctx->ops->view) {
176:        (*ctx->ops->view)(ctx,viewer);
177:      }
178:   } else {
179:     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for SNES matrix free matrix",((PetscObject)viewer)->type_name);
180:   }
181:   return(0);
182: }

186: /*
187:    MatAssemblyEnd_MFFD - Resets the ctx->ncurrenth to zero. This 
188:    allows the user to indicate the beginning of a new linear solve by calling
189:    MatAssemblyXXX() on the matrix free matrix. This then allows the 
190:    MatSNESMFCreate_WP() to properly compute ||U|| only the first time
191:    in the linear solver rather than every time.
192: */
193: PetscErrorCode MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt)
194: {
196:   MatSNESMFCtx   j = (MatSNESMFCtx)J->data;

199:   MatSNESMFResetHHistory(J);
200:   if (j->usesnes) {
201:     SNESGetSolution(j->snes,&j->current_u);
202:     SNESGetFunction(j->snes,&j->current_f,PETSC_NULL,PETSC_NULL);
203:     if (!j->w) {
204:       VecDuplicate(j->current_u, &j->w);
205:     }
206:   }
207:   j->vshift = 0.0;
208:   j->vscale = 1.0;
209:   return(0);
210: }

214: /*
215:   MatMult_MFFD - Default matrix-free form for Jacobian-vector product, y = F'(u)*a:

217:         y ~= (F(u + ha) - F(u))/h, 
218:   where F = nonlinear function, as set by SNESSetFunction()
219:         u = current iterate
220:         h = difference interval
221: */
222: PetscErrorCode MatMult_MFFD(Mat mat,Vec a,Vec y)
223: {
224:   MatSNESMFCtx    ctx = (MatSNESMFCtx)mat->data;
225:   SNES            snes;
226:   PetscScalar     h,mone = -1.0;
227:   Vec             w,U,F;
228:   PetscErrorCode ierr,(*eval_fct)(SNES,Vec,Vec)=0;

231:   /* We log matrix-free matrix-vector products separately, so that we can
232:      separate the performance monitoring from the cases that use conventional
233:      storage.  We may eventually modify event logging to associate events
234:      with particular objects, hence alleviating the more general problem. */
235:   PetscLogEventBegin(MAT_MultMatrixFree,a,y,0,0);

237:   snes = ctx->snes;
238:   w    = ctx->w;
239:   U    = ctx->current_u;

241:   /* 
242:       Compute differencing parameter 
243:   */
244:   if (!ctx->ops->compute) {
245:     MatSNESMFSetType(mat,MATSNESMF_WP);
246:     MatSNESMFSetFromOptions(mat);
247:   }
248:   (*ctx->ops->compute)(ctx,U,a,&h);

250:   if (ctx->checkh) {
251:     (*ctx->checkh)(U,a,&h,ctx->checkhctx);
252:   }

254:   /* keep a record of the current differencing parameter h */
255:   ctx->currenth = h;
256: #if defined(PETSC_USE_COMPLEX)
257:   PetscLogInfo(mat,"MatMult_MFFD:Current differencing parameter: %g + %g i\n",PetscRealPart(h),PetscImaginaryPart(h));
258: #else
259:   PetscLogInfo(mat,"MatMult_MFFD:Current differencing parameter: %15.12e\n",h);
260: #endif
261:   if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
262:     ctx->historyh[ctx->ncurrenth] = h;
263:   }
264:   ctx->ncurrenth++;

266:   /* w = u + ha */
267:   VecWAXPY(&h,a,U,w);

269:   if (ctx->usesnes) {
270:     eval_fct = SNESComputeFunction;
271:     F    = ctx->current_f;
272:     if (!F) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"You must call MatAssembly() even on matrix-free matrices");
273:     (*eval_fct)(snes,w,y);
274:   } else {
275:     F = ctx->funcvec;
276:     /* compute func(U) as base for differencing */
277:     if (ctx->ncurrenth == 1) {
278:       (*ctx->func)(snes,U,F,ctx->funcctx);
279:     }
280:     (*ctx->func)(snes,w,y,ctx->funcctx);
281:   }

283:   VecAXPY(&mone,F,y);
284:   h    = 1.0/h;
285:   VecScale(&h,y);

287:   VecAXPBY(&ctx->vshift,&ctx->vscale,a,y);

289:   if (ctx->sp) {MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);}

291:   PetscLogEventEnd(MAT_MultMatrixFree,a,y,0,0);
292:   return(0);
293: }

297: /*
298:   MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix

300:         y ~= (F(u + ha) - F(u))/h, 
301:   where F = nonlinear function, as set by SNESSetFunction()
302:         u = current iterate
303:         h = difference interval
304: */
305: PetscErrorCode MatGetDiagonal_MFFD(Mat mat,Vec a)
306: {
307:   MatSNESMFCtx   ctx = (MatSNESMFCtx)mat->data;
308:   PetscScalar    h,*aa,*ww,v;
309:   PetscReal      epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
310:   Vec            w,U;
312:   PetscInt       i,rstart,rend;

315:   if (!ctx->funci) {
316:     SETERRQ(PETSC_ERR_ORDER,"Requires calling MatSNESMFSetFunctioni() first");
317:   }

319:   w    = ctx->w;
320:   U    = ctx->current_u;
321:   (*ctx->func)(0,U,a,ctx->funcctx);
322:   (*ctx->funcisetbase)(U,ctx->funcctx);
323:   VecCopy(U,w);

325:   VecGetOwnershipRange(a,&rstart,&rend);
326:   VecGetArray(a,&aa);
327:   for (i=rstart; i<rend; i++) {
328:     VecGetArray(w,&ww);
329:     h  = ww[i-rstart];
330:     if (h == 0.0) h = 1.0;
331: #if !defined(PETSC_USE_COMPLEX)
332:     if (h < umin && h >= 0.0)      h = umin;
333:     else if (h < 0.0 && h > -umin) h = -umin;
334: #else
335:     if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0)     h = umin;
336:     else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
337: #endif
338:     h     *= epsilon;
339: 
340:     ww[i-rstart] += h;
341:     VecRestoreArray(w,&ww);
342:     (*ctx->funci)(i,w,&v,ctx->funcctx);
343:     aa[i-rstart]  = (v - aa[i-rstart])/h;

345:     /* possibly shift and scale result */
346:     aa[i - rstart] = ctx->vshift + ctx->vscale*aa[i-rstart];

348:     VecGetArray(w,&ww);
349:     ww[i-rstart] -= h;
350:     VecRestoreArray(w,&ww);
351:   }
352:   VecRestoreArray(a,&aa);
353:   return(0);
354: }

358: PetscErrorCode MatShift_MFFD(const PetscScalar *a,Mat Y)
359: {
360:   MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
362:   shell->vshift += *a;
363:   return(0);
364: }

368: PetscErrorCode MatScale_MFFD(const PetscScalar *a,Mat Y)
369: {
370:   MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
372:   shell->vscale *= *a;
373:   return(0);
374: }


379: /*@C
380:    MatCreateSNESMF - Creates a matrix-free matrix context for use with
381:    a SNES solver.  This matrix can be used as the Jacobian argument for
382:    the routine SNESSetJacobian().

384:    Collective on SNES and Vec

386:    Input Parameters:
387: +  snes - the SNES context
388: -  x - vector where SNES solution is to be stored.

390:    Output Parameter:
391: .  J - the matrix-free matrix

393:    Level: advanced

395:    Notes:
396:    The matrix-free matrix context merely contains the function pointers
397:    and work space for performing finite difference approximations of
398:    Jacobian-vector products, F'(u)*a, 

400:    The default code uses the following approach to compute h

402: .vb
403:      F'(u)*a = [F(u+h*a) - F(u)]/h where
404:      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
405:        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
406:  where
407:      error_rel = square root of relative error in function evaluation
408:      umin = minimum iterate parameter
409: .ve

411:    The user can set the error_rel via MatSNESMFSetFunctionError() and 
412:    umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
413:    of the users manual for details.

415:    The user should call MatDestroy() when finished with the matrix-free
416:    matrix context.

418:    Options Database Keys:
419: +  -snes_mf_err <error_rel> - Sets error_rel
420: .  -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
421: -  -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h

423: .keywords: SNES, default, matrix-free, create, matrix

425: .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
426:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateMF(),
427:           MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic), MatSNESMFComputeJacobian()
428:  
429: @*/
430: PetscErrorCode MatCreateSNESMF(SNES snes,Vec x,Mat *J)
431: {
432:   MatSNESMFCtx   mfctx;

436:   MatCreateMF(x,J);

438:   mfctx          = (MatSNESMFCtx)(*J)->data;
439:   mfctx->snes    = snes;
440:   mfctx->usesnes = PETSC_TRUE;
441:   PetscLogObjectParent(snes,*J);
442:   return(0);
443: }

448: PetscErrorCode MatSNESMFSetBase_FD(Mat J,Vec U)
449: {
451:   MatSNESMFCtx   ctx = (MatSNESMFCtx)J->data;

454:   MatSNESMFResetHHistory(J);
455:   ctx->current_u = U;
456:   ctx->usesnes   = PETSC_FALSE;
457:   if (!ctx->w) {
458:     VecDuplicate(ctx->current_u, &ctx->w);
459:   }
460:   J->assembled = PETSC_TRUE;
461:   return(0);
462: }

469: PetscErrorCode MatSNESMFSetCheckh_FD(Mat J,FCN3 fun,void*ectx)
470: {
471:   MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;

474:   ctx->checkh    = fun;
475:   ctx->checkhctx = ectx;
476:   return(0);
477: }

482: /*@
483:    MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line
484:    parameter.

486:    Collective on Mat

488:    Input Parameters:
489: .  mat - the matrix obtained with MatCreateSNESMF()

491:    Options Database Keys:
492: +  -snes_mf_type - <default,wp>
493: -  -snes_mf_err - square root of estimated relative error in function evaluation
494: -  -snes_mf_period - how often h is recomputed, defaults to 1, everytime

496:    Level: advanced

498: .keywords: SNES, matrix-free, parameters

500: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(), 
501:           MatSNESMFResetHHistory(), MatSNESMFKSPMonitor()
502: @*/
503: PetscErrorCode MatSNESMFSetFromOptions(Mat mat)
504: {
505:   MatSNESMFCtx   mfctx = (MatSNESMFCtx)mat->data;
507:   PetscTruth     flg;
508:   char           ftype[256];

511:   if (!MatSNESMFRegisterAllCalled) {MatSNESMFRegisterAll(PETSC_NULL);}
512: 
513:   PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatSNESMF");
514:   PetscOptionsList("-snes_mf_type","Matrix free type","MatSNESMFSetType",MatSNESMPetscFList,mfctx->type_name,ftype,256,&flg);
515:   if (flg) {
516:     MatSNESMFSetType(mat,ftype);
517:   }

519:   PetscOptionsReal("-snes_mf_err","set sqrt relative error in function","MatSNESMFSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);
520:   PetscOptionsInt("-snes_mf_period","how often h is recomputed","MatSNESMFSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);
521:   if (mfctx->snes) {
522:     PetscOptionsName("-snes_mf_ksp_monitor","Monitor matrix-free parameters","MatSNESMFKSPMonitor",&flg);
523:     if (flg) {
524:       KSP ksp;
525:       SNESGetKSP(mfctx->snes,&ksp);
526:       KSPSetMonitor(ksp,MatSNESMFKSPMonitor,PETSC_NULL,0);
527:     }
528:   }
529:   PetscOptionsName("-snes_mf_check_positivity","Insure that U + h*a is nonnegative","MatSNESMFSetCheckh",&flg);
530:   if (flg) {
531:     MatSNESMFSetCheckh(mat,MatSNESMFCheckPositivity,0);
532:   }
533:   if (mfctx->ops->setfromoptions) {
534:     (*mfctx->ops->setfromoptions)(mfctx);
535:   }
536:   PetscOptionsEnd();
537:   return(0);
538: }

540: /*MC
541:   MATMFFD - MATMFFD = "mffd" - A matrix free matrix type.

543:   Level: advanced

545: .seealso: MatCreateMF(), MatCreateSNESMF()
546: M*/
550: PetscErrorCode MatCreate_MFFD(Mat A)
551: {
552:   MatSNESMFCtx mfctx;

556: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
557:   SNESInitializePackage(PETSC_NULL);
558: #endif

560:   PetscHeaderCreate(mfctx,_p_MatSNESMFCtx,struct _MFOps,MATSNESMFCTX_COOKIE,0,"SNESMF",A->comm,MatDestroy_MFFD,MatView_MFFD);
561:   PetscLogObjectCreate(mfctx);
562:   mfctx->sp              = 0;
563:   mfctx->snes            = 0;
564:   mfctx->error_rel       = PETSC_SQRT_MACHINE_EPSILON;
565:   mfctx->recomputeperiod = 1;
566:   mfctx->count           = 0;
567:   mfctx->currenth        = 0.0;
568:   mfctx->historyh        = PETSC_NULL;
569:   mfctx->ncurrenth       = 0;
570:   mfctx->maxcurrenth     = 0;
571:   mfctx->type_name       = 0;
572:   mfctx->usesnes         = PETSC_FALSE;

574:   mfctx->vshift          = 0.0;
575:   mfctx->vscale          = 1.0;

577:   /* 
578:      Create the empty data structure to contain compute-h routines.
579:      These will be filled in below from the command line options or 
580:      a later call with MatSNESMFSetType() or if that is not called 
581:      then it will default in the first use of MatMult_MFFD()
582:   */
583:   mfctx->ops->compute        = 0;
584:   mfctx->ops->destroy        = 0;
585:   mfctx->ops->view           = 0;
586:   mfctx->ops->setfromoptions = 0;
587:   mfctx->hctx                = 0;

589:   mfctx->func                = 0;
590:   mfctx->funcctx             = 0;
591:   mfctx->funcvec             = 0;
592:   mfctx->w                   = PETSC_NULL;

594:   A->data                = mfctx;

596:   A->ops->mult           = MatMult_MFFD;
597:   A->ops->destroy        = MatDestroy_MFFD;
598:   A->ops->view           = MatView_MFFD;
599:   A->ops->assemblyend    = MatAssemblyEnd_MFFD;
600:   A->ops->getdiagonal    = MatGetDiagonal_MFFD;
601:   A->ops->scale          = MatScale_MFFD;
602:   A->ops->shift          = MatShift_MFFD;
603:   A->ops->setfromoptions = MatSNESMFSetFromOptions;
604:   A->assembled = PETSC_TRUE;

606:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetBase_C","MatSNESMFSetBase_FD",MatSNESMFSetBase_FD);
607:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioniBase_C","MatSNESMFSetFunctioniBase_FD",MatSNESMFSetFunctioniBase_FD);
608:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioni_C","MatSNESMFSetFunctioni_FD",MatSNESMFSetFunctioni_FD);
609:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetCheckh_C","MatSNESMFSetCheckh_FD",MatSNESMFSetCheckh_FD);
610:   mfctx->mat = A;

612:   return(0);
613: }

618: /*@C
619:    MatCreateMF - Creates a matrix-free matrix. See also MatCreateSNESMF() 

621:    Collective on Vec

623:    Input Parameters:
624: .  x - vector that defines layout of the vectors and matrices

626:    Output Parameter:
627: .  J - the matrix-free matrix

629:    Level: advanced

631:    Notes:
632:    The matrix-free matrix context merely contains the function pointers
633:    and work space for performing finite difference approximations of
634:    Jacobian-vector products, F'(u)*a, 

636:    The default code uses the following approach to compute h

638: .vb
639:      F'(u)*a = [F(u+h*a) - F(u)]/h where
640:      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
641:        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
642:  where
643:      error_rel = square root of relative error in function evaluation
644:      umin = minimum iterate parameter
645: .ve

647:    The user can set the error_rel via MatSNESMFSetFunctionError() and 
648:    umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
649:    of the users manual for details.

651:    The user should call MatDestroy() when finished with the matrix-free
652:    matrix context.

654:    Options Database Keys:
655: +  -snes_mf_err <error_rel> - Sets error_rel
656: .  -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
657: .  -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
658: -  -snes_mf_check_positivity

660: .keywords: default, matrix-free, create, matrix

662: .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
663:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateSNESMF(),
664:           MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic),, MatSNESMFComputeJacobian()
665:  
666: @*/
667: PetscErrorCode MatCreateMF(Vec x,Mat *J)
668: {
669:   MPI_Comm       comm;
671:   PetscInt       n,nloc;

674:   PetscObjectGetComm((PetscObject)x,&comm);
675:   VecGetSize(x,&n);
676:   VecGetLocalSize(x,&nloc);
677:   MatCreate(comm,nloc,nloc,n,n,J);
678:   MatRegisterDynamic(MATMFFD,0,"MatCreate_MFFD",MatCreate_MFFD);
679:   MatSetType(*J,MATMFFD);
680:   return(0);
681: }


686: /*@
687:    MatSNESMFGetH - Gets the last value that was used as the differencing 
688:    parameter.

690:    Not Collective

692:    Input Parameters:
693: .  mat - the matrix obtained with MatCreateSNESMF()

695:    Output Paramter:
696: .  h - the differencing step size

698:    Level: advanced

700: .keywords: SNES, matrix-free, parameters

702: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(), 
703:           MatSNESMFResetHHistory(),MatSNESMFKSPMonitor()
704: @*/
705: PetscErrorCode MatSNESMFGetH(Mat mat,PetscScalar *h)
706: {
707:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

710:   *h = ctx->currenth;
711:   return(0);
712: }

716: /*
717:    MatSNESMFKSPMonitor - A KSP monitor for use with the default PETSc
718:    SNES matrix free routines. Prints the differencing parameter used at 
719:    each step.
720: */
721: PetscErrorCode MatSNESMFKSPMonitor(KSP ksp,PetscInt n,PetscReal rnorm,void *dummy)
722: {
723:   PC             pc;
724:   MatSNESMFCtx   ctx;
726:   Mat            mat;
727:   MPI_Comm       comm;
728:   PetscTruth     nonzeroinitialguess;

731:   PetscObjectGetComm((PetscObject)ksp,&comm);
732:   KSPGetPC(ksp,&pc);
733:   KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);
734:   PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL);
735:   ctx  = (MatSNESMFCtx)mat->data;

737:   if (n > 0 || nonzeroinitialguess) {
738: #if defined(PETSC_USE_COMPLEX)
739:     PetscPrintf(comm,"%D KSP Residual norm %14.12e h %g + %g i\n",n,rnorm,
740:                 PetscRealPart(ctx->currenth),PetscImaginaryPart(ctx->currenth));
741: #else
742:     PetscPrintf(comm,"%D KSP Residual norm %14.12e h %g \n",n,rnorm,ctx->currenth);
743: #endif
744:   } else {
745:     PetscPrintf(comm,"%D KSP Residual norm %14.12e\n",n,rnorm);
746:   }
747:   return(0);
748: }

752: /*@C
753:    MatSNESMFSetFunction - Sets the function used in applying the matrix free.

755:    Collective on Mat

757:    Input Parameters:
758: +  mat - the matrix free matrix created via MatCreateSNESMF()
759: .  v   - workspace vector
760: .  func - the function to use
761: -  funcctx - optional function context passed to function

763:    Level: advanced

765:    Notes:
766:     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
767:     matrix inside your compute Jacobian routine

769:     If this is not set then it will use the function set with SNESSetFunction()

771: .keywords: SNES, matrix-free, function

773: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
774:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
775:           MatSNESMFKSPMonitor(), SNESetFunction()
776: @*/
777: PetscErrorCode MatSNESMFSetFunction(Mat mat,Vec v,PetscErrorCode (*func)(SNES,Vec,Vec,void *),void *funcctx)
778: {
779:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

782:   ctx->func    = func;
783:   ctx->funcctx = funcctx;
784:   ctx->funcvec = v;
785:   return(0);
786: }

790: /*@C
791:    MatSNESMFSetFunctioni - Sets the function for a single component

793:    Collective on Mat

795:    Input Parameters:
796: +  mat - the matrix free matrix created via MatCreateSNESMF()
797: -  funci - the function to use

799:    Level: advanced

801:    Notes:
802:     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
803:     matrix inside your compute Jacobian routine


806: .keywords: SNES, matrix-free, function

808: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
809:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
810:           MatSNESMFKSPMonitor(), SNESetFunction()
811: @*/
812: PetscErrorCode MatSNESMFSetFunctioni(Mat mat,PetscErrorCode (*funci)(PetscInt,Vec,PetscScalar*,void *))
813: {
814:   PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(PetscInt,Vec,PetscScalar*,void *));

818:   PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioni_C",(void (**)(void))&f);
819:   if (f) {
820:     (*f)(mat,funci);
821:   }
822:   return(0);
823: }


828: /*@C
829:    MatSNESMFSetFunctioniBase - Sets the base vector for a single component function evaluation

831:    Collective on Mat

833:    Input Parameters:
834: +  mat - the matrix free matrix created via MatCreateSNESMF()
835: -  func - the function to use

837:    Level: advanced

839:    Notes:
840:     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
841:     matrix inside your compute Jacobian routine


844: .keywords: SNES, matrix-free, function

846: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
847:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
848:           MatSNESMFKSPMonitor(), SNESetFunction()
849: @*/
850: PetscErrorCode MatSNESMFSetFunctioniBase(Mat mat,PetscErrorCode (*func)(Vec,void *))
851: {
852:   PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(Vec,void *));

856:   PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioniBase_C",(void (**)(void))&f);
857:   if (f) {
858:     (*f)(mat,func);
859:   }
860:   return(0);
861: }


866: /*@
867:    MatSNESMFSetPeriod - Sets how often h is recomputed, by default it is everytime

869:    Collective on Mat

871:    Input Parameters:
872: +  mat - the matrix free matrix created via MatCreateSNESMF()
873: -  period - 1 for everytime, 2 for every second etc

875:    Options Database Keys:
876: +  -snes_mf_period <period>

878:    Level: advanced


881: .keywords: SNES, matrix-free, parameters

883: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
884:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
885:           MatSNESMFKSPMonitor()
886: @*/
887: PetscErrorCode MatSNESMFSetPeriod(Mat mat,PetscInt period)
888: {
889:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

892:   ctx->recomputeperiod = period;
893:   return(0);
894: }

898: /*@
899:    MatSNESMFSetFunctionError - Sets the error_rel for the approximation of
900:    matrix-vector products using finite differences.

902:    Collective on Mat

904:    Input Parameters:
905: +  mat - the matrix free matrix created via MatCreateSNESMF()
906: -  error_rel - relative error (should be set to the square root of
907:                the relative error in the function evaluations)

909:    Options Database Keys:
910: +  -snes_mf_err <error_rel> - Sets error_rel

912:    Level: advanced

914:    Notes:
915:    The default matrix-free matrix-vector product routine computes
916: .vb
917:      F'(u)*a = [F(u+h*a) - F(u)]/h where
918:      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
919:        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   else
920: .ve

922: .keywords: SNES, matrix-free, parameters

924: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
925:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
926:           MatSNESMFKSPMonitor()
927: @*/
928: PetscErrorCode MatSNESMFSetFunctionError(Mat mat,PetscReal error)
929: {
930:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

933:   if (error != PETSC_DEFAULT) ctx->error_rel = error;
934:   return(0);
935: }

939: /*@
940:    MatSNESMFAddNullSpace - Provides a null space that an operator is
941:    supposed to have.  Since roundoff will create a small component in
942:    the null space, if you know the null space you may have it
943:    automatically removed.

945:    Collective on Mat 

947:    Input Parameters:
948: +  J - the matrix-free matrix context
949: -  nullsp - object created with MatNullSpaceCreate()

951:    Level: advanced

953: .keywords: SNES, matrix-free, null space

955: .seealso: MatNullSpaceCreate(), MatSNESMFGetH(), MatCreateSNESMF(),
956:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
957:           MatSNESMFKSPMonitor(), MatSNESMFErrorRel()
958: @*/
959: PetscErrorCode MatSNESMFAddNullSpace(Mat J,MatNullSpace nullsp)
960: {
962:   MatSNESMFCtx   ctx = (MatSNESMFCtx)J->data;
963:   MPI_Comm       comm;

966:   PetscObjectGetComm((PetscObject)J,&comm);

968:   ctx->sp = nullsp;
969:   PetscObjectReference((PetscObject)nullsp);
970:   return(0);
971: }

975: /*@
976:    MatSNESMFSetHHistory - Sets an array to collect a history of the
977:    differencing values (h) computed for the matrix-free product.

979:    Collective on Mat 

981:    Input Parameters:
982: +  J - the matrix-free matrix context
983: .  histroy - space to hold the history
984: -  nhistory - number of entries in history, if more entries are generated than
985:               nhistory, then the later ones are discarded

987:    Level: advanced

989:    Notes:
990:    Use MatSNESMFResetHHistory() to reset the history counter and collect
991:    a new batch of differencing parameters, h.

993: .keywords: SNES, matrix-free, h history, differencing history

995: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
996:           MatSNESMFResetHHistory(),
997:           MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()

999: @*/
1000: PetscErrorCode MatSNESMFSetHHistory(Mat J,PetscScalar history[],PetscInt nhistory)
1001: {
1002:   MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;

1005:   ctx->historyh    = history;
1006:   ctx->maxcurrenth = nhistory;
1007:   ctx->currenth    = 0;
1008:   return(0);
1009: }

1013: /*@
1014:    MatSNESMFResetHHistory - Resets the counter to zero to begin 
1015:    collecting a new set of differencing histories.

1017:    Collective on Mat 

1019:    Input Parameters:
1020: .  J - the matrix-free matrix context

1022:    Level: advanced

1024:    Notes:
1025:    Use MatSNESMFSetHHistory() to create the original history counter.

1027: .keywords: SNES, matrix-free, h history, differencing history

1029: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
1030:           MatSNESMFSetHHistory(),
1031:           MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()

1033: @*/
1034: PetscErrorCode MatSNESMFResetHHistory(Mat J)
1035: {
1036:   MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;

1039:   ctx->ncurrenth    = 0;
1040:   return(0);
1041: }

1045: PetscErrorCode MatSNESMFComputeJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy)
1046: {
1049:   MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);
1050:   MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);
1051:   return(0);
1052: }

1056: /*@
1057:     MatSNESMFSetBase - Sets the vector U at which matrix vector products of the 
1058:         Jacobian are computed

1060:     Collective on Mat

1062:     Input Parameters:
1063: +   J - the MatSNESMF matrix
1064: -   U - the vector

1066:     Notes: This is rarely used directly

1068:     Level: advanced

1070: @*/
1071: PetscErrorCode MatSNESMFSetBase(Mat J,Vec U)
1072: {
1073:   PetscErrorCode ierr,(*f)(Mat,Vec);

1078:   PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetBase_C",(void (**)(void))&f);
1079:   if (f) {
1080:     (*f)(J,U);
1081:   }
1082:   return(0);
1083: }

1087: /*@C
1088:     MatSNESMFSetCheckh - Sets a function that checks the computed h and adjusts
1089:         it to satisfy some criteria

1091:     Collective on Mat

1093:     Input Parameters:
1094: +   J - the MatSNESMF matrix
1095: .   fun - the function that checks h
1096: -   ctx - any context needed by the function

1098:     Options Database Keys:
1099: .   -snes_mf_check_positivity

1101:     Level: advanced

1103:     Notes: For example, MatSNESMFSetCheckPositivity() insures that all entries
1104:        of U + h*a are non-negative

1106: .seealso:  MatSNESMFSetCheckPositivity()
1107: @*/
1108: PetscErrorCode MatSNESMFSetCheckh(Mat J,PetscErrorCode (*fun)(Vec,Vec,PetscScalar*,void*),void* ctx)
1109: {
1110:   PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(Vec,Vec,PetscScalar*,void*),void*);

1114:   PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetCheckh_C",(void (**)(void))&f);
1115:   if (f) {
1116:     (*f)(J,fun,ctx);
1117:   }
1118:   return(0);
1119: }

1123: /*@
1124:     MatSNESMFCheckPositivity - Checks that all entries in U + h*a are positive or
1125:         zero, decreases h until this is satisfied.

1127:     Collective on Vec

1129:     Input Parameters:
1130: +   U - base vector that is added to
1131: .   a - vector that is added
1132: .   h - scaling factor on a
1133: -   dummy - context variable (unused)

1135:     Options Database Keys:
1136: .   -snes_mf_check_positivity

1138:     Level: advanced

1140:     Notes: This is rarely used directly, rather it is passed as an argument to 
1141:            MatSNESMFSetCheckh()

1143: .seealso:  MatSNESMFSetCheckh()
1144: @*/
1145: PetscErrorCode MatSNESMFCheckPositivity(Vec U,Vec a,PetscScalar *h,void *dummy)
1146: {
1147:   PetscReal      val, minval;
1148:   PetscScalar    *u_vec, *a_vec;
1150:   PetscInt       i,n;
1151:   MPI_Comm       comm;

1154:   PetscObjectGetComm((PetscObject)U,&comm);
1155:   VecGetArray(U,&u_vec);
1156:   VecGetArray(a,&a_vec);
1157:   VecGetLocalSize(U,&n);
1158:   minval = PetscAbsScalar(*h*1.01);
1159:   for(i=0;i<n;i++) {
1160:     if (PetscRealPart(u_vec[i] + *h*a_vec[i]) <= 0.0) {
1161:       val = PetscAbsScalar(u_vec[i]/a_vec[i]);
1162:       if (val < minval) minval = val;
1163:     }
1164:   }
1165:   VecRestoreArray(U,&u_vec);
1166:   VecRestoreArray(a,&a_vec);
1167:   PetscGlobalMin(&minval,&val,comm);
1168:   if (val <= PetscAbsScalar(*h)) {
1169:     PetscLogInfo(U,"MatSNESMFCheckPositivity: Scaling back h from %g to %g\n",PetscRealPart(*h),.99*val);
1170:     if (PetscRealPart(*h) > 0.0) *h =  0.99*val;
1171:     else                         *h = -0.99*val;
1172:   }
1173:   return(0);
1174: }