xref: /petsc/src/mat/matfd/fdmatrix.c (revision 77ed534321f0a860738694ee6d0aa216f0623125)
1 
2 #ifdef PETSC_RCS_HEADER
3 static char vcid[] = "$Id: fdmatrix.c,v 1.37 1998/10/06 03:23:20 bsmith Exp bsmith $";
4 #endif
5 
6 /*
7    This is where the abstract matrix operations are defined that are
8   used for finite difference computations of Jacobians using coloring.
9 */
10 
11 #include "petsc.h"
12 #include "src/mat/matimpl.h"        /*I "mat.h" I*/
13 #include "src/vec/vecimpl.h"
14 
15 #undef __FUNC__
16 #define __FUNC__ "MatFDColoringView_Draw"
17 static int MatFDColoringView_Draw(MatFDColoring fd,Viewer viewer)
18 {
19   int         ierr,i,j,pause;
20   PetscTruth  isnull;
21   Draw        draw;
22   double      xr,yr,xl,yl,h,w,x,y,xc,yc,scale = 0.0;
23   DrawButton  button;
24 
25   PetscFunctionBegin;
26   ierr = ViewerDrawGetDraw(viewer,0,&draw); CHKERRQ(ierr);
27   ierr = DrawIsNull(draw,&isnull); CHKERRQ(ierr); if (isnull) PetscFunctionReturn(0);
28   ierr = DrawSynchronizedClear(draw); CHKERRQ(ierr);
29 
30   xr  = fd->N; yr = fd->M; h = yr/10.0; w = xr/10.0;
31   xr += w;    yr += h;  xl = -w;     yl = -h;
32   ierr = DrawSetCoordinates(draw,xl,yl,xr,yr); CHKERRQ(ierr);
33 
34   /* loop over colors  */
35   for (i=0; i<fd->ncolors; i++ ) {
36     for ( j=0; j<fd->nrows[i]; j++ ) {
37       y = fd->M - fd->rows[i][j] - fd->rstart;
38       x = fd->columnsforrow[i][j];
39       ierr = DrawRectangle(draw,x,y,x+1,y+1,i+1,i+1,i+1,i+1); CHKERRQ(ierr);
40     }
41   }
42   ierr = DrawSynchronizedFlush(draw); CHKERRQ(ierr);
43   ierr = DrawGetPause(draw,&pause); CHKERRQ(ierr);
44   if (pause >= 0) { PetscSleep(pause); PetscFunctionReturn(0);}
45   ierr = DrawCheckResizedWindow(draw); CHKERRQ(ierr);
46   ierr = DrawSynchronizedGetMouseButton(draw,&button,&xc,&yc,0,0);  CHKERRQ(ierr);
47   while (button != BUTTON_RIGHT) {
48     ierr = DrawSynchronizedClear(draw); CHKERRQ(ierr);
49     if (button == BUTTON_LEFT) scale = .5;
50     else if (button == BUTTON_CENTER) scale = 2.;
51     xl = scale*(xl + w - xc) + xc - w*scale;
52     xr = scale*(xr - w - xc) + xc + w*scale;
53     yl = scale*(yl + h - yc) + yc - h*scale;
54     yr = scale*(yr - h - yc) + yc + h*scale;
55     w *= scale; h *= scale;
56     ierr = DrawSetCoordinates(draw,xl,yl,xr,yr); CHKERRQ(ierr);
57     /* loop over colors  */
58     for (i=0; i<fd->ncolors; i++ ) {
59       for ( j=0; j<fd->nrows[i]; j++ ) {
60         y = fd->M - fd->rows[i][j] - fd->rstart;
61         x = fd->columnsforrow[i][j];
62         ierr = DrawRectangle(draw,x,y,x+1,y+1,i+1,i+1,i+1,i+1); CHKERRQ(ierr);
63       }
64     }
65     ierr = DrawCheckResizedWindow(draw); CHKERRQ(ierr);
66     ierr = DrawSynchronizedGetMouseButton(draw,&button,&xc,&yc,0,0);  CHKERRQ(ierr);
67   }
68 
69   PetscFunctionReturn(0);
70 }
71 
72 #undef __FUNC__
73 #define __FUNC__ "MatFDColoringView"
74 /*@C
75    MatFDColoringView - Views a finite difference coloring context.
76 
77    Collective on MatFDColoring unless Viewer is VIEWER_STDOUT_SELF
78 
79    Input  Parameters:
80 +  c - the coloring context
81 -  viewer - visualization context
82 
83    Notes:
84    The available visualization contexts include
85 +     VIEWER_STDOUT_SELF - standard output (default)
86 .     VIEWER_STDOUT_WORLD - synchronized standard
87         output where only the first processor opens
88         the file.  All other processors send their
89         data to the first processor to print.
90 -     VIEWER_DRAWX_WORLD - graphical display of nonzero structure
91 
92 .seealso: MatFDColoringCreate()
93 
94 .keywords: Mat, finite differences, coloring, view
95 @*/
96 int MatFDColoringView(MatFDColoring c,Viewer viewer)
97 {
98   ViewerType vtype;
99   int        i,j,format,ierr;
100   FILE       *fd;
101 
102   PetscFunctionBegin;
103   PetscValidHeaderSpecific(c,MAT_FDCOLORING_COOKIE);
104   if (viewer) {PetscValidHeader(viewer);}
105   else {viewer = VIEWER_STDOUT_SELF;}
106 
107   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
108   if (!PetscStrcmp(vtype,DRAW_VIEWER)) {
109     ierr = MatFDColoringView_Draw(c,viewer); CHKERRQ(ierr);
110     PetscFunctionReturn(0);
111   } else if (!PetscStrcmp(vtype,ASCII_VIEWER)) {
112     ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
113     PetscFPrintf(c->comm,fd,"MatFDColoring Object:\n");
114     PetscFPrintf(c->comm,fd,"  Error tolerance=%g\n",c->error_rel);
115     PetscFPrintf(c->comm,fd,"  Umin=%g\n",c->umin);
116     PetscFPrintf(c->comm,fd,"  Number of colors=%d\n",c->ncolors);
117 
118     ierr = ViewerGetFormat(viewer,&format); CHKERRQ(ierr);
119     if (format != VIEWER_FORMAT_ASCII_INFO) {
120       for ( i=0; i<c->ncolors; i++ ) {
121         PetscFPrintf(c->comm,fd,"  Information for color %d\n",i);
122         PetscFPrintf(c->comm,fd,"    Number of columns %d\n",c->ncolumns[i]);
123         for ( j=0; j<c->ncolumns[i]; j++ ) {
124           PetscFPrintf(c->comm,fd,"      %d\n",c->columns[i][j]);
125         }
126         PetscFPrintf(c->comm,fd,"    Number of rows %d\n",c->nrows[i]);
127         for ( j=0; j<c->nrows[i]; j++ ) {
128           PetscFPrintf(c->comm,fd,"      %d %d \n",c->rows[i][j],c->columnsforrow[i][j]);
129         }
130       }
131     }
132   } else {
133     SETERRQ(1,1,"Viewer type not supported for this object");
134   }
135   PetscFunctionReturn(0);
136 }
137 
138 #undef __FUNC__
139 #define __FUNC__ "MatFDColoringSetParameters"
140 /*@
141    MatFDColoringSetParameters - Sets the parameters for the sparse approximation of
142    a Jacobian matrix using finite differences.
143 
144    Collective on MatFDColoring
145 
146    The Jacobian is estimated with the differencing approximation
147 .vb
148        J(u)_{:,i} = [J(u+h*dx_{i}) - J(u)]/h where
149        h = error_rel*u[i]                 if  abs(u[i]) > umin
150          = +/- error_rel*umin             otherwise, with +/- determined by the sign of u[i]
151        dx_{i} = (0, ... 1, .... 0)
152 .ve
153 
154    Input Parameters:
155 +  coloring - the coloring context
156 .  error_rel - relative error
157 -  umin - minimum allowable u-value magnitude
158 
159 .keywords: Mat, finite differences, coloring, set, parameters
160 
161 .seealso: MatFDColoringCreate()
162 @*/
163 int MatFDColoringSetParameters(MatFDColoring matfd,double error,double umin)
164 {
165   PetscFunctionBegin;
166   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE);
167 
168   if (error != PETSC_DEFAULT) matfd->error_rel = error;
169   if (umin != PETSC_DEFAULT)  matfd->umin      = umin;
170   PetscFunctionReturn(0);
171 }
172 
173 #undef __FUNC__
174 #define __FUNC__ "MatFDColoringSetFrequency"
175 /*@
176    MatFDColoringSetFrequency - Sets the frequency for computing new Jacobian
177    matrices.
178 
179    Collective on MatFDColoring
180 
181    Input Parameters:
182 +  coloring - the coloring context
183 -  freq - frequency (default is 1)
184 
185    Notes:
186    Using a modified Newton strategy, where the Jacobian remains fixed for several
187    iterations, can be cost effective in terms of overall nonlinear solution
188    efficiency.  This parameter indicates that a new Jacobian will be computed every
189    <freq> nonlinear iterations.
190 
191    Options Database Keys:
192 .  -mat_fd_coloring_freq <freq>  - Sets coloring frequency
193 
194 .keywords: Mat, finite differences, coloring, set, frequency
195 
196 .seealso: MatFDColoringCreate(), MatFDColoringGetFrequency()
197 @*/
198 int MatFDColoringSetFrequency(MatFDColoring matfd,int freq)
199 {
200   PetscFunctionBegin;
201   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE);
202 
203   matfd->freq = freq;
204   PetscFunctionReturn(0);
205 }
206 
207 #undef __FUNC__
208 #define __FUNC__ "MatFDColoringGetFrequency"
209 /*@
210    MatFDColoringGetFrequency - Gets the frequency for computing new Jacobian
211    matrices.
212 
213    Not Collective
214 
215    Input Parameters:
216 .  coloring - the coloring context
217 
218    Output Parameters:
219 .  freq - frequency (default is 1)
220 
221    Notes:
222    Using a modified Newton strategy, where the Jacobian remains fixed for several
223    iterations, can be cost effective in terms of overall nonlinear solution
224    efficiency.  This parameter indicates that a new Jacobian will be computed every
225    <freq> nonlinear iterations.
226 
227    Options Database Keys:
228 .  -mat_fd_coloring_freq <freq> - Sets coloring frequency
229 
230 .keywords: Mat, finite differences, coloring, get, frequency
231 
232 .seealso: MatFDColoringSetFrequency()
233 @*/
234 int MatFDColoringGetFrequency(MatFDColoring matfd,int *freq)
235 {
236   PetscFunctionBegin;
237   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE);
238 
239   *freq = matfd->freq;
240   PetscFunctionReturn(0);
241 }
242 
243 #undef __FUNC__
244 #define __FUNC__ "MatFDColoringSetFunction"
245 /*@C
246    MatFDColoringSetFunction - Sets the function to use for computing the Jacobian.
247 
248    Collective on MatFDColoring
249 
250    Input Parameters:
251 +  coloring - the coloring context
252 .  f - the function
253 -  fctx - the optional user-defined function context
254 
255 .keywords: Mat, Jacobian, finite differences, set, function
256 @*/
257 int MatFDColoringSetFunction(MatFDColoring matfd,int (*f)(void),void *fctx)
258 {
259   PetscFunctionBegin;
260   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE);
261 
262   matfd->f    = f;
263   matfd->fctx = fctx;
264 
265   PetscFunctionReturn(0);
266 }
267 
268 #undef __FUNC__
269 #define __FUNC__ "MatFDColoringSetFromOptions"
270 /*@
271    MatFDColoringSetFromOptions - Sets coloring finite difference parameters from
272    the options database.
273 
274    Collective on MatFDColoring
275 
276    The Jacobian is estimated with the differencing approximation
277 .vb
278        J(u)_{:,i} = [J(u+h*dx_{i}) - J(u)]/h where
279        h = error_rel*u[i]                 if  abs(u[i]) > umin
280          = +/- error_rel*umin             otherwise, with +/- determined by the sign of u[i]
281        dx_{i} = (0, ... 1, .... 0)
282 .ve
283 
284    Input Parameter:
285 .  coloring - the coloring context
286 
287    Options Database Keys:
288 +  -mat_fd_coloring_error <err> - Sets <err> (square root
289            of relative error in the function)
290 .  -mat_fd_coloring_umin <umin> - Sets umin, the minimum allowable u-value magnitude
291 .  -mat_fd_coloring_freq <freq> - Sets frequency of computing a new Jacobian
292 .  -mat_fd_coloring_view - Activates basic viewing
293 .  -mat_fd_coloring_view_info - Activates viewing info
294 -  -mat_fd_coloring_view_draw - Activates drawing
295 
296 .keywords: Mat, finite differences, parameters
297 @*/
298 int MatFDColoringSetFromOptions(MatFDColoring matfd)
299 {
300   int    ierr,flag,freq = 1;
301   double error = PETSC_DEFAULT,umin = PETSC_DEFAULT;
302 
303   PetscFunctionBegin;
304   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE);
305 
306   ierr = OptionsGetDouble(matfd->prefix,"-mat_fd_coloring_err",&error,&flag);CHKERRQ(ierr);
307   ierr = OptionsGetDouble(matfd->prefix,"-mat_fd_coloring_umin",&umin,&flag);CHKERRQ(ierr);
308   ierr = MatFDColoringSetParameters(matfd,error,umin); CHKERRQ(ierr);
309   ierr = OptionsGetInt(matfd->prefix,"-mat_fd_coloring_freq",&freq,&flag);CHKERRQ(ierr);
310   ierr = MatFDColoringSetFrequency(matfd,freq);CHKERRQ(ierr);
311   ierr = OptionsHasName(PETSC_NULL,"-help",&flag); CHKERRQ(ierr);
312   if (flag) {
313     ierr = MatFDColoringPrintHelp(matfd); CHKERRQ(ierr);
314   }
315   PetscFunctionReturn(0);
316 }
317 
318 #undef __FUNC__
319 #define __FUNC__ "MatFDColoringPrintHelp"
320 /*@
321     MatFDColoringPrintHelp - Prints help message for matrix finite difference calculations
322     using coloring.
323 
324     Collective on MatFDColoring
325 
326     Input Parameter:
327 .   fdcoloring - the MatFDColoring context
328 
329 .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringSetFromOptions()
330 @*/
331 int MatFDColoringPrintHelp(MatFDColoring fd)
332 {
333   PetscFunctionBegin;
334   PetscValidHeaderSpecific(fd,MAT_FDCOLORING_COOKIE);
335 
336   (*PetscHelpPrintf)(fd->comm,"-mat_fd_coloring_err <err>: set sqrt rel tol in function, defaults to %g\n",fd->error_rel);
337   (*PetscHelpPrintf)(fd->comm,"-mat_fd_coloring_umin <umin>: see users manual, defaults to %d\n",fd->umin);
338   (*PetscHelpPrintf)(fd->comm,"-mat_fd_coloring_freq <freq>: frequency that Jacobian is recomputed, defaults to %d\n",fd->freq);
339   (*PetscHelpPrintf)(fd->comm,"-mat_fd_coloring_view\n");
340   (*PetscHelpPrintf)(fd->comm,"-mat_fd_coloring_view_draw\n");
341   (*PetscHelpPrintf)(fd->comm,"-mat_fd_coloring_view_info\n");
342   PetscFunctionReturn(0);
343 }
344 
345 int MatFDColoringView_Private(MatFDColoring fd)
346 {
347   int ierr,flg;
348 
349   PetscFunctionBegin;
350   ierr = OptionsHasName(PETSC_NULL,"-mat_fd_coloring_view",&flg); CHKERRQ(ierr);
351   if (flg) {
352     ierr = MatFDColoringView(fd,VIEWER_STDOUT_(fd->comm)); CHKERRQ(ierr);
353   }
354   ierr = OptionsHasName(PETSC_NULL,"-mat_fd_coloring_view_info",&flg); CHKERRQ(ierr);
355   if (flg) {
356     ierr = ViewerPushFormat(VIEWER_STDOUT_(fd->comm),VIEWER_FORMAT_ASCII_INFO,PETSC_NULL);CHKERRQ(ierr);
357     ierr = MatFDColoringView(fd,VIEWER_STDOUT_(fd->comm)); CHKERRQ(ierr);
358     ierr = ViewerPopFormat(VIEWER_STDOUT_(fd->comm));CHKERRQ(ierr);
359   }
360   ierr = OptionsHasName(PETSC_NULL,"-mat_fd_coloring_view_draw",&flg); CHKERRQ(ierr);
361   if (flg) {
362     ierr = MatFDColoringView(fd,VIEWER_DRAWX_(fd->comm)); CHKERRQ(ierr);
363     ierr = ViewerFlush(VIEWER_DRAWX_(fd->comm)); CHKERRQ(ierr);
364   }
365   PetscFunctionReturn(0);
366 }
367 
368 #undef __FUNC__
369 #define __FUNC__ "MatFDColoringCreate"
370 /*@C
371    MatFDColoringCreate - Creates a matrix coloring context for finite difference
372    computation of Jacobians.
373 
374    Collective on Mat
375 
376    Input Parameters:
377 +  mat - the matrix containing the nonzero structure of the Jacobian
378 -  iscoloring - the coloring of the matrix
379 
380     Output Parameter:
381 .   color - the new coloring context
382 
383     Options Database Keys:
384 +    -mat_fd_coloring_view - Activates basic viewing or coloring
385 .    -mat_fd_coloring_view_draw - Activates drawing of coloring
386 -    -mat_fd_coloring_view_info - Activates viewing of coloring info
387 
388 .seealso: MatFDColoringDestroy()
389 @*/
390 int MatFDColoringCreate(Mat mat,ISColoring iscoloring,MatFDColoring *color)
391 {
392   MatFDColoring c;
393   MPI_Comm      comm;
394   int           ierr,M,N;
395 
396   PetscFunctionBegin;
397   ierr = MatGetSize(mat,&M,&N); CHKERRQ(ierr);
398   if (M != N) SETERRQ(PETSC_ERR_SUP,0,"Only for square matrices");
399 
400   PetscObjectGetComm((PetscObject)mat,&comm);
401   PetscHeaderCreate(c,_p_MatFDColoring,int,MAT_FDCOLORING_COOKIE,0,comm,MatFDColoringDestroy,MatFDColoringView);
402   PLogObjectCreate(c);
403 
404   if (mat->ops->fdcoloringcreate) {
405     ierr = (*mat->ops->fdcoloringcreate)(mat,iscoloring,c); CHKERRQ(ierr);
406   } else {
407     SETERRQ(PETSC_ERR_SUP,0,"Code not yet written for this matrix type");
408   }
409 
410   c->error_rel = 1.e-8;
411   c->umin      = 1.e-6;
412   c->freq      = 1;
413 
414   ierr = MatFDColoringView_Private(c); CHKERRQ(ierr);
415 
416   *color = c;
417 
418   PetscFunctionReturn(0);
419 }
420 
421 #undef __FUNC__
422 #define __FUNC__ "MatFDColoringDestroy"
423 /*@C
424     MatFDColoringDestroy - Destroys a matrix coloring context that was created
425     via MatFDColoringCreate().
426 
427     Collective on MatFDColoring
428 
429     Input Parameter:
430 .   c - coloring context
431 
432 .seealso: MatFDColoringCreate()
433 @*/
434 int MatFDColoringDestroy(MatFDColoring c)
435 {
436   int i,ierr;
437 
438   PetscFunctionBegin;
439   if (--c->refct > 0) PetscFunctionReturn(0);
440 
441 
442   for ( i=0; i<c->ncolors; i++ ) {
443     if (c->columns[i])       PetscFree(c->columns[i]);
444     if (c->rows[i])          PetscFree(c->rows[i]);
445     if (c->columnsforrow[i]) PetscFree(c->columnsforrow[i]);
446   }
447   PetscFree(c->ncolumns);
448   PetscFree(c->columns);
449   PetscFree(c->nrows);
450   PetscFree(c->rows);
451   PetscFree(c->columnsforrow);
452   PetscFree(c->scale);
453   if (c->w1) {
454     ierr = VecDestroy(c->w1); CHKERRQ(ierr);
455     ierr = VecDestroy(c->w2); CHKERRQ(ierr);
456     ierr = VecDestroy(c->w3); CHKERRQ(ierr);
457   }
458   PLogObjectDestroy(c);
459   PetscHeaderDestroy(c);
460   PetscFunctionReturn(0);
461 }
462 
463 #include "snes.h"
464 
465 #undef __FUNC__
466 #define __FUNC__ "MatFDColoringApply"
467 /*@
468     MatFDColoringApply - Given a matrix for which a MatFDColoring context
469     has been created, computes the Jacobian for a function via finite differences.
470 
471     Collective on MatFDColoring
472 
473     Input Parameters:
474 +   mat - location to store Jacobian
475 .   coloring - coloring context created with MatFDColoringCreate()
476 .   x1 - location at which Jacobian is to be computed
477 -   sctx - optional context required by function (actually a SNES context)
478 
479    Options Database Keys:
480 .  -mat_fd_coloring_freq <freq> - Sets coloring frequency
481 
482 .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView()
483 
484 .keywords: coloring, Jacobian, finite differences
485 @*/
486 int MatFDColoringApply(Mat J,MatFDColoring coloring,Vec x1,MatStructure *flag,void *sctx)
487 {
488   int           k,fg,ierr,N,start,end,l,row,col,srow;
489   Scalar        dx, mone = -1.0,*y,*scale = coloring->scale,*xx,*wscale = coloring->wscale;
490   double        epsilon = coloring->error_rel, umin = coloring->umin;
491   MPI_Comm      comm = coloring->comm;
492   Vec           w1,w2,w3;
493   int           (*f)(void *,Vec,Vec,void *) = ( int (*)(void *,Vec,Vec,void *))coloring->f;
494   void          *fctx = coloring->fctx;
495 
496   PetscFunctionBegin;
497   PetscValidHeaderSpecific(J,MAT_COOKIE);
498   PetscValidHeaderSpecific(coloring,MAT_FDCOLORING_COOKIE);
499   PetscValidHeaderSpecific(x1,VEC_COOKIE);
500 
501 
502   if (!coloring->w1) {
503     ierr = VecDuplicate(x1,&coloring->w1); CHKERRQ(ierr);
504     PLogObjectParent(coloring,coloring->w1);
505     ierr = VecDuplicate(x1,&coloring->w2); CHKERRQ(ierr);
506     PLogObjectParent(coloring,coloring->w2);
507     ierr = VecDuplicate(x1,&coloring->w3); CHKERRQ(ierr);
508     PLogObjectParent(coloring,coloring->w3);
509   }
510   w1 = coloring->w1; w2 = coloring->w2; w3 = coloring->w3;
511 
512   ierr = OptionsHasName(PETSC_NULL,"-mat_fd_coloring_dont_rezero",&fg); CHKERRQ(ierr);
513   if (fg) {
514     PLogInfo(coloring,"MatFDColoringApply: Not calling MatZeroEntries()\n");
515   } else {
516     ierr = MatZeroEntries(J); CHKERRQ(ierr);
517   }
518 
519   ierr = VecGetOwnershipRange(x1,&start,&end); CHKERRQ(ierr);
520   ierr = VecGetSize(x1,&N); CHKERRQ(ierr);
521   ierr = (*f)(sctx,x1,w1,fctx); CHKERRQ(ierr);
522 
523   PetscMemzero(wscale,N*sizeof(Scalar));
524   /*
525       Loop over each color
526   */
527 
528   ierr = VecGetArray(x1,&xx); CHKERRQ(ierr);
529   for (k=0; k<coloring->ncolors; k++) {
530     ierr = VecCopy(x1,w3); CHKERRQ(ierr);
531     /*
532        Loop over each column associated with color adding the
533        perturbation to the vector w3.
534     */
535     for (l=0; l<coloring->ncolumns[k]; l++) {
536       col = coloring->columns[k][l];    /* column of the matrix we are probing for */
537       dx  = xx[col-start];
538       if (dx == 0.0) dx = 1.0;
539 #if !defined(USE_PETSC_COMPLEX)
540       if (dx < umin && dx >= 0.0)      dx = umin;
541       else if (dx < 0.0 && dx > -umin) dx = -umin;
542 #else
543       if (PetscAbsScalar(dx) < umin && PetscReal(dx) >= 0.0)     dx = umin;
544       else if (PetscReal(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
545 #endif
546       dx          *= epsilon;
547       wscale[col] = 1.0/dx;
548       ierr = VecSetValues(w3,1,&col,&dx,ADD_VALUES);CHKERRQ(ierr);
549     }
550 
551     /*
552        Evaluate function at x1 + dx (here dx is a vector of perturbations)
553     */
554     ierr = (*f)(sctx,w3,w2,fctx); CHKERRQ(ierr);
555     ierr = VecAXPY(&mone,w1,w2); CHKERRQ(ierr);
556     /* Communicate scale to all processors */
557 #if !defined(USE_PETSC_COMPLEX)
558     ierr = MPI_Allreduce(wscale,scale,N,MPI_DOUBLE,MPI_SUM,comm);CHKERRQ(ierr);
559 #else
560     ierr = MPI_Allreduce(wscale,scale,2*N,MPI_DOUBLE,MPI_SUM,comm);CHKERRQ(ierr);
561 #endif
562     /*
563        Loop over rows of vector, putting results into Jacobian matrix
564     */
565     ierr = VecGetArray(w2,&y);CHKERRQ(ierr);
566     for (l=0; l<coloring->nrows[k]; l++) {
567       row    = coloring->rows[k][l];
568       col    = coloring->columnsforrow[k][l];
569       y[row] *= scale[col];
570       srow   = row + start;
571       ierr   = MatSetValues(J,1,&srow,1,&col,y+row,INSERT_VALUES);CHKERRQ(ierr);
572     }
573     ierr = VecRestoreArray(w2,&y); CHKERRQ(ierr);
574   }
575   ierr  = VecRestoreArray(x1,&xx);CHKERRQ(ierr);
576   ierr  = MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
577   ierr  = MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
578   PetscFunctionReturn(0);
579 }
580 
581 #include "ts.h"
582 
583 #undef __FUNC__
584 #define __FUNC__ "MatFDColoringApplyTS"
585 /*@
586     MatFDColoringApplyTS - Given a matrix for which a MatFDColoring context
587     has been created, computes the Jacobian for a function via finite differences.
588 
589    Collective on Mat, MatFDColoring, and Vec
590 
591     Input Parameters:
592 +   mat - location to store Jacobian
593 .   coloring - coloring context created with MatFDColoringCreate()
594 .   x1 - location at which Jacobian is to be computed
595 -   sctx - optional context required by function (actually a SNES context)
596 
597    Options Database Keys:
598 .  -mat_fd_coloring_freq <freq> - Sets coloring frequency
599 
600 .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView()
601 
602 .keywords: coloring, Jacobian, finite differences
603 @*/
604 int MatFDColoringApplyTS(Mat J,MatFDColoring coloring,double t,Vec x1,MatStructure *flag,void *sctx)
605 {
606   int           k,fg,ierr,N,start,end,l,row,col,srow;
607   Scalar        dx, mone = -1.0,*y,*scale = coloring->scale,*xx,*wscale = coloring->wscale;
608   double        epsilon = coloring->error_rel, umin = coloring->umin;
609   MPI_Comm      comm = coloring->comm;
610   Vec           w1,w2,w3;
611   int           (*f)(void *,double,Vec,Vec,void *) = ( int (*)(void *,double,Vec,Vec,void *))coloring->f;
612   void          *fctx = coloring->fctx;
613 
614   PetscFunctionBegin;
615   PetscValidHeaderSpecific(J,MAT_COOKIE);
616   PetscValidHeaderSpecific(coloring,MAT_FDCOLORING_COOKIE);
617   PetscValidHeaderSpecific(x1,VEC_COOKIE);
618 
619   if (!coloring->w1) {
620     ierr = VecDuplicate(x1,&coloring->w1); CHKERRQ(ierr);
621     PLogObjectParent(coloring,coloring->w1);
622     ierr = VecDuplicate(x1,&coloring->w2); CHKERRQ(ierr);
623     PLogObjectParent(coloring,coloring->w2);
624     ierr = VecDuplicate(x1,&coloring->w3); CHKERRQ(ierr);
625     PLogObjectParent(coloring,coloring->w3);
626   }
627   w1 = coloring->w1; w2 = coloring->w2; w3 = coloring->w3;
628 
629   ierr = OptionsHasName(PETSC_NULL,"-mat_fd_coloring_dont_rezero",&fg); CHKERRQ(ierr);
630   if (fg) {
631     PLogInfo(coloring,"MatFDColoringApplyTS: Not calling MatZeroEntries()\n");
632   } else {
633     ierr = MatZeroEntries(J); CHKERRQ(ierr);
634   }
635 
636   ierr = VecGetOwnershipRange(x1,&start,&end); CHKERRQ(ierr);
637   ierr = VecGetSize(x1,&N); CHKERRQ(ierr);
638   ierr = (*f)(sctx,t,x1,w1,fctx); CHKERRQ(ierr);
639 
640   PetscMemzero(wscale,N*sizeof(Scalar));
641   /*
642       Loop over each color
643   */
644 
645   ierr = VecGetArray(x1,&xx); CHKERRQ(ierr);
646   for (k=0; k<coloring->ncolors; k++) {
647     ierr = VecCopy(x1,w3); CHKERRQ(ierr);
648     /*
649        Loop over each column associated with color adding the
650        perturbation to the vector w3.
651     */
652     for (l=0; l<coloring->ncolumns[k]; l++) {
653       col = coloring->columns[k][l];    /* column of the matrix we are probing for */
654       dx  = xx[col-start];
655       if (dx == 0.0) dx = 1.0;
656 #if !defined(USE_PETSC_COMPLEX)
657       if (dx < umin && dx >= 0.0)      dx = umin;
658       else if (dx < 0.0 && dx > -umin) dx = -umin;
659 #else
660       if (PetscAbsScalar(dx) < umin && PetscReal(dx) >= 0.0)     dx = umin;
661       else if (PetscReal(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
662 #endif
663       dx          *= epsilon;
664       wscale[col] = 1.0/dx;
665       ierr = VecSetValues(w3,1,&col,&dx,ADD_VALUES); CHKERRQ(ierr);
666     }
667     /*
668        Evaluate function at x1 + dx (here dx is a vector of perturbations)
669     */
670     ierr = (*f)(sctx,t,w3,w2,fctx); CHKERRQ(ierr);
671     ierr = VecAXPY(&mone,w1,w2); CHKERRQ(ierr);
672     /* Communicate scale to all processors */
673 #if !defined(USE_PETSC_COMPLEX)
674     ierr = MPI_Allreduce(wscale,scale,N,MPI_DOUBLE,MPI_SUM,comm);CHKERRQ(ierr);
675 #else
676     ierr = MPI_Allreduce(wscale,scale,2*N,MPI_DOUBLE,MPI_SUM,comm);CHKERRQ(ierr);
677 #endif
678     /*
679        Loop over rows of vector, putting results into Jacobian matrix
680     */
681     ierr = VecGetArray(w2,&y); CHKERRQ(ierr);
682     for (l=0; l<coloring->nrows[k]; l++) {
683       row    = coloring->rows[k][l];
684       col    = coloring->columnsforrow[k][l];
685       y[row] *= scale[col];
686       srow   = row + start;
687       ierr   = MatSetValues(J,1,&srow,1,&col,y+row,INSERT_VALUES);CHKERRQ(ierr);
688     }
689     ierr = VecRestoreArray(w2,&y); CHKERRQ(ierr);
690   }
691   ierr  = VecRestoreArray(x1,&xx); CHKERRQ(ierr);
692   ierr  = MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
693   ierr  = MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
694   PetscFunctionReturn(0);
695 }
696 
697 
698 
699