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

Last change on this file since 7998 was 7859, checked in by James Hudson, 15 years ago

Cleaned up some code.

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