无法读取NetCDF结构变量数组子范围

时间:2013-06-18 00:20:17

标签: java hdf5 netcdf

我从HDF5文件中检索到NCDF结构,我正在尝试使用Java NetCDF 4.3.16库读取数组变量的子范围。我找到了这样的变量:

Variable netCDFVariable = netCDFFile.findVariable("/group/struct.var");

此时我可以根据需要阅读整个变量:

netCDFArray = netCDFVariable.read();

但是让我们说变量是一个长度为10的整数数组,我想只读取索引3,4,5,6和7的子范围:

Section section=new Section(new int[]{3}, new int[]{5});
netCDFArray = netCDFVariable.read(section);

但是这里Variable.read(Section)会抛出InvalidRangeException。跟踪代码时,变量会检查自己的内部shape变量,该变量恰好是[]并发现它无效。

那么为什么变量没有合适的shape?我是否必须先读取变量以获得正确的形状? (这当然会破坏尝试阅读子范围的目的。)

1 个答案:

答案 0 :(得分:0)

从NetCDF 4.3.17开始,Variable.read()Variable.read(Section)的实现在读取结构数组的成员时有很大差异,并且都没有遵守API文档。下面我提出一个解决方法。

为了说明,我们说我有以下内容:

Structure {
  int foo;
    :_Unsigned = "true";
  int bar;
    :_Unsigned = "true";
} example(24);

这是一个名为example结构的24元素数组,每个结构包含两个成员foobar。我们假设我得到foo成员的引用,如下所示:

final Variable fooVariable = netcdfFile.findVariable("/blah/example.foo");

如果我调用fooVariable.read(),API文档会说我将返回第一个值,因为foo是结构中属于数组元素的一部分。这不是发生的事情;相反,库实际上做了一些聪明的阅读,并将foo成员从所有结构中返回为foo值的单个数组。这是我想要的行为。

不幸的是,fooVariable.read(Section)实现与fooVariable.read()没有相同的聪明代码,而是写入UnsupportedOperationException。 (由于缺少额外的检查,代码甚至没有达到那么远,抛出InvalidRangeException,因为它认为给定的Section无效。这很可惜,因为(一旦添加了检查)为了避免使用InvalidRangeExceptionVariable.read()实现中的聪明代码对Variable.read(Section)同样适用,只需在一行上插入一个方法参数!

使用来自Variable.read()的聪明代码我创建了一个解决此问题的方法,允许调用者请求包含任何变量的数组的一部分。如果变量是数组中结构的成员,则只读取该成员的子范围,从而有效地创建另一个版本的fooVariable.read(Section)方法,该方法与结构成员的fooVariable.read()具有相同的行为:

  /**
   * Reads an array of data from the provided NetCDF variable. If the variable is a member of a structure, that member is read
   * from all the structures in the array and returned as a single array containing that member from each structure.
   * @param variable The NetCDF variable to read.
   * @param section The section indicating the element of the array to read
   * @param indexEnd The ending source index, exclusive, or -1 if all available values should be read.
   * @return An array representing the requested range of values read for the given variable.
   * @throws IOException if there is an error reading the data.
   */
  public static Array readArray(final Variable variable, final Section section) throws IOException, InvalidRangeException {
    if (variable.isMemberOfStructure()) { //if the variable is member of a structure
      final Structure parentStructure = variable.getParentStructure().select(variable.getShortName()); //select just the member variable
      final ArrayStructure arrayStructure = (ArrayStructure) parentStructure.read(section); //read the array of structures
      return arrayStructure.extractMemberArray(arrayStructure.findMember(variable.getShortName())); //extract just the member into an array
    } else { //if the variable is not a member of a structure
      return variable.read(section); //just read the section directly from the variable
    }
  }

我用Unidata NetCDF Support报告了这个问题(现在标识为NRW-974703)。起初我被告知这些方法不适用于HDF5,只适用于Unidata自己的NetCDF文件格式。 (这是完全错误的。)然后我被告知我不理解Java NetCDF API(尽管从之前的回答中我怀疑究竟谁对Unidata库缺乏了解)。在查阅特定问题代码并提供上述解决方法后,我还没有收到Unidata的回复。