source: TI02-CSML/trunk/csml/csmllibs/csmldataiface.py @ 2081

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI02-CSML/trunk/csml/csmllibs/csmldataiface.py@2081
Revision 2081, 14.9 KB checked in by domlowe, 12 years ago (diff)

subsetting seems to be working, but needs more testing and tidying of code

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/usr/bin/env python
2
3#**************************************************************************************
4#csmldataIface.py
5#contains classes for interfacing with various files
6#currently supports cdunif (NetCDF, PP, Grib(untested)) And Nappy (NASAAmes)
7#use by instantiating the factory class: DataInterface
8#v0.00 30th November 2005
9#Dominic Lowe, BADC
10#**************************************************************************************
11
12
13import cdms 
14try:
15    import nappy 
16except ImportError:
17    print 'could not import NASAAmes interface'
18import string
19import sys
20import csml.csmllibs.csmltime
21# This is required to prevent Numeric arrays being truncated when printed.
22import MA
23MA.set_print_limit(0)
24
25
26class DataInterface(object):
27        #Use DataInterface and setInterfaceType to instantiate the correct
28        #subclass for data
29        def __init__(self):
30                self.iface ='None'
31               
32        def setInterfaceType(self,interfaceType):
33                # function returns approprate data interface
34                #set interfaceType: should correspond to available datainterface subclasses
35                self.iface =interfaceType
36                if self.iface == 'nappy':
37                        return NappyInterface()
38                elif self.iface == 'cdunif':
39                        return cdunifInterface()
40               
41               
42        def getUnknownInterfaceType(self, filename):
43                #if the interface type is not known at the time of instantiation, then use
44                #this function to examine the file and return the correct interface (if it exists).
45                fileExtension = str(filename)[-3:]
46                print 'fe: %s'%fileExtension
47                if fileExtension == '.nc':
48                        return cdunifInterface()
49                if fileExtension == '.qxf':
50                        return cdunifInterface()
51                elif fileExtension == '.pp':
52                        return cdunifInterface()
53                elif fileExtension == 'ctl':
54                        return cdunifInterface()
55                elif fileExtension == 'xml':
56                        return cdmlInterface()
57                else:
58                        try:
59                                nappy.readFFI(filename) in [1001,1010,1020,2010,2110,2160,2310,3010,4010]
60                                return NappyInterface()
61                        except:
62                                print "Could not establish file type"
63                                print "See csmldataiface.py"
64                       
65       
66                                                       
67class AbstractDI(object):               
68        #Abstract data interface class
69        #does nothing, but contains templates for methods required for a data interface class
70        #individual interfaces (e.g NappyInterface) should override these methods
71
72        def __init__(self):
73                self.extractType=''
74                self.extractPrefix = ''
75                                       
76        def openFile(self, filename):
77           #opens file, must be overwritten by subclass
78            raise NotImplementedError 
79               
80        def closeFile(self):
81           #closes file, probably needs to be overwritten by subclass
82            try:
83                self.file.close()
84            except:
85                raise NotImplementedError
86         
87        def setAxis(self,axis):
88           #'set' the name of the current axis , must be overwritten by subclass
89           #this may just involve a stub (see NASAAmes interface) or may involve
90           #calling a real set method of the underlying api (see cdunif Interface)
91           raise NotImplementedError 
92                       
93        def getDataForAxis(self):
94            #return all data for axis, must be overwritten by subclass
95           raise NotImplementedError   
96       
97        def setVariable(self,varname):
98             #As for setAxis, 'set' the name of the current axis , must be overwritten by subclass
99             raise NotImplementedError
100       
101        def getDataForVar(self):
102            #return all data for variable, must be overwritten by subclass
103           raise NotImplementedError   
104       
105        def getSubsetOfDataForVar(self,**kwargs):
106            #return subset of data for variable, must be overwritten by subclass
107            raise NotImplementedError
108       
109       
110class NappyInterface(AbstractDI):       
111        # Data Interface for Nappy (NASA Ames Processing in Python)
112   
113        def __init__(self):
114                self.extractType='NASAAmesExtract'
115                self.extractPrefix = '_naextract_'
116                                         
117        def openFile(self, filename):
118                #print 'opening NA file: ' + str(filename)
119                self.file=nappy.openNAFile(filename)
120                #print 'reading data....'
121                #self.file.readData()
122                #print 'nappyopen ' + filename
123
124        def getListOfAxes(self):
125                axes=self.file.XNAME
126                #print 'before units stripped' + str(axes)
127                axes=self.stripunits(axes)
128                #print 'after units stripped' + str(axes)
129                return axes
130
131        def setAxis(self,axis):
132                axes = self.getListOfAxes()
133                self.axisstub=axes.index(axis)
134
135        def getAxisAttribute(self, att):
136                        #need to do something here...? maybe
137                pass
138                return attValue
139
140        def getTimeUnits(self):
141                axes = self.getListOfAxes()
142                for axis in axes:
143                        if string.find(string.upper(axis),'SECONDS SINCE') != -1:
144                                #found possible time axis.
145                                if axis[-3:]=='UTC':
146                                    units =string.lower(axis[:-4]) #hack!
147                                    units=units.replace('/','-') #try and clean it up
148                                else:
149                                    units=string.lower(axis)
150                                break
151                        elif string.find(string.upper(axis),'HOURS SINCE') != -1:
152                                #found possible time axis.
153                                units =(str(axis))
154                                break
155                        elif string.find(string.upper(axis),'DAYS SINCE') != -1:
156                                #found possible time axis.
157                                units =(str(axis))
158                                break
159                       
160                #revisit with udunits python library?
161                return units
162
163
164        def getDataForAxis(self):
165
166                if self.file.X == None:
167                        #print 'reading data....'
168                        self.file.readData()
169
170                if type(self.file.X[1])==list:
171                #if len(self.file.X) > 0:
172                        data = self.file.X[self.axisstub]
173                else:
174                        data =self.file.X
175                return data
176
177        def getSizeOfAxis(self,axis):
178
179                #check this function is okay
180                #is time always the first dimension in NA??
181                axes = self.getListOfAxes()
182                axisPosition=axes.index(axis)
183                #print "axis position" + str( axisPosition)
184                #print "NX" + str(self.file.NX)
185                try :
186                        axisSize=self.file.NX[axisPosition-1]
187                except:
188                        axisSize ='Unknown axis size'
189                return axisSize
190
191        def getListofVariables(self):
192                variableList=self.stripunits(self.file.VNAME)
193                return variableList
194
195        def setVariable(self,varname):
196                vlist=self.getListofVariables()
197                self.varstub=vlist.index(varname)
198
199        def getVariableAxes(self):
200                #hmm, now with Nasa Ames the Axis will be the same for all variables.
201                #so just use the getListOfAxes function again
202                #I think... check this!
203                varAxesList=self.getListOfAxes()
204                return varAxesList
205
206        def getVariableAttribute(self,attName):
207                if attName =='units':
208                        #strip the units (attribute) from the variable
209                        unitslist=self.getUnits(self.file.VNAME)
210                        attribValue = unitslist[self.varstub]
211                        try:
212                                attribValue = unitslist[self.varstub]
213                        except:
214                                attribValue = 'unknown'
215                else:
216                        attribValue = 'unknown'
217                return attribValue
218
219        def getDataForVar(self):
220            #NOTE TO SELF:
221            #Review this function (and in fact all of nasa ames data interface...)
222                if self.file.V == None:
223                        #print 'reading data....'
224                        self.file.readData()
225
226                try:
227                    if type(self.file.V[1])==list:
228                        data = self.file.V[self.varstub]
229                #else:
230                #       data =self.file.X
231                #       print data
232                    return data
233                except:
234                    data = self.file.X
235                   # print data
236                    return data
237
238        def getArraySizeOfVar(self):
239        #iterates through all dimensions in variable to get array size i.e a 3x3x3 array would have a size of 27
240
241                dimlist=self.file.NX
242                varsize =1
243                for item in dimlist:
244                        varsize = varsize * item
245                        #print "VARSISZE" + str(varsize)
246                return varsize
247
248        def getShapeOfVar(self):
249            #this should return a list.
250            varShape = []
251            for item in self.file.NX:
252                varShape.append(item)
253            return varShape
254
255        def getLowLimits(self):
256                lowlims = ""
257                for i in range (0, len(self.file.NX)):
258                        #for now, assume low limit is always of form 1 1 1 ..
259                        lowlims =lowlims + str(1)  +' '
260                return lowlims
261
262        def getHighLimits(self):
263                highlims = ""
264                for i in range (0, len(self.file.NX)):
265                        dimValue = self.file.NX[i]
266                        highlims =highlims  + str(dimValue) +' '
267                return highlims
268
269
270        def stripunits(self,listtostrip):
271                #strips units of measure from list
272                #eg ['Universal time (hours)', 'Altitude (km)', 'Latitude (degrees)', 'Longitude (degrees)']
273                #becomes ['Universal time', 'Altitude', 'Latitude', 'Longitude']
274                cleanlist = []
275                for item in listtostrip:
276                        openbracket=string.find(item,'(')
277                        if openbracket != -1:
278                                #if brackets exist, strip units.
279                                item=item[:openbracket-1]
280                        cleanlist.append(item)
281                return cleanlist
282
283        def getUnits(self,listwithunits):
284                #gets units from list
285                #eg ['Universal time (hours)', 'Altitude (km)', 'Latitude (degrees)', 'Longitude (degrees)']
286                #becomes ['hours', 'km', 'degrees', 'degrees']
287                unitlist=[]
288                for item in listwithunits:
289                        openbracket=string.find(item,'(')
290                        item = item[openbracket+1:-1]
291                        unitlist.append(item)
292                return unitlist
293
294        def getTimes(self):
295                #This function attempts to determine the time axis and read the time data
296                #it may well not manage it.
297                axes = self.getListOfAxes()
298                for axis in axes:
299                        if string.find(string.upper(axis),'TIME') != -1:
300                                #found possible time axis.
301                                self.setAxis(axis)
302                                times=self.getDataForAxis()
303                                break
304                        elif string.find(string.upper(axis),'SECONDS SINCE') != -1:
305                                #found possible time axis.
306                                self.setAxis(axis)
307                                times=self.getDataForAxis()
308                                break
309                        elif string.find(string.upper(axis),'HOURS SINCE') != -1:
310                                #found possible time axis.
311                                self.setAxis(axis)
312                                times=self.getDataForAxis()
313                                break
314                        elif string.find(string.upper(axis),'DAYS SINCE') != -1:
315                                #found possible time axis.
316                                self.setAxis(axis)
317                                times=self.getDataForAxis()
318                                break
319                return times
320
321
322
323class cdunifInterface(AbstractDI):
324    #Data Interface for cdunif (netcdf & pp formats & grib (not tested with grib)
325
326    def __init__(self):
327        #these are just temporary values until we can determine whether the
328        #file is netcdf pp or grib
329        self.extractType='cdunifExtract'
330        self.extractPrefix = '_cdunifextract_'
331
332    def openFile(self, filename):
333        self.file=cdms.open(filename)
334        #print 'cdunifopen ' + filename
335
336        #now we have the file name can properly determine extractType/Prefix
337        fileExtension = str(filename)[-3:]
338        if fileExtension == '.nc':
339            self.extractType = 'NetCDFExtract'
340            self.extractPrefix = '_ncextract_'
341        elif fileExtension == '.qxf':
342            self.extractType = 'NetCDFExtract'
343            self.extractPrefix = '_ncextract_'
344        elif fileExtension == '.pp':
345            self.extractType  = 'PPExtract'
346            self.extractPrefix = '_ppextract_'
347        elif fileExtension == 'ctl':
348            self.extractType = 'GRIBExtract'
349            self.extractPrefix = '_gribextract_'
350        elif fileExtension == 'xml': 
351            self.extractType = 'NetCDFExtract'  #okay this isn't true, but ok for testing
352            self.extractPrefix = '_ncextract__' 
353    def getListOfAxes(self):
354        axes=self.file.dimensions.keys()
355        return axes
356
357    def getSizeOfAxis(self,axis):
358        axisSize=self.file.dimensions[axis]
359        return axisSize
360
361    def getListofVariables(self):
362        variableList=self.file.variables.keys()
363        return variableList
364
365    def setAxis(self,axis):
366        self.axisobj=self.file.getAxis(axis)
367
368    def getAxisAttribute(self, att):
369        attValue=self.axisobj.attributes[att]
370        return attValue
371   
372    def getTimeUnits(self):
373        #this does the same as getAxisAttribute, but is a separate function as different formats handle time differently.
374        return self.getAxisAttribute('units')
375
376    def getDataForAxis(self):
377        data = self.axisobj.getValue()
378        return data
379
380    def setVariable(self,varname):
381        self.varobj=self.file.variables[varname]
382
383    def getVariableAxes(self):
384        varAxesList=self.varobj.getAxisIds()
385        return varAxesList
386
387    def getVariableAttribute(self,attName):
388
389        #atts=self.varobj.getattributes(attName)
390        #print atts
391        if attName == 'long_name':
392            try:
393                attribValue = self.varobj.long_name
394            except:
395                attribValue='no_long_name_found'
396        elif attName == 'units':
397            try:
398                attribValue = self.varobj.units
399            except:
400                attribValue='no_units_found'
401
402        return attribValue
403
404    def getDataForVar(self):
405        data = self.varobj.getValue()
406        return data
407
408    def getSubsetOfDataForVar(self, **kwargs):
409        #takes keyword args defining subset eg
410        #subset=getSubsetOfDataForVar(latitude=(0.,10.0), longitude=(90, 100.0))
411        subset=None
412        lonkey='longitude'
413        if lonkey=='longitude' in kwargs.keys():   #this test needs to be much more robust...!
414            if kwargs[lonkey][0] > kwargs[lonkey][1]:
415                #subsetting greenwich meridian around 0
416                lonMin = kwargs[lonkey][0]
417                lonMax =kwargs[lonkey][1]
418                kwargs[lonkey]=(0.0, lonMax)
419                sel=cdms.selectors.Selector(**kwargs)
420                subset1=self.file(self.varobj.id,sel)
421                kwargs[lonkey]=(lonMin,359.9999)
422                sel=cdms.selectors.Selector(**kwargs)
423                subset2=self.file(self.varobj.id,sel)
424                #concatenate arrays along longitude             
425                longitudeAxis=subset1.getAxisIndex(lonkey)
426                subset = cdms.MV.concatenate([subset1,subset2],axis=longitudeAxis)
427        if type(subset) is not cdms.tvariable.TransientVariable:
428            sel=cdms.selectors.Selector(**kwargs)
429            subset=self.file(self.varobj.id,sel)
430        return subset
431
432    def getArraySizeOfVar(self):
433    #iterates through all dimensions in variable to get array size i.e a 3x3x3 array would have a size of 27
434        var = self.varobj
435        size = var.shape
436        varsize = 1
437        for item in size:
438            varsize = item *varsize
439        return varsize
440
441    def getShapeOfVar(self):
442        varShape = []
443        for item in self.varobj.shape:
444            varShape.append(item)
445        return varShape
446
447    def getLowLimits(self):
448        dimNames = self.varobj.getAxisIds()
449        lowlims = ""
450        for i in range (1, len(dimNames)):
451            #for now, assume low limit is always of form 1 1 1 ..
452            lowlims =lowlims + str(1)  +' '
453        return lowlims
454
455    def getHighLimits(self):
456        dimNames = self.varobj.getAxisIds()
457        highlims = ""
458        for i in range (1, len(dimNames)):
459            dimValue = self.file.dimensions[dimNames[i]]
460            highlims =highlims  + str(dimValue) +' '
461        return highlims
462       
463   
464class cdmlInterface(cdunifInterface):
465    #this is more  or less the cdunif interface but a few methods have been overwritten
466    def __init__(self):
467        #this all needs to be revisited in csml v2.
468        self.extractType='cdmlExtract'
469        self.extractPrefix = '_cdmlextract_'
470       
471    def getListOfAxes(self):
472        axes=self.file.axes.keys() 
473        return axes
474
475    def getSizeOfAxis(self,axis):
476        axisSize=self.file.axes[axis].length
477        return axisSize
Note: See TracBrowser for help on using the repository browser.