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;

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

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

 18:     Level: advanced

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

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

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

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

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

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

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

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

 56:   (*r)(ctx);

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

 60:   return(0);
 61: }

 63: EXTERN_C_BEGIN
 64: int MatSNESMFSetFunctioniBase_FD(Mat mat,int (*func)(Vec,void *))
 65: {
 66:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

 69:   ctx->funcisetbase = func;
 70:   return(0);
 71: }
 72: EXTERN_C_END

 74: EXTERN_C_BEGIN
 75: int MatSNESMFSetFunctioni_FD(Mat mat,int (*funci)(int,Vec,PetscScalar*,void *))
 76: {
 77:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

 80:   ctx->funci = funci;
 81:   return(0);
 82: }
 83: EXTERN_C_END

 85: /*MC
 86:    MatSNESMFRegisterDynamic - Adds a method to the MatSNESMF registry.

 88:    Synopsis:
 89:    int MatSNESMFRegisterDynamic(char *name_solver,char *path,char *name_create,int (*routine_create)(MatSNESMF))

 91:    Not Collective

 93:    Input Parameters:
 94: +  name_solver - name of a new user-defined compute-h module
 95: .  path - path (either absolute or relative) the library containing this solver
 96: .  name_create - name of routine to create method context
 97: -  routine_create - routine to create method context

 99:    Level: developer

101:    Notes:
102:    MatSNESMFRegisterDynamic) may be called multiple times to add several user-defined solvers.

104:    If dynamic libraries are used, then the fourth input argument (routine_create)
105:    is ignored.

107:    Sample usage:
108: .vb
109:    MatSNESMFRegisterDynamic"my_h",/home/username/my_lib/lib/libO/solaris/mylib.a,
110:                "MyHCreate",MyHCreate);
111: .ve

113:    Then, your solver can be chosen with the procedural interface via
114: $     MatSNESMFSetType(mfctx,"my_h")
115:    or at runtime via the option
116: $     -snes_mf_type my_h

118: .keywords: MatSNESMF, register

120: .seealso: MatSNESMFRegisterAll(), MatSNESMFRegisterDestroy()
121: M*/

123: int MatSNESMFRegister(char *sname,char *path,char *name,int (*function)(MatSNESMFCtx))
124: {
126:   char fullname[256];

129:   PetscFListConcat(path,name,fullname);
130:   PetscFListAdd(&MatSNESMPetscFList,sname,fullname,(void (*)(void))function);
131:   return(0);
132: }


135: /*@C
136:    MatSNESMFRegisterDestroy - Frees the list of MatSNESMF methods that were
137:    registered by MatSNESMFRegisterDynamic).

139:    Not Collective

141:    Level: developer

143: .keywords: MatSNESMF, register, destroy

145: .seealso: MatSNESMFRegisterDynamic), MatSNESMFRegisterAll()
146: @*/
147: int MatSNESMFRegisterDestroy(void)
148: {

152:   if (MatSNESMPetscFList) {
153:     PetscFListDestroy(&MatSNESMPetscFList);
154:     MatSNESMPetscFList = 0;
155:   }
156:   MatSNESMFRegisterAllCalled = PETSC_FALSE;
157:   return(0);
158: }

160: /* ----------------------------------------------------------------------------------------*/
161: int MatDestroy_MFFD(Mat mat)
162: {
163:   int          ierr;
164:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

167:   VecDestroy(ctx->w);
168:   if (ctx->ops->destroy) {(*ctx->ops->destroy)(ctx);}
169:   if (ctx->sp) {MatNullSpaceDestroy(ctx->sp);}
170:   PetscHeaderDestroy(ctx);
171:   return(0);
172: }

174: /*
175:    MatSNESMFView_MFFD - Views matrix-free parameters.

177: */
178: int MatView_MFFD(Mat J,PetscViewer viewer)
179: {
180:   int          ierr;
181:   MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
182:   PetscTruth   isascii;

185:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
186:   if (isascii) {
187:      PetscViewerASCIIPrintf(viewer,"  SNES matrix-free approximation:n");
188:      PetscViewerASCIIPrintf(viewer,"    err=%g (relative error in function evaluation)n",ctx->error_rel);
189:      if (!ctx->type_name) {
190:        PetscViewerASCIIPrintf(viewer,"    The compute h routine has not yet been setn");
191:      } else {
192:        PetscViewerASCIIPrintf(viewer,"    Using %s compute h routinen",ctx->type_name);
193:      }
194:      if (ctx->ops->view) {
195:        (*ctx->ops->view)(ctx,viewer);
196:      }
197:   } else {
198:     SETERRQ1(1,"Viewer type %s not supported for SNES matrix free matrix",((PetscObject)viewer)->type_name);
199:   }
200:   return(0);
201: }

203: /*
204:    MatSNESMFAssemblyEnd_Private - Resets the ctx->ncurrenth to zero. This 
205:    allows the user to indicate the beginning of a new linear solve by calling
206:    MatAssemblyXXX() on the matrix free matrix. This then allows the 
207:    MatSNESMFCreate_WP() to properly compute ||U|| only the first time
208:    in the linear solver rather than every time.
209: */
210: int MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt)
211: {
212:   int             ierr;
213:   MatSNESMFCtx    j = (MatSNESMFCtx)J->data;
214:   SNESProblemType type;

217:   MatSNESMFResetHHistory(J);
218:   if (j->usesnes) {
219:     SNESGetSolution(j->snes,&j->current_u);
220:     SNESGetProblemType(j->snes,&type);
221:     if (type == SNES_NONLINEAR_EQUATIONS) {
222:       SNESGetFunction(j->snes,&j->current_f,PETSC_NULL,PETSC_NULL);
223:     } else if (type == SNES_UNCONSTRAINED_MINIMIZATION) {
224:       SNESGetGradient(j->snes,&j->current_f,PETSC_NULL);
225:     } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid method class");
226:   }
227:   j->vshift = 0.0;
228:   j->vscale = 1.0;
229:   return(0);
230: }

232: /*
233:   MatSNESMFMult_Private - Default matrix-free form for Jacobian-vector
234:   product, y = F'(u)*a:

236:         y ~= (F(u + ha) - F(u))/h, 
237:   where F = nonlinear function, as set by SNESSetFunction()
238:         u = current iterate
239:         h = difference interval
240: */
241: int MatMult_MFFD(Mat mat,Vec a,Vec y)
242: {
243:   MatSNESMFCtx    ctx = (MatSNESMFCtx)mat->data;
244:   SNES            snes;
245:   PetscScalar     h,mone = -1.0;
246:   Vec             w,U,F;
247:   int             ierr,(*eval_fct)(SNES,Vec,Vec)=0;
248:   SNESProblemType type;

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

257:   snes = ctx->snes;
258:   w    = ctx->w;
259:   U    = ctx->current_u;

261:   /* 
262:       Compute differencing parameter 
263:   */
264:   if (!ctx->ops->compute) {
265:     MatSNESMFSetType(mat,MATSNESMF_DEFAULT);
266:     MatSNESMFSetFromOptions(mat);
267:   }
268:   (*ctx->ops->compute)(ctx,U,a,&h);

270:   /* keep a record of the current differencing parameter h */
271:   ctx->currenth = h;
272: #if defined(PETSC_USE_COMPLEX)
273:   PetscLogInfo(mat,"MatMult_MFFD:Current differencing parameter: %g + %g in",PetscRealPart(h),PetscImaginaryPart(h));
274: #else
275:   PetscLogInfo(mat,"MatMult_MFFD:Current differencing parameter: %15.12en",h);
276: #endif
277:   if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
278:     ctx->historyh[ctx->ncurrenth] = h;
279:   }
280:   ctx->ncurrenth++;

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

285:   if (ctx->usesnes) {
286:     SNESGetProblemType(snes,&type);
287:     if (type == SNES_NONLINEAR_EQUATIONS) {
288:       eval_fct = SNESComputeFunction;
289:     } else if (type == SNES_UNCONSTRAINED_MINIMIZATION) {
290:       eval_fct = SNESComputeGradient;
291:     } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid method class");
292:     F    = ctx->current_f;
293:     if (!F) SETERRQ(1,"You must call MatAssembly() even on matrix-free matrices");
294:     (*eval_fct)(snes,w,y);
295:   } else {
296:     F = ctx->funcvec;
297:     /* compute func(U) as base for differencing */
298:     if (ctx->ncurrenth == 1) {
299:       (*ctx->func)(snes,U,F,ctx->funcctx);
300:     }
301:     (*ctx->func)(snes,w,y,ctx->funcctx);
302:   }

304:   VecAXPY(&mone,F,y);
305:   h    = 1.0/h;
306:   VecScale(&h,y);


309:   if (ctx->vshift != 0.0 && ctx->vscale != 1.0) {
310:     VecAXPBY(&ctx->vshift,&ctx->vscale,a,y);
311:   } else if (ctx->vscale != 1.0) {
312:     VecScale(&ctx->vscale,y);
313:   } else if (ctx->vshift != 0.0) {
314:     VecAXPY(&ctx->vshift,a,y);
315:   }

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

319:   PetscLogEventEnd(MAT_MultMatrixFree,a,y,0,0);
320:   return(0);
321: }

323: /*
324:   MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix

326:         y ~= (F(u + ha) - F(u))/h, 
327:   where F = nonlinear function, as set by SNESSetFunction()
328:         u = current iterate
329:         h = difference interval
330: */
331: int MatGetDiagonal_MFFD(Mat mat,Vec a)
332: {
333:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
334:   PetscScalar  h,*aa,*ww,v;
335:   PetscReal    epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
336:   Vec          w,U;
337:   int          i,ierr,rstart,rend;

340:   if (!ctx->funci) {
341:     SETERRQ(1,"Requirers calling MatSNESMFSetFunctioni() first");
342:   }

344:   w    = ctx->w;
345:   U    = ctx->current_u;
346:   (*ctx->func)(0,U,a,ctx->funcctx);
347:   (*ctx->funcisetbase)(U,ctx->funcctx);
348:   VecCopy(U,w);

350:   VecGetOwnershipRange(a,&rstart,&rend);
351:   VecGetArray(a,&aa);
352:   for (i=rstart; i<rend; i++) {
353:     VecGetArray(w,&ww);
354:     h  = ww[i-rstart];
355:     if (h == 0.0) h = 1.0;
356: #if !defined(PETSC_USE_COMPLEX)
357:     if (h < umin && h >= 0.0)      h = umin;
358:     else if (h < 0.0 && h > -umin) h = -umin;
359: #else
360:     if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0)     h = umin;
361:     else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
362: #endif
363:     h     *= epsilon;
364: 
365:     ww[i-rstart] += h;
366:     VecRestoreArray(w,&ww);
367:     ierr          = (*ctx->funci)(i,w,&v,ctx->funcctx);
368:     aa[i-rstart]  = (v - aa[i-rstart])/h;

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

373:     VecGetArray(w,&ww);
374:     ww[i-rstart] -= h;
375:     VecRestoreArray(w,&ww);
376:   }
377:   VecRestoreArray(a,&aa);
378:   return(0);
379: }

381: int MatShift_MFFD(PetscScalar *a,Mat Y)
382: {
383:   MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
385:   shell->vshift += *a;
386:   return(0);
387: }

389: int MatScale_MFFD(PetscScalar *a,Mat Y)
390: {
391:   MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
393:   shell->vscale *= *a;
394:   return(0);
395: }


398: /*@C
399:    MatCreateSNESMF - Creates a matrix-free matrix context for use with
400:    a SNES solver.  This matrix can be used as the Jacobian argument for
401:    the routine SNESSetJacobian().

403:    Collective on SNES and Vec

405:    Input Parameters:
406: +  snes - the SNES context
407: -  x - vector where SNES solution is to be stored.

409:    Output Parameter:
410: .  J - the matrix-free matrix

412:    Level: advanced

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

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

421: .vb
422:      F'(u)*a = [F(u+h*a) - F(u)]/h where
423:      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
424:        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
425:  where
426:      error_rel = square root of relative error in function evaluation
427:      umin = minimum iterate parameter
428: .ve

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

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

437:    Options Database Keys:
438: +  -snes_mf_err <error_rel> - Sets error_rel
439: .  -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
440: -  -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h

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

444: .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
445:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateMF(),
446:           MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic), MatSNESMFComputeJacobian()
447:  
448: @*/
449: int MatCreateSNESMF(SNES snes,Vec x,Mat *J)
450: {
451:   MatSNESMFCtx mfctx;
452:   int          ierr;

455:   MatCreateMF(x,J);

457:   mfctx          = (MatSNESMFCtx)(*J)->data;
458:   mfctx->snes    = snes;
459:   mfctx->usesnes = PETSC_TRUE;
460:   PetscLogObjectParent(snes,*J);
461:   return(0);
462: }

464: EXTERN_C_BEGIN
465: int MatSNESMFSetBase_FD(Mat J,Vec U)
466: {
467:   int          ierr;
468:   MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;

471:   MatSNESMFResetHHistory(J);
472:   ctx->current_u = U;
473:   ctx->usesnes   = PETSC_FALSE;
474:   return(0);
475: }
476: EXTERN_C_END

478: /*@
479:    MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line
480:    parameter.

482:    Collective on Mat

484:    Input Parameters:
485: .  mat - the matrix obtained with MatCreateSNESMF()

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

492:    Level: advanced

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

496: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(), 
497:           MatSNESMFResetHHistory(), MatSNESMFKSPMonitor()
498: @*/
499: int MatSNESMFSetFromOptions(Mat mat)
500: {
501:   MatSNESMFCtx mfctx = (MatSNESMFCtx)mat->data;
502:   int          ierr;
503:   PetscTruth   flg;
504:   char         ftype[256];

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

515:   PetscOptionsReal("-snes_mf_err","set sqrt relative error in function","MatSNESMFSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);
516:   PetscOptionsInt("-snes_mf_period","how often h is recomputed","MatSNESMFSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);
517:   if (mfctx->snes) {
518:     PetscOptionsName("-snes_mf_ksp_monitor","Monitor matrix-free parameters","MatSNESMFKSPMonitor",&flg);
519:     if (flg) {
520:       SLES sles;
521:       KSP  ksp;
522:       SNESGetSLES(mfctx->snes,&sles);
523:       SLESGetKSP(sles,&ksp);
524:       KSPSetMonitor(ksp,MatSNESMFKSPMonitor,PETSC_NULL,0);
525:     }
526:   }
527:   if (mfctx->ops->setfromoptions) {
528:     (*mfctx->ops->setfromoptions)(mfctx);
529:   }
530:   PetscOptionsEnd();
531:   return(0);
532: }

534: EXTERN_C_BEGIN
535: int MatCreate_MFFD(Mat A)
536: {
537:   MatSNESMFCtx mfctx;
538:   int          ierr;

541:   PetscHeaderCreate(mfctx,_p_MatSNESMFCtx,struct _MFOps,MATSNESMFCTX_COOKIE,0,"SNESMF",A->comm,MatDestroy_MFFD,MatView_MFFD);
542:   PetscLogObjectCreate(mfctx);
543:   mfctx->sp              = 0;
544:   mfctx->snes            = 0;
545:   mfctx->error_rel       = PETSC_SQRT_MACHINE_EPSILON;
546:   mfctx->recomputeperiod = 1;
547:   mfctx->count           = 0;
548:   mfctx->currenth        = 0.0;
549:   mfctx->historyh        = PETSC_NULL;
550:   mfctx->ncurrenth       = 0;
551:   mfctx->maxcurrenth     = 0;
552:   mfctx->type_name       = 0;
553:   mfctx->usesnes         = PETSC_FALSE;

555:   mfctx->vshift          = 0.0;
556:   mfctx->vscale          = 1.0;

558:   /* 
559:      Create the empty data structure to contain compute-h routines.
560:      These will be filled in below from the command line options or 
561:      a later call with MatSNESMFSetType() or if that is not called 
562:      then it will default in the first use of MatMult_MFFD()
563:   */
564:   mfctx->ops->compute        = 0;
565:   mfctx->ops->destroy        = 0;
566:   mfctx->ops->view           = 0;
567:   mfctx->ops->setfromoptions = 0;
568:   mfctx->hctx                = 0;

570:   mfctx->func                = 0;
571:   mfctx->funcctx             = 0;
572:   mfctx->funcvec             = 0;

574:   A->data                = mfctx;

576:   A->ops->mult           = MatMult_MFFD;
577:   A->ops->destroy        = MatDestroy_MFFD;
578:   A->ops->view           = MatView_MFFD;
579:   A->ops->assemblyend    = MatAssemblyEnd_MFFD;
580:   A->ops->getdiagonal    = MatGetDiagonal_MFFD;
581:   A->ops->scale          = MatScale_MFFD;
582:   A->ops->shift          = MatShift_MFFD;
583:   A->ops->setfromoptions = MatSNESMFSetFromOptions;

585:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetBase_C","MatSNESMFSetBase_FD",MatSNESMFSetBase_FD);
586:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioniBase_C","MatSNESMFSetFunctioniBase_FD",MatSNESMFSetFunctioniBase_FD);
587:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioni_C","MatSNESMFSetFunctioni_FD",MatSNESMFSetFunctioni_FD);
588:   mfctx->mat = A;
589:   VecCreateMPI(A->comm,A->n,A->N,&mfctx->w);

591:   return(0);
592: }

594: EXTERN_C_END

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

599:    Collective on Vec

601:    Input Parameters:
602: .  x - vector that defines layout of the vectors and matrices

604:    Output Parameter:
605: .  J - the matrix-free matrix

607:    Level: advanced

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

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

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

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

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

632:    Options Database Keys:
633: +  -snes_mf_err <error_rel> - Sets error_rel
634: .  -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
635: -  -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h

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

639: .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
640:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateSNESMF(),
641:           MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic),, MatSNESMFComputeJacobian()
642:  
643: @*/
644: int MatCreateMF(Vec x,Mat *J)
645: {
646:   MPI_Comm     comm;
647:   int          n,nloc,ierr;

650:   PetscObjectGetComm((PetscObject)x,&comm);
651:   VecGetSize(x,&n);
652:   VecGetLocalSize(x,&nloc);
653:   MatCreate(comm,nloc,nloc,n,n,J);
654:   MatRegister(MATMFFD,0,"MatCreate_MFFD",MatCreate_MFFD);
655:   MatSetType(*J,MATMFFD);
656:   return(0);
657: }


660: /*@
661:    MatSNESMFGetH - Gets the last value that was used as the differencing 
662:    parameter.

664:    Not Collective

666:    Input Parameters:
667: .  mat - the matrix obtained with MatCreateSNESMF()

669:    Output Paramter:
670: .  h - the differencing step size

672:    Level: advanced

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

676: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(), 
677:           MatSNESMFResetHHistory(),MatSNESMFKSPMonitor()
678: @*/
679: int MatSNESMFGetH(Mat mat,PetscScalar *h)
680: {
681:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

684:   *h = ctx->currenth;
685:   return(0);
686: }

688: /*
689:    MatSNESMFKSPMonitor - A KSP monitor for use with the default PETSc
690:    SNES matrix free routines. Prints the differencing parameter used at 
691:    each step.
692: */
693: int MatSNESMFKSPMonitor(KSP ksp,int n,PetscReal rnorm,void *dummy)
694: {
695:   PC             pc;
696:   MatSNESMFCtx   ctx;
697:   int            ierr;
698:   Mat            mat;
699:   MPI_Comm       comm;
700:   PetscTruth     nonzeroinitialguess;

703:   PetscObjectGetComm((PetscObject)ksp,&comm);
704:   KSPGetPC(ksp,&pc);
705:   KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);
706:   PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL);
707:   ctx  = (MatSNESMFCtx)mat->data;

709:   if (n > 0 || nonzeroinitialguess) {
710: #if defined(PETSC_USE_COMPLEX)
711:     PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g + %g in",n,rnorm,
712:                 PetscRealPart(ctx->currenth),PetscImaginaryPart(ctx->currenth));
713: #else
714:     PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g n",n,rnorm,ctx->currenth);
715: #endif
716:   } else {
717:     PetscPrintf(comm,"%d KSP Residual norm %14.12en",n,rnorm);
718:   }
719:   return(0);
720: }

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

725:    Collective on Mat

727:    Input Parameters:
728: +  mat - the matrix free matrix created via MatCreateSNESMF()
729: .  v   - workspace vector
730: .  func - the function to use
731: -  funcctx - optional function context passed to function

733:    Level: advanced

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

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

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

743: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
744:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
745:           MatSNESMFKSPMonitor(), SNESetFunction()
746: @*/
747: int MatSNESMFSetFunction(Mat mat,Vec v,int (*func)(SNES,Vec,Vec,void *),void *funcctx)
748: {
749:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

752:   ctx->func    = func;
753:   ctx->funcctx = funcctx;
754:   ctx->funcvec = v;
755:   return(0);
756: }

758: /*@C
759:    MatSNESMFSetFunctioni - Sets the function for a single component

761:    Collective on Mat

763:    Input Parameters:
764: +  mat - the matrix free matrix created via MatCreateSNESMF()
765: -  funci - the function to use

767:    Level: advanced

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


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

776: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
777:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
778:           MatSNESMFKSPMonitor(), SNESetFunction()
779: @*/
780: int MatSNESMFSetFunctioni(Mat mat,int (*funci)(int,Vec,PetscScalar*,void *))
781: {
782:   int  ierr,(*f)(Mat,int (*)(int,Vec,PetscScalar*,void *));

786:   PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioni_C",(void (**)(void))&f);
787:   if (f) {
788:     (*f)(mat,funci);
789:   }
790:   return(0);
791: }


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

797:    Collective on Mat

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

803:    Level: advanced

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


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

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

822:   PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioniBase_C",(void (**)(void))&f);
823:   if (f) {
824:     (*f)(mat,func);
825:   }
826:   return(0);
827: }


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

833:    Collective on Mat

835:    Input Parameters:
836: +  mat - the matrix free matrix created via MatCreateSNESMF()
837: -  period - 1 for everytime, 2 for every second etc

839:    Options Database Keys:
840: +  -snes_mf_period <period>

842:    Level: advanced


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

847: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
848:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
849:           MatSNESMFKSPMonitor()
850: @*/
851: int MatSNESMFSetPeriod(Mat mat,int period)
852: {
853:   MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;

856:   ctx->recomputeperiod = period;
857:   return(0);
858: }

860: /*@
861:    MatSNESMFSetFunctionError - Sets the error_rel for the approximation of
862:    matrix-vector products using finite differences.

864:    Collective on Mat

866:    Input Parameters:
867: +  mat - the matrix free matrix created via MatCreateSNESMF()
868: -  error_rel - relative error (should be set to the square root of
869:                the relative error in the function evaluations)

871:    Options Database Keys:
872: +  -snes_mf_err <error_rel> - Sets error_rel

874:    Level: advanced

876:    Notes:
877:    The default matrix-free matrix-vector product routine computes
878: .vb
879:      F'(u)*a = [F(u+h*a) - F(u)]/h where
880:      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
881:        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   else
882: .ve

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

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

895:   if (error != PETSC_DEFAULT) ctx->error_rel = error;
896:   return(0);
897: }

899: /*@
900:    MatSNESMFAddNullSpace - Provides a null space that an operator is
901:    supposed to have.  Since roundoff will create a small component in
902:    the null space, if you know the null space you may have it
903:    automatically removed.

905:    Collective on Mat 

907:    Input Parameters:
908: +  J - the matrix-free matrix context
909: -  nullsp - object created with MatNullSpaceCreate()

911:    Level: advanced

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

915: .seealso: MatNullSpaceCreate(), MatSNESMFGetH(), MatCreateSNESMF(),
916:           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
917:           MatSNESMFKSPMonitor(), MatSNESMFErrorRel()
918: @*/
919: int MatSNESMFAddNullSpace(Mat J,MatNullSpace nullsp)
920: {
921:   int          ierr;
922:   MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
923:   MPI_Comm     comm;

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

928:   ctx->sp = nullsp;
929:   ierr    = PetscObjectReference((PetscObject)nullsp);
930:   return(0);
931: }

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

937:    Collective on Mat 

939:    Input Parameters:
940: +  J - the matrix-free matrix context
941: .  histroy - space to hold the history
942: -  nhistory - number of entries in history, if more entries are generated than
943:               nhistory, then the later ones are discarded

945:    Level: advanced

947:    Notes:
948:    Use MatSNESMFResetHHistory() to reset the history counter and collect
949:    a new batch of differencing parameters, h.

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

953: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
954:           MatSNESMFResetHHistory(),
955:           MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()

957: @*/
958: int MatSNESMFSetHHistory(Mat J,PetscScalar *history,int nhistory)
959: {
960:   MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;

963:   ctx->historyh    = history;
964:   ctx->maxcurrenth = nhistory;
965:   ctx->currenth    = 0;
966:   return(0);
967: }

969: /*@
970:    MatSNESMFResetHHistory - Resets the counter to zero to begin 
971:    collecting a new set of differencing histories.

973:    Collective on Mat 

975:    Input Parameters:
976: .  J - the matrix-free matrix context

978:    Level: advanced

980:    Notes:
981:    Use MatSNESMFSetHHistory() to create the original history counter.

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

985: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
986:           MatSNESMFSetHHistory(),
987:           MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()

989: @*/
990: int MatSNESMFResetHHistory(Mat J)
991: {
992:   MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;

995:   ctx->ncurrenth    = 0;
996:   return(0);
997: }

999: int MatSNESMFComputeJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy)
1000: {
1003:   MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);
1004:   MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);
1005:   return(0);
1006: }

1008: int MatSNESMFSetBase(Mat J,Vec U)
1009: {
1010:   int  ierr,(*f)(Mat,Vec);

1015:   PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetBase_C",(void (**)(void))&f);
1016:   if (f) {
1017:     (*f)(J,U);
1018:   }
1019:   return(0);
1020: }