Actual source code: plexhdf5.c

  1: #include <petsc/private/dmpleximpl.h>
  2: #include <petsc/private/isimpl.h>
  3: #include <petsc/private/vecimpl.h>
  4: #include <petsc/private/viewerhdf5impl.h>
  5: #include <petsclayouthdf5.h>

  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 *);

 12: PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);

 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: }

 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;

 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: }

 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: }

 56: static PetscErrorCode PetscViewerGetAttachedVersion_Private(PetscViewer viewer, const char key[], DMPlexStorageVersion *v)
 57: {
 58:   PetscContainer cont;

 60:   PetscFunctionBegin;
 61:   PetscCall(PetscObjectQuery((PetscObject)viewer, key, (PetscObject *)&cont));
 62:   *v = NULL;
 63:   if (cont) PetscCall(PetscContainerGetPointer(cont, (void **)v));
 64:   PetscFunctionReturn(PETSC_SUCCESS);
 65: }

 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: */
 76: static PetscErrorCode PetscViewerCheckVersion_Private(PetscViewer viewer, DMPlexStorageVersion version)
 77: {
 78:   PetscBool valid = PETSC_FALSE;

 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: }

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: }

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: }

151: /*@C
152:   PetscViewerHDF5SetDMPlexStorageVersionWriting - Set the storage version for writing

154:   Logically collective

156:   Input Parameters:
157: + viewer  - The `PetscViewer`
158: - version - The storage format version

160:   Level: advanced

162:   Note:
163:   The version has major, minor, and subminor integers. Parallel operations are only available for version 3.0.0.

165: .seealso: [](ch_dmbase), `DM`, `PetscViewerHDF5GetDMPlexStorageVersionWriting()`, `PetscViewerHDF5GetDMPlexStorageVersionReading()`, `PetscViewerHDF5SetDMPlexStorageVersionReading()`
166: @*/
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];

174:   PetscFunctionBegin;
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;

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:   }

187:   PetscCall(PetscViewerHDF5HasAttribute(viewer, NULL, ATTR_NAME, &fileHasVersion));
188:   if (fileHasVersion) {
189:     PetscBool flg;
190:     char     *tmp;

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: }

208: /*@C
209:   PetscViewerHDF5GetDMPlexStorageVersionWriting - Get the storage version for writing

211:   Logically collective

213:   Input Parameter:
214: . viewer - The `PetscViewer`

216:   Output Parameter:
217: . version - The storage format version

219:   Options Database Keys:
220: . -dm_plex_view_hdf5_storage_version <num> - Overrides the storage format version

222:   Level: advanced

224:   Note:
225:   The version has major, minor, and subminor integers. Parallel operations are only available for version 3.0.0.

227: .seealso: [](ch_dmbase), `DM`, `PetscViewerHDF5SetDMPlexStorageVersionWriting()`, `PetscViewerHDF5GetDMPlexStorageVersionReading()`, `PetscViewerHDF5SetDMPlexStorageVersionReading()`
228: @*/
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];

235:   PetscFunctionBegin;
237:   PetscAssertPointer(version, 2);
238:   PetscCall(PetscViewerGetAttachedVersion_Private(viewer, DMPLEX_STORAGE_VERSION_WRITING_KEY, version));
239:   if (*version) PetscFunctionReturn(PETSC_SUCCESS);

241:   PetscCall(PetscStrncpy(fileVersion, DMPLEX_STORAGE_VERSION_STABLE, sizeof(fileVersion)));
242:   PetscCall(PetscViewerHDF5HasAttribute(viewer, NULL, ATTR_NAME, &fileHasVersion));
243:   if (fileHasVersion) {
244:     char *tmp;

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;

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: }

268: /*@C
269:   PetscViewerHDF5SetDMPlexStorageVersionReading - Set the storage version for reading

271:   Logically collective

273:   Input Parameters:
274: + viewer  - The `PetscViewer`
275: - version - The storage format version

277:   Level: advanced

279:   Note:
280:   The version has major, minor, and subminor integers. Parallel operations are only available for version 3.0.0.

282: .seealso: [](ch_dmbase), `DM`, `PetscViewerHDF5GetDMPlexStorageVersionReading()`, `PetscViewerHDF5GetDMPlexStorageVersionWriting()`, `PetscViewerHDF5SetDMPlexStorageVersionWriting()`
283: @*/
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];

291:   PetscFunctionBegin;
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;

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:   }

304:   PetscCall(PetscViewerHDF5HasAttribute(viewer, NULL, ATTR_NAME, &fileHasVersion));
305:   if (fileHasVersion) {
306:     char     *fileVersion;
307:     PetscBool flg;

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: }

322: /*@C
323:   PetscViewerHDF5GetDMPlexStorageVersionReading - Get the storage version for reading

325:   Logically collective

327:   Input Parameter:
328: . viewer - The `PetscViewer`

330:   Output Parameter:
331: . version - The storage format version

333:   Options Database Keys:
334: . -dm_plex_view_hdf5_storage_version <num> - Overrides the storage format version

336:   Level: advanced

338:   Note:
339:   The version has major, minor, and subminor integers. Parallel operations are only available for version 3.0.0.

341: .seealso: [](ch_dmbase), `DM`, `PetscViewerHDF5SetDMPlexStorageVersionReading()`, `PetscViewerHDF5GetDMPlexStorageVersionWriting()`, `PetscViewerHDF5SetDMPlexStorageVersionWriting()`
342: @*/
343: PetscErrorCode PetscViewerHDF5GetDMPlexStorageVersionReading(PetscViewer viewer, DMPlexStorageVersion *version)
344: {
345:   const char ATTR_NAME[] = "dmplex_storage_version";
346:   char      *defaultVersion;
347:   char      *versionString;

349:   PetscFunctionBegin;
351:   PetscAssertPointer(version, 2);
352:   PetscCall(PetscViewerGetAttachedVersion_Private(viewer, DMPLEX_STORAGE_VERSION_READING_KEY, version));
353:   if (*version) PetscFunctionReturn(PETSC_SUCCESS);

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: }

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: }

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;

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);

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: }

401: static PetscErrorCode DMSequenceView_HDF5(DM dm, const char seqname[], PetscInt seqnum, PetscScalar value, PetscViewer viewer)
402: {
403:   Vec         stamp;
404:   PetscMPIInt rank;

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;

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: }

435: PetscErrorCode DMSequenceLoad_HDF5_Internal(DM dm, const char seqname[], PetscInt seqnum, PetscScalar *value, PetscViewer viewer)
436: {
437:   Vec         stamp;
438:   PetscMPIInt rank;

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;

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: }

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;

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;

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;

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: }

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;

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;

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;

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;

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;

572:         if (!t) {
573:           PetscCall(PetscViewerHDF5PushGroup(viewer, fgroup));
574:         } else {
575:           char group[PETSC_MAX_PATH_LEN];

577:           PetscCall(PetscSNPrintf(group, PETSC_MAX_PATH_LEN, "%s_%" PetscInt_FMT, fgroup, t));
578:           PetscCall(PetscViewerHDF5PushGroup(viewer, group));
579:         }

581:         if (cutLabel) {
582:           const PetscScalar *ga;
583:           PetscScalar       *suba;
584:           PetscInt           gstart, subSize = 0, extSize = 0, subOff = 0, newOff = 0;

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;

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;

607:             PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
608:             if (gdof > 0) {
609:               PetscInt fdof, fc, f2, poff = 0;

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:         }

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:         }

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: }

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;

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));

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: }

709: PetscErrorCode VecView_Plex_HDF5_Native_Internal(Vec v, PetscViewer viewer)
710: {
711:   PetscBool isseq;

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: }

722: PetscErrorCode VecLoad_Plex_HDF5_Internal(Vec v, PetscViewer viewer)
723: {
724:   DM          dm;
725:   Vec         locv;
726:   const char *name;
727:   PetscInt    seqnum;

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: }

749: PetscErrorCode VecLoad_Plex_HDF5_Native_Internal(Vec v, PetscViewer viewer)
750: {
751:   DM       dm;
752:   PetscInt seqnum;

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: }

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;

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];

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);

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: }

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;

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;

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;

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;

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: }

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;

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: }

936: //TODO get this numbering right away without needing this function
937: /* Renumber global point numbers so that they are 0-based per stratum */
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;

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;

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;

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;

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: }

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;

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;

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:   }

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;

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];

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: }

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];

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));

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" */

1070:   if (DMPlexStorageVersionGE(version, 2, 1, 0)) {
1071:     const char *distribution_name;

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:   }

1082:   PetscCall(PetscViewerHDF5PopGroup(viewer));
1083:   PetscFunctionReturn(PETSC_SUCCESS);
1084: }

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;

1096:   PetscFunctionBegin;
1097:   *numCorners = 0;
1098:   PetscCall(DMGetDimension(dm, &dim));
1099:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1100:   PetscCall(ISGetIndices(globalCellNumbers, &gcell));

1102:   for (cell = cStart; cell < cEnd; ++cell) {
1103:     PetscInt *closure = NULL;
1104:     PetscInt  closureSize, v, Nc = 0;

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;

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;

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];

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: }

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;

1192:   PetscFunctionBegin;
1193:   PetscCall(PetscViewerHDF5PushGroup(viewer, "/viz"));
1194:   PetscCall(PetscViewerHDF5WriteGroup(viewer, NULL));

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;

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];

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: }

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;

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: }

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;

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: }

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;

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;

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;

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: }

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];

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;

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];

1511:       PetscCall(PetscSNPrintf(group, sizeof(group), "%" PetscInt_FMT, values[v]));
1512:       PetscCall(PetscViewerHDF5PushGroup(viewer, group));
1513:       PetscCall(DMLabelGetStratumIS(label, values[v], &stratumIS));

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: }

1541: /* We only write cells and vertices. Does this screw up parallel reading? */
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;

1548:   PetscFunctionBegin;
1549:   PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbers));
1550:   PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));

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:   }

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;

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;

1587:     PetscCall(DMPlexCreateRankField(dm, &v));
1588:     PetscCall(VecView(v, viewer));
1589:     PetscCall(VecDestroy(&v));
1590:   }
1591:   PetscCall(ISDestroy(&globalPointNumbers));
1592:   PetscFunctionReturn(PETSC_SUCCESS);
1593: }

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;

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;

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: }

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;

1661:   PetscFunctionBegin;
1662:   /* Check consistency */
1663:   {
1664:     PetscSF pointsf, pointsf1;

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;

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: }

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;

1725:   PetscFunctionBegin;
1726:   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1727:   /* Check consistency */
1728:   {
1729:     PetscSF pointsf, pointsf1;

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: }

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;

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;

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: }

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: }

1809: /*
1810:     A: on-disk points
1811:     X: global points [0, NX)
1812:     C: distributed plex points
1813: */
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;

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;

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: }

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;

1860:   PetscCall(PetscOptionsStringToInt(vname, &value));
1861:   PetscCall(ISCreate(comm, &stratumIS));
1862:   PetscCall(PetscObjectSetName((PetscObject)stratumIS, "indices"));
1863:   PetscCall(PetscViewerHDF5PushGroup(viewer, vname)); /* labels/<lname>/<vname> */

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));

1873:   if (ctx->sfXC) {
1874:     IS newStratumIS;

1876:     PetscCallHDF5(ReadLabelStratumHDF5_Distribute_Private, (stratumIS, ctx, &newStratumIS));
1877:     PetscCall(ISDestroy(&stratumIS));
1878:     stratumIS = newStratumIS;
1879:   }

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: }

1890: /* TODO: Fix this code, it is returning PETSc error codes when it should be translating them to herr_t codes */
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;

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: }

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;

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;

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: }

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;

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;

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;

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;

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);

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;

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;

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;

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: }

2120: // Serial load of topology
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;

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;

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: }

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;

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: }

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: }

2260: // Parallel load of a depth stratum
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;

2271:   PetscFunctionBegin;
2272:   coneSizesName    = "cone_sizes";
2273:   conesName        = "cones";
2274:   orientationsName = "orientations";
2275:   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));

2277:   /* query size of next lower depth stratum (next lower dimension) */
2278:   if (d > 0) {
2279:     PetscInt NVertices;

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:   }

2288:   PetscCall(PetscSNPrintf(path, sizeof(path), "%" PetscInt_FMT, d));
2289:   PetscCall(PetscViewerHDF5PushGroup(viewer, path));

2291:   /* create coneSizesSection from stored IS coneSizes */
2292:   {
2293:     const PetscInt *coneSizes;

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;

2310:       /* We need to keep the layout until the end of function */
2311:       PetscCall(PetscLayoutReference((PetscLayout)pointsLayout, &tmp));
2312:     }
2313:     PetscCall(ISDestroy(&coneSizesIS));
2314:   }

2316:   /* use value layout of coneSizesSection as layout of cones and orientations */
2317:   {
2318:     PetscLayout conesLayout;

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:   }

2332:   /* check assertion that layout of points is the same as point layout of coneSizesSection */
2333:   {
2334:     PetscLayout pointsLayout0;
2335:     PetscBool   flg;

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));

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: }

2353: static PetscErrorCode PlexLayerDistribute_Private(PlexLayer layer, PetscSF cellLocalToGlobalSF)
2354: {
2355:   IS           newConesIS, newOrientationsIS;
2356:   PetscSection newConeSizesSection;
2357:   MPI_Comm     comm;

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));

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: }

2378: //TODO share code with DMPlexBuildFromCellListParallel()
2379: #include <petsc/private/hashseti.h>
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;

2392:   PetscFunctionBegin;
2393:   PetscCall(PetscObjectGetComm((PetscObject)coneSection, &comm));
2394:   PetscCall(PetscSectionGetStorageSize(coneSection, &n));
2395:   {
2396:     PetscInt n0;

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;

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;

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));

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;

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"));

2445:   PetscCall(PetscFree(verticesAdj));
2446:   *vertexOverlapSF = vOverlapSF;
2447:   *sfXC            = vl2gSF;
2448:   PetscFunctionReturn(PETSC_SUCCESS);
2449: }

2451: static PetscErrorCode PlexLayerCreateCellSFs_Private(PlexLayer layer, PetscSF *cellOverlapSF, PetscSF *cellLocalToGlobalSF)
2452: {
2453:   PetscSection coneSection = layer->coneSizesSection;
2454:   PetscInt     nCells;
2455:   MPI_Comm     comm;

2457:   PetscFunctionBegin;
2458:   PetscCall(PetscObjectGetComm((PetscObject)coneSection, &comm));
2459:   {
2460:     PetscInt cStart;

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;

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: }

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;

2487:   PetscFunctionBegin;
2488:   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2489:   PetscCall(ISGetIndices(strataPermutation, &permArr));

2491:   /* Count points, strata offsets and cones offsets (taking strataPermutation into account) */
2492:   {
2493:     PetscInt stratumOffset = 0;
2494:     PetscInt conesOffset   = 0;

2496:     for (d = 0; d <= depth; d++) {
2497:       const PetscInt  e = permArr[d];
2498:       const PlexLayer l = layers[e];
2499:       PetscInt        lo, n, size;

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:   }

2512:   /* Set interval for all plex points */
2513:   //TODO we should store starting point of plex
2514:   PetscCall(DMPlexSetChart(dm, 0, nPoints));

2516:   /* Set up plex coneSection from layer coneSections */
2517:   {
2518:     PetscSection coneSection;

2520:     PetscCall(DMPlexGetConeSection(dm, &coneSection));
2521:     for (d = 0; d <= depth; d++) {
2522:       const PlexLayer l = layers[d];
2523:       PetscInt        n, q;

2525:       PetscCall(PetscSectionGetChart(l->coneSizesSection, NULL, &n));
2526:       for (q = 0; q < n; q++) {
2527:         const PetscInt p = l->offset + q;
2528:         PetscInt       coneSize;

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));

2538:   /* Renumber cones points from layer-global numbering to plex-local numbering */
2539:   {
2540:     PetscInt *cones, *ornts;

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];

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;

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);

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: }

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;

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];

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: }

2615: // Parallel load of topology
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;

2625:   PetscFunctionBegin;
2626:   {
2627:     PetscInt dim;

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));

2635:   PetscCall(PetscInfo(dm, "Loading DM %s in parallel\n", dm->hdr.name));
2636:   {
2637:     IS spOnComm;

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:   }

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 */

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));

2666:   /* Build DMPlex topology from the layers */
2667:   PetscCall(DMPlexTopologyBuildFromLayers_Private(dm, depth, layers, strataPermutation));

2669:   /* Build overall point SF alias overlap SF */
2670:   {
2671:     PetscSF overlapSF;

2673:     PetscCall(PlexLayerConcatenateSFs_Private(comm, depth, layers, strataPermutation, &overlapSF, sfXC));
2674:     PetscCall(DMSetPointSF(dm, overlapSF));
2675:     PetscCall(PetscSFDestroy(&overlapSF));
2676:   }

2678:   for (d = depth; d >= 0; d--) PetscCall(PlexLayerDestroy(&layers[d]));
2679:   PetscCall(PetscFree(layers));
2680:   PetscCall(ISDestroy(&strataPermutation));
2681:   PetscFunctionReturn(PETSC_SUCCESS);
2682: }

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;

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));

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" */

2710:   if (DMPlexStorageVersionGE(version, 2, 0, 0)) {
2711:     DM          distdm;
2712:     PetscSF     distsf;
2713:     const char *distribution_name;
2714:     PetscBool   exists;

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:   }

2738:   PetscCall(PetscViewerHDF5PopGroup(viewer));
2739:   PetscFunctionReturn(PETSC_SUCCESS);
2740: }

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. */
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;

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: }

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;

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: }

2835: PetscErrorCode DMPlexLoad_HDF5_Internal(DM dm, PetscViewer viewer)
2836: {
2837:   DMPlexStorageVersion version;

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;

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: }

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;

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;

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]);

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: }

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;

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;

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;

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;

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;

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;

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;

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;

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: }

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;

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;

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;

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: }