Source code for pyhetdex.ltl.marray

# Misc python library to support HETDEX software and data analysis
# Copyright (C) 2015, 2016, 2017  "The HETDEX collaboration"
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import numpy as np
from pyhetdex.tools import io_helpers

__version__ = '$Id: marray.py 393 2018-05-08 09:54:47Z montefra $'


[docs]class FVector(object): ''' Python class allowing reading / writing of ltl/FVector object.''' def __init__(self, fname=None): self._data = None if fname: infile = open(fname, 'r') self.read(infile) infile.close() @property def data(self): """The internal numpy array holding the data""" return self._data @data.setter def data(self, dat): if type(dat) != np.ndarray: raise TypeError('Data type for FVector must be a numpy array') if dat.ndim != 1: raise TypeError('Array must be one dimensional for FVector') if 'float' not in dat.dtype.name: if 'int' not in dat.dtype.name: raise TypeError('Only int, float and double are supported!') self._data = dat
[docs] def read(self, ios): # First read the header, format is: # FVector< T,36,0 > dtype = io_helpers.read_to_char(ios, '<').strip() if (dtype != 'FVector'): raise TypeError('Expected FVector, got %s' % dtype) ftype = io_helpers.read_to_char(ios, ',') # Forward through < T, ftype = ftype.strip() if ftype not in ('float', 'double', 'int', 'T'): raise TypeError('Unsupported datatype!') elif ftype == 'T': print('Warning the datatype is unknown, assuming float!') ftype = 'float' elif ftype == 'float': ftype = 'float32' # Read size to next , size = int(io_helpers.read_to_char(ios, ',')) stride = int(io_helpers.read_to_char(ios, '>')) if (stride != 0): raise Exception('Only stride 0 is supported') # Read actual data in # Data is in format [ 6.4277265720642998e+00 4.6045159399542094e+01] # Could span several lines io_helpers.eat_to_blockstart(ios) # Go to start of data self.data = np.fromstring(io_helpers.read_to_char(ios, ']'), dtype=ftype, sep=' ') if (self.data.size != size): raise Exception('Expected to read %d elements, got %d' % (size, self.data.size)) # Clean up the trainling newline io_helpers.eat_to_char(ios, '\n')
[docs] def write(self, ios): if self.data is None: raise Exception('Cowardly refusing to write empty FVector') ios.write("FVector< ") if 'float64' in self._data.dtype.name: ios.write('double,') frmt = ' %.6e' elif 'float' in self._data.dtype.name: ios.write('float,') frmt = ' %.6e' elif 'int' in self._data.dtype.name: ios.write('int,') frmt = ' %d' else: raise TypeError('Unexpected data type!') ios.write("%d,0 >\n " % self.data.size) ios.write("[") for i in range(0, self.data.size): ios.write(frmt % self.data[i]) if not ((i+1) % 9): ios.write(' \n ') ios.write(" ]\n") # LTL writes two spaces before final ]
[docs]class MArray(object): ''' Python class allowing reading / writing of ltl/MArray object.''' def __init__(self, fname=None): self._data = None self.shapes = [] if fname: infile = open(fname, 'r') self.read(infile) infile.close() @property def data(self): """The internal numpy array holding the data""" return self._data @data.setter def data(self, dat): if type(dat) != np.ndarray: raise TypeError('Data type for MArray must be a numpy array') if 'float' not in dat.dtype.name: if 'int' not in dat.dtype.name: raise TypeError('Only int, float and double are supported!') self._data = dat self.shapes = [] for d in range(dat.ndim): self.shapes.append('1,%d' % dat.shape[d])
[docs] def read(self, ios): # First read the header, format is: # MArray<T,2> ( 14 x 246 ) : (1,14) (1,246) dtype = io_helpers.read_to_char(ios, '<').strip() if (dtype != 'MArray'): raise TypeError('Expected MArray, got %s' % dtype) ftype = io_helpers.read_to_char(ios, ',') # Forward through < T, ftype = ftype.strip() if ftype not in ('float', 'double', 'int', 'T'): raise TypeError('Unsupported datatype!') elif ftype == 'T': print('Warning the datatype is unknown, assuming float!') ftype = 'float' elif ftype == 'float': ftype = 'float32' ndims = int(io_helpers.read_to_char(ios, '>')) # Read dimensionsdd) io_helpers.eat_to_char(ios, '(') # Forward to sizes shapes = [] size = [] d = 1 while (d < ndims): size.append(int(io_helpers.read_to_char(ios, 'x'))) d += 1 size.append(int(io_helpers.read_to_char(ios, ')'))) d = 0 while (d < ndims): io_helpers.eat_to_char(ios, '(') shapes.append(io_helpers.read_to_char(ios, ')')) d += 1 # ios.readline() # Read rest of descriptor line # Read actual data in # Data is in format [ 6.4277265720642998e+00 4.6045159399542094e+01] # Could span several lines # Allocate data array size.reverse() data = np.zeros(size, ftype) size.reverse() # Read actual data in io_helpers.eat_to_blockstart(ios) # Now we are at the beginning of the first data block i = 0 while (i < data.size): val = io_helpers.read_to_char(ios, ']') data.flat[i:i+size[0]] = np.fromstring(val, dtype=ftype, sep=' ') i = i + size[0] if(i < data.size): io_helpers.eat_to_blockstart(ios) self.data = data.transpose() self.shapes = shapes # Clean up the trailing newline io_helpers.eat_to_char(ios, '\n')
[docs] def write(self, ios): # Write header line ios.write("MArray<") if 'float64' in self._data.dtype.name: ios.write('double,') frmt = ' %.6e' elif 'float' in self._data.dtype.name: ios.write('float,') frmt = ' %.6e' elif 'int' in self._data.dtype.name: ios.write('int,') frmt = ' %d' else: raise TypeError('Unexpected data type!') ios.write('%d> ( %d' % (self._data.ndim, self._data.shape[0])) d = 1 while d < self._data.ndim: ios.write(' x %d' % self._data.shape[d]) d += 1 ios.write(' ) :') for d in range(self._data.ndim): ios.write(' (%s)' % self.shapes[d]) ios.write(' \n') # Write the data self.__recursive_write(ios, self._data, 0, ' ', frmt) ios.write(']\n')
def __recursive_write(self, ios, data, i, pad, frmt): ios.write('[') if (data.ndim > 1): while (i < data.shape[-1]): self.__recursive_write(ios, data[..., i], 0, pad+' ', frmt) i = i+1 ios.write(']') if(i < data.shape[-1]): ios.write('\n'+pad) else: for j in range(0, data.size): ios.write(frmt % data[j]) # if not ((j+1) % 9): # ios.write('\n'+pad) ios.write(' ')