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