1 2 #include <petsc/private/viewerimpl.h> /*I "petscviewer.h" I*/ 3 #include <petscdraw.h> 4 5 PetscClassId PETSC_VIEWER_CLASSID; 6 7 static PetscBool PetscViewerPackageInitialized = PETSC_FALSE; 8 /*@C 9 PetscViewerFinalizePackage - This function destroys any global objects created in the Petsc viewers. It is 10 called from PetscFinalize(). 11 12 Level: developer 13 14 .seealso: `PetscFinalize()` 15 @*/ 16 PetscErrorCode PetscViewerFinalizePackage(void) 17 { 18 PetscFunctionBegin; 19 if (Petsc_Viewer_keyval != MPI_KEYVAL_INVALID) { 20 PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_keyval)); 21 } 22 if (Petsc_Viewer_Stdout_keyval != MPI_KEYVAL_INVALID) { 23 PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_Stdout_keyval)); 24 } 25 if (Petsc_Viewer_Stderr_keyval != MPI_KEYVAL_INVALID) { 26 PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_Stderr_keyval)); 27 } 28 if (Petsc_Viewer_Binary_keyval != MPI_KEYVAL_INVALID) { 29 PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_Binary_keyval)); 30 } 31 if (Petsc_Viewer_Draw_keyval != MPI_KEYVAL_INVALID) { 32 PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_Draw_keyval)); 33 } 34 #if defined(PETSC_HAVE_HDF5) 35 if (Petsc_Viewer_HDF5_keyval != MPI_KEYVAL_INVALID) { 36 PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_HDF5_keyval)); 37 } 38 #endif 39 #if defined(PETSC_USE_SOCKETVIEWER) 40 if (Petsc_Viewer_Socket_keyval != MPI_KEYVAL_INVALID) { 41 PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_Socket_keyval)); 42 } 43 #endif 44 PetscCall(PetscFunctionListDestroy(&PetscViewerList)); 45 PetscViewerPackageInitialized = PETSC_FALSE; 46 PetscViewerRegisterAllCalled = PETSC_FALSE; 47 PetscFunctionReturn(0); 48 } 49 50 /*@C 51 PetscViewerInitializePackage - This function initializes everything in the main PetscViewer package. 52 53 Level: developer 54 55 .seealso: `PetscInitialize()` 56 @*/ 57 PetscErrorCode PetscViewerInitializePackage(void) 58 { 59 char logList[256]; 60 PetscBool opt,pkg; 61 62 PetscFunctionBegin; 63 if (PetscViewerPackageInitialized) PetscFunctionReturn(0); 64 PetscViewerPackageInitialized = PETSC_TRUE; 65 /* Register Classes */ 66 PetscCall(PetscClassIdRegister("Viewer",&PETSC_VIEWER_CLASSID)); 67 /* Register Constructors */ 68 PetscCall(PetscViewerRegisterAll()); 69 /* Process Info */ 70 { 71 PetscClassId classids[1]; 72 73 classids[0] = PETSC_VIEWER_CLASSID; 74 PetscCall(PetscInfoProcessClass("viewer", 1, classids)); 75 } 76 /* Process summary exclusions */ 77 PetscCall(PetscOptionsGetString(NULL,NULL,"-log_exclude",logList,sizeof(logList),&opt)); 78 if (opt) { 79 PetscCall(PetscStrInList("viewer",logList,',',&pkg)); 80 if (pkg) PetscCall(PetscLogEventExcludeClass(PETSC_VIEWER_CLASSID)); 81 } 82 #if defined(PETSC_HAVE_MATHEMATICA) 83 PetscCall(PetscViewerMathematicaInitializePackage()); 84 #endif 85 /* Register package finalizer */ 86 PetscCall(PetscRegisterFinalize(PetscViewerFinalizePackage)); 87 PetscFunctionReturn(0); 88 } 89 90 /*@ 91 PetscViewerDestroy - Destroys a PetscViewer. 92 93 Collective on PetscViewer 94 95 Input Parameters: 96 . viewer - the PetscViewer to be destroyed. 97 98 Level: beginner 99 100 .seealso: `PetscViewerSocketOpen()`, `PetscViewerASCIIOpen()`, `PetscViewerCreate()`, `PetscViewerDrawOpen()` 101 102 @*/ 103 PetscErrorCode PetscViewerDestroy(PetscViewer *viewer) 104 { 105 PetscFunctionBegin; 106 if (!*viewer) PetscFunctionReturn(0); 107 PetscValidHeaderSpecific(*viewer,PETSC_VIEWER_CLASSID,1); 108 109 PetscCall(PetscViewerFlush(*viewer)); 110 if (--((PetscObject)(*viewer))->refct > 0) {*viewer = NULL; PetscFunctionReturn(0);} 111 112 PetscCall(PetscObjectSAWsViewOff((PetscObject)*viewer)); 113 if ((*viewer)->ops->destroy) { 114 PetscCall((*(*viewer)->ops->destroy)(*viewer)); 115 } 116 PetscCall(PetscHeaderDestroy(viewer)); 117 PetscFunctionReturn(0); 118 } 119 120 /*@C 121 PetscViewerAndFormatCreate - Creates a PetscViewerAndFormat struct. 122 123 Collective on PetscViewer 124 125 Input Parameters: 126 + viewer - the viewer 127 - format - the format 128 129 Output Parameter: 130 . vf - viewer and format object 131 132 Notes: 133 This increases the reference count of the viewer so you can destroy the viewer object after this call 134 Level: developer 135 136 This is used as the context variable for many of the TS, SNES, and KSP monitor functions 137 138 .seealso: `PetscViewerSocketOpen()`, `PetscViewerASCIIOpen()`, `PetscViewerCreate()`, `PetscViewerDrawOpen()`, `PetscViewerAndFormatDestroy()` 139 140 @*/ 141 PetscErrorCode PetscViewerAndFormatCreate(PetscViewer viewer, PetscViewerFormat format, PetscViewerAndFormat **vf) 142 { 143 PetscFunctionBegin; 144 PetscCall(PetscObjectReference((PetscObject)viewer)); 145 PetscCall(PetscNew(vf)); 146 (*vf)->viewer = viewer; 147 (*vf)->format = format; 148 (*vf)->lg = NULL; 149 (*vf)->data = NULL; 150 PetscFunctionReturn(0); 151 } 152 153 /*@C 154 PetscViewerAndFormatDestroy - Destroys a PetscViewerAndFormat struct. 155 156 Collective on PetscViewer 157 158 Input Parameters: 159 . vf - the PetscViewerAndFormat to be destroyed. 160 161 Level: developer 162 163 .seealso: `PetscViewerSocketOpen()`, `PetscViewerASCIIOpen()`, `PetscViewerCreate()`, `PetscViewerDrawOpen()`, `PetscViewerAndFormatCreate()` 164 @*/ 165 PetscErrorCode PetscViewerAndFormatDestroy(PetscViewerAndFormat **vf) 166 { 167 PetscFunctionBegin; 168 PetscCall(PetscViewerDestroy(&(*vf)->viewer)); 169 PetscCall(PetscDrawLGDestroy(&(*vf)->lg)); 170 PetscCall(PetscFree(*vf)); 171 PetscFunctionReturn(0); 172 } 173 174 /*@C 175 PetscViewerGetType - Returns the type of a PetscViewer. 176 177 Not Collective 178 179 Input Parameter: 180 . viewer - the PetscViewer 181 182 Output Parameter: 183 . type - PetscViewer type (see below) 184 185 Available Types Include: 186 + PETSCVIEWERSOCKET - Socket PetscViewer 187 . PETSCVIEWERASCII - ASCII PetscViewer 188 . PETSCVIEWERBINARY - binary file PetscViewer 189 . PETSCVIEWERSTRING - string PetscViewer 190 - PETSCVIEWERDRAW - drawing PetscViewer 191 192 Level: intermediate 193 194 Note: 195 See include/petscviewer.h for a complete list of PetscViewers. 196 197 PetscViewerType is actually a string 198 199 .seealso: `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerType` 200 201 @*/ 202 PetscErrorCode PetscViewerGetType(PetscViewer viewer,PetscViewerType *type) 203 { 204 PetscFunctionBegin; 205 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); 206 PetscValidPointer(type,2); 207 *type = ((PetscObject)viewer)->type_name; 208 PetscFunctionReturn(0); 209 } 210 211 /*@C 212 PetscViewerSetOptionsPrefix - Sets the prefix used for searching for all 213 PetscViewer options in the database. 214 215 Logically Collective on PetscViewer 216 217 Input Parameters: 218 + viewer - the PetscViewer context 219 - prefix - the prefix to prepend to all option names 220 221 Notes: 222 A hyphen (-) must NOT be given at the beginning of the prefix name. 223 The first character of all runtime options is AUTOMATICALLY the hyphen. 224 225 Level: advanced 226 227 .seealso: `PetscViewerSetFromOptions()` 228 @*/ 229 PetscErrorCode PetscViewerSetOptionsPrefix(PetscViewer viewer,const char prefix[]) 230 { 231 PetscFunctionBegin; 232 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); 233 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)viewer,prefix)); 234 PetscFunctionReturn(0); 235 } 236 237 /*@C 238 PetscViewerAppendOptionsPrefix - Appends to the prefix used for searching for all 239 PetscViewer options in the database. 240 241 Logically Collective on PetscViewer 242 243 Input Parameters: 244 + viewer - the PetscViewer context 245 - prefix - the prefix to prepend to all option names 246 247 Notes: 248 A hyphen (-) must NOT be given at the beginning of the prefix name. 249 The first character of all runtime options is AUTOMATICALLY the hyphen. 250 251 Level: advanced 252 253 .seealso: `PetscViewerGetOptionsPrefix()` 254 @*/ 255 PetscErrorCode PetscViewerAppendOptionsPrefix(PetscViewer viewer,const char prefix[]) 256 { 257 PetscFunctionBegin; 258 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); 259 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)viewer,prefix)); 260 PetscFunctionReturn(0); 261 } 262 263 /*@C 264 PetscViewerGetOptionsPrefix - Sets the prefix used for searching for all 265 PetscViewer options in the database. 266 267 Not Collective 268 269 Input Parameter: 270 . viewer - the PetscViewer context 271 272 Output Parameter: 273 . prefix - pointer to the prefix string used 274 275 Notes: 276 On the fortran side, the user should pass in a string 'prefix' of 277 sufficient length to hold the prefix. 278 279 Level: advanced 280 281 .seealso: `PetscViewerAppendOptionsPrefix()` 282 @*/ 283 PetscErrorCode PetscViewerGetOptionsPrefix(PetscViewer viewer,const char *prefix[]) 284 { 285 PetscFunctionBegin; 286 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); 287 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)viewer,prefix)); 288 PetscFunctionReturn(0); 289 } 290 291 /*@ 292 PetscViewerSetUp - Sets up the internal viewer data structures for the later use. 293 294 Collective on PetscViewer 295 296 Input Parameters: 297 . viewer - the PetscViewer context 298 299 Notes: 300 For basic use of the PetscViewer classes the user need not explicitly call 301 PetscViewerSetUp(), since these actions will happen automatically. 302 303 Level: advanced 304 305 .seealso: `PetscViewerCreate()`, `PetscViewerDestroy()` 306 @*/ 307 PetscErrorCode PetscViewerSetUp(PetscViewer viewer) 308 { 309 PetscFunctionBegin; 310 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); 311 if (viewer->setupcalled) PetscFunctionReturn(0); 312 PetscTryTypeMethod(viewer,setup); 313 viewer->setupcalled = PETSC_TRUE; 314 PetscFunctionReturn(0); 315 } 316 317 /*@C 318 PetscViewerViewFromOptions - View from Options 319 320 Collective on PetscViewer 321 322 Input Parameters: 323 + A - the PetscViewer context 324 . obj - Optional object 325 - name - command line option 326 327 Level: intermediate 328 .seealso: `PetscViewer`, `PetscViewerView`, `PetscObjectViewFromOptions()`, `PetscViewerCreate()` 329 @*/ 330 PetscErrorCode PetscViewerViewFromOptions(PetscViewer A,PetscObject obj,const char name[]) 331 { 332 PetscFunctionBegin; 333 PetscValidHeaderSpecific(A,PETSC_VIEWER_CLASSID,1); 334 PetscCall(PetscObjectViewFromOptions((PetscObject)A,obj,name)); 335 PetscFunctionReturn(0); 336 } 337 338 /*@C 339 PetscViewerView - Visualizes a viewer object. 340 341 Collective on PetscViewer 342 343 Input Parameters: 344 + v - the viewer to be viewed 345 - viewer - visualization context 346 347 Notes: 348 The available visualization contexts include 349 + PETSC_VIEWER_STDOUT_SELF - standard output (default) 350 . PETSC_VIEWER_STDOUT_WORLD - synchronized standard 351 output where only the first processor opens 352 the file. All other processors send their 353 data to the first processor to print. 354 - PETSC_VIEWER_DRAW_WORLD - graphical display of nonzero structure 355 356 Level: beginner 357 358 .seealso: `PetscViewerPushFormat()`, `PetscViewerASCIIOpen()`, `PetscViewerDrawOpen()`, 359 `PetscViewerSocketOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerLoad()` 360 @*/ 361 PetscErrorCode PetscViewerView(PetscViewer v,PetscViewer viewer) 362 { 363 PetscBool iascii; 364 PetscViewerFormat format; 365 #if defined(PETSC_HAVE_SAWS) 366 PetscBool issaws; 367 #endif 368 369 PetscFunctionBegin; 370 PetscValidHeaderSpecific(v,PETSC_VIEWER_CLASSID,1); 371 PetscValidType(v,1); 372 if (!viewer) { 373 PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)v),&viewer)); 374 } 375 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 376 PetscCheckSameComm(v,1,viewer,2); 377 378 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii)); 379 #if defined(PETSC_HAVE_SAWS) 380 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERSAWS,&issaws)); 381 #endif 382 if (iascii) { 383 PetscCall(PetscViewerGetFormat(viewer,&format)); 384 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)v,viewer)); 385 if (format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 386 if (v->format) { 387 PetscCall(PetscViewerASCIIPrintf(viewer," Viewer format = %s\n",PetscViewerFormats[v->format])); 388 } 389 PetscCall(PetscViewerASCIIPushTab(viewer)); 390 PetscTryTypeMethod(v,view,viewer); 391 PetscCall(PetscViewerASCIIPopTab(viewer)); 392 } 393 #if defined(PETSC_HAVE_SAWS) 394 } else if (issaws) { 395 if (!((PetscObject)v)->amsmem) { 396 PetscCall(PetscObjectViewSAWs((PetscObject)v,viewer)); 397 PetscTryTypeMethod(v,view,viewer); 398 } 399 #endif 400 } 401 PetscFunctionReturn(0); 402 } 403 404 /*@C 405 PetscViewerRead - Reads data from a PetscViewer 406 407 Collective 408 409 Input Parameters: 410 + viewer - The viewer 411 . data - Location to write the data 412 . num - Number of items of data to read 413 - datatype - Type of data to read 414 415 Output Parameters: 416 . count - number of items of data actually read, or NULL 417 418 Notes: 419 If datatype is PETSC_STRING and num is negative, reads until a newline character is found, 420 until a maximum of (-num - 1) chars. 421 422 Level: beginner 423 424 .seealso: `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, 425 `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`, 426 `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer` 427 @*/ 428 PetscErrorCode PetscViewerRead(PetscViewer viewer, void *data, PetscInt num, PetscInt *count, PetscDataType dtype) 429 { 430 PetscFunctionBegin; 431 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); 432 if (dtype == PETSC_STRING) { 433 PetscInt c, i = 0, cnt; 434 char *s = (char *)data; 435 if (num >= 0) { 436 for (c = 0; c < num; c++) { 437 /* Skip leading whitespaces */ 438 do {PetscCall((*viewer->ops->read)(viewer, &(s[i]), 1, &cnt, PETSC_CHAR)); if (!cnt) break;} 439 while (s[i]=='\n' || s[i]=='\t' || s[i]==' ' || s[i]=='\0' || s[i]=='\v' || s[i]=='\f' || s[i]=='\r'); 440 i++; 441 /* Read strings one char at a time */ 442 do {PetscCall((*viewer->ops->read)(viewer, &(s[i++]), 1, &cnt, PETSC_CHAR)); if (!cnt) break;} 443 while (s[i-1]!='\n' && s[i-1]!='\t' && s[i-1]!=' ' && s[i-1]!='\0' && s[i-1]!='\v' && s[i-1]!='\f' && s[i-1]!='\r'); 444 /* Terminate final string */ 445 if (c == num-1) s[i-1] = '\0'; 446 } 447 } else { 448 /* Read until a \n is encountered (-num is the max size allowed) */ 449 do {PetscCall((*viewer->ops->read)(viewer, &(s[i++]), 1, &cnt, PETSC_CHAR)); if (i == -num || !cnt) break;} 450 while (s[i-1]!='\n'); 451 /* Terminate final string */ 452 s[i-1] = '\0'; 453 c = i; 454 } 455 if (count) *count = c; 456 else PetscCheck(c >= num,PetscObjectComm((PetscObject) viewer), PETSC_ERR_FILE_READ, "Insufficient data, only read %" PetscInt_FMT " < %" PetscInt_FMT " strings", c, num); 457 } else PetscUseTypeMethod(viewer,read , data, num, count, dtype); 458 PetscFunctionReturn(0); 459 } 460 461 /*@ 462 PetscViewerReadable - Return a flag whether the viewer can be read from 463 464 Not Collective 465 466 Input Parameters: 467 . viewer - the PetscViewer context 468 469 Output Parameters: 470 . flg - PETSC_TRUE if the viewer is readable, PETSC_FALSE otherwise 471 472 Notes: 473 PETSC_TRUE means that viewer's PetscViewerType supports reading (this holds e.g. for PETSCVIEWERBINARY) 474 and viewer is in a mode allowing reading, i.e. PetscViewerFileGetMode() 475 returns one of FILE_MODE_READ, FILE_MODE_UPDATE, FILE_MODE_APPEND_UPDATE. 476 477 Level: intermediate 478 479 .seealso: `PetscViewerWritable()`, `PetscViewerCheckReadable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()` 480 @*/ 481 PetscErrorCode PetscViewerReadable(PetscViewer viewer, PetscBool *flg) 482 { 483 PetscFileMode mode; 484 PetscErrorCode (*f)(PetscViewer,PetscFileMode*) = NULL; 485 486 PetscFunctionBegin; 487 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); 488 PetscValidBoolPointer(flg,2); 489 PetscCall(PetscObjectQueryFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", &f)); 490 *flg = PETSC_FALSE; 491 if (!f) PetscFunctionReturn(0); 492 PetscCall((*f)(viewer, &mode)); 493 switch (mode) { 494 case FILE_MODE_READ: 495 case FILE_MODE_UPDATE: 496 case FILE_MODE_APPEND_UPDATE: 497 *flg = PETSC_TRUE; 498 default: break; 499 } 500 PetscFunctionReturn(0); 501 } 502 503 /*@ 504 PetscViewerWritable - Return a flag whether the viewer can be written to 505 506 Not Collective 507 508 Input Parameters: 509 . viewer - the PetscViewer context 510 511 Output Parameters: 512 . flg - PETSC_TRUE if the viewer is writable, PETSC_FALSE otherwise 513 514 Notes: 515 PETSC_TRUE means viewer is in a mode allowing writing, i.e. PetscViewerFileGetMode() 516 returns one of FILE_MODE_WRITE, FILE_MODE_APPEND, FILE_MODE_UPDATE, FILE_MODE_APPEND_UPDATE. 517 518 Level: intermediate 519 520 .seealso: `PetscViewerReadable()`, `PetscViewerCheckWritable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()` 521 @*/ 522 PetscErrorCode PetscViewerWritable(PetscViewer viewer, PetscBool *flg) 523 { 524 PetscFileMode mode; 525 PetscErrorCode (*f)(PetscViewer,PetscFileMode*) = NULL; 526 527 PetscFunctionBegin; 528 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); 529 PetscValidBoolPointer(flg,2); 530 PetscCall(PetscObjectQueryFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", &f)); 531 *flg = PETSC_TRUE; 532 if (!f) PetscFunctionReturn(0); 533 PetscCall((*f)(viewer, &mode)); 534 if (mode == FILE_MODE_READ) *flg = PETSC_FALSE; 535 PetscFunctionReturn(0); 536 } 537 538 /*@ 539 PetscViewerCheckReadable - Check whether the viewer can be read from 540 541 Collective 542 543 Input Parameters: 544 . viewer - the PetscViewer context 545 546 Level: intermediate 547 548 .seealso: `PetscViewerReadable()`, `PetscViewerCheckWritable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()` 549 @*/ 550 PetscErrorCode PetscViewerCheckReadable(PetscViewer viewer) 551 { 552 PetscBool flg; 553 554 PetscFunctionBegin; 555 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); 556 PetscCall(PetscViewerReadable(viewer, &flg)); 557 PetscCheck(flg,PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Viewer doesn't support reading, or is not in reading mode (FILE_MODE_READ, FILE_MODE_UPDATE, FILE_MODE_APPEND_UPDATE)"); 558 PetscFunctionReturn(0); 559 } 560 561 /*@ 562 PetscViewerCheckWritable - Check whether the viewer can be written to 563 564 Collective 565 566 Input Parameters: 567 . viewer - the PetscViewer context 568 569 Level: intermediate 570 571 .seealso: `PetscViewerWritable()`, `PetscViewerCheckReadable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()` 572 @*/ 573 PetscErrorCode PetscViewerCheckWritable(PetscViewer viewer) 574 { 575 PetscBool flg; 576 577 PetscFunctionBegin; 578 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); 579 PetscCall(PetscViewerWritable(viewer, &flg)); 580 PetscCheck(flg,PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Viewer doesn't support writing, or is in FILE_MODE_READ mode"); 581 PetscFunctionReturn(0); 582 } 583