xref: /petsc/src/sys/fileio/mprint.c (revision 1d2e40055fe3bf783df36eeeccf2d7d5fcfab0fd)
1 #define PETSC_DLL
2 /*
3       Utilites routines to add simple ASCII IO capability.
4 */
5 #include "src/sys/fileio/mprint.h"
6 #include "petscconfiginfo.h"
7 /*
8    If petsc_history is on, then all Petsc*Printf() results are saved
9    if the appropriate (usually .petschistory) file.
10 */
11 extern FILE *petsc_history;
12 /*
13      Allows one to overwrite where standard out is sent. For example
14      PETSC_STDOUT = fopen("/dev/ttyXX","w") will cause all standard out
15      writes to go to terminal XX; assuming you have write permission there
16 */
17 FILE *PETSC_STDOUT = 0;
18 
19 #undef __FUNCT__
20 #define __FUNCT__ "PetscFormatConvert"
21 PetscErrorCode PETSC_DLLEXPORT PetscFormatConvert(const char *format,char *newformat,PetscInt size)
22 {
23   PetscInt i = 0,j = 0;
24 
25   while (format[i] && i < size-1) {
26     if (format[i] == '%' && format[i+1] == 'D') {
27       newformat[j++] = '%';
28 #if defined(PETSC_USE_32BIT_INT)
29       newformat[j++] = 'd';
30 #else
31       newformat[j++] = 'l';
32       newformat[j++] = 'l';
33       newformat[j++] = 'd';
34 #endif
35       i += 2;
36     } else if (format[i] == '%' && format[i+1] >= '1' && format[i+1] <= '9' && format[i+2] == 'D') {
37       newformat[j++] = '%';
38       newformat[j++] = format[i+1];
39 #if defined(PETSC_USE_32BIT_INT)
40       newformat[j++] = 'd';
41 #else
42       newformat[j++] = 'l';
43       newformat[j++] = 'l';
44       newformat[j++] = 'd';
45 #endif
46       i += 3;
47     } else if (format[i] == '%' && format[i+1] == 'G') {
48       newformat[j++] = '%';
49 #if defined(PETSC_USE_INT)
50       newformat[j++] = 'd';
51 #elif !defined(PETSC_USE_LONG_DOUBLE)
52       newformat[j++] = 'g';
53 #else
54       newformat[j++] = 'L';
55       newformat[j++] = 'g';
56 #endif
57       i += 2;
58     }else {
59       newformat[j++] = format[i++];
60     }
61   }
62   newformat[j] = 0;
63   return 0;
64 }
65 
66 #undef __FUNCT__
67 #define __FUNCT__ "PetscVSNPrintf"
68 /*
69    No error handling because may be called by error handler
70 */
71 PetscErrorCode PETSC_DLLEXPORT PetscVSNPrintf(char *str,size_t len,const char *format,va_list Argp)
72 {
73   /* no malloc since may be called by error handler */
74   char           newformat[8*1024];
75   size_t         length;
76   PetscErrorCode ierr;
77 
78   PetscFormatConvert(format,newformat,8*1024);
79   ierr = PetscStrlen(newformat, &length);CHKERRQ(ierr);
80   if (length > len) {
81     newformat[len] = '\0';
82   }
83 #if defined(PETSC_HAVE_VPRINTF_CHAR)
84   vsprintf(str,newformat,(char *)Argp);
85 #else
86   vsprintf(str,newformat,Argp);
87 #endif
88   return 0;
89 }
90 
91 #undef __FUNCT__
92 #define __FUNCT__ "PetscVFPrintf"
93 /*
94    All PETSc standard out and error messages are sent through this function; so, in theory, this can
95    can be replaced with something that does not simply write to a file.
96 
97    Note: For error messages this may be called by a process, for regular standard out it is
98    called only by process 0 of a given communicator
99 
100    No error handling because may be called by error handler
101 */
102 PetscErrorCode PETSC_DLLEXPORT PetscVFPrintf(FILE *fd,const char *format,va_list Argp)
103 {
104   /* no malloc since may be called by error handler */
105   char     newformat[8*1024];
106 
107   PetscFormatConvert(format,newformat,8*1024);
108 #if defined(PETSC_HAVE_VPRINTF_CHAR)
109   vfprintf(fd,newformat,(char *)Argp);
110 #else
111   vfprintf(fd,newformat,Argp);
112   fflush(fd);
113 #endif
114   return 0;
115 }
116 
117 /* ----------------------------------------------------------------------- */
118 
119 PrintfQueue queue       = 0,queuebase = 0;
120 int         queuelength = 0;
121 FILE        *queuefile  = PETSC_NULL;
122 
123 #undef __FUNCT__
124 #define __FUNCT__ "PetscSynchronizedPrintf"
125 /*@C
126     PetscSynchronizedPrintf - Prints synchronized output from several processors.
127     Output of the first processor is followed by that of the second, etc.
128 
129     Not Collective
130 
131     Input Parameters:
132 +   comm - the communicator
133 -   format - the usual printf() format string
134 
135    Level: intermediate
136 
137     Notes:
138     REQUIRES a intervening call to PetscSynchronizedFlush() for the information
139     from all the processors to be printed.
140 
141     Fortran Note:
142     The call sequence is PetscSynchronizedPrintf(PetscViewer, character(*), PetscErrorCode ierr) from Fortran.
143     That is, you can only pass a single character string from Fortran.
144 
145     The length of the formatted message cannot exceed QUEUESTRINGSIZE characters.
146 
147 .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(),
148           PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf()
149 @*/
150 PetscErrorCode PETSC_DLLEXPORT PetscSynchronizedPrintf(MPI_Comm comm,const char format[],...)
151 {
152   PetscErrorCode ierr;
153   PetscMPIInt    rank;
154 
155   PetscFunctionBegin;
156   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
157 
158   /* First processor prints immediately to stdout */
159   if (!rank) {
160     va_list Argp;
161     va_start(Argp,format);
162     ierr = PetscVFPrintf(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
163     if (petsc_history) {
164       ierr = PetscVFPrintf(petsc_history,format,Argp);CHKERRQ(ierr);
165     }
166     va_end(Argp);
167   } else { /* other processors add to local queue */
168     va_list     Argp;
169     PrintfQueue next;
170 
171     ierr = PetscNew(struct _PrintfQueue,&next);CHKERRQ(ierr);
172     if (queue) {queue->next = next; queue = next; queue->next = 0;}
173     else       {queuebase   = queue = next;}
174     queuelength++;
175     va_start(Argp,format);
176     ierr = PetscMemzero(next->string,QUEUESTRINGSIZE);CHKERRQ(ierr);
177     ierr = PetscVSNPrintf(next->string,QUEUESTRINGSIZE,format,Argp);CHKERRQ(ierr);
178     va_end(Argp);
179   }
180 
181   PetscFunctionReturn(0);
182 }
183 
184 #undef __FUNCT__
185 #define __FUNCT__ "PetscSynchronizedFPrintf"
186 /*@C
187     PetscSynchronizedFPrintf - Prints synchronized output to the specified file from
188     several processors.  Output of the first processor is followed by that of the
189     second, etc.
190 
191     Not Collective
192 
193     Input Parameters:
194 +   comm - the communicator
195 .   fd - the file pointer
196 -   format - the usual printf() format string
197 
198     Level: intermediate
199 
200     Notes:
201     REQUIRES a intervening call to PetscSynchronizedFlush() for the information
202     from all the processors to be printed.
203 
204     The length of the formatted message cannot exceed QUEUESTRINGSIZE characters.
205 
206     Contributed by: Matthew Knepley
207 
208 .seealso: PetscSynchronizedPrintf(), PetscSynchronizedFlush(), PetscFPrintf(),
209           PetscFOpen(), PetscViewerASCIISynchronizedPrintf(), PetscViewerASCIIPrintf()
210 
211 @*/
212 PetscErrorCode PETSC_DLLEXPORT PetscSynchronizedFPrintf(MPI_Comm comm,FILE* fp,const char format[],...)
213 {
214   PetscErrorCode ierr;
215   PetscMPIInt    rank;
216 
217   PetscFunctionBegin;
218   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
219 
220   /* First processor prints immediately to fp */
221   if (!rank) {
222     va_list Argp;
223     va_start(Argp,format);
224     ierr = PetscVFPrintf(fp,format,Argp);CHKERRQ(ierr);
225     queuefile = fp;
226     if (petsc_history) {
227       ierr = PetscVFPrintf(petsc_history,format,Argp);CHKERRQ(ierr);
228     }
229     va_end(Argp);
230   } else { /* other processors add to local queue */
231     va_list     Argp;
232     PrintfQueue next;
233     ierr = PetscNew(struct _PrintfQueue,&next);CHKERRQ(ierr);
234     if (queue) {queue->next = next; queue = next; queue->next = 0;}
235     else       {queuebase   = queue = next;}
236     queuelength++;
237     va_start(Argp,format);
238     ierr = PetscMemzero(next->string,QUEUESTRINGSIZE);CHKERRQ(ierr);
239     ierr = PetscVSNPrintf(next->string,QUEUESTRINGSIZE,format,Argp);CHKERRQ(ierr);
240     va_end(Argp);
241   }
242   PetscFunctionReturn(0);
243 }
244 
245 #undef __FUNCT__
246 #define __FUNCT__ "PetscSynchronizedFlush"
247 /*@
248     PetscSynchronizedFlush - Flushes to the screen output from all processors
249     involved in previous PetscSynchronizedPrintf() calls.
250 
251     Collective on MPI_Comm
252 
253     Input Parameters:
254 .   comm - the communicator
255 
256     Level: intermediate
257 
258     Notes:
259     Usage of PetscSynchronizedPrintf() and PetscSynchronizedFPrintf() with
260     different MPI communicators REQUIRES an intervening call to PetscSynchronizedFlush().
261 
262 .seealso: PetscSynchronizedPrintf(), PetscFPrintf(), PetscPrintf(), PetscViewerASCIIPrintf(),
263           PetscViewerASCIISynchronizedPrintf()
264 @*/
265 PetscErrorCode PETSC_DLLEXPORT PetscSynchronizedFlush(MPI_Comm comm)
266 {
267   PetscErrorCode ierr;
268   PetscMPIInt    rank,size,tag,i,j,n;
269   char           message[QUEUESTRINGSIZE];
270   MPI_Status     status;
271   FILE           *fd;
272 
273   PetscFunctionBegin;
274   ierr = PetscCommDuplicate(comm,&comm,&tag);CHKERRQ(ierr);
275   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
276   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
277 
278   /* First processor waits for messages from all other processors */
279   if (!rank) {
280     if (queuefile) {
281       fd = queuefile;
282     } else {
283       fd = PETSC_STDOUT;
284     }
285     for (i=1; i<size; i++) {
286       ierr = MPI_Recv(&n,1,MPI_INT,i,tag,comm,&status);CHKERRQ(ierr);
287       for (j=0; j<n; j++) {
288         ierr = MPI_Recv(message,QUEUESTRINGSIZE,MPI_CHAR,i,tag,comm,&status);CHKERRQ(ierr);
289         ierr = PetscFPrintf(comm,fd,"%s",message);
290       }
291     }
292     queuefile = PETSC_NULL;
293   } else { /* other processors send queue to processor 0 */
294     PrintfQueue next = queuebase,previous;
295 
296     ierr = MPI_Send(&queuelength,1,MPI_INT,0,tag,comm);CHKERRQ(ierr);
297     for (i=0; i<queuelength; i++) {
298       ierr     = MPI_Send(next->string,QUEUESTRINGSIZE,MPI_CHAR,0,tag,comm);CHKERRQ(ierr);
299       previous = next;
300       next     = next->next;
301       ierr     = PetscFree(previous);CHKERRQ(ierr);
302     }
303     queue       = 0;
304     queuelength = 0;
305   }
306   ierr = PetscCommDestroy(&comm);CHKERRQ(ierr);
307   PetscFunctionReturn(0);
308 }
309 
310 /* ---------------------------------------------------------------------------------------*/
311 
312 #undef __FUNCT__
313 #define __FUNCT__ "PetscFPrintf"
314 /*@C
315     PetscFPrintf - Prints to a file, only from the first
316     processor in the communicator.
317 
318     Not Collective
319 
320     Input Parameters:
321 +   comm - the communicator
322 .   fd - the file pointer
323 -   format - the usual printf() format string
324 
325     Level: intermediate
326 
327     Fortran Note:
328     This routine is not supported in Fortran.
329 
330    Concepts: printing^in parallel
331    Concepts: printf^in parallel
332 
333 .seealso: PetscPrintf(), PetscSynchronizedPrintf(), PetscViewerASCIIPrintf(),
334           PetscViewerASCIISynchronizedPrintf(), PetscSynchronizedFlush()
335 @*/
336 PetscErrorCode PETSC_DLLEXPORT PetscFPrintf(MPI_Comm comm,FILE* fd,const char format[],...)
337 {
338   PetscErrorCode ierr;
339   PetscMPIInt    rank;
340 
341   PetscFunctionBegin;
342   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
343   if (!rank) {
344     va_list Argp;
345     va_start(Argp,format);
346     ierr = PetscVFPrintf(fd,format,Argp);CHKERRQ(ierr);
347     if (petsc_history) {
348       ierr = PetscVFPrintf(petsc_history,format,Argp);CHKERRQ(ierr);
349     }
350     va_end(Argp);
351   }
352   PetscFunctionReturn(0);
353 }
354 
355 #undef __FUNCT__
356 #define __FUNCT__ "PetscPrintf"
357 /*@C
358     PetscPrintf - Prints to standard out, only from the first
359     processor in the communicator.
360 
361     Not Collective
362 
363     Input Parameters:
364 +   comm - the communicator
365 -   format - the usual printf() format string
366 
367    Level: intermediate
368 
369     Fortran Note:
370     The call sequence is PetscPrintf(PetscViewer, character(*), PetscErrorCode ierr) from Fortran.
371     That is, you can only pass a single character string from Fortran.
372 
373    Notes: %A is replace with %g unless the value is < 1.e-12 when it is
374           replaced with < 1.e-12
375 
376    Concepts: printing^in parallel
377    Concepts: printf^in parallel
378 
379 .seealso: PetscFPrintf(), PetscSynchronizedPrintf()
380 @*/
381 PetscErrorCode PETSC_DLLEXPORT PetscPrintf(MPI_Comm comm,const char format[],...)
382 {
383   PetscErrorCode ierr;
384   PetscMPIInt    rank;
385   size_t         len;
386   char           *nformat,*sub1,*sub2;
387   PetscReal      value;
388 
389   PetscFunctionBegin;
390   if (!comm) comm = PETSC_COMM_WORLD;
391   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
392   if (!rank) {
393     va_list Argp;
394     va_start(Argp,format);
395 
396     ierr = PetscStrstr(format,"%A",&sub1);CHKERRQ(ierr);
397     if (sub1) {
398       ierr = PetscStrstr(format,"%",&sub2);CHKERRQ(ierr);
399       if (sub1 != sub2) SETERRQ(PETSC_ERR_ARG_WRONG,"%%A format must be first in format string");
400       ierr    = PetscStrlen(format,&len);CHKERRQ(ierr);
401       ierr    = PetscMalloc((len+16)*sizeof(char),&nformat);CHKERRQ(ierr);
402       ierr    = PetscStrcpy(nformat,format);CHKERRQ(ierr);
403       ierr    = PetscStrstr(nformat,"%",&sub2);CHKERRQ(ierr);
404       sub2[0] = 0;
405       value   = (double)va_arg(Argp,double);
406       if (PetscAbsReal(value) < 1.e-12) {
407         ierr    = PetscStrcat(nformat,"< 1.e-12");CHKERRQ(ierr);
408       } else {
409         ierr    = PetscStrcat(nformat,"%g");CHKERRQ(ierr);
410         va_end(Argp);
411         va_start(Argp,format);
412       }
413       ierr    = PetscStrcat(nformat,sub1+2);CHKERRQ(ierr);
414     } else {
415       nformat = (char*)format;
416     }
417     ierr = PetscVFPrintf(PETSC_STDOUT,nformat,Argp);CHKERRQ(ierr);
418     if (petsc_history) {
419       ierr = PetscVFPrintf(petsc_history,nformat,Argp);CHKERRQ(ierr);
420     }
421     va_end(Argp);
422     if (sub1) {ierr = PetscFree(nformat);CHKERRQ(ierr);}
423   }
424   PetscFunctionReturn(0);
425 }
426 
427 /* ---------------------------------------------------------------------------------------*/
428 #undef __FUNCT__
429 #define __FUNCT__ "PetscHelpPrintfDefault"
430 PetscErrorCode PETSC_DLLEXPORT PetscHelpPrintfDefault(MPI_Comm comm,const char format[],...)
431 {
432   PetscErrorCode ierr;
433   PetscMPIInt    rank;
434 
435   PetscFunctionBegin;
436   if (!comm) comm = PETSC_COMM_WORLD;
437   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
438   if (!rank) {
439     va_list Argp;
440     va_start(Argp,format);
441     ierr = PetscVFPrintf(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
442     if (petsc_history) {
443       ierr = PetscVFPrintf(petsc_history,format,Argp);CHKERRQ(ierr);
444     }
445     va_end(Argp);
446   }
447   PetscFunctionReturn(0);
448 }
449 
450 /* ---------------------------------------------------------------------------------------*/
451 
452 static char  arch[10],hostname[64],username[16],pname[PETSC_MAX_PATH_LEN],date[64];
453 static PetscTruth PetscErrorPrintfInitializeCalled = PETSC_FALSE;
454 
455 #undef __FUNCT__
456 #define __FUNCT__ "PetscErrorPrintfInitialize"
457 /*
458    Initializes arch, hostname, username,date so that system calls do NOT need
459    to be made during the error handler.
460 */
461 PetscErrorCode PETSC_DLLEXPORT PetscErrorPrintfInitialize()
462 {
463   PetscErrorCode ierr;
464 
465   PetscFunctionBegin;
466   ierr = PetscGetArchType(arch,10);CHKERRQ(ierr);
467   ierr = PetscGetHostName(hostname,64);CHKERRQ(ierr);
468   ierr = PetscGetUserName(username,16);CHKERRQ(ierr);
469   ierr = PetscGetProgramName(pname,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
470   ierr = PetscGetDate(date,64);CHKERRQ(ierr);
471   PetscErrorPrintfInitializeCalled = PETSC_TRUE;
472   PetscFunctionReturn(0);
473 }
474 
475 
476 #undef __FUNCT__
477 #define __FUNCT__ "PetscErrorPrintfDefault"
478 PetscErrorCode PETSC_DLLEXPORT PetscErrorPrintfDefault(const char format[],...)
479 {
480   va_list            Argp;
481   static  PetscTruth PetscErrorPrintfCalled    = PETSC_FALSE;
482   static  PetscTruth InPetscErrorPrintfDefault = PETSC_FALSE;
483   static  FILE       *fd;
484   char               version[256];
485   PetscErrorCode     ierr;
486 
487   /*
488       InPetscErrorPrintfDefault is used to prevent the error handler called (potentially)
489      from PetscSleep(), PetscGetArchName(), ... below from printing its own error message.
490   */
491 
492   /*
493       This function does not call PetscFunctionBegin and PetscFunctionReturn() because
494     it may be called by PetscStackView().
495 
496       This function does not do error checking because it is called by the error handlers.
497   */
498 
499   if (!PetscErrorPrintfCalled) {
500     PetscTruth use_stderr;
501 
502     PetscErrorPrintfCalled    = PETSC_TRUE;
503     InPetscErrorPrintfDefault = PETSC_TRUE;
504 
505     PetscOptionsHasName(PETSC_NULL,"-error_output_stderr",&use_stderr);
506     if (use_stderr) {
507       fd = stderr;
508     } else {
509       fd = PETSC_STDOUT;
510     }
511 
512     /*
513         On the SGI machines and Cray T3E, if errors are generated  "simultaneously" by
514       different processors, the messages are printed all jumbled up; to try to
515       prevent this we have each processor wait based on their rank
516     */
517 #if defined(PETSC_CAN_SLEEP_AFTER_ERROR)
518     {
519       PetscMPIInt rank;
520       if (PetscGlobalRank > 8) rank = 8; else rank = PetscGlobalRank;
521       PetscSleep(rank);
522     }
523 #endif
524 
525     ierr = PetscGetVersion(&version);CHKERRQ(ierr);
526 
527     PetscFPrintf(PETSC_COMM_SELF,fd,"------------------------------------------------------------------------\n");
528     PetscFPrintf(PETSC_COMM_SELF,fd,"%s\n",version);
529     PetscFPrintf(PETSC_COMM_SELF,fd,"See docs/changes/index.html for recent updates.\n");
530     PetscFPrintf(PETSC_COMM_SELF,fd,"See docs/faq.html for hints about trouble shooting.\n");
531     PetscFPrintf(PETSC_COMM_SELF,fd,"See docs/index.html for manual pages.\n");
532     PetscFPrintf(PETSC_COMM_SELF,fd,"------------------------------------------------------------------------\n");
533     if (PetscErrorPrintfInitializeCalled) {
534       PetscFPrintf(PETSC_COMM_SELF,fd,"%s on a %s named %s by %s %s\n",pname,arch,hostname,username,date);
535     }
536     PetscFPrintf(PETSC_COMM_SELF,fd,"Libraries linked from %s\n",PETSC_LIB_DIR);
537     PetscFPrintf(PETSC_COMM_SELF,fd,"Configure run at %s\n",petscconfigureruntime);
538     PetscFPrintf(PETSC_COMM_SELF,fd,"Configure options %s\n",petscconfigureoptions);
539     PetscFPrintf(PETSC_COMM_SELF,fd,"------------------------------------------------------------------------\n");
540     InPetscErrorPrintfDefault = PETSC_FALSE;
541   }
542 
543   if (!InPetscErrorPrintfDefault) {
544     PetscFPrintf(PETSC_COMM_SELF,fd,"[%d]PETSC ERROR: ",PetscGlobalRank);
545     va_start(Argp,format);
546     PetscVFPrintf(fd,format,Argp);
547     va_end(Argp);
548   }
549   return 0;
550 }
551 
552 #undef __FUNCT__
553 #define __FUNCT__ "PetscSynchronizedFGets"
554 /*@C
555     PetscSynchronizedFGets - Several processors all get the same line from a file.
556 
557     Collective on MPI_Comm
558 
559     Input Parameters:
560 +   comm - the communicator
561 .   fd - the file pointer
562 -   len - the length of the output buffer
563 
564     Output Parameter:
565 .   string - the line read from the file
566 
567     Level: intermediate
568 
569 .seealso: PetscSynchronizedPrintf(), PetscSynchronizedFlush(),
570           PetscFOpen(), PetscViewerASCIISynchronizedPrintf(), PetscViewerASCIIPrintf()
571 
572 @*/
573 PetscErrorCode PETSC_DLLEXPORT PetscSynchronizedFGets(MPI_Comm comm,FILE* fp,size_t len,char string[])
574 {
575   PetscErrorCode ierr;
576   PetscMPIInt    rank;
577 
578   PetscFunctionBegin;
579   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
580 
581   if (!rank) {
582     fgets(string,len,fp);
583   }
584   ierr = MPI_Bcast(string,len,MPI_BYTE,0,comm);CHKERRQ(ierr);
585   PetscFunctionReturn(0);
586 }
587