source: trunk/anuga_core/anuga/file_conversion/urs2nc.py @ 9737

Last change on this file since 9737 was 9551, checked in by steve, 10 years ago

Cleaning up the imports

File size: 6.2 KB
Line 
1import os
2from struct import pack, unpack
3import array as p_array
4import numpy as num
5
6from anuga.anuga_exceptions import ANUGAError
7from anuga.utilities.numerical_tools import ensure_numeric   
8from anuga.caching.caching import myhash
9
10from anuga.file.netcdf import Write_nc, write_elevation_nc
11
12import anuga.utilities.log as log
13from anuga.file.mux import WAVEHEIGHT_MUX_LABEL, EAST_VELOCITY_LABEL, \
14                            NORTH_VELOCITY_LABEL
15
16
17def urs2nc(basename_in='o', basename_out='urs'):
18    """Convert the 3 urs files to 4 nc files.
19
20    The name of the urs file names must be;
21    [basename_in]-z-mux
22    [basename_in]-e-mux
23    [basename_in]-n-mux
24    """
25
26    files_in = [basename_in + WAVEHEIGHT_MUX_LABEL,
27                basename_in + EAST_VELOCITY_LABEL,
28                basename_in + NORTH_VELOCITY_LABEL]
29    files_out = [basename_out + '_ha.nc',
30                 basename_out + '_ua.nc',
31                 basename_out + '_va.nc']
32    quantities = ['HA', 'UA', 'VA']
33
34    #if os.access(files_in[0]+'.mux', os.F_OK) == 0 :
35    for i, file_name in enumerate(files_in):
36        if os.access(file_name, os.F_OK) == 0:
37            if os.access(file_name + '.mux', os.F_OK) == 0 :
38                msg = 'File %s does not exist or is not accessible' % file_name
39                raise IOError, msg
40            else:
41               files_in[i] += '.mux'
42               log.critical("file_name %s" % file_name)
43
44    hashed_elevation = None
45    for file_in, file_out, quantity in map(None, files_in,
46                                           files_out,
47                                           quantities):
48        lonlatdep, lon, lat, depth = _binary_c2nc(file_in,
49                                                  file_out,
50                                                  quantity)
51        if hashed_elevation == None:
52            elevation_file = basename_out + '_e.nc'
53            write_elevation_nc(elevation_file,
54                               lon,
55                               lat,
56                               depth)
57            hashed_elevation = myhash(lonlatdep)
58        else:
59            msg = "The elevation information in the mux files is inconsistent"
60            assert hashed_elevation == myhash(lonlatdep), msg
61
62    files_out.append(elevation_file)
63
64    return files_out
65
66
67def _binary_c2nc(file_in, file_out, quantity):
68    """Reads in a quantity urs file and writes a quantity nc file.
69    Additionally, returns the depth and lat, long info,
70    so it can be written to a file.
71    """
72
73    columns = 3                           # long, lat , depth
74    mux_file = open(file_in, 'rb')
75
76    # Number of points/stations
77    (points_num,) = unpack('i', mux_file.read(4))
78
79    # nt, int - Number of time steps
80    (time_step_count,) = unpack('i', mux_file.read(4))
81
82    #dt, float - time step, seconds
83    (time_step,) = unpack('f', mux_file.read(4))
84
85    msg = "Bad data in the mux file."
86    if points_num < 0:
87        mux_file.close()
88        raise ANUGAError, msg
89    if time_step_count < 0:
90        mux_file.close()
91        raise ANUGAError, msg
92    if time_step < 0:
93        mux_file.close()
94        raise ANUGAError, msg
95
96    lonlatdep = p_array.array('f')
97    lonlatdep.read(mux_file, columns * points_num)
98    lonlatdep = num.array(lonlatdep, dtype=num.float)
99    lonlatdep = num.reshape(lonlatdep, (points_num, columns))
100
101    lon, lat, depth = lon_lat2grid(lonlatdep)
102    lon_sorted = list(lon)
103    lon_sorted.sort()
104
105    if not num.alltrue(lon == lon_sorted):
106        msg = "Longitudes in mux file are not in ascending order"
107        raise IOError, msg
108
109    lat_sorted = list(lat)
110    lat_sorted.sort()
111
112    nc_file = Write_nc(quantity,
113                       file_out,
114                       time_step_count,
115                       time_step,
116                       lon,
117                       lat)
118
119    for i in range(time_step_count):
120        #Read in a time slice from mux file
121        hz_p_array = p_array.array('f')
122        hz_p_array.read(mux_file, points_num)
123        hz_p = num.array(hz_p_array, dtype=num.float)
124        hz_p = num.reshape(hz_p, (len(lon), len(lat)))
125        hz_p = num.transpose(hz_p)  # mux has lat varying fastest, nc has long v.f.
126
127        #write time slice to nc file
128        nc_file.store_timestep(hz_p)
129
130    mux_file.close()
131    nc_file.close()
132
133    return lonlatdep, lon, lat, depth
134
135
136
137def lon_lat2grid(long_lat_dep):
138    """
139    given a list of points that are assumed to be an a grid,
140    return the long's and lat's of the grid.
141    long_lat_dep is an array where each row is a position.
142    The first column is longitudes.
143    The second column is latitudes.
144
145    The latitude is the fastest varying dimension - in mux files
146    """
147
148    LONG = 0
149    LAT = 1
150    QUANTITY = 2
151
152    long_lat_dep = ensure_numeric(long_lat_dep, num.float)
153
154    num_points = long_lat_dep.shape[0]
155    this_rows_long = long_lat_dep[0,LONG]
156
157    # Count the length of unique latitudes
158    i = 0
159    while long_lat_dep[i,LONG] == this_rows_long and i < num_points:
160        i += 1
161
162    # determine the lats and longsfrom the grid
163    lat = long_lat_dep[:i, LAT]
164    long = long_lat_dep[::i, LONG]
165
166    lenlong = len(long)
167    lenlat = len(lat)
168
169    msg = 'Input data is not gridded'
170    assert num_points % lenlat == 0, msg
171    assert num_points % lenlong == 0, msg
172
173    # Test that data is gridded
174    for i in range(lenlong):
175        msg = 'Data is not gridded.  It must be for this operation'
176        first = i * lenlat
177        last = first + lenlat
178
179        assert num.allclose(long_lat_dep[first:last,LAT], lat), msg
180        assert num.allclose(long_lat_dep[first:last,LONG], long[i]), msg
181
182    msg = 'Out of range latitudes/longitudes'
183    for l in lat:assert -90 < l < 90 , msg
184    for l in long:assert -180 < l < 180 , msg
185
186    # Changing quantity from lat being the fastest varying dimension to
187    # long being the fastest varying dimension
188    # FIXME - make this faster/do this a better way
189    # use numeric transpose, after reshaping the quantity vector
190    quantity = num.zeros(num_points, num.float)
191
192    for lat_i, _ in enumerate(lat):
193        for long_i, _ in enumerate(long):
194            q_index = lat_i*lenlong + long_i
195            lld_index = long_i*lenlat + lat_i
196            temp = long_lat_dep[lld_index, QUANTITY]
197            quantity[q_index] = temp
198
199    return long, lat, quantity
200
201
202
Note: See TracBrowser for help on using the repository browser.