Actual source code: mffd.c

  1: #define PETSCMAT_DLL

 3:  #include private/matimpl.h
 4:  #include ../src/mat/impls/mffd/mffdimpl.h

  6: PetscFList MatMFFDList        = 0;
  7: PetscTruth MatMFFDRegisterAllCalled = PETSC_FALSE;

  9: PetscCookie  MATMFFD_COOKIE;
 10: PetscLogEvent  MATMFFD_Mult;

 12: static PetscTruth MatMFFDPackageInitialized = PETSC_FALSE;
 15: /*@C
 16:   MatMFFDFinalizePackage - This function destroys everything in the MatMFFD package. It is
 17:   called from PetscFinalize().

 19:   Level: developer

 21: .keywords: Petsc, destroy, package
 22: .seealso: PetscFinalize()
 23: @*/
 24: PetscErrorCode  MatMFFDFinalizePackage(void)
 25: {
 27:   MatMFFDPackageInitialized = PETSC_FALSE;
 28:   MatMFFDRegisterAllCalled  = PETSC_FALSE;
 29:   MatMFFDList               = PETSC_NULL;
 30:   return(0);
 31: }

 35: /*@C
 36:   MatMFFDInitializePackage - This function initializes everything in the MatMFFD package. It is called
 37:   from PetscDLLibraryRegister() when using dynamic libraries, and on the first call to MatCreate_MFFD()
 38:   when using static libraries.

 40:   Input Parameter:
 41: . path - The dynamic library path, or PETSC_NULL

 43:   Level: developer

 45: .keywords: Vec, initialize, package
 46: .seealso: PetscInitialize()
 47: @*/
 48: PetscErrorCode  MatMFFDInitializePackage(const char path[])
 49: {
 50:   char              logList[256];
 51:   char              *className;
 52:   PetscTruth        opt;
 53:   PetscErrorCode    ierr;

 56:   if (MatMFFDPackageInitialized) return(0);
 57:   MatMFFDPackageInitialized = PETSC_TRUE;
 58:   /* Register Classes */
 59:   PetscCookieRegister("MatMFFD",&MATMFFD_COOKIE);
 60:   /* Register Constructors */
 61:   MatMFFDRegisterAll(path);
 62:   /* Register Events */
 63:   PetscLogEventRegister("MatMult MF",          MATMFFD_COOKIE,&MATMFFD_Mult);

 65:   /* Process info exclusions */
 66:   PetscOptionsGetString(PETSC_NULL, "-info_exclude", logList, 256, &opt);
 67:   if (opt) {
 68:     PetscStrstr(logList, "matmffd", &className);
 69:     if (className) {
 70:       PetscInfoDeactivateClass(MATMFFD_COOKIE);
 71:     }
 72:   }
 73:   /* Process summary exclusions */
 74:   PetscOptionsGetString(PETSC_NULL, "-log_summary_exclude", logList, 256, &opt);
 75:   if (opt) {
 76:     PetscStrstr(logList, "matmffd", &className);
 77:     if (className) {
 78:       PetscLogEventDeactivateClass(MATMFFD_COOKIE);
 79:     }
 80:   }
 81:   PetscRegisterFinalize(MatMFFDFinalizePackage);
 82:   return(0);
 83: }

 87: /*@C
 88:     MatMFFDSetType - Sets the method that is used to compute the 
 89:     differencing parameter for finite differene matrix-free formulations. 

 91:     Input Parameters:
 92: +   mat - the "matrix-free" matrix created via MatCreateSNESMF(), or MatCreateMFFD()
 93:           or MatSetType(mat,MATMFFD);
 94: -   ftype - the type requested, either MATMFFD_WP or MATMFFD_DS

 96:     Level: advanced

 98:     Notes:
 99:     For example, such routines can compute h for use in
100:     Jacobian-vector products of the form

102:                         F(x+ha) - F(x)
103:           F'(u)a  ~=  ----------------
104:                               h

106: .seealso: MatCreateSNESMF(), MatMFFDRegisterDynamic(), MatMFFDSetFunction()
107: @*/
108: PetscErrorCode  MatMFFDSetType(Mat mat,const MatMFFDType ftype)
109: {
110:   PetscErrorCode ierr,(*r)(MatMFFD);
111:   MatMFFD        ctx = (MatMFFD)mat->data;
112:   PetscTruth     match;
113: 

118:   /* already set, so just return */
119:   PetscTypeCompare((PetscObject)ctx,ftype,&match);
120:   if (match) return(0);

122:   /* destroy the old one if it exists */
123:   if (ctx->ops->destroy) {
124:     (*ctx->ops->destroy)(ctx);
125:   }

127:    PetscFListFind(MatMFFDList,((PetscObject)ctx)->comm,ftype,(void (**)(void)) &r);
128:   if (!r) SETERRQ1(PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown MatMFFD type %s given",ftype);
129:   (*r)(ctx);
130:   PetscObjectChangeTypeName((PetscObject)ctx,ftype);
131:   return(0);
132: }

138: PetscErrorCode  MatMFFDSetFunctioniBase_MFFD(Mat mat,FCN1 func)
139: {
140:   MatMFFD ctx = (MatMFFD)mat->data;

143:   ctx->funcisetbase = func;
144:   return(0);
145: }

152: PetscErrorCode  MatMFFDSetFunctioni_MFFD(Mat mat,FCN2 funci)
153: {
154:   MatMFFD ctx = (MatMFFD)mat->data;

157:   ctx->funci = funci;
158:   return(0);
159: }


165: PetscErrorCode  MatMFFDRegister(const char sname[],const char path[],const char name[],PetscErrorCode (*function)(MatMFFD))
166: {
168:   char           fullname[PETSC_MAX_PATH_LEN];

171:   PetscFListConcat(path,name,fullname);
172:   PetscFListAdd(&MatMFFDList,sname,fullname,(void (*)(void))function);
173:   return(0);
174: }


179: /*@C
180:    MatMFFDRegisterDestroy - Frees the list of MatMFFD methods that were
181:    registered by MatMFFDRegisterDynamic).

183:    Not Collective

185:    Level: developer

187: .keywords: MatMFFD, register, destroy

189: .seealso: MatMFFDRegisterDynamic), MatMFFDRegisterAll()
190: @*/
191: PetscErrorCode  MatMFFDRegisterDestroy(void)
192: {

196:   PetscFListDestroy(&MatMFFDList);
197:   MatMFFDRegisterAllCalled = PETSC_FALSE;
198:   return(0);
199: }

201: /* ----------------------------------------------------------------------------------------*/
204: PetscErrorCode MatDestroy_MFFD(Mat mat)
205: {
207:   MatMFFD        ctx = (MatMFFD)mat->data;

210:   if (ctx->w) {
211:     VecDestroy(ctx->w);
212:   }
213:   if (ctx->current_f_allocated) {
214:     VecDestroy(ctx->current_f);
215:   }
216:   if (ctx->ops->destroy) {(*ctx->ops->destroy)(ctx);}
217:   if (ctx->sp) {MatNullSpaceDestroy(ctx->sp);}
218:   PetscHeaderDestroy(ctx);

220:   PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetBase_C","",PETSC_NULL);
221:   PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctioniBase_C","",PETSC_NULL);
222:   PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctioni_C","",PETSC_NULL);
223:   PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetCheckh_C","",PETSC_NULL);

225:   return(0);
226: }

230: /*
231:    MatMFFDView_MFFD - Views matrix-free parameters.

233: */
234: PetscErrorCode MatView_MFFD(Mat J,PetscViewer viewer)
235: {
237:   MatMFFD        ctx = (MatMFFD)J->data;
238:   PetscTruth     iascii;

241:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
242:   if (iascii) {
243:      PetscViewerASCIIPrintf(viewer,"  matrix-free approximation:\n");
244:      PetscViewerASCIIPrintf(viewer,"    err=%G (relative error in function evaluation)\n",ctx->error_rel);
245:      if (!((PetscObject)ctx)->type_name) {
246:        PetscViewerASCIIPrintf(viewer,"    The compute h routine has not yet been set\n");
247:      } else {
248:        PetscViewerASCIIPrintf(viewer,"    Using %s compute h routine\n",((PetscObject)ctx)->type_name);
249:      }
250:      if (ctx->ops->view) {
251:        (*ctx->ops->view)(ctx,viewer);
252:      }
253:   } else {
254:     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for matrix-free matrix",((PetscObject)viewer)->type_name);
255:   }
256:   return(0);
257: }

261: /*
262:    MatAssemblyEnd_MFFD - Resets the ctx->ncurrenth to zero. This 
263:    allows the user to indicate the beginning of a new linear solve by calling
264:    MatAssemblyXXX() on the matrix free matrix. This then allows the 
265:    MatMFFDCreate_WP() to properly compute ||U|| only the first time
266:    in the linear solver rather than every time.
267: */
268: PetscErrorCode MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt)
269: {
271:   MatMFFD        j = (MatMFFD)J->data;

274:   MatMFFDResetHHistory(J);
275:   j->vshift = 0.0;
276:   j->vscale = 1.0;
277:   return(0);
278: }

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

285:         y ~= (F(u + ha) - F(u))/h, 
286:   where F = nonlinear function, as set by SNESSetFunction()
287:         u = current iterate
288:         h = difference interval
289: */
290: PetscErrorCode MatMult_MFFD(Mat mat,Vec a,Vec y)
291: {
292:   MatMFFD        ctx = (MatMFFD)mat->data;
293:   PetscScalar    h;
294:   Vec            w,U,F;
296:   PetscTruth     zeroa;

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

305:   w    = ctx->w;
306:   U    = ctx->current_u;
307:   F    = ctx->current_f;
308:   /* 
309:       Compute differencing parameter 
310:   */
311:   if (!ctx->ops->compute) {
312:     MatMFFDSetType(mat,MATMFFD_WP);
313:     MatMFFDSetFromOptions(mat);
314:   }
315:   (*ctx->ops->compute)(ctx,U,a,&h,&zeroa);
316:   if (zeroa) {
317:     VecSet(y,0.0);
318:     return(0);
319:   }

321:   if (h != h) SETERRQ(PETSC_ERR_PLIB,"Computed Nan differencing parameter h");
322:   if (ctx->checkh) {
323:     (*ctx->checkh)(ctx->checkhctx,U,a,&h);
324:   }

326:   /* keep a record of the current differencing parameter h */
327:   ctx->currenth = h;
328: #if defined(PETSC_USE_COMPLEX)
329:   PetscInfo2(mat,"Current differencing parameter: %G + %G i\n",PetscRealPart(h),PetscImaginaryPart(h));
330: #else
331:   PetscInfo1(mat,"Current differencing parameter: %15.12e\n",h);
332: #endif
333:   if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
334:     ctx->historyh[ctx->ncurrenth] = h;
335:   }
336:   ctx->ncurrenth++;

338:   /* w = u + ha */
339:   VecWAXPY(w,h,a,U);

341:   /* compute func(U) as base for differencing; only needed first time in and not when provided by user */
342:   if (ctx->ncurrenth == 1 && ctx->current_f_allocated) {
343:     (*ctx->func)(ctx->funcctx,U,F);
344:   }
345:   (*ctx->func)(ctx->funcctx,w,y);

347:   VecAXPY(y,-1.0,F);
348:   VecScale(y,1.0/h);

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

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

354:   PetscLogEventEnd(MATMFFD_Mult,a,y,0,0);
355:   return(0);
356: }

360: /*
361:   MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix

363:         y ~= (F(u + ha) - F(u))/h, 
364:   where F = nonlinear function, as set by SNESSetFunction()
365:         u = current iterate
366:         h = difference interval
367: */
368: PetscErrorCode MatGetDiagonal_MFFD(Mat mat,Vec a)
369: {
370:   MatMFFD        ctx = (MatMFFD)mat->data;
371:   PetscScalar    h,*aa,*ww,v;
372:   PetscReal      epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
373:   Vec            w,U;
375:   PetscInt       i,rstart,rend;

378:   if (!ctx->funci) {
379:     SETERRQ(PETSC_ERR_ORDER,"Requires calling MatMFFDSetFunctioni() first");
380:   }

382:   w    = ctx->w;
383:   U    = ctx->current_u;
384:   (*ctx->func)(ctx->funcctx,U,a);
385:   (*ctx->funcisetbase)(ctx->funcctx,U);
386:   VecCopy(U,w);

388:   VecGetOwnershipRange(a,&rstart,&rend);
389:   VecGetArray(a,&aa);
390:   for (i=rstart; i<rend; i++) {
391:     VecGetArray(w,&ww);
392:     h  = ww[i-rstart];
393:     if (h == 0.0) h = 1.0;
394: #if !defined(PETSC_USE_COMPLEX)
395:     if (h < umin && h >= 0.0)      h = umin;
396:     else if (h < 0.0 && h > -umin) h = -umin;
397: #else
398:     if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0)     h = umin;
399:     else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
400: #endif
401:     h     *= epsilon;
402: 
403:     ww[i-rstart] += h;
404:     VecRestoreArray(w,&ww);
405:     (*ctx->funci)(ctx->funcctx,i,w,&v);
406:     aa[i-rstart]  = (v - aa[i-rstart])/h;

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

411:     VecGetArray(w,&ww);
412:     ww[i-rstart] -= h;
413:     VecRestoreArray(w,&ww);
414:   }
415:   VecRestoreArray(a,&aa);
416:   return(0);
417: }

421: PetscErrorCode MatShift_MFFD(Mat Y,PetscScalar a)
422: {
423:   MatMFFD shell = (MatMFFD)Y->data;
425:   shell->vshift += a;
426:   return(0);
427: }

431: PetscErrorCode MatScale_MFFD(Mat Y,PetscScalar a)
432: {
433:   MatMFFD shell = (MatMFFD)Y->data;
435:   shell->vscale *= a;
436:   return(0);
437: }

442: PetscErrorCode  MatMFFDSetBase_MFFD(Mat J,Vec U,Vec F)
443: {
445:   MatMFFD        ctx = (MatMFFD)J->data;

448:   MatMFFDResetHHistory(J);
449:   ctx->current_u = U;
450:   if (F) {
451:     if (ctx->current_f_allocated) {VecDestroy(ctx->current_f);}
452:     ctx->current_f           = F;
453:     ctx->current_f_allocated = PETSC_FALSE;
454:   } else if (!ctx->current_f_allocated) {
455:     VecDuplicate(ctx->current_u, &ctx->current_f);
456:     ctx->current_f_allocated = PETSC_TRUE;
457:   }
458:   if (!ctx->w) {
459:     VecDuplicate(ctx->current_u, &ctx->w);
460:   }
461:   J->assembled = PETSC_TRUE;
462:   return(0);
463: }
469: PetscErrorCode  MatMFFDSetCheckh_MFFD(Mat J,FCN3 fun,void*ectx)
470: {
471:   MatMFFD ctx = (MatMFFD)J->data;

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

482: /*@C
483:    MatMFFDSetOptionsPrefix - Sets the prefix used for searching for all 
484:    MatMFFD options in the database.

486:    Collective on Mat

488:    Input Parameter:
489: +  A - the Mat context
490: -  prefix - the prefix to prepend to all option names

492:    Notes:
493:    A hyphen (-) must NOT be given at the beginning of the prefix name.
494:    The first character of all runtime options is AUTOMATICALLY the hyphen.

496:    Level: advanced

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

500: .seealso: MatMFFDSetFromOptions(), MatCreateSNESMF()
501: @*/
502: PetscErrorCode  MatMFFDSetOptionsPrefix(Mat mat,const char prefix[])

504: {
505:   MatMFFD        mfctx = mat ? (MatMFFD)mat->data : PETSC_NULL;
510:   PetscObjectSetOptionsPrefix((PetscObject)mfctx,prefix);
511:   return(0);
512: }

516: /*@
517:    MatMFFDSetFromOptions - Sets the MatMFFD options from the command line
518:    parameter.

520:    Collective on Mat

522:    Input Parameters:
523: .  mat - the matrix obtained with MatCreateMFFD() or MatCreateSNESMF()

525:    Options Database Keys:
526: +  -mat_mffd_type - wp or ds (see MATMFFD_WP or MATMFFD_DS)
527: -  -mat_mffd_err - square root of estimated relative error in function evaluation
528: -  -mat_mffd_period - how often h is recomputed, defaults to 1, everytime

530:    Level: advanced

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

534: .seealso: MatCreateSNESMF(),MatMFFDSetHHistory(), 
535:           MatMFFDResetHHistory(), MatMFFDKSPMonitor()
536: @*/
537: PetscErrorCode  MatMFFDSetFromOptions(Mat mat)
538: {
539:   MatMFFD        mfctx = mat ? (MatMFFD)mat->data : PETSC_NULL;
541:   PetscTruth     flg;
542:   char           ftype[256];

547:   PetscOptionsBegin(((PetscObject)mfctx)->comm,((PetscObject)mfctx)->prefix,"Set matrix free computation parameters","MatMFFD");
548:   PetscOptionsList("-mat_mffd_type","Matrix free type","MatMFFDSetType",MatMFFDList,((PetscObject)mfctx)->type_name,ftype,256,&flg);
549:   if (flg) {
550:     MatMFFDSetType(mat,ftype);
551:   }

553:   PetscOptionsReal("-mat_mffd_err","set sqrt relative error in function","MatMFFDSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);
554:   PetscOptionsInt("-mat_mffd_period","how often h is recomputed","MatMFFDSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);

556:   flg  = PETSC_FALSE;
557:   PetscOptionsTruth("-mat_mffd_check_positivity","Insure that U + h*a is nonnegative","MatMFFDSetCheckh",flg,&flg,PETSC_NULL);
558:   if (flg) {
559:     MatMFFDSetCheckh(mat,MatMFFDCheckPositivity,0);
560:   }
561:   if (mfctx->ops->setfromoptions) {
562:     (*mfctx->ops->setfromoptions)(mfctx);
563:   }
564:   PetscOptionsEnd();
565:   return(0);
566: }

568: /*MC
569:   MATMFFD - MATMFFD = "mffd" - A matrix free matrix type.

571:   Level: advanced

573: .seealso: MatCreateMFFD(), MatCreateSNESMF(), MatMFFDSetFunction()
574: M*/
578: PetscErrorCode  MatCreate_MFFD(Mat A)
579: {
580:   MatMFFD         mfctx;
581:   PetscErrorCode  ierr;

584: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
585:   MatMFFDInitializePackage(PETSC_NULL);
586: #endif

588:   PetscHeaderCreate(mfctx,_p_MatMFFD,struct _MFOps,MATMFFD_COOKIE,0,"MatMFFD",((PetscObject)A)->comm,MatDestroy_MFFD,MatView_MFFD);
589:   mfctx->sp              = 0;
590:   mfctx->error_rel       = PETSC_SQRT_MACHINE_EPSILON;
591:   mfctx->recomputeperiod = 1;
592:   mfctx->count           = 0;
593:   mfctx->currenth        = 0.0;
594:   mfctx->historyh        = PETSC_NULL;
595:   mfctx->ncurrenth       = 0;
596:   mfctx->maxcurrenth     = 0;
597:   ((PetscObject)mfctx)->type_name       = 0;

599:   mfctx->vshift          = 0.0;
600:   mfctx->vscale          = 1.0;

602:   /* 
603:      Create the empty data structure to contain compute-h routines.
604:      These will be filled in below from the command line options or 
605:      a later call with MatMFFDSetType() or if that is not called 
606:      then it will default in the first use of MatMult_MFFD()
607:   */
608:   mfctx->ops->compute        = 0;
609:   mfctx->ops->destroy        = 0;
610:   mfctx->ops->view           = 0;
611:   mfctx->ops->setfromoptions = 0;
612:   mfctx->hctx                = 0;

614:   mfctx->func                = 0;
615:   mfctx->funcctx             = 0;
616:   mfctx->w                   = PETSC_NULL;

618:   A->data                = mfctx;

620:   A->ops->mult           = MatMult_MFFD;
621:   A->ops->destroy        = MatDestroy_MFFD;
622:   A->ops->view           = MatView_MFFD;
623:   A->ops->assemblyend    = MatAssemblyEnd_MFFD;
624:   A->ops->getdiagonal    = MatGetDiagonal_MFFD;
625:   A->ops->scale          = MatScale_MFFD;
626:   A->ops->shift          = MatShift_MFFD;
627:   A->ops->setfromoptions = MatMFFDSetFromOptions;
628:   A->assembled = PETSC_TRUE;

630:   PetscLayoutSetBlockSize(A->rmap,1);
631:   PetscLayoutSetBlockSize(A->cmap,1);
632:   PetscLayoutSetUp(A->rmap);
633:   PetscLayoutSetUp(A->cmap);

635:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetBase_C","MatMFFDSetBase_MFFD",MatMFFDSetBase_MFFD);
636:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetFunctioniBase_C","MatMFFDSetFunctioniBase_MFFD",MatMFFDSetFunctioniBase_MFFD);
637:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetFunctioni_C","MatMFFDSetFunctioni_MFFD",MatMFFDSetFunctioni_MFFD);
638:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetCheckh_C","MatMFFDSetCheckh_MFFD",MatMFFDSetCheckh_MFFD);
639:   mfctx->mat = A;
640:   PetscObjectChangeTypeName((PetscObject)A,MATMFFD);
641:   return(0);
642: }

647: /*@
648:    MatCreateMFFD - Creates a matrix-free matrix. See also MatCreateSNESMF() 

650:    Collective on Vec

652:    Input Parameters:
653: +  comm - MPI communicator
654: .  m - number of local rows (or PETSC_DECIDE to have calculated if M is given)
655:            This value should be the same as the local size used in creating the 
656:            y vector for the matrix-vector product y = Ax.
657: .  n - This value should be the same as the local size used in creating the 
658:        x vector for the matrix-vector product y = Ax. (or PETSC_DECIDE to have
659:        calculated if N is given) For square matrices n is almost always m.
660: .  M - number of global rows (or PETSC_DETERMINE to have calculated if m is given)
661: -  N - number of global columns (or PETSC_DETERMINE to have calculated if n is given)


664:    Output Parameter:
665: .  J - the matrix-free matrix

667:    Level: advanced

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

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

676: .vb
677:      F'(u)*a = [F(u+h*a) - F(u)]/h where
678:      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
679:        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
680:  where
681:      error_rel = square root of relative error in function evaluation
682:      umin = minimum iterate parameter
683: .ve

685:    The user can set the error_rel via MatMFFDSetFunctionError() and 
686:    umin via MatMFFDDefaultSetUmin(); see the nonlinear solvers chapter
687:    of the users manual for details.

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

692:    Options Database Keys:
693: +  -mat_mffd_err <error_rel> - Sets error_rel
694: .  -mat_mffd_unim <umin> - Sets umin (for default PETSc routine that computes h only)
695: .  -mat_mffd_ksp_monitor - KSP monitor routine that prints differencing h
696: -  -mat_mffd_check_positivity

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

700: .seealso: MatDestroy(), MatMFFDSetFunctionError(), MatMFFDDefaultSetUmin(), MatMFFDSetFunction()
701:           MatMFFDSetHHistory(), MatMFFDResetHHistory(), MatCreateSNESMF(), 
702:           MatMFFDGetH(),MatMFFDKSPMonitor(), MatMFFDRegisterDynamic),, MatMFFDComputeJacobian()
703:  
704: @*/
705: PetscErrorCode  MatCreateMFFD(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,Mat *J)
706: {

710:   MatCreate(comm,J);
711:   MatSetSizes(*J,m,n,M,N);
712:   MatSetType(*J,MATMFFD);
713:   return(0);
714: }


719: /*@
720:    MatMFFDGetH - Gets the last value that was used as the differencing 
721:    parameter.

723:    Not Collective

725:    Input Parameters:
726: .  mat - the matrix obtained with MatCreateSNESMF()

728:    Output Paramter:
729: .  h - the differencing step size

731:    Level: advanced

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

735: .seealso: MatCreateSNESMF(),MatMFFDSetHHistory(), MatCreateMFFD(), MATMFFD
736:           MatMFFDResetHHistory(),MatMFFDKSPMonitor()
737: @*/
738: PetscErrorCode  MatMFFDGetH(Mat mat,PetscScalar *h)
739: {
740:   MatMFFD ctx = (MatMFFD)mat->data;

743:   *h = ctx->currenth;
744:   return(0);
745: }


750: /*@C
751:    MatMFFDSetFunction - Sets the function used in applying the matrix free.

753:    Collective on Mat

755:    Input Parameters:
756: +  mat - the matrix free matrix created via MatCreateSNESMF()
757: .  func - the function to use
758: -  funcctx - optional function context passed to function

760:    Level: advanced

762:    Notes:
763:     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
764:     matrix inside your compute Jacobian routine

766:     If this is not set then it will use the function set with SNESSetFunction() if MatCreateSNESMF() was used.

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

770: .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD
771:           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
772:           MatMFFDKSPMonitor(), SNESetFunction()
773: @*/
774: PetscErrorCode  MatMFFDSetFunction(Mat mat,PetscErrorCode (*func)(void*,Vec,Vec),void *funcctx)
775: {
776:   MatMFFD ctx = (MatMFFD)mat->data;

779:   ctx->func    = func;
780:   ctx->funcctx = funcctx;
781:   return(0);
782: }

786: /*@C
787:    MatMFFDSetFunctioni - Sets the function for a single component

789:    Collective on Mat

791:    Input Parameters:
792: +  mat - the matrix free matrix created via MatCreateSNESMF()
793: -  funci - the function to use

795:    Level: advanced

797:    Notes:
798:     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
799:     matrix inside your compute Jacobian routine


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

804: .seealso: MatCreateSNESMF(),MatMFFDGetH(),
805:           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
806:           MatMFFDKSPMonitor(), SNESetFunction()
807: @*/
808: PetscErrorCode  MatMFFDSetFunctioni(Mat mat,PetscErrorCode (*funci)(void*,PetscInt,Vec,PetscScalar*))
809: {
810:   PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(void*,PetscInt,Vec,PetscScalar*));

814:   PetscObjectQueryFunction((PetscObject)mat,"MatMFFDSetFunctioni_C",(void (**)(void))&f);
815:   if (f) {
816:     (*f)(mat,funci);
817:   }
818:   return(0);
819: }


824: /*@C
825:    MatMFFDSetFunctioniBase - Sets the base vector for a single component function evaluation

827:    Collective on Mat

829:    Input Parameters:
830: +  mat - the matrix free matrix created via MatCreateSNESMF()
831: -  func - the function to use

833:    Level: advanced

835:    Notes:
836:     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
837:     matrix inside your compute Jacobian routine


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

842: .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD
843:           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
844:           MatMFFDKSPMonitor(), SNESetFunction()
845: @*/
846: PetscErrorCode  MatMFFDSetFunctioniBase(Mat mat,PetscErrorCode (*func)(void*,Vec))
847: {
848:   PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(void*,Vec));

852:   PetscObjectQueryFunction((PetscObject)mat,"MatMFFDSetFunctioniBase_C",(void (**)(void))&f);
853:   if (f) {
854:     (*f)(mat,func);
855:   }
856:   return(0);
857: }


862: /*@
863:    MatMFFDSetPeriod - Sets how often h is recomputed, by default it is everytime

865:    Collective on Mat

867:    Input Parameters:
868: +  mat - the matrix free matrix created via MatCreateSNESMF()
869: -  period - 1 for everytime, 2 for every second etc

871:    Options Database Keys:
872: +  -mat_mffd_period <period>

874:    Level: advanced


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

879: .seealso: MatCreateSNESMF(),MatMFFDGetH(),
880:           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
881:           MatMFFDKSPMonitor()
882: @*/
883: PetscErrorCode  MatMFFDSetPeriod(Mat mat,PetscInt period)
884: {
885:   MatMFFD ctx = (MatMFFD)mat->data;

888:   ctx->recomputeperiod = period;
889:   return(0);
890: }

894: /*@
895:    MatMFFDSetFunctionError - Sets the error_rel for the approximation of
896:    matrix-vector products using finite differences.

898:    Collective on Mat

900:    Input Parameters:
901: +  mat - the matrix free matrix created via MatCreateMFFD() or MatCreateSNESMF()
902: -  error_rel - relative error (should be set to the square root of
903:                the relative error in the function evaluations)

905:    Options Database Keys:
906: +  -mat_mffd_err <error_rel> - Sets error_rel

908:    Level: advanced

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

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

920: .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD
921:           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
922:           MatMFFDKSPMonitor()
923: @*/
924: PetscErrorCode  MatMFFDSetFunctionError(Mat mat,PetscReal error)
925: {
926:   MatMFFD ctx = (MatMFFD)mat->data;

929:   if (error != PETSC_DEFAULT) ctx->error_rel = error;
930:   return(0);
931: }

935: /*@
936:    MatMFFDAddNullSpace - Provides a null space that an operator is
937:    supposed to have.  Since roundoff will create a small component in
938:    the null space, if you know the null space you may have it
939:    automatically removed.

941:    Collective on Mat 

943:    Input Parameters:
944: +  J - the matrix-free matrix context
945: -  nullsp - object created with MatNullSpaceCreate()

947:    Level: advanced

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

951: .seealso: MatNullSpaceCreate(), MatMFFDGetH(), MatCreateSNESMF(), MatCreateMFFD(), MATMFFD
952:           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
953:           MatMFFDKSPMonitor(), MatMFFDErrorRel()
954: @*/
955: PetscErrorCode  MatMFFDAddNullSpace(Mat J,MatNullSpace nullsp)
956: {
958:   MatMFFD      ctx = (MatMFFD)J->data;

961:   PetscObjectReference((PetscObject)nullsp);
962:   if (ctx->sp) { MatNullSpaceDestroy(ctx->sp); }
963:   ctx->sp = nullsp;
964:   return(0);
965: }

969: /*@
970:    MatMFFDSetHHistory - Sets an array to collect a history of the
971:    differencing values (h) computed for the matrix-free product.

973:    Collective on Mat 

975:    Input Parameters:
976: +  J - the matrix-free matrix context
977: .  histroy - space to hold the history
978: -  nhistory - number of entries in history, if more entries are generated than
979:               nhistory, then the later ones are discarded

981:    Level: advanced

983:    Notes:
984:    Use MatMFFDResetHHistory() to reset the history counter and collect
985:    a new batch of differencing parameters, h.

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

989: .seealso: MatMFFDGetH(), MatCreateSNESMF(),
990:           MatMFFDResetHHistory(),
991:           MatMFFDKSPMonitor(), MatMFFDSetFunctionError()

993: @*/
994: PetscErrorCode  MatMFFDSetHHistory(Mat J,PetscScalar history[],PetscInt nhistory)
995: {
996:   MatMFFD ctx = (MatMFFD)J->data;

999:   ctx->historyh    = history;
1000:   ctx->maxcurrenth = nhistory;
1001:   ctx->currenth    = 0.;
1002:   return(0);
1003: }

1007: /*@
1008:    MatMFFDResetHHistory - Resets the counter to zero to begin 
1009:    collecting a new set of differencing histories.

1011:    Collective on Mat 

1013:    Input Parameters:
1014: .  J - the matrix-free matrix context

1016:    Level: advanced

1018:    Notes:
1019:    Use MatMFFDSetHHistory() to create the original history counter.

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

1023: .seealso: MatMFFDGetH(), MatCreateSNESMF(),
1024:           MatMFFDSetHHistory(),
1025:           MatMFFDKSPMonitor(), MatMFFDSetFunctionError()

1027: @*/
1028: PetscErrorCode  MatMFFDResetHHistory(Mat J)
1029: {
1030:   MatMFFD ctx = (MatMFFD)J->data;

1033:   ctx->ncurrenth    = 0;
1034:   return(0);
1035: }


1040: /*@
1041:     MatMFFDSetBase - Sets the vector U at which matrix vector products of the 
1042:         Jacobian are computed

1044:     Collective on Mat

1046:     Input Parameters:
1047: +   J - the MatMFFD matrix
1048: .   U - the vector
1049: -   F - (optional) vector that contains F(u) if it has been already computed

1051:     Notes: This is rarely used directly

1053:     If F is provided then it is not recomputed. Otherwise the function is evaluated at the base
1054:     point during the first MatMult() after each call to MatMFFDSetBase().

1056:     Level: advanced

1058: @*/
1059: PetscErrorCode  MatMFFDSetBase(Mat J,Vec U,Vec F)
1060: {
1061:   PetscErrorCode ierr,(*f)(Mat,Vec,Vec);

1067:   PetscObjectQueryFunction((PetscObject)J,"MatMFFDSetBase_C",(void (**)(void))&f);
1068:   if (f) {
1069:     (*f)(J,U,F);
1070:   }
1071:   return(0);
1072: }

1076: /*@C
1077:     MatMFFDSetCheckh - Sets a function that checks the computed h and adjusts
1078:         it to satisfy some criteria

1080:     Collective on Mat

1082:     Input Parameters:
1083: +   J - the MatMFFD matrix
1084: .   fun - the function that checks h
1085: -   ctx - any context needed by the function

1087:     Options Database Keys:
1088: .   -mat_mffd_check_positivity

1090:     Level: advanced

1092:     Notes: For example, MatMFFDSetCheckPositivity() insures that all entries
1093:        of U + h*a are non-negative

1095: .seealso:  MatMFFDSetCheckPositivity()
1096: @*/
1097: PetscErrorCode  MatMFFDSetCheckh(Mat J,PetscErrorCode (*fun)(void*,Vec,Vec,PetscScalar*),void* ctx)
1098: {
1099:   PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(void*,Vec,Vec,PetscScalar*),void*);

1103:   PetscObjectQueryFunction((PetscObject)J,"MatMFFDSetCheckh_C",(void (**)(void))&f);
1104:   if (f) {
1105:     (*f)(J,fun,ctx);
1106:   }
1107:   return(0);
1108: }

1112: /*@
1113:     MatMFFDCheckPositivity - Checks that all entries in U + h*a are positive or
1114:         zero, decreases h until this is satisfied.

1116:     Collective on Vec

1118:     Input Parameters:
1119: +   U - base vector that is added to
1120: .   a - vector that is added
1121: .   h - scaling factor on a
1122: -   dummy - context variable (unused)

1124:     Options Database Keys:
1125: .   -mat_mffd_check_positivity

1127:     Level: advanced

1129:     Notes: This is rarely used directly, rather it is passed as an argument to 
1130:            MatMFFDSetCheckh()

1132: .seealso:  MatMFFDSetCheckh()
1133: @*/
1134: PetscErrorCode  MatMFFDCheckPositivity(void* dummy,Vec U,Vec a,PetscScalar *h)
1135: {
1136:   PetscReal      val, minval;
1137:   PetscScalar    *u_vec, *a_vec;
1139:   PetscInt       i,n;
1140:   MPI_Comm       comm;

1143:   PetscObjectGetComm((PetscObject)U,&comm);
1144:   VecGetArray(U,&u_vec);
1145:   VecGetArray(a,&a_vec);
1146:   VecGetLocalSize(U,&n);
1147:   minval = PetscAbsScalar(*h*1.01);
1148:   for(i=0;i<n;i++) {
1149:     if (PetscRealPart(u_vec[i] + *h*a_vec[i]) <= 0.0) {
1150:       val = PetscAbsScalar(u_vec[i]/a_vec[i]);
1151:       if (val < minval) minval = val;
1152:     }
1153:   }
1154:   VecRestoreArray(U,&u_vec);
1155:   VecRestoreArray(a,&a_vec);
1156:   PetscGlobalMin(&minval,&val,comm);
1157:   if (val <= PetscAbsScalar(*h)) {
1158:     PetscInfo2(U,"Scaling back h from %G to %G\n",PetscRealPart(*h),.99*val);
1159:     if (PetscRealPart(*h) > 0.0) *h =  0.99*val;
1160:     else                         *h = -0.99*val;
1161:   }
1162:   return(0);
1163: }