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, either MATSNESMF_WP or MATSNESMF_DS
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;
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: VecSet(y,0.0);
256: return(0);
257: }
259: if (ctx->checkh) {
260: (*ctx->checkh)(U,a,&h,ctx->checkhctx);
261: }
263: /* keep a record of the current differencing parameter h */
264: ctx->currenth = h;
265: #if defined(PETSC_USE_COMPLEX)
266: PetscInfo2(mat,"Current differencing parameter: %G + %G i\n",PetscRealPart(h),PetscImaginaryPart(h));
267: #else
268: PetscInfo1(mat,"Current differencing parameter: %15.12e\n",h);
269: #endif
270: if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
271: ctx->historyh[ctx->ncurrenth] = h;
272: }
273: ctx->ncurrenth++;
275: /* w = u + ha */
276: VecWAXPY(w,h,a,U);
278: if (ctx->usesnes) {
279: eval_fct = SNESComputeFunction;
280: F = ctx->current_f;
281: if (!F) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"You must call MatAssembly() even on matrix-free matrices");
282: (*eval_fct)(snes,w,y);
283: } else {
284: F = ctx->funcvec;
285: /* compute func(U) as base for differencing */
286: if (ctx->ncurrenth == 1) {
287: (*ctx->func)(snes,U,F,ctx->funcctx);
288: }
289: (*ctx->func)(snes,w,y,ctx->funcctx);
290: }
292: VecAXPY(y,-1.0,F);
293: VecScale(y,1.0/h);
295: VecAXPBY(y,ctx->vshift,ctx->vscale,a);
297: if (ctx->sp) {MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);}
299: PetscLogEventEnd(MATSNESMF_Mult,a,y,0,0);
300: return(0);
301: }
305: /*
306: MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix
308: y ~= (F(u + ha) - F(u))/h,
309: where F = nonlinear function, as set by SNESSetFunction()
310: u = current iterate
311: h = difference interval
312: */
313: PetscErrorCode MatGetDiagonal_MFFD(Mat mat,Vec a)
314: {
315: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
316: PetscScalar h,*aa,*ww,v;
317: PetscReal epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
318: Vec w,U;
320: PetscInt i,rstart,rend;
323: if (!ctx->funci) {
324: SETERRQ(PETSC_ERR_ORDER,"Requires calling MatSNESMFSetFunctioni() first");
325: }
327: w = ctx->w;
328: U = ctx->current_u;
329: (*ctx->func)(0,U,a,ctx->funcctx);
330: (*ctx->funcisetbase)(U,ctx->funcctx);
331: VecCopy(U,w);
333: VecGetOwnershipRange(a,&rstart,&rend);
334: VecGetArray(a,&aa);
335: for (i=rstart; i<rend; i++) {
336: VecGetArray(w,&ww);
337: h = ww[i-rstart];
338: if (h == 0.0) h = 1.0;
339: #if !defined(PETSC_USE_COMPLEX)
340: if (h < umin && h >= 0.0) h = umin;
341: else if (h < 0.0 && h > -umin) h = -umin;
342: #else
343: if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0) h = umin;
344: else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
345: #endif
346: h *= epsilon;
347:
348: ww[i-rstart] += h;
349: VecRestoreArray(w,&ww);
350: (*ctx->funci)(i,w,&v,ctx->funcctx);
351: aa[i-rstart] = (v - aa[i-rstart])/h;
353: /* possibly shift and scale result */
354: aa[i - rstart] = ctx->vshift + ctx->vscale*aa[i-rstart];
356: VecGetArray(w,&ww);
357: ww[i-rstart] -= h;
358: VecRestoreArray(w,&ww);
359: }
360: VecRestoreArray(a,&aa);
361: return(0);
362: }
366: PetscErrorCode MatShift_MFFD(Mat Y,PetscScalar a)
367: {
368: MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
370: shell->vshift += a;
371: return(0);
372: }
376: PetscErrorCode MatScale_MFFD(Mat Y,PetscScalar a)
377: {
378: MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
380: shell->vscale *= a;
381: return(0);
382: }
387: /*@
388: MatCreateSNESMF - Creates a matrix-free matrix context for use with
389: a SNES solver. This matrix can be used as the Jacobian argument for
390: the routine SNESSetJacobian().
392: Collective on SNES and Vec
394: Input Parameters:
395: + snes - the SNES context
396: - x - vector where SNES solution is to be stored.
398: Output Parameter:
399: . J - the matrix-free matrix
401: Level: advanced
403: Notes:
404: The matrix-free matrix context merely contains the function pointers
405: and work space for performing finite difference approximations of
406: Jacobian-vector products, F'(u)*a,
408: The default code uses the following approach to compute h
410: .vb
411: F'(u)*a = [F(u+h*a) - F(u)]/h where
412: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
413: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise
414: where
415: error_rel = square root of relative error in function evaluation
416: umin = minimum iterate parameter
417: .ve
418: (see MATSNESMF_WP or MATSNESMF_DS)
419:
420: The user can set the error_rel via MatSNESMFSetFunctionError() and
421: umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
422: of the users manual for details.
424: The user should call MatDestroy() when finished with the matrix-free
425: matrix context.
427: Options Database Keys:
428: + -snes_mf_err <error_rel> - Sets error_rel
429: + -snes_mf_type - wp or ds (see MATSNESMF_WP or MATSNESMF_DS)
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: }
478: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetCheckh_FD(Mat J,FCN3 fun,void*ectx)
479: {
480: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
483: ctx->checkh = fun;
484: ctx->checkhctx = ectx;
485: return(0);
486: }
491: /*@
492: MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line
493: parameter.
495: Collective on Mat
497: Input Parameters:
498: . mat - the matrix obtained with MatCreateSNESMF()
500: Options Database Keys:
501: + -snes_mf_type - wp or ds (see MATSNESMF_WP or MATSNESMF_DS)
502: - -snes_mf_err - square root of estimated relative error in function evaluation
503: - -snes_mf_period - how often h is recomputed, defaults to 1, everytime
505: Level: advanced
507: .keywords: SNES, matrix-free, parameters
509: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
510: MatSNESMFResetHHistory(), MatSNESMFKSPMonitor()
511: @*/
512: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFromOptions(Mat mat)
513: {
514: MatSNESMFCtx mfctx = (MatSNESMFCtx)mat->data;
516: PetscTruth flg;
517: char ftype[256];
520: if (!MatSNESMFRegisterAllCalled) {MatSNESMFRegisterAll(PETSC_NULL);}
521:
522: PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatSNESMF");
523: PetscOptionsList("-snes_mf_type","Matrix free type","MatSNESMFSetType",MatSNESMPetscFList,mfctx->type_name,ftype,256,&flg);
524: if (flg) {
525: MatSNESMFSetType(mat,ftype);
526: }
528: PetscOptionsReal("-snes_mf_err","set sqrt relative error in function","MatSNESMFSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);
529: PetscOptionsInt("-snes_mf_period","how often h is recomputed","MatSNESMFSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);
530: if (mfctx->snes) {
531: PetscOptionsName("-snes_mf_ksp_monitor","Monitor matrix-free parameters","MatSNESMFKSPMonitor",&flg);
532: if (flg) {
533: KSP ksp;
534: SNESGetKSP(mfctx->snes,&ksp);
535: KSPSetMonitor(ksp,MatSNESMFKSPMonitor,PETSC_NULL,0);
536: }
537: }
538: PetscOptionsName("-snes_mf_check_positivity","Insure that U + h*a is nonnegative","MatSNESMFSetCheckh",&flg);
539: if (flg) {
540: MatSNESMFSetCheckh(mat,MatSNESMFCheckPositivity,0);
541: }
542: if (mfctx->ops->setfromoptions) {
543: (*mfctx->ops->setfromoptions)(mfctx);
544: }
545: PetscOptionsEnd();
546: return(0);
547: }
549: /*MC
550: MATMFFD - MATMFFD = "mffd" - A matrix free matrix type.
552: Level: advanced
554: .seealso: MatCreateMF(), MatCreateSNESMF()
555: M*/
559: PetscErrorCode PETSCSNES_DLLEXPORT MatCreate_MFFD(Mat A)
560: {
561: MatSNESMFCtx mfctx;
565: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
566: SNESInitializePackage(PETSC_NULL);
567: #endif
569: PetscHeaderCreate(mfctx,_p_MatSNESMFCtx,struct _MFOps,MATSNESMFCTX_COOKIE,0,"SNESMF",A->comm,MatDestroy_MFFD,MatView_MFFD);
570: mfctx->sp = 0;
571: mfctx->snes = 0;
572: mfctx->error_rel = PETSC_SQRT_MACHINE_EPSILON;
573: mfctx->recomputeperiod = 1;
574: mfctx->count = 0;
575: mfctx->currenth = 0.0;
576: mfctx->historyh = PETSC_NULL;
577: mfctx->ncurrenth = 0;
578: mfctx->maxcurrenth = 0;
579: mfctx->type_name = 0;
580: mfctx->usesnes = PETSC_FALSE;
582: mfctx->vshift = 0.0;
583: mfctx->vscale = 1.0;
585: /*
586: Create the empty data structure to contain compute-h routines.
587: These will be filled in below from the command line options or
588: a later call with MatSNESMFSetType() or if that is not called
589: then it will default in the first use of MatMult_MFFD()
590: */
591: mfctx->ops->compute = 0;
592: mfctx->ops->destroy = 0;
593: mfctx->ops->view = 0;
594: mfctx->ops->setfromoptions = 0;
595: mfctx->hctx = 0;
597: mfctx->func = 0;
598: mfctx->funcctx = 0;
599: mfctx->funcvec = 0;
600: mfctx->w = PETSC_NULL;
602: A->data = mfctx;
604: A->ops->mult = MatMult_MFFD;
605: A->ops->destroy = MatDestroy_MFFD;
606: A->ops->view = MatView_MFFD;
607: A->ops->assemblyend = MatAssemblyEnd_MFFD;
608: A->ops->getdiagonal = MatGetDiagonal_MFFD;
609: A->ops->scale = MatScale_MFFD;
610: A->ops->shift = MatShift_MFFD;
611: A->ops->setfromoptions = MatSNESMFSetFromOptions;
612: A->assembled = PETSC_TRUE;
614: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetBase_C","MatSNESMFSetBase_FD",MatSNESMFSetBase_FD);
615: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioniBase_C","MatSNESMFSetFunctioniBase_FD",MatSNESMFSetFunctioniBase_FD);
616: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioni_C","MatSNESMFSetFunctioni_FD",MatSNESMFSetFunctioni_FD);
617: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetCheckh_C","MatSNESMFSetCheckh_FD",MatSNESMFSetCheckh_FD);
618: mfctx->mat = A;
620: return(0);
621: }
626: /*@
627: MatCreateMF - Creates a matrix-free matrix. See also MatCreateSNESMF()
629: Collective on Vec
631: Input Parameters:
632: . x - vector that defines layout of the vectors and matrices
634: Output Parameter:
635: . J - the matrix-free matrix
637: Level: advanced
639: Notes:
640: The matrix-free matrix context merely contains the function pointers
641: and work space for performing finite difference approximations of
642: Jacobian-vector products, F'(u)*a,
644: The default code uses the following approach to compute h
646: .vb
647: F'(u)*a = [F(u+h*a) - F(u)]/h where
648: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
649: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise
650: where
651: error_rel = square root of relative error in function evaluation
652: umin = minimum iterate parameter
653: .ve
655: The user can set the error_rel via MatSNESMFSetFunctionError() and
656: umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
657: of the users manual for details.
659: The user should call MatDestroy() when finished with the matrix-free
660: matrix context.
662: Options Database Keys:
663: + -snes_mf_err <error_rel> - Sets error_rel
664: . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
665: . -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
666: - -snes_mf_check_positivity
668: .keywords: default, matrix-free, create, matrix
670: .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
671: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateSNESMF(),
672: MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic),, MatSNESMFComputeJacobian()
673:
674: @*/
675: PetscErrorCode PETSCSNES_DLLEXPORT MatCreateMF(Vec x,Mat *J)
676: {
677: MPI_Comm comm;
679: PetscInt n,nloc;
682: PetscObjectGetComm((PetscObject)x,&comm);
683: VecGetSize(x,&n);
684: VecGetLocalSize(x,&nloc);
685: MatCreate(comm,J);
686: MatSetSizes(*J,nloc,nloc,n,n);
687: MatRegisterDynamic(MATMFFD,0,"MatCreate_MFFD",MatCreate_MFFD);
688: MatSetType(*J,MATMFFD);
689: return(0);
690: }
695: /*@
696: MatSNESMFGetH - Gets the last value that was used as the differencing
697: parameter.
699: Not Collective
701: Input Parameters:
702: . mat - the matrix obtained with MatCreateSNESMF()
704: Output Paramter:
705: . h - the differencing step size
707: Level: advanced
709: .keywords: SNES, matrix-free, parameters
711: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
712: MatSNESMFResetHHistory(),MatSNESMFKSPMonitor()
713: @*/
714: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFGetH(Mat mat,PetscScalar *h)
715: {
716: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
719: *h = ctx->currenth;
720: return(0);
721: }
725: /*
726: MatSNESMFKSPMonitor - A KSP monitor for use with the default PETSc
727: SNES matrix free routines. Prints the differencing parameter used at
728: each step.
729: */
730: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFKSPMonitor(KSP ksp,PetscInt n,PetscReal rnorm,void *dummy)
731: {
732: PC pc;
733: MatSNESMFCtx ctx;
735: Mat mat;
736: MPI_Comm comm;
737: PetscTruth nonzeroinitialguess;
740: PetscObjectGetComm((PetscObject)ksp,&comm);
741: KSPGetPC(ksp,&pc);
742: KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);
743: PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL);
744: ctx = (MatSNESMFCtx)mat->data;
746: if (n > 0 || nonzeroinitialguess) {
747: #if defined(PETSC_USE_COMPLEX)
748: PetscPrintf(comm,"%D KSP Residual norm %14.12e h %G + %G i\n",n,rnorm,
749: PetscRealPart(ctx->currenth),PetscImaginaryPart(ctx->currenth));
750: #else
751: PetscPrintf(comm,"%D KSP Residual norm %14.12e h %G \n",n,rnorm,ctx->currenth);
752: #endif
753: } else {
754: PetscPrintf(comm,"%D KSP Residual norm %14.12e\n",n,rnorm);
755: }
756: return(0);
757: }
761: /*@C
762: MatSNESMFSetFunction - Sets the function used in applying the matrix free.
764: Collective on Mat
766: Input Parameters:
767: + mat - the matrix free matrix created via MatCreateSNESMF()
768: . v - workspace vector
769: . func - the function to use
770: - funcctx - optional function context passed to function
772: Level: advanced
774: Notes:
775: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
776: matrix inside your compute Jacobian routine
778: If this is not set then it will use the function set with SNESSetFunction()
780: .keywords: SNES, matrix-free, function
782: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
783: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
784: MatSNESMFKSPMonitor(), SNESetFunction()
785: @*/
786: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunction(Mat mat,Vec v,PetscErrorCode (*func)(SNES,Vec,Vec,void *),void *funcctx)
787: {
788: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
791: ctx->func = func;
792: ctx->funcctx = funcctx;
793: ctx->funcvec = v;
794: return(0);
795: }
799: /*@C
800: MatSNESMFSetFunctioni - Sets the function for a single component
802: Collective on Mat
804: Input Parameters:
805: + mat - the matrix free matrix created via MatCreateSNESMF()
806: - funci - the function to use
808: Level: advanced
810: Notes:
811: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
812: matrix inside your compute Jacobian routine
815: .keywords: SNES, matrix-free, function
817: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
818: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
819: MatSNESMFKSPMonitor(), SNESetFunction()
820: @*/
821: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunctioni(Mat mat,PetscErrorCode (*funci)(PetscInt,Vec,PetscScalar*,void *))
822: {
823: PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(PetscInt,Vec,PetscScalar*,void *));
827: PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioni_C",(void (**)(void))&f);
828: if (f) {
829: (*f)(mat,funci);
830: }
831: return(0);
832: }
837: /*@C
838: MatSNESMFSetFunctioniBase - Sets the base vector for a single component function evaluation
840: Collective on Mat
842: Input Parameters:
843: + mat - the matrix free matrix created via MatCreateSNESMF()
844: - func - the function to use
846: Level: advanced
848: Notes:
849: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
850: matrix inside your compute Jacobian routine
853: .keywords: SNES, matrix-free, function
855: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
856: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
857: MatSNESMFKSPMonitor(), SNESetFunction()
858: @*/
859: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunctioniBase(Mat mat,PetscErrorCode (*func)(Vec,void *))
860: {
861: PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(Vec,void *));
865: PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioniBase_C",(void (**)(void))&f);
866: if (f) {
867: (*f)(mat,func);
868: }
869: return(0);
870: }
875: /*@
876: MatSNESMFSetPeriod - Sets how often h is recomputed, by default it is everytime
878: Collective on Mat
880: Input Parameters:
881: + mat - the matrix free matrix created via MatCreateSNESMF()
882: - period - 1 for everytime, 2 for every second etc
884: Options Database Keys:
885: + -snes_mf_period <period>
887: Level: advanced
890: .keywords: SNES, matrix-free, parameters
892: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
893: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
894: MatSNESMFKSPMonitor()
895: @*/
896: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetPeriod(Mat mat,PetscInt period)
897: {
898: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
901: ctx->recomputeperiod = period;
902: return(0);
903: }
907: /*@
908: MatSNESMFSetFunctionError - Sets the error_rel for the approximation of
909: matrix-vector products using finite differences.
911: Collective on Mat
913: Input Parameters:
914: + mat - the matrix free matrix created via MatCreateSNESMF()
915: - error_rel - relative error (should be set to the square root of
916: the relative error in the function evaluations)
918: Options Database Keys:
919: + -snes_mf_err <error_rel> - Sets error_rel
921: Level: advanced
923: Notes:
924: The default matrix-free matrix-vector product routine computes
925: .vb
926: F'(u)*a = [F(u+h*a) - F(u)]/h where
927: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
928: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else
929: .ve
931: .keywords: SNES, matrix-free, parameters
933: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
934: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
935: MatSNESMFKSPMonitor()
936: @*/
937: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunctionError(Mat mat,PetscReal error)
938: {
939: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
942: if (error != PETSC_DEFAULT) ctx->error_rel = error;
943: return(0);
944: }
948: /*@
949: MatSNESMFAddNullSpace - Provides a null space that an operator is
950: supposed to have. Since roundoff will create a small component in
951: the null space, if you know the null space you may have it
952: automatically removed.
954: Collective on Mat
956: Input Parameters:
957: + J - the matrix-free matrix context
958: - nullsp - object created with MatNullSpaceCreate()
960: Level: advanced
962: .keywords: SNES, matrix-free, null space
964: .seealso: MatNullSpaceCreate(), MatSNESMFGetH(), MatCreateSNESMF(),
965: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
966: MatSNESMFKSPMonitor(), MatSNESMFErrorRel()
967: @*/
968: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFAddNullSpace(Mat J,MatNullSpace nullsp)
969: {
971: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
972: MPI_Comm comm;
975: PetscObjectGetComm((PetscObject)J,&comm);
977: ctx->sp = nullsp;
978: PetscObjectReference((PetscObject)nullsp);
979: return(0);
980: }
984: /*@
985: MatSNESMFSetHHistory - Sets an array to collect a history of the
986: differencing values (h) computed for the matrix-free product.
988: Collective on Mat
990: Input Parameters:
991: + J - the matrix-free matrix context
992: . histroy - space to hold the history
993: - nhistory - number of entries in history, if more entries are generated than
994: nhistory, then the later ones are discarded
996: Level: advanced
998: Notes:
999: Use MatSNESMFResetHHistory() to reset the history counter and collect
1000: a new batch of differencing parameters, h.
1002: .keywords: SNES, matrix-free, h history, differencing history
1004: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
1005: MatSNESMFResetHHistory(),
1006: MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
1008: @*/
1009: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetHHistory(Mat J,PetscScalar history[],PetscInt nhistory)
1010: {
1011: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
1014: ctx->historyh = history;
1015: ctx->maxcurrenth = nhistory;
1016: ctx->currenth = 0;
1017: return(0);
1018: }
1022: /*@
1023: MatSNESMFResetHHistory - Resets the counter to zero to begin
1024: collecting a new set of differencing histories.
1026: Collective on Mat
1028: Input Parameters:
1029: . J - the matrix-free matrix context
1031: Level: advanced
1033: Notes:
1034: Use MatSNESMFSetHHistory() to create the original history counter.
1036: .keywords: SNES, matrix-free, h history, differencing history
1038: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
1039: MatSNESMFSetHHistory(),
1040: MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
1042: @*/
1043: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFResetHHistory(Mat J)
1044: {
1045: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
1048: ctx->ncurrenth = 0;
1049: return(0);
1050: }
1054: /*@
1055: MatSNESMFComputeJacobian - Tells the matrix-free Jacobian object the new location at which
1056: Jacobian matrix vector products will be computed at, i.e. J(x) * a.
1058: Collective on SNES
1060: Input Parameters:
1061: + snes - the nonlinear solver context
1062: . x - the point at which the Jacobian vector products will be performed
1063: . jac - the matrix-free Jacobian object
1064: . B - either the same as jac or another matrix type (ignored)
1065: . flag - not relevent for matrix-free form
1066: - dummy - the user context (ignored)
1068: Level: developer
1070: Notes:
1071: This can be passed into SNESSetJacobian() when using a completely matrix-free solver,
1072: that is the B matrix is also the same matrix operator. This is used when you select
1073: -snes_mf but rarely used directly by users.
1075: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
1076: MatSNESMFSetHHistory(),
1077: MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError(), MatSNESMFCreate(), SNESSetJacobian()
1079: @*/
1080: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFComputeJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy)
1081: {
1084: MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);
1085: MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);
1086: return(0);
1087: }
1091: /*@
1092: MatSNESMFSetBase - Sets the vector U at which matrix vector products of the
1093: Jacobian are computed
1095: Collective on Mat
1097: Input Parameters:
1098: + J - the MatSNESMF matrix
1099: - U - the vector
1101: Notes: This is rarely used directly
1103: Level: advanced
1105: @*/
1106: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetBase(Mat J,Vec U)
1107: {
1108: PetscErrorCode ierr,(*f)(Mat,Vec);
1113: PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetBase_C",(void (**)(void))&f);
1114: if (f) {
1115: (*f)(J,U);
1116: }
1117: return(0);
1118: }
1122: /*@C
1123: MatSNESMFSetCheckh - Sets a function that checks the computed h and adjusts
1124: it to satisfy some criteria
1126: Collective on Mat
1128: Input Parameters:
1129: + J - the MatSNESMF matrix
1130: . fun - the function that checks h
1131: - ctx - any context needed by the function
1133: Options Database Keys:
1134: . -snes_mf_check_positivity
1136: Level: advanced
1138: Notes: For example, MatSNESMFSetCheckPositivity() insures that all entries
1139: of U + h*a are non-negative
1141: .seealso: MatSNESMFSetCheckPositivity()
1142: @*/
1143: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetCheckh(Mat J,PetscErrorCode (*fun)(Vec,Vec,PetscScalar*,void*),void* ctx)
1144: {
1145: PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(Vec,Vec,PetscScalar*,void*),void*);
1149: PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetCheckh_C",(void (**)(void))&f);
1150: if (f) {
1151: (*f)(J,fun,ctx);
1152: }
1153: return(0);
1154: }
1158: /*@
1159: MatSNESMFCheckPositivity - Checks that all entries in U + h*a are positive or
1160: zero, decreases h until this is satisfied.
1162: Collective on Vec
1164: Input Parameters:
1165: + U - base vector that is added to
1166: . a - vector that is added
1167: . h - scaling factor on a
1168: - dummy - context variable (unused)
1170: Options Database Keys:
1171: . -snes_mf_check_positivity
1173: Level: advanced
1175: Notes: This is rarely used directly, rather it is passed as an argument to
1176: MatSNESMFSetCheckh()
1178: .seealso: MatSNESMFSetCheckh()
1179: @*/
1180: PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFCheckPositivity(Vec U,Vec a,PetscScalar *h,void *dummy)
1181: {
1182: PetscReal val, minval;
1183: PetscScalar *u_vec, *a_vec;
1185: PetscInt i,n;
1186: MPI_Comm comm;
1189: PetscObjectGetComm((PetscObject)U,&comm);
1190: VecGetArray(U,&u_vec);
1191: VecGetArray(a,&a_vec);
1192: VecGetLocalSize(U,&n);
1193: minval = PetscAbsScalar(*h*1.01);
1194: for(i=0;i<n;i++) {
1195: if (PetscRealPart(u_vec[i] + *h*a_vec[i]) <= 0.0) {
1196: val = PetscAbsScalar(u_vec[i]/a_vec[i]);
1197: if (val < minval) minval = val;
1198: }
1199: }
1200: VecRestoreArray(U,&u_vec);
1201: VecRestoreArray(a,&a_vec);
1202: PetscGlobalMin(&minval,&val,comm);
1203: if (val <= PetscAbsScalar(*h)) {
1204: PetscInfo2(U,"Scaling back h from %G to %G\n",PetscRealPart(*h),.99*val);
1205: if (PetscRealPart(*h) > 0.0) *h = 0.99*val;
1206: else *h = -0.99*val;
1207: }
1208: return(0);
1209: }