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