Re: questions about H5DSiterate_scales

Howdy all!

I've isolated the code into it's own program, and you can see the
problem I'm having by compiling and running the program appended below
(tst_h_dimscales2.c) including its header file, tests.h, also appended
below.

This program creates a very simple HDF5 file (tst_h_dimscales2.h5),
with two 1D datasets. One dataset is marked as a dimension scale, the
other attaches it as it's dimscale. Then the file is closed. The
h5dump of the file at this point is included below. Everything looks
fine to me, including all the names.

The file is then reopened and I iterate through the objects. When I
find the dimscale I check the name, and it's fine. When I encounter
the other dataset, "var1", I check that it has one scale, and then
call iterate_scales to execute the function alien_visitor on that
dataset/dimscale combination.

The function, alien_visitor, gets the associated names of it's did and
dsid parameters. The did parameter yields a name, as expected:
"/var1". But the dsid parameter, which supposedly points to the
dimscale dataset, returns a name of garbage characters.

How do I know that dsid is really pointing to the dimscale dataset,
named "dimscale" in this example?

Is this a H5DS bug, or am I doing something horribly, tragically, but
hopefully not inexplicably wrong?

Thanks,

Ed

Here's the output:

./tst_h_dimscales2
*** Creating a file with one var with one dimension scale...ok.
*** Checking that one var, one dimscale file can be read...
Encountered: HDF5 object obj_class 2 obj_name dimscale
Encountered: HDF5 object obj_class 2 obj_name var1
unexpected result, tst_h_dimscales2.c, line: 34
visiting did 0x6000003 dim 0 dsid 0x6000004 name of did /var1 
:ú·šzäôÿ¿Ðõÿ¿
1 failures

h5dump of tst_h_dimscales2.h5:
HDF5 "tst_h_dimscales2.h5" {
GROUP "/" {
   DATASET "dimscale" {
      DATATYPE  H5T_STD_I32LE
      DATASPACE  SIMPLE { ( 3 ) / ( H5S_UNLIMITED ) }
      DATA {
      (0): 0, 0, 0
      }
      ATTRIBUTE "CLASS" {
         DATATYPE  H5T_STRING {
               STRSIZE 16;
               STRPAD H5T_STR_NULLTERM;
               CSET H5T_CSET_ASCII;
               CTYPE H5T_C_S1;
            }
         DATASPACE  SCALAR
         DATA {
         (0): "DIMENSION_SCALE"
         }
      }
      ATTRIBUTE "NAME" {
         DATATYPE  H5T_STRING {
               STRSIZE 24;
               STRPAD H5T_STR_NULLTERM;
               CSET H5T_CSET_ASCII;
               CTYPE H5T_C_S1;
            }
         DATASPACE  SCALAR
         DATA {
         (0): "dimscale_name_attribute"
         }
      }
      ATTRIBUTE "REFERENCE_LIST" {
         DATATYPE  H5T_COMPOUND {
            H5T_REFERENCE "dataset";
            H5T_STD_I32LE "dimension";
         }
         DATASPACE  SIMPLE { ( 1 ) / ( 1 ) }
         DATA {
         (0): {
               DATASET 1576 /var1 ,
               0
            }
         }
      }
   }
   DATASET "var1" {
      DATATYPE  H5T_STD_I32LE
      DATASPACE  SIMPLE { ( 3 ) / ( H5S_UNLIMITED ) }
      DATA {
      (0): 0, 0, 0
      }
      ATTRIBUTE "DIMENSION_LIST" {
         DATATYPE  H5T_VLEN { H5T_REFERENCE}
         DATASPACE  SIMPLE { ( 1 ) / ( 1 ) }
         DATA {
         (0): (DATASET 976 /dimscale )
         }
      }
      ATTRIBUTE "DIMENSION_LABELS" {
         DATATYPE  H5T_STRING {
               STRSIZE H5T_VARIABLE;
               STRPAD H5T_STR_NULLTERM;
               CSET H5T_CSET_ASCII;
               CTYPE H5T_C_S1;
            }
         DATASPACE  SIMPLE { ( 1 ) / ( 1 ) }
         DATA {
         (0): "dimscale_label"
         }
      }
   }
}
}


tests.h:

/* This is part of the netCDF package.
   Copyright 2005 University Corporation for Atmospheric Research/Unidata
   See COPYRIGHT file for conditions of use.

   Common includes, defines, etc., for test code in the libsrc4
   directory.

   $Id: tests.h,v 1.6 2005/06/06 20:36:22 ed Exp $
*/
#ifndef _NC4_TESTS_
#define _NC4_TESTS_

#include <config.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "error.h"

int total_err = 0, err = 0;

/* This is handy for print statements. */
char *format_name[] = {"", "classic", "64-bit offset", "netCDF-4", "netCDF-4 
strict NC3"};

#define ERR do { \
fflush(stdout); /* Make sure our stdout is synced with stderr. */ \
err++; \
fprintf(stderr, "unexpected result, %s, line: %d\n", __FILE__, __LINE__); \
} while (0)

#define SUMMARIZE_ERR do { \
   if (err) \
   { \
      printf("%d failures\n", err); \
      total_err += err; \
      err = 0; \
   } \
   else \
      printf("ok.\n"); \
} while (0)


#endif /* _NC4_TESTS_ */

tst_h_dimscales2.c:

/* This is part of the netCDF package.
   Copyright 2005 University Corporation for Atmospheric Research/Unidata
   See COPYRIGHT file for conditions of use.

   Test HDF5 file code. These are not intended to be exhaustive tests,
   but they use HDF5 the same way that netCDF-4 does, so if these
   tests don't work, than netCDF-4 won't work either.

   $Id: tst_h_dimscales.c,v 1.5 2005/07/01 09:33:05 ed Exp $
*/
#include "tests.h"
#include "H5DS.h"

#define FILE_NAME "tst_h_dimscales2.h5"
#define DIMSCALE_NAME "dimscale"
#define VAR1_NAME "var1"
#define NDIMS 1
#define DIM1_LEN 3
#define NAME_ATTRIBUTE "dimscale_name_attribute"
#define DIMSCALE_LABEL "dimscale_label"

herr_t alien_visitor(hid_t did, unsigned dim, hid_t dsid, 
                     void *visitor_data)
{
   char name1[NC_MAX_NAME], name2[NC_MAX_NAME];

   /* This should get "/var1", the name of the dataset that the scale
    * is attached to. */
   if (H5Iget_name(did, name1, NC_MAX_NAME) < 0) ERR;
   if (strcmp(&name1[1], VAR1_NAME)) ERR;
   
   /* This should get "/dimscale" but it doesn't seem to be! */
   if (H5Iget_name(dsid, name2, NC_MAX_NAME) < 0) ERR;
   if (strcmp(&name2[1], DIMSCALE_NAME)) ERR;

   printf("visiting did 0x%x dim %d dsid 0x%x name of did %s \n", 
          did, dim, dsid, name1);
   printf("name of dsid: %s\n", name2);
   return 0;
}

int
main()
{
   printf("*** Creating a file with one var with one dimension scale...");
   
   {
      hid_t fileid, spaceid, datasetid, dimscaleid, cparmsid;
      hsize_t dims[NDIMS] = {DIM1_LEN}, maxdims[NDIMS] = {H5S_UNLIMITED};

      /* Create file. */
      if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, 
                              H5P_DEFAULT)) < 0) ERR;

      /* Create the space that will be used both for the dimscale and
       * the 1D dataset that will attach it. */
      if ((spaceid = H5Screate_simple(NDIMS, dims, maxdims)) < 0) ERR;

      /* Modify dataset creation properties, i.e. enable chunking. */
      dims[0] = 1;
      if ((cparmsid = H5Pcreate(H5P_DATASET_CREATE)) < 0) ERR;
      if (H5Pset_chunk(cparmsid, NDIMS, dims) < 0) ERR;

      /* Create our dimension scale, as an unlimited dataset. */
      if ((dimscaleid = H5Dcreate(fileid, DIMSCALE_NAME, H5T_NATIVE_INT, 
                                  spaceid, cparmsid)) < 0) ERR;
      if (H5DSset_scale(dimscaleid, NAME_ATTRIBUTE) < 0) ERR;

      /* Create a variable which uses it. */
      if ((datasetid = H5Dcreate(fileid, VAR1_NAME, H5T_NATIVE_INT, 
                                 spaceid, cparmsid)) < 0) ERR;
      if (H5DSattach_scale(datasetid, dimscaleid, 0) < 0) ERR;
      if (H5DSset_label(datasetid, 0, DIMSCALE_LABEL) < 0) ERR;

      /* Fold up our tents. */
      if (H5Dclose(dimscaleid) < 0 ||
          H5Dclose(datasetid) < 0 ||
          H5Sclose(spaceid) < 0 ||
          H5Fclose(fileid) < 0) ERR;
   }

   SUMMARIZE_ERR;
   printf("*** Checking that one var, one dimscale file can be read...");

   {
      hid_t fileid, spaceid = 0, datasetid = 0;
      hsize_t num_obj, i;
      int obj_class;
      char obj_name[NC_MAX_NAME + 1];
      char dimscale_name[NC_MAX_NAME+1];
      htri_t is_scale;
      char label[NC_MAX_NAME+1];
      int visitor_data = 0;
      int num_scales;
      hsize_t dims[1], maxdims[1];

      /* Open the file. */
      if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) ERR;
      
      /* Loop through objects in the root group. */
      if (H5Gget_num_objs(fileid, &num_obj) < 0) ERR;
      for (i=0; i<num_obj; i++)
      {
         /* Get the type (i.e. group, dataset, etc.), and the name of
          * the object. */
         if ((obj_class = H5Gget_objtype_by_idx(fileid, i)) < 0) ERR;
         if (H5Gget_objname_by_idx(fileid, i, obj_name, NC_MAX_NAME) < 0) ERR;

         printf("\nEncountered: HDF5 object obj_class %d obj_name %s\n", 
                obj_class, obj_name);

         /* Deal with object based on its obj_class. */
         switch(obj_class)
         {
            case H5G_GROUP:
               break;
            case H5G_DATASET:
               /* Open the dataset. */
               if ((datasetid = H5Dopen(fileid, obj_name)) < 0) ERR;

               /* This should be an unlimited dataset. */
               if ((spaceid = H5Dget_space(datasetid)) < 0) ERR;
               if (H5Sget_simple_extent_dims(spaceid, dims, maxdims) < 0) ERR;
               if (maxdims[0] != H5S_UNLIMITED) ERR;

               /* Is this a dimscale? */
               if ((is_scale = H5DSis_scale(datasetid)) < 0) ERR;
               if (is_scale && strcmp(obj_name, DIMSCALE_NAME)) ERR;
               if (is_scale)
               {
                  /* A dimscale comes with a NAME attribute, in
                   * addition to it's real name. */
                  if (H5DSget_scale_name(datasetid, dimscale_name, NC_MAX_NAME) 
< 0) ERR;
                  if (strcmp(dimscale_name, NAME_ATTRIBUTE)) ERR;
               }
               else
               {
                  /* Here's how to get the number of scales attached
                   * to the dataset's dimension 0. */
                  if ((num_scales = H5DSget_num_scales(datasetid, 0)) < 0) ERR;
                  if (num_scales != 1) ERR;

                  /* Go through all dimscales for this var and learn about 
them. */
                  if (H5DSiterate_scales(datasetid, 0, NULL, alien_visitor, 
                                         &visitor_data) < 0) ERR;
                  
                  /* There's also a label for dimension 0. */
                  if (H5DSget_label(datasetid, 0, label, NC_MAX_NAME) < 0) ERR;

                  /*printf("found non-scale dataset %s, label %s\n", obj_name, 
label);*/
               }
               if (H5Dclose(datasetid) < 0) ERR;
               break;
            case H5G_TYPE:
               break;
            case H5G_LINK:
               break;
            default:
               printf("Unknown object class %d in rec_read_metadata!", 
obj_class);
         }
      }

      /* Close up the shop. */
      if (H5Sclose(spaceid) < 0 ||
          H5Fclose(fileid) < 0) ERR;
   }

   SUMMARIZE_ERR;

   /* Print out our number of errors, if any, and exit badly. */
   if (total_err)
   {
      printf("%d errors detected! Sorry!\n", total_err);
      return 2;
   }
   
   printf("*** Tests successful!\n");
   return 0;
}



-- 
Ed Hartnett  -- ed@xxxxxxxxxxxxxxxx