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

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

New featurefilemap pattern onetomany, tested on DDC data

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