C# HDF5 Batch Behavior Error

Everyone,

I'm new to the HDF5 community, and I'm using the HDF5.net library to help
with some data processing.

We have built a file format around HDF5 that specifies how recorded sensor
channels should be stored. I'm trying to write some some software for that
file format in C#. Right now all I'm trying to do is batch dump the file
format to CSV as a proof of concept that I understand how to read the
datasets and attributes.

The basic flow is I open the HDF5 file and recurse through the groups to
find all of the datasets. I store the path of the datasets in class.

From there I open each of the datasets and read the data into an array.

The array is then processed and stored in memory and then eventually
dumped to CSV.

The problem I'm having is that the code is processing multiple HDF5 files
in sequence, and I start to get errors on the 6th file in the sequence. So
if I have 10 files, the first file process just fine, but the last five
all have errors. It doesn't matter which files they are they just throw an
error. If I restart the software and just have them process the file that
failed before it works just fine.

The error that is thrown is H5G.getObjectNameByIndex:
  Failed to find name of object in group 2000018 with index 0

Which is called in my findChildren function. The line of code that throws
the exception is:
string obj_name = H5G.getObjectNameByIndex(curr_group, j);

Here is the code I'm currently using

if(datasets.Count == 0)
        getDatasets();

//open the HDF5 library
H5.Open();

//open the file
H5FileId gh5file = H5F.open(fname, H5F.OpenMode.ACC_RDONLY);

double[][] data = new double[numElems][];
for(int i = 0; i < numElems; i++)
        data[i] = new double[datasets.Count];

for (int i = 0; i < datasets.Count; i++)
{
        if (datasets[i].dtype_size == 4 && datasets[i].order == H5T.Order
.LE)
        {
                float[] dataArray = readArray<float>(gh5file, i);

                for (int j = 0; j < dataArray.Length; j++)
        {
                        data[j][i] = dataArray[j];
        }
        }
        //repeat for Big Endian and 8 byte floats
}

using (StreamWriter sw = new StreamWriter(csv_filename))
{
        //write data[j][i] to the csv file
}

H5F.close(gh5file);
H5.Close();

readArray is implemented like so
private T[] readArray<T>(H5FileId gh5file, int i)
{
        H5DataSetId dId = H5D.open(gh5file, datasets[i].name);
       T[] dataArray = new T[datasets[i].numPoints];
       H5Array<T> TArray = new H5Array<T>(dataArray);
       H5DataTypeId dtypeID = H5D.getType(dId);
       H5T.Order my_order = H5T.get_order(dtypeID);
       H5D.read(dId, dtypeID, TArray);
       H5D.close(dId);
       return dataArray;
}

getGroups recurses down and all object path information I care about
public void getGroups()
{
        //open the HDF5 library
       H5.Open();
       //open the file
       H5FileId gh5file = H5F.open(fname, H5F.OpenMode.ACC_RDONLY);

       //read in the root group
       H5GroupId rootGroup = H5G.open(gh5file, "/");

       //find out how many objects are under the root group
       long count = H5G.getNumObjects(rootGroup);

       //store the names at this level
       ObjectInfo info = H5G.getObjectInfo(rootGroup, "/DYNAMIC DATA",
false);
       groups.Add(new Group("/DYNAMIC DATA", info.objectType));

       //find all children of roots children recursively
       for (int i = 0; i < groups.Count; i++)
       {
               findChildren(groups[i], gh5file);
       }

       H5G.close(rootGroup);

       H5F.close(gh5file);

       H5.Close();
}

getDatasets just pulls the datasets out of the groups list
public void getDatasets()
{
        getGroups();

       for (int i = 0; i < groups.Count; i++)
       {
        extractDatasets(groups[i], datasets);
       }
}

findChildren is how I read the file info to find the datasets
public static void findChildren(Group s, H5FileId t)
{

        //Get the number of children that belong to current group
       H5GroupId curr_group = H5G.open(t, s.name);
       long count = H5G.getNumObjects(curr_group);

       //for each of the children add them to the parent list
       for (ulong j = 0; j < (ulong)count; j++)
       {
        //read it by index
              string obj_name = H5G.getObjectNameByIndex(curr_group, j);
              ObjectInfo info = H5G.getObjectInfo(curr_group, obj_name,
false);

              s.children.Add(new Group(s.name + "/" + obj_name,
info.objectType));
       }

       //For each child we are going to recurse down
       for (int i = 0; i < s.children.Count; i++)
       {
        //in the GH5 file format there is nothing below dataset
              //if it is not a dataset, recurse on its children
              if (s.children[i].type != H5GType.DATASET)
              {
                findChildren(s.children[i], t);
              }
              else //it is a dataset so log the enformation
              {
                    s.children[i].dsetID = H5D.open(t,
s.children[i].name);
                    H5DataTypeId dID = H5D.getType(s.children[i].dsetID);
                    s.children[i].dtypeID = dID;
                    s.children[i].dtype = H5T.getClass(dID);
                    s.children[i].dtype_size = H5T.getSize(dID);
                    s.children[i].numPoints = H5S.getSimpleExtentNPoints(
H5D.getSpace(s.children[i].dsetID));
                    s.children[i].order = H5T.get_order(dID);
                    s.children[i].unit = Helpers
.ReadAttributeString(s.children[i].dsetID, s.children[i].name,
"UNITS");

                    H5D.close(s.children[i].dsetID);
              }
       }

        H5G.close(curr_group);
}

Hello everyone,

After talking with the help desk it was found that the H5G functions have
been deprecated and replaced by functions in the H5O and H5L classes. So a
big thank you goes out to the Help Desk.

So the code to get the groups in the data set are:

public void getGroups(StreamWriter sw)
        {
            //open the HDF5 library
            int x = H5.Open();

            //open the file
            H5FileId gh5file = H5F.open(fname, H5F.OpenMode.ACC_RDONLY);

            //read in the root group
            H5GroupId rootGroup = H5G.open(gh5file, "/");

            //find out how many objects are under the root group
            long count = H5G.getNumObjects(rootGroup);

            //store the names at this level
            //ObjectInfo info = H5G.getObjectInfo(rootGroup, "/DYNAMIC
DATA", false);
            H5ObjectInfo info = H5O.getInfoByName(rootGroup, "/DYNAMIC
DATA");
            groups.Add(new Group("/DYNAMIC DATA", info.objectType));

            H5G.close(rootGroup);

            //find all children of roots children recursively
            for (int i = 0; i < groups.Count; i++)
            {
                findChildren(groups[i], gh5file, sw);
            }
            H5F.close(gh5file);
            H5.Close();
        }

public static void findChildren(Group s, H5FileId ghfile, StreamWriter sw)
        {
            //Get the number of children that belong to current group

            H5GroupId curr_group = H5G.open(ghfile, s.name);
            try
            {

                long count = H5G.getNumObjects(curr_group);

                //for each of the children add them to the parent list
                for (ulong j = 0; j < (ulong)count; j++)
                {
                    //read it by index

                    string obj_name = H5L.getNameByIndex(curr_group,
s.name, H5IndexType.NAME, H5IterationOrder.NATIVE, j);
                    //string obj_name =
H5G.getObjectNameByIndex(curr_group, j);

                    H5ObjectInfo objinfo = H5O.getInfoByIndex(curr_group,
s.name, H5IndexType.NAME, H5IterationOrder.NATIVE, j);
                    s.children.Add(new Group(s.name + "/" + obj_name,
objinfo.objectType));

                    //ObjectInfo info = H5G.getObjectInfo(curr_group,
obj_name, false);
                    //s.children.Add(new Group(s.name + "/" + obj_name,
info.objectType));
                }

                //H5G.close(curr_group);
                //H5F.close(gh5file);

            }
            catch (Exception ex)
            {
                sw.WriteLine("FindChildren Error: {0}", ex.Message);
                sw.WriteLine("CurrGroup: {0}", s.name);
                throw ex;
            }

            //For each child we are going to recurse down
            for (int i = 0; i < s.children.Count; i++)
            {
                //in the GH5 file format there is nothing below dataset
                //if it is not a dataset, recurse on its children
                if (s.children[i].type != H5ObjectType.DATASET)
//H5GType.DATASET)
                {
                    findChildren(s.children[i], ghfile, sw);
                }
                else //it is a dataset so log the enformation
                {

                    s.children[i].dsetID = H5D.open(ghfile,
s.children[i].name);
                    H5DataTypeId dID = H5D.getType(s.children[i].dsetID);

                    s.children[i].dtypeID = dID;
                    s.children[i].dtype = H5T.getClass(dID);
                    s.children[i].dtype_size = H5T.getSize(dID);
                    s.children[i].numPoints = H5S.getSimpleExtentNPoints(
H5D.getSpace(s.children[i].dsetID));
                    s.children[i].order = H5T.get_order(dID);
                    s.children[i].unit = Helpers
.ReadAttributeString(s.children[i].dsetID, s.children[i].name, "UNITS");

                    H5T.close(dID);
                    H5D.close(s.children[i].dsetID);

                }
            }
            H5G.close(curr_group);
        }

In the findChildren function I'm now using the H5O.getInfoByIndex and the
H5L.getNameByIndex functions. They seem to work well and don't have the
same issue as the H5G function. This code could probably be made more
compact once I figure out how to use the iteration functions inside C#.

I've been trying to solve the issue, and the problem seems to be in the
library itself.

The error is still occurring in the H5G.getObjectNameByIndex() call.

I thought it might be an issue with the recursion keeping to many handles
open, so I moved the H5F.open() and H5G.open() for the group inside the
function and close them before I recurse down.

So the flow for the program is now

For all files
    getGroups()
    saveCSV()
End

getGroups()
public void getGroups(StreamWriter sw)
{
            //open the HDF5 library
            int x = H5.Open();

            //open the file
            H5FileId gh5file = H5F.open(fname, H5F.OpenMode.ACC_RDONLY);

            //read in the root group
            H5GroupId rootGroup = H5G.open(gh5file, "/");

            //find out how many objects are under the root group
            long count = H5G.getNumObjects(rootGroup);

            //store the names at this level
            ObjectInfo info = H5G.getObjectInfo(rootGroup, "/DYNAMIC DATA"
, false);
            groups.Add(new Group("/DYNAMIC DATA", info.objectType));

            H5G.close(rootGroup);
            H5F.close(gh5file);
            //find all children of roots children recursively
            for (int i = 0; i < groups.Count; i++)
            {
                findChildren(groups[i], fname, sw);
            }

            H5.Close();
}

public static void findChildren(Group s, string fname, StreamWriter sw)
{
            try
            {
                //Get the number of children that belong to current group
                H5FileId gh5file = H5F.open(fname, H5F.OpenMode
.ACC_RDONLY);
                H5GroupId curr_group = H5G.open(gh5file, s.name);
                long count = H5G.getNumObjects(curr_group);

                //for each of the children add them to the parent list
                for (ulong j = 0; j < (ulong)count; j++)
                {
                    //read it by index
                    string obj_name = H5G.getObjectNameByIndex(curr_group,
j);
                    ObjectInfo info = H5G.getObjectInfo(curr_group,
obj_name, false);
                    s.children.Add(new Group(s.name + "/" + obj_name,
info.objectType));
                }
                H5G.close(curr_group);
                H5F.close(gh5file);

            }
            catch (Exception ex)
            {
                sw.WriteLine("FindChildren Error: {0}", ex.Message);
                sw.WriteLine("CurrGroup: {0}", s.name);
                throw ex;
            }

            //For each child we are going to recurse down
            for (int i = 0; i < s.children.Count; i++)
            {
                //in the GH5 file format there is nothing below dataset
                //if it is not a dataset, recurse on its children
                if (s.children[i].type != H5GType.DATASET)
                {
                    findChildren(s.children[i], fname, sw);
                }
                else //it is a dataset so log the enformation
                {
                    H5FileId gh5file2 = H5F.open(fname, H5F.OpenMode
.ACC_RDONLY);
                    s.children[i].dsetID = H5D.open(gh5file2,
s.children[i].name);
                    H5DataTypeId dID = H5D.getType(s.children[i].dsetID);
                    s.children[i].dtypeID = dID;
                    s.children[i].dtype = H5T.getClass(dID);
                    s.children[i].dtype_size = H5T.getSize(dID);
                    s.children[i].numPoints = H5S.getSimpleExtentNPoints(
H5D.getSpace(s.children[i].dsetID));
                    s.children[i].order = H5T.get_order(dID);
                    s.children[i].unit = Helpers
.ReadAttributeString(s.children[i].dsetID, s.children[i].name, "UNITS");

                    H5D.close(s.children[i].dsetID);
                    H5F.close(gh5file2);
                }
            }
            //H5G.close(curr_group);
}

So these changes should reduce any handles that are open at any one time.

After getting some info from Scott, I went through my code and found two
H5DataTypeId that I hadn't closed. The error still occurs when trying to
get the object name by reference when working on more than 5 files
sequentially.

So here are the bits of the code that make use of the H5 Library

private T[] readArray<T>(H5FileId gh5file, int i)
{
       H5DataSetId dId = H5D.open(gh5file, datasets[i].name);

       T[] dataArray = new T[datasets[i].numPoints];
       H5Array<T> TArray = new H5Array<T>(dataArray);

       H5DataTypeId dtypeID = H5D.getType(dId);
       H5T.Order my_order = H5T.get_order(dtypeID);
       H5D.read(dId, dtypeID, TArray);

       H5T.close(dtypeID);
       H5D.close(dId);
        return dataArray;
}

public void getGroups(StreamWriter sw)
{
        //open the HDF5 library
       int x = H5.Open();

       //open the file
       H5FileId gh5file = H5F.open(fname, H5F.OpenMode.ACC_RDONLY);

       //read in the root group
       H5GroupId rootGroup = H5G.open(gh5file, "/");

       //find out how many objects are under the root group
       long count = H5G.getNumObjects(rootGroup);

       //store the names at this level
       ObjectInfo info = H5G.getObjectInfo(rootGroup, "/DYNAMIC DATA",
false);
       groups.Add(new Group("/DYNAMIC DATA", info.objectType));

       H5G.close(rootGroup);
       H5F.close(gh5file);
       //find all children of roots children recursively
       for (int i = 0; i < groups.Count; i++)
       {
               findChildren(groups[i], fname, sw);
       }

       H5.Close();
}

public static void findChildren(Group s, string fname, StreamWriter sw)
{
        try
       {
        //Get the number of children that belong to current group
              H5FileId gh5file = H5F.open(fname, H5F.OpenMode.ACC_RDONLY);
              H5GroupId curr_group = H5G.open(gh5file, s.name);
              long count = H5G.getNumObjects(curr_group);

              //for each of the children add them to the parent list
              for (ulong j = 0; j < (ulong)count; j++)
              {
                //read it by index
                     string obj_name = H5G
.getObjectNameByIndex(curr_group, j);
                     ObjectInfo info = H5G.getObjectInfo(curr_group,
obj_name, false);
                     s.children.Add(new Group(s.name + "/" + obj_name,
info.objectType));
              }

              H5G.close(curr_group);
              H5F.close(gh5file);

       }
       catch (Exception ex)
       {
              sw.WriteLine("FindChildren Error: {0}", ex.Message);
              sw.WriteLine("CurrGroup: {0}", s.name);
              throw ex;
       }

       //For each child we are going to recurse down
       for (int i = 0; i < s.children.Count; i++)
       {
        //in the GH5 file format there is nothing below dataset
              //if it is not a dataset, recurse on its children
              if (s.children[i].type != H5GType.DATASET)
              {
                    findChildren(s.children[i], fname, sw);
              }
              else //it is a dataset so log the enformation
              {
                    H5FileId gh5file2 = H5F.open(fname, H5F.OpenMode
.ACC_RDONLY);
                    s.children[i].dsetID = H5D.open(gh5file2,
s.children[i].name);
                    H5DataTypeId dID = H5D.getType(s.children[i].dsetID);

                    s.children[i].dtypeID = dID;
                    s.children[i].dtype = H5T.getClass(dID);
                    s.children[i].dtype_size = H5T.getSize(dID);
                    s.children[i].numPoints = H5S.getSimpleExtentNPoints(
H5D.getSpace(s.children[i].dsetID));
                    s.children[i].order = H5T.get_order(dID);
                    s.children[i].unit = Helpers
.ReadAttributeString(s.children[i].dsetID, s.children[i].name,
"UNITS");

                    H5T.close(dID);
                    H5D.close(s.children[i].dsetID);
                    H5F.close(gh5file2);
              }
       }
       //H5G.close(curr_group);
}

public static string ReadAttributeString(H5ObjectWithAttributes groupId,
string objectName, string attributeName)
{
        H5AttributeId attributeId = null;
       H5DataTypeId dataTypeId = null;
       // Read the Type attribute
       try
       {
        attributeId = H5A.openByName(groupId, objectName, attributeName);
              dataTypeId = H5A.getType(attributeId);
              bool isVariableLength = H5T.isVariableString(dataTypeId);

              if (isVariableLength)
              {
                   // Variable length string attribute
                   // NOTE: This section only works if the array length is
1
                   VariableLengthString[] value = new VariableLengthString
[1];
                   H5A.read<VariableLengthString>(attributeId, dataTypeId,
new H5Array<VariableLengthString>(value));

                   return value[0].ToString();
              }
              else
              {
                  // Make length smaller so null termination character is
not read
                  int length = (int)H5T.getSize(dataTypeId);// -1;

                  // Fixed length string attribute
                  byte[] valueBytes = new byte[length];

                  H5A.read<byte>(attributeId, dataTypeId, new H5Array<byte

(valueBytes));

                  string value = System.Text.ASCIIEncoding
.ASCII.GetString(valueBytes);
                  return value;
              }
        }
        catch (H5AopenByNameException)
        {
              // Attribute does not exist
        }
        catch (H5AreadException)
        {
         // Could not read the attribute correctly
        }
        finally
        {
                if (dataTypeId != null)
              {
                    H5T.close(dataTypeId);
              }
              if (attributeId != null)
              {
                    H5A.close(attributeId);
              }
        }
        return null;
}

public void saveCSV(string csv_filename, StreamWriter sw2)
{
        if(datasets.Count == 0)
        getDatasets(sw2);

       //make sure everything is the same size
       int numElems = datasets[0].numPoints;
       for (int i = 1; i < datasets.Count; i++)
       {
               if (datasets[i].numPoints != numElems)
               throw new Exception("Mismatched number of Elements in
file.");
       }

       //Time needs to be treated seperately so we'll pull that out now
       Group GT = datasets.Find(x => x.name.Contains("GLOBAL_TIME"));
        datasets.Remove(GT);
       datasets.Insert(0, GT);

       //try to create big array

       //open the HDF5 library
       H5.Open();

       //open the file
       H5FileId gh5file = H5F.open(fname, H5F.OpenMode.ACC_RDONLY);
       //set up arrays for the data to be stored
       double[][] data = new double[numElems][];
       for(int i = 0; i < numElems; i++)
        data[i] = new double[datasets.Count];

       #region fill data[][] with data set info
       //start at one since we are going to handle time seperately

        for (int i = 0; i < datasets.Count; i++)
       {
        //need to be careful about datatypes
              //the processing code should be similar for all
             //just datatypes change
             if (datasets[i].dtype_size == 4 && datasets[i].order == H5T.
Order.LE)
             {
              float[] dataArray = readArray<float>(gh5file, i);

                    for (int j = 0; j < dataArray.Length; j++)
                    {
                            data[j][i] = dataArray[j];
                    }
             }
             else if (datasets[i].dtype_size == 8 && datasets[i].order ==
H5T.Order.LE)
             {
                     double[] dataArray = readArray<double>(gh5file, i);

                    for (int j = 0; j < dataArray.Length; j++)
                    {
                            data[j][i] = dataArray[j];
                    }
             }
             else if (datasets[i].dtype_size == 4 && datasets[i].order ==
H5T.Order.BE)
             {
                     float[] dataArray = readArray<float>(gh5file, i);

                    for (int j = 0; j < dataArray.Length; j++)
                    {
                            byte[] b = BitConverter
.GetBytes(dataArray[j]);
                           Array.Reverse(b);
                           data[j][i] = BitConverter.ToSingle(b, 0);
                    }
             }
             else if (datasets[i].dtype_size == 8 && datasets[i].order ==
H5T.Order.BE)
             {
              double[] dataArray = readArray<double>(gh5file, i);

                    for (int j = 0; j < dataArray.Length; j++)
                    {
                            byte[] b = BitConverter
.GetBytes(dataArray[j]);
                           Array.Reverse(b);
                           data[j][i] = BitConverter.ToDouble(b, 0);
                    }
             }
        }
        #endregion

       //now to write the CSV file
       using (StreamWriter sw = new StreamWriter(csv_filename))
       {
               //need to write the header line
             //Time and Timestamp are first
             //then start at one to skip GLOBAL_TIME
             writeHeader(sw);

             //need to get the deltaT between ticks
            //to do that lets get the first 3 times and make sure they are
consistent
             //make sure whe have more than 3 entries
             if(numElems < 3)
                     throw new Exception("Can't check time. Less than
three samples");

              double timestep = checkTimeStep(data[0][0], data[1][0],
data[2][0]);
             double init_time = 0;

             //so header line is written
             //now need to write the actual date
             for (int i = 0; i < numElems; i++)
             {
                     //i is for the rows
                    //j for the columns
                    //columns 1 and 2 are special
                    //Global Time needs converted to Date Format
                    //And Column 2 is the time stamp
                    string curr_line = Helpers.FromJulianLong(data[i][0])+
",";
                    curr_line += init_time.ToString() + ",";
                    //start at 1 since the data array only contains GLOBAL
TIME not relative Time
                    for (int j = 1; j < datasets.Count; j++)
                    {
                           curr_line += data[i][j].ToString() + ",";
                    }
                    sw.WriteLine(curr_line.TrimEnd(new char[] { ',' }));

                    init_time += timestep;
              }
       }
       H5F.close(gh5file);
       H5.Close();
}

···

From: "Mitchell, Scott - IS" <Scott.Mitchell@exelisinc.com>
To: "felty_Tim@cat.com" <Felty_Tim@cat.com>
Date: 10/29/2013 10:09 AM
Subject: RE: [Hdf-forum] C# HDF5 Batch Behavior Error

I haven?t had the opportunity to dig through your code, but my first
impression is a resource problem since it works a few times and then
breaks. Are you sure you?re closing all the
files/datasets/groups/types/attributes/etc.? It?s really easy to leak
those.

From: Hdf-forum [mailto:hdf-forum-bounces@lists.hdfgroup.org] On Behalf Of
Tim Felty
Sent: Tuesday, October 29, 2013 11:02 AM
To: hdf-forum@lists.hdfgroup.org
Subject: Re: [Hdf-forum] C# HDF5 Batch Behavior Error

I've been trying to solve the issue, and the problem seems to be in the
library itself.

The error is still occurring in the H5G.getObjectNameByIndex() call.

I thought it might be an issue with the recursion keeping to many handles
open, so I moved the H5F.open() and H5G.open() for the group inside the
function and close them before I recurse down.

So the flow for the program is now

For all files
    getGroups()
    saveCSV()
End

getGroups()
public void getGroups(StreamWriter sw)
{
            //open the HDF5 library
            int x = H5.Open();

            //open the file
            H5FileId gh5file = H5F.open(fname, H5F.OpenMode.ACC_RDONLY);

            //read in the root group
            H5GroupId rootGroup = H5G.open(gh5file, "/");

            //find out how many objects are under the root group
            long count = H5G.getNumObjects(rootGroup);

            //store the names at this level
            ObjectInfo info = H5G.getObjectInfo(rootGroup, "/DYNAMIC DATA"
, false);
            groups.Add(new Group("/DYNAMIC DATA", info.objectType));

            H5G.close(rootGroup);
            H5F.close(gh5file);
            //find all children of roots children recursively
            for (int i = 0; i < groups.Count; i++)
            {
                findChildren(groups[i], fname, sw);
            }

            H5.Close();
}

public static void findChildren(Group s, string fname, StreamWriter sw)
{
            try
            {
                //Get the number of children that belong to current group
                H5FileId gh5file = H5F.open(fname, H5F.OpenMode
.ACC_RDONLY);
                H5GroupId curr_group = H5G.open(gh5file, s.name);
                long count = H5G.getNumObjects(curr_group);

                //for each of the children add them to the parent list
                for (ulong j = 0; j < (ulong)count; j++)
                {
                    //read it by index
                    string obj_name = H5G.getObjectNameByIndex(curr_group,
j);
                    ObjectInfo info = H5G.getObjectInfo(curr_group,
obj_name, false);
                    s.children.Add(new Group(s.name + "/" + obj_name,
info.objectType));
                }
                H5G.close(curr_group);
                H5F.close(gh5file);

            }
            catch (Exception ex)
            {
                sw.WriteLine("FindChildren Error: {0}", ex.Message);
                sw.WriteLine("CurrGroup: {0}", s.name);
                throw ex;
            }

            //For each child we are going to recurse down
            for (int i = 0; i < s.children.Count; i++)
            {
                //in the GH5 file format there is nothing below dataset
                //if it is not a dataset, recurse on its children
                if (s.children[i].type != H5GType.DATASET)
                {
                    findChildren(s.children[i], fname, sw);
                }
                else //it is a dataset so log the enformation
                {
                    H5FileId gh5file2 = H5F.open(fname, H5F.OpenMode
.ACC_RDONLY);
                    s.children[i].dsetID = H5D.open(gh5file2,
s.children[i].name);
                    H5DataTypeId dID = H5D.getType(s.children[i].dsetID);
                    s.children[i].dtypeID = dID;
                    s.children[i].dtype = H5T.getClass(dID);
                    s.children[i].dtype_size = H5T.getSize(dID);
                    s.children[i].numPoints = H5S.getSimpleExtentNPoints(
H5D.getSpace(s.children[i].dsetID));
                    s.children[i].order = H5T.get_order(dID);
                    s.children[i].unit = Helpers
.ReadAttributeString(s.children[i].dsetID, s.children[i].name, "UNITS");

                    H5D.close(s.children[i].dsetID);
                    H5F.close(gh5file2);
                }
            }
            //H5G.close(curr_group);
}

So these changes should reduce any handles that are open at any one time.

This e-mail and any files transmitted with it may be proprietary and are
intended solely for the use of the individual or entity to whom they are
addressed. If you have received this e-mail in error please notify the
sender. Please note that any views or opinions presented in this e-mail
are solely those of the author and do not necessarily represent those of
Exelis Inc. The recipient should check this e-mail and any attachments for
the presence of viruses. Exelis Inc. accepts no liability for any damage
caused by any virus transmitted by this e-mail.