Index: /anuga_core/source/anuga/fit_interpolate/interpolate.py
===================================================================
--- /anuga_core/source/anuga/fit_interpolate/interpolate.py	(revision 5774)
+++ /anuga_core/source/anuga/fit_interpolate/interpolate.py	(revision 5775)
@@ -46,4 +46,89 @@
 
 
+def interpolate(vertex_coordinates,
+                triangles,
+                vertex_values,
+                interpolation_points,
+                mesh_origin=None,
+                max_vertices_per_cell=None,
+                start_blocking_len=500000,
+                use_cache=False,             
+                verbose=False):                 
+    """Interpolate vertex_values to interpolation points.
+    
+    Inputs (mandatory):
+
+   
+    vertex_coordinates: List of coordinate pairs [xi, eta] of
+                        points constituting a mesh 
+                        (or an m x 2 Numeric array or
+                        a geospatial object)
+                        Points may appear multiple times
+                        (e.g. if vertices have discontinuities)
+
+    triangles: List of 3-tuples (or a Numeric array) of
+               integers representing indices of all vertices 
+               in the mesh.
+               
+    vertex_values: Vector or array of data at the mesh vertices.
+                   If array, interpolation will be done for each column as
+                   per underlying matrix-matrix multiplication
+              
+    interpolation_points: Interpolate mesh data to these positions.
+                          List of coordinate pairs [x, y] of
+	                  data points or an nx2 Numeric array or a Geospatial_data object
+               
+    Inputs (optional)
+               
+    mesh_origin: A geo_reference object or 3-tuples consisting of
+                 UTM zone, easting and northing.
+                 If specified vertex coordinates are assumed to be
+                 relative to their respective origins.
+
+    max_vertices_per_cell: Number of vertices in a quad tree cell
+                           at which the cell is split into 4.
+
+                           Note: Don't supply a vertex coords as a geospatial object and
+                           a mesh origin, since geospatial has its own mesh origin.
+                           
+    start_blocking_len: If the # of points is more or greater than this,
+                        start blocking 
+                        
+    use_cache: True or False
+                            
+
+    Output:
+    
+    Interpolated values at specified point_coordinates                           
+    
+    
+    Note: This function is a simple shortcut for case where interpolation matrix is unnecessary
+    Note: This function does not take blocking into account, but allows caching.
+    
+    """
+    
+    from anuga.caching import cache
+
+    # Create interpolation object with matrix
+    args = (vertex_coordinates, triangles)
+    kwargs = {'mesh_origin': mesh_origin,
+              'max_vertices_per_cell': max_vertices_per_cell,
+              'verbose': verbose}
+              
+    if use_cache is True:
+        I = cache(Interpolate, args, kwargs,
+                  verbose=verbose)
+    else:
+        I = apply(Interpolate, args, kwargs)
+                  
+    
+    # Call interpolate method with interpolation points
+    result = I.interpolate_block(vertex_values, interpolation_points,
+                                 use_cache=use_cache,
+                                 verbose=verbose)
+                           
+    return result
+    
+
 
 class Interpolate (FitInterpolate):
@@ -95,4 +180,6 @@
                                 verbose=verbose,
                                 max_vertices_per_cell=max_vertices_per_cell)
+                                
+                                
 
     def interpolate_polyline(self,
@@ -208,4 +295,6 @@
         # FIXME (Ole): Why is the interpolation matrix rebuilt everytime the
         # method is called even if interpolation points are unchanged.
+        # This really should use some kind of caching in cases where
+        # interpolation points are reused.
 
         #print "point_coordinates interpolate.interpolate", point_coordinates
@@ -270,5 +359,6 @@
     
 
-    def interpolate_block(self, f, point_coordinates, verbose=False):
+    def interpolate_block(self, f, point_coordinates, 
+                          use_cache=False, verbose=False):
         """
         Call this if you want to control the blocking or make sure blocking
@@ -287,7 +377,16 @@
         f = ensure_numeric(f, Float)        
             
-        self._A = self._build_interpolation_matrix_A(point_coordinates,
-                                                     verbose=verbose)
-
+        if use_cache is True:
+            X = cache(self._build_interpolation_matrix_A,
+                      (point_coordinates),
+                      {'verbose': verbose},                        
+                      verbose=verbose)        
+        else:
+            X = self._build_interpolation_matrix_A(point_coordinates,
+                                                   verbose=verbose)    
+        
+        # Unpack result                                       
+        self._A, self.inside_poly_indices, self.outside_poly_indices = X
+        
 
         # Check that input dimensions are compatible
@@ -353,14 +452,15 @@
         
         if verbose: print 'Getting indices inside mesh boundary'
-        self.inside_poly_indices, self.outside_poly_indices  = \
-                     in_and_outside_polygon(point_coordinates,
-                                            self.mesh.get_boundary_polygon(),
-                                            closed = True, verbose = verbose)
-        
-        #Build n x m interpolation matrix
+        inside_poly_indices, outside_poly_indices  =\
+            in_and_outside_polygon(point_coordinates,
+                                   self.mesh.get_boundary_polygon(),
+                                   closed = True, verbose = verbose)
+        
+        # Build n x m interpolation matrix
         if verbose and len(self.outside_poly_indices) > 0:
             print '\n WARNING: Points outside mesh boundary. \n'
+            
         # Since you can block, throw a warning, not an error.
-        if verbose and 0 == len(self.inside_poly_indices):
+        if verbose and 0 == len(inside_poly_indices):
             print '\n WARNING: No points within the mesh! \n'
             
@@ -373,8 +473,9 @@
         A = Sparse(n,m)
 
-        n = len(self.inside_poly_indices)
-        #Compute matrix elements for points inside the mesh
+        n = len(inside_poly_indices)
+        
+        # Compute matrix elements for points inside the mesh
         if verbose: print 'Building interpolation matrix from %d points' %n
-        for d, i in enumerate(self.inside_poly_indices):
+        for d, i in enumerate(inside_poly_indices):
             # For each data_coordinate point
             if verbose and d%((n+10)/10)==0: print 'Doing %d of %d' %(d, n)
@@ -399,5 +500,5 @@
                 msg = 'Could not find triangle for point', x 
                 raise Exception(msg)
-        return A
+        return A, inside_poly_indices, outside_poly_indices
 
 def benchmark_interpolate(vertices,
Index: /anuga_core/source/anuga/fit_interpolate/search_functions.py
===================================================================
--- /anuga_core/source/anuga/fit_interpolate/search_functions.py	(revision 5774)
+++ /anuga_core/source/anuga/fit_interpolate/search_functions.py	(revision 5775)
@@ -55,6 +55,10 @@
 
     # Search the last triangle first
-    element_found, sigma0, sigma1, sigma2, k = \
-                   _search_triangles_of_vertices(mesh,last_triangle, x)
+    try:
+        element_found, sigma0, sigma1, sigma2, k = \
+            _search_triangles_of_vertices(mesh, last_triangle, x)
+    except:
+        element_found = False
+                   
     #print "last_triangle", last_triangle
     if element_found is True:
@@ -103,9 +107,9 @@
             # been searched.  This is the last try
             element_found, sigma0, sigma1, sigma2, k = \
-                           _search_triangles_of_vertices(mesh,triangles, x)
+                           _search_triangles_of_vertices(mesh, triangles, x)
             is_more_elements = False
         else:
             element_found, sigma0, sigma1, sigma2, k = \
-                       _search_triangles_of_vertices(mesh,triangles, x)
+                       _search_triangles_of_vertices(mesh, triangles, x)
         #search_more_cells_time += time.time()-t0
     #print "search_more_cells_time", search_more_cells_time
Index: /anuga_core/source/anuga/fit_interpolate/test_interpolate.py
===================================================================
--- /anuga_core/source/anuga/fit_interpolate/test_interpolate.py	(revision 5774)
+++ /anuga_core/source/anuga/fit_interpolate/test_interpolate.py	(revision 5775)
@@ -103,5 +103,6 @@
 
         interp = Interpolate(points, vertices)
-        assert allclose(interp._build_interpolation_matrix_A(data).todense(),
+        A, _, _ = interp._build_interpolation_matrix_A(data)
+        assert allclose(A.todense(),
                         [[1./3, 1./3, 1./3]])
 
@@ -115,13 +116,13 @@
         from abstract_2d_finite_volumes.quantity import Quantity
 
-        #Create basic mesh
+        # Create basic mesh
         points, vertices, boundary = rectangular(1, 3)
 
-        #Create shallow water domain
+        # Create shallow water domain
         domain = Domain(points, vertices, boundary)
 
-        #---------------
+        #----------------
         #Constant values
-        #---------------        
+        #----------------        
         quantity = Quantity(domain,[[0,0,0],[1,1,1],[2,2,2],[3,3,3],
                                     [4,4,4],[5,5,5]])
@@ -142,7 +143,7 @@
 
 
-        #---------------
-        #Variable values
-        #---------------
+        #----------------
+        # Variable values
+        #----------------
         quantity = Quantity(domain,[[0,1,2],[3,1,7],[2,1,2],[3,3,7],
                                     [1,4,-9],[2,5,0]])
@@ -162,4 +163,99 @@
         
 
+    def test_simple_interpolation_example_using_direct_interface(self):
+        
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+        from abstract_2d_finite_volumes.quantity import Quantity
+
+        # Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+
+        # Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+
+        #----------------
+        # Constant values
+        #----------------        
+        quantity = Quantity(domain,[[0,0,0],[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5]])
+
+
+        x, y, vertex_values, triangles = quantity.get_vertex_values(xy=True, smooth=False)
+        vertex_coordinates = concatenate( (x[:, NewAxis], y[:, NewAxis]), axis=1 )
+        # FIXME: This concat should roll into get_vertex_values
+
+
+        # Get interpolated values at centroids
+        interpolation_points = domain.get_centroid_coordinates()
+        answer = quantity.get_values(location='centroids')
+
+        result = interpolate(vertex_coordinates, triangles, vertex_values, interpolation_points)
+        assert allclose(result, answer)
+
+
+        #----------------
+        # Variable values
+        #----------------
+        quantity = Quantity(domain,[[0,1,2],[3,1,7],[2,1,2],[3,3,7],
+                                    [1,4,-9],[2,5,0]])
+        
+        x, y, vertex_values, triangles = quantity.get_vertex_values(xy=True, smooth=False)
+        vertex_coordinates = concatenate( (x[:, NewAxis], y[:, NewAxis]), axis=1 )
+        # FIXME: This concat should roll into get_vertex_values
+
+
+        # Get interpolated values at centroids
+        interpolation_points = domain.get_centroid_coordinates()
+        answer = quantity.get_values(location='centroids')
+
+        result = interpolate(vertex_coordinates, triangles,
+                             vertex_values, interpolation_points)
+        assert allclose(result, answer)        
+        
+        
+    def test_simple_interpolation_example_using_direct_interface_and_caching(self):
+        
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+        from abstract_2d_finite_volumes.quantity import Quantity
+
+        # Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+
+        # Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+
+        #----------------
+        # First call
+        #----------------
+        quantity = Quantity(domain,[[0,1,2],[3,1,7],[2,1,2],[3,3,7],
+                                    [1,4,-9],[2,5,0]])
+        
+        x, y, vertex_values, triangles = quantity.get_vertex_values(xy=True, smooth=False)
+        vertex_coordinates = concatenate( (x[:, NewAxis], y[:, NewAxis]), axis=1 )
+        # FIXME: This concat should roll into get_vertex_values
+
+
+        # Get interpolated values at centroids
+        interpolation_points = domain.get_centroid_coordinates()
+        answer = quantity.get_values(location='centroids')
+
+        result = interpolate(vertex_coordinates, triangles,
+                             vertex_values, interpolation_points,
+                             use_cache=True,
+                             verbose=False)
+        assert allclose(result, answer)                
+        
+        # Second call using the cache
+        result = interpolate(vertex_coordinates, triangles,
+                             vertex_values, interpolation_points,
+                             use_cache=True,
+                             verbose=False)
+        assert allclose(result, answer)                        
+        
+        
     def test_quad_tree(self):
         p0 = [-10.0, -10.0]
@@ -192,7 +288,7 @@
                       0., 0. , 0., 0., 0., 0.]]
 
-        
-        assert allclose(interp._build_interpolation_matrix_A(data).todense(),
-                        answer)
+        A,_,_ = interp._build_interpolation_matrix_A(data)
+        assert allclose(A.todense(), answer)
+        
         #interp.set_point_coordinates([[-30, -30]]) #point outside of mesh
         #print "PDSG - interp.get_A()", interp.get_A()
@@ -201,6 +297,6 @@
                       0., 0. , 0., 0., 0., 0.]]
         
-        assert allclose(interp._build_interpolation_matrix_A(data).todense(),
-                        answer)
+        A,_,_ = interp._build_interpolation_matrix_A(data)        
+        assert allclose(A.todense(), answer)
 
 
@@ -211,6 +307,8 @@
         answer =  [ [ 0.0,  0.0,  0.0,  0.,
                       0., 0. , 0., 0., 0., 0.]]
-        assert allclose(interp._build_interpolation_matrix_A(data).todense(),
-                        answer)
+                      
+        A,_,_ = interp._build_interpolation_matrix_A(data)        
+        assert allclose(A.todense(), answer)
+
 
     def test_datapoints_at_vertices(self):
@@ -230,6 +328,7 @@
                    [0., 1., 0.],
                    [0., 0., 1.]]
-        assert allclose(interp._build_interpolation_matrix_A(data).todense(),
-                        answer)
+                   
+        A,_,_ = interp._build_interpolation_matrix_A(data)
+        assert allclose(A.todense(), answer)
 
 
@@ -251,6 +350,6 @@
         interp = Interpolate(points, vertices)
 
-        assert allclose(interp._build_interpolation_matrix_A(data).todense(),
-                        answer)
+        A,_,_ = interp._build_interpolation_matrix_A(data)
+        assert allclose(A.todense(), answer)
 
     def test_datapoints_on_edges(self):
@@ -272,6 +371,6 @@
         interp = Interpolate(points, vertices)
 
-        assert allclose(interp._build_interpolation_matrix_A(data).todense(),
-                        answer)
+        A,_,_ = interp._build_interpolation_matrix_A(data)
+        assert allclose(A.todense(), answer)
 
 
@@ -292,5 +391,7 @@
         interp = Interpolate(points, vertices)
         #print "interp.get_A()", interp.get_A()
-        results = interp._build_interpolation_matrix_A(data).todense()
+        
+        A,_,_ = interp._build_interpolation_matrix_A(data)
+        results = A.todense()
         assert allclose(sum(results, axis=1), 1.0)
 
@@ -311,5 +412,7 @@
 
         interp = Interpolate(points, vertices)
-        results = interp._build_interpolation_matrix_A(data).todense()
+        
+        A,_,_ = interp._build_interpolation_matrix_A(data)
+        results = A.todense()
         assert allclose(sum(results, axis=1), [1,1,1,0])
 
@@ -341,5 +444,6 @@
 
 
-        A = interp._build_interpolation_matrix_A(data).todense()
+        A,_,_ = interp._build_interpolation_matrix_A(data)
+        A = A.todense()
         for i in range(A.shape[0]):
             for j in range(A.shape[1]):
