source: nappy/trunk/naFile.py @ 348

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/nappy/trunk/naFile.py@348
Revision 348, 9.8 KB checked in by selatham, 15 years ago (diff)

08/11/04 include Sue Latham's changes for bug fixes and new Write methods.

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