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