コード例 #1
0
ファイル: Read.py プロジェクト: tatawang/pseudonetcdf
class temperature(PseudoNetCDFFile):
    """
    temperature provides a PseudoNetCDF interface for CAMx
    temperature files.  Where possible, the inteface follows
    IOAPI conventions (see www.baronams.com).
    
    ex:
        >>> temperature_path = 'camx_temperature.bin'
        >>> rows,cols = 65,83
        >>> temperaturefile = temperature(temperature_path,rows,cols)
        >>> temperaturefile.variables.keys()
        ['TFLAG', 'AIRTEMP', 'SURFTEMP']
        >>> tflag = temperaturefile.variables['TFLAG']
        >>> tflag.dimensions
        ('TSTEP', 'VAR', 'DATE-TIME')
        >>> tflag[0,0,:]
        array([2005185,       0])
        >>> tflag[-1,0,:]
        array([2005185,  240000])
        >>> v = temperaturefile.variables['SURFTEMP']
        >>> v.dimensions
        ('TSTEP', 'ROW', 'COL')
        >>> v.shape
        (25, 65, 83)
        >>> v = temperaturefile.variables['AIRTEMP']
        >>> v.dimensions
        ('TSTEP', 'LAY', 'ROW', 'COL')
        >>> v.shape
        (25, 28, 65, 83)
        >>> temperaturefile.dimensions
        {'TSTEP': 25, 'LAY': 28, 'ROW': 65, 'COL': 83}
    """
    
    id_fmt='fi'
    data_fmt='f'
    def __init__(self,rf,rows=None,cols=None):
        self.rffile=OpenRecordFile(rf)
        self.id_size=struct.calcsize(self.id_fmt)
        self.__readheader()
        self.__gettimestep()
        if rows==None and cols==None:
            rows=self.cell_count
            cols=1
        elif rows==None:
            rows=self.cell_count/cols
        elif cols==None:
            cols=self.cell_count/rows
        else:
            if cols*rows!=self.cell_count:
                raise ValueError("The product of cols (%d) and rows (%d) must equal cells (%d)" %  (cols,rows,self.cell_count))

        self.createDimension('TSTEP', self.time_step_count)
        self.createDimension('COL', cols)
        self.createDimension('ROW', rows)
        self.createDimension('LAY', self.nlayers)
        self.createDimension('SURF', 1)
        self.variables=PseudoNetCDFVariables(self.__var_get,['AIRTEMP','SURFTEMP'])

    def __var_get(self,key):
        decor=lambda k: dict(units='K',var_desc=k.ljust(16),long_name=k.ljust(16))
        constr=lambda k: self.__variables(k)
        values=constr(key)
        dims={'AIRTEMP':('TSTEP','LAY','ROW','COL'),'SURFTEMP':('TSTEP','SURF','ROW','COL')}[key]
        var=self.createVariable(key,'f',dims)
        var[:] = values
        for k,v in decor(key).items():
            setattr(var,k,v)
        return var

    def __readheader(self):
        self.data_start_byte=0
        self.rffile._newrecord(0)
        
        self.area_size=self.rffile.record_size
        self.area_count=(self.area_size-self.id_size)/struct.calcsize(self.data_fmt)
        self.area_padded_size=self.area_size+8
        self.area_fmt=self.id_fmt+self.data_fmt*(self.area_count)

        self.start_time,self.start_date=self.rffile.read(self.id_fmt)
        
        self.record_size=self.rffile.record_size
        self.padded_size=self.record_size+8
        self.cell_count=(self.record_size-self.id_size)/struct.calcsize(self.data_fmt)
        
        self.record_fmt=self.id_fmt+self.data_fmt*(self.cell_count)
    
    def __gettimestep(self):
        d,t=date,time=self.start_date,self.start_time
        self.nlayers=-1
        while (d,t)==(date,time):
            self.nlayers+=1
            t,d=self.rffile.read(self.id_fmt)
        self.time_step=timediff((self.start_date,self.start_time),(d,t))
        self.rffile.infile.seek(0,2)
        self.rffile.previous()
        self.end_time,self.end_date=self.rffile.read(self.id_fmt)
        self.time_step_count=int(timediff((self.start_date,self.start_time),(self.end_date,self.end_time))/self.time_step)+1
    
    def __variables(self,k):
        if k=='SURFTEMP':
            out=zeros((len(self.dimensions['TSTEP']),1,len(self.dimensions['ROW']),len(self.dimensions['COL'])),'f')
            vars=self.__surfmaps()
        elif k=='AIRTEMP':
            out=zeros((len(self.dimensions['TSTEP']),len(self.dimensions['LAY']),len(self.dimensions['ROW']),len(self.dimensions['COL'])),'f')
            vars=self.__airmaps()
        for i,(d,t) in enumerate(self.timerange()):
            out[i,...]=vars.next()
        return out
        
    def __surfpos(self):
        pos=self.data_start_byte+12
        inc=self.area_padded_size+self.padded_size*self.nlayers
        self.rffile.infile.seek(0,2)
        rflen=self.rffile.tell()
        while pos<rflen:
            yield pos
            pos+=inc
        raise StopIteration
        
    def __surfmaps(self):
        for pos in self.__surfpos():
            yield memmap(self.rffile.infile.name,'>f','r',pos,(self.area_count,)).reshape(len(self.dimensions['ROW']),len(self.dimensions['COL']))
            
    def __airpos(self):
        pos=self.area_padded_size+self.data_start_byte
        inc=self.area_padded_size+self.padded_size*self.nlayers
        self.rffile.infile.seek(0,2)
        rflen=self.rffile.tell()
        while pos<rflen:
            yield pos
            pos+=inc
        raise StopIteration
    
    def __airmaps(self):
        for pos in self.__airpos():
            yield memmap(self.rffile.infile.name,'>f','r',pos,((self.cell_count+4)*self.nlayers,)).reshape(self.nlayers,self.cell_count+4)[:,3:-1].reshape(len(self.dimensions['LAY']),len(self.dimensions['ROW']),len(self.dimensions['COL']))

    def timerange(self):
        return timerange((self.start_date,self.start_time),timeadd((self.end_date,self.end_time),(0,self.time_step),(2400,24)[int(self.time_step % 2)]),self.time_step,(2400,24)[int(self.time_step % 2)])
コード例 #2
0
ファイル: Read.py プロジェクト: wongmengya/pseudonetcdf
class temperature(PseudoNetCDFFile):
    """
    temperature provides a PseudoNetCDF interface for CAMx
    temperature files.  Where possible, the inteface follows
    IOAPI conventions (see www.baronams.com).

    ex:
        >>> temperature_path = 'camx_temperature.bin'
        >>> rows,cols = 65,83
        >>> temperaturefile = temperature(temperature_path,rows,cols)
        >>> temperaturefile.variables.keys()
        ['TFLAG', 'AIRTEMP', 'SURFTEMP']
        >>> tflag = temperaturefile.variables['TFLAG']
        >>> tflag.dimensions
        ('TSTEP', 'VAR', 'DATE-TIME')
        >>> tflag[0,0,:]
        array([2005185,       0])
        >>> tflag[-1,0,:]
        array([2005185,  240000])
        >>> v = temperaturefile.variables['SURFTEMP']
        >>> v.dimensions
        ('TSTEP', 'ROW', 'COL')
        >>> v.shape
        (25, 65, 83)
        >>> v = temperaturefile.variables['AIRTEMP']
        >>> v.dimensions
        ('TSTEP', 'LAY', 'ROW', 'COL')
        >>> v.shape
        (25, 28, 65, 83)
        >>> temperaturefile.dimensions
        {'TSTEP': 25, 'LAY': 28, 'ROW': 65, 'COL': 83}
    """

    id_fmt = 'fi'
    data_fmt = 'f'

    def __init__(self, rf, rows=None, cols=None):
        self.rffile = OpenRecordFile(rf)
        self.id_size = struct.calcsize(self.id_fmt)
        self.__readheader()
        self.__gettimestep()
        if rows is None and cols is None:
            rows = self.cell_count
            cols = 1
        elif rows is None:
            rows = self.cell_count / cols
        elif cols is None:
            cols = self.cell_count / rows
        else:
            if cols * rows != self.cell_count:
                raise ValueError(
                    ("The product of cols (%d) and rows (%d) " +
                     "must equal cells (%d)") % (cols, rows, self.cell_count))

        self.createDimension('TSTEP', self.time_step_count)
        self.createDimension('COL', cols)
        self.createDimension('ROW', rows)
        self.createDimension('LAY', self.nlayers)
        self.createDimension('SURF', 1)
        self.variables = PseudoNetCDFVariables(self.__var_get,
                                               ['AIRTEMP', 'SURFTEMP'])

    def __var_get(self, key):
        def decor(k):
            return dict(units='K', var_desc=k.ljust(16), long_name=k.ljust(16))

        def constr(k):
            return self.__variables(k)

        values = constr(key)
        dims = {
            'AIRTEMP': ('TSTEP', 'LAY', 'ROW', 'COL'),
            'SURFTEMP': ('TSTEP', 'SURF', 'ROW', 'COL')
        }[key]
        var = self.createVariable(key, 'f', dims)
        var[:] = values
        for k, v in decor(key).items():
            setattr(var, k, v)
        return var

    def __readheader(self):
        self.data_start_byte = 0
        self.rffile._newrecord(0)

        self.area_size = self.rffile.record_size
        self.area_count = (self.area_size - self.id_size) // struct.calcsize(
            self.data_fmt)
        self.area_padded_size = self.area_size + 8
        self.area_fmt = self.id_fmt + self.data_fmt * (self.area_count)

        self.start_time, self.start_date = self.rffile.read(self.id_fmt)

        self.record_size = self.rffile.record_size
        self.padded_size = self.record_size + 8
        self.cell_count = (self.record_size - self.id_size) // struct.calcsize(
            self.data_fmt)

        self.record_fmt = self.id_fmt + self.data_fmt * (self.cell_count)

    def __gettimestep(self):
        d, t = date, time = self.start_date, self.start_time
        self.nlayers = -1
        while (d, t) == (date, time):
            self.nlayers += 1
            t, d = self.rffile.read(self.id_fmt)
        self.time_step = timediff((self.start_date, self.start_time), (d, t))
        self.rffile.infile.seek(0, 2)
        self.rffile.previous()
        self.end_time, self.end_date = self.rffile.read(self.id_fmt)
        self.time_step_count = int(
            timediff((self.start_date, self.start_time),
                     (self.end_date, self.end_time)) // self.time_step) + 1

    def __variables(self, k):
        if k == 'SURFTEMP':
            out = zeros(
                (len(self.dimensions['TSTEP']), 1, len(
                    self.dimensions['ROW']), len(self.dimensions['COL'])), 'f')
            vars = self.__surfmaps()
        elif k == 'AIRTEMP':
            out = zeros(
                (len(self.dimensions['TSTEP']), len(self.dimensions['LAY']),
                 len(self.dimensions['ROW']), len(self.dimensions['COL'])),
                'f')
            vars = self.__airmaps()
        for i, v in enumerate(vars):
            out[i, ...] = v
        return out

    def __surfpos(self):
        pos = self.data_start_byte + 12
        inc = self.area_padded_size + self.padded_size * self.nlayers
        self.rffile.infile.seek(0, 2)
        rflen = self.rffile.tell()
        while pos < rflen:
            yield pos
            pos += inc
        raise StopIteration

    def __surfmaps(self):
        for pos in self.__surfpos():
            tmpmm = memmap(self.rffile.infile.name, '>f', 'r', pos,
                           (self.area_count, ))
            newshape = [
                len(self.dimensions['ROW']),
                len(self.dimensions['COL'])
            ]
            yield tmpmm.reshape(*newshape)

    def __airpos(self):
        pos = self.area_padded_size + self.data_start_byte
        inc = self.area_padded_size + self.padded_size * self.nlayers
        self.rffile.infile.seek(0, 2)
        rflen = self.rffile.tell()
        while pos < rflen:
            yield pos
            pos += inc
        raise StopIteration

    def __airmaps(self):
        for pos in self.__airpos():
            firstshape = ((self.cell_count + 4) * self.nlayers, )
            tmpmm = memmap(self.rffile.infile.name, '>f', 'r', pos, firstshape)
            newshape1 = [self.nlayers, self.cell_count + 4]
            tmpmm = tmpmm.reshape(*newshape1)[:, 3:-1]
            newshape2 = [
                len(self.dimensions['LAY']),
                len(self.dimensions['ROW']),
                len(self.dimensions['COL'])
            ]
            yield tmpmm.reshape(*newshape2)

    def timerange(self):
        return timerange(
            (self.start_date, self.start_time),
            timeadd((self.end_date, self.end_time), (0, self.time_step),
                    (2400, 24)[int(self.time_step % 2)]), self.time_step,
            (2400, 24)[int(self.time_step % 2)])
コード例 #3
0
class wind(PseudoNetCDFFile):
    """
    wind provides a PseudoNetCDF interface for CAMx
    wind files.  Where possible, the inteface follows
    IOAPI conventions (see www.baronams.com).
    
    ex:
        >>> wind_path = 'camx_wind.bin'
        >>> rows,cols = 65,83
        >>> windfile = wind(wind_path,rows,cols)
        >>> windfile.variables.keys()
        ['TFLAG', 'U', 'V']
        >>> v = windfile.variables['V']
        >>> tflag = windfile.variables['TFLAG']
        >>> tflag.dimensions
        ('TSTEP', 'VAR', 'DATE-TIME')
        >>> tflag[0,0,:]
        array([2005185,       0])
        >>> tflag[-1,0,:]
        array([2005185,  240000])
        >>> v.dimensions
        ('TSTEP', 'LAY', 'ROW', 'COL')
        >>> v.shape
        (25, 28, 65, 83)
        >>> windfile.dimensions
        {'TSTEP': 25, 'LAY': 28, 'ROW': 65, 'COL': 83}
    """
    
    time_hdr_fmts={12: "fii", 8: "fi"}
    data_fmt="f"
    def __init__(self,rf,rows=None,cols=None):
        """
        Initialization included reading the header and learning
        about the format.
        
        see __readheader and __gettimestep() for more info
        """
        self.rffile=OpenRecordFile(rf)
        self.time_hdr_fmt=self.time_hdr_fmts[self.rffile.record_size]
        
        self.time_hdr_size=struct.calcsize(self.time_hdr_fmt)
        self.padded_time_hdr_size=struct.calcsize("ii"+self.time_hdr_fmt)
        self.__readheader()
        self.__gettimestep()
        if rows==None and cols==None:
            rows=self.cell_count
            cols=1
        elif rows==None:
            rows=self.cell_count/cols
        elif cols==None:
            cols=self.cell_count/rows
        else:
            if cols*rows!=self.cell_count:
                raise ValueError("The product of cols (%d) and rows (%d) must equal cells (%d)" %  (cols,rows,self.cell_count))
        self.createDimension('TSTEP', self.time_step_count)
        self.createDimension('COL', cols)
        self.createDimension('ROW', rows)
        self.createDimension('LAY', self.nlayers)

        self.variables=PseudoNetCDFVariables(self.__var_get,['U','V'])

    def __var_get(self,key):
        constr=lambda uv: self.getArray()[:,{'U': 0, 'V': 1}[uv],:,:,:].copy()
        decor=lambda uv: dict(units='m/s', var_desc=uv.ljust(16), long_name=uv.ljust(16))
        values=constr(key)
        
        var=self.createVariable(key,'f',('TSTEP','LAY','ROW','COL'))
        var[:] = values
        for k,v in decor(key).items():
            setattr(var,k,v)
        return var

    def __readheader(self):
        """
        __readheader reads the header section of the ipr file
        it initializes each header field (see CAMx Users Manual for a list)
        as properties of the ipr class
        """
        self.data_start_byte=0
        if self.time_hdr_fmt=='fii':
            self.start_time,self.start_date,self.lstagger=self.rffile.read(self.time_hdr_fmt)
        elif self.time_hdr_fmt=='fi':
            self.start_time,self.start_date=self.rffile.read(self.time_hdr_fmt)
            self.lstagger=None
        else:
            raise NotImplementedError("Header format is unknown")
            
        self.record_size=self.rffile.record_size
        self.padded_size=self.record_size+8
        self.cell_count=self.record_size/struct.calcsize(self.data_fmt)
        self.record_fmt=self.data_fmt*self.cell_count
        
    def __gettimestep(self):
        """
        Header information provides start and end date, but does not
        indicate the increment between.  This routine reads the first
        and second date/time and initializes variables indicating the
        timestep length and the anticipated number.
        """
        #This is a bit of a hack, but should work:
        #Search for the next record that is the same
        #length as self.padded_time_hdr_size
        #
        #This should be the next date record
        #1) date - startdate = timestep
        #2) (record_start - self.padded_time_hdr_size)/self.padded_size = klayers
        self.rffile.next()
        while not self.rffile.record_size==self.time_hdr_size:
            self.rffile.next()
        
        dist_btwn_dates=self.rffile.record_start - self.padded_time_hdr_size
        self.nlayers=(dist_btwn_dates)/self.padded_size/2
        
        if self.time_hdr_fmt=="fi":
            time,date=self.rffile.read(self.time_hdr_fmt)
        elif self.time_hdr_fmt=="fii":
            time,date,lstagger=self.rffile.read(self.time_hdr_fmt)

        self.time_step=timediff((self.start_date,self.start_time),(date,time))
        
        while True:
            try:
                self.rffile._newrecord(self.rffile.record_start+dist_btwn_dates)
                self.rffile.tell()
                if self.time_hdr_fmt=="fi":
                    self.end_time,self.end_date=self.rffile.read(self.time_hdr_fmt)
                elif self.time_hdr_fmt=="fii":
                    self.end_time,self.end_date,lstagger=self.rffile.read(self.time_hdr_fmt)
            except:
                break
        
        self.time_step_count=int(timediff((self.start_date,self.start_time),(self.end_date,self.end_time))/self.time_step)+1
        
    def __layerrecords(self,k):
        return k-1
        
    def __timerecords(self,dt):
        """
        routine returns the number of records to increment from the
        data start byte to find the first time
        """
        d, t = dt
        nsteps=int(timediff((self.start_date,self.start_time),(d,t))/self.time_step)
        nlays=self.__layerrecords(self.nlayers+1)
        return nsteps*nlays
        
    def __recordposition(self,date,time,k,duv):
        """ 
        routine uses pagridrecords, timerecords,irecords,
        jrecords, and krecords multiplied by the fortran padded size
        to return the byte position of the specified record
        
        pagrid - integer
        date - integer
        time - float
        duv - integer (0=date,1=uwind,2=vwind)
        """
        bytes=self.data_start_byte
        nsteps=self.__timerecords((date,time))
        bytes+=int(nsteps/self.nlayers)*self.padded_time_hdr_size
        bytes+=int(nsteps/self.nlayers)*12
        bytes+=nsteps*self.padded_size*2
        if not duv==0:
            bytes+=self.padded_time_hdr_size
            bytes+=self.__layerrecords(k)*2*self.padded_size
        if duv==2:
            bytes+=self.padded_size
        return bytes
        
    def seek(self,date=None,time=None,k=1,uv=1):
        """
        Move file cursor to beginning of specified record
        see __recordposition for a definition of variables
        """
        if date==None:
            date=self.start_date
        if time==None:
            time=self.start_time
        chkvar=True
        if chkvar and timediff((self.end_date,self.end_time),(date,time))>0 or timediff((self.start_date,self.start_time),(date,time))<0:
            raise KeyError("Wind file includes (%i,%6.1f) thru (%i,%6.1f); you requested (%i,%6.1f)" % (self.start_date,self.start_time,self.end_date,self.end_time,date,time))
        if chkvar and uv<0 or uv >2:
            raise KeyError("Wind file includes Date (uv: 0), u velocity (uv: 1) and v velocity (uv: 2); you requested %i" % (uv))
        
        self.rffile._newrecord(self.__recordposition(date,time,k,uv))
        
    def read(self):
        """
        provide direct access to the underlying RecordFile read
        method
        """
        return self.rffile.read(self.record_fmt)
        
    def read_into(self,dest):
        """
        put values from rffile read into dest
        dest - numpy or numeric array
        """
        return read_into(self.rffile,dest,"",self.data_fmt)
        
    def seekandreadinto(self,dest,date=None,time=None,k=1,duv=1):
        """
        see seek and read_into
        """
        self.seek(date,time,k,duv)
        self.read_into(dest)
        
    def seekandread(self,date=None,time=None,k=1,duv=1):
        """
        see seek and read
        """
        self.seek(date,time,k,duv)
        return self.read()
        
    def keys(self):
        for d,t in timerange((self.start_date,self.start_time),timeadd((self.end_date,self.end_time),(0,self.time_step)),self.time_step):
            for k in range(1,self.nlayers+1):
                yield d,t,k
                
    def values(self):
        for d,t,k in self.keys():
            yield self.seekandread(d,t,k,1),self.seekandread(d,t,k,2)
    
    def items(self):
        for d,t,k in self.keys():
            yield d,t,k,self.seekandread(d,t,k,1),self.seekandread(d,t,k,2)
    
    __iter__=keys
    
    def getArray(self,krange=slice(1,None)):
        if type(krange) != slice :
            if type(krange)==tuple:
                krange = slice(*krange)
            if type(krange)==int:
                krange=slice(krange,krange+1)
        a=zeros(
            (
                self.time_step_count ,
                2 ,
                len(xrange(*krange.indices(self.nlayers+1))),
                len(self.dimensions['ROW']),
                len(self.dimensions['COL']),
            ),'f')
        for i,(d,t) in enumerate(self.timerange()):
            for uv in range(1,3):
                for ki,k in enumerate(xrange(*krange.indices(self.nlayers+1))):
                    self.seekandreadinto(a[i,uv-1,k-1,:,:],d,t,k,uv)
        return a
    
    def timerange(self):
        return timerange((self.start_date,self.start_time),timeadd((self.end_date,self.end_time),(0,self.time_step)),self.time_step)