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