Ejemplo n.º 1
0
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)])
Ejemplo n.º 2
0
class ipr(PseudoNetCDFFile):
    """
    ipr provides a PseudoNetCDF interface for CAMx
    ipr files.  Where possible, the inteface follows
    IOAPI conventions (see www.baronams.com).
    
    ex:
        >>> ipr_path = 'camx_ipr.bin'
        >>> iprfile = ipr(ipr_path)
        >>> iprfile.variables.keys()
        ['TFLAG', 'SPAD_O3', 'DATE_O3', 'TIME_O3', 'SPC_O3', 
         'PAGRID_O3', 'NEST_O3', 'I_O3', 'J_O3', 'K_O3', 
         'INIT_O3', 'CHEM_O3', 'EMIS_O3', 'PTEMIS_O3', 
         'PIG_O3', 'WADV_O3', 'EADV_O3', 'SADV_O3', 'NADV_O3', 
         'BADV_O3', 'TADV_O3', 'DIL_O3', 'WDIF_O3', 'EDIF_O3', 
         'SDIF_O3', 'NDIF_O3', 'BDIF_O3', 'TDIF_O3', 'DDEP_O3', 
         'WDEP_O3', 'INORGACHEM_O3', 'ORGACHEM_O3', 'AQACHEM_O3', 
         'FCONC_O3', 'UCNV_O3', 'AVOL_O3', 'EPAD_O3']
        >>> v = iprfile.variables['CHEM_O3']
        >>> tflag = iprfile.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)
        >>> iprfile.dimensions
        {'TSTEP': 25, 'LAY': 28, 'ROW': 65, 'COL': 83}
    """
    
    id_fmt="if10s5i"
    dt_fmt="if"
    data_fmt="f"
    
    def __init__(self,rf,multi=False, **props):
        """
        Initialization included reading the header and learning
        about the format.
        
        see __readheader and __gettimestep() for more info

        Keywords (i.e., props) for projection: P_ALP, P_BET, P_GAM, XCENT, YCENT, XORIG, YORIG, XCELL, YCELL
        """
        self.__rffile=OpenRecordFile(rf)
        self.__readheader()
        self.__ipr_record_type={
            24: dtype(
                        dict(
                            names=['SPAD', 'DATE', 'TIME', 'SPC', 'PAGRID', 'NEST', 'I', 'J', 'K', 
                                    'INIT', 'CHEM', 'EMIS', 'PTEMIS', 'PIG', 'WADV', 'EADV', 'SADV', 
                                    'NADV', 'BADV', 'TADV', 'DIL', 'WDIF', 'EDIF', 'SDIF', 'NDIF', 
                                    'BDIF', 'TDIF', 'DDEP', 'WDEP', 'AERCHEM', 'FCONC', 'UCNV', 'AVOL', 
                                    'EPAD'], 
                            formats=['>i', '>i', '>f', '>S10', '>i', '>i', '>i', '>i', '>i', 
                                    '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f',
                                    '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f',
                                    '>f', '>f', '>f', '>f', '>f', '>f', '>i'])),
            26: dtype(
                        dict(
                            names=['SPAD', 'DATE', 'TIME', 'SPC', 'PAGRID', 'NEST', 'I', 'J', 'K', 
                                    'INIT', 'CHEM', 'EMIS', 'PTEMIS', 'PIG', 'WADV', 'EADV', 'SADV', 
                                    'NADV', 'BADV', 'TADV', 'DIL', 'WDIF', 'EDIF', 'SDIF', 'NDIF', 
                                    'BDIF', 'TDIF', 'DDEP', 'WDEP', 'INORGACHEM', 'ORGACHEM', 'AQACHEM', 'FCONC', 'UCNV', 'AVOL', 
                                    'EPAD'], 
                            formats=['>i', '>i', '>f', '>S10', '>i', '>i', '>i', '>i', '>i', 
                                    '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f',
                                    '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f',
                                    '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>i']))
                                }[len(self.prcnames)]

        prcs=['SPAD', 'DATE', 'TIME', 'PAGRID', 'NEST', 'I', 'J', 'K', 
                'INIT', 'CHEM', 'EMIS', 'PTEMIS', 'PIG', 'WADV', 'EADV', 'SADV', 
                'NADV', 'BADV', 'TADV', 'DIL', 'WDIF', 'EDIF', 'SDIF', 'NDIF', 
                'BDIF', 'TDIF', 'DDEP', 'WDEP']+{24: ['AERCHEM'], 26: ['INORGACHEM', 'ORGACHEM', 'AQACHEM']}[len(self.prcnames)]+['FCONC', 'UCNV', 'AVOL', 
                'EPAD']
        varkeys=['_'.join(i) for i in cartesian(prcs,self.spcnames)]
        varkeys+=['SPAD','DATE','TIME','PAGRID','NEST','I','J','K','TFLAG']
        self.groups = {}
        NSTEPS = len([i_ for i_ in self.timerange()])
        NVARS = len(varkeys)
        self.createDimension('VAR', NVARS)
        self.createDimension('DATE-TIME', 2)
        self.createDimension('TSTEP', NSTEPS)
        padatatype = []
        pavarkeys = []
        for di, domain in enumerate(self.padomains):
            dk = 'PA%02d' % di
            prefix = dk + '_'
            grp = self.groups[dk] = PseudoNetCDFFile()
            pavarkeys.extend([prefix + k for k in varkeys])
            grp.createDimension('VAR', NVARS)
            grp.createDimension('DATE-TIME', 2)
            grp.createDimension('TSTEP', NSTEPS)
            grp.createDimension('COL', domain['iend'] - domain['istart'] + 1)
            grp.createDimension('ROW', domain['jend'] - domain['jstart'] + 1)
            grp.createDimension('LAY', domain['tlay'] - domain['blay'] + 1)
            padatatype.append((dk, self.__ipr_record_type, (len(grp.dimensions['ROW']), len(grp.dimensions['COL']), len(grp.dimensions['LAY']))))
            if len(self.padomains) == 1:
                self.createDimension('COL', domain['iend']-domain['istart']+1)
                self.createDimension('ROW', domain['jend']-domain['jstart']+1)
                self.createDimension('LAY', domain['tlay']-domain['blay']+1)
            exec("""def varget(k):
                return self._ipr__variables('%s', k)""" % dk, dict(self = self), locals())
            if len(self.padomains) == 1:
                self.variables = PseudoNetCDFVariables(varget,varkeys)
            else:
                grp.variables = PseudoNetCDFVariables(varget,varkeys)
        
        self.__memmaps=memmap(self.__rffile.infile.name,dtype(padatatype),'r',self.data_start_byte).reshape(NSTEPS, len(self.spcnames))
        for k, v in props.items():
            setattr(self, k, v)
        try:
            add_cf_from_ioapi(self)
        except:
            pass

    def __del__(self):
        try:
            self.__memmaps.close()
            del self.__memmaps
        except:
            pass

    def __decorator(self,name,pncfv):
        spc = name.split('_')[-1]
        prc = name.split('_')[0]
        # IPR units are consistent with 'IPR'
        if prc == 'UCNV':
            units = 'm**3/mol'
        elif prc == 'AVOL':
            units = 'm**3'
        else:
            units = get_uamiv_units('IPR', spc)
        decor=lambda k: dict(units=units, var_desc=k.ljust(16), long_name=k.ljust(16))
        for k,v in decor(name).items():
            setattr(pncfv,k,v)        
        return pncfv
        
    def __variables(self,pk, proc_spc):
        if proc_spc in self.__ipr_record_type.names:
            proc=proc_spc
            proc_spc=proc_spc+'_'+self.spcnames[0]
            return PseudoNetCDFVariable(self,proc_spc,'f',('TSTEP','LAY','ROW','COL'),values=self.__memmaps[pk][:,0,:,:,:][proc].swapaxes(1, 3).swapaxes(2, 3))
        if proc_spc=='TFLAG':
            thisdate = self.__memmaps[pk][:,0,:,:,:]['DATE'].swapaxes(1, 3).swapaxes(2, 3)[..., 0, 0, 0]
            thistime = self.__memmaps[pk][:,0,:,:,:]['TIME'].swapaxes(1, 3).swapaxes(2, 3)[..., 0, 0, 0]
            return ConvertCAMxTime(thisdate, thistime, len(self.groups[pk].dimensions['VAR']))
        for k in self.__ipr_record_type.names:
            proc=proc_spc[:len(k)]
            spc=proc_spc[len(k)+1:]
            if proc==k and spc in self.spcnames:
                spc=self.spcnames.index(spc)
                dvals = self.__memmaps[pk][:,spc][proc].swapaxes(1, 3).swapaxes(2, 3)
                return self.__decorator(proc_spc,PseudoNetCDFVariable(self,proc_spc,'f',('TSTEP','LAY','ROW','COL'),values=dvals))
        raise KeyError("Bad!")
                
                
    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.runmessage=self.__rffile.read("80s")
        self.start_date,self.start_time,self.end_date,self.end_time=self.__rffile.read("ifif")
        
        self.grids=[]
        for grid in range(self.__rffile.read("i")[-1]):
            self.grids.append(
                            dict(
                                zip(
                                    ['orgx','orgy','ncol','nrow','xsize','ysize'], 
                                    self.__rffile.read("iiiiii")
                                    )
                                )
                            )
        
        self.spcnames = []
        for spc in range(self.__rffile.read("i")[-1]):
            self.spcnames.append(self.__rffile.read("10s")[-1].strip())
            
        self.nspec=len(self.spcnames)
        self.padomains=[]
        
        for padomain in range(self.__rffile.read("i")[-1]):
            self.padomains.append(
                                dict(
                                    zip(
                                        ['grid','istart','iend','jstart','jend','blay','tlay'],
                                        self.__rffile.read("iiiiiii")
                                        )
                                    )
                                )
        self.activedomain=self.padomains[0]
        self.prcnames=[]
        
        for i in range(self.__rffile.read('i')[-1]):
            self.prcnames.append(self.__rffile.read('25s')[-1].strip())
        
        self.data_start_byte=self.__rffile.record_start
        self.record_fmt=self.id_fmt + str(len(self.prcnames)) + self.data_fmt
        self.record_size=self.__rffile.record_size
        self.SDATE,self.STIME,dummy,dummy,dummy,dummy,dummy,dummy=self.__rffile.read(self.id_fmt)
        self.__rffile.previous()
        self.TSTEP=100.
        self.padded_size=self.record_size+8
        domain=self.padomains[0]
        self.records_per_time=self.nspec*(domain['iend']-domain['istart']+1)*(domain['jend']-domain['jstart']+1)*(domain['tlay']-domain['blay']+1)
        self.time_data_block=self.padded_size*self.records_per_time
        self.time_step=100.

    def timerange(self):
        return timerange((self.start_date,self.start_time+self.time_step),timeadd((self.end_date,self.end_time),(0,self.time_step)),self.time_step)
Ejemplo n.º 3
0
class ipr(PseudoNetCDFFile):
    """
    ipr provides a PseudoNetCDF interface for CAMx
    ipr files.  Where possible, the inteface follows
    IOAPI conventions (see www.baronams.com).
    
    ex:
        >>> ipr_path = 'camx_ipr.bin'
        >>> iprfile = ipr(ipr_path)
        >>> iprfile.variables.keys()
        ['TFLAG', 'SPAD_O3', 'DATE_O3', 'TIME_O3', 'SPC_O3', 
         'PAGRID_O3', 'NEST_O3', 'I_O3', 'J_O3', 'K_O3', 
         'INIT_O3', 'CHEM_O3', 'EMIS_O3', 'PTEMIS_O3', 
         'PIG_O3', 'WADV_O3', 'EADV_O3', 'SADV_O3', 'NADV_O3', 
         'BADV_O3', 'TADV_O3', 'DIL_O3', 'WDIF_O3', 'EDIF_O3', 
         'SDIF_O3', 'NDIF_O3', 'BDIF_O3', 'TDIF_O3', 'DDEP_O3', 
         'WDEP_O3', 'INORGACHEM_O3', 'ORGACHEM_O3', 'AQACHEM_O3', 
         'FCONC_O3', 'UCNV_O3', 'AVOL_O3', 'EPAD_O3']
        >>> v = iprfile.variables['CHEM_O3']
        >>> tflag = iprfile.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)
        >>> iprfile.dimensions
        {'TSTEP': 25, 'LAY': 28, 'ROW': 65, 'COL': 83}
    """

    id_fmt = "if10s5i"
    dt_fmt = "if"
    data_fmt = "f"

    def __init__(self, rf, multi=False, **props):
        """
        Initialization included reading the header and learning
        about the format.
        
        see __readheader and __gettimestep() for more info

        Keywords (i.e., props) for projection: P_ALP, P_BET, P_GAM, XCENT, YCENT, XORIG, YORIG, XCELL, YCELL
        """
        self.__rffile = OpenRecordFile(rf)
        self.__readheader()
        self.__ipr_record_type = {
            24:
            dtype(
                dict(names=[
                    'SPAD', 'DATE', 'TIME', 'SPC', 'PAGRID', 'NEST', 'I', 'J',
                    'K', 'INIT', 'CHEM', 'EMIS', 'PTEMIS', 'PIG', 'WADV',
                    'EADV', 'SADV', 'NADV', 'BADV', 'TADV', 'DIL', 'WDIF',
                    'EDIF', 'SDIF', 'NDIF', 'BDIF', 'TDIF', 'DDEP', 'WDEP',
                    'AERCHEM', 'FCONC', 'UCNV', 'AVOL', 'EPAD'
                ],
                     formats=[
                         '>i', '>i', '>f', '>S10', '>i', '>i', '>i', '>i',
                         '>i', '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f',
                         '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f',
                         '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>i'
                     ])),
            26:
            dtype(
                dict(names=[
                    'SPAD', 'DATE', 'TIME', 'SPC', 'PAGRID', 'NEST', 'I', 'J',
                    'K', 'INIT', 'CHEM', 'EMIS', 'PTEMIS', 'PIG', 'WADV',
                    'EADV', 'SADV', 'NADV', 'BADV', 'TADV', 'DIL', 'WDIF',
                    'EDIF', 'SDIF', 'NDIF', 'BDIF', 'TDIF', 'DDEP', 'WDEP',
                    'INORGACHEM', 'ORGACHEM', 'AQACHEM', 'FCONC', 'UCNV',
                    'AVOL', 'EPAD'
                ],
                     formats=[
                         '>i', '>i', '>f', '>S10', '>i', '>i', '>i', '>i',
                         '>i', '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f',
                         '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f',
                         '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f', '>f',
                         '>i'
                     ]))
        }[len(self.prcnames)]

        prcs = [
            'SPAD', 'DATE', 'TIME', 'PAGRID', 'NEST', 'I', 'J', 'K', 'INIT',
            'CHEM', 'EMIS', 'PTEMIS', 'PIG', 'WADV', 'EADV', 'SADV', 'NADV',
            'BADV', 'TADV', 'DIL', 'WDIF', 'EDIF', 'SDIF', 'NDIF', 'BDIF',
            'TDIF', 'DDEP', 'WDEP'
        ] + {
            24: ['AERCHEM'],
            26: ['INORGACHEM', 'ORGACHEM', 'AQACHEM']
        }[len(self.prcnames)] + ['FCONC', 'UCNV', 'AVOL', 'EPAD']
        varkeys = ['_'.join(i) for i in cartesian(prcs, self.spcnames)]
        varkeys += [
            'SPAD', 'DATE', 'TIME', 'PAGRID', 'NEST', 'I', 'J', 'K', 'TFLAG'
        ]
        self.groups = {}
        NSTEPS = len([i_ for i_ in self.timerange()])
        NVARS = len(varkeys)
        self.createDimension('VAR', NVARS)
        self.createDimension('DATE-TIME', 2)
        self.createDimension('TSTEP', NSTEPS)
        padatatype = []
        pavarkeys = []
        for di, domain in enumerate(self.padomains):
            dk = 'PA%02d' % di
            prefix = dk + '_'
            grp = self.groups[dk] = PseudoNetCDFFile()
            pavarkeys.extend([prefix + k for k in varkeys])
            grp.createDimension('VAR', NVARS)
            grp.createDimension('DATE-TIME', 2)
            grp.createDimension('TSTEP', NSTEPS)
            grp.createDimension('COL', domain['iend'] - domain['istart'] + 1)
            grp.createDimension('ROW', domain['jend'] - domain['jstart'] + 1)
            grp.createDimension('LAY', domain['tlay'] - domain['blay'] + 1)
            padatatype.append(
                (dk, self.__ipr_record_type, (len(grp.dimensions['ROW']),
                                              len(grp.dimensions['COL']),
                                              len(grp.dimensions['LAY']))))
            if len(self.padomains) == 1:
                self.createDimension('COL',
                                     domain['iend'] - domain['istart'] + 1)
                self.createDimension('ROW',
                                     domain['jend'] - domain['jstart'] + 1)
                self.createDimension('LAY',
                                     domain['tlay'] - domain['blay'] + 1)
            exec(
                """def varget(k):
                return self._ipr__variables('%s', k)""" % dk, dict(self=self),
                locals())
            if len(self.padomains) == 1:
                self.variables = PseudoNetCDFVariables(varget, varkeys)
            else:
                grp.variables = PseudoNetCDFVariables(varget, varkeys)

        self.__memmaps = memmap(self.__rffile.infile.name, dtype(padatatype),
                                'r', self.data_start_byte).reshape(
                                    NSTEPS, len(self.spcnames))
        for k, v in props.items():
            setattr(self, k, v)
        try:
            add_cf_from_ioapi(self)
        except:
            pass

    def __del__(self):
        try:
            self.__memmaps.close()
            del self.__memmaps
        except:
            pass

    def __decorator(self, name, pncfv):
        spc = name.split('_')[-1]
        prc = name.split('_')[0]
        # IPR units are consistent with 'IPR'
        if prc == 'UCNV':
            units = 'm**3/mol'
        elif prc == 'AVOL':
            units = 'm**3'
        else:
            units = get_uamiv_units('IPR', spc)
        decor = lambda k: dict(
            units=units, var_desc=k.ljust(16), long_name=k.ljust(16))
        for k, v in decor(name).items():
            setattr(pncfv, k, v)
        return pncfv

    def __variables(self, pk, proc_spc):
        if proc_spc in self.__ipr_record_type.names:
            proc = proc_spc
            proc_spc = proc_spc + '_' + self.spcnames[0]
            return PseudoNetCDFVariable(
                self,
                proc_spc,
                'f', ('TSTEP', 'LAY', 'ROW', 'COL'),
                values=self.__memmaps[pk][:, 0, :, :, :][proc].swapaxes(
                    1, 3).swapaxes(2, 3))
        if proc_spc == 'TFLAG':
            thisdate = self.__memmaps[pk][:, 0, :, :, :]['DATE'].swapaxes(
                1, 3).swapaxes(2, 3)[..., 0, 0, 0]
            thistime = self.__memmaps[pk][:, 0, :, :, :]['TIME'].swapaxes(
                1, 3).swapaxes(2, 3)[..., 0, 0, 0]
            return ConvertCAMxTime(thisdate, thistime,
                                   len(self.groups[pk].dimensions['VAR']))
        for k in self.__ipr_record_type.names:
            proc = proc_spc[:len(k)]
            spc = proc_spc[len(k) + 1:]
            if proc == k and spc in self.spcnames:
                spc = self.spcnames.index(spc)
                dvals = self.__memmaps[pk][:, spc][proc].swapaxes(1,
                                                                  3).swapaxes(
                                                                      2, 3)
                return self.__decorator(
                    proc_spc,
                    PseudoNetCDFVariable(self,
                                         proc_spc,
                                         'f', ('TSTEP', 'LAY', 'ROW', 'COL'),
                                         values=dvals))
        raise KeyError("Bad!")

    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.runmessage = self.__rffile.read("80s")
        self.start_date, self.start_time, self.end_date, self.end_time = self.__rffile.read(
            "ifif")

        self.grids = []
        for grid in range(self.__rffile.read("i")[-1]):
            self.grids.append(
                dict(
                    zip(['orgx', 'orgy', 'ncol', 'nrow', 'xsize', 'ysize'],
                        self.__rffile.read("iiiiii"))))

        self.spcnames = []
        for spc in range(self.__rffile.read("i")[-1]):
            self.spcnames.append(self.__rffile.read("10s")[-1].strip())

        self.nspec = len(self.spcnames)
        self.padomains = []

        for padomain in range(self.__rffile.read("i")[-1]):
            self.padomains.append(
                dict(
                    zip([
                        'grid', 'istart', 'iend', 'jstart', 'jend', 'blay',
                        'tlay'
                    ], self.__rffile.read("iiiiiii"))))
        self.activedomain = self.padomains[0]
        self.prcnames = []

        for i in range(self.__rffile.read('i')[-1]):
            self.prcnames.append(self.__rffile.read('25s')[-1].strip())

        self.data_start_byte = self.__rffile.record_start
        self.record_fmt = self.id_fmt + str(len(self.prcnames)) + self.data_fmt
        self.record_size = self.__rffile.record_size
        self.SDATE, self.STIME, dummy, dummy, dummy, dummy, dummy, dummy = self.__rffile.read(
            self.id_fmt)
        self.__rffile.previous()
        self.TSTEP = 100.
        self.padded_size = self.record_size + 8
        domain = self.padomains[0]
        self.records_per_time = self.nspec * (
            domain['iend'] - domain['istart'] +
            1) * (domain['jend'] - domain['jstart'] + 1) * (domain['tlay'] -
                                                            domain['blay'] + 1)
        self.time_data_block = self.padded_size * self.records_per_time
        self.time_step = 100.

    def timerange(self):
        return timerange((self.start_date, self.start_time + self.time_step),
                         timeadd((self.end_date, self.end_time),
                                 (0, self.time_step)), self.time_step)
Ejemplo n.º 4
0
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)])