1 #include <petsc/private/drawimpl.h> /*I "petscdraw.h" I*/ 2 3 #define PETSC_DRAW_AXIS_MAX_SEGMENTS 20 4 PetscClassId PETSC_DRAWAXIS_CLASSID = 0; 5 6 /*@ 7 PetscDrawAxisCreate - Generate the axis data structure. 8 9 Collective on PetscDraw 10 11 Input Parameters: 12 . win - PetscDraw object where axis to to be made 13 14 Output Parameter: 15 . axis - the axis datastructure 16 17 Notes: 18 the MPI communicator that owns the underlying draw object owns the PetscDrawAxis object, but calls to set PetscDrawAxis options are ignored by all processes 19 except the first MPI process in the communicator 20 21 Level: advanced 22 23 .seealso: PetscDrawLGCreate(), PetscDrawLG, PetscDrawSPCreate(), PetscDrawSP, PetscDrawHGCreate(), PetscDrawHG, PetscDrawBarCreate(), PetscDrawBar, PetscDrawLGGetAxis(), PetscDrawSPGetAxis(), 24 PetscDrawHGGetAxis(), PetscDrawBarGetAxis(), PetscDrawAxis, PetscDrawAxisDestroy(), PetscDrawAxisSetColors(), PetscDrawAxisSetLabels(), PetscDrawAxisSetLimits(), PetscDrawAxisGetLimits(), PetscDrawAxisSetHoldLimits(), 25 PetscDrawAxisDraw() 26 @*/ 27 PetscErrorCode PetscDrawAxisCreate(PetscDraw draw,PetscDrawAxis *axis) 28 { 29 PetscDrawAxis ad; 30 PetscErrorCode ierr; 31 32 PetscFunctionBegin; 33 PetscValidHeaderSpecific(draw,PETSC_DRAW_CLASSID,1); 34 PetscValidPointer(axis,2); 35 36 ierr = PetscHeaderCreate(ad,PETSC_DRAWAXIS_CLASSID,"DrawAxis","Draw Axis","Draw",PetscObjectComm((PetscObject)draw),PetscDrawAxisDestroy,NULL);CHKERRQ(ierr); 37 ierr = PetscLogObjectParent((PetscObject)draw,(PetscObject)ad);CHKERRQ(ierr); 38 39 ierr = PetscObjectReference((PetscObject)draw);CHKERRQ(ierr); 40 ad->win = draw; 41 42 ad->xticks = PetscADefTicks; 43 ad->yticks = PetscADefTicks; 44 ad->xlabelstr = PetscADefLabel; 45 ad->ylabelstr = PetscADefLabel; 46 ad->ac = PETSC_DRAW_BLACK; 47 ad->tc = PETSC_DRAW_BLACK; 48 ad->cc = PETSC_DRAW_BLACK; 49 ad->xlabel = NULL; 50 ad->ylabel = NULL; 51 ad->toplabel = NULL; 52 53 *axis = ad; 54 PetscFunctionReturn(0); 55 } 56 57 /*@ 58 PetscDrawAxisDestroy - Frees the space used by an axis structure. 59 60 Collective on PetscDrawAxis 61 62 Input Parameters: 63 . axis - the axis context 64 65 Level: advanced 66 67 .seealso: PetscDrawAxisCreate(), PetscDrawAxis 68 @*/ 69 PetscErrorCode PetscDrawAxisDestroy(PetscDrawAxis *axis) 70 { 71 PetscErrorCode ierr; 72 73 PetscFunctionBegin; 74 if (!*axis) PetscFunctionReturn(0); 75 PetscValidHeaderSpecific(*axis,PETSC_DRAWAXIS_CLASSID,1); 76 if (--((PetscObject)(*axis))->refct > 0) {*axis = NULL; PetscFunctionReturn(0);} 77 78 ierr = PetscFree((*axis)->toplabel);CHKERRQ(ierr); 79 ierr = PetscFree((*axis)->xlabel);CHKERRQ(ierr); 80 ierr = PetscFree((*axis)->ylabel);CHKERRQ(ierr); 81 ierr = PetscDrawDestroy(&(*axis)->win);CHKERRQ(ierr); 82 ierr = PetscHeaderDestroy(axis);CHKERRQ(ierr); 83 PetscFunctionReturn(0); 84 } 85 86 /*@ 87 PetscDrawAxisSetColors - Sets the colors to be used for the axis, 88 tickmarks, and text. 89 90 Logically Collective on PetscDrawAxis 91 92 Input Parameters: 93 + axis - the axis 94 . ac - the color of the axis lines 95 . tc - the color of the tick marks 96 - cc - the color of the text strings 97 98 Level: advanced 99 100 .seealso: PetscDrawAxisCreate(), PetscDrawAxis, PetscDrawAxisSetLabels(), PetscDrawAxisDraw(), PetscDrawAxisSetLimits() 101 @*/ 102 PetscErrorCode PetscDrawAxisSetColors(PetscDrawAxis axis,int ac,int tc,int cc) 103 { 104 PetscFunctionBegin; 105 PetscValidHeaderSpecific(axis,PETSC_DRAWAXIS_CLASSID,1); 106 PetscValidLogicalCollectiveInt(axis,ac,2); 107 PetscValidLogicalCollectiveInt(axis,tc,3); 108 PetscValidLogicalCollectiveInt(axis,cc,4); 109 axis->ac = ac; axis->tc = tc; axis->cc = cc; 110 PetscFunctionReturn(0); 111 } 112 113 /*@C 114 PetscDrawAxisSetLabels - Sets the x and y axis labels. 115 116 Logically Collective on PetscDrawAxis 117 118 Input Parameters: 119 + axis - the axis 120 . top - the label at the top of the image 121 - xlabel,ylabel - the labes for the x and y axis 122 123 Notes: 124 Must be called before PetscDrawAxisDraw() or PetscDrawLGDraw() 125 There should be no newlines in the arguments 126 127 Level: advanced 128 129 .seealso: PetscDrawAxisCreate(), PetscDrawAxis, PetscDrawAxisSetColors(), PetscDrawAxisDraw(), PetscDrawAxisSetLimits() 130 @*/ 131 PetscErrorCode PetscDrawAxisSetLabels(PetscDrawAxis axis,const char top[],const char xlabel[],const char ylabel[]) 132 { 133 PetscErrorCode ierr; 134 135 PetscFunctionBegin; 136 PetscValidHeaderSpecific(axis,PETSC_DRAWAXIS_CLASSID,1); 137 ierr = PetscFree(axis->xlabel);CHKERRQ(ierr); 138 ierr = PetscFree(axis->ylabel);CHKERRQ(ierr); 139 ierr = PetscFree(axis->toplabel);CHKERRQ(ierr); 140 ierr = PetscStrallocpy(xlabel,&axis->xlabel);CHKERRQ(ierr); 141 ierr = PetscStrallocpy(ylabel,&axis->ylabel);CHKERRQ(ierr); 142 ierr = PetscStrallocpy(top,&axis->toplabel);CHKERRQ(ierr); 143 PetscFunctionReturn(0); 144 } 145 146 /*@ 147 PetscDrawAxisSetLimits - Sets the limits (in user coords) of the axis 148 149 Logically Collective on PetscDrawAxis 150 151 Input Parameters: 152 + axis - the axis 153 . xmin,xmax - limits in x 154 - ymin,ymax - limits in y 155 156 Options Database: 157 . -drawaxis_hold - hold the initial set of axis limits for future plotting 158 159 Level: advanced 160 161 .seealso: PetscDrawAxisSetHoldLimits(), PetscDrawAxisGetLimits(), PetscDrawAxisSetLabels(), PetscDrawAxisSetColors() 162 163 @*/ 164 PetscErrorCode PetscDrawAxisSetLimits(PetscDrawAxis axis,PetscReal xmin,PetscReal xmax,PetscReal ymin,PetscReal ymax) 165 { 166 PetscErrorCode ierr; 167 168 PetscFunctionBegin; 169 PetscValidHeaderSpecific(axis,PETSC_DRAWAXIS_CLASSID,1); 170 if (axis->hold) PetscFunctionReturn(0); 171 axis->xlow = xmin; 172 axis->xhigh= xmax; 173 axis->ylow = ymin; 174 axis->yhigh= ymax; 175 ierr = PetscOptionsHasName(((PetscObject)axis)->options,((PetscObject)axis)->prefix,"-drawaxis_hold",&axis->hold);CHKERRQ(ierr); 176 PetscFunctionReturn(0); 177 } 178 179 /*@ 180 PetscDrawAxisGetLimits - Gets the limits (in user coords) of the axis 181 182 Not Collective 183 184 Input Parameters: 185 + axis - the axis 186 . xmin,xmax - limits in x 187 - ymin,ymax - limits in y 188 189 Level: advanced 190 191 .seealso: PetscDrawAxisCreate(), PetscDrawAxis, PetscDrawAxisSetHoldLimits(), PetscDrawAxisSetLimits(), PetscDrawAxisSetLabels(), PetscDrawAxisSetColors() 192 193 @*/ 194 PetscErrorCode PetscDrawAxisGetLimits(PetscDrawAxis axis,PetscReal *xmin,PetscReal *xmax,PetscReal *ymin,PetscReal *ymax) 195 { 196 PetscFunctionBegin; 197 PetscValidHeaderSpecific(axis,PETSC_DRAWAXIS_CLASSID,1); 198 if (xmin) *xmin = axis->xlow; 199 if (xmax) *xmax = axis->xhigh; 200 if (ymin) *ymin = axis->ylow; 201 if (ymax) *ymax = axis->yhigh; 202 PetscFunctionReturn(0); 203 } 204 205 /*@ 206 PetscDrawAxisSetHoldLimits - Causes an axis to keep the same limits until this is called 207 again 208 209 Logically Collective on PetscDrawAxis 210 211 Input Parameters: 212 + axis - the axis 213 - hold - PETSC_TRUE - hold current limits, PETSC_FALSE allow limits to be changed 214 215 Level: advanced 216 217 Notes: 218 Once this has been called with PETSC_TRUE the limits will not change if you call 219 PetscDrawAxisSetLimits() until you call this with PETSC_FALSE 220 221 .seealso: PetscDrawAxisCreate(), PetscDrawAxis, PetscDrawAxisGetLimits(), PetscDrawAxisSetLimits(), PetscDrawAxisSetLabels(), PetscDrawAxisSetColors() 222 223 @*/ 224 PetscErrorCode PetscDrawAxisSetHoldLimits(PetscDrawAxis axis,PetscBool hold) 225 { 226 PetscFunctionBegin; 227 PetscValidHeaderSpecific(axis,PETSC_DRAWAXIS_CLASSID,1); 228 PetscValidLogicalCollectiveBool(axis,hold,2); 229 axis->hold = hold; 230 PetscFunctionReturn(0); 231 } 232 233 /*@ 234 PetscDrawAxisDraw - PetscDraws an axis. 235 236 Collective on PetscDrawAxis 237 238 Input Parameter: 239 . axis - Axis structure 240 241 Level: advanced 242 243 Note: 244 This draws the actual axis. The limits etc have already been set. 245 By picking special routines for the ticks and labels, special 246 effects may be generated. These routines are part of the Axis 247 structure (axis). 248 249 .seealso: PetscDrawAxisCreate(), PetscDrawAxis, PetscDrawAxisGetLimits(), PetscDrawAxisSetLimits(), PetscDrawAxisSetLabels(), PetscDrawAxisSetColors() 250 251 @*/ 252 PetscErrorCode PetscDrawAxisDraw(PetscDrawAxis axis) 253 { 254 int i,ntick,numx,numy,ac,tc,cc; 255 PetscMPIInt rank; 256 size_t len,ytlen=0; 257 PetscReal coors[4],tickloc[PETSC_DRAW_AXIS_MAX_SEGMENTS],sep,tw,th; 258 PetscReal xl,xr,yl,yr,dxl=0,dyl=0,dxr=0,dyr=0; 259 char *p; 260 PetscDraw draw; 261 PetscBool isnull; 262 PetscErrorCode ierr; 263 264 PetscFunctionBegin; 265 PetscValidHeaderSpecific(axis,PETSC_DRAWAXIS_CLASSID,1); 266 ierr = PetscDrawIsNull(axis->win,&isnull);CHKERRQ(ierr); 267 if (isnull) PetscFunctionReturn(0); 268 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)axis),&rank);CHKERRMPI(ierr); 269 270 draw = axis->win; 271 272 ac = axis->ac; tc = axis->tc; cc = axis->cc; 273 if (axis->xlow == axis->xhigh) {axis->xlow -= .5; axis->xhigh += .5;} 274 if (axis->ylow == axis->yhigh) {axis->ylow -= .5; axis->yhigh += .5;} 275 276 ierr = PetscDrawCollectiveBegin(draw);CHKERRQ(ierr); 277 if (rank) goto finally; 278 279 /* get cannonical string size */ 280 ierr = PetscDrawSetCoordinates(draw,0,0,1,1);CHKERRQ(ierr); 281 ierr = PetscDrawStringGetSize(draw,&tw,&th);CHKERRQ(ierr); 282 /* lower spacing */ 283 if (axis->xlabelstr) dyl += 1.5*th; 284 if (axis->xlabel) dyl += 1.5*th; 285 /* left spacing */ 286 if (axis->ylabelstr) dxl += 7.5*tw; 287 if (axis->ylabel) dxl += 2.0*tw; 288 /* right and top spacing */ 289 if (axis->xlabelstr) dxr = 2.5*tw; 290 if (axis->ylabelstr) dyr = 0.5*th; 291 if (axis->toplabel) dyr = 1.5*th; 292 /* extra spacing */ 293 dxl += 0.7*tw; dxr += 0.5*tw; 294 dyl += 0.2*th; dyr += 0.2*th; 295 /* determine coordinates */ 296 xl = (dxl*axis->xhigh + dxr*axis->xlow - axis->xlow) / (dxl + dxr - 1); 297 xr = (dxl*axis->xhigh + dxr*axis->xlow - axis->xhigh) / (dxl + dxr - 1); 298 yl = (dyl*axis->yhigh + dyr*axis->ylow - axis->ylow) / (dyl + dyr - 1); 299 yr = (dyl*axis->yhigh + dyr*axis->ylow - axis->yhigh) / (dyl + dyr - 1); 300 ierr = PetscDrawSetCoordinates(draw,xl,yl,xr,yr);CHKERRQ(ierr); 301 ierr = PetscDrawStringGetSize(draw,&tw,&th);CHKERRQ(ierr); 302 303 /* PetscDraw the axis lines */ 304 ierr = PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xhigh,axis->ylow,ac);CHKERRQ(ierr); 305 ierr = PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xlow,axis->yhigh,ac);CHKERRQ(ierr); 306 ierr = PetscDrawLine(draw,axis->xlow,axis->yhigh,axis->xhigh,axis->yhigh,ac);CHKERRQ(ierr); 307 ierr = PetscDrawLine(draw,axis->xhigh,axis->ylow,axis->xhigh,axis->yhigh,ac);CHKERRQ(ierr); 308 309 /* PetscDraw the top label */ 310 if (axis->toplabel) { 311 PetscReal x = (axis->xlow + axis->xhigh)/2, y = axis->yhigh + 0.5*th; 312 ierr = PetscDrawStringCentered(draw,x,y,cc,axis->toplabel);CHKERRQ(ierr); 313 } 314 315 /* PetscDraw the X ticks and labels */ 316 if (axis->xticks) { 317 numx = (int)(.15*(axis->xhigh-axis->xlow)/tw); numx = PetscClipInterval(numx,2,6); 318 ierr = (*axis->xticks)(axis->xlow,axis->xhigh,numx,&ntick,tickloc,PETSC_DRAW_AXIS_MAX_SEGMENTS);CHKERRQ(ierr); 319 /* PetscDraw in tick marks */ 320 for (i=0; i<ntick; i++) { 321 ierr = PetscDrawLine(draw,tickloc[i],axis->ylow,tickloc[i],axis->ylow+.5*th,tc);CHKERRQ(ierr); 322 ierr = PetscDrawLine(draw,tickloc[i],axis->yhigh,tickloc[i],axis->yhigh-.5*th,tc);CHKERRQ(ierr); 323 } 324 /* label ticks */ 325 if (axis->xlabelstr) { 326 for (i=0; i<ntick; i++) { 327 if (i < ntick - 1) sep = tickloc[i+1] - tickloc[i]; 328 else if (i > 0) sep = tickloc[i] - tickloc[i-1]; 329 else sep = 0.0; 330 ierr = (*axis->xlabelstr)(tickloc[i],sep,&p);CHKERRQ(ierr); 331 ierr = PetscDrawStringCentered(draw,tickloc[i],axis->ylow-1.5*th,cc,p);CHKERRQ(ierr); 332 } 333 } 334 } 335 if (axis->xlabel) { 336 PetscReal x = (axis->xlow + axis->xhigh)/2, y = axis->ylow - 1.5*th; 337 if (axis->xlabelstr) y -= 1.5*th; 338 ierr = PetscDrawStringCentered(draw,x,y,cc,axis->xlabel);CHKERRQ(ierr); 339 } 340 341 /* PetscDraw the Y ticks and labels */ 342 if (axis->yticks) { 343 numy = (int)(.50*(axis->yhigh-axis->ylow)/th); numy = PetscClipInterval(numy,2,6); 344 ierr = (*axis->yticks)(axis->ylow,axis->yhigh,numy,&ntick,tickloc,PETSC_DRAW_AXIS_MAX_SEGMENTS);CHKERRQ(ierr); 345 /* PetscDraw in tick marks */ 346 for (i=0; i<ntick; i++) { 347 ierr = PetscDrawLine(draw,axis->xlow,tickloc[i],axis->xlow+.5*tw,tickloc[i],tc);CHKERRQ(ierr); 348 ierr = PetscDrawLine(draw,axis->xhigh,tickloc[i],axis->xhigh-.5*tw,tickloc[i],tc);CHKERRQ(ierr); 349 } 350 /* label ticks */ 351 if (axis->ylabelstr) { 352 for (i=0; i<ntick; i++) { 353 if (i < ntick - 1) sep = tickloc[i+1] - tickloc[i]; 354 else if (i > 0) sep = tickloc[i] - tickloc[i-1]; 355 else sep = 0.0; 356 ierr = (*axis->ylabelstr)(tickloc[i],sep,&p);CHKERRQ(ierr); 357 ierr = PetscStrlen(p,&len);CHKERRQ(ierr); ytlen = PetscMax(ytlen,len); 358 ierr = PetscDrawString(draw,axis->xlow-(len+.5)*tw,tickloc[i]-.5*th,cc,p);CHKERRQ(ierr); 359 } 360 } 361 } 362 if (axis->ylabel) { 363 PetscReal x = axis->xlow - 2.0*tw, y = (axis->ylow + axis->yhigh)/2; 364 if (axis->ylabelstr) x -= (ytlen+.5)*tw; 365 ierr = PetscStrlen(axis->ylabel,&len);CHKERRQ(ierr); 366 ierr = PetscDrawStringVertical(draw,x,y+len*th/2,cc,axis->ylabel);CHKERRQ(ierr); 367 } 368 369 ierr = PetscDrawGetCoordinates(draw,&coors[0],&coors[1],&coors[2],&coors[3]);CHKERRQ(ierr); 370 finally: 371 ierr = PetscDrawCollectiveEnd(draw);CHKERRQ(ierr); 372 ierr = MPI_Bcast(coors,4,MPIU_REAL,0,PetscObjectComm((PetscObject)draw));CHKERRMPI(ierr); 373 ierr = PetscDrawSetCoordinates(draw,coors[0],coors[1],coors[2],coors[3]);CHKERRQ(ierr); 374 PetscFunctionReturn(0); 375 } 376 377 /* 378 Removes all zeros but one from .0000 379 */ 380 PetscErrorCode PetscStripe0(char *buf) 381 { 382 PetscErrorCode ierr; 383 size_t n; 384 PetscBool flg; 385 char *str; 386 387 PetscFunctionBegin; 388 ierr = PetscStrlen(buf,&n);CHKERRQ(ierr); 389 ierr = PetscStrendswith(buf,"e00",&flg);CHKERRQ(ierr); 390 if (flg) buf[n-3] = 0; 391 ierr = PetscStrstr(buf,"e0",&str);CHKERRQ(ierr); 392 if (str) { 393 buf[n-2] = buf[n-1]; 394 buf[n-1] = 0; 395 } 396 ierr = PetscStrstr(buf,"e-0",&str);CHKERRQ(ierr); 397 if (str) { 398 buf[n-2] = buf[n-1]; 399 buf[n-1] = 0; 400 } 401 PetscFunctionReturn(0); 402 } 403 404 /* 405 Removes all zeros but one from .0000 406 */ 407 PetscErrorCode PetscStripAllZeros(char *buf) 408 { 409 PetscErrorCode ierr; 410 size_t i,n; 411 412 PetscFunctionBegin; 413 ierr = PetscStrlen(buf,&n);CHKERRQ(ierr); 414 if (buf[0] != '.') PetscFunctionReturn(0); 415 for (i=1; i<n; i++) { 416 if (buf[i] != '0') PetscFunctionReturn(0); 417 } 418 buf[0] = '0'; 419 buf[1] = 0; 420 PetscFunctionReturn(0); 421 } 422 423 /* 424 Removes trailing zeros 425 */ 426 PetscErrorCode PetscStripTrailingZeros(char *buf) 427 { 428 PetscErrorCode ierr; 429 char *found; 430 size_t i,n,m = PETSC_MAX_INT; 431 432 PetscFunctionBegin; 433 /* if there is an e in string DO NOT strip trailing zeros */ 434 ierr = PetscStrchr(buf,'e',&found);CHKERRQ(ierr); 435 if (found) PetscFunctionReturn(0); 436 437 ierr = PetscStrlen(buf,&n);CHKERRQ(ierr); 438 /* locate decimal point */ 439 for (i=0; i<n; i++) { 440 if (buf[i] == '.') {m = i; break;} 441 } 442 /* if not decimal point then no zeros to remove */ 443 if (m == PETSC_MAX_INT) PetscFunctionReturn(0); 444 /* start at right end of string removing 0s */ 445 for (i=n-1; i>m; i++) { 446 if (buf[i] != '0') PetscFunctionReturn(0); 447 buf[i] = 0; 448 } 449 PetscFunctionReturn(0); 450 } 451 452 /* 453 Removes leading 0 from 0.22 or -0.22 454 */ 455 PetscErrorCode PetscStripInitialZero(char *buf) 456 { 457 PetscErrorCode ierr; 458 size_t i,n; 459 460 PetscFunctionBegin; 461 ierr = PetscStrlen(buf,&n);CHKERRQ(ierr); 462 if (buf[0] == '0') { 463 for (i=0; i<n; i++) buf[i] = buf[i+1]; 464 } else if (buf[0] == '-' && buf[1] == '0') { 465 for (i=1; i<n; i++) buf[i] = buf[i+1]; 466 } 467 PetscFunctionReturn(0); 468 } 469 470 /* 471 Removes the extraneous zeros in numbers like 1.10000e6 472 */ 473 PetscErrorCode PetscStripZeros(char *buf) 474 { 475 PetscErrorCode ierr; 476 size_t i,j,n; 477 478 PetscFunctionBegin; 479 ierr = PetscStrlen(buf,&n);CHKERRQ(ierr); 480 if (n<5) PetscFunctionReturn(0); 481 for (i=1; i<n-1; i++) { 482 if (buf[i] == 'e' && buf[i-1] == '0') { 483 for (j=i; j<n+1; j++) buf[j-1] = buf[j]; 484 ierr = PetscStripZeros(buf);CHKERRQ(ierr); 485 PetscFunctionReturn(0); 486 } 487 } 488 PetscFunctionReturn(0); 489 } 490 491 /* 492 Removes the plus in something like 1.1e+2 or 1.1e+02 493 */ 494 PetscErrorCode PetscStripZerosPlus(char *buf) 495 { 496 PetscErrorCode ierr; 497 size_t i,j,n; 498 499 PetscFunctionBegin; 500 ierr = PetscStrlen(buf,&n);CHKERRQ(ierr); 501 if (n<5) PetscFunctionReturn(0); 502 for (i=1; i<n-2; i++) { 503 if (buf[i] == '+') { 504 if (buf[i+1] == '0') { 505 for (j=i+1; j<n; j++) buf[j-1] = buf[j+1]; 506 PetscFunctionReturn(0); 507 } else { 508 for (j=i+1; j<n+1; j++) buf[j-1] = buf[j]; 509 PetscFunctionReturn(0); 510 } 511 } else if (buf[i] == '-') { 512 if (buf[i+1] == '0') { 513 for (j=i+1; j<n; j++) buf[j] = buf[j+1]; 514 PetscFunctionReturn(0); 515 } 516 } 517 } 518 PetscFunctionReturn(0); 519 } 520