Actual source code: snesmfj.c

  1: /*$Id: snesmfj.c,v 1.131 2001/09/05 18:45:40 bsmith Exp $*/

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

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

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

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

 20:     Level: advanced

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

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

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

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

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

 51:   /* Get the function pointers for the requrested method */
 52:   if (!MatSNESMFRegisterAllCalled) {MatSNESMFRegisterAll(PETSC_NULL);}

 54:    PetscFListFind(ctx->comm,MatSNESMPetscFList,ftype,(void (**)(void)) &r);

 56:   if (!r) SETERRQ(1,"Unknown MatSNESMF type given");

 58:   (*r)(ctx);

 60:   PetscObjectChangeTypeName((PetscObject)ctx,ftype);

 62:   return(0);
 63: }

 65: typedef int (*FCN1)(Vec,void*); /* force argument to next function to not be extern C*/
 66: EXTERN_C_BEGIN
 69: int MatSNESMFSetFunctioniBase_FD(Mat mat,FCN1 func)
 70: {
 71:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

 74:   ctx->funcisetbase = func;
 75:   return(0);
 76: }
 77: EXTERN_C_END

 79: typedef int (*FCN2)(int,Vec,PetscScalar*,void*); /* force argument to next function to not be extern C*/
 80: EXTERN_C_BEGIN
 83: int MatSNESMFSetFunctioni_FD(Mat mat,FCN2 funci)
 84: {
 85:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

 88:   ctx->funci = funci;
 89:   return(0);
 90: }
 91: EXTERN_C_END


 96: int MatSNESMFRegister(const char sname[],const char path[],const char name[],int (*function)(MatSNESMFCtx))
 97: {
 99:   char fullname[256];

102:   PetscFListConcat(path,name,fullname);
103:   PetscFListAdd(&MatSNESMPetscFList,sname,fullname,(void (*)(void))function);
104:   return(0);
105: }


110: /*@C
111:    MatSNESMFRegisterDestroy - Frees the list of MatSNESMF methods that were
112:    registered by MatSNESMFRegisterDynamic).

114:    Not Collective

116:    Level: developer

118: .keywords: MatSNESMF, register, destroy

120: .seealso: MatSNESMFRegisterDynamic), MatSNESMFRegisterAll()
121: @*/
122: int MatSNESMFRegisterDestroy(void)
123: {

127:   if (MatSNESMPetscFList) {
128:     PetscFListDestroy(&MatSNESMPetscFList);
129:     MatSNESMPetscFList = 0;
130:   }
131:   MatSNESMFRegisterAllCalled = PETSC_FALSE;
132:   return(0);
133: }

135: /* ----------------------------------------------------------------------------------------*/
138: int MatDestroy_MFFD(Mat mat)
139: {
140:   int          ierr;
141:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

144:   if (ctx->w != PETSC_NULL) {
145:     VecDestroy(ctx->w);
146:   }
147:   if (ctx->ops->destroy) {(*ctx->ops->destroy)(ctx);}
148:   if (ctx->sp) {MatNullSpaceDestroy(ctx->sp);}
149:   PetscHeaderDestroy(ctx);
150:   return(0);
151: }

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

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

166:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
167:   if (isascii) {
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(1,"Viewer type %s not supported for SNES matrix free matrix",((PetscObject)viewer)->type_name);
180:   }
181:   return(0);
182: }

186: /*
187:    MatSNESMFAssemblyEnd_Private - 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: int MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt)
194: {
195:   int             ierr;
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 == PETSC_NULL) {
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: int 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:   int             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(1,"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);


288:   if (ctx->vshift != 0.0 && ctx->vscale != 1.0) {
289:     VecAXPBY(&ctx->vshift,&ctx->vscale,a,y);
290:   } else if (ctx->vscale != 1.0) {
291:     VecScale(&ctx->vscale,y);
292:   } else if (ctx->vshift != 0.0) {
293:     VecAXPY(&ctx->vshift,a,y);
294:   }

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

298:   PetscLogEventEnd(MAT_MultMatrixFree,a,y,0,0);
299:   return(0);
300: }

304: /*
305:   MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix

307:         y ~= (F(u + ha) - F(u))/h, 
308:   where F = nonlinear function, as set by SNESSetFunction()
309:         u = current iterate
310:         h = difference interval
311: */
312: int MatGetDiagonal_MFFD(Mat mat,Vec a)
313: {
314:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
315:   PetscScalar  h,*aa,*ww,v;
316:   PetscReal    epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
317:   Vec          w,U;
318:   int          i,ierr,rstart,rend;

321:   if (!ctx->funci) {
322:     SETERRQ(1,"Requirers calling MatSNESMFSetFunctioni() first");
323:   }

325:   w    = ctx->w;
326:   U    = ctx->current_u;
327:   (*ctx->func)(0,U,a,ctx->funcctx);
328:   (*ctx->funcisetbase)(U,ctx->funcctx);
329:   VecCopy(U,w);

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

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

354:     VecGetArray(w,&ww);
355:     ww[i-rstart] -= h;
356:     VecRestoreArray(w,&ww);
357:   }
358:   VecRestoreArray(a,&aa);
359:   return(0);
360: }

364: int MatShift_MFFD(const PetscScalar *a,Mat Y)
365: {
366:   MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
368:   shell->vshift += *a;
369:   return(0);
370: }

374: int MatScale_MFFD(const PetscScalar *a,Mat Y)
375: {
376:   MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
378:   shell->vscale *= *a;
379:   return(0);
380: }


385: /*@C
386:    MatCreateSNESMF - Creates a matrix-free matrix context for use with
387:    a SNES solver.  This matrix can be used as the Jacobian argument for
388:    the routine SNESSetJacobian().

390:    Collective on SNES and Vec

392:    Input Parameters:
393: +  snes - the SNES context
394: -  x - vector where SNES solution is to be stored.

396:    Output Parameter:
397: .  J - the matrix-free matrix

399:    Level: advanced

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

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

408: .vb
409:      F'(u)*a = [F(u+h*a) - F(u)]/h where
410:      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
411:        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
412:  where
413:      error_rel = square root of relative error in function evaluation
414:      umin = minimum iterate parameter
415: .ve

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

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

424:    Options Database Keys:
425: +  -snes_mf_err <error_rel> - Sets error_rel
426: .  -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
427: -  -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h

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

431: .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
432:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateMF(),
433:           MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic), MatSNESMFComputeJacobian()
434:  
435: @*/
436: int MatCreateSNESMF(SNES snes,Vec x,Mat *J)
437: {
438:   MatSNESMFCtx mfctx;
439:   int          ierr;

442:   MatCreateMF(x,J);

444:   mfctx          = (MatSNESMFCtx)(*J)->data;
445:   mfctx->snes    = snes;
446:   mfctx->usesnes = PETSC_TRUE;
447:   PetscLogObjectParent(snes,*J);
448:   return(0);
449: }

451: EXTERN_C_BEGIN
454: int MatSNESMFSetBase_FD(Mat J,Vec U)
455: {
456:   int          ierr;
457:   MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;

460:   MatSNESMFResetHHistory(J);
461:   ctx->current_u = U;
462:   ctx->usesnes   = PETSC_FALSE;
463:   if (ctx->w == PETSC_NULL) {
464:     VecDuplicate(ctx->current_u, &ctx->w);
465:   }
466:   return(0);
467: }
468: EXTERN_C_END

470: typedef int (*FCN3)(Vec,Vec,PetscScalar*,void*); /* force argument to next function to not be extern C*/
471: EXTERN_C_BEGIN
474: int MatSNESMFSetCheckh_FD(Mat J,FCN3 fun,void*ectx)
475: {
476:   MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;

479:   ctx->checkh    = fun;
480:   ctx->checkhctx = ectx;
481:   return(0);
482: }
483: EXTERN_C_END

487: /*@
488:    MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line
489:    parameter.

491:    Collective on Mat

493:    Input Parameters:
494: .  mat - the matrix obtained with MatCreateSNESMF()

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

501:    Level: advanced

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

505: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(), 
506:           MatSNESMFResetHHistory(), MatSNESMFKSPMonitor()
507: @*/
508: int MatSNESMFSetFromOptions(Mat mat)
509: {
510:   MatSNESMFCtx mfctx = (MatSNESMFCtx)mat->data;
511:   int          ierr;
512:   PetscTruth   flg;
513:   char         ftype[256];

516:   if (!MatSNESMFRegisterAllCalled) {MatSNESMFRegisterAll(PETSC_NULL);}
517: 
518:   PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatSNESMF");
519:   PetscOptionsList("-snes_mf_type","Matrix free type","MatSNESMFSetType",MatSNESMPetscFList,mfctx->type_name,ftype,256,&flg);
520:   if (flg) {
521:     MatSNESMFSetType(mat,ftype);
522:   }

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

545: /*MC
546:   MATMFFD - MATMFFD = "mffd" - A matrix free matrix type.

548:   Level: advanced

550: .seealso: MatCreateMF, MatCreateSNESMF
551: M*/
552: EXTERN_C_BEGIN
555: int MatCreate_MFFD(Mat A)
556: {
557:   MatSNESMFCtx mfctx;
558:   int          ierr;

561: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
562:   SNESInitializePackage(PETSC_NULL);
563: #endif

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

579:   mfctx->vshift          = 0.0;
580:   mfctx->vscale          = 1.0;

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

594:   mfctx->func                = 0;
595:   mfctx->funcctx             = 0;
596:   mfctx->funcvec             = 0;
597:   mfctx->w                   = PETSC_NULL;

599:   A->data                = mfctx;

601:   A->ops->mult           = MatMult_MFFD;
602:   A->ops->destroy        = MatDestroy_MFFD;
603:   A->ops->view           = MatView_MFFD;
604:   A->ops->assemblyend    = MatAssemblyEnd_MFFD;
605:   A->ops->getdiagonal    = MatGetDiagonal_MFFD;
606:   A->ops->scale          = MatScale_MFFD;
607:   A->ops->shift          = MatShift_MFFD;
608:   A->ops->setfromoptions = MatSNESMFSetFromOptions;

610:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetBase_C","MatSNESMFSetBase_FD",MatSNESMFSetBase_FD);
611:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioniBase_C","MatSNESMFSetFunctioniBase_FD",MatSNESMFSetFunctioniBase_FD);
612:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioni_C","MatSNESMFSetFunctioni_FD",MatSNESMFSetFunctioni_FD);
613:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetCheckh_C","MatSNESMFSetCheckh_FD",MatSNESMFSetCheckh_FD);
614:   mfctx->mat = A;

616:   return(0);
617: }
618: EXTERN_C_END

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

625:    Collective on Vec

627:    Input Parameters:
628: .  x - vector that defines layout of the vectors and matrices

630:    Output Parameter:
631: .  J - the matrix-free matrix

633:    Level: advanced

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

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

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

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

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

658:    Options Database Keys:
659: +  -snes_mf_err <error_rel> - Sets error_rel
660: .  -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
661: .  -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
662: -  -snes_mf_check_positivity

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

666: .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
667:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateSNESMF(),
668:           MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic),, MatSNESMFComputeJacobian()
669:  
670: @*/
671: int MatCreateMF(Vec x,Mat *J)
672: {
673:   MPI_Comm     comm;
674:   int          n,nloc,ierr;

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


689: /*@
690:    MatSNESMFGetH - Gets the last value that was used as the differencing 
691:    parameter.

693:    Not Collective

695:    Input Parameters:
696: .  mat - the matrix obtained with MatCreateSNESMF()

698:    Output Paramter:
699: .  h - the differencing step size

701:    Level: advanced

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

705: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(), 
706:           MatSNESMFResetHHistory(),MatSNESMFKSPMonitor()
707: @*/
708: int MatSNESMFGetH(Mat mat,PetscScalar *h)
709: {
710:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

713:   *h = ctx->currenth;
714:   return(0);
715: }

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

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

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

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

758:    Collective on Mat

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

766:    Level: advanced

768:    Notes:
769:     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
770:     matrix inside your compute Jacobian routine

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

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

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

785:   ctx->func    = func;
786:   ctx->funcctx = funcctx;
787:   ctx->funcvec = v;
788:   return(0);
789: }

793: /*@C
794:    MatSNESMFSetFunctioni - Sets the function for a single component

796:    Collective on Mat

798:    Input Parameters:
799: +  mat - the matrix free matrix created via MatCreateSNESMF()
800: -  funci - the function to use

802:    Level: advanced

804:    Notes:
805:     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
806:     matrix inside your compute Jacobian routine


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

811: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
812:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
813:           MatSNESMFKSPMonitor(), SNESetFunction()
814: @*/
815: int MatSNESMFSetFunctioni(Mat mat,int (*funci)(int,Vec,PetscScalar*,void *))
816: {
817:   int  ierr,(*f)(Mat,int (*)(int,Vec,PetscScalar*,void *));

821:   PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioni_C",(void (**)(void))&f);
822:   if (f) {
823:     (*f)(mat,funci);
824:   }
825:   return(0);
826: }


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

834:    Collective on Mat

836:    Input Parameters:
837: +  mat - the matrix free matrix created via MatCreateSNESMF()
838: -  func - the function to use

840:    Level: advanced

842:    Notes:
843:     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
844:     matrix inside your compute Jacobian routine


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

849: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
850:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
851:           MatSNESMFKSPMonitor(), SNESetFunction()
852: @*/
853: int MatSNESMFSetFunctioniBase(Mat mat,int (*func)(Vec,void *))
854: {
855:   int  ierr,(*f)(Mat,int (*)(Vec,void *));

859:   PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioniBase_C",(void (**)(void))&f);
860:   if (f) {
861:     (*f)(mat,func);
862:   }
863:   return(0);
864: }


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

872:    Collective on Mat

874:    Input Parameters:
875: +  mat - the matrix free matrix created via MatCreateSNESMF()
876: -  period - 1 for everytime, 2 for every second etc

878:    Options Database Keys:
879: +  -snes_mf_period <period>

881:    Level: advanced


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

886: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
887:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
888:           MatSNESMFKSPMonitor()
889: @*/
890: int MatSNESMFSetPeriod(Mat mat,int period)
891: {
892:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

895:   ctx->recomputeperiod = period;
896:   return(0);
897: }

901: /*@
902:    MatSNESMFSetFunctionError - Sets the error_rel for the approximation of
903:    matrix-vector products using finite differences.

905:    Collective on Mat

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

912:    Options Database Keys:
913: +  -snes_mf_err <error_rel> - Sets error_rel

915:    Level: advanced

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

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

927: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
928:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
929:           MatSNESMFKSPMonitor()
930: @*/
931: int MatSNESMFSetFunctionError(Mat mat,PetscReal error)
932: {
933:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

936:   if (error != PETSC_DEFAULT) ctx->error_rel = error;
937:   return(0);
938: }

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

948:    Collective on Mat 

950:    Input Parameters:
951: +  J - the matrix-free matrix context
952: -  nullsp - object created with MatNullSpaceCreate()

954:    Level: advanced

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

958: .seealso: MatNullSpaceCreate(), MatSNESMFGetH(), MatCreateSNESMF(),
959:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
960:           MatSNESMFKSPMonitor(), MatSNESMFErrorRel()
961: @*/
962: int MatSNESMFAddNullSpace(Mat J,MatNullSpace nullsp)
963: {
964:   int          ierr;
965:   MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
966:   MPI_Comm     comm;

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

971:   ctx->sp = nullsp;
972:   PetscObjectReference((PetscObject)nullsp);
973:   return(0);
974: }

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

982:    Collective on Mat 

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

990:    Level: advanced

992:    Notes:
993:    Use MatSNESMFResetHHistory() to reset the history counter and collect
994:    a new batch of differencing parameters, h.

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

998: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
999:           MatSNESMFResetHHistory(),
1000:           MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()

1002: @*/
1003: int MatSNESMFSetHHistory(Mat J,PetscScalar history[],int nhistory)
1004: {
1005:   MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;

1008:   ctx->historyh    = history;
1009:   ctx->maxcurrenth = nhistory;
1010:   ctx->currenth    = 0;
1011:   return(0);
1012: }

1016: /*@
1017:    MatSNESMFResetHHistory - Resets the counter to zero to begin 
1018:    collecting a new set of differencing histories.

1020:    Collective on Mat 

1022:    Input Parameters:
1023: .  J - the matrix-free matrix context

1025:    Level: advanced

1027:    Notes:
1028:    Use MatSNESMFSetHHistory() to create the original history counter.

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

1032: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
1033:           MatSNESMFSetHHistory(),
1034:           MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()

1036: @*/
1037: int MatSNESMFResetHHistory(Mat J)
1038: {
1039:   MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;

1042:   ctx->ncurrenth    = 0;
1043:   return(0);
1044: }

1048: int MatSNESMFComputeJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy)
1049: {
1052:   MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);
1053:   MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);
1054:   return(0);
1055: }

1059: /*@
1060:     MatSNESMFSetBase - Sets the vector U at which matrix vector products of the 
1061:         Jacobian are computed

1063:     Collective on Mat

1065:     Input Parameters:
1066: +   J - the MatSNESMF matrix
1067: -   U - the vector

1069:     Notes: This is rarely used directly

1071:     Level: advanced

1073: @*/
1074: int MatSNESMFSetBase(Mat J,Vec U)
1075: {
1076:   int  ierr,(*f)(Mat,Vec);

1081:   PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetBase_C",(void (**)(void))&f);
1082:   if (f) {
1083:     (*f)(J,U);
1084:   }
1085:   return(0);
1086: }

1090: /*@C
1091:     MatSNESMFSetCheckh - Sets a function that checks the computed h and adjusts
1092:         it to satisfy some criteria

1094:     Collective on Mat

1096:     Input Parameters:
1097: +   J - the MatSNESMF matrix
1098: .   fun - the function that checks h
1099: -   ctx - any context needed by the function

1101:     Options Database Keys:
1102: .   -snes_mf_check_positivity

1104:     Level: advanced

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

1109: .seealso:  MatSNESMFSetCheckPositivity()
1110: @*/
1111: int MatSNESMFSetCheckh(Mat J,int (*fun)(Vec,Vec,PetscScalar*,void*),void* ctx)
1112: {
1113:   int  ierr,(*f)(Mat,int (*)(Vec,Vec,PetscScalar*,void*),void*);

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

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

1130:     Collective on Vec

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

1138:     Options Database Keys:
1139: .   -snes_mf_check_positivity

1141:     Level: advanced

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

1146: .seealso:  MatSNESMFSetCheckh()
1147: @*/
1148: int MatSNESMFCheckPositivity(Vec U,Vec a,PetscScalar *h,void *dummy)
1149: {
1150:   PetscReal     val, minval;
1151:   PetscScalar   *u_vec, *a_vec;
1152:   int           ierr, i, size;
1153:   MPI_Comm      comm;

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