1 /* 2 Utilites routines to add simple ASCII IO capability. 3 */ 4 #include <../src/sys/fileio/mprint.h> 5 #include <errno.h> 6 /* 7 If petsc_history is on, then all Petsc*Printf() results are saved 8 if the appropriate (usually .petschistory) file. 9 */ 10 PETSC_INTERN FILE *petsc_history; 11 /* 12 Allows one to overwrite where standard out is sent. For example 13 PETSC_STDOUT = fopen("/dev/ttyXX","w") will cause all standard out 14 writes to go to terminal XX; assuming you have write permission there 15 */ 16 FILE *PETSC_STDOUT = NULL; 17 /* 18 Allows one to overwrite where standard error is sent. For example 19 PETSC_STDERR = fopen("/dev/ttyXX","w") will cause all standard error 20 writes to go to terminal XX; assuming you have write permission there 21 */ 22 FILE *PETSC_STDERR = NULL; 23 24 /*@C 25 PetscFormatConvertGetSize - Gets the length of a string needed to hold format converted with `PetscFormatConvert()` 26 27 Deprecated 28 29 Input Parameter: 30 . format - the PETSc format string 31 32 Output Parameter: 33 . size - the needed length of the new format 34 35 Level: developer 36 37 .seealso: `PetscFormatConvert()`, `PetscVSNPrintf()`, `PetscVFPrintf()` 38 @*/ 39 PetscErrorCode PetscFormatConvertGetSize(const char *format, size_t *size) 40 { 41 size_t sz = 0; 42 PetscInt i = 0; 43 44 PetscFunctionBegin; 45 PetscValidCharPointer(format, 1); 46 PetscValidPointer(size, 2); 47 while (format[i]) { 48 if (format[i] == '%') { 49 if (format[i + 1] == '%') { 50 i += 2; 51 sz += 2; 52 continue; 53 } 54 /* Find the letter */ 55 while (format[i] && (format[i] <= '9')) { 56 ++i; 57 ++sz; 58 } 59 switch (format[i]) { 60 #if PetscDefined(USE_64BIT_INDICES) 61 case 'D': 62 sz += 2; 63 break; 64 #endif 65 case 'g': 66 sz += 4; 67 default: 68 break; 69 } 70 } 71 ++i; 72 ++sz; 73 } 74 *size = sz + 1; /* space for NULL character */ 75 PetscFunctionReturn(0); 76 } 77 78 /*@C 79 PetscFormatConvert - Takes a PETSc format string and converts the %D to %d for 32 bit PETSc indices and %lld for 64 bit PETSc indices. Also 80 converts %g to [|%g|] so that PetscVSNPrintf() can easily insure all %g formatted numbers have a decimal point when printed. 81 82 Deprecated 83 84 Input Parameters: 85 + format - the PETSc format string 86 . newformat - the location to put the new format 87 - size - the length of newformat, you can use `PetscFormatConvertGetSize()` to compute the needed size 88 89 Note: this exists so we can have the same code when `PetscInt` is either int or long long int 90 91 Level: developer 92 93 .seealso: `PetscFormatConvertGetSize()`, `PetscVSNPrintf()`, `PetscVFPrintf()` 94 @*/ 95 PetscErrorCode PetscFormatConvert(const char *format, char *newformat) 96 { 97 PetscInt i = 0, j = 0; 98 99 PetscFunctionBegin; 100 while (format[i]) { 101 if (format[i] == '%' && format[i + 1] == '%') { 102 newformat[j++] = format[i++]; 103 newformat[j++] = format[i++]; 104 } else if (format[i] == '%') { 105 if (format[i + 1] == 'g') { 106 newformat[j++] = '['; 107 newformat[j++] = '|'; 108 } 109 /* Find the letter */ 110 for (; format[i] && format[i] <= '9'; i++) newformat[j++] = format[i]; 111 switch (format[i]) { 112 case 'D': 113 #if !defined(PETSC_USE_64BIT_INDICES) 114 newformat[j++] = 'd'; 115 #else 116 newformat[j++] = 'l'; 117 newformat[j++] = 'l'; 118 newformat[j++] = 'd'; 119 #endif 120 break; 121 case 'g': 122 newformat[j++] = format[i]; 123 if (format[i - 1] == '%') { 124 newformat[j++] = '|'; 125 newformat[j++] = ']'; 126 } 127 break; 128 case 'G': 129 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "%%G format is no longer supported, use %%g and cast the argument to double"); 130 case 'F': 131 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "%%F format is no longer supported, use %%f and cast the argument to double"); 132 default: 133 newformat[j++] = format[i]; 134 break; 135 } 136 i++; 137 } else newformat[j++] = format[i++]; 138 } 139 newformat[j] = 0; 140 PetscFunctionReturn(0); 141 } 142 143 #define PETSCDEFAULTBUFFERSIZE 8 * 1024 144 145 /*@C 146 PetscVSNPrintf - The PETSc version of vsnprintf(). Converts a PETSc format string into a standard C format string and then puts all the 147 function arguments into a string using the format statement. 148 149 Input Parameters: 150 + str - location to put result 151 . len - the amount of space in str 152 + format - the PETSc format string 153 - fullLength - the amount of space in str actually used. 154 155 Developer Note: 156 this function may be called from an error handler, if an error occurs when it is called by the error handler than likely 157 a recursion will occur and possible crash. 158 159 Level: developer 160 161 .seealso: `PetscVSNPrintf()`, `PetscErrorPrintf()`, `PetscVPrintf()` 162 @*/ 163 PetscErrorCode PetscVSNPrintf(char *str, size_t len, const char *format, size_t *fullLength, va_list Argp) 164 { 165 char *newformat = NULL; 166 char formatbuf[PETSCDEFAULTBUFFERSIZE]; 167 size_t newLength; 168 int flen; 169 170 PetscFunctionBegin; 171 PetscCall(PetscFormatConvertGetSize(format, &newLength)); 172 if (newLength < sizeof(formatbuf)) { 173 newformat = formatbuf; 174 newLength = sizeof(formatbuf) - 1; 175 } else { 176 PetscCall(PetscMalloc1(newLength, &newformat)); 177 } 178 PetscCall(PetscFormatConvert(format, newformat)); 179 #if defined(PETSC_HAVE_VSNPRINTF) 180 flen = vsnprintf(str, len, newformat, Argp); 181 #else 182 #error "vsnprintf not found" 183 #endif 184 if (newLength > sizeof(formatbuf) - 1) PetscCall(PetscFree(newformat)); 185 { 186 PetscBool foundedot; 187 size_t cnt = 0, ncnt = 0, leng; 188 PetscCall(PetscStrlen(str, &leng)); 189 if (leng > 4) { 190 for (cnt = 0; cnt < leng - 4; cnt++) { 191 if (str[cnt] == '[' && str[cnt + 1] == '|') { 192 flen -= 4; 193 cnt++; 194 cnt++; 195 foundedot = PETSC_FALSE; 196 for (; cnt < leng - 1; cnt++) { 197 if (str[cnt] == '|' && str[cnt + 1] == ']') { 198 cnt++; 199 if (!foundedot) str[ncnt++] = '.'; 200 ncnt--; 201 break; 202 } else { 203 if (str[cnt] == 'e' || str[cnt] == '.') foundedot = PETSC_TRUE; 204 str[ncnt++] = str[cnt]; 205 } 206 } 207 } else { 208 str[ncnt] = str[cnt]; 209 } 210 ncnt++; 211 } 212 while (cnt < leng) { 213 str[ncnt] = str[cnt]; 214 ncnt++; 215 cnt++; 216 } 217 str[ncnt] = 0; 218 } 219 } 220 #if defined(PETSC_HAVE_WINDOWS_H) && !defined(PETSC_HAVE__SET_OUTPUT_FORMAT) 221 /* older Windows OS always produces e-+0np for floating point output; remove the extra 0 */ 222 { 223 size_t cnt = 0, ncnt = 0, leng; 224 PetscCall(PetscStrlen(str, &leng)); 225 if (leng > 5) { 226 for (cnt = 0; cnt < leng - 4; cnt++) { 227 if (str[cnt] == 'e' && (str[cnt + 1] == '-' || str[cnt + 1] == '+') && str[cnt + 2] == '0' && str[cnt + 3] >= '0' && str[cnt + 3] <= '9' && str[cnt + 4] >= '0' && str[cnt + 4] <= '9') { 228 str[ncnt] = str[cnt]; 229 ncnt++; 230 cnt++; 231 str[ncnt] = str[cnt]; 232 ncnt++; 233 cnt++; 234 cnt++; 235 str[ncnt] = str[cnt]; 236 } else { 237 str[ncnt] = str[cnt]; 238 } 239 ncnt++; 240 } 241 while (cnt < leng) { 242 str[ncnt] = str[cnt]; 243 ncnt++; 244 cnt++; 245 } 246 str[ncnt] = 0; 247 } 248 } 249 #endif 250 if (fullLength) *fullLength = 1 + (size_t)flen; 251 PetscFunctionReturn(0); 252 } 253 254 /*@C 255 PetscVFPrintf - All PETSc standard out and error messages are sent through this function; so, in theory, this can 256 can be replaced with something that does not simply write to a file. 257 258 To use, write your own function for example, 259 $PetscErrorCode mypetscvfprintf(FILE *fd,const char format[],va_list Argp) 260 ${ 261 $ PetscErrorCode ierr; 262 $ 263 $ PetscFunctionBegin; 264 $ if (fd != stdout && fd != stderr) { handle regular files 265 $ CHKERR(PetscVFPrintfDefault(fd,format,Argp)); 266 $ } else { 267 $ char buff[BIG]; 268 $ size_t length; 269 $ PetscCall(PetscVSNPrintf(buff,BIG,format,&length,Argp)); 270 $ now send buff to whatever stream or whatever you want 271 $ } 272 $ PetscFunctionReturn(0); 273 $} 274 then before the call to PetscInitialize() do the assignment 275 $ PetscVFPrintf = mypetscvfprintf; 276 277 Note: 278 For error messages this may be called by any process, for regular standard out it is 279 called only by process 0 of a given communicator 280 281 Developer Note: 282 this could be called by an error handler, if that happens then a recursion of the error handler may occur 283 and a crash 284 285 Level: developer 286 287 .seealso: `PetscVSNPrintf()`, `PetscErrorPrintf()` 288 @*/ 289 PetscErrorCode PetscVFPrintfDefault(FILE *fd, const char *format, va_list Argp) 290 { 291 char str[PETSCDEFAULTBUFFERSIZE]; 292 char *buff = str; 293 size_t fullLength; 294 #if defined(PETSC_HAVE_VA_COPY) 295 va_list Argpcopy; 296 #endif 297 298 PetscFunctionBegin; 299 #if defined(PETSC_HAVE_VA_COPY) 300 va_copy(Argpcopy, Argp); 301 #endif 302 PetscCall(PetscVSNPrintf(str, sizeof(str), format, &fullLength, Argp)); 303 if (fullLength > sizeof(str)) { 304 PetscCall(PetscMalloc1(fullLength, &buff)); 305 #if defined(PETSC_HAVE_VA_COPY) 306 PetscCall(PetscVSNPrintf(buff, fullLength, format, NULL, Argpcopy)); 307 #else 308 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "C89 does not support va_copy() hence cannot print long strings with PETSc printing routines"); 309 #endif 310 } 311 fprintf(fd, "%s", buff); 312 fflush(fd); 313 if (buff != str) PetscCall(PetscFree(buff)); 314 PetscFunctionReturn(0); 315 } 316 317 /*@C 318 PetscSNPrintf - Prints to a string of given length 319 320 Not Collective 321 322 Input Parameters: 323 + str - the string to print to 324 . len - the length of str 325 . format - the usual printf() format string 326 - ... - any arguments that are to be printed, each much have an appropriate symbol in the format argument 327 328 Level: intermediate 329 330 .seealso: `PetscSynchronizedFlush()`, `PetscSynchronizedFPrintf()`, `PetscFPrintf()`, `PetscVSNPrintf()`, 331 `PetscPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscVFPrintf()` 332 @*/ 333 PetscErrorCode PetscSNPrintf(char *str, size_t len, const char format[], ...) 334 { 335 size_t fullLength; 336 va_list Argp; 337 338 PetscFunctionBegin; 339 va_start(Argp, format); 340 PetscCall(PetscVSNPrintf(str, len, format, &fullLength, Argp)); 341 PetscFunctionReturn(0); 342 } 343 344 /*@C 345 PetscSNPrintfCount - Prints to a string of given length, returns count 346 347 Not Collective 348 349 Input Parameters: 350 + str - the string to print to 351 . len - the length of str 352 . format - the usual printf() format string 353 - ... - any arguments that are to be printed, each much have an appropriate symbol in the format argument 354 355 Output Parameter: 356 . countused - number of characters used 357 358 Level: intermediate 359 360 .seealso: `PetscSynchronizedFlush()`, `PetscSynchronizedFPrintf()`, `PetscFPrintf()`, `PetscVSNPrintf()`, 361 `PetscPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscSNPrintf()`, `PetscVFPrintf()` 362 @*/ 363 PetscErrorCode PetscSNPrintfCount(char *str, size_t len, const char format[], size_t *countused, ...) 364 { 365 va_list Argp; 366 367 PetscFunctionBegin; 368 va_start(Argp, countused); 369 PetscCall(PetscVSNPrintf(str, len, format, countused, Argp)); 370 PetscFunctionReturn(0); 371 } 372 373 /* ----------------------------------------------------------------------- */ 374 375 PrintfQueue petsc_printfqueue = NULL, petsc_printfqueuebase = NULL; 376 int petsc_printfqueuelength = 0; 377 378 /*@C 379 PetscSynchronizedPrintf - Prints synchronized output from several processors. 380 Output of the first processor is followed by that of the second, etc. 381 382 Not Collective 383 384 Input Parameters: 385 + comm - the communicator 386 - format - the usual printf() format string 387 388 Level: intermediate 389 390 Note: 391 REQUIRES a call to `PetscSynchronizedFlush()` by all the processes after the completion of the calls to `PetscSynchronizedPrintf()` for the information 392 from all the processors to be printed. 393 394 Fortran Note: 395 The call sequence is `PetscSynchronizedPrintf`(MPI_Comm, character(*), PetscErrorCode ierr) from Fortran. 396 That is, you can only pass a single character string from Fortran. 397 398 .seealso: `PetscSynchronizedFlush()`, `PetscSynchronizedFPrintf()`, `PetscFPrintf()`, 399 `PetscPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()` 400 @*/ 401 PetscErrorCode PetscSynchronizedPrintf(MPI_Comm comm, const char format[], ...) 402 { 403 PetscMPIInt rank; 404 405 PetscFunctionBegin; 406 PetscCheck(comm != MPI_COMM_NULL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Called with MPI_COMM_NULL, likely PetscObjectComm() failed"); 407 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 408 409 /* First processor prints immediately to stdout */ 410 if (rank == 0) { 411 va_list Argp; 412 va_start(Argp, format); 413 PetscCall((*PetscVFPrintf)(PETSC_STDOUT, format, Argp)); 414 if (petsc_history) { 415 va_start(Argp, format); 416 PetscCall((*PetscVFPrintf)(petsc_history, format, Argp)); 417 } 418 va_end(Argp); 419 } else { /* other processors add to local queue */ 420 va_list Argp; 421 PrintfQueue next; 422 size_t fullLength = PETSCDEFAULTBUFFERSIZE; 423 424 PetscCall(PetscNew(&next)); 425 if (petsc_printfqueue) { 426 petsc_printfqueue->next = next; 427 petsc_printfqueue = next; 428 petsc_printfqueue->next = NULL; 429 } else petsc_printfqueuebase = petsc_printfqueue = next; 430 petsc_printfqueuelength++; 431 next->size = 0; 432 next->string = NULL; 433 while (fullLength >= next->size) { 434 next->size = fullLength + 1; 435 PetscCall(PetscFree(next->string)); 436 PetscCall(PetscMalloc1(next->size, &next->string)); 437 va_start(Argp, format); 438 PetscCall(PetscArrayzero(next->string, next->size)); 439 PetscCall(PetscVSNPrintf(next->string, next->size, format, &fullLength, Argp)); 440 va_end(Argp); 441 } 442 } 443 PetscFunctionReturn(0); 444 } 445 446 /*@C 447 PetscSynchronizedFPrintf - Prints synchronized output to the specified file from 448 several processors. Output of the first processor is followed by that of the 449 second, etc. 450 451 Not Collective 452 453 Input Parameters: 454 + comm - the communicator 455 . fd - the file pointer 456 - format - the usual printf() format string 457 458 Level: intermediate 459 460 Note: 461 REQUIRES a intervening call to `PetscSynchronizedFlush()` for the information 462 from all the processors to be printed. 463 464 .seealso: `PetscSynchronizedPrintf()`, `PetscSynchronizedFlush()`, `PetscFPrintf()`, 465 `PetscFOpen()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIPrintf()` 466 @*/ 467 PetscErrorCode PetscSynchronizedFPrintf(MPI_Comm comm, FILE *fp, const char format[], ...) 468 { 469 PetscMPIInt rank; 470 471 PetscFunctionBegin; 472 PetscCheck(comm != MPI_COMM_NULL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Called with MPI_COMM_NULL, likely PetscObjectComm() failed"); 473 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 474 475 /* First processor prints immediately to fp */ 476 if (rank == 0) { 477 va_list Argp; 478 va_start(Argp, format); 479 PetscCall((*PetscVFPrintf)(fp, format, Argp)); 480 if (petsc_history && (fp != petsc_history)) { 481 va_start(Argp, format); 482 PetscCall((*PetscVFPrintf)(petsc_history, format, Argp)); 483 } 484 va_end(Argp); 485 } else { /* other processors add to local queue */ 486 va_list Argp; 487 PrintfQueue next; 488 size_t fullLength = PETSCDEFAULTBUFFERSIZE; 489 490 PetscCall(PetscNew(&next)); 491 if (petsc_printfqueue) { 492 petsc_printfqueue->next = next; 493 petsc_printfqueue = next; 494 petsc_printfqueue->next = NULL; 495 } else petsc_printfqueuebase = petsc_printfqueue = next; 496 petsc_printfqueuelength++; 497 next->size = 0; 498 next->string = NULL; 499 while (fullLength >= next->size) { 500 next->size = fullLength + 1; 501 PetscCall(PetscFree(next->string)); 502 PetscCall(PetscMalloc1(next->size, &next->string)); 503 va_start(Argp, format); 504 PetscCall(PetscArrayzero(next->string, next->size)); 505 PetscCall(PetscVSNPrintf(next->string, next->size, format, &fullLength, Argp)); 506 va_end(Argp); 507 } 508 } 509 PetscFunctionReturn(0); 510 } 511 512 /*@C 513 PetscSynchronizedFlush - Flushes to the screen output from all processors 514 involved in previous `PetscSynchronizedPrintf()`/`PetscSynchronizedFPrintf()` calls. 515 516 Collective 517 518 Input Parameters: 519 + comm - the communicator 520 - fd - the file pointer (valid on process 0 of the communicator) 521 522 Level: intermediate 523 524 Note: 525 If `PetscSynchronizedPrintf()` and/or `PetscSynchronizedFPrintf()` are called with 526 different MPI communicators there must be an intervening call to `PetscSynchronizedFlush()` between the calls with different MPI communicators. 527 528 Fortran Note: 529 Pass `PETSC_STDOUT` if the flush is for standard out; otherwise pass a value obtained from `PetscFOpen()` 530 531 .seealso: `PetscSynchronizedPrintf()`, `PetscFPrintf()`, `PetscPrintf()`, `PetscViewerASCIIPrintf()`, 532 `PetscViewerASCIISynchronizedPrintf()` 533 @*/ 534 PetscErrorCode PetscSynchronizedFlush(MPI_Comm comm, FILE *fd) 535 { 536 PetscMPIInt rank, size, tag, i, j, n = 0, dummy = 0; 537 char *message; 538 MPI_Status status; 539 540 PetscFunctionBegin; 541 PetscCall(PetscCommDuplicate(comm, &comm, &tag)); 542 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 543 PetscCallMPI(MPI_Comm_size(comm, &size)); 544 545 /* First processor waits for messages from all other processors */ 546 if (rank == 0) { 547 if (!fd) fd = PETSC_STDOUT; 548 for (i = 1; i < size; i++) { 549 /* to prevent a flood of messages to process zero, request each message separately */ 550 PetscCallMPI(MPI_Send(&dummy, 1, MPI_INT, i, tag, comm)); 551 PetscCallMPI(MPI_Recv(&n, 1, MPI_INT, i, tag, comm, &status)); 552 for (j = 0; j < n; j++) { 553 PetscMPIInt size = 0; 554 555 PetscCallMPI(MPI_Recv(&size, 1, MPI_INT, i, tag, comm, &status)); 556 PetscCall(PetscMalloc1(size, &message)); 557 PetscCallMPI(MPI_Recv(message, size, MPI_CHAR, i, tag, comm, &status)); 558 PetscCall(PetscFPrintf(comm, fd, "%s", message)); 559 PetscCall(PetscFree(message)); 560 } 561 } 562 } else { /* other processors send queue to processor 0 */ 563 PrintfQueue next = petsc_printfqueuebase, previous; 564 565 PetscCallMPI(MPI_Recv(&dummy, 1, MPI_INT, 0, tag, comm, &status)); 566 PetscCallMPI(MPI_Send(&petsc_printfqueuelength, 1, MPI_INT, 0, tag, comm)); 567 for (i = 0; i < petsc_printfqueuelength; i++) { 568 PetscCallMPI(MPI_Send(&next->size, 1, MPI_INT, 0, tag, comm)); 569 PetscCallMPI(MPI_Send(next->string, next->size, MPI_CHAR, 0, tag, comm)); 570 previous = next; 571 next = next->next; 572 PetscCall(PetscFree(previous->string)); 573 PetscCall(PetscFree(previous)); 574 } 575 petsc_printfqueue = NULL; 576 petsc_printfqueuelength = 0; 577 } 578 PetscCall(PetscCommDestroy(&comm)); 579 PetscFunctionReturn(0); 580 } 581 582 /* ---------------------------------------------------------------------------------------*/ 583 584 /*@C 585 PetscFPrintf - Prints to a file, only from the first 586 processor in the communicator. 587 588 Not Collective 589 590 Input Parameters: 591 + comm - the communicator 592 . fd - the file pointer 593 - format - the usual printf() format string 594 595 Level: intermediate 596 597 Fortran Note: 598 This routine is not supported in Fortran. 599 600 .seealso: `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, 601 `PetscViewerASCIISynchronizedPrintf()`, `PetscSynchronizedFlush()` 602 @*/ 603 PetscErrorCode PetscFPrintf(MPI_Comm comm, FILE *fd, const char format[], ...) 604 { 605 PetscMPIInt rank; 606 607 PetscFunctionBegin; 608 PetscCheck(comm != MPI_COMM_NULL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Called with MPI_COMM_NULL, likely PetscObjectComm() failed"); 609 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 610 if (rank == 0) { 611 va_list Argp; 612 va_start(Argp, format); 613 PetscCall((*PetscVFPrintf)(fd, format, Argp)); 614 if (petsc_history && (fd != petsc_history)) { 615 va_start(Argp, format); 616 PetscCall((*PetscVFPrintf)(petsc_history, format, Argp)); 617 } 618 va_end(Argp); 619 } 620 PetscFunctionReturn(0); 621 } 622 623 /*@C 624 PetscPrintf - Prints to standard out, only from the first 625 processor in the communicator. Calls from other processes are ignored. 626 627 Not Collective 628 629 Input Parameters: 630 + comm - the communicator 631 - format - the usual printf() format string 632 633 Level: intermediate 634 635 Note: 636 Deprecated information: `PetscPrintf()` supports some format specifiers that are unique to PETSc. 637 See the manual page for `PetscFormatConvert()` for details. 638 639 Fortran Note: 640 The call sequence is `PetscPrintf`(MPI_Comm, character(*), `PetscErrorCode` ierr) from Fortran. 641 That is, you can only pass a single character string from Fortran. 642 643 .seealso: `PetscFPrintf()`, `PetscSynchronizedPrintf()`, `PetscFormatConvert()` 644 @*/ 645 PetscErrorCode PetscPrintf(MPI_Comm comm, const char format[], ...) 646 { 647 PetscMPIInt rank; 648 649 PetscFunctionBegin; 650 PetscCheck(comm != MPI_COMM_NULL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Called with MPI_COMM_NULL, likely PetscObjectComm() failed"); 651 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 652 if (rank == 0) { 653 va_list Argp; 654 va_start(Argp, format); 655 PetscCall((*PetscVFPrintf)(PETSC_STDOUT, format, Argp)); 656 if (petsc_history) { 657 va_start(Argp, format); 658 PetscCall((*PetscVFPrintf)(petsc_history, format, Argp)); 659 } 660 va_end(Argp); 661 } 662 PetscFunctionReturn(0); 663 } 664 665 PetscErrorCode PetscHelpPrintfDefault(MPI_Comm comm, const char format[], ...) 666 { 667 PetscMPIInt rank; 668 669 PetscFunctionBegin; 670 PetscCheck(comm != MPI_COMM_NULL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Called with MPI_COMM_NULL, likely PetscObjectComm() failed"); 671 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 672 if (rank == 0) { 673 va_list Argp; 674 va_start(Argp, format); 675 PetscCall((*PetscVFPrintf)(PETSC_STDOUT, format, Argp)); 676 if (petsc_history) { 677 va_start(Argp, format); 678 PetscCall((*PetscVFPrintf)(petsc_history, format, Argp)); 679 } 680 va_end(Argp); 681 } 682 PetscFunctionReturn(0); 683 } 684 685 /* ---------------------------------------------------------------------------------------*/ 686 687 /*@C 688 PetscSynchronizedFGets - Several processors all get the same line from a file. 689 690 Collective 691 692 Input Parameters: 693 + comm - the communicator 694 . fd - the file pointer 695 - len - the length of the output buffer 696 697 Output Parameter: 698 . string - the line read from the file, at end of file string[0] == 0 699 700 Level: intermediate 701 702 .seealso: `PetscSynchronizedPrintf()`, `PetscSynchronizedFlush()`, 703 `PetscFOpen()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIPrintf()` 704 @*/ 705 PetscErrorCode PetscSynchronizedFGets(MPI_Comm comm, FILE *fp, size_t len, char string[]) 706 { 707 PetscMPIInt rank; 708 709 PetscFunctionBegin; 710 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 711 712 if (rank == 0) { 713 char *ptr = fgets(string, len, fp); 714 715 if (!ptr) { 716 string[0] = 0; 717 PetscCheck(feof(fp), PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from file: %d", errno); 718 } 719 } 720 PetscCallMPI(MPI_Bcast(string, len, MPI_BYTE, 0, comm)); 721 PetscFunctionReturn(0); 722 } 723 724 /*@C 725 PetscFormatStrip - Takes a PETSc format string and removes all numerical modifiers to % operations 726 727 Input Parameters: 728 . format - the PETSc format string 729 730 Level: developer 731 732 @*/ 733 PetscErrorCode PetscFormatStrip(char *format) 734 { 735 size_t loc1 = 0, loc2 = 0; 736 737 PetscFunctionBegin; 738 while (format[loc2]) { 739 if (format[loc2] == '%') { 740 format[loc1++] = format[loc2++]; 741 while (format[loc2] && ((format[loc2] >= '0' && format[loc2] <= '9') || format[loc2] == '.')) loc2++; 742 } 743 format[loc1++] = format[loc2++]; 744 } 745 PetscFunctionReturn(0); 746 } 747 748 PetscErrorCode PetscFormatRealArray(char buf[], size_t len, const char *fmt, PetscInt n, const PetscReal x[]) 749 { 750 PetscInt i; 751 size_t left, count; 752 char *p; 753 754 PetscFunctionBegin; 755 for (i = 0, p = buf, left = len; i < n; i++) { 756 PetscCall(PetscSNPrintfCount(p, left, fmt, &count, (double)x[i])); 757 PetscCheck(count < left, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Insufficient space in buffer"); 758 left -= count; 759 p += count - 1; 760 *p++ = ' '; 761 } 762 p[i ? 0 : -1] = 0; 763 PetscFunctionReturn(0); 764 } 765