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

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

Cleaning up the imports

File size: 10.4 KB
Line 
1import os
2import numpy as num
3from anuga.file.netcdf import NetCDFFile
4
5from anuga.file.urs import Read_urs
6
7import anuga.utilities.log as log
8
9from anuga.file_conversion.urs2nc import urs2nc
10from anuga.file_conversion.ferret2sww import ferret2sww
11
12from anuga.coordinate_transforms.redfearn import redfearn, \
13     convert_from_latlon_to_utm
14
15from anuga.geospatial_data.geospatial_data import ensure_absolute, \
16                                                    Geospatial_data
17
18from anuga.file.mux import WAVEHEIGHT_MUX_LABEL, EAST_VELOCITY_LABEL, \
19                            NORTH_VELOCITY_LABEL
20                           
21from anuga.utilities.numerical_tools import ensure_numeric                           
22
23from anuga.config import netcdf_mode_r, netcdf_mode_w, netcdf_mode_a, \
24                            netcdf_float
25
26from anuga.file.sww import Write_sww 
27
28###############################################################
29
30def urs_ungridded2sww(basename_in='o', basename_out=None, verbose=False,
31                      mint=None, maxt=None,
32                      mean_stage=0,
33                      origin=None,
34                      hole_points_UTM=None,
35                      zscale=1):
36    """
37    Convert URS C binary format for wave propagation to
38    sww format native to abstract_2d_finite_volumes.
39
40    Specify only basename_in and read files of the form
41    basefilename-z-mux, basefilename-e-mux and
42    basefilename-n-mux containing relative height,
43    x-velocity and y-velocity, respectively.
44
45    Also convert latitude and longitude to UTM. All coordinates are
46    assumed to be given in the GDA94 datum. The latitude and longitude
47    information is assumed ungridded grid.
48
49    min's and max's: If omitted - full extend is used.
50    To include a value min ans max may equal it.
51    Lat and lon are assumed to be in decimal degrees.
52
53    origin is a 3-tuple with geo referenced
54    UTM coordinates (zone, easting, northing)
55    It will be the origin of the sww file. This shouldn't be used,
56    since all of anuga should be able to handle an arbitary origin.
57    The mux point info is NOT relative to this origin.
58
59    URS C binary format has data organised as TIME, LONGITUDE, LATITUDE
60    which means that latitude is the fastest
61    varying dimension (row major order, so to speak)
62
63    In URS C binary the latitudes and longitudes are in assending order.
64
65    Note, interpolations of the resulting sww file will be different
66    from results of urs2sww.  This is due to the interpolation
67    function used, and the different grid structure between urs2sww
68    and this function.
69
70    Interpolating data that has an underlying gridded source can
71    easily end up with different values, depending on the underlying
72    mesh.
73
74    consider these 4 points
75    50  -50
76
77    0     0
78
79    The grid can be
80     -
81    |\|   A
82     -
83     or;
84      -
85     |/|  B
86      -
87
88    If a point is just below the center of the midpoint, it will have a
89    +ve value in grid A and a -ve value in grid B.
90    """
91
92    from anuga.mesh_engine.mesh_engine import NoTrianglesError
93    from anuga.pmesh.mesh import Mesh
94
95    files_in = [basename_in + WAVEHEIGHT_MUX_LABEL,
96                basename_in + EAST_VELOCITY_LABEL,
97                basename_in + NORTH_VELOCITY_LABEL]
98    quantities = ['HA','UA','VA']
99
100    # instantiate urs_points of the three mux files.
101    mux = {}
102    for quantity, file in map(None, quantities, files_in):
103        mux[quantity] = Read_urs(file)
104
105    # Could check that the depth is the same. (hashing)
106
107    # handle to a mux file to do depth stuff
108    a_mux = mux[quantities[0]]
109
110    # Convert to utm
111    lat = a_mux.lonlatdep[:,1]
112    long = a_mux.lonlatdep[:,0]
113    points_utm, zone = convert_from_latlon_to_utm(latitudes=lat,
114                                                  longitudes=long)
115
116    elevation = a_mux.lonlatdep[:,2] * -1
117
118    # grid (create a mesh from the selected points)
119    # This mesh has a problem.  Triangles are streched over ungridded areas.
120    # If these areas could be described as holes in pmesh, that would be great.
121
122    # I can't just get the user to selection a point in the middle.
123    # A boundary is needed around these points.
124    # But if the zone of points is obvious enough auto-segment should do
125    # a good boundary.
126    mesh = Mesh()
127    mesh.add_vertices(points_utm)
128    mesh.auto_segment(smooth_indents=True, expand_pinch=True)
129
130    # To try and avoid alpha shape 'hugging' too much
131    mesh.auto_segment(mesh.shape.get_alpha() * 1.1)
132    if hole_points_UTM is not None:
133        point = ensure_absolute(hole_points_UTM)
134        mesh.add_hole(point[0], point[1])
135
136    try:
137        mesh.generate_mesh(minimum_triangle_angle=0.0, verbose=False)
138    except NoTrianglesError:
139        # This is a bit of a hack, going in and changing the data structure.
140        mesh.holes = []
141        mesh.generate_mesh(minimum_triangle_angle=0.0, verbose=False)
142
143    mesh_dic = mesh.Mesh2MeshList()
144
145    #mesh.export_mesh_file(basename_in + '_168.tsh')
146    #import sys; sys.exit()
147    # These are the times of the mux file
148    mux_times = []
149    for i in range(a_mux.time_step_count):
150        mux_times.append(a_mux.time_step * i)
151    (mux_times_start_i, mux_times_fin_i) = read_time_from_mux(mux_times, mint, maxt)
152    times = mux_times[mux_times_start_i:mux_times_fin_i]
153
154    if mux_times_start_i == mux_times_fin_i:
155        # Close the mux files
156        for quantity, file in map(None, quantities, files_in):
157            mux[quantity].close()
158        msg = "Due to mint and maxt there's no time info in the boundary SWW."
159        raise Exception(msg)
160
161    # If this raise is removed there is currently no downstream errors
162
163    points_utm=ensure_numeric(points_utm)
164    assert num.alltrue(ensure_numeric(mesh_dic['generatedpointlist'])
165                       == ensure_numeric(points_utm))
166
167    volumes = mesh_dic['generatedtrianglelist']
168
169    # Write sww intro and grid stuff.
170    if basename_out is None:
171        swwname = basename_in + '.sww'
172    else:
173        swwname = basename_out + '.sww'
174
175    if verbose: log.critical('Output to %s' % swwname)
176
177    outfile = NetCDFFile(swwname, netcdf_mode_w)
178
179    # For a different way of doing this, check out tsh2sww
180    # work out sww_times and the index range this covers
181    sww = Write_sww(['elevation'], ['stage', 'xmomentum', 'ymomentum'])
182    sww.store_header(outfile, times, len(volumes), len(points_utm),
183                     verbose=verbose, sww_precision=netcdf_float)
184    outfile.mean_stage = mean_stage
185    outfile.zscale = zscale
186
187    sww.store_triangulation(outfile, points_utm, volumes,
188                            zone, 
189                            new_origin=origin,
190                            verbose=verbose)
191    sww.store_static_quantities(outfile, elevation=elevation)
192
193    if verbose: log.critical('Converting quantities')
194
195    # Read in a time slice from each mux file and write it to the SWW file
196    j = 0
197    for ha, ua, va in map(None, mux['HA'], mux['UA'], mux['VA']):
198        if j >= mux_times_start_i and j < mux_times_fin_i:
199            stage = zscale*ha + mean_stage
200            h = stage - elevation
201            xmomentum = ua*h
202            ymomentum = -1 * va * h # -1 since in mux files south is positive.
203            sww.store_quantities(outfile,
204                                 slice_index=j-mux_times_start_i,
205                                 verbose=verbose,
206                                 stage=stage,
207                                 xmomentum=xmomentum,
208                                 ymomentum=ymomentum,
209                                 sww_precision=num.float)
210        j += 1
211
212    if verbose: sww.verbose_quantities(outfile)
213
214    outfile.close()
215
216    # Do some conversions while writing the sww file
217
218
219def read_time_from_mux(mux_times, mint, maxt):
220    """
221        Read a list of mux times.
222        Return start and finish times which lie within the passed time period.
223    """
224
225    if mint == None:
226        mux_times_start_i = 0
227    else:
228        mux_times_start_i = num.searchsorted(mux_times, mint)
229
230    if maxt == None:
231        mux_times_fin_i = len(mux_times)
232    else:
233        maxt += 0.5 # so if you specify a time where there is
234                    # data that time will be included
235        mux_times_fin_i = num.searchsorted(mux_times, maxt)
236
237    return mux_times_start_i, mux_times_fin_i
238
239
240
241
242
243def urs2sww(basename_in='o', basename_out=None, verbose=False,
244            remove_nc_files=True,
245            minlat=None, maxlat=None,
246            minlon=None, maxlon=None,
247            mint=None, maxt=None,
248            mean_stage=0,
249            origin=None,
250            zscale=1,
251            fail_on_NaN=True,
252            NaN_filler=0):
253    """Convert a URS file to an SWW file.
254    Convert URS C binary format for wave propagation to
255    sww format native to abstract_2d_finite_volumes.
256
257    Specify only basename_in and read files of the form
258    basefilename-z-mux2, basefilename-e-mux2 and
259    basefilename-n-mux2 containing relative height,
260    x-velocity and y-velocity, respectively.
261
262    Also convert latitude and longitude to UTM. All coordinates are
263    assumed to be given in the GDA94 datum. The latitude and longitude
264    information is for  a grid.
265
266    min's and max's: If omitted - full extend is used.
267    To include a value min may equal it, while max must exceed it.
268    Lat and lon are assumed to be in decimal degrees.
269    NOTE: minlon is the most east boundary.
270
271    origin is a 3-tuple with geo referenced
272    UTM coordinates (zone, easting, northing)
273    It will be the origin of the sww file. This shouldn't be used,
274    since all of anuga should be able to handle an arbitary origin.
275
276    URS C binary format has data orgainised as TIME, LONGITUDE, LATITUDE
277    which means that latitude is the fastest
278    varying dimension (row major order, so to speak)
279
280    In URS C binary the latitudes and longitudes are in assending order.
281    """
282
283    if basename_out == None:
284        basename_out = basename_in
285
286    files_out = urs2nc(basename_in, basename_out)
287
288    ferret2sww(basename_out,
289               minlat=minlat,
290               maxlat=maxlat,
291               minlon=minlon,
292               maxlon=maxlon,
293               mint=mint,
294               maxt=maxt,
295               mean_stage=mean_stage,
296               origin=origin,
297               zscale=zscale,
298               fail_on_NaN=fail_on_NaN,
299               NaN_filler=NaN_filler,
300               inverted_bathymetry=True,
301               verbose=verbose)
302   
303    if remove_nc_files:
304        for file_out in files_out:
305            os.remove(file_out)
306
Note: See TracBrowser for help on using the repository browser.