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