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