Actual source code: fdmatrix.c

petsc-3.9.2 2018-05-20
Report Typos and Errors
```
2: /*
3:    This is where the abstract matrix operations are defined that are
4:   used for finite difference computations of Jacobians using coloring.
5: */

7:  #include <petsc/private/matimpl.h>
8:  #include <petsc/private/isimpl.h>

10: PetscErrorCode  MatFDColoringSetF(MatFDColoring fd,Vec F)
11: {

15:   if (F) {
16:     VecCopy(F,fd->w1);
17:     fd->fset = PETSC_TRUE;
18:   } else {
19:     fd->fset = PETSC_FALSE;
20:   }
21:   return(0);
22: }

24:  #include <petscdraw.h>
25: static PetscErrorCode MatFDColoringView_Draw_Zoom(PetscDraw draw,void *Aa)
26: {
27:   MatFDColoring  fd = (MatFDColoring)Aa;
29:   PetscInt       i,j,nz,row;
30:   PetscReal      x,y;
31:   MatEntry       *Jentry=fd->matentry;

34:   /* loop over colors  */
35:   nz = 0;
36:   for (i=0; i<fd->ncolors; i++) {
37:     for (j=0; j<fd->nrows[i]; j++) {
38:       row = Jentry[nz].row;
39:       y   = fd->M - row - fd->rstart;
40:       x   = (PetscReal)Jentry[nz++].col;
41:       PetscDrawRectangle(draw,x,y,x+1,y+1,i+1,i+1,i+1,i+1);
42:     }
43:   }
44:   return(0);
45: }

47: static PetscErrorCode MatFDColoringView_Draw(MatFDColoring fd,PetscViewer viewer)
48: {
50:   PetscBool      isnull;
51:   PetscDraw      draw;
52:   PetscReal      xr,yr,xl,yl,h,w;

55:   PetscViewerDrawGetDraw(viewer,0,&draw);
56:   PetscDrawIsNull(draw,&isnull);
57:   if (isnull) return(0);

59:   xr   = fd->N; yr  = fd->M; h = yr/10.0; w = xr/10.0;
60:   xr  += w;     yr += h;    xl = -w;     yl = -h;
61:   PetscDrawSetCoordinates(draw,xl,yl,xr,yr);
62:   PetscObjectCompose((PetscObject)fd,"Zoomviewer",(PetscObject)viewer);
63:   PetscDrawZoom(draw,MatFDColoringView_Draw_Zoom,fd);
64:   PetscObjectCompose((PetscObject)fd,"Zoomviewer",NULL);
65:   PetscDrawSave(draw);
66:   return(0);
67: }

69: /*@C
70:    MatFDColoringView - Views a finite difference coloring context.

72:    Collective on MatFDColoring

74:    Input  Parameters:
75: +  c - the coloring context
76: -  viewer - visualization context

78:    Level: intermediate

80:    Notes:
81:    The available visualization contexts include
82: +     PETSC_VIEWER_STDOUT_SELF - standard output (default)
83: .     PETSC_VIEWER_STDOUT_WORLD - synchronized standard
84:         output where only the first processor opens
85:         the file.  All other processors send their
86:         data to the first processor to print.
87: -     PETSC_VIEWER_DRAW_WORLD - graphical display of nonzero structure

89:    Notes:
90:      Since PETSc uses only a small number of basic colors (currently 33), if the coloring
91:    involves more than 33 then some seemingly identical colors are displayed making it look
92:    like an illegal coloring. This is just a graphical artifact.

94: .seealso: MatFDColoringCreate()

96: .keywords: Mat, finite differences, coloring, view
97: @*/
98: PetscErrorCode  MatFDColoringView(MatFDColoring c,PetscViewer viewer)
99: {
100:   PetscErrorCode    ierr;
101:   PetscInt          i,j;
102:   PetscBool         isdraw,iascii;
103:   PetscViewerFormat format;

107:   if (!viewer) {
108:     PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)c),&viewer);
109:   }

113:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);
114:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
115:   if (isdraw) {
116:     MatFDColoringView_Draw(c,viewer);
117:   } else if (iascii) {
118:     PetscObjectPrintClassNamePrefixType((PetscObject)c,viewer);
119:     PetscViewerASCIIPrintf(viewer,"  Error tolerance=%g\n",(double)c->error_rel);
120:     PetscViewerASCIIPrintf(viewer,"  Umin=%g\n",(double)c->umin);
121:     PetscViewerASCIIPrintf(viewer,"  Number of colors=%D\n",c->ncolors);

123:     PetscViewerGetFormat(viewer,&format);
124:     if (format != PETSC_VIEWER_ASCII_INFO) {
125:       PetscInt row,col,nz;
126:       nz = 0;
127:       for (i=0; i<c->ncolors; i++) {
128:         PetscViewerASCIIPrintf(viewer,"  Information for color %D\n",i);
129:         PetscViewerASCIIPrintf(viewer,"    Number of columns %D\n",c->ncolumns[i]);
130:         for (j=0; j<c->ncolumns[i]; j++) {
131:           PetscViewerASCIIPrintf(viewer,"      %D\n",c->columns[i][j]);
132:         }
133:         PetscViewerASCIIPrintf(viewer,"    Number of rows %D\n",c->nrows[i]);
134:         if (c->matentry) {
135:           for (j=0; j<c->nrows[i]; j++) {
136:             row  = c->matentry[nz].row;
137:             col  = c->matentry[nz++].col;
138:             PetscViewerASCIIPrintf(viewer,"      %D %D \n",row,col);
139:           }
140:         }
141:       }
142:     }
143:     PetscViewerFlush(viewer);
144:   }
145:   return(0);
146: }

148: /*@
149:    MatFDColoringSetParameters - Sets the parameters for the sparse approximation of
150:    a Jacobian matrix using finite differences.

152:    Logically Collective on MatFDColoring

154:    The Jacobian is estimated with the differencing approximation
155: .vb
156:        F'(u)_{:,i} = [F(u+h*dx_{i}) - F(u)]/h where
157:        htype = 'ds':
158:          h = error_rel*u[i]                 if  abs(u[i]) > umin
159:            = +/- error_rel*umin             otherwise, with +/- determined by the sign of u[i]
160:          dx_{i} = (0, ... 1, .... 0)

162:        htype = 'wp':
163:          h = error_rel * sqrt(1 + ||u||)
164: .ve

166:    Input Parameters:
167: +  coloring - the coloring context
168: .  error_rel - relative error
169: -  umin - minimum allowable u-value magnitude

173: .keywords: Mat, finite differences, coloring, set, parameters

175: .seealso: MatFDColoringCreate(), MatFDColoringSetFromOptions()

177: @*/
178: PetscErrorCode MatFDColoringSetParameters(MatFDColoring matfd,PetscReal error,PetscReal umin)
179: {
184:   if (error != PETSC_DEFAULT) matfd->error_rel = error;
185:   if (umin != PETSC_DEFAULT)  matfd->umin      = umin;
186:   return(0);
187: }

189: /*@
190:    MatFDColoringSetBlockSize - Sets block size for efficient inserting entries of Jacobian matrix.

192:    Logically Collective on MatFDColoring

194:    Input Parameters:
195: +  coloring - the coloring context
196: .  brows - number of rows in the block
197: -  bcols - number of columns in the block

199:    Level: intermediate

201: .keywords: Mat, coloring

203: .seealso: MatFDColoringCreate(), MatFDColoringSetFromOptions()

205: @*/
206: PetscErrorCode MatFDColoringSetBlockSize(MatFDColoring matfd,PetscInt brows,PetscInt bcols)
207: {
212:   if (brows != PETSC_DEFAULT) matfd->brows = brows;
213:   if (bcols != PETSC_DEFAULT) matfd->bcols = bcols;
214:   return(0);
215: }

217: /*@
218:    MatFDColoringSetUp - Sets up the internal data structures of matrix coloring context for the later use.

220:    Collective on Mat

222:    Input Parameters:
223: +  mat - the matrix containing the nonzero structure of the Jacobian
224: .  iscoloring - the coloring of the matrix; usually obtained with MatGetColoring() or DMCreateColoring()
225: -  color - the matrix coloring context

227:    Level: beginner

229: .keywords: MatFDColoring, setup

231: .seealso: MatFDColoringCreate(), MatFDColoringDestroy()
232: @*/
233: PetscErrorCode MatFDColoringSetUp(Mat mat,ISColoring iscoloring,MatFDColoring color)
234: {

240:   if (color->setupcalled) return(0);

242:   PetscLogEventBegin(MAT_FDColoringSetUp,mat,0,0,0);
243:   if (mat->ops->fdcoloringsetup) {
244:     (*mat->ops->fdcoloringsetup)(mat,iscoloring,color);
245:   } else SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Code not yet written for matrix type %s",((PetscObject)mat)->type_name);

247:   color->setupcalled = PETSC_TRUE;
248:    PetscLogEventEnd(MAT_FDColoringSetUp,mat,0,0,0);
249:   return(0);
250: }

252: /*@C
253:    MatFDColoringGetFunction - Gets the function to use for computing the Jacobian.

255:    Not Collective

257:    Input Parameters:
258: .  coloring - the coloring context

260:    Output Parameters:
261: +  f - the function
262: -  fctx - the optional user-defined function context

264:    Level: intermediate

266: .keywords: Mat, Jacobian, finite differences, set, function

268: .seealso: MatFDColoringCreate(), MatFDColoringSetFunction(), MatFDColoringSetFromOptions()

270: @*/
271: PetscErrorCode  MatFDColoringGetFunction(MatFDColoring matfd,PetscErrorCode (**f)(void),void **fctx)
272: {
275:   if (f) *f = matfd->f;
276:   if (fctx) *fctx = matfd->fctx;
277:   return(0);
278: }

280: /*@C
281:    MatFDColoringSetFunction - Sets the function to use for computing the Jacobian.

283:    Logically Collective on MatFDColoring

285:    Input Parameters:
286: +  coloring - the coloring context
287: .  f - the function
288: -  fctx - the optional user-defined function context

290:    Calling sequence of (*f) function:
291:     For SNES:    PetscErrorCode (*f)(SNES,Vec,Vec,void*)
292:     If not using SNES: PetscErrorCode (*f)(void *dummy,Vec,Vec,void*) and dummy is ignored

296:    Notes: This function is usually used automatically by SNES (when one uses SNESSetJacobian() with the argument
297:      SNESComputeJacobianDefaultColor()) and only needs to be used by someone computing a matrix via coloring directly by
298:      calling MatFDColoringApply()

300:    Fortran Notes:
301:     In Fortran you must call MatFDColoringSetFunction() for a coloring object to
302:   be used without SNES or within the SNES solvers.

304: .keywords: Mat, Jacobian, finite differences, set, function

306: .seealso: MatFDColoringCreate(), MatFDColoringGetFunction(), MatFDColoringSetFromOptions()

308: @*/
309: PetscErrorCode  MatFDColoringSetFunction(MatFDColoring matfd,PetscErrorCode (*f)(void),void *fctx)
310: {
313:   matfd->f    = f;
314:   matfd->fctx = fctx;
315:   return(0);
316: }

318: /*@
319:    MatFDColoringSetFromOptions - Sets coloring finite difference parameters from
320:    the options database.

322:    Collective on MatFDColoring

324:    The Jacobian, F'(u), is estimated with the differencing approximation
325: .vb
326:        F'(u)_{:,i} = [F(u+h*dx_{i}) - F(u)]/h where
327:        h = error_rel*u[i]                 if  abs(u[i]) > umin
328:          = +/- error_rel*umin             otherwise, with +/- determined by the sign of u[i]
329:        dx_{i} = (0, ... 1, .... 0)
330: .ve

332:    Input Parameter:
333: .  coloring - the coloring context

335:    Options Database Keys:
336: +  -mat_fd_coloring_err <err> - Sets <err> (square root of relative error in the function)
337: .  -mat_fd_coloring_umin <umin> - Sets umin, the minimum allowable u-value magnitude
338: .  -mat_fd_type - "wp" or "ds" (see MATMFFD_WP or MATMFFD_DS)
339: .  -mat_fd_coloring_view - Activates basic viewing
340: .  -mat_fd_coloring_view ::ascii_info - Activates viewing info
341: -  -mat_fd_coloring_view draw - Activates drawing

343:     Level: intermediate

345: .keywords: Mat, finite differences, parameters

347: .seealso: MatFDColoringCreate(), MatFDColoringView(), MatFDColoringSetParameters()

349: @*/
350: PetscErrorCode  MatFDColoringSetFromOptions(MatFDColoring matfd)
351: {
353:   PetscBool      flg;
354:   char           value[3];

359:   PetscObjectOptionsBegin((PetscObject)matfd);
360:   PetscOptionsReal("-mat_fd_coloring_err","Square root of relative error in function","MatFDColoringSetParameters",matfd->error_rel,&matfd->error_rel,0);
361:   PetscOptionsReal("-mat_fd_coloring_umin","Minimum allowable u magnitude","MatFDColoringSetParameters",matfd->umin,&matfd->umin,0);
362:   PetscOptionsString("-mat_fd_type","Algorithm to compute h, wp or ds","MatFDColoringCreate",matfd->htype,value,3,&flg);
363:   if (flg) {
364:     if (value[0] == 'w' && value[1] == 'p') matfd->htype = "wp";
365:     else if (value[0] == 'd' && value[1] == 's') matfd->htype = "ds";
366:     else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown finite differencing type %s",value);
367:   }
368:   PetscOptionsInt("-mat_fd_coloring_brows","Number of block rows","MatFDColoringSetBlockSize",matfd->brows,&matfd->brows,NULL);
369:   PetscOptionsInt("-mat_fd_coloring_bcols","Number of block columns","MatFDColoringSetBlockSize",matfd->bcols,&matfd->bcols,&flg);
370:   if (flg && matfd->bcols > matfd->ncolors) {
371:     /* input bcols cannot be > matfd->ncolors, thus set it as ncolors */
372:     matfd->bcols = matfd->ncolors;
373:   }

376:   PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject)matfd);
377:   PetscOptionsEnd();
378:   return(0);
379: }

381: /*@C
382:    MatFDColoringSetType - Sets the approach for computing the finite difference parameter

384:    Collective on MatFDColoring

386:    Input Parameters:
387: +  coloring - the coloring context
388: -  type - either MATMFFD_WP or MATMFFD_DS

390:    Options Database Keys:
391: .  -mat_fd_type - "wp" or "ds"

393:    Note: It is goofy that the argument type is MatMFFDType since the MatFDColoring actually computes the matrix entries
394:          but the process of computing the entries is the same as as with the MatMFFD operation so we should reuse the names instead of
395:          introducing another one.

397:    Level: intermediate

399: .keywords: Mat, finite differences, parameters

401: .seealso: MatFDColoringCreate(), MatFDColoringView(), MatFDColoringSetParameters()

403: @*/
404: PetscErrorCode  MatFDColoringSetType(MatFDColoring matfd,MatMFFDType type)
405: {
408:   /*
409:      It is goofy to handle the strings this way but currently there is no code to free a dynamically created matfd->htype
410:      and this function is being provided as patch for a release so it shouldn't change the implementaton
411:   */
412:   if (type[0] == 'w' && type[1] == 'p') matfd->htype = "wp";
413:   else if (type[0] == 'd' && type[1] == 's') matfd->htype = "ds";
414:   else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown finite differencing type %s",type);
415:   return(0);
416: }

418: PetscErrorCode MatFDColoringViewFromOptions(MatFDColoring fd,const char prefix[],const char optionname[])
419: {
420:   PetscErrorCode    ierr;
421:   PetscBool         flg;
422:   PetscViewer       viewer;
423:   PetscViewerFormat format;

426:   if (prefix) {
427:     PetscOptionsGetViewer(PetscObjectComm((PetscObject)fd),prefix,optionname,&viewer,&format,&flg);
428:   } else {
429:     PetscOptionsGetViewer(PetscObjectComm((PetscObject)fd),((PetscObject)fd)->prefix,optionname,&viewer,&format,&flg);
430:   }
431:   if (flg) {
432:     PetscViewerPushFormat(viewer,format);
433:     MatFDColoringView(fd,viewer);
434:     PetscViewerPopFormat(viewer);
435:     PetscViewerDestroy(&viewer);
436:   }
437:   return(0);
438: }

440: /*@
441:    MatFDColoringCreate - Creates a matrix coloring context for finite difference
442:    computation of Jacobians.

444:    Collective on Mat

446:    Input Parameters:
447: +  mat - the matrix containing the nonzero structure of the Jacobian
448: -  iscoloring - the coloring of the matrix; usually obtained with MatColoringCreate() or DMCreateColoring()

450:     Output Parameter:
451: .   color - the new coloring context

453:     Level: intermediate

455: .seealso: MatFDColoringDestroy(),SNESComputeJacobianDefaultColor(), ISColoringCreate(),
456:           MatFDColoringSetFunction(), MatFDColoringSetFromOptions(), MatFDColoringApply(),
457:           MatFDColoringView(), MatFDColoringSetParameters(), MatColoringCreate(), DMCreateColoring()
458: @*/
459: PetscErrorCode  MatFDColoringCreate(Mat mat,ISColoring iscoloring,MatFDColoring *color)
460: {
461:   MatFDColoring  c;
462:   MPI_Comm       comm;
464:   PetscInt       M,N;

468:   if (!mat->assembled) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"Matrix must be assembled by calls to MatAssemblyBegin/End();");
469:   PetscLogEventBegin(MAT_FDColoringCreate,mat,0,0,0);
470:   MatGetSize(mat,&M,&N);
471:   if (M != N) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Only for square matrices");
472:   PetscObjectGetComm((PetscObject)mat,&comm);
473:   PetscHeaderCreate(c,MAT_FDCOLORING_CLASSID,"MatFDColoring","Jacobian computation via finite differences with coloring","Mat",comm,MatFDColoringDestroy,MatFDColoringView);

475:   c->ctype = iscoloring->ctype;

477:   if (mat->ops->fdcoloringcreate) {
478:     (*mat->ops->fdcoloringcreate)(mat,iscoloring,c);
479:   } else SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Code not yet written for matrix type %s",((PetscObject)mat)->type_name);

481:   MatCreateVecs(mat,NULL,&c->w1);
482:   PetscLogObjectParent((PetscObject)c,(PetscObject)c->w1);
483:   VecDuplicate(c->w1,&c->w2);
484:   PetscLogObjectParent((PetscObject)c,(PetscObject)c->w2);

486:   c->error_rel    = PETSC_SQRT_MACHINE_EPSILON;
487:   c->umin         = 100.0*PETSC_SQRT_MACHINE_EPSILON;
488:   c->currentcolor = -1;
489:   c->htype        = "wp";
490:   c->fset         = PETSC_FALSE;
491:   c->setupcalled  = PETSC_FALSE;

493:   *color = c;
494:   PetscObjectCompose((PetscObject)mat,"SNESMatFDColoring",(PetscObject)c);
495:   PetscLogEventEnd(MAT_FDColoringCreate,mat,0,0,0);
496:   return(0);
497: }

499: /*@
500:     MatFDColoringDestroy - Destroys a matrix coloring context that was created
501:     via MatFDColoringCreate().

503:     Collective on MatFDColoring

505:     Input Parameter:
506: .   c - coloring context

508:     Level: intermediate

510: .seealso: MatFDColoringCreate()
511: @*/
512: PetscErrorCode  MatFDColoringDestroy(MatFDColoring *c)
513: {
515:   PetscInt       i;
516:   MatFDColoring  color = *c;

519:   if (!*c) return(0);
520:   if (--((PetscObject)color)->refct > 0) {*c = 0; return(0);}

522:   for (i=0; i<color->ncolors; i++) {
523:     PetscFree(color->columns[i]);
524:   }
525:   PetscFree(color->ncolumns);
526:   PetscFree(color->columns);
527:   PetscFree(color->nrows);
528:   if (color->htype[0] == 'w') {
529:     PetscFree(color->matentry2);
530:   } else {
531:     PetscFree(color->matentry);
532:   }
533:   PetscFree(color->dy);
534:   if (color->vscale) {VecDestroy(&color->vscale);}
535:   VecDestroy(&color->w1);
536:   VecDestroy(&color->w2);
537:   VecDestroy(&color->w3);
539:   return(0);
540: }

542: /*@C
543:     MatFDColoringGetPerturbedColumns - Returns the indices of the columns that
544:       that are currently being perturbed.

546:     Not Collective

548:     Input Parameters:
549: .   coloring - coloring context created with MatFDColoringCreate()

551:     Output Parameters:
552: +   n - the number of local columns being perturbed
553: -   cols - the column indices, in global numbering

557:    Fortran Note:
558:    This routine has a different interface for Fortran
559: \$     #include <petsc/finclude/petscmat.h>
560: \$          use petscmat
561: \$          PetscInt, pointer :: array(:)
562: \$          PetscErrorCode  ierr
563: \$          MatFDColoring   i
564: \$          call MatFDColoringGetPerturbedColumnsF90(i,array,ierr)
565: \$      use the entries of array ...
566: \$          call MatFDColoringRestorePerturbedColumnsF90(i,array,ierr)

568: .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView(), MatFDColoringApply()

570: .keywords: coloring, Jacobian, finite differences
571: @*/
572: PetscErrorCode  MatFDColoringGetPerturbedColumns(MatFDColoring coloring,PetscInt *n,const PetscInt *cols[])
573: {
575:   if (coloring->currentcolor >= 0) {
576:     *n    = coloring->ncolumns[coloring->currentcolor];
577:     *cols = coloring->columns[coloring->currentcolor];
578:   } else {
579:     *n = 0;
580:   }
581:   return(0);
582: }

584: /*@
585:     MatFDColoringApply - Given a matrix for which a MatFDColoring context
586:     has been created, computes the Jacobian for a function via finite differences.

588:     Collective on MatFDColoring

590:     Input Parameters:
591: +   mat - location to store Jacobian
592: .   coloring - coloring context created with MatFDColoringCreate()
593: .   x1 - location at which Jacobian is to be computed
594: -   sctx - context required by function, if this is being used with the SNES solver then it is SNES object, otherwise it is null

596:     Options Database Keys:
597: +    -mat_fd_type - "wp" or "ds"  (see MATMFFD_WP or MATMFFD_DS)
598: .    -mat_fd_coloring_view - Activates basic viewing or coloring
599: .    -mat_fd_coloring_view draw - Activates drawing of coloring
600: -    -mat_fd_coloring_view ::ascii_info - Activates viewing of coloring info

602:     Level: intermediate

604: .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView(), MatFDColoringSetFunction()

606: .keywords: coloring, Jacobian, finite differences
607: @*/
608: PetscErrorCode  MatFDColoringApply(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
609: {
611:   PetscBool      flg = PETSC_FALSE;

617:   if (!coloring->f) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_WRONGSTATE,"Must call MatFDColoringSetFunction()");
618:   if (!J->ops->fdcoloringapply) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not supported for this matrix type %s",((PetscObject)J)->type_name);
619:   if (!coloring->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call MatFDColoringSetUp()");

621:   MatSetUnfactored(J);
622:   PetscOptionsGetBool(((PetscObject)coloring)->options,NULL,"-mat_fd_coloring_dont_rezero",&flg,NULL);
623:   if (flg) {
624:     PetscInfo(coloring,"Not calling MatZeroEntries()\n");
625:   } else {
626:     PetscBool assembled;
627:     MatAssembled(J,&assembled);
628:     if (assembled) {
629:       MatZeroEntries(J);
630:     }
631:   }

633:   PetscLogEventBegin(MAT_FDColoringApply,coloring,J,x1,0);
634:   (*J->ops->fdcoloringapply)(J,coloring,x1,sctx);
635:   PetscLogEventEnd(MAT_FDColoringApply,coloring,J,x1,0);
636:   if (!coloring->viewed) {
637:     MatFDColoringViewFromOptions(coloring,NULL,"-mat_fd_coloring_view");
638:     coloring->viewed = PETSC_TRUE;
639:   }
640:   return(0);
641: }
```