source: trunk/anuga_core/source/anuga/file/netcdf.py @ 8879

Last change on this file since 8879 was 8864, checked in by steve, 12 years ago

Changed anuga.file.netcdf,NetCDFFile so that we get a better error if file not available
to read.

File size: 8.2 KB
Line 
1""" This module is responsible for loading and saving NetCDF NC files
2"""
3
4import numpy as num
5
6from anuga.coordinate_transforms.redfearn import \
7     convert_from_latlon_to_utm
8from anuga.config import minimum_storable_height as \
9     default_minimum_storable_height
10from anuga.config import netcdf_mode_r, netcdf_mode_w
11from anuga.config import netcdf_float, netcdf_int
12from anuga.utilities.numerical_tools import ensure_numeric,  mean
13
14import anuga.utilities.log as log
15
16
17# Definitions of various NetCDF dimension names, etc.
18lon_name = 'LON'
19lat_name = 'LAT'
20time_name = 'TIME'
21precision = netcdf_float # So if we want to change the precision its done here
22
23
24
25def NetCDFFile(file_name, netcdf_mode=netcdf_mode_r):
26    """Wrapper to isolate changes of the netcdf libray.
27
28    In theory we should be able to change over to NetCDF4 via this
29    wrapper, by ensuring the interface to the NetCDF library isthe same as the
30    the old Scientific.IO.NetCDF library.
31
32    There is a difference between extracting dimensions. We have used the following
33    to cover netcdf4 and scientific python
34
35    try: # works with netcdf4
36        number_of_timesteps = len(fid.dimensions['number_of_timesteps'])
37        number_of_points = len(fid.dimensions['number_of_points'])
38    except: # works with Scientific.IO.NetCDF
39        number_of_timesteps = fid.dimensions['number_of_timesteps']
40        number_of_points = fid.dimensions['number_of_points']
41   
42    """
43   
44    using_scientific = using_netcdf4 = False
45   
46    try:
47        from Scientific.IO.NetCDF import NetCDFFile
48        using_scientific = True
49    except: 
50        from netCDF4 import Dataset
51        using_netcdf4 = True
52
53    assert using_scientific or using_netcdf4
54
55    if using_scientific:
56        return NetCDFFile(file_name, netcdf_mode)
57
58    if using_netcdf4:
59        if netcdf_mode == 'wl' :
60            return Dataset(file_name, 'w', format='NETCDF3_64BIT')
61        else:
62            return Dataset(file_name, netcdf_mode, format='NETCDF3_64BIT')
63
64
65
66#    from netCDF4 import Dataset
67#    return Dataset(file_name, netcdf_mode, format='NETCDF3_64BIT')
68
69    #return Dataset(file_name, netcdf_mode, format='NETCDF3_CLASSIC')
70
71
72    # COMMENT SR; Can't use scipy.io.netcdf as we can't append to
73    # a file as of 2013/03/26
74    #from scipy.io.netcdf import netcdf_file
75    #return netcdf_file(file_name, netcdf_mode, version=2)
76
77
78
79
80class Write_nc:
81    """Write an nc file.
82
83    Note, this should be checked to meet cdc netcdf conventions for gridded
84    data. http://www.cdc.noaa.gov/cdc/conventions/cdc_netcdf_standard.shtml
85    """
86
87    def __init__(self,
88                 quantity_name,
89                 file_name,
90                 time_step_count,
91                 time_step,
92                 lon,
93                 lat):
94        """Instantiate a Write_nc instance (NetCDF file writer).
95
96        time_step_count is the number of time steps.
97        time_step is the time step size
98
99        pre-condition: quantity_name must be 'HA', 'UA'or 'VA'.
100        """
101
102        self.quantity_name = quantity_name
103        quantity_units = {'HA':'CENTIMETERS',
104                          'UA':'CENTIMETERS/SECOND',
105                          'VA':'CENTIMETERS/SECOND'}
106
107        multiplier_dic = {'HA':100.0,   # To convert from m to cm
108                          'UA':100.0,   #             and m/s to cm/sec
109                          'VA':-100.0}  # MUX files have positive x in the
110                                        # Southern direction.  This corrects
111                                        # for it, when writing nc files.
112
113        self.quantity_multiplier =  multiplier_dic[self.quantity_name]
114
115        #self.file_name = file_name
116        self.time_step_count = time_step_count
117        self.time_step = time_step
118
119        # NetCDF file definition
120        self.outfile = NetCDFFile(file_name, netcdf_mode_w)
121        outfile = self.outfile
122
123        #Create new file
124        nc_lon_lat_header(outfile, lon, lat)
125
126        # TIME
127        outfile.createDimension(time_name, None)
128        outfile.createVariable(time_name, precision, (time_name,))
129
130        #QUANTITY
131        outfile.createVariable(self.quantity_name, precision,
132                               (time_name, lat_name, lon_name))
133        outfile.variables[self.quantity_name].missing_value = -1.e+034
134        outfile.variables[self.quantity_name].units = \
135                                 quantity_units[self.quantity_name]
136        outfile.variables[lon_name][:]= ensure_numeric(lon)
137        outfile.variables[lat_name][:]= ensure_numeric(lat)
138
139        #Assume no one will be wanting to read this, while we are writing
140        #outfile.close()
141
142    def store_timestep(self, quantity_slice):
143        """Write a time slice of quantity info
144
145        quantity_slice is the data to be stored at this time step
146        """
147
148        # Get the variables
149        time = self.outfile.variables[time_name]
150        quantity = self.outfile.variables[self.quantity_name]
151
152        # get index oflice to write
153        i = len(time)
154
155        #Store time
156        time[i] = i * self.time_step    #self.domain.time
157        quantity[i,:] = quantity_slice * self.quantity_multiplier
158
159    def close(self):
160        """ Close file underlying the class instance. """
161        self.outfile.close()
162
163
164
165def write_elevation_nc(file_out, lon, lat, depth_vector):
166    """Write an nc elevation file."""
167
168    # NetCDF file definition
169    outfile = NetCDFFile(file_out, netcdf_mode_w)
170
171    #Create new file
172    nc_lon_lat_header(outfile, lon, lat)
173
174    # ELEVATION
175    zname = 'ELEVATION'
176    outfile.createVariable(zname, precision, (lat_name, lon_name))
177    outfile.variables[zname].units = 'CENTIMETERS'
178    outfile.variables[zname].missing_value = -1.e+034
179
180    outfile.variables[lon_name][:] = ensure_numeric(lon)
181    outfile.variables[lat_name][:] = ensure_numeric(lat)
182
183    depth = num.reshape(depth_vector, (len(lat), len(lon)))
184    outfile.variables[zname][:] = depth
185
186    outfile.close()
187
188
189def nc_lon_lat_header(outfile, lon, lat):
190    """Write lat/lon headers to a NetCDF file.
191
192    outfile is the netcdf file handle.
193    lon - a list/array of the longitudes
194    lat - a list/array of the latitudes
195    """
196
197    outfile.institution = 'Geoscience Australia'
198    outfile.description = 'Converted from URS binary C'
199
200    # Longitude
201    outfile.createDimension(lon_name, len(lon))
202    outfile.createVariable(lon_name, precision, (lon_name,))
203    outfile.variables[lon_name].point_spacing = 'uneven'
204    outfile.variables[lon_name].units = 'degrees_east'
205    outfile.variables[lon_name].assignValue(lon)
206
207    # Latitude
208    outfile.createDimension(lat_name, len(lat))
209    outfile.createVariable(lat_name, precision, (lat_name,))
210    outfile.variables[lat_name].point_spacing = 'uneven'
211    outfile.variables[lat_name].units = 'degrees_north'
212    outfile.variables[lat_name].assignValue(lat)
213
214
215
216
217def filter_netcdf(filename1, filename2, first=0, last=None, step=1):
218    """Filter data file, selecting timesteps first:step:last.
219   
220    Read netcdf filename1, pick timesteps first:step:last and save to
221    nettcdf file filename2
222    """
223
224    from Scientific.IO.NetCDF import NetCDFFile
225
226    # Get NetCDF
227    infile = NetCDFFile(filename1, netcdf_mode_r)  #Open existing file for read
228    outfile = NetCDFFile(filename2, netcdf_mode_w)  #Open new file
229
230    # Copy dimensions
231    for d in infile.dimensions:
232        outfile.createDimension(d, infile.dimensions[d])
233
234    # Copy variable definitions
235    for name in infile.variables:
236        var = infile.variables[name]
237        outfile.createVariable(name, var.dtype.char, var.dimensions)
238
239    # Copy the static variables
240    for name in infile.variables:
241        if name == 'time' or name == 'stage':
242            pass
243        else:
244            outfile.variables[name][:] = infile.variables[name][:]
245
246    # Copy selected timesteps
247    time = infile.variables['time']
248    stage = infile.variables['stage']
249
250    newtime = outfile.variables['time']
251    newstage = outfile.variables['stage']
252
253    if last is None:
254        last = len(time)
255
256    selection = range(first, last, step)
257    for i, j in enumerate(selection):
258        log.critical('Copying timestep %d of %d (%f)'
259                     % (j, last-first, time[j]))
260        newtime[i] = time[j]
261        newstage[i,:] = stage[j,:]
262
263    # Close
264    infile.close()
265    outfile.close()
266
Note: See TracBrowser for help on using the repository browser.