/* * Copyright (C) 1998 NCSA * All rights reserved. * * Programmer: Robb Matzke <matzke@llnl.gov> * Friday, January 23, 1998 */ #undef NDEBUG #include <assert.h> #include <hdf5.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <H5config.h> #ifndef HAVE_ATTRIBUTE # undef __attribute__ # define __attribute__(X) /*void*/ # define __unused__ /*void*/ #else # define __unused__ __attribute__((unused)) #endif #define TEST_FILE_NAME "cmpd_dset.h5" /* The first dataset */ typedef struct s1_t { unsigned int a; unsigned int b; unsigned int c[4]; unsigned int d; unsigned int e; } s1_t; /* The second dataset (same as first) */ typedef s1_t s2_t; /* The third dataset (reversed fields of s1) */ typedef struct s3_t { unsigned int e; unsigned int d; unsigned int c[4]; unsigned int b; unsigned int a; } s3_t; /* The fourth dataset (a subset of s1) */ typedef struct s4_t { unsigned int b; unsigned int d; } s4_t; /* The fifth dataset (a superset of s1) */ typedef struct s5_t { unsigned int pre; unsigned int a; unsigned int b; unsigned int mid1; unsigned int c[4]; unsigned int mid2; unsigned int d; unsigned int e; unsigned int post; } s5_t; #if 1 # define NX 100u # define NY 2000u #else # define NX 12u # define NY 9u #endif /*------------------------------------------------------------------------- * Function: cleanup * * Purpose: Cleanup temporary test files * * Return: none * * Programmer: Albert Cheng * May 28, 1998 * * Modifications: * *------------------------------------------------------------------------- */ static void cleanup(void) { if (!getenv ("HDF5_NOCLEANUP")) { remove(TEST_FILE_NAME); } } /*------------------------------------------------------------------------- * Function: display_error_cb * * Purpose: Displays the error stack after printing "*FAILED*". * * Return: Success: 0 * * Failure: -1 * * Programmer: Robb Matzke * Wednesday, March 4, 1998 * * Modifications: * *------------------------------------------------------------------------- */ static herr_t display_error_cb (void __unused__ *client_data) { puts ("*FAILED*"); H5Eprint (stdout); return 0; } /*------------------------------------------------------------------------- * Function: main * * Purpose: Creates a simple dataset of a compound type and then reads * it back. The dataset is read back in various ways to * exercise the I/O pipeline and compound type conversion. * * Return: Success: 0 * * Failure: 1 * * Programmer: Robb Matzke * Friday, January 23, 1998 * * Modifications: * *------------------------------------------------------------------------- */ int main (void) { /* First dataset */ static s1_t s1[NX*NY]; hid_t s1_tid; /* Second dataset */ static s2_t s2[NX*NY]; hid_t s2_tid; /* Third dataset */ static s3_t s3[NX*NY]; hid_t s3_tid; /* Fourth dataset */ static s4_t s4[NX*NY]; hid_t s4_tid; /* Fifth dataset */ static s5_t s5[NX*NY]; hid_t s5_tid; /* Sixth dataset */ /* Seventh dataset */ hid_t s7_sid; /* Eighth dataset */ s1_t *s8 = NULL; hid_t s8_f_sid; /*file data space */ hid_t s8_m_sid; /*memory data space */ /* Ninth dataset */ /* Tenth dataset */ /* Eleventh dataset */ #if 0 s4_t *s11 = NULL; int ndims; #endif /* Other variables */ unsigned int i, j; hid_t file, dataset, space, PRESERVE; static hsize_t dim[] = {NX, NY}; hssize_t f_offset[2]; /*offset of hyperslab in file */ hsize_t h_size[2]; /*size of hyperslab */ size_t memb_size[1] = {4}; /* Set up error handling */ H5Eset_auto(display_error_cb, NULL); /* Create the file */ if ((file = H5Fcreate (TEST_FILE_NAME, H5F_ACC_TRUNC|H5F_ACC_DEBUG, H5P_DEFAULT, H5P_DEFAULT))<0) goto error; /* Create the data space */ if ((space = H5Screate_simple (2, dim, NULL))<0) goto error; /* Create xfer properties to preserve initialized data */ if ((PRESERVE = H5Pcreate (H5P_DATASET_XFER))<0) goto error; if (H5Pset_preserve (PRESERVE, 1)<0) goto error; /* *###################################################################### * STEP 1: Save the original dataset natively. */ printf("%-70s", "Testing basic compound write"); fflush(stdout); /* Initialize the dataset */ for (i=0; i<NX*NY; i++) { s1[i].a = 8*i+0; s1[i].b = 2000+2*i; s1[i].c[0] = 8*i+2; s1[i].c[1] = 8*i+3; s1[i].c[2] = 8*i+4; s1[i].c[3] = 8*i+5; s1[i].d = 2001+2*i; s1[i].e = 8*i+7; } /* Create the memory data type */ if ((s1_tid = H5Tcreate (H5T_COMPOUND, sizeof(s1_t)))<0) goto error; if (H5Tinsert (s1_tid, "a", HOFFSET(s1_t,a), H5T_NATIVE_INT)<0 || H5Tinsert (s1_tid, "b", HOFFSET(s1_t,b), H5T_NATIVE_INT)<0 || H5Tinsert_array (s1_tid, "c", HOFFSET(s1_t,c), 1, memb_size, NULL, H5T_NATIVE_INT)<0 || H5Tinsert (s1_tid, "d", HOFFSET(s1_t,d), H5T_NATIVE_INT)<0 || H5Tinsert (s1_tid, "e", HOFFSET(s1_t,e), H5T_NATIVE_INT)<0) { goto error; } /* Create the dataset */ if ((dataset = H5Dcreate (file, "s1", s1_tid, space, H5P_DEFAULT))<0) { goto error; } /* Write the data */ if (H5Dwrite (dataset, s1_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, s1)<0) { goto error; } puts(" PASSED"); /* *###################################################################### * STEP 2: We create a new type ID for the second dataset even though * it's the same as the first just to test things better, but * in fact, we could have used s1_tid. */ printf("%-70s", "Testing basic compound read"); fflush(stdout); /* Create a data type for s2 */ if ((s2_tid = H5Tcreate (H5T_COMPOUND, sizeof(s2_t)))<0) goto error; if (H5Tinsert (s2_tid, "a", HOFFSET(s2_t,a), H5T_NATIVE_INT)<0 || H5Tinsert (s2_tid, "b", HOFFSET(s2_t,b), H5T_NATIVE_INT)<0 || H5Tinsert_array (s2_tid, "c", HOFFSET(s2_t,c), 1, memb_size, NULL, H5T_NATIVE_INT)<0 || H5Tinsert (s2_tid, "d", HOFFSET(s2_t,d), H5T_NATIVE_INT)<0 || H5Tinsert (s2_tid, "e", HOFFSET(s2_t,e), H5T_NATIVE_INT)<0) { goto error; } /* Read the data */ if (H5Dread (dataset, s2_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, s2)<0) { goto error; } /* Compare s2 with s1. They should be the same */ for (i=0; i<NX*NY; i++) { if (s1[i].a!=s2[i].a || s1[i].b!=s2[i].b || s1[i].c[0]!=s2[i].c[0] || s1[i].c[1]!=s2[i].c[1] || s1[i].c[2]!=s2[i].c[2] || s1[i].c[3]!=s2[i].c[3] || s1[i].d!=s2[i].d || s1[i].e!=s2[i].e) { puts("*FAILED*"); puts(" Incorrect values read from the file"); goto error; } } puts(" PASSED"); /* *###################################################################### * STEP 3: Read the dataset back into a third memory buffer. This buffer * has the same data space but the data type is different: the * data type is a struct whose members are in the opposite order. */ printf("%-70s", "Testing reversal of struct members"); fflush (stdout); /* Create a data type for s3 */ if ((s3_tid = H5Tcreate (H5T_COMPOUND, sizeof(s3_t)))<0) goto error; if (H5Tinsert (s3_tid, "a", HOFFSET(s3_t,a), H5T_NATIVE_INT)<0 || H5Tinsert (s3_tid, "b", HOFFSET(s3_t,b), H5T_NATIVE_INT)<0 || H5Tinsert_array (s3_tid, "c", HOFFSET(s3_t,c), 1, memb_size, NULL, H5T_NATIVE_INT)<0 || H5Tinsert (s3_tid, "d", HOFFSET(s3_t,d), H5T_NATIVE_INT)<0 || H5Tinsert (s3_tid, "e", HOFFSET(s3_t,e), H5T_NATIVE_INT)<0) { goto error; } /* Read the data */ if (H5Dread (dataset, s3_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, s3)<0) { goto error; } /* Compare s3 with s1. They should be the same */ for (i=0; i<NX*NY; i++) { if (s1[i].a!=s3[i].a || s1[i].b!=s3[i].b || s1[i].c[0]!=s3[i].c[0] || s1[i].c[1]!=s3[i].c[1] || s1[i].c[2]!=s3[i].c[2] || s1[i].c[3]!=s3[i].c[3] || s1[i].d!=s3[i].d || s1[i].e!=s3[i].e) { puts("*FAILED*"); puts(" Incorrect values read from the file"); goto error; } } puts(" PASSED"); /* *###################################################################### * STEP 4: Read a subset of the members. Of the <a,b,c,d,e> members * stored on disk we'll read <b,d>. */ printf("%-70s", "Testing subset struct read"); fflush (stdout); /* Create a datatype for s4 */ if ((s4_tid = H5Tcreate (H5T_COMPOUND, sizeof(s4_t)))<0) goto error; if (H5Tinsert (s4_tid, "b", HOFFSET(s4_t,b), H5T_NATIVE_INT)<0) goto error; if (H5Tinsert (s4_tid, "d", HOFFSET(s4_t,d), H5T_NATIVE_INT)<0) goto error; /* Read the data */ if (H5Dread (dataset, s4_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, s4)<0) { goto error; } /* Compare s4 with s1 */ for (i=0; i<NX*NY; i++) { if (s1[i].b!=s4[i].b || s1[i].d!=s4[i].d) { puts("*FAILED*"); puts(" Incorrect values read from the file"); goto error; } } puts(" PASSED"); /* *###################################################################### * STEP 5: Read all the members into a struct which has other members * which have already been initialized. */ printf("%-70s", "Testing partially initialized superset read"); fflush(stdout); /* Initialize some members */ for (i=0; i<NX*NY; i++) { s5[i].pre = 1000+4*i; s5[i].mid1 = 1001+4*i; s5[i].mid2 = 1002+4*i; s5[i].post = 1003+4*i; } /* Create a data type for s5 */ if ((s5_tid = H5Tcreate (H5T_COMPOUND, sizeof(s5_t)))<0) goto error; if (H5Tinsert (s5_tid, "a", HOFFSET(s5_t,a), H5T_NATIVE_INT)<0 || H5Tinsert (s5_tid, "b", HOFFSET(s5_t,b), H5T_NATIVE_INT)<0 || H5Tinsert_array (s5_tid, "c", HOFFSET(s5_t,c), 1, memb_size, NULL, H5T_NATIVE_INT)<0 || H5Tinsert (s5_tid, "d", HOFFSET(s5_t,d), H5T_NATIVE_INT)<0 || H5Tinsert (s5_tid, "e", HOFFSET(s5_t,e), H5T_NATIVE_INT)) { goto error; } /* Read the data */ if (H5Dread (dataset, s5_tid, H5S_ALL, H5S_ALL, PRESERVE, s5)<0) { goto error; } /* Check that the data was read properly */ for (i=0; i<NX*NY; i++) { if (s1[i].a!=s5[i].a || s1[i].b!=s5[i].b || s1[i].c[0]!=s5[i].c[0] || s1[i].c[1]!=s5[i].c[1] || s1[i].c[2]!=s5[i].c[2] || s1[i].c[3]!=s5[i].c[3] || s1[i].d!=s5[i].d || s1[i].e!=s5[i].e) { puts("*FAILED*"); puts(" Incorrect values read from the file"); goto error; } } /* Check that no previous values were clobbered */ for (i=0; i<NX*NY; i++) { if (s5[i].pre != 1000+4*i || s5[i].mid1 != 1001+4*i || s5[i].mid2 != 1002+4*i || s5[i].post != 1003+4*i) { puts("*FAILED*"); puts(" Memory values were clobbered"); goto error; } } puts(" PASSED"); /* *###################################################################### * STEP 6: Update fields `b' and `d' on the file leaving the other * fields unchanged. This tests member alignment and background * buffers. */ printf("%-70s", "Testing partially initialized superset write"); fflush (stdout); /* Initialize `s4' with new values */ for (i=0; i<NX*NY; i++) { s4[i].b = 8*i+1; s4[i].d = 8*i+6; } /* Write the data to file */ if (H5Dwrite (dataset, s4_tid, H5S_ALL, H5S_ALL, PRESERVE, s4)<0) { goto error; } /* Read the data back */ if (H5Dread (dataset, s1_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, s1)<0) { goto error; } /* Compare */ for (i=0; i<NX*NY; i++) { if (s1[i].a != 8*i+0 || s1[i].b != 8*i+1 || s1[i].c[0] != 8*i+2 || s1[i].c[1] != 8*i+3 || s1[i].c[2] != 8*i+4 || s1[i].c[3] != 8*i+5 || s1[i].d != 8*i+6 || s1[i].e != 8*i+7) { puts("*FAILED*"); puts(" File values were clobbered"); goto error; } } puts(" PASSED"); /* *###################################################################### * STEP 7. Read the original dataset with an explicit data space. Even * though these data spaces are equal it tests a different part of the * library. */ printf("%-70s", "Testing explicit data space"); fflush (stdout); /* Create the data space */ if ((s7_sid = H5Screate_simple (2, dim, NULL))<0) goto error; /* Read the dataset */ if (H5Dread (dataset, s2_tid, s7_sid, H5S_ALL, H5P_DEFAULT, s2)<0) { goto error; } /* Compare */ for (i=0; i<NX*NY; i++) { if (s2[i].a != s1[i].a || s2[i].b != s1[i].b || s2[i].c[0] != s1[i].c[0] || s2[i].c[1] != s1[i].c[1] || s2[i].c[2] != s1[i].c[2] || s2[i].c[3] != s1[i].c[3] || s2[i].d != s1[i].d || s2[i].e != s1[i].e) { puts("*FAILED*"); puts(" Incorrect values read from file"); goto error; } } puts(" PASSED"); /* *###################################################################### * STEP 8. Read a hyperslab of the file into a complete array in memory. * The hyperslab is the middle third of the array. */ printf("%-70s", "Testing hyperslab partial read to array"); fflush (stdout); /* Create the file data space */ if ((s8_f_sid = H5Dget_space (dataset))<0) goto error; f_offset[0] = NX/3; f_offset[1] = NY/3; h_size[0] = 2*NX/3 - f_offset[0]; h_size[1] = 2*NY/3 - f_offset[1]; if (H5Sselect_hyperslab (s8_f_sid, H5S_SELECT_SET, f_offset, NULL, h_size, NULL)<0) goto error; /* Create memory data space */ if ((s8_m_sid = H5Screate_simple (2, h_size, NULL))<0) goto error; /* Read the dataset */ s8 = calloc ((size_t)(h_size[0]*h_size[1]), sizeof(s1_t)); assert (s8); if (H5Dread (dataset, s1_tid, s8_m_sid, s8_f_sid, H5P_DEFAULT, s8)<0) { goto error; } /* Compare */ for (i=0; i<h_size[0]; i++) { for (j=0; j<h_size[1]; j++) { s1_t *ps1 = s1 + (f_offset[0]+i)*NY + f_offset[1] + j; s1_t *ps8 = s8 + i*h_size[1] + j; if (ps8->a != ps1->a || ps8->b != ps1->b || ps8->c[0] != ps1->c[0] || ps8->c[1] != ps1->c[1] || ps8->c[2] != ps1->c[2] || ps8->c[3] != ps1->c[3] || ps8->d != ps1->d || ps8->e != ps1->e) { puts("*FAILED*"); puts(" Incorrect values read from file"); goto error; } } } free (s8); s8 = NULL; puts(" PASSED"); /* *###################################################################### * STEP 9. Read a hyperslab of the file into a hyperslab of memory. The * part of memory not read is already initialized and must not change. */ printf("%-70s", "Testing hyperslab partial read to another hyperslab"); fflush (stdout); /* Initialize */ for (i=0; i<NX*NY; i++) { s2[i].a = s2[i].b = s2[i].d = s2[i].e = (unsigned)(-1); s2[i].c[0] = s2[i].c[1] = s2[i].c[2] = s2[i].c[3] = (unsigned)(-1); } /* Read the hyperslab */ if (H5Dread (dataset, s2_tid, s8_f_sid, s8_f_sid, H5P_DEFAULT, s2)<0) { goto error; } /* Compare */ for (i=0; i<NX; i++) { for (j=0; j<NY; j++) { s1_t *ps1 = s1 + i*NY + j; s2_t *ps2 = s2 + i*NY + j; if ((hssize_t)i>=f_offset[0] && (hsize_t)i<f_offset[0]+h_size[0] && (hssize_t)j>=f_offset[1] && (hsize_t)j<f_offset[1]+h_size[1]) { if (ps2->a != ps1->a || ps2->b != ps1->b || ps2->c[0] != ps1->c[0] || ps2->c[1] != ps1->c[1] || ps2->c[2] != ps1->c[2] || ps2->c[3] != ps1->c[3] || ps2->d != ps1->d || ps2->e != ps1->e) { puts("*FAILED*"); puts(" Memory values clobbered"); goto error; } } else { if (ps2->a != (unsigned)(-1) || ps2->b != (unsigned)(-1) || ps2->c[0] != (unsigned)(-1) || ps2->c[1] != (unsigned)(-1) || ps2->c[2] != (unsigned)(-1) || ps2->c[3] != (unsigned)(-1) || ps2->d != (unsigned)(-1) || ps2->e != (unsigned)(-1)) { puts("*FAILED*"); puts(" Incorrect values read from file"); goto error; } } } } puts(" PASSED"); /* *###################################################################### * STEP 10. Same as step 9 except the memory array contains some members * which are already initialized, like step 5. */ printf("%-70s", "Testing hyperslab to hyperslab part initialized read"); fflush (stdout); /* Initialize */ for (i=0; i<NX*NY; i++) { s5[i].a = s5[i].b = s5[i].d = s5[i].e = (unsigned)(-1); s5[i].c[0] = s5[i].c[1] = s5[i].c[2] = s5[i].c[3] = (unsigned)(-1); s5[i].pre = s5[i].mid1 = s5[i].mid2 = s5[i].post = (unsigned)(-1); } /* Read the hyperslab */ if (H5Dread (dataset, s5_tid, s8_f_sid, s8_f_sid, PRESERVE, s5)<0) { goto error; } /* Compare */ for (i=0; i<NX; i++) { for (j=0; j<NY; j++) { s1_t *ps1 = s1 + i*NY + j; s5_t *ps5 = s5 + i*NY + j; if ((hssize_t)i>=f_offset[0] && (hsize_t)i<f_offset[0]+h_size[0] && (hssize_t)j>=f_offset[1] && (hsize_t)j<f_offset[1]+h_size[1]) { if (ps5->pre != (unsigned)(-1) || ps5->a != ps1->a || ps5->b != ps1->b || ps5->mid1 != (unsigned)(-1) || ps5->c[0] != ps1->c[0] || ps5->c[1] != ps1->c[1] || ps5->c[2] != ps1->c[2] || ps5->c[3] != ps1->c[3] || ps5->mid2 != (unsigned)(-1) || ps5->d != ps1->d || ps5->e != ps1->e || ps5->post != (unsigned)(-1)) { puts("*FAILED*"); puts(" Memory values clobbered"); goto error; } } else { if (ps5->pre != (unsigned)(-1) || ps5->a != (unsigned)(-1) || ps5->b != (unsigned)(-1) || ps5->mid1 != (unsigned)(-1) || ps5->c[0] != (unsigned)(-1) || ps5->c[1] != (unsigned)(-1) || ps5->c[2] != (unsigned)(-1) || ps5->c[3] != (unsigned)(-1) || ps5->mid2 != (unsigned)(-1) || ps5->d != (unsigned)(-1) || ps5->e != (unsigned)(-1) || ps5->post != (unsigned)(-1)) { puts("*FAILED*"); puts(" Incorrect values read from file"); goto error; } } } } puts(" PASSED"); /* *###################################################################### * Step 11: Write an array into the middle third of the dataset * initializeing only members `b' and `d' to -1. */ #if 0 printf ("\ STEP 11: Write an array back to the middle third of the dataset to\n\ initialize the `b' and `d' members to -1.\n"); fflush (stdout); /* Create the memory array and initialize all fields to zero */ ndims = 2; f_offset[0] = NX/3; f_offset[1] = NY/3; h_size[0] = 2*NX/3 - f_offset[0]; h_size[1] = 2*NY/3 - f_offset[1]; s11 = malloc ((size_t)h_size[0]*(size_t)h_size[1]*sizeof(s4_t)); assert (s11); /* Initialize */ for (i=0; i<h_size[0]*h_size[1]; i++) { s11[i].b = s11[i].d = (unsigned)(-1); } /* Write to disk */ status = H5Dwrite (dataset, s4_tid, s8_m_sid, s8_f_sid, PRESERVE, s11); assert (status>=0); free (s11); s11=NULL; /* Read the whole thing */ status = H5Dread (dataset, s1_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, s1); assert (status>=0); /* Compare */ for (i=0; i<NX; i++) { for (j=0; j<NY; j++) { s1_t *ps1 = s1 + i*NY + j; assert (ps1->a == 8*(i*NY+j)+0); assert (ps1->c[0] == 8*(i*NY+j)+2); assert (ps1->c[1] == 8*(i*NY+j)+3); assert (ps1->c[2] == 8*(i*NY+j)+4); assert (ps1->c[3] == 8*(i*NY+j)+5); assert (ps1->e == 8*(i*NY+j)+7); if ((hssize_t)i>=f_offset[0] && (hsize_t)i<f_offset[0]+h_size[0] && (hssize_t)j>=f_offset[1] && (hsize_t)j<f_offset[1]+h_size[1]) { assert (ps1->b == (unsigned)(-1)); assert (ps1->d == (unsigned)(-1)); } else { assert (ps1->b == 8*(i*NY+j)+1); assert (ps1->d == 8*(i*NY+j)+6); } } } #endif /* * Release resources. */ H5Pclose (PRESERVE); H5Dclose (dataset); H5Fclose (file); cleanup(); puts("All compound dataset tests passed."); return 0; error: cleanup(); puts("Remaining tests have been skipped."); puts("*** DATASET TESTS FAILED ***"); return 1; }