Actual source code: fdmatrix.c
1: #define PETSCMAT_DLL
3: /*
4: This is where the abstract matrix operations are defined that are
5: used for finite difference computations of Jacobians using coloring.
6: */
8: #include src/mat/matimpl.h
10: /* Logging support */
11: PetscCookie PETSCMAT_DLLEXPORT MAT_FDCOLORING_COOKIE = 0;
15: PetscErrorCode PETSCMAT_DLLEXPORT MatFDColoringSetF(MatFDColoring fd,Vec F)
16: {
18: fd->F = F;
19: return(0);
20: }
24: static PetscErrorCode MatFDColoringView_Draw_Zoom(PetscDraw draw,void *Aa)
25: {
26: MatFDColoring fd = (MatFDColoring)Aa;
28: PetscInt i,j;
29: PetscReal x,y;
33: /* loop over colors */
34: for (i=0; i<fd->ncolors; i++) {
35: for (j=0; j<fd->nrows[i]; j++) {
36: y = fd->M - fd->rows[i][j] - fd->rstart;
37: x = fd->columnsforrow[i][j];
38: PetscDrawRectangle(draw,x,y,x+1,y+1,i+1,i+1,i+1,i+1);
39: }
40: }
41: return(0);
42: }
46: static PetscErrorCode MatFDColoringView_Draw(MatFDColoring fd,PetscViewer viewer)
47: {
49: PetscTruth isnull;
50: PetscDraw draw;
51: PetscReal xr,yr,xl,yl,h,w;
54: PetscViewerDrawGetDraw(viewer,0,&draw);
55: PetscDrawIsNull(draw,&isnull); if (isnull) return(0);
57: PetscObjectCompose((PetscObject)fd,"Zoomviewer",(PetscObject)viewer);
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: PetscDrawZoom(draw,MatFDColoringView_Draw_Zoom,fd);
63: PetscObjectCompose((PetscObject)fd,"Zoomviewer",PETSC_NULL);
64: return(0);
65: }
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 PETSCMAT_DLLEXPORT MatFDColoringView(MatFDColoring c,PetscViewer viewer)
99: {
100: PetscErrorCode ierr;
101: PetscInt i,j;
102: PetscTruth isdraw,iascii;
103: PetscViewerFormat format;
107: if (!viewer) viewer = PETSC_VIEWER_STDOUT_(c->comm);
111: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_DRAW,&isdraw);
112: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
113: if (isdraw) {
114: MatFDColoringView_Draw(c,viewer);
115: } else if (iascii) {
116: PetscViewerASCIIPrintf(viewer,"MatFDColoring Object:\n");
117: PetscViewerASCIIPrintf(viewer," Error tolerance=%G\n",c->error_rel);
118: PetscViewerASCIIPrintf(viewer," Umin=%G\n",c->umin);
119: PetscViewerASCIIPrintf(viewer," Number of colors=%D\n",c->ncolors);
121: PetscViewerGetFormat(viewer,&format);
122: if (format != PETSC_VIEWER_ASCII_INFO) {
123: for (i=0; i<c->ncolors; i++) {
124: PetscViewerASCIIPrintf(viewer," Information for color %D\n",i);
125: PetscViewerASCIIPrintf(viewer," Number of columns %D\n",c->ncolumns[i]);
126: for (j=0; j<c->ncolumns[i]; j++) {
127: PetscViewerASCIIPrintf(viewer," %D\n",c->columns[i][j]);
128: }
129: PetscViewerASCIIPrintf(viewer," Number of rows %D\n",c->nrows[i]);
130: for (j=0; j<c->nrows[i]; j++) {
131: PetscViewerASCIIPrintf(viewer," %D %D \n",c->rows[i][j],c->columnsforrow[i][j]);
132: }
133: }
134: }
135: PetscViewerFlush(viewer);
136: } else {
137: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for MatFDColoring",((PetscObject)viewer)->type_name);
138: }
139: return(0);
140: }
144: /*@
145: MatFDColoringSetParameters - Sets the parameters for the sparse approximation of
146: a Jacobian matrix using finite differences.
148: Collective on MatFDColoring
150: The Jacobian is estimated with the differencing approximation
151: .vb
152: F'(u)_{:,i} = [F(u+h*dx_{i}) - F(u)]/h where
153: h = error_rel*u[i] if abs(u[i]) > umin
154: = +/- error_rel*umin otherwise, with +/- determined by the sign of u[i]
155: dx_{i} = (0, ... 1, .... 0)
156: .ve
158: Input Parameters:
159: + coloring - the coloring context
160: . error_rel - relative error
161: - umin - minimum allowable u-value magnitude
163: Level: advanced
165: .keywords: Mat, finite differences, coloring, set, parameters
167: .seealso: MatFDColoringCreate()
168: @*/
169: PetscErrorCode PETSCMAT_DLLEXPORT MatFDColoringSetParameters(MatFDColoring matfd,PetscReal error,PetscReal umin)
170: {
174: if (error != PETSC_DEFAULT) matfd->error_rel = error;
175: if (umin != PETSC_DEFAULT) matfd->umin = umin;
176: return(0);
177: }
181: /*@
182: MatFDColoringSetFrequency - Sets the frequency for computing new Jacobian
183: matrices.
185: Collective on MatFDColoring
187: Input Parameters:
188: + coloring - the coloring context
189: - freq - frequency (default is 1)
191: Options Database Keys:
192: . -mat_fd_coloring_freq <freq> - Sets coloring frequency
194: Level: advanced
196: Notes:
197: Using a modified Newton strategy, where the Jacobian remains fixed for several
198: iterations, can be cost effective in terms of overall nonlinear solution
199: efficiency. This parameter indicates that a new Jacobian will be computed every
200: <freq> nonlinear iterations.
202: .keywords: Mat, finite differences, coloring, set, frequency
204: .seealso: MatFDColoringCreate(), MatFDColoringGetFrequency(), MatFDColoringSetRecompute()
205: @*/
206: PetscErrorCode PETSCMAT_DLLEXPORT MatFDColoringSetFrequency(MatFDColoring matfd,PetscInt freq)
207: {
211: matfd->freq = freq;
212: return(0);
213: }
217: /*@
218: MatFDColoringGetFrequency - Gets the frequency for computing new Jacobian
219: matrices.
221: Not Collective
223: Input Parameters:
224: . coloring - the coloring context
226: Output Parameters:
227: . freq - frequency (default is 1)
229: Options Database Keys:
230: . -mat_fd_coloring_freq <freq> - Sets coloring frequency
232: Level: advanced
234: Notes:
235: Using a modified Newton strategy, where the Jacobian remains fixed for several
236: iterations, can be cost effective in terms of overall nonlinear solution
237: efficiency. This parameter indicates that a new Jacobian will be computed every
238: <freq> nonlinear iterations.
240: .keywords: Mat, finite differences, coloring, get, frequency
242: .seealso: MatFDColoringSetFrequency()
243: @*/
244: PetscErrorCode PETSCMAT_DLLEXPORT MatFDColoringGetFrequency(MatFDColoring matfd,PetscInt *freq)
245: {
248: *freq = matfd->freq;
249: return(0);
250: }
254: /*@C
255: MatFDColoringGetFunction - Gets the function to use for computing the Jacobian.
257: Collective on MatFDColoring
259: Input Parameters:
260: . coloring - the coloring context
262: Output Parameters:
263: + f - the function
264: - fctx - the optional user-defined function context
266: Level: intermediate
268: .keywords: Mat, Jacobian, finite differences, set, function
269: @*/
270: PetscErrorCode PETSCMAT_DLLEXPORT MatFDColoringGetFunction(MatFDColoring matfd,PetscErrorCode (**f)(void),void **fctx)
271: {
274: if (f) *f = matfd->f;
275: if (fctx) *fctx = matfd->fctx;
276: return(0);
277: }
281: /*@C
282: MatFDColoringSetFunction - Sets the function to use for computing the Jacobian.
284: Collective on MatFDColoring
286: Input Parameters:
287: + coloring - the coloring context
288: . f - the function
289: - fctx - the optional user-defined function context
291: Level: intermediate
293: Notes:
294: In Fortran you must call MatFDColoringSetFunctionSNES() for a coloring object to
295: be used with the SNES solvers and MatFDColoringSetFunctionTS() if it is to be used
296: with the TS solvers.
298: .keywords: Mat, Jacobian, finite differences, set, function
299: @*/
300: PetscErrorCode PETSCMAT_DLLEXPORT MatFDColoringSetFunction(MatFDColoring matfd,PetscErrorCode (*f)(void),void *fctx)
301: {
304: matfd->f = f;
305: matfd->fctx = fctx;
306: return(0);
307: }
311: /*@
312: MatFDColoringSetFromOptions - Sets coloring finite difference parameters from
313: the options database.
315: Collective on MatFDColoring
317: The Jacobian, F'(u), is estimated with the differencing approximation
318: .vb
319: F'(u)_{:,i} = [F(u+h*dx_{i}) - F(u)]/h where
320: h = error_rel*u[i] if abs(u[i]) > umin
321: = +/- error_rel*umin otherwise, with +/- determined by the sign of u[i]
322: dx_{i} = (0, ... 1, .... 0)
323: .ve
325: Input Parameter:
326: . coloring - the coloring context
328: Options Database Keys:
329: + -mat_fd_coloring_err <err> - Sets <err> (square root
330: of relative error in the function)
331: . -mat_fd_coloring_umin <umin> - Sets umin, the minimum allowable u-value magnitude
332: . -mat_fd_coloring_freq <freq> - Sets frequency of computing a new Jacobian
333: . -mat_fd_type - "wp" or "ds" (see MATSNESMF_WP or MATSNESMF_DS)
334: . -mat_fd_coloring_view - Activates basic viewing
335: . -mat_fd_coloring_view_info - Activates viewing info
336: - -mat_fd_coloring_view_draw - Activates drawing
338: Level: intermediate
340: .keywords: Mat, finite differences, parameters
342: .seealso: MatFDColoringCreate(), MatFDColoringView(), MatFDColoringSetParameters()
344: @*/
345: PetscErrorCode PETSCMAT_DLLEXPORT MatFDColoringSetFromOptions(MatFDColoring matfd)
346: {
348: PetscTruth flg;
349: char value[3];
354: PetscOptionsBegin(matfd->comm,matfd->prefix,"Jacobian computation via finite differences option","MatFD");
355: PetscOptionsReal("-mat_fd_coloring_err","Square root of relative error in function","MatFDColoringSetParameters",matfd->error_rel,&matfd->error_rel,0);
356: PetscOptionsReal("-mat_fd_coloring_umin","Minimum allowable u magnitude","MatFDColoringSetParameters",matfd->umin,&matfd->umin,0);
357: PetscOptionsInt("-mat_fd_coloring_freq","How often Jacobian is recomputed","MatFDColoringSetFrequency",matfd->freq,&matfd->freq,0);
358: PetscOptionsString("-mat_fd_type","Algorithm to compute h, wp or ds","MatFDColoringCreate",matfd->htype,value,2,&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_ERR_ARG_OUTOFRANGE,"Unknown finite differencing type %s",value);
363: }
364: /* not used here; but so they are presented in the GUI */
365: PetscOptionsName("-mat_fd_coloring_view","Print entire datastructure used for Jacobian","None",0);
366: PetscOptionsName("-mat_fd_coloring_view_info","Print number of colors etc for Jacobian","None",0);
367: PetscOptionsName("-mat_fd_coloring_view_draw","Plot nonzero structure ofJacobian","None",0);
368: PetscOptionsEnd();
369: return(0);
370: }
374: PetscErrorCode MatFDColoringView_Private(MatFDColoring fd)
375: {
377: PetscTruth flg;
380: PetscOptionsHasName(PETSC_NULL,"-mat_fd_coloring_view",&flg);
381: if (flg) {
382: MatFDColoringView(fd,PETSC_VIEWER_STDOUT_(fd->comm));
383: }
384: PetscOptionsHasName(PETSC_NULL,"-mat_fd_coloring_view_info",&flg);
385: if (flg) {
386: PetscViewerPushFormat(PETSC_VIEWER_STDOUT_(fd->comm),PETSC_VIEWER_ASCII_INFO);
387: MatFDColoringView(fd,PETSC_VIEWER_STDOUT_(fd->comm));
388: PetscViewerPopFormat(PETSC_VIEWER_STDOUT_(fd->comm));
389: }
390: PetscOptionsHasName(PETSC_NULL,"-mat_fd_coloring_view_draw",&flg);
391: if (flg) {
392: MatFDColoringView(fd,PETSC_VIEWER_DRAW_(fd->comm));
393: PetscViewerFlush(PETSC_VIEWER_DRAW_(fd->comm));
394: }
395: return(0);
396: }
400: /*@
401: MatFDColoringCreate - Creates a matrix coloring context for finite difference
402: computation of Jacobians.
404: Collective on Mat
406: Input Parameters:
407: + mat - the matrix containing the nonzero structure of the Jacobian
408: - iscoloring - the coloring of the matrix
410: Output Parameter:
411: . color - the new coloring context
412:
413: Level: intermediate
415: .seealso: MatFDColoringDestroy(),SNESDefaultComputeJacobianColor(), ISColoringCreate(),
416: MatFDColoringSetFunction(), MatFDColoringSetFromOptions(), MatFDColoringApply(),
417: MatFDColoringSetFrequency(), MatFDColoringSetRecompute(), MatFDColoringView(),
418: MatFDColoringSetParameters()
419: @*/
420: PetscErrorCode PETSCMAT_DLLEXPORT MatFDColoringCreate(Mat mat,ISColoring iscoloring,MatFDColoring *color)
421: {
422: MatFDColoring c;
423: MPI_Comm comm;
425: PetscInt M,N;
428: PetscLogEventBegin(MAT_FDColoringCreate,mat,0,0,0);
429: MatGetSize(mat,&M,&N);
430: if (M != N) SETERRQ(PETSC_ERR_SUP,"Only for square matrices");
432: PetscObjectGetComm((PetscObject)mat,&comm);
433: PetscHeaderCreate(c,_p_MatFDColoring,int,MAT_FDCOLORING_COOKIE,0,"MatFDColoring",comm,MatFDColoringDestroy,MatFDColoringView);
435: if (mat->ops->fdcoloringcreate) {
436: (*mat->ops->fdcoloringcreate)(mat,iscoloring,c);
437: } else {
438: SETERRQ(PETSC_ERR_SUP,"Code not yet written for this matrix type");
439: }
441: c->error_rel = PETSC_SQRT_MACHINE_EPSILON;
442: c->umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
443: c->freq = 1;
444: c->usersetsrecompute = PETSC_FALSE;
445: c->recompute = PETSC_FALSE;
446: c->currentcolor = -1;
447: c->htype = "wp";
449: *color = c;
450: PetscLogEventEnd(MAT_FDColoringCreate,mat,0,0,0);
451: return(0);
452: }
456: /*@
457: MatFDColoringDestroy - Destroys a matrix coloring context that was created
458: via MatFDColoringCreate().
460: Collective on MatFDColoring
462: Input Parameter:
463: . c - coloring context
465: Level: intermediate
467: .seealso: MatFDColoringCreate()
468: @*/
469: PetscErrorCode PETSCMAT_DLLEXPORT MatFDColoringDestroy(MatFDColoring c)
470: {
472: PetscInt i;
475: if (--c->refct > 0) return(0);
477: for (i=0; i<c->ncolors; i++) {
478: PetscFree(c->columns[i]);
479: PetscFree(c->rows[i]);
480: PetscFree(c->columnsforrow[i]);
481: if (c->vscaleforrow) {PetscFree(c->vscaleforrow[i]);}
482: }
483: PetscFree(c->ncolumns);
484: PetscFree(c->columns);
485: PetscFree(c->nrows);
486: PetscFree(c->rows);
487: PetscFree(c->columnsforrow);
488: PetscFree(c->vscaleforrow);
489: if (c->vscale) {VecDestroy(c->vscale);}
490: if (c->w1) {
491: VecDestroy(c->w1);
492: VecDestroy(c->w2);
493: VecDestroy(c->w3);
494: }
495: PetscHeaderDestroy(c);
496: return(0);
497: }
501: /*@C
502: MatFDColoringGetPerturbedColumns - Returns the indices of the columns that
503: that are currently being perturbed.
505: Not Collective
507: Input Parameters:
508: . coloring - coloring context created with MatFDColoringCreate()
510: Output Parameters:
511: + n - the number of local columns being perturbed
512: - cols - the column indices, in global numbering
514: Level: intermediate
516: .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView(), MatFDColoringApply()
518: .keywords: coloring, Jacobian, finite differences
519: @*/
520: PetscErrorCode PETSCMAT_DLLEXPORT MatFDColoringGetPerturbedColumns(MatFDColoring coloring,PetscInt *n,PetscInt *cols[])
521: {
523: if (coloring->currentcolor >= 0) {
524: *n = coloring->ncolumns[coloring->currentcolor];
525: *cols = coloring->columns[coloring->currentcolor];
526: } else {
527: *n = 0;
528: }
529: return(0);
530: }
534: /*@
535: MatFDColoringApply - Given a matrix for which a MatFDColoring context
536: has been created, computes the Jacobian for a function via finite differences.
538: Collective on MatFDColoring
540: Input Parameters:
541: + mat - location to store Jacobian
542: . coloring - coloring context created with MatFDColoringCreate()
543: . x1 - location at which Jacobian is to be computed
544: - sctx - optional context required by function (actually a SNES context)
546: Options Database Keys:
547: + -mat_fd_coloring_freq <freq> - Sets coloring frequency
548: . -mat_fd_type - "wp" or "ds" (see MATSNESMF_WP or MATSNESMF_DS)
549: . -mat_fd_coloring_view - Activates basic viewing or coloring
550: . -mat_fd_coloring_view_draw - Activates drawing of coloring
551: - -mat_fd_coloring_view_info - Activates viewing of coloring info
553: Level: intermediate
555: .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView()
557: .keywords: coloring, Jacobian, finite differences
558: @*/
559: PetscErrorCode PETSCMAT_DLLEXPORT MatFDColoringApply(Mat J,MatFDColoring coloring,Vec x1,MatStructure *flag,void *sctx)
560: {
561: PetscErrorCode (*f)(void*,Vec,Vec,void*) = (PetscErrorCode (*)(void*,Vec,Vec,void *))coloring->f;
563: PetscInt k,N,start,end,l,row,col,srow,**vscaleforrow,m1,m2;
564: PetscScalar dx,*y,*xx,*w3_array;
565: PetscScalar *vscale_array;
566: PetscReal epsilon = coloring->error_rel,umin = coloring->umin,unorm;
567: Vec w1,w2,w3;
568: void *fctx = coloring->fctx;
569: PetscTruth flg;
577: if (coloring->usersetsrecompute) {
578: if (!coloring->recompute) {
579: *flag = SAME_PRECONDITIONER;
580: PetscInfo(J,"Skipping Jacobian, since user called MatFDColorSetRecompute()\n");
581: return(0);
582: } else {
583: coloring->recompute = PETSC_FALSE;
584: }
585: }
587: PetscLogEventBegin(MAT_FDColoringApply,coloring,J,x1,0);
588: if (J->ops->fdcoloringapply) {
589: (*J->ops->fdcoloringapply)(J,coloring,x1,flag,sctx);
590: } else {
592: if (!coloring->w1) {
593: VecDuplicate(x1,&coloring->w1);
594: PetscLogObjectParent(coloring,coloring->w1);
595: VecDuplicate(x1,&coloring->w2);
596: PetscLogObjectParent(coloring,coloring->w2);
597: VecDuplicate(x1,&coloring->w3);
598: PetscLogObjectParent(coloring,coloring->w3);
599: }
600: w1 = coloring->w1; w2 = coloring->w2; w3 = coloring->w3;
602: MatSetUnfactored(J);
603: PetscOptionsHasName(PETSC_NULL,"-mat_fd_coloring_dont_rezero",&flg);
604: if (flg) {
605: PetscInfo(coloring,"Not calling MatZeroEntries()\n");
606: } else {
607: PetscTruth assembled;
608: MatAssembled(J,&assembled);
609: if (assembled) {
610: MatZeroEntries(J);
611: }
612: }
614: VecGetOwnershipRange(x1,&start,&end);
615: VecGetSize(x1,&N);
616:
617: /*
618: This is a horrible, horrible, hack. See DMMGComputeJacobian_Multigrid() it inproperly sets
619: coloring->F for the coarser grids from the finest
620: */
621: if (coloring->F) {
622: VecGetLocalSize(coloring->F,&m1);
623: VecGetLocalSize(w1,&m2);
624: if (m1 != m2) {
625: coloring->F = 0;
626: }
627: }
629: if (coloring->F) {
630: w1 = coloring->F; /* use already computed value of function */
631: coloring->F = 0;
632: } else {
633: PetscLogEventBegin(MAT_FDColoringFunction,0,0,0,0);
634: (*f)(sctx,x1,w1,fctx);
635: PetscLogEventEnd(MAT_FDColoringFunction,0,0,0,0);
636: }
638: if (coloring->htype[0] == 'w') { /* tacky test; need to make systematic if we add other approaches to computing h*/
639: VecNorm(x1,NORM_2,&unorm);
640: }
642: /*
643: Compute all the scale factors and share with other processors
644: */
645: VecGetArray(x1,&xx);xx = xx - start;
646: VecGetArray(coloring->vscale,&vscale_array);vscale_array = vscale_array - start;
647: for (k=0; k<coloring->ncolors; k++) {
648: /*
649: Loop over each column associated with color adding the
650: perturbation to the vector w3.
651: */
652: for (l=0; l<coloring->ncolumns[k]; l++) {
653: col = coloring->columns[k][l]; /* column of the matrix we are probing for */
654: if (coloring->htype[0] == 'w') {
655: dx = 1.0 + unorm;
656: } else {
657: dx = xx[col];
658: }
659: if (dx == 0.0) dx = 1.0;
660: #if !defined(PETSC_USE_COMPLEX)
661: if (dx < umin && dx >= 0.0) dx = umin;
662: else if (dx < 0.0 && dx > -umin) dx = -umin;
663: #else
664: if (PetscAbsScalar(dx) < umin && PetscRealPart(dx) >= 0.0) dx = umin;
665: else if (PetscRealPart(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
666: #endif
667: dx *= epsilon;
668: vscale_array[col] = 1.0/dx;
669: }
670: }
671: vscale_array = vscale_array + start;
672: VecRestoreArray(coloring->vscale,&vscale_array);
673: VecGhostUpdateBegin(coloring->vscale,INSERT_VALUES,SCATTER_FORWARD);
674: VecGhostUpdateEnd(coloring->vscale,INSERT_VALUES,SCATTER_FORWARD);
676: /* VecView(coloring->vscale,PETSC_VIEWER_STDOUT_WORLD);
677: VecView(x1,PETSC_VIEWER_STDOUT_WORLD);*/
679: if (coloring->vscaleforrow) vscaleforrow = coloring->vscaleforrow;
680: else vscaleforrow = coloring->columnsforrow;
682: VecGetArray(coloring->vscale,&vscale_array);
683: /*
684: Loop over each color
685: */
686: for (k=0; k<coloring->ncolors; k++) {
687: coloring->currentcolor = k;
688: VecCopy(x1,w3);
689: VecGetArray(w3,&w3_array);w3_array = w3_array - start;
690: /*
691: Loop over each column associated with color adding the
692: perturbation to the vector w3.
693: */
694: for (l=0; l<coloring->ncolumns[k]; l++) {
695: col = coloring->columns[k][l]; /* column of the matrix we are probing for */
696: if (coloring->htype[0] == 'w') {
697: dx = 1.0 + unorm;
698: } else {
699: dx = xx[col];
700: }
701: if (dx == 0.0) dx = 1.0;
702: #if !defined(PETSC_USE_COMPLEX)
703: if (dx < umin && dx >= 0.0) dx = umin;
704: else if (dx < 0.0 && dx > -umin) dx = -umin;
705: #else
706: if (PetscAbsScalar(dx) < umin && PetscRealPart(dx) >= 0.0) dx = umin;
707: else if (PetscRealPart(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
708: #endif
709: dx *= epsilon;
710: if (!PetscAbsScalar(dx)) SETERRQ(PETSC_ERR_PLIB,"Computed 0 differencing parameter");
711: w3_array[col] += dx;
712: }
713: w3_array = w3_array + start; VecRestoreArray(w3,&w3_array);
715: /*
716: Evaluate function at x1 + dx (here dx is a vector of perturbations)
717: */
719: PetscLogEventBegin(MAT_FDColoringFunction,0,0,0,0);
720: (*f)(sctx,w3,w2,fctx);
721: PetscLogEventEnd(MAT_FDColoringFunction,0,0,0,0);
722: VecAXPY(w2,-1.0,w1);
724: /*
725: Loop over rows of vector, putting results into Jacobian matrix
726: */
727: VecGetArray(w2,&y);
728: for (l=0; l<coloring->nrows[k]; l++) {
729: row = coloring->rows[k][l];
730: col = coloring->columnsforrow[k][l];
731: y[row] *= vscale_array[vscaleforrow[k][l]];
732: srow = row + start;
733: MatSetValues(J,1,&srow,1,&col,y+row,INSERT_VALUES);
734: }
735: VecRestoreArray(w2,&y);
736: }
737: coloring->currentcolor = -1;
738: VecRestoreArray(coloring->vscale,&vscale_array);
739: xx = xx + start; VecRestoreArray(x1,&xx);
740: MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);
741: MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);
742: }
743: PetscLogEventEnd(MAT_FDColoringApply,coloring,J,x1,0);
745: PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test",&flg);
746: if (flg) {
747: MatNullSpaceTest(J->nullsp,J);
748: }
749: MatFDColoringView_Private(coloring);
751: return(0);
752: }
756: /*@
757: MatFDColoringApplyTS - Given a matrix for which a MatFDColoring context
758: has been created, computes the Jacobian for a function via finite differences.
760: Collective on Mat, MatFDColoring, and Vec
762: Input Parameters:
763: + mat - location to store Jacobian
764: . coloring - coloring context created with MatFDColoringCreate()
765: . x1 - location at which Jacobian is to be computed
766: - sctx - optional context required by function (actually a SNES context)
768: Options Database Keys:
769: . -mat_fd_coloring_freq <freq> - Sets coloring frequency
771: Level: intermediate
773: .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView()
775: .keywords: coloring, Jacobian, finite differences
776: @*/
777: PetscErrorCode PETSCMAT_DLLEXPORT MatFDColoringApplyTS(Mat J,MatFDColoring coloring,PetscReal t,Vec x1,MatStructure *flag,void *sctx)
778: {
779: PetscErrorCode (*f)(void*,PetscReal,Vec,Vec,void*)=(PetscErrorCode (*)(void*,PetscReal,Vec,Vec,void *))coloring->f;
781: PetscInt k,N,start,end,l,row,col,srow,**vscaleforrow;
782: PetscScalar dx,*y,*xx,*w3_array;
783: PetscScalar *vscale_array;
784: PetscReal epsilon = coloring->error_rel,umin = coloring->umin;
785: Vec w1,w2,w3;
786: void *fctx = coloring->fctx;
787: PetscTruth flg;
794: PetscLogEventBegin(MAT_FDColoringApply,coloring,J,x1,0);
795: if (!coloring->w1) {
796: VecDuplicate(x1,&coloring->w1);
797: PetscLogObjectParent(coloring,coloring->w1);
798: VecDuplicate(x1,&coloring->w2);
799: PetscLogObjectParent(coloring,coloring->w2);
800: VecDuplicate(x1,&coloring->w3);
801: PetscLogObjectParent(coloring,coloring->w3);
802: }
803: w1 = coloring->w1; w2 = coloring->w2; w3 = coloring->w3;
805: MatSetUnfactored(J);
806: PetscOptionsHasName(PETSC_NULL,"-mat_fd_coloring_dont_rezero",&flg);
807: if (flg) {
808: PetscInfo(coloring,"Not calling MatZeroEntries()\n");
809: } else {
810: PetscTruth assembled;
811: MatAssembled(J,&assembled);
812: if (assembled) {
813: MatZeroEntries(J);
814: }
815: }
817: VecGetOwnershipRange(x1,&start,&end);
818: VecGetSize(x1,&N);
819: PetscLogEventBegin(MAT_FDColoringFunction,0,0,0,0);
820: (*f)(sctx,t,x1,w1,fctx);
821: PetscLogEventEnd(MAT_FDColoringFunction,0,0,0,0);
823: /*
824: Compute all the scale factors and share with other processors
825: */
826: VecGetArray(x1,&xx);xx = xx - start;
827: VecGetArray(coloring->vscale,&vscale_array);vscale_array = vscale_array - start;
828: for (k=0; k<coloring->ncolors; k++) {
829: /*
830: Loop over each column associated with color adding the
831: perturbation to the vector w3.
832: */
833: for (l=0; l<coloring->ncolumns[k]; l++) {
834: col = coloring->columns[k][l]; /* column of the matrix we are probing for */
835: dx = xx[col];
836: if (dx == 0.0) dx = 1.0;
837: #if !defined(PETSC_USE_COMPLEX)
838: if (dx < umin && dx >= 0.0) dx = umin;
839: else if (dx < 0.0 && dx > -umin) dx = -umin;
840: #else
841: if (PetscAbsScalar(dx) < umin && PetscRealPart(dx) >= 0.0) dx = umin;
842: else if (PetscRealPart(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
843: #endif
844: dx *= epsilon;
845: vscale_array[col] = 1.0/dx;
846: }
847: }
848: vscale_array = vscale_array - start;VecRestoreArray(coloring->vscale,&vscale_array);
849: VecGhostUpdateBegin(coloring->vscale,INSERT_VALUES,SCATTER_FORWARD);
850: VecGhostUpdateEnd(coloring->vscale,INSERT_VALUES,SCATTER_FORWARD);
852: if (coloring->vscaleforrow) vscaleforrow = coloring->vscaleforrow;
853: else vscaleforrow = coloring->columnsforrow;
855: VecGetArray(coloring->vscale,&vscale_array);
856: /*
857: Loop over each color
858: */
859: for (k=0; k<coloring->ncolors; k++) {
860: VecCopy(x1,w3);
861: VecGetArray(w3,&w3_array);w3_array = w3_array - start;
862: /*
863: Loop over each column associated with color adding the
864: perturbation to the vector w3.
865: */
866: for (l=0; l<coloring->ncolumns[k]; l++) {
867: col = coloring->columns[k][l]; /* column of the matrix we are probing for */
868: dx = xx[col];
869: if (dx == 0.0) dx = 1.0;
870: #if !defined(PETSC_USE_COMPLEX)
871: if (dx < umin && dx >= 0.0) dx = umin;
872: else if (dx < 0.0 && dx > -umin) dx = -umin;
873: #else
874: if (PetscAbsScalar(dx) < umin && PetscRealPart(dx) >= 0.0) dx = umin;
875: else if (PetscRealPart(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
876: #endif
877: dx *= epsilon;
878: w3_array[col] += dx;
879: }
880: w3_array = w3_array + start; VecRestoreArray(w3,&w3_array);
882: /*
883: Evaluate function at x1 + dx (here dx is a vector of perturbations)
884: */
885: PetscLogEventBegin(MAT_FDColoringFunction,0,0,0,0);
886: (*f)(sctx,t,w3,w2,fctx);
887: PetscLogEventEnd(MAT_FDColoringFunction,0,0,0,0);
888: VecAXPY(w2,-1.0,w1);
890: /*
891: Loop over rows of vector, putting results into Jacobian matrix
892: */
893: VecGetArray(w2,&y);
894: for (l=0; l<coloring->nrows[k]; l++) {
895: row = coloring->rows[k][l];
896: col = coloring->columnsforrow[k][l];
897: y[row] *= vscale_array[vscaleforrow[k][l]];
898: srow = row + start;
899: MatSetValues(J,1,&srow,1,&col,y+row,INSERT_VALUES);
900: }
901: VecRestoreArray(w2,&y);
902: }
903: VecRestoreArray(coloring->vscale,&vscale_array);
904: xx = xx + start; VecRestoreArray(x1,&xx);
905: MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);
906: MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);
907: PetscLogEventEnd(MAT_FDColoringApply,coloring,J,x1,0);
908: return(0);
909: }
914: /*@C
915: MatFDColoringSetRecompute - Indicates that the next time a Jacobian preconditioner
916: is needed it sholuld be recomputed. Once this is called and the new Jacobian is computed
917: no additional Jacobian's will be computed (the same one will be used) until this is
918: called again.
920: Collective on MatFDColoring
922: Input Parameters:
923: . c - the coloring context
925: Level: intermediate
927: Notes: The MatFDColoringSetFrequency() is ignored once this is called
929: .seealso: MatFDColoringCreate(), MatFDColoringSetFrequency()
931: .keywords: Mat, finite differences, coloring
932: @*/
933: PetscErrorCode PETSCMAT_DLLEXPORT MatFDColoringSetRecompute(MatFDColoring c)
934: {
937: c->usersetsrecompute = PETSC_TRUE;
938: c->recompute = PETSC_TRUE;
939: return(0);
940: }