Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/READ ME.txt
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/READ ME.txt	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/READ ME.txt	(revision 7576)
@@ -0,0 +1,4 @@
+Well-balanced codes added by Sudi Mungkasi, ANU 2009.
+shallow_water_domain_suggestion1 reconstructs: stage and velocity.
+shallow_water_domain_suggestion2 reconstructs: stage, height, and velocity.
+shallow_water_domain_suggestion3 reconstructs: stage, bed, and velocity.
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/analytic_dam_sudi.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/analytic_dam_sudi.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/analytic_dam_sudi.py	(revision 7576)
@@ -0,0 +1,142 @@
+
+
+class AnalyticDam:
+
+    def __init__(self, h0 = 5.0, h1 = 10.0, L = 2000.0):
+        from math import sqrt
+        
+        self.h0 = h0 # depth upstream (m)
+        self.h1 = h1 # depth downstream (m)
+        self.L  = L  # length of domain
+
+        g  = 9.81    # gravity (m/s^2)
+        
+        c0 = sqrt(g*h0) #left celerity
+        c1 = sqrt(g*h1) #right celerity
+        
+        zmin=-100.0
+        zmax=101.0
+        for i in range(100):
+            z=(zmin+zmax)/2.0
+            u2=z-c0*c0/4.0/z*(1.0+sqrt(1.0+8.0*z*z/c0/c0))
+            c2=c0*sqrt(0.5*(sqrt(1.0+8.0*z*z/c0/c0)-1.0))
+            func=2.0*c1/c0-u2/c0-2.0*c2/c0
+            if (func > 0.0):
+                zmin=z
+            else:
+                zmax=z
+            #print 'func=',func
+        if( abs(z) > 99.0):
+            print 'no convergence'
+
+        self.u2 = u2
+        self.c0 = c0
+        self.c1 = c1
+        self.c2 = c2
+        self.g = g
+        self.z = z
+
+
+
+    def __call__(self, C,t):
+        
+        from Numeric import zeros,Float
+        from math import sqrt
+    
+        #t  = 0.0     # time (s)
+        h0 = self.h0    
+        h1 = self.h1    
+        L = self.L 
+        n = len(C)    # number of cells
+
+        u2 = self.u2
+        c0 = self.c0
+        c1 = self.c1
+        c2 = self.c2
+        
+        g = self.g
+        z = self.z
+
+        u = zeros(n,Float)
+        h = zeros(n,Float)
+        uh = zeros(n,Float)
+        x = C-3*L/4.0
+        #x = zeros(n,Float)
+        #for i in range(n):
+        #    x[i] = C[i]-1000.0
+
+        # Upstream and downstream boundary conditions are set to the intial water
+        # depth for all time.
+
+        # Calculate Shock Speed
+        #h2 = 7.2692044
+        
+        #S2 = 2*h2/(h2-h0)*(sqrt(g*h1)-sqrt(g*h2))
+        #u2 = S2 - g*h0/(4*S2)*(1+sqrt(1+8*S2*S2/(g*h0)))
+
+        h2=h0/(1.0-u2/z)
+        x3=(u2-c2)*t
+        x2=z*t
+        x1=-c1*t
+        x1_ = -1*L/2.0-x1
+        x2_ = -1*L/2.0+2*x1
+        #x3_ = -1*L/2.0-x3
+        #t=50 
+        #x = (-L/2:L/2) 
+        for i in range(n):
+            # Calculate Analytical Solution at time t > 0
+            u3 = 2.0/3.0*(sqrt(g*h1)+x[i]/t) 
+            h3 = 4.0/(9.0*g)*(sqrt(g*h1)-x[i]/(2.0*t))*(sqrt(g*h1)-x[i]/(2.0*t))
+            u3_ = 2.0/3.0*((x[i]+L/2.0)/t-sqrt(g*h1))
+            h3_ = 1.0/(9.0*g)*((x[i]+L/2.0)/t+2*sqrt(g*h1))*((x[i]+L/2.0)/t+2*sqrt(g*h1))
+            #if t == 30:
+            #    x[i] = 500
+            #    print 'x2',x2
+            #    print 'x3',x3
+            #    print 'x1',x1
+            if ( x[i] <= x2_ ):
+                #print 'here x2_=', x2_
+                u[i] = 0.0
+                h[i] = 0.0
+                uh [i] = u[i]*h[i]
+            #elif ( x[i] <= x3_ ):
+            #    print 'here x3_=', x3_
+            #    u[i] = -1*u2 
+            #    h[i] = h2
+            #    uh[i] = u[i]*h[i]
+            elif ( x[i] <= x1_ ):
+                #print 'here x1_=', x1_
+                u[i] = u3_ 
+                h[i] = h3_
+                uh[i] = u[i]*h[i]
+            #else:
+            #    u[i] = 0.0 
+            #    h[i] = h0
+            #    uh[i] = u[i]*h[i]
+
+            #elif ( x[i] <= x1/2.0 ):
+            #    u[i] = 0.0 
+            #    h[i] = h1
+            #    uh[i] = u[i]*h[i]
+            elif ( x[i] <= x1 ):
+                #print 'here x1=', x1
+                u[i] = 0.0 
+                h[i] = h1
+                uh[i] = u[i]*h[i]
+            elif ( x[i] <= x3 ):
+                #print 'here x3=', x3
+                u[i] = u3 
+                h[i] = h3
+                uh[i] = u[i]*h[i]
+            elif ( x[i] < x2 ):
+                #print 'here x2=', x2
+                u[i] = u2 
+                h[i] = h2
+                uh[i] = u[i]*h[i]
+            else:
+                #print 'here the last section'
+                u[i] = 0.0 
+                h[i] = h0
+                uh[i] = u[i]*h[i]
+
+        return h , uh, u
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/back_up1_comp_flux_ext_wellbalanced.c
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/back_up1_comp_flux_ext_wellbalanced.c	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/back_up1_comp_flux_ext_wellbalanced.c	(revision 7576)
@@ -0,0 +1,384 @@
+#include "Python.h"
+#include "Numeric/arrayobject.h"
+#include "math.h"
+#include <stdio.h>
+#include "util_ext.h"
+const double pi = 3.14159265358979;
+
+//Innermost flux function (using w=z+h)
+int _flux_function_wellbalanced(double *q_left, 
+								double *q_right,
+								double normals, 
+								double g, 
+								double epsilon,
+								double *edgeflux, 
+								double *max_speed) {		
+		int i;
+        double z_left, z_right;
+		double flux_left[2], flux_right[2];
+		double z_star, w_left, h_left, h_left_star, uh_left, soundspeed_left, u_left;
+		double w_right, h_right, h_right_star, uh_right, soundspeed_right, u_right;                //h_right,
+		double s_max, s_min, denom;
+		
+		w_left  = q_left[0];
+		uh_left = q_left[1];
+		uh_left = uh_left*normals;
+        z_left  = q_left[2];
+		h_left  = q_left[3];
+		u_left  = q_left[4];
+	
+		w_right  = q_right[0];
+		uh_right = q_right[1];
+		uh_right = uh_right*normals;
+        z_right  = q_right[2];
+		h_right  = q_right[3];
+		u_right  = q_right[4];
+		
+		//printf("normals = %f \n",normals);
+		//printf("w_left = %f \n",w_left);
+		//printf("uh_left = %f \n",uh_left);
+		//printf("z_left = %f \n",z_left);
+		//printf("h_left = %f \n",h_left);
+		//printf("u_left = %f \n",u_left);
+		
+		//printf("... \n");
+		
+		//printf("normals = %f \n",normals);
+		//printf("w_right = %f \n",w_right);
+		//printf("uh_right = %f \n",uh_right);
+		//printf("z_right = %f \n",z_right);
+		//printf("h_right = %f \n",h_right);
+		//printf("u_right = %f \n",u_right);
+		
+		//printf("================================ \n");
+	  
+		if (z_left-z_right != 0.0 ) printf("z_l - z_r = %f \n",z_left-z_right);
+        
+		//z = (z_left+z_right)/2.0;
+		z_star = max(z_left, z_right);		              											//equation(7)  
+				   
+		// Compute speeds in x-direction
+		//h_left = w_left-z_left;		                                                                //This is used for computing the edgeflux[1].
+		h_left_star = max(0.0, w_left-z_star);														//(8)
+		
+		if (h_left_star < epsilon) {
+			u_left = 0.0; h_left_star = 0.0;
+		}
+		else {
+			u_left = uh_left/h_left_star;
+		}
+	
+		//h_right = w_right-z_right;                                                                                                                                                                                                     
+		h_right_star = max(0.0, w_right-z_star);														//(9)
+
+		if (h_right_star < epsilon) {
+			u_right = 0.0; h_right_star = 0.0; 
+		}
+		else {
+			u_right = uh_right/h_right_star;
+		}
+  
+		//printf("u_left = %g u_right = %g \n",u_left, u_right);
+		soundspeed_left = sqrt(g*h_left_star);
+		soundspeed_right = sqrt(g*h_right_star);
+		
+		s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
+		if (s_max < 0.0) s_max = 0.0;
+	
+		s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
+		if (s_min > 0.0) s_min = 0.0;
+		
+		
+		// Flux formulas
+		flux_left[0] = u_left*h_left_star;
+		flux_left[1] = u_left*u_left*h_left_star + 0.5*g*h_left_star*h_left_star;
+
+		flux_right[0] = u_right*h_right_star;
+		flux_right[1] = u_right*u_right*h_right_star + 0.5*g*h_right_star*h_right_star;
+
+		// Flux computation
+		denom = s_max-s_min;
+		//printf("denom = %f \n", denom);
+		//printf("epsilon = %f \n", epsilon);
+		if (denom < epsilon && z_right > z_left) {
+			for (i=0; i<2; i++) edgeflux[i] = 0.0;
+			// Maximal wavespeed
+			*max_speed = 0.0;		
+			printf("Momentum edgeflux = %f \n",edgeflux[1]);	
+			edgeflux[1] = edgeflux[1] + (0.5*g*h_left*h_left - 0.5*g*h_left_star*h_left_star );
+			edgeflux[1] *= normals;
+			//printf("Momentum edgeflux = %f \n",edgeflux[1]);
+		} else if (denom < epsilon){
+			for (i=0; i<2; i++) edgeflux[i] = 0.0;
+			// Maximal wavespeed
+			*max_speed = 0.0;
+			//printf("Momentum edgeflux = %f \n",edgeflux[1]);		
+		}else {
+			edgeflux[0] = s_max*flux_left[0] - s_min*flux_right[0];
+			edgeflux[0] += s_max*s_min*(h_right_star-h_left_star);                   //s_max*s_min*(qr[0]-ql[0]);
+			edgeflux[0] /= denom;
+			edgeflux[1] = s_max*flux_left[1] - s_min*flux_right[1];
+			edgeflux[1] += s_max*s_min*(flux_right[0]-flux_left[0]);                 //s_max*s_min*(qr[1]-ql[1]);
+			edgeflux[1] /= denom;
+			printf("Momentum edgeflux = %f \n",edgeflux[1]);	
+			edgeflux[1] = edgeflux[1] + (0.5*g*h_left*h_left - 0.5*g*h_left_star*h_left_star );
+			edgeflux[1] *= normals;
+			// Maximal wavespeed
+			*max_speed = max(fabs(s_max), fabs(s_min));
+		}  
+		//printf("max_speed = %g \n",*max_speed);
+		//printf("NEW Momentum edgeflux = %f \n",edgeflux[1]);
+		//printf("NEW normals = %f \n",normals);
+		//printf("NEW w_left = %f \n",w_left);
+		//printf("NEW uh_left = %f \n",uh_left);
+		//printf("NEW z_left = %f \n",z_left);
+		//printf("NEW h_left = %f \n",h_left);
+		//printf("NEW u_left = %f \n",u_left);
+		
+		//printf("... \n");
+		
+		//printf("NEW normals = %f \n",normals);
+		//printf("NEW w_right = %f \n",w_right);
+		//printf("NEW uh_right = %f \n",uh_right);
+		//printf("NEW z_right = %f \n",z_right);
+		//printf("NEW h_right = %f \n",h_right);
+		//printf("NEW u_right = %f \n",u_right);
+		
+		//printf("================================ \n");
+		//printf("================================ \n");
+    return 0;		
+	}
+		
+		
+	
+	
+// Computational function for flux computation
+double _compute_fluxes_ext_wellbalanced(double timestep,
+		double epsilon,
+		double g,
+		
+		long* neighbours,
+		long* neighbour_vertices,
+		double* normals,
+		double* areas,
+		
+		double* stage_edge_values,
+		double* xmom_edge_values,
+		double* bed_edge_values,
+		double* height_edge_values,
+		double* vel_edge_values,
+		
+		double* stage_boundary_values,
+		double* xmom_boundary_values,
+		double* bed_boundary_values,
+		double* height_boundary_values,
+		double* vel_boundary_values,
+		
+		double* stage_explicit_update,
+		double* xmom_explicit_update,
+		double* bed_explicit_update,
+		double* height_explicit_update,
+		double* vel_explicit_update,
+		
+		int number_of_elements,
+		double* max_speed_array) {
+		
+		double flux[2], ql[5], qr[5], edgeflux[2];
+		double max_speed, normal;
+		int k, i, ki, n, m, nm=0;
+		
+		for (k=0; k<number_of_elements; k++) {
+			flux[0] = 0.0;
+			flux[1] = 0.0;
+			
+			for (i=0; i<2; i++) {
+				ki = k*2+i;
+				
+				ql[0] = stage_edge_values[ki];
+				ql[1] = xmom_edge_values[ki];
+				ql[2] = bed_edge_values[ki];
+                ql[3] = height_edge_values[ki];
+				ql[4] = vel_edge_values[ki];
+                
+				n = neighbours[ki];
+				printf("neighbours[ki] = %i \n",neighbours[ki]);
+				if (n<0) {
+					m = -n-1;
+					qr[0] = stage_boundary_values[m];
+					qr[1] = xmom_boundary_values[m];
+					qr[2] = ql[2];																			//???
+					qr[3] = height_edge_values[m]; 															//Be careful here
+					qr[4] = vel_edge_values[m];																//Be careful here
+                    
+				} else {
+					m = neighbour_vertices[ki];
+					nm = n*2+m;
+					qr[0] = stage_edge_values[nm];
+					qr[1] = xmom_edge_values[nm];
+					qr[2] = bed_edge_values[nm];
+					qr[3] = height_edge_values[nm];															//Be careful here
+					qr[4] = vel_edge_values[nm];															//Be careful here
+				}
+				
+				normal = normals[ki];
+				//printf("normal = %f \n",normal);
+				//printf("edgeflux[0] = %f \n",edgeflux[0]);
+				//printf("edgeflux[1] = %f \n",edgeflux[1]);
+				//printf("maxspeed = %f \n",&max_speed);			
+				_flux_function_wellbalanced(ql, qr, normal, g, epsilon, edgeflux, &max_speed);
+				flux[0] -= edgeflux[0];
+				flux[1] -= edgeflux[1];
+				
+				// Update timestep based on edge i and possibly neighbour n
+				if (max_speed > epsilon) {
+	                // Original CFL calculation
+					
+					timestep = min(timestep, 0.5*areas[k]/max_speed); //Here, CFL=1.0 is assumed.
+					if (n>=0) {
+						timestep = min(timestep, 0.5*areas[n]/max_speed); //Here, CFL=1.0 is assumed. 
+					}
+				}
+            } // End edge i (and neighbour n)
+			flux[0] /= areas[k];
+			stage_explicit_update[k] = flux[0];
+			flux[1] /= areas[k];
+			xmom_explicit_update[k] = flux[1];
+			
+			//Keep track of maximal speeds
+			max_speed_array[k]=max_speed;
+		}
+		//printf("timestep = %f \n",timestep);
+		return timestep;	
+	}
+	
+	
+	
+
+
+
+//=========================================================================
+// Python Glue
+//=========================================================================
+PyObject *compute_fluxes_ext_wellbalanced(PyObject *self, PyObject *args) {
+  
+    PyArrayObject 
+	*neighbours, 
+	*neighbour_vertices,
+	*normals, 
+	*areas,
+	
+	*stage_edge_values,
+	*xmom_edge_values,
+	*bed_edge_values,
+	*height_edge_values,
+	*vel_edge_values,
+	
+	*stage_boundary_values,
+	*xmom_boundary_values,
+	*bed_boundary_values,
+	*height_boundary_values,
+	*vel_boundary_values,
+	
+	*stage_explicit_update,
+	*xmom_explicit_update,
+	*bed_explicit_update,
+	*height_explicit_update,
+	*vel_explicit_update,
+	
+	*max_speed_array;
+    
+  double timestep, epsilon, g;
+  int number_of_elements;
+    
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOOOOOOOOOiO",
+			&timestep,
+			&epsilon,
+			&g,
+			
+			&neighbours,
+			&neighbour_vertices,
+			&normals,
+			&areas,
+			
+			&stage_edge_values,
+			&xmom_edge_values,
+			&bed_edge_values,
+			&height_edge_values,
+			&vel_edge_values,
+			
+			&stage_boundary_values,
+			&xmom_boundary_values,
+			&bed_boundary_values,
+			&height_boundary_values,
+			&vel_boundary_values,
+			
+			&stage_explicit_update,
+			&xmom_explicit_update,
+			&bed_explicit_update,
+			&height_explicit_update,
+			&vel_explicit_update,
+			
+			&number_of_elements,
+			&max_speed_array)) {
+    PyErr_SetString(PyExc_RuntimeError, "comp_flux_ext_wellbalanced.c: compute_fluxes_ext_wellbalanced could not parse input");
+    return NULL;
+  }
+
+ 
+  // Call underlying flux computation routine and update 
+  // the explicit update arrays 
+  timestep = _compute_fluxes_ext_wellbalanced(timestep,
+				 epsilon,
+				 g,
+				 
+				 (long*) neighbours -> data,
+				 (long*) neighbour_vertices -> data,
+				 (double*) normals -> data,
+				 (double*) areas -> data,
+				 
+				 (double*) stage_edge_values -> data,
+				 (double*) xmom_edge_values -> data,
+				 (double*) bed_edge_values -> data,
+				 (double*) height_edge_values -> data,
+				 (double*) vel_edge_values -> data,
+				 
+				 (double*) stage_boundary_values -> data,
+				 (double*) xmom_boundary_values -> data,
+				 (double*) bed_boundary_values -> data,
+				 (double*) height_boundary_values -> data,
+				 (double*) vel_boundary_values -> data,
+				 
+				 (double*) stage_explicit_update -> data,
+				 (double*) xmom_explicit_update -> data,
+				 (double*) bed_explicit_update -> data,
+				 (double*) height_explicit_update -> data,
+				 (double*) vel_explicit_update -> data,
+				 
+				 number_of_elements,
+				 (double*) max_speed_array -> data);
+
+  // Return updated flux timestep
+  return Py_BuildValue("d", timestep);
+}
+
+
+
+
+
+//-------------------------------
+// Method table for python module
+//-------------------------------
+
+static struct PyMethodDef MethodTable[] = {
+  {"compute_fluxes_ext_wellbalanced", compute_fluxes_ext_wellbalanced, METH_VARARGS, "Print out"},
+  {NULL, NULL}
+};
+
+// Module initialisation
+void initcomp_flux_ext_wellbalanced(void){
+  Py_InitModule("comp_flux_ext_wellbalanced", MethodTable);
+  import_array();
+}
+	
+	
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/back_up_comp_flux_ext_wellbalanced.c
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/back_up_comp_flux_ext_wellbalanced.c	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/back_up_comp_flux_ext_wellbalanced.c	(revision 7576)
@@ -0,0 +1,289 @@
+#include "Python.h"
+#include "Numeric/arrayobject.h"
+#include "math.h"
+#include <stdio.h>
+const double pi = 3.14159265358979;
+
+
+// Shared code snippets
+#include "util_ext.h"
+
+
+//double max(double a, double b) { 
+// 	double z; 
+// 	z=(a>b)?a:b; 
+// 	return z;} 
+	
+//double min(double a, double b) { 
+// 	double z; 
+// 	z=(a<b)?a:b; 
+// 	return z;} 
+
+
+
+
+
+//Innermost flux function (using w=z+h)
+int _flux_function_wellbalanced(double *q_left, double *q_right,
+		double normals, double g, double epsilon,
+		double *edgeflux, double *max_speed) {
+		
+		int i;
+        double z_left, z_right;
+		double flux_left[2], flux_right[2];
+		double z_star, w_left, h_left, h_left_star, uh_left, soundspeed_left, u_left;
+		double w_right, h_right, h_right_star, uh_right, soundspeed_right, u_right;                          //h_right,
+		double s_max, s_min, denom;
+		
+		w_left = q_left[0];
+		uh_left = q_left[1];
+		uh_left = uh_left*normals;
+        z_left = q_left[2];
+	
+		w_right = q_right[0];
+		uh_right = q_right[1];
+		uh_right = uh_right*normals;
+        z_right = q_right[2];
+	  
+		if (z_left-z_right != 0.0 ) printf("z_l - z_r = %f \n",z_left-z_right);
+        
+		//z = (z_left+z_right)/2.0;
+		z_star = max(z_left, z_right);		              											//equation(7)  
+				   
+		// Compute speeds in x-direction
+		h_left = w_left-z_left;		                                                                //This is used for computing the edgeflux[1].
+		h_left_star = max(0.0, w_left-z_star);														//(8)
+    
+		if (h_left_star < epsilon) {
+			u_left = 0.0; h_left_star = 0.0;
+		}
+		else {
+			u_left = uh_left/h_left_star;
+		}
+	
+		h_right = w_right-z_right;                                                                                                                                                                                                     
+		h_right_star = max(0.0, w_right-z_star);														//(9)
+
+		if (h_right_star < epsilon) {
+			u_right = 0.0; h_right_star = 0.0; 
+		}
+		else {
+			u_right = uh_right/h_right_star;
+		}
+  
+		//printf("u_left = %g u_right = %g \n",u_left, u_right);
+		soundspeed_left = sqrt(g*h_left_star);
+		soundspeed_right = sqrt(g*h_right_star);
+		
+		s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
+		if (s_max < 0.0) s_max = 0.0;
+	
+		s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
+		if (s_min > 0.0) s_min = 0.0;
+		
+		
+		// Flux formulas
+		flux_left[0] = u_left*h_left_star;
+		flux_left[1] = u_left*u_left*h_left_star + 0.5*g*h_left_star*h_left_star;
+
+		flux_right[0] = u_right*h_right_star;
+		flux_right[1] = u_right*u_right*h_right_star + 0.5*g*h_right_star*h_right_star;
+
+		// Flux computation
+		denom = s_max-s_min;
+		if (denom < epsilon) {
+			for (i=0; i<2; i++) edgeflux[i] = 0.0;
+			*max_speed = 0.0;
+		} else {
+			edgeflux[0] = s_max*flux_left[0] - s_min*flux_right[0];
+			edgeflux[0] += s_max*s_min*(h_right_star-h_left_star);                   //s_max*s_min*(qr[0]-ql[0]);
+			edgeflux[0] /= denom;
+			edgeflux[1] = s_max*flux_left[1] - s_min*flux_right[1];
+			edgeflux[1] += s_max*s_min*(flux_right[0]-flux_left[0]);                 //s_max*s_min*(qr[1]-ql[1]);
+			edgeflux[1] /= denom;
+			
+    
+		//edgeflux[1] = edgeflux[1] + 0.5*g*0.5*(h_left+h_right)*0.5*(h_left+h_right) - 0.5*g*h_left_star*h_left_star;
+		//edgeflux[1] = edgeflux[1] + 0.5*g*h_right*h_right - 0.5*g*h_right_star*h_right_star;
+		edgeflux[1] = edgeflux[1] + (0.5*g*h_left*h_left - 0.5*g*h_left_star*h_left_star );           //what about the h_right and h_right_star??????????????????????
+		edgeflux[1] *= normals;
+		// Maximal wavespeed
+        *max_speed = max(fabs(s_max), fabs(s_min));
+		}  
+		//printf("max_speed = %g \n",*max_speed);
+    return 0;		
+	}
+		
+		
+	
+	
+// Computational function for flux computation
+double _compute_fluxes_ext_wellbalanced(double timestep,
+		double epsilon,
+		double g,
+		long* neighbours,
+		long* neighbour_vertices,
+		double* normals,
+		double* areas,
+		double* stage_edge_values,
+		double* xmom_edge_values,
+		double* bed_edge_values,
+		double* stage_boundary_values,
+		double* xmom_boundary_values,
+		double* stage_explicit_update,
+		double* xmom_explicit_update,
+		int number_of_elements,
+		double* max_speed_array) {
+		
+		double flux[2], ql[3], qr[3], edgeflux[2];
+		double max_speed, normal;
+		int k, i, ki, n, m, nm=0;
+		
+		for (k=0; k<number_of_elements; k++) {
+			flux[0] = 0.0;
+			flux[1] = 0.0;
+			
+			for (i=0; i<2; i++) {
+				ki = k*2+i;
+				
+				ql[0] = stage_edge_values[ki];
+				ql[1] = xmom_edge_values[ki];
+				ql[2] = bed_edge_values[ki];
+				//ql[3] = velocity_edge_values[ki];
+                //ql[4] = height_edge_values[ki];
+                
+				n = neighbours[ki];
+				if (n<0) {
+					m = -n-1;
+					qr[0] = stage_boundary_values[m];
+					qr[1] = xmom_boundary_values[m];
+					qr[2] = ql[2];
+                    
+				} else {
+					m = neighbour_vertices[ki];
+					nm = n*2+m;
+					qr[0] = stage_edge_values[nm];
+					qr[1] = xmom_edge_values[nm];
+					qr[2] = bed_edge_values[nm];				
+				}
+				
+				normal = normals[ki];
+				_flux_function_wellbalanced(ql, qr, normal, g, epsilon, edgeflux, &max_speed);
+				flux[0] -= edgeflux[0];
+				flux[1] -= edgeflux[1];
+				
+				// Update timestep based on edge i and possibly neighbour n
+				if (max_speed > epsilon) {
+	                // Original CFL calculation
+					
+					timestep = min(timestep, 0.5*areas[k]/max_speed); //Here, CFL=1.0 is assumed. ?????????????????????????????????????????????
+					if (n>=0) {
+						timestep = min(timestep, 0.5*areas[n]/max_speed); //Here, CFL=1.0 is assumed. ?????????????????????????????????????????????
+					}
+				}
+            } // End edge i (and neighbour n)
+			flux[0] /= areas[k];
+			stage_explicit_update[k] = flux[0];
+			flux[1] /= areas[k];
+			xmom_explicit_update[k] = flux[1];
+			
+			//Keep track of maximal speeds
+			max_speed_array[k]=max_speed;
+		}
+		//printf("timestep = %f \n",timestep);
+		return timestep;	
+	}
+	
+	
+	
+
+
+
+//=========================================================================
+// Python Glue
+//=========================================================================
+PyObject *compute_fluxes_ext_wellbalanced(PyObject *self, PyObject *args) {
+  
+    PyArrayObject 
+	*neighbours, 
+	*neighbour_vertices,
+	*normals, 
+	*areas,
+	*stage_edge_values,
+	*xmom_edge_values,
+	*bed_edge_values,
+	*stage_boundary_values,
+	*xmom_boundary_values,
+	*stage_explicit_update,
+	*xmom_explicit_update,
+	*max_speed_array;
+    
+  double timestep, epsilon, g;
+  int number_of_elements;
+    
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOiO",
+			&timestep,
+			&epsilon,
+			&g,
+			&neighbours,
+			&neighbour_vertices,
+			&normals,
+			&areas,
+			&stage_edge_values,
+			&xmom_edge_values,
+			&bed_edge_values,
+			&stage_boundary_values,
+			&xmom_boundary_values,
+			&stage_explicit_update,
+			&xmom_explicit_update,
+			&number_of_elements,
+			&max_speed_array)) {
+    PyErr_SetString(PyExc_RuntimeError, "comp_flux_ext.c: compute_fluxes_ext could not parse input");
+    return NULL;
+  }
+
+ 
+  // Call underlying flux computation routine and update 
+  // the explicit update arrays 
+  timestep = _compute_fluxes_ext_wellbalanced(timestep,
+				 epsilon,
+				 g,
+				 (long*) neighbours -> data,
+				 (long*) neighbour_vertices -> data,
+				 (double*) normals -> data,
+				 (double*) areas -> data,
+				 (double*) stage_edge_values -> data,
+				 (double*) xmom_edge_values -> data,
+				 (double*) bed_edge_values -> data,
+				 (double*) stage_boundary_values -> data,
+				 (double*) xmom_boundary_values -> data,
+				 (double*) stage_explicit_update -> data,
+				 (double*) xmom_explicit_update -> data,
+				 number_of_elements,
+				 (double*) max_speed_array -> data);
+
+  // Return updated flux timestep
+  return Py_BuildValue("d", timestep);
+}
+
+
+
+
+
+//-------------------------------
+// Method table for python module
+//-------------------------------
+
+static struct PyMethodDef MethodTable[] = {
+  {"compute_fluxes_ext_wellbalanced", compute_fluxes_ext_wellbalanced, METH_VARARGS, "Print out"},
+  {NULL, NULL}
+};
+
+// Module initialisation
+void initcomp_flux_ext_wellbalanced(void){
+  Py_InitModule("comp_flux_ext_wellbalanced", MethodTable);
+  import_array();
+}
+	
+	
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/back_up_shallow_water_domain_suggestion2.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/back_up_shallow_water_domain_suggestion2.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/back_up_shallow_water_domain_suggestion2.py	(revision 7576)
@@ -0,0 +1,1406 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+
+from domain import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['stage', 'xmomentum']
+        evolved_quantities = ['stage', 'xmomentum', 'elevation', 'height', 'velocity']
+        other_quantities = ['friction']
+        Generic_Domain.__init__(self, coordinates, boundary,
+                                conserved_quantities, evolved_quantities, other_quantities,
+                                tagged_elements)
+        
+        from config import minimum_allowed_height, g, h0
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+        self.h0 = h0
+
+        #forcing terms not included in 1d domain ?WHy?
+        self.forcing_terms.append(gravity)
+        #self.forcing_terms.append(manning_friction)
+        #print "\nI have Removed forcing terms line 64 1dsw"
+
+        #Realtime visualisation
+        self.visualiser = None
+        self.visualise  = False
+        self.visualise_color_stage = False
+        self.visualise_stage_range = 1.0
+        self.visualise_timer = True
+        self.visualise_range_z = None
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        #Evolve parametrs
+        self.cfl = 1.0
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.quantities_to_be_stored = ['stage','xmomentum']
+
+	self.__doc__ = 'shallow_water_domain_suggestion2'
+	self.check_integrity()
+
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from realtime_visualisation_new import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+            self.visualiser.setup['elevation']=True
+            self.visualiser.updating['stage']=True
+        self.visualise = True
+        if self.visualise_color_stage == True:
+            self.visualiser.coloring['stage'] = True
+            self.visualiser.qcolor['stage'] = (0.0, 0.0, 0.8)
+        print 'initialise visualiser'
+        print self.visualiser.setup
+        print self.visualiser.updating
+
+    def check_integrity(self):
+        Generic_Domain.check_integrity(self)
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+		
+	msg = 'First evolved quantity must be "stage"'
+        assert self.evolved_quantities[0] == 'stage', msg
+        msg = 'Second evolved quantity must be "xmomentum"'
+        assert self.evolved_quantities[1] == 'xmomentum', msg
+        msg = 'Third evolved quantity must be "elevation"'
+        assert self.evolved_quantities[2] == 'elevation', msg
+        msg = 'Fourth evolved quantity must be "height"'
+        assert self.evolved_quantities[3] == 'height', msg
+        msg = 'Fifth evolved quantity must be "velocity"'
+        assert self.evolved_quantities[4] == 'velocity', msg
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes_C_wellbalanced(self)
+
+    def compute_timestep(self):
+        #Call correct module function
+        compute_timestep(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+        
+    def evolve(self, yieldstep = None, finaltime = None, duration = None,
+               skip_initial_step = False):
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime,duration,
+                                       skip_initial_step):
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x and bed elevation
+        """
+
+        import data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+
+#Rotation of momentum vector
+def rotate(q, normal, direction = 1):
+    """Rotate the momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector.
+
+    If direction is negative the rotation is inverted.
+
+    Input vector is preserved
+
+    This function is specific to the shallow water wave equation
+    """
+
+    from Numeric import zeros, Float
+
+    assert len(q) == 3,\
+           'Vector of conserved quantities must have length 3'\
+           'for 2D shallow water equation'
+
+    try:
+        l = len(normal)
+    except:
+        raise 'Normal vector must be an Numeric array'
+
+    assert l == 2, 'Normal vector must have 2 components'
+
+
+    n1 = normal[0]
+    n2 = normal[1]
+
+    r = zeros(len(q), Float) #Rotated quantities
+    r[0] = q[0]              #First quantity, height, is not rotated
+
+    if direction == -1:
+        n2 = -n2
+
+
+    r[1] =  n1*q[1] + n2*q[2]
+    r[2] = -n2*q[1] + n1*q[2]
+
+    return r
+
+
+def flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon, h0
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+	
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/(h_left +  h0/h_left)
+
+
+    uh_left = u_left*h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/(h_right + h0/h_right)
+
+    uh_right = u_right*h_right
+	
+
+    #We have got h and u at vertex, then the following is the calculation of fluxes!
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+# 
+def compute_fluxes(domain):
+    """
+	Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    
+    """
+
+    import sys
+    from Numeric import zeros, Float
+    N = domain.number_of_elements
+    Stage = domain.quantities['stage']
+    Xmom  = domain.quantities['xmomentum']
+    Bed   = domain.quantities['elevation']
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    stage, xmom, bed, h_V, u_V = distribute_to_vertices_and_edges(domain)
+    domain.update_boundary()
+	
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            #ql[0] = stage[k, i]
+            #ql[1] = xmom[k, i]
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] = xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            #Flux computation using provided function
+     
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #print 'edgeflux', edgeflux
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        Stage.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k] =  flux[1]
+        #Ymom.explicit_update[k] = flux[2]
+        #print "flux cell",k,flux[0]
+
+    domain.flux_timestep = timestep
+    #print domain.quantities['stage'].centroid_values
+#
+def compute_timestep(domain):
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                qr[0] = stage[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #Update optimal_timestep
+            try:
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+    domain.timestep = timestep
+
+# Compute flux definition
+def compute_fluxes_C_long(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+    #print 'timestep=',timestep
+    #print 'The type of timestep is',type(timestep)
+	
+    epsilon = domain.epsilon
+    #print 'epsilon=',epsilon
+    #print 'The type of epsilon is',type(epsilon)
+	
+    g = domain.g
+    #print 'g=',g
+    #print 'The type of g is',type(g)
+	
+    neighbours = domain.neighbours
+    #print 'neighbours=',neighbours
+    #print 'The type of neighbours is',type(neighbours)
+	
+    neighbour_vertices = domain.neighbour_vertices
+    #print 'neighbour_vertices=',neighbour_vertices
+    #print 'The type of neighbour_vertices is',type(neighbour_vertices)
+	
+    normals = domain.normals
+    #print 'normals=',normals
+    #print 'The type of normals is',type(normals)
+	
+    areas = domain.areas
+    #print 'areas=',areas
+    #print 'The type of areas is',type(areas)
+	
+    stage_edge_values = domain.quantities['stage'].vertex_values
+    #print 'stage_edge_values=',stage_edge_values
+    #print 'The type of stage_edge_values is',type(stage_edge_values)
+	
+    xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+    #print 'xmom_edge_values=',xmom_edge_values
+    #print 'The type of xmom_edge_values is',type(xmom_edge_values)
+	
+    bed_edge_values = domain.quantities['elevation'].vertex_values
+    #print 'bed_edge_values=',bed_edge_values
+    #print 'The type of bed_edge_values is',type(bed_edge_values)
+	
+    stage_boundary_values = domain.quantities['stage'].boundary_values
+    #print 'stage_boundary_values=',stage_boundary_values
+    #print 'The type of stage_boundary_values is',type(stage_boundary_values)
+	
+    xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+    #print 'xmom_boundary_values=',xmom_boundary_values
+    #print 'The type of xmom_boundary_values is',type(xmom_boundary_values)
+	
+    stage_explicit_update = domain.quantities['stage'].explicit_update
+    #print 'stage_explicit_update=',stage_explicit_update
+    #print 'The type of stage_explicit_update is',type(stage_explicit_update)
+	
+    xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+    #print 'xmom_explicit_update=',xmom_explicit_update
+    #print 'The type of xmom_explicit_update is',type(xmom_explicit_update)
+	
+    number_of_elements = len(stage_edge_values)
+    #print 'number_of_elements=',number_of_elements
+    #print 'The type of number_of_elements is',type(number_of_elements)
+	
+    max_speed_array = domain.max_speed_array
+    #print 'max_speed_array=',max_speed_array
+    #print 'The type of max_speed_array is',type(max_speed_array)
+        
+        
+    from comp_flux_ext import compute_fluxes_ext
+	
+    domain.flux_timestep = compute_fluxes_ext(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_edge_values,
+                                  xmom_edge_values,
+                                  bed_edge_values,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+
+# Compute flux definition
+def compute_fluxes_C_short(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+
+    stage = domain.quantities['stage']
+    xmom = domain.quantities['xmomentum']
+    bed = domain.quantities['elevation']
+
+
+    from comp_flux_ext import compute_fluxes_ext_short
+
+    domain.flux_timestep = compute_fluxes_ext_short(timestep,domain,stage,xmom,bed)
+
+
+
+# ###################################
+def compute_fluxes_C_wellbalanced(domain):
+    import sys
+    from Numeric import zeros, Float
+    
+    N = domain.number_of_elements
+    timestep = float(sys.maxint)
+    epsilon = domain.epsilon
+    g = domain.g
+    neighbours = domain.neighbours
+    neighbour_vertices = domain.neighbour_vertices
+    normals = domain.normals
+    areas = domain.areas
+    
+    Stage = domain.quantities['stage']
+    Xmom  = domain.quantities['xmomentum']
+    Bed   = domain.quantities['elevation']
+    #Height = domain.quantities['height']
+    #Velocity = domain.quantities['velocity']
+
+
+    stage_boundary_values = Stage.boundary_values
+    xmom_boundary_values =  Xmom.boundary_values
+    stage_explicit_update = Stage.explicit_update
+    xmom_explicit_update = Xmom.explicit_update
+    max_speed_array = domain.max_speed_array
+   
+    domain.distribute_to_vertices_and_edges()
+    domain.update_boundary()
+    stage_V = Stage.vertex_values
+    xmom_V  = Xmom.vertex_values
+    bed_V   = Bed.vertex_values
+    #h_V     = Height.vertex_values
+    #u_V     = Velocity.vertex_values
+
+    number_of_elements = len(stage_V)
+    # #######
+
+
+        
+    #from comp_flux_ext import compute_fluxes_ext
+    from comp_flux_ext_wellbalanced import compute_fluxes_ext_wellbalanced
+    domain.flux_timestep = compute_fluxes_ext_wellbalanced(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_V,
+                                  xmom_V,
+                                  bed_V,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+# ###################################
+
+
+
+
+
+
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    #protect_against_infinitesimal_and_negative_heights(domain)  
+
+    import sys
+    from Numeric import zeros, Float
+    from config import epsilon, h0, h_min
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    Height = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+    #Arrays   
+    w_C   = Stage.centroid_values    
+    uh_C  = Xmom.centroid_values    
+    z_C   = Bed.centroid_values 
+    h_C   = Height.centroid_values
+    u_C   = Velocity.centroid_values
+    # ###############################
+    for i in range(N):
+	h_C[i] = w_C[i] - z_C[i]						
+        if h_C[i] <= h_min:  #epsilon :
+	    h_C[i] = 0.0
+	    w_C[i] = z_C[i]
+	    uh_C[i] = 0.0
+	    u_C[i] = 0.0
+
+##    for i in range(len(h_C)):
+##	if h_C[i] < epsilon:
+##	    u_C[i] = 0.0  #Could have been negative
+##	    h_C[i] = 0.0
+	else:
+            u_C[i]  = uh_C[i]/(h_C[i] +  h0/h_C[i])
+
+    for name in ['stage', 'height', 'velocity']:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            #print "add extrapolate second order to shallow water"
+            #if name != 'height':
+            Q.extrapolate_second_order()
+            #Q.limit()
+        else:
+            raise 'Unknown order'
+
+    stage_V = domain.quantities['stage'].vertex_values
+    bed_V   = domain.quantities['elevation'].vertex_values
+    h_V     = domain.quantities['height'].vertex_values
+    u_V     = domain.quantities['velocity'].vertex_values		
+    xmom_V  = domain.quantities['xmomentum'].vertex_values 
+    
+
+    bed_V[:] = stage_V - h_V
+    '''
+    for i in range(len(h_C)):
+        for j in range(2):
+            if h_V[i,j] < 0.0 :
+                #CHECK THIS!!!
+                print 'h_V[i,j]=', h_V[i,j]
+                dh = h_V[i,j]
+                h_V[i,j] = 0.0
+                stage_V[i,j] = bed_V[i,j]
+                h_V[i,(j+1)%2] = h_V[i,(j+1)%2] + dh
+                stage_V[i,(j+1)%2] = stage_V[i,(j+1)%2] + dh
+    '''
+
+    xmom_V[:] = u_V * h_V
+    '''
+    for i in range(len(h_V)):
+        if h_V[i] <= h_min:
+            #CHECK THIS!!!
+            print 'h_V[i,j]=', h_V[i,j]
+            u_V[i] = 0.0
+    '''
+    
+    return
+
+    
+#
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+#    ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    zv = domain.quantities['elevation'].vertex_values
+    wv = domain.quantities['stage'].vertex_values
+    hv = wv-zv
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    #remove the above two lines and corresponding code below
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+                wv[k,0] = zv[k,0]
+                wv[k,1] = zv[k,1]
+                
+            xmomc[k] = 0.0
+            
+        #N = domain.number_of_elements
+        #if (k == 0) | (k==N-1):
+        #    wc[k] = zc[k] # Contain 'lost mass' error
+        #    wv[k,0] = zv[k,0]
+        #    wv[k,1] = zv[k,1]
+    
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        #for i in range(3):
+        for i in range(2):   
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    #for i in range(3):
+    for i in range(2):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        #for i in range(3):
+        for i in range(2):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        #for i in range(3):
+        for i in range(2):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]))#,
+#                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using the h-limited
+        #stage and alpha==1 means using the w-limited stage as
+        #computed by the gradient limiter (both 1st or 2nd order)
+
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        alpha  = 0.0
+	#Let
+	#
+	#  wvi be the w-limited stage (wvi = zvi + hvi)
+	#  wvi- be the h-limited state (wvi- = zvi + hvi-)
+	#
+	#
+	#where i=0,1,2 denotes the vertex ids
+	#
+        #Weighted balance between w-limited and h-limited stage is
+        #
+	#  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+	#
+        #It follows that the updated wvi is
+        #  wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+        #
+	# Momentum is balanced between constant and limited
+
+
+        #for i in range(3):
+        #    wv[k,i] = zv[k,i] + hvbar[k,i]
+
+	#return
+
+	if alpha < 1:
+
+            #for i in range(3):
+            for i in range(2):
+                wv[k,i] = zv[k,i] + (1.0-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+#            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+#           ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1.0-alpha)*xmomc[k] + alpha*xmomv[k,:]
+#            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+###############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        #self.stage   = domain.quantities['stage'].edge_values
+        #self.xmom    = domain.quantities['xmomentum'].edge_values
+        #self.ymom    = domain.quantities['ymomentum'].edge_values
+        self.normals  = domain.normals
+        self.stage    = domain.quantities['stage'].vertex_values
+        self.xmom     = domain.quantities['xmomentum'].vertex_values
+        self.bed      = domain.quantities['elevation'].vertex_values
+        self.height   = domain.quantities['height'].vertex_values
+        self.velocity = domain.quantities['velocity'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        #self.conserved_quantities = zeros(2, Float)
+        self.evolved_quantities = zeros(5, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+    """
+    def evaluate(self, vol_id, edge_id):
+        #Reflective boundaries reverses the outward momentum
+        #of the volume they serve.
+        
+        #q = self.conserved_quantities
+        q = self.evolved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = self.xmom[vol_id, edge_id]
+        #q[2] = self.ymom[vol_id, edge_id]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+1]
+        normal = self.normals[vol_id,edge_id]
+
+        #r = rotate(q, normal, direction = 1)
+        #r[1] = -r[1]
+        #q = rotate(r, normal, direction = -1)
+        r = q
+        r[1] = normal*r[1]
+        r[1] = -r[1]
+        r[1] = normal*r[1]
+        q = r
+        #For start interval there is no outward momentum so do not need to
+        #reverse direction in this case
+
+        return q
+    """
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+        q = self.evolved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = -self.xmom[vol_id, edge_id]
+        q[2] = self.bed[vol_id, edge_id]
+        q[3] = self.height[vol_id, edge_id]
+        q[4] = -self.velocity[vol_id, edge_id]
+        return q
+
+
+    
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, conserved_quantities=None):
+        Boundary.__init__(self)
+
+        if conserved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.conserved_quantities=array(conserved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.conserved_quantities
+
+
+#########################
+#Standard forcing terms:
+#
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    stage = domain.quantities['stage'].explicit_update
+#    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    #h = Stage.edge_values - Elevation.edge_values
+    h = Stage.vertex_values - Elevation.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+#        avg_h = sum( h[k,:] )/3
+        avg_h = sum( h[k,:] )/2
+
+        #Compute bed slope
+        #x0, y0, x1, y1, x2, y2 = x[k,:]
+        x0, x1 = x[k,:]
+        #z0, z1, z2 = v[k,:]
+        b0, b1 = b[k,:]
+
+        w0, w1 = w[k,:]
+        wx = gradient(x0, x1, w0, w1)
+
+        #zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        xmom[k] += -g*bx*avg_h
+        #xmom[k] = -g*bx*avg_h
+        #stage[k] = 0.0
+ 
+ 
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    #vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    #ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	#S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+                S = -g * eta[k]**2 * uh[k]
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	#ymom_update[k] += S*vh[k]
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+#    vh = domain.quantities['ymomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+#    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g #Not necessary? Why was this added?
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+ #           	ymom_update[k] += S*vh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
+class Wind_stress:
+    """Apply wind stress to water momentum in terms of
+    wind speed [m/s] and wind direction [degrees]
+    """
+
+    def __init__(self, *args, **kwargs):
+        """Initialise windfield from wind speed s [m/s]
+        and wind direction phi [degrees]
+
+        Inputs v and phi can be either scalars or Python functions, e.g.
+
+        W = Wind_stress(10, 178)
+
+        #FIXME - 'normal' degrees are assumed for now, i.e. the
+        vector (1,0) has zero degrees.
+        We may need to convert from 'compass' degrees later on and also
+        map from True north to grid north.
+
+        Arguments can also be Python functions of t,x,y as in
+
+        def speed(t,x,y):
+            ...
+            return s
+
+        def angle(t,x,y):
+            ...
+            return phi
+
+        where x and y are vectors.
+
+        and then pass the functions in
+
+        W = Wind_stress(speed, angle)
+
+        The instantiated object W can be appended to the list of
+        forcing_terms as in
+
+        Alternatively, one vector valued function for (speed, angle)
+        can be applied, providing both quantities simultaneously.
+        As in
+        W = Wind_stress(F), where returns (speed, angle) for each t.
+
+        domain.forcing_terms.append(W)
+        """
+
+        from config import rho_a, rho_w, eta_w
+        from Numeric import array, Float
+
+        if len(args) == 2:
+            s = args[0]
+            phi = args[1]
+        elif len(args) == 1:
+            #Assume vector function returning (s, phi)(t,x,y)
+            vector_function = args[0]
+            #s = lambda t,x,y: vector_function(t,x=x,y=y)[0]
+            #phi = lambda t,x,y: vector_function(t,x=x,y=y)[1]
+            s = lambda t,x: vector_function(t,x=x)[0]
+            phi = lambda t,x: vector_function(t,x=x)[1]
+        else:
+           #Assume info is in 2 keyword arguments
+
+           if len(kwargs) == 2:
+               s = kwargs['s']
+               phi = kwargs['phi']
+           else:
+               raise 'Assumes two keyword arguments: s=..., phi=....'
+
+        print 'phi', phi
+        self.speed = check_forcefield(s)
+        self.phi = check_forcefield(phi)
+
+        self.const = eta_w*rho_a/rho_w
+
+
+    def __call__(self, domain):
+        """Evaluate windfield based on values found in domain
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import Float, ones, ArrayType
+
+        xmom_update = domain.quantities['xmomentum'].explicit_update
+        #ymom_update = domain.quantities['ymomentum'].explicit_update
+
+        N = domain.number_of_elements
+        t = domain.time
+
+        if callable(self.speed):
+            xc = domain.get_centroid_coordinates()
+            #s_vec = self.speed(t, xc[:,0], xc[:,1])
+            s_vec = self.speed(t, xc)
+        else:
+            #Assume s is a scalar
+
+            try:
+                s_vec = self.speed * ones(N, Float)
+            except:
+                msg = 'Speed must be either callable or a scalar: %s' %self.s
+                raise msg
+
+
+        if callable(self.phi):
+            xc = domain.get_centroid_coordinates()
+            #phi_vec = self.phi(t, xc[:,0], xc[:,1])
+            phi_vec = self.phi(t, xc)
+        else:
+            #Assume phi is a scalar
+
+            try:
+                phi_vec = self.phi * ones(N, Float)
+            except:
+                msg = 'Angle must be either callable or a scalar: %s' %self.phi
+                raise msg
+
+        #assign_windfield_values(xmom_update, ymom_update,
+        #                        s_vec, phi_vec, self.const)
+        assign_windfield_values(xmom_update, s_vec, phi_vec, self.const)
+
+
+#def assign_windfield_values(xmom_update, ymom_update,
+#                            s_vec, phi_vec, const):
+def assign_windfield_values(xmom_update, s_vec, phi_vec, const):
+    """Python version of assigning wind field to update vectors.
+    A c version also exists (for speed)
+    """
+    from math import pi, cos, sin, sqrt
+
+    N = len(s_vec)
+    for k in range(N):
+        s = s_vec[k]
+        phi = phi_vec[k]
+
+        #Convert to radians
+        phi = phi*pi/180
+
+        #Compute velocity vector (u, v)
+        u = s*cos(phi)
+        v = s*sin(phi)
+
+        #Compute wind stress
+        #S = const * sqrt(u**2 + v**2)
+        S = const * u
+        xmom_update[k] += S*u
+        #ymom_update[k] += S*v
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/channel_domain.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/channel_domain.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/channel_domain.py	(revision 7576)
@@ -0,0 +1,584 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+
+from domain import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['stage', 'xmomentum']
+        evolved_quantities = ['stage', 'xmomentum', 'elevation', 'height', 'velocity']
+        other_quantities = ['friction']
+        Generic_Domain.__init__(self,
+                                coordinates = coordinates,
+                                boundary = boundary,
+                                conserved_quantities = conserved_quantities,
+                                evolved_quantities = evolved_quantities,
+                                other_quantities = other_quantities,
+                                tagged_elements = tagged_elements)
+        
+        from config import minimum_allowed_height, g, h0
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+        self.h0 = h0
+
+        #forcing terms not included in 1d domain ?WHy?
+        self.forcing_terms.append(gravity)
+        #self.forcing_terms.append(manning_friction)
+        #print "\nI have Removed forcing terms line 64 1dsw"
+
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.set_quantities_to_be_stored(['stage','xmomentum'])
+
+	self.__doc__ = 'channel_domain'
+
+        self.check_integrity()
+
+
+    def check_integrity(self):
+
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+
+        msg = 'First evolved quantity must be "stage"'
+        assert self.evolved_quantities[0] == 'stage', msg
+        msg = 'Second evolved quantity must be "xmomentum"'
+        assert self.evolved_quantities[1] == 'xmomentum', msg
+        msg = 'Third evolved quantity must be "elevation"'
+        assert self.evolved_quantities[2] == 'elevation', msg
+        msg = 'Fourth evolved quantity must be "height"'
+        assert self.evolved_quantities[3] == 'height', msg
+        msg = 'Fifth evolved quantity must be "velocity"'
+        assert self.evolved_quantities[4] == 'velocity', msg
+
+        Generic_Domain.check_integrity(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes_vel(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges_limit_w_u(self)
+        
+
+#=============== End of Channel Domain ===============================
+#-----------------------------------
+# Compute fluxes interface
+#-----------------------------------
+def compute_fluxes(domain):
+    """
+    Python version of compute fluxes (local_compute_fluxes)
+    is available in test_shallow_water_vel_domain.py
+    """
+ 
+
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+
+    stage = domain.quantities['stage']
+    xmom = domain.quantities['xmomentum']
+    bed = domain.quantities['elevation']
+
+
+    from comp_flux_vel_ext import compute_fluxes_ext
+
+    domain.flux_timestep = compute_fluxes_ext(timestep,domain,stage,xmom,bed)
+
+
+#-----------------------------------
+# Compute flux definition with vel
+#-----------------------------------
+def compute_fluxes_vel(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+
+    stage    = domain.quantities['stage']
+    xmom     = domain.quantities['xmomentum']
+    bed      = domain.quantities['elevation']
+    height   = domain.quantities['height']
+    velocity = domain.quantities['velocity']
+
+
+    from comp_flux_vel_ext import compute_fluxes_vel_ext
+
+    domain.flux_timestep = compute_fluxes_vel_ext(timestep,domain,stage,xmom,bed,height,velocity)
+
+
+#--------------------------------------------------------------------------
+def distribute_to_vertices_and_edges_limit_w_u(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    #protect_against_infinitesimal_and_negative_heights(domain)  
+
+    import sys
+    from Numeric import zeros, Float
+    from config import epsilon, h0
+	
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    Height = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+    #Arrays   
+    w_C   = Stage.centroid_values    
+    uh_C  = Xmom.centroid_values    
+    z_C   = Bed.centroid_values
+    h_C   = Height.centroid_values
+    u_C   = Velocity.centroid_values
+	
+    #print id(h_C)
+    for i in range(N):
+	h_C[i] = w_C[i] - z_C[i]						
+        if h_C[i] <= 1.0e-12:
+	    #print 'h_C[%d]= %15.5e\n' % (i,h_C[i])
+	    h_C[i] = 0.0
+	    w_C[i] = z_C[i]
+	    #uh_C[i] = 0.0
+            
+ #           u_C[i] = 0.0
+ #       else:
+ #           u_C[i] = uh_C[i]/h_C[i]
+		
+    h0 = 1.0e-12    
+    for i in range(len(h_C)):
+	if h_C[i] < 1.0e-12:
+	    u_C[i] = 0.0  #Could have been negative
+	    h_C[i] = 0.0
+	else:
+            u_C[i]  = uh_C[i]/(h_C[i] + h0/h_C[i])
+            #u_C[i]  = uh_C[i]/h_C[i]
+	
+    for name in [ 'velocity', 'stage' ]:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            Q.extrapolate_second_order()
+        else:
+            raise 'Unknown order'
+
+    w_V  = domain.quantities['stage'].vertex_values			
+    z_V  = domain.quantities['elevation'].vertex_values	
+    h_V  = domain.quantities['height'].vertex_values
+    u_V  = domain.quantities['velocity'].vertex_values		
+    uh_V = domain.quantities['xmomentum'].vertex_values	
+
+    h_V[:]    = w_V - z_V
+    for i in range(len(h_C)):
+        for j in range(2):
+            if h_V[i,j] < 0.0 :
+                #print 'h_V[%d,%d] = %f \n' % (i,j,h_V[i,j])                 
+                dh = h_V[i,j]
+                h_V[i,j] = 0.0
+                w_V[i,j] = z_V[i,j]
+                h_V[i,(j+1)%2] = h_V[i,(j+1)%2] + dh
+                w_V[i,(j+1)%2] = w_V[i,(j+1)%2] + dh
+                
+    uh_V[:] = u_V * h_V
+
+    
+    return
+
+#---------------------------------------------------------------------------
+def distribute_to_vertices_and_edges_limit_w_uh(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave equation.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    import sys
+    from Numeric import zeros, Float
+    from config import epsilon, h0
+	
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    Height = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+    #Arrays   
+    w_C   = Stage.centroid_values    
+    uh_C  = Xmom.centroid_values    
+    z_C   = Bed.centroid_values
+    h_C   = Height.centroid_values
+    u_C   = Velocity.centroid_values
+	
+
+    for i in range(N):
+	h_C[i] = w_C[i] - z_C[i]						
+        if h_C[i] <= 1.0e-6:
+	    #print 'h_C[%d]= %15.5e\n' % (i,h_C[i])
+	    h_C[i] = 0.0
+	    w_C[i] = z_C[i]
+	    uh_C[i] = 0.0
+            
+    for name in [ 'stage', 'xmomentum']:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            Q.extrapolate_second_order()
+        else:
+            raise 'Unknown order'
+
+    w_V  = domain.quantities['stage'].vertex_values			
+    z_V  = domain.quantities['elevation'].vertex_values	
+    h_V  = domain.quantities['height'].vertex_values
+    u_V  = domain.quantities['velocity'].vertex_values		
+    uh_V = domain.quantities['xmomentum'].vertex_values	
+
+    h_V[:]    = w_V - z_V
+
+    for i in range(len(h_C)):
+        for j in range(2):
+            if h_V[i,j] < 0.0 :
+                #print 'h_V[%d,%d] = %f \n' % (i,j,h_V[i,j])                 
+                dh = h_V[i,j]
+                h_V[i,j] = 0.0
+                w_V[i,j] = z_V[i,j]
+                h_V[i,(j+1)%2] = h_V[i,(j+1)%2] + dh
+                w_V[i,(j+1)%2] = w_V[i,(j+1)%2] + dh
+                u_V[i,j] = 0.0
+            if h_V[i,j] < h0:
+                u_V[i,j]
+            else:
+                u_V[i,j] = uh_V[i,j]/(h_V[i,j] + h0/h_V[i,j])
+
+
+#--------------------------------------------------------
+#Boundaries - specific to the shallow_water_vel_domain
+#--------------------------------------------------------
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        self.normals  = domain.normals
+        self.stage    = domain.quantities['stage'].vertex_values
+        self.xmom     = domain.quantities['xmomentum'].vertex_values
+        self.bed      = domain.quantities['elevation'].vertex_values
+        self.height   = domain.quantities['height'].vertex_values
+        self.velocity = domain.quantities['velocity'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        self.evolved_quantities = zeros(5, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+
+        q = self.evolved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = -self.xmom[vol_id, edge_id]
+        q[2] = self.bed[vol_id, edge_id]
+        q[3] = self.height[vol_id, edge_id]
+        q[4] = -self.velocity[vol_id, edge_id]
+
+        #print "In Reflective q ",q
+
+
+        return q
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, evolved_quantities=None):
+        Boundary.__init__(self)
+
+        if evolved_quantities is None:
+            msg = 'Must specify one value for each evolved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.evolved_quantities=array(evolved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.evolved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.evolved_quantities
+
+
+#----------------------------
+#Standard forcing terms:
+#---------------------------
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+
+
+    Stage     = domain.quantities['stage']
+    Xmom      = domain.quantities['xmomentum']
+    Elevation = domain.quantities['elevation']
+    Height    = domain.quantities['height']
+
+    xmom_ud  = Xmom.explicit_update
+    #stage_ud = Stage.explicit_update
+
+
+    #h = Stage.vertex_values - Elevation.vertex_values
+    h = Height.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+        avg_h = 0.5*(h[k,0] + h[k,1])
+
+        #Compute bed slope
+        x0, x1 = x[k,:]
+        b0, b1 = b[k,:]
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        xmom_ud[k] += -g*bx*avg_h
+        #stage_ud[k] = 0.0
+ 
+ 
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    #vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    #ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	#S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+                S = -g * eta[k]**2 * uh[k]
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	#ymom_update[k] += S*vh[k]
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/channel_domain_ext.c
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/channel_domain_ext.c	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/channel_domain_ext.c	(revision 7576)
@@ -0,0 +1,510 @@
+#include "Python.h"
+#include "Numeric/arrayobject.h"
+#include "math.h"
+#include <stdio.h>
+const double pi = 3.14159265358979;
+
+
+// Shared code snippets
+#include "util_ext.h"
+
+
+/* double max(double a, double b) { */
+/* 	double z; */
+/* 	z=(a>b)?a:b; */
+/* 	return z;} */
+
+/* double min(double a, double b) { */
+/* 	double z; */
+/* 	z=(a<b)?a:b; */
+/* 	return z;} */
+
+
+// Function to obtain speed from momentum and depth.
+// This is used by flux functions
+// Input parameters uh and h may be modified by this function.
+double _compute_speed(double *uh,
+		      double *h,
+		      double epsilon,
+		      double h0) {
+
+  double u;
+
+  if (*h < epsilon) {
+    *h = 0.0;  //Could have been negative
+     u = 0.0;
+  } else {
+    u = *uh/(*h + h0/ *h);
+  }
+
+
+  // Adjust momentum to be consistent with speed
+  *uh = u * *h;
+
+  return u;
+}
+
+
+
+//Innermost flux function (using w=z+h)
+int _flux_function_channel(double *q_leftm,double *q_leftp, double *q_rightm,
+			   double *q_rightp, double g, double epsilon, double h0,                           double *edgeflux, double *max_speed) {
+
+    int i;
+    double flux_left[2], flux_right[2];
+    double a_leftm,w_leftm, h_leftm, d_leftm, z_leftm, u_leftm, b_leftm, soundspeed_leftm;
+     double a_leftp,w_leftp, h_leftp, d_leftp, z_leftp, u_leftp, b_leftp, soundspeed_leftp;
+ double a_rightm,w_rightm, h_rightm, d_rightm, z_rightm, u_rightm, b_rightm, soundspeed_rightm;
+ double a_rightp,w_rightp, h_rightp, d_rightp, z_rightp, u_rightp, b_rightp, soundspeed_rightp;
+    double s_maxl, s_minl,s_maxr,s_minr, denom;
+    double zphalf,zmhalf,hleftstar,hrightstar;
+    double fluxtemp1,fluxtemp0,speedtemp;
+    double batemp;
+
+    zmhalf = max(q_leftm[2],q_leftp[2]);
+    zphalf = max(q_rightm[2],q_rightp[2]);   
+
+    a_leftm  = q_leftm[0];
+    d_leftm = q_leftm[1];
+    z_leftm  = q_leftm[2];
+    h_leftm  = max(0,q_leftm[3]+q_leftm[2]-zmhalf);
+    u_leftm  = q_leftm[4];
+    b_leftm  = q_leftm[5];
+    w_leftm  = h_leftm+z_leftm;
+
+    a_leftp  = q_leftp[0];
+    d_leftp = q_leftp[1];
+    z_leftp  = q_leftp[2];
+    h_leftp  = max(0,q_leftp[3]+q_leftp[2]-zmhalf);
+    u_leftp  = q_leftp[4];
+    b_leftp  = q_leftp[5];
+    w_leftp  = h_leftp+z_leftp;
+
+    a_rightm  = q_rightm[0];
+    d_rightm = q_rightm[1];
+    z_rightm  = q_rightm[2];
+    h_rightm  = max(0,q_rightm[3]+q_rightm[2]-zphalf);
+    u_rightm  = q_rightm[4];
+    b_rightm  = q_rightm[5];
+    w_rightm  = h_rightm+z_rightm;
+
+    a_rightp  = q_rightp[0];
+    d_rightp = q_rightp[1];
+    z_rightp  = q_rightp[2];
+    h_rightp  = max(0,q_rightp[3]+q_rightp[2]-zphalf);
+    u_rightp  = q_rightp[4];
+    b_rightp  = q_rightp[5];
+    w_rightp  = h_rightp+z_rightp;
+
+    hleftstar = q_leftp[3];
+    hrightstar = q_rightm[3];   
+
+    soundspeed_leftp = sqrt(g*h_leftp);
+    soundspeed_leftm = sqrt(g*h_leftm);
+    soundspeed_rightp = sqrt(g*h_rightp);
+    soundspeed_rightm = sqrt(g*h_rightm);
+
+    s_maxl = max(u_leftm+soundspeed_leftm, u_leftp+soundspeed_leftp);
+    if (s_maxl < 0.0) s_maxl = 0.0;
+
+    s_minl = min(u_leftm-soundspeed_leftm, u_leftp-soundspeed_leftp);
+    if (s_minl > 0.0) s_minl = 0.0;
+
+    s_maxr = max(u_rightm+soundspeed_rightm, u_rightp+soundspeed_rightp);
+    if (s_maxr < 0.0) s_maxr = 0.0;
+
+    s_minr = min(u_rightm-soundspeed_rightm, u_rightp-soundspeed_rightp);
+    if (s_minr > 0.0) s_minr = 0.0;
+
+    // Flux formulas for left hand side
+    flux_left[0] = d_leftm;
+    flux_left[1] = u_leftm*d_leftm + 0.5*g*h_leftm*h_leftm*b_leftm;
+
+    flux_right[0] = d_leftp;
+    flux_right[1] = u_leftp*d_leftp + 0.5*g*h_leftp*h_leftp*b_leftp;
+
+    
+    // Flux computation for left hand side
+    denom = s_maxl-s_minl;
+    if (denom < epsilon) {
+	for (i=0; i<2; i++) edgeflux[i] = 0.0;
+    } else {
+	edgeflux[0] = s_maxl*flux_left[0] - s_minl*flux_right[0];
+
+        batemp = (h_leftp)*b_leftp-(h_leftm)*b_leftm;
+	      	edgeflux[0] += s_maxl*s_minl*batemp;
+	edgeflux[0] /= denom;
+	edgeflux[1] = s_maxl*flux_left[1] - s_minl*flux_right[1];
+	edgeflux[1] += s_maxl*s_minl*(d_leftp-d_leftm);
+	edgeflux[1] /= denom;
+    
+
+    }
+	fluxtemp0 = edgeflux[0];
+        fluxtemp1 = edgeflux[1];
+    
+
+    // Flux formulas for right hand side
+    flux_left[0] = d_rightm;
+    flux_left[1] = u_rightm*d_rightm + 0.5*g*h_rightm*h_rightm*b_rightm;
+
+    flux_right[0] = d_rightp;
+    flux_right[1] = u_rightp*d_rightp + 0.5*g*h_rightp*h_rightp*b_rightp;
+    
+   
+   
+    // Flux computation for right hand side
+    denom = s_maxr-s_minr;
+    if (denom < epsilon) {
+	for (i=0; i<2; i++) edgeflux[i] = 0.0;
+    } else {
+	edgeflux[0] = s_maxr*flux_left[0] - s_minr*flux_right[0];
+
+        batemp = (h_rightp)*b_rightp-(h_rightm)*b_rightm;
+
+         	edgeflux[0] += s_maxr*s_minr*batemp;
+	edgeflux[0] /= denom;
+	edgeflux[1] = s_maxr*flux_left[1] - s_minr*flux_right[1];
+	edgeflux[1] += s_maxr*s_minr*(d_rightp-d_rightm);
+	edgeflux[1] /= denom;
+    
+
+    }
+    
+   
+    edgeflux[0]=edgeflux[0]-fluxtemp0;
+    edgeflux[1]=edgeflux[1]-fluxtemp1;
+    
+   
+     edgeflux[1]-=0.5*g*h_rightm*h_rightm*b_rightm-0.5*g*hrightstar*hrightstar*b_rightm+0.5*g*hleftstar*hleftstar*b_leftp-0.5*g*h_leftp*h_leftp*b_leftp;
+
+   
+     //edgeflux[1]-=0.5*g*h_rightm*h_rightm-0.5*g*hrightstar*hrightstar+0.5*g*hleftstar*hleftstar-0.5*g*h_leftp*h_leftp;
+      
+     //edgeflux[1]-=0.5*g*b_rightm*h_rightm*h_rightm-0.5*g*b_leftp*h_leftp*h_leftp;
+         	// Maximal wavespeed
+	if ( (s_maxl-s_minl)<epsilon && (s_maxr-s_minr)<epsilon ){
+	    *max_speed = 0.0;
+	}else{
+	speedtemp = max(fabs(s_maxl),fabs(s_minl));
+        speedtemp = max(speedtemp,fabs(s_maxr));
+        speedtemp = max(speedtemp,fabs(s_minr));
+	*max_speed = speedtemp;
+	}
+
+//printf("%f\n",h_right);
+    return 0;
+}
+
+
+
+
+
+// Computational function for flux computation
+double _compute_fluxes_channel_ext(double cfl,
+			       double timestep,
+			       double epsilon,
+			       double g,
+			       double h0,
+			       long* neighbours,
+			       long* neighbour_vertices,
+			       double* normals,
+			       double* areas,
+			       double* area_edge_values,
+			       double* discharge_edge_values,
+			       double* bed_edge_values,
+			       double* height_edge_values,
+			       double* velocity_edge_values,
+			       double* width_edge_values,
+			       double* area_boundary_values,
+			       double* discharge_boundary_values,
+			       double* bed_boundary_values,
+			       double* height_boundary_values,
+			       double* velocity_boundary_values,
+			       double* width_boundary_values,
+			       double* area_explicit_update,
+			       double* discharge_explicit_update,
+			       int number_of_elements,
+			       double* max_speed_array) {
+
+    double flux[2], qlm[6],qlp[6], qrm[6],qrp[6], edgeflux[2];
+    double max_speed, normal;
+    int k, i, ki, n, m, nm=0;
+    double zstar;
+    for (k=0; k<number_of_elements; k++) {
+	flux[0] = 0.0;
+	flux[1] = 0.0;
+
+       
+	    ki = k*2;
+           
+
+         n = neighbours[ki];
+	    if (n<0) {
+		m = -n-1;
+
+	    qlm[0] = area_boundary_values[m];
+	    qlm[1] = discharge_boundary_values[m];
+	    qlm[2] = bed_boundary_values[m];
+	    qlm[3] = height_boundary_values[m];
+	    qlm[4] = velocity_boundary_values[m];
+            qlm[5] = width_boundary_values[m];
+
+	    }else{
+	m = neighbour_vertices[ki];
+		nm = n*2+m;
+	    
+
+	    qlm[0] = area_edge_values[nm];
+	    qlm[1] = discharge_edge_values[nm];
+	    qlm[2] = bed_edge_values[nm];
+	    qlm[3] = height_edge_values[nm];
+	    qlm[4] = velocity_edge_values[nm];
+            qlm[5] = width_edge_values[nm];
+    }
+	    qlp[0] = area_edge_values[ki];
+	    qlp[1] = discharge_edge_values[ki];
+	    qlp[2] = bed_edge_values[ki];
+	    qlp[3] = height_edge_values[ki];
+	    qlp[4] = velocity_edge_values[ki];
+            qlp[5] = width_edge_values[ki];
+
+         ki = k*2+1;
+           
+
+         n = neighbours[ki];
+	    if (n<0) {
+		m = -n-1;
+            qrp[0] = area_boundary_values[m];
+	    qrp[1] = discharge_boundary_values[m];
+	    qrp[2] = bed_boundary_values[m];
+	    qrp[3] = height_boundary_values[m];
+	    qrp[4] = velocity_boundary_values[m];
+            qrp[5] = width_boundary_values[m];
+          
+
+
+	    }else{
+	m = neighbour_vertices[ki];
+		nm = n*2+m;
+	    
+           
+            qrp[0] = area_edge_values[nm];
+	    qrp[1] = discharge_edge_values[nm];
+	    qrp[2] = bed_edge_values[nm];
+	    qrp[3] = height_edge_values[nm];
+	    qrp[4] = velocity_edge_values[nm];
+            qrp[5] = width_edge_values[nm];
+            }
+            qrm[0] = area_edge_values[ki];
+	    qrm[1] = discharge_edge_values[ki];
+	    qrm[2] = bed_edge_values[ki];
+	    qrm[3] = height_edge_values[ki];
+	    qrm[4] = velocity_edge_values[ki];
+            qrm[5] = width_edge_values[ki];
+
+             _flux_function_channel(qlm,qlp,qrm,qrp,g,epsilon,h0,edgeflux,&max_speed);
+	    flux[0] -= edgeflux[0];
+	    flux[1] -= edgeflux[1];
+           
+	    // Update timestep based on edge i and possibly neighbour n
+	    if (max_speed > epsilon) {
+		// Original CFL calculation
+
+		timestep = min(timestep, 0.5*cfl*areas[k]/max_speed);
+		if (n>=0) {
+		    timestep = min(timestep, 0.5*cfl*areas[n]/max_speed);
+		}
+	    }
+	 // End edge i (and neighbour n)
+	flux[0] /= areas[k];
+	area_explicit_update[k] = flux[0];
+	flux[1] /= areas[k];
+	discharge_explicit_update[k] = flux[1];
+	//Keep track of maximal speeds
+	max_speed_array[k]=max_speed;
+    }
+    return timestep;
+
+}
+
+
+//-------------------------------------------------------------
+// Old code
+//------------------------------------------------------------
+//Innermost flux function (using w=z+h)
+
+
+
+
+
+// Computational function for flux computation
+
+
+//=========================================================================
+// Python Glue
+//=========================================================================
+
+
+
+//------------------------------------------------
+// New velocity based compute fluxes
+//------------------------------------------------
+
+PyObject *compute_fluxes_channel_ext(PyObject *self, PyObject *args) {
+
+    PyObject
+	*domain,
+	*area,
+	*discharge,
+	*bed,
+	*height,
+	*velocity,
+        *width;
+
+    PyArrayObject
+	*neighbours,
+	*neighbour_vertices,
+	*normals,
+	*areas,
+	*area_vertex_values,
+	*discharge_vertex_values,
+	*bed_vertex_values,
+	*height_vertex_values,
+	*velocity_vertex_values,
+	*width_vertex_values,
+	*area_boundary_values,
+	*discharge_boundary_values,
+	*bed_boundary_values,
+	*height_boundary_values,
+	*velocity_boundary_values,
+	*width_boundary_values,
+	*area_explicit_update,
+	*discharge_explicit_update,
+	*max_speed_array;
+
+  double timestep, epsilon, g, h0, cfl;
+  int number_of_elements;
+
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "dOOOOOOO",
+			&timestep,
+			&domain,
+			&area,
+			&discharge,
+			&bed,
+			&height,
+			&velocity,
+                        &width)) {
+      PyErr_SetString(PyExc_RuntimeError, "comp_flux_channel_ext.c: compute_fluxes_channel_ext could not parse input");
+      return NULL;
+  }
+
+
+    epsilon           = get_python_double(domain,"epsilon");
+    g                 = get_python_double(domain,"g");
+    h0                = get_python_double(domain,"h0");
+    cfl               = get_python_double(domain,"CFL");
+
+
+    neighbours        = get_consecutive_array(domain, "neighbours");
+    neighbour_vertices= get_consecutive_array(domain, "neighbour_vertices");
+    normals           = get_consecutive_array(domain, "normals");
+    areas             = get_consecutive_array(domain, "areas");
+    max_speed_array   = get_consecutive_array(domain, "max_speed_array");
+
+    area_vertex_values      = get_consecutive_array(area,    "vertex_values");
+    discharge_vertex_values       = get_consecutive_array(discharge,     "vertex_values");
+    bed_vertex_values        = get_consecutive_array(bed,      "vertex_values");
+    height_vertex_values     = get_consecutive_array(height,   "vertex_values");
+    velocity_vertex_values   = get_consecutive_array(velocity, "vertex_values");
+    width_vertex_values      = get_consecutive_array(width, "vertex_values");
+
+    area_boundary_values     = get_consecutive_array(area,     "boundary_values");
+    discharge_boundary_values      = get_consecutive_array(discharge,      "boundary_values");
+    bed_boundary_values       = get_consecutive_array(bed,       "boundary_values");
+    height_boundary_values    = get_consecutive_array(height,    "boundary_values");
+    velocity_boundary_values  = get_consecutive_array(velocity,  "boundary_values");
+    width_boundary_values       = get_consecutive_array(width,     "boundary_values");
+
+
+    area_explicit_update = get_consecutive_array(area, "explicit_update");
+    discharge_explicit_update  = get_consecutive_array(discharge,  "explicit_update");
+
+    number_of_elements = area_vertex_values -> dimensions[0];
+
+    // Call underlying flux computation routine and update
+    // the explicit update arrays
+    timestep = _compute_fluxes_channel_ext(cfl,
+				       timestep,
+				       epsilon,
+				       g,
+				       h0,
+				       (long*) neighbours -> data,
+				       (long*) neighbour_vertices -> data,
+				       (double*) normals -> data,
+				       (double*) areas -> data,
+				       (double*) area_vertex_values -> data,
+				       (double*) discharge_vertex_values -> data,
+				       (double*) bed_vertex_values -> data,
+				       (double*) height_vertex_values -> data,
+				       (double*) velocity_vertex_values -> data,
+				       (double*) width_vertex_values -> data,
+				       (double*) area_boundary_values -> data,
+				       (double*) discharge_boundary_values -> data,
+				       (double*) bed_boundary_values -> data,
+				       (double*) height_boundary_values -> data,
+				       (double*) velocity_boundary_values -> data,
+				       (double*) width_boundary_values -> data,
+				       (double*) area_explicit_update -> data,
+				       (double*) discharge_explicit_update -> data,
+				       number_of_elements,
+				       (double*) max_speed_array -> data);
+
+
+    Py_DECREF(neighbours);
+    Py_DECREF(neighbour_vertices);
+    Py_DECREF(normals);
+    Py_DECREF(areas);
+    Py_DECREF(area_vertex_values);
+    Py_DECREF(discharge_vertex_values);
+    Py_DECREF(bed_vertex_values);
+    Py_DECREF(height_vertex_values);
+    Py_DECREF(velocity_vertex_values);
+    Py_DECREF(width_vertex_values);
+    Py_DECREF(area_boundary_values);
+    Py_DECREF(discharge_boundary_values);
+    Py_DECREF(bed_boundary_values);
+    Py_DECREF(height_boundary_values);
+    Py_DECREF(velocity_boundary_values);
+    Py_DECREF(width_boundary_values);
+    Py_DECREF(area_explicit_update);
+    Py_DECREF(discharge_explicit_update);
+    Py_DECREF(max_speed_array);
+
+
+    // Return updated flux timestep
+    return Py_BuildValue("d", timestep);
+}
+
+
+//-------------------------------
+// Method table for python module
+//-------------------------------
+
+static struct PyMethodDef MethodTable[] = {
+  {"compute_fluxes_channel_ext", compute_fluxes_channel_ext, METH_VARARGS, "Print out"},
+  {NULL}
+};
+
+/* // Module initialisation */
+/* void initcomp_flux_vel_ext(void){ */
+/*   Py_InitModule("comp_flux_vel_ext", MethodTable); */
+/*   import_array(); */
+/* } */
+
+void initchannel_domain_ext(void){
+  Py_InitModule("channel_domain_ext", MethodTable);
+  import_array();
+}
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_ext.c
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_ext.c	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_ext.c	(revision 7576)
@@ -0,0 +1,417 @@
+#include "Python.h"
+#include "Numeric/arrayobject.h"
+#include "math.h"
+#include <stdio.h>
+const double pi = 3.14159265358979;
+
+
+// Shared code snippets
+#include "util_ext.h"
+
+
+/* double max(double a, double b) { */
+/* 	double z; */
+/* 	z=(a>b)?a:b; */
+/* 	return z;} */
+	
+/* double min(double a, double b) { */
+/* 	double z; */
+/* 	z=(a<b)?a:b; */
+/* 	return z;} */
+
+
+// Function to obtain speed from momentum and depth.
+// This is used by flux functions
+// Input parameters uh and h may be modified by this function.
+double _compute_speed(double *uh, 
+		      double *h, 
+		      double epsilon, 
+		      double h0) {
+  
+  double u;
+  
+  if (*h < epsilon) {
+    *h = 0.0;  //Could have been negative
+     u = 0.0;
+  } else {
+    u = *uh/(*h + h0/ *h);    
+  }
+  
+
+  // Adjust momentum to be consistent with speed
+  *uh = u * *h;
+  
+  return u;
+}
+
+
+
+
+//Innermost flux function (using w=z+h)
+int _flux_function(double *q_left, double *q_right,
+        double z_left, double z_right,
+		   double normals, double g, double epsilon, double h0,
+		double *edgeflux, double *max_speed) {
+		
+		int i;
+		double ql[2], qr[2], flux_left[2], flux_right[2];
+		double z, w_left, h_left, uh_left, soundspeed_left, u_left;
+		double w_right, h_right, uh_right, soundspeed_right, u_right;
+		double s_max, s_min, denom;
+		
+		//printf("h0 = %f \n",h0);
+		ql[0] = q_left[0];
+		ql[1] = q_left[1];
+		ql[1] = ql[1]*normals;
+	
+		qr[0] = q_right[0];
+		qr[1] = q_right[1];
+		qr[1] = qr[1]*normals;
+	  
+		z = (z_left+z_right)/2.0;		   
+				   
+		//w_left = ql[0];
+		//h_left = w_left-z;
+		//uh_left = ql[1];
+		
+
+
+		// Compute speeds in x-direction
+		w_left = ql[0];          
+		h_left = w_left-z;
+		uh_left = ql[1];
+
+		u_left = _compute_speed(&uh_left, &h_left, epsilon, h0);
+
+		w_right = qr[0];
+		h_right = w_right-z;
+		uh_right = qr[1];
+
+		u_right = _compute_speed(&uh_right, &h_right, epsilon, h0);
+  
+		soundspeed_left = sqrt(g*h_left);
+		soundspeed_right = sqrt(g*h_right);
+		
+		s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
+		if (s_max < 0.0) s_max = 0.0;
+	
+		s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
+		if (s_min > 0.0) s_min = 0.0;
+		
+		
+		// Flux formulas
+		flux_left[0] = u_left*h_left;
+		flux_left[1] = u_left*uh_left + 0.5*g*h_left*h_left;
+
+		flux_right[0] = u_right*h_right;
+		flux_right[1] = u_right*uh_right + 0.5*g*h_right*h_right;
+
+		// Flux computation
+		denom = s_max-s_min;
+		if (denom < epsilon) {
+			for (i=0; i<2; i++) edgeflux[i] = 0.0;
+			*max_speed = 0.0;
+		} else {
+			edgeflux[0] = s_max*flux_left[0] - s_min*flux_right[0];
+			edgeflux[0] += s_max*s_min*(qr[0]-ql[0]);
+			edgeflux[0] /= denom;
+			edgeflux[1] = s_max*flux_left[1] - s_min*flux_right[1];
+			edgeflux[1] += s_max*s_min*(qr[1]-ql[1]);
+			edgeflux[1] /= denom;
+			edgeflux[1] *= normals;
+    
+		// Maximal wavespeed
+        *max_speed = max(fabs(s_max), fabs(s_min));
+		}  
+    return 0;		
+	}
+		
+		
+	
+	
+// Computational function for flux computation
+double _compute_fluxes_ext(
+			   double cfl,
+			   double timestep,
+			   double epsilon,
+			   double g,
+			   double h0,
+			   long* neighbours,
+			   long* neighbour_vertices,
+			   double* normals,
+			   double* areas,
+			   double* stage_edge_values,
+			   double* xmom_edge_values,
+			   double* bed_edge_values,
+			   double* stage_boundary_values,
+			   double* xmom_boundary_values,
+			   double* stage_explicit_update,
+			   double* xmom_explicit_update,
+			   int number_of_elements,
+			   double* max_speed_array) {
+		
+                double flux[2], ql[2], qr[2], edgeflux[2];
+		double zl, zr, max_speed, normal;
+		int k, i, ki, n, m, nm=0;
+		
+		
+		for (k=0; k<number_of_elements; k++) {
+			flux[0] = 0.0;
+			flux[1] = 0.0;
+			
+			for (i=0; i<2; i++) {
+				ki = k*2+i;
+				
+				ql[0] = stage_edge_values[ki];
+				ql[1] = xmom_edge_values[ki];
+				zl = bed_edge_values[ki];
+				
+				n = neighbours[ki];
+				if (n<0) {
+					m = -n-1;
+					qr[0] = stage_boundary_values[m];
+					qr[1] = xmom_boundary_values[m];
+					zr = zl;
+				} else {
+					m = neighbour_vertices[ki];
+					nm = n*2+m;
+					qr[0] = stage_edge_values[nm];
+					qr[1] = xmom_edge_values[nm];
+					zr = bed_edge_values[nm];				
+				}
+				
+				normal = normals[ki];
+				_flux_function(ql, qr, zl, zr, normal, g, epsilon, h0, edgeflux, &max_speed);
+				flux[0] -= edgeflux[0];
+				flux[1] -= edgeflux[1];
+				
+				// Update timestep based on edge i and possibly neighbour n
+				if (max_speed > epsilon) {
+				    // Original CFL calculation
+				    
+				    timestep = min(timestep, 0.5*cfl*areas[k]/max_speed); 
+				    if (n>=0) {
+					timestep = min(timestep, 0.5*cfl*areas[n]/max_speed); 
+				    }
+				}
+            } // End edge i (and neighbour n)
+			flux[0] /= areas[k];
+			stage_explicit_update[k] = flux[0];
+			flux[1] /= areas[k];
+			xmom_explicit_update[k] = flux[1];
+			
+			//Keep track of maximal speeds
+			max_speed_array[k]=max_speed;
+		}
+		return timestep;	
+	}
+	
+	
+	
+	
+	
+
+
+
+//=========================================================================
+// Python Glue
+//=========================================================================
+PyObject *compute_fluxes_ext(PyObject *self, PyObject *args) {
+  
+    PyArrayObject 
+	*neighbours, 
+	*neighbour_vertices,
+	*normals, 
+	*areas,
+	*stage_edge_values,
+	*xmom_edge_values,
+	*bed_edge_values,
+	*stage_boundary_values,
+	*xmom_boundary_values,
+	*stage_explicit_update,
+	*xmom_explicit_update,
+	*max_speed_array;
+    
+  double timestep, epsilon, g, h0, cfl;
+  int number_of_elements;
+    
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "dddddOOOOOOOOOOOiO",
+			&cfl,
+			&timestep,
+			&epsilon,
+			&g,
+			&h0,
+			&neighbours,
+			&neighbour_vertices,
+			&normals,
+			&areas,
+			&stage_edge_values,
+			&xmom_edge_values,
+			&bed_edge_values,
+			&stage_boundary_values,
+			&xmom_boundary_values,
+			&stage_explicit_update,
+			&xmom_explicit_update,
+			&number_of_elements,
+			&max_speed_array)) {
+    PyErr_SetString(PyExc_RuntimeError, "comp_flux_ext.c: compute_fluxes_ext could not parse input");
+    return NULL;
+  }
+
+ 
+  // Call underlying flux computation routine and update 
+  // the explicit update arrays 
+  timestep = _compute_fluxes_ext(cfl,
+				 timestep,
+				 epsilon,
+				 g,
+				 h0,
+				 (long*) neighbours -> data,
+				 (long*) neighbour_vertices -> data,
+				 (double*) normals -> data,
+				 (double*) areas -> data,
+				 (double*) stage_edge_values -> data,
+				 (double*) xmom_edge_values -> data,
+				 (double*) bed_edge_values -> data,
+				 (double*) stage_boundary_values -> data,
+				 (double*) xmom_boundary_values -> data,
+				 (double*) stage_explicit_update -> data,
+				 (double*) xmom_explicit_update -> data,
+				 number_of_elements,
+				 (double*) max_speed_array -> data);
+
+  // Return updated flux timestep
+  return Py_BuildValue("d", timestep);
+}
+
+
+//-----------------------
+PyObject *compute_fluxes_ext_short(PyObject *self, PyObject *args) {
+  
+   PyObject 
+	*domain,
+	*stage, 
+	*xmom, 
+	*bed;
+
+    PyArrayObject 
+	*neighbours, 
+	*neighbour_vertices,
+	*normals, 
+	*areas,
+	*stage_vertex_values,
+	*xmom_vertex_values,
+	*bed_vertex_values,
+	*stage_boundary_values,
+	*xmom_boundary_values,
+	*stage_explicit_update,
+	*xmom_explicit_update,
+	*max_speed_array;
+    
+  double timestep, epsilon, g, h0, cfl;
+  int number_of_elements;
+
+    
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "dOOOO",
+			&timestep,
+			&domain,
+			&stage,
+			&xmom,
+			&bed)) {
+      PyErr_SetString(PyExc_RuntimeError, "comp_flux_ext.c: compute_fluxes_ext_short could not parse input");
+      return NULL;
+  }
+
+
+    epsilon           = get_python_double(domain,"epsilon");
+    g                 = get_python_double(domain,"g");
+    h0                = get_python_double(domain,"h0");
+    cfl               = get_python_double(domain,"CFL");
+ 
+    
+    neighbours        = get_consecutive_array(domain, "neighbours");
+    neighbour_vertices= get_consecutive_array(domain, "neighbour_vertices"); 
+    normals           = get_consecutive_array(domain, "normals");
+    areas             = get_consecutive_array(domain, "areas");    
+    max_speed_array   = get_consecutive_array(domain, "max_speed_array");
+    
+    stage_vertex_values = get_consecutive_array(stage, "vertex_values");    
+    xmom_vertex_values  = get_consecutive_array(xmom, "vertex_values");    
+    bed_vertex_values   = get_consecutive_array(bed, "vertex_values");    
+
+    stage_boundary_values = get_consecutive_array(stage, "boundary_values");    
+    xmom_boundary_values  = get_consecutive_array(xmom, "boundary_values");    
+
+
+    stage_explicit_update = get_consecutive_array(stage, "explicit_update");    
+    xmom_explicit_update  = get_consecutive_array(xmom, "explicit_update");    
+
+
+
+    number_of_elements = stage_vertex_values -> dimensions[0];
+
+
+ 
+    // Call underlying flux computation routine and update 
+    // the explicit update arrays 
+    timestep = _compute_fluxes_ext(
+	cfl,
+	timestep,
+	epsilon,
+	g,
+	h0,
+	(long*) neighbours -> data,
+	(long*) neighbour_vertices -> data,
+	(double*) normals -> data,
+	(double*) areas -> data,
+	(double*) stage_vertex_values -> data,
+	(double*) xmom_vertex_values -> data,
+	(double*) bed_vertex_values -> data,
+	(double*) stage_boundary_values -> data,
+	(double*) xmom_boundary_values -> data,
+	(double*) stage_explicit_update -> data,
+	(double*) xmom_explicit_update -> data,
+	number_of_elements,
+	(double*) max_speed_array -> data);
+
+
+  Py_DECREF(neighbours);
+  Py_DECREF(neighbour_vertices);
+  Py_DECREF(normals);
+  Py_DECREF(areas);
+  Py_DECREF(stage_vertex_values);
+  Py_DECREF(xmom_vertex_values);
+  Py_DECREF(bed_vertex_values);
+  Py_DECREF(stage_boundary_values);
+  Py_DECREF(xmom_boundary_values);
+  Py_DECREF(stage_explicit_update);
+  Py_DECREF(xmom_explicit_update);
+  Py_DECREF(max_speed_array);
+
+
+
+
+  // Return updated flux timestep
+  return Py_BuildValue("d", timestep);
+}
+
+ 
+
+
+//-------------------------------
+// Method table for python module
+//-------------------------------
+
+static struct PyMethodDef MethodTable[] = {
+  {"compute_fluxes_ext", compute_fluxes_ext, METH_VARARGS, "Print out"},
+  {"compute_fluxes_ext_short", compute_fluxes_ext_short, METH_VARARGS, "Print out"},
+  {NULL, NULL}
+};
+
+// Module initialisation
+void initcomp_flux_ext(void){
+  Py_InitModule("comp_flux_ext", MethodTable);
+  import_array();
+}
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_ext_nonwellbalanced2.c
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_ext_nonwellbalanced2.c	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_ext_nonwellbalanced2.c	(revision 7576)
@@ -0,0 +1,366 @@
+#include "Python.h"
+#include "Numeric/arrayobject.h"
+#include "math.h"
+#include <stdio.h>
+#include "util_ext.h"
+const double pi = 3.14159265358979;
+
+//Innermost flux function (using w=z+h)
+int _flux_function_nonwellbalanced2(double *q_left, 
+								double *q_right,
+								double normals, 
+								double g, 
+								double epsilon,
+								double *edgeflux, 
+								double *max_speed) {		
+		int i;
+        double z_in, z_out;
+		double flux_in[2], flux_out[2];
+		double w_in, h_in, uh_in, soundspeed_in, u_in;
+		double w_out, h_out, uh_out, soundspeed_out, u_out;
+		double s_max, s_min, denom;
+		
+		w_in  = q_left[0];
+		uh_in = q_left[1];
+		uh_in = uh_in*normals;
+        z_in  = q_left[2];
+		h_in  = q_left[3];
+		u_in  = q_left[4];
+		u_in = u_in*normals;
+	
+		w_out  = q_right[0];
+		uh_out = q_right[1];
+		uh_out = uh_out*normals;
+        z_out  = q_right[2];
+		h_out  = q_right[3];
+		u_out  = q_right[4];
+		u_out = u_out*normals;
+		
+		printf("------------------ \n");
+		printf("w_in  = %f \n", w_in);
+		printf("uh_in = %f \n", uh_in);
+		printf("z_in  = %f \n", z_in);
+		printf("h_in  = %f \n", h_in);
+		printf("u_in  = %f \n", u_in);
+		printf("------------------ \n");
+		printf("w_out  = %f \n", w_out);
+		printf("uh_out = %f \n", uh_out);
+		printf("z_out  = %f \n", z_out);
+		printf("h_out  = %f \n", h_out);
+		printf("u_out  = %f \n", u_out);	  
+		//////if (z_left-z_right != 0.0 ) printf("z_l - z_r = %f \n",z_left-z_right);
+		
+        
+		//z_star = max(z_in, z_out);		              											//equation(7)  
+				   
+		// Compute speeds in x-direction.
+		//h_in_star = max(0.0, w_in-z_star);														//equation(8)		
+		//h_out_star = max(0.0, w_out-z_star);													//equation(9)
+  
+		soundspeed_in = sqrt(g*h_in);
+		soundspeed_out = sqrt(g*h_out);
+		
+		s_max = max(u_in+soundspeed_in, u_out+soundspeed_out);
+		if (s_max < 0.0) s_max = 0.0;
+	
+		s_min = min(u_in-soundspeed_in, u_out-soundspeed_out);
+		if (s_min > 0.0) s_min = 0.0;
+		
+		
+		// Flux formulas
+		flux_in[0] = u_in*h_in;
+		flux_in[1] = u_in*u_in*h_in + 0.5*g*h_in*h_in;
+
+		flux_out[0] = u_out*h_out;
+		flux_out[1] = u_out*u_out*h_out + 0.5*g*h_out*h_out;
+
+		// Flux computation
+		denom = s_max-s_min;
+		
+		//printf("Edge Mass Flux = %f \n", edgeflux[0]);
+		//printf("Edge Momentum Flux = %f \n", edgeflux[1]);
+		
+	    if (denom < epsilon && z_out > z_in) {
+			for (i=0; i<2; i++) edgeflux[i] = 0.0;
+			// Maximal wavespeed		
+			//edgeflux[1] = edgeflux[1] + (0.5*g*h_in*h_in - 0.5*g*h_in_star*h_in_star );
+			edgeflux[1] *= normals;
+			*max_speed = 0.0;
+			//printf("Part 1 \n");
+		} else if (denom < epsilon) {
+			for (i=0; i<2; i++) edgeflux[i] = 0.0;
+			// Maximal wavespeed
+			*max_speed = 0.0;		
+			//printf("Part 2 \n");
+		//} else if (w_out < z_in) {
+		//	for (i=0; i<2; i++) edgeflux[i] = 0.0;
+		//	*max_speed = 0.0;
+		} else {
+			edgeflux[0] = s_max*flux_in[0] - s_min*flux_out[0];
+			edgeflux[0] += s_max*s_min*(h_out-h_in);                
+			edgeflux[0] /= denom;
+			edgeflux[1] = s_max*flux_in[1] - s_min*flux_out[1];
+			edgeflux[1] += s_max*s_min*(flux_out[0]-flux_in[0]);               
+			edgeflux[1] /= denom;
+			//edgeflux[1] = edgeflux[1] + (0.5*g*h_in*h_in - 0.5*g*h_in_star*h_in_star);
+			edgeflux[1] *= normals;
+			// Maximal wavespeed
+			*max_speed = max(fabs(s_max), fabs(s_min));
+			//printf("Part 3 \n");
+		}  
+		printf("Edge Mass Flux = %f \n", edgeflux[0]);
+		printf("Edge Momentum Flux = %f \n", edgeflux[1]);
+
+    return 0;		
+	}
+		
+		
+	
+	
+// Computational function for flux computation
+double _compute_fluxes_ext_nonwellbalanced2(double timestep,
+		double epsilon,
+		double g,
+		
+		long* neighbours,
+		long* neighbour_vertices,
+		double* normals,
+		double* areas,
+		
+		double* stage_edge_values,
+		double* xmom_edge_values,
+		double* bed_edge_values,
+		double* height_edge_values,
+		double* vel_edge_values,
+		
+		double* stage_boundary_values,
+		double* xmom_boundary_values,
+		double* bed_boundary_values,
+		double* height_boundary_values,
+		double* vel_boundary_values,
+		
+		double* stage_explicit_update,
+		double* xmom_explicit_update,
+		double* bed_explicit_update,
+		double* height_explicit_update,
+		double* vel_explicit_update,
+		
+		int number_of_elements,
+		double* max_speed_array) {
+		
+		double flux[2], ql[5], qr[5], edgeflux[2];
+		double max_speed, normal;
+		int k, i, ki, n, m, nm=0;
+		
+		for (k=0; k<number_of_elements; k++) {
+			flux[0] = 0.0;
+			flux[1] = 0.0;
+			
+			printf("==================================== \n");
+			printf("==================================== \n");
+			printf("cell_number = %i \n",k);
+			
+			for (i=0; i<2; i++) {
+				
+				printf("......................... \n");
+				printf("interface = %i \n",i);
+				
+				ki = k*2+i;
+				
+				ql[0] = stage_edge_values[ki];
+				ql[1] = xmom_edge_values[ki];
+				ql[2] = bed_edge_values[ki];
+                ql[3] = height_edge_values[ki];
+				ql[4] = vel_edge_values[ki];
+                
+				n = neighbours[ki];
+				//printf("neighbours[ki] = %li \n",neighbours[ki]);
+				if (n<0) {
+					m = -n-1;
+					qr[0] = stage_boundary_values[m];
+					qr[1] = xmom_boundary_values[m];
+					qr[2] = ql[2];																			
+					qr[3] = height_edge_values[m]; 														
+					qr[4] = vel_edge_values[m];																
+                    
+				} else {
+					m = neighbour_vertices[ki];
+					nm = n*2+m;
+					qr[0] = stage_edge_values[nm];
+					qr[1] = xmom_edge_values[nm];
+					qr[2] = bed_edge_values[nm];
+					qr[3] = height_edge_values[nm];															
+					qr[4] = vel_edge_values[nm];															
+				}
+				
+				//Added condition!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+				//if (qr[0] < ql[2]) {
+				//ql[4] = 0.0;
+				//vel_edge_values[ki] = 0.0;
+				//}				
+				//if (qr[2] > ql[2]) {
+				//ql[1] = 0.0;
+				//ql[4] = 0.0;
+				//}
+				
+				normal = normals[ki];
+				_flux_function_nonwellbalanced2(ql, qr, normal, g, epsilon, edgeflux, &max_speed);
+				flux[0] -= edgeflux[0];
+				flux[1] -= edgeflux[1];
+				
+				// Update timestep based on edge i and possibly neighbour n
+				if (max_speed > epsilon) {
+	                // Original CFL calculation
+					timestep = min(timestep, 0.5*areas[k]/max_speed); //Here, CFL=1.0 is assumed.
+					if (n>=0) {
+						timestep = min(timestep, 0.5*areas[n]/max_speed); //Here, CFL=1.0 is assumed. 
+					}
+				}
+            } // End edge i (and neighbour n)
+			flux[0] /= areas[k];
+			stage_explicit_update[k] = flux[0];
+			flux[1] /= areas[k];
+			xmom_explicit_update[k] = flux[1];
+			
+			printf("......................... \n");
+			printf("areas = %f \n", areas[k]);
+			printf("Mass Flux in this cell = %f \n",flux[0]);
+			printf("Momentum Flux in this cell = %f \n",flux[1]);
+			//printf("stage_explicit_update in this cell = %f \n",stage_explicit_update[k]);
+			//printf("xmom_explicit_update in this cell = %f \n",xmom_explicit_update[k]);
+			
+			
+			//Keep track of maximal speeds
+			max_speed_array[k]=max_speed;
+		}
+		
+		return timestep;	
+	}
+	
+	
+	
+
+
+
+//=========================================================================
+// Python Glue
+//=========================================================================
+PyObject *compute_fluxes_ext_nonwellbalanced2(PyObject *self, PyObject *args) {
+  
+    PyArrayObject 
+	*neighbours, 
+	*neighbour_vertices,
+	*normals, 
+	*areas,
+	
+	*stage_edge_values,
+	*xmom_edge_values,
+	*bed_edge_values,
+	*height_edge_values,
+	*vel_edge_values,
+	
+	*stage_boundary_values,
+	*xmom_boundary_values,
+	*bed_boundary_values,
+	*height_boundary_values,
+	*vel_boundary_values,
+	
+	*stage_explicit_update,
+	*xmom_explicit_update,
+	*bed_explicit_update,
+	*height_explicit_update,
+	*vel_explicit_update,
+	
+	*max_speed_array;
+    
+  double timestep, epsilon, g;
+  int number_of_elements;
+    
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOOOOOOOOOiO",
+			&timestep,
+			&epsilon,
+			&g,
+			
+			&neighbours,
+			&neighbour_vertices,
+			&normals,
+			&areas,
+			
+			&stage_edge_values,
+			&xmom_edge_values,
+			&bed_edge_values,
+			&height_edge_values,
+			&vel_edge_values,
+			
+			&stage_boundary_values,
+			&xmom_boundary_values,
+			&bed_boundary_values,
+			&height_boundary_values,
+			&vel_boundary_values,
+			
+			&stage_explicit_update,
+			&xmom_explicit_update,
+			&bed_explicit_update,
+			&height_explicit_update,
+			&vel_explicit_update,
+			
+			&number_of_elements,
+			&max_speed_array)) {
+    PyErr_SetString(PyExc_RuntimeError, "comp_flux_ext_nonwellbalanced2.c: compute_fluxes_ext_nonwellbalanced2 could not parse input");
+    return NULL;
+  }
+
+ 
+  // Call underlying flux computation routine and update 
+  // the explicit update arrays 
+  timestep = _compute_fluxes_ext_nonwellbalanced2(timestep,
+				 epsilon,
+				 g,
+				 
+				 (long*) neighbours -> data,
+				 (long*) neighbour_vertices -> data,
+				 (double*) normals -> data,
+				 (double*) areas -> data,
+				 
+				 (double*) stage_edge_values -> data,
+				 (double*) xmom_edge_values -> data,
+				 (double*) bed_edge_values -> data,
+				 (double*) height_edge_values -> data,
+				 (double*) vel_edge_values -> data,
+				 
+				 (double*) stage_boundary_values -> data,
+				 (double*) xmom_boundary_values -> data,
+				 (double*) bed_boundary_values -> data,
+				 (double*) height_boundary_values -> data,
+				 (double*) vel_boundary_values -> data,
+				 
+				 (double*) stage_explicit_update -> data,
+				 (double*) xmom_explicit_update -> data,
+				 (double*) bed_explicit_update -> data,
+				 (double*) height_explicit_update -> data,
+				 (double*) vel_explicit_update -> data,
+				 
+				 number_of_elements,
+				 (double*) max_speed_array -> data);
+
+  // Return updated flux timestep
+  return Py_BuildValue("d", timestep);
+}
+
+
+
+//-------------------------------
+// Method table for python module
+//-------------------------------
+
+static struct PyMethodDef MethodTable[] = {
+  {"compute_fluxes_ext_nonwellbalanced2", compute_fluxes_ext_nonwellbalanced2, METH_VARARGS, "Print out"},
+  {NULL, NULL}
+};
+
+// Module initialisation
+void initcomp_flux_ext_nonwellbalanced2(void){
+  Py_InitModule("comp_flux_ext_nonwellbalanced2", MethodTable);
+  import_array();
+}
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_ext_nonwellbalanced3.c
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_ext_nonwellbalanced3.c	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_ext_nonwellbalanced3.c	(revision 7576)
@@ -0,0 +1,367 @@
+#include "Python.h"
+#include "Numeric/arrayobject.h"
+#include "math.h"
+#include <stdio.h>
+#include "util_ext.h"
+const double pi = 3.14159265358979;
+
+//Innermost flux function (using w=z+h)
+int _flux_function_nonwellbalanced3(double *q_left, 
+								double *q_right,
+								double normals, 
+								double g, 
+								double epsilon,
+								double *edgeflux, 
+								double *max_speed) {		
+		int i;
+        double z_in, z_out;
+		double flux_in[2], flux_out[2];
+		double w_in, h_in, uh_in, soundspeed_in, u_in;
+		double w_out, h_out, uh_out, soundspeed_out, u_out;
+		double s_max, s_min, denom;
+		
+		w_in  = q_left[0];
+		uh_in = q_left[1];
+		uh_in = uh_in*normals;
+        z_in  = q_left[2];
+		h_in  = q_left[3];
+		u_in  = q_left[4];
+		u_in = u_in*normals;
+	
+		w_out  = q_right[0];
+		uh_out = q_right[1];
+		uh_out = uh_out*normals;
+        z_out  = q_right[2];
+		h_out  = q_right[3];
+		u_out  = q_right[4];
+		u_out = u_out*normals;
+		
+		printf("------------------ \n");
+		printf("w_in  = %f \n", w_in);
+		printf("uh_in = %f \n", uh_in);
+		printf("z_in  = %f \n", z_in);
+		printf("h_in  = %f \n", h_in);
+		printf("u_in  = %f \n", u_in);
+		printf("------------------ \n");
+		printf("w_out  = %f \n", w_out);
+		printf("uh_out = %f \n", uh_out);
+		printf("z_out  = %f \n", z_out);
+		printf("h_out  = %f \n", h_out);
+		printf("u_out  = %f \n", u_out);	  
+		//////if (z_left-z_right != 0.0 ) printf("z_l - z_r = %f \n",z_left-z_right);
+		
+        
+		//z_star = max(z_in, z_out);		              											//equation(7)  
+				   
+		// Compute speeds in x-direction.
+		//h_in_star = max(0.0, w_in-z_star);														//equation(8)		
+		//h_out_star = max(0.0, w_out-z_star);													//equation(9)
+
+		//printf("u_left = %g u_right = %g \n",u_left, u_right);
+		soundspeed_in = sqrt(g*h_in);
+		soundspeed_out = sqrt(g*h_out);
+		
+		s_max = max(u_in+soundspeed_in, u_out+soundspeed_out);
+		if (s_max < 0.0) s_max = 0.0;
+	
+		s_min = min(u_in-soundspeed_in, u_out-soundspeed_out);
+		if (s_min > 0.0) s_min = 0.0;
+		
+		
+		// Flux formulas
+		flux_in[0] = u_in*h_in;
+		flux_in[1] = u_in*u_in*h_in + 0.5*g*h_in*h_in;
+
+		flux_out[0] = u_out*h_out;
+		flux_out[1] = u_out*u_out*h_out + 0.5*g*h_out*h_out;
+
+		// Flux computation
+		denom = s_max-s_min;
+		
+		//printf("Edge Mass Flux = %f \n", edgeflux[0]);
+		//printf("Edge Momentum Flux = %f \n", edgeflux[1]);
+		
+	    if (denom < epsilon && z_out > z_in) {
+			for (i=0; i<2; i++) edgeflux[i] = 0.0;
+			// Maximal wavespeed		
+			//edgeflux[1] = edgeflux[1] + (0.5*g*h_in*h_in - 0.5*g*h_in_star*h_in_star );
+			edgeflux[1] *= normals;
+			*max_speed = 0.0;
+			//printf("Part 1 \n");
+		} else if (denom < epsilon) {
+			for (i=0; i<2; i++) edgeflux[i] = 0.0;
+			// Maximal wavespeed
+			*max_speed = 0.0;		
+			//printf("Part 2 \n");
+		//} else if (w_out < z_in) {
+		//	for (i=0; i<2; i++) edgeflux[i] = 0.0;
+		//	*max_speed = 0.0;
+		} else {
+			edgeflux[0] = s_max*flux_in[0] - s_min*flux_out[0];
+			edgeflux[0] += s_max*s_min*(h_out-h_in);                
+			edgeflux[0] /= denom;
+			edgeflux[1] = s_max*flux_in[1] - s_min*flux_out[1];
+			edgeflux[1] += s_max*s_min*(flux_out[0]-flux_in[0]);               
+			edgeflux[1] /= denom;
+			//edgeflux[1] = edgeflux[1] + (0.5*g*h_in*h_in - 0.5*g*h_in_star*h_in_star);
+			edgeflux[1] *= normals;
+			// Maximal wavespeed
+			*max_speed = max(fabs(s_max), fabs(s_min));
+			//printf("Part 3 \n");
+		}  
+		printf("Edge Mass Flux = %f \n", edgeflux[0]);
+		printf("Edge Momentum Flux = %f \n", edgeflux[1]);
+
+    return 0;		
+	}
+		
+		
+	
+	
+// Computational function for flux computation
+double _compute_fluxes_ext_nonwellbalanced3(double timestep,
+		double epsilon,
+		double g,
+		
+		long* neighbours,
+		long* neighbour_vertices,
+		double* normals,
+		double* areas,
+		
+		double* stage_edge_values,
+		double* xmom_edge_values,
+		double* bed_edge_values,
+		double* height_edge_values,
+		double* vel_edge_values,
+		
+		double* stage_boundary_values,
+		double* xmom_boundary_values,
+		double* bed_boundary_values,
+		double* height_boundary_values,
+		double* vel_boundary_values,
+		
+		double* stage_explicit_update,
+		double* xmom_explicit_update,
+		double* bed_explicit_update,
+		double* height_explicit_update,
+		double* vel_explicit_update,
+		
+		int number_of_elements,
+		double* max_speed_array) {
+		
+		double flux[2], ql[5], qr[5], edgeflux[2];
+		double max_speed, normal;
+		int k, i, ki, n, m, nm=0;
+		
+		for (k=0; k<number_of_elements; k++) {
+			flux[0] = 0.0;
+			flux[1] = 0.0;
+			
+			printf("==================================== \n");
+			printf("==================================== \n");
+			printf("cell_number = %i \n",k);
+			
+			for (i=0; i<2; i++) {
+				
+				printf("......................... \n");
+				printf("interface = %i \n",i);
+				
+				ki = k*2+i;
+				
+				ql[0] = stage_edge_values[ki];
+				ql[1] = xmom_edge_values[ki];
+				ql[2] = bed_edge_values[ki];
+                ql[3] = height_edge_values[ki];
+				ql[4] = vel_edge_values[ki];
+                
+				n = neighbours[ki];
+				//printf("neighbours[ki] = %li \n",neighbours[ki]);
+				if (n<0) {
+					m = -n-1;
+					qr[0] = stage_boundary_values[m];
+					qr[1] = xmom_boundary_values[m];
+					qr[2] = ql[2];																			
+					qr[3] = height_edge_values[m]; 														
+					qr[4] = vel_edge_values[m];																
+                    
+				} else {
+					m = neighbour_vertices[ki];
+					nm = n*2+m;
+					qr[0] = stage_edge_values[nm];
+					qr[1] = xmom_edge_values[nm];
+					qr[2] = bed_edge_values[nm];
+					qr[3] = height_edge_values[nm];															
+					qr[4] = vel_edge_values[nm];															
+				}
+				
+				//Added condition!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+				//if (qr[0] < ql[2]) {
+				//ql[4] = 0.0;
+				//vel_edge_values[ki] = 0.0;
+				//}				
+				//if (qr[2] > ql[2]) {
+				//ql[1] = 0.0;
+				//ql[4] = 0.0;
+				//}
+				
+				normal = normals[ki];
+				_flux_function_nonwellbalanced3(ql, qr, normal, g, epsilon, edgeflux, &max_speed);
+				flux[0] -= edgeflux[0];
+				flux[1] -= edgeflux[1];
+				
+				// Update timestep based on edge i and possibly neighbour n
+				if (max_speed > epsilon) {
+	                // Original CFL calculation
+					timestep = min(timestep, 0.5*areas[k]/max_speed); //Here, CFL=1.0 is assumed.
+					if (n>=0) {
+						timestep = min(timestep, 0.5*areas[n]/max_speed); //Here, CFL=1.0 is assumed. 
+					}
+				}
+            } // End edge i (and neighbour n)
+			flux[0] /= areas[k];
+			stage_explicit_update[k] = flux[0];
+			flux[1] /= areas[k];
+			xmom_explicit_update[k] = flux[1];
+			
+			printf("......................... \n");
+			printf("areas = %f \n", areas[k]);
+			printf("Mass Flux in this cell = %f \n",flux[0]);
+			printf("Momentum Flux in this cell = %f \n",flux[1]);
+			//printf("stage_explicit_update in this cell = %f \n",stage_explicit_update[k]);
+			//printf("xmom_explicit_update in this cell = %f \n",xmom_explicit_update[k]);
+			
+			
+			//Keep track of maximal speeds
+			max_speed_array[k]=max_speed;
+		}
+		
+		return timestep;	
+	}
+	
+	
+	
+
+
+
+//=========================================================================
+// Python Glue
+//=========================================================================
+PyObject *compute_fluxes_ext_nonwellbalanced3(PyObject *self, PyObject *args) {
+  
+    PyArrayObject 
+	*neighbours, 
+	*neighbour_vertices,
+	*normals, 
+	*areas,
+	
+	*stage_edge_values,
+	*xmom_edge_values,
+	*bed_edge_values,
+	*height_edge_values,
+	*vel_edge_values,
+	
+	*stage_boundary_values,
+	*xmom_boundary_values,
+	*bed_boundary_values,
+	*height_boundary_values,
+	*vel_boundary_values,
+	
+	*stage_explicit_update,
+	*xmom_explicit_update,
+	*bed_explicit_update,
+	*height_explicit_update,
+	*vel_explicit_update,
+	
+	*max_speed_array;
+    
+  double timestep, epsilon, g;
+  int number_of_elements;
+    
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOOOOOOOOOiO",
+			&timestep,
+			&epsilon,
+			&g,
+			
+			&neighbours,
+			&neighbour_vertices,
+			&normals,
+			&areas,
+			
+			&stage_edge_values,
+			&xmom_edge_values,
+			&bed_edge_values,
+			&height_edge_values,
+			&vel_edge_values,
+			
+			&stage_boundary_values,
+			&xmom_boundary_values,
+			&bed_boundary_values,
+			&height_boundary_values,
+			&vel_boundary_values,
+			
+			&stage_explicit_update,
+			&xmom_explicit_update,
+			&bed_explicit_update,
+			&height_explicit_update,
+			&vel_explicit_update,
+			
+			&number_of_elements,
+			&max_speed_array)) {
+    PyErr_SetString(PyExc_RuntimeError, "comp_flux_ext_nonwellbalanced3.c: compute_fluxes_ext_nonwellbalanced3 could not parse input");
+    return NULL;
+  }
+
+ 
+  // Call underlying flux computation routine and update 
+  // the explicit update arrays 
+  timestep = _compute_fluxes_ext_nonwellbalanced3(timestep,
+				 epsilon,
+				 g,
+				 
+				 (long*) neighbours -> data,
+				 (long*) neighbour_vertices -> data,
+				 (double*) normals -> data,
+				 (double*) areas -> data,
+				 
+				 (double*) stage_edge_values -> data,
+				 (double*) xmom_edge_values -> data,
+				 (double*) bed_edge_values -> data,
+				 (double*) height_edge_values -> data,
+				 (double*) vel_edge_values -> data,
+				 
+				 (double*) stage_boundary_values -> data,
+				 (double*) xmom_boundary_values -> data,
+				 (double*) bed_boundary_values -> data,
+				 (double*) height_boundary_values -> data,
+				 (double*) vel_boundary_values -> data,
+				 
+				 (double*) stage_explicit_update -> data,
+				 (double*) xmom_explicit_update -> data,
+				 (double*) bed_explicit_update -> data,
+				 (double*) height_explicit_update -> data,
+				 (double*) vel_explicit_update -> data,
+				 
+				 number_of_elements,
+				 (double*) max_speed_array -> data);
+
+  // Return updated flux timestep
+  return Py_BuildValue("d", timestep);
+}
+
+
+
+//-------------------------------
+// Method table for python module
+//-------------------------------
+
+static struct PyMethodDef MethodTable[] = {
+  {"compute_fluxes_ext_nonwellbalanced3", compute_fluxes_ext_nonwellbalanced3, METH_VARARGS, "Print out"},
+  {NULL, NULL}
+};
+
+// Module initialisation
+void initcomp_flux_ext_nonwellbalanced3(void){
+  Py_InitModule("comp_flux_ext_nonwellbalanced3", MethodTable);
+  import_array();
+}
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_ext_wellbalanced.c
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_ext_wellbalanced.c	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_ext_wellbalanced.c	(revision 7576)
@@ -0,0 +1,385 @@
+#include "Python.h"
+#include "Numeric/arrayobject.h"
+#include "math.h"
+#include <stdio.h>
+#include "util_ext.h"
+const double pi = 3.14159265358979;
+
+//Innermost flux function (using w=z+h)
+int _flux_function_wellbalanced(double *q_left, 
+								double *q_right,
+								double normals, 
+								double g, 
+								double epsilon,
+								double *edgeflux, 
+								double *max_speed) {		
+		int i;
+        double z_in, z_out;
+		double flux_in[2], flux_out[2];
+		double z_star, w_in, h_in, h_in_star, uh_in, soundspeed_in, u_in;
+		double w_out, h_out, h_out_star, uh_out, soundspeed_out, u_out;
+		double s_max, s_min, denom;
+		
+		w_in  = q_left[0];
+		uh_in = q_left[1];
+		uh_in = uh_in*normals;
+        z_in  = q_left[2];
+		h_in  = q_left[3];
+		u_in  = q_left[4];
+		u_in = u_in*normals;
+	
+		w_out  = q_right[0];
+		uh_out = q_right[1];
+		uh_out = uh_out*normals;
+        z_out  = q_right[2];
+		h_out  = q_right[3];
+		u_out  = q_right[4];
+		u_out = u_out*normals;
+		
+		printf("------------------ \n");
+		printf("w_in  = %f \n", w_in);
+		printf("uh_in = %f \n", uh_in);
+		printf("z_in  = %f \n", z_in);
+		printf("h_in  = %f \n", h_in);
+		printf("u_in  = %f \n", u_in);
+		printf("------------------ \n");
+		printf("w_out  = %f \n", w_out);
+		printf("uh_out = %f \n", uh_out);
+		printf("z_out  = %f \n", z_out);
+		printf("h_out  = %f \n", h_out);
+		printf("u_out  = %f \n", u_out);	  
+		//////if (z_left-z_right != 0.0 ) printf("z_l - z_r = %f \n",z_left-z_right);
+		
+        
+		z_star = max(z_in, z_out);		              											//equation(7)  
+				   
+		// Compute speeds in x-direction.
+		h_in_star = max(0.0, w_in-z_star);														//equation(8)
+		
+		//if (h_in_star < epsilon) {
+		//	u_in = 0.0; h_in_star = 0.0;
+		//}
+		//else {
+		//	u_in = uh_in/h_in_star;
+		//}
+		//if (h_in_star < epsilon) {
+		//h_in_star = 0.0;
+		//}
+		
+		h_out_star = max(0.0, w_out-z_star);													//equation(9)
+
+		//if (h_out_star < epsilon) {
+		//	u_out = 0.0; h_out_star = 0.0; 
+		//}
+		//else {
+		//	u_out = uh_out/h_out_star;
+		//}
+  
+		//printf("u_left = %g u_right = %g \n",u_left, u_right);
+		soundspeed_in = sqrt(g*h_in_star);
+		soundspeed_out = sqrt(g*h_out_star);
+		
+		s_max = max(u_in+soundspeed_in, u_out+soundspeed_out);
+		if (s_max < 0.0) s_max = 0.0;
+	
+		s_min = min(u_in-soundspeed_in, u_out-soundspeed_out);
+		if (s_min > 0.0) s_min = 0.0;
+		
+		
+		// Flux formulas
+		flux_in[0] = u_in*h_in_star;
+		flux_in[1] = u_in*u_in*h_in_star + 0.5*g*h_in_star*h_in_star;
+
+		flux_out[0] = u_out*h_out_star;
+		flux_out[1] = u_out*u_out*h_out_star + 0.5*g*h_out_star*h_out_star;
+
+		// Flux computation
+		denom = s_max-s_min;
+		
+		//printf("Edge Mass Flux = %f \n", edgeflux[0]);
+		//printf("Edge Momentum Flux = %f \n", edgeflux[1]);
+		
+	    if (denom < epsilon && z_out > z_in) {
+			for (i=0; i<2; i++) edgeflux[i] = 0.0;
+			// Maximal wavespeed		
+			edgeflux[1] = edgeflux[1] + (0.5*g*h_in*h_in - 0.5*g*h_in_star*h_in_star );
+			edgeflux[1] *= normals;
+			*max_speed = 0.0;
+			//printf("Part 1 \n");
+		} else if (denom < epsilon) {
+			for (i=0; i<2; i++) edgeflux[i] = 0.0;
+			// Maximal wavespeed
+			*max_speed = 0.0;		
+			//printf("Part 2 \n");
+		//} else if (w_out < z_in) {
+		//	for (i=0; i<2; i++) edgeflux[i] = 0.0;
+		//	*max_speed = 0.0;
+		} else {
+			edgeflux[0] = s_max*flux_in[0] - s_min*flux_out[0];
+			edgeflux[0] += s_max*s_min*(h_out_star-h_in_star);                
+			edgeflux[0] /= denom;
+			edgeflux[1] = s_max*flux_in[1] - s_min*flux_out[1];
+			edgeflux[1] += s_max*s_min*(flux_out[0]-flux_in[0]);               
+			edgeflux[1] /= denom;
+			edgeflux[1] = edgeflux[1] + (0.5*g*h_in*h_in - 0.5*g*h_in_star*h_in_star);
+			edgeflux[1] *= normals;
+			// Maximal wavespeed
+			*max_speed = max(fabs(s_max), fabs(s_min));
+			//printf("Part 3 \n");
+		}  
+		printf("Edge Mass Flux = %f \n", edgeflux[0]);
+		printf("Edge Momentum Flux = %f \n", edgeflux[1]);
+
+    return 0;		
+	}
+		
+		
+	
+	
+// Computational function for flux computation
+double _compute_fluxes_ext_wellbalanced(double timestep,
+		double epsilon,
+		double g,
+		
+		long* neighbours,
+		long* neighbour_vertices,
+		double* normals,
+		double* areas,
+		
+		double* stage_edge_values,
+		double* xmom_edge_values,
+		double* bed_edge_values,
+		double* height_edge_values,
+		double* vel_edge_values,
+		
+		double* stage_boundary_values,
+		double* xmom_boundary_values,
+		double* bed_boundary_values,
+		double* height_boundary_values,
+		double* vel_boundary_values,
+		
+		double* stage_explicit_update,
+		double* xmom_explicit_update,
+		double* bed_explicit_update,
+		double* height_explicit_update,
+		double* vel_explicit_update,
+		
+		int number_of_elements,
+		double* max_speed_array) {
+		
+		double flux[2], ql[5], qr[5], edgeflux[2];
+		double max_speed, normal;
+		int k, i, ki, n, m, nm=0;
+		
+		for (k=0; k<number_of_elements; k++) {
+			flux[0] = 0.0;
+			flux[1] = 0.0;
+			
+			printf("==================================== \n");
+			printf("==================================== \n");
+			printf("cell_number = %i \n",k);
+			
+			for (i=0; i<2; i++) {
+				
+				printf("......................... \n");
+				printf("interface = %i \n",i);
+				
+				ki = k*2+i;
+				
+				ql[0] = stage_edge_values[ki];
+				ql[1] = xmom_edge_values[ki];
+				ql[2] = bed_edge_values[ki];
+                ql[3] = height_edge_values[ki];
+				ql[4] = vel_edge_values[ki];
+                
+				n = neighbours[ki];
+				//printf("neighbours[ki] = %li \n",neighbours[ki]);
+				if (n<0) {
+					m = -n-1;
+					qr[0] = stage_boundary_values[m];
+					qr[1] = xmom_boundary_values[m];
+					qr[2] = ql[2];																			
+					qr[3] = height_edge_values[m]; 														
+					qr[4] = vel_edge_values[m];																
+                    
+				} else {
+					m = neighbour_vertices[ki];
+					nm = n*2+m;
+					qr[0] = stage_edge_values[nm];
+					qr[1] = xmom_edge_values[nm];
+					qr[2] = bed_edge_values[nm];
+					qr[3] = height_edge_values[nm];															
+					qr[4] = vel_edge_values[nm];															
+				}
+				
+				//Added condition!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+				//if (qr[0] < ql[2]) {
+				//ql[4] = 0.0;
+				//vel_edge_values[ki] = 0.0;
+				//}				
+				//if (qr[2] > ql[2]) {
+				//ql[1] = 0.0;
+				//ql[4] = 0.0;
+				//}
+				
+				normal = normals[ki];
+				_flux_function_wellbalanced(ql, qr, normal, g, epsilon, edgeflux, &max_speed);
+				flux[0] -= edgeflux[0];
+				flux[1] -= edgeflux[1];
+				
+				// Update timestep based on edge i and possibly neighbour n
+				if (max_speed > epsilon) {
+	                // Original CFL calculation
+					timestep = min(timestep, 0.5*areas[k]/max_speed); //Here, CFL=1.0 is assumed.
+					if (n>=0) {
+						timestep = min(timestep, 0.5*areas[n]/max_speed); //Here, CFL=1.0 is assumed. 
+					}
+				}
+            } // End edge i (and neighbour n)
+			flux[0] /= areas[k];
+			stage_explicit_update[k] = flux[0];
+			flux[1] /= areas[k];
+			xmom_explicit_update[k] = flux[1];
+			
+			printf("......................... \n");
+			printf("areas = %f \n", areas[k]);
+			printf("Mass Flux in this cell = %f \n",flux[0]);
+			printf("Momentum Flux in this cell = %f \n",flux[1]);
+			//printf("stage_explicit_update in this cell = %f \n",stage_explicit_update[k]);
+			//printf("xmom_explicit_update in this cell = %f \n",xmom_explicit_update[k]);
+			
+			
+			//Keep track of maximal speeds
+			max_speed_array[k]=max_speed;
+		}
+		
+		return timestep;	
+	}
+	
+	
+	
+
+
+
+//=========================================================================
+// Python Glue
+//=========================================================================
+PyObject *compute_fluxes_ext_wellbalanced(PyObject *self, PyObject *args) {
+  
+    PyArrayObject 
+	*neighbours, 
+	*neighbour_vertices,
+	*normals, 
+	*areas,
+	
+	*stage_edge_values,
+	*xmom_edge_values,
+	*bed_edge_values,
+	*height_edge_values,
+	*vel_edge_values,
+	
+	*stage_boundary_values,
+	*xmom_boundary_values,
+	*bed_boundary_values,
+	*height_boundary_values,
+	*vel_boundary_values,
+	
+	*stage_explicit_update,
+	*xmom_explicit_update,
+	*bed_explicit_update,
+	*height_explicit_update,
+	*vel_explicit_update,
+	
+	*max_speed_array;
+    
+  double timestep, epsilon, g;
+  int number_of_elements;
+    
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOOOOOOOOOiO",
+			&timestep,
+			&epsilon,
+			&g,
+			
+			&neighbours,
+			&neighbour_vertices,
+			&normals,
+			&areas,
+			
+			&stage_edge_values,
+			&xmom_edge_values,
+			&bed_edge_values,
+			&height_edge_values,
+			&vel_edge_values,
+			
+			&stage_boundary_values,
+			&xmom_boundary_values,
+			&bed_boundary_values,
+			&height_boundary_values,
+			&vel_boundary_values,
+			
+			&stage_explicit_update,
+			&xmom_explicit_update,
+			&bed_explicit_update,
+			&height_explicit_update,
+			&vel_explicit_update,
+			
+			&number_of_elements,
+			&max_speed_array)) {
+    PyErr_SetString(PyExc_RuntimeError, "comp_flux_ext_wellbalanced.c: compute_fluxes_ext_wellbalanced could not parse input");
+    return NULL;
+  }
+
+ 
+  // Call underlying flux computation routine and update 
+  // the explicit update arrays 
+  timestep = _compute_fluxes_ext_wellbalanced(timestep,
+				 epsilon,
+				 g,
+				 
+				 (long*) neighbours -> data,
+				 (long*) neighbour_vertices -> data,
+				 (double*) normals -> data,
+				 (double*) areas -> data,
+				 
+				 (double*) stage_edge_values -> data,
+				 (double*) xmom_edge_values -> data,
+				 (double*) bed_edge_values -> data,
+				 (double*) height_edge_values -> data,
+				 (double*) vel_edge_values -> data,
+				 
+				 (double*) stage_boundary_values -> data,
+				 (double*) xmom_boundary_values -> data,
+				 (double*) bed_boundary_values -> data,
+				 (double*) height_boundary_values -> data,
+				 (double*) vel_boundary_values -> data,
+				 
+				 (double*) stage_explicit_update -> data,
+				 (double*) xmom_explicit_update -> data,
+				 (double*) bed_explicit_update -> data,
+				 (double*) height_explicit_update -> data,
+				 (double*) vel_explicit_update -> data,
+				 
+				 number_of_elements,
+				 (double*) max_speed_array -> data);
+
+  // Return updated flux timestep
+  return Py_BuildValue("d", timestep);
+}
+
+
+
+//-------------------------------
+// Method table for python module
+//-------------------------------
+
+static struct PyMethodDef MethodTable[] = {
+  {"compute_fluxes_ext_wellbalanced", compute_fluxes_ext_wellbalanced, METH_VARARGS, "Print out"},
+  {NULL, NULL}
+};
+
+// Module initialisation
+void initcomp_flux_ext_wellbalanced(void){
+  Py_InitModule("comp_flux_ext_wellbalanced", MethodTable);
+  import_array();
+}
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_ext_wellbalanced.c.bak
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_ext_wellbalanced.c.bak	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_ext_wellbalanced.c.bak	(revision 7576)
@@ -0,0 +1,284 @@
+#include "Python.h"
+#include "Numeric/arrayobject.h"
+#include "math.h"
+#include <stdio.h>
+const double pi = 3.14159265358979;
+
+
+// Shared code snippets
+#include "util_ext.h"
+
+
+//double max(double a, double b) { 
+// 	double z; 
+// 	z=(a>b)?a:b; 
+// 	return z;} 
+	
+//double min(double a, double b) { 
+// 	double z; 
+// 	z=(a<b)?a:b; 
+// 	return z;} 
+
+
+
+
+
+//Innermost flux function (using w=z+h)
+int _flux_function_wellbalanced(double *q_left, double *q_right,
+        double z_left, double z_right,
+		double normals, double g, double epsilon,
+		double *edgeflux, double *max_speed) {
+		
+		int i;
+		double ql[2], qr[2], flux_left[2], flux_right[2];
+		double z_star, w_left, h_left, h_left_star, uh_left, soundspeed_left, u_left;
+		double w_right, h_right, h_right_star, uh_right, soundspeed_right, u_right;                          //h_right,
+		double s_max, s_min, denom;
+		
+		if (z_left-z_right != 0.0 ) printf("z_l - z_r = %f \n",z_left-z_right);
+		ql[0] = q_left[0];
+		ql[1] = q_left[1];
+		ql[1] = ql[1]*normals;
+	
+		qr[0] = q_right[0];
+		qr[1] = q_right[1];
+		qr[1] = qr[1]*normals;
+	  
+		//z = (z_left+z_right)/2.0;
+		z_star = max(z_left, z_right);		              											//equation(7)  
+				   
+		// Compute speeds in x-direction
+		w_left = ql[0];
+		h_left = w_left-z_left;		                                                                //This is used for computing the edgeflux[1].
+		h_left_star = max(0, w_left-z_star);														//(8)
+		uh_left = ql[1];
+		if (h_left_star < epsilon) {
+			u_left = 0.0; h_left_star = 0.0;
+		}
+		else {
+			u_left = uh_left/h_left_star;
+		}
+	
+		w_right = qr[0];
+		h_right = w_right-z_right;                                                                                                                                                                                                     
+		h_right_star = max(0, w_right-z_star);														//(9)
+		uh_right = qr[1];
+		if (h_right_star < epsilon) {
+			u_right = 0.0; h_right_star = 0.0; 
+		}
+		else {
+			u_right = uh_right/h_right_star;
+		}
+  
+		//printf("u_left = %g u_right = %g \n",u_left, u_right);
+		soundspeed_left = sqrt(g*h_left_star);
+		soundspeed_right = sqrt(g*h_right_star);
+		
+		s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
+		if (s_max < 0.0) s_max = 0.0;
+	
+		s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
+		if (s_min > 0.0) s_min = 0.0;
+		
+		
+		// Flux formulas
+		flux_left[0] = u_left*h_left_star;
+		flux_left[1] = u_left*u_left*h_left_star + 0.5*g*h_left_star*h_left_star;
+
+		flux_right[0] = u_right*h_right_star;
+		flux_right[1] = u_right*u_right*h_right_star + 0.5*g*h_right_star*h_right_star;
+
+		// Flux computation
+		denom = s_max-s_min;
+		if (denom < epsilon) {
+			for (i=0; i<2; i++) edgeflux[i] = 0.0;
+			*max_speed = 0.0;
+		} else {
+			edgeflux[0] = s_max*flux_left[0] - s_min*flux_right[0];
+			edgeflux[0] += s_max*s_min*(h_right_star-h_left_star);                   //s_max*s_min*(qr[0]-ql[0]);
+			edgeflux[0] /= denom;
+			edgeflux[1] = s_max*flux_left[1] - s_min*flux_right[1];
+			edgeflux[1] += s_max*s_min*(flux_right[0]-flux_left[0]);                 //s_max*s_min*(qr[1]-ql[1]);
+			edgeflux[1] /= denom;
+			edgeflux[1] *= normals;
+    
+		//edgeflux[1] = edgeflux[1] + 0.5*g*0.5*(h_left+h_right)*0.5*(h_left+h_right) - 0.5*g*h_left_star*h_left_star;
+		//edgeflux[1] = edgeflux[1] + 0.5*g*h_right*h_right - 0.5*g*h_right_star*h_right_star;
+		edgeflux[1] = edgeflux[1] + 0.5*g*h_left*h_left - 0.5*g*h_left_star*h_left_star;           //what about the h_right and h_right_star??????????????????????
+		// Maximal wavespeed
+        *max_speed = max(fabs(s_max), fabs(s_min));
+		}  
+		//printf("max_speed = %g \n",*max_speed);
+    return 0;		
+	}
+		
+		
+	
+	
+// Computational function for flux computation
+double _compute_fluxes_ext_wellbalanced(double timestep,
+		double epsilon,
+		double g,
+		long* neighbours,
+		long* neighbour_vertices,
+		double* normals,
+		double* areas,
+		double* stage_edge_values,
+		double* xmom_edge_values,
+		double* bed_edge_values,
+		double* stage_boundary_values,
+		double* xmom_boundary_values,
+		double* stage_explicit_update,
+		double* xmom_explicit_update,
+		int number_of_elements,
+		double* max_speed_array) {
+		
+		double flux[2], ql[2], qr[2], edgeflux[2];
+		double zl, zr, max_speed, normal;
+		int k, i, ki, n, m, nm=0;
+		
+		for (k=0; k<number_of_elements; k++) {
+			flux[0] = 0.0;
+			flux[1] = 0.0;
+			
+			for (i=0; i<2; i++) {
+				ki = k*2+i;
+				
+				ql[0] = stage_edge_values[ki];
+				ql[1] = xmom_edge_values[ki];
+				zl = bed_edge_values[ki];
+				
+				n = neighbours[ki];
+				if (n<0) {
+					m = -n-1;
+					qr[0] = stage_boundary_values[m];
+					qr[1] = xmom_boundary_values[m];
+					zr = zl;
+				} else {
+					m = neighbour_vertices[ki];
+					nm = n*2+m;
+					qr[0] = stage_edge_values[nm];
+					qr[1] = xmom_edge_values[nm];
+					zr = bed_edge_values[nm];				
+				}
+				
+				normal = normals[ki];
+				_flux_function_wellbalanced(ql, qr, zl, zr, normal, g, epsilon, edgeflux, &max_speed);
+				flux[0] -= edgeflux[0];
+				flux[1] -= edgeflux[1];
+				
+				// Update timestep based on edge i and possibly neighbour n
+				if (max_speed > epsilon) {
+	                // Original CFL calculation
+					
+					timestep = min(timestep, 0.5*areas[k]/max_speed); //Here, CFL=1.0 is assumed. ?????????????????????????????????????????????
+					if (n>=0) {
+						timestep = min(timestep, 0.5*areas[n]/max_speed); //Here, CFL=1.0 is assumed. ?????????????????????????????????????????????
+					}
+				}
+            } // End edge i (and neighbour n)
+			flux[0] /= areas[k];
+			stage_explicit_update[k] = flux[0];
+			flux[1] /= areas[k];
+			xmom_explicit_update[k] = flux[1];
+			
+			//Keep track of maximal speeds
+			max_speed_array[k]=max_speed;
+		}
+		printf("timestep = %f \n",timestep);
+		return timestep;	
+	}
+	
+	
+	
+
+
+
+//=========================================================================
+// Python Glue
+//=========================================================================
+PyObject *compute_fluxes_ext_wellbalanced(PyObject *self, PyObject *args) {
+  
+    PyArrayObject 
+	*neighbours, 
+	*neighbour_vertices,
+	*normals, 
+	*areas,
+	*stage_edge_values,
+	*xmom_edge_values,
+	*bed_edge_values,
+	*stage_boundary_values,
+	*xmom_boundary_values,
+	*stage_explicit_update,
+	*xmom_explicit_update,
+	*max_speed_array;
+    
+  double timestep, epsilon, g;
+  int number_of_elements;
+    
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOiO",
+			&timestep,
+			&epsilon,
+			&g,
+			&neighbours,
+			&neighbour_vertices,
+			&normals,
+			&areas,
+			&stage_edge_values,
+			&xmom_edge_values,
+			&bed_edge_values,
+			&stage_boundary_values,
+			&xmom_boundary_values,
+			&stage_explicit_update,
+			&xmom_explicit_update,
+			&number_of_elements,
+			&max_speed_array)) {
+    PyErr_SetString(PyExc_RuntimeError, "comp_flux_ext.c: compute_fluxes_ext could not parse input");
+    return NULL;
+  }
+
+ 
+  // Call underlying flux computation routine and update 
+  // the explicit update arrays 
+  timestep = _compute_fluxes_ext_wellbalanced(timestep,
+				 epsilon,
+				 g,
+				 (long*) neighbours -> data,
+				 (long*) neighbour_vertices -> data,
+				 (double*) normals -> data,
+				 (double*) areas -> data,
+				 (double*) stage_edge_values -> data,
+				 (double*) xmom_edge_values -> data,
+				 (double*) bed_edge_values -> data,
+				 (double*) stage_boundary_values -> data,
+				 (double*) xmom_boundary_values -> data,
+				 (double*) stage_explicit_update -> data,
+				 (double*) xmom_explicit_update -> data,
+				 number_of_elements,
+				 (double*) max_speed_array -> data);
+
+  // Return updated flux timestep
+  return Py_BuildValue("d", timestep);
+}
+
+
+
+
+
+//-------------------------------
+// Method table for python module
+//-------------------------------
+
+static struct PyMethodDef MethodTable[] = {
+  {"compute_fluxes_ext_wellbalanced", compute_fluxes_ext_wellbalanced, METH_VARARGS, "Print out"},
+  {NULL, NULL}
+};
+
+// Module initialisation
+void initcomp_flux_ext_wellbalanced(void){
+  Py_InitModule("comp_flux_ext_wellbalanced", MethodTable);
+  import_array();
+}
+	
+	
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_vel_ext.c
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_vel_ext.c	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/comp_flux_vel_ext.c	(revision 7576)
@@ -0,0 +1,638 @@
+#include "Python.h"
+#include "Numeric/arrayobject.h"
+#include "math.h"
+#include <stdio.h>
+const double pi = 3.14159265358979;
+
+
+// Shared code snippets
+#include "util_ext.h"
+
+
+/* double max(double a, double b) { */
+/* 	double z; */
+/* 	z=(a>b)?a:b; */
+/* 	return z;} */
+	
+/* double min(double a, double b) { */
+/* 	double z; */
+/* 	z=(a<b)?a:b; */
+/* 	return z;} */
+
+
+// Function to obtain speed from momentum and depth.
+// This is used by flux functions
+// Input parameters uh and h may be modified by this function.
+double _compute_speed(double *uh, 
+		      double *h, 
+		      double epsilon, 
+		      double h0) {
+  
+  double u;
+  
+  if (*h < epsilon) {
+    *h = 0.0;  //Could have been negative
+     u = 0.0;
+  } else {
+    u = *uh/(*h + h0/ *h);    
+  }
+  
+
+  // Adjust momentum to be consistent with speed
+  *uh = u * *h;
+  
+  return u;
+}
+
+//-------------------------------------------------------------
+// New vel based code
+//-------------------------------------------------------------
+//Innermost flux function (using w=z+h)
+int _flux_function_vel(double *q_left, double *q_right,
+		       double normals, double g, double epsilon, double h0,
+		       double *edgeflux, double *max_speed) {
+    
+    int i;
+    double flux_left[2], flux_right[2];
+    double w_left, h_left, uh_left, z_left, u_left, soundspeed_left;
+    double w_right, h_right, uh_right, z_right, u_right, soundspeed_right;
+    double z, s_max, s_min, denom;
+    
+
+    w_left  = q_left[0];
+    uh_left = q_left[1]*normals;
+    z_left  = q_left[2];
+    h_left  = q_left[3];
+    u_left  = q_left[4]*normals;
+
+/*     printf("w_left  = %f \n",w_left); */
+/*     printf("uh_left = %f \n",uh_left); */
+/*     printf("z_left  = %f \n",z_left); */
+/*     printf("h_left  = %f \n",h_left); */
+/*     printf("u_left  = %f \n",u_left); */
+    
+    w_right  = q_right[0];
+    uh_right = q_right[1]*normals;
+    z_right  = q_right[2];
+    h_right  = q_right[3];
+    u_right  = q_right[4]*normals;		
+    
+    z = (z_left+z_right)/2.0;		   
+    
+    soundspeed_left = sqrt(g*h_left);
+    soundspeed_right = sqrt(g*h_right);
+    
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
+    if (s_max < 0.0) s_max = 0.0;
+    
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
+    if (s_min > 0.0) s_min = 0.0;
+    
+    
+    // Flux formulas
+    flux_left[0] = u_left*h_left;
+    flux_left[1] = u_left*u_left*h_left + 0.5*g*h_left*h_left;
+    
+    flux_right[0] = u_right*h_right;
+    flux_right[1] = u_right*u_right*h_right + 0.5*g*h_right*h_right;
+    
+    // Flux computation
+    denom = s_max-s_min;
+    if (denom < epsilon) {
+	for (i=0; i<2; i++) edgeflux[i] = 0.0;
+	*max_speed = 0.0;
+    } else {
+	edgeflux[0] = s_max*flux_left[0] - s_min*flux_right[0];
+	edgeflux[0] += s_max*s_min*(w_right-w_left);
+	edgeflux[0] /= denom;
+	edgeflux[1] = s_max*flux_left[1] - s_min*flux_right[1];
+	edgeflux[1] += s_max*s_min*(uh_right-uh_left);
+	edgeflux[1] /= denom;
+	edgeflux[1] *= normals;
+	
+	// Maximal wavespeed
+	*max_speed = max(fabs(s_max), fabs(s_min));
+    }  
+    return 0;		
+}
+
+// Computational function for flux computation
+double _compute_fluxes_vel_ext(double cfl,
+			       double timestep,
+			       double epsilon,
+			       double g,
+			       double h0,
+			       long* neighbours,
+			       long* neighbour_vertices,
+			       double* normals,
+			       double* areas,
+			       double* stage_edge_values,
+			       double* xmom_edge_values,
+			       double* bed_edge_values,
+			       double* height_edge_values,
+			       double* velocity_edge_values,
+			       double* stage_boundary_values,
+			       double* xmom_boundary_values,
+			       double* bed_boundary_values,
+			       double* height_boundary_values,
+			       double* velocity_boundary_values,
+			       double* stage_explicit_update,
+			       double* xmom_explicit_update,
+			       int number_of_elements,
+			       double* max_speed_array) {
+		
+    double flux[2], ql[5], qr[5], edgeflux[2];
+    double max_speed, normal;
+    int k, i, ki, n, m, nm=0;
+
+    //printf("Inside _comp\n");    
+    
+    for (k=0; k<number_of_elements; k++) {
+	flux[0] = 0.0;
+	flux[1] = 0.0;
+	//printf("k = %d\n",k);
+
+	for (i=0; i<2; i++) {
+	    ki = k*2+i;
+	    
+	    ql[0] = stage_edge_values[ki];
+	    ql[1] = xmom_edge_values[ki];
+	    ql[2] = bed_edge_values[ki];
+	    ql[3] = height_edge_values[ki];
+	    ql[4] = velocity_edge_values[ki];
+	    
+	    n = neighbours[ki];
+	    if (n<0) {
+		m = -n-1;
+		qr[0] = stage_boundary_values[m];
+		qr[1] = xmom_boundary_values[m];
+		qr[2] = bed_boundary_values[m];
+		qr[3] = height_boundary_values[m];
+		qr[4] = velocity_boundary_values[m];
+	    } else {
+		m = neighbour_vertices[ki];
+		nm = n*2+m;
+		qr[0] = stage_edge_values[nm];
+		qr[1] = xmom_edge_values[nm];
+		qr[2] = bed_edge_values[nm];
+		qr[3] = height_edge_values[nm];
+		qr[4] = velocity_edge_values[nm];
+	    }
+	    
+	    normal = normals[ki];
+	    _flux_function_vel(ql, qr, normal, g, epsilon, h0, edgeflux, &max_speed);
+	    flux[0] -= edgeflux[0];
+	    flux[1] -= edgeflux[1];
+	    
+	    // Update timestep based on edge i and possibly neighbour n
+	    if (max_speed > epsilon) {
+		// Original CFL calculation
+		
+		timestep = min(timestep, 0.5*cfl*areas[k]/max_speed); 
+		if (n>=0) {
+		    timestep = min(timestep, 0.5*cfl*areas[n]/max_speed); 
+		}
+	    }
+	} // End edge i (and neighbour n)
+	flux[0] /= areas[k];
+	stage_explicit_update[k] = flux[0];
+	flux[1] /= areas[k];
+	xmom_explicit_update[k] = flux[1];
+	
+	//Keep track of maximal speeds
+	max_speed_array[k]=max_speed;
+    }
+    return timestep;	
+}
+
+//-------------------------------------------------------------
+// Old code
+//------------------------------------------------------------
+//Innermost flux function (using w=z+h)
+int _flux_function(double *q_left, double *q_right,
+        double z_left, double z_right,
+		   double normals, double g, double epsilon, double h0,
+		double *edgeflux, double *max_speed) {
+		
+		int i;
+		double ql[2], qr[2], flux_left[2], flux_right[2];
+		double z, w_left, h_left, uh_left, soundspeed_left, u_left;
+		double w_right, h_right, uh_right, soundspeed_right, u_right;
+		double s_max, s_min, denom;
+		
+		//printf("h0 = %f \n",h0);
+		ql[0] = q_left[0];
+		ql[1] = q_left[1];
+		ql[1] = ql[1]*normals;
+	
+		qr[0] = q_right[0];
+		qr[1] = q_right[1];
+		qr[1] = qr[1]*normals;
+	  
+		z = (z_left+z_right)/2.0;		   
+				   
+		//w_left = ql[0];
+		//h_left = w_left-z;
+		//uh_left = ql[1];
+		
+
+
+		// Compute speeds in x-direction
+		w_left = ql[0];          
+		h_left = w_left-z;
+		uh_left = ql[1];
+
+		u_left = _compute_speed(&uh_left, &h_left, epsilon, h0);
+
+		w_right = qr[0];
+		h_right = w_right-z;
+		uh_right = qr[1];
+
+		u_right = _compute_speed(&uh_right, &h_right, epsilon, h0);
+  
+		soundspeed_left = sqrt(g*h_left);
+		soundspeed_right = sqrt(g*h_right);
+		
+		s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
+		if (s_max < 0.0) s_max = 0.0;
+	
+		s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
+		if (s_min > 0.0) s_min = 0.0;
+		
+		
+		// Flux formulas
+		flux_left[0] = u_left*h_left;
+		flux_left[1] = u_left*uh_left + 0.5*g*h_left*h_left;
+
+		flux_right[0] = u_right*h_right;
+		flux_right[1] = u_right*uh_right + 0.5*g*h_right*h_right;
+
+		// Flux computation
+		denom = s_max-s_min;
+		if (denom < epsilon) {
+			for (i=0; i<2; i++) edgeflux[i] = 0.0;
+			*max_speed = 0.0;
+		} else {
+			edgeflux[0] = s_max*flux_left[0] - s_min*flux_right[0];
+			edgeflux[0] += s_max*s_min*(qr[0]-ql[0]);
+			edgeflux[0] /= denom;
+			edgeflux[1] = s_max*flux_left[1] - s_min*flux_right[1];
+			edgeflux[1] += s_max*s_min*(qr[1]-ql[1]);
+			edgeflux[1] /= denom;
+			edgeflux[1] *= normals;
+    
+		// Maximal wavespeed
+        *max_speed = max(fabs(s_max), fabs(s_min));
+		}  
+    return 0;		
+	}
+		
+		
+	
+	
+// Computational function for flux computation
+double _compute_fluxes_ext(
+			   double cfl,
+			   double timestep,
+			   double epsilon,
+			   double g,
+			   double h0,
+			   long* neighbours,
+			   long* neighbour_vertices,
+			   double* normals,
+			   double* areas,
+			   double* stage_edge_values,
+			   double* xmom_edge_values,
+			   double* bed_edge_values,
+			   double* stage_boundary_values,
+			   double* xmom_boundary_values,
+			   double* stage_explicit_update,
+			   double* xmom_explicit_update,
+			   int number_of_elements,
+			   double* max_speed_array) {
+		
+                double flux[2], ql[2], qr[2], edgeflux[2];
+		double zl, zr, max_speed, normal;
+		int k, i, ki, n, m, nm=0;
+		
+		
+		for (k=0; k<number_of_elements; k++) {
+			flux[0] = 0.0;
+			flux[1] = 0.0;
+			
+			for (i=0; i<2; i++) {
+				ki = k*2+i;
+				
+				ql[0] = stage_edge_values[ki];
+				ql[1] = xmom_edge_values[ki];
+				zl = bed_edge_values[ki];
+				
+				n = neighbours[ki];
+				if (n<0) {
+					m = -n-1;
+					qr[0] = stage_boundary_values[m];
+					qr[1] = xmom_boundary_values[m];
+					zr = zl;
+				} else {
+					m = neighbour_vertices[ki];
+					nm = n*2+m;
+					qr[0] = stage_edge_values[nm];
+					qr[1] = xmom_edge_values[nm];
+					zr = bed_edge_values[nm];				
+				}
+				
+				normal = normals[ki];
+				_flux_function(ql, qr, zl, zr, normal, g, epsilon, h0, edgeflux, &max_speed);
+				flux[0] -= edgeflux[0];
+				flux[1] -= edgeflux[1];
+				
+				// Update timestep based on edge i and possibly neighbour n
+				if (max_speed > epsilon) {
+				    // Original CFL calculation
+				    
+				    timestep = min(timestep, 0.5*cfl*areas[k]/max_speed); 
+				    if (n>=0) {
+					timestep = min(timestep, 0.5*cfl*areas[n]/max_speed); 
+				    }
+				}
+            } // End edge i (and neighbour n)
+			flux[0] /= areas[k];
+			stage_explicit_update[k] = flux[0];
+			flux[1] /= areas[k];
+			xmom_explicit_update[k] = flux[1];
+			
+			//Keep track of maximal speeds
+			max_speed_array[k]=max_speed;
+		}
+		return timestep;	
+	}
+
+//=========================================================================
+// Python Glue
+//=========================================================================
+PyObject *compute_fluxes_ext(PyObject *self, PyObject *args) {
+  
+   PyObject 
+	*domain,
+	*stage, 
+	*xmom, 
+	*bed;
+
+    PyArrayObject 
+	*neighbours, 
+	*neighbour_vertices,
+	*normals, 
+	*areas,
+	*stage_vertex_values,
+	*xmom_vertex_values,
+	*bed_vertex_values,
+	*stage_boundary_values,
+	*xmom_boundary_values,
+	*stage_explicit_update,
+	*xmom_explicit_update,
+	*max_speed_array;
+    
+  double timestep, epsilon, g, h0, cfl;
+  int number_of_elements;
+
+    
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "dOOOO",
+			&timestep,
+			&domain,
+			&stage,
+			&xmom,
+			&bed)) {
+      PyErr_SetString(PyExc_RuntimeError, "comp_flux_vel_ext.c: compute_fluxes_ext could not parse input");
+      return NULL;
+  }
+
+
+    epsilon           = get_python_double(domain,"epsilon");
+    g                 = get_python_double(domain,"g");
+    h0                = get_python_double(domain,"h0");
+    cfl               = get_python_double(domain,"CFL");
+ 
+    
+    neighbours        = get_consecutive_array(domain, "neighbours");
+    neighbour_vertices= get_consecutive_array(domain, "neighbour_vertices"); 
+    normals           = get_consecutive_array(domain, "normals");
+    areas             = get_consecutive_array(domain, "areas");    
+    max_speed_array   = get_consecutive_array(domain, "max_speed_array");
+    
+    stage_vertex_values = get_consecutive_array(stage, "vertex_values");    
+    xmom_vertex_values  = get_consecutive_array(xmom, "vertex_values");    
+    bed_vertex_values   = get_consecutive_array(bed, "vertex_values");    
+
+    stage_boundary_values = get_consecutive_array(stage, "boundary_values");    
+    xmom_boundary_values  = get_consecutive_array(xmom, "boundary_values");    
+
+
+    stage_explicit_update = get_consecutive_array(stage, "explicit_update");    
+    xmom_explicit_update  = get_consecutive_array(xmom, "explicit_update");    
+
+
+
+    number_of_elements = stage_vertex_values -> dimensions[0];
+
+
+ 
+    // Call underlying flux computation routine and update 
+    // the explicit update arrays 
+    timestep = _compute_fluxes_ext(
+	cfl,
+	timestep,
+	epsilon,
+	g,
+	h0,
+	(long*) neighbours -> data,
+	(long*) neighbour_vertices -> data,
+	(double*) normals -> data,
+	(double*) areas -> data,
+	(double*) stage_vertex_values -> data,
+	(double*) xmom_vertex_values -> data,
+	(double*) bed_vertex_values -> data,
+	(double*) stage_boundary_values -> data,
+	(double*) xmom_boundary_values -> data,
+	(double*) stage_explicit_update -> data,
+	(double*) xmom_explicit_update -> data,
+	number_of_elements,
+	(double*) max_speed_array -> data);
+
+
+  Py_DECREF(neighbours);
+  Py_DECREF(neighbour_vertices);
+  Py_DECREF(normals);
+  Py_DECREF(areas);
+  Py_DECREF(stage_vertex_values);
+  Py_DECREF(xmom_vertex_values);
+  Py_DECREF(bed_vertex_values);
+  Py_DECREF(stage_boundary_values);
+  Py_DECREF(xmom_boundary_values);
+  Py_DECREF(stage_explicit_update);
+  Py_DECREF(xmom_explicit_update);
+  Py_DECREF(max_speed_array);
+
+
+
+
+  // Return updated flux timestep
+  return Py_BuildValue("d", timestep);
+}
+
+
+//------------------------------------------------
+// New velocity based compute fluxes
+//------------------------------------------------
+PyObject *compute_fluxes_vel_ext(PyObject *self, PyObject *args) {
+  
+    PyObject 
+	*domain,
+	*stage, 
+	*xmom, 
+	*bed,
+	*height,
+	*velocity;
+
+    PyArrayObject 
+	*neighbours, 
+	*neighbour_vertices,
+	*normals, 
+	*areas,
+	*stage_vertex_values,
+	*xmom_vertex_values,
+	*bed_vertex_values,
+	*height_vertex_values,
+	*velocity_vertex_values,
+	*stage_boundary_values,
+	*xmom_boundary_values,
+	*bed_boundary_values,
+	*height_boundary_values,
+	*velocity_boundary_values,
+	*stage_explicit_update,
+	*xmom_explicit_update,
+	*max_speed_array;
+    
+  double timestep, epsilon, g, h0, cfl;
+  int number_of_elements;
+
+    
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "dOOOOOO",
+			&timestep,
+			&domain,
+			&stage,
+			&xmom,
+			&bed,
+			&height,
+			&velocity)) {
+      PyErr_SetString(PyExc_RuntimeError, "comp_flux_vel_ext.c: compute_fluxes_vel_ext could not parse input");
+      printf("comp_flux_vel_ext.c: compute_fluxes_vel_ext could not parse input");
+      return NULL;
+  }
+
+
+    epsilon           = get_python_double(domain,"epsilon");
+    g                 = get_python_double(domain,"g");
+    h0                = get_python_double(domain,"h0");
+    cfl               = get_python_double(domain,"CFL");
+ 
+    
+    neighbours        = get_consecutive_array(domain, "neighbours");
+    neighbour_vertices= get_consecutive_array(domain, "neighbour_vertices"); 
+    normals           = get_consecutive_array(domain, "normals");
+    areas             = get_consecutive_array(domain, "areas");    
+    max_speed_array   = get_consecutive_array(domain, "max_speed_array");
+    
+    stage_vertex_values      = get_consecutive_array(stage,    "vertex_values");    
+    xmom_vertex_values       = get_consecutive_array(xmom,     "vertex_values");    
+    bed_vertex_values        = get_consecutive_array(bed,      "vertex_values");    
+    height_vertex_values     = get_consecutive_array(height,   "vertex_values");    
+    velocity_vertex_values   = get_consecutive_array(velocity, "vertex_values");    
+
+    stage_boundary_values     = get_consecutive_array(stage,     "boundary_values");    
+    xmom_boundary_values      = get_consecutive_array(xmom,      "boundary_values");    
+    bed_boundary_values       = get_consecutive_array(bed,       "boundary_values");    
+    height_boundary_values    = get_consecutive_array(height,    "boundary_values");    
+    velocity_boundary_values  = get_consecutive_array(velocity,  "boundary_values");    
+
+
+    stage_explicit_update = get_consecutive_array(stage, "explicit_update");    
+    xmom_explicit_update  = get_consecutive_array(xmom,  "explicit_update");    
+
+    number_of_elements = stage_vertex_values -> dimensions[0];
+ 
+
+    //printf("comp_flux_vel 1 N = %d %15.5e %15.5e %15.5e %15.5e %15.5e \n",number_of_elements,cfl,timestep,epsilon,g,h0);
+
+
+
+    // Call underlying flux computation routine and update 
+    // the explicit update arrays 
+    timestep = _compute_fluxes_vel_ext(cfl,
+				       timestep,
+				       epsilon,
+				       g,
+				       h0,
+				       (long*) neighbours -> data,
+				       (long*) neighbour_vertices -> data,
+				       (double*) normals -> data,
+				       (double*) areas -> data,
+				       (double*) stage_vertex_values -> data,
+				       (double*) xmom_vertex_values -> data,
+				       (double*) bed_vertex_values -> data,
+				       (double*) height_vertex_values -> data,
+				       (double*) velocity_vertex_values -> data,
+				       (double*) stage_boundary_values -> data,
+				       (double*) xmom_boundary_values -> data,
+				       (double*) bed_boundary_values -> data,
+				       (double*) height_boundary_values -> data,
+				       (double*) velocity_boundary_values -> data,
+				       (double*) stage_explicit_update -> data,
+				       (double*) xmom_explicit_update -> data,
+				       number_of_elements,
+				       (double*) max_speed_array -> data);
+
+    //printf("comp_flux_vel 2 \n");    
+    
+    Py_DECREF(neighbours);
+    Py_DECREF(neighbour_vertices);
+    Py_DECREF(normals);
+    Py_DECREF(areas);
+    Py_DECREF(stage_vertex_values);
+    Py_DECREF(xmom_vertex_values);
+    Py_DECREF(bed_vertex_values);
+    Py_DECREF(height_vertex_values);
+    Py_DECREF(velocity_vertex_values);
+    Py_DECREF(stage_boundary_values);
+    Py_DECREF(xmom_boundary_values);
+    Py_DECREF(bed_boundary_values);
+    Py_DECREF(height_boundary_values);
+    Py_DECREF(velocity_boundary_values);
+    Py_DECREF(stage_explicit_update);
+    Py_DECREF(xmom_explicit_update);
+    Py_DECREF(max_speed_array);
+    
+    //printf("comp_flux_vel 3 \n");
+
+    // Return updated flux timestep
+    return Py_BuildValue("d", timestep);
+}
+
+
+
+//-------------------------------
+// Method table for python module
+//-------------------------------
+
+static struct PyMethodDef MethodTable[] = {
+  {"compute_fluxes_ext", compute_fluxes_ext, METH_VARARGS, "Print out"},
+  {"compute_fluxes_vel_ext", compute_fluxes_vel_ext, METH_VARARGS, "Print out"},
+  {NULL, NULL}
+};
+
+// Module initialisation
+void initcomp_flux_vel_ext(void){
+  Py_InitModule("comp_flux_vel_ext", MethodTable);
+  import_array();
+}
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/compile_all.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/compile_all.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/compile_all.py	(revision 7576)
@@ -0,0 +1,15 @@
+import os
+
+buildroot = os.getcwd()
+
+#Attempt to compile all extensions
+
+sudi_dir = '..' + os.sep + '..' + os.sep + '..'
+utilities_dir = sudi_dir + os.sep + 'Documents' + os.sep + 'ga' + os.sep + 'branches' + os.sep + 'Numeric_anuga_source' + os.sep + 'anuga' + os.sep + 'utilities'
+
+execfile( utilities_dir + os.sep + 'compile.py')
+
+
+os.chdir(buildroot)    
+
+    
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/compile_all_old.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/compile_all_old.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/compile_all_old.py	(revision 7576)
@@ -0,0 +1,9 @@
+import os
+
+buildroot = os.getcwd()
+
+file = 'C:\\Users\\Sudi Mungkasi\\Documents\\ga\\anuga_core\\source\\anuga\\utilities\\compile.py'
+print file
+execfile(file)
+
+    
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/config.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/config.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/config.py	(revision 7576)
@@ -0,0 +1,112 @@
+"""Module where global model parameters are set for anuga_1d
+"""
+
+epsilon = 1.0e-6#12
+h0 = 1.0e-12
+
+default_boundary_tag = 'exterior'
+
+
+time_format = '%d/%m/%y %H:%M:%S'
+
+min_timestep = 1.0e-6 #Should be computed based on geometry
+max_timestep = 1.0e3
+max_smallsteps = 50  # Max number of degenerate steps allowed b4 trying first order
+#This is how:
+#Define maximal possible speed in open water v_max, e.g. 500m/s (soundspeed?)
+#Then work out minimal internal distance in mesh r_min and set
+#min_timestep = r_min/v_max
+#
+#Max speeds are calculated in the flux function as
+#
+#lambda = v +/- sqrt(gh)
+#
+# so with 500 m/s, h ~ 500^2/g = 2500 m well out of the domain of the
+# shallow water wave equation
+#
+#The actual soundspeed can be as high as 1530m/s
+#(see http://staff.washington.edu/aganse/public.projects/clustering/clustering.html),
+#but that would only happen with h>225000m in this equation. Why ?
+#The maximal speed we specify is really related to the max speed
+#of surface pertubation
+#
+
+
+v_max = 100 #For use in domain_ext.c
+sound_speed = 500
+
+
+max_smallsteps = 50  #Max number of degenerate steps allowed b4 trying first order
+
+manning = 0.0  #Manning's friction coefficient
+g = 9.81       #Gravity
+#g(phi) = 9780313 * (1 + 0.0053024 sin(phi)**2 - 0.000 0059 sin(2*phi)**2) micro m/s**2, where phi is the latitude
+#The 'official' average is 9.80665
+
+
+
+
+eta_w = 3.0e-3 #Wind stress coefficient
+rho_a = 1.2e-3 #Atmospheric density
+rho_w = 1023   #Fluid density [kg/m^3] (rho_w = 1023 for salt water)
+
+
+#Betas [0;1] control the allowed steepness of gradient for second order
+#extrapolations. Values of 1 allow the steepes gradients while
+#lower values are more conservative. Values of 0 correspond to
+#1'st order extrapolations.
+#
+# Large values of beta_h may cause simulations to require more timesteps
+# as surface will 'hug' closer to the bed.
+# Small values of beta_h will make code faster, but one may experience
+# artificial momenta caused by discontinuities in water depths in
+# the presence of steep slopes. One example of this would be
+# stationary water 'lapping' upwards to a higher point on the coast.
+#
+#
+#
+#There are separate betas for the w-limiter and the h-limiter
+#
+#
+#
+#
+#Good values are:
+#beta_w = 0.9
+#beta_h = 0.2
+
+
+
+beta_w = 1.5
+beta_h = 0.2
+timestepping_method = 'euler'
+
+CFL = 1.0  #FIXME (ole): Is this in use yet??
+           #(Steve) yes, change domain.CFL to
+           #make changes
+
+
+pmesh_filename = '.\\pmesh'
+
+
+import os, sys
+
+if sys.platform == 'win32':
+    #default_datadir = 'C:\grohm_output'
+    default_datadir = '.'
+else:
+    #default_datadir = os.path.expanduser('~'+os.sep+'grohm_output')
+    default_datadir = '.'
+
+
+use_extensions = True    #Try to use C-extensions
+#use_extensions = False   #Do not use C-extensions
+
+use_psyco = True  #Use psyco optimisations
+#use_psyco = False  #Do not use psyco optimisations
+
+
+optimised_gradient_limiter = True #Use hardwired gradient limiter
+
+#Specific to shallow water W.E.
+h_min = minimum_allowed_height = 1.0e-4 #1.0e-6 #Water depth below which it is considered to be 0
+maximum_allowed_speed = 1000.0
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dam_h_elevation.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dam_h_elevation.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dam_h_elevation.py	(revision 7576)
@@ -0,0 +1,182 @@
+import os
+from math import sqrt, sin, cos, pi, exp
+from shallow_water_domain_suggestion3 import *
+from Numeric import zeros, Float
+#from analytic_dam_sudi import AnalyticDam
+
+h0=5.0
+h1=10.0
+
+#analytical_sol=AnalyticDam(h0,h1)
+
+"""
+def newLinePlot(title='Simple Plot'):
+    import Gnuplot
+    gg=Gnuplot.Gnuplot(persist=0)
+    gg.title(title)
+    gg('set data style linespoints')
+    gg.xlabel('x')
+    gg.ylabel('y')
+    return gg
+
+def linePlot(gg, x1, y1, x2, y2):
+    import Gnuplot
+    plot1=Gnuplot.PlotItems.Data(x1.flat, y1.flat, with="linespoints")
+    plot2=Gnuplot.PlotItems.Data(x2.flat, y2.flat, with="lines 3")
+    gg.plot(plot1, plot2)
+"""
+
+
+print "TEST 1D-SOLUTION I"
+
+L=2000.0
+N=200
+
+cell_len=L/N
+
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+
+domain.order = 2
+domain.set_timestepping_method('rk2')
+#domain.default_time_order = 2
+domain.cfl = 1.0
+#domain.limiter = "vanleer"
+
+
+
+def stage(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if x[i]<=1000.0:
+            y[i]=10.0
+        else:
+            y[i]=0.0
+    return y
+
+def stage_perturb(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 800.0 <= x[i] <=1200.0:
+            y[i]=10.0
+        else:
+            y[i]=5.0
+    return y
+
+def stage_sincos(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        y[i] = 5+exp(cos(pi*x[i]*0.001))+sin(pi*x[i]*0.0005)*sin(pi*x[i]*0.0005)
+    return y
+
+
+def elevation_box(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 500.0 <= x[i] <= 1500.0:
+            y[i] = 2.5
+        else:
+            y[i] = 0.0
+    return y
+
+def elevation_parabol(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 1400.0 <= x[i] <= 1600.0:
+            y[i] = 1.25*(1+cos(0.01*pi*(x[i]-500)))
+        else:
+            y[i] = 0.0
+    return y
+
+
+def elevation_sincos(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        y[i] = sin(pi*x[i]*0.0005)*sin(pi*x[i]*0.0005)
+    return y
+
+
+
+def xmom_sincos(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        y[i] = sin(cos(pi*x[i]*0.001))
+    return y
+
+domain.set_quantity('stage',stage)
+#domain.set_quantity('elevation', elevation_box)
+#domain.set_quantity('xmomentum', xmom_sincos)
+#domain.order=domain.default_order
+print "domain order", domain.order
+print "slope limiter", domain.limiter
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+
+X=domain.vertices
+C=domain.centroids
+#plot1x=newLinePlot("Height")
+#plot2x=newLinePlot("Momentum")
+
+
+import time
+t0=time.time()
+yieldstep=10.0 #30.0
+finaltime=10.0 #20.0
+print "integral", domain.quantities['stage'].get_integral()
+for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+    domain.write_time()
+    print "integral", domain.quantities['stage'].get_integral()
+    if t>0.0:
+        HeightQ=domain.quantities['stage'].vertex_values
+        MomentumQ=domain.quantities['xmomentum'].vertex_values
+        ElevationQ=domain.quantities['elevation'].vertex_values
+        #h, uh=analytical_sol(X.flat, domain.time)
+        #linePlot(plot1x, X, HeightQ, X, h)
+        #linePlot(plot2x, X, MomentumQ, X, uh)
+        #print "press return"
+        #pass
+    
+        from pylab import clf,plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot,ion
+        #print 'Test1'
+        ion()
+        hold(False)
+        #clf()
+        #print 'test 2'
+        plot1 = subplot(211)
+        #print 'test 3'
+    
+        
+        #print 'Test4'
+
+        plot(X,ElevationQ,X,HeightQ)
+        plot1.set_ylim([-1.0,11.0])
+        xlabel('Position')
+        ylabel('Stage')
+        #legend( ('Bed Elevation', 'Numerical Solution'),
+        #   'upper right', shadow=False)
+
+        
+        #legend(('Analytical Solution', 'Numerical Solution'),
+        #   'lower right', shadow=False)
+        plot2 = subplot(212)
+        plot(X,MomentumQ)
+        #plot2.set_ylim([-1,1])
+        
+        #legend( ('Numerical Solution', 'for momentum'),
+        #   'upper right', shadow=False)
+    
+        xlabel('Position')
+        ylabel('Xmomentum')
+        
+        #file = "dam_h_"
+        #file += str(number_of_cells[i])
+        #file += ".eps"
+        #savefig(file)
+        #show()
+        
+print 'That took %.2f seconds'%(time.time()-t0)
+
+raw_input("Press any key")
+
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dam_h_sudi.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dam_h_sudi.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dam_h_sudi.py	(revision 7576)
@@ -0,0 +1,120 @@
+import os
+from math import sqrt
+#from shallow_water_h import *
+from shallow_water_domain import *
+from Numeric import zeros, Float
+from analytic_dam_sudi import AnalyticDam
+
+h0=5.0
+h1=10.0
+
+analytical_sol=AnalyticDam(h0,h1)
+
+"""
+def newLinePlot(title='Simple Plot'):
+    import Gnuplot
+    gg=Gnuplot.Gnuplot(persist=0)
+    gg.title(title)
+    gg('set data style linespoints')
+    gg.xlabel('x')
+    gg.ylabel('y')
+    return gg
+
+def linePlot(gg, x1, y1, x2, y2):
+    import Gnuplot
+    plot1=Gnuplot.PlotItems.Data(x1.flat, y1.flat, with="linespoints")
+    plot2=Gnuplot.PlotItems.Data(x2.flat, y2.flat, with="lines 3")
+    gg.plot(plot1, plot2)
+"""
+
+
+print "TEST 1D-SOLUTION I"
+
+L=2000.0
+N=400
+
+cell_len=L/N
+
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+
+domain.default_order = 2
+domain.default_time_order = 1
+domain.cfl = 1.0
+domain.limiter = "vanleer"
+
+
+
+def height(x):
+    y=zeros(len(x), Float)
+    for i in range (len(x)):
+        if x[i]<=L/4.0:
+            y[i]=0.0 #h0
+        elif x[i]<=3*L/4.0:
+            y[i]=h1
+        else:
+            y[i]=h0
+    return y
+
+domain.set_quantity('stage',height) #('height', height)
+domain.order=domain.default_order
+print "domain order", domain.order
+
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+
+X=domain.vertices
+C=domain.centroids
+#plot1x=newLinePlot("Height")
+#plot2x=newLinePlot("Momentum")
+
+
+import time
+t0=time.time()
+yieldstep=30.0
+finaltime=20.0
+print "integral", domain.quantities['stage'].get_integral() #['height'].get_integral()
+for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+    domain.write_time()
+    print "integral", domain.quantities['stage'].get_integral() #['height'].get_integral()
+    if t>0.0:
+        HeightQ=domain.quantities['stage'].vertex_values #['height'].vertex_values
+        MomentumQ=domain.quantities['xmomentum'].vertex_values
+        h, uh=analytical_sol(X.flat, domain.time)
+        #linePlot(plot1x, X, HeightQ, X, h)
+        #linePlot(plot2x, X, MomentumQ, X, uh)
+        #print "press return"
+        #pass
+    
+        from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+        #print 'Test1'
+        hold(False)
+        #print 'test 2'
+        plot1 = subplot(211)
+        #print 'test 3'
+    
+        plot(X,h,X,HeightQ)
+        #print 'Test4'
+        plot1.set_ylim([0,11])
+        xlabel('Position')
+        ylabel('Stage')
+        #legend(('Analytical Solution', 'Numerical Solution'),
+        #   'lower right', shadow=False)
+        plot2 = subplot(212)
+        plot(X,uh,X,MomentumQ)
+        #plot2.set_ylim([-5,35])
+        legend(('Analytical Solution', 'Numerical Solution'),
+           'lower right', shadow=False)
+    
+        xlabel('Position')
+        ylabel('Xmomentum')
+        
+        file = "dam_h_"
+        #file += str(number_of_cells[i])
+        file += ".eps"
+        #savefig(file)
+        show()
+
+print 'That took %.2f seconds'%(time.time()-t0)
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dam_padarn.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dam_padarn.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dam_padarn.py	(revision 7576)
@@ -0,0 +1,172 @@
+import os
+from math import sqrt, pi
+from channel_domain_Ab import *
+from Numeric import allclose, array, zeros, ones, Float, take, sqrt
+from config import g, epsilon
+
+
+h1 = 5.0
+h0 = 0.0
+
+def analytical_sol(C,t):
+    
+    #t  = 0.0     # time (s)
+    # gravity (m/s^2)
+    #h1 = 10.0    # depth upstream (m)
+    #h0 = 0.0     # depth downstream (m)
+    L = 2000.0   # length of stream/domain (m)
+    n = len(C)    # number of cells
+
+    u = zeros(n,Float)
+    h = zeros(n,Float)
+    x = C-3*L/4.0
+    
+
+    for i in range(n):
+        # Calculate Analytical Solution at time t > 0
+        u3 = 2.0/3.0*(sqrt(g*h1)+x[i]/t) 
+        h3 = 4.0/(9.0*g)*(sqrt(g*h1)-x[i]/(2.0*t))*(sqrt(g*h1)-x[i]/(2.0*t))
+        u3_ = 2.0/3.0*((x[i]+L/2.0)/t-sqrt(g*h1))
+        h3_ = 1.0/(9.0*g)*((x[i]+L/2.0)/t+2*sqrt(g*h1))*((x[i]+L/2.0)/t+2*sqrt(g*h1))
+
+        if ( x[i] <= -1*L/2.0+2*(-sqrt(g*h1)*t)):
+            u[i] = 0.0
+            h[i] = h0
+        elif ( x[i] <= -1*L/2.0-(-sqrt(g*h1)*t)):
+            u[i] = u3_
+            h[i] = h3_
+
+        elif ( x[i] <= -t*sqrt(g*h1) ):
+            u[i] = 0.0 
+            h[i] = h1 
+        elif ( x[i] <= 2.0*t*sqrt(g*h1) ):
+            u[i] = u3 
+            h[i] = h3 
+        else:
+            u[i] = 0.0 
+            h[i] = h0 
+
+    return h , u*h, u
+
+#def newLinePlot(title='Simple Plot'):
+#   import Gnuplot
+#    gg = Gnuplot.Gnuplot(persist=0)
+#    gg.terminal(postscript)
+#    gg.title(title)
+#    gg('set data style linespoints') 
+#    gg.xlabel('x')
+#    gg.ylabel('y')
+#    return gg
+
+#def linePlot(gg,x1,y1,x2,y2):
+#    import Gnuplot
+#    plot1 = Gnuplot.PlotItems.Data(x1.flat,y1.flat,with="linespoints")
+#    plot2 = Gnuplot.PlotItems.Data(x2.flat,y2.flat, with="lines 3")
+#    g.plot(plot1,plot2)
+
+h2=5.0
+k=1
+
+print "TEST 1D-SOLUTION III -- DRY BED"
+
+def stage(x):
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        if x[i]<=L/4.0:
+            y[i] = h0*width([x[i]])
+        elif x[i]<=3*L/4.0:
+            y[i] = h2*width([x[i]])
+        else:
+            y[i] = h0*width([x[i]])
+    return y
+
+def width(x):
+    return k
+
+ 
+import time
+
+finaltime = 10.0
+yieldstep = finaltime
+L = 2000.0     # Length of channel (m)
+number_of_cells = [200]
+k = 0
+widths = [1]
+heights= []
+for i in range(len(widths)):
+    k=widths[i]
+    for i in range(len(number_of_cells)):
+        N = int(number_of_cells[i])
+        print "Evaluating domain with %d cells" %N
+        cell_len = L/N # Origin = 0.0
+        points = zeros(N+1,Float)
+        for j in range(N+1):
+            points[j] = j*cell_len
+        
+        domain = Domain(points)
+    
+        domain.set_quantity('area', stage)
+        domain.set_quantity('width',width)
+        print "width in cell 1",domain.quantities['width'].vertex_values[1]
+        domain.set_boundary({'exterior': Reflective_boundary(domain)})
+        domain.order = 2
+        domain.set_timestepping_method('rk2')
+        domain.set_CFL(1.0)
+        domain.set_limiter("vanleer")
+        #domain.h0=0.0001
+ 
+        t0 = time.time()
+
+        for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime):
+            domain.write_time()
+
+        N = float(N)
+        HeightC = domain.quantities['height'].centroid_values 
+        DischargeC = domain.quantities['discharge'].centroid_values
+        C = domain.centroids
+        h, uh, u = analytical_sol(C,domain.time)
+        #h_error[k] = 1.0/(N)*sum(abs(h-StageC))
+        #uh_error[k] = 1.0/(N)*sum(abs(uh-XmomC))
+        #print "h_error %.10f" %(h_error[k])
+        #print "uh_error %.10f"% (uh_error[k])
+        k = k+1
+        print 'That took %.2f seconds' %(time.time()-t0)
+        X = domain.vertices
+        heights.append(domain.quantities['height'].vertex_values)
+        VelocityQ = domain.quantities['velocity'].vertex_values
+        #stage = domain.quantities['stage'].vertex_values
+        h, uh, u = analytical_sol(X.flat,domain.time)
+        x = X.flat
+    
+        #from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+from pylab import *
+import pylab as p
+import matplotlib.axes3d as p3
+print 'test 2'
+hold(False)
+print 'test 3'
+plot1 = subplot(211)
+print 'test 4'
+plot(x,h,x,heights[0].flat)
+print 'test 5'
+plot1.set_ylim([-1,11])
+xlabel('Position')
+ylabel('Stage')
+legend(('Analytical Solution', 'Numerical Solution'),
+           'upper right', shadow=True)
+plot2 = subplot(212)
+plot(x,u,x,VelocityQ.flat)
+plot2.set_ylim([-35,35])
+    
+xlabel('Position')
+ylabel('Velocity')
+   
+file = "dry_bed_"
+file += str(number_of_cells[i])
+file += ".eps"
+#savefig(file)
+show()
+    
+    
+#print "Error in height", h_error
+#print "Error in xmom", uh_error
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/discontinuous_z.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/discontinuous_z.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/discontinuous_z.py	(revision 7576)
@@ -0,0 +1,175 @@
+import os
+import time
+from math import sqrt, sin, cos, pi, exp
+from shallow_water_domain_suggestion3 import *
+from Numeric import zeros, Float
+from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+from scipy import linspace
+
+print "TEST 1D-SOLUTION I"
+L=2000.0
+N=400
+
+cell_len=L/N
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+domain.order = 2
+domain.set_timestepping_method('rk2')
+domain.cfl = 1.0
+domain.limiter = "minmod"
+
+def stage_flat(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        y[i]=4.5
+    return y
+
+def stage45(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 0 <= x[i] < 150.0:
+            y[i] = -0.01*(x[i]-200) + 4.0
+        elif 150.0 <= x[i] < 900.0:
+            y[i] = 4.5
+        elif 900.0 <= x[i] < 1000.0:
+            y[i] = 6.0
+        elif 1000.0 <= x[i] < 1800 + sqrt(100000/4.5):
+            y[i] = 4.5
+        else:
+            y[i] = (4.5/40000)*(x[i]-1800)*(x[i]-1800) + 2.0
+    return y
+
+def nol(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        y[i] = 0.0
+    return y
+
+
+
+
+def elevation_arbitrary(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 0 <= x[i] < 200.0:
+            y[i] = -0.01*(x[i]-200) + 4.0
+        elif 200.0 <= x[i] < 300.0:
+            y[i] = -0.02*(x[i]-200) + 4.0
+        elif 300.0 <= x[i] < 400.0:
+            y[i] = -0.01*(x[i]-300) + 2.0
+        elif 400.0 <= x[i] < 550.0:
+            y[i] = (-1/75.0)*(x[i]-400.0) + 2.0
+        elif 550.0 <= x[i] < 700.0:
+            y[i] = (1/11250)*(x[i]-550)*(x[i]-550)
+        elif 700.0 <= x[i] < 800.0:
+            y[i] = 0.03*(x[i]-700)
+        elif 800.0 <= x[i] < 900.0:
+            y[i] = -0.03*(x[i]-800) + 3.0
+        elif 900.0 <= x[i] < 1000.0:
+            y[i] = 6.0
+        elif 1000.0 <= x[i] < 1400.0:
+            y[i] = (-1.0/20000)*(x[i]-1000)*(x[i]-1400)
+        elif 1400.0 <= x[i] < 1500.0:
+            y[i] = 0.0
+        elif 1500.0 <= x[i] < 1700.0:
+            y[i] = 3.0
+        elif 1700.0 <= x[i] < 1800.0:
+            y[i] = -0.03*(x[i]-1700) + 3.0
+        else:
+            y[i] = (4.5/40000)*(x[i]-1800)*(x[i]-1800) + 2.0
+    return y
+
+def elevation_arbitrary1(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 0 <= x[i] < 200.0:
+            y[i] = -0.01*(x[i]-200) + 5.0
+        elif 200.0 <= x[i] < 900.0:
+            y[i] = 0.0
+        elif 900.0 <= x[i] < 1000.0:    # This is the island
+            y[i] = 5.0
+        elif 1000.0 <= x[i] < 1800.0:
+            y[i] = 0.0
+        else:
+            y[i] = 0.03*(x[i]-1700) + 3.0
+    return y
+
+def elevation_arbitrary2(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 0 <= x[i] < 1000.0:
+            y[i] = 5.0
+        else:
+            y[i] = 0.0
+    return y
+
+domain.set_quantity('stage',stage_flat)
+domain.set_quantity('elevation',elevation_arbitrary)
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+X=domain.vertices
+C=domain.centroids
+
+
+
+
+P_Stage=linspace(0,2000,4000)
+S=stage45(P_Stage)
+
+#E=elevation_arbitrary(P)
+P_Nol=linspace(0,2000,100)
+Enol=nol(P_Nol)
+
+#plot1 = subplot(111)
+#plot(P,S,'k,', P,E,'r-')
+#plot1.set_ylim([-0.5,7.5])
+#legend( ('Stage', 'Bed Elevation'), 'upper right', shadow=False)
+#xlabel('Position')
+#ylabel('Xmomentum')
+#show()
+t0=time.time()
+yieldstep=finaltime=2.0
+while finaltime < 2.2001:
+    for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+        #domain.write_time()
+        #print "t=",t
+        #print "integral", domain.quantities['height'].get_integral()
+        StageQ=domain.quantities['stage'].vertex_values
+        MomentumQ=domain.quantities['xmomentum'].vertex_values
+        ElevationQ=domain.quantities['elevation'].vertex_values
+        VelocityQ=domain.quantities['velocity'].vertex_values
+
+        hold(False)
+        plot1 = subplot(311)
+        plot(P_Stage,S,'k-',X,StageQ,'b,-', X,ElevationQ,'r-')
+        plot1.set_ylim([-1.0,11.0])
+        #xlabel('Position')
+        ylabel('Stage')
+        legend( ('Analytical Solution','Numerical Solution', 'Reconstructed Bed'), 'upper right', shadow=False)
+
+        plot2 = subplot(312)
+        plot(P_Nol,Enol,'k-', X,MomentumQ,'b,-')
+        #plot2.set_ylim([-8.0*10**-15, 8.0*10**-15])
+        legend( ('Analytical Solution','Numerical Solution'), 'lower left', shadow=False)
+        #xlabel('Position')
+        ylabel('Momentum')
+        
+        plot3 = subplot(313)
+        plot(P_Nol,Enol,'k-', X,VelocityQ,'b,-')
+        #plot3.set_ylim([-4.0*10**-15, 4.0*10**-15])
+        legend( ('Analytical Solution','Numerical Solution'), 'lower left', shadow=False)
+        xlabel('Position')
+        ylabel('Velocity')
+        
+        
+        #file = "island_"
+        #file += str(finaltime)
+        #file += ".png"
+        #savefig(file)
+        #show()
+        
+    print 'That took %.2f seconds'%(time.time()-t0)
+    finaltime = finaltime + 20
+raw_input("Press return key")
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/domain.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/domain.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/domain.py	(revision 7576)
@@ -0,0 +1,1613 @@
+"""Class Domain - 1D domains for finite-volume computations of
+   the shallow water wave equation
+
+
+   Copyright 2004
+   Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+   Geoscience Australia
+"""
+
+from generic_boundary_conditions import *
+
+
+class Domain:
+
+    def __init__(self,
+                 coordinates,
+                 boundary = None,
+                 conserved_quantities = None,
+                 evolved_quantities = None,
+                 other_quantities = None,
+                 tagged_elements = None):
+        """
+        Build 1D elements from x coordinates
+        """
+
+        from Numeric import array, zeros, Float, Int
+
+        from config import timestepping_method
+        from config import CFL
+        
+        #Store Points
+        self.coordinates = array(coordinates)
+
+
+        #Register number of Elements
+        self.number_of_elements = N = len(self.coordinates)-1
+
+        self.beta = 1.0
+        self.set_limiter("minmod_kurganov")
+        self.set_CFL(CFL)
+        self.set_timestepping_method(timestepping_method)
+
+        self.wet_nodes = zeros((N,2), Int) # should this be here
+
+        #Allocate space for neighbour and boundary structures
+        self.neighbours = zeros((N, 2), Int)
+        #self.neighbour_edges = zeros((N, 2), Int)
+        self.neighbour_vertices = zeros((N, 2), Int)
+        self.number_of_boundaries = zeros(N, Int)
+        self.surrogate_neighbours = zeros((N, 2), Int)
+        
+        #Allocate space for geometric quantities
+        self.vertices  = zeros((N, 2), Float)
+        self.centroids = zeros(N, Float)
+        self.areas     = zeros(N, Float)
+
+        self.max_speed_array = zeros(N, Float)
+      
+
+        self.normals = zeros((N, 2), Float)
+        
+        for i in range(N):
+            xl = self.coordinates[i]
+            xr = self.coordinates[i+1]
+            self.vertices[i,0] = xl
+            self.vertices[i,1] = xr
+
+            centroid = (xl+xr)/2.0
+            self.centroids[i] = centroid
+
+            msg = 'Coordinates should be ordered, smallest to largest'
+            assert xr>xl, msg
+            
+            #The normal vectors
+            # - point outward from each edge
+            # - are orthogonal to the edge
+            # - have unit length
+            # - Are enumerated by left vertex then right vertex normals
+
+            nl = -1.0
+            nr =  1.0
+            self.normals[i,:] = [nl, nr]
+
+            self.areas[i] = (xr-xl)
+            
+# #         print 'N', N
+# #         print 'Centroid', self.centroids
+# #         print 'Areas', self.areas
+# #         print 'Vertex_Coordinates', self.vertices
+            
+            #Initialise Neighbours (-1 means that it is a boundary neighbour)
+            self.neighbours[i, :] = [-1, -1]
+            #Initialise edge ids of neighbours
+            #Initialise vertex ids of neighbours
+            #In case of boundaries this slot is not used
+            #self.neighbour_edges[i, :] = [-1, -1]
+            self.neighbour_vertices[i, :] = [-1, -1]
+
+        self.build_vertexlist()
+
+        #Build neighbour structure
+        self.build_neighbour_structure()
+
+        #Build surrogate neighbour structure
+        self.build_surrogate_neighbour_structure()          
+
+        #Build boundary dictionary mapping (id, edge) to symbolic tags
+        #Build boundary dictionary mapping (id, vertex) to symbolic tags
+        self.build_boundary_dictionary(boundary)
+
+        #Build tagged element  dictionary mapping (tag) to array of elements
+        self.build_tagged_elements_dictionary(tagged_elements)
+        
+        from quantity import Quantity, Conserved_quantity
+        #from quantity_domain import Quantity, Conserved_quantity
+        
+        #List of quantity names entering
+        #the conservation equations
+        #(Must be a subset of quantities)
+        if conserved_quantities is None:
+            self.conserved_quantities = []
+        else:
+            self.conserved_quantities = conserved_quantities
+
+        if evolved_quantities is None:
+            self.evolved_quantities = self.conserved_quantities
+        else:
+            self.evolved_quantities = evolved_quantities
+
+        if other_quantities is None:
+            self.other_quantities = []
+        else:
+            self.other_quantities = other_quantities
+
+
+        #Build dictionary of Quantity instances keyed by quantity names
+        self.quantities = {}
+
+        #print self.conserved_quantities
+        #print self.evolved_quantities
+        
+
+        #FIXME: remove later - maybe OK, though....
+        for name in self.evolved_quantities:
+            self.quantities[name] = Quantity(self)
+        for name in self.other_quantities:
+            self.quantities[name] = Quantity(self)
+
+        #Create an empty list for explicit forcing terms
+        self.forcing_terms = []
+
+        #Defaults
+        from config import max_smallsteps, beta_w, beta_h, epsilon, CFL
+        self.beta_w = beta_w
+        self.beta_h = beta_h
+        self.epsilon = epsilon
+
+        #FIXME: Maybe have separate orders for h-limiter and w-limiter?
+        #Or maybe get rid of order altogether and use beta_w and beta_h
+        self.default_order = 1
+        self.order = self.default_order
+
+        self.default_time_order = 1
+        self.time_order = self.default_time_order
+        
+        self.smallsteps = 0
+        self.max_smallsteps = max_smallsteps
+        self.number_of_steps = 0
+        self.number_of_first_order_steps = 0
+
+        #Model time
+        self.time = 0.0
+        self.finaltime = None
+        self.min_timestep = self.max_timestep = 0.0
+        self.starttime = 0 #Physical starttime if any (0 is 1 Jan 1970 00:00:00)
+        #Checkpointing and storage
+        from config import default_datadir
+        self.set_datadir(default_datadir)
+        self.filename = 'domain'
+        self.checkpoint = False
+
+    def __len__(self):
+        return self.number_of_elements
+
+    def build_vertexlist(self):
+        """Build vertexlist index by vertex ids and for each entry (point id)
+        build a list of (triangles, vertex_id) pairs that use the point
+        as vertex.
+
+        Preconditions:
+          self.coordinates and self.triangles are defined
+
+        Postcondition:
+          self.vertexlist is built
+        """
+        from Numeric import array
+
+        vertexlist = [None]*len(self.coordinates)
+        for i in range(self.number_of_elements):
+
+            #a = self.triangles[i, 0]
+            #b = self.triangles[i, 1]
+            #c = self.triangles[i, 2]
+            a = i
+            b = i + 1
+
+            #Register the vertices v as lists of
+            #(triangle_id, vertex_id) tuples associated with them
+            #This is used for smoothing
+            #for vertex_id, v in enumerate([a,b,c]):
+            for vertex_id, v in enumerate([a,b]):
+                if vertexlist[v] is None:
+                    vertexlist[v] = []
+
+                vertexlist[v].append( (i, vertex_id) )
+
+        self.vertexlist = vertexlist
+
+        
+    def build_neighbour_structure(self):
+        """Update all registered triangles to point to their neighbours.
+
+        Also, keep a tally of the number of boundaries for each triangle
+
+        Postconditions:
+          neighbours and neighbour_edges is populated
+          neighbours and neighbour_vertices is populated
+          number_of_boundaries integer array is defined.
+        """
+
+        #Step 1:
+        #Build dictionary mapping from segments (2-tuple of points)
+        #to left hand side edge (facing neighbouring triangle)
+
+        N = self.number_of_elements
+        neighbourdict = {}
+        #l_edge = 0
+        #r_edge = 1
+        l_vertex = 0
+        r_vertex = 1
+        for i in range(N):
+
+            #Register all segments as keys mapping to current triangle
+            #and segment id
+            #a = self.triangles[i, 0]
+            #b = self.triangles[i, 1]
+            #c = self.triangles[i, 2]
+            a = self.vertices[i,0]
+            b = self.vertices[i,1]
+            
+            """
+            if neighbourdict.has_key((a,b)):
+                    msg = "Edge 2 of triangle %d is duplicating edge %d of triangle %d.\n" %(i,neighbourdict[a,b][1],neighbourdict[a,b][0])
+                    raise msg
+            if neighbourdict.has_key((b,c)):
+                    msg = "Edge 0 of triangle %d is duplicating edge %d of triangle %d.\n" %(i,neighbourdict[b,c][1],neighbourdict[b,c][0])
+                    raise msg
+            if neighbourdict.has_key((c,a)):
+                    msg = "Edge 1 of triangle %d is duplicating edge %d of triangle %d.\n" %(i,neighbourdict[c,a][1],neighbourdict[c,a][0])
+                    raise msg
+                    """
+            #neighbourdict[a,b] = (i, 2) #(id, edge)
+            #neighbourdict[b,c] = (i, 0) #(id, edge)
+            #neighbourdict[c,a] = (i, 1) #(id, edge)
+            #neighbourdict[a,b] = (i, 1) #(id, edge)
+            #neighbourdict[b,a] = (i, 0) #(id, edge)
+            #neighbourdict[a,l_edge] = (i, 0) #(id, edge)
+            #neighbourdict[b,r_edge] = (i, 1) #(id, edge)
+            neighbourdict[a,l_vertex] = (i, 0) #(id, vertex)
+            neighbourdict[b,r_vertex] = (i, 1) #(id, vertex)
+
+
+        #Step 2:
+        #Go through triangles again, but this time
+        #reverse direction of segments and lookup neighbours.
+        for i in range(N):
+            #a = self.triangles[i, 0]
+            #b = self.triangles[i, 1]
+            #c = self.triangles[i, 2]
+            
+            a = self.vertices[i,0]
+            b = self.vertices[i,1]
+            
+            #self.number_of_boundaries[i] = 3
+            self.number_of_boundaries[i] = 2
+            #if neighbourdict.has_key((b,l_edge)):
+            if neighbourdict.has_key((b,l_vertex)):
+                #self.neighbours[i, 1] = neighbourdict[b,l_edge][0]
+                #self.neighbour_edges[i, 1] = neighbourdict[b,l_edge][1]
+                self.neighbours[i, 1] = neighbourdict[b,l_vertex][0]
+                self.neighbour_vertices[i, 1] = neighbourdict[b,l_vertex][1]
+                self.number_of_boundaries[i] -= 1
+
+            #if neighbourdict.has_key((a,r_edge)):
+            if neighbourdict.has_key((a,r_vertex)):
+                #self.neighbours[i, 0] = neighbourdict[a,r_edge][0]
+                #self.neighbour_edges[i, 0] = neighbourdict[a,r_edge][1]
+                self.neighbours[i, 0] = neighbourdict[a,r_vertex][0]
+                self.neighbour_vertices[i, 0] = neighbourdict[a,r_vertex][1]
+                self.number_of_boundaries[i] -= 1
+                
+            #if neighbourdict.has_key((b,a)):
+            #    self.neighbours[i, 1] = neighbourdict[b,a][0]
+            #    self.neighbour_edges[i, 1] = neighbourdict[b,a][1]
+            #    self.number_of_boundaries[i] -= 1
+
+            #if neighbourdict.has_key((c,b)):
+            #    self.neighbours[i, 0] = neighbourdict[c,b][0]
+            #    self.neighbour_edges[i, 0] = neighbourdict[c,b][1]
+            #    self.number_of_boundaries[i] -= 1
+
+            #if neighbourdict.has_key((a,b)):
+            #    self.neighbours[i, 0] = neighbourdict[a,b][0]
+            #    self.neighbour_edges[i, 0] = neighbourdict[a,b][1]
+            #    self.number_of_boundaries[i] -= 1
+
+    def build_surrogate_neighbour_structure(self):
+        """Build structure where each triangle edge points to its neighbours
+        if they exist. Otherwise point to the triangle itself.
+
+        The surrogate neighbour structure is useful for computing gradients
+        based on centroid values of neighbours.
+
+        Precondition: Neighbour structure is defined
+        Postcondition:
+          Surrogate neighbour structure is defined:
+          surrogate_neighbours: i0, i1, i2 where all i_k >= 0 point to
+          triangles.
+
+        """
+
+        N = self.number_of_elements
+        for i in range(N):
+            #Find all neighbouring volumes that are not boundaries
+            #for k in range(3):
+            for k in range(2):    
+                if self.neighbours[i, k] < 0:
+                    self.surrogate_neighbours[i, k] = i #Point this triangle
+                else:
+                    self.surrogate_neighbours[i, k] = self.neighbours[i, k]
+
+    def build_boundary_dictionary(self, boundary = None):
+        """Build or check the dictionary of boundary tags.
+         self.boundary is a dictionary of tags,
+         keyed by volume id and edge:
+         { (id, edge): tag, ... }
+
+         Postconditions:
+            self.boundary is defined.
+        """
+
+        from config import default_boundary_tag
+
+        if boundary is None:
+            boundary = {}
+            for vol_id in range(self.number_of_elements):
+                #for edge_id in range(0, 3):
+                #for edge_id in range(0, 2):
+                for vertex_id in range(0, 2):    
+                    #if self.neighbours[vol_id, edge_id] < 0:
+                    if self.neighbours[vol_id, vertex_id] < 0:   
+                        #boundary[(vol_id, edge_id)] = default_boundary_tag
+                        boundary[(vol_id, vertex_id)] = default_boundary_tag
+        else:
+            #Check that all keys in given boundary exist
+            #for vol_id, edge_id in boundary.keys():
+            for vol_id, vertex_id in boundary.keys():    
+                #msg = 'Segment (%d, %d) does not exist' %(vol_id, edge_id)
+                msg = 'Segment (%d, %d) does not exist' %(vol_id, vertex_id)
+                a, b = self.neighbours.shape
+                #assert vol_id < a and edge_id < b, msg
+                assert vol_id < a and vertex_id < b, msg
+
+                #FIXME: This assert violates internal boundaries (delete it)
+                #msg = 'Segment (%d, %d) is not a boundary' %(vol_id, edge_id)
+                #assert self.neighbours[vol_id, edge_id] < 0, msg
+
+            #Check that all boundary segments are assigned a tag
+            for vol_id in range(self.number_of_elements):
+                #for edge_id in range(0, 3):
+                #for edge_id in range(0, 2):
+                for vertex_id in range(0, 2):    
+                    #if self.neighbours[vol_id, edge_id] < 0:
+                    if self.neighbours[vol_id, vertex_id] < 0:    
+                        #if not boundary.has_key( (vol_id, edge_id) ):
+                        if not boundary.has_key( (vol_id, vertex_id) ):    
+                            msg = 'WARNING: Given boundary does not contain '
+                            #msg += 'tags for edge (%d, %d). '\
+                            #       %(vol_id, edge_id)
+                            msg += 'tags for vertex (%d, %d). '\
+                                   %(vol_id, vertex_id)
+                            msg += 'Assigning default tag (%s).'\
+                                   %default_boundary_tag
+
+                            #FIXME: Print only as per verbosity
+                            #print msg
+
+                            #FIXME: Make this situation an error in the future
+                            #and make another function which will
+                            #enable default boundary-tags where
+                            #tags a not specified
+                            #boundary[ (vol_id, edge_id) ] =\
+                            boundary[ (vol_id, vertex_id) ] =\
+                                      default_boundary_tag
+
+
+
+        self.boundary = boundary
+
+    def build_tagged_elements_dictionary(self, tagged_elements = None):
+        """Build the dictionary of element tags.
+         self.tagged_elements is a dictionary of element arrays,
+         keyed by tag:
+         { (tag): [e1, e2, e3..] }
+
+         Postconditions:
+            self.element_tag is defined
+        """
+        from Numeric import array, Int
+
+        if tagged_elements is None:
+            tagged_elements = {}
+        else:
+            #Check that all keys in given boundary exist
+            for tag in tagged_elements.keys():
+                tagged_elements[tag] = array(tagged_elements[tag]).astype(Int)
+
+                msg = 'Not all elements exist. '
+                assert max(tagged_elements[tag]) < self.number_of_elements, msg
+        #print "tagged_elements", tagged_elements
+        self.tagged_elements = tagged_elements
+
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+
+
+
+    def get_boundary_tags(self):
+        """Return list of available boundary tags
+        """
+
+        tags = {}
+        for v in self.boundary.values():
+            tags[v] = 1
+
+        return tags.keys()
+        
+    def get_vertex_coordinates(self, obj = False):
+        """Return all vertex coordinates.
+        Return all vertex coordinates for all triangles as an Nx6 array
+        (ordered as x0, y0, x1, y1, x2, y2 for each triangle)
+
+        if obj is True, the x/y pairs are returned in a 3*N x 2 array.
+        FIXME, we might make that the default.
+        FIXME Maybe use keyword: continuous = False for this condition?
+
+        
+        """
+
+        if obj is True:
+            from Numeric import concatenate, reshape
+            #V = self.vertex_coordinates
+            V = self.vertices
+            #return concatenate( (V[:,0:2], V[:,2:4], V[:,4:6]), axis=0)
+
+            N = V.shape[0]
+            #return reshape(V, (3*N, 2))
+            return reshape(V, (N, 2))
+        else:    
+            #return self.vertex_coordinates
+            return self.vertices
+    
+    def get_conserved_quantities(self, vol_id, vertex=None):#, edge=None):
+        """Get conserved quantities at volume vol_id
+
+        If vertex is specified use it as index for vertex values
+        If edge is specified use it as index for edge values
+        If neither are specified use centroid values
+        If both are specified an exeception is raised
+
+        Return value: Vector of length == number_of_conserved quantities
+
+        """
+
+        from Numeric import zeros, Float
+
+        #if not (vertex is None):# or edge is None):
+        #    msg = 'Values for both vertex and edge was specified.'
+        #    msg += 'Only one (or none) is allowed.'
+       #     raise msg
+
+        q = zeros( len(self.conserved_quantities), Float)
+
+        for i, name in enumerate(self.conserved_quantities):
+            Q = self.quantities[name]
+            if vertex is not None:
+                q[i] = Q.vertex_values[vol_id, vertex]
+            #elif edge is not None:
+            #    q[i] = Q.edge_values[vol_id, edge]
+            else:
+                q[i] = Q.centroid_values[vol_id]
+
+        return q
+
+
+    def get_evolved_quantities(self, vol_id, vertex=None):#, edge=None):
+        """Get evolved quantities at volume vol_id
+
+        If vertex is specified use it as index for vertex values
+        If edge is specified use it as index for edge values
+        If neither are specified use centroid values
+        If both are specified an exeception is raised
+
+        Return value: Vector of length == number_of_evolved quantities
+
+        """
+
+        from Numeric import zeros, Float
+
+        #if not (vertex is None):# or edge is None):
+        #    msg = 'Values for both vertex and edge was specified.'
+        #    msg += 'Only one (or none) is allowed.'
+       #     raise msg
+
+        q = zeros( len(self.evolved_quantities), Float)
+
+        for i, name in enumerate(self.evolved_quantities):
+            Q = self.quantities[name]
+            if vertex is not None:
+                q[i] = Q.vertex_values[vol_id, vertex]
+            #elif edge is not None:
+            #    q[i] = Q.edge_values[vol_id, edge]
+            else:
+                q[i] = Q.centroid_values[vol_id]
+
+        return q
+        
+
+    def get_centroids(self):
+        """Return all coordinates of centroids
+        Return x coordinate of centroid for each element as a N array
+        """
+
+        return self.centroids
+
+    def get_vertices(self):
+        """Return all coordinates of centroids
+        Return x coordinate of centroid for each element as a N array
+        """
+
+        return self.vertices
+
+    def get_coordinate(self, elem_id, vertex=None):
+        """Return coordinate of centroid,
+        or left or right vertex.
+        Left vertex (vertex=0). Right vertex (vertex=1)
+        """
+
+        if vertex is None:
+            return self.centroids[elem_id]
+        else:
+            return self.vertices[elem_id,vertex]
+
+    def get_area(self, elem_id):
+        """Return area of element id
+        """
+
+        return self.areas[elem_id]
+
+    def get_quantity(self, name, location='vertices', indices = None):
+        """Get values for named quantity
+
+        name: Name of quantity
+
+        In case of location == 'centroids' the dimension values must
+        be a list of a Numerical array of length N, N being the number
+        of elements. Otherwise it must be of dimension Nx3.
+
+        Indices is the set of element ids that the operation applies to.
+
+        The values will be stored in elements following their
+        internal ordering.
+        """
+
+        return self.quantities[name].get_values( location, indices = indices)
+
+    def get_centroid_coordinates(self):
+        """Return all centroid coordinates.
+        Return all centroid coordinates for all triangles as an Nx2 array
+        (ordered as x0, y0 for each triangle)
+        """
+        return self.centroids
+
+
+    def get_timestepping_method(self):
+        return self.timestepping_method
+
+    def set_timestepping_method(self,timestepping_method):
+        
+        if timestepping_method in ['euler', 'rk2', 'rk3']:
+            self.timestepping_method = timestepping_method
+            return
+
+        msg = '%s is an incorrect timestepping type'% timestepping_method
+        raise Exception, msg
+
+
+    def set_quantity(self, name, *args, **kwargs):
+        """Set values for named quantity
+
+
+        One keyword argument is documented here:
+        expression = None, # Arbitrary expression
+
+        expression:
+          Arbitrary expression involving quantity names
+
+        See Quantity.set_values for further documentation.
+        """
+
+        #FIXME (Ole): Allow new quantities here
+        #from quantity import Quantity, Conserved_quantity
+        #Create appropriate quantity object
+        # #if name in self.conserved_quantities:
+        # #    self.quantities[name] = Conserved_quantity(self)
+        # #else:
+        # #    self.quantities[name] = Quantity(self)
+
+
+        #Do the expression stuff
+        if kwargs.has_key('expression'):
+            expression = kwargs['expression']
+            del kwargs['expression']
+
+            Q = self.create_quantity_from_expression(expression)
+            kwargs['quantity'] = Q
+        
+        #Assign values
+        self.quantities[name].set_values(*args, **kwargs)
+
+    def set_boundary(self, boundary_map):
+        """Associate boundary objects with tagged boundary segments.
+
+        Input boundary_map is a dictionary of boundary objects keyed
+        by symbolic tags to matched against tags in the internal dictionary
+        self.boundary.
+
+        As result one pointer to a boundary object is stored for each vertex
+        in the list self.boundary_objects.
+        More entries may point to the same boundary object
+
+        Schematically the mapping is from two dictionaries to one list
+        where the index is used as pointer to the boundary_values arrays
+        within each quantity.
+
+        self.boundary:          (vol_id, edge_id): tag
+        boundary_map (input):   tag: boundary_object
+        ----------------------------------------------
+        self.boundary_objects:  ((vol_id, edge_id), boundary_object)
+
+
+        Pre-condition:
+          self.boundary has been built.
+
+        Post-condition:
+          self.boundary_objects is built
+
+        If a tag from the domain doesn't appear in the input dictionary an
+        exception is raised.
+        However, if a tag is not used to the domain, no error is thrown.
+        FIXME: This would lead to implementation of a
+        default boundary condition
+
+        Note: If a segment is listed in the boundary dictionary and if it is
+        not None, it *will* become a boundary -
+        even if there is a neighbouring triangle.
+        This would be the case for internal boundaries
+
+        Boundary objects that are None will be skipped.
+
+        FIXME: If set_boundary is called multiple times and if Boundary
+        object is changed into None, the neighbour structure will not be
+        restored!!!
+        """
+
+        self.boundary_objects = []
+        self.boundary_map = boundary_map  #Store for use with eg. boundary_stats.
+
+        #FIXME: Try to remove the sorting and fix test_mesh.py
+        x = self.boundary.keys()
+        x.sort()
+
+        #Loop through edges that lie on the boundary and associate them with
+        #callable boundary objects depending on their tags
+        #for k, (vol_id, edge_id) in enumerate(x):
+        for k, (vol_id, vertex_id) in enumerate(x):
+            #tag = self.boundary[ (vol_id, edge_id) ]
+            tag = self.boundary[ (vol_id, vertex_id) ]
+
+            if boundary_map.has_key(tag):
+                B = boundary_map[tag]  #Get callable boundary object
+
+                if B is not None:
+                    #self.boundary_objects.append( ((vol_id, edge_id), B) )
+                    #self.neighbours[vol_id, edge_id] = -len(self.boundary_objects)
+                    self.boundary_objects.append( ((vol_id, vertex_id), B) )
+                    self.neighbours[vol_id, vertex_id] = -len(self.boundary_objects)
+                else:
+                    pass
+                    #FIXME: Check and perhaps fix neighbour structure
+
+            else:
+                msg = 'ERROR (domain.py): Tag "%s" has not been ' %tag
+                msg += 'bound to a boundary object.\n'
+                msg += 'All boundary tags defined in domain must appear '
+                msg += 'in the supplied dictionary.\n'
+                msg += 'The tags are: %s' %self.get_boundary_tags()
+                raise msg
+
+
+
+    def check_integrity(self):
+        #Mesh.check_integrity(self)
+
+        #print self.quantities
+        #print self.conserved_quantities
+        
+        for quantity in self.conserved_quantities:
+            msg = 'Conserved quantities must be a subset of all quantities'
+            assert quantity in self.quantities, msg
+
+        for quantity in self.evolved_quantities:
+            msg = 'Evolved quantities must be a subset of all quantities'
+            assert quantity in self.quantities, msg            
+
+        # #assert hasattr(self, 'boundary_objects')
+
+    def write_time(self):
+        print self.timestepping_statistics()
+
+    def timestepping_statistics(self):
+        """Return string with time stepping statistics for printing or logging
+        """
+
+        msg = ''
+        if self.min_timestep == self.max_timestep:
+            msg += 'Time = %.4f, delta t = %.8f, steps=%d (%d)'\
+                   %(self.time, self.min_timestep, self.number_of_steps,
+                     self.number_of_first_order_steps)
+        elif self.min_timestep > self.max_timestep:
+            msg += 'Time = %.4f, steps=%d (%d)'\
+                   %(self.time, self.number_of_steps,
+                     self.number_of_first_order_steps)
+        else:
+            msg += 'Time = %.4f, delta t in [%.8f, %.8f], steps=%d (%d)'\
+                   %(self.time, self.min_timestep,
+                     self.max_timestep, self.number_of_steps,
+                     self.number_of_first_order_steps)
+
+        return msg
+
+    def get_name(self):
+        return self.filename
+
+    def set_name(self, name):
+        self.filename = name
+
+    def get_datadir(self):
+        return self.datadir
+
+    def set_datadir(self, name):
+        self.datadir = name
+
+    def set_CFL(self, cfl):
+        if cfl > 1.0:
+            print 'WARNING: Setting CFL condition to %f which is greater than 1' % cfl
+        self.CFL = cfl
+
+    def get_CFL(self):
+        return self.CFL
+    
+    def set_filename(self, name):
+        self.filename = name
+
+    def get_filename(self):
+        return self.filename
+
+    def get_limiter(self):
+        return self.limiter
+
+    def set_limiter(self,limiter):
+
+        possible_limiters = \
+        ['pyvolution', 'minmod_steve', 'minmod', 'minmod_kurganov', 'superbee', 'vanleer', 'vanalbada']
+
+        if limiter in possible_limiters:
+            self.limiter = limiter
+            return
+
+        msg = '%s is an incorrect limiter type.\n'% limiter
+        msg += 'Possible types are: '+ ", ".join(["%s" % el for el in possible_limiters])
+        raise Exception, msg
+
+        
+    #--------------------------
+    # Main components of evolve
+    #--------------------------    
+
+    def evolve(self, yieldstep = None,
+               finaltime = None,
+               duration = None,
+               skip_initial_step = False):
+        """Evolve model through time starting from self.starttime.
+
+
+        yieldstep: Interval between yields where results are stored,
+                   statistics written and domain inspected or
+                   possibly modified. If omitted the internal predefined
+                   max timestep is used.
+                   Internally, smaller timesteps may be taken.
+
+        duration: Duration of simulation
+
+        finaltime: Time where simulation should end. This is currently
+        relative time.  So it's the same as duration.
+
+        If both duration and finaltime are given an exception is thrown.
+
+
+        skip_initial_step: Boolean flag that decides whether the first
+        yield step is skipped or not. This is useful for example to avoid
+        duplicate steps when multiple evolve processes are dove tailed.
+
+
+        Evolve is implemented as a generator and is to be called as such, e.g.
+
+        for t in domain.evolve(yieldstep, finaltime):
+            <Do something with domain and t>
+
+
+        All times are given in seconds
+
+        """
+
+        from config import min_timestep, max_timestep, epsilon
+
+        # FIXME: Maybe lump into a larger check prior to evolving
+        msg = 'Boundary tags must be bound to boundary objects before '
+        msg += 'evolving system, '
+        msg += 'e.g. using the method set_boundary.\n'
+        msg += 'This system has the boundary tags %s '\
+               %self.get_boundary_tags()
+        assert hasattr(self, 'boundary_objects'), msg
+
+
+        if yieldstep is None:
+            yieldstep = max_timestep
+        else:
+            yieldstep = float(yieldstep)
+
+        self._order_ = self.default_order
+
+
+        if finaltime is not None and duration is not None:
+            # print 'F', finaltime, duration
+            msg = 'Only one of finaltime and duration may be specified'
+            raise msg
+        else:
+            if finaltime is not None:
+                self.finaltime = float(finaltime)
+            if duration is not None:
+                self.finaltime = self.starttime + float(duration)
+
+
+
+        N = len(self) # Number of triangles
+        self.yieldtime = 0.0 # Track time between 'yields'
+
+        # Initialise interval of timestep sizes (for reporting only)
+        self.min_timestep = max_timestep
+        self.max_timestep = min_timestep
+        self.number_of_steps = 0
+        self.number_of_first_order_steps = 0
+
+
+        # Update ghosts
+        self.update_ghosts()
+
+        # Initial update of vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        # Update extrema if necessary (for reporting)
+        self.update_extrema()
+        
+        # Initial update boundary values
+        self.update_boundary()
+
+        # Or maybe restore from latest checkpoint
+        if self.checkpoint is True:
+            self.goto_latest_checkpoint()
+
+        if skip_initial_step is False:
+            yield(self.time)  # Yield initial values
+
+        while True:
+
+            # Evolve One Step, using appropriate timestepping method
+            if self.get_timestepping_method() == 'euler':
+                self.evolve_one_euler_step(yieldstep,finaltime)
+                
+            elif self.get_timestepping_method() == 'rk2':
+                self.evolve_one_rk2_step(yieldstep,finaltime)
+
+            elif self.get_timestepping_method() == 'rk3':
+                self.evolve_one_rk3_step(yieldstep,finaltime)               
+
+            
+            # Update extrema if necessary (for reporting)
+            self.update_extrema()            
+
+
+            
+            self.yieldtime += self.timestep
+            self.number_of_steps += 1
+            if self._order_ == 1:
+                self.number_of_first_order_steps += 1
+
+
+            # Yield results
+            if finaltime is not None and self.time >= finaltime-epsilon:
+
+                if self.time > finaltime:
+                    # FIXME (Ole, 30 April 2006): Do we need this check?
+                    # Probably not (Ole, 18 September 2008). Now changed to
+                    # Exception
+                    msg = 'WARNING (domain.py): time overshot finaltime. '
+                    msg += 'Contact Ole.Nielsen@ga.gov.au'
+                    raise Exception, msg
+                    
+
+                # Yield final time and stop
+                self.time = finaltime
+                yield(self.time)
+                break
+
+            if self.yieldtime >= yieldstep:
+                # Yield (intermediate) time and allow inspection of domain
+
+                if self.checkpoint is True:
+                    self.store_checkpoint()
+                    self.delete_old_checkpoints()
+
+                # Pass control on to outer loop for more specific actions
+
+                yield(self.time)
+
+                # Reinitialise
+                self.yieldtime = 0.0
+                self.min_timestep = max_timestep
+                self.max_timestep = min_timestep
+                self.number_of_steps = 0
+                self.number_of_first_order_steps = 0
+                #self.max_speed_array = 0.0
+
+
+    def evolve_one_euler_step(self, yieldstep, finaltime):
+        """
+        One Euler Time Step
+        Q^{n+1} = E(h) Q^n
+        """
+
+
+        # Compute fluxes across each element edge
+        self.compute_fluxes()
+
+        # Update timestep to fit yieldstep and finaltime
+        self.update_timestep(yieldstep, finaltime)
+
+        # Update conserved quantities
+        self.update_conserved_quantities()
+
+        # Update ghosts
+        self.update_ghosts()
+
+        # Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        # Update boundary values
+        self.update_boundary()
+
+        # Update time
+        self.time += self.timestep
+
+        
+
+
+    def evolve_one_rk2_step(self, yieldstep, finaltime):
+        """
+        One 2nd order RK timestep
+        Q^{n+1} = 0.5 Q^n + 0.5 E(h)^2 Q^n
+        """
+
+        # Save initial conserved quantities values
+        self.backup_conserved_quantities()            
+
+        #--------------------------------------
+        # First euler step
+        #--------------------------------------
+
+        # Compute fluxes across each element edge
+        self.compute_fluxes()
+
+        # Update timestep to fit yieldstep and finaltime
+        self.update_timestep(yieldstep, finaltime)
+
+        # Update conserved quantities
+        self.update_conserved_quantities()
+
+        # Update ghosts
+        self.update_ghosts()
+
+        # Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        # Update boundary values
+        self.update_boundary()
+
+        # Update time
+        self.time += self.timestep
+
+        #------------------------------------
+        # Second Euler step
+        #------------------------------------
+            
+        # Compute fluxes across each element edge
+        self.compute_fluxes()
+
+        # Update conserved quantities
+        self.update_conserved_quantities()
+
+        #------------------------------------
+        # Combine initial and final values
+        # of conserved quantities and cleanup
+        #------------------------------------
+        
+        # Combine steps
+        self.saxpy_conserved_quantities(0.5, 0.5)
+
+        #-----------------------------------
+        # clean up vertex values
+        #-----------------------------------
+ 
+        # Update ghosts
+        self.update_ghosts()
+
+        # Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        # Update boundary values
+        self.update_boundary()
+
+
+
+    def evolve_one_rk3_step(self, yieldstep, finaltime):
+        """
+        One 3rd order RK timestep
+        Q^(1) = 3/4 Q^n + 1/4 E(h)^2 Q^n  (at time t^n + h/2)
+        Q^{n+1} = 1/3 Q^n + 2/3 E(h) Q^(1) (at time t^{n+1})
+        """
+
+        # Save initial initial conserved quantities values
+        self.backup_conserved_quantities()            
+
+        initial_time = self.time
+        
+        #--------------------------------------
+        # First euler step
+        #--------------------------------------
+
+        # Compute fluxes across each element edge
+        self.compute_fluxes()
+
+        # Update timestep to fit yieldstep and finaltime
+        self.update_timestep(yieldstep, finaltime)
+
+        # Update conserved quantities
+        self.update_conserved_quantities()
+
+        # Update ghosts
+        self.update_ghosts()
+
+        # Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        # Update boundary values
+        self.update_boundary()
+
+        # Update time
+        self.time += self.timestep
+
+        #------------------------------------
+        # Second Euler step
+        #------------------------------------
+            
+        # Compute fluxes across each element edge
+        self.compute_fluxes()
+
+        # Update conserved quantities
+        self.update_conserved_quantities()
+
+        #------------------------------------
+        #Combine steps to obtain intermediate
+        #solution at time t^n + 0.5 h
+        #------------------------------------
+
+        # Combine steps
+        self.saxpy_conserved_quantities(0.25, 0.75)
+ 
+        # Update ghosts
+        self.update_ghosts()
+
+        # Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        # Update boundary values
+        self.update_boundary()
+
+        # Set substep time
+        self.time = initial_time + self.timestep*0.5
+
+        #------------------------------------
+        # Third Euler step
+        #------------------------------------
+            
+        # Compute fluxes across each element edge
+        self.compute_fluxes()
+
+        # Update conserved quantities
+        self.update_conserved_quantities()
+
+        #------------------------------------
+        # Combine final and initial values
+        # and cleanup
+        #------------------------------------
+        
+        # Combine steps
+        self.saxpy_conserved_quantities(2.0/3.0, 1.0/3.0)
+ 
+        # Update ghosts
+        self.update_ghosts()
+
+        # Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        # Update boundary values
+        self.update_boundary()
+
+        # Set new time
+        self.time = initial_time + self.timestep       
+        
+
+    def backup_conserved_quantities(self):
+        N = len(self) # Number_of_triangles
+
+        # Backup conserved_quantities centroid values
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            Q.backup_centroid_values()        
+
+    def saxpy_conserved_quantities(self,a,b):
+        N = len(self) #number_of_triangles
+
+        # Backup conserved_quantities centroid values
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            Q.saxpy_centroid_values(a,b)        
+
+
+    #==============================
+    # John Jakeman's old evolve code
+    #=============================
+
+    def evolve_john(self, yieldstep = None, finaltime = None,
+               skip_initial_step = False):
+        """Evolve model from time=0.0 to finaltime yielding results
+        every yieldstep.
+
+        Internally, smaller timesteps may be taken.
+
+        Evolve is implemented as a generator and is to be called as such, e.g.
+
+        for t in domain.evolve(timestep, yieldstep, finaltime):
+            <Do something with domain and t>
+
+        """
+
+        from config import min_timestep, max_timestep, epsilon
+
+        #FIXME: Maybe lump into a larger check prior to evolving
+        msg = 'Boundary tags must be bound to boundary objects before evolving system, '
+        msg += 'e.g. using the method set_boundary.\n'
+        msg += 'This system has the boundary tags %s ' %self.get_boundary_tags()
+        assert hasattr(self, 'boundary_objects'), msg
+
+        # #self.set_defaults()
+
+        if yieldstep is None:
+            yieldstep = max_timestep
+        else:
+            yieldstep = float(yieldstep)
+
+        self.order = self.default_order
+        
+        self.time_order = self.default_time_order
+
+        self.yieldtime = 0.0 #Time between 'yields'
+
+        #Initialise interval of timestep sizes (for reporting only)
+        # SEEMS WIERD
+        self.min_timestep = max_timestep
+        self.max_timestep = min_timestep
+        self.finaltime = finaltime
+        self.number_of_steps = 0
+        self.number_of_first_order_steps = 0
+        
+        #update ghosts
+        self.update_ghosts()
+    
+        #Initial update of vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        #Initial update boundary values
+        self.update_boundary()
+
+        #Or maybe restore from latest checkpoint
+        if self.checkpoint is True:
+            self.goto_latest_checkpoint()
+
+        if skip_initial_step is False:
+            yield(self.time)  #Yield initial values   
+
+        while True:
+            if self.time_order == 1:
+                #Compute fluxes across each element edge
+                self.compute_fluxes()
+                #Update timestep to fit yieldstep and finaltime
+                self.update_timestep(yieldstep, finaltime)
+                #Compute forcing terms
+                self.compute_forcing_terms()
+                #Update conserved quantities
+                self.update_conserved_quantities(self.timestep)
+                #update ghosts
+                #self.update_ghosts()
+                #Update vertex and edge values
+                self.distribute_to_vertices_and_edges()                
+                #Update boundary values
+                self.update_boundary()
+
+            elif self.time_order == 2:
+                
+                self.compute_timestep() #self.compute_fluxes()
+
+                #Solve inhomogeneous operator for half a timestep
+                self.solve_inhomogenous_second_order(yieldstep, finaltime)
+                
+                #Solve homogeneous operator for full timestep using
+                #Harten second order timestepping
+                self.solve_homogenous_second_order(yieldstep,finaltime)
+
+                #Solve inhomogeneous operator for half a timestep
+                self.solve_inhomogenous_second_order(yieldstep, finaltime)
+                
+            #Update time
+            self.time += self.timestep
+            self.yieldtime += self.timestep
+            self.number_of_steps += 1
+            if self.order == 1:
+                self.number_of_first_order_steps += 1
+
+            #Yield results
+            if finaltime is not None and abs(self.time - finaltime) < epsilon:
+
+	        #FIXME: There is a rare situation where the
+	        #final time step is stored twice. Can we make a test?
+
+                # Yield final time and stop
+                yield(self.time)
+                break
+
+
+            if abs(self.yieldtime - yieldstep) < epsilon:
+                # Yield (intermediate) time and allow inspection of domain
+
+                if self.checkpoint is True:
+                    self.store_checkpoint()
+                    self.delete_old_checkpoints()
+
+                #Pass control on to outer loop for more specific actions
+                yield(self.time)
+
+                # Reinitialise
+                self.yieldtime = 0.0
+                self.min_timestep = max_timestep
+                self.max_timestep = min_timestep
+                self.number_of_steps = 0
+                self.number_of_first_order_steps = 0
+
+    def solve_inhomogenous_second_order(self,yieldstep, finaltime):
+
+        #Update timestep to fit yieldstep and finaltime
+        self.update_timestep(yieldstep, finaltime)
+        #Compute forcing terms
+        self.compute_forcing_terms()
+        #Update conserved quantities
+        self.update_conserved_quantities(0.5*self.timestep)
+        #Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+        #Update boundary values
+        self.update_boundary()
+
+    def  solve_homogenous_second_order(self,yieldstep,finaltime):
+        """Use Shu Second order timestepping to update
+        conserved quantities
+
+        q^{n+1/2} = q^{n}+0.5*dt*F^{n}
+        q^{n+1} = q^{n}+dt*F^{n+1/2}
+        """
+        import copy
+        from Numeric import zeros,Float
+
+        N = self.number_of_elements
+
+        self.compute_fluxes()
+        #Update timestep to fit yieldstep and finaltime
+        self.update_timestep(yieldstep, finaltime)
+        #Compute forcing terms
+        #NOT NEEDED FOR 2ND ORDER STRANG SPLIITING
+        #ADDING THIS WILL NEED TO REMOVE ZEROING IN COMPUTE_FORCING
+        #self.compute_forcing_terms()
+
+        QC = zeros((N,len(self.conserved_quantities)),Float)
+        QF = zeros((N,len(self.conserved_quantities)),Float)
+
+        i = 0
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            #Store the centroid values at time t^n
+            QC[:,i] = copy.copy(Q.centroid_values)
+            QF[:,i] = copy.copy(Q.explicit_update)
+            #Update conserved quantities
+            Q.update(self.timestep)
+            i+=1
+            
+        #Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+        #Update boundary values
+        self.update_boundary()
+        
+        self.compute_fluxes()
+        self.update_timestep(yieldstep, finaltime)
+        #Compute forcing terms
+        #NOT NEEDED FOR 2ND ORDER STRANG SPLIITING
+        #self.compute_forcing_terms()
+
+        i = 0
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            Q.centroid_values = QC[:,i]
+            Q.explicit_update = 0.5*(Q.explicit_update+QF[:,i]) 
+            #Update conserved quantities
+            Q.update(self.timestep)
+            i+=1
+        
+        #Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+        #Update boundary values
+        self.update_boundary()
+
+    def  solve_homogenous_second_order_harten(self,yieldstep,finaltime):
+        """Use Harten Second order timestepping to update
+        conserved quantities
+
+        q^{n+1/2} = q^{n}+0.5*dt*F^{n}
+        q^{n+1} = q^{n}+dt*F^{n+1/2}
+        """
+        import copy
+        from Numeric import zeros,Float
+
+        N = self.number_of_elements
+
+        self.compute_fluxes()
+        #Update timestep to fit yieldstep and finaltime
+        self.update_timestep(yieldstep, finaltime)
+        #Compute forcing terms
+        #NOT NEEDED FOR 2ND ORDER STRANG SPLIITING
+        #ADDING THIS WILL NEED TO REMOVE ZEROING IN COMPUTE_FORCING
+        #self.compute_forcing_terms()
+
+        QC = zeros((N,len(self.conserved_quantities)),Float)
+
+        i = 0
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            #Store the centroid values at time t^n
+            QC[:,i] = copy.copy(Q.centroid_values)
+            #Update conserved quantities
+            Q.update(0.5*self.timestep)
+            i+=1
+            
+        #Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+        #Update boundary values
+        self.update_boundary()
+        
+        self.compute_fluxes()
+        self.update_timestep(yieldstep, finaltime)
+        #Compute forcing terms
+        #NOT NEEDED FOR 2ND ORDER STRANG SPLIITING
+        #self.compute_forcing_terms()
+
+        i = 0
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            Q.centroid_values = QC[:,i] 
+            #Update conserved quantities
+            Q.update(self.timestep)
+            i+=1
+        
+        #Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+        #Update boundary values
+        self.update_boundary()
+        
+    def distribute_to_vertices_and_edges(self):
+        """Extrapolate conserved quantities from centroid to
+        vertices and edge-midpoints for each volume
+
+        Default implementation is straight first order,
+        i.e. constant values throughout each element and
+        no reference to non-conserved quantities.
+        """
+
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            if self.order == 1:
+                Q.extrapolate_first_order()
+            elif self.order == 2:
+                Q.extrapolate_second_order()
+                #Q.limit()
+            else:
+                raise 'Unknown order'
+            #Q.interpolate_from_vertices_to_edges()
+
+
+    def update_ghosts(self):
+        pass
+    
+    def update_boundary(self):
+        """Go through list of boundary objects and update boundary values
+        for all conserved quantities on boundary.
+        """
+        for i, ((vol_id, vertex_id), B) in enumerate(self.boundary_objects):
+            q = B.evaluate(vol_id, vertex_id)
+            for j, name in enumerate(self.evolved_quantities): #name in enumerate(self.conserved_quantities):
+                #print 'name %s j = %f \n'%(name,j)
+                Q = self.quantities[name]
+                Q.boundary_values[i] = q[j]
+                
+    
+    def update_timestep(self, yieldstep, finaltime):
+
+        from config import min_timestep, max_timestep
+
+        # self.timestep is calculated from speed of characteristics
+        # Apply CFL condition here
+        timestep = min(self.CFL*self.flux_timestep, max_timestep)
+
+        #Record maximal and minimal values of timestep for reporting
+        self.max_timestep = max(timestep, self.max_timestep)
+        self.min_timestep = min(timestep, self.min_timestep)
+
+        #Protect against degenerate time steps
+        if timestep < min_timestep:
+
+            #Number of consecutive small steps taken b4 taking action
+            self.smallsteps += 1
+
+            if self.smallsteps > self.max_smallsteps:
+                self.smallsteps = 0 #Reset
+
+                if self.order == 1:
+                    msg = 'WARNING: Too small timestep %.16f reached '\
+                          %timestep
+                    msg += 'even after %d steps of 1 order scheme'\
+                           %self.max_smallsteps
+                    print msg
+                    timestep = min_timestep  #Try enforcing min_step
+
+                    #raise msg
+                else:
+                    #Try to overcome situation by switching to 1 order
+                    print "changing Order 1"
+                    self.order = 1
+
+        else:
+            self.smallsteps = 0
+            if self.order == 1 and self.default_order == 2:
+                self.order = 2
+
+
+        #Ensure that final time is not exceeded
+        if finaltime is not None and self.time + timestep > finaltime:
+            timestep = finaltime-self.time
+
+        #Ensure that model time is aligned with yieldsteps
+        if self.yieldtime + timestep > yieldstep:
+            timestep = yieldstep-self.yieldtime
+
+        self.timestep = timestep
+
+    def update_extrema(self):
+        pass
+
+    def compute_forcing_terms(self):
+        """If there are any forcing functions driving the system
+        they should be defined in Domain subclass and appended to
+        the list self.forcing_terms
+        """
+        #Clears explicit_update needed for second order method
+        if self.time_order == 2:
+            for name in self.conserved_quantities:
+                Q = self.quantities[name]
+                Q.explicit_update[:] = 0.0
+
+        for f in self.forcing_terms:
+            f(self)
+            
+
+    def update_derived_quantites(self):
+        pass
+    
+    #def update_conserved_quantities(self):
+    def update_conserved_quantities(self):
+        """Update vectors of conserved quantities using previously
+        computed fluxes specified forcing functions.
+        """
+
+        from Numeric import ones, sum, equal, Float
+
+        N = self.number_of_elements
+        d = len(self.conserved_quantities)
+
+        timestep = self.timestep
+
+        #Compute forcing terms
+        self.compute_forcing_terms()
+
+        #Update conserved_quantities
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            Q.update(timestep)
+
+
+
+if __name__ == "__main__":
+
+    points1 = [0.0, 1.0, 2.0, 3.0]
+    D1 = Domain(points1)
+
+    print D1.get_coordinate(0)
+    print D1.get_coordinate(0,1)
+    print 'Number of Elements = ',D1.number_of_elements
+
+    try:
+        print D1.get_coordinate(3)
+    except:
+        pass
+    else:
+        msg =  'Should have raised an out of bounds exception'
+        raise msg
+
+    #points2 = [0.0, 1.0, 2.0, 3.0, 2.5]
+    #D2 = Domain(points2)
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/domain.py.bak
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/domain.py.bak	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/domain.py.bak	(revision 7576)
@@ -0,0 +1,1613 @@
+"""Class Domain - 1D domains for finite-volume computations of
+   the shallow water wave equation
+
+
+   Copyright 2004
+   Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+   Geoscience Australia
+"""
+
+from generic_boundary_conditions import *
+
+
+class Domain:
+
+    def __init__(self,
+                 coordinates,
+                 boundary = None,
+                 conserved_quantities = None,
+                 evolved_quantities = None,
+                 other_quantities = None,
+                 tagged_elements = None):
+        """
+        Build 1D elements from x coordinates
+        """
+
+        from Numeric import array, zeros, Float, Int
+
+        from config import timestepping_method
+        from config import CFL
+        
+        #Store Points
+        self.coordinates = array(coordinates)
+
+
+        #Register number of Elements
+        self.number_of_elements = N = len(self.coordinates)-1
+
+        self.beta = 1.0
+        self.set_limiter("minmod_kurganov")
+        self.set_CFL(CFL)
+        self.set_timestepping_method(timestepping_method)
+
+        self.wet_nodes = zeros((N,2), Int) # should this be here
+
+        #Allocate space for neighbour and boundary structures
+        self.neighbours = zeros((N, 2), Int)
+        #self.neighbour_edges = zeros((N, 2), Int)
+        self.neighbour_vertices = zeros((N, 2), Int)
+        self.number_of_boundaries = zeros(N, Int)
+        self.surrogate_neighbours = zeros((N, 2), Int)
+        
+        #Allocate space for geometric quantities
+        self.vertices  = zeros((N, 2), Float)
+        self.centroids = zeros(N, Float)
+        self.areas     = zeros(N, Float)
+
+        self.max_speed_array = zeros(N, Float)
+      
+
+        self.normals = zeros((N, 2), Float)
+        
+        for i in range(N):
+            xl = self.coordinates[i]
+            xr = self.coordinates[i+1]
+            self.vertices[i,0] = xl
+            self.vertices[i,1] = xr
+
+            centroid = (xl+xr)/2.0
+            self.centroids[i] = centroid
+
+            msg = 'Coordinates should be ordered, smallest to largest'
+            assert xr>xl, msg
+            
+            #The normal vectors
+            # - point outward from each edge
+            # - are orthogonal to the edge
+            # - have unit length
+            # - Are enumerated by left vertex then right vertex normals
+
+            nl = -1.0
+            nr =  1.0
+            self.normals[i,:] = [nl, nr]
+
+            self.areas[i] = (xr-xl)
+            
+# #         print 'N', N
+# #         print 'Centroid', self.centroids
+# #         print 'Areas', self.areas
+# #         print 'Vertex_Coordinates', self.vertices
+            
+            #Initialise Neighbours (-1 means that it is a boundary neighbour)
+            self.neighbours[i, :] = [-1, -1]
+            #Initialise edge ids of neighbours
+            #Initialise vertex ids of neighbours
+            #In case of boundaries this slot is not used
+            #self.neighbour_edges[i, :] = [-1, -1]
+            self.neighbour_vertices[i, :] = [-1, -1]
+
+        self.build_vertexlist()
+
+        #Build neighbour structure
+        self.build_neighbour_structure()
+
+        #Build surrogate neighbour structure
+        self.build_surrogate_neighbour_structure()          
+
+        #Build boundary dictionary mapping (id, edge) to symbolic tags
+        #Build boundary dictionary mapping (id, vertex) to symbolic tags
+        self.build_boundary_dictionary(boundary)
+
+        #Build tagged element  dictionary mapping (tag) to array of elements
+        self.build_tagged_elements_dictionary(tagged_elements)
+        
+        from quantity import Quantity, Conserved_quantity
+        #from quantity_domain import Quantity, Conserved_quantity
+        
+        #List of quantity names entering
+        #the conservation equations
+        #(Must be a subset of quantities)
+        if conserved_quantities is None:
+            self.conserved_quantities = []
+        else:
+            self.conserved_quantities = conserved_quantities
+
+        if evolved_quantities is None:
+            self.evolved_quantities = self.conserved_quantities
+        else:
+            self.evolved_quantities = evolved_quantities
+
+        if other_quantities is None:
+            self.other_quantities = []
+        else:
+            self.other_quantities = other_quantities
+
+
+        #Build dictionary of Quantity instances keyed by quantity names
+        self.quantities = {}
+
+        #print self.conserved_quantities
+        #print self.evolved_quantities
+        
+
+        #FIXME: remove later - maybe OK, though....
+        for name in self.evolved_quantities:
+            self.quantities[name] = Quantity(self)
+        for name in self.other_quantities:
+            self.quantities[name] = Quantity(self)
+
+        #Create an empty list for explicit forcing terms
+        self.forcing_terms = []
+
+        #Defaults
+        from config import max_smallsteps, beta_w, beta_h, epsilon, CFL
+        self.beta_w = beta_w
+        self.beta_h = beta_h
+        self.epsilon = epsilon
+
+        #FIXME: Maybe have separate orders for h-limiter and w-limiter?
+        #Or maybe get rid of order altogether and use beta_w and beta_h
+        self.default_order = 1
+        self.order = self.default_order
+
+        self.default_time_order = 1
+        self.time_order = self.default_time_order
+        
+        self.smallsteps = 0
+        self.max_smallsteps = max_smallsteps
+        self.number_of_steps = 0
+        self.number_of_first_order_steps = 0
+
+        #Model time
+        self.time = 0.0
+        self.finaltime = None
+        self.min_timestep = self.max_timestep = 0.0
+        self.starttime = 0 #Physical starttime if any (0 is 1 Jan 1970 00:00:00)
+        #Checkpointing and storage
+        from config import default_datadir
+        self.set_datadir(default_datadir)
+        self.filename = 'domain'
+        self.checkpoint = False
+
+    def __len__(self):
+        return self.number_of_elements
+
+    def build_vertexlist(self):
+        """Build vertexlist index by vertex ids and for each entry (point id)
+        build a list of (triangles, vertex_id) pairs that use the point
+        as vertex.
+
+        Preconditions:
+          self.coordinates and self.triangles are defined
+
+        Postcondition:
+          self.vertexlist is built
+        """
+        from Numeric import array
+
+        vertexlist = [None]*len(self.coordinates)
+        for i in range(self.number_of_elements):
+
+            #a = self.triangles[i, 0]
+            #b = self.triangles[i, 1]
+            #c = self.triangles[i, 2]
+            a = i
+            b = i + 1
+
+            #Register the vertices v as lists of
+            #(triangle_id, vertex_id) tuples associated with them
+            #This is used for smoothing
+            #for vertex_id, v in enumerate([a,b,c]):
+            for vertex_id, v in enumerate([a,b]):
+                if vertexlist[v] is None:
+                    vertexlist[v] = []
+
+                vertexlist[v].append( (i, vertex_id) )
+
+        self.vertexlist = vertexlist
+
+        
+    def build_neighbour_structure(self):
+        """Update all registered triangles to point to their neighbours.
+
+        Also, keep a tally of the number of boundaries for each triangle
+
+        Postconditions:
+          neighbours and neighbour_edges is populated
+          neighbours and neighbour_vertices is populated
+          number_of_boundaries integer array is defined.
+        """
+
+        #Step 1:
+        #Build dictionary mapping from segments (2-tuple of points)
+        #to left hand side edge (facing neighbouring triangle)
+
+        N = self.number_of_elements
+        neighbourdict = {}
+        #l_edge = 0
+        #r_edge = 1
+        l_vertex = 0
+        r_vertex = 1
+        for i in range(N):
+
+            #Register all segments as keys mapping to current triangle
+            #and segment id
+            #a = self.triangles[i, 0]
+            #b = self.triangles[i, 1]
+            #c = self.triangles[i, 2]
+            a = self.vertices[i,0]
+            b = self.vertices[i,1]
+            
+            """
+            if neighbourdict.has_key((a,b)):
+                    msg = "Edge 2 of triangle %d is duplicating edge %d of triangle %d.\n" %(i,neighbourdict[a,b][1],neighbourdict[a,b][0])
+                    raise msg
+            if neighbourdict.has_key((b,c)):
+                    msg = "Edge 0 of triangle %d is duplicating edge %d of triangle %d.\n" %(i,neighbourdict[b,c][1],neighbourdict[b,c][0])
+                    raise msg
+            if neighbourdict.has_key((c,a)):
+                    msg = "Edge 1 of triangle %d is duplicating edge %d of triangle %d.\n" %(i,neighbourdict[c,a][1],neighbourdict[c,a][0])
+                    raise msg
+                    """
+            #neighbourdict[a,b] = (i, 2) #(id, edge)
+            #neighbourdict[b,c] = (i, 0) #(id, edge)
+            #neighbourdict[c,a] = (i, 1) #(id, edge)
+            #neighbourdict[a,b] = (i, 1) #(id, edge)
+            #neighbourdict[b,a] = (i, 0) #(id, edge)
+            #neighbourdict[a,l_edge] = (i, 0) #(id, edge)
+            #neighbourdict[b,r_edge] = (i, 1) #(id, edge)
+            neighbourdict[a,l_vertex] = (i, 0) #(id, vertex)
+            neighbourdict[b,r_vertex] = (i, 1) #(id, vertex)
+
+
+        #Step 2:
+        #Go through triangles again, but this time
+        #reverse direction of segments and lookup neighbours.
+        for i in range(N):
+            #a = self.triangles[i, 0]
+            #b = self.triangles[i, 1]
+            #c = self.triangles[i, 2]
+            
+            a = self.vertices[i,0]
+            b = self.vertices[i,1]
+            
+            #self.number_of_boundaries[i] = 3
+            self.number_of_boundaries[i] = 2
+            #if neighbourdict.has_key((b,l_edge)):
+            if neighbourdict.has_key((b,l_vertex)):
+                #self.neighbours[i, 1] = neighbourdict[b,l_edge][0]
+                #self.neighbour_edges[i, 1] = neighbourdict[b,l_edge][1]
+                self.neighbours[i, 1] = neighbourdict[b,l_vertex][0]
+                self.neighbour_vertices[i, 1] = neighbourdict[b,l_vertex][1]
+                self.number_of_boundaries[i] -= 1
+
+            #if neighbourdict.has_key((a,r_edge)):
+            if neighbourdict.has_key((a,r_vertex)):
+                #self.neighbours[i, 0] = neighbourdict[a,r_edge][0]
+                #self.neighbour_edges[i, 0] = neighbourdict[a,r_edge][1]
+                self.neighbours[i, 0] = neighbourdict[a,r_vertex][0]
+                self.neighbour_vertices[i, 0] = neighbourdict[a,r_vertex][1]
+                self.number_of_boundaries[i] -= 1
+                
+            #if neighbourdict.has_key((b,a)):
+            #    self.neighbours[i, 1] = neighbourdict[b,a][0]
+            #    self.neighbour_edges[i, 1] = neighbourdict[b,a][1]
+            #    self.number_of_boundaries[i] -= 1
+
+            #if neighbourdict.has_key((c,b)):
+            #    self.neighbours[i, 0] = neighbourdict[c,b][0]
+            #    self.neighbour_edges[i, 0] = neighbourdict[c,b][1]
+            #    self.number_of_boundaries[i] -= 1
+
+            #if neighbourdict.has_key((a,b)):
+            #    self.neighbours[i, 0] = neighbourdict[a,b][0]
+            #    self.neighbour_edges[i, 0] = neighbourdict[a,b][1]
+            #    self.number_of_boundaries[i] -= 1
+
+    def build_surrogate_neighbour_structure(self):
+        """Build structure where each triangle edge points to its neighbours
+        if they exist. Otherwise point to the triangle itself.
+
+        The surrogate neighbour structure is useful for computing gradients
+        based on centroid values of neighbours.
+
+        Precondition: Neighbour structure is defined
+        Postcondition:
+          Surrogate neighbour structure is defined:
+          surrogate_neighbours: i0, i1, i2 where all i_k >= 0 point to
+          triangles.
+
+        """
+
+        N = self.number_of_elements
+        for i in range(N):
+            #Find all neighbouring volumes that are not boundaries
+            #for k in range(3):
+            for k in range(2):    
+                if self.neighbours[i, k] < 0:
+                    self.surrogate_neighbours[i, k] = i #Point this triangle
+                else:
+                    self.surrogate_neighbours[i, k] = self.neighbours[i, k]
+
+    def build_boundary_dictionary(self, boundary = None):
+        """Build or check the dictionary of boundary tags.
+         self.boundary is a dictionary of tags,
+         keyed by volume id and edge:
+         { (id, edge): tag, ... }
+
+         Postconditions:
+            self.boundary is defined.
+        """
+
+        from config import default_boundary_tag
+
+        if boundary is None:
+            boundary = {}
+            for vol_id in range(self.number_of_elements):
+                #for edge_id in range(0, 3):
+                #for edge_id in range(0, 2):
+                for vertex_id in range(0, 2):    
+                    #if self.neighbours[vol_id, edge_id] < 0:
+                    if self.neighbours[vol_id, vertex_id] < 0:   
+                        #boundary[(vol_id, edge_id)] = default_boundary_tag
+                        boundary[(vol_id, vertex_id)] = default_boundary_tag
+        else:
+            #Check that all keys in given boundary exist
+            #for vol_id, edge_id in boundary.keys():
+            for vol_id, vertex_id in boundary.keys():    
+                #msg = 'Segment (%d, %d) does not exist' %(vol_id, edge_id)
+                msg = 'Segment (%d, %d) does not exist' %(vol_id, vertex_id)
+                a, b = self.neighbours.shape
+                #assert vol_id < a and edge_id < b, msg
+                assert vol_id < a and vertex_id < b, msg
+
+                #FIXME: This assert violates internal boundaries (delete it)
+                #msg = 'Segment (%d, %d) is not a boundary' %(vol_id, edge_id)
+                #assert self.neighbours[vol_id, edge_id] < 0, msg
+
+            #Check that all boundary segments are assigned a tag
+            for vol_id in range(self.number_of_elements):
+                #for edge_id in range(0, 3):
+                #for edge_id in range(0, 2):
+                for vertex_id in range(0, 2):    
+                    #if self.neighbours[vol_id, edge_id] < 0:
+                    if self.neighbours[vol_id, vertex_id] < 0:    
+                        #if not boundary.has_key( (vol_id, edge_id) ):
+                        if not boundary.has_key( (vol_id, vertex_id) ):    
+                            msg = 'WARNING: Given boundary does not contain '
+                            #msg += 'tags for edge (%d, %d). '\
+                            #       %(vol_id, edge_id)
+                            msg += 'tags for vertex (%d, %d). '\
+                                   %(vol_id, vertex_id)
+                            msg += 'Assigning default tag (%s).'\
+                                   %default_boundary_tag
+
+                            #FIXME: Print only as per verbosity
+                            #print msg
+
+                            #FIXME: Make this situation an error in the future
+                            #and make another function which will
+                            #enable default boundary-tags where
+                            #tags a not specified
+                            #boundary[ (vol_id, edge_id) ] =\
+                            boundary[ (vol_id, vertex_id) ] =\
+                                      default_boundary_tag
+
+
+
+        self.boundary = boundary
+
+    def build_tagged_elements_dictionary(self, tagged_elements = None):
+        """Build the dictionary of element tags.
+         self.tagged_elements is a dictionary of element arrays,
+         keyed by tag:
+         { (tag): [e1, e2, e3..] }
+
+         Postconditions:
+            self.element_tag is defined
+        """
+        from Numeric import array, Int
+
+        if tagged_elements is None:
+            tagged_elements = {}
+        else:
+            #Check that all keys in given boundary exist
+            for tag in tagged_elements.keys():
+                tagged_elements[tag] = array(tagged_elements[tag]).astype(Int)
+
+                msg = 'Not all elements exist. '
+                assert max(tagged_elements[tag]) < self.number_of_elements, msg
+        #print "tagged_elements", tagged_elements
+        self.tagged_elements = tagged_elements
+
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+
+
+
+    def get_boundary_tags(self):
+        """Return list of available boundary tags
+        """
+
+        tags = {}
+        for v in self.boundary.values():
+            tags[v] = 1
+
+        return tags.keys()
+        
+    def get_vertex_coordinates(self, obj = False):
+        """Return all vertex coordinates.
+        Return all vertex coordinates for all triangles as an Nx6 array
+        (ordered as x0, y0, x1, y1, x2, y2 for each triangle)
+
+        if obj is True, the x/y pairs are returned in a 3*N x 2 array.
+        FIXME, we might make that the default.
+        FIXME Maybe use keyword: continuous = False for this condition?
+
+        
+        """
+
+        if obj is True:
+            from Numeric import concatenate, reshape
+            #V = self.vertex_coordinates
+            V = self.vertices
+            #return concatenate( (V[:,0:2], V[:,2:4], V[:,4:6]), axis=0)
+
+            N = V.shape[0]
+            #return reshape(V, (3*N, 2))
+            return reshape(V, (N, 2))
+        else:    
+            #return self.vertex_coordinates
+            return self.vertices
+    
+    def get_conserved_quantities(self, vol_id, vertex=None):#, edge=None):
+        """Get conserved quantities at volume vol_id
+
+        If vertex is specified use it as index for vertex values
+        If edge is specified use it as index for edge values
+        If neither are specified use centroid values
+        If both are specified an exeception is raised
+
+        Return value: Vector of length == number_of_conserved quantities
+
+        """
+
+        from Numeric import zeros, Float
+
+        #if not (vertex is None):# or edge is None):
+        #    msg = 'Values for both vertex and edge was specified.'
+        #    msg += 'Only one (or none) is allowed.'
+       #     raise msg
+
+        q = zeros( len(self.conserved_quantities), Float)
+
+        for i, name in enumerate(self.conserved_quantities):
+            Q = self.quantities[name]
+            if vertex is not None:
+                q[i] = Q.vertex_values[vol_id, vertex]
+            #elif edge is not None:
+            #    q[i] = Q.edge_values[vol_id, edge]
+            else:
+                q[i] = Q.centroid_values[vol_id]
+
+        return q
+
+
+    def get_evolved_quantities(self, vol_id, vertex=None):#, edge=None):
+        """Get evolved quantities at volume vol_id
+
+        If vertex is specified use it as index for vertex values
+        If edge is specified use it as index for edge values
+        If neither are specified use centroid values
+        If both are specified an exeception is raised
+
+        Return value: Vector of length == number_of_evolved quantities
+
+        """
+
+        from Numeric import zeros, Float
+
+        #if not (vertex is None):# or edge is None):
+        #    msg = 'Values for both vertex and edge was specified.'
+        #    msg += 'Only one (or none) is allowed.'
+       #     raise msg
+
+        q = zeros( len(self.evolved_quantities), Float)
+
+        for i, name in enumerate(self.evolved_quantities):
+            Q = self.quantities[name]
+            if vertex is not None:
+                q[i] = Q.vertex_values[vol_id, vertex]
+            #elif edge is not None:
+            #    q[i] = Q.edge_values[vol_id, edge]
+            else:
+                q[i] = Q.centroid_values[vol_id]
+
+        return q
+        
+
+    def get_centroids(self):
+        """Return all coordinates of centroids
+        Return x coordinate of centroid for each element as a N array
+        """
+
+        return self.centroids
+
+    def get_vertices(self):
+        """Return all coordinates of centroids
+        Return x coordinate of centroid for each element as a N array
+        """
+
+        return self.vertices
+
+    def get_coordinate(self, elem_id, vertex=None):
+        """Return coordinate of centroid,
+        or left or right vertex.
+        Left vertex (vertex=0). Right vertex (vertex=1)
+        """
+
+        if vertex is None:
+            return self.centroids[elem_id]
+        else:
+            return self.vertices[elem_id,vertex]
+
+    def get_area(self, elem_id):
+        """Return area of element id
+        """
+
+        return self.areas[elem_id]
+
+    def get_quantity(self, name, location='vertices', indices = None):
+        """Get values for named quantity
+
+        name: Name of quantity
+
+        In case of location == 'centroids' the dimension values must
+        be a list of a Numerical array of length N, N being the number
+        of elements. Otherwise it must be of dimension Nx3.
+
+        Indices is the set of element ids that the operation applies to.
+
+        The values will be stored in elements following their
+        internal ordering.
+        """
+
+        return self.quantities[name].get_values( location, indices = indices)
+
+    def get_centroid_coordinates(self):
+        """Return all centroid coordinates.
+        Return all centroid coordinates for all triangles as an Nx2 array
+        (ordered as x0, y0 for each triangle)
+        """
+        return self.centroids
+
+
+    def get_timestepping_method(self):
+        return self.timestepping_method
+
+    def set_timestepping_method(self,timestepping_method):
+        
+        if timestepping_method in ['euler', 'rk2', 'rk3']:
+            self.timestepping_method = timestepping_method
+            return
+
+        msg = '%s is an incorrect timestepping type'% timestepping_method
+        raise Exception, msg
+
+
+    def set_quantity(self, name, *args, **kwargs):
+        """Set values for named quantity
+
+
+        One keyword argument is documented here:
+        expression = None, # Arbitrary expression
+
+        expression:
+          Arbitrary expression involving quantity names
+
+        See Quantity.set_values for further documentation.
+        """
+
+        #FIXME (Ole): Allow new quantities here
+        #from quantity import Quantity, Conserved_quantity
+        #Create appropriate quantity object
+        # #if name in self.conserved_quantities:
+        # #    self.quantities[name] = Conserved_quantity(self)
+        # #else:
+        # #    self.quantities[name] = Quantity(self)
+
+
+        #Do the expression stuff
+        if kwargs.has_key('expression'):
+            expression = kwargs['expression']
+            del kwargs['expression']
+
+            Q = self.create_quantity_from_expression(expression)
+            kwargs['quantity'] = Q
+        
+        #Assign values
+        self.quantities[name].set_values(*args, **kwargs)
+
+    def set_boundary(self, boundary_map):
+        """Associate boundary objects with tagged boundary segments.
+
+        Input boundary_map is a dictionary of boundary objects keyed
+        by symbolic tags to matched against tags in the internal dictionary
+        self.boundary.
+
+        As result one pointer to a boundary object is stored for each vertex
+        in the list self.boundary_objects.
+        More entries may point to the same boundary object
+
+        Schematically the mapping is from two dictionaries to one list
+        where the index is used as pointer to the boundary_values arrays
+        within each quantity.
+
+        self.boundary:          (vol_id, edge_id): tag
+        boundary_map (input):   tag: boundary_object
+        ----------------------------------------------
+        self.boundary_objects:  ((vol_id, edge_id), boundary_object)
+
+
+        Pre-condition:
+          self.boundary has been built.
+
+        Post-condition:
+          self.boundary_objects is built
+
+        If a tag from the domain doesn't appear in the input dictionary an
+        exception is raised.
+        However, if a tag is not used to the domain, no error is thrown.
+        FIXME: This would lead to implementation of a
+        default boundary condition
+
+        Note: If a segment is listed in the boundary dictionary and if it is
+        not None, it *will* become a boundary -
+        even if there is a neighbouring triangle.
+        This would be the case for internal boundaries
+
+        Boundary objects that are None will be skipped.
+
+        FIXME: If set_boundary is called multiple times and if Boundary
+        object is changed into None, the neighbour structure will not be
+        restored!!!
+        """
+
+        self.boundary_objects = []
+        self.boundary_map = boundary_map  #Store for use with eg. boundary_stats.
+
+        #FIXME: Try to remove the sorting and fix test_mesh.py
+        x = self.boundary.keys()
+        x.sort()
+
+        #Loop through edges that lie on the boundary and associate them with
+        #callable boundary objects depending on their tags
+        #for k, (vol_id, edge_id) in enumerate(x):
+        for k, (vol_id, vertex_id) in enumerate(x):
+            #tag = self.boundary[ (vol_id, edge_id) ]
+            tag = self.boundary[ (vol_id, vertex_id) ]
+
+            if boundary_map.has_key(tag):
+                B = boundary_map[tag]  #Get callable boundary object
+
+                if B is not None:
+                    #self.boundary_objects.append( ((vol_id, edge_id), B) )
+                    #self.neighbours[vol_id, edge_id] = -len(self.boundary_objects)
+                    self.boundary_objects.append( ((vol_id, vertex_id), B) )
+                    self.neighbours[vol_id, vertex_id] = -len(self.boundary_objects)
+                else:
+                    pass
+                    #FIXME: Check and perhaps fix neighbour structure
+
+            else:
+                msg = 'ERROR (domain.py): Tag "%s" has not been ' %tag
+                msg += 'bound to a boundary object.\n'
+                msg += 'All boundary tags defined in domain must appear '
+                msg += 'in the supplied dictionary.\n'
+                msg += 'The tags are: %s' %self.get_boundary_tags()
+                raise msg
+
+
+
+    def check_integrity(self):
+        #Mesh.check_integrity(self)
+
+        #print self.quantities
+        #print self.conserved_quantities
+        
+        for quantity in self.conserved_quantities:
+            msg = 'Conserved quantities must be a subset of all quantities'
+            assert quantity in self.quantities, msg
+
+        for quantity in self.evolved_quantities:
+            msg = 'Evolved quantities must be a subset of all quantities'
+            assert quantity in self.quantities, msg            
+
+        # #assert hasattr(self, 'boundary_objects')
+
+    def write_time(self):
+        print self.timestepping_statistics()
+
+    def timestepping_statistics(self):
+        """Return string with time stepping statistics for printing or logging
+        """
+
+        msg = ''
+        if self.min_timestep == self.max_timestep:
+            msg += 'Time = %.4f, delta t = %.8f, steps=%d (%d)'\
+                   %(self.time, self.min_timestep, self.number_of_steps,
+                     self.number_of_first_order_steps)
+        elif self.min_timestep > self.max_timestep:
+            msg += 'Time = %.4f, steps=%d (%d)'\
+                   %(self.time, self.number_of_steps,
+                     self.number_of_first_order_steps)
+        else:
+            msg += 'Time = %.4f, delta t in [%.8f, %.8f], steps=%d (%d)'\
+                   %(self.time, self.min_timestep,
+                     self.max_timestep, self.number_of_steps,
+                     self.number_of_first_order_steps)
+
+        return msg
+
+    def get_name(self):
+        return self.filename
+
+    def set_name(self, name):
+        self.filename = name
+
+    def get_datadir(self):
+        return self.datadir
+
+    def set_datadir(self, name):
+        self.datadir = name
+
+    def set_CFL(self, cfl):
+        if cfl > 1.0:
+            print 'WARNING: Setting CFL condition to %f which is greater than 1' % cfl
+        self.CFL = cfl
+
+    def get_CFL(self):
+        return self.CFL
+    
+    def set_filename(self, name):
+        self.filename = name
+
+    def get_filename(self):
+        return self.filename
+
+    def get_limiter(self):
+        return self.limiter
+
+    def set_limiter(self,limiter):
+
+        possible_limiters = \
+        ['pyvolution', 'minmod_steve', 'minmod', 'minmod_kurganov', 'superbee', 'vanleer', 'vanalbada']
+
+        if limiter in possible_limiters:
+            self.limiter = limiter
+            return
+
+        msg = '%s is an incorrect limiter type.\n'% limiter
+        msg += 'Possible types are: '+ ", ".join(["%s" % el for el in possible_limiters])
+        raise Exception, msg
+
+        
+    #--------------------------
+    # Main components of evolve
+    #--------------------------    
+
+    def evolve(self, yieldstep = None,
+               finaltime = None,
+               duration = None,
+               skip_initial_step = False):
+        """Evolve model through time starting from self.starttime.
+
+
+        yieldstep: Interval between yields where results are stored,
+                   statistics written and domain inspected or
+                   possibly modified. If omitted the internal predefined
+                   max timestep is used.
+                   Internally, smaller timesteps may be taken.
+
+        duration: Duration of simulation
+
+        finaltime: Time where simulation should end. This is currently
+        relative time.  So it's the same as duration.
+
+        If both duration and finaltime are given an exception is thrown.
+
+
+        skip_initial_step: Boolean flag that decides whether the first
+        yield step is skipped or not. This is useful for example to avoid
+        duplicate steps when multiple evolve processes are dove tailed.
+
+
+        Evolve is implemented as a generator and is to be called as such, e.g.
+
+        for t in domain.evolve(yieldstep, finaltime):
+            <Do something with domain and t>
+
+
+        All times are given in seconds
+
+        """
+
+        from config import min_timestep, max_timestep, epsilon
+
+        # FIXME: Maybe lump into a larger check prior to evolving
+        msg = 'Boundary tags must be bound to boundary objects before '
+        msg += 'evolving system, '
+        msg += 'e.g. using the method set_boundary.\n'
+        msg += 'This system has the boundary tags %s '\
+               %self.get_boundary_tags()
+        assert hasattr(self, 'boundary_objects'), msg
+
+
+        if yieldstep is None:
+            yieldstep = max_timestep
+        else:
+            yieldstep = float(yieldstep)
+
+        self._order_ = self.default_order
+
+
+        if finaltime is not None and duration is not None:
+            # print 'F', finaltime, duration
+            msg = 'Only one of finaltime and duration may be specified'
+            raise msg
+        else:
+            if finaltime is not None:
+                self.finaltime = float(finaltime)
+            if duration is not None:
+                self.finaltime = self.starttime + float(duration)
+
+
+
+        N = len(self) # Number of triangles
+        self.yieldtime = 0.0 # Track time between 'yields'
+
+        # Initialise interval of timestep sizes (for reporting only)
+        self.min_timestep = max_timestep
+        self.max_timestep = min_timestep
+        self.number_of_steps = 0
+        self.number_of_first_order_steps = 0
+
+
+        # Update ghosts
+        self.update_ghosts()
+
+        # Initial update of vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        # Update extrema if necessary (for reporting)
+        self.update_extrema()
+        
+        # Initial update boundary values
+        self.update_boundary()
+
+        # Or maybe restore from latest checkpoint
+        if self.checkpoint is True:
+            self.goto_latest_checkpoint()
+
+        if skip_initial_step is False:
+            yield(self.time)  # Yield initial values
+
+        while True:
+
+            # Evolve One Step, using appropriate timestepping method
+            if self.get_timestepping_method() == 'euler':
+                self.evolve_one_euler_step(yieldstep,finaltime)
+                
+            elif self.get_timestepping_method() == 'rk2':
+                self.evolve_one_rk2_step(yieldstep,finaltime)
+
+            elif self.get_timestepping_method() == 'rk3':
+                self.evolve_one_rk3_step(yieldstep,finaltime)               
+
+            
+            # Update extrema if necessary (for reporting)
+            self.update_extrema()            
+
+
+            
+            self.yieldtime += self.timestep
+            self.number_of_steps += 1
+            if self._order_ == 1:
+                self.number_of_first_order_steps += 1
+
+
+            # Yield results
+            if finaltime is not None and self.time >= finaltime-epsilon:
+
+                if self.time > finaltime:
+                    # FIXME (Ole, 30 April 2006): Do we need this check?
+                    # Probably not (Ole, 18 September 2008). Now changed to
+                    # Exception
+                    msg = 'WARNING (domain.py): time overshot finaltime. '
+                    msg += 'Contact Ole.Nielsen@ga.gov.au'
+                    raise Exception, msg
+                    
+
+                # Yield final time and stop
+                self.time = finaltime
+                yield(self.time)
+                break
+
+            if self.yieldtime >= yieldstep:
+                # Yield (intermediate) time and allow inspection of domain
+
+                if self.checkpoint is True:
+                    self.store_checkpoint()
+                    self.delete_old_checkpoints()
+
+                # Pass control on to outer loop for more specific actions
+
+                yield(self.time)
+
+                # Reinitialise
+                self.yieldtime = 0.0
+                self.min_timestep = max_timestep
+                self.max_timestep = min_timestep
+                self.number_of_steps = 0
+                self.number_of_first_order_steps = 0
+                #self.max_speed_array = 0.0
+
+
+    def evolve_one_euler_step(self, yieldstep, finaltime):
+        """
+        One Euler Time Step
+        Q^{n+1} = E(h) Q^n
+        """
+
+
+        # Compute fluxes across each element edge
+        self.compute_fluxes()
+
+        # Update timestep to fit yieldstep and finaltime
+        self.update_timestep(yieldstep, finaltime)
+
+        # Update conserved quantities
+        self.update_conserved_quantities()
+
+        # Update ghosts
+        self.update_ghosts()
+
+        # Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        # Update boundary values
+        self.update_boundary()
+
+        # Update time
+        self.time += self.timestep
+
+        
+
+
+    def evolve_one_rk2_step(self, yieldstep, finaltime):
+        """
+        One 2nd order RK timestep
+        Q^{n+1} = 0.5 Q^n + 0.5 E(h)^2 Q^n
+        """
+
+        # Save initial conserved quantities values
+        self.backup_conserved_quantities()            
+
+        #--------------------------------------
+        # First euler step
+        #--------------------------------------
+
+        # Compute fluxes across each element edge
+        self.compute_fluxes()
+
+        # Update timestep to fit yieldstep and finaltime
+        self.update_timestep(yieldstep, finaltime)
+
+        # Update conserved quantities
+        self.update_conserved_quantities()
+
+        # Update ghosts
+        self.update_ghosts()
+
+        # Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        # Update boundary values
+        self.update_boundary()
+
+        # Update time
+        self.time += self.timestep
+
+        #------------------------------------
+        # Second Euler step
+        #------------------------------------
+            
+        # Compute fluxes across each element edge
+        self.compute_fluxes()
+
+        # Update conserved quantities
+        self.update_conserved_quantities()
+
+        #------------------------------------
+        # Combine initial and final values
+        # of conserved quantities and cleanup
+        #------------------------------------
+        
+        # Combine steps
+        self.saxpy_conserved_quantities(0.5, 0.5)
+
+        #-----------------------------------
+        # clean up vertex values
+        #-----------------------------------
+ 
+        # Update ghosts
+        self.update_ghosts()
+
+        # Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        # Update boundary values
+        self.update_boundary()
+
+
+
+    def evolve_one_rk3_step(self, yieldstep, finaltime):
+        """
+        One 3rd order RK timestep
+        Q^(1) = 3/4 Q^n + 1/4 E(h)^2 Q^n  (at time t^n + h/2)
+        Q^{n+1} = 1/3 Q^n + 2/3 E(h) Q^(1) (at time t^{n+1})
+        """
+
+        # Save initial initial conserved quantities values
+        self.backup_conserved_quantities()            
+
+        initial_time = self.time
+        
+        #--------------------------------------
+        # First euler step
+        #--------------------------------------
+
+        # Compute fluxes across each element edge
+        self.compute_fluxes()
+
+        # Update timestep to fit yieldstep and finaltime
+        self.update_timestep(yieldstep, finaltime)
+
+        # Update conserved quantities
+        self.update_conserved_quantities()
+
+        # Update ghosts
+        self.update_ghosts()
+
+        # Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        # Update boundary values
+        self.update_boundary()
+
+        # Update time
+        self.time += self.timestep
+
+        #------------------------------------
+        # Second Euler step
+        #------------------------------------
+            
+        # Compute fluxes across each element edge
+        self.compute_fluxes()
+
+        # Update conserved quantities
+        self.update_conserved_quantities()
+
+        #------------------------------------
+        #Combine steps to obtain intermediate
+        #solution at time t^n + 0.5 h
+        #------------------------------------
+
+        # Combine steps
+        self.saxpy_conserved_quantities(0.25, 0.75)
+ 
+        # Update ghosts
+        self.update_ghosts()
+
+        # Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        # Update boundary values
+        self.update_boundary()
+
+        # Set substep time
+        self.time = initial_time + self.timestep*0.5
+
+        #------------------------------------
+        # Third Euler step
+        #------------------------------------
+            
+        # Compute fluxes across each element edge
+        self.compute_fluxes()
+
+        # Update conserved quantities
+        self.update_conserved_quantities()
+
+        #------------------------------------
+        # Combine final and initial values
+        # and cleanup
+        #------------------------------------
+        
+        # Combine steps
+        self.saxpy_conserved_quantities(2.0/3.0, 1.0/3.0)
+ 
+        # Update ghosts
+        self.update_ghosts()
+
+        # Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        # Update boundary values
+        self.update_boundary()
+
+        # Set new time
+        self.time = initial_time + self.timestep       
+        
+
+    def backup_conserved_quantities(self):
+        N = len(self) # Number_of_triangles
+
+        # Backup conserved_quantities centroid values
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            Q.backup_centroid_values()        
+
+    def saxpy_conserved_quantities(self,a,b):
+        N = len(self) #number_of_triangles
+
+        # Backup conserved_quantities centroid values
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            Q.saxpy_centroid_values(a,b)        
+
+
+    #==============================
+    # John Jakeman's old evolve code
+    #=============================
+
+    def evolve_john(self, yieldstep = None, finaltime = None,
+               skip_initial_step = False):
+        """Evolve model from time=0.0 to finaltime yielding results
+        every yieldstep.
+
+        Internally, smaller timesteps may be taken.
+
+        Evolve is implemented as a generator and is to be called as such, e.g.
+
+        for t in domain.evolve(timestep, yieldstep, finaltime):
+            <Do something with domain and t>
+
+        """
+
+        from config import min_timestep, max_timestep, epsilon
+
+        #FIXME: Maybe lump into a larger check prior to evolving
+        msg = 'Boundary tags must be bound to boundary objects before evolving system, '
+        msg += 'e.g. using the method set_boundary.\n'
+        msg += 'This system has the boundary tags %s ' %self.get_boundary_tags()
+        assert hasattr(self, 'boundary_objects'), msg
+
+        # #self.set_defaults()
+
+        if yieldstep is None:
+            yieldstep = max_timestep
+        else:
+            yieldstep = float(yieldstep)
+
+        self.order = self.default_order
+        
+        self.time_order = self.default_time_order
+
+        self.yieldtime = 0.0 #Time between 'yields'
+
+        #Initialise interval of timestep sizes (for reporting only)
+        # SEEMS WIERD
+        self.min_timestep = max_timestep
+        self.max_timestep = min_timestep
+        self.finaltime = finaltime
+        self.number_of_steps = 0
+        self.number_of_first_order_steps = 0
+        
+        #update ghosts
+        self.update_ghosts()
+    
+        #Initial update of vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        #Initial update boundary values
+        self.update_boundary()
+
+        #Or maybe restore from latest checkpoint
+        if self.checkpoint is True:
+            self.goto_latest_checkpoint()
+
+        if skip_initial_step is False:
+            yield(self.time)  #Yield initial values   
+
+        while True:
+            if self.time_order == 1:
+                #Compute fluxes across each element edge
+                self.compute_fluxes()
+                #Update timestep to fit yieldstep and finaltime
+                self.update_timestep(yieldstep, finaltime)
+                #Compute forcing terms
+                self.compute_forcing_terms()
+                #Update conserved quantities
+                self.update_conserved_quantities(self.timestep)
+                #update ghosts
+                #self.update_ghosts()
+                #Update vertex and edge values
+                self.distribute_to_vertices_and_edges()                
+                #Update boundary values
+                self.update_boundary()
+
+            elif self.time_order == 2:
+                
+                self.compute_timestep() #self.compute_fluxes()
+
+                #Solve inhomogeneous operator for half a timestep
+                self.solve_inhomogenous_second_order(yieldstep, finaltime)
+                
+                #Solve homogeneous operator for full timestep using
+                #Harten second order timestepping
+                self.solve_homogenous_second_order(yieldstep,finaltime)
+
+                #Solve inhomogeneous operator for half a timestep
+                self.solve_inhomogenous_second_order(yieldstep, finaltime)
+                
+            #Update time
+            self.time += self.timestep
+            self.yieldtime += self.timestep
+            self.number_of_steps += 1
+            if self.order == 1:
+                self.number_of_first_order_steps += 1
+
+            #Yield results
+            if finaltime is not None and abs(self.time - finaltime) < epsilon:
+
+	        #FIXME: There is a rare situation where the
+	        #final time step is stored twice. Can we make a test?
+
+                # Yield final time and stop
+                yield(self.time)
+                break
+
+
+            if abs(self.yieldtime - yieldstep) < epsilon:
+                # Yield (intermediate) time and allow inspection of domain
+
+                if self.checkpoint is True:
+                    self.store_checkpoint()
+                    self.delete_old_checkpoints()
+
+                #Pass control on to outer loop for more specific actions
+                yield(self.time)
+
+                # Reinitialise
+                self.yieldtime = 0.0
+                self.min_timestep = max_timestep
+                self.max_timestep = min_timestep
+                self.number_of_steps = 0
+                self.number_of_first_order_steps = 0
+
+    def solve_inhomogenous_second_order(self,yieldstep, finaltime):
+
+        #Update timestep to fit yieldstep and finaltime
+        self.update_timestep(yieldstep, finaltime)
+        #Compute forcing terms
+        self.compute_forcing_terms()
+        #Update conserved quantities
+        self.update_conserved_quantities(0.5*self.timestep)
+        #Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+        #Update boundary values
+        self.update_boundary()
+
+    def  solve_homogenous_second_order(self,yieldstep,finaltime):
+        """Use Shu Second order timestepping to update
+        conserved quantities
+
+        q^{n+1/2} = q^{n}+0.5*dt*F^{n}
+        q^{n+1} = q^{n}+dt*F^{n+1/2}
+        """
+        import copy
+        from Numeric import zeros,Float
+
+        N = self.number_of_elements
+
+        self.compute_fluxes()
+        #Update timestep to fit yieldstep and finaltime
+        self.update_timestep(yieldstep, finaltime)
+        #Compute forcing terms
+        #NOT NEEDED FOR 2ND ORDER STRANG SPLIITING
+        #ADDING THIS WILL NEED TO REMOVE ZEROING IN COMPUTE_FORCING
+        #self.compute_forcing_terms()
+
+        QC = zeros((N,len(self.conserved_quantities)),Float)
+        QF = zeros((N,len(self.conserved_quantities)),Float)
+
+        i = 0
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            #Store the centroid values at time t^n
+            QC[:,i] = copy.copy(Q.centroid_values)
+            QF[:,i] = copy.copy(Q.explicit_update)
+            #Update conserved quantities
+            Q.update(self.timestep)
+            i+=1
+            
+        #Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+        #Update boundary values
+        self.update_boundary()
+        
+        self.compute_fluxes()
+        self.update_timestep(yieldstep, finaltime)
+        #Compute forcing terms
+        #NOT NEEDED FOR 2ND ORDER STRANG SPLIITING
+        #self.compute_forcing_terms()
+
+        i = 0
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            Q.centroid_values = QC[:,i]
+            Q.explicit_update = 0.5*(Q.explicit_update+QF[:,i]) 
+            #Update conserved quantities
+            Q.update(self.timestep)
+            i+=1
+        
+        #Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+        #Update boundary values
+        self.update_boundary()
+
+    def  solve_homogenous_second_order_harten(self,yieldstep,finaltime):
+        """Use Harten Second order timestepping to update
+        conserved quantities
+
+        q^{n+1/2} = q^{n}+0.5*dt*F^{n}
+        q^{n+1} = q^{n}+dt*F^{n+1/2}
+        """
+        import copy
+        from Numeric import zeros,Float
+
+        N = self.number_of_elements
+
+        self.compute_fluxes()
+        #Update timestep to fit yieldstep and finaltime
+        self.update_timestep(yieldstep, finaltime)
+        #Compute forcing terms
+        #NOT NEEDED FOR 2ND ORDER STRANG SPLIITING
+        #ADDING THIS WILL NEED TO REMOVE ZEROING IN COMPUTE_FORCING
+        #self.compute_forcing_terms()
+
+        QC = zeros((N,len(self.conserved_quantities)),Float)
+
+        i = 0
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            #Store the centroid values at time t^n
+            QC[:,i] = copy.copy(Q.centroid_values)
+            #Update conserved quantities
+            Q.update(0.5*self.timestep)
+            i+=1
+            
+        #Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+        #Update boundary values
+        self.update_boundary()
+        
+        self.compute_fluxes()
+        self.update_timestep(yieldstep, finaltime)
+        #Compute forcing terms
+        #NOT NEEDED FOR 2ND ORDER STRANG SPLIITING
+        #self.compute_forcing_terms()
+
+        i = 0
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            Q.centroid_values = QC[:,i] 
+            #Update conserved quantities
+            Q.update(self.timestep)
+            i+=1
+        
+        #Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+        #Update boundary values
+        self.update_boundary()
+        
+    def distribute_to_vertices_and_edges(self):
+        """Extrapolate conserved quantities from centroid to
+        vertices and edge-midpoints for each volume
+
+        Default implementation is straight first order,
+        i.e. constant values throughout each element and
+        no reference to non-conserved quantities.
+        """
+
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            if self.order == 1:
+                Q.extrapolate_first_order()
+            elif self.order == 2:
+                Q.extrapolate_second_order()
+                #Q.limit()
+            else:
+                raise 'Unknown order'
+            #Q.interpolate_from_vertices_to_edges()
+
+
+    def update_ghosts(self):
+        pass
+    
+    def update_boundary(self):
+        """Go through list of boundary objects and update boundary values
+        for all conserved quantities on boundary.
+        """
+        for i, ((vol_id, vertex_id), B) in enumerate(self.boundary_objects):
+            q = B.evaluate(vol_id, vertex_id)
+            for j, name in enumerate(self.evolved_quantities): #name in enumerate(self.conserved_quantities):
+                #print 'name %s j = %f \n'%(name,j)
+                Q = self.quantities[name]
+                Q.boundary_values[i] = q[j]
+                
+    
+    def update_timestep(self, yieldstep, finaltime):
+
+        from config import min_timestep, max_timestep
+
+        # self.timestep is calculated from speed of characteristics
+        # Apply CFL condition here
+        timestep = min(self.CFL*self.flux_timestep, max_timestep)
+
+        #Record maximal and minimal values of timestep for reporting
+        self.max_timestep = max(timestep, self.max_timestep)
+        self.min_timestep = min(timestep, self.min_timestep)
+
+        #Protect against degenerate time steps
+        if timestep < min_timestep:
+
+            #Number of consecutive small steps taken b4 taking action
+            self.smallsteps += 1
+
+            if self.smallsteps > self.max_smallsteps:
+                self.smallsteps = 0 #Reset
+
+                if self.order == 1:
+                    msg = 'WARNING: Too small timestep %.16f reached '\
+                          %timestep
+                    msg += 'even after %d steps of 1 order scheme'\
+                           %self.max_smallsteps
+                    print msg
+                    timestep = min_timestep  #Try enforcing min_step
+
+                    #raise msg
+                else:
+                    #Try to overcome situation by switching to 1 order
+                    print "changing Order 1"
+                    self.order = 1
+
+        else:
+            self.smallsteps = 0
+            if self.order == 1 and self.default_order == 2:
+                self.order = 2
+
+
+        #Ensure that final time is not exceeded
+        if finaltime is not None and self.time + timestep > finaltime:
+            timestep = finaltime-self.time
+
+        #Ensure that model time is aligned with yieldsteps
+        if self.yieldtime + timestep > yieldstep:
+            timestep = yieldstep-self.yieldtime
+
+        self.timestep = timestep
+
+    def update_extrema(self):
+        pass
+
+    def compute_forcing_terms(self):
+        """If there are any forcing functions driving the system
+        they should be defined in Domain subclass and appended to
+        the list self.forcing_terms
+        """
+        #Clears explicit_update needed for second order method
+        if self.time_order == 2:
+            for name in self.conserved_quantities:
+                Q = self.quantities[name]
+                Q.explicit_update[:] = 0.0
+
+        for f in self.forcing_terms:
+            f(self)
+            
+
+    def update_derived_quantites(self):
+        pass
+    
+    #def update_conserved_quantities(self):
+    def update_conserved_quantities(self):
+        """Update vectors of conserved quantities using previously
+        computed fluxes specified forcing functions.
+        """
+
+        from Numeric import ones, sum, equal, Float
+
+        N = self.number_of_elements
+        d = len(self.conserved_quantities)
+
+        timestep = self.timestep
+
+        #Compute forcing terms
+        self.compute_forcing_terms()
+
+        #Update conserved_quantities
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            Q.update(timestep)
+
+
+
+if __name__ == "__main__":
+
+    points1 = [0.0, 1.0, 2.0, 3.0]
+    D1 = Domain(points1)
+
+    print D1.get_coordinate(0)
+    print D1.get_coordinate(0,1)
+    print 'Number of Elements = ',D1.number_of_elements
+
+    try:
+        print D1.get_coordinate(3)
+    except:
+        pass
+    else:
+        msg =  'Should have raised an out of bounds exception'
+        raise msg
+
+    #points2 = [0.0, 1.0, 2.0, 3.0, 2.5]
+    #D2 = Domain(points2)
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/domain_t2.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/domain_t2.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/domain_t2.py	(revision 7576)
@@ -0,0 +1,1112 @@
+"""Class Domain - 1D domains for finite-volume computations of
+   the shallow water wave equation
+
+
+   Copyright 2004
+   Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+   Geoscience Australia
+"""
+from generic_boundary_conditions import *
+from coordinate_transforms.geo_reference import Geo_reference
+
+class Domain:
+
+    def __init__(self, coordinates, boundary = None,
+                 conserved_quantities = None, other_quantities = None,
+                 tagged_elements = None, geo_reference = None):
+        """
+        Build 1D elements from x coordinates
+        """
+
+        from Numeric import array, zeros, Float, Int
+        
+        #Store Points
+        self.coordinates = array(coordinates)
+
+        if geo_reference is None:
+            self.geo_reference = Geo_reference() #Use defaults 
+        else:
+            self.geo_reference = geo_reference
+
+        #Register number of Elements
+        self.number_of_elements = N = len(self.coordinates)-1
+
+        self.beta = 1.0
+        self.limiter = "minmod_kurganov"
+        self.split = False
+        self.wet_nodes = zeros((N,2), Int) # should this be here
+
+        #Allocate space for neighbour and boundary structures
+        self.neighbours = zeros((N, 2), Int)
+        #self.neighbour_edges = zeros((N, 2), Int)
+        self.neighbour_vertices = zeros((N, 2), Int)
+        self.number_of_boundaries = zeros(N, Int)
+        self.surrogate_neighbours = zeros((N, 2), Int)
+        
+        #Allocate space for geometric quantities
+        self.vertices  = zeros((N, 2), Float)
+        self.centroids = zeros(N, Float)
+        self.areas     = zeros(N, Float)
+
+        self.normals = zeros((N, 2), Float)
+        
+        for i in range(N):
+            xl = self.coordinates[i]
+            xr = self.coordinates[i+1]
+            self.vertices[i,0] = xl
+            self.vertices[i,1] = xr
+
+            centroid = (xl+xr)/2.0
+            self.centroids[i] = centroid
+
+            msg = 'Coordinates should be ordered, smallest to largest'
+            assert xr>xl, msg
+            
+            #The normal vectors
+            # - point outward from each edge
+            # - are orthogonal to the edge
+            # - have unit length
+            # - Are enumerated by left vertex then right vertex normals
+
+            nl = -1.0
+            nr =  1.0
+            self.normals[i,:] = [nl, nr]
+
+            self.areas[i] = (xr-xl)
+            
+##         print 'N', N
+##         print 'Centroid', self.centroids
+##         print 'Areas', self.areas
+##         print 'Vertex_Coordinates', self.vertices
+            
+            #Initialise Neighbours (-1 means that it is a boundary neighbour)
+            self.neighbours[i, :] = [-1, -1]
+            #Initialise edge ids of neighbours
+            #Initialise vertex ids of neighbours
+            #In case of boundaries this slot is not used
+            #self.neighbour_edges[i, :] = [-1, -1]
+            self.neighbour_vertices[i, :] = [-1, -1]
+
+        self.build_vertexlist()
+
+        #Build neighbour structure
+        self.build_neighbour_structure()
+
+        #Build surrogate neighbour structure
+        self.build_surrogate_neighbour_structure()          
+
+        #Build boundary dictionary mapping (id, edge) to symbolic tags
+        #Build boundary dictionary mapping (id, vertex) to symbolic tags
+        self.build_boundary_dictionary(boundary)
+
+        #Build tagged element  dictionary mapping (tag) to array of elements
+        self.build_tagged_elements_dictionary(tagged_elements)
+        
+        from quantity import Quantity, Conserved_quantity
+        #from quantity_domain import Quantity, Conserved_quantity
+        
+        #List of quantity names entering
+        #the conservation equations
+        #(Must be a subset of quantities)
+        if conserved_quantities is None:
+            self.conserved_quantities = []
+        else:
+            self.conserved_quantities = conserved_quantities
+
+        if other_quantities is None:
+            self.other_quantities = []
+        else:
+            self.other_quantities = other_quantities
+
+
+        #Build dictionary of Quantity instances keyed by quantity names
+        self.quantities = {}
+
+        #FIXME: remove later - maybe OK, though....
+        for name in self.conserved_quantities:
+            self.quantities[name] = Conserved_quantity(self)
+        for name in self.other_quantities:
+            self.quantities[name] = Quantity(self)
+
+        #Create an empty list for explicit forcing terms
+        self.forcing_terms = []
+
+        #Defaults
+        from config import max_smallsteps, beta_w, beta_h, epsilon, CFL
+        self.beta_w = beta_w
+        self.beta_h = beta_h
+        self.epsilon = epsilon
+
+        #FIXME: Maybe have separate orders for h-limiter and w-limiter?
+        #Or maybe get rid of order altogether and use beta_w and beta_h
+        self.default_order = 1
+        self.order = self.default_order
+
+        self.default_time_order = 1
+        self.time_order = self.default_time_order
+        
+        self.smallsteps = 0
+        self.max_smallsteps = max_smallsteps
+        self.number_of_steps = 0
+        self.number_of_first_order_steps = 0
+        self.CFL = CFL
+
+        #Model time
+        self.time = 0.0
+        self.finaltime = None
+        self.min_timestep = self.max_timestep = 0.0
+        self.starttime = 0 #Physical starttime if any (0 is 1 Jan 1970 00:00:00)
+        #Checkpointing and storage
+        from config import default_datadir
+        self.datadir = default_datadir
+        self.filename = 'domain'
+        self.checkpoint = False
+
+    def __len__(self):
+        return self.number_of_elements
+
+    def build_vertexlist(self):
+        """Build vertexlist index by vertex ids and for each entry (point id)
+        build a list of (triangles, vertex_id) pairs that use the point
+        as vertex.
+
+        Preconditions:
+          self.coordinates and self.triangles are defined
+
+        Postcondition:
+          self.vertexlist is built
+        """
+        from Numeric import array
+
+        vertexlist = [None]*len(self.coordinates)
+        for i in range(self.number_of_elements):
+
+            #a = self.triangles[i, 0]
+            #b = self.triangles[i, 1]
+            #c = self.triangles[i, 2]
+            a = i
+            b = i + 1
+
+            #Register the vertices v as lists of
+            #(triangle_id, vertex_id) tuples associated with them
+            #This is used for smoothing
+            #for vertex_id, v in enumerate([a,b,c]):
+            for vertex_id, v in enumerate([a,b]):
+                if vertexlist[v] is None:
+                    vertexlist[v] = []
+
+                vertexlist[v].append( (i, vertex_id) )
+
+        self.vertexlist = vertexlist
+
+        
+    def build_neighbour_structure(self):
+        """Update all registered triangles to point to their neighbours.
+
+        Also, keep a tally of the number of boundaries for each triangle
+
+        Postconditions:
+          neighbours and neighbour_edges is populated
+          neighbours and neighbour_vertices is populated
+          number_of_boundaries integer array is defined.
+        """
+
+        #Step 1:
+        #Build dictionary mapping from segments (2-tuple of points)
+        #to left hand side edge (facing neighbouring triangle)
+
+        N = self.number_of_elements
+        neighbourdict = {}
+        #l_edge = 0
+        #r_edge = 1
+        l_vertex = 0
+        r_vertex = 1
+        for i in range(N):
+
+            #Register all segments as keys mapping to current triangle
+            #and segment id
+            #a = self.triangles[i, 0]
+            #b = self.triangles[i, 1]
+            #c = self.triangles[i, 2]
+            a = self.vertices[i,0]
+            b = self.vertices[i,1]
+            
+            """
+            if neighbourdict.has_key((a,b)):
+                    msg = "Edge 2 of triangle %d is duplicating edge %d of triangle %d.\n" %(i,neighbourdict[a,b][1],neighbourdict[a,b][0])
+                    raise msg
+            if neighbourdict.has_key((b,c)):
+                    msg = "Edge 0 of triangle %d is duplicating edge %d of triangle %d.\n" %(i,neighbourdict[b,c][1],neighbourdict[b,c][0])
+                    raise msg
+            if neighbourdict.has_key((c,a)):
+                    msg = "Edge 1 of triangle %d is duplicating edge %d of triangle %d.\n" %(i,neighbourdict[c,a][1],neighbourdict[c,a][0])
+                    raise msg
+                    """
+            #neighbourdict[a,b] = (i, 2) #(id, edge)
+            #neighbourdict[b,c] = (i, 0) #(id, edge)
+            #neighbourdict[c,a] = (i, 1) #(id, edge)
+            #neighbourdict[a,b] = (i, 1) #(id, edge)
+            #neighbourdict[b,a] = (i, 0) #(id, edge)
+            #neighbourdict[a,l_edge] = (i, 0) #(id, edge)
+            #neighbourdict[b,r_edge] = (i, 1) #(id, edge)
+            neighbourdict[a,l_vertex] = (i, 0) #(id, vertex)
+            neighbourdict[b,r_vertex] = (i, 1) #(id, vertex)
+
+
+        #Step 2:
+        #Go through triangles again, but this time
+        #reverse direction of segments and lookup neighbours.
+        for i in range(N):
+            #a = self.triangles[i, 0]
+            #b = self.triangles[i, 1]
+            #c = self.triangles[i, 2]
+            
+            a = self.vertices[i,0]
+            b = self.vertices[i,1]
+            
+            #self.number_of_boundaries[i] = 3
+            self.number_of_boundaries[i] = 2
+            #if neighbourdict.has_key((b,l_edge)):
+            if neighbourdict.has_key((b,l_vertex)):
+                #self.neighbours[i, 1] = neighbourdict[b,l_edge][0]
+                #self.neighbour_edges[i, 1] = neighbourdict[b,l_edge][1]
+                self.neighbours[i, 1] = neighbourdict[b,l_vertex][0]
+                self.neighbour_vertices[i, 1] = neighbourdict[b,l_vertex][1]
+                self.number_of_boundaries[i] -= 1
+
+            #if neighbourdict.has_key((a,r_edge)):
+            if neighbourdict.has_key((a,r_vertex)):
+                #self.neighbours[i, 0] = neighbourdict[a,r_edge][0]
+                #self.neighbour_edges[i, 0] = neighbourdict[a,r_edge][1]
+                self.neighbours[i, 0] = neighbourdict[a,r_vertex][0]
+                self.neighbour_vertices[i, 0] = neighbourdict[a,r_vertex][1]
+                self.number_of_boundaries[i] -= 1
+                
+            #if neighbourdict.has_key((b,a)):
+            #    self.neighbours[i, 1] = neighbourdict[b,a][0]
+            #    self.neighbour_edges[i, 1] = neighbourdict[b,a][1]
+            #    self.number_of_boundaries[i] -= 1
+
+            #if neighbourdict.has_key((c,b)):
+            #    self.neighbours[i, 0] = neighbourdict[c,b][0]
+            #    self.neighbour_edges[i, 0] = neighbourdict[c,b][1]
+            #    self.number_of_boundaries[i] -= 1
+
+            #if neighbourdict.has_key((a,b)):
+            #    self.neighbours[i, 0] = neighbourdict[a,b][0]
+            #    self.neighbour_edges[i, 0] = neighbourdict[a,b][1]
+            #    self.number_of_boundaries[i] -= 1
+
+    def build_surrogate_neighbour_structure(self):
+        """Build structure where each triangle edge points to its neighbours
+        if they exist. Otherwise point to the triangle itself.
+
+        The surrogate neighbour structure is useful for computing gradients
+        based on centroid values of neighbours.
+
+        Precondition: Neighbour structure is defined
+        Postcondition:
+          Surrogate neighbour structure is defined:
+          surrogate_neighbours: i0, i1, i2 where all i_k >= 0 point to
+          triangles.
+
+        """
+
+        N = self.number_of_elements
+        for i in range(N):
+            #Find all neighbouring volumes that are not boundaries
+            #for k in range(3):
+            for k in range(2):    
+                if self.neighbours[i, k] < 0:
+                    self.surrogate_neighbours[i, k] = i #Point this triangle
+                else:
+                    self.surrogate_neighbours[i, k] = self.neighbours[i, k]
+
+    def build_boundary_dictionary(self, boundary = None):
+        """Build or check the dictionary of boundary tags.
+         self.boundary is a dictionary of tags,
+         keyed by volume id and edge:
+         { (id, edge): tag, ... }
+
+         Postconditions:
+            self.boundary is defined.
+        """
+
+        from config import default_boundary_tag
+
+        if boundary is None:
+            boundary = {}
+            for vol_id in range(self.number_of_elements):
+                #for edge_id in range(0, 3):
+                #for edge_id in range(0, 2):
+                for vertex_id in range(0, 2):    
+                    #if self.neighbours[vol_id, edge_id] < 0:
+                    if self.neighbours[vol_id, vertex_id] < 0:   
+                        #boundary[(vol_id, edge_id)] = default_boundary_tag
+                        boundary[(vol_id, vertex_id)] = default_boundary_tag
+        else:
+            #Check that all keys in given boundary exist
+            #for vol_id, edge_id in boundary.keys():
+            for vol_id, vertex_id in boundary.keys():    
+                #msg = 'Segment (%d, %d) does not exist' %(vol_id, edge_id)
+                msg = 'Segment (%d, %d) does not exist' %(vol_id, vertex_id)
+                a, b = self.neighbours.shape
+                #assert vol_id < a and edge_id < b, msg
+                assert vol_id < a and vertex_id < b, msg
+
+                #FIXME: This assert violates internal boundaries (delete it)
+                #msg = 'Segment (%d, %d) is not a boundary' %(vol_id, edge_id)
+                #assert self.neighbours[vol_id, edge_id] < 0, msg
+
+            #Check that all boundary segments are assigned a tag
+            for vol_id in range(self.number_of_elements):
+                #for edge_id in range(0, 3):
+                #for edge_id in range(0, 2):
+                for vertex_id in range(0, 2):    
+                    #if self.neighbours[vol_id, edge_id] < 0:
+                    if self.neighbours[vol_id, vertex_id] < 0:    
+                        #if not boundary.has_key( (vol_id, edge_id) ):
+                        if not boundary.has_key( (vol_id, vertex_id) ):    
+                            msg = 'WARNING: Given boundary does not contain '
+                            #msg += 'tags for edge (%d, %d). '\
+                            #       %(vol_id, edge_id)
+                            msg += 'tags for vertex (%d, %d). '\
+                                   %(vol_id, vertex_id)
+                            msg += 'Assigning default tag (%s).'\
+                                   %default_boundary_tag
+
+                            #FIXME: Print only as per verbosity
+                            #print msg
+
+                            #FIXME: Make this situation an error in the future
+                            #and make another function which will
+                            #enable default boundary-tags where
+                            #tags a not specified
+                            #boundary[ (vol_id, edge_id) ] =\
+                            boundary[ (vol_id, vertex_id) ] =\
+                                      default_boundary_tag
+
+
+
+        self.boundary = boundary
+
+    def build_tagged_elements_dictionary(self, tagged_elements = None):
+        """Build the dictionary of element tags.
+         self.tagged_elements is a dictionary of element arrays,
+         keyed by tag:
+         { (tag): [e1, e2, e3..] }
+
+         Postconditions:
+            self.element_tag is defined
+        """
+        from Numeric import array, Int
+
+        if tagged_elements is None:
+            tagged_elements = {}
+        else:
+            #Check that all keys in given boundary exist
+            for tag in tagged_elements.keys():
+                tagged_elements[tag] = array(tagged_elements[tag]).astype(Int)
+
+                msg = 'Not all elements exist. '
+                assert max(tagged_elements[tag]) < self.number_of_elements, msg
+        #print "tagged_elements", tagged_elements
+        self.tagged_elements = tagged_elements
+
+    def get_boundary_tags(self):
+        """Return list of available boundary tags
+        """
+
+        tags = {}
+        for v in self.boundary.values():
+            tags[v] = 1
+
+        return tags.keys()
+        
+    def get_vertex_coordinates(self, obj = False):
+        """Return all vertex coordinates.
+        Return all vertex coordinates for all triangles as an Nx6 array
+        (ordered as x0, y0, x1, y1, x2, y2 for each triangle)
+
+        if obj is True, the x/y pairs are returned in a 3*N x 2 array.
+        FIXME, we might make that the default.
+        FIXME Maybe use keyword: continuous = False for this condition?
+
+        
+        """
+
+        if obj is True:
+            from Numeric import concatenate, reshape
+            #V = self.vertex_coordinates
+            V = self.vertices
+            #return concatenate( (V[:,0:2], V[:,2:4], V[:,4:6]), axis=0)
+
+            N = V.shape[0]
+            #return reshape(V, (3*N, 2))
+            return reshape(V, (N, 2))
+        else:    
+            #return self.vertex_coordinates
+            return self.vertices
+    
+    def get_conserved_quantities(self, vol_id, vertex=None):#, edge=None):
+        """Get conserved quantities at volume vol_id
+
+        If vertex is specified use it as index for vertex values
+        If edge is specified use it as index for edge values
+        If neither are specified use centroid values
+        If both are specified an exeception is raised
+
+        Return value: Vector of length == number_of_conserved quantities
+
+        """
+
+        from Numeric import zeros, Float
+
+        #if not (vertex is None):# or edge is None):
+        #    msg = 'Values for both vertex and edge was specified.'
+        #    msg += 'Only one (or none) is allowed.'
+       #     raise msg
+
+        q = zeros( len(self.conserved_quantities), Float)
+
+        for i, name in enumerate(self.conserved_quantities):
+            Q = self.quantities[name]
+            if vertex is not None:
+                q[i] = Q.vertex_values[vol_id, vertex]
+            #elif edge is not None:
+            #    q[i] = Q.edge_values[vol_id, edge]
+            else:
+                q[i] = Q.centroid_values[vol_id]
+
+        return q
+        
+
+    def get_centroids(self):
+        """Return all coordinates of centroids
+        Return x coordinate of centroid for each element as a N array
+        """
+
+        return self.centroids
+
+    def get_vertices(self):
+        """Return all coordinates of centroids
+        Return x coordinate of centroid for each element as a N array
+        """
+
+        return self.vertices
+
+    def get_coordinate(self, elem_id, vertex=None):
+        """Return coordinate of centroid,
+        or left or right vertex.
+        Left vertex (vertex=0). Right vertex (vertex=1)
+        """
+
+        if vertex is None:
+            return self.centroids[elem_id]
+        else:
+            return self.vertices[elem_id,vertex]
+
+    def get_area(self, elem_id):
+        """Return area of element id
+        """
+
+        return self.areas[elem_id]
+
+    def get_quantity(self, name, location='vertices', indices = None):
+        """Get values for named quantity
+
+        name: Name of quantity
+
+        In case of location == 'centroids' the dimension values must
+        be a list of a Numerical array of length N, N being the number
+        of elements. Otherwise it must be of dimension Nx3.
+
+        Indices is the set of element ids that the operation applies to.
+
+        The values will be stored in elements following their
+        internal ordering.
+        """
+
+        return self.quantities[name].get_values( location, indices = indices)
+
+    def get_centroid_coordinates(self):
+        """Return all centroid coordinates.
+        Return all centroid coordinates for all triangles as an Nx2 array
+        (ordered as x0, y0 for each triangle)
+        """
+        return self.centroids
+
+    def set_quantity(self, name, *args, **kwargs):
+        """Set values for named quantity
+
+
+        One keyword argument is documented here:
+        expression = None, # Arbitrary expression
+
+        expression:
+          Arbitrary expression involving quantity names
+
+        See Quantity.set_values for further documentation.
+        """
+
+        #FIXME (Ole): Allow new quantities here
+        #from quantity import Quantity, Conserved_quantity
+        #Create appropriate quantity object
+        ##if name in self.conserved_quantities:
+        ##    self.quantities[name] = Conserved_quantity(self)
+        ##else:
+        ##    self.quantities[name] = Quantity(self)
+
+
+        #Do the expression stuff
+        if kwargs.has_key('expression'):
+            expression = kwargs['expression']
+            del kwargs['expression']
+
+            Q = self.create_quantity_from_expression(expression)
+            kwargs['quantity'] = Q
+        
+        #Assign values
+        self.quantities[name].set_values(*args, **kwargs)
+
+    def set_boundary(self, boundary_map):
+        """Associate boundary objects with tagged boundary segments.
+
+        Input boundary_map is a dictionary of boundary objects keyed
+        by symbolic tags to matched against tags in the internal dictionary
+        self.boundary.
+
+        As result one pointer to a boundary object is stored for each vertex
+        in the list self.boundary_objects.
+        More entries may point to the same boundary object
+
+        Schematically the mapping is from two dictionaries to one list
+        where the index is used as pointer to the boundary_values arrays
+        within each quantity.
+
+        self.boundary:          (vol_id, edge_id): tag
+        boundary_map (input):   tag: boundary_object
+        ----------------------------------------------
+        self.boundary_objects:  ((vol_id, edge_id), boundary_object)
+
+
+        Pre-condition:
+          self.boundary has been built.
+
+        Post-condition:
+          self.boundary_objects is built
+
+        If a tag from the domain doesn't appear in the input dictionary an
+        exception is raised.
+        However, if a tag is not used to the domain, no error is thrown.
+        FIXME: This would lead to implementation of a
+        default boundary condition
+
+        Note: If a segment is listed in the boundary dictionary and if it is
+        not None, it *will* become a boundary -
+        even if there is a neighbouring triangle.
+        This would be the case for internal boundaries
+
+        Boundary objects that are None will be skipped.
+
+        FIXME: If set_boundary is called multiple times and if Boundary
+        object is changed into None, the neighbour structure will not be
+        restored!!!
+        """
+
+        self.boundary_objects = []
+        
+
+
+
+        
+        self.boundary_map = boundary_map  #Store for use with eg. boundary_stats.
+
+        #FIXME: Try to remove the sorting and fix test_mesh.py
+        x = self.boundary.keys()
+        x.sort()
+
+        #Loop through edges that lie on the boundary and associate them with
+        #callable boundary objects depending on their tags
+        #for k, (vol_id, edge_id) in enumerate(x):
+        for k, (vol_id, vertex_id) in enumerate(x):
+            #tag = self.boundary[ (vol_id, edge_id) ]
+            tag = self.boundary[ (vol_id, vertex_id) ]
+
+            if boundary_map.has_key(tag):
+                B = boundary_map[tag]  #Get callable boundary object
+
+                if B is not None:
+                    #self.boundary_objects.append( ((vol_id, edge_id), B) )
+                    #self.neighbours[vol_id, edge_id] = -len(self.boundary_objects)
+                    self.boundary_objects.append( ((vol_id, vertex_id), B) )
+                    self.neighbours[vol_id, vertex_id] = -len(self.boundary_objects)
+                else:
+                    pass
+                    #FIXME: Check and perhaps fix neighbour structure
+
+            else:
+                msg = 'ERROR (domain.py): Tag "%s" has not been ' %tag
+                msg += 'bound to a boundary object.\n'
+                msg += 'All boundary tags defined in domain must appear '
+                msg += 'in the supplied dictionary.\n'
+                msg += 'The tags are: %s' %self.get_boundary_tags()
+                raise msg
+
+
+
+    def check_integrity(self):
+        #Mesh.check_integrity(self)
+        
+        for quantity in self.conserved_quantities:
+            msg = 'Conserved quantities must be a subset of all quantities'
+            assert quantity in self.quantities, msg
+
+        ##assert hasattr(self, 'boundary_objects')
+
+    def write_time(self):
+        print self.timestepping_statistics()
+
+    def timestepping_statistics(self):
+        """Return string with time stepping statistics for printing or logging
+        """
+
+        msg = ''
+        if self.min_timestep == self.max_timestep:
+            msg += 'Time = %.4f, delta t = %.8f, steps=%d (%d)'\
+                   %(self.time, self.min_timestep, self.number_of_steps,
+                     self.number_of_first_order_steps)
+        elif self.min_timestep > self.max_timestep:
+            msg += 'Time = %.4f, steps=%d (%d)'\
+                   %(self.time, self.number_of_steps,
+                     self.number_of_first_order_steps)
+        else:
+            msg += 'Time = %.4f, delta t in [%.8f, %.8f], steps=%d (%d)'\
+                   %(self.time, self.min_timestep,
+                     self.max_timestep, self.number_of_steps,
+                     self.number_of_first_order_steps)
+
+        return msg
+
+    def get_name(self):
+        return self.filename
+
+    def set_name(self, name):
+        self.filename = name
+
+    def get_datadir(self):
+        return self.datadir
+
+    def set_datadir(self, name):
+        self.datadir = name
+
+#Main components of evolve
+    def evolve(self, yieldstep = None, finaltime = None,
+               skip_initial_step = False):
+        """Evolve model from time=0.0 to finaltime yielding results
+        every yieldstep.
+
+        Internally, smaller timesteps may be taken.
+
+        Evolve is implemented as a generator and is to be called as such, e.g.
+
+        for t in domain.evolve(timestep, yieldstep, finaltime):
+            <Do something with domain and t>
+
+        """
+
+        from config import min_timestep, max_timestep, epsilon
+
+        #FIXME: Maybe lump into a larger check prior to evolving
+        msg = 'Boundary tags must be bound to boundary objects before evolving system, '
+        msg += 'e.g. using the method set_boundary.\n'
+        msg += 'This system has the boundary tags %s ' %self.get_boundary_tags()
+        assert hasattr(self, 'boundary_objects'), msg
+
+        ##self.set_defaults()
+
+        if yieldstep is None:
+            yieldstep = max_timestep
+        else:
+            yieldstep = float(yieldstep)
+
+        self.order = self.default_order
+        self.time_order = self.default_time_order
+
+        self.yieldtime = 0.0 #Time between 'yields'
+
+        #Initialise interval of timestep sizes (for reporting only)
+        # SEEMS WIERD
+        self.min_timestep = max_timestep
+        self.max_timestep = min_timestep
+        self.finaltime = finaltime
+        self.number_of_steps = 0
+        self.number_of_first_order_steps = 0
+        
+        #update ghosts
+        #self.update_ghosts()
+    
+        #Initial update of vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        #Initial update boundary values
+        self.update_boundary()
+
+        #Or maybe restore from latest checkpoint
+        if self.checkpoint is True:
+            self.goto_latest_checkpoint()
+
+        if skip_initial_step is False:
+            yield(self.time)  #Yield initial values   
+
+        while True:
+            if self.time_order == 1:
+                #Compute fluxes across each element edge
+                self.compute_fluxes()
+                #Update timestep to fit yieldstep and finaltime
+                self.update_timestep(yieldstep, finaltime)
+                #Compute forcing terms
+                self.compute_forcing_terms()
+                #Update conserved quantities
+                self.update_conserved_quantities(self.timestep)
+                #update ghosts
+                #self.update_ghosts()
+                #Update vertex and edge values
+                self.distribute_to_vertices_and_edges()                
+                #Update boundary values
+                self.update_boundary()
+
+            elif self.time_order == 2:
+                
+                self.compute_timestep()
+
+                #Solve inhomogeneous operator for half a timestep
+                self.solve_inhomogenous_second_order(yieldstep, finaltime)
+                
+                #Solve homogeneous operator for full timestep using
+                #Harten second order timestepping
+                self.solve_homogenous_second_order(yieldstep,finaltime)
+
+                #Solve inhomogeneous operator for half a timestep
+                self.solve_inhomogenous_second_order(yieldstep, finaltime)
+                
+            #Update time
+            self.time += self.timestep
+            self.yieldtime += self.timestep
+            self.number_of_steps += 1
+            if self.order == 1:
+                self.number_of_first_order_steps += 1
+
+            #Yield results
+            if finaltime is not None and abs(self.time - finaltime) < epsilon:
+
+	        #FIXME: There is a rare situation where the
+	        #final time step is stored twice. Can we make a test?
+
+                # Yield final time and stop
+                yield(self.time)
+                break
+
+
+            if abs(self.yieldtime - yieldstep) < epsilon:
+                # Yield (intermediate) time and allow inspection of domain
+
+                if self.checkpoint is True:
+                    self.store_checkpoint()
+                    self.delete_old_checkpoints()
+
+                #Pass control on to outer loop for more specific actions
+                yield(self.time)
+
+                # Reinitialise
+                self.yieldtime = 0.0
+                self.min_timestep = max_timestep
+                self.max_timestep = min_timestep
+                self.number_of_steps = 0
+                self.number_of_first_order_steps = 0
+
+    def solve_inhomogenous_second_order(self,yieldstep, finaltime):
+
+        #Update timestep to fit yieldstep and finaltime
+        self.update_timestep(yieldstep, finaltime)
+        #Compute forcing terms
+        self.compute_forcing_terms()
+        #Update conserved quantities
+        self.update_conserved_quantities(0.5*self.timestep)
+        #Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+        #Update boundary values
+        self.update_boundary()
+
+    def  solve_homogenous_second_order(self,yieldstep,finaltime):
+        """Use Shu Second order timestepping to update
+        conserved quantities
+
+        q^{n+1/2} = q^{n}+0.5*dt*F^{n}
+        q^{n+1} = q^{n}+dt*F^{n+1/2}
+        """
+        import copy
+        from Numeric import zeros,Float
+
+        N = self.number_of_elements
+
+        self.compute_fluxes()
+        #Update timestep to fit yieldstep and finaltime
+        self.update_timestep(yieldstep, finaltime)
+        #Compute forcing terms
+        #NOT NEEDED FOR 2ND ORDER STRANG SPLIITING
+        #ADDING THIS WILL NEED TO REMOVE ZEROING IN COMPUTE_FORCING
+        #self.compute_forcing_terms()
+
+        QC = zeros((N,len(self.conserved_quantities)),Float)
+        QF = zeros((N,len(self.conserved_quantities)),Float)
+
+        i = 0
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            #Store the centroid values at time t^n
+            QC[:,i] = copy.copy(Q.centroid_values)
+            QF[:,i] = copy.copy(Q.explicit_update)
+            #Update conserved quantities
+            Q.update(self.timestep)
+            i+=1
+            
+        #Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+        #Update boundary values
+        self.update_boundary()
+        
+        self.compute_fluxes()
+        self.update_timestep(yieldstep, finaltime)
+        #Compute forcing terms
+        #NOT NEEDED FOR 2ND ORDER STRANG SPLIITING
+        #self.compute_forcing_terms()
+
+        i = 0
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            Q.centroid_values = QC[:,i]
+            Q.explicit_update = 0.5*(Q.explicit_update+QF[:,i]) 
+            #Update conserved quantities
+            Q.update(self.timestep)
+            i+=1
+        
+        #Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+        #Update boundary values
+        self.update_boundary()
+
+    def  solve_homogenous_second_order_harten(self,yieldstep,finaltime):
+        """Use Harten Second order timestepping to update
+        conserved quantities
+
+        q^{n+1/2} = q^{n}+0.5*dt*F^{n}
+        q^{n+1} = q^{n}+dt*F^{n+1/2}
+        """
+        import copy
+        from Numeric import zeros,Float
+
+        N = self.number_of_elements
+
+        self.compute_fluxes()
+        #Update timestep to fit yieldstep and finaltime
+        self.update_timestep(yieldstep, finaltime)
+        #Compute forcing terms
+        #NOT NEEDED FOR 2ND ORDER STRANG SPLIITING
+        #ADDING THIS WILL NEED TO REMOVE ZEROING IN COMPUTE_FORCING
+        #self.compute_forcing_terms()
+
+        QC = zeros((N,len(self.conserved_quantities)),Float)
+
+        i = 0
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            #Store the centroid values at time t^n
+            QC[:,i] = copy.copy(Q.centroid_values)
+            #Update conserved quantities
+            Q.update(0.5*self.timestep)
+            i+=1
+            
+        #Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+        #Update boundary values
+        self.update_boundary()
+        
+        self.compute_fluxes()
+        self.update_timestep(yieldstep, finaltime)
+        #Compute forcing terms
+        #NOT NEEDED FOR 2ND ORDER STRANG SPLIITING
+        #self.compute_forcing_terms()
+
+        i = 0
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            Q.centroid_values = QC[:,i] 
+            #Update conserved quantities
+            Q.update(self.timestep)
+            i+=1
+        
+        #Update vertex and edge values
+        self.distribute_to_vertices_and_edges()
+        #Update boundary values
+        self.update_boundary()
+        
+    def distribute_to_vertices_and_edges(self):
+        """Extrapolate conserved quantities from centroid to
+        vertices and edge-midpoints for each volume
+
+        Default implementation is straight first order,
+        i.e. constant values throughout each element and
+        no reference to non-conserved quantities.
+        """
+
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            if self.order == 1:
+                Q.extrapolate_first_order()
+            elif self.order == 2:
+                Q.extrapolate_second_order()
+                #Q.limit()
+            else:
+                raise 'Unknown order'
+            #Q.interpolate_from_vertices_to_edges()
+
+
+    def update_boundary(self):
+        """Go through list of boundary objects and update boundary values
+        for all conserved quantities on boundary.
+        """
+
+        #FIXME: Update only those that change (if that can be worked out)
+        #FIXME: Boundary objects should not include ghost nodes.
+        #for i, ((vol_id, edge_id), B) in enumerate(self.boundary_objects):
+        #    q = B.evaluate(vol_id, edge_id)
+        for i, ((vol_id, vertex_id), B) in enumerate(self.boundary_objects):
+            q = B.evaluate(vol_id, vertex_id)
+
+            for j, name in enumerate(self.conserved_quantities):
+                Q = self.quantities[name]
+                Q.boundary_values[i] = q[j]
+
+    def update_timestep(self, yieldstep, finaltime):
+
+        from config import min_timestep
+
+        # self.timestep is calculated from speed of characteristics
+        # Apply CFL condition here
+        timestep = self.CFL*self.timestep
+
+        #Record maximal and minimal values of timestep for reporting
+        self.max_timestep = max(timestep, self.max_timestep)
+        self.min_timestep = min(timestep, self.min_timestep)
+
+        #Protect against degenerate time steps
+        if timestep < min_timestep:
+
+            #Number of consecutive small steps taken b4 taking action
+            self.smallsteps += 1
+
+            if self.smallsteps > self.max_smallsteps:
+                self.smallsteps = 0 #Reset
+
+                if self.order == 1:
+                    msg = 'WARNING: Too small timestep %.16f reached '\
+                          %timestep
+                    msg += 'even after %d steps of 1 order scheme'\
+                           %self.max_smallsteps
+                    print msg
+                    timestep = min_timestep  #Try enforcing min_step
+
+                    #raise msg
+                else:
+                    #Try to overcome situation by switching to 1 order
+                    print "changing Order 1"
+                    self.order = 1
+
+        else:
+            self.smallsteps = 0
+            if self.order == 1 and self.default_order == 2:
+                self.order = 2
+
+
+        #Ensure that final time is not exceeded
+        if finaltime is not None and self.time + timestep > finaltime:
+            timestep = finaltime-self.time
+
+        #Ensure that model time is aligned with yieldsteps
+        if self.yieldtime + timestep > yieldstep:
+            timestep = yieldstep-self.yieldtime
+
+        self.timestep = timestep
+
+
+    def compute_forcing_terms(self):
+        """If there are any forcing functions driving the system
+        they should be defined in Domain subclass and appended to
+        the list self.forcing_terms
+        """
+        #Clears explicit_update needed for second order method
+        if self.time_order == 2:
+            for name in self.conserved_quantities:
+                Q = self.quantities[name]
+                Q.explicit_update[:] = 0.0
+
+        for f in self.forcing_terms:
+            f(self)
+            
+
+    def update_derived_quantites(self):
+        pass
+    
+    #def update_conserved_quantities(self):
+    def update_conserved_quantities(self,timestep):
+        """Update vectors of conserved quantities using previously
+        computed fluxes specified forcing functions.
+        """
+
+        from Numeric import ones, sum, equal, Float
+
+        N = self.number_of_elements
+        d = len(self.conserved_quantities)
+
+        #timestep = self.timestep
+
+        #Compute forcing terms
+        #self.compute_forcing_terms()
+
+        #Update conserved_quantities
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            Q.update(timestep)
+
+            #Clean up
+            #Note that Q.explicit_update is reset by compute_fluxes
+
+            #MH090605 commented out the following since semi_implicit_update is now re-initialized
+            #at the end of the _update function in quantity_ext.c (This is called by the
+            #preceeding Q.update(timestep) statement above).
+            #For run_profile.py with N=128, the time of update_conserved_quantities is cut from 14.00 secs
+            #to 8.35 secs
+
+            #Q.semi_implicit_update[:] = 0.0
+
+if __name__ == "__main__":
+
+    points1 = [0.0, 1.0, 2.0, 3.0]
+    D1 = Domain(points1)
+
+    print D1.get_coordinate(0)
+    print D1.get_coordinate(0,1)
+    print 'Number of Elements = ',D1.number_of_elements
+
+    try:
+        print D1.get_coordinate(3)
+    except:
+        pass
+    else:
+        msg =  'Should have raised an out of bounds exception'
+        raise msg
+
+    #points2 = [0.0, 1.0, 2.0, 3.0, 2.5]
+    #D2 = Domain(points2)
+
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dry_dam_sudi.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dry_dam_sudi.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dry_dam_sudi.py	(revision 7576)
@@ -0,0 +1,161 @@
+import os
+from math import sqrt, pi
+from shallow_water_vel_domain import *
+from Numeric import allclose, array, zeros, ones, Float, take, sqrt
+from config import g, epsilon
+
+
+h1 = 10.0
+h0 = 0.0
+
+def analytical_sol(C,t):
+    
+    #t  = 0.0     # time (s)
+    # gravity (m/s^2)
+    #h1 = 10.0    # depth upstream (m)
+    #h0 = 0.0     # depth downstream (m)
+    L = 2000.0   # length of stream/domain (m)
+    n = len(C)    # number of cells
+
+    u = zeros(n,Float)
+    h = zeros(n,Float)
+    x = C-3*L/4.0
+    
+
+    for i in range(n):
+        # Calculate Analytical Solution at time t > 0
+        u3 = 2.0/3.0*(sqrt(g*h1)+x[i]/t) 
+        h3 = 4.0/(9.0*g)*(sqrt(g*h1)-x[i]/(2.0*t))*(sqrt(g*h1)-x[i]/(2.0*t))
+        u3_ = 2.0/3.0*((x[i]+L/2.0)/t-sqrt(g*h1))
+        h3_ = 1.0/(9.0*g)*((x[i]+L/2.0)/t+2*sqrt(g*h1))*((x[i]+L/2.0)/t+2*sqrt(g*h1))
+
+        if ( x[i] <= -1*L/2.0+2*(-sqrt(g*h1)*t)):
+            u[i] = 0.0
+            h[i] = h0
+        elif ( x[i] <= -1*L/2.0-(-sqrt(g*h1)*t)):
+            u[i] = u3_
+            h[i] = h3_
+
+        elif ( x[i] <= -t*sqrt(g*h1) ):
+            u[i] = 0.0 
+            h[i] = h1 
+        elif ( x[i] <= 2.0*t*sqrt(g*h1) ):
+            u[i] = u3 
+            h[i] = h3 
+        else:
+            u[i] = 0.0 
+            h[i] = h0 
+
+    return h , u*h, u
+
+#def newLinePlot(title='Simple Plot'):
+#   import Gnuplot
+#    gg = Gnuplot.Gnuplot(persist=0)
+#    gg.terminal(postscript)
+#    gg.title(title)
+#    gg('set data style linespoints') 
+#    gg.xlabel('x')
+#    gg.ylabel('y')
+#    return gg
+
+#def linePlot(gg,x1,y1,x2,y2):
+#    import Gnuplot
+#    plot1 = Gnuplot.PlotItems.Data(x1.flat,y1.flat,with="linespoints")
+#    plot2 = Gnuplot.PlotItems.Data(x2.flat,y2.flat, with="lines 3")
+#    g.plot(plot1,plot2)
+
+
+
+print "TEST 1D-SOLUTION III -- DRY BED"
+
+def stage(x):
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        if x[i]<=L/4.0:
+            y[i] = h0
+        elif x[i]<=3*L/4.0:
+            y[i] = h1
+        else:
+            y[i] = h0
+    return y
+
+
+import time
+
+finaltime = 10.0
+yieldstep = finaltime
+L = 2000.0     # Length of channel (m)
+number_of_cells = [810]#,200,500,1000,2000,5000,10000,20000]
+h_error = zeros(len(number_of_cells),Float)
+uh_error = zeros(len(number_of_cells),Float)
+k = 0
+for i in range(len(number_of_cells)):
+    N = int(number_of_cells[i])
+    print "Evaluating domain with %d cells" %N
+    cell_len = L/N # Origin = 0.0
+    points = zeros(N+1,Float)
+    for j in range(N+1):
+        points[j] = j*cell_len
+        
+    domain = Domain(points)
+    
+    domain.set_quantity('stage', stage)
+    domain.set_boundary({'exterior': Reflective_boundary(domain)})
+    domain.order = 2
+    domain.set_timestepping_method('rk2')
+    domain.set_CFL(1.0)
+    domain.set_limiter("vanleer")
+    #domain.h0=0.0001
+
+    t0 = time.time()
+
+    for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime):
+        domain.write_time()
+
+    N = float(N)
+    StageC = domain.quantities['stage'].centroid_values
+    XmomC = domain.quantities['xmomentum'].centroid_values
+    C = domain.centroids
+    h, uh, u = analytical_sol(C,domain.time)
+    h_error[k] = 1.0/(N)*sum(abs(h-StageC))
+    uh_error[k] = 1.0/(N)*sum(abs(uh-XmomC))
+    print "h_error %.10f" %(h_error[k])
+    print "uh_error %.10f"% (uh_error[k])
+    k = k+1
+    print 'That took %.2f seconds' %(time.time()-t0)
+    X = domain.vertices
+    StageQ = domain.quantities['stage'].vertex_values
+    XmomQ = domain.quantities['xmomentum'].vertex_values
+    velQ = domain.quantities['velocity'].vertex_values
+    
+    h, uh, u = analytical_sol(X.flat,domain.time)
+    x = X.flat
+    
+    from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+    print 'test 2'
+    hold(False)
+    print 'test 3'
+    plot1 = subplot(211)
+    print 'test 4'
+    plot(x,h,x,StageQ.flat)
+    print 'test 5'
+    plot1.set_ylim([-1,11])
+    xlabel('Position')
+    ylabel('Stage')
+    legend(('Analytical Solution', 'Numerical Solution'),
+           'upper right', shadow=True)
+    plot2 = subplot(212)
+    plot(x,u,x,velQ.flat)
+    plot2.set_ylim([-35,35])
+    
+    xlabel('Position')
+    ylabel('Velocity')
+   
+    file = "dry_bed_"
+    file += str(number_of_cells[i])
+    file += ".eps"
+    #savefig(file)
+    show()
+    
+print "Error in height", h_error
+print "Error in xmom", uh_error
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dry_dam_sudi.py.bak
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dry_dam_sudi.py.bak	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dry_dam_sudi.py.bak	(revision 7576)
@@ -0,0 +1,166 @@
+import os
+from math import sqrt, pi
+from shallow_water_domain_suggestion1 import *
+from Numeric import allclose, array, zeros, ones, Float, take, sqrt
+from config import g, epsilon
+
+def analytical_sol(C,t):
+    
+    #t  = 0.0     # time (s)
+    g  = 9.81    # gravity (m/s^2)
+    h1 = 10.0    # depth upstream (m)
+    h0 = 0.0     # depth downstream (m)
+    L = 2000.0   # length of stream/domain (m)
+    n = len(C)    # number of cells
+
+    u = zeros(n,Float)
+    h = zeros(n,Float)
+    x = C-3*L/4.0
+    
+
+    for i in range(n):
+        # Calculate Analytical Solution at time t > 0
+        u3 = 2.0/3.0*(sqrt(g*h1)+x[i]/t) 
+        h3 = 4.0/(9.0*g)*(sqrt(g*h1)-x[i]/(2.0*t))*(sqrt(g*h1)-x[i]/(2.0*t))
+        u3_ = 2.0/3.0*((x[i]+L/2.0)/t-sqrt(g*h1))
+        h3_ = 1.0/(9.0*g)*((x[i]+L/2.0)/t+2*sqrt(g*h1))*((x[i]+L/2.0)/t+2*sqrt(g*h1))
+
+        if ( x[i] <= -1*L/2.0+2*(-sqrt(g*h1)*t)):
+            u[i] = 0.0
+            h[i] = h0
+        elif ( x[i] <= -1*L/2.0-(-sqrt(g*h1)*t)):
+            u[i] = u3_
+            h[i] = h3_
+
+        elif ( x[i] <= -t*sqrt(g*h1) ):
+            u[i] = 0.0 
+            h[i] = h1 
+        elif ( x[i] <= 2.0*t*sqrt(g*h1) ):
+            u[i] = u3 
+            h[i] = h3 
+        else:
+            u[i] = 0.0 
+            h[i] = h0 
+
+    return h , u*h
+
+#def newLinePlot(title='Simple Plot'):
+#   import Gnuplot
+#    gg = Gnuplot.Gnuplot(persist=0)
+#    gg.terminal(postscript)
+#    gg.title(title)
+#    gg('set data style linespoints') 
+#    gg.xlabel('x')
+#    gg.ylabel('y')
+#    return gg
+
+#def linePlot(gg,x1,y1,x2,y2):
+#    import Gnuplot
+#    plot1 = Gnuplot.PlotItems.Data(x1.flat,y1.flat,with="linespoints")
+#    plot2 = Gnuplot.PlotItems.Data(x2.flat,y2.flat, with="lines 3")
+#    g.plot(plot1,plot2)
+
+
+
+print "TEST 1D-SOLUTION III -- DRY BED"
+
+L = 2000.0     # Length of channel (m)
+N = 800        # Number of computational cells
+cell_len = L/N # Origin = 0.0
+
+points = zeros(N+1,Float)
+for i in range(N+1):
+    points[i] = i*cell_len
+
+domain = Domain(points)
+
+def stage(x):
+    h1 = 10.0
+    h0 = 0.0
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        if x[i]<=L/4.0:
+            y[i] = h0
+        elif x[i]<=3*L/4.0:
+            y[i] = h1
+        else:
+            y[i] = h0
+    return y
+
+
+import time
+
+finaltime = 10.0
+yieldstep = 10.0
+L = 2000.0     # Length of channel (m)
+number_of_cells = [250]#,200,500,1000,2000,5000,10000,20000]
+h_error = zeros(len(number_of_cells),Float)
+uh_error = zeros(len(number_of_cells),Float)
+k = 0
+for i in range(len(number_of_cells)):
+    N = int(number_of_cells[i])
+    print "Evaluating domain with %d cells" %N
+    cell_len = L/N # Origin = 0.0
+    points = zeros(N+1,Float)
+    for j in range(N+1):
+        points[j] = j*cell_len
+        
+    domain = Domain(points)
+    
+    domain.set_quantity('stage', stage)
+    domain.set_boundary({'exterior': Reflective_boundary(domain)})
+    domain.order = 2
+    domain.set_timestepping_method('rk2')
+    domain.cfl = 1.0
+    domain.limiter = "minmod"
+
+    t0 = time.time()
+
+    for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime):
+        domain.write_time()
+
+    N = float(N)
+    StageC = domain.quantities['stage'].centroid_values
+    XmomC = domain.quantities['xmomentum'].centroid_values
+    C = domain.centroids
+    h, uh = analytical_sol(C,domain.time)
+    h_error[k] = 1.0/(N)*sum(abs(h-StageC))
+    uh_error[k] = 1.0/(N)*sum(abs(uh-XmomC))
+    print "h_error %.10f" %(h_error[k])
+    print "uh_error %.10f"% (uh_error[k])
+    k = k+1
+    print 'That took %.2f seconds' %(time.time()-t0)
+    X = domain.vertices
+    StageQ = domain.quantities['stage'].vertex_values
+    XmomQ = domain.quantities['xmomentum'].vertex_values
+    h, uh = analytical_sol(X.flat,domain.time)
+    x = X.flat
+    
+    from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+    print 'test 2'
+    hold(False)
+    print 'test 3'
+    plot1 = subplot(211)
+    print 'test 4'
+    plot(x,h,x,StageQ.flat)
+    print 'test 5'
+    plot1.set_ylim([-1,11])
+    xlabel('Position')
+    ylabel('Stage')
+    legend(('Analytical Solution', 'Numerical Solution'),
+           'upper right', shadow=True)
+    plot2 = subplot(212)
+    plot(x,uh,x,XmomQ.flat)
+    plot2.set_ylim([-35,35])
+    
+    xlabel('Position')
+    ylabel('Xmomentum')
+   
+    file = "dry_bed_"
+    file += str(number_of_cells[i])
+    file += ".eps"
+    #savefig(file)
+    show()
+    
+print "Error in height", h_error
+print "Error in xmom", uh_error
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dry_dam_vel.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dry_dam_vel.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dry_dam_vel.py	(revision 7576)
@@ -0,0 +1,98 @@
+import os
+from math import sqrt, pi
+from shallow_water_vel_domain import *
+from Numeric import allclose, array, zeros, ones, Float, take, sqrt
+from config import g, epsilon
+
+
+h1 = 10.0
+h0 = 0.0
+
+def analytical_sol(C,t):
+    
+    #t  = 0.0     # time (s)
+    # gravity (m/s^2)
+    #h1 = 10.0    # depth upstream (m)
+    #h0 = 0.0     # depth downstream (m)
+    L = 2000.0   # length of stream/domain (m)
+    n = len(C)    # number of cells
+
+    u = zeros(n,Float)
+    h = zeros(n,Float)
+    x = C-3*L/4.0
+    
+
+    for i in range(n):
+        # Calculate Analytical Solution at time t > 0
+        u3 = 2.0/3.0*(sqrt(g*h1)+x[i]/t) 
+        h3 = 4.0/(9.0*g)*(sqrt(g*h1)-x[i]/(2.0*t))*(sqrt(g*h1)-x[i]/(2.0*t))
+        u3_ = 2.0/3.0*((x[i]+L/2.0)/t-sqrt(g*h1))
+        h3_ = 1.0/(9.0*g)*((x[i]+L/2.0)/t+2*sqrt(g*h1))*((x[i]+L/2.0)/t+2*sqrt(g*h1))
+
+        if ( x[i] <= -1*L/2.0+2*(-sqrt(g*h1)*t)):
+            u[i] = 0.0
+            h[i] = h0
+        elif ( x[i] <= -1*L/2.0-(-sqrt(g*h1)*t)):
+            u[i] = u3_
+            h[i] = h3_
+
+        elif ( x[i] <= -t*sqrt(g*h1) ):
+            u[i] = 0.0 
+            h[i] = h1 
+        elif ( x[i] <= 2.0*t*sqrt(g*h1) ):
+            u[i] = u3 
+            h[i] = h3 
+        else:
+            u[i] = 0.0 
+            h[i] = h0 
+
+    return h , u*h, u
+
+print "TEST 1D-SOLUTION III -- DRY BED"
+
+def stage(x):
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        if x[i]<=L/4.0:
+            y[i] = h0
+        elif x[i]<=3*L/4.0:
+            y[i] = h1
+        else:
+            y[i] = h0
+    return y
+
+
+import time
+
+finaltime = 2.0
+yieldstep = 0.1
+L = 2000.0     # Length of channel (m)
+
+k = 0
+
+N = 800
+print "Evaluating domain with %d cells" %N
+cell_len = L/N # Origin = 0.0
+points = zeros(N+1,Float)
+
+for j in range(N+1):
+    points[j] = j*cell_len
+        
+domain = Domain(points)
+    
+domain.set_quantity('stage', stage)
+domain.set_boundary({'exterior': Reflective_boundary(domain)})
+domain.order = 2
+domain.set_timestepping_method('euler')
+domain.set_CFL(1.0)
+domain.set_limiter("vanleer")
+#domain.h0=0.0001
+
+t0 = time.time()
+
+for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime):
+    domain.write_time()
+
+print 'end'
+
+
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dry_dam_with_nonzeroslope (2).py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dry_dam_with_nonzeroslope (2).py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dry_dam_with_nonzeroslope (2).py	(revision 7576)
@@ -0,0 +1,158 @@
+import os
+from math import sqrt, pi
+from shallow_water_domain_suggestion3 import *
+from Numeric import allclose, array, zeros, ones, Float, take, sqrt
+from config import g, epsilon
+from numpy import sin, cos, tan, arcsin, arccos, arctan
+
+"""
+def analytical_sol(C,t):
+    h1 = 10.0       # depth upstream (m)
+    L = 2000.0      # length of stream/domain (m)
+    n = len(C)      # number of cells
+    b0 = -0.005     # bottom slope
+
+    u = zeros(n,Float)
+    h = zeros(n,Float)
+    x_prime = C-L/2.0
+    x = x_prime/cos(arctan(b0))
+    
+    for i in range(n):
+        # Calculate Analytical Solution at time t > 0
+        u3 = (2.0/3.0) * sqrt(g*h1) * (1.0 + b0*t*sqrt(g/h1) + x[i]/(t*sqrt(g*h1))) 
+        h3 = (h1/9.0) * (2.0 + 0.5*b0*t*sqrt(g/h1) - x[i]/(t*sqrt(g*h1)))**2
+
+        if x[i] < -1*sqrt(g*h1)*t:
+            u[i] = 0.0
+            h[i] = h1
+        elif x[i] <= t*sqrt(g*h1)*(2.0 + 0.5*b0*t*sqrt(g/h1)):
+            u[i] = u3 
+            h[i] = (0.005*x[i] + 0.025) + h3 
+        else:
+            u[i] = 0.0 
+            h[i] = 0.005*x[i] + 0.025 #This 0.005*x[i] + 0.025
+    return h , u*h, u
+"""
+
+b0 = -0.001     # bottom slope
+
+def analytical_sol(C,t):
+    h1 = 10.0       # depth upstream (m)
+    L = 2000.0      # length of stream/domain (m)
+    n = len(C)      # number of cells
+
+    u = zeros(n,Float)
+    h = zeros(n,Float)
+    x_prime = C-L/2.0
+    x = x_prime/cos(arctan(b0))
+    
+    for i in range(n):
+        # Calculate Analytical Solution at time t > 0
+        if x[i] <= -1*sqrt(g*h1)*t:
+            u[i] = 0.0
+            h[i] = h1
+        elif x[i] <= t*sqrt(g*h1)*(2.0 - 0.5*b0*t*sqrt(g/h1)):
+            u[i] = (2.0/3.0) * sqrt(g*h1) * (1.0 - b0*t*sqrt(g/h1) + x[i]/(t*sqrt(g*h1))) 
+            h[i] = (h1/9.0) * (2.0 - 0.5*b0*t*sqrt(g/h1) - x[i]/(t*sqrt(g*h1)))**2   +  b0*x[i]
+        else:
+            u[i] = 0.0 
+            h[i] = b0*x[i]
+    return h , u*h, u
+
+
+
+
+print "TEST 1D-SOLUTION III -- DRY BED"
+
+def stage(x):
+    h1 = 10.0
+    h0 = 0.0
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        if x[i]<=L/2.0:
+            y[i] = h1
+        else:
+            y[i] = b0*(x[i] - 1000) #h0
+    return y
+
+def elevation(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        y[i] = b0*(x[i] - 1000)
+    return y
+
+
+import time
+finaltime = 10.0
+yieldstep = 10.0
+L = 2000.0     # Length of channel (m)
+number_of_cells = [410]#,200,500,1000,2000,5000,10000,20000]
+h_error = zeros(len(number_of_cells),Float)
+uh_error = zeros(len(number_of_cells),Float)
+k = 0
+for i in range(len(number_of_cells)):
+    N = int(number_of_cells[i])
+    print "Evaluating domain with %d cells" %N
+    cell_len = L/N # Origin = 0.0
+    points = zeros(N+1,Float)
+    for j in range(N+1):
+        points[j] = j*cell_len
+        
+    domain = Domain(points)
+    domain.set_quantity('stage', stage)
+    domain.set_quantity('elevation', elevation)
+    
+    domain.set_boundary({'exterior': Reflective_boundary(domain)})
+    domain.order = 2
+    domain.set_timestepping_method('rk2')
+    domain.cfl = 1.0
+    domain.limiter = "vanleer"
+
+    t0 = time.time()
+    for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime):
+        domain.write_time()
+
+    N = float(N)
+    StageC = domain.quantities['stage'].centroid_values
+    XmomC = domain.quantities['xmomentum'].centroid_values
+    C = domain.centroids
+    h, uh, u = analytical_sol(C,domain.time)
+    h_error[k] = 1.0/(N)*sum(abs(h-StageC))
+    uh_error[k] = 1.0/(N)*sum(abs(uh-XmomC))
+    print "h_error %.10f" %(h_error[k])
+    print "uh_error %.10f"% (uh_error[k])
+    k = k+1
+    print 'That took %.2f seconds' %(time.time()-t0)
+    X = domain.vertices
+    StageQ = domain.quantities['stage'].vertex_values
+    XmomQ = domain.quantities['xmomentum'].vertex_values
+    velQ = domain.quantities['velocity'].vertex_values
+    bedQ =domain.quantities['elevation'].vertex_values
+    
+    h, uh, u = analytical_sol(X.flat,domain.time)
+    x = X.flat
+    
+    from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+    hold(False)
+    plot1 = subplot(211)
+    plot(x,h,'b-', x,StageQ.flat,'r-', x, bedQ,'k-')
+    plot1.set_ylim([-1,11])
+    xlabel('Position')
+    ylabel('Stage')
+    legend(('Analytical Solution', 'Numerical Solution', 'Bottom elevation'),
+           'upper right', shadow=True)
+    plot2 = subplot(212)
+    plot(x,u,x,velQ.flat)
+    plot2.set_ylim([-35,35])
+    
+    xlabel('Position')
+    ylabel('Velocity')
+   
+    file = "dry_bed_"
+    file += str(number_of_cells[i])
+    file += ".eps"
+    #savefig(file)
+    show()
+    
+print "Error in height", h_error
+print "Error in xmom", uh_error
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dry_dam_with_nonzeroslope.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dry_dam_with_nonzeroslope.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/dry_dam_with_nonzeroslope.py	(revision 7576)
@@ -0,0 +1,146 @@
+import os
+from math import sqrt, pi
+from shallow_water_domain_suggestion1 import *
+from Numeric import allclose, array, zeros, ones, Float, take, sqrt
+from config import g, epsilon
+from numpy import sin, cos, tan, arcsin, arccos, arctan
+
+def analytical_sol(C,t):
+    h1 = 10.0       # depth upstream (m)
+    L = 2000.0      # length of stream/domain (m)
+    n = len(C)      # number of cells
+    b0 = -0.005     # bottom slope
+
+    u = zeros(n,Float)
+    h = zeros(n,Float)
+    x_prime = C-L/2.0
+    x = x_prime/cos(arctan(b0))
+    
+    for i in range(n):
+        # Calculate Analytical Solution at time t > 0
+        u3 = 2.0/3.0*sqrt(g*h1)*(1.0+ b0*t*sqrt(g/h1)+x[i]/(t*sqrt(g*h1))) 
+        h3 = h1/9.0*(2.0+0.5*b0*t*sqrt(g/h1) - x[i]/(t*sqrt(g*h1)))**2
+
+        if x[i] <= -1*sqrt(g*h1)*t:
+            u[i] = 0.0
+            h[i] = h1
+        elif x[i] <= t*sqrt(g*h1)*(2.0 + 0.5*b0*t*sqrt(g/h1)):
+            u[i] = u3 
+            h[i] = (0.005*x[i] + 0.025) + h3 
+        else:
+            u[i] = 0.0 
+            h[i] = 0.005*x[i] + 0.025
+    return h , u*h, u
+
+#def newLinePlot(title='Simple Plot'):
+#   import Gnuplot
+#    gg = Gnuplot.Gnuplot(persist=0)
+#    gg.terminal(postscript)
+#    gg.title(title)
+#    gg('set data style linespoints') 
+#    gg.xlabel('x')
+#    gg.ylabel('y')
+#    return gg
+
+#def linePlot(gg,x1,y1,x2,y2):
+#    import Gnuplot
+#    plot1 = Gnuplot.PlotItems.Data(x1.flat,y1.flat,with="linespoints")
+#    plot2 = Gnuplot.PlotItems.Data(x2.flat,y2.flat, with="lines 3")
+#    g.plot(plot1,plot2)
+
+
+
+print "TEST 1D-SOLUTION III -- DRY BED"
+
+def stage(x):
+    h1 = 10.0
+    h0 = 0.0
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        if x[i]<=L/2.0:
+            y[i] = h1
+        else:
+            y[i] = h0
+    return y
+
+def elevation(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        y[i] = 0.005*x[i] - 5.0
+    return y
+
+
+import time
+finaltime = 10.0
+yieldstep = 10.0
+L = 2000.0     # Length of channel (m)
+number_of_cells = [810]#,200,500,1000,2000,5000,10000,20000]
+h_error = zeros(len(number_of_cells),Float)
+uh_error = zeros(len(number_of_cells),Float)
+k = 0
+for i in range(len(number_of_cells)):
+    N = int(number_of_cells[i])
+    print "Evaluating domain with %d cells" %N
+    cell_len = L/N # Origin = 0.0
+    points = zeros(N+1,Float)
+    for j in range(N+1):
+        points[j] = j*cell_len
+        
+    domain = Domain(points)
+    domain.set_quantity('stage', stage)
+    domain.set_quantity('elevation', elevation)
+    
+    domain.set_boundary({'exterior': Reflective_boundary(domain)})
+    domain.order = 2
+    domain.set_timestepping_method('rk2')
+    domain.cfl = 1.0
+    domain.limiter = "minmod"
+
+    t0 = time.time()
+    for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime):
+        domain.write_time()
+
+    N = float(N)
+    StageC = domain.quantities['stage'].centroid_values
+    XmomC = domain.quantities['xmomentum'].centroid_values
+    C = domain.centroids
+    h, uh, u = analytical_sol(C,domain.time)
+    h_error[k] = 1.0/(N)*sum(abs(h-StageC))
+    uh_error[k] = 1.0/(N)*sum(abs(uh-XmomC))
+    print "h_error %.10f" %(h_error[k])
+    print "uh_error %.10f"% (uh_error[k])
+    k = k+1
+    print 'That took %.2f seconds' %(time.time()-t0)
+    X = domain.vertices
+    StageQ = domain.quantities['stage'].vertex_values
+    XmomQ = domain.quantities['xmomentum'].vertex_values
+    velQ = domain.quantities['velocity'].vertex_values
+    bedQ =domain.quantities['elevation'].vertex_values
+    
+    h, uh, u = analytical_sol(X.flat,domain.time)
+    x = X.flat
+    
+    from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+    hold(False)
+    plot1 = subplot(211)
+    plot(x,h,'b-', x,StageQ.flat,'r-', x, bedQ,'g-')
+    plot1.set_ylim([-1,11])
+    xlabel('Position')
+    ylabel('Stage')
+    legend(('Analytical Solution', 'Numerical Solution', 'Bottom elevation'),
+           'upper right', shadow=True)
+    plot2 = subplot(212)
+    plot(x,u,x,velQ.flat)
+    plot2.set_ylim([-35,35])
+    
+    xlabel('Position')
+    ylabel('Velocity')
+   
+    file = "dry_bed_"
+    file += str(number_of_cells[i])
+    file += ".eps"
+    #savefig(file)
+    show()
+    
+print "Error in height", h_error
+print "Error in xmom", uh_error
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/generic_boundary_conditions.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/generic_boundary_conditions.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/generic_boundary_conditions.py	(revision 7576)
@@ -0,0 +1,504 @@
+"""boundary.py - Classes for implementing boundary conditions
+"""
+
+
+class Boundary:
+    """Base class for boundary conditions.
+       Specific boundary conditions must provide values for
+       the conserved_quantities
+
+       A boundary object has one neighbour; the one it
+       serves.
+    """
+
+    def __init__(self):
+        pass
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        msg = 'Generic class Boundary must be subclassed'
+        raise msg
+
+
+class Transmissive_boundary(Boundary):
+    """Transmissive boundary returns same conserved quantities as
+    those present in its neighbour volume.
+
+    Underlying domain must be specified when boundary is instantiated
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for transmissive boundary'
+            raise msg
+
+        self.domain = domain
+
+    def __repr__(self):
+        return 'Transmissive_boundary(%s)' %self.domain
+
+    def evaluate(self, vol_id, edge_id):
+        """Transmissive boundaries return the edge values
+        of the volume they serve.
+        """
+
+        q = self.domain.get_conserved_quantities(vol_id, edge = edge_id)
+        return q
+
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, conserved_quantities=None):
+        Boundary.__init__(self)
+
+        if conserved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.conserved_quantities=array(conserved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.conserved_quantities
+
+
+
+class Time_boundary(Boundary):
+    """Time dependent boundary returns values for the
+    conserved quantities as a function of time.
+    Must specify domain to get access to model time and a function f(t)
+    which must return conserved quantities as a function time
+    """
+
+
+    def __init__(self, domain = None, f = None):
+        Boundary.__init__(self)
+
+        try:
+            q = f(0.0)
+        except Exception, e:
+            msg = 'Function for time boundary could not be executed:\n%s' %e
+            raise msg
+
+
+        from Numeric import array, Float
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from time boundary function could '
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        msg = 'ERROR: Time boundary function must return a 1d list or array '
+        assert len(q.shape) == 1, msg
+
+        d = len(domain.conserved_quantities)
+        msg = 'Return value for f must be a list or an array of length %d' %d
+        assert len(q) == d, msg
+
+        self.f = f
+        self.domain = domain
+
+    def __repr__(self):
+        return 'Time boundary'
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.f(self.domain.time)
+
+
+class File_boundary_time(Boundary):
+    """Boundary values obtained from file and interpolated.
+    conserved quantities as a function of time.
+
+    Assumes that file contains a time series.
+
+    No spatial info assumed.
+    """
+
+    #FIXME: Is this still necessary
+
+    def __init__(self, filename, domain):
+        import time
+        from Numeric import array
+        from config import time_format
+        from util import File_function
+
+        Boundary.__init__(self)
+
+        self.F = File_function(filename, domain)
+        self.domain = domain
+
+        #Test
+        q = self.F(0)
+
+        d = len(domain.conserved_quantities)
+        msg = 'Values specified in file must be a list or an array of length %d' %d
+        assert len(q) == d, msg
+
+
+    def __repr__(self):
+        return 'File boundary'
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        """Return linearly interpolated values based on domain.time
+
+        vol_id and edge_id are ignored
+        """
+
+        t = self.domain.time
+        return self.F(t)
+
+
+
+
+class File_boundary(Boundary):
+    """Boundary values obtained from file and interpolated.
+    conserved quantities as a function of time.
+
+    Assumes that file contains a time series and possibly
+    also spatial info.
+    See docstring for File_function in util.py for details about
+    admissible file formats
+
+    The full solution history is not exactly the same as if
+    the models were coupled:
+    File boundary must read and interpolate from *smoothed* version
+    as stored in sww and cannot work with the discontinuos triangles.
+
+    """
+
+    def __init__(self, filename, domain, verbose = False):
+        import time
+        from Numeric import array, zeros, Float
+        from config import time_format
+        from util import file_function
+
+        Boundary.__init__(self)
+
+        #Get x,y vertex coordinates for all triangles
+        V = domain.vertex_coordinates
+
+        #Compute midpoint coordinates for all boundary elements
+        #Only a subset may be invoked when boundary is evaluated but
+        #we don't know which ones at this stage since this object can be attached to
+        #any tagged boundary later on.
+
+        if verbose: print 'Find midpoint coordinates of entire boundary'
+        self.midpoint_coordinates = zeros( (len(domain.boundary), 2), Float)
+        boundary_keys = domain.boundary.keys()
+
+
+        xllcorner = domain.geo_reference.get_xllcorner()
+        yllcorner = domain.geo_reference.get_yllcorner()        
+        
+
+        #Make ordering unique #FIXME: should this happen in domain.py?
+        boundary_keys.sort()
+
+
+        #Record ordering #FIXME: should this also happen in domain.py?
+        self.boundary_indices = {}
+        for i, (vol_id, edge_id) in enumerate(boundary_keys):
+
+            x0 = V[vol_id, 0]; y0 = V[vol_id, 1]
+            x1 = V[vol_id, 2]; y1 = V[vol_id, 3]
+            x2 = V[vol_id, 4]; y2 = V[vol_id, 5]
+
+            #Compute midpoints
+            if edge_id == 0: m = array([(x1 + x2)/2, (y1 + y2)/2])
+            if edge_id == 1: m = array([(x0 + x2)/2, (y0 + y2)/2])
+            if edge_id == 2: m = array([(x1 + x0)/2, (y1 + y0)/2])
+
+            #Convert to absolute UTM coordinates
+            m[0] += xllcorner
+            m[1] += yllcorner
+            
+            #Register point and index
+            self.midpoint_coordinates[i,:] = m
+            self.boundary_indices[(vol_id, edge_id)] = i
+
+
+        if verbose: print 'Initialise file_function'
+        self.F = file_function(filename, domain,
+	                       interpolation_points=self.midpoint_coordinates,
+                               verbose = verbose)
+        self.domain = domain
+
+        #Test
+        q = self.F(0, point_id=0)
+
+        d = len(domain.conserved_quantities)
+        msg = 'Values specified in file %s must be ' %filename
+        msg += ' a list or an array of length %d' %d
+        assert len(q) == d, msg
+
+
+    def __repr__(self):
+        return 'File boundary'
+
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        """Return linearly interpolated values based on domain.time
+
+        vol_id and edge_id are ignored
+        """
+
+        t = self.domain.time
+
+        if vol_id is not None and edge_id is not None:
+            i = self.boundary_indices[ vol_id, edge_id ]
+            return self.F(t, point_id = i)
+        else:
+            #raise 'Boundary call without point_id not implemented'
+            #FIXME: What should the semantics be?
+            return self.F(t)
+
+
+
+
+
+
+
+
+#THIS FAR (10/8/4)
+class Connective_boundary(Boundary):
+    """Connective boundary returns values for the
+    conserved quantities from a volume as defined by a connection table
+    mapping between tuples of (volume id, face id) for volumes that
+    have their boundaries connected.
+
+    FIXME: Perhaps include possibility of mapping between
+    different domains as well
+
+    FIXME: In case of shallow water we may want to have a
+    special version that casts this in terms of height rather than stage
+    """
+
+
+    def __init__(self, table):
+        from domain import Volume
+
+        Boundary.__init__(self)
+
+        self.connection_table = table
+        self.Volume = Volume
+
+    def __repr__(self):
+        return 'Connective boundary'
+
+    #FIXME: IF we ever need to get field_values from connected volume,
+    #that method could be overridden here (using same idea as in
+    #get_conserved_quantities
+    #def get_field_values()
+
+    def get_conserved_quantities(self, volume, face=0):
+
+        id = volume.id
+        if self.connection_table.has_key((id, face)):
+            other_id, other_face = self.connection_table[(id, face)]
+
+            other_volume = self.Volume.instances[other_id]
+            cmd = 'q = other_volume.conserved_quantities_face%d' %face;
+            exec(cmd)
+            return q
+        else:
+            msg = 'Volume, face tuple ($d, %d) has not been mapped'\
+                  %(id, face)
+            raise msg
+
+
+
+
+
+#FIXME: Add a boundary with a general function of x,y, and t
+
+#FIXME: Add periodic boundaries e.g.:
+# Attempt at periodic conditions from advection_spik. Remember this
+#
+#first = 2*(N-1)*N
+#for i in range(1,2*N+1,2):
+#    k = first + i-1#
+#
+#    print i,k
+#
+#    domain[i].faces[2].neighbour = domain[k].faces[1]
+#    domain[k].faces[1].neighbour = domain[i].faces[2]
+
+
+
+class General_boundary(Boundary):
+    """General boundary which can compute conserved quantities based on
+    their previous value, conserved quantities of its neighbour and model time.
+
+    Must specify initial conserved quantities,
+    neighbour,
+    domain to get access to model time
+    a function f(q_old, neighbours_q, t) which must return
+    new conserved quantities q as a function time
+
+    FIXME: COMPLETE UNTESTED - JUST AN IDEA
+    """
+
+    def __init__(self, neighbour=None, conserved_quantities=None, domain=None, f=None):
+        Boundary.__init__(self, neighbour=neighbour, conserved_quantities=conserved_quantities)
+
+        self.f = f
+        self.domain = domain
+
+
+    def get_conserved_quantities(self, volume=None, face=0):
+        return self.f(self.conserved_quantities,
+                      neighbour.conserved_quantities,
+                      self.domain.time)
+
+
+
+
+
+class File_boundary_old(Boundary):
+    """Boundary values obtained from file and interpolated.
+    conserved quantities as a function of time.
+
+    Assumes that file contains a time series.
+
+    No spatial info assumed.
+    """
+
+
+    def __init__(self, domain = None, filename = None):
+        import time
+        from Numeric import array
+        from config import time_format
+
+        Boundary.__init__(self)
+
+
+        try:
+            fid = open(filename)
+        except Exception, e:
+            msg = 'Boundary file %s could not be opened: %s\n' %(filename, e)
+            raise msg
+
+
+        line = fid.readline()
+        fid.close()
+        fields = line.split(',')
+        msg = 'File %s must have the format date, values'
+        assert len(fields) == 2, msg
+
+        try:
+            starttime = time.mktime(time.strptime(fields[0], time_format))
+        except ValueError:
+            msg = 'First field in file %s must be' %filename
+            msg += ' date-time with format %s.\n' %time_format
+            msg += 'I got %s instead.' %fields[0]
+            raise msg
+
+        #Split values
+        values = []
+        for value in fields[1].split():
+            values.append(float(value))
+
+        q = array(values)
+
+        msg = 'ERROR: File boundary function must return a 1d list or array '
+        assert len(q.shape) == 1, msg
+
+        d = len(domain.conserved_quantities)
+        msg = 'Values specified in file must be a list or an array of length %d' %d
+        assert len(q) == d, msg
+
+        self.filename = filename
+        self.domain = domain
+        self.starttime = starttime
+
+        if domain.starttime is None:
+            domain.starttime = starttime
+        else:
+            msg = 'Start time as specified in domain (%s) is earlier '
+            'than the starttime of file %s: %s'\
+                  %(domain.starttime, self.filename, self.starttime)
+            if self.starttime > domain.starttime:
+                raise msg
+
+        self.read_time_boundary() #Now read all times in.
+
+
+    def read_time_boundary(self):
+        from Numeric import zeros, Float, alltrue
+        from config import time_format
+        import time
+
+        fid = open(self.filename)
+        lines = fid.readlines()
+        fid.close()
+
+        N = len(lines)
+        d = len(self.domain.conserved_quantities)
+
+        T = zeros(N, Float)
+        Q = zeros((N, d), Float)
+
+
+        for i, line in enumerate(lines):
+            fields = line.split(',')
+            real_time = time.mktime(time.strptime(fields[0], time_format))
+
+            T[i] = real_time - self.starttime
+
+
+            for j, value in enumerate(fields[1].split()):
+                Q[i, j] = float(value)
+
+        msg = 'Time boundary must list time as a monotonuosly '
+        msg += 'increasing sequence'
+
+        assert alltrue( T[1:] - T[:-1] > 0 ), msg
+
+        self.T = T     #Time
+        self.Q = Q     #Boundary values
+        self.index = 0 #Initial index
+
+
+    def __repr__(self):
+        return 'File boundary'
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        """Return linearly interpolated values based on domain.time
+        """
+
+        t = self.domain.time
+
+        msg = 'Time given in File boundary does not match model time'
+        if t < self.T[0]: raise msg
+        if t > self.T[-1]: raise msg
+
+        oldindex = self.index
+
+        #Find slot
+        while t > self.T[self.index]: self.index += 1
+        while t < self.T[self.index]: self.index -= 1
+
+        #if oldindex != self.index:
+        #    print 'Changing from %d to %d' %(oldindex, self.index)
+
+
+        #t is now between index and index+1
+        ratio = (t - self.T[self.index])/\
+                (self.T[self.index+1] - self.T[self.index])
+
+        return self.Q[self.index,:] +\
+               ratio*(self.Q[self.index+1,:] - self.Q[self.index,:])
+
+
+
+
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/horizontal_dam_h_2sides - Copy.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/horizontal_dam_h_2sides - Copy.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/horizontal_dam_h_2sides - Copy.py	(revision 7576)
@@ -0,0 +1,194 @@
+import os
+from math import sqrt
+#from shallow_water_h import *
+from shallow_water_domain_suggestion1 import *
+from Numeric import zeros, Float
+from analytic_dam_sudi import AnalyticDam
+from scipy import linspace
+
+h0=5.0
+h1=10.0
+
+analytical_sol=AnalyticDam(h0,h1)
+
+"""
+def newLinePlot(title='Simple Plot'):
+    import Gnuplot
+    gg=Gnuplot.Gnuplot(persist=0)
+    gg.title(title)
+    gg('set data style linespoints')
+    gg.xlabel('x')
+    gg.ylabel('y')
+    return gg
+
+def linePlot(gg, x1, y1, x2, y2):
+    import Gnuplot
+    plot1=Gnuplot.PlotItems.Data(x1.flat, y1.flat, with="linespoints")
+    plot2=Gnuplot.PlotItems.Data(x2.flat, y2.flat, with="lines 3")
+    gg.plot(plot1, plot2)
+"""
+
+
+print "TEST 1D-SOLUTION I"
+
+L=2000.0
+N=8000
+
+cell_len=L/N
+
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+
+domain.order = 2
+domain.set_timestepping_method('rk2')
+domain.cfl = 1.0
+domain.limiter = "minmod"
+
+
+
+def height(x):
+    y=zeros(len(x), Float)
+    for i in range (len(x)):
+        if x[i]<=L/4.0:
+            y[i]=0.0 #h0
+        elif x[i]<=3*L/4.0:
+            y[i]=h1
+        else:
+            y[i]=h0
+    return y
+
+def nol(x):
+    y=zeros(len(x), Float)
+    for i in range (len(x)):
+        y[i]=0.0
+    return y
+
+domain.set_quantity('stage',height)
+print "domain order=", domain.order
+print "domain limiter=", domain.limiter
+
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+
+X=domain.vertices
+C=domain.centroids
+#plot1x=newLinePlot("Height")
+#plot2x=newLinePlot("Momentum")
+
+P=linspace(0,2000,1000)
+H=height(P)
+Enol=nol(P)
+
+
+import time
+yieldstep=finaltime=0.01
+t0=time.time()
+
+"""
+for i in range(10):
+    L=2000.0
+    N=400
+    cell_len=L/N
+    points=zeros(N+1, Float)
+    for i in range(N+1):
+        points[i]=i*cell_len
+    domain=Domain(points)
+    domain.order = 2
+    domain.set_timestepping_method('rk2')
+    domain.cfl = 1.0
+    domain.limiter = "vanleer"
+    domain.set_quantity('stage',height)
+    domain.set_boundary({'exterior':Reflective_boundary(domain)})
+    #print "integral", domain.quantities['stage'].get_integral()
+    for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+        domain.write_time()
+    #print "integral", domain.quantities['stage'].get_integral()
+    #print '==================================================================='
+print 'The average time is %.2f seconds'%((time.time()-t0)/10.0)
+"""
+while finaltime<0.011:
+    i = 0
+    yieldstep=finaltime
+    for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+        domain.write_time()
+    #if t>=0.0:
+        print "t=",t
+        N = float(N)
+        StageC = domain.quantities['stage'].centroid_values
+        XmomC = domain.quantities['xmomentum'].centroid_values
+        VelC = domain.quantities['velocity'].centroid_values
+        C = domain.centroids
+
+        """
+        hC, uhC, uC = analytical_sol(C,domain.time)
+        h_error = cell_len*sum(abs(hC-StageC))
+        uh_error = cell_len*sum(abs(uhC-XmomC))
+        u_error = cell_len*sum(abs(uC-VelC))
+        print "h_error %.10f" %(h_error)
+        print "uh_error %.10f"%(uh_error)
+        print "u_error %.10f" %(u_error)
+        print 'That took %.2f seconds' %(time.time()-t0)
+        """
+        
+        X = domain.vertices
+        StageQ = domain.quantities['stage'].vertex_values
+        XmomQ = domain.quantities['xmomentum'].vertex_values
+        VelQ = domain.quantities['velocity'].vertex_values
+
+        #h, uh, u = analytical_sol(X.flat, domain.time)
+        #linePlot(plot1x, X, HeightQ, X, h)
+        #linePlot(plot2x, X, MomentumQ, X, uh)
+        #print "press return"
+        #pass
+   
+        from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+        hold(False)
+       
+        plot1 = subplot(311)
+        plot(P,H, X,StageQ)
+        plot1.set_ylim([-1,11])
+        #plot1.set_xlim([-100.0,2000.0])
+        #xlabel('Position')
+        ylabel('Stage')
+        #legend(('Analytical Solution', 'Numerical Solution'),
+        #   'lower right', shadow=False)
+        
+        plot2 = subplot(312)
+        plot(P,Enol, X,XmomQ)
+        #plot2.set_ylim([-5,35])
+        #plot2.set_xlim([-100.0,2000.0])
+        #legend(('Analytical Solution', 'Numerical Solution'),
+        #        'lower right', shadow=False)
+        #xlabel('Position')
+        ylabel('Momentum')
+
+        plot3 = subplot(313)
+        plot(P,Enol, X,VelQ)
+        #plot2.set_ylim([-5,35])
+        #plot3.set_xlim([-100.0,2000.0])
+        legend(('Penyelesaian Analitis', 'Penyelesaian Numeris'),
+                'lower right', shadow=False)
+        xlabel('Position')
+        ylabel('Kecepatan')
+    
+        #file = "dam_h_"
+        #file += str(number_of_cells[i])
+        #file += ".eps"
+        #savefig(file)
+        #show()
+
+        #file = "dam_"
+        #file += str(finaltime)
+        #file += ".png"
+        #savefig(file)
+        #show()
+        filename = "%s%04i%s" %("dambreak", i, ".eps")
+        savefig(filename)
+        i = i + 1
+        print "The domain.limiter is", domain.limiter
+        print 'That took %.2f seconds'%(time.time()-t0)
+        print '============================================================================='
+        finaltime = finaltime + 0.25
+    
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/horizontal_dam_h_2sides.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/horizontal_dam_h_2sides.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/horizontal_dam_h_2sides.py	(revision 7576)
@@ -0,0 +1,174 @@
+import os
+from math import sqrt
+from shallow_water_domain_nonwellbalanced3 import *
+#from channel_domain import *
+from Numeric import zeros, Float
+from analytic_dam_sudi import AnalyticDam
+
+h0=5.0
+h1=10.0
+
+analytical_sol=AnalyticDam(h0,h1)
+
+"""
+def newLinePlot(title='Simple Plot'):
+    import Gnuplot
+    gg=Gnuplot.Gnuplot(persist=0)
+    gg.title(title)
+    gg('set data style linespoints')
+    gg.xlabel('x')
+    gg.ylabel('y')
+    return gg
+
+def linePlot(gg, x1, y1, x2, y2):
+    import Gnuplot
+    plot1=Gnuplot.PlotItems.Data(x1.flat, y1.flat, with="linespoints")
+    plot2=Gnuplot.PlotItems.Data(x2.flat, y2.flat, with="lines 3")
+    gg.plot(plot1, plot2)
+"""
+
+
+print "TEST 1D-SOLUTION I"
+
+L=2000.0
+N=400
+
+cell_len=L/N
+
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+
+domain.order = 2
+domain.set_timestepping_method('rk2')
+domain.cfl = 1.0
+domain.limiter = "vanleer"
+
+
+
+def height(x):
+    y=zeros(len(x), Float)
+    for i in range (len(x)):
+        if x[i]<=L/4.0:
+            y[i]=0.0 #h0
+        elif x[i]<=3*L/4.0:
+            y[i]=h1
+        else:
+            y[i]=h0
+    return y
+
+domain.set_quantity('stage',height)
+print "domain order=", domain.order
+print "domain limiter=", domain.limiter
+
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+
+X=domain.vertices
+C=domain.centroids
+#plot1x=newLinePlot("Height")
+#plot2x=newLinePlot("Momentum")
+
+import time
+yieldstep=finaltime=10.0
+t0=time.time()
+
+"""
+for i in range(10):
+    L=2000.0
+    N=400
+    cell_len=L/N
+    points=zeros(N+1, Float)
+    for i in range(N+1):
+        points[i]=i*cell_len
+    domain=Domain(points)
+    domain.order = 2
+    domain.set_timestepping_method('rk2')
+    domain.cfl = 1.0
+    domain.limiter = "vanleer"
+    domain.set_quantity('stage',height)
+    domain.set_boundary({'exterior':Reflective_boundary(domain)})
+    #print "integral", domain.quantities['stage'].get_integral()
+    for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+        domain.write_time()
+    #print "integral", domain.quantities['stage'].get_integral()
+    #print '==================================================================='
+print 'The average time is %.2f seconds'%((time.time()-t0)/10.0)
+"""
+while finaltime<10.1:
+    yieldstep=finaltime
+    for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+        domain.write_time()
+    if t>0.0:
+        N = float(N)
+        StageC = domain.quantities['stage'].centroid_values
+        XmomC = domain.quantities['xmomentum'].centroid_values
+        VelC = domain.quantities['velocity'].centroid_values
+        C = domain.centroids
+        hC, uhC, uC = analytical_sol(C,domain.time)
+        h_error = cell_len*sum(abs(hC-StageC))
+        uh_error = cell_len*sum(abs(uhC-XmomC))
+        u_error = cell_len*sum(abs(uC-VelC))
+        print "h_error %.10f" %(h_error)
+        print "uh_error %.10f"%(uh_error)
+        print "u_error %.10f" %(u_error)
+        print 'That took %.2f seconds' %(time.time()-t0)
+        X = domain.vertices
+        StageQ = domain.quantities['stage'].vertex_values
+        XmomQ = domain.quantities['xmomentum'].vertex_values
+        VelQ = domain.quantities['velocity'].vertex_values
+
+        h, uh, u = analytical_sol(X.flat, domain.time)
+        #linePlot(plot1x, X, HeightQ, X, h)
+        #linePlot(plot2x, X, MomentumQ, X, uh)
+        #print "press return"
+        #pass
+   
+        from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+        hold(False)
+       
+        plot1 = subplot(311)
+        plot(X,h,X,StageQ)
+        plot1.set_ylim([-1,11])
+        plot1.set_xlim([-100.0,2000.0])
+        #xlabel('Position')
+        ylabel('Stage')
+        #legend(('Analytical Solution', 'Numerical Solution'),
+        #   'lower right', shadow=False)
+        
+        plot2 = subplot(312)
+        plot(X,uh,X,XmomQ)
+        #plot2.set_ylim([-10,1])
+        plot2.set_xlim([-100.0,2000.0])
+        #legend(('Analytical Solution', 'Numerical Solution'),
+        #        'lower right', shadow=False)
+        #xlabel('Position')
+        ylabel('Momentum')
+
+        
+        plot3 = subplot(313)
+        plot(X,u,X,VelQ)
+        #plot3.set_ylim([-5,35])
+        plot3.set_xlim([-100.0,2000.0])
+        legend(('Analytical Solution', 'Numerical Solution'),
+                'lower right', shadow=False)
+        xlabel('Position')
+        ylabel('Velocity')
+        
+        
+        #file = "dam_h_"
+        #file += str(number_of_cells[i])
+        #file += ".eps"
+        #savefig(file)
+        #show()
+
+        #file = "dam_"
+        #file += str(finaltime)
+        #file += ".png"
+        #savefig(file)
+        #show()
+    print "The domain.limiter is", domain.limiter
+    print 'That took %.2f seconds'%(time.time()-t0)
+    print '============================================================================='
+    finaltime = finaltime + 5.0
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/horizontal_dam_h_2sidesOKTI.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/horizontal_dam_h_2sidesOKTI.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/horizontal_dam_h_2sidesOKTI.py	(revision 7576)
@@ -0,0 +1,144 @@
+import os
+from math import sqrt
+from shallow_water_domain_h_wellbalanced import *
+from Numeric import zeros, Float
+from scipy import linspace
+#from analytic_dam_sudi import AnalyticDam
+
+h0=5.0
+h1=10.0
+
+#analytical_sol=AnalyticDam(h0,h1)
+
+
+print "TEST 1D-SOLUTION I"
+
+L=2000.0
+N=16000
+
+cell_len=L/N
+
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+
+domain.order = 2
+domain.set_timestepping_method('rk2')
+domain.cfl = 1.0
+domain.limiter = "minmod"
+
+
+
+def stage(x):
+    y=zeros(len(x), Float)
+    for i in range (len(x)):
+        if x[i]<=L/4.0:
+            y[i]=0.0 #h0
+        elif x[i]<=3*L/4.0:
+            y[i]=h1
+        else:
+            y[i]=h0
+    return y
+
+def elevation(x):
+    y=zeros(len(x), Float)
+    for i in range (len(x)):
+        if x[i]<=500:
+            y[i]=4*x[i]*x[i]/250000
+        elif x[i]<=1500:
+            y[i]=(500-x[i])/1000 + 4
+        else:
+            y[i]=-3*(x[i]-1000)*(x[i]-2000)/250000
+    return y
+
+
+P=linspace(0,2000,2000)
+Elev_bed=elevation(P)
+
+domain.set_quantity('stage',stage)
+domain.set_quantity('elevation', elevation)
+print "domain order", domain.order
+
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+
+X=domain.vertices
+C=domain.centroids
+#plot1x=newLinePlot("Height")
+#plot2x=newLinePlot("Momentum")
+
+import time
+yieldstep=finaltime=0.0001
+t0=time.time()
+
+i=1
+while finaltime < 0.00011:
+    for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+        domain.write_time()
+    #if t>0.0:
+        #N = float(N)
+        #StageC = domain.quantities['stage'].centroid_values
+        #XmomC = domain.quantities['xmomentum'].centroid_values
+        #VelC = domain.quantities['velocity'].centroid_values
+        #C = domain.centroids
+        #hC, uhC, uC = analytical_sol(C,domain.time)
+
+
+        #h_error = sum(abs(hC-StageC))/N
+        #uh_error = sum(abs(uhC-XmomC))/N
+        #u_error = sum(abs(uC-VelC))/N
+        #print "h_error %.10f" %(h_error)
+        #print "uh_error %.10f"%(uh_error)
+        #print "u_error %.10f" %(u_error)
+        #print 'That took %.2f seconds' %(time.time()-t0)
+        X = domain.vertices
+        StageQ = domain.quantities['stage'].vertex_values
+        XmomQ = domain.quantities['xmomentum'].vertex_values
+        VelQ = domain.quantities['velocity'].vertex_values
+
+        #h, uh, u = analytical_sol(X.flat, domain.time)
+        #linePlot(plot1x, X, HeightQ, X, h)
+        #linePlot(plot2x, X, MomentumQ, X, uh)
+        #print "press return"
+        #pass
+   
+        from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+        hold(False)
+           
+        plot1 = subplot(311)
+        plot(X,StageQ, P,Elev_bed) #plot(X,StageQ,'k-', P,Elev_bed,'k:')
+        plot1.set_ylim([-1,11])
+        plot1.set_xlim([0.0,2000.0])
+        #xlabel('Position')
+        ylabel('Stage')
+        #legend(('Analytical Solution', 'Numerical Solution'),
+        #   'lower right', shadow=False)
+        
+        plot2 = subplot(312)
+        plot(X,XmomQ) #plot(X,XmomQ,'k-')
+        #plot2.set_ylim([-5,35])
+        plot2.set_xlim([0.0,2000.0])
+        #legend(('Analytical Solution', 'Numerical Solution'),
+        #        'lower right', shadow=False)
+        #xlabel('Position')
+        ylabel('Momentum')
+        plot3 = subplot(313)
+        plot(X,VelQ) #plot(X,VelQ,'k-')
+        #plot2.set_ylim([-5,35])
+        plot3.set_xlim([0.0,2000.0])
+        legend(('Penyelesaian Numeris', ' '),
+            'lower right', shadow=False)
+        xlabel('Posisi')
+        ylabel('Kecepatan')
+
+        #file = "dam"
+        #file += str(finaltime)
+        #file += ".png"
+        #savefig(file)
+        #show()
+        
+        filename = "%s%02i%s" %("dam_init2_", i, ".eps")
+        savefig(filename)
+        finaltime = finaltime + 0.25
+        i = i + 1
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/horizontal_dry_dam_h_1side.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/horizontal_dry_dam_h_1side.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/horizontal_dry_dam_h_1side.py	(revision 7576)
@@ -0,0 +1,159 @@
+import os
+from math import sqrt, sin, cos, pi, exp
+from shallow_water_domain_h_nonwellbalanced import *
+from Numeric import zeros, Float
+
+def analytic_dry_dam(C,t):
+    #t  = 0.0     # time (s)
+    g  = 9.81     # gravity (m/s^2)
+    h1 = 10.0     # depth upstream (m)
+    h0 = 0.0      # depth downstream (m)
+    L = 2000.0    # length of stream/domain (m)
+    n = len(C)    # number of cells
+
+    u = zeros(n,Float)
+    h = zeros(n,Float)
+    z = zeros(n,Float)
+    x = C-L/2.0
+
+    for i in range(n):
+        # Calculate Analytical Solution at time t > 0
+        u3 = 2.0/3.0*(sqrt(g*h1)+x[i]/t) 
+        h3 = 4.0/(9.0*g)*(sqrt(g*h1)-x[i]/(2.0*t))*(sqrt(g*h1)-x[i]/(2.0*t)) 
+
+        if ( x[i] <= -t*sqrt(g*h1) ):
+            u[i] = 0.0 
+            h[i] = h1 
+        elif ( x[i] <= 2.0*t*sqrt(g*h1) ):
+            u[i] = u3 
+            h[i] = h3 
+        else:
+            u[i] = 0.0 
+            h[i] = h0 
+
+    return h+z , u*(h+z)
+
+
+def stage_dam(x):
+    h1 = 10.0
+    h0 = 0.0
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if x[i] <= 1000.0:
+            y[i] = h1
+        else:
+            y[i] = h0
+    return y
+
+
+
+'''
+def newLinePlot(title='Simple Plot'):
+    import Gnuplot
+    gg=Gnuplot.Gnuplot(persist=0)
+    gg.title(title)
+    gg('set data style linespoints')
+    gg.xlabel('x')
+    gg.ylabel('y')
+    return gg
+
+def linePlot(gg, x1, y1, x2, y2):
+    import Gnuplot
+    plot1=Gnuplot.PlotItems.Data(x1.flat, y1.flat, with="linespoints")
+    plot2=Gnuplot.PlotItems.Data(x2.flat, y2.flat, with="lines 3")
+    gg.plot(plot1, plot2)
+'''
+
+
+print "TEST 1D-SOLUTION I"
+
+L=2000.0
+N=400
+cell_len=L/N
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+domain=Domain(points)
+domain.order = 2
+domain.set_timestepping_method('rk2')
+domain.cfl = 1.0
+domain.limiter = "vanleer"
+domain.set_quantity('stage',stage_dam)
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+
+X=domain.vertices
+C=domain.centroids
+
+#plot1x=newLinePlot("Stage")
+#plot2x=newLinePlot("Momentum")
+
+print 'THE DOMAIN ORDER is', domain.order
+print 'The Time Stepping Method is', domain.set_timestepping_method
+print 'THE DOMAIN LIMITER is', domain.limiter
+import time
+t0=time.time()
+yieldstep=20.0
+finaltime=20.0
+print "integral", domain.quantities['stage'].get_integral()
+for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+    domain.write_time()
+    print "integral", domain.quantities['stage'].get_integral()
+    if t>0.0:
+        StageQ=domain.quantities['stage'].vertex_values
+        MomentumQ=domain.quantities['xmomentum'].vertex_values
+        ElevationQ=domain.quantities['elevation'].vertex_values
+        
+        #h, uh=analytical_sol(X.flat, domain.time)
+        #linePlot(plot1x, X, StageQ, X, ElevationQ)
+        #linePlot(plot2x, X, MomentumQ, X, MomentumQ)#, X, uh)   #(plot2x, X, MomentumQ, X, uh)
+        #print "press return"
+        #pass
+
+
+        #This is only for dry dam
+        N = float(N)
+        StageC = domain.quantities['stage'].centroid_values
+        XmomC = domain.quantities['xmomentum'].centroid_values
+        ElevationC = domain.quantities['elevation'].centroid_values
+        C = domain.centroids
+        h, uh = analytic_dry_dam(C,domain.time)
+        h_error = 1.0/(N)*sum(abs(h-StageC))
+        uh_error = 1.0/(N)*sum(abs(uh-XmomC))
+        print "h_error %.10f" %(h_error)
+        print "uh_error %.10f"% (uh_error)
+        print 'That took %.2f seconds' %(time.time()-t0)
+        X = domain.vertices
+        StageQ = domain.quantities['stage'].vertex_values
+        XmomQ = domain.quantities['xmomentum'].vertex_values
+        h, uh = analytic_dry_dam(X.flat,domain.time)
+        #End for dry dam
+    
+        
+        from pylab import clf,plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot,ion
+        #ion()
+        hold(False)
+        clf()
+
+        plot1 = subplot(211)
+        plot(X,StageQ, X,h, X,ElevationQ)   #(X,ElevationQ,X,StageQ, X,h)
+        plot1.set_ylim([-1.0,11.0]) #([9.999,10.006]) #([9.9999,10.0006]) #([-1.0,11.0])
+        xlabel('Position')
+        ylabel('Stage')
+        legend( ('Numerical Solution', 'Analytical Solution', 'Bed Elevation'), 'upper right', shadow=False)      
+
+        plot2 = subplot(212)
+        plot(X,MomentumQ, X,uh)
+        plot2.set_ylim([-5.0,30.0])
+        legend( ('Numerical Solution', 'for momentum'), 'upper right', shadow=False)    
+        xlabel('Position')
+        ylabel('Xmomentum')
+        
+        #file = "dam_h_"
+        #file += str(number_of_cells[i])
+        #file += ".eps"
+        #savefig(file)
+        show()
+        
+print 'That took %.2f seconds'%(time.time()-t0)
+raw_input("Press return key")
+
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/island.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/island.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/island.py	(revision 7576)
@@ -0,0 +1,110 @@
+import os
+import time
+from math import sqrt, sin, cos, pi, exp
+from shallow_water_domain_suggestion3 import *
+from Numeric import zeros, Float
+from pylab import clf,plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot,ion
+
+print "TEST USING 3 CELLS"
+L=2000.0
+N=40
+cell_len=L/N
+
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+domain.order = 1
+domain.set_timestepping_method('euler')
+domain.cfl = 1.0
+domain.limiter = "vanleer"
+
+def stage_3cells(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if x[i] <= 100.0:
+            y[i] = 10.0
+        elif 100.0 < x[i] < 900.0:
+            y[i] = 8.0
+        elif 900.0 <= x[i] <= 1100.0:
+            y[i] = 10.0
+        elif 1100.0 < x[i] < 1900.0:
+            y[i] = 8.0
+        else:
+            y[i] = 10.0
+        #else:
+        #    y[i] = x[i]/150.0
+    return y
+
+def elevation_3cells(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if x[i] <= 100.0:
+            y[i] = 10.0
+        elif 100.0 < x[i] < 900.0:
+            y[i] = 0.0
+        elif 900.0 <= x[i] <= 1100.0:
+            y[i] = 10.0
+        elif 1100.0 < x[i] < 1900.0:
+            y[i] = 0.0
+        else:
+            y[i] = 10.0
+    return y
+
+domain.set_quantity('stage',stage_3cells)
+domain.set_quantity('elevation',elevation_3cells)
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+
+X=domain.vertices
+C=domain.centroids
+
+t0=time.time()
+yieldstep=0.01 #30.0
+finaltime=0.01 #20.0
+#print "integral", domain.quantities['height'].get_integral()
+for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+    #domain.write_time()
+    #print "integral", domain.quantities['height'].get_integral()
+    if t>=0.0:
+        StageQ=domain.quantities['stage'].vertex_values
+        MomentumQ=domain.quantities['xmomentum'].vertex_values
+        ElevationQ=domain.quantities['elevation'].vertex_values
+        
+        hold(False)
+
+        plot1 = subplot(211)
+        plot(X,StageQ, X,ElevationQ)  #plot(X,StageQ, X,h, X,ElevationQ)   #(X,ElevationQ,X,StageQ, X,h)
+        plot1.set_ylim([-1.0,11.0]) #([9.999,10.006]) #([9.9999,10.0006]) #([-1.0,11.0])
+        xlabel('Position')
+        ylabel('Stage')
+        legend( ('Numerical Solution', 'Bed Elevation'), 'upper right', shadow=False)
+        #legend(('Analytical Solution', 'Numerical Solution'),
+        #   'lower right', shadow=False)
+
+        plot2 = subplot(212)
+        plot(X,MomentumQ)   #plot(X,MomentumQ, X,uh)
+        #plot2.set_ylim([-5.0,30.0])
+        legend( ('Numerical Solution', 'for momentum'), 'upper right', shadow=False)
+    
+        xlabel('Position')
+        ylabel('Xmomentum')
+
+        '''
+        plot3 = subplot(313)
+        plot(X,VelocityQ) #plot(X,MomentumQ, X,uh)
+        #plot2.set_ylim([-0.01,0.01])
+        legend( ('Numerical Solution', 'for velocity'), 'upper right', shadow=False)
+        xlabel('Position')
+        ylabel('Velocity')
+        '''
+        
+        #file = "dam_h_"
+        #file += str(number_of_cells[i])
+        #file += ".eps"
+        #savefig(file)
+        #show()
+        
+print 'That took %.2f seconds'%(time.time()-t0)
+raw_input("Press return key")
+
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/old_comp_flux_ext_wellbalanced.c
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/old_comp_flux_ext_wellbalanced.c	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/old_comp_flux_ext_wellbalanced.c	(revision 7576)
@@ -0,0 +1,288 @@
+#include "Python.h"
+#include "Numeric/arrayobject.h"
+#include "math.h"
+#include <stdio.h>
+const double pi = 3.14159265358979;
+
+
+// Shared code snippets
+#include "util_ext.h"
+
+
+//double max(double a, double b) { 
+// 	double z; 
+// 	z=(a>b)?a:b; 
+// 	return z;} 
+	
+//double min(double a, double b) { 
+// 	double z; 
+// 	z=(a<b)?a:b; 
+// 	return z;} 
+
+
+
+
+
+//Innermost flux function (using w=z+h)
+int _flux_function_wellbalanced(double *q_left, double *q_right,
+		double normals, double g, double epsilon,
+		double *edgeflux, double *max_speed) {
+		
+		int i;
+        double z_left, z_right;
+		double flux_left[2], flux_right[2];
+		double z_star, w_left, h_left, h_left_star, uh_left, soundspeed_left, u_left;
+		double w_right, h_right, h_right_star, uh_right, soundspeed_right, u_right;                          //h_right,
+		double s_max, s_min, denom;
+		
+		w_left = q_left[0];
+		uh_left = q_left[1];
+		uh_left = uh_left*normals;
+        z_left = q_left[2];
+	
+		w_right = q_right[0];
+		uh_right = q_right[1];
+		uh_right = uh_right*normals;
+        z_right = q_right[2];
+	  
+		if (z_left-z_right != 0.0 ) printf("z_l - z_r = %f \n",z_left-z_right);
+        
+		//z = (z_left+z_right)/2.0;
+		z_star = max(z_left, z_right);		              											//equation(7)  
+				   
+		// Compute speeds in x-direction
+		h_left = w_left-z_left;		                                                                //This is used for computing the edgeflux[1].
+		h_left_star = max(0, w_left-z_star);														//(8)
+    
+		if (h_left_star < epsilon) {
+			u_left = 0.0; h_left_star = 0.0;
+		}
+		else {
+			u_left = uh_left/h_left_star;
+		}
+	
+		h_right = w_right-z_right;                                                                                                                                                                                                     
+		h_right_star = max(0, w_right-z_star);														//(9)
+
+		if (h_right_star < epsilon) {
+			u_right = 0.0; h_right_star = 0.0; 
+		}
+		else {
+			u_right = uh_right/h_right_star;
+		}
+  
+		//printf("u_left = %g u_right = %g \n",u_left, u_right);
+		soundspeed_left = sqrt(g*h_left_star);
+		soundspeed_right = sqrt(g*h_right_star);
+		
+		s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
+		if (s_max < 0.0) s_max = 0.0;
+	
+		s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
+		if (s_min > 0.0) s_min = 0.0;
+		
+		
+		// Flux formulas
+		flux_left[0] = u_left*h_left_star;
+		flux_left[1] = u_left*u_left*h_left_star + 0.5*g*h_left_star*h_left_star;
+
+		flux_right[0] = u_right*h_right_star;
+		flux_right[1] = u_right*u_right*h_right_star + 0.5*g*h_right_star*h_right_star;
+
+		// Flux computation
+		denom = s_max-s_min;
+		if (denom < epsilon) {
+			for (i=0; i<2; i++) edgeflux[i] = 0.0;
+			*max_speed = 0.0;
+		} else {
+			edgeflux[0] = s_max*flux_left[0] - s_min*flux_right[0];
+			edgeflux[0] += s_max*s_min*(h_right_star-h_left_star);                   //s_max*s_min*(qr[0]-ql[0]);
+			edgeflux[0] /= denom;
+			edgeflux[1] = s_max*flux_left[1] - s_min*flux_right[1];
+			edgeflux[1] += s_max*s_min*(flux_right[0]-flux_left[0]);                 //s_max*s_min*(qr[1]-ql[1]);
+			edgeflux[1] /= denom;
+			edgeflux[1] *= normals;
+    
+		//edgeflux[1] = edgeflux[1] + 0.5*g*0.5*(h_left+h_right)*0.5*(h_left+h_right) - 0.5*g*h_left_star*h_left_star;
+		//edgeflux[1] = edgeflux[1] + 0.5*g*h_right*h_right - 0.5*g*h_right_star*h_right_star;
+		edgeflux[1] = edgeflux[1] + 0.5*g*h_left*h_left - 0.5*g*h_left_star*h_left_star;           //what about the h_right and h_right_star??????????????????????
+		// Maximal wavespeed
+        *max_speed = max(fabs(s_max), fabs(s_min));
+		}  
+		//printf("max_speed = %g \n",*max_speed);
+    return 0;		
+	}
+		
+		
+	
+	
+// Computational function for flux computation
+double _compute_fluxes_ext_wellbalanced(double timestep,
+		double epsilon,
+		double g,
+		long* neighbours,
+		long* neighbour_vertices,
+		double* normals,
+		double* areas,
+		double* stage_edge_values,
+		double* xmom_edge_values,
+		double* bed_edge_values,
+		double* stage_boundary_values,
+		double* xmom_boundary_values,
+		double* stage_explicit_update,
+		double* xmom_explicit_update,
+		int number_of_elements,
+		double* max_speed_array) {
+		
+		double flux[2], ql[3], qr[3], edgeflux[2];
+		double max_speed, normal;
+		int k, i, ki, n, m, nm=0;
+		
+		for (k=0; k<number_of_elements; k++) {
+			flux[0] = 0.0;
+			flux[1] = 0.0;
+			
+			for (i=0; i<2; i++) {
+				ki = k*2+i;
+				
+				ql[0] = stage_edge_values[ki];
+				ql[1] = xmom_edge_values[ki];
+				ql[2] = bed_edge_values[ki];
+				//ql[3] = velocity_edge_values[ki];
+                //ql[4] = height_edge_values[ki];
+                
+				n = neighbours[ki];
+				if (n<0) {
+					m = -n-1;
+					qr[0] = stage_boundary_values[m];
+					qr[1] = xmom_boundary_values[m];
+					qr[2] = ql[2];
+                    
+				} else {
+					m = neighbour_vertices[ki];
+					nm = n*2+m;
+					qr[0] = stage_edge_values[nm];
+					qr[1] = xmom_edge_values[nm];
+					qr[2] = bed_edge_values[nm];				
+				}
+				
+				normal = normals[ki];
+				_flux_function_wellbalanced(ql, qr, normal, g, epsilon, edgeflux, &max_speed);
+				flux[0] -= edgeflux[0];
+				flux[1] -= edgeflux[1];
+				
+				// Update timestep based on edge i and possibly neighbour n
+				if (max_speed > epsilon) {
+	                // Original CFL calculation
+					
+					timestep = min(timestep, 0.5*areas[k]/max_speed); //Here, CFL=1.0 is assumed. ?????????????????????????????????????????????
+					if (n>=0) {
+						timestep = min(timestep, 0.5*areas[n]/max_speed); //Here, CFL=1.0 is assumed. ?????????????????????????????????????????????
+					}
+				}
+            } // End edge i (and neighbour n)
+			flux[0] /= areas[k];
+			stage_explicit_update[k] = flux[0];
+			flux[1] /= areas[k];
+			xmom_explicit_update[k] = flux[1];
+			
+			//Keep track of maximal speeds
+			max_speed_array[k]=max_speed;
+		}
+		//printf("timestep = %f \n",timestep);
+		return timestep;	
+	}
+	
+	
+	
+
+
+
+//=========================================================================
+// Python Glue
+//=========================================================================
+PyObject *compute_fluxes_ext_wellbalanced(PyObject *self, PyObject *args) {
+  
+    PyArrayObject 
+	*neighbours, 
+	*neighbour_vertices,
+	*normals, 
+	*areas,
+	*stage_edge_values,
+	*xmom_edge_values,
+	*bed_edge_values,
+	*stage_boundary_values,
+	*xmom_boundary_values,
+	*stage_explicit_update,
+	*xmom_explicit_update,
+	*max_speed_array;
+    
+  double timestep, epsilon, g;
+  int number_of_elements;
+    
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOiO",
+			&timestep,
+			&epsilon,
+			&g,
+			&neighbours,
+			&neighbour_vertices,
+			&normals,
+			&areas,
+			&stage_edge_values,
+			&xmom_edge_values,
+			&bed_edge_values,
+			&stage_boundary_values,
+			&xmom_boundary_values,
+			&stage_explicit_update,
+			&xmom_explicit_update,
+			&number_of_elements,
+			&max_speed_array)) {
+    PyErr_SetString(PyExc_RuntimeError, "old_comp_flux_ext_wellbalanced.c: compute_fluxes_ext_wellbalanced could not parse input");
+    return NULL;
+  }
+
+ 
+  // Call underlying flux computation routine and update 
+  // the explicit update arrays 
+  timestep = _compute_fluxes_ext_wellbalanced(timestep,
+				 epsilon,
+				 g,
+				 (long*) neighbours -> data,
+				 (long*) neighbour_vertices -> data,
+				 (double*) normals -> data,
+				 (double*) areas -> data,
+				 (double*) stage_edge_values -> data,
+				 (double*) xmom_edge_values -> data,
+				 (double*) bed_edge_values -> data,
+				 (double*) stage_boundary_values -> data,
+				 (double*) xmom_boundary_values -> data,
+				 (double*) stage_explicit_update -> data,
+				 (double*) xmom_explicit_update -> data,
+				 number_of_elements,
+				 (double*) max_speed_array -> data);
+
+  // Return updated flux timestep
+  return Py_BuildValue("d", timestep);
+}
+
+
+
+
+
+//-------------------------------
+// Method table for python module
+//-------------------------------
+
+static struct PyMethodDef MethodTable[] = {
+  {"compute_fluxes_ext_wellbalanced", compute_fluxes_ext_wellbalanced, METH_VARARGS, "Print out"},
+  {NULL, NULL}
+};
+
+// Module initialisation
+void initold_comp_flux_ext_wellbalanced(void){
+  Py_InitModule("old_comp_flux_ext_wellbalanced", MethodTable);
+  import_array();
+}
+	
+	
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/old_shallow_water_domain_suggestion1.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/old_shallow_water_domain_suggestion1.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/old_shallow_water_domain_suggestion1.py	(revision 7576)
@@ -0,0 +1,1409 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+
+from domain import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['stage', 'xmomentum']
+        evolved_quantities = ['stage', 'xmomentum', 'elevation', 'height', 'velocity']
+        other_quantities = ['friction']
+        Generic_Domain.__init__(self,
+                                coordinates = coordinates,
+                                boundary = boundary,
+                                conserved_quantities = conserved_quantities,
+                                evolved_quantities = evolved_quantities,
+                                other_quantities = other_quantities,
+                                tagged_elements = tagged_elements)
+        
+        from config import minimum_allowed_height, g, h0, h_min
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+        self.h0 = h0
+        self.h_min = h_min
+
+        #forcing terms not included in 1d domain? Why?
+        self.forcing_terms.append(gravity)
+        #self.forcing_terms.append(manning_friction)
+        #print "\nI have Removed forcing terms line 64 1dsw"
+
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.set_quantities_to_be_stored(['stage','xmomentum'])
+
+	self.__doc__ = 'shallow_water_domain_suggestion1'
+
+        self.check_integrity()
+
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+    def check_integrity(self):
+
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+
+        msg = 'First evolved quantity must be "stage"'
+        assert self.evolved_quantities[0] == 'stage', msg
+        msg = 'Second evolved quantity must be "xmomentum"'
+        assert self.evolved_quantities[1] == 'xmomentum', msg
+        msg = 'Third evolved quantity must be "elevation"'
+        assert self.evolved_quantities[2] == 'elevation', msg
+        msg = 'Fourth evolved quantity must be "height"'
+        assert self.evolved_quantities[3] == 'height', msg
+        msg = 'Fifth evolved quantity must be "velocity"'
+        assert self.evolved_quantities[4] == 'velocity', msg
+
+        Generic_Domain.check_integrity(self)
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes_C_wellbalanced(self)
+
+    def compute_timestep(self):
+        #Call correct module function
+        compute_timestep(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+        
+    def evolve(self, yieldstep = None, finaltime = None, duration = None,
+               skip_initial_step = False):
+        """Specialisation of basic evolve method from parent class
+        """
+
+        #Call check integrity here rather than from user scripts
+        #self.check_integrity()
+
+        #msg = 'Parameter beta_h must be in the interval [0, 1)'
+        #assert 0 <= self.beta_h < 1.0, msg
+        #msg = 'Parameter beta_w must be in the interval [0, 1)'
+        #assert 0 <= self.beta_w < 1.0, msg
+
+
+        #Initial update of vertex and edge values before any storage
+        #and or visualisation
+        
+        #self.distribute_to_vertices_and_edges ?????????????????????????????????
+        
+        #Initialise real time viz if requested
+        #if self.visualise is True and self.time == 0.0:
+        #    if self.visualiser is None:
+        #        self.initialise_visualiser()
+        #
+        #    self.visualiser.update_timer()
+        #    self.visualiser.setup_all()
+
+        #Store model data, e.g. for visualisation
+        #if self.store is True and self.time == 0.0:
+        #    self.initialise_storage()
+        #    #print 'Storing results in ' + self.writer.filename
+        #else:
+        #    pass
+        #    #print 'Results will not be stored.'
+        #    #print 'To store results set domain.store = True'
+        #    #FIXME: Diagnostic output should be controlled by
+        #    # a 'verbose' flag living in domain (or in a parent class)
+
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime,duration,
+                                       skip_initial_step):
+            #Real time viz
+        #    if self.visualise is True:
+        #        self.visualiser.update_all()
+        #        self.visualiser.update_timer()
+
+
+            #Store model data, e.g. for subsequent visualisation
+        #    if self.store is True:
+        #        self.store_timestep(self.quantities_to_be_stored)
+
+            #FIXME: Could maybe be taken from specified list
+            #of 'store every step' quantities
+
+            #Pass control on to outer loop for more specific actions
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x and bed elevation
+        """
+
+        import data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+
+#Rotation of momentum vector
+def rotate(q, normal, direction = 1):
+    """Rotate the momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector.
+
+    If direction is negative the rotation is inverted.
+
+    Input vector is preserved
+
+    This function is specific to the shallow water wave equation
+    """
+
+    from Numeric import zeros, Float
+
+    assert len(q) == 3,\
+           'Vector of conserved quantities must have length 3'\
+           'for 2D shallow water equation'
+
+    try:
+        l = len(normal)
+    except:
+        raise 'Normal vector must be an Numeric array'
+
+    assert l == 2, 'Normal vector must have 2 components'
+
+
+    n1 = normal[0]
+    n2 = normal[1]
+
+    r = zeros(len(q), Float) #Rotated quantities
+    r[0] = q[0]              #First quantity, height, is not rotated
+
+    if direction == -1:
+        n2 = -n2
+
+
+    r[1] =  n1*q[1] + n2*q[2]
+    r[2] = -n2*q[1] + n1*q[2]
+
+    return r
+
+
+def flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon, h0
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+	
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/(h_left +  h0/h_left)
+
+
+    uh_left = u_left*h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/(h_right + h0/h_right)
+
+    uh_right = u_right*h_right
+	
+
+    #We have got h and u at vertex, then the following is the calculation of fluxes!
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+# 
+def compute_fluxes(domain):
+    """
+	Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+
+    domain.distribute_to_vertices_and_edges()
+    domain.update_boundary()
+    
+    N = domain.number_of_elements
+    Stage = domain.quantities['stage']
+    Xmom  = domain.quantities['xmomentum']
+    Bed   = domain.quantities['elevation']
+
+    stage = Stage.vertex_values
+    xmom  = Xmom.vertex_values
+    bed   = Bed.vertex_values
+    
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+
+	
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            #ql[0] = stage[k, i]
+            #ql[1] = xmom[k, i]
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] = xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            #Flux computation using provided function
+     
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #print 'edgeflux', edgeflux
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        Stage.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k] =  flux[1]
+        #Ymom.explicit_update[k] = flux[2]
+        #print "flux cell",k,flux[0]
+
+    domain.flux_timestep = timestep
+    #print domain.quantities['stage'].centroid_values
+#
+def compute_timestep(domain):
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                qr[0] = stage[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #Update optimal_timestep
+            try:
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+    domain.timestep = timestep
+
+# Compute flux definition
+def compute_fluxes_C_long(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+    #print 'timestep=',timestep
+    #print 'The type of timestep is',type(timestep)
+	
+    epsilon = domain.epsilon
+    #print 'epsilon=',epsilon
+    #print 'The type of epsilon is',type(epsilon)
+	
+    g = domain.g
+    #print 'g=',g
+    #print 'The type of g is',type(g)
+	
+    neighbours = domain.neighbours
+    #print 'neighbours=',neighbours
+    #print 'The type of neighbours is',type(neighbours)
+	
+    neighbour_vertices = domain.neighbour_vertices
+    #print 'neighbour_vertices=',neighbour_vertices
+    #print 'The type of neighbour_vertices is',type(neighbour_vertices)
+	
+    normals = domain.normals
+    #print 'normals=',normals
+    #print 'The type of normals is',type(normals)
+	
+    areas = domain.areas
+    #print 'areas=',areas
+    #print 'The type of areas is',type(areas)
+	
+    stage_edge_values = domain.quantities['stage'].vertex_values
+    #print 'stage_edge_values=',stage_edge_values
+    #print 'The type of stage_edge_values is',type(stage_edge_values)
+	
+    xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+    #print 'xmom_edge_values=',xmom_edge_values
+    #print 'The type of xmom_edge_values is',type(xmom_edge_values)
+	
+    bed_edge_values = domain.quantities['elevation'].vertex_values
+    #print 'bed_edge_values=',bed_edge_values
+    #print 'The type of bed_edge_values is',type(bed_edge_values)
+	
+    stage_boundary_values = domain.quantities['stage'].boundary_values
+    #print 'stage_boundary_values=',stage_boundary_values
+    #print 'The type of stage_boundary_values is',type(stage_boundary_values)
+	
+    xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+    #print 'xmom_boundary_values=',xmom_boundary_values
+    #print 'The type of xmom_boundary_values is',type(xmom_boundary_values)
+	
+    stage_explicit_update = domain.quantities['stage'].explicit_update
+    #print 'stage_explicit_update=',stage_explicit_update
+    #print 'The type of stage_explicit_update is',type(stage_explicit_update)
+	
+    xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+    #print 'xmom_explicit_update=',xmom_explicit_update
+    #print 'The type of xmom_explicit_update is',type(xmom_explicit_update)
+	
+    number_of_elements = len(stage_edge_values)
+    #print 'number_of_elements=',number_of_elements
+    #print 'The type of number_of_elements is',type(number_of_elements)
+	
+    max_speed_array = domain.max_speed_array
+    #print 'max_speed_array=',max_speed_array
+    #print 'The type of max_speed_array is',type(max_speed_array)
+        
+        
+    from comp_flux_ext import compute_fluxes_ext
+	
+    domain.flux_timestep = compute_fluxes_ext(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_edge_values,
+                                  xmom_edge_values,
+                                  bed_edge_values,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+
+# Compute flux definition
+def compute_fluxes_C_short(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+
+    stage = domain.quantities['stage']
+    xmom = domain.quantities['xmomentum']
+    bed = domain.quantities['elevation']
+
+
+    from comp_flux_ext import compute_fluxes_ext_short
+
+    domain.flux_timestep = compute_fluxes_ext_short(timestep,domain,stage,xmom,bed)
+
+
+
+# ###################################
+def compute_fluxes_C_wellbalanced(domain):
+    import sys
+    from Numeric import zeros, Float
+    
+    N = domain.number_of_elements
+    timestep = float(sys.maxint)
+    epsilon = domain.epsilon
+    g = domain.g
+    neighbours = domain.neighbours
+    neighbour_vertices = domain.neighbour_vertices
+    normals = domain.normals
+    areas = domain.areas
+    
+    Stage = domain.quantities['stage']
+    Xmom  = domain.quantities['xmomentum']
+    Bed   = domain.quantities['elevation']
+
+    stage_boundary_values = Stage.boundary_values
+    xmom_boundary_values =  Xmom.boundary_values
+    stage_explicit_update = Stage.explicit_update
+    xmom_explicit_update = Xmom.explicit_update
+    max_speed_array = domain.max_speed_array
+    
+    domain.distribute_to_vertices_and_edges()
+    domain.update_boundary()
+    stage_V = Stage.vertex_values
+    xmom_V  = Xmom.vertex_values
+    bed_V   = Bed.vertex_values
+    #h_V     = Height.vertex_values
+    #u_V     = Velocity.vertex_values
+
+    number_of_elements = len(stage_V)
+
+    #flux = zeros(2, Float) #Work array for summing up fluxes
+    #ql = zeros(2, Float)
+    #qr = zeros(2, Float)
+	        
+    from old_comp_flux_ext_wellbalanced import compute_fluxes_ext_wellbalanced  #from comp_flux_ext import compute_fluxes_ext
+	
+    domain.flux_timestep = compute_fluxes_ext_wellbalanced(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_V,
+                                  xmom_V,
+                                  bed_V,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+# ###################################
+
+
+
+
+
+
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    #protect_against_infinitesimal_and_negative_heights(domain)  
+
+    import sys
+    from Numeric import zeros, Float
+    from config import epsilon, h0, h_min
+	
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    Height = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+    #Arrays   
+    w_C   = Stage.centroid_values    
+    uh_C  = Xmom.centroid_values    
+    z_C   = Bed.centroid_values
+    h_C   = Height.centroid_values
+    u_C   = Velocity.centroid_values
+
+	
+    #print id(h_C)
+    for i in range(N):
+	h_C[i] = w_C[i] - z_C[i]						
+        if h_C[i] <= h_min:
+	    #print 'h_C[%d]= %15.5e\n' % (i,h_C[i])
+	    h_C[i] = 0.0
+	    w_C[i] = z_C[i]
+	    uh_C[i] = 0.0
+	    u_C[i] = 0.0
+	else:
+            u_C[i] = uh_C[i]/(h_C[i] + h0/h_C[i])
+		
+	
+    for name in [ 'stage', 'velocity' ]:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            #print "add extrapolate second order to shallow water"
+            #if name != 'height':
+            Q.extrapolate_second_order()
+            #Q.limit()
+        else:
+            raise 'Unknown order'
+
+    stage_V = domain.quantities['stage'].vertex_values			
+    bed_V   = domain.quantities['elevation'].vertex_values	
+    h_V    = domain.quantities['height'].vertex_values
+    u_V    = domain.quantities['velocity'].vertex_values		
+    xmom_V = domain.quantities['xmomentum'].vertex_values
+
+
+    h_V[:]    = stage_V - bed_V
+    for i in range(len(h_C)):
+        for j in range(2):
+            if h_V[i,j] < 0.0 :
+                #print 'h_V[%d,%d] = %f \n' % (i,j,h_V[i,j])                 
+                dh = h_V[i,j]
+                h_V[i,j] = 0.0
+                stage_V[i,j] = bed_V[i,j]
+                h_V[i,(j+1)%2] = h_V[i,(j+1)%2] + dh
+                stage_V[i,(j+1)%2] = stage_V[i,(j+1)%2] + dh
+
+          
+    xmom_V[:] = u_V * h_V
+    for i in range(len(h_V)):
+        if h_V[i] <= h_min:
+            u_V[i] = 0.0 
+    
+    return
+
+#
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+    #ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    zv = domain.quantities['elevation'].vertex_values
+    wv = domain.quantities['stage'].vertex_values
+    hv = wv-zv
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    #remove the above two lines and corresponding code below
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+                wv[k,0] = zv[k,0]
+                wv[k,1] = zv[k,1]
+                
+            xmomc[k] = 0.0
+            
+        #N = domain.number_of_elements
+        #if (k == 0) | (k==N-1):
+        #    wc[k] = zc[k] # Contain 'lost mass' error
+        #    wv[k,0] = zv[k,0]
+        #    wv[k,1] = zv[k,1]
+    
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        #for i in range(3):
+        for i in range(2):   
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    #for i in range(3):
+    for i in range(2):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        #for i in range(3):
+        for i in range(2):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        #for i in range(3):
+        for i in range(2):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]))#,
+#                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using the h-limited
+        #stage and alpha==1 means using the w-limited stage as
+        #computed by the gradient limiter (both 1st or 2nd order)
+
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        alpha  = 0.0
+	#Let
+	#
+	#  wvi be the w-limited stage (wvi = zvi + hvi)
+	#  wvi- be the h-limited state (wvi- = zvi + hvi-)
+	#
+	#
+	#where i=0,1,2 denotes the vertex ids
+	#
+        #Weighted balance between w-limited and h-limited stage is
+        #
+	#  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+	#
+        #It follows that the updated wvi is
+        #  wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+        #
+	# Momentum is balanced between constant and limited
+
+
+        #for i in range(3):
+        #    wv[k,i] = zv[k,i] + hvbar[k,i]
+
+	#return
+
+	if alpha < 1:
+
+            #for i in range(3):
+            for i in range(2):
+                wv[k,i] = zv[k,i] + (1.0-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+#            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+#           ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1.0-alpha)*xmomc[k] + alpha*xmomv[k,:]
+#            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+###############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        self.normals  = domain.normals
+        self.stage    = domain.quantities['stage'].vertex_values
+        self.xmom     = domain.quantities['xmomentum'].vertex_values
+        self.bed      = domain.quantities['elevation'].vertex_values
+        self.height   = domain.quantities['height'].vertex_values
+        self.velocity = domain.quantities['velocity'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        self.evolved_quantities = zeros(5, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+
+        q = self.evolved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = -self.xmom[vol_id, edge_id]
+        q[2] = self.bed[vol_id, edge_id]
+        q[3] = self.height[vol_id, edge_id]
+        q[1] = -self.velocity[vol_id, edge_id]
+
+
+        return q
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, evolved_quantities=None):
+        Boundary.__init__(self)
+
+        if evolved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.evolved_quantities=array(evolved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.evolved_quantities
+
+
+#########################
+#Standard forcing terms:
+#
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    stage = domain.quantities['stage'].explicit_update
+#    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    #h = Stage.edge_values - Elevation.edge_values
+    h = Stage.vertex_values - Elevation.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+#        avg_h = sum( h[k,:] )/3
+        avg_h = sum( h[k,:] )/2
+
+        #Compute bed slope
+        #x0, y0, x1, y1, x2, y2 = x[k,:]
+        x0, x1 = x[k,:]
+        #z0, z1, z2 = v[k,:]
+        b0, b1 = b[k,:]
+
+        w0, w1 = w[k,:]
+        wx = gradient(x0, x1, w0, w1)
+
+        #zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        xmom[k] += -g*bx*avg_h
+        #xmom[k] = -g*bx*avg_h
+        #stage[k] = 0.0
+ 
+ 
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    #vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    #ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	#S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+                S = -g * eta[k]**2 * uh[k]
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	#ymom_update[k] += S*vh[k]
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+#    vh = domain.quantities['ymomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+#    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g #Not necessary? Why was this added?
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+ #           	ymom_update[k] += S*vh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
+class Wind_stress:
+    """Apply wind stress to water momentum in terms of
+    wind speed [m/s] and wind direction [degrees]
+    """
+
+    def __init__(self, *args, **kwargs):
+        """Initialise windfield from wind speed s [m/s]
+        and wind direction phi [degrees]
+
+        Inputs v and phi can be either scalars or Python functions, e.g.
+
+        W = Wind_stress(10, 178)
+
+        #FIXME - 'normal' degrees are assumed for now, i.e. the
+        vector (1,0) has zero degrees.
+        We may need to convert from 'compass' degrees later on and also
+        map from True north to grid north.
+
+        Arguments can also be Python functions of t,x,y as in
+
+        def speed(t,x,y):
+            ...
+            return s
+
+        def angle(t,x,y):
+            ...
+            return phi
+
+        where x and y are vectors.
+
+        and then pass the functions in
+
+        W = Wind_stress(speed, angle)
+
+        The instantiated object W can be appended to the list of
+        forcing_terms as in
+
+        Alternatively, one vector valued function for (speed, angle)
+        can be applied, providing both quantities simultaneously.
+        As in
+        W = Wind_stress(F), where returns (speed, angle) for each t.
+
+        domain.forcing_terms.append(W)
+        """
+
+        from config import rho_a, rho_w, eta_w
+        from Numeric import array, Float
+
+        if len(args) == 2:
+            s = args[0]
+            phi = args[1]
+        elif len(args) == 1:
+            #Assume vector function returning (s, phi)(t,x,y)
+            vector_function = args[0]
+            #s = lambda t,x,y: vector_function(t,x=x,y=y)[0]
+            #phi = lambda t,x,y: vector_function(t,x=x,y=y)[1]
+            s = lambda t,x: vector_function(t,x=x)[0]
+            phi = lambda t,x: vector_function(t,x=x)[1]
+        else:
+           #Assume info is in 2 keyword arguments
+
+           if len(kwargs) == 2:
+               s = kwargs['s']
+               phi = kwargs['phi']
+           else:
+               raise 'Assumes two keyword arguments: s=..., phi=....'
+
+        print 'phi', phi
+        self.speed = check_forcefield(s)
+        self.phi = check_forcefield(phi)
+
+        self.const = eta_w*rho_a/rho_w
+
+
+    def __call__(self, domain):
+        """Evaluate windfield based on values found in domain
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import Float, ones, ArrayType
+
+        xmom_update = domain.quantities['xmomentum'].explicit_update
+        #ymom_update = domain.quantities['ymomentum'].explicit_update
+
+        N = domain.number_of_elements
+        t = domain.time
+
+        if callable(self.speed):
+            xc = domain.get_centroid_coordinates()
+            #s_vec = self.speed(t, xc[:,0], xc[:,1])
+            s_vec = self.speed(t, xc)
+        else:
+            #Assume s is a scalar
+
+            try:
+                s_vec = self.speed * ones(N, Float)
+            except:
+                msg = 'Speed must be either callable or a scalar: %s' %self.s
+                raise msg
+
+
+        if callable(self.phi):
+            xc = domain.get_centroid_coordinates()
+            #phi_vec = self.phi(t, xc[:,0], xc[:,1])
+            phi_vec = self.phi(t, xc)
+        else:
+            #Assume phi is a scalar
+
+            try:
+                phi_vec = self.phi * ones(N, Float)
+            except:
+                msg = 'Angle must be either callable or a scalar: %s' %self.phi
+                raise msg
+
+        #assign_windfield_values(xmom_update, ymom_update,
+        #                        s_vec, phi_vec, self.const)
+        assign_windfield_values(xmom_update, s_vec, phi_vec, self.const)
+
+
+#def assign_windfield_values(xmom_update, ymom_update,
+#                            s_vec, phi_vec, const):
+def assign_windfield_values(xmom_update, s_vec, phi_vec, const):
+    """Python version of assigning wind field to update vectors.
+    A c version also exists (for speed)
+    """
+    from math import pi, cos, sin, sqrt
+
+    N = len(s_vec)
+    for k in range(N):
+        s = s_vec[k]
+        phi = phi_vec[k]
+
+        #Convert to radians
+        phi = phi*pi/180
+
+        #Compute velocity vector (u, v)
+        u = s*cos(phi)
+        v = s*sin(phi)
+
+        #Compute wind stress
+        #S = const * sqrt(u**2 + v**2)
+        S = const * u
+        xmom_update[k] += S*u
+        #ymom_update[k] += S*v
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/parabolic_cannal.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/parabolic_cannal.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/parabolic_cannal.py	(revision 7576)
@@ -0,0 +1,167 @@
+import os
+from math import sqrt, pi, sin, cos
+from shallow_water_domain import *
+from Numeric import allclose, array, zeros, ones, Float, take, sqrt
+from config import g, epsilon
+"""
+def newLinePlot(title='Simple Plot'):
+    import Gnuplot
+    g = Gnuplot.Gnuplot(persist=0)
+    g.title(title)
+    g('set data style linespoints') 
+    g.xlabel('x')
+    g.ylabel('y')
+    return g
+
+def linePlot(g,x1,y1,x2,y2,x3,y3):
+    import Gnuplot
+    plot1 = Gnuplot.PlotItems.Data(x1.flat,y1.flat,with="lines 2")
+    plot2 = Gnuplot.PlotItems.Data(x2.flat,y2.flat,with="lines 3")
+    plot3 = Gnuplot.PlotItems.Data(x3.flat,y3.flat,with="linespoints 1")
+    g.plot(plot1,plot2,plot3)
+"""
+
+def analytic_cannal(C,t):
+    N = len(C)
+    u = zeros(N,Float)    ## water velocity
+    h = zeros(N,Float)    ## water depth
+    x = C
+    g = 9.81
+
+
+    ## Define Basin Bathymetry
+    z_b = zeros(N,Float) ## elevation of basin
+    z = zeros(N,Float)   ## elevation of water surface
+    z_infty = 10.0       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0         ## width of channel
+
+    A0 = 0.5*L_x                  ## determines amplitudes of oscillations
+    omega = sqrt(2*g*z_infty)/L_x ## angular frequency of osccilation
+
+    #x1 = A0*cos(omega*t)-L_x # left shoreline
+    #x2 = A0*cos(omega*t)+L_x # right shoreline
+    
+    for i in range(N):
+        z_b[i] = z_infty*(x[i]**2/L_x**2)
+        u[i] = -A0*omega*sin(omega*t)
+        z[i] = z_infty+2*A0*z_infty/L_x*cos(omega*t)*(x[i]/L_x-0.5*A0/(L_x)*cos(omega*t))
+
+    h = z-z_b
+    return u,h,z,z_b
+
+
+#plot2 = newLinePlot("Momentum")  
+
+L_x = 2500.0     # Length of channel (m)
+N = 100         # Number of compuational cells
+cell_len = 4*L_x/N   # Origin = 0.0
+
+points = zeros(N+1,Float)
+for i in range(N+1):
+        points[i] = -2*L_x +i*cell_len
+
+domain = Domain(points)
+
+domain.order = 2
+domain.set_timestepping_method('rk2')
+domain.cfl = 1.0
+domain.beta = 1.0
+#domain.limiter = "minmod_kurganov"
+#domain.limiter = "vanleer"
+#domain.limiter = "vanalbada"
+#domain.limiter = "superbee"
+#domain.limiter = "steve_minmod"
+domain.limiter = "pyvolution"
+
+def stage(x):
+
+    z_infty = 10.0       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0         ## width of channel
+    A0 = 0.5*L_x                  ## determines amplitudes of oscillations
+    omega = sqrt(2*g*z_infty)/L_x ## angular frequency of osccilation
+    t=0.0
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        #xy[i] = z_infty+2*A0*z_infty/L_x*cos(omega*t)*(x[i]/L_x-0.5*A0/(L_x)*cos(omega*t))
+        y[i] = 12.0
+    return y
+
+def elevation(x):
+    N = len(x)
+    z_infty = 10.0
+    z = zeros(N,Float)
+    L_x = 2500.0
+    A0 = 0.5*L_x
+    omega = sqrt(2*g*z_infty)/L_x
+    for i in range(N):
+        z[i] = z_infty*(x[i]**2/L_x**2)
+    return z
+
+def height(x):
+    z_infty = 10.0       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0         ## width of channel
+    A0 = 0.5*L_x                  ## determines amplitudes of oscillations
+    omega = sqrt(2*g*z_infty)/L_x ## angular frequency of osccilation
+    t=0.0
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        y[i] = max(z_infty+2*A0*z_infty/L_x*cos(omega*t)*(x[i]/L_x-0.5*A0/(L_x)*cos(omega*t))-z_infty*(x[i]**2/L_x**2),0.0)
+    return y
+
+    
+domain.set_quantity('stage', stage)
+domain.set_quantity('elevation',elevation)
+#domain.set_quantity('height',height)
+domain.set_boundary({'exterior': Reflective_boundary(domain)})
+ 
+import time
+t0 = time.time()
+#finaltime = 1122.0*0.75
+yieldstep = finaltime = 10.0
+#yieldstep = 10.0
+#plot1 = newLinePlot("Stage")
+#plot2 = newLinePlot("Xmomentum")
+C = domain.centroids
+X = domain.vertices
+StageQ = domain.quantities['stage'].vertex_values
+XmomQ = domain.quantities['xmomentum'].vertex_values
+#Bed = domain.quantities['elevation'].vertex_values
+import time
+t0 = time.time()
+for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime):
+    #pass
+    domain.write_time()
+    u,h,z,z_b = analytic_cannal(X.flat,t)
+    #linePlot(plot1,X,z,X,z_b,X,StageQ)
+    #linePlot(plot2,X,u*h,X,u*h,X,XmomQ)
+    HeightQ = domain.quantities['stage'].centroid_values-domain.quantities['elevation'].centroid_values
+    u,hc,z,z_b = analytic_cannal(C,t)
+    #for k in range(N):
+    #    if hc[k] < 0.0:
+    #        hc[k] = 0.0
+    error = 1.0/(N)*sum(abs(hc-HeightQ))
+    print 'Error measured at centroids', error
+    # #raw_input()         
+    # #from Gnuplot import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+    from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+    # #import Gnuplot  
+    X = domain.vertices
+    u,h,z,z_b = analytic_cannal(X.flat,domain.time)
+    StageQ = domain.quantities['stage'].vertex_values
+    XmomQ = domain.quantities['xmomentum'].vertex_values
+    hold(False)
+    plot1 = subplot(211)
+    plot(X,h,X,StageQ,X,z_b)
+    #plot1.set_ylim([4,11])
+    #title('?????????')
+    xlabel('Position')
+    ylabel('Stage')
+    legend(('Analytical Solution', 'Numerical Solution', 'Bed'),
+           'upper right', shadow=True)
+    plot2 = subplot(212)
+    plot(X,u*h,X,XmomQ)
+    #plot2.set_ylim([-1,25])
+    #title('?????????????????????????')
+    xlabel('Position')
+    ylabel('Xmomentum')
+    show()
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/parabolic_cannal_curved_surface.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/parabolic_cannal_curved_surface.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/parabolic_cannal_curved_surface.py	(revision 7576)
@@ -0,0 +1,135 @@
+import os
+from math import sqrt, pi, sin, cos
+from shallow_water_domain_suggestion1 import *
+from Numeric import allclose, array, zeros, ones, Float, take, sqrt
+from config import g, epsilon
+
+def analytic_cannal(C,t):
+    N = len(C)
+    u = zeros(N,Float)    ## water velocity
+    h = zeros(N,Float)    ## water depth
+    x = C
+    g = 9.81
+    ## Define Basin Bathymetry
+    z_b = zeros(N,Float) ## elevation of basin
+    z = zeros(N,Float)   ## elevation of water surface
+    z_infty = 10.0       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0         ## width of channel
+    c = 1.0
+    A = ((z_infty+c)**2 -z_infty**2)/((z_infty+c)**2 + z_infty**2)                  ## determines amplitudes of oscillations
+    omega = sqrt(8.0*g*z_infty/L_x**2)## angular frequency of osccilation
+    aux1 = 1.0-A*cos(omega*t)
+    aux2 = 1-A*A
+    for i in range(N):
+        z_b[i] = z_infty*(x[i]**2/L_x**2)       
+        u[i] = (0.5*omega*t*A*sin(omega*t) - aux1) / aux1    
+        z[i] = z_infty + z_infty*(sqrt(aux2)/aux1 - 1.0 - x[i]**2/L_x**2 *(aux2/aux1**2 -1))
+    h = z-z_b
+    T = 2.0*pi/omega
+    return u,h,z,z_b,T
+
+
+L_x = 2500.0     # Length of channel (m)
+N = 400         # Number of compuational cells
+cell_len = 4*L_x/N   # Origin = 0.0 
+
+points = zeros(N+1,Float)
+for i in range(N+1):
+        points[i] = -2*L_x +i*cell_len
+
+domain = Domain(points)
+domain.order = 2
+domain.set_timestepping_method('rk2')
+domain.cfl = 1.0
+domain.beta = 1.0
+domain.limiter = "vanleer"
+
+def stage(x):
+    z_infty = 10.0       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0         ## width of channel
+    c = 1.0
+    A = ((z_infty+c)**2 -z_infty**2)/((z_infty+c)**2 + z_infty**2)                 ## determines amplitudes of oscillations
+    omega = sqrt(8.0*g*z_infty/L_x**2) ## angular frequency of osccilation
+    t= 0.0
+    y = zeros(len(x),Float)
+    aux1 = 1.0-A*cos(omega*t)
+    aux2 = 1.0-A**2
+    for i in range(len(x)):
+        y[i] =  z_infty + z_infty*(sqrt(aux2)/aux1 - 1.0 - x[i]**2/L_x**2 *(aux2/aux1**2 -1.0))
+    return y
+
+def elevation(x):
+    N = len(x)
+    z_infty = 10.0
+    z = zeros(N,Float)
+    L_x = 2500.0
+    #c = 1.0
+    #A = ((z_infty+c)**2 -z_infty**2)/((z_infty+c)**2 + z_infty**2) 
+    #omega = sqrt(8.0*g*z_infty/L_x**2)
+    for i in range(N):
+        z[i] = z_infty*(x[i]**2/L_x**2)
+    return z
+
+def height(x):
+    z_infty = 10.0       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0         ## width of channel
+    c = 1.0
+    A = ((z_infty+c)**2 -z_infty**2)/((z_infty+c)**2 + z_infty**2)                 ## determines amplitudes of oscillations
+    omega = sqrt(8.0*g*z_infty/L_x**2) ## angular frequency of osccilation
+    t= pi/(2.0*omega)
+    y = zeros(len(x),Float)
+    aux1 = 1.0-A*cos(omega*t)
+    aux2 = 1.0-A**2
+    for i in range(len(x)):
+        y[i] = max(z_infty + z_infty*(sqrt(aux2)/aux1 - 1.0 - x[i]**2/L**2 *(aux2/aux1**2 -1.0)), 0.0)
+    return y
+
+    
+domain.set_quantity('stage', stage)
+domain.set_quantity('elevation',elevation)
+domain.set_boundary({'exterior': Reflective_boundary(domain)})
+ 
+X = domain.vertices
+u,h,z,z_b,T = analytic_cannal(X.flat,domain.time)
+print 'T = ',T
+
+yieldstep = finaltime = T
+StageQ = domain.quantities['stage'].vertex_values
+XmomQ = domain.quantities['xmomentum'].vertex_values
+
+import time
+t0 = time.time()
+for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime):
+    domain.write_time()
+    print "integral", domain.quantities['stage'].get_integral()
+    if t>0.0:
+        
+        print 'X=',X
+        print 'domain.time=',domain.time
+        
+        StageQ = domain.quantities['stage'].vertex_values
+        XmomQ = domain.quantities['xmomentum'].vertex_values
+        
+        u,h,z,z_b,T = analytic_cannal(X.flat,domain.time)
+        w = z
+        for k in range(len(h)):
+            if h[k] < 0.0:
+                h[k] = 0.0
+                w[k] = z_b[k]
+        
+        from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+        hold(False)
+        plot1 = subplot(211)
+        plot(X,w,  X,StageQ,  X,z_b)
+        #plot1.set_ylim([4,11])
+        xlabel('Position')
+        ylabel('Stage')
+        legend(('Analytic Solution', 'Numerical Solution', 'Bed'),
+               'upper center', shadow=True)
+        plot2 = subplot(212)
+        plot(X,u*h,X,XmomQ)
+        #plot2.set_ylim([-1,25])
+        xlabel('Position')
+        ylabel('Xmomentum')
+        show()
+raw_input("Press the return key!")
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/parabolic_cannal_sudi.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/parabolic_cannal_sudi.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/parabolic_cannal_sudi.py	(revision 7576)
@@ -0,0 +1,292 @@
+import os
+from math import sqrt, pi, sin, cos
+from shallow_water_domain_suggestion3 import *
+from Numeric import allclose, array, zeros, ones, Float, take, sqrt
+from config import g, epsilon
+import time
+
+def analytic_cannal(C,t):
+    N = len(C)
+    u = zeros(N,Float)              ## water velocity
+    h = zeros(N,Float)              ## water depth
+    x = C
+    g = 9.81
+    ## Define Basin Bathymetry
+    z_b = zeros(N,Float)            ## elevation of basin
+    w = zeros(N,Float)              ## elevation of water surface
+    D0 = 10.0                       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0                    ## width of channel
+    A0 = 0.5*L_x                    ## determines amplitudes of oscillations
+    omega = sqrt(2*g*D0)/L_x        ## angular frequency of osccilation
+    for i in range(N):
+        z_b[i] = D0*(x[i]**2/L_x**2)
+        u[i] = -A0*omega*sin(omega*t)
+        w[i] = D0+2*A0*D0/L_x*cos(omega*t)*(x[i]/L_x-0.5*A0/(L_x)*cos(omega*t))
+        if w[i] <= z_b[i] :
+            u[i] = 0.0
+            w[i] = z_b[i]
+    h = w - z_b
+    T = 2.0*pi/omega
+    return u,h,w,z_b, T
+
+
+L_x = 2500.0                        # Length of channel (m)
+N = 400                               # Number of computational cells
+cell_len = 4*L_x/N                  # Origin = 0.0
+
+points = zeros(N+1,Float)
+for i in range(N+1):
+        points[i] = -2*L_x +i*cell_len
+
+domain = Domain(points)
+domain.order = 2
+domain.set_timestepping_method('rk2')
+domain.set_CFL(1.0)
+domain.beta = 1.0
+domain.set_limiter("minmod")
+
+def stage(x):
+    D0 = 10.0                       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0                    ## width of channel
+    A0 = 0.5*L_x                    ## determines amplitudes of oscillations
+    omega = sqrt(2*g*D0)/L_x        ## angular frequency of osccilation
+    t=0.0
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        y[i] = D0+2*A0*D0/L_x*cos(omega*t)*(x[i]/L_x-0.5*A0/(L_x)*cos(omega*t))
+        #y[i] = 12.0
+    return y
+
+def elevation(x):
+    N = len(x)
+    D0 = 10.0
+    z = zeros(N,Float)
+    L_x = 2500.0
+    A0 = 0.5*L_x
+    omega = sqrt(2*g*D0)/L_x
+    for i in range(N):
+        z[i] = D0*(x[i]**2/L_x**2)
+    return z
+
+def height(x):
+    D0 = 10.0                       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0                    ## width of channel
+    A0 = 0.5*L_x                    ## determines amplitudes of oscillations
+    omega = sqrt(2*g*D0)/L_x        ## angular frequency of osccilation
+    t=0.0
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        y[i] = max(D0+2*A0*D0/L_x*cos(omega*t)*(x[i]/L_x-0.5*A0/(L_x)*cos(omega*t)) - D0*(x[i]**2/L_x**2),  0.0)
+    return y
+
+
+domain.set_quantity('stage', stage)
+domain.set_quantity('elevation',elevation)
+#domain.set_quantity('height',height)
+domain.set_boundary({'exterior': Reflective_boundary(domain)})
+
+C = domain.centroids
+X = domain.vertices
+u,h,w,z_b,T = analytic_cannal(X.flat,domain.time)
+print 'T = ',T
+
+yieldstep = finaltime = T/16 #3.0*T/2.0
+StageQ = domain.quantities['stage'].vertex_values
+XmomQ = domain.quantities['xmomentum'].vertex_values
+
+import time
+while finaltime < T + 1.0:
+    yieldstep = finaltime
+    t0 = time.time()
+    for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime):
+        domain.write_time()
+        #print "integral", domain.quantities['stage'].get_integral()
+        if t>0.0:
+            print "t=",t
+            uC,hC,wC,z_bC,TC = analytic_cannal(C,t)
+            for k in range(len(hC)):
+                if hC[k] < 0.0:
+                    hC[k] = 0.0
+                    wC[k] = z_bC[k]
+                
+            VelC = domain.quantities['velocity'].centroid_values
+            StageC = domain.quantities['stage'].centroid_values
+            ElevC = domain.quantities['elevation'].centroid_values
+            HeightC = domain.quantities['height'].centroid_values
+            XmomC = domain.quantities['xmomentum'].centroid_values
+
+            
+            #for i in range(domain.number_of_elements):
+            #    if HeightC[i] < 0.0 :
+            #        VelC[i] = 0.0
+                
+            #HeightC = domain.quantities['height'].centroid_values
+            #print 'Difference=',HeightC-hC
+            #print 'Difference=',StageC-wC
+        
+
+            error_h = (1.0/N)*sum(abs(hC-HeightC))
+            error_uh = (1.0/N)*sum(abs(uC*hC - XmomC))
+            error_u = (1.0/N)*sum(abs(uC - VelC))
+            #print 'len(hC)=',len(hC)
+            #print 'N=',N
+            print 'Height error measured at centroids = ', error_h
+            print 'Momentum error measured at centroids = ', error_uh
+            print 'Velocity error measured at centroids = ', error_u
+        
+            StageV = domain.quantities['stage'].vertex_values
+            ElevV = domain.quantities['elevation'].vertex_values
+            HeightV = domain.quantities['height'].vertex_values
+            XmomV = domain.quantities['xmomentum'].vertex_values
+            VelV = domain.quantities['velocity'].vertex_values
+        
+            u,h,w,z_b,T = analytic_cannal(X.flat,t)
+            for k in range(len(h)):
+                if h[k] < 0.0:
+                    h[k] = 0.0
+                    w[k] = z_b[k]
+        
+            from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+            hold(False)
+        
+            plot1 = subplot(311)
+            plot(X,w,  X,StageV,  X,z_b)
+            #plot1.set_xlim([-6000,6000])
+            #xlabel('Position')
+            ylabel('Stage')
+            legend(('Analytical Solution', 'Numerical Solution', 'Canal Bed'),
+                   'upper center', shadow=False)
+        
+            plot2 = subplot(312)
+            plot(C,uC*hC, C,XmomC) #(X,u*h,X,XmomV)
+            #plot2.set_ylim([-1,25])
+            #xlabel('Position')
+            ylabel('Momentum')
+            legend(('Analytical Solution', 'Numerical Solution'),
+                   'upper left', shadow=False)
+
+        
+
+            #h_V = zeros(len(VelV),Float)
+            #print 'len(h_V)=',len(h_V)
+            #print 'len(VelV)=', len(VelV)
+            #print 'h_V=',h_V[:]
+            #h_V[:] = HeightV
+        
+            #for i in range(domain.number_of_elements):
+            #    for j in range(2):
+            #        if HeightV[i,j] <= 0.0:
+            #            VelV[i,j] = 0.0
+                    
+            #print 'len(h_V)=',len(h_V)
+            #print 'le(VelV)=', len(VelV)
+            #print 'h_V=',h_V[:]
+        
+            plot3 = subplot(313)
+            plot(C,uC, C,VelC) #(X,u, X,VelV)
+            xlabel('Position')
+            ylabel('Velocity')
+            legend(('Analytical Solution', 'Numerical Solution'),
+                   'upper right', shadow=False)
+            #print 'domain.order=',domain.order
+            #print 'domain.limiter=',domain.limiter
+            #print 'domain.time=',domain.time
+            #print 'domain.timestepping = ',domain.get_timestepping_method()
+
+            #file = "parabolic_new_"
+            #file += str(t)
+            #file += ".eps"
+            #savefig(file)
+            #show()
+    finaltime=finaltime + T/16#10.0 #T/20.0
+raw_input("Press the return key!")
+
+
+
+"""
+domain.set_quantity('stage', stage)
+domain.set_quantity('elevation',elevation)
+domain.set_boundary({'exterior': Reflective_boundary(domain)})
+
+C = domain.centroids
+X = domain.vertices
+u,h,w,z_b,T = analytic_cannal(X.flat,domain.time)
+print 'T = ',T
+
+StageQ = domain.quantities['stage'].vertex_values
+XmomQ = domain.quantities['xmomentum'].vertex_values
+
+print 'domain.order=',domain.order
+print 'domain.limiter=',domain.limiter
+print 'domain.time=',domain.time
+print 'domain.timestepping = ',domain.get_timestepping_method()
+
+yieldstep = finaltime = T
+t0 = time.time()
+while finaltime < T+1.0:
+    #yieldstep = finaltime
+    for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime):
+        domain.write_time()
+        print "integral", domain.quantities['stage'].get_integral()
+        if t>= 0.0:        
+            uC,hC,wC,z_bC,TC = analytic_cannal(C,t)
+                
+            VelC = domain.quantities['velocity'].centroid_values
+            StageC = domain.quantities['stage'].centroid_values
+            ElevC = domain.quantities['elevation'].centroid_values
+            HeightC = domain.quantities['height'].centroid_values
+            XmomC = domain.quantities['xmomentum'].centroid_values
+            
+
+            error_h = cell_len*sum(abs(hC-HeightC))
+            error_uh = cell_len*sum(abs(uC*hC - XmomC))
+            error_u = cell_len*sum(abs(uC - VelC))
+
+            print 'Height error measured at centroids = ', error_h
+            print 'Momentum error measured at centroids = ', error_uh
+            print 'Velocity error measured at centroids = ', error_u
+        
+            StageV = domain.quantities['stage'].vertex_values
+            ElevV = domain.quantities['elevation'].vertex_values
+            HeightV = domain.quantities['height'].vertex_values
+            XmomV = domain.quantities['xmomentum'].vertex_values
+            VelV = domain.quantities['velocity'].vertex_values
+        
+            u,h,w,z_b,T = analytic_cannal(X.flat,t)
+        
+            from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+            hold(False)
+        
+            plot1 = subplot(311)
+            plot(X,w, X,StageV,  X,ElevV)
+            #plot1.set_xlim([-6000,6000])
+            #xlabel('Position')
+            ylabel('Stage')
+            legend(('Analytical Solution', 'Numerical Solution', 'Canal Bed'),
+                   'upper center', shadow=False)
+        
+            plot2 = subplot(312)
+            plot(C,uC*hC, C,XmomC)
+            #plot2.set_ylim([-1,25])
+            #xlabel('Position')
+            ylabel('Momentum')
+            #legend(('Analytical Solution', 'Numerical Solution'),
+            #       'upper right', shadow=False)
+        
+            plot3 = subplot(313)
+            plot(C,uC, C,VelC)
+            #xlabel('Position')
+            ylabel('Velocity')
+
+            #plot4 = subplot(414)
+            #plot(X,h, X,HeightV)
+            #xlabel('Position')
+            #ylabel('Height')
+            #file = "parabolic_2nd_vanleer_"
+            #file += str(t)
+            #file += ".png"
+            #savefig(file)
+            #show()
+    finaltime=finaltime + T/16.0
+raw_input("Press the return key!")
+"""
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/parabolic_cannal_sudi.py.bak
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/parabolic_cannal_sudi.py.bak	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/parabolic_cannal_sudi.py.bak	(revision 7576)
@@ -0,0 +1,121 @@
+import os
+from math import sqrt, pi, sin, cos
+from shallow_water_domain_suggestion1 import *
+from Numeric import allclose, array, zeros, ones, Float, take, sqrt
+from config import g, epsilon
+
+def analytic_cannal(C,t):
+    N = len(C)
+    u = zeros(N,Float)    ## water velocity
+    h = zeros(N,Float)    ## water depth
+    x = C
+    g = 9.81
+    ## Define Basin Bathymetry
+    z_b = zeros(N,Float) ## elevation of basin
+    z = zeros(N,Float)   ## elevation of water surface
+    z_infty = 10.0       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0         ## width of channel
+    A0 = 0.5*L_x                  ## determines amplitudes of oscillations
+    omega = sqrt(2*g*z_infty)/L_x ## angular frequency of osccilation
+    for i in range(N):
+        z_b[i] = z_infty*(x[i]**2/L_x**2)
+        u[i] = -A0*omega*sin(omega*t)
+        z[i] = z_infty+2*A0*z_infty/L_x*cos(omega*t)*(x[i]/L_x-0.5*A0/(L_x)*cos(omega*t))
+    h = z-z_b
+    T = 2.0*pi/omega
+    return u,h,z,z_b, T
+
+
+L_x = 2500.0     # Length of channel (m)
+N = 400         # Number of compuational cells
+cell_len = 4*L_x/N   # Origin = 0.0
+
+points = zeros(N+1,Float)
+for i in range(N+1):
+        points[i] = -2*L_x +i*cell_len
+
+domain = Domain(points)
+domain.order = 2
+domain.set_timestepping_method('rk2')
+domain.cfl = 1.0
+domain.beta = 1.0
+domain.limiter = "vanleer"
+
+def stage(x):
+    z_infty = 10.0       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0         ## width of channel
+    A0 = 0.5*L_x                  ## determines amplitudes of oscillations
+    omega = sqrt(2*g*z_infty)/L_x ## angular frequency of osccilation
+    t=0.0
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        y[i] = z_infty+2*A0*z_infty/L_x*cos(omega*t)*(x[i]/L_x-0.5*A0/(L_x)*cos(omega*t))
+        #y[i] = 12.0
+    return y
+
+def elevation(x):
+    N = len(x)
+    z_infty = 10.0
+    z = zeros(N,Float)
+    L_x = 2500.0
+    A0 = 0.5*L_x
+    omega = sqrt(2*g*z_infty)/L_x
+    for i in range(N):
+        z[i] = z_infty*(x[i]**2/L_x**2)
+    return z
+
+def height(x):
+    z_infty = 10.0       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0         ## width of channel
+    A0 = 0.5*L_x                  ## determines amplitudes of oscillations
+    omega = sqrt(2*g*z_infty)/L_x ## angular frequency of osccilation
+    t=0.0
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        y[i] = max(z_infty+2*A0*z_infty/L_x*cos(omega*t)*(x[i]/L_x-0.5*A0/(L_x)*cos(omega*t))-z_infty*(x[i]**2/L_x**2),0.0)
+    return y
+
+    
+domain.set_quantity('stage', stage)
+domain.set_quantity('elevation',elevation)
+domain.set_boundary({'exterior': Reflective_boundary(domain)})
+ 
+X = domain.vertices
+u,h,z,z_b,T = analytic_cannal(X.flat,domain.time)
+print 'T = ',T
+
+yieldstep = finaltime = T/2.0
+StageQ = domain.quantities['stage'].vertex_values
+XmomQ = domain.quantities['xmomentum'].vertex_values
+
+import time
+t0 = time.time()
+for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime):
+    domain.write_time()
+    print "integral", domain.quantities['stage'].get_integral()
+    if t>0.0:
+        
+        print 'X=',X
+        print 'domain.time=',domain.time
+        
+        for k in range(len(h)):
+            if h[k] < 0.0:
+                h[k] = 0.0
+        StageQ = domain.quantities['stage'].vertex_values
+        XmomQ = domain.quantities['xmomentum'].vertex_values
+        from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+        hold(False)
+        plot1 = subplot(211)
+        plot(X,z,  X,StageQ,  X,z_b)
+        #plot1.set_ylim([4,11])
+        xlabel('Position')
+        ylabel('Stage')
+        legend(('Analytic Solution', 'Numerical Solution', 'Bed'),
+               'upper center', shadow=True)
+        plot2 = subplot(212)
+        plot(X,u*h,X,XmomQ)
+        #plot2.set_ylim([-1,25])
+        xlabel('Position')
+        ylabel('Xmomentum')
+        show()
+raw_input("Press the return key!")
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/parabolic_cannal_vel.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/parabolic_cannal_vel.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/parabolic_cannal_vel.py	(revision 7576)
@@ -0,0 +1,144 @@
+import os
+from math import sqrt, pi, sin, cos
+from shallow_water_vel_domain import *
+from Numeric import allclose, array, zeros, ones, Float, take, sqrt
+from config import g, epsilon
+
+def analytic_cannal(C,t):
+    N = len(C)
+    u = zeros(N,Float)    ## water velocity
+    h = zeros(N,Float)    ## water depth
+    x = C
+    g = 9.81
+    ## Define Basin Bathymetry
+    z_b = zeros(N,Float) ## elevation of basin
+    z = zeros(N,Float)   ## elevation of water surface
+    z_infty = 10.0       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0         ## width of channel
+    A0 = 0.5*L_x                  ## determines amplitudes of oscillations
+    omega = sqrt(2*g*z_infty)/L_x ## angular frequency of osccilation
+    for i in range(N):
+        z_b[i] = z_infty*(x[i]**2/L_x**2)
+        u[i] = -A0*omega*sin(omega*t)
+        z[i] = z_infty+2*A0*z_infty/L_x*cos(omega*t)*(x[i]/L_x-0.5*A0/(L_x)*cos(omega*t))
+    h = z-z_b
+    T = 2.0*pi/omega
+    return u,h,z,z_b, T
+
+
+L_x = 2500.0     # Length of channel (m)
+N = 400         # Number of compuational cells
+cell_len = 4*L_x/N   # Origin = 0.0
+
+points = zeros(N+1,Float)
+for i in range(N+1):
+        points[i] = -2*L_x +i*cell_len
+
+def stage(x):
+    z_infty = 10.0       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0         ## width of channel
+    A0 = 0.5*L_x                  ## determines amplitudes of oscillations
+    omega = sqrt(2*g*z_infty)/L_x ## angular frequency of osccilation
+    t=0.0
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        y[i] = z_infty+2*A0*z_infty/L_x*cos(omega*t)*(x[i]/L_x-0.5*A0/(L_x)*cos(omega*t))
+        #y[i] = 12.0
+    return y
+
+def elevation(x):
+    N = len(x)
+    z_infty = 10.0
+    z = zeros(N,Float)
+    L_x = 2500.0
+    A0 = 0.5*L_x
+    omega = sqrt(2*g*z_infty)/L_x
+    for i in range(N):
+        z[i] = z_infty*(x[i]**2/L_x**2)
+    return z
+
+def height(x):
+    z_infty = 10.0       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0         ## width of channel
+    A0 = 0.5*L_x                  ## determines amplitudes of oscillations
+    omega = sqrt(2*g*z_infty)/L_x ## angular frequency of osccilation
+    t=0.0
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        y[i] = max(z_infty+2*A0*z_infty/L_x*cos(omega*t)*(x[i]/L_x-0.5*A0/(L_x)*cos(omega*t))-z_infty*(x[i]**2/L_x**2),0.0)
+    return y
+
+domain = Domain(points)
+domain.order = 2
+domain.set_timestepping_method('euler')
+domain.set_CFL(1.0)
+domain.beta = 1.0
+domain.set_limiter("vanleer")
+
+    
+domain.set_quantity('stage', stage)
+domain.set_quantity('elevation',elevation)
+domain.set_boundary({'exterior': Reflective_boundary(domain)})
+ 
+X = domain.vertices
+u,h,z,z_b,T = analytic_cannal(X.flat,domain.time)
+print 'T = ',T
+
+yieldstep = finaltime = 10.0 #T/2.0
+StageQ = domain.quantities['stage'].vertex_values
+XmomQ = domain.quantities['xmomentum'].vertex_values
+
+import time
+t0 = time.time()
+for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime):
+    domain.write_time()
+    print "integral", domain.quantities['stage'].get_integral()
+    if t>0.0:
+        
+        x = X.flat
+        print 'domain.time=',domain.time
+        
+        w_V = domain.quantities['stage'].vertex_values.flat
+        uh_V = domain.quantities['xmomentum'].vertex_values.flat
+        u_V = domain.quantities['velocity'].vertex_values.flat
+        h_V = domain.quantities['height'].vertex_values.flat
+        
+        u,h,z,z_b,T = analytic_cannal(x,domain.time)
+        w = z
+        for k in range(len(h)):
+            if h[k] < 0.0:
+                h[k] = 0.0
+                w[k] = z_b[k]
+        
+        from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+        hold(False)
+
+        #print 'size X',X.shape
+        #print 'size w',w.shape
+        signh = (h_V>0)
+
+        plot1 = subplot(311)
+        #plot(x,w,  x,w_V,  x,z_b)
+        plot(x,signh)
+        plot1.set_xlim([-6000,6000])
+        xlabel('Position')
+        ylabel('Stage')
+        legend(('Analytic Solution', 'Numerical Solution', 'Bed'),
+               'upper center', shadow=True)
+
+        
+        plot2 = subplot(312)
+        plot(x,u*h,x,uh_V)
+        #plot2.set_ylim([-1,25])
+        xlabel('Position')
+        ylabel('Xmomentum')
+
+        print u_V
+        
+        plot3 = subplot(313)
+        plot(x,u, x,u_V)
+        #plot2.set_ylim([-1,25])
+        xlabel('Position')
+        ylabel('Velocity')
+        show()
+raw_input("Press the return key!")
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/perturbation.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/perturbation.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/perturbation.py	(revision 7576)
@@ -0,0 +1,169 @@
+import os
+from math import sqrt
+#from shallow_water_h import *
+from shallow_water_domain_suggestion1 import *
+from Numeric import zeros, Float
+from analytic_dam_sudi import AnalyticDam
+
+h0=5.0
+h1=10.0
+
+analytical_sol=AnalyticDam(h0,h1)
+
+"""
+def newLinePlot(title='Simple Plot'):
+    import Gnuplot
+    gg=Gnuplot.Gnuplot(persist=0)
+    gg.title(title)
+    gg('set data style linespoints')
+    gg.xlabel('x')
+    gg.ylabel('y')
+    return gg
+
+def linePlot(gg, x1, y1, x2, y2):
+    import Gnuplot
+    plot1=Gnuplot.PlotItems.Data(x1.flat, y1.flat, with="linespoints")
+    plot2=Gnuplot.PlotItems.Data(x2.flat, y2.flat, with="lines 3")
+    gg.plot(plot1, plot2)
+"""
+
+
+print "TEST 1D-SOLUTION I"
+
+L=2000.0
+N=400
+
+cell_len=L/N
+
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+
+domain.order = 1
+domain.set_timestepping_method('euler')
+domain.cfl = 1.0
+#domain.limiter = "vanalbada"
+
+
+
+def height(x):
+    y=zeros(len(x), Float)
+    for i in range (len(x)):
+        if x[i]<=L/4.0:
+            y[i]=0.0 #h0
+        elif x[i]<=3*L/4.0:
+            y[i]=h1
+        else:
+            y[i]=h0
+    return y
+
+domain.set_quantity('stage',height)
+print "domain order", domain.order
+
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+
+X=domain.vertices
+C=domain.centroids
+#plot1x=newLinePlot("Height")
+#plot2x=newLinePlot("Momentum")
+
+import time
+yieldstep=finaltime=0.5
+t0=time.time()
+
+"""
+for i in range(10):
+    L=2000.0
+    N=800
+    cell_len=L/N
+    points=zeros(N+1, Float)
+    for i in range(N+1):
+        points[i]=i*cell_len
+    domain=Domain(points)
+    domain.order = 2
+    domain.set_timestepping_method('rk2')
+    domain.cfl = 1.0
+    domain.limiter = "vanleer"
+    domain.set_quantity('stage',height)
+    domain.set_boundary({'exterior':Reflective_boundary(domain)})
+    #print "integral", domain.quantities['stage'].get_integral()
+    for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+        domain.write_time()
+    #print "integral", domain.quantities['stage'].get_integral()
+    #print '==================================================================='
+print 'The average time is %.2f seconds'%((time.time()-t0)/10.0)
+"""
+while finaltime < 20.1:
+    for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+        domain.write_time()
+    if t>0.0:
+        N = float(N)
+        StageC = domain.quantities['stage'].centroid_values
+        XmomC = domain.quantities['xmomentum'].centroid_values
+        VelC = domain.quantities['velocity'].centroid_values
+        C = domain.centroids
+        hC, uhC, uC = analytical_sol(C,domain.time)
+        h_error = cell_len*sum(abs(hC-StageC))
+        uh_error = cell_len*sum(abs(uhC-XmomC))
+        u_error = cell_len*sum(abs(uC-VelC))
+        print "h_error %.10f" %(h_error)
+        print "uh_error %.10f"%(uh_error)
+        print "u_error %.10f" %(u_error)
+        print 'That took %.2f seconds' %(time.time()-t0)
+        X = domain.vertices
+        StageQ = domain.quantities['stage'].vertex_values
+        XmomQ = domain.quantities['xmomentum'].vertex_values
+        VelQ = domain.quantities['velocity'].vertex_values
+
+        h, uh, u = analytical_sol(X.flat, domain.time)
+        #linePlot(plot1x, X, HeightQ, X, h)
+        #linePlot(plot2x, X, MomentumQ, X, uh)
+        #print "press return"
+        #pass
+   
+        from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+        hold(False)
+           
+        plot1 = subplot(311)
+        plot(X,h,X,StageQ)
+        plot1.set_ylim([-1,11])
+        plot1.set_xlim([-100.0,2000.0])
+        #xlabel('Position')
+        ylabel('Stage')
+        #legend(('Analytical Solution', 'Numerical Solution'),
+        #   'lower right', shadow=False)
+        
+        plot2 = subplot(312)
+        plot(X,uh,X,XmomQ)
+        #plot2.set_ylim([-5,35])
+        plot2.set_xlim([-100.0,2000.0])
+        #legend(('Analytical Solution', 'Numerical Solution'),
+        #        'lower right', shadow=False)
+        #xlabel('Position')
+        ylabel('Momentum')
+
+        plot3 = subplot(313)
+        plot(X,u,X,VelQ)
+        #plot2.set_ylim([-5,35])
+        plot3.set_xlim([-100.0,2000.0])
+        legend(('Analytical Solution', 'Numerical Solution'),
+            'lower right', shadow=False)
+        xlabel('Position')
+        ylabel('Velocity')
+    
+        #file = "dam_h_"
+        #file += str(number_of_cells[i])
+        #file += ".eps"
+        #savefig(file)
+        #show()
+        file = "dam"
+        file += str(finaltime)
+        file += ".png"
+        savefig(file)
+    finaltime = finaltime + 0.5
+    print "The domain.limiter is", domain.limiter
+    print 'That took %.2f seconds'%(time.time()-t0)
+    print '============================================================================='
+
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/perturbation1.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/perturbation1.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/perturbation1.py	(revision 7576)
@@ -0,0 +1,95 @@
+import os
+from math import sqrt, sin, cos, pi, exp
+from shallow_water_domain_suggestion3 import *
+from Numeric import zeros, Float
+
+print "TEST 1D-SOLUTION I"
+
+L=2.0
+N=200
+cell_len=L/N
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+domain.order = 2
+domain.set_timestepping_method('rk2')
+domain.cfl = 1.0
+domain.limiter = "minmod"
+
+def stage_perturb(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 1.1 <= x[i] <=1.2:
+            y[i]=1.001
+        else:
+            y[i]=1.0
+    return y
+
+def elevation_parabol(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 1.4 <= x[i] <= 1.6:
+            y[i] = 0.25*(1.0+cos(10*pi*(x[i]-0.5)))
+        else:
+            y[i] = 0.0
+    return y
+
+domain.set_quantity('stage',stage_perturb)
+domain.set_quantity('elevation', elevation_parabol)
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+#X=domain.vertices
+#C=domain.centroids
+
+import time
+yieldstep=finaltime=0.25/100
+t0=time.time()
+i=0
+print "integral", domain.quantities['stage'].get_integral()
+while finaltime < 0.25001/100:
+    for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+        domain.write_time() 
+        X = domain.vertices
+        StageQ = domain.quantities['stage'].vertex_values
+        XmomQ = domain.quantities['xmomentum'].vertex_values
+        VelQ = domain.quantities['velocity'].vertex_values
+        ElevQ = domain.quantities['elevation'].vertex_values
+
+        from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+        hold(False)
+            
+        plot1 = subplot(311)
+        plot(X,StageQ,X,ElevQ) #(X,ElevQ,X,StageQ)
+        plot1.set_ylim([-0.1,1.1])
+        #plot1.set_ylim([0.9999,1.001])
+        legend(('Stage','Bed Elevation'),'center left', shadow=False)
+        ylabel('Stage')
+            
+        plot2 = subplot(312)
+        plot(X,XmomQ)
+        ylabel('Momentum')
+    
+        plot3 = subplot(313)
+        plot(X,VelQ)
+        #legend(('Numerical Solution',' '),'lower right', shadow=False)
+        xlabel('Position')
+        ylabel('Velocity')
+    
+        #print "The domain.limiter is", domain.limiter
+        #print "domain order", domain.order
+        #print 'That took %.2f seconds' %(time.time()-t0)
+        #print '============================================================================='
+ 
+        #file = "perturb"
+        #file += str(finaltime)
+        #file += ".png"
+        #show()
+        #savefig(file)
+        
+        filename = "%s%04i%s" %("perturbation", i, ".eps")
+        savefig(filename)
+
+        finaltime = finaltime + 0.25/100
+        i=i+1
+
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/perturbation2.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/perturbation2.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/perturbation2.py	(revision 7576)
@@ -0,0 +1,212 @@
+import os
+from math import sqrt, sin, cos, pi, exp
+from shallow_water_domain_suggestion3 import *
+from Numeric import zeros, Float
+
+print "TEST 1"
+
+L=2.0
+N=200
+cell_len=L/N
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+domain.order = 1
+domain.set_timestepping_method('euler')
+domain.cfl = 1.0
+
+def stage_perturb(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 1.1 <= x[i] <=1.2:
+            y[i]=1.001
+        else:
+            y[i]=1.0
+    return y
+
+def elevation_parabol(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 1.4 <= x[i] <= 1.6:
+            y[i] = 0.25*(1.0+cos(10*pi*(x[i]-0.5)))
+        else:
+            y[i] = 0.0
+    return y
+
+domain.set_quantity('stage',stage_perturb)
+domain.set_quantity('elevation', elevation_parabol)
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+X=domain.vertices
+C=domain.centroids
+
+import time
+yieldstep=finaltime=0.2
+t0=time.time()
+print "integral", domain.quantities['stage'].get_integral()
+for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+    domain.write_time() 
+StageQ = domain.quantities['stage'].vertex_values
+XmomQ = domain.quantities['xmomentum'].vertex_values
+VelQ = domain.quantities['velocity'].vertex_values
+ElevQ = domain.quantities['elevation'].vertex_values
+
+StageC = domain.quantities['stage'].centroid_values
+XmomC = domain.quantities['xmomentum'].centroid_values
+VelC = domain.quantities['velocity'].centroid_values
+ElevC = domain.quantities['elevation'].centroid_values
+
+
+
+
+
+
+
+print "TEST 2"
+
+L=2.0
+N=200
+cell_len=L/N
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+domain.order = 2
+domain.set_timestepping_method('rk2')
+domain.cfl = 1.0
+domain.limiter = "minmod"
+
+def stage_perturb(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 1.1 <= x[i] <=1.2:
+            y[i]=1.001
+        else:
+            y[i]=1.0
+    return y
+
+def elevation_parabol(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 1.4 <= x[i] <= 1.6:
+            y[i] = 0.25*(1.0+cos(10*pi*(x[i]-0.5)))
+        else:
+            y[i] = 0.0
+    return y
+
+domain.set_quantity('stage',stage_perturb)
+domain.set_quantity('elevation', elevation_parabol)
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+XX=domain.vertices
+CC=domain.centroids
+
+import time
+yieldstep=finaltime=0.2
+t0=time.time()
+print "integral", domain.quantities['stage'].get_integral()
+for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+    domain.write_time() 
+StageQQ = domain.quantities['stage'].vertex_values
+XmomQQ = domain.quantities['xmomentum'].vertex_values
+VelQQ = domain.quantities['velocity'].vertex_values
+ElevQQ = domain.quantities['elevation'].vertex_values
+
+StageCC = domain.quantities['stage'].centroid_values
+XmomCC = domain.quantities['xmomentum'].centroid_values
+VelCC = domain.quantities['velocity'].centroid_values
+ElevCC = domain.quantities['elevation'].centroid_values
+
+
+
+
+print "REFERENCE SOLUTION"
+
+L=2.0
+N=3200
+cell_len=L/N
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+domain.order = 2
+domain.set_timestepping_method('rk2')
+domain.cfl = 1.0
+domain.limiter = "minmod"
+
+def stage_perturb(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 1.1 <= x[i] <=1.2:
+            y[i]=1.001
+        else:
+            y[i]=1.0
+    return y
+
+def elevation_parabol(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 1.4 <= x[i] <= 1.6:
+            y[i] = 0.25*(1.0+cos(10*pi*(x[i]-0.5)))
+        else:
+            y[i] = 0.0
+    return y
+
+domain.set_quantity('stage',stage_perturb)
+domain.set_quantity('elevation', elevation_parabol)
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+#X=domain.vertices
+#C=domain.centroids
+
+import time
+yieldstep=finaltime=0.2
+t0=time.time()
+print "integral", domain.quantities['stage'].get_integral()
+for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+    domain.write_time() 
+XXX = domain.vertices
+StageQQQ = domain.quantities['stage'].vertex_values
+XmomQQQ = domain.quantities['xmomentum'].vertex_values
+VelQQQ = domain.quantities['velocity'].vertex_values
+ElevQQQ = domain.quantities['elevation'].vertex_values
+
+from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+hold(False)
+"""  
+plot1 = subplot(311)
+plot(X,StageQ,'k:', XX,StageQQ,'k,', XXX,StageQQQ,'k-')
+plot1.set_ylim([0.9999,1.0006])
+ylabel('Stage')
+"""
+
+"""
+plot1 = subplot(211)
+plot(C,XmomC,'k:', CC,XmomCC,'k,', XXX,XmomQQQ,'k-')
+ylabel('Momentum')
+
+plot2 = subplot(212)
+plot(C,VelC,'k:', CC,VelCC,'k,', XXX,VelQQQ,'k-')
+legend(('first order scheme','second order scheme','reference solution'),'lower right', shadow=False)
+xlabel('Position')
+ylabel('Velocity')
+   
+print "The domain.limiter is", domain.limiter
+print "domain order", domain.order
+print 'That took %.2f seconds' %(time.time()-t0)
+print '============================================================================='
+#file = "perturb"
+#file += str(finaltime)
+#file += ".png"
+#show()
+#savefig(file)
+"""
+
+
+plot(C,StageC,'k:', CC,StageCC,'k.', XXX,StageQQQ,'k-')
+xlabel('Position')
+ylabel('Stage')
+legend(('first order','second order','reference'),'upper center', shadow=False)
+
+
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/quantity.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/quantity.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/quantity.py	(revision 7576)
@@ -0,0 +1,1042 @@
+"""Class Quantity - Implements values at each 1d element
+
+To create:
+
+   Quantity(domain, vertex_values)
+
+   domain: Associated domain structure. Required.
+
+   vertex_values: N x 2 array of values at each vertex for each element.
+                  Default None
+
+   If vertex_values are None Create array of zeros compatible with domain.
+   Otherwise check that it is compatible with dimenions of domain.
+   Otherwise raise an exception
+"""
+
+
+
+class Quantity:
+
+    
+    def __init__(self, domain, vertex_values=None):
+        #Initialise Quantity using optional vertex values.
+        
+        from domain import Domain
+        from Numeric import array, zeros, Float
+
+        msg = 'First argument in Quantity.__init__ '
+        msg += 'must be of class Domain (or a subclass thereof)'
+        assert isinstance(domain, Domain), msg
+
+        if vertex_values is None:
+            N = domain.number_of_elements
+            self.vertex_values = zeros((N, 2), Float)
+        else:
+            self.vertex_values = array(vertex_values, Float)
+
+            N, V = self.vertex_values.shape
+            assert V == 2,\
+                   'Two vertex values per element must be specified'
+
+
+            msg = 'Number of vertex values (%d) must be consistent with'\
+                  %N
+            msg += 'number of elements in specified domain (%d).'\
+                   %domain.number_of_elements
+
+            assert N == domain.number_of_elements, msg
+
+        self.domain = domain
+
+        #Allocate space for other quantities
+        self.centroid_values = zeros(N, Float)
+        self.centroid_backup_values = zeros(N, Float)
+        #self.edge_values = zeros((N, 2), Float)
+        #edge values are values of the ends of each interval
+      
+        #Intialise centroid values
+        self.interpolate()
+
+
+        from Numeric import zeros, Float
+        
+        #Allocate space for boundary values
+        #L = len(domain.boundary)
+        self.boundary_values = zeros(2, Float) #assumes no parrellism
+
+        #Allocate space for updates of conserved quantities by
+        #flux calculations and forcing functions
+        
+        N = domain.number_of_elements
+        self.explicit_update = zeros(N, Float )
+        self.semi_implicit_update = zeros(N, Float )
+
+        self.gradients = zeros(N, Float)
+        self.qmax = zeros(self.centroid_values.shape, Float)
+        self.qmin = zeros(self.centroid_values.shape, Float)
+
+        self.beta = domain.beta        
+
+
+    def __len__(self):
+        """
+        Returns number of intervals.
+        """
+        return self.centroid_values.shape[0]
+    
+    def interpolate(self):
+        """
+        Compute interpolated values at centroid
+        Pre-condition: vertex_values have been set
+        """
+
+        N = self.vertex_values.shape[0]
+        for i in range(N):
+            v0 = self.vertex_values[i, 0]
+            v1 = self.vertex_values[i, 1]
+
+            self.centroid_values[i] = (v0 + v1)/2.0
+
+    def set_values(self, X, location='vertices'):
+        """Set values for quantity
+
+        X: Compatible list, Numeric array (see below), constant or function
+        location: Where values are to be stored.
+                  Permissible options are: vertices, centroid
+                  Default is "vertices"
+
+        In case of location == 'centroid' the dimension values must
+        be a list of a Numerical array of length N, N being the number
+        of elements in the mesh. Otherwise it must be of dimension Nx2
+
+        The values will be stored in elements following their
+        internal ordering.
+
+        If values are described a function, it will be evaluated at specified points
+
+        If selected location is vertices, values for centroid and edges
+        will be assigned interpolated values.
+        In any other case, only values for the specified locations
+        will be assigned and the others will be left undefined.
+        """
+
+        if location not in ['vertices', 'centroids']:
+            msg = 'Invalid location: %s, (possible choices vertices, centroids)' %location
+            raise msg
+
+        if X is None:
+            msg = 'Given values are None'
+            raise msg
+
+        import types
+
+        if callable(X):
+            #Use function specific method
+            self.set_function_values(X, location)
+        elif type(X) in [types.FloatType, types.IntType, types.LongType]:
+            if location == 'centroids':
+                self.centroid_values[:] = X
+            else:
+                self.vertex_values[:] = X
+
+        else:
+            #Use array specific method
+            self.set_array_values(X, location)
+
+        if location == 'vertices':
+            #Intialise centroid and edge values
+            self.interpolate()
+
+
+
+
+
+    def set_function_values(self, f, location='vertices'):
+        """Set values for quantity using specified function
+
+        f: x -> z Function where x and z are arrays
+        location: Where values are to be stored.
+                  Permissible options are: vertices, centroid
+                  Default is "vertices"
+        """
+        
+        if location == 'centroids':
+            
+            P = self.domain.centroids
+            self.set_values(f(P), location)
+        else:
+            #Vertices
+            P = self.domain.get_vertices()
+            
+            for i in range(2):
+                self.vertex_values[:,i] = f(P[:,i])        
+
+    def set_array_values(self, values, location='vertices'):
+        """Set values for quantity
+
+        values: Numeric array
+        location: Where values are to be stored.
+                  Permissible options are: vertices, centroid, edges
+                  Default is "vertices"
+
+        In case of location == 'centroid' the dimension values must
+        be a list of a Numerical array of length N, N being the number
+        of elements in the mesh. Otherwise it must be of dimension Nx2
+
+        The values will be stored in elements following their
+        internal ordering.
+
+        If selected location is vertices, values for centroid
+        will be assigned interpolated values.
+        In any other case, only values for the specified locations
+        will be assigned and the others will be left undefined.
+        """
+
+        from Numeric import array, Float
+
+        values = array(values).astype(Float)
+
+        N = self.centroid_values.shape[0]
+
+        msg = 'Number of values must match number of elements'
+        assert values.shape[0] == N, msg
+
+        if location == 'centroids':
+            assert len(values.shape) == 1, 'Values array must be 1d'
+            self.centroid_values = values
+        #elif location == 'edges':
+        #    assert len(values.shape) == 2, 'Values array must be 2d'
+        #    msg = 'Array must be N x 2'
+        #    self.edge_values = values
+        else:
+            assert len(values.shape) == 2, 'Values array must be 2d'
+            msg = 'Array must be N x 2'
+            assert values.shape[1] == 2, msg
+
+            self.vertex_values = values
+
+
+    def get_values(self, location='vertices', indices = None):
+        """get values for quantity
+
+        return X, Compatible list, Numeric array (see below)
+        location: Where values are to be stored.
+                  Permissible options are: vertices, centroid
+                  and unique vertices. Default is 'vertices'
+
+        In case of location == 'centroids' the dimension values must
+        be a list of a Numerical array of length N, N being the number
+        of elements. Otherwise it must be of dimension Nx3
+
+        The returned values with be a list the length of indices
+        (N if indices = None).  Each value will be a list of the three
+        vertex values for this quantity.
+
+        Indices is the set of element ids that the operation applies to.
+
+        """
+        from Numeric import take
+
+        if location not in ['vertices', 'centroids', 'unique vertices']:
+            msg = 'Invalid location: %s' %location
+            raise msg
+
+        import types, Numeric
+        assert type(indices) in [types.ListType, types.NoneType,
+                                 Numeric.ArrayType],\
+                                 'Indices must be a list or None'
+
+        if location == 'centroids':
+            if (indices ==  None):
+                indices = range(len(self))
+            return take(self.centroid_values,indices)
+        elif location == 'unique vertices':
+            if (indices ==  None):
+                indices=range(self.domain.coordinates.shape[0])
+            vert_values = []
+            #Go through list of unique vertices
+            for unique_vert_id in indices:
+                cells = self.domain.vertexlist[unique_vert_id]
+
+                #In case there are unused points
+                if cells is None:
+                    msg = 'Unique vertex not associated with cells'
+                    raise msg
+
+                # Go through all cells, vertex pairs
+                # Average the values
+                sum = 0
+                for cell_id, vertex_id in cells:
+                    sum += self.vertex_values[cell_id, vertex_id]
+                vert_values.append(sum/len(cells))
+            return Numeric.array(vert_values)
+        else:
+            if (indices ==  None):
+                indices = range(len(self))
+            return take(self.vertex_values,indices)
+
+
+    def get_vertex_values(self,
+                          x=True,
+                          smooth = None,
+                          precision = None,
+                          reduction = None):
+        """Return vertex values like an OBJ format
+
+        The vertex values are returned as one sequence in the 1D float array A.
+        If requested the coordinates will be returned in 1D arrays X.
+
+        The connectivity is represented as an integer array, V, of dimension
+        M x 2, where M is the number of volumes. Each row has two indices
+        into the X, A arrays defining the element.
+
+        if smooth is True, vertex values corresponding to one common
+        coordinate set will be smoothed according to the given
+        reduction operator. In this case vertex coordinates will be
+        de-duplicated.
+
+        If no smoothings is required, vertex coordinates and values will
+        be aggregated as a concatenation of values at
+        vertices 0, vertices 1
+
+
+        Calling convention
+        if x is True:
+           X,A,V = get_vertex_values
+        else:
+           A,V = get_vertex_values
+
+        """
+
+        from Numeric import concatenate, zeros, Float, Int, array, reshape
+
+
+        if smooth is None:
+            smooth = self.domain.smooth
+
+        if precision is None:
+            precision = Float
+
+        if reduction is None:
+            reduction = self.domain.reduction
+
+        #Create connectivity
+
+        if smooth == True:
+
+            V = self.domain.get_vertices()
+            N = len(self.domain.vertexlist)
+            #N = len(self.domain.vertices)
+            A = zeros(N, precision)
+
+            #Smoothing loop
+            for k in range(N):
+                L = self.domain.vertexlist[k]
+                #L = self.domain.vertices[k]
+
+                #Go through all triangle, vertex pairs
+                #contributing to vertex k and register vertex value
+
+                if L is None: continue #In case there are unused points
+
+                contributions = []
+                for volume_id, vertex_id in L:
+                    v = self.vertex_values[volume_id, vertex_id]
+                    contributions.append(v)
+
+                A[k] = reduction(contributions)
+
+            if x is True:
+                 #X = self.domain.coordinates[:,0].astype(precision)
+                 X = self.domain.coordinates[:].astype(precision)
+                 #Y = self.domain.coordinates[:,1].astype(precision)
+
+                 #return X, Y, A, V
+                 return X, A, V
+            
+            #else:
+            return A, V
+        else:
+            #Don't smooth
+            #obj machinery moved to general_mesh
+
+            # Create a V like [[0 1 2], [3 4 5]....[3*m-2 3*m-1 3*m]]
+            # These vert_id's will relate to the verts created below
+            #m = len(self.domain)  #Number of volumes
+            #M = 3*m        #Total number of unique vertices
+            #V = reshape(array(range(M)).astype(Int), (m,3))
+
+            #V = self.domain.get_triangles(obj=True)
+            V = self.domain.get_vertices
+            #FIXME use get_vertices, when ready
+
+            A = self.vertex_values.flat
+
+            #Do vertex coordinates
+            if x is True:
+                X = self.domain.get_vertex_coordinates()
+
+                #X = C[:,0:6:2].copy()
+                #Y = C[:,1:6:2].copy()
+
+                return X.flat, A, V
+            else:
+                return A, V
+
+    def get_integral(self):
+        """Compute the integral of quantity across entire domain
+        """
+        integral = 0
+        for k in range(self.domain.number_of_elements):
+            area = self.domain.areas[k]
+            qc = self.centroid_values[k]
+            integral += qc*area
+
+        return integral
+
+
+    def update(self, timestep):
+        """Update centroid values based on values stored in
+        explicit_update and semi_implicit_update as well as given timestep
+        """
+
+        from Numeric import sum, equal, ones, Float
+
+        N = self.centroid_values.shape[0]
+
+        #Explicit updates
+        self.centroid_values += timestep*self.explicit_update
+        
+        #Semi implicit updates
+        denominator = ones(N, Float)-timestep*self.semi_implicit_update
+
+        if sum(equal(denominator, 0.0)) > 0.0:
+            msg = 'Zero division in semi implicit update. Call Stephen :-)'
+            raise msg
+        else:
+            #Update conserved_quantities from semi implicit updates
+            self.centroid_values /= denominator
+
+
+    def compute_gradients(self):
+        """Compute gradients of piecewise linear function defined by centroids of
+        neighbouring volumes.
+        """
+
+        #print 'compute_gradient'
+
+        from Numeric import array, zeros, Float
+
+        N = self.centroid_values.shape[0]
+
+
+        G = self.gradients
+        Q = self.centroid_values
+        X = self.domain.centroids
+
+        for k in range(N):
+
+    	    # first and last elements have boundaries
+
+            if k == 0:
+
+                #Get data
+                k0 = k
+                k1 = k+1
+                k2 = k+2
+
+                q0 = Q[k0]
+                q1 = Q[k1]
+                q2 = Q[k2]
+
+                x0 = X[k0] #V0 centroid
+                x1 = X[k1] #V1 centroid
+                x2 = X[k2]
+
+                #Gradient
+                #G[k] = (q1 - q0)/(x1 - x0)
+                
+                G[k] = (q1 - q0)*(x2 - x0)*(x2 - x0) - (q2 - q0)*(x1 - x0)*(x1 - x0)
+                G[k] /= (x1 - x0)*(x2 - x0)*(x2 - x1)
+
+            elif k == N-1:
+
+                #Get data
+                k0 = k
+                k1 = k-1
+                k2 = k-2
+
+                q0 = Q[k0]
+                q1 = Q[k1]
+                q2 = Q[k2]
+
+                x0 = X[k0] #V0 centroid
+                x1 = X[k1] #V1 centroid
+                x2 = X[k2]
+
+                #Gradient
+                #G[k] = (q1 - q0)/(x1 - x0)
+                
+                G[k] = (q1 - q0)*(x2 - x0)*(x2 - x0) - (q2 - q0)*(x1 - x0)*(x1 - x0)
+                G[k] /= (x1 - x0)*(x2 - x0)*(x2 - x1)
+
+##                q0 = Q[k0]
+##                q1 = Q[k1]
+##
+##                x0 = X[k0] #V0 centroid
+##                x1 = X[k1] #V1 centroid
+##
+##                #Gradient
+##                G[k] = (q1 - q0)/(x1 - x0)
+
+            else:
+                #Interior Volume (2 neighbours)
+
+                #Get data
+                k0 = k-1
+                k2 = k+1
+
+                q0 = Q[k0]
+                q1 = Q[k]
+                q2 = Q[k2]
+
+                x0 = X[k0] #V0 centroid
+                x1 = X[k]  #V1 centroid (Self)
+                x2 = X[k2] #V2 centroid
+
+                #Gradient
+                #G[k] = (q2-q0)/(x2-x0)
+                G[k] = ((q0-q1)/(x0-x1)*(x2-x1) - (q2-q1)/(x2-x1)*(x0-x1))/(x2-x0)
+
+
+    def compute_minmod_gradients(self):
+        """Compute gradients of piecewise linear function defined by centroids of
+        neighbouring volumes.
+        """
+
+        #print 'compute_minmod_gradients'
+        
+        from Numeric import array, zeros, Float,sign
+        
+        def xmin(a,b):
+            return 0.5*(sign(a)+sign(b))*min(abs(a),abs(b))
+
+        def xmic(t,a,b):
+            return xmin(t*xmin(a,b), 0.50*(a+b) )
+
+
+
+        N = self.centroid_values.shape[0]
+
+
+        G = self.gradients
+        Q = self.centroid_values
+        X = self.domain.centroids
+
+        for k in range(N):
+
+    	    # first and last elements have boundaries
+
+            if k == 0:
+
+                #Get data
+                k0 = k
+                k1 = k+1
+                k2 = k+2
+
+                q0 = Q[k0]
+                q1 = Q[k1]
+                q2 = Q[k2]
+
+                x0 = X[k0] #V0 centroid
+                x1 = X[k1] #V1 centroid
+                x2 = X[k2]
+
+                #Gradient
+                #G[k] = (q1 - q0)/(x1 - x0)
+                
+                G[k] = (q1 - q0)*(x2 - x0)*(x2 - x0) - (q2 - q0)*(x1 - x0)*(x1 - x0)
+                G[k] /= (x1 - x0)*(x2 - x0)*(x2 - x1)
+
+            elif k == N-1:
+
+                #Get data
+                k0 = k
+                k1 = k-1
+                k2 = k-2
+
+                q0 = Q[k0]
+                q1 = Q[k1]
+                q2 = Q[k2]
+
+                x0 = X[k0] #V0 centroid
+                x1 = X[k1] #V1 centroid
+                x2 = X[k2]
+
+                #Gradient
+                #G[k] = (q1 - q0)/(x1 - x0)
+                
+                G[k] = (q1 - q0)*(x2 - x0)*(x2 - x0) - (q2 - q0)*(x1 - x0)*(x1 - x0)
+                G[k] /= (x1 - x0)*(x2 - x0)*(x2 - x1)
+
+##                #Get data
+##                k0 = k
+##                k1 = k-1
+##
+##                q0 = Q[k0]
+##                q1 = Q[k1]
+##
+##                x0 = X[k0] #V0 centroid
+##                x1 = X[k1] #V1 centroid
+##
+##                #Gradient
+##                G[k] = (q1 - q0)/(x1 - x0)
+
+            elif (self.domain.wet_nodes[k,0] == 2) & (self.domain.wet_nodes[k,1] == 2):
+                G[k] = 0.0
+
+            else:
+                #Interior Volume (2 neighbours)
+
+                #Get data
+                k0 = k-1
+                k2 = k+1
+
+                q0 = Q[k0]
+                q1 = Q[k]
+                q2 = Q[k2]
+
+                x0 = X[k0] #V0 centroid
+                x1 = X[k]  #V1 centroid (Self)
+                x2 = X[k2] #V2 centroid
+
+                # assuming uniform grid
+                d1 = (q1 - q0)/(x1-x0)
+                d2 = (q2 - q1)/(x2-x1)
+
+                #Gradient
+                #G[k] = (d1+d2)*0.5
+                #G[k] = (d1*(x2-x1) - d2*(x0-x1))/(x2-x0)                
+                G[k] = xmic( self.domain.beta, d1, d2 )
+        
+
+    def extrapolate_first_order(self):
+        """Extrapolate conserved quantities from centroid to
+        vertices for each volume using
+        first order scheme.
+        """
+
+        qc = self.centroid_values
+        qv = self.vertex_values
+
+        for i in range(2):
+            qv[:,i] = qc
+
+
+    def extrapolate_second_order(self):
+        """Extrapolate conserved quantities from centroid to
+        vertices for each volume using
+        second order scheme.
+        """
+        if self.domain.limiter == "pyvolution":
+            #Z = self.gradients
+            #print "gradients 1",Z
+            self.compute_gradients()
+            #print "gradients 2",Z
+
+            #Z = self.gradients
+            #print "gradients 1",Z
+            #self.compute_minmod_gradients()
+            #print "gradients 2", Z
+
+            G = self.gradients
+            V = self.domain.vertices
+            qc = self.centroid_values
+            qv = self.vertex_values        
+
+            #Check each triangle
+            for k in range(self.domain.number_of_elements):
+                #Centroid coordinates
+                x = self.domain.centroids[k]
+
+                #vertex coordinates
+                x0, x1 = V[k,:]
+
+                #Extrapolate
+                qv[k,0] = qc[k] + G[k]*(x0-x)
+                qv[k,1] = qc[k] + G[k]*(x1-x)
+            self.limit_pyvolution()
+        elif self.domain.limiter == "minmod_steve":
+            self.limit_minmod()
+        else:
+            self.limit_range()
+        
+        
+
+    def limit_minmod(self):
+        #Z = self.gradients
+        #print "gradients 1",Z
+        self.compute_minmod_gradients()
+        #print "gradients 2", Z
+
+        G = self.gradients
+        V = self.domain.vertices
+        qc = self.centroid_values
+        qv = self.vertex_values        
+        
+        #Check each triangle
+        for k in range(self.domain.number_of_elements):
+            #Centroid coordinates
+            x = self.domain.centroids[k]
+
+            #vertex coordinates
+            x0, x1 = V[k,:]
+
+            #Extrapolate
+            qv[k,0] = qc[k] + G[k]*(x0-x)
+            qv[k,1] = qc[k] + G[k]*(x1-x)
+
+ 
+    def limit_pyvolution(self):
+        """
+        Limit slopes for each volume to eliminate artificial variance
+        introduced by e.g. second order extrapolator
+
+        This is an unsophisticated limiter as it does not take into
+        account dependencies among quantities.
+
+        precondition:
+        vertex values are estimated from gradient
+        postcondition:
+        vertex values are updated
+        """
+        from Numeric import zeros, Float
+
+        N = self.domain.number_of_elements
+        beta = self.domain.beta
+        #beta = 0.8
+
+        qc = self.centroid_values
+        qv = self.vertex_values
+
+        #Find min and max of this and neighbour's centroid values
+        qmax = self.qmax
+        qmin = self.qmin
+
+        for k in range(N):
+            qmax[k] = qmin[k] = qc[k]
+            for i in range(2):
+                n = self.domain.neighbours[k,i]
+                if n >= 0:
+                    qn = qc[n] #Neighbour's centroid value
+
+                    qmin[k] = min(qmin[k], qn)
+                    qmax[k] = max(qmax[k], qn)
+
+
+        #Diffences between centroids and maxima/minima
+        dqmax = qmax - qc
+        dqmin = qmin - qc
+
+        #Deltas between vertex and centroid values
+        dq = zeros(qv.shape, Float)
+        for i in range(2):
+            dq[:,i] = qv[:,i] - qc
+
+        #Phi limiter
+        for k in range(N):
+
+            #Find the gradient limiter (phi) across vertices
+            phi = 1.0
+            for i in range(2):
+                r = 1.0
+                if (dq[k,i] > 0): r = dqmax[k]/dq[k,i]
+                if (dq[k,i] < 0): r = dqmin[k]/dq[k,i]
+
+                phi = min( min(r*beta, 1), phi )
+
+            #Then update using phi limiter
+            for i in range(2):
+                qv[k,i] = qc[k] + phi*dq[k,i]
+
+    def limit_range(self):
+        import sys
+        from Numeric import zeros, Float
+        from util import minmod, minmod_kurganov, maxmod, vanleer, vanalbada
+        limiter = self.domain.limiter
+        #print limiter
+        
+        #print 'limit_range'
+        N = self.domain.number_of_elements
+        qc = self.centroid_values
+        qv = self.vertex_values
+        C = self.domain.centroids
+        X = self.domain.vertices
+        beta_p = zeros(N,Float)
+        beta_m = zeros(N,Float)
+        beta_x = zeros(N,Float)
+        
+        for k in range(N):
+        
+            n0 = self.domain.neighbours[k,0]
+            n1 = self.domain.neighbours[k,1]
+            
+            if ( n0 >= 0) & (n1 >= 0):
+                #SLOPE DERIVATIVE LIMIT
+                beta_p[k] = (qc[k]-qc[k-1])/(C[k]-C[k-1])
+                beta_m[k] = (qc[k+1]-qc[k])/(C[k+1]-C[k])
+                beta_x[k] = (qc[k+1]-qc[k-1])/(C[k+1]-C[k-1])
+                
+        dq = zeros(qv.shape, Float)
+        for i in range(2):
+            dq[:,i] =self.domain.vertices[:,i]-self.domain.centroids
+            
+        #Phi limiter
+        for k in range(N):
+            n0 = self.domain.neighbours[k,0]
+            n1 = self.domain.neighbours[k,1]
+            if n0 < 0:
+                phi = (qc[k+1] - qc[k])/(C[k+1] - C[k])
+            elif n1 < 0:
+                phi = (qc[k] - qc[k-1])/(C[k] - C[k-1])
+            #elif (self.domain.wet_nodes[k,0] == 2) & (self.domain.wet_nodes[k,1] == 2):
+            #    phi = 0.0
+            else:
+                if limiter == "minmod":
+                    phi = minmod(beta_p[k],beta_m[k])
+
+                elif limiter == "minmod_kurganov":#Change this
+                    # Also known as monotonized central difference limiter
+                    # if theta = 2.0
+                    theta = 2.0 
+                    phi = minmod_kurganov(theta*beta_p[k],theta*beta_m[k],beta_x[k])
+                elif limiter == "superbee":
+                    slope1 = minmod(beta_m[k],2.0*beta_p[k])
+                    slope2 = minmod(2.0*beta_m[k],beta_p[k])
+                    phi = maxmod(slope1,slope2)
+
+                elif limiter == "vanleer":
+                    phi = vanleer(beta_p[k],beta_m[k])
+
+                elif limiter == "vanalbada":
+                    phi = vanalbada(beta_m[k],beta_p[k])
+            
+            for i in range(2):
+                qv[k,i] = qc[k] + phi*dq[k,i]
+
+    def limit_steve_slope(self):    
+
+        import sys
+        from Numeric import zeros, Float
+        from util import minmod, minmod_kurganov, maxmod, vanleer
+
+        N = self.domain.number_of_elements
+        limiter = self.domain.limiter
+        limiter_type = self.domain.limiter_type
+            
+        qc = self.centroid_values
+        qv = self.vertex_values
+
+        #Find min and max of this and neighbour's centroid values
+        beta_p = zeros(N,Float)
+        beta_m = zeros(N,Float)
+        beta_x = zeros(N,Float)
+        C = self.domain.centroids
+        X = self.domain.vertices
+
+        for k in range(N):
+        
+            n0 = self.domain.neighbours[k,0]
+            n1 = self.domain.neighbours[k,1]
+            
+            if (n0 >= 0) & (n1 >= 0):
+                # Check denominator not zero
+                if (qc[k+1]-qc[k]) == 0.0:
+                    beta_p[k] = float(sys.maxint)
+                    beta_m[k] = float(sys.maxint)
+                else:
+                    #STEVE LIMIT
+                    beta_p[k] = (qc[k]-qc[k-1])/(qc[k+1]-qc[k])
+                    beta_m[k] = (qc[k+2]-qc[k+1])/(qc[k+1]-qc[k])
+
+        #Deltas between vertex and centroid values
+        dq = zeros(qv.shape, Float)
+        for i in range(2):
+            dq[:,i] =self.domain.vertices[:,i]-self.domain.centroids
+            
+        #Phi limiter
+        for k in range(N):
+                
+            phi = 0.0
+            if limiter == "flux_minmod":
+                #FLUX MINMOD
+                phi = minmod_kurganov(1.0,beta_m[k],beta_p[k])
+            elif limiter == "flux_superbee":
+                #FLUX SUPERBEE
+                phi = max(0.0,min(1.0,2.0*beta_m[k]),min(2.0,beta_m[k]))+max(0.0,min(1.0,2.0*beta_p[k]),min(2.0,beta_p[k]))-1.0
+            elif limiter == "flux_muscl":
+                #FLUX MUSCL
+                phi = max(0.0,min(2.0,2.0*beta_m[k],2.0*beta_p[k],0.5*(beta_m[k]+beta_p[k])))
+            elif limiter == "flux_vanleer":
+                #FLUX VAN LEER
+                phi = (beta_m[k]+abs(beta_m[k]))/(1.0+abs(beta_m[k]))+(beta_p[k]+abs(beta_p[k]))/(1.0+abs(beta_p[k]))-1.0
+                
+                #Then update using phi limiter
+                n = self.domain.neighbours[k,1]
+                if n>=0:
+                    #qv[k,0] = qc[k] - 0.5*phi*(qc[k+1]-qc[k])
+                    #qv[k,1] = qc[k] + 0.5*phi*(qc[k+1]-qc[k])
+                    qv[k,0] = qc[k] + 0.5*phi*(qv[k,0]-qc[k])
+                    qv[k,1] = qc[k] + 0.5*phi*(qv[k,1]-qc[k])
+                else:
+                    qv[k,i] = qc[k]
+
+    def backup_centroid_values(self):
+        # Call correct module function
+        # (either from this module or C-extension)
+        #backup_centroid_values(self)
+
+        self.centroid_backup_values[:] = (self.centroid_values).astype('f')
+
+    def saxpy_centroid_values(self,a,b):
+        # Call correct module function
+        # (either from this module or C-extension)
+        self.centroid_values[:] = (a*self.centroid_values + b*self.centroid_backup_values).astype('f')
+        
+class Conserved_quantity(Quantity):
+    """Class conserved quantity adds to Quantity:
+
+    storage and method for updating, and
+    methods for extrapolation from centropid to vertices inluding
+    gradients and limiters
+    """
+
+    def __init__(self, domain, vertex_values=None):
+        Quantity.__init__(self, domain, vertex_values)
+
+        print "Use Quantity instead of Conserved_quantity"
+
+
+##
+##def newLinePlot(title='Simple Plot'):
+##    import Gnuplot
+##    g = Gnuplot.Gnuplot()
+##    g.title(title)
+##    g('set data style linespoints') 
+##    g.xlabel('x')
+##    g.ylabel('y')
+##    return g
+##
+##def linePlot(g,x,y):
+##    import Gnuplot
+##    g.plot(Gnuplot.PlotItems.Data(x.flat,y.flat))
+
+def newLinePlot(title='Simple Plot'):
+    import pylab as g
+    g.ion()
+    g.hold(False)
+    g.title(title)
+    g.xlabel('x')
+    g.ylabel('y')
+    
+
+def linePlot(x,y):
+    import pylab as g
+    g.plot(x.flat,y.flat)
+
+
+def closePlots():
+    import pylab as g
+    g.close('all')
+    
+if __name__ == "__main__":
+    #from domain import Domain
+    from shallow_water_domain import Domain     
+    from Numeric import arange
+    
+    points1 = [0.0, 1.0, 2.0, 3.0]
+    vertex_values = [[1.0,2.0],[4.0,5.0],[-1.0,2.0]]
+
+    D1 = Domain(points1)
+
+    Q1 = Quantity(D1, vertex_values)
+
+    print Q1.vertex_values
+    print Q1.centroid_values
+
+    new_vertex_values = [[2.0,1.0],[3.0,4.0],[-2.0,4.0]]
+
+    Q1.set_values(new_vertex_values)
+
+    print Q1.vertex_values
+    print Q1.centroid_values
+
+    new_centroid_values = [20,30,40]
+    Q1.set_values(new_centroid_values,'centroids')
+
+    print Q1.vertex_values
+    print Q1.centroid_values
+
+    class FunClass:
+        def __init__(self,value):
+            self.value = value
+
+        def __call__(self,x):
+            return self.value*(x**2)
+
+
+    fun = FunClass(1.0)
+    Q1.set_values(fun,'vertices')
+
+    print Q1.vertex_values
+    print Q1.centroid_values
+
+    Xc = Q1.domain.vertices
+    Qc = Q1.vertex_values
+    print Xc
+    print Qc
+
+    Qc[1,0] = 3
+
+    Q1.extrapolate_second_order()
+    #Q1.limit_minmod()
+
+    newLinePlot('plots')
+    linePlot(Xc,Qc)
+    raw_input('press return')
+
+    points2 = arange(10)
+    D2 = Domain(points2)
+
+    Q2 = Quantity(D2)
+    Q2.set_values(fun,'vertices')
+    Xc = Q2.domain.vertices
+    Qc = Q2.vertex_values
+    linePlot(Xc,Qc)
+    raw_input('press return')
+
+    
+    Q2.extrapolate_second_order()
+    #Q2.limit_minmod()
+    Xc = Q2.domain.vertices
+    Qc = Q2.vertex_values
+    print Q2.centroid_values
+    print Qc
+    linePlot(Xc,Qc)
+    raw_input('press return')
+
+
+    for i in range(10):
+        import pylab as g
+        g.hold(True)
+        fun = FunClass(i/10.0)
+        Q2.set_values(fun,'centroids')
+        Q2.extrapolate_second_order()
+        #Q2.limit_minmod()
+        Qc = Q2.vertex_values
+        linePlot(Xc,Qc)
+        raw_input('press return')
+
+    raw_input('press return to quit')
+closePlots()
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/run_profile_dry.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/run_profile_dry.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/run_profile_dry.py	(revision 7576)
@@ -0,0 +1,131 @@
+import os
+from math import sqrt, pi
+from shallow_water_domain import *
+from Numeric import allclose, array, zeros, ones, Float, take, sqrt
+from config import g, epsilon
+
+def analytical_sol(C,t):
+    
+    #t  = 0.0     # time (s)
+    g  = 9.81    # gravity (m/s^2)
+    h1 = 10.0    # depth upstream (m)
+    h0 = 0.0     # depth downstream (m)
+    L = 2000.0   # length of stream/domain (m)
+    n = len(C)    # number of cells
+
+    u = zeros(n,Float)
+    h = zeros(n,Float)
+    x = C-3*L/4.0
+    
+
+    for i in range(n):
+        # Calculate Analytical Solution at time t > 0
+        u3 = 2.0/3.0*(sqrt(g*h1)+x[i]/t) 
+        h3 = 4.0/(9.0*g)*(sqrt(g*h1)-x[i]/(2.0*t))*(sqrt(g*h1)-x[i]/(2.0*t)) 
+
+        if ( x[i] <= -t*sqrt(g*h1) ):
+            u[i] = 0.0 
+            h[i] = h1 
+        elif ( x[i] <= 2.0*t*sqrt(g*h1) ):
+            u[i] = u3 
+            h[i] = h3 
+        else:
+            u[i] = 0.0 
+            h[i] = h0 
+
+    return h , u*h
+
+#def newLinePlot(title='Simple Plot'):
+#   import Gnuplot
+#    gg = Gnuplot.Gnuplot(persist=0)
+#    gg.terminal(postscript)
+#    gg.title(title)
+#    gg('set data style linespoints') 
+#    gg.xlabel('x')
+#    gg.ylabel('y')
+#    return gg
+
+#def linePlot(gg,x1,y1,x2,y2):
+#    import Gnuplot
+#    plot1 = Gnuplot.PlotItems.Data(x1.flat,y1.flat,with="linespoints")
+#    plot2 = Gnuplot.PlotItems.Data(x2.flat,y2.flat, with="lines 3")
+#    g.plot(plot1,plot2)
+
+
+
+print "TEST 1D-SOLUTION III -- DRY BED"
+
+L = 2000.0     # Length of channel (m)
+N = 800        # Number of compuational cells
+cell_len = L/N # Origin = 0.0
+
+points = zeros(N+1,Float)
+for i in range(N+1):
+    points[i] = i*cell_len
+
+domain = Domain(points)
+
+def stage(x):
+    h1 = 10.0
+    h0 = 0.0
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        if x[i]<=L/4.0:
+            y[i] = h0
+        elif x[i]<=3*L/4.0:
+            y[i] = h1
+        else:
+            y[i] = h0
+    return y
+
+
+import time
+
+finaltime = 20.0
+yieldstep = 1.0
+L = 2000.0     # Length of channel (m)
+k = 0
+
+print "Evaluating domain with %d cells" %N
+cell_len = L/N # Origin = 0.0
+points = zeros(N+1,Float)
+for j in range(N+1):
+    points[j] = j*cell_len
+        
+domain = Domain(points)
+    
+domain.set_quantity('stage', stage)
+domain.set_boundary({'exterior': Reflective_boundary(domain)})
+domain.default_order = 2
+domain.default_time_order = 1
+domain.cfl = 1.0
+domain.limiter = "vanleer"
+
+t0 = time.time()
+
+s = 'for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime): domain.write_time()'
+
+import profile, pstats
+FN = 'profile.dat'
+
+profile.run(s, FN)
+
+    #print 'That took %.2f seconds' %(time.time()-t0)
+
+S = pstats.Stats(FN)
+s = S.sort_stats('cumulative').print_stats(30)
+
+print s    
+        
+N = float(N)
+StageC = domain.quantities['stage'].centroid_values
+XmomC = domain.quantities['xmomentum'].centroid_values
+C = domain.centroids
+h, uh = analytical_sol(C,domain.time)
+h_error = 1.0/(N)*sum(abs(h-StageC))
+uh_error = 1.0/(N)*sum(abs(uh-XmomC))
+print "h_error %.10f" %(h_error)
+print "uh_error %.10f"% (uh_error)
+
+print 'That took %.2f seconds' %(time.time()-t0)
+
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_1d.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_1d.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_1d.py	(revision 7576)
@@ -0,0 +1,1322 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+#from domain import *
+#from domain_order2 import *
+from domain import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['stage', 'xmomentum']
+        other_quantities = ['elevation', 'friction']
+        Generic_Domain.__init__(self, coordinates, boundary,
+                                conserved_quantities, other_quantities,
+                                tagged_elements)
+        
+        from config import minimum_allowed_height, g
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+
+        #forcing terms not included in 1d domain ?WHy?
+        self.forcing_terms.append(gravity)
+        #self.forcing_terms.append(manning_friction)
+        #print "\nI have Removed forcing terms line 64 1dsw"
+
+        #Realtime visualisation
+        self.visualiser = None
+        self.visualise  = False
+        self.visualise_color_stage = False
+        self.visualise_stage_range = 1.0
+        self.visualise_timer = True
+        self.visualise_range_z = None
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        #Evolve parametrs
+        self.cfl = 1.0
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.quantities_to_be_stored = ['stage','xmomentum']
+
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from realtime_visualisation_new import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+            self.visualiser.setup['elevation']=True
+            self.visualiser.updating['stage']=True
+        self.visualise = True
+        if self.visualise_color_stage == True:
+            self.visualiser.coloring['stage'] = True
+            self.visualiser.qcolor['stage'] = (0.0, 0.0, 0.8)
+        print 'initialise visualiser'
+        print self.visualiser.setup
+        print self.visualiser.updating
+
+    def check_integrity(self):
+        Generic_Domain.check_integrity(self)
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes(self)
+
+    def compute_timestep(self):
+        #Call correct module function
+        compute_timestep(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+        
+    def evolve(self, yieldstep = None, finaltime = None,
+               skip_initial_step = False):
+        """Specialisation of basic evolve method from parent class
+        """
+
+        #Call check integrity here rather than from user scripts
+        #self.check_integrity()
+
+        #msg = 'Parameter beta_h must be in the interval [0, 1)'
+        #assert 0 <= self.beta_h < 1.0, msg
+        #msg = 'Parameter beta_w must be in the interval [0, 1)'
+        #assert 0 <= self.beta_w < 1.0, msg
+
+
+        #Initial update of vertex and edge values before any storage
+        #and or visualisation
+        
+        self.distribute_to_vertices_and_edges()
+        
+        #Initialise real time viz if requested
+        #if self.visualise is True and self.time == 0.0:
+        #    if self.visualiser is None:
+        #        self.initialise_visualiser()
+        #
+        #    self.visualiser.update_timer()
+        #    self.visualiser.setup_all()
+
+        #Store model data, e.g. for visualisation
+        #if self.store is True and self.time == 0.0:
+        #    self.initialise_storage()
+        #    #print 'Storing results in ' + self.writer.filename
+        #else:
+        #    pass
+        #    #print 'Results will not be stored.'
+        #    #print 'To store results set domain.store = True'
+        #    #FIXME: Diagnostic output should be controlled by
+        #    # a 'verbose' flag living in domain (or in a parent class)
+
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime):
+            #Real time viz
+        #    if self.visualise is True:
+        #        self.visualiser.update_all()
+        #        self.visualiser.update_timer()
+
+
+            #Store model data, e.g. for subsequent visualisation
+        #    if self.store is True:
+        #        self.store_timestep(self.quantities_to_be_stored)
+
+            #FIXME: Could maybe be taken from specified list
+            #of 'store every step' quantities
+
+            #Pass control on to outer loop for more specific actions
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x and bed elevation
+        """
+
+        import data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+
+#Rotation of momentum vector
+def rotate(q, normal, direction = 1):
+    """Rotate the momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector.
+
+    If direction is negative the rotation is inverted.
+
+    Input vector is preserved
+
+    This function is specific to the shallow water wave equation
+    """
+
+    from Numeric import zeros, Float
+
+    assert len(q) == 3,\
+           'Vector of conserved quantities must have length 3'\
+           'for 2D shallow water equation'
+
+    try:
+        l = len(normal)
+    except:
+        raise 'Normal vector must be an Numeric array'
+
+    assert l == 2, 'Normal vector must have 2 components'
+
+
+    n1 = normal[0]
+    n2 = normal[1]
+
+    r = zeros(len(q), Float) #Rotated quantities
+    r[0] = q[0]              #First quantity, height, is not rotated
+
+    if direction == -1:
+        n2 = -n2
+
+
+    r[1] =  n1*q[1] + n2*q[2]
+    r[2] = -n2*q[1] + n1*q[2]
+
+    return r
+
+
+def flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/h_right
+
+    #vh_left  = q_left[2]
+    #vh_right = q_right[2]
+
+    #print h_right
+    #print u_right
+    #print h_left
+    #print u_right
+
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+
+    #flux_left  = array([u_left*h_left,
+    #                    u_left*uh_left + 0.5*g*h_left**2])
+    #flux_right = array([u_right*h_right,
+    #                    u_right*uh_right + 0.5*g*h_right**2])
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+
+
+def flux_function_split(normal, ql, qr, zl, zr):
+    from config import g, epsilon
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/h_right
+
+    #vh_left  = q_left[2]
+    #vh_right = q_right[2]
+
+    #soundspeed_left  = sqrt(g*h_left)
+    #soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    #s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    s_max = max(u_left, u_right, 0)
+    
+    #Minimal wave speed
+    #s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    s_min = min(u_left, u_right, 0)
+    
+    #Flux computation
+
+    #flux_left  = array([u_left*h_left,
+    #                    u_left*uh_left + 0.5*g*h_left*h_left])
+    #flux_right = array([u_right*h_right,
+    #                    u_right*uh_right + 0.5*g*h_right*h_right])
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left])# + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right])# + 0.5*g*h_right*h_right])
+    
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed    
+
+def compute_timestep(domain):
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                qr[0] = stage[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+
+            if domain.split == False:
+                edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+            elif domain.split == True:
+                edgeflux, max_speed = flux_function_split(normal, ql, qr, zl, zr)
+            #Update optimal_timestep
+            try:
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+    domain.timestep = timestep
+
+def compute_fluxes(domain):
+    """Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+#    Ymom = domain.quantities['ymomentum']
+    Bed = domain.quantities['elevation']
+
+    #Arrays
+    #stage = Stage.edge_values
+    #xmom =  Xmom.edge_values
+ #   ymom =  Ymom.edge_values
+    #bed =   Bed.edge_values
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+    
+    #print 'stage edge values', stage
+    #print 'xmom edge values', xmom
+    #print 'bed values', bed
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    #print 'stage_bdry',stage_bdry
+    #print 'xmom_bdry', xmom_bdry
+#    ymom_bdry =  Ymom.boundary_values
+
+#    flux = zeros(3, Float) #Work array for summing up fluxes
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            #ql[0] = stage[k, i]
+            #ql[1] = xmom[k, i]
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            #Flux computation using provided function
+            #edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+            #print 'ql',ql
+            #print 'qr',qr
+            
+
+            #if domain.split == False:
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+            #elif domain.split == True:
+            #    edgeflux, max_speed = flux_function_split(normal, ql, qr, zl, zr)
+            #print 'edgeflux', edgeflux
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        Stage.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k] = flux[1]
+        #Ymom.explicit_update[k] = flux[2]
+        #print "flux cell",k,flux[0]
+
+    domain.timestep = timestep
+    #print domain.quantities['stage'].centroid_values
+
+####################################
+
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    protect_against_infinitesimal_and_negative_heights(domain)
+    
+
+    #Extrapolate all conserved quantities
+    #if optimised_gradient_limiter:
+    #    #MH090605 if second order,
+    #    #perform the extrapolation and limiting on
+    #    #all of the conserved quantities
+
+    #    if (domain.order == 1):
+    #        for name in domain.conserved_quantities:
+    #            Q = domain.quantities[name]
+    #            Q.extrapolate_first_order()
+    #    elif domain.order == 2:
+    #        domain.extrapolate_second_order_sw()
+    #    else:
+    #        raise 'Unknown order'
+    #else:
+        #old code:
+
+    for name in domain.conserved_quantities:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            #print "add extrapolate second order to shallow water"
+            #if name != 'height':
+            Q.extrapolate_second_order()
+            #Q.limit()
+        else:
+            raise 'Unknown order'
+
+    #Take bed elevation into account when water heights are small
+    #balance_deep_and_shallow(domain)
+    #protect_against_infinitesimal_and_negative_heights(domain)
+
+#Compute edge values by interpolation
+    #for name in domain.conserved_quantities:
+    #    Q = domain.quantities[name]
+    #    Q.interpolate_from_vertices_to_edges()    
+    
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+#    ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    zv = domain.quantities['elevation'].vertex_values
+    wv = domain.quantities['stage'].vertex_values
+    hv = wv-zv
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    #remove the above two lines and corresponding code below
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+                wv[k,0] = zv[k,0]
+                wv[k,1] = zv[k,1]
+                
+            xmomc[k] = 0.0
+            
+        #N = domain.number_of_elements
+        #if (k == 0) | (k==N-1):
+        #    wc[k] = zc[k] # Contain 'lost mass' error
+        #    wv[k,0] = zv[k,0]
+        #    wv[k,1] = zv[k,1]
+    
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        #for i in range(3):
+        for i in range(2):   
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    #for i in range(3):
+    for i in range(2):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        #for i in range(3):
+        for i in range(2):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        #for i in range(3):
+        for i in range(2):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]))#,
+#                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using the h-limited
+        #stage and alpha==1 means using the w-limited stage as
+        #computed by the gradient limiter (both 1st or 2nd order)
+
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        alpha  = 0.0
+	#Let
+	#
+	#  wvi be the w-limited stage (wvi = zvi + hvi)
+	#  wvi- be the h-limited state (wvi- = zvi + hvi-)
+	#
+	#
+	#where i=0,1,2 denotes the vertex ids
+	#
+        #Weighted balance between w-limited and h-limited stage is
+        #
+	#  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+	#
+        #It follows that the updated wvi is
+        #  wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+        #
+	# Momentum is balanced between constant and limited
+
+
+        #for i in range(3):
+        #    wv[k,i] = zv[k,i] + hvbar[k,i]
+
+	#return
+
+	if alpha < 1:
+
+            #for i in range(3):
+            for i in range(2):
+                wv[k,i] = zv[k,i] + (1.0-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+#            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+#           ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1.0-alpha)*xmomc[k] + alpha*xmomv[k,:]
+#            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+###############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        #self.stage   = domain.quantities['stage'].edge_values
+        #self.xmom    = domain.quantities['xmomentum'].edge_values
+        #self.ymom    = domain.quantities['ymomentum'].edge_values
+        self.normals = domain.normals
+        self.stage   = domain.quantities['stage'].vertex_values
+        self.xmom    = domain.quantities['xmomentum'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        self.conserved_quantities = zeros(2, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+
+        q = self.conserved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = self.xmom[vol_id, edge_id]
+        #q[2] = self.ymom[vol_id, edge_id]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+1]
+        normal = self.normals[vol_id,edge_id]
+
+        #r = rotate(q, normal, direction = 1)
+        #r[1] = -r[1]
+        #q = rotate(r, normal, direction = -1)
+        r = q
+        r[1] = normal*r[1]
+        r[1] = -r[1]
+        r[1] = normal*r[1]
+        q = r
+        #For start interval there is no outward momentum so do not need to
+        #reverse direction in this case
+
+        return q
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, conserved_quantities=None):
+        Boundary.__init__(self)
+
+        if conserved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.conserved_quantities=array(conserved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.conserved_quantities
+
+
+#########################
+#Standard forcing terms:
+#
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    stage = domain.quantities['stage'].explicit_update
+#    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    #h = Stage.edge_values - Elevation.edge_values
+    h = Stage.vertex_values - Elevation.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+#        avg_h = sum( h[k,:] )/3
+        avg_h = sum( h[k,:] )/2
+
+        #Compute bed slope
+        #x0, y0, x1, y1, x2, y2 = x[k,:]
+        x0, x1 = x[k,:]
+        #z0, z1, z2 = v[k,:]
+        b0, b1 = b[k,:]
+
+        w0, w1 = w[k,:]
+        wx = gradient(x0, x1, w0, w1)
+
+        #zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        if domain.split == False:
+            xmom[k] += -g*bx*avg_h
+            #xmom[k] = -g*bx*avg_h
+            #stage[k] = 0.0
+        elif domain.split == True:
+            xmom[k] += -g*wx*avg_h
+            #xmom[k] = -g*wx*avg_h
+        #ymom[k] += -g*zy*avg_h
+ 
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    #vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    #ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	#S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+                S = -g * eta[k]**2 * uh[k]
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	#ymom_update[k] += S*vh[k]
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+#    vh = domain.quantities['ymomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+#    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g #Not necessary? Why was this added?
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+ #           	ymom_update[k] += S*vh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
+class Wind_stress:
+    """Apply wind stress to water momentum in terms of
+    wind speed [m/s] and wind direction [degrees]
+    """
+
+    def __init__(self, *args, **kwargs):
+        """Initialise windfield from wind speed s [m/s]
+        and wind direction phi [degrees]
+
+        Inputs v and phi can be either scalars or Python functions, e.g.
+
+        W = Wind_stress(10, 178)
+
+        #FIXME - 'normal' degrees are assumed for now, i.e. the
+        vector (1,0) has zero degrees.
+        We may need to convert from 'compass' degrees later on and also
+        map from True north to grid north.
+
+        Arguments can also be Python functions of t,x,y as in
+
+        def speed(t,x,y):
+            ...
+            return s
+
+        def angle(t,x,y):
+            ...
+            return phi
+
+        where x and y are vectors.
+
+        and then pass the functions in
+
+        W = Wind_stress(speed, angle)
+
+        The instantiated object W can be appended to the list of
+        forcing_terms as in
+
+        Alternatively, one vector valued function for (speed, angle)
+        can be applied, providing both quantities simultaneously.
+        As in
+        W = Wind_stress(F), where returns (speed, angle) for each t.
+
+        domain.forcing_terms.append(W)
+        """
+
+        from config import rho_a, rho_w, eta_w
+        from Numeric import array, Float
+
+        if len(args) == 2:
+            s = args[0]
+            phi = args[1]
+        elif len(args) == 1:
+            #Assume vector function returning (s, phi)(t,x,y)
+            vector_function = args[0]
+            #s = lambda t,x,y: vector_function(t,x=x,y=y)[0]
+            #phi = lambda t,x,y: vector_function(t,x=x,y=y)[1]
+            s = lambda t,x: vector_function(t,x=x)[0]
+            phi = lambda t,x: vector_function(t,x=x)[1]
+        else:
+           #Assume info is in 2 keyword arguments
+
+           if len(kwargs) == 2:
+               s = kwargs['s']
+               phi = kwargs['phi']
+           else:
+               raise 'Assumes two keyword arguments: s=..., phi=....'
+
+        print 'phi', phi
+        self.speed = check_forcefield(s)
+        self.phi = check_forcefield(phi)
+
+        self.const = eta_w*rho_a/rho_w
+
+
+    def __call__(self, domain):
+        """Evaluate windfield based on values found in domain
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import Float, ones, ArrayType
+
+        xmom_update = domain.quantities['xmomentum'].explicit_update
+        #ymom_update = domain.quantities['ymomentum'].explicit_update
+
+        N = domain.number_of_elements
+        t = domain.time
+
+        if callable(self.speed):
+            xc = domain.get_centroid_coordinates()
+            #s_vec = self.speed(t, xc[:,0], xc[:,1])
+            s_vec = self.speed(t, xc)
+        else:
+            #Assume s is a scalar
+
+            try:
+                s_vec = self.speed * ones(N, Float)
+            except:
+                msg = 'Speed must be either callable or a scalar: %s' %self.s
+                raise msg
+
+
+        if callable(self.phi):
+            xc = domain.get_centroid_coordinates()
+            #phi_vec = self.phi(t, xc[:,0], xc[:,1])
+            phi_vec = self.phi(t, xc)
+        else:
+            #Assume phi is a scalar
+
+            try:
+                phi_vec = self.phi * ones(N, Float)
+            except:
+                msg = 'Angle must be either callable or a scalar: %s' %self.phi
+                raise msg
+
+        #assign_windfield_values(xmom_update, ymom_update,
+        #                        s_vec, phi_vec, self.const)
+        assign_windfield_values(xmom_update, s_vec, phi_vec, self.const)
+
+
+#def assign_windfield_values(xmom_update, ymom_update,
+#                            s_vec, phi_vec, const):
+def assign_windfield_values(xmom_update, s_vec, phi_vec, const):
+    """Python version of assigning wind field to update vectors.
+    A c version also exists (for speed)
+    """
+    from math import pi, cos, sin, sqrt
+
+    N = len(s_vec)
+    for k in range(N):
+        s = s_vec[k]
+        phi = phi_vec[k]
+
+        #Convert to radians
+        phi = phi*pi/180
+
+        #Compute velocity vector (u, v)
+        u = s*cos(phi)
+        v = s*sin(phi)
+
+        #Compute wind stress
+        #S = const * sqrt(u**2 + v**2)
+        S = const * u
+        xmom_update[k] += S*u
+        #ymom_update[k] += S*v
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain.py	(revision 7576)
@@ -0,0 +1,1354 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+
+from domain import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['stage', 'xmomentum']
+        other_quantities = ['elevation', 'friction']
+        Generic_Domain.__init__(self,
+                                coordinates = coordinates,
+                                boundary = boundary,
+                                conserved_quantities = conserved_quantities,
+                                other_quantities = other_quantities,
+                                tagged_elements = tagged_elements)
+        
+        from config import minimum_allowed_height, g, h0
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+        self.h0 = h0
+
+        #forcing terms not included in 1d domain ?WHy?
+        self.forcing_terms.append(gravity)
+        #self.forcing_terms.append(manning_friction)
+        #print "\nI have Removed forcing terms line 64 1dsw"
+
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        #Evolve parametrs
+        self.set_CFL(1.0)
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.set_quantities_to_be_stored(['stage','xmomentum'])
+
+	self.__doc__ = 'shallow_water_domain'
+
+        self.check_integrity()
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+    def check_integrity(self):
+
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+
+        msg = 'First evolved quantity must be "stage"'
+        assert self.evolved_quantities[0] == 'stage', msg
+        msg = 'Second evolved quantity must be "xmomentum"'
+        assert self.evolved_quantities[1] == 'xmomentum', msg        
+
+        Generic_Domain.check_integrity(self)
+        
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes_C_short(self)
+
+    def compute_timestep(self):
+        #Call correct module function
+        compute_timestep(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+        
+    def evolve(self, yieldstep = None, finaltime = None, duration = None,
+               skip_initial_step = False):
+        """Specialisation of basic evolve method from parent class
+        """
+
+        #Call check integrity here rather than from user scripts
+        #self.check_integrity()
+
+        #msg = 'Parameter beta_h must be in the interval [0, 1)'
+        #assert 0 <= self.beta_h < 1.0, msg
+        #msg = 'Parameter beta_w must be in the interval [0, 1)'
+        #assert 0 <= self.beta_w < 1.0, msg
+
+
+        #Initial update of vertex and edge values before any storage
+        #and or visualisation
+        
+        self.distribute_to_vertices_and_edges()
+        
+        #Initialise real time viz if requested
+        #if self.visualise is True and self.time == 0.0:
+        #    if self.visualiser is None:
+        #        self.initialise_visualiser()
+        #
+        #    self.visualiser.update_timer()
+        #    self.visualiser.setup_all()
+
+        #Store model data, e.g. for visualisation
+        #if self.store is True and self.time == 0.0:
+        #    self.initialise_storage()
+        #    #print 'Storing results in ' + self.writer.filename
+        #else:
+        #    pass
+        #    #print 'Results will not be stored.'
+        #    #print 'To store results set domain.store = True'
+        #    #FIXME: Diagnostic output should be controlled by
+        #    # a 'verbose' flag living in domain (or in a parent class)
+
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime,duration,
+                                       skip_initial_step):
+            #Real time viz
+        #    if self.visualise is True:
+        #        self.visualiser.update_all()
+        #        self.visualiser.update_timer()
+
+
+            #Store model data, e.g. for subsequent visualisation
+        #    if self.store is True:
+        #        self.store_timestep(self.quantities_to_be_stored)
+
+            #FIXME: Could maybe be taken from specified list
+            #of 'store every step' quantities
+
+            #Pass control on to outer loop for more specific actions
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x and bed elevation
+        """
+
+        import data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+
+#Rotation of momentum vector
+def rotate(q, normal, direction = 1):
+    """Rotate the momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector.
+
+    If direction is negative the rotation is inverted.
+
+    Input vector is preserved
+
+    This function is specific to the shallow water wave equation
+    """
+
+    from Numeric import zeros, Float
+
+    assert len(q) == 3,\
+           'Vector of conserved quantities must have length 3'\
+           'for 2D shallow water equation'
+
+    try:
+        l = len(normal)
+    except:
+        raise 'Normal vector must be an Numeric array'
+
+    assert l == 2, 'Normal vector must have 2 components'
+
+
+    n1 = normal[0]
+    n2 = normal[1]
+
+    r = zeros(len(q), Float) #Rotated quantities
+    r[0] = q[0]              #First quantity, height, is not rotated
+
+    if direction == -1:
+        n2 = -n2
+
+
+    r[1] =  n1*q[1] + n2*q[2]
+    r[2] = -n2*q[1] + n1*q[2]
+
+    return r
+
+
+def flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon, h0
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/(h_left +  h0/h_left)
+
+
+    uh_left = u_left*h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/(h_right + h0/h_right)
+
+    uh_right = u_right*h_right
+
+    #vh_left  = q_left[2]
+    #vh_right = q_right[2]
+
+    #print h_right
+    #print u_right
+    #print h_left
+    #print u_right
+
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+
+    #flux_left  = array([u_left*h_left,
+    #                    u_left*uh_left + 0.5*g*h_left**2])
+    #flux_right = array([u_right*h_right,
+    #                    u_right*uh_right + 0.5*g*h_right**2])
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+
+
+  
+
+def compute_timestep(domain):
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                qr[0] = stage[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #Update optimal_timestep
+            try:
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+    domain.timestep = timestep
+
+def compute_fluxes(domain):
+    """Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+#    Ymom = domain.quantities['ymomentum']
+    Bed = domain.quantities['elevation']
+
+    #Arrays
+    #stage = Stage.edge_values
+    #xmom =  Xmom.edge_values
+ #   ymom =  Ymom.edge_values
+    #bed =   Bed.edge_values
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+    
+    #print 'stage edge values', stage
+    #print 'xmom edge values', xmom
+    #print 'bed values', bed
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    #print 'stage_bdry',stage_bdry
+    #print 'xmom_bdry', xmom_bdry
+#    ymom_bdry =  Ymom.boundary_values
+
+#    flux = zeros(3, Float) #Work array for summing up fluxes
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            #ql[0] = stage[k, i]
+            #ql[1] = xmom[k, i]
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] = xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            #Flux computation using provided function
+            #edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+            #print 'ql',ql
+            #print 'qr',qr
+            
+
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #print 'edgeflux', edgeflux
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        Stage.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k] =  flux[1]
+        #Ymom.explicit_update[k] = flux[2]
+        #print "flux cell",k,flux[0]
+
+    domain.flux_timestep = timestep
+    #print domain.quantities['stage'].centroid_values
+
+
+# Compute flux definition
+def compute_fluxes_C_long(domain):
+	from Numeric import zeros, Float
+	import sys
+
+        cfl = domain.get_CFL()
+	
+	timestep = float(sys.maxint)
+	#print 'timestep=',timestep
+	#print 'The type of timestep is',type(timestep)
+	
+	epsilon = domain.epsilon
+	#print 'epsilon=',epsilon
+	#print 'The type of epsilon is',type(epsilon)
+	
+	g = domain.g
+	#print 'g=',g
+	#print 'The type of g is',type(g)
+
+        h0 = domain.h0
+	
+	neighbours = domain.neighbours
+	#print 'neighbours=',neighbours
+	#print 'The type of neighbours is',type(neighbours)
+	
+	neighbour_vertices = domain.neighbour_vertices
+	#print 'neighbour_vertices=',neighbour_vertices
+	#print 'The type of neighbour_vertices is',type(neighbour_vertices)
+	
+	normals = domain.normals
+	#print 'normals=',normals
+	#print 'The type of normals is',type(normals)
+	
+	areas = domain.areas
+	#print 'areas=',areas
+	#print 'The type of areas is',type(areas)
+	
+	stage_edge_values = domain.quantities['stage'].vertex_values
+	#print 'stage_edge_values=',stage_edge_values
+	#print 'The type of stage_edge_values is',type(stage_edge_values)
+	
+	xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+	#print 'xmom_edge_values=',xmom_edge_values
+	#print 'The type of xmom_edge_values is',type(xmom_edge_values)
+	
+	bed_edge_values = domain.quantities['elevation'].vertex_values
+	#print 'bed_edge_values=',bed_edge_values
+	#print 'The type of bed_edge_values is',type(bed_edge_values)
+	
+	stage_boundary_values = domain.quantities['stage'].boundary_values
+	#print 'stage_boundary_values=',stage_boundary_values
+	#print 'The type of stage_boundary_values is',type(stage_boundary_values)
+	
+	xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+	#print 'xmom_boundary_values=',xmom_boundary_values
+	#print 'The type of xmom_boundary_values is',type(xmom_boundary_values)
+	
+	stage_explicit_update = domain.quantities['stage'].explicit_update
+	#print 'stage_explicit_update=',stage_explicit_update
+	#print 'The type of stage_explicit_update is',type(stage_explicit_update)
+	
+	xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+	#print 'xmom_explicit_update=',xmom_explicit_update
+	#print 'The type of xmom_explicit_update is',type(xmom_explicit_update)
+	
+	number_of_elements = len(stage_edge_values)
+	#print 'number_of_elements=',number_of_elements
+	#print 'The type of number_of_elements is',type(number_of_elements)
+	
+	max_speed_array = domain.max_speed_array
+	#print 'max_speed_array=',max_speed_array
+	#print 'The type of max_speed_array is',type(max_speed_array)
+        
+        
+        from comp_flux_ext import compute_fluxes_ext
+	
+	domain.flux_timestep = compute_fluxes_ext(cfl,
+                                                  timestep,
+                                                  epsilon,
+                                                  g,
+                                                  h0,
+                                                  neighbours,
+                                                  neighbour_vertices,
+                                                  normals,
+                                                  areas, 
+                                                  stage_edge_values,
+                                                  xmom_edge_values,
+                                                  bed_edge_values,
+                                                  stage_boundary_values,
+                                                  xmom_boundary_values,
+                                                  stage_explicit_update,
+                                                  xmom_explicit_update,
+                                                  number_of_elements,
+                                                  max_speed_array)
+
+
+# Compute flux definition
+def compute_fluxes_C_short(domain):
+	from Numeric import zeros, Float
+	import sys
+
+	
+	timestep = float(sys.maxint)
+
+        stage = domain.quantities['stage']
+        xmom = domain.quantities['xmomentum']
+        bed = domain.quantities['elevation']
+
+
+        from comp_flux_ext import compute_fluxes_ext_short
+
+ 	domain.flux_timestep = compute_fluxes_ext_short(timestep,domain,stage,xmom,bed)
+
+
+
+####################################
+
+
+
+
+
+
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    protect_against_infinitesimal_and_negative_heights(domain)
+    
+
+    #Extrapolate all conserved quantities
+    #if optimised_gradient_limiter:
+    #    #MH090605 if second order,
+    #    #perform the extrapolation and limiting on
+    #    #all of the conserved quantities
+
+    #    if (domain.order == 1):
+    #        for name in domain.conserved_quantities:
+    #            Q = domain.quantities[name]
+    #            Q.extrapolate_first_order()
+    #    elif domain.order == 2:
+    #        domain.extrapolate_second_order_sw()
+    #    else:
+    #        raise 'Unknown order'
+    #else:
+        #old code:
+
+    for name in domain.conserved_quantities:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            #print "add extrapolate second order to shallow water"
+            #if name != 'height':
+            Q.extrapolate_second_order()
+            #Q.limit()
+        else:
+            raise 'Unknown order'
+
+    #Take bed elevation into account when water heights are small
+    #balance_deep_and_shallow(domain)
+    #protect_against_infinitesimal_and_negative_heights(domain)
+
+#Compute edge values by interpolation
+    #for name in domain.conserved_quantities:
+    #    Q = domain.quantities[name]
+    #    Q.interpolate_from_vertices_to_edges()    
+    
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+#    ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    zv = domain.quantities['elevation'].vertex_values
+    wv = domain.quantities['stage'].vertex_values
+    hv = wv-zv
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    #remove the above two lines and corresponding code below
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+                wv[k,0] = zv[k,0]
+                wv[k,1] = zv[k,1]
+                
+            xmomc[k] = 0.0
+            
+        #N = domain.number_of_elements
+        #if (k == 0) | (k==N-1):
+        #    wc[k] = zc[k] # Contain 'lost mass' error
+        #    wv[k,0] = zv[k,0]
+        #    wv[k,1] = zv[k,1]
+    
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        #for i in range(3):
+        for i in range(2):   
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    #for i in range(3):
+    for i in range(2):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        #for i in range(3):
+        for i in range(2):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        #for i in range(3):
+        for i in range(2):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]))#,
+#                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using the h-limited
+        #stage and alpha==1 means using the w-limited stage as
+        #computed by the gradient limiter (both 1st or 2nd order)
+
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        alpha  = 0.0
+	#Let
+	#
+	#  wvi be the w-limited stage (wvi = zvi + hvi)
+	#  wvi- be the h-limited state (wvi- = zvi + hvi-)
+	#
+	#
+	#where i=0,1,2 denotes the vertex ids
+	#
+        #Weighted balance between w-limited and h-limited stage is
+        #
+	#  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+	#
+        #It follows that the updated wvi is
+        #  wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+        #
+	# Momentum is balanced between constant and limited
+
+
+        #for i in range(3):
+        #    wv[k,i] = zv[k,i] + hvbar[k,i]
+
+	#return
+
+	if alpha < 1:
+
+            #for i in range(3):
+            for i in range(2):
+                wv[k,i] = zv[k,i] + (1.0-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+#            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+#           ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1.0-alpha)*xmomc[k] + alpha*xmomv[k,:]
+#            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+###############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        #self.stage   = domain.quantities['stage'].edge_values
+        #self.xmom    = domain.quantities['xmomentum'].edge_values
+        #self.ymom    = domain.quantities['ymomentum'].edge_values
+        self.normals = domain.normals
+        self.stage   = domain.quantities['stage'].vertex_values
+        self.xmom    = domain.quantities['xmomentum'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        self.conserved_quantities = zeros(2, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+
+        q = self.conserved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = self.xmom[vol_id, edge_id]
+        #q[2] = self.ymom[vol_id, edge_id]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+1]
+        normal = self.normals[vol_id,edge_id]
+
+        #r = rotate(q, normal, direction = 1)
+        #r[1] = -r[1]
+        #q = rotate(r, normal, direction = -1)
+        r = q
+        r[1] = normal*r[1]
+        r[1] = -r[1]
+        r[1] = normal*r[1]
+        q = r
+        #For start interval there is no outward momentum so do not need to
+        #reverse direction in this case
+
+        return q
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, conserved_quantities=None):
+        Boundary.__init__(self)
+
+        if conserved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.conserved_quantities=array(conserved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.conserved_quantities
+
+
+#########################
+#Standard forcing terms:
+#
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    stage = domain.quantities['stage'].explicit_update
+#    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    #h = Stage.edge_values - Elevation.edge_values
+    h = Stage.vertex_values - Elevation.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+#        avg_h = sum( h[k,:] )/3
+        avg_h = sum( h[k,:] )/2
+
+        #Compute bed slope
+        #x0, y0, x1, y1, x2, y2 = x[k,:]
+        x0, x1 = x[k,:]
+        #z0, z1, z2 = v[k,:]
+        b0, b1 = b[k,:]
+
+        w0, w1 = w[k,:]
+        wx = gradient(x0, x1, w0, w1)
+
+        #zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        xmom[k] += -g*bx*avg_h
+        #xmom[k] = -g*bx*avg_h
+        #stage[k] = 0.0
+ 
+ 
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    #vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    #ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	#S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+                S = -g * eta[k]**2 * uh[k]
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	#ymom_update[k] += S*vh[k]
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+#    vh = domain.quantities['ymomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+#    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g #Not necessary? Why was this added?
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+ #           	ymom_update[k] += S*vh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
+class Wind_stress:
+    """Apply wind stress to water momentum in terms of
+    wind speed [m/s] and wind direction [degrees]
+    """
+
+    def __init__(self, *args, **kwargs):
+        """Initialise windfield from wind speed s [m/s]
+        and wind direction phi [degrees]
+
+        Inputs v and phi can be either scalars or Python functions, e.g.
+
+        W = Wind_stress(10, 178)
+
+        #FIXME - 'normal' degrees are assumed for now, i.e. the
+        vector (1,0) has zero degrees.
+        We may need to convert from 'compass' degrees later on and also
+        map from True north to grid north.
+
+        Arguments can also be Python functions of t,x,y as in
+
+        def speed(t,x,y):
+            ...
+            return s
+
+        def angle(t,x,y):
+            ...
+            return phi
+
+        where x and y are vectors.
+
+        and then pass the functions in
+
+        W = Wind_stress(speed, angle)
+
+        The instantiated object W can be appended to the list of
+        forcing_terms as in
+
+        Alternatively, one vector valued function for (speed, angle)
+        can be applied, providing both quantities simultaneously.
+        As in
+        W = Wind_stress(F), where returns (speed, angle) for each t.
+
+        domain.forcing_terms.append(W)
+        """
+
+        from config import rho_a, rho_w, eta_w
+        from Numeric import array, Float
+
+        if len(args) == 2:
+            s = args[0]
+            phi = args[1]
+        elif len(args) == 1:
+            #Assume vector function returning (s, phi)(t,x,y)
+            vector_function = args[0]
+            #s = lambda t,x,y: vector_function(t,x=x,y=y)[0]
+            #phi = lambda t,x,y: vector_function(t,x=x,y=y)[1]
+            s = lambda t,x: vector_function(t,x=x)[0]
+            phi = lambda t,x: vector_function(t,x=x)[1]
+        else:
+           #Assume info is in 2 keyword arguments
+
+           if len(kwargs) == 2:
+               s = kwargs['s']
+               phi = kwargs['phi']
+           else:
+               raise 'Assumes two keyword arguments: s=..., phi=....'
+
+        print 'phi', phi
+        self.speed = check_forcefield(s)
+        self.phi = check_forcefield(phi)
+
+        self.const = eta_w*rho_a/rho_w
+
+
+    def __call__(self, domain):
+        """Evaluate windfield based on values found in domain
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import Float, ones, ArrayType
+
+        xmom_update = domain.quantities['xmomentum'].explicit_update
+        #ymom_update = domain.quantities['ymomentum'].explicit_update
+
+        N = domain.number_of_elements
+        t = domain.time
+
+        if callable(self.speed):
+            xc = domain.get_centroid_coordinates()
+            #s_vec = self.speed(t, xc[:,0], xc[:,1])
+            s_vec = self.speed(t, xc)
+        else:
+            #Assume s is a scalar
+
+            try:
+                s_vec = self.speed * ones(N, Float)
+            except:
+                msg = 'Speed must be either callable or a scalar: %s' %self.s
+                raise msg
+
+
+        if callable(self.phi):
+            xc = domain.get_centroid_coordinates()
+            #phi_vec = self.phi(t, xc[:,0], xc[:,1])
+            phi_vec = self.phi(t, xc)
+        else:
+            #Assume phi is a scalar
+
+            try:
+                phi_vec = self.phi * ones(N, Float)
+            except:
+                msg = 'Angle must be either callable or a scalar: %s' %self.phi
+                raise msg
+
+        #assign_windfield_values(xmom_update, ymom_update,
+        #                        s_vec, phi_vec, self.const)
+        assign_windfield_values(xmom_update, s_vec, phi_vec, self.const)
+
+
+#def assign_windfield_values(xmom_update, ymom_update,
+#                            s_vec, phi_vec, const):
+def assign_windfield_values(xmom_update, s_vec, phi_vec, const):
+    """Python version of assigning wind field to update vectors.
+    A c version also exists (for speed)
+    """
+    from math import pi, cos, sin, sqrt
+
+    N = len(s_vec)
+    for k in range(N):
+        s = s_vec[k]
+        phi = phi_vec[k]
+
+        #Convert to radians
+        phi = phi*pi/180
+
+        #Compute velocity vector (u, v)
+        u = s*cos(phi)
+        v = s*sin(phi)
+
+        #Compute wind stress
+        #S = const * sqrt(u**2 + v**2)
+        S = const * u
+        xmom_update[k] += S*u
+        #ymom_update[k] += S*v
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_h_nonwellbalanced.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_h_nonwellbalanced.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_h_nonwellbalanced.py	(revision 7576)
@@ -0,0 +1,995 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+
+from domain import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+    
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['stage', 'xmomentum']
+        other_quantities = ['elevation', 'height', 'velocity']
+        Generic_Domain.__init__(self, coordinates, boundary,
+                                conserved_quantities, other_quantities,
+                                tagged_elements)
+        
+        from config import minimum_allowed_height, g, h0, h_min
+        self.minimum_allowed_height = minimum_allowed_height
+        self.h0 = h0
+        self.g = g
+        self.h_min = h_min
+
+        #forcing terms not included in 1d domain ? Why?
+        self.forcing_terms.append(gravity)
+        
+        #Realtime visualisation
+        self.visualiser = None
+        self.visualise  = False
+        self.visualise_color_stage = False
+        self.visualise_stage_range = 1.0
+        self.visualise_timer = True
+        self.visualise_range_z = None
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        #Evolve parametrs
+        self.cfl = 1.0
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.quantities_to_be_stored = ['stage', 'xmomentum', 'elevation']
+
+        self.__doc__ = 'shallow_water_domain_h_nonwellbalanced'
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from realtime_visualisation_new import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+            self.visualiser.setup['elevation']=True
+            self.visualiser.updating['stage']=True
+        self.visualise = True
+        if self.visualise_color_stage == True:
+            self.visualiser.coloring['stage'] = True
+            self.visualiser.qcolor['stage'] = (0.0, 0.0, 0.8)
+        print 'initialise visualiser'
+        print self.visualiser.setup
+        print self.visualiser.updating
+
+    def check_integrity(self):
+        Generic_Domain.check_integrity(self)
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes(self) #compute_fluxes_C_short(self)    #compute_fluxes_C_wellbalanced(self)     #compute_fluxes(self)  #compute_fluxes_C_long(self)
+
+    def compute_timestep(self):
+        #Call correct module function
+        compute_timestep(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+        
+    def evolve(self, yieldstep = None,
+               finaltime = None,
+               duration = None,
+               skip_initial_step = False):
+        """Specialisation of basic evolve method from parent class
+        """
+
+        self.distribute_to_vertices_and_edges()
+        
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime, duration,
+                                       skip_initial_step):
+            #Pass control on to outer loop for more specific actions
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x and bed elevation
+        """
+
+        import data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+def compute_timestep(domain):
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                qr[0] = stage[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+
+            #if domain.split == False:
+            #    edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+            #elif domain.split == True:
+            #    edgeflux, max_speed = flux_function_split(normal, ql, qr, zl, zr)
+            #Update optimal_timestep
+            #try:
+            #    timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            #except ZeroDivisionError:
+            #    pass
+
+    domain.timestep = timestep
+#
+def flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/h_right
+
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+
+#The compute_fluxes is involving the flux_function above.
+def compute_fluxes(domain):
+    """Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+#    Ymom = domain.quantities['ymomentum']
+    Bed = domain.quantities['elevation']
+
+    #Arrays
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+    
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] = xmom[n, m]
+                zr = bed[n, m]
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        Stage.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k] =  flux[1]
+        
+
+    domain.flux_timestep = timestep
+    #print domain.quantities['stage'].centroid_values
+
+
+# Compute flux definition
+def compute_fluxes_C_long(domain):
+	from Numeric import zeros, Float
+	import sys
+
+	
+	timestep = float(sys.maxint)
+	epsilon = domain.epsilon
+	g = domain.g
+	neighbours = domain.neighbours
+	neighbour_vertices = domain.neighbour_vertices
+	normals = domain.normals
+	areas = domain.areas
+	stage_edge_values = domain.quantities['stage'].vertex_values
+	xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+	bed_edge_values = domain.quantities['elevation'].vertex_values
+	stage_boundary_values = domain.quantities['stage'].boundary_values
+	xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+	stage_explicit_update = domain.quantities['stage'].explicit_update
+	xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+	number_of_elements = len(stage_edge_values)
+	max_speed_array = domain.max_speed_array
+	        
+        from comp_flux_ext import compute_fluxes_ext
+	
+	domain.flux_timestep = compute_fluxes_ext(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_edge_values,
+                                  xmom_edge_values,
+                                  bed_edge_values,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+
+# Compute flux definition
+def compute_fluxes_C_short(domain):
+	from Numeric import zeros, Float
+	import sys
+
+	
+	timestep = float(sys.maxint)
+
+        stage = domain.quantities['stage']
+        xmom = domain.quantities['xmomentum']
+        bed = domain.quantities['elevation']
+
+
+        from comp_flux_ext import compute_fluxes_ext_short
+
+ 	domain.flux_timestep = compute_fluxes_ext_short(timestep,domain,stage,xmom,bed)
+
+
+def compute_fluxes_C_wellbalanced(domain):
+	from Numeric import zeros, Float
+	import sys
+
+	
+	timestep = float(sys.maxint)
+	epsilon = domain.epsilon
+	g = domain.g
+	neighbours = domain.neighbours
+	neighbour_vertices = domain.neighbour_vertices
+	normals = domain.normals
+	areas = domain.areas
+	stage_edge_values = domain.quantities['stage'].vertex_values
+	xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+	bed_edge_values = domain.quantities['elevation'].vertex_values
+	stage_boundary_values = domain.quantities['stage'].boundary_values
+	xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+	stage_explicit_update = domain.quantities['stage'].explicit_update
+	xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+	number_of_elements = len(stage_edge_values)
+	max_speed_array = domain.max_speed_array
+	        
+        from comp_flux_ext_wellbalanced import compute_fluxes_ext_wellbalanced  #from comp_flux_ext import compute_fluxes_ext
+	
+	domain.flux_timestep = compute_fluxes_ext_wellbalanced(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_edge_values,
+                                  xmom_edge_values,
+                                  bed_edge_values,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+# ###################################
+
+
+
+
+
+
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    import sys
+    from Numeric import zeros, Float
+    from config import epsilon, h0, h_min
+	
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    Height = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+    #Arrays   
+    w_C   = Stage.centroid_values    
+    uh_C  = Xmom.centroid_values    
+    z_C   = Bed.centroid_values
+    h_C   = Height.centroid_values
+    u_C   = Velocity.centroid_values
+    #print 'Here h_C=',h_C
+
+    #print id(h_C)
+    for i in range(N):
+	h_C[i] = w_C[i] - z_C[i]						
+        if h_C[i] <= 1.0e-15: #0.0:
+	    #print 'h_C[%d]= %15.5e\n' % (i,h_C[i])
+	    h_C[i] = 1.0e-15
+	    w_C[i] = z_C[i]
+	    uh_C[i] = 0.0
+	    u_C[i] = 0.0
+        else:
+            u_C[:]  = uh_C/(h_C + h0/h_C)
+    
+    protect_against_infinitesimal_and_negative_heights(domain)    
+
+    for name in ['stage', 'xmomentum']: #domain.conserved_quantities:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            #print "add extrapolate second order to shallow water"
+            #if name != 'height':
+            Q.extrapolate_second_order()
+            #Q.limit()
+        else:
+            raise 'Unknown order'
+        
+    w_V = domain.quantities['stage'].vertex_values			
+    z_V = domain.quantities['elevation'].vertex_values	
+    h_V = domain.quantities['height'].vertex_values
+    u_V = domain.quantities['velocity'].vertex_values		
+    uh_V= domain.quantities['xmomentum'].vertex_values
+
+    for i in range(N):
+	h_V[i] = w_V[i] - z_V[i]						
+        if h_V[i] <= 0.0:
+	    #print 'h_C[%d]= %15.5e\n' % (i,h_C[i])
+	    h_V[i] = 1.0e-15
+	    w_V[i] = z_V[i]
+	    uh_V[i] = 0.0
+    
+    u_V[:]  = uh_V/(h_V + h0/h_V)
+
+    for i in range(len(h_V)):
+        if h_V[i] <= h_min:
+            u_V[i] = 0.0 
+    #print 'Here u_V=',u_V
+    #Take bed elevation into account when water heights are small
+    #balance_deep_and_shallow(domain)
+    #protect_against_infinitesimal_and_negative_heights(domain)
+
+    #Compute edge values by interpolation
+    #for name in domain.conserved_quantities:
+    #    Q = domain.quantities[name]
+    #    Q.interpolate_from_vertices_to_edges()
+    return    
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+#    ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    zv = domain.quantities['elevation'].vertex_values
+    wv = domain.quantities['stage'].vertex_values
+    hv = wv-zv
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    #remove the above two lines and corresponding code below
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+                wv[k,0] = zv[k,0]
+                wv[k,1] = zv[k,1]
+                
+            xmomc[k] = 0.0
+            
+        
+    
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        #for i in range(3):
+        for i in range(2):   
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    #for i in range(3):
+    for i in range(2):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        #for i in range(3):
+        for i in range(2):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        #for i in range(3):
+        for i in range(2):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]))#,
+#                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        alpha  = 0.0
+	
+	if alpha < 1:
+
+            #for i in range(3):
+            for i in range(2):
+                wv[k,i] = zv[k,i] + (1.0-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+#            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+#           ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1.0-alpha)*xmomc[k] + alpha*xmomv[k,:]
+#            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+# ##############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        self.normals = domain.normals
+        self.stage   = domain.quantities['stage'].vertex_values
+        self.xmom    = domain.quantities['xmomentum'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        self.conserved_quantities = zeros(2, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+
+        q = self.conserved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = self.xmom[vol_id, edge_id]
+        normal = self.normals[vol_id,edge_id]
+
+        r = q
+        r[1] = normal*r[1]
+        r[1] = -r[1]
+        r[1] = normal*r[1]
+        q = r
+        #For start interval there is no outward momentum so do not need to
+        #reverse direction in this case
+
+        return q
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, conserved_quantities=None):
+        Boundary.__init__(self)
+
+        if conserved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.conserved_quantities=array(conserved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.conserved_quantities
+
+
+# ########################
+#Standard forcing terms:
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    stage = domain.quantities['stage'].explicit_update
+#    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    #h = Stage.edge_values - Elevation.edge_values
+    h = Stage.vertex_values - Elevation.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+#        avg_h = sum( h[k,:] )/3
+        avg_h = sum( h[k,:] )/2
+
+        #Compute bed slope
+        #x0, y0, x1, y1, x2, y2 = x[k,:]
+        x0, x1 = x[k,:]
+        #z0, z1, z2 = v[k,:]
+        b0, b1 = b[k,:]
+
+        w0, w1 = w[k,:]
+        wx = gradient(x0, x1, w0, w1)
+
+        #zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        xmom[k] += -g*bx*avg_h
+        #xmom[k] = -g*bx*avg_h
+        #stage[k] = 0.0
+ 
+ 
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_h_wellbalanced.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_h_wellbalanced.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_h_wellbalanced.py	(revision 7576)
@@ -0,0 +1,1432 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+
+from domain import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['stage', 'xmomentum']
+        other_quantities = ['elevation', 'friction', 'height', 'velocity']
+        Generic_Domain.__init__(self, coordinates, boundary,
+                                conserved_quantities, other_quantities,
+                                tagged_elements)
+        
+        from config import minimum_allowed_height, g, h0
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+        self.h0 = h0
+
+        #forcing terms not included in 1d domain ?WHy?
+        self.forcing_terms.append(gravity)
+        #self.forcing_terms.append(manning_friction)
+        #print "\nI have Removed forcing terms line 64 1dsw"
+
+        #Realtime visualisation
+        self.visualiser = None
+        self.visualise  = False
+        self.visualise_color_stage = False
+        self.visualise_stage_range = 1.0
+        self.visualise_timer = True
+        self.visualise_range_z = None
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        #Evolve parametrs
+        self.cfl = 1.0
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.quantities_to_be_stored = ['stage','xmomentum']
+
+	self.__doc__ = 'shallow_water_domain_h_wellbalanced'
+
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from realtime_visualisation_new import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+            self.visualiser.setup['elevation']=True
+            self.visualiser.updating['stage']=True
+        self.visualise = True
+        if self.visualise_color_stage == True:
+            self.visualiser.coloring['stage'] = True
+            self.visualiser.qcolor['stage'] = (0.0, 0.0, 0.8)
+        print 'initialise visualiser'
+        print self.visualiser.setup
+        print self.visualiser.updating
+
+    def check_integrity(self):
+        Generic_Domain.check_integrity(self)
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes_C_wellbalanced(self)
+
+    def compute_timestep(self):
+        #Call correct module function
+        compute_timestep(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+        
+    def evolve(self, yieldstep = None, finaltime = None, duration = None,
+               skip_initial_step = False):
+        """Specialisation of basic evolve method from parent class
+        """
+
+        #Call check integrity here rather than from user scripts
+        #self.check_integrity()
+
+        #msg = 'Parameter beta_h must be in the interval [0, 1)'
+        #assert 0 <= self.beta_h < 1.0, msg
+        #msg = 'Parameter beta_w must be in the interval [0, 1)'
+        #assert 0 <= self.beta_w < 1.0, msg
+
+
+        #Initial update of vertex and edge values before any storage
+        #and or visualisation
+        
+        self.distribute_to_vertices_and_edges()
+        
+        #Initialise real time viz if requested
+        #if self.visualise is True and self.time == 0.0:
+        #    if self.visualiser is None:
+        #        self.initialise_visualiser()
+        #
+        #    self.visualiser.update_timer()
+        #    self.visualiser.setup_all()
+
+        #Store model data, e.g. for visualisation
+        #if self.store is True and self.time == 0.0:
+        #    self.initialise_storage()
+        #    #print 'Storing results in ' + self.writer.filename
+        #else:
+        #    pass
+        #    #print 'Results will not be stored.'
+        #    #print 'To store results set domain.store = True'
+        #    #FIXME: Diagnostic output should be controlled by
+        #    # a 'verbose' flag living in domain (or in a parent class)
+
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime,duration,
+                                       skip_initial_step):
+            #Real time viz
+        #    if self.visualise is True:
+        #        self.visualiser.update_all()
+        #        self.visualiser.update_timer()
+
+
+            #Store model data, e.g. for subsequent visualisation
+        #    if self.store is True:
+        #        self.store_timestep(self.quantities_to_be_stored)
+
+            #FIXME: Could maybe be taken from specified list
+            #of 'store every step' quantities
+
+            #Pass control on to outer loop for more specific actions
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x and bed elevation
+        """
+
+        import data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+
+#Rotation of momentum vector
+def rotate(q, normal, direction = 1):
+    """Rotate the momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector.
+
+    If direction is negative the rotation is inverted.
+
+    Input vector is preserved
+
+    This function is specific to the shallow water wave equation
+    """
+
+    from Numeric import zeros, Float
+
+    assert len(q) == 3,\
+           'Vector of conserved quantities must have length 3'\
+           'for 2D shallow water equation'
+
+    try:
+        l = len(normal)
+    except:
+        raise 'Normal vector must be an Numeric array'
+
+    assert l == 2, 'Normal vector must have 2 components'
+
+
+    n1 = normal[0]
+    n2 = normal[1]
+
+    r = zeros(len(q), Float) #Rotated quantities
+    r[0] = q[0]              #First quantity, height, is not rotated
+
+    if direction == -1:
+        n2 = -n2
+
+
+    r[1] =  n1*q[1] + n2*q[2]
+    r[2] = -n2*q[1] + n1*q[2]
+
+    return r
+
+
+def flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon, h0
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/(h_left +  h0/h_left)
+
+
+    uh_left = u_left*h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/(h_right + h0/h_right)
+
+    uh_right = u_right*h_right
+
+    #vh_left  = q_left[2]
+    #vh_right = q_right[2]
+
+    #print h_right
+    #print u_right
+    #print h_left
+    #print u_right
+    #We have got   h   and    u   at vertex, then  the following is the calculation of fluxes!
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+
+    #flux_left  = array([u_left*h_left,
+    #                    u_left*uh_left + 0.5*g*h_left**2])
+    #flux_right = array([u_right*h_right,
+    #                    u_right*uh_right + 0.5*g*h_right**2])
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+
+
+  
+
+def compute_timestep(domain):
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                qr[0] = stage[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #Update optimal_timestep
+            try:
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+    domain.timestep = timestep
+
+def compute_fluxes(domain):
+    """Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+#    Ymom = domain.quantities['ymomentum']
+    Bed = domain.quantities['elevation']
+
+    #Arrays
+    #stage = Stage.edge_values
+    #xmom =  Xmom.edge_values
+ #   ymom =  Ymom.edge_values
+    #bed =   Bed.edge_values
+    
+    stage = Stage.vertex_values    #This is     w     at vertex
+    xmom =  Xmom.vertex_values     #This is     uh     at vertex
+    bed =   Bed.vertex_values      #This is     z     at vertex
+    
+    #print 'stage edge values', stage
+    #print 'xmom edge values', xmom
+    #print 'bed values', bed
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    #print 'stage_bdry',stage_bdry
+    #print 'xmom_bdry', xmom_bdry
+#    ymom_bdry =  Ymom.boundary_values
+
+#    flux = zeros(3, Float) #Work array for summing up fluxes
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            #ql[0] = stage[k, i]
+            #ql[1] = xmom[k, i]
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] = xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            #Flux computation using provided function
+            #edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+            #print 'ql',ql
+            #print 'qr',qr
+            
+
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #print 'edgeflux', edgeflux
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        Stage.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k] =  flux[1]
+        #Ymom.explicit_update[k] = flux[2]
+        #print "flux cell",k,flux[0]
+
+    domain.flux_timestep = timestep
+    #print domain.quantities['stage'].centroid_values
+
+
+# Compute flux definition
+def compute_fluxes_C_long(domain):
+	from Numeric import zeros, Float
+	import sys
+
+	
+	timestep = float(sys.maxint)
+	#print 'timestep=',timestep
+	#print 'The type of timestep is',type(timestep)
+	
+	epsilon = domain.epsilon
+	#print 'epsilon=',epsilon
+	#print 'The type of epsilon is',type(epsilon)
+	
+	g = domain.g
+	#print 'g=',g
+	#print 'The type of g is',type(g)
+	
+	neighbours = domain.neighbours
+	#print 'neighbours=',neighbours
+	#print 'The type of neighbours is',type(neighbours)
+	
+	neighbour_vertices = domain.neighbour_vertices
+	#print 'neighbour_vertices=',neighbour_vertices
+	#print 'The type of neighbour_vertices is',type(neighbour_vertices)
+	
+	normals = domain.normals
+	#print 'normals=',normals
+	#print 'The type of normals is',type(normals)
+	
+	areas = domain.areas
+	#print 'areas=',areas
+	#print 'The type of areas is',type(areas)
+	
+	stage_edge_values = domain.quantities['stage'].vertex_values
+	#print 'stage_edge_values=',stage_edge_values
+	#print 'The type of stage_edge_values is',type(stage_edge_values)
+	
+	xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+	#print 'xmom_edge_values=',xmom_edge_values
+	#print 'The type of xmom_edge_values is',type(xmom_edge_values)
+	
+	bed_edge_values = domain.quantities['elevation'].vertex_values
+	#print 'bed_edge_values=',bed_edge_values
+	#print 'The type of bed_edge_values is',type(bed_edge_values)
+	
+	stage_boundary_values = domain.quantities['stage'].boundary_values
+	#print 'stage_boundary_values=',stage_boundary_values
+	#print 'The type of stage_boundary_values is',type(stage_boundary_values)
+	
+	xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+	#print 'xmom_boundary_values=',xmom_boundary_values
+	#print 'The type of xmom_boundary_values is',type(xmom_boundary_values)
+	
+	stage_explicit_update = domain.quantities['stage'].explicit_update
+	#print 'stage_explicit_update=',stage_explicit_update
+	#print 'The type of stage_explicit_update is',type(stage_explicit_update)
+	
+	xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+	#print 'xmom_explicit_update=',xmom_explicit_update
+	#print 'The type of xmom_explicit_update is',type(xmom_explicit_update)
+	
+	number_of_elements = len(stage_edge_values)
+	#print 'number_of_elements=',number_of_elements
+	#print 'The type of number_of_elements is',type(number_of_elements)
+	
+	max_speed_array = domain.max_speed_array
+	#print 'max_speed_array=',max_speed_array
+	#print 'The type of max_speed_array is',type(max_speed_array)
+        
+        
+        from comp_flux_ext import compute_fluxes_ext
+	
+	domain.flux_timestep = compute_fluxes_ext(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_edge_values,
+                                  xmom_edge_values,
+                                  bed_edge_values,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+
+# Compute flux definition
+def compute_fluxes_C_short(domain):
+	from Numeric import zeros, Float
+	import sys
+
+	
+	timestep = float(sys.maxint)
+
+        stage = domain.quantities['stage']
+        xmom = domain.quantities['xmomentum']
+        bed = domain.quantities['elevation']
+
+
+        from comp_flux_ext import compute_fluxes_ext_short
+
+ 	domain.flux_timestep = compute_fluxes_ext_short(timestep,domain,stage,xmom,bed)
+
+
+
+# ###################################
+def compute_fluxes_C_wellbalanced(domain):
+	from Numeric import zeros, Float
+	import sys
+
+	
+	timestep = float(sys.maxint)
+	epsilon = domain.epsilon
+	g = domain.g
+	neighbours = domain.neighbours
+	neighbour_vertices = domain.neighbour_vertices
+	normals = domain.normals
+	areas = domain.areas
+	stage_edge_values = domain.quantities['stage'].vertex_values
+	xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+	bed_edge_values = domain.quantities['elevation'].vertex_values
+	stage_boundary_values = domain.quantities['stage'].boundary_values
+	xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+	stage_explicit_update = domain.quantities['stage'].explicit_update
+	xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+	number_of_elements = len(stage_edge_values)
+	max_speed_array = domain.max_speed_array
+	        
+        from comp_flux_ext_wellbalanced import compute_fluxes_ext_wellbalanced  #from comp_flux_ext import compute_fluxes_ext
+	
+	domain.flux_timestep = compute_fluxes_ext_wellbalanced(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_edge_values,
+                                  xmom_edge_values,
+                                  bed_edge_values,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+# ###################################
+
+
+
+
+
+
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    import sys
+    from Numeric import zeros, Float
+    from config import epsilon, h0
+	
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    Height = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+    #Arrays   
+    w_C   = Stage.centroid_values    
+    uh_C  = Xmom.centroid_values    
+    z_C   = Bed.centroid_values
+    h_C   = Height.centroid_values
+    u_C   = Velocity.centroid_values
+    #print 'Here h_C=',h_C
+
+    #print id(h_C)
+    for i in range(N):
+	h_C[i] = w_C[i] - z_C[i]						
+        if h_C[i] <= 0.0:
+	    #print 'h_C[%d]= %15.5e\n' % (i,h_C[i])
+	    h_C[i] = 0.0  #1.0e-15
+	    w_C[i] = z_C[i]
+	    uh_C[i] = 0.0
+    
+    u_C[:]  = uh_C/(h_C + h0/h_C)
+
+    protect_against_infinitesimal_and_negative_heights(domain)
+
+    for name in ['stage', 'xmomentum']:  #domain.conserved_quantities:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            #print "add extrapolate second order to shallow water"
+            #if name != 'height':
+            Q.extrapolate_second_order()
+            #Q.limit()
+        else:
+            raise 'Unknown order'
+
+    w_V = domain.quantities['stage'].vertex_values			
+    z_V   = domain.quantities['elevation'].vertex_values	
+    h_V    = domain.quantities['height'].vertex_values
+    uh_V = domain.quantities['xmomentum'].vertex_values
+    u_V    = domain.quantities['velocity'].vertex_values
+
+    for i in range(N):
+	h_V[i] = w_V[i] - z_V[i]						
+        if h_V[i] <= 0.0:
+	    #print 'h_C[%d]= %15.5e\n' % (i,h_C[i])
+	    h_V[i] = 0.0  #1.0e-15
+	    w_V[i] = z_V[i]
+	    uh_V[i] = 0.0
+    
+    u_V[:]  = uh_V/(h_V + h0/h_V)
+    #print 'Here u_V=',u_V
+    #Take bed elevation into account when water heights are small
+    #balance_deep_and_shallow(domain)
+    #protect_against_infinitesimal_and_negative_heights(domain)
+
+    #Compute edge values by interpolation
+    #for name in domain.conserved_quantities:
+    #    Q = domain.quantities[name]
+    #    Q.interpolate_from_vertices_to_edges()    
+    return
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+#    ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    zv = domain.quantities['elevation'].vertex_values
+    wv = domain.quantities['stage'].vertex_values
+    hv = wv-zv
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    #remove the above two lines and corresponding code below
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+                wv[k,0] = zv[k,0]
+                wv[k,1] = zv[k,1]
+                
+            xmomc[k] = 0.0
+            
+        #N = domain.number_of_elements
+        #if (k == 0) | (k==N-1):
+        #    wc[k] = zc[k] # Contain 'lost mass' error
+        #    wv[k,0] = zv[k,0]
+        #    wv[k,1] = zv[k,1]
+    
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        #for i in range(3):
+        for i in range(2):   
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    #for i in range(3):
+    for i in range(2):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        #for i in range(3):
+        for i in range(2):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        #for i in range(3):
+        for i in range(2):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]))#,
+#                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using the h-limited
+        #stage and alpha==1 means using the w-limited stage as
+        #computed by the gradient limiter (both 1st or 2nd order)
+
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        alpha  = 0.0
+	#Let
+	#
+	#  wvi be the w-limited stage (wvi = zvi + hvi)
+	#  wvi- be the h-limited state (wvi- = zvi + hvi-)
+	#
+	#
+	#where i=0,1,2 denotes the vertex ids
+	#
+        #Weighted balance between w-limited and h-limited stage is
+        #
+	#  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+	#
+        #It follows that the updated wvi is
+        #  wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+        #
+	# Momentum is balanced between constant and limited
+
+
+        #for i in range(3):
+        #    wv[k,i] = zv[k,i] + hvbar[k,i]
+
+	#return
+
+	if alpha < 1:
+
+            #for i in range(3):
+            for i in range(2):
+                wv[k,i] = zv[k,i] + (1.0-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+#            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+#           ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1.0-alpha)*xmomc[k] + alpha*xmomv[k,:]
+#            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+###############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        #self.stage   = domain.quantities['stage'].edge_values
+        #self.xmom    = domain.quantities['xmomentum'].edge_values
+        #self.ymom    = domain.quantities['ymomentum'].edge_values
+        self.normals = domain.normals
+        self.stage   = domain.quantities['stage'].vertex_values
+        self.xmom    = domain.quantities['xmomentum'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        self.conserved_quantities = zeros(2, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+
+        q = self.conserved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = self.xmom[vol_id, edge_id]
+        #q[2] = self.ymom[vol_id, edge_id]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+1]
+        normal = self.normals[vol_id,edge_id]
+
+        #r = rotate(q, normal, direction = 1)
+        #r[1] = -r[1]
+        #q = rotate(r, normal, direction = -1)
+        r = q
+        r[1] = normal*r[1]
+        r[1] = -r[1]
+        r[1] = normal*r[1]
+        q = r
+        #For start interval there is no outward momentum so do not need to
+        #reverse direction in this case
+
+        return q
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, conserved_quantities=None):
+        Boundary.__init__(self)
+
+        if conserved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.conserved_quantities=array(conserved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.conserved_quantities
+
+
+#########################
+#Standard forcing terms:
+#
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    stage = domain.quantities['stage'].explicit_update
+#    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    #h = Stage.edge_values - Elevation.edge_values
+    h = Stage.vertex_values - Elevation.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+#        avg_h = sum( h[k,:] )/3
+        avg_h = sum( h[k,:] )/2
+
+        #Compute bed slope
+        #x0, y0, x1, y1, x2, y2 = x[k,:]
+        x0, x1 = x[k,:]
+        #z0, z1, z2 = v[k,:]
+        b0, b1 = b[k,:]
+
+        w0, w1 = w[k,:]
+        wx = gradient(x0, x1, w0, w1)
+
+        #zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        xmom[k] += -g*bx*avg_h
+        #xmom[k] = -g*bx*avg_h
+        #stage[k] = 0.0
+ 
+ 
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    #vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    #ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	#S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+                S = -g * eta[k]**2 * uh[k]
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	#ymom_update[k] += S*vh[k]
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+#    vh = domain.quantities['ymomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+#    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g #Not necessary? Why was this added?
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+ #           	ymom_update[k] += S*vh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
+class Wind_stress:
+    """Apply wind stress to water momentum in terms of
+    wind speed [m/s] and wind direction [degrees]
+    """
+
+    def __init__(self, *args, **kwargs):
+        """Initialise windfield from wind speed s [m/s]
+        and wind direction phi [degrees]
+
+        Inputs v and phi can be either scalars or Python functions, e.g.
+
+        W = Wind_stress(10, 178)
+
+        #FIXME - 'normal' degrees are assumed for now, i.e. the
+        vector (1,0) has zero degrees.
+        We may need to convert from 'compass' degrees later on and also
+        map from True north to grid north.
+
+        Arguments can also be Python functions of t,x,y as in
+
+        def speed(t,x,y):
+            ...
+            return s
+
+        def angle(t,x,y):
+            ...
+            return phi
+
+        where x and y are vectors.
+
+        and then pass the functions in
+
+        W = Wind_stress(speed, angle)
+
+        The instantiated object W can be appended to the list of
+        forcing_terms as in
+
+        Alternatively, one vector valued function for (speed, angle)
+        can be applied, providing both quantities simultaneously.
+        As in
+        W = Wind_stress(F), where returns (speed, angle) for each t.
+
+        domain.forcing_terms.append(W)
+        """
+
+        from config import rho_a, rho_w, eta_w
+        from Numeric import array, Float
+
+        if len(args) == 2:
+            s = args[0]
+            phi = args[1]
+        elif len(args) == 1:
+            #Assume vector function returning (s, phi)(t,x,y)
+            vector_function = args[0]
+            #s = lambda t,x,y: vector_function(t,x=x,y=y)[0]
+            #phi = lambda t,x,y: vector_function(t,x=x,y=y)[1]
+            s = lambda t,x: vector_function(t,x=x)[0]
+            phi = lambda t,x: vector_function(t,x=x)[1]
+        else:
+           #Assume info is in 2 keyword arguments
+
+           if len(kwargs) == 2:
+               s = kwargs['s']
+               phi = kwargs['phi']
+           else:
+               raise 'Assumes two keyword arguments: s=..., phi=....'
+
+        print 'phi', phi
+        self.speed = check_forcefield(s)
+        self.phi = check_forcefield(phi)
+
+        self.const = eta_w*rho_a/rho_w
+
+
+    def __call__(self, domain):
+        """Evaluate windfield based on values found in domain
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import Float, ones, ArrayType
+
+        xmom_update = domain.quantities['xmomentum'].explicit_update
+        #ymom_update = domain.quantities['ymomentum'].explicit_update
+
+        N = domain.number_of_elements
+        t = domain.time
+
+        if callable(self.speed):
+            xc = domain.get_centroid_coordinates()
+            #s_vec = self.speed(t, xc[:,0], xc[:,1])
+            s_vec = self.speed(t, xc)
+        else:
+            #Assume s is a scalar
+
+            try:
+                s_vec = self.speed * ones(N, Float)
+            except:
+                msg = 'Speed must be either callable or a scalar: %s' %self.s
+                raise msg
+
+
+        if callable(self.phi):
+            xc = domain.get_centroid_coordinates()
+            #phi_vec = self.phi(t, xc[:,0], xc[:,1])
+            phi_vec = self.phi(t, xc)
+        else:
+            #Assume phi is a scalar
+
+            try:
+                phi_vec = self.phi * ones(N, Float)
+            except:
+                msg = 'Angle must be either callable or a scalar: %s' %self.phi
+                raise msg
+
+        #assign_windfield_values(xmom_update, ymom_update,
+        #                        s_vec, phi_vec, self.const)
+        assign_windfield_values(xmom_update, s_vec, phi_vec, self.const)
+
+
+#def assign_windfield_values(xmom_update, ymom_update,
+#                            s_vec, phi_vec, const):
+def assign_windfield_values(xmom_update, s_vec, phi_vec, const):
+    """Python version of assigning wind field to update vectors.
+    A c version also exists (for speed)
+    """
+    from math import pi, cos, sin, sqrt
+
+    N = len(s_vec)
+    for k in range(N):
+        s = s_vec[k]
+        phi = phi_vec[k]
+
+        #Convert to radians
+        phi = phi*pi/180
+
+        #Compute velocity vector (u, v)
+        u = s*cos(phi)
+        v = s*sin(phi)
+
+        #Compute wind stress
+        #S = const * sqrt(u**2 + v**2)
+        S = const * u
+        xmom_update[k] += S*u
+        #ymom_update[k] += S*v
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_new.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_new.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_new.py	(revision 7576)
@@ -0,0 +1,934 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+
+from domain import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+    
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['stage', 'xmomentum']
+        other_quantities = ['elevation', 'height', 'velocity']
+        Generic_Domain.__init__(self, coordinates, boundary,
+                                conserved_quantities, other_quantities,
+                                tagged_elements)
+        
+        from config import minimum_allowed_height, g
+        self.minimum_allowed_height = minimum_allowed_height
+        self.h0 = minimum_allowed_height
+        self.g = g
+
+        #forcing terms not included in 1d domain ? Why?
+        self.forcing_terms.append(gravity)
+        
+        #Realtime visualisation
+        self.visualiser = None
+        self.visualise  = False
+        self.visualise_color_stage = False
+        self.visualise_stage_range = 1.0
+        self.visualise_timer = True
+        self.visualise_range_z = None
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        #Evolve parametrs
+        self.cfl = 1.0
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.quantities_to_be_stored = ['stage', 'xmomentum', 'elevation']
+
+        self.__doc__ = 'shallow_water_domain_new'
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from realtime_visualisation_new import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+            self.visualiser.setup['elevation']=True
+            self.visualiser.updating['stage']=True
+        self.visualise = True
+        if self.visualise_color_stage == True:
+            self.visualiser.coloring['stage'] = True
+            self.visualiser.qcolor['stage'] = (0.0, 0.0, 0.8)
+        print 'initialise visualiser'
+        print self.visualiser.setup
+        print self.visualiser.updating
+
+    def check_integrity(self):
+        Generic_Domain.check_integrity(self)
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes_C_short(self)    #compute_fluxes_C_wellbalanced(self)     #compute_fluxes(self)  #compute_fluxes_C_long(self)
+
+    def compute_timestep(self):
+        #Call correct module function
+        compute_timestep(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+        
+    def evolve(self, yieldstep = None,
+               finaltime = None,
+               duration = None,
+               skip_initial_step = False):
+        """Specialisation of basic evolve method from parent class
+        """
+
+        self.distribute_to_vertices_and_edges()
+        
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime, duration,
+                                       skip_initial_step):
+            #Pass control on to outer loop for more specific actions
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x and bed elevation
+        """
+
+        import data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+def compute_timestep(domain):
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                qr[0] = stage[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+
+            #if domain.split == False:
+            #    edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+            #elif domain.split == True:
+            #    edgeflux, max_speed = flux_function_split(normal, ql, qr, zl, zr)
+            #Update optimal_timestep
+            #try:
+            #    timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            #except ZeroDivisionError:
+            #    pass
+
+    domain.timestep = timestep
+#
+def flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/h_right
+
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+
+#The compute_fluxes is involving the flux_function above.
+def compute_fluxes(domain):
+    """Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+#    Ymom = domain.quantities['ymomentum']
+    Bed = domain.quantities['elevation']
+
+    #Arrays
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+    
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] = xmom[n, m]
+                zr = bed[n, m]
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        Stage.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k] =  flux[1]
+        
+
+    domain.flux_timestep = timestep
+    #print domain.quantities['stage'].centroid_values
+
+
+# Compute flux definition
+def compute_fluxes_C_long(domain):
+	from Numeric import zeros, Float
+	import sys
+
+	
+	timestep = float(sys.maxint)
+	epsilon = domain.epsilon
+	g = domain.g
+	neighbours = domain.neighbours
+	neighbour_vertices = domain.neighbour_vertices
+	normals = domain.normals
+	areas = domain.areas
+	stage_edge_values = domain.quantities['stage'].vertex_values
+	xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+	bed_edge_values = domain.quantities['elevation'].vertex_values
+	stage_boundary_values = domain.quantities['stage'].boundary_values
+	xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+	stage_explicit_update = domain.quantities['stage'].explicit_update
+	xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+	number_of_elements = len(stage_edge_values)
+	max_speed_array = domain.max_speed_array
+	        
+        from comp_flux_ext import compute_fluxes_ext
+	
+	domain.flux_timestep = compute_fluxes_ext(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_edge_values,
+                                  xmom_edge_values,
+                                  bed_edge_values,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+
+# Compute flux definition
+def compute_fluxes_C_short(domain):
+	from Numeric import zeros, Float
+	import sys
+
+	
+	timestep = float(sys.maxint)
+
+        stage = domain.quantities['stage']
+        xmom = domain.quantities['xmomentum']
+        bed = domain.quantities['elevation']
+
+
+        from comp_flux_ext import compute_fluxes_ext_short
+
+ 	domain.flux_timestep = compute_fluxes_ext_short(timestep,domain,stage,xmom,bed)
+
+
+def compute_fluxes_C_wellbalanced(domain):
+	from Numeric import zeros, Float
+	import sys
+
+	
+	timestep = float(sys.maxint)
+	epsilon = domain.epsilon
+	g = domain.g
+	neighbours = domain.neighbours
+	neighbour_vertices = domain.neighbour_vertices
+	normals = domain.normals
+	areas = domain.areas
+	stage_edge_values = domain.quantities['stage'].vertex_values
+	xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+	bed_edge_values = domain.quantities['elevation'].vertex_values
+	stage_boundary_values = domain.quantities['stage'].boundary_values
+	xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+	stage_explicit_update = domain.quantities['stage'].explicit_update
+	xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+	number_of_elements = len(stage_edge_values)
+	max_speed_array = domain.max_speed_array
+	        
+        from comp_flux_ext_wellbalanced import compute_fluxes_ext_wellbalanced  #from comp_flux_ext import compute_fluxes_ext
+	
+	domain.flux_timestep = compute_fluxes_ext_wellbalanced(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_edge_values,
+                                  xmom_edge_values,
+                                  bed_edge_values,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+# ###################################
+
+
+
+
+
+
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    protect_against_infinitesimal_and_negative_heights(domain)
+    
+
+    for name in domain.conserved_quantities:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            #print "add extrapolate second order to shallow water"
+            #if name != 'height':
+            Q.extrapolate_second_order()
+            #Q.limit()
+        else:
+            raise 'Unknown order'
+
+    
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+#    ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    zv = domain.quantities['elevation'].vertex_values
+    wv = domain.quantities['stage'].vertex_values
+    hv = wv-zv
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    #remove the above two lines and corresponding code below
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+                wv[k,0] = zv[k,0]
+                wv[k,1] = zv[k,1]
+                
+            xmomc[k] = 0.0
+            
+        
+    
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        #for i in range(3):
+        for i in range(2):   
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    #for i in range(3):
+    for i in range(2):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        #for i in range(3):
+        for i in range(2):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        #for i in range(3):
+        for i in range(2):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]))#,
+#                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        alpha  = 0.0
+	
+	if alpha < 1:
+
+            #for i in range(3):
+            for i in range(2):
+                wv[k,i] = zv[k,i] + (1.0-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+#            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+#           ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1.0-alpha)*xmomc[k] + alpha*xmomv[k,:]
+#            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+# ##############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        self.normals = domain.normals
+        self.stage   = domain.quantities['stage'].vertex_values
+        self.xmom    = domain.quantities['xmomentum'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        self.conserved_quantities = zeros(2, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+
+        q = self.conserved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = self.xmom[vol_id, edge_id]
+        normal = self.normals[vol_id,edge_id]
+
+        r = q
+        r[1] = normal*r[1]
+        r[1] = -r[1]
+        r[1] = normal*r[1]
+        q = r
+        #For start interval there is no outward momentum so do not need to
+        #reverse direction in this case
+
+        return q
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, conserved_quantities=None):
+        Boundary.__init__(self)
+
+        if conserved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.conserved_quantities=array(conserved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.conserved_quantities
+
+
+# ########################
+#Standard forcing terms:
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    stage = domain.quantities['stage'].explicit_update
+#    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    #h = Stage.edge_values - Elevation.edge_values
+    h = Stage.vertex_values - Elevation.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+#        avg_h = sum( h[k,:] )/3
+        avg_h = sum( h[k,:] )/2
+
+        #Compute bed slope
+        #x0, y0, x1, y1, x2, y2 = x[k,:]
+        x0, x1 = x[k,:]
+        #z0, z1, z2 = v[k,:]
+        b0, b1 = b[k,:]
+
+        w0, w1 = w[k,:]
+        wx = gradient(x0, x1, w0, w1)
+
+        #zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        xmom[k] += -g*bx*avg_h
+        #xmom[k] = -g*bx*avg_h
+        #stage[k] = 0.0
+ 
+ 
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_nonwellbalanced2.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_nonwellbalanced2.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_nonwellbalanced2.py	(revision 7576)
@@ -0,0 +1,1421 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+
+from domain import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['stage', 'xmomentum'] #['height', 'xmomentum']
+        evolved_quantities = ['stage', 'xmomentum', 'elevation', 'height', 'velocity']
+        other_quantities = ['friction']
+        Generic_Domain.__init__(self, coordinates, boundary,
+                                conserved_quantities, evolved_quantities, other_quantities,
+                                tagged_elements)
+        
+        from config import minimum_allowed_height, g, h0
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+        self.h0 = h0
+
+        #forcing terms not included in 1d domain ?WHy?
+        self.forcing_terms.append(gravity)
+        #self.forcing_terms.append(manning_friction)
+        #print "\nI have Removed forcing terms line 64 1dsw"
+
+        #Realtime visualisation
+        self.visualiser = None
+        self.visualise  = False
+        self.visualise_color_stage = False
+        self.visualise_stage_range = 1.0
+        self.visualise_timer = True
+        self.visualise_range_z = None
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        #Evolve parametrs
+        self.cfl = 1.0
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.quantities_to_be_stored = ['stage','xmomentum']
+
+	self.__doc__ = 'shallow_water_domain_suggestion2'
+	self.check_integrity()
+
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from realtime_visualisation_new import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+            self.visualiser.setup['elevation']=True
+            self.visualiser.updating['stage']=True
+        self.visualise = True
+        if self.visualise_color_stage == True:
+            self.visualiser.coloring['stage'] = True
+            self.visualiser.qcolor['stage'] = (0.0, 0.0, 0.8)
+        print 'initialise visualiser'
+        print self.visualiser.setup
+        print self.visualiser.updating
+
+    def check_integrity(self):
+        Generic_Domain.check_integrity(self)
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+		
+	msg = 'First evolved quantity must be "stage"'
+        assert self.evolved_quantities[0] == 'stage', msg
+        msg = 'Second evolved quantity must be "xmomentum"'
+        assert self.evolved_quantities[1] == 'xmomentum', msg
+        msg = 'Third evolved quantity must be "elevation"'
+        assert self.evolved_quantities[2] == 'elevation', msg
+        msg = 'Fourth evolved quantity must be "height"'
+        assert self.evolved_quantities[3] == 'height', msg
+        msg = 'Fifth evolved quantity must be "velocity"'
+        assert self.evolved_quantities[4] == 'velocity', msg
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes_C_nonwellbalanced2(self)
+
+    def compute_timestep(self):
+        #Call correct module function
+        compute_timestep(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+        
+    def evolve(self, yieldstep = None, finaltime = None, duration = None, skip_initial_step = False):
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime, duration, skip_initial_step):
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x and bed elevation
+        """
+
+        import data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+
+#Rotation of momentum vector
+def rotate(q, normal, direction = 1):
+    """Rotate the momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector.
+
+    If direction is negative the rotation is inverted.
+
+    Input vector is preserved
+
+    This function is specific to the shallow water wave equation
+    """
+
+    from Numeric import zeros, Float
+
+    assert len(q) == 3,\
+           'Vector of conserved quantities must have length 3'\
+           'for 2D shallow water equation'
+
+    try:
+        l = len(normal)
+    except:
+        raise 'Normal vector must be an Numeric array'
+
+    assert l == 2, 'Normal vector must have 2 components'
+
+
+    n1 = normal[0]
+    n2 = normal[1]
+
+    r = zeros(len(q), Float) #Rotated quantities
+    r[0] = q[0]              #First quantity, height, is not rotated
+
+    if direction == -1:
+        n2 = -n2
+
+
+    r[1] =  n1*q[1] + n2*q[2]
+    r[2] = -n2*q[1] + n1*q[2]
+
+    return r
+
+
+def flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon, h0
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+	
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/(h_left +  h0/h_left)
+
+
+    uh_left = u_left*h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/(h_right + h0/h_right)
+
+    uh_right = u_right*h_right
+	
+
+    #We have got h and u at vertex, then the following is the calculation of fluxes!
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+# 
+def compute_fluxes(domain):
+    """
+	Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    
+    """
+
+    import sys
+    from Numeric import zeros, Float
+    N = domain.number_of_elements
+    Stage = domain.quantities['stage']
+    Xmom  = domain.quantities['xmomentum']
+    Bed   = domain.quantities['elevation']
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    stage, xmom, bed, h_V, u_V = distribute_to_vertices_and_edges(domain)
+    domain.update_boundary()
+	
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            #ql[0] = stage[k, i]
+            #ql[1] = xmom[k, i]
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] = xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            #Flux computation using provided function
+     
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #print 'edgeflux', edgeflux
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        Stage.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k] =  flux[1]
+        #Ymom.explicit_update[k] = flux[2]
+        #print "flux cell",k,flux[0]
+
+    domain.flux_timestep = timestep
+    #print domain.quantities['stage'].centroid_values
+#
+def compute_timestep(domain):
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                qr[0] = stage[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #Update optimal_timestep
+            try:
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+    domain.timestep = timestep
+
+# Compute flux definition
+def compute_fluxes_C_long(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+    #print 'timestep=',timestep
+    #print 'The type of timestep is',type(timestep)
+	
+    epsilon = domain.epsilon
+    #print 'epsilon=',epsilon
+    #print 'The type of epsilon is',type(epsilon)
+	
+    g = domain.g
+    #print 'g=',g
+    #print 'The type of g is',type(g)
+	
+    neighbours = domain.neighbours
+    #print 'neighbours=',neighbours
+    #print 'The type of neighbours is',type(neighbours)
+	
+    neighbour_vertices = domain.neighbour_vertices
+    #print 'neighbour_vertices=',neighbour_vertices
+    #print 'The type of neighbour_vertices is',type(neighbour_vertices)
+	
+    normals = domain.normals
+    #print 'normals=',normals
+    #print 'The type of normals is',type(normals)
+	
+    areas = domain.areas
+    #print 'areas=',areas
+    #print 'The type of areas is',type(areas)
+	
+    stage_edge_values = domain.quantities['stage'].vertex_values
+    #print 'stage_edge_values=',stage_edge_values
+    #print 'The type of stage_edge_values is',type(stage_edge_values)
+	
+    xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+    #print 'xmom_edge_values=',xmom_edge_values
+    #print 'The type of xmom_edge_values is',type(xmom_edge_values)
+	
+    bed_edge_values = domain.quantities['elevation'].vertex_values
+    #print 'bed_edge_values=',bed_edge_values
+    #print 'The type of bed_edge_values is',type(bed_edge_values)
+	
+    stage_boundary_values = domain.quantities['stage'].boundary_values
+    #print 'stage_boundary_values=',stage_boundary_values
+    #print 'The type of stage_boundary_values is',type(stage_boundary_values)
+	
+    xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+    #print 'xmom_boundary_values=',xmom_boundary_values
+    #print 'The type of xmom_boundary_values is',type(xmom_boundary_values)
+	
+    stage_explicit_update = domain.quantities['stage'].explicit_update
+    #print 'stage_explicit_update=',stage_explicit_update
+    #print 'The type of stage_explicit_update is',type(stage_explicit_update)
+	
+    xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+    #print 'xmom_explicit_update=',xmom_explicit_update
+    #print 'The type of xmom_explicit_update is',type(xmom_explicit_update)
+	
+    number_of_elements = len(stage_edge_values)
+    #print 'number_of_elements=',number_of_elements
+    #print 'The type of number_of_elements is',type(number_of_elements)
+	
+    max_speed_array = domain.max_speed_array
+    #print 'max_speed_array=',max_speed_array
+    #print 'The type of max_speed_array is',type(max_speed_array)
+        
+        
+    from comp_flux_ext import compute_fluxes_ext
+	
+    domain.flux_timestep = compute_fluxes_ext(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_edge_values,
+                                  xmom_edge_values,
+                                  bed_edge_values,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+
+# Compute flux definition
+def compute_fluxes_C_short(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+
+    stage = domain.quantities['stage']
+    xmom = domain.quantities['xmomentum']
+    bed = domain.quantities['elevation']
+
+
+    from comp_flux_ext import compute_fluxes_ext_short
+
+    domain.flux_timestep = compute_fluxes_ext_short(timestep,domain,stage,xmom,bed)
+
+
+
+# ###################################
+def compute_fluxes_C_nonwellbalanced2(domain):
+    import sys
+    from Numeric import zeros, Float
+    
+    N = domain.number_of_elements
+    timestep = float(sys.maxint)
+    epsilon = domain.epsilon
+    g = domain.g
+    neighbours = domain.neighbours
+    neighbour_vertices = domain.neighbour_vertices
+    normals = domain.normals
+    areas = domain.areas
+    
+    Stage    = domain.quantities['stage']
+    Xmom     = domain.quantities['xmomentum']
+    Bed      = domain.quantities['elevation']
+    Height   = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+
+    stage_boundary_values = Stage.boundary_values
+    xmom_boundary_values  = Xmom.boundary_values
+    bed_boundary_values   = Bed.boundary_values
+    height_boundary_values= Height.boundary_values
+    vel_boundary_values   = Velocity.boundary_values
+    
+    stage_explicit_update = Stage.explicit_update
+    xmom_explicit_update  = Xmom.explicit_update
+    bed_explicit_values   = Bed.explicit_update
+    height_explicit_values= Height.explicit_update
+    vel_explicit_values   = Velocity.explicit_update
+    
+    max_speed_array = domain.max_speed_array
+   
+    domain.distribute_to_vertices_and_edges()
+    domain.update_boundary()
+    
+    stage_V = Stage.vertex_values
+    xmom_V  = Xmom.vertex_values
+    bed_V   = Bed.vertex_values
+    height_V= Height.vertex_values
+    vel_V   = Velocity.vertex_values
+
+    number_of_elements = len(stage_V)
+
+    #from config import epsilon, h0, h_min
+    # ##Check this:
+    #for i in range(N):
+    #    height_V[i] = stage_V[i] - bed_V[i]						
+    #    if height_V[i] <= h_min:  #epsilon :
+    #	    height_V[i] = 0.0
+    #	    stage_V[i]  = bed_V[i]
+    #	    xmom_V[i]   = 0.0
+    #	    vel_V[i]    = 0.0
+    #	else:
+    #        vel_V[i]  = xmom_V[i]/(height_V[i] +  h0/height_V[i])
+    # ##End of part to be checked.
+
+    
+    #print 'neighbours=',neighbours
+    #print 'neighbour_vertices',neighbour_vertices
+    #print 'stage vertices=', stage_V
+    #print 'bed vertices=', bed_V
+	
+    #from config import h_min
+    from comp_flux_ext_nonwellbalanced2 import compute_fluxes_ext_nonwellbalanced2
+    domain.flux_timestep = compute_fluxes_ext_nonwellbalanced2(timestep,
+                                  epsilon,
+                                  g,
+                                                           
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas,
+                                                           
+                                  stage_V,
+                                  xmom_V,
+                                  bed_V,
+                                  height_V,
+                                  vel_V,
+                                                           
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  bed_boundary_values,
+                                  height_boundary_values,
+                                  vel_boundary_values,
+                                                           
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  bed_explicit_values,
+                                  height_explicit_values,
+                                  vel_explicit_values,
+                                                           
+                                  number_of_elements,
+                                  max_speed_array)
+ 
+
+# ###################################
+
+
+
+
+
+
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    #protect_against_infinitesimal_and_negative_heights(domain)  
+
+    import sys
+    from Numeric import zeros, Float
+    from config import epsilon, h0, h_min
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    Height = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+    #Arrays   
+    w_C   = Stage.centroid_values    
+    uh_C  = Xmom.centroid_values    
+    z_C   = Bed.centroid_values 
+    h_C   = Height.centroid_values
+    u_C   = Velocity.centroid_values
+
+    for i in range(N):
+	h_C[i] = w_C[i] - z_C[i]						
+        if h_C[i] <= 0.01:  #epsilon :
+	    #h_C[i] = 0.0
+	    #w_C[i] = z_C[i]
+	    uh_C[i] = 0.0
+	    u_C[i] = 0.0
+	    
+	if h_C[i] < epsilon: #h_min:
+            h_C[i] = 0.0
+            w_C[i] = z_C[i]
+	else:
+            u_C[i]  = uh_C[i]/h_C[i] #+  h0/h_C[i])
+
+    for name in ['stage', 'height', 'velocity']:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            #print "add extrapolate second order to shallow water"
+            #if name != 'height':
+            Q.extrapolate_second_order()
+            #Q.limit()
+        else:
+            raise 'Unknown order'
+
+    stage_V = domain.quantities['stage'].vertex_values
+    bed_V   = domain.quantities['elevation'].vertex_values
+    h_V     = domain.quantities['height'].vertex_values
+    u_V     = domain.quantities['velocity'].vertex_values		
+    xmom_V  = domain.quantities['xmomentum'].vertex_values 
+
+    bed_V[:] = stage_V - h_V
+    xmom_V[:] = u_V * h_V
+    
+    return
+
+    
+#
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+#    ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    zv = domain.quantities['elevation'].vertex_values
+    wv = domain.quantities['stage'].vertex_values
+    hv = wv-zv
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    #remove the above two lines and corresponding code below
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+                wv[k,0] = zv[k,0]
+                wv[k,1] = zv[k,1]
+                
+            xmomc[k] = 0.0
+            
+        #N = domain.number_of_elements
+        #if (k == 0) | (k==N-1):
+        #    wc[k] = zc[k] # Contain 'lost mass' error
+        #    wv[k,0] = zv[k,0]
+        #    wv[k,1] = zv[k,1]
+    
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        #for i in range(3):
+        for i in range(2):   
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    #for i in range(3):
+    for i in range(2):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        #for i in range(3):
+        for i in range(2):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        #for i in range(3):
+        for i in range(2):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]))#,
+#                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using the h-limited
+        #stage and alpha==1 means using the w-limited stage as
+        #computed by the gradient limiter (both 1st or 2nd order)
+
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        alpha  = 0.0
+	#Let
+	#
+	#  wvi be the w-limited stage (wvi = zvi + hvi)
+	#  wvi- be the h-limited state (wvi- = zvi + hvi-)
+	#
+	#
+	#where i=0,1,2 denotes the vertex ids
+	#
+        #Weighted balance between w-limited and h-limited stage is
+        #
+	#  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+	#
+        #It follows that the updated wvi is
+        #  wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+        #
+	# Momentum is balanced between constant and limited
+
+
+        #for i in range(3):
+        #    wv[k,i] = zv[k,i] + hvbar[k,i]
+
+	#return
+
+	if alpha < 1:
+
+            #for i in range(3):
+            for i in range(2):
+                wv[k,i] = zv[k,i] + (1.0-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+#            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+#           ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1.0-alpha)*xmomc[k] + alpha*xmomv[k,:]
+#            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+###############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        #self.stage   = domain.quantities['stage'].edge_values
+        #self.xmom    = domain.quantities['xmomentum'].edge_values
+        #self.ymom    = domain.quantities['ymomentum'].edge_values
+        self.normals  = domain.normals
+        self.stage    = domain.quantities['stage'].vertex_values
+        self.xmom     = domain.quantities['xmomentum'].vertex_values
+        self.bed      = domain.quantities['elevation'].vertex_values
+        self.height   = domain.quantities['height'].vertex_values
+        self.velocity = domain.quantities['velocity'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        #self.conserved_quantities = zeros(2, Float)
+        self.evolved_quantities = zeros(5, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+    """
+    def evaluate(self, vol_id, edge_id):
+        #Reflective boundaries reverses the outward momentum
+        #of the volume they serve.
+        
+        #q = self.conserved_quantities
+        q = self.evolved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = self.xmom[vol_id, edge_id]
+        #q[2] = self.ymom[vol_id, edge_id]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+1]
+        normal = self.normals[vol_id,edge_id]
+
+        #r = rotate(q, normal, direction = 1)
+        #r[1] = -r[1]
+        #q = rotate(r, normal, direction = -1)
+        r = q
+        r[1] = normal*r[1]
+        r[1] = -r[1]
+        r[1] = normal*r[1]
+        q = r
+        #For start interval there is no outward momentum so do not need to
+        #reverse direction in this case
+
+        return q
+    """
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+        q = self.evolved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = -self.xmom[vol_id, edge_id]
+        q[2] = self.bed[vol_id, edge_id]
+        q[3] = self.height[vol_id, edge_id]
+        q[4] = -self.velocity[vol_id, edge_id]
+        return q
+
+
+    
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, conserved_quantities=None):
+        Boundary.__init__(self)
+
+        if conserved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.conserved_quantities=array(conserved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.conserved_quantities
+
+
+#########################
+#Standard forcing terms:
+#
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    stage = domain.quantities['stage'].explicit_update
+#    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    #h = Stage.edge_values - Elevation.edge_values
+    h = Stage.vertex_values - Elevation.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+#        avg_h = sum( h[k,:] )/3
+        avg_h = sum( h[k,:] )/2
+
+        #Compute bed slope
+        #x0, y0, x1, y1, x2, y2 = x[k,:]
+        x0, x1 = x[k,:]
+        #z0, z1, z2 = v[k,:]
+        b0, b1 = b[k,:]
+
+        w0, w1 = w[k,:]
+        wx = gradient(x0, x1, w0, w1)
+
+        #zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        xmom[k] += -g*bx*avg_h
+        #xmom[k] = -g*bx*avg_h
+        #stage[k] = 0.0
+ 
+ 
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    #vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    #ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	#S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+                S = -g * eta[k]**2 * uh[k]
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	#ymom_update[k] += S*vh[k]
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+#    vh = domain.quantities['ymomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+#    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g #Not necessary? Why was this added?
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+ #           	ymom_update[k] += S*vh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
+class Wind_stress:
+    """Apply wind stress to water momentum in terms of
+    wind speed [m/s] and wind direction [degrees]
+    """
+
+    def __init__(self, *args, **kwargs):
+        """Initialise windfield from wind speed s [m/s]
+        and wind direction phi [degrees]
+
+        Inputs v and phi can be either scalars or Python functions, e.g.
+
+        W = Wind_stress(10, 178)
+
+        #FIXME - 'normal' degrees are assumed for now, i.e. the
+        vector (1,0) has zero degrees.
+        We may need to convert from 'compass' degrees later on and also
+        map from True north to grid north.
+
+        Arguments can also be Python functions of t,x,y as in
+
+        def speed(t,x,y):
+            ...
+            return s
+
+        def angle(t,x,y):
+            ...
+            return phi
+
+        where x and y are vectors.
+
+        and then pass the functions in
+
+        W = Wind_stress(speed, angle)
+
+        The instantiated object W can be appended to the list of
+        forcing_terms as in
+
+        Alternatively, one vector valued function for (speed, angle)
+        can be applied, providing both quantities simultaneously.
+        As in
+        W = Wind_stress(F), where returns (speed, angle) for each t.
+
+        domain.forcing_terms.append(W)
+        """
+
+        from config import rho_a, rho_w, eta_w
+        from Numeric import array, Float
+
+        if len(args) == 2:
+            s = args[0]
+            phi = args[1]
+        elif len(args) == 1:
+            #Assume vector function returning (s, phi)(t,x,y)
+            vector_function = args[0]
+            #s = lambda t,x,y: vector_function(t,x=x,y=y)[0]
+            #phi = lambda t,x,y: vector_function(t,x=x,y=y)[1]
+            s = lambda t,x: vector_function(t,x=x)[0]
+            phi = lambda t,x: vector_function(t,x=x)[1]
+        else:
+           #Assume info is in 2 keyword arguments
+
+           if len(kwargs) == 2:
+               s = kwargs['s']
+               phi = kwargs['phi']
+           else:
+               raise 'Assumes two keyword arguments: s=..., phi=....'
+
+        print 'phi', phi
+        self.speed = check_forcefield(s)
+        self.phi = check_forcefield(phi)
+
+        self.const = eta_w*rho_a/rho_w
+
+
+    def __call__(self, domain):
+        """Evaluate windfield based on values found in domain
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import Float, ones, ArrayType
+
+        xmom_update = domain.quantities['xmomentum'].explicit_update
+        #ymom_update = domain.quantities['ymomentum'].explicit_update
+
+        N = domain.number_of_elements
+        t = domain.time
+
+        if callable(self.speed):
+            xc = domain.get_centroid_coordinates()
+            #s_vec = self.speed(t, xc[:,0], xc[:,1])
+            s_vec = self.speed(t, xc)
+        else:
+            #Assume s is a scalar
+
+            try:
+                s_vec = self.speed * ones(N, Float)
+            except:
+                msg = 'Speed must be either callable or a scalar: %s' %self.s
+                raise msg
+
+
+        if callable(self.phi):
+            xc = domain.get_centroid_coordinates()
+            #phi_vec = self.phi(t, xc[:,0], xc[:,1])
+            phi_vec = self.phi(t, xc)
+        else:
+            #Assume phi is a scalar
+
+            try:
+                phi_vec = self.phi * ones(N, Float)
+            except:
+                msg = 'Angle must be either callable or a scalar: %s' %self.phi
+                raise msg
+
+        #assign_windfield_values(xmom_update, ymom_update,
+        #                        s_vec, phi_vec, self.const)
+        assign_windfield_values(xmom_update, s_vec, phi_vec, self.const)
+
+
+#def assign_windfield_values(xmom_update, ymom_update,
+#                            s_vec, phi_vec, const):
+def assign_windfield_values(xmom_update, s_vec, phi_vec, const):
+    """Python version of assigning wind field to update vectors.
+    A c version also exists (for speed)
+    """
+    from math import pi, cos, sin, sqrt
+
+    N = len(s_vec)
+    for k in range(N):
+        s = s_vec[k]
+        phi = phi_vec[k]
+
+        #Convert to radians
+        phi = phi*pi/180
+
+        #Compute velocity vector (u, v)
+        u = s*cos(phi)
+        v = s*sin(phi)
+
+        #Compute wind stress
+        #S = const * sqrt(u**2 + v**2)
+        S = const * u
+        xmom_update[k] += S*u
+        #ymom_update[k] += S*v
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_nonwellbalanced3.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_nonwellbalanced3.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_nonwellbalanced3.py	(revision 7576)
@@ -0,0 +1,1416 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+
+from domain import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['stage', 'xmomentum']
+        evolved_quantities = ['stage', 'xmomentum', 'elevation', 'height', 'velocity']
+        other_quantities = ['friction']
+        Generic_Domain.__init__(self, coordinates, boundary,
+                                conserved_quantities, evolved_quantities, other_quantities,
+                                tagged_elements)
+        
+        from config import minimum_allowed_height, g, h0
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+        self.h0 = h0
+
+        #forcing terms not included in 1d domain ?WHy?
+        self.forcing_terms.append(gravity)
+        #self.forcing_terms.append(manning_friction)
+        #print "\nI have Removed forcing terms line 64 1dsw"
+
+        #Realtime visualisation
+        self.visualiser = None
+        self.visualise  = False
+        self.visualise_color_stage = False
+        self.visualise_stage_range = 1.0
+        self.visualise_timer = True
+        self.visualise_range_z = None
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        #Evolve parametrs
+        self.cfl = 1.0
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.quantities_to_be_stored = ['stage','xmomentum']
+
+	self.__doc__ = 'shallow_water_domain_suggestion2'
+	self.check_integrity()
+
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from realtime_visualisation_new import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+            self.visualiser.setup['elevation']=True
+            self.visualiser.updating['stage']=True
+        self.visualise = True
+        if self.visualise_color_stage == True:
+            self.visualiser.coloring['stage'] = True
+            self.visualiser.qcolor['stage'] = (0.0, 0.0, 0.8)
+        print 'initialise visualiser'
+        print self.visualiser.setup
+        print self.visualiser.updating
+
+    def check_integrity(self):
+        Generic_Domain.check_integrity(self)
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+		
+	msg = 'First evolved quantity must be "stage"'
+        assert self.evolved_quantities[0] == 'stage', msg
+        msg = 'Second evolved quantity must be "xmomentum"'
+        assert self.evolved_quantities[1] == 'xmomentum', msg
+        msg = 'Third evolved quantity must be "elevation"'
+        assert self.evolved_quantities[2] == 'elevation', msg
+        msg = 'Fourth evolved quantity must be "height"'
+        assert self.evolved_quantities[3] == 'height', msg
+        msg = 'Fifth evolved quantity must be "velocity"'
+        assert self.evolved_quantities[4] == 'velocity', msg
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes_C_nonwellbalanced3(self)
+
+    def compute_timestep(self):
+        #Call correct module function
+        compute_timestep(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+        
+    def evolve(self, yieldstep = None, finaltime = None, duration = None, skip_initial_step = False):
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime, duration, skip_initial_step):
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x and bed elevation
+        """
+
+        import data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+
+#Rotation of momentum vector
+def rotate(q, normal, direction = 1):
+    """Rotate the momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector.
+
+    If direction is negative the rotation is inverted.
+
+    Input vector is preserved
+
+    This function is specific to the shallow water wave equation
+    """
+
+    from Numeric import zeros, Float
+
+    assert len(q) == 3,\
+           'Vector of conserved quantities must have length 3'\
+           'for 2D shallow water equation'
+
+    try:
+        l = len(normal)
+    except:
+        raise 'Normal vector must be an Numeric array'
+
+    assert l == 2, 'Normal vector must have 2 components'
+
+
+    n1 = normal[0]
+    n2 = normal[1]
+
+    r = zeros(len(q), Float) #Rotated quantities
+    r[0] = q[0]              #First quantity, height, is not rotated
+
+    if direction == -1:
+        n2 = -n2
+
+
+    r[1] =  n1*q[1] + n2*q[2]
+    r[2] = -n2*q[1] + n1*q[2]
+
+    return r
+
+
+def flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon, h0
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+	
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/(h_left +  h0/h_left)
+
+
+    uh_left = u_left*h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/(h_right + h0/h_right)
+
+    uh_right = u_right*h_right
+	
+
+    #We have got h and u at vertex, then the following is the calculation of fluxes!
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+# 
+def compute_fluxes(domain):
+    """
+	Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    
+    """
+
+    import sys
+    from Numeric import zeros, Float
+    N = domain.number_of_elements
+    Stage = domain.quantities['stage']
+    Xmom  = domain.quantities['xmomentum']
+    Bed   = domain.quantities['elevation']
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    stage, xmom, bed, h_V, u_V = distribute_to_vertices_and_edges(domain)
+    domain.update_boundary()
+	
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            #ql[0] = stage[k, i]
+            #ql[1] = xmom[k, i]
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] = xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            #Flux computation using provided function
+     
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #print 'edgeflux', edgeflux
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        Stage.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k] =  flux[1]
+        #Ymom.explicit_update[k] = flux[2]
+        #print "flux cell",k,flux[0]
+
+    domain.flux_timestep = timestep
+    #print domain.quantities['stage'].centroid_values
+#
+def compute_timestep(domain):
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                qr[0] = stage[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #Update optimal_timestep
+            try:
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+    domain.timestep = timestep
+
+# Compute flux definition
+def compute_fluxes_C_long(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+    #print 'timestep=',timestep
+    #print 'The type of timestep is',type(timestep)
+	
+    epsilon = domain.epsilon
+    #print 'epsilon=',epsilon
+    #print 'The type of epsilon is',type(epsilon)
+	
+    g = domain.g
+    #print 'g=',g
+    #print 'The type of g is',type(g)
+	
+    neighbours = domain.neighbours
+    #print 'neighbours=',neighbours
+    #print 'The type of neighbours is',type(neighbours)
+	
+    neighbour_vertices = domain.neighbour_vertices
+    #print 'neighbour_vertices=',neighbour_vertices
+    #print 'The type of neighbour_vertices is',type(neighbour_vertices)
+	
+    normals = domain.normals
+    #print 'normals=',normals
+    #print 'The type of normals is',type(normals)
+	
+    areas = domain.areas
+    #print 'areas=',areas
+    #print 'The type of areas is',type(areas)
+	
+    stage_edge_values = domain.quantities['stage'].vertex_values
+    #print 'stage_edge_values=',stage_edge_values
+    #print 'The type of stage_edge_values is',type(stage_edge_values)
+	
+    xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+    #print 'xmom_edge_values=',xmom_edge_values
+    #print 'The type of xmom_edge_values is',type(xmom_edge_values)
+	
+    bed_edge_values = domain.quantities['elevation'].vertex_values
+    #print 'bed_edge_values=',bed_edge_values
+    #print 'The type of bed_edge_values is',type(bed_edge_values)
+	
+    stage_boundary_values = domain.quantities['stage'].boundary_values
+    #print 'stage_boundary_values=',stage_boundary_values
+    #print 'The type of stage_boundary_values is',type(stage_boundary_values)
+	
+    xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+    #print 'xmom_boundary_values=',xmom_boundary_values
+    #print 'The type of xmom_boundary_values is',type(xmom_boundary_values)
+	
+    stage_explicit_update = domain.quantities['stage'].explicit_update
+    #print 'stage_explicit_update=',stage_explicit_update
+    #print 'The type of stage_explicit_update is',type(stage_explicit_update)
+	
+    xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+    #print 'xmom_explicit_update=',xmom_explicit_update
+    #print 'The type of xmom_explicit_update is',type(xmom_explicit_update)
+	
+    number_of_elements = len(stage_edge_values)
+    #print 'number_of_elements=',number_of_elements
+    #print 'The type of number_of_elements is',type(number_of_elements)
+	
+    max_speed_array = domain.max_speed_array
+    #print 'max_speed_array=',max_speed_array
+    #print 'The type of max_speed_array is',type(max_speed_array)
+        
+        
+    from comp_flux_ext import compute_fluxes_ext
+	
+    domain.flux_timestep = compute_fluxes_ext(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_edge_values,
+                                  xmom_edge_values,
+                                  bed_edge_values,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+
+# Compute flux definition
+def compute_fluxes_C_short(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+
+    stage = domain.quantities['stage']
+    xmom = domain.quantities['xmomentum']
+    bed = domain.quantities['elevation']
+
+
+    from comp_flux_ext import compute_fluxes_ext_short
+
+    domain.flux_timestep = compute_fluxes_ext_short(timestep,domain,stage,xmom,bed)
+
+
+
+# ###################################
+def compute_fluxes_C_nonwellbalanced3(domain):
+    import sys
+    from Numeric import zeros, Float
+    
+    N = domain.number_of_elements
+    timestep = float(sys.maxint)
+    epsilon = domain.epsilon
+    g = domain.g
+    neighbours = domain.neighbours
+    neighbour_vertices = domain.neighbour_vertices
+    normals = domain.normals
+    areas = domain.areas
+    
+    Stage    = domain.quantities['stage']
+    Xmom     = domain.quantities['xmomentum']
+    Bed      = domain.quantities['elevation']
+    Height   = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+
+    stage_boundary_values = Stage.boundary_values
+    xmom_boundary_values  = Xmom.boundary_values
+    bed_boundary_values   = Bed.boundary_values
+    height_boundary_values= Height.boundary_values
+    vel_boundary_values   = Velocity.boundary_values
+    
+    stage_explicit_update = Stage.explicit_update
+    xmom_explicit_update  = Xmom.explicit_update
+    bed_explicit_values   = Bed.explicit_update
+    height_explicit_values= Height.explicit_update
+    vel_explicit_values   = Velocity.explicit_update
+    
+    max_speed_array = domain.max_speed_array
+   
+    domain.distribute_to_vertices_and_edges()
+    domain.update_boundary()
+    
+    stage_V = Stage.vertex_values
+    xmom_V  = Xmom.vertex_values
+    bed_V   = Bed.vertex_values
+    height_V= Height.vertex_values
+    vel_V   = Velocity.vertex_values
+
+    number_of_elements = len(stage_V)
+
+
+	
+    #from config import h_min
+    from comp_flux_ext_nonwellbalanced3 import compute_fluxes_ext_nonwellbalanced3
+    domain.flux_timestep = compute_fluxes_ext_nonwellbalanced3(timestep,
+                                  epsilon,
+                                  g,
+                                                           
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas,
+                                                           
+                                  stage_V,
+                                  xmom_V,
+                                  bed_V,
+                                  height_V,
+                                  vel_V,
+                                                           
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  bed_boundary_values,
+                                  height_boundary_values,
+                                  vel_boundary_values,
+                                                           
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  bed_explicit_values,
+                                  height_explicit_values,
+                                  vel_explicit_values,
+                                                           
+                                  number_of_elements,
+                                  max_speed_array)
+ 
+
+# ###################################
+
+
+
+
+
+
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    #protect_against_infinitesimal_and_negative_heights(domain)  
+
+    import sys
+    from Numeric import zeros, Float
+    from config import epsilon, h0, h_min
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    Height = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+    #Arrays   
+    w_C   = Stage.centroid_values    
+    uh_C  = Xmom.centroid_values    
+    z_C   = Bed.centroid_values 
+    h_C   = Height.centroid_values
+    u_C   = Velocity.centroid_values
+
+    for i in range(N):
+	h_C[i] = w_C[i] - z_C[i]						
+        if h_C[i] < epsilon : #0.01:
+	    #h_C[i] = 0.0
+	    #w_C[i] = z_C[i]
+	    uh_C[i] = 0.0
+	    u_C[i] = 0.0
+	    
+	if h_C[i] < epsilon:
+            h_C[i] = 0.0
+            w_C[i] = z_C[i]
+	else:
+            u_C[i]  = uh_C[i]/h_C[i] #+  h0/h_C[i])
+
+    for name in ['stage', 'elevation', 'velocity']:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            #print "add extrapolate second order to shallow water"
+            #if name != 'height':
+            Q.extrapolate_second_order()
+            #Q.limit()
+        else:
+            raise 'Unknown order'
+
+    stage_V = domain.quantities['stage'].vertex_values
+    bed_V   = domain.quantities['elevation'].vertex_values
+    h_V     = domain.quantities['height'].vertex_values
+    u_V     = domain.quantities['velocity'].vertex_values		
+    xmom_V  = domain.quantities['xmomentum'].vertex_values
+
+    i = 0
+    while i < len(stage_V.flat)-1:
+        if bed_V.flat[i] > stage_V.flat[i]: # & (bed_V.flat[i+1] < stage_V.flat[i+1]):
+            delta = bed_V.flat[i] - stage_V.flat[i]
+            bed_V.flat[i] = stage_V.flat[i]
+            bed_V.flat[i+1] = bed_V.flat[i+1] + delta
+        if bed_V.flat[i+1] > stage_V.flat[i+1]: #(bed_V.flat[i] < stage_V.flat[i]) & (bed_V.flat[i+1] > stage_V.flat[i+1]):
+            delta = bed_V.flat[i+1] - stage_V.flat[i+1]
+            bed_V.flat[i+1] = stage_V.flat[i+1]
+            bed_V.flat[i] = bed_V.flat[i] + delta
+        i= i+2
+    #print "stage_V.flat = ", stage_V.flat
+    #print "stage_V      = ", stage_V
+    h_V[:] = stage_V - bed_V
+    xmom_V[:] = u_V * h_V
+    
+    return
+
+    
+#
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+#    ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    zv = domain.quantities['elevation'].vertex_values
+    wv = domain.quantities['stage'].vertex_values
+    hv = wv-zv
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    #remove the above two lines and corresponding code below
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+                wv[k,0] = zv[k,0]
+                wv[k,1] = zv[k,1]
+                
+            xmomc[k] = 0.0
+            
+        #N = domain.number_of_elements
+        #if (k == 0) | (k==N-1):
+        #    wc[k] = zc[k] # Contain 'lost mass' error
+        #    wv[k,0] = zv[k,0]
+        #    wv[k,1] = zv[k,1]
+    
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        #for i in range(3):
+        for i in range(2):   
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    #for i in range(3):
+    for i in range(2):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        #for i in range(3):
+        for i in range(2):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        #for i in range(3):
+        for i in range(2):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]))#,
+#                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using the h-limited
+        #stage and alpha==1 means using the w-limited stage as
+        #computed by the gradient limiter (both 1st or 2nd order)
+
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        alpha  = 0.0
+	#Let
+	#
+	#  wvi be the w-limited stage (wvi = zvi + hvi)
+	#  wvi- be the h-limited state (wvi- = zvi + hvi-)
+	#
+	#
+	#where i=0,1,2 denotes the vertex ids
+	#
+        #Weighted balance between w-limited and h-limited stage is
+        #
+	#  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+	#
+        #It follows that the updated wvi is
+        #  wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+        #
+	# Momentum is balanced between constant and limited
+
+
+        #for i in range(3):
+        #    wv[k,i] = zv[k,i] + hvbar[k,i]
+
+	#return
+
+	if alpha < 1:
+
+            #for i in range(3):
+            for i in range(2):
+                wv[k,i] = zv[k,i] + (1.0-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+#            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+#           ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1.0-alpha)*xmomc[k] + alpha*xmomv[k,:]
+#            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+###############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        #self.stage   = domain.quantities['stage'].edge_values
+        #self.xmom    = domain.quantities['xmomentum'].edge_values
+        #self.ymom    = domain.quantities['ymomentum'].edge_values
+        self.normals  = domain.normals
+        self.stage    = domain.quantities['stage'].vertex_values
+        self.xmom     = domain.quantities['xmomentum'].vertex_values
+        self.bed      = domain.quantities['elevation'].vertex_values
+        self.height   = domain.quantities['height'].vertex_values
+        self.velocity = domain.quantities['velocity'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        #self.conserved_quantities = zeros(2, Float)
+        self.evolved_quantities = zeros(5, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+    """
+    def evaluate(self, vol_id, edge_id):
+        #Reflective boundaries reverses the outward momentum
+        #of the volume they serve.
+        
+        #q = self.conserved_quantities
+        q = self.evolved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = self.xmom[vol_id, edge_id]
+        #q[2] = self.ymom[vol_id, edge_id]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+1]
+        normal = self.normals[vol_id,edge_id]
+
+        #r = rotate(q, normal, direction = 1)
+        #r[1] = -r[1]
+        #q = rotate(r, normal, direction = -1)
+        r = q
+        r[1] = normal*r[1]
+        r[1] = -r[1]
+        r[1] = normal*r[1]
+        q = r
+        #For start interval there is no outward momentum so do not need to
+        #reverse direction in this case
+
+        return q
+    """
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+        q = self.evolved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = -self.xmom[vol_id, edge_id]
+        q[2] = self.bed[vol_id, edge_id]
+        q[3] = self.height[vol_id, edge_id]
+        q[4] = -self.velocity[vol_id, edge_id]
+        return q
+
+
+    
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, conserved_quantities=None):
+        Boundary.__init__(self)
+
+        if conserved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.conserved_quantities=array(conserved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.conserved_quantities
+
+
+#########################
+#Standard forcing terms:
+#
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    stage = domain.quantities['stage'].explicit_update
+#    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    #h = Stage.edge_values - Elevation.edge_values
+    h = Stage.vertex_values - Elevation.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+#        avg_h = sum( h[k,:] )/3
+        avg_h = sum( h[k,:] )/2
+
+        #Compute bed slope
+        #x0, y0, x1, y1, x2, y2 = x[k,:]
+        x0, x1 = x[k,:]
+        #z0, z1, z2 = v[k,:]
+        b0, b1 = b[k,:]
+
+        w0, w1 = w[k,:]
+        wx = gradient(x0, x1, w0, w1)
+
+        #zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        xmom[k] += -g*bx*avg_h
+        #xmom[k] = -g*bx*avg_h
+        #stage[k] = 0.0
+ 
+ 
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    #vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    #ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	#S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+                S = -g * eta[k]**2 * uh[k]
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	#ymom_update[k] += S*vh[k]
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+#    vh = domain.quantities['ymomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+#    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g #Not necessary? Why was this added?
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+ #           	ymom_update[k] += S*vh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
+class Wind_stress:
+    """Apply wind stress to water momentum in terms of
+    wind speed [m/s] and wind direction [degrees]
+    """
+
+    def __init__(self, *args, **kwargs):
+        """Initialise windfield from wind speed s [m/s]
+        and wind direction phi [degrees]
+
+        Inputs v and phi can be either scalars or Python functions, e.g.
+
+        W = Wind_stress(10, 178)
+
+        #FIXME - 'normal' degrees are assumed for now, i.e. the
+        vector (1,0) has zero degrees.
+        We may need to convert from 'compass' degrees later on and also
+        map from True north to grid north.
+
+        Arguments can also be Python functions of t,x,y as in
+
+        def speed(t,x,y):
+            ...
+            return s
+
+        def angle(t,x,y):
+            ...
+            return phi
+
+        where x and y are vectors.
+
+        and then pass the functions in
+
+        W = Wind_stress(speed, angle)
+
+        The instantiated object W can be appended to the list of
+        forcing_terms as in
+
+        Alternatively, one vector valued function for (speed, angle)
+        can be applied, providing both quantities simultaneously.
+        As in
+        W = Wind_stress(F), where returns (speed, angle) for each t.
+
+        domain.forcing_terms.append(W)
+        """
+
+        from config import rho_a, rho_w, eta_w
+        from Numeric import array, Float
+
+        if len(args) == 2:
+            s = args[0]
+            phi = args[1]
+        elif len(args) == 1:
+            #Assume vector function returning (s, phi)(t,x,y)
+            vector_function = args[0]
+            #s = lambda t,x,y: vector_function(t,x=x,y=y)[0]
+            #phi = lambda t,x,y: vector_function(t,x=x,y=y)[1]
+            s = lambda t,x: vector_function(t,x=x)[0]
+            phi = lambda t,x: vector_function(t,x=x)[1]
+        else:
+           #Assume info is in 2 keyword arguments
+
+           if len(kwargs) == 2:
+               s = kwargs['s']
+               phi = kwargs['phi']
+           else:
+               raise 'Assumes two keyword arguments: s=..., phi=....'
+
+        print 'phi', phi
+        self.speed = check_forcefield(s)
+        self.phi = check_forcefield(phi)
+
+        self.const = eta_w*rho_a/rho_w
+
+
+    def __call__(self, domain):
+        """Evaluate windfield based on values found in domain
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import Float, ones, ArrayType
+
+        xmom_update = domain.quantities['xmomentum'].explicit_update
+        #ymom_update = domain.quantities['ymomentum'].explicit_update
+
+        N = domain.number_of_elements
+        t = domain.time
+
+        if callable(self.speed):
+            xc = domain.get_centroid_coordinates()
+            #s_vec = self.speed(t, xc[:,0], xc[:,1])
+            s_vec = self.speed(t, xc)
+        else:
+            #Assume s is a scalar
+
+            try:
+                s_vec = self.speed * ones(N, Float)
+            except:
+                msg = 'Speed must be either callable or a scalar: %s' %self.s
+                raise msg
+
+
+        if callable(self.phi):
+            xc = domain.get_centroid_coordinates()
+            #phi_vec = self.phi(t, xc[:,0], xc[:,1])
+            phi_vec = self.phi(t, xc)
+        else:
+            #Assume phi is a scalar
+
+            try:
+                phi_vec = self.phi * ones(N, Float)
+            except:
+                msg = 'Angle must be either callable or a scalar: %s' %self.phi
+                raise msg
+
+        #assign_windfield_values(xmom_update, ymom_update,
+        #                        s_vec, phi_vec, self.const)
+        assign_windfield_values(xmom_update, s_vec, phi_vec, self.const)
+
+
+#def assign_windfield_values(xmom_update, ymom_update,
+#                            s_vec, phi_vec, const):
+def assign_windfield_values(xmom_update, s_vec, phi_vec, const):
+    """Python version of assigning wind field to update vectors.
+    A c version also exists (for speed)
+    """
+    from math import pi, cos, sin, sqrt
+
+    N = len(s_vec)
+    for k in range(N):
+        s = s_vec[k]
+        phi = phi_vec[k]
+
+        #Convert to radians
+        phi = phi*pi/180
+
+        #Compute velocity vector (u, v)
+        u = s*cos(phi)
+        v = s*sin(phi)
+
+        #Compute wind stress
+        #S = const * sqrt(u**2 + v**2)
+        S = const * u
+        xmom_update[k] += S*u
+        #ymom_update[k] += S*v
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_suggestion1.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_suggestion1.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_suggestion1.py	(revision 7576)
@@ -0,0 +1,1451 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+
+from domain import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['stage', 'xmomentum']
+        evolved_quantities = ['stage', 'xmomentum', 'elevation', 'height', 'velocity']
+        other_quantities = ['friction']
+        Generic_Domain.__init__(self,
+                                coordinates = coordinates,
+                                boundary = boundary,
+                                conserved_quantities = conserved_quantities,
+                                evolved_quantities = evolved_quantities,
+                                other_quantities = other_quantities,
+                                tagged_elements = tagged_elements)
+        
+        from config import minimum_allowed_height, g, h0, h_min
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+        self.h0 = h0
+        self.h_min = h_min
+
+        #forcing terms not included in 1d domain? Why?
+        self.forcing_terms.append(gravity)
+        #self.forcing_terms.append(manning_friction)
+        #print "\nI have Removed forcing terms line 64 1dsw"
+
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.set_quantities_to_be_stored(['stage','xmomentum'])
+
+	self.__doc__ = 'shallow_water_domain_suggestion1'
+
+        self.check_integrity()
+
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+    def check_integrity(self):
+
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+
+        msg = 'First evolved quantity must be "stage"'
+        assert self.evolved_quantities[0] == 'stage', msg
+        msg = 'Second evolved quantity must be "xmomentum"'
+        assert self.evolved_quantities[1] == 'xmomentum', msg
+        msg = 'Third evolved quantity must be "elevation"'
+        assert self.evolved_quantities[2] == 'elevation', msg
+        msg = 'Fourth evolved quantity must be "height"'
+        assert self.evolved_quantities[3] == 'height', msg
+        msg = 'Fifth evolved quantity must be "velocity"'
+        assert self.evolved_quantities[4] == 'velocity', msg
+
+        Generic_Domain.check_integrity(self)
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes_C_wellbalanced(self)
+
+    def compute_timestep(self):
+        #Call correct module function
+        compute_timestep(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+        
+    def evolve(self, yieldstep = None, finaltime = None, duration = None,
+               skip_initial_step = False):
+        """Specialisation of basic evolve method from parent class
+        """
+
+        #Call check integrity here rather than from user scripts
+        #self.check_integrity()
+
+        #msg = 'Parameter beta_h must be in the interval [0, 1)'
+        #assert 0 <= self.beta_h < 1.0, msg
+        #msg = 'Parameter beta_w must be in the interval [0, 1)'
+        #assert 0 <= self.beta_w < 1.0, msg
+
+
+        #Initial update of vertex and edge values before any storage
+        #and or visualisation
+        
+        #self.distribute_to_vertices_and_edges ?????????????????????????????????
+        
+        #Initialise real time viz if requested
+        #if self.visualise is True and self.time == 0.0:
+        #    if self.visualiser is None:
+        #        self.initialise_visualiser()
+        #
+        #    self.visualiser.update_timer()
+        #    self.visualiser.setup_all()
+
+        #Store model data, e.g. for visualisation
+        #if self.store is True and self.time == 0.0:
+        #    self.initialise_storage()
+        #    #print 'Storing results in ' + self.writer.filename
+        #else:
+        #    pass
+        #    #print 'Results will not be stored.'
+        #    #print 'To store results set domain.store = True'
+        #    #FIXME: Diagnostic output should be controlled by
+        #    # a 'verbose' flag living in domain (or in a parent class)
+
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime,duration,
+                                       skip_initial_step):
+            #Real time viz
+        #    if self.visualise is True:
+        #        self.visualiser.update_all()
+        #        self.visualiser.update_timer()
+
+
+            #Store model data, e.g. for subsequent visualisation
+        #    if self.store is True:
+        #        self.store_timestep(self.quantities_to_be_stored)
+
+            #FIXME: Could maybe be taken from specified list
+            #of 'store every step' quantities
+
+            #Pass control on to outer loop for more specific actions
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x and bed elevation
+        """
+
+        import data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+
+#Rotation of momentum vector
+def rotate(q, normal, direction = 1):
+    """Rotate the momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector.
+
+    If direction is negative the rotation is inverted.
+
+    Input vector is preserved
+
+    This function is specific to the shallow water wave equation
+    """
+
+    from Numeric import zeros, Float
+
+    assert len(q) == 3,\
+           'Vector of conserved quantities must have length 3'\
+           'for 2D shallow water equation'
+
+    try:
+        l = len(normal)
+    except:
+        raise 'Normal vector must be an Numeric array'
+
+    assert l == 2, 'Normal vector must have 2 components'
+
+
+    n1 = normal[0]
+    n2 = normal[1]
+
+    r = zeros(len(q), Float) #Rotated quantities
+    r[0] = q[0]              #First quantity, height, is not rotated
+
+    if direction == -1:
+        n2 = -n2
+
+
+    r[1] =  n1*q[1] + n2*q[2]
+    r[2] = -n2*q[1] + n1*q[2]
+
+    return r
+
+
+def flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon, h0
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+	
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/(h_left +  h0/h_left)
+
+
+    uh_left = u_left*h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/(h_right + h0/h_right)
+
+    uh_right = u_right*h_right
+	
+
+    #We have got h and u at vertex, then the following is the calculation of fluxes!
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+# 
+def compute_fluxes(domain):
+    """
+	Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+
+    domain.distribute_to_vertices_and_edges()
+    domain.update_boundary()
+    
+    N = domain.number_of_elements
+    Stage = domain.quantities['stage']
+    Xmom  = domain.quantities['xmomentum']
+    Bed   = domain.quantities['elevation']
+
+    stage = Stage.vertex_values
+    xmom  = Xmom.vertex_values
+    bed   = Bed.vertex_values
+    
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+
+	
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            #ql[0] = stage[k, i]
+            #ql[1] = xmom[k, i]
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] = xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            #Flux computation using provided function
+     
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #print 'edgeflux', edgeflux
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        Stage.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k] =  flux[1]
+        #Ymom.explicit_update[k] = flux[2]
+        #print "flux cell",k,flux[0]
+
+    domain.flux_timestep = timestep
+    #print domain.quantities['stage'].centroid_values
+#
+def compute_timestep(domain):
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                qr[0] = stage[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #Update optimal_timestep
+            try:
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+    domain.timestep = timestep
+
+# Compute flux definition
+def compute_fluxes_C_long(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+    #print 'timestep=',timestep
+    #print 'The type of timestep is',type(timestep)
+	
+    epsilon = domain.epsilon
+    #print 'epsilon=',epsilon
+    #print 'The type of epsilon is',type(epsilon)
+	
+    g = domain.g
+    #print 'g=',g
+    #print 'The type of g is',type(g)
+	
+    neighbours = domain.neighbours
+    #print 'neighbours=',neighbours
+    #print 'The type of neighbours is',type(neighbours)
+	
+    neighbour_vertices = domain.neighbour_vertices
+    #print 'neighbour_vertices=',neighbour_vertices
+    #print 'The type of neighbour_vertices is',type(neighbour_vertices)
+	
+    normals = domain.normals
+    #print 'normals=',normals
+    #print 'The type of normals is',type(normals)
+	
+    areas = domain.areas
+    #print 'areas=',areas
+    #print 'The type of areas is',type(areas)
+	
+    stage_edge_values = domain.quantities['stage'].vertex_values
+    #print 'stage_edge_values=',stage_edge_values
+    #print 'The type of stage_edge_values is',type(stage_edge_values)
+	
+    xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+    #print 'xmom_edge_values=',xmom_edge_values
+    #print 'The type of xmom_edge_values is',type(xmom_edge_values)
+	
+    bed_edge_values = domain.quantities['elevation'].vertex_values
+    #print 'bed_edge_values=',bed_edge_values
+    #print 'The type of bed_edge_values is',type(bed_edge_values)
+	
+    stage_boundary_values = domain.quantities['stage'].boundary_values
+    #print 'stage_boundary_values=',stage_boundary_values
+    #print 'The type of stage_boundary_values is',type(stage_boundary_values)
+	
+    xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+    #print 'xmom_boundary_values=',xmom_boundary_values
+    #print 'The type of xmom_boundary_values is',type(xmom_boundary_values)
+	
+    stage_explicit_update = domain.quantities['stage'].explicit_update
+    #print 'stage_explicit_update=',stage_explicit_update
+    #print 'The type of stage_explicit_update is',type(stage_explicit_update)
+	
+    xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+    #print 'xmom_explicit_update=',xmom_explicit_update
+    #print 'The type of xmom_explicit_update is',type(xmom_explicit_update)
+	
+    number_of_elements = len(stage_edge_values)
+    #print 'number_of_elements=',number_of_elements
+    #print 'The type of number_of_elements is',type(number_of_elements)
+	
+    max_speed_array = domain.max_speed_array
+    #print 'max_speed_array=',max_speed_array
+    #print 'The type of max_speed_array is',type(max_speed_array)
+        
+        
+    from comp_flux_ext import compute_fluxes_ext
+	
+    domain.flux_timestep = compute_fluxes_ext(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_edge_values,
+                                  xmom_edge_values,
+                                  bed_edge_values,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+
+# Compute flux definition
+def compute_fluxes_C_short(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+
+    stage = domain.quantities['stage']
+    xmom = domain.quantities['xmomentum']
+    bed = domain.quantities['elevation']
+
+
+    from comp_flux_ext import compute_fluxes_ext_short
+
+    domain.flux_timestep = compute_fluxes_ext_short(timestep,domain,stage,xmom,bed)
+
+
+
+# ###################################
+def compute_fluxes_C_wellbalanced(domain):
+    import sys
+    from Numeric import zeros, Float
+    
+    N = domain.number_of_elements
+    timestep = float(sys.maxint)
+    epsilon = domain.epsilon
+    g = domain.g
+    neighbours = domain.neighbours
+    neighbour_vertices = domain.neighbour_vertices
+    normals = domain.normals
+    areas = domain.areas
+    
+    Stage    = domain.quantities['stage']
+    Xmom     = domain.quantities['xmomentum']
+    Bed      = domain.quantities['elevation']
+    Height   = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+
+    stage_boundary_values = Stage.boundary_values
+    xmom_boundary_values  = Xmom.boundary_values
+    bed_boundary_values   = Bed.boundary_values
+    height_boundary_values= Height.boundary_values
+    vel_boundary_values   = Velocity.boundary_values
+    
+    stage_explicit_update = Stage.explicit_update
+    xmom_explicit_update  = Xmom.explicit_update
+    bed_explicit_values   = Bed.explicit_update
+    height_explicit_values= Height.explicit_update
+    vel_explicit_values   = Velocity.explicit_update
+    
+    max_speed_array = domain.max_speed_array
+   
+    domain.distribute_to_vertices_and_edges()
+    domain.update_boundary()
+    
+    stage_V = Stage.vertex_values
+    xmom_V  = Xmom.vertex_values
+    bed_V   = Bed.vertex_values
+    height_V= Height.vertex_values
+    vel_V   = Velocity.vertex_values
+
+    number_of_elements = len(stage_V)
+
+    #from config import epsilon, h0, h_min
+    # ##Check this:
+    #for i in range(N):
+    #    height_V[i] = stage_V[i] - bed_V[i]						
+    #    if height_V[i] <= h_min:  #epsilon :
+    #	    height_V[i] = 0.0
+    #	    stage_V[i]  = bed_V[i]
+    #	    xmom_V[i]   = 0.0
+    #	    vel_V[i]    = 0.0
+    #	else:
+    #        vel_V[i]  = xmom_V[i]/(height_V[i] +  h0/height_V[i])
+    # ##End of part to be checked.
+
+    
+    #print 'neighbours=',neighbours
+    #print 'neighbour_vertices',neighbour_vertices
+    #print 'stage vertices=', stage_V
+    #print 'bed vertices=', bed_V
+	
+    #from config import h_min
+    from comp_flux_ext_wellbalanced import compute_fluxes_ext_wellbalanced
+    domain.flux_timestep = compute_fluxes_ext_wellbalanced(timestep,
+                                  epsilon,
+                                  g,
+                                                           
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas,
+                                                           
+                                  stage_V,
+                                  xmom_V,
+                                  bed_V,
+                                  height_V,
+                                  vel_V,
+                                                           
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  bed_boundary_values,
+                                  height_boundary_values,
+                                  vel_boundary_values,
+                                                           
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  bed_explicit_values,
+                                  height_explicit_values,
+                                  vel_explicit_values,
+                                                           
+                                  number_of_elements,
+                                  max_speed_array)
+ 
+
+# ###################################
+
+
+
+
+
+
+
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    #protect_against_infinitesimal_and_negative_heights(domain)  
+
+    import sys
+    from Numeric import zeros, Float
+    from config import epsilon, h0, h_min
+	
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    Height = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+    #Arrays   
+    w_C   = Stage.centroid_values    
+    uh_C  = Xmom.centroid_values    
+    z_C   = Bed.centroid_values
+    h_C   = Height.centroid_values
+    u_C   = Velocity.centroid_values
+
+	
+    #print id(h_C)
+    for i in range(N):
+	h_C[i] = w_C[i] - z_C[i]						
+        if h_C[i] <= h_min:
+	    #print 'h_C[%d]= %15.5e\n' % (i,h_C[i])
+	    h_C[i] = 0.0
+	    w_C[i] = z_C[i]
+	    uh_C[i] = 0.0
+	    u_C[i] = 0.0
+	else:
+            u_C[i] = uh_C[i]/(h_C[i] + h0/h_C[i])
+		
+	
+    for name in [ 'stage', 'velocity']:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            #print "add extrapolate second order to shallow water"
+            #if name != 'height':
+            Q.extrapolate_second_order()
+            #Q.limit()
+        else:
+            raise 'Unknown order'
+
+    stage_V = domain.quantities['stage'].vertex_values			
+    bed_V   = domain.quantities['elevation'].vertex_values	
+    h_V    = domain.quantities['height'].vertex_values
+    u_V    = domain.quantities['velocity'].vertex_values		
+    xmom_V = domain.quantities['xmomentum'].vertex_values
+
+
+    h_V[:]    = stage_V - bed_V
+    for i in range(len(h_C)):
+        for j in range(2):
+            if h_V[i,j] < 0.0 :
+                #print 'h_V[%d,%d] = %f \n' % (i,j,h_V[i,j])                 
+                dh = h_V[i,j]
+                h_V[i,j] = 0.0
+                stage_V[i,j] = bed_V[i,j]
+                h_V[i,(j+1)%2] = h_V[i,(j+1)%2] + dh
+                stage_V[i,(j+1)%2] = stage_V[i,(j+1)%2] + dh
+
+          
+    xmom_V[:] = u_V * h_V
+    for i in range(len(h_V)):
+        if h_V[i] <= h_min:
+            u_V[i] = 0.0 
+    
+    return
+
+#
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+    #ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    zv = domain.quantities['elevation'].vertex_values
+    wv = domain.quantities['stage'].vertex_values
+    hv = wv-zv
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    #remove the above two lines and corresponding code below
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+                wv[k,0] = zv[k,0]
+                wv[k,1] = zv[k,1]
+                
+            xmomc[k] = 0.0
+            
+        #N = domain.number_of_elements
+        #if (k == 0) | (k==N-1):
+        #    wc[k] = zc[k] # Contain 'lost mass' error
+        #    wv[k,0] = zv[k,0]
+        #    wv[k,1] = zv[k,1]
+    
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        #for i in range(3):
+        for i in range(2):   
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    #for i in range(3):
+    for i in range(2):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        #for i in range(3):
+        for i in range(2):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        #for i in range(3):
+        for i in range(2):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]))#,
+#                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using the h-limited
+        #stage and alpha==1 means using the w-limited stage as
+        #computed by the gradient limiter (both 1st or 2nd order)
+
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        alpha  = 0.0
+	#Let
+	#
+	#  wvi be the w-limited stage (wvi = zvi + hvi)
+	#  wvi- be the h-limited state (wvi- = zvi + hvi-)
+	#
+	#
+	#where i=0,1,2 denotes the vertex ids
+	#
+        #Weighted balance between w-limited and h-limited stage is
+        #
+	#  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+	#
+        #It follows that the updated wvi is
+        #  wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+        #
+	# Momentum is balanced between constant and limited
+
+
+        #for i in range(3):
+        #    wv[k,i] = zv[k,i] + hvbar[k,i]
+
+	#return
+
+	if alpha < 1:
+
+            #for i in range(3):
+            for i in range(2):
+                wv[k,i] = zv[k,i] + (1.0-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+#            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+#           ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1.0-alpha)*xmomc[k] + alpha*xmomv[k,:]
+#            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+###############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        self.normals  = domain.normals
+        self.stage    = domain.quantities['stage'].vertex_values
+        self.xmom     = domain.quantities['xmomentum'].vertex_values
+        self.bed      = domain.quantities['elevation'].vertex_values
+        self.height   = domain.quantities['height'].vertex_values
+        self.velocity = domain.quantities['velocity'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        self.evolved_quantities = zeros(5, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+
+        q = self.evolved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = -self.xmom[vol_id, edge_id]
+        q[2] = self.bed[vol_id, edge_id]
+        q[3] = self.height[vol_id, edge_id]
+        q[1] = -self.velocity[vol_id, edge_id]
+
+
+        return q
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, evolved_quantities=None):
+        Boundary.__init__(self)
+
+        if evolved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.evolved_quantities=array(evolved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.evolved_quantities
+
+
+#########################
+#Standard forcing terms:
+#
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    stage = domain.quantities['stage'].explicit_update
+#    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    #h = Stage.edge_values - Elevation.edge_values
+    h = Stage.vertex_values - Elevation.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+#        avg_h = sum( h[k,:] )/3
+        avg_h = sum( h[k,:] )/2
+
+        #Compute bed slope
+        #x0, y0, x1, y1, x2, y2 = x[k,:]
+        x0, x1 = x[k,:]
+        #z0, z1, z2 = v[k,:]
+        b0, b1 = b[k,:]
+
+        w0, w1 = w[k,:]
+        wx = gradient(x0, x1, w0, w1)
+
+        #zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        xmom[k] += -g*bx*avg_h
+        #xmom[k] = -g*bx*avg_h
+        #stage[k] = 0.0
+ 
+ 
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    #vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    #ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	#S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+                S = -g * eta[k]**2 * uh[k]
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	#ymom_update[k] += S*vh[k]
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+#    vh = domain.quantities['ymomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+#    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g #Not necessary? Why was this added?
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+ #           	ymom_update[k] += S*vh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
+class Wind_stress:
+    """Apply wind stress to water momentum in terms of
+    wind speed [m/s] and wind direction [degrees]
+    """
+
+    def __init__(self, *args, **kwargs):
+        """Initialise windfield from wind speed s [m/s]
+        and wind direction phi [degrees]
+
+        Inputs v and phi can be either scalars or Python functions, e.g.
+
+        W = Wind_stress(10, 178)
+
+        #FIXME - 'normal' degrees are assumed for now, i.e. the
+        vector (1,0) has zero degrees.
+        We may need to convert from 'compass' degrees later on and also
+        map from True north to grid north.
+
+        Arguments can also be Python functions of t,x,y as in
+
+        def speed(t,x,y):
+            ...
+            return s
+
+        def angle(t,x,y):
+            ...
+            return phi
+
+        where x and y are vectors.
+
+        and then pass the functions in
+
+        W = Wind_stress(speed, angle)
+
+        The instantiated object W can be appended to the list of
+        forcing_terms as in
+
+        Alternatively, one vector valued function for (speed, angle)
+        can be applied, providing both quantities simultaneously.
+        As in
+        W = Wind_stress(F), where returns (speed, angle) for each t.
+
+        domain.forcing_terms.append(W)
+        """
+
+        from config import rho_a, rho_w, eta_w
+        from Numeric import array, Float
+
+        if len(args) == 2:
+            s = args[0]
+            phi = args[1]
+        elif len(args) == 1:
+            #Assume vector function returning (s, phi)(t,x,y)
+            vector_function = args[0]
+            #s = lambda t,x,y: vector_function(t,x=x,y=y)[0]
+            #phi = lambda t,x,y: vector_function(t,x=x,y=y)[1]
+            s = lambda t,x: vector_function(t,x=x)[0]
+            phi = lambda t,x: vector_function(t,x=x)[1]
+        else:
+           #Assume info is in 2 keyword arguments
+
+           if len(kwargs) == 2:
+               s = kwargs['s']
+               phi = kwargs['phi']
+           else:
+               raise 'Assumes two keyword arguments: s=..., phi=....'
+
+        print 'phi', phi
+        self.speed = check_forcefield(s)
+        self.phi = check_forcefield(phi)
+
+        self.const = eta_w*rho_a/rho_w
+
+
+    def __call__(self, domain):
+        """Evaluate windfield based on values found in domain
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import Float, ones, ArrayType
+
+        xmom_update = domain.quantities['xmomentum'].explicit_update
+        #ymom_update = domain.quantities['ymomentum'].explicit_update
+
+        N = domain.number_of_elements
+        t = domain.time
+
+        if callable(self.speed):
+            xc = domain.get_centroid_coordinates()
+            #s_vec = self.speed(t, xc[:,0], xc[:,1])
+            s_vec = self.speed(t, xc)
+        else:
+            #Assume s is a scalar
+
+            try:
+                s_vec = self.speed * ones(N, Float)
+            except:
+                msg = 'Speed must be either callable or a scalar: %s' %self.s
+                raise msg
+
+
+        if callable(self.phi):
+            xc = domain.get_centroid_coordinates()
+            #phi_vec = self.phi(t, xc[:,0], xc[:,1])
+            phi_vec = self.phi(t, xc)
+        else:
+            #Assume phi is a scalar
+
+            try:
+                phi_vec = self.phi * ones(N, Float)
+            except:
+                msg = 'Angle must be either callable or a scalar: %s' %self.phi
+                raise msg
+
+        #assign_windfield_values(xmom_update, ymom_update,
+        #                        s_vec, phi_vec, self.const)
+        assign_windfield_values(xmom_update, s_vec, phi_vec, self.const)
+
+
+#def assign_windfield_values(xmom_update, ymom_update,
+#                            s_vec, phi_vec, const):
+def assign_windfield_values(xmom_update, s_vec, phi_vec, const):
+    """Python version of assigning wind field to update vectors.
+    A c version also exists (for speed)
+    """
+    from math import pi, cos, sin, sqrt
+
+    N = len(s_vec)
+    for k in range(N):
+        s = s_vec[k]
+        phi = phi_vec[k]
+
+        #Convert to radians
+        phi = phi*pi/180
+
+        #Compute velocity vector (u, v)
+        u = s*cos(phi)
+        v = s*sin(phi)
+
+        #Compute wind stress
+        #S = const * sqrt(u**2 + v**2)
+        S = const * u
+        xmom_update[k] += S*u
+        #ymom_update[k] += S*v
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_suggestion1.py.bak
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_suggestion1.py.bak	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_suggestion1.py.bak	(revision 7576)
@@ -0,0 +1,1438 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+
+from domain import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['stage', 'xmomentum']
+        other_quantities = ['elevation', 'friction', 'height', 'velocity']
+        Generic_Domain.__init__(self, coordinates, boundary,
+                                conserved_quantities, other_quantities,
+                                tagged_elements)
+        
+        from config import minimum_allowed_height, g, h0
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+        self.h0 = h0
+
+        #forcing terms not included in 1d domain ?WHy?
+        self.forcing_terms.append(gravity)
+        #self.forcing_terms.append(manning_friction)
+        #print "\nI have Removed forcing terms line 64 1dsw"
+
+        #Realtime visualisation
+        self.visualiser = None
+        self.visualise  = False
+        self.visualise_color_stage = False
+        self.visualise_stage_range = 1.0
+        self.visualise_timer = True
+        self.visualise_range_z = None
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        #Evolve parametrs
+        self.cfl = 1.0
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.quantities_to_be_stored = ['stage','xmomentum']
+
+	self.__doc__ = 'shallow_water_domain'
+
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from realtime_visualisation_new import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+            self.visualiser.setup['elevation']=True
+            self.visualiser.updating['stage']=True
+        self.visualise = True
+        if self.visualise_color_stage == True:
+            self.visualiser.coloring['stage'] = True
+            self.visualiser.qcolor['stage'] = (0.0, 0.0, 0.8)
+        print 'initialise visualiser'
+        print self.visualiser.setup
+        print self.visualiser.updating
+
+    def check_integrity(self):
+        Generic_Domain.check_integrity(self)
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes_C_wellbalanced(self)
+
+    def compute_timestep(self):
+        #Call correct module function
+        compute_timestep(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+        
+    def evolve(self, yieldstep = None, finaltime = None, duration = None,
+               skip_initial_step = False):
+        """Specialisation of basic evolve method from parent class
+        """
+
+        #Call check integrity here rather than from user scripts
+        #self.check_integrity()
+
+        #msg = 'Parameter beta_h must be in the interval [0, 1)'
+        #assert 0 <= self.beta_h < 1.0, msg
+        #msg = 'Parameter beta_w must be in the interval [0, 1)'
+        #assert 0 <= self.beta_w < 1.0, msg
+
+
+        #Initial update of vertex and edge values before any storage
+        #and or visualisation
+        
+        #self.distribute_to_vertices_and_edges() ?????????????????????????????????
+        
+        #Initialise real time viz if requested
+        #if self.visualise is True and self.time == 0.0:
+        #    if self.visualiser is None:
+        #        self.initialise_visualiser()
+        #
+        #    self.visualiser.update_timer()
+        #    self.visualiser.setup_all()
+
+        #Store model data, e.g. for visualisation
+        #if self.store is True and self.time == 0.0:
+        #    self.initialise_storage()
+        #    #print 'Storing results in ' + self.writer.filename
+        #else:
+        #    pass
+        #    #print 'Results will not be stored.'
+        #    #print 'To store results set domain.store = True'
+        #    #FIXME: Diagnostic output should be controlled by
+        #    # a 'verbose' flag living in domain (or in a parent class)
+
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime,duration,
+                                       skip_initial_step):
+            #Real time viz
+        #    if self.visualise is True:
+        #        self.visualiser.update_all()
+        #        self.visualiser.update_timer()
+
+
+            #Store model data, e.g. for subsequent visualisation
+        #    if self.store is True:
+        #        self.store_timestep(self.quantities_to_be_stored)
+
+            #FIXME: Could maybe be taken from specified list
+            #of 'store every step' quantities
+
+            #Pass control on to outer loop for more specific actions
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x and bed elevation
+        """
+
+        import data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+
+#Rotation of momentum vector
+def rotate(q, normal, direction = 1):
+    """Rotate the momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector.
+
+    If direction is negative the rotation is inverted.
+
+    Input vector is preserved
+
+    This function is specific to the shallow water wave equation
+    """
+
+    from Numeric import zeros, Float
+
+    assert len(q) == 3,\
+           'Vector of conserved quantities must have length 3'\
+           'for 2D shallow water equation'
+
+    try:
+        l = len(normal)
+    except:
+        raise 'Normal vector must be an Numeric array'
+
+    assert l == 2, 'Normal vector must have 2 components'
+
+
+    n1 = normal[0]
+    n2 = normal[1]
+
+    r = zeros(len(q), Float) #Rotated quantities
+    r[0] = q[0]              #First quantity, height, is not rotated
+
+    if direction == -1:
+        n2 = -n2
+
+
+    r[1] =  n1*q[1] + n2*q[2]
+    r[2] = -n2*q[1] + n1*q[2]
+
+    return r
+
+
+def flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon, h0
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+	
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/(h_left +  h0/h_left)
+
+
+    uh_left = u_left*h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/(h_right + h0/h_right)
+
+    uh_right = u_right*h_right
+	
+
+    #We have got   h   and    u   at vertex, then  the following is the calculation of fluxes!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+# 
+def compute_fluxes(domain):
+    """
+	Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+
+    domain.distribute_to_vertices_and_edges()
+    domain.update_boundary()
+    
+    N = domain.number_of_elements
+    Stage = domain.quantities['stage']
+    Xmom  = domain.quantities['xmomentum']
+    Bed   = domain.quantities['elevation']
+
+    stage = Stage.vertex_values
+    xmom  = Xmom.vertex_values
+    bed   = Bed.vertex_values
+    
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+
+	
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            #ql[0] = stage[k, i]
+            #ql[1] = xmom[k, i]
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] = xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            #Flux computation using provided function
+     
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #print 'edgeflux', edgeflux
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        Stage.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k] =  flux[1]
+        #Ymom.explicit_update[k] = flux[2]
+        #print "flux cell",k,flux[0]
+
+    domain.flux_timestep = timestep
+    #print domain.quantities['stage'].centroid_values
+#
+def compute_timestep(domain):
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                qr[0] = stage[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #Update optimal_timestep
+            try:
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+    domain.timestep = timestep
+
+# Compute flux definition
+def compute_fluxes_C_long(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+    #print 'timestep=',timestep
+    #print 'The type of timestep is',type(timestep)
+	
+    epsilon = domain.epsilon
+    #print 'epsilon=',epsilon
+    #print 'The type of epsilon is',type(epsilon)
+	
+    g = domain.g
+    #print 'g=',g
+    #print 'The type of g is',type(g)
+	
+    neighbours = domain.neighbours
+    #print 'neighbours=',neighbours
+    #print 'The type of neighbours is',type(neighbours)
+	
+    neighbour_vertices = domain.neighbour_vertices
+    #print 'neighbour_vertices=',neighbour_vertices
+    #print 'The type of neighbour_vertices is',type(neighbour_vertices)
+	
+    normals = domain.normals
+    #print 'normals=',normals
+    #print 'The type of normals is',type(normals)
+	
+    areas = domain.areas
+    #print 'areas=',areas
+    #print 'The type of areas is',type(areas)
+	
+    stage_edge_values = domain.quantities['stage'].vertex_values
+    #print 'stage_edge_values=',stage_edge_values
+    #print 'The type of stage_edge_values is',type(stage_edge_values)
+	
+    xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+    #print 'xmom_edge_values=',xmom_edge_values
+    #print 'The type of xmom_edge_values is',type(xmom_edge_values)
+	
+    bed_edge_values = domain.quantities['elevation'].vertex_values
+    #print 'bed_edge_values=',bed_edge_values
+    #print 'The type of bed_edge_values is',type(bed_edge_values)
+	
+    stage_boundary_values = domain.quantities['stage'].boundary_values
+    #print 'stage_boundary_values=',stage_boundary_values
+    #print 'The type of stage_boundary_values is',type(stage_boundary_values)
+	
+    xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+    #print 'xmom_boundary_values=',xmom_boundary_values
+    #print 'The type of xmom_boundary_values is',type(xmom_boundary_values)
+	
+    stage_explicit_update = domain.quantities['stage'].explicit_update
+    #print 'stage_explicit_update=',stage_explicit_update
+    #print 'The type of stage_explicit_update is',type(stage_explicit_update)
+	
+    xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+    #print 'xmom_explicit_update=',xmom_explicit_update
+    #print 'The type of xmom_explicit_update is',type(xmom_explicit_update)
+	
+    number_of_elements = len(stage_edge_values)
+    #print 'number_of_elements=',number_of_elements
+    #print 'The type of number_of_elements is',type(number_of_elements)
+	
+    max_speed_array = domain.max_speed_array
+    #print 'max_speed_array=',max_speed_array
+    #print 'The type of max_speed_array is',type(max_speed_array)
+        
+        
+    from comp_flux_ext import compute_fluxes_ext
+	
+    domain.flux_timestep = compute_fluxes_ext(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_edge_values,
+                                  xmom_edge_values,
+                                  bed_edge_values,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+
+# Compute flux definition
+def compute_fluxes_C_short(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+
+    stage = domain.quantities['stage']
+    xmom = domain.quantities['xmomentum']
+    bed = domain.quantities['elevation']
+
+
+    from comp_flux_ext import compute_fluxes_ext_short
+
+    domain.flux_timestep = compute_fluxes_ext_short(timestep,domain,stage,xmom,bed)
+
+
+
+# ###################################
+def compute_fluxes_C_wellbalanced(domain):
+    #from Numeric import zeros, Float
+    #import sys
+
+	
+    #timestep = float(sys.maxint)
+    #epsilon = domain.epsilon
+    #g = domain.g
+    #neighbours = domain.neighbours
+    #neighbour_vertices = domain.neighbour_vertices
+    #normals = domain.normals
+    #areas = domain.areas
+    #stage_edge_values = domain.quantities['stage'].vertex_values
+    #xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+    #bed_edge_values = domain.quantities['elevation'].vertex_values
+    #stage_boundary_values = domain.quantities['stage'].boundary_values
+    #xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+    #stage_explicit_update = domain.quantities['stage'].explicit_update
+    #xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+    #number_of_elements = len(stage_edge_values)
+    #max_speed_array = domain.max_speed_array
+
+    import sys
+    from Numeric import zeros, Float
+    
+    N = domain.number_of_elements
+    timestep = float(sys.maxint)
+    epsilon = domain.epsilon
+    g = domain.g
+    neighbours = domain.neighbours
+    neighbour_vertices = domain.neighbour_vertices
+    normals = domain.normals
+    areas = domain.areas
+    
+    Stage = domain.quantities['stage']
+    Xmom  = domain.quantities['xmomentum']
+    Bed   = domain.quantities['elevation']
+
+    stage_boundary_values = Stage.boundary_values
+    xmom_boundary_values =  Xmom.boundary_values
+    stage_explicit_update = Stage.explicit_update
+    xmom_explicit_update = Xmom.explicit_update
+    max_speed_array = domain.max_speed_array
+    
+    domain.distribute_to_vertices_and_edges()
+    domain.update_boundary()
+    stage_V = Stage.vertex_values
+    xmom_V  = Xmom.vertex_values
+    bed_V   = Bed.vertex_values
+    #h_V     = Height.vertex_values
+    #u_V     = Velocity.vertex_values
+
+    number_of_elements = len(stage_V)
+
+    #flux = zeros(2, Float) #Work array for summing up fluxes
+    #ql = zeros(2, Float)
+    #qr = zeros(2, Float)
+	        
+    from comp_flux_ext_wellbalanced import compute_fluxes_ext_wellbalanced  #from comp_flux_ext import compute_fluxes_ext
+	
+    domain.flux_timestep = compute_fluxes_ext_wellbalanced(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_V,
+                                  xmom_V,
+                                  bed_V,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+# ###################################
+
+
+
+
+
+
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    #protect_against_infinitesimal_and_negative_heights(domain)  
+
+    import sys
+    from Numeric import zeros, Float
+    from config import epsilon, h0
+	
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    Height = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+    #Arrays   
+    w_C   = Stage.centroid_values    
+    uh_C  = Xmom.centroid_values    
+    z_C   = Bed.centroid_values
+    h_C   = Height.centroid_values
+    u_C   = Velocity.centroid_values
+	
+    #print id(h_C)
+    for i in range(N):
+	h_C[i] = w_C[i] - z_C[i]						#This is h at centroids:  OK
+        if h_C[i] < epsilon :
+	    #print 'h_C[%d]= %f\n' % (i,h_C[i])
+	    h_C[i] = 0.0
+	    w_C[i] = z_C[i]
+	    uh_C[i] = 0.0
+		
+    
+    for i in range(len(h_C)):
+	if h_C[i] < epsilon:
+	    u_C[i] = 0.0  #Could have been negative
+	    h_C[i] = 0.0
+	else:
+	    u_C[i]  = uh_C[i]/(h_C[i] +  h0/h_C[i])
+	
+    for name in [ 'velocity', 'stage' ]:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            #print "add extrapolate second order to shallow water"
+            #if name != 'height':
+            Q.extrapolate_second_order()
+            #Q.limit()
+        else:
+            raise 'Unknown order'
+
+    stage_V = domain.quantities['stage'].vertex_values			#This is w at vertices:   OK
+    bed_V   = domain.quantities['elevation'].vertex_values		#This is z at vertices:    OK
+    h_V    = domain.quantities['height'].vertex_values
+    u_V    = domain.quantities['velocity'].vertex_values		
+    xmom_V = domain.quantities['xmomentum'].vertex_values	
+	
+    h_V[:]    = stage_V - bed_V
+    for i in range(len(h_C)):
+        for j in range(2):
+            if h_V[i,j] < 0.0 :
+                #print 'h_V[%d,%d] = %f \n' % (i,j,h_V[i,j])                    # Check this!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+                h_V[i,j] = 0.0
+                stage_V[i,j] = bed_V[i,j]
+                
+    xmom_V[:] = u_V * h_V
+    
+    return
+#
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+#    ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    zv = domain.quantities['elevation'].vertex_values
+    wv = domain.quantities['stage'].vertex_values
+    hv = wv-zv
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    #remove the above two lines and corresponding code below
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+                wv[k,0] = zv[k,0]
+                wv[k,1] = zv[k,1]
+                
+            xmomc[k] = 0.0
+            
+        #N = domain.number_of_elements
+        #if (k == 0) | (k==N-1):
+        #    wc[k] = zc[k] # Contain 'lost mass' error
+        #    wv[k,0] = zv[k,0]
+        #    wv[k,1] = zv[k,1]
+    
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        #for i in range(3):
+        for i in range(2):   
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    #for i in range(3):
+    for i in range(2):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        #for i in range(3):
+        for i in range(2):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        #for i in range(3):
+        for i in range(2):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]))#,
+#                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using the h-limited
+        #stage and alpha==1 means using the w-limited stage as
+        #computed by the gradient limiter (both 1st or 2nd order)
+
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        alpha  = 0.0
+	#Let
+	#
+	#  wvi be the w-limited stage (wvi = zvi + hvi)
+	#  wvi- be the h-limited state (wvi- = zvi + hvi-)
+	#
+	#
+	#where i=0,1,2 denotes the vertex ids
+	#
+        #Weighted balance between w-limited and h-limited stage is
+        #
+	#  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+	#
+        #It follows that the updated wvi is
+        #  wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+        #
+	# Momentum is balanced between constant and limited
+
+
+        #for i in range(3):
+        #    wv[k,i] = zv[k,i] + hvbar[k,i]
+
+	#return
+
+	if alpha < 1:
+
+            #for i in range(3):
+            for i in range(2):
+                wv[k,i] = zv[k,i] + (1.0-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+#            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+#           ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1.0-alpha)*xmomc[k] + alpha*xmomv[k,:]
+#            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+###############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        #self.stage   = domain.quantities['stage'].edge_values
+        #self.xmom    = domain.quantities['xmomentum'].edge_values
+        #self.ymom    = domain.quantities['ymomentum'].edge_values
+        self.normals = domain.normals
+        self.stage   = domain.quantities['stage'].vertex_values
+        self.xmom    = domain.quantities['xmomentum'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        self.conserved_quantities = zeros(2, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+
+        q = self.conserved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = self.xmom[vol_id, edge_id]
+        #q[2] = self.ymom[vol_id, edge_id]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+1]
+        normal = self.normals[vol_id,edge_id]
+
+        #r = rotate(q, normal, direction = 1)
+        #r[1] = -r[1]
+        #q = rotate(r, normal, direction = -1)
+        r = q
+        r[1] = normal*r[1]
+        r[1] = -r[1]
+        r[1] = normal*r[1]
+        q = r
+        #For start interval there is no outward momentum so do not need to
+        #reverse direction in this case
+
+        return q
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, conserved_quantities=None):
+        Boundary.__init__(self)
+
+        if conserved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.conserved_quantities=array(conserved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.conserved_quantities
+
+
+#########################
+#Standard forcing terms:
+#
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    stage = domain.quantities['stage'].explicit_update
+#    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    #h = Stage.edge_values - Elevation.edge_values
+    h = Stage.vertex_values - Elevation.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+#        avg_h = sum( h[k,:] )/3
+        avg_h = sum( h[k,:] )/2
+
+        #Compute bed slope
+        #x0, y0, x1, y1, x2, y2 = x[k,:]
+        x0, x1 = x[k,:]
+        #z0, z1, z2 = v[k,:]
+        b0, b1 = b[k,:]
+
+        w0, w1 = w[k,:]
+        wx = gradient(x0, x1, w0, w1)
+
+        #zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        xmom[k] += -g*bx*avg_h
+        #xmom[k] = -g*bx*avg_h
+        #stage[k] = 0.0
+ 
+ 
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    #vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    #ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	#S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+                S = -g * eta[k]**2 * uh[k]
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	#ymom_update[k] += S*vh[k]
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+#    vh = domain.quantities['ymomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+#    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g #Not necessary? Why was this added?
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+ #           	ymom_update[k] += S*vh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
+class Wind_stress:
+    """Apply wind stress to water momentum in terms of
+    wind speed [m/s] and wind direction [degrees]
+    """
+
+    def __init__(self, *args, **kwargs):
+        """Initialise windfield from wind speed s [m/s]
+        and wind direction phi [degrees]
+
+        Inputs v and phi can be either scalars or Python functions, e.g.
+
+        W = Wind_stress(10, 178)
+
+        #FIXME - 'normal' degrees are assumed for now, i.e. the
+        vector (1,0) has zero degrees.
+        We may need to convert from 'compass' degrees later on and also
+        map from True north to grid north.
+
+        Arguments can also be Python functions of t,x,y as in
+
+        def speed(t,x,y):
+            ...
+            return s
+
+        def angle(t,x,y):
+            ...
+            return phi
+
+        where x and y are vectors.
+
+        and then pass the functions in
+
+        W = Wind_stress(speed, angle)
+
+        The instantiated object W can be appended to the list of
+        forcing_terms as in
+
+        Alternatively, one vector valued function for (speed, angle)
+        can be applied, providing both quantities simultaneously.
+        As in
+        W = Wind_stress(F), where returns (speed, angle) for each t.
+
+        domain.forcing_terms.append(W)
+        """
+
+        from config import rho_a, rho_w, eta_w
+        from Numeric import array, Float
+
+        if len(args) == 2:
+            s = args[0]
+            phi = args[1]
+        elif len(args) == 1:
+            #Assume vector function returning (s, phi)(t,x,y)
+            vector_function = args[0]
+            #s = lambda t,x,y: vector_function(t,x=x,y=y)[0]
+            #phi = lambda t,x,y: vector_function(t,x=x,y=y)[1]
+            s = lambda t,x: vector_function(t,x=x)[0]
+            phi = lambda t,x: vector_function(t,x=x)[1]
+        else:
+           #Assume info is in 2 keyword arguments
+
+           if len(kwargs) == 2:
+               s = kwargs['s']
+               phi = kwargs['phi']
+           else:
+               raise 'Assumes two keyword arguments: s=..., phi=....'
+
+        print 'phi', phi
+        self.speed = check_forcefield(s)
+        self.phi = check_forcefield(phi)
+
+        self.const = eta_w*rho_a/rho_w
+
+
+    def __call__(self, domain):
+        """Evaluate windfield based on values found in domain
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import Float, ones, ArrayType
+
+        xmom_update = domain.quantities['xmomentum'].explicit_update
+        #ymom_update = domain.quantities['ymomentum'].explicit_update
+
+        N = domain.number_of_elements
+        t = domain.time
+
+        if callable(self.speed):
+            xc = domain.get_centroid_coordinates()
+            #s_vec = self.speed(t, xc[:,0], xc[:,1])
+            s_vec = self.speed(t, xc)
+        else:
+            #Assume s is a scalar
+
+            try:
+                s_vec = self.speed * ones(N, Float)
+            except:
+                msg = 'Speed must be either callable or a scalar: %s' %self.s
+                raise msg
+
+
+        if callable(self.phi):
+            xc = domain.get_centroid_coordinates()
+            #phi_vec = self.phi(t, xc[:,0], xc[:,1])
+            phi_vec = self.phi(t, xc)
+        else:
+            #Assume phi is a scalar
+
+            try:
+                phi_vec = self.phi * ones(N, Float)
+            except:
+                msg = 'Angle must be either callable or a scalar: %s' %self.phi
+                raise msg
+
+        #assign_windfield_values(xmom_update, ymom_update,
+        #                        s_vec, phi_vec, self.const)
+        assign_windfield_values(xmom_update, s_vec, phi_vec, self.const)
+
+
+#def assign_windfield_values(xmom_update, ymom_update,
+#                            s_vec, phi_vec, const):
+def assign_windfield_values(xmom_update, s_vec, phi_vec, const):
+    """Python version of assigning wind field to update vectors.
+    A c version also exists (for speed)
+    """
+    from math import pi, cos, sin, sqrt
+
+    N = len(s_vec)
+    for k in range(N):
+        s = s_vec[k]
+        phi = phi_vec[k]
+
+        #Convert to radians
+        phi = phi*pi/180
+
+        #Compute velocity vector (u, v)
+        u = s*cos(phi)
+        v = s*sin(phi)
+
+        #Compute wind stress
+        #S = const * sqrt(u**2 + v**2)
+        S = const * u
+        xmom_update[k] += S*u
+        #ymom_update[k] += S*v
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_suggestion2.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_suggestion2.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_suggestion2.py	(revision 7576)
@@ -0,0 +1,1421 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+
+from domain import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['stage', 'xmomentum'] #['height', 'xmomentum']
+        evolved_quantities = ['stage', 'xmomentum', 'elevation', 'height', 'velocity']
+        other_quantities = ['friction']
+        Generic_Domain.__init__(self, coordinates, boundary,
+                                conserved_quantities, evolved_quantities, other_quantities,
+                                tagged_elements)
+        
+        from config import minimum_allowed_height, g, h0
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+        self.h0 = h0
+
+        #forcing terms not included in 1d domain ?WHy?
+        self.forcing_terms.append(gravity)
+        #self.forcing_terms.append(manning_friction)
+        #print "\nI have Removed forcing terms line 64 1dsw"
+
+        #Realtime visualisation
+        self.visualiser = None
+        self.visualise  = False
+        self.visualise_color_stage = False
+        self.visualise_stage_range = 1.0
+        self.visualise_timer = True
+        self.visualise_range_z = None
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        #Evolve parametrs
+        self.cfl = 1.0
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.quantities_to_be_stored = ['stage','xmomentum']
+
+	self.__doc__ = 'shallow_water_domain_suggestion2'
+	self.check_integrity()
+
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from realtime_visualisation_new import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+            self.visualiser.setup['elevation']=True
+            self.visualiser.updating['stage']=True
+        self.visualise = True
+        if self.visualise_color_stage == True:
+            self.visualiser.coloring['stage'] = True
+            self.visualiser.qcolor['stage'] = (0.0, 0.0, 0.8)
+        print 'initialise visualiser'
+        print self.visualiser.setup
+        print self.visualiser.updating
+
+    def check_integrity(self):
+        Generic_Domain.check_integrity(self)
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+		
+	msg = 'First evolved quantity must be "stage"'
+        assert self.evolved_quantities[0] == 'stage', msg
+        msg = 'Second evolved quantity must be "xmomentum"'
+        assert self.evolved_quantities[1] == 'xmomentum', msg
+        msg = 'Third evolved quantity must be "elevation"'
+        assert self.evolved_quantities[2] == 'elevation', msg
+        msg = 'Fourth evolved quantity must be "height"'
+        assert self.evolved_quantities[3] == 'height', msg
+        msg = 'Fifth evolved quantity must be "velocity"'
+        assert self.evolved_quantities[4] == 'velocity', msg
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes_C_wellbalanced(self)
+
+    def compute_timestep(self):
+        #Call correct module function
+        compute_timestep(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+        
+    def evolve(self, yieldstep = None, finaltime = None, duration = None, skip_initial_step = False):
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime, duration, skip_initial_step):
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x and bed elevation
+        """
+
+        import data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+
+#Rotation of momentum vector
+def rotate(q, normal, direction = 1):
+    """Rotate the momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector.
+
+    If direction is negative the rotation is inverted.
+
+    Input vector is preserved
+
+    This function is specific to the shallow water wave equation
+    """
+
+    from Numeric import zeros, Float
+
+    assert len(q) == 3,\
+           'Vector of conserved quantities must have length 3'\
+           'for 2D shallow water equation'
+
+    try:
+        l = len(normal)
+    except:
+        raise 'Normal vector must be an Numeric array'
+
+    assert l == 2, 'Normal vector must have 2 components'
+
+
+    n1 = normal[0]
+    n2 = normal[1]
+
+    r = zeros(len(q), Float) #Rotated quantities
+    r[0] = q[0]              #First quantity, height, is not rotated
+
+    if direction == -1:
+        n2 = -n2
+
+
+    r[1] =  n1*q[1] + n2*q[2]
+    r[2] = -n2*q[1] + n1*q[2]
+
+    return r
+
+
+def flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon, h0
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+	
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/(h_left +  h0/h_left)
+
+
+    uh_left = u_left*h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/(h_right + h0/h_right)
+
+    uh_right = u_right*h_right
+	
+
+    #We have got h and u at vertex, then the following is the calculation of fluxes!
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+# 
+def compute_fluxes(domain):
+    """
+	Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    
+    """
+
+    import sys
+    from Numeric import zeros, Float
+    N = domain.number_of_elements
+    Stage = domain.quantities['stage']
+    Xmom  = domain.quantities['xmomentum']
+    Bed   = domain.quantities['elevation']
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    stage, xmom, bed, h_V, u_V = distribute_to_vertices_and_edges(domain)
+    domain.update_boundary()
+	
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            #ql[0] = stage[k, i]
+            #ql[1] = xmom[k, i]
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] = xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            #Flux computation using provided function
+     
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #print 'edgeflux', edgeflux
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        Stage.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k] =  flux[1]
+        #Ymom.explicit_update[k] = flux[2]
+        #print "flux cell",k,flux[0]
+
+    domain.flux_timestep = timestep
+    #print domain.quantities['stage'].centroid_values
+#
+def compute_timestep(domain):
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                qr[0] = stage[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #Update optimal_timestep
+            try:
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+    domain.timestep = timestep
+
+# Compute flux definition
+def compute_fluxes_C_long(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+    #print 'timestep=',timestep
+    #print 'The type of timestep is',type(timestep)
+	
+    epsilon = domain.epsilon
+    #print 'epsilon=',epsilon
+    #print 'The type of epsilon is',type(epsilon)
+	
+    g = domain.g
+    #print 'g=',g
+    #print 'The type of g is',type(g)
+	
+    neighbours = domain.neighbours
+    #print 'neighbours=',neighbours
+    #print 'The type of neighbours is',type(neighbours)
+	
+    neighbour_vertices = domain.neighbour_vertices
+    #print 'neighbour_vertices=',neighbour_vertices
+    #print 'The type of neighbour_vertices is',type(neighbour_vertices)
+	
+    normals = domain.normals
+    #print 'normals=',normals
+    #print 'The type of normals is',type(normals)
+	
+    areas = domain.areas
+    #print 'areas=',areas
+    #print 'The type of areas is',type(areas)
+	
+    stage_edge_values = domain.quantities['stage'].vertex_values
+    #print 'stage_edge_values=',stage_edge_values
+    #print 'The type of stage_edge_values is',type(stage_edge_values)
+	
+    xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+    #print 'xmom_edge_values=',xmom_edge_values
+    #print 'The type of xmom_edge_values is',type(xmom_edge_values)
+	
+    bed_edge_values = domain.quantities['elevation'].vertex_values
+    #print 'bed_edge_values=',bed_edge_values
+    #print 'The type of bed_edge_values is',type(bed_edge_values)
+	
+    stage_boundary_values = domain.quantities['stage'].boundary_values
+    #print 'stage_boundary_values=',stage_boundary_values
+    #print 'The type of stage_boundary_values is',type(stage_boundary_values)
+	
+    xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+    #print 'xmom_boundary_values=',xmom_boundary_values
+    #print 'The type of xmom_boundary_values is',type(xmom_boundary_values)
+	
+    stage_explicit_update = domain.quantities['stage'].explicit_update
+    #print 'stage_explicit_update=',stage_explicit_update
+    #print 'The type of stage_explicit_update is',type(stage_explicit_update)
+	
+    xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+    #print 'xmom_explicit_update=',xmom_explicit_update
+    #print 'The type of xmom_explicit_update is',type(xmom_explicit_update)
+	
+    number_of_elements = len(stage_edge_values)
+    #print 'number_of_elements=',number_of_elements
+    #print 'The type of number_of_elements is',type(number_of_elements)
+	
+    max_speed_array = domain.max_speed_array
+    #print 'max_speed_array=',max_speed_array
+    #print 'The type of max_speed_array is',type(max_speed_array)
+        
+        
+    from comp_flux_ext import compute_fluxes_ext
+	
+    domain.flux_timestep = compute_fluxes_ext(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_edge_values,
+                                  xmom_edge_values,
+                                  bed_edge_values,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+
+# Compute flux definition
+def compute_fluxes_C_short(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+
+    stage = domain.quantities['stage']
+    xmom = domain.quantities['xmomentum']
+    bed = domain.quantities['elevation']
+
+
+    from comp_flux_ext import compute_fluxes_ext_short
+
+    domain.flux_timestep = compute_fluxes_ext_short(timestep,domain,stage,xmom,bed)
+
+
+
+# ###################################
+def compute_fluxes_C_wellbalanced(domain):
+    import sys
+    from Numeric import zeros, Float
+    
+    N = domain.number_of_elements
+    timestep = float(sys.maxint)
+    epsilon = domain.epsilon
+    g = domain.g
+    neighbours = domain.neighbours
+    neighbour_vertices = domain.neighbour_vertices
+    normals = domain.normals
+    areas = domain.areas
+    
+    Stage    = domain.quantities['stage']
+    Xmom     = domain.quantities['xmomentum']
+    Bed      = domain.quantities['elevation']
+    Height   = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+
+    stage_boundary_values = Stage.boundary_values
+    xmom_boundary_values  = Xmom.boundary_values
+    bed_boundary_values   = Bed.boundary_values
+    height_boundary_values= Height.boundary_values
+    vel_boundary_values   = Velocity.boundary_values
+    
+    stage_explicit_update = Stage.explicit_update
+    xmom_explicit_update  = Xmom.explicit_update
+    bed_explicit_values   = Bed.explicit_update
+    height_explicit_values= Height.explicit_update
+    vel_explicit_values   = Velocity.explicit_update
+    
+    max_speed_array = domain.max_speed_array
+   
+    domain.distribute_to_vertices_and_edges()
+    domain.update_boundary()
+    
+    stage_V = Stage.vertex_values
+    xmom_V  = Xmom.vertex_values
+    bed_V   = Bed.vertex_values
+    height_V= Height.vertex_values
+    vel_V   = Velocity.vertex_values
+
+    number_of_elements = len(stage_V)
+
+    #from config import epsilon, h0, h_min
+    # ##Check this:
+    #for i in range(N):
+    #    height_V[i] = stage_V[i] - bed_V[i]						
+    #    if height_V[i] <= h_min:  #epsilon :
+    #	    height_V[i] = 0.0
+    #	    stage_V[i]  = bed_V[i]
+    #	    xmom_V[i]   = 0.0
+    #	    vel_V[i]    = 0.0
+    #	else:
+    #        vel_V[i]  = xmom_V[i]/(height_V[i] +  h0/height_V[i])
+    # ##End of part to be checked.
+
+    
+    #print 'neighbours=',neighbours
+    #print 'neighbour_vertices',neighbour_vertices
+    #print 'stage vertices=', stage_V
+    #print 'bed vertices=', bed_V
+	
+    #from config import h_min
+    from comp_flux_ext_wellbalanced import compute_fluxes_ext_wellbalanced
+    domain.flux_timestep = compute_fluxes_ext_wellbalanced(timestep,
+                                  epsilon,
+                                  g,
+                                                           
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas,
+                                                           
+                                  stage_V,
+                                  xmom_V,
+                                  bed_V,
+                                  height_V,
+                                  vel_V,
+                                                           
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  bed_boundary_values,
+                                  height_boundary_values,
+                                  vel_boundary_values,
+                                                           
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  bed_explicit_values,
+                                  height_explicit_values,
+                                  vel_explicit_values,
+                                                           
+                                  number_of_elements,
+                                  max_speed_array)
+ 
+
+# ###################################
+
+
+
+
+
+
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    #protect_against_infinitesimal_and_negative_heights(domain)  
+
+    import sys
+    from Numeric import zeros, Float
+    from config import epsilon, h0, h_min
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    Height = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+    #Arrays   
+    w_C   = Stage.centroid_values    
+    uh_C  = Xmom.centroid_values    
+    z_C   = Bed.centroid_values 
+    h_C   = Height.centroid_values
+    u_C   = Velocity.centroid_values
+
+    for i in range(N):
+	h_C[i] = w_C[i] - z_C[i]						
+        if h_C[i] <= 0.01:  #epsilon :
+	    #h_C[i] = 0.0
+	    #w_C[i] = z_C[i]
+	    uh_C[i] = 0.0
+	    u_C[i] = 0.0
+	    
+	if h_C[i] < epsilon: #h_min:
+            h_C[i] = 0.0
+            w_C[i] = z_C[i]
+	else:
+            u_C[i]  = uh_C[i]/h_C[i] #+  h0/h_C[i])
+
+    for name in ['stage', 'height', 'velocity']:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            #print "add extrapolate second order to shallow water"
+            #if name != 'height':
+            Q.extrapolate_second_order()
+            #Q.limit()
+        else:
+            raise 'Unknown order'
+
+    stage_V = domain.quantities['stage'].vertex_values
+    bed_V   = domain.quantities['elevation'].vertex_values
+    h_V     = domain.quantities['height'].vertex_values
+    u_V     = domain.quantities['velocity'].vertex_values		
+    xmom_V  = domain.quantities['xmomentum'].vertex_values 
+
+    bed_V[:] = stage_V - h_V
+    xmom_V[:] = u_V * h_V
+    
+    return
+
+    
+#
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+#    ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    zv = domain.quantities['elevation'].vertex_values
+    wv = domain.quantities['stage'].vertex_values
+    hv = wv-zv
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    #remove the above two lines and corresponding code below
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+                wv[k,0] = zv[k,0]
+                wv[k,1] = zv[k,1]
+                
+            xmomc[k] = 0.0
+            
+        #N = domain.number_of_elements
+        #if (k == 0) | (k==N-1):
+        #    wc[k] = zc[k] # Contain 'lost mass' error
+        #    wv[k,0] = zv[k,0]
+        #    wv[k,1] = zv[k,1]
+    
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        #for i in range(3):
+        for i in range(2):   
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    #for i in range(3):
+    for i in range(2):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        #for i in range(3):
+        for i in range(2):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        #for i in range(3):
+        for i in range(2):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]))#,
+#                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using the h-limited
+        #stage and alpha==1 means using the w-limited stage as
+        #computed by the gradient limiter (both 1st or 2nd order)
+
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        alpha  = 0.0
+	#Let
+	#
+	#  wvi be the w-limited stage (wvi = zvi + hvi)
+	#  wvi- be the h-limited state (wvi- = zvi + hvi-)
+	#
+	#
+	#where i=0,1,2 denotes the vertex ids
+	#
+        #Weighted balance between w-limited and h-limited stage is
+        #
+	#  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+	#
+        #It follows that the updated wvi is
+        #  wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+        #
+	# Momentum is balanced between constant and limited
+
+
+        #for i in range(3):
+        #    wv[k,i] = zv[k,i] + hvbar[k,i]
+
+	#return
+
+	if alpha < 1:
+
+            #for i in range(3):
+            for i in range(2):
+                wv[k,i] = zv[k,i] + (1.0-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+#            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+#           ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1.0-alpha)*xmomc[k] + alpha*xmomv[k,:]
+#            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+###############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        #self.stage   = domain.quantities['stage'].edge_values
+        #self.xmom    = domain.quantities['xmomentum'].edge_values
+        #self.ymom    = domain.quantities['ymomentum'].edge_values
+        self.normals  = domain.normals
+        self.stage    = domain.quantities['stage'].vertex_values
+        self.xmom     = domain.quantities['xmomentum'].vertex_values
+        self.bed      = domain.quantities['elevation'].vertex_values
+        self.height   = domain.quantities['height'].vertex_values
+        self.velocity = domain.quantities['velocity'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        #self.conserved_quantities = zeros(2, Float)
+        self.evolved_quantities = zeros(5, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+    """
+    def evaluate(self, vol_id, edge_id):
+        #Reflective boundaries reverses the outward momentum
+        #of the volume they serve.
+        
+        #q = self.conserved_quantities
+        q = self.evolved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = self.xmom[vol_id, edge_id]
+        #q[2] = self.ymom[vol_id, edge_id]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+1]
+        normal = self.normals[vol_id,edge_id]
+
+        #r = rotate(q, normal, direction = 1)
+        #r[1] = -r[1]
+        #q = rotate(r, normal, direction = -1)
+        r = q
+        r[1] = normal*r[1]
+        r[1] = -r[1]
+        r[1] = normal*r[1]
+        q = r
+        #For start interval there is no outward momentum so do not need to
+        #reverse direction in this case
+
+        return q
+    """
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+        q = self.evolved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = -self.xmom[vol_id, edge_id]
+        q[2] = self.bed[vol_id, edge_id]
+        q[3] = self.height[vol_id, edge_id]
+        q[4] = -self.velocity[vol_id, edge_id]
+        return q
+
+
+    
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, conserved_quantities=None):
+        Boundary.__init__(self)
+
+        if conserved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.conserved_quantities=array(conserved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.conserved_quantities
+
+
+#########################
+#Standard forcing terms:
+#
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    stage = domain.quantities['stage'].explicit_update
+#    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    #h = Stage.edge_values - Elevation.edge_values
+    h = Stage.vertex_values - Elevation.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+#        avg_h = sum( h[k,:] )/3
+        avg_h = sum( h[k,:] )/2
+
+        #Compute bed slope
+        #x0, y0, x1, y1, x2, y2 = x[k,:]
+        x0, x1 = x[k,:]
+        #z0, z1, z2 = v[k,:]
+        b0, b1 = b[k,:]
+
+        w0, w1 = w[k,:]
+        wx = gradient(x0, x1, w0, w1)
+
+        #zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        xmom[k] += -g*bx*avg_h
+        #xmom[k] = -g*bx*avg_h
+        #stage[k] = 0.0
+ 
+ 
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    #vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    #ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	#S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+                S = -g * eta[k]**2 * uh[k]
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	#ymom_update[k] += S*vh[k]
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+#    vh = domain.quantities['ymomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+#    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g #Not necessary? Why was this added?
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+ #           	ymom_update[k] += S*vh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
+class Wind_stress:
+    """Apply wind stress to water momentum in terms of
+    wind speed [m/s] and wind direction [degrees]
+    """
+
+    def __init__(self, *args, **kwargs):
+        """Initialise windfield from wind speed s [m/s]
+        and wind direction phi [degrees]
+
+        Inputs v and phi can be either scalars or Python functions, e.g.
+
+        W = Wind_stress(10, 178)
+
+        #FIXME - 'normal' degrees are assumed for now, i.e. the
+        vector (1,0) has zero degrees.
+        We may need to convert from 'compass' degrees later on and also
+        map from True north to grid north.
+
+        Arguments can also be Python functions of t,x,y as in
+
+        def speed(t,x,y):
+            ...
+            return s
+
+        def angle(t,x,y):
+            ...
+            return phi
+
+        where x and y are vectors.
+
+        and then pass the functions in
+
+        W = Wind_stress(speed, angle)
+
+        The instantiated object W can be appended to the list of
+        forcing_terms as in
+
+        Alternatively, one vector valued function for (speed, angle)
+        can be applied, providing both quantities simultaneously.
+        As in
+        W = Wind_stress(F), where returns (speed, angle) for each t.
+
+        domain.forcing_terms.append(W)
+        """
+
+        from config import rho_a, rho_w, eta_w
+        from Numeric import array, Float
+
+        if len(args) == 2:
+            s = args[0]
+            phi = args[1]
+        elif len(args) == 1:
+            #Assume vector function returning (s, phi)(t,x,y)
+            vector_function = args[0]
+            #s = lambda t,x,y: vector_function(t,x=x,y=y)[0]
+            #phi = lambda t,x,y: vector_function(t,x=x,y=y)[1]
+            s = lambda t,x: vector_function(t,x=x)[0]
+            phi = lambda t,x: vector_function(t,x=x)[1]
+        else:
+           #Assume info is in 2 keyword arguments
+
+           if len(kwargs) == 2:
+               s = kwargs['s']
+               phi = kwargs['phi']
+           else:
+               raise 'Assumes two keyword arguments: s=..., phi=....'
+
+        print 'phi', phi
+        self.speed = check_forcefield(s)
+        self.phi = check_forcefield(phi)
+
+        self.const = eta_w*rho_a/rho_w
+
+
+    def __call__(self, domain):
+        """Evaluate windfield based on values found in domain
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import Float, ones, ArrayType
+
+        xmom_update = domain.quantities['xmomentum'].explicit_update
+        #ymom_update = domain.quantities['ymomentum'].explicit_update
+
+        N = domain.number_of_elements
+        t = domain.time
+
+        if callable(self.speed):
+            xc = domain.get_centroid_coordinates()
+            #s_vec = self.speed(t, xc[:,0], xc[:,1])
+            s_vec = self.speed(t, xc)
+        else:
+            #Assume s is a scalar
+
+            try:
+                s_vec = self.speed * ones(N, Float)
+            except:
+                msg = 'Speed must be either callable or a scalar: %s' %self.s
+                raise msg
+
+
+        if callable(self.phi):
+            xc = domain.get_centroid_coordinates()
+            #phi_vec = self.phi(t, xc[:,0], xc[:,1])
+            phi_vec = self.phi(t, xc)
+        else:
+            #Assume phi is a scalar
+
+            try:
+                phi_vec = self.phi * ones(N, Float)
+            except:
+                msg = 'Angle must be either callable or a scalar: %s' %self.phi
+                raise msg
+
+        #assign_windfield_values(xmom_update, ymom_update,
+        #                        s_vec, phi_vec, self.const)
+        assign_windfield_values(xmom_update, s_vec, phi_vec, self.const)
+
+
+#def assign_windfield_values(xmom_update, ymom_update,
+#                            s_vec, phi_vec, const):
+def assign_windfield_values(xmom_update, s_vec, phi_vec, const):
+    """Python version of assigning wind field to update vectors.
+    A c version also exists (for speed)
+    """
+    from math import pi, cos, sin, sqrt
+
+    N = len(s_vec)
+    for k in range(N):
+        s = s_vec[k]
+        phi = phi_vec[k]
+
+        #Convert to radians
+        phi = phi*pi/180
+
+        #Compute velocity vector (u, v)
+        u = s*cos(phi)
+        v = s*sin(phi)
+
+        #Compute wind stress
+        #S = const * sqrt(u**2 + v**2)
+        S = const * u
+        xmom_update[k] += S*u
+        #ymom_update[k] += S*v
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_suggestion3.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_suggestion3.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_domain_suggestion3.py	(revision 7576)
@@ -0,0 +1,1425 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+
+from domain import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['stage', 'xmomentum']
+        evolved_quantities = ['stage', 'xmomentum', 'elevation', 'height', 'velocity']
+        other_quantities = ['friction']
+        Generic_Domain.__init__(self, coordinates, boundary,
+                                conserved_quantities, evolved_quantities, other_quantities,
+                                tagged_elements)
+        
+        from config import minimum_allowed_height, g, h0
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+        self.h0 = h0
+
+        #forcing terms not included in 1d domain ?WHy?
+        self.forcing_terms.append(gravity)
+        #self.forcing_terms.append(manning_friction)
+        #print "\nI have Removed forcing terms line 64 1dsw"
+
+        #Realtime visualisation
+        self.visualiser = None
+        self.visualise  = False
+        self.visualise_color_stage = False
+        self.visualise_stage_range = 1.0
+        self.visualise_timer = True
+        self.visualise_range_z = None
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        #Evolve parametrs
+        self.cfl = 1.0
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.quantities_to_be_stored = ['stage','xmomentum']
+
+	self.__doc__ = 'shallow_water_domain_suggestion2'
+	self.check_integrity()
+
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from realtime_visualisation_new import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+            self.visualiser.setup['elevation']=True
+            self.visualiser.updating['stage']=True
+        self.visualise = True
+        if self.visualise_color_stage == True:
+            self.visualiser.coloring['stage'] = True
+            self.visualiser.qcolor['stage'] = (0.0, 0.0, 0.8)
+        print 'initialise visualiser'
+        print self.visualiser.setup
+        print self.visualiser.updating
+
+    def check_integrity(self):
+        Generic_Domain.check_integrity(self)
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+		
+	msg = 'First evolved quantity must be "stage"'
+        assert self.evolved_quantities[0] == 'stage', msg
+        msg = 'Second evolved quantity must be "xmomentum"'
+        assert self.evolved_quantities[1] == 'xmomentum', msg
+        msg = 'Third evolved quantity must be "elevation"'
+        assert self.evolved_quantities[2] == 'elevation', msg
+        msg = 'Fourth evolved quantity must be "height"'
+        assert self.evolved_quantities[3] == 'height', msg
+        msg = 'Fifth evolved quantity must be "velocity"'
+        assert self.evolved_quantities[4] == 'velocity', msg
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes_C_wellbalanced(self)
+
+    def compute_timestep(self):
+        #Call correct module function
+        compute_timestep(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+        
+    def evolve(self, yieldstep = None, finaltime = None, duration = None, skip_initial_step = False):
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime, duration, skip_initial_step):
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x and bed elevation
+        """
+
+        import data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+
+#Rotation of momentum vector
+def rotate(q, normal, direction = 1):
+    """Rotate the momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector.
+
+    If direction is negative the rotation is inverted.
+
+    Input vector is preserved
+
+    This function is specific to the shallow water wave equation
+    """
+
+    from Numeric import zeros, Float
+
+    assert len(q) == 3,\
+           'Vector of conserved quantities must have length 3'\
+           'for 2D shallow water equation'
+
+    try:
+        l = len(normal)
+    except:
+        raise 'Normal vector must be an Numeric array'
+
+    assert l == 2, 'Normal vector must have 2 components'
+
+
+    n1 = normal[0]
+    n2 = normal[1]
+
+    r = zeros(len(q), Float) #Rotated quantities
+    r[0] = q[0]              #First quantity, height, is not rotated
+
+    if direction == -1:
+        n2 = -n2
+
+
+    r[1] =  n1*q[1] + n2*q[2]
+    r[2] = -n2*q[1] + n1*q[2]
+
+    return r
+
+
+def flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon, h0
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+	
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/(h_left +  h0/h_left)
+
+
+    uh_left = u_left*h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/(h_right + h0/h_right)
+
+    uh_right = u_right*h_right
+	
+
+    #We have got h and u at vertex, then the following is the calculation of fluxes!
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+# 
+def compute_fluxes(domain):
+    """
+	Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    
+    """
+
+    import sys
+    from Numeric import zeros, Float
+    N = domain.number_of_elements
+    Stage = domain.quantities['stage']
+    Xmom  = domain.quantities['xmomentum']
+    Bed   = domain.quantities['elevation']
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    stage, xmom, bed, h_V, u_V = distribute_to_vertices_and_edges(domain)
+    domain.update_boundary()
+	
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            #ql[0] = stage[k, i]
+            #ql[1] = xmom[k, i]
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] = xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            #Flux computation using provided function
+     
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #print 'edgeflux', edgeflux
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        Stage.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k] =  flux[1]
+        #Ymom.explicit_update[k] = flux[2]
+        #print "flux cell",k,flux[0]
+
+    domain.flux_timestep = timestep
+    #print domain.quantities['stage'].centroid_values
+#
+def compute_timestep(domain):
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                qr[0] = stage[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #Update optimal_timestep
+            try:
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+    domain.timestep = timestep
+
+# Compute flux definition
+def compute_fluxes_C_long(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+    #print 'timestep=',timestep
+    #print 'The type of timestep is',type(timestep)
+	
+    epsilon = domain.epsilon
+    #print 'epsilon=',epsilon
+    #print 'The type of epsilon is',type(epsilon)
+	
+    g = domain.g
+    #print 'g=',g
+    #print 'The type of g is',type(g)
+	
+    neighbours = domain.neighbours
+    #print 'neighbours=',neighbours
+    #print 'The type of neighbours is',type(neighbours)
+	
+    neighbour_vertices = domain.neighbour_vertices
+    #print 'neighbour_vertices=',neighbour_vertices
+    #print 'The type of neighbour_vertices is',type(neighbour_vertices)
+	
+    normals = domain.normals
+    #print 'normals=',normals
+    #print 'The type of normals is',type(normals)
+	
+    areas = domain.areas
+    #print 'areas=',areas
+    #print 'The type of areas is',type(areas)
+	
+    stage_edge_values = domain.quantities['stage'].vertex_values
+    #print 'stage_edge_values=',stage_edge_values
+    #print 'The type of stage_edge_values is',type(stage_edge_values)
+	
+    xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+    #print 'xmom_edge_values=',xmom_edge_values
+    #print 'The type of xmom_edge_values is',type(xmom_edge_values)
+	
+    bed_edge_values = domain.quantities['elevation'].vertex_values
+    #print 'bed_edge_values=',bed_edge_values
+    #print 'The type of bed_edge_values is',type(bed_edge_values)
+	
+    stage_boundary_values = domain.quantities['stage'].boundary_values
+    #print 'stage_boundary_values=',stage_boundary_values
+    #print 'The type of stage_boundary_values is',type(stage_boundary_values)
+	
+    xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+    #print 'xmom_boundary_values=',xmom_boundary_values
+    #print 'The type of xmom_boundary_values is',type(xmom_boundary_values)
+	
+    stage_explicit_update = domain.quantities['stage'].explicit_update
+    #print 'stage_explicit_update=',stage_explicit_update
+    #print 'The type of stage_explicit_update is',type(stage_explicit_update)
+	
+    xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+    #print 'xmom_explicit_update=',xmom_explicit_update
+    #print 'The type of xmom_explicit_update is',type(xmom_explicit_update)
+	
+    number_of_elements = len(stage_edge_values)
+    #print 'number_of_elements=',number_of_elements
+    #print 'The type of number_of_elements is',type(number_of_elements)
+	
+    max_speed_array = domain.max_speed_array
+    #print 'max_speed_array=',max_speed_array
+    #print 'The type of max_speed_array is',type(max_speed_array)
+        
+        
+    from comp_flux_ext import compute_fluxes_ext
+	
+    domain.flux_timestep = compute_fluxes_ext(timestep,
+                                  epsilon,
+                                  g,
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas, 
+                                  stage_edge_values,
+                                  xmom_edge_values,
+                                  bed_edge_values,
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  number_of_elements,
+                                  max_speed_array)
+
+
+# Compute flux definition
+def compute_fluxes_C_short(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+
+    stage = domain.quantities['stage']
+    xmom = domain.quantities['xmomentum']
+    bed = domain.quantities['elevation']
+
+
+    from comp_flux_ext import compute_fluxes_ext_short
+
+    domain.flux_timestep = compute_fluxes_ext_short(timestep,domain,stage,xmom,bed)
+
+
+
+# ###################################
+def compute_fluxes_C_wellbalanced(domain):
+    import sys
+    from Numeric import zeros, Float
+    
+    N = domain.number_of_elements
+    timestep = float(sys.maxint)
+    epsilon = domain.epsilon
+    g = domain.g
+    neighbours = domain.neighbours
+    neighbour_vertices = domain.neighbour_vertices
+    normals = domain.normals
+    areas = domain.areas
+    
+    Stage    = domain.quantities['stage']
+    Xmom     = domain.quantities['xmomentum']
+    Bed      = domain.quantities['elevation']
+    Height   = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+
+    stage_boundary_values = Stage.boundary_values
+    xmom_boundary_values  = Xmom.boundary_values
+    bed_boundary_values   = Bed.boundary_values
+    height_boundary_values= Height.boundary_values
+    vel_boundary_values   = Velocity.boundary_values
+    
+    stage_explicit_update = Stage.explicit_update
+    xmom_explicit_update  = Xmom.explicit_update
+    bed_explicit_values   = Bed.explicit_update
+    height_explicit_values= Height.explicit_update
+    vel_explicit_values   = Velocity.explicit_update
+    
+    max_speed_array = domain.max_speed_array
+   
+    domain.distribute_to_vertices_and_edges()
+    domain.update_boundary()
+    
+    stage_V = Stage.vertex_values
+    xmom_V  = Xmom.vertex_values
+    bed_V   = Bed.vertex_values
+    height_V= Height.vertex_values
+    vel_V   = Velocity.vertex_values
+
+    number_of_elements = len(stage_V)
+
+    from config import epsilon, h0, h_min
+    #for i in range(N):
+    #    height_V[i] = stage_V[i] - bed_V[i]						
+    #    if height_V[i] <= h_min:  #epsilon :
+    #	    height_V[i] = 0.0
+    #	    stage_V[i]  = bed_V[i]
+    #	    xmom_V[i]   = 0.0
+    #	    vel_V[i]    = 0.0
+    #	else:
+    #        vel_V[i]  = xmom_V[i]/(height_V[i] +  h0/height_V[i])
+
+	
+    from comp_flux_ext_wellbalanced import compute_fluxes_ext_wellbalanced
+    domain.flux_timestep = compute_fluxes_ext_wellbalanced(timestep,
+                                  epsilon,
+                                  g,
+                                                           
+                                  neighbours,
+                                  neighbour_vertices,
+                                  normals,
+                                  areas,
+                                                           
+                                  stage_V,
+                                  xmom_V,
+                                  bed_V,
+                                  height_V,
+                                  vel_V,
+                                                           
+                                  stage_boundary_values,
+                                  xmom_boundary_values,
+                                  bed_boundary_values,
+                                  height_boundary_values,
+                                  vel_boundary_values,
+                                                           
+                                  stage_explicit_update,
+                                  xmom_explicit_update,
+                                  bed_explicit_values,
+                                  height_explicit_values,
+                                  vel_explicit_values,
+                                                           
+                                  number_of_elements,
+                                  max_speed_array)
+ 
+
+# ###################################
+
+
+
+
+
+
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    #protect_against_infinitesimal_and_negative_heights(domain)  
+
+    import sys
+    from Numeric import zeros, Float
+    from config import epsilon, h0, h_min
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    Height = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+    #Arrays   
+    w_C   = Stage.centroid_values    
+    uh_C  = Xmom.centroid_values    
+    z_C   = Bed.centroid_values 
+    h_C   = Height.centroid_values
+    u_C   = Velocity.centroid_values
+
+    for i in range(N):
+	h_C[i] = w_C[i] - z_C[i]						
+        if h_C[i] < epsilon : #0.01:
+	    #h_C[i] = 0.0
+	    #w_C[i] = z_C[i]
+	    uh_C[i] = 0.0
+	    u_C[i] = 0.0
+	    
+	if h_C[i] < epsilon:
+            h_C[i] = 0.0
+            w_C[i] = z_C[i]
+	else:
+            u_C[i]  = uh_C[i]/h_C[i] #+  h0/h_C[i])
+
+    for name in ['stage', 'elevation', 'velocity']:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            #print "add extrapolate second order to shallow water"
+            #if name != 'height':
+            Q.extrapolate_second_order()
+            #Q.limit()
+        else:
+            raise 'Unknown order'
+
+    stage_V = domain.quantities['stage'].vertex_values
+    bed_V   = domain.quantities['elevation'].vertex_values
+    h_V     = domain.quantities['height'].vertex_values
+    u_V     = domain.quantities['velocity'].vertex_values		
+    xmom_V  = domain.quantities['xmomentum'].vertex_values
+
+    i = 0
+    while i < len(stage_V.flat)-1:
+        if bed_V.flat[i] > stage_V.flat[i]: # & (bed_V.flat[i+1] < stage_V.flat[i+1]):
+            delta = bed_V.flat[i] - stage_V.flat[i]
+            bed_V.flat[i] = stage_V.flat[i]
+            bed_V.flat[i+1] = bed_V.flat[i+1] + delta
+        if bed_V.flat[i+1] > stage_V.flat[i+1]: #(bed_V.flat[i] < stage_V.flat[i]) & (bed_V.flat[i+1] > stage_V.flat[i+1]):
+            delta = bed_V.flat[i+1] - stage_V.flat[i+1]
+            bed_V.flat[i+1] = stage_V.flat[i+1]
+            bed_V.flat[i] = bed_V.flat[i] + delta
+        i= i+2
+    #print "stage_V.flat = ", stage_V.flat
+    #print "stage_V      = ", stage_V
+    h_V[:] = stage_V - bed_V
+    xmom_V[:] = u_V * h_V
+    
+    return
+
+    
+#
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+#    ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    zv = domain.quantities['elevation'].vertex_values
+    wv = domain.quantities['stage'].vertex_values
+    hv = wv-zv
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    #remove the above two lines and corresponding code below
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+                wv[k,0] = zv[k,0]
+                wv[k,1] = zv[k,1]
+                
+            xmomc[k] = 0.0
+            
+        #N = domain.number_of_elements
+        #if (k == 0) | (k==N-1):
+        #    wc[k] = zc[k] # Contain 'lost mass' error
+        #    wv[k,0] = zv[k,0]
+        #    wv[k,1] = zv[k,1]
+    
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        #for i in range(3):
+        for i in range(2):   
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    #for i in range(3):
+    for i in range(2):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        #for i in range(3):
+        for i in range(2):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        #for i in range(3):
+        for i in range(2):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]))#,
+#                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using the h-limited
+        #stage and alpha==1 means using the w-limited stage as
+        #computed by the gradient limiter (both 1st or 2nd order)
+
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        alpha  = 0.0
+	#Let
+	#
+	#  wvi be the w-limited stage (wvi = zvi + hvi)
+	#  wvi- be the h-limited state (wvi- = zvi + hvi-)
+	#
+	#
+	#where i=0,1,2 denotes the vertex ids
+	#
+        #Weighted balance between w-limited and h-limited stage is
+        #
+	#  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+	#
+        #It follows that the updated wvi is
+        #  wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+        #
+	# Momentum is balanced between constant and limited
+
+
+        #for i in range(3):
+        #    wv[k,i] = zv[k,i] + hvbar[k,i]
+
+	#return
+
+	if alpha < 1:
+
+            #for i in range(3):
+            for i in range(2):
+                wv[k,i] = zv[k,i] + (1.0-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+#            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+#           ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1.0-alpha)*xmomc[k] + alpha*xmomv[k,:]
+#            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+###############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        #self.stage   = domain.quantities['stage'].edge_values
+        #self.xmom    = domain.quantities['xmomentum'].edge_values
+        #self.ymom    = domain.quantities['ymomentum'].edge_values
+        self.normals  = domain.normals
+        self.stage    = domain.quantities['stage'].vertex_values
+        self.xmom     = domain.quantities['xmomentum'].vertex_values
+        self.bed      = domain.quantities['elevation'].vertex_values
+        self.height   = domain.quantities['height'].vertex_values
+        self.velocity = domain.quantities['velocity'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        #self.conserved_quantities = zeros(2, Float)
+        self.evolved_quantities = zeros(5, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+    """
+    def evaluate(self, vol_id, edge_id):
+        #Reflective boundaries reverses the outward momentum
+        #of the volume they serve.
+        
+        #q = self.conserved_quantities
+        q = self.evolved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = self.xmom[vol_id, edge_id]
+        #q[2] = self.ymom[vol_id, edge_id]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+1]
+        normal = self.normals[vol_id,edge_id]
+
+        #r = rotate(q, normal, direction = 1)
+        #r[1] = -r[1]
+        #q = rotate(r, normal, direction = -1)
+        r = q
+        r[1] = normal*r[1]
+        r[1] = -r[1]
+        r[1] = normal*r[1]
+        q = r
+        #For start interval there is no outward momentum so do not need to
+        #reverse direction in this case
+
+        return q
+    """
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+        q = self.evolved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = -self.xmom[vol_id, edge_id]
+        q[2] = self.bed[vol_id, edge_id]
+        q[3] = self.height[vol_id, edge_id]
+        q[4] = -self.velocity[vol_id, edge_id]
+        return q
+
+
+    
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, conserved_quantities=None):
+        Boundary.__init__(self)
+
+        if conserved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.conserved_quantities=array(conserved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.conserved_quantities
+
+
+#########################
+#Standard forcing terms:
+#
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    stage = domain.quantities['stage'].explicit_update
+#    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    #h = Stage.edge_values - Elevation.edge_values
+    h = Stage.vertex_values - Elevation.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+#        avg_h = sum( h[k,:] )/3
+        avg_h = sum( h[k,:] )/2
+
+        #Compute bed slope
+        #x0, y0, x1, y1, x2, y2 = x[k,:]
+        x0, x1 = x[k,:]
+        #z0, z1, z2 = v[k,:]
+        b0, b1 = b[k,:]
+
+        w0, w1 = w[k,:]
+        wx = gradient(x0, x1, w0, w1)
+
+        #zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        xmom[k] += -g*bx*avg_h
+        #xmom[k] = -g*bx*avg_h
+        #stage[k] = 0.0
+ 
+ 
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    #vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    #ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	#S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+                S = -g * eta[k]**2 * uh[k]
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	#ymom_update[k] += S*vh[k]
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+#    vh = domain.quantities['ymomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+#    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g #Not necessary? Why was this added?
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+ #           	ymom_update[k] += S*vh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
+class Wind_stress:
+    """Apply wind stress to water momentum in terms of
+    wind speed [m/s] and wind direction [degrees]
+    """
+
+    def __init__(self, *args, **kwargs):
+        """Initialise windfield from wind speed s [m/s]
+        and wind direction phi [degrees]
+
+        Inputs v and phi can be either scalars or Python functions, e.g.
+
+        W = Wind_stress(10, 178)
+
+        #FIXME - 'normal' degrees are assumed for now, i.e. the
+        vector (1,0) has zero degrees.
+        We may need to convert from 'compass' degrees later on and also
+        map from True north to grid north.
+
+        Arguments can also be Python functions of t,x,y as in
+
+        def speed(t,x,y):
+            ...
+            return s
+
+        def angle(t,x,y):
+            ...
+            return phi
+
+        where x and y are vectors.
+
+        and then pass the functions in
+
+        W = Wind_stress(speed, angle)
+
+        The instantiated object W can be appended to the list of
+        forcing_terms as in
+
+        Alternatively, one vector valued function for (speed, angle)
+        can be applied, providing both quantities simultaneously.
+        As in
+        W = Wind_stress(F), where returns (speed, angle) for each t.
+
+        domain.forcing_terms.append(W)
+        """
+
+        from config import rho_a, rho_w, eta_w
+        from Numeric import array, Float
+
+        if len(args) == 2:
+            s = args[0]
+            phi = args[1]
+        elif len(args) == 1:
+            #Assume vector function returning (s, phi)(t,x,y)
+            vector_function = args[0]
+            #s = lambda t,x,y: vector_function(t,x=x,y=y)[0]
+            #phi = lambda t,x,y: vector_function(t,x=x,y=y)[1]
+            s = lambda t,x: vector_function(t,x=x)[0]
+            phi = lambda t,x: vector_function(t,x=x)[1]
+        else:
+           #Assume info is in 2 keyword arguments
+
+           if len(kwargs) == 2:
+               s = kwargs['s']
+               phi = kwargs['phi']
+           else:
+               raise 'Assumes two keyword arguments: s=..., phi=....'
+
+        print 'phi', phi
+        self.speed = check_forcefield(s)
+        self.phi = check_forcefield(phi)
+
+        self.const = eta_w*rho_a/rho_w
+
+
+    def __call__(self, domain):
+        """Evaluate windfield based on values found in domain
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import Float, ones, ArrayType
+
+        xmom_update = domain.quantities['xmomentum'].explicit_update
+        #ymom_update = domain.quantities['ymomentum'].explicit_update
+
+        N = domain.number_of_elements
+        t = domain.time
+
+        if callable(self.speed):
+            xc = domain.get_centroid_coordinates()
+            #s_vec = self.speed(t, xc[:,0], xc[:,1])
+            s_vec = self.speed(t, xc)
+        else:
+            #Assume s is a scalar
+
+            try:
+                s_vec = self.speed * ones(N, Float)
+            except:
+                msg = 'Speed must be either callable or a scalar: %s' %self.s
+                raise msg
+
+
+        if callable(self.phi):
+            xc = domain.get_centroid_coordinates()
+            #phi_vec = self.phi(t, xc[:,0], xc[:,1])
+            phi_vec = self.phi(t, xc)
+        else:
+            #Assume phi is a scalar
+
+            try:
+                phi_vec = self.phi * ones(N, Float)
+            except:
+                msg = 'Angle must be either callable or a scalar: %s' %self.phi
+                raise msg
+
+        #assign_windfield_values(xmom_update, ymom_update,
+        #                        s_vec, phi_vec, self.const)
+        assign_windfield_values(xmom_update, s_vec, phi_vec, self.const)
+
+
+#def assign_windfield_values(xmom_update, ymom_update,
+#                            s_vec, phi_vec, const):
+def assign_windfield_values(xmom_update, s_vec, phi_vec, const):
+    """Python version of assigning wind field to update vectors.
+    A c version also exists (for speed)
+    """
+    from math import pi, cos, sin, sqrt
+
+    N = len(s_vec)
+    for k in range(N):
+        s = s_vec[k]
+        phi = phi_vec[k]
+
+        #Convert to radians
+        phi = phi*pi/180
+
+        #Compute velocity vector (u, v)
+        u = s*cos(phi)
+        v = s*sin(phi)
+
+        #Compute wind stress
+        #S = const * sqrt(u**2 + v**2)
+        S = const * u
+        xmom_update[k] += S*u
+        #ymom_update[k] += S*v
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_h.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_h.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_h.py	(revision 7576)
@@ -0,0 +1,1304 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectively.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are h, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+#from domain import *
+#from domain_order2 import *
+from domain_t2 import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['height', 'xmomentum']
+        other_quantities = ['stage', 'elevation', 'friction']
+        Generic_Domain.__init__(self, coordinates, boundary,
+                                conserved_quantities, other_quantities,
+                                tagged_elements)
+        
+        from config import minimum_allowed_height, g
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+
+        #forcing terms not included in 1d domain ?WHy?
+        self.forcing_terms.append(gravity)
+        #self.forcing_terms.append(manning_friction)
+        #print "\nI have Removed forcing terms line 64 1dsw"
+
+        #Realtime visualisation
+        self.visualiser = None
+        self.visualise  = False
+        self.visualise_color_stage = False
+        self.visualise_stage_range = 1.0
+        self.visualise_timer = True
+        self.visualise_range_z = None
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        #Evolve parametrs
+        self.cfl = 1.0
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.quantities_to_be_stored = ['stage','xmomentum']
+
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from realtime_visualisation_new import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+            self.visualiser.setup['elevation']=True
+            self.visualiser.updating['stage']=True
+        self.visualise = True
+        if self.visualise_color_stage == True:
+            self.visualiser.coloring['stage'] = True
+            self.visualiser.qcolor['stage'] = (0.0, 0.0, 0.8)
+        print 'initialise visualiser'
+        print self.visualiser.setup
+        print self.visualiser.updating
+
+    def check_integrity(self):
+        Generic_Domain.check_integrity(self)
+        #Check that we are solving the shallow water wave equation
+
+        #msg = 'First conserved quantity must be "stage"'
+        #assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'First conserved quantity must be "height"'
+        assert self.conserved_quantities[0] == 'height', msg
+
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes(self)
+
+    def compute_timestep(self):
+        #Call correct module function
+        compute_timestep(self)
+    
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+
+    def update_derived_quantities():
+        Stage = domain.quantities['stage']
+        Height = domain.quantities['height']
+        Bed = domain.quantities['elevation']
+
+        #stage = Stage.centroid_values
+        #height = Height.centroid_values
+        #bed =   Bed.centroid_values
+
+        Stage = Height+Bed
+
+        
+        
+
+    def evolve(self, yieldstep = None, finaltime = None,
+               skip_initial_step = False):
+        """Specialisation of basic evolve method from parent class
+        """
+
+        #Call check integrity here rather than from user scripts
+        #self.check_integrity()
+
+        #msg = 'Parameter beta_h must be in the interval [0, 1)'
+        #assert 0 <= self.beta_h < 1.0, msg
+        #msg = 'Parameter beta_w must be in the interval [0, 1)'
+        #assert 0 <= self.beta_w < 1.0, msg
+
+
+        #Initial update of vertex and edge values before any storage
+        #and or visualisation
+        self.distribute_to_vertices_and_edges()
+        
+        #Initialise real time viz if requested
+        #if self.visualise is True and self.time == 0.0:
+        #    if self.visualiser is None:
+        #        self.initialise_visualiser()
+        #
+        #    self.visualiser.update_timer()
+        #    self.visualiser.setup_all()
+
+        #Store model data, e.g. for visualisation
+        #if self.store is True and self.time == 0.0:
+        #    self.initialise_storage()
+        #    #print 'Storing results in ' + self.writer.filename
+        #else:
+        #    pass
+        #    #print 'Results will not be stored.'
+        #    #print 'To store results set domain.store = True'
+        #    #FIXME: Diagnostic output should be controlled by
+        #    # a 'verbose' flag living in domain (or in a parent class)
+
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime,
+                                       skip_initial_step):
+            #Real time viz
+        #    if self.visualise is True:
+        #        self.visualiser.update_all()
+        #        self.visualiser.update_timer()
+
+
+            #Store model data, e.g. for subsequent visualisation
+        #    if self.store is True:
+        #        self.store_timestep(self.quantities_to_be_stored)
+
+            #FIXME: Could maybe be taken from specified list
+            #of 'store every step' quantities
+
+            #Pass control on to outer loop for more specific actions
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x and bed elevation
+        """
+
+        import data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+
+#Rotation of momentum vector
+def rotate(q, normal, direction = 1):
+    """Rotate the momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector.
+
+    If direction is negative the rotation is inverted.
+
+    Input vector is preserved
+
+    This function is specific to the shallow water wave equation
+    """
+
+    from Numeric import zeros, Float
+
+    assert len(q) == 3,\
+           'Vector of conserved quantities must have length 3'\
+           'for 2D shallow water equation'
+
+    try:
+        l = len(normal)
+    except:
+        raise 'Normal vector must be an Numeric array'
+
+    assert l == 2, 'Normal vector must have 2 components'
+
+
+    n1 = normal[0]
+    n2 = normal[1]
+
+    r = zeros(len(q), Float) #Rotated quantities
+    r[0] = q[0]              #First quantity, height, is not rotated
+
+    if direction == -1:
+        n2 = -n2
+
+
+    r[1] =  n1*q[1] + n2*q[2]
+    r[2] = -n2*q[1] + n1*q[2]
+
+    return r
+
+
+def flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    #w_left  = q_left[0]   #w=h+z
+    #h_left  = w_left-z
+    h_left  = q_left[0]
+    w_left  = z + h_left
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/h_left
+
+
+    #w_right  = q_right[0]  #w=h+z
+    #h_right  = w_right-z
+    h_right  = q_right[0]
+    w_right  = z + h_right
+    uh_right = q_right[1]
+
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/h_right
+
+    #vh_left  = q_left[2]
+    #vh_right = q_right[2]
+
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+
+    #flux_left  = array([u_left*h_left,
+    #                    u_left*uh_left + 0.5*g*h_left**2])
+    #flux_right = array([u_right*h_right,
+    #                    u_right*uh_right + 0.5*g*h_right**2])
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+
+
+def compute_timestep(domain):
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    #Stage = domain.quantities['stage']
+    Height = domain.quantities['height']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+
+    #stage = Stage.vertex_values
+    height = Height.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+    
+    #stage_bdry = Stage.boundary_values
+    height_bdry = Height.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            ql = [height[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = height_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                m = domain.neighbour_vertices[k,i]
+                qr[0] = height[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+
+            if domain.split == False:
+                edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+            elif domain.split == True:
+                edgeflux, max_speed = flux_function_split(normal, ql, qr, zl, zr)
+
+            try:
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+    domain.timestep = timestep
+
+
+def compute_fluxes(domain):
+    """Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    #Stage = domain.quantities['stage']
+    Height = domain.quantities['height']
+    Xmom = domain.quantities['xmomentum']
+#    Ymom = domain.quantities['ymomentum']
+    Bed = domain.quantities['elevation']
+    """ 
+    from util import analytic_cannal
+    hc = domain.quantities['height'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    xv = domain.vertices
+
+    #will not show up as correct xmom on plot but is ok
+    for k in range(N):
+        if hc[k] < domain.minimum_allowed_height:
+            xmomc[k] = 0.0
+            xmomv[k,0] = 0.0
+            xmomv[k,1] = 0.0
+        else:
+            #ensure yield step is 1.0 or small enough to be less than min timestep
+            w1,uh1 = analytic_cannal(xv[k,0],domain.time)
+            w2,uh2 = analytic_cannal(xv[k,1],domain.time)
+            xmomv[k,0] = uh1
+            xmomv[k,1] = uh2
+            xmomc[k] = 0.5*(uh1+uh2)
+    """
+    #Arrays
+    #stage = Stage.edge_values
+    #xmom =  Xmom.edge_values
+ #   ymom =  Ymom.edge_values
+    #bed =   Bed.edge_values
+    
+    #stage = Stage.vertex_values
+    height = Height.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+    
+    #print 'stage edge values', stage
+    #print 'xmom edge values', xmom
+    #print 'bed values', bed
+
+    #stage_bdry = Stage.boundary_values
+    height_bdry = Height.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    #print 'stage_bdry',stage_bdry
+    #print 'xmom_bdry', xmom_bdry
+#    ymom_bdry =  Ymom.boundary_values
+
+#    flux = zeros(3, Float) #Work array for summing up fluxes
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            #ql[0] = stage[k, i]
+            #ql[1] = xmom[k, i]
+            ql = [height[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = height_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = height[n, m]
+                qr[1] =  xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            #Flux computation using provided function
+            #edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+            #print 'ql',ql
+            #print 'qr',qr
+            
+
+            if domain.split == False:
+                edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+            elif domain.split == True:
+                edgeflux, max_speed = flux_function_split(normal, ql, qr, zl, zr)
+            #print 'edgeflux', edgeflux
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        Height.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k]   = flux[1]
+        #Ymom.explicit_update[k]  = flux[2]
+
+    #print Height.vertex_values
+    #print Height.centroid_values
+
+    domain.timestep = timestep
+
+####################################
+
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    #protect_against_infinitesimal_and_negative_heights(domain)
+    #classify_wet_dry_cells(domain)
+    #adjust_partially_submerged_cells(domain)
+
+    #Extrapolate all conserved quantities
+    #if optimised_gradient_limiter:
+    #    #MH090605 if second order,
+    #    #perform the extrapolation and limiting on
+    #    #all of the conserved quantities
+
+    #    if (domain.order == 1):
+    #        for name in domain.conserved_quantities:
+    #            Q = domain.quantities[name]
+    #            Q.extrapolate_first_order()
+    #    elif domain.order == 2:
+    #        domain.extrapolate_second_order_sw()
+    #    else:
+    #        raise 'Unknown order'
+    #else:
+        #old code:
+    for name in domain.conserved_quantities:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            #if name != "xmomentum":
+            Q.extrapolate_second_order()
+            #Q.limit()
+        else:
+            raise 'Unknown order'
+
+    #Take bed elevation into account when water heights are small
+    #balance_deep_and_shallow(domain)
+    #protect_dry_beds(domain)
+    protect_against_infinitesimal_and_negative_heights(domain)
+    
+    #Compute edge values by interpolation
+    #for name in domain.conserved_quantities:
+    #    Q = domain.quantities[name]
+    #    Q.interpolate_from_vertices_to_edges()
+
+    #print "dist", domain.quantities['height'].centroid_values
+    #print domain.quantities['height'].vertex_values
+     
+def protect_dry_beds(domain):
+    
+    
+    N = domain.number_of_elements
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = domain.quantities['height'].centroid_values
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    min_centroid_height = 1e-3
+
+    for k in range(N):
+        if hc[k] < min_centroid_height:
+            wc[k] = zc[k]
+            hcv[k,0] = zv[k,0]
+            wv[k,1] = zv[k,1]
+            xmomv[k,:] = 0.0
+
+
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    zc = domain.quantities['elevation'].centroid_values
+    hc = domain.quantities['height'].centroid_values
+    hv = domain.quantities['height'].vertex_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+    xmomv = domain.quantities['xmomentum'].vertex_values
+#    ymomc = domain.quantities['ymomentum'].centroid_values
+    wc = hc + zc  #stage at centroids
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                #wc[k] = zc[k] # Contain 'lost mass' error
+                hv[k,0] = 0.0
+                hv[k,1] = 0.0
+                hc[k] = 0.0
+
+            #Control momentum
+            xmomc[k] = 0.0
+        
+            #xmomc[k] = ymomc[k] = 0.0
+        if (hv[k,0] < domain.minimum_allowed_height) | (hv[k,1] < domain.minimum_allowed_height):
+            hv[k,0] = 0.0
+            hv[k,1] = 0.0
+            xmomc[k] = 0.0
+            xmomv[k,0] = 0.0
+            xmomv[k,1] = 0.0
+
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        #for i in range(3):
+        for i in range(2):   
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    #for i in range(3):
+    for i in range(2):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        #for i in range(3):
+        for i in range(2):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        #for i in range(3):
+        for i in range(2):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]))#,
+#                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using the h-limited
+        #stage and alpha==1 means using the w-limited stage as
+        #computed by the gradient limiter (both 1st or 2nd order)
+
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        alpha  = 0.0
+	#Let
+	#
+	#  wvi be the w-limited stage (wvi = zvi + hvi)
+	#  wvi- be the h-limited state (wvi- = zvi + hvi-)
+	#
+	#
+	#where i=0,1,2 denotes the vertex ids
+	#
+        #Weighted balance between w-limited and h-limited stage is
+        #
+	#  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+	#
+        #It follows that the updated wvi is
+        #  wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+        #
+	# Momentum is balanced between constant and limited
+
+
+        #for i in range(3):
+        #    wv[k,i] = zv[k,i] + hvbar[k,i]
+
+	#return
+
+	if alpha < 1:
+
+            #for i in range(3):
+            for i in range(2):
+                wv[k,i] = zv[k,i] + (1.0-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+#            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+#           ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1.0-alpha)*xmomc[k] + alpha*xmomv[k,:]
+#            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+###############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        #self.stage   = domain.quantities['stage'].edge_values
+        #self.xmom    = domain.quantities['xmomentum'].edge_values
+        #self.ymom    = domain.quantities['ymomentum'].edge_values
+        #self.normals = domain.normals
+        #self.stage   = domain.quantities['stage'].vertex_values
+        self.height  = domain.quantities['height'].vertex_values
+        self.xmom    = domain.quantities['xmomentum'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        self.conserved_quantities = zeros(2, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+
+        q = self.conserved_quantities
+        #q[0] = self.stage[vol_id, edge_id]
+        q[0] = self.height[vol_id, edge_id]
+        #q[0] = 0.0
+        q[1] = self.xmom[vol_id, edge_id]
+        #q[2] = self.ymom[vol_id, edge_id]
+
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+1]
+
+
+        #r = rotate(q, normal, direction = 1)
+        #r[1] = -r[1]
+        #q = rotate(r, normal, direction = -1)
+        r = q
+        r[1] = -q[1]
+        q = r
+        #For start interval there is no outward momentum so do not need to
+        #reverse direction in this case
+
+        return q
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, conserved_quantities=None):
+        Boundary.__init__(self)
+
+        if conserved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.conserved_quantities=array(conserved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.conserved_quantities
+
+
+#########################
+#Standard forcing terms:
+#
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Height = domain.quantities['height']
+    Elevation = domain.quantities['elevation']
+    #h = Stage.edge_values - Elevation.edge_values
+    h = Height.vertex_values
+    b = Elevation.vertex_values
+    w = Elevation.vertex_values + Height.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+        avg_h = sum( h[k,:] )/2
+
+        #Compute bed slope
+        x0, x1 = x[k,:]
+        b0, b1 = b[k,:]
+
+        w0, w1 = w[k,:]
+        wx = gradient(x0, x1, w0, w1)
+
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum
+        if domain.split == False:
+            xmom[k] += -g*bx*avg_h
+        elif domain.split == True:
+            xmom[k] += -g*wx*avg_h
+ 
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    h = domain.quantities['height'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    #h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    #vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    #ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	#S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+                S = -g * eta[k]**2 * uh[k]
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	#ymom_update[k] += S*vh[k]
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = domain.quantities['height'].centroid_values
+    #h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+#    vh = domain.quantities['ymomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+#    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g #Not necessary? Why was this added?
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+ #           	ymom_update[k] += S*vh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
+class Wind_stress:
+    """Apply wind stress to water momentum in terms of
+    wind speed [m/s] and wind direction [degrees]
+    """
+
+    def __init__(self, *args, **kwargs):
+        """Initialise windfield from wind speed s [m/s]
+        and wind direction phi [degrees]
+
+        Inputs v and phi can be either scalars or Python functions, e.g.
+
+        W = Wind_stress(10, 178)
+
+        #FIXME - 'normal' degrees are assumed for now, i.e. the
+        vector (1,0) has zero degrees.
+        We may need to convert from 'compass' degrees later on and also
+        map from True north to grid north.
+
+        Arguments can also be Python functions of t,x,y as in
+
+        def speed(t,x,y):
+            ...
+            return s
+
+        def angle(t,x,y):
+            ...
+            return phi
+
+        where x and y are vectors.
+
+        and then pass the functions in
+
+        W = Wind_stress(speed, angle)
+
+        The instantiated object W can be appended to the list of
+        forcing_terms as in
+
+        Alternatively, one vector valued function for (speed, angle)
+        can be applied, providing both quantities simultaneously.
+        As in
+        W = Wind_stress(F), where returns (speed, angle) for each t.
+
+        domain.forcing_terms.append(W)
+        """
+
+        from config import rho_a, rho_w, eta_w
+        from Numeric import array, Float
+
+        if len(args) == 2:
+            s = args[0]
+            phi = args[1]
+        elif len(args) == 1:
+            #Assume vector function returning (s, phi)(t,x,y)
+            vector_function = args[0]
+            #s = lambda t,x,y: vector_function(t,x=x,y=y)[0]
+            #phi = lambda t,x,y: vector_function(t,x=x,y=y)[1]
+            s = lambda t,x: vector_function(t,x=x)[0]
+            phi = lambda t,x: vector_function(t,x=x)[1]
+        else:
+           #Assume info is in 2 keyword arguments
+
+           if len(kwargs) == 2:
+               s = kwargs['s']
+               phi = kwargs['phi']
+           else:
+               raise 'Assumes two keyword arguments: s=..., phi=....'
+
+        print 'phi', phi
+        self.speed = check_forcefield(s)
+        self.phi = check_forcefield(phi)
+
+        self.const = eta_w*rho_a/rho_w
+
+
+    def __call__(self, domain):
+        """Evaluate windfield based on values found in domain
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import Float, ones, ArrayType
+
+        xmom_update = domain.quantities['xmomentum'].explicit_update
+        #ymom_update = domain.quantities['ymomentum'].explicit_update
+
+        N = domain.number_of_elements
+        t = domain.time
+
+        if callable(self.speed):
+            xc = domain.get_centroid_coordinates()
+            #s_vec = self.speed(t, xc[:,0], xc[:,1])
+            s_vec = self.speed(t, xc)
+        else:
+            #Assume s is a scalar
+
+            try:
+                s_vec = self.speed * ones(N, Float)
+            except:
+                msg = 'Speed must be either callable or a scalar: %s' %self.s
+                raise msg
+
+
+        if callable(self.phi):
+            xc = domain.get_centroid_coordinates()
+            #phi_vec = self.phi(t, xc[:,0], xc[:,1])
+            phi_vec = self.phi(t, xc)
+        else:
+            #Assume phi is a scalar
+
+            try:
+                phi_vec = self.phi * ones(N, Float)
+            except:
+                msg = 'Angle must be either callable or a scalar: %s' %self.phi
+                raise msg
+
+        #assign_windfield_values(xmom_update, ymom_update,
+        #                        s_vec, phi_vec, self.const)
+        assign_windfield_values(xmom_update, s_vec, phi_vec, self.const)
+
+
+#def assign_windfield_values(xmom_update, ymom_update,
+#                            s_vec, phi_vec, const):
+def assign_windfield_values(xmom_update, s_vec, phi_vec, const):
+    """Python version of assigning wind field to update vectors.
+    A c version also exists (for speed)
+    """
+    from math import pi, cos, sin, sqrt
+
+    N = len(s_vec)
+    for k in range(N):
+        s = s_vec[k]
+        phi = phi_vec[k]
+
+        #Convert to radians
+        phi = phi*pi/180
+
+        #Compute velocity vector (u, v)
+        u = s*cos(phi)
+        v = s*sin(phi)
+
+        #Compute wind stress
+        #S = const * sqrt(u**2 + v**2)
+        S = const * u
+        xmom_update[k] += S*u
+        #ymom_update[k] += S*v
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_try.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_try.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_try.py	(revision 7576)
@@ -0,0 +1,1000 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+#from domain import *
+#from domain_order2 import *
+from domain_t2 import *
+from comp_flux_ext import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, boundary = None, tagged_elements = None,
+                 geo_reference = None):
+
+        conserved_quantities = ['stage', 'xmomentum']
+        other_quantities = ['elevation', 'friction']
+        Generic_Domain.__init__(self, coordinates, boundary,
+                                conserved_quantities, other_quantities,
+                                tagged_elements, geo_reference)
+        
+        from config import minimum_allowed_height, g
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+
+        #forcing terms not included in 1d domain ?WHy?
+        self.forcing_terms.append(gravity)
+        #self.forcing_terms.append(manning_friction)
+        #print "\nI have Removed forcing terms line 64 1dsw"
+
+        #Realtime visualisation
+        self.visualiser = None
+        self.visualise  = False
+        self.visualise_color_stage = False
+        self.visualise_stage_range = 1.0
+        self.visualise_timer = True
+        self.visualise_range_z = None
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        #Evolve parametrs
+        self.cfl = 1.0
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.quantities_to_be_stored = ['stage','xmomentum']
+
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each
+        yieldstep
+        (This is in addition to the quantities elevation and friction)  
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []            
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness    
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg 
+        
+        self.quantities_to_be_stored = q
+        
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from realtime_visualisation_new import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+            self.visualiser.setup['elevation']=True
+            self.visualiser.updating['stage']=True
+        self.visualise = True
+        if self.visualise_color_stage == True:
+            self.visualiser.coloring['stage'] = True
+            self.visualiser.qcolor['stage'] = (0.0, 0.0, 0.8)
+        print 'initialise visualiser'
+        print self.visualiser.setup
+        print self.visualiser.updating
+
+    def check_integrity(self):
+        Generic_Domain.check_integrity(self)
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes(self)
+
+    def compute_timestep(self):
+        #Call correct module function
+        compute_timestep(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+        
+    def evolve(self, yieldstep = None, finaltime = None,
+               skip_initial_step = False):
+        """Specialisation of basic evolve method from parent class
+        """
+
+        #Call check integrity here rather than from user scripts
+        #self.check_integrity()
+
+        #msg = 'Parameter beta_h must be in the interval [0, 1)'
+        #assert 0 <= self.beta_h < 1.0, msg
+        #msg = 'Parameter beta_w must be in the interval [0, 1)'
+        #assert 0 <= self.beta_w < 1.0, msg
+
+
+        #Initial update of vertex and edge values before any storage
+        #and or visualisation
+        
+        self.distribute_to_vertices_and_edges()
+        
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime,
+                                       skip_initial_step):
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x and bed elevation
+        """
+
+        import data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+
+#Rotation of momentum vector
+def rotate(q, normal, direction = 1):
+    """Rotate the momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector.
+
+    If direction is negative the rotation is inverted.
+
+    Input vector is preserved
+
+    This function is specific to the shallow water wave equation
+    """
+
+    from Numeric import zeros, Float
+
+    assert len(q) == 3,\
+           'Vector of conserved quantities must have length 3'\
+           'for 2D shallow water equation'
+
+    try:
+        l = len(normal)
+    except:
+        raise 'Normal vector must be an Numeric array'
+
+    assert l == 2, 'Normal vector must have 2 components'
+
+
+    n1 = normal[0]
+    n2 = normal[1]
+
+    r = zeros(len(q), Float) #Rotated quantities
+    r[0] = q[0]              #First quantity, height, is not rotated
+
+    if direction == -1:
+        n2 = -n2
+
+
+    r[1] =  n1*q[1] + n2*q[2]
+    r[2] = -n2*q[1] + n1*q[2]
+
+    return r
+"""++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"""
+# Compute flux definition
+def compute_fluxes(domain):
+	from Numeric import zeros, Float
+	import sys
+	
+	timestep = float(sys.maxint)
+	print 'timestep=',timestep
+	print 'The type of timestep is',type(timestep)
+	
+	epsilon = domain.epsilon
+	print 'epsilon=',epsilon
+	print 'The type of epsilon is',type(epsilon)
+	
+	g = domain.g
+	print 'g=',g
+	print 'The type of g is',type(g)
+	
+	neighbours = domain.neighbours
+	print 'neighbours=',neighbours
+	print 'The type of neighbours is',type(neighbours)
+	
+	neighbour_vertices = domain.neighbour_vertices
+	print 'neighbour_vertices=',neighbour_vertices
+	print 'The type of neighbour_vertices is',type(neighbour_vertices)
+	
+	normals = domain.normals
+	print 'normals=',normals
+	print 'The type of normals is',type(normals)
+	
+	areas = domain.areas
+	print 'areas=',areas
+	print 'The type of areas is',type(areas)
+	
+	stage_edge_values = domain.quantities['stage'].vertex_values
+	print 'stage_edge_values=',stage_edge_values
+	print 'The type of stage_edge_values is',type(stage_edge_values)
+	
+	xmom_edge_values = domain.quantities['xmomentum'].vertex_values
+	print 'xmom_edge_values=',xmom_edge_values
+	print 'The type of xmom_edge_values is',type(xmom_edge_values)
+	
+	bed_edge_values = domain.quantities['elevation'].vertex_values
+	print 'bed_edge_values=',bed_edge_values
+	print 'The type of bed_edge_values is',type(bed_edge_values)
+	
+	stage_boundary_values = domain.quantities['stage'].boundary_values
+	print 'stage_boundary_values=',stage_boundary_values
+	print 'The type of stage_boundary_values is',type(stage_boundary_values)
+	
+	xmom_boundary_values = domain.quantities['xmomentum'].boundary_values
+	print 'xmom_boundary_values=',xmom_boundary_values
+	print 'The type of xmom_boundary_values is',type(xmom_boundary_values)
+	
+	stage_explicit_update = domain.quantities['stage'].explicit_update
+	print 'stage_explicit_update=',stage_explicit_update
+	print 'The type of stage_explicit_update is',type(stage_explicit_update)
+	
+	xmom_explicit_update = domain.quantities['xmomentum'].explicit_update
+	print 'xmom_explicit_update=',xmom_explicit_update
+	print 'The type of xmom_explicit_update is',type(xmom_explicit_update)
+	
+	number_of_elements = len(stage_edge_values)
+	print 'number_of_elements=',number_of_elements
+	print 'The type of number_of_elements is',type(number_of_elements)
+	
+	max_speed_array = zeros(number_of_elements, Float)
+	print 'max_speed_array=',max_speed_array
+	print 'The type of max_speed_array is',type(max_speed_array)
+	
+	return compute_fluxes_ext(timestep, epsilon, g, neighbours, neighbour_vertices,	normals, areas, 
+	stage_edge_values, xmom_edge_values, bed_edge_values, stage_boundary_values, xmom_boundary_values,
+	number_of_elements, max_speed_array)
+####################################
+
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    protect_against_infinitesimal_and_negative_heights(domain)
+    
+
+    #Extrapolate all conserved quantities
+    #if optimised_gradient_limiter:
+    #    #MH090605 if second order,
+    #    #perform the extrapolation and limiting on
+    #    #all of the conserved quantities
+
+    #    if (domain.order == 1):
+    #        for name in domain.conserved_quantities:
+    #            Q = domain.quantities[name]
+    #            Q.extrapolate_first_order()
+    #    elif domain.order == 2:
+    #        domain.extrapolate_second_order_sw()
+    #    else:
+    #        raise 'Unknown order'
+    #else:
+        #old code:
+
+    for name in domain.conserved_quantities:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            #print "add extrapolate second order to shallow water"
+            #if name != 'height':
+            Q.extrapolate_second_order()
+            #Q.limit()
+        else:
+            raise 'Unknown order'
+
+    #Take bed elevation into account when water heights are small
+    #balance_deep_and_shallow(domain)
+    #protect_against_infinitesimal_and_negative_heights(domain)
+
+#Compute edge values by interpolation
+    #for name in domain.conserved_quantities:
+    #    Q = domain.quantities[name]
+    #    Q.interpolate_from_vertices_to_edges()    
+    
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+#    ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    zv = domain.quantities['elevation'].vertex_values
+    wv = domain.quantities['stage'].vertex_values
+    hv = wv-zv
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    #remove the above two lines and corresponding code below
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+                wv[k,0] = zv[k,0]
+                wv[k,1] = zv[k,1]
+                
+            xmomc[k] = 0.0
+            
+        #N = domain.number_of_elements
+        #if (k == 0) | (k==N-1):
+        #    wc[k] = zc[k] # Contain 'lost mass' error
+        #    wv[k,0] = zv[k,0]
+        #    wv[k,1] = zv[k,1]
+    
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        #for i in range(3):
+        for i in range(2):   
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    #for i in range(3):
+    for i in range(2):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        #for i in range(3):
+        for i in range(2):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        #for i in range(3):
+        for i in range(2):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]))#,
+#                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using the h-limited
+        #stage and alpha==1 means using the w-limited stage as
+        #computed by the gradient limiter (both 1st or 2nd order)
+
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        alpha  = 0.0
+	#Let
+	#
+	#  wvi be the w-limited stage (wvi = zvi + hvi)
+	#  wvi- be the h-limited state (wvi- = zvi + hvi-)
+	#
+	#
+	#where i=0,1,2 denotes the vertex ids
+	#
+        #Weighted balance between w-limited and h-limited stage is
+        #
+	#  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+	#
+        #It follows that the updated wvi is
+        #  wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+        #
+	# Momentum is balanced between constant and limited
+
+
+        #for i in range(3):
+        #    wv[k,i] = zv[k,i] + hvbar[k,i]
+
+	#return
+
+	if alpha < 1:
+
+            #for i in range(3):
+            for i in range(2):
+                wv[k,i] = zv[k,i] + (1.0-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+#            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+#           ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1.0-alpha)*xmomc[k] + alpha*xmomv[k,:]
+#            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+###############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        #self.stage   = domain.quantities['stage'].edge_values
+        #self.xmom    = domain.quantities['xmomentum'].edge_values
+        #self.ymom    = domain.quantities['ymomentum'].edge_values
+        self.normals = domain.normals
+        self.stage   = domain.quantities['stage'].vertex_values
+        self.xmom    = domain.quantities['xmomentum'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        self.conserved_quantities = zeros(2, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+
+        q = self.conserved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = self.xmom[vol_id, edge_id]
+        #q[2] = self.ymom[vol_id, edge_id]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
+        #normal = self.normals[vol_id, 2*edge_id:2*edge_id+1]
+        normal = self.normals[vol_id,edge_id]
+
+        #r = rotate(q, normal, direction = 1)
+        #r[1] = -r[1]
+        #q = rotate(r, normal, direction = -1)
+        r = q
+        r[1] = normal*r[1]
+        r[1] = -r[1]
+        r[1] = normal*r[1]
+        q = r
+        #For start interval there is no outward momentum so do not need to
+        #reverse direction in this case
+
+        return q
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, conserved_quantities=None):
+        Boundary.__init__(self)
+
+        if conserved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.conserved_quantities=array(conserved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.conserved_quantities
+
+
+#########################
+#Standard forcing terms:
+#
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    stage = domain.quantities['stage'].explicit_update
+#    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    #h = Stage.edge_values - Elevation.edge_values
+    h = Stage.vertex_values - Elevation.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+#        avg_h = sum( h[k,:] )/3
+        avg_h = sum( h[k,:] )/2
+
+        #Compute bed slope
+        #x0, y0, x1, y1, x2, y2 = x[k,:]
+        x0, x1 = x[k,:]
+        #z0, z1, z2 = v[k,:]
+        b0, b1 = b[k,:]
+
+        w0, w1 = w[k,:]
+        wx = gradient(x0, x1, w0, w1)
+
+        #zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        if domain.split == False:
+            xmom[k] += -g*bx*avg_h
+            #xmom[k] = -g*bx*avg_h
+            #stage[k] = 0.0
+        elif domain.split == True:
+            xmom[k] += -g*wx*avg_h
+            #xmom[k] = -g*wx*avg_h
+        #ymom[k] += -g*zy*avg_h
+ 
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    #vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    #ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	#S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+                S = -g * eta[k]**2 * uh[k]
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	#ymom_update[k] += S*vh[k]
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+#    vh = domain.quantities['ymomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+#    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g #Not necessary? Why was this added?
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+ #           	ymom_update[k] += S*vh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
+class Wind_stress:
+    """Apply wind stress to water momentum in terms of
+    wind speed [m/s] and wind direction [degrees]
+    """
+
+    def __init__(self, *args, **kwargs):
+        """Initialise windfield from wind speed s [m/s]
+        and wind direction phi [degrees]
+
+        Inputs v and phi can be either scalars or Python functions, e.g.
+
+        W = Wind_stress(10, 178)
+
+        #FIXME - 'normal' degrees are assumed for now, i.e. the
+        vector (1,0) has zero degrees.
+        We may need to convert from 'compass' degrees later on and also
+        map from True north to grid north.
+
+        Arguments can also be Python functions of t,x,y as in
+
+        def speed(t,x,y):
+            ...
+            return s
+
+        def angle(t,x,y):
+            ...
+            return phi
+
+        where x and y are vectors.
+
+        and then pass the functions in
+
+        W = Wind_stress(speed, angle)
+
+        The instantiated object W can be appended to the list of
+        forcing_terms as in
+
+        Alternatively, one vector valued function for (speed, angle)
+        can be applied, providing both quantities simultaneously.
+        As in
+        W = Wind_stress(F), where returns (speed, angle) for each t.
+
+        domain.forcing_terms.append(W)
+        """
+
+        from config import rho_a, rho_w, eta_w
+        from Numeric import array, Float
+
+        if len(args) == 2:
+            s = args[0]
+            phi = args[1]
+        elif len(args) == 1:
+            #Assume vector function returning (s, phi)(t,x,y)
+            vector_function = args[0]
+            #s = lambda t,x,y: vector_function(t,x=x,y=y)[0]
+            #phi = lambda t,x,y: vector_function(t,x=x,y=y)[1]
+            s = lambda t,x: vector_function(t,x=x)[0]
+            phi = lambda t,x: vector_function(t,x=x)[1]
+        else:
+           #Assume info is in 2 keyword arguments
+
+           if len(kwargs) == 2:
+               s = kwargs['s']
+               phi = kwargs['phi']
+           else:
+               raise 'Assumes two keyword arguments: s=..., phi=....'
+
+        print 'phi', phi
+        self.speed = check_forcefield(s)
+        self.phi = check_forcefield(phi)
+
+        self.const = eta_w*rho_a/rho_w
+
+
+    def __call__(self, domain):
+        """Evaluate windfield based on values found in domain
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import Float, ones, ArrayType
+
+        xmom_update = domain.quantities['xmomentum'].explicit_update
+        #ymom_update = domain.quantities['ymomentum'].explicit_update
+
+        N = domain.number_of_elements
+        t = domain.time
+
+        if callable(self.speed):
+            xc = domain.get_centroid_coordinates()
+            #s_vec = self.speed(t, xc[:,0], xc[:,1])
+            s_vec = self.speed(t, xc)
+        else:
+            #Assume s is a scalar
+
+            try:
+                s_vec = self.speed * ones(N, Float)
+            except:
+                msg = 'Speed must be either callable or a scalar: %s' %self.s
+                raise msg
+
+
+        if callable(self.phi):
+            xc = domain.get_centroid_coordinates()
+            #phi_vec = self.phi(t, xc[:,0], xc[:,1])
+            phi_vec = self.phi(t, xc)
+        else:
+            #Assume phi is a scalar
+
+            try:
+                phi_vec = self.phi * ones(N, Float)
+            except:
+                msg = 'Angle must be either callable or a scalar: %s' %self.phi
+                raise msg
+
+        #assign_windfield_values(xmom_update, ymom_update,
+        #                        s_vec, phi_vec, self.const)
+        assign_windfield_values(xmom_update, s_vec, phi_vec, self.const)
+
+
+#def assign_windfield_values(xmom_update, ymom_update,
+#                            s_vec, phi_vec, const):
+def assign_windfield_values(xmom_update, s_vec, phi_vec, const):
+    """Python version of assigning wind field to update vectors.
+    A c version also exists (for speed)
+    """
+    from math import pi, cos, sin, sqrt
+
+    N = len(s_vec)
+    for k in range(N):
+        s = s_vec[k]
+        phi = phi_vec[k]
+
+        #Convert to radians
+        phi = phi*pi/180
+
+        #Compute velocity vector (u, v)
+        u = s*cos(phi)
+        v = s*sin(phi)
+
+        #Compute wind stress
+        #S = const * sqrt(u**2 + v**2)
+        S = const * u
+        xmom_update[k] += S*u
+        #ymom_update[k] += S*v
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_vel_domain.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_vel_domain.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/shallow_water_vel_domain.py	(revision 7576)
@@ -0,0 +1,588 @@
+"""Class Domain -
+1D interval domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x = S
+
+where
+
+U = [w, uh]
+E = [uh, u^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2006
+"""
+
+
+from domain import *
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, boundary = None, tagged_elements = None):
+
+        conserved_quantities = ['stage', 'xmomentum']
+        evolved_quantities = ['stage', 'xmomentum', 'elevation', 'height', 'velocity']
+        other_quantities = ['friction']
+        Generic_Domain.__init__(self,
+                                coordinates = coordinates,
+                                boundary = boundary,
+                                conserved_quantities = conserved_quantities,
+                                evolved_quantities = evolved_quantities,
+                                other_quantities = other_quantities,
+                                tagged_elements = tagged_elements)
+        
+        from config import minimum_allowed_height, g, h0
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+        self.h0 = h0
+
+        #forcing terms not included in 1d domain ?WHy?
+        self.forcing_terms.append(gravity)
+        #self.forcing_terms.append(manning_friction)
+        #print "\nI have Removed forcing terms line 64 1dsw"
+
+        
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.smooth = True
+
+        
+        #Reduction operation for get_vertex_values
+        from util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.set_quantities_to_be_stored(['stage','xmomentum'])
+
+	self.__doc__ = 'shallow_water_domain'
+
+        self.check_integrity()
+
+
+
+    def check_integrity(self):
+
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+
+        msg = 'First evolved quantity must be "stage"'
+        assert self.evolved_quantities[0] == 'stage', msg
+        msg = 'Second evolved quantity must be "xmomentum"'
+        assert self.evolved_quantities[1] == 'xmomentum', msg
+        msg = 'Third evolved quantity must be "elevation"'
+        assert self.evolved_quantities[2] == 'elevation', msg
+        msg = 'Fourth evolved quantity must be "height"'
+        assert self.evolved_quantities[3] == 'height', msg
+        msg = 'Fifth evolved quantity must be "velocity"'
+        assert self.evolved_quantities[4] == 'velocity', msg
+
+        Generic_Domain.check_integrity(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes_vel(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges_limit_w_u(self)
+        
+
+#=============== End of Shallow Water Domain ===============================
+#-----------------------------------
+# Compute fluxes interface
+#-----------------------------------
+def compute_fluxes(domain):
+    """
+    Python version of compute fluxes (local_compute_fluxes)
+    is available in test_shallow_water_vel_domain.py
+    """
+ 
+
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+
+    stage = domain.quantities['stage']
+    xmom = domain.quantities['xmomentum']
+    bed = domain.quantities['elevation']
+
+
+    from comp_flux_vel_ext import compute_fluxes_ext
+
+    domain.flux_timestep = compute_fluxes_ext(timestep,domain,stage,xmom,bed)
+
+
+#-----------------------------------
+# Compute flux definition with vel
+#-----------------------------------
+def compute_fluxes_vel(domain):
+    from Numeric import zeros, Float
+    import sys
+
+	
+    timestep = float(sys.maxint)
+
+    stage    = domain.quantities['stage']
+    xmom     = domain.quantities['xmomentum']
+    bed      = domain.quantities['elevation']
+    height   = domain.quantities['height']
+    velocity = domain.quantities['velocity']
+
+
+    from comp_flux_vel_ext import compute_fluxes_vel_ext
+
+    domain.flux_timestep = compute_fluxes_vel_ext(timestep,domain,stage,xmom,bed,height,velocity)
+
+
+
+#--------------------------------------------------------------------------
+def distribute_to_vertices_and_edges_limit_w_u(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    #from config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    #protect_against_infinitesimal_and_negative_heights(domain)  
+
+    import sys
+    from Numeric import zeros, Float
+    from config import epsilon, h0
+	
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    Height = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+    #Arrays   
+    w_C   = Stage.centroid_values    
+    uh_C  = Xmom.centroid_values    
+    z_C   = Bed.centroid_values
+    h_C   = Height.centroid_values
+    u_C   = Velocity.centroid_values
+	
+    #print id(h_C)
+##     for i in range(N):
+## 	h_C[i] = w_C[i] - z_C[i]						
+##         if h_C[i] <= 1.0e-12:
+## 	    #print 'h_C[%d]= %15.5e\n' % (i,h_C[i])
+## 	    h_C[i] = 0.0
+## 	    w_C[i] = z_C[i]
+## 	    #uh_C[i] = 0.0
+            
+##  #           u_C[i] = 0.0
+##  #       else:
+##  #           u_C[i] = uh_C[i]/h_C[i]
+		
+    h0 = 1.0e-12    
+    for i in range(N):
+        h_C[i] = w_C[i] - z_C[i]						
+	if h_C[i] < 1.0e-12:
+	    u_C[i] = 0.0  #Could have been negative
+	    h_C[i] = 0.0
+            w_C[i] = z_C[i]
+	else:
+            #u_C[i]  = uh_C[i]/(h_C[i] + h0/h_C[i])
+            u_C[i]  = uh_C[i]/h_C[i]
+	
+    for name in [ 'velocity', 'stage' ]:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            Q.extrapolate_second_order()
+        else:
+            raise 'Unknown order'
+
+    w_V  = domain.quantities['stage'].vertex_values			
+    z_V  = domain.quantities['elevation'].vertex_values	
+    h_V  = domain.quantities['height'].vertex_values
+    u_V  = domain.quantities['velocity'].vertex_values		
+    uh_V = domain.quantities['xmomentum'].vertex_values	
+
+    h_V[:]    = w_V - z_V
+    for i in range(len(h_C)):
+        for j in range(2):
+            if h_V[i,j] < 0.0 :
+                #print 'h_V[%d,%d] = %f \n' % (i,j,h_V[i,j])                 
+                dh = h_V[i,j]
+                h_V[i,j] = 0.0
+                w_V[i,j] = z_V[i,j]
+                h_V[i,(j+1)%2] = h_V[i,(j+1)%2] + dh
+                w_V[i,(j+1)%2] = w_V[i,(j+1)%2] + dh
+                
+    uh_V[:] = u_V * h_V
+
+    
+    return
+
+#---------------------------------------------------------------------------
+def distribute_to_vertices_and_edges_limit_w_uh(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave equation.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    import sys
+    from Numeric import zeros, Float
+    from config import epsilon, h0
+	
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Bed = domain.quantities['elevation']
+    Height = domain.quantities['height']
+    Velocity = domain.quantities['velocity']
+
+    #Arrays   
+    w_C   = Stage.centroid_values    
+    uh_C  = Xmom.centroid_values    
+    z_C   = Bed.centroid_values
+    h_C   = Height.centroid_values
+    u_C   = Velocity.centroid_values
+	
+
+    for i in range(N):
+	h_C[i] = w_C[i] - z_C[i]						
+        if h_C[i] <= 1.0e-6:
+	    #print 'h_C[%d]= %15.5e\n' % (i,h_C[i])
+	    h_C[i] = 0.0
+	    w_C[i] = z_C[i]
+	    uh_C[i] = 0.0
+            
+    for name in [ 'stage', 'xmomentum']:
+        Q = domain.quantities[name]
+        if domain.order == 1:
+            Q.extrapolate_first_order()
+        elif domain.order == 2:
+            Q.extrapolate_second_order()
+        else:
+            raise 'Unknown order'
+
+    w_V  = domain.quantities['stage'].vertex_values			
+    z_V  = domain.quantities['elevation'].vertex_values	
+    h_V  = domain.quantities['height'].vertex_values
+    u_V  = domain.quantities['velocity'].vertex_values		
+    uh_V = domain.quantities['xmomentum'].vertex_values	
+
+    h_V[:]    = w_V - z_V
+
+    for i in range(len(h_C)):
+        for j in range(2):
+            if h_V[i,j] < 0.0 :
+                #print 'h_V[%d,%d] = %f \n' % (i,j,h_V[i,j])                 
+                dh = h_V[i,j]
+                h_V[i,j] = 0.0
+                w_V[i,j] = z_V[i,j]
+                h_V[i,(j+1)%2] = h_V[i,(j+1)%2] + dh
+                w_V[i,(j+1)%2] = w_V[i,(j+1)%2] + dh
+                u_V[i,j] = 0.0
+            if h_V[i,j] < h0:
+                u_V[i,j]
+            else:
+                u_V[i,j] = uh_V[i,j]/(h_V[i,j] + h0/h_V[i,j])
+
+
+#--------------------------------------------------------
+#Boundaries - specific to the shallow_water_vel_domain
+#--------------------------------------------------------
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        self.normals  = domain.normals
+        self.stage    = domain.quantities['stage'].vertex_values
+        self.xmom     = domain.quantities['xmomentum'].vertex_values
+        self.bed      = domain.quantities['elevation'].vertex_values
+        self.height   = domain.quantities['height'].vertex_values
+        self.velocity = domain.quantities['velocity'].vertex_values
+
+        from Numeric import zeros, Float
+        #self.conserved_quantities = zeros(3, Float)
+        self.evolved_quantities = zeros(5, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+
+        q = self.evolved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = -self.xmom[vol_id, edge_id]
+        q[2] = self.bed[vol_id, edge_id]
+        q[3] = self.height[vol_id, edge_id]
+        q[4] = -self.velocity[vol_id, edge_id]
+
+        #print "In Reflective q ",q
+
+
+        return q
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, evolved_quantities=None):
+        Boundary.__init__(self)
+
+        if evolved_quantities is None:
+            msg = 'Must specify one value for each evolved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.evolved_quantities=array(evolved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.evolved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.evolved_quantities
+
+
+#----------------------------
+#Standard forcing terms:
+#---------------------------
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from util import gradient
+    from Numeric import zeros, Float, array, sum
+
+
+
+    Stage     = domain.quantities['stage']
+    Xmom      = domain.quantities['xmomentum']
+    Elevation = domain.quantities['elevation']
+    Height    = domain.quantities['height']
+
+    xmom_ud  = Xmom.explicit_update
+    #stage_ud = Stage.explicit_update
+
+
+    #h = Stage.vertex_values - Elevation.vertex_values
+    h = Height.vertex_values
+    b = Elevation.vertex_values
+    w = Stage.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+        avg_h = 0.5*(h[k,0] + h[k,1])
+
+        #Compute bed slope
+        x0, x1 = x[k,:]
+        b0, b1 = b[k,:]
+        bx = gradient(x0, x1, b0, b1)
+        
+        #Update momentum (explicit update is reset to source values)
+        xmom_ud[k] += -g*bx*avg_h
+        #stage_ud[k] = 0.0
+ 
+ 
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    #vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    #ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	#S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+                S = -g * eta[k]**2 * uh[k]
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	#ymom_update[k] += S*vh[k]
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        #N = 3
+        N = 2
+        #x = ones(3, Float)
+        #y = ones(3, Float)
+        x = ones(2, Float)
+        #y = ones(2, Float)
+        
+        try:
+            #q = f(1.0, x=x, y=y)
+            q = f(1.0, x=x)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/steady_flow.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/steady_flow.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/steady_flow.py	(revision 7576)
@@ -0,0 +1,184 @@
+import os
+from math import sqrt, pi
+from shallow_water_domain_suggestion3 import *
+from Numeric import allclose, array, zeros, ones, Float, take, sqrt
+from config import g, epsilon
+
+h_0 = 0.5
+u_0 = 0.6
+h_1 = 0.5
+u_1 = 0.6
+
+
+q = 0.3
+g = 9.81
+
+b = 4.0
+xmax = 25.0
+z_bmax = 0.2
+Fr_0 = u_0/sqrt(g*h_0)
+
+def stage(x):
+    y,u,h = analytical_sol(x)
+    return y
+    
+
+def elevation(x):
+    b = 4.0
+    xmax = 25.0
+    z_bmax = 0.2
+    z_b = zeros(len(x),Float)
+    for i in range(len(x)):
+        if (x[i] >= xmax-b) & (x[i] <= xmax+b):
+            z_b[i] = z_bmax*(1.0-(x[i]-xmax)**2/b**2)
+        else:
+            z_b[i] = 0.0 
+    return z_b
+    #return 0.0
+
+def xmomentum(x):
+    return u_0*h_0
+
+
+def bisection(func,xR,xL,H):
+    while ((xR - xL) > epsilon):
+  
+        #Calculate midpoint of domain
+        xM = xL + (xR - xL) / 2.0
+  
+        #Find f(xM)
+        if ((f(xL,H) * f(xM,H)) > 0):
+            #Throw away left half
+            xL = xM
+        else:
+            #Throw away right half
+            xR = xM
+    return xR
+
+def f(D,H):
+    return D**3+D**2*(H-1.0-Fr_0**2/2.0)+Fr_0**2/2.0
+
+def fprime(D,H):
+    Fr_0 = u_0/sqrt(g*h_0)
+    return 3*D**2+2*D*(H-1-Fr_0**2/2.0)
+
+def analytical_sol(x):
+    y = zeros(len(x),Float)
+    u = zeros(len(x),Float)
+    height = zeros(len(x),Float)
+    for i in range(len(x)):
+        if (x[i] >= xmax-b) & (x[i] <= xmax+b):
+            zb = z_bmax*(1.0-(x[i]-xmax)**2/b**2)
+        else:
+            zb = 0.0 
+
+        H = zb/h_0
+        y1 = bisection(f,1.0,0.2/0.5,H)
+        height[i] = y1*h_0
+        y[i] = height[i]+zb
+        u[i] = q/(height[i])
+        
+
+    return y,u,height
+
+Fr_0 = u_0/sqrt(g*h_0)
+zb=0.2
+H = zb/h_0
+D = bisection(f,1,0.2/0.5,H)
+
+L = 50.0
+N = 400
+cell_len = L/N
+points = zeros(N+1,Float)
+for j in range(N+1):
+    points[j] = j*cell_len
+boundary = { (0,0): 'left',(N-1,1): 'right'}
+domain = Domain(points,boundary)
+D1 = Dirichlet_boundary([h_0,u_0*h_0,0.0,h_0,u_0])
+D2 = Dirichlet_boundary([h_1,u_1*h_1,0.0,h_1,u_1])
+
+domain.set_boundary({'left':D1,'right':D2})
+domain.set_quantity('elevation',elevation)
+domain.set_quantity('stage',stage)
+domain.set_quantity('xmomentum',xmomentum)
+X = domain.vertices
+C = domain.centroids
+
+Stage = domain.quantities['stage']
+Xmom = domain.quantities['xmomentum']
+Velocity = domain.quantities['velocity']
+
+StageV = Stage.vertex_values
+StageC = Stage.centroid_values
+XmomV = Xmom.vertex_values
+XmomC = Xmom.centroid_values
+VelC = Velocity.centroid_values
+VelV = Velocity.vertex_values
+ElevationV = domain.quantities['elevation'].vertex_values
+
+stage_bdry = Stage.boundary_values
+xmom_bdry =  Xmom.boundary_values
+
+w,u,h = analytical_sol(X.flat)
+wc, uc, hc = analytical_sol(C)
+
+h_error = zeros(1,Float)
+uh_error = zeros(1,Float)
+u_error = zeros(1,Float)
+k = 0
+
+domain.limiter = "minmod"
+domain.order = 2
+domain.set_timestepping_method('rk2')
+domain.cfl = 1.0
+print 'THE DOMAIN LIMITER is', domain.limiter
+import time
+yieldstep = finaltime = 0.2/71
+t0=time.time()
+while finaltime < 0.20001:
+    for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime):
+        domain.write_time()
+        print "integral", domain.quantities['stage'].get_integral()
+        if t>= 0.0:      
+            h_error[k] = cell_len*sum(abs(wc-StageC))
+            uh_error[k] = cell_len*sum(abs(uc*hc-XmomC))
+            u_error[k] = cell_len*sum(abs(uc-VelC))
+            print "h_error %.10f" %(h_error[k])
+            print "uh_error %.10f"% (uh_error[k])
+            print "u_error %.10f"% (u_error[k])
+            print "h_max %.10f"%max(abs(wc-StageC))
+            print "uh max  %.10f"%max(abs(uc*hc-XmomC))
+            print "u_max %.10f"%max(abs(uc-VelC))
+
+            from pylab import clf,plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot,ion
+            hold(False)
+            clf()
+        
+            plot1 = subplot(311)
+            plot(X,w,X,StageV,X,ElevationV)
+            #xlabel('Position')
+            ylabel('Stage')
+            plot1.set_ylim([-0.1,1.2])
+            legend(('Analytical Solution', 'Numerical Solution', 'Channel Bed'),
+                   'upper right', shadow=False)
+        
+            plot2 = subplot(312)
+            plot(X,u*h,X,XmomV)
+            #xlabel('x (m)')
+            ylabel('Momentum')
+            #plot2.set_ylim([0.299,0.301])
+        
+
+            plot3 = subplot(313)
+            plot(X,u, X,VelV)
+            xlabel('Position')
+            ylabel('Velocity')
+
+            #filename = "steady_"
+            #filename += str(t)
+            #filename += ".png"
+            #savefig(filename)
+            #show()
+    print 'That took %.2f seconds'%(time.time()-t0)
+    # #raw_input("Press return key!")
+    finaltime = finaltime + 0.2/71
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/steady_flow_supercritical.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/steady_flow_supercritical.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/steady_flow_supercritical.py	(revision 7576)
@@ -0,0 +1,191 @@
+import os
+#import Gnuplot
+from math import sqrt, pi
+from shallow_water_domain_suggestion1 import *
+from Numeric import allclose, array, zeros, ones, Float, take, sqrt
+from config import g, epsilon
+
+h_0 = 0.5
+u_0 = 0.6
+h_1 = 0.5
+u_1 = 0.6
+
+
+q = u_0*h_0
+g = 9.81
+
+b = 4.0
+xmax = 25.0
+z_bmax = 0.2
+Fr_0 = u_0/sqrt(g*h_0)
+
+def stage(x):
+    y,u,h = analytical_sol(x)
+    return y
+    
+
+def elevation(x):
+    b = 4.0
+    xmax = 25.0
+    z_bmax = 0.2
+    z_b = zeros(len(x),Float)
+    for i in range(len(x)):
+        if (x[i] >= xmax-b) & (x[i] <= xmax+b):
+            z_b[i] = z_bmax*(1.0-(x[i]-xmax)**2/b**2)
+        else:
+            z_b[i] = 0.0 
+    return z_b
+    #return 0.0
+
+def xmomentum(x):
+    return u_0*h_0
+
+
+def bisection(func,xR,xL,H):
+    while ((xR - xL) > epsilon):
+  
+        #Calculate midpoint of domain
+        xM = xL + (xR - xL) / 2.0
+  
+        #Find f(xM)
+        if ((f(xL,H) * f(xM,H)) > 0):
+            #Throw away left half
+            xL = xM
+        else:
+            #Throw away right half
+            xR = xM
+    return xR
+
+def f(D,H):
+    return D**3+D**2*(H-1.0-Fr_0**2/2.0)+Fr_0**2/2.0
+
+def fprime(D,H):
+    Fr_0 = u_0/sqrt(g*h_0)
+    return 3*D**2+2*D*(H-1-Fr_0**2/2.0)
+
+def analytical_sol(x):
+    y = zeros(len(x),Float)
+    u = zeros(len(x),Float)
+    height = zeros(len(x),Float)
+    for i in range(len(x)):
+        if (x[i] >= xmax-b) & (x[i] <= xmax+b):
+            zb = z_bmax*(1.0-(x[i]-xmax)**2/b**2)
+        else:
+            zb = 0.0 
+
+        H = zb/h_0
+        y1 = bisection(f,1.0,0.2/0.5,H)
+        height[i] = y1*h_0
+        y[i] = height[i]+zb
+        u[i] = q/(height[i])
+        
+
+    return y,u,height
+
+Fr_0 = u_0/sqrt(g*h_0)
+zb=0.2
+H = zb/h_0
+D = bisection(f,1,0.2/0.5,H)
+
+L = 50.0
+N = 400
+cell_len = L/N
+points = zeros(N+1,Float)
+for j in range(N+1):
+    points[j] = j*cell_len
+boundary = { (0,0): 'left',(N-1,1): 'right'}
+domain = Domain(points,boundary)
+D1 = Dirichlet_boundary([h_0,u_0*h_0,0.0,h_0,u_0])
+D2 = Dirichlet_boundary([h_1,u_1*h_1,0.0,h_1,u_1])
+
+domain.set_boundary({'left':D1,'right':D2})
+domain.set_quantity('elevation',elevation)
+domain.set_quantity('stage',stage)
+domain.set_quantity('xmomentum',xmomentum)
+X = domain.vertices
+C = domain.centroids
+
+Stage = domain.quantities['stage']
+Xmom = domain.quantities['xmomentum']
+Velocity = domain.quantities['velocity']
+
+StageV = Stage.vertex_values
+StageC = Stage.centroid_values
+XmomV = Xmom.vertex_values
+XmomC = Xmom.centroid_values
+VelC = Velocity.centroid_values
+VelV = Velocity.vertex_values
+ElevationV = domain.quantities['elevation'].vertex_values
+
+stage_bdry = Stage.boundary_values
+xmom_bdry =  Xmom.boundary_values
+
+w,u,h = analytical_sol(X.flat)
+wc, uc, hc = analytical_sol(C)
+
+#from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot,ylim,xlim, rc
+#hold(False)
+#rc('text', usetex=True)
+h_error = zeros(1,Float)
+uh_error = zeros(1,Float)
+u_error = zeros(1,Float)
+k = 0
+yieldstep = 5.0
+finaltime = 5.0
+domain.limiter = "superbee"
+domain.order = 2
+domain.set_timestepping_method('rk2')
+domain.cfl = 1.0
+print 'THE DOMAIN LIMITER is', domain.limiter
+import time
+t0=time.time()
+for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime):
+    domain.write_time()
+    print "integral", domain.quantities['stage'].get_integral()
+    if t>0.0:
+        from pylab import clf,plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot,ion
+        #ion()
+        hold(False)
+        #rc('text', usetex=True)
+        clf()
+        
+        plot1 = subplot(311)
+        plot(X,w,X,StageV,X,ElevationV)
+        #xlabel('Position')
+        ylabel('Stage')
+        plot1.set_ylim([-0.1,1.2])
+        legend(('Analytical Solution', 'Numerical Solution', 'Channel Bed'),
+               'upper right', shadow=False)
+        
+        plot2 = subplot(312)
+        plot(X,u*h,X,XmomV)#/(StageV-ElevationV))
+        #xlabel('x (m)')
+        ylabel('Momentum')
+        #plot2.set_ylim([0.299,0.301])
+        
+
+        plot3 = subplot(313)
+        #print 'len(uc)=',uc
+        #print 'len(VelC)=',VelC
+        #print 'len(X)=',X
+        plot(X,u, X,VelV)
+        xlabel('Position')
+        ylabel('Velocity')
+        
+        h_error[k] = 1.0/(N)*sum(abs(wc-StageC))
+        uh_error[k] = 1.0/(N)*sum(abs(uc*hc-XmomC))
+        u_error[k] = 1.0/(N)*sum(abs(uc-VelC))
+        print "h_error %.10f" %(h_error[k])
+        print "uh_error %.10f"% (uh_error[k])
+        print "u_error %.10f"% (u_error[k])
+        print "h_max %.10f"%max(abs(wc-StageC))
+        print "uh max  %.10f"%max(abs(uc*hc-XmomC))
+        print "u_max %.10f"%max(abs(uc-VelC))
+        #filename = "steady_flow_"
+        #filename += domain.limiter
+        #filename += str(400)
+        #filename += ".ps"
+        #savefig(filename)
+        #show()
+print 'That took %.2f seconds'%(time.time()-t0)
+raw_input("Press return key!")
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/subcritical_single.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/subcritical_single.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/subcritical_single.py	(revision 7576)
@@ -0,0 +1,115 @@
+import os
+from math import sqrt, pi
+from shallow_water_1d import *
+from Numeric import allclose, array, zeros, ones, Float, take, sqrt
+from config import g, epsilon
+from analytic_dam import AnalyticDam
+
+
+h0 = 5.0
+h1 = 10.0
+
+analytical_sol = AnalyticDam(h0, h1)
+
+def newLinePlot(title='Simple Plot'):
+    import Gnuplot
+    g = Gnuplot.Gnuplot(persist=1)
+    g.title(title)
+    g('set data style linespoints') 
+    g.xlabel('x')
+    g.ylabel('y')
+    return g
+
+def linePlot(g,x1,y1,x2,y2):
+    import Gnuplot
+    plot1 = Gnuplot.PlotItems.Data(x1.flat,y1.flat,with="linespoints")
+    plot2 = Gnuplot.PlotItems.Data(x2.flat,y2.flat, with="lines 3")
+    g.plot(plot1,plot2)
+    #g.plot(Gnuplot.PlotItems.Data(x1.flat,y1.flat),with="linespoints")
+    #g.plot(Gnuplot.PlotItems.Data(x2.flat,y2.flat), with="lines")
+
+def stage(x):
+    y = zeros(len(x),Float)
+    for i in range(len(x)):
+        if x[i]<=1000.0:
+            y[i] = h1
+        else:
+            y[i] = h0
+    return y
+
+
+import time
+finaltime = 30.0
+yieldstep = finaltime
+
+L = 2000.0     # Length of channel (m)
+#number_of_cells = [25,50,100,200,400,800,1600,3200,6400,12800,25600]
+number_of_cells = [20]
+h_error = zeros(len(number_of_cells),Float)
+uh_error = zeros(len(number_of_cells),Float)
+k = 0
+for i in range(len(number_of_cells)):
+    N = int(number_of_cells[i])
+    print "Evaluating domain with",N,"cells"
+    cell_len = L/N # Origin = 0.0
+    points = zeros(N+1,Float)
+    for j in range(N+1):
+        points[j] = j*cell_len
+    domain = Domain(points)
+    domain.set_quantity('stage', stage)
+    domain.set_boundary({'exterior': Reflective_boundary(domain)})
+    domain.default_order = 2
+    domain.default_time_order = 2
+    print "time order", domain.default_time_order
+    domain.cfl = 1.0
+    domain.beta = 1.0
+    domain.limiter = "steve_minmod"
+    #domain.limiter = "superbee"
+    init_integral = domain.quantities['stage'].get_integral()
+    t0 = time.time()
+    for t in domain.evolve(yieldstep = yieldstep, finaltime = finaltime):
+        pass
+    N = float(N)
+    assert(allclose(domain.quantities['stage'].get_integral(),init_integral))
+    StageC = domain.quantities['stage'].centroid_values
+    XmomC = domain.quantities['xmomentum'].centroid_values
+    C = domain.centroids
+    h, uh = analytical_sol(C,domain.time)
+    h_error[k] = 1.0/(N)*sum(abs(h-StageC))
+    uh_error[k] = 1.0/(N)*sum(abs(uh-XmomC))
+    print "h_error %.10f" %(h_error[k])
+    print "uh_error %.10f"% (uh_error[k])
+    k = k+1
+    print 'That took %.2f seconds' %(time.time()-t0)
+    X = domain.vertices
+    StageQ = domain.quantities['stage'].vertex_values
+    XmomQ = domain.quantities['xmomentum'].vertex_values
+    h, uh = analytical_sol(X.flat,domain.time)
+    from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot#,rc
+    #rc('text', usetex=True)
+    hold(False)
+    plot1 = subplot(211)
+    plot(X,h,X,StageQ)
+    plot1.set_ylim([4,11])
+    #title('Free Surface Elevation of a Dry Dam-Break')
+    #ylabel('Stage (m)')
+    #legend(('Analytical Solution', 'Numerical Solution'),
+    #       'upper right', shadow=True)
+    #plot2 = subplot(212)
+    #plot(X,uh,X,XmomQ)
+    #plot2.set_ylim([-1,25])
+    #title('Xmomentum Profile of a Dry Dam-Break')
+    #xlabel('x (m)')
+    #ylabel(r'X-momentum ($m^2/s$)')
+    #legend(('Analytical Solution', 'Numerical Solution'),
+    #       'upper right', shadow=True)
+    #filename = "subcritical_flow_s2_t2_"
+    #filename += domain.limiter
+    #filename += str(number_of_cells[i])
+    #filename += ".eps"
+    #savefig(filename)
+    show()
+
+print "Error in height", h_error
+print "Error in xmom", uh_error
+
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_discontinuousZ_with_nonzeroV.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_discontinuousZ_with_nonzeroV.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_discontinuousZ_with_nonzeroV.py	(revision 7576)
@@ -0,0 +1,116 @@
+import os
+import time
+from math import sqrt, sin, cos, pi, exp
+from shallow_water_domain_suggestion3 import *
+from Numeric import zeros, Float
+from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+
+print "TEST 1D-SOLUTION I"
+L=2000.0
+N=8
+
+cell_len=L/N
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+domain.order = 2
+domain.set_timestepping_method('rk2')
+domain.cfl = 1.0
+domain.limiter = "minmod"
+
+def stage(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 1750 <= x[i] < 2000.0:
+            y[i] = 13.0
+        else:
+            y[i] = 0.0
+    return y
+
+def momentum(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 1500.0 <= x[i] < 1750.0:
+            y[i] = -400.0 #-150.0
+        else:
+            y[i] = 0.0
+    return y
+
+
+def elevation(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 0 <= x[i] < 1250.0:
+            y[i] = 12.0
+        elif 1250.0 <= x[i] < 1500.0:
+            y[i] = 4.0
+        else:
+            y[i] = 0.0
+    return y
+
+domain.set_quantity('stage',stage)
+domain.set_quantity('elevation',elevation)
+domain.set_quantity('xmomentum',momentum)
+
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+X=domain.vertices
+C=domain.centroids
+
+t0=time.time()
+yieldstep=finaltime=10.0
+while finaltime < 300.2:
+    for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+        domain.write_time()
+        print "t=",t
+        print "integral", domain.quantities['height'].get_integral()
+
+        VelC = domain.quantities['velocity'].centroid_values
+        StageC = domain.quantities['stage'].centroid_values
+        ElevC = domain.quantities['elevation'].centroid_values
+        HeightC = domain.quantities['height'].centroid_values
+        XmomV = domain.quantities['xmomentum'].centroid_values
+        
+        print "StageC  = ", StageC
+        print "XmomC   = ", XmomV
+        print "ElevC   = ", ElevC
+        print "HeightC = ", HeightC
+        print "VelC    = ", VelC
+        
+        StageQ=domain.quantities['stage'].vertex_values
+        MomentumQ=domain.quantities['xmomentum'].vertex_values
+        ElevationQ=domain.quantities['elevation'].vertex_values
+        VelocityQ=domain.quantities['velocity'].vertex_values
+
+        hold(False)
+        plot1 = subplot(311)
+        plot(X,StageQ, X,ElevationQ)
+        plot1.set_ylim([-1.0,15.5])
+        xlabel('Position')
+        ylabel('Stage')
+        legend( ('Numerical Solution', 'Bed Elevation'), 'upper right', shadow=False)
+
+        plot2 = subplot(312)
+        plot(X,MomentumQ)
+        #plot2.set_ylim([3.998,4.002])
+        legend( ('Numerical Solution', 'for momentum'), 'upper right', shadow=False)
+        xlabel('Position')
+        ylabel('Xmomentum')
+
+        plot3 = subplot(313)
+        plot(X,VelocityQ)
+        #plot2.set_ylim([-5.0,30.0])
+        legend( ('Numerical Solution', 'for velocity'), 'upper right', shadow=False)
+        xlabel('Position')
+        ylabel('Velocity')
+        
+        #file = "island_"
+        #file += str(finaltime)
+        #file += ".png"
+        #savefig(file)
+        #show()
+        
+    print 'That took %.2f seconds'%(time.time()-t0)
+    finaltime = finaltime + 10.0
+    raw_input("Press return key")
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_discontinuous_z.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_discontinuous_z.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_discontinuous_z.py	(revision 7576)
@@ -0,0 +1,192 @@
+import os
+import time
+from math import sqrt, sin, cos, pi, exp
+from shallow_water_domain_suggestion2 import *
+from Numeric import zeros, Float
+from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+
+print "TEST 1D-SOLUTION I"
+L=2000.0
+N=4
+
+cell_len=L/N
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+domain.order = 1
+domain.set_timestepping_method('euler')
+domain.cfl = 1.0
+domain.limiter = "minmod"
+
+def stage_flat(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        y[i]=4.0
+    return y
+
+def elevation_arbitrary(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 0 <= x[i] < 200.0:
+            y[i] = -0.01*(x[i]-200) + 4.0
+        elif 200.0 <= x[i] < 300.0:
+            y[i] = -0.02*(x[i]-200) + 4.0
+        elif 300.0 <= x[i] < 400.0:
+            y[i] = -0.01*(x[i]-300) + 2.0
+        elif 400.0 <= x[i] < 550.0:
+            y[i] = (-1/75.0)*(x[i]-400.0) + 2.0
+        elif 550.0 <= x[i] < 700.0:
+            y[i] = (1/11250)*(x[i]-550)*(x[i]-550)
+        elif 700.0 <= x[i] < 800.0:
+            y[i] = 0.03*(x[i]-700)
+        elif 800.0 <= x[i] < 900.0:
+            y[i] = -0.03*(x[i]-800) + 3.0
+        elif 900.0 <= x[i] < 1000.0:
+            y[i] = 6.0
+        elif 1000.0 <= x[i] < 1400.0:
+            y[i] = (-1.0/20000)*(x[i]-1000)*(x[i]-1400)
+        elif 1400.0 <= x[i] < 1500.0:
+            y[i] = 0.0
+        elif 1500.0 <= x[i] < 1700.0:
+            y[i] = 3.0
+        elif 1700.0 <= x[i] < 1800.0:
+            y[i] = -0.03*(x[i]-1700) + 3.0
+        else:
+            y[i] = (3.0/40000)*(x[i]-1800)*(x[i]-1800) + 2.0
+    return y
+
+def elevation_arbitrary1(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 0 <= x[i] < 200.0:
+            y[i] = -0.01*(x[i]-200) + 5.0
+        elif 200.0 <= x[i] < 900.0:
+            y[i] = 0.0
+        elif 900.0 <= x[i] < 1000.0:    # This is the island
+            y[i] = 5.0
+        elif 1000.0 <= x[i] < 1800.0:
+            y[i] = 0.0
+        else:
+            y[i] = 0.03*(x[i]-1700) + 3.0
+    return y
+
+def elevation_arbitrary2(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 0 <= x[i] < 1000.0:          # This is the island
+            y[i] = 5.0
+        else:
+            y[i] = 0.0
+    return y
+
+domain.set_quantity('stage',stage_flat)
+domain.set_quantity('elevation',elevation_arbitrary2)
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+X=domain.vertices
+C=domain.centroids
+
+yieldstep = 1.0
+finaltime = 10.0
+
+#---------------------------------------------------------
+# Start of step
+#---------------------------------------------------------
+
+domain._order_ = domain.default_order
+	
+domain.finaltime = float(finaltime)
+
+domain.yieldtime = 0.0 # Track time between 'yields'
+
+# Initialise interval of timestep sizes (for reporting only)
+domain.min_timestep = 1.0e-10
+domain.max_timestep = 1.0
+domain.number_of_steps = 0
+domain.number_of_first_order_steps = 0
+
+
+
+# Update ghosts
+domain.update_ghosts()
+
+# Initial update of vertex and edge values
+domain.distribute_to_vertices_and_edges()
+
+# Update extrema if necessary (for reporting)
+#domain.update_extrema()
+
+# Initial update boundary values
+domain.update_boundary()
+
+# Compute fluxes across each element edge
+domain.compute_fluxes()
+
+# Update timestep to fit yieldstep and finaltime
+domain.update_timestep(yieldstep, finaltime)
+
+print 'timestep = ',domain.timestep
+
+
+# Update conserved quantities
+domain.update_conserved_quantities()
+
+# Update ghosts
+domain.update_ghosts()
+
+# Update vertex and edge values
+domain.distribute_to_vertices_and_edges()
+
+# Update boundary values
+domain.update_boundary()
+
+#------------------------------------------------------------
+# End od one step
+#------------------------------------------------------------
+
+domain.write_time()
+print "integral", domain.quantities['height'].get_integral()
+StageQ=domain.quantities['stage'].vertex_values
+StageUp=domain.quantities['stage'].explicit_update
+MomentumQ=domain.quantities['xmomentum'].vertex_values
+MomentumUp=domain.quantities['xmomentum'].explicit_update
+
+ElevationQ=domain.quantities['elevation'].vertex_values
+VelocityQ=domain.quantities['velocity'].vertex_values
+
+print "momentum", MomentumQ
+
+print "StageUpdates", StageUp
+#StageUp=domain.quantities['stage'].explicit_update
+print "MomUpdates", MomentumUp
+hold(False)
+plot1 = subplot(311)
+plot(X,StageQ, X,ElevationQ)
+plot1.set_ylim([-1.0,8.0])
+xlabel('Position')
+ylabel('Stage')
+legend( ('Numerical Solution', 'Bed Elevation'), 'upper right', shadow=False)
+
+plot2 = subplot(312)
+plot(X,MomentumQ)
+#plot2.set_ylim([3.998,4.002])
+legend( ('Numerical Solution', 'for momentum'), 'upper right', shadow=False)
+xlabel('Position')
+ylabel('Xmomentum')
+
+plot3 = subplot(313)
+plot(X,VelocityQ)
+#plot2.set_ylim([-5.0,30.0])
+legend( ('Numerical Solution', 'for velocity'), 'upper right', shadow=False)
+xlabel('Position')
+ylabel('Velocity')
+
+#file = "island_"
+#file += str(finaltime)
+#file += ".png"
+#savefig(file)
+show()
+
+#print 'That took %.2f seconds'%(time.time()-t0)
+#raw_input("Press return key")
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_parabolic_cannal_sudi.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_parabolic_cannal_sudi.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_parabolic_cannal_sudi.py	(revision 7576)
@@ -0,0 +1,135 @@
+import os
+import time
+from math import sqrt, sin, cos, pi, exp
+from shallow_water_domain_suggestion2 import *
+from Numeric import zeros, Float
+from pylab import plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot
+
+print "TEST 1D-SOLUTION I"
+L=2000.0
+N=8
+
+cell_len=L/N
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+domain.order = 1
+domain.set_timestepping_method('euler')
+domain.cfl = 1.0
+domain.limiter = "minmod"
+
+def stage_flat(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 0.0 <= x[i] < 1000.0:
+            y[i] = 1.0
+        else:
+            y[i] = 6.0
+    return y
+
+def elevation_arbitrary(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 0 <= x[i] < 200.0:
+            y[i] = -0.01*(x[i]-200) + 4.0
+        elif 200.0 <= x[i] < 300.0:
+            y[i] = -0.02*(x[i]-200) + 4.0
+        elif 300.0 <= x[i] < 400.0:
+            y[i] = -0.01*(x[i]-300) + 2.0
+        elif 400.0 <= x[i] < 550.0:
+            y[i] = (-1/75.0)*(x[i]-400.0) + 2.0
+        elif 550.0 <= x[i] < 700.0:
+            y[i] = (1/11250)*(x[i]-550)*(x[i]-550)
+        elif 700.0 <= x[i] < 800.0:
+            y[i] = 0.03*(x[i]-700)
+        elif 800.0 <= x[i] < 900.0:
+            y[i] = -0.03*(x[i]-800) + 3.0
+        elif 900.0 <= x[i] < 1000.0:
+            y[i] = 6.0
+        elif 1000.0 <= x[i] < 1400.0:
+            y[i] = (-1.0/20000)*(x[i]-1000)*(x[i]-1400)
+        elif 1400.0 <= x[i] < 1500.0:
+            y[i] = 0.0
+        elif 1500.0 <= x[i] < 1700.0:
+            y[i] = 3.0
+        elif 1700.0 <= x[i] < 1800.0:
+            y[i] = -0.03*(x[i]-1700) + 3.0
+        else:
+            y[i] = (3.0/40000)*(x[i]-1800)*(x[i]-1800) + 2.0
+    return y
+
+def elevation_arbitrary1(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 0 <= x[i] < 200.0:
+            y[i] = -0.01*(x[i]-200) + 5.0
+        elif 200.0 <= x[i] < 900.0:
+            y[i] = 0.0
+        elif 900.0 <= x[i] < 1000.0:    # This is the island
+            y[i] = 5.0
+        elif 1000.0 <= x[i] < 1800.0:
+            y[i] = 0.0
+        else:
+            y[i] = 0.03*(x[i]-1700) + 3.0
+    return y
+
+def elevation_arbitrary2(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if 0 <= x[i] < 1000.0:
+            y[i] = 0.0
+        else:
+            y[i] = 4.0
+    return y
+
+domain.set_quantity('stage',stage_flat)
+domain.set_quantity('elevation',elevation_arbitrary2)
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+X=domain.vertices
+C=domain.centroids
+
+t0=time.time()
+yieldstep=finaltime=1.0
+while finaltime < 10.2:
+    for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+        domain.write_time()
+        print "t=",t
+        print "integral", domain.quantities['height'].get_integral()
+        StageQ=domain.quantities['stage'].vertex_values
+        MomentumQ=domain.quantities['xmomentum'].vertex_values
+        ElevationQ=domain.quantities['elevation'].vertex_values
+        VelocityQ=domain.quantities['velocity'].vertex_values
+
+        hold(False)
+        plot1 = subplot(311)
+        plot(X,StageQ, X,ElevationQ)
+        plot1.set_ylim([-1.0,8.0])
+        xlabel('Position')
+        ylabel('Stage')
+        legend( ('Numerical Solution', 'Bed Elevation'), 'upper right', shadow=False)
+
+        plot2 = subplot(312)
+        plot(X,MomentumQ)
+        #plot2.set_ylim([3.998,4.002])
+        legend( ('Numerical Solution', 'for momentum'), 'upper right', shadow=False)
+        xlabel('Position')
+        ylabel('Xmomentum')
+
+        plot3 = subplot(313)
+        plot(X,VelocityQ)
+        #plot2.set_ylim([-5.0,30.0])
+        legend( ('Numerical Solution', 'for velocity'), 'upper right', shadow=False)
+        xlabel('Position')
+        ylabel('Velocity')
+        
+        #file = "island_"
+        #file += str(finaltime)
+        #file += ".png"
+        #savefig(file)
+        #show()
+        
+    print 'That took %.2f seconds'%(time.time()-t0)
+    finaltime = finaltime + 1.0
+raw_input("Press return key")
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_quantity.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_quantity.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_quantity.py	(revision 7576)
@@ -0,0 +1,2472 @@
+#!/usr/bin/env python
+
+import unittest
+from math import sqrt, pi
+import tempfile
+
+from quantity import *
+from config import epsilon
+from Numeric import allclose, array, ones, Float
+       
+from domain import Domain
+
+
+#Aux for fit_interpolate.fit example
+def linear_function(point):
+    point = array(point)
+    return point[:,0]+point[:,1]
+
+
+class Test_Quantity(unittest.TestCase):
+    def setUp(self):
+        from domain import Domain
+
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0, 0.0]
+        d = [0.0, 4.0]
+        e = [2.0, 2.0]
+        f = [4.0, 0.0]
+
+        points = [a, b, c, d, e, f]
+
+        #bac, bce, ecf, dbe
+        elements = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4] ]
+
+        self.mesh1 = Domain(points[:3], [elements[0]])
+        self.mesh1.check_integrity()
+
+        self.mesh4 = Domain(points, elements)
+        self.mesh4.check_integrity()
+
+        # UTM round Onslow
+        a = [240000, 7620000]
+        b = [240000, 7680000]
+        c = [300000, 7620000]
+
+        points = [a, b, c]
+        elements = [[0,2,1]]
+        
+        self.mesh_onslow = Domain(points, elements)
+        self.mesh_onslow.check_integrity()
+        
+    def tearDown(self):
+        pass
+        #print "  Tearing down"
+
+
+    def test_creation(self):
+
+        quantity = Quantity(self.mesh1, [[1,2,3]])
+        assert allclose(quantity.vertex_values, [[1.,2.,3.]])
+
+        try:
+            quantity = Quantity()
+        except:
+            pass
+        else:
+            raise 'Should have raised empty quantity exception'
+
+
+        try:
+            quantity = Quantity([1,2,3])
+        except AssertionError:
+            pass
+        except:
+            raise 'Should have raised "mising mesh object" error'
+
+
+    def test_creation_zeros(self):
+
+        quantity = Quantity(self.mesh1)
+        assert allclose(quantity.vertex_values, [[0.,0.,0.]])
+
+
+        quantity = Quantity(self.mesh4)
+        assert allclose(quantity.vertex_values, [[0.,0.,0.], [0.,0.,0.],
+                                                 [0.,0.,0.], [0.,0.,0.]])
+
+
+    def test_interpolation(self):
+        quantity = Quantity(self.mesh1, [[1,2,3]])
+        assert allclose(quantity.centroid_values, [2.0]) #Centroid
+
+        assert allclose(quantity.edge_values, [[2.5, 2.0, 1.5]])
+
+
+    def test_interpolation2(self):
+        quantity = Quantity(self.mesh4,
+                            [[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]])
+        assert allclose(quantity.centroid_values, [2., 5., 3., 0.]) #Centroid
+
+
+        quantity.extrapolate_second_order()
+
+        #print quantity.vertex_values
+        assert allclose(quantity.vertex_values, [[3.5, -1.0, 3.5],
+                                                 [3.+2./3, 6.+2./3, 4.+2./3],
+                                                 [4.6, 3.4, 1.],
+                                                 [-5.0, 1.0, 4.0]])
+
+        #print quantity.edge_values
+        assert allclose(quantity.edge_values, [[1.25, 3.5, 1.25],
+                                               [5. + 2/3.0, 4.0 + 1.0/6, 5.0 + 1.0/6],
+                                               [2.2, 2.8, 4.0],
+                                               [2.5, -0.5, -2.0]])
+
+
+        #assert allclose(quantity.edge_values, [[2.5, 2.0, 1.5],
+        #                                       [5., 5., 5.],
+        #                                       [4.5, 4.5, 0.],
+        #                                       [3.0, -1.5, -1.5]])
+
+    def test_get_extrema_1(self):
+        quantity = Quantity(self.mesh4,
+                                      [[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]])
+        assert allclose(quantity.centroid_values, [2., 5., 3., 0.]) #Centroids
+
+        v = quantity.get_maximum_value()
+        assert v == 5
+
+        v = quantity.get_minimum_value()
+        assert v == 0        
+
+        i = quantity.get_maximum_index()
+        assert i == 1
+
+        i = quantity.get_minimum_index()
+        assert i == 3        
+        
+        x,y = quantity.get_maximum_location()
+        xref, yref = 4.0/3, 4.0/3
+        assert x == xref
+        assert y == yref
+
+        v = quantity.get_values(interpolation_points = [[x,y]])
+        assert allclose(v, 5)
+
+
+        x,y = quantity.get_minimum_location()
+        v = quantity.get_values(interpolation_points = [[x,y]])
+        assert allclose(v, 0)
+
+
+    def test_get_maximum_2(self):
+
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0,0.0]
+        d = [0.0, 4.0]
+        e = [2.0, 2.0]
+        f = [4.0,0.0]
+
+        points = [a, b, c, d, e, f]
+        #bac, bce, ecf, dbe
+        vertices = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        domain = Domain(points, vertices)
+
+        quantity = Quantity(domain)
+        quantity.set_values(lambda x, y: x+2*y) #2 4 4 6
+        
+        v = quantity.get_maximum_value()
+        assert v == 6
+
+        v = quantity.get_minimum_value()
+        assert v == 2        
+
+        i = quantity.get_maximum_index()
+        assert i == 3
+
+        i = quantity.get_minimum_index()
+        assert i == 0        
+        
+        x,y = quantity.get_maximum_location()
+        xref, yref = 2.0/3, 8.0/3
+        assert x == xref
+        assert y == yref
+
+        v = quantity.get_values(interpolation_points = [[x,y]])
+        assert allclose(v, 6)
+
+        x,y = quantity.get_minimum_location()        
+        v = quantity.get_values(interpolation_points = [[x,y]])
+        assert allclose(v, 2)
+
+        #Multiple locations for maximum -
+        #Test that the algorithm picks the first occurrence        
+        v = quantity.get_maximum_value(indices=[0,1,2])
+        assert allclose(v, 4)
+
+        i = quantity.get_maximum_index(indices=[0,1,2])
+        assert i == 1
+        
+        x,y = quantity.get_maximum_location(indices=[0,1,2])
+        xref, yref = 4.0/3, 4.0/3
+        assert x == xref
+        assert y == yref
+
+        v = quantity.get_values(interpolation_points = [[x,y]])
+        assert allclose(v, 4)        
+
+        # More test of indices......
+        v = quantity.get_maximum_value(indices=[2,3])
+        assert allclose(v, 6)
+
+        i = quantity.get_maximum_index(indices=[2,3])
+        assert i == 3
+        
+        x,y = quantity.get_maximum_location(indices=[2,3])
+        xref, yref = 2.0/3, 8.0/3
+        assert x == xref
+        assert y == yref
+
+        v = quantity.get_values(interpolation_points = [[x,y]])
+        assert allclose(v, 6)        
+
+        
+
+    def test_boundary_allocation(self):
+        quantity = Quantity(self.mesh4,
+                            [[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]])
+
+        assert quantity.boundary_values.shape[0] == len(self.mesh4.boundary)
+
+
+    def test_set_values(self):
+        quantity = Quantity(self.mesh4)
+
+
+        quantity.set_values([[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]],
+                            location = 'vertices')
+        assert allclose(quantity.vertex_values,
+                        [[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]])
+        assert allclose(quantity.centroid_values, [2., 5., 3., 0.]) #Centroid
+        assert allclose(quantity.edge_values, [[2.5, 2.0, 1.5],
+                                               [5., 5., 5.],
+                                               [4.5, 4.5, 0.],
+                                               [3.0, -1.5, -1.5]])
+
+
+        # Test default
+        quantity.set_values([[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]])
+        assert allclose(quantity.vertex_values,
+                        [[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]])
+        assert allclose(quantity.centroid_values, [2., 5., 3., 0.]) #Centroid
+        assert allclose(quantity.edge_values, [[2.5, 2.0, 1.5],
+                                               [5., 5., 5.],
+                                               [4.5, 4.5, 0.],
+                                               [3.0, -1.5, -1.5]])
+
+        # Test centroids
+        quantity.set_values([1,2,3,4], location = 'centroids')
+        assert allclose(quantity.centroid_values, [1., 2., 3., 4.]) #Centroid
+
+        # Test exceptions
+        try:
+            quantity.set_values([[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]],
+                                location = 'bas kamel tuba')
+        except:
+            pass
+
+
+        try:
+            quantity.set_values([[1,2,3], [0,0,9]])
+        except AssertionError:
+            pass
+        except:
+            raise 'should have raised Assertionerror'
+
+
+
+    def test_set_values_const(self):
+        quantity = Quantity(self.mesh4)
+
+        quantity.set_values(1.0, location = 'vertices')
+        assert allclose(quantity.vertex_values,
+                        [[1,1,1], [1,1,1], [1,1,1], [1, 1, 1]])
+
+        assert allclose(quantity.centroid_values, [1, 1, 1, 1]) #Centroid
+        assert allclose(quantity.edge_values, [[1, 1, 1],
+                                               [1, 1, 1],
+                                               [1, 1, 1],
+                                               [1, 1, 1]])
+
+
+        quantity.set_values(2.0, location = 'centroids')
+        assert allclose(quantity.centroid_values, [2, 2, 2, 2])
+
+
+    def test_set_values_func(self):
+        quantity = Quantity(self.mesh4)
+
+        def f(x, y):
+            return x+y
+
+        quantity.set_values(f, location = 'vertices')
+        #print "quantity.vertex_values",quantity.vertex_values
+        assert allclose(quantity.vertex_values,
+                        [[2,0,2], [2,2,4], [4,2,4], [4,2,4]])
+        assert allclose(quantity.centroid_values,
+                        [4.0/3, 8.0/3, 10.0/3, 10.0/3])
+        assert allclose(quantity.edge_values,
+                        [[1,2,1], [3,3,2], [3,4,3], [3,4,3]])
+
+
+        quantity.set_values(f, location = 'centroids')
+        assert allclose(quantity.centroid_values,
+                        [4.0/3, 8.0/3, 10.0/3, 10.0/3])
+
+
+    def test_integral(self):
+        quantity = Quantity(self.mesh4)
+
+        #Try constants first
+        const = 5
+        quantity.set_values(const, location = 'vertices')
+        #print 'Q', quantity.get_integral()
+
+        assert allclose(quantity.get_integral(), self.mesh4.get_area() * const)
+
+        #Try with a linear function
+        def f(x, y):
+            return x+y
+
+        quantity.set_values(f, location = 'vertices')
+
+
+        ref_integral = (4.0/3 + 8.0/3 + 10.0/3 + 10.0/3) * 2
+
+        assert allclose (quantity.get_integral(), ref_integral)
+
+
+
+    def test_set_vertex_values(self):
+        quantity = Quantity(self.mesh4)
+        quantity.set_vertex_values([0,1,2,3,4,5])
+
+        assert allclose(quantity.vertex_values,
+                        [[1,0,2], [1,2,4], [4,2,5], [3,1,4]])
+        assert allclose(quantity.centroid_values,
+                        [1., 7./3, 11./3, 8./3]) #Centroid
+        assert allclose(quantity.edge_values, [[1., 1.5, 0.5],
+                                               [3., 2.5, 1.5],
+                                               [3.5, 4.5, 3.],
+                                               [2.5, 3.5, 2]])
+
+
+    def test_set_vertex_values_subset(self):
+        quantity = Quantity(self.mesh4)
+        quantity.set_vertex_values([0,1,2,3,4,5])
+        quantity.set_vertex_values([0,20,30,50], indices = [0,2,3,5])
+
+        assert allclose(quantity.vertex_values,
+                        [[1,0,20], [1,20,4], [4,20,50], [30,1,4]])
+
+
+    def test_set_vertex_values_using_general_interface(self):
+        quantity = Quantity(self.mesh4)
+
+
+        quantity.set_values([0,1,2,3,4,5])
+
+
+        assert allclose(quantity.vertex_values,
+                        [[1,0,2], [1,2,4], [4,2,5], [3,1,4]])
+
+        #Centroid
+        assert allclose(quantity.centroid_values, [1., 7./3, 11./3, 8./3])
+
+        assert allclose(quantity.edge_values, [[1., 1.5, 0.5],
+                                               [3., 2.5, 1.5],
+                                               [3.5, 4.5, 3.],
+                                               [2.5, 3.5, 2]])
+
+
+
+    def test_set_vertex_values_using_general_interface_with_subset(self):
+        """test_set_vertex_values_using_general_interface_with_subset(self):
+        
+        Test that indices and polygon works (for constants values)
+        """
+        
+        quantity = Quantity(self.mesh4)
+
+
+        quantity.set_values([0,2,3,5], indices=[0,2,3,5])
+        assert allclose(quantity.vertex_values,
+                        [[0,0,2], [0,2,0], [0,2,5], [3,0,0]])
+
+
+        # Constant
+        quantity.set_values(0.0)
+        quantity.set_values(3.14, indices=[0,2], location='vertices')
+
+        # Indices refer to triangle numbers
+        assert allclose(quantity.vertex_values,
+                        [[3.14,3.14,3.14], [0,0,0],
+                         [3.14,3.14,3.14], [0,0,0]])        
+        
+
+
+        # Now try with polygon (pick points where y>2)
+        polygon = [[0,2.1], [4,2.1], [4,7], [0,7]]
+        quantity.set_values(0.0)
+        quantity.set_values(3.14, polygon=polygon)
+        
+        assert allclose(quantity.vertex_values,
+                        [[0,0,0], [0,0,0], [0,0,0],
+                         [3.14,3.14,3.14]])                
+
+
+        # Another polygon (pick triangle 1 and 2 (rightmost triangles) 
+        # using centroids
+        polygon = [[2.1, 0.0], [3.5,0.1], [2,2.2], [0.2,2]]
+        quantity.set_values(0.0)
+        quantity.set_values(3.14, location='centroids', polygon=polygon)
+        assert allclose(quantity.vertex_values,
+                        [[0,0,0],
+                         [3.14,3.14,3.14],
+                         [3.14,3.14,3.14],                         
+                         [0,0,0]])                
+
+
+        # Same polygon now use vertices (default)
+        polygon = [[2.1, 0.0], [3.5,0.1], [2,2.2], [0.2,2]]
+        quantity.set_values(0.0)
+        #print 'Here 2'
+        quantity.set_values(3.14, polygon=polygon)
+        assert allclose(quantity.vertex_values,
+                        [[0,0,0],
+                         [3.14,3.14,3.14],
+                         [3.14,3.14,3.14],                         
+                         [0,0,0]])                
+        
+
+        # Test input checking
+        try:
+            quantity.set_values(3.14, polygon=polygon, indices = [0,2])
+        except:
+            pass
+        else:
+            msg = 'Should have caught this'
+            raise msg
+
+
+
+
+
+    def test_set_vertex_values_using_general_interface_subset_and_geo(self):
+        """test_set_vertex_values_using_general_interface_with_subset(self):
+        Test that indices and polygon works using georeferencing
+        """
+        
+        quantity = Quantity(self.mesh4)
+        G = Geo_reference(56, 10, 100)
+        quantity.domain.geo_reference = G
+
+        #print quantity.domain.get_nodes(absolute=True)
+
+
+        # Constant
+        quantity.set_values(0.0)
+        quantity.set_values(3.14, indices=[0,2], location='vertices')
+
+        # Indices refer to triangle numbers here - not vertices (why?)
+        assert allclose(quantity.vertex_values,
+                        [[3.14,3.14,3.14], [0,0,0],
+                         [3.14,3.14,3.14], [0,0,0]])        
+        
+
+
+        # Now try with polygon (pick points where y>2)
+        polygon = array([[0,2.1], [4,2.1], [4,7], [0,7]])
+        polygon += [G.xllcorner, G.yllcorner]
+        
+        quantity.set_values(0.0)
+        quantity.set_values(3.14, polygon=polygon, location='centroids')
+        
+        assert allclose(quantity.vertex_values,
+                        [[0,0,0], [0,0,0], [0,0,0],
+                         [3.14,3.14,3.14]])                
+
+
+        # Another polygon (pick triangle 1 and 2 (rightmost triangles)
+        polygon = array([[2.1, 0.0], [3.5,0.1], [2,2.2], [0.2,2]])
+        polygon += [G.xllcorner, G.yllcorner]
+        
+        quantity.set_values(0.0)
+        quantity.set_values(3.14, polygon=polygon)
+
+        assert allclose(quantity.vertex_values,
+                        [[0,0,0],
+                         [3.14,3.14,3.14],
+                         [3.14,3.14,3.14],                         
+                         [0,0,0]])                
+
+
+
+    def test_set_values_using_fit(self):
+
+
+        quantity = Quantity(self.mesh4)
+
+        #Get (enough) datapoints
+        data_points = [[ 0.66666667, 0.66666667],
+                       [ 1.33333333, 1.33333333],
+                       [ 2.66666667, 0.66666667],
+                       [ 0.66666667, 2.66666667],
+                       [ 0.0, 1.0],
+                       [ 0.0, 3.0],
+                       [ 1.0, 0.0],
+                       [ 1.0, 1.0],
+                       [ 1.0, 2.0],
+                       [ 1.0, 3.0],
+                       [ 2.0, 1.0],
+                       [ 3.0, 0.0],
+                       [ 3.0, 1.0]]
+
+        z = linear_function(data_points)
+
+        #Use built-in fit_interpolate.fit
+        quantity.set_values( Geospatial_data(data_points, z), alpha = 0 )
+        #quantity.set_values(points = data_points, values = z, alpha = 0)
+
+
+        answer = linear_function(quantity.domain.get_vertex_coordinates())
+        #print quantity.vertex_values, answer
+        assert allclose(quantity.vertex_values.flat, answer)
+
+
+        #Now try by setting the same values directly
+        vertex_attributes = fit_to_mesh(data_points,
+                                        quantity.domain.get_nodes(),
+                                        quantity.domain.triangles, #FIXME
+                                        point_attributes=z,
+                                        alpha = 0,
+                                        verbose=False)
+
+        #print vertex_attributes
+        quantity.set_values(vertex_attributes)
+        assert allclose(quantity.vertex_values.flat, answer)
+
+
+
+
+
+    def test_test_set_values_using_fit_w_geo(self):
+
+
+        #Mesh
+        vertex_coordinates = [[0.76, 0.76],
+                              [0.76, 5.76],
+                              [5.76, 0.76]]
+        triangles = [[0,2,1]]
+
+        mesh_georef = Geo_reference(56,-0.76,-0.76)
+        mesh1 = Domain(vertex_coordinates, triangles,
+                       geo_reference = mesh_georef)
+        mesh1.check_integrity()
+
+        #Quantity
+        quantity = Quantity(mesh1)
+
+        #Data
+        data_points = [[ 201.0, 401.0],
+                       [ 201.0, 403.0],
+                       [ 203.0, 401.0]]
+
+        z = [2, 4, 4]
+
+        data_georef = Geo_reference(56,-200,-400)
+
+
+        #Reference
+        ref = fit_to_mesh(data_points, vertex_coordinates, triangles,
+                          point_attributes=z,
+                          data_origin = data_georef.get_origin(),
+                          mesh_origin = mesh_georef.get_origin(),
+                          alpha = 0)
+
+        assert allclose( ref, [0,5,5] )
+
+
+        #Test set_values
+
+        quantity.set_values( Geospatial_data(data_points, z, data_georef), alpha = 0 )
+
+        #quantity.set_values(points = data_points,
+        #                    values = z,
+        #                    data_georef = data_georef,
+        #                    alpha = 0)
+
+
+        #quantity.set_values(points = data_points,
+        #                    values = z,
+        #                    data_georef = data_georef,
+        #                    alpha = 0)
+        assert allclose(quantity.vertex_values.flat, ref)
+
+
+
+        #Test set_values using geospatial data object
+        quantity.vertex_values[:] = 0.0
+
+        geo = Geospatial_data(data_points, z, data_georef)
+
+
+        quantity.set_values(geospatial_data = geo, alpha = 0)
+        assert allclose(quantity.vertex_values.flat, ref)
+
+
+
+    def test_set_values_from_file1(self):
+        quantity = Quantity(self.mesh4)
+
+        #Get (enough) datapoints
+        data_points = [[ 0.66666667, 0.66666667],
+                       [ 1.33333333, 1.33333333],
+                       [ 2.66666667, 0.66666667],
+                       [ 0.66666667, 2.66666667],
+                       [ 0.0, 1.0],
+                       [ 0.0, 3.0],
+                       [ 1.0, 0.0],
+                       [ 1.0, 1.0],
+                       [ 1.0, 2.0],
+                       [ 1.0, 3.0],
+                       [ 2.0, 1.0],
+                       [ 3.0, 0.0],
+                       [ 3.0, 1.0]]
+
+        data_geo_spatial = Geospatial_data(data_points,
+                         geo_reference = Geo_reference(56, 0, 0))
+        data_points_absolute = data_geo_spatial.get_data_points(absolute=True)
+        attributes = linear_function(data_points_absolute)
+        att = 'spam_and_eggs'
+        
+        #Create .txt file
+        ptsfile = tempfile.mktemp(".txt")
+        file = open(ptsfile,"w")
+        file.write(" x,y," + att + " \n")
+        for data_point, attribute in map(None, data_points_absolute
+                                         ,attributes):
+            row = str(data_point[0]) + ',' + str(data_point[1]) \
+                  + ',' + str(attribute)
+            file.write(row + "\n")
+        file.close()
+
+
+        #Check that values can be set from file
+        quantity.set_values(filename = ptsfile,
+                            attribute_name = att, alpha = 0)
+        answer = linear_function(quantity.domain.get_vertex_coordinates())
+
+        #print quantity.vertex_values.flat
+        #print answer
+
+
+        assert allclose(quantity.vertex_values.flat, answer)
+
+
+        #Check that values can be set from file using default attribute
+        quantity.set_values(filename = ptsfile, alpha = 0)
+        assert allclose(quantity.vertex_values.flat, answer)
+
+        #Cleanup
+        import os
+        os.remove(ptsfile)
+
+
+
+    def Xtest_set_values_from_file_using_polygon(self):
+        """test_set_values_from_file_using_polygon(self):
+        
+        Test that polygon restriction works for general points data
+        """
+        
+        quantity = Quantity(self.mesh4)
+
+        #Get (enough) datapoints
+        data_points = [[ 0.66666667, 0.66666667],
+                       [ 1.33333333, 1.33333333],
+                       [ 2.66666667, 0.66666667],
+                       [ 0.66666667, 2.66666667],
+                       [ 0.0, 1.0],
+                       [ 0.0, 3.0],
+                       [ 1.0, 0.0],
+                       [ 1.0, 1.0],
+                       [ 1.0, 2.0],
+                       [ 1.0, 3.0],
+                       [ 2.0, 1.0],
+                       [ 3.0, 0.0],
+                       [ 3.0, 1.0]]
+
+        data_geo_spatial = Geospatial_data(data_points,
+                         geo_reference = Geo_reference(56, 0, 0))
+        data_points_absolute = data_geo_spatial.get_data_points(absolute=True)
+        attributes = linear_function(data_points_absolute)
+        att = 'spam_and_eggs'
+        
+        #Create .txt file
+        ptsfile = tempfile.mktemp(".txt")
+        file = open(ptsfile,"w")
+        file.write(" x,y," + att + " \n")
+        for data_point, attribute in map(None, data_points_absolute
+                                         ,attributes):
+            row = str(data_point[0]) + ',' + str(data_point[1]) \
+                  + ',' + str(attribute)
+            file.write(row + "\n")
+        file.close()
+
+        # Create restricting polygon (containing node #4 (2,2) and 
+        # centroid of triangle #1 (bce)
+        polygon = [[1.0, 1.0], [4.0, 1.0],
+                   [4.0, 4.0], [1.0, 4.0]]
+
+        #print self.mesh4.nodes
+        #print inside_polygon(self.mesh4.nodes, polygon)
+        assert allclose(inside_polygon(self.mesh4.nodes, polygon), 4)
+
+        #print quantity.domain.get_vertex_coordinates()
+        #print quantity.domain.get_nodes()        
+        
+        # Check that values can be set from file
+        quantity.set_values(filename=ptsfile,
+                            polygon=polygon,
+                            location='unique vertices',
+                            alpha=0)
+
+        # Get indices for vertex coordinates in polygon
+        indices = inside_polygon(quantity.domain.get_vertex_coordinates(), 
+                                 polygon)
+        points = take(quantity.domain.get_vertex_coordinates(), indices)
+        
+        answer = linear_function(points)
+
+        #print quantity.vertex_values.flat
+        #print answer
+
+        # Check vertices in polygon have been set
+        assert allclose(take(quantity.vertex_values.flat, indices),
+                             answer)
+
+        # Check vertices outside polygon are zero
+        indices = outside_polygon(quantity.domain.get_vertex_coordinates(), 
+                                  polygon)        
+        assert allclose(take(quantity.vertex_values.flat, indices),
+                             0.0)        
+
+        #Cleanup
+        import os
+        os.remove(ptsfile)
+
+
+        
+
+    def test_cache_test_set_values_from_file(self):
+        # FIXME (Ole): What is this about?
+        # I don't think it checks anything new
+        quantity = Quantity(self.mesh4)
+
+        #Get (enough) datapoints
+        data_points = [[ 0.66666667, 0.66666667],
+                       [ 1.33333333, 1.33333333],
+                       [ 2.66666667, 0.66666667],
+                       [ 0.66666667, 2.66666667],
+                       [ 0.0, 1.0],
+                       [ 0.0, 3.0],
+                       [ 1.0, 0.0],
+                       [ 1.0, 1.0],
+                       [ 1.0, 2.0],
+                       [ 1.0, 3.0],
+                       [ 2.0, 1.0],
+                       [ 3.0, 0.0],
+                       [ 3.0, 1.0]]
+
+        georef = Geo_reference(56, 0, 0)
+        data_geo_spatial = Geospatial_data(data_points,
+                                           geo_reference=georef)
+                                           
+        data_points_absolute = data_geo_spatial.get_data_points(absolute=True)
+        attributes = linear_function(data_points_absolute)
+        att = 'spam_and_eggs'
+        
+        # Create .txt file
+        ptsfile = tempfile.mktemp(".txt")
+        file = open(ptsfile,"w")
+        file.write(" x,y," + att + " \n")
+        for data_point, attribute in map(None, data_points_absolute
+                                         ,attributes):
+            row = str(data_point[0]) + ',' + str(data_point[1]) \
+                  + ',' + str(attribute)
+            file.write(row + "\n")
+        file.close()
+
+
+        # Check that values can be set from file
+        quantity.set_values(filename=ptsfile,
+                            attribute_name=att, 
+                            alpha=0, 
+                            use_cache=True,
+                            verbose=False)
+        answer = linear_function(quantity.domain.get_vertex_coordinates())
+        assert allclose(quantity.vertex_values.flat, answer)
+
+
+        # Check that values can be set from file using default attribute
+        quantity.set_values(filename=ptsfile, 
+                            alpha=0)
+        assert allclose(quantity.vertex_values.flat, answer)
+
+        # Check cache
+        quantity.set_values(filename=ptsfile,
+                            attribute_name=att, 
+                            alpha=0, 
+                            use_cache=True,
+                            verbose=False)
+        
+        
+        #Cleanup
+        import os
+        os.remove(ptsfile)
+
+    def test_set_values_from_lat_long(self):
+        quantity = Quantity(self.mesh_onslow)
+
+        #Get (enough) datapoints
+        data_points = [[-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6]]
+
+        data_geo_spatial = Geospatial_data(data_points,
+                                           points_are_lats_longs=True)
+        points_UTM = data_geo_spatial.get_data_points(absolute=True)
+        attributes = linear_function(points_UTM)
+        att = 'elevation'
+        
+        #Create .txt file
+        txt_file = tempfile.mktemp(".txt")
+        file = open(txt_file,"w")
+        file.write(" lat,long," + att + " \n")
+        for data_point, attribute in map(None, data_points, attributes):
+            row = str(data_point[0]) + ',' + str(data_point[1]) \
+                  + ',' + str(attribute)
+            #print "row", row 
+            file.write(row + "\n")
+        file.close()
+
+
+        #Check that values can be set from file
+        quantity.set_values(filename=txt_file,
+                            attribute_name=att, 
+                            alpha=0)
+        answer = linear_function(quantity.domain.get_vertex_coordinates())
+
+        #print "quantity.vertex_values.flat", quantity.vertex_values.flat
+        #print "answer",answer
+
+        assert allclose(quantity.vertex_values.flat, answer)
+
+
+        #Check that values can be set from file using default attribute
+        quantity.set_values(filename=txt_file, alpha=0)
+        assert allclose(quantity.vertex_values.flat, answer)
+
+        #Cleanup
+        import os
+        os.remove(txt_file)
+         
+    def test_set_values_from_lat_long(self):
+        quantity = Quantity(self.mesh_onslow)
+
+        #Get (enough) datapoints
+        data_points = [[-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6]]
+
+        data_geo_spatial = Geospatial_data(data_points,
+                                           points_are_lats_longs=True)
+        points_UTM = data_geo_spatial.get_data_points(absolute=True)
+        attributes = linear_function(points_UTM)
+        att = 'elevation'
+        
+        #Create .txt file
+        txt_file = tempfile.mktemp(".txt")
+        file = open(txt_file,"w")
+        file.write(" lat,long," + att + " \n")
+        for data_point, attribute in map(None, data_points, attributes):
+            row = str(data_point[0]) + ',' + str(data_point[1]) \
+                  + ',' + str(attribute)
+            #print "row", row 
+            file.write(row + "\n")
+        file.close()
+
+
+        #Check that values can be set from file
+        quantity.set_values(filename=txt_file,
+                            attribute_name=att, alpha=0)
+        answer = linear_function(quantity.domain.get_vertex_coordinates())
+
+        #print "quantity.vertex_values.flat", quantity.vertex_values.flat
+        #print "answer",answer
+
+        assert allclose(quantity.vertex_values.flat, answer)
+
+
+        #Check that values can be set from file using default attribute
+        quantity.set_values(filename=txt_file, alpha=0)
+        assert allclose(quantity.vertex_values.flat, answer)
+
+        #Cleanup
+        import os
+        os.remove(txt_file)
+        
+    def test_set_values_from_UTM_pts(self):
+        quantity = Quantity(self.mesh_onslow)
+
+        #Get (enough) datapoints
+        data_points = [[-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6]]
+
+        data_geo_spatial = Geospatial_data(data_points,
+                                           points_are_lats_longs=True)
+        points_UTM = data_geo_spatial.get_data_points(absolute=True)
+        attributes = linear_function(points_UTM)
+        att = 'elevation'
+        
+        #Create .txt file
+        txt_file = tempfile.mktemp(".txt")
+        file = open(txt_file,"w")
+        file.write(" x,y," + att + " \n")
+        for data_point, attribute in map(None, points_UTM, attributes):
+            row = str(data_point[0]) + ',' + str(data_point[1]) \
+                  + ',' + str(attribute)
+            #print "row", row 
+            file.write(row + "\n")
+        file.close()
+
+
+        pts_file = tempfile.mktemp(".pts")        
+        convert = Geospatial_data(txt_file)
+        convert.export_points_file(pts_file)
+
+        #Check that values can be set from file
+        quantity.set_values_from_file(pts_file, att, 0,
+                                      'vertices', None)
+        answer = linear_function(quantity.domain.get_vertex_coordinates())
+        #print "quantity.vertex_values.flat", quantity.vertex_values.flat
+        #print "answer",answer
+        assert allclose(quantity.vertex_values.flat, answer)
+
+        #Check that values can be set from file
+        quantity.set_values(filename=pts_file,
+                            attribute_name=att, alpha=0)
+        answer = linear_function(quantity.domain.get_vertex_coordinates())
+        #print "quantity.vertex_values.flat", quantity.vertex_values.flat
+        #print "answer",answer
+        assert allclose(quantity.vertex_values.flat, answer)
+
+
+        #Check that values can be set from file using default attribute
+        quantity.set_values(filename=txt_file, alpha=0)
+        assert allclose(quantity.vertex_values.flat, answer)
+
+        #Cleanup
+        import os
+        os.remove(txt_file)
+        os.remove(pts_file)
+        
+    def verbose_test_set_values_from_UTM_pts(self):
+        quantity = Quantity(self.mesh_onslow)
+
+        #Get (enough) datapoints
+        data_points = [[-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6],
+                       [-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6],
+                       [-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6],
+                       [-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6],
+                       [-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6],
+                       [-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6],
+                       [-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6],
+                       [-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6],
+                       [-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6],
+                       [-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6],
+                       [-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6],
+                       [-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6],
+                       [-21.5, 114.5],[-21.4, 114.6],[-21.45,114.65],
+                       [-21.35, 114.65],[-21.45, 114.55],[-21.45,114.6],
+                       ]
+
+        data_geo_spatial = Geospatial_data(data_points,
+                                           points_are_lats_longs=True)
+        points_UTM = data_geo_spatial.get_data_points(absolute=True)
+        attributes = linear_function(points_UTM)
+        att = 'elevation'
+        
+        #Create .txt file
+        txt_file = tempfile.mktemp(".txt")
+        file = open(txt_file,"w")
+        file.write(" x,y," + att + " \n")
+        for data_point, attribute in map(None, points_UTM, attributes):
+            row = str(data_point[0]) + ',' + str(data_point[1]) \
+                  + ',' + str(attribute)
+            #print "row", row 
+            file.write(row + "\n")
+        file.close()
+
+
+        pts_file = tempfile.mktemp(".pts")        
+        convert = Geospatial_data(txt_file)
+        convert.export_points_file(pts_file)
+
+        #Check that values can be set from file
+        quantity.set_values_from_file(pts_file, att, 0,
+                                      'vertices', None, verbose = True,
+                                      max_read_lines=2)
+        answer = linear_function(quantity.domain.get_vertex_coordinates())
+        #print "quantity.vertex_values.flat", quantity.vertex_values.flat
+        #print "answer",answer
+        assert allclose(quantity.vertex_values.flat, answer)
+
+        #Check that values can be set from file
+        quantity.set_values(filename=pts_file,
+                            attribute_name=att, alpha=0)
+        answer = linear_function(quantity.domain.get_vertex_coordinates())
+        #print "quantity.vertex_values.flat", quantity.vertex_values.flat
+        #print "answer",answer
+        assert allclose(quantity.vertex_values.flat, answer)
+
+
+        #Check that values can be set from file using default attribute
+        quantity.set_values(filename=txt_file, alpha=0)
+        assert allclose(quantity.vertex_values.flat, answer)
+
+        #Cleanup
+        import os
+        os.remove(txt_file)
+        os.remove(pts_file)
+        
+    def test_set_values_from_file_with_georef1(self):
+
+        #Mesh in zone 56 (absolute coords)
+
+        x0 = 314036.58727982
+        y0 = 6224951.2960092
+
+        a = [x0+0.0, y0+0.0]
+        b = [x0+0.0, y0+2.0]
+        c = [x0+2.0, y0+0.0]
+        d = [x0+0.0, y0+4.0]
+        e = [x0+2.0, y0+2.0]
+        f = [x0+4.0, y0+0.0]
+
+        points = [a, b, c, d, e, f]
+
+        #bac, bce, ecf, dbe
+        elements = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4] ]
+
+        #absolute going in ..
+        mesh4 = Domain(points, elements,
+                       geo_reference = Geo_reference(56, 0, 0))
+        mesh4.check_integrity()
+        quantity = Quantity(mesh4)
+
+        #Get (enough) datapoints (relative to georef)
+        data_points_rel = [[ 0.66666667, 0.66666667],
+                       [ 1.33333333, 1.33333333],
+                       [ 2.66666667, 0.66666667],
+                       [ 0.66666667, 2.66666667],
+                       [ 0.0, 1.0],
+                       [ 0.0, 3.0],
+                       [ 1.0, 0.0],
+                       [ 1.0, 1.0],
+                       [ 1.0, 2.0],
+                       [ 1.0, 3.0],
+                       [ 2.0, 1.0],
+                       [ 3.0, 0.0],
+                       [ 3.0, 1.0]]
+
+        data_geo_spatial = Geospatial_data(data_points_rel,
+                         geo_reference = Geo_reference(56, x0, y0))
+        data_points_absolute = data_geo_spatial.get_data_points(absolute=True)
+        attributes = linear_function(data_points_absolute)
+        att = 'spam_and_eggs'
+        
+        #Create .txt file
+        ptsfile = tempfile.mktemp(".txt")
+        file = open(ptsfile,"w")
+        file.write(" x,y," + att + " \n")
+        for data_point, attribute in map(None, data_points_absolute
+                                         ,attributes):
+            row = str(data_point[0]) + ',' + str(data_point[1]) \
+                  + ',' + str(attribute)
+            file.write(row + "\n")
+        file.close()
+
+        #file = open(ptsfile, 'r')
+        #lines = file.readlines()
+        #file.close()
+     
+
+        #Check that values can be set from file
+        quantity.set_values(filename=ptsfile,
+                            attribute_name=att, alpha=0)
+        answer = linear_function(quantity.domain.get_vertex_coordinates())
+
+        assert allclose(quantity.vertex_values.flat, answer)
+
+
+        #Check that values can be set from file using default attribute
+        quantity.set_values(filename=ptsfile, alpha=0)
+        assert allclose(quantity.vertex_values.flat, answer)
+
+        #Cleanup
+        import os
+        os.remove(ptsfile)
+
+
+    def test_set_values_from_file_with_georef2(self):
+
+        #Mesh in zone 56 (relative coords)
+
+        x0 = 314036.58727982
+        y0 = 6224951.2960092
+        #x0 = 0.0
+        #y0 = 0.0
+
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0, 0.0]
+        d = [0.0, 4.0]
+        e = [2.0, 2.0]
+        f = [4.0, 0.0]
+
+        points = [a, b, c, d, e, f]
+
+        #bac, bce, ecf, dbe
+        elements = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4] ]
+
+        mesh4 = Domain(points, elements,
+                       geo_reference = Geo_reference(56, x0, y0))
+        mesh4.check_integrity()
+        quantity = Quantity(mesh4)
+
+        #Get (enough) datapoints
+        data_points = [[ x0+0.66666667, y0+0.66666667],
+                       [ x0+1.33333333, y0+1.33333333],
+                       [ x0+2.66666667, y0+0.66666667],
+                       [ x0+0.66666667, y0+2.66666667],
+                       [ x0+0.0, y0+1.0],
+                       [ x0+0.0, y0+3.0],
+                       [ x0+1.0, y0+0.0],
+                       [ x0+1.0, y0+1.0],
+                       [ x0+1.0, y0+2.0],
+                       [ x0+1.0, y0+3.0],
+                       [ x0+2.0, y0+1.0],
+                       [ x0+3.0, y0+0.0],
+                       [ x0+3.0, y0+1.0]]
+
+
+        data_geo_spatial = Geospatial_data(data_points,
+                         geo_reference = Geo_reference(56, 0, 0))
+        data_points_absolute = data_geo_spatial.get_data_points(absolute=True)
+        attributes = linear_function(data_points_absolute)
+        att = 'spam_and_eggs'
+        
+        #Create .txt file
+        ptsfile = tempfile.mktemp(".txt")
+        file = open(ptsfile,"w")
+        file.write(" x,y," + att + " \n")
+        for data_point, attribute in map(None, data_points_absolute
+                                         ,attributes):
+            row = str(data_point[0]) + ',' + str(data_point[1]) \
+                  + ',' + str(attribute)
+            file.write(row + "\n")
+        file.close()
+
+
+        #Check that values can be set from file
+        quantity.set_values(filename=ptsfile,
+                            attribute_name=att, alpha=0)
+        answer = linear_function(quantity.domain. \
+                                 get_vertex_coordinates(absolute=True))
+
+
+        assert allclose(quantity.vertex_values.flat, answer)
+
+
+        #Check that values can be set from file using default attribute
+        quantity.set_values(filename=ptsfile, alpha=0)
+        assert allclose(quantity.vertex_values.flat, answer)
+
+        #Cleanup
+        import os
+        os.remove(ptsfile)
+
+
+
+
+    def test_set_values_from_quantity(self):
+
+        quantity1 = Quantity(self.mesh4)
+        quantity1.set_vertex_values([0,1,2,3,4,5])
+
+        assert allclose(quantity1.vertex_values,
+                        [[1,0,2], [1,2,4], [4,2,5], [3,1,4]])
+
+
+        quantity2 = Quantity(self.mesh4)
+        quantity2.set_values(quantity=quantity1)
+        assert allclose(quantity2.vertex_values,
+                        [[1,0,2], [1,2,4], [4,2,5], [3,1,4]])
+
+        quantity2.set_values(quantity = 2*quantity1)
+        assert allclose(quantity2.vertex_values,
+                        [[2,0,4], [2,4,8], [8,4,10], [6,2,8]])
+
+        quantity2.set_values(quantity = 2*quantity1 + 3)
+        assert allclose(quantity2.vertex_values,
+                        [[5,3,7], [5,7,11], [11,7,13], [9,5,11]])
+
+
+        #Check detection of quantity as first orgument
+        quantity2.set_values(2*quantity1 + 3)
+        assert allclose(quantity2.vertex_values,
+                        [[5,3,7], [5,7,11], [11,7,13], [9,5,11]])
+
+
+
+    def Xtest_set_values_from_quantity_using_polygon(self):
+        """test_set_values_from_quantity_using_polygon(self):
+        
+        Check that polygon can be used to restrict set_values when
+        using another quantity as argument.
+        """
+        
+        # Create restricting polygon (containing node #4 (2,2) and 
+        # centroid of triangle #1 (bce)
+        polygon = [[1.0, 1.0], [4.0, 1.0],
+                   [4.0, 4.0], [1.0, 4.0]]
+        assert allclose(inside_polygon(self.mesh4.nodes, polygon), 4)                   
+        
+        quantity1 = Quantity(self.mesh4)
+        quantity1.set_vertex_values([0,1,2,3,4,5])
+
+        assert allclose(quantity1.vertex_values,
+                        [[1,0,2], [1,2,4], [4,2,5], [3,1,4]])
+
+
+        quantity2 = Quantity(self.mesh4)
+        quantity2.set_values(quantity=quantity1,
+                             polygon=polygon)
+                             
+        msg = 'Only node #4(e) at (2,2) should have values applied '
+        assert allclose(quantity2.vertex_values,
+                        [[0,0,0], [0,0,4], [4,0,0], [0,0,4]]), msg        
+                        #bac,     bce,     ecf,     dbe
+                        
+
+
+    def test_overloading(self):
+
+        quantity1 = Quantity(self.mesh4)
+        quantity1.set_vertex_values([0,1,2,3,4,5])
+
+        assert allclose(quantity1.vertex_values,
+                        [[1,0,2], [1,2,4], [4,2,5], [3,1,4]])
+
+
+        quantity2 = Quantity(self.mesh4)
+        quantity2.set_values([[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]],
+                             location = 'vertices')
+
+
+
+        quantity3 = Quantity(self.mesh4)
+        quantity3.set_values([[2,2,2], [7,8,9], [7,6,3], [3, 8, -8]],
+                             location = 'vertices')
+
+
+        # Negation
+        Q = -quantity1
+        assert allclose(Q.vertex_values, -quantity1.vertex_values)
+        assert allclose(Q.centroid_values, -quantity1.centroid_values)
+        assert allclose(Q.edge_values, -quantity1.edge_values)
+
+        # Addition
+        Q = quantity1 + 7
+        assert allclose(Q.vertex_values, quantity1.vertex_values + 7)
+        assert allclose(Q.centroid_values, quantity1.centroid_values + 7)
+        assert allclose(Q.edge_values, quantity1.edge_values + 7)
+
+        Q = 7 + quantity1
+        assert allclose(Q.vertex_values, quantity1.vertex_values + 7)
+        assert allclose(Q.centroid_values, quantity1.centroid_values + 7)
+        assert allclose(Q.edge_values, quantity1.edge_values + 7)
+
+        Q = quantity1 + quantity2
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values + quantity2.vertex_values)
+        assert allclose(Q.centroid_values,
+                        quantity1.centroid_values + quantity2.centroid_values)
+        assert allclose(Q.edge_values,
+                        quantity1.edge_values + quantity2.edge_values)
+
+
+        Q = quantity1 + quantity2 - 3
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values + quantity2.vertex_values - 3)
+
+        Q = quantity1 - quantity2
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values - quantity2.vertex_values)
+
+        #Scaling
+        Q = quantity1*3
+        assert allclose(Q.vertex_values, quantity1.vertex_values*3)
+        assert allclose(Q.centroid_values, quantity1.centroid_values*3)
+        assert allclose(Q.edge_values, quantity1.edge_values*3)
+        Q = 3*quantity1
+        assert allclose(Q.vertex_values, quantity1.vertex_values*3)
+
+        #Multiplication
+        Q = quantity1 * quantity2
+        #print Q.vertex_values
+        #print Q.centroid_values
+        #print quantity1.centroid_values
+        #print quantity2.centroid_values
+
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values * quantity2.vertex_values)
+
+        #Linear combinations
+        Q = 4*quantity1 + 2
+        assert allclose(Q.vertex_values,
+                        4*quantity1.vertex_values + 2)
+
+        Q = quantity1*quantity2 + 2
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values * quantity2.vertex_values + 2)
+
+        Q = quantity1*quantity2 + quantity3
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values * quantity2.vertex_values +
+                        quantity3.vertex_values)
+        Q = quantity1*quantity2 + 3*quantity3
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values * quantity2.vertex_values +
+                        3*quantity3.vertex_values)
+        Q = quantity1*quantity2 + 3*quantity3 + 5.0
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values * quantity2.vertex_values +
+                        3*quantity3.vertex_values + 5)
+
+        Q = quantity1*quantity2 - quantity3
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values * quantity2.vertex_values -
+                        quantity3.vertex_values)
+        Q = 1.5*quantity1*quantity2 - 3*quantity3 + 5.0
+        assert allclose(Q.vertex_values,
+                        1.5*quantity1.vertex_values * quantity2.vertex_values -
+                        3*quantity3.vertex_values + 5)
+
+        #Try combining quantities and arrays and scalars
+        Q = 1.5*quantity1*quantity2.vertex_values -\
+            3*quantity3.vertex_values + 5.0
+        assert allclose(Q.vertex_values,
+                        1.5*quantity1.vertex_values * quantity2.vertex_values -
+                        3*quantity3.vertex_values + 5)
+
+
+        #Powers
+        Q = quantity1**2
+        assert allclose(Q.vertex_values, quantity1.vertex_values**2)
+
+        Q = quantity1**2 +quantity2**2
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values**2 + \
+                        quantity2.vertex_values**2)
+
+        Q = (quantity1**2 +quantity2**2)**0.5
+        assert allclose(Q.vertex_values,
+                        (quantity1.vertex_values**2 + \
+                        quantity2.vertex_values**2)**0.5)
+
+
+
+
+
+
+
+    def test_compute_gradient(self):
+        quantity = Quantity(self.mesh4)
+
+        #Set up for a gradient of (2,0) at mid triangle
+        quantity.set_values([2.0, 4.0, 6.0, 2.0],
+                            location = 'centroids')
+
+
+        #Gradients
+        quantity.compute_gradients()
+
+        a = quantity.x_gradient
+        b = quantity.y_gradient
+        #print self.mesh4.centroid_coordinates
+        #print a, b
+
+        #The central triangle (1)
+        #(using standard gradient based on neigbours controid values)
+        assert allclose(a[1], 2.0)
+        assert allclose(b[1], 0.0)
+
+
+        #Left triangle (0) using two point gradient
+        #q0 = q1 + a*(x0-x1) + b*(y0-y1)  <=>
+        #2  = 4  + a*(-2/3)  + b*(-2/3)
+        assert allclose(a[0] + b[0], 3)
+        #From orthogonality (a*(y0-y1) + b*(x0-x1) == 0)
+        assert allclose(a[0] - b[0], 0)
+
+
+        #Right triangle (2) using two point gradient
+        #q2 = q1 + a*(x2-x1) + b*(y2-y1)  <=>
+        #6  = 4  + a*(4/3)  + b*(-2/3)
+        assert allclose(2*a[2] - b[2], 3)
+        #From orthogonality (a*(y1-y2) + b*(x2-x1) == 0)
+        assert allclose(a[2] + 2*b[2], 0)
+
+
+        #Top triangle (3) using two point gradient
+        #q3 = q1 + a*(x3-x1) + b*(y3-y1)  <=>
+        #2  = 4  + a*(-2/3)  + b*(4/3)
+        assert allclose(a[3] - 2*b[3], 3)
+        #From orthogonality (a*(y1-y3) + b*(x3-x1) == 0)
+        assert allclose(2*a[3] + b[3], 0)
+
+
+
+        #print a, b
+        quantity.extrapolate_second_order()
+
+        #Apply q(x,y) = qc + a*(x-xc) + b*(y-yc)
+        assert allclose(quantity.vertex_values[0,:], [3., 0.,  3.])
+        assert allclose(quantity.vertex_values[1,:], [4./3, 16./3,  16./3])
+
+
+        #a = 1.2, b=-0.6
+        #q(4,0) = 6 + a*(4 - 8/3) + b*(-2/3)
+        assert allclose(quantity.vertex_values[2,2], 8)
+
+    def test_get_gradients(self):
+        quantity = Quantity(self.mesh4)
+
+        #Set up for a gradient of (2,0) at mid triangle
+        quantity.set_values([2.0, 4.0, 6.0, 2.0],
+                            location = 'centroids')
+
+
+        #Gradients
+        quantity.compute_gradients()
+
+        a, b = quantity.get_gradients()
+        #print self.mesh4.centroid_coordinates
+        #print a, b
+
+        #The central triangle (1)
+        #(using standard gradient based on neigbours controid values)
+        assert allclose(a[1], 2.0)
+        assert allclose(b[1], 0.0)
+
+
+        #Left triangle (0) using two point gradient
+        #q0 = q1 + a*(x0-x1) + b*(y0-y1)  <=>
+        #2  = 4  + a*(-2/3)  + b*(-2/3)
+        assert allclose(a[0] + b[0], 3)
+        #From orthogonality (a*(y0-y1) + b*(x0-x1) == 0)
+        assert allclose(a[0] - b[0], 0)
+
+
+        #Right triangle (2) using two point gradient
+        #q2 = q1 + a*(x2-x1) + b*(y2-y1)  <=>
+        #6  = 4  + a*(4/3)  + b*(-2/3)
+        assert allclose(2*a[2] - b[2], 3)
+        #From orthogonality (a*(y1-y2) + b*(x2-x1) == 0)
+        assert allclose(a[2] + 2*b[2], 0)
+
+
+        #Top triangle (3) using two point gradient
+        #q3 = q1 + a*(x3-x1) + b*(y3-y1)  <=>
+        #2  = 4  + a*(-2/3)  + b*(4/3)
+        assert allclose(a[3] - 2*b[3], 3)
+        #From orthogonality (a*(y1-y3) + b*(x3-x1) == 0)
+        assert allclose(2*a[3] + b[3], 0)
+
+
+    def test_second_order_extrapolation2(self):
+        quantity = Quantity(self.mesh4)
+
+        #Set up for a gradient of (3,1), f(x) = 3x+y
+        quantity.set_values([2.0+2.0/3, 4.0+4.0/3, 8.0+2.0/3, 2.0+8.0/3],
+                            location = 'centroids')
+
+        #Gradients
+        quantity.compute_gradients()
+
+        a = quantity.x_gradient
+        b = quantity.y_gradient
+        
+        #print a, b
+
+        assert allclose(a[1], 3.0)
+        assert allclose(b[1], 1.0)
+
+        #Work out the others
+
+        quantity.extrapolate_second_order()
+
+        #print quantity.vertex_values
+        assert allclose(quantity.vertex_values[1,0], 2.0)
+        assert allclose(quantity.vertex_values[1,1], 6.0)
+        assert allclose(quantity.vertex_values[1,2], 8.0)
+
+
+
+    def test_backup_saxpy_centroid_values(self):
+        quantity = Quantity(self.mesh4)
+
+        #Set up for a gradient of (3,1), f(x) = 3x+y
+        c_values = array([2.0+2.0/3, 4.0+4.0/3, 8.0+2.0/3, 2.0+8.0/3])
+        d_values = array([1.0, 2.0, 3.0, 4.0])
+        quantity.set_values(c_values, location = 'centroids')
+
+        #Backup
+        quantity.backup_centroid_values()
+
+        #print quantity.vertex_values
+        assert allclose(quantity.centroid_values, quantity.centroid_backup_values)
+
+
+        quantity.set_values(d_values, location = 'centroids')
+
+        quantity.saxpy_centroid_values(2.0, 3.0)
+
+        assert(quantity.centroid_values, 2.0*d_values + 3.0*c_values)
+
+
+
+    def test_first_order_extrapolator(self):
+        quantity = Quantity(self.mesh4)
+
+        #Test centroids
+        quantity.set_values([1.,2.,3.,4.], location = 'centroids')
+        assert allclose(quantity.centroid_values, [1, 2, 3, 4]) #Centroid
+
+        #Extrapolate
+        quantity.extrapolate_first_order()
+
+        #Check that gradient is zero
+        a,b = quantity.get_gradients()
+        assert allclose(a, [0,0,0,0])
+        assert allclose(b, [0,0,0,0])
+
+        #Check vertices but not edge values
+        assert allclose(quantity.vertex_values,
+                        [[1,1,1], [2,2,2], [3,3,3], [4, 4, 4]])
+
+
+    def test_second_order_extrapolator(self):
+        quantity = Quantity(self.mesh4)
+
+        #Set up for a gradient of (3,0) at mid triangle
+        quantity.set_values([2.0, 4.0, 8.0, 2.0],
+                            location = 'centroids')
+
+
+
+        quantity.extrapolate_second_order()
+        quantity.limit()
+
+
+        #Assert that central triangle is limited by neighbours
+        assert quantity.vertex_values[1,0] >= quantity.vertex_values[0,0]
+        assert quantity.vertex_values[1,0] >= quantity.vertex_values[3,1]
+
+        assert quantity.vertex_values[1,1] <= quantity.vertex_values[2,1]
+        assert quantity.vertex_values[1,1] >= quantity.vertex_values[0,2]
+
+        assert quantity.vertex_values[1,2] <= quantity.vertex_values[2,0]
+        assert quantity.vertex_values[1,2] >= quantity.vertex_values[3,1]
+
+
+        #Assert that quantities are conserved
+        from Numeric import sum
+        for k in range(quantity.centroid_values.shape[0]):
+            assert allclose (quantity.centroid_values[k],
+                             sum(quantity.vertex_values[k,:])/3)
+
+
+
+
+
+    def test_limit_vertices_by_all_neighbours(self):
+        quantity = Quantity(self.mesh4)
+
+        #Create a deliberate overshoot (e.g. from gradient computation)
+        quantity.set_values([[3,0,3], [2,2,6], [5,3,8], [8,3,5]])
+
+
+        #Limit
+        quantity.limit_vertices_by_all_neighbours()
+
+        #Assert that central triangle is limited by neighbours
+        assert quantity.vertex_values[1,0] >= quantity.vertex_values[0,0]
+        assert quantity.vertex_values[1,0] <= quantity.vertex_values[3,1]
+
+        assert quantity.vertex_values[1,1] <= quantity.vertex_values[2,1]
+        assert quantity.vertex_values[1,1] >= quantity.vertex_values[0,2]
+
+        assert quantity.vertex_values[1,2] <= quantity.vertex_values[2,0]
+        assert quantity.vertex_values[1,2] <= quantity.vertex_values[3,1]
+
+
+
+        #Assert that quantities are conserved
+        from Numeric import sum
+        for k in range(quantity.centroid_values.shape[0]):
+            assert allclose (quantity.centroid_values[k],
+                             sum(quantity.vertex_values[k,:])/3)
+
+
+
+    def test_limit_edges_by_all_neighbours(self):
+        quantity = Quantity(self.mesh4)
+
+        #Create a deliberate overshoot (e.g. from gradient computation)
+        quantity.set_values([[3,0,3], [2,2,6], [5,3,8], [8,3,5]])
+
+
+        #Limit
+        quantity.limit_edges_by_all_neighbours()
+
+        #Assert that central triangle is limited by neighbours
+        assert quantity.edge_values[1,0] <= quantity.centroid_values[2]
+        assert quantity.edge_values[1,0] >= quantity.centroid_values[0]
+
+        assert quantity.edge_values[1,1] <= quantity.centroid_values[2]
+        assert quantity.edge_values[1,1] >= quantity.centroid_values[0]
+
+        assert quantity.edge_values[1,2] <= quantity.centroid_values[2]
+        assert quantity.edge_values[1,2] >= quantity.centroid_values[0]
+
+
+
+        #Assert that quantities are conserved
+        from Numeric import sum
+        for k in range(quantity.centroid_values.shape[0]):
+            assert allclose (quantity.centroid_values[k],
+                             sum(quantity.vertex_values[k,:])/3)
+
+
+    def test_limit_edges_by_neighbour(self):
+        quantity = Quantity(self.mesh4)
+
+        #Create a deliberate overshoot (e.g. from gradient computation)
+        quantity.set_values([[3,0,3], [2,2,6], [5,3,8], [8,3,5]])
+
+
+        #Limit
+        quantity.limit_edges_by_neighbour()
+
+        #Assert that central triangle is limited by neighbours
+        assert quantity.edge_values[1,0] <= quantity.centroid_values[3]
+        assert quantity.edge_values[1,0] >= quantity.centroid_values[1]
+
+        assert quantity.edge_values[1,1] <= quantity.centroid_values[2]
+        assert quantity.edge_values[1,1] >= quantity.centroid_values[1]
+
+        assert quantity.edge_values[1,2] <= quantity.centroid_values[1]
+        assert quantity.edge_values[1,2] >= quantity.centroid_values[0]
+
+
+
+        #Assert that quantities are conserved
+        from Numeric import sum
+        for k in range(quantity.centroid_values.shape[0]):
+            assert allclose (quantity.centroid_values[k],
+                             sum(quantity.vertex_values[k,:])/3)
+
+    def test_limiter2(self):
+        """Taken from test_shallow_water
+        """
+        quantity = Quantity(self.mesh4)
+        quantity.domain.beta_w = 0.9
+        
+        #Test centroids
+        quantity.set_values([2.,4.,8.,2.], location = 'centroids')
+        assert allclose(quantity.centroid_values, [2, 4, 8, 2]) #Centroid
+
+
+        #Extrapolate
+        quantity.extrapolate_second_order()
+
+        assert allclose(quantity.vertex_values[1,:], [0.0, 6, 6])
+
+        #Limit
+        quantity.limit()
+
+        # limited value for beta_w = 0.9
+        
+        assert allclose(quantity.vertex_values[1,:], [2.2, 4.9, 4.9])
+        # limited values for beta_w = 0.5
+        #assert allclose(quantity.vertex_values[1,:], [3.0, 4.5, 4.5])
+
+
+        #Assert that quantities are conserved
+        from Numeric import sum
+        for k in range(quantity.centroid_values.shape[0]):
+            assert allclose (quantity.centroid_values[k],
+                             sum(quantity.vertex_values[k,:])/3)
+
+
+
+
+
+    def test_distribute_first_order(self):
+        quantity = Quantity(self.mesh4)
+
+        #Test centroids
+        quantity.set_values([1.,2.,3.,4.], location = 'centroids')
+        assert allclose(quantity.centroid_values, [1, 2, 3, 4]) #Centroid
+
+
+        #Extrapolate from centroid to vertices and edges
+        quantity.extrapolate_first_order()
+
+        #Interpolate
+        #quantity.interpolate_from_vertices_to_edges()
+
+        assert allclose(quantity.vertex_values,
+                        [[1,1,1], [2,2,2], [3,3,3], [4, 4, 4]])
+        assert allclose(quantity.edge_values, [[1,1,1], [2,2,2],
+                                               [3,3,3], [4, 4, 4]])
+
+
+    def test_interpolate_from_vertices_to_edges(self):
+        quantity = Quantity(self.mesh4)
+
+        quantity.vertex_values = array([[1,0,2], [1,2,4], [4,2,5], [3,1,4]],Float)
+
+        quantity.interpolate_from_vertices_to_edges()
+
+        assert allclose(quantity.edge_values, [[1., 1.5, 0.5],
+                                               [3., 2.5, 1.5],
+                                               [3.5, 4.5, 3.],
+                                               [2.5, 3.5, 2]])
+
+
+    def test_interpolate_from_edges_to_vertices(self):
+        quantity = Quantity(self.mesh4)
+
+        quantity.edge_values = array([[1., 1.5, 0.5],
+                                [3., 2.5, 1.5],
+                                [3.5, 4.5, 3.],
+                                [2.5, 3.5, 2]],Float)
+
+        quantity.interpolate_from_edges_to_vertices()
+
+        assert allclose(quantity.vertex_values,
+                        [[1,0,2], [1,2,4], [4,2,5], [3,1,4]])
+
+
+
+    def test_distribute_second_order(self):
+        quantity = Quantity(self.mesh4)
+
+        #Test centroids
+        quantity.set_values([2.,4.,8.,2.], location = 'centroids')
+        assert allclose(quantity.centroid_values, [2, 4, 8, 2]) #Centroid
+
+
+        #Extrapolate
+        quantity.extrapolate_second_order()
+
+        assert allclose(quantity.vertex_values[1,:], [0.0, 6, 6])
+
+
+    def test_update_explicit(self):
+        quantity = Quantity(self.mesh4)
+
+        #Test centroids
+        quantity.set_values([1.,2.,3.,4.], location = 'centroids')
+        assert allclose(quantity.centroid_values, [1, 2, 3, 4]) #Centroid
+
+        #Set explicit_update
+        quantity.explicit_update = array( [1.,1.,1.,1.] )
+
+        #Update with given timestep
+        quantity.update(0.1)
+
+        x = array([1, 2, 3, 4]) + array( [.1,.1,.1,.1] )
+        assert allclose( quantity.centroid_values, x)
+
+    def test_update_semi_implicit(self):
+        quantity = Quantity(self.mesh4)
+
+        #Test centroids
+        quantity.set_values([1.,2.,3.,4.], location = 'centroids')
+        assert allclose(quantity.centroid_values, [1, 2, 3, 4]) #Centroid
+
+        #Set semi implicit update
+        quantity.semi_implicit_update = array([1.,1.,1.,1.])
+
+        #Update with given timestep
+        timestep = 0.1
+        quantity.update(timestep)
+
+        sem = array([1.,1.,1.,1.])/array([1, 2, 3, 4])
+        denom = ones(4, Float)-timestep*sem
+
+        x = array([1, 2, 3, 4])/denom
+        assert allclose( quantity.centroid_values, x)
+
+
+    def test_both_updates(self):
+        quantity = Quantity(self.mesh4)
+
+        #Test centroids
+        quantity.set_values([1.,2.,3.,4.], location = 'centroids')
+        assert allclose(quantity.centroid_values, [1, 2, 3, 4]) #Centroid
+
+        #Set explicit_update
+        quantity.explicit_update = array( [4.,3.,2.,1.] )
+
+        #Set semi implicit update
+        quantity.semi_implicit_update = array( [1.,1.,1.,1.] )
+
+        #Update with given timestep
+        timestep = 0.1
+        quantity.update(0.1)
+
+        sem = array([1.,1.,1.,1.])/array([1, 2, 3, 4])
+        denom = ones(4, Float)-timestep*sem
+
+        x = array([1., 2., 3., 4.])
+        x /= denom
+        x += timestep*array( [4.0, 3.0, 2.0, 1.0] )
+
+        assert allclose( quantity.centroid_values, x)
+
+
+
+
+    #Test smoothing
+    def test_smoothing(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Transmissive_boundary
+        from Numeric import zeros, Float
+        from anuga.utilities.numerical_tools import mean
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(2, 2)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.default_order=2
+        domain.reduction = mean
+
+
+        #Set some field values
+        domain.set_quantity('elevation', lambda x,y: x)
+        domain.set_quantity('friction', 0.03)
+
+
+        ######################
+        # Boundary conditions
+        B = Transmissive_boundary(domain)
+        domain.set_boundary( {'left': B, 'right': B, 'top': B, 'bottom': B})
+
+
+        ######################
+        #Initial condition - with jumps
+
+        bed = domain.quantities['elevation'].vertex_values
+        stage = zeros(bed.shape, Float)
+
+        h = 0.03
+        for i in range(stage.shape[0]):
+            if i % 2 == 0:
+                stage[i,:] = bed[i,:] + h
+            else:
+                stage[i,:] = bed[i,:]
+
+        domain.set_quantity('stage', stage)
+
+        stage = domain.quantities['stage']
+
+        #Get smoothed stage
+        A, V = stage.get_vertex_values(xy=False, smooth=True)
+        Q = stage.vertex_values
+
+
+        assert A.shape[0] == 9
+        assert V.shape[0] == 8
+        assert V.shape[1] == 3
+
+        #First four points
+        assert allclose(A[0], (Q[0,2] + Q[1,1])/2)
+        assert allclose(A[1], (Q[1,0] + Q[3,1] + Q[2,2])/3)
+        assert allclose(A[2], Q[3,0])
+        assert allclose(A[3], (Q[0,0] + Q[5,1] + Q[4,2])/3)
+
+        #Center point
+        assert allclose(A[4], (Q[0,1] + Q[1,2] + Q[2,0] +\
+                               Q[5,0] + Q[6,2] + Q[7,1])/6)
+
+
+        #Check V
+        assert allclose(V[0,:], [3,4,0])
+        assert allclose(V[1,:], [1,0,4])
+        assert allclose(V[2,:], [4,5,1])
+        assert allclose(V[3,:], [2,1,5])
+        assert allclose(V[4,:], [6,7,3])
+        assert allclose(V[5,:], [4,3,7])
+        assert allclose(V[6,:], [7,8,4])
+        assert allclose(V[7,:], [5,4,8])
+
+        #Get smoothed stage with XY
+        X, Y, A1, V1 = stage.get_vertex_values(xy=True, smooth=True)
+
+        assert allclose(A, A1)
+        assert allclose(V, V1)
+
+        #Check XY
+        assert allclose(X[4], 0.5)
+        assert allclose(Y[4], 0.5)
+
+        assert allclose(X[7], 1.0)
+        assert allclose(Y[7], 0.5)
+
+
+
+
+    def test_vertex_values_no_smoothing(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Transmissive_boundary
+        from Numeric import zeros, Float
+        from anuga.utilities.numerical_tools import mean
+
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(2, 2)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.default_order=2
+        domain.reduction = mean
+
+
+        #Set some field values
+        domain.set_quantity('elevation', lambda x,y: x)
+        domain.set_quantity('friction', 0.03)
+
+
+        ######################
+        #Initial condition - with jumps
+
+        bed = domain.quantities['elevation'].vertex_values
+        stage = zeros(bed.shape, Float)
+
+        h = 0.03
+        for i in range(stage.shape[0]):
+            if i % 2 == 0:
+                stage[i,:] = bed[i,:] + h
+            else:
+                stage[i,:] = bed[i,:]
+
+        domain.set_quantity('stage', stage)
+
+        #Get stage
+        stage = domain.quantities['stage']
+        A, V = stage.get_vertex_values(xy=False, smooth=False)
+        Q = stage.vertex_values.flat
+
+        for k in range(8):
+            assert allclose(A[k], Q[k])
+
+
+        for k in range(8):
+            assert V[k, 0] == 3*k
+            assert V[k, 1] == 3*k+1
+            assert V[k, 2] == 3*k+2
+
+
+
+        X, Y, A1, V1 = stage.get_vertex_values(xy=True, smooth=False)
+
+
+        assert allclose(A, A1)
+        assert allclose(V, V1)
+
+        #Check XY
+        assert allclose(X[1], 0.5)
+        assert allclose(Y[1], 0.5)
+        assert allclose(X[4], 0.0)
+        assert allclose(Y[4], 0.0)
+        assert allclose(X[12], 1.0)
+        assert allclose(Y[12], 0.0)
+
+
+
+    def set_array_values_by_index(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 1)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        #print "domain.number_of_elements ",domain.number_of_elements
+        quantity = Quantity(domain,[[1,1,1],[2,2,2]])
+        value = [7]
+        indices = [1]
+        quantity.set_array_values_by_index(value,
+                                           location = 'centroids',
+                                           indices = indices)
+        #print "quantity.centroid_values",quantity.centroid_values
+
+        assert allclose(quantity.centroid_values, [1,7])
+
+        quantity.set_array_values([15,20,25], indices = indices)
+        assert allclose(quantity.centroid_values, [1,20])
+
+        quantity.set_array_values([15,20,25], indices = indices)
+        assert allclose(quantity.centroid_values, [1,20])
+
+    def test_setting_some_vertex_values(self):
+        """
+        set values based on triangle lists.
+        """
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+        #print "vertices",vertices
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        #print "domain.number_of_elements ",domain.number_of_elements
+        quantity = Quantity(domain,[[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5],[6,6,6]])
+
+
+        # Check that constants work
+        value = 7
+        indices = [1]
+        quantity.set_values(value,
+                            location = 'centroids',
+                            indices = indices)
+        #print "quantity.centroid_values",quantity.centroid_values
+        assert allclose(quantity.centroid_values, [1,7,3,4,5,6])
+        
+        value = [7]
+        indices = [1]
+        quantity.set_values(value,
+                            location = 'centroids',
+                            indices = indices)
+        #print "quantity.centroid_values",quantity.centroid_values
+        assert allclose(quantity.centroid_values, [1,7,3,4,5,6])
+
+        value = [[15,20,25]]
+        quantity.set_values(value, indices = indices)
+        #print "1 quantity.vertex_values",quantity.vertex_values
+        assert allclose(quantity.vertex_values[1], value[0])
+
+
+        #print "quantity",quantity.vertex_values
+        values = [10,100,50]
+        quantity.set_values(values, indices = [0,1,5], location = 'centroids')
+        #print "2 quantity.vertex_values",quantity.vertex_values
+        assert allclose(quantity.vertex_values[0], [10,10,10])
+        assert allclose(quantity.vertex_values[5], [50,50,50])
+        #quantity.interpolate()
+        #print "quantity.centroid_values",quantity.centroid_values
+        assert allclose(quantity.centroid_values, [10,100,3,4,5,50])
+
+
+        quantity = Quantity(domain,[[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5],[6,6,6]])
+        values = [10,100,50]
+        #this will be per unique vertex, indexing the vertices
+        #print "quantity.vertex_values",quantity.vertex_values
+        quantity.set_values(values, indices = [0,1,5])
+        #print "quantity.vertex_values",quantity.vertex_values
+        assert allclose(quantity.vertex_values[0], [1,50,10])
+        assert allclose(quantity.vertex_values[5], [6,6,6])
+        assert allclose(quantity.vertex_values[1], [100,10,50])
+
+        quantity = Quantity(domain,[[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5],[6,6,6]])
+        values = [[31,30,29],[400,400,400],[1000,999,998]]
+        quantity.set_values(values, indices = [3,3,5])
+        quantity.interpolate()
+        assert allclose(quantity.centroid_values, [1,2,3,400,5,999])
+
+        values = [[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5],[6,6,6]]
+        quantity.set_values(values)
+
+        # testing the standard set values by vertex
+        # indexed by vertex_id in general_mesh.coordinates
+        values = [0,1,2,3,4,5,6,7]
+
+        quantity.set_values(values)
+        #print "1 quantity.vertex_values",quantity.vertex_values
+        assert allclose(quantity.vertex_values,[[ 4.,  5.,  0.],
+                                                [ 1.,  0.,  5.],
+                                                [ 5.,  6.,  1.],
+                                                [ 2.,  1.,  6.],
+                                                [ 6.,  7.,  2.],
+                                                [ 3.,  2.,  7.]])
+
+    def test_setting_unique_vertex_values(self):
+        """
+        set values based on unique_vertex lists.
+        """
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+        #print "vertices",vertices
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        #print "domain.number_of_elements ",domain.number_of_elements
+        quantity = Quantity(domain,[[0,0,0],[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5]])
+        value = 7
+        indices = [1,5]
+        quantity.set_values(value,
+                            location = 'unique vertices',
+                            indices = indices)
+        #print "quantity.centroid_values",quantity.centroid_values
+        assert allclose(quantity.vertex_values[0], [0,7,0])
+        assert allclose(quantity.vertex_values[1], [7,1,7])
+        assert allclose(quantity.vertex_values[2], [7,2,7])
+
+
+    def test_get_values(self):
+        """
+        get values based on triangle lists.
+        """
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+
+        #print "points",points
+        #print "vertices",vertices
+        #print "boundary",boundary
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        #print "domain.number_of_elements ",domain.number_of_elements
+        quantity = Quantity(domain,[[0,0,0],[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5]])
+
+        #print "quantity.get_values(location = 'unique vertices')", \
+        #      quantity.get_values(location = 'unique vertices')
+
+        #print "quantity.get_values(location = 'unique vertices')", \
+        #      quantity.get_values(indices=[0,1,2,3,4,5,6,7], \
+        #                          location = 'unique vertices')
+
+        answer = [0.5,2,4,5,0,1,3,4.5]
+        assert allclose(answer,
+                        quantity.get_values(location = 'unique vertices'))
+
+        indices = [0,5,3]
+        answer = [0.5,1,5]
+        assert allclose(answer,
+                        quantity.get_values(indices=indices, \
+                                            location = 'unique vertices'))
+        #print "quantity.centroid_values",quantity.centroid_values
+        #print "quantity.get_values(location = 'centroids') ",\
+        #      quantity.get_values(location = 'centroids')
+
+
+
+
+    def test_get_values_2(self):
+        """Different mesh (working with domain object) - also check centroids.
+        """
+
+        
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0,0.0]
+        d = [0.0, 4.0]
+        e = [2.0, 2.0]
+        f = [4.0,0.0]
+
+        points = [a, b, c, d, e, f]
+        #bac, bce, ecf, dbe
+        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        domain = Domain(points, vertices)
+
+        quantity = Quantity(domain)
+        quantity.set_values(lambda x, y: x+2*y) #2 4 4 6
+        
+        assert allclose(quantity.get_values(location='centroids'), [2,4,4,6])
+        assert allclose(quantity.get_values(location='centroids', indices=[1,3]), [4,6])
+
+
+        assert allclose(quantity.get_values(location='vertices'), [[4,0,2],
+                                                                   [4,2,6],
+                                                                   [6,2,4],
+                                                                   [8,4,6]])
+        
+        assert allclose(quantity.get_values(location='vertices', indices=[1,3]), [[4,2,6],
+                                                                                  [8,4,6]])
+
+
+        assert allclose(quantity.get_values(location='edges'), [[1,3,2],
+                                                                [4,5,3],
+                                                                [3,5,4],
+                                                                [5,7,6]])
+        assert allclose(quantity.get_values(location='edges', indices=[1,3]),
+                        [[4,5,3],
+                         [5,7,6]])        
+
+        # Check averaging over vertices
+        #a: 0
+        #b: (4+4+4)/3
+        #c: (2+2+2)/3
+        #d: 8
+        #e: (6+6+6)/3        
+        #f: 4
+        assert(quantity.get_values(location='unique vertices'), [0, 4, 2, 8, 6, 4])        
+                                                                                  
+        
+
+
+
+
+    def test_get_interpolated_values(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+        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]])
+
+        
+
+        # Get interpolated values at centroids
+        interpolation_points = domain.get_centroid_coordinates()
+        answer = quantity.get_values(location='centroids')
+
+        
+        #print quantity.get_values(points=interpolation_points)
+        assert allclose(answer, quantity.get_values(interpolation_points=interpolation_points))
+
+
+        #Arbitrary values
+        quantity = Quantity(domain,[[0,1,2],[3,1,7],[2,1,2],[3,3,7],
+                                    [1,4,-9],[2,5,0]])
+
+
+        # Get interpolated values at centroids
+        interpolation_points = domain.get_centroid_coordinates()
+        answer = quantity.get_values(location='centroids')
+        #print answer
+        #print quantity.get_values(points=interpolation_points)
+        assert allclose(answer, quantity.get_values(interpolation_points=interpolation_points))        
+                        
+
+        #FIXME TODO
+        #indices = [0,5,3]
+        #answer = [0.5,1,5]
+        #assert allclose(answer,
+        #                quantity.get_values(indices=indices, \
+        #                                    location = 'unique vertices'))
+
+
+
+
+    def test_get_interpolated_values_2(self):
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0,0.0]
+        d = [0.0, 4.0]
+        e = [2.0, 2.0]
+        f = [4.0,0.0]
+
+        points = [a, b, c, d, e, f]
+        #bac, bce, ecf, dbe
+        vertices = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        domain = Domain(points, vertices)
+
+        quantity = Quantity(domain)
+        quantity.set_values(lambda x, y: x+2*y) #2 4 4 6
+
+        #First pick one point
+        x, y = 2.0/3, 8.0/3
+        v = quantity.get_values(interpolation_points = [[x,y]])
+        assert allclose(v, 6)        
+
+        # Then another to test that algorithm won't blindly
+        # reuse interpolation matrix
+        x, y = 4.0/3, 4.0/3
+        v = quantity.get_values(interpolation_points = [[x,y]])
+        assert allclose(v, 4)        
+
+
+
+
+    def test_getting_some_vertex_values(self):
+        """
+        get values based on triangle lists.
+        """
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+
+        #print "points",points
+        #print "vertices",vertices
+        #print "boundary",boundary
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        #print "domain.number_of_elements ",domain.number_of_elements
+        quantity = Quantity(domain,[[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5],[6,6,6]])
+        value = [7]
+        indices = [1]
+        quantity.set_values(value,
+                            location = 'centroids',
+                            indices = indices)
+        #print "quantity.centroid_values",quantity.centroid_values
+        #print "quantity.get_values(location = 'centroids') ",\
+        #      quantity.get_values(location = 'centroids')
+        assert allclose(quantity.centroid_values,
+                        quantity.get_values(location = 'centroids'))
+
+
+        value = [[15,20,25]]
+        quantity.set_values(value, indices = indices)
+        #print "1 quantity.vertex_values",quantity.vertex_values
+        assert allclose(quantity.vertex_values, quantity.get_values())
+
+        assert allclose(quantity.edge_values,
+                        quantity.get_values(location = 'edges'))
+
+        # get a subset of elements
+        subset = quantity.get_values(location='centroids', indices=[0,5])
+        answer = [quantity.centroid_values[0],quantity.centroid_values[5]]
+        assert allclose(subset, answer)
+
+
+        subset = quantity.get_values(location='edges', indices=[0,5])
+        answer = [quantity.edge_values[0],quantity.edge_values[5]]
+        #print "subset",subset
+        #print "answer",answer
+        assert allclose(subset, answer)
+
+        subset = quantity.get_values( indices=[1,5])
+        answer = [quantity.vertex_values[1],quantity.vertex_values[5]]
+        #print "subset",subset
+        #print "answer",answer
+        assert allclose(subset, answer)
+
+    def test_smooth_vertex_values(self):
+        """
+        get values based on triangle lists.
+        """
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(2, 2)
+
+        #print "points",points
+        #print "vertices",vertices
+        #print "boundary",boundary
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        #print "domain.number_of_elements ",domain.number_of_elements
+        quantity = Quantity(domain,[[0,0,0],[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5],[6,6,6],[7,7,7]])
+
+        #print "quantity.get_values(location = 'unique vertices')", \
+        #      quantity.get_values(location = 'unique vertices')
+
+        #print "quantity.get_values(location = 'unique vertices')", \
+        #      quantity.get_values(indices=[0,1,2,3,4,5,6,7], \
+        #                          location = 'unique vertices')
+
+        #print quantity.get_values(location = 'unique vertices')
+        #print quantity.domain.number_of_triangles_per_node
+        #print quantity.vertex_values
+        
+        #answer = [0.5, 2, 3, 3, 3.5, 4, 4, 5, 6.5]
+        #assert allclose(answer,
+        #                quantity.get_values(location = 'unique vertices'))
+
+        quantity.smooth_vertex_values()
+
+        #print quantity.vertex_values
+
+
+        answer_vertex_values = [[3,3.5,0.5],[2,0.5,3.5],[3.5,4,2],[3,2,4],
+                                [4,5,3],[3.5,3,5],[5,6.5,3.5],[4,3.5,6.5]]
+        
+        assert allclose(answer_vertex_values,
+                        quantity.vertex_values)
+        #print "quantity.centroid_values",quantity.centroid_values
+        #print "quantity.get_values(location = 'centroids') ",\
+        #      quantity.get_values(location = 'centroids')
+
+
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_Quantity, 'test')    
+    #suite = unittest.makeSuite(Test_Quantity, 'test_set_values_from_file_using_polygon')
+
+    #suite = unittest.makeSuite(Test_Quantity, 'test_set_vertex_values_using_general_interface_with_subset')
+    #print "restricted test"
+    #suite = unittest.makeSuite(Test_Quantity,'verbose_test_set_values_from_UTM_pts')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_shallow_water.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_shallow_water.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_shallow_water.py	(revision 7576)
@@ -0,0 +1,450 @@
+#!/usr/bin/env python
+
+import unittest
+from math import sqrt, pi
+
+
+#from shallow_water_domain import *
+#from shallow_water_domain import flux_function as domain_flux_function
+
+from shallow_water_domain_suggestion1 import *
+from shallow_water_domain_suggestion1 import flux_function as domain_flux_function
+
+from Numeric import allclose, array, ones, Float, maximum, zeros
+
+
+class Test_Shallow_Water(unittest.TestCase):
+    def setUp(self):
+        self.points = [0.0, 1.0, 2.0, 3.0]
+        self.vertex_values = [[1.0,2.0],[4.0,5.0],[-1.0,2.0]]
+        self.points2 = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
+        
+    def tearDown(self):
+        pass
+        #print "  Tearing down"
+
+
+    def test_creation(self):
+        domain = Domain(self.points)
+        assert allclose(domain.centroids, [0.5, 1.5, 2.5])
+
+    def test_compute_fluxes(self):
+        """
+        Compare shallow_water_domain flux calculation against a previous
+        Python implementation (defined in this file)
+        """
+        domain = Domain(self.points)
+        domain.set_quantity('stage',2.0)
+        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
+
+        stage_ud, xmom_ud = local_compute_fluxes(domain)
+
+        domain.distribute_to_vertices_and_edges()
+        domain.compute_fluxes()
+
+        print domain.quantities['stage'].explicit_update
+        print domain.quantities['xmomentum'].explicit_update
+        print stage_ud
+        print xmom_ud
+
+        assert allclose( domain.quantities['stage'].explicit_update, stage_ud )
+        assert allclose( domain.quantities['xmomentum'].explicit_update, xmom_ud )
+
+
+    def test_local_flux_function(self):
+        normal = 1.0
+        ql = array([1.0, 2.0],Float)
+        qr = array([1.0, 2.0],Float)
+        zl = 0.0
+        zr = 0.0
+
+        #This assumes h0 = 1.0e-3!!
+        edgeflux, maxspeed = local_flux_function(normal, ql,qr,zl,zr)
+        #print maxspeed
+        #print edgeflux
+        
+        assert allclose(array([2.0, 8.9],Float), edgeflux, rtol=1.0e-005)
+        assert allclose(5.1305, maxspeed, rtol=1.0e-005)
+
+        normal = -1.0
+        ql = array([1.0, 2.0],Float)
+        qr = array([1.0, 2.0],Float)
+        zl = 0.0
+        zr = 0.0
+
+        edgeflux, maxspeed = local_flux_function(normal, ql,qr,zl,zr)
+
+
+        #print maxspeed
+        #print edgeflux        
+        
+        assert allclose(array([-2.0, -8.9],Float), edgeflux, rtol=1.0e-005)
+        assert allclose(5.1305, maxspeed, rtol=1.0e-005)
+
+    def test_domain_flux_function(self):
+        normal = 1.0
+        ql = array([1.0, 2.0],Float)
+        qr = array([1.0, 2.0],Float)
+        zl = 0.0
+        zr = 0.0
+
+        edgeflux, maxspeed = local_flux_function(normal, ql,qr,zl,zr)
+
+        #print edgeflux
+
+
+
+        domainedgeflux, domainmaxspeed = domain_flux_function(normal, ql,qr,zl,zr)
+
+        #print domainedgeflux
+
+        assert allclose(domainedgeflux, edgeflux)
+        assert allclose(domainmaxspeed, maxspeed)
+
+    def test_gravity(self):
+        """
+        Compare shallow_water_domain gravity calculation
+        """
+
+        def slope_one(x):
+            return x
+
+        domain = Domain(self.points)
+        domain.set_quantity('stage',4.0)
+        domain.set_quantity('elevation',slope_one)
+        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
+
+        gravity(domain)
+        
+        #print domain.quantities['stage'].vertex_values 
+        #print domain.quantities['elevation'].vertex_values 
+        #print domain.quantities['xmomentum'].explicit_update       
+
+        assert allclose( array([-34.3, -24.5, -14.7], Float), domain.quantities['xmomentum'].explicit_update )
+
+
+    def test_evolve_first_order(self):
+        """
+        Compare still lake solution for various versions of shallow_water_domain
+        """
+        
+        def slope_square(x):
+            return maximum(4.0-(x-5.0)*(x-5.0), 0.0)
+
+        domain = Domain(self.points2)
+        domain.set_quantity('stage',10.0)
+        domain.set_quantity('elevation',slope_square)
+        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
+
+        domain.default_order = 1
+        domain.set_timestepping_method('euler')
+        
+        yieldstep=1.0
+        finaltime=1.0
+
+        for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+            pass
+        
+        ##	print domain.quantities['stage'].vertex_values 
+        ##	print domain.quantities['elevation'].vertex_values 
+        ##        print domain.quantities['xmomentum'].vertex_values
+        ##  
+        ##
+        ##        print domain.quantities['stage'].centroid_values  
+        ##	print domain.quantities['elevation'].centroid_values    
+        ##        print domain.quantities['xmomentum'].centroid_values    
+
+        assert allclose( 10.0*ones(10), domain.quantities['stage'].centroid_values )
+        assert allclose( zeros(10), domain.quantities['xmomentum'].centroid_values )
+
+
+    def test_evolve_euler_second_order_space(self):
+        """
+        Compare still lake solution for various versions of shallow_water_domain
+        """
+
+        def slope_square(x):
+            return maximum(4.0-(x-5.0)*(x-5.0), 0.0)
+
+        domain = Domain(self.points2)
+        domain.set_quantity('stage',10.0)
+        domain.set_quantity('elevation',slope_square)
+        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
+
+        domain.default_order = 2
+        domain.set_timestepping_method('rk2')
+        yieldstep=1.0
+        finaltime=1.0
+
+        for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+            pass
+        
+        assert allclose( 10.0*ones(10), domain.quantities['stage'].centroid_values )
+        assert allclose( zeros(10), domain.quantities['xmomentum'].centroid_values )
+
+    def test_evolve_second_order_space_time(self):
+        """
+        Compare still lake solution for various versions of shallow_water_domain
+        """
+
+        def slope_square(x):
+            return maximum(4.0-(x-5.0)*(x-5.0), 0.0)
+
+        domain = Domain(self.points2)
+        domain.set_quantity('stage',10.0)
+        domain.set_quantity('elevation',slope_square)
+        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
+
+        domain.default_order = 2
+        domain.set_timestepping_method('rk3')
+
+        yieldstep=1.0
+        finaltime=1.0
+
+        for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+            pass
+        
+        assert allclose( 10.0*ones(10), domain.quantities['stage'].centroid_values )
+        assert allclose( zeros(10), domain.quantities['xmomentum'].centroid_values )
+
+
+
+#==============================================================================
+
+def local_compute_fluxes(domain):
+    """Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    tmp0 = zeros(N,Float)
+    tmp1 = zeros(N,Float)
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    #    Ymom = domain.quantities['ymomentum']
+    Bed = domain.quantities['elevation']
+
+    #Arrays
+    #stage = Stage.edge_values
+    #xmom =  Xmom.edge_values
+    #   ymom =  Ymom.edge_values
+    #bed =   Bed.edge_values
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+    
+    #print 'stage edge values', stage
+    #print 'xmom edge values', xmom
+    #print 'bed values', bed
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    #print 'stage_bdry',stage_bdry
+    #print 'xmom_bdry', xmom_bdry
+    #    ymom_bdry =  Ymom.boundary_values
+
+    #    flux = zeros(3, Float) #Work array for summing up fluxes
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            #ql[0] = stage[k, i]
+            #ql[1] = xmom[k, i]
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #print i, ' ' , m
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] = xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            #Flux computation using provided function
+            #edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+            #print 'ql',ql
+            #print 'qr',qr
+            
+
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #print 'edgeflux', edgeflux
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.CFL*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        #Stage.explicit_update[k] = flux[0]
+        tmp0[k] = flux[0]
+        tmp1[k] = flux[1]
+
+
+    return tmp0, tmp1
+
+
+def local_flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon, h0
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/(h_left +  h0/h_left)
+
+
+    uh_left = u_left*h_left
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/(h_right + h0/h_right)
+
+    uh_right = u_right*h_right
+    
+    #vh_left  = q_left[2]
+    #vh_right = q_right[2]
+
+    #print h_right
+    #print u_right
+    #print h_left
+    #print u_right
+
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+
+    #flux_left  = array([u_left*h_left,
+    #                    u_left*uh_left + 0.5*g*h_left**2])
+    #flux_right = array([u_right*h_right,
+    #                    u_right*uh_right + 0.5*g*h_right**2])
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_Shallow_Water, 'test')    
+    #suite = unittest.makeSuite(Test_Quantity, 'test_set_values_from_file_using_polygon')
+
+    #suite = unittest.makeSuite(Test_Quantity, 'test_set_vertex_values_using_general_interface_with_subset')
+    #print "restricted test"
+    #suite = unittest.makeSuite(Test_Quantity,'verbose_test_set_values_from_UTM_pts')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_shallow_water_domain.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_shallow_water_domain.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_shallow_water_domain.py	(revision 7576)
@@ -0,0 +1,449 @@
+#!/usr/bin/env python
+
+import unittest
+from math import sqrt, pi
+
+
+from shallow_water_domain import *
+from shallow_water_domain import flux_function as domain_flux_function
+
+
+
+from Numeric import allclose, array, ones, Float, maximum, zeros
+
+
+class Test_Shallow_Water(unittest.TestCase):
+    def setUp(self):
+        self.points = [0.0, 1.0, 2.0, 3.0]
+        self.vertex_values = [[1.0,2.0],[4.0,5.0],[-1.0,2.0]]
+        self.points2 = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
+        
+    def tearDown(self):
+        pass
+        #print "  Tearing down"
+
+
+    def test_creation(self):
+        domain = Domain(self.points)
+        assert allclose(domain.centroids, [0.5, 1.5, 2.5])
+
+    def test_compute_fluxes(self):
+        """
+        Compare shallow_water_domain flux calculation against a previous
+        Python implementation (defined in this file)
+        """
+        domain = Domain(self.points)
+        domain.set_quantity('stage',2.0)
+        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
+
+        stage_ud, xmom_ud = local_compute_fluxes(domain)
+
+        domain.distribute_to_vertices_and_edges()
+        domain.compute_fluxes()
+
+        print domain.quantities['stage'].explicit_update
+        print domain.quantities['xmomentum'].explicit_update
+        print stage_ud
+        print xmom_ud
+
+        assert allclose( domain.quantities['stage'].explicit_update, stage_ud )
+        assert allclose( domain.quantities['xmomentum'].explicit_update, xmom_ud )
+
+
+    def test_local_flux_function(self):
+        normal = 1.0
+        ql = array([1.0, 2.0],Float)
+        qr = array([1.0, 2.0],Float)
+        zl = 0.0
+        zr = 0.0
+
+        #This assumes h0 = 1.0e-3!!
+        edgeflux, maxspeed = local_flux_function(normal, ql,qr,zl,zr)
+        #print maxspeed
+        #print edgeflux
+        
+        assert allclose(array([2.0, 8.9],Float), edgeflux, rtol=1.0e-005)
+        assert allclose(5.1305, maxspeed, rtol=1.0e-005)
+
+        normal = -1.0
+        ql = array([1.0, 2.0],Float)
+        qr = array([1.0, 2.0],Float)
+        zl = 0.0
+        zr = 0.0
+
+        edgeflux, maxspeed = local_flux_function(normal, ql,qr,zl,zr)
+
+
+        #print maxspeed
+        #print edgeflux        
+        
+        assert allclose(array([-2.0, -8.9],Float), edgeflux, rtol=1.0e-005)
+        assert allclose(5.1305, maxspeed, rtol=1.0e-005)
+
+    def test_domain_flux_function(self):
+        normal = 1.0
+        ql = array([1.0, 2.0],Float)
+        qr = array([1.0, 2.0],Float)
+        zl = 0.0
+        zr = 0.0
+
+        edgeflux, maxspeed = local_flux_function(normal, ql,qr,zl,zr)
+
+        #print edgeflux
+
+
+
+        domainedgeflux, domainmaxspeed = domain_flux_function(normal, ql,qr,zl,zr)
+
+        #print domainedgeflux
+
+        assert allclose(domainedgeflux, edgeflux)
+        assert allclose(domainmaxspeed, maxspeed)
+
+    def test_gravity(self):
+        """
+        Compare shallow_water_domain gravity calculation
+        """
+
+        def slope_one(x):
+            return x
+
+        domain = Domain(self.points)
+        domain.set_quantity('stage',4.0)
+        domain.set_quantity('elevation',slope_one)
+        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
+
+        gravity(domain)
+        
+        #print domain.quantities['stage'].vertex_values 
+        #print domain.quantities['elevation'].vertex_values 
+        #print domain.quantities['xmomentum'].explicit_update       
+
+        assert allclose( array([-34.3, -24.5, -14.7], Float), domain.quantities['xmomentum'].explicit_update )
+
+
+    def test_evolve_first_order(self):
+        """
+        Compare still lake solution for various versions of shallow_water_domain
+        """
+        
+        def slope_square(x):
+            return maximum(4.0-(x-5.0)*(x-5.0), 0.0)
+
+        domain = Domain(self.points2)
+        domain.set_quantity('stage',10.0)
+        domain.set_quantity('elevation',slope_square)
+        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
+
+        domain.default_order = 1
+        domain.set_timestepping_method('euler')
+        
+        yieldstep=1.0
+        finaltime=1.0
+
+        for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+            pass
+        
+        ##	print domain.quantities['stage'].vertex_values 
+        ##	print domain.quantities['elevation'].vertex_values 
+        ##        print domain.quantities['xmomentum'].vertex_values
+        ##  
+        ##
+        ##        print domain.quantities['stage'].centroid_values  
+        ##	print domain.quantities['elevation'].centroid_values    
+        ##        print domain.quantities['xmomentum'].centroid_values    
+
+        assert allclose( 10.0*ones(10), domain.quantities['stage'].centroid_values )
+        assert allclose( zeros(10), domain.quantities['xmomentum'].centroid_values )
+
+
+    def test_evolve_euler_second_order_space(self):
+        """
+        Compare still lake solution for various versions of shallow_water_domain
+        """
+
+        def slope_square(x):
+            return maximum(4.0-(x-5.0)*(x-5.0), 0.0)
+
+        domain = Domain(self.points2)
+        domain.set_quantity('stage',10.0)
+        domain.set_quantity('elevation',slope_square)
+        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
+
+        domain.default_order = 2
+        domain.set_timestepping_method('rk2')
+        yieldstep=1.0
+        finaltime=1.0
+
+        for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+            pass
+        
+        assert allclose( 10.0*ones(10), domain.quantities['stage'].centroid_values )
+        assert allclose( zeros(10), domain.quantities['xmomentum'].centroid_values )
+
+    def test_evolve_second_order_space_time(self):
+        """
+        Compare still lake solution for various versions of shallow_water_domain
+        """
+
+        def slope_square(x):
+            return maximum(4.0-(x-5.0)*(x-5.0), 0.0)
+
+        domain = Domain(self.points2)
+        domain.set_quantity('stage',10.0)
+        domain.set_quantity('elevation',slope_square)
+        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
+
+        domain.default_order = 2
+        domain.set_timestepping_method('rk3')
+
+        yieldstep=1.0
+        finaltime=1.0
+
+        for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+            pass
+        
+        assert allclose( 10.0*ones(10), domain.quantities['stage'].centroid_values )
+        assert allclose( zeros(10), domain.quantities['xmomentum'].centroid_values )
+
+
+
+#==============================================================================
+
+def local_compute_fluxes(domain):
+    """Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    tmp0 = zeros(N,Float)
+    tmp1 = zeros(N,Float)
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    #    Ymom = domain.quantities['ymomentum']
+    Bed = domain.quantities['elevation']
+
+    #Arrays
+    #stage = Stage.edge_values
+    #xmom =  Xmom.edge_values
+    #   ymom =  Ymom.edge_values
+    #bed =   Bed.edge_values
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+    
+    #print 'stage edge values', stage
+    #print 'xmom edge values', xmom
+    #print 'bed values', bed
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    #print 'stage_bdry',stage_bdry
+    #print 'xmom_bdry', xmom_bdry
+    #    ymom_bdry =  Ymom.boundary_values
+
+    #    flux = zeros(3, Float) #Work array for summing up fluxes
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            #ql[0] = stage[k, i]
+            #ql[1] = xmom[k, i]
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #print i, ' ' , m
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] = xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            #Flux computation using provided function
+            #edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+            #print 'ql',ql
+            #print 'qr',qr
+            
+
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            #print 'edgeflux', edgeflux
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.CFL*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        #Stage.explicit_update[k] = flux[0]
+        tmp0[k] = flux[0]
+        tmp1[k] = flux[1]
+
+
+    return tmp0, tmp1
+
+
+def local_flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon, h0
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/(h_left +  h0/h_left)
+
+
+    uh_left = u_left*h_left
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/(h_right + h0/h_right)
+
+    uh_right = u_right*h_right
+    
+    #vh_left  = q_left[2]
+    #vh_right = q_right[2]
+
+    #print h_right
+    #print u_right
+    #print h_left
+    #print u_right
+
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+
+    #flux_left  = array([u_left*h_left,
+    #                    u_left*uh_left + 0.5*g*h_left**2])
+    #flux_right = array([u_right*h_right,
+    #                    u_right*uh_right + 0.5*g*h_right**2])
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_Shallow_Water, 'test')    
+    #suite = unittest.makeSuite(Test_Quantity, 'test_set_values_from_file_using_polygon')
+
+    #suite = unittest.makeSuite(Test_Quantity, 'test_set_vertex_values_using_general_interface_with_subset')
+    #print "restricted test"
+    #suite = unittest.makeSuite(Test_Quantity,'verbose_test_set_values_from_UTM_pts')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_shallow_water_vel_domain.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_shallow_water_vel_domain.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/test_shallow_water_vel_domain.py	(revision 7576)
@@ -0,0 +1,517 @@
+#!/usr/bin/env python
+
+import unittest
+from math import sqrt, pi
+
+
+from shallow_water_vel_domain import *
+
+
+from Numeric import allclose, array, ones, Float, maximum, zeros
+
+
+class Test_Shallow_Water(unittest.TestCase):
+    def setUp(self):
+        self.points = [0.0, 1.0, 2.0, 3.0]
+        self.vertex_values = [[1.0,2.0],[4.0,5.0],[-1.0,2.0]]
+        self.points2 = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
+        
+    def tearDown(self):
+        pass
+        #print "  Tearing down"
+
+
+    def test_creation(self):
+        domain = Domain(self.points)
+        assert allclose(domain.centroids, [0.5, 1.5, 2.5])
+
+    def test_reflective_boundary(self):
+        """
+        Test setting reflective boundary
+        """
+        
+        domain = Domain(self.points)
+        domain.set_quantity('stage',2.0)
+        domain.set_quantity('xmomentum',6.0)
+        
+        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
+
+
+        domain.distribute_to_vertices_and_edges()
+        domain.update_boundary()
+
+##         print 'In test reflective'
+##         print domain.quantities['stage'].vertex_values
+##         print domain.quantities['xmomentum'].vertex_values
+##         print domain.quantities['elevation'].vertex_values
+##         print domain.quantities['height'].vertex_values
+##         print domain.quantities['velocity'].vertex_values
+        
+##         print domain.quantities['stage'].boundary_values
+##         print domain.quantities['xmomentum'].boundary_values
+##         print domain.quantities['elevation'].boundary_values
+##         print domain.quantities['height'].boundary_values
+##         print domain.quantities['velocity'].boundary_values
+
+        assert allclose( domain.quantities['stage'    ].boundary_values, [2.0, 2.0])
+        assert allclose( domain.quantities['xmomentum'].boundary_values, [-6.0, -6.0])
+        assert allclose( domain.quantities['elevation'].boundary_values, [0.0, 0.0])
+        assert allclose( domain.quantities['height'   ].boundary_values, [2.0, 2.0])
+        assert allclose( domain.quantities['velocity' ].boundary_values, [-3.0, -3.0])
+
+        
+
+    def test_dirichlet_boundary(self):
+        """
+        Test setting dirichlet boundary
+        """
+        
+        domain = Domain(self.points)
+        domain.set_quantity('stage',2.0)
+        domain.set_quantity('xmomentum',6.0)
+        
+        domain.set_boundary({'exterior' : Dirichlet_boundary([3.0, 8.0, 1.0, 2.0, 4.0])})
+
+
+        domain.distribute_to_vertices_and_edges()
+        domain.update_boundary()
+
+##         print 'In test dirichlet'
+##         print domain.quantities['stage'].vertex_values
+##         print domain.quantities['xmomentum'].vertex_values
+##         print domain.quantities['elevation'].vertex_values
+##         print domain.quantities['height'].vertex_values
+##         print domain.quantities['velocity'].vertex_values
+        
+##         print domain.quantities['stage'].boundary_values
+##         print domain.quantities['xmomentum'].boundary_values
+##         print domain.quantities['elevation'].boundary_values
+##         print domain.quantities['height'].boundary_values
+##         print domain.quantities['velocity'].boundary_values
+
+        assert allclose( domain.quantities['stage'    ].boundary_values, [3.0, 3.0])
+        assert allclose( domain.quantities['xmomentum'].boundary_values, [8.0, 8.0])
+        assert allclose( domain.quantities['elevation'].boundary_values, [1.0, 1.0])
+        assert allclose( domain.quantities['height'   ].boundary_values, [2.0, 2.0])
+        assert allclose( domain.quantities['velocity' ].boundary_values, [4.0, 4.0])
+
+
+    def test_compute_fluxes(self):
+        """
+        Compare shallow_water_domain flux calculation against a previous
+        Python implementation (defined in this file)
+        """
+        domain = Domain(self.points)
+        domain.set_quantity('stage',2.0)
+        domain.set_boundary({'exterior' : Dirichlet_boundary([0.0, 0.0, 0.0, 0.0, 0.0])})
+
+
+        domain.distribute_to_vertices_and_edges()
+        domain.update_boundary()
+
+        stage_ud, xmom_ud = local_compute_fluxes(domain)
+
+        domain.compute_fluxes()
+        
+        print domain.quantities['stage'].vertex_values
+        print domain.quantities['xmomentum'].vertex_values
+        print domain.quantities['elevation'].vertex_values
+        print domain.quantities['height'].vertex_values
+        print domain.quantities['velocity'].vertex_values
+
+        print domain.quantities['stage'].boundary_values
+        print domain.quantities['xmomentum'].boundary_values
+        print domain.quantities['elevation'].boundary_values
+        print domain.quantities['height'].boundary_values
+        print domain.quantities['velocity'].boundary_values
+        
+        print domain.quantities['stage'].explicit_update
+        print domain.quantities['xmomentum'].explicit_update
+        print stage_ud
+        print xmom_ud
+
+        assert allclose( domain.quantities['stage'].explicit_update, stage_ud )
+        assert allclose( domain.quantities['xmomentum'].explicit_update, xmom_ud )
+
+
+    def test_local_flux_function(self):
+        normal = 1.0
+        ql = array([1.0, 2.0],Float)
+        qr = array([1.0, 2.0],Float)
+        zl = 0.0
+        zr = 0.0
+
+        #This assumes h0 = 1.0e-3!!
+        edgeflux, maxspeed = local_flux_function(normal, ql,qr,zl,zr)
+        #print maxspeed
+        #print edgeflux
+        
+        assert allclose(array([2.0, 8.9],Float), edgeflux, rtol=1.0e-005)
+        assert allclose(5.1305, maxspeed, rtol=1.0e-005)
+
+        normal = -1.0
+        ql = array([1.0, 2.0],Float)
+        qr = array([1.0, 2.0],Float)
+        zl = 0.0
+        zr = 0.0
+
+        edgeflux, maxspeed = local_flux_function(normal, ql,qr,zl,zr)
+
+
+        #print maxspeed
+        #print edgeflux        
+        
+        assert allclose(array([-2.0, -8.9],Float), edgeflux, rtol=1.0e-005)
+        assert allclose(5.1305, maxspeed, rtol=1.0e-005)
+
+
+    def test_gravity(self):
+        """
+        Compare shallow_water_domain gravity calculation
+        """
+
+        def slope_one(x):
+            return x
+
+        domain = Domain(self.points)
+        domain.set_quantity('stage',4.0)
+        domain.set_quantity('elevation',slope_one)
+        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
+
+        domain.distribute_to_vertices_and_edges()
+        domain.update_boundary()
+
+        gravity(domain)
+        
+        #print domain.quantities['stage'].vertex_values 
+        #print domain.quantities['elevation'].vertex_values 
+        #print domain.quantities['xmomentum'].explicit_update       
+
+        assert allclose( array([-34.3, -24.5, -14.7], Float), domain.quantities['xmomentum'].explicit_update )
+
+
+    def test_evolve_first_order(self):
+        """
+        Compare still lake solution for various versions of shallow_water_domain
+        """
+        
+        def slope_square(x):
+            return maximum(4.0-(x-5.0)*(x-5.0), 0.0)
+
+        domain = Domain(self.points2)
+        domain.set_quantity('stage',10.0)
+        domain.set_quantity('elevation',slope_square)
+        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
+
+        domain.default_order = 1
+        domain.set_timestepping_method('euler')
+        
+        yieldstep=0.25
+        finaltime=1.0
+
+        for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+            pass
+        
+        ##	print domain.quantities['stage'].vertex_values 
+        ##	print domain.quantities['elevation'].vertex_values 
+        ##        print domain.quantities['xmomentum'].vertex_values
+        ##  
+        ##
+        ##        print domain.quantities['stage'].centroid_values  
+        ##	print domain.quantities['elevation'].centroid_values    
+        ##        print domain.quantities['xmomentum'].centroid_values    
+
+        #assert allclose( 10.0*ones(10), domain.quantities['stage'].centroid_values )
+        #assert allclose( zeros(10), domain.quantities['xmomentum'].centroid_values )
+
+
+##     def test_evolve_euler_second_order_space(self):
+##         """
+##         Compare still lake solution for various versions of shallow_water_domain
+##         """
+
+##         def slope_square(x):
+##             return maximum(4.0-(x-5.0)*(x-5.0), 0.0)
+
+##         domain = Domain(self.points2)
+##         domain.set_quantity('stage',10.0)
+##         domain.set_quantity('elevation',slope_square)
+##         domain.set_boundary({'exterior' : Reflective_boundary(domain)})
+
+##         domain.default_order = 2
+##         domain.set_timestepping_method('rk2')
+##         yieldstep=1.0
+##         finaltime=1.0
+
+##         for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+##             pass
+        
+##         assert allclose( 10.0*ones(10), domain.quantities['stage'].centroid_values )
+##         assert allclose( zeros(10), domain.quantities['xmomentum'].centroid_values )
+
+##     def test_evolve_second_order_space_time(self):
+##         """
+##         Compare still lake solution for various versions of shallow_water_domain
+##         """
+
+##         def slope_square(x):
+##             return maximum(4.0-(x-5.0)*(x-5.0), 0.0)
+
+##         domain = Domain(self.points2)
+##         domain.set_quantity('stage',10.0)
+##         domain.set_quantity('elevation',slope_square)
+##         domain.set_boundary({'exterior' : Reflective_boundary(domain)})
+
+##         domain.default_order = 2
+##         domain.set_timestepping_method('rk3')
+
+##         yieldstep=1.0
+##         finaltime=1.0
+
+##         for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+##             pass
+        
+##         assert allclose( 10.0*ones(10), domain.quantities['stage'].centroid_values )
+##         assert allclose( zeros(10), domain.quantities['xmomentum'].centroid_values )
+
+
+
+#==============================================================================
+
+def local_compute_fluxes(domain):
+    """Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    tmp0 = zeros(N,Float)
+    tmp1 = zeros(N,Float)
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    #    Ymom = domain.quantities['ymomentum']
+    Bed = domain.quantities['elevation']
+
+    #Arrays
+    #stage = Stage.edge_values
+    #xmom =  Xmom.edge_values
+    #   ymom =  Ymom.edge_values
+    #bed =   Bed.edge_values
+    
+    stage = Stage.vertex_values
+    xmom =  Xmom.vertex_values
+    bed =   Bed.vertex_values
+    
+    #print 'stage edge values', stage
+    #print 'xmom edge values', xmom
+    #print 'bed values', bed
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    #print 'stage_bdry',stage_bdry
+    #print 'xmom_bdry', xmom_bdry
+    #    ymom_bdry =  Ymom.boundary_values
+
+    #    flux = zeros(3, Float) #Work array for summing up fluxes
+    flux = zeros(2, Float) #Work array for summing up fluxes
+    ql = zeros(2, Float)
+    qr = zeros(2, Float)
+
+    #Loop
+    timestep = float(sys.maxint)
+    enter = True
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        #for i in range(3):
+        for i in range(2):
+            #Quantities inside volume facing neighbour i
+            #ql[0] = stage[k, i]
+            #ql[1] = xmom[k, i]
+            ql = [stage[k, i], xmom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr[0] = stage_bdry[m]
+                qr[1] = xmom_bdry[m]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                #m = domain.neighbour_edges[k,i]
+                m = domain.neighbour_vertices[k,i]
+                #print i, ' ' , m
+                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                qr[0] = stage[n, m]
+                qr[1] = xmom[n, m]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, i]
+        
+            #Flux computation using provided function
+            #edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+            #print 'ql',ql
+            #print 'qr',qr
+            
+
+            edgeflux, max_speed = local_flux_function(normal, ql, qr, zl, zr)
+
+            #print 'edgeflux', edgeflux
+
+            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
+            # flux = edgefluxleft - edgefluxright
+            flux -= edgeflux #* domain.edgelengths[k,i]
+            #Update optimal_timestep
+            try:
+                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                timestep = min(timestep, domain.CFL*0.5*domain.areas[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+
+        #Stage.explicit_update[k] = flux[0]
+        tmp0[k] = flux[0]
+        tmp1[k] = flux[1]
+
+
+    return tmp0, tmp1
+
+
+def local_flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, are stored as elements 0 and 1
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from config import g, epsilon, h0
+    from math import sqrt
+    from Numeric import array
+
+    #print 'ql',ql
+
+    #Align momentums with x-axis
+    #q_left  = rotate(ql, normal, direction = 1)
+    #q_right = rotate(qr, normal, direction = 1)
+    q_left = ql
+    q_left[1] = q_left[1]*normal
+    q_right = qr
+    q_right[1] = q_right[1]*normal
+
+    #z = (zl+zr)/2 #Take average of field values
+    z = 0.5*(zl+zr) #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/(h_left +  h0/h_left)
+
+
+    uh_left = u_left*h_left
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/(h_right + h0/h_right)
+
+    uh_right = u_right*h_right
+    
+    #vh_left  = q_left[2]
+    #vh_right = q_right[2]
+
+    #print h_right
+    #print u_right
+    #print h_left
+    #print u_right
+
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+    
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+    
+    #Flux computation
+
+    #flux_left  = array([u_left*h_left,
+    #                    u_left*uh_left + 0.5*g*h_left**2])
+    #flux_right = array([u_right*h_right,
+    #                    u_right*uh_right + 0.5*g*h_right**2])
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left*h_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right*h_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+        
+        edgeflux[1] = edgeflux[1]*normal
+
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_Shallow_Water, 'test')    
+    #suite = unittest.makeSuite(Test_Quantity, 'test_set_values_from_file_using_polygon')
+
+    #suite = unittest.makeSuite(Test_Quantity, 'test_set_vertex_values_using_general_interface_with_subset')
+    #print "restricted test"
+    #suite = unittest.makeSuite(Test_Quantity,'verbose_test_set_values_from_UTM_pts')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/three_cells.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/three_cells.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/three_cells.py	(revision 7576)
@@ -0,0 +1,102 @@
+import os
+from math import sqrt, sin, cos, pi, exp
+from shallow_water_domain_suggestion3 import *
+from Numeric import zeros, Float
+
+print "TEST USING 3 CELLS"
+L=1500.0
+N=3
+cell_len=L/N
+
+points=zeros(N+1, Float)
+for i in range(N+1):
+    points[i]=i*cell_len
+
+domain=Domain(points)
+domain.order = 1
+domain.set_timestepping_method('euler')
+domain.cfl = 1.0
+domain.limiter = "minmod"
+print 'THE DOMAIN LIMITER is', domain.limiter
+
+def stage_3cells(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if x[i]<= 500.0:
+            y[i] = 1.5 #y[i]=4.0
+        elif 500.0 < x[i] < 1000.0:
+            y[i] = 1.8
+        else:
+            y[i] = 3.75 #y[i] = x[i]/150.0
+    return y
+
+def elevation_3cells(x):
+    y=zeros(len(x), Float)
+    for i in range(len(x)):
+        if x[i]<= 500.0:
+            y[i] = 0.5 #y[i]=4.0
+        elif 500.0 < x[i] < 1000.0:
+            y[i] = 1.8
+        else:
+            y[i] = 3.75 #y[i] = x[i]/150.0
+    return y
+
+
+domain.set_quantity('stage',stage_3cells)
+domain.set_quantity('elevation',elevation_3cells)
+domain.set_boundary({'exterior':Reflective_boundary(domain)})
+
+X=domain.vertices
+C=domain.centroids
+
+import time
+t0=time.time()
+yieldstep=10.0 #30.0
+finaltime=10.0 #20.0
+print "integral", domain.quantities['height'].get_integral()
+for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+    domain.write_time()
+    print "integral", domain.quantities['height'].get_integral()
+    if t>=0.0:
+        StageQ=domain.quantities['stage'].vertex_values
+        MomentumQ=domain.quantities['xmomentum'].vertex_values
+        ElevationQ=domain.quantities['elevation'].vertex_values
+
+        from pylab import clf,plot,title,xlabel,ylabel,legend,savefig,show,hold,subplot,ion
+        hold(False)
+
+        plot1 = subplot(211)
+        plot(X,StageQ, X,ElevationQ)  #plot(X,StageQ, X,h, X,ElevationQ)   #(X,ElevationQ,X,StageQ, X,h)
+        plot1.set_ylim([0.0,4.0]) #([9.999,10.006]) #([9.9999,10.0006]) #([-1.0,11.0])
+        xlabel('Position')
+        ylabel('Stage')
+        legend( ('Numerical Solution', 'Bed Elevation'), 'upper right', shadow=False)
+        #legend(('Analytical Solution', 'Numerical Solution'),
+        #   'lower right', shadow=False)
+
+        plot2 = subplot(212)
+        plot(X,MomentumQ)   #plot(X,MomentumQ, X,uh)
+        #plot2.set_ylim([-5.0,30.0])
+        legend( ('Numerical Solution', 'for momentum'), 'upper right', shadow=False)
+    
+        xlabel('Position')
+        ylabel('Xmomentum')
+
+        '''
+        plot3 = subplot(313)
+        plot(X,VelocityQ) #plot(X,MomentumQ, X,uh)
+        #plot2.set_ylim([-0.01,0.01])
+        legend( ('Numerical Solution', 'for velocity'), 'upper right', shadow=False)
+        xlabel('Position')
+        ylabel('Velocity')
+        '''
+        
+        #file = "dam_h_"
+        #file += str(number_of_cells[i])
+        #file += ".eps"
+        #savefig(file)
+        show()
+        
+print 'That took %.2f seconds'%(time.time()-t0)
+raw_input("Press return key")
+
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/util.py
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/util.py	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/util.py	(revision 7576)
@@ -0,0 +1,174 @@
+"""
+This module contains various auxiliary function used by pyvolution.
+"""
+
+def mean(x):
+    from Numeric import sum
+    return sum(x)/len(x)
+
+
+def gradient(x0, x1, q0, q1):
+
+    if q1-q0 != 0:
+        a = (q1-q0)/(x1-x0)
+    else:
+        a = 0
+        
+    return a
+
+def  minmod(beta_p,beta_m):
+    if (abs(beta_p) < abs(beta_m)) & (beta_p*beta_m > 0.0):
+        phi = beta_p
+    elif (abs(beta_m) < abs(beta_p)) & (beta_p*beta_m > 0.0):
+        phi = beta_m
+    else:
+        phi = 0.0
+    return phi
+
+def  minmod_kurganov(a,b,c):
+    from Numeric import sign
+    if sign(a)==sign(b)==sign(c):
+        return sign(a)*min(abs(a),abs(b),abs(c))
+    else:
+        return 0.0
+
+def  maxmod(a,b):
+    if (abs(a) > abs(b)) & (a*b > 0.0):
+        phi = a
+    elif (abs(b) > abs(a)) & (a*b > 0.0):
+        phi = b
+    else:
+        phi = 0.0
+    return phi
+
+def vanleer(a,b):
+    if abs(a)+abs(b) > 1e-12:
+        return (a*abs(b)+abs(a)*b)/(abs(a)+abs(b))
+    else:
+        return 0.0
+
+def vanalbada(a,b):
+    if a*a+b*b > 1e-12:
+        return (a*a*b+a*b*b)/(a*a+b*b)
+    else:
+        return 0.0
+
+def calculate_wetted_area(x1,x2,z1,z2,w1,w2):
+    if (w1 > z1) & (w2 < z2) & (z1 <= z2):
+        x = ((w2-z1)*(x2-x1)+x1*(z2-z1)-x2*(w2-w1))/(z2-z1+w1-w2)
+        A = 0.5*(w1-z1)*(x-x1)
+        L = x-x1
+    elif (w1 < z1) & (w2 > z2) & (z1 < z2):
+        x = ((w2-z1)*(x2-x1)+x1*(z2-z1)-x2*(w2-w1))/(z2-z1+w1-w2)
+        A = 0.5*(w2-z2)*(x2-x)
+        L = x2-x
+    elif (w1 < z1) & (w2 > z2) & (z1 >= z2):
+        x = ((w1-z2)*(x2-x1)+x2*(z2-z1)-x1*(w2-w1))/(z2-z1+w1-w2)
+        A = 0.5*(w2-z2)*(x2-x)
+        L = x2-x
+    elif (w1 > z1) & (w2 < z2) & (z1 > z2):
+        x = ((w1-z2)*(x2-x1)+x2*(z2-z1)-x1*(w2-w1))/(z2-z1+w1-w2)
+        A = 0.5*(w1-z1)*(x-x1)
+        L = x-x1
+    elif (w1 <= z1) & (w2 <= z2):
+        A = 0.0
+    elif (w1 == z1) & (w2 > z2) & (z2 < z1):
+        A = 0.5*(x2-x1)*(w2-z2)
+    elif (w2 == z2) & (w1 > z1) & (z1 < z2):
+        A = 0.5*(x2-x1)*(w1-z1)
+    return A
+
+
+def calculate_new_wet_area(x1,x2,z1,z2,A):
+    from Numeric import sqrt
+    min_centroid_height = 1.0e-3
+    # Assumes reconstructed stage flat in a wetted cell
+    M = (z2-z1)/(x2-x1)
+    L = (x2-x1)
+    min_area = min_centroid_height*L
+    max_area = 0.5*(x2-x1)*abs(z2-z1)
+    if A < max_area:
+        if (z1 < z2):
+            x = sqrt(2*A/M)+x1
+            wet_len = x-x1
+            wc = z1 + sqrt(M*2*A)
+        elif (z2 < z1):
+            x = -sqrt(-2*A/M)+x2
+            wet_len = x2-x 
+            wc = z2+sqrt(-M*2*A)
+        else:
+            wc = A/L+0.5*(z1+z2)
+            wet_len = x2-x1
+    else:
+        wc = 0.5*(z1+z2)+A/L
+        wet_len = x2-x1
+            
+    return wc,wet_len
+
+def calculate_new_wet_area_analytic(x1,x2,z1,z2,A,t):
+    min_centroid_height = 1.0e-3
+    # Assumes reconstructed stage flat in a wetted cell
+    M = (z2-z1)/(x2-x1)
+    L = (x2-x1)
+    min_area = min_centroid_height*L
+    max_area = 0.5*(x2-x1)*abs(z2-z1)
+    w1,uh1 = analytic_cannal(x1,t)
+    w2,uh2 = analytic_cannal(x2,t)
+    if (w1 > z1) & (w2 < z2) & (z1 <= z2):
+        print "test1"
+        x = ((w2-z1)*(x2-x1)+x1*(z2-z1)-x2*(w2-w1))/(z2-z1+w1-w2)
+        wet_len = x-x1
+    elif (w1 < z1) & (w2 > z2) & (z1 < z2):
+        print "test2"
+        x = ((w2-z1)*(x2-x1)+x1*(z2-z1)-x2*(w2-w1))/(z2-z1+w1-w2)
+        wet_len = x2-x
+    elif (w1 < z1) & (w2 > z2) & (z1 >= z2):
+        print "test3"
+        x = ((w1-z2)*(x2-x1)+x2*(z2-z1)-x1*(w2-w1))/(z2-z1+w1-w2)
+        wet_len = x2-x
+    elif (w1 > z1) & (w2 < z2) & (z1 > z2):
+        print "test4"
+        x = ((w1-z2)*(x2-x1)+x2*(z2-z1)-x1*(w2-w1))/(z2-z1+w1-w2)
+        wet_len = x-x1
+    elif (w1 >= z1) & (w2 >= z2):
+        print "test5"
+        wet_len = x2-x1 
+    else: #(w1 <= z1) & (w2 <= z2)
+        print "test5"
+        if (w1 > z1) | (w2 > z2):
+            print "ERROR"
+        wet_len = x2-x1        
+    return w1,w2,wet_len,uh1,uh2
+
+def analytic_cannal(C,t):
+    from Numeric import zeros, Float,sqrt,sin,cos
+
+    
+    #N = len(C)
+    #u = zeros(N,Float)    ## water velocity
+    #h = zeros(N,Float)    ## water depth
+    x = C
+    g = 9.81
+
+
+    ## Define Basin Bathymetry
+    #z_b = zeros(N,Float) ## elevation of basin
+    #z = zeros(N,Float)   ## elevation of water surface
+    z_infty = 10.0       ## max equilibrium water depth at lowest point.
+    L_x = 2500.0         ## width of channel
+
+    A0 = 0.5*L_x                  ## determines amplitudes of oscillations
+    omega = sqrt(2*g*z_infty)/L_x ## angular frequency of osccilation
+
+    x1 = A0*cos(omega*t)-L_x # left shoreline
+    x2 = A0*cos(omega*t)+L_x # right shoreline
+    if (x >=x1) & (x <= x2):
+        z_b = z_infty*(x**2/L_x**2) ## or A0*cos(omega*t)\pmL_x
+        u = -A0*omega*sin(omega*t)
+        z = z_infty+2*A0*z_infty/L_x*cos(omega*t)*(x/L_x-0.5*A0/(L_x)*cos(omega*t))
+    else:
+       z_b = z_infty*(x**2/L_x**2)
+       u=0.0
+       z = z_b
+    h = z-z_b
+    return z,u*h
Index: /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/util_ext.h
===================================================================
--- /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/util_ext.h	(revision 7576)
+++ /anuga_work/development/anuga_1d/anuga_1d_suggestion1_2_3/util_ext.h	(revision 7576)
@@ -0,0 +1,360 @@
+// Python - C extension for finite_volumes util module.
+//
+// To compile (Python2.3):
+//  gcc -c util_ext.c -I/usr/include/python2.3 -o util_ext.o -Wall -O 
+//  gcc -shared util_ext.o  -o util_ext.so	
+//
+// See the module util.py
+//
+//
+// Ole Nielsen, GA 2004
+	
+#include "Python.h"	
+#include "Numeric/arrayobject.h"
+#include "math.h"
+
+
+double max(double x, double y) {  
+  //Return maximum of two doubles
+  
+  if (x > y) return x;
+  else return y;
+}
+
+
+double min(double x, double y) {  
+  //Return minimum of two doubles
+  
+  if (x < y) return x;
+  else return y;
+}
+
+
+int _gradient(double x0, double y0, 
+	      double x1, double y1, 
+	      double x2, double y2, 
+	      double q0, double q1, double q2, 
+	      double *a, double *b) {
+	      
+  /*Compute gradient (a,b) based on three points (x0,y0), (x1,y1) and (x2,y2) 
+  with values q0, q1 and q2.
+  
+  Extrapolation formula (q0 is selected as an arbitrary origin)
+    q(x,y) = q0 + a*(x-x0) + b*(y-y0)                    (1)
+  
+  Substituting the known values for q1 and q2 into (1) yield the 
+  equations for a and b 
+  
+      q1-q0 = a*(x1-x0) + b*(y1-y0)                      (2)
+      q2-q0 = a*(x2-x0) + b*(y2-y0)                      (3)      
+      
+  or in matrix form
+  
+  /               \  /   \   /       \  
+  |  x1-x0  y1-y0 |  | a |   | q1-q0 |
+  |               |  |   | = |       | 
+  |  x2-x0  y2-y0 |  | b |   | q2-q0 |
+  \               /  \   /   \       /
+   
+  which is solved using the standard determinant technique    
+      
+  */
+	      
+
+  double det;
+  
+  det = (y2-y0)*(x1-x0) - (y1-y0)*(x2-x0);
+
+  *a = (y2-y0)*(q1-q0) - (y1-y0)*(q2-q0);
+  *a /= det;
+
+  *b = (x1-x0)*(q2-q0) - (x2-x0)*(q1-q0);
+  *b /= det;
+
+  return 0;
+}
+
+
+int _gradient2(double x0, double y0, 
+	       double x1, double y1, 
+	       double q0, double q1, 
+	       double *a, double *b) {
+  /*Compute gradient (a,b) between two points (x0,y0) and (x1,y1) 
+  with values q0 and q1 such that the plane is constant in the direction 
+  orthogonal to (x1-x0, y1-y0).
+  
+  Extrapolation formula
+    q(x,y) = q0 + a*(x-x0) + b*(y-y0)                    (1)
+  
+  Substituting the known values for q1 into (1) yields an 
+  under determined  equation for a and b 
+      q1-q0 = a*(x1-x0) + b*(y1-y0)                      (2)
+      
+      
+  Now add the additional requirement that the gradient in the direction 
+  orthogonal to (x1-x0, y1-y0) should be zero. The orthogonal direction 
+  is given by the vector (y0-y1, x1-x0).
+  
+  Define the point (x2, y2) = (x0 + y0-y1, y0 + x1-x0) on the orthognal line. 
+  Then we know that the corresponding value q2 should be equal to q0 in order 
+  to obtain the zero gradient, hence applying (1) again    
+      q0 = q2 = q(x2, y2) = q0 + a*(x2-x0) + b*(y2-y0)
+                          = q0 + a*(x0 + y0-y1-x0) + b*(y0 + x1-x0 - y0)
+			  = q0 + a*(y0-y1) + b*(x1-x0)
+			  
+  leads to the orthogonality constraint
+     a*(y0-y1) + b*(x1-x0) = 0                           (3) 
+     
+  which closes the system and yields
+  
+  /               \  /   \   /       \  
+  |  x1-x0  y1-y0 |  | a |   | q1-q0 |
+  |               |  |   | = |       | 
+  |  y0-y1  x1-x0 |  | b |   |   0   |
+  \               /  \   /   \       /
+   
+  which is solved using the standard determinant technique    
+      
+  */
+
+  double det, xx, yy, qq;
+  
+  xx = x1-x0;
+  yy = y1-y0;
+  qq = q1-q0;
+    
+  det = xx*xx + yy*yy;  //FIXME  catch det == 0
+  *a = xx*qq/det;
+  *b = yy*qq/det;
+        
+  return 0;
+}
+
+
+void _limit_old(int N, double beta, double* qc, double* qv, 
+	    double* qmin, double* qmax) { 
+
+  //N are the number of elements
+  int k, i, k3;
+  double dq, dqa[3], phi, r;
+  
+  //printf("INSIDE\n");
+  for (k=0; k<N; k++) {
+    k3 = k*3;
+    
+    //Find the gradient limiter (phi) across vertices  
+    phi = 1.0;
+    for (i=0; i<3; i++) {    
+      r = 1.0;
+      
+      dq = qv[k3+i] - qc[k];    //Delta between vertex and centroid values
+      dqa[i] = dq;              //Save dq for use in the next loop
+      
+      if (dq > 0.0) r = (qmax[k] - qc[k])/dq;
+      if (dq < 0.0) r = (qmin[k] - qc[k])/dq;      
+  
+  
+      phi = min( min(r*beta, 1.0), phi);    
+    }
+    
+    //Then update using phi limiter
+    for (i=0; i<3; i++) {    
+      qv[k3+i] = qc[k] + phi*dqa[i];
+    }
+  }
+}
+
+
+void  print_double_array(char* name, double* array, int n, int m){
+
+    int k,i,km;
+
+    printf("%s = [",name);
+    for (k=0; k<n; k++){
+	km = m*k;
+	printf("[");
+	for (i=0; i<m ; i++){
+	    printf("%g ",array[km+i]);
+	}
+	if (k==(n-1))
+	    printf("]");
+	else
+	    printf("]\n");
+    }
+    printf("]\n");
+}
+
+void  print_int_array(char* name, int* array, int n, int m){
+
+    int k,i,km;
+
+    printf("%s = [",name);
+    for (k=0; k<n; k++){
+	km = m*k;
+	printf("[");
+	for (i=0; i<m ; i++){
+	    printf("%i ",array[km+i]);
+	}
+	if (k==(n-1))
+	    printf("]");
+	else
+	    printf("]\n");
+    }
+    printf("]\n");
+}
+
+
+void  print_long_array(char* name, long* array, int n, int m){
+
+    int k,i,km;
+
+    printf("%s = [",name);
+    for (k=0; k<n; k++){
+	km = m*k;
+	printf("[");
+	for (i=0; i<m ; i++){
+	  printf("%i ",(int) array[km+i]);
+	}
+	if (k==(n-1))
+	    printf("]");
+	else
+	    printf("]\n");
+    }
+    printf("]\n");
+}
+
+void print_numeric_array(PyArrayObject *x) {  
+  int i, j;
+  for (i=0; i<x->dimensions[0]; i++) {  
+    for (j=0; j<x->dimensions[1]; j++) {
+      printf("%f ", *(double*) (x->data + i*x->strides[0] + j*x->strides[1]));
+    }
+    printf("\n");  
+  }
+  printf("\n");    
+}
+
+void print_numeric_vector(PyArrayObject *x) {  
+  int i;
+  for (i=0; i<x->dimensions[0]; i++) {
+    printf("%f ", *(double*) (x->data + i*x->strides[0]));  
+  }
+  printf("\n");  
+}
+
+PyArrayObject *get_consecutive_array(PyObject *O, char *name) {
+  PyArrayObject *A, *B;
+  
+
+  //Get array object from attribute
+  
+  /*
+  //FIXME: THE TEST DOESN't WORK
+  printf("Err = %d\n", PyObject_HasAttrString(O, name));
+  if (PyObject_HasAttrString(O, name) == 1) {
+    B = (PyArrayObject*) PyObject_GetAttrString(O, name);
+    if (!B) return NULL;
+  } else {
+    return NULL;
+    } 
+  */
+    
+  B = (PyArrayObject*) PyObject_GetAttrString(O, name);
+
+  //printf("B = %p\n",(void*)B);
+  if (!B) {
+    printf("util_ext.h: get_consecutive_array could not obtain python object");
+    printf(" %s\n",name);
+    fflush(stdout);
+    PyErr_SetString(PyExc_RuntimeError, "util_ext.h: get_consecutive_array could not obtain python object");
+    return NULL;
+  }     
+  
+  //Convert to consecutive array
+  A = (PyArrayObject*) PyArray_ContiguousFromObject((PyObject*) B, 
+						    B -> descr -> type, 0, 0);
+  
+  Py_DECREF(B); //FIXME: Is this really needed??
+  
+  if (!A) {
+    printf("util_ext.h: get_consecutive_array could not obtain array object");
+    printf(" %s \n",name);
+    fflush(stdout);
+    PyErr_SetString(PyExc_RuntimeError, "util_ext.h: get_consecutive_array could not obtain array");
+    return NULL;
+  }
+
+
+  return A;
+}
+
+
+
+double get_python_double(PyObject *O, char *name) {
+  PyObject *TObject;
+  #define BUFFER_SIZE 80
+  char buf[BUFFER_SIZE];
+  double tmp;
+  int n;
+  
+
+  //Get double from attribute
+  TObject = PyObject_GetAttrString(O, name);
+  if (!TObject) {
+	n =  snprintf(buf, BUFFER_SIZE, "util_ext.h: get_python_double could not obtain double %s.\n", name);
+	//printf("name = %s",name);
+    PyErr_SetString(PyExc_RuntimeError, buf);
+
+    return 0.0;
+  }  
+  
+  tmp = PyFloat_AsDouble(TObject);
+  
+  Py_DECREF(TObject);
+  
+  return tmp;
+}
+
+
+
+
+int get_python_integer(PyObject *O, char *name) {
+  PyObject *TObject;
+  #define BUFFER_SIZE 80
+  char buf[BUFFER_SIZE];
+  long tmp;
+  int n;
+  
+
+  //Get double from attribute
+  TObject = PyObject_GetAttrString(O, name);
+  if (!TObject) {
+  	n =  snprintf(buf, BUFFER_SIZE, "util_ext.h: get_python_integer could not obtain double %s.\n", name);
+	//printf("name = %s",name);
+    PyErr_SetString(PyExc_RuntimeError, buf);
+    return 0;
+  }  
+  
+  tmp = PyInt_AsLong(TObject);
+  
+  Py_DECREF(TObject);
+  
+  return tmp;
+}
+
+
+PyObject *get_python_object(PyObject *O, char *name) {
+  PyObject *Oout;
+
+  Oout = PyObject_GetAttrString(O, name);
+  if (!Oout) {
+    PyErr_SetString(PyExc_RuntimeError, "util_ext.h: get_python_object could not obtain object");
+    return NULL;
+  }
+
+  return Oout;
+
+}
+
+
+
