xref: /petsc/src/sys/classes/viewer/impls/binary/binv.c (revision 4fb89dddf56594b92bdd2ca7e24874fafe134f45)
1 #include <petsc/private/viewerimpl.h>    /*I   "petscviewer.h"   I*/
2 
3 typedef struct  {
4   int           fdes;                 /* file descriptor, ignored if using MPI IO */
5 #if defined(PETSC_HAVE_MPIIO)
6   PetscBool     usempiio;
7   MPI_File      mfdes;                /* ignored unless using MPI IO */
8   MPI_File      mfsub;                /* subviewer support */
9   MPI_Offset    moff;
10 #endif
11   char          *filename;            /* file name */
12   PetscFileMode filemode;             /* read/write/append mode */
13   FILE          *fdes_info;           /* optional file containing info on binary file*/
14   PetscBool     storecompressed;      /* gzip the write binary file when closing it*/
15   char          *ogzfilename;         /* gzip can be run after the filename has been updated */
16   PetscBool     skipinfo;             /* Don't create info file for writing; don't use for reading */
17   PetscBool     skipoptions;          /* don't use PETSc options database when loading */
18   PetscInt      flowcontrol;          /* allow only <flowcontrol> messages outstanding at a time while doing IO */
19   PetscBool     skipheader;           /* don't write header, only raw data */
20   PetscBool     matlabheaderwritten;  /* if format is PETSC_VIEWER_BINARY_MATLAB has the MATLAB .info header been written yet */
21   PetscBool     setfromoptionscalled;
22 } PetscViewer_Binary;
23 
24 static PetscErrorCode PetscViewerBinaryClearFunctionList(PetscViewer v)
25 {
26   PetscFunctionBegin;
27   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetFlowControl_C",NULL));
28   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetFlowControl_C",NULL));
29   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetSkipHeader_C",NULL));
30   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetSkipHeader_C",NULL));
31   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetSkipOptions_C",NULL));
32   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetSkipOptions_C",NULL));
33   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetSkipInfo_C",NULL));
34   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetSkipInfo_C",NULL));
35   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetInfoPointer_C",NULL));
36   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileGetName_C",NULL));
37   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileSetName_C",NULL));
38   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileGetMode_C",NULL));
39   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileSetMode_C",NULL));
40 #if defined(PETSC_HAVE_MPIIO)
41   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetUseMPIIO_C",NULL));
42   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetUseMPIIO_C",NULL));
43 #endif
44   PetscFunctionReturn(0);
45 }
46 
47 #if defined(PETSC_HAVE_MPIIO)
48 static PetscErrorCode PetscViewerBinarySyncMPIIO(PetscViewer viewer)
49 {
50   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
51 
52   PetscFunctionBegin;
53   if (vbinary->filemode == FILE_MODE_READ) PetscFunctionReturn(0);
54   if (vbinary->mfsub != MPI_FILE_NULL) {
55     PetscCallMPI(MPI_File_sync(vbinary->mfsub));
56   }
57   if (vbinary->mfdes != MPI_FILE_NULL) {
58     PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)viewer)));
59     PetscCallMPI(MPI_File_sync(vbinary->mfdes));
60   }
61   PetscFunctionReturn(0);
62 }
63 #endif
64 
65 static PetscErrorCode PetscViewerGetSubViewer_Binary(PetscViewer viewer,MPI_Comm comm,PetscViewer *outviewer)
66 {
67   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
68   PetscMPIInt        rank;
69 
70   PetscFunctionBegin;
71   PetscCall(PetscViewerSetUp(viewer));
72 
73   /* Return subviewer in process zero */
74   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer),&rank));
75   if (rank == 0) {
76     PetscMPIInt flg;
77 
78     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,comm,&flg));
79     PetscCheck(flg == MPI_IDENT || flg == MPI_CONGRUENT,PETSC_COMM_SELF,PETSC_ERR_SUP,"PetscViewerGetSubViewer() for PETSCVIEWERBINARY requires a singleton MPI_Comm");
80     PetscCall(PetscViewerCreate(comm,outviewer));
81     PetscCall(PetscViewerSetType(*outviewer,PETSCVIEWERBINARY));
82     PetscCall(PetscMemcpy((*outviewer)->data,vbinary,sizeof(PetscViewer_Binary)));
83     (*outviewer)->setupcalled = PETSC_TRUE;
84   } else {
85     *outviewer = NULL;
86   }
87 
88 #if defined(PETSC_HAVE_MPIIO)
89   if (vbinary->usempiio && *outviewer) {
90     PetscViewer_Binary *obinary = (PetscViewer_Binary*)(*outviewer)->data;
91     /* Parent viewer opens a new MPI file handle on PETSC_COMM_SELF and keeps track of it for future reuse */
92     if (vbinary->mfsub == MPI_FILE_NULL) {
93       int amode;
94       switch (vbinary->filemode) {
95       case FILE_MODE_READ:   amode = MPI_MODE_RDONLY; break;
96       case FILE_MODE_WRITE:  amode = MPI_MODE_WRONLY; break;
97       case FILE_MODE_APPEND: amode = MPI_MODE_WRONLY; break;
98       default: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported file mode %s",PetscFileModes[vbinary->filemode]);
99       }
100       PetscCallMPI(MPI_File_open(PETSC_COMM_SELF,vbinary->filename,amode,MPI_INFO_NULL,&vbinary->mfsub));
101     }
102     /* Subviewer gets the MPI file handle on PETSC_COMM_SELF */
103     obinary->mfdes = vbinary->mfsub;
104     obinary->mfsub = MPI_FILE_NULL;
105     obinary->moff  = vbinary->moff;
106   }
107 #endif
108 
109 #if defined(PETSC_HAVE_MPIIO)
110   PetscCall(PetscViewerBinarySyncMPIIO(viewer));
111 #endif
112   PetscFunctionReturn(0);
113 }
114 
115 static PetscErrorCode PetscViewerRestoreSubViewer_Binary(PetscViewer viewer,MPI_Comm comm,PetscViewer *outviewer)
116 {
117   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
118   PetscMPIInt        rank;
119 #if defined(PETSC_HAVE_MPIIO)
120   MPI_Offset         moff = 0;
121 #endif
122 
123   PetscFunctionBegin;
124   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer),&rank));
125   PetscCheck(rank == 0 || !*outviewer,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Subviewer not obtained from viewer");
126 
127 #if defined(PETSC_HAVE_MPIIO)
128   if (vbinary->usempiio && *outviewer) {
129     PetscViewer_Binary *obinary = (PetscViewer_Binary*)(*outviewer)->data;
130     PetscCheck(obinary->mfdes == vbinary->mfsub,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Subviewer not obtained from viewer");
131     if (obinary->mfsub != MPI_FILE_NULL) PetscCallMPI(MPI_File_close(&obinary->mfsub));
132     moff = obinary->moff;
133   }
134 #endif
135 
136   if (*outviewer) {
137     PetscViewer_Binary *obinary = (PetscViewer_Binary*)(*outviewer)->data;
138     PetscCheck(obinary->fdes == vbinary->fdes,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Subviewer not obtained from viewer");
139     PetscCall(PetscFree((*outviewer)->data));
140     PetscCall(PetscViewerBinaryClearFunctionList(*outviewer));
141     PetscCall(PetscHeaderDestroy(outviewer));
142   }
143 
144 #if defined(PETSC_HAVE_MPIIO)
145   if (vbinary->usempiio) {
146     PetscInt64 ioff = (PetscInt64)moff; /* We could use MPI_OFFSET datatype (requires MPI 2.2) */
147     PetscCallMPI(MPI_Bcast(&ioff,1,MPIU_INT64,0,PetscObjectComm((PetscObject)viewer)));
148     vbinary->moff = (MPI_Offset)ioff;
149   }
150 #endif
151 
152 #if defined(PETSC_HAVE_MPIIO)
153   PetscCall(PetscViewerBinarySyncMPIIO(viewer));
154 #endif
155   PetscFunctionReturn(0);
156 }
157 
158 #if defined(PETSC_HAVE_MPIIO)
159 /*@C
160     PetscViewerBinaryGetMPIIOOffset - Gets the current global offset that should be passed to `MPI_File_set_view()` or `MPI_File_{write|read}_at[_all]()`
161 
162     Not Collective
163 
164     Input Parameter:
165 .   viewer - PetscViewer context, obtained from `PetscViewerBinaryOpen()`
166 
167     Output Parameter:
168 .   off - the current global offset
169 
170     Level: advanced
171 
172     Fortran Note:
173     This routine is not supported in Fortran.
174 
175     Use `PetscViewerBinaryAddMPIIOOffset()` to increase this value after you have written a view.
176 
177 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinaryGetUseMPIIO()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryAddMPIIOOffset()`
178 @*/
179 PetscErrorCode PetscViewerBinaryGetMPIIOOffset(PetscViewer viewer,MPI_Offset *off)
180 {
181   PetscViewer_Binary *vbinary;
182 
183   PetscFunctionBegin;
184   PetscValidHeaderSpecificType(viewer,PETSC_VIEWER_CLASSID,1,PETSCVIEWERBINARY);
185   PetscValidPointer(off,2);
186   vbinary = (PetscViewer_Binary*)viewer->data;
187   *off = vbinary->moff;
188   PetscFunctionReturn(0);
189 }
190 
191 /*@C
192     PetscViewerBinaryAddMPIIOOffset - Adds to the current global offset
193 
194     Logically Collective
195 
196     Input Parameters:
197 +   viewer - PetscViewer context, obtained from PetscViewerBinaryOpen()
198 -   off - the addition to the global offset
199 
200     Level: advanced
201 
202     Fortran Note:
203     This routine is not supported in Fortran.
204 
205     Use `PetscViewerBinaryGetMPIIOOffset()` to get the value that you should pass to `MPI_File_set_view()` or `MPI_File_{write|read}_at[_all]()`
206 
207 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinaryGetUseMPIIO()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryGetMPIIOOffset()`
208 @*/
209 PetscErrorCode PetscViewerBinaryAddMPIIOOffset(PetscViewer viewer,MPI_Offset off)
210 {
211   PetscViewer_Binary *vbinary;
212 
213   PetscFunctionBegin;
214   PetscValidHeaderSpecificType(viewer,PETSC_VIEWER_CLASSID,1,PETSCVIEWERBINARY);
215   PetscValidLogicalCollectiveInt(viewer,(PetscInt)off,2);
216   vbinary = (PetscViewer_Binary*)viewer->data;
217   vbinary->moff += off;
218   PetscFunctionReturn(0);
219 }
220 
221 /*@C
222     PetscViewerBinaryGetMPIIODescriptor - Extracts the MPI IO file descriptor from a PetscViewer.
223 
224     Not Collective
225 
226     Input Parameter:
227 .   viewer - PetscViewer context, obtained from PetscViewerBinaryOpen()
228 
229     Output Parameter:
230 .   fdes - file descriptor
231 
232     Level: advanced
233 
234     Fortran Note:
235     This routine is not supported in Fortran.
236 
237 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinaryGetUseMPIIO()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryGetMPIIOOffset()`
238 @*/
239 PetscErrorCode PetscViewerBinaryGetMPIIODescriptor(PetscViewer viewer,MPI_File *fdes)
240 {
241   PetscViewer_Binary *vbinary;
242 
243   PetscFunctionBegin;
244   PetscValidHeaderSpecificType(viewer,PETSC_VIEWER_CLASSID,1,PETSCVIEWERBINARY);
245   PetscValidPointer(fdes,2);
246   PetscCall(PetscViewerSetUp(viewer));
247   vbinary = (PetscViewer_Binary*)viewer->data;
248   *fdes = vbinary->mfdes;
249   PetscFunctionReturn(0);
250 }
251 #endif
252 
253 /*@
254     PetscViewerBinarySetUseMPIIO - Sets a binary viewer to use MPI-IO for reading/writing. Must be called
255         before PetscViewerFileSetName()
256 
257     Logically Collective on PetscViewer
258 
259     Input Parameters:
260 +   viewer - the PetscViewer; must be a binary
261 -   use - PETSC_TRUE means MPI-IO will be used
262 
263     Options Database:
264     -viewer_binary_mpiio : Flag for using MPI-IO
265 
266     Level: advanced
267 
268 .seealso: `PetscViewerFileSetMode()`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerBinaryOpen()`,
269           `PetscViewerBinaryGetUseMPIIO()`
270 
271 @*/
272 PetscErrorCode PetscViewerBinarySetUseMPIIO(PetscViewer viewer,PetscBool use)
273 {
274   PetscFunctionBegin;
275   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
276   PetscValidLogicalCollectiveBool(viewer,use,2);
277   PetscTryMethod(viewer,"PetscViewerBinarySetUseMPIIO_C",(PetscViewer,PetscBool),(viewer,use));
278   PetscFunctionReturn(0);
279 }
280 
281 #if defined(PETSC_HAVE_MPIIO)
282 static PetscErrorCode PetscViewerBinarySetUseMPIIO_Binary(PetscViewer viewer,PetscBool use)
283 {
284   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
285   PetscFunctionBegin;
286   PetscCheck(!viewer->setupcalled || vbinary->usempiio == use,PetscObjectComm((PetscObject)viewer),PETSC_ERR_ORDER,"Cannot change MPIIO to %s after setup",PetscBools[use]);
287   vbinary->usempiio = use;
288   PetscFunctionReturn(0);
289 }
290 #endif
291 
292 /*@
293     PetscViewerBinaryGetUseMPIIO - Returns PETSC_TRUE if the binary viewer uses MPI-IO.
294 
295     Not Collective
296 
297     Input Parameter:
298 .   viewer - PetscViewer context, obtained from PetscViewerBinaryOpen()
299 
300     Output Parameter:
301 .   use - PETSC_TRUE if MPI-IO is being used
302 
303     Options Database:
304     -viewer_binary_mpiio : Flag for using MPI-IO
305 
306     Level: advanced
307 
308     Note:
309     If MPI-IO is not available, this function will always return PETSC_FALSE
310 
311     Fortran Note:
312     This routine is not supported in Fortran.
313 
314 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryGetMPIIOOffset()`
315 @*/
316 PetscErrorCode PetscViewerBinaryGetUseMPIIO(PetscViewer viewer,PetscBool *use)
317 {
318   PetscFunctionBegin;
319   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
320   PetscValidBoolPointer(use,2);
321   *use = PETSC_FALSE;
322   PetscTryMethod(viewer,"PetscViewerBinaryGetUseMPIIO_C",(PetscViewer,PetscBool*),(viewer,use));
323   PetscFunctionReturn(0);
324 }
325 
326 #if defined(PETSC_HAVE_MPIIO)
327 static PetscErrorCode PetscViewerBinaryGetUseMPIIO_Binary(PetscViewer viewer,PetscBool  *use)
328 {
329   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
330 
331   PetscFunctionBegin;
332   *use = vbinary->usempiio;
333   PetscFunctionReturn(0);
334 }
335 #endif
336 
337 /*@
338     PetscViewerBinarySetFlowControl - Sets how many messages are allowed to outstanding at the same time during parallel IO reads/writes
339 
340     Not Collective
341 
342     Input Parameters:
343 +   viewer - PetscViewer context, obtained from PetscViewerBinaryOpen()
344 -   fc - the number of messages, defaults to 256 if this function was not called
345 
346     Level: advanced
347 
348 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinaryGetFlowControl()`
349 
350 @*/
351 PetscErrorCode  PetscViewerBinarySetFlowControl(PetscViewer viewer,PetscInt fc)
352 {
353   PetscFunctionBegin;
354   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
355   PetscValidLogicalCollectiveInt(viewer,fc,2);
356   PetscTryMethod(viewer,"PetscViewerBinarySetFlowControl_C",(PetscViewer,PetscInt),(viewer,fc));
357   PetscFunctionReturn(0);
358 }
359 
360 static PetscErrorCode PetscViewerBinarySetFlowControl_Binary(PetscViewer viewer,PetscInt fc)
361 {
362   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
363 
364   PetscFunctionBegin;
365   PetscCheck(fc > 1,PetscObjectComm((PetscObject)viewer),PETSC_ERR_ARG_OUTOFRANGE,"Flow control count must be greater than 1, %" PetscInt_FMT " was set",fc);
366   vbinary->flowcontrol = fc;
367   PetscFunctionReturn(0);
368 }
369 
370 /*@
371     PetscViewerBinaryGetFlowControl - Returns how many messages are allowed to outstanding at the same time during parallel IO reads/writes
372 
373     Not Collective
374 
375     Input Parameter:
376 .   viewer - PetscViewer context, obtained from PetscViewerBinaryOpen()
377 
378     Output Parameter:
379 .   fc - the number of messages
380 
381     Level: advanced
382 
383 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinarySetFlowControl()`
384 
385 @*/
386 PetscErrorCode PetscViewerBinaryGetFlowControl(PetscViewer viewer,PetscInt *fc)
387 {
388   PetscFunctionBegin;
389   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
390   PetscValidIntPointer(fc,2);
391   PetscUseMethod(viewer,"PetscViewerBinaryGetFlowControl_C",(PetscViewer,PetscInt*),(viewer,fc));
392   PetscFunctionReturn(0);
393 }
394 
395 static PetscErrorCode  PetscViewerBinaryGetFlowControl_Binary(PetscViewer viewer,PetscInt *fc)
396 {
397   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
398 
399   PetscFunctionBegin;
400   *fc = vbinary->flowcontrol;
401   PetscFunctionReturn(0);
402 }
403 
404 /*@C
405     PetscViewerBinaryGetDescriptor - Extracts the file descriptor from a PetscViewer.
406 
407     Collective On PetscViewer
408 
409     Input Parameter:
410 .   viewer - PetscViewer context, obtained from PetscViewerBinaryOpen()
411 
412     Output Parameter:
413 .   fdes - file descriptor
414 
415     Level: advanced
416 
417     Notes:
418       For writable binary PetscViewers, the descriptor will only be valid for the
419     first processor in the communicator that shares the PetscViewer. For readable
420     files it will only be valid on nodes that have the file. If node 0 does not
421     have the file it generates an error even if another node does have the file.
422 
423     Fortran Note:
424     This routine is not supported in Fortran.
425 
426     Developer Notes:
427     This must be called on all processes because Dave May changed
428     the source code that this may be trigger a PetscViewerSetUp() call if it was not previously triggered.
429 
430 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`
431 @*/
432 PetscErrorCode PetscViewerBinaryGetDescriptor(PetscViewer viewer,int *fdes)
433 {
434   PetscViewer_Binary *vbinary;
435 
436   PetscFunctionBegin;
437   PetscValidHeaderSpecificType(viewer,PETSC_VIEWER_CLASSID,1,PETSCVIEWERBINARY);
438   PetscValidPointer(fdes,2);
439   PetscCall(PetscViewerSetUp(viewer));
440   vbinary = (PetscViewer_Binary*)viewer->data;
441   *fdes = vbinary->fdes;
442   PetscFunctionReturn(0);
443 }
444 
445 /*@
446     PetscViewerBinarySkipInfo - Binary file will not have .info file created with it
447 
448     Not Collective
449 
450     Input Parameter:
451 .   viewer - PetscViewer context, obtained from PetscViewerCreate()
452 
453     Options Database Key:
454 .   -viewer_binary_skip_info - true indicates do not generate .info file
455 
456     Level: advanced
457 
458     Notes:
459     This must be called after PetscViewerSetType(). If you use PetscViewerBinaryOpen() then
460     you can only skip the info file with the -viewer_binary_skip_info flag. To use the function you must open the
461     viewer with PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinarySkipInfo().
462 
463     The .info contains meta information about the data in the binary file, for example the block size if it was
464     set for a vector or matrix.
465 
466 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySetSkipOptions()`,
467           `PetscViewerBinaryGetSkipOptions()`, `PetscViewerBinaryGetSkipInfo()`
468 @*/
469 PetscErrorCode PetscViewerBinarySkipInfo(PetscViewer viewer)
470 {
471   PetscFunctionBegin;
472   PetscCall(PetscViewerBinarySetSkipInfo(viewer,PETSC_TRUE));
473   PetscFunctionReturn(0);
474 }
475 
476 /*@
477     PetscViewerBinarySetSkipInfo - Binary file will not have .info file created with it
478 
479     Not Collective
480 
481     Input Parameters:
482 +   viewer - PetscViewer context, obtained from PetscViewerCreate()
483 -   skip - PETSC_TRUE implies the .info file will not be generated
484 
485     Options Database Key:
486 .   -viewer_binary_skip_info - true indicates do not generate .info file
487 
488     Level: advanced
489 
490 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySetSkipOptions()`,
491           `PetscViewerBinaryGetSkipOptions()`, `PetscViewerBinaryGetSkipInfo()`
492 @*/
493 PetscErrorCode PetscViewerBinarySetSkipInfo(PetscViewer viewer,PetscBool skip)
494 {
495   PetscFunctionBegin;
496   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
497   PetscValidLogicalCollectiveBool(viewer,skip,2);
498   PetscTryMethod(viewer,"PetscViewerBinarySetSkipInfo_C",(PetscViewer,PetscBool),(viewer,skip));
499   PetscFunctionReturn(0);
500 }
501 
502 static PetscErrorCode PetscViewerBinarySetSkipInfo_Binary(PetscViewer viewer,PetscBool skip)
503 {
504   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
505 
506   PetscFunctionBegin;
507   vbinary->skipinfo = skip;
508   PetscFunctionReturn(0);
509 }
510 
511 /*@
512     PetscViewerBinaryGetSkipInfo - check if viewer wrote a .info file
513 
514     Not Collective
515 
516     Input Parameter:
517 .   viewer - PetscViewer context, obtained from PetscViewerBinaryOpen()
518 
519     Output Parameter:
520 .   skip - PETSC_TRUE implies the .info file was not generated
521 
522     Level: advanced
523 
524     Notes:
525     This must be called after PetscViewerSetType()
526 
527 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySkipInfo()`,
528           `PetscViewerBinarySetSkipOptions()`, `PetscViewerBinarySetSkipInfo()`
529 @*/
530 PetscErrorCode PetscViewerBinaryGetSkipInfo(PetscViewer viewer,PetscBool *skip)
531 {
532   PetscFunctionBegin;
533   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
534   PetscValidBoolPointer(skip,2);
535   PetscUseMethod(viewer,"PetscViewerBinaryGetSkipInfo_C",(PetscViewer,PetscBool*),(viewer,skip));
536   PetscFunctionReturn(0);
537 }
538 
539 static PetscErrorCode PetscViewerBinaryGetSkipInfo_Binary(PetscViewer viewer,PetscBool *skip)
540 {
541   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
542 
543   PetscFunctionBegin;
544   *skip  = vbinary->skipinfo;
545   PetscFunctionReturn(0);
546 }
547 
548 /*@
549     PetscViewerBinarySetSkipOptions - do not use the PETSc options database when loading objects
550 
551     Not Collective
552 
553     Input Parameters:
554 +   viewer - PetscViewer context, obtained from PetscViewerBinaryOpen()
555 -   skip - PETSC_TRUE means do not use the options from the options database
556 
557     Options Database Key:
558 .   -viewer_binary_skip_options - true means do not use the options from the options database
559 
560     Level: advanced
561 
562     Notes:
563     This must be called after PetscViewerSetType()
564 
565 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySkipInfo()`,
566           `PetscViewerBinaryGetSkipOptions()`
567 @*/
568 PetscErrorCode PetscViewerBinarySetSkipOptions(PetscViewer viewer,PetscBool skip)
569 {
570   PetscFunctionBegin;
571   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
572   PetscValidLogicalCollectiveBool(viewer,skip,2);
573   PetscTryMethod(viewer,"PetscViewerBinarySetSkipOptions_C",(PetscViewer,PetscBool),(viewer,skip));
574   PetscFunctionReturn(0);
575 }
576 
577 static PetscErrorCode PetscViewerBinarySetSkipOptions_Binary(PetscViewer viewer,PetscBool skip)
578 {
579   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
580 
581   PetscFunctionBegin;
582   vbinary->skipoptions = skip;
583   PetscFunctionReturn(0);
584 }
585 
586 /*@
587     PetscViewerBinaryGetSkipOptions - checks if viewer uses the PETSc options database when loading objects
588 
589     Not Collective
590 
591     Input Parameter:
592 .   viewer - PetscViewer context, obtained from PetscViewerBinaryOpen()
593 
594     Output Parameter:
595 .   skip - PETSC_TRUE means do not use
596 
597     Level: advanced
598 
599     Notes:
600     This must be called after PetscViewerSetType()
601 
602 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySkipInfo()`,
603           `PetscViewerBinarySetSkipOptions()`
604 @*/
605 PetscErrorCode PetscViewerBinaryGetSkipOptions(PetscViewer viewer,PetscBool *skip)
606 {
607   PetscFunctionBegin;
608   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
609   PetscValidBoolPointer(skip,2);
610   PetscUseMethod(viewer,"PetscViewerBinaryGetSkipOptions_C",(PetscViewer,PetscBool*),(viewer,skip));
611   PetscFunctionReturn(0);
612 }
613 
614 static PetscErrorCode PetscViewerBinaryGetSkipOptions_Binary(PetscViewer viewer,PetscBool *skip)
615 {
616   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
617 
618   PetscFunctionBegin;
619   *skip = vbinary->skipoptions;
620   PetscFunctionReturn(0);
621 }
622 
623 /*@
624     PetscViewerBinarySetSkipHeader - do not write a header with size information on output, just raw data
625 
626     Not Collective
627 
628     Input Parameters:
629 +   viewer - PetscViewer context, obtained from PetscViewerBinaryOpen()
630 -   skip - PETSC_TRUE means do not write header
631 
632     Options Database Key:
633 .   -viewer_binary_skip_header - PETSC_TRUE means do not write header
634 
635     Level: advanced
636 
637     Notes:
638       This must be called after PetscViewerSetType()
639 
640       Is ignored on anything but a binary viewer
641 
642 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySkipInfo()`,
643           `PetscViewerBinaryGetSkipHeader()`
644 @*/
645 PetscErrorCode PetscViewerBinarySetSkipHeader(PetscViewer viewer,PetscBool skip)
646 {
647   PetscFunctionBegin;
648   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
649   PetscValidLogicalCollectiveBool(viewer,skip,2);
650   PetscTryMethod(viewer,"PetscViewerBinarySetSkipHeader_C",(PetscViewer,PetscBool),(viewer,skip));
651   PetscFunctionReturn(0);
652 }
653 
654 static PetscErrorCode PetscViewerBinarySetSkipHeader_Binary(PetscViewer viewer,PetscBool skip)
655 {
656   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
657 
658   PetscFunctionBegin;
659   vbinary->skipheader = skip;
660   PetscFunctionReturn(0);
661 }
662 
663 /*@
664     PetscViewerBinaryGetSkipHeader - checks whether to write a header with size information on output, or just raw data
665 
666     Not Collective
667 
668     Input Parameter:
669 .   viewer - PetscViewer context, obtained from PetscViewerBinaryOpen()
670 
671     Output Parameter:
672 .   skip - PETSC_TRUE means do not write header
673 
674     Level: advanced
675 
676     Notes:
677     This must be called after PetscViewerSetType()
678 
679             Returns false for PETSCSOCKETVIEWER, you cannot skip the header for it.
680 
681 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySkipInfo()`,
682           `PetscViewerBinarySetSkipHeader()`
683 @*/
684 PetscErrorCode PetscViewerBinaryGetSkipHeader(PetscViewer viewer,PetscBool  *skip)
685 {
686   PetscFunctionBegin;
687   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
688   PetscValidBoolPointer(skip,2);
689   PetscUseMethod(viewer,"PetscViewerBinaryGetSkipHeader_C",(PetscViewer,PetscBool*),(viewer,skip));
690   PetscFunctionReturn(0);
691 }
692 
693 static PetscErrorCode PetscViewerBinaryGetSkipHeader_Binary(PetscViewer viewer,PetscBool  *skip)
694 {
695   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
696 
697   PetscFunctionBegin;
698   *skip = vbinary->skipheader;
699   PetscFunctionReturn(0);
700 }
701 
702 /*@C
703     PetscViewerBinaryGetInfoPointer - Extracts the file pointer for the ASCII
704           info file associated with a binary file.
705 
706     Not Collective
707 
708     Input Parameter:
709 .   viewer - PetscViewer context, obtained from PetscViewerBinaryOpen()
710 
711     Output Parameter:
712 .   file - file pointer  Always returns NULL if not a binary viewer
713 
714     Level: advanced
715 
716     Notes:
717       For writable binary PetscViewers, the descriptor will only be valid for the
718     first processor in the communicator that shares the PetscViewer.
719 
720     Fortran Note:
721     This routine is not supported in Fortran.
722 
723 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`
724 @*/
725 PetscErrorCode PetscViewerBinaryGetInfoPointer(PetscViewer viewer,FILE **file)
726 {
727   PetscFunctionBegin;
728   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
729   PetscValidPointer(file,2);
730   *file = NULL;
731   PetscTryMethod(viewer,"PetscViewerBinaryGetInfoPointer_C",(PetscViewer,FILE **),(viewer,file));
732   PetscFunctionReturn(0);
733 }
734 
735 static PetscErrorCode PetscViewerBinaryGetInfoPointer_Binary(PetscViewer viewer,FILE **file)
736 {
737   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
738 
739   PetscFunctionBegin;
740   PetscCall(PetscViewerSetUp(viewer));
741   *file = vbinary->fdes_info;
742   if (viewer->format == PETSC_VIEWER_BINARY_MATLAB && !vbinary->matlabheaderwritten) {
743     if (vbinary->fdes_info) {
744       FILE *info = vbinary->fdes_info;
745       PetscCall(PetscFPrintf(PETSC_COMM_SELF,info,"#--- begin code written by PetscViewerBinary for MATLAB format ---#\n"));
746       PetscCall(PetscFPrintf(PETSC_COMM_SELF,info,"#$$ Set.filename = '%s';\n",vbinary->filename));
747       PetscCall(PetscFPrintf(PETSC_COMM_SELF,info,"#$$ fd = PetscOpenFile(Set.filename);\n"));
748       PetscCall(PetscFPrintf(PETSC_COMM_SELF,info,"#--- end code written by PetscViewerBinary for MATLAB format ---#\n\n"));
749     }
750     vbinary->matlabheaderwritten = PETSC_TRUE;
751   }
752   PetscFunctionReturn(0);
753 }
754 
755 #if defined(PETSC_HAVE_MPIIO)
756 static PetscErrorCode PetscViewerFileClose_BinaryMPIIO(PetscViewer v)
757 {
758   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)v->data;
759 
760   PetscFunctionBegin;
761   if (vbinary->mfdes != MPI_FILE_NULL) {
762     PetscCallMPI(MPI_File_close(&vbinary->mfdes));
763   }
764   if (vbinary->mfsub != MPI_FILE_NULL) {
765     PetscCallMPI(MPI_File_close(&vbinary->mfsub));
766   }
767   vbinary->moff = 0;
768   PetscFunctionReturn(0);
769 }
770 #endif
771 
772 static PetscErrorCode PetscViewerFileClose_BinarySTDIO(PetscViewer v)
773 {
774   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)v->data;
775 
776   PetscFunctionBegin;
777   if (vbinary->fdes != -1) {
778     PetscCall(PetscBinaryClose(vbinary->fdes));
779     vbinary->fdes = -1;
780     if (vbinary->storecompressed) {
781       char cmd[8+PETSC_MAX_PATH_LEN],out[64+PETSC_MAX_PATH_LEN] = "";
782       const char *gzfilename = vbinary->ogzfilename ? vbinary->ogzfilename : vbinary->filename;
783       /* compress the file */
784       PetscCall(PetscStrncpy(cmd,"gzip -f ",sizeof(cmd)));
785       PetscCall(PetscStrlcat(cmd,gzfilename,sizeof(cmd)));
786 #if defined(PETSC_HAVE_POPEN)
787       {
788         FILE *fp;
789         PetscCall(PetscPOpen(PETSC_COMM_SELF,NULL,cmd,"r",&fp));
790         PetscCheck(!fgets(out,(int)(sizeof(out)-1),fp),PETSC_COMM_SELF,PETSC_ERR_LIB,"Error from command %s\n%s",cmd,out);
791         PetscCall(PetscPClose(PETSC_COMM_SELF,fp));
792       }
793 #endif
794     }
795   }
796   PetscCall(PetscFree(vbinary->ogzfilename));
797   PetscFunctionReturn(0);
798 }
799 
800 static PetscErrorCode PetscViewerFileClose_BinaryInfo(PetscViewer v)
801 {
802   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)v->data;
803 
804   PetscFunctionBegin;
805   if (v->format == PETSC_VIEWER_BINARY_MATLAB && vbinary->matlabheaderwritten) {
806     if (vbinary->fdes_info) {
807       FILE *info = vbinary->fdes_info;
808       PetscCall(PetscFPrintf(PETSC_COMM_SELF,info,"#--- begin code written by PetscViewerBinary for MATLAB format ---#\n"));
809       PetscCall(PetscFPrintf(PETSC_COMM_SELF,info,"#$$ close(fd);\n"));
810       PetscCall(PetscFPrintf(PETSC_COMM_SELF,info,"#--- end code written by PetscViewerBinary for MATLAB format ---#\n\n"));
811     }
812   }
813   if (vbinary->fdes_info) {
814     FILE *info = vbinary->fdes_info;
815     vbinary->fdes_info = NULL;
816     PetscCheck(!fclose(info),PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on file");
817   }
818   PetscFunctionReturn(0);
819 }
820 
821 static PetscErrorCode PetscViewerFileClose_Binary(PetscViewer v)
822 {
823   PetscFunctionBegin;
824 #if defined(PETSC_HAVE_MPIIO)
825   PetscCall(PetscViewerFileClose_BinaryMPIIO(v));
826 #endif
827   PetscCall(PetscViewerFileClose_BinarySTDIO(v));
828   PetscCall(PetscViewerFileClose_BinaryInfo(v));
829   PetscFunctionReturn(0);
830 }
831 
832 static PetscErrorCode PetscViewerDestroy_Binary(PetscViewer v)
833 {
834   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)v->data;
835 
836   PetscFunctionBegin;
837   PetscCall(PetscViewerFileClose_Binary(v));
838   PetscCall(PetscFree(vbinary->filename));
839   PetscCall(PetscFree(vbinary));
840   PetscCall(PetscViewerBinaryClearFunctionList(v));
841   PetscFunctionReturn(0);
842 }
843 
844 /*@C
845    PetscViewerBinaryOpen - Opens a file for binary input/output.
846 
847    Collective
848 
849    Input Parameters:
850 +  comm - MPI communicator
851 .  name - name of file
852 -  mode - open mode of file
853 $    FILE_MODE_WRITE - create new file for binary output
854 $    FILE_MODE_READ - open existing file for binary input
855 $    FILE_MODE_APPEND - open existing file for binary output
856 
857    Output Parameter:
858 .  viewer - PetscViewer for binary input/output to use with the specified file
859 
860     Options Database Keys:
861 +    -viewer_binary_filename <name> -
862 .    -viewer_binary_skip_info -
863 .    -viewer_binary_skip_options -
864 .    -viewer_binary_skip_header -
865 -    -viewer_binary_mpiio -
866 
867    Level: beginner
868 
869    Note:
870    This PetscViewer should be destroyed with PetscViewerDestroy().
871 
872     For reading files, the filename may begin with ftp:// or http:// and/or
873     end with .gz; in this case file is brought over and uncompressed.
874 
875     For creating files, if the file name ends with .gz it is automatically
876     compressed when closed.
877 
878 .seealso: `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`,
879           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`,
880           `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()`, `PetscViewerBinarySetUseMPIIO()`,
881           `PetscViewerBinaryGetUseMPIIO()`, `PetscViewerBinaryGetMPIIOOffset()`
882 @*/
883 PetscErrorCode PetscViewerBinaryOpen(MPI_Comm comm,const char name[],PetscFileMode mode,PetscViewer *viewer)
884 {
885   PetscFunctionBegin;
886   PetscCall(PetscViewerCreate(comm,viewer));
887   PetscCall(PetscViewerSetType(*viewer,PETSCVIEWERBINARY));
888   PetscCall(PetscViewerFileSetMode(*viewer,mode));
889   PetscCall(PetscViewerFileSetName(*viewer,name));
890   PetscCall(PetscViewerSetFromOptions(*viewer));
891   PetscFunctionReturn(0);
892 }
893 
894 #if defined(PETSC_HAVE_MPIIO)
895 static PetscErrorCode PetscViewerBinaryWriteReadMPIIO(PetscViewer viewer,void *data,PetscInt num,PetscInt *count,PetscDataType dtype,PetscBool write)
896 {
897   MPI_Comm           comm = PetscObjectComm((PetscObject)viewer);
898   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
899   MPI_File           mfdes = vbinary->mfdes;
900   MPI_Datatype       mdtype;
901   PetscMPIInt        rank,cnt;
902   MPI_Status         status;
903   MPI_Aint           ul,dsize;
904 
905   PetscFunctionBegin;
906   PetscCallMPI(MPI_Comm_rank(comm,&rank));
907   PetscCall(PetscMPIIntCast(num,&cnt));
908   PetscCall(PetscDataTypeToMPIDataType(dtype,&mdtype));
909   if (write) {
910     if (rank == 0) {
911       PetscCall(MPIU_File_write_at(mfdes,vbinary->moff,data,cnt,mdtype,&status));
912     }
913   } else {
914     if (rank == 0) {
915       PetscCall(MPIU_File_read_at(mfdes,vbinary->moff,data,cnt,mdtype,&status));
916       if (cnt > 0) PetscCallMPI(MPI_Get_count(&status,mdtype,&cnt));
917     }
918     PetscCallMPI(MPI_Bcast(&cnt,1,MPI_INT,0,comm));
919     PetscCallMPI(MPI_Bcast(data,cnt,mdtype,0,comm));
920   }
921   PetscCallMPI(MPI_Type_get_extent(mdtype,&ul,&dsize));
922   vbinary->moff += dsize*cnt;
923   if (count) *count = cnt;
924   PetscFunctionReturn(0);
925 }
926 #endif
927 
928 /*@C
929    PetscViewerBinaryRead - Reads from a binary file, all processors get the same result
930 
931    Collective
932 
933    Input Parameters:
934 +  viewer - the binary viewer
935 .  data - location of the data to be written
936 .  num - number of items of data to read
937 -  dtype - type of data to read
938 
939    Output Parameters:
940 .  count - number of items of data actually read, or NULL.
941 
942    Level: beginner
943 
944 .seealso: `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`,
945           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`,
946           `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()`
947 @*/
948 PetscErrorCode PetscViewerBinaryRead(PetscViewer viewer,void *data,PetscInt num,PetscInt *count,PetscDataType dtype)
949 {
950   PetscViewer_Binary *vbinary;
951 
952   PetscFunctionBegin;
953   PetscValidHeaderSpecificType(viewer,PETSC_VIEWER_CLASSID,1,PETSCVIEWERBINARY);
954   PetscValidLogicalCollectiveInt(viewer,num,3);
955   PetscCall(PetscViewerSetUp(viewer));
956   vbinary = (PetscViewer_Binary*)viewer->data;
957 #if defined(PETSC_HAVE_MPIIO)
958   if (vbinary->usempiio) {
959     PetscCall(PetscViewerBinaryWriteReadMPIIO(viewer,data,num,count,dtype,PETSC_FALSE));
960   } else {
961 #endif
962     PetscCall(PetscBinarySynchronizedRead(PetscObjectComm((PetscObject)viewer),vbinary->fdes,data,num,count,dtype));
963 #if defined(PETSC_HAVE_MPIIO)
964   }
965 #endif
966   PetscFunctionReturn(0);
967 }
968 
969 /*@C
970    PetscViewerBinaryWrite - writes to a binary file, only from the first process
971 
972    Collective
973 
974    Input Parameters:
975 +  viewer - the binary viewer
976 .  data - location of data
977 .  count - number of items of data to write
978 -  dtype - type of data to write
979 
980    Level: beginner
981 
982 .seealso: `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`,
983           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`, `PetscDataType`
984           `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()`
985 @*/
986 PetscErrorCode PetscViewerBinaryWrite(PetscViewer viewer,const void *data,PetscInt count,PetscDataType dtype)
987 {
988   PetscViewer_Binary *vbinary;
989 
990   PetscFunctionBegin;
991   PetscValidHeaderSpecificType(viewer,PETSC_VIEWER_CLASSID,1,PETSCVIEWERBINARY);
992   PetscValidLogicalCollectiveInt(viewer,count,3);
993   PetscCall(PetscViewerSetUp(viewer));
994   vbinary = (PetscViewer_Binary*)viewer->data;
995 #if defined(PETSC_HAVE_MPIIO)
996   if (vbinary->usempiio) {
997     PetscCall(PetscViewerBinaryWriteReadMPIIO(viewer,(void*)data,count,NULL,dtype,PETSC_TRUE));
998   } else {
999 #endif
1000     PetscCall(PetscBinarySynchronizedWrite(PetscObjectComm((PetscObject)viewer),vbinary->fdes,data,count,dtype));
1001 #if defined(PETSC_HAVE_MPIIO)
1002   }
1003 #endif
1004   PetscFunctionReturn(0);
1005 }
1006 
1007 static PetscErrorCode PetscViewerBinaryWriteReadAll(PetscViewer viewer,PetscBool write,void *data,PetscInt count,PetscInt start,PetscInt total,PetscDataType dtype)
1008 {
1009   MPI_Comm              comm = PetscObjectComm((PetscObject)viewer);
1010   PetscMPIInt           size,rank;
1011   MPI_Datatype          mdtype;
1012   PETSC_UNUSED MPI_Aint lb;
1013   MPI_Aint              dsize;
1014   PetscBool             useMPIIO;
1015 
1016   PetscFunctionBegin;
1017   PetscValidHeaderSpecificType(viewer,PETSC_VIEWER_CLASSID,1,PETSCVIEWERBINARY);
1018   PetscValidLogicalCollectiveBool(viewer,((start>=0)||(start==PETSC_DETERMINE)),5);
1019   PetscValidLogicalCollectiveBool(viewer,((total>=0)||(total==PETSC_DETERMINE)),6);
1020   PetscValidLogicalCollectiveInt(viewer,total,6);
1021   PetscCall(PetscViewerSetUp(viewer));
1022 
1023   PetscCall(PetscDataTypeToMPIDataType(dtype,&mdtype));
1024   PetscCallMPI(MPI_Type_get_extent(mdtype,&lb,&dsize));
1025   PetscCallMPI(MPI_Comm_rank(comm,&rank));
1026   PetscCallMPI(MPI_Comm_size(comm,&size));
1027 
1028   PetscCall(PetscViewerBinaryGetUseMPIIO(viewer,&useMPIIO));
1029 #if defined(PETSC_HAVE_MPIIO)
1030   if (useMPIIO) {
1031     MPI_File       mfdes;
1032     MPI_Offset     off;
1033     PetscMPIInt    cnt;
1034 
1035     if (start == PETSC_DETERMINE) {
1036       PetscCallMPI(MPI_Scan(&count,&start,1,MPIU_INT,MPI_SUM,comm));
1037       start -= count;
1038     }
1039     if (total == PETSC_DETERMINE) {
1040       total = start + count;
1041       PetscCallMPI(MPI_Bcast(&total,1,MPIU_INT,size-1,comm));
1042     }
1043     PetscCall(PetscMPIIntCast(count,&cnt));
1044     PetscCall(PetscViewerBinaryGetMPIIODescriptor(viewer,&mfdes));
1045     PetscCall(PetscViewerBinaryGetMPIIOOffset(viewer,&off));
1046     off += (MPI_Offset)(start*dsize);
1047     if (write) {
1048       PetscCall(MPIU_File_write_at_all(mfdes,off,data,cnt,mdtype,MPI_STATUS_IGNORE));
1049     } else {
1050       PetscCall(MPIU_File_read_at_all(mfdes,off,data,cnt,mdtype,MPI_STATUS_IGNORE));
1051     }
1052     off  = (MPI_Offset)(total*dsize);
1053     PetscCall(PetscViewerBinaryAddMPIIOOffset(viewer,off));
1054     PetscFunctionReturn(0);
1055   }
1056 #endif
1057   {
1058     int         fdes;
1059     char        *workbuf = NULL;
1060     PetscInt    tcount = rank == 0 ? 0 : count,maxcount=0,message_count,flowcontrolcount;
1061     PetscMPIInt tag,cnt,maxcnt,scnt=0,rcnt=0,j;
1062     MPI_Status  status;
1063 
1064     PetscCall(PetscCommGetNewTag(comm,&tag));
1065     PetscCallMPI(MPI_Reduce(&tcount,&maxcount,1,MPIU_INT,MPI_MAX,0,comm));
1066     PetscCall(PetscMPIIntCast(maxcount,&maxcnt));
1067     PetscCall(PetscMPIIntCast(count,&cnt));
1068 
1069     PetscCall(PetscViewerBinaryGetDescriptor(viewer,&fdes));
1070     PetscCall(PetscViewerFlowControlStart(viewer,&message_count,&flowcontrolcount));
1071     if (rank == 0) {
1072       PetscCall(PetscMalloc(maxcnt*dsize,&workbuf));
1073       if (write) {
1074         PetscCall(PetscBinaryWrite(fdes,data,cnt,dtype));
1075       } else {
1076         PetscCall(PetscBinaryRead(fdes,data,cnt,NULL,dtype));
1077       }
1078       for (j=1; j<size; j++) {
1079         PetscCall(PetscViewerFlowControlStepMain(viewer,j,&message_count,flowcontrolcount));
1080         if (write) {
1081           PetscCallMPI(MPI_Recv(workbuf,maxcnt,mdtype,j,tag,comm,&status));
1082           PetscCallMPI(MPI_Get_count(&status,mdtype,&rcnt));
1083           PetscCall(PetscBinaryWrite(fdes,workbuf,rcnt,dtype));
1084         } else {
1085           PetscCallMPI(MPI_Recv(&scnt,1,MPI_INT,j,tag,comm,MPI_STATUS_IGNORE));
1086           PetscCall(PetscBinaryRead(fdes,workbuf,scnt,NULL,dtype));
1087           PetscCallMPI(MPI_Send(workbuf,scnt,mdtype,j,tag,comm));
1088         }
1089       }
1090       PetscCall(PetscFree(workbuf));
1091       PetscCall(PetscViewerFlowControlEndMain(viewer,&message_count));
1092     } else {
1093       PetscCall(PetscViewerFlowControlStepWorker(viewer,rank,&message_count));
1094       if (write) {
1095         PetscCallMPI(MPI_Send(data,cnt,mdtype,0,tag,comm));
1096       } else {
1097         PetscCallMPI(MPI_Send(&cnt,1,MPI_INT,0,tag,comm));
1098         PetscCallMPI(MPI_Recv(data,cnt,mdtype,0,tag,comm,MPI_STATUS_IGNORE));
1099       }
1100       PetscCall(PetscViewerFlowControlEndWorker(viewer,&message_count));
1101     }
1102   }
1103   PetscFunctionReturn(0);
1104 }
1105 
1106 /*@C
1107    PetscViewerBinaryReadAll - reads from a binary file from all processes
1108 
1109    Collective
1110 
1111    Input Parameters:
1112 +  viewer - the binary viewer
1113 .  data - location of data
1114 .  count - local number of items of data to read
1115 .  start - local start, can be PETSC_DETERMINE
1116 .  total - global number of items of data to read, can be PETSC_DETERMINE
1117 -  dtype - type of data to read
1118 
1119    Level: advanced
1120 
1121 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryRead()`, `PetscViewerBinaryWriteAll()`
1122 @*/
1123 PetscErrorCode PetscViewerBinaryReadAll(PetscViewer viewer,void *data,PetscInt count,PetscInt start,PetscInt total,PetscDataType dtype)
1124 {
1125   PetscFunctionBegin;
1126   PetscCall(PetscViewerBinaryWriteReadAll(viewer,PETSC_FALSE,data,count,start,total,dtype));
1127   PetscFunctionReturn(0);
1128 }
1129 
1130 /*@C
1131    PetscViewerBinaryWriteAll - writes to a binary file from all processes
1132 
1133    Collective
1134 
1135    Input Parameters:
1136 +  viewer - the binary viewer
1137 .  data - location of data
1138 .  count - local number of items of data to write
1139 .  start - local start, can be PETSC_DETERMINE
1140 .  total - global number of items of data to write, can be PETSC_DETERMINE
1141 -  dtype - type of data to write
1142 
1143    Level: advanced
1144 
1145 .seealso: `PetscViewerBinaryOpen()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryWriteAll()`, `PetscViewerBinaryReadAll()`
1146 @*/
1147 PetscErrorCode PetscViewerBinaryWriteAll(PetscViewer viewer,const void *data,PetscInt count,PetscInt start,PetscInt total,PetscDataType dtype)
1148 {
1149   PetscFunctionBegin;
1150   PetscCall(PetscViewerBinaryWriteReadAll(viewer,PETSC_TRUE,(void*)data,count,start,total,dtype));
1151   PetscFunctionReturn(0);
1152 }
1153 
1154 /*@C
1155    PetscViewerBinaryWriteStringArray - writes to a binary file, only from the first process an array of strings
1156 
1157    Collective
1158 
1159    Input Parameters:
1160 +  viewer - the binary viewer
1161 -  data - location of the array of strings
1162 
1163    Level: intermediate
1164 
1165     Notes:
1166     array of strings is null terminated
1167 
1168 .seealso: `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`,
1169           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`,
1170           `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()`
1171 @*/
1172 PetscErrorCode PetscViewerBinaryWriteStringArray(PetscViewer viewer,const char * const *data)
1173 {
1174   PetscInt       i,n = 0,*sizes;
1175   size_t         len;
1176 
1177   PetscFunctionBegin;
1178   PetscCall(PetscViewerSetUp(viewer));
1179   /* count number of strings */
1180   while (data[n++]);
1181   n--;
1182   PetscCall(PetscMalloc1(n+1,&sizes));
1183   sizes[0] = n;
1184   for (i=0; i<n; i++) {
1185     PetscCall(PetscStrlen(data[i],&len));
1186     sizes[i+1] = (PetscInt)len + 1; /* size includes space for the null terminator */
1187   }
1188   PetscCall(PetscViewerBinaryWrite(viewer,sizes,n+1,PETSC_INT));
1189   for (i=0; i<n; i++) {
1190     PetscCall(PetscViewerBinaryWrite(viewer,(void*)data[i],sizes[i+1],PETSC_CHAR));
1191   }
1192   PetscCall(PetscFree(sizes));
1193   PetscFunctionReturn(0);
1194 }
1195 
1196 /*@C
1197    PetscViewerBinaryReadStringArray - reads a binary file an array of strings
1198 
1199    Collective
1200 
1201    Input Parameter:
1202 .  viewer - the binary viewer
1203 
1204    Output Parameter:
1205 .  data - location of the array of strings
1206 
1207    Level: intermediate
1208 
1209     Notes:
1210     array of strings is null terminated
1211 
1212 .seealso: `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`,
1213           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`,
1214           `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()`
1215 @*/
1216 PetscErrorCode PetscViewerBinaryReadStringArray(PetscViewer viewer,char ***data)
1217 {
1218   PetscInt       i,n,*sizes,N = 0;
1219 
1220   PetscFunctionBegin;
1221   PetscCall(PetscViewerSetUp(viewer));
1222   /* count number of strings */
1223   PetscCall(PetscViewerBinaryRead(viewer,&n,1,NULL,PETSC_INT));
1224   PetscCall(PetscMalloc1(n,&sizes));
1225   PetscCall(PetscViewerBinaryRead(viewer,sizes,n,NULL,PETSC_INT));
1226   for (i=0; i<n; i++) N += sizes[i];
1227   PetscCall(PetscMalloc((n+1)*sizeof(char*) + N*sizeof(char),data));
1228   (*data)[0] = (char*)((*data) + n + 1);
1229   for (i=1; i<n; i++) (*data)[i] = (*data)[i-1] + sizes[i-1];
1230   PetscCall(PetscViewerBinaryRead(viewer,(*data)[0],N,NULL,PETSC_CHAR));
1231   (*data)[n] = NULL;
1232   PetscCall(PetscFree(sizes));
1233   PetscFunctionReturn(0);
1234 }
1235 
1236 /*@C
1237      PetscViewerFileSetMode - Sets the open mode of file
1238 
1239     Logically Collective on PetscViewer
1240 
1241   Input Parameters:
1242 +  viewer - the PetscViewer; must be a a PETSCVIEWERBINARY, PETSCVIEWERMATLAB, PETSCVIEWERHDF5, or PETSCVIEWERASCII  PetscViewer
1243 -  mode - open mode of file
1244 $    FILE_MODE_WRITE - create new file for output
1245 $    FILE_MODE_READ - open existing file for input
1246 $    FILE_MODE_APPEND - open existing file for output
1247 
1248   Level: advanced
1249 
1250 .seealso: `PetscViewerFileSetMode()`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerBinaryOpen()`
1251 
1252 @*/
1253 PetscErrorCode PetscViewerFileSetMode(PetscViewer viewer,PetscFileMode mode)
1254 {
1255   PetscFunctionBegin;
1256   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1257   PetscValidLogicalCollectiveEnum(viewer,mode,2);
1258   PetscCheck(mode != FILE_MODE_UNDEFINED,PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"Cannot set FILE_MODE_UNDEFINED");
1259   PetscCheck(mode >= FILE_MODE_UNDEFINED && mode <= FILE_MODE_APPEND_UPDATE,PetscObjectComm((PetscObject)viewer),PETSC_ERR_ARG_OUTOFRANGE,"Invalid file mode %d",(int)mode);
1260   PetscTryMethod(viewer,"PetscViewerFileSetMode_C",(PetscViewer,PetscFileMode),(viewer,mode));
1261   PetscFunctionReturn(0);
1262 }
1263 
1264 static PetscErrorCode PetscViewerFileSetMode_Binary(PetscViewer viewer,PetscFileMode mode)
1265 {
1266   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
1267 
1268   PetscFunctionBegin;
1269   PetscCheck(!viewer->setupcalled || vbinary->filemode == mode,PetscObjectComm((PetscObject)viewer),PETSC_ERR_ORDER,"Cannot change mode to %s after setup",PetscFileModes[mode]);
1270   vbinary->filemode = mode;
1271   PetscFunctionReturn(0);
1272 }
1273 
1274 /*@C
1275      PetscViewerFileGetMode - Gets the open mode of file
1276 
1277     Not Collective
1278 
1279   Input Parameter:
1280 .  viewer - the PetscViewer; must be a PETSCVIEWERBINARY, PETSCVIEWERMATLAB, PETSCVIEWERHDF5, or PETSCVIEWERASCII  PetscViewer
1281 
1282   Output Parameter:
1283 .  mode - open mode of file
1284 $    FILE_MODE_WRITE - create new file for binary output
1285 $    FILE_MODE_READ - open existing file for binary input
1286 $    FILE_MODE_APPEND - open existing file for binary output
1287 
1288   Level: advanced
1289 
1290 .seealso: `PetscViewerFileSetMode()`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerBinaryOpen()`
1291 
1292 @*/
1293 PetscErrorCode PetscViewerFileGetMode(PetscViewer viewer,PetscFileMode *mode)
1294 {
1295   PetscFunctionBegin;
1296   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1297   PetscValidPointer(mode,2);
1298   PetscUseMethod(viewer,"PetscViewerFileGetMode_C",(PetscViewer,PetscFileMode*),(viewer,mode));
1299   PetscFunctionReturn(0);
1300 }
1301 
1302 static PetscErrorCode PetscViewerFileGetMode_Binary(PetscViewer viewer,PetscFileMode *mode)
1303 {
1304   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
1305 
1306   PetscFunctionBegin;
1307   *mode = vbinary->filemode;
1308   PetscFunctionReturn(0);
1309 }
1310 
1311 static PetscErrorCode PetscViewerFileSetName_Binary(PetscViewer viewer,const char name[])
1312 {
1313   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
1314 
1315   PetscFunctionBegin;
1316   if (viewer->setupcalled && vbinary->filename) {
1317     /* gzip can be run after the file with the previous filename has been closed */
1318     PetscCall(PetscFree(vbinary->ogzfilename));
1319     PetscCall(PetscStrallocpy(vbinary->filename,&vbinary->ogzfilename));
1320   }
1321   PetscCall(PetscFree(vbinary->filename));
1322   PetscCall(PetscStrallocpy(name,&vbinary->filename));
1323   viewer->setupcalled = PETSC_FALSE;
1324   PetscFunctionReturn(0);
1325 }
1326 
1327 static PetscErrorCode PetscViewerFileGetName_Binary(PetscViewer viewer,const char **name)
1328 {
1329   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
1330 
1331   PetscFunctionBegin;
1332   *name = vbinary->filename;
1333   PetscFunctionReturn(0);
1334 }
1335 
1336 #if defined(PETSC_HAVE_MPIIO)
1337 static PetscErrorCode PetscViewerFileSetUp_BinaryMPIIO(PetscViewer viewer)
1338 {
1339   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
1340   int                amode;
1341 
1342   PetscFunctionBegin;
1343   vbinary->storecompressed = PETSC_FALSE;
1344 
1345   vbinary->moff = 0;
1346   switch (vbinary->filemode) {
1347   case FILE_MODE_READ:   amode = MPI_MODE_RDONLY; break;
1348   case FILE_MODE_WRITE:  amode = MPI_MODE_WRONLY | MPI_MODE_CREATE; break;
1349   case FILE_MODE_APPEND: amode = MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_APPEND; break;
1350   case FILE_MODE_UNDEFINED: SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_ORDER, "Must call PetscViewerFileSetMode() before PetscViewerSetUp()");
1351   default: SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"Unsupported file mode %s",PetscFileModes[vbinary->filemode]);
1352   }
1353   PetscCallMPI(MPI_File_open(PetscObjectComm((PetscObject)viewer),vbinary->filename,amode,MPI_INFO_NULL,&vbinary->mfdes));
1354   /*
1355       The MPI standard does not have MPI_MODE_TRUNCATE. We emulate this behavior by setting the file size to zero.
1356   */
1357   if (vbinary->filemode == FILE_MODE_WRITE) PetscCallMPI(MPI_File_set_size(vbinary->mfdes,0));
1358   /*
1359       Initially, all processes view the file as a linear byte stream. Therefore, for files opened with MPI_MODE_APPEND,
1360       MPI_File_get_position[_shared](fh, &offset) returns the absolute byte position at the end of file.
1361       Otherwise, we would need to call MPI_File_get_byte_offset(fh, offset, &byte_offset) to convert
1362       the offset in etype units to an absolute byte position.
1363    */
1364   if (vbinary->filemode == FILE_MODE_APPEND) PetscCallMPI(MPI_File_get_position(vbinary->mfdes,&vbinary->moff));
1365   PetscFunctionReturn(0);
1366 }
1367 #endif
1368 
1369 static PetscErrorCode PetscViewerFileSetUp_BinarySTDIO(PetscViewer viewer)
1370 {
1371   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
1372   const char         *fname;
1373   char               bname[PETSC_MAX_PATH_LEN],*gz;
1374   PetscBool          found;
1375   PetscMPIInt        rank;
1376 
1377   PetscFunctionBegin;
1378   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer),&rank));
1379 
1380   /* if file name ends in .gz strip that off and note user wants file compressed */
1381   vbinary->storecompressed = PETSC_FALSE;
1382   if (vbinary->filemode == FILE_MODE_WRITE) {
1383     PetscCall(PetscStrstr(vbinary->filename,".gz",&gz));
1384     if (gz && gz[3] == 0) {*gz = 0; vbinary->storecompressed = PETSC_TRUE;}
1385   }
1386 #if !defined(PETSC_HAVE_POPEN)
1387   PetscCheck(!vbinary->storecompressed,PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP_SYS,"Cannot run gzip on this machine");
1388 #endif
1389 
1390   fname = vbinary->filename;
1391   if (vbinary->filemode == FILE_MODE_READ) { /* possibly get the file from remote site or compressed file */
1392     PetscCall(PetscFileRetrieve(PetscObjectComm((PetscObject)viewer),fname,bname,PETSC_MAX_PATH_LEN,&found));
1393     PetscCheck(found,PetscObjectComm((PetscObject)viewer),PETSC_ERR_FILE_OPEN,"Cannot locate file: %s",fname);
1394     fname = bname;
1395   }
1396 
1397   vbinary->fdes = -1;
1398   if (rank == 0) { /* only first processor opens file*/
1399     PetscFileMode mode = vbinary->filemode;
1400     if (mode == FILE_MODE_APPEND) {
1401       /* check if asked to append to a non-existing file */
1402       PetscCall(PetscTestFile(fname,'\0',&found));
1403       if (!found) mode = FILE_MODE_WRITE;
1404     }
1405     PetscCall(PetscBinaryOpen(fname,mode,&vbinary->fdes));
1406   }
1407   PetscFunctionReturn(0);
1408 }
1409 
1410 static PetscErrorCode PetscViewerFileSetUp_BinaryInfo(PetscViewer viewer)
1411 {
1412   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
1413   PetscMPIInt        rank;
1414   PetscBool          found;
1415 
1416   PetscFunctionBegin;
1417   vbinary->fdes_info = NULL;
1418   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer),&rank));
1419   if (!vbinary->skipinfo && (vbinary->filemode == FILE_MODE_READ || rank == 0)) {
1420     char infoname[PETSC_MAX_PATH_LEN],iname[PETSC_MAX_PATH_LEN],*gz;
1421 
1422     PetscCall(PetscStrncpy(infoname,vbinary->filename,sizeof(infoname)));
1423     /* remove .gz if it ends file name */
1424     PetscCall(PetscStrstr(infoname,".gz",&gz));
1425     if (gz && gz[3] == 0) *gz = 0;
1426 
1427     PetscCall(PetscStrlcat(infoname,".info",sizeof(infoname)));
1428     if (vbinary->filemode == FILE_MODE_READ) {
1429       PetscCall(PetscFixFilename(infoname,iname));
1430       PetscCall(PetscFileRetrieve(PetscObjectComm((PetscObject)viewer),iname,infoname,PETSC_MAX_PATH_LEN,&found));
1431       if (found) PetscCall(PetscOptionsInsertFile(PetscObjectComm((PetscObject)viewer),((PetscObject)viewer)->options,infoname,PETSC_FALSE));
1432     } else if (rank == 0) { /* write or append */
1433       const char *omode = (vbinary->filemode == FILE_MODE_APPEND) ? "a" : "w";
1434       vbinary->fdes_info = fopen(infoname,omode);
1435       PetscCheck(vbinary->fdes_info,PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open .info file %s for writing",infoname);
1436     }
1437   }
1438   PetscFunctionReturn(0);
1439 }
1440 
1441 static PetscErrorCode PetscViewerSetUp_Binary(PetscViewer viewer)
1442 {
1443   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)viewer->data;
1444   PetscBool          usempiio;
1445 
1446   PetscFunctionBegin;
1447   if (!vbinary->setfromoptionscalled) PetscCall(PetscViewerSetFromOptions(viewer));
1448   PetscCheck(vbinary->filename,PETSC_COMM_SELF,PETSC_ERR_ORDER,"Must call PetscViewerFileSetName()");
1449   PetscCheck(vbinary->filemode != (PetscFileMode)-1,PETSC_COMM_SELF,PETSC_ERR_ORDER,"Must call PetscViewerFileSetMode()");
1450   PetscCall(PetscViewerFileClose_Binary(viewer));
1451 
1452   PetscCall(PetscViewerBinaryGetUseMPIIO(viewer,&usempiio));
1453   if (usempiio) {
1454 #if defined(PETSC_HAVE_MPIIO)
1455     PetscCall(PetscViewerFileSetUp_BinaryMPIIO(viewer));
1456 #endif
1457   } else {
1458     PetscCall(PetscViewerFileSetUp_BinarySTDIO(viewer));
1459   }
1460   PetscCall(PetscViewerFileSetUp_BinaryInfo(viewer));
1461 
1462   PetscCall(PetscLogObjectState((PetscObject)viewer,"File: %s",vbinary->filename));
1463   PetscFunctionReturn(0);
1464 }
1465 
1466 static PetscErrorCode PetscViewerView_Binary(PetscViewer v,PetscViewer viewer)
1467 {
1468   PetscViewer_Binary *vbinary = (PetscViewer_Binary*)v->data;
1469   const char         *fname = vbinary->filename ? vbinary->filename : "not yet set";
1470   const char         *fmode = vbinary->filemode != (PetscFileMode) -1 ? PetscFileModes[vbinary->filemode] : "not yet set";
1471   PetscBool          usempiio;
1472 
1473   PetscFunctionBegin;
1474   PetscCall(PetscViewerBinaryGetUseMPIIO(v,&usempiio));
1475   PetscCall(PetscViewerASCIIPrintf(viewer,"Filename: %s\n",fname));
1476   PetscCall(PetscViewerASCIIPrintf(viewer,"Mode: %s (%s)\n",fmode,usempiio ? "mpiio" : "stdio"));
1477   PetscFunctionReturn(0);
1478 }
1479 
1480 static PetscErrorCode PetscViewerSetFromOptions_Binary(PetscOptionItems *PetscOptionsObject,PetscViewer viewer)
1481 {
1482   PetscViewer_Binary *binary = (PetscViewer_Binary*)viewer->data;
1483   char               defaultname[PETSC_MAX_PATH_LEN];
1484   PetscBool          flg;
1485 
1486   PetscFunctionBegin;
1487   if (viewer->setupcalled) PetscFunctionReturn(0);
1488   PetscOptionsHeadBegin(PetscOptionsObject,"Binary PetscViewer Options");
1489   PetscCall(PetscSNPrintf(defaultname,PETSC_MAX_PATH_LEN-1,"binaryoutput"));
1490   PetscCall(PetscOptionsString("-viewer_binary_filename","Specify filename","PetscViewerFileSetName",defaultname,defaultname,sizeof(defaultname),&flg));
1491   if (flg) PetscCall(PetscViewerFileSetName_Binary(viewer,defaultname));
1492   PetscCall(PetscOptionsBool("-viewer_binary_skip_info","Skip writing/reading .info file","PetscViewerBinarySetSkipInfo",binary->skipinfo,&binary->skipinfo,NULL));
1493   PetscCall(PetscOptionsBool("-viewer_binary_skip_options","Skip parsing Vec/Mat load options","PetscViewerBinarySetSkipOptions",binary->skipoptions,&binary->skipoptions,NULL));
1494   PetscCall(PetscOptionsBool("-viewer_binary_skip_header","Skip writing/reading header information","PetscViewerBinarySetSkipHeader",binary->skipheader,&binary->skipheader,NULL));
1495 #if defined(PETSC_HAVE_MPIIO)
1496   PetscCall(PetscOptionsBool("-viewer_binary_mpiio","Use MPI-IO functionality to write/read binary file","PetscViewerBinarySetUseMPIIO",binary->usempiio,&binary->usempiio,NULL));
1497 #else
1498   PetscCall(PetscOptionsBool("-viewer_binary_mpiio","Use MPI-IO functionality to write/read binary file (NOT AVAILABLE)","PetscViewerBinarySetUseMPIIO",PETSC_FALSE,NULL,NULL));
1499 #endif
1500   PetscOptionsHeadEnd();
1501   binary->setfromoptionscalled = PETSC_TRUE;
1502   PetscFunctionReturn(0);
1503 }
1504 
1505 /*MC
1506    PETSCVIEWERBINARY - A viewer that saves to binary files
1507 
1508 .seealso: `PetscViewerBinaryOpen()`, `PETSC_VIEWER_STDOUT_()`, `PETSC_VIEWER_STDOUT_SELF`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscViewerCreate()`, `PetscViewerASCIIOpen()`,
1509           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERASCII`, `PETSCVIEWERMATLAB`, `PETSCVIEWERDRAW`,
1510           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`,
1511           `PetscViewerBinaryGetUseMPIIO()`, `PetscViewerBinarySetUseMPIIO()`
1512 
1513   Level: beginner
1514 
1515 M*/
1516 
1517 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Binary(PetscViewer v)
1518 {
1519   PetscViewer_Binary *vbinary;
1520 
1521   PetscFunctionBegin;
1522   PetscCall(PetscNewLog(v,&vbinary));
1523   v->data = (void*)vbinary;
1524 
1525   v->ops->setfromoptions   = PetscViewerSetFromOptions_Binary;
1526   v->ops->destroy          = PetscViewerDestroy_Binary;
1527   v->ops->view             = PetscViewerView_Binary;
1528   v->ops->setup            = PetscViewerSetUp_Binary;
1529   v->ops->flush            = NULL; /* Should we support Flush() ? */
1530   v->ops->getsubviewer     = PetscViewerGetSubViewer_Binary;
1531   v->ops->restoresubviewer = PetscViewerRestoreSubViewer_Binary;
1532   v->ops->read             = PetscViewerBinaryRead;
1533 
1534   vbinary->fdes            = -1;
1535 #if defined(PETSC_HAVE_MPIIO)
1536   vbinary->usempiio        = PETSC_FALSE;
1537   vbinary->mfdes           = MPI_FILE_NULL;
1538   vbinary->mfsub           = MPI_FILE_NULL;
1539 #endif
1540   vbinary->filename        = NULL;
1541   vbinary->filemode        = FILE_MODE_UNDEFINED;
1542   vbinary->fdes_info       = NULL;
1543   vbinary->skipinfo        = PETSC_FALSE;
1544   vbinary->skipoptions     = PETSC_TRUE;
1545   vbinary->skipheader      = PETSC_FALSE;
1546   vbinary->storecompressed = PETSC_FALSE;
1547   vbinary->ogzfilename     = NULL;
1548   vbinary->flowcontrol     = 256; /* seems a good number for Cray XT-5 */
1549 
1550   vbinary->setfromoptionscalled = PETSC_FALSE;
1551 
1552   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetFlowControl_C",PetscViewerBinaryGetFlowControl_Binary));
1553   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetFlowControl_C",PetscViewerBinarySetFlowControl_Binary));
1554   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetSkipHeader_C",PetscViewerBinaryGetSkipHeader_Binary));
1555   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetSkipHeader_C",PetscViewerBinarySetSkipHeader_Binary));
1556   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetSkipOptions_C",PetscViewerBinaryGetSkipOptions_Binary));
1557   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetSkipOptions_C",PetscViewerBinarySetSkipOptions_Binary));
1558   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetSkipInfo_C",PetscViewerBinaryGetSkipInfo_Binary));
1559   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetSkipInfo_C",PetscViewerBinarySetSkipInfo_Binary));
1560   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetInfoPointer_C",PetscViewerBinaryGetInfoPointer_Binary));
1561   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileGetName_C",PetscViewerFileGetName_Binary));
1562   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileSetName_C",PetscViewerFileSetName_Binary));
1563   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileGetMode_C",PetscViewerFileGetMode_Binary));
1564   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileSetMode_C",PetscViewerFileSetMode_Binary));
1565 #if defined(PETSC_HAVE_MPIIO)
1566   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetUseMPIIO_C",PetscViewerBinaryGetUseMPIIO_Binary));
1567   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetUseMPIIO_C",PetscViewerBinarySetUseMPIIO_Binary));
1568 #endif
1569   PetscFunctionReturn(0);
1570 }
1571 
1572 /* ---------------------------------------------------------------------*/
1573 /*
1574     The variable Petsc_Viewer_Binary_keyval is used to indicate an MPI attribute that
1575   is attached to a communicator, in this case the attribute is a PetscViewer.
1576 */
1577 PetscMPIInt Petsc_Viewer_Binary_keyval = MPI_KEYVAL_INVALID;
1578 
1579 /*@C
1580      PETSC_VIEWER_BINARY_ - Creates a binary PetscViewer shared by all processors
1581                      in a communicator.
1582 
1583      Collective
1584 
1585      Input Parameter:
1586 .    comm - the MPI communicator to share the binary PetscViewer
1587 
1588      Level: intermediate
1589 
1590    Options Database Keys:
1591 +    -viewer_binary_filename <name> - filename in which to store the binary data, defaults to binaryoutput
1592 .    -viewer_binary_skip_info - true means do not create .info file for this viewer
1593 .    -viewer_binary_skip_options - true means do not use the options database for this viewer
1594 .    -viewer_binary_skip_header - true means do not store the usual header information in the binary file
1595 -    -viewer_binary_mpiio - true means use the file via MPI-IO, maybe faster for large files and many MPI ranks
1596 
1597    Environmental variables:
1598 -   PETSC_VIEWER_BINARY_FILENAME - filename in which to store the binary data, defaults to binaryoutput
1599 
1600      Notes:
1601      Unlike almost all other PETSc routines, PETSC_VIEWER_BINARY_ does not return
1602      an error code.  The binary PetscViewer is usually used in the form
1603 $       XXXView(XXX object,PETSC_VIEWER_BINARY_(comm));
1604 
1605 .seealso: `PETSC_VIEWER_BINARY_WORLD`, `PETSC_VIEWER_BINARY_SELF`, `PetscViewerBinaryOpen()`, `PetscViewerCreate()`,
1606           `PetscViewerDestroy()`
1607 @*/
1608 PetscViewer PETSC_VIEWER_BINARY_(MPI_Comm comm)
1609 {
1610   PetscErrorCode ierr;
1611   PetscBool      flg;
1612   PetscViewer    viewer;
1613   char           fname[PETSC_MAX_PATH_LEN];
1614   MPI_Comm       ncomm;
1615 
1616   PetscFunctionBegin;
1617   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_BINARY_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
1618   if (Petsc_Viewer_Binary_keyval == MPI_KEYVAL_INVALID) {
1619     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Viewer_Binary_keyval,NULL);
1620     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_BINARY_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
1621   }
1622   ierr = MPI_Comm_get_attr(ncomm,Petsc_Viewer_Binary_keyval,(void**)&viewer,(int*)&flg);
1623   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_BINARY_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
1624   if (!flg) { /* PetscViewer not yet created */
1625     ierr = PetscOptionsGetenv(ncomm,"PETSC_VIEWER_BINARY_FILENAME",fname,PETSC_MAX_PATH_LEN,&flg);
1626     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_BINARY_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
1627     if (!flg) {
1628       ierr = PetscStrcpy(fname,"binaryoutput");
1629       if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_BINARY_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
1630     }
1631     ierr = PetscViewerBinaryOpen(ncomm,fname,FILE_MODE_WRITE,&viewer);
1632     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_BINARY_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
1633     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
1634     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_BINARY_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
1635     ierr = MPI_Comm_set_attr(ncomm,Petsc_Viewer_Binary_keyval,(void*)viewer);
1636     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_BINARY_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
1637   }
1638   ierr = PetscCommDestroy(&ncomm);
1639   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_BINARY_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
1640   PetscFunctionReturn(viewer);
1641 }
1642