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 if (viewer->ops->setup) { 313 PetscCall((*viewer->ops->setup)(viewer)); 314 } 315 viewer->setupcalled = PETSC_TRUE; 316 PetscFunctionReturn(0); 317 } 318 319 /*@C 320 PetscViewerViewFromOptions - View from Options 321 322 Collective on PetscViewer 323 324 Input Parameters: 325 + A - the PetscViewer context 326 . obj - Optional object 327 - name - command line option 328 329 Level: intermediate 330 .seealso: `PetscViewer`, `PetscViewerView`, `PetscObjectViewFromOptions()`, `PetscViewerCreate()` 331 @*/ 332 PetscErrorCode PetscViewerViewFromOptions(PetscViewer A,PetscObject obj,const char name[]) 333 { 334 PetscFunctionBegin; 335 PetscValidHeaderSpecific(A,PETSC_VIEWER_CLASSID,1); 336 PetscCall(PetscObjectViewFromOptions((PetscObject)A,obj,name)); 337 PetscFunctionReturn(0); 338 } 339 340 /*@C 341 PetscViewerView - Visualizes a viewer object. 342 343 Collective on PetscViewer 344 345 Input Parameters: 346 + v - the viewer to be viewed 347 - viewer - visualization context 348 349 Notes: 350 The available visualization contexts include 351 + PETSC_VIEWER_STDOUT_SELF - standard output (default) 352 . PETSC_VIEWER_STDOUT_WORLD - synchronized standard 353 output where only the first processor opens 354 the file. All other processors send their 355 data to the first processor to print. 356 - PETSC_VIEWER_DRAW_WORLD - graphical display of nonzero structure 357 358 Level: beginner 359 360 .seealso: `PetscViewerPushFormat()`, `PetscViewerASCIIOpen()`, `PetscViewerDrawOpen()`, 361 `PetscViewerSocketOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerLoad()` 362 @*/ 363 PetscErrorCode PetscViewerView(PetscViewer v,PetscViewer viewer) 364 { 365 PetscBool iascii; 366 PetscViewerFormat format; 367 #if defined(PETSC_HAVE_SAWS) 368 PetscBool issaws; 369 #endif 370 371 PetscFunctionBegin; 372 PetscValidHeaderSpecific(v,PETSC_VIEWER_CLASSID,1); 373 PetscValidType(v,1); 374 if (!viewer) { 375 PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)v),&viewer)); 376 } 377 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 378 PetscCheckSameComm(v,1,viewer,2); 379 380 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii)); 381 #if defined(PETSC_HAVE_SAWS) 382 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERSAWS,&issaws)); 383 #endif 384 if (iascii) { 385 PetscCall(PetscViewerGetFormat(viewer,&format)); 386 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)v,viewer)); 387 if (format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 388 if (v->format) { 389 PetscCall(PetscViewerASCIIPrintf(viewer," Viewer format = %s\n",PetscViewerFormats[v->format])); 390 } 391 PetscCall(PetscViewerASCIIPushTab(viewer)); 392 if (v->ops->view) { 393 PetscCall((*v->ops->view)(v,viewer)); 394 } 395 PetscCall(PetscViewerASCIIPopTab(viewer)); 396 } 397 #if defined(PETSC_HAVE_SAWS) 398 } else if (issaws) { 399 if (!((PetscObject)v)->amsmem) { 400 PetscCall(PetscObjectViewSAWs((PetscObject)v,viewer)); 401 if (v->ops->view) { 402 PetscCall((*v->ops->view)(v,viewer)); 403 } 404 } 405 #endif 406 } 407 PetscFunctionReturn(0); 408 } 409 410 /*@C 411 PetscViewerRead - Reads data from a PetscViewer 412 413 Collective 414 415 Input Parameters: 416 + viewer - The viewer 417 . data - Location to write the data 418 . num - Number of items of data to read 419 - datatype - Type of data to read 420 421 Output Parameters: 422 . count - number of items of data actually read, or NULL 423 424 Notes: 425 If datatype is PETSC_STRING and num is negative, reads until a newline character is found, 426 until a maximum of (-num - 1) chars. 427 428 Level: beginner 429 430 .seealso: `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, 431 `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`, 432 `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer` 433 @*/ 434 PetscErrorCode PetscViewerRead(PetscViewer viewer, void *data, PetscInt num, PetscInt *count, PetscDataType dtype) 435 { 436 PetscFunctionBegin; 437 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); 438 if (dtype == PETSC_STRING) { 439 PetscInt c, i = 0, cnt; 440 char *s = (char *)data; 441 if (num >= 0) { 442 for (c = 0; c < num; c++) { 443 /* Skip leading whitespaces */ 444 do {PetscCall((*viewer->ops->read)(viewer, &(s[i]), 1, &cnt, PETSC_CHAR)); if (!cnt) break;} 445 while (s[i]=='\n' || s[i]=='\t' || s[i]==' ' || s[i]=='\0' || s[i]=='\v' || s[i]=='\f' || s[i]=='\r'); 446 i++; 447 /* Read strings one char at a time */ 448 do {PetscCall((*viewer->ops->read)(viewer, &(s[i++]), 1, &cnt, PETSC_CHAR)); if (!cnt) break;} 449 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'); 450 /* Terminate final string */ 451 if (c == num-1) s[i-1] = '\0'; 452 } 453 } else { 454 /* Read until a \n is encountered (-num is the max size allowed) */ 455 do {PetscCall((*viewer->ops->read)(viewer, &(s[i++]), 1, &cnt, PETSC_CHAR)); if (i == -num || !cnt) break;} 456 while (s[i-1]!='\n'); 457 /* Terminate final string */ 458 s[i-1] = '\0'; 459 c = i; 460 } 461 if (count) *count = c; 462 else PetscCheck(c >= num,PetscObjectComm((PetscObject) viewer), PETSC_ERR_FILE_READ, "Insufficient data, only read %" PetscInt_FMT " < %" PetscInt_FMT " strings", c, num); 463 } else { 464 PetscCall((*viewer->ops->read)(viewer, data, num, count, dtype)); 465 } 466 PetscFunctionReturn(0); 467 } 468 469 /*@ 470 PetscViewerReadable - Return a flag whether the viewer can be read from 471 472 Not Collective 473 474 Input Parameters: 475 . viewer - the PetscViewer context 476 477 Output Parameters: 478 . flg - PETSC_TRUE if the viewer is readable, PETSC_FALSE otherwise 479 480 Notes: 481 PETSC_TRUE means that viewer's PetscViewerType supports reading (this holds e.g. for PETSCVIEWERBINARY) 482 and viewer is in a mode allowing reading, i.e. PetscViewerFileGetMode() 483 returns one of FILE_MODE_READ, FILE_MODE_UPDATE, FILE_MODE_APPEND_UPDATE. 484 485 Level: intermediate 486 487 .seealso: `PetscViewerWritable()`, `PetscViewerCheckReadable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()` 488 @*/ 489 PetscErrorCode PetscViewerReadable(PetscViewer viewer, PetscBool *flg) 490 { 491 PetscFileMode mode; 492 PetscErrorCode (*f)(PetscViewer,PetscFileMode*) = NULL; 493 494 PetscFunctionBegin; 495 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); 496 PetscValidBoolPointer(flg,2); 497 PetscCall(PetscObjectQueryFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", &f)); 498 *flg = PETSC_FALSE; 499 if (!f) PetscFunctionReturn(0); 500 PetscCall((*f)(viewer, &mode)); 501 switch (mode) { 502 case FILE_MODE_READ: 503 case FILE_MODE_UPDATE: 504 case FILE_MODE_APPEND_UPDATE: 505 *flg = PETSC_TRUE; 506 default: break; 507 } 508 PetscFunctionReturn(0); 509 } 510 511 /*@ 512 PetscViewerWritable - Return a flag whether the viewer can be written to 513 514 Not Collective 515 516 Input Parameters: 517 . viewer - the PetscViewer context 518 519 Output Parameters: 520 . flg - PETSC_TRUE if the viewer is writable, PETSC_FALSE otherwise 521 522 Notes: 523 PETSC_TRUE means viewer is in a mode allowing writing, i.e. PetscViewerFileGetMode() 524 returns one of FILE_MODE_WRITE, FILE_MODE_APPEND, FILE_MODE_UPDATE, FILE_MODE_APPEND_UPDATE. 525 526 Level: intermediate 527 528 .seealso: `PetscViewerReadable()`, `PetscViewerCheckWritable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()` 529 @*/ 530 PetscErrorCode PetscViewerWritable(PetscViewer viewer, PetscBool *flg) 531 { 532 PetscFileMode mode; 533 PetscErrorCode (*f)(PetscViewer,PetscFileMode*) = NULL; 534 535 PetscFunctionBegin; 536 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); 537 PetscValidBoolPointer(flg,2); 538 PetscCall(PetscObjectQueryFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", &f)); 539 *flg = PETSC_TRUE; 540 if (!f) PetscFunctionReturn(0); 541 PetscCall((*f)(viewer, &mode)); 542 if (mode == FILE_MODE_READ) *flg = PETSC_FALSE; 543 PetscFunctionReturn(0); 544 } 545 546 /*@ 547 PetscViewerCheckReadable - Check whether the viewer can be read from 548 549 Collective 550 551 Input Parameters: 552 . viewer - the PetscViewer context 553 554 Level: intermediate 555 556 .seealso: `PetscViewerReadable()`, `PetscViewerCheckWritable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()` 557 @*/ 558 PetscErrorCode PetscViewerCheckReadable(PetscViewer viewer) 559 { 560 PetscBool flg; 561 562 PetscFunctionBegin; 563 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); 564 PetscCall(PetscViewerReadable(viewer, &flg)); 565 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)"); 566 PetscFunctionReturn(0); 567 } 568 569 /*@ 570 PetscViewerCheckWritable - Check whether the viewer can be written to 571 572 Collective 573 574 Input Parameters: 575 . viewer - the PetscViewer context 576 577 Level: intermediate 578 579 .seealso: `PetscViewerWritable()`, `PetscViewerCheckReadable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()` 580 @*/ 581 PetscErrorCode PetscViewerCheckWritable(PetscViewer viewer) 582 { 583 PetscBool flg; 584 585 PetscFunctionBegin; 586 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); 587 PetscCall(PetscViewerWritable(viewer, &flg)); 588 PetscCheck(flg,PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Viewer doesn't support writing, or is in FILE_MODE_READ mode"); 589 PetscFunctionReturn(0); 590 } 591