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

Last change on this file since 5482 was 5482, checked in by ole, 16 years ago

Comments

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