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

Last change on this file since 4949 was 4949, checked in by sexton, 16 years ago

(a) minor updates for Cairns example in manual (b) scripts for stratification investigation for other model areas

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