source: TI02-CSML/trunk/csml/csmllibs/csmlfeaturetypes.py @ 2105

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

Parser changes -  csml:id for Dataset, TimeSeriesDomain? to TimeSeries?, plus fixing description/id in subsetting 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#csmlfeaturetypes.py
4#For creating CSML featuretypes
5#v0.5 split off 11th November 2005
6#Dominic Lowe, BADC
7#**************************************************************************************
8
9import csml.parser as cp
10import csml.csmllibs
11import sys
12   
13
14class featureBuilder(object):
15    def __init__(self, dataset_element, featureCollection_element, ffmap,fileExtractDictionary, timedim, timestorage,spatialstorage,valuestorage):
16        self.ds_element=dataset_element
17        self.featureCollection = featureCollection_element
18        self.ffmap = ffmap
19        self.fileExtractDictionary = fileExtractDictionary
20        self.timedim = timedim
21        self.timestorage=timestorage
22        self.spatialstorage=spatialstorage
23        self.valuestorage=valuestorage
24               
25        #empty list to hold featureMembers
26        self.fms =[]
27               
28        #at the moment, only one featuretype per CSML Dataset is supported.
29        #get the featuretype of the first representative file in the ffmap object
30        self.featuretype=  self.ffmap.getRepresentativeFiles()[0].getFeatureType()
31       #and create the features
32        print 'determining feature type'
33        print self.featuretype
34        if self.featuretype == 'GridSeries':
35            self.createCSMLGridSeriesFeatures()
36        elif self.featuretype == 'PointSeries':       
37            self.createCSMLPointSeriesFeatures()
38       
39        #after the features have been generated append all featureMembers to the feature collection
40        self.featureCollection.featureMembers=self.fms
41       
42    #Some internal methods that are of use to all feature types:
43    def _getDescriptiveName(self,DI):
44        #given a data interface class with the variable or axis set, try to get a descriptive name
45        #eg. long name
46        try:
47            descName=DI.getVariableAttribute('long_name')
48            descName
49        except AttributeError:
50            descName = "missing name"
51        descName=descName.replace('&','&') #remove ampersands TODO- extend this
52        return descName
53   
54    def _populateListOfFiles(self,repfile):
55        #given a representative file, get list of files: one representative file + all related files
56        listOfFiles=[]
57        repfilename=repfile.getRepresentativeFileName()
58        listOfFiles.append(repfilename)
59        relfiles = repfile.getRelatedFiles()
60        for f in relfiles:
61            fname = f.getRelatedFileName()
62            listOfFiles.append(fname)
63        return repfilename,listOfFiles
64       
65    def _getFilesAndTimes(self):
66        #TODO try and speed up csmllibs.csmltime.getFileTimeList
67        OrderedFileTimeList,self.caltype,self.units = csml.csmllibs.csmltime.getFileTimeList(self.listOfFiles,self.timedim)
68        #build strings to hold times/filenames for current gridseriesfeature
69        self.timeString =''
70        self.filesinDir = ''
71        lastf=''
72        for j in range (0, len(OrderedFileTimeList)):
73            t= OrderedFileTimeList[j][0]
74            f = OrderedFileTimeList[j][1]
75            self.timeString = self.timeString + ' ' + str(t)
76            if f != lastf:
77                self.filesinDir = self.filesinDir + ' ' + f
78                lastf=f
79           
80    def _getCorrectExtractType(self):
81        #returns an empty parser file extract object of the correct type.
82        if self.extractType=='NetCDFExtract':
83            fe = csml.parser.NetCDFExtract()
84        if self.extractType=='NASAAmesExtract':
85            fe = csml.parser.NASAAmesExtract()
86        if self.extractType=='GRIBExtract':
87            fe = csml.parser.GRIBExtract()
88        if self.extractType=='PPExtract':
89            fe = csml.parser.PPExtract()
90        return fe
91       
92   
93   
94    #the following __functions are used by all or most feature types:
95   
96    def __getVarInfo(self, representativeFile):
97        self.repfilename,self.listOfFiles=self._populateListOfFiles(representativeFile)
98        self._getFilesAndTimes()
99        #Open representative file and create feature members:
100        self.DI = csml.csmllibs.csmldataiface.DataInterface()
101        self.DI=self.DI.getUnknownInterfaceType(self.repfilename)
102        self.DI.openFile(self.repfilename)
103        allVarNames=self.DI.getListofVariables()
104        numFeatures=len(allVarNames)
105        return allVarNames, numFeatures
106   
107    def __getGridCoordinatesTable(self,dimNames, crs,axisorder):
108        #referenceableGrid/GridCoordinatesTable
109        gcT=cp.GridCoordinatesTable()
110        ##add an axisName element(s) for  each spatial dimension.
111        #and an ordinate element
112        axes=''
113        for axis in dimNames:
114            axes =axes + ' '+ axis
115        ordinates=[]
116        for dimName in enumerate(dimNames):
117            ord=cp.GridOrdinateDescription()               
118            #map the grid axis to the crs axis
119            #default to empty element
120            ord.coordAxisLabel=cp.csString('')
121            ord.gridAxesSpanned=cp.csString('')
122            for axis in axisorder:
123                if axisorder[axis]==dimName[0]:
124                    ord.coordAxisLabel=cp.csString(axis)
125                    ord.gridAxesSpanned=cp.csString(dimName[1])
126                    break
127            seqRule= cp.SequenceRule()
128            seqRule.CONTENT='Linear'
129            seqRule.axisOrder='+1'  #TO DO. Work this out.
130            ord.sequenceRule=seqRule
131            sptList=cp.SpatialOrTemporalPositionList()
132           
133            if dimName[1]==self.timedim:
134                #this is the time dimension. handle calendaring etc when getting the data.
135                if self.timestorage=='fileextract':
136                    #look up file extract name in dictionary
137                    #(axisid stored in dictionary = current filename + variable name)
138                    axisid=self.repfilename+dimName[1]
139                    sptList.coordinateList=cp.csString('#'+self.fileExtractDictionary[axisid])
140                else:
141                    #store times inline
142                    self.DI.setAxis(dimName[1])
143                    sptList.coordinateList=cp.csString(self.timeString)
144                    sptList.frame='%s:%s'%(self.caltype,self.units)
145            else:  #for all other dimensions, create ordinates
146                if self.spatialstorage=='fileextract':
147                    #look up file extract name in dictionary
148                    #(axisid stored in dictionary = current filename + variable name)
149                    axisid=self.repfilename+dimName[1]
150                    sptList.coordinateList=cp.csString('#'+self.fileExtractDictionary[axisid])
151                else:
152                    #store inline
153                    self.DI.setAxis(dimName[1])
154                    sptList.coordinateList=cp.csString(csml.csmllibs.csmlextra.cleanString(str(self.DI.getDataForAxis())))
155            ord.coordAxisValues=sptList
156            gcT.addChildElem('gridOrdinates',ord)                         
157        return gcT
158   
159   
160    def __getCRS(self,varName,catalogue):
161        self.DI.setVariable(varName)
162        dimNames=self.DI.getVariableAxes() 
163        if len(dimNames) <= 2:
164                #it's an axis or bounds not a feature, try next variable
165            return None, None, None
166        unitlist=[]
167        for dim in dimNames:
168            self.DI.setAxis(dim)
169            units=self.DI.getAxisAttribute('units')  #need to make special case of units in DI layer
170            unitlist.append(units)   
171        crs, axisorder=catalogue.determineCRS(dimNames,unitlist)
172        return crs, axisorder, dimNames
173   
174    def __featureMetadata(self,feature, varName):
175        feature.id=str(varName)
176        desc = self._getDescriptiveName(self.DI)
177        feature.description=csml.parser.csString(desc)
178       
179    def __getGMLRangeset(self,varName):
180        #GML RANGESET
181        rs=csml.parser.RangeSet()
182        self.DI.setVariable(varName)
183        arrSz = self.DI.getArraySizeOfVar()
184        try:
185            strUom = self.DI.getVariableAttribute('units')
186        except AttributeError:
187            # if units attribute doesn't exist:
188            strUom ="dimensionless or units not determined"
189        if self.valuestorage=='inline':
190            #TO DO, store the rangeset inline - use Datablock class???
191            pass
192        else:
193            #store the rangeSet as an aggregatedArray
194            #TODO, need to take this out of the rangeset and use xlink to reference it.
195            aa=cp.AggregatedArray()
196            aa.arraySize=cp.csString(arrSz)
197            aa.uom=cp.csString(strUom)
198            aa.aggType=cp.csString('new') #can it be anything else?
199            aa.aggIndex=cp.csString('1')
200            #FileExtract (fe) element will be NetCDF/GRIB/PPExtract element (As defined earlier in ExtractType)
201            self.extractType= self.DI.extractType
202            fe = self._getCorrectExtractType()
203            varSize=self.DI.getShapeOfVar()
204            varSize=csml.csmllibs.csmlextra.cleanString1(str(varSize))
205            fe.arraySize=cp.csString(varSize)
206            fl=cp.FileList()
207            fl.fileNames=cp.csString(self.filesinDir)
208            fe.fileList=fl
209            fe.variableName=cp.csString(varName)
210            aa.components=[fe]
211            aa.id=csml.csmllibs.csmlextra.getRandomID()
212            if hasattr(self.ds_element, 'storageDescriptor'):
213                self.ds_element.storageDescriptor.descriptors.append(aa)
214            else:
215                sd =csml.parser.CSMLStorageDescriptor()
216                sd.descriptors=aa
217                setattr(self.ds_element, 'storageDescriptor',sd)
218            #rs.aggregatedArray=aa
219            va=csml.parser.ValueArray()
220            vc=csml.parser.ValueComponent()
221            vc.href='#%s'%aa.id
222            vc.arcrole="http://ndg.nerc.ac.uk/xlinkUsage/insert#QuantityList"
223            vc.role="http://ndg.nerc.ac.uk/fileFormat/csmlStorageDescriptor"
224            vc.show='embed'
225            ql=csml.parser.MeasureOrNullList()
226            ql.uom=strUom
227            vc.quantityList=ql
228            va.valueComponent=vc
229            rs.valueArray=va
230        return rs
231   
232   
233    #the following functions are for creation of specific feature types (and call the __functions above)
234    def createCSMLGridSeriesFeatures(self):
235        #This method assumes that the variables (features) are shared across identically structured files
236        #should be supplied with a featurefilemap object (see csmlfiles for FileMapMaker)
237        representativeFiles=self.ffmap.getRepresentativeFiles()
238        cat=csml.csmllibs.csmlcrs.CRSCatalogue()
239        for repfile in representativeFiles:
240            #get the names of all the variables in the files:
241            allVarNames, numFeatures = self.__getVarInfo(repfile)
242            #Create a GridSeriesFeature for each variable:
243            for i in range(0, numFeatures):
244                crs,axisorder, dimNames=self.__getCRS(allVarNames[i], cat)
245                if crs == None:
246                    continue            #try next variable
247                gsFeature=cp.GridSeriesFeature()
248                self.__featureMetadata(gsFeature,allVarNames[i])
249                #VALUE (coverage)
250                gsCoverage=cp.GridSeriesCoverage()
251                gsDomain=cp.GridSeriesDomain()
252                gsDomain.srsName=crs.srsName
253                gsDomain.axisLabels=crs.axisLabels # note this is the xml attribute axisLabels, not the child element (aLabels)
254                gsDomain.srsDimension=crs.srsDimension
255                aLabels=''
256                for dim in dimNames:
257                    aLabels=aLabels + dim + ' '
258                gsDomain.aLabels=cp.csString(aLabels)
259                gcT=self.__getGridCoordinatesTable(dimNames, crs,axisorder)
260                gsDomain.coordTransformTable=gcT
261                gsCoverage.gridSeriesDomain=gsDomain
262               
263                #COVERAGE FUNCTION
264                mr =csml.csmllibs.csmlextra.getMappingRule(len(dimNames))
265                gsCoverage.coverageFunction=cp.csString(mr)
266                rs=self.__getGMLRangeset(allVarNames[i])
267               
268                #RANGESET
269                gsCoverage.rangeSet=rs
270                gsFeature.parameter=csml.parser.Phenomenon(href='http://badc.rl.ac.uk/localparams#%s'%allVarNames[i])
271                gsFeature.value=gsCoverage
272                self.fms.append(gsFeature)
273            self.DI.closeFile()
274    ###End of createCSMLGridSeriesFeatures###
275
276
277
278        #BELOW THIS POINT ALL NEEDS REWRITING
279####################################
280    def createCSMLPointSeriesFeatures(self): 
281
282        representativeFiles=self.ffmap.getRepresentativeFiles()
283        for repfile in representativeFiles:
284            self.repfilename,self.listOfFiles=self._populateListOfFiles(repfile)
285            self._getFilesAndTimes()
286            DI = csml.csmllibs.csmldataiface.DataInterface()
287            DI=DI.getUnknownInterfaceType(self.repfilename)
288            DI.openFile(self.repfilename)
289            allVarNames=DI.getListofVariables()
290            numFeatures=len(allVarNames)       
291            try:
292                DI.setAxis(self.timedim)
293                times=DI.getDataForAxis()
294            except:                     
295                times = DI.getTimes()
296            #Create features:
297            for i in range (0, numFeatures):
298                PointSeriesFeature_element=csml.parser.PointSeriesFeature()
299                if str(allVarNames[i]).upper() in ['ERROR FLAG', 'ERROR']: #might need to extend this list
300                    break
301                PointSeriesFeature_element.id=str(allVarNames[i])
302                desc=self._getDescriptiveName(DI)
303                PointSeriesFeature_element.description=csml.parser.Description(desc)
304                #DOMAIN
305                psDomain=csml.parser.PointSeriesDomain()
306                t=csml.parser.Trajectory()
307                t.srsName='urn:EPSG:geographicCRS:4326' #TO Do
308                t.locations =csml.parser.DirectPositionList(vals='1 1')
309               
310                if self.timestorage =='inline':
311                    tpl =csml.parser.TimePositionList()
312                    tpl.timePositions=self.timeString
313                    tpl.frame='%s:%s'%(self.caltype,self.units)
314                    t.times=tpl
315                else:
316                    # do something to create a single extract for the times (from the representative file).
317                    tpl.timePositions = csml.csmllibs.csmlfileextracts.createSingleExtract(self.extractType, repfilename, self.timedim, len(self.timeString.split())) 
318                    tpl.frame='%s:%s'%(self.caltype,self.units)
319               
320               
321#                 if self.timestorage =='inline':
322#                     t.times=csmllibs.Parser.TimePositionList('#RefSysX',str(times))
323#                 else:
324#                     #todo: depends on the file mapping???
325#                     t.times=csmllibs.Parser.TimePositionList('#RefSysX','blah') #blah = dummy times
326#                 print 'times: ' + str(allVarNames[i])
327#                 print len(times)
328#                 print len(listOfFiles)
329#                 arraySize=len(times) * len(listOfFiles)
330#                 fextract=csmllibs.csmlfileextracts.createSingleExtract(self.extractType,filenames,self.timedim,arraySize)
331#                 tplist = csmllibs.Parser.TimePositionList(timePositions=fextract)
332#                 t.times=tplist                                                                   
333                filenames=csml.csmllibs.csmlextra.cleanString(str(self.listOfFiles))
334                psDomain.domainReference=t
335                #RANGESET
336                DI.setVariable(allVarNames[i])
337                try:
338                    strUom = DI.getVariableAttribute('units')
339                except AttributeError:
340                    #if units attribute doesn't exist:
341                    strUom ="dimensionless or units not determined"
342                try:                   
343                    measuredvalues = DI.getDataForVar()
344                except:
345                    measuredvalues = ' could not get values '
346                rs=csml.parser.RangeSet()
347                if self.valuestorage=='inline':
348                    #encode inline
349                    rs.quantityList=csml.parser.MeasureOrNullList(uom=strUom, val=str(measuredvalues)[1:-1])                         
350                else:
351                    #create a file extract link
352                    arraySize=len(measuredvalues)*len(self.listOfFiles) 
353                    #TODO this needs to be able to handle inline, use VALUESTORAGE to determine which to use:
354                    self.extractType=DI.extractType
355                    fextract=csml.csmllibs.csmlfileextracts.createSingleExtract(self.extractType,filenames,allVarNames[i],arraySize)
356                    qlist = csml.parser.MeasureOrNullList(val=fextract)
357                    rs.quantityList=qlist
358                PointSeriesFeature_element.rangeSet=rs
359                #COVERAGEFUNCTION                           
360                #PARAMETER
361                #need to do parameter and coverageFunction elements
362                PointSeriesFeature_element.domain=psDomain
363                self.fms.append(PointSeriesFeature_element)
364            DI.closeFile()
365       
366
367#This function needs revising in light of a) csml parser and b) new profile feature types
368    def createCSMLProfileFeature(csmldoc, dataset_element, gml_FeatureCollection_element,  ffmap, timedim):
369            representativeFiles=ffmap.getRepresentativeFiles()
370            listOfFiles=[]
371            for repfile in representativeFiles:
372                    repfilename=repfile.getRepresentativeFileName()
373                    listOfFiles.append(repfilename)
374                    relfiles = repfile.getRelatedFiles()
375                    for f in relfiles:
376                            #hopefully there are no related files at the moment!
377                            fname = f.getRelatedFileName()
378                            listOfFiles.append(fname)
379                    #print listOfFiles
380                   
381            for file in listOfFiles:
382                    DI = csmllibs.csmldataiface.DataInterface()
383                    DI=DI.getUnknownInterfaceType(file)
384                    print'opening file'
385                    DI.openFile(file)
386                    print 'getting variables'
387                    allVarNames=DI.getListofVariables()
388                    print 'getting feature count'
389                    numFeatures=len(allVarNames)       
390                   
391                    print "FEATURES"
392                    print "***********"
393                    for i in range (0, len(allVarNames)):
394                            print allVarNames[i]
395                           
396                    for i in range (0, numFeatures):
397                            gml_featureMember_element=csmldoc.createElement("gml:featureMember")
398                            ProfileFeature_element=csmldoc.createElement("ProfileFeature")
399                            ProfileFeature_element.setAttribute('gml:id',str(allVarNames[i]))
400                            gml_description_element = csmldoc.createElement("gml:description")
401                            gml_featureMember_element.appendChild(ProfileFeature_element)
402                            #***********************************************************************
403                            #PointSeriesDomain:
404                            #***********************************************************************
405                            ProfileDomain_element=csmldoc.createElement("ProfileDomain")
406                           
407                           
408                            #***********************************************************************
409                            # domainReference element (and sub-elements)               
410                            #***********************************************************************
411                            domainReference_element=csmldoc.createElement("domainReference")
412                            #orientedPosition_element=csmldoc.createElement("OrientedPosition")
413                            #locations_element=csmldoc.createElement("locations")
414                            #times_element=csmldoc.createElement("times")
415                            #trajectory_element.appendChild(locations_element)
416                            #trajectory_element.appendChild(times_element)
417                            #domainReference_element.appendChild(orientedPosition_element)
418                           
419                            #gml_timePositionList_element = csmldoc.createElement("gml:TimePositionList")
420                            #gml_timePositionList_element.appendChild(csmldoc.createTextNode(self.timeString))
421                            #domainReference_element.appendChild(gml_timePositionList_element)
422                            ProfileDomain_element.appendChild(domainReference_element)
423                            #***********************************************************************
424                            domainComplement_element=csmldoc.createElement("domainComplement")
425                            ProfileDomain_element.appendChild(domainComplement_element)
426                           
427                            #***********************************************************************
428                            # gml:rangeSet_element
429                            #***********************************************************************
430                           
431                            gml_rangeSet_element=csmldoc.createElement("gml:rangeSet") 
432                           
433                            #***********************************************************************
434                            # gml:coverageFunction element (and sub-element MappingRule)               
435                            #***********************************************************************
436                            gml_coverageFunction_element=csmldoc.createElement("gml:coverageFunction")
437                            MappingRule_element=csmldoc.createElement("MappingRule")
438                            #MappingRule_element.setAttribute('scanOrder',csmllibs.csmlextra.getMappingRule(len(dimNames)))
439                            MappingRule_element.setAttribute('scanOrder','tba')
440                            gml_coverageFunction_element.appendChild(MappingRule_element)
441                           
442                           
443                            gml_featureMember_element.appendChild(ProfileDomain_element)
444                            gml_featureMember_element.appendChild(gml_rangeSet_element)
445                            gml_featureMember_element.appendChild(gml_coverageFunction_element)
446                            gml_FeatureCollection_element.appendChild(gml_featureMember_element)       
447                           
448            return 
449                           
450       
Note: See TracBrowser for help on using the repository browser.