Actual source code: mffd.c
1: #define PETSCMAT_DLL
3: #include private/matimpl.h
4: #include ../src/mat/impls/mffd/mffdimpl.h
6: PetscFList MatMFFDList = 0;
7: PetscTruth MatMFFDRegisterAllCalled = PETSC_FALSE;
9: PetscCookie MATMFFD_COOKIE;
10: PetscLogEvent MATMFFD_Mult;
12: static PetscTruth MatMFFDPackageInitialized = PETSC_FALSE;
15: /*@C
16: MatMFFDFinalizePackage - This function destroys everything in the MatMFFD package. It is
17: called from PetscFinalize().
19: Level: developer
21: .keywords: Petsc, destroy, package
22: .seealso: PetscFinalize()
23: @*/
24: PetscErrorCode MatMFFDFinalizePackage(void)
25: {
27: MatMFFDPackageInitialized = PETSC_FALSE;
28: MatMFFDRegisterAllCalled = PETSC_FALSE;
29: MatMFFDList = PETSC_NULL;
30: return(0);
31: }
35: /*@C
36: MatMFFDInitializePackage - This function initializes everything in the MatMFFD package. It is called
37: from PetscDLLibraryRegister() when using dynamic libraries, and on the first call to MatCreate_MFFD()
38: when using static libraries.
40: Input Parameter:
41: . path - The dynamic library path, or PETSC_NULL
43: Level: developer
45: .keywords: Vec, initialize, package
46: .seealso: PetscInitialize()
47: @*/
48: PetscErrorCode MatMFFDInitializePackage(const char path[])
49: {
50: char logList[256];
51: char *className;
52: PetscTruth opt;
53: PetscErrorCode ierr;
56: if (MatMFFDPackageInitialized) return(0);
57: MatMFFDPackageInitialized = PETSC_TRUE;
58: /* Register Classes */
59: PetscCookieRegister("MatMFFD",&MATMFFD_COOKIE);
60: /* Register Constructors */
61: MatMFFDRegisterAll(path);
62: /* Register Events */
63: PetscLogEventRegister("MatMult MF", MATMFFD_COOKIE,&MATMFFD_Mult);
65: /* Process info exclusions */
66: PetscOptionsGetString(PETSC_NULL, "-info_exclude", logList, 256, &opt);
67: if (opt) {
68: PetscStrstr(logList, "matmffd", &className);
69: if (className) {
70: PetscInfoDeactivateClass(MATMFFD_COOKIE);
71: }
72: }
73: /* Process summary exclusions */
74: PetscOptionsGetString(PETSC_NULL, "-log_summary_exclude", logList, 256, &opt);
75: if (opt) {
76: PetscStrstr(logList, "matmffd", &className);
77: if (className) {
78: PetscLogEventDeactivateClass(MATMFFD_COOKIE);
79: }
80: }
81: PetscRegisterFinalize(MatMFFDFinalizePackage);
82: return(0);
83: }
87: /*@C
88: MatMFFDSetType - Sets the method that is used to compute the
89: differencing parameter for finite differene matrix-free formulations.
91: Input Parameters:
92: + mat - the "matrix-free" matrix created via MatCreateSNESMF(), or MatCreateMFFD()
93: or MatSetType(mat,MATMFFD);
94: - ftype - the type requested, either MATMFFD_WP or MATMFFD_DS
96: Level: advanced
98: Notes:
99: For example, such routines can compute h for use in
100: Jacobian-vector products of the form
102: F(x+ha) - F(x)
103: F'(u)a ~= ----------------
104: h
106: .seealso: MatCreateSNESMF(), MatMFFDRegisterDynamic(), MatMFFDSetFunction()
107: @*/
108: PetscErrorCode MatMFFDSetType(Mat mat,const MatMFFDType ftype)
109: {
110: PetscErrorCode ierr,(*r)(MatMFFD);
111: MatMFFD ctx = (MatMFFD)mat->data;
112: PetscTruth match;
113:
118: /* already set, so just return */
119: PetscTypeCompare((PetscObject)ctx,ftype,&match);
120: if (match) return(0);
122: /* destroy the old one if it exists */
123: if (ctx->ops->destroy) {
124: (*ctx->ops->destroy)(ctx);
125: }
127: PetscFListFind(MatMFFDList,((PetscObject)ctx)->comm,ftype,(void (**)(void)) &r);
128: if (!r) SETERRQ1(PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown MatMFFD type %s given",ftype);
129: (*r)(ctx);
130: PetscObjectChangeTypeName((PetscObject)ctx,ftype);
131: return(0);
132: }
138: PetscErrorCode MatMFFDSetFunctioniBase_MFFD(Mat mat,FCN1 func)
139: {
140: MatMFFD ctx = (MatMFFD)mat->data;
143: ctx->funcisetbase = func;
144: return(0);
145: }
152: PetscErrorCode MatMFFDSetFunctioni_MFFD(Mat mat,FCN2 funci)
153: {
154: MatMFFD ctx = (MatMFFD)mat->data;
157: ctx->funci = funci;
158: return(0);
159: }
165: PetscErrorCode MatMFFDRegister(const char sname[],const char path[],const char name[],PetscErrorCode (*function)(MatMFFD))
166: {
168: char fullname[PETSC_MAX_PATH_LEN];
171: PetscFListConcat(path,name,fullname);
172: PetscFListAdd(&MatMFFDList,sname,fullname,(void (*)(void))function);
173: return(0);
174: }
179: /*@C
180: MatMFFDRegisterDestroy - Frees the list of MatMFFD methods that were
181: registered by MatMFFDRegisterDynamic).
183: Not Collective
185: Level: developer
187: .keywords: MatMFFD, register, destroy
189: .seealso: MatMFFDRegisterDynamic), MatMFFDRegisterAll()
190: @*/
191: PetscErrorCode MatMFFDRegisterDestroy(void)
192: {
196: PetscFListDestroy(&MatMFFDList);
197: MatMFFDRegisterAllCalled = PETSC_FALSE;
198: return(0);
199: }
201: /* ----------------------------------------------------------------------------------------*/
204: PetscErrorCode MatDestroy_MFFD(Mat mat)
205: {
207: MatMFFD ctx = (MatMFFD)mat->data;
210: if (ctx->w) {
211: VecDestroy(ctx->w);
212: }
213: if (ctx->current_f_allocated) {
214: VecDestroy(ctx->current_f);
215: }
216: if (ctx->ops->destroy) {(*ctx->ops->destroy)(ctx);}
217: if (ctx->sp) {MatNullSpaceDestroy(ctx->sp);}
218: PetscHeaderDestroy(ctx);
220: PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetBase_C","",PETSC_NULL);
221: PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctioniBase_C","",PETSC_NULL);
222: PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctioni_C","",PETSC_NULL);
223: PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetCheckh_C","",PETSC_NULL);
225: return(0);
226: }
230: /*
231: MatMFFDView_MFFD - Views matrix-free parameters.
233: */
234: PetscErrorCode MatView_MFFD(Mat J,PetscViewer viewer)
235: {
237: MatMFFD ctx = (MatMFFD)J->data;
238: PetscTruth iascii;
241: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
242: if (iascii) {
243: PetscViewerASCIIPrintf(viewer," matrix-free approximation:\n");
244: PetscViewerASCIIPrintf(viewer," err=%G (relative error in function evaluation)\n",ctx->error_rel);
245: if (!((PetscObject)ctx)->type_name) {
246: PetscViewerASCIIPrintf(viewer," The compute h routine has not yet been set\n");
247: } else {
248: PetscViewerASCIIPrintf(viewer," Using %s compute h routine\n",((PetscObject)ctx)->type_name);
249: }
250: if (ctx->ops->view) {
251: (*ctx->ops->view)(ctx,viewer);
252: }
253: } else {
254: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for matrix-free matrix",((PetscObject)viewer)->type_name);
255: }
256: return(0);
257: }
261: /*
262: MatAssemblyEnd_MFFD - Resets the ctx->ncurrenth to zero. This
263: allows the user to indicate the beginning of a new linear solve by calling
264: MatAssemblyXXX() on the matrix free matrix. This then allows the
265: MatMFFDCreate_WP() to properly compute ||U|| only the first time
266: in the linear solver rather than every time.
267: */
268: PetscErrorCode MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt)
269: {
271: MatMFFD j = (MatMFFD)J->data;
274: MatMFFDResetHHistory(J);
275: j->vshift = 0.0;
276: j->vscale = 1.0;
277: return(0);
278: }
282: /*
283: MatMult_MFFD - Default matrix-free form for Jacobian-vector product, y = F'(u)*a:
285: y ~= (F(u + ha) - F(u))/h,
286: where F = nonlinear function, as set by SNESSetFunction()
287: u = current iterate
288: h = difference interval
289: */
290: PetscErrorCode MatMult_MFFD(Mat mat,Vec a,Vec y)
291: {
292: MatMFFD ctx = (MatMFFD)mat->data;
293: PetscScalar h;
294: Vec w,U,F;
296: PetscTruth zeroa;
299: /* We log matrix-free matrix-vector products separately, so that we can
300: separate the performance monitoring from the cases that use conventional
301: storage. We may eventually modify event logging to associate events
302: with particular objects, hence alleviating the more general problem. */
303: PetscLogEventBegin(MATMFFD_Mult,a,y,0,0);
305: w = ctx->w;
306: U = ctx->current_u;
307: F = ctx->current_f;
308: /*
309: Compute differencing parameter
310: */
311: if (!ctx->ops->compute) {
312: MatMFFDSetType(mat,MATMFFD_WP);
313: MatMFFDSetFromOptions(mat);
314: }
315: (*ctx->ops->compute)(ctx,U,a,&h,&zeroa);
316: if (zeroa) {
317: VecSet(y,0.0);
318: return(0);
319: }
321: if (h != h) SETERRQ(PETSC_ERR_PLIB,"Computed Nan differencing parameter h");
322: if (ctx->checkh) {
323: (*ctx->checkh)(ctx->checkhctx,U,a,&h);
324: }
326: /* keep a record of the current differencing parameter h */
327: ctx->currenth = h;
328: #if defined(PETSC_USE_COMPLEX)
329: PetscInfo2(mat,"Current differencing parameter: %G + %G i\n",PetscRealPart(h),PetscImaginaryPart(h));
330: #else
331: PetscInfo1(mat,"Current differencing parameter: %15.12e\n",h);
332: #endif
333: if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
334: ctx->historyh[ctx->ncurrenth] = h;
335: }
336: ctx->ncurrenth++;
338: /* w = u + ha */
339: VecWAXPY(w,h,a,U);
341: /* compute func(U) as base for differencing; only needed first time in and not when provided by user */
342: if (ctx->ncurrenth == 1 && ctx->current_f_allocated) {
343: (*ctx->func)(ctx->funcctx,U,F);
344: }
345: (*ctx->func)(ctx->funcctx,w,y);
347: VecAXPY(y,-1.0,F);
348: VecScale(y,1.0/h);
350: VecAXPBY(y,ctx->vshift,ctx->vscale,a);
352: if (ctx->sp) {MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);}
354: PetscLogEventEnd(MATMFFD_Mult,a,y,0,0);
355: return(0);
356: }
360: /*
361: MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix
363: y ~= (F(u + ha) - F(u))/h,
364: where F = nonlinear function, as set by SNESSetFunction()
365: u = current iterate
366: h = difference interval
367: */
368: PetscErrorCode MatGetDiagonal_MFFD(Mat mat,Vec a)
369: {
370: MatMFFD ctx = (MatMFFD)mat->data;
371: PetscScalar h,*aa,*ww,v;
372: PetscReal epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
373: Vec w,U;
375: PetscInt i,rstart,rend;
378: if (!ctx->funci) {
379: SETERRQ(PETSC_ERR_ORDER,"Requires calling MatMFFDSetFunctioni() first");
380: }
382: w = ctx->w;
383: U = ctx->current_u;
384: (*ctx->func)(ctx->funcctx,U,a);
385: (*ctx->funcisetbase)(ctx->funcctx,U);
386: VecCopy(U,w);
388: VecGetOwnershipRange(a,&rstart,&rend);
389: VecGetArray(a,&aa);
390: for (i=rstart; i<rend; i++) {
391: VecGetArray(w,&ww);
392: h = ww[i-rstart];
393: if (h == 0.0) h = 1.0;
394: #if !defined(PETSC_USE_COMPLEX)
395: if (h < umin && h >= 0.0) h = umin;
396: else if (h < 0.0 && h > -umin) h = -umin;
397: #else
398: if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0) h = umin;
399: else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
400: #endif
401: h *= epsilon;
402:
403: ww[i-rstart] += h;
404: VecRestoreArray(w,&ww);
405: (*ctx->funci)(ctx->funcctx,i,w,&v);
406: aa[i-rstart] = (v - aa[i-rstart])/h;
408: /* possibly shift and scale result */
409: aa[i - rstart] = ctx->vshift + ctx->vscale*aa[i-rstart];
411: VecGetArray(w,&ww);
412: ww[i-rstart] -= h;
413: VecRestoreArray(w,&ww);
414: }
415: VecRestoreArray(a,&aa);
416: return(0);
417: }
421: PetscErrorCode MatShift_MFFD(Mat Y,PetscScalar a)
422: {
423: MatMFFD shell = (MatMFFD)Y->data;
425: shell->vshift += a;
426: return(0);
427: }
431: PetscErrorCode MatScale_MFFD(Mat Y,PetscScalar a)
432: {
433: MatMFFD shell = (MatMFFD)Y->data;
435: shell->vscale *= a;
436: return(0);
437: }
442: PetscErrorCode MatMFFDSetBase_MFFD(Mat J,Vec U,Vec F)
443: {
445: MatMFFD ctx = (MatMFFD)J->data;
448: MatMFFDResetHHistory(J);
449: ctx->current_u = U;
450: if (F) {
451: if (ctx->current_f_allocated) {VecDestroy(ctx->current_f);}
452: ctx->current_f = F;
453: ctx->current_f_allocated = PETSC_FALSE;
454: } else if (!ctx->current_f_allocated) {
455: VecDuplicate(ctx->current_u, &ctx->current_f);
456: ctx->current_f_allocated = PETSC_TRUE;
457: }
458: if (!ctx->w) {
459: VecDuplicate(ctx->current_u, &ctx->w);
460: }
461: J->assembled = PETSC_TRUE;
462: return(0);
463: }
469: PetscErrorCode MatMFFDSetCheckh_MFFD(Mat J,FCN3 fun,void*ectx)
470: {
471: MatMFFD ctx = (MatMFFD)J->data;
474: ctx->checkh = fun;
475: ctx->checkhctx = ectx;
476: return(0);
477: }
482: /*@C
483: MatMFFDSetOptionsPrefix - Sets the prefix used for searching for all
484: MatMFFD options in the database.
486: Collective on Mat
488: Input Parameter:
489: + A - the Mat context
490: - prefix - the prefix to prepend to all option names
492: Notes:
493: A hyphen (-) must NOT be given at the beginning of the prefix name.
494: The first character of all runtime options is AUTOMATICALLY the hyphen.
496: Level: advanced
498: .keywords: SNES, matrix-free, parameters
500: .seealso: MatMFFDSetFromOptions(), MatCreateSNESMF()
501: @*/
502: PetscErrorCode MatMFFDSetOptionsPrefix(Mat mat,const char prefix[])
504: {
505: MatMFFD mfctx = mat ? (MatMFFD)mat->data : PETSC_NULL;
510: PetscObjectSetOptionsPrefix((PetscObject)mfctx,prefix);
511: return(0);
512: }
516: /*@
517: MatMFFDSetFromOptions - Sets the MatMFFD options from the command line
518: parameter.
520: Collective on Mat
522: Input Parameters:
523: . mat - the matrix obtained with MatCreateMFFD() or MatCreateSNESMF()
525: Options Database Keys:
526: + -mat_mffd_type - wp or ds (see MATMFFD_WP or MATMFFD_DS)
527: - -mat_mffd_err - square root of estimated relative error in function evaluation
528: - -mat_mffd_period - how often h is recomputed, defaults to 1, everytime
530: Level: advanced
532: .keywords: SNES, matrix-free, parameters
534: .seealso: MatCreateSNESMF(),MatMFFDSetHHistory(),
535: MatMFFDResetHHistory(), MatMFFDKSPMonitor()
536: @*/
537: PetscErrorCode MatMFFDSetFromOptions(Mat mat)
538: {
539: MatMFFD mfctx = mat ? (MatMFFD)mat->data : PETSC_NULL;
541: PetscTruth flg;
542: char ftype[256];
547: PetscOptionsBegin(((PetscObject)mfctx)->comm,((PetscObject)mfctx)->prefix,"Set matrix free computation parameters","MatMFFD");
548: PetscOptionsList("-mat_mffd_type","Matrix free type","MatMFFDSetType",MatMFFDList,((PetscObject)mfctx)->type_name,ftype,256,&flg);
549: if (flg) {
550: MatMFFDSetType(mat,ftype);
551: }
553: PetscOptionsReal("-mat_mffd_err","set sqrt relative error in function","MatMFFDSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);
554: PetscOptionsInt("-mat_mffd_period","how often h is recomputed","MatMFFDSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);
556: flg = PETSC_FALSE;
557: PetscOptionsTruth("-mat_mffd_check_positivity","Insure that U + h*a is nonnegative","MatMFFDSetCheckh",flg,&flg,PETSC_NULL);
558: if (flg) {
559: MatMFFDSetCheckh(mat,MatMFFDCheckPositivity,0);
560: }
561: if (mfctx->ops->setfromoptions) {
562: (*mfctx->ops->setfromoptions)(mfctx);
563: }
564: PetscOptionsEnd();
565: return(0);
566: }
568: /*MC
569: MATMFFD - MATMFFD = "mffd" - A matrix free matrix type.
571: Level: advanced
573: .seealso: MatCreateMFFD(), MatCreateSNESMF(), MatMFFDSetFunction()
574: M*/
578: PetscErrorCode MatCreate_MFFD(Mat A)
579: {
580: MatMFFD mfctx;
581: PetscErrorCode ierr;
584: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
585: MatMFFDInitializePackage(PETSC_NULL);
586: #endif
588: PetscHeaderCreate(mfctx,_p_MatMFFD,struct _MFOps,MATMFFD_COOKIE,0,"MatMFFD",((PetscObject)A)->comm,MatDestroy_MFFD,MatView_MFFD);
589: mfctx->sp = 0;
590: mfctx->error_rel = PETSC_SQRT_MACHINE_EPSILON;
591: mfctx->recomputeperiod = 1;
592: mfctx->count = 0;
593: mfctx->currenth = 0.0;
594: mfctx->historyh = PETSC_NULL;
595: mfctx->ncurrenth = 0;
596: mfctx->maxcurrenth = 0;
597: ((PetscObject)mfctx)->type_name = 0;
599: mfctx->vshift = 0.0;
600: mfctx->vscale = 1.0;
602: /*
603: Create the empty data structure to contain compute-h routines.
604: These will be filled in below from the command line options or
605: a later call with MatMFFDSetType() or if that is not called
606: then it will default in the first use of MatMult_MFFD()
607: */
608: mfctx->ops->compute = 0;
609: mfctx->ops->destroy = 0;
610: mfctx->ops->view = 0;
611: mfctx->ops->setfromoptions = 0;
612: mfctx->hctx = 0;
614: mfctx->func = 0;
615: mfctx->funcctx = 0;
616: mfctx->w = PETSC_NULL;
618: A->data = mfctx;
620: A->ops->mult = MatMult_MFFD;
621: A->ops->destroy = MatDestroy_MFFD;
622: A->ops->view = MatView_MFFD;
623: A->ops->assemblyend = MatAssemblyEnd_MFFD;
624: A->ops->getdiagonal = MatGetDiagonal_MFFD;
625: A->ops->scale = MatScale_MFFD;
626: A->ops->shift = MatShift_MFFD;
627: A->ops->setfromoptions = MatMFFDSetFromOptions;
628: A->assembled = PETSC_TRUE;
630: PetscLayoutSetBlockSize(A->rmap,1);
631: PetscLayoutSetBlockSize(A->cmap,1);
632: PetscLayoutSetUp(A->rmap);
633: PetscLayoutSetUp(A->cmap);
635: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetBase_C","MatMFFDSetBase_MFFD",MatMFFDSetBase_MFFD);
636: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetFunctioniBase_C","MatMFFDSetFunctioniBase_MFFD",MatMFFDSetFunctioniBase_MFFD);
637: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetFunctioni_C","MatMFFDSetFunctioni_MFFD",MatMFFDSetFunctioni_MFFD);
638: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetCheckh_C","MatMFFDSetCheckh_MFFD",MatMFFDSetCheckh_MFFD);
639: mfctx->mat = A;
640: PetscObjectChangeTypeName((PetscObject)A,MATMFFD);
641: return(0);
642: }
647: /*@
648: MatCreateMFFD - Creates a matrix-free matrix. See also MatCreateSNESMF()
650: Collective on Vec
652: Input Parameters:
653: + comm - MPI communicator
654: . m - number of local rows (or PETSC_DECIDE to have calculated if M is given)
655: This value should be the same as the local size used in creating the
656: y vector for the matrix-vector product y = Ax.
657: . n - This value should be the same as the local size used in creating the
658: x vector for the matrix-vector product y = Ax. (or PETSC_DECIDE to have
659: calculated if N is given) For square matrices n is almost always m.
660: . M - number of global rows (or PETSC_DETERMINE to have calculated if m is given)
661: - N - number of global columns (or PETSC_DETERMINE to have calculated if n is given)
664: Output Parameter:
665: . J - the matrix-free matrix
667: Level: advanced
669: Notes:
670: The matrix-free matrix context merely contains the function pointers
671: and work space for performing finite difference approximations of
672: Jacobian-vector products, F'(u)*a,
674: The default code uses the following approach to compute h
676: .vb
677: F'(u)*a = [F(u+h*a) - F(u)]/h where
678: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
679: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise
680: where
681: error_rel = square root of relative error in function evaluation
682: umin = minimum iterate parameter
683: .ve
685: The user can set the error_rel via MatMFFDSetFunctionError() and
686: umin via MatMFFDDefaultSetUmin(); see the nonlinear solvers chapter
687: of the users manual for details.
689: The user should call MatDestroy() when finished with the matrix-free
690: matrix context.
692: Options Database Keys:
693: + -mat_mffd_err <error_rel> - Sets error_rel
694: . -mat_mffd_unim <umin> - Sets umin (for default PETSc routine that computes h only)
695: . -mat_mffd_ksp_monitor - KSP monitor routine that prints differencing h
696: - -mat_mffd_check_positivity
698: .keywords: default, matrix-free, create, matrix
700: .seealso: MatDestroy(), MatMFFDSetFunctionError(), MatMFFDDefaultSetUmin(), MatMFFDSetFunction()
701: MatMFFDSetHHistory(), MatMFFDResetHHistory(), MatCreateSNESMF(),
702: MatMFFDGetH(),MatMFFDKSPMonitor(), MatMFFDRegisterDynamic),, MatMFFDComputeJacobian()
703:
704: @*/
705: PetscErrorCode MatCreateMFFD(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,Mat *J)
706: {
710: MatCreate(comm,J);
711: MatSetSizes(*J,m,n,M,N);
712: MatSetType(*J,MATMFFD);
713: return(0);
714: }
719: /*@
720: MatMFFDGetH - Gets the last value that was used as the differencing
721: parameter.
723: Not Collective
725: Input Parameters:
726: . mat - the matrix obtained with MatCreateSNESMF()
728: Output Paramter:
729: . h - the differencing step size
731: Level: advanced
733: .keywords: SNES, matrix-free, parameters
735: .seealso: MatCreateSNESMF(),MatMFFDSetHHistory(), MatCreateMFFD(), MATMFFD
736: MatMFFDResetHHistory(),MatMFFDKSPMonitor()
737: @*/
738: PetscErrorCode MatMFFDGetH(Mat mat,PetscScalar *h)
739: {
740: MatMFFD ctx = (MatMFFD)mat->data;
743: *h = ctx->currenth;
744: return(0);
745: }
750: /*@C
751: MatMFFDSetFunction - Sets the function used in applying the matrix free.
753: Collective on Mat
755: Input Parameters:
756: + mat - the matrix free matrix created via MatCreateSNESMF()
757: . func - the function to use
758: - funcctx - optional function context passed to function
760: Level: advanced
762: Notes:
763: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
764: matrix inside your compute Jacobian routine
766: If this is not set then it will use the function set with SNESSetFunction() if MatCreateSNESMF() was used.
768: .keywords: SNES, matrix-free, function
770: .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD
771: MatMFFDSetHHistory(), MatMFFDResetHHistory(),
772: MatMFFDKSPMonitor(), SNESetFunction()
773: @*/
774: PetscErrorCode MatMFFDSetFunction(Mat mat,PetscErrorCode (*func)(void*,Vec,Vec),void *funcctx)
775: {
776: MatMFFD ctx = (MatMFFD)mat->data;
779: ctx->func = func;
780: ctx->funcctx = funcctx;
781: return(0);
782: }
786: /*@C
787: MatMFFDSetFunctioni - Sets the function for a single component
789: Collective on Mat
791: Input Parameters:
792: + mat - the matrix free matrix created via MatCreateSNESMF()
793: - funci - the function to use
795: Level: advanced
797: Notes:
798: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
799: matrix inside your compute Jacobian routine
802: .keywords: SNES, matrix-free, function
804: .seealso: MatCreateSNESMF(),MatMFFDGetH(),
805: MatMFFDSetHHistory(), MatMFFDResetHHistory(),
806: MatMFFDKSPMonitor(), SNESetFunction()
807: @*/
808: PetscErrorCode MatMFFDSetFunctioni(Mat mat,PetscErrorCode (*funci)(void*,PetscInt,Vec,PetscScalar*))
809: {
810: PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(void*,PetscInt,Vec,PetscScalar*));
814: PetscObjectQueryFunction((PetscObject)mat,"MatMFFDSetFunctioni_C",(void (**)(void))&f);
815: if (f) {
816: (*f)(mat,funci);
817: }
818: return(0);
819: }
824: /*@C
825: MatMFFDSetFunctioniBase - Sets the base vector for a single component function evaluation
827: Collective on Mat
829: Input Parameters:
830: + mat - the matrix free matrix created via MatCreateSNESMF()
831: - func - the function to use
833: Level: advanced
835: Notes:
836: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
837: matrix inside your compute Jacobian routine
840: .keywords: SNES, matrix-free, function
842: .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD
843: MatMFFDSetHHistory(), MatMFFDResetHHistory(),
844: MatMFFDKSPMonitor(), SNESetFunction()
845: @*/
846: PetscErrorCode MatMFFDSetFunctioniBase(Mat mat,PetscErrorCode (*func)(void*,Vec))
847: {
848: PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(void*,Vec));
852: PetscObjectQueryFunction((PetscObject)mat,"MatMFFDSetFunctioniBase_C",(void (**)(void))&f);
853: if (f) {
854: (*f)(mat,func);
855: }
856: return(0);
857: }
862: /*@
863: MatMFFDSetPeriod - Sets how often h is recomputed, by default it is everytime
865: Collective on Mat
867: Input Parameters:
868: + mat - the matrix free matrix created via MatCreateSNESMF()
869: - period - 1 for everytime, 2 for every second etc
871: Options Database Keys:
872: + -mat_mffd_period <period>
874: Level: advanced
877: .keywords: SNES, matrix-free, parameters
879: .seealso: MatCreateSNESMF(),MatMFFDGetH(),
880: MatMFFDSetHHistory(), MatMFFDResetHHistory(),
881: MatMFFDKSPMonitor()
882: @*/
883: PetscErrorCode MatMFFDSetPeriod(Mat mat,PetscInt period)
884: {
885: MatMFFD ctx = (MatMFFD)mat->data;
888: ctx->recomputeperiod = period;
889: return(0);
890: }
894: /*@
895: MatMFFDSetFunctionError - Sets the error_rel for the approximation of
896: matrix-vector products using finite differences.
898: Collective on Mat
900: Input Parameters:
901: + mat - the matrix free matrix created via MatCreateMFFD() or MatCreateSNESMF()
902: - error_rel - relative error (should be set to the square root of
903: the relative error in the function evaluations)
905: Options Database Keys:
906: + -mat_mffd_err <error_rel> - Sets error_rel
908: Level: advanced
910: Notes:
911: The default matrix-free matrix-vector product routine computes
912: .vb
913: F'(u)*a = [F(u+h*a) - F(u)]/h where
914: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
915: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else
916: .ve
918: .keywords: SNES, matrix-free, parameters
920: .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD
921: MatMFFDSetHHistory(), MatMFFDResetHHistory(),
922: MatMFFDKSPMonitor()
923: @*/
924: PetscErrorCode MatMFFDSetFunctionError(Mat mat,PetscReal error)
925: {
926: MatMFFD ctx = (MatMFFD)mat->data;
929: if (error != PETSC_DEFAULT) ctx->error_rel = error;
930: return(0);
931: }
935: /*@
936: MatMFFDAddNullSpace - Provides a null space that an operator is
937: supposed to have. Since roundoff will create a small component in
938: the null space, if you know the null space you may have it
939: automatically removed.
941: Collective on Mat
943: Input Parameters:
944: + J - the matrix-free matrix context
945: - nullsp - object created with MatNullSpaceCreate()
947: Level: advanced
949: .keywords: SNES, matrix-free, null space
951: .seealso: MatNullSpaceCreate(), MatMFFDGetH(), MatCreateSNESMF(), MatCreateMFFD(), MATMFFD
952: MatMFFDSetHHistory(), MatMFFDResetHHistory(),
953: MatMFFDKSPMonitor(), MatMFFDErrorRel()
954: @*/
955: PetscErrorCode MatMFFDAddNullSpace(Mat J,MatNullSpace nullsp)
956: {
958: MatMFFD ctx = (MatMFFD)J->data;
961: PetscObjectReference((PetscObject)nullsp);
962: if (ctx->sp) { MatNullSpaceDestroy(ctx->sp); }
963: ctx->sp = nullsp;
964: return(0);
965: }
969: /*@
970: MatMFFDSetHHistory - Sets an array to collect a history of the
971: differencing values (h) computed for the matrix-free product.
973: Collective on Mat
975: Input Parameters:
976: + J - the matrix-free matrix context
977: . histroy - space to hold the history
978: - nhistory - number of entries in history, if more entries are generated than
979: nhistory, then the later ones are discarded
981: Level: advanced
983: Notes:
984: Use MatMFFDResetHHistory() to reset the history counter and collect
985: a new batch of differencing parameters, h.
987: .keywords: SNES, matrix-free, h history, differencing history
989: .seealso: MatMFFDGetH(), MatCreateSNESMF(),
990: MatMFFDResetHHistory(),
991: MatMFFDKSPMonitor(), MatMFFDSetFunctionError()
993: @*/
994: PetscErrorCode MatMFFDSetHHistory(Mat J,PetscScalar history[],PetscInt nhistory)
995: {
996: MatMFFD ctx = (MatMFFD)J->data;
999: ctx->historyh = history;
1000: ctx->maxcurrenth = nhistory;
1001: ctx->currenth = 0.;
1002: return(0);
1003: }
1007: /*@
1008: MatMFFDResetHHistory - Resets the counter to zero to begin
1009: collecting a new set of differencing histories.
1011: Collective on Mat
1013: Input Parameters:
1014: . J - the matrix-free matrix context
1016: Level: advanced
1018: Notes:
1019: Use MatMFFDSetHHistory() to create the original history counter.
1021: .keywords: SNES, matrix-free, h history, differencing history
1023: .seealso: MatMFFDGetH(), MatCreateSNESMF(),
1024: MatMFFDSetHHistory(),
1025: MatMFFDKSPMonitor(), MatMFFDSetFunctionError()
1027: @*/
1028: PetscErrorCode MatMFFDResetHHistory(Mat J)
1029: {
1030: MatMFFD ctx = (MatMFFD)J->data;
1033: ctx->ncurrenth = 0;
1034: return(0);
1035: }
1040: /*@
1041: MatMFFDSetBase - Sets the vector U at which matrix vector products of the
1042: Jacobian are computed
1044: Collective on Mat
1046: Input Parameters:
1047: + J - the MatMFFD matrix
1048: . U - the vector
1049: - F - (optional) vector that contains F(u) if it has been already computed
1051: Notes: This is rarely used directly
1053: If F is provided then it is not recomputed. Otherwise the function is evaluated at the base
1054: point during the first MatMult() after each call to MatMFFDSetBase().
1056: Level: advanced
1058: @*/
1059: PetscErrorCode MatMFFDSetBase(Mat J,Vec U,Vec F)
1060: {
1061: PetscErrorCode ierr,(*f)(Mat,Vec,Vec);
1067: PetscObjectQueryFunction((PetscObject)J,"MatMFFDSetBase_C",(void (**)(void))&f);
1068: if (f) {
1069: (*f)(J,U,F);
1070: }
1071: return(0);
1072: }
1076: /*@C
1077: MatMFFDSetCheckh - Sets a function that checks the computed h and adjusts
1078: it to satisfy some criteria
1080: Collective on Mat
1082: Input Parameters:
1083: + J - the MatMFFD matrix
1084: . fun - the function that checks h
1085: - ctx - any context needed by the function
1087: Options Database Keys:
1088: . -mat_mffd_check_positivity
1090: Level: advanced
1092: Notes: For example, MatMFFDSetCheckPositivity() insures that all entries
1093: of U + h*a are non-negative
1095: .seealso: MatMFFDSetCheckPositivity()
1096: @*/
1097: PetscErrorCode MatMFFDSetCheckh(Mat J,PetscErrorCode (*fun)(void*,Vec,Vec,PetscScalar*),void* ctx)
1098: {
1099: PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(void*,Vec,Vec,PetscScalar*),void*);
1103: PetscObjectQueryFunction((PetscObject)J,"MatMFFDSetCheckh_C",(void (**)(void))&f);
1104: if (f) {
1105: (*f)(J,fun,ctx);
1106: }
1107: return(0);
1108: }
1112: /*@
1113: MatMFFDCheckPositivity - Checks that all entries in U + h*a are positive or
1114: zero, decreases h until this is satisfied.
1116: Collective on Vec
1118: Input Parameters:
1119: + U - base vector that is added to
1120: . a - vector that is added
1121: . h - scaling factor on a
1122: - dummy - context variable (unused)
1124: Options Database Keys:
1125: . -mat_mffd_check_positivity
1127: Level: advanced
1129: Notes: This is rarely used directly, rather it is passed as an argument to
1130: MatMFFDSetCheckh()
1132: .seealso: MatMFFDSetCheckh()
1133: @*/
1134: PetscErrorCode MatMFFDCheckPositivity(void* dummy,Vec U,Vec a,PetscScalar *h)
1135: {
1136: PetscReal val, minval;
1137: PetscScalar *u_vec, *a_vec;
1139: PetscInt i,n;
1140: MPI_Comm comm;
1143: PetscObjectGetComm((PetscObject)U,&comm);
1144: VecGetArray(U,&u_vec);
1145: VecGetArray(a,&a_vec);
1146: VecGetLocalSize(U,&n);
1147: minval = PetscAbsScalar(*h*1.01);
1148: for(i=0;i<n;i++) {
1149: if (PetscRealPart(u_vec[i] + *h*a_vec[i]) <= 0.0) {
1150: val = PetscAbsScalar(u_vec[i]/a_vec[i]);
1151: if (val < minval) minval = val;
1152: }
1153: }
1154: VecRestoreArray(U,&u_vec);
1155: VecRestoreArray(a,&a_vec);
1156: PetscGlobalMin(&minval,&val,comm);
1157: if (val <= PetscAbsScalar(*h)) {
1158: PetscInfo2(U,"Scaling back h from %G to %G\n",PetscRealPart(*h),.99*val);
1159: if (PetscRealPart(*h) > 0.0) *h = 0.99*val;
1160: else *h = -0.99*val;
1161: }
1162: return(0);
1163: }