IDL 即将推出的新功能——附简要示例
19700 为本文评分:
未评分
IDL 即将推出的新功能——附简要示例
匿名用户 2015年2月5日,星期四
IDL 8.4.1 计划在未来几周内发布。尽管这只是一个小版本更新而非全新版本,但 IDL 团队实现的几个功能让我感到非常兴奋。
HDF 与 NetCDF 更新
在处理科学数据时,我经常使用 IDL 来打开和读取 HDF4 与 HDF5 文件。尽管 HDF5 的设计比 HDF4 简单得多,但使用这两种格式的 API 有时仍然相当麻烦,并且我几乎总是需要参考文档示例才能开始工作。
我在 IDL 中最喜欢的例程之一是 H5_PARSE(这是 IDL 库中的一个函数,并非标准 HDF5 接口的一部分)。我非常喜欢这个函数的原因是,我可以使用它来查询文件中的数据集和属性,而无需编写多行代码来搜索和访问所需信息(并且我也不会忘记确保即使发生错误文件也能被正确关闭)。我需要的所有信息都会被简单地转储到一个层次结构中。
然而,我对 H5_PARSE 的一个抱怨是它可能相当慢,尤其是处理大文件时。原因在于,该结构是在 IDL 遍历文件时动态创建的,使用了以下逻辑:
sTree = CREATE_STRUCT(sTree, tagname, sMember)
就像追加数组非常低效一样,以这种方式创建结构不仅速度慢,而且占用大量内存,特别是在使用 /READ_DATA 关键字时。
幸运的是,IDL 新的 OrderedHash 数据类型提供了一个便捷的替代方案;向哈希表添加字段比向结构追加要高效得多。此外,有序哈希不仅保留了顺序,还保留了名称和大小写(结构不区分大小写,对象名称中的特殊字符和空格必须转换为下划线才能成为有效的结构标签)。
更有趣的是,有序哈希可以使用隐式打印,IDL 会以层次化的 JSON 格式打印出文件信息,模拟文件的结构。要在调用 H5_PARSE 时使用有序哈希代替结构,请使用 /ORDEREDHASH 关键字。以下是一个使用 HDF5-EOS 文件的示例:
file = 'C:\hdf5\hdfeos\OMI-Aura_L2-OMNO2_2008m0720t2016-o21357_v003-2008m0721t101450.he5'
result = H5_PARSE(file, /ORDEREDHASH)
result
IDL 将打印:
{
"_NAME": "C:\\hdf5\\hdfeos\\OMI-Aura_L2-OMNO2_2008m0720t2016-o21357_v003-2008m0721t101450.he5",
"_ICONTYPE": "hdf",
"_TYPE": "GROUP",
"_FILE": "C:\\hdf5\\hdfeos\\OMI-Aura_L2-OMNO2_2008m0720t2016-o21357_v003-2008m0721t101450.he5",
"_PATH": "/",
"_COMMENT": "",
"HDFEOS": {
"_NAME": "HDFEOS",
"_ICONTYPE": "",
"_TYPE": "GROUP",
"_FILE": "C:\\hdf5\\hdfeos\\OMI-Aura_L2-OMNO2_2008m0720t2016-o21357_v003-2008m0721t101450.he5",
"_PATH": "/",
"_COMMENT": "",
"ADDITIONAL": {
"_NAME": "ADDITIONAL",
"_ICONTYPE": "",
"_TYPE": "GROUP",
"_FILE": "C:\\hdf5\\hdfeos\\OMI-Aura_L2-OMNO2_2008m0720t2016-o21357_v003-2008m0721t101450.he5",
"_PATH": "/HDFEOS",
"_COMMENT": "",
"FILE_ATTRIBUTES": {
"_NAME": "FILE_ATTRIBUTES",
"_ICONTYPE": "",
"_TYPE": "GROUP",
"_FILE": "C:\\hdf5\\hdfeos\\OMI-Aura_L2-OMNO2_2008m0720t2016-o21357_v003-2008m0721t101450.he5",
"_PATH": "/HDFEOS/ADDITIONAL",
"_COMMENT": "",
"InstrumentName": {
"_NAME": "InstrumentName",
"_ICONTYPE": "text",
"_TYPE": "ATTRIBUTE",
"_NDIMENSIONS": 0,
"_DIMENSIONS": 0,
"_NELEMENTS": 1,
"_DATATYPE": "H5T_STRING",
"_STORAGESIZE": 3,
"_PRECISION": 24,
"_SIGN": "",
"_DATA": "OMI"
等等。
IDL 8.4.1 将提供的另一个新函数是 **HDF_PARSE**。这相当于 H5_PARSE,但用于 HDF4 文件。它会遍历文件并返回有关组、科学数据集、图像、调色板、注释和 VData 的信息。这些信息将按照文件中存储的相同结构,以有序哈希的形式返回。HDF_PARSE 将始终返回一个有序哈希;如果您希望获得结构,可以使用 [OrderedHash::ToStruct](/docs/HASH.html#ToStructMethod) 将哈希转换为结构。以下是一个使用 MODIS 文件的示例:
```idl
file = 'C:\scratch\modisl2\MOD10_L2.A2002013.0930.003.2002017035237.hdf'
result = HDF_PARSE(file)
result
IDL 打印:
{
"_NAME": "C:\\scratch\\modisl2\\MOD10_L2.A2002013.0930.003.2002017035237.hdf",
"_TYPE": "GROUP",
"_FILE": "C:\\scratch\\modisl2\\MOD10_L2.A2002013.0930.003.2002017035237.hdf",
"_PATH": "/",
"MOD_Swath_Snow": {
"_NAME": "MOD_Swath_Snow",
"_TYPE": "GROUP",
"_FILE": "C:\\scratch\\modisl2\\MOD10_L2.A2002013.0930.003.2002017035237.hdf",
"_PATH": "/",
"Geolocation Fields": {
"_NAME": "Geolocation Fields",
"_TYPE": "GROUP",
"_FILE": "C:\\scratch\\modisl2\\MOD10_L2.A2002013.0930.003.2002017035237.hdf",
"_PATH": "/MOD_Swath_Snow",
"Latitude": {
"_NAME": "Latitude",
"_TYPE": "SD",
"_FILE": "C:\\scratch\\modisl2\\MOD10_L2.A2002013.0930.003.2002017035237.hdf",
"_PATH": "/MOD_Swath_Snow/Geolocation Fields",
"_NDIMENSIONS": 2,
"_DIMENSIONS": [271, 406],
"_IDL_DATATYPE": "FLOAT",
"_DATA": "<unread>",
"long_name": {
"_NAME": "long_name",
"_TYPE": "ATTRIBUTE",
"_FILE": "C:\\scratch\\modisl2\\MOD10_L2.A2002013.0930.003.2002017035237.hdf",
"_PATH": "/MOD_Swath_Snow/Geolocation Fields/Latitude",
"_IDL_DATATYPE": "STRING",
"_DATA": "Coarse 5 km resolution latitude"
},
"units": {
"_NAME": "units",
"_TYPE": "ATTRIBUTE",
"_FILE": "C:\\scratch\\modisl2\\MOD10_L2.A2002013.0930.003.2002017035237.hdf",
"_PATH": "/MOD_Swath_Snow/Geolocation Fields/Latitude",
"_IDL_DATATYPE": "STRING",
"_DATA": "degrees"
},
"valid_range": {
"_NAME": "valid_range",
"_TYPE": "ATTRIBUTE",
"_FILE": "C:\\scratch\\modisl2\\MOD10_L2.A2002013.0930.003.2002017035237.hdf",
"_PATH": "/MOD_Swath_Snow/Geolocation Fields/Latitude",
"_IDL_DATATYPE": "FLOAT",
"_DATA": [-90.000000, 90.000000]
},
"_FillValue": {
"_NAME": "_FillValue",
"_TYPE": "ATTRIBUTE",
"_FILE": "C:\\scratch\\modisl2\\MOD10_L2.A2002013.0930.003.2002017035237.hdf",
"_PATH": "/MOD_Swath_Snow/Geolocation Fields/Latitude",
"_IDL_DATATYPE": "FLOAT",
"_DATA": [-999.00000]
},
"source": {
"_NAME": "source",
"_TYPE": "ATTRIBUTE",
"_FILE": "C:\\scratch\\modisl2\\MOD10_L2.A2002013.0930.003.2002017035237.hdf",
"_PATH": "/MOD_Swath_Snow/Geolocation Fields/Latitude",
"_IDL_DATATYPE": "STRING",
"_DATA": "MOD03 geolocation product; data read from center pixel in 5 km box"
}
},
"Longitude": {
等等。
IDL 8.4.1 还将包含用于查询、检索和创建 NetCDF 文件的新 NetCDF 例程。这些例程包括 NCDF_GET、NCDF_LIST 和 NCDF_PUT。
# 重载 ++ 和 -- 运算符
我一直很喜欢 IDL 对继承 [IDL_Object](/docs/IDL_Object.html) 的类进行[运算符重载](/docs/Creating_Operator_Overlo.html)的能力。这使我能够创建行为像其自身数据类型的对象。
此前无法重载的一组运算符是自增/自减运算符 ++/--。我喜欢这个运算符,不仅因为输入 `var++` 比 `var = var + 1` 更容易,而且更高效。此外,在某些情况下,"递增"可能意味着"加一"以外的含义,例如当值不是数字时。下面是一个字母类(SequentialLetters)的示例,它逐个字母(全部小写)递增。当值到达字母 "z" 后,序列中的下一个值将是 "aa"。当到达 "az" 时,再次递增将把值更改为 "ba",依此类推。
```idl
pro SequentialLetters::_OverloadPlusPlus
compile_opt idl2, hidden
if (StrCmp(self.value, '')) then begin
self.value = 'a'
return
endif
byteValue = Byte(self.value)
if (byteValue[-1] eq 122) then begin
if (StrLen(self.value) eq 1) then begin
self.value = 'aa'
endif else begin
; 创建一个新的 SequentialLetters 对象来递归处理除最后一个字母外的所有字母。
newObj = Obj_New('SequentialLetters', VALUE=StrMid(self.value, 0, StrLen(self.value)-1))
newObj++
self.value = newObj.VALUE + 'a'
Obj_Destroy, newObj
endelse
endif else begin
byteValue[-1]++
self.value = String(byteValue)
endelse
end
;-------------------------------------------------------------------------------
pro SequentialLetters::_OverloadMinusMinus
compile_opt idl2, hidden
; 如果只有一个字符且为 'a',则值变为空字符串。
if (StrCmp(self.value, 'a')) then begin
self.value = ''
return
endif
byteValue = Byte(self.value)
if (byteValue[-1] eq 97) then begin
; 创建一个新的 SequentialLetters 对象来递归处理除最后一个字母外的所有字母。
newObj = Obj_New('SequentialLetters', VALUE=StrMid(self.value, 0, StrLen(self.value)-1))
newObj--
self.value = newObj.VALUE + 'z'
Obj_Destroy, newObj
endif else begin
byteValue[-1]--
self.value = String(byteValue)
endelse
end
;-------------------------------------------------------------------------------
pro SequentialLetters::SetProperty, VALUE=value, _REF_EXTRA=extra
compile_opt idl2
if (N_Elements(value) gt 0) then begin
self.value = value
endif
if (ISA(extra)) then begin
self.IDL_Object::SetProperty, _EXTRA=extra
endif
end
;-------------------------------------------------------------------------------
pro SequentialLetters::GetProperty, VALUE=value, _REF_EXTRA=extra
compile_opt idl2
if (Arg_Present(value)) then begin
value = self.value
endif
if (ISA(extra)) then begin
self.IDL_Object::GetProperty, _EXTRA=extra
endif
end
;-------------------------------------------------------------------------------
function SequentialLetters::Init, _REF_EXTRA=extra
compile_opt idl2
if (~self.IDL_Object::Init()) then return, 0
if (ISA(extra)) then begin
self.SetProperty, _EXTRA=extra
endif
return, 1
end
;-------------------------------------------------------------------------------
pro SequentialLetters__Define
compile_opt idl2
!null = {SequentialLetters, $
inherits IDL_Object, $
value: ''}
end
以下是使用此对象的示例:
myLetters = Obj_New('SequentialLetters', VALUE='z')
myLetters++
print, myLetters.VALUE
IDL 打印:
aa
myLetters--
print, myLetters.VALUE
IDL 打印:
z
其他更新
IDL 8.4.1 中新功能和产品改进的完整列表将很快发布。敬请关注!