source: anuga_work/development/Hinwood_2008/slope.py @ 5532

Last change on this file since 5532 was 5532, checked in by duncan, 16 years ago

Current Hinwood scenario

File size: 23.8 KB
Line 
1
2"""
3Plot up files from the Hinwood project.
4"""
5from os import sep
6import project
7from copy import deepcopy
8#from scipy import arange
9from csv import writer
10
11from Numeric import arange, array, zeros, Float, where, greater, less, \
12     compress, argmin, choose, searchsorted
13
14from anuga.fit_interpolate.interpolate import interpolate_sww2csv
15from anuga.shallow_water.data_manager import csv2dict
16from anuga.utilities.numerical_tools import ensure_numeric
17
18
19SLOPE_STR = 'stage_slopes'
20TIME_STR = 'times'
21
22TIME_BORDER = 5
23LOCATION_BORDER = .5
24
25def load_sensors(quantity_file):
26    """
27    Load a csv file, where the first row is the column header and
28    the first colum explains the rows.
29    """
30    #slope, _ = csv2dict(file_sim)
31   
32    # Read the depth file
33    dfid = open(quantity_file)
34    lines = dfid.readlines()
35    dfid.close()
36
37    title = lines.pop(0)
38    n_time = len(lines)
39    n_sensors = len(lines[0].split(','))-1  # -1 to remove time
40    times = zeros(n_time, Float)  #Time
41    depths = zeros(n_time, Float)  #
42    sensors = zeros((n_time,n_sensors), Float)
43    quantity_locations = title.split(',') #(',')
44    quantity_locations.pop(0) # remove 'time'
45   
46    locations = [float(j.split(':')[0]) for j in quantity_locations]
47   
48    for i, line in enumerate(lines):
49        fields = line.split(',') #(',')
50        fields = [float(j) for j in fields]
51        times[i] = fields[0]
52        sensors[i] = fields[1:] # 1: to remove time
53
54    #print "times",times
55    #print "locations", locations
56    #print "sensors", sensors
57    return times, locations, sensors
58   
59def load_slopes(stage_file):
60    """
61    Finds the slope, wrt distance of a distance, time, quantity csv file.
62
63    returns the times and slope_locations vectors and the slopes array.
64    """
65    times, locations, sensors = load_sensors(stage_file)
66    n_slope_locations = len(locations)-1
67    n_time = len(times)
68    slope_locations = zeros(n_slope_locations, Float)  #
69    slopes = zeros((n_time,n_slope_locations), Float)
70
71    # An array of the sensor spacing values
72    delta_locations = zeros(n_slope_locations, Float)
73   
74    for i in arange(n_slope_locations):
75        delta_locations[i] = (locations[i+1] - locations[i])
76        slope_locations[i] = locations[i] + 0.5*delta_locations[i]
77   
78    for j in arange(n_time):
79        for i in arange(n_slope_locations):
80            slopes[j,i] = (sensors[j,i+1] - sensors[j,i])/delta_locations[i]
81
82    return times, slope_locations, slopes
83
84
85def graph_contours(times, x_data, z_data,
86                 y_label='Time, seconds',
87                 plot_title="slope",
88                 x_label='x location, m',
89                 save_as=None,
90                 is_interactive=False,
91                 break_xs=None,
92                 break_times=None):
93    """
94    Currently used to generate stage slope contour graphs.
95
96    Has been generalised a bit.
97    """
98    # Do not move these imports.  Tornado doesn't have pylab
99    from pylab import meshgrid, cm, contourf, contour, ion, plot, xlabel, \
100         ylabel, close, legend, savefig, title, figure ,colorbar, show , axis
101
102    origin = 'lower'
103
104    if is_interactive:
105        ion()
106       
107    # Can't seem to reshape this info once it is in the function
108    CS = contourf(x_data, times, z_data, 10,
109                  cmap=cm.bone,
110                  origin=origin)
111   
112    #CS2 = contour(x_data, times, z_data, CS.levels[::1],
113     #             colors = 'r',
114      #            origin=origin,
115       #           hold='on')
116   
117    title(plot_title)
118    xlabel(x_label)
119    ylabel(y_label)
120
121    if break_times is not None and break_xs is not None:
122        plot(break_xs, break_times, 'ro')
123   
124   
125    # Make a colorbar for the ContourSet returned by the contourf call.
126    cbar = colorbar(CS)
127
128    # Add the contour line levels to the colorbar
129    cbar.ax.set_ylabel('stage slope')
130    #cbar.add_lines(CS2)
131         
132    if is_interactive:       
133        raw_input() # Wait for enter pressed
134       
135    if save_as is not None:
136        savefig(save_as)
137    close()  #Need to close this plot
138
139def graph_froude(times, x_data, z_data,
140                 y_label='Time, seconds',
141                 plot_title="Froude Number",
142                 x_label='x location, m',
143                 save_as=None,
144                 is_interactive=False,
145                 break_xs=None,
146                 break_times=None):
147    """
148    Used to generate a froude Number contour graphs.
149
150    """
151    # Do not move these imports.  Tornado doesn't have pylab
152    from pylab import meshgrid, cm, contourf, contour, ion, plot, xlabel, \
153         ylabel, close, legend, savefig, title, figure ,colorbar, show , axis
154
155    origin = 'lower'
156
157    if is_interactive:
158        ion()
159       
160    # Can't seem to reshape this info once it is in the function
161    #CS = contourf(x_data, times, z_data, [-1,0.6,0.8,1,2,4],
162     #             colors = ('black', 'r', 'g', 'b','r'),
163      #            #cmap=cm.bone,
164       #           origin=origin)
165    CS = contourf(x_data, times, z_data, 10,
166                  #colors = ('black', 'r', 'g', 'b','r'),
167                  cmap=cm.bone,
168                  origin=origin)
169   
170    #CS2 = contour(x_data, times, z_data, CS.levels[::1],
171     #             colors = 'r',
172      #            origin=origin,
173       #           hold='on')
174   
175    title(plot_title)
176    xlabel(x_label)
177    ylabel(y_label)
178
179    if break_times is not None and break_xs is not None:
180        plot(break_xs, break_times, 'yo')
181   
182   
183    # Make a colorbar for the ContourSet returned by the contourf call.
184    cbar = colorbar(CS)
185
186    # Add the contour line levels to the colorbar
187    cbar.ax.set_ylabel('Froude Number')
188    #cbar.add_lines(CS2)
189         
190    if is_interactive:       
191        raw_input() # Wait for enter pressed
192       
193    if save_as is not None:
194        savefig(save_as)
195    close()  #Need to close this plot
196   
197def auto_graph_slopes(outputdir_tag, scenarios, is_interactive=False):
198    """
199    Used to generate all the stage slope contour graphs of a scenario list
200    """
201    plot_type = ".pdf"
202    for run_data in scenarios:
203        id = run_data['scenario_id']
204        outputdir_name = id + outputdir_tag
205        pro_instance = project.Project(['data','flumes','Hinwood_2008'],
206                                       outputdir_name=outputdir_name)
207        end = id + ".csv"
208        anuga_break_times = []
209        for break_time in run_data['break_times']:
210            anuga_break_times.append( \
211                break_time -  run_data['ANUGA_start_time'])
212        stage_file = pro_instance.outputdir + "fslope_stage_" + end
213        plot_title = "Stage slope " + id + "\n file:" + \
214                     outputdir_name + "_slope_stage" + plot_type
215        print "Creating ", stage_file
216        save_as = pro_instance.plots_dir + sep + \
217                            outputdir_name + "_slope_stage" + plot_type
218        times, locations, slopes = load_slopes(stage_file)
219        #times, slopes = get_band(anuga_break_times[0]-TIME_BORDER,
220         #                          100, times, slopes, 0)
221        #locations, slopes = get_band(
222         #   min(run_data['break_xs'])- 2*LOCATION_BORDER,
223          #  100, locations, slopes, -1)
224        graph_contours(times, locations, slopes,
225                       plot_title=plot_title,
226                       break_xs=run_data['break_xs'],
227                       break_times=anuga_break_times,
228                       save_as=save_as,
229                       is_interactive=is_interactive)
230
231def auto_graph_froudes(outputdir_tag, scenarios, is_interactive=False):
232    """
233    Used to generate all the Froude number contour graphs of a scenario list
234    """
235   
236    plot_type = ".pdf"
237   
238    for run_data in scenarios:
239        id = run_data['scenario_id']
240        outputdir_name = id + outputdir_tag
241        pro_instance = project.Project(['data','flumes','Hinwood_2008'],
242                                       outputdir_name=outputdir_name)
243        end = id + ".csv"
244        anuga_break_times = []
245        for break_time in run_data['break_times']:
246            anuga_break_times.append( \
247                break_time -  run_data['ANUGA_start_time'])
248        plot_title = "Froude Number" + id + "\n file:" + \
249                     outputdir_name + "_froude" + plot_type
250        froude_file = pro_instance.outputdir + "fslope_froude_" + end
251        print "Creating ", froude_file
252        save_as = pro_instance.plots_dir + sep + \
253                            outputdir_name + "_froude" + plot_type
254        dtimes, locations, sensors = load_sensors(froude_file)
255        dtimes, sensors = get_band(anuga_break_times[0]-TIME_BORDER,
256                                   100, dtimes, sensors, 0)
257        locations, sensors = get_band(
258            min(run_data['break_xs'])-LOCATION_BORDER,
259            100, locations, sensors, -1)
260        #print "dtimes", dtimes
261        #print "sensors", sensors
262        #times, slope_locations, slopes = load_slopes(stage_file)
263        graph_froude(dtimes, locations, sensors,
264                     plot_title=plot_title,
265                     break_xs=run_data['break_xs'],
266                     break_times=anuga_break_times,
267                     save_as=save_as,
268                     is_interactive=is_interactive)
269       
270def find_froude(times_froude, locations_froude, froudes_array,
271                times, locations):
272    """
273    interpolate across location to find froude number values
274    """
275   
276    if len(times) == 0:
277        return []
278    time_indexes = searchsorted(times_froude, times)
279    location_indexes = searchsorted(locations_froude, locations)
280
281   
282    assert len(time_indexes) == len(location_indexes)
283
284    froudes = []
285    for time_i, loc_i, time, location in map(None, time_indexes,
286                                             location_indexes,
287                                             times, locations):
288        # the time values should be the same
289        assert times_froude[time_i] == time
290
291        # The distance value should be half way between the froude locations
292        midpoint = locations_froude[loc_i-1] + \
293                   (locations_froude[loc_i]-locations_froude[loc_i-1])*0.5
294        #print "location", location
295        #print "midpoint", midpoint
296        assert location == midpoint
297        froude = froudes_array[time_i, loc_i-1] + \
298                   (froudes_array[time_i, loc_i]- \
299                    froudes_array[time_i, loc_i-1])*0.5
300        froudes.append(froude)
301               
302    return froudes
303   
304def auto_find_min_slopes(slope_tag, outputdir_tag, scenarios):
305    """
306    Given stage and froude wrt time and location csv files,
307    find the waves and get the froude number and stage slope
308    at the wave face.
309
310    For each wave write a csv file giving the location, stage slope, time and
311    froude number.
312    """
313   
314    for run_data in scenarios:
315        id = run_data['scenario_id']
316        outputdir_name = id + outputdir_tag
317        pro_instance = project.Project(['data','flumes','Hinwood_2008'],
318                                       outputdir_name=outputdir_name)
319        end = id + ".csv"
320        anuga_break_times = []
321        for break_time in run_data['break_times']:
322            anuga_break_times.append( \
323                break_time -  run_data['ANUGA_start_time'])
324           
325        stage_file = pro_instance.outputdir + slope_tag + "slope_stage_" + end
326        froude_file = pro_instance.outputdir + slope_tag + "slope_froude_" + \
327                      end
328       
329        times, slope_locations, slopes = load_slopes(stage_file)
330        #print "slope_locations", slope_locations
331        times_froude, locations_froude, froudes_a = load_sensors(froude_file)
332        #print "locations_froude", locations_froude
333        waves = find_min_slopes(times, slope_locations, slopes,
334                                anuga_break_times,
335                                run_data['band_offset'])
336       
337        # write the wave info here
338        # and find the froude values
339        for i, wave in enumerate(waves):
340           
341            id = "wave_" + str(i)
342            wave_file = stage_file[:-4] + '_'+ id + ".csv"
343            print "wave_file", wave_file
344            froudes = find_froude(times_froude, locations_froude,
345                             froudes_a, wave[TIME_STR],
346                                  slope_locations)
347            wave_writer = writer(file(wave_file, "wb"))
348            wave_writer.writerow(["x location", "min slope", "Time", "Froude"])
349            wave_writer.writerows(map(None,
350                                      slope_locations,
351                                      wave[SLOPE_STR],
352                                      wave[TIME_STR],
353                                      froudes))
354
355def calc_wave_file_min_slope_max_froude(slope_tag, outputdir_tag, scenarios):
356    """
357    Calc the min slope and max froude number in the wave files
358    Used so all graphs have the same axis.
359    """
360    min_slope = 0
361    max_froude = 0
362   
363    for run_data in scenarios:
364        for wave_file, save_as, wave_number in Get_file_name(
365        run_data, outputdir_tag, slope_tag):
366            simulation, _ = csv2dict(wave_file)
367            slope = [float(x) for x in simulation['min slope']]
368            froude = [float(x) for x in simulation['Froude']]
369           
370            min_slope = min(min(slope), min_slope)
371           
372            max_froude = max(max(froude), max_froude)
373           
374   
375    return min_slope, max_froude
376
377class Get_file_name:
378    """
379    Used to make the file names, and workout the wave number.
380    """
381   
382    def __init__(self, run_data, outputdir_tag, slope_tag):
383       
384        self.plot_type = ".pdf"
385        # The scenario data
386        id = run_data['scenario_id']
387       
388        self.outputdir_name = id + outputdir_tag
389        self.pro_instance = project.Project(['data','flumes','Hinwood_2008'],
390                                            outputdir_name=self.outputdir_name)
391        self.wave_number = -1
392        self.max_waves = len(run_data['break_type'])
393        self.slope_tag = slope_tag
394        self.end = id + ".csv"
395
396    def next(self):
397        self.wave_number += 1
398        if self.wave_number >= self.max_waves: raise StopIteration
399        wave_tag = "wave_" + str(self.wave_number)
400        stage_file = self.pro_instance.outputdir + self.slope_tag + \
401                     "slope_stage_" + self.end
402        wave_file = stage_file[:-4] + '_'+ wave_tag + ".csv"
403        save_as = self.pro_instance.plots_dir + sep + \
404                  self.outputdir_name + "_" + wave_tag + self.plot_type
405        return wave_file, save_as, self.wave_number
406
407    def __iter__(self):
408        return self
409       
410
411
412
413def auto_plot_froude_slopes(slope_tag, outputdir_tag, scenarios):
414    """
415    Used to generate all the Froude number, stage slope, time graphs
416    of a scenario list
417    """
418
419    slope_min, froude_max = calc_wave_file_min_slope_max_froude(
420        slope_tag, outputdir_tag, scenarios)
421   
422   
423    for run_data in scenarios:
424        assert len(run_data['break_times']) == len(run_data['break_xs'])
425        assert len(run_data['break_times']) == len(run_data['break_type'])
426       
427        anuga_break_times = []
428        for break_time in run_data['break_times']:
429            anuga_break_times.append( \
430                break_time -  run_data['ANUGA_start_time'])
431           
432        for wave_file, save_as, wave_number in Get_file_name(
433        run_data, outputdir_tag, slope_tag):
434            print "wave_file", wave_file
435            break_type = run_data['break_type'][wave_number]
436            plot_title = run_data['scenario_id'] + \
437                         ' Wave: ' + str(wave_number) + \
438                         ' Break Type: ' + break_type + '\n' + \
439                         'File: ' + wave_file[34:] # not good!
440            plot_foude_slope_stage(wave_file,
441                                   anuga_break_times[wave_number],
442                                   run_data['break_xs'][wave_number],
443                                   plot_title=plot_title,
444                                   break_type=break_type,
445                                   save_as=save_as,
446                                   is_interactive=False,
447                                   froude_min=0,
448                                   froude_max=froude_max,
449                                   slope_min=slope_min,
450                                   slope_max=0)
451       
452       
453   
454def gauges_for_slope(slope_tag, outputdir_tag, scenarios):
455    """
456    This is used to create a stage file, using gauges relivent to
457    finding a slope.
458
459    It also create's a frounde file.
460    """
461    dx = 0.05
462    for run_data in scenarios:
463        point_x = arange(run_data['start_slope_x'],
464                        run_data['finish_slope_x'],
465                        dx).tolist()
466        flume_y_middle = 0.5
467        points = []
468        for gauge_x in point_x:
469            points.append([gauge_x, flume_y_middle])
470        id = run_data['scenario_id']
471   
472        basename = 'zz_' + run_data['scenario_id']
473        outputdir_name = id + outputdir_tag
474        pro_instance = project.Project(['data','flumes','Hinwood_2008'],
475                                       outputdir_name=outputdir_name)
476        end = id + ".csv"
477        interpolate_sww2csv( \
478            pro_instance.outputdir + basename +".sww",
479            points,
480            pro_instance.outputdir + slope_tag + "slope_depth_" + end,
481            pro_instance.outputdir + slope_tag + "slope_velocity_x_" + end,
482            pro_instance.outputdir + slope_tag + "slope_velocity_y_" + end,
483            pro_instance.outputdir + slope_tag + "slope_stage_" + end,
484            pro_instance.outputdir + slope_tag + "slope_froude_" + end,
485            time_thinning=1)
486
487def find_min_slopes(times, slope_locations, slopes,
488                    anuga_break_times, band_offset):
489    """
490   
491    """
492    bands = break_times2bands(anuga_break_times, band_offset)
493
494    waves = []
495    for i,_ in enumerate(bands[0:-1]):
496        max_q, max_q_times = get_min_in_band(bands[i], bands[i+1],
497                                             times, slopes)
498        waves.append({SLOPE_STR:max_q, TIME_STR:max_q_times})
499    return waves
500
501   
502def get_band(min, max, vector, quantity_array, axis):
503    """
504    Return a band of vector and quantity, within (not including) the
505    min, max.
506
507    For a time band, set the axis to 0.
508    For a location band, set the axis to -1.
509   
510    """
511
512    SMALL_MIN = -1e10  # Not that small, but small enough
513    vector = ensure_numeric(vector)
514    quantity_array = ensure_numeric(quantity_array)
515
516    assert min > SMALL_MIN
517    no_maxs = where(less(vector,max), vector, SMALL_MIN)
518    #print "no_maxs", no_maxs
519    band_condition = greater(no_maxs, min)
520    band_vector = compress(band_condition, vector, axis=axis)
521    #print "band_time", band_time
522    #print "quantity_array", quantity_array.shape
523    band_quantity = compress(band_condition, quantity_array, axis=axis)
524    return band_vector, band_quantity
525
526def get_min_in_band(min_time, max_time, time_vector, quantity_array):
527    """
528    given a quantity array, with the 2nd axis being
529    time, represented by the time_vector, find the minimum within
530    the time band.
531
532    Assumes times are positive
533    """
534   
535    time_vector = ensure_numeric(time_vector)
536    quantity_array = ensure_numeric(quantity_array)
537
538    band_time, band_quantity  = get_band(min_time, max_time,
539                                         time_vector, quantity_array, 0)
540    #print "band_quantity",band_quantity
541    try:
542        max_quantity_indices = argmin(band_quantity, axis=0)
543    except:
544        #print "time_vector", time_vector
545        print "min_time",min_time
546        print "max_time", max_time
547        return [],[]
548       
549    #print "max_quantity_indices", max_quantity_indices
550    max_quantity_times = choose(max_quantity_indices, band_time)
551    #print "max_quantity_times", max_quantity_times
552    max_quantities = choose(max_quantity_indices, band_quantity)
553    #print "max_quantities", max_quantities
554
555    return max_quantities, max_quantity_times
556
557def break_times2bands(break_times, band_offset):
558    """
559    Break_times is a list of times, ascending.
560    bands is a list of times, being the midpoints of break_times, with a min
561    and max band added.
562    """
563    assert len(break_times)>2
564   
565    bands = [] #deepcopy(break_times)
566    bands.append(break_times[0]-0.5*(break_times[1]-break_times[0]))
567
568
569    for i,break_x in enumerate(break_times[0:-1]):
570        bands.append(break_times[i]+0.5*(break_times[i+1]-break_times[i]))
571       
572    bands.append(break_times[-1]+0.5*(break_times[-1]-break_times[-2]))
573    bands = ensure_numeric(bands)
574    bands += band_offset
575    return bands
576
577def plot_foude_slope_stage(wave_file,
578                           break_time,
579                           break_x,
580                           save_as=None,
581                           plot_title="",
582                           is_interactive=False,
583                           break_type="",
584                           froude_min=None,
585                           froude_max=None,
586                           slope_min=None,
587                           slope_max=None):
588    """
589    """
590    from pylab import ion, plot, xlabel, ylabel, close, legend, \
591         savefig, title, axis, setp, subplot, grid, axvspan
592    from anuga.shallow_water.data_manager import csv2dict
593
594
595
596    # Load in the csv files and convert info from strings to floats
597    simulation, _ = csv2dict(wave_file)
598    location = [float(x) for x in simulation['x location']]
599    slope = [float(x) for x in simulation['min slope']]
600    time = [float(x) for x in simulation['Time']]
601    froude = [float(x) for x in simulation['Froude']]
602
603    min_location = min(location)
604    max_location = max(location)
605   
606    if is_interactive:
607        ion()
608    # The upper subplot
609    subplot(311)
610    l_froude = plot(location, froude)
611    #setp(l_froude, color='r')
612
613    # Add axis stuff
614    title(plot_title)
615    y_label = "Froude Number"
616    ylabel(y_label)
617    grid(True)
618    axvspan(break_x-0.001,break_x+0.001, facecolor='g')
619    if froude_min is not None and froude_max is not None:
620        axis(ymin=froude_min, ymax=froude_max)
621   
622    # The slope subplot
623    subplot(312)
624    l_slope = plot(location, slope)
625    setp(l_slope, color='r')
626
627    # Add axis stuff and legend
628    x_label = "X location, m"
629    y_label = "Stage slope"
630    #xlabel(x_label)
631    ylabel(y_label)
632    grid(True)
633    axvspan(break_x-0.001,break_x+0.001, facecolor='g')
634    if slope_min is not None and slope_max is not None:
635        axis(ymin=slope_min, ymax=slope_max )
636
637    # The time, x location subplot
638    subplot(313)
639    l_time = plot(location, time)
640    setp(l_time, color='g')
641    #print "break_x", break_x
642    #print "break_time", break_time
643    plot([break_x], [break_time], 'yo')
644    #plot([break_x-1], [], 'yo')
645
646    # Add axis stuff and legend
647    x_label = "X location, m"
648    y_label = "time, sec"
649    xlabel(x_label)
650    ylabel(y_label)
651    grid(True)
652
653   
654    # The order defines the label
655    #legend((legend_exp, legend_sim),'upper left')
656    #legend(('Wave front'),'upper left')
657   
658    if is_interactive:
659        # Wait for enter pressed
660        raw_input()
661
662    if save_as is not None:
663        savefig(save_as)
664   
665    #Need to close this plot
666    close()
667   
668#-------------------------------------------------------------
669if __name__ == "__main__":
670    """
671    """
672    from scenarios import scenarios
673    #scenarios = [scenarios[0]]
674    outputdir_tag = "_good_tri_area_0.01_limiterD"
675    outputdir_tag = "_good_tri_area_0.001_limiterD"
676    slope_tag = ""
677    #outputdir_tag = "_test_limiterC"
678    #scenarios = [scenarios[0]] # !!!!!!!!!!!!!!!!!!!!!!
679    #scenarios = scenarios[4:] # !!!!!!!!!!!!!!!!!!!!!!
680   
681    #gauges_for_slope(slope_tag, outputdir_tag, scenarios)
682    #auto_graph_slopes(outputdir_tag, scenarios) #, is_interactive=True)
683    #auto_find_min_slopes(slope_tag, outputdir_tag, scenarios)
684    #auto_graph_froudes(outputdir_tag, scenarios)
685    auto_plot_froude_slopes(slope_tag, outputdir_tag, scenarios)
686    #g = Get_file_name(scenarios[0], outputdir_tag, slope_tag)
687    #for wave_file, save_as, wave_number in Get_file_name(
688     #   scenarios[0], outputdir_tag, slope_tag):
689      #  print "**************"
Note: See TracBrowser for help on using the repository browser.