xref: /petsc/src/dm/impls/plex/hdf5/plexhdf5.c (revision 42e5ec60e3f6d3f21d92afbe12a337913bc9ad72)
1 #include <petsc/private/dmpleximpl.h> /*I      "petscdmplex.h"   I*/
2 #include <petsc/private/isimpl.h>
3 #include <petsc/private/vecimpl.h>
4 #include <petsc/private/viewerhdf5impl.h>
5 #include <petsclayouthdf5.h>
6 
7 /* Logging support */
8 PetscLogEvent DMPLEX_DistributionView, DMPLEX_DistributionLoad;
9 
10 static PetscErrorCode PetscViewerParseVersion_Private(PetscViewer, const char[], DMPlexStorageVersion *);
11 static PetscErrorCode PetscViewerCheckVersion_Private(PetscViewer, DMPlexStorageVersion);
12 static PetscErrorCode PetscViewerAttachVersion_Private(PetscViewer, const char[], DMPlexStorageVersion);
13 static PetscErrorCode PetscViewerGetAttachedVersion_Private(PetscViewer, const char[], DMPlexStorageVersion *);
14 
15 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
16 
17 static PetscErrorCode PetscViewerPrintVersion_Private(PetscViewer viewer, DMPlexStorageVersion version, char str[], size_t len)
18 {
19   PetscFunctionBegin;
20   PetscCall(PetscViewerCheckVersion_Private(viewer, version));
21   PetscCall(PetscSNPrintf(str, len, "%d.%d.%d", version->major, version->minor, version->subminor));
22   PetscFunctionReturn(PETSC_SUCCESS);
23 }
24 
25 static PetscErrorCode PetscViewerParseVersion_Private(PetscViewer viewer, const char str[], DMPlexStorageVersion *version)
26 {
27   PetscToken           t;
28   char                *ts;
29   PetscInt             i;
30   PetscInt             ti[3];
31   DMPlexStorageVersion v;
32 
33   PetscFunctionBegin;
34   PetscCall(PetscTokenCreate(str, '.', &t));
35   for (i = 0; i < 3; i++) {
36     PetscCall(PetscTokenFind(t, &ts));
37     PetscCheck(ts, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONG, "Malformed version string %s", str);
38     PetscCall(PetscOptionsStringToInt(ts, &ti[i]));
39   }
40   PetscCall(PetscTokenFind(t, &ts));
41   PetscCheck(!ts, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONG, "Malformed version string %s", str);
42   PetscCall(PetscTokenDestroy(&t));
43   PetscCall(PetscNew(&v));
44   v->major    = (int)ti[0];
45   v->minor    = (int)ti[1];
46   v->subminor = (int)ti[2];
47   PetscCall(PetscViewerCheckVersion_Private(viewer, v));
48   *version = v;
49   PetscFunctionReturn(PETSC_SUCCESS);
50 }
51 
52 static PetscErrorCode PetscViewerAttachVersion_Private(PetscViewer viewer, const char key[], DMPlexStorageVersion v)
53 {
54   PetscFunctionBegin;
55   PetscCall(PetscObjectContainerCompose((PetscObject)viewer, key, v, PetscCtxDestroyDefault));
56   PetscFunctionReturn(PETSC_SUCCESS);
57 }
58 
59 static PetscErrorCode PetscViewerGetAttachedVersion_Private(PetscViewer viewer, const char key[], DMPlexStorageVersion *v)
60 {
61   PetscContainer cont;
62 
63   PetscFunctionBegin;
64   PetscCall(PetscObjectQuery((PetscObject)viewer, key, (PetscObject *)&cont));
65   *v = NULL;
66   if (cont) PetscCall(PetscContainerGetPointer(cont, (void **)v));
67   PetscFunctionReturn(PETSC_SUCCESS);
68 }
69 
70 /*
71   Version log:
72   1.0.0 legacy version (default if no "dmplex_storage_version" attribute found in file)
73   1.1.0 legacy version, but output VIZ by default
74   2.0.0 introduce versioning and multiple topologies
75   2.1.0 introduce distributions
76   3.0.0 new checkpointing format in Firedrake paper
77   3.1.0 new format with IS compression
78 */
79 static PetscErrorCode PetscViewerCheckVersion_Private(PetscViewer viewer, DMPlexStorageVersion version)
80 {
81   PetscBool valid = PETSC_FALSE;
82 
83   PetscFunctionBegin;
84   switch (version->major) {
85   case 1:
86     switch (version->minor) {
87     case 0:
88       switch (version->subminor) {
89       case 0:
90         valid = PETSC_TRUE;
91         break;
92       }
93       break;
94     case 1:
95       switch (version->subminor) {
96       case 0:
97         valid = PETSC_TRUE;
98         break;
99       }
100       break;
101     }
102     break;
103   case 2:
104     switch (version->minor) {
105     case 0:
106       switch (version->subminor) {
107       case 0:
108         valid = PETSC_TRUE;
109         break;
110       }
111       break;
112     case 1:
113       switch (version->subminor) {
114       case 0:
115         valid = PETSC_TRUE;
116         break;
117       }
118       break;
119     }
120     break;
121   case 3:
122     switch (version->minor) {
123     case 0:
124       switch (version->subminor) {
125       case 0:
126         valid = PETSC_TRUE;
127         break;
128       }
129       break;
130     case 1:
131       switch (version->subminor) {
132       case 0:
133         valid = PETSC_TRUE;
134         break;
135       }
136       break;
137     }
138     break;
139   }
140   PetscCheck(valid, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "DMPlexStorageVersion %d.%d.%d not supported", version->major, version->minor, version->subminor);
141   PetscFunctionReturn(PETSC_SUCCESS);
142 }
143 
144 static inline PetscBool DMPlexStorageVersionEQ(DMPlexStorageVersion version, int major, int minor, int subminor)
145 {
146   return (PetscBool)(version->major == major && version->minor == minor && version->subminor == subminor);
147 }
148 
149 static inline PetscBool DMPlexStorageVersionGE(DMPlexStorageVersion version, int major, int minor, int subminor)
150 {
151   return (PetscBool)((version->major == major && version->minor == minor && version->subminor >= subminor) || (version->major == major && version->minor > minor) || (version->major > major));
152 }
153 
154 /*@C
155   PetscViewerHDF5SetDMPlexStorageVersionWriting - Set the storage version for writing
156 
157   Logically collective
158 
159   Input Parameters:
160 + viewer  - The `PetscViewer`
161 - version - The storage format version
162 
163   Level: advanced
164 
165   Note:
166   The version has major, minor, and subminor integers. Parallel operations are only available for version 3.0.0.
167 
168 .seealso: [](ch_dmbase), `DM`, `PetscViewerHDF5GetDMPlexStorageVersionWriting()`, `PetscViewerHDF5GetDMPlexStorageVersionReading()`, `PetscViewerHDF5SetDMPlexStorageVersionReading()`
169 @*/
170 PetscErrorCode PetscViewerHDF5SetDMPlexStorageVersionWriting(PetscViewer viewer, DMPlexStorageVersion version)
171 {
172   const char           ATTR_NAME[] = "dmplex_storage_version";
173   DMPlexStorageVersion viewerVersion;
174   PetscBool            fileHasVersion;
175   char                 fileVersion[16], versionStr[16], viewerVersionStr[16];
176 
177   PetscFunctionBegin;
178   PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 1, PETSCVIEWERHDF5);
179   PetscAssertPointer(version, 2);
180   PetscCall(PetscViewerPrintVersion_Private(viewer, version, versionStr, 16));
181   PetscCall(PetscViewerGetAttachedVersion_Private(viewer, DMPLEX_STORAGE_VERSION_WRITING_KEY, &viewerVersion));
182   if (viewerVersion) {
183     PetscBool flg;
184 
185     PetscCall(PetscViewerPrintVersion_Private(viewer, viewerVersion, viewerVersionStr, 16));
186     PetscCall(PetscStrcmp(versionStr, viewerVersionStr, &flg));
187     PetscCheck(flg, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "User requested DMPlex storage version %s but viewer already has version %s - cannot mix versions", versionStr, viewerVersionStr);
188   }
189 
190   PetscCall(PetscViewerHDF5HasAttribute(viewer, NULL, ATTR_NAME, &fileHasVersion));
191   if (fileHasVersion) {
192     PetscBool flg;
193     char     *tmp;
194 
195     PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", ATTR_NAME, PETSC_STRING, NULL, &tmp));
196     PetscCall(PetscStrncpy(fileVersion, tmp, sizeof(fileVersion)));
197     PetscCall(PetscFree(tmp));
198     PetscCall(PetscStrcmp(fileVersion, versionStr, &flg));
199     PetscCheck(flg, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "User requested DMPlex storage version %s but file already has version %s - cannot mix versions", versionStr, fileVersion);
200   } else {
201     PetscCall(PetscViewerHDF5WriteAttribute(viewer, "/", ATTR_NAME, PETSC_STRING, versionStr));
202   }
203   PetscCall(PetscNew(&viewerVersion));
204   viewerVersion->major    = version->major;
205   viewerVersion->minor    = version->minor;
206   viewerVersion->subminor = version->subminor;
207   PetscCall(PetscViewerAttachVersion_Private(viewer, DMPLEX_STORAGE_VERSION_WRITING_KEY, viewerVersion));
208   PetscFunctionReturn(PETSC_SUCCESS);
209 }
210 
211 /*@C
212   PetscViewerHDF5GetDMPlexStorageVersionWriting - Get the storage version for writing
213 
214   Logically collective
215 
216   Input Parameter:
217 . viewer - The `PetscViewer`
218 
219   Output Parameter:
220 . version - The storage format version
221 
222   Options Database Keys:
223 . -dm_plex_view_hdf5_storage_version <num> - Overrides the storage format version
224 
225   Level: advanced
226 
227   Note:
228   The version has major, minor, and subminor integers. Parallel operations are only available for version 3.0.0.
229 
230 .seealso: [](ch_dmbase), `DM`, `PetscViewerHDF5SetDMPlexStorageVersionWriting()`, `PetscViewerHDF5GetDMPlexStorageVersionReading()`, `PetscViewerHDF5SetDMPlexStorageVersionReading()`
231 @*/
232 PetscErrorCode PetscViewerHDF5GetDMPlexStorageVersionWriting(PetscViewer viewer, DMPlexStorageVersion *version)
233 {
234   const char ATTR_NAME[] = "dmplex_storage_version";
235   PetscBool  fileHasVersion;
236   char       optVersion[16], fileVersion[16];
237 
238   PetscFunctionBegin;
239   PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 1, PETSCVIEWERHDF5);
240   PetscAssertPointer(version, 2);
241   PetscCall(PetscViewerGetAttachedVersion_Private(viewer, DMPLEX_STORAGE_VERSION_WRITING_KEY, version));
242   if (*version) PetscFunctionReturn(PETSC_SUCCESS);
243 
244   PetscCall(PetscStrncpy(fileVersion, DMPLEX_STORAGE_VERSION_STABLE, sizeof(fileVersion)));
245   PetscCall(PetscViewerHDF5HasAttribute(viewer, NULL, ATTR_NAME, &fileHasVersion));
246   if (fileHasVersion) {
247     char *tmp;
248 
249     PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", ATTR_NAME, PETSC_STRING, NULL, &tmp));
250     PetscCall(PetscStrncpy(fileVersion, tmp, sizeof(fileVersion)));
251     PetscCall(PetscFree(tmp));
252   }
253   PetscCall(PetscStrncpy(optVersion, fileVersion, sizeof(optVersion)));
254   PetscObjectOptionsBegin((PetscObject)viewer);
255   PetscCall(PetscOptionsString("-dm_plex_view_hdf5_storage_version", "DMPlex HDF5 viewer storage version", NULL, optVersion, optVersion, sizeof(optVersion), NULL));
256   PetscOptionsEnd();
257   if (!fileHasVersion) {
258     PetscCall(PetscViewerHDF5WriteAttribute(viewer, "/", ATTR_NAME, PETSC_STRING, optVersion));
259   } else {
260     PetscBool flg;
261 
262     PetscCall(PetscStrcmp(fileVersion, optVersion, &flg));
263     PetscCheck(flg, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "User requested DMPlex storage version %s but file already has version %s - cannot mix versions", optVersion, fileVersion);
264   }
265   PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "petsc_version_git", PETSC_STRING, PETSC_VERSION_GIT));
266   PetscCall(PetscViewerParseVersion_Private(viewer, optVersion, version));
267   PetscCall(PetscViewerAttachVersion_Private(viewer, DMPLEX_STORAGE_VERSION_WRITING_KEY, *version));
268   PetscFunctionReturn(PETSC_SUCCESS);
269 }
270 
271 /*@C
272   PetscViewerHDF5SetDMPlexStorageVersionReading - Set the storage version for reading
273 
274   Logically collective
275 
276   Input Parameters:
277 + viewer  - The `PetscViewer`
278 - version - The storage format version
279 
280   Level: advanced
281 
282   Note:
283   The version has major, minor, and subminor integers. Parallel operations are only available for version 3.0.0.
284 
285 .seealso: [](ch_dmbase), `DM`, `PetscViewerHDF5GetDMPlexStorageVersionReading()`, `PetscViewerHDF5GetDMPlexStorageVersionWriting()`, `PetscViewerHDF5SetDMPlexStorageVersionWriting()`
286 @*/
287 PetscErrorCode PetscViewerHDF5SetDMPlexStorageVersionReading(PetscViewer viewer, DMPlexStorageVersion version)
288 {
289   const char           ATTR_NAME[] = "dmplex_storage_version";
290   DMPlexStorageVersion viewerVersion;
291   PetscBool            fileHasVersion;
292   char                 versionStr[16], viewerVersionStr[16];
293 
294   PetscFunctionBegin;
295   PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 1, PETSCVIEWERHDF5);
296   PetscAssertPointer(version, 2);
297   PetscCall(PetscViewerPrintVersion_Private(viewer, version, versionStr, 16));
298   PetscCall(PetscViewerGetAttachedVersion_Private(viewer, DMPLEX_STORAGE_VERSION_READING_KEY, &viewerVersion));
299   if (viewerVersion) {
300     PetscBool flg;
301 
302     PetscCall(PetscViewerPrintVersion_Private(viewer, viewerVersion, viewerVersionStr, 16));
303     PetscCall(PetscStrcmp(versionStr, viewerVersionStr, &flg));
304     PetscCheck(flg, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "User requested DMPlex storage version %s but viewer already has version %s - cannot mix versions", versionStr, viewerVersionStr);
305   }
306 
307   PetscCall(PetscViewerHDF5HasAttribute(viewer, NULL, ATTR_NAME, &fileHasVersion));
308   if (fileHasVersion) {
309     char     *fileVersion;
310     PetscBool flg;
311 
312     PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", ATTR_NAME, PETSC_STRING, NULL, &fileVersion));
313     PetscCall(PetscStrcmp(fileVersion, versionStr, &flg));
314     PetscCheck(flg, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "User requested DMPlex storage version %s but file already has version %s - cannot mix versions", versionStr, fileVersion);
315     PetscCall(PetscFree(fileVersion));
316   }
317   PetscCall(PetscNew(&viewerVersion));
318   viewerVersion->major    = version->major;
319   viewerVersion->minor    = version->minor;
320   viewerVersion->subminor = version->subminor;
321   PetscCall(PetscViewerAttachVersion_Private(viewer, DMPLEX_STORAGE_VERSION_READING_KEY, viewerVersion));
322   PetscFunctionReturn(PETSC_SUCCESS);
323 }
324 
325 /*@C
326   PetscViewerHDF5GetDMPlexStorageVersionReading - Get the storage version for reading
327 
328   Logically collective
329 
330   Input Parameter:
331 . viewer - The `PetscViewer`
332 
333   Output Parameter:
334 . version - The storage format version
335 
336   Options Database Keys:
337 . -dm_plex_view_hdf5_storage_version <num> - Overrides the storage format version
338 
339   Level: advanced
340 
341   Note:
342   The version has major, minor, and subminor integers. Parallel operations are only available for version 3.0.0.
343 
344 .seealso: [](ch_dmbase), `DM`, `PetscViewerHDF5SetDMPlexStorageVersionReading()`, `PetscViewerHDF5GetDMPlexStorageVersionWriting()`, `PetscViewerHDF5SetDMPlexStorageVersionWriting()`
345 @*/
346 PetscErrorCode PetscViewerHDF5GetDMPlexStorageVersionReading(PetscViewer viewer, DMPlexStorageVersion *version)
347 {
348   const char ATTR_NAME[] = "dmplex_storage_version";
349   char      *defaultVersion;
350   char      *versionString;
351 
352   PetscFunctionBegin;
353   PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 1, PETSCVIEWERHDF5);
354   PetscAssertPointer(version, 2);
355   PetscCall(PetscViewerGetAttachedVersion_Private(viewer, DMPLEX_STORAGE_VERSION_READING_KEY, version));
356   if (*version) PetscFunctionReturn(PETSC_SUCCESS);
357 
358   //TODO string HDF5 attribute handling is terrible and should be redesigned
359   PetscCall(PetscStrallocpy(DMPLEX_STORAGE_VERSION_FIRST, &defaultVersion));
360   PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", ATTR_NAME, PETSC_STRING, &defaultVersion, &versionString));
361   PetscCall(PetscViewerParseVersion_Private(viewer, versionString, version));
362   PetscCall(PetscViewerAttachVersion_Private(viewer, DMPLEX_STORAGE_VERSION_READING_KEY, *version));
363   PetscCall(PetscFree(versionString));
364   PetscCall(PetscFree(defaultVersion));
365   PetscFunctionReturn(PETSC_SUCCESS);
366 }
367 
368 static PetscErrorCode DMPlexGetHDF5Name_Private(DM dm, const char *name[])
369 {
370   PetscFunctionBegin;
371   if (((PetscObject)dm)->name) {
372     PetscCall(PetscObjectGetName((PetscObject)dm, name));
373   } else {
374     *name = "plex";
375   }
376   PetscFunctionReturn(PETSC_SUCCESS);
377 }
378 
379 PetscErrorCode DMSequenceGetLength_HDF5_Internal(DM dm, const char seqname[], PetscInt *seqlen, PetscViewer viewer)
380 {
381   hid_t     file, group, dset, dspace;
382   hsize_t   rdim, *dims;
383   char     *groupname;
384   PetscBool has;
385 
386   PetscFunctionBegin;
387   PetscCall(PetscViewerHDF5GetGroup(viewer, NULL, &groupname));
388   PetscCall(PetscViewerHDF5HasDataset(viewer, seqname, &has));
389   PetscCheck(has, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Object (dataset) \"%s\" not stored in group %s", seqname, groupname);
390 
391   PetscCall(PetscViewerHDF5OpenGroup(viewer, NULL, &file, &group));
392   PetscCallHDF5Return(dset, H5Dopen2, (group, seqname, H5P_DEFAULT));
393   PetscCallHDF5Return(dspace, H5Dget_space, (dset));
394   PetscCallHDF5ReturnNoCheck(rdim, H5Sget_simple_extent_dims, (dspace, NULL, NULL));
395   PetscCall(PetscMalloc1(rdim, &dims));
396   PetscCallHDF5ReturnNoCheck(rdim, H5Sget_simple_extent_dims, (dspace, dims, NULL));
397   *seqlen = (PetscInt)dims[0];
398   PetscCall(PetscFree(dims));
399   PetscCallHDF5(H5Dclose, (dset));
400   PetscCallHDF5(H5Gclose, (group));
401   PetscFunctionReturn(PETSC_SUCCESS);
402 }
403 
404 static PetscErrorCode DMSequenceView_HDF5(DM dm, const char seqname[], PetscInt seqnum, PetscScalar value, PetscViewer viewer)
405 {
406   Vec         stamp;
407   PetscMPIInt rank;
408 
409   PetscFunctionBegin;
410   if (seqnum < 0) PetscFunctionReturn(PETSC_SUCCESS);
411   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
412   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)viewer), rank ? 0 : 1, 1, &stamp));
413   PetscCall(VecSetBlockSize(stamp, 1));
414   PetscCall(PetscObjectSetName((PetscObject)stamp, seqname));
415   if (rank == 0) {
416     PetscReal timeScale;
417     PetscBool istime;
418 
419     PetscCall(PetscStrncmp(seqname, "time", 5, &istime));
420     if (istime) {
421       PetscCall(DMPlexGetScale(dm, PETSC_UNIT_TIME, &timeScale));
422       value *= timeScale;
423     }
424     PetscCall(VecSetValue(stamp, 0, value, INSERT_VALUES));
425   }
426   PetscCall(VecAssemblyBegin(stamp));
427   PetscCall(VecAssemblyEnd(stamp));
428   PetscCall(PetscViewerHDF5PushGroup(viewer, "/"));
429   PetscCall(PetscViewerHDF5PushTimestepping(viewer));
430   PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum)); /* seqnum < 0 jumps out above */
431   PetscCall(VecView(stamp, viewer));
432   PetscCall(PetscViewerHDF5PopTimestepping(viewer));
433   PetscCall(PetscViewerHDF5PopGroup(viewer));
434   PetscCall(VecDestroy(&stamp));
435   PetscFunctionReturn(PETSC_SUCCESS);
436 }
437 
438 PetscErrorCode DMSequenceLoad_HDF5_Internal(DM dm, const char seqname[], PetscInt seqnum, PetscScalar *value, PetscViewer viewer)
439 {
440   Vec         stamp;
441   PetscMPIInt rank;
442 
443   PetscFunctionBegin;
444   if (seqnum < 0) PetscFunctionReturn(PETSC_SUCCESS);
445   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
446   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)viewer), rank ? 0 : 1, 1, &stamp));
447   PetscCall(VecSetBlockSize(stamp, 1));
448   PetscCall(PetscObjectSetName((PetscObject)stamp, seqname));
449   PetscCall(PetscViewerHDF5PushGroup(viewer, "/"));
450   PetscCall(PetscViewerHDF5PushTimestepping(viewer));
451   PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum)); /* seqnum < 0 jumps out above */
452   PetscCall(VecLoad(stamp, viewer));
453   PetscCall(PetscViewerHDF5PopTimestepping(viewer));
454   PetscCall(PetscViewerHDF5PopGroup(viewer));
455   if (rank == 0) {
456     const PetscScalar *a;
457     PetscReal          timeScale;
458     PetscBool          istime;
459 
460     PetscCall(VecGetArrayRead(stamp, &a));
461     *value = a[0];
462     PetscCall(VecRestoreArrayRead(stamp, &a));
463     PetscCall(PetscStrncmp(seqname, "time", 5, &istime));
464     if (istime) {
465       PetscCall(DMPlexGetScale(dm, PETSC_UNIT_TIME, &timeScale));
466       *value /= timeScale;
467     }
468   }
469   PetscCall(VecDestroy(&stamp));
470   PetscFunctionReturn(PETSC_SUCCESS);
471 }
472 
473 static PetscErrorCode DMPlexCreateCutVertexLabel_Private(DM dm, DMLabel cutLabel, DMLabel *cutVertexLabel)
474 {
475   IS              cutcells = NULL;
476   const PetscInt *cutc;
477   PetscInt        cellHeight, vStart, vEnd, cStart, cEnd, c;
478 
479   PetscFunctionBegin;
480   if (!cutLabel) PetscFunctionReturn(PETSC_SUCCESS);
481   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
482   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
483   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
484   /* Label vertices that should be duplicated */
485   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Cut Vertices", cutVertexLabel));
486   PetscCall(DMLabelGetStratumIS(cutLabel, 2, &cutcells));
487   if (cutcells) {
488     PetscInt n;
489 
490     PetscCall(ISGetIndices(cutcells, &cutc));
491     PetscCall(ISGetLocalSize(cutcells, &n));
492     for (c = 0; c < n; ++c) {
493       if ((cutc[c] >= cStart) && (cutc[c] < cEnd)) {
494         PetscInt *closure = NULL;
495         PetscInt  closureSize, cl, value;
496 
497         PetscCall(DMPlexGetTransitiveClosure(dm, cutc[c], PETSC_TRUE, &closureSize, &closure));
498         for (cl = 0; cl < closureSize * 2; cl += 2) {
499           if ((closure[cl] >= vStart) && (closure[cl] < vEnd)) {
500             PetscCall(DMLabelGetValue(cutLabel, closure[cl], &value));
501             if (value == 1) PetscCall(DMLabelSetValue(*cutVertexLabel, closure[cl], 1));
502           }
503         }
504         PetscCall(DMPlexRestoreTransitiveClosure(dm, cutc[c], PETSC_TRUE, &closureSize, &closure));
505       }
506     }
507     PetscCall(ISRestoreIndices(cutcells, &cutc));
508   }
509   PetscCall(ISDestroy(&cutcells));
510   PetscFunctionReturn(PETSC_SUCCESS);
511 }
512 
513 PetscErrorCode VecView_Plex_Local_HDF5_Internal(Vec v, PetscViewer viewer)
514 {
515   DMPlexStorageVersion version;
516   DM                   dm;
517   DM                   dmBC;
518   PetscSection         section, sectionGlobal;
519   Vec                  gv;
520   const char          *name;
521   PetscViewerFormat    format;
522   PetscInt             seqnum;
523   PetscReal            seqval;
524   PetscBool            isseq;
525 
526   PetscFunctionBegin;
527   PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version));
528   PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
529   PetscCall(VecGetDM(v, &dm));
530   PetscCall(DMGetLocalSection(dm, &section));
531   PetscCall(DMGetOutputSequenceNumber(dm, &seqnum, &seqval));
532   PetscCall(DMSequenceView_HDF5(dm, "time", seqnum, (PetscScalar)seqval, viewer));
533   if (seqnum >= 0) {
534     PetscCall(PetscViewerHDF5PushTimestepping(viewer));
535     PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum));
536   }
537   PetscCall(PetscViewerGetFormat(viewer, &format));
538   PetscCall(DMGetOutputDM(dm, &dmBC));
539   PetscCall(DMGetGlobalSection(dmBC, &sectionGlobal));
540   PetscCall(DMGetGlobalVector(dmBC, &gv));
541   PetscCall(PetscObjectGetName((PetscObject)v, &name));
542   PetscCall(PetscObjectSetName((PetscObject)gv, name));
543   PetscCall(DMLocalToGlobalBegin(dmBC, v, INSERT_VALUES, gv));
544   PetscCall(DMLocalToGlobalEnd(dmBC, v, INSERT_VALUES, gv));
545   PetscCall(PetscObjectTypeCompare((PetscObject)gv, VECSEQ, &isseq));
546   if (format == PETSC_VIEWER_HDF5_VIZ) {
547     /* Output visualization representation */
548     PetscInt numFields, f;
549     DMLabel  cutLabel, cutVertexLabel = NULL;
550 
551     PetscCall(PetscSectionGetNumFields(section, &numFields));
552     PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel));
553     for (f = 0; f < numFields; ++f) {
554       Vec                      subv;
555       IS                       is;
556       const char              *fname, *fgroup, *componentName, *fname_def = "unnamed";
557       char                     subname[PETSC_MAX_PATH_LEN];
558       PetscInt                 Nc, Nt = 1;
559       PetscInt                *pStart, *pEnd;
560       PetscViewerVTKFieldType *ft;
561 
562       if (DMPlexStorageVersionEQ(version, 1, 1, 0)) PetscCall(DMPlexGetFieldTypes_Internal(dm, section, f, &Nt, &pStart, &pEnd, &ft));
563       else {
564         PetscCall(PetscMalloc3(Nt, &pStart, Nt, &pEnd, Nt, &ft));
565         PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart[0], &pEnd[0], &ft[0]));
566       }
567       for (PetscInt t = 0; t < Nt; ++t) {
568         if (ft[t] == PETSC_VTK_INVALID) continue;
569         fgroup = (ft[t] == PETSC_VTK_POINT_VECTOR_FIELD) || (ft[t] == PETSC_VTK_POINT_FIELD) ? "/vertex_fields" : "/cell_fields";
570         PetscCall(PetscSectionGetFieldName(section, f, &fname));
571         if (!fname) fname = fname_def;
572 
573         if (!t) {
574           PetscCall(PetscViewerHDF5PushGroup(viewer, fgroup));
575         } else {
576           char group[PETSC_MAX_PATH_LEN];
577 
578           PetscCall(PetscSNPrintf(group, PETSC_MAX_PATH_LEN, "%s_%" PetscInt_FMT, fgroup, t));
579           PetscCall(PetscViewerHDF5PushGroup(viewer, group));
580         }
581 
582         if (cutLabel) {
583           const PetscScalar *ga;
584           PetscScalar       *suba;
585           PetscInt           gstart, subSize = 0, extSize = 0, subOff = 0, newOff = 0;
586 
587           PetscCall(DMPlexCreateCutVertexLabel_Private(dm, cutLabel, &cutVertexLabel));
588           PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
589           for (PetscInt p = pStart[t]; p < pEnd[t]; ++p) {
590             PetscInt gdof, fdof = 0, val;
591 
592             PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
593             if (gdof > 0) PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
594             subSize += fdof;
595             PetscCall(DMLabelGetValue(cutVertexLabel, p, &val));
596             if (val == 1) extSize += fdof;
597           }
598           PetscCall(VecCreate(PetscObjectComm((PetscObject)gv), &subv));
599           PetscCall(VecSetSizes(subv, subSize + extSize, PETSC_DETERMINE));
600           PetscCall(VecSetBlockSize(subv, Nc));
601           PetscCall(VecSetType(subv, VECSTANDARD));
602           PetscCall(VecGetOwnershipRange(gv, &gstart, NULL));
603           PetscCall(VecGetArrayRead(gv, &ga));
604           PetscCall(VecGetArray(subv, &suba));
605           for (PetscInt p = pStart[t]; p < pEnd[t]; ++p) {
606             PetscInt gdof, goff, val;
607 
608             PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
609             if (gdof > 0) {
610               PetscInt fdof, fc, f2, poff = 0;
611 
612               PetscCall(PetscSectionGetOffset(sectionGlobal, p, &goff));
613               /* Can get rid of this loop by storing field information in the global section */
614               for (f2 = 0; f2 < f; ++f2) {
615                 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof));
616                 poff += fdof;
617               }
618               PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
619               for (fc = 0; fc < fdof; ++fc, ++subOff) suba[subOff] = ga[goff + poff + fc - gstart];
620               PetscCall(DMLabelGetValue(cutVertexLabel, p, &val));
621               if (val == 1) {
622                 for (fc = 0; fc < fdof; ++fc, ++newOff) suba[subSize + newOff] = ga[goff + poff + fc - gstart];
623               }
624             }
625           }
626           PetscCall(VecRestoreArrayRead(gv, &ga));
627           PetscCall(VecRestoreArray(subv, &suba));
628           PetscCall(DMLabelDestroy(&cutVertexLabel));
629         } else {
630           PetscCall(PetscSectionGetField_Internal(section, sectionGlobal, gv, f, pStart[t], pEnd[t], &is, &subv));
631         }
632         PetscCall(PetscStrncpy(subname, name, sizeof(subname)));
633         PetscCall(PetscStrlcat(subname, "_", sizeof(subname)));
634         PetscCall(PetscStrlcat(subname, fname, sizeof(subname)));
635         PetscCall(PetscObjectSetName((PetscObject)subv, subname));
636         if (isseq) PetscCall(VecView_Seq(subv, viewer));
637         else PetscCall(VecView_MPI(subv, viewer));
638         if (ft[t] == PETSC_VTK_POINT_VECTOR_FIELD || ft[t] == PETSC_VTK_CELL_VECTOR_FIELD) {
639           PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)subv, "vector_field_type", PETSC_STRING, "vector"));
640         } else {
641           PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)subv, "vector_field_type", PETSC_STRING, "scalar"));
642         }
643 
644         /* Output the component names in the field if available */
645         PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
646         for (PetscInt c = 0; c < Nc; ++c) {
647           char componentNameLabel[PETSC_MAX_PATH_LEN];
648           PetscCall(PetscSectionGetComponentName(section, f, c, &componentName));
649           PetscCall(PetscSNPrintf(componentNameLabel, sizeof(componentNameLabel), "componentName%" PetscInt_FMT, c));
650           PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)subv, componentNameLabel, PETSC_STRING, componentName));
651         }
652 
653         if (cutLabel) PetscCall(VecDestroy(&subv));
654         else PetscCall(PetscSectionRestoreField_Internal(section, sectionGlobal, gv, f, pStart[t], pEnd[t], &is, &subv));
655         PetscCall(PetscViewerHDF5PopGroup(viewer));
656       }
657       if (!DMPlexStorageVersionEQ(version, 1, 1, 0)) PetscCall(PetscFree3(pStart, pEnd, ft));
658     }
659   } else {
660     /* Output full vector */
661     PetscCall(PetscViewerHDF5PushGroup(viewer, "/fields"));
662     if (isseq) PetscCall(VecView_Seq(gv, viewer));
663     else PetscCall(VecView_MPI(gv, viewer));
664     PetscCall(PetscViewerHDF5PopGroup(viewer));
665   }
666   if (seqnum >= 0) PetscCall(PetscViewerHDF5PopTimestepping(viewer));
667   PetscCall(DMRestoreGlobalVector(dmBC, &gv));
668   PetscFunctionReturn(PETSC_SUCCESS);
669 }
670 
671 PetscErrorCode VecView_Plex_HDF5_Internal(Vec v, PetscViewer viewer)
672 {
673   DMPlexStorageVersion version;
674   DM                   dm;
675   Vec                  locv;
676   PetscObject          isZero;
677   const char          *name;
678   PetscReal            time;
679 
680   PetscFunctionBegin;
681   PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version));
682   PetscCall(PetscInfo(v, "Writing Vec %s storage version %d.%d.%d\n", v->hdr.name, version->major, version->minor, version->subminor));
683 
684   PetscCall(VecGetDM(v, &dm));
685   PetscCall(DMGetLocalVector(dm, &locv));
686   PetscCall(PetscObjectGetName((PetscObject)v, &name));
687   PetscCall(PetscObjectSetName((PetscObject)locv, name));
688   PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
689   PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
690   PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv));
691   PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv));
692   PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
693   PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL));
694   PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer));
695   if (DMPlexStorageVersionEQ(version, 1, 1, 0)) {
696     PetscCall(PetscViewerHDF5PushGroup(viewer, "/fields"));
697     PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ));
698     PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer));
699     PetscCall(PetscViewerPopFormat(viewer));
700     PetscCall(PetscViewerHDF5PopGroup(viewer));
701   }
702   PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
703   PetscCall(DMRestoreLocalVector(dm, &locv));
704   PetscFunctionReturn(PETSC_SUCCESS);
705 }
706 
707 PetscErrorCode VecView_Plex_HDF5_Native_Internal(Vec v, PetscViewer viewer)
708 {
709   PetscBool isseq;
710 
711   PetscFunctionBegin;
712   PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
713   PetscCall(PetscViewerHDF5PushGroup(viewer, "/fields"));
714   if (isseq) PetscCall(VecView_Seq(v, viewer));
715   else PetscCall(VecView_MPI(v, viewer));
716   PetscCall(PetscViewerHDF5PopGroup(viewer));
717   PetscFunctionReturn(PETSC_SUCCESS);
718 }
719 
720 PetscErrorCode VecLoad_Plex_HDF5_Internal(Vec v, PetscViewer viewer)
721 {
722   DM          dm;
723   Vec         locv;
724   const char *name;
725   PetscInt    seqnum;
726 
727   PetscFunctionBegin;
728   PetscCall(VecGetDM(v, &dm));
729   PetscCall(DMGetLocalVector(dm, &locv));
730   PetscCall(PetscObjectGetName((PetscObject)v, &name));
731   PetscCall(PetscObjectSetName((PetscObject)locv, name));
732   PetscCall(DMGetOutputSequenceNumber(dm, &seqnum, NULL));
733   PetscCall(PetscViewerHDF5PushGroup(viewer, "/fields"));
734   if (seqnum >= 0) {
735     PetscCall(PetscViewerHDF5PushTimestepping(viewer));
736     PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum));
737   }
738   PetscCall(VecLoad_Plex_Local(locv, viewer));
739   if (seqnum >= 0) PetscCall(PetscViewerHDF5PopTimestepping(viewer));
740   PetscCall(PetscViewerHDF5PopGroup(viewer));
741   PetscCall(DMLocalToGlobalBegin(dm, locv, INSERT_VALUES, v));
742   PetscCall(DMLocalToGlobalEnd(dm, locv, INSERT_VALUES, v));
743   PetscCall(DMRestoreLocalVector(dm, &locv));
744   PetscFunctionReturn(PETSC_SUCCESS);
745 }
746 
747 PetscErrorCode VecLoad_Plex_HDF5_Native_Internal(Vec v, PetscViewer viewer)
748 {
749   DM       dm;
750   PetscInt seqnum;
751 
752   PetscFunctionBegin;
753   PetscCall(VecGetDM(v, &dm));
754   PetscCall(DMGetOutputSequenceNumber(dm, &seqnum, NULL));
755   PetscCall(PetscViewerHDF5PushGroup(viewer, "/fields"));
756   if (seqnum >= 0) {
757     PetscCall(PetscViewerHDF5PushTimestepping(viewer));
758     PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum));
759   }
760   PetscCall(VecLoad_Default(v, viewer));
761   if (seqnum >= 0) PetscCall(PetscViewerHDF5PopTimestepping(viewer));
762   PetscCall(PetscViewerHDF5PopGroup(viewer));
763   PetscFunctionReturn(PETSC_SUCCESS);
764 }
765 
766 static PetscErrorCode DMPlexDistributionView_HDF5_Private(DM dm, IS globalPointNumbers, PetscViewer viewer)
767 {
768   DMPlexStorageVersion version;
769   MPI_Comm             comm;
770   PetscMPIInt          size, rank;
771   PetscInt             size_petsc_int;
772   const char          *topologydm_name, *distribution_name;
773   const PetscInt      *gpoint;
774   PetscInt             pStart, pEnd, p;
775   PetscSF              pointSF;
776   PetscInt             nroots, nleaves;
777   const PetscInt      *ilocal;
778   const PetscSFNode   *iremote;
779   IS                   chartSizesIS, ownersIS, gpointsIS;
780   PetscInt            *chartSize, *owners, *gpoints;
781 
782   PetscFunctionBegin;
783   PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version));
784   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
785   PetscCallMPI(MPI_Comm_size(comm, &size));
786   PetscCallMPI(MPI_Comm_rank(comm, &rank));
787   PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name));
788   PetscCall(DMPlexDistributionGetName(dm, &distribution_name));
789   if (!distribution_name) PetscFunctionReturn(PETSC_SUCCESS);
790   PetscCall(PetscLogEventBegin(DMPLEX_DistributionView, viewer, 0, 0, 0));
791   size_petsc_int = (PetscInt)size;
792   PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "comm_size", PETSC_INT, (void *)&size_petsc_int));
793   PetscCall(ISGetIndices(globalPointNumbers, &gpoint));
794   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
795   PetscCall(PetscMalloc1(1, &chartSize));
796   *chartSize = pEnd - pStart;
797   PetscCall(PetscMalloc1(*chartSize, &owners));
798   PetscCall(PetscMalloc1(*chartSize, &gpoints));
799   PetscCall(DMGetPointSF(dm, &pointSF));
800   PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &ilocal, &iremote));
801   for (p = pStart; p < pEnd; ++p) {
802     PetscInt gp = gpoint[p - pStart];
803 
804     owners[p - pStart]  = rank;
805     gpoints[p - pStart] = (gp < 0 ? -(gp + 1) : gp);
806   }
807   for (p = 0; p < nleaves; ++p) {
808     PetscInt ilocalp = (ilocal ? ilocal[p] : p);
809 
810     owners[ilocalp] = iremote[p].rank;
811   }
812   PetscCall(ISCreateGeneral(comm, 1, chartSize, PETSC_OWN_POINTER, &chartSizesIS));
813   PetscCall(ISCreateGeneral(comm, *chartSize, owners, PETSC_OWN_POINTER, &ownersIS));
814   PetscCall(ISCreateGeneral(comm, *chartSize, gpoints, PETSC_OWN_POINTER, &gpointsIS));
815   if (DMPlexStorageVersionGE(version, 3, 1, 0)) {
816     PetscCall(ISSetCompressOutput(chartSizesIS, PETSC_TRUE));
817     PetscCall(ISSetCompressOutput(ownersIS, PETSC_TRUE));
818     PetscCall(ISSetCompressOutput(gpointsIS, PETSC_TRUE));
819   }
820   PetscCall(PetscObjectSetName((PetscObject)chartSizesIS, "chart_sizes"));
821   PetscCall(PetscObjectSetName((PetscObject)ownersIS, "owners"));
822   PetscCall(PetscObjectSetName((PetscObject)gpointsIS, "global_point_numbers"));
823   PetscCall(ISView(chartSizesIS, viewer));
824   PetscCall(ISView(ownersIS, viewer));
825   PetscCall(ISView(gpointsIS, viewer));
826   PetscCall(ISDestroy(&chartSizesIS));
827   PetscCall(ISDestroy(&ownersIS));
828   PetscCall(ISDestroy(&gpointsIS));
829   PetscCall(ISRestoreIndices(globalPointNumbers, &gpoint));
830   PetscCall(PetscLogEventEnd(DMPLEX_DistributionView, viewer, 0, 0, 0));
831   PetscFunctionReturn(PETSC_SUCCESS);
832 }
833 
834 static PetscErrorCode DMPlexTopologyView_HDF5_Inner_Private(DM dm, IS globalPointNumbers, PetscViewer viewer, PetscInt pStart, PetscInt pEnd, const char pointsName[], const char coneSizesName[], const char conesName[], const char orientationsName[])
835 {
836   DMPlexStorageVersion version;
837   IS                   coneSizesIS, conesIS, orientationsIS;
838   PetscInt            *coneSizes, *cones, *orientations;
839   const PetscInt      *gpoint;
840   PetscInt             nPoints = 0, conesSize = 0;
841   PetscInt             p, c, s;
842   MPI_Comm             comm;
843 
844   PetscFunctionBegin;
845   PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version));
846   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
847   PetscCall(ISGetIndices(globalPointNumbers, &gpoint));
848   for (p = pStart; p < pEnd; ++p) {
849     if (gpoint[p] >= 0) {
850       PetscInt coneSize;
851 
852       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
853       nPoints += 1;
854       conesSize += coneSize;
855     }
856   }
857   PetscCall(PetscMalloc1(nPoints, &coneSizes));
858   PetscCall(PetscMalloc1(conesSize, &cones));
859   PetscCall(PetscMalloc1(conesSize, &orientations));
860   for (p = pStart, c = 0, s = 0; p < pEnd; ++p) {
861     if (gpoint[p] >= 0) {
862       const PetscInt *cone, *ornt;
863       PetscInt        coneSize, cp;
864 
865       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
866       PetscCall(DMPlexGetCone(dm, p, &cone));
867       PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
868       coneSizes[s] = coneSize;
869       for (cp = 0; cp < coneSize; ++cp, ++c) {
870         cones[c]        = gpoint[cone[cp]] < 0 ? -(gpoint[cone[cp]] + 1) : gpoint[cone[cp]];
871         orientations[c] = ornt[cp];
872       }
873       ++s;
874     }
875   }
876   PetscCheck(s == nPoints, PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of points %" PetscInt_FMT " != %" PetscInt_FMT, s, nPoints);
877   PetscCheck(c == conesSize, PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of cone points %" PetscInt_FMT " != %" PetscInt_FMT, c, conesSize);
878   PetscCall(ISCreateGeneral(comm, nPoints, coneSizes, PETSC_OWN_POINTER, &coneSizesIS));
879   PetscCall(ISCreateGeneral(comm, conesSize, cones, PETSC_OWN_POINTER, &conesIS));
880   PetscCall(ISCreateGeneral(comm, conesSize, orientations, PETSC_OWN_POINTER, &orientationsIS));
881   PetscCall(PetscObjectSetName((PetscObject)coneSizesIS, coneSizesName));
882   PetscCall(PetscObjectSetName((PetscObject)conesIS, conesName));
883   PetscCall(PetscObjectSetName((PetscObject)orientationsIS, orientationsName));
884   if (DMPlexStorageVersionGE(version, 3, 1, 0)) {
885     PetscCall(ISSetCompressOutput(coneSizesIS, PETSC_TRUE));
886     PetscCall(ISSetCompressOutput(conesIS, PETSC_TRUE));
887     PetscCall(ISSetCompressOutput(orientationsIS, PETSC_TRUE));
888   }
889   PetscCall(ISView(coneSizesIS, viewer));
890   PetscCall(ISView(conesIS, viewer));
891   PetscCall(ISView(orientationsIS, viewer));
892   PetscCall(ISDestroy(&coneSizesIS));
893   PetscCall(ISDestroy(&conesIS));
894   PetscCall(ISDestroy(&orientationsIS));
895   if (pointsName) {
896     IS        pointsIS;
897     PetscInt *points;
898 
899     PetscCall(PetscMalloc1(nPoints, &points));
900     for (p = pStart, c = 0, s = 0; p < pEnd; ++p) {
901       if (gpoint[p] >= 0) {
902         points[s] = gpoint[p];
903         ++s;
904       }
905     }
906     PetscCall(ISCreateGeneral(comm, nPoints, points, PETSC_OWN_POINTER, &pointsIS));
907     PetscCall(PetscObjectSetName((PetscObject)pointsIS, pointsName));
908     if (DMPlexStorageVersionGE(version, 3, 1, 0)) PetscCall(ISSetCompressOutput(pointsIS, PETSC_TRUE));
909     PetscCall(ISView(pointsIS, viewer));
910     PetscCall(ISDestroy(&pointsIS));
911   }
912   PetscCall(ISRestoreIndices(globalPointNumbers, &gpoint));
913   PetscFunctionReturn(PETSC_SUCCESS);
914 }
915 
916 static PetscErrorCode DMPlexTopologyView_HDF5_Legacy_Private(DM dm, IS globalPointNumbers, PetscViewer viewer)
917 {
918   const char *pointsName, *coneSizesName, *conesName, *orientationsName;
919   PetscInt    pStart, pEnd, dim;
920 
921   PetscFunctionBegin;
922   pointsName       = "order";
923   coneSizesName    = "cones";
924   conesName        = "cells";
925   orientationsName = "orientation";
926   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
927   PetscCall(DMPlexTopologyView_HDF5_Inner_Private(dm, globalPointNumbers, viewer, pStart, pEnd, pointsName, coneSizesName, conesName, orientationsName));
928   PetscCall(DMGetDimension(dm, &dim));
929   PetscCall(PetscViewerHDF5WriteAttribute(viewer, conesName, "cell_dim", PETSC_INT, (void *)&dim));
930   PetscFunctionReturn(PETSC_SUCCESS);
931 }
932 
933 //TODO get this numbering right away without needing this function
934 /* Renumber global point numbers so that they are 0-based per stratum */
935 static PetscErrorCode RenumberGlobalPointNumbersPerStratum_Private(DM dm, IS globalPointNumbers, IS *newGlobalPointNumbers, IS *strataPermutation)
936 {
937   PetscInt        d, depth, p, n;
938   PetscInt       *offsets;
939   const PetscInt *gpn;
940   PetscInt       *ngpn;
941   MPI_Comm        comm;
942 
943   PetscFunctionBegin;
944   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
945   PetscCall(ISGetLocalSize(globalPointNumbers, &n));
946   PetscCall(ISGetIndices(globalPointNumbers, &gpn));
947   PetscCall(PetscMalloc1(n, &ngpn));
948   PetscCall(DMPlexGetDepth(dm, &depth));
949   PetscCall(PetscMalloc1(depth + 1, &offsets));
950   for (d = 0; d <= depth; d++) {
951     PetscInt pStart, pEnd;
952 
953     PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
954     offsets[d] = PETSC_INT_MAX;
955     for (p = pStart; p < pEnd; p++) {
956       if (gpn[p] >= 0 && gpn[p] < offsets[d]) offsets[d] = gpn[p];
957     }
958   }
959   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, offsets, depth + 1, MPIU_INT, MPI_MIN, comm));
960   for (d = 0; d <= depth; d++) {
961     PetscInt pStart, pEnd;
962 
963     PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
964     for (p = pStart; p < pEnd; p++) ngpn[p] = gpn[p] - PetscSign(gpn[p]) * offsets[d];
965   }
966   PetscCall(ISRestoreIndices(globalPointNumbers, &gpn));
967   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)globalPointNumbers), n, ngpn, PETSC_OWN_POINTER, newGlobalPointNumbers));
968   {
969     PetscInt *perm;
970 
971     PetscCall(PetscMalloc1(depth + 1, &perm));
972     for (d = 0; d <= depth; d++) perm[d] = d;
973     PetscCall(PetscSortIntWithPermutation(depth + 1, offsets, perm));
974     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, depth + 1, perm, PETSC_OWN_POINTER, strataPermutation));
975   }
976   PetscCall(PetscFree(offsets));
977   PetscFunctionReturn(PETSC_SUCCESS);
978 }
979 
980 static PetscErrorCode DMPlexTopologyView_HDF5_Private(DM dm, IS globalPointNumbers, PetscViewer viewer)
981 {
982   IS          globalPointNumbers0, strataPermutation;
983   const char *coneSizesName, *conesName, *orientationsName;
984   PetscInt    depth, d;
985   MPI_Comm    comm;
986 
987   PetscFunctionBegin;
988   coneSizesName    = "cone_sizes";
989   conesName        = "cones";
990   orientationsName = "orientations";
991   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
992   PetscCall(DMPlexGetDepth(dm, &depth));
993   {
994     PetscInt dim;
995 
996     PetscCall(DMGetDimension(dm, &dim));
997     PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "cell_dim", PETSC_INT, &dim));
998     PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "depth", PETSC_INT, &depth));
999   }
1000 
1001   PetscCall(RenumberGlobalPointNumbersPerStratum_Private(dm, globalPointNumbers, &globalPointNumbers0, &strataPermutation));
1002   /* TODO dirty trick to save serial IS using the same parallel viewer */
1003   {
1004     IS              spOnComm;
1005     PetscInt        n   = 0, N;
1006     const PetscInt *idx = NULL;
1007     const PetscInt *old;
1008     PetscMPIInt     rank;
1009 
1010     PetscCallMPI(MPI_Comm_rank(comm, &rank));
1011     PetscCall(ISGetLocalSize(strataPermutation, &N));
1012     PetscCall(ISGetIndices(strataPermutation, &old));
1013     if (!rank) {
1014       n   = N;
1015       idx = old;
1016     }
1017     PetscCall(ISCreateGeneral(comm, n, idx, PETSC_COPY_VALUES, &spOnComm));
1018     PetscCall(ISRestoreIndices(strataPermutation, &old));
1019     PetscCall(ISDestroy(&strataPermutation));
1020     strataPermutation = spOnComm;
1021   }
1022   PetscCall(PetscObjectSetName((PetscObject)strataPermutation, "permutation"));
1023   PetscCall(ISView(strataPermutation, viewer));
1024   PetscCall(PetscViewerHDF5PushGroup(viewer, "strata"));
1025   for (d = 0; d <= depth; d++) {
1026     PetscInt pStart, pEnd;
1027     char     group[128];
1028 
1029     PetscCall(PetscSNPrintf(group, sizeof(group), "%" PetscInt_FMT, d));
1030     PetscCall(PetscViewerHDF5PushGroup(viewer, group));
1031     PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
1032     PetscCall(DMPlexTopologyView_HDF5_Inner_Private(dm, globalPointNumbers0, viewer, pStart, pEnd, NULL, coneSizesName, conesName, orientationsName));
1033     PetscCall(PetscViewerHDF5PopGroup(viewer));
1034   }
1035   PetscCall(PetscViewerHDF5PopGroup(viewer)); /* strata */
1036   PetscCall(ISDestroy(&globalPointNumbers0));
1037   PetscCall(ISDestroy(&strataPermutation));
1038   PetscFunctionReturn(PETSC_SUCCESS);
1039 }
1040 
1041 PetscErrorCode DMPlexTopologyView_HDF5_Internal(DM dm, IS globalPointNumbers, PetscViewer viewer)
1042 {
1043   DMPlexStorageVersion version;
1044   const char          *topologydm_name;
1045   char                 group[PETSC_MAX_PATH_LEN];
1046 
1047   PetscFunctionBegin;
1048   PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version));
1049   PetscCall(PetscInfo(dm, "Writing DM %s storage version %d.%d.%d\n", dm->hdr.name, version->major, version->minor, version->subminor));
1050   PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name));
1051   if (DMPlexStorageVersionGE(version, 2, 0, 0)) {
1052     PetscCall(PetscSNPrintf(group, sizeof(group), "topologies/%s", topologydm_name));
1053   } else {
1054     PetscCall(PetscStrncpy(group, "/", sizeof(group)));
1055   }
1056   PetscCall(PetscViewerHDF5PushGroup(viewer, group));
1057 
1058   PetscCall(PetscViewerHDF5PushGroup(viewer, "topology"));
1059   if (version->major < 3) {
1060     PetscCall(DMPlexTopologyView_HDF5_Legacy_Private(dm, globalPointNumbers, viewer));
1061   } else {
1062     /* since DMPlexStorageVersion 3.0.0 */
1063     PetscCall(DMPlexTopologyView_HDF5_Private(dm, globalPointNumbers, viewer));
1064   }
1065   PetscCall(PetscViewerHDF5PopGroup(viewer)); /* "topology" */
1066 
1067   if (DMPlexStorageVersionGE(version, 2, 1, 0)) {
1068     const char *distribution_name;
1069 
1070     PetscCall(DMPlexDistributionGetName(dm, &distribution_name));
1071     PetscCall(PetscViewerHDF5PushGroup(viewer, "distributions"));
1072     PetscCall(PetscViewerHDF5WriteGroup(viewer, NULL));
1073     PetscCall(PetscViewerHDF5PushGroup(viewer, distribution_name));
1074     PetscCall(DMPlexDistributionView_HDF5_Private(dm, globalPointNumbers, viewer));
1075     PetscCall(PetscViewerHDF5PopGroup(viewer)); /* distribution_name */
1076     PetscCall(PetscViewerHDF5PopGroup(viewer)); /* "distributions" */
1077   }
1078 
1079   PetscCall(PetscViewerHDF5PopGroup(viewer));
1080   PetscFunctionReturn(PETSC_SUCCESS);
1081 }
1082 
1083 static PetscErrorCode CreateConesIS_Private(DM dm, PetscInt cStart, PetscInt cEnd, IS globalCellNumbers, PetscInt *numCorners, IS *cellIS)
1084 {
1085   PetscSF         sfPoint;
1086   DMLabel         cutLabel, cutVertexLabel         = NULL;
1087   IS              globalVertexNumbers, cutvertices = NULL;
1088   const PetscInt *gcell, *gvertex, *cutverts = NULL;
1089   PetscInt       *vertices;
1090   PetscInt        conesSize = 0;
1091   PetscInt        dim, numCornersLocal = 0, cell, vStart, vEnd, vExtra = 0, v;
1092 
1093   PetscFunctionBegin;
1094   *numCorners = 0;
1095   PetscCall(DMGetDimension(dm, &dim));
1096   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1097   PetscCall(ISGetIndices(globalCellNumbers, &gcell));
1098 
1099   for (cell = cStart; cell < cEnd; ++cell) {
1100     PetscInt *closure = NULL;
1101     PetscInt  closureSize, v, Nc = 0;
1102 
1103     if (gcell[cell] < 0) continue;
1104     PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
1105     for (v = 0; v < closureSize * 2; v += 2) {
1106       if ((closure[v] >= vStart) && (closure[v] < vEnd)) ++Nc;
1107     }
1108     PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
1109     conesSize += Nc;
1110     if (!numCornersLocal) numCornersLocal = Nc;
1111     else if (numCornersLocal != Nc) numCornersLocal = 1;
1112   }
1113   PetscCallMPI(MPIU_Allreduce(&numCornersLocal, numCorners, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
1114   PetscCheck(!numCornersLocal || !(numCornersLocal != *numCorners || *numCorners == 0), PETSC_COMM_SELF, PETSC_ERR_SUP, "Visualization topology currently only supports identical cell shapes");
1115   /* Handle periodic cuts by identifying vertices which should be duplicated */
1116   PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel));
1117   PetscCall(DMPlexCreateCutVertexLabel_Private(dm, cutLabel, &cutVertexLabel));
1118   if (cutVertexLabel) PetscCall(DMLabelGetStratumIS(cutVertexLabel, 1, &cutvertices));
1119   if (cutvertices) {
1120     PetscCall(ISGetIndices(cutvertices, &cutverts));
1121     PetscCall(ISGetLocalSize(cutvertices, &vExtra));
1122   }
1123   PetscCall(DMGetPointSF(dm, &sfPoint));
1124   if (cutLabel) {
1125     const PetscInt    *ilocal;
1126     const PetscSFNode *iremote;
1127     PetscInt           nroots, nleaves;
1128 
1129     PetscCall(PetscSFGetGraph(sfPoint, &nroots, &nleaves, &ilocal, &iremote));
1130     if (nleaves < 0) {
1131       PetscCall(PetscObjectReference((PetscObject)sfPoint));
1132     } else {
1133       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)sfPoint), &sfPoint));
1134       PetscCall(PetscSFSetGraph(sfPoint, nroots + vExtra, nleaves, (PetscInt *)ilocal, PETSC_COPY_VALUES, (PetscSFNode *)iremote, PETSC_COPY_VALUES));
1135     }
1136   } else {
1137     PetscCall(PetscObjectReference((PetscObject)sfPoint));
1138   }
1139   /* Number all vertices */
1140   PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd + vExtra, 0, NULL, sfPoint, &globalVertexNumbers));
1141   PetscCall(PetscSFDestroy(&sfPoint));
1142   /* Create cones */
1143   PetscCall(ISGetIndices(globalVertexNumbers, &gvertex));
1144   PetscCall(PetscMalloc1(conesSize, &vertices));
1145   for (cell = cStart, v = 0; cell < cEnd; ++cell) {
1146     PetscInt *closure = NULL;
1147     PetscInt  closureSize, Nc = 0, p, value = -1;
1148     PetscBool replace;
1149 
1150     if (gcell[cell] < 0) continue;
1151     if (cutLabel) PetscCall(DMLabelGetValue(cutLabel, cell, &value));
1152     replace = (value == 2) ? PETSC_TRUE : PETSC_FALSE;
1153     PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
1154     for (p = 0; p < closureSize * 2; p += 2) {
1155       if ((closure[p] >= vStart) && (closure[p] < vEnd)) closure[Nc++] = closure[p];
1156     }
1157     PetscCall(DMPlexReorderCell(dm, cell, closure));
1158     for (p = 0; p < Nc; ++p) {
1159       PetscInt nv, gv = gvertex[closure[p] - vStart];
1160 
1161       if (replace) {
1162         PetscCall(PetscFindInt(closure[p], vExtra, cutverts, &nv));
1163         if (nv >= 0) gv = gvertex[vEnd - vStart + nv];
1164       }
1165       vertices[v++] = gv < 0 ? -(gv + 1) : gv;
1166     }
1167     PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
1168   }
1169   PetscCall(ISRestoreIndices(globalVertexNumbers, &gvertex));
1170   PetscCall(ISDestroy(&globalVertexNumbers));
1171   PetscCall(ISRestoreIndices(globalCellNumbers, &gcell));
1172   if (cutvertices) PetscCall(ISRestoreIndices(cutvertices, &cutverts));
1173   PetscCall(ISDestroy(&cutvertices));
1174   PetscCall(DMLabelDestroy(&cutVertexLabel));
1175   PetscCheck(v == conesSize, PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of cell vertices %" PetscInt_FMT " != %" PetscInt_FMT, v, conesSize);
1176   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), conesSize, vertices, PETSC_OWN_POINTER, cellIS));
1177   PetscCall(PetscLayoutSetBlockSize((*cellIS)->map, *numCorners));
1178   PetscCall(PetscObjectSetName((PetscObject)*cellIS, "cells"));
1179   PetscFunctionReturn(PETSC_SUCCESS);
1180 }
1181 
1182 static PetscErrorCode DMPlexTopologyView_HDF5_XDMF_Private(DM dm, IS globalCellNumbers, PetscViewer viewer)
1183 {
1184   DM       cdm;
1185   DMLabel  depthLabel, ctLabel;
1186   IS       cellIS;
1187   PetscInt dim, depth, cellHeight, c, n = 0;
1188 
1189   PetscFunctionBegin;
1190   PetscCall(PetscViewerHDF5PushGroup(viewer, "/viz"));
1191   PetscCall(PetscViewerHDF5WriteGroup(viewer, NULL));
1192 
1193   PetscCall(PetscViewerHDF5PopGroup(viewer));
1194   PetscCall(DMGetDimension(dm, &dim));
1195   PetscCall(DMPlexGetDepth(dm, &depth));
1196   PetscCall(DMGetCoordinateDM(dm, &cdm));
1197   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
1198   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
1199   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
1200   for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
1201     const DMPolytopeType ict = (DMPolytopeType)c;
1202     PetscInt             pStart, pEnd, dep, numCorners;
1203     PetscBool            output = PETSC_FALSE, doOutput;
1204 
1205     if (ict == DM_POLYTOPE_FV_GHOST) continue;
1206     PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &pStart, &pEnd));
1207     if (pStart >= 0) {
1208       PetscCall(DMLabelGetValue(depthLabel, pStart, &dep));
1209       if (dep == depth - cellHeight) output = PETSC_TRUE;
1210     }
1211     PetscCallMPI(MPIU_Allreduce(&output, &doOutput, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
1212     if (!doOutput) continue;
1213     PetscCall(CreateConesIS_Private(dm, pStart, pEnd, globalCellNumbers, &numCorners, &cellIS));
1214     if (!n) {
1215       PetscCall(PetscViewerHDF5PushGroup(viewer, "/viz/topology"));
1216     } else {
1217       char group[PETSC_MAX_PATH_LEN];
1218 
1219       PetscCall(PetscSNPrintf(group, PETSC_MAX_PATH_LEN, "/viz/topology_%" PetscInt_FMT, n));
1220       PetscCall(PetscViewerHDF5PushGroup(viewer, group));
1221     }
1222     PetscCall(ISView(cellIS, viewer));
1223     PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)cellIS, "cell_corners", PETSC_INT, (void *)&numCorners));
1224     PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)cellIS, "cell_dim", PETSC_INT, (void *)&dim));
1225     PetscCall(ISDestroy(&cellIS));
1226     PetscCall(PetscViewerHDF5PopGroup(viewer));
1227     ++n;
1228   }
1229   PetscFunctionReturn(PETSC_SUCCESS);
1230 }
1231 
1232 static PetscErrorCode DMPlexCoordinatesView_HDF5_Legacy_Private(DM dm, PetscViewer viewer)
1233 {
1234   DM        cdm;
1235   Vec       coordinates, newcoords;
1236   PetscReal lengthScale;
1237   PetscInt  m, M, bs;
1238 
1239   PetscFunctionBegin;
1240   PetscCall(DMPlexGetScale(dm, PETSC_UNIT_LENGTH, &lengthScale));
1241   PetscCall(DMGetCoordinateDM(dm, &cdm));
1242   PetscCall(DMGetCoordinates(dm, &coordinates));
1243   PetscCall(VecCreate(PetscObjectComm((PetscObject)coordinates), &newcoords));
1244   PetscCall(PetscObjectSetName((PetscObject)newcoords, "vertices"));
1245   PetscCall(VecGetSize(coordinates, &M));
1246   PetscCall(VecGetLocalSize(coordinates, &m));
1247   PetscCall(VecSetSizes(newcoords, m, M));
1248   PetscCall(VecGetBlockSize(coordinates, &bs));
1249   PetscCall(VecSetBlockSize(newcoords, bs));
1250   PetscCall(VecSetType(newcoords, VECSTANDARD));
1251   PetscCall(VecCopy(coordinates, newcoords));
1252   PetscCall(VecScale(newcoords, lengthScale));
1253   /* Did not use DMGetGlobalVector() in order to bypass default group assignment */
1254   PetscCall(PetscViewerHDF5PushGroup(viewer, "/geometry"));
1255   PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_NATIVE));
1256   PetscCall(VecView(newcoords, viewer));
1257   PetscCall(PetscViewerPopFormat(viewer));
1258   PetscCall(PetscViewerHDF5PopGroup(viewer));
1259   PetscCall(VecDestroy(&newcoords));
1260   PetscFunctionReturn(PETSC_SUCCESS);
1261 }
1262 
1263 PetscErrorCode DMPlexCoordinatesView_HDF5_Internal(DM dm, PetscViewer viewer)
1264 {
1265   DM          cdm;
1266   Vec         coords, newcoords;
1267   PetscInt    m, M, bs;
1268   PetscReal   lengthScale;
1269   PetscBool   viewSection = PETSC_TRUE;
1270   const char *topologydm_name, *coordinatedm_name, *coordinates_name;
1271 
1272   PetscFunctionBegin;
1273   {
1274     PetscViewerFormat    format;
1275     DMPlexStorageVersion version;
1276 
1277     PetscCall(PetscViewerGetFormat(viewer, &format));
1278     PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version));
1279     if (!DMPlexStorageVersionGE(version, 2, 0, 0) || format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
1280       PetscCall(DMPlexCoordinatesView_HDF5_Legacy_Private(dm, viewer));
1281       PetscFunctionReturn(PETSC_SUCCESS);
1282     }
1283   }
1284   /* since 2.0.0 */
1285   PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_view_coordinate_section", &viewSection, NULL));
1286   PetscCall(DMGetCoordinateDM(dm, &cdm));
1287   PetscCall(DMGetCoordinates(dm, &coords));
1288   PetscCall(PetscObjectGetName((PetscObject)cdm, &coordinatedm_name));
1289   PetscCall(PetscObjectGetName((PetscObject)coords, &coordinates_name));
1290   PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name));
1291   PetscCall(PetscViewerHDF5PushGroup(viewer, "topologies"));
1292   PetscCall(PetscViewerHDF5PushGroup(viewer, topologydm_name));
1293   PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "coordinateDMName", PETSC_STRING, coordinatedm_name));
1294   PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "coordinatesName", PETSC_STRING, coordinates_name));
1295   PetscCall(PetscViewerHDF5PopGroup(viewer));
1296   PetscCall(PetscViewerHDF5PopGroup(viewer));
1297   if (viewSection) PetscCall(DMPlexSectionView(dm, viewer, cdm));
1298   PetscCall(VecCreate(PetscObjectComm((PetscObject)coords), &newcoords));
1299   PetscCall(PetscObjectSetName((PetscObject)newcoords, coordinates_name));
1300   PetscCall(VecGetSize(coords, &M));
1301   PetscCall(VecGetLocalSize(coords, &m));
1302   PetscCall(VecSetSizes(newcoords, m, M));
1303   PetscCall(VecGetBlockSize(coords, &bs));
1304   PetscCall(VecSetBlockSize(newcoords, bs));
1305   PetscCall(VecSetType(newcoords, VECSTANDARD));
1306   PetscCall(VecCopy(coords, newcoords));
1307   PetscCall(DMPlexGetScale(dm, PETSC_UNIT_LENGTH, &lengthScale));
1308   PetscCall(VecScale(newcoords, lengthScale));
1309   PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_NATIVE));
1310   PetscCall(DMPlexGlobalVectorView(dm, viewer, cdm, newcoords));
1311   PetscCall(PetscViewerPopFormat(viewer));
1312   PetscCall(VecDestroy(&newcoords));
1313   PetscFunctionReturn(PETSC_SUCCESS);
1314 }
1315 
1316 static PetscErrorCode DMPlexCoordinatesView_HDF5_XDMF_Private(DM dm, PetscViewer viewer)
1317 {
1318   DM               cdm;
1319   Vec              coordinatesLocal, newcoords;
1320   PetscSection     cSection, cGlobalSection;
1321   PetscScalar     *coords, *ncoords;
1322   DMLabel          cutLabel, cutVertexLabel = NULL;
1323   const PetscReal *L;
1324   PetscReal        lengthScale;
1325   PetscInt         vStart, vEnd, v, bs, N, coordSize, dof, off, d;
1326   PetscBool        localized, embedded;
1327 
1328   PetscFunctionBegin;
1329   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1330   PetscCall(DMPlexGetScale(dm, PETSC_UNIT_LENGTH, &lengthScale));
1331   PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal));
1332   PetscCall(VecGetBlockSize(coordinatesLocal, &bs));
1333   PetscCall(DMGetCoordinatesLocalized(dm, &localized));
1334   if (localized == PETSC_FALSE) PetscFunctionReturn(PETSC_SUCCESS);
1335   PetscCall(DMGetPeriodicity(dm, NULL, NULL, &L));
1336   PetscCall(DMGetCoordinateDM(dm, &cdm));
1337   PetscCall(DMGetLocalSection(cdm, &cSection));
1338   PetscCall(DMGetGlobalSection(cdm, &cGlobalSection));
1339   PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel));
1340   N = 0;
1341 
1342   PetscCall(DMPlexCreateCutVertexLabel_Private(dm, cutLabel, &cutVertexLabel));
1343   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &newcoords));
1344   PetscCall(PetscSectionGetDof(cSection, vStart, &dof));
1345   PetscCall(PetscPrintf(PETSC_COMM_SELF, "DOF: %" PetscInt_FMT "\n", dof));
1346   embedded = (PetscBool)(L && dof == 2 && !cutLabel);
1347   if (cutVertexLabel) {
1348     PetscCall(DMLabelGetStratumSize(cutVertexLabel, 1, &v));
1349     N += dof * v;
1350   }
1351   for (v = vStart; v < vEnd; ++v) {
1352     PetscCall(PetscSectionGetDof(cGlobalSection, v, &dof));
1353     if (dof < 0) continue;
1354     if (embedded) N += dof + 1;
1355     else N += dof;
1356   }
1357   if (embedded) PetscCall(VecSetBlockSize(newcoords, bs + 1));
1358   else PetscCall(VecSetBlockSize(newcoords, bs));
1359   PetscCall(VecSetSizes(newcoords, N, PETSC_DETERMINE));
1360   PetscCall(VecSetType(newcoords, VECSTANDARD));
1361   PetscCall(VecGetArray(coordinatesLocal, &coords));
1362   PetscCall(VecGetArray(newcoords, &ncoords));
1363   coordSize = 0;
1364   for (v = vStart; v < vEnd; ++v) {
1365     PetscCall(PetscSectionGetDof(cGlobalSection, v, &dof));
1366     PetscCall(PetscSectionGetOffset(cSection, v, &off));
1367     if (dof < 0) continue;
1368     if (embedded) {
1369       if (L && (L[0] > 0.0) && (L[1] > 0.0)) {
1370         PetscReal theta, phi, r, R;
1371         /* XY-periodic */
1372         /* Suppose its an y-z circle, then
1373              \hat r = (0, cos(th), sin(th)) \hat x = (1, 0, 0)
1374            and the circle in that plane is
1375              \hat r cos(phi) + \hat x sin(phi) */
1376         theta                = 2.0 * PETSC_PI * PetscRealPart(coords[off + 1]) / L[1];
1377         phi                  = 2.0 * PETSC_PI * PetscRealPart(coords[off + 0]) / L[0];
1378         r                    = L[0] / (2.0 * PETSC_PI * 2.0 * L[1]);
1379         R                    = L[1] / (2.0 * PETSC_PI);
1380         ncoords[coordSize++] = PetscSinReal(phi) * r;
1381         ncoords[coordSize++] = -PetscCosReal(theta) * (R + r * PetscCosReal(phi));
1382         ncoords[coordSize++] = PetscSinReal(theta) * (R + r * PetscCosReal(phi));
1383       } else if (L && (L[0] > 0.0)) {
1384         /* X-periodic */
1385         ncoords[coordSize++] = -PetscCosReal(2.0 * PETSC_PI * PetscRealPart(coords[off + 0]) / L[0]) * (L[0] / (2.0 * PETSC_PI));
1386         ncoords[coordSize++] = coords[off + 1];
1387         ncoords[coordSize++] = PetscSinReal(2.0 * PETSC_PI * PetscRealPart(coords[off + 0]) / L[0]) * (L[0] / (2.0 * PETSC_PI));
1388       } else if (L && (L[1] > 0.0)) {
1389         /* Y-periodic */
1390         ncoords[coordSize++] = coords[off + 0];
1391         ncoords[coordSize++] = PetscSinReal(2.0 * PETSC_PI * PetscRealPart(coords[off + 1]) / L[1]) * (L[1] / (2.0 * PETSC_PI));
1392         ncoords[coordSize++] = -PetscCosReal(2.0 * PETSC_PI * PetscRealPart(coords[off + 1]) / L[1]) * (L[1] / (2.0 * PETSC_PI));
1393 #if 0
1394       } else if ((bd[0] == DM_BOUNDARY_TWIST)) {
1395         PetscReal phi, r, R;
1396         /* Mobius strip */
1397         /* Suppose its an x-z circle, then
1398              \hat r = (-cos(phi), 0, sin(phi)) \hat y = (0, 1, 0)
1399            and in that plane we rotate by pi as we go around the circle
1400              \hat r cos(phi/2) + \hat y sin(phi/2) */
1401         phi   = 2.0*PETSC_PI*PetscRealPart(coords[off+0])/L[0];
1402         R     = L[0];
1403         r     = PetscRealPart(coords[off+1]) - L[1]/2.0;
1404         ncoords[coordSize++] = -PetscCosReal(phi) * (R + r * PetscCosReal(phi/2.0));
1405         ncoords[coordSize++] =  PetscSinReal(phi/2.0) * r;
1406         ncoords[coordSize++] =  PetscSinReal(phi) * (R + r * PetscCosReal(phi/2.0));
1407 #endif
1408       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot handle periodicity in this domain");
1409     } else {
1410       for (d = 0; d < dof; ++d, ++coordSize) ncoords[coordSize] = coords[off + d];
1411     }
1412   }
1413   if (cutVertexLabel) {
1414     IS              vertices;
1415     const PetscInt *verts;
1416     PetscInt        n;
1417 
1418     PetscCall(DMLabelGetStratumIS(cutVertexLabel, 1, &vertices));
1419     if (vertices) {
1420       PetscCall(ISGetIndices(vertices, &verts));
1421       PetscCall(ISGetLocalSize(vertices, &n));
1422       for (v = 0; v < n; ++v) {
1423         PetscCall(PetscSectionGetDof(cSection, verts[v], &dof));
1424         PetscCall(PetscSectionGetOffset(cSection, verts[v], &off));
1425         for (d = 0; d < dof; ++d) ncoords[coordSize++] = coords[off + d] + ((L[d] > 0.) ? L[d] : 0.0);
1426       }
1427       PetscCall(ISRestoreIndices(vertices, &verts));
1428       PetscCall(ISDestroy(&vertices));
1429     }
1430   }
1431   PetscCheck(coordSize == N, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched sizes: %" PetscInt_FMT " != %" PetscInt_FMT, coordSize, N);
1432   PetscCall(DMLabelDestroy(&cutVertexLabel));
1433   PetscCall(VecRestoreArray(coordinatesLocal, &coords));
1434   PetscCall(VecRestoreArray(newcoords, &ncoords));
1435   PetscCall(PetscObjectSetName((PetscObject)newcoords, "vertices"));
1436   PetscCall(VecScale(newcoords, lengthScale));
1437   PetscCall(PetscViewerHDF5PushGroup(viewer, "/viz"));
1438   PetscCall(PetscViewerHDF5WriteGroup(viewer, NULL));
1439   PetscCall(PetscViewerHDF5PopGroup(viewer));
1440   PetscCall(PetscViewerHDF5PushGroup(viewer, "/viz/geometry"));
1441   PetscCall(VecView(newcoords, viewer));
1442   PetscCall(PetscViewerHDF5PopGroup(viewer));
1443   PetscCall(VecDestroy(&newcoords));
1444   PetscFunctionReturn(PETSC_SUCCESS);
1445 }
1446 
1447 PetscErrorCode DMPlexLabelsView_HDF5_Internal(DM dm, IS globalPointNumbers, PetscViewer viewer)
1448 {
1449   const char          *topologydm_name;
1450   const PetscInt      *gpoint;
1451   PetscInt             numLabels;
1452   PetscBool            omitCelltypes = PETSC_FALSE;
1453   DMPlexStorageVersion version;
1454   char                 group[PETSC_MAX_PATH_LEN];
1455 
1456   PetscFunctionBegin;
1457   PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_omit_celltypes", &omitCelltypes, NULL));
1458   PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version));
1459   PetscCall(ISGetIndices(globalPointNumbers, &gpoint));
1460   PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name));
1461   if (DMPlexStorageVersionGE(version, 2, 0, 0)) {
1462     PetscCall(PetscSNPrintf(group, sizeof(group), "topologies/%s/labels", topologydm_name));
1463   } else {
1464     PetscCall(PetscStrncpy(group, "/labels", sizeof(group)));
1465   }
1466   PetscCall(PetscViewerHDF5PushGroup(viewer, group));
1467   PetscCall(DMGetNumLabels(dm, &numLabels));
1468   for (PetscInt l = 0; l < numLabels; ++l) {
1469     DMLabel         label;
1470     const char     *name;
1471     IS              valueIS, pvalueIS, globalValueIS;
1472     const PetscInt *values;
1473     PetscInt        numValues, v;
1474     PetscBool       isDepth, isCelltype, output;
1475 
1476     PetscCall(DMGetLabelByNum(dm, l, &label));
1477     PetscCall(PetscObjectGetName((PetscObject)label, &name));
1478     PetscCall(DMGetLabelOutput(dm, name, &output));
1479     PetscCall(PetscStrncmp(name, "depth", 10, &isDepth));
1480     PetscCall(PetscStrncmp(name, "celltype", 10, &isCelltype));
1481     // TODO Should only filter out celltype if it can be calculated
1482     if (isDepth || (isCelltype && omitCelltypes) || !output) continue;
1483     PetscCall(PetscViewerHDF5PushGroup(viewer, name));
1484     PetscCall(DMLabelGetValueIS(label, &valueIS));
1485     /* Must copy to a new IS on the global comm */
1486     PetscCall(ISGetLocalSize(valueIS, &numValues));
1487     PetscCall(ISGetIndices(valueIS, &values));
1488     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), numValues, values, PETSC_COPY_VALUES, &pvalueIS));
1489     PetscCall(ISRestoreIndices(valueIS, &values));
1490     PetscCall(ISAllGather(pvalueIS, &globalValueIS));
1491     PetscCall(ISDestroy(&pvalueIS));
1492     PetscCall(ISSortRemoveDups(globalValueIS));
1493     PetscCall(ISGetLocalSize(globalValueIS, &numValues));
1494     PetscCall(ISGetIndices(globalValueIS, &values));
1495     for (v = 0; v < numValues; ++v) {
1496       IS              stratumIS, globalStratumIS;
1497       const PetscInt *spoints = NULL;
1498       PetscInt       *gspoints, n = 0, gn, p;
1499       const char     *iname = "indices";
1500       char            group[PETSC_MAX_PATH_LEN];
1501 
1502       PetscCall(PetscSNPrintf(group, sizeof(group), "%" PetscInt_FMT, values[v]));
1503       PetscCall(PetscViewerHDF5PushGroup(viewer, group));
1504       PetscCall(DMLabelGetStratumIS(label, values[v], &stratumIS));
1505 
1506       if (stratumIS) PetscCall(ISGetLocalSize(stratumIS, &n));
1507       if (stratumIS) PetscCall(ISGetIndices(stratumIS, &spoints));
1508       for (gn = 0, p = 0; p < n; ++p)
1509         if (gpoint[spoints[p]] >= 0) ++gn;
1510       PetscCall(PetscMalloc1(gn, &gspoints));
1511       for (gn = 0, p = 0; p < n; ++p)
1512         if (gpoint[spoints[p]] >= 0) gspoints[gn++] = gpoint[spoints[p]];
1513       if (stratumIS) PetscCall(ISRestoreIndices(stratumIS, &spoints));
1514       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), gn, gspoints, PETSC_OWN_POINTER, &globalStratumIS));
1515       PetscCall(PetscObjectSetName((PetscObject)globalStratumIS, iname));
1516       if (DMPlexStorageVersionGE(version, 3, 1, 0)) PetscCall(ISSetCompressOutput(globalStratumIS, PETSC_TRUE));
1517 
1518       PetscCall(ISView(globalStratumIS, viewer));
1519       PetscCall(ISDestroy(&globalStratumIS));
1520       PetscCall(ISDestroy(&stratumIS));
1521       PetscCall(PetscViewerHDF5PopGroup(viewer));
1522     }
1523     PetscCall(ISRestoreIndices(globalValueIS, &values));
1524     PetscCall(ISDestroy(&globalValueIS));
1525     PetscCall(ISDestroy(&valueIS));
1526     PetscCall(PetscViewerHDF5PopGroup(viewer));
1527   }
1528   PetscCall(ISRestoreIndices(globalPointNumbers, &gpoint));
1529   PetscCall(PetscViewerHDF5PopGroup(viewer));
1530   PetscFunctionReturn(PETSC_SUCCESS);
1531 }
1532 
1533 /* We only write cells and vertices. Does this screw up parallel reading? */
1534 PetscErrorCode DMPlexView_HDF5_Internal(DM dm, PetscViewer viewer)
1535 {
1536   IS                globalPointNumbers;
1537   PetscViewerFormat format;
1538   PetscBool         viz_geom = PETSC_FALSE, xdmf_topo = PETSC_FALSE, petsc_topo = PETSC_FALSE;
1539 
1540   PetscFunctionBegin;
1541   PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbers));
1542   PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
1543 
1544   PetscCall(PetscViewerGetFormat(viewer, &format));
1545   switch (format) {
1546   case PETSC_VIEWER_HDF5_VIZ:
1547     viz_geom  = PETSC_TRUE;
1548     xdmf_topo = PETSC_TRUE;
1549     break;
1550   case PETSC_VIEWER_HDF5_XDMF:
1551     xdmf_topo = PETSC_TRUE;
1552     break;
1553   case PETSC_VIEWER_HDF5_PETSC:
1554     petsc_topo = PETSC_TRUE;
1555     break;
1556   case PETSC_VIEWER_DEFAULT:
1557   case PETSC_VIEWER_NATIVE:
1558     viz_geom   = PETSC_TRUE;
1559     xdmf_topo  = PETSC_TRUE;
1560     petsc_topo = PETSC_TRUE;
1561     break;
1562   default:
1563     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
1564   }
1565 
1566   if (viz_geom) PetscCall(DMPlexCoordinatesView_HDF5_XDMF_Private(dm, viewer));
1567   if (xdmf_topo) PetscCall(DMPlexTopologyView_HDF5_XDMF_Private(dm, globalPointNumbers, viewer));
1568   if (petsc_topo) {
1569     PetscBool viewLabels = PETSC_TRUE;
1570 
1571     PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbers, viewer));
1572     PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_view_labels", &viewLabels, NULL));
1573     if (viewLabels) PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbers, viewer));
1574   }
1575 
1576   PetscCall(ISDestroy(&globalPointNumbers));
1577   PetscFunctionReturn(PETSC_SUCCESS);
1578 }
1579 
1580 PetscErrorCode DMPlexSectionView_HDF5_Internal(DM dm, PetscViewer viewer, DM sectiondm)
1581 {
1582   DMPlexStorageVersion version;
1583   MPI_Comm             comm;
1584   const char          *topologydm_name;
1585   const char          *sectiondm_name;
1586   PetscSection         gsection;
1587 
1588   PetscFunctionBegin;
1589   PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version));
1590   PetscCall(PetscObjectGetComm((PetscObject)sectiondm, &comm));
1591   PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name));
1592   PetscCall(PetscObjectGetName((PetscObject)sectiondm, &sectiondm_name));
1593   PetscCall(PetscViewerHDF5PushGroup(viewer, "topologies"));
1594   PetscCall(PetscViewerHDF5PushGroup(viewer, topologydm_name));
1595   PetscCall(PetscViewerHDF5PushGroup(viewer, "dms"));
1596   PetscCall(PetscViewerHDF5PushGroup(viewer, sectiondm_name));
1597   PetscCall(DMGetGlobalSection(sectiondm, &gsection));
1598   /* Save raw section */
1599   PetscCall(PetscSectionView(gsection, viewer));
1600   /* Save plex wrapper */
1601   {
1602     PetscInt        pStart, pEnd, p, n;
1603     IS              globalPointNumbers;
1604     const PetscInt *gpoints;
1605     IS              orderIS;
1606     PetscInt       *order;
1607 
1608     PetscCall(PetscSectionGetChart(gsection, &pStart, &pEnd));
1609     PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbers));
1610     PetscCall(ISGetIndices(globalPointNumbers, &gpoints));
1611     for (p = pStart, n = 0; p < pEnd; ++p)
1612       if (gpoints[p] >= 0) n++;
1613     /* "order" is an array of global point numbers.
1614        When loading, it is used with topology/order array
1615        to match section points with plex topology points. */
1616     PetscCall(PetscMalloc1(n, &order));
1617     for (p = pStart, n = 0; p < pEnd; ++p)
1618       if (gpoints[p] >= 0) order[n++] = gpoints[p];
1619     PetscCall(ISRestoreIndices(globalPointNumbers, &gpoints));
1620     PetscCall(ISDestroy(&globalPointNumbers));
1621     PetscCall(ISCreateGeneral(comm, n, order, PETSC_OWN_POINTER, &orderIS));
1622     PetscCall(PetscObjectSetName((PetscObject)orderIS, "order"));
1623     if (DMPlexStorageVersionGE(version, 3, 1, 0)) PetscCall(ISSetCompressOutput(orderIS, PETSC_TRUE));
1624     PetscCall(ISView(orderIS, viewer));
1625     PetscCall(ISDestroy(&orderIS));
1626   }
1627   PetscCall(PetscViewerHDF5PopGroup(viewer));
1628   PetscCall(PetscViewerHDF5PopGroup(viewer));
1629   PetscCall(PetscViewerHDF5PopGroup(viewer));
1630   PetscCall(PetscViewerHDF5PopGroup(viewer));
1631   PetscFunctionReturn(PETSC_SUCCESS);
1632 }
1633 
1634 PetscErrorCode DMPlexGlobalVectorView_HDF5_Internal(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
1635 {
1636   const char *topologydm_name;
1637   const char *sectiondm_name;
1638   const char *vec_name;
1639   PetscInt    bs;
1640 
1641   PetscFunctionBegin;
1642   /* Check consistency */
1643   {
1644     PetscSF pointsf, pointsf1;
1645 
1646     PetscCall(DMGetPointSF(dm, &pointsf));
1647     PetscCall(DMGetPointSF(sectiondm, &pointsf1));
1648     PetscCheck(pointsf1 == pointsf, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatching point SFs for dm and sectiondm");
1649   }
1650   PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name));
1651   PetscCall(PetscObjectGetName((PetscObject)sectiondm, &sectiondm_name));
1652   PetscCall(PetscObjectGetName((PetscObject)vec, &vec_name));
1653   PetscCall(PetscViewerHDF5PushGroup(viewer, "topologies"));
1654   PetscCall(PetscViewerHDF5PushGroup(viewer, topologydm_name));
1655   PetscCall(PetscViewerHDF5PushGroup(viewer, "dms"));
1656   PetscCall(PetscViewerHDF5PushGroup(viewer, sectiondm_name));
1657   PetscCall(PetscViewerHDF5PushGroup(viewer, "vecs"));
1658   PetscCall(PetscViewerHDF5PushGroup(viewer, vec_name));
1659   PetscCall(VecGetBlockSize(vec, &bs));
1660   PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "blockSize", PETSC_INT, (void *)&bs));
1661   PetscCall(VecSetBlockSize(vec, 1));
1662   /* VecView(vec, viewer) would call (*vec->opt->view)(vec, viewer), but,    */
1663   /* if vec was created with DMGet{Global, Local}Vector(), vec->opt->view    */
1664   /* is set to VecView_Plex, which would save vec in a predefined location.  */
1665   /* To save vec in where we want, we create a new Vec (temp) with           */
1666   /* VecCreate(), wrap the vec data in temp, and call VecView(temp, viewer). */
1667   {
1668     Vec                temp;
1669     const PetscScalar *array;
1670     PetscLayout        map;
1671 
1672     PetscCall(VecCreate(PetscObjectComm((PetscObject)vec), &temp));
1673     PetscCall(PetscObjectSetName((PetscObject)temp, vec_name));
1674     PetscCall(VecGetLayout(vec, &map));
1675     PetscCall(VecSetLayout(temp, map));
1676     PetscCall(VecSetUp(temp));
1677     PetscCall(VecGetArrayRead(vec, &array));
1678     PetscCall(VecPlaceArray(temp, array));
1679     PetscCall(VecView(temp, viewer));
1680     PetscCall(VecResetArray(temp));
1681     PetscCall(VecRestoreArrayRead(vec, &array));
1682     PetscCall(VecDestroy(&temp));
1683   }
1684   PetscCall(VecSetBlockSize(vec, bs));
1685   PetscCall(PetscViewerHDF5PopGroup(viewer));
1686   PetscCall(PetscViewerHDF5PopGroup(viewer));
1687   PetscCall(PetscViewerHDF5PopGroup(viewer));
1688   PetscCall(PetscViewerHDF5PopGroup(viewer));
1689   PetscCall(PetscViewerHDF5PopGroup(viewer));
1690   PetscCall(PetscViewerHDF5PopGroup(viewer));
1691   PetscFunctionReturn(PETSC_SUCCESS);
1692 }
1693 
1694 PetscErrorCode DMPlexLocalVectorView_HDF5_Internal(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
1695 {
1696   MPI_Comm     comm;
1697   const char  *topologydm_name;
1698   const char  *sectiondm_name;
1699   const char  *vec_name;
1700   PetscSection section;
1701   PetscBool    includesConstraints;
1702   Vec          gvec;
1703   PetscInt     m, bs;
1704 
1705   PetscFunctionBegin;
1706   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1707   /* Check consistency */
1708   {
1709     PetscSF pointsf, pointsf1;
1710 
1711     PetscCall(DMGetPointSF(dm, &pointsf));
1712     PetscCall(DMGetPointSF(sectiondm, &pointsf1));
1713     PetscCheck(pointsf1 == pointsf, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatching point SFs for dm and sectiondm");
1714   }
1715   PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name));
1716   PetscCall(PetscObjectGetName((PetscObject)sectiondm, &sectiondm_name));
1717   PetscCall(PetscObjectGetName((PetscObject)vec, &vec_name));
1718   PetscCall(PetscViewerHDF5PushGroup(viewer, "topologies"));
1719   PetscCall(PetscViewerHDF5PushGroup(viewer, topologydm_name));
1720   PetscCall(PetscViewerHDF5PushGroup(viewer, "dms"));
1721   PetscCall(PetscViewerHDF5PushGroup(viewer, sectiondm_name));
1722   PetscCall(PetscViewerHDF5PushGroup(viewer, "vecs"));
1723   PetscCall(PetscViewerHDF5PushGroup(viewer, vec_name));
1724   PetscCall(VecGetBlockSize(vec, &bs));
1725   PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "blockSize", PETSC_INT, (void *)&bs));
1726   PetscCall(VecCreate(comm, &gvec));
1727   PetscCall(PetscObjectSetName((PetscObject)gvec, vec_name));
1728   PetscCall(DMGetGlobalSection(sectiondm, &section));
1729   PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
1730   if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
1731   else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
1732   PetscCall(VecSetSizes(gvec, m, PETSC_DECIDE));
1733   PetscCall(VecSetUp(gvec));
1734   PetscCall(DMLocalToGlobalBegin(sectiondm, vec, INSERT_VALUES, gvec));
1735   PetscCall(DMLocalToGlobalEnd(sectiondm, vec, INSERT_VALUES, gvec));
1736   PetscCall(VecView(gvec, viewer));
1737   PetscCall(VecDestroy(&gvec));
1738   PetscCall(PetscViewerHDF5PopGroup(viewer));
1739   PetscCall(PetscViewerHDF5PopGroup(viewer));
1740   PetscCall(PetscViewerHDF5PopGroup(viewer));
1741   PetscCall(PetscViewerHDF5PopGroup(viewer));
1742   PetscCall(PetscViewerHDF5PopGroup(viewer));
1743   PetscCall(PetscViewerHDF5PopGroup(viewer));
1744   PetscFunctionReturn(PETSC_SUCCESS);
1745 }
1746 
1747 struct _n_LoadLabelsCtx {
1748   MPI_Comm    comm;
1749   PetscMPIInt rank;
1750   DM          dm;
1751   PetscViewer viewer;
1752   DMLabel     label;
1753   PetscSF     sfXC;
1754   PetscLayout layoutX;
1755 };
1756 typedef struct _n_LoadLabelsCtx *LoadLabelsCtx;
1757 
1758 static PetscErrorCode LoadLabelsCtxCreate(DM dm, PetscViewer viewer, PetscSF sfXC, LoadLabelsCtx *ctx)
1759 {
1760   PetscFunctionBegin;
1761   PetscCall(PetscNew(ctx));
1762   PetscCall(PetscObjectReference((PetscObject)((*ctx)->dm = dm)));
1763   PetscCall(PetscObjectReference((PetscObject)((*ctx)->viewer = viewer)));
1764   PetscCall(PetscObjectGetComm((PetscObject)dm, &(*ctx)->comm));
1765   PetscCallMPI(MPI_Comm_rank((*ctx)->comm, &(*ctx)->rank));
1766   (*ctx)->sfXC = sfXC;
1767   if (sfXC) {
1768     PetscInt nX;
1769 
1770     PetscCall(PetscObjectReference((PetscObject)sfXC));
1771     PetscCall(PetscSFGetGraph(sfXC, &nX, NULL, NULL, NULL));
1772     PetscCall(PetscLayoutCreateFromSizes((*ctx)->comm, nX, PETSC_DECIDE, 1, &(*ctx)->layoutX));
1773   }
1774   PetscFunctionReturn(PETSC_SUCCESS);
1775 }
1776 
1777 static PetscErrorCode LoadLabelsCtxDestroy(LoadLabelsCtx *ctx)
1778 {
1779   PetscFunctionBegin;
1780   if (!*ctx) PetscFunctionReturn(PETSC_SUCCESS);
1781   PetscCall(DMDestroy(&(*ctx)->dm));
1782   PetscCall(PetscViewerDestroy(&(*ctx)->viewer));
1783   PetscCall(PetscSFDestroy(&(*ctx)->sfXC));
1784   PetscCall(PetscLayoutDestroy(&(*ctx)->layoutX));
1785   PetscCall(PetscFree(*ctx));
1786   PetscFunctionReturn(PETSC_SUCCESS);
1787 }
1788 
1789 /*
1790     A: on-disk points
1791     X: global points [0, NX)
1792     C: distributed plex points
1793 */
1794 static herr_t ReadLabelStratumHDF5_Distribute_Private(IS stratumIS, LoadLabelsCtx ctx, IS *newStratumIS)
1795 {
1796   MPI_Comm        comm    = ctx->comm;
1797   PetscSF         sfXC    = ctx->sfXC;
1798   PetscLayout     layoutX = ctx->layoutX;
1799   PetscSF         sfXA;
1800   const PetscInt *A_points;
1801   PetscInt        nX, nC;
1802   PetscInt        n;
1803 
1804   PetscFunctionBegin;
1805   PetscCall(PetscSFGetGraph(sfXC, &nX, &nC, NULL, NULL));
1806   PetscCall(ISGetLocalSize(stratumIS, &n));
1807   PetscCall(ISGetIndices(stratumIS, &A_points));
1808   PetscCall(PetscSFCreate(comm, &sfXA));
1809   PetscCall(PetscSFSetGraphLayout(sfXA, layoutX, n, NULL, PETSC_USE_POINTER, A_points));
1810   PetscCall(ISCreate(comm, newStratumIS));
1811   PetscCall(ISSetType(*newStratumIS, ISGENERAL));
1812   {
1813     PetscInt   i;
1814     PetscBool *A_mask, *X_mask, *C_mask;
1815 
1816     PetscCall(PetscCalloc3(n, &A_mask, nX, &X_mask, nC, &C_mask));
1817     for (i = 0; i < n; i++) A_mask[i] = PETSC_TRUE;
1818     PetscCall(PetscSFReduceBegin(sfXA, MPIU_BOOL, A_mask, X_mask, MPI_REPLACE));
1819     PetscCall(PetscSFReduceEnd(sfXA, MPIU_BOOL, A_mask, X_mask, MPI_REPLACE));
1820     PetscCall(PetscSFBcastBegin(sfXC, MPIU_BOOL, X_mask, C_mask, MPI_LOR));
1821     PetscCall(PetscSFBcastEnd(sfXC, MPIU_BOOL, X_mask, C_mask, MPI_LOR));
1822     PetscCall(ISGeneralSetIndicesFromMask(*newStratumIS, 0, nC, C_mask));
1823     PetscCall(PetscFree3(A_mask, X_mask, C_mask));
1824   }
1825   PetscCall(PetscSFDestroy(&sfXA));
1826   PetscCall(ISRestoreIndices(stratumIS, &A_points));
1827   PetscFunctionReturn(PETSC_SUCCESS);
1828 }
1829 
1830 static herr_t ReadLabelStratumHDF5_Static(hid_t g_id, const char *vname, const H5L_info_t *info, void *op_data)
1831 {
1832   LoadLabelsCtx   ctx    = (LoadLabelsCtx)op_data;
1833   PetscViewer     viewer = ctx->viewer;
1834   DMLabel         label  = ctx->label;
1835   MPI_Comm        comm   = ctx->comm;
1836   IS              stratumIS;
1837   const PetscInt *ind;
1838   PetscInt        value, N, i;
1839 
1840   PetscCall(PetscOptionsStringToInt(vname, &value));
1841   PetscCall(ISCreate(comm, &stratumIS));
1842   PetscCall(PetscObjectSetName((PetscObject)stratumIS, "indices"));
1843   PetscCall(PetscViewerHDF5PushGroup(viewer, vname)); /* labels/<lname>/<vname> */
1844 
1845   if (!ctx->sfXC) {
1846     /* Force serial load */
1847     PetscCall(PetscViewerHDF5ReadSizes(viewer, "indices", NULL, &N));
1848     PetscCall(PetscLayoutSetLocalSize(stratumIS->map, !ctx->rank ? N : 0));
1849     PetscCall(PetscLayoutSetSize(stratumIS->map, N));
1850   }
1851   PetscCall(ISLoad(stratumIS, viewer));
1852 
1853   if (ctx->sfXC) {
1854     IS newStratumIS;
1855 
1856     PetscCallHDF5(ReadLabelStratumHDF5_Distribute_Private, (stratumIS, ctx, &newStratumIS));
1857     PetscCall(ISDestroy(&stratumIS));
1858     stratumIS = newStratumIS;
1859   }
1860 
1861   PetscCall(PetscViewerHDF5PopGroup(viewer));
1862   PetscCall(ISGetLocalSize(stratumIS, &N));
1863   PetscCall(ISGetIndices(stratumIS, &ind));
1864   for (i = 0; i < N; ++i) PetscCall(DMLabelSetValue(label, ind[i], value));
1865   PetscCall(ISRestoreIndices(stratumIS, &ind));
1866   PetscCall(ISDestroy(&stratumIS));
1867   return 0;
1868 }
1869 
1870 /* TODO: Fix this code, it is returning PETSc error codes when it should be translating them to herr_t codes */
1871 static herr_t ReadLabelHDF5_Static(hid_t g_id, const char *lname, const H5L_info_t *info, void *op_data)
1872 {
1873   LoadLabelsCtx  ctx = (LoadLabelsCtx)op_data;
1874   DM             dm  = ctx->dm;
1875   hsize_t        idx = 0;
1876   PetscErrorCode ierr;
1877   PetscBool      flg;
1878   herr_t         err;
1879 
1880   PetscCall(DMHasLabel(dm, lname, &flg));
1881   if (flg) PetscCall(DMRemoveLabel(dm, lname, NULL));
1882   ierr = DMCreateLabel(dm, lname);
1883   if (ierr) return (herr_t)ierr;
1884   ierr = DMGetLabel(dm, lname, &ctx->label);
1885   if (ierr) return (herr_t)ierr;
1886   ierr = PetscViewerHDF5PushGroup(ctx->viewer, lname);
1887   if (ierr) return (herr_t)ierr;
1888   /* Iterate over the label's strata */
1889   PetscCallHDF5Return(err, H5Literate_by_name, (g_id, lname, H5_INDEX_NAME, H5_ITER_NATIVE, &idx, ReadLabelStratumHDF5_Static, op_data, 0));
1890   ierr = PetscViewerHDF5PopGroup(ctx->viewer);
1891   if (ierr) return (herr_t)ierr;
1892   return err;
1893 }
1894 
1895 PetscErrorCode DMPlexLabelsLoad_HDF5_Internal(DM dm, PetscViewer viewer, PetscSF sfXC)
1896 {
1897   const char          *topologydm_name;
1898   LoadLabelsCtx        ctx;
1899   hsize_t              idx = 0;
1900   char                 group[PETSC_MAX_PATH_LEN];
1901   DMPlexStorageVersion version;
1902   PetscBool            distributed, hasGroup;
1903 
1904   PetscFunctionBegin;
1905   PetscCall(DMPlexIsDistributed(dm, &distributed));
1906   if (distributed) PetscCheck(sfXC, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_NULL, "PetscSF must be given for parallel load");
1907   PetscCall(LoadLabelsCtxCreate(dm, viewer, sfXC, &ctx));
1908   PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name));
1909   PetscCall(PetscViewerHDF5GetDMPlexStorageVersionReading(viewer, &version));
1910   if (DMPlexStorageVersionGE(version, 2, 0, 0)) {
1911     PetscCall(PetscSNPrintf(group, sizeof(group), "topologies/%s/labels", topologydm_name));
1912   } else {
1913     PetscCall(PetscStrncpy(group, "labels", sizeof(group)));
1914   }
1915   PetscCall(PetscViewerHDF5PushGroup(viewer, group));
1916   PetscCall(PetscViewerHDF5HasGroup(viewer, NULL, &hasGroup));
1917   if (hasGroup) {
1918     hid_t fileId, groupId;
1919 
1920     PetscCall(PetscViewerHDF5OpenGroup(viewer, NULL, &fileId, &groupId));
1921     /* Iterate over labels */
1922     PetscCallHDF5(H5Literate, (groupId, H5_INDEX_NAME, H5_ITER_NATIVE, &idx, ReadLabelHDF5_Static, ctx));
1923     PetscCallHDF5(H5Gclose, (groupId));
1924   }
1925   PetscCall(PetscViewerHDF5PopGroup(viewer));
1926   PetscCall(LoadLabelsCtxDestroy(&ctx));
1927   PetscFunctionReturn(PETSC_SUCCESS);
1928 }
1929 
1930 static PetscErrorCode DMPlexDistributionLoad_HDF5_Private(DM dm, PetscViewer viewer, PetscSF sf, PetscSF *distsf, DM *distdm)
1931 {
1932   MPI_Comm        comm;
1933   PetscMPIInt     size, rank;
1934   PetscInt        dist_size;
1935   const char     *distribution_name;
1936   PetscInt        p, lsize;
1937   IS              chartSizesIS, ownersIS, gpointsIS;
1938   const PetscInt *chartSize, *owners, *gpoints;
1939   PetscLayout     layout;
1940   PetscBool       has;
1941 
1942   PetscFunctionBegin;
1943   *distsf = NULL;
1944   *distdm = NULL;
1945   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1946   PetscCallMPI(MPI_Comm_size(comm, &size));
1947   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1948   PetscCall(DMPlexDistributionGetName(dm, &distribution_name));
1949   if (!distribution_name) PetscFunctionReturn(PETSC_SUCCESS);
1950   PetscCall(PetscLogEventBegin(DMPLEX_DistributionLoad, viewer, 0, 0, 0));
1951   PetscCall(PetscViewerHDF5HasGroup(viewer, NULL, &has));
1952   if (!has) {
1953     char *full_group;
1954 
1955     PetscCall(PetscViewerHDF5GetGroup(viewer, NULL, &full_group));
1956     PetscCheck(has, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Distribution %s cannot be found: HDF5 group %s not found in file", distribution_name, full_group);
1957   }
1958   PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "comm_size", PETSC_INT, NULL, (void *)&dist_size));
1959   PetscCheck(dist_size == (PetscInt)size, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mismatching comm sizes: comm size of this session (%d) != comm size used for %s (%" PetscInt_FMT ")", size, distribution_name, dist_size);
1960   PetscCall(ISCreate(comm, &chartSizesIS));
1961   PetscCall(PetscObjectSetName((PetscObject)chartSizesIS, "chart_sizes"));
1962   PetscCall(ISCreate(comm, &ownersIS));
1963   PetscCall(PetscObjectSetName((PetscObject)ownersIS, "owners"));
1964   PetscCall(ISCreate(comm, &gpointsIS));
1965   PetscCall(PetscObjectSetName((PetscObject)gpointsIS, "global_point_numbers"));
1966   PetscCall(PetscLayoutSetLocalSize(chartSizesIS->map, 1));
1967   PetscCall(ISLoad(chartSizesIS, viewer));
1968   PetscCall(ISGetIndices(chartSizesIS, &chartSize));
1969   PetscCall(PetscLayoutSetLocalSize(ownersIS->map, *chartSize));
1970   PetscCall(PetscLayoutSetLocalSize(gpointsIS->map, *chartSize));
1971   PetscCall(ISLoad(ownersIS, viewer));
1972   PetscCall(ISLoad(gpointsIS, viewer));
1973   PetscCall(ISGetIndices(ownersIS, &owners));
1974   PetscCall(ISGetIndices(gpointsIS, &gpoints));
1975   PetscCall(PetscSFCreate(comm, distsf));
1976   PetscCall(PetscSFSetFromOptions(*distsf));
1977   PetscCall(PetscLayoutCreate(comm, &layout));
1978   PetscCall(PetscSFGetGraph(sf, &lsize, NULL, NULL, NULL));
1979   PetscCall(PetscLayoutSetLocalSize(layout, lsize));
1980   PetscCall(PetscLayoutSetBlockSize(layout, 1));
1981   PetscCall(PetscLayoutSetUp(layout));
1982   PetscCall(PetscSFSetGraphLayout(*distsf, layout, *chartSize, NULL, PETSC_OWN_POINTER, gpoints));
1983   PetscCall(PetscLayoutDestroy(&layout));
1984   /* Migrate DM */
1985   {
1986     PetscInt     pStart, pEnd;
1987     PetscSFNode *buffer0, *buffer1, *buffer2;
1988 
1989     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1990     PetscCall(PetscMalloc2(pEnd - pStart, &buffer0, lsize, &buffer1));
1991     PetscCall(PetscMalloc1(*chartSize, &buffer2));
1992     {
1993       PetscSF            workPointSF;
1994       PetscInt           workNroots, workNleaves;
1995       const PetscInt    *workIlocal;
1996       const PetscSFNode *workIremote;
1997 
1998       for (p = pStart; p < pEnd; ++p) {
1999         buffer0[p - pStart].rank  = rank;
2000         buffer0[p - pStart].index = p - pStart;
2001       }
2002       PetscCall(DMGetPointSF(dm, &workPointSF));
2003       PetscCall(PetscSFGetGraph(workPointSF, &workNroots, &workNleaves, &workIlocal, &workIremote));
2004       for (p = 0; p < workNleaves; ++p) {
2005         PetscInt workIlocalp = (workIlocal ? workIlocal[p] : p);
2006 
2007         buffer0[workIlocalp].rank = -1;
2008       }
2009     }
2010     for (p = 0; p < lsize; ++p) buffer1[p].rank = -1;
2011     for (p = 0; p < *chartSize; ++p) buffer2[p].rank = -1;
2012     PetscCall(PetscSFReduceBegin(sf, MPIU_SF_NODE, buffer0, buffer1, MPI_MAXLOC));
2013     PetscCall(PetscSFReduceEnd(sf, MPIU_SF_NODE, buffer0, buffer1, MPI_MAXLOC));
2014     PetscCall(PetscSFBcastBegin(*distsf, MPIU_SF_NODE, buffer1, buffer2, MPI_REPLACE));
2015     PetscCall(PetscSFBcastEnd(*distsf, MPIU_SF_NODE, buffer1, buffer2, MPI_REPLACE));
2016     if (PetscDefined(USE_DEBUG)) {
2017       for (p = 0; p < *chartSize; ++p) {
2018         PetscCheck(buffer2[p].rank >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Found negative root rank %" PetscInt_FMT " at local point %" PetscInt_FMT " on rank %d when making migrationSF", buffer2[p].rank, p, rank);
2019       }
2020     }
2021     PetscCall(PetscFree2(buffer0, buffer1));
2022     PetscCall(DMCreate(comm, distdm));
2023     PetscCall(DMSetType(*distdm, DMPLEX));
2024     PetscCall(PetscObjectSetName((PetscObject)*distdm, ((PetscObject)dm)->name));
2025     PetscCall(DMPlexDistributionSetName(*distdm, distribution_name));
2026     {
2027       PetscSF migrationSF;
2028 
2029       PetscCall(PetscSFCreate(comm, &migrationSF));
2030       PetscCall(PetscSFSetFromOptions(migrationSF));
2031       PetscCall(PetscSFSetGraph(migrationSF, pEnd - pStart, *chartSize, NULL, PETSC_OWN_POINTER, buffer2, PETSC_OWN_POINTER));
2032       PetscCall(PetscSFSetUp(migrationSF));
2033       PetscCall(DMPlexMigrate(dm, migrationSF, *distdm));
2034       PetscCall(PetscSFDestroy(&migrationSF));
2035     }
2036   }
2037   /* Set pointSF */
2038   {
2039     PetscSF      pointSF;
2040     PetscInt    *ilocal, nleaves, q;
2041     PetscSFNode *iremote, *buffer0, *buffer1;
2042 
2043     PetscCall(PetscMalloc2(*chartSize, &buffer0, lsize, &buffer1));
2044     for (p = 0, nleaves = 0; p < *chartSize; ++p) {
2045       if (owners[p] == rank) {
2046         buffer0[p].rank = rank;
2047       } else {
2048         buffer0[p].rank = -1;
2049         nleaves++;
2050       }
2051       buffer0[p].index = p;
2052     }
2053     for (p = 0; p < lsize; ++p) buffer1[p].rank = -1;
2054     PetscCall(PetscSFReduceBegin(*distsf, MPIU_SF_NODE, buffer0, buffer1, MPI_MAXLOC));
2055     PetscCall(PetscSFReduceEnd(*distsf, MPIU_SF_NODE, buffer0, buffer1, MPI_MAXLOC));
2056     for (p = 0; p < *chartSize; ++p) buffer0[p].rank = -1;
2057     PetscCall(PetscSFBcastBegin(*distsf, MPIU_SF_NODE, buffer1, buffer0, MPI_REPLACE));
2058     PetscCall(PetscSFBcastEnd(*distsf, MPIU_SF_NODE, buffer1, buffer0, MPI_REPLACE));
2059     if (PetscDefined(USE_DEBUG)) {
2060       for (p = 0; p < *chartSize; ++p) PetscCheck(buffer0[p].rank >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Found negative root rank %" PetscInt_FMT " at local point %" PetscInt_FMT " on rank %d when making pointSF", buffer0[p].rank, p, rank);
2061     }
2062     PetscCall(PetscMalloc1(nleaves, &ilocal));
2063     PetscCall(PetscMalloc1(nleaves, &iremote));
2064     for (p = 0, q = 0; p < *chartSize; ++p) {
2065       if (buffer0[p].rank != rank) {
2066         ilocal[q]        = p;
2067         iremote[q].rank  = buffer0[p].rank;
2068         iremote[q].index = buffer0[p].index;
2069         q++;
2070       }
2071     }
2072     PetscCheck(q == nleaves, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatching leaf sizes: %" PetscInt_FMT " != %" PetscInt_FMT, q, nleaves);
2073     PetscCall(PetscFree2(buffer0, buffer1));
2074     PetscCall(PetscSFCreate(comm, &pointSF));
2075     PetscCall(PetscSFSetFromOptions(pointSF));
2076     PetscCall(PetscSFSetGraph(pointSF, *chartSize, nleaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
2077     PetscCall(DMSetPointSF(*distdm, pointSF));
2078     {
2079       DM cdm;
2080 
2081       PetscCall(DMGetCoordinateDM(*distdm, &cdm));
2082       PetscCall(DMSetPointSF(cdm, pointSF));
2083     }
2084     PetscCall(PetscSFDestroy(&pointSF));
2085   }
2086   PetscCall(ISRestoreIndices(chartSizesIS, &chartSize));
2087   PetscCall(ISRestoreIndices(ownersIS, &owners));
2088   PetscCall(ISRestoreIndices(gpointsIS, &gpoints));
2089   PetscCall(ISDestroy(&chartSizesIS));
2090   PetscCall(ISDestroy(&ownersIS));
2091   PetscCall(ISDestroy(&gpointsIS));
2092   /* Record that overlap has been manually created.               */
2093   /* This is to pass `DMPlexCheckPointSF()`, which checks that    */
2094   /* pointSF does not contain cells in the leaves if overlap = 0. */
2095   PetscCall(DMPlexSetOverlap_Plex(*distdm, NULL, DMPLEX_OVERLAP_MANUAL));
2096   PetscCall(DMPlexDistributeSetDefault(*distdm, PETSC_FALSE));
2097   PetscCall(DMPlexReorderSetDefault(*distdm, DM_REORDER_DEFAULT_FALSE));
2098   PetscCall(PetscLogEventEnd(DMPLEX_DistributionLoad, viewer, 0, 0, 0));
2099   PetscFunctionReturn(PETSC_SUCCESS);
2100 }
2101 
2102 // Serial load of topology
2103 static PetscErrorCode DMPlexTopologyLoad_HDF5_Legacy_Private(DM dm, PetscViewer viewer, PetscSF *sf)
2104 {
2105   MPI_Comm        comm;
2106   const char     *pointsName, *coneSizesName, *conesName, *orientationsName;
2107   IS              pointsIS, coneSizesIS, conesIS, orientationsIS;
2108   const PetscInt *points, *coneSizes, *cones, *orientations;
2109   PetscInt       *cone, *ornt;
2110   PetscInt        dim, N, Np, pEnd, p, q, maxConeSize = 0, c;
2111   PetscMPIInt     size, rank;
2112 
2113   PetscFunctionBegin;
2114   pointsName       = "order";
2115   coneSizesName    = "cones";
2116   conesName        = "cells";
2117   orientationsName = "orientation";
2118   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2119   PetscCallMPI(MPI_Comm_size(comm, &size));
2120   PetscCallMPI(MPI_Comm_rank(comm, &rank));
2121   PetscCall(ISCreate(comm, &pointsIS));
2122   PetscCall(PetscObjectSetName((PetscObject)pointsIS, pointsName));
2123   PetscCall(ISCreate(comm, &coneSizesIS));
2124   PetscCall(PetscObjectSetName((PetscObject)coneSizesIS, coneSizesName));
2125   PetscCall(ISCreate(comm, &conesIS));
2126   PetscCall(PetscObjectSetName((PetscObject)conesIS, conesName));
2127   PetscCall(ISCreate(comm, &orientationsIS));
2128   PetscCall(PetscObjectSetName((PetscObject)orientationsIS, orientationsName));
2129   PetscCall(PetscViewerHDF5ReadObjectAttribute(viewer, (PetscObject)conesIS, "cell_dim", PETSC_INT, NULL, &dim));
2130   PetscCall(DMSetDimension(dm, dim));
2131   {
2132     /* Force serial load */
2133     PetscCall(PetscInfo(dm, "Loading DM %s in serial\n", dm->hdr.name));
2134     PetscCall(PetscViewerHDF5ReadSizes(viewer, pointsName, NULL, &Np));
2135     PetscCall(PetscLayoutSetLocalSize(pointsIS->map, rank == 0 ? Np : 0));
2136     PetscCall(PetscLayoutSetSize(pointsIS->map, Np));
2137     pEnd = rank == 0 ? Np : 0;
2138     PetscCall(PetscViewerHDF5ReadSizes(viewer, coneSizesName, NULL, &Np));
2139     PetscCall(PetscLayoutSetLocalSize(coneSizesIS->map, rank == 0 ? Np : 0));
2140     PetscCall(PetscLayoutSetSize(coneSizesIS->map, Np));
2141     PetscCall(PetscViewerHDF5ReadSizes(viewer, conesName, NULL, &N));
2142     PetscCall(PetscLayoutSetLocalSize(conesIS->map, rank == 0 ? N : 0));
2143     PetscCall(PetscLayoutSetSize(conesIS->map, N));
2144     PetscCall(PetscViewerHDF5ReadSizes(viewer, orientationsName, NULL, &N));
2145     PetscCall(PetscLayoutSetLocalSize(orientationsIS->map, rank == 0 ? N : 0));
2146     PetscCall(PetscLayoutSetSize(orientationsIS->map, N));
2147   }
2148   PetscCall(ISLoad(pointsIS, viewer));
2149   PetscCall(ISLoad(coneSizesIS, viewer));
2150   PetscCall(ISLoad(conesIS, viewer));
2151   PetscCall(ISLoad(orientationsIS, viewer));
2152   /* Create Plex */
2153   PetscCall(DMPlexSetChart(dm, 0, pEnd));
2154   PetscCall(ISGetIndices(pointsIS, &points));
2155   PetscCall(ISGetIndices(coneSizesIS, &coneSizes));
2156   for (p = 0; p < pEnd; ++p) {
2157     PetscCall(DMPlexSetConeSize(dm, points[p], coneSizes[p]));
2158     maxConeSize = PetscMax(maxConeSize, coneSizes[p]);
2159   }
2160   PetscCall(DMSetUp(dm));
2161   PetscCall(ISGetIndices(conesIS, &cones));
2162   PetscCall(ISGetIndices(orientationsIS, &orientations));
2163   PetscCall(PetscMalloc2(maxConeSize, &cone, maxConeSize, &ornt));
2164   for (p = 0, q = 0; p < pEnd; ++p) {
2165     for (c = 0; c < coneSizes[p]; ++c, ++q) {
2166       cone[c] = cones[q];
2167       ornt[c] = orientations[q];
2168     }
2169     PetscCall(DMPlexSetCone(dm, points[p], cone));
2170     PetscCall(DMPlexSetConeOrientation(dm, points[p], ornt));
2171   }
2172   PetscCall(PetscFree2(cone, ornt));
2173   /* Create global section migration SF */
2174   if (sf) {
2175     PetscLayout layout;
2176     PetscInt   *globalIndices;
2177 
2178     PetscCall(PetscMalloc1(pEnd, &globalIndices));
2179     /* plex point == globalPointNumber in this case */
2180     for (p = 0; p < pEnd; ++p) globalIndices[p] = p;
2181     PetscCall(PetscLayoutCreate(comm, &layout));
2182     PetscCall(PetscLayoutSetSize(layout, Np));
2183     PetscCall(PetscLayoutSetBlockSize(layout, 1));
2184     PetscCall(PetscLayoutSetUp(layout));
2185     PetscCall(PetscSFCreate(comm, sf));
2186     PetscCall(PetscSFSetFromOptions(*sf));
2187     PetscCall(PetscSFSetGraphLayout(*sf, layout, pEnd, NULL, PETSC_OWN_POINTER, globalIndices));
2188     PetscCall(PetscLayoutDestroy(&layout));
2189     PetscCall(PetscFree(globalIndices));
2190   }
2191   /* Clean-up */
2192   PetscCall(ISRestoreIndices(pointsIS, &points));
2193   PetscCall(ISRestoreIndices(coneSizesIS, &coneSizes));
2194   PetscCall(ISRestoreIndices(conesIS, &cones));
2195   PetscCall(ISRestoreIndices(orientationsIS, &orientations));
2196   PetscCall(ISDestroy(&pointsIS));
2197   PetscCall(ISDestroy(&coneSizesIS));
2198   PetscCall(ISDestroy(&conesIS));
2199   PetscCall(ISDestroy(&orientationsIS));
2200   /* Fill in the rest of the topology structure */
2201   PetscCall(DMPlexSymmetrize(dm));
2202   PetscCall(DMPlexStratify(dm));
2203   PetscFunctionReturn(PETSC_SUCCESS);
2204 }
2205 
2206 /* Representation of two DMPlex strata in 0-based global numbering */
2207 struct _n_PlexLayer {
2208   PetscInt     d;
2209   IS           conesIS, orientationsIS;
2210   PetscSection coneSizesSection;
2211   PetscLayout  vertexLayout;
2212   PetscSF      overlapSF, l2gSF; //TODO maybe confusing names (in DMPlex in general)
2213   PetscInt     offset, conesOffset, leafOffset;
2214 };
2215 typedef struct _n_PlexLayer *PlexLayer;
2216 
2217 static PetscErrorCode PlexLayerDestroy(PlexLayer *layer)
2218 {
2219   PetscFunctionBegin;
2220   if (!*layer) PetscFunctionReturn(PETSC_SUCCESS);
2221   PetscCall(PetscSectionDestroy(&(*layer)->coneSizesSection));
2222   PetscCall(ISDestroy(&(*layer)->conesIS));
2223   PetscCall(ISDestroy(&(*layer)->orientationsIS));
2224   PetscCall(PetscSFDestroy(&(*layer)->overlapSF));
2225   PetscCall(PetscSFDestroy(&(*layer)->l2gSF));
2226   PetscCall(PetscLayoutDestroy(&(*layer)->vertexLayout));
2227   PetscCall(PetscFree(*layer));
2228   PetscFunctionReturn(PETSC_SUCCESS);
2229 }
2230 
2231 static PetscErrorCode PlexLayerCreate_Private(PlexLayer *layer)
2232 {
2233   PetscFunctionBegin;
2234   PetscCall(PetscNew(layer));
2235   (*layer)->d           = -1;
2236   (*layer)->offset      = -1;
2237   (*layer)->conesOffset = -1;
2238   (*layer)->leafOffset  = -1;
2239   PetscFunctionReturn(PETSC_SUCCESS);
2240 }
2241 
2242 // Parallel load of a depth stratum
2243 static PetscErrorCode PlexLayerLoad_Private(PlexLayer layer, PetscViewer viewer, PetscInt d, PetscLayout pointsLayout)
2244 {
2245   char         path[128];
2246   MPI_Comm     comm;
2247   const char  *coneSizesName, *conesName, *orientationsName;
2248   IS           coneSizesIS, conesIS, orientationsIS;
2249   PetscSection coneSizesSection;
2250   PetscLayout  vertexLayout = NULL;
2251   PetscInt     s;
2252 
2253   PetscFunctionBegin;
2254   coneSizesName    = "cone_sizes";
2255   conesName        = "cones";
2256   orientationsName = "orientations";
2257   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
2258 
2259   /* query size of next lower depth stratum (next lower dimension) */
2260   if (d > 0) {
2261     PetscInt NVertices;
2262 
2263     PetscCall(PetscSNPrintf(path, sizeof(path), "%" PetscInt_FMT "/%s", d - 1, coneSizesName));
2264     PetscCall(PetscViewerHDF5ReadSizes(viewer, path, NULL, &NVertices));
2265     PetscCall(PetscLayoutCreate(comm, &vertexLayout));
2266     PetscCall(PetscLayoutSetSize(vertexLayout, NVertices));
2267     PetscCall(PetscLayoutSetUp(vertexLayout));
2268   }
2269 
2270   PetscCall(PetscSNPrintf(path, sizeof(path), "%" PetscInt_FMT, d));
2271   PetscCall(PetscViewerHDF5PushGroup(viewer, path));
2272 
2273   /* create coneSizesSection from stored IS coneSizes */
2274   {
2275     const PetscInt *coneSizes;
2276 
2277     PetscCall(ISCreate(comm, &coneSizesIS));
2278     PetscCall(PetscObjectSetName((PetscObject)coneSizesIS, coneSizesName));
2279     if (pointsLayout) PetscCall(ISSetLayout(coneSizesIS, pointsLayout));
2280     PetscCall(ISLoad(coneSizesIS, viewer));
2281     if (!pointsLayout) PetscCall(ISGetLayout(coneSizesIS, &pointsLayout));
2282     PetscCall(ISGetIndices(coneSizesIS, &coneSizes));
2283     PetscCall(PetscSectionCreate(comm, &coneSizesSection));
2284     //TODO different start ?
2285     PetscCall(PetscSectionSetChart(coneSizesSection, 0, pointsLayout->n));
2286     for (s = 0; s < pointsLayout->n; ++s) PetscCall(PetscSectionSetDof(coneSizesSection, s, coneSizes[s]));
2287     PetscCall(PetscSectionSetUp(coneSizesSection));
2288     PetscCall(ISRestoreIndices(coneSizesIS, &coneSizes));
2289     {
2290       PetscLayout tmp = NULL;
2291 
2292       /* We need to keep the layout until the end of function */
2293       PetscCall(PetscLayoutReference((PetscLayout)pointsLayout, &tmp));
2294     }
2295     PetscCall(ISDestroy(&coneSizesIS));
2296   }
2297 
2298   /* use value layout of coneSizesSection as layout of cones and orientations */
2299   {
2300     PetscLayout conesLayout;
2301 
2302     PetscCall(PetscSectionGetValueLayout(comm, coneSizesSection, &conesLayout));
2303     PetscCall(ISCreate(comm, &conesIS));
2304     PetscCall(ISCreate(comm, &orientationsIS));
2305     PetscCall(PetscObjectSetName((PetscObject)conesIS, conesName));
2306     PetscCall(PetscObjectSetName((PetscObject)orientationsIS, orientationsName));
2307     PetscCall(PetscLayoutDuplicate(conesLayout, &conesIS->map));
2308     PetscCall(PetscLayoutDuplicate(conesLayout, &orientationsIS->map));
2309     PetscCall(ISLoad(conesIS, viewer));
2310     PetscCall(ISLoad(orientationsIS, viewer));
2311     PetscCall(PetscLayoutDestroy(&conesLayout));
2312   }
2313 
2314   /* check assertion that layout of points is the same as point layout of coneSizesSection */
2315   {
2316     PetscLayout pointsLayout0;
2317     PetscBool   flg;
2318 
2319     PetscCall(PetscSectionGetPointLayout(comm, coneSizesSection, &pointsLayout0));
2320     PetscCall(PetscLayoutCompare(pointsLayout, pointsLayout0, &flg));
2321     PetscCheck(flg, comm, PETSC_ERR_PLIB, "points layout != coneSizesSection point layout");
2322     PetscCall(PetscLayoutDestroy(&pointsLayout0));
2323   }
2324   PetscCall(PetscViewerHDF5PopGroup(viewer));
2325   PetscCall(PetscLayoutDestroy(&pointsLayout));
2326 
2327   layer->d                = d;
2328   layer->conesIS          = conesIS;
2329   layer->coneSizesSection = coneSizesSection;
2330   layer->orientationsIS   = orientationsIS;
2331   layer->vertexLayout     = vertexLayout;
2332   PetscFunctionReturn(PETSC_SUCCESS);
2333 }
2334 
2335 static PetscErrorCode PlexLayerDistribute_Private(PlexLayer layer, PetscSF cellLocalToGlobalSF)
2336 {
2337   IS           newConesIS, newOrientationsIS;
2338   PetscSection newConeSizesSection;
2339   MPI_Comm     comm;
2340 
2341   PetscFunctionBegin;
2342   PetscCall(PetscObjectGetComm((PetscObject)cellLocalToGlobalSF, &comm));
2343   PetscCall(PetscSectionCreate(comm, &newConeSizesSection));
2344   //TODO rename to something like ISDistribute() with optional PetscSection argument
2345   PetscCall(DMPlexDistributeFieldIS(NULL, cellLocalToGlobalSF, layer->coneSizesSection, layer->conesIS, newConeSizesSection, &newConesIS));
2346   PetscCall(DMPlexDistributeFieldIS(NULL, cellLocalToGlobalSF, layer->coneSizesSection, layer->orientationsIS, newConeSizesSection, &newOrientationsIS));
2347 
2348   PetscCall(PetscObjectSetName((PetscObject)newConeSizesSection, ((PetscObject)layer->coneSizesSection)->name));
2349   PetscCall(PetscObjectSetName((PetscObject)newConesIS, ((PetscObject)layer->conesIS)->name));
2350   PetscCall(PetscObjectSetName((PetscObject)newOrientationsIS, ((PetscObject)layer->orientationsIS)->name));
2351   PetscCall(PetscSectionDestroy(&layer->coneSizesSection));
2352   PetscCall(ISDestroy(&layer->conesIS));
2353   PetscCall(ISDestroy(&layer->orientationsIS));
2354   layer->coneSizesSection = newConeSizesSection;
2355   layer->conesIS          = newConesIS;
2356   layer->orientationsIS   = newOrientationsIS;
2357   PetscFunctionReturn(PETSC_SUCCESS);
2358 }
2359 
2360 //TODO share code with DMPlexBuildFromCellListParallel()
2361 #include <petsc/private/hashseti.h>
2362 static PetscErrorCode PlexLayerCreateSFs_Private(PlexLayer layer, PetscSF *vertexOverlapSF, PetscSF *sfXC)
2363 {
2364   PetscLayout     vertexLayout     = layer->vertexLayout;
2365   PetscSection    coneSection      = layer->coneSizesSection;
2366   IS              cellVertexData   = layer->conesIS;
2367   IS              coneOrientations = layer->orientationsIS;
2368   PetscSF         vl2gSF, vOverlapSF;
2369   PetscInt       *verticesAdj;
2370   PetscInt        i, n, numVerticesAdj;
2371   const PetscInt *cvd, *co = NULL;
2372   MPI_Comm        comm;
2373 
2374   PetscFunctionBegin;
2375   PetscCall(PetscObjectGetComm((PetscObject)coneSection, &comm));
2376   PetscCall(PetscSectionGetStorageSize(coneSection, &n));
2377   {
2378     PetscInt n0;
2379 
2380     PetscCall(ISGetLocalSize(cellVertexData, &n0));
2381     PetscCheck(n == n0, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local size of IS cellVertexData = %" PetscInt_FMT " != %" PetscInt_FMT " = storage size of PetscSection coneSection", n0, n);
2382     PetscCall(ISGetIndices(cellVertexData, &cvd));
2383   }
2384   if (coneOrientations) {
2385     PetscInt n0;
2386 
2387     PetscCall(ISGetLocalSize(coneOrientations, &n0));
2388     PetscCheck(n == n0, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local size of IS coneOrientations = %" PetscInt_FMT " != %" PetscInt_FMT " = storage size of PetscSection coneSection", n0, n);
2389     PetscCall(ISGetIndices(coneOrientations, &co));
2390   }
2391   /* Get/check global number of vertices */
2392   {
2393     PetscInt NVerticesInCells = PETSC_INT_MIN;
2394 
2395     /* NVerticesInCells = max(cellVertexData) + 1 */
2396     for (i = 0; i < n; i++)
2397       if (cvd[i] > NVerticesInCells) NVerticesInCells = cvd[i];
2398     ++NVerticesInCells;
2399     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, comm));
2400 
2401     if (vertexLayout->n == PETSC_DECIDE && vertexLayout->N == PETSC_DECIDE) vertexLayout->N = NVerticesInCells;
2402     else
2403       PetscCheck(vertexLayout->N == PETSC_DECIDE || vertexLayout->N >= NVerticesInCells, comm, PETSC_ERR_ARG_SIZ, "Specified global number of vertices %" PetscInt_FMT " must be greater than or equal to the number of unique vertices in the cell-vertex dataset %" PetscInt_FMT,
2404                  vertexLayout->N, NVerticesInCells);
2405     PetscCall(PetscLayoutSetUp(vertexLayout));
2406   }
2407   /* Find locally unique vertices in cellVertexData */
2408   {
2409     PetscHSetI vhash;
2410     PetscInt   off = 0;
2411 
2412     PetscCall(PetscHSetICreate(&vhash));
2413     for (i = 0; i < n; ++i) PetscCall(PetscHSetIAdd(vhash, cvd[i]));
2414     PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj));
2415     PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj));
2416     PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj));
2417     PetscAssert(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Assertion failed: off == numVerticesAdj (%" PetscInt_FMT " != %" PetscInt_FMT ")", off, numVerticesAdj);
2418     PetscCall(PetscHSetIDestroy(&vhash));
2419   }
2420   /* We must sort vertices to preserve numbering */
2421   PetscCall(PetscSortInt(numVerticesAdj, verticesAdj));
2422   /* Connect locally unique vertices with star forest */
2423   PetscCall(PetscSFCreateByMatchingIndices(vertexLayout, numVerticesAdj, verticesAdj, NULL, 0, numVerticesAdj, verticesAdj, NULL, 0, &vl2gSF, &vOverlapSF));
2424   PetscCall(PetscObjectSetName((PetscObject)vOverlapSF, "overlapSF"));
2425   PetscCall(PetscObjectSetName((PetscObject)vl2gSF, "localToGlobalSF"));
2426 
2427   PetscCall(PetscFree(verticesAdj));
2428   *vertexOverlapSF = vOverlapSF;
2429   *sfXC            = vl2gSF;
2430   PetscFunctionReturn(PETSC_SUCCESS);
2431 }
2432 
2433 static PetscErrorCode PlexLayerCreateCellSFs_Private(PlexLayer layer, PetscSF *cellOverlapSF, PetscSF *cellLocalToGlobalSF)
2434 {
2435   PetscSection coneSection = layer->coneSizesSection;
2436   PetscInt     nCells;
2437   MPI_Comm     comm;
2438 
2439   PetscFunctionBegin;
2440   PetscCall(PetscObjectGetComm((PetscObject)coneSection, &comm));
2441   {
2442     PetscInt cStart;
2443 
2444     PetscCall(PetscSectionGetChart(coneSection, &cStart, &nCells));
2445     PetscCheck(cStart == 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "coneSection must start at 0");
2446   }
2447   /* Create overlapSF as empty SF with the right number of roots */
2448   PetscCall(PetscSFCreate(comm, cellOverlapSF));
2449   PetscCall(PetscSFSetGraph(*cellOverlapSF, nCells, 0, NULL, PETSC_USE_POINTER, NULL, PETSC_USE_POINTER));
2450   PetscCall(PetscSFSetUp(*cellOverlapSF));
2451   /* Create localToGlobalSF as identity mapping */
2452   {
2453     PetscLayout map;
2454 
2455     PetscCall(PetscLayoutCreateFromSizes(comm, nCells, PETSC_DECIDE, 1, &map));
2456     PetscCall(PetscSFCreateFromLayouts(map, map, cellLocalToGlobalSF));
2457     PetscCall(PetscSFSetUp(*cellLocalToGlobalSF));
2458     PetscCall(PetscLayoutDestroy(&map));
2459   }
2460   PetscFunctionReturn(PETSC_SUCCESS);
2461 }
2462 
2463 static PetscErrorCode DMPlexTopologyBuildFromLayers_Private(DM dm, PetscInt depth, PlexLayer *layers, IS strataPermutation)
2464 {
2465   const PetscInt *permArr;
2466   PetscInt        d, nPoints;
2467   MPI_Comm        comm;
2468 
2469   PetscFunctionBegin;
2470   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2471   PetscCall(ISGetIndices(strataPermutation, &permArr));
2472 
2473   /* Count points, strata offsets and cones offsets (taking strataPermutation into account) */
2474   {
2475     PetscInt stratumOffset = 0;
2476     PetscInt conesOffset   = 0;
2477 
2478     for (d = 0; d <= depth; d++) {
2479       const PetscInt  e = permArr[d];
2480       const PlexLayer l = layers[e];
2481       PetscInt        lo, n, size;
2482 
2483       PetscCall(PetscSectionGetChart(l->coneSizesSection, &lo, &n));
2484       PetscCall(PetscSectionGetStorageSize(l->coneSizesSection, &size));
2485       PetscCheck(lo == 0, comm, PETSC_ERR_PLIB, "starting point should be 0 in coneSizesSection %" PetscInt_FMT, d);
2486       l->offset      = stratumOffset;
2487       l->conesOffset = conesOffset;
2488       stratumOffset += n;
2489       conesOffset += size;
2490     }
2491     nPoints = stratumOffset;
2492   }
2493 
2494   /* Set interval for all plex points */
2495   //TODO we should store starting point of plex
2496   PetscCall(DMPlexSetChart(dm, 0, nPoints));
2497 
2498   /* Set up plex coneSection from layer coneSections */
2499   {
2500     PetscSection coneSection;
2501 
2502     PetscCall(DMPlexGetConeSection(dm, &coneSection));
2503     for (d = 0; d <= depth; d++) {
2504       const PlexLayer l = layers[d];
2505       PetscInt        n, q;
2506 
2507       PetscCall(PetscSectionGetChart(l->coneSizesSection, NULL, &n));
2508       for (q = 0; q < n; q++) {
2509         const PetscInt p = l->offset + q;
2510         PetscInt       coneSize;
2511 
2512         PetscCall(PetscSectionGetDof(l->coneSizesSection, q, &coneSize));
2513         PetscCall(PetscSectionSetDof(coneSection, p, coneSize));
2514       }
2515     }
2516   }
2517   //TODO this is terrible, DMSetUp_Plex() should be DMPlexSetUpSections() or so
2518   PetscCall(DMSetUp(dm));
2519 
2520   /* Renumber cones points from layer-global numbering to plex-local numbering */
2521   {
2522     PetscInt *cones, *ornts;
2523 
2524     PetscCall(DMPlexGetCones(dm, &cones));
2525     PetscCall(DMPlexGetConeOrientations(dm, &ornts));
2526     for (d = 1; d <= depth; d++) {
2527       const PlexLayer l = layers[d];
2528       PetscInt        i, lConesSize;
2529       PetscInt       *lCones;
2530       const PetscInt *lOrnts;
2531       PetscInt       *pCones = &cones[l->conesOffset];
2532       PetscInt       *pOrnts = &ornts[l->conesOffset];
2533 
2534       PetscCall(PetscSectionGetStorageSize(l->coneSizesSection, &lConesSize));
2535       /* Get cones in local plex numbering */
2536       {
2537         ISLocalToGlobalMapping l2g;
2538         PetscLayout            vertexLayout = l->vertexLayout;
2539         PetscSF                vertexSF     = layers[d - 1]->l2gSF; /* vertices of this layer are cells of previous layer */
2540         const PetscInt        *gCones;
2541         PetscInt               lConesSize0;
2542 
2543         PetscCall(ISGetLocalSize(l->conesIS, &lConesSize0));
2544         PetscCheck(lConesSize0 == lConesSize, comm, PETSC_ERR_PLIB, "layer %" PetscInt_FMT " size(conesIS) = %" PetscInt_FMT " != %" PetscInt_FMT " = storageSize(coneSizesSection)", d, lConesSize0, lConesSize);
2545         PetscCall(ISGetLocalSize(l->orientationsIS, &lConesSize0));
2546         PetscCheck(lConesSize0 == lConesSize, comm, PETSC_ERR_PLIB, "layer %" PetscInt_FMT " size(orientationsIS) = %" PetscInt_FMT " != %" PetscInt_FMT " = storageSize(coneSizesSection)", d, lConesSize0, lConesSize);
2547 
2548         PetscCall(PetscMalloc1(lConesSize, &lCones));
2549         PetscCall(ISGetIndices(l->conesIS, &gCones));
2550         PetscCall(ISLocalToGlobalMappingCreateSF(vertexSF, vertexLayout->rstart, &l2g));
2551         PetscCall(ISGlobalToLocalMappingApply(l2g, IS_GTOLM_MASK, lConesSize, gCones, &lConesSize0, lCones));
2552         PetscCheck(lConesSize0 == lConesSize, comm, PETSC_ERR_PLIB, "global to local does not cover all indices (%" PetscInt_FMT " of %" PetscInt_FMT ")", lConesSize0, lConesSize);
2553         PetscCall(ISLocalToGlobalMappingDestroy(&l2g));
2554         PetscCall(ISRestoreIndices(l->conesIS, &gCones));
2555       }
2556       PetscCall(ISGetIndices(l->orientationsIS, &lOrnts));
2557       /* Set cones, need to add stratum offset */
2558       for (i = 0; i < lConesSize; i++) {
2559         pCones[i] = lCones[i] + layers[d - 1]->offset; /* cone points of current layer are points of previous layer */
2560         pOrnts[i] = lOrnts[i];
2561       }
2562       PetscCall(PetscFree(lCones));
2563       PetscCall(ISRestoreIndices(l->orientationsIS, &lOrnts));
2564     }
2565   }
2566   PetscCall(DMPlexSymmetrize(dm));
2567   PetscCall(DMPlexStratify(dm));
2568   PetscCall(ISRestoreIndices(strataPermutation, &permArr));
2569   PetscFunctionReturn(PETSC_SUCCESS);
2570 }
2571 
2572 static PetscErrorCode PlexLayerConcatenateSFs_Private(MPI_Comm comm, PetscInt depth, PlexLayer layers[], IS strataPermutation, PetscSF *overlapSF, PetscSF *l2gSF)
2573 {
2574   PetscInt        d;
2575   PetscSF        *osfs, *lsfs;
2576   PetscInt       *leafOffsets;
2577   const PetscInt *permArr;
2578 
2579   PetscFunctionBegin;
2580   PetscCall(ISGetIndices(strataPermutation, &permArr));
2581   PetscCall(PetscCalloc3(depth + 1, &osfs, depth + 1, &lsfs, depth + 1, &leafOffsets));
2582   for (d = 0; d <= depth; d++) {
2583     const PetscInt e = permArr[d];
2584 
2585     PetscAssert(e == layers[e]->d, PETSC_COMM_SELF, PETSC_ERR_PLIB, "assertion: e == layers[e]->d");
2586     osfs[d]        = layers[e]->overlapSF;
2587     lsfs[d]        = layers[e]->l2gSF;
2588     leafOffsets[d] = layers[e]->offset;
2589   }
2590   PetscCall(PetscSFConcatenate(comm, depth + 1, osfs, PETSCSF_CONCATENATE_ROOTMODE_LOCAL, leafOffsets, overlapSF));
2591   PetscCall(PetscSFConcatenate(comm, depth + 1, lsfs, PETSCSF_CONCATENATE_ROOTMODE_GLOBAL, leafOffsets, l2gSF));
2592   PetscCall(PetscFree3(osfs, lsfs, leafOffsets));
2593   PetscCall(ISRestoreIndices(strataPermutation, &permArr));
2594   PetscFunctionReturn(PETSC_SUCCESS);
2595 }
2596 
2597 // Parallel load of topology
2598 static PetscErrorCode DMPlexTopologyLoad_HDF5_Private(DM dm, PetscViewer viewer, PetscSF *sfXC)
2599 {
2600   PlexLayer  *layers;
2601   IS          strataPermutation;
2602   PetscLayout pointsLayout;
2603   PetscInt    depth;
2604   PetscInt    d;
2605   MPI_Comm    comm;
2606 
2607   PetscFunctionBegin;
2608   {
2609     PetscInt dim;
2610 
2611     PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "depth", PETSC_INT, NULL, &depth));
2612     PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "cell_dim", PETSC_INT, NULL, &dim));
2613     PetscCall(DMSetDimension(dm, dim));
2614   }
2615   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2616 
2617   PetscCall(PetscInfo(dm, "Loading DM %s in parallel\n", dm->hdr.name));
2618   {
2619     IS spOnComm;
2620 
2621     PetscCall(ISCreate(comm, &spOnComm));
2622     PetscCall(PetscObjectSetName((PetscObject)spOnComm, "permutation"));
2623     PetscCall(ISLoad(spOnComm, viewer));
2624     /* have the same serial IS on every rank */
2625     PetscCall(ISAllGather(spOnComm, &strataPermutation));
2626     PetscCall(PetscObjectSetName((PetscObject)strataPermutation, ((PetscObject)spOnComm)->name));
2627     PetscCall(ISDestroy(&spOnComm));
2628   }
2629 
2630   /* Create layers, load raw data for each layer */
2631   PetscCall(PetscViewerHDF5PushGroup(viewer, "strata"));
2632   PetscCall(PetscMalloc1(depth + 1, &layers));
2633   for (d = depth, pointsLayout = NULL; d >= 0; pointsLayout = layers[d]->vertexLayout, d--) {
2634     PetscCall(PlexLayerCreate_Private(&layers[d]));
2635     PetscCall(PlexLayerLoad_Private(layers[d], viewer, d, pointsLayout));
2636   }
2637   PetscCall(PetscViewerHDF5PopGroup(viewer)); /* strata */
2638 
2639   for (d = depth; d >= 0; d--) {
2640     /* Redistribute cells and vertices for each applicable layer */
2641     if (d < depth) PetscCall(PlexLayerDistribute_Private(layers[d], layers[d]->l2gSF));
2642     /* Create vertex overlap SF and vertex localToGlobal SF for each applicable layer */
2643     if (d > 0) PetscCall(PlexLayerCreateSFs_Private(layers[d], &layers[d - 1]->overlapSF, &layers[d - 1]->l2gSF));
2644   }
2645   /* Build trivial SFs for the cell layer as well */
2646   PetscCall(PlexLayerCreateCellSFs_Private(layers[depth], &layers[depth]->overlapSF, &layers[depth]->l2gSF));
2647 
2648   /* Build DMPlex topology from the layers */
2649   PetscCall(DMPlexTopologyBuildFromLayers_Private(dm, depth, layers, strataPermutation));
2650 
2651   /* Build overall point SF alias overlap SF */
2652   {
2653     PetscSF overlapSF;
2654 
2655     PetscCall(PlexLayerConcatenateSFs_Private(comm, depth, layers, strataPermutation, &overlapSF, sfXC));
2656     PetscCall(DMSetPointSF(dm, overlapSF));
2657     PetscCall(PetscSFDestroy(&overlapSF));
2658   }
2659 
2660   for (d = depth; d >= 0; d--) PetscCall(PlexLayerDestroy(&layers[d]));
2661   PetscCall(PetscFree(layers));
2662   PetscCall(ISDestroy(&strataPermutation));
2663   PetscFunctionReturn(PETSC_SUCCESS);
2664 }
2665 
2666 PetscErrorCode DMPlexTopologyLoad_HDF5_Internal(DM dm, PetscViewer viewer, PetscSF *sfXC)
2667 {
2668   DMPlexStorageVersion version;
2669   const char          *topologydm_name;
2670   char                 group[PETSC_MAX_PATH_LEN];
2671   PetscSF              sfwork = NULL;
2672 
2673   PetscFunctionBegin;
2674   PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name));
2675   PetscCall(PetscViewerHDF5GetDMPlexStorageVersionReading(viewer, &version));
2676   if (DMPlexStorageVersionGE(version, 2, 0, 0)) {
2677     PetscCall(PetscSNPrintf(group, sizeof(group), "topologies/%s", topologydm_name));
2678   } else {
2679     PetscCall(PetscStrncpy(group, "/", sizeof(group)));
2680   }
2681   PetscCall(PetscViewerHDF5PushGroup(viewer, group));
2682 
2683   PetscCall(PetscViewerHDF5PushGroup(viewer, "topology"));
2684   if (version->major < 3) {
2685     PetscCall(DMPlexTopologyLoad_HDF5_Legacy_Private(dm, viewer, &sfwork));
2686   } else {
2687     /* since DMPlexStorageVersion 3.0.0 */
2688     PetscCall(DMPlexTopologyLoad_HDF5_Private(dm, viewer, &sfwork));
2689   }
2690   PetscCall(PetscViewerHDF5PopGroup(viewer)); /* "topology" */
2691 
2692   if (DMPlexStorageVersionGE(version, 2, 0, 0)) {
2693     DM          distdm;
2694     PetscSF     distsf;
2695     const char *distribution_name;
2696     PetscBool   exists;
2697 
2698     PetscCall(DMPlexDistributionGetName(dm, &distribution_name));
2699     /* this group is guaranteed to be present since DMPlexStorageVersion 2.1.0 */
2700     PetscCall(PetscViewerHDF5PushGroup(viewer, "distributions"));
2701     PetscCall(PetscViewerHDF5HasGroup(viewer, NULL, &exists));
2702     if (exists) {
2703       PetscCall(PetscViewerHDF5PushGroup(viewer, distribution_name));
2704       PetscCall(DMPlexDistributionLoad_HDF5_Private(dm, viewer, sfwork, &distsf, &distdm));
2705       if (distdm) {
2706         PetscCall(DMPlexReplace_Internal(dm, &distdm));
2707         PetscCall(PetscSFDestroy(&sfwork));
2708         sfwork = distsf;
2709       }
2710       PetscCall(PetscViewerHDF5PopGroup(viewer)); /* distribution_name */
2711     }
2712     PetscCall(PetscViewerHDF5PopGroup(viewer)); /* "distributions" */
2713   }
2714   if (sfXC) {
2715     *sfXC = sfwork;
2716   } else {
2717     PetscCall(PetscSFDestroy(&sfwork));
2718   }
2719 
2720   PetscCall(PetscViewerHDF5PopGroup(viewer));
2721   PetscFunctionReturn(PETSC_SUCCESS);
2722 }
2723 
2724 /* If the file is old, it not only has different path to the coordinates, but   */
2725 /* does not contain coordinateDMs, so must fall back to the old implementation. */
2726 static PetscErrorCode DMPlexCoordinatesLoad_HDF5_Legacy_Private(DM dm, PetscViewer viewer)
2727 {
2728   PetscSection coordSection;
2729   Vec          coordinates;
2730   PetscReal    lengthScale;
2731   PetscInt     spatialDim, N, numVertices, vStart, vEnd, v;
2732   PetscMPIInt  rank;
2733 
2734   PetscFunctionBegin;
2735   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
2736   /* Read geometry */
2737   PetscCall(PetscViewerHDF5PushGroup(viewer, "/geometry"));
2738   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &coordinates));
2739   PetscCall(PetscObjectSetName((PetscObject)coordinates, "vertices"));
2740   {
2741     /* Force serial load */
2742     PetscCall(PetscViewerHDF5ReadSizes(viewer, "vertices", &spatialDim, &N));
2743     PetscCall(VecSetSizes(coordinates, rank == 0 ? N : 0, N));
2744     PetscCall(VecSetBlockSize(coordinates, spatialDim));
2745   }
2746   PetscCall(VecLoad(coordinates, viewer));
2747   PetscCall(PetscViewerHDF5PopGroup(viewer));
2748   PetscCall(DMPlexGetScale(dm, PETSC_UNIT_LENGTH, &lengthScale));
2749   PetscCall(VecScale(coordinates, 1.0 / lengthScale));
2750   PetscCall(VecGetLocalSize(coordinates, &numVertices));
2751   PetscCall(VecGetBlockSize(coordinates, &spatialDim));
2752   numVertices /= spatialDim;
2753   /* Create coordinates */
2754   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2755   PetscCheck(numVertices == vEnd - vStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of coordinates loaded %" PetscInt_FMT " does not match number of vertices %" PetscInt_FMT, numVertices, vEnd - vStart);
2756   PetscCall(DMGetCoordinateSection(dm, &coordSection));
2757   PetscCall(PetscSectionSetNumFields(coordSection, 1));
2758   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spatialDim));
2759   PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd));
2760   for (v = vStart; v < vEnd; ++v) {
2761     PetscCall(PetscSectionSetDof(coordSection, v, spatialDim));
2762     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spatialDim));
2763   }
2764   PetscCall(PetscSectionSetUp(coordSection));
2765   PetscCall(DMSetCoordinates(dm, coordinates));
2766   PetscCall(VecDestroy(&coordinates));
2767   PetscFunctionReturn(PETSC_SUCCESS);
2768 }
2769 
2770 PetscErrorCode DMPlexCoordinatesLoad_HDF5_Internal(DM dm, PetscViewer viewer, PetscSF sfXC)
2771 {
2772   DMPlexStorageVersion version;
2773   DM                   cdm;
2774   Vec                  coords;
2775   PetscInt             blockSize;
2776   PetscReal            lengthScale;
2777   PetscSF              lsf;
2778   const char          *topologydm_name;
2779   char                *coordinatedm_name, *coordinates_name;
2780 
2781   PetscFunctionBegin;
2782   PetscCall(PetscViewerHDF5GetDMPlexStorageVersionReading(viewer, &version));
2783   if (!DMPlexStorageVersionGE(version, 2, 0, 0)) {
2784     PetscCall(DMPlexCoordinatesLoad_HDF5_Legacy_Private(dm, viewer));
2785     PetscFunctionReturn(PETSC_SUCCESS);
2786   }
2787   /* else: since DMPlexStorageVersion 2.0.0 */
2788   PetscCheck(sfXC, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_NULL, "PetscSF must be given for parallel load");
2789   PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name));
2790   PetscCall(PetscViewerHDF5PushGroup(viewer, "topologies"));
2791   PetscCall(PetscViewerHDF5PushGroup(viewer, topologydm_name));
2792   PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "coordinateDMName", PETSC_STRING, NULL, &coordinatedm_name));
2793   PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "coordinatesName", PETSC_STRING, NULL, &coordinates_name));
2794   PetscCall(PetscViewerHDF5PopGroup(viewer));
2795   PetscCall(PetscViewerHDF5PopGroup(viewer));
2796   PetscCall(DMGetCoordinateDM(dm, &cdm));
2797   PetscCall(PetscObjectSetName((PetscObject)cdm, coordinatedm_name));
2798   PetscCall(PetscFree(coordinatedm_name));
2799   /* lsf: on-disk data -> in-memory local vector associated with cdm's local section */
2800   PetscCall(DMPlexSectionLoad(dm, viewer, cdm, sfXC, NULL, &lsf));
2801   PetscCall(DMCreateLocalVector(cdm, &coords));
2802   PetscCall(PetscObjectSetName((PetscObject)coords, coordinates_name));
2803   PetscCall(PetscFree(coordinates_name));
2804   PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_NATIVE));
2805   PetscCall(DMPlexLocalVectorLoad(dm, viewer, cdm, lsf, coords));
2806   PetscCall(PetscViewerPopFormat(viewer));
2807   PetscCall(DMPlexGetScale(dm, PETSC_UNIT_LENGTH, &lengthScale));
2808   PetscCall(VecScale(coords, 1.0 / lengthScale));
2809   PetscCall(DMSetCoordinatesLocal(dm, coords));
2810   PetscCall(VecGetBlockSize(coords, &blockSize));
2811   PetscCall(DMSetCoordinateDim(dm, blockSize));
2812   PetscCall(VecDestroy(&coords));
2813   PetscCall(PetscSFDestroy(&lsf));
2814   PetscFunctionReturn(PETSC_SUCCESS);
2815 }
2816 
2817 PetscErrorCode DMPlexLoad_HDF5_Internal(DM dm, PetscViewer viewer)
2818 {
2819   DMPlexStorageVersion version;
2820 
2821   PetscFunctionBegin;
2822   PetscCall(PetscViewerHDF5GetDMPlexStorageVersionReading(viewer, &version));
2823   PetscCall(PetscInfo(dm, "Loading DM %s storage version %d.%d.%d\n", dm->hdr.name, version->major, version->minor, version->subminor));
2824   if (!DMPlexStorageVersionGE(version, 2, 0, 0)) {
2825     PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, NULL));
2826     PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, NULL));
2827     PetscCall(DMPlexCoordinatesLoad_HDF5_Legacy_Private(dm, viewer));
2828   } else {
2829     PetscSF sfXC;
2830 
2831     /* since DMPlexStorageVersion 2.0.0 */
2832     PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, &sfXC));
2833     PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, sfXC));
2834     PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, sfXC));
2835     PetscCall(PetscSFDestroy(&sfXC));
2836   }
2837   PetscFunctionReturn(PETSC_SUCCESS);
2838 }
2839 
2840 static PetscErrorCode DMPlexSectionLoad_HDF5_Internal_CreateDataSF(PetscSection rootSection, PetscLayout layout, PetscInt globalOffsets[], PetscSection leafSection, PetscSF *sectionSF)
2841 {
2842   MPI_Comm  comm;
2843   PetscInt  pStart, pEnd, p, m;
2844   PetscInt *goffs, *ilocal;
2845   PetscBool rootIncludeConstraints, leafIncludeConstraints;
2846 
2847   PetscFunctionBegin;
2848   PetscCall(PetscObjectGetComm((PetscObject)leafSection, &comm));
2849   PetscCall(PetscSectionGetChart(leafSection, &pStart, &pEnd));
2850   PetscCall(PetscSectionGetIncludesConstraints(rootSection, &rootIncludeConstraints));
2851   PetscCall(PetscSectionGetIncludesConstraints(leafSection, &leafIncludeConstraints));
2852   if (rootIncludeConstraints && leafIncludeConstraints) PetscCall(PetscSectionGetStorageSize(leafSection, &m));
2853   else PetscCall(PetscSectionGetConstrainedStorageSize(leafSection, &m));
2854   PetscCall(PetscMalloc1(m, &ilocal));
2855   PetscCall(PetscMalloc1(m, &goffs));
2856   /* Currently, PetscSFDistributeSection() returns globalOffsets[] only */
2857   /* for the top-level section (not for each field), so one must have   */
2858   /* rootSection->pointMajor == PETSC_TRUE.                             */
2859   PetscCheck(rootSection->pointMajor, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for field major ordering");
2860   /* Currently, we also assume that leafSection->pointMajor == PETSC_TRUE. */
2861   PetscCheck(leafSection->pointMajor, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for field major ordering");
2862   for (p = pStart, m = 0; p < pEnd; ++p) {
2863     PetscInt        dof, cdof, i, j, off, goff;
2864     const PetscInt *cinds;
2865 
2866     PetscCall(PetscSectionGetDof(leafSection, p, &dof));
2867     if (dof < 0) continue;
2868     goff = globalOffsets[p - pStart];
2869     PetscCall(PetscSectionGetOffset(leafSection, p, &off));
2870     PetscCall(PetscSectionGetConstraintDof(leafSection, p, &cdof));
2871     PetscCall(PetscSectionGetConstraintIndices(leafSection, p, &cinds));
2872     for (i = 0, j = 0; i < dof; ++i) {
2873       PetscBool constrained = (PetscBool)(j < cdof && i == cinds[j]);
2874 
2875       if (!constrained || (leafIncludeConstraints && rootIncludeConstraints)) {
2876         ilocal[m]  = off++;
2877         goffs[m++] = goff++;
2878       } else if (leafIncludeConstraints && !rootIncludeConstraints) ++off;
2879       else if (!leafIncludeConstraints && rootIncludeConstraints) ++goff;
2880       if (constrained) ++j;
2881     }
2882   }
2883   PetscCall(PetscSFCreate(comm, sectionSF));
2884   PetscCall(PetscSFSetFromOptions(*sectionSF));
2885   PetscCall(PetscSFSetGraphLayout(*sectionSF, layout, m, ilocal, PETSC_OWN_POINTER, goffs));
2886   PetscCall(PetscFree(goffs));
2887   PetscFunctionReturn(PETSC_SUCCESS);
2888 }
2889 
2890 PetscErrorCode DMPlexSectionLoad_HDF5_Internal(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sfXB, PetscSF *gsf, PetscSF *lsf)
2891 {
2892   MPI_Comm     comm;
2893   PetscMPIInt  size, rank;
2894   const char  *topologydm_name;
2895   const char  *sectiondm_name;
2896   PetscSection sectionA, sectionB;
2897   PetscBool    has;
2898   PetscInt     nX, n, i;
2899   PetscSF      sfAB;
2900 
2901   PetscFunctionBegin;
2902   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2903   PetscCallMPI(MPI_Comm_size(comm, &size));
2904   PetscCallMPI(MPI_Comm_rank(comm, &rank));
2905   PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name));
2906   PetscCall(PetscObjectGetName((PetscObject)sectiondm, &sectiondm_name));
2907   PetscCall(PetscViewerHDF5PushGroup(viewer, "topologies"));
2908   PetscCall(PetscViewerHDF5PushGroup(viewer, topologydm_name));
2909   PetscCall(PetscViewerHDF5PushGroup(viewer, "dms"));
2910   PetscCall(PetscViewerHDF5PushGroup(viewer, sectiondm_name));
2911   /* A: on-disk points                        */
2912   /* X: list of global point numbers, [0, NX) */
2913   /* B: plex points                           */
2914   /* Load raw section (sectionA)              */
2915   PetscCall(PetscSectionCreate(comm, &sectionA));
2916   PetscCall(PetscViewerHDF5HasGroup(viewer, "section", &has));
2917   if (has) PetscCall(PetscSectionLoad(sectionA, viewer));
2918   else {
2919     // TODO If section is missing, create the default affine section with dim dofs on each vertex. Use PetscSplitOwnership() to split vertices.
2920     //   How do I know the total number of vertices?
2921     PetscInt dim, Nf = 1, Nv, nv = PETSC_DECIDE;
2922 
2923     PetscCall(DMGetDimension(dm, &dim));
2924     PetscCall(DMPlexGetDepthStratumGlobalSize(dm, 0, &Nv));
2925     PetscCall(PetscSectionSetNumFields(sectionA, Nf));
2926     PetscCall(PetscSectionSetFieldName(sectionA, 0, "Cartesian"));
2927     PetscCall(PetscSectionSetFieldComponents(sectionA, 0, dim));
2928     for (PetscInt c = 0; c < dim; ++c) {
2929       char axis = 'X' + (char)c;
2930 
2931       PetscCall(PetscSectionSetComponentName(sectionA, 0, c, &axis));
2932     }
2933     PetscCall(PetscSplitOwnership(comm, &nv, &Nv));
2934     PetscCall(PetscSectionSetChart(sectionA, 0, nv));
2935     for (PetscInt p = 0; p < nv; ++p) {
2936       PetscCall(PetscSectionSetDof(sectionA, p, dim));
2937       PetscCall(PetscSectionSetFieldDof(sectionA, p, 0, dim));
2938     }
2939     PetscCall(PetscSectionSetUp(sectionA));
2940   }
2941   PetscCall(PetscSectionGetChart(sectionA, NULL, &n));
2942 /* Create sfAB: A -> B */
2943 #if defined(PETSC_USE_DEBUG)
2944   {
2945     PetscInt N, N1;
2946 
2947     PetscCall(PetscViewerHDF5ReadSizes(viewer, "order", NULL, &N1));
2948     PetscCallMPI(MPIU_Allreduce(&n, &N, 1, MPIU_INT, MPI_SUM, comm));
2949     PetscCheck(N1 == N, comm, PETSC_ERR_ARG_SIZ, "Mismatching sizes: on-disk order array size (%" PetscInt_FMT ") != number of loaded section points (%" PetscInt_FMT ")", N1, N);
2950   }
2951 #endif
2952   {
2953     IS              orderIS;
2954     const PetscInt *gpoints;
2955     PetscSF         sfXA, sfAX;
2956     PetscLayout     layout;
2957     PetscSFNode    *owners, *buffer;
2958     PetscInt        nleaves;
2959     PetscInt       *ilocal;
2960     PetscSFNode    *iremote;
2961 
2962     /* Create sfAX: A -> X */
2963     PetscCall(ISCreate(comm, &orderIS));
2964     PetscCall(PetscObjectSetName((PetscObject)orderIS, "order"));
2965     PetscCall(PetscLayoutSetLocalSize(orderIS->map, n));
2966     PetscCall(ISLoad(orderIS, viewer));
2967     PetscCall(PetscLayoutCreate(comm, &layout));
2968     PetscCall(PetscSFGetGraph(sfXB, &nX, NULL, NULL, NULL));
2969     PetscCall(PetscLayoutSetLocalSize(layout, nX));
2970     PetscCall(PetscLayoutSetBlockSize(layout, 1));
2971     PetscCall(PetscLayoutSetUp(layout));
2972     PetscCall(PetscSFCreate(comm, &sfXA));
2973     PetscCall(ISGetIndices(orderIS, &gpoints));
2974     PetscCall(PetscSFSetGraphLayout(sfXA, layout, n, NULL, PETSC_OWN_POINTER, gpoints));
2975     PetscCall(ISRestoreIndices(orderIS, &gpoints));
2976     PetscCall(ISDestroy(&orderIS));
2977     PetscCall(PetscLayoutDestroy(&layout));
2978     PetscCall(PetscMalloc1(n, &owners));
2979     PetscCall(PetscMalloc1(nX, &buffer));
2980     for (i = 0; i < n; ++i) {
2981       owners[i].rank  = rank;
2982       owners[i].index = i;
2983     }
2984     for (i = 0; i < nX; ++i) {
2985       buffer[i].rank  = -1;
2986       buffer[i].index = -1;
2987     }
2988     PetscCall(PetscSFReduceBegin(sfXA, MPIU_SF_NODE, owners, buffer, MPI_MAXLOC));
2989     PetscCall(PetscSFReduceEnd(sfXA, MPIU_SF_NODE, owners, buffer, MPI_MAXLOC));
2990     PetscCall(PetscSFDestroy(&sfXA));
2991     PetscCall(PetscFree(owners));
2992     for (i = 0, nleaves = 0; i < nX; ++i)
2993       if (buffer[i].rank >= 0) nleaves++;
2994     PetscCall(PetscMalloc1(nleaves, &ilocal));
2995     PetscCall(PetscMalloc1(nleaves, &iremote));
2996     for (i = 0, nleaves = 0; i < nX; ++i) {
2997       if (buffer[i].rank >= 0) {
2998         ilocal[nleaves]        = i;
2999         iremote[nleaves].rank  = buffer[i].rank;
3000         iremote[nleaves].index = buffer[i].index;
3001         nleaves++;
3002       }
3003     }
3004     PetscCall(PetscFree(buffer));
3005     PetscCall(PetscSFCreate(comm, &sfAX));
3006     PetscCall(PetscSFSetFromOptions(sfAX));
3007     PetscCall(PetscSFSetGraph(sfAX, n, nleaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
3008     PetscCall(PetscSFCompose(sfAX, sfXB, &sfAB));
3009     PetscCall(PetscSFDestroy(&sfAX));
3010   }
3011   PetscCall(PetscViewerHDF5PopGroup(viewer));
3012   PetscCall(PetscViewerHDF5PopGroup(viewer));
3013   PetscCall(PetscViewerHDF5PopGroup(viewer));
3014   PetscCall(PetscViewerHDF5PopGroup(viewer));
3015   /* Create plex section (sectionB) */
3016   PetscCall(DMGetLocalSection(sectiondm, &sectionB));
3017   if (lsf || gsf) {
3018     PetscLayout layout;
3019     PetscInt    M, m;
3020     PetscInt   *offsetsA;
3021     PetscBool   includesConstraintsA;
3022 
3023     PetscCall(PetscSFDistributeSection(sfAB, sectionA, &offsetsA, sectionB));
3024     PetscCall(PetscSectionGetIncludesConstraints(sectionA, &includesConstraintsA));
3025     if (includesConstraintsA) PetscCall(PetscSectionGetStorageSize(sectionA, &m));
3026     else PetscCall(PetscSectionGetConstrainedStorageSize(sectionA, &m));
3027     PetscCallMPI(MPIU_Allreduce(&m, &M, 1, MPIU_INT, MPI_SUM, comm));
3028     PetscCall(PetscLayoutCreate(comm, &layout));
3029     PetscCall(PetscLayoutSetSize(layout, M));
3030     PetscCall(PetscLayoutSetUp(layout));
3031     if (lsf) {
3032       PetscSF lsfABdata;
3033 
3034       PetscCall(DMPlexSectionLoad_HDF5_Internal_CreateDataSF(sectionA, layout, offsetsA, sectionB, &lsfABdata));
3035       *lsf = lsfABdata;
3036     }
3037     if (gsf) {
3038       PetscSection gsectionB, gsectionB1;
3039       PetscBool    includesConstraintsB;
3040       PetscSF      gsfABdata, pointsf;
3041 
3042       PetscCall(DMGetGlobalSection(sectiondm, &gsectionB1));
3043       PetscCall(PetscSectionGetIncludesConstraints(gsectionB1, &includesConstraintsB));
3044       PetscCall(DMGetPointSF(sectiondm, &pointsf));
3045       PetscCall(PetscSectionCreateGlobalSection(sectionB, pointsf, PETSC_TRUE, includesConstraintsB, PETSC_TRUE, &gsectionB));
3046       PetscCall(DMPlexSectionLoad_HDF5_Internal_CreateDataSF(sectionA, layout, offsetsA, gsectionB, &gsfABdata));
3047       PetscCall(PetscSectionDestroy(&gsectionB));
3048       *gsf = gsfABdata;
3049     }
3050     PetscCall(PetscLayoutDestroy(&layout));
3051     PetscCall(PetscFree(offsetsA));
3052   } else {
3053     PetscCall(PetscSFDistributeSection(sfAB, sectionA, NULL, sectionB));
3054   }
3055   PetscCall(PetscSFDestroy(&sfAB));
3056   PetscCall(PetscSectionDestroy(&sectionA));
3057   PetscFunctionReturn(PETSC_SUCCESS);
3058 }
3059 
3060 PetscErrorCode DMPlexVecLoad_HDF5_Internal(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
3061 {
3062   MPI_Comm           comm;
3063   const char        *topologydm_name;
3064   const char        *sectiondm_name;
3065   const char        *vec_name;
3066   Vec                vecA;
3067   PetscInt           mA, m, bs;
3068   const PetscInt    *ilocal;
3069   const PetscScalar *src;
3070   PetscScalar       *dest;
3071 
3072   PetscFunctionBegin;
3073   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3074   PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name));
3075   PetscCall(PetscObjectGetName((PetscObject)sectiondm, &sectiondm_name));
3076   PetscCall(PetscObjectGetName((PetscObject)vec, &vec_name));
3077   PetscCall(PetscViewerHDF5PushGroup(viewer, "topologies"));
3078   PetscCall(PetscViewerHDF5PushGroup(viewer, topologydm_name));
3079   PetscCall(PetscViewerHDF5PushGroup(viewer, "dms"));
3080   PetscCall(PetscViewerHDF5PushGroup(viewer, sectiondm_name));
3081   PetscCall(PetscViewerHDF5PushGroup(viewer, "vecs"));
3082   PetscCall(PetscViewerHDF5PushGroup(viewer, vec_name));
3083   PetscCall(VecCreate(comm, &vecA));
3084   PetscCall(PetscObjectSetName((PetscObject)vecA, vec_name));
3085   PetscCall(PetscSFGetGraph(sf, &mA, &m, &ilocal, NULL));
3086   /* Check consistency */
3087   {
3088     PetscSF  pointsf, pointsf1;
3089     PetscInt m1, i, j;
3090 
3091     PetscCall(DMGetPointSF(dm, &pointsf));
3092     PetscCall(DMGetPointSF(sectiondm, &pointsf1));
3093     PetscCheck(pointsf1 == pointsf, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatching point SFs for dm and sectiondm");
3094 #if defined(PETSC_USE_DEBUG)
3095     {
3096       PetscInt MA, MA1;
3097 
3098       PetscCallMPI(MPIU_Allreduce(&mA, &MA, 1, MPIU_INT, MPI_SUM, comm));
3099       PetscCall(PetscViewerHDF5ReadSizes(viewer, vec_name, NULL, &MA1));
3100       PetscCheck(MA1 == MA, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total SF root size (%" PetscInt_FMT ") != On-disk vector data size (%" PetscInt_FMT ")", MA, MA1);
3101     }
3102 #endif
3103     PetscCall(VecGetLocalSize(vec, &m1));
3104     PetscCheck(m1 >= m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Target vector size (%" PetscInt_FMT ") < SF leaf size (%" PetscInt_FMT ")", m1, m);
3105     for (i = 0; i < m; ++i) {
3106       j = ilocal ? ilocal[i] : i;
3107       PetscCheck(j >= 0 && j < m1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Leaf's %" PetscInt_FMT "-th index, %" PetscInt_FMT ", not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", i, j, (PetscInt)0, m1);
3108     }
3109   }
3110   PetscCall(VecSetSizes(vecA, mA, PETSC_DECIDE));
3111   PetscCall(VecLoad(vecA, viewer));
3112   PetscCall(VecGetArrayRead(vecA, &src));
3113   PetscCall(VecGetArray(vec, &dest));
3114   PetscCall(PetscSFBcastBegin(sf, MPIU_SCALAR, src, dest, MPI_REPLACE));
3115   PetscCall(PetscSFBcastEnd(sf, MPIU_SCALAR, src, dest, MPI_REPLACE));
3116   PetscCall(VecRestoreArray(vec, &dest));
3117   PetscCall(VecRestoreArrayRead(vecA, &src));
3118   PetscCall(VecDestroy(&vecA));
3119   PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "blockSize", PETSC_INT, NULL, (void *)&bs));
3120   PetscCall(VecSetBlockSize(vec, bs));
3121   PetscCall(PetscViewerHDF5PopGroup(viewer));
3122   PetscCall(PetscViewerHDF5PopGroup(viewer));
3123   PetscCall(PetscViewerHDF5PopGroup(viewer));
3124   PetscCall(PetscViewerHDF5PopGroup(viewer));
3125   PetscCall(PetscViewerHDF5PopGroup(viewer));
3126   PetscCall(PetscViewerHDF5PopGroup(viewer));
3127   PetscFunctionReturn(PETSC_SUCCESS);
3128 }
3129