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