Actual source code: fdmatrix.c
petsc-3.9.4 2018-09-11
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: htype = 'ds':
158: h = error_rel*u[i] if abs(u[i]) > umin
159: = +/- error_rel*umin otherwise, with +/- determined by the sign of u[i]
160: dx_{i} = (0, ... 1, .... 0)
162: htype = 'wp':
163: h = error_rel * sqrt(1 + ||u||)
164: .ve
166: Input Parameters:
167: + coloring - the coloring context
168: . error_rel - relative error
169: - umin - minimum allowable u-value magnitude
171: Level: advanced
173: .keywords: Mat, finite differences, coloring, set, parameters
175: .seealso: MatFDColoringCreate(), MatFDColoringSetFromOptions()
177: @*/
178: PetscErrorCode MatFDColoringSetParameters(MatFDColoring matfd,PetscReal error,PetscReal umin)
179: {
184: if (error != PETSC_DEFAULT) matfd->error_rel = error;
185: if (umin != PETSC_DEFAULT) matfd->umin = umin;
186: return(0);
187: }
189: /*@
190: MatFDColoringSetBlockSize - Sets block size for efficient inserting entries of Jacobian matrix.
192: Logically Collective on MatFDColoring
194: Input Parameters:
195: + coloring - the coloring context
196: . brows - number of rows in the block
197: - bcols - number of columns in the block
199: Level: intermediate
201: .keywords: Mat, coloring
203: .seealso: MatFDColoringCreate(), MatFDColoringSetFromOptions()
205: @*/
206: PetscErrorCode MatFDColoringSetBlockSize(MatFDColoring matfd,PetscInt brows,PetscInt bcols)
207: {
212: if (brows != PETSC_DEFAULT) matfd->brows = brows;
213: if (bcols != PETSC_DEFAULT) matfd->bcols = bcols;
214: return(0);
215: }
217: /*@
218: MatFDColoringSetUp - Sets up the internal data structures of matrix coloring context for the later use.
220: Collective on Mat
222: Input Parameters:
223: + mat - the matrix containing the nonzero structure of the Jacobian
224: . iscoloring - the coloring of the matrix; usually obtained with MatGetColoring() or DMCreateColoring()
225: - color - the matrix coloring context
227: Level: beginner
229: .keywords: MatFDColoring, setup
231: .seealso: MatFDColoringCreate(), MatFDColoringDestroy()
232: @*/
233: PetscErrorCode MatFDColoringSetUp(Mat mat,ISColoring iscoloring,MatFDColoring color)
234: {
240: if (color->setupcalled) return(0);
242: PetscLogEventBegin(MAT_FDColoringSetUp,mat,0,0,0);
243: if (mat->ops->fdcoloringsetup) {
244: (*mat->ops->fdcoloringsetup)(mat,iscoloring,color);
245: } else SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Code not yet written for matrix type %s",((PetscObject)mat)->type_name);
247: color->setupcalled = PETSC_TRUE;
248: PetscLogEventEnd(MAT_FDColoringSetUp,mat,0,0,0);
249: return(0);
250: }
252: /*@C
253: MatFDColoringGetFunction - Gets the function to use for computing the Jacobian.
255: Not Collective
257: Input Parameters:
258: . coloring - the coloring context
260: Output Parameters:
261: + f - the function
262: - fctx - the optional user-defined function context
264: Level: intermediate
266: .keywords: Mat, Jacobian, finite differences, set, function
268: .seealso: MatFDColoringCreate(), MatFDColoringSetFunction(), MatFDColoringSetFromOptions()
270: @*/
271: PetscErrorCode MatFDColoringGetFunction(MatFDColoring matfd,PetscErrorCode (**f)(void),void **fctx)
272: {
275: if (f) *f = matfd->f;
276: if (fctx) *fctx = matfd->fctx;
277: return(0);
278: }
280: /*@C
281: MatFDColoringSetFunction - Sets the function to use for computing the Jacobian.
283: Logically Collective on MatFDColoring
285: Input Parameters:
286: + coloring - the coloring context
287: . f - the function
288: - fctx - the optional user-defined function context
290: Calling sequence of (*f) function:
291: For SNES: PetscErrorCode (*f)(SNES,Vec,Vec,void*)
292: If not using SNES: PetscErrorCode (*f)(void *dummy,Vec,Vec,void*) and dummy is ignored
294: Level: advanced
296: Notes: This function is usually used automatically by SNES (when one uses SNESSetJacobian() with the argument
297: SNESComputeJacobianDefaultColor()) and only needs to be used by someone computing a matrix via coloring directly by
298: calling MatFDColoringApply()
300: Fortran Notes:
301: In Fortran you must call MatFDColoringSetFunction() for a coloring object to
302: be used without SNES or within the SNES solvers.
304: .keywords: Mat, Jacobian, finite differences, set, function
306: .seealso: MatFDColoringCreate(), MatFDColoringGetFunction(), MatFDColoringSetFromOptions()
308: @*/
309: PetscErrorCode MatFDColoringSetFunction(MatFDColoring matfd,PetscErrorCode (*f)(void),void *fctx)
310: {
313: matfd->f = f;
314: matfd->fctx = fctx;
315: return(0);
316: }
318: /*@
319: MatFDColoringSetFromOptions - Sets coloring finite difference parameters from
320: the options database.
322: Collective on MatFDColoring
324: The Jacobian, F'(u), is estimated with the differencing approximation
325: .vb
326: F'(u)_{:,i} = [F(u+h*dx_{i}) - F(u)]/h where
327: h = error_rel*u[i] if abs(u[i]) > umin
328: = +/- error_rel*umin otherwise, with +/- determined by the sign of u[i]
329: dx_{i} = (0, ... 1, .... 0)
330: .ve
332: Input Parameter:
333: . coloring - the coloring context
335: Options Database Keys:
336: + -mat_fd_coloring_err <err> - Sets <err> (square root of relative error in the function)
337: . -mat_fd_coloring_umin <umin> - Sets umin, the minimum allowable u-value magnitude
338: . -mat_fd_type - "wp" or "ds" (see MATMFFD_WP or MATMFFD_DS)
339: . -mat_fd_coloring_view - Activates basic viewing
340: . -mat_fd_coloring_view ::ascii_info - Activates viewing info
341: - -mat_fd_coloring_view draw - Activates drawing
343: Level: intermediate
345: .keywords: Mat, finite differences, parameters
347: .seealso: MatFDColoringCreate(), MatFDColoringView(), MatFDColoringSetParameters()
349: @*/
350: PetscErrorCode MatFDColoringSetFromOptions(MatFDColoring matfd)
351: {
353: PetscBool flg;
354: char value[3];
359: PetscObjectOptionsBegin((PetscObject)matfd);
360: PetscOptionsReal("-mat_fd_coloring_err","Square root of relative error in function","MatFDColoringSetParameters",matfd->error_rel,&matfd->error_rel,0);
361: PetscOptionsReal("-mat_fd_coloring_umin","Minimum allowable u magnitude","MatFDColoringSetParameters",matfd->umin,&matfd->umin,0);
362: PetscOptionsString("-mat_fd_type","Algorithm to compute h, wp or ds","MatFDColoringCreate",matfd->htype,value,3,&flg);
363: if (flg) {
364: if (value[0] == 'w' && value[1] == 'p') matfd->htype = "wp";
365: else if (value[0] == 'd' && value[1] == 's') matfd->htype = "ds";
366: else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown finite differencing type %s",value);
367: }
368: PetscOptionsInt("-mat_fd_coloring_brows","Number of block rows","MatFDColoringSetBlockSize",matfd->brows,&matfd->brows,NULL);
369: PetscOptionsInt("-mat_fd_coloring_bcols","Number of block columns","MatFDColoringSetBlockSize",matfd->bcols,&matfd->bcols,&flg);
370: if (flg && matfd->bcols > matfd->ncolors) {
371: /* input bcols cannot be > matfd->ncolors, thus set it as ncolors */
372: matfd->bcols = matfd->ncolors;
373: }
375: /* process any options handlers added with PetscObjectAddOptionsHandler() */
376: PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject)matfd);
377: PetscOptionsEnd();
378: return(0);
379: }
381: /*@C
382: MatFDColoringSetType - Sets the approach for computing the finite difference parameter
384: Collective on MatFDColoring
386: Input Parameters:
387: + coloring - the coloring context
388: - type - either MATMFFD_WP or MATMFFD_DS
390: Options Database Keys:
391: . -mat_fd_type - "wp" or "ds"
393: Note: It is goofy that the argument type is MatMFFDType since the MatFDColoring actually computes the matrix entries
394: but the process of computing the entries is the same as as with the MatMFFD operation so we should reuse the names instead of
395: introducing another one.
397: Level: intermediate
399: .keywords: Mat, finite differences, parameters
401: .seealso: MatFDColoringCreate(), MatFDColoringView(), MatFDColoringSetParameters()
403: @*/
404: PetscErrorCode MatFDColoringSetType(MatFDColoring matfd,MatMFFDType type)
405: {
408: /*
409: It is goofy to handle the strings this way but currently there is no code to free a dynamically created matfd->htype
410: and this function is being provided as patch for a release so it shouldn't change the implementaton
411: */
412: if (type[0] == 'w' && type[1] == 'p') matfd->htype = "wp";
413: else if (type[0] == 'd' && type[1] == 's') matfd->htype = "ds";
414: else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown finite differencing type %s",type);
415: return(0);
416: }
418: PetscErrorCode MatFDColoringViewFromOptions(MatFDColoring fd,const char prefix[],const char optionname[])
419: {
420: PetscErrorCode ierr;
421: PetscBool flg;
422: PetscViewer viewer;
423: PetscViewerFormat format;
426: if (prefix) {
427: PetscOptionsGetViewer(PetscObjectComm((PetscObject)fd),prefix,optionname,&viewer,&format,&flg);
428: } else {
429: PetscOptionsGetViewer(PetscObjectComm((PetscObject)fd),((PetscObject)fd)->prefix,optionname,&viewer,&format,&flg);
430: }
431: if (flg) {
432: PetscViewerPushFormat(viewer,format);
433: MatFDColoringView(fd,viewer);
434: PetscViewerPopFormat(viewer);
435: PetscViewerDestroy(&viewer);
436: }
437: return(0);
438: }
440: /*@
441: MatFDColoringCreate - Creates a matrix coloring context for finite difference
442: computation of Jacobians.
444: Collective on Mat
446: Input Parameters:
447: + mat - the matrix containing the nonzero structure of the Jacobian
448: - iscoloring - the coloring of the matrix; usually obtained with MatColoringCreate() or DMCreateColoring()
450: Output Parameter:
451: . color - the new coloring context
453: Level: intermediate
455: .seealso: MatFDColoringDestroy(),SNESComputeJacobianDefaultColor(), ISColoringCreate(),
456: MatFDColoringSetFunction(), MatFDColoringSetFromOptions(), MatFDColoringApply(),
457: MatFDColoringView(), MatFDColoringSetParameters(), MatColoringCreate(), DMCreateColoring()
458: @*/
459: PetscErrorCode MatFDColoringCreate(Mat mat,ISColoring iscoloring,MatFDColoring *color)
460: {
461: MatFDColoring c;
462: MPI_Comm comm;
464: PetscInt M,N;
468: if (!mat->assembled) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"Matrix must be assembled by calls to MatAssemblyBegin/End();");
469: PetscLogEventBegin(MAT_FDColoringCreate,mat,0,0,0);
470: MatGetSize(mat,&M,&N);
471: if (M != N) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Only for square matrices");
472: PetscObjectGetComm((PetscObject)mat,&comm);
473: PetscHeaderCreate(c,MAT_FDCOLORING_CLASSID,"MatFDColoring","Jacobian computation via finite differences with coloring","Mat",comm,MatFDColoringDestroy,MatFDColoringView);
475: c->ctype = iscoloring->ctype;
477: if (mat->ops->fdcoloringcreate) {
478: (*mat->ops->fdcoloringcreate)(mat,iscoloring,c);
479: } else SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Code not yet written for matrix type %s",((PetscObject)mat)->type_name);
481: MatCreateVecs(mat,NULL,&c->w1);
482: PetscLogObjectParent((PetscObject)c,(PetscObject)c->w1);
483: VecDuplicate(c->w1,&c->w2);
484: PetscLogObjectParent((PetscObject)c,(PetscObject)c->w2);
486: c->error_rel = PETSC_SQRT_MACHINE_EPSILON;
487: c->umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
488: c->currentcolor = -1;
489: c->htype = "wp";
490: c->fset = PETSC_FALSE;
491: c->setupcalled = PETSC_FALSE;
493: *color = c;
494: PetscObjectCompose((PetscObject)mat,"SNESMatFDColoring",(PetscObject)c);
495: PetscLogEventEnd(MAT_FDColoringCreate,mat,0,0,0);
496: return(0);
497: }
499: /*@
500: MatFDColoringDestroy - Destroys a matrix coloring context that was created
501: via MatFDColoringCreate().
503: Collective on MatFDColoring
505: Input Parameter:
506: . c - coloring context
508: Level: intermediate
510: .seealso: MatFDColoringCreate()
511: @*/
512: PetscErrorCode MatFDColoringDestroy(MatFDColoring *c)
513: {
515: PetscInt i;
516: MatFDColoring color = *c;
519: if (!*c) return(0);
520: if (--((PetscObject)color)->refct > 0) {*c = 0; return(0);}
522: for (i=0; i<color->ncolors; i++) {
523: PetscFree(color->columns[i]);
524: }
525: PetscFree(color->ncolumns);
526: PetscFree(color->columns);
527: PetscFree(color->nrows);
528: if (color->htype[0] == 'w') {
529: PetscFree(color->matentry2);
530: } else {
531: PetscFree(color->matentry);
532: }
533: PetscFree(color->dy);
534: if (color->vscale) {VecDestroy(&color->vscale);}
535: VecDestroy(&color->w1);
536: VecDestroy(&color->w2);
537: VecDestroy(&color->w3);
538: PetscHeaderDestroy(c);
539: return(0);
540: }
542: /*@C
543: MatFDColoringGetPerturbedColumns - Returns the indices of the columns that
544: that are currently being perturbed.
546: Not Collective
548: Input Parameters:
549: . coloring - coloring context created with MatFDColoringCreate()
551: Output Parameters:
552: + n - the number of local columns being perturbed
553: - cols - the column indices, in global numbering
555: Level: advanced
557: Fortran Note:
558: This routine has a different interface for Fortran
559: $ #include <petsc/finclude/petscmat.h>
560: $ use petscmat
561: $ PetscInt, pointer :: array(:)
562: $ PetscErrorCode ierr
563: $ MatFDColoring i
564: $ call MatFDColoringGetPerturbedColumnsF90(i,array,ierr)
565: $ use the entries of array ...
566: $ call MatFDColoringRestorePerturbedColumnsF90(i,array,ierr)
568: .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView(), MatFDColoringApply()
570: .keywords: coloring, Jacobian, finite differences
571: @*/
572: PetscErrorCode MatFDColoringGetPerturbedColumns(MatFDColoring coloring,PetscInt *n,const PetscInt *cols[])
573: {
575: if (coloring->currentcolor >= 0) {
576: *n = coloring->ncolumns[coloring->currentcolor];
577: *cols = coloring->columns[coloring->currentcolor];
578: } else {
579: *n = 0;
580: }
581: return(0);
582: }
584: /*@
585: MatFDColoringApply - Given a matrix for which a MatFDColoring context
586: has been created, computes the Jacobian for a function via finite differences.
588: Collective on MatFDColoring
590: Input Parameters:
591: + mat - location to store Jacobian
592: . coloring - coloring context created with MatFDColoringCreate()
593: . x1 - location at which Jacobian is to be computed
594: - sctx - context required by function, if this is being used with the SNES solver then it is SNES object, otherwise it is null
596: Options Database Keys:
597: + -mat_fd_type - "wp" or "ds" (see MATMFFD_WP or MATMFFD_DS)
598: . -mat_fd_coloring_view - Activates basic viewing or coloring
599: . -mat_fd_coloring_view draw - Activates drawing of coloring
600: - -mat_fd_coloring_view ::ascii_info - Activates viewing of coloring info
602: Level: intermediate
604: .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView(), MatFDColoringSetFunction()
606: .keywords: coloring, Jacobian, finite differences
607: @*/
608: PetscErrorCode MatFDColoringApply(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
609: {
611: PetscBool flg = PETSC_FALSE;
617: if (!coloring->f) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_WRONGSTATE,"Must call MatFDColoringSetFunction()");
618: if (!J->ops->fdcoloringapply) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not supported for this matrix type %s",((PetscObject)J)->type_name);
619: if (!coloring->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call MatFDColoringSetUp()");
621: MatSetUnfactored(J);
622: PetscOptionsGetBool(((PetscObject)coloring)->options,NULL,"-mat_fd_coloring_dont_rezero",&flg,NULL);
623: if (flg) {
624: PetscInfo(coloring,"Not calling MatZeroEntries()\n");
625: } else {
626: PetscBool assembled;
627: MatAssembled(J,&assembled);
628: if (assembled) {
629: MatZeroEntries(J);
630: }
631: }
633: PetscLogEventBegin(MAT_FDColoringApply,coloring,J,x1,0);
634: (*J->ops->fdcoloringapply)(J,coloring,x1,sctx);
635: PetscLogEventEnd(MAT_FDColoringApply,coloring,J,x1,0);
636: if (!coloring->viewed) {
637: MatFDColoringViewFromOptions(coloring,NULL,"-mat_fd_coloring_view");
638: coloring->viewed = PETSC_TRUE;
639: }
640: return(0);
641: }