【问题标题】:How to make a compound datatype with HDF5DOTNET?如何使用 HDF5DOTNET 制作复合数据类型?
【发布时间】:2020-03-25 11:31:13
【问题描述】:

当我将包含数组的结构写入 HDF5 数据集时遇到问题。首先,窗体不以行开头:

H5T.insert(typeStruct, "string", 0, H5T.create_array(new H5DataTypeId(H5T.H5Type.C_S1), dims2));

窗口窗体至少开始时没有行,所以我认为定义复合数据类型有问题。我查看了手册和许多示例,但仍然无法解决问题。我可以举一个使用复合数据类型在 C# 中编写具有多个数组的结构的示例吗?

using HDF5DotNet;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Reflection;


namespace WindowsFormsApplication1
{
    public unsafe partial class Form1 : Form
    {

        public unsafe struct struct_TR
        {
            public string[] arr_currentLong;

            public struct_TR(byte size_currentTime)
            {
                arr_currentLong = new string[size_currentTime];
            }
        }


        public Form1()
        {
            InitializeComponent();

            long ARRAY_SIZE = 255;
            struct_TR structMade = new struct_TR(255);

            for (int i = 0; i < 255; i++)
            {
                structMade.arr_currentLong[i] = i.ToString();
            }

            string currentPath = Path.GetDirectoryName(Application.ExecutablePath);     
            Directory.SetCurrentDirectory(currentPath);                                 


            H5FileId fileId = H5F.create(@"weights.h5", H5F.CreateMode.ACC_TRUNC);

            long[] dims1 = { 1 };
            long[] dims2 = { 1, ARRAY_SIZE };

            H5DataSpaceId myDataSpace = H5S.create_simple(1, dims1);

            H5DataTypeId string_type = H5T.copy(H5T.H5Type.C_S1);
            H5DataTypeId array_tid1 = H5T.create_array(string_type, dims2);

            H5DataTypeId typeStruct = H5T.create(H5T.CreateClass.COMPOUND, Marshal.SizeOf(typeof(struct_TR)));
            H5T.insert(typeStruct, "string", 0, H5T.create_array(new H5DataTypeId(H5T.H5Type.C_S1), dims2));

            H5DataSetId myDataSet = H5D.create(fileId, "/dset", typeStruct, myDataSpace);

            H5D.writeScalar<struct_TR>(myDataSet, typeStruct, ref structMade);

        }
    }
}

【问题讨论】:

    标签: c# hdf5 hdf5dotnet


    【解决方案1】:

    我知道如何用数组保存结构的唯一方法是创建一个常量数组 例如,这是一个长度为 4 的数组的结构。

        [StructLayout(LayoutKind.Sequential)]
        public struct Responses
        {
            public Int64 MCID;
            public int PanelIdx;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public short[] ResponseValues;
        }
    

    这里创建了一个由 4 个结构组成的数组,其中包含一个数组:

           responseList = new Responses[4] {
                new Responses() { MCID=1,PanelIdx=5,ResponseValues=new short[4]{ 1,2,3,4} },
                new Responses() { MCID=2,PanelIdx=6,ResponseValues=new short[4]{ 5,6,7,8}},
                new Responses() { MCID=3,PanelIdx=7,ResponseValues=new short[4]{ 1,2,3,4}},
                new Responses() { MCID=4,PanelIdx=8,ResponseValues=new short[4]{ 5,6,7,8}}
            };
    

    以下代码行将结构数组写入 HDF5 文件:

            string filename = "testArrayCompounds.H5";
            var fileId =H5F.create(filename, H5F.ACC_TRUNC);
            var status = WriteCompounds(fileId, "/test", responseList);
            H5F.close(fileId);
    

    WriteCompounds 方法如下所示:

        public static int WriteCompounds<T>(hid_t groupId, string name, IEnumerable<T> list) //where T : struct
        {
            Type type = typeof(T);
            var size = Marshal.SizeOf(type);
            var cnt = list.Count();
    
            var typeId = CreateType(type);
    
            var log10 = (int)Math.Log10(cnt);
            ulong pow = (ulong)Math.Pow(10, log10);
            ulong c_s = Math.Min(1000, pow);
            ulong[] chunk_size = new ulong[] { c_s };
    
            ulong[] dims = new ulong[] { (ulong)cnt };
    
            long dcpl = 0;
            if (!list.Any() || log10 == 0) { }
            else
            {
                dcpl = CreateProperty(chunk_size);
            }
    
            // Create dataspace.  Setting maximum size to NULL sets the maximum
            // size to be the current size.
            var spaceId = H5S.create_simple(dims.Length, dims, null);
    
            // Create the dataset and write the compound data to it.
            var datasetId = H5D.create(groupId, name, typeId, spaceId, H5P.DEFAULT, dcpl);
    
            IntPtr p = Marshal.AllocHGlobal(size * (int)dims[0]);
    
            var ms = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(ms);
            foreach (var strct in list)
                writer.Write(getBytes(strct));
            var bytes = ms.ToArray();
    
            GCHandle hnd = GCHandle.Alloc(bytes, GCHandleType.Pinned);
            var statusId = H5D.write(datasetId, typeId, spaceId, H5S.ALL,
                H5P.DEFAULT, hnd.AddrOfPinnedObject());
    
            hnd.Free();
            /*
             * Close and release resources.
             */
            H5D.close(datasetId);
            H5S.close(spaceId);
            H5T.close(typeId);
            H5P.close(dcpl);
            Marshal.FreeHGlobal(p);
            return statusId;
        }
    

    需要三个额外的帮助功能,这里显示两个:

        private static long CreateType(Type t)
        {
            var size = Marshal.SizeOf(t);
            var float_size = Marshal.SizeOf(typeof(float));
            var int_size = Marshal.SizeOf(typeof(int));
            var typeId = H5T.create(H5T.class_t.COMPOUND, new IntPtr(size));
    
            var compoundInfo = Hdf5.GetCompoundInfo(t);
            foreach (var cmp in compoundInfo)
            {
                H5T.insert(typeId, cmp.name, Marshal.OffsetOf(t, cmp.name), cmp.datatype);
            }
            return typeId;
        }
    
        private static long CreateProperty(ulong[] chunk_size)
        {
            var dcpl = H5P.create(H5P.DATASET_CREATE);
            H5P.set_layout(dcpl, H5D.layout_t.CHUNKED);
            H5P.set_chunk(dcpl, chunk_size.Length, chunk_size);
            H5P.set_deflate(dcpl, 6);
            return dcpl;
        }
    

    我还有一个 ReadCompounds 来读取 hdf5 文件。 CreateType方法中使用的Hdf5.GetCompoundInfo方法也很长。所以我不会在这里展示这些方法。

    因此,仅用于编写一些结构的代码就相当多。 我制作了一个名为HDF5DotnetTools 的库,它允许您更轻松地读写类和结构。您还可以在那里找到 ReadCompounds 和 GetCompoundInfo 方法。

    HDF5DotnetTools 的单元测试中,您还可以找到如何使用数组编写类的示例

    【讨论】:

    • 感谢您的详细解释和示例代码!我从你的回答中学到了很多!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-21
    • 2020-01-22
    • 2021-10-31
    • 2013-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多