Index: /trunk/anuga_work/development/2010-projects/anuga_1d/channel/channel_domain.py
===================================================================
--- /trunk/anuga_work/development/2010-projects/anuga_1d/channel/channel_domain.py	(revision 8244)
+++ /trunk/anuga_work/development/2010-projects/anuga_1d/channel/channel_domain.py	(revision 8245)
@@ -174,10 +174,10 @@
         self.plot1 = pylab.subplot(311)
 
-        self.zplot, = pylab.plot(x, z)
-        self.wplot, = pylab.plot(x, w)
+        self.zplot, = pylab.plot(x, z, 'k')
+        self.wplot, = pylab.plot(x, w, 'k')
 
         self.plot1.set_ylim(stage_lim)
         #pylab.xlabel('Position')
-        pylab.ylabel('Stage')
+        pylab.ylabel('Bed/Stage')
 
         #-------------------------------
@@ -186,5 +186,5 @@
         self.plot2 = pylab.subplot(312)
 
-        self.bplot, = pylab.plot(x, b)
+        self.bplot, = pylab.plot(x, b, 'k')
 
         self.plot2.set_ylim(width_lim)
@@ -197,5 +197,5 @@
         self.plot3 = pylab.subplot(313)
 
-        self.vplot, = pylab.plot(x, v)
+        self.vplot, = pylab.plot(x, v, 'k')
 
         self.plot3.set_ylim(velocity_lim)
Index: /trunk/anuga_work/development/2010-projects/anuga_1d/channel/circular_test.py
===================================================================
--- /trunk/anuga_work/development/2010-projects/anuga_1d/channel/circular_test.py	(revision 8244)
+++ /trunk/anuga_work/development/2010-projects/anuga_1d/channel/circular_test.py	(revision 8245)
@@ -15,5 +15,5 @@
 
 
-def initialize_plotting(domain, style = '-',
+def initialize_plotting(domain, style = '-k',
                         stage_lim = [-1.0, 40.0],
                         velocity_lim = [-5.0, 5.0]):
@@ -178,5 +178,5 @@
 yieldstep = 0.2
 
-initialize_plotting(domain, style = '.', stage_lim = [0.0, 16.0],
+initialize_plotting(domain, style = '.k', stage_lim = [0.0, 16.0],
                             velocity_lim = [-10.0, 10.0])
 
@@ -190,5 +190,5 @@
 #-------------------------------------------------------------
 
-domain1 = Domain(*uniform_mesh(5000, x_0 = 0.0, x_1 = 100.0))
+domain1 = Domain(*uniform_mesh(1000, x_0 = 0.0, x_1 = 100.0))
 
 
@@ -221,7 +221,7 @@
 
 
-hold_plotting(domain1, save="circular_dam_break_not_well_balanced")
-
-
-
-
+hold_plotting(domain1, save="circular_dam_break_well_balanced")
+
+
+
+
Index: /trunk/anuga_work/development/2010-projects/anuga_1d/channel/var_width_depth.py
===================================================================
--- /trunk/anuga_work/development/2010-projects/anuga_1d/channel/var_width_depth.py	(revision 8244)
+++ /trunk/anuga_work/development/2010-projects/anuga_1d/channel/var_width_depth.py	(revision 8245)
@@ -115,5 +115,5 @@
 domain.initialize_plotting(stage_lim = [-1.0, 20.0],
                            width_lim = [0.0, 6.0],
-                           velocity_lim = [-1.0, 1.0])
+                           velocity_lim = [-15.0, 15.0])
 
 
@@ -125,4 +125,4 @@
 #print domain.quantities['elevation'].vertex_values
 
-domain.hold_plotting()
+domain.hold_plotting(save='not_well_balanced_random_depth_and_width')
 
Index: /trunk/anuga_work/shallow_water_balanced_steve/__init__.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/__init__.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/__init__.py	(revision 8245)
@@ -0,0 +1,21 @@
+"""Make directory available as a Python package
+"""
+
+# Add path of package to PYTHONPATH to allow C-extensions to be loaded
+import sys
+sys.path += __path__
+
+# Make selected classes available directly
+from swb_domain import Domain,\
+     Transmissive_boundary, Reflective_boundary,\
+     Dirichlet_boundary, Time_boundary, File_boundary,\
+     Transmissive_momentum_set_stage_boundary,\
+     Dirichlet_discharge_boundary,\
+     Field_boundary,\
+     Transmissive_stage_zero_momentum_boundary,\
+     Transmissive_n_momentum_zero_t_momentum_set_stage_boundary,\
+     AWI_boundary
+
+
+
+ 
Index: /trunk/anuga_work/shallow_water_balanced_steve/domain.lic
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/domain.lic	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/domain.lic	(revision 8245)
@@ -0,0 +1,16 @@
+<?xml version='1.0' encoding='iso-8859-1'?>
+<ga_license_file>
+  <metadata>
+    <author>Ole Nielsen</author>
+  </metadata>
+  <datafile>
+    <filename>domain.csv</filename>
+    <checksum>2053574511</checksum>
+    <publishable>Yes</publishable>
+    <accountable>Ole Nielsen</accountable>
+    <source>Geoscience Australia</source>
+    <IP_owner>Geoscience Australia</IP_owner>
+    <IP_info></IP_info>
+  </datafile>
+
+</ga_license_file>
Index: /trunk/anuga_work/shallow_water_balanced_steve/run_boundary_condition_time.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/run_boundary_condition_time.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/run_boundary_condition_time.py	(revision 8245)
@@ -0,0 +1,72 @@
+
+
+import numpy as num
+from swb_domain import *
+
+
+"""test_boundary_condition_time
+
+This tests that boundary conditions are evaluated
+using the right time from domain.
+"""
+
+# Setup computational domain
+from anuga.abstract_2d_finite_volumes.mesh_factory \
+     import rectangular_cross
+
+#--------------------------------------------------------------
+# Setup computational domain
+#--------------------------------------------------------------
+N = 20
+points, vertices, boundary = rectangular_cross(N, N)
+domain = Domain(points, vertices, boundary)
+
+#--------------------------------------------------------------
+# Setup initial conditions
+#--------------------------------------------------------------
+domain.set_quantity('elevation', 0.0)
+domain.set_quantity('friction', 0.0)
+domain.set_quantity('stage', 0.0)
+
+#--------------------------------------------------------------
+# Setup boundary conditions
+#--------------------------------------------------------------
+# Time dependent boundary
+Bt = Time_boundary(domain=domain, f=lambda t: [t, 0.0, 0.0])
+
+Br = Reflective_boundary(domain)              # Reflective wall
+
+domain.set_boundary({'left': Bt, 'right': Br, 'top': Br, 'bottom': Br})
+
+
+
+interactive_visualisation = True
+
+#===============================================================================
+if interactive_visualisation:
+    from anuga.visualiser import RealtimeVisualiser
+    vis = RealtimeVisualiser(domain)
+    vis.render_quantity_height("elevation", zScale =1.0, dynamic=True)    
+    vis.render_quantity_height("stage", zScale =1.0, dynamic=True)
+    vis.colour_height_quantity('stage', (1.0, 0.5, 0.5))
+    vis.start()
+#===============================================================================
+
+
+
+for t in domain.evolve(yieldstep = 0.02, finaltime = 20.0):
+    #print domain.get_time()
+    #q = Bt.evaluate()
+    
+    # FIXME (Ole): This test would not have passed in
+    # changeset:5846.
+    #msg = 'Time boundary not evaluated correctly'
+    #assert num.allclose(t, q[0]), msg
+
+    domain.write_time()
+    if interactive_visualisation:
+        vis.update()
+
+if interactive_visualisation:
+    vis.evolveFinished()    
+    
Index: /trunk/anuga_work/shallow_water_balanced_steve/run_step.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/run_step.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/run_step.py	(revision 8245)
@@ -0,0 +1,124 @@
+"""Simple water flow example using ANUGA
+
+Will Powers example of a simple sinusoidal wave which showed diffusive effects of
+thefirst order and standard second order method. Problem resolved if "rk2" timestepping
+and higher beta = 2 limiter used. Also new edge limiter with rk2 resolves problem 
+"""
+
+#------------------------------------------------------------------------------
+# Import necessary modules
+#------------------------------------------------------------------------------
+
+import sys
+import anuga
+from swb_domain import *
+
+from math import cos
+import numpy as num
+from time import localtime, strftime, gmtime
+from os import sep
+
+
+
+#-------------------------------------------------------------------------------
+# Copy scripts to time stamped output directory and capture screen
+# output to file
+#-------------------------------------------------------------------------------
+time = strftime('%Y%m%d_%H%M%S',localtime())
+
+#output_dir = 'step_'+time
+output_dir = '.'
+output_file = 'data_step_'+time
+
+#copy_code_files(output_dir,__file__)
+#start_screen_catcher(output_dir+sep)
+
+interactive_visualisation = True
+
+#------------------------------------------------------------------------------
+# Setup domain
+#------------------------------------------------------------------------------
+dx = 1000.
+dy = dx
+L = 100000.
+W = 10*dx
+
+# structured mesh
+points, vertices, boundary = anuga.rectangular_cross(int(L/dx), int(W/dy), L, W, (0.0, -W/2))
+
+domain = Domain(points, vertices, boundary) 
+
+domain.set_name(output_file)                
+domain.set_datadir(output_dir)  
+
+#------------------------------------------------------------------------------
+# Setup Algorithm
+#------------------------------------------------------------------------------
+domain.set_timestepping_method('rk2')
+domain.set_default_order(2)
+
+print domain.get_timestepping_method()
+
+#domain.use_edge_limiter = True
+#domain.tight_slope_limiters = False
+#domain.use_centroid_velocities = False
+
+
+#------------------------------------------------------------------------------
+# Setup initial conditions
+#------------------------------------------------------------------------------
+domain.set_quantity('elevation',-100.0)
+domain.set_quantity('friction', 0.00)
+domain.set_quantity('stage', 0.0)
+
+def stage(x,y):
+    z = num.zeros_like(x)
+    num.putmask(z, (2*L/5 < x) * (x < 3*L/5) , 1.0)
+    return z
+
+domain.set_quantity('stage', stage  )            
+
+#-----------------------------------------------------------------------------
+# Setup boundary conditions
+#------------------------------------------------------------------------------
+from math import sin, pi, exp
+Br = anuga.Reflective_boundary(domain)      # Solid reflective wall
+Bt = anuga.Transmissive_boundary(domain)    # Continue all values on boundary
+Bd = anuga.Dirichlet_boundary([1,0.,0.]) # Constant boundary values
+amplitude = 1
+Bw = anuga.Time_boundary(domain=domain,     # Time dependent boundary
+## Sine wave
+                  f=lambda t: [(-amplitude*sin((1./300.)*t*2*pi)), 0.0, 0.0])
+## Sawtooth?
+#                   f=lambda t: [(-8.0*(sin((1./180.)*t*2*pi))+(1./2.)*sin((2./180.)*t*2*pi)+(1./3.)*sin((3./180.)*t*2*pi)), 0.0, 0.0])
+## Sharp rise, linear fall
+#                   f=lambda t: [(5.0*(-((t-0.)/300.)*(t<300.)-cos((t-300.)*2.*pi*(1./240.))*(t>=300. and t<420.)+(1.-(t-420.)/300.)*(t>=420. and t <720.))), 0.0, 0.0])
+#                   f=lambda t: [amplitude*(1.-2.*(pi*(1./720.)*(t-720.))**2)/exp((pi*(1./720.)*(t-720.))**2) , 0.0, 0.0])
+#                   f=lambda t: [(-8.0*sin((1./720.)*t*2*pi))*((t<720.)-0.5*(t<360.)), 0.0, 0.0])
+
+# Associate boundary tags with boundary objects
+domain.set_boundary({'left': Bt, 'right': Bt, 'top': Br, 'bottom': Br})
+
+
+#===============================================================================
+if interactive_visualisation:
+    from anuga.visualiser import RealtimeVisualiser
+    vis = RealtimeVisualiser(domain)
+    vis.render_quantity_height("stage", zScale =10000, dynamic=True)
+    vis.colour_height_quantity('stage', (1.0, 0.5, 0.5))
+    vis.start()
+#===============================================================================
+
+
+#------------------------------------------------------------------------------
+# Evolve system through time
+#------------------------------------------------------------------------------
+
+for t in domain.evolve(yieldstep = 50.0, finaltime = 60*60.):
+    domain.write_time()
+    if interactive_visualisation:
+        vis.update()
+
+if interactive_visualisation:
+    vis.evolveFinished()
+
Index: /trunk/anuga_work/shallow_water_balanced_steve/run_wave.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/run_wave.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/run_wave.py	(revision 8245)
@@ -0,0 +1,117 @@
+"""Simple water flow example using ANUGA
+
+Will Powers example of a simple sinusoidal wave which showed diffusive effects of
+thefirst order and standard second order method. Problem resolved if "rk2" timestepping
+and higher beta = 2 limiter used. Also new edge limiter with rk2 resolves problem 
+"""
+
+#------------------------------------------------------------------------------
+# Import necessary modules
+#------------------------------------------------------------------------------
+
+import sys
+import anuga
+from swb_domain import *
+
+from math import cos
+import numpy as num
+from time import localtime, strftime, gmtime
+from os import sep
+
+
+
+#-------------------------------------------------------------------------------
+# Copy scripts to time stamped output directory and capture screen
+# output to file
+#-------------------------------------------------------------------------------
+time = strftime('%Y%m%d_%H%M%S',localtime())
+
+output_dir = '.'
+output_file = 'data_wave_'+time
+
+#copy_code_files(output_dir,__file__)
+#start_screen_catcher(output_dir+sep)
+
+interactive_visualisation = True
+
+#------------------------------------------------------------------------------
+# Setup domain
+#------------------------------------------------------------------------------
+dx = 1000.
+dy = dx
+L = 100000.
+W = 10*dx
+
+# structured mesh
+points, vertices, boundary = anuga.rectangular_cross(int(L/dx), int(W/dy), L, W, (0.0, -W/2))
+
+domain = Domain(points, vertices, boundary) 
+
+domain.set_name(output_file)                
+domain.set_datadir(output_dir)  
+
+#------------------------------------------------------------------------------
+# Setup Algorithm
+#------------------------------------------------------------------------------
+domain.set_timestepping_method('rk2')
+domain.set_default_order(2)
+
+print domain.get_timestepping_method()
+
+#domain.use_edge_limiter = True
+#domain.tight_slope_limiters = False
+#domain.use_centroid_velocities = False
+
+
+#------------------------------------------------------------------------------
+# Setup initial conditions
+#------------------------------------------------------------------------------
+domain.set_quantity('elevation',-100.0)
+domain.set_quantity('friction', 0.00)
+domain.set_quantity('stage', 0.0)            
+
+#-----------------------------------------------------------------------------
+# Setup boundary conditions
+#------------------------------------------------------------------------------
+from math import sin, pi, exp
+Br = anuga.Reflective_boundary(domain)      # Solid reflective wall
+Bt = anuga.Transmissive_boundary(domain)    # Continue all values on boundary
+Bd = anuga.Dirichlet_boundary([1,0.,0.]) # Constant boundary values
+amplitude = 1
+wave_length = 1000.0
+Bw = anuga.Time_boundary(domain=domain,     # Time dependent boundary
+## Sine wave
+                  f=lambda t: [(-amplitude*sin((1./wave_length)*t*2*pi)), 0.0, 0.0])
+## Sawtooth?
+#                   f=lambda t: [(-8.0*(sin((1./180.)*t*2*pi))+(1./2.)*sin((2./180.)*t*2*pi)+(1./3.)*sin((3./180.)*t*2*pi)), 0.0, 0.0])
+## Sharp rise, linear fall
+#                   f=lambda t: [(5.0*(-((t-0.)/300.)*(t<300.)-cos((t-300.)*2.*pi*(1./240.))*(t>=300. and t<420.)+(1.-(t-420.)/300.)*(t>=420. and t <720.))), 0.0, 0.0])
+#                   f=lambda t: [amplitude*(1.-2.*(pi*(1./720.)*(t-720.))**2)/exp((pi*(1./720.)*(t-720.))**2) , 0.0, 0.0])
+#                   f=lambda t: [(-8.0*sin((1./720.)*t*2*pi))*((t<720.)-0.5*(t<360.)), 0.0, 0.0])
+
+# Associate boundary tags with boundary objects
+domain.set_boundary({'left': Bw, 'right': Bt, 'top': Br, 'bottom': Br})
+
+
+#===============================================================================
+if interactive_visualisation:
+    from anuga.visualiser import RealtimeVisualiser
+    vis = RealtimeVisualiser(domain)
+    vis.render_quantity_height("stage", zScale =10000, dynamic=True)
+    vis.colour_height_quantity('stage', (1.0, 0.5, 0.5))
+    vis.start()
+#===============================================================================
+
+
+#------------------------------------------------------------------------------
+# Evolve system through time
+#------------------------------------------------------------------------------
+
+for t in domain.evolve(yieldstep = 50.0, finaltime = 60*60.):
+    domain.write_time()
+    if interactive_visualisation:
+        vis.update()
+
+if interactive_visualisation:
+    vis.evolveFinished()
+
Index: /trunk/anuga_work/shallow_water_balanced_steve/run_wave_shelf.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/run_wave_shelf.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/run_wave_shelf.py	(revision 8245)
@@ -0,0 +1,139 @@
+"""Simple water flow example using ANUGA
+
+Oscillatory wave from off shore coming into shore
+"""
+
+#------------------------------------------------------------------------------
+# Import necessary modules
+#------------------------------------------------------------------------------
+
+import sys
+import anuga
+from swb_domain import *
+
+from math import cos
+import numpy as num
+from time import localtime, strftime, gmtime
+from os import sep
+
+
+
+#-------------------------------------------------------------------------------
+# Copy scripts to time stamped output directory and capture screen
+# output to file
+#-------------------------------------------------------------------------------
+time = strftime('%Y%m%d_%H%M%S',localtime())
+
+output_dir = '.'
+output_file = 'data_wave_shelf_'+time
+
+#copy_code_files(output_dir,__file__)
+#start_screen_catcher(output_dir+sep)
+
+interactive_visualisation = True
+
+#------------------------------------------------------------------------------
+# Setup domain
+#------------------------------------------------------------------------------
+dx = 1000.
+dy = dx
+L = 150000.
+W = 10*dx
+
+# structured mesh
+points, vertices, boundary = anuga.rectangular_cross(int(L/dx), int(W/dy), L, W, (0.0, -W/2))
+
+domain = Domain(points, vertices, boundary)
+
+domain.set_name(output_file)                
+domain.set_datadir(output_dir)  
+
+#------------------------------------------------------------------------------
+# Setup Algorithm
+#------------------------------------------------------------------------------
+domain.set_timestepping_method('rk2')
+domain.set_default_order(2)
+
+print domain.get_timestepping_method()
+
+#domain.use_edge_limiter = True
+#domain.tight_slope_limiters = False
+#domain.use_centroid_velocities = False
+
+
+#------------------------------------------------------------------------------
+# Setup initial conditions
+#------------------------------------------------------------------------------
+depth1 = -100.0
+depth2 = -30.00
+def topography(x,y):
+    z = num.zeros_like(x)
+    z[:] = depth1
+
+    N = len(x)
+    for i in range(N):
+        if  40000.0 < x[i] < 60000.0:
+            z[i] = depth1 + (depth2-depth1)*((x[i] - 40000.0)/20000.0)
+
+        if x[i] > 60000.0:
+            z[i] = depth2
+
+        if x[i] > 100000.0:
+            z[i] = depth2*(1.0 - 1.1*(x[i] - 100000.0)/50000)
+    return z
+
+domain.set_quantity('elevation',topography)
+domain.set_quantity('friction', 0.00)
+domain.set_quantity('stage', 0.0)            
+
+#-----------------------------------------------------------------------------
+# Setup boundary conditions
+#------------------------------------------------------------------------------
+from math import sin, pi, exp
+Br = anuga.Reflective_boundary(domain)      # Solid reflective wall
+Bt = anuga.Transmissive_boundary(domain)    # Continue all values on boundary
+Bd = anuga.Dirichlet_boundary([1,0.,0.]) # Constant boundary values
+amplitude = 1
+wave_length = 2000.0
+Bw = anuga.Time_boundary(domain=domain,     # Time dependent boundary
+## Sine wave
+                  f=lambda t: [(amplitude*sin((1./wave_length)*t*2*pi)), 0.0, 0.0])
+## Sawtooth?
+#                   f=lambda t: [(-8.0*(sin((1./180.)*t*2*pi))+(1./2.)*sin((2./180.)*t*2*pi)+(1./3.)*sin((3./180.)*t*2*pi)), 0.0, 0.0])
+## Sharp rise, linear fall
+#                   f=lambda t: [(5.0*(-((t-0.)/300.)*(t<300.)-cos((t-300.)*2.*pi*(1./240.))*(t>=300. and t<420.)+(1.-(t-420.)/300.)*(t>=420. and t <720.))), 0.0, 0.0])
+#                   f=lambda t: [amplitude*(1.-2.*(pi*(1./720.)*(t-720.))**2)/exp((pi*(1./720.)*(t-720.))**2) , 0.0, 0.0])
+#                   f=lambda t: [(-8.0*sin((1./720.)*t*2*pi))*((t<720.)-0.5*(t<360.)), 0.0, 0.0])
+
+# Associate boundary tags with boundary objects
+domain.set_boundary({'left': Bw, 'right': Br, 'top': Br, 'bottom': Br})
+
+
+#===============================================================================
+if interactive_visualisation:
+    from anuga.visualiser import RealtimeVisualiser
+    vis = RealtimeVisualiser(domain)
+    vis.render_quantity_height("stage", zScale =10000, dynamic=True)
+    vis.colour_height_quantity('stage', (1.0, 0.5, 0.5))
+    vis.start()
+#===============================================================================
+
+
+#------------------------------------------------------------------------------
+# Evolve system through time
+#------------------------------------------------------------------------------
+
+min = 60.0
+hr = 60*min
+
+for t in domain.evolve(yieldstep = min, finaltime = 5*hr):
+    domain.write_time()
+    if interactive_visualisation:
+        vis.update()
+
+    if domain.get_time()> 2*hr:
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+if interactive_visualisation:
+    vis.evolveFinished()
+
Index: /trunk/anuga_work/shallow_water_balanced_steve/swb_boundary_conditions.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/swb_boundary_conditions.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/swb_boundary_conditions.py	(revision 8245)
@@ -0,0 +1,33 @@
+
+from anuga.abstract_2d_finite_volumes.generic_boundary_conditions\
+     import Boundary
+
+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 Exception, 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.
+        """
+
+        if self.domain.get_centroid_transmissive_bc() :
+            q = self.domain.get_evolved_quantities(vol_id)
+        else:
+            q = self.domain.get_evolved_quantities(vol_id, edge = edge_id)
+        return q
Index: /trunk/anuga_work/shallow_water_balanced_steve/swb_domain.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/swb_domain.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/swb_domain.py	(revision 8245)
@@ -0,0 +1,444 @@
+
+from anuga.shallow_water.shallow_water_domain import *
+from anuga.shallow_water.shallow_water_domain import Domain as Sww_domain
+
+
+##############################################################################
+# Shallow Water Balanced Domain
+#
+# Uses extra evolved quantities height, elevation, xvelocity, yvelocity
+##############################################################################
+
+class Domain(Sww_domain):
+
+    def __init__(self,
+                 coordinates=None,
+                 vertices=None,
+                 boundary=None,
+                 tagged_elements=None,
+                 geo_reference=None,
+                 use_inscribed_circle=False,
+                 mesh_filename=None,
+                 use_cache=False,
+                 verbose=False,
+                 full_send_dict=None,
+                 ghost_recv_dict=None,
+                 starttime=0.0,
+                 processor=0,
+                 numproc=1,
+                 number_of_full_nodes=None,
+                 number_of_full_triangles=None):
+
+        conserved_quantities = [ 'stage', 'xmomentum', 'ymomentum']
+
+        evolved_quantities = [ 'stage', 'xmomentum', 'ymomentum', \
+                               'height', 'elevation', \
+                               'xvelocity', 'yvelocity' ]
+        
+        other_quantities = [ 'friction', 'x', 'y' ]
+
+        
+        Sww_domain.__init__(self,
+                            coordinates = coordinates,
+                            vertices = vertices,
+                            boundary = boundary,
+                            tagged_elements = tagged_elements,
+                            geo_reference = geo_reference,
+                            use_inscribed_circle = use_inscribed_circle,
+                            mesh_filename = mesh_filename,
+                            use_cache = use_cache,
+                            verbose = verbose,
+                            conserved_quantities = conserved_quantities,
+                            evolved_quantities = evolved_quantities,
+                            other_quantities = other_quantities,
+                            full_send_dict = full_send_dict,
+                            ghost_recv_dict = ghost_recv_dict,
+                            starttime = starttime,
+                            processor = processor,
+                            numproc = numproc,
+                            number_of_full_nodes = number_of_full_nodes,
+                            number_of_full_triangles = number_of_full_triangles)
+        
+        #---------------------
+        # set some defaults
+        #---------------------
+        self.set_timestepping_method(2)
+        self.set_default_order(2)
+        self.set_sloped_mannings_function(True)
+        self.set_centroid_transmissive_bc(True)
+        self.set_CFL(1.0)
+        self.set_beta(1.5)
+        self.quantities['height'].set_beta(1.5)
+
+        #--------------------------------------------
+        # Replace shallow water gravity forcing term
+        # with swb version
+        #--------------------------------------------
+        self.forcing_terms[1] = swb_gravity
+
+
+    def check_integrity(self):
+        Sww_domain.check_integrity(self)
+
+        #Check that the evolved quantities are correct (order)
+        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 "ymomentum"'
+        assert self.evolved_quantities[2] == 'ymomentum', msg
+        msg = 'Fourth evolved quantity must be "height"'
+        assert self.evolved_quantities[3] == 'height', msg
+        msg = 'Fifth evolved quantity must be "elevation"'
+        assert self.evolved_quantities[4] == 'elevation', msg
+        msg = 'Sixth evolved quantity must be "xvelocity"'
+        assert self.evolved_quantities[5] == 'xvelocity', msg        
+        msg = 'Seventh evolved quantity must be "yvelocity"'
+        assert self.evolved_quantities[6] == 'yvelocity', msg        
+
+        msg = 'First other quantity must be "friction"'
+        assert self.other_quantities[0] == 'friction', msg
+        msg = 'Second other quantity must be "x"'
+        assert self.other_quantities[1] == 'x', msg
+        msg = 'Third other quantity must be "y"'
+        assert self.other_quantities[2] == 'y', msg
+
+
+    def compute_fluxes(self):
+        """
+        Call correct module function (either from this module or C-extension)
+        """
+
+        from swb_domain_ext import compute_fluxes_c
+
+        #Shortcuts
+        W  = self.quantities['stage']
+        UH = self.quantities['xmomentum']
+        VH = self.quantities['ymomentum']
+        H  = self.quantities['height']
+        Z  = self.quantities['elevation']
+        U  = self.quantities['xvelocity']
+        V  = self.quantities['yvelocity']
+
+        timestep = self.get_evolve_max_timestep()
+        
+        self.flux_timestep = \
+            compute_fluxes_c(timestep, self, W, UH, VH, H, Z, U, V)
+
+
+    def distribute_to_vertices_and_edges(self):
+        """Distribution from centroids to edges specific to the SWW eqn.
+
+        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).
+        
+
+        Precondition:
+        All conserved quantities defined at centroids and bed elevation defined at
+        edges.
+        
+        Postcondition
+        Evolved quantities defined at vertices and edges
+        """
+
+        from anuga.shallow_water.shallow_water_domain import \
+                  protect_against_infinitesimal_and_negative_heights as protect
+    
+        #Shortcuts
+        W  = self.quantities['stage']
+        UH = self.quantities['xmomentum']
+        VH = self.quantities['ymomentum']
+        H  = self.quantities['height']
+        Z  = self.quantities['elevation']
+        U  = self.quantities['xvelocity']
+        V  = self.quantities['yvelocity']
+
+        #Arrays   
+        w_C   = W.centroid_values    
+        uh_C  = UH.centroid_values
+        vh_C  = VH.centroid_values    
+        z_C   = Z.centroid_values
+        h_C   = H.centroid_values
+        u_C   = U.centroid_values
+        v_C   = V.centroid_values
+
+        #num_min = num.min(w_C-z_C)
+        #if num_min < -1.0e-5:
+        #    print '**** num.min(w_C-z_C)', num_min
+
+    
+        w_C[:] = num.maximum(w_C, z_C)
+        h_C[:] = w_C - z_C
+
+
+        assert num.min(h_C) >= 0.0
+                
+        num.putmask(uh_C, h_C < 1.0e-15, 0.0)
+        num.putmask(vh_C, h_C < 1.0e-15, 0.0)
+        #num.putmask(h_C, h_C < 1.0e-15, 1.0e-16)
+
+        # Noelle has an alternative method for calculating velcities
+        # Check it out in the GPU shallow water paper
+        H0 = 1.0e-16
+        u_C[:]  = uh_C/(h_C + H0/h_C)
+        v_C[:]  = vh_C/(h_C + H0/h_C)
+
+        #num.putmask(h_C, h_C < 1.0e-15, 0.0)
+        
+        for name in [ 'stage', 'xvelocity', 'yvelocity' ]:
+            Q = self.quantities[name]
+            if self._order_ == 1:
+                Q.extrapolate_first_order()
+            elif self._order_ == 2:
+                Q.extrapolate_second_order_and_limit_by_edge()
+                #Q.extrapolate_second_order_and_limit_by_vertex()
+            else:
+                raise Exception('Unknown order: %s' % str(self._order_))
+
+        for name in [ 'height' ]:
+            Q = self.quantities[name]
+            if self._order_ == 1:
+                Q.extrapolate_first_order()
+            elif self._order_ == 2:
+                #Q.extrapolate_second_order_and_limit_by_edge()
+                Q.extrapolate_second_order_and_limit_by_vertex()
+            else:
+                raise Exception('Unknown order: %s' % str(self._order_))
+
+
+        w_V     = W.vertex_values 
+        u_V     = U.vertex_values
+        v_V     = V.vertex_values
+        z_V     = Z.vertex_values
+
+        h_V     = H.vertex_values
+        uh_V    = UH.vertex_values
+        vh_V    = VH.vertex_values
+        
+
+        # Update other quantities
+        #protect(self)
+
+        z_V[:]  = w_V - h_V
+        uh_V[:] = u_V * h_V
+        vh_V[:] = v_V * h_V
+
+        
+        num_min = num.min(h_V)
+        if num_min < -1.0e-14:
+            print 'num.min(h_V)', num_min
+
+        
+        # Compute edge values by interpolation
+        for name in ['xmomentum', 'ymomentum', 'elevation']:
+            Q = self.quantities[name]
+            Q.interpolate_from_vertices_to_edges()
+
+
+
+
+
+    def distribute_to_vertices_and_edges_h(self):
+        """Distribution from centroids to edges specific to the SWW eqn.
+
+        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).
+        
+
+        Precondition:
+        All conserved quantities defined at centroids and bed elevation defined at
+        edges.
+        
+        Postcondition
+        Evolved quantities defined at vertices and edges
+        """
+
+
+        #Shortcuts
+        W  = self.quantities['stage']
+        UH = self.quantities['xmomentum']
+        VH = self.quantities['ymomentum']
+        H  = self.quantities['height']
+        Z  = self.quantities['elevation']
+        U  = self.quantities['xvelocity']
+        V  = self.quantities['yvelocity']
+
+        #Arrays   
+        w_C   = W.centroid_values    
+        uh_C  = UH.centroid_values
+        vh_C  = VH.centroid_values    
+        z_C   = Z.centroid_values
+        h_C   = H.centroid_values
+        u_C   = U.centroid_values
+        v_C   = V.centroid_values
+
+        w_C[:] = num.maximum(w_C, z_C)
+        
+        h_C[:] = w_C - z_C
+
+
+        assert num.min(h_C) >= 0
+                
+        num.putmask(uh_C, h_C < 1.0e-15, 0.0)
+        num.putmask(vh_C, h_C < 1.0e-15, 0.0)
+        num.putmask(h_C, h_C < 1.0e-15, 1.0e-16)        
+        
+        u_C[:]  = uh_C/h_C
+        v_C[:]  = vh_C/h_C
+
+        num.putmask(h_C, h_C < 1.0e-15, 0.0)
+        
+        for name in [ 'stage', 'height', 'xvelocity', 'yvelocity' ]:
+            Q = self.quantities[name]
+            if self._order_ == 1:
+                Q.extrapolate_first_order()
+            elif self._order_ == 2:
+                Q.extrapolate_second_order_and_limit_by_edge()
+                #Q.extrapolate_second_order_and_limit_by_vertex()
+            else:
+                raise Exception('Unknown order: %s' % str(self._order_))
+
+
+        w_E     = W.edge_values
+        uh_E    = UH.edge_values
+        vh_E    = VH.edge_values	
+        h_E     = H.edge_values
+        z_E     = Z.edge_values	
+        u_E     = U.edge_values
+        v_E     = V.edge_values		
+
+
+        #minh_E = num.min(h_E)
+        #msg = 'min h_E = %g ' % minh_E
+        #assert minh_E >= -1.0e-15, msg
+
+        z_E[:]   = w_E - h_E
+
+        num.putmask(h_E, h_E <= 1.0e-8, 0.0)
+        num.putmask(u_E, h_E <= 1.0e-8, 0.0)
+        num.putmask(v_E, h_E <= 1.0e-8, 0.0)
+        num.putmask(w_E, h_E <= 1.0e-8, z_E)
+        #num.putmask(h_E, h_E <= 0.0, 0.0)
+        
+        uh_E[:] = u_E * h_E
+        vh_E[:] = v_E * h_E
+
+        """
+        print '=========================================================='
+        print 'Time ', self.get_time()
+        print h_E
+        print uh_E
+        print vh_E
+        """
+        
+        # Compute vertex values by interpolation
+        for name in self.evolved_quantities:
+            Q = self.quantities[name]
+            Q.interpolate_from_edges_to_vertices()
+
+
+        w_V     = W.vertex_values
+        uh_V    = UH.vertex_values
+        vh_V    = VH.vertex_values	
+        z_V     = Z.vertex_values	
+        h_V     = H.vertex_values
+        u_V     = U.vertex_values
+        v_V     = V.vertex_values		
+
+
+        #w_V[:]    = z_V + h_V
+
+        #num.putmask(u_V, h_V <= 0.0, 0.0)
+        #num.putmask(v_V, h_V <= 0.0, 0.0)
+        #num.putmask(w_V, h_V <= 0.0, z_V)        
+        #num.putmask(h_V, h_V <= 0.0, 0.0)
+        
+        uh_V[:] = u_V * h_V
+        vh_V[:] = v_V * h_V
+
+
+
+
+    def conserved_values_to_evolved_values(self, q_cons, q_evol):
+        """Mapping between conserved quantities and the evolved quantities.
+        Used where we have a boundary condition which works with conserved
+        quantities and we now want to use them for the new well balanced
+        code using the evolved quantities
+
+        Typically the old boundary condition will set the values in q_cons,
+
+        q_evol on input will have the values of the evolved quantities at the
+        edge point (useful as it provides values for evlevation).
+        """
+
+        wc  = q_cons[0]
+        uhc = q_cons[1]
+        vhc = q_cons[2]
+
+        we  = q_evol[0]
+        uhe = q_evol[1]
+        vhe = q_evol[2]
+
+        he  = q_evol[3]
+        be  = q_evol[4]
+        ue  = q_evol[5]
+        ve  = q_evol[6]
+
+
+        hc = wc - be
+
+        if hc <= 0.0:
+            hc = 0.0
+            uc = 0.0
+            vc = 0.0
+        else:
+            uc = uhc/hc
+            vc = vhc/hc
+
+        q_evol[0]  = wc
+        q_evol[1]  = uhc
+        q_evol[2]  = vhc
+
+        q_evol[3]  = hc
+        q_evol[4]  = be
+        q_evol[5]  = uc
+        q_evol[6]  = vc
+
+
+        return q_evol
+
+ 
+################################################################################
+# Standard forcing terms
+################################################################################
+
+def swb_gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    Wrapper calls underlying C implementation
+    """
+
+    from swb_domain_ext import gravity_c
+
+    #print "Using swb gravity"
+
+    xmom_update = domain.quantities['xmomentum'].explicit_update
+    ymom_update = domain.quantities['ymomentum'].explicit_update
+
+    stage     = domain.quantities['stage']
+    elevation = domain.quantities['elevation']
+
+
+    stage     = stage.vertex_values
+    elevation = elevation.vertex_values
+
+    points = domain.get_vertex_coordinates()
+
+    gravity_c(domain.g, stage, elevation, points, xmom_update, ymom_update)
Index: /trunk/anuga_work/shallow_water_balanced_steve/swb_domain_ext.c
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/swb_domain_ext.c	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/swb_domain_ext.c	(revision 8245)
@@ -0,0 +1,677 @@
+// Python - C extension module for shallow_water.py
+//
+// To compile (Python2.6):
+//  gcc -c swb_domain_ext.c -I/usr/include/python2.6 -o domain_ext.o -Wall -O
+//  gcc -shared swb_domain_ext.o  -o swb_domain_ext.so
+//
+// or use python compile.py
+//
+// See the module swb_domain.py for more documentation on 
+// how to use this module
+//
+//
+// Stephen Roberts, ANU 2009
+// Ole Nielsen, GA 2004
+
+
+#include "Python.h"
+#include "numpy/arrayobject.h"
+#include "math.h"
+#include <stdio.h>
+//#include "numpy_shim.h"
+
+// Shared code snippets
+#include "util_ext.h"
+
+
+const double pi = 3.14159265358979;
+
+// Computational function for rotation
+int _rotate(double *q, double n1, double n2) {
+  /*Rotate the last  2 coordinates of q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector (n1, n2).
+
+    Result is returned in array 2x1 r
+    To rotate in opposite direction, call rotate with (q, n1, -n2)
+
+    Contents of q are changed by this function */
+
+
+  double q1, q2;
+
+  // Shorthands
+  q1 = q[1];  // x coordinate
+  q2 = q[2];  // y coordinate
+
+  // Rotate
+  q[1] =  n1*q1 + n2*q2;
+  q[2] = -n2*q1 + n1*q2;
+
+  return 0;
+}
+
+// Innermost flux function
+int _flux_function(double *q_inside, double *q_outside,
+		   double n1, double n2, 
+		   double g,
+		   double *edgeflux, double *local_max_speed) 
+{
+
+  /*Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of the 'stage', 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
+  */
+
+  int i;
+
+  double z_star, h_inside_star, h_outside_star;
+  double w_inside,  h_inside,  u_inside,  v_inside,  z_inside;
+  double w_outside, h_outside, u_outside, v_outside, z_outside;
+  double s_min, s_max, soundspeed_inside, soundspeed_outside;
+  double epsilon, denom, inverse_denominator;
+
+  // Workspace
+  double cons_inside[3], cons_outside[3], flux_outside[3], flux_inside[3];
+
+  epsilon = 1.0e-15;
+
+  // Setup aliases
+  w_inside = q_inside[0]; 
+  h_inside = q_inside[3];
+  z_inside = q_inside[4];
+  u_inside = q_inside[5];
+  v_inside = q_inside[6];
+
+  w_outside = q_outside[0]; 
+  h_outside = q_outside[3];
+  z_outside = q_outside[4];
+  u_outside = q_outside[5];
+  v_outside = q_outside[6];
+
+
+  // Rotate the velocity terms and update. Setup cons_ to hold conservative rotated
+  // variables 
+  cons_inside[0] = w_inside;
+  cons_inside[1] = u_inside;
+  cons_inside[2] = v_inside;
+
+  _rotate(cons_inside, n1, n2);
+
+  u_inside = cons_inside[1];
+  v_inside = cons_inside[2];
+  cons_inside[1] = u_inside*h_inside;
+  cons_inside[2] = v_inside*h_inside;
+
+  cons_outside[0] = w_outside;
+  cons_outside[1] = u_outside;
+  cons_outside[2] = v_outside;
+
+  _rotate(cons_outside, n1, n2);
+
+  u_outside = cons_outside[1];
+  v_outside = cons_outside[2];
+  cons_outside[1] = u_outside*h_outside;
+  cons_outside[2] = v_outside*h_outside;
+
+
+
+  // Deal with discontinuous z
+  z_star = max(z_inside, z_outside);
+  h_inside_star  = max(0.0, w_inside-z_star);
+  h_outside_star = max(0.0, w_outside-z_star);
+	           
+
+  // Maximal and minimal wave speeds
+  soundspeed_inside  = sqrt(g*h_inside_star);
+  soundspeed_outside = sqrt(g*h_outside_star);  
+  
+  s_max = max(u_inside + soundspeed_inside, u_outside + soundspeed_outside);
+  s_max = max(0.0, s_max);
+
+  s_min = min(u_inside - soundspeed_inside, u_outside - soundspeed_outside);
+  s_min = min(0.0, s_min);
+  
+  // Flux formulas
+  flux_inside[0] = u_inside*h_inside_star;
+  flux_inside[1] = u_inside*u_inside*h_inside_star + 0.5*g*h_inside_star*h_inside_star;
+  flux_inside[2] = u_inside*v_inside*h_inside_star;
+
+  flux_outside[0] = u_outside*h_outside_star;
+  flux_outside[1] = u_outside*u_outside*h_outside_star + 0.5*g*h_outside_star*h_outside_star;
+  flux_outside[2] = u_outside*v_outside*h_outside_star;
+
+  // Flux computation
+  denom = s_max - s_min;
+
+  edgeflux[0] = 0.0;
+  edgeflux[1] = 0.0;
+  edgeflux[2] = 0.0;
+  
+  if (denom < epsilon) 
+    {     
+      *local_max_speed = 0.0;
+      //printf("here %g\n",h_inside);
+      // Add in edge pressure term due to discontinuous bed
+      if ( h_inside > 0.0 ) edgeflux[1] = 0.5*g*h_inside*h_inside ;
+    } 
+  else 
+    {
+      inverse_denominator = 1.0/denom;
+      for (i = 0; i < 3; i++) 
+	{
+	  edgeflux[i] = s_max*flux_inside[i] - s_min*flux_outside[i];
+	  edgeflux[i] += s_max*s_min*(cons_outside[i] - cons_inside[i]);
+	  edgeflux[i] *= inverse_denominator;
+	}
+
+      // Balance the pressure term
+      // FIXME SR: I think we need to add a term which uses simpson's rule.
+      //edgeflux[1] += 0.5*g*h_inside*h_inside - 0.5*g*h_inside_star*h_inside_star;
+      edgeflux[1] -=  0.5*g*h_inside_star*h_inside_star;
+      
+    }
+  
+// Maximal wavespeed
+  *local_max_speed = max(fabs(s_max), fabs(s_min));
+  //printf("local speed % g  h_inside %g \n",*local_max_speed, h_inside);
+  // Rotate back
+  _rotate(edgeflux, n1, -n2);
+  
+  return 0;
+}
+
+
+
+//=========================================================================
+// Python Glue
+//=========================================================================
+
+
+//========================================================================
+// Compute fluxes
+//========================================================================
+
+PyObject *compute_fluxes(PyObject *self, PyObject *args) {
+  /*Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function_central"
+
+    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.
+
+    Python call:
+    timestep = compute_fluxes(timestep, domain, stage, xmom, ymom, height, bed, xvel, yvel)
+
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      returns timestep which is the largest step satisfying all volumes.
+
+
+  */
+
+  PyObject 
+    *domain,
+    *stage, 
+    *xmom, 
+    *ymom,
+    *height,
+    *bed,
+    *xvel,
+    *yvel;
+
+    PyArrayObject 
+      *num_neighbours          ,
+      *num_neighbour_edges     ,
+      *num_normals             ,
+      *num_edgelengths         ,      
+      *num_radii               ,   
+      *num_areas               ,
+      *num_tri_full_flag       ,
+      *num_max_speed           ,
+      *num_stage_edge_values   ,
+      *num_xmom_edge_values    ,
+      *num_ymom_edge_values    ,
+      *num_height_edge_values  ,
+      *num_bed_edge_values     ,
+      *num_xvel_edge_values    ,
+      *num_yvel_edge_values    ,
+      *num_stage_boundary_values ,
+      *num_xmom_boundary_values  ,
+      *num_ymom_boundary_values  ,
+      *num_height_boundary_values,
+      *num_bed_boundary_values   ,
+      *num_xvel_boundary_values  ,
+      *num_yvel_boundary_values  ,
+      *num_stage_explicit_update ,
+      *num_xmom_explicit_update  ,
+      *num_ymom_explicit_update ;
+
+    long
+      *neighbours          ,
+      *neighbour_edges     ,
+      *tri_full_flag       ; 
+
+    double
+      *normals             ,
+      *edgelengths         ,      
+      *radii               ,   
+      *areas               ,
+      *max_speed           ,
+      *stage_edge_values   ,
+      *xmom_edge_values    ,
+      *ymom_edge_values    ,
+      *height_edge_values  ,
+      *bed_edge_values     ,
+      *xvel_edge_values    ,
+      *yvel_edge_values    ,
+      *stage_boundary_values ,
+      *xmom_boundary_values  ,
+      *ymom_boundary_values  ,
+      *height_boundary_values,
+      *bed_boundary_values   ,
+      *xvel_boundary_values  ,
+      *yvel_boundary_values  ,
+      *stage_explicit_update ,
+      *xmom_explicit_update  ,
+      *ymom_explicit_update ;
+
+    
+
+    double flux_timestep, g;
+    double local_max_speed, length, inv_area;
+
+    int k, i, m, n;
+    int ki, nm=0, ki2; // Index shorthands
+   
+    double ql[7], qr[7]; // Work arrays for storing local evolving quantities
+    double edgeflux[3];  // Work array for summing up fluxes
+
+    
+    //======================================================================
+    // Convert Python arguments to C
+    //======================================================================
+    if (!PyArg_ParseTuple(args, "dOOOOOOOO", 
+			  &flux_timestep, 
+			  &domain, 
+			  &stage, 
+			  &xmom, 
+			  &ymom, 
+			  &height,
+			  &bed,
+			  &xvel, 
+			  &yvel)) {
+      PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
+      return NULL;
+    }
+    
+    //======================================================================
+    // Extract data from python objects
+    //======================================================================
+    g = get_python_double(domain,"g");
+    
+    num_neighbours             = get_consecutive_array(domain, "neighbours");
+    num_neighbour_edges        = get_consecutive_array(domain, "neighbour_edges"); 
+    num_normals                = get_consecutive_array(domain, "normals");
+    num_edgelengths            = get_consecutive_array(domain, "edgelengths");    
+    num_radii                  = get_consecutive_array(domain, "radii");    
+    num_areas                  = get_consecutive_array(domain, "areas");    
+    num_tri_full_flag          = get_consecutive_array(domain, "tri_full_flag");
+    num_max_speed              = get_consecutive_array(domain, "max_speed");
+    
+    num_stage_edge_values      = get_consecutive_array(stage, "edge_values");    
+    num_xmom_edge_values       = get_consecutive_array(xmom, "edge_values");    
+    num_ymom_edge_values       = get_consecutive_array(ymom, "edge_values"); 
+    num_height_edge_values     = get_consecutive_array(height, "edge_values"); 
+    num_bed_edge_values        = get_consecutive_array(bed, "edge_values");       
+    num_xvel_edge_values       = get_consecutive_array(xvel, "edge_values");    
+    num_yvel_edge_values       = get_consecutive_array(yvel, "edge_values");    
+    
+    num_stage_boundary_values  = get_consecutive_array(stage, "boundary_values");    
+    num_xmom_boundary_values   = get_consecutive_array(xmom, "boundary_values");    
+    num_ymom_boundary_values   = get_consecutive_array(ymom, "boundary_values"); 
+    num_height_boundary_values = get_consecutive_array(height, "boundary_values"); 
+    num_bed_boundary_values    = get_consecutive_array(bed, "boundary_values"); 
+    num_xvel_boundary_values   = get_consecutive_array(xvel, "boundary_values"); 
+    num_yvel_boundary_values   = get_consecutive_array(yvel, "boundary_values"); 
+    
+    num_stage_explicit_update  = get_consecutive_array(stage, "explicit_update");    
+    num_xmom_explicit_update   = get_consecutive_array(xmom, "explicit_update");    
+    num_ymom_explicit_update   = get_consecutive_array(ymom, "explicit_update"); 
+    
+    //---------------------------------------------------------------------------
+    
+    neighbours         = (long *) num_neighbours-> data;
+    neighbour_edges    = (long *) num_neighbour_edges-> data;
+    normals            = (double *) num_normals -> data;
+    edgelengths        = (double *) num_edgelengths -> data;
+    radii              = (double *) num_radii -> data;
+    areas              = (double *) num_areas -> data; 
+    tri_full_flag      = (long *) num_tri_full_flag -> data; 
+    max_speed          = (double *) num_max_speed -> data;
+    
+    stage_edge_values       = (double *) num_stage_edge_values -> data;   
+    xmom_edge_values        = (double *) num_xmom_edge_values -> data;
+    ymom_edge_values        = (double *) num_ymom_edge_values -> data;
+    height_edge_values      = (double *) num_height_edge_values -> data;
+    bed_edge_values         = (double *) num_bed_edge_values -> data;
+    xvel_edge_values        = (double *) num_xvel_edge_values -> data;
+    yvel_edge_values        = (double *) num_yvel_edge_values -> data;
+    
+    stage_boundary_values      = (double *) num_stage_boundary_values -> data; 
+    xmom_boundary_values       = (double *) num_xmom_boundary_values -> data;
+    ymom_boundary_values       = (double *) num_ymom_boundary_values -> data;
+    height_boundary_values     = (double *) num_height_boundary_values -> data;
+    bed_boundary_values        = (double *) num_bed_boundary_values -> data;
+    xvel_boundary_values       = (double *) num_xvel_boundary_values -> data;
+    yvel_boundary_values       = (double *) num_yvel_boundary_values -> data;
+    
+    stage_explicit_update      = (double *) num_stage_explicit_update -> data;
+    xmom_explicit_update       = (double *) num_xmom_explicit_update -> data;
+    ymom_explicit_update       = (double *) num_ymom_explicit_update -> data;
+    
+    
+    int number_of_elements = num_stage_edge_values -> dimensions[0];
+
+    //======================================================================
+    // Flux computation routine and update the explicit update arrays 
+    //======================================================================
+
+    // Set explicit_update to zero for all conserved_quantities.
+    // This assumes compute_fluxes called before forcing terms
+
+    memset((char*) stage_explicit_update, 0, number_of_elements*sizeof(double));
+    memset((char*) xmom_explicit_update, 0, number_of_elements*sizeof(double));
+    memset((char*) ymom_explicit_update, 0, number_of_elements*sizeof(double));    
+  
+    // For all triangles
+    for (k = 0; k < number_of_elements; k++) 
+      {  
+	max_speed[k] = 0.0;
+
+	// Loop through neighbours and compute edge flux for each  epsilon
+	for (i = 0; i < 3; i++) 
+	  {
+	    ki = k*3 + i; // Linear index to edge i of triangle k
+      
+	    // Get left hand side values from triangle k, edge i 
+	    ql[0] = stage_edge_values[ki];
+	    ql[1] = xmom_edge_values[ki];
+	    ql[2] = ymom_edge_values[ki];
+	    ql[3] = height_edge_values[ki];
+	    ql[4] = bed_edge_values[ki];
+	    ql[5] = xvel_edge_values[ki];
+	    ql[6] = yvel_edge_values[ki];
+
+	    // Get right hand side values either from neighbouring triangle
+	    // or from boundary array (Quantities at neighbour on nearest face).
+	    n = neighbours[ki];
+	    if (n < 0) 
+	      {
+		// Neighbour is a boundary condition
+		m = -n - 1; // Convert negative flag to boundary index
+		
+		qr[0] = stage_boundary_values[m];
+		qr[1] = xmom_boundary_values[m];
+		qr[2] = ymom_boundary_values[m];
+		qr[3] = height_boundary_values[m];
+		qr[4] = bed_boundary_values[m];
+		qr[5] = xvel_boundary_values[m];
+		qr[6] = yvel_boundary_values[m];
+		
+	      } 
+	    else 
+	      {
+		// Neighbour is a real triangle
+		m = neighbour_edges[ki];
+		nm = n*3 + m; // Linear index (triangle n, edge m)
+		
+		qr[0] = stage_edge_values[nm];
+		qr[1] = xmom_edge_values[nm];
+		qr[2] = ymom_edge_values[nm];
+		qr[3] = height_edge_values[nm];
+		qr[4] = bed_edge_values[nm];
+		qr[5] = xvel_edge_values[nm];
+		qr[6] = yvel_edge_values[nm];
+		
+	      }
+	    
+	    // Now we have values for this edge - both from left and right side.
+
+	    // Outward pointing normal vector (domain.normals[k, 2*i:2*i+2])
+	    ki2 = 2*ki; //k*6 + i*2
+
+	    // Edge flux computation (triangle k, edge i)
+	    _flux_function(ql,
+			   qr,
+			   normals[ki2], 
+			   normals[ki2+1],
+			   g,
+			   edgeflux, 
+			   &local_max_speed);
+	    
+	    
+	    // Multiply edgeflux by edgelength
+	    length = edgelengths[ki];
+	    edgeflux[0] *= length;            
+	    edgeflux[1] *= length;            
+	    edgeflux[2] *= length;                        
+      
+      
+	    // Update triangle k with flux from edge i
+	    stage_explicit_update[k] -= edgeflux[0];
+	    xmom_explicit_update[k]  -= edgeflux[1];
+	    ymom_explicit_update[k]  -= edgeflux[2];
+      
+
+	    // Update flux_timestep based on edge i and possibly neighbour n
+	    if (tri_full_flag[k] == 1) 
+	      {
+		if (local_max_speed > 1.0e-15) 
+		  {
+		    // Calculate safe timestep based on local_max_speed and size of triangle k
+		    // A reduction of timestep based on domain.CFL is applied in update_timestep 
+		    flux_timestep = min(flux_timestep, radii[k]/local_max_speed);
+		    
+		  }
+	      }
+	    
+	  } // End edge i 
+	
+	
+	// Normalise triangle k by area and store for when all conserved
+	// quantities get updated
+	inv_area = 1.0/areas[k];
+	stage_explicit_update[k] *= inv_area;
+	xmom_explicit_update[k]  *= inv_area;
+	ymom_explicit_update[k]  *= inv_area;
+	
+	
+	// Keep track of maximal speeds
+	max_speed[k] = max(max_speed[k],local_max_speed);
+	
+      } // End triangle k
+    
+    
+    //======================================================================
+    // Cleanup
+    //======================================================================
+
+    Py_DECREF(num_neighbours            );
+    Py_DECREF(num_neighbour_edges       );
+    Py_DECREF(num_normals               );
+    Py_DECREF(num_edgelengths           );      
+    Py_DECREF(num_radii                 );   
+    Py_DECREF(num_areas                 );
+    Py_DECREF(num_tri_full_flag         );
+    Py_DECREF(num_max_speed             );
+    Py_DECREF(num_stage_edge_values     );
+    Py_DECREF(num_xmom_edge_values      );
+    Py_DECREF(num_ymom_edge_values      );
+    Py_DECREF(num_height_edge_values    );
+    Py_DECREF(num_bed_edge_values       );
+    Py_DECREF(num_xvel_edge_values      );
+    Py_DECREF(num_yvel_edge_values      );
+    Py_DECREF(num_stage_boundary_values );
+    Py_DECREF(num_xmom_boundary_values  );
+    Py_DECREF(num_ymom_boundary_values  );
+    Py_DECREF(num_height_boundary_values);
+    Py_DECREF(num_bed_boundary_values   );
+    Py_DECREF(num_xvel_boundary_values  );
+    Py_DECREF(num_yvel_boundary_values  );
+    Py_DECREF(num_stage_explicit_update );
+    Py_DECREF(num_xmom_explicit_update  );
+    Py_DECREF(num_ymom_explicit_update  );
+
+    //======================================================================
+    // Return updated flux flux_timestep
+    //======================================================================
+    return Py_BuildValue("d", flux_timestep);
+}
+
+//========================================================================
+// Flux Function
+//========================================================================
+
+PyObject *flux_function(PyObject *self, PyObject *args) {
+  //
+  // Gateway to innermost flux function.
+  // This is only used by the unit tests as the c implementation is
+  // normally called by compute_fluxes in this module.
+
+
+  PyArrayObject *normal, *ql, *qr,  *edgeflux;
+  double g, local_max_speed;
+
+  if (!PyArg_ParseTuple(args, "OOOOd",
+            &normal, &ql, &qr, &edgeflux, &g)) {
+    PyErr_SetString(PyExc_RuntimeError, 
+		    "swb_domain_ext.c: flux_function could not parse input arguments");
+    return NULL;
+  }
+
+  
+  _flux_function((double*) ql -> data, 
+		 (double*) qr -> data, 
+		 ((double*) normal -> data)[0],
+		 ((double*) normal -> data)[1],          
+		 g,
+		 (double*) edgeflux -> data, 
+		 &local_max_speed);
+  
+  return Py_BuildValue("d", local_max_speed);  
+}
+
+
+//========================================================================
+// Gravity
+//========================================================================
+
+PyObject *gravity(PyObject *self, PyObject *args) {
+  //
+  //  gravity(g, h, v, x, xmom, ymom)
+  //
+  
+  
+  PyArrayObject *w, *z, *x, *xmom, *ymom;
+  int k, N, k3, k6;
+  double g, avg_h, wx, wy;
+  double x0, y0, x1, y1, x2, y2, w0, w1, w2, h0, h1, h2;
+  //double epsilon;
+  
+  if (!PyArg_ParseTuple(args, "dOOOOO",
+			&g, &w, &z, &x,
+			&xmom, &ymom)) {
+    //&epsilon)) {
+    PyErr_SetString(PyExc_RuntimeError, "swb_domain_ext.c: gravity could not parse input arguments");
+    return NULL;
+  }
+  
+  // check that numpy array objects arrays are C contiguous memory
+  CHECK_C_CONTIG(w);
+  CHECK_C_CONTIG(z);
+  CHECK_C_CONTIG(x);
+  CHECK_C_CONTIG(xmom);
+  CHECK_C_CONTIG(ymom);
+  
+  N = z -> dimensions[0];
+  for (k=0; k<N; k++) {
+    k3 = 3*k;  // base index
+    
+    // Get stage
+    w0 = ((double*) w -> data)[k3 + 0];
+    w1 = ((double*) w -> data)[k3 + 1];
+    w2 = ((double*) w -> data)[k3 + 2];
+
+    // Get water depth
+    h0 = ((double*) w -> data)[k3 + 0] - ((double*) z -> data)[k3 + 0];
+    h1 = ((double*) w -> data)[k3 + 1] - ((double*) z -> data)[k3 + 1];
+    h2 = ((double*) w -> data)[k3 + 2] - ((double*) z -> data)[k3 + 2];
+    
+    // Optimise for flat bed
+    // Note (Ole): This didn't produce measurable speed up.
+    // Revisit later
+    //if (fabs(z0-z1)<epsilon && fabs(z1-z2)<epsilon) {
+    //  continue;
+    //} 
+    
+    // Get average depth from centroid values
+    avg_h = 1.0/3.0*( h0 + h1 +h2 );
+    
+    // Compute bed slope
+    k6 = 6*k;  // base index
+    
+    x0 = ((double*) x -> data)[k6 + 0];
+    y0 = ((double*) x -> data)[k6 + 1];
+    x1 = ((double*) x -> data)[k6 + 2];
+    y1 = ((double*) x -> data)[k6 + 3];
+    x2 = ((double*) x -> data)[k6 + 4];
+    y2 = ((double*) x -> data)[k6 + 5];
+    
+    
+    _gradient(x0, y0, x1, y1, x2, y2, w0, w1, w2, &wx, &wy);
+    
+    // Update momentum
+    ((double*) xmom -> data)[k] += -g*wx*avg_h;
+    ((double*) ymom -> data)[k] += -g*wy*avg_h;
+  }
+  
+  return Py_BuildValue("");
+}
+
+
+
+//========================================================================
+// Method table for python module
+//========================================================================
+
+static struct PyMethodDef MethodTable[] = {
+  /* The cast of the function is necessary since PyCFunction values
+   * only take two PyObject* parameters, and rotate() takes
+   * three.
+   */
+  {"compute_fluxes_c", compute_fluxes,     METH_VARARGS, "Print out"},
+  {"gravity_c",        gravity,            METH_VARARGS, "Print out"},
+  {"flux_function_c",  flux_function,      METH_VARARGS, "Print out"},
+  {NULL, NULL, 0, NULL}
+};
+
+// Module initialisation
+void initswb_domain_ext(void){
+  Py_InitModule("swb_domain_ext", MethodTable);
+
+  import_array(); // Necessary for handling of NumPY structures
+}
Index: /trunk/anuga_work/shallow_water_balanced_steve/test_all.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/test_all.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/test_all.py	(revision 8245)
@@ -0,0 +1,83 @@
+"""Regression testing framework
+This module will search for scripts in the same directory named
+test_*.py.  Each such script should be a test suite that tests a
+module through PyUnit. This script will aggregate all
+found test suites into one big test suite and run them all at once.
+"""
+
+# Author: Mark Pilgrim
+# Modified by Ole Nielsen
+
+import unittest
+import os
+
+
+#List files that should be excluded from the testing process.
+#E.g. if they are known to fail and under development
+exclude = [] 
+
+
+def get_test_files(path):
+
+    import sys
+
+    files = os.listdir(path)
+
+    #Check sub directories
+    test_files = []
+    for file in files:
+        if os.path.isdir(file):
+            sys.path.append(file)
+            #print 'Recursing into', file
+            test_files += get_test_files(path + os.sep + file)
+        elif file[:5] == 'test_' and file[-2:] == 'py':
+            #print 'Appending', file
+            test_files.append(file)
+        else:
+            pass
+    return test_files
+
+
+
+def regressionTest():
+    import sys, os, re, unittest
+    path = os.path.split(sys.argv[0])[0] or os.getcwd()
+
+
+    files = get_test_files(path)
+
+
+
+    #test = re.compile('^test_[\w]*.py$', re.IGNORECASE)
+    #files = filter(test.search, files)
+
+
+    try:
+        files.remove(__file__)  #Remove self from list (Ver 2.3. or later)
+    except:
+        files.remove('test_all.py')
+
+    print 'Testing:'
+    for file in files:
+        print '  ' + file
+
+    if globals().has_key('exclude'):
+        for file in exclude:
+            files.remove(file)
+            print 'WARNING: File '+ file + ' excluded from testing'
+
+
+    filenameToModuleName = lambda f: os.path.splitext(f)[0]
+    #print "files",files 
+    moduleNames = map(filenameToModuleName, files)
+    #print "moduleNames",moduleNames
+    modules = map(__import__, moduleNames)
+    load = unittest.defaultTestLoader.loadTestsFromModule
+    return unittest.TestSuite(map(load, modules))
+
+################################################################################
+
+if __name__ == '__main__':   
+    suite = regressionTest()
+    runner = unittest.TextTestRunner(verbosity=1)
+    runner.run(suite)
Index: /trunk/anuga_work/shallow_water_balanced_steve/test_swb_balance.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/test_swb_balance.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/test_swb_balance.py	(revision 8245)
@@ -0,0 +1,350 @@
+#!/usr/bin/env python
+
+import unittest, os
+import os.path
+from math import pi, sqrt
+import tempfile
+
+from anuga.config import g, epsilon
+from anuga.config import netcdf_mode_r, netcdf_mode_w, netcdf_mode_a
+from anuga.utilities.numerical_tools import mean
+from anuga.geometry.polygon import is_inside_polygon
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+from anuga.abstract_2d_finite_volumes.quantity import Quantity
+from anuga.geospatial_data.geospatial_data import Geospatial_data
+from anuga.abstract_2d_finite_volumes.mesh_factory import rectangular_cross
+
+from anuga.utilities.system_tools import get_pathname_from_package
+from swb_domain import *
+
+import numpy as num
+
+# Get gateway to C implementation of flux function for direct testing
+from shallow_water_ext import flux_function_central as flux_function
+
+
+
+
+class Test_swb_clean(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+
+    def test_balance_deep_and_shallow(self):
+        """Test that balanced limiters preserve conserved quantites.
+        This test is using old depth based balanced limiters
+        """
+
+        import copy
+
+        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] ]
+
+        domain = Domain(points, elements)
+        domain.check_integrity()
+
+        # Create a deliberate overshoot
+        domain.set_quantity('stage', [[3,0,3], [2,2,6], [5,3,8], [8,3,5]])
+        domain.set_quantity('elevation', 0)    # Flat bed
+        stage = domain.quantities['stage']
+
+        ref_centroid_values = copy.copy(stage.centroid_values[:])    # Copy
+
+        # Limit
+        domain.distribute_to_vertices_and_edges()
+
+        # Assert that quantities are conserved
+        for k in range(len(domain)):
+            assert num.allclose(ref_centroid_values[k],
+                                num.sum(stage.vertex_values[k,:])/3)
+
+        # Now try with a non-flat bed - closely hugging initial stage in places
+        domain.set_quantity('stage', [[3,0,3], [2,2,6], [5,3,8], [8,3,5]])
+        domain.set_quantity('elevation', [[0,0,0],
+                                          [1.8,1.9,5.9],
+                                          [4.6,0,0],
+                                          [0,2,4]])
+        stage = domain.quantities['stage']
+        #elevation = domain.quantities['elevation']
+        #height = domain.quantities['height']
+
+        ref_centroid_values = copy.copy(stage.centroid_values[:])    # Copy
+        ref_vertex_values = copy.copy(stage.vertex_values[:])        # Copy
+
+        # Limit
+        domain.distribute_to_vertices_and_edges()
+
+        # Assert that all vertex quantities have changed
+        for k in range(len(domain)):
+            assert not num.allclose(ref_vertex_values[k,:],
+                                    stage.vertex_values[k,:])
+        # and assert that quantities are still conserved
+        for k in range(len(domain)):
+            assert num.allclose(ref_centroid_values[k],
+                                num.sum(stage.vertex_values[k,:])/3)
+
+        # Check actual results
+
+        #print stage.vertex_values
+
+        assert num.allclose(stage.vertex_values,
+                            [[ 2.         , 2.         , 2.        ],
+                             [ 2.22222222 , 2.22222222 , 5.55555556],
+                             [ 5.33333333 , 5.33333333 , 5.33333333],
+                             [ 5.33333333 , 5.33333333 , 5.33333333]])
+
+
+    def test_balance_deep_and_shallow_tight_SL(self):
+        """Test that balanced limiters preserve conserved quantites.
+        This test is using Tight Slope Limiters
+        """
+
+        import copy
+
+        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] ]
+
+        domain = Domain(points, elements)
+        domain.check_integrity()
+
+        # Create a deliberate overshoot
+        domain.set_quantity('stage', [[3,0,3], [2,2,6], [5,3,8], [8,3,5]])
+        domain.set_quantity('elevation', 0)    # Flat bed
+        stage = domain.quantities['stage']
+
+        ref_centroid_values = copy.copy(stage.centroid_values[:])    # Copy
+
+        # Limit
+        domain.tight_slope_limiters = 1
+        domain.distribute_to_vertices_and_edges()
+
+        # Assert that quantities are conserved
+        for k in range(len(domain)):
+            assert num.allclose (ref_centroid_values[k],
+                                 num.sum(stage.vertex_values[k,:])/3)
+
+        # Now try with a non-flat bed - closely hugging initial stage in places
+        # This will create alphas in the range [0, 0.478260, 1]
+        domain.set_quantity('stage', [[3,0,3], [2,2,6], [5,3,8], [8,3,5]])
+        domain.set_quantity('elevation', [[0,0,0],
+                                          [1.8,1.9,5.9],
+                                          [4.6,0,0],
+                                          [0,2,4]])
+        stage = domain.quantities['stage']
+
+        ref_centroid_values = copy.copy(stage.centroid_values[:])    # Copy
+        ref_vertex_values = copy.copy(stage.vertex_values[:])        # Copy
+
+        # Limit
+        domain.tight_slope_limiters = 1
+        domain.distribute_to_vertices_and_edges()
+
+        # Assert that all vertex quantities have changed
+        for k in range(len(domain)):
+            assert not num.allclose(ref_vertex_values[k,:],
+                                    stage.vertex_values[k,:])
+        # and assert that quantities are still conserved
+        for k in range(len(domain)):
+            assert num.allclose(ref_centroid_values[k],
+                                num.sum(stage.vertex_values[k,:])/3)
+
+    def test_balance_deep_and_shallow_Froude(self):
+        """Test that balanced limiters preserve conserved quantites -
+        and also that excessive Froude numbers are dealt with.
+        This test is using tight slope limiters.
+        """
+
+        import copy
+
+        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] ]
+
+        domain = Domain(points, elements)
+        domain.check_integrity()
+        domain.tight_slope_limiters = True
+        domain.use_centroid_velocities = True
+
+        # Create non-flat bed - closely hugging initial stage in places
+        # This will create alphas in the range [0, 0.478260, 1]
+        domain.set_quantity('stage', [[3,0,3], [2,2,6], [5,3,8], [8,3,5]])
+        domain.set_quantity('elevation', [[0,0,0],
+                                          [1.8,1.999,5.999],
+                                          [4.6,0,0],
+                                          [0,2,4]])
+
+        # Create small momenta, that nonetheless will generate large speeds
+        # due to shallow depth at isolated vertices
+        domain.set_quantity('xmomentum', -0.0058)
+        domain.set_quantity('ymomentum', 0.0890)
+
+        stage = domain.quantities['stage']
+        elevation = domain.quantities['elevation']
+        xmomentum = domain.quantities['xmomentum']
+        ymomentum = domain.quantities['ymomentum']
+
+        # Setup triangle #1 to mimick real Froude explosion observed
+        # in the Onslow example 13 Nov 2007.
+        stage.vertex_values[1,:] = [1.6385, 1.6361, 1.2953]
+        elevation.vertex_values[1,:] = [1.6375, 1.6336, 0.4647]
+        xmomentum.vertex_values[1,:] = [-0.0058, -0.0050, -0.0066]
+        ymomentum.vertex_values[1,:] = [0.0890, 0.0890, 0.0890]
+
+        xmomentum.interpolate()
+        ymomentum.interpolate()
+        stage.interpolate()
+        elevation.interpolate()
+
+        # Verify interpolation
+        assert num.allclose(stage.centroid_values[1], 1.5233)
+        assert num.allclose(elevation.centroid_values[1], 1.2452667)
+        assert num.allclose(xmomentum.centroid_values[1], -0.0058)
+        assert num.allclose(ymomentum.centroid_values[1], 0.089)
+
+        # Derived quantities
+        depth = stage-elevation
+        u = xmomentum/depth
+        v = ymomentum/depth
+
+        denom = (depth*g)**0.5
+        Fx = u/denom
+        Fy = v/denom
+
+        # Verify against Onslow example (14 Nov 2007)
+        assert num.allclose(depth.centroid_values[1], 0.278033)
+        assert num.allclose(u.centroid_values[1], -0.0208608)
+        assert num.allclose(v.centroid_values[1], 0.3201055)
+
+        assert num.allclose(denom.centroid_values[1],
+                            num.sqrt(depth.centroid_values[1]*g))
+
+        assert num.allclose(u.centroid_values[1]/denom.centroid_values[1],
+                            -0.012637746977)
+        assert num.allclose(Fx.centroid_values[1],
+                            u.centroid_values[1]/denom.centroid_values[1])
+
+        # Check that Froude numbers are small at centroids.
+        assert num.allclose(Fx.centroid_values[1], -0.012637746977)
+        assert num.allclose(Fy.centroid_values[1], 0.193924048435)
+
+        # But Froude numbers are huge at some vertices and edges
+        assert num.allclose(Fx.vertex_values[1,:], [-5.85888475e+01,
+                                                    -1.27775313e+01,
+                                                    -2.78511420e-03])
+
+        assert num.allclose(Fx.edge_values[1,:], [-6.89150773e-03,
+                                                  -7.38672488e-03,
+                                                  -2.35626238e+01])
+
+        assert num.allclose(Fy.vertex_values[1,:], [8.99035764e+02,
+                                                    2.27440057e+02,
+                                                    3.75568430e-02])
+
+        assert num.allclose(Fy.edge_values[1,:], [1.05748998e-01,
+                                                  1.06035244e-01,
+                                                  3.88346947e+02])
+
+
+        # The task is now to arrange the limiters such that Froude numbers
+        # remain under control whil at the same time obeying the conservation
+        # laws.
+        ref_centroid_values = copy.copy(stage.centroid_values[:])    # Copy
+        ref_vertex_values = copy.copy(stage.vertex_values[:])        # Copy
+
+        # Limit (and invoke balance_deep_and_shallow)
+        domain.tight_slope_limiters = 1
+        domain.distribute_to_vertices_and_edges()
+
+        # Redo derived quantities
+        depth = stage - elevation
+        u = xmomentum/depth
+        v = ymomentum/depth
+
+        # Assert that all vertex velocities stay within one
+        # order of magnitude of centroid velocities.
+        assert num.alltrue(num.absolute(u.vertex_values[1,:]) <=
+                           num.absolute(u.centroid_values[1])*10)
+        assert num.alltrue(num.absolute(v.vertex_values[1,:]) <=
+                           num.absolute(v.centroid_values[1])*10)
+
+        denom = (depth*g)**0.5
+        Fx = u/denom
+        Fy = v/denom
+
+        # Assert that Froude numbers are less than max value (TBA)
+        # at vertices, edges and centroids.
+        from anuga.config import maximum_froude_number
+
+        assert num.alltrue(num.absolute(Fx.vertex_values[1,:]) <
+                           maximum_froude_number)
+        assert num.alltrue(num.absolute(Fy.vertex_values[1,:]) <
+                           maximum_froude_number)
+
+        # Assert that all vertex quantities have changed
+        for k in range(len(domain)):
+            assert not num.allclose(ref_vertex_values[k,:],
+                                    stage.vertex_values[k,:])
+
+        # Assert that quantities are still conserved
+        for k in range(len(domain)):
+            assert num.allclose(ref_centroid_values[k],
+                                num.sum(stage.vertex_values[k,:])/3)
+
+        return
+
+        qwidth = 12
+        for k in [1]:    # range(len(domain)):
+            print 'Triangle %d (C, V, E)' % k
+
+            print ('stage'.ljust(qwidth), stage.centroid_values[k],
+                   stage.vertex_values[k,:], stage.edge_values[k,:])
+            print ('elevation'.ljust(qwidth), elevation.centroid_values[k],
+                   elevation.vertex_values[k,:], elevation.edge_values[k,:])
+            print ('depth'.ljust(qwidth), depth.centroid_values[k],
+                   depth.vertex_values[k,:], depth.edge_values[k,:])
+            print ('xmomentum'.ljust(qwidth), xmomentum.centroid_values[k],
+                   xmomentum.vertex_values[k,:], xmomentum.edge_values[k,:])
+            print ('ymomentum'.ljust(qwidth), ymomentum.centroid_values[k],
+                   ymomentum.vertex_values[k,:], ymomentum.edge_values[k,:])
+            print ('u'.ljust(qwidth),u.centroid_values[k],
+                   u.vertex_values[k,:], u.edge_values[k,:])
+            print ('v'.ljust(qwidth), v.centroid_values[k],
+                   v.vertex_values[k,:], v.edge_values[k,:])
+            print ('Fx'.ljust(qwidth), Fx.centroid_values[k],
+                   Fx.vertex_values[k,:], Fx.edge_values[k,:])
+            print ('Fy'.ljust(qwidth), Fy.centroid_values[k],
+                   Fy.vertex_values[k,:], Fy.edge_values[k,:])
+
+
+#################################################################################
+
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_swb_clean, 'test')
+    runner = unittest.TextTestRunner(verbosity=1)
+    runner.run(suite)
Index: /trunk/anuga_work/shallow_water_balanced_steve/test_swb_basic.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/test_swb_basic.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/test_swb_basic.py	(revision 8245)
@@ -0,0 +1,2154 @@
+#!/usr/bin/env python
+
+import unittest, os
+import os.path
+from math import pi, sqrt
+import tempfile
+
+import anuga
+
+from anuga.config import g, epsilon
+from anuga.config import netcdf_mode_r, netcdf_mode_w, netcdf_mode_a
+from anuga.utilities.numerical_tools import mean
+from anuga.geometry.polygon import is_inside_polygon
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+from anuga.abstract_2d_finite_volumes.quantity import Quantity
+from anuga.geospatial_data.geospatial_data import Geospatial_data
+from anuga.abstract_2d_finite_volumes.mesh_factory import rectangular_cross
+
+from anuga.utilities.system_tools import get_pathname_from_package
+from swb_domain import *
+
+import numpy as num
+
+# Get gateway to C implementation of flux function for direct testing
+from shallow_water_ext import flux_function_central as flux_function
+
+
+# For test_fitting_using_shallow_water_domain example
+def linear_function(point):
+    point = num.array(point)
+    return point[:,0]+point[:,1]
+
+class Weir:
+    """Set a bathymetry for weir with a hole and a downstream gutter
+    x,y are assumed to be in the unit square
+    """
+
+    def __init__(self, stage):
+        self.inflow_stage = stage
+
+    def __call__(self, x, y):
+        N = len(x)
+        assert N == len(y)
+
+        z = num.zeros(N, num.float)
+        for i in range(N):
+            z[i] = -x[i]/2  #General slope
+
+            #Flattish bit to the left
+            if x[i] < 0.3:
+                z[i] = -x[i]/10
+
+            #Weir
+            if x[i] >= 0.3 and x[i] < 0.4:
+                z[i] = -x[i]+0.9
+
+            #Dip
+            x0 = 0.6
+            depth = -1.0
+            plateaux = -0.6
+            if y[i] < 0.7:
+                if x[i] > x0 and x[i] < 0.9:
+                    z[i] = depth
+                #RHS plateaux
+                if x[i] >= 0.9:
+                    z[i] = plateaux
+            elif y[i] >= 0.7 and y[i] < 1.5:
+                #Restrict and deepen
+                if x[i] >= x0 and x[i] < 0.8:
+                    z[i] = depth - (y[i]/3 - 0.3)
+                elif x[i] >= 0.8:
+                    #RHS plateaux
+                    z[i] = plateaux
+            elif y[i] >= 1.5:
+                if x[i] >= x0 and x[i] < 0.8 + (y[i]-1.5)/1.2:
+                    #Widen up and stay at constant depth
+                    z[i] = depth-1.5/5
+                elif x[i] >= 0.8 + (y[i]-1.5)/1.2:
+                    #RHS plateaux
+                    z[i] = plateaux
+
+            #Hole in weir (slightly higher than inflow condition)
+            if x[i] >= 0.3 and x[i] < 0.4 and y[i] > 0.2 and y[i] < 0.4:
+                z[i] = -x[i]+self.inflow_stage + 0.02
+
+            #Channel behind weir
+            x0 = 0.5
+            if x[i] >= 0.4 and x[i] < x0 and y[i] > 0.2 and y[i] < 0.4:
+                z[i] = -x[i]+self.inflow_stage + 0.02
+
+            if x[i] >= x0 and x[i] < 0.6 and y[i] > 0.2 and y[i] < 0.4:
+                #Flatten it out towards the end
+                z[i] = -x0+self.inflow_stage + 0.02 + (x0-x[i])/5
+
+            # Hole to the east
+            x0 = 1.1
+            y0 = 0.35
+            if num.sqrt((2*(x[i]-x0))**2 + (2*(y[i]-y0))**2) < 0.2:
+                z[i] = num.sqrt(((x[i]-x0))**2 + ((y[i]-y0))**2)-1.0
+
+            #Tiny channel draining hole
+            if x[i] >= 1.14 and x[i] < 1.2 and y[i] >= 0.4 and y[i] < 0.6:
+                z[i] = -0.9 #North south
+
+            if x[i] >= 0.9 and x[i] < 1.18 and y[i] >= 0.58 and y[i] < 0.65:
+                z[i] = -1.0 + (x[i]-0.9)/3 #East west
+
+            # Stuff not in use
+
+            # Upward slope at inlet to the north west
+            # if x[i] < 0.0: # and y[i] > 0.5:
+            #    #z[i] = -y[i]+0.5  #-x[i]/2
+            #    z[i] = x[i]/4 - y[i]**2 + 0.5
+
+            # Hole to the west
+            # x0 = -0.4; y0 = 0.35 # center
+            # if sqrt((2*(x[i]-x0))**2 + (2*(y[i]-y0))**2) < 0.2:
+            #    z[i] = sqrt(((x[i]-x0))**2 + ((y[i]-y0))**2)-0.2
+
+        return z/2
+
+
+
+#########################################################
+
+class Test_swb_basic(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+
+    def test_rotate(self):
+        from anuga.shallow_water.shallow_water_ext import rotate
+        normal = num.array([0.0, -1.0])
+
+        q = num.array([1.0, 2.0, 3.0])
+
+        r = rotate(q, normal, direction = 1)
+        assert r[0] == 1
+        assert r[1] == -3
+        assert r[2] == 2
+
+        w = rotate(r, normal, direction = -1)
+        assert num.allclose(w, q)
+
+        # Check error check
+        try:
+            rotate(r, num.array([1, 1, 1]))
+        except:
+            pass
+        else:
+            raise Exception('Should have raised an exception')
+
+    # Individual flux tests
+    def test_flux_zero_case(self):
+        ql = num.zeros(3, num.float)
+        qr = num.zeros(3, num.float)
+        normal = num.zeros(2, num.float)
+        edgeflux = num.zeros(3, num.float)
+        zl = zr = 0.
+        H0 = 1.0e-3 # As suggested in the manual
+        
+        max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux, epsilon, g, H0)
+
+        assert num.allclose(edgeflux, [0,0,0])
+        assert max_speed == 0.
+
+    def test_flux_constants(self):
+        w = 2.0
+
+        normal = num.array([1.,0])
+        ql = num.array([w, 0, 0])
+        qr = num.array([w, 0, 0])
+        edgeflux = num.zeros(3, num.float)
+        zl = zr = 0.
+        h = w - (zl+zr)/2
+        H0 = 0.0
+
+        max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux, epsilon, g, H0)        
+        assert num.allclose(edgeflux, [0., 0.5*g*h**2, 0.])
+        assert max_speed == num.sqrt(g*h)
+
+    #def test_flux_slope(self):
+    #    #FIXME: TODO
+    #    w = 2.0
+    #
+    #    normal = array([1.,0])
+    #    ql = array([w, 0, 0])
+    #    qr = array([w, 0, 0])
+    #    zl = zr = 0.
+    #    h = w - (zl+zr)/2
+    #
+    #    flux, max_speed = flux_function(normal, ql, qr, zl, zr)
+    #
+    #    assert allclose(flux, [0., 0.5*g*h**2, 0.])
+    #    assert max_speed == sqrt(g*h)
+
+    def test_flux1(self):
+        # Use data from previous version of abstract_2d_finite_volumes
+        normal = num.array([1., 0])
+        ql = num.array([-0.2, 2, 3])
+        qr = num.array([-0.2, 2, 3])
+        zl = zr = -0.5
+        edgeflux = num.zeros(3, num.float)
+
+        H0 = 0.0
+
+        max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux,
+                                  epsilon, g, H0)
+
+        assert num.allclose(edgeflux, [2., 13.77433333, 20.])
+        assert num.allclose(max_speed, 8.38130948661)
+
+    def test_flux2(self):
+        # Use data from previous version of abstract_2d_finite_volumes
+        normal = num.array([0., -1.])
+        ql = num.array([-0.075, 2, 3])
+        qr = num.array([-0.075, 2, 3])
+        zl = zr = -0.375
+
+        edgeflux = num.zeros(3, num.float)
+        H0 = 0.0
+        max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux,
+                                  epsilon, g, H0)
+
+        assert num.allclose(edgeflux, [-3., -20.0, -30.441])
+        assert num.allclose(max_speed, 11.7146428199)
+
+    def test_flux3(self):
+        # Use data from previous version of abstract_2d_finite_volumes
+        normal = num.array([-sqrt(2)/2, sqrt(2)/2])
+        ql = num.array([-0.075, 2, 3])
+        qr = num.array([-0.075, 2, 3])
+        zl = zr = -0.375
+
+        edgeflux = num.zeros(3, num.float)
+        H0 = 0.0
+        max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux,
+                                  epsilon, g, H0)
+
+        assert num.allclose(edgeflux, [sqrt(2)/2, 4.40221112, 7.3829019])
+        assert num.allclose(max_speed, 4.0716654239)
+
+    def test_flux4(self):
+        # Use data from previous version of abstract_2d_finite_volumes
+        normal = num.array([-sqrt(2)/2, sqrt(2)/2])
+        ql = num.array([-0.34319278, 0.10254161, 0.07273855])
+        qr = num.array([-0.30683287, 0.1071986, 0.05930515])
+        zl = zr = -0.375
+
+        edgeflux = num.zeros(3, num.float)
+        H0 = 0.0
+        max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux,
+                                  epsilon, g, H0)
+
+        assert num.allclose(edgeflux, [-0.04072676, -0.07096636, -0.01604364])
+        assert num.allclose(max_speed, 1.31414103233)
+
+    def test_flux_computation(self):
+        """test flux calculation (actual C implementation)
+
+        This one tests the constant case where only the pressure term
+        contributes to each edge and cancels out once the total flux has
+        been summed up.
+        """
+
+        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)
+        domain.check_integrity()
+
+        # The constant case
+        domain.set_quantity('elevation', -1)
+        domain.set_quantity('stage', 1)
+
+        domain.compute_fluxes()
+        # Central triangle
+        assert num.allclose(domain.get_quantity('stage').explicit_update[1], 0)
+
+        # The more general case
+        def surface(x, y):
+            return -x/2
+
+        domain.set_quantity('elevation', -10)
+        domain.set_quantity('stage', surface)
+        domain.set_quantity('xmomentum', 1)
+
+        domain.compute_fluxes()
+
+        #print domain.get_quantity('stage').explicit_update
+        # FIXME (Ole): TODO the general case
+        #assert allclose(domain.get_quantity('stage').explicit_update[1], ...??)
+
+    def test_sw_domain_simple(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]]
+
+        #from anuga.abstract_2d_finite_volumes.domain import Domain as Generic_domain
+        #msg = 'The class %s is not a subclass of the generic domain class %s'\
+        #      %(DomainClass, Domain)
+        #assert issubclass(DomainClass, Domain), msg
+
+        domain = Domain(points, vertices)
+        domain.check_integrity()
+
+        for name in ['stage', 'xmomentum', 'ymomentum',
+                     'elevation', 'friction']:
+            assert domain.quantities.has_key(name)
+
+        assert num.alltrue(domain.get_conserved_quantities(0, edge=1) == 0.)
+
+    def xtest_catching_negative_heights(self):
+        #OBSOLETE
+
+        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)
+        val0 = 2. + 2.0/3
+        val1 = 4. + 4.0/3
+        val2 = 8. + 2.0/3
+        val3 = 2. + 8.0/3
+
+        zl = zr = 4    # Too large
+        domain.set_quantity('elevation', zl*num.ones((4, 3), num.int)) #array default#
+        domain.set_quantity('stage', [[val0, val0-1, val0-2],
+                                      [val1, val1+1, val1],
+                                      [val2, val2-2, val2],
+                                      [val3-0.5, val3, val3]])
+
+        #Should fail
+        try:
+            domain.check_integrity()
+        except:
+            pass
+
+    def test_get_wet_elements(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)
+
+        val0 = 2. + 2.0/3
+        val1 = 4. + 4.0/3
+        val2 = 8. + 2.0/3
+        val3 = 2. + 8.0/3
+
+        zl = zr = 5
+        domain.set_quantity('elevation', zl*num.ones((4, 3), num.int)) #array default#
+        domain.set_quantity('stage', [[val0, val0-1, val0-2],
+                                      [val1, val1+1, val1],
+                                      [val2, val2-2, val2],
+                                      [val3-0.5, val3, val3]])
+
+        domain.check_integrity()
+
+        indices = domain.get_wet_elements()
+        assert num.allclose(indices, [1, 2])
+
+        indices = domain.get_wet_elements(indices=[0, 1, 3])
+        assert num.allclose(indices, [1])
+
+    def test_get_maximum_inundation_1(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)
+
+        domain.set_quantity('elevation', lambda x, y: x+2*y)    # 2 4 4 6
+        domain.set_quantity('stage', 3)
+
+        domain.check_integrity()
+
+        indices = domain.get_wet_elements()
+        assert num.allclose(indices, [0])
+
+        q = domain.get_maximum_inundation_elevation()
+        assert num.allclose(q, domain.get_quantity('elevation').\
+                                   get_values(location='centroids')[0])
+
+        x, y = domain.get_maximum_inundation_location()
+        assert num.allclose([x, y], domain.get_centroid_coordinates()[0])
+
+    def test_get_maximum_inundation_2(self):
+        """test_get_maximum_inundation_2(self)
+
+        Test multiple wet cells with same elevation
+        """
+
+        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)
+
+        domain.set_quantity('elevation', lambda x, y: x+2*y)    # 2 4 4 6
+        domain.set_quantity('stage', 4.1)
+
+        domain.check_integrity()
+
+        indices = domain.get_wet_elements()
+        assert num.allclose(indices, [0, 1, 2])
+
+        q = domain.get_maximum_inundation_elevation()
+        assert num.allclose(q, 4)
+
+        x, y = domain.get_maximum_inundation_location()
+        assert num.allclose([x, y], domain.get_centroid_coordinates()[1])
+
+    def test_get_maximum_inundation_3(self):
+        """test_get_maximum_inundation_3(self)
+
+        Test of real runup example:
+        """
+
+        from anuga.abstract_2d_finite_volumes.mesh_factory \
+                import rectangular_cross
+
+        initial_runup_height = -0.4
+        final_runup_height = -0.3
+
+        #--------------------------------------------------------------
+        # Setup computational domain
+        #--------------------------------------------------------------
+        N = 5
+        points, vertices, boundary = rectangular_cross(N, N)
+        domain = Domain(points, vertices, boundary)
+        domain.set_maximum_allowed_speed(1.0)
+
+        #--------------------------------------------------------------
+        # Setup initial conditions
+        #--------------------------------------------------------------
+        def topography(x, y):
+            return -x/2                             # linear bed slope
+
+        # Use function for elevation
+        domain.set_quantity('elevation', topography)
+        domain.set_quantity('friction', 0.)                # Zero friction
+        # Constant negative initial stage
+        domain.set_quantity('stage', initial_runup_height)
+
+        #--------------------------------------------------------------
+        # Setup boundary conditions
+        #--------------------------------------------------------------
+        Br = anuga.Reflective_boundary(domain)                 # Reflective wall
+        Bd = anuga.Dirichlet_boundary([final_runup_height, 0, 0])# Steady inflow
+
+        # All reflective to begin with (still water)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        #--------------------------------------------------------------
+        # Test initial inundation height
+        #--------------------------------------------------------------
+
+        indices = domain.get_wet_elements()
+        z = domain.get_quantity('elevation').get_values(location='centroids',
+                                                        indices=indices)
+        assert num.alltrue(z < initial_runup_height)
+
+        q = domain.get_maximum_inundation_elevation()
+        # First order accuracy
+        assert num.allclose(q, initial_runup_height, rtol=1.0/N)
+
+        x, y = domain.get_maximum_inundation_location()
+
+        qref = domain.get_quantity('elevation').\
+                     get_values(interpolation_points=[[x, y]])
+        assert num.allclose(q, qref)
+
+        wet_elements = domain.get_wet_elements()
+        wet_elevations = domain.get_quantity('elevation').\
+                                    get_values(location='centroids',
+                                               indices=wet_elements)
+        assert num.alltrue(wet_elevations < initial_runup_height)
+        assert num.allclose(wet_elevations, z)
+
+        #--------------------------------------------------------------
+        # Let triangles adjust
+        #--------------------------------------------------------------
+        for t in domain.evolve(yieldstep = 0.1, finaltime = 1.0):
+            pass
+
+        #--------------------------------------------------------------
+        # Test inundation height again
+        #--------------------------------------------------------------
+        indices = domain.get_wet_elements()
+        z = domain.get_quantity('elevation').get_values(location='centroids',
+                                                        indices=indices)
+
+        assert num.alltrue(z < initial_runup_height)
+
+        q = domain.get_maximum_inundation_elevation()
+        # First order accuracy
+        assert num.allclose(q, initial_runup_height, rtol=1.0/N)
+
+        x, y = domain.get_maximum_inundation_location()
+        qref = domain.get_quantity('elevation').\
+                        get_values(interpolation_points=[[x, y]])
+        assert num.allclose(q, qref)
+
+        #--------------------------------------------------------------
+        # Update boundary to allow inflow
+        #--------------------------------------------------------------
+        domain.set_boundary({'right': Bd})
+
+        #--------------------------------------------------------------
+        # Evolve system through time
+        #--------------------------------------------------------------
+        for t in domain.evolve(yieldstep = 0.1, finaltime = 3.0):
+            pass
+
+        #--------------------------------------------------------------
+        # Test inundation height again
+        #--------------------------------------------------------------
+        indices = domain.get_wet_elements()
+        z = domain.get_quantity('elevation').\
+                    get_values(location='centroids', indices=indices)
+
+        assert num.alltrue(z < final_runup_height)
+
+        q = domain.get_maximum_inundation_elevation()
+        # First order accuracy
+        assert num.allclose(q, final_runup_height, rtol=1.0/N)
+
+        x, y = domain.get_maximum_inundation_location()
+        qref = domain.get_quantity('elevation').\
+                        get_values(interpolation_points=[[x, y]])
+        assert num.allclose(q, qref)
+
+        wet_elements = domain.get_wet_elements()
+        wet_elevations = domain.get_quantity('elevation').\
+                             get_values(location='centroids',
+                                        indices=wet_elements)
+        assert num.alltrue(wet_elevations < final_runup_height)
+        assert num.allclose(wet_elevations, z)
+
+    def test_get_maximum_inundation_from_sww(self):
+        """test_get_maximum_inundation_from_sww(self)
+
+        Test of get_maximum_inundation_elevation()
+        and get_maximum_inundation_location() from data_manager.py
+
+        This is based on test_get_maximum_inundation_3(self) but works with the
+        stored results instead of with the internal data structure.
+
+        This test uses the underlying get_maximum_inundation_data for tests
+        """
+
+        from anuga.abstract_2d_finite_volumes.mesh_factory \
+                import rectangular_cross
+        from anuga.shallow_water.sww_interrogate import \
+            get_maximum_inundation_elevation, get_maximum_inundation_location, \
+            get_maximum_inundation_data
+
+        initial_runup_height = -0.4
+        final_runup_height = -0.3
+
+        #--------------------------------------------------------------
+        # Setup computational domain
+        #--------------------------------------------------------------
+        N = 10
+        points, vertices, boundary = rectangular_cross(N, N)
+        domain = Domain(points, vertices, boundary)
+        domain.set_name('runup_test')
+        #domain.set_maximum_allowed_speed(1.0)
+
+        # FIXME: This works better with old limiters so far
+        #domain.tight_slope_limiters = 0
+
+        #--------------------------------------------------------------
+        # Setup initial conditions
+        #--------------------------------------------------------------
+        def topography(x, y):
+            return -x/2                             # linear bed slope
+
+        # Use function for elevation
+        domain.set_quantity('elevation', topography)
+        domain.set_quantity('friction', 0.)                # Zero friction
+        # Constant negative initial stage
+        domain.set_quantity('stage', initial_runup_height)
+
+        #--------------------------------------------------------------
+        # Setup boundary conditions
+        #--------------------------------------------------------------
+        Br = anuga.Reflective_boundary(domain)                 # Reflective wall
+        Bd = anuga.Dirichlet_boundary([final_runup_height, 0, 0])# Steady inflow
+
+        # All reflective to begin with (still water)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        #--------------------------------------------------------------
+        # Test initial inundation height
+        #--------------------------------------------------------------
+        indices = domain.get_wet_elements()
+        z = domain.get_quantity('elevation').\
+                get_values(location='centroids', indices=indices)
+        assert num.alltrue(z < initial_runup_height)
+
+        q_ref = domain.get_maximum_inundation_elevation()
+        # First order accuracy
+        assert num.allclose(q_ref, initial_runup_height, rtol=1.0/N)
+
+        #--------------------------------------------------------------
+        # Let triangles adjust
+        #--------------------------------------------------------------
+        for t in domain.evolve(yieldstep = 0.1, finaltime = 1.0):
+            pass
+
+        #--------------------------------------------------------------
+        # Test inundation height again
+        #--------------------------------------------------------------
+        q_ref = domain.get_maximum_inundation_elevation()
+        q = get_maximum_inundation_elevation('runup_test.sww')
+        msg = 'We got %f, should have been %f' % (q, q_ref)
+        assert num.allclose(q, q_ref, rtol=1.0/N), msg
+
+        q = get_maximum_inundation_elevation('runup_test.sww')
+        msg = 'We got %f, should have been %f' % (q, initial_runup_height)
+        assert num.allclose(q, initial_runup_height, rtol = 1.0/N), msg
+
+        # Test error condition if time interval is out
+        try:
+            q = get_maximum_inundation_elevation('runup_test.sww',
+                                                 time_interval=[2.0, 3.0])
+        except ValueError:
+            pass
+        else:
+            msg = 'should have caught wrong time interval'
+            raise Exception(msg)
+
+        # Check correct time interval
+        q, loc = get_maximum_inundation_data('runup_test.sww',
+                                             time_interval=[0.0, 3.0])
+        msg = 'We got %f, should have been %f' % (q, initial_runup_height)
+        assert num.allclose(q, initial_runup_height, rtol = 1.0/N), msg
+        assert num.allclose(-loc[0]/2, q)    # From topography formula
+
+        #--------------------------------------------------------------
+        # Update boundary to allow inflow
+        #--------------------------------------------------------------
+        domain.set_boundary({'right': Bd})
+
+        #--------------------------------------------------------------
+        # Evolve system through time
+        #--------------------------------------------------------------
+        q_max = None
+        for t in domain.evolve(yieldstep = 0.1, finaltime = 3.0,
+                               skip_initial_step = True):
+            q = domain.get_maximum_inundation_elevation()
+            if q > q_max:
+                q_max = q
+
+        #--------------------------------------------------------------
+        # Test inundation height again
+        #--------------------------------------------------------------
+        indices = domain.get_wet_elements()
+        z = domain.get_quantity('elevation').\
+                get_values(location='centroids', indices=indices)
+
+        assert num.alltrue(z < final_runup_height)
+
+        q = domain.get_maximum_inundation_elevation()
+        # First order accuracy
+        assert num.allclose(q, final_runup_height, rtol=1.0/N)
+
+        q, loc = get_maximum_inundation_data('runup_test.sww',
+                                             time_interval=[3.0, 3.0])
+        msg = 'We got %f, should have been %f' % (q, final_runup_height)
+        assert num.allclose(q, final_runup_height, rtol=1.0/N), msg
+        assert num.allclose(-loc[0]/2, q)    # From topography formula
+
+        q = get_maximum_inundation_elevation('runup_test.sww')
+        loc = get_maximum_inundation_location('runup_test.sww')
+        msg = 'We got %f, should have been %f' % (q, q_max)
+        assert num.allclose(q, q_max, rtol=1.0/N), msg
+        assert num.allclose(-loc[0]/2, q)    # From topography formula
+
+        q = get_maximum_inundation_elevation('runup_test.sww',
+                                             time_interval=[0, 3])
+        msg = 'We got %f, should have been %f' % (q, q_max)
+        assert num.allclose(q, q_max, rtol=1.0/N), msg
+
+        # Check polygon mode
+        # Runup region
+        polygon = [[0.3, 0.0], [0.9, 0.0], [0.9, 1.0], [0.3, 1.0]]
+        q = get_maximum_inundation_elevation('runup_test.sww',
+                                             polygon = polygon,
+                                             time_interval=[0, 3])
+        msg = 'We got %f, should have been %f' % (q, q_max)
+        assert num.allclose(q, q_max, rtol=1.0/N), msg
+
+        # Offshore region
+        polygon = [[0.9, 0.0], [1.0, 0.0], [1.0, 1.0], [0.9, 1.0]]
+        q, loc = get_maximum_inundation_data('runup_test.sww',
+                                             polygon = polygon,
+                                             time_interval=[0, 3])
+        msg = 'We got %f, should have been %f' % (q, -0.475)
+        assert num.allclose(q, -0.475, rtol=1.0/N), msg
+        assert is_inside_polygon(loc, polygon)
+        assert num.allclose(-loc[0]/2, q)    # From topography formula
+
+        # Dry region
+        polygon = [[0.0, 0.0], [0.2, 0.0], [0.2, 1.0], [0.0, 1.0]]
+        q, loc = get_maximum_inundation_data('runup_test.sww',
+                                             polygon = polygon,
+                                             time_interval=[0, 3])
+        msg = 'We got %s, should have been None' % (q)
+        assert q is None, msg
+        msg = 'We got %s, should have been None' % (loc)
+        assert loc is None, msg
+
+        # Check what happens if no time point is within interval
+        try:
+            q = get_maximum_inundation_elevation('runup_test.sww',
+                                                 time_interval=[2.75, 2.75])
+        except AssertionError:
+            pass
+        else:
+            msg = 'Time interval should have raised an exception'
+            raise Exception(msg)
+
+        # Cleanup
+        try:
+            os.remove(domain.get_name() + '.sww')
+        except:
+            pass
+            #FIXME(Ole): Windows won't allow removal of this
+
+
+
+
+
+    def test_another_runup_example(self):
+        """test_another_runup_example
+
+        Test runup example where actual timeseries at interpolated
+        points are tested.
+        """
+
+        #-----------------------------------------------------------------
+        # Setup computational domain
+        #-----------------------------------------------------------------
+        points, vertices, boundary = anuga.rectangular_cross(10, 10)# Basic mesh
+        domain = anuga.Domain(points, vertices, boundary) # Create domain
+        domain.set_default_order(2)
+        domain.set_quantities_to_be_stored(None)
+        domain.H0 = 1.0e-3
+
+        #-----------------------------------------------------------------
+        # Setup initial conditions
+        #-----------------------------------------------------------------
+        def topography(x, y):
+            return -x/2                              # linear bed slope
+
+        domain.set_quantity('elevation', topography)
+        domain.set_quantity('friction', 0.0)
+        domain.set_quantity('stage', expression='elevation')
+
+        #----------------------------------------------------------------
+        # Setup boundary conditions
+        #----------------------------------------------------------------
+        Br = anuga.Reflective_boundary(domain)           # Solid reflective wall
+        Bd = anuga.Dirichlet_boundary([-0.2, 0., 0.])    # Constant
+        domain.set_boundary({'left': Br, 'right': Bd, 'top': Br, 'bottom': Br})
+
+        #----------------------------------------------------------------
+        # Evolve system through time
+        #----------------------------------------------------------------
+        interpolation_points = [[0.4,0.5], [0.6,0.5], [0.8,0.5], [0.9,0.5]]
+        gauge_values = []
+        for _ in interpolation_points:
+            gauge_values.append([])
+
+        time = []
+        for t in domain.evolve(yieldstep=0.1, finaltime=5.0):
+            # Record time series at known points
+            time.append(domain.get_time())
+
+            stage = domain.get_quantity('stage')
+            w = stage.get_values(interpolation_points=interpolation_points)
+
+            for i, _ in enumerate(interpolation_points):
+                gauge_values[i].append(w[i])
+
+        #Reference (nautilus 26/6/2008)
+        
+        G0 = [-0.20000000000000001, -0.20000000000000001, -0.20000000000000001, -0.1958465301767274, -0.19059602372752493, -0.18448466250700923, -0.16979321333876071, -0.15976372740651074, -0.1575649333345176, -0.15710373731900584, -0.1530922283220747, -0.18836084336565725, -0.19921529311644628, -0.19923451799698919, -0.19923795414410964, -0.19923178806924047, -0.19925157557666154, -0.19930747801697429, -0.1993266428576112, -0.19932004930281799, -0.19929691326931867, -0.19926285267313795, -0.19916645449780995, -0.1988942593296438, -0.19900620256621993, -0.19914327423060865, -0.19918708440899577, -0.19921557252449132, -0.1992404368022069, -0.19925070370697717, -0.19925975477892274, -0.1992671090445659, -0.19927254203777162, -0.19927631910959256, -0.19927843552031504, -0.19927880339239365, -0.19927763204453783, -0.19927545249577633, -0.19927289590622824, -0.19927076261495152, -0.19926974334736983, -0.19927002562760332, -0.19927138236272213, -0.1992734501064522, -0.19927573251318192, -0.19927778936001547, -0.1992793776883893, -0.19928040577720926, -0.19928092586206753, -0.19928110982948721, -0.19928118887248453]
+
+        G1 = [-0.29999999999999993, -0.29999999999999993, -0.29139135018319512, -0.27257394456094503, -0.24141437432643265, -0.22089173942479151, -0.20796171092975532, -0.19874580192293825, -0.19014580508752857, -0.18421165368665365, -0.18020808282748838, -0.17518824759550247, -0.16436633464497749, -0.18714479115225544, -0.2045242886738807, -0.21011244240826329, -0.21151316017424124, -0.21048112933621732, -0.20772920477355789, -0.20489184334204144, -0.20286043930678221, -0.20094305756540246, -0.19948172752345467, -0.19886725178309209, -0.1986680808256765, -0.19860718133373548, -0.19862076543539733, -0.19888949069732539, -0.19932190310819023, -0.19982482967777454, -0.20036045468470615, -0.20064263130562704, -0.2007255389410077, -0.20068815669152493, -0.20057471332984647, -0.20042203940851802, -0.20026779013499779, -0.20015995671464712, -0.2000684005446525, -0.20001486753189174, -0.20000743467898013, -0.20003739771775905, -0.20008784600912621, -0.20013758305093884, -0.20017277554845025, -0.20018629233766885, -0.20018106288462198, -0.20016648079299326, -0.20015155958426531, -0.20014259747382254, -0.20014096648362509]
+        
+        
+        G2 = [-0.40000000000000002, -0.38885199453206343, -0.33425057028323962, -0.30154253721772117, -0.27624597383474103, -0.26037811196890087, -0.24415404585285019, -0.22941383121091052, -0.21613496492144549, -0.20418199946908885, -0.19506212965221825, -0.18851924999737435, -0.18271143344718843, -0.16910750701722474, -0.17963775224176018, -0.19442870510406052, -0.20164216917300118, -0.20467219452758528, -0.20608246104917802, -0.20640259931640445, -0.2054749739152594, -0.20380549124050265, -0.20227296931678532, -0.20095834856297176, -0.20000430919304379, -0.19946673053844086, -0.1990733499211611, -0.19882136174363013, -0.19877442300323914, -0.19905182154377868, -0.19943266521643804, -0.19988524183849191, -0.20018905307631765, -0.20031895675727809, -0.20033991149804931, -0.20031574232920274, -0.20027004750680638, -0.20020472427796293, -0.20013382447039607, -0.2000635018536408, -0.20001515436367642, -0.19998427691514989, -0.19997263083178107, -0.19998545383896535, -0.20000134502238734, -0.2000127243362736, -0.20001564474711939, -0.20001267360809977, -0.20002707579781318, -0.20004087961702843, -0.20004212947389177]
+        
+        G3 = [-0.45000000000000001, -0.38058172993544187, -0.33756059941741273, -0.31015371357441396, -0.29214769368562965, -0.27545447937118606, -0.25871585649808154, -0.24254276680581988, -0.22758633129006092, -0.21417276895743134, -0.20237184768790789, -0.19369491041576814, -0.18721625333717057, -0.1794243868465818, -0.17052113574042196, -0.18534300640363346, -0.19601184621026671, -0.20185028431829469, -0.20476187496918136, -0.20602933256960082, -0.20598569228739247, -0.20492643756666848, -0.20339695828762758, -0.20196440373022595, -0.20070304052919338, -0.19986227854052355, -0.19933020476408528, -0.19898034831018035, -0.19878317651286193, -0.19886879323961787, -0.19915860801206181, -0.19953675278099042, -0.19992828019602107, -0.20015957043092364, -0.20025268671087426, -0.20028559516444974, -0.20027084877341045, -0.20022991487243985, -0.20016234295579871, -0.20009131445092507, -0.20003149397006523, -0.19998473356473795, -0.19996011913447218, -0.19995647168667186, -0.19996526209120422, -0.19996600297827097, -0.19997268800221216, -0.19998682275066659, -0.20000372259781876, -0.20001628681983963, -0.2000173314086407]
+        
+        assert num.allclose(gauge_values[0], G0)
+        assert num.allclose(gauge_values[1], G1)
+        assert num.allclose(gauge_values[2], G2)
+        assert num.allclose(gauge_values[3], G3)
+
+    #####################################################
+
+
+    def test_initial_condition(self):
+        """test_initial_condition
+
+        Test that initial condition is output at time == 0 and that
+        computed values change as system evolves
+        """
+
+        from anuga.config import g
+        import copy
+
+        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 = anuga.Domain(points, vertices)
+
+        #Set up for a gradient of (3,0) at mid triangle (bce)
+        def slope(x, y):
+            return 3*x
+
+        h = 0.1
+        def stage(x, y):
+            return slope(x, y) + h
+
+        domain.set_quantity('elevation', slope)
+        domain.set_quantity('stage', stage)
+
+        # Allow slope limiters to work
+        # (FIXME (Ole): Shouldn't this be automatic in ANUGA?)
+        domain.distribute_to_vertices_and_edges()
+
+        initial_stage = copy.copy(domain.quantities['stage'].vertex_values)
+
+        domain.set_boundary({'exterior': anuga.Reflective_boundary(domain)})
+
+        domain.optimise_dry_cells = True
+
+        #Evolution
+        for t in domain.evolve(yieldstep=0.5, finaltime=2.0):
+            stage = domain.quantities['stage'].vertex_values
+
+            if t == 0.0:
+                assert num.allclose(stage, initial_stage)
+            else:
+                assert not num.allclose(stage, initial_stage)
+
+        os.remove(domain.get_name() + '.sww')
+
+    #####################################################
+
+    def test_second_order_flat_bed_onestep(self):
+
+        #Create basic mesh
+        points, vertices, boundary = anuga.rectangular(6, 6)
+
+        #Create shallow water domain
+        domain = anuga.Domain(points, vertices, boundary)
+        domain.set_default_order(2)
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain)
+        Bd = anuga.Dirichlet_boundary([0.1, 0., 0.])
+        domain.set_boundary({'left': Bd, 'right': Br, 'top': Br, 'bottom': Br})
+
+        domain.check_integrity()
+
+        # Evolution
+        for t in domain.evolve(yieldstep=0.05, finaltime=0.05):
+            pass
+
+
+        # Data from earlier version of abstract_2d_finite_volumes
+        assert num.allclose(domain.recorded_min_timestep, 0.0396825396825) or \
+               num.allclose(domain.recorded_min_timestep, 0.0235282801879)
+               
+        assert num.allclose(domain.recorded_max_timestep, 0.0396825396825) or \
+               num.allclose(domain.recorded_max_timestep, 0.0235282801879)
+
+
+                
+        assert num.allclose(domain.quantities['stage'].centroid_values[:12],
+                            [0.00171396, 0.02656103, 0.00241523, 0.02656103,
+                             0.00241523, 0.02656103, 0.00241523, 0.02656103,
+                             0.00241523, 0.02656103, 0.00241523, 0.0272623], atol=1.0e-3) or \
+               num.allclose(domain.quantities['stage'].centroid_values[:12],
+                            [ 0.00053119,  0.02900893,  0.00077912,  0.02900893,
+                              0.00077912,  0.02900893,  0.00077912,  0.02900893,
+                              0.00077912,  0.02900893,  0.00077912,  0.02873746], atol=1.0e-3)
+
+        domain.distribute_to_vertices_and_edges()
+
+ 
+
+        assert num.allclose(domain.quantities['stage'].vertex_values[:12,0],
+                            [ -1.96794125e-03,   2.65610347e-02,   0.00000000e+00,   2.65610347e-02,
+                              -8.67361738e-19,   2.65610347e-02,   4.33680869e-19,   2.65610347e-02,
+                              -2.16840434e-18,   2.65610347e-02,  -9.44042339e-05,   2.72623006e-02],
+                            atol =1.0e-3) or \
+                num.allclose(domain.quantities['stage'].vertex_values[:12,0],
+                            [ -5.51381419e-04,   5.74866732e-02,   1.00006808e-15,   5.72387383e-02,
+                              9.99851243e-16,   5.72387383e-02,   1.00050176e-15,   5.72387383e-02,
+                              9.99417563e-16,   5.72387383e-02,   1.09882029e-05,   5.66957956e-02],
+                             atol=1.0e-3)
+
+
+        assert num.allclose(domain.quantities['stage'].vertex_values[:12,1],
+                            [  5.14188587e-03,   2.65610347e-02,   0.00000000e+00,   2.65610347e-02,
+                               8.67361738e-19,   2.65610347e-02,  -4.33680869e-19,   2.65610347e-02,
+                               1.30104261e-18,   2.65610347e-02,   9.44042339e-05,   2.72623006e-02],
+                            atol =1.0e-3) or \
+               num.allclose(domain.quantities['stage'].vertex_values[:12,1],
+                           [  1.59356551e-03,   5.72387383e-02,   1.00006808e-15,   5.72387383e-02,
+                              1.00006808e-15,   5.72387383e-02,   9.99634403e-16,   5.72387383e-02,
+                              1.00050176e-15,   5.72387383e-02,  -1.09882029e-05,   1.47582915e-02],
+                            atol =1.0e-3)
+        
+        assert num.allclose(domain.quantities['stage'].vertex_values[:12,2],
+                            [ 0.00196794,  0.02656103,  0.00724568,  0.02656103,
+                              0.00724568,  0.02656103,  0.00724568,  0.02656103,
+                              0.00724568,  0.02656103,  0.00724568,  0.0272623 ], atol =1.0e-3) or \
+               num.allclose(domain.quantities['stage'].vertex_values[:12,2],
+                            [ 0.00055138, -0.02769862,  0.00233737, -0.02745068,
+                              0.00233737, -0.02745068,  0.00233737, -0.02745068,
+                              0.00233737, -0.02745068,  0.00233737,  0.01475829], atol =1.0e-3)
+
+
+        assert num.allclose(domain.quantities['xmomentum'].centroid_values[:12],
+                            [0.00113961, 0.01302432, 0.00148672,
+                             0.01302432, 0.00148672, 0.01302432,
+                             0.00148672, 0.01302432, 0.00148672 ,
+                             0.01302432, 0.00148672, 0.01337143], atol=1.0e-3) or \
+               num.allclose(domain.quantities['xmomentum'].centroid_values[:12],
+                        [ 0.00019529,  0.01425863,  0.00025665,
+                          0.01425863,  0.00025665,  0.01425863,
+                          0.00025665,  0.01425863,  0.00025665,
+                          0.01425863,  0.00025665,  0.014423  ], atol=1.0e-3)
+        
+        assert num.allclose(domain.quantities['ymomentum'].centroid_values[:12],
+                            [-2.91240050e-004 , 1.22721531e-004,
+                             -1.22721531e-004,  1.22721531e-004 ,
+                             -1.22721531e-004,  1.22721531e-004,
+                             -1.22721531e-004 , 1.22721531e-004,
+                             -1.22721531e-004,  1.22721531e-004,
+                             -1.22721531e-004,  -4.57969873e-005], atol=1.0e-5) or \
+               num.allclose(domain.quantities['ymomentum'].centroid_values[:12],
+                            [ -6.38239364e-05,   2.16943067e-05,
+                              -2.16943067e-05,   2.16943067e-05,
+                              -2.16943067e-05,   2.16943067e-05,
+                              -2.16943067e-05,   2.16943067e-05,
+                              -2.16943067e-05,   2.16943067e-05,
+                              -2.16943067e-05,  -4.62796434e-04], atol=1.0e-5)
+        
+        os.remove(domain.get_name() + '.sww')
+
+    def test_second_order_flat_bed_moresteps(self):
+        from mesh_factory import rectangular
+
+        # Create basic mesh
+        points, vertices, boundary = rectangular(6, 6)
+
+        # Create shallow water domain
+        domain = anuga.Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.default_order = 2
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain)
+        Bd = anuga.Dirichlet_boundary([0.1, 0., 0.])
+        domain.set_boundary({'left': Bd, 'right': Br, 'top': Br, 'bottom': Br})
+
+        domain.check_integrity()
+
+        # Evolution
+        for t in domain.evolve(yieldstep=0.05, finaltime=0.1):
+            pass
+
+        # Data from earlier version of abstract_2d_finite_volumes
+        #assert allclose(domain.recorded_min_timestep, 0.0396825396825)
+        #assert allclose(domain.recorded_max_timestep, 0.0396825396825)
+        #print domain.quantities['stage'].centroid_values
+
+        os.remove(domain.get_name() + '.sww')
+
+    def test_flatbed_first_order(self):
+        from mesh_factory import rectangular
+
+        # Create basic mesh
+        N = 8
+        points, vertices, boundary = rectangular(N, N)
+
+        # Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.default_order = 1
+        domain.H0 = 1.0e-3 # As suggested in the manual
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain)
+        Bd = anuga.Dirichlet_boundary([0.2, 0., 0.])
+
+        domain.set_boundary({'left': Bd, 'right': Br, 'top': Br, 'bottom': Br})
+        domain.check_integrity()
+
+        # Evolution
+        for t in domain.evolve(yieldstep=0.02, finaltime=0.5):
+            pass
+
+        # FIXME: These numbers were from version before 25/10
+        #assert allclose(domain.recorded_min_timestep, 0.0140413643926)
+        #assert allclose(domain.recorded_max_timestep, 0.0140947355753)
+
+        for i in range(3):
+            #assert allclose(domain.quantities['stage'].edge_values[:4,i],
+            #                [0.10730244,0.12337617,0.11200126,0.12605666])
+            assert num.allclose(domain.quantities['xmomentum'].\
+                                    edge_values[:4,i],
+                                [0.07610894,0.06901572,0.07284461,0.06819712])
+            #assert allclose(domain.quantities['ymomentum'].edge_values[:4,i],
+            #                [-0.0060238, -0.00157404, -0.00309633, -0.0001637])
+
+        os.remove(domain.get_name() + '.sww')
+
+    def test_flatbed_second_order(self):
+        from mesh_factory import rectangular
+
+        # Create basic mesh
+        N = 8
+        points, vertices, boundary = rectangular(N, N)
+
+        # Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.set_store_vertices_uniquely(True)
+        domain.set_default_order(2)
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain)
+        Bd = anuga.Dirichlet_boundary([0.2, 0., 0.])
+
+        domain.set_boundary({'left': Bd, 'right': Br, 'top': Br, 'bottom': Br})
+        domain.check_integrity()
+
+        # Evolution
+        for t in domain.evolve(yieldstep=0.01, finaltime=0.03):
+            pass
+
+
+        
+        msg = 'min step was %f instead of %f' % (domain.recorded_min_timestep,
+                                                 0.0155604907816)
+
+        assert num.allclose(domain.recorded_min_timestep, 0.0155604907816), msg
+        assert num.allclose(domain.recorded_max_timestep, 0.0155604907816)
+
+
+        assert num.allclose(domain.quantities['stage'].vertex_values[:4,0],
+                            [-0.009, 0.0535,  0.0, 0.0535], atol=1.0e-3) or \
+               num.allclose(domain.quantities['stage'].vertex_values[:4,0],
+                      [-3.54158995e-03,1.22050959e-01,-2.36227400e-05,1.21501627e-01], atol=1.0e-3)
+        
+        
+        assert num.allclose(domain.quantities['xmomentum'].vertex_values[:4,0],
+                            [-0.008, 0.0368, 0.0, 0.0368], atol=1.0e-3) or \
+               num.allclose(domain.quantities['xmomentum'].vertex_values[:4,0],
+                      [-2.32056226e-03,9.10618822e-02, -1.06135035e-05,9.75175956e-02], atol=1.0e-3)
+
+        assert num.allclose(domain.quantities['ymomentum'].vertex_values[:4,0],
+                            [ 0.002 , 6.0e-04, 0.0, 6.0e-04],
+                            atol=1.0e-3) or \
+               num.allclose(domain.quantities['ymomentum'].vertex_values[:4,0],
+                            [ 1.43500775e-03,  6.07102924e-05,   1.59329371e-06,   8.44572599e-03],
+                            atol=1.0e-3)
+
+        os.remove(domain.get_name() + '.sww')
+
+
+    def test_flatbed_second_order_vmax_0(self):
+        from mesh_factory import rectangular
+
+        # Create basic mesh
+        N = 8
+        points, vertices, boundary = rectangular(N, N)
+
+        # Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+
+        domain.set_store_vertices_uniquely(True)
+        domain.set_default_order(2)
+
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain)
+        Bd = anuga.Dirichlet_boundary([0.2, 0., 0.])
+
+        domain.set_boundary({'left': Bd, 'right': Br, 'top': Br, 'bottom': Br})
+        domain.check_integrity()
+
+        # Evolution
+        for t in domain.evolve(yieldstep=0.01, finaltime=0.03):
+            pass
+
+
+        assert num.allclose(domain.recorded_min_timestep, 0.0210448446782) or \
+               num.allclose(domain.recorded_min_timestep, 0.0155604907816)
+               
+        assert num.allclose(domain.recorded_max_timestep, 0.0210448446782) or \
+               num.allclose(domain.recorded_min_timestep, 0.0155604907816)
+
+
+        assert num.allclose(domain.quantities['xmomentum'].vertex_values[:4,0],
+                            [ -2.32056226e-03,   9.10618822e-02,  -1.06135035e-05,   9.75175956e-02],
+                            atol=1.0e-3)
+
+        assert num.allclose(domain.quantities['ymomentum'].vertex_values[:4,0],
+                            [  1.43500775e-03,   6.07102924e-05,   1.59329371e-06,   8.44572599e-03],
+                            atol=1.0e-3)
+
+        os.remove(domain.get_name() + '.sww')
+
+    def test_flatbed_second_order_distribute(self):
+        #Use real data from anuga.abstract_2d_finite_volumes 2
+        #painfully setup and extracted.
+
+        from mesh_factory import rectangular
+
+        # Create basic mesh
+        N = 8
+        points, vertices, boundary = rectangular(N, N)
+
+        # Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+
+        domain.set_store_vertices_uniquely(True)
+        domain.set_default_order(2)
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain)
+        Bd = anuga.Dirichlet_boundary([0.2, 0., 0.])
+
+        domain.set_boundary({'left': Bd, 'right': Br, 'top': Br, 'bottom': Br})
+        domain.check_integrity()
+
+        for V in [False, True]:
+            if V:
+                # Set centroids as if system had been evolved
+                L = num.zeros(2*N*N, num.float)
+                L[:32] = [7.21205592e-003, 5.35214298e-002, 1.00910824e-002,
+                          5.35439433e-002, 1.00910824e-002, 5.35439433e-002,
+                          1.00910824e-002, 5.35439433e-002, 1.00910824e-002,
+                          5.35439433e-002, 1.00910824e-002, 5.35439433e-002,
+                          1.00910824e-002, 5.35393928e-002, 1.02344264e-002,
+                          5.59605058e-002, 0.00000000e+000, 3.31027800e-004,
+                          0.00000000e+000, 4.37962142e-005, 0.00000000e+000,
+                          4.37962142e-005, 0.00000000e+000, 4.37962142e-005,
+                          0.00000000e+000, 4.37962142e-005, 0.00000000e+000,
+                          4.37962142e-005, 0.00000000e+000, 4.37962142e-005,
+                          0.00000000e+000, 5.57305948e-005]
+
+                X = num.zeros(2*N*N, num.float)
+                X[:32] = [6.48351607e-003, 3.68571894e-002, 8.50733285e-003,
+                          3.68731327e-002, 8.50733285e-003, 3.68731327e-002,
+                          8.50733285e-003, 3.68731327e-002, 8.50733285e-003,
+                          3.68731327e-002, 8.50733285e-003, 3.68731327e-002,
+                          8.50733285e-003, 3.68693861e-002, 8.65220973e-003,
+                          3.85055387e-002, 0.00000000e+000, 2.86060840e-004,
+                          0.00000000e+000, 3.58905503e-005, 0.00000000e+000,
+                          3.58905503e-005, 0.00000000e+000, 3.58905503e-005,
+                          0.00000000e+000, 3.58905503e-005, 0.00000000e+000,
+                          3.58905503e-005, 0.00000000e+000, 3.58905503e-005,
+                          0.00000000e+000, 4.57662812e-005]
+
+                Y = num.zeros(2*N*N, num.float)
+                Y[:32] = [-1.39463104e-003, 6.15600298e-004, -6.03637382e-004,
+                          6.18272251e-004, -6.03637382e-004, 6.18272251e-004,
+                          -6.03637382e-004, 6.18272251e-004, -6.03637382e-004,
+                          6.18272251e-004, -6.03637382e-004, 6.18272251e-004,
+                          -6.03637382e-004, 6.18599320e-004, -6.74622797e-004,
+                          -1.48934756e-004, 0.00000000e+000, -5.35079969e-005,
+                          0.00000000e+000, -2.57264987e-005, 0.00000000e+000,
+                          -2.57264987e-005, 0.00000000e+000, -2.57264987e-005,
+                          0.00000000e+000, -2.57264987e-005, 0.00000000e+000,
+                          -2.57264987e-005, 0.00000000e+000, -2.57264987e-005,
+                          0.00000000e+000, -2.57635178e-005]
+
+                domain.set_quantity('stage', L, location='centroids')
+                domain.set_quantity('xmomentum', X, location='centroids')
+                domain.set_quantity('ymomentum', Y, location='centroids')
+
+                domain.check_integrity()
+            else:
+                # Evolution
+                for t in domain.evolve(yieldstep=0.01, finaltime=0.03):
+                    pass
+
+                
+                assert num.allclose(domain.recorded_min_timestep, 0.0155604907816)
+                assert num.allclose(domain.recorded_max_timestep, 0.0155604907816)
+
+            #print domain.quantities['stage'].centroid_values[:4]
+            #print domain.quantities['xmomentum'].centroid_values[:4]
+            #print domain.quantities['ymomentum'].centroid_values[:4]                        
+                
+            #Centroids were correct but not vertices.
+            #Hence the check of distribute below.
+
+            if not V:
+
+                assert num.allclose(domain.quantities['stage'].centroid_values[:4],
+                               [0.00725574, 0.05350737, 0.01008413, 0.0535293], atol=1.0e-3) or \
+                       num.allclose(domain.quantities['stage'].centroid_values[:4],
+                               [0.00318259,  0.06261678,  0.00420215,  0.06285189], atol=1.0e-3)
+                
+                assert num.allclose(domain.quantities['xmomentum'].centroid_values[:4],
+                               [0.00654964, 0.03684904, 0.00852561, 0.03686323],atol=1.0e-3) or \
+                       num.allclose(domain.quantities['xmomentum'].centroid_values[:4],
+                               [0.00218173, 0.04482164, 0.0026334,  0.04491656],atol=1.0e-3)       
+
+                assert num.allclose(domain.quantities['ymomentum'].centroid_values[:4],
+                               [-0.00143169, 0.00061027, -0.00062325, 0.00061408],atol=1.0e-3) or \
+                       num.allclose(domain.quantities['ymomentum'].centroid_values[:4],
+                [-6.46340592e-04,-6.16702557e-05,-2.83424134e-04, 6.48556590e-05],atol=1.0e-3)
+
+                                    
+                assert num.allclose(domain.quantities['xmomentum'].centroid_values[17], 0.0,
+                                    atol=3.0e-4)                
+            else:
+                assert num.allclose(domain.quantities['xmomentum'].\
+                                        centroid_values[17],
+                                    0.00028606084)
+                return #FIXME - Bailout for V True
+
+            import copy
+
+            XX = copy.copy(domain.quantities['xmomentum'].centroid_values)
+            assert num.allclose(domain.quantities['xmomentum'].centroid_values,
+                                XX)
+
+            domain.distribute_to_vertices_and_edges()
+
+            assert num.allclose(domain.quantities['xmomentum'].centroid_values[17], 0.0, atol=3.0e-4)
+
+            assert num.allclose(domain.quantities['ymomentum'].vertex_values[:4,0],
+                                [ 1.84104149e-03, 6.05658846e-04, 1.77092716e-07, 6.10687334e-04],
+                                atol=1.0e-4) or \
+                   num.allclose(domain.quantities['ymomentum'].vertex_values[:4,0],
+                                [1.43500775e-03, 6.07102924e-05, 1.59329371e-06, 8.44572599e-03],
+                                atol=1.0e-4)             
+
+            assert num.allclose(domain.quantities['xmomentum'].vertex_values[:4,0],
+                                [ -8.31184293e-03, 3.68841505e-02, -2.42843889e-06, 3.68900189e-02],
+                                atol=1.0e-4) or \
+                   num.allclose(domain.quantities['xmomentum'].vertex_values[:4,0],
+                                [-2.32056226e-03, 9.10618822e-02, -1.06135035e-05, 9.75175956e-02],
+                                rtol=1.0e-2)             
+
+
+        os.remove(domain.get_name() + '.sww')
+
+
+    def test_bedslope_problem_second_order_more_steps(self):
+        """test_bedslope_problem_second_order_more_step
+
+        Test shallow water balanced finite volumes
+        """
+
+        from mesh_factory import rectangular
+
+        # Create basic mesh
+        points, vertices, boundary = rectangular(6, 6)
+
+        # Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+
+        domain.set_store_vertices_uniquely(True)
+        domain.set_default_order(2)
+
+        # Bed-slope and friction at vertices (and interpolated elsewhere)
+        def x_slope(x, y):
+            return -x/3
+
+        domain.set_quantity('elevation', x_slope)
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        # Initial condition
+        domain.set_quantity('stage', expression='elevation+0.05')
+        domain.check_integrity()
+
+        assert num.allclose(domain.quantities['stage'].centroid_values,
+                            [ 0.01296296,  0.03148148,  0.01296296,
+                              0.03148148,  0.01296296,  0.03148148,
+                              0.01296296,  0.03148148,  0.01296296,
+                              0.03148148,  0.01296296,  0.03148148,
+                             -0.04259259, -0.02407407, -0.04259259,
+                             -0.02407407, -0.04259259, -0.02407407,
+                             -0.04259259, -0.02407407, -0.04259259,
+                             -0.02407407, -0.04259259, -0.02407407,
+                             -0.09814815, -0.07962963, -0.09814815,
+                             -0.07962963, -0.09814815, -0.07962963,
+                             -0.09814815, -0.07962963, -0.09814815,
+                             -0.07962963, -0.09814815, -0.07962963,
+                             -0.1537037 , -0.13518519, -0.1537037,
+                             -0.13518519, -0.1537037,  -0.13518519,
+                             -0.1537037 , -0.13518519, -0.1537037,
+                             -0.13518519, -0.1537037,  -0.13518519,
+                             -0.20925926, -0.19074074, -0.20925926,
+                             -0.19074074, -0.20925926, -0.19074074,
+                             -0.20925926, -0.19074074, -0.20925926,
+                             -0.19074074, -0.20925926, -0.19074074,
+                             -0.26481481, -0.2462963,  -0.26481481,
+                             -0.2462963,  -0.26481481, -0.2462963,
+                             -0.26481481, -0.2462963,  -0.26481481,
+                             -0.2462963,  -0.26481481, -0.2462963])
+
+        # Evolution
+        for t in domain.evolve(yieldstep = 0.05, finaltime = 0.5):
+            pass
+
+
+        assert num.allclose(domain.quantities['stage'].centroid_values,
+     [-0.02901283, -0.01619385, -0.03040423, -0.01564474, -0.02936756, -0.01507953,
+      -0.02858108, -0.01491531, -0.02793549, -0.0147037,  -0.02792804, -0.014363,
+      -0.07794301, -0.05951952, -0.07675098, -0.06182336, -0.07736607, -0.06079504,
+      -0.07696764, -0.06039043, -0.07708793, -0.0601453,  -0.07669911, -0.06020719,
+      -0.12223185, -0.10857309, -0.12286676, -0.10837591, -0.12386938, -0.10842744,
+      -0.12363769, -0.10790002, -0.12304837, -0.10871278, -0.12543768, -0.10961026,
+      -0.15664473, -0.14630207, -0.15838364, -0.14910271, -0.15804002, -0.15029627,
+      -0.15829717, -0.1503869,  -0.15852604, -0.14971109, -0.15856346, -0.15205092,
+      -0.20900931, -0.19658843, -0.20669607, -0.19558708, -0.20654186, -0.19492423,
+      -0.20438765, -0.19492931, -0.20644142, -0.19423147, -0.20237449, -0.19198454,
+      -0.13699658, -0.14209126, -0.13600697, -0.14334968, -0.1347657,  -0.14224247,
+      -0.13442376, -0.14136926, -0.13501004, -0.14339389, -0.13479263, -0.14304073], atol=1.0e-2) or \
+              num.allclose(domain.quantities['stage'].centroid_values,      
+     [-0.03393968, -0.0166423,  -0.03253538, -0.01722023, -0.03270405, -0.01728606,
+      -0.03277786, -0.0173903,  -0.03333736, -0.01743236, -0.03189526, -0.01463918,
+      -0.07951756, -0.06410763, -0.07847973, -0.06350794, -0.07842429, -0.06240852,
+      -0.07808697, -0.06255924, -0.07854662, -0.06322442, -0.07867314, -0.06287121,
+      -0.11533356, -0.10559238, -0.11971301, -0.10742123, -0.1215759 , -0.10830046,
+      -0.12202867, -0.10831703, -0.122214,   -0.10854099, -0.12343779, -0.11035803,
+      -0.15725714, -0.14300757, -0.15559898, -0.1447275 , -0.15478568, -0.14483551,
+      -0.15461918, -0.14489704, -0.15462074, -0.14516256, -0.15522298, -0.1452902,
+      -0.22637615, -0.19192974, -0.20922654, -0.1907441 , -0.20900039, -0.19074809,
+      -0.20897969, -0.19073365, -0.209195,   -0.19071396, -0.20922513, -0.19067714,
+      -0.11357515, -0.14185801, -0.13224763, -0.14395805, -0.13379438, -0.14497114,
+      -0.13437773, -0.14536013, -0.13607796, -0.14799629, -0.13148351, -0.15568502], atol=1.0e-1)
+
+
+
+        assert num.allclose(domain.quantities['xmomentum'].centroid_values,
+               [ 0.00478273,  0.003297,    0.00471129,  0.00320957,  0.00462171,  0.00320135,
+                 0.00458295,  0.00317193,  0.00451704,  0.00314308,  0.00442684,  0.00320466,
+                 0.01512907,  0.01150756,  0.01604672,  0.01156605,  0.01583911,  0.01135809,
+                 0.01578499,  0.01132479,  0.01543668,  0.01100614,  0.01570445,  0.0120152,
+                 0.04019477,  0.02721469,  0.03509982,  0.02735229,  0.03369315,  0.02727871,
+                 0.03317931,  0.02706421,  0.03332704,  0.02722779,  0.03170258,  0.02556134,
+                 0.07157025,  0.06074271,  0.07249738,  0.05570979,  0.07311261,  0.05428175,
+                 0.07316986,  0.05379702,  0.0719581,   0.05230996,  0.07034837,  0.05468702,
+                 0.08145001,  0.07753479,  0.08148804,  0.08119069,  0.08247295,  0.08134969,
+                 0.0823216,   0.081411,    0.08190964,  0.08151441,  0.08163076,  0.08166174,
+                 0.03680205,  0.0768216,   0.03943625,  0.07791183,  0.03930529,  0.07760588,
+                 0.03949756,  0.07839929,  0.03992892,  0.08001416,  0.04444335,  0.08628738],
+                            atol=1.0e-2) or \
+               num.allclose(domain.quantities['xmomentum'].centroid_values,
+               [ 0.00178414,  0.00147791,  0.00373636,  0.00169124,  0.00395649,  0.0014468,
+                 0.00387617,  0.00135572,  0.00338418,  0.00134554,  0.00404961,  0.00252769,
+                 0.01365204,  0.00890416,  0.01381613,  0.00986246,  0.01419385,  0.01145017,
+                 0.01465116,  0.01125933,  0.01407359,  0.01055426,  0.01403563,  0.01095544,
+                 0.04653827,  0.03018236,  0.03709973,  0.0265533 ,  0.0337694 ,  0.02541724,
+                 0.03304266,  0.02535335,  0.03264548,  0.02484769,  0.03047682,  0.02205757,
+                 0.07400338,  0.06470583,  0.07756503,  0.06098108,  0.07942593,  0.06086531,
+                 0.07977427,  0.06074404,  0.07979513,  0.06019911,  0.07806395,  0.06011152,
+                 0.07305045,  0.07883894,  0.08120393,  0.08166623,  0.08180501,  0.08166251,
+                 0.0818353 ,  0.08169641,  0.08173762,  0.08174118,  0.08176467,  0.08181817,
+                 0.01549926,  0.08259719,  0.01835423,  0.07302656,  0.01672924,  0.07198839,
+                 0.01676006,  0.07223233,  0.01775672,  0.07362164,  0.01955846,  0.09361223],
+                            atol=1.0e-2)
+
+
+        assert num.allclose(domain.quantities['ymomentum'].centroid_values,
+                            [ -1.09771684e-05,  -2.60328801e-05,  -1.03481959e-05,  -7.75907380e-05,
+                              -5.00409090e-05,  -7.83807512e-05,  -3.60509918e-05,  -6.19321031e-05,
+                              -1.40041903e-05,  -2.95707259e-05,   3.90296618e-06,   1.87556544e-05,
+                              9.27848053e-05,   6.66937557e-07,   1.00653468e-04,   8.24734209e-06,
+                              -1.04548672e-05,  -4.40402988e-05,  -2.95549946e-05,  -1.86360736e-05,
+                              1.12527016e-04,   1.27240681e-04,   2.02147284e-04,   9.18457482e-05,
+                              1.41781748e-03,   7.23407624e-04,   5.09160779e-04,   1.29136939e-04,
+                              -4.70131286e-05,  -1.00180290e-04,  -1.76806614e-05,  -4.19421384e-06,
+                              -6.17759681e-05,  -3.02124967e-05,   4.32689360e-04,   5.49717934e-04,
+                              1.15031101e-03,   1.02737170e-03,   5.77937840e-04,   3.36230967e-04,
+                              5.44877516e-04,  -7.28594977e-05,   4.60064858e-04,  -3.94125434e-05,
+                              7.48242964e-04,   2.88528341e-04,   6.25148041e-05,  -1.74477175e-04,
+                              -5.06603166e-05,   7.07720999e-04,  -2.04937748e-04,   3.38595573e-05,
+                              -4.64116229e-05,   1.49325340e-04,  -2.41342281e-05,   1.83817970e-04,
+                              -1.44417277e-05,   2.47823834e-04,   7.91185571e-05,   1.71615793e-04,
+                              1.56883043e-03,   8.39352974e-04,   3.23353846e-03,   1.70597880e-03,
+                              2.27789107e-03,   1.48928169e-03,   2.09854126e-03,   1.50248643e-03,
+                              2.83029467e-03,   1.09151499e-03,   6.52455118e-03,  -2.04468968e-03],
+                            atol=1.0e-3) or \
+               num.allclose(domain.quantities['ymomentum'].centroid_values,
+                             [ -1.24810991e-04,  -3.08228767e-04,  -1.56701128e-04,  -1.01904208e-04,
+                               -3.36282053e-05,  -1.17956840e-04,  -3.55986664e-05,  -9.38578996e-05,
+                               7.13704069e-05,   2.47022380e-05,   1.71121489e-04,   2.65941677e-04,
+                               6.90055205e-04,   1.99195585e-04,   1.33804448e-04,  -1.66563316e-04,
+                               -2.00962830e-04,  -3.81664130e-05,  -9.50456053e-05,  -3.14620186e-06,
+                               1.29388102e-04,   3.16945980e-04,   4.77556581e-04,   2.57217342e-04,
+                               1.42300612e-03,   9.60776359e-04,   5.08941026e-04,   1.06939990e-04,
+                               6.37673950e-05,  -2.69783047e-04,  -8.55760509e-05,  -2.12987309e-04,
+                               -5.86840949e-06,  -9.75751293e-05,   8.25447727e-04,   1.14139065e-03,
+                               8.56206468e-04,   3.83113329e-04,   1.75041847e-04,   4.39999200e-04,
+                               3.75156469e-04,   2.48774698e-04,   4.09671654e-04,   2.07125615e-04,
+                               4.59587647e-04,   2.70581830e-04,  -1.24082302e-06,  -4.29155678e-04,
+                               -9.66841218e-03,   4.93278794e-04,  -5.25778806e-06,  -4.90396857e-05,
+                               -9.75373988e-06,   7.28023591e-06,  -5.20499868e-06,   3.61013683e-05,
+                               -7.54919544e-06,   4.14115771e-05,  -1.35778834e-05,  -2.23991903e-05,
+                               3.63635844e-02,   5.29865244e-04,   5.13015379e-03,   1.19233296e-03,
+                               4.70681275e-04,   2.62292296e-04,  -1.28084045e-04,   7.04826916e-04,
+                               1.50377987e-04,   1.35053814e-03,   1.30710492e-02,   1.93011958e-03],
+                            atol=1.0e-1)
+                            
+
+
+        os.remove(domain.get_name() + '.sww')
+
+
+    def test_temp_play(self):
+        from mesh_factory import rectangular
+
+        # Create basic mesh
+        points, vertices, boundary = rectangular(5, 5)
+
+        # Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+
+        domain.set_store_vertices_uniquely(True)
+        domain.set_default_order(2)
+
+
+
+        # Bed-slope and friction at vertices (and interpolated elsewhere)
+        def x_slope(x, y):
+            return -x/3
+
+        domain.set_quantity('elevation', x_slope)
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        # Initial condition
+        domain.set_quantity('stage', expression='elevation+0.05')
+        domain.check_integrity()
+
+        # Evolution
+        for t in domain.evolve(yieldstep=0.05, finaltime=0.1):
+            pass
+
+
+        assert num.allclose(domain.quantities['stage'].centroid_values[:4],
+                            [ 0.01,   0.015,  0.01,  0.015], atol=1.0e-2)
+                            
+        assert num.allclose(domain.quantities['xmomentum'].centroid_values[:4],
+                            [ 0.015,  0.01,  0.015,  0.01], atol=1.0e-2)
+        
+        assert num.allclose(domain.quantities['ymomentum'].centroid_values[:4],
+                            [  0.0,  0.0,  0.0,   0.0]
+                            , atol=1.0e-3)
+
+        os.remove(domain.get_name() + '.sww')
+
+    def test_complex_bed(self):
+        # No friction is tested here
+
+        from mesh_factory import rectangular
+
+        N = 12
+        points, vertices, boundary = rectangular(N, N/2, len1=1.2, len2=0.6,
+                                                 origin=(-0.07, 0))
+
+
+        domain = Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.set_default_order(2)
+        domain.set_timestepping_method('rk2')
+        domain.set_beta(1.0)
+
+        inflow_stage = 0.1
+        Z = Weir(inflow_stage)
+        domain.set_quantity('elevation', Z)
+
+        Br = anuga.Reflective_boundary(domain)
+        Bd = anuga.Dirichlet_boundary([inflow_stage, 0.0, 0.0])
+        domain.set_boundary({'left': Bd, 'right': Br, 'bottom': Br, 'top': Br})
+
+        domain.set_quantity('stage', expression='elevation')
+
+        for t in domain.evolve(yieldstep=0.02, finaltime=0.2):
+            pass
+
+        #FIXME: These numbers were from version before 25/10
+        #assert allclose(domain.quantities['stage'].centroid_values,
+# [3.95822638e-002,  5.61022588e-002,  4.66437868e-002,  5.73081011e-002,
+#  4.72394613e-002,  5.74684939e-002,  4.74309483e-002,  5.77458084e-002,
+#  4.80628177e-002,  5.85656225e-002,  4.90498542e-002,  6.02609831e-002,
+#  1.18470315e-002,  1.75136443e-002,  1.18035266e-002,  2.15565695e-002,
+#  1.31620268e-002,  2.14351640e-002,  1.32351076e-002,  2.15450687e-002,
+#  1.36414028e-002,  2.24274619e-002,  1.51689511e-002,  2.21789655e-002,
+# -7.54337535e-003, -6.86362021e-004, -7.74146760e-003, -1.83756530e-003,
+# -8.16773628e-003, -4.49916813e-004, -8.08202599e-003, -3.91118720e-004,
+# -8.10292716e-003, -3.88584984e-004, -7.35226124e-003,  2.73985295e-004,
+#  1.86166683e-001,  8.74070369e-002,  1.86166712e-001,  8.74035875e-002,
+#  6.11666935e-002, -3.76173225e-002, -6.38333276e-002, -3.76147365e-002,
+#  6.11666725e-002,  8.73846774e-002,  1.86166697e-001,  8.74171550e-002,
+# -4.83333333e-002,  1.18333333e-001, -4.83333333e-002,  1.18333333e-001,
+# -4.83333333e-002, -6.66666667e-003, -1.73333333e-001, -1.31666667e-001,
+# -1.73333333e-001, -6.66666667e-003, -4.83333333e-002,  1.18333333e-001,
+# -2.48333333e-001, -2.31666667e-001, -2.48333333e-001, -2.31666667e-001,
+# -2.48333333e-001, -2.31666667e-001, -2.48333333e-001, -2.31666667e-001,
+# -2.48333333e-001, -2.31666667e-001, -2.48333333e-001, -2.31666667e-001,
+# -4.65000000e-001, -3.65000000e-001, -4.65000000e-001, -3.65000000e-001,
+# -4.65000000e-001, -3.65000000e-001, -4.65000000e-001, -3.65000000e-001,
+# -4.65000000e-001, -3.65000000e-001, -4.65000000e-001, -3.65000000e-001,
+# -5.98333333e-001, -5.81666667e-001, -5.98333333e-001, -5.81666667e-001,
+# -5.98333333e-001, -5.81666667e-001, -5.98333333e-001, -5.81666667e-001,
+# -5.98333333e-001, -5.81666667e-001, -5.98333333e-001, -5.81666667e-001,
+# -6.48333333e-001, -6.31666667e-001, -6.48333333e-001, -6.31666667e-001,
+# -6.48333333e-001, -6.31666667e-001, -6.48333333e-001, -6.31666667e-001,
+# -6.48333333e-001, -6.31666667e-001, -6.48333333e-001, -6.31666667e-001,
+# -5.31666667e-001, -5.98333333e-001, -5.31666667e-001, -5.98333333e-001,
+# -5.31666667e-001, -5.98333333e-001, -5.31666667e-001, -5.98333333e-001,
+# -5.31666667e-001, -5.98333333e-001, -5.31666667e-001, -5.98333333e-001,
+# -4.98333333e-001, -4.81666667e-001, -4.98333333e-001, -4.81666667e-001,
+# -4.98333333e-001, -4.81666667e-001, -4.98333333e-001, -4.81666667e-001,
+# -4.98333333e-001, -4.81666667e-001, -4.98333333e-001, -4.81666667e-001,
+# -5.48333333e-001, -5.31666667e-001, -5.48333333e-001, -5.31666667e-001,
+# -5.48333333e-001, -5.31666667e-001, -5.48333333e-001, -5.31666667e-001,
+# -5.48333333e-001, -5.31666667e-001, -5.48333333e-001, -5.31666667e-001])
+
+        os.remove(domain.get_name() + '.sww')
+
+
+    def test_tight_slope_limiters(self):
+        """Test that new slope limiters (Feb 2007) don't induce extremely
+        small timesteps. This test actually reveals the problem as it
+        was in March-April 2007
+        """
+        import time, os
+        from Scientific.IO.NetCDF import NetCDFFile
+        from mesh_factory import rectangular_cross
+
+        # Create basic mesh
+        points, vertices, boundary = rectangular_cross(2, 2)
+
+        # Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.set_default_order(2)
+        domain.set_beta(1.0)
+        domain.set_timestepping_method('euler')
+        #domain.set_CFL(0.5)
+        
+
+        # This will pass
+        #domain.tight_slope_limiters = 1
+        #domain.H0 = 0.01
+
+        # This will fail
+        #domain.tight_slope_limiters = 1
+        #domain.H0 = 0.001
+
+        # This will pass provided C extension implements limiting of
+        # momentum in _compute_speeds
+        #domain.tight_slope_limiters = 1
+        #domain.H0 = 0.001
+        #domain.protect_against_isolated_degenerate_timesteps = True
+
+        # Set some field values
+        domain.set_quantity('elevation', lambda x,y: -x)
+        domain.set_quantity('friction', 0.03)
+
+        # Boundary conditions
+        B = anuga.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 = num.zeros(bed.shape, num.float)
+
+        h = 0.3
+        for i in range(stage.shape[0]):
+            if i % 2 == 1:
+                stage[i,:] = bed[i,:] + h
+            else:
+                stage[i,:] = bed[i,:]
+
+        domain.set_quantity('stage', stage)
+
+        domain.distribute_to_vertices_and_edges()
+
+        domain.set_name('tight_limiters')
+        domain.smooth = True
+        domain.reduction = mean
+        domain.set_datadir('.')
+        domain.smooth = False
+        domain.store = True
+
+        # Evolution
+        for t in domain.evolve(yieldstep=0.1, finaltime=0.3):
+            #domain.write_time(track_speeds=True)
+            stage = domain.quantities['stage'].vertex_values
+
+            # Get NetCDF
+            #fid = NetCDFFile(domain.writer.filename, netcdf_mode_r)
+            #stage_file = fid.variables['stage']
+
+            #fid.close()
+
+        os.remove(domain.writer.filename)
+
+
+
+    def test_pmesh2Domain(self):
+         import os
+         import tempfile
+
+         fileName = tempfile.mktemp(".tsh")
+         file = open(fileName, "w")
+         file.write("4 3 # <vertex #> <x> <y> [attributes]\n \
+0 0.0 0.0 0.0 0.0 0.01 \n \
+1 1.0 0.0 10.0 10.0 0.02  \n \
+2 0.0 1.0 0.0 10.0 0.03  \n \
+3 0.5 0.25 8.0 12.0 0.04  \n \
+# Vert att title  \n \
+elevation  \n \
+stage  \n \
+friction  \n \
+2 # <triangle #> [<vertex #>] [<neigbouring triangle #>]  \n\
+0 0 3 2 -1  -1  1 dsg\n\
+1 0 1 3 -1  0 -1   ole nielsen\n\
+4 # <segment #> <vertex #>  <vertex #> [boundary tag] \n\
+0 1 0 2 \n\
+1 0 2 3 \n\
+2 2 3 \n\
+3 3 1 1 \n\
+3 0 # <x> <y> [attributes] ...Mesh Vertices... \n \
+0 216.0 -86.0 \n \
+1 160.0 -167.0 \n \
+2 114.0 -91.0 \n \
+3 # <vertex #>  <vertex #> [boundary tag] ...Mesh Segments... \n \
+0 0 1 0 \n \
+1 1 2 0 \n \
+2 2 0 0 \n \
+0 # <x> <y> ...Mesh Holes... \n \
+0 # <x> <y> <attribute>...Mesh Regions... \n \
+0 # <x> <y> <attribute>...Mesh Regions, area... \n\
+#Geo reference \n \
+56 \n \
+140 \n \
+120 \n")
+         file.close()
+
+         tags = {}
+         b1 =  anuga.Dirichlet_boundary(conserved_quantities = num.array([0.0]))
+         b2 =  anuga.Dirichlet_boundary(conserved_quantities = num.array([1.0]))
+         b3 =  anuga.Dirichlet_boundary(conserved_quantities = num.array([2.0]))
+         tags["1"] = b1
+         tags["2"] = b2
+         tags["3"] = b3
+
+         domain = Domain(mesh_filename=fileName)
+                         # verbose=True, use_cache=True)
+
+         ## check the quantities
+         answer = [[0., 8., 0.],
+                   [0., 10., 8.]]
+         assert num.allclose(domain.quantities['elevation'].vertex_values,
+                             answer)
+
+         answer = [[0., 12., 10.],
+                   [0., 10., 12.]]
+         assert num.allclose(domain.quantities['stage'].vertex_values,
+                             answer)
+
+         answer = [[0.01, 0.04, 0.03],
+                   [0.01, 0.02, 0.04]]
+         assert num.allclose(domain.quantities['friction'].vertex_values,
+                             answer)
+
+         tagged_elements = domain.get_tagged_elements()
+         assert num.allclose(tagged_elements['dsg'][0], 0)
+         assert num.allclose(tagged_elements['ole nielsen'][0], 1)
+
+         msg = "test_tags_to_boundaries failed. Single boundary wasn't added."
+         self.failUnless( domain.boundary[(1, 0)]  == '1', msg)
+         self.failUnless( domain.boundary[(1, 2)]  == '2', msg)
+         self.failUnless( domain.boundary[(0, 1)]  == '3', msg)
+         self.failUnless( domain.boundary[(0, 0)]  == 'exterior', msg)
+         msg = "test_pmesh2Domain Too many boundaries"
+         self.failUnless( len(domain.boundary)  == 4, msg)
+
+         # FIXME change to use get_xllcorner
+         msg = 'Bad geo-reference'
+         self.failUnless(domain.geo_reference.xllcorner  == 140.0, msg)
+
+         domain = Domain(fileName)
+
+         answer = [[0., 8., 0.],
+                   [0., 10., 8.]]
+         assert num.allclose(domain.quantities['elevation'].vertex_values,
+                             answer)
+
+         answer = [[0., 12., 10.],
+                   [0., 10., 12.]]
+         assert num.allclose(domain.quantities['stage'].vertex_values,
+                             answer)
+
+         answer = [[0.01, 0.04, 0.03],
+                   [0.01, 0.02, 0.04]]
+         assert num.allclose(domain.quantities['friction'].vertex_values,
+                             answer)
+
+         tagged_elements = domain.get_tagged_elements()
+         assert num.allclose(tagged_elements['dsg'][0], 0)
+         assert num.allclose(tagged_elements['ole nielsen'][0], 1)
+
+         msg = "test_tags_to_boundaries failed. Single boundary wasn't added."
+         self.failUnless(domain.boundary[(1, 0)]  == '1', msg)
+         self.failUnless(domain.boundary[(1, 2)]  == '2', msg)
+         self.failUnless(domain.boundary[(0, 1)]  == '3', msg)
+         self.failUnless(domain.boundary[(0, 0)]  == 'exterior', msg)
+         msg = "test_pmesh2Domain Too many boundaries"
+         self.failUnless(len(domain.boundary)  == 4, msg)
+
+         # FIXME change to use get_xllcorner
+         msg = 'Bad geo_reference'
+         self.failUnless(domain.geo_reference.xllcorner  == 140.0, msg)
+
+         os.remove(fileName)
+
+    def test_get_lone_vertices(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] ]
+        boundary = {(0, 0): 'Third',
+                    (0, 2): 'First',
+                    (2, 0): 'Second',
+                    (2, 1): 'Second',
+                    (3, 1): 'Second',
+                    (3, 2): 'Third'}
+
+        domain = Domain(points, vertices, boundary)
+        domain.get_lone_vertices()
+
+    def test_fitting_using_shallow_water_domain(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()
+
+        # 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 num.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 num.allclose(quantity.vertex_values.flat, answer)
+
+        # Cleanup
+        import os
+        os.remove(ptsfile)
+
+    def test_fitting_example_that_crashed(self):
+        """This unit test has been derived from a real world example
+        (the Towradgi '98 rainstorm simulation).
+
+        It shows a condition where fitting as called from set_quantity crashes
+        when ANUGA mesh is reused. The test passes in the case where a new mesh
+        is created.
+
+        See ticket:314
+        """
+
+        verbose = False
+        
+        # Get path where this test is run
+        path = get_pathname_from_package('anuga.shallow_water')        
+        
+        
+        #----------------------------------------------------------------------
+        # Create domain
+        #--------------------------------------------------------------------
+        W = 303400
+        N = 6195800
+        E = 308640
+        S = 6193120
+        bounding_polygon = [[W, S], [E, S], [E, N], [W, N]]
+
+        offending_regions = []
+
+        # From culvert 8
+        offending_regions.append([[307611.43896231, 6193631.6894806],
+                                  [307600.11394969, 6193608.2855474],
+                                  [307597.41349586, 6193609.59227963],
+                                  [307608.73850848, 6193632.99621282]])
+        offending_regions.append([[307633.69143231, 6193620.9216536],
+                                  [307622.36641969, 6193597.5177204],
+                                  [307625.06687352, 6193596.21098818],
+                                  [307636.39188614, 6193619.61492137]])
+
+        # From culvert 9
+        offending_regions.append([[306326.69660524, 6194818.62900522],
+                                  [306324.67939476, 6194804.37099478],
+                                  [306323.75856492, 6194804.50127295],
+                                  [306325.7757754, 6194818.7592834]])
+        offending_regions.append([[306365.57160524, 6194813.12900522],
+                                  [306363.55439476, 6194798.87099478],
+                                  [306364.4752246, 6194798.7407166],
+                                  [306366.49243508, 6194812.99872705]])
+
+        # From culvert 10
+        offending_regions.append([[306955.071019428608, 6194465.704096679576],
+                                  [306951.616980571358, 6194457.295903320424],
+                                  [306950.044491164153, 6194457.941873183474],
+                                  [306953.498530021403, 6194466.350066542625]])
+        offending_regions.append([[307002.540019428649, 6194446.204096679576],
+                                  [306999.085980571399, 6194437.795903320424],
+                                  [307000.658469978604, 6194437.149933457375],
+                                  [307004.112508835853, 6194445.558126816526]])
+
+        interior_regions = []
+        for polygon in offending_regions:
+            interior_regions.append( [polygon, 100] ) 
+
+        meshname = os.path.join(path, 'offending_mesh.msh')
+        anuga.create_mesh_from_regions(bounding_polygon,
+                                 boundary_tags={'south': [0], 'east': [1],
+                                                'north': [2], 'west': [3]},
+                                 maximum_triangle_area=1000000,
+                                 interior_regions=interior_regions,
+                                 filename=meshname,
+                                 use_cache=False,
+                                 verbose=verbose)
+
+        domain = anuga.Domain(meshname, use_cache=False, verbose=verbose)
+
+        #----------------------------------------------------------------------
+        # Fit data point to mesh
+        #----------------------------------------------------------------------
+
+        points_file = os.path.join(path, 'offending_point.pts')
+
+        # Offending point
+        G = Geospatial_data(data_points=[[306953.344, 6194461.5]],
+                            attributes=[1])
+        G.export_points_file(points_file)
+        
+        try:
+            domain.set_quantity('elevation', filename=points_file,
+                                use_cache=False, verbose=verbose, alpha=0.01)
+        except RuntimeError, e:
+            msg = 'Test failed: %s' % str(e)
+            raise Exception(msg)
+            # clean up in case raise fails
+            os.remove(meshname)
+            os.remove(points_file)
+        else:
+            os.remove(meshname)
+            os.remove(points_file)            
+        
+
+    def test_fitting_example_that_crashed_2(self):
+        """test_fitting_example_that_crashed_2
+        
+        This unit test has been derived from a real world example 
+        (the JJKelly study, by Petar Milevski).
+        
+        It shows a condition where set_quantity crashes due to AtA
+        not being built properly
+        
+        See ticket:314
+        """
+
+        verbose = False        
+        
+        # Get path where this test is run
+        path = get_pathname_from_package('anuga.shallow_water')        
+
+        meshname = os.path.join(path, 'test_mesh.msh')
+        W = 304180
+        S = 6185270
+        E = 307650
+        N = 6189040
+        maximum_triangle_area = 1000000
+
+        bounding_polygon = [[W, S], [E, S], [E, N], [W, N]]
+
+        anuga.create_mesh_from_regions(bounding_polygon,
+                                 boundary_tags={'south': [0], 
+                                                'east': [1], 
+                                                'north': [2], 
+                                                'west': [3]},
+                                 maximum_triangle_area=maximum_triangle_area,
+                                 filename=meshname,
+                                 use_cache=False,
+                                 verbose=verbose)
+
+        domain = anuga.Domain(meshname, use_cache=True, verbose=verbose)
+        
+        # Large test set revealed one problem
+        points_file = os.path.join(path, 'test_points_large.csv')
+        try:
+            domain.set_quantity('elevation', filename=points_file,
+                                use_cache=False, verbose=verbose)
+        except AssertionError, e:
+            msg = 'Test failed: %s' % str(e)
+            raise Exception(msg)
+            # Cleanup in case this failed
+            os.remove(meshname)
+
+        # Small test set revealed another problem
+        points_file = os.path.join(path, 'test_points_small.csv')
+        try:    
+            domain.set_quantity('elevation', filename=points_file,
+                                use_cache=False, verbose=verbose)                            
+        except AssertionError, e:
+            msg = 'Test failed: %s' % str(e)
+            raise Exception(msg)
+            # Cleanup in case this failed
+            os.remove(meshname)
+        else:
+            os.remove(meshname)
+
+
+
+
+    def test_variable_elevation(self):            
+        """test_variable_elevation
+
+        This will test that elevagtion van be stored in sww files
+        as a time dependent quantity.
+        
+        It will also chck that storage of other quantities 
+        can be controlled this way.
+        """
+        
+        #---------------------------------------------------------------------
+        # Setup computational domain
+        #---------------------------------------------------------------------
+        length = 8.
+        width = 6.
+        dx = dy = 1    # Resolution: Length of subdivisions on both axes
+        
+        inc = 0.05 # Elevation increment
+
+        points, vertices, boundary = rectangular_cross(int(length/dx), 
+                                                       int(width/dy),
+                                                       len1=length, 
+                                                       len2=width)
+        domain = anuga.Domain(points, vertices, boundary)
+        domain.set_name('channel_variable_test')  # Output name
+        domain.set_quantities_to_be_stored({'elevation': 2,
+                                            'stage': 2})
+
+        #---------------------------------------------------------------------
+        # Setup initial conditions
+        #---------------------------------------------------------------------
+
+        def pole_increment(x,y):
+            """This provides a small increment to a pole located mid stream
+            For use with variable elevation data
+            """
+            
+            z = 0.0*x
+
+            N = len(x)
+            for i in range(N):
+                # Pole
+                if (x[i] - 4)**2 + (y[i] - 2)**2 < 1.0**2:
+                    z[i] += inc
+            return z
+            
+        domain.set_quantity('elevation', 0.0)    # Flat bed initially
+        domain.set_quantity('friction', 0.01)    # Constant friction
+        domain.set_quantity('stage', 0.0)        # Dry initial condition
+
+        #------------------------------------------------------------------
+        # Setup boundary conditions
+        #------------------------------------------------------------------
+        Bi = anuga.Dirichlet_boundary([0.4, 0, 0])          # Inflow
+        Br = anuga.Reflective_boundary(domain)              # Solid reflective wall
+        Bo = anuga.Dirichlet_boundary([-5, 0, 0])           # Outflow
+
+        domain.set_boundary({'left': Bi, 'right': Bo, 'top': Br, 'bottom': Br})
+
+        #-------------------------------------------------------------------
+        # Evolve system through time
+        #-------------------------------------------------------------------
+
+        for t in domain.evolve(yieldstep=1, finaltime=3.0):
+            #print domain.timestepping_statistics()
+
+            domain.add_quantity('elevation', pole_increment)
+        
+            
+        # Check that quantities have been stored correctly    
+        from Scientific.IO.NetCDF import NetCDFFile
+        sww_file = domain.get_name() + '.sww'
+        fid = NetCDFFile(sww_file)
+
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        stage = fid.variables['stage'][:]
+        elevation = fid.variables['elevation'][:]
+        fid.close()
+
+        os.remove(sww_file)
+        
+                   
+        assert len(stage.shape) == 2
+        assert len(elevation.shape) == 2        
+        
+        M, N = stage.shape
+                
+        for i in range(M): 
+            # For each timestep
+            assert num.allclose(max(elevation[i,:]), i * inc) 
+
+
+
+#################################################################################
+
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_swb_basic, 'test')
+    runner = unittest.TextTestRunner(verbosity=1)
+    runner.run(suite)
Index: /trunk/anuga_work/shallow_water_balanced_steve/test_swb_boundary_condition.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/test_swb_boundary_condition.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/test_swb_boundary_condition.py	(revision 8245)
@@ -0,0 +1,878 @@
+#!/usr/bin/env python
+
+import unittest, os
+import os.path
+from math import pi, sqrt
+import tempfile
+
+import anuga
+
+from anuga.config import g, epsilon
+from anuga.config import netcdf_mode_r, netcdf_mode_w, netcdf_mode_a
+from anuga.utilities.numerical_tools import mean
+from anuga.geometry.polygon import is_inside_polygon
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+from anuga.abstract_2d_finite_volumes.quantity import Quantity
+from anuga.geospatial_data.geospatial_data import Geospatial_data
+from anuga.abstract_2d_finite_volumes.mesh_factory import rectangular_cross
+
+from anuga.utilities.system_tools import get_pathname_from_package
+from swb_domain import *
+
+import numpy as num
+
+# Get gateway to C implementation of flux function for direct testing
+from shallow_water_ext import flux_function_central as flux_function
+
+
+
+
+class Test_swb_boundary_condition(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+    def test_boundary_conditions(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]]
+        boundary = {(0, 0): 'Third',
+                    (0, 2): 'First',
+                    (2, 0): 'Second',
+                    (2, 1): 'Second',
+                    (3, 1): 'Second',
+                    (3, 2): 'Third'}
+
+        domain = Domain(points, vertices, boundary)
+        domain.check_integrity()
+
+        domain.set_quantity('stage', [[1,2,3], [5,5,5], [0,0,9], [-6,3,3]])
+
+        domain.set_quantity('xmomentum', [[1,1,1], [2,2,2], [3,3,3], [4,4,4]])
+
+        domain.set_quantity('ymomentum', [[10,10,10], [20,20,20],
+                                          [30,30,30], [40,40,40]])
+
+        D = anuga.Dirichlet_boundary([5, 2, 1])
+        T = anuga.Transmissive_boundary(domain)
+        R = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'First': D, 'Second': T, 'Third': R})
+
+        domain.set_centroid_transmissive_bc(False)
+        domain.update_boundary()
+
+        # Stage
+        assert domain.quantities['stage'].boundary_values[0] == 2.5
+        # Reflective (2.5)
+        assert (domain.quantities['stage'].boundary_values[0] ==
+                domain.get_conserved_quantities(0, edge=0)[0])
+        # Dirichlet
+        assert domain.quantities['stage'].boundary_values[1] == 5.
+
+        
+        # Transmissive (4.5)
+        assert (domain.quantities['stage'].boundary_values[2] ==
+                domain.get_conserved_quantities(2, edge=0)[0])
+        # Transmissive (4.5)
+        assert (domain.quantities['stage'].boundary_values[3] ==
+                domain.get_conserved_quantities(2, edge=1)[0])
+        # Transmissive (-1.5)
+        assert (domain.quantities['stage'].boundary_values[4] ==
+                domain.get_conserved_quantities(3, edge=1)[0])
+        # Reflective (-1.5)
+        assert (domain.quantities['stage'].boundary_values[5] ==
+                domain.get_conserved_quantities(3, edge=2)[0])
+
+        # Xmomentum
+        # Reflective
+        assert domain.quantities['xmomentum'].boundary_values[0] == 1.0
+        # Dirichlet
+        assert domain.quantities['xmomentum'].boundary_values[1] == 2.
+        # Transmissive
+        assert (domain.quantities['xmomentum'].boundary_values[2] ==
+                domain.get_conserved_quantities(2, edge=0)[1])
+        # Transmissive
+        assert (domain.quantities['xmomentum'].boundary_values[3] ==
+                domain.get_conserved_quantities(2, edge=1)[1])
+        # Transmissive
+        assert (domain.quantities['xmomentum'].boundary_values[4] ==
+                domain.get_conserved_quantities(3, edge=1)[1])
+        # Reflective
+        assert domain.quantities['xmomentum'].boundary_values[5] == -4.0
+
+        # Ymomentum
+        # Reflective
+        assert domain.quantities['ymomentum'].boundary_values[0] == -10.0
+        # Dirichlet
+        assert domain.quantities['ymomentum'].boundary_values[1] == 1.
+        # Transmissive
+        assert domain.quantities['ymomentum'].boundary_values[2] == 30.
+        # Transmissive
+        assert domain.quantities['ymomentum'].boundary_values[3] == 30.
+        # Transmissive
+        assert domain.quantities['ymomentum'].boundary_values[4] == 40.
+        # Reflective
+        assert domain.quantities['ymomentum'].boundary_values[5] == 40.
+
+    def test_boundary_conditionsII(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]]
+        boundary = {(0, 0): 'Third',
+                    (0, 2): 'First',
+                    (2, 0): 'Second',
+                    (2, 1): 'Second',
+                    (3, 1): 'Second',
+                    (3, 2): 'Third',
+                    (0, 1): 'Internal',
+                    (1, 2): 'Internal'}
+
+        domain = anuga.Domain(points, vertices, boundary)
+        domain.check_integrity()
+
+        domain.set_quantity('stage', [[1,2,3], [5,5,5], [0,0,9], [-6,3,3]])
+
+        domain.set_quantity('xmomentum', [[1,1,1], [2,2,2], [3,3,3], [4,4,4]])
+
+        domain.set_quantity('ymomentum', [[10,10,10], [20,20,20],
+                                          [30,30,30], [40,40,40]])
+
+        D = anuga.Dirichlet_boundary([5, 2, 1])
+        T = anuga.Transmissive_boundary(domain)
+        R = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'First': D, 'Second': T,
+                             'Third': R, 'Internal': None})
+
+        domain.update_boundary()
+        domain.check_integrity()
+
+    def test_boundary_conditionsIII(self):
+        """test_boundary_conditionsIII
+
+        Test Transmissive_stage_zero_momentum_boundary
+        """
+
+        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]]
+        boundary = {(0, 0): 'Third',
+                    (0, 2): 'First',
+                    (2, 0): 'Second',
+                    (2, 1): 'Second',
+                    (3, 1): 'Second',
+                    (3, 2): 'Third'}
+
+        domain = Domain(points, vertices, boundary)
+        domain.check_integrity()
+
+        domain.set_quantity('stage', [[1,2,3], [5,5,5], [0,0,9], [-6,3,3]])
+
+        domain.set_quantity('xmomentum', [[1,1,1], [2,2,2], [3,3,3], [4,4,4]])
+
+        domain.set_quantity('ymomentum', [[10,10,10], [20,20,20],
+                                          [30,30,30], [40,40,40]])
+
+        D = anuga.Dirichlet_boundary([5, 2, 1])
+        T = anuga.Transmissive_stage_zero_momentum_boundary(domain)
+        R = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'First': D, 'Second': T, 'Third': R})
+
+        domain.update_boundary()
+
+        # Stage
+        # Reflective (2.5)
+        assert domain.quantities['stage'].boundary_values[0] == 2.5
+        assert (domain.quantities['stage'].boundary_values[0] ==
+                domain.get_conserved_quantities(0, edge=0)[0])
+        # Dirichlet
+        assert domain.quantities['stage'].boundary_values[1] == 5.
+        # Transmissive (4.5)
+        assert (domain.quantities['stage'].boundary_values[2] ==
+                domain.get_conserved_quantities(2, edge=0)[0])
+        # Transmissive (4.5)
+        assert (domain.quantities['stage'].boundary_values[3] ==
+                domain.get_conserved_quantities(2, edge=1)[0])
+        # Transmissive (-1.5)
+        assert (domain.quantities['stage'].boundary_values[4] ==
+                domain.get_conserved_quantities(3, edge=1)[0])
+        # Reflective (-1.5)
+        assert (domain.quantities['stage'].boundary_values[5] ==
+                domain.get_conserved_quantities(3, edge=2)[0])
+
+        # Xmomentum
+        # Reflective
+        assert domain.quantities['xmomentum'].boundary_values[0] == 1.0
+        # Dirichlet
+        assert domain.quantities['xmomentum'].boundary_values[1] == 2.
+        assert domain.quantities['xmomentum'].boundary_values[2] == 0.0
+        assert domain.quantities['xmomentum'].boundary_values[3] == 0.0
+        assert domain.quantities['xmomentum'].boundary_values[4] == 0.0
+        # Reflective
+        assert domain.quantities['xmomentum'].boundary_values[5] == -4.0
+
+        # Ymomentum
+        # Reflective
+        assert domain.quantities['ymomentum'].boundary_values[0] == -10.0
+        # Dirichlet
+        assert domain.quantities['ymomentum'].boundary_values[1] == 1.
+        assert domain.quantities['ymomentum'].boundary_values[2] == 0.0
+        assert domain.quantities['ymomentum'].boundary_values[3] == 0.0
+        assert domain.quantities['ymomentum'].boundary_values[4] == 0.0
+        # Reflective
+        assert domain.quantities['ymomentum'].boundary_values[5] == 40.
+
+    def test_boundary_condition_time(self):
+        """test_boundary_condition_time
+
+        This tests that boundary conditions are evaluated
+        using the right time from domain.
+        """
+
+        # Setup computational domain
+        from anuga.abstract_2d_finite_volumes.mesh_factory \
+                import rectangular_cross
+
+        #--------------------------------------------------------------
+        # Setup computational domain
+        #--------------------------------------------------------------
+        N = 5
+        points, vertices, boundary = rectangular_cross(N, N)
+        domain = Domain(points, vertices, boundary)
+
+        #--------------------------------------------------------------
+        # Setup initial conditions
+        #--------------------------------------------------------------
+        domain.set_quantity('elevation', 0.0)
+        domain.set_quantity('friction', 0.0)
+        domain.set_quantity('stage', 0.0)
+
+        #--------------------------------------------------------------
+        # Setup boundary conditions
+        #--------------------------------------------------------------
+        # Time dependent boundary
+        Bt = anuga.Time_boundary(domain=domain, f=lambda t: [t, 0.0, 0.0])
+
+        Br = anuga.Reflective_boundary(domain)              # Reflective wall
+
+        domain.set_boundary({'left': Bt, 'right': Br, 'top': Br, 'bottom': Br})
+
+        for t in domain.evolve(yieldstep = 10, finaltime = 20.0):
+            q = Bt.evaluate()
+
+            # FIXME (Ole): This test would not have passed in
+            # changeset:5846.
+            msg = 'Time boundary not evaluated correctly'
+            assert num.allclose(t, q[0]), msg
+
+
+    def test_spatio_temporal_boundary_1(self):
+        """Test that boundary values can be read from file and interpolated
+        in both time and space.
+
+        Verify that the same steady state solution is arrived at and that
+        time interpolation works.
+
+        The full solution history is not exactly the same as
+        file boundary must read and interpolate from *smoothed* version
+        as stored in sww.
+        """
+
+        # Create sww file of simple propagation from left to right
+        # through rectangular domain
+
+        import time
+        from mesh_factory import rectangular
+
+        # Create basic mesh
+        points, vertices, boundary = rectangular(3, 3)
+
+        # Create shallow water domain
+        domain1 = Domain(points, vertices, boundary)
+
+        domain1.reduction = mean
+        domain1.smooth = False    # Exact result
+
+        domain1.default_order = 2
+        domain1.store = True
+        domain1.set_datadir('.')
+        domain1.set_name('spatio_temporal_boundary_source' + str(time.time()))
+
+        # FIXME: This is extremely important!
+        # How can we test if they weren't stored?
+
+
+        # Bed-slope and friction at vertices (and interpolated elsewhere)
+        domain1.set_quantity('elevation', 0)
+        domain1.set_quantity('friction', 0)
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain1)
+        Bd = anuga.Dirichlet_boundary([0.3,0,0])
+        domain1.set_boundary({'left': Bd, 'top': Bd, 'right': Br, 'bottom': Br})
+
+        # Initial condition
+        domain1.set_quantity('stage', 0)
+        domain1.check_integrity()
+
+        finaltime = 5
+
+        # Evolution  (full domain - large steps)
+        for t in domain1.evolve(yieldstep=0.671, finaltime=finaltime):
+            pass
+
+        cv1 = domain1.quantities['stage'].centroid_values
+
+        # Create a triangle shaped domain (reusing coordinates from domain 1),
+        # formed from the lower and right hand  boundaries and
+        # the sw-ne diagonal
+        # from domain 1. Call it domain2
+
+        points = [[0,0], [1.0/3,0], [1.0/3,1.0/3],
+                  [2.0/3,0], [2.0/3,1.0/3], [2.0/3,2.0/3],
+                  [1,0], [1,1.0/3], [1,2.0/3], [1,1]]
+
+        vertices = [[1,2,0], [3,4,1], [2,1,4], [4,5,2],
+                    [6,7,3], [4,3,7], [7,8,4], [5,4,8], [8,9,5]]
+
+        boundary = {(0,1): 'bottom',   (1,1): 'bottom',   (4,1): 'bottom',
+                    (4,2): 'right',    (6,2): 'right',    (8,2): 'right',
+                    (0,0): 'diagonal', (3,0): 'diagonal', (8,0): 'diagonal'}
+
+        domain2 = Domain(points, vertices, boundary)
+
+        domain2.reduction = domain1.reduction
+        domain2.smooth = False
+        domain2.default_order = 2
+
+        # Bed-slope and friction at vertices (and interpolated elsewhere)
+        domain2.set_quantity('elevation', 0)
+        domain2.set_quantity('friction', 0)
+        domain2.set_quantity('stage', 0)
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain2)
+        Bf = anuga.Field_boundary(domain1.get_name() + '.sww', domain2)
+        domain2.set_boundary({'right':Br, 'bottom':Br, 'diagonal':Bf})
+        domain2.check_integrity()
+
+        # Evolution (small steps)
+        for t in domain2.evolve(yieldstep=0.0711, finaltime=finaltime):
+            pass
+
+        # Use output from domain1 as spatio-temporal boundary for domain2
+        # and verify that results at right hand side are close.
+        cv2 = domain2.quantities['stage'].centroid_values
+
+
+        assert num.allclose(num.take(cv1, (0,8,16), axis=0),
+                            num.take(cv2, (0,3,8), axis=0),atol=1.0e-2)      # Diag
+        assert num.allclose(num.take(cv1, (0,6,12), axis=0),
+                            num.take(cv2, (0,1,4), axis=0),atol=1.0e-2)      # Bottom
+        assert num.allclose(num.take(cv1, (12,14,16), axis=0),
+                            num.take(cv2, (4,6,8), axis=0),atol=1.0e-2)      # RHS
+
+        # Cleanup
+        os.remove(domain1.get_name() + '.sww')
+
+    def test_spatio_temporal_boundary_2(self):
+        """Test that boundary values can be read from file and interpolated
+        in both time and space.
+        This is a more basic test, verifying that boundary object
+        produces the expected results
+        """
+
+        import time
+        from mesh_factory import rectangular
+
+        # Create sww file of simple propagation from left to right
+        # through rectangular domain
+
+        # Create basic mesh
+        points, vertices, boundary = rectangular(3, 3)
+
+        #Create shallow water domain
+        domain1 = Domain(points, vertices, boundary)
+
+        domain1.reduction = mean
+        domain1.smooth = True    # To mimic MOST output
+
+        domain1.default_order = 2
+        domain1.store = True
+        domain1.set_datadir('.')
+        domain1.set_name('spatio_temporal_boundary_source' + str(time.time()))
+
+        # FIXME: This is extremely important!
+        # How can we test if they weren't stored?
+        domain1.quantities_to_be_stored = {'elevation': 1,
+                                           'stage': 2, 
+                                           'xmomentum': 2, 
+                                           'ymomentum': 2}
+
+        # Bed-slope and friction at vertices (and interpolated elsewhere)
+        domain1.set_quantity('elevation', 0)
+        domain1.set_quantity('friction', 0)
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain1)
+        Bd = anuga.Dirichlet_boundary([0.3,0,0])
+        domain1.set_boundary({'left': Bd, 'top': Bd, 'right': Br, 'bottom': Br})
+
+        # Initial condition
+        domain1.set_quantity('stage', 0)
+        domain1.check_integrity()
+
+        finaltime = 5
+
+        # Evolution  (full domain - large steps)
+        for t in domain1.evolve(yieldstep=1, finaltime=finaltime):
+            pass
+
+        # Create an triangle shaped domain (coinciding with some
+        # coordinates from domain 1),
+        # formed from the lower and right hand  boundaries and
+        # the sw-ne diagonal
+        # from domain 1. Call it domain2
+        points = [[0,0],
+                  [1.0/3,0], [1.0/3,1.0/3],
+                  [2.0/3,0], [2.0/3,1.0/3], [2.0/3,2.0/3],
+                  [1,0],     [1,1.0/3],     [1,2.0/3],     [1,1]]
+
+        vertices = [[1,2,0], [3,4,1], [2,1,4], [4,5,2],
+                    [6,7,3], [4,3,7], [7,8,4], [5,4,8], [8,9,5]]
+
+        boundary = {(0,1): 'bottom',   (1,1): 'bottom',   (4,1): 'bottom',
+                    (4,2): 'right',    (6,2): 'right',    (8,2): 'right',
+                    (0,0): 'diagonal', (3,0): 'diagonal', (8,0): 'diagonal'}
+
+        domain2 = Domain(points, vertices, boundary)
+
+        domain2.reduction = domain1.reduction
+        domain2.smooth = False
+        domain2.default_order = 2
+
+        # Bed-slope and friction at vertices (and interpolated elsewhere)
+        domain2.set_quantity('elevation', 0)
+        domain2.set_quantity('friction', 0)
+        domain2.set_quantity('stage', 0)
+
+        # Read results for specific timesteps t=1 and t=2
+        from Scientific.IO.NetCDF import NetCDFFile
+        fid = NetCDFFile(domain1.get_name() + '.sww')
+
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        s1 = fid.variables['stage'][1,:]
+        s2 = fid.variables['stage'][2,:]
+        fid.close()
+
+        shp = (len(x), 1)
+        points = num.concatenate((num.reshape(x, shp), num.reshape(y, shp)),
+                                 axis=1)
+
+        # The diagonal points of domain 1 are 0, 5, 10, 15
+        msg = ('value was\n%s\nshould be\n'
+               '[[0,0], [1.0/3, 1.0/3],\n'
+               '[2.0/3, 2.0/3], [1,1]]'
+               % str(num.take(points, [0,5,10,15], axis=0)))
+        assert num.allclose(num.take(points, [0,5,10,15], axis=0),
+                            [[0,0], [1.0/3, 1.0/3], [2.0/3, 2.0/3], [1,1]]), msg
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain2)
+        Bf = anuga.Field_boundary(domain1.get_name() + '.sww',
+                            domain2, verbose=False)
+        domain2.set_boundary({'right':Br, 'bottom':Br, 'diagonal':Bf})
+        domain2.check_integrity()
+
+        # Test that interpolation points are the mid points of the all boundary
+        # segments
+        boundary_midpoints = [[1.0/6, 0], [1.0/2, 0], [5.0/6,0],
+                              [1.0, 1.0/6], [1.0, 1.0/2], [1.0, 5.0/6],
+                              [1.0/6, 1.0/6], [0.5, 0.5], [5.0/6, 5.0/6]]
+
+        boundary_midpoints.sort()
+        R = Bf.F.interpolation_points.tolist()
+        R.sort()
+        assert num.allclose(boundary_midpoints, R)
+
+        # Check spatially interpolated output at time == 1
+        domain2.time = 1
+
+        # First diagonal midpoint
+        R0 = Bf.evaluate(0, 0)
+        assert num.allclose(R0[0], (s1[0] + s1[5])/2)
+
+        # Second diagonal midpoint
+        R0 = Bf.evaluate(3, 0)
+        assert num.allclose(R0[0], (s1[5] + s1[10])/2)
+
+        # First diagonal midpoint
+        R0 = Bf.evaluate(8, 0)
+        assert num.allclose(R0[0], (s1[10] + s1[15])/2)
+
+        # Check spatially interpolated output at time == 2
+        domain2.time = 2
+
+        # First diagonal midpoint
+        R0 = Bf.evaluate(0, 0)
+        assert num.allclose(R0[0], (s2[0] + s2[5])/2)
+
+        # Second diagonal midpoint
+        R0 = Bf.evaluate(3, 0)
+        assert num.allclose(R0[0], (s2[5] + s2[10])/2)
+
+        # First diagonal midpoint
+        R0 = Bf.evaluate(8, 0)
+        assert num.allclose(R0[0], (s2[10] + s2[15])/2)
+
+        # Now check temporal interpolation
+        domain2.time = 1 + 2.0/3
+
+        # First diagonal midpoint
+        R0 = Bf.evaluate(0,0)
+        assert num.allclose(R0[0],
+                            ((s1[0] + s1[5])/2 + 2.0*(s2[0] + s2[5])/2)/3)
+
+        # Second diagonal midpoint
+        R0 = Bf.evaluate(3, 0)
+        assert num.allclose(R0[0],
+                            ((s1[5] + s1[10])/2 + 2.0*(s2[5] + s2[10])/2)/3)
+
+        # First diagonal midpoint
+        R0 = Bf.evaluate(8, 0)
+        assert num.allclose(R0[0],
+                            ((s1[10] + s1[15])/2 + 2.0*(s2[10] + s2[15])/2)/3)
+
+        # Cleanup
+        os.remove(domain1.get_name() + '.sww')
+
+    def test_spatio_temporal_boundary_3(self):
+        """Test that boundary values can be read from file and interpolated
+        in both time and space.
+        This is a more basic test, verifying that boundary object
+        produces the expected results
+
+        This tests adjusting using mean_stage
+        """
+
+        #Create sww file of simple propagation from left to right
+        #through rectangular domain
+
+        import time
+        from mesh_factory import rectangular
+
+        mean_stage = 5.2    # Adjust stage by this amount in boundary
+
+        # Create basic mesh
+        points, vertices, boundary = rectangular(3, 3)
+
+        # Create shallow water domain
+        domain1 = Domain(points, vertices, boundary)
+
+        domain1.reduction = mean
+        domain1.smooth = True    # To mimic MOST output
+
+        domain1.default_order = 2
+        domain1.store = True
+        domain1.set_datadir('.')
+        domain1.set_name('spatio_temporal_boundary_source' + str(time.time()))
+
+        # FIXME: This is extremely important!
+        # How can we test if they weren't stored?
+
+        # Bed-slope and friction at vertices (and interpolated elsewhere)
+        domain1.set_quantity('elevation', 0)
+        domain1.set_quantity('friction', 0)
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain1)
+        Bd = anuga.Dirichlet_boundary([0.3, 0, 0])
+        domain1.set_boundary({'left': Bd, 'top': Bd, 'right': Br, 'bottom': Br})
+
+        # Initial condition
+        domain1.set_quantity('stage', 0)
+        domain1.check_integrity()
+
+        finaltime = 5
+
+        # Evolution  (full domain - large steps)
+        for t in domain1.evolve(yieldstep=1, finaltime=finaltime):
+            pass
+
+        # Create an triangle shaped domain (coinciding with some
+        # coordinates from domain 1),
+        # formed from the lower and right hand  boundaries and
+        # the sw-ne diagonal
+        # from domain 1. Call it domain2
+        points = [[0,0],
+                  [1.0/3,0], [1.0/3,1.0/3],
+                  [2.0/3,0], [2.0/3,1.0/3], [2.0/3,2.0/3],
+                  [1,0],     [1,1.0/3],     [1,2.0/3],     [1,1]]
+
+        vertices = [[1,2,0],
+                    [3,4,1], [2,1,4], [4,5,2],
+                    [6,7,3], [4,3,7], [7,8,4], [5,4,8], [8,9,5]]
+
+        boundary = {(0,1): 'bottom',   (1,1): 'bottom',   (4,1): 'bottom',
+                    (4,2): 'right',    (6,2): 'right',    (8,2): 'right',
+                    (0,0): 'diagonal', (3,0): 'diagonal', (8,0): 'diagonal'}
+
+        domain2 = Domain(points, vertices, boundary)
+
+        domain2.reduction = domain1.reduction
+        domain2.smooth = False
+        domain2.default_order = 2
+
+        # Bed-slope and friction at vertices (and interpolated elsewhere)
+        domain2.set_quantity('elevation', 0)
+        domain2.set_quantity('friction', 0)
+        domain2.set_quantity('stage', 0)
+
+        # Read results for specific timesteps t=1 and t=2
+        from Scientific.IO.NetCDF import NetCDFFile
+        fid = NetCDFFile(domain1.get_name() + '.sww')
+
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        s1 = fid.variables['stage'][1,:]
+        s2 = fid.variables['stage'][2,:]
+        fid.close()
+
+        shp = (len(x), 1)
+        points = num.concatenate((num.reshape(x, shp), num.reshape(y, shp)),
+                                 axis=1)
+        #The diagonal points of domain 1 are 0, 5, 10, 15
+
+        msg = ('values was\n%s\nshould be\n'
+               '[[0,0], [1.0/3, 1.0/3],\n'
+               '[2.0/3, 2.0/3], [1,1]]'
+               % str(num.take(points, [0,5,10,15], axis=0)))
+        assert num.allclose(num.take(points, [0,5,10,15], axis=0),
+                            [[0,0], [1.0/3, 1.0/3], [2.0/3, 2.0/3], [1,1]]), msg
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain2)
+        Bf = anuga.Field_boundary(domain1.get_name() + '.sww',
+                            domain2, mean_stage=mean_stage, verbose=False)
+
+        domain2.set_boundary({'right':Br, 'bottom':Br, 'diagonal':Bf})
+        domain2.check_integrity()
+
+        # Test that interpolation points are the mid points of the all boundary
+        # segments
+        boundary_midpoints = [[1.0/6, 0], [1.0/2, 0], [5.0/6,0],
+                              [1.0, 1.0/6], [1.0, 1.0/2], [1.0, 5.0/6],
+                              [1.0/6, 1.0/6], [0.5, 0.5], [5.0/6, 5.0/6]]
+
+        boundary_midpoints.sort()
+        R = Bf.F.interpolation_points.tolist()
+        R.sort()
+        assert num.allclose(boundary_midpoints, R)
+
+        # Check spatially interpolated output at time == 1
+        domain2.time = 1
+
+        # First diagonal midpoint
+        R0 = Bf.evaluate(0, 0)
+        assert num.allclose(R0[0], (s1[0] + s1[5])/2 + mean_stage)
+
+        # Second diagonal midpoint
+        R0 = Bf.evaluate(3, 0)
+        assert num.allclose(R0[0], (s1[5] + s1[10])/2 + mean_stage)
+
+        # First diagonal midpoint
+        R0 = Bf.evaluate(8, 0)
+        assert num.allclose(R0[0], (s1[10] + s1[15])/2 + mean_stage)
+
+        # Check spatially interpolated output at time == 2
+        domain2.time = 2
+
+        # First diagonal midpoint
+        R0 = Bf.evaluate(0, 0)
+        assert num.allclose(R0[0], (s2[0] + s2[5])/2 + mean_stage)
+
+        # Second diagonal midpoint
+        R0 = Bf.evaluate(3, 0)
+        assert num.allclose(R0[0], (s2[5] + s2[10])/2 + mean_stage)
+
+        # First diagonal midpoint
+        R0 = Bf.evaluate(8, 0)
+        assert num.allclose(R0[0], (s2[10] + s2[15])/2 + mean_stage)
+
+        #Now check temporal interpolation
+        domain2.time = 1 + 2.0/3
+
+        # First diagonal midpoint
+        R0 = Bf.evaluate(0, 0)
+        assert num.allclose(R0[0],
+                            ((s1[0] + s1[5])/2 + 2.0*(s2[0] + s2[5])/2)/3 +
+                                mean_stage)
+
+        # Second diagonal midpoint
+        R0 = Bf.evaluate(3, 0)
+        assert num.allclose(R0[0],
+                            ((s1[5] + s1[10])/2 + 2.0*(s2[5] + s2[10])/2)/3 +
+                                mean_stage)
+
+        # First diagonal midpoint
+        R0 = Bf.evaluate(8, 0)
+        assert num.allclose(R0[0],
+                            ((s1[10] + s1[15])/2 + 2.0*(s2[10] + s2[15])/2)/3 +
+                                mean_stage)
+
+        # Cleanup
+        os.remove(domain1.get_name() + '.sww')
+        os.remove(domain2.get_name() + '.sww')
+
+        
+
+    def test_spatio_temporal_boundary_outside(self):
+        """Test that field_boundary catches if a point is outside the sww
+        that defines it
+        """
+
+        import time
+        from mesh_factory import rectangular
+
+        # Create sww file of simple propagation from left to right
+        # through rectangular domain
+
+        # Create basic mesh
+        points, vertices, boundary = rectangular(3, 3)
+
+        # Create shallow water domain
+        domain1 = anuga.Domain(points, vertices, boundary)
+
+        domain1.reduction = mean
+        domain1.smooth = True    # To mimic MOST output
+
+        domain1.default_order = 2
+        domain1.store = True
+        domain1.set_datadir('.')
+        domain1.set_name('spatio_temporal_boundary_source' + str(time.time()))
+
+        # FIXME: This is extremely important!
+        # How can we test if they weren't stored?
+        domain1.set_quantities_to_be_stored({'elevation': 1,
+                                             'stage': 2, 
+                                             'xmomentum': 2, 
+                                             'ymomentum': 2})
+
+
+        # Bed-slope and friction at vertices (and interpolated elsewhere)
+        domain1.set_quantity('elevation', 0)
+        domain1.set_quantity('friction', 0)
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain1)
+        Bd = anuga.Dirichlet_boundary([0.3, 0, 0])
+        domain1.set_boundary({'left': Bd, 'top': Bd, 'right': Br, 'bottom': Br})
+
+        # Initial condition
+        domain1.set_quantity('stage', 0)
+        domain1.check_integrity()
+
+        finaltime = 5
+
+        # Evolution  (full domain - large steps)
+        for t in domain1.evolve(yieldstep=1, finaltime=finaltime):
+            pass
+
+        # Create an triangle shaped domain (coinciding with some
+        # coordinates from domain 1, but one edge outside!),
+        # formed from the lower and right hand  boundaries and
+        # the sw-ne diagonal as in the previous test but scaled
+        # in the x direction by a factor of 2
+        points = [[0,0],
+                  [2.0/3,0], [2.0/3,1.0/3],
+                  [4.0/3,0], [4.0/3,1.0/3], [4.0/3,2.0/3],
+                  [2,0],     [2,1.0/3],     [2,2.0/3],     [2,1]]
+
+        vertices = [[1,2,0],
+                    [3,4,1], [2,1,4], [4,5,2],
+                    [6,7,3], [4,3,7], [7,8,4], [5,4,8], [8,9,5]]
+
+        boundary = {(0,1): 'bottom',   (1,1): 'bottom',   (4,1): 'bottom',
+                    (4,2): 'right',    (6,2): 'right',    (8,2): 'right',
+                    (0,0): 'diagonal', (3,0): 'diagonal', (8,0): 'diagonal'}
+
+        domain2 = Domain(points, vertices, boundary)
+
+        domain2.reduction = domain1.reduction
+        domain2.smooth = False
+        domain2.default_order = 2
+
+        # Bed-slope and friction at vertices (and interpolated elsewhere)
+        domain2.set_quantity('elevation', 0)
+        domain2.set_quantity('friction', 0)
+        domain2.set_quantity('stage', 0)
+
+        # Read results for specific timesteps t=1 and t=2
+        from Scientific.IO.NetCDF import NetCDFFile
+        fid = NetCDFFile(domain1.get_name() + '.sww')
+
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        s1 = fid.variables['stage'][1,:]
+        s2 = fid.variables['stage'][2,:]
+        fid.close()
+
+        shp = (len(x), 1)
+        points = num.concatenate((num.reshape(x, shp), num.reshape(y, shp)),
+                                 axis=1)
+        #The diagonal points of domain 1 are 0, 5, 10, 15
+
+        assert num.allclose(num.take(points, [0,5,10,15], axis=0),
+                            [[0,0], [1.0/3,1.0/3], [2.0/3,2.0/3], [1,1]])
+
+        # Boundary conditions
+        Br = anuga.Reflective_boundary(domain2)
+        Bf = anuga.Field_boundary(domain1.get_name() + '.sww',
+                            domain2, mean_stage=1, verbose=False)
+
+        domain2.set_boundary({'right':Br, 'bottom':Br, 'diagonal':Bf})
+        domain2.check_integrity()
+
+        try:
+            for t in domain2.evolve(yieldstep=1, finaltime=finaltime):
+                pass
+        except:
+            pass
+        else:
+            msg = 'This should have caught NAN at boundary'
+            raise Exception, msg
+
+        #Cleanup
+        os.remove(domain1.get_name() + '.sww')
+        os.remove(domain2.get_name() + '.sww')        
+
+
+
+#################################################################################
+
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_swb_boundary_condition, 'test')
+    runner = unittest.TextTestRunner(verbosity=1)
+    runner.run(suite)
Index: /trunk/anuga_work/shallow_water_balanced_steve/test_swb_conservation.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/test_swb_conservation.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/test_swb_conservation.py	(revision 8245)
@@ -0,0 +1,817 @@
+#!/usr/bin/env python
+
+import unittest, os
+import os.path
+from math import pi, sqrt
+import tempfile
+
+import anuga
+
+from anuga.config import g, epsilon
+from anuga.config import netcdf_mode_r, netcdf_mode_w, netcdf_mode_a
+from anuga.utilities.numerical_tools import mean
+from anuga.geometry.polygon import is_inside_polygon
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+from anuga.abstract_2d_finite_volumes.quantity import Quantity
+from anuga.geospatial_data.geospatial_data import Geospatial_data
+from anuga.abstract_2d_finite_volumes.mesh_factory import rectangular_cross
+
+from anuga.utilities.system_tools import get_pathname_from_package
+from swb_domain import *
+
+import numpy as num
+
+# Get gateway to C implementation of flux function for direct testing
+from shallow_water_ext import flux_function_central as flux_function
+
+
+
+
+class Test_swb_conservation(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+
+    def test_conservation_1(self):
+        """Test that stage is conserved globally
+
+        This one uses a flat bed, reflective bdries and a suitable
+        initial condition
+        """
+
+        from mesh_factory import rectangular
+
+        # Create basic mesh
+        points, vertices, boundary = rectangular(6, 6)
+
+        # Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.default_order = 2
+
+        # IC
+        def x_slope(x, y):
+            return x/3
+
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('friction', 0)
+        domain.set_quantity('stage', x_slope)
+
+        # Boundary conditions (reflective everywhere)
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        domain.check_integrity()
+
+        initial_volume = domain.quantities['stage'].get_integral()
+        initial_xmom = domain.quantities['xmomentum'].get_integral()
+
+        # Evolution
+        for t in domain.evolve(yieldstep=0.05, finaltime=5.0):
+            volume = domain.quantities['stage'].get_integral()
+            assert num.allclose(volume, initial_volume)
+
+            #I don't believe that the total momentum should be the same
+            #It starts with zero and ends with zero though
+            #xmom = domain.quantities['xmomentum'].get_integral()
+            #print xmom
+            #assert allclose (xmom, initial_xmom)
+
+        os.remove(domain.get_name() + '.sww')
+
+    def test_conservation_2(self):
+        """Test that stage is conserved globally
+
+        This one uses a slopy bed, reflective bdries and a suitable
+        initial condition
+        """
+
+        # Create basic mesh
+        points, vertices, boundary = anuga.rectangular(6, 6)
+
+        # Create shallow water domain
+        domain = anuga.Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.default_order = 2
+
+        # IC
+        def x_slope(x, y):
+            return x/3
+
+        domain.set_quantity('elevation', x_slope)
+        domain.set_quantity('friction', 0)
+        domain.set_quantity('stage', 0.4)    # Steady
+
+        # Boundary conditions (reflective everywhere)
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        domain.check_integrity()
+
+        initial_volume = domain.quantities['stage'].get_integral()
+        initial_xmom = domain.quantities['xmomentum'].get_integral()
+
+        # Evolution
+        for t in domain.evolve(yieldstep=0.05, finaltime=5.0):
+            volume = domain.quantities['stage'].get_integral()
+            assert num.allclose(volume, initial_volume)
+
+            #FIXME: What would we expect from momentum
+            #xmom = domain.quantities['xmomentum'].get_integral()
+            #print xmom
+            #assert allclose (xmom, initial_xmom)
+
+        os.remove(domain.get_name() + '.sww')
+
+    def test_conservation_3(self):
+        """Test that stage is conserved globally
+
+        This one uses a larger grid, convoluted bed, reflective boundaries
+        and a suitable initial condition
+        """
+
+        from mesh_factory import rectangular
+
+        # Create basic mesh
+        points, vertices, boundary = rectangular(2, 1)
+
+        # Create shallow water domain
+        domain = anuga.Domain(points, vertices, boundary)
+        domain.smooth = False
+
+
+        # IC
+        def x_slope(x, y):
+            z = 0*x
+            for i in range(len(x)):
+                if x[i] < 0.3:
+                    z[i] = x[i]/3
+                if 0.3 <= x[i] < 0.5:
+                    z[i] = -0.5
+                if 0.5 <= x[i] < 0.7:
+                    z[i] = 0.39
+                if 0.7 <= x[i]:
+                    z[i] = x[i]/3
+            return z
+
+        domain.set_quantity('elevation', x_slope)
+        domain.set_quantity('friction', 0)
+        domain.set_quantity('stage', 0.4) #Steady
+
+        # Boundary conditions (reflective everywhere)
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        domain.check_integrity()
+
+        initial_volume = domain.quantities['stage'].get_integral()
+        initial_xmom = domain.quantities['xmomentum'].get_integral()
+
+        import copy
+
+        ref_centroid_values = copy.copy(domain.quantities['stage'].\
+                                            centroid_values)
+
+        domain.distribute_to_vertices_and_edges()
+
+        assert num.allclose(domain.quantities['stage'].centroid_values,
+                            ref_centroid_values)
+
+        # Check that initial limiter doesn't violate cons quan
+        assert num.allclose(domain.quantities['stage'].get_integral(),
+                            initial_volume)
+
+        # Evolution
+        for t in domain.evolve(yieldstep=0.05, finaltime=10):
+            volume =  domain.quantities['stage'].get_integral()
+                        
+            assert num.allclose (volume, initial_volume)
+
+        os.remove(domain.get_name() + '.sww')
+
+    def test_conservation_4(self):
+        """Test that stage is conserved globally
+
+        This one uses a larger grid, convoluted bed, reflective boundaries
+        and a suitable initial condition
+        """
+
+        # Create basic mesh
+        points, vertices, boundary = anuga.rectangular(6, 6)
+
+        # Create shallow water domain
+        domain = anuga.Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.default_order = 2
+
+        # IC
+        def x_slope(x, y):
+            z = 0*x
+            for i in range(len(x)):
+                if x[i] < 0.3:
+                    z[i] = x[i]/3
+                if 0.3 <= x[i] < 0.5:
+                    z[i] = -0.5
+                if 0.5 <= x[i] < 0.7:
+                    #z[i] = 0.3     # OK with beta == 0.2
+                    z[i] = 0.34     # OK with beta == 0.0
+                    #z[i] = 0.35    # Fails after 80 timesteps with an error
+                                    # of the order 1.0e-5
+                if 0.7 <= x[i]:
+                    z[i] = x[i]/3
+            return z
+
+        domain.set_quantity('elevation', x_slope)
+        domain.set_quantity('friction', 0)
+        domain.set_quantity('stage', 0.4) #Steady
+
+        # Boundary conditions (reflective everywhere)
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        domain.check_integrity()
+
+
+        initial_volume = domain.quantities['stage'].get_integral()
+        initial_xmom = domain.quantities['xmomentum'].get_integral()
+
+        import copy
+
+        ref_centroid_values = copy.copy(domain.quantities['stage'].\
+                                            centroid_values)
+
+        # Test limiter by itself
+        domain.distribute_to_vertices_and_edges()
+
+        # Check that initial limiter doesn't violate cons quan
+        assert num.allclose(domain.quantities['stage'].get_integral(),
+                            initial_volume)
+        # NOTE: This would fail if any initial stage was less than the
+        # corresponding bed elevation - but that is reasonable.
+
+        #Evolution
+        #print domain.get_time(), initial_volume
+        for t in domain.evolve(yieldstep=0.05, finaltime=10.0):
+            volume =  domain.quantities['stage'].get_integral()
+
+            #print domain.get_time(), volume
+            assert num.allclose (volume, initial_volume)
+
+        os.remove(domain.get_name() + '.sww')
+
+    def test_conservation_5(self):
+        """Test that momentum is conserved globally in steady state scenario
+
+        This one uses a slopy bed, dirichlet and reflective bdries
+        """
+
+        # Create basic mesh
+        points, vertices, boundary = anuga.rectangular(6, 6)
+
+        # Create shallow water domain
+        domain = anuga.Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.default_order = 2
+
+        # IC
+        def x_slope(x, y):
+            return x/3
+
+        domain.set_quantity('elevation', x_slope)
+        domain.set_quantity('friction', 0)
+        domain.set_quantity('stage', 0.4) # Steady
+
+        # Boundary conditions (reflective everywhere)
+        Br = anuga.Reflective_boundary(domain)
+        Bleft = anuga.Dirichlet_boundary([0.5, 0, 0])
+        Bright = anuga.Dirichlet_boundary([0.1, 0, 0])
+        domain.set_boundary({'left': Bleft, 'right': Bright,
+                             'top': Br, 'bottom': Br})
+
+        domain.check_integrity()
+
+        initial_volume = domain.quantities['stage'].get_integral()
+        initial_xmom = domain.quantities['xmomentum'].get_integral()
+
+        # Evolution
+        for t in domain.evolve(yieldstep=0.05, finaltime=15.0):
+            stage =  domain.quantities['stage'].get_integral()
+            xmom = domain.quantities['xmomentum'].get_integral()
+            ymom = domain.quantities['ymomentum'].get_integral()
+
+            if num.allclose(t, 10):    # Steady state reached
+                steady_xmom = domain.quantities['xmomentum'].get_integral()
+                steady_ymom = domain.quantities['ymomentum'].get_integral()
+                steady_stage = domain.quantities['stage'].get_integral()
+
+            if t > 10:
+                msg = 'time=%.2f, xmom=%.10f, steady_xmom=%.10f' % (t, xmom, steady_xmom)
+                assert num.allclose(xmom, steady_xmom,atol=1.0e-4), msg
+
+                msg = 'time=%.2f, ymom=%.10f, steady_ymom=%.10f' % (t, ymom, steady_ymom)
+                assert num.allclose(ymom, steady_ymom,atol=1.0e-4), msg
+
+                msg = 'time=%.2f, stage=%.10f, steady_stage=%.10f' % (t, stage, steady_stage)
+                assert num.allclose(stage, steady_stage,atol=1.0e-4)
+
+        os.remove(domain.get_name() + '.sww')
+
+    def test_conservation_real(self):
+        """Test that momentum is conserved globally
+
+        Stephen finally made a test that revealed the problem.
+        This test failed with code prior to 25 July 2005
+        """
+
+        import sys
+        import os.path
+        sys.path.append(os.path.join('..', 'abstract_2d_finite_volumes'))
+        from mesh_factory import rectangular
+
+        yieldstep = 0.01
+        finaltime = 0.05
+        min_depth = 1.0e-2
+
+        #Create shallow water domain
+        points, vertices, boundary = rectangular(10, 10, len1=500, len2=500)
+        domain = Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.default_order = 1
+        domain.minimum_allowed_height = min_depth
+
+        # Set initial condition
+        class Set_IC:
+            """Set an initial condition with a constant value, for x0<x<x1"""
+
+            def __init__(self, x0=0.25, x1=0.5, h=1.0):
+                self.x0 = x0
+                self.x1 = x1
+                self.h  = h
+
+            def __call__(self, x, y):
+                return self.h*((x > self.x0) & (x < self.x1))
+
+        domain.set_quantity('stage', Set_IC(200.0, 300.0, 5.0))
+
+        # Boundaries
+        R = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'left': R, 'right': R, 'top':R, 'bottom': R})
+
+        ref = domain.quantities['stage'].get_integral()
+
+        # Evolution
+        for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
+            pass
+
+        now = domain.quantities['stage'].get_integral()
+
+        msg = 'Stage not conserved: was %f, now %f' % (ref, now)
+        assert num.allclose(ref, now), msg
+
+        os.remove(domain.get_name() + '.sww')
+
+
+    def test_total_volume(self):        
+        """test_total_volume
+        
+        Test that total volume can be computed correctly
+        """            
+
+        #----------------------------------------------------------------------
+        # Setup computational domain
+        #----------------------------------------------------------------------
+
+        length = 100.
+        width  = 20.
+        dx = dy = 5       # Resolution: of grid on both axes
+        
+        points, vertices, boundary = rectangular_cross(int(length/dx),
+                                                       int(width/dy),
+                                                       len1=length,
+                                                       len2=width)
+        domain = Domain(points, vertices, boundary)   
+
+        #----------------------------------------------------------------------
+        # Simple flat bottom bathtub
+        #----------------------------------------------------------------------
+
+        d = 1.0
+        domain.set_quantity('elevation', 0.0)
+        domain.set_quantity('stage', d)
+        
+        assert num.allclose(domain.compute_total_volume(), length*width*d)
+
+        #----------------------------------------------------------------------
+        # Slope
+        #----------------------------------------------------------------------
+                
+        slope = 1.0/10          # RHS drops to -10m
+        def topography(x, y):
+            return -x * slope
+
+        domain.set_quantity('elevation', topography)
+        domain.set_quantity('stage', 0.0)       # Domain full
+        
+        V = domain.compute_total_volume()
+        assert num.allclose(V, length*width*10/2)
+
+        domain.set_quantity('stage', -5.0)      # Domain 'half' full
+        
+        # IMPORTANT: Adjust stage to match elevation
+        domain.distribute_to_vertices_and_edges()
+        
+        V = domain.compute_total_volume()
+        assert num.allclose(V, width*(length/2)*5.0/2)
+
+
+    def test_volumetric_balance_computation(self):
+        """test_volumetric_balance_computation
+        
+        Test that total in and out flows are computed correctly 
+        in a steady state situation
+        """
+
+        # Set to True if volumetric output is sought
+        verbose = False
+
+
+
+        #----------------------------------------------------------------------
+        # Setup computational domain
+        #----------------------------------------------------------------------
+
+        finaltime = 500.0
+        length = 300.
+        width  = 20.
+        dx = dy = 5       # Resolution: of grid on both axes
+        
+        # Input parameters
+        uh = 1.0
+        vh = 0.0
+        d = 1.0
+        
+        # 20 m^3/s in the x direction across entire domain
+        ref_flow = uh*d*width
+
+        points, vertices, boundary = rectangular_cross(int(length/dx),
+                                                       int(width/dy),
+                                                       len1=length,
+                                                       len2=width)
+
+        domain = Domain(points, vertices, boundary)   
+        domain.set_name('Inflow_flowline_test')              # Output name
+
+        #----------------------------------------------------------------------
+        # Setup initial conditions
+        #----------------------------------------------------------------------
+
+        domain.set_quantity('elevation', 0.0)  # Flat bed
+        domain.set_quantity('friction', 0.0)   # Constant zero friction
+                
+        domain.set_quantity('stage', expression='elevation + %d' % d) 
+
+        #----------------------------------------------------------------------
+        # Setup boundary conditions
+        #----------------------------------------------------------------------
+
+        Br = anuga.Reflective_boundary(domain)      # Solid reflective wall
+                
+        # Constant flow in and out of domain
+        # Depth = 1m, uh=1 m/s, i.e. a flow of 20 m^3/s 
+        Bi = anuga.Dirichlet_boundary([d, uh, vh]) 
+        Bo = anuga.Dirichlet_boundary([d, uh, vh])
+
+        domain.set_boundary({'left': Bi, 'right': Bo, 'top': Br, 'bottom': Br})
+
+        #----------------------------------------------------------------------
+        # Evolve system through time
+        #----------------------------------------------------------------------
+
+        for t in domain.evolve(yieldstep=50.0, finaltime=finaltime):
+            S = domain.volumetric_balance_statistics()
+            if verbose :
+                print domain.timestepping_statistics()
+                print S
+                
+            if t > 300:
+                # Steady state reached
+                
+                # Square on flowline at 200m
+                q = domain.get_flow_through_cross_section([[200.0,  0.0],
+                                                           [200.0, 20.0]])
+                
+                assert num.allclose(q, ref_flow)
+
+        os.remove('Inflow_flowline_test.sww') 
+
+    def test_volume_conservation_inflow(self):
+        """test_volume_conservation
+        
+        Test that total volume in domain is as expected, based on questions
+        raised by Petar Milevski in May 2009.
+        
+        This test adds inflow at a known rate and verifies that the total 
+        terminal volume is as expected.
+        
+        """
+
+        verbose = False
+        
+
+        #----------------------------------------------------------------------
+        # Setup computational domain
+        #----------------------------------------------------------------------
+        finaltime = 200.0
+
+        length = 300.
+        width  = 20.
+        dx = dy = 5       # Resolution: of grid on both axes
+        
+
+        points, vertices, boundary = rectangular_cross(int(length/dx), 
+                                                       int(width/dy),
+                                                       len1=length, len2=width)
+
+
+        domain = anuga.Domain(points, vertices, boundary)   
+        domain.set_name('Inflow_volume_test')              # Output name
+                
+
+        #----------------------------------------------------------------------
+        # Setup initial conditions
+        #----------------------------------------------------------------------
+        slope = 0.0
+        def topography(x, y):
+            z=-x * slope
+            return z
+
+        domain.set_quantity('elevation', topography) # Use function for elevation
+        domain.set_quantity('friction', 0.0)         # Constant friction
+                
+        domain.set_quantity('stage',
+                            expression='elevation')  # Dry initially
+                            
+
+        #--------------------------------------------------------------
+        # Setup Inflow
+        #--------------------------------------------------------------
+
+        # Fixed Flowrate onto Area 
+        fixed_inflow = anuga.Inflow(domain,
+                              center=(10.0, 10.0),
+                              radius=5.00,
+                              rate=10.00)                               
+                            
+        domain.forcing_terms.append(fixed_inflow)                            
+        
+        #----------------------------------------------------------------------
+        # Setup boundary conditions
+        #----------------------------------------------------------------------
+
+        Br = anuga.Reflective_boundary(domain) # Solid reflective wall
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        
+        #----------------------------------------------------------------------
+        # Evolve system through time
+        #----------------------------------------------------------------------
+        ref_volume = 0.0
+        ys = 10.0  # Yieldstep
+        for t in domain.evolve(yieldstep=ys, finaltime=finaltime):
+        
+            # Check volume
+            assert num.allclose(domain.compute_total_volume(), ref_volume)
+        
+            if verbose :
+                print domain.timestepping_statistics()
+                print domain.volumetric_balance_statistics()
+                print 'reference volume', ref_volume
+            
+            
+            # Update reference volume
+            ref_volume += ys * fixed_inflow.rate
+
+
+        os.remove('Inflow_volume_test.sww')
+
+
+        
+    def test_volume_conservation_rain(self):
+        """test_volume_conservation
+        
+        Test that total volume in domain is as expected, based on questions
+        raised by Petar Milevski in May 2009.
+        
+        This test adds rain at a known rate and verifies that the total 
+        terminal volume is as expected.
+        
+        """
+
+        verbose = False
+        
+
+        #----------------------------------------------------------------------
+        # Setup computational domain
+        #----------------------------------------------------------------------
+        finaltime = 200.0
+
+        length = 300.
+        width  = 20.
+        dx = dy = 5       # Resolution: of grid on both axes
+        
+
+        points, vertices, boundary = anuga.rectangular_cross(int(length/dx), 
+                                                       int(width/dy),
+                                                       len1=length, len2=width)
+
+
+        domain = anuga.Domain(points, vertices, boundary)   
+        domain.set_name('Rain_volume_test')              # Output name
+                
+
+        #----------------------------------------------------------------------
+        # Setup initial conditions
+        #----------------------------------------------------------------------
+        slope = 0.0
+        def topography(x, y):
+            z=-x * slope
+            return z
+
+        domain.set_quantity('elevation', topography) # Use function for elevation
+        domain.set_quantity('friction', 0.0)         # Constant friction
+                
+        domain.set_quantity('stage',
+                            expression='elevation')  # Dry initially
+                            
+
+        #--------------------------------------------------------------
+        # Setup rain
+        #--------------------------------------------------------------
+
+        # Fixed rain onto small circular area 
+        fixed_rain = anuga.Rainfall(domain,
+                              center=(10.0, 10.0),
+                              radius=5.00,
+                              rate=10.00)   # 10 mm/s                            
+                            
+        domain.forcing_terms.append(fixed_rain)                            
+        
+        #----------------------------------------------------------------------
+        # Setup boundary conditions
+        #----------------------------------------------------------------------
+
+        Br = anuga.Reflective_boundary(domain) # Solid reflective wall
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        
+        #----------------------------------------------------------------------
+        # Evolve system through time
+        #----------------------------------------------------------------------
+        ref_volume = 0.0
+        ys = 10.0  # Yieldstep
+        for t in domain.evolve(yieldstep=ys, finaltime=finaltime):
+        
+            # Check volume
+            V = domain.compute_total_volume()
+            msg = 'V = %e, Ref = %e' % (V, ref_volume)
+            assert num.allclose(V, ref_volume), msg
+        
+            if verbose :
+                print domain.timestepping_statistics()
+                print domain.volumetric_balance_statistics()
+                print 'reference volume', ref_volume
+                print V
+            
+            
+            # Update reference volume.
+            # FIXME: Note that rate has now been redefined
+            # as m/s internally. This is a little confusing
+            # when it was specfied as mm/s.
+            
+            delta_V = fixed_rain.rate*fixed_rain.exchange_area
+            ref_volume += ys * delta_V
+
+        os.remove('Rain_volume_test.sww')
+
+    def Xtest_rain_conservation_and_runoff(self):
+        """test_rain_conservation_and_runoff
+        
+        Test that total volume in domain is as expected, based on questions
+        raised by Petar Milevski in May 2009.
+        
+        This test adds rain at a known rate and verifies that the total 
+        volume and outflows are as expected.
+        
+        """
+
+        # FIXME (Ole): Does not work yet. Investigate boundary flows
+        
+        verbose = True #False
+        
+
+        #----------------------------------------------------------------------
+        # Setup computational domain
+        #----------------------------------------------------------------------
+        finaltime = 500.0
+
+        length = 300.
+        width  = 20.
+        dx = dy = 5       # Resolution: of grid on both axes
+        
+
+        points, vertices, boundary = rectangular_cross(int(length/dx), 
+                                                       int(width/dy),
+                                                       len1=length, len2=width)
+
+
+        domain = Domain(points, vertices, boundary)   
+        domain.set_name('Rain_volume_runoff_test')         # Output name
+                
+
+        #----------------------------------------------------------------------
+        # Setup initial conditions
+        #----------------------------------------------------------------------
+        slope = 0.0
+        def topography(x, y):
+            z=-x * slope
+            return z
+
+        domain.set_quantity('elevation', topography) # Use function for elevation
+        domain.set_quantity('friction', 0.0)         # Constant friction
+                
+        domain.set_quantity('stage',
+                            expression='elevation')  # Dry initially
+                            
+
+        #--------------------------------------------------------------
+        # Setup rain
+        #--------------------------------------------------------------
+
+        # Fixed rain onto small circular area 
+        fixed_rain = Rainfall(domain,
+                              center=(10.0, 10.0),
+                              radius=5.00,
+                              rate=10.00)   # 10 mm/s                            
+                            
+        domain.forcing_terms.append(fixed_rain)                            
+        
+        #----------------------------------------------------------------------
+        # Setup boundary conditions
+        #----------------------------------------------------------------------
+
+        Br = anuga.Reflective_boundary(domain) # Solid reflective wall
+        Bt = anuga.Transmissive_stage_zero_momentum_boundary(domain)
+        Bd = anuga.Dirichlet_boundary([-10, 0, 0])
+        domain.set_boundary({'left': Bt, 'right': Bd, 'top': Bt, 'bottom': Bt})
+
+        
+        #----------------------------------------------------------------------
+        # Evolve system through time
+        #----------------------------------------------------------------------
+        ref_volume = 0.0
+        ys = 10.0  # Yieldstep
+        for t in domain.evolve(yieldstep=ys, finaltime=finaltime):
+        
+            # Check volume
+            V = domain.compute_total_volume()
+            msg = 'V = %e, Ref = %e' % (V, ref_volume)
+            #assert num.allclose(V, ref_volume) or V < ref_volume, msg
+        
+            if verbose:
+                print domain.timestepping_statistics()
+                print domain.volumetric_balance_statistics()
+                print 'reference volume', ref_volume
+                print V
+            
+            
+            # Update reference volume.
+            # FIXME: Note that rate has now been redefined
+            # as m/s internally. This is a little confusing
+            # when it was specfied as mm/s.
+            
+            delta_V = fixed_rain.rate*fixed_rain.exchange_area
+            ref_volume += ys * delta_V
+        
+            # Compute outflow at right hand downstream boundary
+            boundary_flows, inflow , outflow = domain.compute_boundary_flows()
+            net_outflow = outflow - inflow
+        
+            outflow = boundary_flows['right']
+            if verbose:
+                print 'Outflow', outflow
+                print 'Net outflow', net_outflow
+        
+            # Update reference volume
+            ref_volume += ys * outflow            
+
+
+
+#################################################################################
+
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_swb_conservation, 'test')
+    runner = unittest.TextTestRunner(verbosity=1)
+    runner.run(suite)
Index: /trunk/anuga_work/shallow_water_balanced_steve/test_swb_cross_sections.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/test_swb_cross_sections.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/test_swb_cross_sections.py	(revision 8245)
@@ -0,0 +1,319 @@
+#!/usr/bin/env python
+
+import unittest, os
+import os.path
+from math import pi, sqrt
+import tempfile
+
+import anuga
+
+from anuga.config import g, epsilon
+from anuga.config import netcdf_mode_r, netcdf_mode_w, netcdf_mode_a
+from anuga.utilities.numerical_tools import mean
+from anuga.geometry.polygon import is_inside_polygon
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+
+from anuga.utilities.system_tools import get_pathname_from_package
+from swb_domain import *
+
+import numpy as num
+
+# Get gateway to C implementation of flux function for direct testing
+from shallow_water_ext import flux_function_central as flux_function
+
+
+
+
+class Test_swb_clean(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_get_flow_through_cross_section_with_geo(self):
+        """test_get_flow_through_cross_section(self):
+
+        Test that the total flow through a cross section can be
+        correctly obtained at run-time from the ANUGA domain.
+
+        This test creates a flat bed with a known flow through it and tests
+        that the function correctly returns the expected flow.
+
+        The specifics are
+        e = -1 m
+        u = 2 m/s
+        h = 2 m
+        w = 3 m (width of channel)
+
+        q = u*h*w = 12 m^3/s
+
+        This run tries it with georeferencing and with elevation = -1
+        """
+
+        import time, os
+        from Scientific.IO.NetCDF import NetCDFFile
+        from mesh_factory import rectangular
+
+        # Create basic mesh (20m x 3m)
+        width = 3
+        length = 20
+        t_end = 1
+        points, vertices, boundary = rectangular(length, width, length, width)
+
+        # Create shallow water domain
+        domain = Domain(points, vertices, boundary,
+                        geo_reference=Geo_reference(56, 308500, 6189000))
+
+        domain.default_order = 2
+        domain.set_quantities_to_be_stored(None)
+
+        e = -1.0
+        w = 1.0
+        h = w-e
+        u = 2.0
+        uh = u*h
+
+        Br = anuga.Reflective_boundary(domain)     # Side walls
+        Bd = anuga.Dirichlet_boundary([w, uh, 0])  # 2 m/s across the 3 m inlet: 
+
+
+        # Initial conditions
+        domain.set_quantity('elevation', e)
+        domain.set_quantity('stage', w)
+        domain.set_quantity('xmomentum', uh)
+        domain.set_boundary({'left': Bd, 'right': Bd, 'top': Br, 'bottom': Br})
+
+        # Interpolation points down the middle
+        I = [[0, width/2.],
+             [length/2., width/2.],
+             [length, width/2.]]
+        interpolation_points = domain.geo_reference.get_absolute(I)
+
+        # Shortcuts to quantites
+        stage = domain.get_quantity('stage')
+        xmomentum = domain.get_quantity('xmomentum')
+        ymomentum = domain.get_quantity('ymomentum')
+
+        for t in domain.evolve(yieldstep=0.1, finaltime=t_end):
+            # Check that quantities are they should be in the interior
+            w_t = stage.get_values(interpolation_points)
+            uh_t = xmomentum.get_values(interpolation_points)
+            vh_t = ymomentum.get_values(interpolation_points)
+
+            assert num.allclose(w_t, w)
+            assert num.allclose(uh_t, uh)
+            assert num.allclose(vh_t, 0.0, atol=1.0e-6)
+
+            # Check flows through the middle
+            for i in range(5):
+                x = length/2. + i*0.23674563    # Arbitrary
+                cross_section = [[x, 0], [x, width]]
+
+                cross_section = domain.geo_reference.get_absolute(cross_section)
+                Q = domain.get_flow_through_cross_section(cross_section,
+                                                          verbose=False)
+
+                assert num.allclose(Q, uh*width)
+
+    def test_get_energy_through_cross_section_with_geo(self):
+        """test_get_energy_through_cross_section(self):
+
+        Test that the total and specific energy through a cross section can be
+        correctly obtained at run-time from the ANUGA domain.
+
+        This test creates a flat bed with a known flow through it and tests
+        that the function correctly returns the expected energies.
+
+        The specifics are
+        e = -1 m
+        u = 2 m/s
+        h = 2 m
+        w = 3 m (width of channel)
+
+        q = u*h*w = 12 m^3/s
+
+        This run tries it with georeferencing and with elevation = -1
+        """
+
+        import time, os
+        from Scientific.IO.NetCDF import NetCDFFile
+        from mesh_factory import rectangular
+
+        # Create basic mesh (20m x 3m)
+        width = 3
+        length = 20
+        t_end = 1
+        points, vertices, boundary = rectangular(length, width, length, width)
+
+        # Create shallow water domain
+        domain = Domain(points, vertices, boundary,
+                        geo_reference=Geo_reference(56, 308500, 6189000))
+
+        domain.default_order = 2
+        domain.set_quantities_to_be_stored(None)
+
+        e = -1.0
+        w = 1.0
+        h = w-e
+        u = 2.0
+        uh = u*h
+
+        Br = anuga.Reflective_boundary(domain)     # Side walls
+        Bd = anuga.Dirichlet_boundary([w, uh, 0])  # 2 m/s across the 3 m inlet:
+
+        # Initial conditions
+        domain.set_quantity('elevation', e)
+        domain.set_quantity('stage', w)
+        domain.set_quantity('xmomentum', uh)
+        domain.set_boundary({'left': Bd, 'right': Bd, 'top': Br, 'bottom': Br})
+
+        # Interpolation points down the middle
+        I = [[0, width/2.],
+             [length/2., width/2.],
+             [length, width/2.]]
+        interpolation_points = domain.geo_reference.get_absolute(I)
+
+        # Shortcuts to quantites
+        stage = domain.get_quantity('stage')
+        xmomentum = domain.get_quantity('xmomentum')
+        ymomentum = domain.get_quantity('ymomentum')
+
+        for t in domain.evolve(yieldstep=0.1, finaltime=t_end):
+            # Check that quantities are they should be in the interior
+            w_t = stage.get_values(interpolation_points)
+            uh_t = xmomentum.get_values(interpolation_points)
+            vh_t = ymomentum.get_values(interpolation_points)
+
+            assert num.allclose(w_t, w)
+            assert num.allclose(uh_t, uh)
+            assert num.allclose(vh_t, 0.0, atol=1.0e-6)
+
+            # Check energies through the middle
+            for i in range(5):
+                x = length/2. + i*0.23674563    # Arbitrary
+                cross_section = [[x, 0], [x, width]]
+
+                cross_section = domain.geo_reference.get_absolute(cross_section)
+                Es = domain.get_energy_through_cross_section(cross_section,
+                                                             kind='specific',
+                                                             verbose=False)
+
+                assert num.allclose(Es, h + 0.5*u*u/g)
+
+                Et = domain.get_energy_through_cross_section(cross_section,
+                                                             kind='total',
+                                                             verbose=False)
+                assert num.allclose(Et, w + 0.5*u*u/g)
+
+
+    def test_cross_section_class(self):
+        """test_cross_section_class(self):
+
+        Test that the total and specific energy through a cross section can be
+        correctly obtained at run-time from the ANUGA cross section class.
+
+        This test creates a flat bed with a known flow through it, creates a cross
+        section and tests that the correct flow and energies are calculated
+
+        The specifics are
+        e = -1 m
+        u = 2 m/s
+        h = 2 m
+        w = 3 m (width of channel)
+
+        q = u*h*w = 12 m^3/s
+
+        This run tries it with georeferencing and with elevation = -1
+        """
+
+        import time, os
+        from Scientific.IO.NetCDF import NetCDFFile
+        from mesh_factory import rectangular
+
+        # Create basic mesh (20m x 3m)
+        width = 3
+        length = 20
+        t_end = 1
+        points, vertices, boundary = rectangular(length, width, length, width)
+
+        # Create shallow water domain
+        domain = Domain(points, vertices, boundary,
+                        geo_reference=Geo_reference(56, 308500, 6189000))
+
+        domain.default_order = 2
+        domain.set_quantities_to_be_stored(None)
+
+        e = -1.0
+        w = 1.0
+        h = w-e
+        u = 2.0
+        uh = u*h
+
+        Br = anuga.Reflective_boundary(domain)     # Side walls
+        Bd = anuga.Dirichlet_boundary([w, uh, 0])  # 2 m/s across the 3 m inlet:
+
+        # Initial conditions
+        domain.set_quantity('elevation', e)
+        domain.set_quantity('stage', w)
+        domain.set_quantity('xmomentum', uh)
+        domain.set_boundary({'left': Bd, 'right': Bd, 'top': Br, 'bottom': Br})
+
+        # Interpolation points down the middle
+        I = [[0, width/2.],
+             [length/2., width/2.],
+             [length, width/2.]]
+        interpolation_points = domain.geo_reference.get_absolute(I)
+
+        # Shortcuts to quantites
+        stage = domain.get_quantity('stage')
+        xmomentum = domain.get_quantity('xmomentum')
+        ymomentum = domain.get_quantity('ymomentum')
+
+
+        # Create some cross sections
+        cross_sections = []
+        for i in range(5):
+            x = length/2. + i*0.23674563    # Arbitrary
+            polyline = [[x, 0], [x, width]]
+
+            polyline = domain.geo_reference.get_absolute(polyline)
+        
+            cross_sections.append(Cross_section(domain,polyline))
+
+
+ 
+        for t in domain.evolve(yieldstep=0.1, finaltime=t_end):
+            # Check that quantities are they should be in the interior
+            w_t = stage.get_values(interpolation_points)
+            uh_t = xmomentum.get_values(interpolation_points)
+            vh_t = ymomentum.get_values(interpolation_points)
+
+            assert num.allclose(w_t, w)
+            assert num.allclose(uh_t, uh)
+            assert num.allclose(vh_t, 0.0, atol=1.0e-6)
+
+
+            # Check flows and energies through the middle
+            for cross_section in cross_sections:
+                
+                Q = cross_section.get_flow_through_cross_section()
+
+                assert num.allclose(Q, uh*width)
+
+                Es = cross_section.get_energy_through_cross_section(kind='specific')
+
+                assert num.allclose(Es, h + 0.5*u*u/g)
+
+                Et = cross_section.get_energy_through_cross_section(kind='total')
+                
+                assert num.allclose(Et, w + 0.5*u*u/g)
+
+
+
+#################################################################################
+
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_swb_clean, 'test')
+    runner = unittest.TextTestRunner(verbosity=1)
+    runner.run(suite)
Index: /trunk/anuga_work/shallow_water_balanced_steve/test_swb_distribute.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/test_swb_distribute.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/test_swb_distribute.py	(revision 8245)
@@ -0,0 +1,406 @@
+#!/usr/bin/env python
+
+import unittest, os
+import os.path
+from math import pi, sqrt
+import tempfile
+
+from anuga.config import g, epsilon
+from anuga.config import netcdf_mode_r, netcdf_mode_w, netcdf_mode_a
+from anuga.utilities.numerical_tools import mean
+from anuga.geometry.polygon import is_inside_polygon
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+from anuga.abstract_2d_finite_volumes.quantity import Quantity
+from anuga.geospatial_data.geospatial_data import Geospatial_data
+from anuga.abstract_2d_finite_volumes.mesh_factory import rectangular_cross
+
+from anuga.utilities.system_tools import get_pathname_from_package
+from swb_domain import *
+
+import numpy as num
+
+# Get gateway to C implementation of flux function for direct testing
+from shallow_water_ext import flux_function_central as flux_function
+
+
+
+
+class Test_swb_distribute(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+
+
+
+    def test_first_order_extrapolator_const_z(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)
+        val0 = 2. + 2.0/3
+        val1 = 4. + 4.0/3
+        val2 = 8. + 2.0/3
+        val3 = 2. + 8.0/3
+
+        zl = zr = -3.75    # Assume constant bed (must be less than stage)
+        domain.set_quantity('elevation', zl*num.ones((4, 3), num.int)) #array default#
+        domain.set_quantity('stage', [[val0, val0-1, val0-2],
+                                      [val1, val1+1, val1],
+                                      [val2, val2-2, val2],
+                                      [val3-0.5, val3, val3]])
+
+        domain._order_ = 1
+        domain.distribute_to_vertices_and_edges()
+
+        #Check that centroid values were distributed to vertices
+        C = domain.quantities['stage'].centroid_values
+        for i in range(3):
+            assert num.allclose(domain.quantities['stage'].vertex_values[:,i],
+                                C)
+
+
+
+
+    def test_first_order_limiter_variable_z(self):
+        '''Check that first order limiter follows bed_slope'''
+
+        from anuga.config import epsilon
+
+        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)
+        val0 = 2.+2.0/3
+        val1 = 4.+4.0/3
+        val2 = 8.+2.0/3
+        val3 = 2.+8.0/3
+
+        domain.set_quantity('elevation', [[0,0,0], [6,0,0],
+                                          [6,6,6], [6,6,6]])
+        domain.set_quantity('stage', [[val0, val0, val0],
+                                      [val1, val1, val1],
+                                      [val2, val2, val2],
+                                      [val3, val3, val3]])
+
+        E = domain.quantities['elevation'].vertex_values
+        L = domain.quantities['stage'].vertex_values
+
+
+        #Check that some stages are not above elevation (within eps)
+        #- so that the limiter has something to work with
+        assert not num.alltrue(num.alltrue(num.greater_equal(L,E-epsilon)))
+
+        domain._order_ = 1
+        domain.distribute_to_vertices_and_edges()
+
+        #Check that all stages are above elevation (within eps)
+        assert num.alltrue(num.alltrue(num.greater_equal(L,E-epsilon)))
+
+
+
+
+
+    def test_distribute_basic(self):
+        #Using test data generated by abstract_2d_finite_volumes-2
+        #Assuming no friction and flat bed (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
+        vertices = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        domain = Domain(points, vertices)
+
+        val0 = 2.
+        val1 = 4.
+        val2 = 8.
+        val3 = 2.
+
+        domain.set_quantity('stage', [val0, val1, val2, val3],
+                            location='centroids')
+        L = domain.quantities['stage'].vertex_values
+
+        # First order
+        domain.set_default_order(1)
+        domain.distribute_to_vertices_and_edges()
+        
+        assert num.allclose(L[1], val1)
+
+        # Second order
+        domain.set_default_order(2)
+        domain.distribute_to_vertices_and_edges()
+
+        assert num.allclose(L[1], [0.0,   6.0,  6.0], atol=2.0e-3 )
+
+        assert num.allclose(val1, num.sum(L[1])/3)
+
+    def test_distribute_away_from_bed(self):
+        #Using test data generated by abstract_2d_finite_volumes-2
+        #Assuming no friction and flat bed (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
+        vertices = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        domain = Domain(points, vertices)
+        L = domain.quantities['stage'].vertex_values
+
+        def stage(x, y):
+            return x**2
+
+        domain.set_quantity('stage', stage, location='centroids')
+        domain.set_quantity('elevation',-3.0)
+
+        domain.quantities['stage'].compute_gradients()
+
+        a, b = domain.quantities['stage'].get_gradients()
+
+        assert num.allclose(a[1], 3.33333334)
+        assert num.allclose(b[1], 0.0)
+
+        domain.set_default_order(1)
+        domain.distribute_to_vertices_and_edges()
+
+        f1 = stage(4.0/3.0, 4.0/3.0)
+        assert num.allclose(L[1], f1)
+
+        domain.set_default_order(2)
+        domain.distribute_to_vertices_and_edges()
+
+
+        fv0 = f1 - a[1]*4.0/3.0 + b[1]*2.0/3.0
+        fv1 = f1 + a[1]*2.0/3.0 - b[1]*4.0/3.0
+        fv2 = f1 + a[1]*2.0/3.0 + b[1]*2.0/3.0
+
+        assert num.allclose(L[1], [fv0,fv1,fv2])
+
+        assert num.allclose(f1, num.sum(L[1])/3)
+
+    def test_distribute_away_from_bed1(self):
+        #Using test data generated by abstract_2d_finite_volumes-2
+        #Assuming no friction and flat bed (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
+        vertices = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        domain = Domain(points, vertices)
+        L = domain.quantities['stage'].vertex_values
+
+        def stage(x, y):
+            return x**4 + y**2
+
+        domain.set_quantity('stage', stage, location='centroids')
+        domain.set_quantity('elevation', -10.0)
+
+        domain.quantities['stage'].compute_gradients()
+        a, b = domain.quantities['stage'].get_gradients()
+        assert num.allclose(a[1], 25.18518519)
+        assert num.allclose(b[1], 3.33333333)
+
+        domain.set_default_order(1)
+        domain.distribute_to_vertices_and_edges()
+
+        f1 = stage(4.0/3.0, 4.0/3.0)
+        assert num.allclose(L[1], f1)
+
+        domain.set_default_order(2)
+        domain.distribute_to_vertices_and_edges()
+
+
+        fv0 = f1 - a[1]*4.0/3.0 + b[1]*2.0/3.0
+        fv1 = f1 + a[1]*2.0/3.0 - b[1]*4.0/3.0
+        fv2 = f1 + a[1]*2.0/3.0 + b[1]*2.0/3.0
+
+        
+        assert num.allclose(L[1], [ fv0, fv1, fv2]) or \
+               num.allclose(L[1], [ -9.23392657,  10.51787718,  13.5308642 ]) 
+
+
+    def test_distribute_near_bed(self):
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [1.0, 1.0]
+        d = [2.0, 0.0]
+        e = [2.0, 2.0]
+    
+
+        points = [a, b, c, d, e]
+
+        vertices = [[0,3,2], [0,2,1], [2,3,4], [1,2,4]]
+
+        domain = Domain(points, vertices)
+
+        # Set up for a gradient of (10,0) at mid triangle (bce)
+        def slope(x, y):
+            return 10*x
+
+        h = 0.1
+        def stage(x, y):
+            return slope(x, y) + h
+
+        domain.set_quantity('elevation', slope, location='centroids')
+        domain.set_quantity('stage', stage, location='centroids')
+
+
+
+        E = domain.quantities['elevation']
+        L = domain.quantities['stage']
+        Z = domain.quantities['elevation']
+
+        E_V = E.vertex_values
+        L_V = L.vertex_values
+
+        E_E = E.edge_values
+        L_E = L.edge_values        
+        E_C = E.centroid_values
+        L_C = L.centroid_values
+
+
+        domain.set_default_order(1)
+        domain.distribute_to_vertices_and_edges()
+
+        assert num.allclose(L_V,[[ 10.1,         10.1,         10.1       ],
+                                 [  3.43333333,   3.43333333,   3.43333333],
+                                 [ 16.76666667,  16.76666667,  16.76666667],
+                                 [ 10.1,         10.1,         10.1       ]])
+
+        assert num.allclose(E_V,[[ 10.,          10.,          10.,        ],
+                                 [  3.33333333,   3.33333333,   3.33333333],
+                                 [ 16.66666667,  16.66666667,  16.66666667],
+                                 [ 10.,          10.,          10.        ]])
+
+        domain.set_default_order(2)
+
+        # Setup the elevation to be pw linear (actually linear)
+        Z.extrapolate_second_order_and_limit_by_edge()
+
+
+        domain.distribute_to_vertices_and_edges()
+
+
+
+        assert num.allclose(L_V,[[  0.1,  20.1,  10.1],
+                                 [  0.1,  10.1,   0.1],
+                                 [ 10.1,  20.1,  20.1],
+                                 [  0.1,  10.1,  20.1]]) or \
+               num.allclose(L_V,[[  0.1,         20.1,         10.1,       ],
+                                 [  3.43333333,   3.43333333,   3.43333333],
+                                 [ 16.76666667,  16.76666667,  16.76666667],
+                                 [  0.1,         10.1,         20.1       ]])
+        
+
+        assert num.allclose(E_V,[[  0.,  20.,  10.],
+                                 [  0.,  10.,   0.],
+                                 [ 10.,  20.,  20.],
+                                 [  0.,  10.,  20.]]) or \
+               num.allclose(E_V,[[  0.,          20.,          10.,        ],
+                                 [  3.33333333,   3.33333333,   3.33333333],
+                                 [ 16.66666667,  16.66666667,  16.66666667],
+                                 [  0.,          10.,          20.        ]])
+
+                                 
+
+        
+
+    def test_second_order_distribute_real_data(self):
+        #Using test data generated by abstract_2d_finite_volumes-2
+        #Assuming no friction and flat bed (0.0)
+
+        a = [0.0, 0.0]
+        b = [0.0, 1.0/5]
+        c = [0.0, 2.0/5]
+        d = [1.0/5, 0.0]
+        e = [1.0/5, 1.0/5]
+        f = [1.0/5, 2.0/5]
+        g = [2.0/5, 2.0/5]
+
+        points = [a, b, c, d, e, f, g]
+        #             bae,     efb,     cbf,     feg
+        vertices = [[1,0,4], [4,5,1], [2,1,5], [5,4,6]]
+
+        domain = Domain(points, vertices)
+
+        def slope(x, y):
+            return -x/3
+
+        domain.set_quantity('elevation', slope)
+        domain.set_quantity('stage',
+                            [0.01298164, 0.00365611,
+                             0.01440365, -0.0381856437096],
+                            location='centroids')
+        domain.set_quantity('xmomentum',
+                            [0.00670439, 0.01263789,
+                             0.00647805, 0.0178180740668],
+                            location='centroids')
+        domain.set_quantity('ymomentum',
+                            [-7.23510980e-004, -6.30413883e-005,
+                             6.30413883e-005, 0.000200907255866],
+                            location='centroids')
+
+        E = domain.quantities['elevation'].vertex_values
+        L = domain.quantities['stage'].vertex_values
+        X = domain.quantities['xmomentum'].vertex_values
+        Y = domain.quantities['ymomentum'].vertex_values
+
+        domain.set_default_order(2)
+
+        domain.distribute_to_vertices_and_edges()
+
+
+        assert num.allclose(L[1,:],
+                            [-0.01434766, -0.01292565, 0.03824164], atol=1.0e-2)
+
+        assert num.allclose(X[1,:],
+                            [ 0.01702702, 0.01676034,  0.0057706 ], atol=1.0e-2)
+
+        assert num.allclose(Y[1,:],
+                            [-0.00041792,  0.00076771, -0.00039118], atol=1.0e-4)
+
+
+
+#################################################################################
+
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_swb_distribute, 'test')
+    runner = unittest.TextTestRunner(verbosity=1)
+    runner.run(suite)
Index: /trunk/anuga_work/shallow_water_balanced_steve/test_swb_domain_ext.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/test_swb_domain_ext.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/test_swb_domain_ext.py	(revision 8245)
@@ -0,0 +1,495 @@
+#!/usr/bin/env python
+
+import unittest, os
+import os.path
+from math import pi, sqrt
+
+from swb_domain import *
+
+from anuga.config import g
+
+import numpy as num
+
+# Get gateway to C implementation of flux function for direct testing
+from swb_domain_ext import flux_function_c
+from swb_domain_ext import gravity_c
+from swb_domain_ext import compute_fluxes_c
+
+
+class Test_swb_domain_ext(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_compute_fluxes0(self):
+        # Do a full triangle and check that fluxes cancel out for
+        # the constant stage case
+
+        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)
+        domain.set_quantity('stage', [[2,2,2], [2,2,2], [2,2,2], [2,2,2]])
+        domain.check_integrity()
+        domain.distribute_to_vertices_and_edges()
+
+        assert num.allclose(domain.neighbours,
+                            [[-1,1,-2], [2,3,0], [-3,-4,1],[1,-5,-6]])
+        assert num.allclose(domain.neighbour_edges,
+                            [[-1,2,-1], [2,0,1], [-1,-1,0],[1,-1,-1]])
+
+        edgeflux = num.zeros(3, num.float)
+        edgeflux0 = num.zeros(3, num.float)
+        edgeflux1 = num.zeros(3, num.float)
+        edgeflux2 = num.zeros(3, num.float)
+
+        # Flux across right edge of volume 1
+        normal = domain.get_normal(1, 0)
+        ql = domain.get_evolved_quantities(vol_id=1, edge=0)
+        qr = domain.get_evolved_quantities(vol_id=2, edge=2)
+
+        #print ql
+        #print qr
+        local_max_speed = flux_function_c(normal, ql, qr, edgeflux0, g)
+
+        # Check that flux seen from other triangles is inverse
+        (ql, qr) = (qr, ql)
+        normal = domain.get_normal(2, 2)
+        local_max_speed = flux_function_c(normal, ql, qr, edgeflux, g)
+
+        assert num.allclose(edgeflux0 + edgeflux, 0.)
+
+        # Flux across upper edge of volume 1
+        normal = domain.get_normal(1, 1)
+        ql = domain.get_evolved_quantities(vol_id=1, edge=1)
+        qr = domain.get_evolved_quantities(vol_id=3, edge=0)
+        #print ql
+        #print qr
+        local_max_speed = flux_function_c(normal, ql, qr, edgeflux1, g)
+
+        # Check that flux seen from other triangles is inverse
+        (ql, qr) = (qr, ql)
+        normal = domain.get_normal(3, 0)
+        local_max_speed = flux_function_c(normal, ql, qr, edgeflux, g)
+
+        assert num.allclose(edgeflux1 + edgeflux, 0.)
+
+        # Flux across lower left hypotenuse of volume 1
+        normal = domain.get_normal(1, 2)
+        ql = domain.get_evolved_quantities(vol_id=1, edge=2)
+        qr = domain.get_evolved_quantities(vol_id=0, edge=1)
+        #print ql
+        #print qr
+        local_max_speed = flux_function_c(normal, ql, qr, edgeflux2, g)
+
+        # Check that flux seen from other triangles is inverse
+        (ql, qr) = (qr, ql)
+        normal = domain.get_normal(0, 1)
+        max_speed = flux_function_c(normal, ql, qr, edgeflux, g)
+        assert num.allclose(edgeflux2 + edgeflux, 0.)
+
+        # Scale by edgelengths, add up anc check that total flux is zero
+        e0 = domain.edgelengths[1, 0]
+        e1 = domain.edgelengths[1, 1]
+        e2 = domain.edgelengths[1, 2]
+
+        assert num.allclose(e0*edgeflux0 + e1*edgeflux1 + e2*edgeflux2, 0.)
+
+        # Now check that compute_flux yields zeros as well
+        w  = domain.quantities['stage']
+        uh = domain.quantities['xmomentum']
+        vh = domain.quantities['ymomentum']
+        h  = domain.quantities['height']
+        z  = domain.quantities['elevation']
+        u  = domain.quantities['xvelocity']
+        v  = domain.quantities['yvelocity']
+        timestep = compute_fluxes_c(2.0,domain,w,uh,vh,h,z,u,v)
+
+        assert num.allclose(timestep,  0.1064794275)
+
+
+        for name in ['stage', 'xmomentum', 'ymomentum']:
+            assert num.allclose(domain.quantities[name].explicit_update[1], 0.0)
+
+    def test_compute_fluxes1(self):
+        #Use values from previous version
+        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)
+        val0 = 2. + 2.0/3
+        val1 = 4. + 4.0/3
+        val2 = 8. + 2.0/3
+        val3 = 2. + 8.0/3
+
+        domain.set_quantity('stage', [[val0, val0, val0], [val1, val1, val1],
+                                      [val2, val2, val2], [val3, val3, val3]])
+        domain.check_integrity()
+        domain.set_default_order(1)
+        domain.distribute_to_vertices_and_edges()
+
+
+        w  = domain.quantities['stage']
+        uh = domain.quantities['xmomentum']
+        vh = domain.quantities['ymomentum']
+        h  = domain.quantities['height']
+        z  = domain.quantities['elevation']
+        u  = domain.quantities['xvelocity']
+        v  = domain.quantities['yvelocity']
+
+
+        edgeflux = num.zeros(3, num.float)
+        edgeflux0 = num.zeros(3, num.float)
+        edgeflux1 = num.zeros(3, num.float)
+        edgeflux2 = num.zeros(3, num.float)
+
+
+        # Flux across right edge of volume 1
+        normal = domain.get_normal(1, 0)    # Get normal 0 of triangle 1
+        assert num.allclose(normal, [1, 0])
+
+  
+        ql = domain.get_evolved_quantities(vol_id=1, edge=0)
+        #print ql, val1
+        assert num.allclose(ql, [val1, 0, 0, val1, 0, 0, 0])
+
+        qr = domain.get_evolved_quantities(vol_id=2, edge=2)
+        assert num.allclose(qr, [val2, 0, 0, val2, 0, 0, 0])
+
+        local_max_speed = flux_function_c(normal, ql, qr, edgeflux0, g)
+
+        #print edgeflux0
+        #print local_max_speed
+        
+        # Flux across edge in the east direction (as per normal vector)
+        assert num.allclose(edgeflux0, [-15.3598804, 253.71111111, 0.])
+        assert num.allclose(local_max_speed, 9.21592824046)
+
+        #Flux across edge in the west direction (opposite sign for xmomentum)
+        normal_opposite = domain.get_normal(2, 2)   # Get normal 2 of triangle 2
+        assert num.allclose(normal_opposite, [-1, 0])
+
+        max_speed = flux_function_c(normal_opposite, ql, qr, edgeflux, g)
+        assert num.allclose(edgeflux, [-15.3598804, -253.71111111, 0.])
+
+        #Flux across upper edge of volume 1
+        normal = domain.get_normal(1, 1)
+        ql = domain.get_evolved_quantities(vol_id=1, edge=1)
+        qr = domain.get_evolved_quantities(vol_id=3, edge=0)
+        max_speed = flux_function_c(normal, ql, qr, edgeflux1, g)
+
+        assert num.allclose(edgeflux1, [2.4098563, 0., 123.04444444])
+        assert num.allclose(max_speed, 7.22956891292)
+
+        #Flux across lower left hypotenuse of volume 1
+        normal = domain.get_normal(1, 2)
+        ql = domain.get_evolved_quantities(vol_id=1, edge=2)
+        qr = domain.get_evolved_quantities(vol_id=0, edge=1)
+        max_speed = flux_function_c(normal, ql, qr, edgeflux2, g)
+
+        assert num.allclose(edgeflux2, [9.63942522, -61.59685738, -61.59685738])
+        assert num.allclose(max_speed, 7.22956891292)
+
+        #Scale, add up and check that compute_fluxes is correct for vol 1
+        e0 = domain.edgelengths[1, 0]
+        e1 = domain.edgelengths[1, 1]
+        e2 = domain.edgelengths[1, 2]
+
+        total_flux = -(e0*edgeflux0 +
+                       e1*edgeflux1 +
+                       e2*edgeflux2) / domain.areas[1]
+
+        assert num.allclose(total_flux, [-0.68218178, -166.6, -35.93333333])
+
+
+        timestep = compute_fluxes_c(2.0,domain,w,uh,vh,h,z,u,v)
+        assert num.allclose(timestep, 0.0511510624314)
+
+        for i, name in enumerate(['stage', 'xmomentum', 'ymomentum']):
+            assert num.allclose(total_flux[i],
+                                domain.quantities[name].explicit_update[1])
+
+
+        assert num.allclose(domain.quantities['stage'].explicit_update,
+                            [0., -0.68218178, -111.77316251, -35.68522449])
+        assert num.allclose(domain.quantities['xmomentum'].explicit_update,
+                            [-69.68888889, -166.6, 69.68888889, 0])
+        assert num.allclose(domain.quantities['ymomentum'].explicit_update,
+                            [-69.68888889, -35.93333333, 0., 69.68888889])
+
+    def test_compute_fluxes2(self):
+        #Random values, incl momentum
+        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)
+        domain.set_default_order(1)
+
+        w  = domain.quantities['stage']
+        uh = domain.quantities['xmomentum']
+        vh = domain.quantities['ymomentum']
+        h  = domain.quantities['height']
+        z  = domain.quantities['elevation']
+        u  = domain.quantities['xvelocity']
+        v  = domain.quantities['yvelocity']
+
+        zl = 10    # Assume flat bed
+        val0 = zl + 2. + 2.0/3
+        val1 = zl + 4. + 4.0/3
+        val2 = zl + 8. + 2.0/3
+        val3 = zl + 2. + 8.0/3
+
+
+        edgeflux = num.zeros(3, num.float)
+        edgeflux0 = num.zeros(3, num.float)
+        edgeflux1 = num.zeros(3, num.float)
+        edgeflux2 = num.zeros(3, num.float)
+
+        domain.set_quantity('elevation', zl*num.ones((4, 3), num.int)) #array default#
+
+        domain.set_quantity('stage', [[val0, val0-1, val0-2],
+                                      [val1, val1+1, val1],
+                                      [val2, val2-2, val2],
+                                      [val3-0.5, val3, val3]])
+
+        domain.set_quantity('xmomentum',
+                            [[1,2,3], [3,4,5], [1,-1,0], [0,-2,2]])
+
+        domain.set_quantity('ymomentum',
+                            [[1,-1,0], [0,-3,2], [0,1,0], [-1,2,2]])
+
+        domain.check_integrity()
+        domain.distribute_to_vertices_and_edges()
+
+        
+        # Flux across right edge of volume 1
+        normal = domain.get_normal(1, 0)
+        ql = domain.get_evolved_quantities(vol_id=1, edge=0)
+        qr = domain.get_evolved_quantities(vol_id=2, edge=2)
+        max_speed = flux_function_c(normal, ql, qr, edgeflux0, g)
+
+        # Flux across upper edge of volume 1
+        normal = domain.get_normal(1, 1)
+        ql = domain.get_evolved_quantities(vol_id=1, edge=1)
+        qr = domain.get_evolved_quantities(vol_id=3, edge=0)
+        max_speed = flux_function_c(normal, ql, qr, edgeflux1, g)
+
+        # Flux across lower left hypotenuse of volume 1
+        normal = domain.get_normal(1, 2)
+        ql = domain.get_evolved_quantities(vol_id=1, edge=2)
+        qr = domain.get_evolved_quantities(vol_id=0, edge=1)
+        max_speed = flux_function_c(normal, ql, qr, edgeflux2, g)
+
+        # Scale, add up and check that compute_fluxes is correct for vol 1
+        e0 = domain.edgelengths[1, 0]
+        e1 = domain.edgelengths[1, 1]
+        e2 = domain.edgelengths[1, 2]
+
+        total_flux = -(e0*edgeflux0 +
+                       e1*edgeflux1 +
+                       e2*edgeflux2) / domain.areas[1]
+
+        timestep = compute_fluxes_c(2.0,domain,w,uh,vh,h,z,u,v)
+        assert num.allclose(timestep, 0.0529903533177)
+
+        for i, name in enumerate(['stage', 'xmomentum', 'ymomentum']):
+            assert num.allclose(total_flux[i],
+                                domain.quantities[name].explicit_update[1])
+
+    # FIXME (Ole): Need test like this for fluxes in very shallow water.
+    def test_compute_fluxes3(self):
+        #Random values, incl momentum
+        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)
+        domain.set_default_order(1)
+
+
+        w  = domain.quantities['stage']
+        uh = domain.quantities['xmomentum']
+        vh = domain.quantities['ymomentum']
+        h  = domain.quantities['height']
+        z  = domain.quantities['elevation']
+        u  = domain.quantities['xvelocity']
+        v  = domain.quantities['yvelocity']
+        
+        val0 = 2.+2.0/3
+        val1 = 4.+4.0/3
+        val2 = 8.+2.0/3
+        val3 = 2.+8.0/3
+
+        zl = -3.75    # Assume constant bed (must be less than stage)
+        domain.set_quantity('elevation', zl*num.ones((4, 3), num.int)) #array default#
+
+        edgeflux = num.zeros(3, num.float)
+        edgeflux0 = num.zeros(3, num.float)
+        edgeflux1 = num.zeros(3, num.float)
+        edgeflux2 = num.zeros(3, num.float)
+
+
+        domain.set_quantity('stage', [[val0, val0-1, val0-2],
+                                      [val1, val1+1, val1],
+                                      [val2, val2-2, val2],
+                                      [val3-0.5, val3, val3]])
+
+        domain.set_quantity('xmomentum',
+                            [[1,2,3], [3,4,5], [1,-1,0], [0,-2,2]])
+
+        domain.set_quantity('ymomentum',
+                            [[1,-1,0], [0,-3,2], [0,1,0], [-1,2,2]])
+
+        domain.check_integrity()
+        domain.distribute_to_vertices_and_edges()        
+
+        # Flux across right edge of volume 1
+        normal = domain.get_normal(1, 0)
+        ql = domain.get_evolved_quantities(vol_id=1, edge=0)
+        qr = domain.get_evolved_quantities(vol_id=2, edge=2)
+        max_speed = flux_function_c(normal, ql, qr, edgeflux0, g)
+
+        #print max_speed, edgeflux0
+        assert num.allclose(edgeflux0, [-10.51926294, 577.81462335, -3.64772873], rtol=1.0e-2)
+
+        # Flux across upper edge of volume 1
+        normal = domain.get_normal(1, 1)
+        ql = domain.get_evolved_quantities(vol_id=1, edge=1)
+        qr = domain.get_evolved_quantities(vol_id=3, edge=0)
+        max_speed = flux_function_c(normal, ql, qr, edgeflux1, g)
+
+        #print max_speed, edgeflux1
+        assert num.allclose(edgeflux1, [ 5.93945967, 19.14204647,  377.48851296], rtol=1.0e-2)
+        
+        # Flux across lower left hypotenuse of volume 1
+        normal = domain.get_normal(1, 2)
+        ql = domain.get_evolved_quantities(vol_id=1, edge=2)
+        qr = domain.get_evolved_quantities(vol_id=0, edge=1)
+        max_speed = flux_function_c(normal, ql, qr, edgeflux2, g)
+
+        #print max_speed, edgeflux2
+        assert num.allclose(edgeflux2, [17.21047971, -192.90578267, -203.05771337], rtol=1.0e-2)
+
+        
+        # Scale, add up and check that compute_fluxes is correct for vol 1
+        e0 = domain.edgelengths[1, 0]
+        e1 = domain.edgelengths[1, 1]
+        e2 = domain.edgelengths[1, 2]
+
+        total_flux = -(e0*edgeflux0 +
+                       e1*edgeflux1 +
+                       e2*edgeflux2) / domain.areas[1]
+
+        timestep = compute_fluxes_c(100.0,domain,w,uh,vh,h,z,u,v)
+
+        assert num.allclose(timestep, 0.0438142267244, rtol=1.0e-2)
+
+        for i, name in enumerate(['stage', 'xmomentum', 'ymomentum']):
+            assert num.allclose(total_flux[i],
+                                domain.quantities[name].explicit_update[1])
+
+
+
+    def test_compute_fluxes4(self):
+        #Random values, incl momentum
+        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)
+        domain.set_default_order(1)
+
+
+        w  = domain.quantities['stage']
+        uh = domain.quantities['xmomentum']
+        vh = domain.quantities['ymomentum']
+        h  = domain.quantities['height']
+        z  = domain.quantities['elevation']
+        u  = domain.quantities['xvelocity']
+        v  = domain.quantities['yvelocity']
+        
+        val0 = 2.+2.0/3
+        val1 = 4.+4.0/3
+        val2 = 8.+2.0/3
+        val3 = 2.+8.0/3
+
+        zl = -3.75    # Assume constant bed (must be less than stage)
+        domain.set_quantity('elevation', [0.0, -2.0, 0.0 ,0.0], location='centroids') 
+
+        edgeflux = num.zeros(3, num.float)
+        edgeflux0 = num.zeros(3, num.float)
+        edgeflux1 = num.zeros(3, num.float)
+        edgeflux2 = num.zeros(3, num.float)
+
+
+        domain.set_quantity('stage', -1.0)
+
+        domain.set_quantity('xmomentum',0.0)
+
+        domain.set_quantity('ymomentum',0.0)
+
+        domain.check_integrity()
+        domain.distribute_to_vertices_and_edges()        
+
+
+        #print w.edge_values
+        #print u.edge_values
+        #print v.edge_values
+        #print h.edge_values
+        #print z.edge_values
+
+
+        domain.compute_fluxes()
+
+        #for i, name in enumerate(['stage', 'xmomentum', 'ymomentum']):
+            #print domain.quantities[name].explicit_update[1]
+            #assert num.allclose(total_flux[i],
+            #                    domain.quantities[name].explicit_update[1])
+
+
+#################################################################################
+
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_swb_domain_ext, 'test')
+    runner = unittest.TextTestRunner(verbosity=1)
+    runner.run(suite)
Index: /trunk/anuga_work/shallow_water_balanced_steve/test_swb_forcing_terms.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/test_swb_forcing_terms.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/test_swb_forcing_terms.py	(revision 8245)
@@ -0,0 +1,1602 @@
+#!/usr/bin/env python
+
+import unittest, os
+import os.path
+from math import pi, sqrt
+import tempfile
+import anuga
+
+from anuga.config import g, epsilon
+from anuga.config import netcdf_mode_r, netcdf_mode_w, netcdf_mode_a
+from anuga.utilities.numerical_tools import mean, ensure_numeric
+from anuga.geometry.polygon import is_inside_polygon
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+from anuga.abstract_2d_finite_volumes.quantity import Quantity
+from anuga.geospatial_data.geospatial_data import Geospatial_data
+from anuga.abstract_2d_finite_volumes.mesh_factory import rectangular_cross
+
+from anuga.utilities.system_tools import get_pathname_from_package
+from swb_domain import *
+
+import numpy as num
+
+# Get gateway to C implementation of flux function for direct testing
+from shallow_water_ext import flux_function_central as flux_function
+
+
+# Variable windfield implemented using functions
+def speed(t, x, y):
+    """Large speeds halfway between center and edges
+
+    Low speeds at center and edges
+    """
+
+    from math import exp, cos, pi
+
+    x = num.array(x)
+    y = num.array(y)
+
+    N = len(x)
+    s = 0*x  #New array
+
+    for k in range(N):
+        r = num.sqrt(x[k]**2 + y[k]**2)
+        factor = exp(-(r-0.15)**2)
+        s[k] = 4000 * factor * (cos(t*2*pi/150) + 2)
+
+    return s
+
+def scalar_func(t, x, y):
+    """Function that returns a scalar.
+
+    Used to test error message when numeric array is expected
+    """
+
+    return 17.7
+
+def scalar_func_list(t, x, y):
+    """Function that returns a scalar.
+
+    Used to test error message when numeric array is expected
+    """
+
+    return [17.7]
+
+
+def angle(t, x, y):
+    """Rotating field
+    """
+    from math import atan, pi
+
+    x = num.array(x)
+    y = num.array(y)
+
+    N = len(x)
+    a = 0 * x    # New array
+
+    for k in range(N):
+        r = num.sqrt(x[k]**2 + y[k]**2)
+
+        angle = atan(y[k]/x[k])
+
+        if x[k] < 0:
+            angle += pi
+
+        # Take normal direction
+        angle -= pi/2
+
+        # Ensure positive radians
+        if angle < 0:
+            angle += 2*pi
+
+        a[k] = angle/pi*180
+
+    return a
+
+
+###############################################################################
+
+class Test_swb_forcing_terms(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_gravity(self):
+        #Assuming no friction
+
+        from anuga.config import g
+
+        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)
+
+        #Set up for a gradient of (3,0) at mid triangle (bce)
+        def slope(x, y):
+            return 3*x
+
+        h = 0.1
+        def stage(x, y):
+            return slope(x, y) + h
+
+        domain.set_quantity('elevation', slope)
+        domain.set_quantity('stage', stage)
+
+        for name in domain.conserved_quantities:
+            assert num.allclose(domain.quantities[name].explicit_update, 0)
+            assert num.allclose(domain.quantities[name].semi_implicit_update, 0)
+
+        domain.compute_forcing_terms()
+
+        assert num.allclose(domain.quantities['stage'].explicit_update, 0)
+        assert num.allclose(domain.quantities['xmomentum'].explicit_update,
+                            -g*h*3)
+        assert num.allclose(domain.quantities['ymomentum'].explicit_update, 0)
+
+    def test_manning_friction(self):
+        from anuga.config import g
+
+        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)
+
+        #Set up for a gradient of (3,0) at mid triangle (bce)
+        def slope(x, y):
+            return 3*x
+
+        h = 0.1
+        def stage(x, y):
+            return slope(x, y) + h
+
+        eta = 0.07
+        domain.set_quantity('elevation', slope)
+        domain.set_quantity('stage', stage)
+        domain.set_quantity('friction', eta)
+
+        for name in domain.conserved_quantities:
+            assert num.allclose(domain.quantities[name].explicit_update, 0)
+            assert num.allclose(domain.quantities[name].semi_implicit_update, 0)
+
+        domain.compute_forcing_terms()
+
+        assert num.allclose(domain.quantities['stage'].explicit_update, 0)
+        assert num.allclose(domain.quantities['xmomentum'].explicit_update,
+                            -g*h*3)
+        assert num.allclose(domain.quantities['ymomentum'].explicit_update, 0)
+
+        assert num.allclose(domain.quantities['stage'].semi_implicit_update, 0)
+        assert num.allclose(domain.quantities['xmomentum'].semi_implicit_update,
+                            0)
+        assert num.allclose(domain.quantities['ymomentum'].semi_implicit_update,
+                            0)
+
+        #Create some momentum for friction to work with
+        domain.set_quantity('xmomentum', 1)
+        dz = sqrt(10.0)
+        S = -g*eta**2 *dz / h**(7.0/3) 
+
+        domain.compute_forcing_terms()
+        assert num.allclose(domain.quantities['stage'].semi_implicit_update, 0)
+        assert num.allclose(domain.quantities['xmomentum'].semi_implicit_update,
+                            S)
+        assert num.allclose(domain.quantities['ymomentum'].semi_implicit_update,
+                            0)
+
+        #A more complex example
+        domain.quantities['stage'].semi_implicit_update[:] = 0.0
+        domain.quantities['xmomentum'].semi_implicit_update[:] = 0.0
+        domain.quantities['ymomentum'].semi_implicit_update[:] = 0.0
+
+        domain.set_quantity('xmomentum', 3)
+        domain.set_quantity('ymomentum', 4)
+
+        S = -g*eta**2*5*dz / h**(7.0/3) 
+
+        domain.compute_forcing_terms()
+
+        assert num.allclose(domain.quantities['stage'].semi_implicit_update, 0)
+        assert num.allclose(domain.quantities['xmomentum'].semi_implicit_update,
+                            3*S)
+        assert num.allclose(domain.quantities['ymomentum'].semi_implicit_update,
+                            4*S)
+
+
+
+    def test_manning_friction_not_sloped(self):
+        from anuga.config import g
+
+        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)
+
+        #Turn old mannings function on
+        domain.set_sloped_mannings_function(False)
+
+        #Set up for a gradient of (3,0) at mid triangle (bce)
+        def slope(x, y):
+            return 3*x
+
+        h = 0.1
+        def stage(x, y):
+            return slope(x, y) + h
+
+        eta = 0.07
+        domain.set_quantity('elevation', slope)
+        domain.set_quantity('stage', stage)
+        domain.set_quantity('friction', eta)
+
+        for name in domain.conserved_quantities:
+            assert num.allclose(domain.quantities[name].explicit_update, 0)
+            assert num.allclose(domain.quantities[name].semi_implicit_update, 0)
+
+        domain.compute_forcing_terms()
+
+        assert num.allclose(domain.quantities['stage'].explicit_update, 0)
+        assert num.allclose(domain.quantities['xmomentum'].explicit_update,
+                            -g*h*3)
+        assert num.allclose(domain.quantities['ymomentum'].explicit_update, 0)
+
+        assert num.allclose(domain.quantities['stage'].semi_implicit_update, 0)
+        assert num.allclose(domain.quantities['xmomentum'].semi_implicit_update,
+                            0)
+        assert num.allclose(domain.quantities['ymomentum'].semi_implicit_update,
+                            0)
+
+        #Create some momentum for friction to work with
+        domain.set_quantity('xmomentum', 1)
+        S = -g*eta**2 / h**(7.0/3)
+
+        domain.compute_forcing_terms()
+        assert num.allclose(domain.quantities['stage'].semi_implicit_update, 0)
+        assert num.allclose(domain.quantities['xmomentum'].semi_implicit_update,
+                            S)
+        assert num.allclose(domain.quantities['ymomentum'].semi_implicit_update,
+                            0)
+
+        #A more complex example
+        domain.quantities['stage'].semi_implicit_update[:] = 0.0
+        domain.quantities['xmomentum'].semi_implicit_update[:] = 0.0
+        domain.quantities['ymomentum'].semi_implicit_update[:] = 0.0
+
+        domain.set_quantity('xmomentum', 3)
+        domain.set_quantity('ymomentum', 4)
+
+        S = -g*eta**2*5 / h**(7.0/3)
+
+        domain.compute_forcing_terms()
+
+        assert num.allclose(domain.quantities['stage'].semi_implicit_update, 0)
+        assert num.allclose(domain.quantities['xmomentum'].semi_implicit_update,
+                            3*S)
+        assert num.allclose(domain.quantities['ymomentum'].semi_implicit_update,
+                            4*S)
+
+
+    def test_manning_friction_sloped(self):
+        from anuga.config import g
+
+        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)
+
+        # Use the new function which takes into account the extra
+        # wetted area due to slope of bed
+        domain.set_sloped_mannings_function(True)
+        
+        #Set up for a gradient of (3,0) at mid triangle (bce)
+        def slope(x, y):
+            return 3*x
+
+        h = 0.1
+        def stage(x, y):
+            return slope(x, y) + h
+
+        eta = 0.07
+        domain.set_quantity('elevation', slope)
+        domain.set_quantity('stage', stage)
+        domain.set_quantity('friction', eta)
+
+        for name in domain.conserved_quantities:
+            assert num.allclose(domain.quantities[name].explicit_update, 0)
+            assert num.allclose(domain.quantities[name].semi_implicit_update, 0)
+
+        domain.compute_forcing_terms()
+
+        assert num.allclose(domain.quantities['stage'].explicit_update, 0)
+        assert num.allclose(domain.quantities['xmomentum'].explicit_update,
+                            -g*h*3)
+        assert num.allclose(domain.quantities['ymomentum'].explicit_update, 0)
+
+        assert num.allclose(domain.quantities['stage'].semi_implicit_update, 0)
+        assert num.allclose(domain.quantities['xmomentum'].semi_implicit_update,
+                            0)
+        assert num.allclose(domain.quantities['ymomentum'].semi_implicit_update,
+                            0)
+
+        #Create some momentum for friction to work with
+        domain.set_quantity('xmomentum', 1)
+        S = -g*eta**2 / h**(7.0/3) * sqrt(10)
+
+        domain.compute_forcing_terms()
+        assert num.allclose(domain.quantities['stage'].semi_implicit_update, 0)
+        assert num.allclose(domain.quantities['xmomentum'].semi_implicit_update,
+                            S)
+        assert num.allclose(domain.quantities['ymomentum'].semi_implicit_update,
+                            0)
+
+        #A more complex example
+        domain.quantities['stage'].semi_implicit_update[:] = 0.0
+        domain.quantities['xmomentum'].semi_implicit_update[:] = 0.0
+        domain.quantities['ymomentum'].semi_implicit_update[:] = 0.0
+
+        domain.set_quantity('xmomentum', 3)
+        domain.set_quantity('ymomentum', 4)
+
+        S = -g*eta**2*5 / h**(7.0/3) * sqrt(10.0)
+
+        domain.compute_forcing_terms()
+
+        assert num.allclose(domain.quantities['stage'].semi_implicit_update, 0)
+        assert num.allclose(domain.quantities['xmomentum'].semi_implicit_update,
+                            3*S)
+        assert num.allclose(domain.quantities['ymomentum'].semi_implicit_update,
+                            4*S)
+        
+    def test_constant_wind_stress(self):
+        from anuga.config import rho_a, rho_w, eta_w
+        from math import pi, cos, sin
+
+        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 = anuga.Domain(points, vertices)
+
+        #Flat surface with 1m of water
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', 1.0)
+        domain.set_quantity('friction', 0)
+
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'exterior': Br})
+
+        #Setup only one forcing term, constant wind stress
+        s = 100
+        phi = 135
+        domain.forcing_terms = []
+        domain.forcing_terms.append(anuga.Wind_stress(s, phi))
+
+        domain.compute_forcing_terms()
+
+        const = eta_w*rho_a / rho_w
+
+        #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 * num.sqrt(u**2 + v**2)
+
+        assert num.allclose(domain.quantities['stage'].explicit_update, 0)
+        assert num.allclose(domain.quantities['xmomentum'].explicit_update, S*u)
+        assert num.allclose(domain.quantities['ymomentum'].explicit_update, S*v)
+
+    def test_variable_wind_stress(self):
+        from anuga.config import rho_a, rho_w, eta_w
+        from math import pi, cos, sin
+
+        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)
+
+        #Flat surface with 1m of water
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', 1.0)
+        domain.set_quantity('friction', 0)
+
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'exterior': Br})
+
+        domain.time = 5.54    # Take a random time (not zero)
+
+        #Setup only one forcing term, constant wind stress
+        s = 100
+        phi = 135
+        domain.forcing_terms = []
+        domain.forcing_terms.append(anuga.Wind_stress(s=speed, phi=angle))
+
+        domain.compute_forcing_terms()
+
+        #Compute reference solution
+        const = eta_w*rho_a / rho_w
+
+        N = len(domain)    # number_of_triangles
+
+        xc = domain.get_centroid_coordinates()
+        t = domain.time
+
+        x = xc[:,0]
+        y = xc[:,1]
+        s_vec = speed(t,x,y)
+        phi_vec = angle(t,x,y)
+
+        for k in range(N):
+            # Convert to radians
+            phi = phi_vec[k]*pi / 180
+            s = s_vec[k]
+
+            # Compute velocity vector (u, v)
+            u = s*cos(phi)
+            v = s*sin(phi)
+
+            # Compute wind stress
+            S = const * num.sqrt(u**2 + v**2)
+
+            assert num.allclose(domain.quantities['stage'].explicit_update[k],
+                                0)
+            assert num.allclose(domain.quantities['xmomentum'].\
+                                     explicit_update[k],
+                                S*u)
+            assert num.allclose(domain.quantities['ymomentum'].\
+                                     explicit_update[k],
+                                S*v)
+
+    def test_windfield_from_file(self):
+        import time
+        from anuga.config import rho_a, rho_w, eta_w
+        from math import pi, cos, sin
+        from anuga.config import time_format
+        from anuga.abstract_2d_finite_volumes.util import file_function
+
+        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)
+
+        # Flat surface with 1m of water
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', 1.0)
+        domain.set_quantity('friction', 0)
+
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'exterior': Br})
+
+        domain.time = 7    # Take a time that is represented in file (not zero)
+
+        # Write wind stress file (ensure that domain.time is covered)
+        # Take x=1 and y=0
+        filename = 'test_windstress_from_file'
+        start = time.mktime(time.strptime('2000', '%Y'))
+        fid = open(filename + '.txt', 'w')
+        dt = 1    # One second interval
+        t = 0.0
+        while t <= 10.0:
+            t_string = time.strftime(time_format, time.gmtime(t+start))
+
+            fid.write('%s, %f %f\n' %
+                      (t_string, speed(t,[1],[0])[0], angle(t,[1],[0])[0]))
+            t += dt
+
+        fid.close()
+
+        anuga.timefile2netcdf(filename+'.txt', filename+'.tms')
+        os.remove(filename + '.txt')
+
+        # Setup wind stress
+        F = file_function(filename + '.tms',
+                          quantities=['Attribute0', 'Attribute1'])
+        os.remove(filename + '.tms')
+
+        W = anuga.Wind_stress(F)
+
+        domain.forcing_terms = []
+        domain.forcing_terms.append(W)
+
+        domain.compute_forcing_terms()
+
+        # Compute reference solution
+        const = eta_w*rho_a / rho_w
+
+        N = len(domain)    # number_of_triangles
+
+        t = domain.time
+
+        s = speed(t, [1], [0])[0]
+        phi = angle(t, [1], [0])[0]
+
+        # 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 * num.sqrt(u**2 + v**2)
+
+        for k in range(N):
+            assert num.allclose(domain.quantities['stage'].explicit_update[k],
+                                0)
+            assert num.allclose(domain.quantities['xmomentum'].\
+                                    explicit_update[k],
+                                S*u)
+            assert num.allclose(domain.quantities['ymomentum'].\
+                                    explicit_update[k],
+                                S*v)
+
+    def test_windfield_from_file_seconds(self):
+        import time
+        from anuga.config import rho_a, rho_w, eta_w
+        from math import pi, cos, sin
+        from anuga.config import time_format
+        from anuga.abstract_2d_finite_volumes.util import file_function
+
+        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)
+
+        # Flat surface with 1m of water
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', 1.0)
+        domain.set_quantity('friction', 0)
+
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'exterior': Br})
+
+        domain.time = 7    # Take a time that is represented in file (not zero)
+
+        # Write wind stress file (ensure that domain.time is covered)
+        # Take x=1 and y=0
+        filename = 'test_windstress_from_file.txt'
+        file_out = 'test_windstress_from_file.tms'
+        start = time.mktime(time.strptime('2000', '%Y'))
+        fid = open(filename, 'w')
+        dt = 0.5    # Half second interval
+        t = 0.0
+        while t <= 10.0:
+            fid.write('%s, %f %f\n'
+                      % (str(t), speed(t, [1], [0])[0], angle(t, [1], [0])[0]))
+            t += dt
+
+        fid.close()
+
+        anuga.timefile2netcdf(filename, file_out, time_as_seconds=True)
+        os.remove(filename)
+
+        # Setup wind stress
+        F = file_function(file_out,
+                          quantities=['Attribute0', 'Attribute1'])
+        os.remove(file_out)
+
+        W = anuga.Wind_stress(F)
+
+        domain.forcing_terms = []
+        domain.forcing_terms.append(W)
+
+        domain.compute_forcing_terms()
+
+        # Compute reference solution
+        const = eta_w*rho_a / rho_w
+
+        N = len(domain)    # number_of_triangles
+
+        t = domain.time
+
+        s = speed(t, [1], [0])[0]
+        phi = angle(t, [1], [0])[0]
+
+        # 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 * num.sqrt(u**2 + v**2)
+
+        for k in range(N):
+            assert num.allclose(domain.quantities['stage'].explicit_update[k],
+                                0)
+            assert num.allclose(domain.quantities['xmomentum'].\
+                                    explicit_update[k],
+                                S*u)
+            assert num.allclose(domain.quantities['ymomentum'].\
+                                    explicit_update[k],
+                                S*v)
+
+    def test_wind_stress_error_condition(self):
+        """Test that windstress reacts properly when forcing functions
+        are wrong - e.g. returns a scalar
+        """
+
+        from math import pi, cos, sin
+        from anuga.config import rho_a, rho_w, eta_w
+
+        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)
+
+        # Flat surface with 1m of water
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', 1.0)
+        domain.set_quantity('friction', 0)
+
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'exterior': Br})
+
+        domain.time = 5.54    # Take a random time (not zero)
+
+        # Setup only one forcing term, bad func
+        domain.forcing_terms = []
+
+        try:
+            domain.forcing_terms.append(anuga.Wind_stress(s=scalar_func_list,
+                                                    phi=angle))
+        except AssertionError:
+            pass
+        else:
+            msg = 'Should have raised exception'
+            raise Exception, msg
+
+        try:
+            domain.forcing_terms.append(Wind_stress(s=speed, phi=scalar_func))
+        except Exception:
+            pass
+        else:
+            msg = 'Should have raised exception'
+            raise Exception, msg
+
+        try:
+            domain.forcing_terms.append(Wind_stress(s=speed, phi='xx'))
+        except:
+            pass
+        else:
+            msg = 'Should have raised exception'
+            raise Exception, msg
+
+    def test_rainfall(self):
+        from math import pi, cos, sin
+
+        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)
+
+        # Flat surface with 1m of water
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', 1.0)
+        domain.set_quantity('friction', 0)
+
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'exterior': Br})
+
+        # Setup only one forcing term, constant rainfall
+        domain.forcing_terms = []
+        domain.forcing_terms.append(anuga.Rainfall(domain, rate=2.0))
+
+        domain.compute_forcing_terms()
+        assert num.allclose(domain.quantities['stage'].explicit_update,
+                            2.0/1000)
+
+    def test_rainfall_restricted_by_polygon(self):
+        from math import pi, cos, sin
+
+        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)
+
+        # Flat surface with 1m of water
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', 1.0)
+        domain.set_quantity('friction', 0)
+
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'exterior': Br})
+
+        # Setup only one forcing term, constant rainfall
+        # restricted to a polygon enclosing triangle #1 (bce)
+        domain.forcing_terms = []
+        R = anuga.Rainfall(domain, rate=2.0, polygon=[[1,1], [2,1], [2,2], [1,2]])
+
+        assert num.allclose(R.exchange_area, 2)
+
+        domain.forcing_terms.append(R)
+
+        domain.compute_forcing_terms()
+
+        assert num.allclose(domain.quantities['stage'].explicit_update[1],
+                            2.0/1000)
+        assert num.allclose(domain.quantities['stage'].explicit_update[0], 0)
+        assert num.allclose(domain.quantities['stage'].explicit_update[2:], 0)
+
+    def test_time_dependent_rainfall_restricted_by_polygon(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 = anuga.Domain(points, vertices)
+
+        # Flat surface with 1m of water
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', 1.0)
+        domain.set_quantity('friction', 0)
+
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'exterior': Br})
+
+        # Setup only one forcing term, time dependent rainfall
+        # restricted to a polygon enclosing triangle #1 (bce)
+        domain.forcing_terms = []
+        R = anuga.Rainfall(domain,
+                     rate=lambda t: 3*t + 7,
+                     polygon = [[1,1], [2,1], [2,2], [1,2]])
+
+        assert num.allclose(R.exchange_area, 2)
+        
+        domain.forcing_terms.append(R)
+
+        domain.time = 10.
+
+        domain.compute_forcing_terms()
+
+        assert num.allclose(domain.quantities['stage'].explicit_update[1],
+                            (3*domain.time + 7)/1000)
+        assert num.allclose(domain.quantities['stage'].explicit_update[0], 0)
+        assert num.allclose(domain.quantities['stage'].explicit_update[2:], 0)
+
+    def test_time_dependent_rainfall_using_starttime(self):
+        rainfall_poly = ensure_numeric([[1,1], [2,1], [2,2], [1,2]], num.float)
+
+        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 = anuga.Domain(points, vertices)
+
+        # Flat surface with 1m of water
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', 1.0)
+        domain.set_quantity('friction', 0)
+
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'exterior': Br})
+
+        # Setup only one forcing term, time dependent rainfall
+        # restricted to a polygon enclosing triangle #1 (bce)
+        domain.forcing_terms = []
+        R = anuga.Rainfall(domain,
+                     rate=lambda t: 3*t + 7,
+                     polygon=rainfall_poly)                     
+
+        assert num.allclose(R.exchange_area, 2)
+        
+        domain.forcing_terms.append(R)
+
+        # This will test that time used in the forcing function takes
+        # startime into account.
+        domain.starttime = 5.0
+
+        domain.time = 7.
+
+        domain.compute_forcing_terms()
+
+        assert num.allclose(domain.quantities['stage'].explicit_update[1],
+                            (3*domain.get_time() + 7)/1000)
+
+        assert num.allclose(domain.quantities['stage'].explicit_update[0], 0)
+        assert num.allclose(domain.quantities['stage'].explicit_update[2:], 0)
+
+    def test_time_dependent_rainfall_using_georef(self):
+        """test_time_dependent_rainfall_using_georef
+
+        This will also test the General forcing term using georef
+        """
+
+        # Mesh in zone 56 (absolute coords)
+        x0 = 314036.58727982
+        y0 = 6224951.2960092
+
+        rainfall_poly = ensure_numeric([[1,1], [2,1], [2,2], [1,2]], num.float)
+        rainfall_poly += [x0, y0]
+
+        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,
+                        geo_reference=Geo_reference(56, x0, y0))
+
+        # Flat surface with 1m of water
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', 1.0)
+        domain.set_quantity('friction', 0)
+
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'exterior': Br})
+
+        # Setup only one forcing term, time dependent rainfall
+        # restricted to a polygon enclosing triangle #1 (bce)
+        domain.forcing_terms = []
+        R = anuga.Rainfall(domain,
+                     rate=lambda t: 3*t + 7,
+                     polygon=rainfall_poly)
+
+        assert num.allclose(R.exchange_area, 2)
+        
+        domain.forcing_terms.append(R)
+
+        # This will test that time used in the forcing function takes
+        # startime into account.
+        domain.starttime = 5.0
+
+        domain.time = 7.
+
+        domain.compute_forcing_terms()
+
+        assert num.allclose(domain.quantities['stage'].explicit_update[1],
+                            (3*domain.get_time() + 7)/1000)
+
+
+        assert num.allclose(domain.quantities['stage'].explicit_update[0], 0)
+        assert num.allclose(domain.quantities['stage'].explicit_update[2:], 0)
+
+    def test_time_dependent_rainfall_restricted_by_polygon_with_default(self):
+        """
+        Test that default rainfall can be used when given rate runs out of data.
+        """
+
+        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)
+
+        # Flat surface with 1m of water
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', 1.0)
+        domain.set_quantity('friction', 0)
+
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'exterior': Br})
+
+        # Setup only one forcing term, time dependent rainfall
+        # that expires at t==20
+        from anuga.fit_interpolate.interpolate import Modeltime_too_late
+
+        def main_rate(t):
+            if t > 20:
+                msg = 'Model time exceeded.'
+                raise Modeltime_too_late, msg
+            else:
+                return 3*t + 7
+
+        domain.forcing_terms = []
+        R = anuga.Rainfall(domain,
+                     rate=main_rate,
+                     polygon = [[1,1], [2,1], [2,2], [1,2]],
+                     default_rate=5.0)
+
+        assert num.allclose(R.exchange_area, 2)
+        
+        domain.forcing_terms.append(R)
+
+        domain.time = 10.
+
+        domain.compute_forcing_terms()
+
+        assert num.allclose(domain.quantities['stage'].explicit_update[1],
+                            (3*domain.time+7)/1000)
+        assert num.allclose(domain.quantities['stage'].explicit_update[0], 0)
+        assert num.allclose(domain.quantities['stage'].explicit_update[2:], 0)
+
+        domain.time = 100.
+        domain.quantities['stage'].explicit_update[:] = 0.0     # Reset
+        domain.compute_forcing_terms()
+
+        assert num.allclose(domain.quantities['stage'].explicit_update[1],
+                            5.0/1000) # Default value
+        assert num.allclose(domain.quantities['stage'].explicit_update[0], 0)
+        assert num.allclose(domain.quantities['stage'].explicit_update[2:], 0)
+
+    def test_rainfall_forcing_with_evolve(self):
+        """test_rainfall_forcing_with_evolve
+
+        Test how forcing terms are called within evolve
+        """
+
+        # FIXME(Ole): This test is just to experiment
+
+        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)
+
+        # Flat surface with 1m of water
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', 1.0)
+        domain.set_quantity('friction', 0)
+
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'exterior': Br})
+
+        # Setup only one forcing term, time dependent rainfall
+        # that expires at t==20
+        from anuga.fit_interpolate.interpolate import Modeltime_too_late
+
+        def main_rate(t):
+            if t > 20:
+                msg = 'Model time exceeded.'
+                raise Modeltime_too_late, msg
+            else:
+                return 3*t + 7
+
+        domain.forcing_terms = []
+        R = anuga.Rainfall(domain,
+                     rate=main_rate,
+                     polygon=[[1,1], [2,1], [2,2], [1,2]],
+                     default_rate=5.0)
+
+        assert num.allclose(R.exchange_area, 2)
+        
+        domain.forcing_terms.append(R)
+
+        for t in domain.evolve(yieldstep=1, finaltime=25):
+            pass
+            #FIXME(Ole):  A test here is hard because explicit_update also
+            # receives updates from the flux calculation.
+
+
+
+    def test_inflow_using_circle(self):
+        from math import pi, cos, sin
+
+        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)
+
+        # Flat surface with 1m of water
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', 1.0)
+        domain.set_quantity('friction', 0)
+
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'exterior': Br})
+
+        # Setup only one forcing term, constant inflow of 2 m^3/s
+        # on a circle affecting triangles #0 and #1 (bac and bce)
+        domain.forcing_terms = []
+        
+        I = anuga.Inflow(domain, rate=2.0, center=(1,1), radius=1)
+        domain.forcing_terms.append(I)        
+        domain.compute_forcing_terms()
+
+        
+        A = I.exchange_area
+        assert num.allclose(A, 4) # Two triangles        
+        
+        assert num.allclose(domain.quantities['stage'].explicit_update[1], 2.0/A)
+        assert num.allclose(domain.quantities['stage'].explicit_update[0], 2.0/A)
+        assert num.allclose(domain.quantities['stage'].explicit_update[2:], 0)        
+
+
+    def test_inflow_using_circle_function(self):
+        from math import pi, cos, sin
+
+        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 = anuga.Domain(points, vertices)
+
+        # Flat surface with 1m of water
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', 1.0)
+        domain.set_quantity('friction', 0)
+
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'exterior': Br})
+
+        # Setup only one forcing term, time dependent inflow of 2 m^3/s
+        # on a circle affecting triangles #0 and #1 (bac and bce)
+        domain.forcing_terms = []
+        I = anuga.Inflow(domain, rate=lambda t: 2., center=(1,1), radius=1)
+        domain.forcing_terms.append(I)
+        
+        domain.compute_forcing_terms()        
+
+        A = I.exchange_area
+        assert num.allclose(A, 4) # Two triangles
+        
+        assert num.allclose(domain.quantities['stage'].explicit_update[1], 2.0/A)
+        assert num.allclose(domain.quantities['stage'].explicit_update[0], 2.0/A)
+        assert num.allclose(domain.quantities['stage'].explicit_update[2:], 0)        
+        
+
+
+
+    def test_inflow_catch_too_few_triangles(self):
+        """
+        Test that exception is thrown if no triangles are covered
+        by the inflow area
+        """
+
+        from math import pi, cos, sin
+
+        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)
+
+        # Flat surface with 1m of water
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', 1.0)
+        domain.set_quantity('friction', 0)
+
+        Br = anuga.Reflective_boundary(domain)
+        domain.set_boundary({'exterior': Br})
+
+        # Setup only one forcing term, constant inflow of 2 m^3/s
+        # on a circle affecting triangles #0 and #1 (bac and bce)
+        try:
+            Inflow(domain, rate=2.0, center=(1,1.1), radius=0.01)
+        except:
+            pass
+        else:
+            msg = 'Should have raised exception'
+            raise Exception, msg
+
+    def Xtest_inflow_outflow_conservation(self):
+        """
+        Test what happens if water is abstracted from one area and
+        injected into another - especially if there is not enough
+        water to match the abstraction.
+        This tests that the total volume is kept constant under a range of
+        scenarios.
+
+        This test will fail as the problem was only fixed for culverts.
+        """
+
+        from math import pi, cos, sin
+
+        length = 20.
+        width = 10.
+
+        dx = dy = 2    # 1 or 2 OK
+        points, vertices, boundary = rectangular_cross(int(length/dx),
+                                                       int(width/dy),
+                                                       len1=length,
+                                                       len2=width)
+        domain = Domain(points, vertices, boundary)
+        domain.set_name('test_inflow_conservation')    # Output name
+        domain.set_default_order(2)
+
+        # Flat surface with 1m of water
+        stage = 1.0
+        domain.set_quantity('elevation', 0)
+        domain.set_quantity('stage', stage)
+        domain.set_quantity('friction', 0)
+
+        Br = Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'bottom': Br, 'top': Br})
+
+        # Setup one forcing term, constant inflow of 2 m^3/s on a circle
+        domain.forcing_terms = []
+        domain.forcing_terms.append(Inflow(domain, rate=2.0,
+                                           center=(5,5), radius=1))
+
+        domain.compute_forcing_terms()
+
+        # Check that update values are correct
+        for x in domain.quantities['stage'].explicit_update:
+            assert num.allclose(x, 2.0/pi) or num.allclose(x, 0.0)
+
+        # Check volumes without inflow
+        domain.forcing_terms = []
+        initial_volume = domain.quantities['stage'].get_integral()
+
+        assert num.allclose(initial_volume, width*length*stage)
+
+        for t in domain.evolve(yieldstep = 0.05, finaltime = 5.0):
+            volume = domain.quantities['stage'].get_integral()
+            assert num.allclose(volume, initial_volume)
+
+        # Now apply the inflow and check volumes for a range of stage values
+        for stage in [2.0, 1.0, 0.5, 0.25, 0.1, 0.0]:
+            domain.time = 0.0
+            domain.set_quantity('stage', stage)
+            domain.forcing_terms = []
+            domain.forcing_terms.append(Inflow(domain, rate=2.0,
+                                               center=(5,5), radius=1))
+            initial_volume = domain.quantities['stage'].get_integral()
+            predicted_volume = initial_volume
+            dt = 0.05
+            for t in domain.evolve(yieldstep=dt, finaltime=5.0):
+                volume = domain.quantities['stage'].get_integral()
+                assert num.allclose (volume, predicted_volume)
+                predicted_volume = predicted_volume + 2.0/pi/100/dt # Why 100?
+
+        # Apply equivalent outflow only and check volumes
+        # for a range of stage values
+        for stage in [2.0, 1.0, 0.5, 0.25, 0.1, 0.0]:
+            domain.time = 0.0
+            domain.set_quantity('stage', stage)
+            domain.forcing_terms = []
+            domain.forcing_terms.append(Inflow(domain, rate=-2.0,
+                                               center=(15,5), radius=1))
+            initial_volume = domain.quantities['stage'].get_integral()
+            predicted_volume = initial_volume
+            dt = 0.05
+            for t in domain.evolve(yieldstep=dt, finaltime=5.0):
+                volume = domain.quantities['stage'].get_integral()
+                assert num.allclose (volume, predicted_volume)
+                predicted_volume = predicted_volume - 2.0/pi/100/dt # Why 100?
+
+        # Apply both inflow and outflow and check volumes being constant for a
+        # range of stage values
+        for stage in [2.0, 1.0, 0.5, 0.25, 0.1, 0.0]:
+            domain.time = 0.0
+            domain.set_quantity('stage', stage)
+            domain.forcing_terms = []
+            domain.forcing_terms.append(Inflow(domain, rate=2.0,
+                                               center=(5,5), radius=1))
+            domain.forcing_terms.append(Inflow(domain, rate=-2.0,
+                                               center=(15,5), radius=1))
+            initial_volume = domain.quantities['stage'].get_integral()
+
+            dt = 0.05
+            for t in domain.evolve(yieldstep=dt, finaltime=5.0):
+                volume = domain.quantities['stage'].get_integral()
+                assert num.allclose(volume, initial_volume)
+
+    #####################################################
+
+        
+    def xtest_inflow_using_flowline(self):
+        """test_inflow_using_flowline
+
+        Test the ability of a flowline to match inflow above the flowline by
+        creating constant inflow onto a circle at the head of a 20m
+        wide by 300m long plane dipping at various slopes with a
+        perpendicular flowline and gauge downstream of the inflow and
+        a 45 degree flowlines at 200m downstream.
+
+        A more substantial version of this test with finer resolution and
+        including the depth calculation using Manning's equation is
+        available under the validate_all suite in the directory
+        anuga_validation/automated_validation_tests/flow_tests.
+        """
+
+        
+        verbose = False
+        
+        #----------------------------------------------------------------------
+        # Setup computational domain
+        #----------------------------------------------------------------------
+        number_of_inflows = 2 # Number of inflows on top of each other
+        finaltime = 500 #700.0 # If this is too short, steady state will not be achieved
+
+        length = 250.
+        width  = 20.
+        dx = dy = 5                 # Resolution: of grid on both axes
+
+        points, vertices, boundary = rectangular_cross(int(length/dx),
+                                                       int(width/dy),
+                                                       len1=length,
+                                                       len2=width)
+
+        for mannings_n in [0.1, 0.01]:
+            # Loop over a range of roughnesses              
+            
+            for slope in [1.0/300, 1.0/100]:
+                # Loop over a range of bedslopes representing
+                # sub to super critical flows 
+
+
+                domain = Domain(points, vertices, boundary)   
+                domain.set_name('inflow_flowline_test')     # Output name
+
+                #--------------------------------------------------------------
+                # Setup initial conditions
+                #--------------------------------------------------------------
+
+                def topography(x, y):
+                    z = -x * slope
+                    return z
+
+                # Use function for elevation
+                domain.set_quantity('elevation', topography)
+                # Constant friction of conc surface   
+                domain.set_quantity('friction', mannings_n)
+                # Dry initial condition
+                domain.set_quantity('stage', expression='elevation')
+
+                #--------------------------------------------------------------
+                # Setup Inflow
+                #--------------------------------------------------------------
+
+                # Fixed Flowrate onto Area 
+                fixed_inflow = anuga.Inflow(domain,
+                                      center=(10.0, 10.0),
+                                      radius=5.00,
+                                      rate=10.00)   
+
+                # Stack this flow
+                for i in range(number_of_inflows):
+                    domain.forcing_terms.append(fixed_inflow)
+                
+                ref_flow = fixed_inflow.rate*number_of_inflows
+
+                # Compute normal depth on plane using Mannings equation
+                # v=1/n*(r^2/3)*(s^0.5) or r=(Q*n/(s^0.5*W))^0.6
+                normal_depth=(ref_flow*mannings_n/(slope**0.5*width))**0.6
+                if verbose:
+                    print
+                    print 'Slope:', slope, 'Mannings n:', mannings_n
+                    
+                    
+                #--------------------------------------------------------------
+                # Setup boundary conditions
+                #--------------------------------------------------------------
+
+                Br = anuga.Reflective_boundary(domain)
+                
+                # Define downstream boundary based on predicted depth
+                def normal_depth_stage_downstream(t):
+                    return (-slope*length) + normal_depth
+                
+                Bt = anuga.Transmissive_momentum_set_stage_boundary(
+                        domain=domain, function=normal_depth_stage_downstream)
+
+                domain.set_boundary({'left': Br,
+                                     'right': Bt,
+                                     'top': Br,
+                                     'bottom': Br})
+
+
+                #--------------------------------------------------------------
+                # Evolve system through time
+                #--------------------------------------------------------------
+
+                for t in domain.evolve(yieldstep=100.0, finaltime=finaltime):
+                    print domain.timestepping_statistics()
+                    #if verbose :
+                    #    print domain.timestepping_statistics()
+
+                    #    print domain.volumetric_balance_statistics()                                    
+
+
+                #--------------------------------------------------------------
+                # Compute flow thru flowlines ds of inflow
+                #--------------------------------------------------------------
+                    
+                # Square on flowline at 200m
+                q = domain.get_flow_through_cross_section([[200.0,  0.0],
+                                                           [200.0, 20.0]])
+                if verbose:
+                    print ('90 degree flowline: ANUGA = %f, Ref = %f'
+                           % (q, ref_flow))
+
+                msg = ('Predicted flow was %f, should have been %f'
+                       % (q, ref_flow))
+                assert num.allclose(q, ref_flow, rtol=1.0e-2), msg         
+
+                           
+                # 45 degree flowline at 200m
+                q = domain.get_flow_through_cross_section([[200.0,  0.0],
+                                                           [220.0, 20.0]])
+                if verbose:
+                    print ('45 degree flowline: ANUGA = %f, Ref = %f'
+                           % (q, ref_flow))
+                    
+                msg = ('Predicted flow was %f, should have been %f'
+                       % (q, ref_flow))
+                assert num.allclose(q, ref_flow, rtol=1.0e-2), msg         
+
+        os.remove('inflow_flowline_test.sww')
+
+        
+    def Xtest_inflow_boundary_using_flowline(self):
+        """test_inflow_boundary_using_flowline
+        Test the ability of a flowline to match inflow above the flowline by
+        creating constant inflow into the boundary at the head of a 20m
+        wide by 300m long plane dipping at various slopes with a
+        perpendicular flowline and gauge downstream of the inflow and
+        a 45 degree flowlines at 200m downstream
+        
+        
+        """
+
+        # FIXME (Ole): Work in progress
+        
+        verbose = False
+        
+
+        #----------------------------------------------------------------------
+        # Import necessary modules
+        #----------------------------------------------------------------------
+        from anuga.abstract_2d_finite_volumes.mesh_factory import rectangular_cross
+        from anuga.shallow_water import Domain
+        from anuga.shallow_water.shallow_water_domain import Reflective_boundary
+        from anuga.shallow_water.shallow_water_domain import Dirichlet_boundary
+        from anuga.shallow_water.forcing import Inflow_boundary
+        from anuga.shallow_water.data_manager import get_flow_through_cross_section
+        from anuga.abstract_2d_finite_volumes.util import sww2csv_gauges, csv2timeseries_graphs
+
+
+        #----------------------------------------------------------------------
+        # Setup computational domain
+        #----------------------------------------------------------------------
+
+        finaltime = 500 #700.0 # If this is too short, steady state will not be achieved
+
+        length = 250.
+        width  = 20.
+        dx = dy = 5          # Resolution: of grid on both axes
+
+        points, vertices, boundary = rectangular_cross(int(length/dx), int(width/dy),
+                                                       len1=length, len2=width)
+
+        for mannings_n in [0.1, 0.01]:
+            # Loop over a range of roughnesses              
+            
+            for slope in [1.0/300, 1.0/100]:
+                # Loop over a range of bedslopes representing sub to super critical flows 
+
+
+                domain = Domain(points, vertices, boundary)   
+                domain.set_name('inflow_boundary_flowline_test')
+                
+
+                #-------------------------------------------------------------
+                # Setup initial conditions
+                #-------------------------------------------------------------
+
+                def topography(x, y):
+                    z=-x * slope
+                    return z
+
+                domain.set_quantity('elevation', topography)
+                domain.set_quantity('friction', mannings_n)
+                domain.set_quantity('stage',
+                                    expression='elevation')
+
+
+                    
+                #--------------------------------------------------------------
+                # Setup boundary conditions
+                #--------------------------------------------------------------
+                
+
+
+                ref_flow = 10.00
+
+                # Compute normal depth on plane using Mannings equation
+                # v=1/n*(r^2/3)*(s^0.5) or r=(Q*n/(s^0.5*W))^0.6
+                normal_depth=(ref_flow*mannings_n/(slope**0.5*width))**0.6
+                if verbose:
+                    print
+                    print 'Slope:', slope, 'Mannings n:', mannings_n
+                    
+                
+                
+                Bi = Inflow_boundary(domain, rate=ref_flow)
+
+                Br = Reflective_boundary(domain)
+                
+                # Define downstream boundary based on predicted depth
+                def normal_depth_stage_downstream(t):
+                    return (-slope*length) + normal_depth
+                
+                Bt = Transmissive_momentum_set_stage_boundary(domain=domain,
+                                                              function=normal_depth_stage_downstream)
+                
+
+                
+
+                domain.set_boundary({'left': Bi,
+                                     'right': Bt,
+                                     'top': Br,
+                                     'bottom': Br})
+
+
+
+                #--------------------------------------------------------------
+                # Evolve system through time
+                #--------------------------------------------------------------
+
+
+                for t in domain.evolve(yieldstep=100.0, finaltime=finaltime):
+                    pass
+                    #if verbose :
+                    #    print domain.timestepping_statistics()
+                    #    print domain.volumetric_balance_statistics()
+                                                        
+
+
+                #--------------------------------------------------------------
+                # Compute flow thru flowlines ds of inflow
+                #--------------------------------------------------------------
+                    
+                # Square on flowline at 200m
+                q=domain.get_flow_through_cross_section([[200.0,0.0],[200.0,20.0]])
+                msg = 'Predicted flow was %f, should have been %f' % (q, ref_flow)
+                if verbose:
+                    print '90 degree flowline: ANUGA = %f, Ref = %f' % (q, ref_flow)
+                assert num.allclose(q, ref_flow, rtol=1.0e-2), msg         
+
+                           
+                # 45 degree flowline at 200m
+                q=domain.get_flow_through_cross_section([[200.0,0.0],[220.0,20.0]])
+                msg = 'Predicted flow was %f, should have been %f' % (q, ref_flow)
+                if verbose:
+                    print '45 degree flowline: ANUGA = %f, Ref = %f' % (q, ref_flow)
+                    
+                assert num.allclose(q, ref_flow, rtol=1.0e-2), msg         
+
+        
+ ################################################################################
+
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_swb_forcing_terms, 'test')
+    runner = unittest.TextTestRunner(verbosity=1)
+    runner.run(suite)
Index: /trunk/anuga_work/shallow_water_balanced_steve/test_swb_reporting.py
===================================================================
--- /trunk/anuga_work/shallow_water_balanced_steve/test_swb_reporting.py	(revision 8245)
+++ /trunk/anuga_work/shallow_water_balanced_steve/test_swb_reporting.py	(revision 8245)
@@ -0,0 +1,146 @@
+#!/usr/bin/env python
+
+import unittest, os
+import os.path
+from math import pi, sqrt
+import tempfile
+
+import anuga
+
+from anuga.config import g, epsilon
+from anuga.config import netcdf_mode_r, netcdf_mode_w, netcdf_mode_a
+from anuga.utilities.numerical_tools import mean
+from anuga.geometry.polygon import is_inside_polygon
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+from anuga.abstract_2d_finite_volumes.quantity import Quantity
+from anuga.geospatial_data.geospatial_data import Geospatial_data
+from anuga.abstract_2d_finite_volumes.mesh_factory import rectangular_cross
+
+from anuga.utilities.system_tools import get_pathname_from_package
+from swb_domain import *
+
+import numpy as num
+
+# Get gateway to C implementation of flux function for direct testing
+from shallow_water_ext import flux_function_central as flux_function
+
+
+
+
+class Test_swb_clean(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+
+    def test_extrema(self):
+        """Test that extrema of quantities are computed correctly
+        Extrema are updated at every *internal* timestep
+        """
+
+        from anuga.abstract_2d_finite_volumes.mesh_factory \
+                import rectangular_cross
+
+        initial_runup_height = -0.4
+        final_runup_height = -0.3
+
+        #--------------------------------------------------------------
+        # Setup computational domain
+        #--------------------------------------------------------------
+        N = 5
+        points, vertices, boundary = rectangular_cross(N, N)
+        domain = Domain(points, vertices, boundary)
+        domain.set_name('extrema_test')
+
+        #--------------------------------------------------------------
+        # Setup initial conditions
+        #--------------------------------------------------------------
+        def topography(x,y):
+            return -x/2                             # linear bed slope
+
+        domain.set_quantity('elevation', topography)    # function for elevation
+        domain.set_quantity('friction', 0.)             # Zero friction
+        # Constant negative initial stage
+        domain.set_quantity('stage', initial_runup_height)
+        domain.set_quantities_to_be_monitored(['stage', 'height'],
+                                              time_interval=[0.5, 2.7],
+                                              polygon=[[0,0], [0,1],
+                                                       [1,1], [1,0]])
+
+        assert len(domain.quantities_to_be_monitored) == 2
+        assert domain.quantities_to_be_monitored.has_key('stage')
+        assert domain.quantities_to_be_monitored.has_key('height')
+        for key in domain.quantities_to_be_monitored['stage'].keys():
+            assert domain.quantities_to_be_monitored['stage'][key] is None
+
+        #--------------------------------------------------------------
+        # Setup boundary conditions
+        #--------------------------------------------------------------
+        Br = anuga.Reflective_boundary(domain)       # Reflective wall
+        # Constant inflow
+        Bd = anuga.Dirichlet_boundary([final_runup_height, 0, 0])
+
+        # All reflective to begin with (still water)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        #--------------------------------------------------------------
+        # Let triangles adjust and check extrema
+        #--------------------------------------------------------------
+        for t in domain.evolve(yieldstep=0.1, finaltime=1.0):
+            domain.quantity_statistics() # Run it silently
+
+        #--------------------------------------------------------------
+        # Test extrema
+        #--------------------------------------------------------------
+        stage = domain.quantities_to_be_monitored['stage']
+        assert stage['min'] <= stage['max']
+
+        assert num.allclose(stage['min'], initial_runup_height,
+                            rtol=1.0/N)    # First order accuracy
+
+        depth = domain.quantities_to_be_monitored['height']
+
+        assert depth['min'] <= depth['max']
+        assert depth['min'] >= 0.0
+        assert depth['max'] >= 0.0
+
+        #--------------------------------------------------------------
+        # Update boundary to allow inflow
+        #--------------------------------------------------------------
+        domain.set_boundary({'right': Bd})
+
+        #--------------------------------------------------------------
+        # Evolve system through time
+        #--------------------------------------------------------------
+        for t in domain.evolve(yieldstep=0.1, finaltime=3.0):
+            domain.quantity_statistics()    # Run it silently
+
+        #--------------------------------------------------------------
+        # Test extrema again
+        #--------------------------------------------------------------
+        stage = domain.quantities_to_be_monitored['stage']
+        assert stage['min'] <= stage['max']
+
+        assert num.allclose(stage['min'], initial_runup_height,
+                            rtol = 1.0/N) # First order accuracy
+
+        depth = domain.quantities_to_be_monitored['height']
+        assert depth['min'] <= depth['max']
+        assert depth['min'] >= 0.0
+        assert depth['max'] >= 0.0
+
+        # Cleanup
+        os.remove(domain.get_name() + '.sww')
+
+
+
+
+
+#################################################################################
+
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_swb_clean, 'test')
+    runner = unittest.TextTestRunner(verbosity=1)
+    runner.run(suite)
