1 /* This is part of the netCDF package.
2    Copyright 2005 University Corporation for Atmospheric Research/Unidata
3    See COPYRIGHT file for conditions of use.
4 
5    Test that HDF5 and NetCDF-4 can read and write the same file.
6 
7    $Id: tst_interops.c,v 1.24 2010/06/01 15:34:52 ed Exp $
8 */
9 #include <config.h>
10 #include <nc_tests.h>
11 #include "err_macros.h"
12 #include <hdf5.h>
13 #include <H5DSpublic.h>
14 
15 #define FILE_NAME "tst_interops.h5"
16 #define DIMSCALE_NAME "dimscale"
17 #define VAR1_NAME "var1"
18 #define NDIMS 1
19 #define DIM1_LEN 3
20 #define NAME_ATTRIBUTE "dimscale_name_attribute"
21 #define DIMSCALE_LABEL "dimscale_label"
22 #define LAT_LEN 3
23 #define LON_LEN 2
24 #define DIMS_2 2
25 #define LAT_NAME "lat"
26 #define LON_NAME "lon"
27 #define PRES_NAME "pres"
28 #define TEMP_NAME "temp"
29 #define ATT_NAME "song"
30 #define NEW_FLOAT 1.0
31 
32 void
printRes(const char * msg,int ires)33 printRes(const char *msg, int ires)
34 {
35    printf("%s: %d\n", msg, ires);
36    if (ires < 0)
37    {
38       printf("bad ires: %d\n", ires);
39       /*H5Eprint2(ires, stdout);*/
40       exit(1);
41    }
42 }
43 
44 static char song[] = "Oh, better far to live and die\n\
45 Under the brave black flag I fly,\n\
46 Than play a sanctimonious part,\n\
47 With a pirate head and a pirate heart.\n\
48 Away to the cheating world go you,\n\
49 Where pirates all are well-to-do;\n\
50 But I.ll be true to the song I sing,\n\
51 And live and die a Pirate King.\n\
52 For I am a Pirate King!\n\
53 And it is, it is a glorious thing\n\
54 To be a Pirate King!\n";
55 
56 int
main(int argc,char ** argv)57 main(int argc, char **argv)
58 {
59    printf("\n*** Testing HDF5/NetCDF-4 interoperability...\n");
60    printf("*** Creating a HDF5 file with one var with two dimension scales...");
61    {
62       hid_t fileid, lat_spaceid, lon_spaceid, pres_spaceid;
63       hid_t pres_datasetid, lat_dimscaleid, lon_dimscaleid;
64       hsize_t dims[DIMS_2];
65       hid_t fapl_id = H5P_DEFAULT, fcpl_id = H5P_DEFAULT;
66 
67       /* Set latest_format in access propertly list and
68        * H5P_CRT_ORDER_TRACKED in the creation property list. This turns
69        * on HDF5 creation ordering. */
70       if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
71       if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
72       if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0) ERR;
73       if (H5Pset_link_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
74 					       H5P_CRT_ORDER_INDEXED)) < 0) ERR;
75 
76       /* Create file. */
77       if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, fcpl_id, fapl_id)) < 0) ERR;
78       if (H5Pclose(fcpl_id) < 0) ERR;
79       if (H5Pclose(fapl_id) < 0) ERR;
80 
81       /* Create the spaces that will be used for the dimscales. */
82       dims[0] = LAT_LEN;
83       if ((lat_spaceid = H5Screate_simple(1, dims, dims)) < 0) ERR;
84       dims[0] = LON_LEN;
85       if ((lon_spaceid = H5Screate_simple(1, dims, dims)) < 0) ERR;
86 
87       /* Create the space for the dataset. */
88       dims[0] = LAT_LEN;
89       dims[1] = LON_LEN;
90       if ((pres_spaceid = H5Screate_simple(DIMS_2, dims, dims)) < 0) ERR;
91 
92       /* Create our dimension scales. */
93       if ((lat_dimscaleid = H5Dcreate(fileid, LAT_NAME, H5T_NATIVE_INT,
94 				      lat_spaceid, H5P_DEFAULT)) < 0) ERR;
95       if (H5DSset_scale(lat_dimscaleid, NULL) < 0) ERR;
96       if ((lon_dimscaleid = H5Dcreate(fileid, LON_NAME, H5T_NATIVE_INT,
97 				      lon_spaceid, H5P_DEFAULT)) < 0) ERR;
98       if (H5DSset_scale(lon_dimscaleid, NULL) < 0) ERR;
99 
100       /* Create a variable which uses these two dimscales. */
101       if ((pres_datasetid = H5Dcreate(fileid, PRES_NAME, H5T_NATIVE_FLOAT,
102 				      pres_spaceid, H5P_DEFAULT)) < 0) ERR;
103       if (H5DSattach_scale(pres_datasetid, lat_dimscaleid, 0) < 0) ERR;
104       if (H5DSattach_scale(pres_datasetid, lon_dimscaleid, 1) < 0) ERR;
105 
106       /* Fold up our tents. */
107       if (H5Dclose(lat_dimscaleid) < 0 ||
108 	  H5Dclose(lon_dimscaleid) < 0 ||
109 	  H5Dclose(pres_datasetid) < 0 ||
110 	  H5Sclose(lat_spaceid) < 0 ||
111 	  H5Sclose(lon_spaceid) < 0 ||
112 	  H5Sclose(pres_spaceid) < 0 ||
113 	  H5Fclose(fileid) < 0) ERR;
114    }
115    SUMMARIZE_ERR;
116    printf("*** Checking that HDF5 file can be read by netCDF-4, and adding an att...");
117    {
118       int ncid;
119       char name_in[NC_MAX_NAME + 1];
120       int natts_in, ndims_in, nvars_in, varid_in, dimids_in[5], unlimdimid_in;
121       size_t len_in;
122       nc_type xtype_in;
123       size_t index[2];
124       float new_float = NEW_FLOAT;
125 
126       if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
127 
128       /* Check it out. Can't count on creation order until HDF5 1.8.0,
129        * so the following code doesn't depend on it. */
130       if (nc_inq(ncid, &ndims_in, &nvars_in, &natts_in, &unlimdimid_in)) ERR;
131       if (ndims_in != 2 || nvars_in != 3 || natts_in != 0 || unlimdimid_in != -1) ERR;
132       if (nc_inq_varid(ncid, PRES_NAME, &varid_in)) ERR;
133       if (nc_inq_var(ncid, varid_in, name_in, &xtype_in, &ndims_in, dimids_in, &natts_in)) ERR;
134       if (strcmp(name_in, PRES_NAME) || xtype_in != NC_FLOAT || ndims_in != 2 ||
135 	  natts_in != 0) ERR;
136       if (nc_inq_dim(ncid, dimids_in[0], name_in, &len_in)) ERR;
137       if (len_in != LAT_LEN || strcmp(name_in, LAT_NAME)) ERR;
138       if (nc_inq_dim(ncid, dimids_in[1], name_in, &len_in)) ERR;
139       if (len_in != LON_LEN || strcmp(name_in, LON_NAME)) ERR;
140 
141       /* Change some data. */
142       index[0] = index[1] = 0;
143       if (nc_put_var1_float(ncid, varid_in, index, &new_float)) ERR;
144 
145       /* Just for swank, add an attribute. Now we're talking
146        * interoperabity, dude! */
147       if (nc_put_att_text(ncid, NC_GLOBAL, ATT_NAME, strlen(song)+1,
148 			  song)) ERR;
149 
150       if (nc_close(ncid)) ERR;
151    }
152    SUMMARIZE_ERR;
153    printf("*** Checking that one var, two dimscales, one att file can still be read by HDF5...");
154 
155    {
156       hid_t fileid, spaceid, datasetid, attid, typeid, grpid;
157       char song_in[1024];
158       float pres_in[LAT_LEN][LON_LEN];
159 
160       /* Open the file. */
161       if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) ERR;
162       if ((grpid = H5Gopen(fileid, "/")) < 0) ERR;
163 
164       /* Check it out. */
165       if ((datasetid = H5Dopen1(grpid, PRES_NAME)) < 0) ERR;
166       if ((spaceid = H5Dget_space(datasetid)) < 0) ERR;
167       if (H5Dread(datasetid, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL,
168 		  H5P_DEFAULT, pres_in) < 0) ERR;
169       if (pres_in[0][0] != NEW_FLOAT) ERR;
170       if ((attid = H5Aopen_name(grpid, ATT_NAME)) < 0) ERR;
171       if ((typeid = H5Aget_type(attid)) < 0) ERR;
172       if (H5Aread(attid, typeid, song_in) < 0) ERR;
173       if (strcmp(song, song_in)) ERR;
174 
175       /* Close up the shop. */
176       if (H5Tclose(typeid) < 0 ||
177 	  H5Aclose(attid) < 0 ||
178 	  H5Sclose(spaceid) < 0 ||
179 	  H5Dclose(datasetid) < 0 ||
180 	  H5Gclose(grpid) < 0 ||
181 	  H5Fclose(fileid) < 0) ERR;
182    }
183    SUMMARIZE_ERR;
184    printf("*** Creating a HDF5 file with one var and no dimension scales...");
185    {
186       hid_t fileid, pres_spaceid, pres_datasetid;
187       hsize_t dims[DIMS_2];
188       hid_t fapl_id, fcpl_id;
189       int ncid, nvars_in, ndims_in, natts_in, unlimdim_in;
190       size_t len_in;
191 
192       /* Set latest_format in access propertly list and
193        * H5P_CRT_ORDER_TRACKED in the creation property list. This
194        * turns on HDF5 creation ordering. */
195       if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
196       if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
197       if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0) ERR;
198       if (H5Pset_link_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
199 					       H5P_CRT_ORDER_INDEXED)) < 0) ERR;
200 
201       /* Create file. */
202       if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, fcpl_id, fapl_id)) < 0) ERR;
203       if (H5Pclose(fcpl_id) < 0) ERR;
204       if (H5Pclose(fapl_id) < 0) ERR;
205 
206       /* Create the space for the dataset. */
207       dims[0] = LAT_LEN;
208       dims[1] = LON_LEN;
209       if ((pres_spaceid = H5Screate_simple(DIMS_2, dims, dims)) < 0) ERR;
210 
211       /* Create a variable. It will not have dimension scales. */
212       if ((pres_datasetid = H5Dcreate(fileid, PRES_NAME, H5T_NATIVE_FLOAT,
213 				      pres_spaceid, H5P_DEFAULT)) < 0) ERR;
214 
215       /* Ring down the curtain. */
216       if (H5Dclose(pres_datasetid) < 0 ||
217 	  H5Sclose(pres_spaceid) < 0 ||
218 	  H5Fclose(fileid) < 0) ERR;
219 
220       /* Read the data with netCDF. */
221       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
222       if (nc_inq(ncid, &ndims_in, &nvars_in, &natts_in, &unlimdim_in)) ERR;
223       if (ndims_in != 2 || nvars_in != 1 || natts_in != 0 || unlimdim_in != -1) ERR;
224       if (nc_inq_dim(ncid, 0, NULL, &len_in)) ERR;
225       if (len_in != LAT_LEN) ERR;
226       if (nc_inq_dim(ncid, 1, NULL, &len_in)) ERR;
227       if (len_in != LON_LEN) ERR;
228       if (nc_close(ncid)) ERR;
229    }
230    SUMMARIZE_ERR;
231    printf("*** Creating a HDF5 file with one var and no dimension scales, without creation ordering...");
232    {
233       hid_t fileid, pres_spaceid, pres_datasetid;
234       hsize_t dims[DIMS_2];
235       int ncid, nvars_in, ndims_in, natts_in, unlimdim_in;
236       size_t len_in;
237 
238       /* Create file. */
239       if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT,
240 			      H5P_DEFAULT)) < 0) ERR;
241 
242       /* Create the space for the dataset. */
243       dims[0] = LAT_LEN;
244       dims[1] = LON_LEN;
245       if ((pres_spaceid = H5Screate_simple(DIMS_2, dims, dims)) < 0) ERR;
246 
247       /* Create a variable. It will not have dimension scales. */
248       if ((pres_datasetid = H5Dcreate(fileid, PRES_NAME, H5T_NATIVE_FLOAT,
249 				      pres_spaceid, H5P_DEFAULT)) < 0) ERR;
250 
251       /* Ring down the curtain. */
252       if (H5Dclose(pres_datasetid) < 0 ||
253 	  H5Sclose(pres_spaceid) < 0 ||
254 	  H5Fclose(fileid) < 0) ERR;
255 
256       /* Read the data with netCDF. */
257       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
258       if (nc_inq(ncid, &ndims_in, &nvars_in, &natts_in, &unlimdim_in)) ERR;
259       if (ndims_in != 2 || nvars_in != 1 || natts_in != 0 || unlimdim_in != -1) ERR;
260       if (nc_inq_dim(ncid, 0, NULL, &len_in)) ERR;
261       if (len_in != LAT_LEN) ERR;
262       if (nc_inq_dim(ncid, 1, NULL, &len_in)) ERR;
263       if (len_in != LON_LEN) ERR;
264       if (nc_close(ncid)) ERR;
265    }
266    SUMMARIZE_ERR;
267    printf("*** Creating a HDF5 file with two vars and no dimension scales, without creation ordering...");
268    {
269       hid_t fileid, spaceid, pres_datasetid, temp_datasetid;
270       hsize_t dims[DIMS_2];
271       int ncid, nvars_in, ndims_in, natts_in, unlimdim_in;
272       size_t len_in;
273 
274       /* Create file. */
275       if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT,
276 			      H5P_DEFAULT)) < 0) ERR;
277 
278       /* Create the space for the datasets. */
279       dims[0] = LAT_LEN;
280       dims[1] = LON_LEN;
281       if ((spaceid = H5Screate_simple(DIMS_2, dims, dims)) < 0) ERR;
282 
283       /* Create two datasets. They will not have dimension scales. */
284       if ((pres_datasetid = H5Dcreate(fileid, PRES_NAME, H5T_NATIVE_FLOAT,
285 				      spaceid, H5P_DEFAULT)) < 0) ERR;
286       if ((temp_datasetid = H5Dcreate(fileid, TEMP_NAME, H5T_NATIVE_FLOAT,
287 				      spaceid, H5P_DEFAULT)) < 0) ERR;
288 
289       /* Ring down the curtain. */
290       if (H5Dclose(pres_datasetid) < 0 ||
291 	  H5Dclose(temp_datasetid) < 0 ||
292 	  H5Sclose(spaceid) < 0 ||
293 	  H5Fclose(fileid) < 0) ERR;
294 
295       /* Read the data with netCDF. */
296       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
297       if (nc_inq(ncid, &ndims_in, &nvars_in, &natts_in, &unlimdim_in)) ERR;
298       if (ndims_in != 2 || nvars_in != 2 || natts_in != 0 || unlimdim_in != -1) ERR;
299       if (nc_inq_dim(ncid, 0, NULL, &len_in)) ERR;
300       if (len_in != LAT_LEN) ERR;
301       if (nc_inq_dim(ncid, 1, NULL, &len_in)) ERR;
302       if (len_in != LON_LEN) ERR;
303       if (nc_close(ncid)) ERR;
304    }
305    SUMMARIZE_ERR;
306    printf("*** Creating a HDF5 file with fixed length string...");
307    {
308 #define ATT_LEN 3
309 #define ATT_NAME2 "genius"
310 #define MAX_LEN 6
311       hid_t fileid, spaceid, typeid, attid, fapl_id;
312       hid_t class;
313       int ncid, nvars_in, ndims_in, natts_in, unlimdim_in;
314       char data[ATT_LEN][MAX_LEN + 1] = {"Larry_", "Curley", "Moe111"};
315       char *data_in, *cur, *data_in2[ATT_LEN];
316       hsize_t dims[1] = {ATT_LEN};
317       nc_type type_in;
318       size_t size_in;
319       int i;
320 
321       /* Create file. */
322       if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT,
323 			      H5P_DEFAULT)) < 0) ERR;
324 
325 
326       if ((typeid =  H5Tcopy(H5T_C_S1)) < 0) ERR;
327       if (H5Tset_size(typeid, MAX_LEN + 1) < 0) ERR;
328 
329       /* Write an attribute of this (string) type. */
330       if ((spaceid = H5Screate_simple(1, dims, NULL)) < 0) ERR;
331       if ((attid = H5Acreate(fileid, ATT_NAME2, typeid, spaceid,
332 			     H5P_DEFAULT)) < 0) ERR;
333       if (H5Awrite(attid, typeid, data) < 0) ERR;
334 
335       /* Close HDF5 objects. */
336       if (H5Aclose(attid) < 0) ERR;
337       if (H5Sclose(spaceid) < 0) ERR;
338       if (H5Tclose(typeid) < 0) ERR;
339       if (H5Fclose(fileid) < 0) ERR;
340 
341       /* Open the file and read the attribute of fixed length
342        * strings. */
343       if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) ERR;
344       if ((attid = H5Aopen_name(fileid, ATT_NAME2)) < 0) ERR;
345       if ((typeid = H5Aget_type(attid)) < 0) ERR;
346 
347       /* Given this type id, how would we know this is a string
348        * attribute? */
349       if ((class = H5Tget_class(typeid)) < 0)
350 	 return NC_EHDFERR;
351       if (class != H5T_STRING) ERR;
352 /*      if (!(type_size = H5Tget_size(typeid))) ERR;
353 	if ((is_str = H5Tis_variable_str(typeid)) < 0) ERR;*/
354 
355       /* How many strings are in the string array? */
356       if ((spaceid = H5Aget_space(attid)) < 0) ERR;
357       if (H5Sget_simple_extent_dims(spaceid, dims, NULL) < 0) ERR;
358       if (!(data_in = malloc(dims[0] * sizeof(char *) * (MAX_LEN + 1)))) ERR;
359 
360       /* Now read the array of strings. The HDF5 library will allocate
361        * space for each string. */
362       if (H5Aread(attid, typeid, data_in) < 0) ERR;
363 
364       /* Compare the values to make sure it worked... */
365       for (cur = data_in, i = 0; i < ATT_LEN; i++)
366       {
367 	 if (strcmp(data[i], cur)) ERR;
368 	 cur += MAX_LEN + 1;
369       }
370 
371       /* Free the memory that we allocated. */
372       free(data_in);
373 
374       /* Close everything up. */
375       if (H5Aclose(attid) < 0) ERR;
376       if (H5Tclose(typeid) < 0) ERR;
377       if (H5Fclose(fileid) < 0) ERR;
378 
379       /* Read the data with netCDF. */
380       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
381       if (nc_inq(ncid, &ndims_in, &nvars_in, &natts_in, &unlimdim_in)) ERR;
382       if (ndims_in != 0 || nvars_in != 0 || natts_in != 1 || unlimdim_in != -1) ERR;
383       if (nc_inq_att(ncid, NC_GLOBAL, ATT_NAME2, &type_in, &size_in)) ERR;
384       if (type_in != NC_STRING || size_in != ATT_LEN) ERR;
385       if (nc_get_att_string(ncid, NC_GLOBAL, ATT_NAME2, data_in2)) ERR;
386       for (i = 0; i < size_in; i++)
387 	 if (strcmp(data[i], data_in2[i])) ERR;
388       if (nc_free_string(size_in, data_in2)) ERR;
389 
390       /* Open the file with HDF5 while netcdf still has it open. */
391       if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
392       /* Turn this off for*/
393       if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI)) ERR;
394       if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDONLY, fapl_id)) < 0) ERR;
395       if (H5Pclose(fapl_id) < 0) ERR;
396       if (H5Fclose(fileid) < 0) ERR;
397 
398       if (nc_close(ncid)) ERR;
399    }
400    SUMMARIZE_ERR;
401 /*    printf("**** testing 2D coordinate variable..."); */
402 
403 /*    { */
404 /* #define VAR_NAME "Britany" */
405 /* #define NDIMS 2 */
406 /* #define TEXT_LEN 15 */
407 /* #define D0_NAME "time" */
408 /* #define D1_NAME "tl" */
409 /*       int ncid, nvars_in, varids_in[1]; */
410 /*       int time_dimids[NDIMS], time_id; */
411 /*       size_t time_count[NDIMS], time_index[NDIMS] = {0, 0}; */
412 /*       const char ttext[TEXT_LEN]="20051224.150000"; */
413 /*       int nvars, ndims, ngatts, unlimdimid; */
414 /*       int ndims_in, natts_in, dimids_in[NDIMS]; */
415 /*       char var_name_in[NC_MAX_NAME + 1]; */
416 /*       nc_type xtype_in; */
417 
418 /*       /\* Create a netcdf-4 file with 2D coordinate var. *\/ */
419 /*       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR; */
420 
421 /*       if (nc_def_dim(ncid, D0_NAME, NC_UNLIMITED, &time_dimids[0])) ERR; */
422 /*       if (nc_def_dim(ncid, D1_NAME, TEXT_LEN, &time_dimids[1])) ERR; */
423 /*       if (nc_def_var(ncid, D0_NAME, NC_CHAR, NDIMS, time_dimids, &time_id)) ERR; */
424 
425 /*       /\* Write one time to the coordinate variable. *\/ */
426 /*       time_count[0] = 1; */
427 /*       time_count[1] = TEXT_LEN; */
428 /*       if (nc_put_vara_text(ncid, time_id, time_index, time_count, ttext)) ERR; */
429 /*       if (nc_close(ncid)) ERR; */
430 
431 /*       /\* Open the file and check. *\/ */
432 /*       if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR; */
433 /*       if (nc_inq(ncid, &ndims, &nvars, &ngatts, &unlimdimid)) ERR; */
434 /*       if (nvars != 1 || ndims != 2 || ngatts != 0 || unlimdimid != 0) ERR; */
435 /*       if (nc_inq_varids(ncid, &nvars_in, varids_in)) ERR; */
436 /*       if (nvars_in != 1 || varids_in[0] != 0) ERR; */
437 /*       if (nc_inq_var(ncid, 0, var_name_in, &xtype_in, &ndims_in, dimids_in, &natts_in)) ERR; */
438 /*       if (strcmp(var_name_in, D0_NAME) || xtype_in != NC_CHAR || ndims_in != 2 || */
439 /* 	dimids_in[0] != 0 || dimids_in[1] != 1 || natts_in != 0) ERR; */
440 /*       if (nc_close(ncid)) ERR; */
441 /*    } */
442 /*    SUMMARIZE_ERR; */
443    FINAL_RESULTS;
444 }
445