xref: /petsc/src/mat/matfd/fdmatrix.c (revision 6d187b9135d66ac23f29b4e7e5d4e626b6954b97)
1 
2 /*
3    This is where the abstract matrix operations are defined that are
4   used for finite difference computations of Jacobians using coloring.
5 */
6 
7 #include <petsc-private/matimpl.h>        /*I "petscmat.h" I*/
8 
9 #undef __FUNCT__
10 #define __FUNCT__ "MatFDColoringSetF"
11 PetscErrorCode  MatFDColoringSetF(MatFDColoring fd,Vec F)
12 {
13   PetscErrorCode ierr;
14   PetscFunctionBegin;
15   if (F) {
16     ierr = VecCopy(F,fd->w1);CHKERRQ(ierr);
17     fd->fset = PETSC_TRUE;
18   } else {
19     fd->fset = PETSC_FALSE;
20   }
21   PetscFunctionReturn(0);
22 }
23 
24 #undef __FUNCT__
25 #define __FUNCT__ "MatFDColoringView_Draw_Zoom"
26 static PetscErrorCode MatFDColoringView_Draw_Zoom(PetscDraw draw,void *Aa)
27 {
28   MatFDColoring  fd = (MatFDColoring)Aa;
29   PetscErrorCode ierr;
30   PetscInt       i,j;
31   PetscReal      x,y;
32 
33   PetscFunctionBegin;
34 
35   /* loop over colors  */
36   for (i=0; i<fd->ncolors; i++) {
37     for (j=0; j<fd->nrows[i]; j++) {
38       y = fd->M - fd->rows[i][j] - fd->rstart;
39       x = fd->columnsforrow[i][j];
40       ierr = PetscDrawRectangle(draw,x,y,x+1,y+1,i+1,i+1,i+1,i+1);CHKERRQ(ierr);
41     }
42   }
43   PetscFunctionReturn(0);
44 }
45 
46 #undef __FUNCT__
47 #define __FUNCT__ "MatFDColoringView_Draw"
48 static PetscErrorCode MatFDColoringView_Draw(MatFDColoring fd,PetscViewer viewer)
49 {
50   PetscErrorCode ierr;
51   PetscBool      isnull;
52   PetscDraw      draw;
53   PetscReal      xr,yr,xl,yl,h,w;
54 
55   PetscFunctionBegin;
56   ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr);
57   ierr = PetscDrawIsNull(draw,&isnull);CHKERRQ(ierr); if (isnull) PetscFunctionReturn(0);
58 
59   ierr = PetscObjectCompose((PetscObject)fd,"Zoomviewer",(PetscObject)viewer);CHKERRQ(ierr);
60 
61   xr  = fd->N; yr = fd->M; h = yr/10.0; w = xr/10.0;
62   xr += w;     yr += h;    xl = -w;     yl = -h;
63   ierr = PetscDrawSetCoordinates(draw,xl,yl,xr,yr);CHKERRQ(ierr);
64   ierr = PetscDrawZoom(draw,MatFDColoringView_Draw_Zoom,fd);CHKERRQ(ierr);
65   ierr = PetscObjectCompose((PetscObject)fd,"Zoomviewer",PETSC_NULL);CHKERRQ(ierr);
66   PetscFunctionReturn(0);
67 }
68 
69 #undef __FUNCT__
70 #define __FUNCT__ "MatFDColoringView"
71 /*@C
72    MatFDColoringView - Views a finite difference coloring context.
73 
74    Collective on MatFDColoring
75 
76    Input  Parameters:
77 +  c - the coloring context
78 -  viewer - visualization context
79 
80    Level: intermediate
81 
82    Notes:
83    The available visualization contexts include
84 +     PETSC_VIEWER_STDOUT_SELF - standard output (default)
85 .     PETSC_VIEWER_STDOUT_WORLD - synchronized standard
86         output where only the first processor opens
87         the file.  All other processors send their
88         data to the first processor to print.
89 -     PETSC_VIEWER_DRAW_WORLD - graphical display of nonzero structure
90 
91    Notes:
92      Since PETSc uses only a small number of basic colors (currently 33), if the coloring
93    involves more than 33 then some seemingly identical colors are displayed making it look
94    like an illegal coloring. This is just a graphical artifact.
95 
96 .seealso: MatFDColoringCreate()
97 
98 .keywords: Mat, finite differences, coloring, view
99 @*/
100 PetscErrorCode  MatFDColoringView(MatFDColoring c,PetscViewer viewer)
101 {
102   PetscErrorCode    ierr;
103   PetscInt          i,j;
104   PetscBool         isdraw,iascii;
105   PetscViewerFormat format;
106 
107   PetscFunctionBegin;
108   PetscValidHeaderSpecific(c,MAT_FDCOLORING_CLASSID,1);
109   if (!viewer) {
110     ierr = PetscViewerASCIIGetStdout(((PetscObject)c)->comm,&viewer);CHKERRQ(ierr);
111   }
112   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
113   PetscCheckSameComm(c,1,viewer,2);
114 
115   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr);
116   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
117   if (isdraw) {
118     ierr = MatFDColoringView_Draw(c,viewer);CHKERRQ(ierr);
119   } else if (iascii) {
120     ierr = PetscObjectPrintClassNamePrefixType((PetscObject)c,viewer,"MatFDColoring Object");CHKERRQ(ierr);
121     ierr = PetscViewerASCIIPrintf(viewer,"  Error tolerance=%G\n",c->error_rel);CHKERRQ(ierr);
122     ierr = PetscViewerASCIIPrintf(viewer,"  Umin=%G\n",c->umin);CHKERRQ(ierr);
123     ierr = PetscViewerASCIIPrintf(viewer,"  Number of colors=%D\n",c->ncolors);CHKERRQ(ierr);
124 
125     ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
126     if (format != PETSC_VIEWER_ASCII_INFO) {
127       for (i=0; i<c->ncolors; i++) {
128         ierr = PetscViewerASCIIPrintf(viewer,"  Information for color %D\n",i);CHKERRQ(ierr);
129         ierr = PetscViewerASCIIPrintf(viewer,"    Number of columns %D\n",c->ncolumns[i]);CHKERRQ(ierr);
130         for (j=0; j<c->ncolumns[i]; j++) {
131           ierr = PetscViewerASCIIPrintf(viewer,"      %D\n",c->columns[i][j]);CHKERRQ(ierr);
132         }
133         ierr = PetscViewerASCIIPrintf(viewer,"    Number of rows %D\n",c->nrows[i]);CHKERRQ(ierr);
134         for (j=0; j<c->nrows[i]; j++) {
135           ierr = PetscViewerASCIIPrintf(viewer,"      %D %D \n",c->rows[i][j],c->columnsforrow[i][j]);CHKERRQ(ierr);
136         }
137       }
138     }
139     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
140   } else {
141     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Viewer type %s not supported for MatFDColoring",((PetscObject)viewer)->type_name);
142   }
143   PetscFunctionReturn(0);
144 }
145 
146 #undef __FUNCT__
147 #define __FUNCT__ "MatFDColoringSetParameters"
148 /*@
149    MatFDColoringSetParameters - Sets the parameters for the sparse approximation of
150    a Jacobian matrix using finite differences.
151 
152    Logically Collective on MatFDColoring
153 
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        h = error_rel*u[i]                 if  abs(u[i]) > umin
158          = +/- error_rel*umin             otherwise, with +/- determined by the sign of u[i]
159        dx_{i} = (0, ... 1, .... 0)
160 .ve
161 
162    Input Parameters:
163 +  coloring - the coloring context
164 .  error_rel - relative error
165 -  umin - minimum allowable u-value magnitude
166 
167    Level: advanced
168 
169 .keywords: Mat, finite differences, coloring, set, parameters
170 
171 .seealso: MatFDColoringCreate(), MatFDColoringSetFromOptions()
172 
173 @*/
174 PetscErrorCode  MatFDColoringSetParameters(MatFDColoring matfd,PetscReal error,PetscReal umin)
175 {
176   PetscFunctionBegin;
177   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_CLASSID,1);
178   PetscValidLogicalCollectiveReal(matfd,error,2);
179   PetscValidLogicalCollectiveReal(matfd,umin,3);
180   if (error != PETSC_DEFAULT) matfd->error_rel = error;
181   if (umin != PETSC_DEFAULT)  matfd->umin      = umin;
182   PetscFunctionReturn(0);
183 }
184 
185 
186 
187 #undef __FUNCT__
188 #define __FUNCT__ "MatFDColoringGetFunction"
189 /*@C
190    MatFDColoringGetFunction - Gets the function to use for computing the Jacobian.
191 
192    Not Collective
193 
194    Input Parameters:
195 .  coloring - the coloring context
196 
197    Output Parameters:
198 +  f - the function
199 -  fctx - the optional user-defined function context
200 
201    Level: intermediate
202 
203 .keywords: Mat, Jacobian, finite differences, set, function
204 
205 .seealso: MatFDColoringCreate(), MatFDColoringSetFunction(), MatFDColoringSetFromOptions()
206 
207 @*/
208 PetscErrorCode  MatFDColoringGetFunction(MatFDColoring matfd,PetscErrorCode (**f)(void),void **fctx)
209 {
210   PetscFunctionBegin;
211   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_CLASSID,1);
212   if (f) *f = matfd->f;
213   if (fctx) *fctx = matfd->fctx;
214   PetscFunctionReturn(0);
215 }
216 
217 #undef __FUNCT__
218 #define __FUNCT__ "MatFDColoringSetFunction"
219 /*@C
220    MatFDColoringSetFunction - Sets the function to use for computing the Jacobian.
221 
222    Logically Collective on MatFDColoring
223 
224    Input Parameters:
225 +  coloring - the coloring context
226 .  f - the function
227 -  fctx - the optional user-defined function context
228 
229    Calling sequence of (*f) function:
230     For SNES:    PetscErrorCode (*f)(SNES,Vec,Vec,void*)
231     If not using SNES: PetscErrorCode (*f)(void *dummy,Vec,Vec,void*) and dummy is ignored
232 
233    Level: advanced
234 
235    Notes: This function is usually used automatically by SNES (when one uses SNESSetJacobian() with the argument
236      SNESDefaultComputeJacobianColor()) and only needs to be used by someone computing a matrix via coloring directly by
237      calling MatFDColoringApply()
238 
239    Fortran Notes:
240     In Fortran you must call MatFDColoringSetFunction() for a coloring object to
241   be used without SNES or within the SNES solvers.
242 
243 .keywords: Mat, Jacobian, finite differences, set, function
244 
245 .seealso: MatFDColoringCreate(), MatFDColoringGetFunction(), MatFDColoringSetFromOptions()
246 
247 @*/
248 PetscErrorCode  MatFDColoringSetFunction(MatFDColoring matfd,PetscErrorCode (*f)(void),void *fctx)
249 {
250   PetscFunctionBegin;
251   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_CLASSID,1);
252   matfd->f    = f;
253   matfd->fctx = fctx;
254   PetscFunctionReturn(0);
255 }
256 
257 #undef __FUNCT__
258 #define __FUNCT__ "MatFDColoringSetFromOptions"
259 /*@
260    MatFDColoringSetFromOptions - Sets coloring finite difference parameters from
261    the options database.
262 
263    Collective on MatFDColoring
264 
265    The Jacobian, F'(u), is estimated with the differencing approximation
266 .vb
267        F'(u)_{:,i} = [F(u+h*dx_{i}) - F(u)]/h where
268        h = error_rel*u[i]                 if  abs(u[i]) > umin
269          = +/- error_rel*umin             otherwise, with +/- determined by the sign of u[i]
270        dx_{i} = (0, ... 1, .... 0)
271 .ve
272 
273    Input Parameter:
274 .  coloring - the coloring context
275 
276    Options Database Keys:
277 +  -mat_fd_coloring_err <err> - Sets <err> (square root
278            of relative error in the function)
279 .  -mat_fd_coloring_umin <umin> - Sets umin, the minimum allowable u-value magnitude
280 .  -mat_fd_type - "wp" or "ds" (see MATMFFD_WP or MATMFFD_DS)
281 .  -mat_fd_coloring_view - Activates basic viewing
282 .  -mat_fd_coloring_view ::ascii_info - Activates viewing info
283 -  -mat_fd_coloring_view draw - Activates drawing
284 
285     Level: intermediate
286 
287 .keywords: Mat, finite differences, parameters
288 
289 .seealso: MatFDColoringCreate(), MatFDColoringView(), MatFDColoringSetParameters()
290 
291 @*/
292 PetscErrorCode  MatFDColoringSetFromOptions(MatFDColoring matfd)
293 {
294   PetscErrorCode ierr;
295   PetscBool      flg;
296   char           value[3];
297 
298   PetscFunctionBegin;
299   PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_CLASSID,1);
300 
301   ierr = PetscObjectOptionsBegin((PetscObject)matfd);CHKERRQ(ierr);
302     ierr = PetscOptionsReal("-mat_fd_coloring_err","Square root of relative error in function","MatFDColoringSetParameters",matfd->error_rel,&matfd->error_rel,0);CHKERRQ(ierr);
303     ierr = PetscOptionsReal("-mat_fd_coloring_umin","Minimum allowable u magnitude","MatFDColoringSetParameters",matfd->umin,&matfd->umin,0);CHKERRQ(ierr);
304     ierr = PetscOptionsString("-mat_fd_type","Algorithm to compute h, wp or ds","MatFDColoringCreate",matfd->htype,value,3,&flg);CHKERRQ(ierr);
305     if (flg) {
306       if (value[0] == 'w' && value[1] == 'p') matfd->htype = "wp";
307       else if (value[0] == 'd' && value[1] == 's') matfd->htype = "ds";
308       else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown finite differencing type %s",value);
309     }
310     /* process any options handlers added with PetscObjectAddOptionsHandler() */
311     ierr = PetscObjectProcessOptionsHandlers((PetscObject)matfd);CHKERRQ(ierr);
312   PetscOptionsEnd();CHKERRQ(ierr);
313   PetscFunctionReturn(0);
314 }
315 
316 #undef __FUNCT__
317 #define __FUNCT__ "MatFDColoringViewFromOptions"
318 PetscErrorCode MatFDColoringViewFromOptions(MatFDColoring fd,const char optionname[])
319 {
320   PetscErrorCode ierr;
321   PetscBool      flg;
322   PetscViewer    viewer;
323 
324   PetscFunctionBegin;
325   ierr = PetscOptionsGetViewer(((PetscObject)fd)->comm,((PetscObject)fd)->prefix,optionname,&viewer,&flg);CHKERRQ(ierr);
326   if (flg) {
327     ierr = MatFDColoringView(fd,viewer);CHKERRQ(ierr);
328     ierr = PetscOptionsRestoreViewer(viewer);CHKERRQ(ierr);
329   }
330   PetscFunctionReturn(0);
331 }
332 
333 #undef __FUNCT__
334 #define __FUNCT__ "MatFDColoringCreate"
335 /*@
336    MatFDColoringCreate - Creates a matrix coloring context for finite difference
337    computation of Jacobians.
338 
339    Collective on Mat
340 
341    Input Parameters:
342 +  mat - the matrix containing the nonzero structure of the Jacobian
343 -  iscoloring - the coloring of the matrix; usually obtained with MatGetColoring() or DMCreateColoring()
344 
345     Output Parameter:
346 .   color - the new coloring context
347 
348     Level: intermediate
349 
350 .seealso: MatFDColoringDestroy(),SNESDefaultComputeJacobianColor(), ISColoringCreate(),
351           MatFDColoringSetFunction(), MatFDColoringSetFromOptions(), MatFDColoringApply(),
352           MatFDColoringView(), MatFDColoringSetParameters(), MatGetColoring(), DMCreateColoring()
353 @*/
354 PetscErrorCode  MatFDColoringCreate(Mat mat,ISColoring iscoloring,MatFDColoring *color)
355 {
356   MatFDColoring  c;
357   MPI_Comm       comm;
358   PetscErrorCode ierr;
359   PetscInt       M,N;
360 
361   PetscFunctionBegin;
362   ierr = PetscLogEventBegin(MAT_FDColoringCreate,mat,0,0,0);CHKERRQ(ierr);
363   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
364   if (M != N) SETERRQ(((PetscObject)mat)->comm,PETSC_ERR_SUP,"Only for square matrices");
365   ierr = PetscObjectGetComm((PetscObject)mat,&comm);CHKERRQ(ierr);
366   ierr = PetscHeaderCreate(c,_p_MatFDColoring,int,MAT_FDCOLORING_CLASSID,0,"MatFDColoring","Jacobian computation via finite differences with coloring","Mat",comm,MatFDColoringDestroy,MatFDColoringView);CHKERRQ(ierr);
367 
368   c->ctype = iscoloring->ctype;
369 
370   if (mat->ops->fdcoloringcreate) {
371     ierr = (*mat->ops->fdcoloringcreate)(mat,iscoloring,c);CHKERRQ(ierr);
372   } else SETERRQ1(((PetscObject)mat)->comm,PETSC_ERR_SUP,"Code not yet written for matrix type %s",((PetscObject)mat)->type_name);
373 
374   ierr = MatGetVecs(mat,PETSC_NULL,&c->w1);CHKERRQ(ierr);
375   ierr = PetscLogObjectParent(c,c->w1);CHKERRQ(ierr);
376   ierr = VecDuplicate(c->w1,&c->w2);CHKERRQ(ierr);
377   ierr = PetscLogObjectParent(c,c->w2);CHKERRQ(ierr);
378 
379   c->error_rel         = PETSC_SQRT_MACHINE_EPSILON;
380   c->umin              = 100.0*PETSC_SQRT_MACHINE_EPSILON;
381   c->currentcolor      = -1;
382   c->htype             = "wp";
383   c->fset              = PETSC_FALSE;
384 
385   *color = c;
386   ierr = PetscObjectCompose((PetscObject)mat,"SNESMatFDColoring",(PetscObject)c);CHKERRQ(ierr);
387   ierr = PetscLogEventEnd(MAT_FDColoringCreate,mat,0,0,0);CHKERRQ(ierr);
388   PetscFunctionReturn(0);
389 }
390 
391 #undef __FUNCT__
392 #define __FUNCT__ "MatFDColoringDestroy"
393 /*@
394     MatFDColoringDestroy - Destroys a matrix coloring context that was created
395     via MatFDColoringCreate().
396 
397     Collective on MatFDColoring
398 
399     Input Parameter:
400 .   c - coloring context
401 
402     Level: intermediate
403 
404 .seealso: MatFDColoringCreate()
405 @*/
406 PetscErrorCode  MatFDColoringDestroy(MatFDColoring *c)
407 {
408   PetscErrorCode ierr;
409   PetscInt       i;
410 
411   PetscFunctionBegin;
412   if (!*c) PetscFunctionReturn(0);
413   if (--((PetscObject)(*c))->refct > 0) {*c = 0; PetscFunctionReturn(0);}
414 
415   for (i=0; i<(*c)->ncolors; i++) {
416     ierr = PetscFree((*c)->columns[i]);CHKERRQ(ierr);
417     ierr = PetscFree((*c)->rows[i]);CHKERRQ(ierr);
418     ierr = PetscFree((*c)->columnsforrow[i]);CHKERRQ(ierr);
419     if ((*c)->vscaleforrow) {ierr = PetscFree((*c)->vscaleforrow[i]);CHKERRQ(ierr);}
420   }
421   ierr = PetscFree((*c)->ncolumns);CHKERRQ(ierr);
422   ierr = PetscFree((*c)->columns);CHKERRQ(ierr);
423   ierr = PetscFree((*c)->nrows);CHKERRQ(ierr);
424   ierr = PetscFree((*c)->rows);CHKERRQ(ierr);
425   ierr = PetscFree((*c)->columnsforrow);CHKERRQ(ierr);
426   ierr = PetscFree((*c)->vscaleforrow);CHKERRQ(ierr);
427   ierr = VecDestroy(&(*c)->vscale);CHKERRQ(ierr);
428   ierr = VecDestroy(&(*c)->w1);CHKERRQ(ierr);
429   ierr = VecDestroy(&(*c)->w2);CHKERRQ(ierr);
430   ierr = VecDestroy(&(*c)->w3);CHKERRQ(ierr);
431   ierr = PetscHeaderDestroy(c);CHKERRQ(ierr);
432   PetscFunctionReturn(0);
433 }
434 
435 #undef __FUNCT__
436 #define __FUNCT__ "MatFDColoringGetPerturbedColumns"
437 /*@C
438     MatFDColoringGetPerturbedColumns - Returns the indices of the columns that
439       that are currently being perturbed.
440 
441     Not Collective
442 
443     Input Parameters:
444 .   coloring - coloring context created with MatFDColoringCreate()
445 
446     Output Parameters:
447 +   n - the number of local columns being perturbed
448 -   cols - the column indices, in global numbering
449 
450    Level: intermediate
451 
452 .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView(), MatFDColoringApply()
453 
454 .keywords: coloring, Jacobian, finite differences
455 @*/
456 PetscErrorCode  MatFDColoringGetPerturbedColumns(MatFDColoring coloring,PetscInt *n,PetscInt *cols[])
457 {
458   PetscFunctionBegin;
459   if (coloring->currentcolor >= 0) {
460     *n    = coloring->ncolumns[coloring->currentcolor];
461     *cols = coloring->columns[coloring->currentcolor];
462   } else {
463     *n = 0;
464   }
465   PetscFunctionReturn(0);
466 }
467 
468 #undef __FUNCT__
469 #define __FUNCT__ "MatFDColoringApply"
470 /*@
471     MatFDColoringApply - Given a matrix for which a MatFDColoring context
472     has been created, computes the Jacobian for a function via finite differences.
473 
474     Collective on MatFDColoring
475 
476     Input Parameters:
477 +   mat - location to store Jacobian
478 .   coloring - coloring context created with MatFDColoringCreate()
479 .   x1 - location at which Jacobian is to be computed
480 -   sctx - context required by function, if this is being used with the SNES solver then it is SNES object, otherwise it is null
481 
482     Options Database Keys:
483 +    -mat_fd_type - "wp" or "ds"  (see MATMFFD_WP or MATMFFD_DS)
484 .    -mat_fd_coloring_view - Activates basic viewing or coloring
485 .    -mat_fd_coloring_view draw - Activates drawing of coloring
486 -    -mat_fd_coloring_view ::ascii_info - Activates viewing of coloring info
487 
488     Level: intermediate
489 
490 .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView(), MatFDColoringSetFunction()
491 
492 .keywords: coloring, Jacobian, finite differences
493 @*/
494 PetscErrorCode  MatFDColoringApply(Mat J,MatFDColoring coloring,Vec x1,MatStructure *flag,void *sctx)
495 {
496   PetscErrorCode ierr;
497 
498   PetscFunctionBegin;
499   PetscValidHeaderSpecific(J,MAT_CLASSID,1);
500   PetscValidHeaderSpecific(coloring,MAT_FDCOLORING_CLASSID,2);
501   PetscValidHeaderSpecific(x1,VEC_CLASSID,3);
502   if (!coloring->f) SETERRQ(((PetscObject)J)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must call MatFDColoringSetFunction()");
503   if (!J->ops->fdcoloringapply) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not supported for this matrix type %s",((PetscObject)J)->type_name);
504   ierr = (*J->ops->fdcoloringapply)(J,coloring,x1,flag,sctx);CHKERRQ(ierr);
505   PetscFunctionReturn(0);
506 }
507 
508 #undef __FUNCT__
509 #define __FUNCT__ "MatFDColoringApply_AIJ"
510 PetscErrorCode  MatFDColoringApply_AIJ(Mat J,MatFDColoring coloring,Vec x1,MatStructure *flag,void *sctx)
511 {
512   PetscErrorCode (*f)(void*,Vec,Vec,void*) = (PetscErrorCode (*)(void*,Vec,Vec,void *))coloring->f;
513   PetscErrorCode ierr;
514   PetscInt       k,start,end,l,row,col,srow,**vscaleforrow;
515   PetscScalar    dx,*y,*xx,*w3_array;
516   PetscScalar    *vscale_array;
517   PetscReal      epsilon = coloring->error_rel,umin = coloring->umin,unorm;
518   Vec            w1=coloring->w1,w2=coloring->w2,w3;
519   void           *fctx = coloring->fctx;
520   PetscBool      flg = PETSC_FALSE;
521   PetscInt       ctype=coloring->ctype,N,col_start=0,col_end=0;
522   Vec            x1_tmp;
523 
524   PetscFunctionBegin;
525   PetscValidHeaderSpecific(J,MAT_CLASSID,1);
526   PetscValidHeaderSpecific(coloring,MAT_FDCOLORING_CLASSID,2);
527   PetscValidHeaderSpecific(x1,VEC_CLASSID,3);
528   if (!f) SETERRQ(((PetscObject)J)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must call MatFDColoringSetFunction()");
529 
530   ierr = PetscLogEventBegin(MAT_FDColoringApply,coloring,J,x1,0);CHKERRQ(ierr);
531   ierr = MatSetUnfactored(J);CHKERRQ(ierr);
532   ierr = PetscOptionsGetBool(PETSC_NULL,"-mat_fd_coloring_dont_rezero",&flg,PETSC_NULL);CHKERRQ(ierr);
533   if (flg) {
534     ierr = PetscInfo(coloring,"Not calling MatZeroEntries()\n");CHKERRQ(ierr);
535   } else {
536     PetscBool  assembled;
537     ierr = MatAssembled(J,&assembled);CHKERRQ(ierr);
538     if (assembled) {
539       ierr = MatZeroEntries(J);CHKERRQ(ierr);
540     }
541   }
542 
543   x1_tmp = x1;
544   if (!coloring->vscale){
545     ierr = VecDuplicate(x1_tmp,&coloring->vscale);CHKERRQ(ierr);
546   }
547 
548   if (coloring->htype[0] == 'w') { /* tacky test; need to make systematic if we add other approaches to computing h*/
549     ierr = VecNorm(x1_tmp,NORM_2,&unorm);CHKERRQ(ierr);
550   }
551   ierr = VecGetOwnershipRange(w1,&start,&end);CHKERRQ(ierr); /* OwnershipRange is used by ghosted x! */
552 
553   /* Set w1 = F(x1) */
554   if (!coloring->fset) {
555     ierr = PetscLogEventBegin(MAT_FDColoringFunction,0,0,0,0);CHKERRQ(ierr);
556     ierr = (*f)(sctx,x1_tmp,w1,fctx);CHKERRQ(ierr);
557     ierr = PetscLogEventEnd(MAT_FDColoringFunction,0,0,0,0);CHKERRQ(ierr);
558   } else {
559     coloring->fset = PETSC_FALSE;
560   }
561 
562   if (!coloring->w3) {
563     ierr = VecDuplicate(x1_tmp,&coloring->w3);CHKERRQ(ierr);
564     ierr = PetscLogObjectParent(coloring,coloring->w3);CHKERRQ(ierr);
565   }
566   w3 = coloring->w3;
567 
568     /* Compute all the local scale factors, including ghost points */
569   ierr = VecGetLocalSize(x1_tmp,&N);CHKERRQ(ierr);
570   ierr = VecGetArray(x1_tmp,&xx);CHKERRQ(ierr);
571   ierr = VecGetArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);
572   if (ctype == IS_COLORING_GHOSTED){
573     col_start = 0; col_end = N;
574   } else if (ctype == IS_COLORING_GLOBAL){
575     xx = xx - start;
576     vscale_array = vscale_array - start;
577     col_start = start; col_end = N + start;
578   }
579   for (col=col_start; col<col_end; col++){
580     /* Loop over each local column, vscale[col] = 1./(epsilon*dx[col]) */
581     if (coloring->htype[0] == 'w') {
582       dx = 1.0 + unorm;
583     } else {
584       dx  = xx[col];
585     }
586     if (dx == (PetscScalar)0.0) dx = 1.0;
587 #if !defined(PETSC_USE_COMPLEX)
588     if (dx < umin && dx >= 0.0)      dx = umin;
589     else if (dx < 0.0 && dx > -umin) dx = -umin;
590 #else
591     if (PetscAbsScalar(dx) < umin && PetscRealPart(dx) >= 0.0)     dx = umin;
592     else if (PetscRealPart(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
593 #endif
594     dx               *= epsilon;
595     vscale_array[col] = (PetscScalar)1.0/dx;
596   }
597   if (ctype == IS_COLORING_GLOBAL)  vscale_array = vscale_array + start;
598   ierr = VecRestoreArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);
599   if (ctype == IS_COLORING_GLOBAL){
600     ierr = VecGhostUpdateBegin(coloring->vscale,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
601     ierr = VecGhostUpdateEnd(coloring->vscale,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
602   }
603 
604   if (coloring->vscaleforrow) {
605     vscaleforrow = coloring->vscaleforrow;
606   } else SETERRQ(((PetscObject)J)->comm,PETSC_ERR_ARG_NULL,"Null Object: coloring->vscaleforrow");
607 
608   /*
609     Loop over each color
610   */
611   ierr = VecGetArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);
612   for (k=0; k<coloring->ncolors; k++) {
613     coloring->currentcolor = k;
614     ierr = VecCopy(x1_tmp,w3);CHKERRQ(ierr);
615     ierr = VecGetArray(w3,&w3_array);CHKERRQ(ierr);
616     if (ctype == IS_COLORING_GLOBAL) w3_array = w3_array - start;
617     /*
618       Loop over each column associated with color
619       adding the perturbation to the vector w3.
620     */
621     for (l=0; l<coloring->ncolumns[k]; l++) {
622       col = coloring->columns[k][l];    /* local column of the matrix we are probing for */
623       if (coloring->htype[0] == 'w') {
624         dx = 1.0 + unorm;
625       } else {
626         dx  = xx[col];
627       }
628       if (dx == (PetscScalar)0.0) dx = 1.0;
629 #if !defined(PETSC_USE_COMPLEX)
630       if (dx < umin && dx >= 0.0)      dx = umin;
631       else if (dx < 0.0 && dx > -umin) dx = -umin;
632 #else
633       if (PetscAbsScalar(dx) < umin && PetscRealPart(dx) >= 0.0)     dx = umin;
634       else if (PetscRealPart(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
635 #endif
636       dx            *= epsilon;
637       if (!PetscAbsScalar(dx)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Computed 0 differencing parameter");
638       w3_array[col] += dx;
639     }
640     if (ctype == IS_COLORING_GLOBAL) w3_array = w3_array + start;
641     ierr = VecRestoreArray(w3,&w3_array);CHKERRQ(ierr);
642 
643     /*
644       Evaluate function at w3 = x1 + dx (here dx is a vector of perturbations)
645                            w2 = F(x1 + dx) - F(x1)
646     */
647     ierr = PetscLogEventBegin(MAT_FDColoringFunction,0,0,0,0);CHKERRQ(ierr);
648     ierr = (*f)(sctx,w3,w2,fctx);CHKERRQ(ierr);
649     ierr = PetscLogEventEnd(MAT_FDColoringFunction,0,0,0,0);CHKERRQ(ierr);
650     ierr = VecAXPY(w2,-1.0,w1);CHKERRQ(ierr);
651 
652     /*
653       Loop over rows of vector, putting results into Jacobian matrix
654     */
655     ierr = VecGetArray(w2,&y);CHKERRQ(ierr);
656     for (l=0; l<coloring->nrows[k]; l++) {
657       row    = coloring->rows[k][l];             /* local row index */
658       col    = coloring->columnsforrow[k][l];    /* global column index */
659       y[row] *= vscale_array[vscaleforrow[k][l]];
660       srow   = row + start;
661       ierr   = MatSetValues(J,1,&srow,1,&col,y+row,INSERT_VALUES);CHKERRQ(ierr);
662     }
663     ierr = VecRestoreArray(w2,&y);CHKERRQ(ierr);
664   } /* endof for each color */
665   if (ctype == IS_COLORING_GLOBAL) xx = xx + start;
666   ierr = VecRestoreArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);
667   ierr = VecRestoreArray(x1_tmp,&xx);CHKERRQ(ierr);
668 
669   coloring->currentcolor = -1;
670   ierr  = MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
671   ierr  = MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
672   ierr = PetscLogEventEnd(MAT_FDColoringApply,coloring,J,x1,0);CHKERRQ(ierr);
673 
674   ierr = MatFDColoringViewFromOptions(coloring,"-mat_fd_coloring_view");CHKERRQ(ierr);
675   PetscFunctionReturn(0);
676 }
677