xref: /petsc/src/mat/matfd/fdmatrix.c (revision 4ad8454beace47809662cdae21ee081016eaa39a)
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 /*@C
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 /*@C
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(PetscOptionsGetViewer(PetscObjectComm((PetscObject)fd), ((PetscObject)fd)->options, prefix, optionname, &viewer, &format, &flg));
415   } else {
416     PetscCall(PetscOptionsGetViewer(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(PetscOptionsRestoreViewer(&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   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Matrix must be assembled by calls to MatAssemblyBegin/End();");
455   PetscCall(PetscLogEventBegin(MAT_FDColoringCreate, mat, 0, 0, 0));
456   PetscCall(MatGetSize(mat, &M, &N));
457   PetscCheck(M == N, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Only for square matrices");
458   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
459   PetscCall(PetscHeaderCreate(c, MAT_FDCOLORING_CLASSID, "MatFDColoring", "Jacobian computation via finite differences with coloring", "Mat", comm, MatFDColoringDestroy, MatFDColoringView));
460 
461   c->ctype = iscoloring->ctype;
462   PetscCall(PetscObjectGetId((PetscObject)mat, &c->matid));
463 
464   PetscUseTypeMethod(mat, fdcoloringcreate, iscoloring, c);
465 
466   PetscCall(MatCreateVecs(mat, NULL, &c->w1));
467   /* Vec is used intensively in particular piece of scalar CPU code; won't benefit from bouncing back and forth to the GPU */
468   PetscCall(VecBindToCPU(c->w1, PETSC_TRUE));
469   PetscCall(VecDuplicate(c->w1, &c->w2));
470   /* Vec is used intensively in particular piece of scalar CPU code; won't benefit from bouncing back and forth to the GPU */
471   PetscCall(VecBindToCPU(c->w2, PETSC_TRUE));
472 
473   c->error_rel    = PETSC_SQRT_MACHINE_EPSILON;
474   c->umin         = 100.0 * PETSC_SQRT_MACHINE_EPSILON;
475   c->currentcolor = -1;
476   c->htype        = "wp";
477   c->fset         = PETSC_FALSE;
478   c->setupcalled  = PETSC_FALSE;
479 
480   *color = c;
481   PetscCall(PetscObjectCompose((PetscObject)mat, "SNESMatFDColoring", (PetscObject)c));
482   PetscCall(PetscLogEventEnd(MAT_FDColoringCreate, mat, 0, 0, 0));
483   PetscFunctionReturn(PETSC_SUCCESS);
484 }
485 
486 /*@
487   MatFDColoringDestroy - Destroys a matrix coloring context that was created
488   via `MatFDColoringCreate()`.
489 
490   Collective
491 
492   Input Parameter:
493 . c - coloring context
494 
495   Level: intermediate
496 
497 .seealso: `Mat`, `MatFDColoring`, `MatFDColoringCreate()`
498 @*/
499 PetscErrorCode MatFDColoringDestroy(MatFDColoring *c)
500 {
501   PetscInt      i;
502   MatFDColoring color = *c;
503 
504   PetscFunctionBegin;
505   if (!*c) PetscFunctionReturn(PETSC_SUCCESS);
506   if (--((PetscObject)color)->refct > 0) {
507     *c = NULL;
508     PetscFunctionReturn(PETSC_SUCCESS);
509   }
510 
511   /* we do not free the column arrays since their entries are owned by the ISs in color->isa */
512   for (i = 0; i < color->ncolors; i++) PetscCall(ISDestroy(&color->isa[i]));
513   PetscCall(PetscFree(color->isa));
514   PetscCall(PetscFree2(color->ncolumns, color->columns));
515   PetscCall(PetscFree(color->nrows));
516   if (color->htype[0] == 'w') {
517     PetscCall(PetscFree(color->matentry2));
518   } else {
519     PetscCall(PetscFree(color->matentry));
520   }
521   PetscCall(PetscFree(color->dy));
522   if (color->vscale) PetscCall(VecDestroy(&color->vscale));
523   PetscCall(VecDestroy(&color->w1));
524   PetscCall(VecDestroy(&color->w2));
525   PetscCall(VecDestroy(&color->w3));
526   PetscCall(PetscHeaderDestroy(c));
527   PetscFunctionReturn(PETSC_SUCCESS);
528 }
529 
530 /*@C
531   MatFDColoringGetPerturbedColumns - Returns the indices of the columns that
532   that are currently being perturbed.
533 
534   Not Collective
535 
536   Input Parameter:
537 . coloring - coloring context created with `MatFDColoringCreate()`
538 
539   Output Parameters:
540 + n    - the number of local columns being perturbed
541 - cols - the column indices, in global numbering
542 
543   Level: advanced
544 
545   Note:
546   IF the matrix type is `MATBAIJ`, then the block column indices are returned
547 
548   Fortran Notes:
549   This routine has a different interface for Fortran
550 .vb
551      #include <petsc/finclude/petscmat.h>
552           use petscmat
553           PetscInt, pointer :: array(:)
554           PetscErrorCode  ierr
555           MatFDColoring   i
556           call MatFDColoringGetPerturbedColumnsF90(i,array,ierr)
557       use the entries of array ...
558           call MatFDColoringRestorePerturbedColumnsF90(i,array,ierr)
559 .ve
560 
561 .seealso: `Mat`, `MatFDColoring`, `MatFDColoringCreate()`, `MatFDColoringDestroy()`, `MatFDColoringView()`, `MatFDColoringApply()`
562 @*/
563 PetscErrorCode MatFDColoringGetPerturbedColumns(MatFDColoring coloring, PetscInt *n, const PetscInt *cols[])
564 {
565   PetscFunctionBegin;
566   if (coloring->currentcolor >= 0) {
567     *n    = coloring->ncolumns[coloring->currentcolor];
568     *cols = coloring->columns[coloring->currentcolor];
569   } else {
570     *n = 0;
571   }
572   PetscFunctionReturn(PETSC_SUCCESS);
573 }
574 
575 /*@
576   MatFDColoringApply - Given a matrix for which a `MatFDColoring` context
577   has been created, computes the Jacobian for a function via finite differences.
578 
579   Collective
580 
581   Input Parameters:
582 + J        - location to store Jacobian
583 . coloring - coloring context created with `MatFDColoringCreate()`
584 . x1       - location at which Jacobian is to be computed
585 - sctx     - context required by function, if this is being used with the SNES solver then it is `SNES` object, otherwise it is null
586 
587   Options Database Keys:
588 + -mat_fd_type                       - "wp" or "ds"  (see `MATMFFD_WP` or `MATMFFD_DS`)
589 . -mat_fd_coloring_view              - Activates basic viewing or coloring
590 . -mat_fd_coloring_view draw         - Activates drawing of coloring
591 - -mat_fd_coloring_view ::ascii_info - Activates viewing of coloring info
592 
593   Level: intermediate
594 
595 .seealso: `Mat`, `MatFDColoring`, `MatFDColoringCreate()`, `MatFDColoringDestroy()`, `MatFDColoringView()`, `MatFDColoringSetFunction()`, `MatFDColoringSetValues()`
596 @*/
597 PetscErrorCode MatFDColoringApply(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
598 {
599   PetscBool eq;
600 
601   PetscFunctionBegin;
602   PetscValidHeaderSpecific(J, MAT_CLASSID, 1);
603   PetscValidHeaderSpecific(coloring, MAT_FDCOLORING_CLASSID, 2);
604   PetscValidHeaderSpecific(x1, VEC_CLASSID, 3);
605   PetscCall(PetscObjectCompareId((PetscObject)J, coloring->matid, &eq));
606   PetscCheck(eq, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_WRONG, "Matrix used with MatFDColoringApply() must be that used with MatFDColoringCreate()");
607   PetscCheck(coloring->f, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_WRONGSTATE, "Must call MatFDColoringSetFunction()");
608   PetscCheck(coloring->setupcalled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call MatFDColoringSetUp()");
609 
610   PetscCall(MatSetUnfactored(J));
611   PetscCall(PetscLogEventBegin(MAT_FDColoringApply, coloring, J, x1, 0));
612   PetscUseTypeMethod(J, fdcoloringapply, coloring, x1, sctx);
613   PetscCall(PetscLogEventEnd(MAT_FDColoringApply, coloring, J, x1, 0));
614   if (!coloring->viewed) {
615     PetscCall(MatFDColoringViewFromOptions(coloring, NULL, "-mat_fd_coloring_view"));
616     coloring->viewed = PETSC_TRUE;
617   }
618   PetscFunctionReturn(PETSC_SUCCESS);
619 }
620