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