source: anuga_core/source/anuga/abstract_2d_finite_volumes/util.py @ 7679

Last change on this file since 7679 was 7679, checked in by hudson, 14 years ago

Added documentation. Fixes in sww2timeseries.

File size: 64.9 KB
Line 
1"""This module contains various auxiliary function used by pyvolution.
2
3It is also a clearing house for functions that may later earn a module
4of their own.
5"""
6
7import anuga.utilities.polygon
8import sys
9import os
10
11from os import remove, mkdir, access, F_OK, R_OK, W_OK, sep,getcwd
12from os.path import exists, basename, split,join
13from warnings import warn
14from shutil import copy
15
16from anuga.utilities.numerical_tools import ensure_numeric
17
18from math import sqrt, atan, degrees
19
20# FIXME (Ole): Temporary short cuts -
21# FIXME (Ole): remove and update scripts where they are used
22from anuga.utilities.system_tools import get_revision_number
23from anuga.utilities.system_tools import store_version_info
24
25import anuga.utilities.log as log
26
27import numpy as num
28
29
30def file_function(filename,
31                  domain=None,
32                  quantities=None,
33                  interpolation_points=None,
34                  time_thinning=1,
35                  time_limit=None,
36                  verbose=False,
37                  use_cache=False,
38                  boundary_polygon=None,
39                  output_centroids=False):
40    from file_function import file_function as file_function_new
41    return file_function_new(filename, domain, quantities, interpolation_points,
42                      time_thinning, time_limit, verbose, use_cache,
43                      boundary_polygon, output_centroids)
44
45##
46# @brief Replace multiple substrings in a string.
47# @param text The string to operate on.
48# @param dictionary A dict containing replacements, key->value.
49# @return The new string.
50def multiple_replace(text, dictionary):
51    """Multiple replace of words in text
52
53    text:       String to be modified
54    dictionary: Mapping of words that are to be substituted
55
56    Python Cookbook 3.14 page 88 and page 90
57    http://code.activestate.com/recipes/81330/
58    """
59
60    import re
61   
62    #Create a regular expression from all of the dictionary keys
63    #matching only entire words
64    regex = re.compile(r'\b'+ \
65                       r'\b|\b'.join(map(re.escape, dictionary.keys()))+ \
66                       r'\b' )
67
68    #For each match, lookup the corresponding value in the dictionary
69    return regex.sub(lambda match: dictionary[match.group(0)], text)
70
71
72##
73# @brief Apply arbitrary expressions to the values of a dict.
74# @param expression A string expression to apply.
75# @param dictionary The dictionary to apply the expression to.
76def apply_expression_to_dictionary(expression, dictionary):
77    """Apply arbitrary expression to values of dictionary
78
79    Given an expression in terms of the keys, replace key by the
80    corresponding values and evaluate.
81
82    expression: Arbitrary, e.g. arithmetric, expression relating keys
83                from dictionary.
84
85    dictionary: Mapping between symbols in expression and objects that
86                will be evaluated by expression.
87                Values in dictionary must support operators given in
88                expression e.g. by overloading
89
90    Due to a limitation with numeric, this can not evaluate 0/0
91    In general, the user can fix by adding 1e-30 to the numerator.
92    SciPy core can handle this situation.
93    """
94
95    import types
96    import re
97
98    assert isinstance(expression, basestring)
99    assert type(dictionary) == types.DictType
100
101    #Convert dictionary values to textual representations suitable for eval
102    D = {}
103    for key in dictionary:
104        D[key] = 'dictionary["%s"]' % key
105
106    #Perform substitution of variables   
107    expression = multiple_replace(expression, D)
108
109    #Evaluate and return
110    try:
111        return eval(expression)
112    except NameError, e:
113        msg = 'Expression "%s" could not be evaluated: %s' % (expression, e)
114        raise NameError, msg
115    except ValueError, e:
116        msg = 'Expression "%s" could not be evaluated: %s' % (expression, e)
117        raise ValueError, msg
118
119
120##
121# @brief Format a float into a string.
122# @param value Float value to format.
123# @param format The format to use (%.2f is default).
124# @return The formatted float as a string.
125def get_textual_float(value, format = '%.2f'):
126    """Get textual representation of floating point numbers
127    and accept None as valid entry
128
129    format is a string - default = '%.2f'
130    """
131
132    if value is None:
133        return 'None'
134    else:
135        try:
136            float(value)
137        except:
138            # May this is a vector
139            if len(value) > 1:
140                s = '('
141                for v in value:
142                    s += get_textual_float(v, format) + ', '
143                   
144                s = s[:-2] + ')' # Strip trailing comma and close
145                return s
146            else:
147                raise 'Illegal input to get_textual_float:', value
148        else:
149            return format % float(value)
150
151
152#################################################################################
153# OBSOLETE STUFF
154#################################################################################
155
156# @note TEMP
157def angle(v1, v2):
158    """Temporary Interface to new location"""
159
160    import anuga.utilities.numerical_tools as NT       
161   
162    msg = 'angle has moved from util.py.  '
163    msg += 'Please use "from anuga.utilities.numerical_tools import angle"'
164    warn(msg, DeprecationWarning) 
165
166    return NT.angle(v1, v2)
167
168   
169# @note TEMP
170def anglediff(v0, v1):
171    """Temporary Interface to new location"""
172
173    import anuga.utilities.numerical_tools as NT
174   
175    msg = 'anglediff has moved from util.py.  '
176    msg += 'Please use "from anuga.utilities.numerical_tools import anglediff"'
177    warn(msg, DeprecationWarning) 
178
179    return NT.anglediff(v0, v1)   
180
181# @note TEMP
182def point_on_line(*args, **kwargs):
183    """Temporary Interface to new location"""
184
185    msg = 'point_on_line has moved from util.py.  '
186    msg += 'Please use "from anuga.utilities.polygon import point_on_line"'
187    warn(msg, DeprecationWarning) 
188
189    return utilities.polygon.point_on_line(*args, **kwargs)     
190
191   
192# @note TEMP
193def inside_polygon(*args, **kwargs):
194    """Temporary Interface to new location"""
195
196    log.critical('inside_polygon has moved from util.py.')
197    log.critical('Please use '
198                 '"from anuga.utilities.polygon import inside_polygon"')
199
200    return utilities.polygon.inside_polygon(*args, **kwargs)   
201
202   
203# @note TEMP
204def outside_polygon(*args, **kwargs):
205    """Temporary Interface to new location"""
206
207    log.critical('outside_polygon has moved from util.py.')
208    log.critical('Please use '
209                 '"from anuga.utilities.polygon import outside_polygon"')
210
211    return utilities.polygon.outside_polygon(*args, **kwargs)   
212
213
214# @note TEMP
215def separate_points_by_polygon(*args, **kwargs):
216    """Temporary Interface to new location"""
217
218    log.critical('separate_points_by_polygon has moved from util.py.')
219    log.critical('Please use "from anuga.utilities.polygon import '
220                 'separate_points_by_polygon"')
221
222    return utilities.polygon.separate_points_by_polygon(*args, **kwargs)   
223
224
225# @note TEMP
226def read_polygon(*args, **kwargs):
227    """Temporary Interface to new location"""
228
229    log.critical('read_polygon has moved from util.py.')
230    log.critical('Please use '
231                 '"from anuga.utilities.polygon import read_polygon"')
232
233    return utilities.polygon.read_polygon(*args, **kwargs)   
234
235
236# @note TEMP
237def populate_polygon(*args, **kwargs):
238    """Temporary Interface to new location"""
239
240    log.critical('populate_polygon has moved from util.py.')
241    log.critical('Please use '
242                 '"from anuga.utilities.polygon import populate_polygon"')
243
244    return utilities.polygon.populate_polygon(*args, **kwargs)   
245
246
247#################################################################################
248# End of obsolete stuff ?
249#################################################################################
250
251# @note TEMP
252def start_screen_catcher(dir_name, myid='', numprocs='', extra_info='',
253                         verbose=False):
254    """Temporary Interface to new location"""
255    from anuga.shallow_water.data_manager import start_screen_catcher \
256         as dm_start_screen_catcher
257
258    log.critical('start_screen_catcher has moved from util.py.')
259    log.critical('Please use "from anuga.shallow_water.data_manager import '
260                 'start_screen_catcher"')
261   
262    return dm_start_screen_catcher(dir_name, myid='', numprocs='',
263                                   extra_info='', verbose=False)
264
265
266
267##
268# @brief Read gauge info from a file.
269# @param filename The name of the file to read.
270# @return A (gauges, gaugelocation, elev) tuple.
271def get_gauges_from_file(filename):
272    return gauge_get_from_file(filename)
273
274
275##
276# @brief Check that input quantities in quantity list are legal.
277# @param quantity Quantity list to check.
278# @note Raises an exception of list is not legal.
279def check_list(quantity):
280    """ Check that input quantities in quantity list are possible
281    """
282    import sys
283
284    all_quantity = ['stage', 'depth', 'momentum', 'xmomentum',
285                    'ymomentum', 'speed', 'bearing', 'elevation']
286
287    # convert all quanitiy names to lowercase
288    for i,j in enumerate(quantity):
289        quantity[i] = quantity[i].lower()
290
291    # check that all names in 'quantity' appear in 'all_quantity'
292    p = list(set(quantity).difference(set(all_quantity)))
293    if len(p) != 0:
294        msg = 'Quantities %s do not exist - please try again' %p
295        raise Exception, msg
296
297
298##
299# @brief Calculate velocity bearing from North.
300# @param uh ??
301# @param vh ??
302# @return The calculated bearing.
303def calc_bearing(uh, vh):
304    """ Calculate velocity bearing from North
305    """
306    #FIXME (Ole): I reckon we should refactor this one to use
307    #             the function angle() in utilities/numerical_tools
308    #
309    #             It will be a simple matter of
310    # * converting from radians to degrees
311    # * moving the reference direction from [1,0] to North
312    # * changing from counter clockwise to clocwise.
313       
314    angle = degrees(atan(vh/(uh+1.e-15)))
315
316    if (0 < angle < 90.0):
317        if vh > 0:
318            bearing = 90.0 - abs(angle)
319        if vh < 0:
320            bearing = 270.0 - abs(angle)
321   
322    if (-90 < angle < 0):
323        if vh < 0:
324            bearing = 90.0 - (angle)
325        if vh > 0:
326            bearing = 270.0 - (angle)
327    if angle == 0: bearing = 0.0
328
329    return bearing
330
331
332##
333# @brief Generate figures from quantities and gauges for each sww file.
334# @param plot_quantity  ??
335# @param file_loc ??
336# @param report ??
337# @param reportname ??
338# @param surface ??
339# @param leg_label ??
340# @param f_list ??
341# @param gauges ??
342# @param locations ??
343# @param elev ??
344# @param gauge_index ??
345# @param production_dirs ??
346# @param time_min ??
347# @param time_max ??
348# @param time_unit ??
349# @param title_on ??
350# @param label_id ??
351# @param generate_fig ??
352# @param verbose??
353# @return (texfile2, elev_output)
354def generate_figures(plot_quantity, file_loc, report, reportname, surface,
355                     leg_label, f_list, gauges, locations, elev, gauge_index,
356                     production_dirs, time_min, time_max, time_unit,
357                     title_on, label_id, generate_fig, verbose):
358    """ Generate figures based on required quantities and gauges for
359    each sww file
360    """
361    from os import sep, altsep, getcwd, mkdir, access, F_OK, environ
362
363    if generate_fig is True:
364        from pylab import ion, hold, plot, axis, figure, legend, savefig, \
365             xlabel, ylabel, title, close, subplot
366   
367        if surface is True:
368            import pylab as p1
369            import mpl3d.mplot3d as p3
370       
371    if report == True:   
372        texdir = getcwd()+sep+'report'+sep
373        if access(texdir,F_OK) == 0:
374            mkdir (texdir)
375        if len(label_id) == 1:
376            label_id1 = label_id[0].replace(sep,'')
377            label_id2 = label_id1.replace('_','')
378            texfile = texdir + reportname + '%s' % label_id2
379            texfile2 = reportname + '%s' % label_id2
380            texfilename = texfile + '.tex'
381            fid = open(texfilename, 'w')
382
383            if verbose: log.critical('Latex output printed to %s' % texfilename)
384        else:
385            texfile = texdir+reportname
386            texfile2 = reportname
387            texfilename = texfile + '.tex' 
388            fid = open(texfilename, 'w')
389
390            if verbose: log.critical('Latex output printed to %s' % texfilename)
391    else:
392        texfile = ''
393        texfile2 = ''
394
395    p = len(f_list)
396    n = []
397    n0 = 0
398    for i in range(len(f_list)):
399        n.append(len(f_list[i].get_time()))
400        if n[i] > n0: n0 = n[i] 
401    n0 = int(n0)
402    m = len(locations)
403    model_time = num.zeros((n0, m, p), num.float) 
404    stages = num.zeros((n0, m, p), num.float)
405    elevations = num.zeros((n0, m, p), num.float) 
406    momenta = num.zeros((n0, m, p), num.float)
407    xmom = num.zeros((n0, m, p), num.float)
408    ymom = num.zeros((n0, m, p), num.float)
409    speed = num.zeros((n0, m, p), num.float)
410    bearings = num.zeros((n0, m, p), num.float)
411    due_east = 90.0*num.ones((n0, 1), num.float)
412    due_west = 270.0*num.ones((n0, 1), num.float)
413    depths = num.zeros((n0, m, p), num.float)
414    eastings = num.zeros((n0, m, p), num.float)
415    min_stages = []
416    max_stages = []
417    min_momentums = []   
418    max_momentums = []
419    max_xmomentums = []
420    max_ymomentums = []
421    min_xmomentums = []
422    min_ymomentums = []
423    max_speeds = []
424    min_speeds = []   
425    max_depths = []
426    model_time_plot3d = num.zeros((n0, m), num.float)
427    stages_plot3d = num.zeros((n0, m), num.float)
428    eastings_plot3d = num.zeros((n0, m),num.float)
429    if time_unit is 'mins': scale = 60.0
430    if time_unit is 'hours': scale = 3600.0
431
432    ##### loop over each swwfile #####
433    for j, f in enumerate(f_list):
434        if verbose: log.critical('swwfile %d of %d' % (j, len(f_list)))
435
436        starttime = f.starttime
437        comparefile = file_loc[j] + sep + 'gauges_maxmins' + '.csv'
438        fid_compare = open(comparefile, 'w')
439        file0 = file_loc[j] + 'gauges_t0.csv'
440        fid_0 = open(file0, 'w')
441
442        ##### loop over each gauge #####
443        for k in gauge_index:
444            if verbose: log.critical('Gauge %d of %d' % (k, len(gauges)))
445
446            g = gauges[k]
447            min_stage = 10
448            max_stage = 0
449            max_momentum = max_xmomentum = max_ymomentum = 0
450            min_momentum = min_xmomentum = min_ymomentum = 100
451            max_speed = 0
452            min_speed = 0           
453            max_depth = 0           
454            gaugeloc = str(locations[k])
455            thisfile = file_loc[j] + sep + 'gauges_time_series' + '_' \
456                       + gaugeloc + '.csv'
457            if j == 0:
458                fid_out = open(thisfile, 'w')
459                s = 'Time, Stage, Momentum, Speed, Elevation, xmom, ymom, Bearing \n'
460                fid_out.write(s)           
461
462            #### generate quantities #######
463            for i, t in enumerate(f.get_time()):
464                if time_min <= t <= time_max:
465                    w = f(t, point_id = k)[0]
466                    z = f(t, point_id = k)[1]
467                    uh = f(t, point_id = k)[2]
468                    vh = f(t, point_id = k)[3]
469                    depth = w-z     
470                    m = sqrt(uh*uh + vh*vh)
471                    if depth < 0.001:
472                        vel = 0.0
473                    else:
474                        vel = m / (depth + 1.e-6/depth) 
475                    bearing = calc_bearing(uh, vh)                   
476                    model_time[i,k,j] = (t + starttime)/scale #t/60.0
477                    stages[i,k,j] = w
478                    elevations[i,k,j] = z
479                    xmom[i,k,j] = uh
480                    ymom[i,k,j] = vh
481                    momenta[i,k,j] = m
482                    speed[i,k,j] = vel
483                    bearings[i,k,j] = bearing
484                    depths[i,k,j] = depth
485                    thisgauge = gauges[k]
486                    eastings[i,k,j] = thisgauge[0]
487                    s = '%.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f,\n' \
488                            % (t, w, m, vel, z, uh, vh, bearing)
489                    fid_out.write(s)
490                    if t == 0:
491                        s = '%.2f, %.2f, %.2f\n' % (g[0], g[1], w)
492                        fid_0.write(s)
493                    if t/60.0 <= 13920: tindex = i
494                    if w > max_stage: max_stage = w
495                    if w < min_stage: min_stage = w
496                    if m > max_momentum: max_momentum = m
497                    if m < min_momentum: min_momentum = m                   
498                    if uh > max_xmomentum: max_xmomentum = uh
499                    if vh > max_ymomentum: max_ymomentum = vh
500                    if uh < min_xmomentum: min_xmomentum = uh
501                    if vh < min_ymomentum: min_ymomentum = vh
502                    if vel > max_speed: max_speed = vel
503                    if vel < min_speed: min_speed = vel                   
504                    if z > 0 and depth > max_depth: max_depth = depth
505                   
506                   
507            s = '%.2f, %.2f, %.2f, %.2f, %s\n' \
508                    % (max_stage, min_stage, z, thisgauge[0], leg_label[j])
509            fid_compare.write(s)
510            max_stages.append(max_stage)
511            min_stages.append(min_stage)
512            max_momentums.append(max_momentum)
513            max_xmomentums.append(max_xmomentum)
514            max_ymomentums.append(max_ymomentum)
515            min_xmomentums.append(min_xmomentum)
516            min_ymomentums.append(min_ymomentum)
517            min_momentums.append(min_momentum)           
518            max_depths.append(max_depth)
519            max_speeds.append(max_speed)
520            min_speeds.append(min_speed)           
521            #### finished generating quantities for each swwfile #####
522       
523        model_time_plot3d[:,:] = model_time[:,:,j]
524        stages_plot3d[:,:] = stages[:,:,j]
525        eastings_plot3d[:,] = eastings[:,:,j]
526           
527        if surface is True:
528            log.critical('Printing surface figure')
529            for i in range(2):
530                fig = p1.figure(10)
531                ax = p3.Axes3D(fig)
532                if len(gauges) > 80:
533                    ax.plot_surface(model_time[:,:,j],
534                                    eastings[:,:,j],
535                                    stages[:,:,j])
536                else:
537                    ax.plot3D(num.ravel(eastings[:,:,j]),
538                              num.ravel(model_time[:,:,j]),
539                              num.ravel(stages[:,:,j]))
540                ax.set_xlabel('time')
541                ax.set_ylabel('x')
542                ax.set_zlabel('stage')
543                fig.add_axes(ax)
544                p1.show()
545                surfacefig = 'solution_surface%s' % leg_label[j]
546                p1.savefig(surfacefig)
547                p1.close()
548           
549    #### finished generating quantities for all swwfiles #####
550
551    # x profile for given time
552    if surface is True:
553        figure(11)
554        plot(eastings[tindex,:,j], stages[tindex,:,j])
555        xlabel('x')
556        ylabel('stage')
557        profilefig = 'solution_xprofile' 
558        savefig('profilefig')
559
560    elev_output = []
561    if generate_fig is True:
562        depth_axis = axis([starttime/scale, time_max/scale, -0.1,
563                           max(max_depths)*1.1])
564        stage_axis = axis([starttime/scale, time_max/scale,
565                           min(min_stages), max(max_stages)*1.1])
566        vel_axis = axis([starttime/scale, time_max/scale,
567                         min(min_speeds), max(max_speeds)*1.1])
568        mom_axis = axis([starttime/scale, time_max/scale,
569                         min(min_momentums), max(max_momentums)*1.1])
570        xmom_axis = axis([starttime/scale, time_max/scale,
571                          min(min_xmomentums), max(max_xmomentums)*1.1])
572        ymom_axis = axis([starttime/scale, time_max/scale,
573                          min(min_ymomentums), max(max_ymomentums)*1.1])
574        cstr = ['g', 'r', 'b', 'c', 'm', 'y', 'k']
575        nn = len(plot_quantity)
576        no_cols = 2
577       
578        if len(label_id) > 1: graphname_report = []
579        pp = 1
580        div = 11.
581        cc = 0
582        for k in gauge_index:
583            g = gauges[k]
584            count1 = 0
585            if report == True and len(label_id) > 1:
586                s = '\\begin{figure}[ht] \n' \
587                    '\\centering \n' \
588                    '\\begin{tabular}{cc} \n'
589                fid.write(s)
590            if len(label_id) > 1: graphname_report = []
591
592            #### generate figures for each gauge ####
593            for j, f in enumerate(f_list):
594                ion()
595                hold(True)
596                count = 0
597                where1 = 0
598                where2 = 0
599                word_quantity = ''
600                if report == True and len(label_id) == 1:
601                    s = '\\begin{figure}[hbt] \n' \
602                        '\\centering \n' \
603                        '\\begin{tabular}{cc} \n'
604                    fid.write(s)
605                   
606                for which_quantity in plot_quantity:
607                    count += 1
608                    where1 += 1
609                    figure(count, frameon = False)
610                    if which_quantity == 'depth':
611                        plot(model_time[0:n[j]-1,k,j],
612                             depths[0:n[j]-1,k,j], '-', c = cstr[j])
613                        units = 'm'
614                        axis(depth_axis)
615                    if which_quantity == 'stage':
616                        if elevations[0,k,j] <= 0:
617                            plot(model_time[0:n[j]-1,k,j],
618                                 stages[0:n[j]-1,k,j], '-', c = cstr[j])
619                            axis(stage_axis)
620                        else:
621                            plot(model_time[0:n[j]-1,k,j],
622                                 depths[0:n[j]-1,k,j], '-', c = cstr[j])
623                            #axis(depth_axis)                 
624                        units = 'm'
625                    if which_quantity == 'momentum':
626                        plot(model_time[0:n[j]-1,k,j],
627                             momenta[0:n[j]-1,k,j], '-', c = cstr[j])
628                        axis(mom_axis)
629                        units = 'm^2 / sec'
630                    if which_quantity == 'xmomentum':
631                        plot(model_time[0:n[j]-1,k,j],
632                             xmom[0:n[j]-1,k,j], '-', c = cstr[j])
633                        axis(xmom_axis)
634                        units = 'm^2 / sec'
635                    if which_quantity == 'ymomentum':
636                        plot(model_time[0:n[j]-1,k,j],
637                             ymom[0:n[j]-1,k,j], '-', c = cstr[j])
638                        axis(ymom_axis)
639                        units = 'm^2 / sec'
640                    if which_quantity == 'speed':
641                        plot(model_time[0:n[j]-1,k,j],
642                             speed[0:n[j]-1,k,j], '-', c = cstr[j])
643                        axis(vel_axis)
644                        units = 'm / sec'
645                    if which_quantity == 'bearing':
646                        plot(model_time[0:n[j]-1,k,j],bearings[0:n[j]-1,k,j],'-',
647                             model_time[0:n[j]-1,k,j], due_west[0:n[j]-1], '-.', 
648                             model_time[0:n[j]-1,k,j], due_east[0:n[j]-1], '-.')
649                        units = 'degrees from North'
650                        #ax = axis([time_min, time_max, 0.0, 360.0])
651                        legend(('Bearing','West','East'))
652
653                    if time_unit is 'mins': xlabel('time (mins)')
654                    if time_unit is 'hours': xlabel('time (hours)')
655                    #if which_quantity == 'stage' \
656                    #   and elevations[0:n[j]-1,k,j] > 0:
657                    #    ylabel('%s (%s)' %('depth', units))
658                    #else:
659                    #    ylabel('%s (%s)' %(which_quantity, units))
660                        #ylabel('%s (%s)' %('wave height', units))
661                    ylabel('%s (%s)' %(which_quantity, units))
662                    if len(label_id) > 1: legend((leg_label),loc='upper right')
663
664                    #gaugeloc1 = gaugeloc.replace(' ','')
665                    #gaugeloc2 = gaugeloc1.replace('_','')
666                    gaugeloc2 = str(locations[k]).replace(' ','')
667                    graphname = '%sgauge%s_%s' %(file_loc[j],
668                                                 gaugeloc2,
669                                                 which_quantity)
670
671                    if report == True and len(label_id) > 1:
672                        figdir = getcwd()+sep+'report_figures'+sep
673                        if access(figdir,F_OK) == 0 :
674                            mkdir (figdir)
675                        latex_file_loc = figdir.replace(sep,altsep) 
676                        # storing files in production directory   
677                        graphname_latex = '%sgauge%s%s' \
678                                          % (latex_file_loc, gaugeloc2,
679                                             which_quantity)
680                        # giving location in latex output file
681                        graphname_report_input = '%sgauge%s%s' % \
682                                                 ('..' + altsep + 
683                                                      'report_figures' + altsep,
684                                                  gaugeloc2, which_quantity)
685                        graphname_report.append(graphname_report_input)
686                       
687                        # save figures in production directory for report
688                        savefig(graphname_latex)
689
690                    if report == True:
691                        figdir = getcwd() + sep + 'report_figures' + sep
692                        if access(figdir,F_OK) == 0:
693                            mkdir(figdir)
694                        latex_file_loc = figdir.replace(sep,altsep)   
695
696                        if len(label_id) == 1: 
697                            # storing files in production directory 
698                            graphname_latex = '%sgauge%s%s%s' % \
699                                              (latex_file_loc, gaugeloc2,
700                                               which_quantity, label_id2)
701                            # giving location in latex output file
702                            graphname_report = '%sgauge%s%s%s' % \
703                                               ('..' + altsep +
704                                                    'report_figures' + altsep,
705                                                gaugeloc2, which_quantity,
706                                                label_id2)
707                            s = '\includegraphics' \
708                                '[width=0.49\linewidth, height=50mm]{%s%s}' % \
709                                (graphname_report, '.png')
710                            fid.write(s)
711                            if where1 % 2 == 0:
712                                s = '\\\\ \n'
713                                where1 = 0
714                            else:
715                                s = '& \n'
716                            fid.write(s)
717                            savefig(graphname_latex)
718                   
719                    if title_on == True:
720                        title('%s scenario: %s at %s gauge' % \
721                              (label_id, which_quantity, gaugeloc2))
722                        #title('Gauge %s (MOST elevation %.2f, ' \
723                        #      'ANUGA elevation %.2f)' % \
724                        #      (gaugeloc2, elevations[10,k,0],
725                        #       elevations[10,k,1]))
726
727                    savefig(graphname) # save figures with sww file
728
729                if report == True and len(label_id) == 1:
730                    for i in range(nn-1):
731                        if nn > 2:
732                            if plot_quantity[i] == 'stage' \
733                               and elevations[0,k,j] > 0:
734                                word_quantity += 'depth' + ', '
735                            else:
736                                word_quantity += plot_quantity[i] + ', '
737                        else:
738                            if plot_quantity[i] == 'stage' \
739                               and elevations[0,k,j] > 0:
740                                word_quantity += 'depth' + ', '
741                            else:
742                                word_quantity += plot_quantity[i]
743                       
744                    if plot_quantity[nn-1] == 'stage' and elevations[0,k,j] > 0:
745                        word_quantity += ' and ' + 'depth'
746                    else:
747                        word_quantity += ' and ' + plot_quantity[nn-1]
748                    caption = 'Time series for %s at %s location ' \
749                              '(elevation %.2fm)' % \
750                              (word_quantity, locations[k], elev[k])
751                    if elev[k] == 0.0:
752                        caption = 'Time series for %s at %s location ' \
753                                  '(elevation %.2fm)' % \
754                                  (word_quantity, locations[k],
755                                   elevations[0,k,j])
756                        east = gauges[0]
757                        north = gauges[1]
758                        elev_output.append([locations[k], east, north,
759                                            elevations[0,k,j]])
760                    label = '%sgauge%s' % (label_id2, gaugeloc2)
761                    s = '\end{tabular} \n' \
762                        '\\caption{%s} \n' \
763                        '\label{fig:%s} \n' \
764                        '\end{figure} \n \n' % (caption, label)
765                    fid.write(s)
766                    cc += 1
767                    if cc % 6 == 0: fid.write('\\clearpage \n')
768                    savefig(graphname_latex)               
769                   
770            if report == True and len(label_id) > 1:
771                for i in range(nn-1):
772                    if nn > 2:
773                        if plot_quantity[i] == 'stage' and elevations[0,k,j] > 0:
774                            word_quantity += 'depth' + ','
775                        else:
776                            word_quantity += plot_quantity[i] + ', '
777                    else:
778                        if plot_quantity[i] == 'stage' and elevations[0,k,j] > 0:
779                            word_quantity += 'depth'
780                        else:
781                            word_quantity += plot_quantity[i]
782                    where1 = 0
783                    count1 += 1
784                    index = j*len(plot_quantity)
785                    for which_quantity in plot_quantity:
786                        where1 += 1
787                        s = '\includegraphics' \
788                            '[width=0.49\linewidth, height=50mm]{%s%s}' % \
789                            (graphname_report[index], '.png')
790                        index += 1
791                        fid.write(s)
792                        if where1 % 2 == 0:
793                            s = '\\\\ \n'
794                            where1 = 0
795                        else:
796                            s = '& \n'
797                        fid.write(s)
798                word_quantity += ' and ' + plot_quantity[nn-1]           
799                label = 'gauge%s' %(gaugeloc2) 
800                caption = 'Time series for %s at %s location ' \
801                          '(elevation %.2fm)' % \
802                          (word_quantity, locations[k], elev[k])
803                if elev[k] == 0.0:
804                        caption = 'Time series for %s at %s location ' \
805                                  '(elevation %.2fm)' % \
806                                  (word_quantity, locations[k],
807                                   elevations[0,k,j])
808                        thisgauge = gauges[k]
809                        east = thisgauge[0]
810                        north = thisgauge[1]
811                        elev_output.append([locations[k], east, north,
812                                            elevations[0,k,j]])
813                       
814                s = '\end{tabular} \n' \
815                    '\\caption{%s} \n' \
816                    '\label{fig:%s} \n' \
817                    '\end{figure} \n \n' % (caption, label)
818                fid.write(s)
819                if float((k+1)/div - pp) == 0.:
820                    fid.write('\\clearpage \n')
821                    pp += 1
822                #### finished generating figures ###
823
824            close('all')
825       
826    return texfile2, elev_output
827
828
829# FIXME (DSG): Add unit test, make general, not just 2 files,
830# but any number of files.
831##
832# @brief ??
833# @param dir_name ??
834# @param filename1 ??
835# @param filename2 ??
836# @return ??
837# @note TEMP
838def copy_code_files(dir_name, filename1, filename2):
839    """Temporary Interface to new location"""
840
841    from anuga.shallow_water.data_manager import \
842                    copy_code_files as dm_copy_code_files
843    log.critical('copy_code_files has moved from util.py.')
844    log.critical('Please use "from anuga.shallow_water.data_manager import '
845                 'copy_code_files"')
846   
847    return dm_copy_code_files(dir_name, filename1, filename2)
848
849
850##
851# @brief Create a nested sub-directory path.
852# @param root_directory The base diretory path.
853# @param directories An iterable of sub-directory names.
854# @return The final joined directory path.
855# @note If each sub-directory doesn't exist, it will be created.
856def add_directories(root_directory, directories):
857    """
858    Add the first sub-directory in 'directories' to root_directory.
859    Then add the second sub-directory to the accumulating path and so on.
860
861    Return the path of the final directory.
862
863    This is handy for specifying and creating a directory where data will go.
864    """
865    dir = root_directory
866    for new_dir in directories:
867        dir = os.path.join(dir, new_dir)
868        if not access(dir,F_OK):
869            mkdir(dir)
870    return dir
871
872
873##
874# @brief
875# @param filename
876# @param separator_value
877# @return
878# @note TEMP
879def get_data_from_file(filename, separator_value=','):
880    """Temporary Interface to new location"""
881    from anuga.shallow_water.data_manager import \
882                        get_data_from_file as dm_get_data_from_file
883    log.critical('get_data_from_file has moved from util.py')
884    log.critical('Please use "from anuga.shallow_water.data_manager import '
885                 'get_data_from_file"')
886   
887    return dm_get_data_from_file(filename,separator_value = ',')
888
889
890##
891# @brief
892# @param verbose
893# @param kwargs
894# @return
895# @note TEMP
896def store_parameters(verbose=False,**kwargs):
897    """Temporary Interface to new location"""
898   
899    from anuga.shallow_water.data_manager \
900                    import store_parameters as dm_store_parameters
901    log.critical('store_parameters has moved from util.py.')
902    log.critical('Please use "from anuga.shallow_water.data_manager '
903                 'import store_parameters"')
904   
905    return dm_store_parameters(verbose=False,**kwargs)
906
907
908##
909# @brief Remove vertices that are not associated with any triangle.
910# @param verts An iterable (or array) of points.
911# @param triangles An iterable of 3 element tuples.
912# @param number_of_full_nodes ??
913# @return (verts, triangles) where 'verts' has been updated.
914def remove_lone_verts(verts, triangles, number_of_full_nodes=None):
915    """Removes vertices that are not associated with any triangles.
916
917    verts is a list/array of points.
918    triangles is a list of 3 element tuples.  Each tuple represents a triangle.
919    number_of_full_nodes relate to parallelism when a mesh has an
920        extra layer of ghost points.
921    """
922
923    verts = ensure_numeric(verts)
924    triangles = ensure_numeric(triangles)
925   
926    N = len(verts)
927   
928    # initialise the array to easily find the index of the first loner
929    # ie, if N=3 -> [6,5,4]
930    loners=num.arange(2*N, N, -1)
931    for t in triangles:
932        for vert in t:
933            loners[vert]= vert # all non-loners will have loners[i]=i
934
935    lone_start = 2*N - max(loners) # The index of the first loner
936
937    if lone_start-1 == N:
938        # no loners
939        pass
940    elif min(loners[lone_start:N]) > N:
941        # All the loners are at the end of the vert array
942        verts = verts[0:lone_start]
943    else:
944        # change the loners list so it can be used to modify triangles
945        # Remove the loners from verts
946        # Could've used X=compress(less(loners,N),loners)
947        # verts=num.take(verts,X,axis=0)  to Remove the loners from verts
948        # but I think it would use more memory
949        new_i = lone_start      # point at first loner - 'shuffle down' target
950        for i in range(lone_start, N):
951            if loners[i] >= N:  # [i] is a loner, leave alone
952                pass
953            else:               # a non-loner, move down
954                loners[i] = new_i
955                verts[new_i] = verts[i]
956                new_i += 1
957        verts = verts[0:new_i]
958
959        # Modify the triangles
960        triangles = num.choose(triangles,loners)
961    return verts, triangles
962
963
964##
965# @brief Compute centroid values from vertex values
966# @param x Values at vertices of triangular mesh.
967# @param triangles Nx3 integer array pointing to vertex information.
968# @return [N] array of centroid values.
969def get_centroid_values(x, triangles):
970    """Compute centroid values from vertex values
971   
972    x: Values at vertices of triangular mesh
973    triangles: Nx3 integer array pointing to vertex information
974    for each of the N triangels. Elements of triangles are
975    indices into x
976    """
977       
978    xc = num.zeros(triangles.shape[0], num.float) # Space for centroid info
979   
980    for k in range(triangles.shape[0]):
981        # Indices of vertices
982        i0 = triangles[k][0]
983        i1 = triangles[k][1]
984        i2 = triangles[k][2]       
985       
986        xc[k] = (x[i0] + x[i1] + x[i2])/3
987
988    return xc
989
990
991# @note TEMP
992def make_plots_from_csv_file(directories_dic={dir:['gauge', 0, 0]},
993                                output_dir='',
994                                base_name='',
995                                plot_numbers=['3-5'],
996                                quantities=['speed','stage','momentum'],
997                                assess_all_csv_files=True,
998                                extra_plot_name='test'):
999
1000    msg = 'make_plots_from_csv_file has been replaced by csv2timeseries_graphs '
1001    msg += 'Please use "from anuga.abstract_2d_finite_volumes.util import ' \
1002           'csv2timeseries_graphs"'
1003    raise Exception, msg
1004
1005    return csv2timeseries_graphs(directories_dic,
1006                                 output_dir,
1007                                 base_name,
1008                                 plot_numbers,
1009                                 quantities,
1010                                 extra_plot_name,
1011                                 assess_all_csv_files)
1012
1013
1014##
1015# @brief Plot time series from CSV files.
1016# @param directories_dic
1017# @param output_dir
1018# @param base_name
1019# @param plot_numbers
1020# @param quantities
1021# @param extra_plot_name
1022# @param assess_all_csv_files
1023# @param create_latex
1024# @param verbose
1025# @note Assumes that 'elevation' is in the CSV file(s).
1026def csv2timeseries_graphs(directories_dic={},
1027                          output_dir='',
1028                          base_name=None,
1029                          plot_numbers='',
1030                          quantities=['stage'],
1031                          extra_plot_name='',
1032                          assess_all_csv_files=True,
1033                          create_latex=False,
1034                          verbose=False):
1035                               
1036    """
1037    Read in csv files that have the right header information and
1038    plot time series such as Stage, Speed, etc. Will also plot several
1039    time series on one plot. Filenames must follow this convention,
1040    <base_name><plot_number>.csv eg gauge_timeseries3.csv
1041   
1042    NOTE: relies that 'elevation' is in the csv file!
1043
1044    Each file represents a location and within each file there are
1045    time, quantity columns.
1046   
1047    For example:   
1048    if "directories_dic" defines 4 directories and in each directories
1049    there is a csv files corresponding to the right "plot_numbers",
1050    this will create a plot with 4 lines one for each directory AND
1051    one plot for each "quantities".  ??? FIXME: unclear.
1052   
1053    Usage:
1054        csv2timeseries_graphs(directories_dic={'slide'+sep:['Slide',0, 0],
1055                                       'fixed_wave'+sep:['Fixed Wave',0,0]},
1056                            output_dir='fixed_wave'+sep,
1057                            base_name='gauge_timeseries_',
1058                            plot_numbers='',
1059                            quantities=['stage','speed'],
1060                            extra_plot_name='',
1061                            assess_all_csv_files=True,                           
1062                            create_latex=False,
1063                            verbose=True)
1064            this will create one plot for stage with both 'slide' and
1065            'fixed_wave' lines on it for stage and speed for each csv
1066            file with 'gauge_timeseries_' as the prefix. The graghs
1067            will be in the output directory 'fixed_wave' and the graph
1068            axis will be determined by assessing all the
1069   
1070    ANOTHER EXAMPLE
1071        new_csv2timeseries_graphs(directories_dic={'slide'+sep:['Slide',0, 0],
1072                                       'fixed_wave'+sep:['Fixed Wave',0,0]},
1073                            output_dir='fixed_wave'+sep,
1074                            base_name='gauge_timeseries_',
1075                            plot_numbers=['1-3'],
1076                            quantities=['stage','speed'],
1077                            extra_plot_name='',
1078                            assess_all_csv_files=False,                           
1079                            create_latex=False,
1080                            verbose=True)
1081        This will plot csv files called gauge_timeseries_1.csv and
1082        gauge_timeseries3.csv from both 'slide' and 'fixed_wave' directories
1083        to 'fixed_wave'. There will be 4 plots created two speed and two stage
1084        one for each csv file. There will be two lines on each of these plots.
1085        And the axis will have been determined from only these files, had
1086        assess_all_csv_files = True all csv file with 'gauges_timeseries_' prefix
1087        would of been assessed.
1088   
1089    ANOTHER EXAMPLE   
1090         csv2timeseries_graphs({'J:'+sep+'anuga_validation'+sep:['new',20,-.1],
1091                                   'J:'+sep+'conical_island'+sep:['test',0,0]},
1092                                   output_dir='',
1093                                   plot_numbers=['1','3'],
1094                                   quantities=['stage','depth','bearing'],
1095                                   base_name='gauge_b',
1096                                   assess_all_csv_files=True,
1097                                  verbose=True)   
1098       
1099            This will produce one plot for each quantity (therefore 3) in the
1100            current directory, each plot will have 2 lines on them. The first
1101            plot named 'new' will have the time offseted by 20secs and the stage
1102            height adjusted by -0.1m
1103       
1104    Inputs:
1105        directories_dic: dictionary of directory with values (plot
1106                         legend name for directory), (start time of
1107                         the time series) and the (value to add to
1108                         stage if needed). For example
1109                         {dir1:['Anuga_ons',5000, 0],
1110                          dir2:['b_emoth',5000,1.5],
1111                          dir3:['b_ons',5000,1.5]}
1112                         Having multiple directories defined will plot them on
1113                         one plot, therefore there will be 3 lines on each of
1114                         these plot. If you only want one line per plot call
1115                         csv2timeseries_graph separately for each directory,
1116                         eg only have one directory in the 'directories_dic' in
1117                         each call.
1118                         
1119        output_dir: directory for the plot outputs. Only important to define when
1120                    you have more than one directory in your directories_dic, if
1121                    you have not defined it and you have multiple directories in
1122                    'directories_dic' there will be plots in each directory,
1123                    however only one directory will contain the complete
1124                    plot/graphs.
1125       
1126        base_name: Is used a couple of times.
1127                   1) to find the csv files to be plotted if there is no
1128                      'plot_numbers' then csv files with 'base_name' are plotted
1129                   2) in the title of the plots, the length of base_name is
1130                      removed from the front of the filename to be used in the
1131                      title.
1132                   This could be changed if needed.
1133                   Note is ignored if assess_all_csv_files=True
1134       
1135        plot_numbers: a String list of numbers to plot. For example
1136                      [0-4,10,15-17] will read and attempt to plot
1137                      the follow 0,1,2,3,4,10,15,16,17
1138                      NOTE: if no plot numbers this will create one plot per
1139                            quantity, per gauge
1140
1141        quantities: Will get available quantities from the header in the csv
1142                    file.  Quantities must be one of these.
1143                    NOTE: ALL QUANTITY NAMES MUST BE lower case!
1144                   
1145        extra_plot_name: A string that is appended to the end of the
1146                         output filename.
1147                   
1148        assess_all_csv_files: if true it will read ALL csv file with
1149                             "base_name", regardless of 'plot_numbers'
1150                              and determine a uniform set of axes for
1151                              Stage, Speed and Momentum. IF FALSE it
1152                              will only read the csv file within the
1153                             'plot_numbers'
1154                             
1155        create_latex: NOT IMPLEMENTED YET!! sorry Jane....
1156       
1157    OUTPUTS: saves the plots to
1158              <output_dir><base_name><plot_number><extra_plot_name>.png
1159    """
1160
1161    try: 
1162        import pylab
1163    except ImportError:
1164        msg='csv2timeseries_graphs needs pylab to be installed correctly'
1165        raise msg
1166            #ANUGA don't need pylab to work so the system doesn't
1167            #rely on pylab being installed
1168        return
1169
1170    from os import sep
1171    from anuga.shallow_water.data_manager import \
1172                               get_all_files_with_extension, csv2dict
1173
1174    seconds_in_hour = 3600
1175    seconds_in_minutes = 60
1176   
1177    quantities_label={}
1178#    quantities_label['time'] = 'time (hours)'
1179    quantities_label['time'] = 'time (minutes)'
1180    quantities_label['stage'] = 'wave height (m)'
1181    quantities_label['speed'] = 'speed (m/s)'
1182    quantities_label['momentum'] = 'momentum (m^2/sec)'
1183    quantities_label['depth'] = 'water depth (m)'
1184    quantities_label['xmomentum'] = 'momentum (m^2/sec)'
1185    quantities_label['ymomentum'] = 'momentum (m^2/sec)'
1186    quantities_label['bearing'] = 'degrees (o)'
1187    quantities_label['elevation'] = 'elevation (m)'
1188   
1189    if extra_plot_name != '':
1190        extra_plot_name = '_' + extra_plot_name
1191
1192    new_plot_numbers=[]
1193    #change plot_numbers to list, eg ['0-4','10']
1194    #to ['0','1','2','3','4','10']
1195    for i, num_string in enumerate(plot_numbers):
1196        if '-' in num_string: 
1197            start = int(num_string[:num_string.rfind('-')])
1198            end = int(num_string[num_string.rfind('-') + 1:]) + 1
1199            for x in range(start, end):
1200                new_plot_numbers.append(str(x))
1201        else:
1202            new_plot_numbers.append(num_string)
1203
1204    #finds all the files that fit the specs provided and return a list of them
1205    #so to help find a uniform max and min for the plots...
1206    list_filenames=[]
1207    all_csv_filenames=[]
1208    if verbose: log.critical('Determining files to access for axes ranges.')
1209   
1210    for i,directory in enumerate(directories_dic.keys()):
1211        all_csv_filenames.append(get_all_files_with_extension(directory,
1212                                                              base_name, '.csv'))
1213
1214        filenames=[]
1215        if plot_numbers == '': 
1216            list_filenames.append(get_all_files_with_extension(directory,
1217                                                               base_name,'.csv'))
1218        else:
1219            for number in new_plot_numbers:
1220                filenames.append(base_name + number)
1221            list_filenames.append(filenames)
1222
1223    #use all the files to get the values for the plot axis
1224    max_start_time= -1000.
1225    min_start_time = 100000 
1226   
1227    if verbose: log.critical('Determining uniform axes')
1228
1229    #this entire loop is to determine the min and max range for the
1230    #axes of the plots
1231
1232#    quantities.insert(0,'elevation')
1233    quantities.insert(0,'time')
1234
1235    directory_quantity_value={}
1236#    quantity_value={}
1237    min_quantity_value={}
1238    max_quantity_value={}
1239
1240    for i, directory in enumerate(directories_dic.keys()):
1241        filename_quantity_value = {}
1242        if assess_all_csv_files == False:
1243            which_csv_to_assess = list_filenames[i]
1244        else:
1245            #gets list of filenames for directory "i"
1246            which_csv_to_assess = all_csv_filenames[i]
1247       
1248        for j, filename in enumerate(which_csv_to_assess):
1249            quantity_value = {}
1250
1251            dir_filename = join(directory,filename)
1252            attribute_dic, title_index_dic = csv2dict(dir_filename + '.csv')
1253            directory_start_time = directories_dic[directory][1]
1254            directory_add_tide = directories_dic[directory][2]
1255
1256            if verbose: log.critical('reading: %s.csv' % dir_filename)
1257
1258            #add time to get values
1259            for k, quantity in enumerate(quantities):
1260                quantity_value[quantity] = [float(x) for
1261                                                x in attribute_dic[quantity]]
1262
1263                #add tide to stage if provided
1264                if quantity == 'stage':
1265                     quantity_value[quantity] = num.array(quantity_value[quantity],
1266                                                          num.float) + directory_add_tide
1267
1268                #condition to find max and mins for all the plots
1269                # populate the list with something when i=0 and j=0 and
1270                # then compare to the other values to determine abs max and min
1271                if i==0 and j==0:
1272                    min_quantity_value[quantity], \
1273                        max_quantity_value[quantity] = \
1274                            get_min_max_values(quantity_value[quantity])
1275
1276                    if quantity != 'time':
1277                        min_quantity_value[quantity] = \
1278                            min_quantity_value[quantity] *1.1
1279                        max_quantity_value[quantity] = \
1280                            max_quantity_value[quantity] *1.1
1281                else:
1282                    min, max = get_min_max_values(quantity_value[quantity])
1283               
1284                    # min and max are multipled by "1+increase_axis" to get axes
1285                    # that are slighty bigger than the max and mins
1286                    # so the plots look good.
1287
1288                    increase_axis = (max-min)*0.05
1289                    if min <= min_quantity_value[quantity]:
1290                        if quantity == 'time': 
1291                            min_quantity_value[quantity] = min
1292                        else:
1293                            if round(min,2) == 0.00:
1294                                min_quantity_value[quantity] = -increase_axis
1295#                                min_quantity_value[quantity] = -2.
1296                                #min_quantity_value[quantity] = \
1297                                #    -max_quantity_value[quantity]*increase_axis
1298                            else:
1299#                                min_quantity_value[quantity] = \
1300#                                    min*(1+increase_axis)
1301                                min_quantity_value[quantity]=min-increase_axis
1302                   
1303                    if max > max_quantity_value[quantity]: 
1304                        if quantity == 'time': 
1305                            max_quantity_value[quantity] = max
1306                        else:
1307                            max_quantity_value[quantity] = max + increase_axis
1308#                            max_quantity_value[quantity]=max*(1+increase_axis)
1309
1310            #set the time... ???
1311            if min_start_time > directory_start_time: 
1312                min_start_time = directory_start_time
1313            if max_start_time < directory_start_time: 
1314                max_start_time = directory_start_time
1315           
1316            filename_quantity_value[filename]=quantity_value
1317           
1318        directory_quantity_value[directory]=filename_quantity_value
1319   
1320    #final step to unifrom axis for the graphs
1321    quantities_axis={}
1322   
1323    for i, quantity in enumerate(quantities):
1324        quantities_axis[quantity] = (float(min_start_time) \
1325                                         / float(seconds_in_minutes),
1326                                     (float(max_quantity_value['time']) \
1327                                          + float(max_start_time)) \
1328                                              / float(seconds_in_minutes),
1329                                     min_quantity_value[quantity],
1330                                     max_quantity_value[quantity])
1331
1332        if verbose and (quantity != 'time' and quantity != 'elevation'): 
1333            log.critical('axis for quantity %s are x:(%s to %s)%s '
1334                         'and y:(%s to %s)%s' 
1335                         % (quantity, quantities_axis[quantity][0],
1336                            quantities_axis[quantity][1],
1337                            quantities_label['time'],
1338                            quantities_axis[quantity][2],
1339                            quantities_axis[quantity][3],
1340                            quantities_label[quantity]))
1341
1342    cstr = ['b', 'r', 'g', 'c', 'm', 'y', 'k']
1343
1344    if verbose: log.critical('Now start to plot')
1345   
1346    i_max = len(directories_dic.keys())
1347    legend_list_dic = {}
1348    legend_list = []
1349    for i, directory in enumerate(directories_dic.keys()):
1350        if verbose: log.critical('Plotting in %s %s'
1351                                 % (directory, new_plot_numbers))
1352
1353        # FIXME THIS SORT IS VERY IMPORTANT
1354        # Without it the assigned plot numbers may not work correctly
1355        # there must be a better way
1356        list_filenames[i].sort()
1357        for j, filename in enumerate(list_filenames[i]):
1358            if verbose: log.critical('Starting %s' % filename)
1359
1360            directory_name = directories_dic[directory][0]
1361            directory_start_time = directories_dic[directory][1]
1362            directory_add_tide = directories_dic[directory][2]
1363           
1364            # create an if about the start time and tide height if don't exist
1365            attribute_dic, title_index_dic = csv2dict(directory + sep
1366                                                      + filename + '.csv')
1367            #get data from dict in to list
1368            #do maths to list by changing to array
1369            t = (num.array(directory_quantity_value[directory][filename]['time'])
1370                     + directory_start_time) / seconds_in_minutes
1371
1372            #finds the maximum elevation, used only as a test
1373            # and as info in the graphs
1374            max_ele=-100000
1375            min_ele=100000
1376            elevation = [float(x) for x in attribute_dic["elevation"]]
1377           
1378            min_ele, max_ele = get_min_max_values(elevation)
1379           
1380            if min_ele != max_ele:
1381                log.critical("Note! Elevation changes in %s" % dir_filename)
1382
1383            # creates a dictionary with keys that is the filename and attributes
1384            # are a list of lists containing 'directory_name' and 'elevation'.
1385            # This is used to make the contents for the legends in the graphs,
1386            # this is the name of the model and the elevation.  All in this
1387            # great one liner from DG. If the key 'filename' doesn't exist it
1388            # creates the entry if the entry exist it appends to the key.
1389
1390            legend_list_dic.setdefault(filename,[]) \
1391                .append([directory_name, round(max_ele, 3)])
1392
1393            # creates a LIST for the legend on the last iteration of the
1394            # directories which is when "legend_list_dic" has been fully
1395            # populated. Creates a list of strings which is used in the legend
1396            # only runs on the last iteration for all the gauges(csv) files
1397            # empties the list before creating it
1398
1399            if i == i_max - 1:
1400                legend_list = []
1401   
1402                for name_and_elevation in legend_list_dic[filename]:
1403                    legend_list.append('%s (elevation = %sm)'\
1404                                       % (name_and_elevation[0],
1405                                          name_and_elevation[1]))
1406           
1407            #skip time and elevation so it is not plotted!
1408            for k, quantity in enumerate(quantities):
1409                if quantity != 'time' and quantity != 'elevation':
1410                    pylab.figure(int(k*100+j))
1411                    pylab.ylabel(quantities_label[quantity])
1412                    pylab.plot(t,
1413                               directory_quantity_value[directory]\
1414                                                       [filename][quantity],
1415                               c = cstr[i], linewidth=1)
1416                    pylab.xlabel(quantities_label['time'])
1417                    pylab.axis(quantities_axis[quantity])
1418                    pylab.legend(legend_list,loc='upper right')
1419                   
1420                    pylab.title('%s at %s gauge'
1421                                % (quantity, filename[len(base_name):]))
1422
1423                    if output_dir == '':
1424                        figname = '%s%s%s_%s%s.png' \
1425                                  % (directory, sep, filename, quantity,
1426                                     extra_plot_name)
1427                    else:
1428                        figname = '%s%s%s_%s%s.png' \
1429                                  % (output_dir, sep, filename, quantity,
1430                                     extra_plot_name)
1431
1432                    if verbose: log.critical('saving figure here %s' % figname)
1433
1434                    pylab.savefig(figname)
1435           
1436    if verbose: log.critical('Closing all plots')
1437
1438    pylab.close('all')
1439    del pylab
1440
1441    if verbose: log.critical('Finished closing plots')
1442
1443##
1444# @brief Return min and max of an iterable.
1445# @param list The iterable to return min & max of.
1446# @return (min, max) of 'list'.
1447def get_min_max_values(list=None):
1448    """
1449    Returns the min and max of the list it was provided.
1450    """
1451
1452    if list == None: log.critical('List must be provided')
1453       
1454    return min(list), max(list)
1455
1456
1457##
1458# @brief Get runup around a point in a CSV file.
1459# @param gauge_filename gauge file name.
1460# @param sww_filename SWW file name.
1461# @param runup_filename Name of file to report into.
1462# @param size ??
1463# @param verbose ??
1464def get_runup_data_for_locations_from_file(gauge_filename,
1465                                           sww_filename,
1466                                           runup_filename,
1467                                           size=10,
1468                                           verbose=False):
1469    """this will read a csv file with the header x,y. Then look in a square
1470    'size'x2 around this position for the 'max_inundaiton_height' in the
1471    'sww_filename' and report the findings in the 'runup_filename'.
1472   
1473    WARNING: NO TESTS!
1474    """
1475
1476    from anuga.shallow_water.data_manager import get_all_directories_with_name,\
1477                                                 get_maximum_inundation_data,\
1478                                                 csv2dict
1479                                                 
1480    file = open(runup_filename, "w")
1481    file.write("easting,northing,runup \n ")
1482    file.close()
1483   
1484    #read gauge csv file to dictionary
1485    attribute_dic, title_index_dic = csv2dict(gauge_filename)
1486    northing = [float(x) for x in attribute_dic["y"]]
1487    easting = [float(x) for x in attribute_dic["x"]]
1488
1489    log.critical('Reading %s' % sww_filename)
1490
1491    runup_locations=[]
1492    for i, x in enumerate(northing):
1493        poly = [[int(easting[i]+size),int(northing[i]+size)],
1494                [int(easting[i]+size),int(northing[i]-size)],
1495                [int(easting[i]-size),int(northing[i]-size)],
1496                [int(easting[i]-size),int(northing[i]+size)]]
1497       
1498        run_up, x_y = get_maximum_inundation_data(filename=sww_filename,
1499                                                  polygon=poly,
1500                                                  verbose=False) 
1501
1502        #if no runup will return 0 instead of NONE
1503        if run_up==None: run_up=0
1504        if x_y==None: x_y=[0,0]
1505       
1506        if verbose:
1507            log.critical('maximum inundation runup near %s is %s meters'
1508                         % (x_y, run_up))
1509       
1510        #writes to file
1511        file = open(runup_filename, "a")
1512        temp = '%s,%s,%s \n' % (x_y[0], x_y[1], run_up)
1513        file.write(temp)
1514        file.close()
1515
1516##
1517# @brief ??
1518# @param  ??
1519# @param gauge_file ??
1520# @param out_name ??
1521# @param quantities ??
1522# @param verbose ??
1523# @param use_cache ??
1524def sww2csv_gauges(sww_file,
1525                   gauge_file,
1526                   out_name='gauge_',
1527                   quantities=['stage', 'depth', 'elevation',
1528                               'xmomentum', 'ymomentum'],
1529                   verbose=False,
1530                   use_cache=True):
1531    """
1532   
1533    Inputs:
1534        NOTE: if using csv2timeseries_graphs after creating csv file,
1535        it is essential to export quantities 'depth' and 'elevation'.
1536        'depth' is good to analyse gauges on land and elevation is used
1537        automatically by csv2timeseries_graphs in the legend.
1538       
1539        sww_file: path to any sww file
1540       
1541        gauge_file: Assumes that it follows this format
1542            name, easting, northing, elevation
1543            point1, 100.3, 50.2, 10.0
1544            point2, 10.3, 70.3, 78.0
1545       
1546        NOTE: order of column can change but names eg 'easting', 'elevation'
1547        must be the same! ALL lowercaps!
1548
1549        out_name: prefix for output file name (default is 'gauge_')
1550       
1551    Outputs:
1552        one file for each gauge/point location in the points file. They
1553        will be named with this format in the same directory as the 'sww_file'
1554            <out_name><name>.csv
1555        eg gauge_point1.csv if <out_name> not supplied
1556           myfile_2_point1.csv if <out_name> ='myfile_2_'
1557           
1558        They will all have a header
1559   
1560    Usage: sww2csv_gauges(sww_file='test1.sww',
1561                          quantities = ['stage', 'elevation','depth','bearing'],
1562                          gauge_file='gauge.txt')   
1563   
1564    Interpolate the quantities at a given set of locations, given
1565    an sww file.
1566    The results are written to a csv file.
1567
1568    In the future let points be a points file.
1569    And the user choose the quantities.
1570
1571    This is currently quite specific.
1572    If it needs to be more general, change things.
1573
1574    This is really returning speed, not velocity.
1575    """
1576    from gauge import sww2csv_gauges as sww2csv
1577       
1578    return sww2csv(sww_file, gauge_file, out_name, quantities, verbose, use_cache)
1579       
1580def sww2timeseries(swwfiles,
1581                   gauge_filename,
1582                   production_dirs,
1583                   report=None,
1584                   reportname=None,
1585                   plot_quantity=None,
1586                   generate_fig=False,
1587                   surface=None,
1588                   time_min=None,
1589                   time_max=None,
1590                   time_thinning=1,                   
1591                   time_unit=None,
1592                   title_on=None,
1593                   use_cache=False,
1594                   verbose=False,
1595                   output_centroids=False):
1596    from gauge import sww2timeseries as sww2timeseries_new
1597    return sww2timeseries_new(swwfiles,
1598                   gauge_filename,
1599                   production_dirs,
1600                   report,
1601                   reportname,
1602                   plot_quantity,
1603                   generate_fig,
1604                   surface,
1605                   time_min,
1606                   time_max,
1607                   time_thinning,                   
1608                   time_unit,
1609                   title_on,
1610                   use_cache,
1611                   verbose,
1612                   output_centroids)                               
1613       
1614##
1615# @brief Get a wave height at a certain depth given wave height at another depth.
1616# @param d1 The first depth.
1617# @param d2 The second depth.
1618# @param h1 Wave ampitude at d1
1619# @param verbose True if this function is to be verbose.
1620# @return The wave height at d2.
1621def greens_law(d1, d2, h1, verbose=False):
1622    """Green's Law
1623
1624    Green's Law allows an approximation of wave amplitude at
1625    a given depth based on the fourh root of the ratio of two depths
1626    and the amplitude at another given depth.
1627
1628    Note, wave amplitude is equal to stage.
1629   
1630    Inputs:
1631
1632    d1, d2 - the two depths
1633    h1     - the wave amplitude at d1
1634    h2     - the derived amplitude at d2
1635
1636    h2 = h1 (d1/d2)^(1/4), where d2 cannot equal 0.
1637   
1638    """
1639
1640    d1 = ensure_numeric(d1)
1641    d2 = ensure_numeric(d2)
1642    h1 = ensure_numeric(h1)
1643
1644    if d1 <= 0.0:
1645        msg = 'the first depth, d1 (%f), must be strictly positive' % (d1)
1646        raise Exception(msg)
1647
1648    if d2 <= 0.0:
1649        msg = 'the second depth, d2 (%f), must be strictly positive' % (d2)
1650        raise Exception(msg)
1651   
1652    if h1 <= 0.0:
1653        msg = 'the wave amplitude, h1 (%f), must be strictly positive' % (h1)
1654        raise Exception(msg)
1655   
1656    h2 = h1*(d1/d2)**0.25
1657
1658    assert h2 > 0
1659   
1660    return h2
1661       
1662
1663##
1664# @brief Get the square-root of a value.
1665# @param s The value to get the square-root of.
1666# @return The square-root of 's'.
1667def square_root(s):
1668    return sqrt(s)
1669
1670
Note: See TracBrowser for help on using the repository browser.