1 static char help[] = "Tests HDF5 attribute I/O.\n\n";
2
3 #include <petscviewerhdf5.h>
4 #include <petscvec.h>
5
6 static PetscInt n = 5; /* testing vector size */
7 static PetscBool verbose = PETSC_FALSE;
8 #define SLEN 128
9
10 /* sequence of unique absolute paths */
11 #define nap 9
12 static const char *apaths[nap] = {
13 /* 0 */
14 "/", "/g1", "/g1/g2", "/g1/nonExistingGroup1", "/g1/g3",
15 /* 5 */
16 "/g1/g3/g4", "/g1/nonExistingGroup2", "/g1/nonExistingGroup2/g5", "/g1/g6/g7"};
17
18 #define np 21
19 /* sequence of paths (absolute or relative); "<" encodes Pop */
20 static const char *paths[np] = {
21 /* 0 */
22 "/",
23 "/g1",
24 "/g1/g2",
25 "/g1/nonExistingGroup1",
26 "<",
27 /* 5 */
28 ".", /* /g1/g2 */
29 "<",
30 "<",
31 "g3", /* /g1/g3 */
32 "g4", /* /g1/g3/g4 */
33 /* 10 */
34 "<",
35 "<",
36 ".", /* /g1 */
37 "<",
38 "nonExistingGroup2", /* /g1/nonExistingG2 */
39 /* 15 */
40 "g5", /* /g1/nonExistingG2/g5 */
41 "<",
42 "<",
43 "g6/g7", /* /g1/g6/g7 */
44 "<",
45 /* 20 */
46 "<",
47 };
48 /* corresponding expected absolute paths - positions in abspath */
49 static const PetscInt paths2apaths[np] = {
50 /* 0 */
51 0,
52 1,
53 2,
54 3,
55 2,
56 /* 5 */
57 2,
58 2,
59 1,
60 4,
61 5,
62 /* 10 */
63 4,
64 1,
65 1,
66 1,
67 6,
68 /* 15 */
69 7,
70 6,
71 1,
72 8,
73 1,
74 /* 20 */
75 0,
76 };
77
78 #define ns 4
79 /* for "" attribute will be stored to group, otherwise to given dataset */
80 static const char *datasets[ns] = {"", "x", "nonExistingVec", "y"};
81
82 /* beware this yields PETSC_FALSE for "" but group "" is interpreted as "/" */
shouldExist(const char name[],PetscBool emptyExists,PetscBool * has)83 static inline PetscErrorCode shouldExist(const char name[], PetscBool emptyExists, PetscBool *has)
84 {
85 size_t len = 0;
86
87 PetscFunctionBegin;
88 PetscCall(PetscStrlen(name, &len));
89 *has = emptyExists;
90 if (len) {
91 char *loc = NULL;
92 PetscCall(PetscStrstr(name, "nonExisting", &loc));
93 *has = PetscNot(loc);
94 }
95 PetscFunctionReturn(PETSC_SUCCESS);
96 }
97
isPop(const char path[],PetscBool * has)98 static inline PetscErrorCode isPop(const char path[], PetscBool *has)
99 {
100 PetscFunctionBegin;
101 PetscCall(PetscStrcmp(path, "<", has));
102 PetscFunctionReturn(PETSC_SUCCESS);
103 }
104
isDot(const char path[],PetscBool * has)105 static inline PetscErrorCode isDot(const char path[], PetscBool *has)
106 {
107 PetscFunctionBegin;
108 PetscCall(PetscStrcmp(path, ".", has));
109 PetscFunctionReturn(PETSC_SUCCESS);
110 }
111
isRoot(const char path[],PetscBool * flg)112 static inline PetscErrorCode isRoot(const char path[], PetscBool *flg)
113 {
114 size_t len;
115
116 PetscFunctionBegin;
117 PetscCall(PetscStrlen(path, &len));
118 *flg = PetscNot(len);
119 if (!*flg) PetscCall(PetscStrcmp(path, "/", flg));
120 PetscFunctionReturn(PETSC_SUCCESS);
121 }
122
compare(PetscDataType dt,void * ptr0,void * ptr1,PetscBool * flg)123 static inline PetscErrorCode compare(PetscDataType dt, void *ptr0, void *ptr1, PetscBool *flg)
124 {
125 PetscFunctionBegin;
126 switch (dt) {
127 case PETSC_INT:
128 *flg = (PetscBool)(*(PetscInt *)ptr0 == *(PetscInt *)ptr1);
129 if (verbose) {
130 if (*flg) {
131 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT, *(PetscInt *)ptr0));
132 } else {
133 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT " != %" PetscInt_FMT "\n", *(PetscInt *)ptr0, *(PetscInt *)ptr1));
134 }
135 }
136 break;
137 case PETSC_REAL:
138 *flg = (PetscBool)(*(PetscReal *)ptr0 == *(PetscReal *)ptr1);
139 if (verbose) {
140 if (*flg) {
141 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%f", *(PetscReal *)ptr0));
142 } else {
143 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%f != %f\n", *(PetscReal *)ptr0, *(PetscReal *)ptr1));
144 }
145 }
146 break;
147 case PETSC_BOOL:
148 *flg = (PetscBool)(*(PetscBool *)ptr0 == *(PetscBool *)ptr1);
149 if (verbose) {
150 if (*flg) {
151 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s", PetscBools[*(PetscBool *)ptr0]));
152 } else {
153 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s != %s\n", PetscBools[*(PetscBool *)ptr0], PetscBools[*(PetscBool *)ptr1]));
154 }
155 }
156 break;
157 case PETSC_STRING:
158 PetscCall(PetscStrcmp((const char *)ptr0, (const char *)ptr1, flg));
159 if (verbose) {
160 if (*flg) {
161 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s", (char *)ptr0));
162 } else {
163 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s != %s\n", (char *)ptr0, (char *)ptr1));
164 }
165 }
166 break;
167 default:
168 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "PetscDataType %s not handled here", PetscDataTypes[dt]);
169 }
170 PetscFunctionReturn(PETSC_SUCCESS);
171 }
172
alterString(const char oldstr[],char str[])173 static inline PetscErrorCode alterString(const char oldstr[], char str[])
174 {
175 size_t i, n;
176
177 PetscFunctionBegin;
178 PetscCall(PetscStrlen(oldstr, &n));
179 PetscCall(PetscStrncpy(str, oldstr, n + 1));
180 for (i = 0; i < n; i++) {
181 if (('A' <= str[i] && str[i] < 'Z') || ('a' <= str[i] && str[i] < 'z')) {
182 str[i]++;
183 break;
184 }
185 }
186 PetscFunctionReturn(PETSC_SUCCESS);
187 }
188
189 /* if name given, check dataset with this name exists under current group, otherwise just check current group exists */
190 /* flg: 0 doesn't exist, 1 group, 2 dataset */
hasGroupOrDataset(PetscViewer viewer,const char path[],int * flg)191 static PetscErrorCode hasGroupOrDataset(PetscViewer viewer, const char path[], int *flg)
192 {
193 PetscBool has;
194
195 PetscFunctionBegin;
196 *flg = 0;
197 PetscCall(PetscViewerHDF5HasGroup(viewer, path, &has));
198 if (has) *flg = 1;
199 else {
200 PetscCall(PetscViewerHDF5HasDataset(viewer, path, &has));
201 if (has) *flg = 2;
202 }
203 PetscFunctionReturn(PETSC_SUCCESS);
204 }
205
206 #define nt 5 /* number of datatypes */
207 typedef struct _n_Capsule *Capsule;
208 struct _n_Capsule {
209 char names[nt][SLEN];
210 PetscDataType types[nt];
211 char typeNames[nt][SLEN];
212 size_t sizes[nt];
213 void *vals[nt];
214 PetscInt id, ntypes;
215 };
216
CapsuleCreate(Capsule old,Capsule * newcapsule)217 static PetscErrorCode CapsuleCreate(Capsule old, Capsule *newcapsule)
218 {
219 Capsule c;
220 PetscBool bool0 = PETSC_TRUE;
221 PetscInt int0 = -1;
222 PetscReal real0 = -1.1;
223 char str0[] = "Test String";
224 char nestr0[] = "NONEXISTING STRING"; /* this attribute shall be skipped for writing */
225 void *vals[nt] = {&bool0, &int0, &real0, str0, nestr0};
226 size_t sizes[nt] = {sizeof(bool0), sizeof(int0), sizeof(real0), sizeof(str0), sizeof(str0)};
227 PetscDataType types[nt] = {PETSC_BOOL, PETSC_INT, PETSC_REAL, PETSC_STRING, PETSC_STRING};
228 const char *tNames[nt] = {"bool", "int", "real", "str", "nonExisting"};
229 PetscInt t;
230
231 PetscFunctionBegin;
232 PetscCall(PetscNew(&c));
233 c->id = 0;
234 c->ntypes = nt;
235 if (old) {
236 /* alter values */
237 t = 0;
238 bool0 = PetscNot(*((PetscBool *)old->vals[t]));
239 t++;
240 int0 = *((PetscInt *)old->vals[t]) * -2;
241 t++;
242 real0 = *((PetscReal *)old->vals[t]) * -2.0;
243 t++;
244 PetscCall(alterString((const char *)old->vals[t], str0));
245 t++;
246 c->id = old->id + 1;
247 }
248 for (t = 0; t < nt; t++) {
249 c->sizes[t] = sizes[t];
250 c->types[t] = types[t];
251 PetscCall(PetscStrncpy(c->typeNames[t], tNames[t], sizeof(c->typeNames[t])));
252 PetscCall(PetscSNPrintf(c->names[t], SLEN, "attr_%" PetscInt_FMT "_%s", c->id, tNames[t]));
253 PetscCall(PetscMalloc(sizes[t], &c->vals[t]));
254 PetscCall(PetscMemcpy(c->vals[t], vals[t], sizes[t]));
255 }
256 *newcapsule = c;
257 PetscFunctionReturn(PETSC_SUCCESS);
258 }
259 #undef nt
260
CapsuleWriteAttributes(Capsule c,PetscViewer v,const char parent[])261 static PetscErrorCode CapsuleWriteAttributes(Capsule c, PetscViewer v, const char parent[])
262 {
263 PetscInt t;
264 PetscBool flg = PETSC_FALSE;
265
266 PetscFunctionBegin;
267 for (t = 0; t < c->ntypes; t++) {
268 PetscCall(shouldExist(c->names[t], PETSC_FALSE, &flg));
269 if (!flg) continue;
270 PetscCall(PetscViewerHDF5WriteAttribute(v, parent, c->names[t], c->types[t], c->vals[t]));
271 }
272 PetscFunctionReturn(PETSC_SUCCESS);
273 }
274
CapsuleReadAndCompareAttributes(Capsule c,PetscViewer v,const char parent[])275 static PetscErrorCode CapsuleReadAndCompareAttributes(Capsule c, PetscViewer v, const char parent[])
276 {
277 const char *group;
278 int gd = 0;
279 PetscInt t;
280 PetscBool flg = PETSC_FALSE, hasAttr = PETSC_FALSE;
281 MPI_Comm comm;
282
283 PetscFunctionBegin;
284 PetscCall(PetscObjectGetComm((PetscObject)v, &comm));
285 PetscCall(PetscViewerHDF5GetGroup(v, NULL, &group));
286 PetscCall(hasGroupOrDataset(v, parent, &gd));
287 /* check correct existence of attributes */
288 for (t = 0; t < c->ntypes; t++) {
289 const char *attribute = c->names[t];
290 PetscCall(shouldExist(attribute, PETSC_FALSE, &flg));
291 PetscCall(PetscViewerHDF5HasAttribute(v, parent, attribute, &hasAttr));
292 if (verbose) {
293 PetscCall(PetscPrintf(comm, " %-24s = ", attribute));
294 if (!hasAttr) PetscCall(PetscPrintf(comm, "---"));
295 }
296 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);
297 PetscCheck(flg == hasAttr, comm, PETSC_ERR_PLIB, "Attribute %s/%s should exist? %s Exists? %s", parent, attribute, PetscBools[flg], PetscBools[hasAttr]);
298
299 /* check loaded attributes are the same as original */
300 if (hasAttr) {
301 char buffer[SLEN];
302 char *str;
303 void *ptr0;
304 /* check the stored data is the same as original */
305 //TODO datatype should better be output arg, not input
306 //TODO string attributes should probably have a separate function since the handling is different;
307 //TODO or maybe it should just accept string buffer rather than pointer to string
308 if (c->types[t] == PETSC_STRING) {
309 PetscCall(PetscViewerHDF5ReadAttribute(v, parent, attribute, c->types[t], NULL, &str));
310 ptr0 = str;
311 } else {
312 PetscCall(PetscViewerHDF5ReadAttribute(v, parent, attribute, c->types[t], NULL, &buffer));
313 ptr0 = &buffer;
314 }
315 PetscCall(compare(c->types[t], ptr0, c->vals[t], &flg));
316 PetscCheck(flg, comm, PETSC_ERR_PLIB, "Value of attribute %s/%s/%s is not equal to the original value", group, parent, attribute);
317 if (verbose) PetscCall(PetscPrintf(comm, " (=)"));
318 if (c->types[t] == PETSC_STRING) PetscCall(PetscFree(str));
319 }
320 if (verbose && gd) PetscCall(PetscPrintf(comm, "\n"));
321 }
322 PetscCall(PetscFree(group));
323 PetscFunctionReturn(PETSC_SUCCESS);
324 }
325
CapsuleDestroy(Capsule * c)326 static PetscErrorCode CapsuleDestroy(Capsule *c)
327 {
328 PetscInt t;
329
330 PetscFunctionBegin;
331 if (!*c) PetscFunctionReturn(PETSC_SUCCESS);
332 for (t = 0; t < (*c)->ntypes; t++) PetscCall(PetscFree((*c)->vals[t]));
333 PetscCall(PetscFree(*c));
334 PetscFunctionReturn(PETSC_SUCCESS);
335 }
336
testGroupsDatasets(PetscViewer viewer)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;
346
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)));
356
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;
370
371 for (s = 0; s < ns; s++) {
372 Vec v;
373
374 PetscCall(shouldExist(datasets[s], PETSC_FALSE, &flg));
375 if (!flg) continue;
376
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 }
388
389 PetscCall(VecView(v, viewer));
390 vecs[paths2apaths[p]][s] = v;
391 }
392 }
393 PetscCall(PetscViewerFlush(viewer));
394 PetscCall(PetscRandomDestroy(&rand));
395
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]];
401
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 }
418
419 /* check existence of datasets; compare loaded vectors with original ones */
420 for (p = 0; p < np; p++) {
421 const char *group;
422
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;
436
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]);
444
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 }
466
formPath(PetscBool relativize,const char path[],const char dataset[],char buf[],size_t bufsize)467 static inline PetscErrorCode formPath(PetscBool relativize, const char path[], const char dataset[], char buf[], size_t bufsize)
468 {
469 PetscBool isroot = PETSC_FALSE;
470
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 }
485
486 /* test attribute writing, existence checking and reading, use absolute paths */
testAttributesAbsolutePath(PetscViewer viewer,const char prefix[])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;
494
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)));
506
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;
516
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;
525
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 }
533
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));
542
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;
550
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 }
561
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;
567
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 }
578
579 /* test attribute writing, existence checking and reading, use group push/pop */
testAttributesPushedPath(PetscViewer viewer)580 static PetscErrorCode testAttributesPushedPath(PetscViewer viewer)
581 {
582 Capsule capsules[nap][ns], c = NULL, old = NULL;
583 PetscInt p, s;
584 int gd;
585 PetscBool flg = PETSC_FALSE, flg1 = PETSC_FALSE;
586 MPI_Comm comm;
587
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)));
595
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;
607
608 /* assume here that groups and datasets are already in the file */
609 for (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));
621
622 if (verbose) PetscCall(PetscPrintf(comm, "\n## READ PHASE\n"));
623 for (p = 0; p < np; p++) {
624 const char *group;
625
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 (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"));
636
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;
643
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 (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 }
655
656 /* test attribute writing, existence checking and reading, use group push/pop */
testObjectAttributes(PetscViewer viewer)657 static PetscErrorCode testObjectAttributes(PetscViewer viewer)
658 {
659 Capsule capsules[nap][ns], c = NULL, old = NULL;
660 PetscInt p, s;
661 PetscBool flg = PETSC_FALSE, flg1 = PETSC_FALSE;
662 MPI_Comm comm;
663
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)));
671
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;
683
684 /* assume here that groups and datasets are already in the file */
685 for (s = 0; s < ns; s++) {
686 Vec v;
687 size_t len;
688 const char *name = datasets[s];
689
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));
707
708 if (verbose) PetscCall(PetscPrintf(comm, "\n## READ PHASE\n"));
709 for (p = 0; p < np; p++) {
710 const char *group;
711
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 (s = 0; s < ns; s++) {
720 Vec v;
721 size_t len;
722 const char *name = datasets[s];
723
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]));
730
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]);
735
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 (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 }
748
testAttributesDefaultValue(PetscViewer viewer)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 PetscInt i;
758 MPI_Comm comm;
759
760 PetscFunctionBegin;
761 PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
762 if (verbose) PetscCall(PetscPrintf(comm, "# TEST testAttributesDefaultValue\n"));
763
764 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_bool", PETSC_BOOL, NULL, &bools[0]));
765 bools[1] = PetscNot(bools[0]);
766 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_bool", PETSC_BOOL, &bools[1], &bools[2]));
767 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_nonExisting_bool", PETSC_BOOL, &bools[1], &bools[3]));
768 PetscCheck(bools[2] == bools[0], comm, PETSC_ERR_PLIB, "%s = bools[2] != bools[0] = %s", PetscBools[bools[2]], PetscBools[bools[0]]);
769 PetscCheck(bools[3] == bools[1], comm, PETSC_ERR_PLIB, "%s = bools[3] != bools[1] = %s", PetscBools[bools[3]], PetscBools[bools[1]]);
770
771 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_int", PETSC_INT, NULL, &ints[0]));
772 ints[1] = ints[0] * -333;
773 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_int", PETSC_INT, &ints[1], &ints[2]));
774 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_nonExisting_int", PETSC_INT, &ints[1], &ints[3]));
775 PetscCheck(ints[2] == ints[0], comm, PETSC_ERR_PLIB, "%" PetscInt_FMT " = ints[2] != ints[0] = %" PetscInt_FMT, ints[2], ints[0]);
776 PetscCheck(ints[3] == ints[1], comm, PETSC_ERR_PLIB, "%" PetscInt_FMT " = ints[3] != ints[1] = %" PetscInt_FMT, ints[3], ints[1]);
777 if (verbose) PetscCall(PetscIntView(nv, ints, PETSC_VIEWER_STDOUT_WORLD));
778
779 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_real", PETSC_REAL, NULL, &reals[0]));
780 reals[1] = reals[0] * -11.1;
781 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_real", PETSC_REAL, &reals[1], &reals[2]));
782 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_nonExisting_real", PETSC_REAL, &reals[1], &reals[3]));
783 PetscCheck(reals[2] == reals[0], comm, PETSC_ERR_PLIB, "%f = reals[2] != reals[0] = %f", reals[2], reals[0]);
784 PetscCheck(reals[3] == reals[1], comm, PETSC_ERR_PLIB, "%f = reals[3] != reals[1] = %f", reals[3], reals[1]);
785 if (verbose) PetscCall(PetscRealView(nv, reals, PETSC_VIEWER_STDOUT_WORLD));
786
787 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_str", PETSC_STRING, NULL, &strings[0]));
788 PetscCall(PetscStrallocpy(strings[0], &strings[1]));
789 PetscCall(alterString(strings[0], strings[1]));
790 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_0_str", PETSC_STRING, &strings[1], &strings[2]));
791 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", "attr_nonExisting_str", PETSC_STRING, &strings[1], &strings[3]));
792 PetscCall(PetscStrcmp(strings[2], strings[0], &flg));
793 PetscCheck(flg, comm, PETSC_ERR_PLIB, "%s = strings[2] != strings[0] = %s", strings[2], strings[0]);
794 PetscCall(PetscStrcmp(strings[3], strings[1], &flg));
795 PetscCheck(flg, comm, PETSC_ERR_PLIB, "%s = strings[3] != strings[1] = %s", strings[3], strings[1]);
796 for (i = 0; i < nv; i++) PetscCall(PetscFree(strings[i]));
797
798 PetscCall(PetscViewerFlush(viewer));
799 if (verbose) PetscCall(PetscPrintf(comm, "# END testAttributesDefaultValue\n"));
800 #undef nv
801 PetscFunctionReturn(PETSC_SUCCESS);
802 }
803
main(int argc,char ** argv)804 int main(int argc, char **argv)
805 {
806 static char filename[PETSC_MAX_PATH_LEN] = "ex48.h5";
807 PetscMPIInt rank;
808 MPI_Comm comm;
809 PetscViewer viewer;
810
811 PetscFunctionBegin;
812 PetscFunctionBeginUser;
813 PetscCall(PetscInitialize(&argc, &argv, NULL, help));
814 comm = PETSC_COMM_WORLD;
815 PetscCallMPI(MPI_Comm_rank(comm, &rank));
816 PetscCall(PetscOptionsGetInt(NULL, NULL, "-n", &n, NULL));
817 PetscCall(PetscOptionsGetBool(NULL, NULL, "-verbose", &verbose, NULL));
818 PetscCall(PetscOptionsGetString(NULL, NULL, "-filename", filename, sizeof(filename), NULL));
819 if (verbose) PetscCall(PetscPrintf(comm, "np ns " PetscStringize(np) " " PetscStringize(ns) "\n"));
820
821 PetscCall(PetscViewerHDF5Open(comm, filename, FILE_MODE_WRITE, &viewer));
822 PetscCall(testGroupsDatasets(viewer));
823 PetscCall(testAttributesAbsolutePath(viewer, "/"));
824 PetscCall(testAttributesAbsolutePath(viewer, "/prefix"));
825 PetscCall(PetscViewerDestroy(&viewer));
826
827 /* test reopening in update mode */
828 PetscCall(PetscViewerHDF5Open(comm, filename, FILE_MODE_UPDATE, &viewer));
829 PetscCall(testAttributesPushedPath(viewer));
830 PetscCall(testObjectAttributes(viewer));
831 PetscCall(testAttributesDefaultValue(viewer));
832 PetscCall(PetscViewerDestroy(&viewer));
833 PetscCall(PetscFinalize());
834 return 0;
835 }
836
837 /*TEST
838
839 build:
840 requires: hdf5
841
842 test:
843 nsize: {{1 4}}
844 output_file: output/empty.out
845
846 TEST*/
847