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;
9: /*@C
10: MatSNESMFSetType - Sets the method that is used to compute the
11: differencing parameter for finite differene matrix-free formulations.
13: Input Parameters:
14: + mat - the "matrix-free" matrix created via MatCreateSNESMF(), or MatCreateMF()
15: or MatSetType(mat,MATMFFD);
16: - ftype - the type requested
18: Level: advanced
20: Notes:
21: For example, such routines can compute h for use in
22: Jacobian-vector products of the form
24: F(x+ha) - F(x)
25: F'(u)a ~= ----------------
26: h
28: .seealso: MatCreateSNESMF(), MatSNESMFRegisterDynamic)
29: @*/
30: int MatSNESMFSetType(Mat mat,MatSNESMFType ftype)
31: {
32: int ierr,(*r)(MatSNESMFCtx);
33: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
34: PetscTruth match;
35:
40: /* already set, so just return */
41: PetscTypeCompare((PetscObject)ctx,ftype,&match);
42: if (match) return(0);
44: /* destroy the old one if it exists */
45: if (ctx->ops->destroy) {
46: (*ctx->ops->destroy)(ctx);
47: }
49: /* Get the function pointers for the requrested method */
50: if (!MatSNESMFRegisterAllCalled) {MatSNESMFRegisterAll(PETSC_NULL);}
52: PetscFListFind(ctx->comm,MatSNESMPetscFList,ftype,(void (**)(void)) &r);
54: if (!r) SETERRQ(1,"Unknown MatSNESMF type given");
56: (*r)(ctx);
58: PetscObjectChangeTypeName((PetscObject)ctx,ftype);
60: return(0);
61: }
63: EXTERN_C_BEGIN
64: int MatSNESMFSetFunctioniBase_FD(Mat mat,int (*func)(Vec,void *))
65: {
66: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
69: ctx->funcisetbase = func;
70: return(0);
71: }
72: EXTERN_C_END
74: EXTERN_C_BEGIN
75: int MatSNESMFSetFunctioni_FD(Mat mat,int (*funci)(int,Vec,PetscScalar*,void *))
76: {
77: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
80: ctx->funci = funci;
81: return(0);
82: }
83: EXTERN_C_END
85: /*MC
86: MatSNESMFRegisterDynamic - Adds a method to the MatSNESMF registry.
88: Synopsis:
89: int MatSNESMFRegisterDynamic(char *name_solver,char *path,char *name_create,int (*routine_create)(MatSNESMF))
91: Not Collective
93: Input Parameters:
94: + name_solver - name of a new user-defined compute-h module
95: . path - path (either absolute or relative) the library containing this solver
96: . name_create - name of routine to create method context
97: - routine_create - routine to create method context
99: Level: developer
101: Notes:
102: MatSNESMFRegisterDynamic) may be called multiple times to add several user-defined solvers.
104: If dynamic libraries are used, then the fourth input argument (routine_create)
105: is ignored.
107: Sample usage:
108: .vb
109: MatSNESMFRegisterDynamic"my_h",/home/username/my_lib/lib/libO/solaris/mylib.a,
110: "MyHCreate",MyHCreate);
111: .ve
113: Then, your solver can be chosen with the procedural interface via
114: $ MatSNESMFSetType(mfctx,"my_h")
115: or at runtime via the option
116: $ -snes_mf_type my_h
118: .keywords: MatSNESMF, register
120: .seealso: MatSNESMFRegisterAll(), MatSNESMFRegisterDestroy()
121: M*/
123: int MatSNESMFRegister(char *sname,char *path,char *name,int (*function)(MatSNESMFCtx))
124: {
126: char fullname[256];
129: PetscFListConcat(path,name,fullname);
130: PetscFListAdd(&MatSNESMPetscFList,sname,fullname,(void (*)(void))function);
131: return(0);
132: }
135: /*@C
136: MatSNESMFRegisterDestroy - Frees the list of MatSNESMF methods that were
137: registered by MatSNESMFRegisterDynamic).
139: Not Collective
141: Level: developer
143: .keywords: MatSNESMF, register, destroy
145: .seealso: MatSNESMFRegisterDynamic), MatSNESMFRegisterAll()
146: @*/
147: int MatSNESMFRegisterDestroy(void)
148: {
152: if (MatSNESMPetscFList) {
153: PetscFListDestroy(&MatSNESMPetscFList);
154: MatSNESMPetscFList = 0;
155: }
156: MatSNESMFRegisterAllCalled = PETSC_FALSE;
157: return(0);
158: }
160: /* ----------------------------------------------------------------------------------------*/
161: int MatDestroy_MFFD(Mat mat)
162: {
163: int ierr;
164: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
167: VecDestroy(ctx->w);
168: if (ctx->ops->destroy) {(*ctx->ops->destroy)(ctx);}
169: if (ctx->sp) {MatNullSpaceDestroy(ctx->sp);}
170: PetscHeaderDestroy(ctx);
171: return(0);
172: }
174: /*
175: MatSNESMFView_MFFD - Views matrix-free parameters.
177: */
178: int MatView_MFFD(Mat J,PetscViewer viewer)
179: {
180: int ierr;
181: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
182: PetscTruth isascii;
185: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
186: if (isascii) {
187: PetscViewerASCIIPrintf(viewer," SNES matrix-free approximation:n");
188: PetscViewerASCIIPrintf(viewer," err=%g (relative error in function evaluation)n",ctx->error_rel);
189: if (!ctx->type_name) {
190: PetscViewerASCIIPrintf(viewer," The compute h routine has not yet been setn");
191: } else {
192: PetscViewerASCIIPrintf(viewer," Using %s compute h routinen",ctx->type_name);
193: }
194: if (ctx->ops->view) {
195: (*ctx->ops->view)(ctx,viewer);
196: }
197: } else {
198: SETERRQ1(1,"Viewer type %s not supported for SNES matrix free matrix",((PetscObject)viewer)->type_name);
199: }
200: return(0);
201: }
203: /*
204: MatSNESMFAssemblyEnd_Private - Resets the ctx->ncurrenth to zero. This
205: allows the user to indicate the beginning of a new linear solve by calling
206: MatAssemblyXXX() on the matrix free matrix. This then allows the
207: MatSNESMFCreate_WP() to properly compute ||U|| only the first time
208: in the linear solver rather than every time.
209: */
210: int MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt)
211: {
212: int ierr;
213: MatSNESMFCtx j = (MatSNESMFCtx)J->data;
214: SNESProblemType type;
217: MatSNESMFResetHHistory(J);
218: if (j->usesnes) {
219: SNESGetSolution(j->snes,&j->current_u);
220: SNESGetProblemType(j->snes,&type);
221: if (type == SNES_NONLINEAR_EQUATIONS) {
222: SNESGetFunction(j->snes,&j->current_f,PETSC_NULL,PETSC_NULL);
223: } else if (type == SNES_UNCONSTRAINED_MINIMIZATION) {
224: SNESGetGradient(j->snes,&j->current_f,PETSC_NULL);
225: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid method class");
226: }
227: j->vshift = 0.0;
228: j->vscale = 1.0;
229: return(0);
230: }
232: /*
233: MatSNESMFMult_Private - Default matrix-free form for Jacobian-vector
234: product, y = F'(u)*a:
236: y ~= (F(u + ha) - F(u))/h,
237: where F = nonlinear function, as set by SNESSetFunction()
238: u = current iterate
239: h = difference interval
240: */
241: int MatMult_MFFD(Mat mat,Vec a,Vec y)
242: {
243: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
244: SNES snes;
245: PetscScalar h,mone = -1.0;
246: Vec w,U,F;
247: int ierr,(*eval_fct)(SNES,Vec,Vec)=0;
248: SNESProblemType type;
251: /* We log matrix-free matrix-vector products separately, so that we can
252: separate the performance monitoring from the cases that use conventional
253: storage. We may eventually modify event logging to associate events
254: with particular objects, hence alleviating the more general problem. */
255: PetscLogEventBegin(MAT_MultMatrixFree,a,y,0,0);
257: snes = ctx->snes;
258: w = ctx->w;
259: U = ctx->current_u;
261: /*
262: Compute differencing parameter
263: */
264: if (!ctx->ops->compute) {
265: MatSNESMFSetType(mat,MATSNESMF_DEFAULT);
266: MatSNESMFSetFromOptions(mat);
267: }
268: (*ctx->ops->compute)(ctx,U,a,&h);
270: /* keep a record of the current differencing parameter h */
271: ctx->currenth = h;
272: #if defined(PETSC_USE_COMPLEX)
273: PetscLogInfo(mat,"MatMult_MFFD:Current differencing parameter: %g + %g in",PetscRealPart(h),PetscImaginaryPart(h));
274: #else
275: PetscLogInfo(mat,"MatMult_MFFD:Current differencing parameter: %15.12en",h);
276: #endif
277: if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
278: ctx->historyh[ctx->ncurrenth] = h;
279: }
280: ctx->ncurrenth++;
282: /* w = u + ha */
283: VecWAXPY(&h,a,U,w);
285: if (ctx->usesnes) {
286: SNESGetProblemType(snes,&type);
287: if (type == SNES_NONLINEAR_EQUATIONS) {
288: eval_fct = SNESComputeFunction;
289: } else if (type == SNES_UNCONSTRAINED_MINIMIZATION) {
290: eval_fct = SNESComputeGradient;
291: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid method class");
292: F = ctx->current_f;
293: if (!F) SETERRQ(1,"You must call MatAssembly() even on matrix-free matrices");
294: (*eval_fct)(snes,w,y);
295: } else {
296: F = ctx->funcvec;
297: /* compute func(U) as base for differencing */
298: if (ctx->ncurrenth == 1) {
299: (*ctx->func)(snes,U,F,ctx->funcctx);
300: }
301: (*ctx->func)(snes,w,y,ctx->funcctx);
302: }
304: VecAXPY(&mone,F,y);
305: h = 1.0/h;
306: VecScale(&h,y);
309: if (ctx->vshift != 0.0 && ctx->vscale != 1.0) {
310: VecAXPBY(&ctx->vshift,&ctx->vscale,a,y);
311: } else if (ctx->vscale != 1.0) {
312: VecScale(&ctx->vscale,y);
313: } else if (ctx->vshift != 0.0) {
314: VecAXPY(&ctx->vshift,a,y);
315: }
317: if (ctx->sp) {MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);}
319: PetscLogEventEnd(MAT_MultMatrixFree,a,y,0,0);
320: return(0);
321: }
323: /*
324: MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix
326: y ~= (F(u + ha) - F(u))/h,
327: where F = nonlinear function, as set by SNESSetFunction()
328: u = current iterate
329: h = difference interval
330: */
331: int MatGetDiagonal_MFFD(Mat mat,Vec a)
332: {
333: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
334: PetscScalar h,*aa,*ww,v;
335: PetscReal epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
336: Vec w,U;
337: int i,ierr,rstart,rend;
340: if (!ctx->funci) {
341: SETERRQ(1,"Requirers calling MatSNESMFSetFunctioni() first");
342: }
344: w = ctx->w;
345: U = ctx->current_u;
346: (*ctx->func)(0,U,a,ctx->funcctx);
347: (*ctx->funcisetbase)(U,ctx->funcctx);
348: VecCopy(U,w);
350: VecGetOwnershipRange(a,&rstart,&rend);
351: VecGetArray(a,&aa);
352: for (i=rstart; i<rend; i++) {
353: VecGetArray(w,&ww);
354: h = ww[i-rstart];
355: if (h == 0.0) h = 1.0;
356: #if !defined(PETSC_USE_COMPLEX)
357: if (h < umin && h >= 0.0) h = umin;
358: else if (h < 0.0 && h > -umin) h = -umin;
359: #else
360: if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0) h = umin;
361: else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
362: #endif
363: h *= epsilon;
364:
365: ww[i-rstart] += h;
366: VecRestoreArray(w,&ww);
367: ierr = (*ctx->funci)(i,w,&v,ctx->funcctx);
368: aa[i-rstart] = (v - aa[i-rstart])/h;
370: /* possibly shift and scale result */
371: aa[i - rstart] = ctx->vshift + ctx->vscale*aa[i-rstart];
373: VecGetArray(w,&ww);
374: ww[i-rstart] -= h;
375: VecRestoreArray(w,&ww);
376: }
377: VecRestoreArray(a,&aa);
378: return(0);
379: }
381: int MatShift_MFFD(PetscScalar *a,Mat Y)
382: {
383: MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
385: shell->vshift += *a;
386: return(0);
387: }
389: int MatScale_MFFD(PetscScalar *a,Mat Y)
390: {
391: MatSNESMFCtx shell = (MatSNESMFCtx)Y->data;
393: shell->vscale *= *a;
394: return(0);
395: }
398: /*@C
399: MatCreateSNESMF - Creates a matrix-free matrix context for use with
400: a SNES solver. This matrix can be used as the Jacobian argument for
401: the routine SNESSetJacobian().
403: Collective on SNES and Vec
405: Input Parameters:
406: + snes - the SNES context
407: - x - vector where SNES solution is to be stored.
409: Output Parameter:
410: . J - the matrix-free matrix
412: Level: advanced
414: Notes:
415: The matrix-free matrix context merely contains the function pointers
416: and work space for performing finite difference approximations of
417: Jacobian-vector products, F'(u)*a,
419: The default code uses the following approach to compute h
421: .vb
422: F'(u)*a = [F(u+h*a) - F(u)]/h where
423: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
424: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise
425: where
426: error_rel = square root of relative error in function evaluation
427: umin = minimum iterate parameter
428: .ve
430: The user can set the error_rel via MatSNESMFSetFunctionError() and
431: umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
432: of the users manual for details.
434: The user should call MatDestroy() when finished with the matrix-free
435: matrix context.
437: Options Database Keys:
438: + -snes_mf_err <error_rel> - Sets error_rel
439: . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
440: - -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
442: .keywords: SNES, default, matrix-free, create, matrix
444: .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
445: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateMF(),
446: MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic), MatSNESMFComputeJacobian()
447:
448: @*/
449: int MatCreateSNESMF(SNES snes,Vec x,Mat *J)
450: {
451: MatSNESMFCtx mfctx;
452: int ierr;
455: MatCreateMF(x,J);
457: mfctx = (MatSNESMFCtx)(*J)->data;
458: mfctx->snes = snes;
459: mfctx->usesnes = PETSC_TRUE;
460: PetscLogObjectParent(snes,*J);
461: return(0);
462: }
464: EXTERN_C_BEGIN
465: int MatSNESMFSetBase_FD(Mat J,Vec U)
466: {
467: int ierr;
468: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
471: MatSNESMFResetHHistory(J);
472: ctx->current_u = U;
473: ctx->usesnes = PETSC_FALSE;
474: return(0);
475: }
476: EXTERN_C_END
478: /*@
479: MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line
480: parameter.
482: Collective on Mat
484: Input Parameters:
485: . mat - the matrix obtained with MatCreateSNESMF()
487: Options Database Keys:
488: + -snes_mf_type - <default,wp>
489: - -snes_mf_err - square root of estimated relative error in function evaluation
490: - -snes_mf_period - how often h is recomputed, defaults to 1, everytime
492: Level: advanced
494: .keywords: SNES, matrix-free, parameters
496: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
497: MatSNESMFResetHHistory(), MatSNESMFKSPMonitor()
498: @*/
499: int MatSNESMFSetFromOptions(Mat mat)
500: {
501: MatSNESMFCtx mfctx = (MatSNESMFCtx)mat->data;
502: int ierr;
503: PetscTruth flg;
504: char ftype[256];
507: if (!MatSNESMFRegisterAllCalled) {MatSNESMFRegisterAll(PETSC_NULL);}
508:
509: PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatSNESMF");
510: PetscOptionsList("-snes_mf_type","Matrix free type","MatSNESMFSetType",MatSNESMPetscFList,mfctx->type_name,ftype,256,&flg);
511: if (flg) {
512: MatSNESMFSetType(mat,ftype);
513: }
515: PetscOptionsReal("-snes_mf_err","set sqrt relative error in function","MatSNESMFSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);
516: PetscOptionsInt("-snes_mf_period","how often h is recomputed","MatSNESMFSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);
517: if (mfctx->snes) {
518: PetscOptionsName("-snes_mf_ksp_monitor","Monitor matrix-free parameters","MatSNESMFKSPMonitor",&flg);
519: if (flg) {
520: SLES sles;
521: KSP ksp;
522: SNESGetSLES(mfctx->snes,&sles);
523: SLESGetKSP(sles,&ksp);
524: KSPSetMonitor(ksp,MatSNESMFKSPMonitor,PETSC_NULL,0);
525: }
526: }
527: if (mfctx->ops->setfromoptions) {
528: (*mfctx->ops->setfromoptions)(mfctx);
529: }
530: PetscOptionsEnd();
531: return(0);
532: }
534: EXTERN_C_BEGIN
535: int MatCreate_MFFD(Mat A)
536: {
537: MatSNESMFCtx mfctx;
538: int ierr;
541: PetscHeaderCreate(mfctx,_p_MatSNESMFCtx,struct _MFOps,MATSNESMFCTX_COOKIE,0,"SNESMF",A->comm,MatDestroy_MFFD,MatView_MFFD);
542: PetscLogObjectCreate(mfctx);
543: mfctx->sp = 0;
544: mfctx->snes = 0;
545: mfctx->error_rel = PETSC_SQRT_MACHINE_EPSILON;
546: mfctx->recomputeperiod = 1;
547: mfctx->count = 0;
548: mfctx->currenth = 0.0;
549: mfctx->historyh = PETSC_NULL;
550: mfctx->ncurrenth = 0;
551: mfctx->maxcurrenth = 0;
552: mfctx->type_name = 0;
553: mfctx->usesnes = PETSC_FALSE;
555: mfctx->vshift = 0.0;
556: mfctx->vscale = 1.0;
558: /*
559: Create the empty data structure to contain compute-h routines.
560: These will be filled in below from the command line options or
561: a later call with MatSNESMFSetType() or if that is not called
562: then it will default in the first use of MatMult_MFFD()
563: */
564: mfctx->ops->compute = 0;
565: mfctx->ops->destroy = 0;
566: mfctx->ops->view = 0;
567: mfctx->ops->setfromoptions = 0;
568: mfctx->hctx = 0;
570: mfctx->func = 0;
571: mfctx->funcctx = 0;
572: mfctx->funcvec = 0;
574: A->data = mfctx;
576: A->ops->mult = MatMult_MFFD;
577: A->ops->destroy = MatDestroy_MFFD;
578: A->ops->view = MatView_MFFD;
579: A->ops->assemblyend = MatAssemblyEnd_MFFD;
580: A->ops->getdiagonal = MatGetDiagonal_MFFD;
581: A->ops->scale = MatScale_MFFD;
582: A->ops->shift = MatShift_MFFD;
583: A->ops->setfromoptions = MatSNESMFSetFromOptions;
585: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetBase_C","MatSNESMFSetBase_FD",MatSNESMFSetBase_FD);
586: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioniBase_C","MatSNESMFSetFunctioniBase_FD",MatSNESMFSetFunctioniBase_FD);
587: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioni_C","MatSNESMFSetFunctioni_FD",MatSNESMFSetFunctioni_FD);
588: mfctx->mat = A;
589: VecCreateMPI(A->comm,A->n,A->N,&mfctx->w);
591: return(0);
592: }
594: EXTERN_C_END
596: /*@C
597: MatCreateMF - Creates a matrix-free matrix. See also MatCreateSNESMF()
599: Collective on Vec
601: Input Parameters:
602: . x - vector that defines layout of the vectors and matrices
604: Output Parameter:
605: . J - the matrix-free matrix
607: Level: advanced
609: Notes:
610: The matrix-free matrix context merely contains the function pointers
611: and work space for performing finite difference approximations of
612: Jacobian-vector products, F'(u)*a,
614: The default code uses the following approach to compute h
616: .vb
617: F'(u)*a = [F(u+h*a) - F(u)]/h where
618: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
619: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise
620: where
621: error_rel = square root of relative error in function evaluation
622: umin = minimum iterate parameter
623: .ve
625: The user can set the error_rel via MatSNESMFSetFunctionError() and
626: umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
627: of the users manual for details.
629: The user should call MatDestroy() when finished with the matrix-free
630: matrix context.
632: Options Database Keys:
633: + -snes_mf_err <error_rel> - Sets error_rel
634: . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
635: - -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
637: .keywords: default, matrix-free, create, matrix
639: .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
640: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateSNESMF(),
641: MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic),, MatSNESMFComputeJacobian()
642:
643: @*/
644: int MatCreateMF(Vec x,Mat *J)
645: {
646: MPI_Comm comm;
647: int n,nloc,ierr;
650: PetscObjectGetComm((PetscObject)x,&comm);
651: VecGetSize(x,&n);
652: VecGetLocalSize(x,&nloc);
653: MatCreate(comm,nloc,nloc,n,n,J);
654: MatRegister(MATMFFD,0,"MatCreate_MFFD",MatCreate_MFFD);
655: MatSetType(*J,MATMFFD);
656: return(0);
657: }
660: /*@
661: MatSNESMFGetH - Gets the last value that was used as the differencing
662: parameter.
664: Not Collective
666: Input Parameters:
667: . mat - the matrix obtained with MatCreateSNESMF()
669: Output Paramter:
670: . h - the differencing step size
672: Level: advanced
674: .keywords: SNES, matrix-free, parameters
676: .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
677: MatSNESMFResetHHistory(),MatSNESMFKSPMonitor()
678: @*/
679: int MatSNESMFGetH(Mat mat,PetscScalar *h)
680: {
681: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
684: *h = ctx->currenth;
685: return(0);
686: }
688: /*
689: MatSNESMFKSPMonitor - A KSP monitor for use with the default PETSc
690: SNES matrix free routines. Prints the differencing parameter used at
691: each step.
692: */
693: int MatSNESMFKSPMonitor(KSP ksp,int n,PetscReal rnorm,void *dummy)
694: {
695: PC pc;
696: MatSNESMFCtx ctx;
697: int ierr;
698: Mat mat;
699: MPI_Comm comm;
700: PetscTruth nonzeroinitialguess;
703: PetscObjectGetComm((PetscObject)ksp,&comm);
704: KSPGetPC(ksp,&pc);
705: KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);
706: PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL);
707: ctx = (MatSNESMFCtx)mat->data;
709: if (n > 0 || nonzeroinitialguess) {
710: #if defined(PETSC_USE_COMPLEX)
711: PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g + %g in",n,rnorm,
712: PetscRealPart(ctx->currenth),PetscImaginaryPart(ctx->currenth));
713: #else
714: PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g n",n,rnorm,ctx->currenth);
715: #endif
716: } else {
717: PetscPrintf(comm,"%d KSP Residual norm %14.12en",n,rnorm);
718: }
719: return(0);
720: }
722: /*@C
723: MatSNESMFSetFunction - Sets the function used in applying the matrix free.
725: Collective on Mat
727: Input Parameters:
728: + mat - the matrix free matrix created via MatCreateSNESMF()
729: . v - workspace vector
730: . func - the function to use
731: - funcctx - optional function context passed to function
733: Level: advanced
735: Notes:
736: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
737: matrix inside your compute Jacobian routine
739: If this is not set then it will use the function set with SNESSetFunction()
741: .keywords: SNES, matrix-free, function
743: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
744: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
745: MatSNESMFKSPMonitor(), SNESetFunction()
746: @*/
747: int MatSNESMFSetFunction(Mat mat,Vec v,int (*func)(SNES,Vec,Vec,void *),void *funcctx)
748: {
749: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
752: ctx->func = func;
753: ctx->funcctx = funcctx;
754: ctx->funcvec = v;
755: return(0);
756: }
758: /*@C
759: MatSNESMFSetFunctioni - Sets the function for a single component
761: Collective on Mat
763: Input Parameters:
764: + mat - the matrix free matrix created via MatCreateSNESMF()
765: - funci - the function to use
767: Level: advanced
769: Notes:
770: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
771: matrix inside your compute Jacobian routine
774: .keywords: SNES, matrix-free, function
776: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
777: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
778: MatSNESMFKSPMonitor(), SNESetFunction()
779: @*/
780: int MatSNESMFSetFunctioni(Mat mat,int (*funci)(int,Vec,PetscScalar*,void *))
781: {
782: int ierr,(*f)(Mat,int (*)(int,Vec,PetscScalar*,void *));
786: PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioni_C",(void (**)(void))&f);
787: if (f) {
788: (*f)(mat,funci);
789: }
790: return(0);
791: }
794: /*@C
795: MatSNESMFSetFunctioniBase - Sets the base vector for a single component function evaluation
797: Collective on Mat
799: Input Parameters:
800: + mat - the matrix free matrix created via MatCreateSNESMF()
801: - func - the function to use
803: Level: advanced
805: Notes:
806: If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
807: matrix inside your compute Jacobian routine
810: .keywords: SNES, matrix-free, function
812: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
813: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
814: MatSNESMFKSPMonitor(), SNESetFunction()
815: @*/
816: int MatSNESMFSetFunctioniBase(Mat mat,int (*func)(Vec,void *))
817: {
818: int ierr,(*f)(Mat,int (*)(Vec,void *));
822: PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioniBase_C",(void (**)(void))&f);
823: if (f) {
824: (*f)(mat,func);
825: }
826: return(0);
827: }
830: /*@
831: MatSNESMFSetPeriod - Sets how often h is recomputed, by default it is everytime
833: Collective on Mat
835: Input Parameters:
836: + mat - the matrix free matrix created via MatCreateSNESMF()
837: - period - 1 for everytime, 2 for every second etc
839: Options Database Keys:
840: + -snes_mf_period <period>
842: Level: advanced
845: .keywords: SNES, matrix-free, parameters
847: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
848: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
849: MatSNESMFKSPMonitor()
850: @*/
851: int MatSNESMFSetPeriod(Mat mat,int period)
852: {
853: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
856: ctx->recomputeperiod = period;
857: return(0);
858: }
860: /*@
861: MatSNESMFSetFunctionError - Sets the error_rel for the approximation of
862: matrix-vector products using finite differences.
864: Collective on Mat
866: Input Parameters:
867: + mat - the matrix free matrix created via MatCreateSNESMF()
868: - error_rel - relative error (should be set to the square root of
869: the relative error in the function evaluations)
871: Options Database Keys:
872: + -snes_mf_err <error_rel> - Sets error_rel
874: Level: advanced
876: Notes:
877: The default matrix-free matrix-vector product routine computes
878: .vb
879: F'(u)*a = [F(u+h*a) - F(u)]/h where
880: h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1}
881: = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else
882: .ve
884: .keywords: SNES, matrix-free, parameters
886: .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
887: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
888: MatSNESMFKSPMonitor()
889: @*/
890: int MatSNESMFSetFunctionError(Mat mat,PetscReal error)
891: {
892: MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data;
895: if (error != PETSC_DEFAULT) ctx->error_rel = error;
896: return(0);
897: }
899: /*@
900: MatSNESMFAddNullSpace - Provides a null space that an operator is
901: supposed to have. Since roundoff will create a small component in
902: the null space, if you know the null space you may have it
903: automatically removed.
905: Collective on Mat
907: Input Parameters:
908: + J - the matrix-free matrix context
909: - nullsp - object created with MatNullSpaceCreate()
911: Level: advanced
913: .keywords: SNES, matrix-free, null space
915: .seealso: MatNullSpaceCreate(), MatSNESMFGetH(), MatCreateSNESMF(),
916: MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
917: MatSNESMFKSPMonitor(), MatSNESMFErrorRel()
918: @*/
919: int MatSNESMFAddNullSpace(Mat J,MatNullSpace nullsp)
920: {
921: int ierr;
922: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
923: MPI_Comm comm;
926: PetscObjectGetComm((PetscObject)J,&comm);
928: ctx->sp = nullsp;
929: ierr = PetscObjectReference((PetscObject)nullsp);
930: return(0);
931: }
933: /*@
934: MatSNESMFSetHHistory - Sets an array to collect a history of the
935: differencing values (h) computed for the matrix-free product.
937: Collective on Mat
939: Input Parameters:
940: + J - the matrix-free matrix context
941: . histroy - space to hold the history
942: - nhistory - number of entries in history, if more entries are generated than
943: nhistory, then the later ones are discarded
945: Level: advanced
947: Notes:
948: Use MatSNESMFResetHHistory() to reset the history counter and collect
949: a new batch of differencing parameters, h.
951: .keywords: SNES, matrix-free, h history, differencing history
953: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
954: MatSNESMFResetHHistory(),
955: MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
957: @*/
958: int MatSNESMFSetHHistory(Mat J,PetscScalar *history,int nhistory)
959: {
960: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
963: ctx->historyh = history;
964: ctx->maxcurrenth = nhistory;
965: ctx->currenth = 0;
966: return(0);
967: }
969: /*@
970: MatSNESMFResetHHistory - Resets the counter to zero to begin
971: collecting a new set of differencing histories.
973: Collective on Mat
975: Input Parameters:
976: . J - the matrix-free matrix context
978: Level: advanced
980: Notes:
981: Use MatSNESMFSetHHistory() to create the original history counter.
983: .keywords: SNES, matrix-free, h history, differencing history
985: .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
986: MatSNESMFSetHHistory(),
987: MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
989: @*/
990: int MatSNESMFResetHHistory(Mat J)
991: {
992: MatSNESMFCtx ctx = (MatSNESMFCtx)J->data;
995: ctx->ncurrenth = 0;
996: return(0);
997: }
999: int MatSNESMFComputeJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy)
1000: {
1003: MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);
1004: MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);
1005: return(0);
1006: }
1008: int MatSNESMFSetBase(Mat J,Vec U)
1009: {
1010: int ierr,(*f)(Mat,Vec);
1015: PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetBase_C",(void (**)(void))&f);
1016: if (f) {
1017: (*f)(J,U);
1018: }
1019: return(0);
1020: }