Actual source code: mffd.c
1: #define PETSCMAT_DLL
3: #include private/matimpl.h
4: #include ../src/mat/impls/mffd/mffdimpl.h
6: PetscFList MatMFFDPetscFList = 0;
7: PetscTruth MatMFFDRegisterAllCalled = PETSC_FALSE;
9: PetscCookie MATMFFD_COOKIE;
10: PetscLogEvent MATMFFD_Mult;
14: /*@C
15: MatMFFDInitializePackage - This function initializes everything in the MatMFFD package. It is called
16: from PetscDLLibraryRegister() when using dynamic libraries, and on the first call to MatCreate_MFFD()
17: when using static libraries.
19: Input Parameter:
20: . path - The dynamic library path, or PETSC_NULL
22: Level: developer
24: .keywords: Vec, initialize, package
25: .seealso: PetscInitialize()
26: @*/
27: PetscErrorCode MatMFFDInitializePackage(const char path[])
28: {
29: static PetscTruth initialized = PETSC_FALSE;
30: char logList[256];
31: char *className;
32: PetscTruth opt;
33: PetscErrorCode ierr;
36: if (initialized) return(0);
37: initialized = PETSC_TRUE;
38: /* Register Classes */
39: PetscCookieRegister("MatMFFD",&MATMFFD_COOKIE);
40: /* Register Constructors */
41: MatMFFDRegisterAll(path);
42: /* Register Events */
43: PetscLogEventRegister("MatMult MF", MATMFFD_COOKIE,&MATMFFD_Mult);
45: /* Process info exclusions */
46: PetscOptionsGetString(PETSC_NULL, "-info_exclude", logList, 256, &opt);
47: if (opt) {
48: PetscStrstr(logList, "matmffd", &className);
49: if (className) {
50: PetscInfoDeactivateClass(MATMFFD_COOKIE);
51: }
52: }
53: /* Process summary exclusions */
54: PetscOptionsGetString(PETSC_NULL, "-log_summary_exclude", logList, 256, &opt);
55: if (opt) {
56: PetscStrstr(logList, "matmffd", &className);
57: if (className) {
58: PetscLogEventDeactivateClass(MATMFFD_COOKIE);
59: }
60: }
61: return(0);
62: }
66: /*@C
67: MatMFFDSetType - Sets the method that is used to compute the
68: differencing parameter for finite differene matrix-free formulations.
70: Input Parameters:
71: + mat - the "matrix-free" matrix created via MatCreateSNESMF(), or MatCreateMFFD()
72: or MatSetType(mat,MATMFFD);
73: - ftype - the type requested, either MATMFFD_WP or MATMFFD_DS
75: Level: advanced
77: Notes:
78: For example, such routines can compute h for use in
79: Jacobian-vector products of the form
81: F(x+ha) - F(x)
82: F'(u)a ~= ----------------
83: h
85: .seealso: MatCreateSNESMF(), MatMFFDRegisterDynamic)
86: @*/
87: PetscErrorCode MatMFFDSetType(Mat mat,const MatMFFDType ftype)
88: {
89: PetscErrorCode ierr,(*r)(MatMFFD);
90: MatMFFD ctx = (MatMFFD)mat->data;
91: PetscTruth match;
92:
97: /* already set, so just return */
98: PetscTypeCompare((PetscObject)ctx,ftype,&match);
99: if (match) return(0);
101: /* destroy the old one if it exists */
102: if (ctx->ops->destroy) {
103: (*ctx->ops->destroy)(ctx);
104: }
106: PetscFListFind(MatMFFDPetscFList,((PetscObject)ctx)->comm,ftype,(void (**)(void)) &r);
107: if (!r) SETERRQ1(PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown MatMFFD type %s given",ftype);
108: (*r)(ctx);
109: PetscObjectChangeTypeName((PetscObject)ctx,ftype);
110: return(0);
111: }
117: PetscErrorCode MatMFFDSetFunctioniBase_MFFD(Mat mat,FCN1 func)
118: {
119: MatMFFD ctx = (MatMFFD)mat->data;
122: ctx->funcisetbase = func;
123: return(0);
124: }
131: PetscErrorCode MatMFFDSetFunctioni_MFFD(Mat mat,FCN2 funci)
132: {
133: MatMFFD ctx = (MatMFFD)mat->data;
136: ctx->funci = funci;
137: return(0);
138: }
144: PetscErrorCode MatMFFDRegister(const char sname[],const char path[],const char name[],PetscErrorCode (*function)(MatMFFD))
145: {
147: char fullname[PETSC_MAX_PATH_LEN];
150: PetscFListConcat(path,name,fullname);
151: PetscFListAdd(&MatMFFDPetscFList,sname,fullname,(void (*)(void))function);
152: return(0);
153: }
158: /*@C
159: MatMFFDRegisterDestroy - Frees the list of MatMFFD methods that were
160: registered by MatMFFDRegisterDynamic).
162: Not Collective
164: Level: developer
166: .keywords: MatMFFD, register, destroy
168: .seealso: MatMFFDRegisterDynamic), MatMFFDRegisterAll()
169: @*/
170: PetscErrorCode MatMFFDRegisterDestroy(void)
171: {
175: PetscFListDestroy(&MatMFFDPetscFList);
176: MatMFFDRegisterAllCalled = PETSC_FALSE;
177: return(0);
178: }
180: /* ----------------------------------------------------------------------------------------*/
183: PetscErrorCode MatDestroy_MFFD(Mat mat)
184: {
186: MatMFFD ctx = (MatMFFD)mat->data;
189: if (ctx->w) {
190: VecDestroy(ctx->w);
191: }
192: if (ctx->current_f_allocated) {
193: VecDestroy(ctx->current_f);
194: }
195: if (ctx->ops->destroy) {(*ctx->ops->destroy)(ctx);}
196: if (ctx->sp) {MatNullSpaceDestroy(ctx->sp);}
197: PetscHeaderDestroy(ctx);
199: PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetBase_C","",PETSC_NULL);
200: PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctioniBase_C","",PETSC_NULL);
201: PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctioni_C","",PETSC_NULL);
202: PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetCheckh_C","",PETSC_NULL);
204: return(0);
205: }
209: /*
210: MatMFFDView_MFFD - Views matrix-free parameters.
212: */
213: PetscErrorCode MatView_MFFD(Mat J,PetscViewer viewer)
214: {
216: MatMFFD ctx = (MatMFFD)J->data;
217: PetscTruth iascii;
220: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
221: if (iascii) {
222: PetscViewerASCIIPrintf(viewer," matrix-free approximation:\n");
223: PetscViewerASCIIPrintf(viewer," err=%G (relative error in function evaluation)\n",ctx->error_rel);
224: if (!((PetscObject)ctx)->type_name) {
225: PetscViewerASCIIPrintf(viewer," The compute h routine has not yet been set\n");
226: } else {
227: PetscViewerASCIIPrintf(viewer," Using %s compute h routine\n",((PetscObject)ctx)->type_name);
228: }
229: if (ctx->ops->view) {
230: (*ctx->ops->view)(ctx,viewer);
231: }
232: } else {
233: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for matrix-free matrix",((PetscObject)viewer)->type_name);
234: }
235: return(0);
236: }
240: /*
241: MatAssemblyEnd_MFFD - Resets the ctx->ncurrenth to zero. This
242: allows the user to indicate the beginning of a new linear solve by calling
243: MatAssemblyXXX() on the matrix free matrix. This then allows the
244: MatMFFDCreate_WP() to properly compute ||U|| only the first time
245: in the linear solver rather than every time.
246: */
247: PetscErrorCode MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt)
248: {
250: MatMFFD j = (MatMFFD)J->data;
253: MatMFFDResetHHistory(J);
254: j->vshift = 0.0;
255: j->vscale = 1.0;
256: return(0);
257: }
261: /*
262: MatMult_MFFD - Default matrix-free form for Jacobian-vector product, y = F'(u)*a:
264: y ~= (F(u + ha) - F(u))/h,
265: where F = nonlinear function, as set by SNESSetFunction()
266: u = current iterate
267: h = difference interval
268: */
269: PetscErrorCode MatMult_MFFD(Mat mat,Vec a,Vec y)
270: {
271: MatMFFD ctx = (MatMFFD)mat->data;
272: PetscScalar h;
273: Vec w,U,F;
275: PetscTruth zeroa;
278: /* We log matrix-free matrix-vector products separately, so that we can
279: separate the performance monitoring from the cases that use conventional
280: storage. We may eventually modify event logging to associate events
281: with particular objects, hence alleviating the more general problem. */
282: PetscLogEventBegin(MATMFFD_Mult,a,y,0,0);
284: w = ctx->w;
285: U = ctx->current_u;
286: F = ctx->current_f;
287: /*
288: Compute differencing parameter
289: */
290: if (!ctx->ops->compute) {
291: MatMFFDSetType(mat,MATMFFD_WP);
292: MatMFFDSetFromOptions(mat);
293: }
294: (*ctx->ops->compute)(ctx,U,a,&h,&zeroa);
295: if (zeroa) {
296: VecSet(y,0.0);
297: return(0);
298: }
300: if (h != h) SETERRQ(PETSC_ERR_PLIB,"Computed Nan differencing parameter h");
301: if (ctx->checkh) {
302: (*ctx->checkh)(ctx->checkhctx,U,a,&h);
303: }
305: /* keep a record of the current differencing parameter h */
306: ctx->currenth = h;
307: #if defined(PETSC_USE_COMPLEX)
308: PetscInfo2(mat,"Current differencing parameter: %G + %G i\n",PetscRealPart(h),PetscImaginaryPart(h));
309: #else
310: PetscInfo1(mat,"Current differencing parameter: %15.12e\n",h);
311: #endif
312: if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
313: ctx->historyh[ctx->ncurrenth] = h;
314: }
315: ctx->ncurrenth++;
317: /* w = u + ha */
318: VecWAXPY(w,h,a,U);
320: /* compute func(U) as base for differencing; only needed first time in and not when provided by user */
321: if (ctx->ncurrenth == 1 && ctx->current_f_allocated) {
322: (*ctx->func)(ctx->funcctx,U,F);
323: }
324: (*ctx->func)(ctx->funcctx,w,y);
326: VecAXPY(y,-1.0,F);
327: VecScale(y,1.0/h);
329: VecAXPBY(y,ctx->vshift,ctx->vscale,a);
331: if (ctx->sp) {MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);}
333: PetscLogEventEnd(MATMFFD_Mult,a,y,0,0);
334: return(0);
335: }
339: /*
340: MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix
342: y ~= (F(u + ha) - F(u))/h,
343: where F = nonlinear function, as set by SNESSetFunction()
344: u = current iterate
345: h = difference interval
346: */
347: PetscErrorCode MatGetDiagonal_MFFD(Mat mat,Vec a)
348: {
349: MatMFFD ctx = (MatMFFD)mat->data;
350: PetscScalar h,*aa,*ww,v;
351: PetscReal epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
352: Vec w,U;
354: PetscInt i,rstart,rend;
357: if (!ctx->funci) {
358: SETERRQ(PETSC_ERR_ORDER,"Requires calling MatMFFDSetFunctioni() first");
359: }
361: w = ctx->w;
362: U = ctx->current_u;
363: (*ctx->func)(ctx->funcctx,U,a);
364: (*ctx->funcisetbase)(ctx->funcctx,U);
365: VecCopy(U,w);
367: VecGetOwnershipRange(a,&rstart,&rend);
368: VecGetArray(a,&aa);
369: for (i=rstart; i<rend; i++) {
370: VecGetArray(w,&ww);
371: h = ww[i-rstart];
372: if (h == 0.0) h = 1.0;
373: #if !defined(PETSC_USE_COMPLEX)
374: if (h < umin && h >= 0.0) h = umin;
375: else if (h < 0.0 && h > -umin) h = -umin;
376: #else
377: if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0) h = umin;
378: else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
379: #endif
380: h *= epsilon;
381:
382: ww[i-rstart] += h;
383: VecRestoreArray(w,&ww);
384: (*ctx->funci)(ctx->funcctx,i,w,&v);
385: aa[i-rstart] = (v - aa[i-rstart])/h;
387: /* possibly shift and scale result */
388: aa[i - rstart] = ctx->vshift + ctx->vscale*aa[i-rstart];
390: VecGetArray(w,&ww);
391: ww[i-rstart] -= h;
392: VecRestoreArray(w,&ww);
393: }
394: VecRestoreArray(a,&aa);
395: return(0);
396: }
400: PetscErrorCode MatShift_MFFD(Mat Y,PetscScalar a)
401: {
402: MatMFFD shell = (MatMFFD)Y->data;
404: shell->vshift += a;
405: return(0);
406: }
410: PetscErrorCode MatScale_MFFD(Mat Y,PetscScalar a)
411: {
412: MatMFFD shell = (MatMFFD)Y->data;
414: shell->vscale *= a;
415: return(0);
416: }
421: PetscErrorCode MatMFFDSetBase_MFFD(Mat J,Vec U,Vec F)
422: {
424: MatMFFD ctx = (MatMFFD)J->data;
427: MatMFFDResetHHistory(J);
428: ctx->current_u = U;
429: if (F) {
430: if (ctx->current_f_allocated) {VecDestroy(ctx->current_f);}
431: ctx->current_f = F;
432: ctx->current_f_allocated = PETSC_FALSE;
433: } else if (!ctx->current_f_allocated) {
434: VecDuplicate(ctx->current_u, &ctx->current_f);
435: ctx->current_f_allocated = PETSC_TRUE;
436: }
437: if (!ctx->w) {
438: VecDuplicate(ctx->current_u, &ctx->w);
439: }
440: J->assembled = PETSC_TRUE;
441: return(0);
442: }
448: PetscErrorCode MatMFFDSetCheckh_MFFD(Mat J,FCN3 fun,void*ectx)
449: {
450: MatMFFD ctx = (MatMFFD)J->data;
453: ctx->checkh = fun;
454: ctx->checkhctx = ectx;
455: return(0);
456: }
461: /*@
462: MatMFFDSetFromOptions - Sets the MatMFFD options from the command line
463: parameter.
465: Collective on Mat
467: Input Parameters:
468: . mat - the matrix obtained with MatCreateMFFD() or MatCreateSNESMF()
470: Options Database Keys:
471: + -mat_mffd_type - wp or ds (see MATMFFD_WP or MATMFFD_DS)
472: - -mat_mffd_err - square root of estimated relative error in function evaluation
473: - -mat_mffd_period - how often h is recomputed, defaults to 1, everytime
475: Level: advanced
477: .keywords: SNES, matrix-free, parameters
479: .seealso: MatCreateSNESMF(),MatMFFDSetHHistory(),
480: MatMFFDResetHHistory(), MatMFFDKSPMonitor()
481: @*/
482: PetscErrorCode MatMFFDSetFromOptions(Mat mat)
483: {
484: MatMFFD mfctx = (MatMFFD)mat->data;
486: PetscTruth flg;
487: char ftype[256];
490: PetscOptionsBegin(((PetscObject)mfctx)->comm,((PetscObject)mfctx)->prefix,"Set matrix free computation parameters","MatMFFD");
491: PetscOptionsList("-mat_mffd_type","Matrix free type","MatMFFDSetType",MatMFFDPetscFList,((PetscObject)mfctx)->type_name,ftype,256,&flg);
492: if (flg) {
493: MatMFFDSetType(mat,ftype);
494: }
496: PetscOptionsReal("-mat_mffd_err","set sqrt relative error in function","MatMFFDSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);
497: PetscOptionsInt("-mat_mffd_period","how often h is recomputed","MatMFFDSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);
499: PetscOptionsName("-mat_mffd_check_positivity","Insure that U + h*a is nonnegative","MatMFFDSetCheckh",&flg);
500: if (flg) {
501: MatMFFDSetCheckh(mat,MatMFFDCheckPositivity,0);
502: }
503: if (mfctx->ops->setfromoptions) {
504: (*mfctx->ops->setfromoptions)(mfctx);
505: }
506: PetscOptionsEnd();
507: return(0);
508: }
510: /*MC
511: MATMFFD - MATMFFD = "mffd" - A matrix free matrix type.
513: Level: advanced
515: .seealso: MatCreateMFFD(), MatCreateSNESMF()
516: M*/
520: PetscErrorCode MatCreate_MFFD(Mat A)
521: {
522: MatMFFD mfctx;
523: PetscErrorCode ierr;
526: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
527: MatMFFDInitializePackage(PETSC_NULL);
528: #endif
530: PetscHeaderCreate(mfctx,_p_MatMFFD,struct _MFOps,MATMFFD_COOKIE,0,"MatMFFD",((PetscObject)A)->comm,MatDestroy_MFFD,MatView_MFFD);
531: mfctx->sp = 0;
532: mfctx->error_rel = PETSC_SQRT_MACHINE_EPSILON;
533: mfctx->recomputeperiod = 1;
534: mfctx->count = 0;
535: mfctx->currenth = 0.0;
536: mfctx->historyh = PETSC_NULL;
537: mfctx->ncurrenth = 0;
538: mfctx->maxcurrenth = 0;
539: ((PetscObject)mfctx)->type_name = 0;
541: mfctx->vshift = 0.0;
542: mfctx->vscale = 1.0;
544: /*
545: Create the empty data structure to contain compute-h routines.
546: These will be filled in below from the command line options or
547: a later call with MatMFFDSetType() or if that is not called
548: then it will default in the first use of MatMult_MFFD()
549: */
550: mfctx->ops->compute = 0;
551: mfctx->ops->destroy = 0;
552: mfctx->ops->view = 0;
553: mfctx->ops->setfromoptions = 0;
554: mfctx->hctx = 0;
556: mfctx->func = 0;
557: mfctx->funcctx = 0;
558: mfctx->w = PETSC_NULL;
560: A->data = mfctx;
562: A->ops->mult = MatMult_MFFD;
563: A->ops->destroy = MatDestroy_MFFD;
564: A->ops->view = MatView_MFFD;
565: A->ops->assemblyend = MatAssemblyEnd_MFFD;
566: A->ops->getdiagonal = MatGetDiagonal_MFFD;
567: A->ops->scale = MatScale_MFFD;
568: A->ops->shift = MatShift_MFFD;
569: A->ops->setfromoptions = MatMFFDSetFromOptions;
570: A->assembled = PETSC_TRUE;
572: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetBase_C","MatMFFDSetBase_MFFD",MatMFFDSetBase_MFFD);
573: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetFunctioniBase_C","MatMFFDSetFunctioniBase_MFFD",MatMFFDSetFunctioniBase_MFFD);
574: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetFunctioni_C","MatMFFDSetFunctioni_MFFD",MatMFFDSetFunctioni_MFFD);
575: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetCheckh_C","MatMFFDSetCheckh_MFFD",MatMFFDSetCheckh_MFFD);
576: mfctx->mat = A;
577: PetscObjectChangeTypeName((PetscObject)A,MATMFFD);
578: return(0);
579: }
584: /*@
585: MatCreateMFFD - Creates a matrix-free matrix. See also MatCreateSNESMF()
587: Collective on Vec
589: Input Parameters:
590: + comm - MPI communicator
591: . m - number of local rows (or PETSC_DECIDE to have calculated if M is given)
592: This value should be the same as the local size used in creating the
593: y vector for the matrix-vector product y = Ax.
594: . n - This value should be the same as the local size used in creating the
595: x vector for the matrix-vector product y = Ax. (or PETSC_DECIDE to have
596: calculated if N is given) For square matrices n is almost always m.
597: . M - number of global rows (or PETSC_DETERMINE to have calculated if m is given)
598: - N - number of global columns (or PETSC_DETERMINE to have calculated if n is given)
601: Output Parameter:
602: . J - the matrix-free matrix
604: Level: advanced
606: Notes:
607: The matrix-free matrix context merely contains the function pointers
608: and work space for performing finite difference approximations of
609: Jacobian-vector products, F'(u)*a,
611: The default code uses the following approach to compute h
613: .vb
614: F'(u)*a = [F(u+h*a) - F(u)]/h where
615: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
616: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise
617: where
618: error_rel = square root of relative error in function evaluation
619: umin = minimum iterate parameter
620: .ve
622: The user can set the error_rel via MatMFFDSetFunctionError() and
623: umin via MatMFFDDefaultSetUmin(); see the nonlinear solvers chapter
624: of the users manual for details.
626: The user should call MatDestroy() when finished with the matrix-free
627: matrix context.
629: Options Database Keys:
630: + -mat_mffd_err <error_rel> - Sets error_rel
631: . -mat_mffd_unim <umin> - Sets umin (for default PETSc routine that computes h only)
632: . -mat_mffd_ksp_monitor - KSP monitor routine that prints differencing h
633: - -mat_mffd_check_positivity
635: .keywords: default, matrix-free, create, matrix
637: .seealso: MatDestroy(), MatMFFDSetFunctionError(), MatMFFDDefaultSetUmin(), MatMFFDSetFunction()
638: MatMFFDSetHHistory(), MatMFFDResetHHistory(), MatCreateSNESMF(),
639: MatMFFDGetH(),MatMFFDKSPMonitor(), MatMFFDRegisterDynamic),, MatMFFDComputeJacobian()
640:
641: @*/
642: PetscErrorCode MatCreateMFFD(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,Mat *J)
643: {
647: MatCreate(comm,J);
648: MatSetSizes(*J,m,n,M,N);
649: MatSetType(*J,MATMFFD);
650: return(0);
651: }
656: /*@
657: MatMFFDGetH - Gets the last value that was used as the differencing
658: parameter.
660: Not Collective
662: Input Parameters:
663: . mat - the matrix obtained with MatCreateSNESMF()
665: Output Paramter:
666: . h - the differencing step size
668: Level: advanced
670: .keywords: SNES, matrix-free, parameters
672: .seealso: MatCreateSNESMF(),MatMFFDSetHHistory(), MatCreateMFFD(), MATMFFD
673: MatMFFDResetHHistory(),MatMFFDKSPMonitor()
674: @*/
675: PetscErrorCode MatMFFDGetH(Mat mat,PetscScalar *h)
676: {
677: MatMFFD ctx = (MatMFFD)mat->data;
680: *h = ctx->currenth;
681: return(0);
682: }
687: /*@C
688: MatMFFDSetFunction - Sets the function used in applying the matrix free.
690: Collective on Mat
692: Input Parameters:
693: + mat - the matrix free matrix created via MatCreateSNESMF()
694: . func - the function to use
695: - funcctx - optional function context passed to function
697: Level: advanced
699: Notes:
700: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
701: matrix inside your compute Jacobian routine
703: If this is not set then it will use the function set with SNESSetFunction() if MatCreateSNESMF() was used.
705: .keywords: SNES, matrix-free, function
707: .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD
708: MatMFFDSetHHistory(), MatMFFDResetHHistory(),
709: MatMFFDKSPMonitor(), SNESetFunction()
710: @*/
711: PetscErrorCode MatMFFDSetFunction(Mat mat,PetscErrorCode (*func)(void*,Vec,Vec),void *funcctx)
712: {
713: MatMFFD ctx = (MatMFFD)mat->data;
716: ctx->func = func;
717: ctx->funcctx = funcctx;
718: return(0);
719: }
723: /*@C
724: MatMFFDSetFunctioni - Sets the function for a single component
726: Collective on Mat
728: Input Parameters:
729: + mat - the matrix free matrix created via MatCreateSNESMF()
730: - funci - the function to use
732: Level: advanced
734: Notes:
735: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
736: matrix inside your compute Jacobian routine
739: .keywords: SNES, matrix-free, function
741: .seealso: MatCreateSNESMF(),MatMFFDGetH(),
742: MatMFFDSetHHistory(), MatMFFDResetHHistory(),
743: MatMFFDKSPMonitor(), SNESetFunction()
744: @*/
745: PetscErrorCode MatMFFDSetFunctioni(Mat mat,PetscErrorCode (*funci)(void*,PetscInt,Vec,PetscScalar*))
746: {
747: PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(void*,PetscInt,Vec,PetscScalar*));
751: PetscObjectQueryFunction((PetscObject)mat,"MatMFFDSetFunctioni_C",(void (**)(void))&f);
752: if (f) {
753: (*f)(mat,funci);
754: }
755: return(0);
756: }
761: /*@C
762: MatMFFDSetFunctioniBase - Sets the base vector for a single component function evaluation
764: Collective on Mat
766: Input Parameters:
767: + mat - the matrix free matrix created via MatCreateSNESMF()
768: - func - the function to use
770: Level: advanced
772: Notes:
773: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
774: matrix inside your compute Jacobian routine
777: .keywords: SNES, matrix-free, function
779: .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD
780: MatMFFDSetHHistory(), MatMFFDResetHHistory(),
781: MatMFFDKSPMonitor(), SNESetFunction()
782: @*/
783: PetscErrorCode MatMFFDSetFunctioniBase(Mat mat,PetscErrorCode (*func)(void*,Vec))
784: {
785: PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(void*,Vec));
789: PetscObjectQueryFunction((PetscObject)mat,"MatMFFDSetFunctioniBase_C",(void (**)(void))&f);
790: if (f) {
791: (*f)(mat,func);
792: }
793: return(0);
794: }
799: /*@
800: MatMFFDSetPeriod - Sets how often h is recomputed, by default it is everytime
802: Collective on Mat
804: Input Parameters:
805: + mat - the matrix free matrix created via MatCreateSNESMF()
806: - period - 1 for everytime, 2 for every second etc
808: Options Database Keys:
809: + -mat_mffd_period <period>
811: Level: advanced
814: .keywords: SNES, matrix-free, parameters
816: .seealso: MatCreateSNESMF(),MatMFFDGetH(),
817: MatMFFDSetHHistory(), MatMFFDResetHHistory(),
818: MatMFFDKSPMonitor()
819: @*/
820: PetscErrorCode MatMFFDSetPeriod(Mat mat,PetscInt period)
821: {
822: MatMFFD ctx = (MatMFFD)mat->data;
825: ctx->recomputeperiod = period;
826: return(0);
827: }
831: /*@
832: MatMFFDSetFunctionError - Sets the error_rel for the approximation of
833: matrix-vector products using finite differences.
835: Collective on Mat
837: Input Parameters:
838: + mat - the matrix free matrix created via MatCreateMFFD() or MatCreateSNESMF()
839: - error_rel - relative error (should be set to the square root of
840: the relative error in the function evaluations)
842: Options Database Keys:
843: + -mat_mffd_err <error_rel> - Sets error_rel
845: Level: advanced
847: Notes:
848: The default matrix-free matrix-vector product routine computes
849: .vb
850: F'(u)*a = [F(u+h*a) - F(u)]/h where
851: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
852: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else
853: .ve
855: .keywords: SNES, matrix-free, parameters
857: .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD
858: MatMFFDSetHHistory(), MatMFFDResetHHistory(),
859: MatMFFDKSPMonitor()
860: @*/
861: PetscErrorCode MatMFFDSetFunctionError(Mat mat,PetscReal error)
862: {
863: MatMFFD ctx = (MatMFFD)mat->data;
866: if (error != PETSC_DEFAULT) ctx->error_rel = error;
867: return(0);
868: }
872: /*@
873: MatMFFDAddNullSpace - Provides a null space that an operator is
874: supposed to have. Since roundoff will create a small component in
875: the null space, if you know the null space you may have it
876: automatically removed.
878: Collective on Mat
880: Input Parameters:
881: + J - the matrix-free matrix context
882: - nullsp - object created with MatNullSpaceCreate()
884: Level: advanced
886: .keywords: SNES, matrix-free, null space
888: .seealso: MatNullSpaceCreate(), MatMFFDGetH(), MatCreateSNESMF(), MatCreateMFFD(), MATMFFD
889: MatMFFDSetHHistory(), MatMFFDResetHHistory(),
890: MatMFFDKSPMonitor(), MatMFFDErrorRel()
891: @*/
892: PetscErrorCode MatMFFDAddNullSpace(Mat J,MatNullSpace nullsp)
893: {
895: MatMFFD ctx = (MatMFFD)J->data;
898: PetscObjectReference((PetscObject)nullsp);
899: if (ctx->sp) { MatNullSpaceDestroy(ctx->sp); }
900: ctx->sp = nullsp;
901: return(0);
902: }
906: /*@
907: MatMFFDSetHHistory - Sets an array to collect a history of the
908: differencing values (h) computed for the matrix-free product.
910: Collective on Mat
912: Input Parameters:
913: + J - the matrix-free matrix context
914: . histroy - space to hold the history
915: - nhistory - number of entries in history, if more entries are generated than
916: nhistory, then the later ones are discarded
918: Level: advanced
920: Notes:
921: Use MatMFFDResetHHistory() to reset the history counter and collect
922: a new batch of differencing parameters, h.
924: .keywords: SNES, matrix-free, h history, differencing history
926: .seealso: MatMFFDGetH(), MatCreateSNESMF(),
927: MatMFFDResetHHistory(),
928: MatMFFDKSPMonitor(), MatMFFDSetFunctionError()
930: @*/
931: PetscErrorCode MatMFFDSetHHistory(Mat J,PetscScalar history[],PetscInt nhistory)
932: {
933: MatMFFD ctx = (MatMFFD)J->data;
936: ctx->historyh = history;
937: ctx->maxcurrenth = nhistory;
938: ctx->currenth = 0;
939: return(0);
940: }
944: /*@
945: MatMFFDResetHHistory - Resets the counter to zero to begin
946: collecting a new set of differencing histories.
948: Collective on Mat
950: Input Parameters:
951: . J - the matrix-free matrix context
953: Level: advanced
955: Notes:
956: Use MatMFFDSetHHistory() to create the original history counter.
958: .keywords: SNES, matrix-free, h history, differencing history
960: .seealso: MatMFFDGetH(), MatCreateSNESMF(),
961: MatMFFDSetHHistory(),
962: MatMFFDKSPMonitor(), MatMFFDSetFunctionError()
964: @*/
965: PetscErrorCode MatMFFDResetHHistory(Mat J)
966: {
967: MatMFFD ctx = (MatMFFD)J->data;
970: ctx->ncurrenth = 0;
971: return(0);
972: }
977: /*@
978: MatMFFDSetBase - Sets the vector U at which matrix vector products of the
979: Jacobian are computed
981: Collective on Mat
983: Input Parameters:
984: + J - the MatMFFD matrix
985: . U - the vector
986: - F - (optional) vector that contains F(u) if it has been already computed
988: Notes: This is rarely used directly
990: If F is provided then it is not recomputed. Otherwise the function is evaluated at the base
991: point during the first MatMult() after each call to MatMFFDSetBase().
993: Level: advanced
995: @*/
996: PetscErrorCode MatMFFDSetBase(Mat J,Vec U,Vec F)
997: {
998: PetscErrorCode ierr,(*f)(Mat,Vec,Vec);
1004: PetscObjectQueryFunction((PetscObject)J,"MatMFFDSetBase_C",(void (**)(void))&f);
1005: if (f) {
1006: (*f)(J,U,F);
1007: }
1008: return(0);
1009: }
1013: /*@C
1014: MatMFFDSetCheckh - Sets a function that checks the computed h and adjusts
1015: it to satisfy some criteria
1017: Collective on Mat
1019: Input Parameters:
1020: + J - the MatMFFD matrix
1021: . fun - the function that checks h
1022: - ctx - any context needed by the function
1024: Options Database Keys:
1025: . -mat_mffd_check_positivity
1027: Level: advanced
1029: Notes: For example, MatMFFDSetCheckPositivity() insures that all entries
1030: of U + h*a are non-negative
1032: .seealso: MatMFFDSetCheckPositivity()
1033: @*/
1034: PetscErrorCode MatMFFDSetCheckh(Mat J,PetscErrorCode (*fun)(void*,Vec,Vec,PetscScalar*),void* ctx)
1035: {
1036: PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(void*,Vec,Vec,PetscScalar*),void*);
1040: PetscObjectQueryFunction((PetscObject)J,"MatMFFDSetCheckh_C",(void (**)(void))&f);
1041: if (f) {
1042: (*f)(J,fun,ctx);
1043: }
1044: return(0);
1045: }
1049: /*@
1050: MatMFFDCheckPositivity - Checks that all entries in U + h*a are positive or
1051: zero, decreases h until this is satisfied.
1053: Collective on Vec
1055: Input Parameters:
1056: + U - base vector that is added to
1057: . a - vector that is added
1058: . h - scaling factor on a
1059: - dummy - context variable (unused)
1061: Options Database Keys:
1062: . -mat_mffd_check_positivity
1064: Level: advanced
1066: Notes: This is rarely used directly, rather it is passed as an argument to
1067: MatMFFDSetCheckh()
1069: .seealso: MatMFFDSetCheckh()
1070: @*/
1071: PetscErrorCode MatMFFDCheckPositivity(void* dummy,Vec U,Vec a,PetscScalar *h)
1072: {
1073: PetscReal val, minval;
1074: PetscScalar *u_vec, *a_vec;
1076: PetscInt i,n;
1077: MPI_Comm comm;
1080: PetscObjectGetComm((PetscObject)U,&comm);
1081: VecGetArray(U,&u_vec);
1082: VecGetArray(a,&a_vec);
1083: VecGetLocalSize(U,&n);
1084: minval = PetscAbsScalar(*h*1.01);
1085: for(i=0;i<n;i++) {
1086: if (PetscRealPart(u_vec[i] + *h*a_vec[i]) <= 0.0) {
1087: val = PetscAbsScalar(u_vec[i]/a_vec[i]);
1088: if (val < minval) minval = val;
1089: }
1090: }
1091: VecRestoreArray(U,&u_vec);
1092: VecRestoreArray(a,&a_vec);
1093: PetscGlobalMin(&minval,&val,comm);
1094: if (val <= PetscAbsScalar(*h)) {
1095: PetscInfo2(U,"Scaling back h from %G to %G\n",PetscRealPart(*h),.99*val);
1096: if (PetscRealPart(*h) > 0.0) *h = 0.99*val;
1097: else *h = -0.99*val;
1098: }
1099: return(0);
1100: }