source: TI02-CSML/trunk/csml/API/ops_GridSeriesFeature.py @ 3267

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

Documenting CSML code - not complete

Line 
1''' ops_GridSeriesFeature  contains operations for GridSeriesFeatures. These methods are attached to GridFeature instances at runtime.'''
2
3import csml.parser
4import csml.csmllibs.csmltime
5import csml.csmllibs.csmldocument
6import csml.API.ops_AbstractFeature
7import csml.API.genSubset
8import csml.csmllibs.netCDFWriter
9import csml.csmllibs.csmlcrs
10import csmlutils
11
12def testmethod(self):
13    ''' testmethod for gridseries feature'''
14    return 'testmethod - gridseries'
15
16def getAllowedSubsettings(self):
17    '''get the allowed operations
18    @return:    list of operations'''
19    return ['subsetToGridSeries', 'subsetToProfileSeries']  #other operations
20
21
22def getBoundingBox(self):
23    ''' get the simple boundingBox '''
24    try:
25        lower1=eval(bbox.boundedBy.lowerCorner.CONTENT.split()[0])
26        lower2=eval(bbox.boundedBy.lowerCorner.CONTENT.split()[1])
27        upper1=eval(bbox.boundedBy.upperCorner.CONTENT.split()[0])
28        upper2=eval(bbox.boundedBy.upperCorner.CONTENT.split()[1])
29        return [lower1,lower2,upper1,upper2]
30    except:
31        return None
32   
33   
34def getDomain(self):
35    ''' get domain of the feature
36    @return:   domain as a dictionary of ordinates {name: [values], ...}'''
37    self.domain={}
38    self.gridnames={}
39    for gridOrd in self.value.gridSeriesDomain.coordTransformTable.gridOrdinates:
40        name=gridOrd.coordAxisLabel.CONTENT
41        self.gridnames[gridOrd.gridAxesSpanned.CONTENT]=name
42        if hasattr(gridOrd.coordAxisValues, 'insertedExtract'):
43            self.domain[name], fill, axisorder, units=gridOrd.coordAxisValues.insertedExtract.getData()
44            #add to cache
45        else:           
46            valList=[]
47            try:
48                vals=gridOrd.coordAxisValues.coordinateList.CONTENT
49                for val in vals.split(): 
50                    valList.append(eval(val))
51            except:
52                vals=gridOrd.coordAxisValues.timePositionList.CONTENT
53                for val in vals.split(): 
54                    valList.append(val)           
55            self.domain[name]=valList   
56    return self.domain
57
58def getNativeCRS(self):
59    ''' get the the coordinate reference system of the domain of the feature
60    return:   a string, the srsName'''
61    return self.value.gridSeriesDomain.srsName
62
63def getUom(self):
64    ''' get the uom of the phenomenon.
65    @return: string - uom attribute'''
66    uom=None
67    try: 
68        uom=self.value.rangeSet.valueArray.valueComponent.quantityList.insertedExtract.uom.CONTENT
69    except AttributeError:
70        uom =None
71    return uom
72   
73def getDomainUnits(self):
74    ''' get the units used in the domain
75    @return:     list of units'''   
76    srsname=self.value.gridSeriesDomain.srsName
77    cat=csml.csmllibs.csmlcrs.CRSCatalogue()
78    crs=cat.getCRS(srsname)
79    return crs.units
80   
81def __getAxis(self, name):
82    '''called by getLongitudeAxis, getTimeAxis and getLatitudeAxis'''   
83    srsname=self.value.gridSeriesDomain.srsName
84    cat=csml.csmllibs.csmlcrs.CRSCatalogue()
85    crs=cat.getCRS(srsname) 
86    axID=None
87    if name == 'lon':
88        axID = crs.lonAxis
89    elif name == 'lat':
90        axID = crs.latAxis
91    elif name == 'time':
92        axID = crs.timeAxis     
93    if axID is not None:
94        return crs.getAxisLabels()[axID]
95    else:
96        return None
97   
98def getLongitudeAxis(self):
99    ''' get the index of the longitude axis'''
100    return self.__getAxis('lon')
101
102def getLatitudeAxis(self):
103    ''' get the index of the latitude axis'''
104    return self.__getAxis('lat')
105
106def getTimeAxis(self):
107    ''' get the index of the time axis'''
108    return self.__getAxis('time')
109
110def getAxisLabels(self):
111    '''get the names of the axes'''
112    labels=[]
113    for label in self.value.gridSeriesDomain.axisLabels.split():
114        labels.append(label)
115    return labels
116
117def _subsetGrid(self, **kwargs):
118    '''this takes a selection from a gridseries object (be it a profile, a grid, whatever, it is still just a selection).  It is called internally  by the subsetToGridSeries method.
119    @return: a load of things which can then be used to rebuild a new csml feature: pathToSubsetNetCDF, crs, frame, timeName, times, strTimes, caltype, axisorder,units, fulldata, fillvalue, kwargs '''
120           
121    #set self.domain:
122    self.getDomain()     
123   
124    #get the CRS from a  the  catalogue
125    cat=csml.csmllibs.csmlcrs.CRSCatalogue()
126    crs=cat.getCRS(self.value.gridSeriesDomain.srsName) 
127   
128    #non-feature specific setup code, mainly handles the time dimension/calendar
129   
130    pathToSubsetNetCDF, kwargs, timeAxis, timeName, caltype, times=csml.API.genSubset.genericSubset(self, self.outputdir, self.ncname, self.domain, kwargs)
131    ##Get names of variables in file and relate them to the subset selection
132    selection={}
133    frame=''
134   
135    for gridOrd in self.value.gridSeriesDomain.coordTransformTable.gridOrdinates:
136        try:
137            selection[gridOrd.gridAxesSpanned.CONTENT]=kwargs[gridOrd.coordAxisLabel.CONTENT]           
138        except KeyError:
139            allValues=tuple(self.domain[gridOrd.coordAxisLabel.CONTENT])
140        if hasattr(gridOrd.coordAxisValues, 'timePositionList'):
141            if hasattr(gridOrd.coordAxisValues, 'frame'):
142                frame=gridOrd.coordAxisValues.frame
143    try:
144        del selection[timeAxis] #NOTE: Haven't resolved the single CRS issue so cannot subset by time within an individual file for now
145    except KeyError:
146        pass
147   
148    #get slice indices
149    selection=self.getSliceIndices(selection)                 #commented out while fixing subsetting
150
151    strTimes, axisorder, units, fulldata, fillvalue =csml.API.genSubset.getTheData(self, selection, times, timeName, timeAxis)
152    return pathToSubsetNetCDF, crs, frame, timeName, times, strTimes, caltype, axisorder,units, fulldata, fillvalue, kwargs
153   
154def subsetToGridSeries(self, outputdir=None, ncname='gridseries.nc',**kwargs):
155    '''Subset a GridSeriesFeature to another smaller  GridSeriesFeature. Performs the subset (note this includes nearest neighbour searching, so may return a different set of kwargs
156    @param outputdir:    name of directory to write data files to
157    @param ncname:     name of netcdf file to write out
158    @param kwargs:      subset selection by axis name.
159    @return:     subsettedFeature (GridSeriesFeature instance)  pathToSubsetNetCDF (filepath), descriptor (array descriptor instance)
160   
161    '''
162    if outputdir is not None:
163        self.outputdir=outputdir
164    elif csml.API.csmlContainer.globalContainer.OUTPUTDIR is not None:
165        self.outputdir=csml.API.csmlContainer.globalContainer.OUTPUTDIR
166    csml.csmllibs.csmlextra.checkDirExists(self.outputdir)
167    self.ncname=ncname
168    pathToSubsetNetCDF, crs, frame, timeName, times, strTimes, caltype, axisorder,units, fulldata, fillvalue, kwargs=self._subsetGrid(**kwargs) 
169    #Okay, got the data now. Need to write CSML feature and NetCDF files.
170    #Writing out the CSML feature   
171   
172    # define domain/coverage  to use in 'value' attribute   
173    newdomain=csml.parser.GridSeriesDomain()
174    domainSubset, totalArraySize=csml.API.genSubset.subsetDomain(timeName,strTimes,self.domain, **kwargs)
175    cTT=csml.API.genSubset.getCoordTransformTable(domainSubset, crs, frame)
176    newdomain.id=csml.csmllibs.csmlextra.getRandomID()
177    newdomain.coordTransformTable=cTT
178    newdomain.srsName=self.value.gridSeriesDomain.srsName 
179    newdomain.axisLabels=self.value.gridSeriesDomain.axisLabels
180    newdomain.srsDimension=self.value.gridSeriesDomain.srsDimension
181    newdomain.dimension=self.value.gridSeriesDomain.dimension
182    env=csml.parser.GridEnvelope()
183    env.low=csml.parser.csString('0 0 0') #TODO
184    env.high=csml.parser.csString('0 0 0')
185    newdomain.limits=env
186    newdomain.aLabels=self.value.gridSeriesDomain.aLabels
187    rs=csml.parser.RangeSet()
188    sdid=csml.csmllibs.csmlextra.getRandomID()
189    descriptor=csml.parser.NetCDFExtract(id=sdid,fileName=csml.parser.csString(self.ncname),variableName=self.name,arraySize=csml.parser.csString(totalArraySize))
190    rs=csml.parser.RangeSet()
191    va=csml.parser.ValueArray()
192    vc=csml.parser.MeasureOrNullList()
193    vc.href='#%s'%sdid
194    vc.arcrole="http://ndg.nerc.ac.uk/xlinkUsage/insert#QuantityList"
195    vc.role="http://ndg.nerc.ac.uk/fileFormat/csmlStorageDescriptor"
196    vc.show='embed'
197    try:
198        vc.uom=self.value.rangeSet.valueArray.valueComponent.uom
199    except:
200        vc.uom = 'unknown'  #TODO,
201    va.valueComponent=vc
202    va.id=csml.csmllibs.csmlextra.getRandomID()
203    rs.valueArray=va
204    #gridseries coverage
205    cvg=csml.parser.GridSeriesCoverage()
206    cvg.id=csml.csmllibs.csmlextra.getRandomID()
207    cvg.rangeSet=rs
208    cvg.gridSeriesDomain=newdomain   
209   
210    #parameter, as before subsetting.
211    param = self.parameter
212       
213    #create a stand alone gridseries feature containing this coverage
214    csmlWrap=csml.csmllibs.csmlfeaturewrap.CSMLWrapper()
215    subsettedFeature=csmlWrap.createGridSeriesFeature(value=cvg,parameter=param,featureID=csml.csmllibs.csmlextra.getRandomID(),name=self.name,description=self.description)
216 
217    ### write netcdf using NCWriter class (wraps cdms) ###
218    nc=csml.csmllibs.netCDFWriter.NCwriter(pathToSubsetNetCDF)
219    ords=cTT.gridOrdinates
220    axislist=[]
221    for a in axisorder:
222        axislist.append(self.gridnames[a])
223    stdname=param.getStandardName()
224    nc.genWriteVar(self.name.CONTENT,ords, times, caltype, axislist, units, stdname, fulldata, fillvalue)
225    nc.closeFinishedFile()
226    print 'NetCDF file written to %s'%pathToSubsetNetCDF
227    return subsettedFeature, pathToSubsetNetCDF, descriptor
228   
229
230def subsetToProfileSeries(self, outputdir=None, ncname='profileseries.nc',**kwargs):
231    '''Subset a GridSeriesFeature to a ProfileSeriesFeature. Performs the subset (note this includes nearest neighbour searching, so may return a different set of kwargs
232    @param outputdir:    name of directory to write data files to
233    @param ncname:     name of netcdf file to write out
234    @param kwargs:      subset selection by axis name.
235    @return:     subsettedFeature (ProfileSeriesFeature instance)  pathToSubsetNetCDF (filepath), descriptor (array descriptor instance)'''
236   
237   
238    #TODO   !!!!!!!!! Need to perform some sort of testing on the kwargs to check it is a profileseries request.
239    if outputdir is not None:
240        self.outputdir=outputdir
241    elif csml.API.csmlContainer.globalContainer.OUTPUTDIR is not None:
242        self.outputdir=csml.API.csmlContainer.globalContainer.OUTPUTDIR
243    csml.csmllibs.csmlextra.checkDirExists(self.outputdir)
244    self.ncname=ncname   
245   
246    #perform the subset (note this included nearest neighbour searching, so may return a different set of kwargs
247    pathToSubsetNetCDF, crs,frame, timeName, times, strTimes, caltype, axisorder,units, fulldata, fillvalue, kwargs=self._subsetGrid(**kwargs) 
248
249    latName=crs.axes[crs.latAxis]
250    lonName=crs.axes[crs.lonAxis]
251    #Okay, got the data now. Need to write CSML feature and NetCDF files.
252    #Writing out the CSML feature
253   
254    # define domain/coverage  to use in 'value' attribute   
255    newdomain=csml.parser.ProfileSeriesDomain()
256   
257   
258    domainSubset, totalArraySize=csml.API.genSubset.subsetDomain(timeName,strTimes,self.domain, **kwargs)
259    cTT=csml.API.genSubset.getCoordTransformTable(domainSubset, crs, frame) 
260   
261    #Need to remove location (lat/lon) axes from the cTT
262    newGridOrds=[]
263    for gridOrd in cTT.gridOrdinates:
264        if gridOrd.coordAxisLabel.CONTENT not in  [latName,lonName]:
265            newGridOrds.append(gridOrd)
266    cTT.gridOrdinates=newGridOrds
267    axes=[]
268    for ord in newGridOrds:
269        axes.append(ord.coordAxisLabel.CONTENT)
270    cat = csml.csmllibs.csmlcrs.CRSCatalogue()
271    crsInfo=cat.determineCRS(knownCRSAxes=axes)   
272    crs=cat.getCRS(crsInfo[0].srsName)
273   
274    newdomain.coordTransformTable=cTT   
275    newdomain.id=csml.csmllibs.csmlextra.getRandomID()
276    #TODO need to remove 'location' from this srs
277    newdomain.srsName=crsInfo[0].srsName
278    axisLabels=csml.csmllibs.csmlextra.stringify(crsInfo[1].keys())
279    newdomain.axisLabels=axisLabels
280    newdomain.srsDimension=2
281    newdomain.dimension=2
282    env=csml.parser.GridEnvelope()
283    env.low=csml.parser.csString('0 0 0') #TODO
284    env.high=csml.parser.csString('0 0 0')
285    newdomain.limits=env
286    newdomain.aLabels=self.value.gridSeriesDomain.aLabels #todo 
287    rangeSet=csml.parser.RangeSet()
288    descid=csml.csmllibs.csmlextra.getRandomID()
289    descriptor=csml.parser.NetCDFExtract(id=descid,fileName=csml.parser.csString(ncname),variableName=self.name,arraySize=csml.parser.csString(totalArraySize))
290    rs=csml.parser.RangeSet()
291    va=csml.parser.ValueArray()
292    vc=csml.parser.MeasureOrNullList()
293    vc.href='#%s'%descid
294    vc.arcrole="http://ndg.nerc.ac.uk/xlinkUsage/insert#QuantityList"
295    vc.role="http://ndg.nerc.ac.uk/fileFormat/csmlStorageDescriptor"
296    vc.show='embed'
297    vc.insertedExtract=descriptor
298    try:
299        vc.uom=self.value.rangeSet.valueArray.valueComponent.uom
300    except:
301        vc.uom = 'unknown'  #TODO,
302   
303    va.valueComponent=vc
304    va.id=csml.csmllibs.csmlextra.getRandomID()
305    rs.valueArray=va
306    #profileseries coverage
307    cvg=csml.parser.ProfileSeriesCoverage()
308    cvg.id=csml.csmllibs.csmlextra.getRandomID()
309    cvg.rangeSet=rs
310    cvg.profileSeriesDomain=newdomain   
311    csmlWrap=csml.csmllibs.csmlfeaturewrap.CSMLWrapper()
312   
313    #parameter, as before subsetting.
314    param = self.parameter
315   
316    #create 'location' attribute:
317    if (latName, lonName) is not (None, None):
318        locStr ='%s %s'%(kwargs[latName], kwargs[lonName])
319        loc=csml.parser.csString(locStr)
320    else:
321        loc = csml.parser.csString('unknown location')
322       
323   
324    #create a stand alone gridseries feature containing this coverage
325    subsettedFeature=csmlWrap.createProfileSeriesFeature(value=cvg,parameter=param, location=loc, featureID=csml.csmllibs.csmlextra.getRandomID(),name=self.name,description=self.description)
326 
327   
328    ### write netcdf using NCWriter class (wraps cdms) ###
329    nc=csml.csmllibs.netCDFWriter.NCwriter(pathToSubsetNetCDF)
330    ords=cTT.gridOrdinates
331    axislist=[]
332       
333    for a in axisorder:
334        axislist.append(self.gridnames[a])
335    stdname=param.getStandardName()
336    nc.genWriteVar(self.name.CONTENT,ords, times, caltype, axislist, units, stdname, fulldata, fillvalue, latitude=kwargs[latName], longitude=kwargs[lonName])
337    nc.closeFinishedFile()
338   
339    return subsettedFeature, pathToSubsetNetCDF, descriptor
340
341def subsetToProfile(self, outputdir = None, ncname='profile.nc',**kwargs):
342    '''Subset a GridSeriesFeature to a ProfileFeature. Performs the subset (note this includes nearest neighbour searching, so may return a different set of kwargs.
343       
344        Is a two step process - subsets GridSeries to ProfileSeries, then ProfileSeries to Profile
345    @param outputdir:    name of directory to write data files to
346    @param ncname:     name of netcdf file to write out
347    @param kwargs:      subset selection by axis name.
348    @return:     subsettedFeature (ProfileFeature instance)  pathToSubsetNetCDF (filepath), descriptor (array descriptor instance)'''
349
350    odir=outputdir
351    profileSeries, pSfile, descriptor=self.subsetToProfileSeries(odir, ncname, **kwargs)   
352    del kwargs['latitude']    #TODO - need to remove excess kwargs based on the domain of the temporary profileSeries feature
353    del kwargs['longitude']
354    subsettedFeature, pathToSubsetNetCDF, descriptor =profileSeries.subsetToProfile(odir,ncname, **kwargs)   
355    return subsettedFeature, pathToSubsetNetCDF, descriptor
356
357def subsetToPointSeries(self, outputdir =None, ncname='pointseries.nc',**kwargs):
358    '''Subset a GridSeriesFeature to a PointSeriesFeature. Performs the subset (note this includes nearest neighbour searching, so may return a different set of kwargs.
359       
360        Is a two step process - subsets GridSeries to ProfileSeries, then ProfileSeries to PointSeries
361    @param outputdir:    name of directory to write data files to
362    @param ncname:     name of netcdf file to write out
363    @param kwargs:      subset selection by axis name.
364    @return:     subsettedFeature (PointSeriesFeature instance)  pathToSubsetNetCDF (filepath), descriptor (array descriptor instance)'''
365   
366    profileSeries, pSfile, descriptor =self.subsetToProfileSeries(outputdir, ncname, **kwargs)   
367    del kwargs['latitude']    #TODO - need to remove excess kwargs based on the domain of the temporary profileSeries feature
368    del kwargs['longitude']
369    subsettedFeature, pathToSubsetNetCDF, descriptor=profileSeries.subsetToPointSeries(outputdir, ncname, **kwargs)   
370    return subsettedFeature, pathToSubsetNetCDF, descriptor
Note: See TracBrowser for help on using the repository browser.