Actual source code: ex48.c
1: static char help[] = "Tests HDF5 attribute I/O.\n\n";
3: #include <petscviewerhdf5.h>
4: #include <petscvec.h>
6: static PetscInt n = 5; /* testing vector size */
7: static PetscBool verbose = PETSC_FALSE;
8: #define SLEN 128
10: /* sequence of unique absolute paths */
11: #define nap 9
12: static const char *apaths[nap] = {/* 0 */ "/",
13: "/g1",
14: "/g1/g2",
15: "/g1/nonExistingGroup1",
16: "/g1/g3",
17: /* 5 */ "/g1/g3/g4",
18: "/g1/nonExistingGroup2",
19: "/g1/nonExistingGroup2/g5",
20: "/g1/g6/g7"};
22: #define np 21
23: /* sequence of paths (absolute or relative); "<" encodes Pop */
24: static const char *paths[np] = {
25: /* 0 */
26: "/",
27: "/g1",
28: "/g1/g2",
29: "/g1/nonExistingGroup1",
30: "<",
31: /* 5 */
32: ".", /* /g1/g2 */
33: "<",
34: "<",
35: "g3", /* /g1/g3 */
36: "g4", /* /g1/g3/g4 */
37: /* 10 */
38: "<",
39: "<",
40: ".", /* /g1 */
41: "<",
42: "nonExistingGroup2", /* /g1/nonExistingG2 */
43: /* 15 */
44: "g5", /* /g1/nonExistingG2/g5 */
45: "<",
46: "<",
47: "g6/g7", /* /g1/g6/g7 */
48: "<",
49: /* 20 */
50: "<",
51: };
52: /* corresponding expected absolute paths - positions in abspath */
53: static const PetscInt paths2apaths[np] = {
54: /* 0 */
55: 0,
56: 1,
57: 2,
58: 3,
59: 2,
60: /* 5 */
61: 2,
62: 2,
63: 1,
64: 4,
65: 5,
66: /* 10 */
67: 4,
68: 1,
69: 1,
70: 1,
71: 6,
72: /* 15 */
73: 7,
74: 6,
75: 1,
76: 8,
77: 1,
78: /* 20 */
79: 0,
80: };
82: #define ns 4
83: /* for "" attribute will be stored to group, otherwise to given dataset */
84: static const char *datasets[ns] = {"", "x", "nonExistingVec", "y"};
86: /* beware this yields PETSC_FALSE for "" but group "" is interpreted as "/" */
87: static inline PetscErrorCode shouldExist(const char name[], PetscBool emptyExists, PetscBool *has)
88: {
89: size_t len = 0;
91: PetscFunctionBegin;
92: PetscCall(PetscStrlen(name, &len));
93: *has = emptyExists;
94: if (len) {
95: char *loc = NULL;
96: PetscCall(PetscStrstr(name, "nonExisting", &loc));
97: *has = PetscNot(loc);
98: }
99: PetscFunctionReturn(PETSC_SUCCESS);
100: }
102: static inline PetscErrorCode isPop(const char path[], PetscBool *has)
103: {
104: PetscFunctionBegin;
105: PetscCall(PetscStrcmp(path, "<", has));
106: PetscFunctionReturn(PETSC_SUCCESS);
107: }
109: static inline PetscErrorCode isDot(const char path[], PetscBool *has)
110: {
111: PetscFunctionBegin;
112: PetscCall(PetscStrcmp(path, ".", has));
113: PetscFunctionReturn(PETSC_SUCCESS);
114: }
116: static inline PetscErrorCode isRoot(const char path[], PetscBool *flg)
117: {
118: size_t len;
120: PetscFunctionBegin;
121: PetscCall(PetscStrlen(path, &len));
122: *flg = PetscNot(len);
123: if (!*flg) PetscCall(PetscStrcmp(path, "/", flg));
124: PetscFunctionReturn(PETSC_SUCCESS);
125: }
127: static inline PetscErrorCode compare(PetscDataType dt, void *ptr0, void *ptr1, PetscBool *flg)
128: {
129: PetscFunctionBegin;
130: switch (dt) {
131: case PETSC_INT:
132: *flg = (PetscBool)(*(PetscInt *)ptr0 == *(PetscInt *)ptr1);
133: if (verbose) {
134: if (*flg) {
135: PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT, *(PetscInt *)ptr0));
136: } else {
137: PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT " != %" PetscInt_FMT "\n", *(PetscInt *)ptr0, *(PetscInt *)ptr1));
138: }
139: }
140: break;
141: case PETSC_REAL:
142: *flg = (PetscBool)(*(PetscReal *)ptr0 == *(PetscReal *)ptr1);
143: if (verbose) {
144: if (*flg) {
145: PetscCall(PetscPrintf(PETSC_COMM_SELF, "%f", *(PetscReal *)ptr0));
146: } else {
147: PetscCall(PetscPrintf(PETSC_COMM_SELF, "%f != %f\n", *(PetscReal *)ptr0, *(PetscReal *)ptr1));
148: }
149: }
150: break;
151: case PETSC_BOOL:
152: *flg = (PetscBool)(*(PetscBool *)ptr0 == *(PetscBool *)ptr1);
153: if (verbose) {
154: if (*flg) {
155: PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s", PetscBools[*(PetscBool *)ptr0]));
156: } else {
157: PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s != %s\n", PetscBools[*(PetscBool *)ptr0], PetscBools[*(PetscBool *)ptr1]));
158: }
159: }
160: break;
161: case PETSC_STRING:
162: PetscCall(PetscStrcmp((const char *)ptr0, (const char *)ptr1, flg));
163: if (verbose) {
164: if (*flg) {
165: PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s", (char *)ptr0));
166: } else {
167: PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s != %s\n", (char *)ptr0, (char *)ptr1));
168: }
169: }
170: break;
171: default:
172: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "PetscDataType %s not handled here", PetscDataTypes[dt]);
173: }
174: PetscFunctionReturn(PETSC_SUCCESS);
175: }
177: static inline PetscErrorCode alterString(const char oldstr[], char str[])
178: {
179: size_t i, n;
181: PetscFunctionBegin;
182: PetscCall(PetscStrlen(oldstr, &n));
183: PetscCall(PetscStrncpy(str, oldstr, n + 1));
184: for (i = 0; i < n; i++) {
185: if (('A' <= str[i] && str[i] < 'Z') || ('a' <= str[i] && str[i] < 'z')) {
186: str[i]++;
187: break;
188: }
189: }
190: PetscFunctionReturn(PETSC_SUCCESS);
191: }
193: /* if name given, check dataset with this name exists under current group, otherwise just check current group exists */
194: /* flg: 0 doesn't exist, 1 group, 2 dataset */
195: static PetscErrorCode hasGroupOrDataset(PetscViewer viewer, const char path[], int *flg)
196: {
197: PetscBool has;
199: PetscFunctionBegin;
200: *flg = 0;
201: PetscCall(PetscViewerHDF5HasGroup(viewer, path, &has));
202: if (has) *flg = 1;
203: else {
204: PetscCall(PetscViewerHDF5HasDataset(viewer, path, &has));
205: if (has) *flg = 2;
206: }
207: PetscFunctionReturn(PETSC_SUCCESS);
208: }
210: #define nt 5 /* number of datatypes */
211: typedef struct _n_Capsule *Capsule;
212: struct _n_Capsule {
213: char names[nt][SLEN];
214: PetscDataType types[nt];
215: char typeNames[nt][SLEN];
216: size_t sizes[nt];
217: void *vals[nt];
218: PetscInt id, ntypes;
219: };
221: static PetscErrorCode CapsuleCreate(Capsule old, Capsule *newcapsule)
222: {
223: Capsule c;
224: PetscBool bool0 = PETSC_TRUE;
225: PetscInt int0 = -1;
226: PetscReal real0 = -1.1;
227: char str0[] = "Test String";
228: char nestr0[] = "NONEXISTING STRING"; /* this attribute shall be skipped for writing */
229: void *vals[nt] = {&bool0, &int0, &real0, str0, nestr0};
230: size_t sizes[nt] = {sizeof(bool0), sizeof(int0), sizeof(real0), sizeof(str0), sizeof(str0)};
231: PetscDataType types[nt] = {PETSC_BOOL, PETSC_INT, PETSC_REAL, PETSC_STRING, PETSC_STRING};
232: const char *tNames[nt] = {"bool", "int", "real", "str", "nonExisting"};
233: PetscInt t;
235: PetscFunctionBegin;
236: PetscCall(PetscNew(&c));
237: c->id = 0;
238: c->ntypes = nt;
239: if (old) {
240: /* alter values */
241: t = 0;
242: bool0 = PetscNot(*((PetscBool *)old->vals[t]));
243: t++;
244: int0 = *((PetscInt *)old->vals[t]) * -2;
245: t++;
246: real0 = *((PetscReal *)old->vals[t]) * -2.0;
247: t++;
248: PetscCall(alterString((const char *)old->vals[t], str0));
249: t++;
250: c->id = old->id + 1;
251: }
252: for (t = 0; t < nt; t++) {
253: c->sizes[t] = sizes[t];
254: c->types[t] = types[t];
255: PetscCall(PetscStrncpy(c->typeNames[t], tNames[t], sizeof(c->typeNames[t])));
256: PetscCall(PetscSNPrintf(c->names[t], SLEN, "attr_%" PetscInt_FMT "_%s", c->id, tNames[t]));
257: PetscCall(PetscMalloc(sizes[t], &c->vals[t]));
258: PetscCall(PetscMemcpy(c->vals[t], vals[t], sizes[t]));
259: }
260: *newcapsule = c;
261: PetscFunctionReturn(PETSC_SUCCESS);
262: }
263: #undef nt
265: static PetscErrorCode CapsuleWriteAttributes(Capsule c, PetscViewer v, const char parent[])
266: {
267: PetscBool flg = PETSC_FALSE;
269: PetscFunctionBegin;
270: for (PetscInt t = 0; t < c->ntypes; t++) {
271: PetscCall(shouldExist(c->names[t], PETSC_FALSE, &flg));
272: if (!flg) continue;
273: PetscCall(PetscViewerHDF5WriteAttribute(v, parent, c->names[t], c->types[t], c->vals[t]));
274: }
275: PetscFunctionReturn(PETSC_SUCCESS);
276: }
278: static PetscErrorCode CapsuleReadAndCompareAttributes(Capsule c, PetscViewer v, const char parent[])
279: {
280: const char *group;
281: int gd = 0;
282: PetscBool flg = PETSC_FALSE, hasAttr = PETSC_FALSE;
283: MPI_Comm comm;
285: PetscFunctionBegin;
286: PetscCall(PetscObjectGetComm((PetscObject)v, &comm));
287: PetscCall(PetscViewerHDF5GetGroup(v, NULL, &group));
288: PetscCall(hasGroupOrDataset(v, parent, &gd));
289: /* check correct existence of attributes */
290: for (PetscInt t = 0; t < c->ntypes; t++) {
291: const char *attribute = c->names[t];
292: PetscCall(shouldExist(attribute, PETSC_FALSE, &flg));
293: PetscCall(PetscViewerHDF5HasAttribute(v, parent, attribute, &hasAttr));
294: if (verbose) {
295: PetscCall(PetscPrintf(comm, " %-24s = ", attribute));
296: if (!hasAttr) PetscCall(PetscPrintf(comm, "---"));
297: }
298: PetscCheck(gd || !hasAttr, comm, PETSC_ERR_PLIB, "Attribute %s/%s/%s exists while its parent %s/%s doesn't exist", group, parent, attribute, group, parent);
299: PetscCheck(flg == hasAttr, comm, PETSC_ERR_PLIB, "Attribute %s/%s should exist? %s Exists? %s", parent, attribute, PetscBools[flg], PetscBools[hasAttr]);
301: /* check loaded attributes are the same as original */
302: if (hasAttr) {
303: char buffer[SLEN];
304: char *str;
305: void *ptr0;
306: /* check the stored data is the same as original */
307: //TODO datatype should better be output arg, not input
308: //TODO string attributes should probably have a separate function since the handling is different;
309: //TODO or maybe it should just accept string buffer rather than pointer to string
310: if (c->types[t] == PETSC_STRING) {
311: PetscCall(PetscViewerHDF5ReadAttribute(v, parent, attribute, c->types[t], NULL, &str));
312: ptr0 = str;
313: } else {
314: PetscCall(PetscViewerHDF5ReadAttribute(v, parent, attribute, c->types[t], NULL, &buffer));
315: ptr0 = &buffer;
316: }
317: PetscCall(compare(c->types[t], ptr0, c->vals[t], &flg));
318: PetscCheck(flg, comm, PETSC_ERR_PLIB, "Value of attribute %s/%s/%s is not equal to the original value", group, parent, attribute);
319: if (verbose) PetscCall(PetscPrintf(comm, " (=)"));
320: if (c->types[t] == PETSC_STRING) PetscCall(PetscFree(str));
321: }
322: if (verbose && gd) PetscCall(PetscPrintf(comm, "\n"));
323: }
324: PetscCall(PetscFree(group));
325: PetscFunctionReturn(PETSC_SUCCESS);
326: }
328: static PetscErrorCode CapsuleDestroy(Capsule *c)
329: {
330: PetscFunctionBegin;
331: if (!*c) PetscFunctionReturn(PETSC_SUCCESS);
332: for (PetscInt t = 0; t < (*c)->ntypes; t++) PetscCall(PetscFree((*c)->vals[t]));
333: PetscCall(PetscFree(*c));
334: PetscFunctionReturn(PETSC_SUCCESS);
335: }
337: static PetscErrorCode testGroupsDatasets(PetscViewer viewer)
338: {
339: char buf[PETSC_MAX_PATH_LEN];
340: Vec vecs[nap][ns];
341: PetscInt p, s;
342: PetscBool flg = PETSC_FALSE, flg1 = PETSC_FALSE, flg2 = PETSC_FALSE;
343: PetscRandom rand;
344: const char *filename;
345: MPI_Comm comm;
347: PetscFunctionBegin;
348: PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
349: PetscCall(PetscViewerFileGetName(viewer, &filename));
350: if (verbose) PetscCall(PetscPrintf(comm, "# TEST testGroupsDatasets\n"));
351: /* store random vectors */
352: PetscCall(PetscRandomCreate(comm, &rand));
353: PetscCall(PetscRandomSetInterval(rand, 0.0, 10.0));
354: PetscCall(PetscRandomSetFromOptions(rand));
355: PetscCall(PetscMemzero(vecs, nap * ns * sizeof(Vec)));
357: /* test dataset writing */
358: if (verbose) PetscCall(PetscPrintf(comm, "## WRITE PHASE\n"));
359: for (p = 0; p < np; p++) {
360: PetscCall(isPop(paths[p], &flg));
361: PetscCall(isDot(paths[p], &flg1));
362: PetscCall(shouldExist(apaths[paths2apaths[p]], PETSC_FALSE, &flg2));
363: if (flg) {
364: PetscCall(PetscViewerHDF5PopGroup(viewer));
365: } else {
366: PetscCall(PetscViewerHDF5PushGroup(viewer, paths[p]));
367: }
368: if (verbose) PetscCall(PetscPrintf(comm, "%-32s => %4s => %-32s should exist? %s\n", paths[p], flg ? "pop" : "push", apaths[paths2apaths[p]], PetscBools[flg2]));
369: if (flg || flg1 || !flg2) continue;
371: for (s = 0; s < ns; s++) {
372: Vec v;
374: PetscCall(shouldExist(datasets[s], PETSC_FALSE, &flg));
375: if (!flg) continue;
377: PetscCall(VecCreate(comm, &v));
378: PetscCall(PetscObjectSetName((PetscObject)v, datasets[s]));
379: PetscCall(VecSetSizes(v, n, PETSC_DECIDE));
380: PetscCall(VecSetFromOptions(v));
381: PetscCall(VecSetRandom(v, rand));
382: if (verbose) {
383: PetscReal min, max;
384: PetscCall(VecMin(v, NULL, &min));
385: PetscCall(VecMax(v, NULL, &max));
386: PetscCall(PetscPrintf(comm, " Create dataset %s/%s, keep in memory in vecs[%" PetscInt_FMT "][%" PetscInt_FMT "], min %.3e max %.3e\n", apaths[paths2apaths[p]], datasets[s], paths2apaths[p], s, min, max));
387: }
389: PetscCall(VecView(v, viewer));
390: vecs[paths2apaths[p]][s] = v;
391: }
392: }
393: PetscCall(PetscViewerFlush(viewer));
394: PetscCall(PetscRandomDestroy(&rand));
396: if (verbose) PetscCall(PetscPrintf(comm, "\n## READ PHASE\n"));
397: /* check correct existence of groups in file */
398: for (p = 0; p < np; p++) {
399: const char *group;
400: const char *expected = apaths[paths2apaths[p]];
402: /* check Push/Pop is correct */
403: PetscCall(isPop(paths[p], &flg));
404: if (flg) {
405: PetscCall(PetscViewerHDF5PopGroup(viewer));
406: } else {
407: PetscCall(PetscViewerHDF5PushGroup(viewer, paths[p]));
408: }
409: PetscCall(PetscViewerHDF5GetGroup(viewer, NULL, &group));
410: PetscCall(PetscViewerHDF5HasGroup(viewer, NULL, &flg1));
411: if (verbose) PetscCall(PetscPrintf(comm, "%-32s => %4s => %-32s exists? %s\n", paths[p], flg ? "pop" : "push", group, PetscBools[flg1]));
412: PetscCall(PetscStrcmp(group, expected, &flg2));
413: PetscCheck(flg2, comm, PETSC_ERR_PLIB, "Current group %s not equal to expected %s", group, expected);
414: PetscCall(shouldExist(group, PETSC_TRUE, &flg2));
415: PetscCheck(flg1 == flg2, comm, PETSC_ERR_PLIB, "Group %s should exist? %s Exists in %s? %s", group, PetscBools[flg2], filename, PetscBools[flg1]);
416: PetscCall(PetscFree(group));
417: }
419: /* check existence of datasets; compare loaded vectors with original ones */
420: for (p = 0; p < np; p++) {
421: const char *group;
423: /* check Push/Pop is correct */
424: PetscCall(isPop(paths[p], &flg));
425: if (flg) {
426: PetscCall(PetscViewerHDF5PopGroup(viewer));
427: } else {
428: PetscCall(PetscViewerHDF5PushGroup(viewer, paths[p]));
429: }
430: PetscCall(PetscViewerHDF5GetGroup(viewer, NULL, &group));
431: PetscCall(PetscViewerHDF5HasGroup(viewer, NULL, &flg));
432: if (verbose) PetscCall(PetscPrintf(comm, "Has %s group? %s\n", group, PetscBools[flg]));
433: for (s = 0; s < ns; s++) {
434: const char *name = datasets[s];
435: char *fullname = buf;
437: /* check correct existence of datasets in file */
438: PetscCall(PetscSNPrintf(fullname, sizeof(buf), "%s/%s", group, name));
439: PetscCall(shouldExist(name, PETSC_FALSE, &flg1));
440: flg1 = (PetscBool)(flg && flg1); /* both group and dataset need to exist */
441: PetscCall(PetscViewerHDF5HasDataset(viewer, name, &flg2));
442: if (verbose) PetscCall(PetscPrintf(comm, " %s dataset? %s", fullname, PetscBools[flg2]));
443: PetscCheck(flg2 == flg1, comm, PETSC_ERR_PLIB, "Dataset %s should exist? %s Exists in %s? %s", fullname, PetscBools[flg1], filename, PetscBools[flg2]);
445: if (flg2) {
446: Vec v;
447: /* check loaded Vec is the same as original */
448: PetscCall(VecCreate(comm, &v));
449: PetscCall(PetscObjectSetName((PetscObject)v, name));
450: PetscCall(VecLoad(v, viewer));
451: PetscCall(VecEqual(v, vecs[paths2apaths[p]][s], &flg1));
452: PetscCheck(flg1, comm, PETSC_ERR_PLIB, "Dataset %s in %s is not equal to the original Vec", fullname, filename);
453: if (verbose) PetscCall(PetscPrintf(comm, " (=)"));
454: PetscCall(VecDestroy(&v));
455: }
456: if (verbose) PetscCall(PetscPrintf(comm, "\n"));
457: }
458: PetscCall(PetscFree(group));
459: }
460: PetscCall(PetscViewerFlush(viewer));
461: for (p = 0; p < nap; p++)
462: for (s = 0; s < ns; s++) PetscCall(VecDestroy(&vecs[p][s]));
463: if (verbose) PetscCall(PetscPrintf(comm, "# END testGroupsDatasets\n\n"));
464: PetscFunctionReturn(PETSC_SUCCESS);
465: }
467: static inline PetscErrorCode formPath(PetscBool relativize, const char path[], const char dataset[], char buf[], size_t bufsize)
468: {
469: PetscBool isroot = PETSC_FALSE;
471: PetscFunctionBegin;
472: PetscCall(isRoot(path, &isroot));
473: if (relativize) {
474: if (isroot) {
475: PetscCall(PetscStrncpy(buf, dataset, bufsize));
476: } else {
477: /* skip initial '/' in paths[p] if prefix given */
478: PetscCall(PetscSNPrintf(buf, bufsize, "%s/%s", path + 1, dataset));
479: }
480: } else {
481: PetscCall(PetscSNPrintf(buf, bufsize, "%s/%s", isroot ? "" : path, dataset));
482: }
483: PetscFunctionReturn(PETSC_SUCCESS);
484: }
486: /* test attribute writing, existence checking and reading, use absolute paths */
487: static PetscErrorCode testAttributesAbsolutePath(PetscViewer viewer, const char prefix[])
488: {
489: char buf[PETSC_MAX_PATH_LEN];
490: Capsule capsules[nap][ns], c = NULL, old = NULL;
491: PetscInt p, s;
492: PetscBool flg = PETSC_FALSE, flg1 = PETSC_FALSE;
493: MPI_Comm comm;
495: PetscFunctionBegin;
496: PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
497: if (verbose) {
498: if (prefix) {
499: PetscCall(PetscPrintf(comm, "# TEST testAttributesAbsolutePath, prefix=\"%s\"\n", prefix));
500: } else {
501: PetscCall(PetscPrintf(comm, "# TEST testAttributesAbsolutePath\n"));
502: }
503: PetscCall(PetscPrintf(comm, "## WRITE PHASE\n"));
504: }
505: PetscCall(PetscMemzero(capsules, nap * ns * sizeof(Capsule)));
507: /* test attribute writing */
508: if (prefix) PetscCall(PetscViewerHDF5PushGroup(viewer, prefix));
509: for (p = 0; p < np; p++)
510: for (s = 0; s < ns; s++) {
511: /* we test only absolute paths here */
512: PetscCall(PetscViewerHDF5PathIsRelative(paths[p], PETSC_FALSE, &flg));
513: if (flg) continue;
514: {
515: const char *group;
517: PetscCall(PetscViewerHDF5GetGroup(viewer, NULL, &group));
518: PetscCall(PetscStrcmp(group, prefix, &flg));
519: PetscCheck(flg, comm, PETSC_ERR_PLIB, "prefix %s not equal to pushed group %s", prefix, group);
520: PetscCall(PetscFree(group));
521: }
522: PetscCall(formPath((PetscBool)!!prefix, paths[p], datasets[s], buf, sizeof(buf)));
523: PetscCall(shouldExist(buf, PETSC_TRUE, &flg));
524: if (!flg) continue;
526: if (verbose) {
527: if (prefix) {
528: PetscCall(PetscPrintf(comm, "Write attributes to %s/%s\n", prefix, buf));
529: } else {
530: PetscCall(PetscPrintf(comm, "Write attributes to %s\n", buf));
531: }
532: }
534: PetscCall(CapsuleCreate(old, &c));
535: PetscCall(CapsuleWriteAttributes(c, viewer, buf));
536: PetscCheck(!capsules[paths2apaths[p]][s], comm, PETSC_ERR_PLIB, "capsules[%" PetscInt_FMT "][%" PetscInt_FMT "] gets overwritten for %s", paths2apaths[p], s, buf);
537: capsules[paths2apaths[p]][s] = c;
538: old = c;
539: }
540: if (prefix) PetscCall(PetscViewerHDF5PopGroup(viewer));
541: PetscCall(PetscViewerFlush(viewer));
543: if (verbose) PetscCall(PetscPrintf(comm, "\n## READ PHASE\n"));
544: if (prefix) PetscCall(PetscViewerHDF5PushGroup(viewer, prefix));
545: for (p = 0; p < np; p++)
546: for (s = 0; s < ns; s++) {
547: /* we test only absolute paths here */
548: PetscCall(PetscViewerHDF5PathIsRelative(paths[p], PETSC_FALSE, &flg));
549: if (flg) continue;
551: /* check existence of given group/dataset */
552: PetscCall(formPath((PetscBool)!!prefix, paths[p], datasets[s], buf, sizeof(buf)));
553: PetscCall(shouldExist(buf, PETSC_TRUE, &flg));
554: if (verbose) {
555: if (prefix) {
556: PetscCall(PetscPrintf(comm, "Has %s/%s? %s\n", prefix, buf, PetscBools[flg]));
557: } else {
558: PetscCall(PetscPrintf(comm, "Has %s? %s\n", buf, PetscBools[flg]));
559: }
560: }
562: /* check attribute capsule has been created for given path */
563: c = capsules[paths2apaths[p]][s];
564: flg1 = (PetscBool)!!c;
565: PetscCheck(flg == flg1, comm, PETSC_ERR_PLIB, "Capsule should exist for %s? %s Exists? %s", buf, PetscBools[flg], PetscBools[flg1]);
566: if (!flg) continue;
568: /* check correct existence and fidelity of attributes in file */
569: PetscCall(CapsuleReadAndCompareAttributes(c, viewer, buf));
570: }
571: if (prefix) PetscCall(PetscViewerHDF5PopGroup(viewer));
572: PetscCall(PetscViewerFlush(viewer));
573: for (p = 0; p < nap; p++)
574: for (s = 0; s < ns; s++) PetscCall(CapsuleDestroy(&capsules[p][s]));
575: if (verbose) PetscCall(PetscPrintf(comm, "# END testAttributesAbsolutePath\n\n"));
576: PetscFunctionReturn(PETSC_SUCCESS);
577: }
579: /* test attribute writing, existence checking and reading, use group push/pop */
580: static PetscErrorCode testAttributesPushedPath(PetscViewer viewer)
581: {
582: Capsule capsules[nap][ns], c = NULL, old = NULL;
583: PetscInt p;
584: int gd;
585: PetscBool flg = PETSC_FALSE, flg1 = PETSC_FALSE;
586: MPI_Comm comm;
588: PetscFunctionBegin;
589: PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
590: if (verbose) {
591: PetscCall(PetscPrintf(comm, "# TEST testAttributesPushedPath\n"));
592: PetscCall(PetscPrintf(comm, "## WRITE PHASE\n"));
593: }
594: PetscCall(PetscMemzero(capsules, nap * ns * sizeof(Capsule)));
596: /* test attribute writing */
597: for (p = 0; p < np; p++) {
598: PetscCall(isPop(paths[p], &flg));
599: PetscCall(isDot(paths[p], &flg1));
600: if (flg) {
601: PetscCall(PetscViewerHDF5PopGroup(viewer));
602: } else {
603: PetscCall(PetscViewerHDF5PushGroup(viewer, paths[p]));
604: }
605: /* < and . have been already visited => skip */
606: if (flg || flg1) continue;
608: /* assume here that groups and datasets are already in the file */
609: for (PetscInt s = 0; s < ns; s++) {
610: PetscCall(hasGroupOrDataset(viewer, datasets[s], &gd));
611: if (!gd) continue;
612: if (verbose) PetscCall(PetscPrintf(comm, "Write attributes to %s/%s\n", apaths[paths2apaths[p]], datasets[s]));
613: PetscCall(CapsuleCreate(old, &c));
614: PetscCall(CapsuleWriteAttributes(c, viewer, datasets[s]));
615: PetscCheck(!capsules[paths2apaths[p]][s], comm, PETSC_ERR_PLIB, "capsules[%" PetscInt_FMT "][%" PetscInt_FMT "] gets overwritten for %s/%s", paths2apaths[p], s, paths[p], datasets[s]);
616: capsules[paths2apaths[p]][s] = c;
617: old = c;
618: }
619: }
620: PetscCall(PetscViewerFlush(viewer));
622: if (verbose) PetscCall(PetscPrintf(comm, "\n## READ PHASE\n"));
623: for (p = 0; p < np; p++) {
624: const char *group;
626: PetscCall(isPop(paths[p], &flg1));
627: if (flg1) {
628: PetscCall(PetscViewerHDF5PopGroup(viewer));
629: } else {
630: PetscCall(PetscViewerHDF5PushGroup(viewer, paths[p]));
631: }
632: PetscCall(PetscViewerHDF5GetGroup(viewer, NULL, &group));
633: for (PetscInt s = 0; s < ns; s++) {
634: PetscCall(hasGroupOrDataset(viewer, datasets[s], &gd));
635: if (verbose) PetscCall(PetscPrintf(comm, "%s/%s %s\n", group, datasets[s], gd ? (gd == 1 ? "is group" : "is dataset") : "does not exist"));
637: /* check attribute capsule has been created for given path */
638: c = capsules[paths2apaths[p]][s];
639: flg = (PetscBool)!!gd;
640: flg1 = (PetscBool)!!c;
641: PetscCheck(flg == flg1, comm, PETSC_ERR_PLIB, "Capsule should exist for %s/%s? %s Exists? %s", group, datasets[s], PetscBools[flg], PetscBools[flg1]);
642: if (!flg) continue;
644: /* check correct existence of attributes in file */
645: PetscCall(CapsuleReadAndCompareAttributes(c, viewer, datasets[s]));
646: }
647: PetscCall(PetscFree(group));
648: }
649: PetscCall(PetscViewerFlush(viewer));
650: for (p = 0; p < nap; p++)
651: for (PetscInt s = 0; s < ns; s++) PetscCall(CapsuleDestroy(&capsules[p][s]));
652: if (verbose) PetscCall(PetscPrintf(comm, "# END testAttributesPushedPath\n\n"));
653: PetscFunctionReturn(PETSC_SUCCESS);
654: }
656: /* test attribute writing, existence checking and reading, use group push/pop */
657: static PetscErrorCode testObjectAttributes(PetscViewer viewer)
658: {
659: Capsule capsules[nap][ns], c = NULL, old = NULL;
660: PetscInt p;
661: PetscBool flg = PETSC_FALSE, flg1 = PETSC_FALSE;
662: MPI_Comm comm;
664: PetscFunctionBegin;
665: PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
666: if (verbose) {
667: PetscCall(PetscPrintf(comm, "# TEST testObjectAttributes\n"));
668: PetscCall(PetscPrintf(comm, "## WRITE PHASE\n"));
669: }
670: PetscCall(PetscMemzero(capsules, nap * ns * sizeof(Capsule)));
672: /* test attribute writing */
673: for (p = 0; p < np; p++) {
674: PetscCall(isPop(paths[p], &flg));
675: PetscCall(isDot(paths[p], &flg1));
676: if (flg) {
677: PetscCall(PetscViewerHDF5PopGroup(viewer));
678: } else {
679: PetscCall(PetscViewerHDF5PushGroup(viewer, paths[p]));
680: }
681: /* < and . have been already visited => skip */
682: if (flg || flg1) continue;
684: /* assume here that groups and datasets are already in the file */
685: for (PetscInt s = 0; s < ns; s++) {
686: Vec v;
687: size_t len;
688: const char *name = datasets[s];
690: PetscCall(PetscStrlen(name, &len));
691: if (!len) continue;
692: PetscCall(VecCreate(comm, &v));
693: PetscCall(PetscObjectSetName((PetscObject)v, name));
694: PetscCall(PetscViewerHDF5HasObject(viewer, (PetscObject)v, &flg));
695: if (flg) {
696: if (verbose) PetscCall(PetscPrintf(comm, "Write attributes to %s/%s\n", apaths[paths2apaths[p]], name));
697: PetscCall(CapsuleCreate(old, &c));
698: PetscCall(CapsuleWriteAttributes(c, viewer, name));
699: PetscCheck(!capsules[paths2apaths[p]][s], comm, PETSC_ERR_PLIB, "capsules[%" PetscInt_FMT "][%" PetscInt_FMT "] gets overwritten for %s/%s", paths2apaths[p], s, paths[p], name);
700: capsules[paths2apaths[p]][s] = c;
701: old = c;
702: }
703: PetscCall(VecDestroy(&v));
704: }
705: }
706: PetscCall(PetscViewerFlush(viewer));
708: if (verbose) PetscCall(PetscPrintf(comm, "\n## READ PHASE\n"));
709: for (p = 0; p < np; p++) {
710: const char *group;
712: PetscCall(isPop(paths[p], &flg));
713: if (flg) {
714: PetscCall(PetscViewerHDF5PopGroup(viewer));
715: } else {
716: PetscCall(PetscViewerHDF5PushGroup(viewer, paths[p]));
717: }
718: PetscCall(PetscViewerHDF5GetGroup(viewer, NULL, &group));
719: for (PetscInt s = 0; s < ns; s++) {
720: Vec v;
721: size_t len;
722: const char *name = datasets[s];
724: PetscCall(PetscStrlen(name, &len));
725: if (!len) continue;
726: PetscCall(VecCreate(comm, &v));
727: PetscCall(PetscObjectSetName((PetscObject)v, name));
728: PetscCall(PetscViewerHDF5HasObject(viewer, (PetscObject)v, &flg));
729: if (verbose) PetscCall(PetscPrintf(comm, "Is %s/%s dataset? %s\n", group, name, PetscBools[flg]));
731: /* check attribute capsule has been created for given path */
732: c = capsules[paths2apaths[p]][s];
733: flg1 = (PetscBool)!!c;
734: PetscCheck(flg == flg1, comm, PETSC_ERR_PLIB, "Capsule should exist for %s/%s? %s Exists? %s", group, name, PetscBools[flg], PetscBools[flg1]);
736: /* check correct existence of attributes in file */
737: if (flg) PetscCall(CapsuleReadAndCompareAttributes(c, viewer, name));
738: PetscCall(VecDestroy(&v));
739: }
740: PetscCall(PetscFree(group));
741: }
742: PetscCall(PetscViewerFlush(viewer));
743: for (p = 0; p < nap; p++)
744: for (PetscInt s = 0; s < ns; s++) PetscCall(CapsuleDestroy(&capsules[p][s]));
745: if (verbose) PetscCall(PetscPrintf(comm, "# END testObjectAttributes\n\n"));
746: PetscFunctionReturn(PETSC_SUCCESS);
747: }
749: static PetscErrorCode testAttributesDefaultValue(PetscViewer viewer)
750: {
751: #define nv 4
752: PetscBool bools[nv];
753: PetscInt ints[nv];
754: PetscReal reals[nv];
755: char *strings[nv];
756: PetscBool flg;
757: MPI_Comm comm;
759: PetscFunctionBegin;
760: PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
761: if (verbose) PetscCall(PetscPrintf(comm, "# TEST testAttributesDefaultValue\n"));
763: PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_bool", PETSC_BOOL, NULL, &bools[0]));
764: bools[1] = PetscNot(bools[0]);
765: PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_bool", PETSC_BOOL, &bools[1], &bools[2]));
766: PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_nonExisting_bool", PETSC_BOOL, &bools[1], &bools[3]));
767: PetscCheck(bools[2] == bools[0], comm, PETSC_ERR_PLIB, "%s = bools[2] != bools[0] = %s", PetscBools[bools[2]], PetscBools[bools[0]]);
768: PetscCheck(bools[3] == bools[1], comm, PETSC_ERR_PLIB, "%s = bools[3] != bools[1] = %s", PetscBools[bools[3]], PetscBools[bools[1]]);
770: PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_int", PETSC_INT, NULL, &ints[0]));
771: ints[1] = ints[0] * -333;
772: PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_int", PETSC_INT, &ints[1], &ints[2]));
773: PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_nonExisting_int", PETSC_INT, &ints[1], &ints[3]));
774: PetscCheck(ints[2] == ints[0], comm, PETSC_ERR_PLIB, "%" PetscInt_FMT " = ints[2] != ints[0] = %" PetscInt_FMT, ints[2], ints[0]);
775: PetscCheck(ints[3] == ints[1], comm, PETSC_ERR_PLIB, "%" PetscInt_FMT " = ints[3] != ints[1] = %" PetscInt_FMT, ints[3], ints[1]);
776: if (verbose) PetscCall(PetscIntView(nv, ints, PETSC_VIEWER_STDOUT_WORLD));
778: PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_real", PETSC_REAL, NULL, &reals[0]));
779: reals[1] = reals[0] * -11.1;
780: PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_real", PETSC_REAL, &reals[1], &reals[2]));
781: PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_nonExisting_real", PETSC_REAL, &reals[1], &reals[3]));
782: PetscCheck(reals[2] == reals[0], comm, PETSC_ERR_PLIB, "%f = reals[2] != reals[0] = %f", reals[2], reals[0]);
783: PetscCheck(reals[3] == reals[1], comm, PETSC_ERR_PLIB, "%f = reals[3] != reals[1] = %f", reals[3], reals[1]);
784: if (verbose) PetscCall(PetscRealView(nv, reals, PETSC_VIEWER_STDOUT_WORLD));
786: PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_str", PETSC_STRING, NULL, &strings[0]));
787: PetscCall(PetscStrallocpy(strings[0], &strings[1]));
788: PetscCall(alterString(strings[0], strings[1]));
789: PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_str", PETSC_STRING, &strings[1], &strings[2]));
790: PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_nonExisting_str", PETSC_STRING, &strings[1], &strings[3]));
791: PetscCall(PetscStrcmp(strings[2], strings[0], &flg));
792: PetscCheck(flg, comm, PETSC_ERR_PLIB, "%s = strings[2] != strings[0] = %s", strings[2], strings[0]);
793: PetscCall(PetscStrcmp(strings[3], strings[1], &flg));
794: PetscCheck(flg, comm, PETSC_ERR_PLIB, "%s = strings[3] != strings[1] = %s", strings[3], strings[1]);
795: for (PetscInt i = 0; i < nv; i++) PetscCall(PetscFree(strings[i]));
797: PetscCall(PetscViewerFlush(viewer));
798: if (verbose) PetscCall(PetscPrintf(comm, "# END testAttributesDefaultValue\n"));
799: #undef nv
800: PetscFunctionReturn(PETSC_SUCCESS);
801: }
803: int main(int argc, char **argv)
804: {
805: static char filename[PETSC_MAX_PATH_LEN] = "ex48.h5";
806: PetscMPIInt rank;
807: MPI_Comm comm;
808: PetscViewer viewer;
810: PetscFunctionBegin;
811: PetscFunctionBeginUser;
812: PetscCall(PetscInitialize(&argc, &argv, NULL, help));
813: comm = PETSC_COMM_WORLD;
814: PetscCallMPI(MPI_Comm_rank(comm, &rank));
815: PetscCall(PetscOptionsGetInt(NULL, NULL, "-n", &n, NULL));
816: PetscCall(PetscOptionsGetBool(NULL, NULL, "-verbose", &verbose, NULL));
817: PetscCall(PetscOptionsGetString(NULL, NULL, "-filename", filename, sizeof(filename), NULL));
818: if (verbose) PetscCall(PetscPrintf(comm, "np ns " PetscStringize(np) " " PetscStringize(ns) "\n"));
820: PetscCall(PetscViewerHDF5Open(comm, filename, FILE_MODE_WRITE, &viewer));
821: PetscCall(testGroupsDatasets(viewer));
822: PetscCall(testAttributesAbsolutePath(viewer, "/"));
823: PetscCall(testAttributesAbsolutePath(viewer, "/prefix"));
824: PetscCall(PetscViewerDestroy(&viewer));
826: /* test reopening in update mode */
827: PetscCall(PetscViewerHDF5Open(comm, filename, FILE_MODE_UPDATE, &viewer));
828: PetscCall(testAttributesPushedPath(viewer));
829: PetscCall(testObjectAttributes(viewer));
830: PetscCall(testAttributesDefaultValue(viewer));
831: PetscCall(PetscViewerDestroy(&viewer));
832: PetscCall(PetscFinalize());
833: return 0;
834: }
836: /*TEST
838: build:
839: requires: hdf5
841: test:
842: nsize: {{1 4}}
843: output_file: output/empty.out
845: TEST*/