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