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

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

support for fileList and xlink when creating csml

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