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

Last change on this file since 5372 was 5372, checked in by jakeman, 15 years ago

updated mux2 boundary interpolation methods

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