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