source: nappy/trunk/nappy/contrib/aircraft/old_na_to_nc_with_aircraft.py @ 5905

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/nappy/trunk/nappy/contrib/aircraft/old_na_to_nc_with_aircraft.py@5905
Revision 5905, 30.8 KB checked in by astephen, 11 years ago (diff)

Removed dependency on local cdms_utils, now using official egg.

Line 
1#!/usr/bin/env python
2#   Copyright (C) 2004 CCLRC & NERC( Natural Environment Research Council ).
3#   This software may be distributed under the terms of the
4#   Q Public License, version 1.0 or later. http://ndg.nerc.ac.uk/public_docs/QPublic_license.txt
5
6"""
7cdms_to_na.py
8=============
9
10Holds the class CDMSToNA that converts a set of CDMS variables and global attributes.
11
12"""
13
14# Imports from python standard library
15import sys
16import os
17import time
18import string
19import re
20
21# Import from nappy package
22from nappy.na_error import na_error
23import nappy.utils
24import nappy.utils.common_utils
25import nappy.na_file.na_core
26
27
28nc_to_na_map = utils.getConfigDict()["nc_to_na_map"]
29
30# Import external packages (if available)
31if sys.platform.find("win") > -1:
32    raise na_error.NAPlatformError("Windows does not support CDMS. CDMS is required to convert to CDMS objects and NetCDF.")
33try:
34    import cdms, Numeric
35except:
36    raise Exception("Could not import third-party software. Nappy requires the CDMS and Numeric packages to be installed to convert to CDMS and NetCDF.")
37
38cdms.setAutoBounds("off") 
39
40compareAxes = cdms_utils.axis_utils.compareAxes
41compareVariables = cdms_utils.var_utils.compareVariables
42arrayToList = nappy.utils.list_manipulator.arrayToList
43listOfListsCreator = nappy.utils.list_manipulator.listOfListsCreator
44getBestName = cdms_utils.var_utils.getBestName
45getMissingValue = cdms_utils.var_utils.getMissingValue
46flatten2DTimeAxis = nappy.contrib.aircraft.aircraft_utils.flatten2DTimeAxis
47modifyNADictCopy = nappy.utils.common_utils.modifyNADictCopy
48
49
50def cdms2na(ncfile, na_file_names, naVars={}, variables=None, nFilesOnly="no", 
51            rule=None, ffi="automatic", delimiter="    ", float_format="%g", 
52            rules=None, sizeLimit=None):
53    """
54    Main conversion function that calls the appropriate classes and functions
55    to write a NASA Ames file.
56    """
57    #print infilename, outfilenames, nFilesOnly, naVars, variables
58    if type(na_file_names) == type("string"): 
59        na_file_names = [na_file_names]
60   
61    # Get which NASA Ames internal variables are allowed to be overwritten in the output files (i.e. by user inputs)
62    allowedOverwriteMetadata = ("DATE",  "RDATE", "ANAME", "MNAME",
63           "ONAME", "ORG", "SNAME", "VNAME")
64    arrayArgs=["DATE", "RDATE", "ANAME", "VNAME"]
65    # ANAME[a] - array of 'a' x ANAME strings - aux var names
66    # DATE (array of three) - UT date at which the data within the file starts
67    # MNAME - mission name
68    # ONAME - name of originator(s)
69    # ORG - org or affiliation of originator(s)
70    # RDATE (array of three) - date of data reduction or revision
71    # SNAME - source of measurement or model output VNAME[n] - array of 'n' x
72    # VNAME strings - var names.
73    outputMessage=[]
74    msg="Reading data from: %s\n" % infilename
75    print msg
76    outputMessage.append(msg)
77    cdmsfile=cdms.open(infilename)
78    globals=cdmsfile.attributes
79   
80    vars=[]
81    if not variables:
82        variables=cdmsfile.listvariables()
83        #for var in cdmsfile.listvariables():
84            #vars.append(cdmsfile(var))   
85           
86    for variable in variables:
87        varObj=cdmsfile(variable)
88        # Deal with singleton variables
89        if not hasattr(varObj, "rank"):
90                varMetadata=cdmsfile[variable].attributes
91                varValue=varObj
92                #print varMetadata, varValue, varMetadata.keys(), varMetadata._obj_.id
93                varObj=cdms.createVariable(Numeric.array(varObj), id=getBestName(varMetadata).replace(" ", "_"), attributes=varMetadata)
94                #print varObj, dir(varObj); sys.exit()
95                varObj.value=varObj._data[0]
96                #varObj.rank=0
97               
98        #print varObj, varObj.attributes                         
99        vars.append(varObj)
100       
101    # Re-order variables if they have the attribute 'nasa_ames_var_number'
102    orderedVars=[None]*1000
103    otherVars=[]
104    for var in vars:
105        varMetadata=cdmsfile[var]
106        if hasattr(varMetadata, "nasa_ames_var_number"):
107            num=varMetadata.nasa_ames_var_number
108            orderedVars[num]=var
109        else:
110            otherVars.append(var)
111   
112    vars=[]
113    for var in orderedVars:
114        if var!=None:
115            vars.append(var)
116           
117    vars=vars+otherVars
118   
119    builder=NAContentCollector(vars, globals, rule=rule, cdmsfile=cdmsfile)
120    #print builder.na_dict["X"]
121    builtNADicts=[[builder.na_dict, builder.varIDs]]
122    if builder.varIDs==None:
123        msg="\nNo files created after variables parsed."
124        print msg
125        outputMessage.append(msg)
126        return outputMessage
127
128    while len(builder.varBin)>0:
129        builder=NAContentCollector(builder.varBin, globals, rule=rule, cdmsfile=cdmsfile)
130        outputMessage=outputMessage+builder.outputMessage
131        if builder.varIDs!=None:  builtNADicts.append([builder.na_dict, builder.varIDs])
132
133    # Return only filenames if only want to know them now.
134    ncount=1
135    fileNames=[]
136    if nFilesOnly=="yes": 
137        for i in builtNADicts:
138            if len(builtNADicts)==1:
139                suffix=""
140            else:
141                suffix="_%s" % ncount
142            nameparts=outfilenames[0].split(".")   
143            newname=(".".join(nameparts[:-1]))+suffix+"."+nameparts[-1]
144            fileNames.append(newname)
145        ncount=ncount+1
146           
147        return fileNames
148               
149    msg="\n%s files to write" % len(builtNADicts)
150    print msg
151    outputMessage.append(msg)
152
153    count=1
154    ncount=1
155    for i in builtNADicts:
156        if len(outfilenames)==1:
157            if len(builtNADicts)==1:
158                suffix=""
159            else:
160                suffix="_%s" % ncount
161            nameparts=outfilenames[0].split(".")   
162            newname=(".".join(nameparts[:-1]))+suffix+"."+nameparts[-1]
163        else:
164            newname=outfilenames[count-1]
165 
166        msg="\nWriting output NASA Ames file: %s" % newname
167        print msg
168        outputMessage.append(msg)
169       
170        builtNADict=i[0]
171        for key in naVars.keys():
172            if key in allowedOverwriteMetadata:
173           
174                if key in arrayArgs:
175                    newItem=naVars[key].split()           
176                else:
177                    newItem=naVars[key]
178                                   
179                if newItem!=builtNADict[key]:
180                    builtNADict[key]=newItem
181                    msg="Metadata overwritten in output file: '%s' is now '%s'" % (key, builtNADict[key])
182                    print msg
183                    outputMessage.append(msg)
184       
185        fileList=[]
186        # Cope with size limits if specified and FFI is 1001
187        if sizeLimit and (builtNADict["FFI"]==1001 and len(builtNADict["V"][0])>sizeLimit):
188            varList=builtNADict["V"]
189            arrayLength=len(varList[0])
190            nvolInfo=divmod(arrayLength, sizeLimit)
191            nvol=nvolInfo[0]
192            if nvolInfo[1]>0: nvol=nvol+1
193            start=0
194            letterCount=0
195            ivol=0
196            while start<arrayLength:
197                ivol=ivol+1
198                end=start+sizeLimit
199                if end>arrayLength:
200                    end=arrayLength
201                currentBlock=[]
202                # Write new V array
203                for v in varList:
204                    currentBlock.append(v[start:end])
205
206                # Adjust X accordingly
207                NADictCopy=modifyNADictCopy(builtNADict, currentBlock, start, end, ivol, nvol)
208               
209                # Write data to output file
210                newnamePlusLetter="%s-%.3d.na" % (newname[:-3], ivol)
211                fileList.append(newnamePlusLetter)
212                general.openNAFile(newnamePlusLetter, 'w', NADictCopy, delimiter=delimiter, float_format=float_format)
213                msg="\nOutput files split on size limit: %s\nFilename used: %s" % (sizeLimit, newnamePlusLetter)
214                print msg
215                outputMessage.append(msg)
216                letterCount=letterCount+1
217                start=end
218
219
220        else:           
221            general.openNAFile(newname, 'w', builtNADict, delimiter=delimiter, float_format=float_format)
222
223        msg="\nWrote the following variables:"+"\n\t"+("\n\t".join(i[1][0]))
224        print msg
225        outputMessage.append(msg)
226       
227        if len(i[1][1])>0:
228            msg="\nWrote the following auxiliary variables:"
229            msg=msg+"\n\t"+("\n\t".join(i[1][1]))       
230           
231        if len(i[1][2])>0:
232            msg="\nWrote the following Singleton variables:"
233            msg=msg+"\n\t"+("\n\t".join(i[1][2]))
234
235        if len(fileList)>0:
236            msg=msg+("\n\nNASA Ames files written successfully: \n%s" % "\n".join(fileList))
237            count=count+len(fileList)
238        else:
239            msg=msg+"\n\nNASA Ames file written successfully: %s" % newname
240            count=count+1
241        ncount=ncount+1
242
243        print msg
244        outputMessage.append(msg)
245           
246    if (count-1)==1:
247        plural=""
248    else:
249        plural="s"           
250    msg="\n%s file%s written." % ((count-1), plural)
251    print msg
252    outputMessage.append(msg)
253    return outputMessage
254
255
256class NAContentCollector(NACore):
257    """
258    Class to build a NASA Ames File object from a set of
259    CDMS variables and global attributes (optional).
260    """
261   
262    def __init__(self, vars, global_attributes={}, cdmsfile=None, rule=None):
263        """
264        Sets up instance variables and calls appropriate methods to
265        generate sections of NASA Ames file object.
266        """
267        self.rule=rule
268        self.cdmsfile=cdmsfile
269        self.outputMessage=[]
270        self.na_dict={}
271        self.vars=vars
272        self.varIDs=None
273        self.globals=global_attributes 
274        self.rankZeroVars=[]
275        self.rankZeroVarIDs=[]
276        (self.orderedVars, auxVars)=self.analyseVariables()
277        if self.orderedVars==None:
278            self.varBin=[]
279        else:
280            #print "NAMELISTS:", [var.id for var in self.orderedVars],[var.id for var in auxVars]
281            self.varIDs=[[var.id for var in self.orderedVars],[var.id for var in auxVars], self.rankZeroVarIDs]
282       
283            self.na_dict["NLHEAD"]="-999"
284       
285            #print [var.id for var in self.orderedVars]
286            #print [var.rank() for var in self.orderedVars]     
287            self.defineNAVars(self.orderedVars)
288            self.defineNAAuxVars(auxVars)
289            self.defineNAGlobals()
290            self.defineNAComments()
291            self.defineGeneralHeader()
292            # Quick fudge
293            if self.na_dict["FFI"]==1001: self.na_dict["X"]=self.na_dict["X"][0]
294
295
296    def analyseVariables(self):
297        """
298        Method to examine the content of CDMS variables to return
299        a tuple of two lists containing variables and auxiliary variables
300        for the NASA Ames file object.
301        Variables not compatible with the first file are binned to be used next.
302        """
303        # Need to group the variables together in bins
304        self.varBin=[]
305        # Get largest ranked variable as the one we use as standard
306        highrank=-1
307        bestVar=None
308        count=0
309        for var in self.vars:
310            msg="Analysing: %s" % var.id
311            print msg
312            self.outputMessage.append(msg)
313            count=count+1
314
315            # get rank
316            rank=var.rank()
317
318            # Deal with specific datasets with special rules
319            if self.rule!=None and self.rule[0]=="aircraft":
320                var=self._useLocalRule(var, self.rule)
321                if type(var)==type(None): 
322                    continue 
323                rank=1
324
325            # Deal with singleton variables
326            if rank==0: 
327                self.rankZeroVars.append(var)
328                self.rankZeroVarIDs.append(var.id)
329                continue
330           
331            if rank>highrank:
332                highrank=rank
333                bestVar=var
334                bestVarIndex=count
335            elif rank==highrank:
336                if len(var.flat)>len(bestVar.flat):
337                    bestVar=var
338                    bestVarIndex=count
339       
340        if len(self.rankZeroVars)==len(self.vars):  return (None, None)
341        if not bestVar: 
342            print "No variables produced"
343            return (None, None)
344
345        vars4NA=[bestVar]
346        auxVars4NA=[]
347        shape=bestVar.shape
348        ndims=len(shape)
349        self.na_dict["NIV"]=ndims
350
351        # Work out which File Format Index is appropriate
352        if ndims in (2,3,4):
353            self.na_dict["FFI"]=10+(ndims*1000)
354        elif ndims>4:
355            raise "Cannot write variables defined against greater than 4 axes in NASA Ames format."
356        else:
357            if len(auxVars4NA)>0 or (self.na_dict.has_key("NAUXV") and self.na_dict["NAUXV"]>0):
358                self.na_dict["FFI"]=1010
359            else:
360                self.na_dict["FFI"]=1001
361        #print self.na_dict["FFI"]
362        axes=bestVar.getAxisList()
363       
364        # Get other variable info
365        #print [v.id for v in self.vars], bestVarIndex
366        #print [v.id for v in self.vars[:bestVarIndex-1]+self.vars[bestVarIndex:]]
367        for var in self.vars[:bestVarIndex-1]+self.vars[bestVarIndex:]:
368            # Deal with specific datasets with special rules
369            if self.rule!=None and self.rule[0]=="aircraft":
370                if var.rank()==2:
371                    var=self._useLocalRule(var, self.rule)
372                    if type(var)==type(None): continue
373
374            #print self.rankZeroVars
375            #for rzv in self.rankZeroVars: 
376            #    if var.id==rzv.id and var[0]==rzv[0]: continue
377            #print [v.id for v in self.rankZeroVars]
378            if var.id in self.rankZeroVarIDs: continue
379            #print var.id, ndims, shape, len(var.shape), var.shape
380            if len(var.shape)!=ndims or var.shape!=shape: 
381                # Could it be an auxiliary variable
382                if len(var.shape)!=1: 
383                    self.varBin.append(var)
384                    continue
385                caxis=var.getAxis(0)
386                if compareAxes(axes[0], caxis)==0: 
387                    self.varBin.append(var)
388                    continue
389                # I think it is an auxiliary variable
390                auxVars4NA.append(var) 
391                # Also put it in var bin because auxiliary vars might be useful
392                self.varBin.append(var)
393            else:
394                caxes=var.getAxisList()
395                #print var.id, "here"
396                for i in range(ndims):           
397                    if compareAxes(axes[i], caxes[i])==0:
398                        self.varBin.append(var)
399                        continue
400                # OK, I think they are compatible
401                vars4NA.append(var)
402               
403        # Re-order if they previously came from NASA Ames files (i.e. including
404        # the attribute 'nasa_ames_var_number')
405        orderedVars=[None]*1000
406        otherVars=[]
407        for var in vars4NA:
408            if hasattr(var, "nasa_ames_var_number"):
409                orderedVars[var.nasa_ames_var_number[0]]=var
410            else:
411                otherVars.append(var)
412        # Remake vars4NA now in order
413        vars4NA=[]
414        for var in orderedVars:
415            if var!=None: vars4NA.append(var)
416        vars4NA=vars4NA+otherVars
417
418        # Now re-order the Auxiliary variables if they previously came from NASA
419        # Ames files (i.e. including the attribute 'nasa_ames_aux_var_number')
420
421        orderedAuxVars=[None]*1000
422        otherAuxVars=[]
423        for var in auxVars4NA:
424            if hasattr(var, "nasa_ames_aux_var_number"):
425                orderedAuxVars[var.nasa_ames_aux_var_number[0]]=var
426            else:
427                otherAuxVars.append(var)
428        # Remake auxVars4NA now in order
429        auxVars4NA=[]
430        for var in orderedAuxVars:
431            if var!=None: auxVars4NA.append(var)
432        auxVars4NA=auxVars4NA+otherAuxVars     
433        return (vars4NA, auxVars4NA)
434
435
436    def defineNAVars(self, vars):
437        """
438        Method to define NASA Ames file object variables and their
439        associated metadata.
440        """
441        self.na_dict["NV"]=len(vars)
442        self.na_dict["VNAME"]=[]
443        self.na_dict["VMISS"]=[]
444        self.na_dict["VSCAL"]=[]
445        self.na_dict["V"]=[]
446        for var in vars:
447            name=getBestName(var)
448            self.na_dict["VNAME"].append(name)
449            miss=getMissingValue(var)
450            if type(miss) not in (float, int, long):  miss=miss[0]
451            self.na_dict["VMISS"].append(miss)
452            #print self.na_dict["VMISS"]
453            self.na_dict["VSCAL"].append(1)
454            # AND THE ARRAY
455            # Populate the variable list 
456            ######## NOTE - might not have to do this #####
457            ######## It  might handle writing from a Numeric array ########
458            self.na_dict["V"].append(var._data)
459            #listOfListsCreator(inlist, var.shape)
460            #arrayToList(var, inlist)
461
462            if not self.na_dict.has_key("X"):
463                self.na_dict["NXDEF"]=[]
464                self.na_dict["NX"]=[]
465                # Create independent variable information
466                #print var.id, var.getAxis(0)
467                self.ax0=var.getAxis(0)
468                self.na_dict["X"]=[list(self.ax0._data_)]
469                self.na_dict["XNAME"]=[getBestName(self.ax0)]
470                if len(self.ax0)==1:
471                    self.na_dict["DX"]=[0]
472                else:
473                    incr=self.ax0[1]-self.ax0[0]
474                    # Set default increment as gap between first two
475                    self.na_dict["DX"]=[incr]
476                    # Now overwrite it as zero if non-uniform interval in axis
477                    for i in range(1, len(self.ax0)):
478                        if (self.ax0[i]-self.ax0[i-1])!=incr:
479                            self.na_dict["DX"]=[0]
480                            break
481
482                # Now sort the rest of the axes
483                for axis in var.getAxisList()[1:]:
484                    self.getAxisDefinition(axis)
485
486
487    def defineNAAuxVars(self, auxVars):
488        """
489        Method to define NASA Ames file object auxiliary variables and their
490        associated metadata.
491        """
492        self.na_dict["NAUXV"]=len(auxVars)
493        self.na_dict["ANAME"]=[]
494        self.na_dict["AMISS"]=[]
495        self.na_dict["ASCAL"]=[]
496        self.na_dict["A"]=[]
497        for var in auxVars:
498            name=getBestName(var)
499            self.na_dict["ANAME"].append(name)
500            miss=getMissingValue(var)
501            if type(miss)!=float:  miss=miss[0]
502            self.na_dict["AMISS"].append(miss)
503            self.na_dict["ASCAL"].append(1)
504            # AND THE ARRAY
505            # Populate the variable list 
506            ######## NOTE - might not have to do this #####
507            ######## It  might handle writing from a Numeric array ########
508            self.na_dict["A"].append(var._data)
509            #listOfListsCreator(inlist, var.shape)
510            #arrayToList(var, inlist)     
511
512
513    def getAxisDefinition(self, axis):
514        """
515        Method to create the appropriate NASA Ames file object
516        items associated with an axis (independent variable in
517        NASA Ames).
518        """
519        length=len(axis)
520        self.na_dict["NX"].append(length)
521        self.na_dict["XNAME"].append(getBestName(axis))
522        # If only one item in axis values
523        if length<2:
524            self.na_dict["DX"].append(0)
525            self.na_dict["NXDEF"].append(length)
526            self.na_dict["X"].append(list(axis._data_))       
527            return
528   
529        incr=axis[1]-axis[0]
530        for i in range(1, length):
531            if (axis[i]-axis[i-1])!=incr:
532                self.na_dict["DX"].append(0)
533                self.na_dict["NXDEF"].append(length)
534                self.na_dict["X"].append(list(axis._data_))
535                break
536        else:
537            maxLength=length
538            if length>3: maxLength=3
539            self.na_dict["DX"].append(incr)
540            self.na_dict["NXDEF"].append(maxLength)
541            self.na_dict["X"].append(axis[:maxLength])
542        return
543
544
545    def defineNAGlobals(self):
546        """
547        Maps CDMS (NetCDF) global attributes into NASA Ames Header fields.
548        """
549        # Get the global mapping dictionary
550        globalmap=cdmsMap.toNA
551        # Check if we should add to it with locally set rules
552        locGlobs=localRules.localGlobalAttributes
553        for att in locGlobs.keys():
554            if not globalmap.has_key(att):
555                globalmap[key]=locGlobs[key]
556
557        self.extra_comments=[[],[],[]]  # Normal comments, special comments, other comments
558        conventionOrReferenceComments=[]
559        for key in self.globals.keys():
560            if key!="first_valid_date_of_data" and type(self.globals[key]) not in (str, float, int): continue
561            if key in globalmap.keys():
562                if key=="history":
563                    timestring=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
564                    history="History:\t%s - Converted to NASA Ames format using nappy-%s.\n\t%s" % (timestring, version.version, self.globals[key])
565                    history=history.split("\n") 
566                    self.history=[]
567                    for h in history:
568                        if h[:8]!="History:" and h[:1]!="\t": h="\t"+h
569                        self.history.append(h) 
570                   
571                elif key=="institution":
572                    # If fields came from NA then extract appropriate fields.
573                    match=re.match(r"(.*)\s+\(ONAME from NASA Ames file\);\s+(.*)\s+\(ORG from NASA Ames file\)\.", self.globals[key])
574                    if match:
575                        self.na_dict["ONAME"]=match.groups()[0]
576                        self.na_dict["ORG"]=match.groups()[1]
577                    else:
578                        self.na_dict["ONAME"]=self.globals[key]
579                        self.na_dict["ORG"]=self.globals[key]               
580                   
581                    # NOte: should probably do the following search and replace on all string lines
582                    self.na_dict["ONAME"]=self.na_dict["ONAME"].replace("\n", "  ")
583                    self.na_dict["ORG"]=self.na_dict["ORG"].replace("\n", "  ")
584                                   
585                elif key=="comment":
586                    # Need to work out if they are actually comments from NASA Ames in the first place
587                    #self.ncom=[self.globals[key]]
588                    comLines=self.globals[key].split("\n")
589                    normComms=[]
590                    normCommFlag=None
591                    specComms=[]
592                    specCommFlag=None
593                    for line in comLines:
594                        if line.find("###NASA Ames Special Comments follow###")>-1:
595                            specCommFlag=1
596                        elif line.find("###NASA Ames Special Comments end###")>-1:
597                            specCommFlag=None
598                        elif line.find("###NASA Ames Normal Comments follow###")>-1:
599                            normCommFlag=1
600                        elif line.find("###NASA Ames Normal Comments end###")>-1:
601                            normCommFlag=None   
602                        elif specCommFlag==1:
603                            specComms.append(line)
604                        elif normCommFlag==1:
605                            normComms.append(line)
606                        elif line.find("###Data Section begins on the next line###")>-1:
607                            pass
608                        else:
609                            normComms.append(line)         
610                   
611                    self.extra_comments=[specComms, normComms, []]                 
612                                   
613                elif key=="first_valid_date_of_data":
614                    self.na_dict["DATE"]=self.globals[key]
615               
616                elif key in ("Conventions", "references"):
617                    #conventionOrReferenceComments.append("%s:   %s" % (key, self.globals[key]))
618                    self.extra_comments[2].append("%s:   %s" % (key, self.globals[key]))
619                else:
620                    self.na_dict[globalmap[key]]=self.globals[key]
621            else:
622                self.extra_comments[2].append("%s:   %s" % (key, self.globals[key]))
623        #self.extra_comments
624        return
625
626
627    def defineNAComments(self, normal_comments=[], special_comments=[]):
628        """
629        Defines the Special and Normal comments sections in the NASA Ames file
630        object - including information gathered from the defineNAGlobals method.
631        """
632       
633        if hasattr(self, "ncom"):  normal_comments=self.ncom+normal_comments
634        NCOM=[]
635        for ncom in normal_comments:
636            NCOM.append(ncom)
637        if len(NCOM)>0:   NCOM.append("")
638       
639        if len(self.extra_comments[2])>0:
640            for excom in self.extra_comments[2]:
641                NCOM.append(excom)
642       
643        if len(self.extra_comments[1])>0: 
644            NCOM.append("Additional Global Attributes defined in the source file and not translated elsewhere:")
645            for excom in self.extra_comments[1]:
646                NCOM.append(excom)
647
648        if hasattr(self, "history"):
649            for h in self.history:
650                NCOM.append(h)
651       
652        if len(NCOM)>0:
653            NCOM.insert(0, "###NASA Ames Normal Comments follow###")
654            NCOM.append("")
655            NCOM.append("###NASA Ames Normal Comments end###")
656        NCOM.append("###Data Section begins on the next line###")
657
658        specCommentsFlag=None
659        SCOM=[]
660        special_comments=self.extra_comments[0]
661        if len(special_comments)>0: 
662            SCOM=["###NASA Ames Special Comments follow###"]
663            specCommentsFlag=1
664        for scom in special_comments:
665            SCOM.append(scom)
666
667
668        #used_var_atts=("name", "long_name", "standard_name", "id",
669            #    "missing_value", "fill_value", "units",
670                #"nasa_ames_var_number", "nasa_ames_aux_var_number")
671        used_var_atts=("id",  "missing_value", "fill_value", "units", 
672                   "nasa_ames_var_number", "nasa_ames_aux_var_number")
673        varCommentsFlag=None
674
675        # Create a string for the Special comments to hold rank-zero vars
676        rankZeroVarsString=[]
677        for var in self.rankZeroVars:
678            rankZeroVarsString.append("\tVariable %s: %s" % (var.id, getBestName(var)))
679            for att in var.attributes.keys():
680                value=var.attributes[att]
681                if type(value) in (str, float, int):
682                    rankZeroVarsString.append("\t\t%s = %s" % (att, var.attributes[att]))
683            #print "VALUES", dir(var), var._data ; rankZeroVarsString.append("\t\tvalue = %s" % var._data)
684       
685        if len(rankZeroVarsString)>0:
686            rankZeroVarsString.insert(0, "###Singleton Variables defined in the source file follow###")
687            rankZeroVarsString.append("###Singleton Variables defined in the source file end###")
688
689        for var in self.orderedVars:
690            varflag="unused"
691            name=getBestName(var)
692            for scom,value in var.attributes.items():
693                if type(value) in (type([]), type(Numeric.array([0]))) and len(value)==1:
694                    value=value[0]
695                if type(value) in (str, float, int) and scom not in used_var_atts:
696                    if varflag=="unused":
697                        if varCommentsFlag==None:
698                            varCommentsFlag=1
699                            if specCommentsFlag==None:
700                                SCOM=["###NASA Ames Special Comments follow###"]+rankZeroVarsString
701                            SCOM.append("Additional Variable Attributes defined in the source file and not translated elsewhere:")
702                            SCOM.append("###Variable attributes from source (NetCDF) file follow###")
703                        varflag="using" 
704                        SCOM.append("\tVariable %s: %s" % (var.id, name))
705                    SCOM.append("\t\t%s = %s" % (scom, value))
706
707        if varCommentsFlag==1:  SCOM.append("###Variable attributes from source (NetCDF) file end###")
708        if specCommentsFlag==1:
709            SCOM.append("###NASA Ames Special Comments end###")
710
711        """used_var_atts=("name", "long_name", "standard_name", "id", "missing_value", "fill_value", "units")
712        for var in self.vars:
713            for scom,value in var.attributes.items():
714                name=getBestName(var)
715                if type(value) in (str, float, int) and scom not in used_var_atts:
716                    SCOM.append("\t%s: %s - %s" % (name, scom, value))"""
717
718        # Strip out empty lines (or returns)
719        NCOM_cleaned=[]
720        SCOM_cleaned=[]
721        #hiddenNewLineCount1=0
722        for c in NCOM:
723            if c.strip() not in ("", " ", "  "):
724                #hiddenNewLineCount1=hiddenNewLineCount1+c.count("\n")
725                # Replace new lines within one attribute with a newline and tab so easier to read
726                lines=c.split("\n")
727                for line in lines:
728                    if line!=lines[0]: line="\t"+line
729                    NCOM_cleaned.append(line)
730               
731        #hiddenNewLineCount2=0 
732        for c in SCOM:
733            if c.strip() not in ("", " ", "  "):               
734                #hiddenNewLineCount2=hiddenNewLineCount2+c.count("\n")
735                # Replace new lines within one attribute with a newline and tab so easier to read
736                #c=c.replace("\n", "\n\t")
737                #SCOM_cleaned.append(c)
738                lines=c.split("\n")
739                for line in lines:
740                    if line!=lines[0]: line="\t"+line
741                    SCOM_cleaned.append(line)
742                   
743        self.na_dict["NCOM"]=NCOM_cleaned
744        self.na_dict["NNCOML"]=len(self.na_dict["NCOM"])#+hiddenNewLineCount1
745        self.na_dict["SCOM"]=SCOM_cleaned
746        self.na_dict["NSCOML"]=len(self.na_dict["SCOM"])#+hiddenNewLineCount2
747        return
748
749
750    def defineGeneralHeader(self, header_items={}):
751        """
752        Defines known header items and overwrites any with header_items
753        key/value pairs.
754        """
755        # Check if DATE field previously known in NASA Ames file
756        time_now=time.strftime("%Y %m %d", time.localtime(time.time())).split()
757        if not self.na_dict.has_key("RDATE"):
758            self.na_dict["RDATE"]=time_now
759       
760        if self.ax0.isTime():
761            # Get first date in list
762            try:
763                (unit, start_date)=re.match("(\w+)\s+?since\s+?(\d+-\d+-\d+)", self.ax0.units).groups()           
764                comptime=cdtime.s2c(start_date)
765                first_day=comptime.add(self.na_dict["X"][0][0], getattr(cdtime, unit.capitalize()))
766                self.na_dict["DATE"]=string.replace(str(first_day).split(" ")[0], "-", " ").split()
767            except:
768                msg="Nappy Warning: Could not get the first date in the file. You will need to manually edit the output file."
769                print msg
770                self.outputMessage.append(msg)
771                self.na_dict["DATE"]=("DATE", "NOT", "KNOWN")
772        else: 
773            if not self.na_dict.has_key("DATE"):
774                msg="Nappy Warning: Could not get the first date in the file. You will need to manually edit the output file."
775                print msg
776                self.outputMessage.append(msg)
777                self.na_dict["DATE"]=("DATE", "NOT", "KNOWN")
778        self.na_dict["IVOL"]=1
779        self.na_dict["NVOL"]=1
780        for key in header_items.keys():
781             self.na_dict[key]=header_items[key]
782        return
783
784
785    def _useLocalRule(self, var, ruleArgs):
786        """
787        Applies some logic based on a local rule.
788        """
789        ruleName=ruleArgs[0]
790        rule=ruleArgs
791        if ruleName=="aircraft":
792            # Fixes aircraft data 2D time axis, missing values and does sub-selection by default
793            flagVar=None
794
795            # return if variable is time
796            if var.id=="Time":
797                return None
798
799            if len(rule)<2: rule.append("av")
800            if len(rule)<3: rule.append("flag")
801            if rule[2]=="flag":
802                # Only use flag var for processing real variable
803                if var.id.strip()[-4:]=="FLAG": 
804                    print "Ignore flag: %s" % var.id
805                    return None 
806
807                flagID=var.id.strip()+"FLAG"
808                try:
809                    flagVar=self.cdmsfile(flagID)
810                except:
811                    raise "Cannot get flag variable for '%s'" % var.id
812            elif rule[2]=="noflag":
813                flagVar=None
814
815            timeVar=self.cdmsfile("Time")
816            import localRules.aircraftData
817            ruleArgs=[rule[1]]+rule[3:]
818            fixedVar=localRules.aircraftData.AircraftData(var, timeVar, flagVar, ruleArgs).subSampledVar
819            return fixedVar
820        else:
821            raise "Rule '%s' not yet defined." % ruleName
822               
823
824usenc2nainstead="""if __name__=="__main__":
825
826    args=sys.argv[1:]
827    if len(args)<4:
828        print helpMessage
829        print "Incorrect number of arguments used."
830        sys.exit()
831       
832    for arg in args:
833        if arg=="-i":
834            infile=args[args.index(arg)+1]
835        elif arg=="-o":
836            outfile=args[args.index(arg)+1]
837
838    cdms2na(infile, outfile) """
Note: See TracBrowser for help on using the repository browser.