source: anuga_core/source_numpy_conversion/anuga/abstract_2d_finite_volumes/util.py @ 5899

Last change on this file since 5899 was 5899, checked in by rwilson, 15 years ago

Initial NumPy? changes (again!).

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