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

Last change on this file since 6013 was 6013, checked in by kristy, 15 years ago

Created and out name for sww2csv, so that it can be renamed due to several sww files in the one directory.

File size: 90.5 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
17from Numeric import arange, choose, zeros, Float, array, allclose, take, compress
18   
19from anuga.geospatial_data.geospatial_data import ensure_absolute
20from math import sqrt, atan, degrees
21
22
23
24# FIXME (Ole): Temporary short cuts - remove and update scripts where they are used
25from anuga.utilities.system_tools import get_revision_number
26from anuga.utilities.system_tools import store_version_info
27
28
29def file_function(filename,
30                  domain=None,
31                  quantities=None,
32                  interpolation_points=None,
33                  time_thinning=1,
34                  verbose=False,
35                  use_cache=False,
36                  boundary_polygon=None):
37    """Read time history of spatial data from NetCDF file and return
38    a callable object.
39
40    Input variables:
41   
42    filename - Name of sww or tms file
43       
44       If the file has extension 'sww' then it is assumed to be spatio-temporal
45       or temporal and the callable object will have the form f(t,x,y) or f(t)
46       depending on whether the file contains spatial data
47
48       If the file has extension 'tms' then it is assumed to be temporal only
49       and the callable object will have the form f(t)
50
51       Either form will return interpolated values based on the input file
52       using the underlying interpolation_function.
53
54    domain - Associated domain object   
55       If domain is specified, model time (domain.starttime)
56       will be checked and possibly modified.
57   
58       All times are assumed to be in UTC
59       
60       All spatial information is assumed to be in absolute UTM coordinates.
61
62    quantities - the name of the quantity to be interpolated or a
63                 list of quantity names. The resulting function will return
64                 a tuple of values - one for each quantity
65                 If quantities are None, the default quantities are
66                 ['stage', 'xmomentum', 'ymomentum']
67                 
68
69    interpolation_points - list of absolute UTM coordinates for points (N x 2)
70    or geospatial object or points file name at which values are sought
71   
72    use_cache: True means that caching of intermediate result of
73               Interpolation_function is attempted
74
75   
76    See Interpolation function in anuga.fit_interpolate.interpolation for further documentation
77    """
78
79
80    # FIXME (OLE): Should check origin of domain against that of file
81    # In fact, this is where origin should be converted to that of domain
82    # Also, check that file covers domain fully.
83
84    # Take into account:
85    # - domain's georef
86    # - sww file's georef
87    # - interpolation points as absolute UTM coordinates
88
89    if quantities is None:
90        if verbose:
91            msg = 'Quantities specified in file_function are None,'
92            msg += ' so I will use stage, xmomentum, and ymomentum in that order.'
93            print msg
94
95        quantities = ['stage', 'xmomentum', 'ymomentum']
96           
97
98    # Use domain's startime if available
99    if domain is not None:   
100        domain_starttime = domain.get_starttime()
101    else:
102        domain_starttime = None
103
104
105    # Build arguments and keyword arguments for use with caching or apply.
106    args = (filename,)
107
108
109    # FIXME (Ole): Caching this function will not work well
110    # if domain is passed in as instances change hash code.
111    # Instead we pass in those attributes that are needed (and return them
112    # if modified)
113    kwargs = {'quantities': quantities,
114              'interpolation_points': interpolation_points,
115              'domain_starttime': domain_starttime,
116              'time_thinning': time_thinning,                   
117              'verbose': verbose,
118              'boundary_polygon': boundary_polygon}
119
120
121    # Call underlying engine with or without caching
122    if use_cache is True:
123        try:
124            from caching import cache
125        except:
126            msg = 'Caching was requested, but caching module'+\
127                  'could not be imported'
128            raise msg
129
130        f, starttime = cache(_file_function,
131                             args, kwargs,
132                             dependencies=[filename],
133                             compression=False,                 
134                             verbose=verbose)
135
136    else:
137        f, starttime = apply(_file_function,
138                             args, kwargs)
139
140
141    #FIXME (Ole): Pass cache arguments, such as compression, in some sort of
142    #structure
143
144    f.starttime = starttime
145    f.filename = filename
146   
147    if domain is not None:
148        #Update domain.startime if it is *earlier* than starttime from file
149        if starttime > domain.starttime:
150            msg = 'WARNING: Start time as specified in domain (%f)'\
151                  %domain.starttime
152            msg += ' is earlier than the starttime of file %s (%f).'\
153                     %(filename, starttime)
154            msg += ' Modifying domain starttime accordingly.'
155           
156            if verbose: print msg
157            domain.set_starttime(starttime) #Modifying model time
158            if verbose: print 'Domain starttime is now set to %f'\
159               %domain.starttime
160
161    return f
162
163
164
165def _file_function(filename,
166                   quantities=None,
167                   interpolation_points=None,
168                   domain_starttime=None,
169                   time_thinning=1,
170                   verbose=False,
171                   boundary_polygon=None):
172    """Internal function
173   
174    See file_function for documentatiton
175    """
176   
177
178    assert type(filename) == type(''),\
179               'First argument to File_function must be a string'
180
181    try:
182        fid = open(filename)
183    except Exception, e:
184        msg = 'File "%s" could not be opened: Error="%s"'\
185                  %(filename, e)
186        raise msg
187
188    line = fid.readline()
189    fid.close()
190
191
192    if line[:3] == 'CDF':
193        return get_netcdf_file_function(filename,
194                                        quantities,
195                                        interpolation_points,
196                                        domain_starttime,
197                                        time_thinning=time_thinning,
198                                        verbose=verbose,
199                                        boundary_polygon=boundary_polygon)
200    else:
201        # FIXME (Ole): Could add csv file here to address Ted Rigby's suggestion about reading hydrographs.
202        # This may also deal with the gist of ticket:289
203        raise 'Must be a NetCDF File'
204
205
206
207def get_netcdf_file_function(filename,
208                             quantity_names=None,
209                             interpolation_points=None,
210                             domain_starttime=None,                           
211                             time_thinning=1,                             
212                             verbose=False,
213                             boundary_polygon=None):
214    """Read time history of spatial data from NetCDF sww file and
215    return a callable object f(t,x,y)
216    which will return interpolated values based on the input file.
217
218    Model time (domain_starttime)
219    will be checked, possibly modified and returned
220   
221    All times are assumed to be in UTC
222
223    See Interpolation function for further documetation
224   
225    """
226   
227   
228    # FIXME: Check that model origin is the same as file's origin
229    # (both in UTM coordinates)
230    # If not - modify those from file to match domain
231    # (origin should be passed in)
232    # Take this code from e.g. dem2pts in data_manager.py
233    # FIXME: Use geo_reference to read and write xllcorner...
234       
235
236    import time, calendar, types
237    from anuga.config import time_format
238    from Scientific.IO.NetCDF import NetCDFFile
239    from Numeric import array, zeros, Float, alltrue, concatenate, reshape
240
241    # Open NetCDF file
242    if verbose: print 'Reading', filename
243    fid = NetCDFFile(filename, 'r')
244
245    if type(quantity_names) == types.StringType:
246        quantity_names = [quantity_names]       
247
248    if quantity_names is None or len(quantity_names) < 1:
249        msg = 'No quantities are specified in file_function'
250        raise Exception, msg
251
252 
253    if interpolation_points is not None:
254        interpolation_points = ensure_absolute(interpolation_points)
255        msg = 'Points must by N x 2. I got %d' %interpolation_points.shape[1]
256        assert interpolation_points.shape[1] == 2, msg
257
258
259    # Now assert that requested quantitites (and the independent ones)
260    # are present in file
261    missing = []
262    for quantity in ['time'] + quantity_names:
263        if not fid.variables.has_key(quantity):
264            missing.append(quantity)
265
266    if len(missing) > 0:
267        msg = 'Quantities %s could not be found in file %s'\
268              %(str(missing), filename)
269        fid.close()
270        raise Exception, msg
271
272    # Decide whether this data has a spatial dimension
273    spatial = True
274    for quantity in ['x', 'y']:
275        if not fid.variables.has_key(quantity):
276            spatial = False
277
278    if filename[-3:] == 'tms' and spatial is True:
279        msg = 'Files of type tms must not contain spatial  information'
280        raise msg
281
282    if filename[-3:] == 'sww' and spatial is False:
283        msg = 'Files of type sww must contain spatial information'       
284        raise msg
285
286    if filename[-3:] == 'sts' and spatial is False:
287        #What if mux file only contains one point
288        msg = 'Files of type sts must contain spatial information'       
289        raise msg
290
291    if filename[-3:] == 'sts' and boundary_polygon is None:
292        #What if mux file only contains one point
293        msg = 'Files of type sts require boundary polygon'       
294        raise msg
295
296    # Get first timestep
297    try:
298        starttime = fid.starttime[0]
299    except ValueError:
300        msg = 'Could not read starttime from file %s' %filename
301        raise msg
302
303    # Get variables
304    # if verbose: print 'Get variables'   
305    time = fid.variables['time'][:]   
306
307    # Get time independent stuff
308    if spatial:
309        # Get origin
310        xllcorner = fid.xllcorner[0]
311        yllcorner = fid.yllcorner[0]
312        zone = fid.zone[0]       
313
314        x = fid.variables['x'][:]
315        y = fid.variables['y'][:]
316        if filename[-3:] == 'sww':
317            triangles = fid.variables['volumes'][:]
318
319        x = reshape(x, (len(x),1))
320        y = reshape(y, (len(y),1))
321        vertex_coordinates = concatenate((x,y), axis=1) #m x 2 array
322
323        if boundary_polygon is not None:
324            #removes sts points that do not lie on boundary
325            boundary_polygon=ensure_numeric(boundary_polygon)
326            boundary_polygon[:,0] -= xllcorner
327            boundary_polygon[:,1] -= yllcorner
328            temp=[]
329            boundary_id=[]
330            gauge_id=[]
331            for i in range(len(boundary_polygon)):
332                for j in range(len(x)):
333                    if allclose(vertex_coordinates[j],boundary_polygon[i],1e-4):
334                        #FIX ME:
335                        #currently gauges lat and long is stored as float and
336                        #then cast to double. This cuases slight repositioning
337                        #of vertex_coordinates.
338                        temp.append(boundary_polygon[i])
339                        gauge_id.append(j)
340                        boundary_id.append(i)
341                        break
342            gauge_neighbour_id=[]
343            for i in range(len(boundary_id)-1):
344                if boundary_id[i]+1==boundary_id[i+1]:
345                    gauge_neighbour_id.append(i+1)
346                else:
347                    gauge_neighbour_id.append(-1)
348            if boundary_id[len(boundary_id)-1]==len(boundary_polygon)-1 and boundary_id[0]==0:
349                gauge_neighbour_id.append(0)
350            else:
351                gauge_neighbour_id.append(-1)
352            gauge_neighbour_id=ensure_numeric(gauge_neighbour_id)
353            if len(compress(gauge_neighbour_id>=0,gauge_neighbour_id))!=len(temp)-1:
354                msg='incorrect number of segments'
355                raise msg
356            vertex_coordinates=ensure_numeric(temp)
357            if len(vertex_coordinates)==0:
358                msg = 'None of the sts gauges fall on the boundary'
359                raise msg
360        else:
361            gauge_neighbour_id=None
362
363        if interpolation_points is not None:
364            # Adjust for georef
365            interpolation_points[:,0] -= xllcorner
366            interpolation_points[:,1] -= yllcorner       
367   
368    else:
369        gauge_neighbour_id=None
370       
371    if domain_starttime is not None:
372
373        # If domain_startime is *later* than starttime,
374        # move time back - relative to domain's time
375        if domain_starttime > starttime:
376            time = time - domain_starttime + starttime
377
378        # FIXME Use method in geo to reconcile
379        # if spatial:
380        # assert domain.geo_reference.xllcorner == xllcorner
381        # assert domain.geo_reference.yllcorner == yllcorner
382        # assert domain.geo_reference.zone == zone       
383       
384    if verbose:
385        print 'File_function data obtained from: %s' %filename
386        print '  References:'
387        #print '    Datum ....' #FIXME
388        if spatial:
389            print '    Lower left corner: [%f, %f]'\
390                  %(xllcorner, yllcorner)
391        print '    Start time:   %f' %starttime               
392       
393   
394    # Produce values for desired data points at
395    # each timestep for each quantity
396    quantities = {}
397    for i, name in enumerate(quantity_names):
398        quantities[name] = fid.variables[name][:]
399        if boundary_polygon is not None:
400            #removes sts points that do not lie on boundary
401            quantities[name] = take(quantities[name],gauge_id,1)
402           
403    # Close sww, tms or sts netcdf file         
404    fid.close()
405
406    from anuga.fit_interpolate.interpolate import Interpolation_function
407
408    if not spatial:
409        vertex_coordinates = triangles = interpolation_points = None
410    if filename[-3:] == 'sts':#added
411        triangles = None
412        #vertex coordinates is position of urs gauges
413
414    # Return Interpolation_function instance as well as
415    # starttime for use to possible modify that of domain
416    return Interpolation_function(time,
417                                  quantities,
418                                  quantity_names,
419                                  vertex_coordinates,
420                                  triangles,
421                                  interpolation_points,
422                                  time_thinning=time_thinning,
423                                  verbose=verbose,gauge_neighbour_id=gauge_neighbour_id), starttime
424
425    # NOTE (Ole): Caching Interpolation function is too slow as
426    # the very long parameters need to be hashed.
427
428
429
430
431def multiple_replace(text, dictionary):
432    """Multiple replace of words in text
433
434    text:       String to be modified
435    dictionary: Mapping of words that are to be substituted
436
437    Python Cookbook 3.14 page 88 and page 90
438    """
439
440    import re
441   
442    #Create a regular expression from all of the dictionary keys
443    #matching only entire words
444    regex = re.compile(r'\b'+ \
445                       r'\b|\b'.join(map(re.escape, dictionary.keys()))+ \
446                       r'\b' )
447
448    #For each match, lookup the corresponding value in the dictionary
449    return regex.sub(lambda match: dictionary[match.group(0)], text)
450
451
452
453
454def apply_expression_to_dictionary(expression, dictionary):#dictionary):
455    """Apply arbitrary expression to values of dictionary
456
457    Given an expression in terms of the keys, replace key by the
458    corresponding values and evaluate.
459   
460
461    expression: Arbitrary, e.g. arithmetric, expression relating keys
462                from dictionary.
463
464    dictionary: Mapping between symbols in expression and objects that
465                will be evaluated by expression.
466                Values in dictionary must support operators given in
467                expression e.g. by overloading
468
469    due to a limitation with Numeric, this can not evaluate 0/0
470    In general, the user can fix by adding 1e-30 to the numerator.
471    SciPy core can handle this situation.
472    """
473
474    import types
475    import re
476
477    assert isinstance(expression, basestring)
478    assert type(dictionary) == types.DictType
479
480    #Convert dictionary values to textual representations suitable for eval
481    D = {}
482    for key in dictionary:
483        D[key] = 'dictionary["%s"]' %key
484
485    #Perform substitution of variables   
486    expression = multiple_replace(expression, D)
487
488    #Evaluate and return
489    try:
490        return eval(expression)
491    except NameError, e:
492        msg = 'Expression "%s" could not be evaluated: %s' %(expression, e)
493        raise NameError, msg
494    except ValueError, e:
495        msg = 'Expression "%s" could not be evaluated: %s' %(expression, e)
496        raise ValueError, msg
497   
498
499def get_textual_float(value, format = '%.2f'):
500    """Get textual representation of floating point numbers
501    and accept None as valid entry
502
503    format is a string - default = '%.2f'
504    """
505
506    if value is None:
507        return 'None'
508    else:
509        try:
510            float(value)
511        except:
512            # May this is a vector
513            if len(value) > 1:
514                s = '('
515                for v in value:
516                    s += get_textual_float(v, format) + ', '
517                   
518                s = s[:-2] + ')' # Strip trailing comma and close
519                return s
520            else:
521                raise 'Illegal input to get_textual_float:', value
522        else:
523            return format %float(value)
524
525
526
527####################################
528####OBSOLETE STUFF
529
530
531def angle(v1, v2):
532    """Temporary Interface to new location"""
533
534    import anuga.utilities.numerical_tools as NT       
535   
536    msg = 'angle has moved from util.py.  '
537    msg += 'Please use "from anuga.utilities.numerical_tools import angle"'
538    warn(msg, DeprecationWarning) 
539
540    return NT.angle(v1, v2)
541   
542def anglediff(v0, v1):
543    """Temporary Interface to new location"""
544
545    import anuga.utilities.numerical_tools as NT
546   
547    msg = 'anglediff has moved from util.py.  '
548    msg += 'Please use "from anuga.utilities.numerical_tools import anglediff"'
549    warn(msg, DeprecationWarning) 
550
551    return NT.anglediff(v0, v1)   
552
553   
554def mean(x):
555    """Temporary Interface to new location"""
556
557    import anuga.utilities.numerical_tools as NT   
558   
559    msg = 'mean has moved from util.py.  '
560    msg += 'Please use "from anuga.utilities.numerical_tools import mean"'
561    warn(msg, DeprecationWarning) 
562
563    return NT.mean(x)   
564
565def point_on_line(*args, **kwargs):
566    """Temporary Interface to new location"""
567
568    msg = 'point_on_line has moved from util.py.  '
569    msg += 'Please use "from anuga.utilities.polygon import point_on_line"'
570    warn(msg, DeprecationWarning) 
571
572    return utilities.polygon.point_on_line(*args, **kwargs)     
573   
574def inside_polygon(*args, **kwargs):
575    """Temporary Interface to new location"""
576
577    print 'inside_polygon has moved from util.py.  ',
578    print 'Please use "from anuga.utilities.polygon import inside_polygon"'
579
580    return utilities.polygon.inside_polygon(*args, **kwargs)   
581   
582def outside_polygon(*args, **kwargs):
583    """Temporary Interface to new location"""
584
585    print 'outside_polygon has moved from util.py.  ',
586    print 'Please use "from anuga.utilities.polygon import outside_polygon"'
587
588    return utilities.polygon.outside_polygon(*args, **kwargs)   
589
590
591def separate_points_by_polygon(*args, **kwargs):
592    """Temporary Interface to new location"""
593
594    print 'separate_points_by_polygon has moved from util.py.  ',
595    print 'Please use "from anuga.utilities.polygon import separate_points_by_polygon"'
596
597    return utilities.polygon.separate_points_by_polygon(*args, **kwargs)   
598
599
600
601def read_polygon(*args, **kwargs):
602    """Temporary Interface to new location"""
603
604    print 'read_polygon has moved from util.py.  ',
605    print 'Please use "from anuga.utilities.polygon import read_polygon"'
606
607    return utilities.polygon.read_polygon(*args, **kwargs)   
608
609
610def populate_polygon(*args, **kwargs):
611    """Temporary Interface to new location"""
612
613    print 'populate_polygon has moved from util.py.  ',
614    print 'Please use "from anuga.utilities.polygon import populate_polygon"'
615
616    return utilities.polygon.populate_polygon(*args, **kwargs)   
617
618##################### end of obsolete stuff ? ############
619
620def start_screen_catcher(dir_name, myid='', numprocs='', extra_info='',
621                         verbose=False):
622    """Temporary Interface to new location"""
623    from anuga.shallow_water.data_manager import start_screen_catcher as dm_start_screen_catcher
624
625    print 'start_screen_catcher has moved from util.py.  ',
626    print 'Please use "from anuga.shallow_water.data_manager import start_screen_catcher"'
627   
628    return dm_start_screen_catcher(dir_name, myid='', numprocs='', extra_info='',
629                         verbose=False)
630
631
632def sww2timeseries(swwfiles,
633                   gauge_filename,
634                   production_dirs,
635                   report = None,
636                   reportname = None,
637                   plot_quantity = None,
638                   generate_fig = False,
639                   surface = None,
640                   time_min = None,
641                   time_max = None,
642                   time_thinning = 1,                   
643                   time_unit = None,
644                   title_on = None,
645                   use_cache = False,
646                   verbose = False):
647   
648    """ Read sww file and plot the time series for the
649    prescribed quantities at defined gauge locations and
650    prescribed time range.
651
652    Input variables:
653
654    swwfiles        - dictionary of sww files with label_ids (used in
655                      generating latex output. It will be part of
656                      the directory name of file_loc (typically the timestamp).
657                      Helps to differentiate latex files for different simulations
658                      for a particular scenario. 
659                    - assume that all conserved quantities have been stored
660                    - assume each sww file has been simulated with same timestep
661   
662    gauge_filename  - name of file containing gauge data
663                        - easting, northing, name , elevation?
664                    - OR (this is not yet done)
665                        - structure which can be converted to a Numeric array,
666                          such as a geospatial data object
667                     
668    production_dirs -  A list of list, example {20061101_121212: '1 in 10000',
669                                                'boundaries': 'urs boundary'}
670                      this will use the second part as the label and the first part
671                      as the ?
672                      #FIXME: Is it a list or a dictionary
673                      # This is probably obsolete by now
674                     
675    report          - if True, then write figures to report_figures directory in
676                      relevant production directory
677                    - if False, figures are already stored with sww file
678                    - default to False
679
680    reportname      - name for report if wishing to generate report
681   
682    plot_quantity   - list containing quantities to plot, they must
683                      be the name of an existing quantity or one of
684                      the following possibilities
685                    - possibilities:
686                        - stage; 'stage'
687                        - depth; 'depth'
688                        - speed; calculated as absolute momentum
689                         (pointwise) divided by depth; 'speed'
690                        - bearing; calculated as the angle of the momentum
691                          vector (xmomentum, ymomentum) from the North; 'bearing'
692                        - absolute momentum; calculated as
693                          sqrt(xmomentum^2 + ymomentum^2); 'momentum'
694                        - x momentum; 'xmomentum'
695                        - y momentum; 'ymomentum'
696                    - default will be ['stage', 'speed', 'bearing']
697
698    generate_fig     - if True, generate figures as well as csv files of quantities
699                     - if False, csv files created only
700                     
701    surface          - if True, then generate solution surface with 3d plot
702                       and save to current working directory
703                     - default = False
704   
705    time_min         - beginning of user defined time range for plotting purposes
706                        - default will be first available time found in swwfile
707                       
708    time_max         - end of user defined time range for plotting purposes
709                        - default will be last available time found in swwfile
710                       
711    title_on        - if True, export standard graphics with title
712                    - if False, export standard graphics without title
713
714
715                     
716    Output:
717   
718    - time series data stored in .csv for later use if required.
719      Name = gauges_timeseries followed by gauge name
720    - latex file will be generated in same directory as where script is
721      run (usually production scenario directory.
722      Name = latexoutputlabel_id.tex
723
724    Other important information:
725   
726    It is assumed that the used has stored all the conserved quantities
727    and elevation during the scenario run, i.e.
728    ['stage', 'elevation', 'xmomentum', 'ymomentum']
729    If this has not occurred then sww2timeseries will not work.
730
731
732    Usage example
733    texname = sww2timeseries({project.boundary_name + '.sww': ''},
734                             project.polygons_dir + sep + 'boundary_extent.csv',
735                             project.anuga_dir,
736                             report = False,
737                             plot_quantity = ['stage', 'speed', 'bearing'],
738                             time_min = None,
739                             time_max = None,
740                             title_on = True,   
741                             verbose = True)
742   
743    """
744
745    msg = 'NOTE: A new function is available to create csv files from sww files called'
746    msg += 'sww2csv_gauges in anuga.abstract_2d_finite_volumes.util'
747    msg += 'PLUS another new function to create graphs from csv files called'   
748    msg += 'csv2timeseries_graphs in anuga.abstract_2d_finite_volumes.util'
749    print msg
750   
751    k = _sww2timeseries(swwfiles,
752                        gauge_filename,
753                        production_dirs,
754                        report,
755                        reportname,
756                        plot_quantity,
757                        generate_fig,
758                        surface,
759                        time_min,
760                        time_max,
761                        time_thinning,                       
762                        time_unit,
763                        title_on,
764                        use_cache,
765                        verbose)
766
767    return k
768
769def _sww2timeseries(swwfiles,
770                    gauge_filename,
771                    production_dirs,
772                    report = None,
773                    reportname = None,
774                    plot_quantity = None,
775                    generate_fig = False,
776                    surface = None,
777                    time_min = None,
778                    time_max = None,
779                    time_thinning = 1,                   
780                    time_unit = None,
781                    title_on = None,
782                    use_cache = False,
783                    verbose = False):   
784       
785    assert type(gauge_filename) == type(''),\
786           'Gauge filename must be a string'
787   
788    try:
789        fid = open(gauge_filename)
790    except Exception, e:
791        msg = 'File "%s" could not be opened: Error="%s"'\
792                  %(gauge_filename, e)
793        raise msg
794
795    if report is None:
796        report = False
797       
798    if plot_quantity is None:
799        plot_quantity = ['depth', 'speed']
800    else:
801        assert type(plot_quantity) == list,\
802               'plot_quantity must be a list'
803        check_list(plot_quantity)
804
805    if surface is None:
806        surface = False
807
808    if time_unit is None:
809        time_unit = 'hours'
810   
811    if title_on is None:
812        title_on = True
813   
814    if verbose: print '\n Gauges obtained from: %s \n' %gauge_filename
815    gauges, locations, elev = get_gauges_from_file(gauge_filename)
816
817    sww_quantity = ['stage', 'elevation', 'xmomentum', 'ymomentum']
818
819    file_loc = []
820    f_list = []
821    label_id = []
822    leg_label = []
823    themaxT = 0.0
824    theminT = 0.0
825
826    for swwfile in swwfiles.keys():
827
828        try:
829            fid = open(swwfile)
830        except Exception, e:
831            msg = 'File "%s" could not be opened: Error="%s"'\
832                  %(swwfile, e)
833            raise msg
834
835        print 'swwfile', swwfile
836
837        # Extract parent dir name and use as label
838        path, _ = os.path.split(swwfile)
839        _, label = os.path.split(path)       
840       
841        #print 'label', label
842        leg_label.append(label)
843
844       
845
846        f = file_function(swwfile,
847                          quantities = sww_quantity,
848                          interpolation_points = gauges,
849                          time_thinning = time_thinning,
850                          verbose = verbose,
851                          use_cache = use_cache)
852
853        # determine which gauges are contained in sww file
854        count = 0
855        gauge_index = []
856        for k, g in enumerate(gauges):
857            if f(0.0, point_id = k)[2] > 1.0e6:
858                count += 1
859                if count == 1: print 'Gauges not contained here:'
860                print locations[k]
861            else:
862                gauge_index.append(k)
863
864        if len(gauge_index) > 0:
865            print 'Gauges contained here: \n',
866        else:
867            print 'No gauges contained here. \n'
868        for i in range(len(gauge_index)):
869             print locations[gauge_index[i]]
870             
871        index = swwfile.rfind(sep)
872        file_loc.append(swwfile[:index+1])
873        label_id.append(swwfiles[swwfile])
874
875       
876        f_list.append(f)
877        maxT = max(f.get_time())
878        minT = min(f.get_time())
879        if maxT > themaxT: themaxT = maxT
880        if minT > theminT: theminT = minT
881
882    if time_min is None:
883        time_min = theminT # min(T)
884    else:
885        if time_min < theminT: # min(T):
886            msg = 'Minimum time entered not correct - please try again'
887            raise Exception, msg
888
889    if time_max is None:
890        time_max = themaxT # max(T)
891    else:
892        if time_max > themaxT: # max(T):
893            msg = 'Maximum time entered not correct - please try again'
894            raise Exception, msg
895
896    if verbose and len(gauge_index) > 0: print 'Inputs OK - going to generate figures'
897
898    if len(gauge_index) <> 0:
899        texfile, elev_output = generate_figures(plot_quantity, file_loc, report, reportname, surface,
900                                                leg_label, f_list, gauges, locations, elev, gauge_index,
901                                                production_dirs, time_min, time_max, time_unit,
902                                                title_on, label_id, generate_fig, verbose)
903    else:
904        texfile = ''
905        elev_output = []
906
907    return texfile, elev_output
908               
909def get_gauges_from_file(filename):
910    """ Read in gauge information from file
911    """
912    from os import sep, getcwd, access, F_OK, mkdir
913    fid = open(filename)
914    lines = fid.readlines()
915    fid.close()
916   
917    gauges = []
918    gaugelocation = []
919    elev = []
920
921    # Check header information   
922    line1 = lines[0]
923    line11 = line1.split(',')
924
925    if isinstance(line11[0],str) is True:
926        # We have found text in the first line
927        east_index = None
928        north_index = None
929        name_index = None
930        elev_index = None
931        for i in range(len(line11)):
932            if line11[i].strip('\n').strip('\r').strip(' ').lower() == 'easting': east_index = i
933            if line11[i].strip('\n').strip('\r').strip(' ').lower() == 'northing': north_index = i
934            if line11[i].strip('\n').strip('\r').strip(' ').lower() == 'name': name_index = i
935            if line11[i].strip('\n').strip('\r').strip(' ').lower() == 'elevation': elev_index = i
936
937        if east_index < len(line11) and north_index < len(line11):
938            pass
939        else:
940            msg = 'WARNING: %s does not contain correct header information' %(filename)
941            msg += 'The header must be: easting, northing, name, elevation'
942            raise Exception, msg
943
944        if elev_index is None: 
945            raise Exception
946   
947        if name_index is None: 
948            raise Exception
949
950        lines = lines[1:] # Remove header from data
951    else:
952        # No header, assume that this is a simple easting, northing file
953
954        msg = 'There was no header in file %s and the number of columns is %d' %(filename, len(line11))
955        msg += '- I was assuming two columns corresponding to Easting and Northing'
956        assert len(line11) == 2, msg
957
958        east_index = 0
959        north_index = 1
960
961        N = len(lines)
962        elev = [-9999]*N
963        gaugelocation = range(N)
964       
965    # Read in gauge data
966    for line in lines:
967        fields = line.split(',')
968
969        gauges.append([float(fields[east_index]), float(fields[north_index])])
970
971        if len(fields) > 2:
972            elev.append(float(fields[elev_index]))
973            loc = fields[name_index]
974            gaugelocation.append(loc.strip('\n'))
975
976    return gauges, gaugelocation, elev
977
978
979
980def check_list(quantity):
981    """ Check that input quantities in quantity list are possible
982    """
983    all_quantity = ['stage', 'depth', 'momentum', 'xmomentum',
984                    'ymomentum', 'speed', 'bearing', 'elevation']
985
986       
987                   
988    import sys
989    #if not sys.version.startswith('2.4'):
990        # Backwards compatibility
991    #   from sets import Set as set
992
993    from sets import Set as set
994           
995    for i,j in enumerate(quantity):
996        quantity[i] = quantity[i].lower()
997    p = list(set(quantity).difference(set(all_quantity)))
998    if len(p) <> 0:
999        msg = 'Quantities %s do not exist - please try again' %p
1000        raise Exception, msg
1001       
1002    return 
1003
1004def calc_bearing(uh, vh):
1005    """ Calculate velocity bearing from North
1006    """
1007    #FIXME (Ole): I reckon we should refactor this one to use
1008    #             the function angle() in utilities/numerical_tools
1009    #
1010    #             It will be a simple matter of
1011    # * converting from radians to degrees
1012    # * moving the reference direction from [1,0] to North
1013    # * changing from counter clockwise to clocwise.
1014       
1015    angle = degrees(atan(vh/(uh+1.e-15)))
1016    if (0 < angle < 90.0):
1017        if vh > 0:
1018            bearing = 90.0 - abs(angle)
1019        if vh < 0:
1020            bearing = 270.0 - abs(angle)
1021   
1022    if (-90 < angle < 0):
1023        if vh < 0:
1024            bearing = 90.0 - (angle)
1025        if vh > 0:
1026            bearing = 270.0 - (angle)
1027    if angle == 0: bearing = 0.0
1028
1029    return bearing
1030
1031def generate_figures(plot_quantity, file_loc, report, reportname, surface,
1032                     leg_label, f_list, gauges, locations, elev, gauge_index,
1033                     production_dirs, time_min, time_max, time_unit,
1034                     title_on, label_id, generate_fig, verbose):
1035    """ Generate figures based on required quantities and gauges for
1036    each sww file
1037    """
1038#    from math import sqrt, atan, degrees
1039    from Numeric import ones, allclose, zeros, Float, ravel
1040    from os import sep, altsep, getcwd, mkdir, access, F_OK, environ
1041
1042    if generate_fig is True:
1043        from pylab import ion, hold, plot, axis, figure, legend, savefig, \
1044             xlabel, ylabel, title, close, subplot
1045   
1046        if surface is True:
1047            import pylab as p1
1048            import mpl3d.mplot3d as p3
1049       
1050    if report == True:   
1051        texdir = getcwd()+sep+'report'+sep
1052        if access(texdir,F_OK) == 0:
1053            mkdir (texdir)
1054        if len(label_id) == 1:
1055            label_id1 = label_id[0].replace(sep,'')
1056            label_id2 = label_id1.replace('_','')
1057            texfile = texdir+reportname+'%s' %(label_id2)
1058            texfile2 = reportname+'%s' %(label_id2)
1059            texfilename = texfile + '.tex'
1060            if verbose: print '\n Latex output printed to %s \n' %texfilename
1061            fid = open(texfilename, 'w')
1062        else:
1063            texfile = texdir+reportname
1064            texfile2 = reportname
1065            texfilename = texfile + '.tex' 
1066            if verbose: print '\n Latex output printed to %s \n' %texfilename
1067            fid = open(texfilename, 'w')
1068    else:
1069        texfile = ''
1070        texfile2 = ''
1071
1072    p = len(f_list)
1073    n = []
1074    n0 = 0
1075    for i in range(len(f_list)):
1076        n.append(len(f_list[i].get_time()))
1077        if n[i] > n0: n0 = n[i] 
1078    n0 = int(n0)
1079    m = len(locations)
1080    model_time = zeros((n0,m,p), Float) 
1081    stages = zeros((n0,m,p), Float)
1082    elevations = zeros((n0,m,p), Float) 
1083    momenta = zeros((n0,m,p), Float)
1084    xmom = zeros((n0,m,p), Float)
1085    ymom = zeros((n0,m,p), Float)
1086    speed = zeros((n0,m,p), Float)
1087    bearings = zeros((n0,m,p), Float)
1088    due_east = 90.0*ones((n0,1), Float)
1089    due_west = 270.0*ones((n0,1), Float)
1090    depths = zeros((n0,m,p), Float)
1091    eastings = zeros((n0,m,p), Float)
1092    min_stages = []
1093    max_stages = []
1094    min_momentums = []   
1095    max_momentums = []
1096    max_xmomentums = []
1097    max_ymomentums = []
1098    min_xmomentums = []
1099    min_ymomentums = []
1100    max_speeds = []
1101    min_speeds = []   
1102    max_depths = []
1103    model_time_plot3d = zeros((n0,m), Float)
1104    stages_plot3d = zeros((n0,m), Float)
1105    eastings_plot3d = zeros((n0,m),Float)
1106    if time_unit is 'mins': scale = 60.0
1107    if time_unit is 'hours': scale = 3600.0
1108    ##### loop over each swwfile #####
1109    for j, f in enumerate(f_list):
1110        starttime = f.starttime
1111        if verbose: print 'swwfile %d of %d' %(j, len(f_list))
1112        comparefile = file_loc[j]+sep+'gauges_maxmins'+'.csv'
1113        fid_compare = open(comparefile, 'w')
1114        file0 = file_loc[j]+'gauges_t0.csv'
1115        fid_0 = open(file0, 'w')
1116        ##### loop over each gauge #####
1117        for k in gauge_index:
1118            g = gauges[k]
1119            if verbose: print 'Gauge %d of %d' %(k, len(gauges))
1120            min_stage = 10
1121            max_stage = 0
1122            max_momentum = max_xmomentum = max_ymomentum = 0
1123            min_momentum = min_xmomentum = min_ymomentum = 100
1124            max_speed = 0
1125            min_speed = 0           
1126            max_depth = 0           
1127            gaugeloc = str(locations[k])
1128            thisfile = file_loc[j]+sep+'gauges_time_series'+'_'\
1129                       +gaugeloc+'.csv'
1130            fid_out = open(thisfile, 'w')
1131            s = 'Time, Stage, Momentum, Speed, Elevation, xmom, ymom, Bearing \n'
1132            fid_out.write(s)
1133            #### generate quantities #######
1134            for i, t in enumerate(f.get_time()):
1135                if time_min <= t <= time_max:
1136                    w = f(t, point_id = k)[0]
1137                    z = f(t, point_id = k)[1]
1138                    uh = f(t, point_id = k)[2]
1139                    vh = f(t, point_id = k)[3]
1140                    depth = w-z     
1141                    m = sqrt(uh*uh + vh*vh)
1142                    if depth < 0.001:
1143                        vel = 0.0
1144                    else:
1145                        vel = m / (depth + 1.e-6/depth) 
1146                    bearing = calc_bearing(uh, vh)                   
1147                    model_time[i,k,j] = (t + starttime)/scale #t/60.0
1148                    stages[i,k,j] = w
1149                    elevations[i,k,j] = z
1150                    xmom[i,k,j] = uh
1151                    ymom[i,k,j] = vh
1152                    momenta[i,k,j] = m
1153                    speed[i,k,j] = vel
1154                    bearings[i,k,j] = bearing
1155                    depths[i,k,j] = depth
1156                    thisgauge = gauges[k]
1157                    eastings[i,k,j] = thisgauge[0]
1158                    s = '%.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f,\n' %(t, w, m, vel, z, uh, vh, bearing)
1159                    fid_out.write(s)
1160                    if t == 0:
1161                        s = '%.2f, %.2f, %.2f\n' %(g[0], g[1], w)
1162                        fid_0.write(s)
1163                    if t/60.0 <= 13920: tindex = i
1164                    if w > max_stage: max_stage = w
1165                    if w < min_stage: min_stage = w
1166                    if m > max_momentum: max_momentum = m
1167                    if m < min_momentum: min_momentum = m                   
1168                    if uh > max_xmomentum: max_xmomentum = uh
1169                    if vh > max_ymomentum: max_ymomentum = vh
1170                    if uh < min_xmomentum: min_xmomentum = uh
1171                    if vh < min_ymomentum: min_ymomentum = vh
1172                    if vel > max_speed: max_speed = vel
1173                    if vel < min_speed: min_speed = vel                   
1174                    if z > 0 and depth > max_depth: max_depth = depth
1175                   
1176                   
1177            s = '%.2f, %.2f, %.2f, %.2f, %s\n' %(max_stage, min_stage, z, thisgauge[0], leg_label[j])
1178            fid_compare.write(s)
1179            max_stages.append(max_stage)
1180            min_stages.append(min_stage)
1181            max_momentums.append(max_momentum)
1182            max_xmomentums.append(max_xmomentum)
1183            max_ymomentums.append(max_ymomentum)
1184            min_xmomentums.append(min_xmomentum)
1185            min_ymomentums.append(min_ymomentum)
1186            min_momentums.append(min_momentum)           
1187            max_depths.append(max_depth)
1188            max_speeds.append(max_speed)
1189            min_speeds.append(min_speed)           
1190            #### finished generating quantities for each swwfile #####
1191       
1192        model_time_plot3d[:,:] = model_time[:,:,j]
1193        stages_plot3d[:,:] = stages[:,:,j]
1194        eastings_plot3d[:,] = eastings[:,:,j]
1195           
1196        if surface is  True:
1197            print 'Printing surface figure'
1198            for i in range(2):
1199                fig = p1.figure(10)
1200                ax = p3.Axes3D(fig)
1201                if len(gauges) > 80:
1202                    ax.plot_surface(model_time[:,:,j],eastings[:,:,j],stages[:,:,j])
1203                else:
1204                    #ax.plot_wireframe(model_time[:,:,j],eastings[:,:,j],stages[:,:,j])
1205                    ax.plot3D(ravel(eastings[:,:,j]),ravel(model_time[:,:,j]),ravel(stages[:,:,j]))
1206                ax.set_xlabel('time')
1207                ax.set_ylabel('x')
1208                ax.set_zlabel('stage')
1209                fig.add_axes(ax)
1210                p1.show()
1211                surfacefig = 'solution_surface%s' %leg_label[j]
1212                p1.savefig(surfacefig)
1213                p1.close()
1214           
1215    #### finished generating quantities for all swwfiles #####
1216
1217    # x profile for given time
1218    if surface is True:
1219        figure(11)
1220        plot(eastings[tindex,:,j],stages[tindex,:,j])
1221        xlabel('x')
1222        ylabel('stage')
1223        profilefig = 'solution_xprofile' 
1224        savefig('profilefig')
1225
1226    elev_output = []
1227    if generate_fig is True:
1228        depth_axis = axis([starttime/scale, time_max/scale, -0.1, max(max_depths)*1.1])
1229        stage_axis = axis([starttime/scale, time_max/scale, min(min_stages), max(max_stages)*1.1])
1230        vel_axis = axis([starttime/scale, time_max/scale, min(min_speeds), max(max_speeds)*1.1])
1231        mom_axis = axis([starttime/scale, time_max/scale, min(min_momentums), max(max_momentums)*1.1])
1232        xmom_axis = axis([starttime/scale, time_max/scale, min(min_xmomentums), max(max_xmomentums)*1.1])
1233        ymom_axis = axis([starttime/scale, time_max/scale, min(min_ymomentums), max(max_ymomentums)*1.1])
1234        cstr = ['g', 'r', 'b', 'c', 'm', 'y', 'k']
1235        nn = len(plot_quantity)
1236        no_cols = 2
1237       
1238        if len(label_id) > 1: graphname_report = []
1239        pp = 1
1240        div = 11.
1241        cc = 0
1242        for k in gauge_index:
1243            g = gauges[k]
1244            count1 = 0
1245            if report == True and len(label_id) > 1:
1246                s = '\\begin{figure}[ht] \n \\centering \n \\begin{tabular}{cc} \n'
1247                fid.write(s)
1248            if len(label_id) > 1: graphname_report = []
1249            #### generate figures for each gauge ####
1250            for j, f in enumerate(f_list):
1251                ion()
1252                hold(True)
1253                count = 0
1254                where1 = 0
1255                where2 = 0
1256                word_quantity = ''
1257                if report == True and len(label_id) == 1:
1258                    s = '\\begin{figure}[hbt] \n \\centering \n \\begin{tabular}{cc} \n'
1259                    fid.write(s)
1260                   
1261                for which_quantity in plot_quantity:
1262                    count += 1
1263                    where1 += 1
1264                    figure(count, frameon = False)
1265                    if which_quantity == 'depth':
1266                        plot(model_time[0:n[j]-1,k,j], depths[0:n[j]-1,k,j], '-', c = cstr[j])
1267                        units = 'm'
1268                        axis(depth_axis)
1269                    if which_quantity == 'stage':
1270                        if elevations[0,k,j] <= 0:
1271                            plot(model_time[0:n[j]-1,k,j], stages[0:n[j]-1,k,j], '-', c = cstr[j])
1272                            axis(stage_axis)
1273                        else:
1274                            plot(model_time[0:n[j]-1,k,j], depths[0:n[j]-1,k,j], '-', c = cstr[j])
1275                            #axis(depth_axis)                 
1276                        units = 'm'
1277                    if which_quantity == 'momentum':
1278                        plot(model_time[0:n[j]-1,k,j], momenta[0:n[j]-1,k,j], '-', c = cstr[j])
1279                        axis(mom_axis)
1280                        units = 'm^2 / sec'
1281                    if which_quantity == 'xmomentum':
1282                        plot(model_time[0:n[j]-1,k,j], xmom[0:n[j]-1,k,j], '-', c = cstr[j])
1283                        axis(xmom_axis)
1284                        units = 'm^2 / sec'
1285                    if which_quantity == 'ymomentum':
1286                        plot(model_time[0:n[j]-1,k,j], ymom[0:n[j]-1,k,j], '-', c = cstr[j])
1287                        axis(ymom_axis)
1288                        units = 'm^2 / sec'
1289                    if which_quantity == 'speed':
1290                        plot(model_time[0:n[j]-1,k,j], speed[0:n[j]-1,k,j], '-', c = cstr[j])
1291                        axis(vel_axis)
1292                        units = 'm / sec'
1293                    if which_quantity == 'bearing':
1294                        plot(model_time[0:n[j]-1,k,j], bearings[0:n[j]-1,k,j], '-', 
1295                             model_time[0:n[j]-1,k,j], due_west[0:n[j]-1], '-.', 
1296                             model_time[0:n[j]-1,k,j], due_east[0:n[j]-1], '-.')
1297                        units = 'degrees from North'
1298                        #ax = axis([time_min, time_max, 0.0, 360.0])
1299                        legend(('Bearing','West','East'))
1300
1301                    if time_unit is 'mins': xlabel('time (mins)')
1302                    if time_unit is 'hours': xlabel('time (hours)')
1303                    #if which_quantity == 'stage' and elevations[0:n[j]-1,k,j] > 0:
1304                    #    ylabel('%s (%s)' %('depth', units))
1305                    #else:
1306                    #    ylabel('%s (%s)' %(which_quantity, units))
1307                        #ylabel('%s (%s)' %('wave height', units))
1308                    ylabel('%s (%s)' %(which_quantity, units))
1309                    if len(label_id) > 1: legend((leg_label),loc='upper right')
1310
1311                    #gaugeloc1 = gaugeloc.replace(' ','')
1312                    #gaugeloc2 = gaugeloc1.replace('_','')
1313                    gaugeloc2 = str(locations[k]).replace(' ','')
1314                    graphname = '%sgauge%s_%s' %(file_loc[j],
1315                                                 gaugeloc2,
1316                                                 which_quantity)
1317
1318                    if report == True and len(label_id) > 1:
1319                        figdir = getcwd()+sep+'report_figures'+sep
1320                        if access(figdir,F_OK) == 0 :
1321                            mkdir (figdir)
1322                        latex_file_loc = figdir.replace(sep,altsep) 
1323                        graphname_latex = '%sgauge%s%s' %(latex_file_loc, gaugeloc2, which_quantity) # storing files in production directory   
1324                        graphname_report_input = '%sgauge%s%s' %('..'+altsep+'report_figures'+altsep, gaugeloc2, which_quantity) # giving location in latex output file
1325                        graphname_report.append(graphname_report_input)
1326                       
1327                        savefig(graphname_latex) # save figures in production directory for report generation
1328
1329                    if report == True:
1330
1331                        figdir = getcwd()+sep+'report_figures'+sep
1332                        if access(figdir,F_OK) == 0 :
1333                            mkdir (figdir)
1334                        latex_file_loc = figdir.replace(sep,altsep)   
1335
1336                        if len(label_id) == 1: 
1337                            graphname_latex = '%sgauge%s%s%s' %(latex_file_loc, gaugeloc2, which_quantity, label_id2) # storing files in production directory 
1338                            graphname_report = '%sgauge%s%s%s' %('..'+altsep+'report_figures'+altsep, gaugeloc2, which_quantity, label_id2) # giving location in latex output file
1339                            s = '\includegraphics[width=0.49\linewidth, height=50mm]{%s%s}' %(graphname_report, '.png')
1340                            fid.write(s)
1341                            if where1 % 2 == 0:
1342                                s = '\\\\ \n'
1343                                where1 = 0
1344                            else:
1345                                s = '& \n'
1346                            fid.write(s)
1347                            savefig(graphname_latex)
1348                   
1349                    if title_on == True:
1350                        title('%s scenario: %s at %s gauge' %(label_id, which_quantity, gaugeloc2))
1351                        #title('Gauge %s (MOST elevation %.2f, ANUGA elevation %.2f)' %(gaugeloc2, elevations[10,k,0], elevations[10,k,1] ))
1352
1353                    savefig(graphname) # save figures with sww file
1354
1355                if report == True and len(label_id) == 1:
1356                    for i in range(nn-1):
1357                        if nn > 2:
1358                            if plot_quantity[i] == 'stage' and elevations[0,k,j] > 0:
1359                                word_quantity += 'depth' + ', '
1360                            else:
1361                                word_quantity += plot_quantity[i] + ', '
1362                        else:
1363                            if plot_quantity[i] == 'stage' and elevations[0,k,j] > 0:
1364                                word_quantity += 'depth' + ', '
1365                            else:
1366                                word_quantity += plot_quantity[i]
1367                       
1368                    if plot_quantity[nn-1] == 'stage' and elevations[0,k,j] > 0:
1369                        word_quantity += ' and ' + 'depth'
1370                    else:
1371                        word_quantity += ' and ' + plot_quantity[nn-1]
1372                    caption = 'Time series for %s at %s location (elevation %.2fm)' %(word_quantity, locations[k], elev[k]) #gaugeloc.replace('_',' '))
1373                    if elev[k] == 0.0:
1374                        caption = 'Time series for %s at %s location (elevation %.2fm)' %(word_quantity, locations[k], elevations[0,k,j])
1375                        east = gauges[0]
1376                        north = gauges[1]
1377                        elev_output.append([locations[k],east,north,elevations[0,k,j]])
1378                    label = '%sgauge%s' %(label_id2, gaugeloc2)
1379                    s = '\end{tabular} \n \\caption{%s} \n \label{fig:%s} \n \end{figure} \n \n' %(caption, label)
1380                    fid.write(s)
1381                    cc += 1
1382                    if cc % 6 == 0: fid.write('\\clearpage \n')
1383                    savefig(graphname_latex)               
1384                   
1385            if report == True and len(label_id) > 1:
1386                for i in range(nn-1):
1387                    if nn > 2:
1388                        if plot_quantity[i] == 'stage' and elevations[0,k,j] > 0:
1389                            word_quantity += 'depth' + ','
1390                        else:
1391                            word_quantity += plot_quantity[i] + ', '
1392                    else:
1393                        if plot_quantity[i] == 'stage' and elevations[0,k,j] > 0:
1394                            word_quantity += 'depth'
1395                        else:
1396                            word_quantity += plot_quantity[i]
1397                    where1 = 0
1398                    count1 += 1
1399                    index = j*len(plot_quantity)
1400                    for which_quantity in plot_quantity:
1401                        where1 += 1
1402                        s = '\includegraphics[width=0.49\linewidth, height=50mm]{%s%s}' %(graphname_report[index], '.png')
1403                        index += 1
1404                        fid.write(s)
1405                        if where1 % 2 == 0:
1406                            s = '\\\\ \n'
1407                            where1 = 0
1408                        else:
1409                            s = '& \n'
1410                        fid.write(s)
1411                word_quantity += ' and ' + plot_quantity[nn-1]           
1412                label = 'gauge%s' %(gaugeloc2) 
1413                caption = 'Time series for %s at %s location (elevation %.2fm)' %(word_quantity, locations[k], elev[k])
1414                if elev[k] == 0.0:
1415                        caption = 'Time series for %s at %s location (elevation %.2fm)' %(word_quantity, locations[k], elevations[0,k,j])
1416                        thisgauge = gauges[k]
1417                        east = thisgauge[0]
1418                        north = thisgauge[1]
1419                        elev_output.append([locations[k],east,north,elevations[0,k,j]])
1420                       
1421                s = '\end{tabular} \n \\caption{%s} \n \label{fig:%s} \n \end{figure} \n \n' %(caption, label)
1422                fid.write(s)
1423                if float((k+1)/div - pp) == 0.:
1424                    fid.write('\\clearpage \n')
1425                    pp += 1
1426               
1427                #### finished generating figures ###
1428
1429            close('all')
1430       
1431    return texfile2, elev_output
1432
1433# FIXME (DSG): Add unit test, make general, not just 2 files,
1434# but any number of files.
1435def copy_code_files(dir_name, filename1, filename2):
1436    """Temporary Interface to new location"""
1437
1438    from anuga.shallow_water.data_manager import \
1439                    copy_code_files as dm_copy_code_files
1440    print 'copy_code_files has moved from util.py.  ',
1441    print 'Please use "from anuga.shallow_water.data_manager \
1442                                        import copy_code_files"'
1443   
1444    return dm_copy_code_files(dir_name, filename1, filename2)
1445
1446
1447def add_directories(root_directory, directories):
1448    """
1449    Add the first directory in directories to root_directory.
1450    Then add the second
1451    directory to the first directory and so on.
1452
1453    Return the path of the final directory.
1454
1455    This is handy for specifying and creating a directory
1456    where data will go.
1457    """
1458    dir = root_directory
1459    for new_dir in directories:
1460        dir = os.path.join(dir, new_dir)
1461        if not access(dir,F_OK):
1462            mkdir (dir)
1463    return dir
1464
1465def get_data_from_file(filename,separator_value = ','):
1466    """Temporary Interface to new location"""
1467    from anuga.shallow_water.data_manager import \
1468                        get_data_from_file as dm_get_data_from_file
1469    print 'get_data_from_file has moved from util.py'
1470    print 'Please use "from anuga.shallow_water.data_manager \
1471                                     import get_data_from_file"'
1472   
1473    return dm_get_data_from_file(filename,separator_value = ',')
1474
1475def store_parameters(verbose=False,**kwargs):
1476    """Temporary Interface to new location"""
1477   
1478    from anuga.shallow_water.data_manager \
1479                    import store_parameters as dm_store_parameters
1480    print 'store_parameters has moved from util.py.'
1481    print 'Please use "from anuga.shallow_water.data_manager \
1482                                     import store_parameters"'
1483   
1484    return dm_store_parameters(verbose=False,**kwargs)
1485
1486def remove_lone_verts(verts, triangles, number_of_full_nodes=None):
1487    """
1488    Removes vertices that are not associated with any triangles.
1489
1490    verts is a list/array of points
1491    triangles is a list of 3 element tuples. 
1492    Each tuple represents a triangle.
1493
1494    number_of_full_nodes relate to parallelism when a mesh has an
1495        extra layer of ghost points.
1496       
1497    """
1498    verts = ensure_numeric(verts)
1499    triangles = ensure_numeric(triangles)
1500   
1501    N = len(verts)
1502   
1503    # initialise the array to easily find the index of the first loner
1504    loners=arange(2*N, N, -1) # if N=3 [6,5,4]
1505    for t in triangles:
1506        for vert in t:
1507            loners[vert]= vert # all non-loners will have loners[i]=i
1508    #print loners
1509
1510    lone_start = 2*N - max(loners) # The index of the first loner
1511
1512    if lone_start-1 == N:
1513        # no loners
1514        pass
1515    elif min(loners[lone_start:N]) > N:
1516        # All the loners are at the end of the vert array
1517        verts = verts[0:lone_start]
1518    else:
1519        # change the loners list so it can be used to modify triangles
1520        # Remove the loners from verts
1521        # Could've used X=compress(less(loners,N),loners)
1522        # verts=take(verts,X)  to Remove the loners from verts
1523        # but I think it would use more memory
1524        new_i = 0
1525        for i in range(lone_start, N):
1526            if loners[i] >= N:
1527                # Loner!
1528                pass
1529            else:
1530                loners[i] = new_i
1531                verts[new_i] = verts[i]
1532                new_i += 1
1533        verts = verts[0:new_i]
1534
1535        # Modify the triangles
1536        #print "loners", loners
1537        #print "triangles before", triangles
1538        triangles = choose(triangles,loners)
1539        #print "triangles after", triangles
1540    return verts, triangles
1541
1542 
1543def get_centroid_values(x, triangles):
1544    """Compute centroid values from vertex values
1545   
1546    x: Values at vertices of triangular mesh
1547    triangles: Nx3 integer array pointing to vertex information
1548    for each of the N triangels. Elements of triangles are
1549    indices into x
1550    """
1551
1552       
1553    xc = zeros(triangles.shape[0], Float) # Space for centroid info
1554   
1555    for k in range(triangles.shape[0]):
1556        # Indices of vertices
1557        i0 = triangles[k][0]
1558        i1 = triangles[k][1]
1559        i2 = triangles[k][2]       
1560       
1561        xc[k] = (x[i0] + x[i1] + x[i2])/3
1562
1563
1564    return xc
1565
1566def make_plots_from_csv_file(directories_dic={dir:['gauge', 0, 0]},
1567                                output_dir='',
1568                                base_name='',
1569                                plot_numbers=['3-5'],
1570                                quantities=['speed','stage','momentum'],
1571                                assess_all_csv_files=True,
1572                                extra_plot_name='test' ):
1573
1574    msg = 'make_plots_from_csv_file has been replaced by csv2timeseries_graphs ',
1575    msg += 'Please use "from anuga.abstract_2d_finite_volumes.util import csv2timeseries_graphs"'
1576
1577    raise Exception, msg
1578    return csv2timeseries_graphs(directories_dic,
1579                                 output_dir,
1580                                 base_name,
1581                                 plot_numbers,
1582                                 quantities,
1583                                 extra_plot_name,
1584                                 assess_all_csv_files
1585                                 )
1586   
1587def csv2timeseries_graphs(directories_dic={},
1588                            output_dir='',
1589                            base_name=None,
1590                            plot_numbers='',
1591                            quantities=['stage'],
1592                            extra_plot_name='',
1593                            assess_all_csv_files=True,                           
1594                            create_latex=False,
1595                            verbose=False):
1596                               
1597    """
1598    Read in csv files that have the right header information and
1599    plot time series such as Stage, Speed, etc. Will also plot several
1600    time series on one plot. Filenames must follow this convention,
1601    <base_name><plot_number>.csv eg gauge_timeseries3.csv
1602   
1603    NOTE: relies that 'elevation' is in the csv file!
1604
1605    Each file represents a location and within each file there are
1606    time, quantity columns.
1607   
1608    For example:   
1609    if "directories_dic" defines 4 directories and in each directories
1610    there is a csv files corresponding to the right "plot_numbers",
1611    this will create a plot with 4 lines one for each directory AND
1612    one plot for each "quantities".  ??? FIXME: unclear.
1613   
1614    Usage:
1615        csv2timeseries_graphs(directories_dic={'slide'+sep:['Slide',0, 0],
1616                                       'fixed_wave'+sep:['Fixed Wave',0,0]},
1617                            output_dir='fixed_wave'+sep,
1618                            base_name='gauge_timeseries_',
1619                            plot_numbers='',
1620                            quantities=['stage','speed'],
1621                            extra_plot_name='',
1622                            assess_all_csv_files=True,                           
1623                            create_latex=False,
1624                            verbose=True)
1625            this will create one plot for stage with both 'slide' and
1626            'fixed_wave' lines on it for stage and speed for each csv
1627            file with 'gauge_timeseries_' as the prefix. The graghs
1628            will be in the output directory 'fixed_wave' and the graph
1629            axis will be determined by assessing all the
1630   
1631    ANOTHER EXAMPLE
1632        new_csv2timeseries_graphs(directories_dic={'slide'+sep:['Slide',0, 0],
1633                                       'fixed_wave'+sep:['Fixed Wave',0,0]},
1634                            output_dir='fixed_wave'+sep,
1635                            base_name='gauge_timeseries_',
1636                            plot_numbers=['1-3'],
1637                            quantities=['stage','speed'],
1638                            extra_plot_name='',
1639                            assess_all_csv_files=False,                           
1640                            create_latex=False,
1641                            verbose=True)
1642        This will plot csv files called gauge_timeseries_1.csv and
1643        gauge_timeseries3.csv from both 'slide' and 'fixed_wave' directories
1644        to 'fixed_wave'. There will be 4 plots created two speed and two stage
1645        one for each csv file. There will be two lines on each of these plots.
1646        And the axis will have been determined from only these files, had
1647        assess_all_csv_files = True all csv file with 'gauges_timeseries_' prefix
1648        would of been assessed.
1649   
1650    ANOTHER EXAMPLE   
1651         csv2timeseries_graphs({'J:'+sep+'anuga_validation'+sep:['new',20,-.1],
1652                                   'J:'+sep+'conical_island'+sep:['test',0,0]},
1653                                   output_dir='',
1654                                   plot_numbers=['1','3'],
1655                                   quantities=['stage','depth','bearing'],
1656                                   base_name='gauge_b',
1657                                   assess_all_csv_files=True,
1658                                  verbose=True)   
1659       
1660            This will produce one plot for each quantity (therefore 3) in the current directory,
1661            each plot will have 2 lines on them. The first plot named 'new' will have the time
1662            offseted by 20secs and the stage height adjusted by -0.1m
1663       
1664    Inputs:
1665        directories_dic: dictionary of directory with values (plot
1666                         legend name for directory), (start time of
1667                         the time series) and the (value to add to
1668                         stage if needed). For example
1669                        {dir1:['Anuga_ons',5000, 0],
1670                         dir2:['b_emoth',5000,1.5],
1671                         dir3:['b_ons',5000,1.5]}
1672                         Having multiple directories defined will plot them on
1673                         one plot, therefore there will be 3 lines on each of these
1674                         plot. If you only want one line per plot call csv2timeseries_graph
1675                         separately for each directory, eg only have one directory in the
1676                         'directories_dic' in each call.
1677                         
1678        output_dir: directory for the plot outputs. Only important to define
1679                    when you have more than one directory in your directories_dic,
1680                    if you have not defined it and you have multiple directories in
1681                    'directories_dic' there will be plots in each directory however only
1682                    one directory will contain the complete plot/graphs.
1683       
1684        base_name: Is used a couple of times. 1) to find the csv files to be plotted
1685                   if there is no 'plot_numbers' then csv files with 'base_name' are
1686                   plotted and 2) in the title of the plots, the lenght of base_name is
1687                   removed from the front of the filename to be used in the title.
1688                   This could be changed if needed.
1689                   Note is ignored if assess_all_csv_files=True
1690       
1691        plot_numbers: a String list of numbers to plot. For example
1692                      [0-4,10,15-17] will read and attempt to plot
1693                       the follow 0,1,2,3,4,10,15,16,17
1694                       NOTE: if no plot numbers this will create
1695                       one plot per quantity, per gauge
1696        quantities: Will get available quantities from the header in the csv file.
1697                    quantities must be one of these.
1698                    NOTE: ALL QUANTITY NAMES MUST BE lower case!
1699                   
1700        extra_plot_name: A string that is appended to the end of the
1701                         output filename.
1702                   
1703        assess_all_csv_files: if true it will read ALL csv file with
1704                             "base_name", regardless of 'plot_numbers'
1705                              and determine a uniform set of axes for
1706                              Stage, Speed and Momentum. IF FALSE it
1707                              will only read the csv file within the
1708                             'plot_numbers'
1709                             
1710        create_latex: NOT IMPLEMENTED YET!! sorry Jane....
1711       
1712    OUTPUTS: saves the plots to
1713              <output_dir><base_name><plot_number><extra_plot_name>.png
1714             
1715     
1716    """
1717    try: 
1718        import pylab
1719    except ImportError:
1720        msg='csv2timeseries_graphs needs pylab to be installed correctly'
1721        raise msg
1722            #ANUGA don't need pylab to work so the system doesn't
1723            #rely on pylab being installed
1724        return
1725
1726    from os import sep
1727    from anuga.shallow_water.data_manager import \
1728                               get_all_files_with_extension, csv2dict
1729
1730    seconds_in_hour = 3600
1731    seconds_in_minutes = 60
1732   
1733    quantities_label={}
1734#    quantities_label['time'] = 'time (hours)'
1735    quantities_label['time'] = 'time (minutes)'
1736    quantities_label['stage'] = 'wave height (m)'
1737    quantities_label['speed'] = 'speed (m/s)'
1738    quantities_label['momentum'] = 'momentum (m^2/sec)'
1739    quantities_label['depth'] = 'water depth (m)'
1740    quantities_label['xmomentum'] = 'momentum (m^2/sec)'
1741    quantities_label['ymomentum'] = 'momentum (m^2/sec)'
1742    quantities_label['bearing'] = 'degrees (o)'
1743    quantities_label['elevation'] = 'elevation (m)'
1744
1745   
1746    if extra_plot_name != '':
1747        extra_plot_name='_'+extra_plot_name
1748
1749    new_plot_numbers=[]
1750    #change plot_numbers to list, eg ['0-4','10']
1751    #to ['0','1','2','3','4','10']
1752    for i, num_string in enumerate(plot_numbers):
1753        if '-' in num_string: 
1754            start = int(num_string[:num_string.rfind('-')])
1755            end = int(num_string[num_string.rfind('-')+1:])+1
1756            for x in range(start, end):
1757                new_plot_numbers.append(str(x))
1758        else:
1759            new_plot_numbers.append(num_string)
1760
1761    #finds all the files that fit the specs provided and return a list of them
1762    #so to help find a uniform max and min for the plots...
1763    list_filenames=[]
1764    all_csv_filenames=[]
1765    if verbose: print 'Determining files to access for axes ranges \n'
1766   
1767    #print directories_dic.keys(), base_name
1768 
1769    for i,directory in enumerate(directories_dic.keys()):
1770        all_csv_filenames.append(get_all_files_with_extension(directory,
1771                                  base_name,'.csv'))
1772
1773        filenames=[]
1774        if plot_numbers == '': 
1775            list_filenames.append(get_all_files_with_extension(directory,
1776                                  base_name,'.csv'))
1777        else:
1778            for number in new_plot_numbers:
1779#                print 'number!!!', base_name, number
1780                filenames.append(base_name+number)
1781#                print filenames
1782            list_filenames.append(filenames)
1783
1784
1785
1786    #print "list_filenames", list_filenames
1787
1788    #use all the files to get the values for the plot axis
1789    max_start_time= -1000.
1790    min_start_time = 100000 
1791   
1792   
1793    if verbose: print 'Determining uniform axes \n' 
1794    #this entire loop is to determine the min and max range for the
1795    #axes of the plots
1796
1797#    quantities.insert(0,'elevation')
1798    quantities.insert(0,'time')
1799
1800    directory_quantity_value={}
1801#    quantity_value={}
1802    min_quantity_value={}
1803    max_quantity_value={}
1804
1805   
1806    for i, directory in enumerate(directories_dic.keys()):
1807        filename_quantity_value={}
1808        if assess_all_csv_files==False:
1809            which_csv_to_assess = list_filenames[i]
1810        else:
1811            #gets list of filenames for directory "i"
1812            which_csv_to_assess = all_csv_filenames[i]
1813#        print'IN DIR', list_filenames[i]
1814       
1815
1816
1817       
1818        for j, filename in enumerate(which_csv_to_assess):
1819            quantity_value={}
1820
1821            dir_filename=join(directory,filename)
1822            attribute_dic, title_index_dic = csv2dict(dir_filename+
1823                                                       '.csv')
1824            directory_start_time = directories_dic[directory][1]
1825            directory_add_tide = directories_dic[directory][2]
1826
1827            if verbose: print 'reading: %s.csv' %dir_filename
1828#            print 'keys',attribute_dic.keys()
1829            #add time to get values
1830            for k, quantity in enumerate(quantities):
1831                quantity_value[quantity] = [float(x) for x in attribute_dic[quantity]]
1832
1833                #add tide to stage if provided
1834                if quantity == 'stage':
1835                     quantity_value[quantity]=array(quantity_value[quantity])+directory_add_tide
1836
1837                #condition to find max and mins for all the plots
1838                # populate the list with something when i=0 and j=0 and
1839                # then compare to the other values to determine abs max and min
1840                if i==0 and j==0:
1841
1842                    min_quantity_value[quantity], \
1843                    max_quantity_value[quantity] = get_min_max_values(quantity_value[quantity])
1844
1845                    if quantity != 'time':
1846                        min_quantity_value[quantity] = min_quantity_value[quantity] *1.1
1847                        max_quantity_value[quantity] = max_quantity_value[quantity] *1.1
1848
1849                   
1850#                    print '1 min,max',i,j,k,quantity, min_quantity_value[quantity],max_quantity_value[quantity],directory, filename
1851                else:
1852#                    print 'min,max',i,j,k,quantity, min_quantity_value[quantity],max_quantity_value[quantity],directory, filename
1853                    min, max = get_min_max_values(quantity_value[quantity])
1854#                    print "MIN",min, max
1855               
1856                    #min and max are multipled by "1+increase_axis" to get axes that are slighty bigger
1857                    # than the max and mins so the plots look good.
1858
1859                    increase_axis = (max-min)*0.05
1860#                    print quantity, "MIN MAX", max, min
1861                    if min<=min_quantity_value[quantity]:
1862                        if quantity == 'time': 
1863                            min_quantity_value[quantity]=min
1864                        else:
1865                            if round(min,2) == 0.00:
1866                                min_quantity_value[quantity]=-increase_axis
1867#                                min_quantity_value[quantity]=-2.
1868                                #min_quantity_value[quantity]= -max_quantity_value[quantity]*increase_axis
1869                            else:
1870#                                min_quantity_value[quantity]=min*(1+increase_axis)
1871                                min_quantity_value[quantity]=min-increase_axis
1872#                        print quantity, min_quantity_value[quantity]
1873                   
1874                    if max>max_quantity_value[quantity]: 
1875                        if quantity == 'time': 
1876                            max_quantity_value[quantity]=max
1877                        else:
1878                            max_quantity_value[quantity]=max+increase_axis
1879#                            max_quantity_value[quantity]=max*(1+increase_axis)
1880#                        print quantity, max_quantity_value[quantity],increase_axis
1881               
1882#                print 'min,maj',quantity, min_quantity_value[quantity],max_quantity_value[quantity]
1883
1884           
1885           
1886           
1887            #set the time... ???
1888            if min_start_time > directory_start_time: 
1889                min_start_time = directory_start_time
1890            if max_start_time < directory_start_time: 
1891                max_start_time = directory_start_time
1892            #print 'start_time' , max_start_time, min_start_time
1893           
1894            filename_quantity_value[filename]=quantity_value
1895           
1896        directory_quantity_value[directory]=filename_quantity_value
1897   
1898    #final step to unifrom axis for the graphs
1899    quantities_axis={}
1900   
1901    for i, quantity in enumerate(quantities):
1902        quantities_axis[quantity] = (float(min_start_time)/float(seconds_in_minutes),
1903                                        (float(max_quantity_value['time'])+float(max_start_time))\
1904                                              /float(seconds_in_minutes),
1905                                         min_quantity_value[quantity], 
1906                                         max_quantity_value[quantity])
1907        if verbose and (quantity != 'time' and quantity != 'elevation'): 
1908            print 'axis for quantity %s are x:(%s to %s)%s and y:(%s to %s)%s' %(quantity, 
1909                               quantities_axis[quantity][0],
1910                               quantities_axis[quantity][1],
1911                               quantities_label['time'],
1912                               quantities_axis[quantity][2],
1913                               quantities_axis[quantity][3],
1914                               quantities_label[quantity])
1915   
1916        #print  quantities_axis[quantity]
1917
1918    cstr = ['b', 'r', 'g', 'c', 'm', 'y', 'k']
1919
1920    if verbose: print 'Now start to plot \n'
1921   
1922    i_max = len(directories_dic.keys())
1923    legend_list_dic={}
1924    legend_list =[]
1925    for i, directory in enumerate(directories_dic.keys()):
1926       
1927        if verbose: print'Plotting in %s %s' %(directory, new_plot_numbers)
1928#        print 'LIST',list_filenames
1929        #FIXME THIS SORT IS VERY IMPORTANT, without it the assigned plot numbers may not work correctly
1930        #there must be a better way
1931        list_filenames[i].sort()
1932        for j, filename in enumerate(list_filenames[i]):
1933#            print'IN plot', list_filenames[i]
1934           
1935            if verbose: print'Starting %s' %filename 
1936            directory_name = directories_dic[directory][0]
1937            directory_start_time = directories_dic[directory][1]
1938            directory_add_tide = directories_dic[directory][2]
1939           
1940            #create an if about the start time and tide hieght
1941            #if they don't exist
1942            #print 'i %s,j %s, number %s, file %s' %(i,j,number,file)
1943            attribute_dic, title_index_dic = csv2dict(directory+sep+filename+'.csv')
1944            #get data from dict in to list
1945            #do maths to list by changing to array
1946            t=(array(directory_quantity_value[directory][filename]['time'])+directory_start_time)/seconds_in_minutes
1947
1948            #finds the maximum elevation, used only as a test
1949            # and as info in the graphs
1950            max_ele=-100000
1951            min_ele=100000
1952            elevation = [float(x) for x in attribute_dic["elevation"]]
1953           
1954            min_ele, max_ele = get_min_max_values(elevation)
1955           
1956            if min_ele != max_ele:
1957                print "Note! Elevation changes in %s" %dir_filename
1958
1959            # creates a dictionary with keys that is the filename and attributes are a list of
1960            # lists containing 'directory_name' and 'elevation'. This is used to make the contents
1961            # for the legends in the graphs, this is the name of the model and the elevation.
1962            # All in this great one liner from DG. If the key 'filename' doesn't exist it creates the
1963            # entry if the entry exist it appends to the key.
1964           
1965            legend_list_dic.setdefault(filename,[]).append([directory_name,round(max_ele,3)])
1966
1967            # creates a LIST for the legend on the last iteration of the directories
1968            # which is when "legend_list_dic" has been fully populated. Creates a list of strings
1969            # which is used in the legend
1970            # only runs on the last iteration for all the gauges(csv) files
1971            # empties the list before creating it
1972            if i==i_max-1:
1973                legend_list=[]
1974   
1975                #print 'DIC',legend_list_dic
1976                for name_and_elevation in legend_list_dic[filename]:
1977                    legend_list.append('%s (elevation = %sm)'%(name_and_elevation[0],name_and_elevation[1]))
1978           
1979            #print 'filename',filename, quantities
1980            #skip time and elevation so it is not plotted!
1981            for k, quantity in enumerate(quantities):
1982                if quantity != 'time' and quantity != 'elevation':
1983                   
1984                    num=int(k*100+j)
1985                    pylab.figure(num)
1986                    pylab.ylabel(quantities_label[quantity])
1987                    pylab.plot(t, directory_quantity_value[directory][filename][quantity], c = cstr[i], linewidth=1)
1988                    pylab.xlabel(quantities_label['time'])
1989                    pylab.axis(quantities_axis[quantity])
1990                    pylab.legend(legend_list,loc='upper right')
1991                   
1992                    pylab.title('%s at %s gauge' %(quantity,filename[len(base_name):]))
1993                    if output_dir == '':
1994                        figname = '%s%s%s_%s%s.png' %(directory,sep,
1995                                            filename,
1996                                            quantity,
1997                                            extra_plot_name)
1998                    else:
1999                        figname = '%s%s%s_%s%s.png' %(output_dir,sep,
2000                                            filename,
2001                                            quantity,
2002                                            extra_plot_name)
2003                    if verbose: print 'saving figure here %s' %figname
2004                    pylab.savefig(figname)
2005           
2006    if verbose: print 'Closing all plots'
2007    pylab.close('all')
2008    del pylab
2009    if verbose: print 'Finished closing plots'
2010
2011def get_min_max_values(list=None):
2012    """
2013    Returns the min and max of the list it was provided.
2014    """
2015    if list == None: print 'List must be provided'
2016       
2017    return min(list), max(list)
2018
2019
2020
2021def get_runup_data_for_locations_from_file(gauge_filename,
2022                                           sww_filename,
2023                                           runup_filename,
2024                                           size=10,
2025                                           verbose=False):
2026
2027    """this will read a csv file with the header x,y. Then look in a square
2028    'size'x2 around this position for the 'max_inundaiton_height' in the
2029    'sww_filename' and report the findings in the 'runup_filename
2030   
2031    WARNING: NO TESTS!
2032    """
2033
2034    from anuga.shallow_water.data_manager import get_all_directories_with_name,\
2035                                                 get_maximum_inundation_data,\
2036                                                 csv2dict
2037                                                 
2038    file = open(runup_filename,"w")
2039    file.write("easting,northing,runup \n ")
2040    file.close()
2041   
2042    #read gauge csv file to dictionary
2043    attribute_dic, title_index_dic = csv2dict(gauge_filename)
2044    northing = [float(x) for x in attribute_dic["y"]]
2045    easting = [float(x) for x in attribute_dic["x"]]
2046
2047    print 'Reading %s' %sww_filename
2048
2049    runup_locations=[]
2050    for i, x in enumerate(northing):
2051#        print 'easting,northing',i,easting[i],northing[i]
2052        poly = [[int(easting[i]+size),int(northing[i]+size)],
2053                [int(easting[i]+size),int(northing[i]-size)],
2054                [int(easting[i]-size),int(northing[i]-size)],
2055                [int(easting[i]-size),int(northing[i]+size)]]
2056       
2057        run_up, x_y = get_maximum_inundation_data(filename=sww_filename,
2058                                              polygon=poly,
2059                                              verbose=False) 
2060        #if no runup will return 0 instead of NONE
2061        if run_up==None: run_up=0
2062        if x_y==None: x_y=[0,0]
2063       
2064        if verbose:
2065            print 'maximum inundation runup near %s is %s meters' %(x_y,run_up)
2066       
2067        #writes to file
2068        file = open(runup_filename,"a")
2069        temp = '%s,%s,%s \n' %(x_y[0], x_y[1], run_up)
2070        file.write(temp)
2071        file.close()
2072       
2073
2074def sww2csv_gauges(sww_file,
2075                   gauge_file,
2076                   out_name=None,
2077                   quantities = ['stage', 'depth', 'elevation',
2078                                 'xmomentum', 'ymomentum'],
2079                   verbose=False,
2080                   use_cache = True):
2081    """
2082   
2083    Inputs:
2084       
2085        NOTE: if using csv2timeseries_graphs after creating csv file,
2086        it is essential to export quantities 'depth' and 'elevation'.
2087        'depth' is good to analyse gauges on land and elevation is used
2088        automatically by csv2timeseries_graphs in the legend.
2089       
2090        sww_file: path to any sww file
2091       
2092        points_file: Assumes that it follows this format
2093            name, easting, northing, elevation
2094            point1, 100.3, 50.2, 10.0
2095            point2, 10.3, 70.3, 78.0
2096       
2097        NOTE: order of column can change but names eg 'easting', 'elevation'
2098        must be the same! ALL lowercaps!
2099
2100        out_name: prefix for output file name (default is 'gauge_')
2101       
2102    Outputs:
2103        one file for each gauge/point location in the points file. They
2104        will be named with this format in the same directory as the 'sww_file'
2105            <out_name><name>.csv
2106        eg gauge_point1.csv if <out_name> not supplied
2107           myfile_2_point1.csv if <out_name> ='myfile_2_'
2108           
2109           
2110        They will all have a header
2111   
2112    Usage: gauges_sww2csv(sww_file='test1.sww',
2113                          quantities = ['stage', 'elevation','depth','bearing'],
2114                          gauge_file='gauge.txt')   
2115   
2116    Interpolate the quantities at a given set of locations, given
2117    an sww file.
2118    The results are written to a csv file.
2119
2120    In the future let points be a points file.
2121    And the user choose the quantities.
2122
2123    This is currently quite specific.
2124    If it need to be more general, chagne things.
2125
2126    This is really returning speed, not velocity.
2127     
2128   
2129    """
2130   
2131    from csv import reader,writer
2132    from anuga.utilities.numerical_tools import ensure_numeric, mean, NAN
2133    from Numeric import array, resize, shape, Float, zeros, take, argsort, argmin
2134    import string
2135    from anuga.shallow_water.data_manager import get_all_swwfiles
2136#    quantities =  ['stage', 'elevation', 'xmomentum', 'ymomentum']
2137    #print "points",points
2138
2139    assert type(gauge_file) == type(''),\
2140           'Gauge filename must be a string'
2141    assert type(out_name) == type(''),\
2142           'Output filename prefix must be a string'
2143   
2144    try:
2145    #    fid = open(gauge_file)
2146        point_reader = reader(file(gauge_file))
2147
2148    except Exception, e:
2149        msg = 'File "%s" could not be opened: Error="%s"'\
2150                  %(gauge_file, e)
2151        raise msg
2152    if verbose: print '\n Gauges obtained from: %s \n' %gauge_file
2153   
2154   
2155    point_reader = reader(file(gauge_file))
2156    points = []
2157    point_name = []
2158   
2159    #read point info from file
2160    for i,row in enumerate(point_reader):
2161#        print 'i',i,'row',row
2162        #read header and determine the column numbers to read correcty.
2163        if i==0:
2164            for j,value in enumerate(row):
2165#                print 'j',j,value, row
2166                if value.strip()=='easting':easting=j
2167                if value.strip()=='northing':northing=j
2168                if value.strip()=='name':name=j
2169                if value.strip()=='elevation':elevation=j
2170        else:
2171#            print i,'easting',easting,'northing',northing, row[easting]
2172            points.append([float(row[easting]),float(row[northing])])
2173            point_name.append(row[name])
2174       
2175    #convert to array for file_function
2176    points_array = array(points,Float)
2177       
2178    points_array = ensure_absolute(points_array)
2179
2180    dir_name, base = os.path.split(sww_file)   
2181    #print 'dirname',dir_name, base
2182    #need to get current directory so when path and file
2183    #are "joined" below the directory is correct
2184    if dir_name == '':
2185        dir_name =getcwd()
2186       
2187    if access(sww_file,R_OK):
2188        if verbose: print 'File %s exists' %(sww_file)
2189    else:
2190        msg = 'File "%s" could not be opened: no read permission'\
2191               %(sww_file)
2192        raise msg
2193
2194    sww_files = get_all_swwfiles(look_in_dir=dir_name,
2195                                 base_name=base,
2196                                 verbose=verbose)
2197   
2198    #to make all the quantities lower case for file_function
2199    quantities = [quantity.lower() for quantity in quantities]
2200
2201    # what is quantities are needed from sww file to calculate output quantities
2202    # also
2203
2204    core_quantities = ['stage', 'elevation', 'xmomentum', 'ymomentum']
2205   
2206    for sww_file in sww_files:
2207   
2208#        print 'sww_file',sww_file
2209        sww_file = join(dir_name, sww_file+'.sww')
2210#        print 'sww_file',sww_file, core_quantities
2211       
2212        callable_sww = file_function(sww_file,
2213                                 quantities=core_quantities,
2214                                 interpolation_points=points_array,
2215                                 verbose=verbose,
2216                                 use_cache=use_cache)
2217
2218    if out_name is None:
2219        gauge_file='gauge_'
2220    else:
2221        gauge_file = out_name
2222
2223    heading = [quantity for quantity in quantities]
2224    heading.insert(0,'time')
2225
2226#    print 'start time', callable_sww.starttime, heading, quantities
2227
2228    #create a list of csv writers for all the points and write header
2229    points_writer = []
2230    for i,point in enumerate(points):
2231        #print 'gauge file:',dir_name+sep+'gauge_'+point_name[i]+'.csv'
2232        points_writer.append(writer(file(dir_name+sep+gauge_file+point_name[i]+'.csv', "wb")))
2233        points_writer[i].writerow(heading)
2234   
2235    if verbose: print 'Writing csv files'
2236
2237    for time in callable_sww.get_time():
2238
2239        for point_i, point in enumerate(points_array):
2240            #add domain starttime to relative time.
2241            points_list = [time+callable_sww.starttime]
2242#            print'time',time,'point_i',point_i,point, points_array
2243            point_quantities = callable_sww(time,point_i)
2244#            print "quantities", point_quantities
2245           
2246            for quantity in quantities:
2247                if quantity==NAN:
2248                    print 'quantity does not exist in' %callable_sww.get_name
2249                else:
2250                    if quantity == 'stage':
2251                        points_list.append(point_quantities[0])
2252                       
2253                    if quantity == 'elevation':
2254                        points_list.append(point_quantities[1])
2255                       
2256                    if quantity == 'xmomentum':
2257                        points_list.append(point_quantities[2])
2258                       
2259                    if quantity == 'ymomentum':
2260                        points_list.append(point_quantities[3])
2261                       
2262                    if quantity == 'depth':
2263                        points_list.append(point_quantities[0] - point_quantities[1])
2264                       
2265                       
2266                    if quantity == 'momentum':
2267                        momentum = sqrt(point_quantities[2]**2 +\
2268                                        point_quantities[3]**2)
2269                        points_list.append(momentum)
2270                       
2271                    if quantity == 'speed':
2272                        #if depth is less than 0.001 then speed = 0.0
2273                        if point_quantities[0] - point_quantities[1] < 0.001:
2274                            vel = 0.0
2275                        else:
2276                            if point_quantities[2] < 1.0e6:
2277                                momentum = sqrt(point_quantities[2]**2 +\
2278                                                point_quantities[3]**2)
2279    #                            vel = momentum/depth             
2280                                vel = momentum/(point_quantities[0] - point_quantities[1])
2281    #                            vel = momentum/(depth + 1.e-6/depth)
2282                            else:
2283                                momentum = 0
2284                                vel = 0
2285                           
2286                        points_list.append(vel)
2287                       
2288                    if quantity == 'bearing':
2289                        points_list.append(calc_bearing(point_quantities[2],
2290                                                        point_quantities[3]))
2291                       
2292                #print 'list',points_list
2293               
2294            points_writer[point_i].writerow(points_list)
2295       
2296
2297def greens_law(d1,d2,h1,verbose=False):
2298    """
2299
2300    Green's Law allows an approximation of wave amplitude at
2301    a given depth based on the fourh root of the ratio of two depths
2302    and the amplitude at another given depth.
2303
2304    Note, wave amplitude is equal to stage.
2305   
2306    Inputs:
2307
2308    d1, d2 - the two depths
2309    h1     - the wave amplitude at d1
2310    h2     - the derived amplitude at d2
2311
2312    h2 = h1 (d1/d2)^(1/4), where d2 cannot equal 0.
2313   
2314    """
2315
2316    d1 = ensure_numeric(d1)
2317    d2 = ensure_numeric(d2)
2318    h1 = ensure_numeric(h1)
2319
2320    if d1 <= 0.0:
2321        msg = 'the first depth, d1 (%f), must be strictly positive' %(d1)
2322        raise Exception(msg)
2323
2324    if d2 <= 0.0:
2325        msg = 'the second depth, d2 (%f), must be strictly positive' %(d2)
2326        raise Exception(msg)
2327   
2328    if h1 <= 0.0:
2329        msg = 'the wave amplitude, h1 (%f), must be strictly positive' %(h1)
2330        raise Exception(msg)
2331   
2332    h2 = h1*(d1/d2)**0.25
2333
2334    assert h2 > 0
2335   
2336    return h2
2337       
2338
2339def square_root(s):
2340    return sqrt(s)
Note: See TracBrowser for help on using the repository browser.