HDF5中嵌套的复合数据类型

Nested compound datatypes in HDF5

本文关键字:复合 数据类型 嵌套 HDF5      更新时间:2023-10-16

我是C++应用程序团队的一员,该应用程序处理各种类型的消息并以各种格式输出这些消息。出于本讨论的目的,可以将消息视为名称-值对的集合。这些值通常是数字,但也可以是字符串。消息的结构基本上是在处理过程中发现的消息可以任意大,因此不允许在内存中存储表示。一条消息一次处理一个名称值对消息可以具有内部结构,该结构由名称-值对中的名称捕获。一个很好的类比是在目录层次结构中考虑文件名。

我正在开发一个子系统来处理这些消息,并使用低级HDF5 API来产生HDF输出。由于我上面描述的限制,我使用的方法涉及对一条消息进行两次传递。在第一步中,我收集布局信息并构建一个复合数据类型和一个数据集。然后,我对消息进行第二次传递,以写出值。因为我一次写出一个值,所以我有一个这样的序列:


 // name, value, dataType, dtSize, ctDataSet and ctSpace have been defined elsewhere 
hid_t valueDT = H5Tcreate(H5T_COMPOUND, dtSize);
herr_t status = H5Tinsert(valueDT, name, 0, dataType);
hid_t filespace = H5Dget_space(ctDataSet);
hsize_t offset[] = { 0 };
hsize_t dim[] = [ 1 };
status = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, offset, NULL,
                                             dim, NULL);
status = H5Dwrite(ctDataSet, valueDT, ctSpace, filespace, H5P_DEFAULT, &value);

我已经完成了这项工作,现在我正在尝试将其扩展到处理嵌套的复合数据类型。我已经完成了第一个步骤,但我在第二个步骤上遇到了困难。代码段中的代码构建了一个与值相关的独立数据类型,为其提供了一个对应于数据集中现有字段的名称,然后诱使HDF5将该值作为数据集的一部分写入我意识到我对所用的名字并不明确。假设我们正在查看位置中的字段x。使用的名称将是位置.x

当值属于内部复合数据类型时,我很困惑如何建立这种关联。如有任何见解,我们将不胜感激。

您需要在每个嵌套级别创建正确的HDF5数据类型,从底部开始。然后,一旦您可以使用总复合数据类型创建数据集,并继续将数据写入文件。

除了在Common Lisp中使用HDF5之外,我刚刚完成了类似的操作。我最终做的是定义一个类型规范(听起来像你的消息)来完全描述数据类型的结构,然后使用记忆(记忆函数输出的花哨单词)生成C结构。

举个例子:假设您有以下结构(伪代码):

Type = {
    x of Xtype;
    y of Ytype;
}

您可以通过为Type创建复合数据类型

  1. 为Xtype创建HDF5数据类型(这是递归的,应该被存储)
  2. 为Ytype创建HDF5数据类型(如下)
  3. 使用Xtype和Ytype的HDF5数据类型为Type创建HDF5数据型

不过,这确实需要在第一次传递过程中完全确定数据类型的结构,但这听起来不像是处理方式的问题

为了扩展示例,您需要做的是

  1. 获取复合结构的数据类型规范列表
  2. (递归)为每个类型规范生成HDF5数据类型
  3. 根据生成的HDF5数据类型组装总的HDF5复合类型

将数据填充到(递归)复合结构中

对此,通常有两种方法。

源代码生成

您可以创建用于在第一次传递数据期间访问/填充结构的代码。如果你想编写了解C/C++结构和类的代码,这是必要的,因为数据类型是静态的,所以如果一个类型在编译时不存在,那么它在运行时就不可能存在。因此,您可以通过生成C++代码使该类型在编译时存在,然后对其进行编译,然后作为第二遍运行

对于您正在做的事情来说,这种方法听起来不太有前景,因为听起来您将处理相当大的消息流,这将需要相当多的代码生成和编译。因此,转到下一个方法:

原始二进制数据访问

这种方法完全取消了对结构使用静态类型,从而消除了生成C/C++复合类型的要求。

您所做的是使用有关数据类型的信息来计算复合数据类型的总大小,以及类型成员应出现在总类型的内存块中的偏移量。这可以像生成HDF5类型一样递归地完成。

示例:如果你有复合型

Type = {
    x of Xtype;
    y of Ytype;
}

你会

  1. 通过递归下降到Type的结构中得到Type的总大小,并以相同的方式将下降到其结构中得到的XtypeYtype的大小相加。

  2. 分配内存中Type字节的大小。

  3. 获取将组成Type对象的所有基本结构元素的偏移量。如果Xtype是化合物,那么你必须得到Xtype的成员,如果其中任何一个是化合物,你就得到它的成员,等等。

  4. 将每个基本结构元素以适当的偏移量写入分配的内存中。这也必须递归地进行,因为XtypeYtype可以是复合类型。

这种方法之所以有效,是因为(至少从程序员的角度来看)数据是连续分配的,因此xy并排放置在分配的内存中。

在这种方法中,您不得不取消结构/类的便利性,但这就是编译器在幕后管理结构/类。

我最终尝试了一种与我最初描述的方法根本不同的方法。我没有尝试将消息映射到复合数据类型上,而是创建了一个顶级的,并为消息中的每个字段创建一个数据集。在处理消息的后续实例时,我会更改每个数据集的范围。在消息字段是可选的情况下,我在数据集上设置一个属性,以确定哪些消息实例具有与其关联的值。

令我有些惊讶的是,在给定相同输入的情况下,"多数据集"方法会比"复合数据集"方式产生更大的输出文件。我天真的期望是它会更小,但如果我错过了使用API的微妙之处,我也不会感到惊讶。然而,还有一个更令人烦恼的问题。输出文件的使用者将使用MATLAB读取它们MATLAB确实有一些高级函数来读取HDF5文件,特别是h5read()。实现h5read()时,其参数之一是要提取的数据集的名称。我真的不想让用户单独提取他们可能感兴趣的每个数据集。有人能想出一种合理的方法将顶级封装在数据集中中吗?