Actual source code: snesmfj.c
1: /*$Id: snesmfj.c,v 1.131 2001/09/05 18:45:40 bsmith Exp $*/
3: #include src/mat/matimpl.h
4: #include src/snes/mf/snesmfj.h
6: PetscFList MatSNESMPetscFList = 0;
7: PetscTruth MatSNESMFRegisterAllCalled = PETSC_FALSE;
11: /*@C
12: MatSNESMFSetType - Sets the method that is used to compute the
13: differencing parameter for finite differene matrix-free formulations.
15: Input Parameters:
16: + mat - the "matrix-free" matrix created via MatCreateSNESMF(), or MatCreateMF()
17: or MatSetType(mat,MATMFFD);
18: - ftype - the type requested
20: Level: advanced
22: Notes:
23: For example, such routines can compute h for use in
24: Jacobian-vector products of the form
26: F(x+ha) - F(x)
27: F'(u)a ~= ----------------
28: h
30: .seealso: MatCreateSNESMF(), MatSNESMFRegisterDynamic)
31: @*/
32: int MatSNESMFSetType(Mat mat,const MatSNESMFType ftype)
33: {
34: int ierr,(*r)(MatSNESMFCtx);
35: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
36: PetscTruth match;
37:
42: /* already set, so just return */
43: PetscTypeCompare((PetscObject)ctx,ftype,&match);
44: if (match) return(0);
46: /* destroy the old one if it exists */
47: if (ctx->ops->destroy) {
48: (*ctx->ops->destroy)(ctx);
49: }
51: /* Get the function pointers for the requrested method */
52: if (!MatSNESMFRegisterAllCalled) {MatSNESMFRegisterAll(PETSC_NULL);}
54: PetscFListFind(ctx->comm,MatSNESMPetscFList,ftype,(void (**)(void)) &r);
56: if (!r) SETERRQ(1,"Unknown MatSNESMF type given");
58: (*r)(ctx);
60: PetscObjectChangeTypeName((PetscObject)ctx,ftype);
62: return(0);
63: }
65: typedef int (*FCN1)(Vec,void*); /* force argument to next function to not be extern C*/
66: EXTERN_C_BEGIN
69: int MatSNESMFSetFunctioniBase_FD(Mat mat,FCN1 func)
70: {
71: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
74: ctx->funcisetbase = func;
75: return(0);
76: }
77: EXTERN_C_END
79: typedef int (*FCN2)(int,Vec,PetscScalar*,void*); /* force argument to next function to not be extern C*/
80: EXTERN_C_BEGIN
83: int MatSNESMFSetFunctioni_FD(Mat mat,FCN2 funci)
84: {
85: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
88: ctx->funci = funci;
89: return(0);
90: }
91: EXTERN_C_END
96: int MatSNESMFRegister(const char sname[],const char path[],const char name[],int (*function)(MatSNESMFCtx))
97: {
99: char fullname[256];
102: PetscFListConcat(path,name,fullname);
103: PetscFListAdd(&MatSNESMPetscFList,sname,fullname,(void (*)(void))function);
104: return(0);
105: }
110: /*@C
111: MatSNESMFRegisterDestroy - Frees the list of MatSNESMF methods that were
112: registered by MatSNESMFRegisterDynamic).
114: Not Collective
116: Level: developer
118: .keywords: MatSNESMF, register, destroy
120: .seealso: MatSNESMFRegisterDynamic), MatSNESMFRegisterAll()
121: @*/
122: int MatSNESMFRegisterDestroy(void)
123: {
127: if (MatSNESMPetscFList) {
128: PetscFListDestroy(&MatSNESMPetscFList);
129: MatSNESMPetscFList = 0;
130: }
131: MatSNESMFRegisterAllCalled = PETSC_FALSE;
132: return(0);
133: }
135: /* ----------------------------------------------------------------------------------------*/
138: int MatDestroy_MFFD(Mat mat)
139: {
140: int ierr;
141: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
144: if (ctx->w != PETSC_NULL) {
145: VecDestroy(ctx->w);
146: }
147: if (ctx->ops->destroy) {(*ctx->ops->destroy)(ctx);}
148: if (ctx->sp) {MatNullSpaceDestroy(ctx->sp);}
149: PetscHeaderDestroy(ctx);
150: return(0);
151: }
155: /*
156: MatSNESMFView_MFFD - Views matrix-free parameters.
158: */
159: int MatView_MFFD(Mat J,PetscViewer viewer)
160: {
161: int ierr;
162: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
163: PetscTruth isascii;
166: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
167: if (isascii) {
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(1,"Viewer type %s not supported for SNES matrix free matrix",((PetscObject)viewer)->type_name);
180: }
181: return(0);
182: }
186: /*
187: MatSNESMFAssemblyEnd_Private - 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: int MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt)
194: {
195: int ierr;
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 == PETSC_NULL) {
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: int 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: int 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(1,"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);
288: if (ctx->vshift != 0.0 && ctx->vscale != 1.0) {
289: VecAXPBY(&ctx->vshift,&ctx->vscale,a,y);
290: } else if (ctx->vscale != 1.0) {
291: VecScale(&ctx->vscale,y);
292: } else if (ctx->vshift != 0.0) {
293: VecAXPY(&ctx->vshift,a,y);
294: }
296: if (ctx->sp) {MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);}
298: PetscLogEventEnd(MAT_MultMatrixFree,a,y,0,0);
299: return(0);
300: }
304: /*
305: MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix
307: y ~= (F(u + ha) - F(u))/h,
308: where F = nonlinear function, as set by SNESSetFunction()
309: u = current iterate
310: h = difference interval
311: */
312: int MatGetDiagonal_MFFD(Mat mat,Vec a)
313: {
314: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
315: PetscScalar h,*aa,*ww,v;
316: PetscReal epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
317: Vec w,U;
318: int i,ierr,rstart,rend;
321: if (!ctx->funci) {
322: SETERRQ(1,"Requirers calling MatSNESMFSetFunctioni() first");
323: }
325: w = ctx->w;
326: U = ctx->current_u;
327: (*ctx->func)(0,U,a,ctx->funcctx);
328: (*ctx->funcisetbase)(U,ctx->funcctx);
329: VecCopy(U,w);
331: VecGetOwnershipRange(a,&rstart,&rend);
332: VecGetArray(a,&aa);
333: for (i=rstart; i<rend; i++) {
334: VecGetArray(w,&ww);
335: h = ww[i-rstart];
336: if (h == 0.0) h = 1.0;
337: #if !defined(PETSC_USE_COMPLEX)
338: if (h < umin && h >= 0.0) h = umin;
339: else if (h < 0.0 && h > -umin) h = -umin;
340: #else
341: if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0) h = umin;
342: else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
343: #endif
344: h *= epsilon;
345:
346: ww[i-rstart] += h;
347: VecRestoreArray(w,&ww);
348: (*ctx->funci)(i,w,&v,ctx->funcctx);
349: aa[i-rstart] = (v - aa[i-rstart])/h;
351: /* possibly shift and scale result */
352: aa[i - rstart] = ctx->vshift + ctx->vscale*aa[i-rstart];
354: VecGetArray(w,&ww);
355: ww[i-rstart] -= h;
356: VecRestoreArray(w,&ww);
357: }
358: VecRestoreArray(a,&aa);
359: return(0);
360: }
364: int MatShift_MFFD(const PetscScalar *a,Mat Y)
365: {
366: MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
368: shell->vshift += *a;
369: return(0);
370: }
374: int MatScale_MFFD(const PetscScalar *a,Mat Y)
375: {
376: MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
378: shell->vscale *= *a;
379: return(0);
380: }
385: /*@C
386: MatCreateSNESMF - Creates a matrix-free matrix context for use with
387: a SNES solver. This matrix can be used as the Jacobian argument for
388: the routine SNESSetJacobian().
390: Collective on SNES and Vec
392: Input Parameters:
393: + snes - the SNES context
394: - x - vector where SNES solution is to be stored.
396: Output Parameter:
397: . J - the matrix-free matrix
399: Level: advanced
401: Notes:
402: The matrix-free matrix context merely contains the function pointers
403: and work space for performing finite difference approximations of
404: Jacobian-vector products, F'(u)*a,
406: The default code uses the following approach to compute h
408: .vb
409: F'(u)*a = [F(u+h*a) - F(u)]/h where
410: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
411: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise
412: where
413: error_rel = square root of relative error in function evaluation
414: umin = minimum iterate parameter
415: .ve
417: The user can set the error_rel via MatSNESMFSetFunctionError() and
418: umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
419: of the users manual for details.
421: The user should call MatDestroy() when finished with the matrix-free
422: matrix context.
424: Options Database Keys:
425: + -snes_mf_err <error_rel> - Sets error_rel
426: . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
427: - -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
429: .keywords: SNES, default, matrix-free, create, matrix
431: .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
432: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateMF(),
433: MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic), MatSNESMFComputeJacobian()
434:
435: @*/
436: int MatCreateSNESMF(SNES snes,Vec x,Mat *J)
437: {
438: MatSNESMFCtx mfctx;
439: int ierr;
442: MatCreateMF(x,J);
444: mfctx = (MatSNESMFCtx)(*J)->data;
445: mfctx->snes = snes;
446: mfctx->usesnes = PETSC_TRUE;
447: PetscLogObjectParent(snes,*J);
448: return(0);
449: }
451: EXTERN_C_BEGIN
454: int MatSNESMFSetBase_FD(Mat J,Vec U)
455: {
456: int ierr;
457: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
460: MatSNESMFResetHHistory(J);
461: ctx->current_u = U;
462: ctx->usesnes = PETSC_FALSE;
463: if (ctx->w == PETSC_NULL) {
464: VecDuplicate(ctx->current_u, &ctx->w);
465: }
466: return(0);
467: }
468: EXTERN_C_END
470: typedef int (*FCN3)(Vec,Vec,PetscScalar*,void*); /* force argument to next function to not be extern C*/
471: EXTERN_C_BEGIN
474: int MatSNESMFSetCheckh_FD(Mat J,FCN3 fun,void*ectx)
475: {
476: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
479: ctx->checkh = fun;
480: ctx->checkhctx = ectx;
481: return(0);
482: }
483: EXTERN_C_END
487: /*@
488: MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line
489: parameter.
491: Collective on Mat
493: Input Parameters:
494: . mat - the matrix obtained with MatCreateSNESMF()
496: Options Database Keys:
497: + -snes_mf_type - <default,wp>
498: - -snes_mf_err - square root of estimated relative error in function evaluation
499: - -snes_mf_period - how often h is recomputed, defaults to 1, everytime
501: Level: advanced
503: .keywords: SNES, matrix-free, parameters
505: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
506: MatSNESMFResetHHistory(), MatSNESMFKSPMonitor()
507: @*/
508: int MatSNESMFSetFromOptions(Mat mat)
509: {
510: MatSNESMFCtx mfctx = (MatSNESMFCtx)mat->data;
511: int ierr;
512: PetscTruth flg;
513: char ftype[256];
516: if (!MatSNESMFRegisterAllCalled) {MatSNESMFRegisterAll(PETSC_NULL);}
517:
518: PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatSNESMF");
519: PetscOptionsList("-snes_mf_type","Matrix free type","MatSNESMFSetType",MatSNESMPetscFList,mfctx->type_name,ftype,256,&flg);
520: if (flg) {
521: MatSNESMFSetType(mat,ftype);
522: }
524: PetscOptionsReal("-snes_mf_err","set sqrt relative error in function","MatSNESMFSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);
525: PetscOptionsInt("-snes_mf_period","how often h is recomputed","MatSNESMFSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);
526: if (mfctx->snes) {
527: PetscOptionsName("-snes_mf_ksp_monitor","Monitor matrix-free parameters","MatSNESMFKSPMonitor",&flg);
528: if (flg) {
529: KSP ksp;
530: SNESGetKSP(mfctx->snes,&ksp);
531: KSPSetMonitor(ksp,MatSNESMFKSPMonitor,PETSC_NULL,0);
532: }
533: }
534: PetscOptionsName("-snes_mf_check_positivity","Insure that U + h*a is nonnegative","MatSNESMFSetCheckh",&flg);
535: if (flg) {
536: MatSNESMFSetCheckh(mat,MatSNESMFCheckPositivity,0);
537: }
538: if (mfctx->ops->setfromoptions) {
539: (*mfctx->ops->setfromoptions)(mfctx);
540: }
541: PetscOptionsEnd();
542: return(0);
543: }
545: /*MC
546: MATMFFD - MATMFFD = "mffd" - A matrix free matrix type.
548: Level: advanced
550: .seealso: MatCreateMF, MatCreateSNESMF
551: M*/
552: EXTERN_C_BEGIN
555: int MatCreate_MFFD(Mat A)
556: {
557: MatSNESMFCtx mfctx;
558: int ierr;
561: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
562: SNESInitializePackage(PETSC_NULL);
563: #endif
565: PetscHeaderCreate(mfctx,_p_MatSNESMFCtx,struct _MFOps,MATSNESMFCTX_COOKIE,0,"SNESMF",A->comm,MatDestroy_MFFD,MatView_MFFD);
566: PetscLogObjectCreate(mfctx);
567: mfctx->sp = 0;
568: mfctx->snes = 0;
569: mfctx->error_rel = PETSC_SQRT_MACHINE_EPSILON;
570: mfctx->recomputeperiod = 1;
571: mfctx->count = 0;
572: mfctx->currenth = 0.0;
573: mfctx->historyh = PETSC_NULL;
574: mfctx->ncurrenth = 0;
575: mfctx->maxcurrenth = 0;
576: mfctx->type_name = 0;
577: mfctx->usesnes = PETSC_FALSE;
579: mfctx->vshift = 0.0;
580: mfctx->vscale = 1.0;
582: /*
583: Create the empty data structure to contain compute-h routines.
584: These will be filled in below from the command line options or
585: a later call with MatSNESMFSetType() or if that is not called
586: then it will default in the first use of MatMult_MFFD()
587: */
588: mfctx->ops->compute = 0;
589: mfctx->ops->destroy = 0;
590: mfctx->ops->view = 0;
591: mfctx->ops->setfromoptions = 0;
592: mfctx->hctx = 0;
594: mfctx->func = 0;
595: mfctx->funcctx = 0;
596: mfctx->funcvec = 0;
597: mfctx->w = PETSC_NULL;
599: A->data = mfctx;
601: A->ops->mult = MatMult_MFFD;
602: A->ops->destroy = MatDestroy_MFFD;
603: A->ops->view = MatView_MFFD;
604: A->ops->assemblyend = MatAssemblyEnd_MFFD;
605: A->ops->getdiagonal = MatGetDiagonal_MFFD;
606: A->ops->scale = MatScale_MFFD;
607: A->ops->shift = MatShift_MFFD;
608: A->ops->setfromoptions = MatSNESMFSetFromOptions;
610: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetBase_C","MatSNESMFSetBase_FD",MatSNESMFSetBase_FD);
611: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioniBase_C","MatSNESMFSetFunctioniBase_FD",MatSNESMFSetFunctioniBase_FD);
612: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioni_C","MatSNESMFSetFunctioni_FD",MatSNESMFSetFunctioni_FD);
613: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetCheckh_C","MatSNESMFSetCheckh_FD",MatSNESMFSetCheckh_FD);
614: mfctx->mat = A;
616: return(0);
617: }
618: EXTERN_C_END
622: /*@C
623: MatCreateMF - Creates a matrix-free matrix. See also MatCreateSNESMF()
625: Collective on Vec
627: Input Parameters:
628: . x - vector that defines layout of the vectors and matrices
630: Output Parameter:
631: . J - the matrix-free matrix
633: Level: advanced
635: Notes:
636: The matrix-free matrix context merely contains the function pointers
637: and work space for performing finite difference approximations of
638: Jacobian-vector products, F'(u)*a,
640: The default code uses the following approach to compute h
642: .vb
643: F'(u)*a = [F(u+h*a) - F(u)]/h where
644: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
645: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise
646: where
647: error_rel = square root of relative error in function evaluation
648: umin = minimum iterate parameter
649: .ve
651: The user can set the error_rel via MatSNESMFSetFunctionError() and
652: umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
653: of the users manual for details.
655: The user should call MatDestroy() when finished with the matrix-free
656: matrix context.
658: Options Database Keys:
659: + -snes_mf_err <error_rel> - Sets error_rel
660: . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
661: . -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
662: - -snes_mf_check_positivity
664: .keywords: default, matrix-free, create, matrix
666: .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
667: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateSNESMF(),
668: MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic),, MatSNESMFComputeJacobian()
669:
670: @*/
671: int MatCreateMF(Vec x,Mat *J)
672: {
673: MPI_Comm comm;
674: int n,nloc,ierr;
677: PetscObjectGetComm((PetscObject)x,&comm);
678: VecGetSize(x,&n);
679: VecGetLocalSize(x,&nloc);
680: MatCreate(comm,nloc,nloc,n,n,J);
681: MatRegisterDynamic(MATMFFD,0,"MatCreate_MFFD",MatCreate_MFFD);
682: MatSetType(*J,MATMFFD);
683: return(0);
684: }
689: /*@
690: MatSNESMFGetH - Gets the last value that was used as the differencing
691: parameter.
693: Not Collective
695: Input Parameters:
696: . mat - the matrix obtained with MatCreateSNESMF()
698: Output Paramter:
699: . h - the differencing step size
701: Level: advanced
703: .keywords: SNES, matrix-free, parameters
705: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
706: MatSNESMFResetHHistory(),MatSNESMFKSPMonitor()
707: @*/
708: int MatSNESMFGetH(Mat mat,PetscScalar *h)
709: {
710: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
713: *h = ctx->currenth;
714: return(0);
715: }
719: /*
720: MatSNESMFKSPMonitor - A KSP monitor for use with the default PETSc
721: SNES matrix free routines. Prints the differencing parameter used at
722: each step.
723: */
724: int MatSNESMFKSPMonitor(KSP ksp,int n,PetscReal rnorm,void *dummy)
725: {
726: PC pc;
727: MatSNESMFCtx ctx;
728: int ierr;
729: Mat mat;
730: MPI_Comm comm;
731: PetscTruth nonzeroinitialguess;
734: PetscObjectGetComm((PetscObject)ksp,&comm);
735: KSPGetPC(ksp,&pc);
736: KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);
737: PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL);
738: ctx = (MatSNESMFCtx)mat->data;
740: if (n > 0 || nonzeroinitialguess) {
741: #if defined(PETSC_USE_COMPLEX)
742: PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g + %g i\n",n,rnorm,
743: PetscRealPart(ctx->currenth),PetscImaginaryPart(ctx->currenth));
744: #else
745: PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g \n",n,rnorm,ctx->currenth);
746: #endif
747: } else {
748: PetscPrintf(comm,"%d KSP Residual norm %14.12e\n",n,rnorm);
749: }
750: return(0);
751: }
755: /*@C
756: MatSNESMFSetFunction - Sets the function used in applying the matrix free.
758: Collective on Mat
760: Input Parameters:
761: + mat - the matrix free matrix created via MatCreateSNESMF()
762: . v - workspace vector
763: . func - the function to use
764: - funcctx - optional function context passed to function
766: Level: advanced
768: Notes:
769: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
770: matrix inside your compute Jacobian routine
772: If this is not set then it will use the function set with SNESSetFunction()
774: .keywords: SNES, matrix-free, function
776: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
777: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
778: MatSNESMFKSPMonitor(), SNESetFunction()
779: @*/
780: int MatSNESMFSetFunction(Mat mat,Vec v,int (*func)(SNES,Vec,Vec,void *),void *funcctx)
781: {
782: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
785: ctx->func = func;
786: ctx->funcctx = funcctx;
787: ctx->funcvec = v;
788: return(0);
789: }
793: /*@C
794: MatSNESMFSetFunctioni - Sets the function for a single component
796: Collective on Mat
798: Input Parameters:
799: + mat - the matrix free matrix created via MatCreateSNESMF()
800: - funci - the function to use
802: Level: advanced
804: Notes:
805: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
806: matrix inside your compute Jacobian routine
809: .keywords: SNES, matrix-free, function
811: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
812: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
813: MatSNESMFKSPMonitor(), SNESetFunction()
814: @*/
815: int MatSNESMFSetFunctioni(Mat mat,int (*funci)(int,Vec,PetscScalar*,void *))
816: {
817: int ierr,(*f)(Mat,int (*)(int,Vec,PetscScalar*,void *));
821: PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioni_C",(void (**)(void))&f);
822: if (f) {
823: (*f)(mat,funci);
824: }
825: return(0);
826: }
831: /*@C
832: MatSNESMFSetFunctioniBase - Sets the base vector for a single component function evaluation
834: Collective on Mat
836: Input Parameters:
837: + mat - the matrix free matrix created via MatCreateSNESMF()
838: - func - the function to use
840: Level: advanced
842: Notes:
843: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
844: matrix inside your compute Jacobian routine
847: .keywords: SNES, matrix-free, function
849: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
850: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
851: MatSNESMFKSPMonitor(), SNESetFunction()
852: @*/
853: int MatSNESMFSetFunctioniBase(Mat mat,int (*func)(Vec,void *))
854: {
855: int ierr,(*f)(Mat,int (*)(Vec,void *));
859: PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioniBase_C",(void (**)(void))&f);
860: if (f) {
861: (*f)(mat,func);
862: }
863: return(0);
864: }
869: /*@
870: MatSNESMFSetPeriod - Sets how often h is recomputed, by default it is everytime
872: Collective on Mat
874: Input Parameters:
875: + mat - the matrix free matrix created via MatCreateSNESMF()
876: - period - 1 for everytime, 2 for every second etc
878: Options Database Keys:
879: + -snes_mf_period <period>
881: Level: advanced
884: .keywords: SNES, matrix-free, parameters
886: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
887: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
888: MatSNESMFKSPMonitor()
889: @*/
890: int MatSNESMFSetPeriod(Mat mat,int period)
891: {
892: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
895: ctx->recomputeperiod = period;
896: return(0);
897: }
901: /*@
902: MatSNESMFSetFunctionError - Sets the error_rel for the approximation of
903: matrix-vector products using finite differences.
905: Collective on Mat
907: Input Parameters:
908: + mat - the matrix free matrix created via MatCreateSNESMF()
909: - error_rel - relative error (should be set to the square root of
910: the relative error in the function evaluations)
912: Options Database Keys:
913: + -snes_mf_err <error_rel> - Sets error_rel
915: Level: advanced
917: Notes:
918: The default matrix-free matrix-vector product routine computes
919: .vb
920: F'(u)*a = [F(u+h*a) - F(u)]/h where
921: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
922: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else
923: .ve
925: .keywords: SNES, matrix-free, parameters
927: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
928: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
929: MatSNESMFKSPMonitor()
930: @*/
931: int MatSNESMFSetFunctionError(Mat mat,PetscReal error)
932: {
933: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
936: if (error != PETSC_DEFAULT) ctx->error_rel = error;
937: return(0);
938: }
942: /*@
943: MatSNESMFAddNullSpace - Provides a null space that an operator is
944: supposed to have. Since roundoff will create a small component in
945: the null space, if you know the null space you may have it
946: automatically removed.
948: Collective on Mat
950: Input Parameters:
951: + J - the matrix-free matrix context
952: - nullsp - object created with MatNullSpaceCreate()
954: Level: advanced
956: .keywords: SNES, matrix-free, null space
958: .seealso: MatNullSpaceCreate(), MatSNESMFGetH(), MatCreateSNESMF(),
959: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
960: MatSNESMFKSPMonitor(), MatSNESMFErrorRel()
961: @*/
962: int MatSNESMFAddNullSpace(Mat J,MatNullSpace nullsp)
963: {
964: int ierr;
965: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
966: MPI_Comm comm;
969: PetscObjectGetComm((PetscObject)J,&comm);
971: ctx->sp = nullsp;
972: PetscObjectReference((PetscObject)nullsp);
973: return(0);
974: }
978: /*@
979: MatSNESMFSetHHistory - Sets an array to collect a history of the
980: differencing values (h) computed for the matrix-free product.
982: Collective on Mat
984: Input Parameters:
985: + J - the matrix-free matrix context
986: . histroy - space to hold the history
987: - nhistory - number of entries in history, if more entries are generated than
988: nhistory, then the later ones are discarded
990: Level: advanced
992: Notes:
993: Use MatSNESMFResetHHistory() to reset the history counter and collect
994: a new batch of differencing parameters, h.
996: .keywords: SNES, matrix-free, h history, differencing history
998: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
999: MatSNESMFResetHHistory(),
1000: MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
1002: @*/
1003: int MatSNESMFSetHHistory(Mat J,PetscScalar history[],int nhistory)
1004: {
1005: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
1008: ctx->historyh = history;
1009: ctx->maxcurrenth = nhistory;
1010: ctx->currenth = 0;
1011: return(0);
1012: }
1016: /*@
1017: MatSNESMFResetHHistory - Resets the counter to zero to begin
1018: collecting a new set of differencing histories.
1020: Collective on Mat
1022: Input Parameters:
1023: . J - the matrix-free matrix context
1025: Level: advanced
1027: Notes:
1028: Use MatSNESMFSetHHistory() to create the original history counter.
1030: .keywords: SNES, matrix-free, h history, differencing history
1032: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
1033: MatSNESMFSetHHistory(),
1034: MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
1036: @*/
1037: int MatSNESMFResetHHistory(Mat J)
1038: {
1039: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
1042: ctx->ncurrenth = 0;
1043: return(0);
1044: }
1048: int MatSNESMFComputeJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy)
1049: {
1052: MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);
1053: MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);
1054: return(0);
1055: }
1059: /*@
1060: MatSNESMFSetBase - Sets the vector U at which matrix vector products of the
1061: Jacobian are computed
1063: Collective on Mat
1065: Input Parameters:
1066: + J - the MatSNESMF matrix
1067: - U - the vector
1069: Notes: This is rarely used directly
1071: Level: advanced
1073: @*/
1074: int MatSNESMFSetBase(Mat J,Vec U)
1075: {
1076: int ierr,(*f)(Mat,Vec);
1081: PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetBase_C",(void (**)(void))&f);
1082: if (f) {
1083: (*f)(J,U);
1084: }
1085: return(0);
1086: }
1090: /*@C
1091: MatSNESMFSetCheckh - Sets a function that checks the computed h and adjusts
1092: it to satisfy some criteria
1094: Collective on Mat
1096: Input Parameters:
1097: + J - the MatSNESMF matrix
1098: . fun - the function that checks h
1099: - ctx - any context needed by the function
1101: Options Database Keys:
1102: . -snes_mf_check_positivity
1104: Level: advanced
1106: Notes: For example, MatSNESMFSetCheckPositivity() insures that all entries
1107: of U + h*a are non-negative
1109: .seealso: MatSNESMFSetCheckPositivity()
1110: @*/
1111: int MatSNESMFSetCheckh(Mat J,int (*fun)(Vec,Vec,PetscScalar*,void*),void* ctx)
1112: {
1113: int ierr,(*f)(Mat,int (*)(Vec,Vec,PetscScalar*,void*),void*);
1117: PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetCheckh_C",(void (**)(void))&f);
1118: if (f) {
1119: (*f)(J,fun,ctx);
1120: }
1121: return(0);
1122: }
1126: /*@
1127: MatSNESMFCheckPositivity - Checks that all entries in U + h*a are positive or
1128: zero, decreases h until this is satisfied.
1130: Collective on Vec
1132: Input Parameters:
1133: + U - base vector that is added to
1134: . a - vector that is added
1135: . h - scaling factor on a
1136: - dummy - context variable (unused)
1138: Options Database Keys:
1139: . -snes_mf_check_positivity
1141: Level: advanced
1143: Notes: This is rarely used directly, rather it is passed as an argument to
1144: MatSNESMFSetCheckh()
1146: .seealso: MatSNESMFSetCheckh()
1147: @*/
1148: int MatSNESMFCheckPositivity(Vec U,Vec a,PetscScalar *h,void *dummy)
1149: {
1150: PetscReal val, minval;
1151: PetscScalar *u_vec, *a_vec;
1152: int ierr, i, size;
1153: MPI_Comm comm;
1156: PetscObjectGetComm((PetscObject)U,&comm);
1157: VecGetArray(U,&u_vec);
1158: VecGetArray(a,&a_vec);
1159: VecGetLocalSize(U,&size);
1160: minval = PetscAbsScalar(*h*1.01);
1161: for(i=0;i<size;i++) {
1162: if (PetscRealPart(u_vec[i] + *h*a_vec[i]) <= 0.0) {
1163: val = PetscAbsScalar(u_vec[i]/a_vec[i]);
1164: if (val < minval) minval = val;
1165: }
1166: }
1167: VecRestoreArray(U,&u_vec);
1168: VecRestoreArray(a,&a_vec);
1169: PetscGlobalMin(&minval,&val,comm);
1170: if (val <= PetscAbsScalar(*h)) {
1171: PetscLogInfo(U,"MatSNESMFCheckPositivity: Scaling back h from %g to %g\n",PetscRealPart(*h),.99*val);
1172: if (PetscRealPart(*h) > 0.0) *h = 0.99*val;
1173: else *h = -0.99*val;
1174: }
1175: return(0);
1176: }