; docformat = 'rst' ;+ ; This class represents a variable in an HDF5 file. ; ; :Categories: ; file i/o, hdf5, sdf ; ; :Examples: ; Try:: ; ; IDL> h = mg_h5(file_which('hdf5_test.h5')) ; IDL> g1 = h.images ; IDL> e = g1.eskimo ; IDL> help, e ; E H5BYTE = Array[600, 649] ; IDL> help, size(e, /structure), /structures ; ** Structure IDL_SIZE, 8 tags, length=80, data length=80: ; TYPE_NAME STRING 'OBJREF' ; STRUCTURE_NAME STRING '' ; TYPE INT 11 ; FILE_LUN INT 0 ; FILE_OFFSET LONG 0 ; N_ELEMENTS LONG 389400 ; N_DIMENSIONS LONG 2 ; DIMENSIONS LONG Array[8] ; IDL> plot, e[*, 400], xstyle=9, ystyle=8 ; IDL> print, e.image_colormodel, format='(%"IMAGE_COLORMODEL attribute = %s")' ; IMAGE_COLORMODEL attribute = RGB ; IDL> print, e['IMAGE_COLORMODEL'], format='(%"IMAGE_COLORMODEL attribute = %s")' ; IMAGE_COLORMODEL attribute = RGB ; ; :Requires: ; IDL 8.0 ; ; :Author: ; Michael Galloy ;- ;+ ; Get properties ;- pro mgffh5dataset::getProperty, _ref_extra=e compile_opt strictarr if (n_elements(e) gt 0L) then self->MGffH5Base::getProperty, _extra=e end ;+ ; Opens the file. ; ; :Private: ; ; :Keywords: ; error : out, optional, type=long ; error code, 0 indicates no error ;- pro mgffh5dataset::_open, error=error compile_opt strictarr catch, error if (error ne 0L) then begin catch, /cancel return endif self.parent->getProperty, identifier=parent_id self.id = h5d_open(parent_id, self.name) end ;+ ; Close the file. ; ; :Private: ; ; :Keywords: ; error : out, optional, type=long ; error code, 0 indicates no error ;- pro mgffh5dataset::_close, error=error compile_opt strictarr catch, error if (error ne 0L) then begin catch, /cancel return endif h5d_close, self.id end ;+ ; Helper method to determine the dimensions of the data set. ; ; :Private: ; ; :Returns: ; lonarr ;- function mgffh5dataset::_getDimensions compile_opt strictarr variableSpace = h5d_get_space(self.id) fullBounds = h5s_get_select_bounds(variableSpace) sz = size(fullBounds, /dimensions) fullBounds = [[fullBounds], [lonarr(sz[0]) + 1L]] dimensions = reform(fullBounds[*, 1] - fullBounds[*, 0] + 1L) h5s_close, variableSpace return, dimensions end ;+ ; Helper method to determine the IDL type (using the codes used by SIZE) of ; the data set. ; ; :Private: ; ; :Returns: ; long ;- function mgffh5dataset::_getIdlType compile_opt strictarr typeId = h5d_get_type(self.id) idlType = h5t_idltype(typeId) h5t_close, typeId return, idlType end ;+ ; Operator overloading method for returning information from SIZE. ; ; :Returns: ; lonarr ; ; :Examples: ; Try:: ; ; IDL> h = mg_h5(file_which('hdf5_test.h5')) ; IDL> g = h.images ; IDL> print, size(g.eskimo) ; 2 600 649 11 389400 ;- function mgffh5dataset::_overloadSize compile_opt strictarr return, self->_getDimensions() end ;+ ; Overload method for HELP routine output. Returns information about data as ; a normal array, but tacks on 'H5' to the data type. ; ; :Returns: ; string ; ; :Params: ; varname : in, required, type=string ; variable's name so that it can be placed into the output ;- function mgffh5dataset::_overloadHelp, varname compile_opt strictarr sdims = strjoin(strtrim(self->_getDimensions(), 2), ', ') type = mg_h5_typedecl(self->_getIdlType()) specs = string(self.name, sdims, format='(%"H5Dataset:%s[%s]")') return, self->MGffH5Base::_overloadHelp(varname, type=type, specs=specs) end ;+ ; Overload method for `PRINT` routine output. Returns entire data array. ; ; :Returns: ; numeric array ;- function mgffh5dataset::_overloadPrint compile_opt strictarr dims = self->_getDimensions() case 1 of n_elements(dims) eq 8: return, self[*, *, *, *, *, *, *, *] n_elements(dims) eq 7: return, self[*, *, *, *, *, *, *] n_elements(dims) eq 6: return, self[*, *, *, *, *, *] n_elements(dims) eq 5: return, self[*, *, *, *, *] n_elements(dims) eq 4: return, self[*, *, *, *] n_elements(dims) eq 3: return, self[*, *, *] n_elements(dims) eq 2: return, self[*, *] n_elements(dims) eq 1: return, self[*] endcase end ;+ ; Convert the parameters needed by H5S_SELECT_HYPERSLAB. ; ; :Params: ; bounds : in, required, type="lonarr(ndims, 3)" ; bounds in the form of `[start, stop, stride]` indices ; ; :Keywords: ; start : out, optional, type=lonarr(ndims) ; count : out, optional, type=lonarr(ndims) ; block : out, optional, type=lonarr(ndims) ; stride : out, optional, type=lonarr(ndims) ;- pro mgffh5dataset::_computeslab, bounds, $ start=start, count=count, $ block=block, stride=stride compile_opt strictarr on_error, 2 ndims = (size(bounds, /dimensions))[0] start = reform(bounds[*, 0]) stride = reform(bounds[*, 2]) count = ceil((bounds[*, 1] - bounds[*, 0] + 1L) / float(bounds[*, 2])) > 1 block = lonarr(ndims) + 1L end ;+ ; Helper method to convert information about a dimension's range into a three ; element vector: `[start, stop, stride]`. ; ; :Params: ; isRange : in, required, type=boolean ; boolean indicating whether the dimension is a range or a single index ; bounds : in, required, type=long/lonarr(3) ; if `isRange` is set then bounds will be a `lonarr(3)` specifying ; `[start, stop, stride]` (with -1 in the `stop` position indicating to ; to continue to the end of the dimension); if `isRange` is not set then ; bounds will be a single index ; ; :Keywords: ; dimensions ;- function mgffh5dataset::_convertbounds, isRange, bounds, dimensions=dimensions compile_opt strictarr on_error, 2 if (~isRange) then return, [bounds, bounds, 1L] result = bounds if (result[1] eq -1L) then result[1] = dimensions - 1L return, result end ;+ ; Get value of attribute. ; ; :Returns: ; attribute value ; ; :Params: ; name : in, required, type=string ; name of attribute ;- function mgffh5dataset::readAttribute, name compile_opt strictarr on_error, 2 catch, error if (error ne 0L) then begin catch, /cancel message, 'attribute not found' endif att = h5a_open_name(self.id, name) result = h5a_read(att) h5a_close, att return, result end ;+ ; Operator overloading methods for retrieving subsets of the dataset. Also ; will retrieve an attribute if indexed by the attribute name as a string ; (useful to specifiy an attribute name case-sensitively). ; ; :Examples: ; Try:: ; ; IDL> h = mg_h5(file_which('hdf5_test.h5')) ; IDL> g = h.images ; IDL> e = g.eskimo ; IDL> plot, e[*, 400], xstyle=9, ystyle=8 ; ; :Returns: ; numeric array ; ; :Params: ; isRange : in, required, type=lonarr ; lonarr with 1-8 elements, 1 for each dimension specified in the ; indexing operation, indicating whether the corresponding dimension ; is a range or single value ; ss1 : in, required, type=long/lonarr(3) ; subscripts for 1st dimension ; ss2 : in, optional, type=long/lonarr(3) ; subscripts for 2nd dimension ; ss3 : in, optional, type=long/lonarr(3) ; subscripts for 3rd dimension ; ss4 : in, optional, type=long/lonarr(3) ; subscripts for 4th dimension ; ss5 : in, optional, type=long/lonarr(3) ; subscripts for 5th dimension ; ss6 : in, optional, type=long/lonarr(3) ; subscripts for 6th dimension ; ss7 : in, optional, type=long/lonarr(3) ; subscripts for 7th dimension ; ss8 : in, optional, type=long/lonarr(3) ; subscripts for 8th dimension ;- function mgffh5dataset::_overloadBracketsRightSide, isRange, $ ss1, ss2, ss3, ss4, $ ss5, ss6, ss7, ss8 compile_opt strictarr on_error, 2 if (size(ss1, /type) eq 7) then return, self->readAttribute(ss1) variableSpace = h5d_get_space(self.id) fullBounds = h5s_get_select_bounds(variableSpace) sz = size(fullBounds, /dimensions) fullBounds = [[fullBounds], [lonarr(sz[0]) + 1L]] dimensions = reform(fullBounds[*, 1] - fullBounds[*, 0] + 1L) if ((n_elements(isRange) eq 1L) && (sz[0] ne 1L) && (array_equal(ss1, [0, -1, 1]))) then begin ; asking for all the elements _bounds = fullBounds endif else begin _bounds = lonarr(n_elements(isRange), 3) switch 1 of n_elements(ss8) gt 0L: begin _bounds[7, *] = self->_convertbounds(isRange[7], ss8, $ dimensions=dimensions[7]) end n_elements(ss7) gt 0L: begin _bounds[6, *] = self->_convertbounds(isRange[6], ss7, $ dimensions=dimensions[6]) end n_elements(ss6) gt 0L: begin _bounds[5, *] = self->_convertbounds(isRange[5], ss6, $ dimensions=dimensions[5]) end n_elements(ss5) gt 0L: begin _bounds[4, *] = self->_convertbounds(isRange[4], ss5, $ dimensions=dimensions[4]) end n_elements(ss4) gt 0L: begin _bounds[3, *] = self->_convertbounds(isRange[3], ss4, $ dimensions=dimensions[3]) end n_elements(ss3) gt 0L: begin _bounds[2, *] = self->_convertbounds(isRange[2], ss3, $ dimensions=dimensions[2]) end n_elements(ss2) gt 0L: begin _bounds[1, *] = self->_convertbounds(isRange[1], ss2, $ dimensions=dimensions[1]) end n_elements(ss1) gt 0L: begin _bounds[0, *] = self->_convertbounds(isRange[0], ss1, $ dimensions=dimensions[0]) end endswitch endelse self->_computeslab, _bounds, $ start=start, count=count, $ block=block, stride=stride resultSpace = h5s_create_simple(count) h5s_select_hyperslab, variableSpace, start, count, $ block=block, stride=stride, /reset data = h5d_read(self.id, $ file_space=variableSpace, $ memory_space=resultSpace) h5s_close, resultSpace h5s_close, variableSpace return, data end ;+ ; Free resources. ;- pro mgffh5dataset::cleanup compile_opt strictarr self->_close end ;+ ; Create an HDF5 dataset. ; ; :Returns: ; 1 for success, 0 for failure ; ; :Keywords: ; error : out, optional, type=long ; error code, 0 indicates no error ;- function mgffh5dataset::init, error=error, _extra=e compile_opt strictarr on_error, 2 if (~self->MGffH5Base::init(_extra=e)) then return, 0 self->_open, error=error if (error ne 0L) then message, 'invalid HDF5 dataset' return, 1 end ;+ ; Define instance variables and class inheritance. ;- pro mgffh5dataset__define compile_opt strictarr define = { MGffH5Dataset, inherits MGffH5Base } end