xref: /petsc/src/mat/matfd/fdmatrix.c (revision 2b8d69ca7ea5fe9190df62c1dce3bbd66fce84dd)
1 
2 /*
3    This is where the abstract matrix operations are defined that are
4   used for finite difference computations of Jacobians using coloring.
5 */
6 
7 #include <petsc/private/matimpl.h>        /*I "petscmat.h" I*/
8 #include <petsc/private/isimpl.h>
9 
10 #undef __FUNCT__
11 #define __FUNCT__ "MatFDColoringSetF"
12 PetscErrorCode  MatFDColoringSetF(MatFDColoring fd,Vec F)
13 {
14   PetscErrorCode ierr;
15 
16   PetscFunctionBegin;
17   if (F) {
18     ierr     = VecCopy(F,fd->w1);CHKERRQ(ierr);
19     fd->fset = PETSC_TRUE;
20   } else {
21     fd->fset = PETSC_FALSE;
22   }
23   PetscFunctionReturn(0);
24 }
25 
26 #include <petscdraw.h>
27 #undef __FUNCT__
28 #define __FUNCT__ "MatFDColoringView_Draw_Zoom"
29 static PetscErrorCode MatFDColoringView_Draw_Zoom(PetscDraw draw,void *Aa)
30 {
31   MatFDColoring  fd = (MatFDColoring)Aa;
32   PetscErrorCode ierr;
33   PetscInt       i,j,nz,row;
34   PetscReal      x,y;
35   MatEntry       *Jentry=fd->matentry;
36 
37   PetscFunctionBegin;
38   /* loop over colors  */
39   nz = 0;
40   for (i=0; i<fd->ncolors; i++) {
41     for (j=0; j<fd->nrows[i]; j++) {
42       row = Jentry[nz].row;
43       y   = fd->M - row - fd->rstart;
44       x   = (PetscReal)Jentry[nz++].col;
45       ierr = PetscDrawRectangle(draw,x,y,x+1,y+1,i+1,i+1,i+1,i+1);CHKERRQ(ierr);
46     }
47   }
48   PetscFunctionReturn(0);
49 }
50 
51 #undef __FUNCT__
52 #define __FUNCT__ "MatFDColoringView_Draw"
53 static PetscErrorCode MatFDColoringView_Draw(MatFDColoring fd,PetscViewer viewer)
54 {
55   PetscErrorCode ierr;
56   PetscBool      isnull;
57   PetscDraw      draw;
58   PetscReal      xr,yr,xl,yl,h,w;
59 
60   PetscFunctionBegin;
61   ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr);
62   ierr = PetscDrawIsNull(draw,&isnull);CHKERRQ(ierr);
63   if (isnull) PetscFunctionReturn(0);
64 
65   xr   = fd->N; yr  = fd->M; h = yr/10.0; w = xr/10.0;
66   xr  += w;     yr += h;    xl = -w;     yl = -h;
67   ierr = PetscDrawSetCoordinates(draw,xl,yl,xr,yr);CHKERRQ(ierr);
68   ierr = PetscObjectCompose((PetscObject)fd,"Zoomviewer",(PetscObject)viewer);CHKERRQ(ierr);
69   ierr = PetscDrawZoom(draw,MatFDColoringView_Draw_Zoom,fd);CHKERRQ(ierr);
70   ierr = PetscObjectCompose((PetscObject)fd,"Zoomviewer",NULL);CHKERRQ(ierr);
71   ierr = PetscDrawSave(draw);CHKERRQ(ierr);
72   PetscFunctionReturn(0);
73 }
74 
75 #undef __FUNCT__
76 #define __FUNCT__ "MatFDColoringView"
77 /*@C
78    MatFDColoringView - Views a finite difference coloring context.
79 
80    Collective on MatFDColoring
81 
82    Input  Parameters:
83 +  c - the coloring context
84 -  viewer - visualization context
85 
86    Level: intermediate
87 
88    Notes:
89    The available visualization contexts include
90 +     PETSC_VIEWER_STDOUT_SELF - standard output (default)
91 .     PETSC_VIEWER_STDOUT_WORLD - synchronized standard
92         output where only the first processor opens
93         the file.  All other processors send their
94         data to the first processor to print.
95 -     PETSC_VIEWER_DRAW_WORLD - graphical display of nonzero structure
96 
97    Notes:
98      Since PETSc uses only a small number of basic colors (currently 33), if the coloring
99    involves more than 33 then some seemingly identical colors are displayed making it look
100    like an illegal coloring. This is just a graphical artifact.
101 
102 .seealso: MatFDColoringCreate()
103 
104 .keywords: Mat, finite differences, coloring, view
105 @*/
106 PetscErrorCode  MatFDColoringView(MatFDColoring c,PetscViewer viewer)
107 {
108   PetscErrorCode    ierr;
109   PetscInt          i,j;
110   PetscBool         isdraw,iascii;
111   PetscViewerFormat format;
112 
113   PetscFunctionBegin;
114   PetscValidHeaderSpecific(c,MAT_FDCOLORING_CLASSID,1);
115   if (!viewer) {
116     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)c),&viewer);CHKERRQ(ierr);
117   }
118   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
119   PetscCheckSameComm(c,1,viewer,2);
120 
121   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr);
122   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
123   if (isdraw) {
124     ierr = MatFDColoringView_Draw(c,viewer);CHKERRQ(ierr);
125   } else if (iascii) {
126     ierr = PetscObjectPrintClassNamePrefixType((PetscObject)c,viewer);CHKERRQ(ierr);
127     ierr = PetscViewerASCIIPrintf(viewer,"  Error tolerance=%g\n",(double)c->error_rel);CHKERRQ(ierr);
128     ierr = PetscViewerASCIIPrintf(viewer,"  Umin=%g\n",(double)c->umin);CHKERRQ(ierr);
129     ierr = PetscViewerASCIIPrintf(viewer,"  Number of colors=%D\n",c->ncolors);CHKERRQ(ierr);
130 
131     ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
132     if (format != PETSC_VIEWER_ASCII_INFO) {
133       PetscInt row,col,nz;
134       nz = 0;
135       for (i=0; i<c->ncolors; i++) {
136         ierr = PetscViewerASCIIPrintf(viewer,"  Information for color %D\n",i);CHKERRQ(ierr);
137         ierr = PetscViewerASCIIPrintf(viewer,"    Number of columns %D\n",c->ncolumns[i]);CHKERRQ(ierr);
138         for (j=0; j<c->ncolumns[i]; j++) {
139           ierr = PetscViewerASCIIPrintf(viewer,"      %D\n",c->columns[i][j]);CHKERRQ(ierr);
140         }
141         ierr = PetscViewerASCIIPrintf(viewer,"    Number of rows %D\n",c->nrows[i]);CHKERRQ(ierr);
142         for (j=0; j<c->nrows[i]; j++) {
143           row  = c->matentry[nz].row;
144           col  = c->matentry[nz++].col;
145           ierr = PetscViewerASCIIPrintf(viewer,"      %D %D \n",row,col);CHKERRQ(ierr);
146         }
147       }
148     }
149     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
150   }
151   PetscFunctionReturn(0);
152 }
153 
154 #undef __FUNCT__
155 #define __FUNCT__ "MatFDColoringSetParameters"
156 /*@
157    MatFDColoringSetParameters - Sets the parameters for the sparse approximation of
158    a Jacobian matrix using finite differences.
159 
160    Logically Collective on MatFDColoring
161 
162    The Jacobian is estimated with the differencing approximation
163 .vb
164        F'(u)_{:,i} = [F(u+h*dx_{i}) - F(u)]/h where
165        h = error_rel*u[i]                 if  abs(u[i]) > umin
166          = +/- error_rel*umin             otherwise, with +/- determined by the sign of u[i]
167        dx_{i} = (0, ... 1, .... 0)
168 .ve
169 
170    Input Parameters:
171 +  coloring - the coloring context
172 .  error_rel - relative error
173 -  umin - minimum allowable u-value magnitude
174 
175    Level: advanced
176 
177 .keywords: Mat, finite differences, coloring, set, parameters
178 
179 .seealso: MatFDColoringCreate(), MatFDColoringSetFromOptions()
180 
181 @*/
182 PetscErrorCode MatFDColoringSetParameters(MatFDColoring matfd,PetscReal error,PetscReal umin)
183 {
184   PetscFunctionBegin;
185   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_CLASSID,1);
186   PetscValidLogicalCollectiveReal(matfd,error,2);
187   PetscValidLogicalCollectiveReal(matfd,umin,3);
188   if (error != PETSC_DEFAULT) matfd->error_rel = error;
189   if (umin != PETSC_DEFAULT)  matfd->umin      = umin;
190   PetscFunctionReturn(0);
191 }
192 
193 #undef __FUNCT__
194 #define __FUNCT__ "MatFDColoringSetBlockSize"
195 /*@
196    MatFDColoringSetBlockSize - Sets block size for efficient inserting entries of Jacobian matrix.
197 
198    Logically Collective on MatFDColoring
199 
200    Input Parameters:
201 +  coloring - the coloring context
202 .  brows - number of rows in the block
203 -  bcols - number of columns in the block
204 
205    Level: intermediate
206 
207 .keywords: Mat, coloring
208 
209 .seealso: MatFDColoringCreate(), MatFDColoringSetFromOptions()
210 
211 @*/
212 PetscErrorCode MatFDColoringSetBlockSize(MatFDColoring matfd,PetscInt brows,PetscInt bcols)
213 {
214   PetscFunctionBegin;
215   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_CLASSID,1);
216   PetscValidLogicalCollectiveInt(matfd,brows,2);
217   PetscValidLogicalCollectiveInt(matfd,bcols,3);
218   if (brows != PETSC_DEFAULT) matfd->brows = brows;
219   if (bcols != PETSC_DEFAULT) matfd->bcols = bcols;
220   PetscFunctionReturn(0);
221 }
222 
223 #undef __FUNCT__
224 #define __FUNCT__ "MatFDColoringSetUp"
225 /*@
226    MatFDColoringSetUp - Sets up the internal data structures of matrix coloring context for the later use.
227 
228    Collective on Mat
229 
230    Input Parameters:
231 +  mat - the matrix containing the nonzero structure of the Jacobian
232 .  iscoloring - the coloring of the matrix; usually obtained with MatGetColoring() or DMCreateColoring()
233 -  color - the matrix coloring context
234 
235    Level: beginner
236 
237 .keywords: MatFDColoring, setup
238 
239 .seealso: MatFDColoringCreate(), MatFDColoringDestroy()
240 @*/
241 PetscErrorCode MatFDColoringSetUp(Mat mat,ISColoring iscoloring,MatFDColoring color)
242 {
243   PetscErrorCode ierr;
244 
245   PetscFunctionBegin;
246   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
247   PetscValidHeaderSpecific(color,MAT_FDCOLORING_CLASSID,3);
248   if (color->setupcalled) PetscFunctionReturn(0);
249 
250   ierr = PetscLogEventBegin(MAT_FDColoringSetUp,mat,0,0,0);CHKERRQ(ierr);
251   if (mat->ops->fdcoloringsetup) {
252     ierr = (*mat->ops->fdcoloringsetup)(mat,iscoloring,color);CHKERRQ(ierr);
253   } else SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Code not yet written for matrix type %s",((PetscObject)mat)->type_name);
254 
255   color->setupcalled = PETSC_TRUE;
256    ierr   = PetscLogEventEnd(MAT_FDColoringSetUp,mat,0,0,0);CHKERRQ(ierr);
257   PetscFunctionReturn(0);
258 }
259 
260 #undef __FUNCT__
261 #define __FUNCT__ "MatFDColoringGetFunction"
262 /*@C
263    MatFDColoringGetFunction - Gets the function to use for computing the Jacobian.
264 
265    Not Collective
266 
267    Input Parameters:
268 .  coloring - the coloring context
269 
270    Output Parameters:
271 +  f - the function
272 -  fctx - the optional user-defined function context
273 
274    Level: intermediate
275 
276 .keywords: Mat, Jacobian, finite differences, set, function
277 
278 .seealso: MatFDColoringCreate(), MatFDColoringSetFunction(), MatFDColoringSetFromOptions()
279 
280 @*/
281 PetscErrorCode  MatFDColoringGetFunction(MatFDColoring matfd,PetscErrorCode (**f)(void),void **fctx)
282 {
283   PetscFunctionBegin;
284   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_CLASSID,1);
285   if (f) *f = matfd->f;
286   if (fctx) *fctx = matfd->fctx;
287   PetscFunctionReturn(0);
288 }
289 
290 #undef __FUNCT__
291 #define __FUNCT__ "MatFDColoringSetFunction"
292 /*@C
293    MatFDColoringSetFunction - Sets the function to use for computing the Jacobian.
294 
295    Logically Collective on MatFDColoring
296 
297    Input Parameters:
298 +  coloring - the coloring context
299 .  f - the function
300 -  fctx - the optional user-defined function context
301 
302    Calling sequence of (*f) function:
303     For SNES:    PetscErrorCode (*f)(SNES,Vec,Vec,void*)
304     If not using SNES: PetscErrorCode (*f)(void *dummy,Vec,Vec,void*) and dummy is ignored
305 
306    Level: advanced
307 
308    Notes: This function is usually used automatically by SNES (when one uses SNESSetJacobian() with the argument
309      SNESComputeJacobianDefaultColor()) and only needs to be used by someone computing a matrix via coloring directly by
310      calling MatFDColoringApply()
311 
312    Fortran Notes:
313     In Fortran you must call MatFDColoringSetFunction() for a coloring object to
314   be used without SNES or within the SNES solvers.
315 
316 .keywords: Mat, Jacobian, finite differences, set, function
317 
318 .seealso: MatFDColoringCreate(), MatFDColoringGetFunction(), MatFDColoringSetFromOptions()
319 
320 @*/
321 PetscErrorCode  MatFDColoringSetFunction(MatFDColoring matfd,PetscErrorCode (*f)(void),void *fctx)
322 {
323   PetscFunctionBegin;
324   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_CLASSID,1);
325   matfd->f    = f;
326   matfd->fctx = fctx;
327   PetscFunctionReturn(0);
328 }
329 
330 #undef __FUNCT__
331 #define __FUNCT__ "MatFDColoringSetFromOptions"
332 /*@
333    MatFDColoringSetFromOptions - Sets coloring finite difference parameters from
334    the options database.
335 
336    Collective on MatFDColoring
337 
338    The Jacobian, F'(u), is estimated with the differencing approximation
339 .vb
340        F'(u)_{:,i} = [F(u+h*dx_{i}) - F(u)]/h where
341        h = error_rel*u[i]                 if  abs(u[i]) > umin
342          = +/- error_rel*umin             otherwise, with +/- determined by the sign of u[i]
343        dx_{i} = (0, ... 1, .... 0)
344 .ve
345 
346    Input Parameter:
347 .  coloring - the coloring context
348 
349    Options Database Keys:
350 +  -mat_fd_coloring_err <err> - Sets <err> (square root of relative error in the function)
351 .  -mat_fd_coloring_umin <umin> - Sets umin, the minimum allowable u-value magnitude
352 .  -mat_fd_type - "wp" or "ds" (see MATMFFD_WP or MATMFFD_DS)
353 .  -mat_fd_coloring_view - Activates basic viewing
354 .  -mat_fd_coloring_view ::ascii_info - Activates viewing info
355 -  -mat_fd_coloring_view draw - Activates drawing
356 
357     Level: intermediate
358 
359 .keywords: Mat, finite differences, parameters
360 
361 .seealso: MatFDColoringCreate(), MatFDColoringView(), MatFDColoringSetParameters()
362 
363 @*/
364 PetscErrorCode  MatFDColoringSetFromOptions(MatFDColoring matfd)
365 {
366   PetscErrorCode ierr;
367   PetscBool      flg;
368   char           value[3];
369 
370   PetscFunctionBegin;
371   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_CLASSID,1);
372 
373   ierr = PetscObjectOptionsBegin((PetscObject)matfd);CHKERRQ(ierr);
374   ierr = PetscOptionsReal("-mat_fd_coloring_err","Square root of relative error in function","MatFDColoringSetParameters",matfd->error_rel,&matfd->error_rel,0);CHKERRQ(ierr);
375   ierr = PetscOptionsReal("-mat_fd_coloring_umin","Minimum allowable u magnitude","MatFDColoringSetParameters",matfd->umin,&matfd->umin,0);CHKERRQ(ierr);
376   ierr = PetscOptionsString("-mat_fd_type","Algorithm to compute h, wp or ds","MatFDColoringCreate",matfd->htype,value,3,&flg);CHKERRQ(ierr);
377   if (flg) {
378     if (value[0] == 'w' && value[1] == 'p') matfd->htype = "wp";
379     else if (value[0] == 'd' && value[1] == 's') matfd->htype = "ds";
380     else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown finite differencing type %s",value);
381   }
382   ierr = PetscOptionsInt("-mat_fd_coloring_brows","Number of block rows","MatFDColoringSetBlockSize",matfd->brows,&matfd->brows,NULL);CHKERRQ(ierr);
383   ierr = PetscOptionsInt("-mat_fd_coloring_bcols","Number of block columns","MatFDColoringSetBlockSize",matfd->bcols,&matfd->bcols,&flg);CHKERRQ(ierr);
384   if (flg && matfd->bcols > matfd->ncolors) {
385     /* input bcols cannot be > matfd->ncolors, thus set it as ncolors */
386     matfd->bcols = matfd->ncolors;
387   }
388 
389   /* process any options handlers added with PetscObjectAddOptionsHandler() */
390   ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject)matfd);CHKERRQ(ierr);
391   PetscOptionsEnd();CHKERRQ(ierr);
392   PetscFunctionReturn(0);
393 }
394 
395 #undef __FUNCT__
396 #define __FUNCT__ "MatFDColoringViewFromOptions"
397 PetscErrorCode MatFDColoringViewFromOptions(MatFDColoring fd,const char prefix[],const char optionname[])
398 {
399   PetscErrorCode    ierr;
400   PetscBool         flg;
401   PetscViewer       viewer;
402   PetscViewerFormat format;
403 
404   PetscFunctionBegin;
405   if (prefix) {
406     ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject)fd),prefix,optionname,&viewer,&format,&flg);CHKERRQ(ierr);
407   } else {
408     ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject)fd),((PetscObject)fd)->prefix,optionname,&viewer,&format,&flg);CHKERRQ(ierr);
409   }
410   if (flg) {
411     ierr = PetscViewerPushFormat(viewer,format);CHKERRQ(ierr);
412     ierr = MatFDColoringView(fd,viewer);CHKERRQ(ierr);
413     ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
414     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
415   }
416   PetscFunctionReturn(0);
417 }
418 
419 #undef __FUNCT__
420 #define __FUNCT__ "MatFDColoringCreate"
421 /*@
422    MatFDColoringCreate - Creates a matrix coloring context for finite difference
423    computation of Jacobians.
424 
425    Collective on Mat
426 
427    Input Parameters:
428 +  mat - the matrix containing the nonzero structure of the Jacobian
429 -  iscoloring - the coloring of the matrix; usually obtained with MatColoringCreate() or DMCreateColoring()
430 
431     Output Parameter:
432 .   color - the new coloring context
433 
434     Level: intermediate
435 
436 .seealso: MatFDColoringDestroy(),SNESComputeJacobianDefaultColor(), ISColoringCreate(),
437           MatFDColoringSetFunction(), MatFDColoringSetFromOptions(), MatFDColoringApply(),
438           MatFDColoringView(), MatFDColoringSetParameters(), MatColoringCreate(), DMCreateColoring()
439 @*/
440 PetscErrorCode  MatFDColoringCreate(Mat mat,ISColoring iscoloring,MatFDColoring *color)
441 {
442   MatFDColoring  c;
443   MPI_Comm       comm;
444   PetscErrorCode ierr;
445   PetscInt       M,N;
446 
447   PetscFunctionBegin;
448   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
449   if (!mat->assembled) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"Matrix must be assembled by calls to MatAssemblyBegin/End();");
450   ierr = PetscLogEventBegin(MAT_FDColoringCreate,mat,0,0,0);CHKERRQ(ierr);
451   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
452   if (M != N) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Only for square matrices");
453   ierr = PetscObjectGetComm((PetscObject)mat,&comm);CHKERRQ(ierr);
454   ierr = PetscHeaderCreate(c,MAT_FDCOLORING_CLASSID,"MatFDColoring","Jacobian computation via finite differences with coloring","Mat",comm,MatFDColoringDestroy,MatFDColoringView);CHKERRQ(ierr);
455 
456   c->ctype = iscoloring->ctype;
457 
458   if (mat->ops->fdcoloringcreate) {
459     ierr = (*mat->ops->fdcoloringcreate)(mat,iscoloring,c);CHKERRQ(ierr);
460   } else SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Code not yet written for matrix type %s",((PetscObject)mat)->type_name);
461 
462   ierr = MatCreateVecs(mat,NULL,&c->w1);CHKERRQ(ierr);
463   ierr = PetscLogObjectParent((PetscObject)c,(PetscObject)c->w1);CHKERRQ(ierr);
464   ierr = VecDuplicate(c->w1,&c->w2);CHKERRQ(ierr);
465   ierr = PetscLogObjectParent((PetscObject)c,(PetscObject)c->w2);CHKERRQ(ierr);
466 
467   c->error_rel    = PETSC_SQRT_MACHINE_EPSILON;
468   c->umin         = 100.0*PETSC_SQRT_MACHINE_EPSILON;
469   c->currentcolor = -1;
470   c->htype        = "wp";
471   c->fset         = PETSC_FALSE;
472   c->setupcalled  = PETSC_FALSE;
473 
474   *color = c;
475   ierr   = PetscObjectCompose((PetscObject)mat,"SNESMatFDColoring",(PetscObject)c);CHKERRQ(ierr);
476   ierr   = PetscLogEventEnd(MAT_FDColoringCreate,mat,0,0,0);CHKERRQ(ierr);
477   PetscFunctionReturn(0);
478 }
479 
480 #undef __FUNCT__
481 #define __FUNCT__ "MatFDColoringDestroy"
482 /*@
483     MatFDColoringDestroy - Destroys a matrix coloring context that was created
484     via MatFDColoringCreate().
485 
486     Collective on MatFDColoring
487 
488     Input Parameter:
489 .   c - coloring context
490 
491     Level: intermediate
492 
493 .seealso: MatFDColoringCreate()
494 @*/
495 PetscErrorCode  MatFDColoringDestroy(MatFDColoring *c)
496 {
497   PetscErrorCode ierr;
498   PetscInt       i;
499   MatFDColoring  color = *c;
500 
501   PetscFunctionBegin;
502   if (!*c) PetscFunctionReturn(0);
503   if (--((PetscObject)color)->refct > 0) {*c = 0; PetscFunctionReturn(0);}
504 
505   for (i=0; i<color->ncolors; i++) {
506     ierr = PetscFree(color->columns[i]);CHKERRQ(ierr);
507   }
508   ierr = PetscFree(color->ncolumns);CHKERRQ(ierr);
509   ierr = PetscFree(color->columns);CHKERRQ(ierr);
510   ierr = PetscFree(color->nrows);CHKERRQ(ierr);
511   if (color->htype[0] == 'w') {
512     ierr = PetscFree(color->matentry2);CHKERRQ(ierr);
513   } else {
514     ierr = PetscFree(color->matentry);CHKERRQ(ierr);
515   }
516   ierr = PetscFree(color->dy);CHKERRQ(ierr);
517   if (color->vscale) {ierr = VecDestroy(&color->vscale);CHKERRQ(ierr);}
518   ierr = VecDestroy(&color->w1);CHKERRQ(ierr);
519   ierr = VecDestroy(&color->w2);CHKERRQ(ierr);
520   ierr = VecDestroy(&color->w3);CHKERRQ(ierr);
521   ierr = PetscHeaderDestroy(c);CHKERRQ(ierr);
522   PetscFunctionReturn(0);
523 }
524 
525 #undef __FUNCT__
526 #define __FUNCT__ "MatFDColoringGetPerturbedColumns"
527 /*@C
528     MatFDColoringGetPerturbedColumns - Returns the indices of the columns that
529       that are currently being perturbed.
530 
531     Not Collective
532 
533     Input Parameters:
534 .   coloring - coloring context created with MatFDColoringCreate()
535 
536     Output Parameters:
537 +   n - the number of local columns being perturbed
538 -   cols - the column indices, in global numbering
539 
540    Level: intermediate
541 
542 .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView(), MatFDColoringApply()
543 
544 .keywords: coloring, Jacobian, finite differences
545 @*/
546 PetscErrorCode  MatFDColoringGetPerturbedColumns(MatFDColoring coloring,PetscInt *n,PetscInt *cols[])
547 {
548   PetscFunctionBegin;
549   if (coloring->currentcolor >= 0) {
550     *n    = coloring->ncolumns[coloring->currentcolor];
551     *cols = coloring->columns[coloring->currentcolor];
552   } else {
553     *n = 0;
554   }
555   PetscFunctionReturn(0);
556 }
557 
558 #undef __FUNCT__
559 #define __FUNCT__ "MatFDColoringApply"
560 /*@
561     MatFDColoringApply - Given a matrix for which a MatFDColoring context
562     has been created, computes the Jacobian for a function via finite differences.
563 
564     Collective on MatFDColoring
565 
566     Input Parameters:
567 +   mat - location to store Jacobian
568 .   coloring - coloring context created with MatFDColoringCreate()
569 .   x1 - location at which Jacobian is to be computed
570 -   sctx - context required by function, if this is being used with the SNES solver then it is SNES object, otherwise it is null
571 
572     Options Database Keys:
573 +    -mat_fd_type - "wp" or "ds"  (see MATMFFD_WP or MATMFFD_DS)
574 .    -mat_fd_coloring_view - Activates basic viewing or coloring
575 .    -mat_fd_coloring_view draw - Activates drawing of coloring
576 -    -mat_fd_coloring_view ::ascii_info - Activates viewing of coloring info
577 
578     Level: intermediate
579 
580 .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView(), MatFDColoringSetFunction()
581 
582 .keywords: coloring, Jacobian, finite differences
583 @*/
584 PetscErrorCode  MatFDColoringApply(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
585 {
586   PetscErrorCode ierr;
587   PetscBool      flg = PETSC_FALSE;
588 
589   PetscFunctionBegin;
590   PetscValidHeaderSpecific(J,MAT_CLASSID,1);
591   PetscValidHeaderSpecific(coloring,MAT_FDCOLORING_CLASSID,2);
592   PetscValidHeaderSpecific(x1,VEC_CLASSID,3);
593   if (!coloring->f) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_WRONGSTATE,"Must call MatFDColoringSetFunction()");
594   if (!J->ops->fdcoloringapply) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not supported for this matrix type %s",((PetscObject)J)->type_name);
595   if (!coloring->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call MatFDColoringSetUp()");
596 
597   ierr = MatSetUnfactored(J);CHKERRQ(ierr);
598   ierr = PetscOptionsGetBool(((PetscObject)coloring)->options,NULL,"-mat_fd_coloring_dont_rezero",&flg,NULL);CHKERRQ(ierr);
599   if (flg) {
600     ierr = PetscInfo(coloring,"Not calling MatZeroEntries()\n");CHKERRQ(ierr);
601   } else {
602     PetscBool assembled;
603     ierr = MatAssembled(J,&assembled);CHKERRQ(ierr);
604     if (assembled) {
605       ierr = MatZeroEntries(J);CHKERRQ(ierr);
606     }
607   }
608 
609   ierr = PetscLogEventBegin(MAT_FDColoringApply,coloring,J,x1,0);CHKERRQ(ierr);
610   ierr = (*J->ops->fdcoloringapply)(J,coloring,x1,sctx);CHKERRQ(ierr);
611   ierr = PetscLogEventEnd(MAT_FDColoringApply,coloring,J,x1,0);CHKERRQ(ierr);
612   PetscFunctionReturn(0);
613 }
614