source: nappy/trunk/naFile.py @ 343

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/nappy/trunk/naFile.py@343
Revision 343, 9.5 KB checked in by astephen, 16 years ago (diff)

Latest version with new files in test directory.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
RevLine 
[339]1"""
2naFile.py
3=========
4
[343]5A containter module for the mixin base class NAFile that is subclassed
6for individual FFIs. Each FFI class is held in an individual file.
[339]7
8"""
9
[343]10# Imports from python standard library
[339]11import sys
12import time
13import re
14
[343]15# Imports from nappy package
16import naCore
[339]17from textParser import *
[343]18from naError import *
19import naToCdms
[339]20
[343]21class NAFile(naCore.NACore, naToCdms.NAToCdms):
[339]22
[343]23    """
24    NAFile class is a sub-class of NACore and NAToCdms mixin classes.
25    NAFile is also a mixin class and should not be called directly.
26   
27    NAFile holds all the methods are common to either all or more than
28    one NASA Ames FFI class. These methods set up the main read and write
29    functionality for the NASA Ames format.
[339]30
[343]31    When a sub-class of NAFile is called with a read ('r' - default) or
32    write ('w') mode the header in the file is automatically read or written.
33    However, the user must explicitly read or write the data section with a
34    call to the 'readData' or 'writeData' methods.
[339]35
[343]36    """
[339]37
[343]38    def __init__(self, filename, mode="r", naDict={}, spacer="    ", floatFormat="%8.3f"):
39        """
40        Initialization of class, decides if user wishes to read or write
41        NASA Ames file.
42        """
43        naCore.NACore.__init__(self)
[339]44        self.naDict=naDict
45        self.filename=filename
[343]46        self._open(mode)
47        self.spacer=spacer
48        self.floatFormat=floatFormat
49
[339]50        if mode=="r":
[343]51            self._normalizedX="yes"
[339]52            self.readHeader()
53        elif mode=="w":
[343]54            self._parseDictionary()
[339]55            self.writeHeader()
56            self.writeData()
57        else:
58            raise "Unknown file mode '%s'." % mode
59        self.close()
60       
[343]61    def _open(self, mode):
62        "Wrapper to builtin open file function."
[339]63        self.file=open(self.filename, mode)
64
65    def close(self):
[343]66        "Wrapper to builtin close file function."
[339]67        self.file.close()
68
[343]69    def _parseDictionary(self):
70        """
71        Parser for the optional naDict argument containing a dictionary
72        of NASA Ames internal variables. These are saved as instance attributes
73        with the name used in the NASA Ames documentation.
74        """
[339]75        for i in self.naDict.keys():
76            setattr(self, i, self.naDict[i])
77
[343]78    def _readTopLine(self):
[339]79        """
80        Reads number of header lines and File Format Index from top line.
[343]81        Also assigns a value to NIV for the number of independent variables
[339]82        based on the first character in the FFI.
[343]83
84        Returns NLHEAD and FFI in a tuple.
[339]85        """
86        (self.NLHEAD, self.FFI)=readItemsFromLine(self.file.readline(), 2, int)
87        self.NIV=int(self.FFI/1000)
88        return (self.NLHEAD, self.FFI)
89
[343]90    def _readLines(self, nlines):
91        "Reads nlines lines from a file and returns them in a list."
[339]92        lines=[]
93        for i in range(nlines):
94            lines.append(self.file.readline().strip())
95        return lines
96
[343]97    def _checkForBlankLines(self, datalines):
[339]98        """
99        Searches for empty lines in the middle of the data section and raises
100        as error if found. It ignores empty lines at the end of the file but
101        strips them out before returning a list of lines for reading.
102        """
103        empties=None
104        count=0
105        rtlines=[]
106        for line in datalines:
107            if re.match(r"^[\s\n\t\r]*$", line):
108                empties=1
109            else:
110                if empties==1:   # If data line found after empty line then raise
111                    raise "Empty line found in data section at line: %s" % count
112                else:
113                    rtlines.append(line)
114            count=count+1
115        return rtlines
116
[343]117    def _readCommonHeader(self):
118        """
119        Reads the header section common to all NASA Ames files.
120        """
121        self._readTopLine()
[339]122        self.ONAME=readItemFromLine(self.file.readline(), str)
123        self.ORG=readItemFromLine(self.file.readline(), str)
124        self.SNAME=readItemFromLine(self.file.readline(), str)
125        self.MNAME=readItemFromLine(self.file.readline(), str)
126        (self.IVOL, self.NVOL)=readItemsFromLine(self.file.readline(), 2, int)
127        dates=readItemsFromLine(self.file.readline(), 6, int)
128        (self.DATE, self.RDATE)=(dates[:3], dates[3:])
129
[343]130    def _writeCommonHeader(self):
131        """
132        Writes the header section common to all NASA Ames files.
133        """
[339]134        self.file.write("%s    %s\n" % (self.NLHEAD, self.FFI))
135        self.file.write("%s\n" % self.ONAME)
136        self.file.write("%s\n" % self.ORG)
137        self.file.write("%s\n" % self.SNAME)
138        self.file.write("%s\n" % self.MNAME)
139        self.file.write("%s    %s\n" % (self.IVOL, self.NVOL))
140        self.file.write("%s %s %s    %s %s %s\n" % (self.DATE[0], self.DATE[1], self.DATE[2], self.RDATE[0], self.RDATE[1], self.RDATE[2]))
141
[343]142    def _readVariablesHeaderSection(self):
143        """
144        Reads the variables section of the header.
145        Assumes we are at the right point in the file.
146        """
[339]147        self.NV=readItemFromLine(self.file.readline(), int)
148        self.VSCAL=readItemsFromUnknownLines(self.file, self.NV, float)
149        self.VMISS=readItemsFromUnknownLines(self.file, self.NV, float)
[343]150        self.VNAME=readItemsFromLines(self._readLines(self.NV), self.NV, str)
[339]151
[343]152    def _writeVariablesHeaderSection(self):
153        """
154        Writes the variables section of the header.
155        Assumes we are at the right point in the file.
156        """       
[339]157        self.file.write("%s\n" % self.NV)
158        self.file.write(("%s "*self.NV+"\n") % tuple(self.VSCAL))
159        self.file.write(("%s "*self.NV+"\n")  % tuple(self.VMISS))
160        self.file.write("%s\n"*self.NV % tuple(self.VNAME))
161
[343]162    def _readAuxVariablesHeaderSection(self):
163        """
164        Reads the auxiliary variables section of the header.
165        Assumes we are at the right point in the file.
166        """
[339]167        self.NAUXV=readItemFromLine(self.file.readline(), int)
168        if self.NAUXV>0:       
169            self.ASCAL=readItemsFromUnknownLines(self.file, self.NAUXV, float)
170            self.AMISS=readItemsFromUnknownLines(self.file, self.NAUXV, float)
[343]171            self.ANAME=readItemsFromLines(self._readLines(self.NAUXV), self.NAUXV, str)
[339]172
[343]173    def _writeAuxVariablesHeaderSection(self):
174        """
175        Writes the auxiliary variables section of the header.
176        Assumes we are at the right point in the file.
177        """       
[339]178        self.file.write("%s\n" % self.NAUXV)
179        if self.NAUXV>0:
180            self.file.write(("%s "*self.NAUXV+"\n")  % tuple(self.ASCAL))
181            self.file.write(("%s "*self.NAUXV+"\n")  % tuple(self.AMISS))
182            self.file.write("%s\n"*self.NV % tuple(self.ANAME))
183
[343]184    def _readCharAuxVariablesHeaderSection(self):
185        """
186        Reads the character-encoded auxiliary variables section of the header.
187        Assumes we are at the right point in the file.
188        """
[339]189        self.NAUXV=readItemFromLine(self.file.readline(), int)
190        self.NAUXC=readItemFromLine(self.file.readline(), int)
191        nonCharAuxVars=self.NAUXV-self.NAUXC
192        if self.NAUXV>0:
193            self.ASCAL=readItemsFromUnknownLines(self.file, nonCharAuxVars, float)
194            self.AMISS=readItemsFromUnknownLines(self.file, nonCharAuxVars, float)
195            self.LENA=readItemsFromUnknownLines(self.file, self.NAUXC, int)
196            for i in range(nonCharAuxVars):
197                self.LENA.insert(0, None)
198            self.AMISS=self.AMISS+readItemsFromUnknownLines(self.file, self.NAUXC, str)   
[343]199            self.ANAME=readItemsFromLines(self._readLines(self.NAUXV), self.NAUXV, str)       
[339]200           
[343]201    def _readComments(self):
202        """
203        Reads the special and normal comments sections.
204        Assumes we are at the right point in the file.
205        """       
[339]206        self.NSCOML=readItemFromLine(self.file.readline(), int)
[343]207        self._readSpecialComments()
[339]208        self.NNCOML=readItemFromLine(self.file.readline(), int)
[343]209        self._readNormalComments()
[339]210
[343]211    def _writeComments(self):
212        """
213        Writes the special and normal comments sections.
214        Assumes we are at the right point in the file.
215        """ 
[339]216        self.file.write("%s\n" % self.NSCOML)
217        self.file.write("%s\n"*self.NSCOML % tuple(self.SCOM))
218        self.file.write("%s\n" % self.NNCOML)
219        self.file.write("%s\n"*self.NNCOML % tuple(self.NCOM))
220
[343]221    def _readSpecialComments(self):
[339]222        """
[343]223        Reads the special comments section.       
224        Assumes that we are at the right point in the file and that NSCOML
225        variable is known.
[339]226        """
[343]227        self.SCOM=self._readLines(self.NSCOML)
228        return self.SCOM
[339]229
[343]230    def _readNormalComments(self):
[339]231        """
[343]232        Reads the normal comments section.       
233        Assumes that we are at the right point in the file and that NNCOML
234        variable is known.
[339]235        """
[343]236        self.NCOM=self._readLines(self.NNCOML)
237        return self.NCOM
[339]238
239    def readData(self):
[343]240        """
241        Reads the data section of the file. This method actually calls a number
242        of FFI specific methods to setup the data arrays (lists of lists) and
243        read the various data sections.
[339]244
[343]245        This method can be called directly by the user.
[339]246        """
247        self._setupArrays()
248        datalines=open(self.filename).readlines()[self.NLHEAD:]
[343]249        datalines=self._checkForBlankLines(datalines)
[339]250
251        # Set up loop over unbounded indpendent variable
252        m=0   # Unbounded independent variable mark       
253        while len(datalines)>0:
254            datalines=self._readData1(datalines, m)
255            datalines=self._readData2(datalines, m)
256            m=m+1   
257
Note: See TracBrowser for help on using the repository browser.