; docformat = 'rst'
;+
; Convert string bounds like `0:*` to a 3-element bounds specification::
;
; [start_index, stop_index, string]
;
; :Private:
;
; :Returns:
; `lonarr(3)`
;
; :Params:
; sbounds : in, required, type=string
; notation for 1 dimension, e.g., '0', '3:9', '3:*:2'
; dim_size : in, required, type=lonarr
; size of the dimension being converted
;-
function mg_hdf_getdata_convertbounds_1d, sbounds, dim_size
compile_opt strictarr
args = strsplit(sbounds, ':', /extract, count=nargs)
result = [0L, dim_size - 1L, 1L]
case nargs of
1: begin
if (args[0] ne '*') then begin
index = long(args)
if (index lt 0L) then index += dim_size
result[0:1] = index
endif
end
2: begin
if (args[1] eq '*') then begin
result[0] = long(args[0])
result[0] = result[0] lt 0L ? (dim_size + result[0]) : result[0]
endif else begin
result[0:1] = long(args)
if (result[0] lt 0L) then result[0] = dim_size + result[0]
if (result[1] lt 0L) then result[1] = dim_size + result[1]
endelse
end
3: begin
if (args[1] eq '*') then begin
result[0] = long(args[0])
result[0] = result[0] lt 0L ? (dim_size + result[0]) : result[0]
result[2] = long(args[2])
endif else begin
result[0:2] = long(args)
if (result[0] lt 0L) then result[0] = dim_size + result[0]
if (result[1] lt 0L) then result[1] = dim_size + result[1]
endelse
end
else: message, 'invalid indexing notation: ' + sbounds
endcase
return, result
end
;+
; Converts normal IDL indexing notation (represented as a string) into a
; `lonarr(ndims, 3)` where the first row is start values, the second row is
; the end values, and the last row is the stride value.
;
; :Private:
;
; :Returns:
; lonarr(ndims, 3)
;
; :Params:
; sbounds : in, required, type=string
; bounds specified as a string using IDL's normal indexing notation
;
; :Keywords:
; dimensions : in, optional, type=lonarr(ndims)
; dimensions of the full array; required if a '*' is used in sbounds
; single : out, optional, type=boolean
; set to a named variable to determine if the bounds expression was
; specified in single-index dimensioning
;-
function mg_hdf_getdata_convertbounds, sbounds, dimensions=dimensions, $
single=single
compile_opt strictarr
on_error, 2
dimIndices = strtrim(strsplit(sbounds, ',', /extract, count=ndims), 2)
result = lonarr(ndims, 3)
case ndims of
1: begin
single = 1B
result[0, *] = mg_hdf_getdata_convertbounds_1d(dimIndices[0], $
dimensions[0])
end
n_elements(dimensions): begin
single = 0B
for d = 0L, ndims - 1L do begin
result[d, *] = mg_hdf_getdata_convertbounds_1d(dimIndices[0], $
dimensions[0])
endfor
end
else: message, 'invalid number of dimensions in array indexing notation'
endcase
return, result
end
;+
; Compute the `START`, `COUNT`, and `STRIDE` arguments from the bounds.
;
; :Private:
;
; :Params:
; bounds : in, required, type="lonarr(ndims, 3)"
; bounds
;
; :Keywords:
; start : out, optional, type=lonarr(ndims)
; input for start argument to H5S_SELECT_HYPERSLAB
; count : out, optional, type=lonarr(ndims)
; input for count argument to H5S_SELECT_HYPERSLAB
; stride : out, optional, type=lonarr(ndims)
; input for stride keyword to H5S_SELECT_HYPERSLAB
;-
pro mg_hdf_getdata_computeslab, bounds, $
start=start, count=count, stride=stride
compile_opt strictarr
ndims = (size(bounds, /dimensions))[0]
start = reform(bounds[*, 0])
stride = reform(bounds[*, 2])
count = ceil((bounds[*, 1] - bounds[*, 0] + 1L) / float(bounds[*, 2])) > 1
end
;+
; Retrieves an SD variable from an HDF file, scaled appropriately.
;
; :Private:
;
; :Requires:
; IDL 8.0
;
; :Returns:
;
; :Params:
; sd_id : in, required, type=long
; HDF file identifier
; varname : in, required, type=string
; name of variable to retreive from file
;-
function mg_hdf_getdata_getsdvariable, sd_id, varname, $
bounds=bounds, $
error=error
compile_opt strictarr
catch, error
if (error ne 0L) then begin
catch, /cancel
return, !null
endif
index = hdf_sd_nametoindex(sd_id, varname)
sds_id = hdf_sd_select(sd_id, index)
hdf_sd_getinfo, sds_id, dims=dims, ndims=ndims
fullBounds = [[lonarr(ndims)], [dims - 1L], [lonarr(ndims) + 1L]]
case size(bounds, /type) of
0 : _bounds = fullBounds
7 : _bounds = mg_hdf_getdata_convertbounds(bounds, dimensions=dims)
else: _bounds = transpose(bounds)
endcase
mg_hdf_getdata_computeslab, _bounds, $
start=start, count=count, stride=stride
hdf_sd_getdata, sds_id, data, count=count, start=start, stride=stride
hdf_sd_endaccess, sds_id
return, data
end
;+
; Pulls out a section of a HDF variable.
;
; :Returns:
; data array
;
; :Params:
; filename : in, required, type=string
; filename of the HDF file
; variable : in, required, type=string
; variable name (with path if inside a group)
;
; :Keywords:
; bounds : in, optional, type="lonarr(3, ndims) or string"
; gives start value, end value, and stride for each dimension of the
; variable
; error : out, optional, type=long
; error value
;-
function mg_hdf_getdata, filename, variable, bounds=bounds, error=error
compile_opt strictarr
on_error, 2
file_id = hdf_sd_start(filename)
tokens = strsplit(variable, '.', escape='\', count=ndots)
if (ndots eq 1L) then begin
; variable
bracketPos = strpos(variable, '[')
if (bracketPos eq -1L) then begin
_variable = variable
if (n_elements(bounds) gt 0L) then _bounds = bounds
endif else begin
_variable = strmid(variable, 0L, bracketPos)
closedBracketPos = strpos(variable, ']', /reverse_search)
_bounds = strmid(variable, bracketPos + 1L, closedBracketPos - bracketPos - 1L)
endelse
result = mg_hdf_getdata_getsdvariable(file_id, _variable, $
bounds=_bounds, $
error=error)
if (error) then message, 'variable not found', /informational
endif else begin
; attribute
; TODO: implement
;result = mg_hdf_getdata_getattribute(fileId, variable, error=error)
;if (error) then message, 'attribute not found', /informational
endelse
hdf_sd_end, file_id
return, result
end