Wednesday, February 23, 2011

HDF5: Fixed length strings

For the sake of Google searches - here is a bit of code on how to create compound data types with fixed length strings in HDF5 H5 files.


/**
* Create the H5 file with the contents of the Data list.
*/
public Boolean create() {
try {
FileInfo h5 = new FileInfo(this.h5Path);

H5FileId fileId = null;
if (this.makeNew) {
fileId = H5F.create(h5.Name, H5F.CreateMode.ACC_TRUNC);
H5F.close(fileId);
}
fileId = H5F.open(h5.Name, H5F.OpenMode.ACC_RDWR);

H5DataTypeId stringMeasurand = H5T.copy(H5T.H5Type.C_S1);
H5T.setSize(stringMeasurand, (uint)MEASURAND_LENGTH);

H5DataTypeId stringChannel = H5T.copy(H5T.H5Type.C_S1);
H5T.setSize(stringChannel, (uint)CHANNEL_LENGTH);

H5DataTypeId tid1 = H5T.create(H5T.CreateClass.COMPOUND,(uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(dictStruct)));
H5T.insert(tid1, "Measurand", 0, stringMeasurand);
H5T.insert(tid1, "Rate", MEASURAND_LENGTH, H5T.H5Type.NATIVE_FLOAT);
H5T.insert(tid1, "Channel", MEASURAND_LENGTH+sizeof(float), stringChannel);

// Rank is the number of dimensions of the data array.
const int RANK = 1;
ulong[] attributeDims = new ulong[RANK];
attributeDims[0] = (ulong)data.Count;

H5DataSpaceId spaceId = H5S.create_simple(RANK, attributeDims);
H5DataSetId dataSetId = H5D.create(fileId, "/foo",
tid1, spaceId);

H5D.write(dataSetId, tid1, new H5Array(data.ToArray()));
H5T.close(tid1);

H5D.close(dataSetId);
H5F.close(fileId);

return true;
} catch(Exception ex) {
Console.WriteLine(ex.Message);
return false;
}

return true;
}



/**
* Create a new struct with the specified measurand information.
*/
private unsafe dictStruct addRow(string measurand, float rate, string channel) {
dictStruct retval = new dictStruct();

byte[] mBytes = System.Text.Encoding.ASCII.GetBytes(measurand);
byteCopy(mBytes, retval.measurand,MESSAGE_LENGTH);


retval.rate = rate;

byte[] channelBytes = System.Text.Encoding.ASCII.GetBytes(channel);
byteCopy(channelBytes, retval.channel, CHANNEL_LENGTH);


return retval;
}


And then how you define your struct:


public const int MEASURAND_LENGTH = 16;
public const int CHANNEL_LENGTH = 12;

[StructLayout(LayoutKind.Sequential, Pack=1)]
public unsafe struct dictStruct {

public fixed byte measurand[MEASURAND_LENGTH];
public float rate;
public fixed byte channel[CHANNEL_LENGTH];

}

1 comment:

Gustavo said...

Great code, but I can't understand this line:

H5D.write(dataSetId, tid1, new H5Array(data.ToArray()));

As far as I understood, HDF5 expects to receive all elements in a contiguous BYTE array. If you have multiple elements in data, how do you ensure that they will be allocated contiguously?