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