Actual source code: mffd.c

  1: #define PETSCMAT_DLL

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

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

  9: PetscCookie  MATMFFD_COOKIE = 0;
 10: PetscEvent  MATMFFD_Mult = 0;

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

 19:   Input Parameter:
 20: . path - The dynamic library path, or PETSC_NULL

 22:   Level: developer

 24: .keywords: Vec, initialize, package
 25: .seealso: PetscInitialize()
 26: @*/
 27: PetscErrorCode  MatMFFDInitializePackage(const char path[])
 28: {
 29:   static PetscTruth initialized = PETSC_FALSE;
 30:   char              logList[256];
 31:   char              *className;
 32:   PetscTruth        opt;
 33:   PetscErrorCode    ierr;

 36:   if (initialized) return(0);
 37:   initialized = PETSC_TRUE;
 38:   /* Register Classes */
 39:   PetscLogClassRegister(&MATMFFD_COOKIE,     "MatMFFD");
 40:   /* Register Constructors */
 41:   MatMFFDRegisterAll(path);
 42:   /* Register Events */

 45:   /* Process info exclusions */
 46:   PetscOptionsGetString(PETSC_NULL, "-info_exclude", logList, 256, &opt);
 47:   if (opt) {
 48:     PetscStrstr(logList, "matmffd", &className);
 49:     if (className) {
 50:       PetscInfoDeactivateClass(MATMFFD_COOKIE);
 51:     }
 52:   }
 53:   /* Process summary exclusions */
 54:   PetscOptionsGetString(PETSC_NULL, "-log_summary_exclude", logList, 256, &opt);
 55:   if (opt) {
 56:     PetscStrstr(logList, "matmffd", &className);
 57:     if (className) {
 59:     }
 60:   }
 61:   return(0);
 62: }

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

 70:     Input Parameters:
 71: +   mat - the "matrix-free" matrix created via MatCreateSNESMF(), or MatCreateMFFD()
 72:           or MatSetType(mat,MATMFFD);
 73: -   ftype - the type requested, either MATMFFD_WP or MATMFFD_DS

 75:     Level: advanced

 77:     Notes:
 78:     For example, such routines can compute h for use in
 79:     Jacobian-vector products of the form

 81:                         F(x+ha) - F(x)
 82:           F'(u)a  ~=  ----------------
 83:                               h

 85: .seealso: MatCreateSNESMF(), MatMFFDRegisterDynamic)
 86: @*/
 87: PetscErrorCode  MatMFFDSetType(Mat mat,MatMFFDType ftype)
 88: {
 89:   PetscErrorCode ierr,(*r)(MatMFFD);
 90:   MatMFFD        ctx = (MatMFFD)mat->data;
 91:   PetscTruth     match;
 92: 

 97:   /* already set, so just return */
 98:   PetscTypeCompare((PetscObject)ctx,ftype,&match);
 99:   if (match) return(0);

101:   /* destroy the old one if it exists */
102:   if (ctx->ops->destroy) {
103:     (*ctx->ops->destroy)(ctx);
104:   }

106:    PetscFListFind(MatMFFDPetscFList,ctx->comm,ftype,(void (**)(void)) &r);
107:   if (!r) SETERRQ1(PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown MatMFFD type %s given",ftype);
108:   (*r)(ctx);
109:   PetscObjectChangeTypeName((PetscObject)ctx,ftype);
110:   return(0);
111: }

117: PetscErrorCode  MatMFFDSetFunctioniBase_FD(Mat mat,FCN1 func)
118: {
119:   MatMFFD ctx = (MatMFFD)mat->data;

122:   ctx->funcisetbase = func;
123:   return(0);
124: }

131: PetscErrorCode  MatMFFDSetFunctioni_FD(Mat mat,FCN2 funci)
132: {
133:   MatMFFD ctx = (MatMFFD)mat->data;

136:   ctx->funci = funci;
137:   return(0);
138: }


144: PetscErrorCode  MatMFFDRegister(const char sname[],const char path[],const char name[],PetscErrorCode (*function)(MatMFFD))
145: {
147:   char           fullname[PETSC_MAX_PATH_LEN];

150:   PetscFListConcat(path,name,fullname);
151:   PetscFListAdd(&MatMFFDPetscFList,sname,fullname,(void (*)(void))function);
152:   return(0);
153: }


158: /*@C
159:    MatMFFDRegisterDestroy - Frees the list of MatMFFD methods that were
160:    registered by MatMFFDRegisterDynamic).

162:    Not Collective

164:    Level: developer

166: .keywords: MatMFFD, register, destroy

168: .seealso: MatMFFDRegisterDynamic), MatMFFDRegisterAll()
169: @*/
170: PetscErrorCode  MatMFFDRegisterDestroy(void)
171: {

175:   PetscFListDestroy(&MatMFFDPetscFList);
176:   MatMFFDRegisterAllCalled = PETSC_FALSE;
177:   return(0);
178: }

180: /* ----------------------------------------------------------------------------------------*/
183: PetscErrorCode MatDestroy_MFFD(Mat mat)
184: {
186:   MatMFFD        ctx = (MatMFFD)mat->data;

189:   if (ctx->w) {
190:     VecDestroy(ctx->w);
191:   }
192:   if (ctx->current_f_allocated) {
193:     VecDestroy(ctx->current_f);
194:   }
195:   if (ctx->ops->destroy) {(*ctx->ops->destroy)(ctx);}
196:   if (ctx->sp) {MatNullSpaceDestroy(ctx->sp);}
197:   PetscHeaderDestroy(ctx);

199:   PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetBase_C","",PETSC_NULL);
200:   PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctioniBase_C","",PETSC_NULL);
201:   PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctioni_C","",PETSC_NULL);
202:   PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetCheckh_C","",PETSC_NULL);

204:   return(0);
205: }

209: /*
210:    MatMFFDView_MFFD - Views matrix-free parameters.

212: */
213: PetscErrorCode MatView_MFFD(Mat J,PetscViewer viewer)
214: {
216:   MatMFFD        ctx = (MatMFFD)J->data;
217:   PetscTruth     iascii;

220:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
221:   if (iascii) {
222:      PetscViewerASCIIPrintf(viewer,"  matrix-free approximation:\n");
223:      PetscViewerASCIIPrintf(viewer,"    err=%G (relative error in function evaluation)\n",ctx->error_rel);
224:      if (!ctx->type_name) {
225:        PetscViewerASCIIPrintf(viewer,"    The compute h routine has not yet been set\n");
226:      } else {
227:        PetscViewerASCIIPrintf(viewer,"    Using %s compute h routine\n",ctx->type_name);
228:      }
229:      if (ctx->ops->view) {
230:        (*ctx->ops->view)(ctx,viewer);
231:      }
232:   } else {
233:     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for matrix-free matrix",((PetscObject)viewer)->type_name);
234:   }
235:   return(0);
236: }

240: /*
241:    MatAssemblyEnd_MFFD - Resets the ctx->ncurrenth to zero. This 
242:    allows the user to indicate the beginning of a new linear solve by calling
243:    MatAssemblyXXX() on the matrix free matrix. This then allows the 
244:    MatMFFDCreate_WP() to properly compute ||U|| only the first time
245:    in the linear solver rather than every time.
246: */
247: PetscErrorCode MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt)
248: {
250:   MatMFFD        j = (MatMFFD)J->data;

253:   MatMFFDResetHHistory(J);
254:   j->vshift = 0.0;
255:   j->vscale = 1.0;
256:   return(0);
257: }

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

264:         y ~= (F(u + ha) - F(u))/h, 
265:   where F = nonlinear function, as set by SNESSetFunction()
266:         u = current iterate
267:         h = difference interval
268: */
269: PetscErrorCode MatMult_MFFD(Mat mat,Vec a,Vec y)
270: {
271:   MatMFFD        ctx = (MatMFFD)mat->data;
272:   PetscScalar    h;
273:   Vec            w,U,F;
275:   PetscTruth     zeroa;

278:   /* We log matrix-free matrix-vector products separately, so that we can
279:      separate the performance monitoring from the cases that use conventional
280:      storage.  We may eventually modify event logging to associate events
281:      with particular objects, hence alleviating the more general problem. */

284:   w    = ctx->w;
285:   U    = ctx->current_u;
286:   F    = ctx->current_f;
287:   /* 
288:       Compute differencing parameter 
289:   */
290:   if (!ctx->ops->compute) {
291:     MatMFFDSetType(mat,MATMFFD_WP);
292:     MatMFFDSetFromOptions(mat);
293:   }
294:   (*ctx->ops->compute)(ctx,U,a,&h,&zeroa);
295:   if (zeroa) {
296:     VecSet(y,0.0);
297:     return(0);
298:   }

300:   if (h != h) SETERRQ(PETSC_ERR_PLIB,"Computed Nan differencing parameter h");
301:   if (ctx->checkh) {
302:     (*ctx->checkh)(ctx->checkhctx,U,a,&h);
303:   }

305:   /* keep a record of the current differencing parameter h */
306:   ctx->currenth = h;
307: #if defined(PETSC_USE_COMPLEX)
308:   PetscInfo2(mat,"Current differencing parameter: %G + %G i\n",PetscRealPart(h),PetscImaginaryPart(h));
309: #else
310:   PetscInfo1(mat,"Current differencing parameter: %15.12e\n",h);
311: #endif
312:   if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
313:     ctx->historyh[ctx->ncurrenth] = h;
314:   }
315:   ctx->ncurrenth++;

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

320:   /* compute func(U) as base for differencing; only needed first time in */
321:   if (ctx->ncurrenth == 1) {
322:     (*ctx->func)(ctx->funcctx,U,F);
323:   }
324:   (*ctx->func)(ctx->funcctx,w,y);

326:   VecAXPY(y,-1.0,F);
327:   VecScale(y,1.0/h);

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

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

334:   return(0);
335: }

339: /*
340:   MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix

342:         y ~= (F(u + ha) - F(u))/h, 
343:   where F = nonlinear function, as set by SNESSetFunction()
344:         u = current iterate
345:         h = difference interval
346: */
347: PetscErrorCode MatGetDiagonal_MFFD(Mat mat,Vec a)
348: {
349:   MatMFFD        ctx = (MatMFFD)mat->data;
350:   PetscScalar    h,*aa,*ww,v;
351:   PetscReal      epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
352:   Vec            w,U;
354:   PetscInt       i,rstart,rend;

357:   if (!ctx->funci) {
358:     SETERRQ(PETSC_ERR_ORDER,"Requires calling MatMFFDSetFunctioni() first");
359:   }

361:   w    = ctx->w;
362:   U    = ctx->current_u;
363:   (*ctx->func)(ctx->funcctx,U,a);
364:   (*ctx->funcisetbase)(ctx->funcctx,U);
365:   VecCopy(U,w);

367:   VecGetOwnershipRange(a,&rstart,&rend);
368:   VecGetArray(a,&aa);
369:   for (i=rstart; i<rend; i++) {
370:     VecGetArray(w,&ww);
371:     h  = ww[i-rstart];
372:     if (h == 0.0) h = 1.0;
373: #if !defined(PETSC_USE_COMPLEX)
374:     if (h < umin && h >= 0.0)      h = umin;
375:     else if (h < 0.0 && h > -umin) h = -umin;
376: #else
377:     if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0)     h = umin;
378:     else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
379: #endif
380:     h     *= epsilon;
381: 
382:     ww[i-rstart] += h;
383:     VecRestoreArray(w,&ww);
384:     (*ctx->funci)(ctx->funcctx,i,w,&v);
385:     aa[i-rstart]  = (v - aa[i-rstart])/h;

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

390:     VecGetArray(w,&ww);
391:     ww[i-rstart] -= h;
392:     VecRestoreArray(w,&ww);
393:   }
394:   VecRestoreArray(a,&aa);
395:   return(0);
396: }

400: PetscErrorCode MatShift_MFFD(Mat Y,PetscScalar a)
401: {
402:   MatMFFD shell = (MatMFFD)Y->data;
404:   shell->vshift += a;
405:   return(0);
406: }

410: PetscErrorCode MatScale_MFFD(Mat Y,PetscScalar a)
411: {
412:   MatMFFD shell = (MatMFFD)Y->data;
414:   shell->vscale *= a;
415:   return(0);
416: }

421: PetscErrorCode  MatMFFDSetBase_FD(Mat J,Vec U,Vec F)
422: {
424:   MatMFFD        ctx = (MatMFFD)J->data;

427:   MatMFFDResetHHistory(J);
428:   ctx->current_u = U;
429:   if (F) {
430:     if (ctx->current_f_allocated) {VecDestroy(ctx->current_f);}
431:     ctx->current_f           = F;
432:     ctx->current_f_allocated = PETSC_FALSE;
433:   } else if (!ctx->current_f_allocated) {
434:     VecDuplicate(ctx->current_u, &ctx->current_f);
435:     ctx->current_f_allocated = PETSC_TRUE;
436:   }
437:   if (!ctx->w) {
438:     VecDuplicate(ctx->current_u, &ctx->w);
439:   }
440:   J->assembled = PETSC_TRUE;
441:   return(0);
442: }
448: PetscErrorCode  MatMFFDSetCheckh_FD(Mat J,FCN3 fun,void*ectx)
449: {
450:   MatMFFD ctx = (MatMFFD)J->data;

453:   ctx->checkh    = fun;
454:   ctx->checkhctx = ectx;
455:   return(0);
456: }

461: /*@
462:    MatMFFDSetFromOptions - Sets the MatMFFD options from the command line
463:    parameter.

465:    Collective on Mat

467:    Input Parameters:
468: .  mat - the matrix obtained with MatCreateMFFD() or MatCreateSNESMF()

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

475:    Level: advanced

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

479: .seealso: MatCreateSNESMF(),MatMFFDSetHHistory(), 
480:           MatMFFDResetHHistory(), MatMFFDKSPMonitor()
481: @*/
482: PetscErrorCode  MatMFFDSetFromOptions(Mat mat)
483: {
484:   MatMFFD        mfctx = (MatMFFD)mat->data;
486:   PetscTruth     flg;
487:   char           ftype[256];

490:   PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatMFFD");
491:   PetscOptionsList("-mat_mffd_type","Matrix free type","MatMFFDSetType",MatMFFDPetscFList,mfctx->type_name,ftype,256,&flg);
492:   if (flg) {
493:     MatMFFDSetType(mat,ftype);
494:   }

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

499:   PetscOptionsName("-mat_mffd_check_positivity","Insure that U + h*a is nonnegative","MatMFFDSetCheckh",&flg);
500:   if (flg) {
501:     MatMFFDSetCheckh(mat,MatMFFDCheckPositivity,0);
502:   }
503:   if (mfctx->ops->setfromoptions) {
504:     (*mfctx->ops->setfromoptions)(mfctx);
505:   }
506:   PetscOptionsEnd();
507:   return(0);
508: }

510: /*MC
511:   MATMFFD - MATMFFD = "mffd" - A matrix free matrix type.

513:   Level: advanced

515: .seealso: MatCreateMFFD(), MatCreateSNESMF()
516: M*/
520: PetscErrorCode  MatCreate_MFFD(Mat A)
521: {
522:   MatMFFD         mfctx;
523:   PetscErrorCode  ierr;

526: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
527:   MatMFFDInitializePackage(PETSC_NULL);
528: #endif

530:   PetscHeaderCreate(mfctx,_p_MatMFFD,struct _MFOps,MATMFFD_COOKIE,0,"MatMFFD",A->comm,MatDestroy_MFFD,MatView_MFFD);
531:   mfctx->sp              = 0;
532:   mfctx->error_rel       = PETSC_SQRT_MACHINE_EPSILON;
533:   mfctx->recomputeperiod = 1;
534:   mfctx->count           = 0;
535:   mfctx->currenth        = 0.0;
536:   mfctx->historyh        = PETSC_NULL;
537:   mfctx->ncurrenth       = 0;
538:   mfctx->maxcurrenth     = 0;
539:   mfctx->type_name       = 0;

541:   mfctx->vshift          = 0.0;
542:   mfctx->vscale          = 1.0;

544:   /* 
545:      Create the empty data structure to contain compute-h routines.
546:      These will be filled in below from the command line options or 
547:      a later call with MatMFFDSetType() or if that is not called 
548:      then it will default in the first use of MatMult_MFFD()
549:   */
550:   mfctx->ops->compute        = 0;
551:   mfctx->ops->destroy        = 0;
552:   mfctx->ops->view           = 0;
553:   mfctx->ops->setfromoptions = 0;
554:   mfctx->hctx                = 0;

556:   mfctx->func                = 0;
557:   mfctx->funcctx             = 0;
558:   mfctx->w                   = PETSC_NULL;

560:   A->data                = mfctx;

562:   A->ops->mult           = MatMult_MFFD;
563:   A->ops->destroy        = MatDestroy_MFFD;
564:   A->ops->view           = MatView_MFFD;
565:   A->ops->assemblyend    = MatAssemblyEnd_MFFD;
566:   A->ops->getdiagonal    = MatGetDiagonal_MFFD;
567:   A->ops->scale          = MatScale_MFFD;
568:   A->ops->shift          = MatShift_MFFD;
569:   A->ops->setfromoptions = MatMFFDSetFromOptions;
570:   A->assembled = PETSC_TRUE;

572:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetBase_C","MatMFFDSetBase_FD",MatMFFDSetBase_FD);
573:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetFunctioniBase_C","MatMFFDSetFunctioniBase_FD",MatMFFDSetFunctioniBase_FD);
574:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetFunctioni_C","MatMFFDSetFunctioni_FD",MatMFFDSetFunctioni_FD);
575:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetCheckh_C","MatMFFDSetCheckh_FD",MatMFFDSetCheckh_FD);
576:   mfctx->mat = A;
577:   PetscObjectChangeTypeName((PetscObject)A,MATMFFD);
578:   return(0);
579: }

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

587:    Collective on Vec

589:    Input Parameters:
590: +  comm - MPI communicator
591: .  m - number of local rows (or PETSC_DECIDE to have calculated if M is given)
592:            This value should be the same as the local size used in creating the 
593:            y vector for the matrix-vector product y = Ax.
594: .  n - This value should be the same as the local size used in creating the 
595:        x vector for the matrix-vector product y = Ax. (or PETSC_DECIDE to have
596:        calculated if N is given) For square matrices n is almost always m.
597: .  M - number of global rows (or PETSC_DETERMINE to have calculated if m is given)
598: -  N - number of global columns (or PETSC_DETERMINE to have calculated if n is given)


601:    Output Parameter:
602: .  J - the matrix-free matrix

604:    Level: advanced

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

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

613: .vb
614:      F'(u)*a = [F(u+h*a) - F(u)]/h where
615:      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
616:        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
617:  where
618:      error_rel = square root of relative error in function evaluation
619:      umin = minimum iterate parameter
620: .ve

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

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

629:    Options Database Keys:
630: +  -mat_mffd_err <error_rel> - Sets error_rel
631: .  -mat_mffd_unim <umin> - Sets umin (for default PETSc routine that computes h only)
632: .  -mat_mffd_ksp_monitor - KSP monitor routine that prints differencing h
633: -  -mat_mffd_check_positivity

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

637: .seealso: MatDestroy(), MatMFFDSetFunctionError(), MatMFFDDefaultSetUmin(), MatMFFDSetFunction()
638:           MatMFFDSetHHistory(), MatMFFDResetHHistory(), MatCreateSNESMF(),
639:           MatMFFDGetH(),MatMFFDKSPMonitor(), MatMFFDRegisterDynamic),, MatMFFDComputeJacobian()
640:  
641: @*/
642: PetscErrorCode  MatCreateMFFD(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,Mat *J)
643: {

647:   MatCreate(comm,J);
648:   MatSetSizes(*J,m,n,M,N);
649:   MatSetType(*J,MATMFFD);
650:   return(0);
651: }


656: /*@
657:    MatMFFDGetH - Gets the last value that was used as the differencing 
658:    parameter.

660:    Not Collective

662:    Input Parameters:
663: .  mat - the matrix obtained with MatCreateSNESMF()

665:    Output Paramter:
666: .  h - the differencing step size

668:    Level: advanced

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

672: .seealso: MatCreateSNESMF(),MatMFFDSetHHistory(), MatCreateMFFD(), MATMFFD
673:           MatMFFDResetHHistory(),MatMFFDKSPMonitor()
674: @*/
675: PetscErrorCode  MatMFFDGetH(Mat mat,PetscScalar *h)
676: {
677:   MatMFFD ctx = (MatMFFD)mat->data;

680:   *h = ctx->currenth;
681:   return(0);
682: }


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

690:    Collective on Mat

692:    Input Parameters:
693: +  mat - the matrix free matrix created via MatCreateSNESMF()
694: .  func - the function to use
695: -  funcctx - optional function context passed to function

697:    Level: advanced

699:    Notes:
700:     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
701:     matrix inside your compute Jacobian routine

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

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

707: .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD
708:           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
709:           MatMFFDKSPMonitor(), SNESetFunction()
710: @*/
711: PetscErrorCode  MatMFFDSetFunction(Mat mat,PetscErrorCode (*func)(void*,Vec,Vec),void *funcctx)
712: {
713:   MatMFFD ctx = (MatMFFD)mat->data;

716:   ctx->func    = func;
717:   ctx->funcctx = funcctx;
718:   return(0);
719: }

723: /*@C
724:    MatMFFDSetFunctioni - Sets the function for a single component

726:    Collective on Mat

728:    Input Parameters:
729: +  mat - the matrix free matrix created via MatCreateSNESMF()
730: -  funci - the function to use

732:    Level: advanced

734:    Notes:
735:     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
736:     matrix inside your compute Jacobian routine


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

741: .seealso: MatCreateSNESMF(),MatMFFDGetH(),
742:           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
743:           MatMFFDKSPMonitor(), SNESetFunction()
744: @*/
745: PetscErrorCode  MatMFFDSetFunctioni(Mat mat,PetscErrorCode (*funci)(void*,PetscInt,Vec,PetscScalar*))
746: {
747:   PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(void*,PetscInt,Vec,PetscScalar*));

751:   PetscObjectQueryFunction((PetscObject)mat,"MatMFFDSetFunctioni_C",(void (**)(void))&f);
752:   if (f) {
753:     (*f)(mat,funci);
754:   }
755:   return(0);
756: }


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

764:    Collective on Mat

766:    Input Parameters:
767: +  mat - the matrix free matrix created via MatCreateSNESMF()
768: -  func - the function to use

770:    Level: advanced

772:    Notes:
773:     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
774:     matrix inside your compute Jacobian routine


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

779: .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD
780:           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
781:           MatMFFDKSPMonitor(), SNESetFunction()
782: @*/
783: PetscErrorCode  MatMFFDSetFunctioniBase(Mat mat,PetscErrorCode (*func)(void*,Vec))
784: {
785:   PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(void*,Vec));

789:   PetscObjectQueryFunction((PetscObject)mat,"MatMFFDSetFunctioniBase_C",(void (**)(void))&f);
790:   if (f) {
791:     (*f)(mat,func);
792:   }
793:   return(0);
794: }


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

802:    Collective on Mat

804:    Input Parameters:
805: +  mat - the matrix free matrix created via MatCreateSNESMF()
806: -  period - 1 for everytime, 2 for every second etc

808:    Options Database Keys:
809: +  -mat_mffd_period <period>

811:    Level: advanced


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

816: .seealso: MatCreateSNESMF(),MatMFFDGetH(),
817:           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
818:           MatMFFDKSPMonitor()
819: @*/
820: PetscErrorCode  MatMFFDSetPeriod(Mat mat,PetscInt period)
821: {
822:   MatMFFD ctx = (MatMFFD)mat->data;

825:   ctx->recomputeperiod = period;
826:   return(0);
827: }

831: /*@
832:    MatMFFDSetFunctionError - Sets the error_rel for the approximation of
833:    matrix-vector products using finite differences.

835:    Collective on Mat

837:    Input Parameters:
838: +  mat - the matrix free matrix created via MatCreateMFFD() or MatCreateSNESMF()
839: -  error_rel - relative error (should be set to the square root of
840:                the relative error in the function evaluations)

842:    Options Database Keys:
843: +  -mat_mffd_err <error_rel> - Sets error_rel

845:    Level: advanced

847:    Notes:
848:    The default matrix-free matrix-vector product routine computes
849: .vb
850:      F'(u)*a = [F(u+h*a) - F(u)]/h where
851:      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
852:        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   else
853: .ve

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

857: .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD
858:           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
859:           MatMFFDKSPMonitor()
860: @*/
861: PetscErrorCode  MatMFFDSetFunctionError(Mat mat,PetscReal error)
862: {
863:   MatMFFD ctx = (MatMFFD)mat->data;

866:   if (error != PETSC_DEFAULT) ctx->error_rel = error;
867:   return(0);
868: }

872: /*@
873:    MatMFFDAddNullSpace - Provides a null space that an operator is
874:    supposed to have.  Since roundoff will create a small component in
875:    the null space, if you know the null space you may have it
876:    automatically removed.

878:    Collective on Mat 

880:    Input Parameters:
881: +  J - the matrix-free matrix context
882: -  nullsp - object created with MatNullSpaceCreate()

884:    Level: advanced

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

888: .seealso: MatNullSpaceCreate(), MatMFFDGetH(), MatCreateSNESMF(), MatCreateMFFD(), MATMFFD
889:           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
890:           MatMFFDKSPMonitor(), MatMFFDErrorRel()
891: @*/
892: PetscErrorCode  MatMFFDAddNullSpace(Mat J,MatNullSpace nullsp)
893: {
895:   MatMFFD      ctx = (MatMFFD)J->data;

898:   PetscObjectReference((PetscObject)nullsp);
899:   if (ctx->sp) { MatNullSpaceDestroy(ctx->sp); }
900:   ctx->sp = nullsp;
901:   return(0);
902: }

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

910:    Collective on Mat 

912:    Input Parameters:
913: +  J - the matrix-free matrix context
914: .  histroy - space to hold the history
915: -  nhistory - number of entries in history, if more entries are generated than
916:               nhistory, then the later ones are discarded

918:    Level: advanced

920:    Notes:
921:    Use MatMFFDResetHHistory() to reset the history counter and collect
922:    a new batch of differencing parameters, h.

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

926: .seealso: MatMFFDGetH(), MatCreateSNESMF(),
927:           MatMFFDResetHHistory(),
928:           MatMFFDKSPMonitor(), MatMFFDSetFunctionError()

930: @*/
931: PetscErrorCode  MatMFFDSetHHistory(Mat J,PetscScalar history[],PetscInt nhistory)
932: {
933:   MatMFFD ctx = (MatMFFD)J->data;

936:   ctx->historyh    = history;
937:   ctx->maxcurrenth = nhistory;
938:   ctx->currenth    = 0;
939:   return(0);
940: }

944: /*@
945:    MatMFFDResetHHistory - Resets the counter to zero to begin 
946:    collecting a new set of differencing histories.

948:    Collective on Mat 

950:    Input Parameters:
951: .  J - the matrix-free matrix context

953:    Level: advanced

955:    Notes:
956:    Use MatMFFDSetHHistory() to create the original history counter.

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

960: .seealso: MatMFFDGetH(), MatCreateSNESMF(),
961:           MatMFFDSetHHistory(),
962:           MatMFFDKSPMonitor(), MatMFFDSetFunctionError()

964: @*/
965: PetscErrorCode  MatMFFDResetHHistory(Mat J)
966: {
967:   MatMFFD ctx = (MatMFFD)J->data;

970:   ctx->ncurrenth    = 0;
971:   return(0);
972: }


977: /*@
978:     MatMFFDSetBase - Sets the vector U at which matrix vector products of the 
979:         Jacobian are computed

981:     Collective on Mat

983:     Input Parameters:
984: +   J - the MatMFFD matrix
985: .   U - the vector
986: -   F - vector that contains F(u) if it has been already computed

988:     Notes: This is rarely used directly

990:     Warning: for a given Mat, this must be called either ALWAYS with an F or never

992:     Level: advanced

994: @*/
995: PetscErrorCode  MatMFFDSetBase(Mat J,Vec U,Vec F)
996: {
997:   PetscErrorCode ierr,(*f)(Mat,Vec,Vec);

1003:   PetscObjectQueryFunction((PetscObject)J,"MatMFFDSetBase_C",(void (**)(void))&f);
1004:   if (f) {
1005:     (*f)(J,U,F);
1006:   }
1007:   return(0);
1008: }

1012: /*@C
1013:     MatMFFDSetCheckh - Sets a function that checks the computed h and adjusts
1014:         it to satisfy some criteria

1016:     Collective on Mat

1018:     Input Parameters:
1019: +   J - the MatMFFD matrix
1020: .   fun - the function that checks h
1021: -   ctx - any context needed by the function

1023:     Options Database Keys:
1024: .   -mat_mffd_check_positivity

1026:     Level: advanced

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

1031: .seealso:  MatMFFDSetCheckPositivity()
1032: @*/
1033: PetscErrorCode  MatMFFDSetCheckh(Mat J,PetscErrorCode (*fun)(void*,Vec,Vec,PetscScalar*),void* ctx)
1034: {
1035:   PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(void*,Vec,Vec,PetscScalar*),void*);

1039:   PetscObjectQueryFunction((PetscObject)J,"MatMFFDSetCheckh_C",(void (**)(void))&f);
1040:   if (f) {
1041:     (*f)(J,fun,ctx);
1042:   }
1043:   return(0);
1044: }

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

1052:     Collective on Vec

1054:     Input Parameters:
1055: +   U - base vector that is added to
1056: .   a - vector that is added
1057: .   h - scaling factor on a
1058: -   dummy - context variable (unused)

1060:     Options Database Keys:
1061: .   -mat_mffd_check_positivity

1063:     Level: advanced

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

1068: .seealso:  MatMFFDSetCheckh()
1069: @*/
1070: PetscErrorCode  MatMFFDCheckPositivity(void* dummy,Vec U,Vec a,PetscScalar *h)
1071: {
1072:   PetscReal      val, minval;
1073:   PetscScalar    *u_vec, *a_vec;
1075:   PetscInt       i,n;
1076:   MPI_Comm       comm;

1079:   PetscObjectGetComm((PetscObject)U,&comm);
1080:   VecGetArray(U,&u_vec);
1081:   VecGetArray(a,&a_vec);
1082:   VecGetLocalSize(U,&n);
1083:   minval = PetscAbsScalar(*h*1.01);
1084:   for(i=0;i<n;i++) {
1085:     if (PetscRealPart(u_vec[i] + *h*a_vec[i]) <= 0.0) {
1086:       val = PetscAbsScalar(u_vec[i]/a_vec[i]);
1087:       if (val < minval) minval = val;
1088:     }
1089:   }
1090:   VecRestoreArray(U,&u_vec);
1091:   VecRestoreArray(a,&a_vec);
1092:   PetscGlobalMin(&minval,&val,comm);
1093:   if (val <= PetscAbsScalar(*h)) {
1094:     PetscInfo2(U,"Scaling back h from %G to %G\n",PetscRealPart(*h),.99*val);
1095:     if (PetscRealPart(*h) > 0.0) *h =  0.99*val;
1096:     else                         *h = -0.99*val;
1097:   }
1098:   return(0);
1099: }