1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
from numpy.ma import masked_where as numpy_ma_masked_where
from ..constants import _file_to_fh
from ..functions import (open_files_threshold_exceeded,
close_one_file,
parse_indices,
get_subspace)
from ..data.filearray import FileArray
from .functions import _open_um_file, _close_um_file
from .umread.umfile import Rec
_filename_to_file = _file_to_fh.setdefault('UM', {})
# ====================================================================
#
# UMFileArray object
#
# ====================================================================
class UMFileArray(FileArray):
'''A sub-array stored in a PP or UM fields file.
**Initialization**
:Parameters:
file : str
The file name in normalized, absolute form.
dtype : numpy.dtype
The data type of the data array on disk.
ndim : int
The number of dimensions in the unpacked data array.
shape : tuple
The shape of the unpacked data array.
size : int
The number of elements in the unpacked data array.
header_offset : int
The start position in the file of the header.
data_offset : int
The start position in the file of the data array.
disk_length : int
The number of words on disk for the data array, usually
LBLREC-LBEXT. If set to 0 then `!size` is used.
:Examples:
>>> a = UMFileArray(file='file.pp', header_offset=3156, data_offset=3420,
... dtype=numpy.dtype('float32'), shape=(30, 24),
... size=720, ndim=2, disk_length=0)
>>> a = UMFileArray(file='packed_file.pp', header_offset=3156, data_offset=3420,
... dtype=numpy.dtype('float32'), shape=(30, 24),
... size=720, ndim=2, disk_length=423)
'''
def __getitem__(self, indices):
'''
Implement indexing
x.__getitem__(indices) <==> x[indices]
Returns a numpy array.
'''
f = self.open()
rec = Rec.from_file_and_offsets(f, self.header_offset,
self.data_offset,
self.disk_length)
int_hdr = rec.int_hdr
real_hdr = rec.real_hdr
array = rec.get_data().reshape(int_hdr.item(17,), int_hdr.item(18,))
if indices is not Ellipsis:
indices = parse_indices(array, indices)
array = get_subspace(array, indices)
LBUSER2 = int_hdr.item(38,)
if LBUSER2 == 3:
# Return the numpy array now if it is a boolean array
return array.astype(bool)
integer_array = LBUSER2 == 2
# ------------------------------------------------------------
# Convert to a masked array
# ------------------------------------------------------------
# Set the fill_value from BMDI
fill_value = real_hdr.item(17,)
if fill_value != -1.0e30:
# -1.0e30 is the flag for no missing data
if integer_array:
# The fill_value must be of the same type as the data
# values
fill_value = int(fill_value)
# Mask any missing values
mask = (array == fill_value)
if mask.any():
array = numpy_ma_masked_where(mask, array, copy=False)
#--- End: if
# ------------------------------------------------------------
# Unpack the array using the scale_factor and add_offset, if
# either is available
# ------------------------------------------------------------
# Treat BMKS as a scale_factor if it is neither 0 nor 1
scale_factor = real_hdr.item(18,)
if scale_factor != 1.0 and scale_factor != 0.0:
if integer_array:
scale_factor = int(scale_factor)
array *= scale_factor
# Treat BDATUM as an add_offset if it is not 0
add_offset = real_hdr.item(4,)
if add_offset != 0.0:
if integer_array:
add_offset = int(add_offset)
array += add_offset
# Return the numpy array
return array
#--- End: def
def __str__(self):
'''
x.__str__() <==> str(x)
'''
return "%s%s in %s" % (self.header_offset, self.shape, self.file)
#--- End: def
@property
def file_pointer(self):
'''
'''
return (self.file, self.header_offset)
#--- End: def
def close(self):
'''
Close the file containing the data array.
If the file is not open then no action is taken.
:Returns:
None
:Examples:
>>> f.close()
'''
_close_um_file(self.file)
#--- End: def
def open(self):
'''
Open the file containing the data array.
:Returns:
out : um.umread.umfile.File
:Examples:
>>> f.open()
'''
return _open_um_file(self.file)
#--- End: def
#--- End: class
|