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

Last change on this file since 4306 was 4306, checked in by nick, 17 years ago

Added get_data_from_file to util.py and add some tests

File size: 51.8 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, W_OK, sep
12from os.path import exists, basename
13from warnings import warn
14from shutil import copy
15
16from anuga.geospatial_data.geospatial_data import ensure_absolute
17
18def file_function(filename,
19                  domain=None,
20                  quantities=None,
21                  interpolation_points=None,
22                  time_thinning=1,
23                  verbose=False,
24                  use_cache=False):
25    """Read time history of spatial data from NetCDF file and return
26    a callable object.
27
28    Input variables:
29   
30    filename - Name of sww or tms file
31       
32       If the file has extension 'sww' then it is assumed to be spatio-temporal
33       or temporal and the callable object will have the form f(t,x,y) or f(t)
34       depending on whether the file contains spatial data
35
36       If the file has extension 'tms' then it is assumed to be temporal only
37       and the callable object will have the form f(t)
38
39       Either form will return interpolated values based on the input file
40       using the underlying interpolation_function.
41
42    domain - Associated domain object   
43       If domain is specified, model time (domain.starttime)
44       will be checked and possibly modified.
45   
46       All times are assumed to be in UTC
47       
48       All spatial information is assumed to be in absolute UTM coordinates.
49
50    quantities - the name of the quantity to be interpolated or a
51                 list of quantity names. The resulting function will return
52                 a tuple of values - one for each quantity 
53
54    interpolation_points - list of absolute UTM coordinates for points (N x 2)
55    or geospatial object or points file name at which values are sought
56   
57    use_cache: True means that caching of intermediate result of
58               Interpolation_function is attempted
59
60   
61    See Interpolation function for further documentation
62    """
63
64
65    # Build arguments and keyword arguments for use with caching or apply.
66    args = (filename,)
67   
68    kwargs = {'domain': domain,
69              'quantities': quantities,
70              'interpolation_points': interpolation_points,
71              'time_thinning': time_thinning,                   
72              'verbose': verbose,
73              'use_cache': use_cache
74              }
75
76    #caching moved to deeper within the function to avoid caching an
77    #instance of an object, which isn't generally good.
78    f = apply(_file_function,
79                  args, kwargs)
80
81
82    #FIXME (Ole): Pass cache arguments, such as compression, in some sort of
83    #structure
84       
85
86    return f
87
88
89
90def _file_function(filename,
91                   domain=None,
92                   quantities=None,
93                   interpolation_points=None,
94                   time_thinning=1, 
95                   verbose=False,
96                   use_cache=False):
97    """Internal function
98   
99    See file_function for documentatiton
100    """
101   
102
103    #FIXME (OLE): Should check origin of domain against that of file
104    #In fact, this is where origin should be converted to that of domain
105    #Also, check that file covers domain fully.
106
107    #Take into account:
108    #- domain's georef
109    #- sww file's georef
110    #- interpolation points as absolute UTM coordinates
111
112
113    assert type(filename) == type(''),\
114               'First argument to File_function must be a string'
115
116    try:
117        fid = open(filename)
118    except Exception, e:
119        msg = 'File "%s" could not be opened: Error="%s"'\
120                  %(filename, e)
121        raise msg
122
123    line = fid.readline()
124    fid.close()
125
126    if quantities is None: 
127        if domain is not None:
128            quantities = domain.conserved_quantities
129
130
131
132    if line[:3] == 'CDF':
133        return get_netcdf_file_function(filename, domain, quantities,
134                                        interpolation_points,
135                                        time_thinning=time_thinning,
136                                        verbose=verbose,
137                                        use_cache=use_cache)
138    else:
139        raise 'Must be a NetCDF File'
140
141
142
143def get_netcdf_file_function(filename,
144                             domain=None,
145                             quantity_names=None,
146                             interpolation_points=None,
147                             time_thinning=1,                             
148                             verbose=False,
149                             use_cache=False):
150    """Read time history of spatial data from NetCDF sww file and
151    return a callable object f(t,x,y)
152    which will return interpolated values based on the input file.
153
154    If domain is specified, model time (domain.starttime)
155    will be checked and possibly modified
156   
157    All times are assumed to be in UTC
158
159    See Interpolation function for further documetation
160   
161    """
162   
163   
164    #FIXME: Check that model origin is the same as file's origin
165    #(both in UTM coordinates)
166    #If not - modify those from file to match domain
167    #Take this code from e.g. dem2pts in data_manager.py
168    #FIXME: Use geo_reference to read and write xllcorner...
169       
170
171    #FIXME: Maybe move caching out to this level rather than at the
172    #Interpolation_function level (below)
173
174    import time, calendar, types
175    from anuga.config import time_format
176    from Scientific.IO.NetCDF import NetCDFFile
177    from Numeric import array, zeros, Float, alltrue, concatenate, reshape
178
179    #Open NetCDF file
180    if verbose: print 'Reading', filename
181    fid = NetCDFFile(filename, 'r')
182
183    if type(quantity_names) == types.StringType:
184        quantity_names = [quantity_names]       
185   
186    if quantity_names is None or len(quantity_names) < 1:
187        #If no quantities are specified get quantities from file
188        #x, y, time are assumed as the independent variables so
189        #they are excluded as potentiol quantities
190        quantity_names = []
191        for name in fid.variables.keys():
192            if name not in ['x', 'y', 'time']:
193                quantity_names.append(name)
194
195    if len(quantity_names) < 1:               
196        msg = 'ERROR: At least one independent value must be specified'
197        raise msg
198
199
200    if interpolation_points is not None:
201        interpolation_points = ensure_absolute(interpolation_points)
202        msg = 'Points must by N x 2. I got %d' %interpolation_points.shape[1]
203        assert interpolation_points.shape[1] == 2, msg
204
205
206    #Now assert that requested quantitites (and the independent ones)
207    #are present in file
208    missing = []
209    for quantity in ['time'] + quantity_names:
210        if not fid.variables.has_key(quantity):
211            missing.append(quantity)
212
213    if len(missing) > 0:
214        msg = 'Quantities %s could not be found in file %s'\
215              %(str(missing), filename)
216        fid.close()
217        raise Exception, msg
218
219    #Decide whether this data has a spatial dimension
220    spatial = True
221    for quantity in ['x', 'y']:
222        if not fid.variables.has_key(quantity):
223            spatial = False
224
225    if filename[-3:] == 'tms' and spatial is True:
226        msg = 'Files of type tms must not contain spatial information'
227        raise msg
228
229    if filename[-3:] == 'sww' and spatial is False:
230        msg = 'Files of type sww must contain spatial information'       
231        raise msg       
232
233    #Get first timestep
234    try:
235        starttime = fid.starttime[0]
236    except ValueError:
237        msg = 'Could not read starttime from file %s' %filename
238        raise msg
239
240    #Get variables
241    #if verbose: print 'Get variables'   
242    time = fid.variables['time'][:]   
243
244    # Get time independent stuff
245    if spatial:
246        #Get origin
247        xllcorner = fid.xllcorner[0]
248        yllcorner = fid.yllcorner[0]
249        zone = fid.zone[0]       
250
251        x = fid.variables['x'][:]
252        y = fid.variables['y'][:]
253        triangles = fid.variables['volumes'][:]
254
255        x = reshape(x, (len(x),1))
256        y = reshape(y, (len(y),1))
257        vertex_coordinates = concatenate((x,y), axis=1) #m x 2 array
258
259        if interpolation_points is not None:
260            #Adjust for georef
261            interpolation_points[:,0] -= xllcorner
262            interpolation_points[:,1] -= yllcorner       
263       
264
265
266
267    if domain is not None:
268        #Update domain.startime if it is *earlier* than starttime
269        if starttime > domain.starttime:
270            msg = 'WARNING: Start time as specified in domain (%f)'\
271                  %domain.starttime
272            msg += ' is earlier than the starttime of file %s (%f).'\
273                     %(filename, starttime)
274            msg += ' Modifying domain starttime accordingly.'
275           
276            if verbose: print msg
277            domain.starttime = starttime #Modifying model time
278            if verbose: print 'Domain starttime is now set to %f'\
279               %domain.starttime
280
281
282        #If domain.startime is *later* than starttime,
283        #move time back - relative to domain's time
284        if domain.starttime > starttime:
285            time = time - domain.starttime + starttime
286
287        #FIXME Use method in geo to reconcile
288        #if spatial:
289        #assert domain.geo_reference.xllcorner == xllcorner
290        #assert domain.geo_reference.yllcorner == yllcorner
291        #assert domain.geo_reference.zone == zone       
292       
293    if verbose:
294        print 'File_function data obtained from: %s' %filename
295        print '  References:'
296        #print '    Datum ....' #FIXME
297        if spatial:
298            print '    Lower left corner: [%f, %f]'\
299                  %(xllcorner, yllcorner)
300        print '    Start time:   %f' %starttime               
301       
302   
303    # Produce values for desired data points at
304    # each timestep for each quantity
305    quantities = {}
306    for i, name in enumerate(quantity_names):
307        quantities[name] = fid.variables[name][:]
308    fid.close()
309   
310
311    #from least_squares import Interpolation_function
312    from anuga.fit_interpolate.interpolate import Interpolation_function
313
314    if not spatial:
315        vertex_coordinates = triangles = interpolation_points = None         
316
317   
318 
319    args = (time, quantities, quantity_names, vertex_coordinates, 
320            triangles, interpolation_points, )
321           
322    kwargs = {'time_thinning': time_thinning,
323              'verbose': verbose
324              }
325#    print'CACHING FROM UTIL.py for interpolation_function', use_cache
326    from anuga.caching import myhash
327    if use_cache is True:
328        from caching import cache
329       
330        interpolation_function = cache(Interpolation_function,
331                                       args, kwargs,
332                                       verbose=verbose,
333                                       compression=False)
334    else:
335        interpolation_function = apply(Interpolation_function,
336                                       args, kwargs)
337#    print 'myhash', myhash(interpolation_function)
338    return interpolation_function
339
340
341
342
343def multiple_replace(text, dictionary):
344    """Multiple replace of words in text
345
346    text:       String to be modified
347    dictionary: Mapping of words that are to be substituted
348
349    Python Cookbook 3.14 page 88 and page 90
350    """
351
352    import re
353   
354    #Create a regular expression from all of the dictionary keys
355    #matching only entire words
356    regex = re.compile(r'\b'+ \
357                       r'\b|\b'.join(map(re.escape, dictionary.keys()))+ \
358                       r'\b' )
359
360    #For each match, lookup the corresponding value in the dictionary
361    return regex.sub(lambda match: dictionary[match.group(0)], text)
362
363
364
365
366def apply_expression_to_dictionary(expression, dictionary):#dictionary):
367    """Apply arbitrary expression to values of dictionary
368
369    Given an expression in terms of the keys, replace key by the
370    corresponding values and evaluate.
371   
372
373    expression: Arbitrary, e.g. arithmetric, expression relating keys
374                from dictionary.
375
376    dictionary: Mapping between symbols in expression and objects that
377                will be evaluated by expression.
378                Values in dictionary must support operators given in
379                expression e.g. by overloading
380
381    due to a limitation with Numeric, this can not evaluate 0/0
382    In general, the user can fix by adding 1e-30 to the numerator.
383    SciPy core can handle this situation.
384    """
385
386    import types
387    import re
388
389    assert isinstance(expression, basestring)
390    assert type(dictionary) == types.DictType
391
392    #Convert dictionary values to textual representations suitable for eval
393    D = {}
394    for key in dictionary:
395        D[key] = 'dictionary["%s"]' %key
396
397    #Perform substitution of variables   
398    expression = multiple_replace(expression, D)
399
400    #Evaluate and return
401    try:
402        return eval(expression)
403    except NameError, e:
404        msg = 'Expression "%s" could not be evaluated: %s' %(expression, e)
405        raise NameError, msg
406    except ValueError, e:
407        msg = 'Expression "%s" could not be evaluated: %s' %(expression, e)
408        raise ValueError, msg
409   
410
411
412
413####################################
414####OBSOLETE STUFF
415
416
417def angle(v1, v2):
418    """Temporary Interface to new location"""
419
420    import anuga.utilities.numerical_tools as NT       
421   
422    msg = 'angle has moved from util.py.  '
423    msg += 'Please use "from anuga.utilities.numerical_tools import angle"'
424    warn(msg, DeprecationWarning) 
425
426    return NT.angle(v1, v2)
427   
428def anglediff(v0, v1):
429    """Temporary Interface to new location"""
430
431    import anuga.utilities.numerical_tools as NT
432   
433    msg = 'anglediff has moved from util.py.  '
434    msg += 'Please use "from anuga.utilities.numerical_tools import anglediff"'
435    warn(msg, DeprecationWarning) 
436
437    return NT.anglediff(v0, v1)   
438
439   
440def mean(x):
441    """Temporary Interface to new location"""
442
443    import anuga.utilities.numerical_tools as NT   
444   
445    msg = 'mean has moved from util.py.  '
446    msg += 'Please use "from anuga.utilities.numerical_tools import mean"'
447    warn(msg, DeprecationWarning) 
448
449    return NT.mean(x)   
450
451def point_on_line(*args, **kwargs):
452    """Temporary Interface to new location"""
453
454    msg = 'point_on_line has moved from util.py.  '
455    msg += 'Please use "from anuga.utilities.polygon import point_on_line"'
456    warn(msg, DeprecationWarning) 
457
458    return utilities.polygon.point_on_line(*args, **kwargs)     
459   
460def inside_polygon(*args, **kwargs):
461    """Temporary Interface to new location"""
462
463    print 'inside_polygon has moved from util.py.  ',
464    print 'Please use "from anuga.utilities.polygon import inside_polygon"'
465
466    return utilities.polygon.inside_polygon(*args, **kwargs)   
467   
468def outside_polygon(*args, **kwargs):
469    """Temporary Interface to new location"""
470
471    print 'outside_polygon has moved from util.py.  ',
472    print 'Please use "from anuga.utilities.polygon import outside_polygon"'
473
474    return utilities.polygon.outside_polygon(*args, **kwargs)   
475
476
477def separate_points_by_polygon(*args, **kwargs):
478    """Temporary Interface to new location"""
479
480    print 'separate_points_by_polygon has moved from util.py.  ',
481    print 'Please use "from anuga.utilities.polygon import separate_points_by_polygon"'
482
483    return utilities.polygon.separate_points_by_polygon(*args, **kwargs)   
484
485
486
487def read_polygon(*args, **kwargs):
488    """Temporary Interface to new location"""
489
490    print 'read_polygon has moved from util.py.  ',
491    print 'Please use "from anuga.utilities.polygon import read_polygon"'
492
493    return utilities.polygon.read_polygon(*args, **kwargs)   
494
495
496def populate_polygon(*args, **kwargs):
497    """Temporary Interface to new location"""
498
499    print 'populate_polygon has moved from util.py.  ',
500    print 'Please use "from anuga.utilities.polygon import populate_polygon"'
501
502    return utilities.polygon.populate_polygon(*args, **kwargs)   
503
504##################### end of obsolete stuff ? ############
505
506def start_screen_catcher(dir_name, myid='', numprocs='', extra_info='',
507                         print_to_screen=False, verbose=False):
508    """
509    Used to store screen output and errors to file, if run on multiple
510    processes eachprocessor will have its own output and error file.
511   
512    extra_info - is used as a string that can identify outputs with another
513    string eg. '_other'
514    """
515
516    dir_name = dir_name
517    if access(dir_name,W_OK) == 0:
518        if verbose: print 'Make directory %s' %dir_name
519        if verbose: print "myid", myid
520        mkdir (dir_name,0777)
521    if myid <>'':
522        myid = '_'+str(myid)
523    if numprocs <>'':
524        numprocs = '_'+str(numprocs)
525    if extra_info <>'':
526        extra_info = '_'+str(extra_info)
527    screen_output_name = dir_name + "screen_output%s%s%s.txt" %(myid,numprocs,extra_info)
528    screen_error_name = dir_name + "screen_error%s%s%s.txt" %(myid,numprocs,extra_info)
529    print screen_output_name
530    #used to catch screen output to file
531    sys.stdout = Screen_Catcher(screen_output_name)
532    sys.stderr = Screen_Catcher(screen_error_name)
533
534class Screen_Catcher:
535    """this simply catches the screen output and stores it to file defined by
536    start_screen_catcher (above)
537    """
538   
539    def __init__(self, filename):
540        self.filename = filename
541 
542        if exists(self.filename)is True:
543            remove(self.filename)
544            print'Old existing file "%s" has been deleted' %(self.filename)
545
546    def write(self, stuff):
547        fid = open(self.filename, 'a')
548        fid.write(stuff)
549#        if print_to_screen: print stuff
550
551def get_revision_number():
552    """Get the version number of the SVN
553    NOTE: This requires that the command svn is on the system PATH
554    (simply aliasing svn to the binary will not work)
555    """
556
557    # Create dummy info
558    #info = 'Revision: Version info could not be obtained.'
559    #info += 'A command line version of svn must be availbable '
560    #info += 'on the system PATH, access to the subversion '
561    #info += 'repository is necessary and the output must '
562    #info += 'contain a line starting with "Revision:"'
563   
564
565    #FIXME (Ole): Change this so that svn info is attempted first.
566    # If that fails, try to read a stored file with that same info (this would be created by e.g. the release script). Failing that, throw an exception.
567
568    #FIXME (Ole): Move this and store_version_info to utilities
569
570
571    try:
572        from anuga.stored_version_info import version_info
573    except:
574       
575        # No file available - try using Subversion
576        try:
577            fid = os.popen('svn info')
578        except:
579            msg = 'No version info stored and command "svn" is not '
580            msg += 'recognised on the system PATH. What do you want me to do?'
581            raise Exception(msg)
582        else:
583            #print 'Got version from svn'           
584            version_info = fid.read()
585    else:
586        pass
587        #print 'Got version from file'
588
589           
590    for line in version_info.split('\n'):
591        if line.startswith('Revision:'):
592            break
593
594    fields = line.split(':')
595    msg = 'Keyword "Revision" was not found anywhere in text: %s' %version_info
596    assert fields[0].startswith('Revision'), msg           
597
598    try:
599        revision_number = int(fields[1])
600    except:
601        msg = 'Revision number must be an integer. I got %s' %fields[1]
602        msg += 'Check that the command svn is on the system path' 
603        raise Exception(msg)               
604       
605    return revision_number
606
607
608def store_version_info(destination_path='.', verbose=False):
609    """Obtain current version from Subversion and store it.
610   
611    Title: store_version_info()
612
613    Author: Ole Nielsen (Ole.Nielsen@ga.gov.au)
614
615    CreationDate: January 2006
616
617    Description:
618        This function obtains current version from Subversion and stores it
619        is a Python file named 'stored_version_info.py' for use with
620        get_version_info()
621
622        If svn is not available on the system PATH, an Exception is thrown
623    """
624
625    # Note (Ole): This function should not be unit tested as it will only
626    # work when running out of the sandpit. End users downloading the
627    # ANUGA distribution would see a failure.
628    #
629    # FIXME: This function should really only be used by developers (
630    # (e.g. for creating new ANUGA releases), so maybe it should move
631    # to somewhere else.
632   
633    import config
634
635    try:
636        fid = os.popen('svn info')
637    except:
638        msg = 'Command "svn" is not recognised on the system PATH'
639        raise Exception(msg)
640    else:   
641        txt = fid.read()
642        fid.close()
643
644
645        # Determine absolute filename
646        if destination_path[-1] != os.sep:
647            destination_path += os.sep
648           
649        filename = destination_path + config.version_filename
650
651        fid = open(filename, 'w')
652
653        docstring = 'Stored version info.\n\n'
654        docstring += 'This file provides the version for distributions '
655        docstring += 'that are not accessing Subversion directly.\n'
656        docstring += 'The file is automatically generated and should not '
657        docstring += 'be modified manually.\n'
658        fid.write('"""%s"""\n\n' %docstring)
659       
660        fid.write('version_info = """\n%s"""' %txt)
661        fid.close()
662
663
664        if verbose is True:
665            print 'Version info stored to %s' %filename
666           
667   
668def sww2timeseries(swwfiles,
669                   gauge_filename,
670                   production_dirs,
671                   report = None,
672                   reportname = None,
673                   plot_quantity = None,
674                   generate_fig = False,
675                   surface = None,
676                   time_min = None,
677                   time_max = None,
678                   title_on = None,
679                   use_cache = False,
680                   verbose = False):
681   
682    """ Read sww file and plot the time series for the
683    prescribed quantities at defined gauge locations and
684    prescribed time range.
685
686    Input variables:
687
688    swwfiles        - dictionary of sww files with label_ids (used in
689                      generating latex output. It will be part of
690                      the directory name of file_loc (typically the timestamp).
691                      Helps to differentiate latex files for different simulations
692                      for a particular scenario. 
693                    - assume that all conserved quantities have been stored
694                    - assume each sww file has been simulated with same timestep
695   
696    gauge_filename  - name of file containing gauge data
697                        - easting, northing, name , elevation?
698                    - OR (this is not yet done)
699                        - structure which can be converted to a Numeric array,
700                          such as a geospatial data object
701                     
702    production_dirs -  A list of list, example {20061101_121212: '1 in 10000',
703                                                'boundaries': 'urs boundary'}
704                      this will use the second part as the label and the first part
705                      as the ?
706                     
707    report          - if True, then write figures to report_figures directory in
708                      relevant production directory
709                    - if False, figures are already stored with sww file
710                    - default to False
711
712    reportname      - name for report if wishing to generate report
713   
714    plot_quantity   - list containing quantities to plot, they must
715                      be the name of an existing quantity or one of
716                      the following possibilities
717                    - possibilities:
718                        - stage; 'stage'
719                        - depth; 'depth'
720                        - speed; calculated as absolute momentum
721                         (pointwise) divided by depth; 'speed'
722                        - bearing; calculated as the angle of the momentum
723                          vector (xmomentum, ymomentum) from the North; 'bearing'
724                        - absolute momentum; calculated as
725                          sqrt(xmomentum^2 + ymomentum^2); 'momentum'
726                        - x momentum; 'xmomentum'
727                        - y momentum; 'ymomentum'
728                    - default will be ['stage', 'speed', 'bearing']
729
730    generate_fig     - if True, generate figures as well as csv files of quantities
731                     - if False, csv files created only
732                     
733    surface          - if True, then generate solution surface with 3d plot
734                       and save to current working directory
735                     - default = False
736   
737    time_min         - beginning of user defined time range for plotting purposes
738                        - default will be first available time found in swwfile
739                       
740    time_max         - end of user defined time range for plotting purposes
741                        - default will be last available time found in swwfile
742                       
743    title_on        - if True, export standard graphics with title
744                    - if False, export standard graphics without title
745
746
747                     
748    Output:
749   
750    - time series data stored in .csv for later use if required.
751      Name = gauges_timeseries followed by gauge name
752    - latex file will be generated in same directory as where script is
753      run (usually production scenario directory.
754      Name = latexoutputlabel_id.tex
755
756    Other important information:
757   
758    It is assumed that the used has stored all the conserved quantities
759    and elevation during the scenario run, i.e.
760    ['stage', 'elevation', 'xmomentum', 'ymomentum']
761    If this has not occurred then sww2timeseries will not work.
762    """
763
764   
765    k = _sww2timeseries(swwfiles,
766                        gauge_filename,
767                        production_dirs,
768                        report,
769                        reportname,
770                        plot_quantity,
771                        generate_fig,
772                        surface,
773                        time_min,
774                        time_max,
775                        title_on,
776                        use_cache,
777                        verbose)
778
779    return k
780
781def _sww2timeseries(swwfiles,
782                    gauge_filename,
783                    production_dirs,
784                    report = None,
785                    reportname = None,
786                    plot_quantity = None,
787                    generate_fig = False,
788                    surface = None,
789                    time_min = None,
790                    time_max = None,
791                    title_on = None,
792                    use_cache = False,
793                    verbose = False):   
794       
795    assert type(gauge_filename) == type(''),\
796           'Gauge filename must be a string'
797   
798    try:
799        fid = open(gauge_filename)
800    except Exception, e:
801        msg = 'File "%s" could not be opened: Error="%s"'\
802                  %(gauge_filename, e)
803        raise msg
804
805    if report is None:
806        report = False
807       
808    if plot_quantity is None:
809        plot_quantity = ['depth', 'speed']
810    else:
811        assert type(plot_quantity) == list,\
812               'plot_quantity must be a list'
813        check_list(plot_quantity)
814
815    if surface is None:
816        surface = False
817       
818    if title_on is None:
819        title_on = True
820   
821    if verbose: print '\n Gauges obtained from: %s \n' %gauge_filename
822    gauges, locations, elev = get_gauges_from_file(gauge_filename)
823
824    sww_quantity = ['stage', 'elevation', 'xmomentum', 'ymomentum']
825
826    file_loc = []
827    f_list = []
828    label_id = []
829    leg_label = []
830    themaxT = 0.0
831    theminT = 0.0
832   
833    for swwfile in swwfiles.keys():
834
835        try:
836            fid = open(swwfile)
837        except Exception, e:
838            msg = 'File "%s" could not be opened: Error="%s"'\
839                  %(swwfile, e)
840            raise msg
841
842        f = file_function(swwfile,
843                          quantities = sww_quantity,
844                          interpolation_points = gauges,
845                          verbose = True,
846                          use_cache = use_cache)
847
848        # determine which gauges are contained in sww file
849        count = 0
850        gauge_index = []
851        print 'swwfile', swwfile
852        for k, g in enumerate(gauges):
853            if f(0.0, point_id = k)[2] > 1.0e6:
854                count += 1
855                if count == 1: print 'Gauges not contained here:'
856                print locations[k]
857            else:
858                gauge_index.append(k)
859
860        if len(gauge_index) > 0:
861            print 'Gauges contained here: \n',
862        else:
863            print 'No gauges contained here. \n'
864        for i in range(len(gauge_index)):
865             print locations[gauge_index[i]]
866             
867        index = swwfile.rfind(sep)
868        file_loc.append(swwfile[:index+1])
869        label_id.append(swwfiles[swwfile])
870        leg_label.append(production_dirs[swwfiles[swwfile]])
871       
872        f_list.append(f)
873        maxT = max(f.get_time())
874        minT = min(f.get_time())
875        if maxT > themaxT: themaxT = maxT
876        if minT > theminT: theminT = minT
877
878    if time_min is None:
879        time_min = theminT # min(T)
880    else:
881        if time_min < theminT: # min(T):
882            msg = 'Minimum time entered not correct - please try again'
883            raise Exception, msg
884
885    if time_max is None:
886        time_max = themaxT # max(T)
887    else:
888        if time_max > themaxT: # max(T):
889            msg = 'Maximum time entered not correct - please try again'
890            raise Exception, msg
891
892    if verbose and len(gauge_index) > 0: print 'Inputs OK - going to generate figures'
893
894    if len(gauge_index) <> 0:
895        texfile, elev_output = generate_figures(plot_quantity, file_loc, report, reportname, surface,
896                                                leg_label, f_list, gauges, locations, elev, gauge_index,
897                                                production_dirs, time_min, time_max, title_on, label_id,
898                                                generate_fig, verbose)
899    else:
900        texfile = ''
901        elev_output = []
902
903    return texfile, elev_output
904                         
905
906
907#Fixme - Use geospatial to read this file - it's an xya file
908#Need to include other information into this filename, so xya + Name - required for report
909def get_gauges_from_file(filename):
910    """ Read in gauge information from file
911    """
912    from os import sep, getcwd, access, F_OK, mkdir
913    fid = open(filename)
914    lines = fid.readlines()
915    fid.close()
916   
917    gauges = []
918    gaugelocation = []
919    elev = []
920    line1 = lines[0]
921    line11 = line1.split(',')
922    east_index = len(line11)+1
923    north_index = len(line11)+1
924    name_index = len(line11)+1
925    elev_index = len(line11)+1
926    for i in range(len(line11)):
927        if line11[i].strip('\n').strip(' ').lower() == 'easting': east_index = i
928        if line11[i].strip('\n').strip(' ').lower() == 'northing': north_index = i
929        if line11[i].strip('\n').strip(' ').lower() == 'name': name_index = i
930        if line11[i].strip('\n').strip(' ').lower() == 'elevation': elev_index = i
931
932    for line in lines[1:]:
933        fields = line.split(',')
934        if east_index < len(line11) and north_index < len(line11):
935            gauges.append([float(fields[east_index]), float(fields[north_index])])
936        else:
937            msg = 'WARNING: %s does not contain location information' %(filename)
938            raise Exception, msg
939        if elev_index < len(line11): elev.append(float(fields[elev_index]))
940        if name_index < len(line11):
941            loc = fields[name_index]
942            gaugelocation.append(loc.strip('\n'))
943
944    return gauges, gaugelocation, elev
945
946def check_list(quantity):
947    """ Check that input quantities in quantity list are possible
948    """
949    all_quantity = ['stage', 'depth', 'momentum', 'xmomentum',
950                    'ymomentum', 'speed', 'bearing', 'elevation']
951
952       
953                   
954    import sys
955    #if not sys.version.startswith('2.4'):
956        # Backwards compatibility
957    #   from sets import Set as set
958
959    from sets import Set as set
960           
961    for i,j in enumerate(quantity):
962        quantity[i] = quantity[i].lower()
963    p = list(set(quantity).difference(set(all_quantity)))
964    if len(p) <> 0:
965        msg = 'Quantities %s do not exist - please try again' %p
966        raise Exception, msg
967       
968    return 
969
970def calc_bearing(uh, vh):
971    """ Calculate velocity bearing from North
972    """
973    from math import atan, degrees
974   
975    angle = degrees(atan(vh/(uh+1.e-15)))
976    if (0 < angle < 90.0):
977        if vh > 0:
978            bearing = 90.0 - abs(angle)
979        if vh < 0:
980            bearing = 270.0 - abs(angle)
981    if (-90 < angle < 0):
982        if vh < 0:
983            bearing = 90.0 - abs(angle)
984        if vh > 0:
985            bearing = 270.0 - abs(angle)
986    if angle == 0: bearing = 0.0
987           
988    return bearing
989
990def generate_figures(plot_quantity, file_loc, report, reportname, surface,
991                     leg_label, f_list, gauges, locations, elev, gauge_index,
992                     production_dirs, time_min, time_max, title_on, label_id,
993                     generate_fig, verbose):
994    """ Generate figures based on required quantities and gauges for each sww file
995    """
996    from math import sqrt, atan, degrees
997    from Numeric import ones, allclose, zeros, Float, ravel
998    from os import sep, altsep, getcwd, mkdir, access, F_OK, environ
999
1000    if generate_fig is True:
1001        from pylab import ion, hold, plot, axis, figure, legend, savefig, \
1002             xlabel, ylabel, title, close, subplot
1003   
1004        if surface is True:
1005            import pylab as p1
1006            import mpl3d.mplot3d as p3
1007       
1008    if report == True:   
1009        texdir = getcwd()+sep+'report'+sep
1010        if access(texdir,F_OK) == 0:
1011            mkdir (texdir)
1012        if len(label_id) == 1:
1013            label_id1 = label_id[0].replace(sep,'')
1014            label_id2 = label_id1.replace('_','')
1015            texfile = texdir+reportname+'%s' %(label_id2)
1016            texfile2 = reportname+'%s' %(label_id2)
1017            texfilename = texfile + '.tex'
1018            if verbose: print '\n Latex output printed to %s \n' %texfilename
1019            fid = open(texfilename, 'w')
1020        else:
1021            texfile = texdir+reportname
1022            texfile2 = reportname
1023            texfilename = texfile + '.tex' 
1024            if verbose: print '\n Latex output printed to %s \n' %texfilename
1025            fid = open(texfilename, 'w')
1026    else:
1027        texfile = ''
1028        texfile2 = ''
1029
1030    p = len(f_list)
1031    n = []
1032    n0 = 0
1033    for i in range(len(f_list)):
1034        n.append(len(f_list[i].get_time()))
1035        if n[i] > n0: n0 = n[i] 
1036    n0 = int(n0)
1037    m = len(locations)
1038    model_time = zeros((n0,m,p), Float) 
1039    stages = zeros((n0,m,p), Float)
1040    elevations = zeros((n0,m,p), Float) 
1041    momenta = zeros((n0,m,p), Float)
1042    xmom = zeros((n0,m,p), Float)
1043    ymom = zeros((n0,m,p), Float)
1044    speed = zeros((n0,m,p), Float)
1045    bearings = zeros((n0,m,p), Float)
1046    depths = zeros((n0,m,p), Float)
1047    eastings = zeros((n0,m,p), Float)
1048    min_stages = []
1049    max_stages = []
1050    max_momentums = []
1051    max_speeds = []
1052    max_depths = []
1053    model_time_plot3d = zeros((n0,m), Float)
1054    stages_plot3d = zeros((n0,m), Float)
1055    eastings_plot3d = zeros((n0,m),Float)
1056    ##### loop over each swwfile #####
1057    for j, f in enumerate(f_list):
1058        if verbose: print 'swwfile %d of %d' %(j, len(f_list))
1059        comparefile = file_loc[j]+sep+'gauges_maxmins'+'.csv'
1060        fid_compare = open(comparefile, 'w')
1061        ##### loop over each gauge #####
1062        for k in gauge_index:
1063            g = gauges[k]
1064            if verbose: print 'Gauge %d of %d' %(k, len(gauges))
1065            min_stage = 10
1066            max_stage = 0
1067            max_momentum = 0
1068            max_speed = 0
1069            max_depth = 0
1070            gaugeloc = locations[k]
1071            thisfile = file_loc[j]+sep+'gauges_time_series'+'_'+gaugeloc+'.csv'
1072            fid_out = open(thisfile, 'w')
1073            s = 'Time, Stage, Momentum, Speed, Elevation, xmom, ymom \n'
1074            fid_out.write(s)
1075           
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/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\n' %(t, w, m, vel, z, uh, vh)
1102                    fid_out.write(s)
1103                    if t/60.0 <= 13920: tindex = i
1104                    if w > max_stage: max_stage = w
1105                    if w < min_stage: min_stage = w
1106                    if m > max_momentum: max_momentum = m
1107                    if vel > max_speed: max_speed = vel
1108                    if z > 0 and depth > max_depth: max_depth = depth
1109                   
1110                   
1111            s = '%.2f, %.2f, %.2f, %.2f, %s\n' %(max_stage, min_stage, z, thisgauge[0], leg_label[j])
1112            fid_compare.write(s)
1113            max_stages.append(max_stage)
1114            min_stages.append(min_stage)
1115            max_momentums.append(max_momentum)
1116            max_speeds.append(max_speed)
1117            max_depths.append(max_depth)
1118            #### finished generating quantities for each swwfile #####
1119       
1120        model_time_plot3d[:,:] = model_time[:,:,j]
1121        stages_plot3d[:,:] = stages[:,:,j]
1122        eastings_plot3d[:,] = eastings[:,:,j]
1123           
1124        if surface is  True:
1125            print 'Printing surface figure'
1126            for i in range(2):
1127                fig = p1.figure(10)
1128                ax = p3.Axes3D(fig)
1129                if len(gauges) > 80:
1130                    ax.plot_surface(model_time[:,:,j],eastings[:,:,j],stages[:,:,j])
1131                else:
1132                    #ax.plot_wireframe(model_time[:,:,j],eastings[:,:,j],stages[:,:,j])
1133                    ax.plot3D(ravel(eastings[:,:,j]),ravel(model_time[:,:,j]),ravel(stages[:,:,j]))
1134                ax.set_xlabel('time')
1135                ax.set_ylabel('x')
1136                ax.set_zlabel('stage')
1137                fig.add_axes(ax)
1138                p1.show()
1139                surfacefig = 'solution_surface%s' %leg_label[j]
1140                p1.savefig(surfacefig)
1141                p1.close()
1142           
1143    #### finished generating quantities for all swwfiles #####
1144
1145    # x profile for given time
1146    if surface is True:
1147        figure(11)
1148        plot(eastings[tindex,:,j],stages[tindex,:,j])
1149        xlabel('x')
1150        ylabel('stage')
1151        profilefig = 'solution_xprofile' 
1152        savefig('profilefig')
1153
1154    elev_output = []
1155    if generate_fig is True:
1156        depth_axis = axis([time_min/60.0, time_max/60.0, -0.1, max(max_depths)*1.1])
1157        stage_axis = axis([time_min/60.0, time_max/60.0, min(min_stages), max(max_stages)*1.1])
1158        vel_axis = axis([time_min/60.0, time_max/60.0, min(max_speeds), max(max_speeds)*1.1])
1159        mom_axis = axis([time_min/60.0, time_max/60.0, min(max_momentums), max(max_momentums)*1.1])
1160        cstr = ['g', 'r', 'b', 'c', 'm', 'y', 'k']
1161        nn = len(plot_quantity)
1162        no_cols = 2
1163       
1164        if len(label_id) > 1: graphname_report = []
1165        pp = 1
1166        div = 11.
1167        cc = 0
1168        for k in gauge_index:
1169            g = gauges[k]
1170            count1 = 0
1171            if report == True and len(label_id) > 1:
1172                s = '\\begin{figure}[ht] \n \\centering \n \\begin{tabular}{cc} \n'
1173                fid.write(s)
1174            if len(label_id) > 1: graphname_report = []
1175            #### generate figures for each gauge ####
1176            for j, f in enumerate(f_list):
1177                ion()
1178                hold(True)
1179                count = 0
1180                where1 = 0
1181                where2 = 0
1182                word_quantity = ''
1183                if report == True and len(label_id) == 1:
1184                    s = '\\begin{figure}[hbt] \n \\centering \n \\begin{tabular}{cc} \n'
1185                    fid.write(s)
1186                   
1187                for which_quantity in plot_quantity:
1188                    count += 1
1189                    where1 += 1
1190                    figure(count, frameon = False)
1191                    if which_quantity == 'depth':
1192                        plot(model_time[0:n[j]-1,k,j], depths[0:n[j]-1,k,j], '-', c = cstr[j])
1193                        units = 'm'
1194                        axis(depth_axis)
1195                    if which_quantity == 'stage':
1196                        if elevations[0,k,j] < 0:
1197                            plot(model_time[0:n[j]-1,k,j], stages[0:n[j]-1,k,j], '-', c = cstr[j])
1198                            axis(stage_axis)
1199                        else:
1200                            plot(model_time[0:n[j]-1,k,j], depths[0:n[j]-1,k,j], '-', c = cstr[j])
1201                            #axis(depth_axis)                 
1202                        units = 'm'
1203                    if which_quantity == 'momentum':
1204                        plot(model_time[0:n[j]-1,k,j], momenta[0:n[j]-1,k,j], '-', c = cstr[j])
1205                        axis(mom_axis)
1206                        units = 'm^2 / sec'
1207                    if which_quantity == 'xmomentum':
1208                        plot(model_time[0:n[j]-1,k,j], xmom[0:n[j]-1,k,j], '-', c = cstr[j])
1209                        axis(mom_axis)
1210                        units = 'm^2 / sec'
1211                    if which_quantity == 'ymomentum':
1212                        plot(model_time[0:n[j]-1,k,j], ymom[0:n[j]-1,k,j], '-', c = cstr[j])
1213                        axis(mom_axis)
1214                        units = 'm^2 / sec'
1215                    if which_quantity == 'speed':
1216                        plot(model_time[0:n[j]-1,k,j], speed[0:n[j]-1,k,j], '-', c = cstr[j])
1217                        axis(vel_axis)
1218                        units = 'm / sec'
1219                    if which_quantity == 'bearing':
1220                        due_east = 90.0*ones(shape(model_time[0:n[j]-1,k,j],Float))
1221                        due_west = 270.0*ones(shape(model_time[0:n[j]-1,k,j],Float))
1222                        plot(model_time[0:n[j]-1,k,j], bearings, '-', 
1223                             model_time[0:n[j]-1,k,j], due_west, '-.', 
1224                             model_time[0:n[j]-1,k,j], due_east, '-.')
1225                        units = 'degrees from North'
1226                        ax = axis([time_min, time_max, 0.0, 360.0])
1227                        legend(('Bearing','West','East'))
1228
1229                    xlabel('time (mins)')
1230                    if which_quantity == 'stage' and elevations[0:n[j]-1,k,j] > 0:
1231                        ylabel('%s (%s)' %('depth', units))
1232                    else:
1233                        ylabel('%s (%s)' %(which_quantity, units))
1234                    if len(label_id) > 1: legend((leg_label),loc='upper right')
1235
1236                    gaugeloc1 = gaugeloc.replace(' ','')
1237                    #gaugeloc2 = gaugeloc1.replace('_','')
1238                    gaugeloc2 = locations[k].replace(' ','')
1239                    graphname = '%sgauge%s_%s' %(file_loc[j], gaugeloc2, which_quantity)
1240
1241                    if report == True and len(label_id) > 1:
1242                        figdir = getcwd()+sep+'report_figures'+sep
1243                        if access(figdir,F_OK) == 0 :
1244                            mkdir (figdir)
1245                        latex_file_loc = figdir.replace(sep,altsep) 
1246                        graphname_latex = '%sgauge%s%s' %(latex_file_loc, gaugeloc2, which_quantity) # storing files in production directory   
1247                        graphname_report_input = '%sgauge%s%s' %('..'+altsep+'report_figures'+altsep, gaugeloc2, which_quantity) # giving location in latex output file
1248                        graphname_report.append(graphname_report_input)
1249                       
1250                        savefig(graphname_latex) # save figures in production directory for report generation
1251
1252                    if report == True:
1253
1254                        figdir = getcwd()+sep+'report_figures'+sep
1255                        if access(figdir,F_OK) == 0 :
1256                            mkdir (figdir)
1257                        latex_file_loc = figdir.replace(sep,altsep)   
1258
1259                        if len(label_id) == 1: 
1260                            graphname_latex = '%sgauge%s%s%s' %(latex_file_loc, gaugeloc2, which_quantity, label_id2) # storing files in production directory 
1261                            graphname_report = '%sgauge%s%s%s' %('..'+altsep+'report_figures'+altsep, gaugeloc2, which_quantity, label_id2) # giving location in latex output file
1262                            s = '\includegraphics[width=0.49\linewidth, height=50mm]{%s%s}' %(graphname_report, '.png')
1263                            fid.write(s)
1264                            if where1 % 2 == 0:
1265                                s = '\\\\ \n'
1266                                where1 = 0
1267                            else:
1268                                s = '& \n'
1269                            fid.write(s)
1270                            savefig(graphname_latex)
1271                   
1272                    if title_on == True:
1273                        title('%s scenario: %s at %s gauge' %(label_id, which_quantity, gaugeloc2))
1274
1275                    savefig(graphname) # save figures with sww file
1276
1277                if report == True and len(label_id) == 1:
1278                    for i in range(nn-1):
1279                        if nn > 2:
1280                            if plot_quantity[i] == 'stage' and elevations[0,k,j] > 0:
1281                                word_quantity += 'depth' + ', '
1282                            else:
1283                                word_quantity += plot_quantity[i] + ', '
1284                        else:
1285                            if plot_quantity[i] == 'stage' and elevations[0,k,j] > 0:
1286                                word_quantity += 'depth' + ', '
1287                            else:
1288                                word_quantity += plot_quantity[i]
1289                       
1290                    if plot_quantity[nn-1] == 'stage' and elevations[0,k,j] > 0:
1291                        word_quantity += ' and ' + 'depth'
1292                    else:
1293                        word_quantity += ' and ' + plot_quantity[nn-1]
1294                    caption = 'Time series for %s at %s location (elevation %.2fm)' %(word_quantity, locations[k], elev[k]) #gaugeloc.replace('_',' '))
1295                    if elev[k] == 0.0:
1296                        caption = 'Time series for %s at %s location (elevation %.2fm)' %(word_quantity, locations[k], elevations[0,k,j])
1297                        east = gauges[0]
1298                        north = gauges[1]
1299                        elev_output.append([locations[k],east,north,elevations[0,k,j]])
1300                    label = '%sgauge%s' %(label_id2, gaugeloc2)
1301                    s = '\end{tabular} \n \\caption{%s} \n \label{fig:%s} \n \end{figure} \n \n' %(caption, label)
1302                    fid.write(s)
1303                    cc += 1
1304                    if cc % 6 == 0: fid.write('\\clearpage \n')
1305                    savefig(graphname_latex)               
1306                   
1307            if report == True and len(label_id) > 1:
1308                for i in range(nn-1):
1309                    if nn > 2:
1310                        if plot_quantity[i] == 'stage' and elevations[0,k,j] > 0:
1311                            word_quantity += 'depth' + ','
1312                        else:
1313                            word_quantity += plot_quantity[i] + ', '
1314                    else:
1315                        if plot_quantity[i] == 'stage' and elevations[0,k,j] > 0:
1316                            word_quantity += 'depth'
1317                        else:
1318                            word_quantity += plot_quantity[i]
1319                    where1 = 0
1320                    count1 += 1
1321                    index = j*len(plot_quantity)
1322                    for which_quantity in plot_quantity:
1323                        where1 += 1
1324                        s = '\includegraphics[width=0.49\linewidth, height=50mm]{%s%s}' %(graphname_report[index], '.png')
1325                        index += 1
1326                        fid.write(s)
1327                        if where1 % 2 == 0:
1328                            s = '\\\\ \n'
1329                            where1 = 0
1330                        else:
1331                            s = '& \n'
1332                        fid.write(s)
1333                word_quantity += ' and ' + plot_quantity[nn-1]           
1334                label = 'gauge%s' %(gaugeloc2) 
1335                caption = 'Time series for %s at %s location (elevation %.2fm)' %(word_quantity, locations[k], elev[k])
1336                if elev[k] == 0.0:
1337                        caption = 'Time series for %s at %s location (elevation %.2fm)' %(word_quantity, locations[k], elevations[0,k,j])
1338                        thisgauge = gauges[k]
1339                        east = thisgauge[0]
1340                        north = thisgauge[1]
1341                        elev_output.append([locations[k],east,north,elevations[0,k,j]])
1342                       
1343                s = '\end{tabular} \n \\caption{%s} \n \label{fig:%s} \n \end{figure} \n \n' %(caption, label)
1344                fid.write(s)
1345                if float((k+1)/div - pp) == 0.:
1346                    fid.write('\\clearpage \n')
1347                    pp += 1
1348               
1349                #### finished generating figures ###
1350
1351            close('all')
1352       
1353    return texfile2, elev_output
1354
1355# FIXME (DSG): Add unit test, make general, not just 2 files,
1356# but any number of files.
1357def copy_code_files(dir_name, filename1, filename2):
1358    """Copies "filename1" and "filename2" to "dir_name". Very useful for
1359    information management """
1360
1361    if access(dir_name,F_OK) == 0:
1362        print 'Make directory %s' %dir_name
1363        mkdir (dir_name,0777)
1364    copy(filename1, dir_name + sep + basename(filename1))
1365    copy(filename2, dir_name + sep + basename(filename2))
1366#    copy (__file__, project.output_run_time_dir + basename(__file__))
1367    print 'Files %s and %s copied' %(filename1, filename2)
1368
1369
1370def add_directories(root_directory, directories):
1371    """
1372    Add the first directory in directories to root_directory.
1373    Then add the second
1374    direcotory to the first directory and so on.
1375
1376    Return the path of the final directory.
1377
1378    This is handy for specifying and creating a directory where data will go.
1379    """
1380    dir = root_directory
1381    for new_dir in directories:
1382        dir = os.path.join(dir, new_dir)
1383        if not access(dir,F_OK):
1384            mkdir (dir)
1385    return dir
1386
1387def get_data_from_file(filename,separator_value = ','):
1388    """
1389    Read in data information from file
1390    NOTE: wont deal with columns with different lenghts and there must be
1391    no blank lines at the end.
1392    """
1393    from os import sep, getcwd, access, F_OK, mkdir
1394    from Numeric import array, resize,shape,Float
1395    import string
1396    fid = open(filename)
1397    lines = fid.readlines()
1398   
1399    fid.close()
1400   
1401    header_line = lines[0]
1402    header_fields = header_line.split(separator_value)
1403
1404    #array to store data, number in there is to allow float...
1405    #i'm sure there is a better way!
1406    data=array([],typecode=Float)
1407    data=resize(data,((len(lines)-1),len(header_fields)))
1408#    print 'number of fields',range(len(header_fields))
1409#    print 'number of lines',len(lines), shape(data)
1410#    print'data',data[1,1],header_line
1411
1412    array_number = 0
1413    line_number = 1
1414    while line_number < (len(lines)):
1415        for i in range(len(header_fields)): 
1416            #this get line below the header, explaining the +1
1417            #and also the line_number can be used as the array index
1418            fields = lines[line_number].split(separator_value)
1419            #assign to array
1420            data[array_number,i] = float(fields[i])
1421           
1422        line_number = line_number +1
1423        array_number = array_number +1
1424       
1425    return header_fields, data
1426
1427
1428
Note: See TracBrowser for help on using the repository browser.