Actual source code: snesmfj.c
1: #define PETSCSNES_DLL
3: #include src/mat/matimpl.h
4: #include src/snes/mf/snesmfj.h
6: PetscFList MatSNESMPetscFList = 0;
7: PetscTruth MatSNESMFRegisterAllCalled = PETSC_FALSE;
9: PetscCookie PETSCSNES_DLLEXPORT MATSNESMFCTX_COOKIE = 0;
10: PetscEvent MATSNESMF_Mult = 0;
14: /*@C
15: MatSNESMFSetType - Sets the method that is used to compute the
16: differencing parameter for finite differene matrix-free formulations.
18: Input Parameters:
19: + mat - the "matrix-free" matrix created via MatCreateSNESMF(), or MatCreateMF()
20: or MatSetType(mat,MATMFFD);
21: - ftype - the type requested
23: Level: advanced
25: Notes:
26: For example, such routines can compute h for use in
27: Jacobian-vector products of the form
29: F(x+ha) - F(x)
30: F'(u)a ~= ----------------
31: h
33: .seealso: MatCreateSNESMF(), MatSNESMFRegisterDynamic)
34: @*/
35: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetType(Mat mat,const MatSNESMFType ftype)
36: {
37: PetscErrorCode ierr,(*r)(MatSNESMFCtx);
38: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
39: PetscTruth match;
40:
45: /* already set, so just return */
46: PetscTypeCompare((PetscObject)ctx,ftype,&match);
47: if (match) return(0);
49: /* destroy the old one if it exists */
50: if (ctx->ops->destroy) {
51: (*ctx->ops->destroy)(ctx);
52: }
54: /* Get the function pointers for the requrested method */
55: if (!MatSNESMFRegisterAllCalled) {MatSNESMFRegisterAll(PETSC_NULL);}
56: PetscFListFind(ctx->comm,MatSNESMPetscFList,ftype,(void (**)(void)) &r);
57: if (!r) SETERRQ1(PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown MatSNESMF type %s given",ftype);
58: (*r)(ctx);
59: PetscObjectChangeTypeName((PetscObject)ctx,ftype);
60: return(0);
61: }
67: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunctioniBase_FD(Mat mat,FCN1 func)
68: {
69: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
72: ctx->funcisetbase = func;
73: return(0);
74: }
81: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunctioni_FD(Mat mat,FCN2 funci)
82: {
83: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
86: ctx->funci = funci;
87: return(0);
88: }
94: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFRegister(const char sname[],const char path[],const char name[],PetscErrorCode (*function)(MatSNESMFCtx))
95: {
97: char fullname[PETSC_MAX_PATH_LEN];
100: PetscFListConcat(path,name,fullname);
101: PetscFListAdd(&MatSNESMPetscFList,sname,fullname,(void (*)(void))function);
102: return(0);
103: }
108: /*@C
109: MatSNESMFRegisterDestroy - Frees the list of MatSNESMF methods that were
110: registered by MatSNESMFRegisterDynamic).
112: Not Collective
114: Level: developer
116: .keywords: MatSNESMF, register, destroy
118: .seealso: MatSNESMFRegisterDynamic), MatSNESMFRegisterAll()
119: @*/
120: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFRegisterDestroy(void)
121: {
125: if (MatSNESMPetscFList) {
126: PetscFListDestroy(&MatSNESMPetscFList);
127: MatSNESMPetscFList = 0;
128: }
129: MatSNESMFRegisterAllCalled = PETSC_FALSE;
130: return(0);
131: }
133: /* ----------------------------------------------------------------------------------------*/
136: PetscErrorCode MatDestroy_MFFD(Mat mat)
137: {
139: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
142: if (ctx->w) {
143: VecDestroy(ctx->w);
144: }
145: if (ctx->ops->destroy) {(*ctx->ops->destroy)(ctx);}
146: if (ctx->sp) {MatNullSpaceDestroy(ctx->sp);}
147: PetscHeaderDestroy(ctx);
149: PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetBase_C","",PETSC_NULL);
150: PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetFunctioniBase_C","",PETSC_NULL);
151: PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetFunctioni_C","",PETSC_NULL);
152: PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetCheckh_C","",PETSC_NULL);
154: return(0);
155: }
159: /*
160: MatSNESMFView_MFFD - Views matrix-free parameters.
162: */
163: PetscErrorCode MatView_MFFD(Mat J,PetscViewer viewer)
164: {
166: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
167: PetscTruth iascii;
170: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
171: if (iascii) {
172: PetscViewerASCIIPrintf(viewer," SNES matrix-free approximation:\n");
173: PetscViewerASCIIPrintf(viewer," err=%g (relative error in function evaluation)\n",ctx->error_rel);
174: if (!ctx->type_name) {
175: PetscViewerASCIIPrintf(viewer," The compute h routine has not yet been set\n");
176: } else {
177: PetscViewerASCIIPrintf(viewer," Using %s compute h routine\n",ctx->type_name);
178: }
179: if (ctx->ops->view) {
180: (*ctx->ops->view)(ctx,viewer);
181: }
182: } else {
183: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for SNES matrix free matrix",((PetscObject)viewer)->type_name);
184: }
185: return(0);
186: }
190: /*
191: MatAssemblyEnd_MFFD - Resets the ctx->ncurrenth to zero. This
192: allows the user to indicate the beginning of a new linear solve by calling
193: MatAssemblyXXX() on the matrix free matrix. This then allows the
194: MatSNESMFCreate_WP() to properly compute ||U|| only the first time
195: in the linear solver rather than every time.
196: */
197: PetscErrorCode MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt)
198: {
200: MatSNESMFCtx j = (MatSNESMFCtx)J->data;
203: MatSNESMFResetHHistory(J);
204: if (j->usesnes) {
205: SNESGetSolution(j->snes,&j->current_u);
206: SNESGetFunction(j->snes,&j->current_f,PETSC_NULL,PETSC_NULL);
207: if (!j->w) {
208: VecDuplicate(j->current_u, &j->w);
209: }
210: }
211: j->vshift = 0.0;
212: j->vscale = 1.0;
213: return(0);
214: }
218: /*
219: MatMult_MFFD - Default matrix-free form for Jacobian-vector product, y = F'(u)*a:
221: y ~= (F(u + ha) - F(u))/h,
222: where F = nonlinear function, as set by SNESSetFunction()
223: u = current iterate
224: h = difference interval
225: */
226: PetscErrorCode MatMult_MFFD(Mat mat,Vec a,Vec y)
227: {
228: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
229: SNES snes;
230: PetscScalar h,mone = -1.0;
231: Vec w,U,F;
232: PetscErrorCode ierr,(*eval_fct)(SNES,Vec,Vec)=0;
233: PetscTruth zeroa;
236: /* We log matrix-free matrix-vector products separately, so that we can
237: separate the performance monitoring from the cases that use conventional
238: storage. We may eventually modify event logging to associate events
239: with particular objects, hence alleviating the more general problem. */
240: PetscLogEventBegin(MATSNESMF_Mult,a,y,0,0);
242: snes = ctx->snes;
243: w = ctx->w;
244: U = ctx->current_u;
246: /*
247: Compute differencing parameter
248: */
249: if (!ctx->ops->compute) {
250: MatSNESMFSetType(mat,MATSNESMF_WP);
251: MatSNESMFSetFromOptions(mat);
252: }
253: (*ctx->ops->compute)(ctx,U,a,&h,&zeroa);
254: if (zeroa) {
255: PetscScalar zero = 0.0;
256: VecSet(y,zero);
257: return(0);
258: }
260: if (ctx->checkh) {
261: (*ctx->checkh)(U,a,&h,ctx->checkhctx);
262: }
264: /* keep a record of the current differencing parameter h */
265: ctx->currenth = h;
266: #if defined(PETSC_USE_COMPLEX)
267: PetscLogInfo((mat,"MatMult_MFFD:Current differencing parameter: %g + %g i\n",PetscRealPart(h),PetscImaginaryPart(h)));
268: #else
269: PetscLogInfo((mat,"MatMult_MFFD:Current differencing parameter: %15.12e\n",h));
270: #endif
271: if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
272: ctx->historyh[ctx->ncurrenth] = h;
273: }
274: ctx->ncurrenth++;
276: /* w = u + ha */
277: VecWAXPY(w,h,a,U);
279: if (ctx->usesnes) {
280: eval_fct = SNESComputeFunction;
281: F = ctx->current_f;
282: if (!F) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"You must call MatAssembly() even on matrix-free matrices");
283: (*eval_fct)(snes,w,y);
284: } else {
285: F = ctx->funcvec;
286: /* compute func(U) as base for differencing */
287: if (ctx->ncurrenth == 1) {
288: (*ctx->func)(snes,U,F,ctx->funcctx);
289: }
290: (*ctx->func)(snes,w,y,ctx->funcctx);
291: }
293: VecAXPY(y,mone,F);
294: h = 1.0/h;
295: VecScale(y,h);
297: VecAXPBY(y,ctx->vshift,ctx->vscale,a);
299: if (ctx->sp) {MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);}
301: PetscLogEventEnd(MATSNESMF_Mult,a,y,0,0);
302: return(0);
303: }
307: /*
308: MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix
310: y ~= (F(u + ha) - F(u))/h,
311: where F = nonlinear function, as set by SNESSetFunction()
312: u = current iterate
313: h = difference interval
314: */
315: PetscErrorCode MatGetDiagonal_MFFD(Mat mat,Vec a)
316: {
317: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
318: PetscScalar h,*aa,*ww,v;
319: PetscReal epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
320: Vec w,U;
322: PetscInt i,rstart,rend;
325: if (!ctx->funci) {
326: SETERRQ(PETSC_ERR_ORDER,"Requires calling MatSNESMFSetFunctioni() first");
327: }
329: w = ctx->w;
330: U = ctx->current_u;
331: (*ctx->func)(0,U,a,ctx->funcctx);
332: (*ctx->funcisetbase)(U,ctx->funcctx);
333: VecCopy(U,w);
335: VecGetOwnershipRange(a,&rstart,&rend);
336: VecGetArray(a,&aa);
337: for (i=rstart; i<rend; i++) {
338: VecGetArray(w,&ww);
339: h = ww[i-rstart];
340: if (h == 0.0) h = 1.0;
341: #if !defined(PETSC_USE_COMPLEX)
342: if (h < umin && h >= 0.0) h = umin;
343: else if (h < 0.0 && h > -umin) h = -umin;
344: #else
345: if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0) h = umin;
346: else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
347: #endif
348: h *= epsilon;
349:
350: ww[i-rstart] += h;
351: VecRestoreArray(w,&ww);
352: (*ctx->funci)(i,w,&v,ctx->funcctx);
353: aa[i-rstart] = (v - aa[i-rstart])/h;
355: /* possibly shift and scale result */
356: aa[i - rstart] = ctx->vshift + ctx->vscale*aa[i-rstart];
358: VecGetArray(w,&ww);
359: ww[i-rstart] -= h;
360: VecRestoreArray(w,&ww);
361: }
362: VecRestoreArray(a,&aa);
363: return(0);
364: }
368: PetscErrorCode MatShift_MFFD(Mat Y,PetscScalar a)
369: {
370: MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
372: shell->vshift += a;
373: return(0);
374: }
378: PetscErrorCode MatScale_MFFD(Mat Y,PetscScalar a)
379: {
380: MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
382: shell->vscale *= a;
383: return(0);
384: }
389: /*@C
390: MatCreateSNESMF - Creates a matrix-free matrix context for use with
391: a SNES solver. This matrix can be used as the Jacobian argument for
392: the routine SNESSetJacobian().
394: Collective on SNES and Vec
396: Input Parameters:
397: + snes - the SNES context
398: - x - vector where SNES solution is to be stored.
400: Output Parameter:
401: . J - the matrix-free matrix
403: Level: advanced
405: Notes:
406: The matrix-free matrix context merely contains the function pointers
407: and work space for performing finite difference approximations of
408: Jacobian-vector products, F'(u)*a,
410: The default code uses the following approach to compute h
412: .vb
413: F'(u)*a = [F(u+h*a) - F(u)]/h where
414: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
415: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise
416: where
417: error_rel = square root of relative error in function evaluation
418: umin = minimum iterate parameter
419: .ve
421: The user can set the error_rel via MatSNESMFSetFunctionError() and
422: umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
423: of the users manual for details.
425: The user should call MatDestroy() when finished with the matrix-free
426: matrix context.
428: Options Database Keys:
429: + -snes_mf_err <error_rel> - Sets error_rel
430: . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
431: - -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
433: .keywords: SNES, default, matrix-free, create, matrix
435: .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
436: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateMF(),
437: MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic), MatSNESMFComputeJacobian()
438:
439: @*/
440: PetscErrorCode PETSCSNES_DLLEXPORT MatCreateSNESMF(SNES snes,Vec x,Mat *J)
441: {
442: MatSNESMFCtx mfctx;
446: MatCreateMF(x,J);
448: mfctx = (MatSNESMFCtx)(*J)->data;
449: mfctx->snes = snes;
450: mfctx->usesnes = PETSC_TRUE;
451: PetscLogObjectParent(snes,*J);
452: return(0);
453: }
458: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetBase_FD(Mat J,Vec U)
459: {
461: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
464: MatSNESMFResetHHistory(J);
465: ctx->current_u = U;
466: ctx->usesnes = PETSC_FALSE;
467: if (!ctx->w) {
468: VecDuplicate(ctx->current_u, &ctx->w);
469: }
470: J->assembled = PETSC_TRUE;
471: return(0);
472: }
479: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetCheckh_FD(Mat J,FCN3 fun,void*ectx)
480: {
481: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
484: ctx->checkh = fun;
485: ctx->checkhctx = ectx;
486: return(0);
487: }
492: /*@
493: MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line
494: parameter.
496: Collective on Mat
498: Input Parameters:
499: . mat - the matrix obtained with MatCreateSNESMF()
501: Options Database Keys:
502: + -snes_mf_type - <default,wp>
503: - -snes_mf_err - square root of estimated relative error in function evaluation
504: - -snes_mf_period - how often h is recomputed, defaults to 1, everytime
506: Level: advanced
508: .keywords: SNES, matrix-free, parameters
510: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
511: MatSNESMFResetHHistory(), MatSNESMFKSPMonitor()
512: @*/
513: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFromOptions(Mat mat)
514: {
515: MatSNESMFCtx mfctx = (MatSNESMFCtx)mat->data;
517: PetscTruth flg;
518: char ftype[256];
521: if (!MatSNESMFRegisterAllCalled) {MatSNESMFRegisterAll(PETSC_NULL);}
522:
523: PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatSNESMF");
524: PetscOptionsList("-snes_mf_type","Matrix free type","MatSNESMFSetType",MatSNESMPetscFList,mfctx->type_name,ftype,256,&flg);
525: if (flg) {
526: MatSNESMFSetType(mat,ftype);
527: }
529: PetscOptionsReal("-snes_mf_err","set sqrt relative error in function","MatSNESMFSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);
530: PetscOptionsInt("-snes_mf_period","how often h is recomputed","MatSNESMFSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);
531: if (mfctx->snes) {
532: PetscOptionsName("-snes_mf_ksp_monitor","Monitor matrix-free parameters","MatSNESMFKSPMonitor",&flg);
533: if (flg) {
534: KSP ksp;
535: SNESGetKSP(mfctx->snes,&ksp);
536: KSPSetMonitor(ksp,MatSNESMFKSPMonitor,PETSC_NULL,0);
537: }
538: }
539: PetscOptionsName("-snes_mf_check_positivity","Insure that U + h*a is nonnegative","MatSNESMFSetCheckh",&flg);
540: if (flg) {
541: MatSNESMFSetCheckh(mat,MatSNESMFCheckPositivity,0);
542: }
543: if (mfctx->ops->setfromoptions) {
544: (*mfctx->ops->setfromoptions)(mfctx);
545: }
546: PetscOptionsEnd();
547: return(0);
548: }
550: /*MC
551: MATMFFD - MATMFFD = "mffd" - A matrix free matrix type.
553: Level: advanced
555: .seealso: MatCreateMF(), MatCreateSNESMF()
556: M*/
560: PetscErrorCode PETSCSNES_DLLEXPORT MatCreate_MFFD(Mat A)
561: {
562: MatSNESMFCtx mfctx;
566: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
567: SNESInitializePackage(PETSC_NULL);
568: #endif
570: PetscHeaderCreate(mfctx,_p_MatSNESMFCtx,struct _MFOps,MATSNESMFCTX_COOKIE,0,"SNESMF",A->comm,MatDestroy_MFFD,MatView_MFFD);
571: mfctx->sp = 0;
572: mfctx->snes = 0;
573: mfctx->error_rel = PETSC_SQRT_MACHINE_EPSILON;
574: mfctx->recomputeperiod = 1;
575: mfctx->count = 0;
576: mfctx->currenth = 0.0;
577: mfctx->historyh = PETSC_NULL;
578: mfctx->ncurrenth = 0;
579: mfctx->maxcurrenth = 0;
580: mfctx->type_name = 0;
581: mfctx->usesnes = PETSC_FALSE;
583: mfctx->vshift = 0.0;
584: mfctx->vscale = 1.0;
586: /*
587: Create the empty data structure to contain compute-h routines.
588: These will be filled in below from the command line options or
589: a later call with MatSNESMFSetType() or if that is not called
590: then it will default in the first use of MatMult_MFFD()
591: */
592: mfctx->ops->compute = 0;
593: mfctx->ops->destroy = 0;
594: mfctx->ops->view = 0;
595: mfctx->ops->setfromoptions = 0;
596: mfctx->hctx = 0;
598: mfctx->func = 0;
599: mfctx->funcctx = 0;
600: mfctx->funcvec = 0;
601: mfctx->w = PETSC_NULL;
603: A->data = mfctx;
605: A->ops->mult = MatMult_MFFD;
606: A->ops->destroy = MatDestroy_MFFD;
607: A->ops->view = MatView_MFFD;
608: A->ops->assemblyend = MatAssemblyEnd_MFFD;
609: A->ops->getdiagonal = MatGetDiagonal_MFFD;
610: A->ops->scale = MatScale_MFFD;
611: A->ops->shift = MatShift_MFFD;
612: A->ops->setfromoptions = MatSNESMFSetFromOptions;
613: A->assembled = PETSC_TRUE;
615: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetBase_C","MatSNESMFSetBase_FD",MatSNESMFSetBase_FD);
616: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioniBase_C","MatSNESMFSetFunctioniBase_FD",MatSNESMFSetFunctioniBase_FD);
617: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioni_C","MatSNESMFSetFunctioni_FD",MatSNESMFSetFunctioni_FD);
618: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetCheckh_C","MatSNESMFSetCheckh_FD",MatSNESMFSetCheckh_FD);
619: mfctx->mat = A;
621: return(0);
622: }
627: /*@C
628: MatCreateMF - Creates a matrix-free matrix. See also MatCreateSNESMF()
630: Collective on Vec
632: Input Parameters:
633: . x - vector that defines layout of the vectors and matrices
635: Output Parameter:
636: . J - the matrix-free matrix
638: Level: advanced
640: Notes:
641: The matrix-free matrix context merely contains the function pointers
642: and work space for performing finite difference approximations of
643: Jacobian-vector products, F'(u)*a,
645: The default code uses the following approach to compute h
647: .vb
648: F'(u)*a = [F(u+h*a) - F(u)]/h where
649: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
650: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise
651: where
652: error_rel = square root of relative error in function evaluation
653: umin = minimum iterate parameter
654: .ve
656: The user can set the error_rel via MatSNESMFSetFunctionError() and
657: umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
658: of the users manual for details.
660: The user should call MatDestroy() when finished with the matrix-free
661: matrix context.
663: Options Database Keys:
664: + -snes_mf_err <error_rel> - Sets error_rel
665: . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
666: . -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
667: - -snes_mf_check_positivity
669: .keywords: default, matrix-free, create, matrix
671: .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
672: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateSNESMF(),
673: MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic),, MatSNESMFComputeJacobian()
674:
675: @*/
676: PetscErrorCode PETSCSNES_DLLEXPORT MatCreateMF(Vec x,Mat *J)
677: {
678: MPI_Comm comm;
680: PetscInt n,nloc;
683: PetscObjectGetComm((PetscObject)x,&comm);
684: VecGetSize(x,&n);
685: VecGetLocalSize(x,&nloc);
686: MatCreate(comm,J);
687: MatSetSizes(*J,nloc,nloc,n,n);
688: MatRegisterDynamic(MATMFFD,0,"MatCreate_MFFD",MatCreate_MFFD);
689: MatSetType(*J,MATMFFD);
690: return(0);
691: }
696: /*@
697: MatSNESMFGetH - Gets the last value that was used as the differencing
698: parameter.
700: Not Collective
702: Input Parameters:
703: . mat - the matrix obtained with MatCreateSNESMF()
705: Output Paramter:
706: . h - the differencing step size
708: Level: advanced
710: .keywords: SNES, matrix-free, parameters
712: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
713: MatSNESMFResetHHistory(),MatSNESMFKSPMonitor()
714: @*/
715: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFGetH(Mat mat,PetscScalar *h)
716: {
717: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
720: *h = ctx->currenth;
721: return(0);
722: }
726: /*
727: MatSNESMFKSPMonitor - A KSP monitor for use with the default PETSc
728: SNES matrix free routines. Prints the differencing parameter used at
729: each step.
730: */
731: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFKSPMonitor(KSP ksp,PetscInt n,PetscReal rnorm,void *dummy)
732: {
733: PC pc;
734: MatSNESMFCtx ctx;
736: Mat mat;
737: MPI_Comm comm;
738: PetscTruth nonzeroinitialguess;
741: PetscObjectGetComm((PetscObject)ksp,&comm);
742: KSPGetPC(ksp,&pc);
743: KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);
744: PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL);
745: ctx = (MatSNESMFCtx)mat->data;
747: if (n > 0 || nonzeroinitialguess) {
748: #if defined(PETSC_USE_COMPLEX)
749: PetscPrintf(comm,"%D KSP Residual norm %14.12e h %g + %g i\n",n,rnorm,
750: PetscRealPart(ctx->currenth),PetscImaginaryPart(ctx->currenth));
751: #else
752: PetscPrintf(comm,"%D KSP Residual norm %14.12e h %g \n",n,rnorm,ctx->currenth);
753: #endif
754: } else {
755: PetscPrintf(comm,"%D KSP Residual norm %14.12e\n",n,rnorm);
756: }
757: return(0);
758: }
762: /*@C
763: MatSNESMFSetFunction - Sets the function used in applying the matrix free.
765: Collective on Mat
767: Input Parameters:
768: + mat - the matrix free matrix created via MatCreateSNESMF()
769: . v - workspace vector
770: . func - the function to use
771: - funcctx - optional function context passed to function
773: Level: advanced
775: Notes:
776: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
777: matrix inside your compute Jacobian routine
779: If this is not set then it will use the function set with SNESSetFunction()
781: .keywords: SNES, matrix-free, function
783: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
784: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
785: MatSNESMFKSPMonitor(), SNESetFunction()
786: @*/
787: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunction(Mat mat,Vec v,PetscErrorCode (*func)(SNES,Vec,Vec,void *),void *funcctx)
788: {
789: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
792: ctx->func = func;
793: ctx->funcctx = funcctx;
794: ctx->funcvec = v;
795: return(0);
796: }
800: /*@C
801: MatSNESMFSetFunctioni - Sets the function for a single component
803: Collective on Mat
805: Input Parameters:
806: + mat - the matrix free matrix created via MatCreateSNESMF()
807: - funci - the function to use
809: Level: advanced
811: Notes:
812: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
813: matrix inside your compute Jacobian routine
816: .keywords: SNES, matrix-free, function
818: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
819: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
820: MatSNESMFKSPMonitor(), SNESetFunction()
821: @*/
822: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunctioni(Mat mat,PetscErrorCode (*funci)(PetscInt,Vec,PetscScalar*,void *))
823: {
824: PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(PetscInt,Vec,PetscScalar*,void *));
828: PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioni_C",(void (**)(void))&f);
829: if (f) {
830: (*f)(mat,funci);
831: }
832: return(0);
833: }
838: /*@C
839: MatSNESMFSetFunctioniBase - Sets the base vector for a single component function evaluation
841: Collective on Mat
843: Input Parameters:
844: + mat - the matrix free matrix created via MatCreateSNESMF()
845: - func - the function to use
847: Level: advanced
849: Notes:
850: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
851: matrix inside your compute Jacobian routine
854: .keywords: SNES, matrix-free, function
856: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
857: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
858: MatSNESMFKSPMonitor(), SNESetFunction()
859: @*/
860: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunctioniBase(Mat mat,PetscErrorCode (*func)(Vec,void *))
861: {
862: PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(Vec,void *));
866: PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioniBase_C",(void (**)(void))&f);
867: if (f) {
868: (*f)(mat,func);
869: }
870: return(0);
871: }
876: /*@
877: MatSNESMFSetPeriod - Sets how often h is recomputed, by default it is everytime
879: Collective on Mat
881: Input Parameters:
882: + mat - the matrix free matrix created via MatCreateSNESMF()
883: - period - 1 for everytime, 2 for every second etc
885: Options Database Keys:
886: + -snes_mf_period <period>
888: Level: advanced
891: .keywords: SNES, matrix-free, parameters
893: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
894: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
895: MatSNESMFKSPMonitor()
896: @*/
897: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetPeriod(Mat mat,PetscInt period)
898: {
899: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
902: ctx->recomputeperiod = period;
903: return(0);
904: }
908: /*@
909: MatSNESMFSetFunctionError - Sets the error_rel for the approximation of
910: matrix-vector products using finite differences.
912: Collective on Mat
914: Input Parameters:
915: + mat - the matrix free matrix created via MatCreateSNESMF()
916: - error_rel - relative error (should be set to the square root of
917: the relative error in the function evaluations)
919: Options Database Keys:
920: + -snes_mf_err <error_rel> - Sets error_rel
922: Level: advanced
924: Notes:
925: The default matrix-free matrix-vector product routine computes
926: .vb
927: F'(u)*a = [F(u+h*a) - F(u)]/h where
928: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
929: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else
930: .ve
932: .keywords: SNES, matrix-free, parameters
934: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
935: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
936: MatSNESMFKSPMonitor()
937: @*/
938: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunctionError(Mat mat,PetscReal error)
939: {
940: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
943: if (error != PETSC_DEFAULT) ctx->error_rel = error;
944: return(0);
945: }
949: /*@
950: MatSNESMFAddNullSpace - Provides a null space that an operator is
951: supposed to have. Since roundoff will create a small component in
952: the null space, if you know the null space you may have it
953: automatically removed.
955: Collective on Mat
957: Input Parameters:
958: + J - the matrix-free matrix context
959: - nullsp - object created with MatNullSpaceCreate()
961: Level: advanced
963: .keywords: SNES, matrix-free, null space
965: .seealso: MatNullSpaceCreate(), MatSNESMFGetH(), MatCreateSNESMF(),
966: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
967: MatSNESMFKSPMonitor(), MatSNESMFErrorRel()
968: @*/
969: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFAddNullSpace(Mat J,MatNullSpace nullsp)
970: {
972: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
973: MPI_Comm comm;
976: PetscObjectGetComm((PetscObject)J,&comm);
978: ctx->sp = nullsp;
979: PetscObjectReference((PetscObject)nullsp);
980: return(0);
981: }
985: /*@
986: MatSNESMFSetHHistory - Sets an array to collect a history of the
987: differencing values (h) computed for the matrix-free product.
989: Collective on Mat
991: Input Parameters:
992: + J - the matrix-free matrix context
993: . histroy - space to hold the history
994: - nhistory - number of entries in history, if more entries are generated than
995: nhistory, then the later ones are discarded
997: Level: advanced
999: Notes:
1000: Use MatSNESMFResetHHistory() to reset the history counter and collect
1001: a new batch of differencing parameters, h.
1003: .keywords: SNES, matrix-free, h history, differencing history
1005: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
1006: MatSNESMFResetHHistory(),
1007: MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
1009: @*/
1010: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetHHistory(Mat J,PetscScalar history[],PetscInt nhistory)
1011: {
1012: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
1015: ctx->historyh = history;
1016: ctx->maxcurrenth = nhistory;
1017: ctx->currenth = 0;
1018: return(0);
1019: }
1023: /*@
1024: MatSNESMFResetHHistory - Resets the counter to zero to begin
1025: collecting a new set of differencing histories.
1027: Collective on Mat
1029: Input Parameters:
1030: . J - the matrix-free matrix context
1032: Level: advanced
1034: Notes:
1035: Use MatSNESMFSetHHistory() to create the original history counter.
1037: .keywords: SNES, matrix-free, h history, differencing history
1039: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
1040: MatSNESMFSetHHistory(),
1041: MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
1043: @*/
1044: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFResetHHistory(Mat J)
1045: {
1046: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
1049: ctx->ncurrenth = 0;
1050: return(0);
1051: }
1055: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFComputeJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy)
1056: {
1059: MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);
1060: MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);
1061: return(0);
1062: }
1066: /*@
1067: MatSNESMFSetBase - Sets the vector U at which matrix vector products of the
1068: Jacobian are computed
1070: Collective on Mat
1072: Input Parameters:
1073: + J - the MatSNESMF matrix
1074: - U - the vector
1076: Notes: This is rarely used directly
1078: Level: advanced
1080: @*/
1081: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetBase(Mat J,Vec U)
1082: {
1083: PetscErrorCode ierr,(*f)(Mat,Vec);
1088: PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetBase_C",(void (**)(void))&f);
1089: if (f) {
1090: (*f)(J,U);
1091: }
1092: return(0);
1093: }
1097: /*@C
1098: MatSNESMFSetCheckh - Sets a function that checks the computed h and adjusts
1099: it to satisfy some criteria
1101: Collective on Mat
1103: Input Parameters:
1104: + J - the MatSNESMF matrix
1105: . fun - the function that checks h
1106: - ctx - any context needed by the function
1108: Options Database Keys:
1109: . -snes_mf_check_positivity
1111: Level: advanced
1113: Notes: For example, MatSNESMFSetCheckPositivity() insures that all entries
1114: of U + h*a are non-negative
1116: .seealso: MatSNESMFSetCheckPositivity()
1117: @*/
1118: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetCheckh(Mat J,PetscErrorCode (*fun)(Vec,Vec,PetscScalar*,void*),void* ctx)
1119: {
1120: PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(Vec,Vec,PetscScalar*,void*),void*);
1124: PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetCheckh_C",(void (**)(void))&f);
1125: if (f) {
1126: (*f)(J,fun,ctx);
1127: }
1128: return(0);
1129: }
1133: /*@
1134: MatSNESMFCheckPositivity - Checks that all entries in U + h*a are positive or
1135: zero, decreases h until this is satisfied.
1137: Collective on Vec
1139: Input Parameters:
1140: + U - base vector that is added to
1141: . a - vector that is added
1142: . h - scaling factor on a
1143: - dummy - context variable (unused)
1145: Options Database Keys:
1146: . -snes_mf_check_positivity
1148: Level: advanced
1150: Notes: This is rarely used directly, rather it is passed as an argument to
1151: MatSNESMFSetCheckh()
1153: .seealso: MatSNESMFSetCheckh()
1154: @*/
1155: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFCheckPositivity(Vec U,Vec a,PetscScalar *h,void *dummy)
1156: {
1157: PetscReal val, minval;
1158: PetscScalar *u_vec, *a_vec;
1160: PetscInt i,n;
1161: MPI_Comm comm;
1164: PetscObjectGetComm((PetscObject)U,&comm);
1165: VecGetArray(U,&u_vec);
1166: VecGetArray(a,&a_vec);
1167: VecGetLocalSize(U,&n);
1168: minval = PetscAbsScalar(*h*1.01);
1169: for(i=0;i<n;i++) {
1170: if (PetscRealPart(u_vec[i] + *h*a_vec[i]) <= 0.0) {
1171: val = PetscAbsScalar(u_vec[i]/a_vec[i]);
1172: if (val < minval) minval = val;
1173: }
1174: }
1175: VecRestoreArray(U,&u_vec);
1176: VecRestoreArray(a,&a_vec);
1177: PetscGlobalMin(&minval,&val,comm);
1178: if (val <= PetscAbsScalar(*h)) {
1179: PetscLogInfo((U,"MatSNESMFCheckPositivity: Scaling back h from %g to %g\n",PetscRealPart(*h),.99*val));
1180: if (PetscRealPart(*h) > 0.0) *h = 0.99*val;
1181: else *h = -0.99*val;
1182: }
1183: return(0);
1184: }