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