source: inundation/fit_interpolate/interpolate.py @ 3422

Last change on this file since 3422 was 3419, checked in by duncan, 19 years ago

add time column

File size: 29.1 KB
Line 
1"""Least squares interpolation.
2
3   Implements a least-squares interpolation.
4   Putting mesh data onto points.
5
6   Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
7   Geoscience Australia, 2004.
8
9DESIGN ISSUES
10* what variables should be global?
11- if there are no global vars functions can be moved around alot easier
12
13* The public interface to Interpolate
14__init__
15interpolate
16interpolate_block
17
18"""
19
20import time
21import os
22from warnings import warn
23from math import sqrt
24from csv import writer, DictWriter
25
26from Numeric import zeros, array, Float, Int, dot, transpose, concatenate, \
27     ArrayType, allclose, take, NewAxis, arange
28
29from caching.caching import cache
30from pyvolution.neighbour_mesh import Mesh
31from utilities.sparse import Sparse, Sparse_CSR
32from utilities.cg_solve import conjugate_gradient, VectorShapeError
33from coordinate_transforms.geo_reference import Geo_reference
34from pyvolution.quad import build_quadtree
35from utilities.numerical_tools import ensure_numeric, mean, INF
36from utilities.polygon import in_and_outside_polygon
37from geospatial_data.geospatial_data import Geospatial_data, ensure_absolute
38from fit_interpolate.search_functions import search_tree_of_vertices
39from fit_interpolate.general_fit_interpolate import FitInterpolate
40from pyvolution.util import file_function
41
42
43class Interpolate (FitInterpolate):
44       
45    def __init__(self,
46                 vertex_coordinates,
47                 triangles,
48                 mesh_origin=None,
49                 verbose=False,
50                 max_vertices_per_cell=30):
51
52
53        """ Build interpolation matrix mapping from
54        function values at vertices to function values at data points
55
56        Inputs:
57
58          vertex_coordinates: List of coordinate pairs [xi, eta] of
59              points constituting a mesh (or an m x 2 Numeric array or
60              a geospatial object)
61              Points may appear multiple times
62              (e.g. if vertices have discontinuities)
63
64          triangles: List of 3-tuples (or a Numeric array) of
65              integers representing indices of all vertices in the mesh.
66
67          mesh_origin: A geo_reference object or 3-tuples consisting of
68              UTM zone, easting and northing.
69              If specified vertex coordinates are assumed to be
70              relative to their respective origins.
71
72          max_vertices_per_cell: Number of vertices in a quad tree cell
73          at which the cell is split into 4.
74
75          Note: Don't supply a vertex coords as a geospatial object and
76              a mesh origin, since geospatial has its own mesh origin.
77        """
78       
79        # Initialise variabels
80        self._A_can_be_reused = False
81        self._point_coordinates = None
82       
83        FitInterpolate.__init__(self,
84                 vertex_coordinates,
85                 triangles,
86                 mesh_origin,
87                 verbose,
88                 max_vertices_per_cell)
89
90     # FIXME: What is a good start_blocking_len value?
91    def interpolate(self, f, point_coordinates = None,
92                    start_blocking_len = 500000, verbose=False):
93        """Interpolate mesh data f to determine values, z, at points.
94
95        f is the data on the mesh vertices.
96
97        The mesh values representing a smooth surface are
98        assumed to be specified in f.
99
100        Inputs:
101          f: Vector or array of data at the mesh vertices.
102              If f is an array, interpolation will be done for each column as
103              per underlying matrix-matrix multiplication
104          point_coordinates: Interpolate mesh data to these positions.
105              List of coordinate pairs [x, y] of
106              data points or an nx2 Numeric array or a Geospatial_data object
107             
108              If point_coordinates is absent, the points inputted last time
109              this method was called are used, if possible.
110          start_blocking_len: If the # of points is more or greater than this,
111              start blocking
112
113        Output:
114          Interpolated values at inputted points (z).
115        """
116        #print "point_coordinates interpolate.interpolate",point_coordinates
117        if isinstance(point_coordinates,Geospatial_data):
118            point_coordinates = point_coordinates.get_data_points( \
119                absolute = True)
120       
121        # Can I interpolate, based on previous point_coordinates?
122        if point_coordinates is None:
123            if self._A_can_be_reused is True and \
124            len(self._point_coordinates) < start_blocking_len: 
125                z = self._get_point_data_z(f,
126                                           verbose=verbose)
127            elif self._point_coordinates is not None:
128                #     if verbose, give warning
129                if verbose:
130                    print 'WARNING: Recalculating A matrix, due to blocking.'
131                point_coordinates = self._point_coordinates
132            else:
133                #There are no good point_coordinates. import sys; sys.exit()
134                msg = 'ERROR (interpolate.py): No point_coordinates inputted'
135                raise Exception(msg)
136           
137           
138        if point_coordinates is not None:
139            self._point_coordinates = point_coordinates
140            if len(point_coordinates) < start_blocking_len or \
141                   start_blocking_len == 0:
142                self._A_can_be_reused = True
143                z = self.interpolate_block(f, point_coordinates,
144                                           verbose=verbose)
145            else:
146                #Handle blocking
147                self._A_can_be_reused = False
148                start=0
149                # creating a dummy array to concatenate to.
150               
151                f = ensure_numeric(f, Float)
152                #print "f.shape",f.shape
153                if len(f.shape) > 1:
154                    z = zeros((0,f.shape[1]))
155                else:
156                    z = zeros((0,))
157                   
158                for end in range(start_blocking_len
159                                 ,len(point_coordinates)
160                                 ,start_blocking_len):
161                    t = self.interpolate_block(f, point_coordinates[start:end],
162                                               verbose=verbose)
163                    #print "t", t
164                    #print "z", z
165                    z = concatenate((z,t))
166                    start = end
167                end = len(point_coordinates)
168                t = self.interpolate_block(f, point_coordinates[start:end],
169                                           verbose=verbose)
170                z = concatenate((z,t))
171        return z
172
173    def interpolate_block(self, f, point_coordinates = None, verbose=False):
174        """
175        Call this if you want to control the blocking or make sure blocking
176        doesn't occur.
177
178        Return the point data, z.
179       
180        See interpolate for doc info.
181        """
182        if isinstance(point_coordinates,Geospatial_data):
183            point_coordinates = point_coordinates.get_data_points( \
184                absolute = True)
185        if point_coordinates is not None:
186            self._A =self._build_interpolation_matrix_A(point_coordinates,
187                                                       verbose=verbose)
188        return self._get_point_data_z(f)
189
190    def _get_point_data_z(self, f, verbose=False):
191        """
192        Return the point data, z.
193       
194        Precondition,
195        The _A matrix has been created
196        """
197        z = self._A * f
198        # Taking into account points outside the mesh.
199        #print "self.outside_poly_indices", self.outside_poly_indices
200        #print "self.inside_poly_indices", self.inside_poly_indices
201        #print "z", z
202        for i in self.outside_poly_indices: 
203            z[i] = INF
204        return z
205
206
207    def _build_interpolation_matrix_A(self,
208                                     point_coordinates,
209                                     verbose = False):
210        """Build n x m interpolation matrix, where
211        n is the number of data points and
212        m is the number of basis functions phi_k (one per vertex)
213
214        This algorithm uses a quad tree data structure for fast binning
215        of data points
216        origin is a 3-tuple consisting of UTM zone, easting and northing.
217        If specified coordinates are assumed to be relative to this origin.
218
219        This one will override any data_origin that may be specified in
220        instance interpolation
221
222        Preconditions
223        Point_coordindates and mesh vertices have the same origin.
224        """
225
226
227       
228        #Convert point_coordinates to Numeric arrays, in case it was a list.
229        point_coordinates = ensure_numeric(point_coordinates, Float)
230       
231        if verbose: print 'Getting indices inside mesh boundary'
232        #print "self.mesh.get_boundary_polygon()",self.mesh.get_boundary_polygon()
233        self.inside_poly_indices, self.outside_poly_indices  = \
234                     in_and_outside_polygon(point_coordinates,
235                                            self.mesh.get_boundary_polygon(),
236                                            closed = True, verbose = verbose)
237        #print "self.inside_poly_indices",self.inside_poly_indices
238        #print "self.outside_poly_indices",self.outside_poly_indices
239        #Build n x m interpolation matrix
240        if verbose and len(self.outside_poly_indices) >0:
241            print '\n WARNING: Points outside mesh boundary. \n'
242        # Since you can block, throw a warning, not an error.
243        if verbose and 0 == len(self.inside_poly_indices):
244            print '\n WARNING: No points within the mesh! \n'
245           
246        m = self.mesh.coordinates.shape[0] #Nbr of basis functions (1/vertex)
247        n = point_coordinates.shape[0]     #Nbr of data points
248
249        if verbose: print 'Number of datapoints: %d' %n
250        if verbose: print 'Number of basis functions: %d' %m
251
252        A = Sparse(n,m)
253
254        n = len(self.inside_poly_indices)
255        #Compute matrix elements for points inside the mesh
256        for i in self.inside_poly_indices:
257            #For each data_coordinate point
258            if verbose and i%((n+10)/10)==0: print 'Doing %d of %d' %(i, n)
259            x = point_coordinates[i]
260            element_found, sigma0, sigma1, sigma2, k = \
261                           search_tree_of_vertices(self.root, self.mesh, x)
262            #Update interpolation matrix A if necessary
263            if element_found is True:
264                #Assign values to matrix A
265
266                j0 = self.mesh.triangles[k,0] #Global vertex id for sigma0
267                j1 = self.mesh.triangles[k,1] #Global vertex id for sigma1
268                j2 = self.mesh.triangles[k,2] #Global vertex id for sigma2
269
270                sigmas = {j0:sigma0, j1:sigma1, j2:sigma2}
271                js     = [j0,j1,j2]
272
273                for j in js:
274                    A[i,j] = sigmas[j]
275            else:
276                msg = 'Could not find triangle for point', x
277                raise Exception(msg)
278        return A
279
280def interpolate_sww2csv(sww_file,
281                        points,
282                        depth_file,
283                        velocity_file,
284                        #quantities = ['depth', 'velocity'],
285                        verbose=True,
286                        use_cache = True):
287    """
288    Interpolate the quantities at a given set of locations, given
289    an sww file.
290    The results are written to a csv file.
291
292    In the future let points be a csv or xya file.
293    And the user choose the quantities.
294
295    This is currently quite specific.
296    If it need to be more general, chagne things.
297    """
298    quantities =  ['stage', 'elevation', 'xmomentum', 'ymomentum']
299    #print "points",points
300    points = ensure_absolute(points)
301    point_count = len(points)
302    callable_sww = file_function(sww_file,
303                                 quantities=quantities,
304                                 interpolation_points=points,
305                                 verbose=verbose,
306                                 use_cache=use_cache)
307   
308    depth_writer = writer(file(depth_file, "wb"))
309    velocity_writer = writer(file(velocity_file, "wb"))
310    # Write heading
311    heading = [str(x[0])+ ':' + str(x[1]) for x in points]
312    heading.insert(0, "time")
313    depth_writer.writerow(heading)
314    velocity_writer.writerow(heading)
315    #for row in someiterable:
316        #csvwriter.writerow(row)
317    for time in callable_sww.get_time():
318        depths = [time]
319        velocitys = [time]
320        for point_i, point in enumerate(points):
321            quantities = callable_sww(time,point_i)
322            #print "quantities", quantities
323           
324            w = quantities[0]
325            z = quantities[1]
326            uh = quantities[2]
327            vh = quantities[3]
328            depth = w - z
329             
330            if w == INF or z == INF or uh == INF or vh == INF:
331                velocity = INF
332            else:
333                momentum = sqrt(uh*uh + vh*vh)
334                if depth > 1.e-30: # use epsilon
335                    velocity = momentum / depth  #Absolute velocity
336                else:
337                    velocity = 0
338            depths.append(depth)
339            velocitys.append(velocity)
340        depth_writer.writerow(depths)
341        velocity_writer.writerow(velocitys)
342
343class Interpolation_function:
344    """Interpolation_interface - creates callable object f(t, id) or f(t,x,y)
345    which is interpolated from time series defined at vertices of
346    triangular mesh (such as those stored in sww files)
347
348    Let m be the number of vertices, n the number of triangles
349    and p the number of timesteps.
350
351    Mandatory input
352        time:               px1 array of monotonously increasing times (Float)
353        quantities:         Dictionary of arrays or 1 array (Float)
354                            The arrays must either have dimensions pxm or mx1.
355                            The resulting function will be time dependent in
356                            the former case while it will be constan with
357                            respect to time in the latter case.
358       
359    Optional input:
360        quantity_names:     List of keys into the quantities dictionary
361        vertex_coordinates: mx2 array of coordinates (Float)
362        triangles:          nx3 array of indices into vertex_coordinates (Int)
363        interpolation_points: Nx2 array of coordinates to be interpolated to
364        verbose:            Level of reporting
365   
366   
367    The quantities returned by the callable object are specified by
368    the list quantities which must contain the names of the
369    quantities to be returned and also reflect the order, e.g. for
370    the shallow water wave equation, on would have
371    quantities = ['stage', 'xmomentum', 'ymomentum']
372
373    The parameter interpolation_points decides at which points interpolated
374    quantities are to be computed whenever object is called.
375    If None, return average value
376    """
377
378   
379   
380    def __init__(self,
381                 time,
382                 quantities,
383                 quantity_names = None, 
384                 vertex_coordinates = None,
385                 triangles = None,
386                 interpolation_points = None,
387                 verbose = False):
388        """Initialise object and build spatial interpolation if required
389        """
390
391        from Numeric import array, zeros, Float, alltrue, concatenate,\
392             reshape, ArrayType
393
394
395        #from util import mean, ensure_numeric
396        from config import time_format
397        import types
398
399
400        #Check temporal info
401        time = ensure_numeric(time)       
402        msg = 'Time must be a monotonuosly '
403        msg += 'increasing sequence %s' %time
404        assert alltrue(time[1:] - time[:-1] >= 0 ), msg
405
406
407        #Check if quantities is a single array only
408        if type(quantities) != types.DictType:
409            quantities = ensure_numeric(quantities)
410            quantity_names = ['Attribute']
411
412            #Make it a dictionary
413            quantities = {quantity_names[0]: quantities}
414
415
416        #Use keys if no names are specified
417        if quantity_names is None:
418            quantity_names = quantities.keys()
419
420
421        #Check spatial info
422        if vertex_coordinates is None:
423            self.spatial = False
424        else:   
425            vertex_coordinates = ensure_numeric(vertex_coordinates)
426
427            assert triangles is not None, 'Triangles array must be specified'
428            triangles = ensure_numeric(triangles)
429            self.spatial = True           
430
431             
432        #Save for use with statistics
433
434        self.quantities_range = {}
435        for name in quantity_names:
436            q = quantities[name][:].flat
437            self.quantities_range[name] = [min(q), max(q)]
438       
439        self.quantity_names = quantity_names       
440        #self.quantities = quantities  #Takes too much memory     
441        self.vertex_coordinates = vertex_coordinates
442        self.interpolation_points = interpolation_points
443        self.time = time[:]  # Time assumed to be relative to starttime
444        self.index = 0    # Initial time index
445        self.precomputed_values = {}
446       
447
448
449
450       
451           
452        #Precomputed spatial interpolation if requested
453        if interpolation_points is not None:
454            if self.spatial is False:
455                raise 'Triangles and vertex_coordinates must be specified'
456           
457            try:
458                self.interpolation_points = ensure_numeric(interpolation_points)
459            except:
460                msg = 'Interpolation points must be an N x 2 Numeric array '+\
461                      'or a list of points\n'
462                msg += 'I got: %s.' %(str(self.interpolation_points)[:60] +\
463                                      '...')
464                raise msg
465
466
467            m = len(self.interpolation_points)
468            p = len(self.time)
469           
470            for name in quantity_names:
471                self.precomputed_values[name] = zeros((p, m), Float)
472
473            #Build interpolator
474            interpol = Interpolate(vertex_coordinates,
475                                     triangles,
476                                     #point_coordinates = \
477                                     #self.interpolation_points,
478                                     #alpha = 0,
479                                     verbose = verbose)
480
481            if verbose: print 'Interpolate'
482            for i, t in enumerate(self.time):
483                #Interpolate quantities at this timestep
484                if verbose and i%((p+10)/10)==0:
485                    print ' time step %d of %d' %(i, p)
486                   
487                for name in quantity_names:
488                    if len(quantities[name].shape) == 2:
489                        result = interpol.interpolate(quantities[name][i,:],
490                                     point_coordinates = \
491                                     self.interpolation_points)
492                    else:
493                       #Assume no time dependency
494                       result = interpol.interpolate(quantities[name][:],
495                                     point_coordinates = \
496                                     self.interpolation_points)
497                       
498                    self.precomputed_values[name][i, :] = result
499                   
500            #Report
501            if verbose:
502                print self.statistics()
503                #self.print_statistics()
504           
505        else:
506            #Store quantitites as is
507            for name in quantity_names:
508                self.precomputed_values[name] = quantities[name]
509
510
511    def __repr__(self):
512        #return 'Interpolation function (spatio-temporal)'
513        return self.statistics()
514   
515
516    def __call__(self, t, point_id = None, x = None, y = None):
517        """Evaluate f(t), f(t, point_id) or f(t, x, y)
518
519        Inputs:
520          t: time - Model time. Must lie within existing timesteps
521          point_id: index of one of the preprocessed points.
522          x, y:     Overrides location, point_id ignored
523         
524          If spatial info is present and all of x,y,point_id
525          are None an exception is raised
526                   
527          If no spatial info is present, point_id and x,y arguments are ignored
528          making f a function of time only.
529
530         
531          FIXME: point_id could also be a slice
532          FIXME: What if x and y are vectors?
533          FIXME: What about f(x,y) without t?
534        """
535
536        from math import pi, cos, sin, sqrt
537        from Numeric import zeros, Float
538        from util import mean       
539
540        if self.spatial is True:
541            if point_id is None:
542                if x is None or y is None:
543                    msg = 'Either point_id or x and y must be specified'
544                    raise Exception(msg)
545            else:
546                if self.interpolation_points is None:
547                    msg = 'Interpolation_function must be instantiated ' +\
548                          'with a list of interpolation points before parameter ' +\
549                          'point_id can be used'
550                    raise Exception(msg)
551
552        msg = 'Time interval [%.16f:%.16f]' %(self.time[0], self.time[-1])
553        msg += ' does not match model time: %.16f\n' %t
554        if t < self.time[0]: raise Exception(msg)
555        if t > self.time[-1]: raise Exception(msg)
556
557        oldindex = self.index #Time index
558
559        #Find current time slot
560        while t > self.time[self.index]: self.index += 1
561        while t < self.time[self.index]: self.index -= 1
562
563        if t == self.time[self.index]:
564            #Protect against case where t == T[-1] (last time)
565            # - also works in general when t == T[i]
566            ratio = 0
567        else:
568            #t is now between index and index+1
569            ratio = (t - self.time[self.index])/\
570                    (self.time[self.index+1] - self.time[self.index])
571
572        #Compute interpolated values
573        q = zeros(len(self.quantity_names), Float)
574        #print "self.precomputed_values", self.precomputed_values
575        for i, name in enumerate(self.quantity_names):
576            Q = self.precomputed_values[name]
577
578            if self.spatial is False:
579                #If there is no spatial info               
580                assert len(Q.shape) == 1
581
582                Q0 = Q[self.index]
583                if ratio > 0: Q1 = Q[self.index+1]
584
585            else:
586                if x is not None and y is not None:
587                    #Interpolate to x, y
588                   
589                    raise 'x,y interpolation not yet implemented'
590                else:
591                    #Use precomputed point
592                    Q0 = Q[self.index, point_id]
593                    if ratio > 0:
594                        Q1 = Q[self.index+1, point_id]
595           
596            #Linear temporal interpolation   
597            if ratio > 0:
598                if Q0 == INF and Q1 == INF:
599                    q[i]  = Q0
600                else:
601                    q[i] = Q0 + ratio*(Q1 - Q0)
602            else:
603                q[i] = Q0
604
605
606        #Return vector of interpolated values
607        #if len(q) == 1:
608        #    return q[0]
609        #else:
610        #    return q
611
612
613        #Return vector of interpolated values
614        #FIXME:
615        if self.spatial is True:
616            return q
617        else:
618            #Replicate q according to x and y
619            #This is e.g used for Wind_stress
620            if x is None or y is None: 
621                return q
622            else:
623                try:
624                    N = len(x)
625                except:
626                    return q
627                else:
628                    from Numeric import ones, Float
629                    #x is a vector - Create one constant column for each value
630                    N = len(x)
631                    assert len(y) == N, 'x and y must have same length'
632                    res = []
633                    for col in q:
634                        res.append(col*ones(N, Float))
635                       
636                return res
637
638
639    def get_time(self):
640        """Return model time as a vector of timesteps
641        """
642        return self.time
643
644    def statistics(self):
645        """Output statistics about interpolation_function
646        """
647       
648        vertex_coordinates = self.vertex_coordinates
649        interpolation_points = self.interpolation_points               
650        quantity_names = self.quantity_names
651        #quantities = self.quantities
652        precomputed_values = self.precomputed_values                 
653               
654        x = vertex_coordinates[:,0]
655        y = vertex_coordinates[:,1]               
656
657        str =  '------------------------------------------------\n'
658        str += 'Interpolation_function (spatio-temporal) statistics:\n'
659        str += '  Extent:\n'
660        str += '    x in [%f, %f], len(x) == %d\n'\
661               %(min(x), max(x), len(x))
662        str += '    y in [%f, %f], len(y) == %d\n'\
663               %(min(y), max(y), len(y))
664        str += '    t in [%f, %f], len(t) == %d\n'\
665               %(min(self.time), max(self.time), len(self.time))
666        str += '  Quantities:\n'
667        for name in quantity_names:
668            minq, maxq = self.quantities_range[name]
669            str += '    %s in [%f, %f]\n' %(name, minq, maxq)           
670            #q = quantities[name][:].flat
671            #str += '    %s in [%f, %f]\n' %(name, min(q), max(q))
672
673        if interpolation_points is not None:   
674            str += '  Interpolation points (xi, eta):'\
675                   ' number of points == %d\n' %interpolation_points.shape[0]
676            str += '    xi in [%f, %f]\n' %(min(interpolation_points[:,0]),
677                                            max(interpolation_points[:,0]))
678            str += '    eta in [%f, %f]\n' %(min(interpolation_points[:,1]),
679                                             max(interpolation_points[:,1]))
680            str += '  Interpolated quantities (over all timesteps):\n'
681       
682            for name in quantity_names:
683                q = precomputed_values[name][:].flat
684                str += '    %s at interpolation points in [%f, %f]\n'\
685                       %(name, min(q), max(q))
686        str += '------------------------------------------------\n'
687
688        return str
689
690def interpolate_sww(sww_file, time, interpolation_points,
691                    quantity_names = None, verbose = False):
692    """
693    obsolete.
694    use file_function in utils
695    """
696    #open sww file
697    x, y, volumes, time, quantities = read_sww(sww_file)
698    print "x",x
699    print "y",y
700   
701    print "time", time
702    print "quantities", quantities
703
704    #Add the x and y together
705    vertex_coordinates = concatenate((x[:,NewAxis], y[:,NewAxis]),axis=1)
706
707    #Will return the quantity values at the specified times and locations
708    interp =  Interpolation_interface(
709                 time,
710                 quantities,
711                 quantity_names = quantity_names, 
712                 vertex_coordinates = vertex_coordinates,
713                 triangles = volumes,
714                 interpolation_points = interpolation_points,
715                 verbose = verbose)
716
717
718def read_sww(file_name):
719    """
720    obsolete - Nothing should be calling this
721   
722    Read in an sww file.
723   
724    Input;
725    file_name - the sww file
726   
727    Output;
728    x - Vector of x values
729    y - Vector of y values
730    z - Vector of bed elevation
731    volumes - Array.  Each row has 3 values, representing
732    the vertices that define the volume
733    time - Vector of the times where there is stage information
734    stage - array with respect to time and vertices (x,y)
735    """
736   
737    #FIXME Have this reader as part of data_manager?
738   
739    from Scientific.IO.NetCDF import NetCDFFile     
740    import tempfile
741    import sys
742    import os
743   
744    #Check contents
745    #Get NetCDF
746   
747    # see if the file is there.  Throw a QUIET IO error if it isn't
748    # I don't think I could implement the above
749   
750    #throws prints to screen if file not present
751    junk = tempfile.mktemp(".txt")
752    fd = open(junk,'w')
753    stdout = sys.stdout
754    sys.stdout = fd
755    fid = NetCDFFile(file_name, 'r') 
756    sys.stdout = stdout
757    fd.close()
758    #clean up
759    os.remove(junk)     
760     
761    # Get the variables
762    x = fid.variables['x'][:]
763    y = fid.variables['y'][:]
764    volumes = fid.variables['volumes'][:] 
765    time = fid.variables['time'][:]
766
767    keys = fid.variables.keys()
768    keys.remove("x")
769    keys.remove("y")
770    keys.remove("volumes")
771    keys.remove("time")
772     #Turn NetCDF objects into Numeric arrays
773    quantities = {}
774    for name in keys:
775        quantities[name] = fid.variables[name][:]
776           
777    fid.close()
778    return x, y, volumes, time, quantities
779
780#-------------------------------------------------------------
781if __name__ == "__main__":
782    names = ["x","y"]
783    someiterable = [[1,2],[3,4]]
784    csvwriter = writer(file("some.csv", "wb"))
785    csvwriter.writerow(names)
786    for row in someiterable:
787        csvwriter.writerow(row)
Note: See TracBrowser for help on using the repository browser.