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