source: TI03-DataExtractor/trunk/pydxs/OutputManager.py @ 1153

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI03-DataExtractor/trunk/pydxs/OutputManager.py@1153
Revision 1153, 16.8 KB checked in by astephen, 14 years ago (diff)

Latest version with javascript select all in the GUI, date/time
javascript checking (needs onsubmit), cleaned up selection by domain.

Line 
1#   Copyright (C) 2004 CCLRC & NERC( Natural Environment Research Council ).
2#   This software may be distributed under the terms of the
3#   Q Public License, version 1.0 or later. http://ndg.nerc.ac.uk/public_docs/QPublic_license.txt
4
5"""
6OutputManager.py
7================
8
9This module holds the OutputManager class used to generate products
10in the Data Extractor.
11
12"""
13
14# Import required modules
15import os
16import re
17import cdms
18import vcs
19import sys
20import time
21
22# Import package modules including global variables
23from common import *
24from serverConfig import *
25from localRules import *
26from NumericalOperations import *
27from DXDMLHandler import *
28from CDMSDataHandler import *
29from CDMSOutputHandler import *
30from CSMLDataHandler import *
31from CSMLOutputHandler import *
32from DatasetFormatDecider import *
33from FileNames import *
34from DXErrors import *
35
36# Make sure CDMS automatic bounds generation is set to OFF
37#cdms.setAutoBounds("off")
38
39#global ONE_FILE_PER_TIMESTEP   
40#ONE_FILE_PER_TIMESTEP=0
41
42
43class OutputManager:
44    """
45    Class to control generation of output variables as selected.
46    Externally called as:
47   
48    x=OutputManager(request)
49    x.getOutputFilePaths()
50    x.createOutputs()
51    """
52
53    def __init__(self, sessionObject):
54        """
55        Takes in request object and sets up processing.
56        """
57        self.bag=sessionObject
58        self.outputDir=checkSubDirectory(self.bag["username"]) 
59        self.DXDML=DXDMLHandler()
60        self.varDict={}
61                       
62
63    def _getDatasetDetails(self, varCodes):
64        """
65        Returns the datasetURI for a given variable code.
66        """
67        match=re.match("variable_(\d+)\.(\d+)\.(\d+)", varCodes)
68        if not match:
69            raise DXProcessingError, "Cannot match variable code: "+varCodes
70
71        (dsgCode, dsCode, varCode)=intAll(match.groups())
72        dsURICodes="%s.%s" % (dsgCode, dsCode)
73       
74        dsg=self.bag["datasetGroup_%s" % dsgCode]
75        ds=self.bag["dataset_%s.%s" % (dsgCode, dsCode)]       
76       
77        if self.bag.has_key("datasetURI_%s" % dsURICodes):
78            datasetURI=self.bag["datasetURI_%s" % dsURICodes]
79        else:
80            datasetURI=self.DXDML.getDatasetURI(dsg, ds)
81         
82        return (dsg, ds, datasetURI)
83
84
85    def getOutputInfoDict(self):
86        """
87        Returns output file dictionary including output paths, sizes
88        and estimated duration for producing the output.
89        """
90        if self.varDict!={}:
91            return self.varDict
92        if self.bag.has_key("numericalOperation"):
93            self._handleNumericalOperation(mode="file names")
94        else:
95            self._loopThroughVariables(mode="file names")
96        return self.varDict
97       
98
99    def getOutputFilePathDict(self):
100        """
101        Returns a dictionary of output files with variable IDs as keys.
102        """
103        dct=self.getOutputInfoDict()
104        pathdict={}
105        for key in dct.keys():
106            varID=dct[key][1]
107            paths=dct[key][4]
108            pathdict[varID]=paths
109        return pathdict
110
111
112    def getOutputSizes(self):
113        """
114        Returns a dictionary of the sizes of output variables with IDs as keys.
115        """
116        dct=self.getOutputInfoDict()
117        sizedict={}
118        for key in dct.keys():
119            varID=dct[key][1]
120            size=dct[key][2]
121            sizedict[varID]=size
122        return sizedict
123       
124
125    def getOutputDurationEstimates(self):
126        """
127        Returns a dictionary of the estimated durations to produce the requested
128        outputs, with variable IDs as keys.
129        """
130        dct=self.getOutputInfoDict()
131        durationdict={}
132        for key in dct.keys():
133            varID=dct[key][1]
134            size=dct[key][2]
135            format=dct[key][3]
136            multiplier=1
137            if format=="NASA Ames":
138                multiplier=3
139            durationdict[varID]=size*TIMING_SCALE_FACTOR*multiplier
140        return durationdict
141
142
143    def createOutputs(self):
144        """
145        Calls the appropriate methods to create output files.
146        """
147        if self.bag.has_key("numericalOperation"):
148            self._handleNumericalOperation(mode="create outputs")
149        else:
150            self._loopThroughVariables(mode="create outputs")
151
152
153    def _adjustFileSizeByFormat(self, size, outputFormat):
154        """
155        Returns the size of an output file adjusted according to the format used.
156        """
157        if outputFormat=="NASA Ames":   
158            size=size*5 
159        return size
160
161           
162    def _loopThroughVariables(self, mode):
163        """
164        Loop through the selected variables to generate the output
165        file paths or data.
166        """
167        varKeys=getSortedKeysLike(self.bag, "variable_")
168        self.varDict={}
169
170        varCount=0
171        for varKey in varKeys:
172            varCodes=varKey.split("_")[-1]
173            varID=self.bag[varKey]
174           
175            (datasetGroup, dataset, datasetURI)=self._getDatasetDetails(varKey)
176
177            dataFileHandler=DatasetFormatDecider(datasetGroup, dataset, datasetURI).datasetFormat
178            outputFormat=self.bag["outputFormat_%s" % varCodes]
179            #print dataFileHandler
180           
181            axisSelectionDict=getDictSubsetMatching(self.bag, "axis_%s" % varCodes)
182
183            timeStepStringList=dataFileHandler.getSelectedTimeSteps(datasetURI, varID, axisSelectionDict)
184           
185            sizeOfRequest=dataFileHandler.getSelectedVariableSubsetSize(datasetURI, varID, axisSelectionDict)
186            sizeOfRequest=self._adjustFileSizeByFormat(sizeOfRequest, outputFormat)
187           
188                   
189            if sizeOfRequest>(MAX_FILE_SIZE*(2**20)) or ONE_FILE_PER_TIMESTEP==1:
190                   
191                print "\n\n\n", (MAX_FILE_SIZE*(2**20)), sizeOfRequest, ONE_FILE_PER_TIMESTEP
192                if mode=="file names":
193                    fileNamer=FileNames(datasetGroup=datasetGroup, dataset=dataset, timeSteps=timeStepStringList, 
194                                    fileFormat=outputFormat, variables=[varID],
195                                    basedir=self.outputDir)
196                    outputFilePathList=fileNamer.createFileNameList()
197               
198                elif mode=="create outputs":
199                    # Now get the real data
200                    outputHandler=self._getOutputHandler(outputFormat, dataFileHandler)
201                   
202                    outputFilePathList=[]
203                    for timeStep in timeStepStringList:
204                        fileNamer=FileNames(datasetGroup=datasetGroup, dataset=dataset, timeSteps=[timeStep], 
205                                    fileFormat=outputFormat, variables=[varID],
206                                    basedir=self.outputDir)
207                        outputFilePath=fileNamer.createFileNameList()[0]
208                        outputFilePathList.append(outputFilePath)
209                                               
210                        data=dataFileHandler.readVariableSubsetIntoMemory(datasetURI, varID, axisSelectionDict, timeStep)
211                       
212                        outputFileHandler=outputHandler(outputFilePath)
213                        globalAttributes=dataFileHandler.getCFGlobalAttributes(datasetURI)
214                        outputFileHandler.writeVariableAndGlobalAttributes(data, globalAttributes)
215                        outputFileHandler.closeFile()
216                        print "\nWrote variable '%s' to output file: %s" % (varID, outputFilePath)             
217                       
218            else:
219                if len(timeStepStringList)==0:
220                    timeStepStringList=[]
221                elif len(timeStepStringList)==1:
222                    timeStepStringList=timeStepStringList
223                else:
224                    timeStepStringList=["%s-%s" % (timeStepStringList[0], timeStepStringList[-1])]
225                           
226                print "Work out file name as only one file..."
227                fileNamer=FileNames(datasetGroup=datasetGroup, dataset=dataset, timeSteps=timeStepStringList, 
228                                    fileFormat=outputFormat, variables=[varID],
229                                    basedir=self.outputDir)
230                outputFilePathList=fileNamer.createFileNameList()       
231               
232                if mode=="create outputs":
233                    # Now get the real data
234                    outputHandler=self._getOutputHandler(outputFormat, dataFileHandler)         
235                    outputFilePath=outputFilePathList[0]
236                   
237                    if isinstance(dataFileHandler, CSMLDataHandler):
238                        # CSML needs subsetting in one go
239                        ncPath=outputFilePath
240                        csmlPath=os.path.splitext(ncPath)[0]+".xml"
241                        outputFilePathList.insert(0, csmlPath)
242                        dataFileHandler.subsetVariableToCSMLNC(datasetURI, varID, axisSelectionDict, csmlPath, ncPath)
243                        print "\nWrote variable '%s' to output files: %s, %s" % (varID, csmlPath, ncPath)
244                    else:
245                        data=dataFileHandler.readVariableSubsetIntoMemory(datasetURI, varID, axisSelectionDict)
246                       
247                        outputFileHandler=outputHandler(outputFilePath)
248                        globalAttributes=dataFileHandler.getCFGlobalAttributes(datasetURI)
249                        outputFileHandler.writeVariableAndGlobalAttributes(data, globalAttributes)
250                        outputFileHandler.closeFile()
251                        print "\nWrote variable '%s' to output file: %s" % (varID, outputFilePath)                 
252                   
253   
254            self.varDict[varCount]=(datasetURI, varID, sizeOfRequest, outputFormat, outputFilePathList[:])
255            varCount=varCount+1
256
257
258    def _getOutputHandler(self, outputFormat, dataHandler):
259        """
260        Get output handler.
261        """
262        if outputFormat not in OUTPUT_FORMATS:
263            raise DXOptionHandlingError, "Output format '%s' is not supported." % outputFormat
264           
265        if isinstance(dataHandler, CDMSDataHandler):
266            if outputFormat=="NetCDF":     
267                outputHandler=CDMSOutputHandler
268            elif outputFormat=="NASA Ames":
269                outputHandler==NASAAmesOutputHandler
270        elif isinstance(dataHandler, CSMLDataHandler):
271            outputHandler=CSMLOutputHandler
272           
273        return outputHandler
274       
275
276    def _handleNumericalOperation(self, mode):
277        """
278        If a numerical operation is defined then don't loop through
279        variables, only output one calculated variable to keep simple.
280        """
281        print "Performing a numerical operation, only one output variable is supported when this option is selected...\n\n"
282        opController=NumericalOperations(self.bag["numericalOperation"])
283        usedVariableIndices=opController.variableIndices
284        opMethod=opController.opMethod.__name__
285       
286        varKeys=getSortedKeysLike(self.bag, "variable_")
287       
288        usedVars=[]
289        indx=0
290        for var in varKeys:
291            if indx in usedVariableIndices:
292                usedVars.append(var)
293               
294        self.varDict={}
295        varGrids=[]
296        arrayShapes=[]
297        arraySizes=[]
298        fileVarSelectorList=[]
299
300        outputFilePathList=None
301        for varKey in usedVars:
302            varCodes=varKey.split("_")[-1]
303            varID=self.bag[varKey]
304           
305            (datasetGroup, dataset, datasetURI)=self._getDatasetDetails(varKey)
306            dataFileHandler=DatasetFormatDecider(datasetGroup, dataset, datasetURI).datasetFormat
307            outputFormat=self.bag["outputFormat_%s" % varCodes]
308           
309            if outputFilePathList==None: 
310                outputFileName="%s_%s.%s" % (opMethod, os.getpid(), mapFileFormatToExtension(outputFormat))         
311                outputFilePathList=[os.path.join(self.outputDir, outputFileName)]
312           
313            if not isinstance(dataFileHandler, CDMSDataHandler):
314                raise DXOptionHandlingError, """The DX can currently only perform numerical operations on CDMS-type variables.
315                    You have selected a non-CDMS variable: '%s'.""" % (varID)
316           
317            axisSelectionDict=getDictSubsetMatching(self.bag, "axis_%s" % varCodes)
318            fileVarSelectorList.append([datasetURI, varID, axisSelectionDict])
319
320            (arrayShape, gridShape, size)=dataFileHandler.getSelectedVariableArrayDetails(datasetURI, varID, axisSelectionDict)
321            #print gridShape, arrayShape
322            varGrids.append(gridShape)
323            arrayShapes.append(arrayShape)
324            arraySizes.append(size)
325
326        print "Now compare grid shapes of variables..."
327        lenGrids=len(varGrids)
328        noneList=lenGrids*[None]
329
330        if noneList==varGrids:
331            gridsPresent="no"
332        elif None in varGrids:
333            raise DXOptionHandlingError, "Variable axes are different and cannot therefore be used in a mathematical operation."
334        else:
335            gridsPresent="yes"
336
337        refshape=arrayShapes[0]
338        for shape in arrayShapes[1:]:
339   
340            if len(shape)!=len(refshape):
341                raise DXOptionHandlingError, "Shapes of chosen variables are incompatible for mathematical operation."
342            if gridsPresent=="no":
343                if shape!=refshape:
344                    raise DXOptionHandlingError, "Axis lengths of chosen variables are different and cannot therefore be used in a mathematical operation."
345                elif gridsPresent=="yes":
346                    if shape[:-2]!=refshape[:-2]:
347                        raise DXOptionHandlingError, "Axis lengths of chosen variables are different and cannot therefore be used in a mathematical operation."
348
349        outputSize=arraySizes[0]
350        for sz in arraySizes[1:]:
351            if sz<outputSize:
352                outputSize=sz
353
354        if mode=="create outputs":
355            varsToUse=[]
356            print "Fetch each var from file..."
357            for (datasetURI, varID, axisSelectionDict) in fileVarSelectorList:
358                varsToUse.append(dataFileHandler.readVariableSubsetIntoMemory(datasetURI, varID, axisSelectionDict))
359               
360            data=opController.performOperation(varsToUse)
361           
362            # Now write the data
363            outputHandler=self._getOutputHandler(outputFormat, dataFileHandler) 
364            outputFilePath=outputFilePathList[0]               
365            outputFileHandler=outputHandler(outputFilePath)
366            outputFileHandler.writeVariableAndGlobalAttributes(data, {})
367            outputFileHandler.closeFile()
368           
369            print "\nWrote variable '%s' to output file: %s" % (data.id, outputFilePath)                   
370           
371
372        outputVarID=opMethod
373        self.varDict[0]=(datasetURI, outputVarID, outputSize, outputFormat, outputFilePathList[:])
374
375
376           
377                   
378   
379
380if __name__=="__main__":
381    #print "Setting ONE_FILE_PER_TIMESTEP=1"
382 
383    #ONE_FILE_PER_TIMESTEP=1
384    x=OutputManager({"username":"jane", "datasetGroup_1":"Test Data Group 1",
385                     "dataset_1.3":"Test Dataset 1", "variable_1.3.1":"pqn",
386                     "outputFormat_1.3.1":"NetCDF"})
387    print x.getOutputFilePathDict()   
388                 
389    x=OutputManager({"username":"jane", "datasetGroup_1":"Test Data Group 1",
390                     "dataset_1.3":"Test Dataset 1", "variable_1.3.1":"pqn",
391                     "axis_1.3.1.1":("1999-01-01T00:00:00", "1999-01-01T06:00:00"),
392                     "outputFormat_1.3.1":"NetCDF",
393                     "datasetGroup_2":"Test Data Group 2",
394                     "dataset_2.1":"Test Dataset 2", "variable_2.1.1":"var2",
395                     "axis_2.1.1.1":("2004-01-01T12:00:00", "2004-01-01T12:00:00"),
396                     "outputFormat_2.1.1":"NetCDF"})
397
398    print x.getOutputFilePathDict()   
399   
400    print "\n\n\n"
401    x=OutputManager({"username":"jane", "datasetGroup_1":"Test Data Group 1",
402                     "dataset_1.3":"Test Dataset 1", "variable_1.3.1":"pqn",
403                     "axis_1.3.1.1":("1999-01-01T00:00:00", "1999-01-01T06:00:00"),
404                     "outputFormat_1.3.1":"NetCDF",
405                     "datasetGroup_2":"Test Data Group 2",
406                     "dataset_2.1":"Test Dataset 2", "variable_2.1.1":"var2",
407                     "axis_2.1.1.1":("2004-01-01T12:00:00", "2004-01-01T12:00:00"),
408                     "axis_2.1.1.2":(30,-30),
409                     "outputFormat_2.1.1":"NetCDF"})
410
411    x.createOutputs()       
412   
413    print "Setting ONE_FILE_PER_TIMESTEP=0"
414    ONE_FILE_PER_TIMESTEP=0
415    x=OutputManager({"username":"jane", "datasetGroup_1":"Test Data Group 1",
416                     "dataset_1.3":"Test Dataset 1", "variable_1.3.1":"pqn",
417                     "axis_1.3.1.1":("1999-01-01T00:00:00", "1999-01-01T06:00:00"),
418                     "outputFormat_1.3.1":"NetCDF",
419                     "datasetGroup_2":"Test Data Group 2",
420                     "dataset_2.1":"Test Dataset 2", "variable_2.1.1":"var2",
421                     "axis_2.1.1.1":("2004-01-01T12:00:00", "2004-01-01T12:00:00"),
422                     "axis_2.1.1.2":(30,-30),
423                     "outputFormat_2.1.1":"NetCDF"})
424    print x.getOutputFilePathDict()       
425   
426    x=OutputManager({"username":"jane", "datasetGroup_1":"Test Data Group 1",
427                     "dataset_1.3":"Test Dataset 1", "variable_1.3.1":"pqn",
428                     "axis_1.3.1.1":("1999-01-01T00:00:00", "1999-01-01T06:00:00"),
429                     "outputFormat_1.3.1":"NetCDF",
430                     "datasetGroup_2":"Test Data Group 2",
431                     "dataset_2.1":"Test Dataset 2", "variable_2.1.1":"var2",
432                     "axis_2.1.1.1":("2004-01-01T12:00:00", "2004-01-01T12:00:00"),
433                     "axis_2.1.1.2":(30,-30),
434                     "outputFormat_2.1.1":"NetCDF"})
435    x.createOutputs()   
436    print x.getOutputFilePathDict() 
437    print x.getOutputInfoDict()
438    print x.getOutputDurationEstimates()
439    print x.getOutputSizes()
440   
441    print "\n\n\n"
442    print "DIFFERENCING VARS..."
443    x=OutputManager({"username":"jane", "datasetGroup_1":"Test Data Group 1",
444                     "dataset_1.3":"Test Dataset 1", "variable_1.3.1":"pqn",
445                     "axis_1.3.1.1":("1999-01-01T00:00:00", "1999-01-01T06:00:00"),
446                     "outputFormat_1.3.1":"NetCDF",
447                     "datasetGroup_2":"Test Data Group 2",
448                     "dataset_2.1":"Test Dataset 2", "variable_2.1.1":"var2",
449                     "axis_2.1.1.1":("2004-01-01T12:00:00", "2004-01-01T12:00:00"),
450                     "axis_2.1.1.2":(30,-30),
451                     "outputFormat_2.1.1":"NetCDF",
452                     "numericalOperation":"(var2)-(var1)"})     
453   
454    x.getOutputFilePathDict()
455    x.createOutputs()
456
457    print "TRYING REAL TEST.................."
458    x=OutputManager({'username':None, 'variable_1.1.1':'pqn', 
459                     'outputFormat_1.1.1':'NetCDF', 'userRoles':[], 
460                     'datasetGroup_1':'Test Data Group 1', 
461                     'axis_1.1.1.3':(-30, 30), 'dataset_1.1':'Test Dataset 1'})
462    print x.getOutputFilePathDict()
463   
464    ONE_FILE_PER_TIMESTEP=0   
465    print "\n\nCSML test!\n"
466    x=OutputManager({'username':None, 'variable_1.1.1':'var2', 
467                     'outputFormat_1.1.1':'NetCDF', 'userRoles':[], 
468                     'datasetGroup_1':'CSML test dataset group', 
469                     'axis_1.1.1.3':(0, 35), 'dataset_1.1':'CSML test dataset great test'})
470    print "\nGet output file path dict...", x.getOutputFilePathDict()
471    print "\nCREATE CSML Outputs...", x.createOutputs()
Note: See TracBrowser for help on using the repository browser.