xref: /petsc/src/mat/matfd/fdmatrix.c (revision 72ce74bd30d5d09d1371a3eb387704f4af395d1a)
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 "src/mat/matimpl.h"        /*I "petscmat.h" I*/
7 
8 /* Logging support */
9 int MAT_FDCOLORING_COOKIE = 0;
10 
11 #undef __FUNCT__
12 #define __FUNCT__ "MatFDColoringSetF"
13 PetscErrorCode MatFDColoringSetF(MatFDColoring fd,Vec F)
14 {
15   PetscFunctionBegin;
16   fd->F = F;
17   PetscFunctionReturn(0);
18 }
19 
20 #undef __FUNCT__
21 #define __FUNCT__ "MatFDColoringView_Draw_Zoom"
22 static int MatFDColoringView_Draw_Zoom(PetscDraw draw,void *Aa)
23 {
24   MatFDColoring fd = (MatFDColoring)Aa;
25   PetscErrorCode ierr;
26   int i,j;
27   PetscReal     x,y;
28 
29   PetscFunctionBegin;
30 
31   /* loop over colors  */
32   for (i=0; i<fd->ncolors; i++) {
33     for (j=0; j<fd->nrows[i]; j++) {
34       y = fd->M - fd->rows[i][j] - fd->rstart;
35       x = fd->columnsforrow[i][j];
36       ierr = PetscDrawRectangle(draw,x,y,x+1,y+1,i+1,i+1,i+1,i+1);CHKERRQ(ierr);
37     }
38   }
39   PetscFunctionReturn(0);
40 }
41 
42 #undef __FUNCT__
43 #define __FUNCT__ "MatFDColoringView_Draw"
44 static int MatFDColoringView_Draw(MatFDColoring fd,PetscViewer viewer)
45 {
46   PetscErrorCode ierr;
47   PetscTruth  isnull;
48   PetscDraw   draw;
49   PetscReal   xr,yr,xl,yl,h,w;
50 
51   PetscFunctionBegin;
52   ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr);
53   ierr = PetscDrawIsNull(draw,&isnull);CHKERRQ(ierr); if (isnull) PetscFunctionReturn(0);
54 
55   ierr = PetscObjectCompose((PetscObject)fd,"Zoomviewer",(PetscObject)viewer);CHKERRQ(ierr);
56 
57   xr  = fd->N; yr = fd->M; h = yr/10.0; w = xr/10.0;
58   xr += w;     yr += h;    xl = -w;     yl = -h;
59   ierr = PetscDrawSetCoordinates(draw,xl,yl,xr,yr);CHKERRQ(ierr);
60   ierr = PetscDrawZoom(draw,MatFDColoringView_Draw_Zoom,fd);CHKERRQ(ierr);
61   ierr = PetscObjectCompose((PetscObject)fd,"Zoomviewer",PETSC_NULL);CHKERRQ(ierr);
62   PetscFunctionReturn(0);
63 }
64 
65 #undef __FUNCT__
66 #define __FUNCT__ "MatFDColoringView"
67 /*@C
68    MatFDColoringView - Views a finite difference coloring context.
69 
70    Collective on MatFDColoring
71 
72    Input  Parameters:
73 +  c - the coloring context
74 -  viewer - visualization context
75 
76    Level: intermediate
77 
78    Notes:
79    The available visualization contexts include
80 +     PETSC_VIEWER_STDOUT_SELF - standard output (default)
81 .     PETSC_VIEWER_STDOUT_WORLD - synchronized standard
82         output where only the first processor opens
83         the file.  All other processors send their
84         data to the first processor to print.
85 -     PETSC_VIEWER_DRAW_WORLD - graphical display of nonzero structure
86 
87    Notes:
88      Since PETSc uses only a small number of basic colors (currently 33), if the coloring
89    involves more than 33 then some seemingly identical colors are displayed making it look
90    like an illegal coloring. This is just a graphical artifact.
91 
92 .seealso: MatFDColoringCreate()
93 
94 .keywords: Mat, finite differences, coloring, view
95 @*/
96 PetscErrorCode MatFDColoringView(MatFDColoring c,PetscViewer viewer)
97 {
98   int               i,j,ierr;
99   PetscTruth        isdraw,iascii;
100   PetscViewerFormat format;
101 
102   PetscFunctionBegin;
103   PetscValidHeaderSpecific(c,MAT_FDCOLORING_COOKIE,1);
104   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(c->comm);
105   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_COOKIE,2);
106   PetscCheckSameComm(c,1,viewer,2);
107 
108   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_DRAW,&isdraw);CHKERRQ(ierr);
109   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
110   if (isdraw) {
111     ierr = MatFDColoringView_Draw(c,viewer);CHKERRQ(ierr);
112   } else if (iascii) {
113     ierr = PetscViewerASCIIPrintf(viewer,"MatFDColoring Object:\n");CHKERRQ(ierr);
114     ierr = PetscViewerASCIIPrintf(viewer,"  Error tolerance=%g\n",c->error_rel);CHKERRQ(ierr);
115     ierr = PetscViewerASCIIPrintf(viewer,"  Umin=%g\n",c->umin);CHKERRQ(ierr);
116     ierr = PetscViewerASCIIPrintf(viewer,"  Number of colors=%d\n",c->ncolors);CHKERRQ(ierr);
117 
118     ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
119     if (format != PETSC_VIEWER_ASCII_INFO) {
120       for (i=0; i<c->ncolors; i++) {
121         ierr = PetscViewerASCIIPrintf(viewer,"  Information for color %d\n",i);CHKERRQ(ierr);
122         ierr = PetscViewerASCIIPrintf(viewer,"    Number of columns %d\n",c->ncolumns[i]);CHKERRQ(ierr);
123         for (j=0; j<c->ncolumns[i]; j++) {
124           ierr = PetscViewerASCIIPrintf(viewer,"      %d\n",c->columns[i][j]);CHKERRQ(ierr);
125         }
126         ierr = PetscViewerASCIIPrintf(viewer,"    Number of rows %d\n",c->nrows[i]);CHKERRQ(ierr);
127         for (j=0; j<c->nrows[i]; j++) {
128           ierr = PetscViewerASCIIPrintf(viewer,"      %d %d \n",c->rows[i][j],c->columnsforrow[i][j]);CHKERRQ(ierr);
129         }
130       }
131     }
132     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
133   } else {
134     SETERRQ1(1,"Viewer type %s not supported for MatFDColoring",((PetscObject)viewer)->type_name);
135   }
136   PetscFunctionReturn(0);
137 }
138 
139 #undef __FUNCT__
140 #define __FUNCT__ "MatFDColoringSetParameters"
141 /*@
142    MatFDColoringSetParameters - Sets the parameters for the sparse approximation of
143    a Jacobian matrix using finite differences.
144 
145    Collective on MatFDColoring
146 
147    The Jacobian is estimated with the differencing approximation
148 .vb
149        F'(u)_{:,i} = [F(u+h*dx_{i}) - F(u)]/h where
150        h = error_rel*u[i]                 if  abs(u[i]) > umin
151          = +/- error_rel*umin             otherwise, with +/- determined by the sign of u[i]
152        dx_{i} = (0, ... 1, .... 0)
153 .ve
154 
155    Input Parameters:
156 +  coloring - the coloring context
157 .  error_rel - relative error
158 -  umin - minimum allowable u-value magnitude
159 
160    Level: advanced
161 
162 .keywords: Mat, finite differences, coloring, set, parameters
163 
164 .seealso: MatFDColoringCreate()
165 @*/
166 PetscErrorCode MatFDColoringSetParameters(MatFDColoring matfd,PetscReal error,PetscReal umin)
167 {
168   PetscFunctionBegin;
169   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE,1);
170 
171   if (error != PETSC_DEFAULT) matfd->error_rel = error;
172   if (umin != PETSC_DEFAULT)  matfd->umin      = umin;
173   PetscFunctionReturn(0);
174 }
175 
176 #undef __FUNCT__
177 #define __FUNCT__ "MatFDColoringSetFrequency"
178 /*@
179    MatFDColoringSetFrequency - Sets the frequency for computing new Jacobian
180    matrices.
181 
182    Collective on MatFDColoring
183 
184    Input Parameters:
185 +  coloring - the coloring context
186 -  freq - frequency (default is 1)
187 
188    Options Database Keys:
189 .  -mat_fd_coloring_freq <freq>  - Sets coloring frequency
190 
191    Level: advanced
192 
193    Notes:
194    Using a modified Newton strategy, where the Jacobian remains fixed for several
195    iterations, can be cost effective in terms of overall nonlinear solution
196    efficiency.  This parameter indicates that a new Jacobian will be computed every
197    <freq> nonlinear iterations.
198 
199 .keywords: Mat, finite differences, coloring, set, frequency
200 
201 .seealso: MatFDColoringCreate(), MatFDColoringGetFrequency(), MatFDColoringSetRecompute()
202 @*/
203 PetscErrorCode MatFDColoringSetFrequency(MatFDColoring matfd,int freq)
204 {
205   PetscFunctionBegin;
206   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE,1);
207 
208   matfd->freq = freq;
209   PetscFunctionReturn(0);
210 }
211 
212 #undef __FUNCT__
213 #define __FUNCT__ "MatFDColoringGetFrequency"
214 /*@
215    MatFDColoringGetFrequency - Gets the frequency for computing new Jacobian
216    matrices.
217 
218    Not Collective
219 
220    Input Parameters:
221 .  coloring - the coloring context
222 
223    Output Parameters:
224 .  freq - frequency (default is 1)
225 
226    Options Database Keys:
227 .  -mat_fd_coloring_freq <freq> - Sets coloring frequency
228 
229    Level: advanced
230 
231    Notes:
232    Using a modified Newton strategy, where the Jacobian remains fixed for several
233    iterations, can be cost effective in terms of overall nonlinear solution
234    efficiency.  This parameter indicates that a new Jacobian will be computed every
235    <freq> nonlinear iterations.
236 
237 .keywords: Mat, finite differences, coloring, get, frequency
238 
239 .seealso: MatFDColoringSetFrequency()
240 @*/
241 PetscErrorCode MatFDColoringGetFrequency(MatFDColoring matfd,int *freq)
242 {
243   PetscFunctionBegin;
244   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE,1);
245   *freq = matfd->freq;
246   PetscFunctionReturn(0);
247 }
248 
249 #undef __FUNCT__
250 #define __FUNCT__ "MatFDColoringSetFunction"
251 /*@C
252    MatFDColoringSetFunction - Sets the function to use for computing the Jacobian.
253 
254    Collective on MatFDColoring
255 
256    Input Parameters:
257 +  coloring - the coloring context
258 .  f - the function
259 -  fctx - the optional user-defined function context
260 
261    Level: intermediate
262 
263    Notes:
264     In Fortran you must call MatFDColoringSetFunctionSNES() for a coloring object to
265   be used with the SNES solvers and MatFDColoringSetFunctionTS() if it is to be used
266   with the TS solvers.
267 
268 .keywords: Mat, Jacobian, finite differences, set, function
269 @*/
270 PetscErrorCode MatFDColoringSetFunction(MatFDColoring matfd,int (*f)(void),void *fctx)
271 {
272   PetscFunctionBegin;
273   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE,1);
274   matfd->f    = f;
275   matfd->fctx = fctx;
276   PetscFunctionReturn(0);
277 }
278 
279 #undef __FUNCT__
280 #define __FUNCT__ "MatFDColoringSetFromOptions"
281 /*@
282    MatFDColoringSetFromOptions - Sets coloring finite difference parameters from
283    the options database.
284 
285    Collective on MatFDColoring
286 
287    The Jacobian, F'(u), is estimated with the differencing approximation
288 .vb
289        F'(u)_{:,i} = [F(u+h*dx_{i}) - F(u)]/h where
290        h = error_rel*u[i]                 if  abs(u[i]) > umin
291          = +/- error_rel*umin             otherwise, with +/- determined by the sign of u[i]
292        dx_{i} = (0, ... 1, .... 0)
293 .ve
294 
295    Input Parameter:
296 .  coloring - the coloring context
297 
298    Options Database Keys:
299 +  -mat_fd_coloring_err <err> - Sets <err> (square root
300            of relative error in the function)
301 .  -mat_fd_coloring_umin <umin> - Sets umin, the minimum allowable u-value magnitude
302 .  -mat_fd_coloring_freq <freq> - Sets frequency of computing a new Jacobian
303 .  -mat_fd_coloring_view - Activates basic viewing
304 .  -mat_fd_coloring_view_info - Activates viewing info
305 -  -mat_fd_coloring_view_draw - Activates drawing
306 
307     Level: intermediate
308 
309 .keywords: Mat, finite differences, parameters
310 
311 .seealso: MatFDColoringCreate(), MatFDColoringView(), MatFDColoringSetParameters()
312 
313 @*/
314 PetscErrorCode MatFDColoringSetFromOptions(MatFDColoring matfd)
315 {
316   PetscErrorCode ierr;
317 
318   PetscFunctionBegin;
319   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE,1);
320 
321   ierr = PetscOptionsBegin(matfd->comm,matfd->prefix,"Jacobian computation via finite differences option","MatFD");CHKERRQ(ierr);
322     ierr = PetscOptionsReal("-mat_fd_coloring_err","Square root of relative error in function","MatFDColoringSetParameters",matfd->error_rel,&matfd->error_rel,0);CHKERRQ(ierr);
323     ierr = PetscOptionsReal("-mat_fd_coloring_umin","Minimum allowable u magnitude","MatFDColoringSetParameters",matfd->umin,&matfd->umin,0);CHKERRQ(ierr);
324     ierr = PetscOptionsInt("-mat_fd_coloring_freq","How often Jacobian is recomputed","MatFDColoringSetFrequency",matfd->freq,&matfd->freq,0);CHKERRQ(ierr);
325     /* not used here; but so they are presented in the GUI */
326     ierr = PetscOptionsName("-mat_fd_coloring_view","Print entire datastructure used for Jacobian","None",0);CHKERRQ(ierr);
327     ierr = PetscOptionsName("-mat_fd_coloring_view_info","Print number of colors etc for Jacobian","None",0);CHKERRQ(ierr);
328     ierr = PetscOptionsName("-mat_fd_coloring_view_draw","Plot nonzero structure ofJacobian","None",0);CHKERRQ(ierr);
329   PetscOptionsEnd();CHKERRQ(ierr);
330   PetscFunctionReturn(0);
331 }
332 
333 #undef __FUNCT__
334 #define __FUNCT__ "MatFDColoringView_Private"
335 PetscErrorCode MatFDColoringView_Private(MatFDColoring fd)
336 {
337   PetscErrorCode ierr;
338   PetscTruth flg;
339 
340   PetscFunctionBegin;
341   ierr = PetscOptionsHasName(PETSC_NULL,"-mat_fd_coloring_view",&flg);CHKERRQ(ierr);
342   if (flg) {
343     ierr = MatFDColoringView(fd,PETSC_VIEWER_STDOUT_(fd->comm));CHKERRQ(ierr);
344   }
345   ierr = PetscOptionsHasName(PETSC_NULL,"-mat_fd_coloring_view_info",&flg);CHKERRQ(ierr);
346   if (flg) {
347     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_(fd->comm),PETSC_VIEWER_ASCII_INFO);CHKERRQ(ierr);
348     ierr = MatFDColoringView(fd,PETSC_VIEWER_STDOUT_(fd->comm));CHKERRQ(ierr);
349     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_(fd->comm));CHKERRQ(ierr);
350   }
351   ierr = PetscOptionsHasName(PETSC_NULL,"-mat_fd_coloring_view_draw",&flg);CHKERRQ(ierr);
352   if (flg) {
353     ierr = MatFDColoringView(fd,PETSC_VIEWER_DRAW_(fd->comm));CHKERRQ(ierr);
354     ierr = PetscViewerFlush(PETSC_VIEWER_DRAW_(fd->comm));CHKERRQ(ierr);
355   }
356   PetscFunctionReturn(0);
357 }
358 
359 #undef __FUNCT__
360 #define __FUNCT__ "MatFDColoringCreate"
361 /*@C
362    MatFDColoringCreate - Creates a matrix coloring context for finite difference
363    computation of Jacobians.
364 
365    Collective on Mat
366 
367    Input Parameters:
368 +  mat - the matrix containing the nonzero structure of the Jacobian
369 -  iscoloring - the coloring of the matrix
370 
371     Output Parameter:
372 .   color - the new coloring context
373 
374     Level: intermediate
375 
376 .seealso: MatFDColoringDestroy(),SNESDefaultComputeJacobianColor(), ISColoringCreate(),
377           MatFDColoringSetFunction(), MatFDColoringSetFromOptions(), MatFDColoringApply(),
378           MatFDColoringSetFrequency(), MatFDColoringSetRecompute(), MatFDColoringView(),
379           MatFDColoringSetParameters()
380 @*/
381 PetscErrorCode MatFDColoringCreate(Mat mat,ISColoring iscoloring,MatFDColoring *color)
382 {
383   MatFDColoring c;
384   MPI_Comm      comm;
385   PetscErrorCode ierr;
386   int M,N;
387 
388   PetscFunctionBegin;
389   ierr = PetscLogEventBegin(MAT_FDColoringCreate,mat,0,0,0);CHKERRQ(ierr);
390   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
391   if (M != N) SETERRQ(PETSC_ERR_SUP,"Only for square matrices");
392 
393   ierr = PetscObjectGetComm((PetscObject)mat,&comm);CHKERRQ(ierr);
394   PetscHeaderCreate(c,_p_MatFDColoring,int,MAT_FDCOLORING_COOKIE,0,"MatFDColoring",comm,MatFDColoringDestroy,MatFDColoringView);
395   PetscLogObjectCreate(c);
396 
397   if (mat->ops->fdcoloringcreate) {
398     ierr = (*mat->ops->fdcoloringcreate)(mat,iscoloring,c);CHKERRQ(ierr);
399   } else {
400     SETERRQ(PETSC_ERR_SUP,"Code not yet written for this matrix type");
401   }
402 
403   c->error_rel         = PETSC_SQRT_MACHINE_EPSILON;
404   c->umin              = 100.0*PETSC_SQRT_MACHINE_EPSILON;
405   c->freq              = 1;
406   c->usersetsrecompute = PETSC_FALSE;
407   c->recompute         = PETSC_FALSE;
408   c->currentcolor      = -1;
409 
410   *color = c;
411   ierr = PetscLogEventEnd(MAT_FDColoringCreate,mat,0,0,0);CHKERRQ(ierr);
412   PetscFunctionReturn(0);
413 }
414 
415 #undef __FUNCT__
416 #define __FUNCT__ "MatFDColoringDestroy"
417 /*@C
418     MatFDColoringDestroy - Destroys a matrix coloring context that was created
419     via MatFDColoringCreate().
420 
421     Collective on MatFDColoring
422 
423     Input Parameter:
424 .   c - coloring context
425 
426     Level: intermediate
427 
428 .seealso: MatFDColoringCreate()
429 @*/
430 PetscErrorCode MatFDColoringDestroy(MatFDColoring c)
431 {
432   int i,ierr;
433 
434   PetscFunctionBegin;
435   if (--c->refct > 0) PetscFunctionReturn(0);
436 
437   for (i=0; i<c->ncolors; i++) {
438     if (c->columns[i])         {ierr = PetscFree(c->columns[i]);CHKERRQ(ierr);}
439     if (c->rows[i])            {ierr = PetscFree(c->rows[i]);CHKERRQ(ierr);}
440     if (c->columnsforrow[i])   {ierr = PetscFree(c->columnsforrow[i]);CHKERRQ(ierr);}
441     if (c->vscaleforrow && c->vscaleforrow[i]) {ierr = PetscFree(c->vscaleforrow[i]);CHKERRQ(ierr);}
442   }
443   ierr = PetscFree(c->ncolumns);CHKERRQ(ierr);
444   ierr = PetscFree(c->columns);CHKERRQ(ierr);
445   ierr = PetscFree(c->nrows);CHKERRQ(ierr);
446   ierr = PetscFree(c->rows);CHKERRQ(ierr);
447   ierr = PetscFree(c->columnsforrow);CHKERRQ(ierr);
448   if (c->vscaleforrow) {ierr = PetscFree(c->vscaleforrow);CHKERRQ(ierr);}
449   if (c->vscale)       {ierr = VecDestroy(c->vscale);CHKERRQ(ierr);}
450   if (c->w1) {
451     ierr = VecDestroy(c->w1);CHKERRQ(ierr);
452     ierr = VecDestroy(c->w2);CHKERRQ(ierr);
453     ierr = VecDestroy(c->w3);CHKERRQ(ierr);
454   }
455   PetscLogObjectDestroy(c);
456   PetscHeaderDestroy(c);
457   PetscFunctionReturn(0);
458 }
459 
460 #undef __FUNCT__
461 #define __FUNCT__ "MatFDColoringGetPerturbedColumns"
462 /*@C
463     MatFDColoringGetPerturbedColumns - Returns the indices of the columns that
464       that are currently being perturbed.
465 
466     Not Collective
467 
468     Input Parameters:
469 .   coloring - coloring context created with MatFDColoringCreate()
470 
471     Output Parameters:
472 +   n - the number of local columns being perturbed
473 -   cols - the column indices, in global numbering
474 
475    Level: intermediate
476 
477 .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView(), MatFDColoringApply()
478 
479 .keywords: coloring, Jacobian, finite differences
480 @*/
481 EXTERN PetscErrorCode MatFDColoringGetPerturbedColumns(MatFDColoring coloring,int *n,int *cols[])
482 {
483   PetscFunctionBegin;
484   if (coloring->currentcolor >= 0) {
485     *n    = coloring->ncolumns[coloring->currentcolor];
486     *cols = coloring->columns[coloring->currentcolor];
487   } else {
488     *n = 0;
489   }
490   PetscFunctionReturn(0);
491 }
492 
493 #undef __FUNCT__
494 #define __FUNCT__ "MatFDColoringApply"
495 /*@
496     MatFDColoringApply - Given a matrix for which a MatFDColoring context
497     has been created, computes the Jacobian for a function via finite differences.
498 
499     Collective on MatFDColoring
500 
501     Input Parameters:
502 +   mat - location to store Jacobian
503 .   coloring - coloring context created with MatFDColoringCreate()
504 .   x1 - location at which Jacobian is to be computed
505 -   sctx - optional context required by function (actually a SNES context)
506 
507     Options Database Keys:
508 +    -mat_fd_coloring_freq <freq> - Sets coloring frequency
509 .    -mat_fd_coloring_view - Activates basic viewing or coloring
510 .    -mat_fd_coloring_view_draw - Activates drawing of coloring
511 -    -mat_fd_coloring_view_info - Activates viewing of coloring info
512 
513     Level: intermediate
514 
515 .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView()
516 
517 .keywords: coloring, Jacobian, finite differences
518 @*/
519 PetscErrorCode MatFDColoringApply(Mat J,MatFDColoring coloring,Vec x1,MatStructure *flag,void *sctx)
520 {
521   int           (*f)(void*,Vec,Vec,void*) = (int (*)(void*,Vec,Vec,void *))coloring->f;
522   int           k,ierr,N,start,end,l,row,col,srow,**vscaleforrow,m1,m2;
523   PetscScalar   dx,mone = -1.0,*y,*xx,*w3_array;
524   PetscScalar   *vscale_array;
525   PetscReal     epsilon = coloring->error_rel,umin = coloring->umin;
526   Vec           w1,w2,w3;
527   void          *fctx = coloring->fctx;
528   PetscTruth    flg;
529 
530 
531   PetscFunctionBegin;
532   PetscValidHeaderSpecific(J,MAT_COOKIE,1);
533   PetscValidHeaderSpecific(coloring,MAT_FDCOLORING_COOKIE,2);
534   PetscValidHeaderSpecific(x1,VEC_COOKIE,3);
535 
536   if (coloring->usersetsrecompute) {
537     if (!coloring->recompute) {
538       *flag = SAME_PRECONDITIONER;
539       PetscLogInfo(J,"MatFDColoringApply:Skipping Jacobian, since user called MatFDColorSetRecompute()\n");
540       PetscFunctionReturn(0);
541     } else {
542       coloring->recompute = PETSC_FALSE;
543     }
544   }
545 
546   ierr = PetscLogEventBegin(MAT_FDColoringApply,coloring,J,x1,0);CHKERRQ(ierr);
547   if (J->ops->fdcoloringapply) {
548     ierr = (*J->ops->fdcoloringapply)(J,coloring,x1,flag,sctx);CHKERRQ(ierr);
549   } else {
550 
551     if (!coloring->w1) {
552       ierr = VecDuplicate(x1,&coloring->w1);CHKERRQ(ierr);
553       PetscLogObjectParent(coloring,coloring->w1);
554       ierr = VecDuplicate(x1,&coloring->w2);CHKERRQ(ierr);
555       PetscLogObjectParent(coloring,coloring->w2);
556       ierr = VecDuplicate(x1,&coloring->w3);CHKERRQ(ierr);
557       PetscLogObjectParent(coloring,coloring->w3);
558     }
559     w1 = coloring->w1; w2 = coloring->w2; w3 = coloring->w3;
560 
561     ierr = MatSetUnfactored(J);CHKERRQ(ierr);
562     ierr = PetscOptionsHasName(PETSC_NULL,"-mat_fd_coloring_dont_rezero",&flg);CHKERRQ(ierr);
563     if (flg) {
564       PetscLogInfo(coloring,"MatFDColoringApply: Not calling MatZeroEntries()\n");
565     } else {
566       ierr = MatZeroEntries(J);CHKERRQ(ierr);
567     }
568 
569     ierr = VecGetOwnershipRange(x1,&start,&end);CHKERRQ(ierr);
570     ierr = VecGetSize(x1,&N);CHKERRQ(ierr);
571 
572     /*
573       This is a horrible, horrible, hack. See DMMGComputeJacobian_Multigrid() it inproperly sets
574       coloring->F for the coarser grids from the finest
575     */
576     if (coloring->F) {
577       ierr = VecGetLocalSize(coloring->F,&m1);CHKERRQ(ierr);
578       ierr = VecGetLocalSize(w1,&m2);CHKERRQ(ierr);
579       if (m1 != m2) {
580 	coloring->F = 0;
581       }
582     }
583 
584     if (coloring->F) {
585       w1          = coloring->F; /* use already computed value of function */
586       coloring->F = 0;
587     } else {
588       ierr = PetscLogEventBegin(MAT_FDColoringFunction,0,0,0,0);CHKERRQ(ierr);
589       ierr = (*f)(sctx,x1,w1,fctx);CHKERRQ(ierr);
590       ierr = PetscLogEventEnd(MAT_FDColoringFunction,0,0,0,0);CHKERRQ(ierr);
591     }
592 
593     /*
594        Compute all the scale factors and share with other processors
595     */
596     ierr = VecGetArray(x1,&xx);CHKERRQ(ierr);xx = xx - start;
597     ierr = VecGetArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);vscale_array = vscale_array - start;
598     for (k=0; k<coloring->ncolors; k++) {
599       /*
600 	Loop over each column associated with color adding the
601 	perturbation to the vector w3.
602       */
603       for (l=0; l<coloring->ncolumns[k]; l++) {
604 	col = coloring->columns[k][l];    /* column of the matrix we are probing for */
605 	dx  = xx[col];
606 	if (dx == 0.0) dx = 1.0;
607 #if !defined(PETSC_USE_COMPLEX)
608 	if (dx < umin && dx >= 0.0)      dx = umin;
609 	else if (dx < 0.0 && dx > -umin) dx = -umin;
610 #else
611 	if (PetscAbsScalar(dx) < umin && PetscRealPart(dx) >= 0.0)     dx = umin;
612 	else if (PetscRealPart(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
613 #endif
614 	dx                *= epsilon;
615 	vscale_array[col] = 1.0/dx;
616       }
617     }
618     vscale_array = vscale_array + start;ierr = VecRestoreArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);
619     ierr = VecGhostUpdateBegin(coloring->vscale,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
620     ierr = VecGhostUpdateEnd(coloring->vscale,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
621 
622     /*  ierr = VecView(coloring->vscale,PETSC_VIEWER_STDOUT_WORLD);
623 	ierr = VecView(x1,PETSC_VIEWER_STDOUT_WORLD);*/
624 
625     if (coloring->vscaleforrow) vscaleforrow = coloring->vscaleforrow;
626     else                        vscaleforrow = coloring->columnsforrow;
627 
628     ierr = VecGetArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);
629     /*
630       Loop over each color
631     */
632     for (k=0; k<coloring->ncolors; k++) {
633       coloring->currentcolor = k;
634       ierr = VecCopy(x1,w3);CHKERRQ(ierr);
635       ierr = VecGetArray(w3,&w3_array);CHKERRQ(ierr);w3_array = w3_array - start;
636       /*
637 	Loop over each column associated with color adding the
638 	perturbation to the vector w3.
639       */
640       for (l=0; l<coloring->ncolumns[k]; l++) {
641 	col = coloring->columns[k][l];    /* column of the matrix we are probing for */
642 	dx  = xx[col];
643 	if (dx == 0.0) dx = 1.0;
644 #if !defined(PETSC_USE_COMPLEX)
645 	if (dx < umin && dx >= 0.0)      dx = umin;
646 	else if (dx < 0.0 && dx > -umin) dx = -umin;
647 #else
648 	if (PetscAbsScalar(dx) < umin && PetscRealPart(dx) >= 0.0)     dx = umin;
649 	else if (PetscRealPart(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
650 #endif
651 	dx            *= epsilon;
652 	if (!PetscAbsScalar(dx)) SETERRQ(1,"Computed 0 differencing parameter");
653 	w3_array[col] += dx;
654       }
655       w3_array = w3_array + start; ierr = VecRestoreArray(w3,&w3_array);CHKERRQ(ierr);
656 
657       /*
658 	Evaluate function at x1 + dx (here dx is a vector of perturbations)
659       */
660 
661       ierr = PetscLogEventBegin(MAT_FDColoringFunction,0,0,0,0);CHKERRQ(ierr);
662       ierr = (*f)(sctx,w3,w2,fctx);CHKERRQ(ierr);
663       ierr = PetscLogEventEnd(MAT_FDColoringFunction,0,0,0,0);CHKERRQ(ierr);
664       ierr = VecAXPY(&mone,w1,w2);CHKERRQ(ierr);
665 
666       /*
667 	Loop over rows of vector, putting results into Jacobian matrix
668       */
669       ierr = VecGetArray(w2,&y);CHKERRQ(ierr);
670       for (l=0; l<coloring->nrows[k]; l++) {
671 	row    = coloring->rows[k][l];
672 	col    = coloring->columnsforrow[k][l];
673 	y[row] *= vscale_array[vscaleforrow[k][l]];
674 	srow   = row + start;
675 	ierr   = MatSetValues(J,1,&srow,1,&col,y+row,INSERT_VALUES);CHKERRQ(ierr);
676       }
677       ierr = VecRestoreArray(w2,&y);CHKERRQ(ierr);
678     }
679     coloring->currentcolor = -1;
680     ierr = VecRestoreArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);
681     xx = xx + start; ierr  = VecRestoreArray(x1,&xx);CHKERRQ(ierr);
682     ierr  = MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
683     ierr  = MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
684   }
685   ierr = PetscLogEventEnd(MAT_FDColoringApply,coloring,J,x1,0);CHKERRQ(ierr);
686 
687   ierr = PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test",&flg);CHKERRQ(ierr);
688   if (flg) {
689     ierr = MatNullSpaceTest(J->nullsp,J);CHKERRQ(ierr);
690   }
691   ierr = MatFDColoringView_Private(coloring);CHKERRQ(ierr);
692 
693   PetscFunctionReturn(0);
694 }
695 
696 #undef __FUNCT__
697 #define __FUNCT__ "MatFDColoringApplyTS"
698 /*@
699     MatFDColoringApplyTS - Given a matrix for which a MatFDColoring context
700     has been created, computes the Jacobian for a function via finite differences.
701 
702    Collective on Mat, MatFDColoring, and Vec
703 
704     Input Parameters:
705 +   mat - location to store Jacobian
706 .   coloring - coloring context created with MatFDColoringCreate()
707 .   x1 - location at which Jacobian is to be computed
708 -   sctx - optional context required by function (actually a SNES context)
709 
710    Options Database Keys:
711 .  -mat_fd_coloring_freq <freq> - Sets coloring frequency
712 
713    Level: intermediate
714 
715 .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView()
716 
717 .keywords: coloring, Jacobian, finite differences
718 @*/
719 PetscErrorCode MatFDColoringApplyTS(Mat J,MatFDColoring coloring,PetscReal t,Vec x1,MatStructure *flag,void *sctx)
720 {
721   int           (*f)(void*,PetscReal,Vec,Vec,void*)=(int (*)(void*,PetscReal,Vec,Vec,void *))coloring->f;
722   int           k,ierr,N,start,end,l,row,col,srow,**vscaleforrow;
723   PetscScalar   dx,mone = -1.0,*y,*xx,*w3_array;
724   PetscScalar   *vscale_array;
725   PetscReal     epsilon = coloring->error_rel,umin = coloring->umin;
726   Vec           w1,w2,w3;
727   void          *fctx = coloring->fctx;
728   PetscTruth    flg;
729 
730   PetscFunctionBegin;
731   PetscValidHeaderSpecific(J,MAT_COOKIE,1);
732   PetscValidHeaderSpecific(coloring,MAT_FDCOLORING_COOKIE,2);
733   PetscValidHeaderSpecific(x1,VEC_COOKIE,4);
734 
735   ierr = PetscLogEventBegin(MAT_FDColoringApply,coloring,J,x1,0);CHKERRQ(ierr);
736   if (!coloring->w1) {
737     ierr = VecDuplicate(x1,&coloring->w1);CHKERRQ(ierr);
738     PetscLogObjectParent(coloring,coloring->w1);
739     ierr = VecDuplicate(x1,&coloring->w2);CHKERRQ(ierr);
740     PetscLogObjectParent(coloring,coloring->w2);
741     ierr = VecDuplicate(x1,&coloring->w3);CHKERRQ(ierr);
742     PetscLogObjectParent(coloring,coloring->w3);
743   }
744   w1 = coloring->w1; w2 = coloring->w2; w3 = coloring->w3;
745 
746   ierr = MatSetUnfactored(J);CHKERRQ(ierr);
747   ierr = PetscOptionsHasName(PETSC_NULL,"-mat_fd_coloring_dont_rezero",&flg);CHKERRQ(ierr);
748   if (flg) {
749     PetscLogInfo(coloring,"MatFDColoringApply: Not calling MatZeroEntries()\n");
750   } else {
751     ierr = MatZeroEntries(J);CHKERRQ(ierr);
752   }
753 
754   ierr = VecGetOwnershipRange(x1,&start,&end);CHKERRQ(ierr);
755   ierr = VecGetSize(x1,&N);CHKERRQ(ierr);
756   ierr = PetscLogEventBegin(MAT_FDColoringFunction,0,0,0,0);CHKERRQ(ierr);
757   ierr = (*f)(sctx,t,x1,w1,fctx);CHKERRQ(ierr);
758   ierr = PetscLogEventEnd(MAT_FDColoringFunction,0,0,0,0);CHKERRQ(ierr);
759 
760   /*
761       Compute all the scale factors and share with other processors
762   */
763   ierr = VecGetArray(x1,&xx);CHKERRQ(ierr);xx = xx - start;
764   ierr = VecGetArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);vscale_array = vscale_array - start;
765   for (k=0; k<coloring->ncolors; k++) {
766     /*
767        Loop over each column associated with color adding the
768        perturbation to the vector w3.
769     */
770     for (l=0; l<coloring->ncolumns[k]; l++) {
771       col = coloring->columns[k][l];    /* column of the matrix we are probing for */
772       dx  = xx[col];
773       if (dx == 0.0) dx = 1.0;
774 #if !defined(PETSC_USE_COMPLEX)
775       if (dx < umin && dx >= 0.0)      dx = umin;
776       else if (dx < 0.0 && dx > -umin) dx = -umin;
777 #else
778       if (PetscAbsScalar(dx) < umin && PetscRealPart(dx) >= 0.0)     dx = umin;
779       else if (PetscRealPart(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
780 #endif
781       dx                *= epsilon;
782       vscale_array[col] = 1.0/dx;
783     }
784   }
785   vscale_array = vscale_array - start;ierr = VecRestoreArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);
786   ierr = VecGhostUpdateBegin(coloring->vscale,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
787   ierr = VecGhostUpdateEnd(coloring->vscale,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
788 
789   if (coloring->vscaleforrow) vscaleforrow = coloring->vscaleforrow;
790   else                        vscaleforrow = coloring->columnsforrow;
791 
792   ierr = VecGetArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);
793   /*
794       Loop over each color
795   */
796   for (k=0; k<coloring->ncolors; k++) {
797     ierr = VecCopy(x1,w3);CHKERRQ(ierr);
798     ierr = VecGetArray(w3,&w3_array);CHKERRQ(ierr);w3_array = w3_array - start;
799     /*
800        Loop over each column associated with color adding the
801        perturbation to the vector w3.
802     */
803     for (l=0; l<coloring->ncolumns[k]; l++) {
804       col = coloring->columns[k][l];    /* column of the matrix we are probing for */
805       dx  = xx[col];
806       if (dx == 0.0) dx = 1.0;
807 #if !defined(PETSC_USE_COMPLEX)
808       if (dx < umin && dx >= 0.0)      dx = umin;
809       else if (dx < 0.0 && dx > -umin) dx = -umin;
810 #else
811       if (PetscAbsScalar(dx) < umin && PetscRealPart(dx) >= 0.0)     dx = umin;
812       else if (PetscRealPart(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
813 #endif
814       dx            *= epsilon;
815       w3_array[col] += dx;
816     }
817     w3_array = w3_array + start; ierr = VecRestoreArray(w3,&w3_array);CHKERRQ(ierr);
818 
819     /*
820        Evaluate function at x1 + dx (here dx is a vector of perturbations)
821     */
822     ierr = PetscLogEventBegin(MAT_FDColoringFunction,0,0,0,0);CHKERRQ(ierr);
823     ierr = (*f)(sctx,t,w3,w2,fctx);CHKERRQ(ierr);
824     ierr = PetscLogEventEnd(MAT_FDColoringFunction,0,0,0,0);CHKERRQ(ierr);
825     ierr = VecAXPY(&mone,w1,w2);CHKERRQ(ierr);
826 
827     /*
828        Loop over rows of vector, putting results into Jacobian matrix
829     */
830     ierr = VecGetArray(w2,&y);CHKERRQ(ierr);
831     for (l=0; l<coloring->nrows[k]; l++) {
832       row    = coloring->rows[k][l];
833       col    = coloring->columnsforrow[k][l];
834       y[row] *= vscale_array[vscaleforrow[k][l]];
835       srow   = row + start;
836       ierr   = MatSetValues(J,1,&srow,1,&col,y+row,INSERT_VALUES);CHKERRQ(ierr);
837     }
838     ierr = VecRestoreArray(w2,&y);CHKERRQ(ierr);
839   }
840   ierr  = VecRestoreArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);
841   xx    = xx + start; ierr  = VecRestoreArray(x1,&xx);CHKERRQ(ierr);
842   ierr  = MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
843   ierr  = MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
844   ierr  = PetscLogEventEnd(MAT_FDColoringApply,coloring,J,x1,0);CHKERRQ(ierr);
845   PetscFunctionReturn(0);
846 }
847 
848 
849 #undef __FUNCT__
850 #define __FUNCT__ "MatFDColoringSetRecompute()"
851 /*@C
852    MatFDColoringSetRecompute - Indicates that the next time a Jacobian preconditioner
853      is needed it sholuld be recomputed. Once this is called and the new Jacobian is computed
854      no additional Jacobian's will be computed (the same one will be used) until this is
855      called again.
856 
857    Collective on MatFDColoring
858 
859    Input  Parameters:
860 .  c - the coloring context
861 
862    Level: intermediate
863 
864    Notes: The MatFDColoringSetFrequency() is ignored once this is called
865 
866 .seealso: MatFDColoringCreate(), MatFDColoringSetFrequency()
867 
868 .keywords: Mat, finite differences, coloring
869 @*/
870 PetscErrorCode MatFDColoringSetRecompute(MatFDColoring c)
871 {
872   PetscFunctionBegin;
873   PetscValidHeaderSpecific(c,MAT_FDCOLORING_COOKIE,1);
874   c->usersetsrecompute = PETSC_TRUE;
875   c->recompute         = PETSC_TRUE;
876   PetscFunctionReturn(0);
877 }
878 
879 
880