1 #ifdef PETSC_RCS_HEADER 2 static char vcid[] = "$Id: fdmatrix.c,v 1.16 1997/09/25 22:39:43 curfman Exp curfman $"; 3 #endif 4 5 /* 6 This is where the abstract matrix operations are defined that are 7 used for finite difference computations of Jacobians using coloring. 8 */ 9 10 #include "petsc.h" 11 #include "src/mat/matimpl.h" /*I "mat.h" I*/ 12 #include "src/vec/vecimpl.h" 13 #include "pinclude/pviewer.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 ierr = ViewerDrawGetDraw(viewer,&draw); CHKERRQ(ierr); 26 ierr = DrawIsNull(draw,&isnull); CHKERRQ(ierr); if (isnull) return 0; 27 ierr = DrawSyncClear(draw); CHKERRQ(ierr); 28 29 xr = fd->N; yr = fd->M; h = yr/10.0; w = xr/10.0; 30 xr += w; yr += h; xl = -w; yl = -h; 31 ierr = DrawSetCoordinates(draw,xl,yl,xr,yr); CHKERRQ(ierr); 32 33 /* loop over colors */ 34 for (i=0; i<fd->ncolors; i++ ) { 35 for ( j=0; j<fd->nrows[i]; j++ ) { 36 y = fd->M - fd->rows[i][j] - fd->rstart; 37 x = fd->columnsforrow[i][j]; 38 DrawRectangle(draw,x,y,x+1,y+1,i+1,i+1,i+1,i+1); 39 } 40 } 41 ierr = DrawSyncFlush(draw); CHKERRQ(ierr); 42 ierr = DrawGetPause(draw,&pause); CHKERRQ(ierr); 43 if (pause >= 0) { PetscSleep(pause); return 0;} 44 ierr = DrawCheckResizedWindow(draw); 45 ierr = DrawSyncGetMouseButton(draw,&button,&xc,&yc,0,0); 46 while (button != BUTTON_RIGHT) { 47 ierr = DrawSyncClear(draw); CHKERRQ(ierr); 48 if (button == BUTTON_LEFT) scale = .5; 49 else if (button == BUTTON_CENTER) scale = 2.; 50 xl = scale*(xl + w - xc) + xc - w*scale; 51 xr = scale*(xr - w - xc) + xc + w*scale; 52 yl = scale*(yl + h - yc) + yc - h*scale; 53 yr = scale*(yr - h - yc) + yc + h*scale; 54 w *= scale; h *= scale; 55 ierr = DrawSetCoordinates(draw,xl,yl,xr,yr); CHKERRQ(ierr); 56 /* loop over colors */ 57 for (i=0; i<fd->ncolors; i++ ) { 58 for ( j=0; j<fd->nrows[i]; j++ ) { 59 y = fd->M - fd->rows[i][j] - fd->rstart; 60 x = fd->columnsforrow[i][j]; 61 DrawRectangle(draw,x,y,x+1,y+1,i+1,i+1,i+1,i+1); 62 } 63 } 64 ierr = DrawCheckResizedWindow(draw); 65 ierr = DrawSyncGetMouseButton(draw,&button,&xc,&yc,0,0); 66 } 67 68 return 0; 69 } 70 71 #undef __FUNC__ 72 #define __FUNC__ "MatFDColoringView" 73 /*@C 74 MatFDColoringView - Views a finite difference coloring context. 75 76 Input Parameters: 77 . c - the coloring context 78 . viewer - visualization context 79 80 Notes: 81 The available visualization contexts include 82 $ VIEWER_STDOUT_SELF - standard output (default) 83 $ 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 $ VIEWER_DRAWX_WORLD - graphical display of nonzero structure 88 89 .seealso: MatFDColoringCreate() 90 91 .keywords: Mat, finite differences, coloring, view 92 @*/ 93 int MatFDColoringView(MatFDColoring c,Viewer viewer) 94 { 95 ViewerType vtype; 96 int i,j,format,ierr; 97 FILE *fd; 98 99 PetscValidHeaderSpecific(c,MAT_FDCOLORING_COOKIE); 100 if (viewer) {PetscValidHeader(viewer);} 101 else {viewer = VIEWER_STDOUT_SELF;} 102 103 ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr); 104 if (vtype == DRAW_VIEWER) { 105 ierr = MatFDColoringView_Draw(c,viewer); CHKERRQ(ierr); 106 return 0; 107 } 108 else if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) { 109 ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr); 110 PetscFPrintf(c->comm,fd,"MatFDColoring Object:\n"); 111 PetscFPrintf(c->comm,fd," Error tolerance=%g\n",c->error_rel); 112 PetscFPrintf(c->comm,fd," Umin=%g\n",c->umin); 113 PetscFPrintf(c->comm,fd," Number of colors=%d\n",c->ncolors); 114 115 ierr = ViewerGetFormat(viewer,&format); CHKERRQ(ierr); 116 if (format != VIEWER_FORMAT_ASCII_INFO) { 117 for ( i=0; i<c->ncolors; i++ ) { 118 PetscFPrintf(c->comm,fd," Information for color %d\n",i); 119 PetscFPrintf(c->comm,fd," Number of columns %d\n",c->ncolumns[i]); 120 for ( j=0; j<c->ncolumns[i]; j++ ) { 121 PetscFPrintf(c->comm,fd," %d\n",c->columns[i][j]); 122 } 123 PetscFPrintf(c->comm,fd," Number of rows %d\n",c->nrows[i]); 124 for ( j=0; j<c->nrows[i]; j++ ) { 125 PetscFPrintf(c->comm,fd," %d %d \n",c->rows[i][j],c->columnsforrow[i][j]); 126 } 127 } 128 } 129 } 130 return 0; 131 } 132 133 #undef __FUNC__ 134 #define __FUNC__ "MatFDColoringSetParameters" 135 /*@ 136 MatFDColoringSetParameters - Sets the parameters for the sparse approximation of 137 a Jacobian matrix using finite differences. 138 139 $ J(u)_{:,i} = [J(u+h*dx_{i}) - J(u)]/h where 140 $ h = error_rel*u[i] if u[i] > umin 141 $ = error_rel*umin else 142 $ 143 $ dx_{i} = (0, ... 1, .... 0) 144 145 Input Parameters: 146 . coloring - the coloring context 147 . error_rel - relative error 148 . umin - minimum allowable u-value 149 150 .keywords: Mat, finite differences, coloring, set, parameters 151 152 .seealso: MatFDColoringCreate() 153 @*/ 154 int MatFDColoringSetParameters(MatFDColoring matfd,double error,double umin) 155 { 156 PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE); 157 158 if (error != PETSC_DEFAULT) matfd->error_rel = error; 159 if (umin != PETSC_DEFAULT) matfd->umin = umin; 160 return 0; 161 } 162 163 #undef __FUNC__ 164 #define __FUNC__ "MatFDColoringSetFrequency" 165 /*@ 166 MatFDColoringSetFrequency - Sets the frequency for computing new Jacobian 167 matrices. 168 169 Input Parameters: 170 . coloring - the coloring context 171 . freq - frequency (default is 1) 172 173 Notes: 174 Using a modified Newton strategy, where the Jacobian remains fixed for several 175 iterations, can be cost effective in terms of overall nonlinear solution 176 efficiency. This parameter indicates that a new Jacobian will be computed every 177 <freq> nonlinear iterations. 178 179 Options Database Keys: 180 $ -mat_fd_coloring_freq <freq> 181 182 .keywords: Mat, finite differences, coloring, set, frequency 183 @*/ 184 int MatFDColoringSetFrequency(MatFDColoring matfd,int freq) 185 { 186 PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE); 187 188 matfd->freq = freq; 189 return 0; 190 } 191 192 #undef __FUNC__ 193 #define __FUNC__ "MatFDColoringSetFunction" 194 /*@ 195 MatFDColoringSetFunction - Sets the function to use for computing the Jacobian. 196 197 Input Parameters: 198 . coloring - the coloring context 199 . f - the function 200 . fctx - the function context 201 202 .keywords: Mat, Jacobian, finite differences, set, function 203 @*/ 204 int MatFDColoringSetFunction(MatFDColoring matfd,int (*f)(void *,Vec,Vec,void *),void *fctx) 205 { 206 PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE); 207 208 matfd->f = f; 209 matfd->fctx = fctx; 210 211 return 0; 212 } 213 214 #undef __FUNC__ 215 #define __FUNC__ "MatFDColoringSetFromOptions" 216 /*@ 217 MatFDColoringSetFromOptions - Sets coloring finite difference parameters from 218 the options database. 219 220 The Jacobian is estimated with the differencing approximation 221 $ J(u)_{:,i} = [J(u+h*dx_{i}) - J(u)]/h where 222 $ h = error_rel*u[i] if u[i] > umin 223 $ = error_rel*umin else 224 $ 225 $ dx_{i} = (0, ... 1, .... 0) 226 227 Input Parameters: 228 . coloring - the coloring context 229 230 Options Database Keys: 231 $ -mat_fd_coloring_error <err>, where <err> is the square root 232 $ of relative error in the function 233 $ -mat_fd_coloring_umin <umin>, where umin is described above 234 $ -mat_fd_coloring_freq <freq> where <freq> is the frequency of 235 $ computing a new Jacobian 236 237 .keywords: Mat, finite differences, parameters 238 @*/ 239 int MatFDColoringSetFromOptions(MatFDColoring matfd) 240 { 241 int ierr,flag,freq = 1; 242 double error = PETSC_DEFAULT,umin = PETSC_DEFAULT; 243 PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE); 244 245 ierr = OptionsGetDouble(matfd->prefix,"-mat_fd_coloring_err",&error,&flag);CHKERRQ(ierr); 246 ierr = OptionsGetDouble(matfd->prefix,"-mat_fd_coloring_umin",&umin,&flag);CHKERRQ(ierr); 247 ierr = MatFDColoringSetParameters(matfd,error,umin); CHKERRQ(ierr); 248 ierr = OptionsGetInt(matfd->prefix,"-mat_fd_coloring_freq",&freq,&flag);CHKERRQ(ierr); 249 ierr = MatFDColoringSetFrequency(matfd,freq);CHKERRQ(ierr); 250 ierr = OptionsHasName(PETSC_NULL,"-help",&flag); CHKERRQ(ierr); 251 if (flag) { 252 ierr = MatFDColoringPrintHelp(matfd); CHKERRQ(ierr); 253 } 254 return 0; 255 } 256 257 #undef __FUNC__ 258 #define __FUNC__ "MatFDColoringPrintHelp" 259 /*@ 260 MatFDColoringPrintHelp - Prints help message for matrix finite difference calculations 261 using coloring. 262 263 Input Parameter: 264 . fdcoloring - the MatFDColoring context 265 266 .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringSetFromOptions() 267 @*/ 268 int MatFDColoringPrintHelp(MatFDColoring fd) 269 { 270 PetscValidHeaderSpecific(fd,MAT_FDCOLORING_COOKIE); 271 272 PetscPrintf(fd->comm,"-mat_fd_coloring_err <err>: set sqrt rel tol in function, defaults to %g\n",fd->error_rel); 273 PetscPrintf(fd->comm,"-mat_fd_coloring_umin <umin>: see users manual, defaults to %d\n",fd->umin); 274 PetscPrintf(fd->comm,"-mat_fd_coloring_freq <freq>: frequency that Jacobian is recomputed, defaults to %d\n",fd->freq); 275 PetscPrintf(fd->comm,"-mat_fd_coloring_view\n"); 276 PetscPrintf(fd->comm,"-mat_fd_coloring_view_draw\n"); 277 PetscPrintf(fd->comm,"-mat_fd_coloring_view_info\n"); 278 return 0; 279 } 280 281 int MatFDColoringView_Private(MatFDColoring fd) 282 { 283 int ierr,flg; 284 285 ierr = OptionsHasName(PETSC_NULL,"-mat_fd_coloring_view",&flg); CHKERRQ(ierr); 286 if (flg) { 287 Viewer viewer; 288 ierr = ViewerFileOpenASCII(fd->comm,"stdout",&viewer);CHKERRQ(ierr); 289 ierr = MatFDColoringView(fd,viewer); CHKERRQ(ierr); 290 ierr = ViewerDestroy(viewer); CHKERRQ(ierr); 291 } 292 ierr = OptionsHasName(PETSC_NULL,"-mat_fd_coloring_view_info",&flg); CHKERRQ(ierr); 293 if (flg) { 294 Viewer viewer; 295 ierr = ViewerFileOpenASCII(fd->comm,"stdout",&viewer);CHKERRQ(ierr); 296 ierr = ViewerPushFormat(viewer,VIEWER_FORMAT_ASCII_INFO,PETSC_NULL);CHKERRQ(ierr); 297 ierr = MatFDColoringView(fd,viewer); CHKERRQ(ierr); 298 ierr = ViewerPopFormat(viewer);CHKERRQ(ierr); 299 ierr = ViewerDestroy(viewer); CHKERRQ(ierr); 300 } 301 ierr = OptionsHasName(PETSC_NULL,"-mat_fd_coloring_view_draw",&flg); CHKERRQ(ierr); 302 if (flg) { 303 ierr = MatFDColoringView(fd,VIEWER_DRAWX_(fd->comm)); CHKERRQ(ierr); 304 ierr = ViewerFlush(VIEWER_DRAWX_(fd->comm)); CHKERRQ(ierr); 305 } 306 return 0; 307 } 308 309 #undef __FUNC__ 310 #define __FUNC__ "MatFDColoringCreate" 311 /*@C 312 MatFDColoringCreate - Creates a matrix coloring context for finite difference 313 computation of Jacobians. 314 315 Input Parameters: 316 . mat - the matrix containing the nonzero structure of the Jacobian 317 . iscoloring - the coloring of the matrix 318 319 Output Parameter: 320 . color - the new coloring context 321 322 Options Database Keys: 323 $ -mat_fd_coloring_view 324 $ -mat_fd_coloring_view_draw 325 $ -mat_fd_coloring_view_info 326 327 .seealso: MatFDColoringDestroy() 328 @*/ 329 int MatFDColoringCreate(Mat mat,ISColoring iscoloring,MatFDColoring *color) 330 { 331 MatFDColoring c; 332 MPI_Comm comm; 333 int ierr,M,N; 334 335 ierr = MatGetSize(mat,&M,&N); CHKERRQ(ierr); 336 if (M != N) SETERRQ(PETSC_ERR_SUP,0,"Only for square matrices"); 337 338 PetscObjectGetComm((PetscObject)mat,&comm); 339 PetscHeaderCreate(c,_p_MatFDColoring,MAT_FDCOLORING_COOKIE,0,comm,MatFDColoringDestroy,MatFDColoringView); 340 PLogObjectCreate(c); 341 342 if (mat->ops.fdcoloringcreate) { 343 ierr = (*mat->ops.fdcoloringcreate)(mat,iscoloring,c); CHKERRQ(ierr); 344 } else { 345 SETERRQ(PETSC_ERR_SUP,0,"Code not yet written for this matrix type"); 346 } 347 348 c->error_rel = 1.e-8; 349 c->umin = 1.e-6; 350 c->freq = 1; 351 352 ierr = MatFDColoringView_Private(c); CHKERRQ(ierr); 353 354 *color = c; 355 356 return 0; 357 } 358 359 #undef __FUNC__ 360 #define __FUNC__ "MatFDColoringDestroy" 361 /*@C 362 MatFDColoringDestroy - Destroys a matrix coloring context that was created 363 via MatFDColoringCreate(). 364 365 Input Parameter: 366 . c - coloring context 367 368 .seealso: MatFDColoringCreate() 369 @*/ 370 int MatFDColoringDestroy(MatFDColoring c) 371 { 372 int i,ierr,flag; 373 374 if (--c->refct > 0) return 0; 375 376 ierr = OptionsHasName(PETSC_NULL,"-matfdcoloring_view",&flag); 377 if (flag) { 378 Viewer viewer; 379 ierr = ViewerFileOpenASCII(c->comm,"stdout",&viewer);CHKERRQ(ierr); 380 ierr = MatFDColoringView(c,viewer);CHKERRQ(ierr); 381 ierr = ViewerDestroy(viewer); CHKERRQ(ierr); 382 } 383 ierr = OptionsHasName(PETSC_NULL,"-matfdcoloring_view_info",&flag); 384 if (flag) { 385 Viewer viewer; 386 ierr = ViewerFileOpenASCII(c->comm,"stdout",&viewer);CHKERRQ(ierr); 387 ierr = ViewerPushFormat(viewer,VIEWER_FORMAT_ASCII_INFO, PETSC_NULL); CHKERRQ(ierr); 388 ierr = MatFDColoringView(c,viewer);CHKERRQ(ierr); 389 ierr = ViewerPopFormat(viewer); 390 ierr = ViewerDestroy(viewer); CHKERRQ(ierr); 391 } 392 393 for ( i=0; i<c->ncolors; i++ ) { 394 if (c->columns[i]) PetscFree(c->columns[i]); 395 if (c->rows[i]) PetscFree(c->rows[i]); 396 if (c->columnsforrow[i]) PetscFree(c->columnsforrow[i]); 397 } 398 PetscFree(c->ncolumns); 399 PetscFree(c->columns); 400 PetscFree(c->nrows); 401 PetscFree(c->rows); 402 PetscFree(c->columnsforrow); 403 PetscFree(c->scale); 404 if (c->w1) { 405 ierr = VecDestroy(c->w1); CHKERRQ(ierr); 406 ierr = VecDestroy(c->w2); CHKERRQ(ierr); 407 ierr = VecDestroy(c->w3); CHKERRQ(ierr); 408 } 409 PLogObjectDestroy(c); 410 PetscHeaderDestroy(c); 411 return 0; 412 } 413 414 #include "snes.h" 415 416 #undef __FUNC__ 417 #define __FUNC__ "MatFDColoringApply" 418 /*@ 419 MatFDColoringApply - Given a matrix for which a MatFDColoring context 420 has been created, computes the Jacobian for a function via finite differences. 421 422 Input Parameters: 423 . mat - location to store Jacobian 424 . coloring - coloring context created with MatFDColoringCreate() 425 . x1 - location at which Jacobian is to be computed 426 . sctx - optional context required by function (actually a SNES context) 427 428 .seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView() 429 430 .keywords: coloring, Jacobian, finite differences 431 @*/ 432 int MatFDColoringApply(Mat J,MatFDColoring coloring,Vec x1,MatStructure *flag,void *sctx) 433 { 434 int k,fg,ierr,N,start,end,l,row,col,srow; 435 Scalar dx, mone = -1.0,*y,*scale = coloring->scale,*xx,*wscale = coloring->wscale; 436 double epsilon = coloring->error_rel, umin = coloring->umin; 437 MPI_Comm comm = coloring->comm; 438 Vec w1,w2,w3; 439 int (*f)(void *,Vec,Vec,void *) = coloring->f; 440 void *fctx = coloring->fctx; 441 442 PetscValidHeaderSpecific(J,MAT_COOKIE); 443 PetscValidHeaderSpecific(coloring,MAT_FDCOLORING_COOKIE); 444 PetscValidHeaderSpecific(x1,VEC_COOKIE); 445 446 /* 447 ierr = SNESGetIterationNumber((SNES)sctx,&it); CHKERRQ(ierr); 448 if ((freq > 1) && ((it % freq) != 1)) { 449 PLogInfo(coloring,"MatFDColoringApply:Skipping Jacobian, iteration %d, freq %d\n",it,freq); 450 *flag = SAME_PRECONDITIONER; 451 return 0; 452 } else { 453 PLogInfo(coloring,"MatFDColoringApply:Computing Jacobian, iteration %d, freq %d\n",it,freq); 454 *flag = SAME_NONZERO_PATTERN; 455 }*/ 456 457 if (!coloring->w1) { 458 ierr = VecDuplicate(x1,&coloring->w1); CHKERRQ(ierr); 459 PLogObjectParent(coloring,coloring->w1); 460 ierr = VecDuplicate(x1,&coloring->w2); CHKERRQ(ierr); 461 PLogObjectParent(coloring,coloring->w2); 462 ierr = VecDuplicate(x1,&coloring->w3); CHKERRQ(ierr); 463 PLogObjectParent(coloring,coloring->w3); 464 } 465 w1 = coloring->w1; w2 = coloring->w2; w3 = coloring->w3; 466 467 ierr = OptionsHasName(PETSC_NULL,"-mat_fd_coloring_dont_rezero",&fg); CHKERRQ(ierr); 468 if (fg) { 469 PLogInfo(coloring,"MatFDColoringApply: Not calling MatZeroEntries()\n"); 470 } else { 471 ierr = MatZeroEntries(J); CHKERRQ(ierr); 472 } 473 474 ierr = VecGetOwnershipRange(x1,&start,&end); CHKERRQ(ierr); 475 ierr = VecGetSize(x1,&N); CHKERRQ(ierr); 476 ierr = VecGetArray(x1,&xx); CHKERRQ(ierr); 477 ierr = (*f)(sctx,x1,w1,fctx); CHKERRQ(ierr); 478 479 PetscMemzero(wscale,N*sizeof(Scalar)); 480 /* 481 Loop over each color 482 */ 483 484 for (k=0; k<coloring->ncolors; k++) { 485 ierr = VecCopy(x1,w3); CHKERRQ(ierr); 486 /* 487 Loop over each column associated with color adding the 488 perturbation to the vector w3. 489 */ 490 for (l=0; l<coloring->ncolumns[k]; l++) { 491 col = coloring->columns[k][l]; /* column of the matrix we are probing for */ 492 dx = xx[col-start]; 493 if (dx == 0.0) dx = 1.0; 494 #if !defined(PETSC_COMPLEX) 495 if (dx < umin && dx >= 0.0) dx = umin; 496 else if (dx < 0.0 && dx > -umin) dx = -umin; 497 #else 498 if (abs(dx) < umin && real(dx) >= 0.0) dx = umin; 499 else if (real(dx) < 0.0 && abs(dx) < umin) dx = -umin; 500 #endif 501 dx *= epsilon; 502 wscale[col] = 1.0/dx; 503 VecSetValues(w3,1,&col,&dx,ADD_VALUES); 504 } 505 VecRestoreArray(x1,&xx); 506 /* 507 Evaluate function at x1 + dx (here dx is a vector of perturbations) 508 */ 509 ierr = (*f)(sctx,w3,w2,fctx); CHKERRQ(ierr); 510 ierr = VecAXPY(&mone,w1,w2); CHKERRQ(ierr); 511 /* Communicate scale to all processors */ 512 #if !defined(PETSC_COMPLEX) 513 MPI_Allreduce(wscale,scale,N,MPI_DOUBLE,MPI_SUM,comm); 514 #else 515 MPI_Allreduce(wscale,scale,2*N,MPI_DOUBLE,MPI_SUM,comm); 516 #endif 517 /* 518 Loop over rows of vector, putting results into Jacobian matrix 519 */ 520 VecGetArray(w2,&y); 521 for (l=0; l<coloring->nrows[k]; l++) { 522 row = coloring->rows[k][l]; 523 col = coloring->columnsforrow[k][l]; 524 y[row] *= scale[col]; 525 srow = row + start; 526 ierr = MatSetValues(J,1,&srow,1,&col,y+row,INSERT_VALUES);CHKERRQ(ierr); 527 } 528 VecRestoreArray(w2,&y); 529 } 530 ierr = MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr); 531 ierr = MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr); 532 return 0; 533 } 534