无法读取 NetCDF 结构变量数组子范围
Posted
技术标签:
【中文标题】无法读取 NetCDF 结构变量数组子范围【英文标题】:Unable to read NetCDF structure variable array subrange 【发布时间】:2013-06-14 01:49:03 【问题描述】:我有一个从 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】:从 NetCDF 4.3.17 开始,Variable.read()
和 Variable.read(Section)
的实现在读取结构数组的成员时存在很大差异,两者均不遵守 API 文档。下面我介绍一个解决方法。
为了说明,假设我有以下内容:
Structure
int foo;
:_Unsigned = "true";
int bar;
:_Unsigned = "true";
example(24);
这是一个名为 example
的结构的 24 元素数组,每个结构包含两个成员 foo
和 bar
。让我们假设我得到了对 foo
成员的引用,如下所示:
final Variable fooVariable = netcdfFile.findVariable("/blah/example.foo");
如果我调用fooVariable.read()
,API 文档说我会取回第一个值,因为foo
是结构的一部分,它是数组中的一个元素。这不是发生的事情;相反,该库实际上做了一些巧妙的阅读,并将所有结构中的 foo
成员作为 foo
值的单个数组返回。这是我想要的行为。
不幸的是,fooVariable.read(Section)
的实现没有fooVariable.read()
一样的聪明代码,而是编写为抛出UnsupportedOperationException
。 (由于没有添加检查,代码甚至没有走那么远,抛出InvalidRangeException
,因为它认为给定的Section
是无效的。很遗憾,因为(一旦添加检查以避免@ 987654339@) Variable.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 的回复。
【讨论】:
以上是关于无法读取 NetCDF 结构变量数组子范围的主要内容,如果未能解决你的问题,请参考以下文章
使用 Java 从 HDF5 文件中的 NetCDF 字符数组变量中检索一维数组