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.