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