def _reorder_arguments(self, range1, range2): """ Reinterpret the range arguments into actual "physical" arguments of memory, in light of the symmetry attribute. Parameters ---------- range1 : None|int|tuple * if `None`, then the range is not limited in first axis * if `int` = step size * if (`int`, `int`) = `end`, `step size` * if (`int`, `int`, `int`) = `start`, `stop`, `step size` range2 : None|int|tuple same as `range1`, except for the second axis. Returns ------- None|int|tuple actual range 1 - in light of `range1`, `range2` and symmetry None|int|tuple actual range 2 - in light of `range1`, `range2` and symmetry """ if isinstance(range1, (numpy.ndarray, list)): range1 = tuple(int_func(el) for el in range1) if isinstance(range2, (numpy.ndarray, list)): range2 = tuple(int_func(el) for el in range2) if not (range1 is None or isinstance(range1, integer_types) or isinstance(range1, tuple)): raise TypeError('range1 is of type {}, but must be an instance of None, ' 'int or tuple.'.format(range1)) if isinstance(range1, tuple) and len(range1) > 3: raise TypeError('range1 must have no more than 3 entries, received {}.'.format(range1)) if not (range2 is None or isinstance(range2, integer_types) or isinstance(range2, tuple)): raise TypeError('range2 is of type {}, but must be an instance of None, ' 'int or tuple.'.format(range2)) if isinstance(range2, tuple) and len(range2) > 3: raise TypeError('range2 must have no more than 3 entries, received {}.'.format(range2)) # switch the axes symmetry dictates if self._symmetry[2]: range1, range2 = range2, range1 lim1, lim2 = self._data_size[1], self._data_size[0] else: lim1, lim2 = self._data_size[0], self._data_size[1] # validate the first range if self._symmetry[0]: real_arg1 = reverse_range(range1, lim1) else: real_arg1 = validate_range(range1, lim1) # validate the second range if self._symmetry[1]: real_arg2 = reverse_range(range2, lim2) else: real_arg2 = validate_range(range2, lim2) return real_arg1, real_arg2
def read_support_array(self, index, dim1_range, dim2_range): # find the support array basic details the_entry = None if isinstance(index, integer_types): the_entry = self.crsd_meta.Data.SupportArrays[index] identifier = the_entry.Identifier elif isinstance(index, string_types): identifier = index for entry in self.crsd_meta.Data.SupportArrays: if entry.Identifier == index: the_entry = entry break if the_entry is None: raise KeyError( 'Identifier {} not associated with a support array.'. format(identifier)) else: raise TypeError('Got unexpected type {} for identifier'.format( type(index))) # TODO: use the memmaps defined above... # validate the range definition range1 = validate_range(dim1_range, the_entry.NumRows) range2 = validate_range(dim2_range, the_entry.NumCols) # extract the support array metadata details details = self.crsd_meta.SupportArray.find_support_array(identifier) # determine array byte offset offset = self.crsd_header.SUPPORT_BLOCK_BYTE_OFFSET + the_entry.ArrayByteOffset # determine numpy dtype and depth of array dtype, depth = details.get_numpy_format() # set up the numpy memory map shape = (the_entry.NumRows, the_entry.NumCols) if depth == 1 else \ (the_entry.NumRows, the_entry.NumCols, depth) # TODO: revamp this for file like object support... mem_map = numpy.memmap(self.crsd_details.file_name, dtype=dtype, mode='r', offset=offset, shape=shape) if range1[0] == -1 and range1[2] < 0 and range2[ 0] == -1 and range2[2] < 0: data = mem_map[range1[0]::range1[2], range2[0]::range2[2]] elif range1[0] == -1 and range1[2] < 0: data = mem_map[range1[0]::range1[2], range2[0]:range2[1]:range2[2]] elif range2[0] == -1 and range2[2] < 0: data = mem_map[range1[0]:range1[1]:range1[2], range2[0]::range2[2]] else: data = mem_map[range1[0]:range1[1]:range1[2], range2[0]:range2[1]:range2[2]] return data
def read_pvp_array(self, index, the_range=None): int_index = self._validate_index(index) # fetch the appropriate details from the crsd structure crsd_meta = self.crsd_meta channel = crsd_meta.Data.Channels[int_index] the_range = validate_range(the_range, channel.NumVectors) return self._pvp_memmap[ channel.Identifier][the_range[0]:the_range[1]:the_range[2]]
def read_pvp_variable(self, variable, index, the_range=None): int_index = self._validate_index(index) # fetch the appropriate details from the crsd structure crsd_meta = self.crsd_meta channel = crsd_meta.Data.Channels[int_index] the_range = validate_range(the_range, channel.NumVectors) if variable in self._pvp_memmap[channel.Identifier].dtype.fields: return self._pvp_memmap[channel.Identifier][variable][ the_range[0]:the_range[1]:the_range[2]] else: return None
def _read_pvp_vector(self, pvp_block_offset, pvp_offset, vector_size, field_offset, frm, fld_siz, row_count, dim_range): """ Read the given Per Vector parameter from the disc. Parameters ---------- pvp_block_offset : int The Per Vector block offset from the start of the file, in bytes. pvp_offset : int The offset for the pvp vectors associated with this channel from the start of the PVP block, in bytes. vector_size : int The size of each vector, in bytes. field_offset : int The offset for field from the start of the vector, in bytes. frm : str The struct format string for the field fld_siz : int The size of the field, in bytes - probably 8 or 24. row_count : int The number of rows present for this CPHD channel. dim_range : None|int|Tuple[int, int]|Tuple[int, int, int] The indices for the vector parameter. Returns ------- numpy.ndarray """ # reformat the range definition the_range = validate_range(dim_range, row_count) dtype, elem_size = _format_mapping(frm) siz = int(fld_siz / elem_size) out_count = int_func((the_range[1] - the_range[0]) / the_range[2]) shp = (out_count, ) if siz == 1 else (out_count, siz) out = numpy.zeros(shp, dtype=dtype) current_offset = pvp_block_offset + pvp_offset + the_range[ 0] * vector_size + field_offset with open(self.cphd_details.file_name, 'rb') as fi: for i in range(out_count): fi.seek(current_offset) element = struct.unpack('>{}{}'.format(siz, frm), fi.read(fld_siz)) out[i] = element[0] if siz == 1 else element current_offset += the_range[2] * vector_size return out
def read_support_array(self, index, dim1_range, dim2_range): """ Read the support array. Parameters ---------- index : int|str The support array integer index (of cphd.Data.SupportArrays list) or identifier. dim1_range : None|int|Tuple[int, int]|Tuple[int, int, int] The row data selection of the form `[start, [stop, [stride]]]`, and `None` defaults to all rows (i.e. `(0, NumRows, 1)`) dim2_range : None|int|Tuple[int, int]|Tuple[int, int, int] The column data selection of the form `[start, [stop, [stride]]]`, and `None` defaults to all rows (i.e. `(0, NumCols, 1)`) Returns ------- numpy.ndarray """ # find the support array basic details the_entry = None if isinstance(index, integer_types): the_entry = self.cphd_meta.Data.SupportArrays[index] identifier = the_entry.Identifier elif isinstance(index, string_types): identifier = index for entry in self.cphd_meta.Data.SupportArrays: if entry.Identifier == index: the_entry = entry break if the_entry is None: raise KeyError( 'Identifier {} not associated with a support array.'. format(identifier)) else: raise TypeError('Got unexpected type {} for identifier'.format( type(index))) # validate the range definition range1 = validate_range(dim1_range, the_entry.NumRows) range2 = validate_range(dim2_range, the_entry.NumCols) # extract the support array metadata details details = self.cphd_meta.SupportArray.find_support_array(identifier) # determine array byte offset offset = self.cphd_header.SUPPORT_BLOCK_BYTE_OFFSET + the_entry.ArrayByteOffset # determine numpy dtype and depth of array dtype, depth = details.get_numpy_format() # set up the numpy memory map shape = (the_entry.NumRows, the_entry.NumCols) if depth == 1 else \ (the_entry.NumRows, the_entry.NumCols, depth) mem_map = numpy.memmap(self.cphd_details.file_name, dtype=dtype, mode='r', offset=offset, shape=shape) if range1[0] == -1 and range1[2] < 0 and range2[ 0] == -1 and range2[2] < 0: data = mem_map[range1[0]::range1[2], range2[0]::range2[2]] elif range1[0] == -1 and range1[2] < 0: data = mem_map[range1[0]::range1[2], range2[0]:range2[1]:range2[2]] elif range2[0] == -1 and range2[2] < 0: data = mem_map[range1[0]:range1[1]:range1[2], range2[0]::range2[2]] else: data = mem_map[range1[0]:range1[1]:range1[2], range2[0]:range2[1]:range2[2]] # clean up the memmap object, probably unnecessary, and there SHOULD be a close method del mem_map return data