Actual source code: fdmatrix.c
petsc-3.8.4 2018-03-24
2: /*
3: This is where the abstract matrix operations are defined that are
4: used for finite difference computations of Jacobians using coloring.
5: */
7: #include <petsc/private/matimpl.h>
8: #include <petsc/private/isimpl.h>
10: PetscErrorCode MatFDColoringSetF(MatFDColoring fd,Vec F)
11: {
15: if (F) {
16: VecCopy(F,fd->w1);
17: fd->fset = PETSC_TRUE;
18: } else {
19: fd->fset = PETSC_FALSE;
20: }
21: return(0);
22: }
24: #include <petscdraw.h>
25: static PetscErrorCode MatFDColoringView_Draw_Zoom(PetscDraw draw,void *Aa)
26: {
27: MatFDColoring fd = (MatFDColoring)Aa;
29: PetscInt i,j,nz,row;
30: PetscReal x,y;
31: MatEntry *Jentry=fd->matentry;
34: /* loop over colors */
35: nz = 0;
36: for (i=0; i<fd->ncolors; i++) {
37: for (j=0; j<fd->nrows[i]; j++) {
38: row = Jentry[nz].row;
39: y = fd->M - row - fd->rstart;
40: x = (PetscReal)Jentry[nz++].col;
41: PetscDrawRectangle(draw,x,y,x+1,y+1,i+1,i+1,i+1,i+1);
42: }
43: }
44: return(0);
45: }
47: static PetscErrorCode MatFDColoringView_Draw(MatFDColoring fd,PetscViewer viewer)
48: {
50: PetscBool isnull;
51: PetscDraw draw;
52: PetscReal xr,yr,xl,yl,h,w;
55: PetscViewerDrawGetDraw(viewer,0,&draw);
56: PetscDrawIsNull(draw,&isnull);
57: if (isnull) return(0);
59: xr = fd->N; yr = fd->M; h = yr/10.0; w = xr/10.0;
60: xr += w; yr += h; xl = -w; yl = -h;
61: PetscDrawSetCoordinates(draw,xl,yl,xr,yr);
62: PetscObjectCompose((PetscObject)fd,"Zoomviewer",(PetscObject)viewer);
63: PetscDrawZoom(draw,MatFDColoringView_Draw_Zoom,fd);
64: PetscObjectCompose((PetscObject)fd,"Zoomviewer",NULL);
65: PetscDrawSave(draw);
66: return(0);
67: }
69: /*@C
70: MatFDColoringView - Views a finite difference coloring context.
72: Collective on MatFDColoring
74: Input Parameters:
75: + c - the coloring context
76: - viewer - visualization context
78: Level: intermediate
80: Notes:
81: The available visualization contexts include
82: + PETSC_VIEWER_STDOUT_SELF - standard output (default)
83: . PETSC_VIEWER_STDOUT_WORLD - synchronized standard
84: output where only the first processor opens
85: the file. All other processors send their
86: data to the first processor to print.
87: - PETSC_VIEWER_DRAW_WORLD - graphical display of nonzero structure
89: Notes:
90: Since PETSc uses only a small number of basic colors (currently 33), if the coloring
91: involves more than 33 then some seemingly identical colors are displayed making it look
92: like an illegal coloring. This is just a graphical artifact.
94: .seealso: MatFDColoringCreate()
96: .keywords: Mat, finite differences, coloring, view
97: @*/
98: PetscErrorCode MatFDColoringView(MatFDColoring c,PetscViewer viewer)
99: {
100: PetscErrorCode ierr;
101: PetscInt i,j;
102: PetscBool isdraw,iascii;
103: PetscViewerFormat format;
107: if (!viewer) {
108: PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)c),&viewer);
109: }
113: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);
114: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
115: if (isdraw) {
116: MatFDColoringView_Draw(c,viewer);
117: } else if (iascii) {
118: PetscObjectPrintClassNamePrefixType((PetscObject)c,viewer);
119: PetscViewerASCIIPrintf(viewer," Error tolerance=%g\n",(double)c->error_rel);
120: PetscViewerASCIIPrintf(viewer," Umin=%g\n",(double)c->umin);
121: PetscViewerASCIIPrintf(viewer," Number of colors=%D\n",c->ncolors);
123: PetscViewerGetFormat(viewer,&format);
124: if (format != PETSC_VIEWER_ASCII_INFO) {
125: PetscInt row,col,nz;
126: nz = 0;
127: for (i=0; i<c->ncolors; i++) {
128: PetscViewerASCIIPrintf(viewer," Information for color %D\n",i);
129: PetscViewerASCIIPrintf(viewer," Number of columns %D\n",c->ncolumns[i]);
130: for (j=0; j<c->ncolumns[i]; j++) {
131: PetscViewerASCIIPrintf(viewer," %D\n",c->columns[i][j]);
132: }
133: PetscViewerASCIIPrintf(viewer," Number of rows %D\n",c->nrows[i]);
134: if (c->matentry) {
135: for (j=0; j<c->nrows[i]; j++) {
136: row = c->matentry[nz].row;
137: col = c->matentry[nz++].col;
138: PetscViewerASCIIPrintf(viewer," %D %D \n",row,col);
139: }
140: }
141: }
142: }
143: PetscViewerFlush(viewer);
144: }
145: return(0);
146: }
148: /*@
149: MatFDColoringSetParameters - Sets the parameters for the sparse approximation of
150: a Jacobian matrix using finite differences.
152: Logically Collective on MatFDColoring
154: The Jacobian is estimated with the differencing approximation
155: .vb
156: F'(u)_{:,i} = [F(u+h*dx_{i}) - F(u)]/h where
157: h = error_rel*u[i] if abs(u[i]) > umin
158: = +/- error_rel*umin otherwise, with +/- determined by the sign of u[i]
159: dx_{i} = (0, ... 1, .... 0)
160: .ve
162: Input Parameters:
163: + coloring - the coloring context
164: . error_rel - relative error
165: - umin - minimum allowable u-value magnitude
167: Level: advanced
169: .keywords: Mat, finite differences, coloring, set, parameters
171: .seealso: MatFDColoringCreate(), MatFDColoringSetFromOptions()
173: @*/
174: PetscErrorCode MatFDColoringSetParameters(MatFDColoring matfd,PetscReal error,PetscReal umin)
175: {
180: if (error != PETSC_DEFAULT) matfd->error_rel = error;
181: if (umin != PETSC_DEFAULT) matfd->umin = umin;
182: return(0);
183: }
185: /*@
186: MatFDColoringSetBlockSize - Sets block size for efficient inserting entries of Jacobian matrix.
188: Logically Collective on MatFDColoring
190: Input Parameters:
191: + coloring - the coloring context
192: . brows - number of rows in the block
193: - bcols - number of columns in the block
195: Level: intermediate
197: .keywords: Mat, coloring
199: .seealso: MatFDColoringCreate(), MatFDColoringSetFromOptions()
201: @*/
202: PetscErrorCode MatFDColoringSetBlockSize(MatFDColoring matfd,PetscInt brows,PetscInt bcols)
203: {
208: if (brows != PETSC_DEFAULT) matfd->brows = brows;
209: if (bcols != PETSC_DEFAULT) matfd->bcols = bcols;
210: return(0);
211: }
213: /*@
214: MatFDColoringSetUp - Sets up the internal data structures of matrix coloring context for the later use.
216: Collective on Mat
218: Input Parameters:
219: + mat - the matrix containing the nonzero structure of the Jacobian
220: . iscoloring - the coloring of the matrix; usually obtained with MatGetColoring() or DMCreateColoring()
221: - color - the matrix coloring context
223: Level: beginner
225: .keywords: MatFDColoring, setup
227: .seealso: MatFDColoringCreate(), MatFDColoringDestroy()
228: @*/
229: PetscErrorCode MatFDColoringSetUp(Mat mat,ISColoring iscoloring,MatFDColoring color)
230: {
236: if (color->setupcalled) return(0);
238: PetscLogEventBegin(MAT_FDColoringSetUp,mat,0,0,0);
239: if (mat->ops->fdcoloringsetup) {
240: (*mat->ops->fdcoloringsetup)(mat,iscoloring,color);
241: } else SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Code not yet written for matrix type %s",((PetscObject)mat)->type_name);
243: color->setupcalled = PETSC_TRUE;
244: PetscLogEventEnd(MAT_FDColoringSetUp,mat,0,0,0);
245: return(0);
246: }
248: /*@C
249: MatFDColoringGetFunction - Gets the function to use for computing the Jacobian.
251: Not Collective
253: Input Parameters:
254: . coloring - the coloring context
256: Output Parameters:
257: + f - the function
258: - fctx - the optional user-defined function context
260: Level: intermediate
262: .keywords: Mat, Jacobian, finite differences, set, function
264: .seealso: MatFDColoringCreate(), MatFDColoringSetFunction(), MatFDColoringSetFromOptions()
266: @*/
267: PetscErrorCode MatFDColoringGetFunction(MatFDColoring matfd,PetscErrorCode (**f)(void),void **fctx)
268: {
271: if (f) *f = matfd->f;
272: if (fctx) *fctx = matfd->fctx;
273: return(0);
274: }
276: /*@C
277: MatFDColoringSetFunction - Sets the function to use for computing the Jacobian.
279: Logically Collective on MatFDColoring
281: Input Parameters:
282: + coloring - the coloring context
283: . f - the function
284: - fctx - the optional user-defined function context
286: Calling sequence of (*f) function:
287: For SNES: PetscErrorCode (*f)(SNES,Vec,Vec,void*)
288: If not using SNES: PetscErrorCode (*f)(void *dummy,Vec,Vec,void*) and dummy is ignored
290: Level: advanced
292: Notes: This function is usually used automatically by SNES (when one uses SNESSetJacobian() with the argument
293: SNESComputeJacobianDefaultColor()) and only needs to be used by someone computing a matrix via coloring directly by
294: calling MatFDColoringApply()
296: Fortran Notes:
297: In Fortran you must call MatFDColoringSetFunction() for a coloring object to
298: be used without SNES or within the SNES solvers.
300: .keywords: Mat, Jacobian, finite differences, set, function
302: .seealso: MatFDColoringCreate(), MatFDColoringGetFunction(), MatFDColoringSetFromOptions()
304: @*/
305: PetscErrorCode MatFDColoringSetFunction(MatFDColoring matfd,PetscErrorCode (*f)(void),void *fctx)
306: {
309: matfd->f = f;
310: matfd->fctx = fctx;
311: return(0);
312: }
314: /*@
315: MatFDColoringSetFromOptions - Sets coloring finite difference parameters from
316: the options database.
318: Collective on MatFDColoring
320: The Jacobian, F'(u), is estimated with the differencing approximation
321: .vb
322: F'(u)_{:,i} = [F(u+h*dx_{i}) - F(u)]/h where
323: h = error_rel*u[i] if abs(u[i]) > umin
324: = +/- error_rel*umin otherwise, with +/- determined by the sign of u[i]
325: dx_{i} = (0, ... 1, .... 0)
326: .ve
328: Input Parameter:
329: . coloring - the coloring context
331: Options Database Keys:
332: + -mat_fd_coloring_err <err> - Sets <err> (square root of relative error in the function)
333: . -mat_fd_coloring_umin <umin> - Sets umin, the minimum allowable u-value magnitude
334: . -mat_fd_type - "wp" or "ds" (see MATMFFD_WP or MATMFFD_DS)
335: . -mat_fd_coloring_view - Activates basic viewing
336: . -mat_fd_coloring_view ::ascii_info - Activates viewing info
337: - -mat_fd_coloring_view draw - Activates drawing
339: Level: intermediate
341: .keywords: Mat, finite differences, parameters
343: .seealso: MatFDColoringCreate(), MatFDColoringView(), MatFDColoringSetParameters()
345: @*/
346: PetscErrorCode MatFDColoringSetFromOptions(MatFDColoring matfd)
347: {
349: PetscBool flg;
350: char value[3];
355: PetscObjectOptionsBegin((PetscObject)matfd);
356: PetscOptionsReal("-mat_fd_coloring_err","Square root of relative error in function","MatFDColoringSetParameters",matfd->error_rel,&matfd->error_rel,0);
357: PetscOptionsReal("-mat_fd_coloring_umin","Minimum allowable u magnitude","MatFDColoringSetParameters",matfd->umin,&matfd->umin,0);
358: PetscOptionsString("-mat_fd_type","Algorithm to compute h, wp or ds","MatFDColoringCreate",matfd->htype,value,3,&flg);
359: if (flg) {
360: if (value[0] == 'w' && value[1] == 'p') matfd->htype = "wp";
361: else if (value[0] == 'd' && value[1] == 's') matfd->htype = "ds";
362: else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown finite differencing type %s",value);
363: }
364: PetscOptionsInt("-mat_fd_coloring_brows","Number of block rows","MatFDColoringSetBlockSize",matfd->brows,&matfd->brows,NULL);
365: PetscOptionsInt("-mat_fd_coloring_bcols","Number of block columns","MatFDColoringSetBlockSize",matfd->bcols,&matfd->bcols,&flg);
366: if (flg && matfd->bcols > matfd->ncolors) {
367: /* input bcols cannot be > matfd->ncolors, thus set it as ncolors */
368: matfd->bcols = matfd->ncolors;
369: }
371: /* process any options handlers added with PetscObjectAddOptionsHandler() */
372: PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject)matfd);
373: PetscOptionsEnd();
374: return(0);
375: }
377: /*@C
378: MatFDColoringSetType - Sets the approach for computing the finite difference parameter
380: Collective on MatFDColoring
382: Input Parameters:
383: + coloring - the coloring context
384: - type - either MATMFFD_WP or MATMFFD_DS
386: Options Database Keys:
387: . -mat_fd_type - "wp" or "ds"
389: Note: It is goofy that the argument type is MatMFFDType since the MatFDColoring actually computes the matrix entries
390: but the process of computing the entries is the same as as with the MatMFFD operation so we should reuse the names instead of
391: introducing another one.
393: Level: intermediate
395: .keywords: Mat, finite differences, parameters
397: .seealso: MatFDColoringCreate(), MatFDColoringView(), MatFDColoringSetParameters()
399: @*/
400: PetscErrorCode MatFDColoringSetType(MatFDColoring matfd,MatMFFDType type)
401: {
404: /*
405: It is goofy to handle the strings this way but currently there is no code to free a dynamically created matfd->htype
406: and this function is being provided as patch for a release so it shouldn't change the implementaton
407: */
408: if (type[0] == 'w' && type[1] == 'p') matfd->htype = "wp";
409: else if (type[0] == 'd' && type[1] == 's') matfd->htype = "ds";
410: else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown finite differencing type %s",type);
411: return(0);
412: }
414: PetscErrorCode MatFDColoringViewFromOptions(MatFDColoring fd,const char prefix[],const char optionname[])
415: {
416: PetscErrorCode ierr;
417: PetscBool flg;
418: PetscViewer viewer;
419: PetscViewerFormat format;
422: if (prefix) {
423: PetscOptionsGetViewer(PetscObjectComm((PetscObject)fd),prefix,optionname,&viewer,&format,&flg);
424: } else {
425: PetscOptionsGetViewer(PetscObjectComm((PetscObject)fd),((PetscObject)fd)->prefix,optionname,&viewer,&format,&flg);
426: }
427: if (flg) {
428: PetscViewerPushFormat(viewer,format);
429: MatFDColoringView(fd,viewer);
430: PetscViewerPopFormat(viewer);
431: PetscViewerDestroy(&viewer);
432: }
433: return(0);
434: }
436: /*@
437: MatFDColoringCreate - Creates a matrix coloring context for finite difference
438: computation of Jacobians.
440: Collective on Mat
442: Input Parameters:
443: + mat - the matrix containing the nonzero structure of the Jacobian
444: - iscoloring - the coloring of the matrix; usually obtained with MatColoringCreate() or DMCreateColoring()
446: Output Parameter:
447: . color - the new coloring context
449: Level: intermediate
451: .seealso: MatFDColoringDestroy(),SNESComputeJacobianDefaultColor(), ISColoringCreate(),
452: MatFDColoringSetFunction(), MatFDColoringSetFromOptions(), MatFDColoringApply(),
453: MatFDColoringView(), MatFDColoringSetParameters(), MatColoringCreate(), DMCreateColoring()
454: @*/
455: PetscErrorCode MatFDColoringCreate(Mat mat,ISColoring iscoloring,MatFDColoring *color)
456: {
457: MatFDColoring c;
458: MPI_Comm comm;
460: PetscInt M,N;
464: if (!mat->assembled) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"Matrix must be assembled by calls to MatAssemblyBegin/End();");
465: PetscLogEventBegin(MAT_FDColoringCreate,mat,0,0,0);
466: MatGetSize(mat,&M,&N);
467: if (M != N) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Only for square matrices");
468: PetscObjectGetComm((PetscObject)mat,&comm);
469: PetscHeaderCreate(c,MAT_FDCOLORING_CLASSID,"MatFDColoring","Jacobian computation via finite differences with coloring","Mat",comm,MatFDColoringDestroy,MatFDColoringView);
471: c->ctype = iscoloring->ctype;
473: if (mat->ops->fdcoloringcreate) {
474: (*mat->ops->fdcoloringcreate)(mat,iscoloring,c);
475: } else SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Code not yet written for matrix type %s",((PetscObject)mat)->type_name);
477: MatCreateVecs(mat,NULL,&c->w1);
478: PetscLogObjectParent((PetscObject)c,(PetscObject)c->w1);
479: VecDuplicate(c->w1,&c->w2);
480: PetscLogObjectParent((PetscObject)c,(PetscObject)c->w2);
482: c->error_rel = PETSC_SQRT_MACHINE_EPSILON;
483: c->umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
484: c->currentcolor = -1;
485: c->htype = "wp";
486: c->fset = PETSC_FALSE;
487: c->setupcalled = PETSC_FALSE;
489: *color = c;
490: PetscObjectCompose((PetscObject)mat,"SNESMatFDColoring",(PetscObject)c);
491: PetscLogEventEnd(MAT_FDColoringCreate,mat,0,0,0);
492: return(0);
493: }
495: /*@
496: MatFDColoringDestroy - Destroys a matrix coloring context that was created
497: via MatFDColoringCreate().
499: Collective on MatFDColoring
501: Input Parameter:
502: . c - coloring context
504: Level: intermediate
506: .seealso: MatFDColoringCreate()
507: @*/
508: PetscErrorCode MatFDColoringDestroy(MatFDColoring *c)
509: {
511: PetscInt i;
512: MatFDColoring color = *c;
515: if (!*c) return(0);
516: if (--((PetscObject)color)->refct > 0) {*c = 0; return(0);}
518: for (i=0; i<color->ncolors; i++) {
519: PetscFree(color->columns[i]);
520: }
521: PetscFree(color->ncolumns);
522: PetscFree(color->columns);
523: PetscFree(color->nrows);
524: if (color->htype[0] == 'w') {
525: PetscFree(color->matentry2);
526: } else {
527: PetscFree(color->matentry);
528: }
529: PetscFree(color->dy);
530: if (color->vscale) {VecDestroy(&color->vscale);}
531: VecDestroy(&color->w1);
532: VecDestroy(&color->w2);
533: VecDestroy(&color->w3);
534: PetscHeaderDestroy(c);
535: return(0);
536: }
538: /*@C
539: MatFDColoringGetPerturbedColumns - Returns the indices of the columns that
540: that are currently being perturbed.
542: Not Collective
544: Input Parameters:
545: . coloring - coloring context created with MatFDColoringCreate()
547: Output Parameters:
548: + n - the number of local columns being perturbed
549: - cols - the column indices, in global numbering
551: Level: intermediate
553: Fortran Note:
554: This routine has a different interface for Fortran
555: $ use petscisdef
556: $ PetscInt, pointer :: array(:)
557: $ PetscErrorCode ierr
558: $ MatFDColoring i
559: $ call MatFDColoringGetPerturbedColumnsF90(i,array,ierr)
560: $ use the entries of array ...
561: $ call MatFDColoringRestorePerturbedColumnsF90(i,array,ierr)
563: .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView(), MatFDColoringApply()
565: .keywords: coloring, Jacobian, finite differences
566: @*/
567: PetscErrorCode MatFDColoringGetPerturbedColumns(MatFDColoring coloring,PetscInt *n,const PetscInt *cols[])
568: {
570: if (coloring->currentcolor >= 0) {
571: *n = coloring->ncolumns[coloring->currentcolor];
572: *cols = coloring->columns[coloring->currentcolor];
573: } else {
574: *n = 0;
575: }
576: return(0);
577: }
579: /*@
580: MatFDColoringApply - Given a matrix for which a MatFDColoring context
581: has been created, computes the Jacobian for a function via finite differences.
583: Collective on MatFDColoring
585: Input Parameters:
586: + mat - location to store Jacobian
587: . coloring - coloring context created with MatFDColoringCreate()
588: . x1 - location at which Jacobian is to be computed
589: - sctx - context required by function, if this is being used with the SNES solver then it is SNES object, otherwise it is null
591: Options Database Keys:
592: + -mat_fd_type - "wp" or "ds" (see MATMFFD_WP or MATMFFD_DS)
593: . -mat_fd_coloring_view - Activates basic viewing or coloring
594: . -mat_fd_coloring_view draw - Activates drawing of coloring
595: - -mat_fd_coloring_view ::ascii_info - Activates viewing of coloring info
597: Level: intermediate
599: .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView(), MatFDColoringSetFunction()
601: .keywords: coloring, Jacobian, finite differences
602: @*/
603: PetscErrorCode MatFDColoringApply(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
604: {
606: PetscBool flg = PETSC_FALSE;
612: if (!coloring->f) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_WRONGSTATE,"Must call MatFDColoringSetFunction()");
613: if (!J->ops->fdcoloringapply) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not supported for this matrix type %s",((PetscObject)J)->type_name);
614: if (!coloring->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call MatFDColoringSetUp()");
616: MatSetUnfactored(J);
617: PetscOptionsGetBool(((PetscObject)coloring)->options,NULL,"-mat_fd_coloring_dont_rezero",&flg,NULL);
618: if (flg) {
619: PetscInfo(coloring,"Not calling MatZeroEntries()\n");
620: } else {
621: PetscBool assembled;
622: MatAssembled(J,&assembled);
623: if (assembled) {
624: MatZeroEntries(J);
625: }
626: }
628: PetscLogEventBegin(MAT_FDColoringApply,coloring,J,x1,0);
629: (*J->ops->fdcoloringapply)(J,coloring,x1,sctx);
630: PetscLogEventEnd(MAT_FDColoringApply,coloring,J,x1,0);
631: if (!coloring->viewed) {
632: MatFDColoringViewFromOptions(coloring,NULL,"-mat_fd_coloring_view");
633: coloring->viewed = PETSC_TRUE;
634: }
635: return(0);
636: }