|
|
|
@ -116,6 +116,7 @@ class fortran_bin_file(object): |
|
|
|
|
|
|
|
|
|
def byte_length(self, *fields): |
|
|
|
|
"""Given a list of field descriptors, determine how many bytes this |
|
|
|
|
set of fields would occupy. |
|
|
|
|
""" |
|
|
|
|
expected_len = sum([ self.fld_count(f) * numpy.dtype(f[1]).itemsize |
|
|
|
|
for f in fields ]) |
|
|
|
@ -194,6 +195,41 @@ class fortran_bin_file(object): |
|
|
|
|
|
|
|
|
|
return rslt |
|
|
|
|
|
|
|
|
|
def bulk_read_array1(self, dtype, shape): |
|
|
|
|
"""Reads data that is regularly stored as an array of Fortran records |
|
|
|
|
(all of the same type and length). |
|
|
|
|
Each record must be 'read' individually and validated if the record lengths |
|
|
|
|
are indeed correct. |
|
|
|
|
But this routine will bulk-read all the records at once, and shape it |
|
|
|
|
into an array with that format. |
|
|
|
|
|
|
|
|
|
Warning: because we load all the leading and trailing reclen markers, the array |
|
|
|
|
will be larger than the actual size of the data, and the memory will not be |
|
|
|
|
contiguous. |
|
|
|
|
Use copy_subarray below to create the contiguous representation of the data |
|
|
|
|
(per field name). |
|
|
|
|
""" |
|
|
|
|
from numpy import product, fromfile, all |
|
|
|
|
dtype1 = numpy.dtype([('reclen', self.record_marker_type), |
|
|
|
|
('content', dtype), |
|
|
|
|
('reclen2', self.record_marker_type)]) |
|
|
|
|
|
|
|
|
|
dtype_itemsize = dtype1['content'].itemsize |
|
|
|
|
|
|
|
|
|
size = product(shape) # total number of elements to read in bulk |
|
|
|
|
# reads in *ALL* the records in a linear fashion, in one read stmt |
|
|
|
|
arr = fromfile(self.F, dtype1, size) |
|
|
|
|
|
|
|
|
|
if not all(arr['reclen'] == dtype_itemsize) \ |
|
|
|
|
or not all(arr['reclen2'] == dtype_itemsize): |
|
|
|
|
raise IOError, \ |
|
|
|
|
(("Inconsistency detected in record array: " \ |
|
|
|
|
"one or more records do not have the expected record length=%d") \ |
|
|
|
|
% (dtype_itemsize,)) |
|
|
|
|
|
|
|
|
|
# Returns only the content--this WILL NOT be contiguous in memory. |
|
|
|
|
return arr['content'].reshape(shape, order='F') |
|
|
|
|
|
|
|
|
|
def write_vals(self, *vals, **opts): |
|
|
|
|
"""Writes a Fortran record. |
|
|
|
|
Only values need to be given, because the types are known. |
|
|
|
@ -315,3 +351,27 @@ def array_major_dim(arr): |
|
|
|
|
"Unable to determine whether this is a row or column major object." |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def copy_subarray(arr, key, order='F'): |
|
|
|
|
"""Given a numpy array of structured datatype, copy out a subarray field |
|
|
|
|
into a new array with contiguous format. |
|
|
|
|
The field accessed by arr[key] must be a fixed-size array. |
|
|
|
|
The order argument can be either 'F' or 'C': |
|
|
|
|
- For 'F' ordering, then the subarray index will become the *first* index. |
|
|
|
|
- For 'C' ordering, then the subarray index will become the *last* index. |
|
|
|
|
""" |
|
|
|
|
subarr = arr[key] |
|
|
|
|
dim = len(arr.shape) |
|
|
|
|
subdim = len(subarr.shape) - dim |
|
|
|
|
if order == 'F': |
|
|
|
|
rslt = numpy.transpose(subarr, axes=list(range(dim, subdim+dim) + range(dim))) |
|
|
|
|
elif order == 'C': |
|
|
|
|
rslt = subarr |
|
|
|
|
else: |
|
|
|
|
raise ValueError, 'Invalid order argument' |
|
|
|
|
# Always return a copy! |
|
|
|
|
if numpy.may_share_memory(rslt, arr): |
|
|
|
|
return rslt.copy(order=order) |
|
|
|
|
else: |
|
|
|
|
return rslt |
|
|
|
|
|
|
|
|
|
|
|
|
|
|