Actual source code: snesmfj.c
2: #include src/mat/matimpl.h
3: #include src/snes/mf/snesmfj.h
5: PetscFList MatSNESMPetscFList = 0;
6: PetscTruth MatSNESMFRegisterAllCalled = PETSC_FALSE;
10: /*@C
11: MatSNESMFSetType - Sets the method that is used to compute the
12: differencing parameter for finite differene matrix-free formulations.
14: Input Parameters:
15: + mat - the "matrix-free" matrix created via MatCreateSNESMF(), or MatCreateMF()
16: or MatSetType(mat,MATMFFD);
17: - ftype - the type requested
19: Level: advanced
21: Notes:
22: For example, such routines can compute h for use in
23: Jacobian-vector products of the form
25: F(x+ha) - F(x)
26: F'(u)a ~= ----------------
27: h
29: .seealso: MatCreateSNESMF(), MatSNESMFRegisterDynamic)
30: @*/
31: PetscErrorCode MatSNESMFSetType(Mat mat,const MatSNESMFType ftype)
32: {
33: PetscErrorCode ierr,(*r)(MatSNESMFCtx);
34: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
35: PetscTruth match;
36:
41: /* already set, so just return */
42: PetscTypeCompare((PetscObject)ctx,ftype,&match);
43: if (match) return(0);
45: /* destroy the old one if it exists */
46: if (ctx->ops->destroy) {
47: (*ctx->ops->destroy)(ctx);
48: }
50: /* Get the function pointers for the requrested method */
51: if (!MatSNESMFRegisterAllCalled) {MatSNESMFRegisterAll(PETSC_NULL);}
52: PetscFListFind(ctx->comm,MatSNESMPetscFList,ftype,(void (**)(void)) &r);
53: if (!r) SETERRQ1(PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown MatSNESMF type %s given",ftype);
54: (*r)(ctx);
55: PetscObjectChangeTypeName((PetscObject)ctx,ftype);
56: return(0);
57: }
63: PetscErrorCode MatSNESMFSetFunctioniBase_FD(Mat mat,FCN1 func)
64: {
65: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
68: ctx->funcisetbase = func;
69: return(0);
70: }
77: PetscErrorCode MatSNESMFSetFunctioni_FD(Mat mat,FCN2 funci)
78: {
79: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
82: ctx->funci = funci;
83: return(0);
84: }
90: PetscErrorCode MatSNESMFRegister(const char sname[],const char path[],const char name[],PetscErrorCode (*function)(MatSNESMFCtx))
91: {
93: char fullname[PETSC_MAX_PATH_LEN];
96: PetscFListConcat(path,name,fullname);
97: PetscFListAdd(&MatSNESMPetscFList,sname,fullname,(void (*)(void))function);
98: return(0);
99: }
104: /*@C
105: MatSNESMFRegisterDestroy - Frees the list of MatSNESMF methods that were
106: registered by MatSNESMFRegisterDynamic).
108: Not Collective
110: Level: developer
112: .keywords: MatSNESMF, register, destroy
114: .seealso: MatSNESMFRegisterDynamic), MatSNESMFRegisterAll()
115: @*/
116: PetscErrorCode MatSNESMFRegisterDestroy(void)
117: {
121: if (MatSNESMPetscFList) {
122: PetscFListDestroy(&MatSNESMPetscFList);
123: MatSNESMPetscFList = 0;
124: }
125: MatSNESMFRegisterAllCalled = PETSC_FALSE;
126: return(0);
127: }
129: /* ----------------------------------------------------------------------------------------*/
132: PetscErrorCode MatDestroy_MFFD(Mat mat)
133: {
135: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
138: if (ctx->w != PETSC_NULL) {
139: VecDestroy(ctx->w);
140: }
141: if (ctx->ops->destroy) {(*ctx->ops->destroy)(ctx);}
142: if (ctx->sp) {MatNullSpaceDestroy(ctx->sp);}
143: PetscHeaderDestroy(ctx);
145: PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetBase_C","",PETSC_NULL);
146: PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetFunctioniBase_C","",PETSC_NULL);
147: PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetFunctioni_C","",PETSC_NULL);
148: PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetCheckh_C","",PETSC_NULL);
150: return(0);
151: }
155: /*
156: MatSNESMFView_MFFD - Views matrix-free parameters.
158: */
159: PetscErrorCode MatView_MFFD(Mat J,PetscViewer viewer)
160: {
162: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
163: PetscTruth iascii;
166: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
167: if (iascii) {
168: PetscViewerASCIIPrintf(viewer," SNES matrix-free approximation:\n");
169: PetscViewerASCIIPrintf(viewer," err=%g (relative error in function evaluation)\n",ctx->error_rel);
170: if (!ctx->type_name) {
171: PetscViewerASCIIPrintf(viewer," The compute h routine has not yet been set\n");
172: } else {
173: PetscViewerASCIIPrintf(viewer," Using %s compute h routine\n",ctx->type_name);
174: }
175: if (ctx->ops->view) {
176: (*ctx->ops->view)(ctx,viewer);
177: }
178: } else {
179: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for SNES matrix free matrix",((PetscObject)viewer)->type_name);
180: }
181: return(0);
182: }
186: /*
187: MatAssemblyEnd_MFFD - Resets the ctx->ncurrenth to zero. This
188: allows the user to indicate the beginning of a new linear solve by calling
189: MatAssemblyXXX() on the matrix free matrix. This then allows the
190: MatSNESMFCreate_WP() to properly compute ||U|| only the first time
191: in the linear solver rather than every time.
192: */
193: PetscErrorCode MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt)
194: {
196: MatSNESMFCtx j = (MatSNESMFCtx)J->data;
199: MatSNESMFResetHHistory(J);
200: if (j->usesnes) {
201: SNESGetSolution(j->snes,&j->current_u);
202: SNESGetFunction(j->snes,&j->current_f,PETSC_NULL,PETSC_NULL);
203: if (!j->w) {
204: VecDuplicate(j->current_u, &j->w);
205: }
206: }
207: j->vshift = 0.0;
208: j->vscale = 1.0;
209: return(0);
210: }
214: /*
215: MatMult_MFFD - Default matrix-free form for Jacobian-vector product, y = F'(u)*a:
217: y ~= (F(u + ha) - F(u))/h,
218: where F = nonlinear function, as set by SNESSetFunction()
219: u = current iterate
220: h = difference interval
221: */
222: PetscErrorCode MatMult_MFFD(Mat mat,Vec a,Vec y)
223: {
224: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
225: SNES snes;
226: PetscScalar h,mone = -1.0;
227: Vec w,U,F;
228: PetscErrorCode ierr,(*eval_fct)(SNES,Vec,Vec)=0;
231: /* We log matrix-free matrix-vector products separately, so that we can
232: separate the performance monitoring from the cases that use conventional
233: storage. We may eventually modify event logging to associate events
234: with particular objects, hence alleviating the more general problem. */
235: PetscLogEventBegin(MAT_MultMatrixFree,a,y,0,0);
237: snes = ctx->snes;
238: w = ctx->w;
239: U = ctx->current_u;
241: /*
242: Compute differencing parameter
243: */
244: if (!ctx->ops->compute) {
245: MatSNESMFSetType(mat,MATSNESMF_WP);
246: MatSNESMFSetFromOptions(mat);
247: }
248: (*ctx->ops->compute)(ctx,U,a,&h);
250: if (ctx->checkh) {
251: (*ctx->checkh)(U,a,&h,ctx->checkhctx);
252: }
254: /* keep a record of the current differencing parameter h */
255: ctx->currenth = h;
256: #if defined(PETSC_USE_COMPLEX)
257: PetscLogInfo(mat,"MatMult_MFFD:Current differencing parameter: %g + %g i\n",PetscRealPart(h),PetscImaginaryPart(h));
258: #else
259: PetscLogInfo(mat,"MatMult_MFFD:Current differencing parameter: %15.12e\n",h);
260: #endif
261: if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
262: ctx->historyh[ctx->ncurrenth] = h;
263: }
264: ctx->ncurrenth++;
266: /* w = u + ha */
267: VecWAXPY(&h,a,U,w);
269: if (ctx->usesnes) {
270: eval_fct = SNESComputeFunction;
271: F = ctx->current_f;
272: if (!F) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"You must call MatAssembly() even on matrix-free matrices");
273: (*eval_fct)(snes,w,y);
274: } else {
275: F = ctx->funcvec;
276: /* compute func(U) as base for differencing */
277: if (ctx->ncurrenth == 1) {
278: (*ctx->func)(snes,U,F,ctx->funcctx);
279: }
280: (*ctx->func)(snes,w,y,ctx->funcctx);
281: }
283: VecAXPY(&mone,F,y);
284: h = 1.0/h;
285: VecScale(&h,y);
287: VecAXPBY(&ctx->vshift,&ctx->vscale,a,y);
289: if (ctx->sp) {MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);}
291: PetscLogEventEnd(MAT_MultMatrixFree,a,y,0,0);
292: return(0);
293: }
297: /*
298: MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix
300: y ~= (F(u + ha) - F(u))/h,
301: where F = nonlinear function, as set by SNESSetFunction()
302: u = current iterate
303: h = difference interval
304: */
305: PetscErrorCode MatGetDiagonal_MFFD(Mat mat,Vec a)
306: {
307: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
308: PetscScalar h,*aa,*ww,v;
309: PetscReal epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
310: Vec w,U;
312: PetscInt i,rstart,rend;
315: if (!ctx->funci) {
316: SETERRQ(PETSC_ERR_ORDER,"Requires calling MatSNESMFSetFunctioni() first");
317: }
319: w = ctx->w;
320: U = ctx->current_u;
321: (*ctx->func)(0,U,a,ctx->funcctx);
322: (*ctx->funcisetbase)(U,ctx->funcctx);
323: VecCopy(U,w);
325: VecGetOwnershipRange(a,&rstart,&rend);
326: VecGetArray(a,&aa);
327: for (i=rstart; i<rend; i++) {
328: VecGetArray(w,&ww);
329: h = ww[i-rstart];
330: if (h == 0.0) h = 1.0;
331: #if !defined(PETSC_USE_COMPLEX)
332: if (h < umin && h >= 0.0) h = umin;
333: else if (h < 0.0 && h > -umin) h = -umin;
334: #else
335: if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0) h = umin;
336: else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
337: #endif
338: h *= epsilon;
339:
340: ww[i-rstart] += h;
341: VecRestoreArray(w,&ww);
342: (*ctx->funci)(i,w,&v,ctx->funcctx);
343: aa[i-rstart] = (v - aa[i-rstart])/h;
345: /* possibly shift and scale result */
346: aa[i - rstart] = ctx->vshift + ctx->vscale*aa[i-rstart];
348: VecGetArray(w,&ww);
349: ww[i-rstart] -= h;
350: VecRestoreArray(w,&ww);
351: }
352: VecRestoreArray(a,&aa);
353: return(0);
354: }
358: PetscErrorCode MatShift_MFFD(const PetscScalar *a,Mat Y)
359: {
360: MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
362: shell->vshift += *a;
363: return(0);
364: }
368: PetscErrorCode MatScale_MFFD(const PetscScalar *a,Mat Y)
369: {
370: MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
372: shell->vscale *= *a;
373: return(0);
374: }
379: /*@C
380: MatCreateSNESMF - Creates a matrix-free matrix context for use with
381: a SNES solver. This matrix can be used as the Jacobian argument for
382: the routine SNESSetJacobian().
384: Collective on SNES and Vec
386: Input Parameters:
387: + snes - the SNES context
388: - x - vector where SNES solution is to be stored.
390: Output Parameter:
391: . J - the matrix-free matrix
393: Level: advanced
395: Notes:
396: The matrix-free matrix context merely contains the function pointers
397: and work space for performing finite difference approximations of
398: Jacobian-vector products, F'(u)*a,
400: The default code uses the following approach to compute h
402: .vb
403: F'(u)*a = [F(u+h*a) - F(u)]/h where
404: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
405: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise
406: where
407: error_rel = square root of relative error in function evaluation
408: umin = minimum iterate parameter
409: .ve
411: The user can set the error_rel via MatSNESMFSetFunctionError() and
412: umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
413: of the users manual for details.
415: The user should call MatDestroy() when finished with the matrix-free
416: matrix context.
418: Options Database Keys:
419: + -snes_mf_err <error_rel> - Sets error_rel
420: . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
421: - -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
423: .keywords: SNES, default, matrix-free, create, matrix
425: .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
426: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateMF(),
427: MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic), MatSNESMFComputeJacobian()
428:
429: @*/
430: PetscErrorCode MatCreateSNESMF(SNES snes,Vec x,Mat *J)
431: {
432: MatSNESMFCtx mfctx;
436: MatCreateMF(x,J);
438: mfctx = (MatSNESMFCtx)(*J)->data;
439: mfctx->snes = snes;
440: mfctx->usesnes = PETSC_TRUE;
441: PetscLogObjectParent(snes,*J);
442: return(0);
443: }
448: PetscErrorCode MatSNESMFSetBase_FD(Mat J,Vec U)
449: {
451: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
454: MatSNESMFResetHHistory(J);
455: ctx->current_u = U;
456: ctx->usesnes = PETSC_FALSE;
457: if (!ctx->w) {
458: VecDuplicate(ctx->current_u, &ctx->w);
459: }
460: J->assembled = PETSC_TRUE;
461: return(0);
462: }
469: PetscErrorCode MatSNESMFSetCheckh_FD(Mat J,FCN3 fun,void*ectx)
470: {
471: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
474: ctx->checkh = fun;
475: ctx->checkhctx = ectx;
476: return(0);
477: }
482: /*@
483: MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line
484: parameter.
486: Collective on Mat
488: Input Parameters:
489: . mat - the matrix obtained with MatCreateSNESMF()
491: Options Database Keys:
492: + -snes_mf_type - <default,wp>
493: - -snes_mf_err - square root of estimated relative error in function evaluation
494: - -snes_mf_period - how often h is recomputed, defaults to 1, everytime
496: Level: advanced
498: .keywords: SNES, matrix-free, parameters
500: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
501: MatSNESMFResetHHistory(), MatSNESMFKSPMonitor()
502: @*/
503: PetscErrorCode MatSNESMFSetFromOptions(Mat mat)
504: {
505: MatSNESMFCtx mfctx = (MatSNESMFCtx)mat->data;
507: PetscTruth flg;
508: char ftype[256];
511: if (!MatSNESMFRegisterAllCalled) {MatSNESMFRegisterAll(PETSC_NULL);}
512:
513: PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatSNESMF");
514: PetscOptionsList("-snes_mf_type","Matrix free type","MatSNESMFSetType",MatSNESMPetscFList,mfctx->type_name,ftype,256,&flg);
515: if (flg) {
516: MatSNESMFSetType(mat,ftype);
517: }
519: PetscOptionsReal("-snes_mf_err","set sqrt relative error in function","MatSNESMFSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);
520: PetscOptionsInt("-snes_mf_period","how often h is recomputed","MatSNESMFSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);
521: if (mfctx->snes) {
522: PetscOptionsName("-snes_mf_ksp_monitor","Monitor matrix-free parameters","MatSNESMFKSPMonitor",&flg);
523: if (flg) {
524: KSP ksp;
525: SNESGetKSP(mfctx->snes,&ksp);
526: KSPSetMonitor(ksp,MatSNESMFKSPMonitor,PETSC_NULL,0);
527: }
528: }
529: PetscOptionsName("-snes_mf_check_positivity","Insure that U + h*a is nonnegative","MatSNESMFSetCheckh",&flg);
530: if (flg) {
531: MatSNESMFSetCheckh(mat,MatSNESMFCheckPositivity,0);
532: }
533: if (mfctx->ops->setfromoptions) {
534: (*mfctx->ops->setfromoptions)(mfctx);
535: }
536: PetscOptionsEnd();
537: return(0);
538: }
540: /*MC
541: MATMFFD - MATMFFD = "mffd" - A matrix free matrix type.
543: Level: advanced
545: .seealso: MatCreateMF(), MatCreateSNESMF()
546: M*/
550: PetscErrorCode MatCreate_MFFD(Mat A)
551: {
552: MatSNESMFCtx mfctx;
556: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
557: SNESInitializePackage(PETSC_NULL);
558: #endif
560: PetscHeaderCreate(mfctx,_p_MatSNESMFCtx,struct _MFOps,MATSNESMFCTX_COOKIE,0,"SNESMF",A->comm,MatDestroy_MFFD,MatView_MFFD);
561: PetscLogObjectCreate(mfctx);
562: mfctx->sp = 0;
563: mfctx->snes = 0;
564: mfctx->error_rel = PETSC_SQRT_MACHINE_EPSILON;
565: mfctx->recomputeperiod = 1;
566: mfctx->count = 0;
567: mfctx->currenth = 0.0;
568: mfctx->historyh = PETSC_NULL;
569: mfctx->ncurrenth = 0;
570: mfctx->maxcurrenth = 0;
571: mfctx->type_name = 0;
572: mfctx->usesnes = PETSC_FALSE;
574: mfctx->vshift = 0.0;
575: mfctx->vscale = 1.0;
577: /*
578: Create the empty data structure to contain compute-h routines.
579: These will be filled in below from the command line options or
580: a later call with MatSNESMFSetType() or if that is not called
581: then it will default in the first use of MatMult_MFFD()
582: */
583: mfctx->ops->compute = 0;
584: mfctx->ops->destroy = 0;
585: mfctx->ops->view = 0;
586: mfctx->ops->setfromoptions = 0;
587: mfctx->hctx = 0;
589: mfctx->func = 0;
590: mfctx->funcctx = 0;
591: mfctx->funcvec = 0;
592: mfctx->w = PETSC_NULL;
594: A->data = mfctx;
596: A->ops->mult = MatMult_MFFD;
597: A->ops->destroy = MatDestroy_MFFD;
598: A->ops->view = MatView_MFFD;
599: A->ops->assemblyend = MatAssemblyEnd_MFFD;
600: A->ops->getdiagonal = MatGetDiagonal_MFFD;
601: A->ops->scale = MatScale_MFFD;
602: A->ops->shift = MatShift_MFFD;
603: A->ops->setfromoptions = MatSNESMFSetFromOptions;
604: A->assembled = PETSC_TRUE;
606: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetBase_C","MatSNESMFSetBase_FD",MatSNESMFSetBase_FD);
607: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioniBase_C","MatSNESMFSetFunctioniBase_FD",MatSNESMFSetFunctioniBase_FD);
608: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioni_C","MatSNESMFSetFunctioni_FD",MatSNESMFSetFunctioni_FD);
609: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetCheckh_C","MatSNESMFSetCheckh_FD",MatSNESMFSetCheckh_FD);
610: mfctx->mat = A;
612: return(0);
613: }
618: /*@C
619: MatCreateMF - Creates a matrix-free matrix. See also MatCreateSNESMF()
621: Collective on Vec
623: Input Parameters:
624: . x - vector that defines layout of the vectors and matrices
626: Output Parameter:
627: . J - the matrix-free matrix
629: Level: advanced
631: Notes:
632: The matrix-free matrix context merely contains the function pointers
633: and work space for performing finite difference approximations of
634: Jacobian-vector products, F'(u)*a,
636: The default code uses the following approach to compute h
638: .vb
639: F'(u)*a = [F(u+h*a) - F(u)]/h where
640: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
641: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise
642: where
643: error_rel = square root of relative error in function evaluation
644: umin = minimum iterate parameter
645: .ve
647: The user can set the error_rel via MatSNESMFSetFunctionError() and
648: umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
649: of the users manual for details.
651: The user should call MatDestroy() when finished with the matrix-free
652: matrix context.
654: Options Database Keys:
655: + -snes_mf_err <error_rel> - Sets error_rel
656: . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
657: . -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
658: - -snes_mf_check_positivity
660: .keywords: default, matrix-free, create, matrix
662: .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
663: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateSNESMF(),
664: MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic),, MatSNESMFComputeJacobian()
665:
666: @*/
667: PetscErrorCode MatCreateMF(Vec x,Mat *J)
668: {
669: MPI_Comm comm;
671: PetscInt n,nloc;
674: PetscObjectGetComm((PetscObject)x,&comm);
675: VecGetSize(x,&n);
676: VecGetLocalSize(x,&nloc);
677: MatCreate(comm,nloc,nloc,n,n,J);
678: MatRegisterDynamic(MATMFFD,0,"MatCreate_MFFD",MatCreate_MFFD);
679: MatSetType(*J,MATMFFD);
680: return(0);
681: }
686: /*@
687: MatSNESMFGetH - Gets the last value that was used as the differencing
688: parameter.
690: Not Collective
692: Input Parameters:
693: . mat - the matrix obtained with MatCreateSNESMF()
695: Output Paramter:
696: . h - the differencing step size
698: Level: advanced
700: .keywords: SNES, matrix-free, parameters
702: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
703: MatSNESMFResetHHistory(),MatSNESMFKSPMonitor()
704: @*/
705: PetscErrorCode MatSNESMFGetH(Mat mat,PetscScalar *h)
706: {
707: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
710: *h = ctx->currenth;
711: return(0);
712: }
716: /*
717: MatSNESMFKSPMonitor - A KSP monitor for use with the default PETSc
718: SNES matrix free routines. Prints the differencing parameter used at
719: each step.
720: */
721: PetscErrorCode MatSNESMFKSPMonitor(KSP ksp,PetscInt n,PetscReal rnorm,void *dummy)
722: {
723: PC pc;
724: MatSNESMFCtx ctx;
726: Mat mat;
727: MPI_Comm comm;
728: PetscTruth nonzeroinitialguess;
731: PetscObjectGetComm((PetscObject)ksp,&comm);
732: KSPGetPC(ksp,&pc);
733: KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);
734: PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL);
735: ctx = (MatSNESMFCtx)mat->data;
737: if (n > 0 || nonzeroinitialguess) {
738: #if defined(PETSC_USE_COMPLEX)
739: PetscPrintf(comm,"%D KSP Residual norm %14.12e h %g + %g i\n",n,rnorm,
740: PetscRealPart(ctx->currenth),PetscImaginaryPart(ctx->currenth));
741: #else
742: PetscPrintf(comm,"%D KSP Residual norm %14.12e h %g \n",n,rnorm,ctx->currenth);
743: #endif
744: } else {
745: PetscPrintf(comm,"%D KSP Residual norm %14.12e\n",n,rnorm);
746: }
747: return(0);
748: }
752: /*@C
753: MatSNESMFSetFunction - Sets the function used in applying the matrix free.
755: Collective on Mat
757: Input Parameters:
758: + mat - the matrix free matrix created via MatCreateSNESMF()
759: . v - workspace vector
760: . func - the function to use
761: - funcctx - optional function context passed to function
763: Level: advanced
765: Notes:
766: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
767: matrix inside your compute Jacobian routine
769: If this is not set then it will use the function set with SNESSetFunction()
771: .keywords: SNES, matrix-free, function
773: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
774: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
775: MatSNESMFKSPMonitor(), SNESetFunction()
776: @*/
777: PetscErrorCode MatSNESMFSetFunction(Mat mat,Vec v,PetscErrorCode (*func)(SNES,Vec,Vec,void *),void *funcctx)
778: {
779: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
782: ctx->func = func;
783: ctx->funcctx = funcctx;
784: ctx->funcvec = v;
785: return(0);
786: }
790: /*@C
791: MatSNESMFSetFunctioni - Sets the function for a single component
793: Collective on Mat
795: Input Parameters:
796: + mat - the matrix free matrix created via MatCreateSNESMF()
797: - funci - the function to use
799: Level: advanced
801: Notes:
802: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
803: matrix inside your compute Jacobian routine
806: .keywords: SNES, matrix-free, function
808: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
809: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
810: MatSNESMFKSPMonitor(), SNESetFunction()
811: @*/
812: PetscErrorCode MatSNESMFSetFunctioni(Mat mat,PetscErrorCode (*funci)(PetscInt,Vec,PetscScalar*,void *))
813: {
814: PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(PetscInt,Vec,PetscScalar*,void *));
818: PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioni_C",(void (**)(void))&f);
819: if (f) {
820: (*f)(mat,funci);
821: }
822: return(0);
823: }
828: /*@C
829: MatSNESMFSetFunctioniBase - Sets the base vector for a single component function evaluation
831: Collective on Mat
833: Input Parameters:
834: + mat - the matrix free matrix created via MatCreateSNESMF()
835: - func - the function to use
837: Level: advanced
839: Notes:
840: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
841: matrix inside your compute Jacobian routine
844: .keywords: SNES, matrix-free, function
846: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
847: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
848: MatSNESMFKSPMonitor(), SNESetFunction()
849: @*/
850: PetscErrorCode MatSNESMFSetFunctioniBase(Mat mat,PetscErrorCode (*func)(Vec,void *))
851: {
852: PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(Vec,void *));
856: PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioniBase_C",(void (**)(void))&f);
857: if (f) {
858: (*f)(mat,func);
859: }
860: return(0);
861: }
866: /*@
867: MatSNESMFSetPeriod - Sets how often h is recomputed, by default it is everytime
869: Collective on Mat
871: Input Parameters:
872: + mat - the matrix free matrix created via MatCreateSNESMF()
873: - period - 1 for everytime, 2 for every second etc
875: Options Database Keys:
876: + -snes_mf_period <period>
878: Level: advanced
881: .keywords: SNES, matrix-free, parameters
883: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
884: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
885: MatSNESMFKSPMonitor()
886: @*/
887: PetscErrorCode MatSNESMFSetPeriod(Mat mat,PetscInt period)
888: {
889: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
892: ctx->recomputeperiod = period;
893: return(0);
894: }
898: /*@
899: MatSNESMFSetFunctionError - Sets the error_rel for the approximation of
900: matrix-vector products using finite differences.
902: Collective on Mat
904: Input Parameters:
905: + mat - the matrix free matrix created via MatCreateSNESMF()
906: - error_rel - relative error (should be set to the square root of
907: the relative error in the function evaluations)
909: Options Database Keys:
910: + -snes_mf_err <error_rel> - Sets error_rel
912: Level: advanced
914: Notes:
915: The default matrix-free matrix-vector product routine computes
916: .vb
917: F'(u)*a = [F(u+h*a) - F(u)]/h where
918: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
919: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else
920: .ve
922: .keywords: SNES, matrix-free, parameters
924: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
925: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
926: MatSNESMFKSPMonitor()
927: @*/
928: PetscErrorCode MatSNESMFSetFunctionError(Mat mat,PetscReal error)
929: {
930: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
933: if (error != PETSC_DEFAULT) ctx->error_rel = error;
934: return(0);
935: }
939: /*@
940: MatSNESMFAddNullSpace - Provides a null space that an operator is
941: supposed to have. Since roundoff will create a small component in
942: the null space, if you know the null space you may have it
943: automatically removed.
945: Collective on Mat
947: Input Parameters:
948: + J - the matrix-free matrix context
949: - nullsp - object created with MatNullSpaceCreate()
951: Level: advanced
953: .keywords: SNES, matrix-free, null space
955: .seealso: MatNullSpaceCreate(), MatSNESMFGetH(), MatCreateSNESMF(),
956: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
957: MatSNESMFKSPMonitor(), MatSNESMFErrorRel()
958: @*/
959: PetscErrorCode MatSNESMFAddNullSpace(Mat J,MatNullSpace nullsp)
960: {
962: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
963: MPI_Comm comm;
966: PetscObjectGetComm((PetscObject)J,&comm);
968: ctx->sp = nullsp;
969: PetscObjectReference((PetscObject)nullsp);
970: return(0);
971: }
975: /*@
976: MatSNESMFSetHHistory - Sets an array to collect a history of the
977: differencing values (h) computed for the matrix-free product.
979: Collective on Mat
981: Input Parameters:
982: + J - the matrix-free matrix context
983: . histroy - space to hold the history
984: - nhistory - number of entries in history, if more entries are generated than
985: nhistory, then the later ones are discarded
987: Level: advanced
989: Notes:
990: Use MatSNESMFResetHHistory() to reset the history counter and collect
991: a new batch of differencing parameters, h.
993: .keywords: SNES, matrix-free, h history, differencing history
995: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
996: MatSNESMFResetHHistory(),
997: MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
999: @*/
1000: PetscErrorCode MatSNESMFSetHHistory(Mat J,PetscScalar history[],PetscInt nhistory)
1001: {
1002: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
1005: ctx->historyh = history;
1006: ctx->maxcurrenth = nhistory;
1007: ctx->currenth = 0;
1008: return(0);
1009: }
1013: /*@
1014: MatSNESMFResetHHistory - Resets the counter to zero to begin
1015: collecting a new set of differencing histories.
1017: Collective on Mat
1019: Input Parameters:
1020: . J - the matrix-free matrix context
1022: Level: advanced
1024: Notes:
1025: Use MatSNESMFSetHHistory() to create the original history counter.
1027: .keywords: SNES, matrix-free, h history, differencing history
1029: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
1030: MatSNESMFSetHHistory(),
1031: MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
1033: @*/
1034: PetscErrorCode MatSNESMFResetHHistory(Mat J)
1035: {
1036: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
1039: ctx->ncurrenth = 0;
1040: return(0);
1041: }
1045: PetscErrorCode MatSNESMFComputeJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy)
1046: {
1049: MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);
1050: MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);
1051: return(0);
1052: }
1056: /*@
1057: MatSNESMFSetBase - Sets the vector U at which matrix vector products of the
1058: Jacobian are computed
1060: Collective on Mat
1062: Input Parameters:
1063: + J - the MatSNESMF matrix
1064: - U - the vector
1066: Notes: This is rarely used directly
1068: Level: advanced
1070: @*/
1071: PetscErrorCode MatSNESMFSetBase(Mat J,Vec U)
1072: {
1073: PetscErrorCode ierr,(*f)(Mat,Vec);
1078: PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetBase_C",(void (**)(void))&f);
1079: if (f) {
1080: (*f)(J,U);
1081: }
1082: return(0);
1083: }
1087: /*@C
1088: MatSNESMFSetCheckh - Sets a function that checks the computed h and adjusts
1089: it to satisfy some criteria
1091: Collective on Mat
1093: Input Parameters:
1094: + J - the MatSNESMF matrix
1095: . fun - the function that checks h
1096: - ctx - any context needed by the function
1098: Options Database Keys:
1099: . -snes_mf_check_positivity
1101: Level: advanced
1103: Notes: For example, MatSNESMFSetCheckPositivity() insures that all entries
1104: of U + h*a are non-negative
1106: .seealso: MatSNESMFSetCheckPositivity()
1107: @*/
1108: PetscErrorCode MatSNESMFSetCheckh(Mat J,PetscErrorCode (*fun)(Vec,Vec,PetscScalar*,void*),void* ctx)
1109: {
1110: PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(Vec,Vec,PetscScalar*,void*),void*);
1114: PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetCheckh_C",(void (**)(void))&f);
1115: if (f) {
1116: (*f)(J,fun,ctx);
1117: }
1118: return(0);
1119: }
1123: /*@
1124: MatSNESMFCheckPositivity - Checks that all entries in U + h*a are positive or
1125: zero, decreases h until this is satisfied.
1127: Collective on Vec
1129: Input Parameters:
1130: + U - base vector that is added to
1131: . a - vector that is added
1132: . h - scaling factor on a
1133: - dummy - context variable (unused)
1135: Options Database Keys:
1136: . -snes_mf_check_positivity
1138: Level: advanced
1140: Notes: This is rarely used directly, rather it is passed as an argument to
1141: MatSNESMFSetCheckh()
1143: .seealso: MatSNESMFSetCheckh()
1144: @*/
1145: PetscErrorCode MatSNESMFCheckPositivity(Vec U,Vec a,PetscScalar *h,void *dummy)
1146: {
1147: PetscReal val, minval;
1148: PetscScalar *u_vec, *a_vec;
1150: PetscInt i,n;
1151: MPI_Comm comm;
1154: PetscObjectGetComm((PetscObject)U,&comm);
1155: VecGetArray(U,&u_vec);
1156: VecGetArray(a,&a_vec);
1157: VecGetLocalSize(U,&n);
1158: minval = PetscAbsScalar(*h*1.01);
1159: for(i=0;i<n;i++) {
1160: if (PetscRealPart(u_vec[i] + *h*a_vec[i]) <= 0.0) {
1161: val = PetscAbsScalar(u_vec[i]/a_vec[i]);
1162: if (val < minval) minval = val;
1163: }
1164: }
1165: VecRestoreArray(U,&u_vec);
1166: VecRestoreArray(a,&a_vec);
1167: PetscGlobalMin(&minval,&val,comm);
1168: if (val <= PetscAbsScalar(*h)) {
1169: PetscLogInfo(U,"MatSNESMFCheckPositivity: Scaling back h from %g to %g\n",PetscRealPart(*h),.99*val);
1170: if (PetscRealPart(*h) > 0.0) *h = 0.99*val;
1171: else *h = -0.99*val;
1172: }
1173: return(0);
1174: }