Index: /anuga_core/compile_all.py
===================================================================
--- /anuga_core/compile_all.py	(revision 3559)
+++ /anuga_core/compile_all.py	(revision 3560)
@@ -26,5 +26,5 @@
 
 os.chdir('..')
-os.chdir('pyvolution')
+os.chdir('abstract_2d_finite_volumes')
 execfile('..' + os.sep + 'utilities' + os.sep + 'compile.py')
 
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/SConscript
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/SConscript	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/SConscript	(revision 3560)
@@ -0,0 +1,9 @@
+import os
+Import('env')
+env2 = env.Copy()
+env2.Append(CPPPATH=['#source/anuga/utilities'])
+
+instdir = os.path.join(env['PREFIX'], 'anuga', 'pyvolution')
+env.Install(instdir, env2.SharedLibrary('quantity_ext', ['quantity_ext.c']))
+env.Install(instdir, env2.SharedLibrary('shallow_water_ext', ['shallow_water_ext.c']))
+env.Install(instdir, env2.SharedLibrary('shallow_water_kinetic', ['shallow_water_kinetic_ext.c']))
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/__init__.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/__init__.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/__init__.py	(revision 3560)
@@ -0,0 +1,9 @@
+"""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__
+
+
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/_test_sww2domain.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/_test_sww2domain.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/_test_sww2domain.py	(revision 3560)
@@ -0,0 +1,80 @@
+"""Simple example of shallow water wave equation using Pyvolution
+
+Water driven by linear slope and Dirichlet boundary
+
+"""
+
+######################
+# Module imports 
+#
+from mesh_factory import rectangular
+from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+     Constant_height, Time_boundary, Transmissive_boundary
+from Numeric import array
+
+#Create basic mesh
+points, vertices, boundary = rectangular(10, 10)
+
+#Create shallow water domain
+domain = Domain(points, vertices, boundary)
+domain.smooth = False
+domain.visualise = False
+domain.store = True
+domain.filename = 'bedslope'
+domain.default_order=2
+
+#######################
+#Bed-slope and friction
+domain.set_quantity('elevation', lambda x,y: -x/3)
+domain.set_quantity('friction', 0.1)
+
+######################
+# Boundary conditions
+from math import sin, pi
+Br = Reflective_boundary(domain)
+Bt = Transmissive_boundary(domain)
+Bd = Dirichlet_boundary([0.2,0.,0.])
+Bw = Time_boundary(domain=domain,
+                   f=lambda t: [(0.1*sin(t*2*pi)), 0.0, 0.0])
+
+domain.set_boundary({'left': Bd, 'right': Br, 'top': Br, 'bottom': Br})
+domain.quantities_to_be_stored.extend(['xmomentum','ymomentum'])
+
+######################
+#Initial condition
+h = 0.05
+elevation = domain.quantities['elevation'].vertex_values
+domain.set_quantity('stage', elevation + h)
+#elevation = domain.get_quantity('elevation',location='unique vertices')
+#domain.set_quantity('stage', elevation + h,location='unique vertices')
+
+domain.check_integrity()
+dir(domain)
+
+######################
+#Evolution
+for t in domain.evolve(yieldstep = 1, finaltime = 2.0):
+#    domain.write_time()
+    pass
+
+
+##NOW TEST IT!!!
+
+from anuga.pyvolution.data_manager import sww2domain
+from Numeric import allclose
+
+filename = domain.datadir+'\\'+domain.filename+'.sww'
+
+domain2 = sww2domain(filename,fail_if_NaN=False,verbose = False)
+
+
+bits = ['xllcorner','yllcorner','vertex_coordinates','time','starttime']
+
+for quantity in ['elevation']+domain.quantities_to_be_stored:
+    bits.append('get_quantity("%s")'%quantity)
+
+for bit in bits:
+#    print 'testing that domain.'+bit+' has been restored'
+    assert allclose(eval('domain.'+bit),eval('domain2.'+bit))
+
+#print 'passed'
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/_test_sww2domain2.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/_test_sww2domain2.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/_test_sww2domain2.py	(revision 3560)
@@ -0,0 +1,96 @@
+"""Simple example of shallow water wave equation using Pyvolution
+
+Water driven by linear slope and Dirichlet boundary
+
+"""
+
+######################
+# Module imports 
+#
+from mesh_factory import rectangular
+from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+     Constant_height, Time_boundary, Transmissive_boundary
+from Numeric import array
+
+#Create basic mesh
+points, vertices, boundary = rectangular(10, 10)
+
+#Create shallow water domain
+domain = Domain(points, vertices, boundary)
+domain.smooth = False
+domain.visualise = False
+domain.store = True
+domain.filename = 'bedslope'
+domain.default_order=2
+domain.quantities_to_be_stored=['stage']
+
+#######################
+#Bed-slope and friction
+domain.set_quantity('elevation', lambda x,y: -x/3)
+domain.set_quantity('friction', 0.1)
+
+######################
+# Boundary conditions
+from math import sin, pi
+Br = Reflective_boundary(domain)
+Bt = Transmissive_boundary(domain)
+Bd = Dirichlet_boundary([0.2,0.,0.])
+Bw = Time_boundary(domain=domain,
+                   f=lambda t: [(0.1*sin(t*2*pi)), 0.0, 0.0])
+
+domain.set_boundary({'left': Bd, 'right': Br, 'top': Br, 'bottom': Br})
+
+######################
+#Initial condition
+h = 0.05
+elevation = domain.quantities['elevation'].vertex_values
+domain.set_quantity('stage', elevation + h)
+#elevation = domain.get_quantity('elevation',location='unique vertices')
+#domain.set_quantity('stage', elevation + h,location='unique vertices')
+
+domain.check_integrity()
+######################
+#Evolution
+for t in domain.evolve(yieldstep = 1, finaltime = 2.0):
+    pass
+    #domain.write_time()
+
+
+##NOW TEST IT!!!
+
+from anuga.pyvolution.data_manager import sww2domain
+from Numeric import allclose
+
+filename = domain.datadir+'\\'+domain.filename+'.sww'
+
+try:
+    domain2 = sww2domain(filename,verbose=False)
+    assert True == False
+except:
+    filler = 0
+    domain2 = sww2domain(filename,fail_if_NaN=False,NaN_filler = filler,verbose=False)
+
+bits = ['xllcorner','yllcorner','vertex_coordinates','time','starttime']
+
+for quantity in ['elevation']+domain.quantities_to_be_stored:
+    bits.append('get_quantity("%s")'%quantity)
+
+for bit in bits:
+#    print 'testing that domain.'+bit+' has been restored'
+    assert allclose(eval('domain.'+bit),eval('domain2.'+bit))
+
+#print max(max(domain2.get_quantity('xmomentum')))
+#print min(min(domain2.get_quantity('xmomentum')))
+#print max(max(domain2.get_quantity('ymomentum')))
+#print min(min(domain2.get_quantity('ymomentum')))
+
+assert max(max(domain2.get_quantity('xmomentum')))==filler
+assert min(min(domain2.get_quantity('xmomentum')))==filler
+assert max(max(domain2.get_quantity('ymomentum')))==filler
+assert min(min(domain2.get_quantity('ymomentum')))==filler
+
+#print 'passed'
+
+#cleanup
+#import os
+#os.remove(domain.datadir+'/'+domain.filename+'.sww')
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/advection.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/advection.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/advection.py	(revision 3560)
@@ -0,0 +1,403 @@
+import sys
+from os import sep
+sys.path.append('..'+sep+'pyvolution')
+
+"""Class Domain -
+2D triangular domains for finite-volume computations of
+the advection equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the advection equantion
+
+The equation is
+
+  u_t + (v_1 u)_x + (v_2 u)_y = 0
+
+There is only one conserved quantity, the stage u
+
+The advection equation is a very simple specialisation of the generic
+domain and may serve as an instructive example or a test of other
+components such as visualisation.
+
+Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2004
+"""
+
+
+import logging, logging.config
+logger = logging.getLogger('advection')
+logger.setLevel(logging.WARNING)
+
+try:
+    logging.config.fileConfig('log.ini')
+except:
+    pass
+
+
+from domain import *
+Generic_domain = Domain #Rename
+
+class Domain(Generic_domain):
+
+    def __init__(self,
+                 coordinates,
+                 vertices,
+                 boundary = None,
+                 tagged_elements = None,
+                 geo_reference = None,
+                 use_inscribed_circle=False,
+                 velocity = None,
+                 full_send_dict=None,
+                 ghost_recv_dict=None,
+                 processor=0,
+                 numproc=1
+                 ):
+
+        conserved_quantities = ['stage']
+        other_quantities = []
+        Generic_domain.__init__(self,
+                                source=coordinates,
+                                triangles=vertices,
+                                boundary=boundary,
+                                conserved_quantities=conserved_quantities,
+                                other_quantities=other_quantities,
+                                tagged_elements=tagged_elements,
+                                geo_reference=geo_reference,
+                                use_inscribed_circle=use_inscribed_circle,
+                                full_send_dict=full_send_dict,
+                                ghost_recv_dict=ghost_recv_dict,
+                                processor=processor,
+                                numproc=numproc)
+
+
+        if velocity is None:
+            self.velocity = [1,0]
+        else:
+            self.velocity = velocity
+
+        #Only first is implemented for advection
+        self.default_order = self.order = 1
+
+        #Realtime visualisation
+        self.visualiser = None
+        self.visualise  = False
+        self.visualise_color_stage = False
+        self.visualise_stage_range = 1.0
+        self.visualise_timer = True
+        self.visualise_range_z = None
+
+
+        self.smooth = True
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from realtime_visualisation_new import Visualiser
+ #           from vtk_realtime_visualiser import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+        self.visualise = True
+
+
+    def check_integrity(self):
+        Generic_domain.check_integrity(self)
+
+        msg = 'Conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+
+
+    def flux_function(self, normal, ql, qr, zl=None, zr=None):
+        """Compute outward flux as inner product between velocity
+        vector v=(v_1, v_2) and normal vector n.
+
+        if <n,v> > 0 flux direction is outward bound and its magnitude is
+        determined by the quantity inside volume: ql.
+        Otherwise it is inbound and magnitude is determined by the
+        quantity outside the volume: qr.
+        """
+
+        v1 = self.velocity[0]
+        v2 = self.velocity[1]
+
+
+        normal_velocity = v1*normal[0] + v2*normal[1]
+
+        if normal_velocity < 0:
+            flux = qr * normal_velocity
+        else:
+            flux = ql * normal_velocity
+
+        max_speed = abs(normal_velocity)
+        return flux, max_speed
+
+    def compute_fluxes(self):
+
+        try:
+            import weave
+            self.weave_available = True
+        except:
+            self.weave_available = False
+
+        if self.weave_available:
+            self.compute_fluxes_weave()
+        else:
+            self.compute_fluxes_python()
+
+
+
+    def compute_fluxes_python(self):
+        """Compute all fluxes and the timestep suitable for all volumes
+        in domain.
+
+        Compute total flux for each conserved quantity using "flux_function"
+
+        Fluxes across each edge are scaled by edgelengths and summed up
+        Resulting flux is then scaled by area and stored in
+        domain.explicit_update
+
+        The maximal allowable speed computed by the flux_function
+        for each volume
+        is converted to a timestep that must not be exceeded. The minimum of
+        those is computed as the next overall timestep.
+
+        Post conditions:
+        domain.explicit_update is reset to computed flux values
+        domain.timestep is set to the largest step satisfying all volumes.
+        """
+
+        import sys
+        from Numeric import zeros, Float
+        from anuga.config import max_timestep
+
+        N = self.number_of_elements
+
+        neighbours = self.neighbours
+        neighbour_edges = self.neighbour_edges
+        normals = self.normals
+
+        areas = self.areas
+        radii = self.radii
+        edgelengths = self.edgelengths
+
+        timestep = max_timestep #FIXME: Get rid of this
+
+        #Shortcuts
+        Stage = self.quantities['stage']
+
+        #Arrays
+        stage = Stage.edge_values
+
+        stage_bdry = Stage.boundary_values
+
+        flux = zeros(1, Float) #Work array for summing up fluxes
+
+        #Loop
+        for k in range(N):
+            optimal_timestep = float(sys.maxint)
+
+            flux[:] = 0.  #Reset work array
+            for i in range(3):
+                #Quantities inside volume facing neighbour i
+                ql = stage[k, i]
+
+                #Quantities at neighbour on nearest face
+                n = neighbours[k,i]
+                if n < 0:
+                    m = -n-1 #Convert neg flag to index
+                    qr = stage_bdry[m]
+                else:
+                    m = neighbour_edges[k,i]
+                    qr = stage[n, m]
+
+
+                #Outward pointing normal vector
+                normal = normals[k, 2*i:2*i+2]
+
+                #Flux computation using provided function
+                edgeflux, max_speed = self.flux_function(normal, ql, qr)
+                flux -= edgeflux * edgelengths[k,i]
+
+                #Update optimal_timestep
+                if  self.tri_full_flag[k] == 1 :
+                    try:
+                        optimal_timestep = min(optimal_timestep, radii[k]/max_speed)
+                    except ZeroDivisionError:
+                        pass
+
+            #Normalise by area and store for when all conserved
+            #quantities get updated
+            flux /= areas[k]
+            Stage.explicit_update[k] = flux[0]
+
+            timestep = min(timestep, optimal_timestep)
+
+        self.timestep = timestep
+
+    def compute_fluxes_weave(self):
+        """Compute all fluxes and the timestep suitable for all volumes
+        in domain.
+
+        Compute total flux for each conserved quantity using "flux_function"
+
+        Fluxes across each edge are scaled by edgelengths and summed up
+        Resulting flux is then scaled by area and stored in
+        domain.explicit_update
+
+        The maximal allowable speed computed by the flux_function
+        for each volume
+        is converted to a timestep that must not be exceeded. The minimum of
+        those is computed as the next overall timestep.
+
+        Post conditions:
+        domain.explicit_update is reset to computed flux values
+        domain.timestep is set to the largest step satisfying all volumes.
+        """
+
+        import sys
+        from Numeric import zeros, Float
+        from anuga.config import max_timestep
+
+        import weave
+        from weave import converters
+
+        N = self.number_of_elements
+
+
+        timestep    = zeros( 1, Float);
+        timestep[0] = float(max_timestep) #FIXME: Get rid of this
+
+        #Shortcuts
+        Stage = self.quantities['stage']
+
+        #Arrays
+        neighbours      = self.neighbours
+        neighbour_edges = self.neighbour_edges
+        normals         = self.normals
+        areas           = self.areas
+        radii           = self.radii
+        edgelengths     = self.edgelengths
+        tri_full_flag   = self.tri_full_flag
+
+        stage_edge      = Stage.edge_values
+        stage_bdry      = Stage.boundary_values
+        stage_update    = Stage.explicit_update
+
+        huge_timestep = float(sys.maxint)
+
+        v1 = self.velocity[0]
+        v2 = self.velocity[1]
+
+        code = """
+        //Loop
+
+        double qr,ql;
+        int m,n;
+        double normal[2];
+        double normal_velocity;
+        double flux, edgeflux;
+        double max_speed;
+        double optimal_timestep;
+        for (int k=0; k<N; k++){
+
+            optimal_timestep = huge_timestep;
+            flux = 0.0;  //Reset work array
+            for (int i=0; i<3; i++){
+                //Quantities inside volume facing neighbour i
+                ql = stage_edge(k, i);
+
+                //Quantities at neighbour on nearest face
+                n = neighbours(k,i);
+                if (n < 0) {
+                    m = -n-1; //Convert neg flag to index
+                    qr = stage_bdry(m);
+                } else {
+                    m = neighbour_edges(k,i);
+                    qr = stage_edge(n, m);
+                }
+
+
+                //Outward pointing normal vector
+                for (int j=0; j<2; j++){
+                    normal[j] = normals(k, 2*i+j);
+                }
+
+
+                //Flux computation using provided function
+                normal_velocity = v1*normal[0] + v2*normal[1];
+
+                if (normal_velocity < 0) {
+                    edgeflux = qr * normal_velocity;
+                } else {
+                    edgeflux = ql * normal_velocity;
+                }
+
+                max_speed = fabs(normal_velocity);
+                flux = flux - edgeflux * edgelengths(k,i);
+
+                //Update optimal_timestep
+                if (tri_full_flag(k) == 1) {
+                    if (max_speed != 0.0) {
+                        optimal_timestep = (optimal_timestep>radii(k)/max_speed) ? radii(k)/max_speed : optimal_timestep;
+                    }
+                }
+
+            }
+
+            //Normalise by area and store for when all conserved
+            //quantities get updated
+            stage_update(k) = flux/areas(k);
+
+            timestep(0) = (timestep(0)>optimal_timestep) ? optimal_timestep : timestep(0);
+
+        }
+        """
+
+        logger.debug('Trying to weave advection.compute_fluxes')
+        weave.inline(code, ['stage_edge','stage_bdry','stage_update',
+                             'neighbours','neighbour_edges','normals',
+                             'areas','radii','edgelengths','tri_full_flag',
+                             'huge_timestep',
+                             'timestep','v1','v2','N'],
+                             type_converters = converters.blitz, compiler='gcc');
+
+        self.timestep = timestep[0]
+
+
+
+    def evolve(self,
+               yieldstep = None,
+               finaltime = None,
+               duration = None,
+               skip_initial_step = False):
+
+        """Specialisation of basic evolve method from parent class
+        """
+
+        #Initialise real time viz if requested
+        if self.visualise is True and self.time == 0.0:
+            #pass
+            #import realtime_visualisation_new as visualise
+            #visualise.create_surface(self)
+            self.initialise_visualiser()
+            self.visualiser.setup_all()
+            self.visualiser.update_timer()
+
+
+        #Call basic machinery from parent class
+        for t in Generic_domain.evolve(self,
+                                       yieldstep=yieldstep,
+                                       finaltime=finaltime,
+                                       duration=duration,
+                                       skip_initial_step=skip_initial_step):
+
+
+
+
+            #Real time viz
+            if self.visualise is True:
+                #pass
+                self.visualiser.update_all()
+                self.visualiser.update_timer()
+
+
+            #Pass control on to outer loop for more specific actions
+            yield(t)
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/bed_w_eden_boundary.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/bed_w_eden_boundary.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/bed_w_eden_boundary.py	(revision 3560)
@@ -0,0 +1,65 @@
+"""Example of shallow water wave equation
+using time boundary from a file
+"""
+
+######################
+# Module imports 
+#
+from mesh_factory import rectangular
+from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+     Constant_height, Time_boundary, File_boundary
+from Numeric import array, ones
+
+#Create basic mesh (100m x 100m)
+points, vertices, boundary = rectangular(50, 50, 100, 100)
+
+#Create shallow water domain
+domain = Domain(points, vertices, boundary)
+domain.smooth = False
+domain.visualise = False
+domain.default_order = 2
+domain.store = True     #Store for visualisation purposes
+domain.format = 'sww'   #Native netcdf visualisation format
+
+
+
+#######################
+#Bed-slope and friction
+domain.set_quantity('elevation', 0.0) #Flat
+#domain.set_quantity('elevation', lambda x,y: -(x+y)/3) #Slopy
+domain.set_quantity('friction', 0.1)
+
+
+######################
+# Boundary conditions
+
+
+#Write file
+import os, time
+from anuga.config import time_format
+from math import sin, pi
+
+filename = 'Eden_Australia_31082004.txt'
+
+Br = Reflective_boundary(domain)
+Bd = Dirichlet_boundary([1. ,0.,0.])
+Bw = Time_boundary(domain=domain,
+                   f=lambda t: [(1*sin(t*pi/20)), 0.0, 0.0])
+
+Bf = File_boundary(filename, domain)
+
+#domain.set_boundary({'left': Bw, 'right': Br, 'top': Br, 'bottom': Br})
+domain.set_boundary({'left': Bf, 'right': Br, 'top': Br, 'bottom': Br})
+
+
+######################
+#Initial condition (constant)
+domain.set_quantity('stage', 0.0)
+domain.check_integrity()
+
+  
+######################
+#Evolution
+for t in domain.evolve(yieldstep = 60, finaltime = 385*15*60):
+    domain.write_time()
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/bed_w_file_boundary.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/bed_w_file_boundary.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/bed_w_file_boundary.py	(revision 3560)
@@ -0,0 +1,87 @@
+"""Example of shallow water wave equation.
+
+Generate slope
+
+"""
+
+######################
+# Module imports 
+#
+from mesh_factory import rectangular
+from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+     Constant_height, Time_boundary, File_boundary
+from Numeric import array
+
+#Create basic mesh
+points, vertices, boundary = rectangular(10, 10, 100, 100)
+
+#Create shallow water domain
+domain = Domain(points, vertices, boundary)
+domain.smooth = False
+domain.visualise = True
+domain.default_order=2
+
+#######################
+#Bed-slope and friction
+def x_slope(x, y):
+    return -x/3
+
+#domain.set_quantity('elevation', x_slope)
+domain.set_quantity('elevation', lambda x,y: -x/3)
+domain.set_quantity('friction', 0.1)
+
+
+######################
+# Boundary conditions
+
+
+#Write file
+import os, time
+from anuga.config import time_format
+from math import sin, pi
+
+finaltime = 100
+filename = 'bed_w_boundary'
+fid = open(filename + '.txt', 'w')
+start = time.mktime(time.strptime('2000', '%Y'))
+dt = 5  #Five second intervals
+t = 0.0
+while t <= finaltime:
+    t_string = time.strftime(time_format, time.gmtime(t+start))    
+    fid.write('%s, %f %f %f\n' %(t_string, 10*sin(t*0.1*pi), 0.0, 0.0))
+    
+    t += dt
+    
+fid.close()
+
+
+#Convert ASCII file to NetCDF (Which is what we really like!)
+from anuga.pyvolution.data_manager import timefile2swww        
+timefile2swww(filename, quantity_names = domain.conserved_quantities)
+
+
+Br = Reflective_boundary(domain)
+Bd = Dirichlet_boundary([0.2,0.,0.])
+Bw = Time_boundary(domain=domain,
+                   f=lambda t: [(10*sin(t*0.1*pi)), 0.0, 0.0])
+
+Bf = File_boundary(filename + '.sww', domain)
+
+#domain.set_boundary({'left': Bw, 'right': Br, 'top': Br, 'bottom': Br})
+domain.set_boundary({'left': Bf, 'right': Br, 'top': Br, 'bottom': Br})
+
+
+######################
+#Initial condition
+h = 0.5
+h = 0.0
+domain.set_quantity('stage', Constant_height(x_slope, h))
+
+domain.check_integrity()
+
+  
+######################
+#Evolution
+for t in domain.evolve(yieldstep = 1, finaltime = 100.0):
+    domain.write_time()
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/check_sww_tsh.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/check_sww_tsh.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/check_sww_tsh.py	(revision 3560)
@@ -0,0 +1,54 @@
+
+######################
+# Module imports 
+import sys
+from os import sep, path
+
+import anuga.pyvolution.data_manager
+from load_mesh.loadASCII import import_mesh_file
+from shallow_water import Domain
+from anuga.pyvolution.pmesh2domain import pmesh_to_domain_instance
+
+def check_sww_tsh(sww_file, tsh_file, verbose = False):
+    [xmin, xmax, ymin, ymax, stagemin, stagemax] =  \
+           data_manager.extent_sww(sww_file)
+    if verbose == True:print "Extent of ", sww_file
+    if verbose == True:print "xmin", xmin 
+    if verbose == True:print "xmax", xmax 
+    if verbose == True:print "ymin", ymin 
+    if verbose == True:print "ymax", ymax 
+    if verbose == True:print "stagemin", stagemin 
+    if verbose == True:print "stagemax", stagemax
+    
+    domain = pmesh_to_domain_instance(tsh_file, Domain)
+    [tsh_xmin, tsh_xmax, tsh_ymin, tsh_ymax] =  domain.get_extent()
+    if verbose == True:print "Extent of ", tsh_file
+    if verbose == True:print "tsh_xmin", tsh_xmin 
+    if verbose == True:print "tsh_xmax", tsh_xmax 
+    if verbose == True:print "tsh_ymin", tsh_ymin 
+    if verbose == True:print "tsh_ymax", tsh_ymax
+    is_subset = xmin < tsh_xmin and xmax > tsh_xmax and  \
+                ymin < tsh_ymin and ymax > tsh_ymax 
+    if verbose == True:
+        if is_subset:
+            print "tsh within sww"
+        else:
+            print "WARNING: tsh NOT within sww"
+        
+  
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    """
+    Load in a mesh and data points with attributes.
+    Fit the attributes to the mesh.
+    Save a new mesh file.
+    """
+    import os, sys
+    usage = "usage: %s *.sww *.tsh" %os.path.basename(sys.argv[0])
+
+    if len(sys.argv) < 3:
+        print usage
+    else:
+        sww_file = sys.argv[1]
+        tsh_file = sys.argv[2]
+        check_sww_tsh(sww_file, tsh_file, verbose = True)
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/combine_pts.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/combine_pts.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/combine_pts.py	(revision 3560)
@@ -0,0 +1,185 @@
+"""Functionality for aggregation of points files
+
+   Ole Nielsen, Stephen Roberts, Duncan Gray
+   Geoscience Australia, 2005.   
+"""
+
+from anuga.utilities.polygon import outside_polygon, inside_polygon
+from Numeric import take, concatenate
+import time
+
+import exceptions
+class AttributeError(exceptions.Exception): pass
+
+def combine_rectangular_points_files(fine_points_file,
+                                     coarse_points_file,
+                                     output_points_file,
+                                     verbose = False):
+    """Add two point files by the union of the fine and coarse points.
+    
+       Course points that are in the extent of the fine points are removed.
+
+       The extent of the fine points file is assumed to be a rectangle, parallel
+       to the x and y axis.
+    """
+    
+    from load_mesh.loadASCII import import_points_file, extent, point_atts2array, export_points_file, add_point_dictionaries, take_points
+
+    
+    # load fine points file
+    if verbose: print "loading Point files"
+    fine = import_points_file(fine_points_file)
+    
+    # load course points file
+    coarse = import_points_file(coarse_points_file)
+        
+    if verbose: print "doing other stuff"
+    # convert to Numeric    
+    fine = point_atts2array(fine)
+    coarse = point_atts2array(coarse)
+    
+    #check that the attribute info is the same
+    #FIXME is not sorting this a problem?
+    if not fine['attributelist'].keys() == coarse['attributelist'].keys():
+        raise AttributeError
+    
+    # set points to the same geo ref -  say the fine points geo ref
+    if fine.has_key('geo_reference')and not fine['geo_reference'] is None:
+        if coarse.has_key('geo_reference'):
+            coarse['pointlist'] = \
+                fine['geo_reference'].change_points_geo_ref(coarse['pointlist'],
+                                                            points_geo_ref=coarse['geo_reference'])  
+    # find extent of course points
+    extent = extent(fine['pointlist'])    
+
+    # find out_points - coarse points outside of fine points extent
+
+    if verbose:
+        print "starting outside_polygon"
+        t0 = time.time()
+    outside_coarse_indices = outside_polygon(coarse['pointlist'],
+                                             extent, closed=True)
+    if verbose:
+        print "Points outside determined"
+        print 'That took %.2f seconds' %(time.time()-t0)
+
+    # Remove points from the coarse data
+    coarse = take_points(coarse, outside_coarse_indices)
+        
+    # add fine points and out_points
+    if verbose: print "Adding points"
+    combined = add_point_dictionaries(fine, coarse)
+
+    # save
+    if verbose: print "writing points"
+    export_points_file(output_points_file, combined)
+
+def add_points_files(fine_points_file,
+                     coarse_points_file,
+                     output_points_file,
+                     verbose = False):
+    """
+    """
+    
+    from load_mesh.loadASCII import import_points_file, extent, point_atts2array, export_points_file, add_point_dictionaries,take_points
+
+    
+    # load fine points file
+    if verbose:print "loading Point files"
+    try:
+        fine = import_points_file(fine_points_file,delimiter = ',')
+    except SyntaxError,e:
+        fine = import_points_file(fine_points_file,delimiter = ' ')
+    
+    
+    # load course points file
+    try:
+        coarse = import_points_file(coarse_points_file,
+                                              delimiter = ',')
+    except SyntaxError,e:
+        coarse = import_points_file(coarse_points_file,
+                                              delimiter = ' ')
+        
+    if verbose:print "doing other stuff"
+    # convert to Numeric    
+    fine = point_atts2array(fine)
+    coarse = point_atts2array(coarse)
+    
+    #check that the attribute info is the same
+    #FIXME is not sorting this a problem?
+    if not fine['attributelist'].keys() == coarse['attributelist'].keys():
+        raise AttributeError
+    
+    # set points to the same geo ref -  say the fine points geo ref
+    if fine.has_key('geo_reference')and not fine['geo_reference'] is None:
+        if coarse.has_key('geo_reference'):
+            coarse['pointlist'] = \
+             fine['geo_reference'].change_points_geo_ref(coarse['pointlist'],
+                                                         points_geo_ref=coarse['geo_reference'])  
+        
+    # add fine points and out_points
+    if verbose: print "Adding points"
+    combined = add_point_dictionaries(fine, coarse)
+
+    # save
+    if verbose: print "writing points"
+    export_points_file(output_points_file, combined)
+
+def reduce_points_to_mesh_extent(points_file,
+                                 mesh_file,
+                                 output_points_file,
+                                 verbose = False):
+    """
+    """    
+    
+    from load_mesh.loadASCII import import_points_file, extent, point_atts2array, export_points_file, add_point_dictionaries,take_points, import_mesh_file
+
+    
+    # load  points file
+    try:
+        points = import_points_file(points_file,delimiter = ',')
+    except SyntaxError,e:
+        points = import_points_file(points_file,delimiter = ' ')
+    
+    # load  mesh file
+    mesh = import_mesh_file(mesh_file)
+
+    # get extent of mesh
+    extent = extent(mesh['vertices'])
+    #print "extent",extent 
+    # set points to the same geo ref - the points geo ref
+    if points.has_key('geo_reference')and not points['geo_reference'] is None:
+        if mesh.has_key('geo_reference'):
+            extent = \
+             points['geo_reference'].change_points_geo_ref(extent,
+                                                           points_geo_ref=mesh['geo_reference'])  
+    #print "extent",extent 
+
+    inside_indices = inside_polygon(points['pointlist'],
+				    extent, closed=True)
+    #create a list of in points
+    points = take_points(points, inside_indices)
+
+    # save the list, along with geo-ref
+    export_points_file(output_points_file,points)
+    
+    #-------------------------------------------------------------
+if __name__ == "__main__":
+    """
+    Load in two data points files.
+    Save a new points file.
+    """
+    import os, sys
+    usage = "usage: %s fine_input.pts coarse_input.pts output.pts " \
+            %os.path.basename(sys.argv[0])
+
+    if len(sys.argv) < 4:
+        print usage
+    else:
+        fine_file  = sys.argv[1]
+        coarse_file = sys.argv[2]
+        output_file = sys.argv[3]
+        
+        combine_rectangular_points_files(fine_file,
+                                         coarse_file,
+                                         output_file)
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/cornell_room.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/cornell_room.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/cornell_room.py	(revision 3560)
@@ -0,0 +1,130 @@
+"""Example of shallow water wave equation.
+
+This is called Netherlands because it shows a dam with a gap in it and
+stylised housed behind it and below the water surface.
+
+"""
+
+######################
+# Module imports 
+#
+from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+     Transmissive_boundary, Time_boundary, Constant_height
+
+from mesh_factory import from_polyfile, rectangular
+from Numeric import array
+from math import sqrt
+#from least_squares import Interpolation
+from anuga.fit_interpolate.interpolate import Interpolate
+    
+
+print 'Creating domain'
+#data_points, _, data_values = from_polyfile('cornell_room_medres')
+#points, triangles, values = from_polyfile('hires2')
+data_points, _, data_values = from_polyfile('hires2')
+
+
+#Regrid onto numerically stable mesh
+#
+#Compute regular mesh based on resolution and extent of data
+data_points = array(data_points)
+pmax = max(data_points)
+pmin = min(data_points)
+
+M = len(data_points)
+
+N = int(0.8*sqrt(M))
+
+#print N
+
+mesh_points, vertices, boundary = rectangular(N, N, 
+					      len1=pmax[0]-pmin[0],
+                                              len2=pmax[1]-pmin[1],
+					      origin = pmin)
+					      
+
+#Compute smooth surface on new mesh based on values from old (regrid)
+print 'Interp'
+interp = Interpolate(mesh_points, vertices, alpha=10)
+mesh_values = interp.fit( data_points, data_values) # this has not been tested
+print 'Len mesh values', len(mesh_values)
+print 'Len mesh points', len(mesh_points)
+
+    
+#Create shallow water domain
+print 'Creating domain'
+domain = Domain(mesh_points, vertices) #, boundary)
+
+domain.check_integrity()
+domain.default_order = 2
+domain.smooth = True
+domain.reduction = min  #Looks a lot better on top of steep slopes
+
+print "Number of triangles = ", len(domain)
+
+domain.visualise = False
+domain.checkpoint = False
+domain.store = True    #Store for visualisation purposes
+domain.format = 'sww'   #Native netcdf visualisation format
+import sys, os
+root, ext = os.path.splitext(sys.argv[0])
+if domain.smooth is True:
+    s = 'smooth'
+else:
+    s = 'nonsmooth'        
+domain.filename = root + '_' + s
+
+#Set bed-slope and friction
+manning = 0.0
+
+print 'Field values'
+domain.set_quantity('elevation', mesh_values)
+domain.set_quantity('friction', manning)
+
+
+######################
+# Boundary conditions
+#
+print 'Boundaries'
+Br = Reflective_boundary(domain)
+domain.set_boundary({'exterior': Br})
+
+                  
+
+######################
+#Initial condition
+#
+print 'Initial condition'
+
+#Define water height as a lump in one corner
+def height(x, y):
+    from Numeric import zeros, Float
+    
+    N = len(x)
+    assert N == len(y)    
+
+    xmin = min(x); xmax = max(x)
+    ymin = min(y); ymax = max(y)
+
+    xrange = xmax - xmin
+    yrange = ymax - ymin    
+
+    z = zeros(N, Float)
+    for i in range(N):
+        if x[i] <= xmin + 0.25*xrange and y[i] <= ymin + 0.25*yrange:
+            z[i] = 300
+
+    return z
+
+domain.set_quantity('stage', height)
+
+E = domain.quantities['elevation'].vertex_values
+L = domain.quantities['stage'].vertex_values
+domain.set_quantity('stage', E+L)
+
+#Evolve
+for t in domain.evolve(yieldstep = 0.05, finaltime = 5.0):
+    domain.write_time()
+    
+
+    
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/cornell_room_medres.poly
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/cornell_room_medres.poly	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/cornell_room_medres.poly	(revision 3560)
@@ -0,0 +1,12420 @@
+POINTS
+1: 0 0 0
+2: 0 -8.7375 -3.81928e-007
+3: 0 -17.475 -7.63857e-007
+4: 0 -26.2125 -1.14578e-006
+5: 0 -34.95 -1.52771e-006
+6: 0 -43.6875 -1.90964e-006
+7: 0 -52.425 -2.29157e-006
+8: 0 -61.1625 -2.6735e-006
+9: 0 -69.9 -3.05543e-006
+10: 0 -78.6375 -3.43735e-006
+11: 0 -87.375 -3.81928e-006
+12: 0 -96.1125 -4.20121e-006
+13: 0 -104.85 -4.58314e-006
+14: 0 -113.588 -4.96507e-006
+15: 0 -122.325 -5.347e-006
+16: 0 -131.063 -5.72892e-006
+17: 0 -139.8 -6.11085e-006
+18: 0 -148.538 -6.49278e-006
+19: 0 -157.275 -6.87471e-006
+20: 0 -166.013 -7.25664e-006
+21: 0 -174.75 -7.63856e-006
+22: 0 -183.488 -8.02049e-006
+23: 0 -192.225 -8.40242e-006
+24: 0 -200.963 -8.78435e-006
+25: 0 -209.7 -9.16628e-006
+26: 0 -218.438 -9.54821e-006
+27: 0 -227.175 -9.93014e-006
+28: 0 -235.913 -1.03121e-005
+29: 0 -244.65 -1.0694e-005
+30: 0 -253.388 -1.10759e-005
+31: 0 -262.125 -1.14579e-005
+32: 0 -270.863 -1.18398e-005
+33: 0 -279.6 -1.22217e-005
+34: 0 -288.338 -1.26036e-005
+35: 0 -297.075 -1.29856e-005
+36: 0 -305.813 -1.33675e-005
+37: 0 -314.55 -1.37494e-005
+38: 0 -323.288 -1.41313e-005
+39: 0 -332.025 -1.45133e-005
+40: 0 -340.763 -1.48952e-005
+41: 0 -349.5 -1.52771e-005
+42: 0 -358.237 -1.56591e-005
+43: 0 -366.975 -1.6041e-005
+44: 0 -375.713 -1.64229e-005
+45: 0 -384.45 -1.68048e-005
+46: 0 -393.188 -1.71868e-005
+47: 0 -401.925 -1.75687e-005
+48: 0 -410.663 -1.79506e-005
+49: 0 -419.4 -1.83326e-005
+50: 0 -428.138 -1.87145e-005
+51: 0 -436.875 -1.90964e-005
+52: 0 -445.613 -1.94783e-005
+53: 0 -454.35 -1.98603e-005
+54: 0 -463.088 -2.02422e-005
+55: 0 -471.825 -2.06241e-005
+56: 0 -480.563 -2.10061e-005
+57: 0 -489.3 -2.1388e-005
+58: 0 -498.037 -2.17699e-005
+59: 0 -506.775 -2.21518e-005
+60: 0 -515.513 -2.25338e-005
+61: 0 -524.25 -2.29157e-005
+62: 0 -532.987 -2.32976e-005
+63: 0 -541.725 -2.36796e-005
+64: 0 -550.463 -2.40615e-005
+65: 0 -559.2 -2.44434e-005
+66: 8.6375 0 0
+67: 8.63672 -8.7375 -3.81928e-007
+68: 8.63594 -17.475 -7.63857e-007
+69: 8.63516 -26.2125 -1.14578e-006
+70: 8.63437 -34.95 -1.52771e-006
+71: 8.63359 -43.6875 -1.90964e-006
+72: 8.63281 -52.425 -2.29157e-006
+73: 8.63203 -61.1625 -2.6735e-006
+74: 8.63125 -69.9 -3.05543e-006
+75: 8.63047 -78.6375 -3.43735e-006
+76: 8.62969 -87.375 -3.81928e-006
+77: 8.62891 -96.1125 -4.20121e-006
+78: 8.62813 -104.85 -4.58314e-006
+79: 8.62734 -113.588 -4.96507e-006
+80: 8.62656 -122.325 -5.347e-006
+81: 8.62578 -131.063 -5.72892e-006
+82: 8.625 -139.8 -6.11085e-006
+83: 8.62422 -148.538 -6.49278e-006
+84: 8.62344 -157.275 -6.87471e-006
+85: 8.62266 -166.012 -7.25664e-006
+86: 8.62187 -174.75 -7.63856e-006
+87: 8.62109 -183.487 -8.02049e-006
+88: 8.62031 -192.225 -8.40242e-006
+89: 8.61953 -200.963 -8.78435e-006
+90: 8.61875 -209.7 -9.16628e-006
+91: 8.61797 -218.438 -9.54821e-006
+92: 8.61719 -227.175 -9.93014e-006
+93: 8.61641 -235.913 -1.03121e-005
+94: 8.61562 -244.65 -1.0694e-005
+95: 8.61484 -253.388 -1.10759e-005
+96: 8.61406 -262.125 -1.14578e-005
+97: 8.61328 -270.863 -1.18398e-005
+98: 8.6125 -279.6 -1.22217e-005
+99: 8.61172 -288.338 -1.26036e-005
+100: 8.61094 -297.075 -1.29856e-005
+101: 8.61016 -305.813 -1.33675e-005
+102: 8.60937 -314.55 -1.37494e-005
+103: 8.60859 -323.288 -1.41313e-005
+104: 8.60781 -332.025 -1.45133e-005
+105: 8.60703 -340.763 -1.48952e-005
+106: 8.60625 -349.5 -1.52771e-005
+107: 8.60547 -358.237 -1.56591e-005
+108: 8.60469 -366.975 -1.6041e-005
+109: 8.60391 -375.713 -1.64229e-005
+110: 8.60312 -384.45 -1.68048e-005
+111: 8.60234 -393.188 -1.71868e-005
+112: 8.60156 -401.925 -1.75687e-005
+113: 8.60078 -410.663 -1.79506e-005
+114: 8.6 -419.4 -1.83326e-005
+115: 8.59922 -428.138 -1.87145e-005
+116: 8.59844 -436.875 -1.90964e-005
+117: 8.59766 -445.613 -1.94783e-005
+118: 8.59687 -454.35 -1.98603e-005
+119: 8.59609 -463.088 -2.02422e-005
+120: 8.59531 -471.825 -2.06241e-005
+121: 8.59453 -480.563 -2.10061e-005
+122: 8.59375 -489.3 -2.1388e-005
+123: 8.59297 -498.038 -2.17699e-005
+124: 8.59219 -506.775 -2.21518e-005
+125: 8.59141 -515.513 -2.25338e-005
+126: 8.59062 -524.25 -2.29157e-005
+127: 8.58984 -532.987 -2.32976e-005
+128: 8.58906 -541.725 -2.36796e-005
+129: 8.58828 -550.463 -2.40615e-005
+130: 8.5875 -559.2 -2.44434e-005
+131: 17.275 0 0
+132: 17.2734 -8.7375 -3.81928e-007
+133: 17.2719 -17.475 -7.63857e-007
+134: 17.2703 -26.2125 -1.14578e-006
+135: 17.2687 -34.95 -1.52771e-006
+136: 17.2672 -43.6875 -1.90964e-006
+137: 17.2656 -52.425 -2.29157e-006
+138: 17.2641 -61.1625 -2.6735e-006
+139: 17.2625 -69.9 -3.05543e-006
+140: 17.2609 -78.6375 -3.43735e-006
+141: 17.2594 -87.375 -3.81928e-006
+142: 17.2578 -96.1125 -4.20121e-006
+143: 17.2563 -104.85 -4.58314e-006
+144: 17.2547 -113.588 -4.96507e-006
+145: 17.2531 -122.325 -5.347e-006
+146: 17.2516 -131.063 -5.72892e-006
+147: 17.25 -139.8 -6.11085e-006
+148: 17.2484 -148.538 -6.49278e-006
+149: 17.2469 -157.275 -6.87471e-006
+150: 17.2453 -166.012 -7.25664e-006
+151: 17.2437 -174.75 -7.63856e-006
+152: 17.2422 -183.487 -8.02049e-006
+153: 17.2406 -192.225 -8.40242e-006
+154: 17.2391 -200.963 -8.78435e-006
+155: 17.2375 -209.7 -9.16628e-006
+156: 17.2359 -218.438 -9.54821e-006
+157: 17.2344 -227.175 -9.93014e-006
+158: 17.2328 -235.913 -1.03121e-005
+159: 17.2312 -244.65 -1.0694e-005
+160: 17.2297 -253.388 -1.10759e-005
+161: 17.2281 -262.125 -1.14578e-005
+162: 17.2266 -270.863 -1.18398e-005
+163: 17.225 -279.6 -1.22217e-005
+164: 17.2234 -288.338 -1.26036e-005
+165: 17.2219 -297.075 -1.29856e-005
+166: 17.2203 -305.813 -1.33675e-005
+167: 17.2187 -314.55 -1.37494e-005
+168: 17.2172 -323.287 -1.41313e-005
+169: 17.2156 -332.025 -1.45133e-005
+170: 17.2141 -340.763 -1.48952e-005
+171: 17.2125 -349.5 -1.52771e-005
+172: 17.2109 -358.237 -1.56591e-005
+173: 17.2094 -366.975 -1.6041e-005
+174: 17.2078 -375.712 -1.64229e-005
+175: 17.2062 -384.45 -1.68048e-005
+176: 17.2047 -393.188 -1.71868e-005
+177: 17.2031 -401.925 -1.75687e-005
+178: 17.2016 -410.663 -1.79506e-005
+179: 17.2 -419.4 -1.83326e-005
+180: 17.1984 -428.138 -1.87145e-005
+181: 17.1969 -436.875 -1.90964e-005
+182: 17.1953 -445.613 -1.94783e-005
+183: 17.1937 -454.35 -1.98603e-005
+184: 17.1922 -463.088 -2.02422e-005
+185: 17.1906 -471.825 -2.06241e-005
+186: 17.1891 -480.563 -2.10061e-005
+187: 17.1875 -489.3 -2.1388e-005
+188: 17.1859 -498.037 -2.17699e-005
+189: 17.1844 -506.775 -2.21518e-005
+190: 17.1828 -515.513 -2.25338e-005
+191: 17.1812 -524.25 -2.29157e-005
+192: 17.1797 -532.987 -2.32976e-005
+193: 17.1781 -541.725 -2.36796e-005
+194: 17.1766 -550.463 -2.40615e-005
+195: 17.175 -559.2 -2.44434e-005
+196: 25.9125 0 0
+197: 25.9102 -8.7375 -3.81928e-007
+198: 25.9078 -17.475 -7.63857e-007
+199: 25.9055 -26.2125 -1.14578e-006
+200: 25.9031 -34.95 -1.52771e-006
+201: 25.9008 -43.6875 -1.90964e-006
+202: 25.8984 -52.425 -2.29157e-006
+203: 25.8961 -61.1625 -2.6735e-006
+204: 25.8938 -69.9 -3.05543e-006
+205: 25.8914 -78.6375 -3.43735e-006
+206: 25.8891 -87.375 -3.81928e-006
+207: 25.8867 -96.1125 -4.20121e-006
+208: 25.8844 -104.85 -4.58314e-006
+209: 25.882 -113.588 -4.96507e-006
+210: 25.8797 -122.325 -5.347e-006
+211: 25.8773 -131.063 -5.72892e-006
+212: 25.875 -139.8 -6.11085e-006
+213: 25.8727 -148.538 -6.49278e-006
+214: 25.8703 -157.275 -6.87471e-006
+215: 25.868 -166.012 -7.25664e-006
+216: 25.8656 -174.75 -7.63856e-006
+217: 25.8633 -183.487 -8.02049e-006
+218: 25.8609 -192.225 -8.40242e-006
+219: 25.8586 -200.963 -8.78435e-006
+220: 25.8562 -209.7 -9.16628e-006
+221: 25.8539 -218.438 -9.54821e-006
+222: 25.8516 -227.175 -9.93014e-006
+223: 25.8492 -235.913 -1.03121e-005
+224: 25.8469 -244.65 -1.0694e-005
+225: 25.8445 -253.388 -1.10759e-005
+226: 25.8422 -262.125 -1.14578e-005
+227: 25.8398 -270.863 -1.18398e-005
+228: 25.8375 -279.6 -1.22217e-005
+229: 25.8352 -288.338 -1.26036e-005
+230: 25.8328 -297.075 -1.29856e-005
+231: 25.8305 -305.813 -1.33675e-005
+232: 25.8281 -314.55 -1.37494e-005
+233: 25.8258 -323.287 -1.41313e-005
+234: 25.8234 -332.025 -1.45133e-005
+235: 25.8211 -340.763 -1.48952e-005
+236: 25.8187 -349.5 -1.52771e-005
+237: 25.8164 -358.237 -1.56591e-005
+238: 25.8141 -366.975 -1.6041e-005
+239: 25.8117 -375.712 -1.64229e-005
+240: 25.8094 -384.45 -1.68048e-005
+241: 25.807 -393.188 -1.71868e-005
+242: 25.8047 -401.925 -1.75687e-005
+243: 25.8023 -410.663 -1.79506e-005
+244: 25.8 -419.4 -1.83326e-005
+245: 25.7977 -428.138 -1.87145e-005
+246: 25.7953 -436.875 -1.90964e-005
+247: 25.793 -445.613 -1.94783e-005
+248: 25.7906 -454.35 -1.98603e-005
+249: 25.7883 -463.088 -2.02422e-005
+250: 25.7859 -471.825 -2.06241e-005
+251: 25.7836 -480.563 -2.10061e-005
+252: 25.7813 -489.3 -2.1388e-005
+253: 25.7789 -498.038 -2.17699e-005
+254: 25.7766 -506.775 -2.21518e-005
+255: 25.7742 -515.513 -2.25338e-005
+256: 25.7719 -524.25 -2.29157e-005
+257: 25.7695 -532.987 -2.32976e-005
+258: 25.7672 -541.725 -2.36796e-005
+259: 25.7648 -550.463 -2.40615e-005
+260: 25.7625 -559.2 -2.44434e-005
+261: 34.55 0 0
+262: 34.5469 -8.7375 -3.81928e-007
+263: 34.5437 -17.475 -7.63857e-007
+264: 34.5406 -26.2125 -1.14578e-006
+265: 34.5375 -34.95 -1.52771e-006
+266: 34.5344 -43.6875 -1.90964e-006
+267: 34.5313 -52.425 -2.29157e-006
+268: 34.5281 -61.1625 -2.6735e-006
+269: 34.525 -69.9 -3.05543e-006
+270: 34.5219 -78.6375 -3.43735e-006
+271: 34.5188 -87.375 -3.81928e-006
+272: 34.5156 -96.1125 -4.20121e-006
+273: 34.5125 -104.85 -4.58314e-006
+274: 34.5094 -113.588 -4.96507e-006
+275: 34.5062 -122.325 -5.347e-006
+276: 34.5031 -131.063 -5.72892e-006
+277: 34.5 -139.8 -6.11085e-006
+278: 34.4969 -148.538 -6.49278e-006
+279: 34.4938 -157.275 -6.87471e-006
+280: 34.4906 -166.012 -7.25664e-006
+281: 34.4875 -174.75 -7.63856e-006
+282: 34.4844 -183.487 -8.02049e-006
+283: 34.4812 -192.225 -8.40242e-006
+284: 34.4781 -200.963 -8.78435e-006
+285: 34.475 -209.7 -9.16628e-006
+286: 34.4719 -218.438 -9.54821e-006
+287: 34.4688 -227.175 -9.93014e-006
+288: 34.4656 -235.913 -1.03121e-005
+289: 34.4625 -244.65 -1.0694e-005
+290: 34.4594 -253.388 -1.10759e-005
+291: 34.4562 -262.125 -1.14578e-005
+292: 34.4531 -270.863 -1.18398e-005
+293: 34.45 -279.6 -1.22217e-005
+294: 34.4469 -288.338 -1.26036e-005
+295: 34.4437 -297.075 -1.29856e-005
+296: 34.4406 -305.813 -1.33675e-005
+297: 34.4375 -314.55 -1.37494e-005
+298: 34.4344 -323.287 -1.41313e-005
+299: 34.4312 -332.025 -1.45133e-005
+300: 34.4281 -340.763 -1.48952e-005
+301: 34.425 -349.5 -1.52771e-005
+302: 34.4219 -358.237 -1.56591e-005
+303: 34.4187 -366.975 -1.6041e-005
+304: 34.4156 -375.712 -1.64229e-005
+305: 34.4125 -384.45 -1.68048e-005
+306: 34.4094 -393.188 -1.71868e-005
+307: 34.4063 -401.925 -1.75687e-005
+308: 34.4031 -410.663 -1.79506e-005
+309: 34.4 -419.4 -1.83326e-005
+310: 34.3969 -428.138 -1.87145e-005
+311: 34.3937 -436.875 -1.90964e-005
+312: 34.3906 -445.613 -1.94783e-005
+313: 34.3875 -454.35 -1.98603e-005
+314: 34.3844 -463.088 -2.02422e-005
+315: 34.3812 -471.825 -2.06241e-005
+316: 34.3781 -480.563 -2.10061e-005
+317: 34.375 -489.3 -2.1388e-005
+318: 34.3719 -498.037 -2.17699e-005
+319: 34.3688 -506.775 -2.21518e-005
+320: 34.3656 -515.513 -2.25338e-005
+321: 34.3625 -524.25 -2.29157e-005
+322: 34.3594 -532.987 -2.32976e-005
+323: 34.3562 -541.725 -2.36796e-005
+324: 34.3531 -550.463 -2.40615e-005
+325: 34.35 -559.2 -2.44434e-005
+326: 43.1875 0 0
+327: 43.1836 -8.7375 -3.81928e-007
+328: 43.1797 -17.475 -7.63857e-007
+329: 43.1758 -26.2125 -1.14578e-006
+330: 43.1719 -34.95 -1.52771e-006
+331: 43.168 -43.6875 -1.90964e-006
+332: 43.1641 -52.425 -2.29157e-006
+333: 43.1602 -61.1625 -2.6735e-006
+334: 43.1563 -69.9 -3.05543e-006
+335: 43.1523 -78.6375 -3.43735e-006
+336: 43.1484 -87.375 -3.81928e-006
+337: 43.1445 -96.1125 -4.20121e-006
+338: 43.1406 -104.85 -4.58314e-006
+339: 43.1367 -113.588 -4.96507e-006
+340: 43.1328 -122.325 -5.347e-006
+341: 43.1289 -131.063 -5.72892e-006
+342: 43.125 -139.8 -6.11085e-006
+343: 43.1211 -148.538 -6.49278e-006
+344: 43.1172 -157.275 -6.87471e-006
+345: 43.1133 -166.012 -7.25664e-006
+346: 43.1094 -174.75 -7.63856e-006
+347: 43.1055 -183.487 -8.02049e-006
+348: 43.1016 -192.225 -8.40242e-006
+349: 43.0977 -200.963 -8.78435e-006
+350: 43.0938 -209.7 -9.16628e-006
+351: 43.0898 -218.438 -9.54821e-006
+352: 43.0859 -227.175 -9.93014e-006
+353: 43.082 -235.913 -1.03121e-005
+354: 43.0781 -244.65 -1.0694e-005
+355: 43.0742 -253.387 -1.10759e-005
+356: 43.0703 -262.125 -1.14578e-005
+357: 43.0664 -270.863 -1.18398e-005
+358: 43.0625 -279.6 -1.22217e-005
+359: 43.0586 -288.338 -1.26036e-005
+360: 43.0547 -297.075 -1.29856e-005
+361: 43.0508 -305.813 -1.33675e-005
+362: 43.0469 -314.55 -1.37494e-005
+363: 43.043 -323.287 -1.41313e-005
+364: 43.0391 -332.025 -1.45133e-005
+365: 43.0351 -340.763 -1.48952e-005
+366: 43.0312 -349.5 -1.52771e-005
+367: 43.0273 -358.237 -1.56591e-005
+368: 43.0234 -366.975 -1.6041e-005
+369: 43.0195 -375.712 -1.64229e-005
+370: 43.0156 -384.45 -1.68048e-005
+371: 43.0117 -393.188 -1.71868e-005
+372: 43.0078 -401.925 -1.75687e-005
+373: 43.0039 -410.663 -1.79506e-005
+374: 43 -419.4 -1.83326e-005
+375: 42.9961 -428.138 -1.87145e-005
+376: 42.9922 -436.875 -1.90964e-005
+377: 42.9883 -445.613 -1.94783e-005
+378: 42.9844 -454.35 -1.98603e-005
+379: 42.9805 -463.088 -2.02422e-005
+380: 42.9766 -471.825 -2.06241e-005
+381: 42.9727 -480.563 -2.10061e-005
+382: 42.9688 -489.3 -2.1388e-005
+383: 42.9648 -498.038 -2.17699e-005
+384: 42.9609 -506.775 -2.21518e-005
+385: 42.957 -515.513 -2.25338e-005
+386: 42.9531 -524.25 -2.29157e-005
+387: 42.9492 -532.987 -2.32976e-005
+388: 42.9453 -541.725 -2.36796e-005
+389: 42.9414 -550.463 -2.40615e-005
+390: 42.9375 -559.2 -2.44434e-005
+391: 51.825 0 0
+392: 51.8203 -8.7375 -3.81928e-007
+393: 51.8156 -17.475 -7.63857e-007
+394: 51.8109 -26.2125 -1.14578e-006
+395: 51.8062 -34.95 -1.52771e-006
+396: 51.8016 -43.6875 -1.90964e-006
+397: 51.7969 -52.425 -2.29157e-006
+398: 51.7922 -61.1625 -2.6735e-006
+399: 51.7875 -69.9 -3.05543e-006
+400: 51.7828 -78.6375 -3.43735e-006
+401: 51.7781 -87.375 -3.81928e-006
+402: 51.7734 -96.1125 -4.20121e-006
+403: 51.7688 -104.85 -4.58314e-006
+404: 51.7641 -113.588 -4.96507e-006
+405: 51.7594 -122.325 -5.347e-006
+406: 51.7547 -131.063 -5.72892e-006
+407: 51.75 -139.8 -6.11085e-006
+408: 51.7453 -148.538 -6.49278e-006
+409: 51.7406 -157.275 -6.87471e-006
+410: 51.7359 -166.012 -7.25664e-006
+411: 51.7312 -174.75 -7.63856e-006
+412: 51.7266 -183.487 -8.02049e-006
+413: 51.7219 -192.225 -8.40242e-006
+414: 51.7172 -200.963 -8.78435e-006
+415: 51.7125 -209.7 -9.16628e-006
+416: 51.7078 -218.438 -9.54821e-006
+417: 51.7031 -227.175 -9.93014e-006
+418: 51.6984 -235.913 -1.03121e-005
+419: 51.6937 -244.65 -1.0694e-005
+420: 51.6891 -253.387 -1.10759e-005
+421: 51.6844 -262.125 -1.14578e-005
+422: 51.6797 -270.862 -1.18398e-005
+423: 51.675 -279.6 -1.22217e-005
+424: 51.6703 -288.338 -1.26036e-005
+425: 51.6656 -297.075 -1.29856e-005
+426: 51.6609 -305.813 -1.33675e-005
+427: 51.6562 -314.55 -1.37494e-005
+428: 51.6516 -323.287 -1.41313e-005
+429: 51.6469 -332.025 -1.45133e-005
+430: 51.6422 -340.763 -1.48952e-005
+431: 51.6375 -349.5 -1.52771e-005
+432: 51.6328 -358.237 -1.56591e-005
+433: 51.6281 -366.975 -1.6041e-005
+434: 51.6234 -375.712 -1.64229e-005
+435: 51.6187 -384.45 -1.68048e-005
+436: 51.6141 -393.188 -1.71868e-005
+437: 51.6094 -401.925 -1.75687e-005
+438: 51.6047 -410.663 -1.79506e-005
+439: 51.6 -419.4 -1.83326e-005
+440: 51.5953 -428.138 -1.87145e-005
+441: 51.5906 -436.875 -1.90964e-005
+442: 51.5859 -445.613 -1.94783e-005
+443: 51.5812 -454.35 -1.98603e-005
+444: 51.5766 -463.088 -2.02422e-005
+445: 51.5719 -471.825 -2.06241e-005
+446: 51.5672 -480.563 -2.10061e-005
+447: 51.5625 -489.3 -2.1388e-005
+448: 51.5578 -498.037 -2.17699e-005
+449: 51.5531 -506.775 -2.21518e-005
+450: 51.5484 -515.513 -2.25338e-005
+451: 51.5437 -524.25 -2.29157e-005
+452: 51.5391 -532.987 -2.32976e-005
+453: 51.5344 -541.725 -2.36796e-005
+454: 51.5297 -550.463 -2.40615e-005
+455: 51.525 -559.2 -2.44434e-005
+456: 60.4625 0 0
+457: 60.457 -8.7375 -3.81928e-007
+458: 60.4516 -17.475 -7.63857e-007
+459: 60.4461 -26.2125 -1.14578e-006
+460: 60.4406 -34.95 -1.52771e-006
+461: 60.4352 -43.6875 -1.90964e-006
+462: 60.4297 -52.425 -2.29157e-006
+463: 60.4242 -61.1625 -2.6735e-006
+464: 60.4187 -69.9 -3.05543e-006
+465: 60.4133 -78.6375 -3.43735e-006
+466: 60.4078 -87.375 -3.81928e-006
+467: 60.4023 -96.1125 -4.20121e-006
+468: 60.3969 -104.85 -4.58314e-006
+469: 60.3914 -113.588 -4.96507e-006
+470: 60.3859 -122.325 -5.347e-006
+471: 60.3805 -131.063 -5.72892e-006
+472: 60.375 -139.8 -6.11085e-006
+473: 60.3695 -148.538 -6.49278e-006
+474: 60.3641 -157.275 -6.87471e-006
+475: 60.3586 -166.012 -7.25664e-006
+476: 60.3531 -174.75 -7.63856e-006
+477: 60.3477 -183.487 -8.02049e-006
+478: 60.3422 -192.225 -8.40242e-006
+479: 60.3367 -200.963 -8.78435e-006
+480: 60.3312 -209.7 -9.16628e-006
+481: 60.3258 -218.438 -9.54821e-006
+482: 60.3203 -227.175 -9.93014e-006
+483: 60.3148 -235.913 -1.03121e-005
+484: 60.3094 -244.65 -1.0694e-005
+485: 60.3039 -253.387 -1.10759e-005
+486: 60.2984 -262.125 -1.14578e-005
+487: 60.293 -270.862 -1.18398e-005
+488: 60.2875 -279.6 -1.22217e-005
+489: 60.282 -288.338 -1.26036e-005
+490: 60.2766 -297.075 -1.29856e-005
+491: 60.2711 -305.813 -1.33675e-005
+492: 60.2656 -314.55 -1.37494e-005
+493: 60.2602 -323.287 -1.41313e-005
+494: 60.2547 -332.025 -1.45133e-005
+495: 60.2492 -340.763 -1.48952e-005
+496: 60.2437 -349.5 -1.52771e-005
+497: 60.2383 -358.237 -1.56591e-005
+498: 60.2328 -366.975 -1.6041e-005
+499: 60.2273 -375.712 -1.64229e-005
+500: 60.2219 -384.45 -1.68048e-005
+501: 60.2164 -393.188 -1.71868e-005
+502: 60.2109 -401.925 -1.75687e-005
+503: 60.2055 -410.663 -1.79506e-005
+504: 60.2 -419.4 -1.83326e-005
+505: 60.1945 -428.138 -1.87145e-005
+506: 60.1891 -436.875 -1.90964e-005
+507: 60.1836 -445.613 -1.94783e-005
+508: 60.1781 -454.35 -1.98603e-005
+509: 60.1727 -463.088 -2.02422e-005
+510: 60.1672 -471.825 -2.06241e-005
+511: 60.1617 -480.563 -2.10061e-005
+512: 60.1563 -489.3 -2.1388e-005
+513: 60.1508 -498.038 -2.17699e-005
+514: 60.1453 -506.775 -2.21518e-005
+515: 60.1398 -515.513 -2.25338e-005
+516: 60.1344 -524.25 -2.29157e-005
+517: 60.1289 -532.987 -2.32976e-005
+518: 60.1234 -541.725 -2.36796e-005
+519: 60.118 -550.463 -2.40615e-005
+520: 60.1125 -559.2 -2.44434e-005
+521: 69.1 0 0
+522: 69.0938 -8.7375 -3.81928e-007
+523: 69.0875 -17.475 -7.63857e-007
+524: 69.0812 -26.2125 -1.14578e-006
+525: 69.075 -34.95 -1.52771e-006
+526: 69.0687 -43.6875 -1.90964e-006
+527: 69.0625 -52.425 -2.29157e-006
+528: 69.0562 -61.1625 -2.6735e-006
+529: 69.05 -69.9 -3.05543e-006
+530: 69.0438 -78.6375 -3.43735e-006
+531: 69.0375 -87.375 -3.81928e-006
+532: 69.0313 -96.1125 -4.20121e-006
+533: 69.025 -104.85 -4.58314e-006
+534: 69.0188 -113.588 -4.96507e-006
+535: 69.0125 -122.325 -5.347e-006
+536: 69.0062 -131.063 -5.72892e-006
+537: 69 -139.8 -6.11085e-006
+538: 68.9938 -148.538 -6.49278e-006
+539: 68.9875 -157.275 -6.87471e-006
+540: 68.9812 -166.012 -7.25664e-006
+541: 68.975 -174.75 -7.63856e-006
+542: 68.9688 -183.487 -8.02049e-006
+543: 68.9625 -192.225 -8.40242e-006
+544: 68.9562 -200.963 -8.78435e-006
+545: 68.95 -209.7 -9.16628e-006
+546: 68.9437 -218.438 -9.54821e-006
+547: 68.9375 -227.175 -9.93014e-006
+548: 68.9312 -235.913 -1.03121e-005
+549: 68.925 -244.65 -1.0694e-005
+550: 68.9187 -253.387 -1.10759e-005
+551: 68.9125 -262.125 -1.14578e-005
+552: 68.9062 -270.862 -1.18398e-005
+553: 68.9 -279.6 -1.22217e-005
+554: 68.8937 -288.338 -1.26036e-005
+555: 68.8875 -297.075 -1.29856e-005
+556: 68.8812 -305.813 -1.33675e-005
+557: 68.875 -314.55 -1.37494e-005
+558: 68.8687 -323.287 -1.41313e-005
+559: 68.8625 -332.025 -1.45133e-005
+560: 68.8562 -340.763 -1.48952e-005
+561: 68.85 -349.5 -1.52771e-005
+562: 68.8437 -358.237 -1.56591e-005
+563: 68.8375 -366.975 -1.6041e-005
+564: 68.8312 -375.712 -1.64229e-005
+565: 68.825 -384.45 -1.68048e-005
+566: 68.8187 -393.188 -1.71868e-005
+567: 68.8125 -401.925 -1.75687e-005
+568: 68.8062 -410.663 -1.79506e-005
+569: 68.8 -419.4 -1.83326e-005
+570: 68.7937 -428.138 -1.87145e-005
+571: 68.7875 -436.875 -1.90964e-005
+572: 68.7813 -445.613 -1.94783e-005
+573: 68.775 -454.35 -1.98603e-005
+574: 68.7687 -463.088 -2.02422e-005
+575: 68.7625 -471.825 -2.06241e-005
+576: 68.7562 -480.563 -2.10061e-005
+577: 68.75 -489.3 -2.1388e-005
+578: 68.7438 -498.037 -2.17699e-005
+579: 68.7375 -506.775 -2.21518e-005
+580: 68.7313 -515.513 -2.25338e-005
+581: 68.725 -524.25 -2.29157e-005
+582: 68.7188 -532.987 -2.32976e-005
+583: 68.7125 -541.725 -2.36796e-005
+584: 68.7062 -550.463 -2.40615e-005
+585: 68.7 -559.2 -2.44434e-005
+586: 77.7375 0 0
+587: 77.7305 -8.7375 -3.81928e-007
+588: 77.7234 -17.475 -7.63857e-007
+589: 77.7164 -26.2125 -1.14578e-006
+590: 77.7094 -34.95 -1.52771e-006
+591: 77.7023 -43.6875 -1.90964e-006
+592: 77.6953 -52.425 -2.29157e-006
+593: 77.6883 -61.1625 -2.6735e-006
+594: 77.6813 -69.9 -3.05543e-006
+595: 77.6742 -78.6375 -3.43735e-006
+596: 77.6672 -87.375 -3.81928e-006
+597: 77.6602 -96.1125 -4.20121e-006
+598: 77.6531 -104.85 -4.58314e-006
+599: 77.6461 -113.588 -4.96507e-006
+600: 77.6391 -122.325 -5.347e-006
+601: 77.632 -131.063 -5.72892e-006
+602: 77.625 -139.8 -6.11085e-006
+603: 77.618 -148.538 -6.49278e-006
+604: 77.6109 -157.275 -6.87471e-006
+605: 77.6039 -166.012 -7.25664e-006
+606: 77.5969 -174.75 -7.63856e-006
+607: 77.5898 -183.487 -8.02049e-006
+608: 77.5828 -192.225 -8.40242e-006
+609: 77.5758 -200.963 -8.78435e-006
+610: 77.5687 -209.7 -9.16628e-006
+611: 77.5617 -218.438 -9.54821e-006
+612: 77.5547 -227.175 -9.93014e-006
+613: 77.5476 -235.913 -1.03121e-005
+614: 77.5406 -244.65 -1.0694e-005
+615: 77.5336 -253.387 -1.10759e-005
+616: 77.5266 -262.125 -1.14578e-005
+617: 77.5195 -270.862 -1.18398e-005
+618: 77.5125 -279.6 -1.22217e-005
+619: 77.5055 -288.338 -1.26036e-005
+620: 77.4984 -297.075 -1.29856e-005
+621: 77.4914 -305.813 -1.33675e-005
+622: 77.4844 -314.55 -1.37494e-005
+623: 77.4773 -323.287 -1.41313e-005
+624: 77.4703 -332.025 -1.45133e-005
+625: 77.4633 -340.763 -1.48952e-005
+626: 77.4562 -349.5 -1.52771e-005
+627: 77.4492 -358.237 -1.56591e-005
+628: 77.4422 -366.975 -1.6041e-005
+629: 77.4352 -375.712 -1.64229e-005
+630: 77.4281 -384.45 -1.68048e-005
+631: 77.4211 -393.188 -1.71868e-005
+632: 77.414 -401.925 -1.75687e-005
+633: 77.407 -410.663 -1.79506e-005
+634: 77.4 -419.4 -1.83326e-005
+635: 77.393 -428.138 -1.87145e-005
+636: 77.3859 -436.875 -1.90964e-005
+637: 77.3789 -445.613 -1.94783e-005
+638: 77.3719 -454.35 -1.98603e-005
+639: 77.3648 -463.088 -2.02422e-005
+640: 77.3578 -471.825 -2.06241e-005
+641: 77.3508 -480.563 -2.10061e-005
+642: 77.3438 -489.3 -2.1388e-005
+643: 77.3367 -498.038 -2.17699e-005
+644: 77.3297 -506.775 -2.21518e-005
+645: 77.3227 -515.513 -2.25338e-005
+646: 77.3156 -524.25 -2.29157e-005
+647: 77.3086 -532.987 -2.32976e-005
+648: 77.3016 -541.725 -2.36796e-005
+649: 77.2945 -550.463 -2.40615e-005
+650: 77.2875 -559.2 -2.44434e-005
+651: 86.375 0 0
+652: 86.3672 -8.7375 -3.81928e-007
+653: 86.3594 -17.475 -7.63857e-007
+654: 86.3516 -26.2125 -1.14578e-006
+655: 86.3438 -34.95 -1.52771e-006
+656: 86.3359 -43.6875 -1.90964e-006
+657: 86.3281 -52.425 -2.29157e-006
+658: 86.3203 -61.1625 -2.6735e-006
+659: 86.3125 -69.9 -3.05543e-006
+660: 86.3047 -78.6375 -3.43735e-006
+661: 86.2969 -87.375 -3.81928e-006
+662: 86.2891 -96.1125 -4.20121e-006
+663: 86.2813 -104.85 -4.58314e-006
+664: 86.2734 -113.588 -4.96507e-006
+665: 86.2656 -122.325 -5.347e-006
+666: 86.2578 -131.063 -5.72892e-006
+667: 86.25 -139.8 -6.11085e-006
+668: 86.2422 -148.538 -6.49278e-006
+669: 86.2344 -157.275 -6.87471e-006
+670: 86.2266 -166.012 -7.25664e-006
+671: 86.2188 -174.75 -7.63856e-006
+672: 86.2109 -183.487 -8.02049e-006
+673: 86.2031 -192.225 -8.40242e-006
+674: 86.1953 -200.963 -8.78435e-006
+675: 86.1875 -209.7 -9.16628e-006
+676: 86.1797 -218.438 165
+677: 86.1719 -227.175 -9.93014e-006
+678: 86.164 -235.913 -1.03121e-005
+679: 86.1562 -244.65 -1.0694e-005
+680: 86.1484 -253.387 -1.10759e-005
+681: 86.1406 -262.125 -1.14578e-005
+682: 86.1328 -270.862 -1.18398e-005
+683: 86.125 -279.6 -1.22217e-005
+684: 86.1172 -288.338 -1.26036e-005
+685: 86.1094 -297.075 -1.29856e-005
+686: 86.1015 -305.813 -1.33675e-005
+687: 86.0937 -314.55 -1.37494e-005
+688: 86.0859 -323.287 -1.41313e-005
+689: 86.0781 -332.025 -1.45133e-005
+690: 86.0703 -340.763 -1.48952e-005
+691: 86.0625 -349.5 -1.52771e-005
+692: 86.0547 -358.237 -1.56591e-005
+693: 86.0469 -366.975 -1.6041e-005
+694: 86.0391 -375.712 -1.64229e-005
+695: 86.0312 -384.45 -1.68048e-005
+696: 86.0234 -393.188 -1.71868e-005
+697: 86.0156 -401.925 -1.75687e-005
+698: 86.0078 -410.663 -1.79506e-005
+699: 86 -419.4 -1.83326e-005
+700: 85.9922 -428.138 -1.87145e-005
+701: 85.9844 -436.875 -1.90964e-005
+702: 85.9766 -445.613 -1.94783e-005
+703: 85.9688 -454.35 -1.98603e-005
+704: 85.9609 -463.088 -2.02422e-005
+705: 85.9531 -471.825 -2.06241e-005
+706: 85.9453 -480.563 -2.10061e-005
+707: 85.9375 -489.3 -2.1388e-005
+708: 85.9297 -498.037 -2.17699e-005
+709: 85.9219 -506.775 -2.21518e-005
+710: 85.9141 -515.513 -2.25338e-005
+711: 85.9063 -524.25 -2.29157e-005
+712: 85.8984 -532.987 -2.32976e-005
+713: 85.8906 -541.725 -2.36796e-005
+714: 85.8828 -550.463 -2.40615e-005
+715: 85.875 -559.2 -2.44434e-005
+716: 95.0125 0 0
+717: 95.0039 -8.7375 -3.81928e-007
+718: 94.9953 -17.475 -7.63857e-007
+719: 94.9867 -26.2125 -1.14578e-006
+720: 94.9781 -34.95 -1.52771e-006
+721: 94.9695 -43.6875 -1.90964e-006
+722: 94.9609 -52.425 -2.29157e-006
+723: 94.9523 -61.1625 -2.6735e-006
+724: 94.9438 -69.9 -3.05543e-006
+725: 94.9352 -78.6375 -3.43735e-006
+726: 94.9266 -87.375 -3.81928e-006
+727: 94.918 -96.1125 -4.20121e-006
+728: 94.9094 -104.85 -4.58314e-006
+729: 94.9008 -113.588 -4.96507e-006
+730: 94.8922 -122.325 -5.347e-006
+731: 94.8836 -131.063 -5.72892e-006
+732: 94.875 -139.8 -6.11085e-006
+733: 94.8664 -148.538 -6.49278e-006
+734: 94.8578 -157.275 -6.87471e-006
+735: 94.8492 -166.012 -7.25664e-006
+736: 94.8406 -174.75 -7.63856e-006
+737: 94.832 -183.487 165
+738: 94.8234 -192.225 165
+739: 94.8148 -200.963 165
+740: 94.8062 -209.7 165
+741: 94.7976 -218.438 165
+742: 94.789 -227.175 165
+743: 94.7805 -235.913 -1.03121e-005
+744: 94.7719 -244.65 -1.0694e-005
+745: 94.7633 -253.387 -1.10759e-005
+746: 94.7547 -262.125 -1.14578e-005
+747: 94.7461 -270.862 -1.18398e-005
+748: 94.7375 -279.6 -1.22217e-005
+749: 94.7289 -288.337 -1.26036e-005
+750: 94.7203 -297.075 -1.29856e-005
+751: 94.7117 -305.813 -1.33675e-005
+752: 94.7031 -314.55 -1.37494e-005
+753: 94.6945 -323.287 -1.41313e-005
+754: 94.6859 -332.025 -1.45133e-005
+755: 94.6773 -340.763 -1.48952e-005
+756: 94.6687 -349.5 -1.52771e-005
+757: 94.6601 -358.237 -1.56591e-005
+758: 94.6516 -366.975 -1.6041e-005
+759: 94.643 -375.712 -1.64229e-005
+760: 94.6344 -384.45 -1.68048e-005
+761: 94.6258 -393.188 -1.71868e-005
+762: 94.6172 -401.925 -1.75687e-005
+763: 94.6086 -410.663 -1.79506e-005
+764: 94.6 -419.4 -1.83326e-005
+765: 94.5914 -428.138 -1.87145e-005
+766: 94.5828 -436.875 -1.90964e-005
+767: 94.5742 -445.613 -1.94783e-005
+768: 94.5656 -454.35 -1.98603e-005
+769: 94.557 -463.088 -2.02422e-005
+770: 94.5484 -471.825 -2.06241e-005
+771: 94.5398 -480.563 -2.10061e-005
+772: 94.5313 -489.3 -2.1388e-005
+773: 94.5227 -498.038 -2.17699e-005
+774: 94.5141 -506.775 -2.21518e-005
+775: 94.5055 -515.513 -2.25338e-005
+776: 94.4969 -524.25 -2.29157e-005
+777: 94.4883 -532.987 -2.32976e-005
+778: 94.4797 -541.725 -2.36796e-005
+779: 94.4711 -550.463 -2.40615e-005
+780: 94.4625 -559.2 -2.44434e-005
+781: 103.65 0 0
+782: 103.641 -8.7375 -3.81928e-007
+783: 103.631 -17.475 -7.63857e-007
+784: 103.622 -26.2125 -1.14578e-006
+785: 103.613 -34.95 -1.52771e-006
+786: 103.603 -43.6875 -1.90964e-006
+787: 103.594 -52.425 -2.29157e-006
+788: 103.584 -61.1625 -2.6735e-006
+789: 103.575 -69.9 -3.05543e-006
+790: 103.566 -78.6375 -3.43735e-006
+791: 103.556 -87.375 -3.81928e-006
+792: 103.547 -96.1125 -4.20121e-006
+793: 103.538 -104.85 -4.58314e-006
+794: 103.528 -113.588 -4.96507e-006
+795: 103.519 -122.325 -5.347e-006
+796: 103.509 -131.063 -5.72892e-006
+797: 103.5 -139.8 -6.11085e-006
+798: 103.491 -148.538 -6.49278e-006
+799: 103.481 -157.275 165
+800: 103.472 -166.012 165
+801: 103.462 -174.75 165
+802: 103.453 -183.487 165
+803: 103.444 -192.225 165
+804: 103.434 -200.963 165
+805: 103.425 -209.7 165
+806: 103.416 -218.438 165
+807: 103.406 -227.175 165
+808: 103.397 -235.913 -1.03121e-005
+809: 103.387 -244.65 -1.0694e-005
+810: 103.378 -253.387 -1.10759e-005
+811: 103.369 -262.125 -1.14578e-005
+812: 103.359 -270.862 -1.18398e-005
+813: 103.35 -279.6 -1.22217e-005
+814: 103.341 -288.337 -1.26036e-005
+815: 103.331 -297.075 -1.29856e-005
+816: 103.322 -305.813 -1.33675e-005
+817: 103.312 -314.55 -1.37494e-005
+818: 103.303 -323.287 -1.41313e-005
+819: 103.294 -332.025 -1.45133e-005
+820: 103.284 -340.763 -1.48952e-005
+821: 103.275 -349.5 -1.52771e-005
+822: 103.266 -358.237 -1.56591e-005
+823: 103.256 -366.975 -1.6041e-005
+824: 103.247 -375.712 -1.64229e-005
+825: 103.237 -384.45 -1.68048e-005
+826: 103.228 -393.188 -1.71868e-005
+827: 103.219 -401.925 -1.75687e-005
+828: 103.209 -410.663 -1.79506e-005
+829: 103.2 -419.4 -1.83326e-005
+830: 103.191 -428.138 -1.87145e-005
+831: 103.181 -436.875 -1.90964e-005
+832: 103.172 -445.613 -1.94783e-005
+833: 103.162 -454.35 -1.98603e-005
+834: 103.153 -463.088 -2.02422e-005
+835: 103.144 -471.825 -2.06241e-005
+836: 103.134 -480.563 -2.10061e-005
+837: 103.125 -489.3 -2.1388e-005
+838: 103.116 -498.037 -2.17699e-005
+839: 103.106 -506.775 -2.21518e-005
+840: 103.097 -515.513 -2.25338e-005
+841: 103.087 -524.25 -2.29157e-005
+842: 103.078 -532.987 -2.32976e-005
+843: 103.069 -541.725 -2.36796e-005
+844: 103.059 -550.463 -2.40615e-005
+845: 103.05 -559.2 -2.44434e-005
+846: 112.287 0 0
+847: 112.277 -8.7375 -3.81928e-007
+848: 112.267 -17.475 -7.63857e-007
+849: 112.257 -26.2125 -1.14578e-006
+850: 112.247 -34.95 -1.52771e-006
+851: 112.237 -43.6875 -1.90964e-006
+852: 112.227 -52.425 -2.29157e-006
+853: 112.216 -61.1625 -2.6735e-006
+854: 112.206 -69.9 -3.05543e-006
+855: 112.196 -78.6375 -3.43735e-006
+856: 112.186 -87.375 -3.81928e-006
+857: 112.176 -96.1125 -4.20121e-006
+858: 112.166 -104.85 -4.58314e-006
+859: 112.155 -113.588 -4.96507e-006
+860: 112.145 -122.325 -5.347e-006
+861: 112.135 -131.063 165
+862: 112.125 -139.8 165
+863: 112.115 -148.538 165
+864: 112.105 -157.275 165
+865: 112.095 -166.012 165
+866: 112.084 -174.75 165
+867: 112.074 -183.487 165
+868: 112.064 -192.225 165
+869: 112.054 -200.963 165
+870: 112.044 -209.7 165
+871: 112.034 -218.438 165
+872: 112.023 -227.175 165
+873: 112.013 -235.913 -1.03121e-005
+874: 112.003 -244.65 -1.0694e-005
+875: 111.993 -253.387 -1.10759e-005
+876: 111.983 -262.125 -1.14578e-005
+877: 111.973 -270.862 -1.18398e-005
+878: 111.962 -279.6 -1.22217e-005
+879: 111.952 -288.337 -1.26036e-005
+880: 111.942 -297.075 -1.29856e-005
+881: 111.932 -305.813 -1.33675e-005
+882: 111.922 -314.55 -1.37494e-005
+883: 111.912 -323.287 -1.41313e-005
+884: 111.902 -332.025 -1.45133e-005
+885: 111.891 -340.763 -1.48952e-005
+886: 111.881 -349.5 -1.52771e-005
+887: 111.871 -358.237 -1.56591e-005
+888: 111.861 -366.975 -1.6041e-005
+889: 111.851 -375.712 -1.64229e-005
+890: 111.841 -384.45 -1.68048e-005
+891: 111.83 -393.188 -1.71868e-005
+892: 111.82 -401.925 -1.75687e-005
+893: 111.81 -410.663 -1.79506e-005
+894: 111.8 -419.4 -1.83326e-005
+895: 111.79 -428.138 -1.87145e-005
+896: 111.78 -436.875 -1.90964e-005
+897: 111.77 -445.613 -1.94783e-005
+898: 111.759 -454.35 -1.98603e-005
+899: 111.749 -463.088 -2.02422e-005
+900: 111.739 -471.825 -2.06241e-005
+901: 111.729 -480.563 -2.10061e-005
+902: 111.719 -489.3 -2.1388e-005
+903: 111.709 -498.038 -2.17699e-005
+904: 111.698 -506.775 -2.21518e-005
+905: 111.688 -515.513 -2.25338e-005
+906: 111.678 -524.25 -2.29157e-005
+907: 111.668 -532.987 -2.32976e-005
+908: 111.658 -541.725 -2.36796e-005
+909: 111.648 -550.463 -2.40615e-005
+910: 111.637 -559.2 -2.44434e-005
+911: 120.925 0 0
+912: 120.914 -8.7375 -3.81928e-007
+913: 120.903 -17.475 -7.63857e-007
+914: 120.892 -26.2125 -1.14578e-006
+915: 120.881 -34.95 -1.52771e-006
+916: 120.87 -43.6875 -1.90964e-006
+917: 120.859 -52.425 -2.29157e-006
+918: 120.848 -61.1625 -2.6735e-006
+919: 120.838 -69.9 -3.05543e-006
+920: 120.827 -78.6375 -3.43735e-006
+921: 120.816 -87.375 -3.81928e-006
+922: 120.805 -96.1125 165
+923: 120.794 -104.85 165
+924: 120.783 -113.588 165
+925: 120.772 -122.325 165
+926: 120.761 -131.063 165
+927: 120.75 -139.8 165
+928: 120.739 -148.538 165
+929: 120.728 -157.275 165
+930: 120.717 -166.012 165
+931: 120.706 -174.75 165
+932: 120.695 -183.487 165
+933: 120.684 -192.225 165
+934: 120.673 -200.963 165
+935: 120.662 -209.7 165
+936: 120.652 -218.438 165
+937: 120.641 -227.175 165
+938: 120.63 -235.913 165
+939: 120.619 -244.65 -1.0694e-005
+940: 120.608 -253.387 -1.10759e-005
+941: 120.597 -262.125 -1.14578e-005
+942: 120.586 -270.862 -1.18398e-005
+943: 120.575 -279.6 -1.22217e-005
+944: 120.564 -288.338 -1.26036e-005
+945: 120.553 -297.075 -1.29856e-005
+946: 120.542 -305.813 -1.33675e-005
+947: 120.531 -314.55 -1.37494e-005
+948: 120.52 -323.287 -1.41313e-005
+949: 120.509 -332.025 -1.45133e-005
+950: 120.498 -340.763 -1.48952e-005
+951: 120.487 -349.5 -1.52771e-005
+952: 120.477 -358.237 -1.56591e-005
+953: 120.466 -366.975 -1.6041e-005
+954: 120.455 -375.712 -1.64229e-005
+955: 120.444 -384.45 -1.68048e-005
+956: 120.433 -393.188 -1.71868e-005
+957: 120.422 -401.925 -1.75687e-005
+958: 120.411 -410.663 -1.79506e-005
+959: 120.4 -419.4 -1.83326e-005
+960: 120.389 -428.138 -1.87145e-005
+961: 120.378 -436.875 -1.90964e-005
+962: 120.367 -445.613 -1.94783e-005
+963: 120.356 -454.35 -1.98603e-005
+964: 120.345 -463.088 -2.02422e-005
+965: 120.334 -471.825 -2.06241e-005
+966: 120.323 -480.563 -2.10061e-005
+967: 120.313 -489.3 -2.1388e-005
+968: 120.302 -498.037 -2.17699e-005
+969: 120.291 -506.775 -2.21518e-005
+970: 120.28 -515.513 -2.25338e-005
+971: 120.269 -524.25 -2.29157e-005
+972: 120.258 -532.987 -2.32976e-005
+973: 120.247 -541.725 -2.36796e-005
+974: 120.236 -550.463 -2.40615e-005
+975: 120.225 -559.2 -2.44434e-005
+976: 129.563 0 0
+977: 129.551 -8.7375 -3.81928e-007
+978: 129.539 -17.475 -7.63857e-007
+979: 129.527 -26.2125 -1.14578e-006
+980: 129.516 -34.95 -1.52771e-006
+981: 129.504 -43.6875 -1.90964e-006
+982: 129.492 -52.425 -2.29157e-006
+983: 129.48 -61.1625 -2.6735e-006
+984: 129.469 -69.9 165
+985: 129.457 -78.6375 165
+986: 129.445 -87.375 165
+987: 129.434 -96.1125 165
+988: 129.422 -104.85 165
+989: 129.41 -113.588 165
+990: 129.398 -122.325 165
+991: 129.387 -131.063 165
+992: 129.375 -139.8 165
+993: 129.363 -148.538 165
+994: 129.352 -157.275 165
+995: 129.34 -166.012 165
+996: 129.328 -174.75 165
+997: 129.316 -183.487 165
+998: 129.305 -192.225 165
+999: 129.293 -200.963 165
+1000: 129.281 -209.7 165
+1001: 129.27 -218.438 165
+1002: 129.258 -227.175 165
+1003: 129.246 -235.913 165
+1004: 129.234 -244.65 -1.0694e-005
+1005: 129.223 -253.387 -1.10759e-005
+1006: 129.211 -262.125 -1.14578e-005
+1007: 129.199 -270.862 -1.18398e-005
+1008: 129.187 -279.6 -1.22217e-005
+1009: 129.176 -288.338 -1.26036e-005
+1010: 129.164 -297.075 -1.29856e-005
+1011: 129.152 -305.813 -1.33675e-005
+1012: 129.141 -314.55 -1.37494e-005
+1013: 129.129 -323.287 -1.41313e-005
+1014: 129.117 -332.025 -1.45133e-005
+1015: 129.105 -340.763 -1.48952e-005
+1016: 129.094 -349.5 -1.52771e-005
+1017: 129.082 -358.237 -1.56591e-005
+1018: 129.07 -366.975 -1.6041e-005
+1019: 129.059 -375.712 -1.64229e-005
+1020: 129.047 -384.45 -1.68048e-005
+1021: 129.035 -393.188 -1.71868e-005
+1022: 129.023 -401.925 -1.75687e-005
+1023: 129.012 -410.663 -1.79506e-005
+1024: 129 -419.4 -1.83326e-005
+1025: 128.988 -428.138 -1.87145e-005
+1026: 128.977 -436.875 -1.90964e-005
+1027: 128.965 -445.613 -1.94783e-005
+1028: 128.953 -454.35 -1.98603e-005
+1029: 128.941 -463.088 -2.02422e-005
+1030: 128.93 -471.825 -2.06241e-005
+1031: 128.918 -480.563 -2.10061e-005
+1032: 128.906 -489.3 -2.1388e-005
+1033: 128.895 -498.038 -2.17699e-005
+1034: 128.883 -506.775 -2.21518e-005
+1035: 128.871 -515.513 -2.25338e-005
+1036: 128.859 -524.25 -2.29157e-005
+1037: 128.848 -532.987 -2.32976e-005
+1038: 128.836 -541.725 -2.36796e-005
+1039: 128.824 -550.463 -2.40615e-005
+1040: 128.813 -559.2 -2.44434e-005
+1041: 138.2 0 0
+1042: 138.188 -8.7375 -3.81928e-007
+1043: 138.175 -17.475 -7.63857e-007
+1044: 138.162 -26.2125 -1.14578e-006
+1045: 138.15 -34.95 -1.52771e-006
+1046: 138.137 -43.6875 -1.90964e-006
+1047: 138.125 -52.425 -2.29157e-006
+1048: 138.113 -61.1625 -2.6735e-006
+1049: 138.1 -69.9 165
+1050: 138.088 -78.6375 165
+1051: 138.075 -87.375 165
+1052: 138.063 -96.1125 165
+1053: 138.05 -104.85 165
+1054: 138.038 -113.588 165
+1055: 138.025 -122.325 165
+1056: 138.012 -131.063 165
+1057: 138 -139.8 165
+1058: 137.988 -148.538 165
+1059: 137.975 -157.275 165
+1060: 137.962 -166.012 165
+1061: 137.95 -174.75 165
+1062: 137.938 -183.487 165
+1063: 137.925 -192.225 165
+1064: 137.912 -200.963 165
+1065: 137.9 -209.7 165
+1066: 137.887 -218.438 165
+1067: 137.875 -227.175 165
+1068: 137.862 -235.913 165
+1069: 137.85 -244.65 -1.0694e-005
+1070: 137.837 -253.387 -1.10759e-005
+1071: 137.825 -262.125 -1.14578e-005
+1072: 137.812 -270.862 -1.18398e-005
+1073: 137.8 -279.6 -1.22217e-005
+1074: 137.787 -288.338 -1.26036e-005
+1075: 137.775 -297.075 -1.29856e-005
+1076: 137.762 -305.813 -1.33675e-005
+1077: 137.75 -314.55 -1.37494e-005
+1078: 137.737 -323.287 -1.41313e-005
+1079: 137.725 -332.025 -1.45133e-005
+1080: 137.712 -340.763 -1.48952e-005
+1081: 137.7 -349.5 -1.52771e-005
+1082: 137.687 -358.237 -1.56591e-005
+1083: 137.675 -366.975 -1.6041e-005
+1084: 137.662 -375.712 -1.64229e-005
+1085: 137.65 -384.45 -1.68048e-005
+1086: 137.637 -393.188 -1.71868e-005
+1087: 137.625 -401.925 -1.75687e-005
+1088: 137.612 -410.663 -1.79506e-005
+1089: 137.6 -419.4 -1.83326e-005
+1090: 137.587 -428.138 -1.87145e-005
+1091: 137.575 -436.875 -1.90964e-005
+1092: 137.563 -445.613 -1.94783e-005
+1093: 137.55 -454.35 -1.98603e-005
+1094: 137.537 -463.088 -2.02422e-005
+1095: 137.525 -471.825 -2.06241e-005
+1096: 137.512 -480.563 -2.10061e-005
+1097: 137.5 -489.3 -2.1388e-005
+1098: 137.488 -498.037 -2.17699e-005
+1099: 137.475 -506.775 -2.21518e-005
+1100: 137.462 -515.513 -2.25338e-005
+1101: 137.45 -524.25 -2.29157e-005
+1102: 137.438 -532.987 -2.32976e-005
+1103: 137.425 -541.725 -2.36796e-005
+1104: 137.412 -550.463 -2.40615e-005
+1105: 137.4 -559.2 -2.44434e-005
+1106: 146.837 0 0
+1107: 146.824 -8.7375 -3.81928e-007
+1108: 146.811 -17.475 -7.63857e-007
+1109: 146.798 -26.2125 -1.14578e-006
+1110: 146.784 -34.95 -1.52771e-006
+1111: 146.771 -43.6875 -1.90964e-006
+1112: 146.758 -52.425 -2.29157e-006
+1113: 146.745 -61.1625 -2.6735e-006
+1114: 146.731 -69.9 -3.05543e-006
+1115: 146.718 -78.6375 165
+1116: 146.705 -87.375 165
+1117: 146.691 -96.1125 165
+1118: 146.678 -104.85 165
+1119: 146.665 -113.588 165
+1120: 146.652 -122.325 165
+1121: 146.638 -131.063 165
+1122: 146.625 -139.8 165
+1123: 146.612 -148.538 165
+1124: 146.598 -157.275 165
+1125: 146.585 -166.012 165
+1126: 146.572 -174.75 165
+1127: 146.559 -183.487 165
+1128: 146.545 -192.225 165
+1129: 146.532 -200.963 165
+1130: 146.519 -209.7 165
+1131: 146.505 -218.438 165
+1132: 146.492 -227.175 165
+1133: 146.479 -235.913 165
+1134: 146.466 -244.65 -1.0694e-005
+1135: 146.452 -253.387 -1.10759e-005
+1136: 146.439 -262.125 -1.14578e-005
+1137: 146.426 -270.862 -1.18398e-005
+1138: 146.412 -279.6 -1.22217e-005
+1139: 146.399 -288.338 -1.26036e-005
+1140: 146.386 -297.075 -1.29856e-005
+1141: 146.373 -305.813 -1.33675e-005
+1142: 146.359 -314.55 -1.37494e-005
+1143: 146.346 -323.287 -1.41313e-005
+1144: 146.333 -332.025 -1.45133e-005
+1145: 146.32 -340.763 -1.48952e-005
+1146: 146.306 -349.5 -1.52771e-005
+1147: 146.293 -358.237 -1.56591e-005
+1148: 146.28 -366.975 -1.6041e-005
+1149: 146.266 -375.712 -1.64229e-005
+1150: 146.253 -384.45 -1.68048e-005
+1151: 146.24 -393.188 -1.71868e-005
+1152: 146.227 -401.925 -1.75687e-005
+1153: 146.213 -410.663 -1.79506e-005
+1154: 146.2 -419.4 -1.83326e-005
+1155: 146.187 -428.138 -1.87145e-005
+1156: 146.173 -436.875 -1.90964e-005
+1157: 146.16 -445.613 -1.94783e-005
+1158: 146.147 -454.35 -1.98603e-005
+1159: 146.134 -463.088 -2.02422e-005
+1160: 146.12 -471.825 -2.06241e-005
+1161: 146.107 -480.563 -2.10061e-005
+1162: 146.094 -489.3 -2.1388e-005
+1163: 146.08 -498.038 -2.17699e-005
+1164: 146.067 -506.775 -2.21518e-005
+1165: 146.054 -515.513 -2.25338e-005
+1166: 146.041 -524.25 -2.29157e-005
+1167: 146.027 -532.987 -2.32976e-005
+1168: 146.014 -541.725 -2.36796e-005
+1169: 146.001 -550.463 -2.40615e-005
+1170: 145.987 -559.2 -2.44434e-005
+1171: 155.475 0 0
+1172: 155.461 -8.7375 -3.81928e-007
+1173: 155.447 -17.475 -7.63857e-007
+1174: 155.433 -26.2125 -1.14578e-006
+1175: 155.419 -34.95 -1.52771e-006
+1176: 155.405 -43.6875 -1.90964e-006
+1177: 155.391 -52.425 -2.29157e-006
+1178: 155.377 -61.1625 -2.6735e-006
+1179: 155.363 -69.9 -3.05543e-006
+1180: 155.348 -78.6375 165
+1181: 155.334 -87.375 165
+1182: 155.32 -96.1125 165
+1183: 155.306 -104.85 165
+1184: 155.292 -113.588 165
+1185: 155.278 -122.325 165
+1186: 155.264 -131.063 165
+1187: 155.25 -139.8 165
+1188: 155.236 -148.538 165
+1189: 155.222 -157.275 165
+1190: 155.208 -166.012 165
+1191: 155.194 -174.75 165
+1192: 155.18 -183.487 165
+1193: 155.166 -192.225 165
+1194: 155.152 -200.963 165
+1195: 155.138 -209.7 165
+1196: 155.123 -218.438 165
+1197: 155.109 -227.175 165
+1198: 155.095 -235.913 165
+1199: 155.081 -244.65 165
+1200: 155.067 -253.387 -1.10759e-005
+1201: 155.053 -262.125 -1.14578e-005
+1202: 155.039 -270.862 -1.18398e-005
+1203: 155.025 -279.6 -1.22217e-005
+1204: 155.011 -288.338 -1.26036e-005
+1205: 154.997 -297.075 -1.29856e-005
+1206: 154.983 -305.813 -1.33675e-005
+1207: 154.969 -314.55 -1.37494e-005
+1208: 154.955 -323.287 -1.41313e-005
+1209: 154.941 -332.025 -1.45133e-005
+1210: 154.927 -340.763 -1.48952e-005
+1211: 154.912 -349.5 -1.52771e-005
+1212: 154.898 -358.237 -1.56591e-005
+1213: 154.884 -366.975 -1.6041e-005
+1214: 154.87 -375.712 -1.64229e-005
+1215: 154.856 -384.45 -1.68048e-005
+1216: 154.842 -393.188 -1.71868e-005
+1217: 154.828 -401.925 -1.75687e-005
+1218: 154.814 -410.663 -1.79506e-005
+1219: 154.8 -419.4 -1.83326e-005
+1220: 154.786 -428.138 -1.87145e-005
+1221: 154.772 -436.875 -1.90964e-005
+1222: 154.758 -445.613 -1.94783e-005
+1223: 154.744 -454.35 -1.98603e-005
+1224: 154.73 -463.088 -2.02422e-005
+1225: 154.716 -471.825 -2.06241e-005
+1226: 154.702 -480.563 -2.10061e-005
+1227: 154.688 -489.3 -2.1388e-005
+1228: 154.673 -498.037 -2.17699e-005
+1229: 154.659 -506.775 -2.21518e-005
+1230: 154.645 -515.513 -2.25338e-005
+1231: 154.631 -524.25 -2.29157e-005
+1232: 154.617 -532.987 -2.32976e-005
+1233: 154.603 -541.725 -2.36796e-005
+1234: 154.589 -550.463 -2.40615e-005
+1235: 154.575 -559.2 -2.44434e-005
+1236: 164.113 0 0
+1237: 164.098 -8.7375 -3.81928e-007
+1238: 164.083 -17.475 -7.63857e-007
+1239: 164.068 -26.2125 -1.14578e-006
+1240: 164.053 -34.95 -1.52771e-006
+1241: 164.038 -43.6875 -1.90964e-006
+1242: 164.023 -52.425 -2.29157e-006
+1243: 164.009 -61.1625 -2.6735e-006
+1244: 163.994 -69.9 -3.05543e-006
+1245: 163.979 -78.6375 165
+1246: 163.964 -87.375 165
+1247: 163.949 -96.1125 165
+1248: 163.934 -104.85 165
+1249: 163.92 -113.588 165
+1250: 163.905 -122.325 165
+1251: 163.89 -131.063 165
+1252: 163.875 -139.8 165
+1253: 163.86 -148.538 165
+1254: 163.845 -157.275 165
+1255: 163.83 -166.012 165
+1256: 163.816 -174.75 165
+1257: 163.801 -183.487 165
+1258: 163.786 -192.225 165
+1259: 163.771 -200.963 165
+1260: 163.756 -209.7 165
+1261: 163.741 -218.438 165
+1262: 163.727 -227.175 165
+1263: 163.712 -235.913 165
+1264: 163.697 -244.65 165
+1265: 163.682 -253.387 -1.10759e-005
+1266: 163.667 -262.125 -1.14578e-005
+1267: 163.652 -270.862 -1.18398e-005
+1268: 163.637 -279.6 -1.22217e-005
+1269: 163.623 -288.337 -1.26036e-005
+1270: 163.608 -297.075 -1.29856e-005
+1271: 163.593 -305.813 -1.33675e-005
+1272: 163.578 -314.55 -1.37494e-005
+1273: 163.563 -323.287 -1.41313e-005
+1274: 163.548 -332.025 -1.45133e-005
+1275: 163.534 -340.763 -1.48952e-005
+1276: 163.519 -349.5 -1.52771e-005
+1277: 163.504 -358.237 -1.56591e-005
+1278: 163.489 -366.975 -1.6041e-005
+1279: 163.474 -375.712 -1.64229e-005
+1280: 163.459 -384.45 -1.68048e-005
+1281: 163.445 -393.188 -1.71868e-005
+1282: 163.43 -401.925 -1.75687e-005
+1283: 163.415 -410.663 -1.79506e-005
+1284: 163.4 -419.4 -1.83326e-005
+1285: 163.385 -428.138 -1.87145e-005
+1286: 163.37 -436.875 -1.90964e-005
+1287: 163.355 -445.613 -1.94783e-005
+1288: 163.341 -454.35 -1.98603e-005
+1289: 163.326 -463.088 -2.02422e-005
+1290: 163.311 -471.825 -2.06241e-005
+1291: 163.296 -480.563 -2.10061e-005
+1292: 163.281 -489.3 -2.1388e-005
+1293: 163.266 -498.038 -2.17699e-005
+1294: 163.252 -506.775 -2.21518e-005
+1295: 163.237 -515.513 -2.25338e-005
+1296: 163.222 -524.25 -2.29157e-005
+1297: 163.207 -532.987 -2.32976e-005
+1298: 163.192 -541.725 -2.36796e-005
+1299: 163.177 -550.463 -2.40615e-005
+1300: 163.163 -559.2 -2.44434e-005
+1301: 172.75 0 0
+1302: 172.734 -8.7375 -3.81928e-007
+1303: 172.719 -17.475 -7.63857e-007
+1304: 172.703 -26.2125 -1.14578e-006
+1305: 172.688 -34.95 -1.52771e-006
+1306: 172.672 -43.6875 -1.90964e-006
+1307: 172.656 -52.425 -2.29157e-006
+1308: 172.641 -61.1625 -2.6735e-006
+1309: 172.625 -69.9 -3.05543e-006
+1310: 172.609 -78.6375 165
+1311: 172.594 -87.375 165
+1312: 172.578 -96.1125 165
+1313: 172.563 -104.85 165
+1314: 172.547 -113.588 165
+1315: 172.531 -122.325 165
+1316: 172.516 -131.063 165
+1317: 172.5 -139.8 165
+1318: 172.484 -148.538 165
+1319: 172.469 -157.275 165
+1320: 172.453 -166.012 165
+1321: 172.438 -174.75 165
+1322: 172.422 -183.487 165
+1323: 172.406 -192.225 165
+1324: 172.391 -200.963 165
+1325: 172.375 -209.7 165
+1326: 172.359 -218.438 165
+1327: 172.344 -227.175 165
+1328: 172.328 -235.913 165
+1329: 172.313 -244.65 165
+1330: 172.297 -253.387 -1.10759e-005
+1331: 172.281 -262.125 -1.14578e-005
+1332: 172.266 -270.862 -1.18398e-005
+1333: 172.25 -279.6 -1.22217e-005
+1334: 172.234 -288.337 -1.26036e-005
+1335: 172.219 -297.075 -1.29856e-005
+1336: 172.203 -305.813 -1.33675e-005
+1337: 172.187 -314.55 -1.37494e-005
+1338: 172.172 -323.287 -1.41313e-005
+1339: 172.156 -332.025 -1.45133e-005
+1340: 172.141 -340.763 -1.48952e-005
+1341: 172.125 -349.5 -1.52771e-005
+1342: 172.109 -358.237 -1.56591e-005
+1343: 172.094 -366.975 -1.6041e-005
+1344: 172.078 -375.712 -1.64229e-005
+1345: 172.062 -384.45 -1.68048e-005
+1346: 172.047 -393.188 -1.71868e-005
+1347: 172.031 -401.925 -1.75687e-005
+1348: 172.016 -410.663 -1.79506e-005
+1349: 172 -419.4 -1.83326e-005
+1350: 171.984 -428.138 -1.87145e-005
+1351: 171.969 -436.875 -1.90964e-005
+1352: 171.953 -445.613 -1.94783e-005
+1353: 171.938 -454.35 -1.98603e-005
+1354: 171.922 -463.088 -2.02422e-005
+1355: 171.906 -471.825 -2.06241e-005
+1356: 171.891 -480.563 -2.10061e-005
+1357: 171.875 -489.3 -2.1388e-005
+1358: 171.859 -498.037 -2.17699e-005
+1359: 171.844 -506.775 -2.21518e-005
+1360: 171.828 -515.513 -2.25338e-005
+1361: 171.813 -524.25 -2.29157e-005
+1362: 171.797 -532.987 -2.32976e-005
+1363: 171.781 -541.725 -2.36796e-005
+1364: 171.766 -550.463 -2.40615e-005
+1365: 171.75 -559.2 -2.44434e-005
+1366: 181.387 0 0
+1367: 181.371 -8.7375 -3.81928e-007
+1368: 181.355 -17.475 -7.63857e-007
+1369: 181.338 -26.2125 -1.14578e-006
+1370: 181.322 -34.95 -1.52771e-006
+1371: 181.305 -43.6875 -1.90964e-006
+1372: 181.289 -52.425 -2.29157e-006
+1373: 181.273 -61.1625 -2.6735e-006
+1374: 181.256 -69.9 -3.05543e-006
+1375: 181.24 -78.6375 -3.43735e-006
+1376: 181.223 -87.375 165
+1377: 181.207 -96.1125 165
+1378: 181.191 -104.85 165
+1379: 181.174 -113.588 165
+1380: 181.158 -122.325 165
+1381: 181.141 -131.063 165
+1382: 181.125 -139.8 165
+1383: 181.109 -148.538 165
+1384: 181.092 -157.275 165
+1385: 181.076 -166.012 165
+1386: 181.059 -174.75 165
+1387: 181.043 -183.487 165
+1388: 181.027 -192.225 165
+1389: 181.01 -200.963 165
+1390: 180.994 -209.7 165
+1391: 180.977 -218.438 165
+1392: 180.961 -227.175 165
+1393: 180.945 -235.913 165
+1394: 180.928 -244.65 165
+1395: 180.912 -253.387 165
+1396: 180.895 -262.125 -1.14578e-005
+1397: 180.879 -270.862 -1.18398e-005
+1398: 180.862 -279.6 -1.22217e-005
+1399: 180.846 -288.337 -1.26036e-005
+1400: 180.83 -297.075 -1.29856e-005
+1401: 180.813 -305.813 -1.33675e-005
+1402: 180.797 -314.55 -1.37494e-005
+1403: 180.78 -323.287 -1.41313e-005
+1404: 180.764 -332.025 -1.45133e-005
+1405: 180.748 -340.763 -1.48952e-005
+1406: 180.731 -349.5 -1.52771e-005
+1407: 180.715 -358.237 -1.56591e-005
+1408: 180.698 -366.975 -1.6041e-005
+1409: 180.682 -375.712 -1.64229e-005
+1410: 180.666 -384.45 -1.68048e-005
+1411: 180.649 -393.188 -1.71868e-005
+1412: 180.633 -401.925 -1.75687e-005
+1413: 180.616 -410.663 -1.79506e-005
+1414: 180.6 -419.4 -1.83326e-005
+1415: 180.584 -428.138 -1.87145e-005
+1416: 180.567 -436.875 -1.90964e-005
+1417: 180.551 -445.613 -1.94783e-005
+1418: 180.534 -454.35 -1.98603e-005
+1419: 180.518 -463.088 -2.02422e-005
+1420: 180.502 -471.825 -2.06241e-005
+1421: 180.485 -480.563 -2.10061e-005
+1422: 180.469 -489.3 -2.1388e-005
+1423: 180.452 -498.038 -2.17699e-005
+1424: 180.436 -506.775 -2.21518e-005
+1425: 180.42 -515.513 -2.25338e-005
+1426: 180.403 -524.25 -2.29157e-005
+1427: 180.387 -532.987 -2.32976e-005
+1428: 180.37 -541.725 -2.36796e-005
+1429: 180.354 -550.463 -2.40615e-005
+1430: 180.337 -559.2 -2.44434e-005
+1431: 190.025 0 0
+1432: 190.008 -8.7375 -3.81928e-007
+1433: 189.991 -17.475 -7.63857e-007
+1434: 189.973 -26.2125 -1.14578e-006
+1435: 189.956 -34.95 -1.52771e-006
+1436: 189.939 -43.6875 -1.90964e-006
+1437: 189.922 -52.425 -2.29157e-006
+1438: 189.905 -61.1625 -2.6735e-006
+1439: 189.887 -69.9 -3.05543e-006
+1440: 189.87 -78.6375 -3.43735e-006
+1441: 189.853 -87.375 165
+1442: 189.836 -96.1125 165
+1443: 189.819 -104.85 165
+1444: 189.802 -113.588 165
+1445: 189.784 -122.325 165
+1446: 189.767 -131.063 165
+1447: 189.75 -139.8 165
+1448: 189.733 -148.538 165
+1449: 189.716 -157.275 165
+1450: 189.698 -166.012 165
+1451: 189.681 -174.75 165
+1452: 189.664 -183.487 165
+1453: 189.647 -192.225 165
+1454: 189.63 -200.963 165
+1455: 189.612 -209.7 165
+1456: 189.595 -218.438 165
+1457: 189.578 -227.175 165
+1458: 189.561 -235.913 165
+1459: 189.544 -244.65 165
+1460: 189.527 -253.387 165
+1461: 189.509 -262.125 -1.14578e-005
+1462: 189.492 -270.862 -1.18398e-005
+1463: 189.475 -279.6 -1.22217e-005
+1464: 189.458 -288.338 -1.26036e-005
+1465: 189.441 -297.075 -1.29856e-005
+1466: 189.423 -305.813 -1.33675e-005
+1467: 189.406 -314.55 -1.37494e-005
+1468: 189.389 -323.287 -1.41313e-005
+1469: 189.372 -332.025 -1.45133e-005
+1470: 189.355 -340.763 -1.48952e-005
+1471: 189.337 -349.5 -1.52771e-005
+1472: 189.32 -358.237 -1.56591e-005
+1473: 189.303 -366.975 -1.6041e-005
+1474: 189.286 -375.712 -1.64229e-005
+1475: 189.269 -384.45 -1.68048e-005
+1476: 189.252 -393.188 -1.71868e-005
+1477: 189.234 -401.925 -1.75687e-005
+1478: 189.217 -410.663 -1.79506e-005
+1479: 189.2 -419.4 -1.83326e-005
+1480: 189.183 -428.138 -1.87145e-005
+1481: 189.166 -436.875 -1.90964e-005
+1482: 189.148 -445.613 -1.94783e-005
+1483: 189.131 -454.35 -1.98603e-005
+1484: 189.114 -463.088 -2.02422e-005
+1485: 189.097 -471.825 -2.06241e-005
+1486: 189.08 -480.563 -2.10061e-005
+1487: 189.063 -489.3 -2.1388e-005
+1488: 189.045 -498.037 -2.17699e-005
+1489: 189.028 -506.775 -2.21518e-005
+1490: 189.011 -515.513 -2.25338e-005
+1491: 188.994 -524.25 -2.29157e-005
+1492: 188.977 -532.987 -2.32976e-005
+1493: 188.959 -541.725 -2.36796e-005
+1494: 188.942 -550.463 -2.40615e-005
+1495: 188.925 -559.2 -2.44434e-005
+1496: 198.662 0 0
+1497: 198.645 -8.7375 -3.81928e-007
+1498: 198.627 -17.475 -7.63857e-007
+1499: 198.609 -26.2125 -1.14578e-006
+1500: 198.591 -34.95 -1.52771e-006
+1501: 198.573 -43.6875 -1.90964e-006
+1502: 198.555 -52.425 -2.29157e-006
+1503: 198.537 -61.1625 -2.6735e-006
+1504: 198.519 -69.9 -3.05543e-006
+1505: 198.501 -78.6375 -3.43735e-006
+1506: 198.483 -87.375 165
+1507: 198.465 -96.1125 165
+1508: 198.447 -104.85 165
+1509: 198.429 -113.588 165
+1510: 198.411 -122.325 165
+1511: 198.393 -131.063 165
+1512: 198.375 -139.8 165
+1513: 198.357 -148.538 165
+1514: 198.339 -157.275 165
+1515: 198.321 -166.012 165
+1516: 198.303 -174.75 165
+1517: 198.285 -183.487 165
+1518: 198.267 -192.225 165
+1519: 198.249 -200.963 165
+1520: 198.231 -209.7 165
+1521: 198.213 -218.438 165
+1522: 198.195 -227.175 165
+1523: 198.177 -235.913 165
+1524: 198.159 -244.65 165
+1525: 198.141 -253.387 165
+1526: 198.123 -262.125 -1.14578e-005
+1527: 198.105 -270.862 -1.18398e-005
+1528: 198.087 -279.6 -1.22217e-005
+1529: 198.07 -288.338 -1.26036e-005
+1530: 198.052 -297.075 -1.29856e-005
+1531: 198.034 -305.813 -1.33675e-005
+1532: 198.016 -314.55 -1.37494e-005
+1533: 197.998 -323.287 -1.41313e-005
+1534: 197.98 -332.025 -1.45133e-005
+1535: 197.962 -340.763 -1.48952e-005
+1536: 197.944 -349.5 -1.52771e-005
+1537: 197.926 -358.237 -1.56591e-005
+1538: 197.908 -366.975 -1.6041e-005
+1539: 197.89 -375.712 -1.64229e-005
+1540: 197.872 -384.45 -1.68048e-005
+1541: 197.854 -393.188 -1.71868e-005
+1542: 197.836 -401.925 -1.75687e-005
+1543: 197.818 -410.663 -1.79506e-005
+1544: 197.8 -419.4 -1.83326e-005
+1545: 197.782 -428.138 -1.87145e-005
+1546: 197.764 -436.875 -1.90964e-005
+1547: 197.746 -445.613 -1.94783e-005
+1548: 197.728 -454.35 -1.98603e-005
+1549: 197.71 -463.088 -2.02422e-005
+1550: 197.692 -471.825 -2.06241e-005
+1551: 197.674 -480.563 -2.10061e-005
+1552: 197.656 -489.3 -2.1388e-005
+1553: 197.638 -498.038 -2.17699e-005
+1554: 197.62 -506.775 -2.21518e-005
+1555: 197.602 -515.513 -2.25338e-005
+1556: 197.584 -524.25 -2.29157e-005
+1557: 197.566 -532.987 -2.32976e-005
+1558: 197.548 -541.725 -2.36796e-005
+1559: 197.53 -550.463 -2.40615e-005
+1560: 197.512 -559.2 -2.44434e-005
+1561: 207.3 0 0
+1562: 207.281 -8.7375 -3.81928e-007
+1563: 207.262 -17.475 -7.63857e-007
+1564: 207.244 -26.2125 -1.14578e-006
+1565: 207.225 -34.95 -1.52771e-006
+1566: 207.206 -43.6875 -1.90964e-006
+1567: 207.188 -52.425 -2.29157e-006
+1568: 207.169 -61.1625 -2.6735e-006
+1569: 207.15 -69.9 -3.05543e-006
+1570: 207.131 -78.6375 -3.43735e-006
+1571: 207.112 -87.375 -3.81928e-006
+1572: 207.094 -96.1125 165
+1573: 207.075 -104.85 165
+1574: 207.056 -113.588 165
+1575: 207.038 -122.325 165
+1576: 207.019 -131.063 165
+1577: 207 -139.8 165
+1578: 206.981 -148.538 165
+1579: 206.962 -157.275 165
+1580: 206.944 -166.013 165
+1581: 206.925 -174.75 165
+1582: 206.906 -183.487 165
+1583: 206.887 -192.225 165
+1584: 206.869 -200.963 165
+1585: 206.85 -209.7 165
+1586: 206.831 -218.438 165
+1587: 206.813 -227.175 165
+1588: 206.794 -235.913 165
+1589: 206.775 -244.65 165
+1590: 206.756 -253.387 165
+1591: 206.737 -262.125 -1.14578e-005
+1592: 206.719 -270.862 -1.18398e-005
+1593: 206.7 -279.6 -1.22217e-005
+1594: 206.681 -288.338 -1.26036e-005
+1595: 206.662 -297.075 -1.29856e-005
+1596: 206.644 -305.813 -1.33675e-005
+1597: 206.625 -314.55 -1.37494e-005
+1598: 206.606 -323.287 -1.41313e-005
+1599: 206.587 -332.025 -1.45133e-005
+1600: 206.569 -340.763 -1.48952e-005
+1601: 206.55 -349.5 -1.52771e-005
+1602: 206.531 -358.237 -1.56591e-005
+1603: 206.512 -366.975 -1.6041e-005
+1604: 206.494 -375.712 -1.64229e-005
+1605: 206.475 -384.45 -1.68048e-005
+1606: 206.456 -393.188 -1.71868e-005
+1607: 206.438 -401.925 -1.75687e-005
+1608: 206.419 -410.663 -1.79506e-005
+1609: 206.4 -419.4 -1.83326e-005
+1610: 206.381 -428.138 -1.87145e-005
+1611: 206.362 -436.875 -1.90964e-005
+1612: 206.344 -445.613 -1.94783e-005
+1613: 206.325 -454.35 -1.98603e-005
+1614: 206.306 -463.088 -2.02422e-005
+1615: 206.288 -471.825 -2.06241e-005
+1616: 206.269 -480.563 -2.10061e-005
+1617: 206.25 -489.3 -2.1388e-005
+1618: 206.231 -498.037 -2.17699e-005
+1619: 206.212 -506.775 -2.21518e-005
+1620: 206.194 -515.513 -2.25338e-005
+1621: 206.175 -524.25 -2.29157e-005
+1622: 206.156 -532.987 -2.32976e-005
+1623: 206.137 -541.725 -2.36796e-005
+1624: 206.119 -550.463 -2.40615e-005
+1625: 206.1 -559.2 -2.44434e-005
+1626: 215.937 0 0
+1627: 215.918 -8.7375 -3.81928e-007
+1628: 215.898 -17.475 -7.63857e-007
+1629: 215.879 -26.2125 -1.14578e-006
+1630: 215.859 -34.95 -1.52771e-006
+1631: 215.84 -43.6875 -1.90964e-006
+1632: 215.82 -52.425 -2.29157e-006
+1633: 215.801 -61.1625 -2.6735e-006
+1634: 215.781 -69.9 -3.05543e-006
+1635: 215.762 -78.6375 -3.43735e-006
+1636: 215.742 -87.375 -3.81928e-006
+1637: 215.723 -96.1125 165
+1638: 215.703 -104.85 165
+1639: 215.684 -113.588 165
+1640: 215.664 -122.325 165
+1641: 215.645 -131.063 165
+1642: 215.625 -139.8 165
+1643: 215.605 -148.538 165
+1644: 215.586 -157.275 165
+1645: 215.566 -166.013 165
+1646: 215.547 -174.75 165
+1647: 215.527 -183.487 165
+1648: 215.508 -192.225 165
+1649: 215.488 -200.963 165
+1650: 215.469 -209.7 165
+1651: 215.449 -218.438 165
+1652: 215.43 -227.175 165
+1653: 215.41 -235.913 165
+1654: 215.391 -244.65 165
+1655: 215.371 -253.387 165
+1656: 215.352 -262.125 165
+1657: 215.332 -270.862 -1.18398e-005
+1658: 215.312 -279.6 -1.22217e-005
+1659: 215.293 -288.338 -1.26036e-005
+1660: 215.273 -297.075 -1.29856e-005
+1661: 215.254 -305.813 -1.33675e-005
+1662: 215.234 -314.55 -1.37494e-005
+1663: 215.215 -323.287 -1.41313e-005
+1664: 215.195 -332.025 -1.45133e-005
+1665: 215.176 -340.763 -1.48952e-005
+1666: 215.156 -349.5 -1.52771e-005
+1667: 215.137 -358.237 -1.56591e-005
+1668: 215.117 -366.975 -1.6041e-005
+1669: 215.098 -375.712 -1.64229e-005
+1670: 215.078 -384.45 -1.68048e-005
+1671: 215.059 -393.188 -1.71868e-005
+1672: 215.039 -401.925 -1.75687e-005
+1673: 215.02 -410.663 -1.79506e-005
+1674: 215 -419.4 -1.83326e-005
+1675: 214.98 -428.138 -1.87145e-005
+1676: 214.961 -436.875 -1.90964e-005
+1677: 214.941 -445.613 -1.94783e-005
+1678: 214.922 -454.35 -1.98603e-005
+1679: 214.902 -463.088 -2.02422e-005
+1680: 214.883 -471.825 -2.06241e-005
+1681: 214.863 -480.563 -2.10061e-005
+1682: 214.844 -489.3 -2.1388e-005
+1683: 214.824 -498.038 -2.17699e-005
+1684: 214.805 -506.775 -2.21518e-005
+1685: 214.785 -515.513 -2.25338e-005
+1686: 214.766 -524.25 -2.29157e-005
+1687: 214.746 -532.987 -2.32976e-005
+1688: 214.727 -541.725 -2.36796e-005
+1689: 214.707 -550.463 -2.40615e-005
+1690: 214.688 -559.2 -2.44434e-005
+1691: 224.575 0 0
+1692: 224.555 -8.7375 -3.81928e-007
+1693: 224.534 -17.475 -7.63857e-007
+1694: 224.514 -26.2125 -1.14578e-006
+1695: 224.494 -34.95 -1.52771e-006
+1696: 224.473 -43.6875 -1.90964e-006
+1697: 224.453 -52.425 -2.29157e-006
+1698: 224.433 -61.1625 -2.6735e-006
+1699: 224.413 -69.9 -3.05543e-006
+1700: 224.392 -78.6375 -3.43735e-006
+1701: 224.372 -87.375 -3.81928e-006
+1702: 224.352 -96.1125 165
+1703: 224.331 -104.85 165
+1704: 224.311 -113.588 165
+1705: 224.291 -122.325 165
+1706: 224.27 -131.063 165
+1707: 224.25 -139.8 165
+1708: 224.23 -148.538 165
+1709: 224.209 -157.275 165
+1710: 224.189 -166.013 165
+1711: 224.169 -174.75 165
+1712: 224.148 -183.488 165
+1713: 224.128 -192.225 165
+1714: 224.108 -200.963 165
+1715: 224.087 -209.7 165
+1716: 224.067 -218.438 165
+1717: 224.047 -227.175 165
+1718: 224.027 -235.913 165
+1719: 224.006 -244.65 165
+1720: 223.986 -253.387 165
+1721: 223.966 -262.125 165
+1722: 223.945 -270.862 -1.18398e-005
+1723: 223.925 -279.6 -1.22217e-005
+1724: 223.905 -288.338 -1.26036e-005
+1725: 223.884 -297.075 -1.29856e-005
+1726: 223.864 -305.813 -1.33675e-005
+1727: 223.844 -314.55 -1.37494e-005
+1728: 223.823 -323.287 -1.41313e-005
+1729: 223.803 -332.025 -1.45133e-005
+1730: 223.783 -340.763 -1.48952e-005
+1731: 223.762 -349.5 -1.52771e-005
+1732: 223.742 -358.237 -1.56591e-005
+1733: 223.722 -366.975 -1.6041e-005
+1734: 223.702 -375.712 -1.64229e-005
+1735: 223.681 -384.45 -1.68048e-005
+1736: 223.661 -393.188 -1.71868e-005
+1737: 223.641 -401.925 -1.75687e-005
+1738: 223.62 -410.663 -1.79506e-005
+1739: 223.6 -419.4 -1.83326e-005
+1740: 223.58 -428.138 -1.87145e-005
+1741: 223.559 -436.875 -1.90964e-005
+1742: 223.539 -445.613 -1.94783e-005
+1743: 223.519 -454.35 -1.98603e-005
+1744: 223.498 -463.088 -2.02422e-005
+1745: 223.478 -471.825 -2.06241e-005
+1746: 223.458 -480.563 -2.10061e-005
+1747: 223.438 -489.3 -2.1388e-005
+1748: 223.417 -498.037 -2.17699e-005
+1749: 223.397 -506.775 -2.21518e-005
+1750: 223.377 -515.513 -2.25338e-005
+1751: 223.356 -524.25 -2.29157e-005
+1752: 223.336 -532.987 -2.32976e-005
+1753: 223.316 -541.725 -2.36796e-005
+1754: 223.295 -550.463 -2.40615e-005
+1755: 223.275 -559.2 -2.44434e-005
+1756: 233.212 0 0
+1757: 233.191 -8.7375 -3.81928e-007
+1758: 233.17 -17.475 -7.63857e-007
+1759: 233.149 -26.2125 -1.14578e-006
+1760: 233.128 -34.95 -1.52771e-006
+1761: 233.107 -43.6875 -1.90964e-006
+1762: 233.086 -52.425 -2.29157e-006
+1763: 233.065 -61.1625 -2.6735e-006
+1764: 233.044 -69.9 -3.05543e-006
+1765: 233.023 -78.6375 -3.43735e-006
+1766: 233.002 -87.375 -3.81928e-006
+1767: 232.98 -96.1125 -4.20121e-006
+1768: 232.959 -104.85 165
+1769: 232.938 -113.588 165
+1770: 232.917 -122.325 165
+1771: 232.896 -131.063 165
+1772: 232.875 -139.8 165
+1773: 232.854 -148.538 165
+1774: 232.833 -157.275 165
+1775: 232.812 -166.013 165
+1776: 232.791 -174.75 165
+1777: 232.77 -183.488 165
+1778: 232.748 -192.225 165
+1779: 232.727 -200.963 165
+1780: 232.706 -209.7 165
+1781: 232.685 -218.438 165
+1782: 232.664 -227.175 165
+1783: 232.643 -235.913 165
+1784: 232.622 -244.65 165
+1785: 232.601 -253.387 165
+1786: 232.58 -262.125 165
+1787: 232.559 -270.862 -1.18398e-005
+1788: 232.537 -279.6 -1.22217e-005
+1789: 232.516 -288.337 -1.26036e-005
+1790: 232.495 -297.075 -1.29856e-005
+1791: 232.474 -305.813 -1.33675e-005
+1792: 232.453 -314.55 -1.37494e-005
+1793: 232.432 -323.287 -1.41313e-005
+1794: 232.411 -332.025 -1.45133e-005
+1795: 232.39 -340.763 -1.48952e-005
+1796: 232.369 -349.5 -1.52771e-005
+1797: 232.348 -358.237 -1.56591e-005
+1798: 232.327 -366.975 -1.6041e-005
+1799: 232.305 -375.712 -1.64229e-005
+1800: 232.284 -384.45 -1.68048e-005
+1801: 232.263 -393.188 -1.71868e-005
+1802: 232.242 -401.925 -1.75687e-005
+1803: 232.221 -410.663 -1.79506e-005
+1804: 232.2 -419.4 -1.83326e-005
+1805: 232.179 -428.138 -1.87145e-005
+1806: 232.158 -436.875 -1.90964e-005
+1807: 232.137 -445.613 -1.94783e-005
+1808: 232.116 -454.35 -1.98603e-005
+1809: 232.095 -463.088 -2.02422e-005
+1810: 232.073 -471.825 -2.06241e-005
+1811: 232.052 -480.563 -2.10061e-005
+1812: 232.031 -489.3 -2.1388e-005
+1813: 232.01 -498.038 -2.17699e-005
+1814: 231.989 -506.775 -2.21518e-005
+1815: 231.968 -515.513 -2.25338e-005
+1816: 231.947 -524.25 -2.29157e-005
+1817: 231.926 -532.987 -2.32976e-005
+1818: 231.905 -541.725 -2.36796e-005
+1819: 231.884 -550.463 -2.40615e-005
+1820: 231.862 -559.2 -2.44434e-005
+1821: 241.85 0 0
+1822: 241.828 -8.7375 -3.81928e-007
+1823: 241.806 -17.475 -7.63857e-007
+1824: 241.784 -26.2125 -1.14578e-006
+1825: 241.763 -34.95 -1.52771e-006
+1826: 241.741 -43.6875 -1.90964e-006
+1827: 241.719 -52.425 -2.29157e-006
+1828: 241.697 -61.1625 -2.6735e-006
+1829: 241.675 -69.9 -3.05543e-006
+1830: 241.653 -78.6375 -3.43735e-006
+1831: 241.631 -87.375 -3.81928e-006
+1832: 241.609 -96.1125 -4.20121e-006
+1833: 241.588 -104.85 165
+1834: 241.566 -113.588 165
+1835: 241.544 -122.325 165
+1836: 241.522 -131.063 165
+1837: 241.5 -139.8 165
+1838: 241.478 -148.538 165
+1839: 241.456 -157.275 165
+1840: 241.434 -166.013 165
+1841: 241.412 -174.75 165
+1842: 241.391 -183.488 165
+1843: 241.369 -192.225 165
+1844: 241.347 -200.963 165
+1845: 241.325 -209.7 165
+1846: 241.303 -218.438 165
+1847: 241.281 -227.175 165
+1848: 241.259 -235.913 165
+1849: 241.237 -244.65 165
+1850: 241.216 -253.387 165
+1851: 241.194 -262.125 165
+1852: 241.172 -270.862 -1.18398e-005
+1853: 241.15 -279.6 -1.22217e-005
+1854: 241.128 -288.337 -1.26036e-005
+1855: 241.106 -297.075 -1.29856e-005
+1856: 241.084 -305.813 -1.33675e-005
+1857: 241.063 -314.55 -1.37494e-005
+1858: 241.041 -323.287 -1.41313e-005
+1859: 241.019 -332.025 -1.45133e-005
+1860: 240.997 -340.763 -1.48952e-005
+1861: 240.975 -349.5 -1.52771e-005
+1862: 240.953 -358.237 -1.56591e-005
+1863: 240.931 -366.975 -1.6041e-005
+1864: 240.909 -375.712 -1.64229e-005
+1865: 240.887 -384.45 -1.68048e-005
+1866: 240.866 -393.188 -1.71868e-005
+1867: 240.844 -401.925 -1.75687e-005
+1868: 240.822 -410.663 -1.79506e-005
+1869: 240.8 -419.4 -1.83326e-005
+1870: 240.778 -428.138 -1.87145e-005
+1871: 240.756 -436.875 -1.90964e-005
+1872: 240.734 -445.613 -1.94783e-005
+1873: 240.712 -454.35 -1.98603e-005
+1874: 240.691 -463.088 -2.02422e-005
+1875: 240.669 -471.825 -2.06241e-005
+1876: 240.647 -480.563 -2.10061e-005
+1877: 240.625 -489.3 -2.1388e-005
+1878: 240.603 -498.037 -2.17699e-005
+1879: 240.581 -506.775 -2.21518e-005
+1880: 240.559 -515.513 -2.25338e-005
+1881: 240.537 -524.25 -2.29157e-005
+1882: 240.516 -532.987 -2.32976e-005
+1883: 240.494 -541.725 -2.36796e-005
+1884: 240.472 -550.463 -2.40615e-005
+1885: 240.45 -559.2 -2.44434e-005
+1886: 250.487 0 0
+1887: 250.465 -8.7375 -3.81928e-007
+1888: 250.442 -17.475 -7.63857e-007
+1889: 250.42 -26.2125 -1.14578e-006
+1890: 250.397 -34.95 -1.52771e-006
+1891: 250.374 -43.6875 -1.90964e-006
+1892: 250.352 -52.425 -2.29157e-006
+1893: 250.329 -61.1625 -2.6735e-006
+1894: 250.306 -69.9 -3.05543e-006
+1895: 250.284 -78.6375 -3.43735e-006
+1896: 250.261 -87.375 -3.81928e-006
+1897: 250.238 -96.1125 -4.20121e-006
+1898: 250.216 -104.85 165
+1899: 250.193 -113.588 165
+1900: 250.17 -122.325 165
+1901: 250.148 -131.063 165
+1902: 250.125 -139.8 165
+1903: 250.102 -148.538 165
+1904: 250.08 -157.275 165
+1905: 250.057 -166.013 165
+1906: 250.034 -174.75 165
+1907: 250.012 -183.488 165
+1908: 249.989 -192.225 165
+1909: 249.966 -200.963 165
+1910: 249.944 -209.7 165
+1911: 249.921 -218.438 165
+1912: 249.898 -227.175 165
+1913: 249.876 -235.913 165
+1914: 249.853 -244.65 -1.0694e-005
+1915: 249.83 -253.387 -1.10759e-005
+1916: 249.808 -262.125 -1.14578e-005
+1917: 249.785 -270.862 -1.18398e-005
+1918: 249.762 -279.6 -1.22217e-005
+1919: 249.74 -288.337 -1.26036e-005
+1920: 249.717 -297.075 -1.29856e-005
+1921: 249.695 -305.813 -1.33675e-005
+1922: 249.672 -314.55 -1.37494e-005
+1923: 249.649 -323.287 -1.41313e-005
+1924: 249.627 -332.025 -1.45133e-005
+1925: 249.604 -340.763 -1.48952e-005
+1926: 249.581 -349.5 -1.52771e-005
+1927: 249.559 -358.237 -1.56591e-005
+1928: 249.536 -366.975 -1.6041e-005
+1929: 249.513 -375.712 -1.64229e-005
+1930: 249.491 -384.45 -1.68048e-005
+1931: 249.468 -393.188 -1.71868e-005
+1932: 249.445 -401.925 -1.75687e-005
+1933: 249.423 -410.663 -1.79506e-005
+1934: 249.4 -419.4 -1.83326e-005
+1935: 249.377 -428.138 -1.87145e-005
+1936: 249.355 -436.875 -1.90964e-005
+1937: 249.332 -445.613 -1.94783e-005
+1938: 249.309 -454.35 -1.98603e-005
+1939: 249.287 -463.088 -2.02422e-005
+1940: 249.264 -471.825 -2.06241e-005
+1941: 249.241 -480.563 -2.10061e-005
+1942: 249.219 -489.3 -2.1388e-005
+1943: 249.196 -498.038 -2.17699e-005
+1944: 249.173 -506.775 -2.21518e-005
+1945: 249.151 -515.513 -2.25338e-005
+1946: 249.128 -524.25 -2.29157e-005
+1947: 249.105 -532.987 -2.32976e-005
+1948: 249.083 -541.725 -2.36796e-005
+1949: 249.06 -550.463 -2.40615e-005
+1950: 249.038 -559.2 -2.44434e-005
+1951: 259.125 0 0
+1952: 259.102 -8.7375 -3.81928e-007
+1953: 259.078 -17.475 -7.63857e-007
+1954: 259.055 -26.2125 -1.14578e-006
+1955: 259.031 -34.95 -1.52771e-006
+1956: 259.008 -43.6875 -1.90964e-006
+1957: 258.984 -52.425 -2.29157e-006
+1958: 258.961 -61.1625 -2.6735e-006
+1959: 258.938 -69.9 -3.05543e-006
+1960: 258.914 -78.6375 -3.43735e-006
+1961: 258.891 -87.375 -3.81928e-006
+1962: 258.867 -96.1125 -4.20121e-006
+1963: 258.844 -104.85 165
+1964: 258.82 -113.588 165
+1965: 258.797 -122.325 165
+1966: 258.773 -131.063 165
+1967: 258.75 -139.8 165
+1968: 258.727 -148.538 165
+1969: 258.703 -157.275 165
+1970: 258.68 -166.013 165
+1971: 258.656 -174.75 165
+1972: 258.633 -183.488 165
+1973: 258.609 -192.225 165
+1974: 258.586 -200.963 165
+1975: 258.563 -209.7 165
+1976: 258.539 -218.438 -9.54821e-006
+1977: 258.516 -227.175 -9.93014e-006
+1978: 258.492 -235.913 -1.03121e-005
+1979: 258.469 -244.65 -1.0694e-005
+1980: 258.445 -253.387 -1.10759e-005
+1981: 258.422 -262.125 -1.14578e-005
+1982: 258.398 -270.862 -1.18398e-005
+1983: 258.375 -279.6 -1.22217e-005
+1984: 258.352 -288.338 -1.26036e-005
+1985: 258.328 -297.075 -1.29856e-005
+1986: 258.305 -305.813 -1.33675e-005
+1987: 258.281 -314.55 -1.37494e-005
+1988: 258.258 -323.287 -1.41313e-005
+1989: 258.234 -332.025 -1.45133e-005
+1990: 258.211 -340.763 -1.48952e-005
+1991: 258.187 -349.5 -1.52771e-005
+1992: 258.164 -358.237 -1.56591e-005
+1993: 258.141 -366.975 -1.6041e-005
+1994: 258.117 -375.712 -1.64229e-005
+1995: 258.094 -384.45 -1.68048e-005
+1996: 258.07 -393.188 -1.71868e-005
+1997: 258.047 -401.925 -1.75687e-005
+1998: 258.023 -410.663 -1.79506e-005
+1999: 258 -419.4 -1.83326e-005
+2000: 257.977 -428.138 -1.87145e-005
+2001: 257.953 -436.875 -1.90964e-005
+2002: 257.93 -445.613 -1.94783e-005
+2003: 257.906 -454.35 -1.98603e-005
+2004: 257.883 -463.088 -2.02422e-005
+2005: 257.859 -471.825 -2.06241e-005
+2006: 257.836 -480.563 -2.10061e-005
+2007: 257.813 -489.3 -2.1388e-005
+2008: 257.789 -498.037 -2.17699e-005
+2009: 257.766 -506.775 -2.21518e-005
+2010: 257.742 -515.513 -2.25338e-005
+2011: 257.719 -524.25 -2.29157e-005
+2012: 257.695 -532.987 -2.32976e-005
+2013: 257.672 -541.725 -2.36796e-005
+2014: 257.648 -550.463 -2.40615e-005
+2015: 257.625 -559.2 -2.44434e-005
+2016: 267.763 0 0
+2017: 267.738 -8.7375 -3.81928e-007
+2018: 267.714 -17.475 -7.63857e-007
+2019: 267.69 -26.2125 -1.14578e-006
+2020: 267.666 -34.95 -1.52771e-006
+2021: 267.641 -43.6875 -1.90964e-006
+2022: 267.617 -52.425 -2.29157e-006
+2023: 267.593 -61.1625 -2.6735e-006
+2024: 267.569 -69.9 -3.05543e-006
+2025: 267.545 -78.6375 -3.43735e-006
+2026: 267.52 -87.375 -3.81928e-006
+2027: 267.496 -96.1125 -4.20121e-006
+2028: 267.472 -104.85 -4.58314e-006
+2029: 267.448 -113.588 165
+2030: 267.423 -122.325 165
+2031: 267.399 -131.063 165
+2032: 267.375 -139.8 165
+2033: 267.351 -148.538 165
+2034: 267.327 -157.275 165
+2035: 267.302 -166.013 165
+2036: 267.278 -174.75 165
+2037: 267.254 -183.487 165
+2038: 267.23 -192.225 -8.40242e-006
+2039: 267.205 -200.963 -8.78435e-006
+2040: 267.181 -209.7 -9.16628e-006
+2041: 267.157 -218.438 -9.54821e-006
+2042: 267.133 -227.175 -9.93014e-006
+2043: 267.109 -235.913 -1.03121e-005
+2044: 267.084 -244.65 -1.0694e-005
+2045: 267.06 -253.387 -1.10759e-005
+2046: 267.036 -262.125 -1.14578e-005
+2047: 267.012 -270.862 -1.18398e-005
+2048: 266.987 -279.6 -1.22217e-005
+2049: 266.963 -288.338 -1.26036e-005
+2050: 266.939 -297.075 330
+2051: 266.915 -305.813 -1.33675e-005
+2052: 266.891 -314.55 -1.37494e-005
+2053: 266.866 -323.287 -1.41313e-005
+2054: 266.842 -332.025 -1.45133e-005
+2055: 266.818 -340.763 -1.48952e-005
+2056: 266.794 -349.5 -1.52771e-005
+2057: 266.77 -358.237 -1.56591e-005
+2058: 266.745 -366.975 -1.6041e-005
+2059: 266.721 -375.712 -1.64229e-005
+2060: 266.697 -384.45 -1.68048e-005
+2061: 266.673 -393.188 -1.71868e-005
+2062: 266.648 -401.925 -1.75687e-005
+2063: 266.624 -410.663 -1.79506e-005
+2064: 266.6 -419.4 -1.83326e-005
+2065: 266.576 -428.138 -1.87145e-005
+2066: 266.552 -436.875 -1.90964e-005
+2067: 266.527 -445.613 -1.94783e-005
+2068: 266.503 -454.35 -1.98603e-005
+2069: 266.479 -463.088 -2.02422e-005
+2070: 266.455 -471.825 -2.06241e-005
+2071: 266.43 -480.563 -2.10061e-005
+2072: 266.406 -489.3 -2.1388e-005
+2073: 266.382 -498.038 -2.17699e-005
+2074: 266.358 -506.775 -2.21518e-005
+2075: 266.334 -515.513 -2.25338e-005
+2076: 266.309 -524.25 -2.29157e-005
+2077: 266.285 -532.987 -2.32976e-005
+2078: 266.261 -541.725 -2.36796e-005
+2079: 266.237 -550.463 -2.40615e-005
+2080: 266.212 -559.2 -2.44434e-005
+2081: 276.4 0 0
+2082: 276.375 -8.7375 -3.81928e-007
+2083: 276.35 -17.475 -7.63857e-007
+2084: 276.325 -26.2125 -1.14578e-006
+2085: 276.3 -34.95 -1.52771e-006
+2086: 276.275 -43.6875 -1.90964e-006
+2087: 276.25 -52.425 -2.29157e-006
+2088: 276.225 -61.1625 -2.6735e-006
+2089: 276.2 -69.9 -3.05543e-006
+2090: 276.175 -78.6375 -3.43735e-006
+2091: 276.15 -87.375 -3.81928e-006
+2092: 276.125 -96.1125 -4.20121e-006
+2093: 276.1 -104.85 -4.58314e-006
+2094: 276.075 -113.588 165
+2095: 276.05 -122.325 165
+2096: 276.025 -131.063 165
+2097: 276 -139.8 165
+2098: 275.975 -148.538 165
+2099: 275.95 -157.275 165
+2100: 275.925 -166.013 -7.25664e-006
+2101: 275.9 -174.75 -7.63856e-006
+2102: 275.875 -183.487 -8.02049e-006
+2103: 275.85 -192.225 -8.40242e-006
+2104: 275.825 -200.963 -8.78435e-006
+2105: 275.8 -209.7 -9.16628e-006
+2106: 275.775 -218.438 -9.54821e-006
+2107: 275.75 -227.175 -9.93014e-006
+2108: 275.725 -235.913 -1.03121e-005
+2109: 275.7 -244.65 -1.0694e-005
+2110: 275.675 -253.387 -1.10759e-005
+2111: 275.65 -262.125 -1.14578e-005
+2112: 275.625 -270.862 -1.18398e-005
+2113: 275.6 -279.6 -1.22217e-005
+2114: 275.575 -288.338 -1.26036e-005
+2115: 275.55 -297.075 330
+2116: 275.525 -305.813 330
+2117: 275.5 -314.55 330
+2118: 275.475 -323.287 330
+2119: 275.45 -332.025 -1.45133e-005
+2120: 275.425 -340.763 -1.48952e-005
+2121: 275.4 -349.5 -1.52771e-005
+2122: 275.375 -358.237 -1.56591e-005
+2123: 275.35 -366.975 -1.6041e-005
+2124: 275.325 -375.712 -1.64229e-005
+2125: 275.3 -384.45 -1.68048e-005
+2126: 275.275 -393.188 -1.71868e-005
+2127: 275.25 -401.925 -1.75687e-005
+2128: 275.225 -410.663 -1.79506e-005
+2129: 275.2 -419.4 -1.83326e-005
+2130: 275.175 -428.138 -1.87145e-005
+2131: 275.15 -436.875 -1.90964e-005
+2132: 275.125 -445.613 -1.94783e-005
+2133: 275.1 -454.35 -1.98603e-005
+2134: 275.075 -463.088 -2.02422e-005
+2135: 275.05 -471.825 -2.06241e-005
+2136: 275.025 -480.563 -2.10061e-005
+2137: 275 -489.3 -2.1388e-005
+2138: 274.975 -498.037 -2.17699e-005
+2139: 274.95 -506.775 -2.21518e-005
+2140: 274.925 -515.513 -2.25338e-005
+2141: 274.9 -524.25 -2.29157e-005
+2142: 274.875 -532.987 -2.32976e-005
+2143: 274.85 -541.725 -2.36796e-005
+2144: 274.825 -550.463 -2.40615e-005
+2145: 274.8 -559.2 -2.44434e-005
+2146: 285.037 0 0
+2147: 285.012 -8.7375 -3.81928e-007
+2148: 284.986 -17.475 -7.63857e-007
+2149: 284.96 -26.2125 -1.14578e-006
+2150: 284.934 -34.95 -1.52771e-006
+2151: 284.909 -43.6875 -1.90964e-006
+2152: 284.883 -52.425 -2.29157e-006
+2153: 284.857 -61.1625 -2.6735e-006
+2154: 284.831 -69.9 -3.05543e-006
+2155: 284.805 -78.6375 -3.43735e-006
+2156: 284.78 -87.375 -3.81928e-006
+2157: 284.754 -96.1125 -4.20121e-006
+2158: 284.728 -104.85 -4.58314e-006
+2159: 284.702 -113.588 165
+2160: 284.677 -122.325 165
+2161: 284.651 -131.063 -5.72892e-006
+2162: 284.625 -139.8 -6.11085e-006
+2163: 284.599 -148.538 -6.49278e-006
+2164: 284.573 -157.275 -6.87471e-006
+2165: 284.548 -166.013 -7.25664e-006
+2166: 284.522 -174.75 -7.63856e-006
+2167: 284.496 -183.487 -8.02049e-006
+2168: 284.47 -192.225 -8.40242e-006
+2169: 284.445 -200.963 -8.78435e-006
+2170: 284.419 -209.7 -9.16628e-006
+2171: 284.393 -218.438 -9.54821e-006
+2172: 284.367 -227.175 -9.93014e-006
+2173: 284.341 -235.913 -1.03121e-005
+2174: 284.316 -244.65 -1.0694e-005
+2175: 284.29 -253.387 -1.10759e-005
+2176: 284.264 -262.125 -1.14578e-005
+2177: 284.238 -270.862 -1.18398e-005
+2178: 284.212 -279.6 -1.22217e-005
+2179: 284.187 -288.338 -1.26036e-005
+2180: 284.161 -297.075 330
+2181: 284.135 -305.813 330
+2182: 284.109 -314.55 330
+2183: 284.084 -323.287 330
+2184: 284.058 -332.025 330
+2185: 284.032 -340.763 330
+2186: 284.006 -349.5 330
+2187: 283.98 -358.237 -1.56591e-005
+2188: 283.955 -366.975 -1.6041e-005
+2189: 283.929 -375.712 -1.64229e-005
+2190: 283.903 -384.45 -1.68048e-005
+2191: 283.877 -393.188 -1.71868e-005
+2192: 283.852 -401.925 -1.75687e-005
+2193: 283.826 -410.663 -1.79506e-005
+2194: 283.8 -419.4 -1.83326e-005
+2195: 283.774 -428.138 -1.87145e-005
+2196: 283.748 -436.875 -1.90964e-005
+2197: 283.723 -445.613 -1.94783e-005
+2198: 283.697 -454.35 -1.98603e-005
+2199: 283.671 -463.088 -2.02422e-005
+2200: 283.645 -471.825 -2.06241e-005
+2201: 283.62 -480.563 -2.10061e-005
+2202: 283.594 -489.3 -2.1388e-005
+2203: 283.568 -498.038 -2.17699e-005
+2204: 283.542 -506.775 -2.21518e-005
+2205: 283.516 -515.513 -2.25338e-005
+2206: 283.491 -524.25 -2.29157e-005
+2207: 283.465 -532.987 -2.32976e-005
+2208: 283.439 -541.725 -2.36796e-005
+2209: 283.413 -550.463 -2.40615e-005
+2210: 283.387 -559.2 -2.44434e-005
+2211: 293.675 0 0
+2212: 293.648 -8.7375 -3.81928e-007
+2213: 293.622 -17.475 -7.63857e-007
+2214: 293.595 -26.2125 -1.14578e-006
+2215: 293.569 -34.95 -1.52771e-006
+2216: 293.542 -43.6875 -1.90964e-006
+2217: 293.516 -52.425 -2.29157e-006
+2218: 293.489 -61.1625 -2.6735e-006
+2219: 293.463 -69.9 -3.05543e-006
+2220: 293.436 -78.6375 -3.43735e-006
+2221: 293.409 -87.375 -3.81928e-006
+2222: 293.383 -96.1125 -4.20121e-006
+2223: 293.356 -104.85 -4.58314e-006
+2224: 293.33 -113.588 -4.96507e-006
+2225: 293.303 -122.325 -5.347e-006
+2226: 293.277 -131.063 -5.72892e-006
+2227: 293.25 -139.8 -6.11085e-006
+2228: 293.223 -148.538 -6.49278e-006
+2229: 293.197 -157.275 -6.87471e-006
+2230: 293.17 -166.013 -7.25664e-006
+2231: 293.144 -174.75 -7.63856e-006
+2232: 293.117 -183.487 -8.02049e-006
+2233: 293.091 -192.225 -8.40242e-006
+2234: 293.064 -200.963 -8.78435e-006
+2235: 293.037 -209.7 -9.16628e-006
+2236: 293.011 -218.438 -9.54821e-006
+2237: 292.984 -227.175 -9.93014e-006
+2238: 292.958 -235.913 -1.03121e-005
+2239: 292.931 -244.65 -1.0694e-005
+2240: 292.905 -253.387 -1.10759e-005
+2241: 292.878 -262.125 -1.14578e-005
+2242: 292.852 -270.862 -1.18398e-005
+2243: 292.825 -279.6 -1.22217e-005
+2244: 292.798 -288.338 330
+2245: 292.772 -297.075 330
+2246: 292.745 -305.813 330
+2247: 292.719 -314.55 330
+2248: 292.692 -323.287 330
+2249: 292.666 -332.025 330
+2250: 292.639 -340.763 330
+2251: 292.612 -349.5 330
+2252: 292.586 -358.237 330
+2253: 292.559 -366.975 330
+2254: 292.533 -375.712 330
+2255: 292.506 -384.45 330
+2256: 292.48 -393.188 -1.71868e-005
+2257: 292.453 -401.925 -1.75687e-005
+2258: 292.427 -410.663 -1.79506e-005
+2259: 292.4 -419.4 -1.83326e-005
+2260: 292.373 -428.138 -1.87145e-005
+2261: 292.347 -436.875 -1.90964e-005
+2262: 292.32 -445.613 -1.94783e-005
+2263: 292.294 -454.35 -1.98603e-005
+2264: 292.267 -463.088 -2.02422e-005
+2265: 292.241 -471.825 -2.06241e-005
+2266: 292.214 -480.563 -2.10061e-005
+2267: 292.188 -489.3 -2.1388e-005
+2268: 292.161 -498.037 -2.17699e-005
+2269: 292.134 -506.775 -2.21518e-005
+2270: 292.108 -515.513 -2.25338e-005
+2271: 292.081 -524.25 -2.29157e-005
+2272: 292.055 -532.987 -2.32976e-005
+2273: 292.028 -541.725 -2.36796e-005
+2274: 292.002 -550.463 -2.40615e-005
+2275: 291.975 -559.2 -2.44434e-005
+2276: 302.313 0 0
+2277: 302.285 -8.7375 -3.81928e-007
+2278: 302.258 -17.475 -7.63857e-007
+2279: 302.23 -26.2125 -1.14578e-006
+2280: 302.203 -34.95 -1.52771e-006
+2281: 302.176 -43.6875 -1.90964e-006
+2282: 302.148 -52.425 -2.29157e-006
+2283: 302.121 -61.1625 -2.6735e-006
+2284: 302.094 -69.9 -3.05543e-006
+2285: 302.066 -78.6375 -3.43735e-006
+2286: 302.039 -87.375 -3.81928e-006
+2287: 302.012 -96.1125 -4.20121e-006
+2288: 301.984 -104.85 -4.58314e-006
+2289: 301.957 -113.588 -4.96507e-006
+2290: 301.93 -122.325 -5.347e-006
+2291: 301.902 -131.063 -5.72892e-006
+2292: 301.875 -139.8 -6.11085e-006
+2293: 301.848 -148.538 -6.49278e-006
+2294: 301.82 -157.275 -6.87471e-006
+2295: 301.793 -166.013 -7.25664e-006
+2296: 301.766 -174.75 -7.63856e-006
+2297: 301.738 -183.487 -8.02049e-006
+2298: 301.711 -192.225 -8.40242e-006
+2299: 301.684 -200.963 -8.78435e-006
+2300: 301.656 -209.7 -9.16628e-006
+2301: 301.629 -218.438 -9.54821e-006
+2302: 301.602 -227.175 -9.93014e-006
+2303: 301.574 -235.913 -1.03121e-005
+2304: 301.547 -244.65 -1.0694e-005
+2305: 301.52 -253.387 -1.10759e-005
+2306: 301.492 -262.125 -1.14578e-005
+2307: 301.465 -270.862 -1.18398e-005
+2308: 301.438 -279.6 -1.22217e-005
+2309: 301.41 -288.337 330
+2310: 301.383 -297.075 330
+2311: 301.355 -305.813 330
+2312: 301.328 -314.55 330
+2313: 301.301 -323.287 330
+2314: 301.273 -332.025 330
+2315: 301.246 -340.763 330
+2316: 301.219 -349.5 330
+2317: 301.191 -358.237 330
+2318: 301.164 -366.975 330
+2319: 301.137 -375.712 330
+2320: 301.109 -384.45 330
+2321: 301.082 -393.188 330
+2322: 301.055 -401.925 330
+2323: 301.027 -410.663 330
+2324: 301 -419.4 -1.83326e-005
+2325: 300.973 -428.138 -1.87145e-005
+2326: 300.945 -436.875 -1.90964e-005
+2327: 300.918 -445.613 -1.94783e-005
+2328: 300.891 -454.35 -1.98603e-005
+2329: 300.863 -463.088 -2.02422e-005
+2330: 300.836 -471.825 -2.06241e-005
+2331: 300.809 -480.563 -2.10061e-005
+2332: 300.781 -489.3 -2.1388e-005
+2333: 300.754 -498.038 -2.17699e-005
+2334: 300.727 -506.775 -2.21518e-005
+2335: 300.699 -515.513 -2.25338e-005
+2336: 300.672 -524.25 -2.29157e-005
+2337: 300.645 -532.987 -2.32976e-005
+2338: 300.617 -541.725 -2.36796e-005
+2339: 300.59 -550.463 -2.40615e-005
+2340: 300.563 -559.2 -2.44434e-005
+2341: 310.95 0 0
+2342: 310.922 -8.7375 -3.81928e-007
+2343: 310.894 -17.475 -7.63857e-007
+2344: 310.866 -26.2125 -1.14578e-006
+2345: 310.837 -34.95 -1.52771e-006
+2346: 310.809 -43.6875 -1.90964e-006
+2347: 310.781 -52.425 -2.29157e-006
+2348: 310.753 -61.1625 -2.6735e-006
+2349: 310.725 -69.9 -3.05543e-006
+2350: 310.697 -78.6375 -3.43735e-006
+2351: 310.669 -87.375 -3.81928e-006
+2352: 310.641 -96.1125 -4.20121e-006
+2353: 310.612 -104.85 -4.58314e-006
+2354: 310.584 -113.588 -4.96507e-006
+2355: 310.556 -122.325 -5.347e-006
+2356: 310.528 -131.063 -5.72892e-006
+2357: 310.5 -139.8 -6.11085e-006
+2358: 310.472 -148.538 -6.49278e-006
+2359: 310.444 -157.275 -6.87471e-006
+2360: 310.416 -166.013 -7.25664e-006
+2361: 310.388 -174.75 -7.63856e-006
+2362: 310.359 -183.487 -8.02049e-006
+2363: 310.331 -192.225 -8.40242e-006
+2364: 310.303 -200.963 -8.78435e-006
+2365: 310.275 -209.7 -9.16628e-006
+2366: 310.247 -218.438 -9.54821e-006
+2367: 310.219 -227.175 -9.93014e-006
+2368: 310.191 -235.913 -1.03121e-005
+2369: 310.162 -244.65 -1.0694e-005
+2370: 310.134 -253.387 -1.10759e-005
+2371: 310.106 -262.125 -1.14578e-005
+2372: 310.078 -270.862 -1.18398e-005
+2373: 310.05 -279.6 -1.22217e-005
+2374: 310.022 -288.337 330
+2375: 309.994 -297.075 330
+2376: 309.966 -305.813 330
+2377: 309.938 -314.55 330
+2378: 309.909 -323.287 330
+2379: 309.881 -332.025 330
+2380: 309.853 -340.763 330
+2381: 309.825 -349.5 330
+2382: 309.797 -358.237 330
+2383: 309.769 -366.975 330
+2384: 309.741 -375.712 330
+2385: 309.712 -384.45 330
+2386: 309.684 -393.188 330
+2387: 309.656 -401.925 330
+2388: 309.628 -410.663 330
+2389: 309.6 -419.4 330
+2390: 309.572 -428.138 330
+2391: 309.544 -436.875 330
+2392: 309.516 -445.613 -1.94783e-005
+2393: 309.487 -454.35 -1.98603e-005
+2394: 309.459 -463.088 -2.02422e-005
+2395: 309.431 -471.825 -2.06241e-005
+2396: 309.403 -480.563 -2.10061e-005
+2397: 309.375 -489.3 -2.1388e-005
+2398: 309.347 -498.037 -2.17699e-005
+2399: 309.319 -506.775 -2.21518e-005
+2400: 309.291 -515.513 -2.25338e-005
+2401: 309.263 -524.25 -2.29157e-005
+2402: 309.234 -532.987 -2.32976e-005
+2403: 309.206 -541.725 -2.36796e-005
+2404: 309.178 -550.463 -2.40615e-005
+2405: 309.15 -559.2 -2.44434e-005
+2406: 319.588 0 0
+2407: 319.559 -8.7375 -3.81928e-007
+2408: 319.53 -17.475 -7.63857e-007
+2409: 319.501 -26.2125 -1.14578e-006
+2410: 319.472 -34.95 -1.52771e-006
+2411: 319.443 -43.6875 -1.90964e-006
+2412: 319.414 -52.425 -2.29157e-006
+2413: 319.385 -61.1625 -2.6735e-006
+2414: 319.356 -69.9 -3.05543e-006
+2415: 319.327 -78.6375 -3.43735e-006
+2416: 319.298 -87.375 -3.81928e-006
+2417: 319.27 -96.1125 -4.20121e-006
+2418: 319.241 -104.85 -4.58314e-006
+2419: 319.212 -113.588 -4.96507e-006
+2420: 319.183 -122.325 -5.347e-006
+2421: 319.154 -131.063 -5.72892e-006
+2422: 319.125 -139.8 -6.11085e-006
+2423: 319.096 -148.538 -6.49278e-006
+2424: 319.067 -157.275 -6.87471e-006
+2425: 319.038 -166.013 -7.25664e-006
+2426: 319.009 -174.75 -7.63856e-006
+2427: 318.98 -183.487 -8.02049e-006
+2428: 318.952 -192.225 -8.40242e-006
+2429: 318.923 -200.963 -8.78435e-006
+2430: 318.894 -209.7 -9.16628e-006
+2431: 318.865 -218.438 -9.54821e-006
+2432: 318.836 -227.175 -9.93014e-006
+2433: 318.807 -235.913 -1.03121e-005
+2434: 318.778 -244.65 -1.0694e-005
+2435: 318.749 -253.387 -1.10759e-005
+2436: 318.72 -262.125 -1.14578e-005
+2437: 318.691 -270.862 -1.18398e-005
+2438: 318.662 -279.6 330
+2439: 318.634 -288.337 330
+2440: 318.605 -297.075 330
+2441: 318.576 -305.813 330
+2442: 318.547 -314.55 330
+2443: 318.518 -323.287 330
+2444: 318.489 -332.025 330
+2445: 318.46 -340.763 330
+2446: 318.431 -349.5 330
+2447: 318.402 -358.237 330
+2448: 318.373 -366.975 330
+2449: 318.345 -375.712 330
+2450: 318.316 -384.45 330
+2451: 318.287 -393.188 330
+2452: 318.258 -401.925 330
+2453: 318.229 -410.663 330
+2454: 318.2 -419.4 330
+2455: 318.171 -428.138 330
+2456: 318.142 -436.875 330
+2457: 318.113 -445.613 330
+2458: 318.084 -454.35 330
+2459: 318.055 -463.088 -2.02422e-005
+2460: 318.027 -471.825 -2.06241e-005
+2461: 317.998 -480.563 -2.10061e-005
+2462: 317.969 -489.3 -2.1388e-005
+2463: 317.94 -498.038 -2.17699e-005
+2464: 317.911 -506.775 -2.21518e-005
+2465: 317.882 -515.513 -2.25338e-005
+2466: 317.853 -524.25 -2.29157e-005
+2467: 317.824 -532.987 -2.32976e-005
+2468: 317.795 -541.725 -2.36796e-005
+2469: 317.766 -550.463 -2.40615e-005
+2470: 317.737 -559.2 -2.44434e-005
+2471: 328.225 0 0
+2472: 328.195 -8.7375 -3.81928e-007
+2473: 328.166 -17.475 -7.63857e-007
+2474: 328.136 -26.2125 -1.14578e-006
+2475: 328.106 -34.95 -1.52771e-006
+2476: 328.077 -43.6875 -1.90964e-006
+2477: 328.047 -52.425 -2.29157e-006
+2478: 328.017 -61.1625 -2.6735e-006
+2479: 327.988 -69.9 -3.05543e-006
+2480: 327.958 -78.6375 -3.43735e-006
+2481: 327.928 -87.375 -3.81928e-006
+2482: 327.898 -96.1125 -4.20121e-006
+2483: 327.869 -104.85 -4.58314e-006
+2484: 327.839 -113.588 -4.96507e-006
+2485: 327.809 -122.325 -5.347e-006
+2486: 327.78 -131.063 -5.72892e-006
+2487: 327.75 -139.8 -6.11085e-006
+2488: 327.72 -148.538 -6.49278e-006
+2489: 327.691 -157.275 -6.87471e-006
+2490: 327.661 -166.013 -7.25664e-006
+2491: 327.631 -174.75 -7.63856e-006
+2492: 327.602 -183.487 -8.02049e-006
+2493: 327.572 -192.225 -8.40242e-006
+2494: 327.542 -200.963 -8.78435e-006
+2495: 327.513 -209.7 -9.16628e-006
+2496: 327.483 -218.438 -9.54821e-006
+2497: 327.453 -227.175 -9.93014e-006
+2498: 327.423 -235.913 -1.03121e-005
+2499: 327.394 -244.65 -1.0694e-005
+2500: 327.364 -253.387 -1.10759e-005
+2501: 327.334 -262.125 -1.14578e-005
+2502: 327.305 -270.862 -1.18398e-005
+2503: 327.275 -279.6 330
+2504: 327.245 -288.337 330
+2505: 327.216 -297.075 330
+2506: 327.186 -305.813 330
+2507: 327.156 -314.55 330
+2508: 327.127 -323.287 330
+2509: 327.097 -332.025 330
+2510: 327.067 -340.763 330
+2511: 327.037 -349.5 330
+2512: 327.008 -358.237 330
+2513: 326.978 -366.975 330
+2514: 326.948 -375.712 330
+2515: 326.919 -384.45 330
+2516: 326.889 -393.188 330
+2517: 326.859 -401.925 330
+2518: 326.83 -410.663 330
+2519: 326.8 -419.4 330
+2520: 326.77 -428.138 330
+2521: 326.741 -436.875 330
+2522: 326.711 -445.613 330
+2523: 326.681 -454.35 -1.98603e-005
+2524: 326.652 -463.088 -2.02422e-005
+2525: 326.622 -471.825 -2.06241e-005
+2526: 326.592 -480.563 -2.10061e-005
+2527: 326.563 -489.3 -2.1388e-005
+2528: 326.533 -498.037 -2.17699e-005
+2529: 326.503 -506.775 -2.21518e-005
+2530: 326.473 -515.513 -2.25338e-005
+2531: 326.444 -524.25 -2.29157e-005
+2532: 326.414 -532.987 -2.32976e-005
+2533: 326.384 -541.725 -2.36796e-005
+2534: 326.355 -550.463 -2.40615e-005
+2535: 326.325 -559.2 -2.44434e-005
+2536: 336.862 0 0
+2537: 336.832 -8.7375 -3.81928e-007
+2538: 336.802 -17.475 -7.63857e-007
+2539: 336.771 -26.2125 -1.14578e-006
+2540: 336.741 -34.95 -1.52771e-006
+2541: 336.71 -43.6875 -1.90964e-006
+2542: 336.68 -52.425 -2.29157e-006
+2543: 336.649 -61.1625 -2.6735e-006
+2544: 336.619 -69.9 -3.05543e-006
+2545: 336.588 -78.6375 -3.43735e-006
+2546: 336.558 -87.375 -3.81928e-006
+2547: 336.527 -96.1125 -4.20121e-006
+2548: 336.497 -104.85 -4.58314e-006
+2549: 336.466 -113.588 -4.96507e-006
+2550: 336.436 -122.325 -5.347e-006
+2551: 336.405 -131.063 -5.72892e-006
+2552: 336.375 -139.8 -6.11085e-006
+2553: 336.345 -148.538 -6.49278e-006
+2554: 336.314 -157.275 -6.87471e-006
+2555: 336.284 -166.012 -7.25664e-006
+2556: 336.253 -174.75 -7.63856e-006
+2557: 336.223 -183.487 -8.02049e-006
+2558: 336.192 -192.225 -8.40242e-006
+2559: 336.162 -200.963 -8.78435e-006
+2560: 336.131 -209.7 -9.16628e-006
+2561: 336.101 -218.438 -9.54821e-006
+2562: 336.07 -227.175 -9.93014e-006
+2563: 336.04 -235.913 -1.03121e-005
+2564: 336.009 -244.65 -1.0694e-005
+2565: 335.979 -253.387 -1.10759e-005
+2566: 335.948 -262.125 -1.14578e-005
+2567: 335.918 -270.862 -1.18398e-005
+2568: 335.887 -279.6 330
+2569: 335.857 -288.337 330
+2570: 335.827 -297.075 330
+2571: 335.796 -305.813 330
+2572: 335.766 -314.55 330
+2573: 335.735 -323.287 330
+2574: 335.705 -332.025 330
+2575: 335.674 -340.763 330
+2576: 335.644 -349.5 330
+2577: 335.613 -358.237 330
+2578: 335.583 -366.975 330
+2579: 335.552 -375.712 330
+2580: 335.522 -384.45 330
+2581: 335.491 -393.188 330
+2582: 335.461 -401.925 330
+2583: 335.43 -410.663 330
+2584: 335.4 -419.4 330
+2585: 335.37 -428.138 330
+2586: 335.339 -436.875 330
+2587: 335.309 -445.613 330
+2588: 335.278 -454.35 -1.98603e-005
+2589: 335.248 -463.088 -2.02422e-005
+2590: 335.217 -471.825 -2.06241e-005
+2591: 335.187 -480.563 -2.10061e-005
+2592: 335.156 -489.3 -2.1388e-005
+2593: 335.126 -498.038 -2.17699e-005
+2594: 335.095 -506.775 -2.21518e-005
+2595: 335.065 -515.513 -2.25338e-005
+2596: 335.034 -524.25 -2.29157e-005
+2597: 335.004 -532.987 -2.32976e-005
+2598: 334.973 -541.725 -2.36796e-005
+2599: 334.943 -550.463 -2.40615e-005
+2600: 334.913 -559.2 -2.44434e-005
+2601: 345.5 0 0
+2602: 345.469 -8.7375 -3.81928e-007
+2603: 345.438 -17.475 -7.63857e-007
+2604: 345.406 -26.2125 -1.14578e-006
+2605: 345.375 -34.95 -1.52771e-006
+2606: 345.344 -43.6875 -1.90964e-006
+2607: 345.313 -52.425 -2.29157e-006
+2608: 345.281 -61.1625 -2.6735e-006
+2609: 345.25 -69.9 -3.05543e-006
+2610: 345.219 -78.6375 -3.43735e-006
+2611: 345.188 -87.375 -3.81928e-006
+2612: 345.156 -96.1125 -4.20121e-006
+2613: 345.125 -104.85 -4.58314e-006
+2614: 345.094 -113.588 -4.96507e-006
+2615: 345.063 -122.325 -5.347e-006
+2616: 345.031 -131.063 -5.72892e-006
+2617: 345 -139.8 -6.11085e-006
+2618: 344.969 -148.538 -6.49278e-006
+2619: 344.938 -157.275 -6.87471e-006
+2620: 344.906 -166.012 -7.25664e-006
+2621: 344.875 -174.75 -7.63856e-006
+2622: 344.844 -183.487 -8.02049e-006
+2623: 344.813 -192.225 -8.40242e-006
+2624: 344.781 -200.963 -8.78435e-006
+2625: 344.75 -209.7 -9.16628e-006
+2626: 344.719 -218.438 -9.54821e-006
+2627: 344.688 -227.175 -9.93014e-006
+2628: 344.656 -235.913 -1.03121e-005
+2629: 344.625 -244.65 -1.0694e-005
+2630: 344.594 -253.387 -1.10759e-005
+2631: 344.562 -262.125 -1.14578e-005
+2632: 344.531 -270.862 -1.18398e-005
+2633: 344.5 -279.6 330
+2634: 344.469 -288.337 330
+2635: 344.438 -297.075 330
+2636: 344.406 -305.813 330
+2637: 344.375 -314.55 330
+2638: 344.344 -323.287 330
+2639: 344.313 -332.025 330
+2640: 344.281 -340.763 330
+2641: 344.25 -349.5 330
+2642: 344.219 -358.237 330
+2643: 344.188 -366.975 330
+2644: 344.156 -375.712 330
+2645: 344.125 -384.45 330
+2646: 344.094 -393.188 330
+2647: 344.063 -401.925 330
+2648: 344.031 -410.663 330
+2649: 344 -419.4 330
+2650: 343.969 -428.138 330
+2651: 343.938 -436.875 330
+2652: 343.906 -445.613 330
+2653: 343.875 -454.35 -1.98603e-005
+2654: 343.844 -463.088 -2.02422e-005
+2655: 343.813 -471.825 -2.06241e-005
+2656: 343.781 -480.563 -2.10061e-005
+2657: 343.75 -489.3 -2.1388e-005
+2658: 343.719 -498.037 -2.17699e-005
+2659: 343.688 -506.775 -2.21518e-005
+2660: 343.656 -515.513 -2.25338e-005
+2661: 343.625 -524.25 -2.29157e-005
+2662: 343.594 -532.987 -2.32976e-005
+2663: 343.563 -541.725 -2.36796e-005
+2664: 343.531 -550.463 -2.40615e-005
+2665: 343.5 -559.2 -2.44434e-005
+2666: 354.138 0 0
+2667: 354.105 -8.7375 -3.81928e-007
+2668: 354.073 -17.475 -7.63857e-007
+2669: 354.041 -26.2125 -1.14578e-006
+2670: 354.009 -34.95 -1.52771e-006
+2671: 353.977 -43.6875 -1.90964e-006
+2672: 353.945 -52.425 -2.29157e-006
+2673: 353.913 -61.1625 -2.6735e-006
+2674: 353.881 -69.9 -3.05543e-006
+2675: 353.849 -78.6375 -3.43735e-006
+2676: 353.817 -87.375 -3.81928e-006
+2677: 353.785 -96.1125 -4.20121e-006
+2678: 353.753 -104.85 -4.58314e-006
+2679: 353.721 -113.588 -4.96507e-006
+2680: 353.689 -122.325 -5.347e-006
+2681: 353.657 -131.063 -5.72892e-006
+2682: 353.625 -139.8 -6.11085e-006
+2683: 353.593 -148.538 -6.49278e-006
+2684: 353.561 -157.275 -6.87471e-006
+2685: 353.529 -166.012 -7.25664e-006
+2686: 353.497 -174.75 -7.63856e-006
+2687: 353.465 -183.487 -8.02049e-006
+2688: 353.433 -192.225 -8.40242e-006
+2689: 353.401 -200.963 -8.78435e-006
+2690: 353.369 -209.7 -9.16628e-006
+2691: 353.337 -218.438 -9.54821e-006
+2692: 353.305 -227.175 -9.93014e-006
+2693: 353.273 -235.913 -1.03121e-005
+2694: 353.241 -244.65 -1.0694e-005
+2695: 353.209 -253.387 -1.10759e-005
+2696: 353.177 -262.125 -1.14578e-005
+2697: 353.145 -270.862 330
+2698: 353.112 -279.6 330
+2699: 353.08 -288.337 330
+2700: 353.048 -297.075 330
+2701: 353.016 -305.813 330
+2702: 352.984 -314.55 330
+2703: 352.952 -323.287 330
+2704: 352.92 -332.025 330
+2705: 352.888 -340.763 330
+2706: 352.856 -349.5 330
+2707: 352.824 -358.237 330
+2708: 352.792 -366.975 330
+2709: 352.76 -375.712 330
+2710: 352.728 -384.45 330
+2711: 352.696 -393.188 330
+2712: 352.664 -401.925 330
+2713: 352.632 -410.663 330
+2714: 352.6 -419.4 330
+2715: 352.568 -428.138 330
+2716: 352.536 -436.875 330
+2717: 352.504 -445.613 -1.94783e-005
+2718: 352.472 -454.35 -1.98603e-005
+2719: 352.44 -463.088 -2.02422e-005
+2720: 352.408 -471.825 -2.06241e-005
+2721: 352.376 -480.563 -2.10061e-005
+2722: 352.344 -489.3 -2.1388e-005
+2723: 352.312 -498.038 -2.17699e-005
+2724: 352.28 -506.775 -2.21518e-005
+2725: 352.248 -515.513 -2.25338e-005
+2726: 352.216 -524.25 -2.29157e-005
+2727: 352.184 -532.987 -2.32976e-005
+2728: 352.152 -541.725 -2.36796e-005
+2729: 352.12 -550.463 -2.40615e-005
+2730: 352.087 -559.2 -2.44434e-005
+2731: 362.775 0 0
+2732: 362.742 -8.7375 -3.81928e-007
+2733: 362.709 -17.475 -7.63857e-007
+2734: 362.677 -26.2125 -1.14578e-006
+2735: 362.644 -34.95 -1.52771e-006
+2736: 362.611 -43.6875 -1.90964e-006
+2737: 362.578 -52.425 -2.29157e-006
+2738: 362.545 -61.1625 -2.6735e-006
+2739: 362.512 -69.9 -3.05543e-006
+2740: 362.48 -78.6375 -3.43735e-006
+2741: 362.447 -87.375 -3.81928e-006
+2742: 362.414 -96.1125 -4.20121e-006
+2743: 362.381 -104.85 -4.58314e-006
+2744: 362.348 -113.588 -4.96507e-006
+2745: 362.316 -122.325 -5.347e-006
+2746: 362.283 -131.063 -5.72892e-006
+2747: 362.25 -139.8 -6.11085e-006
+2748: 362.217 -148.538 -6.49278e-006
+2749: 362.184 -157.275 -6.87471e-006
+2750: 362.152 -166.012 -7.25664e-006
+2751: 362.119 -174.75 -7.63856e-006
+2752: 362.086 -183.487 -8.02049e-006
+2753: 362.053 -192.225 -8.40242e-006
+2754: 362.02 -200.963 -8.78435e-006
+2755: 361.987 -209.7 -9.16628e-006
+2756: 361.955 -218.438 -9.54821e-006
+2757: 361.922 -227.175 -9.93014e-006
+2758: 361.889 -235.913 -1.03121e-005
+2759: 361.856 -244.65 -1.0694e-005
+2760: 361.823 -253.387 -1.10759e-005
+2761: 361.791 -262.125 -1.14578e-005
+2762: 361.758 -270.862 330
+2763: 361.725 -279.6 330
+2764: 361.692 -288.337 330
+2765: 361.659 -297.075 330
+2766: 361.627 -305.813 330
+2767: 361.594 -314.55 330
+2768: 361.561 -323.287 330
+2769: 361.528 -332.025 330
+2770: 361.495 -340.763 330
+2771: 361.462 -349.5 330
+2772: 361.43 -358.237 330
+2773: 361.397 -366.975 330
+2774: 361.364 -375.712 330
+2775: 361.331 -384.45 330
+2776: 361.298 -393.188 330
+2777: 361.266 -401.925 330
+2778: 361.233 -410.663 330
+2779: 361.2 -419.4 330
+2780: 361.167 -428.138 330
+2781: 361.134 -436.875 330
+2782: 361.102 -445.613 -1.94783e-005
+2783: 361.069 -454.35 -1.98603e-005
+2784: 361.036 -463.088 -2.02422e-005
+2785: 361.003 -471.825 -2.06241e-005
+2786: 360.97 -480.563 -2.10061e-005
+2787: 360.938 -489.3 -2.1388e-005
+2788: 360.905 -498.037 -2.17699e-005
+2789: 360.872 -506.775 -2.21518e-005
+2790: 360.839 -515.513 -2.25338e-005
+2791: 360.806 -524.25 -2.29157e-005
+2792: 360.773 -532.987 -2.32976e-005
+2793: 360.741 -541.725 -2.36796e-005
+2794: 360.708 -550.463 -2.40615e-005
+2795: 360.675 -559.2 -2.44434e-005
+2796: 371.412 0 0
+2797: 371.379 -8.7375 -3.81928e-007
+2798: 371.345 -17.475 -7.63857e-007
+2799: 371.312 -26.2125 -1.14578e-006
+2800: 371.278 -34.95 -1.52771e-006
+2801: 371.245 -43.6875 -1.90964e-006
+2802: 371.211 -52.425 -2.29157e-006
+2803: 371.177 -61.1625 -2.6735e-006
+2804: 371.144 -69.9 -3.05543e-006
+2805: 371.11 -78.6375 -3.43735e-006
+2806: 371.077 -87.375 -3.81928e-006
+2807: 371.043 -96.1125 -4.20121e-006
+2808: 371.009 -104.85 -4.58314e-006
+2809: 370.976 -113.588 -4.96507e-006
+2810: 370.942 -122.325 -5.347e-006
+2811: 370.909 -131.063 -5.72892e-006
+2812: 370.875 -139.8 -6.11085e-006
+2813: 370.841 -148.538 -6.49278e-006
+2814: 370.808 -157.275 -6.87471e-006
+2815: 370.774 -166.012 -7.25664e-006
+2816: 370.741 -174.75 -7.63856e-006
+2817: 370.707 -183.487 -8.02049e-006
+2818: 370.673 -192.225 -8.40242e-006
+2819: 370.64 -200.963 -8.78435e-006
+2820: 370.606 -209.7 -9.16628e-006
+2821: 370.573 -218.438 -9.54821e-006
+2822: 370.539 -227.175 -9.93014e-006
+2823: 370.505 -235.913 -1.03121e-005
+2824: 370.472 -244.65 -1.0694e-005
+2825: 370.438 -253.387 -1.10759e-005
+2826: 370.405 -262.125 -1.14578e-005
+2827: 370.371 -270.862 330
+2828: 370.337 -279.6 330
+2829: 370.304 -288.337 330
+2830: 370.27 -297.075 330
+2831: 370.237 -305.813 330
+2832: 370.203 -314.55 330
+2833: 370.169 -323.287 330
+2834: 370.136 -332.025 330
+2835: 370.102 -340.763 330
+2836: 370.069 -349.5 330
+2837: 370.035 -358.237 330
+2838: 370.002 -366.975 330
+2839: 369.968 -375.712 330
+2840: 369.934 -384.45 330
+2841: 369.901 -393.188 330
+2842: 369.867 -401.925 330
+2843: 369.834 -410.663 330
+2844: 369.8 -419.4 330
+2845: 369.766 -428.138 330
+2846: 369.733 -436.875 330
+2847: 369.699 -445.613 -1.94783e-005
+2848: 369.666 -454.35 -1.98603e-005
+2849: 369.632 -463.088 -2.02422e-005
+2850: 369.598 -471.825 -2.06241e-005
+2851: 369.565 -480.563 -2.10061e-005
+2852: 369.531 -489.3 -2.1388e-005
+2853: 369.498 -498.038 -2.17699e-005
+2854: 369.464 -506.775 -2.21518e-005
+2855: 369.43 -515.513 -2.25338e-005
+2856: 369.397 -524.25 -2.29157e-005
+2857: 369.363 -532.987 -2.32976e-005
+2858: 369.33 -541.725 -2.36796e-005
+2859: 369.296 -550.463 -2.40615e-005
+2860: 369.262 -559.2 -2.44434e-005
+2861: 380.05 0 0
+2862: 380.016 -8.7375 -3.81928e-007
+2863: 379.981 -17.475 -7.63857e-007
+2864: 379.947 -26.2125 -1.14578e-006
+2865: 379.912 -34.95 -1.52771e-006
+2866: 379.878 -43.6875 -1.90964e-006
+2867: 379.844 -52.425 -2.29157e-006
+2868: 379.809 -61.1625 -2.6735e-006
+2869: 379.775 -69.9 -3.05543e-006
+2870: 379.741 -78.6375 -3.43735e-006
+2871: 379.706 -87.375 -3.81928e-006
+2872: 379.672 -96.1125 -4.20121e-006
+2873: 379.638 -104.85 -4.58314e-006
+2874: 379.603 -113.588 -4.96507e-006
+2875: 379.569 -122.325 -5.347e-006
+2876: 379.534 -131.063 -5.72892e-006
+2877: 379.5 -139.8 -6.11085e-006
+2878: 379.466 -148.538 -6.49278e-006
+2879: 379.431 -157.275 -6.87471e-006
+2880: 379.397 -166.012 -7.25664e-006
+2881: 379.362 -174.75 -7.63856e-006
+2882: 379.328 -183.487 -8.02049e-006
+2883: 379.294 -192.225 -8.40242e-006
+2884: 379.259 -200.963 -8.78435e-006
+2885: 379.225 -209.7 -9.16628e-006
+2886: 379.191 -218.438 -9.54821e-006
+2887: 379.156 -227.175 -9.93014e-006
+2888: 379.122 -235.913 -1.03121e-005
+2889: 379.087 -244.65 -1.0694e-005
+2890: 379.053 -253.387 -1.10759e-005
+2891: 379.019 -262.125 330
+2892: 378.984 -270.862 330
+2893: 378.95 -279.6 330
+2894: 378.916 -288.337 330
+2895: 378.881 -297.075 330
+2896: 378.847 -305.813 330
+2897: 378.812 -314.55 330
+2898: 378.778 -323.287 330
+2899: 378.744 -332.025 330
+2900: 378.709 -340.763 330
+2901: 378.675 -349.5 330
+2902: 378.641 -358.237 330
+2903: 378.606 -366.975 330
+2904: 378.572 -375.712 330
+2905: 378.537 -384.45 330
+2906: 378.503 -393.188 330
+2907: 378.469 -401.925 330
+2908: 378.434 -410.663 330
+2909: 378.4 -419.4 330
+2910: 378.366 -428.138 330
+2911: 378.331 -436.875 -1.90964e-005
+2912: 378.297 -445.613 -1.94783e-005
+2913: 378.263 -454.35 -1.98603e-005
+2914: 378.228 -463.088 -2.02422e-005
+2915: 378.194 -471.825 -2.06241e-005
+2916: 378.159 -480.563 -2.10061e-005
+2917: 378.125 -489.3 -2.1388e-005
+2918: 378.091 -498.037 -2.17699e-005
+2919: 378.056 -506.775 -2.21518e-005
+2920: 378.022 -515.513 -2.25338e-005
+2921: 377.987 -524.25 -2.29157e-005
+2922: 377.953 -532.987 -2.32976e-005
+2923: 377.919 -541.725 -2.36796e-005
+2924: 377.884 -550.463 -2.40615e-005
+2925: 377.85 -559.2 -2.44434e-005
+2926: 388.688 0 0
+2927: 388.652 -8.7375 -3.81928e-007
+2928: 388.617 -17.475 -7.63857e-007
+2929: 388.582 -26.2125 -1.14578e-006
+2930: 388.547 -34.95 -1.52771e-006
+2931: 388.512 -43.6875 -1.90964e-006
+2932: 388.477 -52.425 -2.29157e-006
+2933: 388.441 -61.1625 -2.6735e-006
+2934: 388.406 -69.9 -3.05543e-006
+2935: 388.371 -78.6375 -3.43735e-006
+2936: 388.336 -87.375 -3.81928e-006
+2937: 388.301 -96.1125 -4.20121e-006
+2938: 388.266 -104.85 -4.58314e-006
+2939: 388.23 -113.588 -4.96507e-006
+2940: 388.195 -122.325 -5.347e-006
+2941: 388.16 -131.063 -5.72892e-006
+2942: 388.125 -139.8 -6.11085e-006
+2943: 388.09 -148.538 -6.49278e-006
+2944: 388.055 -157.275 -6.87471e-006
+2945: 388.02 -166.012 -7.25664e-006
+2946: 387.984 -174.75 -7.63856e-006
+2947: 387.949 -183.487 -8.02049e-006
+2948: 387.914 -192.225 -8.40242e-006
+2949: 387.879 -200.963 -8.78435e-006
+2950: 387.844 -209.7 -9.16628e-006
+2951: 387.809 -218.438 -9.54821e-006
+2952: 387.773 -227.175 -9.93014e-006
+2953: 387.738 -235.913 -1.03121e-005
+2954: 387.703 -244.65 -1.0694e-005
+2955: 387.668 -253.387 -1.10759e-005
+2956: 387.633 -262.125 330
+2957: 387.598 -270.862 330
+2958: 387.562 -279.6 330
+2959: 387.527 -288.337 330
+2960: 387.492 -297.075 330
+2961: 387.457 -305.813 330
+2962: 387.422 -314.55 330
+2963: 387.387 -323.287 330
+2964: 387.352 -332.025 330
+2965: 387.316 -340.763 330
+2966: 387.281 -349.5 330
+2967: 387.246 -358.237 330
+2968: 387.211 -366.975 330
+2969: 387.176 -375.712 330
+2970: 387.141 -384.45 330
+2971: 387.105 -393.188 330
+2972: 387.07 -401.925 330
+2973: 387.035 -410.663 330
+2974: 387 -419.4 330
+2975: 386.965 -428.138 330
+2976: 386.93 -436.875 -1.90964e-005
+2977: 386.895 -445.613 -1.94783e-005
+2978: 386.859 -454.35 -1.98603e-005
+2979: 386.824 -463.088 -2.02422e-005
+2980: 386.789 -471.825 -2.06241e-005
+2981: 386.754 -480.563 -2.10061e-005
+2982: 386.719 -489.3 -2.1388e-005
+2983: 386.684 -498.038 -2.17699e-005
+2984: 386.648 -506.775 -2.21518e-005
+2985: 386.613 -515.513 -2.25338e-005
+2986: 386.578 -524.25 -2.29157e-005
+2987: 386.543 -532.987 -2.32976e-005
+2988: 386.508 -541.725 -2.36796e-005
+2989: 386.473 -550.463 -2.40615e-005
+2990: 386.437 -559.2 -2.44434e-005
+2991: 397.325 0 0
+2992: 397.289 -8.7375 -3.81928e-007
+2993: 397.253 -17.475 -7.63857e-007
+2994: 397.217 -26.2125 -1.14578e-006
+2995: 397.181 -34.95 -1.52771e-006
+2996: 397.145 -43.6875 -1.90964e-006
+2997: 397.109 -52.425 -2.29157e-006
+2998: 397.073 -61.1625 -2.6735e-006
+2999: 397.037 -69.9 -3.05543e-006
+3000: 397.002 -78.6375 -3.43735e-006
+3001: 396.966 -87.375 -3.81928e-006
+3002: 396.93 -96.1125 -4.20121e-006
+3003: 396.894 -104.85 -4.58314e-006
+3004: 396.858 -113.588 -4.96507e-006
+3005: 396.822 -122.325 -5.347e-006
+3006: 396.786 -131.063 -5.72892e-006
+3007: 396.75 -139.8 -6.11085e-006
+3008: 396.714 -148.538 -6.49278e-006
+3009: 396.678 -157.275 -6.87471e-006
+3010: 396.642 -166.012 -7.25664e-006
+3011: 396.606 -174.75 -7.63856e-006
+3012: 396.57 -183.487 -8.02049e-006
+3013: 396.534 -192.225 -8.40242e-006
+3014: 396.498 -200.963 -8.78435e-006
+3015: 396.462 -209.7 -9.16628e-006
+3016: 396.427 -218.438 -9.54821e-006
+3017: 396.391 -227.175 -9.93014e-006
+3018: 396.355 -235.913 -1.03121e-005
+3019: 396.319 -244.65 -1.0694e-005
+3020: 396.283 -253.387 -1.10759e-005
+3021: 396.247 -262.125 330
+3022: 396.211 -270.862 330
+3023: 396.175 -279.6 330
+3024: 396.139 -288.337 330
+3025: 396.103 -297.075 330
+3026: 396.067 -305.813 330
+3027: 396.031 -314.55 330
+3028: 395.995 -323.287 330
+3029: 395.959 -332.025 330
+3030: 395.923 -340.763 330
+3031: 395.887 -349.5 330
+3032: 395.852 -358.237 330
+3033: 395.816 -366.975 330
+3034: 395.78 -375.712 330
+3035: 395.744 -384.45 330
+3036: 395.708 -393.188 330
+3037: 395.672 -401.925 330
+3038: 395.636 -410.663 330
+3039: 395.6 -419.4 330
+3040: 395.564 -428.138 330
+3041: 395.528 -436.875 -1.90964e-005
+3042: 395.492 -445.613 -1.94783e-005
+3043: 395.456 -454.35 -1.98603e-005
+3044: 395.42 -463.088 -2.02422e-005
+3045: 395.384 -471.825 -2.06241e-005
+3046: 395.348 -480.563 -2.10061e-005
+3047: 395.313 -489.3 -2.1388e-005
+3048: 395.277 -498.037 -2.17699e-005
+3049: 395.241 -506.775 -2.21518e-005
+3050: 395.205 -515.513 -2.25338e-005
+3051: 395.169 -524.25 -2.29157e-005
+3052: 395.133 -532.987 -2.32976e-005
+3053: 395.097 -541.725 -2.36796e-005
+3054: 395.061 -550.463 -2.40615e-005
+3055: 395.025 -559.2 -2.44434e-005
+3056: 405.962 0 0
+3057: 405.926 -8.7375 -3.81928e-007
+3058: 405.889 -17.475 -7.63857e-007
+3059: 405.852 -26.2125 -1.14578e-006
+3060: 405.816 -34.95 -1.52771e-006
+3061: 405.779 -43.6875 -1.90964e-006
+3062: 405.742 -52.425 -2.29157e-006
+3063: 405.705 -61.1625 -2.6735e-006
+3064: 405.669 -69.9 -3.05543e-006
+3065: 405.632 -78.6375 -3.43735e-006
+3066: 405.595 -87.375 -3.81928e-006
+3067: 405.559 -96.1125 -4.20121e-006
+3068: 405.522 -104.85 -4.58314e-006
+3069: 405.485 -113.588 -4.96507e-006
+3070: 405.448 -122.325 -5.347e-006
+3071: 405.412 -131.063 -5.72892e-006
+3072: 405.375 -139.8 -6.11085e-006
+3073: 405.338 -148.538 -6.49278e-006
+3074: 405.302 -157.275 -6.87471e-006
+3075: 405.265 -166.012 -7.25664e-006
+3076: 405.228 -174.75 -7.63856e-006
+3077: 405.191 -183.487 -8.02049e-006
+3078: 405.155 -192.225 -8.40242e-006
+3079: 405.118 -200.963 -8.78435e-006
+3080: 405.081 -209.7 -9.16628e-006
+3081: 405.044 -218.438 -9.54821e-006
+3082: 405.008 -227.175 -9.93014e-006
+3083: 404.971 -235.913 -1.03121e-005
+3084: 404.934 -244.65 -1.0694e-005
+3085: 404.898 -253.388 330
+3086: 404.861 -262.125 330
+3087: 404.824 -270.862 330
+3088: 404.787 -279.6 330
+3089: 404.751 -288.337 330
+3090: 404.714 -297.075 330
+3091: 404.677 -305.813 330
+3092: 404.641 -314.55 330
+3093: 404.604 -323.287 330
+3094: 404.567 -332.025 330
+3095: 404.53 -340.763 330
+3096: 404.494 -349.5 330
+3097: 404.457 -358.237 330
+3098: 404.42 -366.975 330
+3099: 404.384 -375.712 330
+3100: 404.347 -384.45 330
+3101: 404.31 -393.188 330
+3102: 404.273 -401.925 330
+3103: 404.237 -410.663 330
+3104: 404.2 -419.4 330
+3105: 404.163 -428.138 -1.87145e-005
+3106: 404.127 -436.875 -1.90964e-005
+3107: 404.09 -445.613 -1.94783e-005
+3108: 404.053 -454.35 -1.98603e-005
+3109: 404.016 -463.088 -2.02422e-005
+3110: 403.98 -471.825 -2.06241e-005
+3111: 403.943 -480.563 -2.10061e-005
+3112: 403.906 -489.3 -2.1388e-005
+3113: 403.87 -498.038 -2.17699e-005
+3114: 403.833 -506.775 -2.21518e-005
+3115: 403.796 -515.513 -2.25338e-005
+3116: 403.759 -524.25 -2.29157e-005
+3117: 403.723 -532.987 -2.32976e-005
+3118: 403.686 -541.725 -2.36796e-005
+3119: 403.649 -550.463 -2.40615e-005
+3120: 403.612 -559.2 -2.44434e-005
+3121: 414.6 0 0
+3122: 414.562 -8.7375 -3.81928e-007
+3123: 414.525 -17.475 -7.63857e-007
+3124: 414.487 -26.2125 -1.14578e-006
+3125: 414.45 -34.95 -1.52771e-006
+3126: 414.412 -43.6875 -1.90964e-006
+3127: 414.375 -52.425 -2.29157e-006
+3128: 414.338 -61.1625 -2.6735e-006
+3129: 414.3 -69.9 -3.05543e-006
+3130: 414.263 -78.6375 -3.43735e-006
+3131: 414.225 -87.375 -3.81928e-006
+3132: 414.188 -96.1125 -4.20121e-006
+3133: 414.15 -104.85 -4.58314e-006
+3134: 414.112 -113.588 -4.96507e-006
+3135: 414.075 -122.325 -5.347e-006
+3136: 414.038 -131.063 -5.72892e-006
+3137: 414 -139.8 -6.11085e-006
+3138: 413.963 -148.538 -6.49278e-006
+3139: 413.925 -157.275 -6.87471e-006
+3140: 413.887 -166.012 -7.25664e-006
+3141: 413.85 -174.75 -7.63856e-006
+3142: 413.812 -183.487 -8.02049e-006
+3143: 413.775 -192.225 -8.40242e-006
+3144: 413.737 -200.963 -8.78435e-006
+3145: 413.7 -209.7 -9.16628e-006
+3146: 413.662 -218.438 -9.54821e-006
+3147: 413.625 -227.175 -9.93014e-006
+3148: 413.587 -235.913 -1.03121e-005
+3149: 413.55 -244.65 -1.0694e-005
+3150: 413.512 -253.388 330
+3151: 413.475 -262.125 330
+3152: 413.437 -270.862 330
+3153: 413.4 -279.6 330
+3154: 413.362 -288.337 330
+3155: 413.325 -297.075 330
+3156: 413.287 -305.813 330
+3157: 413.25 -314.55 330
+3158: 413.212 -323.287 330
+3159: 413.175 -332.025 330
+3160: 413.137 -340.763 330
+3161: 413.1 -349.5 330
+3162: 413.062 -358.237 330
+3163: 413.025 -366.975 330
+3164: 412.987 -375.712 330
+3165: 412.95 -384.45 330
+3166: 412.912 -393.188 330
+3167: 412.875 -401.925 330
+3168: 412.838 -410.663 330
+3169: 412.8 -419.4 330
+3170: 412.763 -428.138 -1.87145e-005
+3171: 412.725 -436.875 -1.90964e-005
+3172: 412.688 -445.613 -1.94783e-005
+3173: 412.65 -454.35 -1.98603e-005
+3174: 412.613 -463.088 -2.02422e-005
+3175: 412.575 -471.825 -2.06241e-005
+3176: 412.538 -480.563 -2.10061e-005
+3177: 412.5 -489.3 -2.1388e-005
+3178: 412.463 -498.037 -2.17699e-005
+3179: 412.425 -506.775 -2.21518e-005
+3180: 412.387 -515.513 -2.25338e-005
+3181: 412.35 -524.25 -2.29157e-005
+3182: 412.312 -532.987 -2.32976e-005
+3183: 412.275 -541.725 -2.36796e-005
+3184: 412.237 -550.463 -2.40615e-005
+3185: 412.2 -559.2 -2.44434e-005
+3186: 423.237 0 0
+3187: 423.199 -8.7375 -3.81928e-007
+3188: 423.161 -17.475 -7.63857e-007
+3189: 423.123 -26.2125 -1.14578e-006
+3190: 423.084 -34.95 -1.52771e-006
+3191: 423.046 -43.6875 -1.90964e-006
+3192: 423.008 -52.425 -2.29157e-006
+3193: 422.97 -61.1625 -2.6735e-006
+3194: 422.931 -69.9 -3.05543e-006
+3195: 422.893 -78.6375 -3.43735e-006
+3196: 422.855 -87.375 -3.81928e-006
+3197: 422.816 -96.1125 -4.20121e-006
+3198: 422.778 -104.85 -4.58314e-006
+3199: 422.74 -113.588 -4.96507e-006
+3200: 422.702 -122.325 -5.347e-006
+3201: 422.663 -131.063 -5.72892e-006
+3202: 422.625 -139.8 -6.11085e-006
+3203: 422.587 -148.538 -6.49278e-006
+3204: 422.548 -157.275 -6.87471e-006
+3205: 422.51 -166.012 -7.25664e-006
+3206: 422.472 -174.75 -7.63856e-006
+3207: 422.434 -183.487 -8.02049e-006
+3208: 422.395 -192.225 -8.40242e-006
+3209: 422.357 -200.963 -8.78435e-006
+3210: 422.319 -209.7 -9.16628e-006
+3211: 422.28 -218.438 -9.54821e-006
+3212: 422.242 -227.175 -9.93014e-006
+3213: 422.204 -235.913 -1.03121e-005
+3214: 422.166 -244.65 -1.0694e-005
+3215: 422.127 -253.388 330
+3216: 422.089 -262.125 330
+3217: 422.051 -270.862 330
+3218: 422.012 -279.6 330
+3219: 421.974 -288.337 330
+3220: 421.936 -297.075 330
+3221: 421.898 -305.813 330
+3222: 421.859 -314.55 330
+3223: 421.821 -323.287 330
+3224: 421.783 -332.025 330
+3225: 421.745 -340.763 330
+3226: 421.706 -349.5 330
+3227: 421.668 -358.237 330
+3228: 421.63 -366.975 330
+3229: 421.591 -375.712 330
+3230: 421.553 -384.45 330
+3231: 421.515 -393.188 330
+3232: 421.477 -401.925 330
+3233: 421.438 -410.663 330
+3234: 421.4 -419.4 330
+3235: 421.362 -428.138 -1.87145e-005
+3236: 421.323 -436.875 -1.90964e-005
+3237: 421.285 -445.613 -1.94783e-005
+3238: 421.247 -454.35 -1.98603e-005
+3239: 421.209 -463.088 -2.02422e-005
+3240: 421.17 -471.825 -2.06241e-005
+3241: 421.132 -480.563 -2.10061e-005
+3242: 421.094 -489.3 -2.1388e-005
+3243: 421.055 -498.038 -2.17699e-005
+3244: 421.017 -506.775 -2.21518e-005
+3245: 420.979 -515.513 -2.25338e-005
+3246: 420.941 -524.25 -2.29157e-005
+3247: 420.902 -532.987 -2.32976e-005
+3248: 420.864 -541.725 -2.36796e-005
+3249: 420.826 -550.463 -2.40615e-005
+3250: 420.787 -559.2 -2.44434e-005
+3251: 431.875 0 0
+3252: 431.836 -8.7375 -3.81928e-007
+3253: 431.797 -17.475 -7.63857e-007
+3254: 431.758 -26.2125 -1.14578e-006
+3255: 431.719 -34.95 -1.52771e-006
+3256: 431.68 -43.6875 -1.90964e-006
+3257: 431.641 -52.425 -2.29157e-006
+3258: 431.602 -61.1625 -2.6735e-006
+3259: 431.563 -69.9 -3.05543e-006
+3260: 431.523 -78.6375 -3.43735e-006
+3261: 431.484 -87.375 -3.81928e-006
+3262: 431.445 -96.1125 -4.20121e-006
+3263: 431.406 -104.85 -4.58314e-006
+3264: 431.367 -113.588 -4.96507e-006
+3265: 431.328 -122.325 -5.347e-006
+3266: 431.289 -131.063 -5.72892e-006
+3267: 431.25 -139.8 -6.11085e-006
+3268: 431.211 -148.538 -6.49278e-006
+3269: 431.172 -157.275 -6.87471e-006
+3270: 431.133 -166.012 -7.25664e-006
+3271: 431.094 -174.75 -7.63856e-006
+3272: 431.055 -183.487 -8.02049e-006
+3273: 431.016 -192.225 -8.40242e-006
+3274: 430.977 -200.963 -8.78435e-006
+3275: 430.937 -209.7 -9.16628e-006
+3276: 430.898 -218.438 -9.54821e-006
+3277: 430.859 -227.175 -9.93014e-006
+3278: 430.82 -235.913 -1.03121e-005
+3279: 430.781 -244.65 -1.0694e-005
+3280: 430.742 -253.387 -1.10759e-005
+3281: 430.703 -262.125 -1.14578e-005
+3282: 430.664 -270.862 -1.18398e-005
+3283: 430.625 -279.6 330
+3284: 430.586 -288.337 330
+3285: 430.547 -297.075 330
+3286: 430.508 -305.813 330
+3287: 430.469 -314.55 330
+3288: 430.43 -323.287 330
+3289: 430.391 -332.025 330
+3290: 430.352 -340.763 330
+3291: 430.313 -349.5 330
+3292: 430.273 -358.237 330
+3293: 430.234 -366.975 330
+3294: 430.195 -375.712 330
+3295: 430.156 -384.45 330
+3296: 430.117 -393.188 330
+3297: 430.078 -401.925 330
+3298: 430.039 -410.663 330
+3299: 430 -419.4 -1.83326e-005
+3300: 429.961 -428.138 -1.87145e-005
+3301: 429.922 -436.875 -1.90964e-005
+3302: 429.883 -445.613 -1.94783e-005
+3303: 429.844 -454.35 -1.98603e-005
+3304: 429.805 -463.088 -2.02422e-005
+3305: 429.766 -471.825 -2.06241e-005
+3306: 429.727 -480.563 -2.10061e-005
+3307: 429.688 -489.3 -2.1388e-005
+3308: 429.648 -498.037 -2.17699e-005
+3309: 429.609 -506.775 -2.21518e-005
+3310: 429.57 -515.513 -2.25338e-005
+3311: 429.531 -524.25 -2.29157e-005
+3312: 429.492 -532.987 -2.32976e-005
+3313: 429.453 -541.725 -2.36796e-005
+3314: 429.414 -550.463 -2.40615e-005
+3315: 429.375 -559.2 -2.44434e-005
+3316: 440.512 0 0
+3317: 440.473 -8.7375 -3.81928e-007
+3318: 440.433 -17.475 -7.63857e-007
+3319: 440.393 -26.2125 -1.14578e-006
+3320: 440.353 -34.95 -1.52771e-006
+3321: 440.313 -43.6875 -1.90964e-006
+3322: 440.273 -52.425 -2.29157e-006
+3323: 440.234 -61.1625 -2.6735e-006
+3324: 440.194 -69.9 -3.05543e-006
+3325: 440.154 -78.6375 -3.43735e-006
+3326: 440.114 -87.375 -3.81928e-006
+3327: 440.074 -96.1125 -4.20121e-006
+3328: 440.034 -104.85 -4.58314e-006
+3329: 439.995 -113.588 -4.96507e-006
+3330: 439.955 -122.325 -5.347e-006
+3331: 439.915 -131.063 -5.72892e-006
+3332: 439.875 -139.8 -6.11085e-006
+3333: 439.835 -148.538 -6.49278e-006
+3334: 439.795 -157.275 -6.87471e-006
+3335: 439.755 -166.012 -7.25664e-006
+3336: 439.716 -174.75 -7.63856e-006
+3337: 439.676 -183.487 -8.02049e-006
+3338: 439.636 -192.225 -8.40242e-006
+3339: 439.596 -200.963 -8.78435e-006
+3340: 439.556 -209.7 -9.16628e-006
+3341: 439.516 -218.438 -9.54821e-006
+3342: 439.477 -227.175 -9.93014e-006
+3343: 439.437 -235.913 -1.03121e-005
+3344: 439.397 -244.65 -1.0694e-005
+3345: 439.357 -253.387 -1.10759e-005
+3346: 439.317 -262.125 -1.14578e-005
+3347: 439.277 -270.862 -1.18398e-005
+3348: 439.237 -279.6 -1.22217e-005
+3349: 439.198 -288.337 -1.26036e-005
+3350: 439.158 -297.075 -1.29856e-005
+3351: 439.118 -305.813 330
+3352: 439.078 -314.55 330
+3353: 439.038 -323.287 330
+3354: 438.998 -332.025 330
+3355: 438.959 -340.763 330
+3356: 438.919 -349.5 330
+3357: 438.879 -358.237 330
+3358: 438.839 -366.975 330
+3359: 438.799 -375.712 330
+3360: 438.759 -384.45 330
+3361: 438.72 -393.188 330
+3362: 438.68 -401.925 330
+3363: 438.64 -410.663 330
+3364: 438.6 -419.4 -1.83326e-005
+3365: 438.56 -428.138 -1.87145e-005
+3366: 438.52 -436.875 -1.90964e-005
+3367: 438.48 -445.613 -1.94783e-005
+3368: 438.441 -454.35 -1.98603e-005
+3369: 438.401 -463.088 -2.02422e-005
+3370: 438.361 -471.825 -2.06241e-005
+3371: 438.321 -480.563 -2.10061e-005
+3372: 438.281 -489.3 -2.1388e-005
+3373: 438.241 -498.038 -2.17699e-005
+3374: 438.202 -506.775 -2.21518e-005
+3375: 438.162 -515.513 -2.25338e-005
+3376: 438.122 -524.25 -2.29157e-005
+3377: 438.082 -532.987 -2.32976e-005
+3378: 438.042 -541.725 -2.36796e-005
+3379: 438.002 -550.463 -2.40615e-005
+3380: 437.962 -559.2 -2.44434e-005
+3381: 449.15 0 0
+3382: 449.109 -8.7375 -3.81928e-007
+3383: 449.069 -17.475 -7.63857e-007
+3384: 449.028 -26.2125 -1.14578e-006
+3385: 448.987 -34.95 -1.52771e-006
+3386: 448.947 -43.6875 -1.90964e-006
+3387: 448.906 -52.425 -2.29157e-006
+3388: 448.866 -61.1625 -2.6735e-006
+3389: 448.825 -69.9 -3.05543e-006
+3390: 448.784 -78.6375 -3.43735e-006
+3391: 448.744 -87.375 -3.81928e-006
+3392: 448.703 -96.1125 -4.20121e-006
+3393: 448.663 -104.85 -4.58314e-006
+3394: 448.622 -113.588 -4.96507e-006
+3395: 448.581 -122.325 -5.347e-006
+3396: 448.541 -131.063 -5.72892e-006
+3397: 448.5 -139.8 -6.11085e-006
+3398: 448.459 -148.538 -6.49278e-006
+3399: 448.419 -157.275 -6.87471e-006
+3400: 448.378 -166.012 -7.25664e-006
+3401: 448.337 -174.75 -7.63856e-006
+3402: 448.297 -183.487 -8.02049e-006
+3403: 448.256 -192.225 -8.40242e-006
+3404: 448.216 -200.963 -8.78435e-006
+3405: 448.175 -209.7 -9.16628e-006
+3406: 448.134 -218.438 -9.54821e-006
+3407: 448.094 -227.175 -9.93014e-006
+3408: 448.053 -235.913 -1.03121e-005
+3409: 448.012 -244.65 -1.0694e-005
+3410: 447.972 -253.387 -1.10759e-005
+3411: 447.931 -262.125 -1.14578e-005
+3412: 447.891 -270.862 -1.18398e-005
+3413: 447.85 -279.6 -1.22217e-005
+3414: 447.809 -288.337 -1.26036e-005
+3415: 447.769 -297.075 -1.29856e-005
+3416: 447.728 -305.813 -1.33675e-005
+3417: 447.688 -314.55 -1.37494e-005
+3418: 447.647 -323.287 -1.41313e-005
+3419: 447.606 -332.025 330
+3420: 447.566 -340.763 330
+3421: 447.525 -349.5 330
+3422: 447.484 -358.237 330
+3423: 447.444 -366.975 330
+3424: 447.403 -375.712 330
+3425: 447.362 -384.45 330
+3426: 447.322 -393.188 330
+3427: 447.281 -401.925 330
+3428: 447.241 -410.663 330
+3429: 447.2 -419.4 -1.83326e-005
+3430: 447.159 -428.138 -1.87145e-005
+3431: 447.119 -436.875 -1.90964e-005
+3432: 447.078 -445.613 -1.94783e-005
+3433: 447.038 -454.35 -1.98603e-005
+3434: 446.997 -463.088 -2.02422e-005
+3435: 446.956 -471.825 -2.06241e-005
+3436: 446.916 -480.563 -2.10061e-005
+3437: 446.875 -489.3 -2.1388e-005
+3438: 446.834 -498.037 -2.17699e-005
+3439: 446.794 -506.775 -2.21518e-005
+3440: 446.753 -515.513 -2.25338e-005
+3441: 446.712 -524.25 -2.29157e-005
+3442: 446.672 -532.987 -2.32976e-005
+3443: 446.631 -541.725 -2.36796e-005
+3444: 446.591 -550.463 -2.40615e-005
+3445: 446.55 -559.2 -2.44434e-005
+3446: 457.787 0 0
+3447: 457.746 -8.7375 -3.81928e-007
+3448: 457.705 -17.475 -7.63857e-007
+3449: 457.663 -26.2125 -1.14578e-006
+3450: 457.622 -34.95 -1.52771e-006
+3451: 457.58 -43.6875 -1.90964e-006
+3452: 457.539 -52.425 -2.29157e-006
+3453: 457.498 -61.1625 -2.6735e-006
+3454: 457.456 -69.9 -3.05543e-006
+3455: 457.415 -78.6375 -3.43735e-006
+3456: 457.373 -87.375 -3.81928e-006
+3457: 457.332 -96.1125 -4.20121e-006
+3458: 457.291 -104.85 -4.58314e-006
+3459: 457.249 -113.588 -4.96507e-006
+3460: 457.208 -122.325 -5.347e-006
+3461: 457.166 -131.063 -5.72892e-006
+3462: 457.125 -139.8 -6.11085e-006
+3463: 457.084 -148.538 -6.49278e-006
+3464: 457.042 -157.275 -6.87471e-006
+3465: 457.001 -166.012 -7.25664e-006
+3466: 456.959 -174.75 -7.63856e-006
+3467: 456.918 -183.487 -8.02049e-006
+3468: 456.877 -192.225 -8.40242e-006
+3469: 456.835 -200.963 -8.78435e-006
+3470: 456.794 -209.7 -9.16628e-006
+3471: 456.752 -218.438 -9.54821e-006
+3472: 456.711 -227.175 -9.93014e-006
+3473: 456.669 -235.913 -1.03121e-005
+3474: 456.628 -244.65 -1.0694e-005
+3475: 456.587 -253.387 -1.10759e-005
+3476: 456.545 -262.125 -1.14578e-005
+3477: 456.504 -270.862 -1.18398e-005
+3478: 456.462 -279.6 -1.22217e-005
+3479: 456.421 -288.337 -1.26036e-005
+3480: 456.38 -297.075 -1.29856e-005
+3481: 456.338 -305.813 -1.33675e-005
+3482: 456.297 -314.55 -1.37494e-005
+3483: 456.255 -323.287 -1.41313e-005
+3484: 456.214 -332.025 -1.45133e-005
+3485: 456.173 -340.763 -1.48952e-005
+3486: 456.131 -349.5 -1.52771e-005
+3487: 456.09 -358.237 330
+3488: 456.048 -366.975 330
+3489: 456.007 -375.712 330
+3490: 455.966 -384.45 330
+3491: 455.924 -393.188 330
+3492: 455.883 -401.925 330
+3493: 455.841 -410.663 330
+3494: 455.8 -419.4 -1.83326e-005
+3495: 455.759 -428.138 -1.87145e-005
+3496: 455.717 -436.875 -1.90964e-005
+3497: 455.676 -445.613 -1.94783e-005
+3498: 455.634 -454.35 -1.98603e-005
+3499: 455.593 -463.088 -2.02422e-005
+3500: 455.552 -471.825 -2.06241e-005
+3501: 455.51 -480.563 -2.10061e-005
+3502: 455.469 -489.3 -2.1388e-005
+3503: 455.427 -498.038 -2.17699e-005
+3504: 455.386 -506.775 -2.21518e-005
+3505: 455.344 -515.513 -2.25338e-005
+3506: 455.303 -524.25 -2.29157e-005
+3507: 455.262 -532.987 -2.32976e-005
+3508: 455.22 -541.725 -2.36796e-005
+3509: 455.179 -550.463 -2.40615e-005
+3510: 455.137 -559.2 -2.44434e-005
+3511: 466.425 0 0
+3512: 466.383 -8.7375 -3.81928e-007
+3513: 466.341 -17.475 -7.63857e-007
+3514: 466.298 -26.2125 -1.14578e-006
+3515: 466.256 -34.95 -1.52771e-006
+3516: 466.214 -43.6875 -1.90964e-006
+3517: 466.172 -52.425 -2.29157e-006
+3518: 466.13 -61.1625 -2.6735e-006
+3519: 466.087 -69.9 -3.05543e-006
+3520: 466.045 -78.6375 -3.43735e-006
+3521: 466.003 -87.375 -3.81928e-006
+3522: 465.961 -96.1125 -4.20121e-006
+3523: 465.919 -104.85 -4.58314e-006
+3524: 465.877 -113.588 -4.96507e-006
+3525: 465.834 -122.325 -5.347e-006
+3526: 465.792 -131.063 -5.72892e-006
+3527: 465.75 -139.8 -6.11085e-006
+3528: 465.708 -148.538 -6.49278e-006
+3529: 465.666 -157.275 -6.87471e-006
+3530: 465.623 -166.012 -7.25664e-006
+3531: 465.581 -174.75 -7.63856e-006
+3532: 465.539 -183.487 -8.02049e-006
+3533: 465.497 -192.225 -8.40242e-006
+3534: 465.455 -200.963 -8.78435e-006
+3535: 465.412 -209.7 -9.16628e-006
+3536: 465.37 -218.438 -9.54821e-006
+3537: 465.328 -227.175 -9.93014e-006
+3538: 465.286 -235.913 -1.03121e-005
+3539: 465.244 -244.65 -1.0694e-005
+3540: 465.202 -253.388 -1.10759e-005
+3541: 465.159 -262.125 -1.14578e-005
+3542: 465.117 -270.862 -1.18398e-005
+3543: 465.075 -279.6 -1.22217e-005
+3544: 465.033 -288.338 -1.26036e-005
+3545: 464.991 -297.075 -1.29856e-005
+3546: 464.948 -305.813 -1.33675e-005
+3547: 464.906 -314.55 -1.37494e-005
+3548: 464.864 -323.287 -1.41313e-005
+3549: 464.822 -332.025 -1.45133e-005
+3550: 464.78 -340.763 -1.48952e-005
+3551: 464.737 -349.5 -1.52771e-005
+3552: 464.695 -358.237 -1.56591e-005
+3553: 464.653 -366.975 -1.6041e-005
+3554: 464.611 -375.712 -1.64229e-005
+3555: 464.569 -384.45 330
+3556: 464.527 -393.188 330
+3557: 464.484 -401.925 330
+3558: 464.442 -410.663 -1.79506e-005
+3559: 464.4 -419.4 -1.83326e-005
+3560: 464.358 -428.138 -1.87145e-005
+3561: 464.316 -436.875 -1.90964e-005
+3562: 464.273 -445.613 -1.94783e-005
+3563: 464.231 -454.35 -1.98603e-005
+3564: 464.189 -463.088 -2.02422e-005
+3565: 464.147 -471.825 -2.06241e-005
+3566: 464.105 -480.563 -2.10061e-005
+3567: 464.063 -489.3 -2.1388e-005
+3568: 464.02 -498.037 -2.17699e-005
+3569: 463.978 -506.775 -2.21518e-005
+3570: 463.936 -515.513 -2.25338e-005
+3571: 463.894 -524.25 -2.29157e-005
+3572: 463.852 -532.987 -2.32976e-005
+3573: 463.809 -541.725 -2.36796e-005
+3574: 463.767 -550.463 -2.40615e-005
+3575: 463.725 -559.2 -2.44434e-005
+3576: 475.063 0 0
+3577: 475.02 -8.7375 -3.81928e-007
+3578: 474.977 -17.475 -7.63857e-007
+3579: 474.934 -26.2125 -1.14578e-006
+3580: 474.891 -34.95 -1.52771e-006
+3581: 474.848 -43.6875 -1.90964e-006
+3582: 474.805 -52.425 -2.29157e-006
+3583: 474.762 -61.1625 -2.6735e-006
+3584: 474.719 -69.9 -3.05543e-006
+3585: 474.676 -78.6375 -3.43735e-006
+3586: 474.633 -87.375 -3.81928e-006
+3587: 474.59 -96.1125 -4.20121e-006
+3588: 474.547 -104.85 -4.58314e-006
+3589: 474.504 -113.588 -4.96507e-006
+3590: 474.461 -122.325 -5.347e-006
+3591: 474.418 -131.063 -5.72892e-006
+3592: 474.375 -139.8 -6.11085e-006
+3593: 474.332 -148.538 -6.49278e-006
+3594: 474.289 -157.275 -6.87471e-006
+3595: 474.246 -166.012 -7.25664e-006
+3596: 474.203 -174.75 -7.63856e-006
+3597: 474.16 -183.487 -8.02049e-006
+3598: 474.117 -192.225 -8.40242e-006
+3599: 474.074 -200.963 -8.78435e-006
+3600: 474.031 -209.7 -9.16628e-006
+3601: 473.988 -218.438 -9.54821e-006
+3602: 473.945 -227.175 -9.93014e-006
+3603: 473.902 -235.913 -1.03121e-005
+3604: 473.859 -244.65 -1.0694e-005
+3605: 473.816 -253.388 -1.10759e-005
+3606: 473.773 -262.125 -1.14578e-005
+3607: 473.73 -270.862 -1.18398e-005
+3608: 473.687 -279.6 -1.22217e-005
+3609: 473.645 -288.338 -1.26036e-005
+3610: 473.602 -297.075 -1.29856e-005
+3611: 473.559 -305.813 -1.33675e-005
+3612: 473.516 -314.55 -1.37494e-005
+3613: 473.473 -323.288 -1.41313e-005
+3614: 473.43 -332.025 -1.45133e-005
+3615: 473.387 -340.763 -1.48952e-005
+3616: 473.344 -349.5 -1.52771e-005
+3617: 473.301 -358.237 -1.56591e-005
+3618: 473.258 -366.975 -1.6041e-005
+3619: 473.215 -375.712 -1.64229e-005
+3620: 473.172 -384.45 -1.68048e-005
+3621: 473.129 -393.188 -1.71868e-005
+3622: 473.086 -401.925 -1.75687e-005
+3623: 473.043 -410.663 -1.79506e-005
+3624: 473 -419.4 -1.83326e-005
+3625: 472.957 -428.138 -1.87145e-005
+3626: 472.914 -436.875 -1.90964e-005
+3627: 472.871 -445.613 -1.94783e-005
+3628: 472.828 -454.35 -1.98603e-005
+3629: 472.785 -463.088 -2.02422e-005
+3630: 472.742 -471.825 -2.06241e-005
+3631: 472.699 -480.563 -2.10061e-005
+3632: 472.656 -489.3 -2.1388e-005
+3633: 472.613 -498.038 -2.17699e-005
+3634: 472.57 -506.775 -2.21518e-005
+3635: 472.527 -515.513 -2.25338e-005
+3636: 472.484 -524.25 -2.29157e-005
+3637: 472.441 -532.987 -2.32976e-005
+3638: 472.398 -541.725 -2.36796e-005
+3639: 472.355 -550.463 -2.40615e-005
+3640: 472.313 -559.2 -2.44434e-005
+3641: 483.7 0 0
+3642: 483.656 -8.7375 -3.81928e-007
+3643: 483.612 -17.475 -7.63857e-007
+3644: 483.569 -26.2125 -1.14578e-006
+3645: 483.525 -34.95 -1.52771e-006
+3646: 483.481 -43.6875 -1.90964e-006
+3647: 483.438 -52.425 -2.29157e-006
+3648: 483.394 -61.1625 -2.6735e-006
+3649: 483.35 -69.9 -3.05543e-006
+3650: 483.306 -78.6375 -3.43735e-006
+3651: 483.262 -87.375 -3.81928e-006
+3652: 483.219 -96.1125 -4.20121e-006
+3653: 483.175 -104.85 -4.58314e-006
+3654: 483.131 -113.588 -4.96507e-006
+3655: 483.087 -122.325 -5.347e-006
+3656: 483.044 -131.063 -5.72892e-006
+3657: 483 -139.8 -6.11085e-006
+3658: 482.956 -148.538 -6.49278e-006
+3659: 482.912 -157.275 -6.87471e-006
+3660: 482.869 -166.012 -7.25664e-006
+3661: 482.825 -174.75 -7.63856e-006
+3662: 482.781 -183.487 -8.02049e-006
+3663: 482.737 -192.225 -8.40242e-006
+3664: 482.694 -200.963 -8.78435e-006
+3665: 482.65 -209.7 -9.16628e-006
+3666: 482.606 -218.438 -9.54821e-006
+3667: 482.563 -227.175 -9.93014e-006
+3668: 482.519 -235.913 -1.03121e-005
+3669: 482.475 -244.65 -1.0694e-005
+3670: 482.431 -253.388 -1.10759e-005
+3671: 482.387 -262.125 -1.14578e-005
+3672: 482.344 -270.862 -1.18398e-005
+3673: 482.3 -279.6 -1.22217e-005
+3674: 482.256 -288.338 -1.26036e-005
+3675: 482.212 -297.075 -1.29856e-005
+3676: 482.169 -305.813 -1.33675e-005
+3677: 482.125 -314.55 -1.37494e-005
+3678: 482.081 -323.288 -1.41313e-005
+3679: 482.037 -332.025 -1.45133e-005
+3680: 481.994 -340.763 -1.48952e-005
+3681: 481.95 -349.5 -1.52771e-005
+3682: 481.906 -358.237 -1.56591e-005
+3683: 481.862 -366.975 -1.6041e-005
+3684: 481.819 -375.712 -1.64229e-005
+3685: 481.775 -384.45 -1.68048e-005
+3686: 481.731 -393.188 -1.71868e-005
+3687: 481.688 -401.925 -1.75687e-005
+3688: 481.644 -410.663 -1.79506e-005
+3689: 481.6 -419.4 -1.83326e-005
+3690: 481.556 -428.138 -1.87145e-005
+3691: 481.512 -436.875 -1.90964e-005
+3692: 481.469 -445.613 -1.94783e-005
+3693: 481.425 -454.35 -1.98603e-005
+3694: 481.381 -463.088 -2.02422e-005
+3695: 481.338 -471.825 -2.06241e-005
+3696: 481.294 -480.563 -2.10061e-005
+3697: 481.25 -489.3 -2.1388e-005
+3698: 481.206 -498.037 -2.17699e-005
+3699: 481.162 -506.775 -2.21518e-005
+3700: 481.119 -515.513 -2.25338e-005
+3701: 481.075 -524.25 -2.29157e-005
+3702: 481.031 -532.987 -2.32976e-005
+3703: 480.987 -541.725 -2.36796e-005
+3704: 480.944 -550.463 -2.40615e-005
+3705: 480.9 -559.2 -2.44434e-005
+3706: 492.337 0 0
+3707: 492.293 -8.7375 -3.81928e-007
+3708: 492.248 -17.475 -7.63857e-007
+3709: 492.204 -26.2125 -1.14578e-006
+3710: 492.159 -34.95 -1.52771e-006
+3711: 492.115 -43.6875 -1.90964e-006
+3712: 492.07 -52.425 -2.29157e-006
+3713: 492.026 -61.1625 -2.6735e-006
+3714: 491.981 -69.9 -3.05543e-006
+3715: 491.937 -78.6375 -3.43735e-006
+3716: 491.892 -87.375 -3.81928e-006
+3717: 491.848 -96.1125 -4.20121e-006
+3718: 491.803 -104.85 -4.58314e-006
+3719: 491.759 -113.588 -4.96507e-006
+3720: 491.714 -122.325 -5.347e-006
+3721: 491.67 -131.063 -5.72892e-006
+3722: 491.625 -139.8 -6.11085e-006
+3723: 491.58 -148.538 -6.49278e-006
+3724: 491.536 -157.275 -6.87471e-006
+3725: 491.491 -166.012 -7.25664e-006
+3726: 491.447 -174.75 -7.63856e-006
+3727: 491.402 -183.487 -8.02049e-006
+3728: 491.358 -192.225 -8.40242e-006
+3729: 491.313 -200.963 -8.78435e-006
+3730: 491.269 -209.7 -9.16628e-006
+3731: 491.224 -218.438 -9.54821e-006
+3732: 491.18 -227.175 -9.93014e-006
+3733: 491.135 -235.913 -1.03121e-005
+3734: 491.091 -244.65 -1.0694e-005
+3735: 491.046 -253.388 -1.10759e-005
+3736: 491.002 -262.125 -1.14578e-005
+3737: 490.957 -270.863 -1.18398e-005
+3738: 490.912 -279.6 -1.22217e-005
+3739: 490.868 -288.338 -1.26036e-005
+3740: 490.823 -297.075 -1.29856e-005
+3741: 490.779 -305.813 -1.33675e-005
+3742: 490.734 -314.55 -1.37494e-005
+3743: 490.69 -323.288 -1.41313e-005
+3744: 490.645 -332.025 -1.45133e-005
+3745: 490.601 -340.763 -1.48952e-005
+3746: 490.556 -349.5 -1.52771e-005
+3747: 490.512 -358.237 -1.56591e-005
+3748: 490.467 -366.975 -1.6041e-005
+3749: 490.423 -375.712 -1.64229e-005
+3750: 490.378 -384.45 -1.68048e-005
+3751: 490.334 -393.188 -1.71868e-005
+3752: 490.289 -401.925 -1.75687e-005
+3753: 490.245 -410.663 -1.79506e-005
+3754: 490.2 -419.4 -1.83326e-005
+3755: 490.155 -428.138 -1.87145e-005
+3756: 490.111 -436.875 -1.90964e-005
+3757: 490.066 -445.613 -1.94783e-005
+3758: 490.022 -454.35 -1.98603e-005
+3759: 489.977 -463.088 -2.02422e-005
+3760: 489.933 -471.825 -2.06241e-005
+3761: 489.888 -480.563 -2.10061e-005
+3762: 489.844 -489.3 -2.1388e-005
+3763: 489.799 -498.038 -2.17699e-005
+3764: 489.755 -506.775 -2.21518e-005
+3765: 489.71 -515.513 -2.25338e-005
+3766: 489.666 -524.25 -2.29157e-005
+3767: 489.621 -532.987 -2.32976e-005
+3768: 489.577 -541.725 -2.36796e-005
+3769: 489.532 -550.463 -2.40615e-005
+3770: 489.487 -559.2 -2.44434e-005
+3771: 500.975 0 0
+3772: 500.93 -8.7375 -3.81928e-007
+3773: 500.884 -17.475 -7.63857e-007
+3774: 500.839 -26.2125 -1.14578e-006
+3775: 500.794 -34.95 -1.52771e-006
+3776: 500.748 -43.6875 -1.90964e-006
+3777: 500.703 -52.425 -2.29157e-006
+3778: 500.658 -61.1625 -2.6735e-006
+3779: 500.612 -69.9 -3.05543e-006
+3780: 500.567 -78.6375 -3.43735e-006
+3781: 500.522 -87.375 -3.81928e-006
+3782: 500.477 -96.1125 -4.20121e-006
+3783: 500.431 -104.85 -4.58314e-006
+3784: 500.386 -113.588 -4.96507e-006
+3785: 500.341 -122.325 -5.347e-006
+3786: 500.295 -131.063 -5.72892e-006
+3787: 500.25 -139.8 -6.11085e-006
+3788: 500.205 -148.538 -6.49278e-006
+3789: 500.159 -157.275 -6.87471e-006
+3790: 500.114 -166.012 -7.25664e-006
+3791: 500.069 -174.75 -7.63856e-006
+3792: 500.023 -183.487 -8.02049e-006
+3793: 499.978 -192.225 -8.40242e-006
+3794: 499.933 -200.963 -8.78435e-006
+3795: 499.887 -209.7 -9.16628e-006
+3796: 499.842 -218.438 -9.54821e-006
+3797: 499.797 -227.175 -9.93014e-006
+3798: 499.752 -235.913 -1.03121e-005
+3799: 499.706 -244.65 -1.0694e-005
+3800: 499.661 -253.388 -1.10759e-005
+3801: 499.616 -262.125 -1.14578e-005
+3802: 499.57 -270.863 -1.18398e-005
+3803: 499.525 -279.6 -1.22217e-005
+3804: 499.48 -288.338 -1.26036e-005
+3805: 499.434 -297.075 -1.29856e-005
+3806: 499.389 -305.813 -1.33675e-005
+3807: 499.344 -314.55 -1.37494e-005
+3808: 499.298 -323.288 -1.41313e-005
+3809: 499.253 -332.025 -1.45133e-005
+3810: 499.208 -340.763 -1.48952e-005
+3811: 499.162 -349.5 -1.52771e-005
+3812: 499.117 -358.237 -1.56591e-005
+3813: 499.072 -366.975 -1.6041e-005
+3814: 499.027 -375.712 -1.64229e-005
+3815: 498.981 -384.45 -1.68048e-005
+3816: 498.936 -393.188 -1.71868e-005
+3817: 498.891 -401.925 -1.75687e-005
+3818: 498.845 -410.663 -1.79506e-005
+3819: 498.8 -419.4 -1.83326e-005
+3820: 498.755 -428.138 -1.87145e-005
+3821: 498.709 -436.875 -1.90964e-005
+3822: 498.664 -445.613 -1.94783e-005
+3823: 498.619 -454.35 -1.98603e-005
+3824: 498.573 -463.088 -2.02422e-005
+3825: 498.528 -471.825 -2.06241e-005
+3826: 498.483 -480.563 -2.10061e-005
+3827: 498.438 -489.3 -2.1388e-005
+3828: 498.392 -498.037 -2.17699e-005
+3829: 498.347 -506.775 -2.21518e-005
+3830: 498.302 -515.513 -2.25338e-005
+3831: 498.256 -524.25 -2.29157e-005
+3832: 498.211 -532.987 -2.32976e-005
+3833: 498.166 -541.725 -2.36796e-005
+3834: 498.12 -550.463 -2.40615e-005
+3835: 498.075 -559.2 -2.44434e-005
+3836: 509.612 0 0
+3837: 509.566 -8.7375 -3.81928e-007
+3838: 509.52 -17.475 -7.63857e-007
+3839: 509.474 -26.2125 -1.14578e-006
+3840: 509.428 -34.95 -1.52771e-006
+3841: 509.382 -43.6875 -1.90964e-006
+3842: 509.336 -52.425 -2.29157e-006
+3843: 509.29 -61.1625 -2.6735e-006
+3844: 509.244 -69.9 -3.05543e-006
+3845: 509.198 -78.6375 -3.43735e-006
+3846: 509.152 -87.375 -3.81928e-006
+3847: 509.105 -96.1125 -4.20121e-006
+3848: 509.059 -104.85 -4.58314e-006
+3849: 509.013 -113.588 -4.96507e-006
+3850: 508.967 -122.325 -5.347e-006
+3851: 508.921 -131.063 -5.72892e-006
+3852: 508.875 -139.8 -6.11085e-006
+3853: 508.829 -148.538 -6.49278e-006
+3854: 508.783 -157.275 -6.87471e-006
+3855: 508.737 -166.012 -7.25664e-006
+3856: 508.691 -174.75 -7.63856e-006
+3857: 508.645 -183.487 -8.02049e-006
+3858: 508.598 -192.225 -8.40242e-006
+3859: 508.552 -200.963 -8.78435e-006
+3860: 508.506 -209.7 -9.16628e-006
+3861: 508.46 -218.438 -9.54821e-006
+3862: 508.414 -227.175 -9.93014e-006
+3863: 508.368 -235.913 -1.03121e-005
+3864: 508.322 -244.65 -1.0694e-005
+3865: 508.276 -253.388 -1.10759e-005
+3866: 508.23 -262.125 -1.14578e-005
+3867: 508.184 -270.863 -1.18398e-005
+3868: 508.137 -279.6 -1.22217e-005
+3869: 508.091 -288.338 -1.26036e-005
+3870: 508.045 -297.075 -1.29856e-005
+3871: 507.999 -305.813 -1.33675e-005
+3872: 507.953 -314.55 -1.37494e-005
+3873: 507.907 -323.288 -1.41313e-005
+3874: 507.861 -332.025 -1.45133e-005
+3875: 507.815 -340.763 -1.48952e-005
+3876: 507.769 -349.5 -1.52771e-005
+3877: 507.723 -358.237 -1.56591e-005
+3878: 507.677 -366.975 -1.6041e-005
+3879: 507.63 -375.712 -1.64229e-005
+3880: 507.584 -384.45 -1.68048e-005
+3881: 507.538 -393.188 -1.71868e-005
+3882: 507.492 -401.925 -1.75687e-005
+3883: 507.446 -410.663 -1.79506e-005
+3884: 507.4 -419.4 -1.83326e-005
+3885: 507.354 -428.138 -1.87145e-005
+3886: 507.308 -436.875 -1.90964e-005
+3887: 507.262 -445.613 -1.94783e-005
+3888: 507.216 -454.35 -1.98603e-005
+3889: 507.17 -463.088 -2.02422e-005
+3890: 507.123 -471.825 -2.06241e-005
+3891: 507.077 -480.563 -2.10061e-005
+3892: 507.031 -489.3 -2.1388e-005
+3893: 506.985 -498.038 -2.17699e-005
+3894: 506.939 -506.775 -2.21518e-005
+3895: 506.893 -515.513 -2.25338e-005
+3896: 506.847 -524.25 -2.29157e-005
+3897: 506.801 -532.987 -2.32976e-005
+3898: 506.755 -541.725 -2.36796e-005
+3899: 506.709 -550.463 -2.40615e-005
+3900: 506.663 -559.2 -2.44434e-005
+3901: 518.25 0 0
+3902: 518.203 -8.7375 -3.81928e-007
+3903: 518.156 -17.475 -7.63857e-007
+3904: 518.109 -26.2125 -1.14578e-006
+3905: 518.063 -34.95 -1.52771e-006
+3906: 518.016 -43.6875 -1.90964e-006
+3907: 517.969 -52.425 -2.29157e-006
+3908: 517.922 -61.1625 -2.6735e-006
+3909: 517.875 -69.9 -3.05543e-006
+3910: 517.828 -78.6375 -3.43735e-006
+3911: 517.781 -87.375 -3.81928e-006
+3912: 517.734 -96.1125 -4.20121e-006
+3913: 517.688 -104.85 -4.58314e-006
+3914: 517.641 -113.588 -4.96507e-006
+3915: 517.594 -122.325 -5.347e-006
+3916: 517.547 -131.063 -5.72892e-006
+3917: 517.5 -139.8 -6.11085e-006
+3918: 517.453 -148.538 -6.49278e-006
+3919: 517.406 -157.275 -6.87471e-006
+3920: 517.359 -166.013 -7.25664e-006
+3921: 517.313 -174.75 -7.63856e-006
+3922: 517.266 -183.487 -8.02049e-006
+3923: 517.219 -192.225 -8.40242e-006
+3924: 517.172 -200.963 -8.78435e-006
+3925: 517.125 -209.7 -9.16628e-006
+3926: 517.078 -218.438 -9.54821e-006
+3927: 517.031 -227.175 -9.93014e-006
+3928: 516.984 -235.913 -1.03121e-005
+3929: 516.938 -244.65 -1.0694e-005
+3930: 516.891 -253.388 -1.10759e-005
+3931: 516.844 -262.125 -1.14578e-005
+3932: 516.797 -270.863 -1.18398e-005
+3933: 516.75 -279.6 -1.22217e-005
+3934: 516.703 -288.338 -1.26036e-005
+3935: 516.656 -297.075 -1.29856e-005
+3936: 516.609 -305.813 -1.33675e-005
+3937: 516.563 -314.55 -1.37494e-005
+3938: 516.516 -323.288 -1.41313e-005
+3939: 516.469 -332.025 -1.45133e-005
+3940: 516.422 -340.763 -1.48952e-005
+3941: 516.375 -349.5 -1.52771e-005
+3942: 516.328 -358.237 -1.56591e-005
+3943: 516.281 -366.975 -1.6041e-005
+3944: 516.234 -375.712 -1.64229e-005
+3945: 516.188 -384.45 -1.68048e-005
+3946: 516.141 -393.188 -1.71868e-005
+3947: 516.094 -401.925 -1.75687e-005
+3948: 516.047 -410.663 -1.79506e-005
+3949: 516 -419.4 -1.83326e-005
+3950: 515.953 -428.138 -1.87145e-005
+3951: 515.906 -436.875 -1.90964e-005
+3952: 515.859 -445.613 -1.94783e-005
+3953: 515.813 -454.35 -1.98603e-005
+3954: 515.766 -463.088 -2.02422e-005
+3955: 515.719 -471.825 -2.06241e-005
+3956: 515.672 -480.563 -2.10061e-005
+3957: 515.625 -489.3 -2.1388e-005
+3958: 515.578 -498.038 -2.17699e-005
+3959: 515.531 -506.775 -2.21518e-005
+3960: 515.484 -515.513 -2.25338e-005
+3961: 515.438 -524.25 -2.29157e-005
+3962: 515.391 -532.987 -2.32976e-005
+3963: 515.344 -541.725 -2.36796e-005
+3964: 515.297 -550.463 -2.40615e-005
+3965: 515.25 -559.2 -2.44434e-005
+3966: 526.888 0 0
+3967: 526.84 -8.7375 -3.81928e-007
+3968: 526.792 -17.475 -7.63857e-007
+3969: 526.745 -26.2125 -1.14578e-006
+3970: 526.697 -34.95 -1.52771e-006
+3971: 526.649 -43.6875 -1.90964e-006
+3972: 526.602 -52.425 -2.29157e-006
+3973: 526.554 -61.1625 -2.6735e-006
+3974: 526.506 -69.9 -3.05543e-006
+3975: 526.459 -78.6375 -3.43735e-006
+3976: 526.411 -87.375 -3.81928e-006
+3977: 526.363 -96.1125 -4.20121e-006
+3978: 526.316 -104.85 -4.58314e-006
+3979: 526.268 -113.588 -4.96507e-006
+3980: 526.22 -122.325 -5.347e-006
+3981: 526.173 -131.063 -5.72892e-006
+3982: 526.125 -139.8 -6.11085e-006
+3983: 526.077 -148.538 -6.49278e-006
+3984: 526.03 -157.275 -6.87471e-006
+3985: 525.982 -166.013 -7.25664e-006
+3986: 525.934 -174.75 -7.63856e-006
+3987: 525.887 -183.487 -8.02049e-006
+3988: 525.839 -192.225 -8.40242e-006
+3989: 525.791 -200.963 -8.78435e-006
+3990: 525.744 -209.7 -9.16628e-006
+3991: 525.696 -218.438 -9.54821e-006
+3992: 525.648 -227.175 -9.93014e-006
+3993: 525.601 -235.913 -1.03121e-005
+3994: 525.553 -244.65 -1.0694e-005
+3995: 525.505 -253.388 -1.10759e-005
+3996: 525.458 -262.125 -1.14578e-005
+3997: 525.41 -270.863 -1.18398e-005
+3998: 525.362 -279.6 -1.22217e-005
+3999: 525.315 -288.338 -1.26036e-005
+4000: 525.267 -297.075 -1.29856e-005
+4001: 525.22 -305.813 -1.33675e-005
+4002: 525.172 -314.55 -1.37494e-005
+4003: 525.124 -323.288 -1.41313e-005
+4004: 525.077 -332.025 -1.45133e-005
+4005: 525.029 -340.763 -1.48952e-005
+4006: 524.981 -349.5 -1.52771e-005
+4007: 524.934 -358.237 -1.56591e-005
+4008: 524.886 -366.975 -1.6041e-005
+4009: 524.838 -375.712 -1.64229e-005
+4010: 524.791 -384.45 -1.68048e-005
+4011: 524.743 -393.188 -1.71868e-005
+4012: 524.695 -401.925 -1.75687e-005
+4013: 524.648 -410.663 -1.79506e-005
+4014: 524.6 -419.4 -1.83326e-005
+4015: 524.552 -428.138 -1.87145e-005
+4016: 524.505 -436.875 -1.90964e-005
+4017: 524.457 -445.613 -1.94783e-005
+4018: 524.409 -454.35 -1.98603e-005
+4019: 524.362 -463.088 -2.02422e-005
+4020: 524.314 -471.825 -2.06241e-005
+4021: 524.266 -480.563 -2.10061e-005
+4022: 524.219 -489.3 -2.1388e-005
+4023: 524.171 -498.038 -2.17699e-005
+4024: 524.123 -506.775 -2.21518e-005
+4025: 524.076 -515.513 -2.25338e-005
+4026: 524.028 -524.25 -2.29157e-005
+4027: 523.98 -532.987 -2.32976e-005
+4028: 523.933 -541.725 -2.36796e-005
+4029: 523.885 -550.463 -2.40615e-005
+4030: 523.838 -559.2 -2.44434e-005
+4031: 535.525 0 0
+4032: 535.477 -8.7375 -3.81928e-007
+4033: 535.428 -17.475 -7.63857e-007
+4034: 535.38 -26.2125 -1.14578e-006
+4035: 535.331 -34.95 -1.52771e-006
+4036: 535.283 -43.6875 -1.90964e-006
+4037: 535.234 -52.425 -2.29157e-006
+4038: 535.186 -61.1625 -2.6735e-006
+4039: 535.138 -69.9 -3.05543e-006
+4040: 535.089 -78.6375 -3.43735e-006
+4041: 535.041 -87.375 -3.81928e-006
+4042: 534.992 -96.1125 -4.20121e-006
+4043: 534.944 -104.85 -4.58314e-006
+4044: 534.895 -113.588 -4.96507e-006
+4045: 534.847 -122.325 -5.347e-006
+4046: 534.798 -131.063 -5.72892e-006
+4047: 534.75 -139.8 -6.11085e-006
+4048: 534.702 -148.538 -6.49278e-006
+4049: 534.653 -157.275 -6.87471e-006
+4050: 534.605 -166.013 -7.25664e-006
+4051: 534.556 -174.75 -7.63856e-006
+4052: 534.508 -183.487 -8.02049e-006
+4053: 534.459 -192.225 -8.40242e-006
+4054: 534.411 -200.963 -8.78435e-006
+4055: 534.362 -209.7 -9.16628e-006
+4056: 534.314 -218.438 -9.54821e-006
+4057: 534.266 -227.175 -9.93014e-006
+4058: 534.217 -235.913 -1.03121e-005
+4059: 534.169 -244.65 -1.0694e-005
+4060: 534.12 -253.388 -1.10759e-005
+4061: 534.072 -262.125 -1.14578e-005
+4062: 534.023 -270.863 -1.18398e-005
+4063: 533.975 -279.6 -1.22217e-005
+4064: 533.927 -288.338 -1.26036e-005
+4065: 533.878 -297.075 -1.29856e-005
+4066: 533.83 -305.813 -1.33675e-005
+4067: 533.781 -314.55 -1.37494e-005
+4068: 533.733 -323.288 -1.41313e-005
+4069: 533.684 -332.025 -1.45133e-005
+4070: 533.636 -340.763 -1.48952e-005
+4071: 533.587 -349.5 -1.52771e-005
+4072: 533.539 -358.237 -1.56591e-005
+4073: 533.491 -366.975 -1.6041e-005
+4074: 533.442 -375.712 -1.64229e-005
+4075: 533.394 -384.45 -1.68048e-005
+4076: 533.345 -393.188 -1.71868e-005
+4077: 533.297 -401.925 -1.75687e-005
+4078: 533.248 -410.663 -1.79506e-005
+4079: 533.2 -419.4 -1.83326e-005
+4080: 533.151 -428.138 -1.87145e-005
+4081: 533.103 -436.875 -1.90964e-005
+4082: 533.055 -445.613 -1.94783e-005
+4083: 533.006 -454.35 -1.98603e-005
+4084: 532.958 -463.088 -2.02422e-005
+4085: 532.909 -471.825 -2.06241e-005
+4086: 532.861 -480.563 -2.10061e-005
+4087: 532.813 -489.3 -2.1388e-005
+4088: 532.764 -498.038 -2.17699e-005
+4089: 532.716 -506.775 -2.21518e-005
+4090: 532.667 -515.513 -2.25338e-005
+4091: 532.619 -524.25 -2.29157e-005
+4092: 532.57 -532.987 -2.32976e-005
+4093: 532.522 -541.725 -2.36796e-005
+4094: 532.473 -550.463 -2.40615e-005
+4095: 532.425 -559.2 -2.44434e-005
+4096: 544.162 0 0
+4097: 544.113 -8.7375 -3.81928e-007
+4098: 544.064 -17.475 -7.63857e-007
+4099: 544.015 -26.2125 -1.14578e-006
+4100: 543.966 -34.95 -1.52771e-006
+4101: 543.916 -43.6875 -1.90964e-006
+4102: 543.867 -52.425 -2.29157e-006
+4103: 543.818 -61.1625 -2.6735e-006
+4104: 543.769 -69.9 -3.05543e-006
+4105: 543.72 -78.6375 -3.43735e-006
+4106: 543.67 -87.375 -3.81928e-006
+4107: 543.621 -96.1125 -4.20121e-006
+4108: 543.572 -104.85 -4.58314e-006
+4109: 543.523 -113.588 -4.96507e-006
+4110: 543.473 -122.325 -5.347e-006
+4111: 543.424 -131.063 -5.72892e-006
+4112: 543.375 -139.8 -6.11085e-006
+4113: 543.326 -148.538 -6.49278e-006
+4114: 543.277 -157.275 -6.87471e-006
+4115: 543.227 -166.013 -7.25664e-006
+4116: 543.178 -174.75 -7.63856e-006
+4117: 543.129 -183.487 -8.02049e-006
+4118: 543.08 -192.225 -8.40242e-006
+4119: 543.03 -200.963 -8.78435e-006
+4120: 542.981 -209.7 -9.16628e-006
+4121: 542.932 -218.438 -9.54821e-006
+4122: 542.883 -227.175 -9.93014e-006
+4123: 542.834 -235.913 -1.03121e-005
+4124: 542.784 -244.65 -1.0694e-005
+4125: 542.735 -253.388 -1.10759e-005
+4126: 542.686 -262.125 -1.14578e-005
+4127: 542.637 -270.863 -1.18398e-005
+4128: 542.588 -279.6 -1.22217e-005
+4129: 542.538 -288.338 -1.26036e-005
+4130: 542.489 -297.075 -1.29856e-005
+4131: 542.44 -305.813 -1.33675e-005
+4132: 542.391 -314.55 -1.37494e-005
+4133: 542.341 -323.288 -1.41313e-005
+4134: 542.292 -332.025 -1.45133e-005
+4135: 542.243 -340.763 -1.48952e-005
+4136: 542.194 -349.5 -1.52771e-005
+4137: 542.145 -358.237 -1.56591e-005
+4138: 542.095 -366.975 -1.6041e-005
+4139: 542.046 -375.713 -1.64229e-005
+4140: 541.997 -384.45 -1.68048e-005
+4141: 541.948 -393.188 -1.71868e-005
+4142: 541.898 -401.925 -1.75687e-005
+4143: 541.849 -410.663 -1.79506e-005
+4144: 541.8 -419.4 -1.83326e-005
+4145: 541.751 -428.138 -1.87145e-005
+4146: 541.702 -436.875 -1.90964e-005
+4147: 541.652 -445.613 -1.94783e-005
+4148: 541.603 -454.35 -1.98603e-005
+4149: 541.554 -463.088 -2.02422e-005
+4150: 541.505 -471.825 -2.06241e-005
+4151: 541.455 -480.563 -2.10061e-005
+4152: 541.406 -489.3 -2.1388e-005
+4153: 541.357 -498.038 -2.17699e-005
+4154: 541.308 -506.775 -2.21518e-005
+4155: 541.259 -515.513 -2.25338e-005
+4156: 541.209 -524.25 -2.29157e-005
+4157: 541.16 -532.987 -2.32976e-005
+4158: 541.111 -541.725 -2.36796e-005
+4159: 541.062 -550.463 -2.40615e-005
+4160: 541.012 -559.2 -2.44434e-005
+4161: 552.8 0 0
+4162: 552.75 -8.7375 -3.81928e-007
+4163: 552.7 -17.475 -7.63857e-007
+4164: 552.65 -26.2125 -1.14578e-006
+4165: 552.6 -34.95 -1.52771e-006
+4166: 552.55 -43.6875 -1.90964e-006
+4167: 552.5 -52.425 -2.29157e-006
+4168: 552.45 -61.1625 -2.6735e-006
+4169: 552.4 -69.9 -3.05543e-006
+4170: 552.35 -78.6375 -3.43735e-006
+4171: 552.3 -87.375 -3.81928e-006
+4172: 552.25 -96.1125 -4.20121e-006
+4173: 552.2 -104.85 -4.58314e-006
+4174: 552.15 -113.588 -4.96507e-006
+4175: 552.1 -122.325 -5.347e-006
+4176: 552.05 -131.063 -5.72892e-006
+4177: 552 -139.8 -6.11085e-006
+4178: 551.95 -148.538 -6.49278e-006
+4179: 551.9 -157.275 -6.87471e-006
+4180: 551.85 -166.013 -7.25664e-006
+4181: 551.8 -174.75 -7.63856e-006
+4182: 551.75 -183.488 -8.02049e-006
+4183: 551.7 -192.225 -8.40242e-006
+4184: 551.65 -200.963 -8.78435e-006
+4185: 551.6 -209.7 -9.16628e-006
+4186: 551.55 -218.438 -9.54821e-006
+4187: 551.5 -227.175 -9.93014e-006
+4188: 551.45 -235.913 -1.03121e-005
+4189: 551.4 -244.65 -1.0694e-005
+4190: 551.35 -253.388 -1.10759e-005
+4191: 551.3 -262.125 -1.14578e-005
+4192: 551.25 -270.863 -1.18398e-005
+4193: 551.2 -279.6 -1.22217e-005
+4194: 551.15 -288.338 -1.26036e-005
+4195: 551.1 -297.075 -1.29856e-005
+4196: 551.05 -305.813 -1.33675e-005
+4197: 551 -314.55 -1.37494e-005
+4198: 550.95 -323.288 -1.41313e-005
+4199: 550.9 -332.025 -1.45133e-005
+4200: 550.85 -340.763 -1.48952e-005
+4201: 550.8 -349.5 -1.52771e-005
+4202: 550.75 -358.237 -1.56591e-005
+4203: 550.7 -366.975 -1.6041e-005
+4204: 550.65 -375.713 -1.64229e-005
+4205: 550.6 -384.45 -1.68048e-005
+4206: 550.55 -393.188 -1.71868e-005
+4207: 550.5 -401.925 -1.75687e-005
+4208: 550.45 -410.663 -1.79506e-005
+4209: 550.4 -419.4 -1.83326e-005
+4210: 550.35 -428.138 -1.87145e-005
+4211: 550.3 -436.875 -1.90964e-005
+4212: 550.25 -445.613 -1.94783e-005
+4213: 550.2 -454.35 -1.98603e-005
+4214: 550.15 -463.088 -2.02422e-005
+4215: 550.1 -471.825 -2.06241e-005
+4216: 550.05 -480.563 -2.10061e-005
+4217: 550 -489.3 -2.1388e-005
+4218: 549.95 -498.038 -2.17699e-005
+4219: 549.9 -506.775 -2.21518e-005
+4220: 549.85 -515.513 -2.25338e-005
+4221: 549.8 -524.25 -2.29157e-005
+4222: 549.75 -532.987 -2.32976e-005
+4223: 549.7 -541.725 -2.36796e-005
+4224: 549.65 -550.463 -2.40615e-005
+4225: 549.6 -559.2 -2.44434e-005
+POLYS
+1: 1 2 67 <
+2: 1 67 66 <
+3: 2 3 68 <
+4: 2 68 67 <
+5: 3 4 69 <
+6: 3 69 68 <
+7: 4 5 70 <
+8: 4 70 69 <
+9: 5 6 71 <
+10: 5 71 70 <
+11: 6 7 72 <
+12: 6 72 71 <
+13: 7 8 73 <
+14: 7 73 72 <
+15: 8 9 74 <
+16: 8 74 73 <
+17: 9 10 75 <
+18: 9 75 74 <
+19: 10 11 76 <
+20: 10 76 75 <
+21: 11 12 77 <
+22: 11 77 76 <
+23: 12 13 78 <
+24: 12 78 77 <
+25: 13 14 79 <
+26: 13 79 78 <
+27: 14 15 80 <
+28: 14 80 79 <
+29: 15 16 81 <
+30: 15 81 80 <
+31: 16 17 82 <
+32: 16 82 81 <
+33: 17 18 83 <
+34: 17 83 82 <
+35: 18 19 84 <
+36: 18 84 83 <
+37: 19 20 85 <
+38: 19 85 84 <
+39: 20 21 86 <
+40: 20 86 85 <
+41: 21 22 87 <
+42: 21 87 86 <
+43: 22 23 88 <
+44: 22 88 87 <
+45: 23 24 89 <
+46: 23 89 88 <
+47: 24 25 90 <
+48: 24 90 89 <
+49: 25 26 91 <
+50: 25 91 90 <
+51: 26 27 92 <
+52: 26 92 91 <
+53: 27 28 93 <
+54: 27 93 92 <
+55: 28 29 94 <
+56: 28 94 93 <
+57: 29 30 95 <
+58: 29 95 94 <
+59: 30 31 96 <
+60: 30 96 95 <
+61: 31 32 97 <
+62: 31 97 96 <
+63: 32 33 98 <
+64: 32 98 97 <
+65: 33 34 99 <
+66: 33 99 98 <
+67: 34 35 100 <
+68: 34 100 99 <
+69: 35 36 101 <
+70: 35 101 100 <
+71: 36 37 102 <
+72: 36 102 101 <
+73: 37 38 103 <
+74: 37 103 102 <
+75: 38 39 104 <
+76: 38 104 103 <
+77: 39 40 105 <
+78: 39 105 104 <
+79: 40 41 106 <
+80: 40 106 105 <
+81: 41 42 107 <
+82: 41 107 106 <
+83: 42 43 108 <
+84: 42 108 107 <
+85: 43 44 109 <
+86: 43 109 108 <
+87: 44 45 110 <
+88: 44 110 109 <
+89: 45 46 111 <
+90: 45 111 110 <
+91: 46 47 112 <
+92: 46 112 111 <
+93: 47 48 113 <
+94: 47 113 112 <
+95: 48 49 114 <
+96: 48 114 113 <
+97: 49 50 115 <
+98: 49 115 114 <
+99: 50 51 116 <
+100: 50 116 115 <
+101: 51 52 117 <
+102: 51 117 116 <
+103: 52 53 118 <
+104: 52 118 117 <
+105: 53 54 119 <
+106: 53 119 118 <
+107: 54 55 120 <
+108: 54 120 119 <
+109: 55 56 121 <
+110: 55 121 120 <
+111: 56 57 122 <
+112: 56 122 121 <
+113: 57 58 123 <
+114: 57 123 122 <
+115: 58 59 124 <
+116: 58 124 123 <
+117: 59 60 125 <
+118: 59 125 124 <
+119: 60 61 126 <
+120: 60 126 125 <
+121: 61 62 127 <
+122: 61 127 126 <
+123: 62 63 128 <
+124: 62 128 127 <
+125: 63 64 129 <
+126: 63 129 128 <
+127: 64 65 130 <
+128: 64 130 129 <
+129: 66 67 132 <
+130: 66 132 131 <
+131: 67 68 133 <
+132: 67 133 132 <
+133: 68 69 134 <
+134: 68 134 133 <
+135: 69 70 135 <
+136: 69 135 134 <
+137: 70 71 136 <
+138: 70 136 135 <
+139: 71 72 137 <
+140: 71 137 136 <
+141: 72 73 138 <
+142: 72 138 137 <
+143: 73 74 139 <
+144: 73 139 138 <
+145: 74 75 140 <
+146: 74 140 139 <
+147: 75 76 141 <
+148: 75 141 140 <
+149: 76 77 142 <
+150: 76 142 141 <
+151: 77 78 143 <
+152: 77 143 142 <
+153: 78 79 144 <
+154: 78 144 143 <
+155: 79 80 145 <
+156: 79 145 144 <
+157: 80 81 146 <
+158: 80 146 145 <
+159: 81 82 147 <
+160: 81 147 146 <
+161: 82 83 148 <
+162: 82 148 147 <
+163: 83 84 149 <
+164: 83 149 148 <
+165: 84 85 150 <
+166: 84 150 149 <
+167: 85 86 151 <
+168: 85 151 150 <
+169: 86 87 152 <
+170: 86 152 151 <
+171: 87 88 153 <
+172: 87 153 152 <
+173: 88 89 154 <
+174: 88 154 153 <
+175: 89 90 155 <
+176: 89 155 154 <
+177: 90 91 156 <
+178: 90 156 155 <
+179: 91 92 157 <
+180: 91 157 156 <
+181: 92 93 158 <
+182: 92 158 157 <
+183: 93 94 159 <
+184: 93 159 158 <
+185: 94 95 160 <
+186: 94 160 159 <
+187: 95 96 161 <
+188: 95 161 160 <
+189: 96 97 162 <
+190: 96 162 161 <
+191: 97 98 163 <
+192: 97 163 162 <
+193: 98 99 164 <
+194: 98 164 163 <
+195: 99 100 165 <
+196: 99 165 164 <
+197: 100 101 166 <
+198: 100 166 165 <
+199: 101 102 167 <
+200: 101 167 166 <
+201: 102 103 168 <
+202: 102 168 167 <
+203: 103 104 169 <
+204: 103 169 168 <
+205: 104 105 170 <
+206: 104 170 169 <
+207: 105 106 171 <
+208: 105 171 170 <
+209: 106 107 172 <
+210: 106 172 171 <
+211: 107 108 173 <
+212: 107 173 172 <
+213: 108 109 174 <
+214: 108 174 173 <
+215: 109 110 175 <
+216: 109 175 174 <
+217: 110 111 176 <
+218: 110 176 175 <
+219: 111 112 177 <
+220: 111 177 176 <
+221: 112 113 178 <
+222: 112 178 177 <
+223: 113 114 179 <
+224: 113 179 178 <
+225: 114 115 180 <
+226: 114 180 179 <
+227: 115 116 181 <
+228: 115 181 180 <
+229: 116 117 182 <
+230: 116 182 181 <
+231: 117 118 183 <
+232: 117 183 182 <
+233: 118 119 184 <
+234: 118 184 183 <
+235: 119 120 185 <
+236: 119 185 184 <
+237: 120 121 186 <
+238: 120 186 185 <
+239: 121 122 187 <
+240: 121 187 186 <
+241: 122 123 188 <
+242: 122 188 187 <
+243: 123 124 189 <
+244: 123 189 188 <
+245: 124 125 190 <
+246: 124 190 189 <
+247: 125 126 191 <
+248: 125 191 190 <
+249: 126 127 192 <
+250: 126 192 191 <
+251: 127 128 193 <
+252: 127 193 192 <
+253: 128 129 194 <
+254: 128 194 193 <
+255: 129 130 195 <
+256: 129 195 194 <
+257: 131 132 197 <
+258: 131 197 196 <
+259: 132 133 198 <
+260: 132 198 197 <
+261: 133 134 199 <
+262: 133 199 198 <
+263: 134 135 200 <
+264: 134 200 199 <
+265: 135 136 201 <
+266: 135 201 200 <
+267: 136 137 202 <
+268: 136 202 201 <
+269: 137 138 203 <
+270: 137 203 202 <
+271: 138 139 204 <
+272: 138 204 203 <
+273: 139 140 205 <
+274: 139 205 204 <
+275: 140 141 206 <
+276: 140 206 205 <
+277: 141 142 207 <
+278: 141 207 206 <
+279: 142 143 208 <
+280: 142 208 207 <
+281: 143 144 209 <
+282: 143 209 208 <
+283: 144 145 210 <
+284: 144 210 209 <
+285: 145 146 211 <
+286: 145 211 210 <
+287: 146 147 212 <
+288: 146 212 211 <
+289: 147 148 213 <
+290: 147 213 212 <
+291: 148 149 214 <
+292: 148 214 213 <
+293: 149 150 215 <
+294: 149 215 214 <
+295: 150 151 216 <
+296: 150 216 215 <
+297: 151 152 217 <
+298: 151 217 216 <
+299: 152 153 218 <
+300: 152 218 217 <
+301: 153 154 219 <
+302: 153 219 218 <
+303: 154 155 220 <
+304: 154 220 219 <
+305: 155 156 221 <
+306: 155 221 220 <
+307: 156 157 222 <
+308: 156 222 221 <
+309: 157 158 223 <
+310: 157 223 222 <
+311: 158 159 224 <
+312: 158 224 223 <
+313: 159 160 225 <
+314: 159 225 224 <
+315: 160 161 226 <
+316: 160 226 225 <
+317: 161 162 227 <
+318: 161 227 226 <
+319: 162 163 228 <
+320: 162 228 227 <
+321: 163 164 229 <
+322: 163 229 228 <
+323: 164 165 230 <
+324: 164 230 229 <
+325: 165 166 231 <
+326: 165 231 230 <
+327: 166 167 232 <
+328: 166 232 231 <
+329: 167 168 233 <
+330: 167 233 232 <
+331: 168 169 234 <
+332: 168 234 233 <
+333: 169 170 235 <
+334: 169 235 234 <
+335: 170 171 236 <
+336: 170 236 235 <
+337: 171 172 237 <
+338: 171 237 236 <
+339: 172 173 238 <
+340: 172 238 237 <
+341: 173 174 239 <
+342: 173 239 238 <
+343: 174 175 240 <
+344: 174 240 239 <
+345: 175 176 241 <
+346: 175 241 240 <
+347: 176 177 242 <
+348: 176 242 241 <
+349: 177 178 243 <
+350: 177 243 242 <
+351: 178 179 244 <
+352: 178 244 243 <
+353: 179 180 245 <
+354: 179 245 244 <
+355: 180 181 246 <
+356: 180 246 245 <
+357: 181 182 247 <
+358: 181 247 246 <
+359: 182 183 248 <
+360: 182 248 247 <
+361: 183 184 249 <
+362: 183 249 248 <
+363: 184 185 250 <
+364: 184 250 249 <
+365: 185 186 251 <
+366: 185 251 250 <
+367: 186 187 252 <
+368: 186 252 251 <
+369: 187 188 253 <
+370: 187 253 252 <
+371: 188 189 254 <
+372: 188 254 253 <
+373: 189 190 255 <
+374: 189 255 254 <
+375: 190 191 256 <
+376: 190 256 255 <
+377: 191 192 257 <
+378: 191 257 256 <
+379: 192 193 258 <
+380: 192 258 257 <
+381: 193 194 259 <
+382: 193 259 258 <
+383: 194 195 260 <
+384: 194 260 259 <
+385: 196 197 262 <
+386: 196 262 261 <
+387: 197 198 263 <
+388: 197 263 262 <
+389: 198 199 264 <
+390: 198 264 263 <
+391: 199 200 265 <
+392: 199 265 264 <
+393: 200 201 266 <
+394: 200 266 265 <
+395: 201 202 267 <
+396: 201 267 266 <
+397: 202 203 268 <
+398: 202 268 267 <
+399: 203 204 269 <
+400: 203 269 268 <
+401: 204 205 270 <
+402: 204 270 269 <
+403: 205 206 271 <
+404: 205 271 270 <
+405: 206 207 272 <
+406: 206 272 271 <
+407: 207 208 273 <
+408: 207 273 272 <
+409: 208 209 274 <
+410: 208 274 273 <
+411: 209 210 275 <
+412: 209 275 274 <
+413: 210 211 276 <
+414: 210 276 275 <
+415: 211 212 277 <
+416: 211 277 276 <
+417: 212 213 278 <
+418: 212 278 277 <
+419: 213 214 279 <
+420: 213 279 278 <
+421: 214 215 280 <
+422: 214 280 279 <
+423: 215 216 281 <
+424: 215 281 280 <
+425: 216 217 282 <
+426: 216 282 281 <
+427: 217 218 283 <
+428: 217 283 282 <
+429: 218 219 284 <
+430: 218 284 283 <
+431: 219 220 285 <
+432: 219 285 284 <
+433: 220 221 286 <
+434: 220 286 285 <
+435: 221 222 287 <
+436: 221 287 286 <
+437: 222 223 288 <
+438: 222 288 287 <
+439: 223 224 289 <
+440: 223 289 288 <
+441: 224 225 290 <
+442: 224 290 289 <
+443: 225 226 291 <
+444: 225 291 290 <
+445: 226 227 292 <
+446: 226 292 291 <
+447: 227 228 293 <
+448: 227 293 292 <
+449: 228 229 294 <
+450: 228 294 293 <
+451: 229 230 295 <
+452: 229 295 294 <
+453: 230 231 296 <
+454: 230 296 295 <
+455: 231 232 297 <
+456: 231 297 296 <
+457: 232 233 298 <
+458: 232 298 297 <
+459: 233 234 299 <
+460: 233 299 298 <
+461: 234 235 300 <
+462: 234 300 299 <
+463: 235 236 301 <
+464: 235 301 300 <
+465: 236 237 302 <
+466: 236 302 301 <
+467: 237 238 303 <
+468: 237 303 302 <
+469: 238 239 304 <
+470: 238 304 303 <
+471: 239 240 305 <
+472: 239 305 304 <
+473: 240 241 306 <
+474: 240 306 305 <
+475: 241 242 307 <
+476: 241 307 306 <
+477: 242 243 308 <
+478: 242 308 307 <
+479: 243 244 309 <
+480: 243 309 308 <
+481: 244 245 310 <
+482: 244 310 309 <
+483: 245 246 311 <
+484: 245 311 310 <
+485: 246 247 312 <
+486: 246 312 311 <
+487: 247 248 313 <
+488: 247 313 312 <
+489: 248 249 314 <
+490: 248 314 313 <
+491: 249 250 315 <
+492: 249 315 314 <
+493: 250 251 316 <
+494: 250 316 315 <
+495: 251 252 317 <
+496: 251 317 316 <
+497: 252 253 318 <
+498: 252 318 317 <
+499: 253 254 319 <
+500: 253 319 318 <
+501: 254 255 320 <
+502: 254 320 319 <
+503: 255 256 321 <
+504: 255 321 320 <
+505: 256 257 322 <
+506: 256 322 321 <
+507: 257 258 323 <
+508: 257 323 322 <
+509: 258 259 324 <
+510: 258 324 323 <
+511: 259 260 325 <
+512: 259 325 324 <
+513: 261 262 327 <
+514: 261 327 326 <
+515: 262 263 328 <
+516: 262 328 327 <
+517: 263 264 329 <
+518: 263 329 328 <
+519: 264 265 330 <
+520: 264 330 329 <
+521: 265 266 331 <
+522: 265 331 330 <
+523: 266 267 332 <
+524: 266 332 331 <
+525: 267 268 333 <
+526: 267 333 332 <
+527: 268 269 334 <
+528: 268 334 333 <
+529: 269 270 335 <
+530: 269 335 334 <
+531: 270 271 336 <
+532: 270 336 335 <
+533: 271 272 337 <
+534: 271 337 336 <
+535: 272 273 338 <
+536: 272 338 337 <
+537: 273 274 339 <
+538: 273 339 338 <
+539: 274 275 340 <
+540: 274 340 339 <
+541: 275 276 341 <
+542: 275 341 340 <
+543: 276 277 342 <
+544: 276 342 341 <
+545: 277 278 343 <
+546: 277 343 342 <
+547: 278 279 344 <
+548: 278 344 343 <
+549: 279 280 345 <
+550: 279 345 344 <
+551: 280 281 346 <
+552: 280 346 345 <
+553: 281 282 347 <
+554: 281 347 346 <
+555: 282 283 348 <
+556: 282 348 347 <
+557: 283 284 349 <
+558: 283 349 348 <
+559: 284 285 350 <
+560: 284 350 349 <
+561: 285 286 351 <
+562: 285 351 350 <
+563: 286 287 352 <
+564: 286 352 351 <
+565: 287 288 353 <
+566: 287 353 352 <
+567: 288 289 354 <
+568: 288 354 353 <
+569: 289 290 355 <
+570: 289 355 354 <
+571: 290 291 356 <
+572: 290 356 355 <
+573: 291 292 357 <
+574: 291 357 356 <
+575: 292 293 358 <
+576: 292 358 357 <
+577: 293 294 359 <
+578: 293 359 358 <
+579: 294 295 360 <
+580: 294 360 359 <
+581: 295 296 361 <
+582: 295 361 360 <
+583: 296 297 362 <
+584: 296 362 361 <
+585: 297 298 363 <
+586: 297 363 362 <
+587: 298 299 364 <
+588: 298 364 363 <
+589: 299 300 365 <
+590: 299 365 364 <
+591: 300 301 366 <
+592: 300 366 365 <
+593: 301 302 367 <
+594: 301 367 366 <
+595: 302 303 368 <
+596: 302 368 367 <
+597: 303 304 369 <
+598: 303 369 368 <
+599: 304 305 370 <
+600: 304 370 369 <
+601: 305 306 371 <
+602: 305 371 370 <
+603: 306 307 372 <
+604: 306 372 371 <
+605: 307 308 373 <
+606: 307 373 372 <
+607: 308 309 374 <
+608: 308 374 373 <
+609: 309 310 375 <
+610: 309 375 374 <
+611: 310 311 376 <
+612: 310 376 375 <
+613: 311 312 377 <
+614: 311 377 376 <
+615: 312 313 378 <
+616: 312 378 377 <
+617: 313 314 379 <
+618: 313 379 378 <
+619: 314 315 380 <
+620: 314 380 379 <
+621: 315 316 381 <
+622: 315 381 380 <
+623: 316 317 382 <
+624: 316 382 381 <
+625: 317 318 383 <
+626: 317 383 382 <
+627: 318 319 384 <
+628: 318 384 383 <
+629: 319 320 385 <
+630: 319 385 384 <
+631: 320 321 386 <
+632: 320 386 385 <
+633: 321 322 387 <
+634: 321 387 386 <
+635: 322 323 388 <
+636: 322 388 387 <
+637: 323 324 389 <
+638: 323 389 388 <
+639: 324 325 390 <
+640: 324 390 389 <
+641: 326 327 392 <
+642: 326 392 391 <
+643: 327 328 393 <
+644: 327 393 392 <
+645: 328 329 394 <
+646: 328 394 393 <
+647: 329 330 395 <
+648: 329 395 394 <
+649: 330 331 396 <
+650: 330 396 395 <
+651: 331 332 397 <
+652: 331 397 396 <
+653: 332 333 398 <
+654: 332 398 397 <
+655: 333 334 399 <
+656: 333 399 398 <
+657: 334 335 400 <
+658: 334 400 399 <
+659: 335 336 401 <
+660: 335 401 400 <
+661: 336 337 402 <
+662: 336 402 401 <
+663: 337 338 403 <
+664: 337 403 402 <
+665: 338 339 404 <
+666: 338 404 403 <
+667: 339 340 405 <
+668: 339 405 404 <
+669: 340 341 406 <
+670: 340 406 405 <
+671: 341 342 407 <
+672: 341 407 406 <
+673: 342 343 408 <
+674: 342 408 407 <
+675: 343 344 409 <
+676: 343 409 408 <
+677: 344 345 410 <
+678: 344 410 409 <
+679: 345 346 411 <
+680: 345 411 410 <
+681: 346 347 412 <
+682: 346 412 411 <
+683: 347 348 413 <
+684: 347 413 412 <
+685: 348 349 414 <
+686: 348 414 413 <
+687: 349 350 415 <
+688: 349 415 414 <
+689: 350 351 416 <
+690: 350 416 415 <
+691: 351 352 417 <
+692: 351 417 416 <
+693: 352 353 418 <
+694: 352 418 417 <
+695: 353 354 419 <
+696: 353 419 418 <
+697: 354 355 420 <
+698: 354 420 419 <
+699: 355 356 421 <
+700: 355 421 420 <
+701: 356 357 422 <
+702: 356 422 421 <
+703: 357 358 423 <
+704: 357 423 422 <
+705: 358 359 424 <
+706: 358 424 423 <
+707: 359 360 425 <
+708: 359 425 424 <
+709: 360 361 426 <
+710: 360 426 425 <
+711: 361 362 427 <
+712: 361 427 426 <
+713: 362 363 428 <
+714: 362 428 427 <
+715: 363 364 429 <
+716: 363 429 428 <
+717: 364 365 430 <
+718: 364 430 429 <
+719: 365 366 431 <
+720: 365 431 430 <
+721: 366 367 432 <
+722: 366 432 431 <
+723: 367 368 433 <
+724: 367 433 432 <
+725: 368 369 434 <
+726: 368 434 433 <
+727: 369 370 435 <
+728: 369 435 434 <
+729: 370 371 436 <
+730: 370 436 435 <
+731: 371 372 437 <
+732: 371 437 436 <
+733: 372 373 438 <
+734: 372 438 437 <
+735: 373 374 439 <
+736: 373 439 438 <
+737: 374 375 440 <
+738: 374 440 439 <
+739: 375 376 441 <
+740: 375 441 440 <
+741: 376 377 442 <
+742: 376 442 441 <
+743: 377 378 443 <
+744: 377 443 442 <
+745: 378 379 444 <
+746: 378 444 443 <
+747: 379 380 445 <
+748: 379 445 444 <
+749: 380 381 446 <
+750: 380 446 445 <
+751: 381 382 447 <
+752: 381 447 446 <
+753: 382 383 448 <
+754: 382 448 447 <
+755: 383 384 449 <
+756: 383 449 448 <
+757: 384 385 450 <
+758: 384 450 449 <
+759: 385 386 451 <
+760: 385 451 450 <
+761: 386 387 452 <
+762: 386 452 451 <
+763: 387 388 453 <
+764: 387 453 452 <
+765: 388 389 454 <
+766: 388 454 453 <
+767: 389 390 455 <
+768: 389 455 454 <
+769: 391 392 457 <
+770: 391 457 456 <
+771: 392 393 458 <
+772: 392 458 457 <
+773: 393 394 459 <
+774: 393 459 458 <
+775: 394 395 460 <
+776: 394 460 459 <
+777: 395 396 461 <
+778: 395 461 460 <
+779: 396 397 462 <
+780: 396 462 461 <
+781: 397 398 463 <
+782: 397 463 462 <
+783: 398 399 464 <
+784: 398 464 463 <
+785: 399 400 465 <
+786: 399 465 464 <
+787: 400 401 466 <
+788: 400 466 465 <
+789: 401 402 467 <
+790: 401 467 466 <
+791: 402 403 468 <
+792: 402 468 467 <
+793: 403 404 469 <
+794: 403 469 468 <
+795: 404 405 470 <
+796: 404 470 469 <
+797: 405 406 471 <
+798: 405 471 470 <
+799: 406 407 472 <
+800: 406 472 471 <
+801: 407 408 473 <
+802: 407 473 472 <
+803: 408 409 474 <
+804: 408 474 473 <
+805: 409 410 475 <
+806: 409 475 474 <
+807: 410 411 476 <
+808: 410 476 475 <
+809: 411 412 477 <
+810: 411 477 476 <
+811: 412 413 478 <
+812: 412 478 477 <
+813: 413 414 479 <
+814: 413 479 478 <
+815: 414 415 480 <
+816: 414 480 479 <
+817: 415 416 481 <
+818: 415 481 480 <
+819: 416 417 482 <
+820: 416 482 481 <
+821: 417 418 483 <
+822: 417 483 482 <
+823: 418 419 484 <
+824: 418 484 483 <
+825: 419 420 485 <
+826: 419 485 484 <
+827: 420 421 486 <
+828: 420 486 485 <
+829: 421 422 487 <
+830: 421 487 486 <
+831: 422 423 488 <
+832: 422 488 487 <
+833: 423 424 489 <
+834: 423 489 488 <
+835: 424 425 490 <
+836: 424 490 489 <
+837: 425 426 491 <
+838: 425 491 490 <
+839: 426 427 492 <
+840: 426 492 491 <
+841: 427 428 493 <
+842: 427 493 492 <
+843: 428 429 494 <
+844: 428 494 493 <
+845: 429 430 495 <
+846: 429 495 494 <
+847: 430 431 496 <
+848: 430 496 495 <
+849: 431 432 497 <
+850: 431 497 496 <
+851: 432 433 498 <
+852: 432 498 497 <
+853: 433 434 499 <
+854: 433 499 498 <
+855: 434 435 500 <
+856: 434 500 499 <
+857: 435 436 501 <
+858: 435 501 500 <
+859: 436 437 502 <
+860: 436 502 501 <
+861: 437 438 503 <
+862: 437 503 502 <
+863: 438 439 504 <
+864: 438 504 503 <
+865: 439 440 505 <
+866: 439 505 504 <
+867: 440 441 506 <
+868: 440 506 505 <
+869: 441 442 507 <
+870: 441 507 506 <
+871: 442 443 508 <
+872: 442 508 507 <
+873: 443 444 509 <
+874: 443 509 508 <
+875: 444 445 510 <
+876: 444 510 509 <
+877: 445 446 511 <
+878: 445 511 510 <
+879: 446 447 512 <
+880: 446 512 511 <
+881: 447 448 513 <
+882: 447 513 512 <
+883: 448 449 514 <
+884: 448 514 513 <
+885: 449 450 515 <
+886: 449 515 514 <
+887: 450 451 516 <
+888: 450 516 515 <
+889: 451 452 517 <
+890: 451 517 516 <
+891: 452 453 518 <
+892: 452 518 517 <
+893: 453 454 519 <
+894: 453 519 518 <
+895: 454 455 520 <
+896: 454 520 519 <
+897: 456 457 522 <
+898: 456 522 521 <
+899: 457 458 523 <
+900: 457 523 522 <
+901: 458 459 524 <
+902: 458 524 523 <
+903: 459 460 525 <
+904: 459 525 524 <
+905: 460 461 526 <
+906: 460 526 525 <
+907: 461 462 527 <
+908: 461 527 526 <
+909: 462 463 528 <
+910: 462 528 527 <
+911: 463 464 529 <
+912: 463 529 528 <
+913: 464 465 530 <
+914: 464 530 529 <
+915: 465 466 531 <
+916: 465 531 530 <
+917: 466 467 532 <
+918: 466 532 531 <
+919: 467 468 533 <
+920: 467 533 532 <
+921: 468 469 534 <
+922: 468 534 533 <
+923: 469 470 535 <
+924: 469 535 534 <
+925: 470 471 536 <
+926: 470 536 535 <
+927: 471 472 537 <
+928: 471 537 536 <
+929: 472 473 538 <
+930: 472 538 537 <
+931: 473 474 539 <
+932: 473 539 538 <
+933: 474 475 540 <
+934: 474 540 539 <
+935: 475 476 541 <
+936: 475 541 540 <
+937: 476 477 542 <
+938: 476 542 541 <
+939: 477 478 543 <
+940: 477 543 542 <
+941: 478 479 544 <
+942: 478 544 543 <
+943: 479 480 545 <
+944: 479 545 544 <
+945: 480 481 546 <
+946: 480 546 545 <
+947: 481 482 547 <
+948: 481 547 546 <
+949: 482 483 548 <
+950: 482 548 547 <
+951: 483 484 549 <
+952: 483 549 548 <
+953: 484 485 550 <
+954: 484 550 549 <
+955: 485 486 551 <
+956: 485 551 550 <
+957: 486 487 552 <
+958: 486 552 551 <
+959: 487 488 553 <
+960: 487 553 552 <
+961: 488 489 554 <
+962: 488 554 553 <
+963: 489 490 555 <
+964: 489 555 554 <
+965: 490 491 556 <
+966: 490 556 555 <
+967: 491 492 557 <
+968: 491 557 556 <
+969: 492 493 558 <
+970: 492 558 557 <
+971: 493 494 559 <
+972: 493 559 558 <
+973: 494 495 560 <
+974: 494 560 559 <
+975: 495 496 561 <
+976: 495 561 560 <
+977: 496 497 562 <
+978: 496 562 561 <
+979: 497 498 563 <
+980: 497 563 562 <
+981: 498 499 564 <
+982: 498 564 563 <
+983: 499 500 565 <
+984: 499 565 564 <
+985: 500 501 566 <
+986: 500 566 565 <
+987: 501 502 567 <
+988: 501 567 566 <
+989: 502 503 568 <
+990: 502 568 567 <
+991: 503 504 569 <
+992: 503 569 568 <
+993: 504 505 570 <
+994: 504 570 569 <
+995: 505 506 571 <
+996: 505 571 570 <
+997: 506 507 572 <
+998: 506 572 571 <
+999: 507 508 573 <
+1000: 507 573 572 <
+1001: 508 509 574 <
+1002: 508 574 573 <
+1003: 509 510 575 <
+1004: 509 575 574 <
+1005: 510 511 576 <
+1006: 510 576 575 <
+1007: 511 512 577 <
+1008: 511 577 576 <
+1009: 512 513 578 <
+1010: 512 578 577 <
+1011: 513 514 579 <
+1012: 513 579 578 <
+1013: 514 515 580 <
+1014: 514 580 579 <
+1015: 515 516 581 <
+1016: 515 581 580 <
+1017: 516 517 582 <
+1018: 516 582 581 <
+1019: 517 518 583 <
+1020: 517 583 582 <
+1021: 518 519 584 <
+1022: 518 584 583 <
+1023: 519 520 585 <
+1024: 519 585 584 <
+1025: 521 522 587 <
+1026: 521 587 586 <
+1027: 522 523 588 <
+1028: 522 588 587 <
+1029: 523 524 589 <
+1030: 523 589 588 <
+1031: 524 525 590 <
+1032: 524 590 589 <
+1033: 525 526 591 <
+1034: 525 591 590 <
+1035: 526 527 592 <
+1036: 526 592 591 <
+1037: 527 528 593 <
+1038: 527 593 592 <
+1039: 528 529 594 <
+1040: 528 594 593 <
+1041: 529 530 595 <
+1042: 529 595 594 <
+1043: 530 531 596 <
+1044: 530 596 595 <
+1045: 531 532 597 <
+1046: 531 597 596 <
+1047: 532 533 598 <
+1048: 532 598 597 <
+1049: 533 534 599 <
+1050: 533 599 598 <
+1051: 534 535 600 <
+1052: 534 600 599 <
+1053: 535 536 601 <
+1054: 535 601 600 <
+1055: 536 537 602 <
+1056: 536 602 601 <
+1057: 537 538 603 <
+1058: 537 603 602 <
+1059: 538 539 604 <
+1060: 538 604 603 <
+1061: 539 540 605 <
+1062: 539 605 604 <
+1063: 540 541 606 <
+1064: 540 606 605 <
+1065: 541 542 607 <
+1066: 541 607 606 <
+1067: 542 543 608 <
+1068: 542 608 607 <
+1069: 543 544 609 <
+1070: 543 609 608 <
+1071: 544 545 610 <
+1072: 544 610 609 <
+1073: 545 546 611 <
+1074: 545 611 610 <
+1075: 546 547 612 <
+1076: 546 612 611 <
+1077: 547 548 613 <
+1078: 547 613 612 <
+1079: 548 549 614 <
+1080: 548 614 613 <
+1081: 549 550 615 <
+1082: 549 615 614 <
+1083: 550 551 616 <
+1084: 550 616 615 <
+1085: 551 552 617 <
+1086: 551 617 616 <
+1087: 552 553 618 <
+1088: 552 618 617 <
+1089: 553 554 619 <
+1090: 553 619 618 <
+1091: 554 555 620 <
+1092: 554 620 619 <
+1093: 555 556 621 <
+1094: 555 621 620 <
+1095: 556 557 622 <
+1096: 556 622 621 <
+1097: 557 558 623 <
+1098: 557 623 622 <
+1099: 558 559 624 <
+1100: 558 624 623 <
+1101: 559 560 625 <
+1102: 559 625 624 <
+1103: 560 561 626 <
+1104: 560 626 625 <
+1105: 561 562 627 <
+1106: 561 627 626 <
+1107: 562 563 628 <
+1108: 562 628 627 <
+1109: 563 564 629 <
+1110: 563 629 628 <
+1111: 564 565 630 <
+1112: 564 630 629 <
+1113: 565 566 631 <
+1114: 565 631 630 <
+1115: 566 567 632 <
+1116: 566 632 631 <
+1117: 567 568 633 <
+1118: 567 633 632 <
+1119: 568 569 634 <
+1120: 568 634 633 <
+1121: 569 570 635 <
+1122: 569 635 634 <
+1123: 570 571 636 <
+1124: 570 636 635 <
+1125: 571 572 637 <
+1126: 571 637 636 <
+1127: 572 573 638 <
+1128: 572 638 637 <
+1129: 573 574 639 <
+1130: 573 639 638 <
+1131: 574 575 640 <
+1132: 574 640 639 <
+1133: 575 576 641 <
+1134: 575 641 640 <
+1135: 576 577 642 <
+1136: 576 642 641 <
+1137: 577 578 643 <
+1138: 577 643 642 <
+1139: 578 579 644 <
+1140: 578 644 643 <
+1141: 579 580 645 <
+1142: 579 645 644 <
+1143: 580 581 646 <
+1144: 580 646 645 <
+1145: 581 582 647 <
+1146: 581 647 646 <
+1147: 582 583 648 <
+1148: 582 648 647 <
+1149: 583 584 649 <
+1150: 583 649 648 <
+1151: 584 585 650 <
+1152: 584 650 649 <
+1153: 586 587 652 <
+1154: 586 652 651 <
+1155: 587 588 653 <
+1156: 587 653 652 <
+1157: 588 589 654 <
+1158: 588 654 653 <
+1159: 589 590 655 <
+1160: 589 655 654 <
+1161: 590 591 656 <
+1162: 590 656 655 <
+1163: 591 592 657 <
+1164: 591 657 656 <
+1165: 592 593 658 <
+1166: 592 658 657 <
+1167: 593 594 659 <
+1168: 593 659 658 <
+1169: 594 595 660 <
+1170: 594 660 659 <
+1171: 595 596 661 <
+1172: 595 661 660 <
+1173: 596 597 662 <
+1174: 596 662 661 <
+1175: 597 598 663 <
+1176: 597 663 662 <
+1177: 598 599 664 <
+1178: 598 664 663 <
+1179: 599 600 665 <
+1180: 599 665 664 <
+1181: 600 601 666 <
+1182: 600 666 665 <
+1183: 601 602 667 <
+1184: 601 667 666 <
+1185: 602 603 668 <
+1186: 602 668 667 <
+1187: 603 604 669 <
+1188: 603 669 668 <
+1189: 604 605 670 <
+1190: 604 670 669 <
+1191: 605 606 671 <
+1192: 605 671 670 <
+1193: 606 607 672 <
+1194: 606 672 671 <
+1195: 607 608 673 <
+1196: 607 673 672 <
+1197: 608 609 674 <
+1198: 608 674 673 <
+1199: 609 610 675 <
+1200: 609 675 674 <
+1201: 610 611 676 <
+1202: 610 676 675 <
+1203: 611 612 677 <
+1204: 611 677 676 <
+1205: 612 613 678 <
+1206: 612 678 677 <
+1207: 613 614 679 <
+1208: 613 679 678 <
+1209: 614 615 680 <
+1210: 614 680 679 <
+1211: 615 616 681 <
+1212: 615 681 680 <
+1213: 616 617 682 <
+1214: 616 682 681 <
+1215: 617 618 683 <
+1216: 617 683 682 <
+1217: 618 619 684 <
+1218: 618 684 683 <
+1219: 619 620 685 <
+1220: 619 685 684 <
+1221: 620 621 686 <
+1222: 620 686 685 <
+1223: 621 622 687 <
+1224: 621 687 686 <
+1225: 622 623 688 <
+1226: 622 688 687 <
+1227: 623 624 689 <
+1228: 623 689 688 <
+1229: 624 625 690 <
+1230: 624 690 689 <
+1231: 625 626 691 <
+1232: 625 691 690 <
+1233: 626 627 692 <
+1234: 626 692 691 <
+1235: 627 628 693 <
+1236: 627 693 692 <
+1237: 628 629 694 <
+1238: 628 694 693 <
+1239: 629 630 695 <
+1240: 629 695 694 <
+1241: 630 631 696 <
+1242: 630 696 695 <
+1243: 631 632 697 <
+1244: 631 697 696 <
+1245: 632 633 698 <
+1246: 632 698 697 <
+1247: 633 634 699 <
+1248: 633 699 698 <
+1249: 634 635 700 <
+1250: 634 700 699 <
+1251: 635 636 701 <
+1252: 635 701 700 <
+1253: 636 637 702 <
+1254: 636 702 701 <
+1255: 637 638 703 <
+1256: 637 703 702 <
+1257: 638 639 704 <
+1258: 638 704 703 <
+1259: 639 640 705 <
+1260: 639 705 704 <
+1261: 640 641 706 <
+1262: 640 706 705 <
+1263: 641 642 707 <
+1264: 641 707 706 <
+1265: 642 643 708 <
+1266: 642 708 707 <
+1267: 643 644 709 <
+1268: 643 709 708 <
+1269: 644 645 710 <
+1270: 644 710 709 <
+1271: 645 646 711 <
+1272: 645 711 710 <
+1273: 646 647 712 <
+1274: 646 712 711 <
+1275: 647 648 713 <
+1276: 647 713 712 <
+1277: 648 649 714 <
+1278: 648 714 713 <
+1279: 649 650 715 <
+1280: 649 715 714 <
+1281: 651 652 717 <
+1282: 651 717 716 <
+1283: 652 653 718 <
+1284: 652 718 717 <
+1285: 653 654 719 <
+1286: 653 719 718 <
+1287: 654 655 720 <
+1288: 654 720 719 <
+1289: 655 656 721 <
+1290: 655 721 720 <
+1291: 656 657 722 <
+1292: 656 722 721 <
+1293: 657 658 723 <
+1294: 657 723 722 <
+1295: 658 659 724 <
+1296: 658 724 723 <
+1297: 659 660 725 <
+1298: 659 725 724 <
+1299: 660 661 726 <
+1300: 660 726 725 <
+1301: 661 662 727 <
+1302: 661 727 726 <
+1303: 662 663 728 <
+1304: 662 728 727 <
+1305: 663 664 729 <
+1306: 663 729 728 <
+1307: 664 665 730 <
+1308: 664 730 729 <
+1309: 665 666 731 <
+1310: 665 731 730 <
+1311: 666 667 732 <
+1312: 666 732 731 <
+1313: 667 668 733 <
+1314: 667 733 732 <
+1315: 668 669 734 <
+1316: 668 734 733 <
+1317: 669 670 735 <
+1318: 669 735 734 <
+1319: 670 671 736 <
+1320: 670 736 735 <
+1321: 671 672 737 <
+1322: 671 737 736 <
+1323: 672 673 738 <
+1324: 672 738 737 <
+1325: 673 674 739 <
+1326: 673 739 738 <
+1327: 674 675 740 <
+1328: 674 740 739 <
+1329: 675 676 741 <
+1330: 675 741 740 <
+1331: 676 677 742 <
+1332: 676 742 741 <
+1333: 677 678 743 <
+1334: 677 743 742 <
+1335: 678 679 744 <
+1336: 678 744 743 <
+1337: 679 680 745 <
+1338: 679 745 744 <
+1339: 680 681 746 <
+1340: 680 746 745 <
+1341: 681 682 747 <
+1342: 681 747 746 <
+1343: 682 683 748 <
+1344: 682 748 747 <
+1345: 683 684 749 <
+1346: 683 749 748 <
+1347: 684 685 750 <
+1348: 684 750 749 <
+1349: 685 686 751 <
+1350: 685 751 750 <
+1351: 686 687 752 <
+1352: 686 752 751 <
+1353: 687 688 753 <
+1354: 687 753 752 <
+1355: 688 689 754 <
+1356: 688 754 753 <
+1357: 689 690 755 <
+1358: 689 755 754 <
+1359: 690 691 756 <
+1360: 690 756 755 <
+1361: 691 692 757 <
+1362: 691 757 756 <
+1363: 692 693 758 <
+1364: 692 758 757 <
+1365: 693 694 759 <
+1366: 693 759 758 <
+1367: 694 695 760 <
+1368: 694 760 759 <
+1369: 695 696 761 <
+1370: 695 761 760 <
+1371: 696 697 762 <
+1372: 696 762 761 <
+1373: 697 698 763 <
+1374: 697 763 762 <
+1375: 698 699 764 <
+1376: 698 764 763 <
+1377: 699 700 765 <
+1378: 699 765 764 <
+1379: 700 701 766 <
+1380: 700 766 765 <
+1381: 701 702 767 <
+1382: 701 767 766 <
+1383: 702 703 768 <
+1384: 702 768 767 <
+1385: 703 704 769 <
+1386: 703 769 768 <
+1387: 704 705 770 <
+1388: 704 770 769 <
+1389: 705 706 771 <
+1390: 705 771 770 <
+1391: 706 707 772 <
+1392: 706 772 771 <
+1393: 707 708 773 <
+1394: 707 773 772 <
+1395: 708 709 774 <
+1396: 708 774 773 <
+1397: 709 710 775 <
+1398: 709 775 774 <
+1399: 710 711 776 <
+1400: 710 776 775 <
+1401: 711 712 777 <
+1402: 711 777 776 <
+1403: 712 713 778 <
+1404: 712 778 777 <
+1405: 713 714 779 <
+1406: 713 779 778 <
+1407: 714 715 780 <
+1408: 714 780 779 <
+1409: 716 717 782 <
+1410: 716 782 781 <
+1411: 717 718 783 <
+1412: 717 783 782 <
+1413: 718 719 784 <
+1414: 718 784 783 <
+1415: 719 720 785 <
+1416: 719 785 784 <
+1417: 720 721 786 <
+1418: 720 786 785 <
+1419: 721 722 787 <
+1420: 721 787 786 <
+1421: 722 723 788 <
+1422: 722 788 787 <
+1423: 723 724 789 <
+1424: 723 789 788 <
+1425: 724 725 790 <
+1426: 724 790 789 <
+1427: 725 726 791 <
+1428: 725 791 790 <
+1429: 726 727 792 <
+1430: 726 792 791 <
+1431: 727 728 793 <
+1432: 727 793 792 <
+1433: 728 729 794 <
+1434: 728 794 793 <
+1435: 729 730 795 <
+1436: 729 795 794 <
+1437: 730 731 796 <
+1438: 730 796 795 <
+1439: 731 732 797 <
+1440: 731 797 796 <
+1441: 732 733 798 <
+1442: 732 798 797 <
+1443: 733 734 799 <
+1444: 733 799 798 <
+1445: 734 735 800 <
+1446: 734 800 799 <
+1447: 735 736 801 <
+1448: 735 801 800 <
+1449: 736 737 802 <
+1450: 736 802 801 <
+1451: 737 738 803 <
+1452: 737 803 802 <
+1453: 738 739 804 <
+1454: 738 804 803 <
+1455: 739 740 805 <
+1456: 739 805 804 <
+1457: 740 741 806 <
+1458: 740 806 805 <
+1459: 741 742 807 <
+1460: 741 807 806 <
+1461: 742 743 808 <
+1462: 742 808 807 <
+1463: 743 744 809 <
+1464: 743 809 808 <
+1465: 744 745 810 <
+1466: 744 810 809 <
+1467: 745 746 811 <
+1468: 745 811 810 <
+1469: 746 747 812 <
+1470: 746 812 811 <
+1471: 747 748 813 <
+1472: 747 813 812 <
+1473: 748 749 814 <
+1474: 748 814 813 <
+1475: 749 750 815 <
+1476: 749 815 814 <
+1477: 750 751 816 <
+1478: 750 816 815 <
+1479: 751 752 817 <
+1480: 751 817 816 <
+1481: 752 753 818 <
+1482: 752 818 817 <
+1483: 753 754 819 <
+1484: 753 819 818 <
+1485: 754 755 820 <
+1486: 754 820 819 <
+1487: 755 756 821 <
+1488: 755 821 820 <
+1489: 756 757 822 <
+1490: 756 822 821 <
+1491: 757 758 823 <
+1492: 757 823 822 <
+1493: 758 759 824 <
+1494: 758 824 823 <
+1495: 759 760 825 <
+1496: 759 825 824 <
+1497: 760 761 826 <
+1498: 760 826 825 <
+1499: 761 762 827 <
+1500: 761 827 826 <
+1501: 762 763 828 <
+1502: 762 828 827 <
+1503: 763 764 829 <
+1504: 763 829 828 <
+1505: 764 765 830 <
+1506: 764 830 829 <
+1507: 765 766 831 <
+1508: 765 831 830 <
+1509: 766 767 832 <
+1510: 766 832 831 <
+1511: 767 768 833 <
+1512: 767 833 832 <
+1513: 768 769 834 <
+1514: 768 834 833 <
+1515: 769 770 835 <
+1516: 769 835 834 <
+1517: 770 771 836 <
+1518: 770 836 835 <
+1519: 771 772 837 <
+1520: 771 837 836 <
+1521: 772 773 838 <
+1522: 772 838 837 <
+1523: 773 774 839 <
+1524: 773 839 838 <
+1525: 774 775 840 <
+1526: 774 840 839 <
+1527: 775 776 841 <
+1528: 775 841 840 <
+1529: 776 777 842 <
+1530: 776 842 841 <
+1531: 777 778 843 <
+1532: 777 843 842 <
+1533: 778 779 844 <
+1534: 778 844 843 <
+1535: 779 780 845 <
+1536: 779 845 844 <
+1537: 781 782 847 <
+1538: 781 847 846 <
+1539: 782 783 848 <
+1540: 782 848 847 <
+1541: 783 784 849 <
+1542: 783 849 848 <
+1543: 784 785 850 <
+1544: 784 850 849 <
+1545: 785 786 851 <
+1546: 785 851 850 <
+1547: 786 787 852 <
+1548: 786 852 851 <
+1549: 787 788 853 <
+1550: 787 853 852 <
+1551: 788 789 854 <
+1552: 788 854 853 <
+1553: 789 790 855 <
+1554: 789 855 854 <
+1555: 790 791 856 <
+1556: 790 856 855 <
+1557: 791 792 857 <
+1558: 791 857 856 <
+1559: 792 793 858 <
+1560: 792 858 857 <
+1561: 793 794 859 <
+1562: 793 859 858 <
+1563: 794 795 860 <
+1564: 794 860 859 <
+1565: 795 796 861 <
+1566: 795 861 860 <
+1567: 796 797 862 <
+1568: 796 862 861 <
+1569: 797 798 863 <
+1570: 797 863 862 <
+1571: 798 799 864 <
+1572: 798 864 863 <
+1573: 799 800 865 <
+1574: 799 865 864 <
+1575: 800 801 866 <
+1576: 800 866 865 <
+1577: 801 802 867 <
+1578: 801 867 866 <
+1579: 802 803 868 <
+1580: 802 868 867 <
+1581: 803 804 869 <
+1582: 803 869 868 <
+1583: 804 805 870 <
+1584: 804 870 869 <
+1585: 805 806 871 <
+1586: 805 871 870 <
+1587: 806 807 872 <
+1588: 806 872 871 <
+1589: 807 808 873 <
+1590: 807 873 872 <
+1591: 808 809 874 <
+1592: 808 874 873 <
+1593: 809 810 875 <
+1594: 809 875 874 <
+1595: 810 811 876 <
+1596: 810 876 875 <
+1597: 811 812 877 <
+1598: 811 877 876 <
+1599: 812 813 878 <
+1600: 812 878 877 <
+1601: 813 814 879 <
+1602: 813 879 878 <
+1603: 814 815 880 <
+1604: 814 880 879 <
+1605: 815 816 881 <
+1606: 815 881 880 <
+1607: 816 817 882 <
+1608: 816 882 881 <
+1609: 817 818 883 <
+1610: 817 883 882 <
+1611: 818 819 884 <
+1612: 818 884 883 <
+1613: 819 820 885 <
+1614: 819 885 884 <
+1615: 820 821 886 <
+1616: 820 886 885 <
+1617: 821 822 887 <
+1618: 821 887 886 <
+1619: 822 823 888 <
+1620: 822 888 887 <
+1621: 823 824 889 <
+1622: 823 889 888 <
+1623: 824 825 890 <
+1624: 824 890 889 <
+1625: 825 826 891 <
+1626: 825 891 890 <
+1627: 826 827 892 <
+1628: 826 892 891 <
+1629: 827 828 893 <
+1630: 827 893 892 <
+1631: 828 829 894 <
+1632: 828 894 893 <
+1633: 829 830 895 <
+1634: 829 895 894 <
+1635: 830 831 896 <
+1636: 830 896 895 <
+1637: 831 832 897 <
+1638: 831 897 896 <
+1639: 832 833 898 <
+1640: 832 898 897 <
+1641: 833 834 899 <
+1642: 833 899 898 <
+1643: 834 835 900 <
+1644: 834 900 899 <
+1645: 835 836 901 <
+1646: 835 901 900 <
+1647: 836 837 902 <
+1648: 836 902 901 <
+1649: 837 838 903 <
+1650: 837 903 902 <
+1651: 838 839 904 <
+1652: 838 904 903 <
+1653: 839 840 905 <
+1654: 839 905 904 <
+1655: 840 841 906 <
+1656: 840 906 905 <
+1657: 841 842 907 <
+1658: 841 907 906 <
+1659: 842 843 908 <
+1660: 842 908 907 <
+1661: 843 844 909 <
+1662: 843 909 908 <
+1663: 844 845 910 <
+1664: 844 910 909 <
+1665: 846 847 912 <
+1666: 846 912 911 <
+1667: 847 848 913 <
+1668: 847 913 912 <
+1669: 848 849 914 <
+1670: 848 914 913 <
+1671: 849 850 915 <
+1672: 849 915 914 <
+1673: 850 851 916 <
+1674: 850 916 915 <
+1675: 851 852 917 <
+1676: 851 917 916 <
+1677: 852 853 918 <
+1678: 852 918 917 <
+1679: 853 854 919 <
+1680: 853 919 918 <
+1681: 854 855 920 <
+1682: 854 920 919 <
+1683: 855 856 921 <
+1684: 855 921 920 <
+1685: 856 857 922 <
+1686: 856 922 921 <
+1687: 857 858 923 <
+1688: 857 923 922 <
+1689: 858 859 924 <
+1690: 858 924 923 <
+1691: 859 860 925 <
+1692: 859 925 924 <
+1693: 860 861 926 <
+1694: 860 926 925 <
+1695: 861 862 927 <
+1696: 861 927 926 <
+1697: 862 863 928 <
+1698: 862 928 927 <
+1699: 863 864 929 <
+1700: 863 929 928 <
+1701: 864 865 930 <
+1702: 864 930 929 <
+1703: 865 866 931 <
+1704: 865 931 930 <
+1705: 866 867 932 <
+1706: 866 932 931 <
+1707: 867 868 933 <
+1708: 867 933 932 <
+1709: 868 869 934 <
+1710: 868 934 933 <
+1711: 869 870 935 <
+1712: 869 935 934 <
+1713: 870 871 936 <
+1714: 870 936 935 <
+1715: 871 872 937 <
+1716: 871 937 936 <
+1717: 872 873 938 <
+1718: 872 938 937 <
+1719: 873 874 939 <
+1720: 873 939 938 <
+1721: 874 875 940 <
+1722: 874 940 939 <
+1723: 875 876 941 <
+1724: 875 941 940 <
+1725: 876 877 942 <
+1726: 876 942 941 <
+1727: 877 878 943 <
+1728: 877 943 942 <
+1729: 878 879 944 <
+1730: 878 944 943 <
+1731: 879 880 945 <
+1732: 879 945 944 <
+1733: 880 881 946 <
+1734: 880 946 945 <
+1735: 881 882 947 <
+1736: 881 947 946 <
+1737: 882 883 948 <
+1738: 882 948 947 <
+1739: 883 884 949 <
+1740: 883 949 948 <
+1741: 884 885 950 <
+1742: 884 950 949 <
+1743: 885 886 951 <
+1744: 885 951 950 <
+1745: 886 887 952 <
+1746: 886 952 951 <
+1747: 887 888 953 <
+1748: 887 953 952 <
+1749: 888 889 954 <
+1750: 888 954 953 <
+1751: 889 890 955 <
+1752: 889 955 954 <
+1753: 890 891 956 <
+1754: 890 956 955 <
+1755: 891 892 957 <
+1756: 891 957 956 <
+1757: 892 893 958 <
+1758: 892 958 957 <
+1759: 893 894 959 <
+1760: 893 959 958 <
+1761: 894 895 960 <
+1762: 894 960 959 <
+1763: 895 896 961 <
+1764: 895 961 960 <
+1765: 896 897 962 <
+1766: 896 962 961 <
+1767: 897 898 963 <
+1768: 897 963 962 <
+1769: 898 899 964 <
+1770: 898 964 963 <
+1771: 899 900 965 <
+1772: 899 965 964 <
+1773: 900 901 966 <
+1774: 900 966 965 <
+1775: 901 902 967 <
+1776: 901 967 966 <
+1777: 902 903 968 <
+1778: 902 968 967 <
+1779: 903 904 969 <
+1780: 903 969 968 <
+1781: 904 905 970 <
+1782: 904 970 969 <
+1783: 905 906 971 <
+1784: 905 971 970 <
+1785: 906 907 972 <
+1786: 906 972 971 <
+1787: 907 908 973 <
+1788: 907 973 972 <
+1789: 908 909 974 <
+1790: 908 974 973 <
+1791: 909 910 975 <
+1792: 909 975 974 <
+1793: 911 912 977 <
+1794: 911 977 976 <
+1795: 912 913 978 <
+1796: 912 978 977 <
+1797: 913 914 979 <
+1798: 913 979 978 <
+1799: 914 915 980 <
+1800: 914 980 979 <
+1801: 915 916 981 <
+1802: 915 981 980 <
+1803: 916 917 982 <
+1804: 916 982 981 <
+1805: 917 918 983 <
+1806: 917 983 982 <
+1807: 918 919 984 <
+1808: 918 984 983 <
+1809: 919 920 985 <
+1810: 919 985 984 <
+1811: 920 921 986 <
+1812: 920 986 985 <
+1813: 921 922 987 <
+1814: 921 987 986 <
+1815: 922 923 988 <
+1816: 922 988 987 <
+1817: 923 924 989 <
+1818: 923 989 988 <
+1819: 924 925 990 <
+1820: 924 990 989 <
+1821: 925 926 991 <
+1822: 925 991 990 <
+1823: 926 927 992 <
+1824: 926 992 991 <
+1825: 927 928 993 <
+1826: 927 993 992 <
+1827: 928 929 994 <
+1828: 928 994 993 <
+1829: 929 930 995 <
+1830: 929 995 994 <
+1831: 930 931 996 <
+1832: 930 996 995 <
+1833: 931 932 997 <
+1834: 931 997 996 <
+1835: 932 933 998 <
+1836: 932 998 997 <
+1837: 933 934 999 <
+1838: 933 999 998 <
+1839: 934 935 1000 <
+1840: 934 1000 999 <
+1841: 935 936 1001 <
+1842: 935 1001 1000 <
+1843: 936 937 1002 <
+1844: 936 1002 1001 <
+1845: 937 938 1003 <
+1846: 937 1003 1002 <
+1847: 938 939 1004 <
+1848: 938 1004 1003 <
+1849: 939 940 1005 <
+1850: 939 1005 1004 <
+1851: 940 941 1006 <
+1852: 940 1006 1005 <
+1853: 941 942 1007 <
+1854: 941 1007 1006 <
+1855: 942 943 1008 <
+1856: 942 1008 1007 <
+1857: 943 944 1009 <
+1858: 943 1009 1008 <
+1859: 944 945 1010 <
+1860: 944 1010 1009 <
+1861: 945 946 1011 <
+1862: 945 1011 1010 <
+1863: 946 947 1012 <
+1864: 946 1012 1011 <
+1865: 947 948 1013 <
+1866: 947 1013 1012 <
+1867: 948 949 1014 <
+1868: 948 1014 1013 <
+1869: 949 950 1015 <
+1870: 949 1015 1014 <
+1871: 950 951 1016 <
+1872: 950 1016 1015 <
+1873: 951 952 1017 <
+1874: 951 1017 1016 <
+1875: 952 953 1018 <
+1876: 952 1018 1017 <
+1877: 953 954 1019 <
+1878: 953 1019 1018 <
+1879: 954 955 1020 <
+1880: 954 1020 1019 <
+1881: 955 956 1021 <
+1882: 955 1021 1020 <
+1883: 956 957 1022 <
+1884: 956 1022 1021 <
+1885: 957 958 1023 <
+1886: 957 1023 1022 <
+1887: 958 959 1024 <
+1888: 958 1024 1023 <
+1889: 959 960 1025 <
+1890: 959 1025 1024 <
+1891: 960 961 1026 <
+1892: 960 1026 1025 <
+1893: 961 962 1027 <
+1894: 961 1027 1026 <
+1895: 962 963 1028 <
+1896: 962 1028 1027 <
+1897: 963 964 1029 <
+1898: 963 1029 1028 <
+1899: 964 965 1030 <
+1900: 964 1030 1029 <
+1901: 965 966 1031 <
+1902: 965 1031 1030 <
+1903: 966 967 1032 <
+1904: 966 1032 1031 <
+1905: 967 968 1033 <
+1906: 967 1033 1032 <
+1907: 968 969 1034 <
+1908: 968 1034 1033 <
+1909: 969 970 1035 <
+1910: 969 1035 1034 <
+1911: 970 971 1036 <
+1912: 970 1036 1035 <
+1913: 971 972 1037 <
+1914: 971 1037 1036 <
+1915: 972 973 1038 <
+1916: 972 1038 1037 <
+1917: 973 974 1039 <
+1918: 973 1039 1038 <
+1919: 974 975 1040 <
+1920: 974 1040 1039 <
+1921: 976 977 1042 <
+1922: 976 1042 1041 <
+1923: 977 978 1043 <
+1924: 977 1043 1042 <
+1925: 978 979 1044 <
+1926: 978 1044 1043 <
+1927: 979 980 1045 <
+1928: 979 1045 1044 <
+1929: 980 981 1046 <
+1930: 980 1046 1045 <
+1931: 981 982 1047 <
+1932: 981 1047 1046 <
+1933: 982 983 1048 <
+1934: 982 1048 1047 <
+1935: 983 984 1049 <
+1936: 983 1049 1048 <
+1937: 984 985 1050 <
+1938: 984 1050 1049 <
+1939: 985 986 1051 <
+1940: 985 1051 1050 <
+1941: 986 987 1052 <
+1942: 986 1052 1051 <
+1943: 987 988 1053 <
+1944: 987 1053 1052 <
+1945: 988 989 1054 <
+1946: 988 1054 1053 <
+1947: 989 990 1055 <
+1948: 989 1055 1054 <
+1949: 990 991 1056 <
+1950: 990 1056 1055 <
+1951: 991 992 1057 <
+1952: 991 1057 1056 <
+1953: 992 993 1058 <
+1954: 992 1058 1057 <
+1955: 993 994 1059 <
+1956: 993 1059 1058 <
+1957: 994 995 1060 <
+1958: 994 1060 1059 <
+1959: 995 996 1061 <
+1960: 995 1061 1060 <
+1961: 996 997 1062 <
+1962: 996 1062 1061 <
+1963: 997 998 1063 <
+1964: 997 1063 1062 <
+1965: 998 999 1064 <
+1966: 998 1064 1063 <
+1967: 999 1000 1065 <
+1968: 999 1065 1064 <
+1969: 1000 1001 1066 <
+1970: 1000 1066 1065 <
+1971: 1001 1002 1067 <
+1972: 1001 1067 1066 <
+1973: 1002 1003 1068 <
+1974: 1002 1068 1067 <
+1975: 1003 1004 1069 <
+1976: 1003 1069 1068 <
+1977: 1004 1005 1070 <
+1978: 1004 1070 1069 <
+1979: 1005 1006 1071 <
+1980: 1005 1071 1070 <
+1981: 1006 1007 1072 <
+1982: 1006 1072 1071 <
+1983: 1007 1008 1073 <
+1984: 1007 1073 1072 <
+1985: 1008 1009 1074 <
+1986: 1008 1074 1073 <
+1987: 1009 1010 1075 <
+1988: 1009 1075 1074 <
+1989: 1010 1011 1076 <
+1990: 1010 1076 1075 <
+1991: 1011 1012 1077 <
+1992: 1011 1077 1076 <
+1993: 1012 1013 1078 <
+1994: 1012 1078 1077 <
+1995: 1013 1014 1079 <
+1996: 1013 1079 1078 <
+1997: 1014 1015 1080 <
+1998: 1014 1080 1079 <
+1999: 1015 1016 1081 <
+2000: 1015 1081 1080 <
+2001: 1016 1017 1082 <
+2002: 1016 1082 1081 <
+2003: 1017 1018 1083 <
+2004: 1017 1083 1082 <
+2005: 1018 1019 1084 <
+2006: 1018 1084 1083 <
+2007: 1019 1020 1085 <
+2008: 1019 1085 1084 <
+2009: 1020 1021 1086 <
+2010: 1020 1086 1085 <
+2011: 1021 1022 1087 <
+2012: 1021 1087 1086 <
+2013: 1022 1023 1088 <
+2014: 1022 1088 1087 <
+2015: 1023 1024 1089 <
+2016: 1023 1089 1088 <
+2017: 1024 1025 1090 <
+2018: 1024 1090 1089 <
+2019: 1025 1026 1091 <
+2020: 1025 1091 1090 <
+2021: 1026 1027 1092 <
+2022: 1026 1092 1091 <
+2023: 1027 1028 1093 <
+2024: 1027 1093 1092 <
+2025: 1028 1029 1094 <
+2026: 1028 1094 1093 <
+2027: 1029 1030 1095 <
+2028: 1029 1095 1094 <
+2029: 1030 1031 1096 <
+2030: 1030 1096 1095 <
+2031: 1031 1032 1097 <
+2032: 1031 1097 1096 <
+2033: 1032 1033 1098 <
+2034: 1032 1098 1097 <
+2035: 1033 1034 1099 <
+2036: 1033 1099 1098 <
+2037: 1034 1035 1100 <
+2038: 1034 1100 1099 <
+2039: 1035 1036 1101 <
+2040: 1035 1101 1100 <
+2041: 1036 1037 1102 <
+2042: 1036 1102 1101 <
+2043: 1037 1038 1103 <
+2044: 1037 1103 1102 <
+2045: 1038 1039 1104 <
+2046: 1038 1104 1103 <
+2047: 1039 1040 1105 <
+2048: 1039 1105 1104 <
+2049: 1041 1042 1107 <
+2050: 1041 1107 1106 <
+2051: 1042 1043 1108 <
+2052: 1042 1108 1107 <
+2053: 1043 1044 1109 <
+2054: 1043 1109 1108 <
+2055: 1044 1045 1110 <
+2056: 1044 1110 1109 <
+2057: 1045 1046 1111 <
+2058: 1045 1111 1110 <
+2059: 1046 1047 1112 <
+2060: 1046 1112 1111 <
+2061: 1047 1048 1113 <
+2062: 1047 1113 1112 <
+2063: 1048 1049 1114 <
+2064: 1048 1114 1113 <
+2065: 1049 1050 1115 <
+2066: 1049 1115 1114 <
+2067: 1050 1051 1116 <
+2068: 1050 1116 1115 <
+2069: 1051 1052 1117 <
+2070: 1051 1117 1116 <
+2071: 1052 1053 1118 <
+2072: 1052 1118 1117 <
+2073: 1053 1054 1119 <
+2074: 1053 1119 1118 <
+2075: 1054 1055 1120 <
+2076: 1054 1120 1119 <
+2077: 1055 1056 1121 <
+2078: 1055 1121 1120 <
+2079: 1056 1057 1122 <
+2080: 1056 1122 1121 <
+2081: 1057 1058 1123 <
+2082: 1057 1123 1122 <
+2083: 1058 1059 1124 <
+2084: 1058 1124 1123 <
+2085: 1059 1060 1125 <
+2086: 1059 1125 1124 <
+2087: 1060 1061 1126 <
+2088: 1060 1126 1125 <
+2089: 1061 1062 1127 <
+2090: 1061 1127 1126 <
+2091: 1062 1063 1128 <
+2092: 1062 1128 1127 <
+2093: 1063 1064 1129 <
+2094: 1063 1129 1128 <
+2095: 1064 1065 1130 <
+2096: 1064 1130 1129 <
+2097: 1065 1066 1131 <
+2098: 1065 1131 1130 <
+2099: 1066 1067 1132 <
+2100: 1066 1132 1131 <
+2101: 1067 1068 1133 <
+2102: 1067 1133 1132 <
+2103: 1068 1069 1134 <
+2104: 1068 1134 1133 <
+2105: 1069 1070 1135 <
+2106: 1069 1135 1134 <
+2107: 1070 1071 1136 <
+2108: 1070 1136 1135 <
+2109: 1071 1072 1137 <
+2110: 1071 1137 1136 <
+2111: 1072 1073 1138 <
+2112: 1072 1138 1137 <
+2113: 1073 1074 1139 <
+2114: 1073 1139 1138 <
+2115: 1074 1075 1140 <
+2116: 1074 1140 1139 <
+2117: 1075 1076 1141 <
+2118: 1075 1141 1140 <
+2119: 1076 1077 1142 <
+2120: 1076 1142 1141 <
+2121: 1077 1078 1143 <
+2122: 1077 1143 1142 <
+2123: 1078 1079 1144 <
+2124: 1078 1144 1143 <
+2125: 1079 1080 1145 <
+2126: 1079 1145 1144 <
+2127: 1080 1081 1146 <
+2128: 1080 1146 1145 <
+2129: 1081 1082 1147 <
+2130: 1081 1147 1146 <
+2131: 1082 1083 1148 <
+2132: 1082 1148 1147 <
+2133: 1083 1084 1149 <
+2134: 1083 1149 1148 <
+2135: 1084 1085 1150 <
+2136: 1084 1150 1149 <
+2137: 1085 1086 1151 <
+2138: 1085 1151 1150 <
+2139: 1086 1087 1152 <
+2140: 1086 1152 1151 <
+2141: 1087 1088 1153 <
+2142: 1087 1153 1152 <
+2143: 1088 1089 1154 <
+2144: 1088 1154 1153 <
+2145: 1089 1090 1155 <
+2146: 1089 1155 1154 <
+2147: 1090 1091 1156 <
+2148: 1090 1156 1155 <
+2149: 1091 1092 1157 <
+2150: 1091 1157 1156 <
+2151: 1092 1093 1158 <
+2152: 1092 1158 1157 <
+2153: 1093 1094 1159 <
+2154: 1093 1159 1158 <
+2155: 1094 1095 1160 <
+2156: 1094 1160 1159 <
+2157: 1095 1096 1161 <
+2158: 1095 1161 1160 <
+2159: 1096 1097 1162 <
+2160: 1096 1162 1161 <
+2161: 1097 1098 1163 <
+2162: 1097 1163 1162 <
+2163: 1098 1099 1164 <
+2164: 1098 1164 1163 <
+2165: 1099 1100 1165 <
+2166: 1099 1165 1164 <
+2167: 1100 1101 1166 <
+2168: 1100 1166 1165 <
+2169: 1101 1102 1167 <
+2170: 1101 1167 1166 <
+2171: 1102 1103 1168 <
+2172: 1102 1168 1167 <
+2173: 1103 1104 1169 <
+2174: 1103 1169 1168 <
+2175: 1104 1105 1170 <
+2176: 1104 1170 1169 <
+2177: 1106 1107 1172 <
+2178: 1106 1172 1171 <
+2179: 1107 1108 1173 <
+2180: 1107 1173 1172 <
+2181: 1108 1109 1174 <
+2182: 1108 1174 1173 <
+2183: 1109 1110 1175 <
+2184: 1109 1175 1174 <
+2185: 1110 1111 1176 <
+2186: 1110 1176 1175 <
+2187: 1111 1112 1177 <
+2188: 1111 1177 1176 <
+2189: 1112 1113 1178 <
+2190: 1112 1178 1177 <
+2191: 1113 1114 1179 <
+2192: 1113 1179 1178 <
+2193: 1114 1115 1180 <
+2194: 1114 1180 1179 <
+2195: 1115 1116 1181 <
+2196: 1115 1181 1180 <
+2197: 1116 1117 1182 <
+2198: 1116 1182 1181 <
+2199: 1117 1118 1183 <
+2200: 1117 1183 1182 <
+2201: 1118 1119 1184 <
+2202: 1118 1184 1183 <
+2203: 1119 1120 1185 <
+2204: 1119 1185 1184 <
+2205: 1120 1121 1186 <
+2206: 1120 1186 1185 <
+2207: 1121 1122 1187 <
+2208: 1121 1187 1186 <
+2209: 1122 1123 1188 <
+2210: 1122 1188 1187 <
+2211: 1123 1124 1189 <
+2212: 1123 1189 1188 <
+2213: 1124 1125 1190 <
+2214: 1124 1190 1189 <
+2215: 1125 1126 1191 <
+2216: 1125 1191 1190 <
+2217: 1126 1127 1192 <
+2218: 1126 1192 1191 <
+2219: 1127 1128 1193 <
+2220: 1127 1193 1192 <
+2221: 1128 1129 1194 <
+2222: 1128 1194 1193 <
+2223: 1129 1130 1195 <
+2224: 1129 1195 1194 <
+2225: 1130 1131 1196 <
+2226: 1130 1196 1195 <
+2227: 1131 1132 1197 <
+2228: 1131 1197 1196 <
+2229: 1132 1133 1198 <
+2230: 1132 1198 1197 <
+2231: 1133 1134 1199 <
+2232: 1133 1199 1198 <
+2233: 1134 1135 1200 <
+2234: 1134 1200 1199 <
+2235: 1135 1136 1201 <
+2236: 1135 1201 1200 <
+2237: 1136 1137 1202 <
+2238: 1136 1202 1201 <
+2239: 1137 1138 1203 <
+2240: 1137 1203 1202 <
+2241: 1138 1139 1204 <
+2242: 1138 1204 1203 <
+2243: 1139 1140 1205 <
+2244: 1139 1205 1204 <
+2245: 1140 1141 1206 <
+2246: 1140 1206 1205 <
+2247: 1141 1142 1207 <
+2248: 1141 1207 1206 <
+2249: 1142 1143 1208 <
+2250: 1142 1208 1207 <
+2251: 1143 1144 1209 <
+2252: 1143 1209 1208 <
+2253: 1144 1145 1210 <
+2254: 1144 1210 1209 <
+2255: 1145 1146 1211 <
+2256: 1145 1211 1210 <
+2257: 1146 1147 1212 <
+2258: 1146 1212 1211 <
+2259: 1147 1148 1213 <
+2260: 1147 1213 1212 <
+2261: 1148 1149 1214 <
+2262: 1148 1214 1213 <
+2263: 1149 1150 1215 <
+2264: 1149 1215 1214 <
+2265: 1150 1151 1216 <
+2266: 1150 1216 1215 <
+2267: 1151 1152 1217 <
+2268: 1151 1217 1216 <
+2269: 1152 1153 1218 <
+2270: 1152 1218 1217 <
+2271: 1153 1154 1219 <
+2272: 1153 1219 1218 <
+2273: 1154 1155 1220 <
+2274: 1154 1220 1219 <
+2275: 1155 1156 1221 <
+2276: 1155 1221 1220 <
+2277: 1156 1157 1222 <
+2278: 1156 1222 1221 <
+2279: 1157 1158 1223 <
+2280: 1157 1223 1222 <
+2281: 1158 1159 1224 <
+2282: 1158 1224 1223 <
+2283: 1159 1160 1225 <
+2284: 1159 1225 1224 <
+2285: 1160 1161 1226 <
+2286: 1160 1226 1225 <
+2287: 1161 1162 1227 <
+2288: 1161 1227 1226 <
+2289: 1162 1163 1228 <
+2290: 1162 1228 1227 <
+2291: 1163 1164 1229 <
+2292: 1163 1229 1228 <
+2293: 1164 1165 1230 <
+2294: 1164 1230 1229 <
+2295: 1165 1166 1231 <
+2296: 1165 1231 1230 <
+2297: 1166 1167 1232 <
+2298: 1166 1232 1231 <
+2299: 1167 1168 1233 <
+2300: 1167 1233 1232 <
+2301: 1168 1169 1234 <
+2302: 1168 1234 1233 <
+2303: 1169 1170 1235 <
+2304: 1169 1235 1234 <
+2305: 1171 1172 1237 <
+2306: 1171 1237 1236 <
+2307: 1172 1173 1238 <
+2308: 1172 1238 1237 <
+2309: 1173 1174 1239 <
+2310: 1173 1239 1238 <
+2311: 1174 1175 1240 <
+2312: 1174 1240 1239 <
+2313: 1175 1176 1241 <
+2314: 1175 1241 1240 <
+2315: 1176 1177 1242 <
+2316: 1176 1242 1241 <
+2317: 1177 1178 1243 <
+2318: 1177 1243 1242 <
+2319: 1178 1179 1244 <
+2320: 1178 1244 1243 <
+2321: 1179 1180 1245 <
+2322: 1179 1245 1244 <
+2323: 1180 1181 1246 <
+2324: 1180 1246 1245 <
+2325: 1181 1182 1247 <
+2326: 1181 1247 1246 <
+2327: 1182 1183 1248 <
+2328: 1182 1248 1247 <
+2329: 1183 1184 1249 <
+2330: 1183 1249 1248 <
+2331: 1184 1185 1250 <
+2332: 1184 1250 1249 <
+2333: 1185 1186 1251 <
+2334: 1185 1251 1250 <
+2335: 1186 1187 1252 <
+2336: 1186 1252 1251 <
+2337: 1187 1188 1253 <
+2338: 1187 1253 1252 <
+2339: 1188 1189 1254 <
+2340: 1188 1254 1253 <
+2341: 1189 1190 1255 <
+2342: 1189 1255 1254 <
+2343: 1190 1191 1256 <
+2344: 1190 1256 1255 <
+2345: 1191 1192 1257 <
+2346: 1191 1257 1256 <
+2347: 1192 1193 1258 <
+2348: 1192 1258 1257 <
+2349: 1193 1194 1259 <
+2350: 1193 1259 1258 <
+2351: 1194 1195 1260 <
+2352: 1194 1260 1259 <
+2353: 1195 1196 1261 <
+2354: 1195 1261 1260 <
+2355: 1196 1197 1262 <
+2356: 1196 1262 1261 <
+2357: 1197 1198 1263 <
+2358: 1197 1263 1262 <
+2359: 1198 1199 1264 <
+2360: 1198 1264 1263 <
+2361: 1199 1200 1265 <
+2362: 1199 1265 1264 <
+2363: 1200 1201 1266 <
+2364: 1200 1266 1265 <
+2365: 1201 1202 1267 <
+2366: 1201 1267 1266 <
+2367: 1202 1203 1268 <
+2368: 1202 1268 1267 <
+2369: 1203 1204 1269 <
+2370: 1203 1269 1268 <
+2371: 1204 1205 1270 <
+2372: 1204 1270 1269 <
+2373: 1205 1206 1271 <
+2374: 1205 1271 1270 <
+2375: 1206 1207 1272 <
+2376: 1206 1272 1271 <
+2377: 1207 1208 1273 <
+2378: 1207 1273 1272 <
+2379: 1208 1209 1274 <
+2380: 1208 1274 1273 <
+2381: 1209 1210 1275 <
+2382: 1209 1275 1274 <
+2383: 1210 1211 1276 <
+2384: 1210 1276 1275 <
+2385: 1211 1212 1277 <
+2386: 1211 1277 1276 <
+2387: 1212 1213 1278 <
+2388: 1212 1278 1277 <
+2389: 1213 1214 1279 <
+2390: 1213 1279 1278 <
+2391: 1214 1215 1280 <
+2392: 1214 1280 1279 <
+2393: 1215 1216 1281 <
+2394: 1215 1281 1280 <
+2395: 1216 1217 1282 <
+2396: 1216 1282 1281 <
+2397: 1217 1218 1283 <
+2398: 1217 1283 1282 <
+2399: 1218 1219 1284 <
+2400: 1218 1284 1283 <
+2401: 1219 1220 1285 <
+2402: 1219 1285 1284 <
+2403: 1220 1221 1286 <
+2404: 1220 1286 1285 <
+2405: 1221 1222 1287 <
+2406: 1221 1287 1286 <
+2407: 1222 1223 1288 <
+2408: 1222 1288 1287 <
+2409: 1223 1224 1289 <
+2410: 1223 1289 1288 <
+2411: 1224 1225 1290 <
+2412: 1224 1290 1289 <
+2413: 1225 1226 1291 <
+2414: 1225 1291 1290 <
+2415: 1226 1227 1292 <
+2416: 1226 1292 1291 <
+2417: 1227 1228 1293 <
+2418: 1227 1293 1292 <
+2419: 1228 1229 1294 <
+2420: 1228 1294 1293 <
+2421: 1229 1230 1295 <
+2422: 1229 1295 1294 <
+2423: 1230 1231 1296 <
+2424: 1230 1296 1295 <
+2425: 1231 1232 1297 <
+2426: 1231 1297 1296 <
+2427: 1232 1233 1298 <
+2428: 1232 1298 1297 <
+2429: 1233 1234 1299 <
+2430: 1233 1299 1298 <
+2431: 1234 1235 1300 <
+2432: 1234 1300 1299 <
+2433: 1236 1237 1302 <
+2434: 1236 1302 1301 <
+2435: 1237 1238 1303 <
+2436: 1237 1303 1302 <
+2437: 1238 1239 1304 <
+2438: 1238 1304 1303 <
+2439: 1239 1240 1305 <
+2440: 1239 1305 1304 <
+2441: 1240 1241 1306 <
+2442: 1240 1306 1305 <
+2443: 1241 1242 1307 <
+2444: 1241 1307 1306 <
+2445: 1242 1243 1308 <
+2446: 1242 1308 1307 <
+2447: 1243 1244 1309 <
+2448: 1243 1309 1308 <
+2449: 1244 1245 1310 <
+2450: 1244 1310 1309 <
+2451: 1245 1246 1311 <
+2452: 1245 1311 1310 <
+2453: 1246 1247 1312 <
+2454: 1246 1312 1311 <
+2455: 1247 1248 1313 <
+2456: 1247 1313 1312 <
+2457: 1248 1249 1314 <
+2458: 1248 1314 1313 <
+2459: 1249 1250 1315 <
+2460: 1249 1315 1314 <
+2461: 1250 1251 1316 <
+2462: 1250 1316 1315 <
+2463: 1251 1252 1317 <
+2464: 1251 1317 1316 <
+2465: 1252 1253 1318 <
+2466: 1252 1318 1317 <
+2467: 1253 1254 1319 <
+2468: 1253 1319 1318 <
+2469: 1254 1255 1320 <
+2470: 1254 1320 1319 <
+2471: 1255 1256 1321 <
+2472: 1255 1321 1320 <
+2473: 1256 1257 1322 <
+2474: 1256 1322 1321 <
+2475: 1257 1258 1323 <
+2476: 1257 1323 1322 <
+2477: 1258 1259 1324 <
+2478: 1258 1324 1323 <
+2479: 1259 1260 1325 <
+2480: 1259 1325 1324 <
+2481: 1260 1261 1326 <
+2482: 1260 1326 1325 <
+2483: 1261 1262 1327 <
+2484: 1261 1327 1326 <
+2485: 1262 1263 1328 <
+2486: 1262 1328 1327 <
+2487: 1263 1264 1329 <
+2488: 1263 1329 1328 <
+2489: 1264 1265 1330 <
+2490: 1264 1330 1329 <
+2491: 1265 1266 1331 <
+2492: 1265 1331 1330 <
+2493: 1266 1267 1332 <
+2494: 1266 1332 1331 <
+2495: 1267 1268 1333 <
+2496: 1267 1333 1332 <
+2497: 1268 1269 1334 <
+2498: 1268 1334 1333 <
+2499: 1269 1270 1335 <
+2500: 1269 1335 1334 <
+2501: 1270 1271 1336 <
+2502: 1270 1336 1335 <
+2503: 1271 1272 1337 <
+2504: 1271 1337 1336 <
+2505: 1272 1273 1338 <
+2506: 1272 1338 1337 <
+2507: 1273 1274 1339 <
+2508: 1273 1339 1338 <
+2509: 1274 1275 1340 <
+2510: 1274 1340 1339 <
+2511: 1275 1276 1341 <
+2512: 1275 1341 1340 <
+2513: 1276 1277 1342 <
+2514: 1276 1342 1341 <
+2515: 1277 1278 1343 <
+2516: 1277 1343 1342 <
+2517: 1278 1279 1344 <
+2518: 1278 1344 1343 <
+2519: 1279 1280 1345 <
+2520: 1279 1345 1344 <
+2521: 1280 1281 1346 <
+2522: 1280 1346 1345 <
+2523: 1281 1282 1347 <
+2524: 1281 1347 1346 <
+2525: 1282 1283 1348 <
+2526: 1282 1348 1347 <
+2527: 1283 1284 1349 <
+2528: 1283 1349 1348 <
+2529: 1284 1285 1350 <
+2530: 1284 1350 1349 <
+2531: 1285 1286 1351 <
+2532: 1285 1351 1350 <
+2533: 1286 1287 1352 <
+2534: 1286 1352 1351 <
+2535: 1287 1288 1353 <
+2536: 1287 1353 1352 <
+2537: 1288 1289 1354 <
+2538: 1288 1354 1353 <
+2539: 1289 1290 1355 <
+2540: 1289 1355 1354 <
+2541: 1290 1291 1356 <
+2542: 1290 1356 1355 <
+2543: 1291 1292 1357 <
+2544: 1291 1357 1356 <
+2545: 1292 1293 1358 <
+2546: 1292 1358 1357 <
+2547: 1293 1294 1359 <
+2548: 1293 1359 1358 <
+2549: 1294 1295 1360 <
+2550: 1294 1360 1359 <
+2551: 1295 1296 1361 <
+2552: 1295 1361 1360 <
+2553: 1296 1297 1362 <
+2554: 1296 1362 1361 <
+2555: 1297 1298 1363 <
+2556: 1297 1363 1362 <
+2557: 1298 1299 1364 <
+2558: 1298 1364 1363 <
+2559: 1299 1300 1365 <
+2560: 1299 1365 1364 <
+2561: 1301 1302 1367 <
+2562: 1301 1367 1366 <
+2563: 1302 1303 1368 <
+2564: 1302 1368 1367 <
+2565: 1303 1304 1369 <
+2566: 1303 1369 1368 <
+2567: 1304 1305 1370 <
+2568: 1304 1370 1369 <
+2569: 1305 1306 1371 <
+2570: 1305 1371 1370 <
+2571: 1306 1307 1372 <
+2572: 1306 1372 1371 <
+2573: 1307 1308 1373 <
+2574: 1307 1373 1372 <
+2575: 1308 1309 1374 <
+2576: 1308 1374 1373 <
+2577: 1309 1310 1375 <
+2578: 1309 1375 1374 <
+2579: 1310 1311 1376 <
+2580: 1310 1376 1375 <
+2581: 1311 1312 1377 <
+2582: 1311 1377 1376 <
+2583: 1312 1313 1378 <
+2584: 1312 1378 1377 <
+2585: 1313 1314 1379 <
+2586: 1313 1379 1378 <
+2587: 1314 1315 1380 <
+2588: 1314 1380 1379 <
+2589: 1315 1316 1381 <
+2590: 1315 1381 1380 <
+2591: 1316 1317 1382 <
+2592: 1316 1382 1381 <
+2593: 1317 1318 1383 <
+2594: 1317 1383 1382 <
+2595: 1318 1319 1384 <
+2596: 1318 1384 1383 <
+2597: 1319 1320 1385 <
+2598: 1319 1385 1384 <
+2599: 1320 1321 1386 <
+2600: 1320 1386 1385 <
+2601: 1321 1322 1387 <
+2602: 1321 1387 1386 <
+2603: 1322 1323 1388 <
+2604: 1322 1388 1387 <
+2605: 1323 1324 1389 <
+2606: 1323 1389 1388 <
+2607: 1324 1325 1390 <
+2608: 1324 1390 1389 <
+2609: 1325 1326 1391 <
+2610: 1325 1391 1390 <
+2611: 1326 1327 1392 <
+2612: 1326 1392 1391 <
+2613: 1327 1328 1393 <
+2614: 1327 1393 1392 <
+2615: 1328 1329 1394 <
+2616: 1328 1394 1393 <
+2617: 1329 1330 1395 <
+2618: 1329 1395 1394 <
+2619: 1330 1331 1396 <
+2620: 1330 1396 1395 <
+2621: 1331 1332 1397 <
+2622: 1331 1397 1396 <
+2623: 1332 1333 1398 <
+2624: 1332 1398 1397 <
+2625: 1333 1334 1399 <
+2626: 1333 1399 1398 <
+2627: 1334 1335 1400 <
+2628: 1334 1400 1399 <
+2629: 1335 1336 1401 <
+2630: 1335 1401 1400 <
+2631: 1336 1337 1402 <
+2632: 1336 1402 1401 <
+2633: 1337 1338 1403 <
+2634: 1337 1403 1402 <
+2635: 1338 1339 1404 <
+2636: 1338 1404 1403 <
+2637: 1339 1340 1405 <
+2638: 1339 1405 1404 <
+2639: 1340 1341 1406 <
+2640: 1340 1406 1405 <
+2641: 1341 1342 1407 <
+2642: 1341 1407 1406 <
+2643: 1342 1343 1408 <
+2644: 1342 1408 1407 <
+2645: 1343 1344 1409 <
+2646: 1343 1409 1408 <
+2647: 1344 1345 1410 <
+2648: 1344 1410 1409 <
+2649: 1345 1346 1411 <
+2650: 1345 1411 1410 <
+2651: 1346 1347 1412 <
+2652: 1346 1412 1411 <
+2653: 1347 1348 1413 <
+2654: 1347 1413 1412 <
+2655: 1348 1349 1414 <
+2656: 1348 1414 1413 <
+2657: 1349 1350 1415 <
+2658: 1349 1415 1414 <
+2659: 1350 1351 1416 <
+2660: 1350 1416 1415 <
+2661: 1351 1352 1417 <
+2662: 1351 1417 1416 <
+2663: 1352 1353 1418 <
+2664: 1352 1418 1417 <
+2665: 1353 1354 1419 <
+2666: 1353 1419 1418 <
+2667: 1354 1355 1420 <
+2668: 1354 1420 1419 <
+2669: 1355 1356 1421 <
+2670: 1355 1421 1420 <
+2671: 1356 1357 1422 <
+2672: 1356 1422 1421 <
+2673: 1357 1358 1423 <
+2674: 1357 1423 1422 <
+2675: 1358 1359 1424 <
+2676: 1358 1424 1423 <
+2677: 1359 1360 1425 <
+2678: 1359 1425 1424 <
+2679: 1360 1361 1426 <
+2680: 1360 1426 1425 <
+2681: 1361 1362 1427 <
+2682: 1361 1427 1426 <
+2683: 1362 1363 1428 <
+2684: 1362 1428 1427 <
+2685: 1363 1364 1429 <
+2686: 1363 1429 1428 <
+2687: 1364 1365 1430 <
+2688: 1364 1430 1429 <
+2689: 1366 1367 1432 <
+2690: 1366 1432 1431 <
+2691: 1367 1368 1433 <
+2692: 1367 1433 1432 <
+2693: 1368 1369 1434 <
+2694: 1368 1434 1433 <
+2695: 1369 1370 1435 <
+2696: 1369 1435 1434 <
+2697: 1370 1371 1436 <
+2698: 1370 1436 1435 <
+2699: 1371 1372 1437 <
+2700: 1371 1437 1436 <
+2701: 1372 1373 1438 <
+2702: 1372 1438 1437 <
+2703: 1373 1374 1439 <
+2704: 1373 1439 1438 <
+2705: 1374 1375 1440 <
+2706: 1374 1440 1439 <
+2707: 1375 1376 1441 <
+2708: 1375 1441 1440 <
+2709: 1376 1377 1442 <
+2710: 1376 1442 1441 <
+2711: 1377 1378 1443 <
+2712: 1377 1443 1442 <
+2713: 1378 1379 1444 <
+2714: 1378 1444 1443 <
+2715: 1379 1380 1445 <
+2716: 1379 1445 1444 <
+2717: 1380 1381 1446 <
+2718: 1380 1446 1445 <
+2719: 1381 1382 1447 <
+2720: 1381 1447 1446 <
+2721: 1382 1383 1448 <
+2722: 1382 1448 1447 <
+2723: 1383 1384 1449 <
+2724: 1383 1449 1448 <
+2725: 1384 1385 1450 <
+2726: 1384 1450 1449 <
+2727: 1385 1386 1451 <
+2728: 1385 1451 1450 <
+2729: 1386 1387 1452 <
+2730: 1386 1452 1451 <
+2731: 1387 1388 1453 <
+2732: 1387 1453 1452 <
+2733: 1388 1389 1454 <
+2734: 1388 1454 1453 <
+2735: 1389 1390 1455 <
+2736: 1389 1455 1454 <
+2737: 1390 1391 1456 <
+2738: 1390 1456 1455 <
+2739: 1391 1392 1457 <
+2740: 1391 1457 1456 <
+2741: 1392 1393 1458 <
+2742: 1392 1458 1457 <
+2743: 1393 1394 1459 <
+2744: 1393 1459 1458 <
+2745: 1394 1395 1460 <
+2746: 1394 1460 1459 <
+2747: 1395 1396 1461 <
+2748: 1395 1461 1460 <
+2749: 1396 1397 1462 <
+2750: 1396 1462 1461 <
+2751: 1397 1398 1463 <
+2752: 1397 1463 1462 <
+2753: 1398 1399 1464 <
+2754: 1398 1464 1463 <
+2755: 1399 1400 1465 <
+2756: 1399 1465 1464 <
+2757: 1400 1401 1466 <
+2758: 1400 1466 1465 <
+2759: 1401 1402 1467 <
+2760: 1401 1467 1466 <
+2761: 1402 1403 1468 <
+2762: 1402 1468 1467 <
+2763: 1403 1404 1469 <
+2764: 1403 1469 1468 <
+2765: 1404 1405 1470 <
+2766: 1404 1470 1469 <
+2767: 1405 1406 1471 <
+2768: 1405 1471 1470 <
+2769: 1406 1407 1472 <
+2770: 1406 1472 1471 <
+2771: 1407 1408 1473 <
+2772: 1407 1473 1472 <
+2773: 1408 1409 1474 <
+2774: 1408 1474 1473 <
+2775: 1409 1410 1475 <
+2776: 1409 1475 1474 <
+2777: 1410 1411 1476 <
+2778: 1410 1476 1475 <
+2779: 1411 1412 1477 <
+2780: 1411 1477 1476 <
+2781: 1412 1413 1478 <
+2782: 1412 1478 1477 <
+2783: 1413 1414 1479 <
+2784: 1413 1479 1478 <
+2785: 1414 1415 1480 <
+2786: 1414 1480 1479 <
+2787: 1415 1416 1481 <
+2788: 1415 1481 1480 <
+2789: 1416 1417 1482 <
+2790: 1416 1482 1481 <
+2791: 1417 1418 1483 <
+2792: 1417 1483 1482 <
+2793: 1418 1419 1484 <
+2794: 1418 1484 1483 <
+2795: 1419 1420 1485 <
+2796: 1419 1485 1484 <
+2797: 1420 1421 1486 <
+2798: 1420 1486 1485 <
+2799: 1421 1422 1487 <
+2800: 1421 1487 1486 <
+2801: 1422 1423 1488 <
+2802: 1422 1488 1487 <
+2803: 1423 1424 1489 <
+2804: 1423 1489 1488 <
+2805: 1424 1425 1490 <
+2806: 1424 1490 1489 <
+2807: 1425 1426 1491 <
+2808: 1425 1491 1490 <
+2809: 1426 1427 1492 <
+2810: 1426 1492 1491 <
+2811: 1427 1428 1493 <
+2812: 1427 1493 1492 <
+2813: 1428 1429 1494 <
+2814: 1428 1494 1493 <
+2815: 1429 1430 1495 <
+2816: 1429 1495 1494 <
+2817: 1431 1432 1497 <
+2818: 1431 1497 1496 <
+2819: 1432 1433 1498 <
+2820: 1432 1498 1497 <
+2821: 1433 1434 1499 <
+2822: 1433 1499 1498 <
+2823: 1434 1435 1500 <
+2824: 1434 1500 1499 <
+2825: 1435 1436 1501 <
+2826: 1435 1501 1500 <
+2827: 1436 1437 1502 <
+2828: 1436 1502 1501 <
+2829: 1437 1438 1503 <
+2830: 1437 1503 1502 <
+2831: 1438 1439 1504 <
+2832: 1438 1504 1503 <
+2833: 1439 1440 1505 <
+2834: 1439 1505 1504 <
+2835: 1440 1441 1506 <
+2836: 1440 1506 1505 <
+2837: 1441 1442 1507 <
+2838: 1441 1507 1506 <
+2839: 1442 1443 1508 <
+2840: 1442 1508 1507 <
+2841: 1443 1444 1509 <
+2842: 1443 1509 1508 <
+2843: 1444 1445 1510 <
+2844: 1444 1510 1509 <
+2845: 1445 1446 1511 <
+2846: 1445 1511 1510 <
+2847: 1446 1447 1512 <
+2848: 1446 1512 1511 <
+2849: 1447 1448 1513 <
+2850: 1447 1513 1512 <
+2851: 1448 1449 1514 <
+2852: 1448 1514 1513 <
+2853: 1449 1450 1515 <
+2854: 1449 1515 1514 <
+2855: 1450 1451 1516 <
+2856: 1450 1516 1515 <
+2857: 1451 1452 1517 <
+2858: 1451 1517 1516 <
+2859: 1452 1453 1518 <
+2860: 1452 1518 1517 <
+2861: 1453 1454 1519 <
+2862: 1453 1519 1518 <
+2863: 1454 1455 1520 <
+2864: 1454 1520 1519 <
+2865: 1455 1456 1521 <
+2866: 1455 1521 1520 <
+2867: 1456 1457 1522 <
+2868: 1456 1522 1521 <
+2869: 1457 1458 1523 <
+2870: 1457 1523 1522 <
+2871: 1458 1459 1524 <
+2872: 1458 1524 1523 <
+2873: 1459 1460 1525 <
+2874: 1459 1525 1524 <
+2875: 1460 1461 1526 <
+2876: 1460 1526 1525 <
+2877: 1461 1462 1527 <
+2878: 1461 1527 1526 <
+2879: 1462 1463 1528 <
+2880: 1462 1528 1527 <
+2881: 1463 1464 1529 <
+2882: 1463 1529 1528 <
+2883: 1464 1465 1530 <
+2884: 1464 1530 1529 <
+2885: 1465 1466 1531 <
+2886: 1465 1531 1530 <
+2887: 1466 1467 1532 <
+2888: 1466 1532 1531 <
+2889: 1467 1468 1533 <
+2890: 1467 1533 1532 <
+2891: 1468 1469 1534 <
+2892: 1468 1534 1533 <
+2893: 1469 1470 1535 <
+2894: 1469 1535 1534 <
+2895: 1470 1471 1536 <
+2896: 1470 1536 1535 <
+2897: 1471 1472 1537 <
+2898: 1471 1537 1536 <
+2899: 1472 1473 1538 <
+2900: 1472 1538 1537 <
+2901: 1473 1474 1539 <
+2902: 1473 1539 1538 <
+2903: 1474 1475 1540 <
+2904: 1474 1540 1539 <
+2905: 1475 1476 1541 <
+2906: 1475 1541 1540 <
+2907: 1476 1477 1542 <
+2908: 1476 1542 1541 <
+2909: 1477 1478 1543 <
+2910: 1477 1543 1542 <
+2911: 1478 1479 1544 <
+2912: 1478 1544 1543 <
+2913: 1479 1480 1545 <
+2914: 1479 1545 1544 <
+2915: 1480 1481 1546 <
+2916: 1480 1546 1545 <
+2917: 1481 1482 1547 <
+2918: 1481 1547 1546 <
+2919: 1482 1483 1548 <
+2920: 1482 1548 1547 <
+2921: 1483 1484 1549 <
+2922: 1483 1549 1548 <
+2923: 1484 1485 1550 <
+2924: 1484 1550 1549 <
+2925: 1485 1486 1551 <
+2926: 1485 1551 1550 <
+2927: 1486 1487 1552 <
+2928: 1486 1552 1551 <
+2929: 1487 1488 1553 <
+2930: 1487 1553 1552 <
+2931: 1488 1489 1554 <
+2932: 1488 1554 1553 <
+2933: 1489 1490 1555 <
+2934: 1489 1555 1554 <
+2935: 1490 1491 1556 <
+2936: 1490 1556 1555 <
+2937: 1491 1492 1557 <
+2938: 1491 1557 1556 <
+2939: 1492 1493 1558 <
+2940: 1492 1558 1557 <
+2941: 1493 1494 1559 <
+2942: 1493 1559 1558 <
+2943: 1494 1495 1560 <
+2944: 1494 1560 1559 <
+2945: 1496 1497 1562 <
+2946: 1496 1562 1561 <
+2947: 1497 1498 1563 <
+2948: 1497 1563 1562 <
+2949: 1498 1499 1564 <
+2950: 1498 1564 1563 <
+2951: 1499 1500 1565 <
+2952: 1499 1565 1564 <
+2953: 1500 1501 1566 <
+2954: 1500 1566 1565 <
+2955: 1501 1502 1567 <
+2956: 1501 1567 1566 <
+2957: 1502 1503 1568 <
+2958: 1502 1568 1567 <
+2959: 1503 1504 1569 <
+2960: 1503 1569 1568 <
+2961: 1504 1505 1570 <
+2962: 1504 1570 1569 <
+2963: 1505 1506 1571 <
+2964: 1505 1571 1570 <
+2965: 1506 1507 1572 <
+2966: 1506 1572 1571 <
+2967: 1507 1508 1573 <
+2968: 1507 1573 1572 <
+2969: 1508 1509 1574 <
+2970: 1508 1574 1573 <
+2971: 1509 1510 1575 <
+2972: 1509 1575 1574 <
+2973: 1510 1511 1576 <
+2974: 1510 1576 1575 <
+2975: 1511 1512 1577 <
+2976: 1511 1577 1576 <
+2977: 1512 1513 1578 <
+2978: 1512 1578 1577 <
+2979: 1513 1514 1579 <
+2980: 1513 1579 1578 <
+2981: 1514 1515 1580 <
+2982: 1514 1580 1579 <
+2983: 1515 1516 1581 <
+2984: 1515 1581 1580 <
+2985: 1516 1517 1582 <
+2986: 1516 1582 1581 <
+2987: 1517 1518 1583 <
+2988: 1517 1583 1582 <
+2989: 1518 1519 1584 <
+2990: 1518 1584 1583 <
+2991: 1519 1520 1585 <
+2992: 1519 1585 1584 <
+2993: 1520 1521 1586 <
+2994: 1520 1586 1585 <
+2995: 1521 1522 1587 <
+2996: 1521 1587 1586 <
+2997: 1522 1523 1588 <
+2998: 1522 1588 1587 <
+2999: 1523 1524 1589 <
+3000: 1523 1589 1588 <
+3001: 1524 1525 1590 <
+3002: 1524 1590 1589 <
+3003: 1525 1526 1591 <
+3004: 1525 1591 1590 <
+3005: 1526 1527 1592 <
+3006: 1526 1592 1591 <
+3007: 1527 1528 1593 <
+3008: 1527 1593 1592 <
+3009: 1528 1529 1594 <
+3010: 1528 1594 1593 <
+3011: 1529 1530 1595 <
+3012: 1529 1595 1594 <
+3013: 1530 1531 1596 <
+3014: 1530 1596 1595 <
+3015: 1531 1532 1597 <
+3016: 1531 1597 1596 <
+3017: 1532 1533 1598 <
+3018: 1532 1598 1597 <
+3019: 1533 1534 1599 <
+3020: 1533 1599 1598 <
+3021: 1534 1535 1600 <
+3022: 1534 1600 1599 <
+3023: 1535 1536 1601 <
+3024: 1535 1601 1600 <
+3025: 1536 1537 1602 <
+3026: 1536 1602 1601 <
+3027: 1537 1538 1603 <
+3028: 1537 1603 1602 <
+3029: 1538 1539 1604 <
+3030: 1538 1604 1603 <
+3031: 1539 1540 1605 <
+3032: 1539 1605 1604 <
+3033: 1540 1541 1606 <
+3034: 1540 1606 1605 <
+3035: 1541 1542 1607 <
+3036: 1541 1607 1606 <
+3037: 1542 1543 1608 <
+3038: 1542 1608 1607 <
+3039: 1543 1544 1609 <
+3040: 1543 1609 1608 <
+3041: 1544 1545 1610 <
+3042: 1544 1610 1609 <
+3043: 1545 1546 1611 <
+3044: 1545 1611 1610 <
+3045: 1546 1547 1612 <
+3046: 1546 1612 1611 <
+3047: 1547 1548 1613 <
+3048: 1547 1613 1612 <
+3049: 1548 1549 1614 <
+3050: 1548 1614 1613 <
+3051: 1549 1550 1615 <
+3052: 1549 1615 1614 <
+3053: 1550 1551 1616 <
+3054: 1550 1616 1615 <
+3055: 1551 1552 1617 <
+3056: 1551 1617 1616 <
+3057: 1552 1553 1618 <
+3058: 1552 1618 1617 <
+3059: 1553 1554 1619 <
+3060: 1553 1619 1618 <
+3061: 1554 1555 1620 <
+3062: 1554 1620 1619 <
+3063: 1555 1556 1621 <
+3064: 1555 1621 1620 <
+3065: 1556 1557 1622 <
+3066: 1556 1622 1621 <
+3067: 1557 1558 1623 <
+3068: 1557 1623 1622 <
+3069: 1558 1559 1624 <
+3070: 1558 1624 1623 <
+3071: 1559 1560 1625 <
+3072: 1559 1625 1624 <
+3073: 1561 1562 1627 <
+3074: 1561 1627 1626 <
+3075: 1562 1563 1628 <
+3076: 1562 1628 1627 <
+3077: 1563 1564 1629 <
+3078: 1563 1629 1628 <
+3079: 1564 1565 1630 <
+3080: 1564 1630 1629 <
+3081: 1565 1566 1631 <
+3082: 1565 1631 1630 <
+3083: 1566 1567 1632 <
+3084: 1566 1632 1631 <
+3085: 1567 1568 1633 <
+3086: 1567 1633 1632 <
+3087: 1568 1569 1634 <
+3088: 1568 1634 1633 <
+3089: 1569 1570 1635 <
+3090: 1569 1635 1634 <
+3091: 1570 1571 1636 <
+3092: 1570 1636 1635 <
+3093: 1571 1572 1637 <
+3094: 1571 1637 1636 <
+3095: 1572 1573 1638 <
+3096: 1572 1638 1637 <
+3097: 1573 1574 1639 <
+3098: 1573 1639 1638 <
+3099: 1574 1575 1640 <
+3100: 1574 1640 1639 <
+3101: 1575 1576 1641 <
+3102: 1575 1641 1640 <
+3103: 1576 1577 1642 <
+3104: 1576 1642 1641 <
+3105: 1577 1578 1643 <
+3106: 1577 1643 1642 <
+3107: 1578 1579 1644 <
+3108: 1578 1644 1643 <
+3109: 1579 1580 1645 <
+3110: 1579 1645 1644 <
+3111: 1580 1581 1646 <
+3112: 1580 1646 1645 <
+3113: 1581 1582 1647 <
+3114: 1581 1647 1646 <
+3115: 1582 1583 1648 <
+3116: 1582 1648 1647 <
+3117: 1583 1584 1649 <
+3118: 1583 1649 1648 <
+3119: 1584 1585 1650 <
+3120: 1584 1650 1649 <
+3121: 1585 1586 1651 <
+3122: 1585 1651 1650 <
+3123: 1586 1587 1652 <
+3124: 1586 1652 1651 <
+3125: 1587 1588 1653 <
+3126: 1587 1653 1652 <
+3127: 1588 1589 1654 <
+3128: 1588 1654 1653 <
+3129: 1589 1590 1655 <
+3130: 1589 1655 1654 <
+3131: 1590 1591 1656 <
+3132: 1590 1656 1655 <
+3133: 1591 1592 1657 <
+3134: 1591 1657 1656 <
+3135: 1592 1593 1658 <
+3136: 1592 1658 1657 <
+3137: 1593 1594 1659 <
+3138: 1593 1659 1658 <
+3139: 1594 1595 1660 <
+3140: 1594 1660 1659 <
+3141: 1595 1596 1661 <
+3142: 1595 1661 1660 <
+3143: 1596 1597 1662 <
+3144: 1596 1662 1661 <
+3145: 1597 1598 1663 <
+3146: 1597 1663 1662 <
+3147: 1598 1599 1664 <
+3148: 1598 1664 1663 <
+3149: 1599 1600 1665 <
+3150: 1599 1665 1664 <
+3151: 1600 1601 1666 <
+3152: 1600 1666 1665 <
+3153: 1601 1602 1667 <
+3154: 1601 1667 1666 <
+3155: 1602 1603 1668 <
+3156: 1602 1668 1667 <
+3157: 1603 1604 1669 <
+3158: 1603 1669 1668 <
+3159: 1604 1605 1670 <
+3160: 1604 1670 1669 <
+3161: 1605 1606 1671 <
+3162: 1605 1671 1670 <
+3163: 1606 1607 1672 <
+3164: 1606 1672 1671 <
+3165: 1607 1608 1673 <
+3166: 1607 1673 1672 <
+3167: 1608 1609 1674 <
+3168: 1608 1674 1673 <
+3169: 1609 1610 1675 <
+3170: 1609 1675 1674 <
+3171: 1610 1611 1676 <
+3172: 1610 1676 1675 <
+3173: 1611 1612 1677 <
+3174: 1611 1677 1676 <
+3175: 1612 1613 1678 <
+3176: 1612 1678 1677 <
+3177: 1613 1614 1679 <
+3178: 1613 1679 1678 <
+3179: 1614 1615 1680 <
+3180: 1614 1680 1679 <
+3181: 1615 1616 1681 <
+3182: 1615 1681 1680 <
+3183: 1616 1617 1682 <
+3184: 1616 1682 1681 <
+3185: 1617 1618 1683 <
+3186: 1617 1683 1682 <
+3187: 1618 1619 1684 <
+3188: 1618 1684 1683 <
+3189: 1619 1620 1685 <
+3190: 1619 1685 1684 <
+3191: 1620 1621 1686 <
+3192: 1620 1686 1685 <
+3193: 1621 1622 1687 <
+3194: 1621 1687 1686 <
+3195: 1622 1623 1688 <
+3196: 1622 1688 1687 <
+3197: 1623 1624 1689 <
+3198: 1623 1689 1688 <
+3199: 1624 1625 1690 <
+3200: 1624 1690 1689 <
+3201: 1626 1627 1692 <
+3202: 1626 1692 1691 <
+3203: 1627 1628 1693 <
+3204: 1627 1693 1692 <
+3205: 1628 1629 1694 <
+3206: 1628 1694 1693 <
+3207: 1629 1630 1695 <
+3208: 1629 1695 1694 <
+3209: 1630 1631 1696 <
+3210: 1630 1696 1695 <
+3211: 1631 1632 1697 <
+3212: 1631 1697 1696 <
+3213: 1632 1633 1698 <
+3214: 1632 1698 1697 <
+3215: 1633 1634 1699 <
+3216: 1633 1699 1698 <
+3217: 1634 1635 1700 <
+3218: 1634 1700 1699 <
+3219: 1635 1636 1701 <
+3220: 1635 1701 1700 <
+3221: 1636 1637 1702 <
+3222: 1636 1702 1701 <
+3223: 1637 1638 1703 <
+3224: 1637 1703 1702 <
+3225: 1638 1639 1704 <
+3226: 1638 1704 1703 <
+3227: 1639 1640 1705 <
+3228: 1639 1705 1704 <
+3229: 1640 1641 1706 <
+3230: 1640 1706 1705 <
+3231: 1641 1642 1707 <
+3232: 1641 1707 1706 <
+3233: 1642 1643 1708 <
+3234: 1642 1708 1707 <
+3235: 1643 1644 1709 <
+3236: 1643 1709 1708 <
+3237: 1644 1645 1710 <
+3238: 1644 1710 1709 <
+3239: 1645 1646 1711 <
+3240: 1645 1711 1710 <
+3241: 1646 1647 1712 <
+3242: 1646 1712 1711 <
+3243: 1647 1648 1713 <
+3244: 1647 1713 1712 <
+3245: 1648 1649 1714 <
+3246: 1648 1714 1713 <
+3247: 1649 1650 1715 <
+3248: 1649 1715 1714 <
+3249: 1650 1651 1716 <
+3250: 1650 1716 1715 <
+3251: 1651 1652 1717 <
+3252: 1651 1717 1716 <
+3253: 1652 1653 1718 <
+3254: 1652 1718 1717 <
+3255: 1653 1654 1719 <
+3256: 1653 1719 1718 <
+3257: 1654 1655 1720 <
+3258: 1654 1720 1719 <
+3259: 1655 1656 1721 <
+3260: 1655 1721 1720 <
+3261: 1656 1657 1722 <
+3262: 1656 1722 1721 <
+3263: 1657 1658 1723 <
+3264: 1657 1723 1722 <
+3265: 1658 1659 1724 <
+3266: 1658 1724 1723 <
+3267: 1659 1660 1725 <
+3268: 1659 1725 1724 <
+3269: 1660 1661 1726 <
+3270: 1660 1726 1725 <
+3271: 1661 1662 1727 <
+3272: 1661 1727 1726 <
+3273: 1662 1663 1728 <
+3274: 1662 1728 1727 <
+3275: 1663 1664 1729 <
+3276: 1663 1729 1728 <
+3277: 1664 1665 1730 <
+3278: 1664 1730 1729 <
+3279: 1665 1666 1731 <
+3280: 1665 1731 1730 <
+3281: 1666 1667 1732 <
+3282: 1666 1732 1731 <
+3283: 1667 1668 1733 <
+3284: 1667 1733 1732 <
+3285: 1668 1669 1734 <
+3286: 1668 1734 1733 <
+3287: 1669 1670 1735 <
+3288: 1669 1735 1734 <
+3289: 1670 1671 1736 <
+3290: 1670 1736 1735 <
+3291: 1671 1672 1737 <
+3292: 1671 1737 1736 <
+3293: 1672 1673 1738 <
+3294: 1672 1738 1737 <
+3295: 1673 1674 1739 <
+3296: 1673 1739 1738 <
+3297: 1674 1675 1740 <
+3298: 1674 1740 1739 <
+3299: 1675 1676 1741 <
+3300: 1675 1741 1740 <
+3301: 1676 1677 1742 <
+3302: 1676 1742 1741 <
+3303: 1677 1678 1743 <
+3304: 1677 1743 1742 <
+3305: 1678 1679 1744 <
+3306: 1678 1744 1743 <
+3307: 1679 1680 1745 <
+3308: 1679 1745 1744 <
+3309: 1680 1681 1746 <
+3310: 1680 1746 1745 <
+3311: 1681 1682 1747 <
+3312: 1681 1747 1746 <
+3313: 1682 1683 1748 <
+3314: 1682 1748 1747 <
+3315: 1683 1684 1749 <
+3316: 1683 1749 1748 <
+3317: 1684 1685 1750 <
+3318: 1684 1750 1749 <
+3319: 1685 1686 1751 <
+3320: 1685 1751 1750 <
+3321: 1686 1687 1752 <
+3322: 1686 1752 1751 <
+3323: 1687 1688 1753 <
+3324: 1687 1753 1752 <
+3325: 1688 1689 1754 <
+3326: 1688 1754 1753 <
+3327: 1689 1690 1755 <
+3328: 1689 1755 1754 <
+3329: 1691 1692 1757 <
+3330: 1691 1757 1756 <
+3331: 1692 1693 1758 <
+3332: 1692 1758 1757 <
+3333: 1693 1694 1759 <
+3334: 1693 1759 1758 <
+3335: 1694 1695 1760 <
+3336: 1694 1760 1759 <
+3337: 1695 1696 1761 <
+3338: 1695 1761 1760 <
+3339: 1696 1697 1762 <
+3340: 1696 1762 1761 <
+3341: 1697 1698 1763 <
+3342: 1697 1763 1762 <
+3343: 1698 1699 1764 <
+3344: 1698 1764 1763 <
+3345: 1699 1700 1765 <
+3346: 1699 1765 1764 <
+3347: 1700 1701 1766 <
+3348: 1700 1766 1765 <
+3349: 1701 1702 1767 <
+3350: 1701 1767 1766 <
+3351: 1702 1703 1768 <
+3352: 1702 1768 1767 <
+3353: 1703 1704 1769 <
+3354: 1703 1769 1768 <
+3355: 1704 1705 1770 <
+3356: 1704 1770 1769 <
+3357: 1705 1706 1771 <
+3358: 1705 1771 1770 <
+3359: 1706 1707 1772 <
+3360: 1706 1772 1771 <
+3361: 1707 1708 1773 <
+3362: 1707 1773 1772 <
+3363: 1708 1709 1774 <
+3364: 1708 1774 1773 <
+3365: 1709 1710 1775 <
+3366: 1709 1775 1774 <
+3367: 1710 1711 1776 <
+3368: 1710 1776 1775 <
+3369: 1711 1712 1777 <
+3370: 1711 1777 1776 <
+3371: 1712 1713 1778 <
+3372: 1712 1778 1777 <
+3373: 1713 1714 1779 <
+3374: 1713 1779 1778 <
+3375: 1714 1715 1780 <
+3376: 1714 1780 1779 <
+3377: 1715 1716 1781 <
+3378: 1715 1781 1780 <
+3379: 1716 1717 1782 <
+3380: 1716 1782 1781 <
+3381: 1717 1718 1783 <
+3382: 1717 1783 1782 <
+3383: 1718 1719 1784 <
+3384: 1718 1784 1783 <
+3385: 1719 1720 1785 <
+3386: 1719 1785 1784 <
+3387: 1720 1721 1786 <
+3388: 1720 1786 1785 <
+3389: 1721 1722 1787 <
+3390: 1721 1787 1786 <
+3391: 1722 1723 1788 <
+3392: 1722 1788 1787 <
+3393: 1723 1724 1789 <
+3394: 1723 1789 1788 <
+3395: 1724 1725 1790 <
+3396: 1724 1790 1789 <
+3397: 1725 1726 1791 <
+3398: 1725 1791 1790 <
+3399: 1726 1727 1792 <
+3400: 1726 1792 1791 <
+3401: 1727 1728 1793 <
+3402: 1727 1793 1792 <
+3403: 1728 1729 1794 <
+3404: 1728 1794 1793 <
+3405: 1729 1730 1795 <
+3406: 1729 1795 1794 <
+3407: 1730 1731 1796 <
+3408: 1730 1796 1795 <
+3409: 1731 1732 1797 <
+3410: 1731 1797 1796 <
+3411: 1732 1733 1798 <
+3412: 1732 1798 1797 <
+3413: 1733 1734 1799 <
+3414: 1733 1799 1798 <
+3415: 1734 1735 1800 <
+3416: 1734 1800 1799 <
+3417: 1735 1736 1801 <
+3418: 1735 1801 1800 <
+3419: 1736 1737 1802 <
+3420: 1736 1802 1801 <
+3421: 1737 1738 1803 <
+3422: 1737 1803 1802 <
+3423: 1738 1739 1804 <
+3424: 1738 1804 1803 <
+3425: 1739 1740 1805 <
+3426: 1739 1805 1804 <
+3427: 1740 1741 1806 <
+3428: 1740 1806 1805 <
+3429: 1741 1742 1807 <
+3430: 1741 1807 1806 <
+3431: 1742 1743 1808 <
+3432: 1742 1808 1807 <
+3433: 1743 1744 1809 <
+3434: 1743 1809 1808 <
+3435: 1744 1745 1810 <
+3436: 1744 1810 1809 <
+3437: 1745 1746 1811 <
+3438: 1745 1811 1810 <
+3439: 1746 1747 1812 <
+3440: 1746 1812 1811 <
+3441: 1747 1748 1813 <
+3442: 1747 1813 1812 <
+3443: 1748 1749 1814 <
+3444: 1748 1814 1813 <
+3445: 1749 1750 1815 <
+3446: 1749 1815 1814 <
+3447: 1750 1751 1816 <
+3448: 1750 1816 1815 <
+3449: 1751 1752 1817 <
+3450: 1751 1817 1816 <
+3451: 1752 1753 1818 <
+3452: 1752 1818 1817 <
+3453: 1753 1754 1819 <
+3454: 1753 1819 1818 <
+3455: 1754 1755 1820 <
+3456: 1754 1820 1819 <
+3457: 1756 1757 1822 <
+3458: 1756 1822 1821 <
+3459: 1757 1758 1823 <
+3460: 1757 1823 1822 <
+3461: 1758 1759 1824 <
+3462: 1758 1824 1823 <
+3463: 1759 1760 1825 <
+3464: 1759 1825 1824 <
+3465: 1760 1761 1826 <
+3466: 1760 1826 1825 <
+3467: 1761 1762 1827 <
+3468: 1761 1827 1826 <
+3469: 1762 1763 1828 <
+3470: 1762 1828 1827 <
+3471: 1763 1764 1829 <
+3472: 1763 1829 1828 <
+3473: 1764 1765 1830 <
+3474: 1764 1830 1829 <
+3475: 1765 1766 1831 <
+3476: 1765 1831 1830 <
+3477: 1766 1767 1832 <
+3478: 1766 1832 1831 <
+3479: 1767 1768 1833 <
+3480: 1767 1833 1832 <
+3481: 1768 1769 1834 <
+3482: 1768 1834 1833 <
+3483: 1769 1770 1835 <
+3484: 1769 1835 1834 <
+3485: 1770 1771 1836 <
+3486: 1770 1836 1835 <
+3487: 1771 1772 1837 <
+3488: 1771 1837 1836 <
+3489: 1772 1773 1838 <
+3490: 1772 1838 1837 <
+3491: 1773 1774 1839 <
+3492: 1773 1839 1838 <
+3493: 1774 1775 1840 <
+3494: 1774 1840 1839 <
+3495: 1775 1776 1841 <
+3496: 1775 1841 1840 <
+3497: 1776 1777 1842 <
+3498: 1776 1842 1841 <
+3499: 1777 1778 1843 <
+3500: 1777 1843 1842 <
+3501: 1778 1779 1844 <
+3502: 1778 1844 1843 <
+3503: 1779 1780 1845 <
+3504: 1779 1845 1844 <
+3505: 1780 1781 1846 <
+3506: 1780 1846 1845 <
+3507: 1781 1782 1847 <
+3508: 1781 1847 1846 <
+3509: 1782 1783 1848 <
+3510: 1782 1848 1847 <
+3511: 1783 1784 1849 <
+3512: 1783 1849 1848 <
+3513: 1784 1785 1850 <
+3514: 1784 1850 1849 <
+3515: 1785 1786 1851 <
+3516: 1785 1851 1850 <
+3517: 1786 1787 1852 <
+3518: 1786 1852 1851 <
+3519: 1787 1788 1853 <
+3520: 1787 1853 1852 <
+3521: 1788 1789 1854 <
+3522: 1788 1854 1853 <
+3523: 1789 1790 1855 <
+3524: 1789 1855 1854 <
+3525: 1790 1791 1856 <
+3526: 1790 1856 1855 <
+3527: 1791 1792 1857 <
+3528: 1791 1857 1856 <
+3529: 1792 1793 1858 <
+3530: 1792 1858 1857 <
+3531: 1793 1794 1859 <
+3532: 1793 1859 1858 <
+3533: 1794 1795 1860 <
+3534: 1794 1860 1859 <
+3535: 1795 1796 1861 <
+3536: 1795 1861 1860 <
+3537: 1796 1797 1862 <
+3538: 1796 1862 1861 <
+3539: 1797 1798 1863 <
+3540: 1797 1863 1862 <
+3541: 1798 1799 1864 <
+3542: 1798 1864 1863 <
+3543: 1799 1800 1865 <
+3544: 1799 1865 1864 <
+3545: 1800 1801 1866 <
+3546: 1800 1866 1865 <
+3547: 1801 1802 1867 <
+3548: 1801 1867 1866 <
+3549: 1802 1803 1868 <
+3550: 1802 1868 1867 <
+3551: 1803 1804 1869 <
+3552: 1803 1869 1868 <
+3553: 1804 1805 1870 <
+3554: 1804 1870 1869 <
+3555: 1805 1806 1871 <
+3556: 1805 1871 1870 <
+3557: 1806 1807 1872 <
+3558: 1806 1872 1871 <
+3559: 1807 1808 1873 <
+3560: 1807 1873 1872 <
+3561: 1808 1809 1874 <
+3562: 1808 1874 1873 <
+3563: 1809 1810 1875 <
+3564: 1809 1875 1874 <
+3565: 1810 1811 1876 <
+3566: 1810 1876 1875 <
+3567: 1811 1812 1877 <
+3568: 1811 1877 1876 <
+3569: 1812 1813 1878 <
+3570: 1812 1878 1877 <
+3571: 1813 1814 1879 <
+3572: 1813 1879 1878 <
+3573: 1814 1815 1880 <
+3574: 1814 1880 1879 <
+3575: 1815 1816 1881 <
+3576: 1815 1881 1880 <
+3577: 1816 1817 1882 <
+3578: 1816 1882 1881 <
+3579: 1817 1818 1883 <
+3580: 1817 1883 1882 <
+3581: 1818 1819 1884 <
+3582: 1818 1884 1883 <
+3583: 1819 1820 1885 <
+3584: 1819 1885 1884 <
+3585: 1821 1822 1887 <
+3586: 1821 1887 1886 <
+3587: 1822 1823 1888 <
+3588: 1822 1888 1887 <
+3589: 1823 1824 1889 <
+3590: 1823 1889 1888 <
+3591: 1824 1825 1890 <
+3592: 1824 1890 1889 <
+3593: 1825 1826 1891 <
+3594: 1825 1891 1890 <
+3595: 1826 1827 1892 <
+3596: 1826 1892 1891 <
+3597: 1827 1828 1893 <
+3598: 1827 1893 1892 <
+3599: 1828 1829 1894 <
+3600: 1828 1894 1893 <
+3601: 1829 1830 1895 <
+3602: 1829 1895 1894 <
+3603: 1830 1831 1896 <
+3604: 1830 1896 1895 <
+3605: 1831 1832 1897 <
+3606: 1831 1897 1896 <
+3607: 1832 1833 1898 <
+3608: 1832 1898 1897 <
+3609: 1833 1834 1899 <
+3610: 1833 1899 1898 <
+3611: 1834 1835 1900 <
+3612: 1834 1900 1899 <
+3613: 1835 1836 1901 <
+3614: 1835 1901 1900 <
+3615: 1836 1837 1902 <
+3616: 1836 1902 1901 <
+3617: 1837 1838 1903 <
+3618: 1837 1903 1902 <
+3619: 1838 1839 1904 <
+3620: 1838 1904 1903 <
+3621: 1839 1840 1905 <
+3622: 1839 1905 1904 <
+3623: 1840 1841 1906 <
+3624: 1840 1906 1905 <
+3625: 1841 1842 1907 <
+3626: 1841 1907 1906 <
+3627: 1842 1843 1908 <
+3628: 1842 1908 1907 <
+3629: 1843 1844 1909 <
+3630: 1843 1909 1908 <
+3631: 1844 1845 1910 <
+3632: 1844 1910 1909 <
+3633: 1845 1846 1911 <
+3634: 1845 1911 1910 <
+3635: 1846 1847 1912 <
+3636: 1846 1912 1911 <
+3637: 1847 1848 1913 <
+3638: 1847 1913 1912 <
+3639: 1848 1849 1914 <
+3640: 1848 1914 1913 <
+3641: 1849 1850 1915 <
+3642: 1849 1915 1914 <
+3643: 1850 1851 1916 <
+3644: 1850 1916 1915 <
+3645: 1851 1852 1917 <
+3646: 1851 1917 1916 <
+3647: 1852 1853 1918 <
+3648: 1852 1918 1917 <
+3649: 1853 1854 1919 <
+3650: 1853 1919 1918 <
+3651: 1854 1855 1920 <
+3652: 1854 1920 1919 <
+3653: 1855 1856 1921 <
+3654: 1855 1921 1920 <
+3655: 1856 1857 1922 <
+3656: 1856 1922 1921 <
+3657: 1857 1858 1923 <
+3658: 1857 1923 1922 <
+3659: 1858 1859 1924 <
+3660: 1858 1924 1923 <
+3661: 1859 1860 1925 <
+3662: 1859 1925 1924 <
+3663: 1860 1861 1926 <
+3664: 1860 1926 1925 <
+3665: 1861 1862 1927 <
+3666: 1861 1927 1926 <
+3667: 1862 1863 1928 <
+3668: 1862 1928 1927 <
+3669: 1863 1864 1929 <
+3670: 1863 1929 1928 <
+3671: 1864 1865 1930 <
+3672: 1864 1930 1929 <
+3673: 1865 1866 1931 <
+3674: 1865 1931 1930 <
+3675: 1866 1867 1932 <
+3676: 1866 1932 1931 <
+3677: 1867 1868 1933 <
+3678: 1867 1933 1932 <
+3679: 1868 1869 1934 <
+3680: 1868 1934 1933 <
+3681: 1869 1870 1935 <
+3682: 1869 1935 1934 <
+3683: 1870 1871 1936 <
+3684: 1870 1936 1935 <
+3685: 1871 1872 1937 <
+3686: 1871 1937 1936 <
+3687: 1872 1873 1938 <
+3688: 1872 1938 1937 <
+3689: 1873 1874 1939 <
+3690: 1873 1939 1938 <
+3691: 1874 1875 1940 <
+3692: 1874 1940 1939 <
+3693: 1875 1876 1941 <
+3694: 1875 1941 1940 <
+3695: 1876 1877 1942 <
+3696: 1876 1942 1941 <
+3697: 1877 1878 1943 <
+3698: 1877 1943 1942 <
+3699: 1878 1879 1944 <
+3700: 1878 1944 1943 <
+3701: 1879 1880 1945 <
+3702: 1879 1945 1944 <
+3703: 1880 1881 1946 <
+3704: 1880 1946 1945 <
+3705: 1881 1882 1947 <
+3706: 1881 1947 1946 <
+3707: 1882 1883 1948 <
+3708: 1882 1948 1947 <
+3709: 1883 1884 1949 <
+3710: 1883 1949 1948 <
+3711: 1884 1885 1950 <
+3712: 1884 1950 1949 <
+3713: 1886 1887 1952 <
+3714: 1886 1952 1951 <
+3715: 1887 1888 1953 <
+3716: 1887 1953 1952 <
+3717: 1888 1889 1954 <
+3718: 1888 1954 1953 <
+3719: 1889 1890 1955 <
+3720: 1889 1955 1954 <
+3721: 1890 1891 1956 <
+3722: 1890 1956 1955 <
+3723: 1891 1892 1957 <
+3724: 1891 1957 1956 <
+3725: 1892 1893 1958 <
+3726: 1892 1958 1957 <
+3727: 1893 1894 1959 <
+3728: 1893 1959 1958 <
+3729: 1894 1895 1960 <
+3730: 1894 1960 1959 <
+3731: 1895 1896 1961 <
+3732: 1895 1961 1960 <
+3733: 1896 1897 1962 <
+3734: 1896 1962 1961 <
+3735: 1897 1898 1963 <
+3736: 1897 1963 1962 <
+3737: 1898 1899 1964 <
+3738: 1898 1964 1963 <
+3739: 1899 1900 1965 <
+3740: 1899 1965 1964 <
+3741: 1900 1901 1966 <
+3742: 1900 1966 1965 <
+3743: 1901 1902 1967 <
+3744: 1901 1967 1966 <
+3745: 1902 1903 1968 <
+3746: 1902 1968 1967 <
+3747: 1903 1904 1969 <
+3748: 1903 1969 1968 <
+3749: 1904 1905 1970 <
+3750: 1904 1970 1969 <
+3751: 1905 1906 1971 <
+3752: 1905 1971 1970 <
+3753: 1906 1907 1972 <
+3754: 1906 1972 1971 <
+3755: 1907 1908 1973 <
+3756: 1907 1973 1972 <
+3757: 1908 1909 1974 <
+3758: 1908 1974 1973 <
+3759: 1909 1910 1975 <
+3760: 1909 1975 1974 <
+3761: 1910 1911 1976 <
+3762: 1910 1976 1975 <
+3763: 1911 1912 1977 <
+3764: 1911 1977 1976 <
+3765: 1912 1913 1978 <
+3766: 1912 1978 1977 <
+3767: 1913 1914 1979 <
+3768: 1913 1979 1978 <
+3769: 1914 1915 1980 <
+3770: 1914 1980 1979 <
+3771: 1915 1916 1981 <
+3772: 1915 1981 1980 <
+3773: 1916 1917 1982 <
+3774: 1916 1982 1981 <
+3775: 1917 1918 1983 <
+3776: 1917 1983 1982 <
+3777: 1918 1919 1984 <
+3778: 1918 1984 1983 <
+3779: 1919 1920 1985 <
+3780: 1919 1985 1984 <
+3781: 1920 1921 1986 <
+3782: 1920 1986 1985 <
+3783: 1921 1922 1987 <
+3784: 1921 1987 1986 <
+3785: 1922 1923 1988 <
+3786: 1922 1988 1987 <
+3787: 1923 1924 1989 <
+3788: 1923 1989 1988 <
+3789: 1924 1925 1990 <
+3790: 1924 1990 1989 <
+3791: 1925 1926 1991 <
+3792: 1925 1991 1990 <
+3793: 1926 1927 1992 <
+3794: 1926 1992 1991 <
+3795: 1927 1928 1993 <
+3796: 1927 1993 1992 <
+3797: 1928 1929 1994 <
+3798: 1928 1994 1993 <
+3799: 1929 1930 1995 <
+3800: 1929 1995 1994 <
+3801: 1930 1931 1996 <
+3802: 1930 1996 1995 <
+3803: 1931 1932 1997 <
+3804: 1931 1997 1996 <
+3805: 1932 1933 1998 <
+3806: 1932 1998 1997 <
+3807: 1933 1934 1999 <
+3808: 1933 1999 1998 <
+3809: 1934 1935 2000 <
+3810: 1934 2000 1999 <
+3811: 1935 1936 2001 <
+3812: 1935 2001 2000 <
+3813: 1936 1937 2002 <
+3814: 1936 2002 2001 <
+3815: 1937 1938 2003 <
+3816: 1937 2003 2002 <
+3817: 1938 1939 2004 <
+3818: 1938 2004 2003 <
+3819: 1939 1940 2005 <
+3820: 1939 2005 2004 <
+3821: 1940 1941 2006 <
+3822: 1940 2006 2005 <
+3823: 1941 1942 2007 <
+3824: 1941 2007 2006 <
+3825: 1942 1943 2008 <
+3826: 1942 2008 2007 <
+3827: 1943 1944 2009 <
+3828: 1943 2009 2008 <
+3829: 1944 1945 2010 <
+3830: 1944 2010 2009 <
+3831: 1945 1946 2011 <
+3832: 1945 2011 2010 <
+3833: 1946 1947 2012 <
+3834: 1946 2012 2011 <
+3835: 1947 1948 2013 <
+3836: 1947 2013 2012 <
+3837: 1948 1949 2014 <
+3838: 1948 2014 2013 <
+3839: 1949 1950 2015 <
+3840: 1949 2015 2014 <
+3841: 1951 1952 2017 <
+3842: 1951 2017 2016 <
+3843: 1952 1953 2018 <
+3844: 1952 2018 2017 <
+3845: 1953 1954 2019 <
+3846: 1953 2019 2018 <
+3847: 1954 1955 2020 <
+3848: 1954 2020 2019 <
+3849: 1955 1956 2021 <
+3850: 1955 2021 2020 <
+3851: 1956 1957 2022 <
+3852: 1956 2022 2021 <
+3853: 1957 1958 2023 <
+3854: 1957 2023 2022 <
+3855: 1958 1959 2024 <
+3856: 1958 2024 2023 <
+3857: 1959 1960 2025 <
+3858: 1959 2025 2024 <
+3859: 1960 1961 2026 <
+3860: 1960 2026 2025 <
+3861: 1961 1962 2027 <
+3862: 1961 2027 2026 <
+3863: 1962 1963 2028 <
+3864: 1962 2028 2027 <
+3865: 1963 1964 2029 <
+3866: 1963 2029 2028 <
+3867: 1964 1965 2030 <
+3868: 1964 2030 2029 <
+3869: 1965 1966 2031 <
+3870: 1965 2031 2030 <
+3871: 1966 1967 2032 <
+3872: 1966 2032 2031 <
+3873: 1967 1968 2033 <
+3874: 1967 2033 2032 <
+3875: 1968 1969 2034 <
+3876: 1968 2034 2033 <
+3877: 1969 1970 2035 <
+3878: 1969 2035 2034 <
+3879: 1970 1971 2036 <
+3880: 1970 2036 2035 <
+3881: 1971 1972 2037 <
+3882: 1971 2037 2036 <
+3883: 1972 1973 2038 <
+3884: 1972 2038 2037 <
+3885: 1973 1974 2039 <
+3886: 1973 2039 2038 <
+3887: 1974 1975 2040 <
+3888: 1974 2040 2039 <
+3889: 1975 1976 2041 <
+3890: 1975 2041 2040 <
+3891: 1976 1977 2042 <
+3892: 1976 2042 2041 <
+3893: 1977 1978 2043 <
+3894: 1977 2043 2042 <
+3895: 1978 1979 2044 <
+3896: 1978 2044 2043 <
+3897: 1979 1980 2045 <
+3898: 1979 2045 2044 <
+3899: 1980 1981 2046 <
+3900: 1980 2046 2045 <
+3901: 1981 1982 2047 <
+3902: 1981 2047 2046 <
+3903: 1982 1983 2048 <
+3904: 1982 2048 2047 <
+3905: 1983 1984 2049 <
+3906: 1983 2049 2048 <
+3907: 1984 1985 2050 <
+3908: 1984 2050 2049 <
+3909: 1985 1986 2051 <
+3910: 1985 2051 2050 <
+3911: 1986 1987 2052 <
+3912: 1986 2052 2051 <
+3913: 1987 1988 2053 <
+3914: 1987 2053 2052 <
+3915: 1988 1989 2054 <
+3916: 1988 2054 2053 <
+3917: 1989 1990 2055 <
+3918: 1989 2055 2054 <
+3919: 1990 1991 2056 <
+3920: 1990 2056 2055 <
+3921: 1991 1992 2057 <
+3922: 1991 2057 2056 <
+3923: 1992 1993 2058 <
+3924: 1992 2058 2057 <
+3925: 1993 1994 2059 <
+3926: 1993 2059 2058 <
+3927: 1994 1995 2060 <
+3928: 1994 2060 2059 <
+3929: 1995 1996 2061 <
+3930: 1995 2061 2060 <
+3931: 1996 1997 2062 <
+3932: 1996 2062 2061 <
+3933: 1997 1998 2063 <
+3934: 1997 2063 2062 <
+3935: 1998 1999 2064 <
+3936: 1998 2064 2063 <
+3937: 1999 2000 2065 <
+3938: 1999 2065 2064 <
+3939: 2000 2001 2066 <
+3940: 2000 2066 2065 <
+3941: 2001 2002 2067 <
+3942: 2001 2067 2066 <
+3943: 2002 2003 2068 <
+3944: 2002 2068 2067 <
+3945: 2003 2004 2069 <
+3946: 2003 2069 2068 <
+3947: 2004 2005 2070 <
+3948: 2004 2070 2069 <
+3949: 2005 2006 2071 <
+3950: 2005 2071 2070 <
+3951: 2006 2007 2072 <
+3952: 2006 2072 2071 <
+3953: 2007 2008 2073 <
+3954: 2007 2073 2072 <
+3955: 2008 2009 2074 <
+3956: 2008 2074 2073 <
+3957: 2009 2010 2075 <
+3958: 2009 2075 2074 <
+3959: 2010 2011 2076 <
+3960: 2010 2076 2075 <
+3961: 2011 2012 2077 <
+3962: 2011 2077 2076 <
+3963: 2012 2013 2078 <
+3964: 2012 2078 2077 <
+3965: 2013 2014 2079 <
+3966: 2013 2079 2078 <
+3967: 2014 2015 2080 <
+3968: 2014 2080 2079 <
+3969: 2016 2017 2082 <
+3970: 2016 2082 2081 <
+3971: 2017 2018 2083 <
+3972: 2017 2083 2082 <
+3973: 2018 2019 2084 <
+3974: 2018 2084 2083 <
+3975: 2019 2020 2085 <
+3976: 2019 2085 2084 <
+3977: 2020 2021 2086 <
+3978: 2020 2086 2085 <
+3979: 2021 2022 2087 <
+3980: 2021 2087 2086 <
+3981: 2022 2023 2088 <
+3982: 2022 2088 2087 <
+3983: 2023 2024 2089 <
+3984: 2023 2089 2088 <
+3985: 2024 2025 2090 <
+3986: 2024 2090 2089 <
+3987: 2025 2026 2091 <
+3988: 2025 2091 2090 <
+3989: 2026 2027 2092 <
+3990: 2026 2092 2091 <
+3991: 2027 2028 2093 <
+3992: 2027 2093 2092 <
+3993: 2028 2029 2094 <
+3994: 2028 2094 2093 <
+3995: 2029 2030 2095 <
+3996: 2029 2095 2094 <
+3997: 2030 2031 2096 <
+3998: 2030 2096 2095 <
+3999: 2031 2032 2097 <
+4000: 2031 2097 2096 <
+4001: 2032 2033 2098 <
+4002: 2032 2098 2097 <
+4003: 2033 2034 2099 <
+4004: 2033 2099 2098 <
+4005: 2034 2035 2100 <
+4006: 2034 2100 2099 <
+4007: 2035 2036 2101 <
+4008: 2035 2101 2100 <
+4009: 2036 2037 2102 <
+4010: 2036 2102 2101 <
+4011: 2037 2038 2103 <
+4012: 2037 2103 2102 <
+4013: 2038 2039 2104 <
+4014: 2038 2104 2103 <
+4015: 2039 2040 2105 <
+4016: 2039 2105 2104 <
+4017: 2040 2041 2106 <
+4018: 2040 2106 2105 <
+4019: 2041 2042 2107 <
+4020: 2041 2107 2106 <
+4021: 2042 2043 2108 <
+4022: 2042 2108 2107 <
+4023: 2043 2044 2109 <
+4024: 2043 2109 2108 <
+4025: 2044 2045 2110 <
+4026: 2044 2110 2109 <
+4027: 2045 2046 2111 <
+4028: 2045 2111 2110 <
+4029: 2046 2047 2112 <
+4030: 2046 2112 2111 <
+4031: 2047 2048 2113 <
+4032: 2047 2113 2112 <
+4033: 2048 2049 2114 <
+4034: 2048 2114 2113 <
+4035: 2049 2050 2115 <
+4036: 2049 2115 2114 <
+4037: 2050 2051 2116 <
+4038: 2050 2116 2115 <
+4039: 2051 2052 2117 <
+4040: 2051 2117 2116 <
+4041: 2052 2053 2118 <
+4042: 2052 2118 2117 <
+4043: 2053 2054 2119 <
+4044: 2053 2119 2118 <
+4045: 2054 2055 2120 <
+4046: 2054 2120 2119 <
+4047: 2055 2056 2121 <
+4048: 2055 2121 2120 <
+4049: 2056 2057 2122 <
+4050: 2056 2122 2121 <
+4051: 2057 2058 2123 <
+4052: 2057 2123 2122 <
+4053: 2058 2059 2124 <
+4054: 2058 2124 2123 <
+4055: 2059 2060 2125 <
+4056: 2059 2125 2124 <
+4057: 2060 2061 2126 <
+4058: 2060 2126 2125 <
+4059: 2061 2062 2127 <
+4060: 2061 2127 2126 <
+4061: 2062 2063 2128 <
+4062: 2062 2128 2127 <
+4063: 2063 2064 2129 <
+4064: 2063 2129 2128 <
+4065: 2064 2065 2130 <
+4066: 2064 2130 2129 <
+4067: 2065 2066 2131 <
+4068: 2065 2131 2130 <
+4069: 2066 2067 2132 <
+4070: 2066 2132 2131 <
+4071: 2067 2068 2133 <
+4072: 2067 2133 2132 <
+4073: 2068 2069 2134 <
+4074: 2068 2134 2133 <
+4075: 2069 2070 2135 <
+4076: 2069 2135 2134 <
+4077: 2070 2071 2136 <
+4078: 2070 2136 2135 <
+4079: 2071 2072 2137 <
+4080: 2071 2137 2136 <
+4081: 2072 2073 2138 <
+4082: 2072 2138 2137 <
+4083: 2073 2074 2139 <
+4084: 2073 2139 2138 <
+4085: 2074 2075 2140 <
+4086: 2074 2140 2139 <
+4087: 2075 2076 2141 <
+4088: 2075 2141 2140 <
+4089: 2076 2077 2142 <
+4090: 2076 2142 2141 <
+4091: 2077 2078 2143 <
+4092: 2077 2143 2142 <
+4093: 2078 2079 2144 <
+4094: 2078 2144 2143 <
+4095: 2079 2080 2145 <
+4096: 2079 2145 2144 <
+4097: 2081 2082 2147 <
+4098: 2081 2147 2146 <
+4099: 2082 2083 2148 <
+4100: 2082 2148 2147 <
+4101: 2083 2084 2149 <
+4102: 2083 2149 2148 <
+4103: 2084 2085 2150 <
+4104: 2084 2150 2149 <
+4105: 2085 2086 2151 <
+4106: 2085 2151 2150 <
+4107: 2086 2087 2152 <
+4108: 2086 2152 2151 <
+4109: 2087 2088 2153 <
+4110: 2087 2153 2152 <
+4111: 2088 2089 2154 <
+4112: 2088 2154 2153 <
+4113: 2089 2090 2155 <
+4114: 2089 2155 2154 <
+4115: 2090 2091 2156 <
+4116: 2090 2156 2155 <
+4117: 2091 2092 2157 <
+4118: 2091 2157 2156 <
+4119: 2092 2093 2158 <
+4120: 2092 2158 2157 <
+4121: 2093 2094 2159 <
+4122: 2093 2159 2158 <
+4123: 2094 2095 2160 <
+4124: 2094 2160 2159 <
+4125: 2095 2096 2161 <
+4126: 2095 2161 2160 <
+4127: 2096 2097 2162 <
+4128: 2096 2162 2161 <
+4129: 2097 2098 2163 <
+4130: 2097 2163 2162 <
+4131: 2098 2099 2164 <
+4132: 2098 2164 2163 <
+4133: 2099 2100 2165 <
+4134: 2099 2165 2164 <
+4135: 2100 2101 2166 <
+4136: 2100 2166 2165 <
+4137: 2101 2102 2167 <
+4138: 2101 2167 2166 <
+4139: 2102 2103 2168 <
+4140: 2102 2168 2167 <
+4141: 2103 2104 2169 <
+4142: 2103 2169 2168 <
+4143: 2104 2105 2170 <
+4144: 2104 2170 2169 <
+4145: 2105 2106 2171 <
+4146: 2105 2171 2170 <
+4147: 2106 2107 2172 <
+4148: 2106 2172 2171 <
+4149: 2107 2108 2173 <
+4150: 2107 2173 2172 <
+4151: 2108 2109 2174 <
+4152: 2108 2174 2173 <
+4153: 2109 2110 2175 <
+4154: 2109 2175 2174 <
+4155: 2110 2111 2176 <
+4156: 2110 2176 2175 <
+4157: 2111 2112 2177 <
+4158: 2111 2177 2176 <
+4159: 2112 2113 2178 <
+4160: 2112 2178 2177 <
+4161: 2113 2114 2179 <
+4162: 2113 2179 2178 <
+4163: 2114 2115 2180 <
+4164: 2114 2180 2179 <
+4165: 2115 2116 2181 <
+4166: 2115 2181 2180 <
+4167: 2116 2117 2182 <
+4168: 2116 2182 2181 <
+4169: 2117 2118 2183 <
+4170: 2117 2183 2182 <
+4171: 2118 2119 2184 <
+4172: 2118 2184 2183 <
+4173: 2119 2120 2185 <
+4174: 2119 2185 2184 <
+4175: 2120 2121 2186 <
+4176: 2120 2186 2185 <
+4177: 2121 2122 2187 <
+4178: 2121 2187 2186 <
+4179: 2122 2123 2188 <
+4180: 2122 2188 2187 <
+4181: 2123 2124 2189 <
+4182: 2123 2189 2188 <
+4183: 2124 2125 2190 <
+4184: 2124 2190 2189 <
+4185: 2125 2126 2191 <
+4186: 2125 2191 2190 <
+4187: 2126 2127 2192 <
+4188: 2126 2192 2191 <
+4189: 2127 2128 2193 <
+4190: 2127 2193 2192 <
+4191: 2128 2129 2194 <
+4192: 2128 2194 2193 <
+4193: 2129 2130 2195 <
+4194: 2129 2195 2194 <
+4195: 2130 2131 2196 <
+4196: 2130 2196 2195 <
+4197: 2131 2132 2197 <
+4198: 2131 2197 2196 <
+4199: 2132 2133 2198 <
+4200: 2132 2198 2197 <
+4201: 2133 2134 2199 <
+4202: 2133 2199 2198 <
+4203: 2134 2135 2200 <
+4204: 2134 2200 2199 <
+4205: 2135 2136 2201 <
+4206: 2135 2201 2200 <
+4207: 2136 2137 2202 <
+4208: 2136 2202 2201 <
+4209: 2137 2138 2203 <
+4210: 2137 2203 2202 <
+4211: 2138 2139 2204 <
+4212: 2138 2204 2203 <
+4213: 2139 2140 2205 <
+4214: 2139 2205 2204 <
+4215: 2140 2141 2206 <
+4216: 2140 2206 2205 <
+4217: 2141 2142 2207 <
+4218: 2141 2207 2206 <
+4219: 2142 2143 2208 <
+4220: 2142 2208 2207 <
+4221: 2143 2144 2209 <
+4222: 2143 2209 2208 <
+4223: 2144 2145 2210 <
+4224: 2144 2210 2209 <
+4225: 2146 2147 2212 <
+4226: 2146 2212 2211 <
+4227: 2147 2148 2213 <
+4228: 2147 2213 2212 <
+4229: 2148 2149 2214 <
+4230: 2148 2214 2213 <
+4231: 2149 2150 2215 <
+4232: 2149 2215 2214 <
+4233: 2150 2151 2216 <
+4234: 2150 2216 2215 <
+4235: 2151 2152 2217 <
+4236: 2151 2217 2216 <
+4237: 2152 2153 2218 <
+4238: 2152 2218 2217 <
+4239: 2153 2154 2219 <
+4240: 2153 2219 2218 <
+4241: 2154 2155 2220 <
+4242: 2154 2220 2219 <
+4243: 2155 2156 2221 <
+4244: 2155 2221 2220 <
+4245: 2156 2157 2222 <
+4246: 2156 2222 2221 <
+4247: 2157 2158 2223 <
+4248: 2157 2223 2222 <
+4249: 2158 2159 2224 <
+4250: 2158 2224 2223 <
+4251: 2159 2160 2225 <
+4252: 2159 2225 2224 <
+4253: 2160 2161 2226 <
+4254: 2160 2226 2225 <
+4255: 2161 2162 2227 <
+4256: 2161 2227 2226 <
+4257: 2162 2163 2228 <
+4258: 2162 2228 2227 <
+4259: 2163 2164 2229 <
+4260: 2163 2229 2228 <
+4261: 2164 2165 2230 <
+4262: 2164 2230 2229 <
+4263: 2165 2166 2231 <
+4264: 2165 2231 2230 <
+4265: 2166 2167 2232 <
+4266: 2166 2232 2231 <
+4267: 2167 2168 2233 <
+4268: 2167 2233 2232 <
+4269: 2168 2169 2234 <
+4270: 2168 2234 2233 <
+4271: 2169 2170 2235 <
+4272: 2169 2235 2234 <
+4273: 2170 2171 2236 <
+4274: 2170 2236 2235 <
+4275: 2171 2172 2237 <
+4276: 2171 2237 2236 <
+4277: 2172 2173 2238 <
+4278: 2172 2238 2237 <
+4279: 2173 2174 2239 <
+4280: 2173 2239 2238 <
+4281: 2174 2175 2240 <
+4282: 2174 2240 2239 <
+4283: 2175 2176 2241 <
+4284: 2175 2241 2240 <
+4285: 2176 2177 2242 <
+4286: 2176 2242 2241 <
+4287: 2177 2178 2243 <
+4288: 2177 2243 2242 <
+4289: 2178 2179 2244 <
+4290: 2178 2244 2243 <
+4291: 2179 2180 2245 <
+4292: 2179 2245 2244 <
+4293: 2180 2181 2246 <
+4294: 2180 2246 2245 <
+4295: 2181 2182 2247 <
+4296: 2181 2247 2246 <
+4297: 2182 2183 2248 <
+4298: 2182 2248 2247 <
+4299: 2183 2184 2249 <
+4300: 2183 2249 2248 <
+4301: 2184 2185 2250 <
+4302: 2184 2250 2249 <
+4303: 2185 2186 2251 <
+4304: 2185 2251 2250 <
+4305: 2186 2187 2252 <
+4306: 2186 2252 2251 <
+4307: 2187 2188 2253 <
+4308: 2187 2253 2252 <
+4309: 2188 2189 2254 <
+4310: 2188 2254 2253 <
+4311: 2189 2190 2255 <
+4312: 2189 2255 2254 <
+4313: 2190 2191 2256 <
+4314: 2190 2256 2255 <
+4315: 2191 2192 2257 <
+4316: 2191 2257 2256 <
+4317: 2192 2193 2258 <
+4318: 2192 2258 2257 <
+4319: 2193 2194 2259 <
+4320: 2193 2259 2258 <
+4321: 2194 2195 2260 <
+4322: 2194 2260 2259 <
+4323: 2195 2196 2261 <
+4324: 2195 2261 2260 <
+4325: 2196 2197 2262 <
+4326: 2196 2262 2261 <
+4327: 2197 2198 2263 <
+4328: 2197 2263 2262 <
+4329: 2198 2199 2264 <
+4330: 2198 2264 2263 <
+4331: 2199 2200 2265 <
+4332: 2199 2265 2264 <
+4333: 2200 2201 2266 <
+4334: 2200 2266 2265 <
+4335: 2201 2202 2267 <
+4336: 2201 2267 2266 <
+4337: 2202 2203 2268 <
+4338: 2202 2268 2267 <
+4339: 2203 2204 2269 <
+4340: 2203 2269 2268 <
+4341: 2204 2205 2270 <
+4342: 2204 2270 2269 <
+4343: 2205 2206 2271 <
+4344: 2205 2271 2270 <
+4345: 2206 2207 2272 <
+4346: 2206 2272 2271 <
+4347: 2207 2208 2273 <
+4348: 2207 2273 2272 <
+4349: 2208 2209 2274 <
+4350: 2208 2274 2273 <
+4351: 2209 2210 2275 <
+4352: 2209 2275 2274 <
+4353: 2211 2212 2277 <
+4354: 2211 2277 2276 <
+4355: 2212 2213 2278 <
+4356: 2212 2278 2277 <
+4357: 2213 2214 2279 <
+4358: 2213 2279 2278 <
+4359: 2214 2215 2280 <
+4360: 2214 2280 2279 <
+4361: 2215 2216 2281 <
+4362: 2215 2281 2280 <
+4363: 2216 2217 2282 <
+4364: 2216 2282 2281 <
+4365: 2217 2218 2283 <
+4366: 2217 2283 2282 <
+4367: 2218 2219 2284 <
+4368: 2218 2284 2283 <
+4369: 2219 2220 2285 <
+4370: 2219 2285 2284 <
+4371: 2220 2221 2286 <
+4372: 2220 2286 2285 <
+4373: 2221 2222 2287 <
+4374: 2221 2287 2286 <
+4375: 2222 2223 2288 <
+4376: 2222 2288 2287 <
+4377: 2223 2224 2289 <
+4378: 2223 2289 2288 <
+4379: 2224 2225 2290 <
+4380: 2224 2290 2289 <
+4381: 2225 2226 2291 <
+4382: 2225 2291 2290 <
+4383: 2226 2227 2292 <
+4384: 2226 2292 2291 <
+4385: 2227 2228 2293 <
+4386: 2227 2293 2292 <
+4387: 2228 2229 2294 <
+4388: 2228 2294 2293 <
+4389: 2229 2230 2295 <
+4390: 2229 2295 2294 <
+4391: 2230 2231 2296 <
+4392: 2230 2296 2295 <
+4393: 2231 2232 2297 <
+4394: 2231 2297 2296 <
+4395: 2232 2233 2298 <
+4396: 2232 2298 2297 <
+4397: 2233 2234 2299 <
+4398: 2233 2299 2298 <
+4399: 2234 2235 2300 <
+4400: 2234 2300 2299 <
+4401: 2235 2236 2301 <
+4402: 2235 2301 2300 <
+4403: 2236 2237 2302 <
+4404: 2236 2302 2301 <
+4405: 2237 2238 2303 <
+4406: 2237 2303 2302 <
+4407: 2238 2239 2304 <
+4408: 2238 2304 2303 <
+4409: 2239 2240 2305 <
+4410: 2239 2305 2304 <
+4411: 2240 2241 2306 <
+4412: 2240 2306 2305 <
+4413: 2241 2242 2307 <
+4414: 2241 2307 2306 <
+4415: 2242 2243 2308 <
+4416: 2242 2308 2307 <
+4417: 2243 2244 2309 <
+4418: 2243 2309 2308 <
+4419: 2244 2245 2310 <
+4420: 2244 2310 2309 <
+4421: 2245 2246 2311 <
+4422: 2245 2311 2310 <
+4423: 2246 2247 2312 <
+4424: 2246 2312 2311 <
+4425: 2247 2248 2313 <
+4426: 2247 2313 2312 <
+4427: 2248 2249 2314 <
+4428: 2248 2314 2313 <
+4429: 2249 2250 2315 <
+4430: 2249 2315 2314 <
+4431: 2250 2251 2316 <
+4432: 2250 2316 2315 <
+4433: 2251 2252 2317 <
+4434: 2251 2317 2316 <
+4435: 2252 2253 2318 <
+4436: 2252 2318 2317 <
+4437: 2253 2254 2319 <
+4438: 2253 2319 2318 <
+4439: 2254 2255 2320 <
+4440: 2254 2320 2319 <
+4441: 2255 2256 2321 <
+4442: 2255 2321 2320 <
+4443: 2256 2257 2322 <
+4444: 2256 2322 2321 <
+4445: 2257 2258 2323 <
+4446: 2257 2323 2322 <
+4447: 2258 2259 2324 <
+4448: 2258 2324 2323 <
+4449: 2259 2260 2325 <
+4450: 2259 2325 2324 <
+4451: 2260 2261 2326 <
+4452: 2260 2326 2325 <
+4453: 2261 2262 2327 <
+4454: 2261 2327 2326 <
+4455: 2262 2263 2328 <
+4456: 2262 2328 2327 <
+4457: 2263 2264 2329 <
+4458: 2263 2329 2328 <
+4459: 2264 2265 2330 <
+4460: 2264 2330 2329 <
+4461: 2265 2266 2331 <
+4462: 2265 2331 2330 <
+4463: 2266 2267 2332 <
+4464: 2266 2332 2331 <
+4465: 2267 2268 2333 <
+4466: 2267 2333 2332 <
+4467: 2268 2269 2334 <
+4468: 2268 2334 2333 <
+4469: 2269 2270 2335 <
+4470: 2269 2335 2334 <
+4471: 2270 2271 2336 <
+4472: 2270 2336 2335 <
+4473: 2271 2272 2337 <
+4474: 2271 2337 2336 <
+4475: 2272 2273 2338 <
+4476: 2272 2338 2337 <
+4477: 2273 2274 2339 <
+4478: 2273 2339 2338 <
+4479: 2274 2275 2340 <
+4480: 2274 2340 2339 <
+4481: 2276 2277 2342 <
+4482: 2276 2342 2341 <
+4483: 2277 2278 2343 <
+4484: 2277 2343 2342 <
+4485: 2278 2279 2344 <
+4486: 2278 2344 2343 <
+4487: 2279 2280 2345 <
+4488: 2279 2345 2344 <
+4489: 2280 2281 2346 <
+4490: 2280 2346 2345 <
+4491: 2281 2282 2347 <
+4492: 2281 2347 2346 <
+4493: 2282 2283 2348 <
+4494: 2282 2348 2347 <
+4495: 2283 2284 2349 <
+4496: 2283 2349 2348 <
+4497: 2284 2285 2350 <
+4498: 2284 2350 2349 <
+4499: 2285 2286 2351 <
+4500: 2285 2351 2350 <
+4501: 2286 2287 2352 <
+4502: 2286 2352 2351 <
+4503: 2287 2288 2353 <
+4504: 2287 2353 2352 <
+4505: 2288 2289 2354 <
+4506: 2288 2354 2353 <
+4507: 2289 2290 2355 <
+4508: 2289 2355 2354 <
+4509: 2290 2291 2356 <
+4510: 2290 2356 2355 <
+4511: 2291 2292 2357 <
+4512: 2291 2357 2356 <
+4513: 2292 2293 2358 <
+4514: 2292 2358 2357 <
+4515: 2293 2294 2359 <
+4516: 2293 2359 2358 <
+4517: 2294 2295 2360 <
+4518: 2294 2360 2359 <
+4519: 2295 2296 2361 <
+4520: 2295 2361 2360 <
+4521: 2296 2297 2362 <
+4522: 2296 2362 2361 <
+4523: 2297 2298 2363 <
+4524: 2297 2363 2362 <
+4525: 2298 2299 2364 <
+4526: 2298 2364 2363 <
+4527: 2299 2300 2365 <
+4528: 2299 2365 2364 <
+4529: 2300 2301 2366 <
+4530: 2300 2366 2365 <
+4531: 2301 2302 2367 <
+4532: 2301 2367 2366 <
+4533: 2302 2303 2368 <
+4534: 2302 2368 2367 <
+4535: 2303 2304 2369 <
+4536: 2303 2369 2368 <
+4537: 2304 2305 2370 <
+4538: 2304 2370 2369 <
+4539: 2305 2306 2371 <
+4540: 2305 2371 2370 <
+4541: 2306 2307 2372 <
+4542: 2306 2372 2371 <
+4543: 2307 2308 2373 <
+4544: 2307 2373 2372 <
+4545: 2308 2309 2374 <
+4546: 2308 2374 2373 <
+4547: 2309 2310 2375 <
+4548: 2309 2375 2374 <
+4549: 2310 2311 2376 <
+4550: 2310 2376 2375 <
+4551: 2311 2312 2377 <
+4552: 2311 2377 2376 <
+4553: 2312 2313 2378 <
+4554: 2312 2378 2377 <
+4555: 2313 2314 2379 <
+4556: 2313 2379 2378 <
+4557: 2314 2315 2380 <
+4558: 2314 2380 2379 <
+4559: 2315 2316 2381 <
+4560: 2315 2381 2380 <
+4561: 2316 2317 2382 <
+4562: 2316 2382 2381 <
+4563: 2317 2318 2383 <
+4564: 2317 2383 2382 <
+4565: 2318 2319 2384 <
+4566: 2318 2384 2383 <
+4567: 2319 2320 2385 <
+4568: 2319 2385 2384 <
+4569: 2320 2321 2386 <
+4570: 2320 2386 2385 <
+4571: 2321 2322 2387 <
+4572: 2321 2387 2386 <
+4573: 2322 2323 2388 <
+4574: 2322 2388 2387 <
+4575: 2323 2324 2389 <
+4576: 2323 2389 2388 <
+4577: 2324 2325 2390 <
+4578: 2324 2390 2389 <
+4579: 2325 2326 2391 <
+4580: 2325 2391 2390 <
+4581: 2326 2327 2392 <
+4582: 2326 2392 2391 <
+4583: 2327 2328 2393 <
+4584: 2327 2393 2392 <
+4585: 2328 2329 2394 <
+4586: 2328 2394 2393 <
+4587: 2329 2330 2395 <
+4588: 2329 2395 2394 <
+4589: 2330 2331 2396 <
+4590: 2330 2396 2395 <
+4591: 2331 2332 2397 <
+4592: 2331 2397 2396 <
+4593: 2332 2333 2398 <
+4594: 2332 2398 2397 <
+4595: 2333 2334 2399 <
+4596: 2333 2399 2398 <
+4597: 2334 2335 2400 <
+4598: 2334 2400 2399 <
+4599: 2335 2336 2401 <
+4600: 2335 2401 2400 <
+4601: 2336 2337 2402 <
+4602: 2336 2402 2401 <
+4603: 2337 2338 2403 <
+4604: 2337 2403 2402 <
+4605: 2338 2339 2404 <
+4606: 2338 2404 2403 <
+4607: 2339 2340 2405 <
+4608: 2339 2405 2404 <
+4609: 2341 2342 2407 <
+4610: 2341 2407 2406 <
+4611: 2342 2343 2408 <
+4612: 2342 2408 2407 <
+4613: 2343 2344 2409 <
+4614: 2343 2409 2408 <
+4615: 2344 2345 2410 <
+4616: 2344 2410 2409 <
+4617: 2345 2346 2411 <
+4618: 2345 2411 2410 <
+4619: 2346 2347 2412 <
+4620: 2346 2412 2411 <
+4621: 2347 2348 2413 <
+4622: 2347 2413 2412 <
+4623: 2348 2349 2414 <
+4624: 2348 2414 2413 <
+4625: 2349 2350 2415 <
+4626: 2349 2415 2414 <
+4627: 2350 2351 2416 <
+4628: 2350 2416 2415 <
+4629: 2351 2352 2417 <
+4630: 2351 2417 2416 <
+4631: 2352 2353 2418 <
+4632: 2352 2418 2417 <
+4633: 2353 2354 2419 <
+4634: 2353 2419 2418 <
+4635: 2354 2355 2420 <
+4636: 2354 2420 2419 <
+4637: 2355 2356 2421 <
+4638: 2355 2421 2420 <
+4639: 2356 2357 2422 <
+4640: 2356 2422 2421 <
+4641: 2357 2358 2423 <
+4642: 2357 2423 2422 <
+4643: 2358 2359 2424 <
+4644: 2358 2424 2423 <
+4645: 2359 2360 2425 <
+4646: 2359 2425 2424 <
+4647: 2360 2361 2426 <
+4648: 2360 2426 2425 <
+4649: 2361 2362 2427 <
+4650: 2361 2427 2426 <
+4651: 2362 2363 2428 <
+4652: 2362 2428 2427 <
+4653: 2363 2364 2429 <
+4654: 2363 2429 2428 <
+4655: 2364 2365 2430 <
+4656: 2364 2430 2429 <
+4657: 2365 2366 2431 <
+4658: 2365 2431 2430 <
+4659: 2366 2367 2432 <
+4660: 2366 2432 2431 <
+4661: 2367 2368 2433 <
+4662: 2367 2433 2432 <
+4663: 2368 2369 2434 <
+4664: 2368 2434 2433 <
+4665: 2369 2370 2435 <
+4666: 2369 2435 2434 <
+4667: 2370 2371 2436 <
+4668: 2370 2436 2435 <
+4669: 2371 2372 2437 <
+4670: 2371 2437 2436 <
+4671: 2372 2373 2438 <
+4672: 2372 2438 2437 <
+4673: 2373 2374 2439 <
+4674: 2373 2439 2438 <
+4675: 2374 2375 2440 <
+4676: 2374 2440 2439 <
+4677: 2375 2376 2441 <
+4678: 2375 2441 2440 <
+4679: 2376 2377 2442 <
+4680: 2376 2442 2441 <
+4681: 2377 2378 2443 <
+4682: 2377 2443 2442 <
+4683: 2378 2379 2444 <
+4684: 2378 2444 2443 <
+4685: 2379 2380 2445 <
+4686: 2379 2445 2444 <
+4687: 2380 2381 2446 <
+4688: 2380 2446 2445 <
+4689: 2381 2382 2447 <
+4690: 2381 2447 2446 <
+4691: 2382 2383 2448 <
+4692: 2382 2448 2447 <
+4693: 2383 2384 2449 <
+4694: 2383 2449 2448 <
+4695: 2384 2385 2450 <
+4696: 2384 2450 2449 <
+4697: 2385 2386 2451 <
+4698: 2385 2451 2450 <
+4699: 2386 2387 2452 <
+4700: 2386 2452 2451 <
+4701: 2387 2388 2453 <
+4702: 2387 2453 2452 <
+4703: 2388 2389 2454 <
+4704: 2388 2454 2453 <
+4705: 2389 2390 2455 <
+4706: 2389 2455 2454 <
+4707: 2390 2391 2456 <
+4708: 2390 2456 2455 <
+4709: 2391 2392 2457 <
+4710: 2391 2457 2456 <
+4711: 2392 2393 2458 <
+4712: 2392 2458 2457 <
+4713: 2393 2394 2459 <
+4714: 2393 2459 2458 <
+4715: 2394 2395 2460 <
+4716: 2394 2460 2459 <
+4717: 2395 2396 2461 <
+4718: 2395 2461 2460 <
+4719: 2396 2397 2462 <
+4720: 2396 2462 2461 <
+4721: 2397 2398 2463 <
+4722: 2397 2463 2462 <
+4723: 2398 2399 2464 <
+4724: 2398 2464 2463 <
+4725: 2399 2400 2465 <
+4726: 2399 2465 2464 <
+4727: 2400 2401 2466 <
+4728: 2400 2466 2465 <
+4729: 2401 2402 2467 <
+4730: 2401 2467 2466 <
+4731: 2402 2403 2468 <
+4732: 2402 2468 2467 <
+4733: 2403 2404 2469 <
+4734: 2403 2469 2468 <
+4735: 2404 2405 2470 <
+4736: 2404 2470 2469 <
+4737: 2406 2407 2472 <
+4738: 2406 2472 2471 <
+4739: 2407 2408 2473 <
+4740: 2407 2473 2472 <
+4741: 2408 2409 2474 <
+4742: 2408 2474 2473 <
+4743: 2409 2410 2475 <
+4744: 2409 2475 2474 <
+4745: 2410 2411 2476 <
+4746: 2410 2476 2475 <
+4747: 2411 2412 2477 <
+4748: 2411 2477 2476 <
+4749: 2412 2413 2478 <
+4750: 2412 2478 2477 <
+4751: 2413 2414 2479 <
+4752: 2413 2479 2478 <
+4753: 2414 2415 2480 <
+4754: 2414 2480 2479 <
+4755: 2415 2416 2481 <
+4756: 2415 2481 2480 <
+4757: 2416 2417 2482 <
+4758: 2416 2482 2481 <
+4759: 2417 2418 2483 <
+4760: 2417 2483 2482 <
+4761: 2418 2419 2484 <
+4762: 2418 2484 2483 <
+4763: 2419 2420 2485 <
+4764: 2419 2485 2484 <
+4765: 2420 2421 2486 <
+4766: 2420 2486 2485 <
+4767: 2421 2422 2487 <
+4768: 2421 2487 2486 <
+4769: 2422 2423 2488 <
+4770: 2422 2488 2487 <
+4771: 2423 2424 2489 <
+4772: 2423 2489 2488 <
+4773: 2424 2425 2490 <
+4774: 2424 2490 2489 <
+4775: 2425 2426 2491 <
+4776: 2425 2491 2490 <
+4777: 2426 2427 2492 <
+4778: 2426 2492 2491 <
+4779: 2427 2428 2493 <
+4780: 2427 2493 2492 <
+4781: 2428 2429 2494 <
+4782: 2428 2494 2493 <
+4783: 2429 2430 2495 <
+4784: 2429 2495 2494 <
+4785: 2430 2431 2496 <
+4786: 2430 2496 2495 <
+4787: 2431 2432 2497 <
+4788: 2431 2497 2496 <
+4789: 2432 2433 2498 <
+4790: 2432 2498 2497 <
+4791: 2433 2434 2499 <
+4792: 2433 2499 2498 <
+4793: 2434 2435 2500 <
+4794: 2434 2500 2499 <
+4795: 2435 2436 2501 <
+4796: 2435 2501 2500 <
+4797: 2436 2437 2502 <
+4798: 2436 2502 2501 <
+4799: 2437 2438 2503 <
+4800: 2437 2503 2502 <
+4801: 2438 2439 2504 <
+4802: 2438 2504 2503 <
+4803: 2439 2440 2505 <
+4804: 2439 2505 2504 <
+4805: 2440 2441 2506 <
+4806: 2440 2506 2505 <
+4807: 2441 2442 2507 <
+4808: 2441 2507 2506 <
+4809: 2442 2443 2508 <
+4810: 2442 2508 2507 <
+4811: 2443 2444 2509 <
+4812: 2443 2509 2508 <
+4813: 2444 2445 2510 <
+4814: 2444 2510 2509 <
+4815: 2445 2446 2511 <
+4816: 2445 2511 2510 <
+4817: 2446 2447 2512 <
+4818: 2446 2512 2511 <
+4819: 2447 2448 2513 <
+4820: 2447 2513 2512 <
+4821: 2448 2449 2514 <
+4822: 2448 2514 2513 <
+4823: 2449 2450 2515 <
+4824: 2449 2515 2514 <
+4825: 2450 2451 2516 <
+4826: 2450 2516 2515 <
+4827: 2451 2452 2517 <
+4828: 2451 2517 2516 <
+4829: 2452 2453 2518 <
+4830: 2452 2518 2517 <
+4831: 2453 2454 2519 <
+4832: 2453 2519 2518 <
+4833: 2454 2455 2520 <
+4834: 2454 2520 2519 <
+4835: 2455 2456 2521 <
+4836: 2455 2521 2520 <
+4837: 2456 2457 2522 <
+4838: 2456 2522 2521 <
+4839: 2457 2458 2523 <
+4840: 2457 2523 2522 <
+4841: 2458 2459 2524 <
+4842: 2458 2524 2523 <
+4843: 2459 2460 2525 <
+4844: 2459 2525 2524 <
+4845: 2460 2461 2526 <
+4846: 2460 2526 2525 <
+4847: 2461 2462 2527 <
+4848: 2461 2527 2526 <
+4849: 2462 2463 2528 <
+4850: 2462 2528 2527 <
+4851: 2463 2464 2529 <
+4852: 2463 2529 2528 <
+4853: 2464 2465 2530 <
+4854: 2464 2530 2529 <
+4855: 2465 2466 2531 <
+4856: 2465 2531 2530 <
+4857: 2466 2467 2532 <
+4858: 2466 2532 2531 <
+4859: 2467 2468 2533 <
+4860: 2467 2533 2532 <
+4861: 2468 2469 2534 <
+4862: 2468 2534 2533 <
+4863: 2469 2470 2535 <
+4864: 2469 2535 2534 <
+4865: 2471 2472 2537 <
+4866: 2471 2537 2536 <
+4867: 2472 2473 2538 <
+4868: 2472 2538 2537 <
+4869: 2473 2474 2539 <
+4870: 2473 2539 2538 <
+4871: 2474 2475 2540 <
+4872: 2474 2540 2539 <
+4873: 2475 2476 2541 <
+4874: 2475 2541 2540 <
+4875: 2476 2477 2542 <
+4876: 2476 2542 2541 <
+4877: 2477 2478 2543 <
+4878: 2477 2543 2542 <
+4879: 2478 2479 2544 <
+4880: 2478 2544 2543 <
+4881: 2479 2480 2545 <
+4882: 2479 2545 2544 <
+4883: 2480 2481 2546 <
+4884: 2480 2546 2545 <
+4885: 2481 2482 2547 <
+4886: 2481 2547 2546 <
+4887: 2482 2483 2548 <
+4888: 2482 2548 2547 <
+4889: 2483 2484 2549 <
+4890: 2483 2549 2548 <
+4891: 2484 2485 2550 <
+4892: 2484 2550 2549 <
+4893: 2485 2486 2551 <
+4894: 2485 2551 2550 <
+4895: 2486 2487 2552 <
+4896: 2486 2552 2551 <
+4897: 2487 2488 2553 <
+4898: 2487 2553 2552 <
+4899: 2488 2489 2554 <
+4900: 2488 2554 2553 <
+4901: 2489 2490 2555 <
+4902: 2489 2555 2554 <
+4903: 2490 2491 2556 <
+4904: 2490 2556 2555 <
+4905: 2491 2492 2557 <
+4906: 2491 2557 2556 <
+4907: 2492 2493 2558 <
+4908: 2492 2558 2557 <
+4909: 2493 2494 2559 <
+4910: 2493 2559 2558 <
+4911: 2494 2495 2560 <
+4912: 2494 2560 2559 <
+4913: 2495 2496 2561 <
+4914: 2495 2561 2560 <
+4915: 2496 2497 2562 <
+4916: 2496 2562 2561 <
+4917: 2497 2498 2563 <
+4918: 2497 2563 2562 <
+4919: 2498 2499 2564 <
+4920: 2498 2564 2563 <
+4921: 2499 2500 2565 <
+4922: 2499 2565 2564 <
+4923: 2500 2501 2566 <
+4924: 2500 2566 2565 <
+4925: 2501 2502 2567 <
+4926: 2501 2567 2566 <
+4927: 2502 2503 2568 <
+4928: 2502 2568 2567 <
+4929: 2503 2504 2569 <
+4930: 2503 2569 2568 <
+4931: 2504 2505 2570 <
+4932: 2504 2570 2569 <
+4933: 2505 2506 2571 <
+4934: 2505 2571 2570 <
+4935: 2506 2507 2572 <
+4936: 2506 2572 2571 <
+4937: 2507 2508 2573 <
+4938: 2507 2573 2572 <
+4939: 2508 2509 2574 <
+4940: 2508 2574 2573 <
+4941: 2509 2510 2575 <
+4942: 2509 2575 2574 <
+4943: 2510 2511 2576 <
+4944: 2510 2576 2575 <
+4945: 2511 2512 2577 <
+4946: 2511 2577 2576 <
+4947: 2512 2513 2578 <
+4948: 2512 2578 2577 <
+4949: 2513 2514 2579 <
+4950: 2513 2579 2578 <
+4951: 2514 2515 2580 <
+4952: 2514 2580 2579 <
+4953: 2515 2516 2581 <
+4954: 2515 2581 2580 <
+4955: 2516 2517 2582 <
+4956: 2516 2582 2581 <
+4957: 2517 2518 2583 <
+4958: 2517 2583 2582 <
+4959: 2518 2519 2584 <
+4960: 2518 2584 2583 <
+4961: 2519 2520 2585 <
+4962: 2519 2585 2584 <
+4963: 2520 2521 2586 <
+4964: 2520 2586 2585 <
+4965: 2521 2522 2587 <
+4966: 2521 2587 2586 <
+4967: 2522 2523 2588 <
+4968: 2522 2588 2587 <
+4969: 2523 2524 2589 <
+4970: 2523 2589 2588 <
+4971: 2524 2525 2590 <
+4972: 2524 2590 2589 <
+4973: 2525 2526 2591 <
+4974: 2525 2591 2590 <
+4975: 2526 2527 2592 <
+4976: 2526 2592 2591 <
+4977: 2527 2528 2593 <
+4978: 2527 2593 2592 <
+4979: 2528 2529 2594 <
+4980: 2528 2594 2593 <
+4981: 2529 2530 2595 <
+4982: 2529 2595 2594 <
+4983: 2530 2531 2596 <
+4984: 2530 2596 2595 <
+4985: 2531 2532 2597 <
+4986: 2531 2597 2596 <
+4987: 2532 2533 2598 <
+4988: 2532 2598 2597 <
+4989: 2533 2534 2599 <
+4990: 2533 2599 2598 <
+4991: 2534 2535 2600 <
+4992: 2534 2600 2599 <
+4993: 2536 2537 2602 <
+4994: 2536 2602 2601 <
+4995: 2537 2538 2603 <
+4996: 2537 2603 2602 <
+4997: 2538 2539 2604 <
+4998: 2538 2604 2603 <
+4999: 2539 2540 2605 <
+5000: 2539 2605 2604 <
+5001: 2540 2541 2606 <
+5002: 2540 2606 2605 <
+5003: 2541 2542 2607 <
+5004: 2541 2607 2606 <
+5005: 2542 2543 2608 <
+5006: 2542 2608 2607 <
+5007: 2543 2544 2609 <
+5008: 2543 2609 2608 <
+5009: 2544 2545 2610 <
+5010: 2544 2610 2609 <
+5011: 2545 2546 2611 <
+5012: 2545 2611 2610 <
+5013: 2546 2547 2612 <
+5014: 2546 2612 2611 <
+5015: 2547 2548 2613 <
+5016: 2547 2613 2612 <
+5017: 2548 2549 2614 <
+5018: 2548 2614 2613 <
+5019: 2549 2550 2615 <
+5020: 2549 2615 2614 <
+5021: 2550 2551 2616 <
+5022: 2550 2616 2615 <
+5023: 2551 2552 2617 <
+5024: 2551 2617 2616 <
+5025: 2552 2553 2618 <
+5026: 2552 2618 2617 <
+5027: 2553 2554 2619 <
+5028: 2553 2619 2618 <
+5029: 2554 2555 2620 <
+5030: 2554 2620 2619 <
+5031: 2555 2556 2621 <
+5032: 2555 2621 2620 <
+5033: 2556 2557 2622 <
+5034: 2556 2622 2621 <
+5035: 2557 2558 2623 <
+5036: 2557 2623 2622 <
+5037: 2558 2559 2624 <
+5038: 2558 2624 2623 <
+5039: 2559 2560 2625 <
+5040: 2559 2625 2624 <
+5041: 2560 2561 2626 <
+5042: 2560 2626 2625 <
+5043: 2561 2562 2627 <
+5044: 2561 2627 2626 <
+5045: 2562 2563 2628 <
+5046: 2562 2628 2627 <
+5047: 2563 2564 2629 <
+5048: 2563 2629 2628 <
+5049: 2564 2565 2630 <
+5050: 2564 2630 2629 <
+5051: 2565 2566 2631 <
+5052: 2565 2631 2630 <
+5053: 2566 2567 2632 <
+5054: 2566 2632 2631 <
+5055: 2567 2568 2633 <
+5056: 2567 2633 2632 <
+5057: 2568 2569 2634 <
+5058: 2568 2634 2633 <
+5059: 2569 2570 2635 <
+5060: 2569 2635 2634 <
+5061: 2570 2571 2636 <
+5062: 2570 2636 2635 <
+5063: 2571 2572 2637 <
+5064: 2571 2637 2636 <
+5065: 2572 2573 2638 <
+5066: 2572 2638 2637 <
+5067: 2573 2574 2639 <
+5068: 2573 2639 2638 <
+5069: 2574 2575 2640 <
+5070: 2574 2640 2639 <
+5071: 2575 2576 2641 <
+5072: 2575 2641 2640 <
+5073: 2576 2577 2642 <
+5074: 2576 2642 2641 <
+5075: 2577 2578 2643 <
+5076: 2577 2643 2642 <
+5077: 2578 2579 2644 <
+5078: 2578 2644 2643 <
+5079: 2579 2580 2645 <
+5080: 2579 2645 2644 <
+5081: 2580 2581 2646 <
+5082: 2580 2646 2645 <
+5083: 2581 2582 2647 <
+5084: 2581 2647 2646 <
+5085: 2582 2583 2648 <
+5086: 2582 2648 2647 <
+5087: 2583 2584 2649 <
+5088: 2583 2649 2648 <
+5089: 2584 2585 2650 <
+5090: 2584 2650 2649 <
+5091: 2585 2586 2651 <
+5092: 2585 2651 2650 <
+5093: 2586 2587 2652 <
+5094: 2586 2652 2651 <
+5095: 2587 2588 2653 <
+5096: 2587 2653 2652 <
+5097: 2588 2589 2654 <
+5098: 2588 2654 2653 <
+5099: 2589 2590 2655 <
+5100: 2589 2655 2654 <
+5101: 2590 2591 2656 <
+5102: 2590 2656 2655 <
+5103: 2591 2592 2657 <
+5104: 2591 2657 2656 <
+5105: 2592 2593 2658 <
+5106: 2592 2658 2657 <
+5107: 2593 2594 2659 <
+5108: 2593 2659 2658 <
+5109: 2594 2595 2660 <
+5110: 2594 2660 2659 <
+5111: 2595 2596 2661 <
+5112: 2595 2661 2660 <
+5113: 2596 2597 2662 <
+5114: 2596 2662 2661 <
+5115: 2597 2598 2663 <
+5116: 2597 2663 2662 <
+5117: 2598 2599 2664 <
+5118: 2598 2664 2663 <
+5119: 2599 2600 2665 <
+5120: 2599 2665 2664 <
+5121: 2601 2602 2667 <
+5122: 2601 2667 2666 <
+5123: 2602 2603 2668 <
+5124: 2602 2668 2667 <
+5125: 2603 2604 2669 <
+5126: 2603 2669 2668 <
+5127: 2604 2605 2670 <
+5128: 2604 2670 2669 <
+5129: 2605 2606 2671 <
+5130: 2605 2671 2670 <
+5131: 2606 2607 2672 <
+5132: 2606 2672 2671 <
+5133: 2607 2608 2673 <
+5134: 2607 2673 2672 <
+5135: 2608 2609 2674 <
+5136: 2608 2674 2673 <
+5137: 2609 2610 2675 <
+5138: 2609 2675 2674 <
+5139: 2610 2611 2676 <
+5140: 2610 2676 2675 <
+5141: 2611 2612 2677 <
+5142: 2611 2677 2676 <
+5143: 2612 2613 2678 <
+5144: 2612 2678 2677 <
+5145: 2613 2614 2679 <
+5146: 2613 2679 2678 <
+5147: 2614 2615 2680 <
+5148: 2614 2680 2679 <
+5149: 2615 2616 2681 <
+5150: 2615 2681 2680 <
+5151: 2616 2617 2682 <
+5152: 2616 2682 2681 <
+5153: 2617 2618 2683 <
+5154: 2617 2683 2682 <
+5155: 2618 2619 2684 <
+5156: 2618 2684 2683 <
+5157: 2619 2620 2685 <
+5158: 2619 2685 2684 <
+5159: 2620 2621 2686 <
+5160: 2620 2686 2685 <
+5161: 2621 2622 2687 <
+5162: 2621 2687 2686 <
+5163: 2622 2623 2688 <
+5164: 2622 2688 2687 <
+5165: 2623 2624 2689 <
+5166: 2623 2689 2688 <
+5167: 2624 2625 2690 <
+5168: 2624 2690 2689 <
+5169: 2625 2626 2691 <
+5170: 2625 2691 2690 <
+5171: 2626 2627 2692 <
+5172: 2626 2692 2691 <
+5173: 2627 2628 2693 <
+5174: 2627 2693 2692 <
+5175: 2628 2629 2694 <
+5176: 2628 2694 2693 <
+5177: 2629 2630 2695 <
+5178: 2629 2695 2694 <
+5179: 2630 2631 2696 <
+5180: 2630 2696 2695 <
+5181: 2631 2632 2697 <
+5182: 2631 2697 2696 <
+5183: 2632 2633 2698 <
+5184: 2632 2698 2697 <
+5185: 2633 2634 2699 <
+5186: 2633 2699 2698 <
+5187: 2634 2635 2700 <
+5188: 2634 2700 2699 <
+5189: 2635 2636 2701 <
+5190: 2635 2701 2700 <
+5191: 2636 2637 2702 <
+5192: 2636 2702 2701 <
+5193: 2637 2638 2703 <
+5194: 2637 2703 2702 <
+5195: 2638 2639 2704 <
+5196: 2638 2704 2703 <
+5197: 2639 2640 2705 <
+5198: 2639 2705 2704 <
+5199: 2640 2641 2706 <
+5200: 2640 2706 2705 <
+5201: 2641 2642 2707 <
+5202: 2641 2707 2706 <
+5203: 2642 2643 2708 <
+5204: 2642 2708 2707 <
+5205: 2643 2644 2709 <
+5206: 2643 2709 2708 <
+5207: 2644 2645 2710 <
+5208: 2644 2710 2709 <
+5209: 2645 2646 2711 <
+5210: 2645 2711 2710 <
+5211: 2646 2647 2712 <
+5212: 2646 2712 2711 <
+5213: 2647 2648 2713 <
+5214: 2647 2713 2712 <
+5215: 2648 2649 2714 <
+5216: 2648 2714 2713 <
+5217: 2649 2650 2715 <
+5218: 2649 2715 2714 <
+5219: 2650 2651 2716 <
+5220: 2650 2716 2715 <
+5221: 2651 2652 2717 <
+5222: 2651 2717 2716 <
+5223: 2652 2653 2718 <
+5224: 2652 2718 2717 <
+5225: 2653 2654 2719 <
+5226: 2653 2719 2718 <
+5227: 2654 2655 2720 <
+5228: 2654 2720 2719 <
+5229: 2655 2656 2721 <
+5230: 2655 2721 2720 <
+5231: 2656 2657 2722 <
+5232: 2656 2722 2721 <
+5233: 2657 2658 2723 <
+5234: 2657 2723 2722 <
+5235: 2658 2659 2724 <
+5236: 2658 2724 2723 <
+5237: 2659 2660 2725 <
+5238: 2659 2725 2724 <
+5239: 2660 2661 2726 <
+5240: 2660 2726 2725 <
+5241: 2661 2662 2727 <
+5242: 2661 2727 2726 <
+5243: 2662 2663 2728 <
+5244: 2662 2728 2727 <
+5245: 2663 2664 2729 <
+5246: 2663 2729 2728 <
+5247: 2664 2665 2730 <
+5248: 2664 2730 2729 <
+5249: 2666 2667 2732 <
+5250: 2666 2732 2731 <
+5251: 2667 2668 2733 <
+5252: 2667 2733 2732 <
+5253: 2668 2669 2734 <
+5254: 2668 2734 2733 <
+5255: 2669 2670 2735 <
+5256: 2669 2735 2734 <
+5257: 2670 2671 2736 <
+5258: 2670 2736 2735 <
+5259: 2671 2672 2737 <
+5260: 2671 2737 2736 <
+5261: 2672 2673 2738 <
+5262: 2672 2738 2737 <
+5263: 2673 2674 2739 <
+5264: 2673 2739 2738 <
+5265: 2674 2675 2740 <
+5266: 2674 2740 2739 <
+5267: 2675 2676 2741 <
+5268: 2675 2741 2740 <
+5269: 2676 2677 2742 <
+5270: 2676 2742 2741 <
+5271: 2677 2678 2743 <
+5272: 2677 2743 2742 <
+5273: 2678 2679 2744 <
+5274: 2678 2744 2743 <
+5275: 2679 2680 2745 <
+5276: 2679 2745 2744 <
+5277: 2680 2681 2746 <
+5278: 2680 2746 2745 <
+5279: 2681 2682 2747 <
+5280: 2681 2747 2746 <
+5281: 2682 2683 2748 <
+5282: 2682 2748 2747 <
+5283: 2683 2684 2749 <
+5284: 2683 2749 2748 <
+5285: 2684 2685 2750 <
+5286: 2684 2750 2749 <
+5287: 2685 2686 2751 <
+5288: 2685 2751 2750 <
+5289: 2686 2687 2752 <
+5290: 2686 2752 2751 <
+5291: 2687 2688 2753 <
+5292: 2687 2753 2752 <
+5293: 2688 2689 2754 <
+5294: 2688 2754 2753 <
+5295: 2689 2690 2755 <
+5296: 2689 2755 2754 <
+5297: 2690 2691 2756 <
+5298: 2690 2756 2755 <
+5299: 2691 2692 2757 <
+5300: 2691 2757 2756 <
+5301: 2692 2693 2758 <
+5302: 2692 2758 2757 <
+5303: 2693 2694 2759 <
+5304: 2693 2759 2758 <
+5305: 2694 2695 2760 <
+5306: 2694 2760 2759 <
+5307: 2695 2696 2761 <
+5308: 2695 2761 2760 <
+5309: 2696 2697 2762 <
+5310: 2696 2762 2761 <
+5311: 2697 2698 2763 <
+5312: 2697 2763 2762 <
+5313: 2698 2699 2764 <
+5314: 2698 2764 2763 <
+5315: 2699 2700 2765 <
+5316: 2699 2765 2764 <
+5317: 2700 2701 2766 <
+5318: 2700 2766 2765 <
+5319: 2701 2702 2767 <
+5320: 2701 2767 2766 <
+5321: 2702 2703 2768 <
+5322: 2702 2768 2767 <
+5323: 2703 2704 2769 <
+5324: 2703 2769 2768 <
+5325: 2704 2705 2770 <
+5326: 2704 2770 2769 <
+5327: 2705 2706 2771 <
+5328: 2705 2771 2770 <
+5329: 2706 2707 2772 <
+5330: 2706 2772 2771 <
+5331: 2707 2708 2773 <
+5332: 2707 2773 2772 <
+5333: 2708 2709 2774 <
+5334: 2708 2774 2773 <
+5335: 2709 2710 2775 <
+5336: 2709 2775 2774 <
+5337: 2710 2711 2776 <
+5338: 2710 2776 2775 <
+5339: 2711 2712 2777 <
+5340: 2711 2777 2776 <
+5341: 2712 2713 2778 <
+5342: 2712 2778 2777 <
+5343: 2713 2714 2779 <
+5344: 2713 2779 2778 <
+5345: 2714 2715 2780 <
+5346: 2714 2780 2779 <
+5347: 2715 2716 2781 <
+5348: 2715 2781 2780 <
+5349: 2716 2717 2782 <
+5350: 2716 2782 2781 <
+5351: 2717 2718 2783 <
+5352: 2717 2783 2782 <
+5353: 2718 2719 2784 <
+5354: 2718 2784 2783 <
+5355: 2719 2720 2785 <
+5356: 2719 2785 2784 <
+5357: 2720 2721 2786 <
+5358: 2720 2786 2785 <
+5359: 2721 2722 2787 <
+5360: 2721 2787 2786 <
+5361: 2722 2723 2788 <
+5362: 2722 2788 2787 <
+5363: 2723 2724 2789 <
+5364: 2723 2789 2788 <
+5365: 2724 2725 2790 <
+5366: 2724 2790 2789 <
+5367: 2725 2726 2791 <
+5368: 2725 2791 2790 <
+5369: 2726 2727 2792 <
+5370: 2726 2792 2791 <
+5371: 2727 2728 2793 <
+5372: 2727 2793 2792 <
+5373: 2728 2729 2794 <
+5374: 2728 2794 2793 <
+5375: 2729 2730 2795 <
+5376: 2729 2795 2794 <
+5377: 2731 2732 2797 <
+5378: 2731 2797 2796 <
+5379: 2732 2733 2798 <
+5380: 2732 2798 2797 <
+5381: 2733 2734 2799 <
+5382: 2733 2799 2798 <
+5383: 2734 2735 2800 <
+5384: 2734 2800 2799 <
+5385: 2735 2736 2801 <
+5386: 2735 2801 2800 <
+5387: 2736 2737 2802 <
+5388: 2736 2802 2801 <
+5389: 2737 2738 2803 <
+5390: 2737 2803 2802 <
+5391: 2738 2739 2804 <
+5392: 2738 2804 2803 <
+5393: 2739 2740 2805 <
+5394: 2739 2805 2804 <
+5395: 2740 2741 2806 <
+5396: 2740 2806 2805 <
+5397: 2741 2742 2807 <
+5398: 2741 2807 2806 <
+5399: 2742 2743 2808 <
+5400: 2742 2808 2807 <
+5401: 2743 2744 2809 <
+5402: 2743 2809 2808 <
+5403: 2744 2745 2810 <
+5404: 2744 2810 2809 <
+5405: 2745 2746 2811 <
+5406: 2745 2811 2810 <
+5407: 2746 2747 2812 <
+5408: 2746 2812 2811 <
+5409: 2747 2748 2813 <
+5410: 2747 2813 2812 <
+5411: 2748 2749 2814 <
+5412: 2748 2814 2813 <
+5413: 2749 2750 2815 <
+5414: 2749 2815 2814 <
+5415: 2750 2751 2816 <
+5416: 2750 2816 2815 <
+5417: 2751 2752 2817 <
+5418: 2751 2817 2816 <
+5419: 2752 2753 2818 <
+5420: 2752 2818 2817 <
+5421: 2753 2754 2819 <
+5422: 2753 2819 2818 <
+5423: 2754 2755 2820 <
+5424: 2754 2820 2819 <
+5425: 2755 2756 2821 <
+5426: 2755 2821 2820 <
+5427: 2756 2757 2822 <
+5428: 2756 2822 2821 <
+5429: 2757 2758 2823 <
+5430: 2757 2823 2822 <
+5431: 2758 2759 2824 <
+5432: 2758 2824 2823 <
+5433: 2759 2760 2825 <
+5434: 2759 2825 2824 <
+5435: 2760 2761 2826 <
+5436: 2760 2826 2825 <
+5437: 2761 2762 2827 <
+5438: 2761 2827 2826 <
+5439: 2762 2763 2828 <
+5440: 2762 2828 2827 <
+5441: 2763 2764 2829 <
+5442: 2763 2829 2828 <
+5443: 2764 2765 2830 <
+5444: 2764 2830 2829 <
+5445: 2765 2766 2831 <
+5446: 2765 2831 2830 <
+5447: 2766 2767 2832 <
+5448: 2766 2832 2831 <
+5449: 2767 2768 2833 <
+5450: 2767 2833 2832 <
+5451: 2768 2769 2834 <
+5452: 2768 2834 2833 <
+5453: 2769 2770 2835 <
+5454: 2769 2835 2834 <
+5455: 2770 2771 2836 <
+5456: 2770 2836 2835 <
+5457: 2771 2772 2837 <
+5458: 2771 2837 2836 <
+5459: 2772 2773 2838 <
+5460: 2772 2838 2837 <
+5461: 2773 2774 2839 <
+5462: 2773 2839 2838 <
+5463: 2774 2775 2840 <
+5464: 2774 2840 2839 <
+5465: 2775 2776 2841 <
+5466: 2775 2841 2840 <
+5467: 2776 2777 2842 <
+5468: 2776 2842 2841 <
+5469: 2777 2778 2843 <
+5470: 2777 2843 2842 <
+5471: 2778 2779 2844 <
+5472: 2778 2844 2843 <
+5473: 2779 2780 2845 <
+5474: 2779 2845 2844 <
+5475: 2780 2781 2846 <
+5476: 2780 2846 2845 <
+5477: 2781 2782 2847 <
+5478: 2781 2847 2846 <
+5479: 2782 2783 2848 <
+5480: 2782 2848 2847 <
+5481: 2783 2784 2849 <
+5482: 2783 2849 2848 <
+5483: 2784 2785 2850 <
+5484: 2784 2850 2849 <
+5485: 2785 2786 2851 <
+5486: 2785 2851 2850 <
+5487: 2786 2787 2852 <
+5488: 2786 2852 2851 <
+5489: 2787 2788 2853 <
+5490: 2787 2853 2852 <
+5491: 2788 2789 2854 <
+5492: 2788 2854 2853 <
+5493: 2789 2790 2855 <
+5494: 2789 2855 2854 <
+5495: 2790 2791 2856 <
+5496: 2790 2856 2855 <
+5497: 2791 2792 2857 <
+5498: 2791 2857 2856 <
+5499: 2792 2793 2858 <
+5500: 2792 2858 2857 <
+5501: 2793 2794 2859 <
+5502: 2793 2859 2858 <
+5503: 2794 2795 2860 <
+5504: 2794 2860 2859 <
+5505: 2796 2797 2862 <
+5506: 2796 2862 2861 <
+5507: 2797 2798 2863 <
+5508: 2797 2863 2862 <
+5509: 2798 2799 2864 <
+5510: 2798 2864 2863 <
+5511: 2799 2800 2865 <
+5512: 2799 2865 2864 <
+5513: 2800 2801 2866 <
+5514: 2800 2866 2865 <
+5515: 2801 2802 2867 <
+5516: 2801 2867 2866 <
+5517: 2802 2803 2868 <
+5518: 2802 2868 2867 <
+5519: 2803 2804 2869 <
+5520: 2803 2869 2868 <
+5521: 2804 2805 2870 <
+5522: 2804 2870 2869 <
+5523: 2805 2806 2871 <
+5524: 2805 2871 2870 <
+5525: 2806 2807 2872 <
+5526: 2806 2872 2871 <
+5527: 2807 2808 2873 <
+5528: 2807 2873 2872 <
+5529: 2808 2809 2874 <
+5530: 2808 2874 2873 <
+5531: 2809 2810 2875 <
+5532: 2809 2875 2874 <
+5533: 2810 2811 2876 <
+5534: 2810 2876 2875 <
+5535: 2811 2812 2877 <
+5536: 2811 2877 2876 <
+5537: 2812 2813 2878 <
+5538: 2812 2878 2877 <
+5539: 2813 2814 2879 <
+5540: 2813 2879 2878 <
+5541: 2814 2815 2880 <
+5542: 2814 2880 2879 <
+5543: 2815 2816 2881 <
+5544: 2815 2881 2880 <
+5545: 2816 2817 2882 <
+5546: 2816 2882 2881 <
+5547: 2817 2818 2883 <
+5548: 2817 2883 2882 <
+5549: 2818 2819 2884 <
+5550: 2818 2884 2883 <
+5551: 2819 2820 2885 <
+5552: 2819 2885 2884 <
+5553: 2820 2821 2886 <
+5554: 2820 2886 2885 <
+5555: 2821 2822 2887 <
+5556: 2821 2887 2886 <
+5557: 2822 2823 2888 <
+5558: 2822 2888 2887 <
+5559: 2823 2824 2889 <
+5560: 2823 2889 2888 <
+5561: 2824 2825 2890 <
+5562: 2824 2890 2889 <
+5563: 2825 2826 2891 <
+5564: 2825 2891 2890 <
+5565: 2826 2827 2892 <
+5566: 2826 2892 2891 <
+5567: 2827 2828 2893 <
+5568: 2827 2893 2892 <
+5569: 2828 2829 2894 <
+5570: 2828 2894 2893 <
+5571: 2829 2830 2895 <
+5572: 2829 2895 2894 <
+5573: 2830 2831 2896 <
+5574: 2830 2896 2895 <
+5575: 2831 2832 2897 <
+5576: 2831 2897 2896 <
+5577: 2832 2833 2898 <
+5578: 2832 2898 2897 <
+5579: 2833 2834 2899 <
+5580: 2833 2899 2898 <
+5581: 2834 2835 2900 <
+5582: 2834 2900 2899 <
+5583: 2835 2836 2901 <
+5584: 2835 2901 2900 <
+5585: 2836 2837 2902 <
+5586: 2836 2902 2901 <
+5587: 2837 2838 2903 <
+5588: 2837 2903 2902 <
+5589: 2838 2839 2904 <
+5590: 2838 2904 2903 <
+5591: 2839 2840 2905 <
+5592: 2839 2905 2904 <
+5593: 2840 2841 2906 <
+5594: 2840 2906 2905 <
+5595: 2841 2842 2907 <
+5596: 2841 2907 2906 <
+5597: 2842 2843 2908 <
+5598: 2842 2908 2907 <
+5599: 2843 2844 2909 <
+5600: 2843 2909 2908 <
+5601: 2844 2845 2910 <
+5602: 2844 2910 2909 <
+5603: 2845 2846 2911 <
+5604: 2845 2911 2910 <
+5605: 2846 2847 2912 <
+5606: 2846 2912 2911 <
+5607: 2847 2848 2913 <
+5608: 2847 2913 2912 <
+5609: 2848 2849 2914 <
+5610: 2848 2914 2913 <
+5611: 2849 2850 2915 <
+5612: 2849 2915 2914 <
+5613: 2850 2851 2916 <
+5614: 2850 2916 2915 <
+5615: 2851 2852 2917 <
+5616: 2851 2917 2916 <
+5617: 2852 2853 2918 <
+5618: 2852 2918 2917 <
+5619: 2853 2854 2919 <
+5620: 2853 2919 2918 <
+5621: 2854 2855 2920 <
+5622: 2854 2920 2919 <
+5623: 2855 2856 2921 <
+5624: 2855 2921 2920 <
+5625: 2856 2857 2922 <
+5626: 2856 2922 2921 <
+5627: 2857 2858 2923 <
+5628: 2857 2923 2922 <
+5629: 2858 2859 2924 <
+5630: 2858 2924 2923 <
+5631: 2859 2860 2925 <
+5632: 2859 2925 2924 <
+5633: 2861 2862 2927 <
+5634: 2861 2927 2926 <
+5635: 2862 2863 2928 <
+5636: 2862 2928 2927 <
+5637: 2863 2864 2929 <
+5638: 2863 2929 2928 <
+5639: 2864 2865 2930 <
+5640: 2864 2930 2929 <
+5641: 2865 2866 2931 <
+5642: 2865 2931 2930 <
+5643: 2866 2867 2932 <
+5644: 2866 2932 2931 <
+5645: 2867 2868 2933 <
+5646: 2867 2933 2932 <
+5647: 2868 2869 2934 <
+5648: 2868 2934 2933 <
+5649: 2869 2870 2935 <
+5650: 2869 2935 2934 <
+5651: 2870 2871 2936 <
+5652: 2870 2936 2935 <
+5653: 2871 2872 2937 <
+5654: 2871 2937 2936 <
+5655: 2872 2873 2938 <
+5656: 2872 2938 2937 <
+5657: 2873 2874 2939 <
+5658: 2873 2939 2938 <
+5659: 2874 2875 2940 <
+5660: 2874 2940 2939 <
+5661: 2875 2876 2941 <
+5662: 2875 2941 2940 <
+5663: 2876 2877 2942 <
+5664: 2876 2942 2941 <
+5665: 2877 2878 2943 <
+5666: 2877 2943 2942 <
+5667: 2878 2879 2944 <
+5668: 2878 2944 2943 <
+5669: 2879 2880 2945 <
+5670: 2879 2945 2944 <
+5671: 2880 2881 2946 <
+5672: 2880 2946 2945 <
+5673: 2881 2882 2947 <
+5674: 2881 2947 2946 <
+5675: 2882 2883 2948 <
+5676: 2882 2948 2947 <
+5677: 2883 2884 2949 <
+5678: 2883 2949 2948 <
+5679: 2884 2885 2950 <
+5680: 2884 2950 2949 <
+5681: 2885 2886 2951 <
+5682: 2885 2951 2950 <
+5683: 2886 2887 2952 <
+5684: 2886 2952 2951 <
+5685: 2887 2888 2953 <
+5686: 2887 2953 2952 <
+5687: 2888 2889 2954 <
+5688: 2888 2954 2953 <
+5689: 2889 2890 2955 <
+5690: 2889 2955 2954 <
+5691: 2890 2891 2956 <
+5692: 2890 2956 2955 <
+5693: 2891 2892 2957 <
+5694: 2891 2957 2956 <
+5695: 2892 2893 2958 <
+5696: 2892 2958 2957 <
+5697: 2893 2894 2959 <
+5698: 2893 2959 2958 <
+5699: 2894 2895 2960 <
+5700: 2894 2960 2959 <
+5701: 2895 2896 2961 <
+5702: 2895 2961 2960 <
+5703: 2896 2897 2962 <
+5704: 2896 2962 2961 <
+5705: 2897 2898 2963 <
+5706: 2897 2963 2962 <
+5707: 2898 2899 2964 <
+5708: 2898 2964 2963 <
+5709: 2899 2900 2965 <
+5710: 2899 2965 2964 <
+5711: 2900 2901 2966 <
+5712: 2900 2966 2965 <
+5713: 2901 2902 2967 <
+5714: 2901 2967 2966 <
+5715: 2902 2903 2968 <
+5716: 2902 2968 2967 <
+5717: 2903 2904 2969 <
+5718: 2903 2969 2968 <
+5719: 2904 2905 2970 <
+5720: 2904 2970 2969 <
+5721: 2905 2906 2971 <
+5722: 2905 2971 2970 <
+5723: 2906 2907 2972 <
+5724: 2906 2972 2971 <
+5725: 2907 2908 2973 <
+5726: 2907 2973 2972 <
+5727: 2908 2909 2974 <
+5728: 2908 2974 2973 <
+5729: 2909 2910 2975 <
+5730: 2909 2975 2974 <
+5731: 2910 2911 2976 <
+5732: 2910 2976 2975 <
+5733: 2911 2912 2977 <
+5734: 2911 2977 2976 <
+5735: 2912 2913 2978 <
+5736: 2912 2978 2977 <
+5737: 2913 2914 2979 <
+5738: 2913 2979 2978 <
+5739: 2914 2915 2980 <
+5740: 2914 2980 2979 <
+5741: 2915 2916 2981 <
+5742: 2915 2981 2980 <
+5743: 2916 2917 2982 <
+5744: 2916 2982 2981 <
+5745: 2917 2918 2983 <
+5746: 2917 2983 2982 <
+5747: 2918 2919 2984 <
+5748: 2918 2984 2983 <
+5749: 2919 2920 2985 <
+5750: 2919 2985 2984 <
+5751: 2920 2921 2986 <
+5752: 2920 2986 2985 <
+5753: 2921 2922 2987 <
+5754: 2921 2987 2986 <
+5755: 2922 2923 2988 <
+5756: 2922 2988 2987 <
+5757: 2923 2924 2989 <
+5758: 2923 2989 2988 <
+5759: 2924 2925 2990 <
+5760: 2924 2990 2989 <
+5761: 2926 2927 2992 <
+5762: 2926 2992 2991 <
+5763: 2927 2928 2993 <
+5764: 2927 2993 2992 <
+5765: 2928 2929 2994 <
+5766: 2928 2994 2993 <
+5767: 2929 2930 2995 <
+5768: 2929 2995 2994 <
+5769: 2930 2931 2996 <
+5770: 2930 2996 2995 <
+5771: 2931 2932 2997 <
+5772: 2931 2997 2996 <
+5773: 2932 2933 2998 <
+5774: 2932 2998 2997 <
+5775: 2933 2934 2999 <
+5776: 2933 2999 2998 <
+5777: 2934 2935 3000 <
+5778: 2934 3000 2999 <
+5779: 2935 2936 3001 <
+5780: 2935 3001 3000 <
+5781: 2936 2937 3002 <
+5782: 2936 3002 3001 <
+5783: 2937 2938 3003 <
+5784: 2937 3003 3002 <
+5785: 2938 2939 3004 <
+5786: 2938 3004 3003 <
+5787: 2939 2940 3005 <
+5788: 2939 3005 3004 <
+5789: 2940 2941 3006 <
+5790: 2940 3006 3005 <
+5791: 2941 2942 3007 <
+5792: 2941 3007 3006 <
+5793: 2942 2943 3008 <
+5794: 2942 3008 3007 <
+5795: 2943 2944 3009 <
+5796: 2943 3009 3008 <
+5797: 2944 2945 3010 <
+5798: 2944 3010 3009 <
+5799: 2945 2946 3011 <
+5800: 2945 3011 3010 <
+5801: 2946 2947 3012 <
+5802: 2946 3012 3011 <
+5803: 2947 2948 3013 <
+5804: 2947 3013 3012 <
+5805: 2948 2949 3014 <
+5806: 2948 3014 3013 <
+5807: 2949 2950 3015 <
+5808: 2949 3015 3014 <
+5809: 2950 2951 3016 <
+5810: 2950 3016 3015 <
+5811: 2951 2952 3017 <
+5812: 2951 3017 3016 <
+5813: 2952 2953 3018 <
+5814: 2952 3018 3017 <
+5815: 2953 2954 3019 <
+5816: 2953 3019 3018 <
+5817: 2954 2955 3020 <
+5818: 2954 3020 3019 <
+5819: 2955 2956 3021 <
+5820: 2955 3021 3020 <
+5821: 2956 2957 3022 <
+5822: 2956 3022 3021 <
+5823: 2957 2958 3023 <
+5824: 2957 3023 3022 <
+5825: 2958 2959 3024 <
+5826: 2958 3024 3023 <
+5827: 2959 2960 3025 <
+5828: 2959 3025 3024 <
+5829: 2960 2961 3026 <
+5830: 2960 3026 3025 <
+5831: 2961 2962 3027 <
+5832: 2961 3027 3026 <
+5833: 2962 2963 3028 <
+5834: 2962 3028 3027 <
+5835: 2963 2964 3029 <
+5836: 2963 3029 3028 <
+5837: 2964 2965 3030 <
+5838: 2964 3030 3029 <
+5839: 2965 2966 3031 <
+5840: 2965 3031 3030 <
+5841: 2966 2967 3032 <
+5842: 2966 3032 3031 <
+5843: 2967 2968 3033 <
+5844: 2967 3033 3032 <
+5845: 2968 2969 3034 <
+5846: 2968 3034 3033 <
+5847: 2969 2970 3035 <
+5848: 2969 3035 3034 <
+5849: 2970 2971 3036 <
+5850: 2970 3036 3035 <
+5851: 2971 2972 3037 <
+5852: 2971 3037 3036 <
+5853: 2972 2973 3038 <
+5854: 2972 3038 3037 <
+5855: 2973 2974 3039 <
+5856: 2973 3039 3038 <
+5857: 2974 2975 3040 <
+5858: 2974 3040 3039 <
+5859: 2975 2976 3041 <
+5860: 2975 3041 3040 <
+5861: 2976 2977 3042 <
+5862: 2976 3042 3041 <
+5863: 2977 2978 3043 <
+5864: 2977 3043 3042 <
+5865: 2978 2979 3044 <
+5866: 2978 3044 3043 <
+5867: 2979 2980 3045 <
+5868: 2979 3045 3044 <
+5869: 2980 2981 3046 <
+5870: 2980 3046 3045 <
+5871: 2981 2982 3047 <
+5872: 2981 3047 3046 <
+5873: 2982 2983 3048 <
+5874: 2982 3048 3047 <
+5875: 2983 2984 3049 <
+5876: 2983 3049 3048 <
+5877: 2984 2985 3050 <
+5878: 2984 3050 3049 <
+5879: 2985 2986 3051 <
+5880: 2985 3051 3050 <
+5881: 2986 2987 3052 <
+5882: 2986 3052 3051 <
+5883: 2987 2988 3053 <
+5884: 2987 3053 3052 <
+5885: 2988 2989 3054 <
+5886: 2988 3054 3053 <
+5887: 2989 2990 3055 <
+5888: 2989 3055 3054 <
+5889: 2991 2992 3057 <
+5890: 2991 3057 3056 <
+5891: 2992 2993 3058 <
+5892: 2992 3058 3057 <
+5893: 2993 2994 3059 <
+5894: 2993 3059 3058 <
+5895: 2994 2995 3060 <
+5896: 2994 3060 3059 <
+5897: 2995 2996 3061 <
+5898: 2995 3061 3060 <
+5899: 2996 2997 3062 <
+5900: 2996 3062 3061 <
+5901: 2997 2998 3063 <
+5902: 2997 3063 3062 <
+5903: 2998 2999 3064 <
+5904: 2998 3064 3063 <
+5905: 2999 3000 3065 <
+5906: 2999 3065 3064 <
+5907: 3000 3001 3066 <
+5908: 3000 3066 3065 <
+5909: 3001 3002 3067 <
+5910: 3001 3067 3066 <
+5911: 3002 3003 3068 <
+5912: 3002 3068 3067 <
+5913: 3003 3004 3069 <
+5914: 3003 3069 3068 <
+5915: 3004 3005 3070 <
+5916: 3004 3070 3069 <
+5917: 3005 3006 3071 <
+5918: 3005 3071 3070 <
+5919: 3006 3007 3072 <
+5920: 3006 3072 3071 <
+5921: 3007 3008 3073 <
+5922: 3007 3073 3072 <
+5923: 3008 3009 3074 <
+5924: 3008 3074 3073 <
+5925: 3009 3010 3075 <
+5926: 3009 3075 3074 <
+5927: 3010 3011 3076 <
+5928: 3010 3076 3075 <
+5929: 3011 3012 3077 <
+5930: 3011 3077 3076 <
+5931: 3012 3013 3078 <
+5932: 3012 3078 3077 <
+5933: 3013 3014 3079 <
+5934: 3013 3079 3078 <
+5935: 3014 3015 3080 <
+5936: 3014 3080 3079 <
+5937: 3015 3016 3081 <
+5938: 3015 3081 3080 <
+5939: 3016 3017 3082 <
+5940: 3016 3082 3081 <
+5941: 3017 3018 3083 <
+5942: 3017 3083 3082 <
+5943: 3018 3019 3084 <
+5944: 3018 3084 3083 <
+5945: 3019 3020 3085 <
+5946: 3019 3085 3084 <
+5947: 3020 3021 3086 <
+5948: 3020 3086 3085 <
+5949: 3021 3022 3087 <
+5950: 3021 3087 3086 <
+5951: 3022 3023 3088 <
+5952: 3022 3088 3087 <
+5953: 3023 3024 3089 <
+5954: 3023 3089 3088 <
+5955: 3024 3025 3090 <
+5956: 3024 3090 3089 <
+5957: 3025 3026 3091 <
+5958: 3025 3091 3090 <
+5959: 3026 3027 3092 <
+5960: 3026 3092 3091 <
+5961: 3027 3028 3093 <
+5962: 3027 3093 3092 <
+5963: 3028 3029 3094 <
+5964: 3028 3094 3093 <
+5965: 3029 3030 3095 <
+5966: 3029 3095 3094 <
+5967: 3030 3031 3096 <
+5968: 3030 3096 3095 <
+5969: 3031 3032 3097 <
+5970: 3031 3097 3096 <
+5971: 3032 3033 3098 <
+5972: 3032 3098 3097 <
+5973: 3033 3034 3099 <
+5974: 3033 3099 3098 <
+5975: 3034 3035 3100 <
+5976: 3034 3100 3099 <
+5977: 3035 3036 3101 <
+5978: 3035 3101 3100 <
+5979: 3036 3037 3102 <
+5980: 3036 3102 3101 <
+5981: 3037 3038 3103 <
+5982: 3037 3103 3102 <
+5983: 3038 3039 3104 <
+5984: 3038 3104 3103 <
+5985: 3039 3040 3105 <
+5986: 3039 3105 3104 <
+5987: 3040 3041 3106 <
+5988: 3040 3106 3105 <
+5989: 3041 3042 3107 <
+5990: 3041 3107 3106 <
+5991: 3042 3043 3108 <
+5992: 3042 3108 3107 <
+5993: 3043 3044 3109 <
+5994: 3043 3109 3108 <
+5995: 3044 3045 3110 <
+5996: 3044 3110 3109 <
+5997: 3045 3046 3111 <
+5998: 3045 3111 3110 <
+5999: 3046 3047 3112 <
+6000: 3046 3112 3111 <
+6001: 3047 3048 3113 <
+6002: 3047 3113 3112 <
+6003: 3048 3049 3114 <
+6004: 3048 3114 3113 <
+6005: 3049 3050 3115 <
+6006: 3049 3115 3114 <
+6007: 3050 3051 3116 <
+6008: 3050 3116 3115 <
+6009: 3051 3052 3117 <
+6010: 3051 3117 3116 <
+6011: 3052 3053 3118 <
+6012: 3052 3118 3117 <
+6013: 3053 3054 3119 <
+6014: 3053 3119 3118 <
+6015: 3054 3055 3120 <
+6016: 3054 3120 3119 <
+6017: 3056 3057 3122 <
+6018: 3056 3122 3121 <
+6019: 3057 3058 3123 <
+6020: 3057 3123 3122 <
+6021: 3058 3059 3124 <
+6022: 3058 3124 3123 <
+6023: 3059 3060 3125 <
+6024: 3059 3125 3124 <
+6025: 3060 3061 3126 <
+6026: 3060 3126 3125 <
+6027: 3061 3062 3127 <
+6028: 3061 3127 3126 <
+6029: 3062 3063 3128 <
+6030: 3062 3128 3127 <
+6031: 3063 3064 3129 <
+6032: 3063 3129 3128 <
+6033: 3064 3065 3130 <
+6034: 3064 3130 3129 <
+6035: 3065 3066 3131 <
+6036: 3065 3131 3130 <
+6037: 3066 3067 3132 <
+6038: 3066 3132 3131 <
+6039: 3067 3068 3133 <
+6040: 3067 3133 3132 <
+6041: 3068 3069 3134 <
+6042: 3068 3134 3133 <
+6043: 3069 3070 3135 <
+6044: 3069 3135 3134 <
+6045: 3070 3071 3136 <
+6046: 3070 3136 3135 <
+6047: 3071 3072 3137 <
+6048: 3071 3137 3136 <
+6049: 3072 3073 3138 <
+6050: 3072 3138 3137 <
+6051: 3073 3074 3139 <
+6052: 3073 3139 3138 <
+6053: 3074 3075 3140 <
+6054: 3074 3140 3139 <
+6055: 3075 3076 3141 <
+6056: 3075 3141 3140 <
+6057: 3076 3077 3142 <
+6058: 3076 3142 3141 <
+6059: 3077 3078 3143 <
+6060: 3077 3143 3142 <
+6061: 3078 3079 3144 <
+6062: 3078 3144 3143 <
+6063: 3079 3080 3145 <
+6064: 3079 3145 3144 <
+6065: 3080 3081 3146 <
+6066: 3080 3146 3145 <
+6067: 3081 3082 3147 <
+6068: 3081 3147 3146 <
+6069: 3082 3083 3148 <
+6070: 3082 3148 3147 <
+6071: 3083 3084 3149 <
+6072: 3083 3149 3148 <
+6073: 3084 3085 3150 <
+6074: 3084 3150 3149 <
+6075: 3085 3086 3151 <
+6076: 3085 3151 3150 <
+6077: 3086 3087 3152 <
+6078: 3086 3152 3151 <
+6079: 3087 3088 3153 <
+6080: 3087 3153 3152 <
+6081: 3088 3089 3154 <
+6082: 3088 3154 3153 <
+6083: 3089 3090 3155 <
+6084: 3089 3155 3154 <
+6085: 3090 3091 3156 <
+6086: 3090 3156 3155 <
+6087: 3091 3092 3157 <
+6088: 3091 3157 3156 <
+6089: 3092 3093 3158 <
+6090: 3092 3158 3157 <
+6091: 3093 3094 3159 <
+6092: 3093 3159 3158 <
+6093: 3094 3095 3160 <
+6094: 3094 3160 3159 <
+6095: 3095 3096 3161 <
+6096: 3095 3161 3160 <
+6097: 3096 3097 3162 <
+6098: 3096 3162 3161 <
+6099: 3097 3098 3163 <
+6100: 3097 3163 3162 <
+6101: 3098 3099 3164 <
+6102: 3098 3164 3163 <
+6103: 3099 3100 3165 <
+6104: 3099 3165 3164 <
+6105: 3100 3101 3166 <
+6106: 3100 3166 3165 <
+6107: 3101 3102 3167 <
+6108: 3101 3167 3166 <
+6109: 3102 3103 3168 <
+6110: 3102 3168 3167 <
+6111: 3103 3104 3169 <
+6112: 3103 3169 3168 <
+6113: 3104 3105 3170 <
+6114: 3104 3170 3169 <
+6115: 3105 3106 3171 <
+6116: 3105 3171 3170 <
+6117: 3106 3107 3172 <
+6118: 3106 3172 3171 <
+6119: 3107 3108 3173 <
+6120: 3107 3173 3172 <
+6121: 3108 3109 3174 <
+6122: 3108 3174 3173 <
+6123: 3109 3110 3175 <
+6124: 3109 3175 3174 <
+6125: 3110 3111 3176 <
+6126: 3110 3176 3175 <
+6127: 3111 3112 3177 <
+6128: 3111 3177 3176 <
+6129: 3112 3113 3178 <
+6130: 3112 3178 3177 <
+6131: 3113 3114 3179 <
+6132: 3113 3179 3178 <
+6133: 3114 3115 3180 <
+6134: 3114 3180 3179 <
+6135: 3115 3116 3181 <
+6136: 3115 3181 3180 <
+6137: 3116 3117 3182 <
+6138: 3116 3182 3181 <
+6139: 3117 3118 3183 <
+6140: 3117 3183 3182 <
+6141: 3118 3119 3184 <
+6142: 3118 3184 3183 <
+6143: 3119 3120 3185 <
+6144: 3119 3185 3184 <
+6145: 3121 3122 3187 <
+6146: 3121 3187 3186 <
+6147: 3122 3123 3188 <
+6148: 3122 3188 3187 <
+6149: 3123 3124 3189 <
+6150: 3123 3189 3188 <
+6151: 3124 3125 3190 <
+6152: 3124 3190 3189 <
+6153: 3125 3126 3191 <
+6154: 3125 3191 3190 <
+6155: 3126 3127 3192 <
+6156: 3126 3192 3191 <
+6157: 3127 3128 3193 <
+6158: 3127 3193 3192 <
+6159: 3128 3129 3194 <
+6160: 3128 3194 3193 <
+6161: 3129 3130 3195 <
+6162: 3129 3195 3194 <
+6163: 3130 3131 3196 <
+6164: 3130 3196 3195 <
+6165: 3131 3132 3197 <
+6166: 3131 3197 3196 <
+6167: 3132 3133 3198 <
+6168: 3132 3198 3197 <
+6169: 3133 3134 3199 <
+6170: 3133 3199 3198 <
+6171: 3134 3135 3200 <
+6172: 3134 3200 3199 <
+6173: 3135 3136 3201 <
+6174: 3135 3201 3200 <
+6175: 3136 3137 3202 <
+6176: 3136 3202 3201 <
+6177: 3137 3138 3203 <
+6178: 3137 3203 3202 <
+6179: 3138 3139 3204 <
+6180: 3138 3204 3203 <
+6181: 3139 3140 3205 <
+6182: 3139 3205 3204 <
+6183: 3140 3141 3206 <
+6184: 3140 3206 3205 <
+6185: 3141 3142 3207 <
+6186: 3141 3207 3206 <
+6187: 3142 3143 3208 <
+6188: 3142 3208 3207 <
+6189: 3143 3144 3209 <
+6190: 3143 3209 3208 <
+6191: 3144 3145 3210 <
+6192: 3144 3210 3209 <
+6193: 3145 3146 3211 <
+6194: 3145 3211 3210 <
+6195: 3146 3147 3212 <
+6196: 3146 3212 3211 <
+6197: 3147 3148 3213 <
+6198: 3147 3213 3212 <
+6199: 3148 3149 3214 <
+6200: 3148 3214 3213 <
+6201: 3149 3150 3215 <
+6202: 3149 3215 3214 <
+6203: 3150 3151 3216 <
+6204: 3150 3216 3215 <
+6205: 3151 3152 3217 <
+6206: 3151 3217 3216 <
+6207: 3152 3153 3218 <
+6208: 3152 3218 3217 <
+6209: 3153 3154 3219 <
+6210: 3153 3219 3218 <
+6211: 3154 3155 3220 <
+6212: 3154 3220 3219 <
+6213: 3155 3156 3221 <
+6214: 3155 3221 3220 <
+6215: 3156 3157 3222 <
+6216: 3156 3222 3221 <
+6217: 3157 3158 3223 <
+6218: 3157 3223 3222 <
+6219: 3158 3159 3224 <
+6220: 3158 3224 3223 <
+6221: 3159 3160 3225 <
+6222: 3159 3225 3224 <
+6223: 3160 3161 3226 <
+6224: 3160 3226 3225 <
+6225: 3161 3162 3227 <
+6226: 3161 3227 3226 <
+6227: 3162 3163 3228 <
+6228: 3162 3228 3227 <
+6229: 3163 3164 3229 <
+6230: 3163 3229 3228 <
+6231: 3164 3165 3230 <
+6232: 3164 3230 3229 <
+6233: 3165 3166 3231 <
+6234: 3165 3231 3230 <
+6235: 3166 3167 3232 <
+6236: 3166 3232 3231 <
+6237: 3167 3168 3233 <
+6238: 3167 3233 3232 <
+6239: 3168 3169 3234 <
+6240: 3168 3234 3233 <
+6241: 3169 3170 3235 <
+6242: 3169 3235 3234 <
+6243: 3170 3171 3236 <
+6244: 3170 3236 3235 <
+6245: 3171 3172 3237 <
+6246: 3171 3237 3236 <
+6247: 3172 3173 3238 <
+6248: 3172 3238 3237 <
+6249: 3173 3174 3239 <
+6250: 3173 3239 3238 <
+6251: 3174 3175 3240 <
+6252: 3174 3240 3239 <
+6253: 3175 3176 3241 <
+6254: 3175 3241 3240 <
+6255: 3176 3177 3242 <
+6256: 3176 3242 3241 <
+6257: 3177 3178 3243 <
+6258: 3177 3243 3242 <
+6259: 3178 3179 3244 <
+6260: 3178 3244 3243 <
+6261: 3179 3180 3245 <
+6262: 3179 3245 3244 <
+6263: 3180 3181 3246 <
+6264: 3180 3246 3245 <
+6265: 3181 3182 3247 <
+6266: 3181 3247 3246 <
+6267: 3182 3183 3248 <
+6268: 3182 3248 3247 <
+6269: 3183 3184 3249 <
+6270: 3183 3249 3248 <
+6271: 3184 3185 3250 <
+6272: 3184 3250 3249 <
+6273: 3186 3187 3252 <
+6274: 3186 3252 3251 <
+6275: 3187 3188 3253 <
+6276: 3187 3253 3252 <
+6277: 3188 3189 3254 <
+6278: 3188 3254 3253 <
+6279: 3189 3190 3255 <
+6280: 3189 3255 3254 <
+6281: 3190 3191 3256 <
+6282: 3190 3256 3255 <
+6283: 3191 3192 3257 <
+6284: 3191 3257 3256 <
+6285: 3192 3193 3258 <
+6286: 3192 3258 3257 <
+6287: 3193 3194 3259 <
+6288: 3193 3259 3258 <
+6289: 3194 3195 3260 <
+6290: 3194 3260 3259 <
+6291: 3195 3196 3261 <
+6292: 3195 3261 3260 <
+6293: 3196 3197 3262 <
+6294: 3196 3262 3261 <
+6295: 3197 3198 3263 <
+6296: 3197 3263 3262 <
+6297: 3198 3199 3264 <
+6298: 3198 3264 3263 <
+6299: 3199 3200 3265 <
+6300: 3199 3265 3264 <
+6301: 3200 3201 3266 <
+6302: 3200 3266 3265 <
+6303: 3201 3202 3267 <
+6304: 3201 3267 3266 <
+6305: 3202 3203 3268 <
+6306: 3202 3268 3267 <
+6307: 3203 3204 3269 <
+6308: 3203 3269 3268 <
+6309: 3204 3205 3270 <
+6310: 3204 3270 3269 <
+6311: 3205 3206 3271 <
+6312: 3205 3271 3270 <
+6313: 3206 3207 3272 <
+6314: 3206 3272 3271 <
+6315: 3207 3208 3273 <
+6316: 3207 3273 3272 <
+6317: 3208 3209 3274 <
+6318: 3208 3274 3273 <
+6319: 3209 3210 3275 <
+6320: 3209 3275 3274 <
+6321: 3210 3211 3276 <
+6322: 3210 3276 3275 <
+6323: 3211 3212 3277 <
+6324: 3211 3277 3276 <
+6325: 3212 3213 3278 <
+6326: 3212 3278 3277 <
+6327: 3213 3214 3279 <
+6328: 3213 3279 3278 <
+6329: 3214 3215 3280 <
+6330: 3214 3280 3279 <
+6331: 3215 3216 3281 <
+6332: 3215 3281 3280 <
+6333: 3216 3217 3282 <
+6334: 3216 3282 3281 <
+6335: 3217 3218 3283 <
+6336: 3217 3283 3282 <
+6337: 3218 3219 3284 <
+6338: 3218 3284 3283 <
+6339: 3219 3220 3285 <
+6340: 3219 3285 3284 <
+6341: 3220 3221 3286 <
+6342: 3220 3286 3285 <
+6343: 3221 3222 3287 <
+6344: 3221 3287 3286 <
+6345: 3222 3223 3288 <
+6346: 3222 3288 3287 <
+6347: 3223 3224 3289 <
+6348: 3223 3289 3288 <
+6349: 3224 3225 3290 <
+6350: 3224 3290 3289 <
+6351: 3225 3226 3291 <
+6352: 3225 3291 3290 <
+6353: 3226 3227 3292 <
+6354: 3226 3292 3291 <
+6355: 3227 3228 3293 <
+6356: 3227 3293 3292 <
+6357: 3228 3229 3294 <
+6358: 3228 3294 3293 <
+6359: 3229 3230 3295 <
+6360: 3229 3295 3294 <
+6361: 3230 3231 3296 <
+6362: 3230 3296 3295 <
+6363: 3231 3232 3297 <
+6364: 3231 3297 3296 <
+6365: 3232 3233 3298 <
+6366: 3232 3298 3297 <
+6367: 3233 3234 3299 <
+6368: 3233 3299 3298 <
+6369: 3234 3235 3300 <
+6370: 3234 3300 3299 <
+6371: 3235 3236 3301 <
+6372: 3235 3301 3300 <
+6373: 3236 3237 3302 <
+6374: 3236 3302 3301 <
+6375: 3237 3238 3303 <
+6376: 3237 3303 3302 <
+6377: 3238 3239 3304 <
+6378: 3238 3304 3303 <
+6379: 3239 3240 3305 <
+6380: 3239 3305 3304 <
+6381: 3240 3241 3306 <
+6382: 3240 3306 3305 <
+6383: 3241 3242 3307 <
+6384: 3241 3307 3306 <
+6385: 3242 3243 3308 <
+6386: 3242 3308 3307 <
+6387: 3243 3244 3309 <
+6388: 3243 3309 3308 <
+6389: 3244 3245 3310 <
+6390: 3244 3310 3309 <
+6391: 3245 3246 3311 <
+6392: 3245 3311 3310 <
+6393: 3246 3247 3312 <
+6394: 3246 3312 3311 <
+6395: 3247 3248 3313 <
+6396: 3247 3313 3312 <
+6397: 3248 3249 3314 <
+6398: 3248 3314 3313 <
+6399: 3249 3250 3315 <
+6400: 3249 3315 3314 <
+6401: 3251 3252 3317 <
+6402: 3251 3317 3316 <
+6403: 3252 3253 3318 <
+6404: 3252 3318 3317 <
+6405: 3253 3254 3319 <
+6406: 3253 3319 3318 <
+6407: 3254 3255 3320 <
+6408: 3254 3320 3319 <
+6409: 3255 3256 3321 <
+6410: 3255 3321 3320 <
+6411: 3256 3257 3322 <
+6412: 3256 3322 3321 <
+6413: 3257 3258 3323 <
+6414: 3257 3323 3322 <
+6415: 3258 3259 3324 <
+6416: 3258 3324 3323 <
+6417: 3259 3260 3325 <
+6418: 3259 3325 3324 <
+6419: 3260 3261 3326 <
+6420: 3260 3326 3325 <
+6421: 3261 3262 3327 <
+6422: 3261 3327 3326 <
+6423: 3262 3263 3328 <
+6424: 3262 3328 3327 <
+6425: 3263 3264 3329 <
+6426: 3263 3329 3328 <
+6427: 3264 3265 3330 <
+6428: 3264 3330 3329 <
+6429: 3265 3266 3331 <
+6430: 3265 3331 3330 <
+6431: 3266 3267 3332 <
+6432: 3266 3332 3331 <
+6433: 3267 3268 3333 <
+6434: 3267 3333 3332 <
+6435: 3268 3269 3334 <
+6436: 3268 3334 3333 <
+6437: 3269 3270 3335 <
+6438: 3269 3335 3334 <
+6439: 3270 3271 3336 <
+6440: 3270 3336 3335 <
+6441: 3271 3272 3337 <
+6442: 3271 3337 3336 <
+6443: 3272 3273 3338 <
+6444: 3272 3338 3337 <
+6445: 3273 3274 3339 <
+6446: 3273 3339 3338 <
+6447: 3274 3275 3340 <
+6448: 3274 3340 3339 <
+6449: 3275 3276 3341 <
+6450: 3275 3341 3340 <
+6451: 3276 3277 3342 <
+6452: 3276 3342 3341 <
+6453: 3277 3278 3343 <
+6454: 3277 3343 3342 <
+6455: 3278 3279 3344 <
+6456: 3278 3344 3343 <
+6457: 3279 3280 3345 <
+6458: 3279 3345 3344 <
+6459: 3280 3281 3346 <
+6460: 3280 3346 3345 <
+6461: 3281 3282 3347 <
+6462: 3281 3347 3346 <
+6463: 3282 3283 3348 <
+6464: 3282 3348 3347 <
+6465: 3283 3284 3349 <
+6466: 3283 3349 3348 <
+6467: 3284 3285 3350 <
+6468: 3284 3350 3349 <
+6469: 3285 3286 3351 <
+6470: 3285 3351 3350 <
+6471: 3286 3287 3352 <
+6472: 3286 3352 3351 <
+6473: 3287 3288 3353 <
+6474: 3287 3353 3352 <
+6475: 3288 3289 3354 <
+6476: 3288 3354 3353 <
+6477: 3289 3290 3355 <
+6478: 3289 3355 3354 <
+6479: 3290 3291 3356 <
+6480: 3290 3356 3355 <
+6481: 3291 3292 3357 <
+6482: 3291 3357 3356 <
+6483: 3292 3293 3358 <
+6484: 3292 3358 3357 <
+6485: 3293 3294 3359 <
+6486: 3293 3359 3358 <
+6487: 3294 3295 3360 <
+6488: 3294 3360 3359 <
+6489: 3295 3296 3361 <
+6490: 3295 3361 3360 <
+6491: 3296 3297 3362 <
+6492: 3296 3362 3361 <
+6493: 3297 3298 3363 <
+6494: 3297 3363 3362 <
+6495: 3298 3299 3364 <
+6496: 3298 3364 3363 <
+6497: 3299 3300 3365 <
+6498: 3299 3365 3364 <
+6499: 3300 3301 3366 <
+6500: 3300 3366 3365 <
+6501: 3301 3302 3367 <
+6502: 3301 3367 3366 <
+6503: 3302 3303 3368 <
+6504: 3302 3368 3367 <
+6505: 3303 3304 3369 <
+6506: 3303 3369 3368 <
+6507: 3304 3305 3370 <
+6508: 3304 3370 3369 <
+6509: 3305 3306 3371 <
+6510: 3305 3371 3370 <
+6511: 3306 3307 3372 <
+6512: 3306 3372 3371 <
+6513: 3307 3308 3373 <
+6514: 3307 3373 3372 <
+6515: 3308 3309 3374 <
+6516: 3308 3374 3373 <
+6517: 3309 3310 3375 <
+6518: 3309 3375 3374 <
+6519: 3310 3311 3376 <
+6520: 3310 3376 3375 <
+6521: 3311 3312 3377 <
+6522: 3311 3377 3376 <
+6523: 3312 3313 3378 <
+6524: 3312 3378 3377 <
+6525: 3313 3314 3379 <
+6526: 3313 3379 3378 <
+6527: 3314 3315 3380 <
+6528: 3314 3380 3379 <
+6529: 3316 3317 3382 <
+6530: 3316 3382 3381 <
+6531: 3317 3318 3383 <
+6532: 3317 3383 3382 <
+6533: 3318 3319 3384 <
+6534: 3318 3384 3383 <
+6535: 3319 3320 3385 <
+6536: 3319 3385 3384 <
+6537: 3320 3321 3386 <
+6538: 3320 3386 3385 <
+6539: 3321 3322 3387 <
+6540: 3321 3387 3386 <
+6541: 3322 3323 3388 <
+6542: 3322 3388 3387 <
+6543: 3323 3324 3389 <
+6544: 3323 3389 3388 <
+6545: 3324 3325 3390 <
+6546: 3324 3390 3389 <
+6547: 3325 3326 3391 <
+6548: 3325 3391 3390 <
+6549: 3326 3327 3392 <
+6550: 3326 3392 3391 <
+6551: 3327 3328 3393 <
+6552: 3327 3393 3392 <
+6553: 3328 3329 3394 <
+6554: 3328 3394 3393 <
+6555: 3329 3330 3395 <
+6556: 3329 3395 3394 <
+6557: 3330 3331 3396 <
+6558: 3330 3396 3395 <
+6559: 3331 3332 3397 <
+6560: 3331 3397 3396 <
+6561: 3332 3333 3398 <
+6562: 3332 3398 3397 <
+6563: 3333 3334 3399 <
+6564: 3333 3399 3398 <
+6565: 3334 3335 3400 <
+6566: 3334 3400 3399 <
+6567: 3335 3336 3401 <
+6568: 3335 3401 3400 <
+6569: 3336 3337 3402 <
+6570: 3336 3402 3401 <
+6571: 3337 3338 3403 <
+6572: 3337 3403 3402 <
+6573: 3338 3339 3404 <
+6574: 3338 3404 3403 <
+6575: 3339 3340 3405 <
+6576: 3339 3405 3404 <
+6577: 3340 3341 3406 <
+6578: 3340 3406 3405 <
+6579: 3341 3342 3407 <
+6580: 3341 3407 3406 <
+6581: 3342 3343 3408 <
+6582: 3342 3408 3407 <
+6583: 3343 3344 3409 <
+6584: 3343 3409 3408 <
+6585: 3344 3345 3410 <
+6586: 3344 3410 3409 <
+6587: 3345 3346 3411 <
+6588: 3345 3411 3410 <
+6589: 3346 3347 3412 <
+6590: 3346 3412 3411 <
+6591: 3347 3348 3413 <
+6592: 3347 3413 3412 <
+6593: 3348 3349 3414 <
+6594: 3348 3414 3413 <
+6595: 3349 3350 3415 <
+6596: 3349 3415 3414 <
+6597: 3350 3351 3416 <
+6598: 3350 3416 3415 <
+6599: 3351 3352 3417 <
+6600: 3351 3417 3416 <
+6601: 3352 3353 3418 <
+6602: 3352 3418 3417 <
+6603: 3353 3354 3419 <
+6604: 3353 3419 3418 <
+6605: 3354 3355 3420 <
+6606: 3354 3420 3419 <
+6607: 3355 3356 3421 <
+6608: 3355 3421 3420 <
+6609: 3356 3357 3422 <
+6610: 3356 3422 3421 <
+6611: 3357 3358 3423 <
+6612: 3357 3423 3422 <
+6613: 3358 3359 3424 <
+6614: 3358 3424 3423 <
+6615: 3359 3360 3425 <
+6616: 3359 3425 3424 <
+6617: 3360 3361 3426 <
+6618: 3360 3426 3425 <
+6619: 3361 3362 3427 <
+6620: 3361 3427 3426 <
+6621: 3362 3363 3428 <
+6622: 3362 3428 3427 <
+6623: 3363 3364 3429 <
+6624: 3363 3429 3428 <
+6625: 3364 3365 3430 <
+6626: 3364 3430 3429 <
+6627: 3365 3366 3431 <
+6628: 3365 3431 3430 <
+6629: 3366 3367 3432 <
+6630: 3366 3432 3431 <
+6631: 3367 3368 3433 <
+6632: 3367 3433 3432 <
+6633: 3368 3369 3434 <
+6634: 3368 3434 3433 <
+6635: 3369 3370 3435 <
+6636: 3369 3435 3434 <
+6637: 3370 3371 3436 <
+6638: 3370 3436 3435 <
+6639: 3371 3372 3437 <
+6640: 3371 3437 3436 <
+6641: 3372 3373 3438 <
+6642: 3372 3438 3437 <
+6643: 3373 3374 3439 <
+6644: 3373 3439 3438 <
+6645: 3374 3375 3440 <
+6646: 3374 3440 3439 <
+6647: 3375 3376 3441 <
+6648: 3375 3441 3440 <
+6649: 3376 3377 3442 <
+6650: 3376 3442 3441 <
+6651: 3377 3378 3443 <
+6652: 3377 3443 3442 <
+6653: 3378 3379 3444 <
+6654: 3378 3444 3443 <
+6655: 3379 3380 3445 <
+6656: 3379 3445 3444 <
+6657: 3381 3382 3447 <
+6658: 3381 3447 3446 <
+6659: 3382 3383 3448 <
+6660: 3382 3448 3447 <
+6661: 3383 3384 3449 <
+6662: 3383 3449 3448 <
+6663: 3384 3385 3450 <
+6664: 3384 3450 3449 <
+6665: 3385 3386 3451 <
+6666: 3385 3451 3450 <
+6667: 3386 3387 3452 <
+6668: 3386 3452 3451 <
+6669: 3387 3388 3453 <
+6670: 3387 3453 3452 <
+6671: 3388 3389 3454 <
+6672: 3388 3454 3453 <
+6673: 3389 3390 3455 <
+6674: 3389 3455 3454 <
+6675: 3390 3391 3456 <
+6676: 3390 3456 3455 <
+6677: 3391 3392 3457 <
+6678: 3391 3457 3456 <
+6679: 3392 3393 3458 <
+6680: 3392 3458 3457 <
+6681: 3393 3394 3459 <
+6682: 3393 3459 3458 <
+6683: 3394 3395 3460 <
+6684: 3394 3460 3459 <
+6685: 3395 3396 3461 <
+6686: 3395 3461 3460 <
+6687: 3396 3397 3462 <
+6688: 3396 3462 3461 <
+6689: 3397 3398 3463 <
+6690: 3397 3463 3462 <
+6691: 3398 3399 3464 <
+6692: 3398 3464 3463 <
+6693: 3399 3400 3465 <
+6694: 3399 3465 3464 <
+6695: 3400 3401 3466 <
+6696: 3400 3466 3465 <
+6697: 3401 3402 3467 <
+6698: 3401 3467 3466 <
+6699: 3402 3403 3468 <
+6700: 3402 3468 3467 <
+6701: 3403 3404 3469 <
+6702: 3403 3469 3468 <
+6703: 3404 3405 3470 <
+6704: 3404 3470 3469 <
+6705: 3405 3406 3471 <
+6706: 3405 3471 3470 <
+6707: 3406 3407 3472 <
+6708: 3406 3472 3471 <
+6709: 3407 3408 3473 <
+6710: 3407 3473 3472 <
+6711: 3408 3409 3474 <
+6712: 3408 3474 3473 <
+6713: 3409 3410 3475 <
+6714: 3409 3475 3474 <
+6715: 3410 3411 3476 <
+6716: 3410 3476 3475 <
+6717: 3411 3412 3477 <
+6718: 3411 3477 3476 <
+6719: 3412 3413 3478 <
+6720: 3412 3478 3477 <
+6721: 3413 3414 3479 <
+6722: 3413 3479 3478 <
+6723: 3414 3415 3480 <
+6724: 3414 3480 3479 <
+6725: 3415 3416 3481 <
+6726: 3415 3481 3480 <
+6727: 3416 3417 3482 <
+6728: 3416 3482 3481 <
+6729: 3417 3418 3483 <
+6730: 3417 3483 3482 <
+6731: 3418 3419 3484 <
+6732: 3418 3484 3483 <
+6733: 3419 3420 3485 <
+6734: 3419 3485 3484 <
+6735: 3420 3421 3486 <
+6736: 3420 3486 3485 <
+6737: 3421 3422 3487 <
+6738: 3421 3487 3486 <
+6739: 3422 3423 3488 <
+6740: 3422 3488 3487 <
+6741: 3423 3424 3489 <
+6742: 3423 3489 3488 <
+6743: 3424 3425 3490 <
+6744: 3424 3490 3489 <
+6745: 3425 3426 3491 <
+6746: 3425 3491 3490 <
+6747: 3426 3427 3492 <
+6748: 3426 3492 3491 <
+6749: 3427 3428 3493 <
+6750: 3427 3493 3492 <
+6751: 3428 3429 3494 <
+6752: 3428 3494 3493 <
+6753: 3429 3430 3495 <
+6754: 3429 3495 3494 <
+6755: 3430 3431 3496 <
+6756: 3430 3496 3495 <
+6757: 3431 3432 3497 <
+6758: 3431 3497 3496 <
+6759: 3432 3433 3498 <
+6760: 3432 3498 3497 <
+6761: 3433 3434 3499 <
+6762: 3433 3499 3498 <
+6763: 3434 3435 3500 <
+6764: 3434 3500 3499 <
+6765: 3435 3436 3501 <
+6766: 3435 3501 3500 <
+6767: 3436 3437 3502 <
+6768: 3436 3502 3501 <
+6769: 3437 3438 3503 <
+6770: 3437 3503 3502 <
+6771: 3438 3439 3504 <
+6772: 3438 3504 3503 <
+6773: 3439 3440 3505 <
+6774: 3439 3505 3504 <
+6775: 3440 3441 3506 <
+6776: 3440 3506 3505 <
+6777: 3441 3442 3507 <
+6778: 3441 3507 3506 <
+6779: 3442 3443 3508 <
+6780: 3442 3508 3507 <
+6781: 3443 3444 3509 <
+6782: 3443 3509 3508 <
+6783: 3444 3445 3510 <
+6784: 3444 3510 3509 <
+6785: 3446 3447 3512 <
+6786: 3446 3512 3511 <
+6787: 3447 3448 3513 <
+6788: 3447 3513 3512 <
+6789: 3448 3449 3514 <
+6790: 3448 3514 3513 <
+6791: 3449 3450 3515 <
+6792: 3449 3515 3514 <
+6793: 3450 3451 3516 <
+6794: 3450 3516 3515 <
+6795: 3451 3452 3517 <
+6796: 3451 3517 3516 <
+6797: 3452 3453 3518 <
+6798: 3452 3518 3517 <
+6799: 3453 3454 3519 <
+6800: 3453 3519 3518 <
+6801: 3454 3455 3520 <
+6802: 3454 3520 3519 <
+6803: 3455 3456 3521 <
+6804: 3455 3521 3520 <
+6805: 3456 3457 3522 <
+6806: 3456 3522 3521 <
+6807: 3457 3458 3523 <
+6808: 3457 3523 3522 <
+6809: 3458 3459 3524 <
+6810: 3458 3524 3523 <
+6811: 3459 3460 3525 <
+6812: 3459 3525 3524 <
+6813: 3460 3461 3526 <
+6814: 3460 3526 3525 <
+6815: 3461 3462 3527 <
+6816: 3461 3527 3526 <
+6817: 3462 3463 3528 <
+6818: 3462 3528 3527 <
+6819: 3463 3464 3529 <
+6820: 3463 3529 3528 <
+6821: 3464 3465 3530 <
+6822: 3464 3530 3529 <
+6823: 3465 3466 3531 <
+6824: 3465 3531 3530 <
+6825: 3466 3467 3532 <
+6826: 3466 3532 3531 <
+6827: 3467 3468 3533 <
+6828: 3467 3533 3532 <
+6829: 3468 3469 3534 <
+6830: 3468 3534 3533 <
+6831: 3469 3470 3535 <
+6832: 3469 3535 3534 <
+6833: 3470 3471 3536 <
+6834: 3470 3536 3535 <
+6835: 3471 3472 3537 <
+6836: 3471 3537 3536 <
+6837: 3472 3473 3538 <
+6838: 3472 3538 3537 <
+6839: 3473 3474 3539 <
+6840: 3473 3539 3538 <
+6841: 3474 3475 3540 <
+6842: 3474 3540 3539 <
+6843: 3475 3476 3541 <
+6844: 3475 3541 3540 <
+6845: 3476 3477 3542 <
+6846: 3476 3542 3541 <
+6847: 3477 3478 3543 <
+6848: 3477 3543 3542 <
+6849: 3478 3479 3544 <
+6850: 3478 3544 3543 <
+6851: 3479 3480 3545 <
+6852: 3479 3545 3544 <
+6853: 3480 3481 3546 <
+6854: 3480 3546 3545 <
+6855: 3481 3482 3547 <
+6856: 3481 3547 3546 <
+6857: 3482 3483 3548 <
+6858: 3482 3548 3547 <
+6859: 3483 3484 3549 <
+6860: 3483 3549 3548 <
+6861: 3484 3485 3550 <
+6862: 3484 3550 3549 <
+6863: 3485 3486 3551 <
+6864: 3485 3551 3550 <
+6865: 3486 3487 3552 <
+6866: 3486 3552 3551 <
+6867: 3487 3488 3553 <
+6868: 3487 3553 3552 <
+6869: 3488 3489 3554 <
+6870: 3488 3554 3553 <
+6871: 3489 3490 3555 <
+6872: 3489 3555 3554 <
+6873: 3490 3491 3556 <
+6874: 3490 3556 3555 <
+6875: 3491 3492 3557 <
+6876: 3491 3557 3556 <
+6877: 3492 3493 3558 <
+6878: 3492 3558 3557 <
+6879: 3493 3494 3559 <
+6880: 3493 3559 3558 <
+6881: 3494 3495 3560 <
+6882: 3494 3560 3559 <
+6883: 3495 3496 3561 <
+6884: 3495 3561 3560 <
+6885: 3496 3497 3562 <
+6886: 3496 3562 3561 <
+6887: 3497 3498 3563 <
+6888: 3497 3563 3562 <
+6889: 3498 3499 3564 <
+6890: 3498 3564 3563 <
+6891: 3499 3500 3565 <
+6892: 3499 3565 3564 <
+6893: 3500 3501 3566 <
+6894: 3500 3566 3565 <
+6895: 3501 3502 3567 <
+6896: 3501 3567 3566 <
+6897: 3502 3503 3568 <
+6898: 3502 3568 3567 <
+6899: 3503 3504 3569 <
+6900: 3503 3569 3568 <
+6901: 3504 3505 3570 <
+6902: 3504 3570 3569 <
+6903: 3505 3506 3571 <
+6904: 3505 3571 3570 <
+6905: 3506 3507 3572 <
+6906: 3506 3572 3571 <
+6907: 3507 3508 3573 <
+6908: 3507 3573 3572 <
+6909: 3508 3509 3574 <
+6910: 3508 3574 3573 <
+6911: 3509 3510 3575 <
+6912: 3509 3575 3574 <
+6913: 3511 3512 3577 <
+6914: 3511 3577 3576 <
+6915: 3512 3513 3578 <
+6916: 3512 3578 3577 <
+6917: 3513 3514 3579 <
+6918: 3513 3579 3578 <
+6919: 3514 3515 3580 <
+6920: 3514 3580 3579 <
+6921: 3515 3516 3581 <
+6922: 3515 3581 3580 <
+6923: 3516 3517 3582 <
+6924: 3516 3582 3581 <
+6925: 3517 3518 3583 <
+6926: 3517 3583 3582 <
+6927: 3518 3519 3584 <
+6928: 3518 3584 3583 <
+6929: 3519 3520 3585 <
+6930: 3519 3585 3584 <
+6931: 3520 3521 3586 <
+6932: 3520 3586 3585 <
+6933: 3521 3522 3587 <
+6934: 3521 3587 3586 <
+6935: 3522 3523 3588 <
+6936: 3522 3588 3587 <
+6937: 3523 3524 3589 <
+6938: 3523 3589 3588 <
+6939: 3524 3525 3590 <
+6940: 3524 3590 3589 <
+6941: 3525 3526 3591 <
+6942: 3525 3591 3590 <
+6943: 3526 3527 3592 <
+6944: 3526 3592 3591 <
+6945: 3527 3528 3593 <
+6946: 3527 3593 3592 <
+6947: 3528 3529 3594 <
+6948: 3528 3594 3593 <
+6949: 3529 3530 3595 <
+6950: 3529 3595 3594 <
+6951: 3530 3531 3596 <
+6952: 3530 3596 3595 <
+6953: 3531 3532 3597 <
+6954: 3531 3597 3596 <
+6955: 3532 3533 3598 <
+6956: 3532 3598 3597 <
+6957: 3533 3534 3599 <
+6958: 3533 3599 3598 <
+6959: 3534 3535 3600 <
+6960: 3534 3600 3599 <
+6961: 3535 3536 3601 <
+6962: 3535 3601 3600 <
+6963: 3536 3537 3602 <
+6964: 3536 3602 3601 <
+6965: 3537 3538 3603 <
+6966: 3537 3603 3602 <
+6967: 3538 3539 3604 <
+6968: 3538 3604 3603 <
+6969: 3539 3540 3605 <
+6970: 3539 3605 3604 <
+6971: 3540 3541 3606 <
+6972: 3540 3606 3605 <
+6973: 3541 3542 3607 <
+6974: 3541 3607 3606 <
+6975: 3542 3543 3608 <
+6976: 3542 3608 3607 <
+6977: 3543 3544 3609 <
+6978: 3543 3609 3608 <
+6979: 3544 3545 3610 <
+6980: 3544 3610 3609 <
+6981: 3545 3546 3611 <
+6982: 3545 3611 3610 <
+6983: 3546 3547 3612 <
+6984: 3546 3612 3611 <
+6985: 3547 3548 3613 <
+6986: 3547 3613 3612 <
+6987: 3548 3549 3614 <
+6988: 3548 3614 3613 <
+6989: 3549 3550 3615 <
+6990: 3549 3615 3614 <
+6991: 3550 3551 3616 <
+6992: 3550 3616 3615 <
+6993: 3551 3552 3617 <
+6994: 3551 3617 3616 <
+6995: 3552 3553 3618 <
+6996: 3552 3618 3617 <
+6997: 3553 3554 3619 <
+6998: 3553 3619 3618 <
+6999: 3554 3555 3620 <
+7000: 3554 3620 3619 <
+7001: 3555 3556 3621 <
+7002: 3555 3621 3620 <
+7003: 3556 3557 3622 <
+7004: 3556 3622 3621 <
+7005: 3557 3558 3623 <
+7006: 3557 3623 3622 <
+7007: 3558 3559 3624 <
+7008: 3558 3624 3623 <
+7009: 3559 3560 3625 <
+7010: 3559 3625 3624 <
+7011: 3560 3561 3626 <
+7012: 3560 3626 3625 <
+7013: 3561 3562 3627 <
+7014: 3561 3627 3626 <
+7015: 3562 3563 3628 <
+7016: 3562 3628 3627 <
+7017: 3563 3564 3629 <
+7018: 3563 3629 3628 <
+7019: 3564 3565 3630 <
+7020: 3564 3630 3629 <
+7021: 3565 3566 3631 <
+7022: 3565 3631 3630 <
+7023: 3566 3567 3632 <
+7024: 3566 3632 3631 <
+7025: 3567 3568 3633 <
+7026: 3567 3633 3632 <
+7027: 3568 3569 3634 <
+7028: 3568 3634 3633 <
+7029: 3569 3570 3635 <
+7030: 3569 3635 3634 <
+7031: 3570 3571 3636 <
+7032: 3570 3636 3635 <
+7033: 3571 3572 3637 <
+7034: 3571 3637 3636 <
+7035: 3572 3573 3638 <
+7036: 3572 3638 3637 <
+7037: 3573 3574 3639 <
+7038: 3573 3639 3638 <
+7039: 3574 3575 3640 <
+7040: 3574 3640 3639 <
+7041: 3576 3577 3642 <
+7042: 3576 3642 3641 <
+7043: 3577 3578 3643 <
+7044: 3577 3643 3642 <
+7045: 3578 3579 3644 <
+7046: 3578 3644 3643 <
+7047: 3579 3580 3645 <
+7048: 3579 3645 3644 <
+7049: 3580 3581 3646 <
+7050: 3580 3646 3645 <
+7051: 3581 3582 3647 <
+7052: 3581 3647 3646 <
+7053: 3582 3583 3648 <
+7054: 3582 3648 3647 <
+7055: 3583 3584 3649 <
+7056: 3583 3649 3648 <
+7057: 3584 3585 3650 <
+7058: 3584 3650 3649 <
+7059: 3585 3586 3651 <
+7060: 3585 3651 3650 <
+7061: 3586 3587 3652 <
+7062: 3586 3652 3651 <
+7063: 3587 3588 3653 <
+7064: 3587 3653 3652 <
+7065: 3588 3589 3654 <
+7066: 3588 3654 3653 <
+7067: 3589 3590 3655 <
+7068: 3589 3655 3654 <
+7069: 3590 3591 3656 <
+7070: 3590 3656 3655 <
+7071: 3591 3592 3657 <
+7072: 3591 3657 3656 <
+7073: 3592 3593 3658 <
+7074: 3592 3658 3657 <
+7075: 3593 3594 3659 <
+7076: 3593 3659 3658 <
+7077: 3594 3595 3660 <
+7078: 3594 3660 3659 <
+7079: 3595 3596 3661 <
+7080: 3595 3661 3660 <
+7081: 3596 3597 3662 <
+7082: 3596 3662 3661 <
+7083: 3597 3598 3663 <
+7084: 3597 3663 3662 <
+7085: 3598 3599 3664 <
+7086: 3598 3664 3663 <
+7087: 3599 3600 3665 <
+7088: 3599 3665 3664 <
+7089: 3600 3601 3666 <
+7090: 3600 3666 3665 <
+7091: 3601 3602 3667 <
+7092: 3601 3667 3666 <
+7093: 3602 3603 3668 <
+7094: 3602 3668 3667 <
+7095: 3603 3604 3669 <
+7096: 3603 3669 3668 <
+7097: 3604 3605 3670 <
+7098: 3604 3670 3669 <
+7099: 3605 3606 3671 <
+7100: 3605 3671 3670 <
+7101: 3606 3607 3672 <
+7102: 3606 3672 3671 <
+7103: 3607 3608 3673 <
+7104: 3607 3673 3672 <
+7105: 3608 3609 3674 <
+7106: 3608 3674 3673 <
+7107: 3609 3610 3675 <
+7108: 3609 3675 3674 <
+7109: 3610 3611 3676 <
+7110: 3610 3676 3675 <
+7111: 3611 3612 3677 <
+7112: 3611 3677 3676 <
+7113: 3612 3613 3678 <
+7114: 3612 3678 3677 <
+7115: 3613 3614 3679 <
+7116: 3613 3679 3678 <
+7117: 3614 3615 3680 <
+7118: 3614 3680 3679 <
+7119: 3615 3616 3681 <
+7120: 3615 3681 3680 <
+7121: 3616 3617 3682 <
+7122: 3616 3682 3681 <
+7123: 3617 3618 3683 <
+7124: 3617 3683 3682 <
+7125: 3618 3619 3684 <
+7126: 3618 3684 3683 <
+7127: 3619 3620 3685 <
+7128: 3619 3685 3684 <
+7129: 3620 3621 3686 <
+7130: 3620 3686 3685 <
+7131: 3621 3622 3687 <
+7132: 3621 3687 3686 <
+7133: 3622 3623 3688 <
+7134: 3622 3688 3687 <
+7135: 3623 3624 3689 <
+7136: 3623 3689 3688 <
+7137: 3624 3625 3690 <
+7138: 3624 3690 3689 <
+7139: 3625 3626 3691 <
+7140: 3625 3691 3690 <
+7141: 3626 3627 3692 <
+7142: 3626 3692 3691 <
+7143: 3627 3628 3693 <
+7144: 3627 3693 3692 <
+7145: 3628 3629 3694 <
+7146: 3628 3694 3693 <
+7147: 3629 3630 3695 <
+7148: 3629 3695 3694 <
+7149: 3630 3631 3696 <
+7150: 3630 3696 3695 <
+7151: 3631 3632 3697 <
+7152: 3631 3697 3696 <
+7153: 3632 3633 3698 <
+7154: 3632 3698 3697 <
+7155: 3633 3634 3699 <
+7156: 3633 3699 3698 <
+7157: 3634 3635 3700 <
+7158: 3634 3700 3699 <
+7159: 3635 3636 3701 <
+7160: 3635 3701 3700 <
+7161: 3636 3637 3702 <
+7162: 3636 3702 3701 <
+7163: 3637 3638 3703 <
+7164: 3637 3703 3702 <
+7165: 3638 3639 3704 <
+7166: 3638 3704 3703 <
+7167: 3639 3640 3705 <
+7168: 3639 3705 3704 <
+7169: 3641 3642 3707 <
+7170: 3641 3707 3706 <
+7171: 3642 3643 3708 <
+7172: 3642 3708 3707 <
+7173: 3643 3644 3709 <
+7174: 3643 3709 3708 <
+7175: 3644 3645 3710 <
+7176: 3644 3710 3709 <
+7177: 3645 3646 3711 <
+7178: 3645 3711 3710 <
+7179: 3646 3647 3712 <
+7180: 3646 3712 3711 <
+7181: 3647 3648 3713 <
+7182: 3647 3713 3712 <
+7183: 3648 3649 3714 <
+7184: 3648 3714 3713 <
+7185: 3649 3650 3715 <
+7186: 3649 3715 3714 <
+7187: 3650 3651 3716 <
+7188: 3650 3716 3715 <
+7189: 3651 3652 3717 <
+7190: 3651 3717 3716 <
+7191: 3652 3653 3718 <
+7192: 3652 3718 3717 <
+7193: 3653 3654 3719 <
+7194: 3653 3719 3718 <
+7195: 3654 3655 3720 <
+7196: 3654 3720 3719 <
+7197: 3655 3656 3721 <
+7198: 3655 3721 3720 <
+7199: 3656 3657 3722 <
+7200: 3656 3722 3721 <
+7201: 3657 3658 3723 <
+7202: 3657 3723 3722 <
+7203: 3658 3659 3724 <
+7204: 3658 3724 3723 <
+7205: 3659 3660 3725 <
+7206: 3659 3725 3724 <
+7207: 3660 3661 3726 <
+7208: 3660 3726 3725 <
+7209: 3661 3662 3727 <
+7210: 3661 3727 3726 <
+7211: 3662 3663 3728 <
+7212: 3662 3728 3727 <
+7213: 3663 3664 3729 <
+7214: 3663 3729 3728 <
+7215: 3664 3665 3730 <
+7216: 3664 3730 3729 <
+7217: 3665 3666 3731 <
+7218: 3665 3731 3730 <
+7219: 3666 3667 3732 <
+7220: 3666 3732 3731 <
+7221: 3667 3668 3733 <
+7222: 3667 3733 3732 <
+7223: 3668 3669 3734 <
+7224: 3668 3734 3733 <
+7225: 3669 3670 3735 <
+7226: 3669 3735 3734 <
+7227: 3670 3671 3736 <
+7228: 3670 3736 3735 <
+7229: 3671 3672 3737 <
+7230: 3671 3737 3736 <
+7231: 3672 3673 3738 <
+7232: 3672 3738 3737 <
+7233: 3673 3674 3739 <
+7234: 3673 3739 3738 <
+7235: 3674 3675 3740 <
+7236: 3674 3740 3739 <
+7237: 3675 3676 3741 <
+7238: 3675 3741 3740 <
+7239: 3676 3677 3742 <
+7240: 3676 3742 3741 <
+7241: 3677 3678 3743 <
+7242: 3677 3743 3742 <
+7243: 3678 3679 3744 <
+7244: 3678 3744 3743 <
+7245: 3679 3680 3745 <
+7246: 3679 3745 3744 <
+7247: 3680 3681 3746 <
+7248: 3680 3746 3745 <
+7249: 3681 3682 3747 <
+7250: 3681 3747 3746 <
+7251: 3682 3683 3748 <
+7252: 3682 3748 3747 <
+7253: 3683 3684 3749 <
+7254: 3683 3749 3748 <
+7255: 3684 3685 3750 <
+7256: 3684 3750 3749 <
+7257: 3685 3686 3751 <
+7258: 3685 3751 3750 <
+7259: 3686 3687 3752 <
+7260: 3686 3752 3751 <
+7261: 3687 3688 3753 <
+7262: 3687 3753 3752 <
+7263: 3688 3689 3754 <
+7264: 3688 3754 3753 <
+7265: 3689 3690 3755 <
+7266: 3689 3755 3754 <
+7267: 3690 3691 3756 <
+7268: 3690 3756 3755 <
+7269: 3691 3692 3757 <
+7270: 3691 3757 3756 <
+7271: 3692 3693 3758 <
+7272: 3692 3758 3757 <
+7273: 3693 3694 3759 <
+7274: 3693 3759 3758 <
+7275: 3694 3695 3760 <
+7276: 3694 3760 3759 <
+7277: 3695 3696 3761 <
+7278: 3695 3761 3760 <
+7279: 3696 3697 3762 <
+7280: 3696 3762 3761 <
+7281: 3697 3698 3763 <
+7282: 3697 3763 3762 <
+7283: 3698 3699 3764 <
+7284: 3698 3764 3763 <
+7285: 3699 3700 3765 <
+7286: 3699 3765 3764 <
+7287: 3700 3701 3766 <
+7288: 3700 3766 3765 <
+7289: 3701 3702 3767 <
+7290: 3701 3767 3766 <
+7291: 3702 3703 3768 <
+7292: 3702 3768 3767 <
+7293: 3703 3704 3769 <
+7294: 3703 3769 3768 <
+7295: 3704 3705 3770 <
+7296: 3704 3770 3769 <
+7297: 3706 3707 3772 <
+7298: 3706 3772 3771 <
+7299: 3707 3708 3773 <
+7300: 3707 3773 3772 <
+7301: 3708 3709 3774 <
+7302: 3708 3774 3773 <
+7303: 3709 3710 3775 <
+7304: 3709 3775 3774 <
+7305: 3710 3711 3776 <
+7306: 3710 3776 3775 <
+7307: 3711 3712 3777 <
+7308: 3711 3777 3776 <
+7309: 3712 3713 3778 <
+7310: 3712 3778 3777 <
+7311: 3713 3714 3779 <
+7312: 3713 3779 3778 <
+7313: 3714 3715 3780 <
+7314: 3714 3780 3779 <
+7315: 3715 3716 3781 <
+7316: 3715 3781 3780 <
+7317: 3716 3717 3782 <
+7318: 3716 3782 3781 <
+7319: 3717 3718 3783 <
+7320: 3717 3783 3782 <
+7321: 3718 3719 3784 <
+7322: 3718 3784 3783 <
+7323: 3719 3720 3785 <
+7324: 3719 3785 3784 <
+7325: 3720 3721 3786 <
+7326: 3720 3786 3785 <
+7327: 3721 3722 3787 <
+7328: 3721 3787 3786 <
+7329: 3722 3723 3788 <
+7330: 3722 3788 3787 <
+7331: 3723 3724 3789 <
+7332: 3723 3789 3788 <
+7333: 3724 3725 3790 <
+7334: 3724 3790 3789 <
+7335: 3725 3726 3791 <
+7336: 3725 3791 3790 <
+7337: 3726 3727 3792 <
+7338: 3726 3792 3791 <
+7339: 3727 3728 3793 <
+7340: 3727 3793 3792 <
+7341: 3728 3729 3794 <
+7342: 3728 3794 3793 <
+7343: 3729 3730 3795 <
+7344: 3729 3795 3794 <
+7345: 3730 3731 3796 <
+7346: 3730 3796 3795 <
+7347: 3731 3732 3797 <
+7348: 3731 3797 3796 <
+7349: 3732 3733 3798 <
+7350: 3732 3798 3797 <
+7351: 3733 3734 3799 <
+7352: 3733 3799 3798 <
+7353: 3734 3735 3800 <
+7354: 3734 3800 3799 <
+7355: 3735 3736 3801 <
+7356: 3735 3801 3800 <
+7357: 3736 3737 3802 <
+7358: 3736 3802 3801 <
+7359: 3737 3738 3803 <
+7360: 3737 3803 3802 <
+7361: 3738 3739 3804 <
+7362: 3738 3804 3803 <
+7363: 3739 3740 3805 <
+7364: 3739 3805 3804 <
+7365: 3740 3741 3806 <
+7366: 3740 3806 3805 <
+7367: 3741 3742 3807 <
+7368: 3741 3807 3806 <
+7369: 3742 3743 3808 <
+7370: 3742 3808 3807 <
+7371: 3743 3744 3809 <
+7372: 3743 3809 3808 <
+7373: 3744 3745 3810 <
+7374: 3744 3810 3809 <
+7375: 3745 3746 3811 <
+7376: 3745 3811 3810 <
+7377: 3746 3747 3812 <
+7378: 3746 3812 3811 <
+7379: 3747 3748 3813 <
+7380: 3747 3813 3812 <
+7381: 3748 3749 3814 <
+7382: 3748 3814 3813 <
+7383: 3749 3750 3815 <
+7384: 3749 3815 3814 <
+7385: 3750 3751 3816 <
+7386: 3750 3816 3815 <
+7387: 3751 3752 3817 <
+7388: 3751 3817 3816 <
+7389: 3752 3753 3818 <
+7390: 3752 3818 3817 <
+7391: 3753 3754 3819 <
+7392: 3753 3819 3818 <
+7393: 3754 3755 3820 <
+7394: 3754 3820 3819 <
+7395: 3755 3756 3821 <
+7396: 3755 3821 3820 <
+7397: 3756 3757 3822 <
+7398: 3756 3822 3821 <
+7399: 3757 3758 3823 <
+7400: 3757 3823 3822 <
+7401: 3758 3759 3824 <
+7402: 3758 3824 3823 <
+7403: 3759 3760 3825 <
+7404: 3759 3825 3824 <
+7405: 3760 3761 3826 <
+7406: 3760 3826 3825 <
+7407: 3761 3762 3827 <
+7408: 3761 3827 3826 <
+7409: 3762 3763 3828 <
+7410: 3762 3828 3827 <
+7411: 3763 3764 3829 <
+7412: 3763 3829 3828 <
+7413: 3764 3765 3830 <
+7414: 3764 3830 3829 <
+7415: 3765 3766 3831 <
+7416: 3765 3831 3830 <
+7417: 3766 3767 3832 <
+7418: 3766 3832 3831 <
+7419: 3767 3768 3833 <
+7420: 3767 3833 3832 <
+7421: 3768 3769 3834 <
+7422: 3768 3834 3833 <
+7423: 3769 3770 3835 <
+7424: 3769 3835 3834 <
+7425: 3771 3772 3837 <
+7426: 3771 3837 3836 <
+7427: 3772 3773 3838 <
+7428: 3772 3838 3837 <
+7429: 3773 3774 3839 <
+7430: 3773 3839 3838 <
+7431: 3774 3775 3840 <
+7432: 3774 3840 3839 <
+7433: 3775 3776 3841 <
+7434: 3775 3841 3840 <
+7435: 3776 3777 3842 <
+7436: 3776 3842 3841 <
+7437: 3777 3778 3843 <
+7438: 3777 3843 3842 <
+7439: 3778 3779 3844 <
+7440: 3778 3844 3843 <
+7441: 3779 3780 3845 <
+7442: 3779 3845 3844 <
+7443: 3780 3781 3846 <
+7444: 3780 3846 3845 <
+7445: 3781 3782 3847 <
+7446: 3781 3847 3846 <
+7447: 3782 3783 3848 <
+7448: 3782 3848 3847 <
+7449: 3783 3784 3849 <
+7450: 3783 3849 3848 <
+7451: 3784 3785 3850 <
+7452: 3784 3850 3849 <
+7453: 3785 3786 3851 <
+7454: 3785 3851 3850 <
+7455: 3786 3787 3852 <
+7456: 3786 3852 3851 <
+7457: 3787 3788 3853 <
+7458: 3787 3853 3852 <
+7459: 3788 3789 3854 <
+7460: 3788 3854 3853 <
+7461: 3789 3790 3855 <
+7462: 3789 3855 3854 <
+7463: 3790 3791 3856 <
+7464: 3790 3856 3855 <
+7465: 3791 3792 3857 <
+7466: 3791 3857 3856 <
+7467: 3792 3793 3858 <
+7468: 3792 3858 3857 <
+7469: 3793 3794 3859 <
+7470: 3793 3859 3858 <
+7471: 3794 3795 3860 <
+7472: 3794 3860 3859 <
+7473: 3795 3796 3861 <
+7474: 3795 3861 3860 <
+7475: 3796 3797 3862 <
+7476: 3796 3862 3861 <
+7477: 3797 3798 3863 <
+7478: 3797 3863 3862 <
+7479: 3798 3799 3864 <
+7480: 3798 3864 3863 <
+7481: 3799 3800 3865 <
+7482: 3799 3865 3864 <
+7483: 3800 3801 3866 <
+7484: 3800 3866 3865 <
+7485: 3801 3802 3867 <
+7486: 3801 3867 3866 <
+7487: 3802 3803 3868 <
+7488: 3802 3868 3867 <
+7489: 3803 3804 3869 <
+7490: 3803 3869 3868 <
+7491: 3804 3805 3870 <
+7492: 3804 3870 3869 <
+7493: 3805 3806 3871 <
+7494: 3805 3871 3870 <
+7495: 3806 3807 3872 <
+7496: 3806 3872 3871 <
+7497: 3807 3808 3873 <
+7498: 3807 3873 3872 <
+7499: 3808 3809 3874 <
+7500: 3808 3874 3873 <
+7501: 3809 3810 3875 <
+7502: 3809 3875 3874 <
+7503: 3810 3811 3876 <
+7504: 3810 3876 3875 <
+7505: 3811 3812 3877 <
+7506: 3811 3877 3876 <
+7507: 3812 3813 3878 <
+7508: 3812 3878 3877 <
+7509: 3813 3814 3879 <
+7510: 3813 3879 3878 <
+7511: 3814 3815 3880 <
+7512: 3814 3880 3879 <
+7513: 3815 3816 3881 <
+7514: 3815 3881 3880 <
+7515: 3816 3817 3882 <
+7516: 3816 3882 3881 <
+7517: 3817 3818 3883 <
+7518: 3817 3883 3882 <
+7519: 3818 3819 3884 <
+7520: 3818 3884 3883 <
+7521: 3819 3820 3885 <
+7522: 3819 3885 3884 <
+7523: 3820 3821 3886 <
+7524: 3820 3886 3885 <
+7525: 3821 3822 3887 <
+7526: 3821 3887 3886 <
+7527: 3822 3823 3888 <
+7528: 3822 3888 3887 <
+7529: 3823 3824 3889 <
+7530: 3823 3889 3888 <
+7531: 3824 3825 3890 <
+7532: 3824 3890 3889 <
+7533: 3825 3826 3891 <
+7534: 3825 3891 3890 <
+7535: 3826 3827 3892 <
+7536: 3826 3892 3891 <
+7537: 3827 3828 3893 <
+7538: 3827 3893 3892 <
+7539: 3828 3829 3894 <
+7540: 3828 3894 3893 <
+7541: 3829 3830 3895 <
+7542: 3829 3895 3894 <
+7543: 3830 3831 3896 <
+7544: 3830 3896 3895 <
+7545: 3831 3832 3897 <
+7546: 3831 3897 3896 <
+7547: 3832 3833 3898 <
+7548: 3832 3898 3897 <
+7549: 3833 3834 3899 <
+7550: 3833 3899 3898 <
+7551: 3834 3835 3900 <
+7552: 3834 3900 3899 <
+7553: 3836 3837 3902 <
+7554: 3836 3902 3901 <
+7555: 3837 3838 3903 <
+7556: 3837 3903 3902 <
+7557: 3838 3839 3904 <
+7558: 3838 3904 3903 <
+7559: 3839 3840 3905 <
+7560: 3839 3905 3904 <
+7561: 3840 3841 3906 <
+7562: 3840 3906 3905 <
+7563: 3841 3842 3907 <
+7564: 3841 3907 3906 <
+7565: 3842 3843 3908 <
+7566: 3842 3908 3907 <
+7567: 3843 3844 3909 <
+7568: 3843 3909 3908 <
+7569: 3844 3845 3910 <
+7570: 3844 3910 3909 <
+7571: 3845 3846 3911 <
+7572: 3845 3911 3910 <
+7573: 3846 3847 3912 <
+7574: 3846 3912 3911 <
+7575: 3847 3848 3913 <
+7576: 3847 3913 3912 <
+7577: 3848 3849 3914 <
+7578: 3848 3914 3913 <
+7579: 3849 3850 3915 <
+7580: 3849 3915 3914 <
+7581: 3850 3851 3916 <
+7582: 3850 3916 3915 <
+7583: 3851 3852 3917 <
+7584: 3851 3917 3916 <
+7585: 3852 3853 3918 <
+7586: 3852 3918 3917 <
+7587: 3853 3854 3919 <
+7588: 3853 3919 3918 <
+7589: 3854 3855 3920 <
+7590: 3854 3920 3919 <
+7591: 3855 3856 3921 <
+7592: 3855 3921 3920 <
+7593: 3856 3857 3922 <
+7594: 3856 3922 3921 <
+7595: 3857 3858 3923 <
+7596: 3857 3923 3922 <
+7597: 3858 3859 3924 <
+7598: 3858 3924 3923 <
+7599: 3859 3860 3925 <
+7600: 3859 3925 3924 <
+7601: 3860 3861 3926 <
+7602: 3860 3926 3925 <
+7603: 3861 3862 3927 <
+7604: 3861 3927 3926 <
+7605: 3862 3863 3928 <
+7606: 3862 3928 3927 <
+7607: 3863 3864 3929 <
+7608: 3863 3929 3928 <
+7609: 3864 3865 3930 <
+7610: 3864 3930 3929 <
+7611: 3865 3866 3931 <
+7612: 3865 3931 3930 <
+7613: 3866 3867 3932 <
+7614: 3866 3932 3931 <
+7615: 3867 3868 3933 <
+7616: 3867 3933 3932 <
+7617: 3868 3869 3934 <
+7618: 3868 3934 3933 <
+7619: 3869 3870 3935 <
+7620: 3869 3935 3934 <
+7621: 3870 3871 3936 <
+7622: 3870 3936 3935 <
+7623: 3871 3872 3937 <
+7624: 3871 3937 3936 <
+7625: 3872 3873 3938 <
+7626: 3872 3938 3937 <
+7627: 3873 3874 3939 <
+7628: 3873 3939 3938 <
+7629: 3874 3875 3940 <
+7630: 3874 3940 3939 <
+7631: 3875 3876 3941 <
+7632: 3875 3941 3940 <
+7633: 3876 3877 3942 <
+7634: 3876 3942 3941 <
+7635: 3877 3878 3943 <
+7636: 3877 3943 3942 <
+7637: 3878 3879 3944 <
+7638: 3878 3944 3943 <
+7639: 3879 3880 3945 <
+7640: 3879 3945 3944 <
+7641: 3880 3881 3946 <
+7642: 3880 3946 3945 <
+7643: 3881 3882 3947 <
+7644: 3881 3947 3946 <
+7645: 3882 3883 3948 <
+7646: 3882 3948 3947 <
+7647: 3883 3884 3949 <
+7648: 3883 3949 3948 <
+7649: 3884 3885 3950 <
+7650: 3884 3950 3949 <
+7651: 3885 3886 3951 <
+7652: 3885 3951 3950 <
+7653: 3886 3887 3952 <
+7654: 3886 3952 3951 <
+7655: 3887 3888 3953 <
+7656: 3887 3953 3952 <
+7657: 3888 3889 3954 <
+7658: 3888 3954 3953 <
+7659: 3889 3890 3955 <
+7660: 3889 3955 3954 <
+7661: 3890 3891 3956 <
+7662: 3890 3956 3955 <
+7663: 3891 3892 3957 <
+7664: 3891 3957 3956 <
+7665: 3892 3893 3958 <
+7666: 3892 3958 3957 <
+7667: 3893 3894 3959 <
+7668: 3893 3959 3958 <
+7669: 3894 3895 3960 <
+7670: 3894 3960 3959 <
+7671: 3895 3896 3961 <
+7672: 3895 3961 3960 <
+7673: 3896 3897 3962 <
+7674: 3896 3962 3961 <
+7675: 3897 3898 3963 <
+7676: 3897 3963 3962 <
+7677: 3898 3899 3964 <
+7678: 3898 3964 3963 <
+7679: 3899 3900 3965 <
+7680: 3899 3965 3964 <
+7681: 3901 3902 3967 <
+7682: 3901 3967 3966 <
+7683: 3902 3903 3968 <
+7684: 3902 3968 3967 <
+7685: 3903 3904 3969 <
+7686: 3903 3969 3968 <
+7687: 3904 3905 3970 <
+7688: 3904 3970 3969 <
+7689: 3905 3906 3971 <
+7690: 3905 3971 3970 <
+7691: 3906 3907 3972 <
+7692: 3906 3972 3971 <
+7693: 3907 3908 3973 <
+7694: 3907 3973 3972 <
+7695: 3908 3909 3974 <
+7696: 3908 3974 3973 <
+7697: 3909 3910 3975 <
+7698: 3909 3975 3974 <
+7699: 3910 3911 3976 <
+7700: 3910 3976 3975 <
+7701: 3911 3912 3977 <
+7702: 3911 3977 3976 <
+7703: 3912 3913 3978 <
+7704: 3912 3978 3977 <
+7705: 3913 3914 3979 <
+7706: 3913 3979 3978 <
+7707: 3914 3915 3980 <
+7708: 3914 3980 3979 <
+7709: 3915 3916 3981 <
+7710: 3915 3981 3980 <
+7711: 3916 3917 3982 <
+7712: 3916 3982 3981 <
+7713: 3917 3918 3983 <
+7714: 3917 3983 3982 <
+7715: 3918 3919 3984 <
+7716: 3918 3984 3983 <
+7717: 3919 3920 3985 <
+7718: 3919 3985 3984 <
+7719: 3920 3921 3986 <
+7720: 3920 3986 3985 <
+7721: 3921 3922 3987 <
+7722: 3921 3987 3986 <
+7723: 3922 3923 3988 <
+7724: 3922 3988 3987 <
+7725: 3923 3924 3989 <
+7726: 3923 3989 3988 <
+7727: 3924 3925 3990 <
+7728: 3924 3990 3989 <
+7729: 3925 3926 3991 <
+7730: 3925 3991 3990 <
+7731: 3926 3927 3992 <
+7732: 3926 3992 3991 <
+7733: 3927 3928 3993 <
+7734: 3927 3993 3992 <
+7735: 3928 3929 3994 <
+7736: 3928 3994 3993 <
+7737: 3929 3930 3995 <
+7738: 3929 3995 3994 <
+7739: 3930 3931 3996 <
+7740: 3930 3996 3995 <
+7741: 3931 3932 3997 <
+7742: 3931 3997 3996 <
+7743: 3932 3933 3998 <
+7744: 3932 3998 3997 <
+7745: 3933 3934 3999 <
+7746: 3933 3999 3998 <
+7747: 3934 3935 4000 <
+7748: 3934 4000 3999 <
+7749: 3935 3936 4001 <
+7750: 3935 4001 4000 <
+7751: 3936 3937 4002 <
+7752: 3936 4002 4001 <
+7753: 3937 3938 4003 <
+7754: 3937 4003 4002 <
+7755: 3938 3939 4004 <
+7756: 3938 4004 4003 <
+7757: 3939 3940 4005 <
+7758: 3939 4005 4004 <
+7759: 3940 3941 4006 <
+7760: 3940 4006 4005 <
+7761: 3941 3942 4007 <
+7762: 3941 4007 4006 <
+7763: 3942 3943 4008 <
+7764: 3942 4008 4007 <
+7765: 3943 3944 4009 <
+7766: 3943 4009 4008 <
+7767: 3944 3945 4010 <
+7768: 3944 4010 4009 <
+7769: 3945 3946 4011 <
+7770: 3945 4011 4010 <
+7771: 3946 3947 4012 <
+7772: 3946 4012 4011 <
+7773: 3947 3948 4013 <
+7774: 3947 4013 4012 <
+7775: 3948 3949 4014 <
+7776: 3948 4014 4013 <
+7777: 3949 3950 4015 <
+7778: 3949 4015 4014 <
+7779: 3950 3951 4016 <
+7780: 3950 4016 4015 <
+7781: 3951 3952 4017 <
+7782: 3951 4017 4016 <
+7783: 3952 3953 4018 <
+7784: 3952 4018 4017 <
+7785: 3953 3954 4019 <
+7786: 3953 4019 4018 <
+7787: 3954 3955 4020 <
+7788: 3954 4020 4019 <
+7789: 3955 3956 4021 <
+7790: 3955 4021 4020 <
+7791: 3956 3957 4022 <
+7792: 3956 4022 4021 <
+7793: 3957 3958 4023 <
+7794: 3957 4023 4022 <
+7795: 3958 3959 4024 <
+7796: 3958 4024 4023 <
+7797: 3959 3960 4025 <
+7798: 3959 4025 4024 <
+7799: 3960 3961 4026 <
+7800: 3960 4026 4025 <
+7801: 3961 3962 4027 <
+7802: 3961 4027 4026 <
+7803: 3962 3963 4028 <
+7804: 3962 4028 4027 <
+7805: 3963 3964 4029 <
+7806: 3963 4029 4028 <
+7807: 3964 3965 4030 <
+7808: 3964 4030 4029 <
+7809: 3966 3967 4032 <
+7810: 3966 4032 4031 <
+7811: 3967 3968 4033 <
+7812: 3967 4033 4032 <
+7813: 3968 3969 4034 <
+7814: 3968 4034 4033 <
+7815: 3969 3970 4035 <
+7816: 3969 4035 4034 <
+7817: 3970 3971 4036 <
+7818: 3970 4036 4035 <
+7819: 3971 3972 4037 <
+7820: 3971 4037 4036 <
+7821: 3972 3973 4038 <
+7822: 3972 4038 4037 <
+7823: 3973 3974 4039 <
+7824: 3973 4039 4038 <
+7825: 3974 3975 4040 <
+7826: 3974 4040 4039 <
+7827: 3975 3976 4041 <
+7828: 3975 4041 4040 <
+7829: 3976 3977 4042 <
+7830: 3976 4042 4041 <
+7831: 3977 3978 4043 <
+7832: 3977 4043 4042 <
+7833: 3978 3979 4044 <
+7834: 3978 4044 4043 <
+7835: 3979 3980 4045 <
+7836: 3979 4045 4044 <
+7837: 3980 3981 4046 <
+7838: 3980 4046 4045 <
+7839: 3981 3982 4047 <
+7840: 3981 4047 4046 <
+7841: 3982 3983 4048 <
+7842: 3982 4048 4047 <
+7843: 3983 3984 4049 <
+7844: 3983 4049 4048 <
+7845: 3984 3985 4050 <
+7846: 3984 4050 4049 <
+7847: 3985 3986 4051 <
+7848: 3985 4051 4050 <
+7849: 3986 3987 4052 <
+7850: 3986 4052 4051 <
+7851: 3987 3988 4053 <
+7852: 3987 4053 4052 <
+7853: 3988 3989 4054 <
+7854: 3988 4054 4053 <
+7855: 3989 3990 4055 <
+7856: 3989 4055 4054 <
+7857: 3990 3991 4056 <
+7858: 3990 4056 4055 <
+7859: 3991 3992 4057 <
+7860: 3991 4057 4056 <
+7861: 3992 3993 4058 <
+7862: 3992 4058 4057 <
+7863: 3993 3994 4059 <
+7864: 3993 4059 4058 <
+7865: 3994 3995 4060 <
+7866: 3994 4060 4059 <
+7867: 3995 3996 4061 <
+7868: 3995 4061 4060 <
+7869: 3996 3997 4062 <
+7870: 3996 4062 4061 <
+7871: 3997 3998 4063 <
+7872: 3997 4063 4062 <
+7873: 3998 3999 4064 <
+7874: 3998 4064 4063 <
+7875: 3999 4000 4065 <
+7876: 3999 4065 4064 <
+7877: 4000 4001 4066 <
+7878: 4000 4066 4065 <
+7879: 4001 4002 4067 <
+7880: 4001 4067 4066 <
+7881: 4002 4003 4068 <
+7882: 4002 4068 4067 <
+7883: 4003 4004 4069 <
+7884: 4003 4069 4068 <
+7885: 4004 4005 4070 <
+7886: 4004 4070 4069 <
+7887: 4005 4006 4071 <
+7888: 4005 4071 4070 <
+7889: 4006 4007 4072 <
+7890: 4006 4072 4071 <
+7891: 4007 4008 4073 <
+7892: 4007 4073 4072 <
+7893: 4008 4009 4074 <
+7894: 4008 4074 4073 <
+7895: 4009 4010 4075 <
+7896: 4009 4075 4074 <
+7897: 4010 4011 4076 <
+7898: 4010 4076 4075 <
+7899: 4011 4012 4077 <
+7900: 4011 4077 4076 <
+7901: 4012 4013 4078 <
+7902: 4012 4078 4077 <
+7903: 4013 4014 4079 <
+7904: 4013 4079 4078 <
+7905: 4014 4015 4080 <
+7906: 4014 4080 4079 <
+7907: 4015 4016 4081 <
+7908: 4015 4081 4080 <
+7909: 4016 4017 4082 <
+7910: 4016 4082 4081 <
+7911: 4017 4018 4083 <
+7912: 4017 4083 4082 <
+7913: 4018 4019 4084 <
+7914: 4018 4084 4083 <
+7915: 4019 4020 4085 <
+7916: 4019 4085 4084 <
+7917: 4020 4021 4086 <
+7918: 4020 4086 4085 <
+7919: 4021 4022 4087 <
+7920: 4021 4087 4086 <
+7921: 4022 4023 4088 <
+7922: 4022 4088 4087 <
+7923: 4023 4024 4089 <
+7924: 4023 4089 4088 <
+7925: 4024 4025 4090 <
+7926: 4024 4090 4089 <
+7927: 4025 4026 4091 <
+7928: 4025 4091 4090 <
+7929: 4026 4027 4092 <
+7930: 4026 4092 4091 <
+7931: 4027 4028 4093 <
+7932: 4027 4093 4092 <
+7933: 4028 4029 4094 <
+7934: 4028 4094 4093 <
+7935: 4029 4030 4095 <
+7936: 4029 4095 4094 <
+7937: 4031 4032 4097 <
+7938: 4031 4097 4096 <
+7939: 4032 4033 4098 <
+7940: 4032 4098 4097 <
+7941: 4033 4034 4099 <
+7942: 4033 4099 4098 <
+7943: 4034 4035 4100 <
+7944: 4034 4100 4099 <
+7945: 4035 4036 4101 <
+7946: 4035 4101 4100 <
+7947: 4036 4037 4102 <
+7948: 4036 4102 4101 <
+7949: 4037 4038 4103 <
+7950: 4037 4103 4102 <
+7951: 4038 4039 4104 <
+7952: 4038 4104 4103 <
+7953: 4039 4040 4105 <
+7954: 4039 4105 4104 <
+7955: 4040 4041 4106 <
+7956: 4040 4106 4105 <
+7957: 4041 4042 4107 <
+7958: 4041 4107 4106 <
+7959: 4042 4043 4108 <
+7960: 4042 4108 4107 <
+7961: 4043 4044 4109 <
+7962: 4043 4109 4108 <
+7963: 4044 4045 4110 <
+7964: 4044 4110 4109 <
+7965: 4045 4046 4111 <
+7966: 4045 4111 4110 <
+7967: 4046 4047 4112 <
+7968: 4046 4112 4111 <
+7969: 4047 4048 4113 <
+7970: 4047 4113 4112 <
+7971: 4048 4049 4114 <
+7972: 4048 4114 4113 <
+7973: 4049 4050 4115 <
+7974: 4049 4115 4114 <
+7975: 4050 4051 4116 <
+7976: 4050 4116 4115 <
+7977: 4051 4052 4117 <
+7978: 4051 4117 4116 <
+7979: 4052 4053 4118 <
+7980: 4052 4118 4117 <
+7981: 4053 4054 4119 <
+7982: 4053 4119 4118 <
+7983: 4054 4055 4120 <
+7984: 4054 4120 4119 <
+7985: 4055 4056 4121 <
+7986: 4055 4121 4120 <
+7987: 4056 4057 4122 <
+7988: 4056 4122 4121 <
+7989: 4057 4058 4123 <
+7990: 4057 4123 4122 <
+7991: 4058 4059 4124 <
+7992: 4058 4124 4123 <
+7993: 4059 4060 4125 <
+7994: 4059 4125 4124 <
+7995: 4060 4061 4126 <
+7996: 4060 4126 4125 <
+7997: 4061 4062 4127 <
+7998: 4061 4127 4126 <
+7999: 4062 4063 4128 <
+8000: 4062 4128 4127 <
+8001: 4063 4064 4129 <
+8002: 4063 4129 4128 <
+8003: 4064 4065 4130 <
+8004: 4064 4130 4129 <
+8005: 4065 4066 4131 <
+8006: 4065 4131 4130 <
+8007: 4066 4067 4132 <
+8008: 4066 4132 4131 <
+8009: 4067 4068 4133 <
+8010: 4067 4133 4132 <
+8011: 4068 4069 4134 <
+8012: 4068 4134 4133 <
+8013: 4069 4070 4135 <
+8014: 4069 4135 4134 <
+8015: 4070 4071 4136 <
+8016: 4070 4136 4135 <
+8017: 4071 4072 4137 <
+8018: 4071 4137 4136 <
+8019: 4072 4073 4138 <
+8020: 4072 4138 4137 <
+8021: 4073 4074 4139 <
+8022: 4073 4139 4138 <
+8023: 4074 4075 4140 <
+8024: 4074 4140 4139 <
+8025: 4075 4076 4141 <
+8026: 4075 4141 4140 <
+8027: 4076 4077 4142 <
+8028: 4076 4142 4141 <
+8029: 4077 4078 4143 <
+8030: 4077 4143 4142 <
+8031: 4078 4079 4144 <
+8032: 4078 4144 4143 <
+8033: 4079 4080 4145 <
+8034: 4079 4145 4144 <
+8035: 4080 4081 4146 <
+8036: 4080 4146 4145 <
+8037: 4081 4082 4147 <
+8038: 4081 4147 4146 <
+8039: 4082 4083 4148 <
+8040: 4082 4148 4147 <
+8041: 4083 4084 4149 <
+8042: 4083 4149 4148 <
+8043: 4084 4085 4150 <
+8044: 4084 4150 4149 <
+8045: 4085 4086 4151 <
+8046: 4085 4151 4150 <
+8047: 4086 4087 4152 <
+8048: 4086 4152 4151 <
+8049: 4087 4088 4153 <
+8050: 4087 4153 4152 <
+8051: 4088 4089 4154 <
+8052: 4088 4154 4153 <
+8053: 4089 4090 4155 <
+8054: 4089 4155 4154 <
+8055: 4090 4091 4156 <
+8056: 4090 4156 4155 <
+8057: 4091 4092 4157 <
+8058: 4091 4157 4156 <
+8059: 4092 4093 4158 <
+8060: 4092 4158 4157 <
+8061: 4093 4094 4159 <
+8062: 4093 4159 4158 <
+8063: 4094 4095 4160 <
+8064: 4094 4160 4159 <
+8065: 4096 4097 4162 <
+8066: 4096 4162 4161 <
+8067: 4097 4098 4163 <
+8068: 4097 4163 4162 <
+8069: 4098 4099 4164 <
+8070: 4098 4164 4163 <
+8071: 4099 4100 4165 <
+8072: 4099 4165 4164 <
+8073: 4100 4101 4166 <
+8074: 4100 4166 4165 <
+8075: 4101 4102 4167 <
+8076: 4101 4167 4166 <
+8077: 4102 4103 4168 <
+8078: 4102 4168 4167 <
+8079: 4103 4104 4169 <
+8080: 4103 4169 4168 <
+8081: 4104 4105 4170 <
+8082: 4104 4170 4169 <
+8083: 4105 4106 4171 <
+8084: 4105 4171 4170 <
+8085: 4106 4107 4172 <
+8086: 4106 4172 4171 <
+8087: 4107 4108 4173 <
+8088: 4107 4173 4172 <
+8089: 4108 4109 4174 <
+8090: 4108 4174 4173 <
+8091: 4109 4110 4175 <
+8092: 4109 4175 4174 <
+8093: 4110 4111 4176 <
+8094: 4110 4176 4175 <
+8095: 4111 4112 4177 <
+8096: 4111 4177 4176 <
+8097: 4112 4113 4178 <
+8098: 4112 4178 4177 <
+8099: 4113 4114 4179 <
+8100: 4113 4179 4178 <
+8101: 4114 4115 4180 <
+8102: 4114 4180 4179 <
+8103: 4115 4116 4181 <
+8104: 4115 4181 4180 <
+8105: 4116 4117 4182 <
+8106: 4116 4182 4181 <
+8107: 4117 4118 4183 <
+8108: 4117 4183 4182 <
+8109: 4118 4119 4184 <
+8110: 4118 4184 4183 <
+8111: 4119 4120 4185 <
+8112: 4119 4185 4184 <
+8113: 4120 4121 4186 <
+8114: 4120 4186 4185 <
+8115: 4121 4122 4187 <
+8116: 4121 4187 4186 <
+8117: 4122 4123 4188 <
+8118: 4122 4188 4187 <
+8119: 4123 4124 4189 <
+8120: 4123 4189 4188 <
+8121: 4124 4125 4190 <
+8122: 4124 4190 4189 <
+8123: 4125 4126 4191 <
+8124: 4125 4191 4190 <
+8125: 4126 4127 4192 <
+8126: 4126 4192 4191 <
+8127: 4127 4128 4193 <
+8128: 4127 4193 4192 <
+8129: 4128 4129 4194 <
+8130: 4128 4194 4193 <
+8131: 4129 4130 4195 <
+8132: 4129 4195 4194 <
+8133: 4130 4131 4196 <
+8134: 4130 4196 4195 <
+8135: 4131 4132 4197 <
+8136: 4131 4197 4196 <
+8137: 4132 4133 4198 <
+8138: 4132 4198 4197 <
+8139: 4133 4134 4199 <
+8140: 4133 4199 4198 <
+8141: 4134 4135 4200 <
+8142: 4134 4200 4199 <
+8143: 4135 4136 4201 <
+8144: 4135 4201 4200 <
+8145: 4136 4137 4202 <
+8146: 4136 4202 4201 <
+8147: 4137 4138 4203 <
+8148: 4137 4203 4202 <
+8149: 4138 4139 4204 <
+8150: 4138 4204 4203 <
+8151: 4139 4140 4205 <
+8152: 4139 4205 4204 <
+8153: 4140 4141 4206 <
+8154: 4140 4206 4205 <
+8155: 4141 4142 4207 <
+8156: 4141 4207 4206 <
+8157: 4142 4143 4208 <
+8158: 4142 4208 4207 <
+8159: 4143 4144 4209 <
+8160: 4143 4209 4208 <
+8161: 4144 4145 4210 <
+8162: 4144 4210 4209 <
+8163: 4145 4146 4211 <
+8164: 4145 4211 4210 <
+8165: 4146 4147 4212 <
+8166: 4146 4212 4211 <
+8167: 4147 4148 4213 <
+8168: 4147 4213 4212 <
+8169: 4148 4149 4214 <
+8170: 4148 4214 4213 <
+8171: 4149 4150 4215 <
+8172: 4149 4215 4214 <
+8173: 4150 4151 4216 <
+8174: 4150 4216 4215 <
+8175: 4151 4152 4217 <
+8176: 4151 4217 4216 <
+8177: 4152 4153 4218 <
+8178: 4152 4218 4217 <
+8179: 4153 4154 4219 <
+8180: 4153 4219 4218 <
+8181: 4154 4155 4220 <
+8182: 4154 4220 4219 <
+8183: 4155 4156 4221 <
+8184: 4155 4221 4220 <
+8185: 4156 4157 4222 <
+8186: 4156 4222 4221 <
+8187: 4157 4158 4223 <
+8188: 4157 4223 4222 <
+8189: 4158 4159 4224 <
+8190: 4158 4224 4223 <
+8191: 4159 4160 4225 <
+8192: 4159 4225 4224 <
+END
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/data_manager.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/data_manager.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/data_manager.py	(revision 3560)
@@ -0,0 +1,4050 @@
+"""datamanager.py - input output for AnuGA
+
+
+This module takes care of reading and writing datafiles such as topograhies,
+model output, etc
+
+
+Formats used within AnuGA:
+
+.sww: Netcdf format for storing model output f(t,x,y)
+.tms: Netcdf format for storing time series f(t)
+
+.xya: ASCII format for storing arbitrary points and associated attributes
+.pts: NetCDF format for storing arbitrary points and associated attributes
+
+.asc: ASCII format of regular DEMs as output from ArcView
+.prj: Associated ArcView file giving more meta data for asc format
+.ers: ERMapper header format of regular DEMs for ArcView
+
+.dem: NetCDF representation of regular DEM data
+
+.tsh: ASCII format for storing meshes and associated boundary and region info
+.msh: NetCDF format for storing meshes and associated boundary and region info
+
+.nc: Native ferret NetCDF format
+.geo: Houdinis ascii geometry format (?)
+
+
+A typical dataflow can be described as follows
+
+Manually created files:
+ASC, PRJ:     Digital elevation models (gridded)
+TSH:          Triangular meshes (e.g. created from anuga.pmesh)
+NC            Model outputs for use as boundary conditions (e.g from MOST)
+
+
+AUTOMATICALLY CREATED FILES:
+
+ASC, PRJ  ->  DEM  ->  PTS: Conversion of DEM's to native pts file
+
+NC -> SWW: Conversion of MOST bundary files to boundary sww
+
+PTS + TSH -> TSH with elevation: Least squares fit
+
+TSH -> SWW:  Conversion of TSH to sww viewable using Swollen
+
+TSH + Boundary SWW -> SWW: Simluation using abstract_2d_finite_volumes
+
+"""
+
+import exceptions
+class TitleValueError(exceptions.Exception): pass
+class DataMissingValuesError(exceptions.Exception): pass
+class DataFileNotOpenError(exceptions.Exception): pass
+class DataTimeError(exceptions.Exception): pass
+class DataDomainError(exceptions.Exception): pass
+
+
+
+import csv
+import os
+
+from Numeric import concatenate, array, Float, Int, Int32, resize, sometrue, \
+     searchsorted, zeros, allclose, around
+
+
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+from anuga.geospatial_data.geospatial_data import Geospatial_data
+from anuga.config import minimum_sww_depth
+
+def make_filename(s):
+    """Transform argument string into a suitable filename
+    """
+
+    s = s.strip()
+    s = s.replace(' ', '_')
+    s = s.replace('(', '')
+    s = s.replace(')', '')
+    s = s.replace('__', '_')
+
+    return s
+
+
+def check_dir(path, verbose=None):
+    """Check that specified path exists.
+    If path does not exist it will be created if possible
+
+    USAGE:
+       checkdir(path, verbose):
+
+    ARGUMENTS:
+        path -- Directory
+        verbose -- Flag verbose output (default: None)
+
+    RETURN VALUE:
+        Verified path including trailing separator
+
+    """
+
+    import os, sys
+    import os.path
+
+    if sys.platform in ['nt', 'dos', 'win32', 'what else?']:
+        unix = 0
+    else:
+        unix = 1
+
+
+    if path[-1] != os.sep:
+        path = path + os.sep  # Add separator for directories
+
+    path = os.path.expanduser(path) # Expand ~ or ~user in pathname
+    if not (os.access(path,os.R_OK and os.W_OK) or path == ''):
+        try:
+            exitcode=os.mkdir(path)
+
+            # Change access rights if possible
+            #
+            if unix:
+                exitcode=os.system('chmod 775 '+path)
+            else:
+                pass  # FIXME: What about acces rights under Windows?
+
+            if verbose: print 'MESSAGE: Directory', path, 'created.'
+
+        except:
+            print 'WARNING: Directory', path, 'could not be created.'
+            if unix:
+                path = '/tmp/'
+            else:
+                path = 'C:'
+
+            print 'Using directory %s instead' %path
+
+    return(path)
+
+
+
+def del_dir(path):
+    """Recursively delete directory path and all its contents
+    """
+
+    import os
+
+    if os.path.isdir(path):
+        for file in os.listdir(path):
+            X = os.path.join(path, file)
+
+
+            if os.path.isdir(X) and not os.path.islink(X):
+                del_dir(X)
+            else:
+                try:
+                    os.remove(X)
+                except:
+                    print "Could not remove file %s" %X
+
+        os.rmdir(path)
+
+
+
+def create_filename(datadir, filename, format, size=None, time=None):
+
+    import os
+    #from anuga.config import data_dir
+
+    FN = check_dir(datadir) + filename
+
+    if size is not None:
+        FN += '_size%d' %size
+
+    if time is not None:
+        FN += '_time%.2f' %time
+
+    FN += '.' + format
+    return FN
+
+
+def get_files(datadir, filename, format, size):
+    """Get all file (names) with gven name, size and format
+    """
+
+    import glob
+
+    import os
+    #from anuga.config import data_dir
+
+    dir = check_dir(datadir)
+
+    pattern = dir + os.sep + filename + '_size=%d*.%s' %(size, format)
+    return glob.glob(pattern)
+
+
+
+#Generic class for storing output to e.g. visualisation or checkpointing
+class Data_format:
+    """Generic interface to data formats
+    """
+
+
+    def __init__(self, domain, extension, mode = 'w'):
+        assert mode in ['r', 'w', 'a'], '''Mode %s must be either:''' %mode +\
+                                        '''   'w' (write)'''+\
+                                        '''   'r' (read)''' +\
+                                        '''   'a' (append)'''
+
+        #Create filename
+        #self.filename = create_filename(domain.get_datadir(),
+        #domain.get_name(), extension, len(domain))
+
+
+        self.filename = create_filename(domain.get_datadir(),
+            domain.get_name(), extension)
+
+        #print 'F', self.filename
+        self.timestep = 0
+        self.number_of_volumes = len(domain)
+        self.domain = domain
+
+
+        #FIXME: Should we have a general set_precision function?
+
+
+
+#Class for storing output to e.g. visualisation
+class Data_format_sww(Data_format):
+    """Interface to native NetCDF format (.sww) for storing model output
+
+    There are two kinds of data
+
+    1: Constant data: Vertex coordinates and field values. Stored once
+    2: Variable data: Conserved quantities. Stored once per timestep.
+
+    All data is assumed to reside at vertex locations.
+    """
+
+
+    def __init__(self, domain, mode = 'w',\
+                 max_size = 2000000000,
+                 recursion = False):
+        from Scientific.IO.NetCDF import NetCDFFile
+        from Numeric import Int, Float, Float32
+
+        self.precision = Float32 #Use single precision for quantities
+        if hasattr(domain, 'max_size'):
+            self.max_size = domain.max_size #file size max is 2Gig
+        else:
+            self.max_size = max_size
+        self.recursion = recursion
+        self.mode = mode
+
+        Data_format.__init__(self, domain, 'sww', mode)
+
+        if hasattr(domain, 'minimum_sww_depth'):
+            self.minimum_sww_depth =  domain.minimum_sww_depth
+        else:
+            self.minimum_sww_depth = minimum_sww_depth
+
+        # NetCDF file definition
+        fid = NetCDFFile(self.filename, mode)
+
+        if mode == 'w':
+
+            #Create new file
+            fid.institution = 'Geoscience Australia'
+            fid.description = 'Output from anuga.abstract_2d_finite_volumes suitable for plotting'
+
+            if domain.smooth:
+                fid.smoothing = 'Yes'
+            else:
+                fid.smoothing = 'No'
+
+            fid.order = domain.default_order
+
+            if hasattr(domain, 'texture'):
+                fid.texture = domain.texture
+        #else:
+            #    fid.texture = 'None'
+
+            #Reference point
+            #Start time in seconds since the epoch (midnight 1/1/1970)
+            #FIXME: Use Georef
+            fid.starttime = domain.starttime
+
+            # dimension definitions
+            fid.createDimension('number_of_volumes', self.number_of_volumes)
+            fid.createDimension('number_of_vertices', 3)
+
+            if domain.smooth is True:
+                fid.createDimension('number_of_points', len(domain.vertexlist))
+            else:
+                fid.createDimension('number_of_points', 3*self.number_of_volumes)
+
+            fid.createDimension('number_of_timesteps', None) #extensible
+
+            # variable definitions
+            fid.createVariable('x', self.precision, ('number_of_points',))
+            fid.createVariable('y', self.precision, ('number_of_points',))
+            fid.createVariable('elevation', self.precision, ('number_of_points',))
+            if domain.geo_reference is not None:
+                domain.geo_reference.write_NetCDF(fid)
+
+            #FIXME: Backwards compatibility
+            fid.createVariable('z', self.precision, ('number_of_points',))
+            #################################
+
+            fid.createVariable('volumes', Int, ('number_of_volumes',
+                                                'number_of_vertices'))
+
+            fid.createVariable('time', Float,  # Always use full precision lest two timesteps 
+	                                       # close to each other may appear as the same step 
+                               ('number_of_timesteps',))
+
+            fid.createVariable('stage', self.precision,
+                               ('number_of_timesteps',
+                                'number_of_points'))
+
+            fid.createVariable('xmomentum', self.precision,
+                               ('number_of_timesteps',
+                                'number_of_points'))
+
+            fid.createVariable('ymomentum', self.precision,
+                               ('number_of_timesteps',
+                                'number_of_points'))
+
+        #Close
+        fid.close()
+
+
+    def store_connectivity(self):
+        """Specialisation of store_connectivity for net CDF format
+
+        Writes x,y,z coordinates of triangles constituting
+        the bed elevation.
+        """
+
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        from Numeric import concatenate, Int
+
+        domain = self.domain
+
+        #Get NetCDF
+        fid = NetCDFFile(self.filename, 'a')  #Open existing file for append
+
+        # Get the variables
+        x = fid.variables['x']
+        y = fid.variables['y']
+        z = fid.variables['elevation']
+
+        volumes = fid.variables['volumes']
+
+        # Get X, Y and bed elevation Z
+        Q = domain.quantities['elevation']
+        X,Y,Z,V = Q.get_vertex_values(xy=True,
+                      precision = self.precision)
+
+
+
+        x[:] = X.astype(self.precision)
+        y[:] = Y.astype(self.precision)
+        z[:] = Z.astype(self.precision)
+
+        #FIXME: Backwards compatibility
+        z = fid.variables['z']
+        z[:] = Z.astype(self.precision)
+        ################################
+
+        volumes[:] = V.astype(volumes.typecode())
+
+        #Close
+        fid.close()
+
+    def store_timestep(self, names):
+        """Store time and named quantities to file
+        """
+        from Scientific.IO.NetCDF import NetCDFFile
+        import types
+        from time import sleep
+        from os import stat
+
+        minimum_sww_depth = 0.001
+        #minimum_sww_depth = 0.0  #FIXME pass in or read from domain
+        from Numeric import choose
+
+        #Get NetCDF
+        retries = 0
+        file_open = False
+        while not file_open and retries < 10:
+            try:
+                fid = NetCDFFile(self.filename, 'a') #Open existing file
+            except IOError:
+                #This could happen if someone was reading the file.
+                #In that case, wait a while and try again
+                msg = 'Warning (store_timestep): File %s could not be opened'\
+                      %self.filename
+                msg += ' - trying step %s again' %self.domain.time
+                print msg
+                retries += 1
+                sleep(1)
+            else:
+                file_open = True
+
+        if not file_open:
+            msg = 'File %s could not be opened for append' %self.filename
+            raise DataFileNotOpenError, msg
+
+
+
+        #Check to see if the file is already too big:
+        time = fid.variables['time']
+        i = len(time)+1
+        file_size = stat(self.filename)[6]
+        file_size_increase =  file_size/i
+        if file_size + file_size_increase > self.max_size*(2**self.recursion):
+            #in order to get the file name and start time correct,
+            #I change the domian.filename and domain.starttime.
+            #This is the only way to do this without changing
+            #other modules (I think).
+
+            #write a filename addon that won't break swollens reader
+            #(10.sww is bad)
+            filename_ext = '_time_%s'%self.domain.time
+            filename_ext = filename_ext.replace('.', '_')
+            #remember the old filename, then give domain a
+            #name with the extension
+            old_domain_filename = self.domain.filename
+            if not self.recursion:
+                self.domain.filename = self.domain.filename+filename_ext
+
+            #change the domain starttime to the current time
+            old_domain_starttime = self.domain.starttime
+            self.domain.starttime = self.domain.time
+
+            #build a new data_structure.
+            next_data_structure=\
+                Data_format_sww(self.domain, mode=self.mode,\
+                                max_size = self.max_size,\
+                                recursion = self.recursion+1)
+            if not self.recursion:
+                print '    file_size = %s'%file_size
+                print '    saving file to %s'%next_data_structure.filename
+            #set up the new data_structure
+            self.domain.writer = next_data_structure
+
+            #FIXME - could be cleaner to use domain.store_timestep etc.
+            next_data_structure.store_connectivity()
+            next_data_structure.store_timestep(names)
+            fid.sync()
+            fid.close()
+
+            #restore the old starttime and filename
+            self.domain.starttime = old_domain_starttime
+            self.domain.filename = old_domain_filename
+        else:
+            self.recursion = False
+            domain = self.domain
+
+            # Get the variables
+            time = fid.variables['time']
+            stage = fid.variables['stage']
+            xmomentum = fid.variables['xmomentum']
+            ymomentum = fid.variables['ymomentum']
+            i = len(time)
+
+            #Store time
+            time[i] = self.domain.time
+
+
+            if type(names) not in [types.ListType, types.TupleType]:
+                names = [names]
+
+            for name in names:
+                # Get quantity
+                Q = domain.quantities[name]
+                A,V = Q.get_vertex_values(xy = False,
+                                          precision = self.precision)
+
+                #FIXME: Make this general (see below)
+                if name == 'stage':
+                    z = fid.variables['elevation']
+                    #print z[:]
+                    #print A-z[:]
+                    A = choose( A-z[:] >= self.minimum_sww_depth,
+                                (z[:], A))
+                    stage[i,:] = A.astype(self.precision)
+                elif name == 'xmomentum':
+                    xmomentum[i,:] = A.astype(self.precision)
+                elif name == 'ymomentum':
+                    ymomentum[i,:] = A.astype(self.precision)
+
+                #As in....
+            #eval( name + '[i,:] = A.astype(self.precision)' )
+            #FIXME: But we need a UNIT test for that before refactoring
+
+
+
+            #Flush and close
+            fid.sync()
+            fid.close()
+
+
+
+#Class for handling checkpoints data
+class Data_format_cpt(Data_format):
+    """Interface to native NetCDF format (.cpt)
+    """
+
+
+    def __init__(self, domain, mode = 'w'):
+        from Scientific.IO.NetCDF import NetCDFFile
+        from Numeric import Int, Float, Float
+
+        self.precision = Float #Use full precision
+
+        Data_format.__init__(self, domain, 'sww', mode)
+
+
+        # NetCDF file definition
+        fid = NetCDFFile(self.filename, mode)
+
+        if mode == 'w':
+            #Create new file
+            fid.institution = 'Geoscience Australia'
+            fid.description = 'Checkpoint data'
+            #fid.smooth = domain.smooth
+            fid.order = domain.default_order
+
+            # dimension definitions
+            fid.createDimension('number_of_volumes', self.number_of_volumes)
+            fid.createDimension('number_of_vertices', 3)
+
+            #Store info at all vertices (no smoothing)
+            fid.createDimension('number_of_points', 3*self.number_of_volumes)
+            fid.createDimension('number_of_timesteps', None) #extensible
+
+            # variable definitions
+
+            #Mesh
+            fid.createVariable('x', self.precision, ('number_of_points',))
+            fid.createVariable('y', self.precision, ('number_of_points',))
+
+
+            fid.createVariable('volumes', Int, ('number_of_volumes',
+                                                'number_of_vertices'))
+
+            fid.createVariable('time', self.precision,
+                               ('number_of_timesteps',))
+
+            #Allocate space for all quantities
+            for name in domain.quantities.keys():
+                fid.createVariable(name, self.precision,
+                                   ('number_of_timesteps',
+                                    'number_of_points'))
+
+        #Close
+        fid.close()
+
+
+    def store_checkpoint(self):
+        """
+        Write x,y coordinates of triangles.
+        Write connectivity (
+        constituting
+        the bed elevation.
+        """
+
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        from Numeric import concatenate
+
+        domain = self.domain
+
+        #Get NetCDF
+        fid = NetCDFFile(self.filename, 'a')  #Open existing file for append
+
+        # Get the variables
+        x = fid.variables['x']
+        y = fid.variables['y']
+
+        volumes = fid.variables['volumes']
+
+        # Get X, Y and bed elevation Z
+        Q = domain.quantities['elevation']
+        X,Y,Z,V = Q.get_vertex_values(xy=True,
+                      precision = self.precision)
+
+
+
+        x[:] = X.astype(self.precision)
+        y[:] = Y.astype(self.precision)
+        z[:] = Z.astype(self.precision)
+
+        volumes[:] = V
+
+        #Close
+        fid.close()
+
+
+    def store_timestep(self, name):
+        """Store time and named quantity to file
+        """
+        from Scientific.IO.NetCDF import NetCDFFile
+        from time import sleep
+
+        #Get NetCDF
+        retries = 0
+        file_open = False
+        while not file_open and retries < 10:
+            try:
+                fid = NetCDFFile(self.filename, 'a') #Open existing file
+            except IOError:
+                #This could happen if someone was reading the file.
+                #In that case, wait a while and try again
+                msg = 'Warning (store_timestep): File %s could not be opened'\
+                  %self.filename
+                msg += ' - trying again'
+                print msg
+                retries += 1
+                sleep(1)
+            else:
+                file_open = True
+
+        if not file_open:
+            msg = 'File %s could not be opened for append' %self.filename
+            raise DataFileNotOPenError, msg
+
+
+        domain = self.domain
+
+        # Get the variables
+        time = fid.variables['time']
+        stage = fid.variables['stage']
+        i = len(time)
+
+        #Store stage
+        time[i] = self.domain.time
+
+        # Get quantity
+        Q = domain.quantities[name]
+        A,V = Q.get_vertex_values(xy=False,
+                  precision = self.precision)
+
+        stage[i,:] = A.astype(self.precision)
+
+        #Flush and close
+        fid.sync()
+        fid.close()
+
+
+
+
+
+#Function for storing xya output
+#FIXME Not done yet for this version
+#This is obsolete.  Use geo_spatial_data instead
+class Data_format_xya(Data_format):
+    """Generic interface to data formats
+    """
+
+
+    def __init__(self, domain, mode = 'w'):
+        from Scientific.IO.NetCDF import NetCDFFile
+        from Numeric import Int, Float, Float32
+
+        self.precision = Float32 #Use single precision
+
+        Data_format.__init__(self, domain, 'xya', mode)
+
+
+
+    #FIXME -This is the old xya format
+    def store_all(self):
+        """Specialisation of store all for xya format
+
+        Writes x,y,z coordinates of triangles constituting
+        the bed elevation.
+        """
+
+        from Numeric import concatenate
+
+        domain = self.domain
+
+        fd = open(self.filename, 'w')
+
+
+        if domain.smooth is True:
+            number_of_points =  len(domain.vertexlist)
+        else:
+            number_of_points = 3*self.number_of_volumes
+
+        numVertAttrib = 3 #Three attributes is what is assumed by the xya format
+
+        fd.write(str(number_of_points) + " " + str(numVertAttrib) +\
+                 " # <vertex #> <x> <y> [attributes]" + "\n")
+
+
+        # Get X, Y, bed elevation and friction (index=0,1)
+        X,Y,A,V = domain.get_vertex_values(xy=True, value_array='field_values',
+                                           indices = (0,1), precision = self.precision)
+
+        bed_eles = A[:,0]
+        fricts = A[:,1]
+
+        # Get stage (index=0)
+        B,V = domain.get_vertex_values(xy=False, value_array='conserved_quantities',
+                                       indices = (0,), precision = self.precision)
+
+        stages = B[:,0]
+
+        #<vertex #> <x> <y> [attributes]
+        for x, y, bed_ele, stage, frict in map(None, X, Y, bed_eles,
+                                               stages, fricts):
+
+            s = '%.6f %.6f %.6f %.6f %.6f\n' %(x, y, bed_ele, stage, frict)
+            fd.write(s)
+
+        #close
+        fd.close()
+
+
+    def store_timestep(self, t, V0, V1, V2):
+        """Store time, water heights (and momentums) to file
+        """
+        pass
+
+
+#### NBED national exposure database
+    
+LAT_TITLE = 'LATITUDE'
+LONG_TITLE = 'LONGITUDE'
+X_TITLE = 'x'
+Y_TITLE = 'y'
+class Exposure_csv:
+    def __init__(self,file_name, latitude_title=LAT_TITLE,
+                 longitude_title=LONG_TITLE, is_x_y_locations=None,
+                 x_title=X_TITLE, y_title=Y_TITLE,
+                 refine_polygon=None):
+        """
+        This class is for handling the exposure csv file.
+        It reads the file in and converts the lats and longs to a geospatial
+        data object.
+        Use the methods to read and write columns.
+
+        The format of the csv files it reads is;
+           The first row is a title row.
+           comma's are the delimiters
+           each column is a 'set' of data
+
+        Feel free to use/expand it to read other csv files. 
+           
+           
+        It is not for adding and deleting rows
+        
+        Can geospatial handle string attributes? It's not made for them.
+        Currently it can't load and save string att's.
+
+        So just use geospatial to hold the x, y and georef? Bad, since
+        different att's are in diferent structures.  Not so bad, the info
+        to write if the .csv file is saved is in attribute_dic
+
+        The location info is in the geospatial attribute.
+        
+        
+        """
+        self._file_name = file_name
+        self._geospatial = None #
+
+        # self._attribute_dic is a dictionary.
+        #The keys are the column titles.
+        #The values are lists of column data
+        
+        # self._title_index_dic is a dictionary.
+        #The keys are the column titles.
+        #The values are the index positions of file columns.
+        self._attribute_dic, self._title_index_dic = \
+        self._load_exposure_csv(self._file_name)
+        try:
+            lats = self._attribute_dic[latitude_title]
+            longs = self._attribute_dic[longitude_title]
+            
+        except KeyError:
+            # maybe a warning..
+            #Let's see if this works..
+            if False != is_x_y_locations:
+                is_x_y_locations = True
+            pass
+        else:
+            self._geospatial = Geospatial_data(latitudes = lats,
+                 longitudes = longs)
+
+        if is_x_y_locations is True:
+            if self._geospatial is not None:
+                pass #fixme throw an error
+            try:
+                xs = self._attribute_dic[x_title]
+                ys = self._attribute_dic[y_title]
+                points = [[float(i),float(j)] for i,j in map(None,xs,ys)]
+            except KeyError:
+                # maybe a warning..
+                raise TitleValueError, msg
+            else:
+                self._geospatial = Geospatial_data(data_points=points)
+            
+        # create a list of points that are in the refining_polygon
+        # described by a list of indexes representing the points
+
+    def __cmp__(self, other):
+        #print "self._attribute_dic",self._attribute_dic
+        #print "other._attribute_dic",other._attribute_dic
+        #print "self._title_index_dic", self._title_index_dic
+        #print "other._title_index_dic", other._title_index_dic
+        
+        #check that a is an instance of this class
+        if isinstance(self, type(other)):
+            result = cmp(self._attribute_dic, other._attribute_dic)
+            if result <>0:
+                return result
+            # The order of the columns is important. Therefore.. 
+            result = cmp(self._title_index_dic, other._title_index_dic)
+            if result <>0:
+                return result
+            for self_ls, other_ls in map(None,self._attribute_dic, \
+                    other._attribute_dic):
+                result = cmp(self._attribute_dic[self_ls],
+                             other._attribute_dic[other_ls])
+                if result <>0:
+                    return result
+            return 0
+        else:
+            return 1
+    
+    def _load_exposure_csv(self, file_name):
+        """
+        Load in the csv as a dic, title as key and column info as value, .
+        Also, create a dic, title as key and column index as value. 
+        """
+        #
+        attribute_dic = {}
+        title_index_dic = {}
+        titles_stripped = [] # list of titles
+        
+        reader = csv.reader(file(file_name))
+
+        # Read in and manipulate the title info
+        titles = reader.next()
+        for i,title in enumerate(titles):
+            titles_stripped.append(title.strip())
+            title_index_dic[title.strip()] = i
+        title_count = len(titles_stripped)       
+        #print "title_index_dic",title_index_dic
+
+        
+        #create a dic of colum values, indexed by column title
+        for line in reader:
+            if len(line) <> title_count:
+                raise IOError #FIXME make this nicer
+            for i, value in enumerate(line):
+                attribute_dic.setdefault(titles_stripped[i],[]).append(value)
+            
+        return attribute_dic, title_index_dic
+
+    def get_column(self, column_name, use_refind_polygon=False):
+        """
+        Given a column name return a list of the column values
+
+        Note, the type of the values will be String!
+        do this to change a list of strings to a list of floats
+        time = [float(x) for x in time]
+        
+        Not implemented:
+        if use_refind_polygon is True, only return values in the
+        refined polygon
+        """
+        if not self._attribute_dic.has_key(column_name):
+            msg = 'Therer is  no column called %s!' %column_name
+            raise TitleValueError, msg
+        return self._attribute_dic[column_name]
+
+
+    def get_value(self, value_column_name,
+                  known_column_name,
+                  known_values,
+                  use_refind_polygon=False):
+        """
+        Do linear interpolation on the known_colum, using the known_value,
+        to return a value of the column_value_name.
+        """
+        pass
+
+
+    def get_location(self, use_refind_polygon=False):
+        """
+        Return a geospatial object which describes the
+        locations of the location file.
+
+        Note, if there is not location info, this returns None.
+        
+        Not implemented:
+        if use_refind_polygon is True, only return values in the
+        refined polygon
+        """
+        return self._geospatial
+
+    def set_column(self, column_name, column_values, overwrite=False):
+        """
+        Add a column to the 'end' (with the right most column being the end)
+        of the csv file.
+
+        Set overwrite to True if you want to overwrite a column.
+        
+        Note, in column_name white space is removed and case is not checked.
+        Precondition
+        The column_name and column_values cannot have comma's in it.
+        """
+        
+        value_row_count = \
+            len(self._attribute_dic[self._title_index_dic.keys()[0]])
+        if len(column_values) <> value_row_count: 
+            msg = 'The number of column values must equal the number of rows.'
+            raise DataMissingValuesError, msg
+        
+        if self._attribute_dic.has_key(column_name):
+            if not overwrite:
+                msg = 'Column name %s already in use!' %column_name
+                raise TitleValueError, msg
+        else:
+            # New title.  Add it to the title index.
+            self._title_index_dic[column_name] = len(self._title_index_dic)
+        self._attribute_dic[column_name] = column_values
+        #print "self._title_index_dic[column_name]",self._title_index_dic 
+
+    def save(self, file_name=None):
+        """
+        Save the exposure csv file
+        """
+        if file_name is None:
+            file_name = self._file_name
+        
+        fd = open(file_name,'wb')
+        writer = csv.writer(fd)
+        
+        #Write the title to a cvs file
+        line = [None]* len(self._title_index_dic)
+        for title in self._title_index_dic.iterkeys():
+            line[self._title_index_dic[title]]= title
+        writer.writerow(line)
+        
+        # Write the values to a cvs file
+        value_row_count = \
+            len(self._attribute_dic[self._title_index_dic.keys()[0]])
+        for row_i in range(value_row_count):
+            line = [None]* len(self._title_index_dic)
+            for title in self._title_index_dic.iterkeys():
+                line[self._title_index_dic[title]]= \
+                     self._attribute_dic[title][row_i]
+            writer.writerow(line)
+
+
+#Auxiliary
+def write_obj(filename,x,y,z):
+    """Store x,y,z vectors into filename (obj format)
+       Vectors are assumed to have dimension (M,3) where
+       M corresponds to the number elements.
+       triangles are assumed to be disconnected
+
+       The three numbers in each vector correspond to three vertices,
+
+       e.g. the x coordinate of vertex 1 of element i is in x[i,1]
+
+    """
+    #print 'Writing obj to %s' % filename
+
+    import os.path
+
+    root, ext = os.path.splitext(filename)
+    if ext == '.obj':
+        FN = filename
+    else:
+        FN = filename + '.obj'
+
+
+    outfile = open(FN, 'wb')
+    outfile.write("# Triangulation as an obj file\n")
+
+    M, N = x.shape
+    assert N==3  #Assuming three vertices per element
+
+    for i in range(M):
+        for j in range(N):
+            outfile.write("v %f %f %f\n" % (x[i,j],y[i,j],z[i,j]))
+
+    for i in range(M):
+        base = i*N
+        outfile.write("f %d %d %d\n" % (base+1,base+2,base+3))
+
+    outfile.close()
+
+
+#########################################################
+#Conversion routines
+########################################################
+
+def sww2obj(basefilename, size):
+    """Convert netcdf based data output to obj
+    """
+    from Scientific.IO.NetCDF import NetCDFFile
+
+    from Numeric import Float, zeros
+
+    #Get NetCDF
+    FN = create_filename('.', basefilename, 'sww', size)
+    print 'Reading from ', FN
+    fid = NetCDFFile(FN, 'r')  #Open existing file for read
+
+
+    # Get the variables
+    x = fid.variables['x']
+    y = fid.variables['y']
+    z = fid.variables['elevation']
+    time = fid.variables['time']
+    stage = fid.variables['stage']
+
+    M = size  #Number of lines
+    xx = zeros((M,3), Float)
+    yy = zeros((M,3), Float)
+    zz = zeros((M,3), Float)
+
+    for i in range(M):
+        for j in range(3):
+            xx[i,j] = x[i+j*M]
+            yy[i,j] = y[i+j*M]
+            zz[i,j] = z[i+j*M]
+
+    #Write obj for bathymetry
+    FN = create_filename('.', basefilename, 'obj', size)
+    write_obj(FN,xx,yy,zz)
+
+
+    #Now read all the data with variable information, combine with
+    #x,y info and store as obj
+
+    for k in range(len(time)):
+        t = time[k]
+        print 'Processing timestep %f' %t
+
+        for i in range(M):
+            for j in range(3):
+                zz[i,j] = stage[k,i+j*M]
+
+
+        #Write obj for variable data
+        #FN = create_filename(basefilename, 'obj', size, time=t)
+        FN = create_filename('.', basefilename[:5], 'obj', size, time=t)
+        write_obj(FN,xx,yy,zz)
+
+
+def dat2obj(basefilename):
+    """Convert line based data output to obj
+    FIXME: Obsolete?
+    """
+
+    import glob, os
+    from anuga.config import data_dir
+
+
+    #Get bathymetry and x,y's
+    lines = open(data_dir+os.sep+basefilename+'_geometry.dat', 'r').readlines()
+
+    from Numeric import zeros, Float
+
+    M = len(lines)  #Number of lines
+    x = zeros((M,3), Float)
+    y = zeros((M,3), Float)
+    z = zeros((M,3), Float)
+
+    ##i = 0
+    for i, line in enumerate(lines):
+        tokens = line.split()
+        values = map(float,tokens)
+
+        for j in range(3):
+            x[i,j] = values[j*3]
+            y[i,j] = values[j*3+1]
+            z[i,j] = values[j*3+2]
+
+        ##i += 1
+
+
+    #Write obj for bathymetry
+    write_obj(data_dir+os.sep+basefilename+'_geometry',x,y,z)
+
+
+    #Now read all the data files with variable information, combine with
+    #x,y info
+    #and store as obj
+
+    files = glob.glob(data_dir+os.sep+basefilename+'*.dat')
+
+    for filename in files:
+        print 'Processing %s' % filename
+
+        lines = open(data_dir+os.sep+filename,'r').readlines()
+        assert len(lines) == M
+        root, ext = os.path.splitext(filename)
+
+        #Get time from filename
+        i0 = filename.find('_time=')
+        if i0 == -1:
+            #Skip bathymetry file
+            continue
+
+        i0 += 6  #Position where time starts
+        i1 = filename.find('.dat')
+
+        if i1 > i0:
+            t = float(filename[i0:i1])
+        else:
+            raise DataTimeError, 'Hmmmm'
+
+
+
+        ##i = 0
+        for i, line in enumerate(lines):
+            tokens = line.split()
+            values = map(float,tokens)
+
+            for j in range(3):
+                z[i,j] = values[j]
+
+            ##i += 1
+
+        #Write obj for variable data
+        write_obj(data_dir+os.sep+basefilename+'_time=%.4f' %t,x,y,z)
+
+
+def filter_netcdf(filename1, filename2, first=0, last=None, step = 1):
+    """Read netcdf filename1, pick timesteps first:step:last and save to
+    nettcdf file filename2
+    """
+    from Scientific.IO.NetCDF import NetCDFFile
+
+    #Get NetCDF
+    infile = NetCDFFile(filename1, 'r')  #Open existing file for read
+    outfile = NetCDFFile(filename2, 'w')  #Open new file
+
+
+    #Copy dimensions
+    for d in infile.dimensions:
+        outfile.createDimension(d, infile.dimensions[d])
+
+    for name in infile.variables:
+        var = infile.variables[name]
+        outfile.createVariable(name, var.typecode(), var.dimensions)
+
+
+    #Copy the static variables
+    for name in infile.variables:
+        if name == 'time' or name == 'stage':
+            pass
+        else:
+            #Copy
+            outfile.variables[name][:] = infile.variables[name][:]
+
+    #Copy selected timesteps
+    time = infile.variables['time']
+    stage = infile.variables['stage']
+
+    newtime = outfile.variables['time']
+    newstage = outfile.variables['stage']
+
+    if last is None:
+        last = len(time)
+
+    selection = range(first, last, step)
+    for i, j in enumerate(selection):
+        print 'Copying timestep %d of %d (%f)' %(j, last-first, time[j])
+        newtime[i] = time[j]
+        newstage[i,:] = stage[j,:]
+
+    #Close
+    infile.close()
+    outfile.close()
+
+
+#Get data objects
+def get_dataobject(domain, mode='w'):
+    """Return instance of class of given format using filename
+    """
+
+    cls = eval('Data_format_%s' %domain.format)
+    return cls(domain, mode)
+
+#FIXME move into geospatial.  There should only be one method that
+# reads xya, and writes pts.
+def xya2pts(basename_in, basename_out=None, verbose=False,
+            #easting_min=None, easting_max=None,
+            #northing_min=None, northing_max=None,
+            stride = 1,
+            attribute_name = 'elevation',
+            z_func = None):
+    """Read points data from ascii (.xya)
+
+    Example:
+
+              x(m)        y(m)        z(m)
+         0.00000e+00  0.00000e+00  1.3535000e-01
+         0.00000e+00  1.40000e-02  1.3535000e-01
+
+
+
+    Convert to NetCDF pts format which is
+
+    points:  (Nx2) Float array
+    elevation: N Float array
+
+    Only lines that contain three numeric values are processed
+
+    If z_func is specified, it will be applied to the third field
+    """
+
+    import os
+    #from Scientific.IO.NetCDF import NetCDFFile
+    from Numeric import Float, arrayrange, concatenate
+
+    root, ext = os.path.splitext(basename_in)
+
+    if ext == '': ext = '.xya'
+
+    #Get NetCDF
+    infile = open(root + ext, 'r')  #Open existing xya file for read
+
+    if verbose: print 'Reading xya points from %s' %(root + ext)
+
+    points = []
+    attribute = []
+    for i, line in enumerate(infile.readlines()):
+
+        if i % stride != 0: continue
+
+        fields = line.split()
+
+        try:
+            assert len(fields) == 3
+        except:
+            print 'WARNING: Line %d doesn\'t have 3 elements: %s' %(i, line)
+
+        try:
+            x = float( fields[0] )
+            y = float( fields[1] )
+            z = float( fields[2] )
+        except:
+            continue
+
+        points.append( [x, y] )
+
+        if callable(z_func):
+            attribute.append(z_func(z))
+        else:
+            attribute.append(z)
+
+
+    #Get output file
+    if basename_out == None:
+        ptsname = root + '.pts'
+    else:
+        ptsname = basename_out + '.pts'
+
+    if verbose: print 'Store to NetCDF file %s' %ptsname
+    write_ptsfile(ptsname, points, attribute, attribute_name)
+
+
+
+######Obsoleted by export_points in load_mesh
+def write_ptsfile(ptsname, points, attribute, attribute_name = None,
+                  zone=None, xllcorner=None, yllcorner=None):
+    """Write points and associated attribute to pts (NetCDF) format
+    """
+
+    print 'WARNING: write_ptsfile is obsolete. Use export_points from load_mesh.loadASCII instead.'
+
+    from Numeric import Float
+
+    if attribute_name is None:
+        attribute_name = 'attribute'
+
+
+    from Scientific.IO.NetCDF import NetCDFFile
+
+    # NetCDF file definition
+    outfile = NetCDFFile(ptsname, 'w')
+
+
+    #Create new file
+    outfile.institution = 'Geoscience Australia'
+    outfile.description = 'NetCDF pts format for compact and '\
+                          'portable storage of spatial point data'
+
+
+    #Georeferencing
+    from anuga.coordinate_transforms.geo_reference import Geo_reference
+    if zone is None:
+        assert xllcorner is None, 'xllcorner must be None'
+        assert yllcorner is None, 'yllcorner must be None'
+        Geo_reference().write_NetCDF(outfile)
+    else:
+        Geo_reference(zone, xllcorner, yllcorner).write_NetCDF(outfile)
+
+
+
+    outfile.createDimension('number_of_points', len(points))
+    outfile.createDimension('number_of_dimensions', 2) #This is 2d data
+
+    # variable definitions
+    outfile.createVariable('points', Float, ('number_of_points',
+                                             'number_of_dimensions'))
+    outfile.createVariable(attribute_name, Float, ('number_of_points',))
+
+    # Get handles to the variables
+    nc_points = outfile.variables['points']
+    nc_attribute = outfile.variables[attribute_name]
+
+    #Store data
+    nc_points[:, :] = points
+    nc_attribute[:] = attribute
+
+    outfile.close()
+
+
+def dem2pts(basename_in, basename_out=None,
+            easting_min=None, easting_max=None,
+            northing_min=None, northing_max=None,
+            use_cache=False, verbose=False,):
+    """Read Digitial Elevation model from the following NetCDF format (.dem)
+
+    Example:
+
+    ncols         3121
+    nrows         1800
+    xllcorner     722000
+    yllcorner     5893000
+    cellsize      25
+    NODATA_value  -9999
+    138.3698 137.4194 136.5062 135.5558 ..........
+
+    Convert to NetCDF pts format which is
+
+    points:  (Nx2) Float array
+    elevation: N Float array
+    """
+
+
+
+    kwargs = {'basename_out': basename_out,
+              'easting_min': easting_min,
+              'easting_max': easting_max,
+              'northing_min': northing_min,
+              'northing_max': northing_max,
+              'verbose': verbose}
+
+    if use_cache is True:
+        from caching import cache
+        result = cache(_dem2pts, basename_in, kwargs,
+                       dependencies = [basename_in + '.dem'],
+                       verbose = verbose)
+
+    else:
+        result = apply(_dem2pts, [basename_in], kwargs)
+
+    return result
+
+
+def _dem2pts(basename_in, basename_out=None, verbose=False,
+            easting_min=None, easting_max=None,
+            northing_min=None, northing_max=None):
+    """Read Digitial Elevation model from the following NetCDF format (.dem)
+
+    Internal function. See public function dem2pts for details.
+    """
+
+    #FIXME: Can this be written feasibly using write_pts?
+
+    import os
+    from Scientific.IO.NetCDF import NetCDFFile
+    from Numeric import Float, zeros, reshape, sum
+
+    root = basename_in
+
+    #Get NetCDF
+    infile = NetCDFFile(root + '.dem', 'r')  #Open existing netcdf file for read
+
+    if verbose: print 'Reading DEM from %s' %(root + '.dem')
+
+    ncols = infile.ncols[0]
+    nrows = infile.nrows[0]
+    xllcorner = infile.xllcorner[0]  #Easting of lower left corner
+    yllcorner = infile.yllcorner[0]  #Northing of lower left corner
+    cellsize = infile.cellsize[0]
+    NODATA_value = infile.NODATA_value[0]
+    dem_elevation = infile.variables['elevation']
+
+    zone = infile.zone[0]
+    false_easting = infile.false_easting[0]
+    false_northing = infile.false_northing[0]
+
+    #Text strings
+    projection = infile.projection
+    datum = infile.datum
+    units = infile.units
+
+
+    #Get output file
+    if basename_out == None:
+        ptsname = root + '.pts'
+    else:
+        ptsname = basename_out + '.pts'
+
+    if verbose: print 'Store to NetCDF file %s' %ptsname
+    # NetCDF file definition
+    outfile = NetCDFFile(ptsname, 'w')
+
+    #Create new file
+    outfile.institution = 'Geoscience Australia'
+    outfile.description = 'NetCDF pts format for compact and portable storage ' +\
+                      'of spatial point data'
+    #assign default values
+    if easting_min is None: easting_min = xllcorner
+    if easting_max is None: easting_max = xllcorner + ncols*cellsize
+    if northing_min is None: northing_min = yllcorner
+    if northing_max is None: northing_max = yllcorner + nrows*cellsize
+
+    #compute offsets to update georeferencing
+    easting_offset = xllcorner - easting_min
+    northing_offset = yllcorner - northing_min
+
+    #Georeferencing
+    outfile.zone = zone
+    outfile.xllcorner = easting_min #Easting of lower left corner
+    outfile.yllcorner = northing_min #Northing of lower left corner
+    outfile.false_easting = false_easting
+    outfile.false_northing = false_northing
+
+    outfile.projection = projection
+    outfile.datum = datum
+    outfile.units = units
+
+
+    #Grid info (FIXME: probably not going to be used, but heck)
+    outfile.ncols = ncols
+    outfile.nrows = nrows
+
+    dem_elevation_r = reshape(dem_elevation, (nrows, ncols))
+    totalnopoints = nrows*ncols
+
+    # calculating number of NODATA_values for each row in clipped region
+    #FIXME: use array operations to do faster
+    nn = 0
+    k = 0
+    i1_0 = 0
+    j1_0 = 0
+    thisj = 0
+    thisi = 0
+    for i in range(nrows):
+        y = (nrows-i-1)*cellsize + yllcorner
+        for j in range(ncols):
+            x = j*cellsize + xllcorner
+            if easting_min <= x <= easting_max and \
+               northing_min <= y <= northing_max:
+                thisj = j
+                thisi = i
+                if dem_elevation_r[i,j] == NODATA_value: nn += 1
+
+                if k == 0:
+                    i1_0 = i
+                    j1_0 = j
+                k += 1
+
+    index1 = j1_0
+    index2 = thisj
+
+    # dimension definitions
+    nrows_in_bounding_box = int(round((northing_max-northing_min)/cellsize))
+    ncols_in_bounding_box = int(round((easting_max-easting_min)/cellsize))
+
+    clippednopoints = (thisi+1-i1_0)*(thisj+1-j1_0)
+    nopoints = clippednopoints-nn
+
+    clipped_dem_elev = dem_elevation_r[i1_0:thisi+1,j1_0:thisj+1]
+
+    if verbose and nn > 0:
+        print 'There are %d values in the elevation' %totalnopoints
+        print 'There are %d values in the clipped elevation' %clippednopoints
+        print 'There are %d NODATA_values in the clipped elevation' %nn
+
+    outfile.createDimension('number_of_points', nopoints)
+    outfile.createDimension('number_of_dimensions', 2) #This is 2d data
+
+    # variable definitions
+    outfile.createVariable('points', Float, ('number_of_points',
+                                             'number_of_dimensions'))
+    outfile.createVariable('elevation', Float, ('number_of_points',))
+
+    # Get handles to the variables
+    points = outfile.variables['points']
+    elevation = outfile.variables['elevation']
+
+    lenv = index2-index1+1
+    #Store data
+    global_index = 0
+    #for i in range(nrows):
+    for i in range(i1_0,thisi+1,1):
+        if verbose and i%((nrows+10)/10)==0:
+            print 'Processing row %d of %d' %(i, nrows)
+
+        lower_index = global_index
+
+        v = dem_elevation_r[i,index1:index2+1]
+        no_NODATA = sum(v == NODATA_value)
+        if no_NODATA > 0:
+            newcols = lenv - no_NODATA #ncols_in_bounding_box - no_NODATA
+        else:
+            newcols = lenv #ncols_in_bounding_box
+
+        telev = zeros(newcols, Float)
+        tpoints = zeros((newcols, 2), Float)
+
+        local_index = 0
+
+        y = (nrows-i-1)*cellsize + yllcorner
+        #for j in range(ncols):
+        for j in range(j1_0,index2+1,1):
+
+            x = j*cellsize + xllcorner
+            if easting_min <= x <= easting_max and \
+               northing_min <= y <= northing_max and \
+               dem_elevation_r[i,j] <> NODATA_value:
+                tpoints[local_index, :] = [x-easting_min,y-northing_min]
+                telev[local_index] = dem_elevation_r[i, j]
+                global_index += 1
+                local_index += 1
+
+        upper_index = global_index
+
+        if upper_index == lower_index + newcols:
+            points[lower_index:upper_index, :] = tpoints
+            elevation[lower_index:upper_index] = telev
+
+    assert global_index == nopoints, 'index not equal to number of points'
+
+    infile.close()
+    outfile.close()
+
+
+
+def _read_hecras_cross_sections(lines):
+    """Return block of surface lines for each cross section
+    Starts with SURFACE LINE,
+    Ends with END CROSS-SECTION
+    """
+
+    points = []
+
+    reading_surface = False
+    for i, line in enumerate(lines):
+
+        if len(line.strip()) == 0:    #Ignore blanks
+            continue
+
+        if lines[i].strip().startswith('SURFACE LINE'):
+            reading_surface = True
+            continue
+
+        if lines[i].strip().startswith('END') and reading_surface:
+            yield points
+            reading_surface = False
+            points = []
+
+        if reading_surface:
+            fields = line.strip().split(',')
+            easting = float(fields[0])
+            northing = float(fields[1])
+            elevation = float(fields[2])
+            points.append([easting, northing, elevation])
+
+
+
+
+def hecras_cross_sections2pts(basename_in,
+                              basename_out=None,
+                              verbose=False):
+    """Read HEC-RAS Elevation datal from the following ASCII format (.sdf)
+
+    Example:
+
+
+# RAS export file created on Mon 15Aug2005 11:42
+# by HEC-RAS Version 3.1.1
+
+BEGIN HEADER:
+  UNITS: METRIC
+  DTM TYPE: TIN
+  DTM: v:\1\cit\perth_topo\river_tin
+  STREAM LAYER: c:\local\hecras\21_02_03\up_canning_cent3d.shp
+  CROSS-SECTION LAYER: c:\local\hecras\21_02_03\up_can_xs3d.shp
+  MAP PROJECTION: UTM
+  PROJECTION ZONE: 50
+  DATUM: AGD66
+  VERTICAL DATUM:
+  NUMBER OF REACHES:  19
+  NUMBER OF CROSS-SECTIONS:  14206
+END HEADER:
+
+
+Only the SURFACE LINE data of the following form will be utilised
+
+  CROSS-SECTION:
+    STREAM ID:Southern-Wungong
+    REACH ID:Southern-Wungong
+    STATION:19040.*
+    CUT LINE:
+      405548.671603161 , 6438142.7594925
+      405734.536092045 , 6438326.10404912
+      405745.130459356 , 6438331.48627354
+      405813.89633823 , 6438368.6272789
+    SURFACE LINE:
+     405548.67,   6438142.76,   35.37
+     405552.24,   6438146.28,   35.41
+     405554.78,   6438148.78,   35.44
+     405555.80,   6438149.79,   35.44
+     405559.37,   6438153.31,   35.45
+     405560.88,   6438154.81,   35.44
+     405562.93,   6438156.83,   35.42
+     405566.50,   6438160.35,   35.38
+     405566.99,   6438160.83,   35.37
+     ...
+   END CROSS-SECTION
+
+    Convert to NetCDF pts format which is
+
+    points:  (Nx2) Float array
+    elevation: N Float array
+    """
+
+    #FIXME: Can this be written feasibly using write_pts?
+
+    import os
+    from Scientific.IO.NetCDF import NetCDFFile
+    from Numeric import Float, zeros, reshape
+
+    root = basename_in
+
+    #Get ASCII file
+    infile = open(root + '.sdf', 'r')  #Open SDF file for read
+
+    if verbose: print 'Reading DEM from %s' %(root + '.sdf')
+
+    lines = infile.readlines()
+    infile.close()
+
+    if verbose: print 'Converting to pts format'
+
+    i = 0
+    while lines[i].strip() == '' or lines[i].strip().startswith('#'):
+        i += 1
+
+    assert lines[i].strip().upper() == 'BEGIN HEADER:'
+    i += 1
+
+    assert lines[i].strip().upper().startswith('UNITS:')
+    units = lines[i].strip().split()[1]
+    i += 1
+
+    assert lines[i].strip().upper().startswith('DTM TYPE:')
+    i += 1
+
+    assert lines[i].strip().upper().startswith('DTM:')
+    i += 1
+
+    assert lines[i].strip().upper().startswith('STREAM')
+    i += 1
+
+    assert lines[i].strip().upper().startswith('CROSS')
+    i += 1
+
+    assert lines[i].strip().upper().startswith('MAP PROJECTION:')
+    projection = lines[i].strip().split(':')[1]
+    i += 1
+
+    assert lines[i].strip().upper().startswith('PROJECTION ZONE:')
+    zone = int(lines[i].strip().split(':')[1])
+    i += 1
+
+    assert lines[i].strip().upper().startswith('DATUM:')
+    datum = lines[i].strip().split(':')[1]
+    i += 1
+
+    assert lines[i].strip().upper().startswith('VERTICAL DATUM:')
+    i += 1
+
+    assert lines[i].strip().upper().startswith('NUMBER OF REACHES:')
+    i += 1
+
+    assert lines[i].strip().upper().startswith('NUMBER OF CROSS-SECTIONS:')
+    number_of_cross_sections = int(lines[i].strip().split(':')[1])
+    i += 1
+
+
+    #Now read all points
+    points = []
+    elevation = []
+    for j, entries in enumerate(_read_hecras_cross_sections(lines[i:])):
+        for k, entry in enumerate(entries):
+            points.append(entry[:2])
+            elevation.append(entry[2])
+
+
+    msg = 'Actual #number_of_cross_sections == %d, Reported as %d'\
+          %(j+1, number_of_cross_sections)
+    assert j+1 == number_of_cross_sections, msg
+
+    #Get output file
+    if basename_out == None:
+        ptsname = root + '.pts'
+    else:
+        ptsname = basename_out + '.pts'
+
+    #FIXME (DSG-ON): use loadASCII export_points_file
+    if verbose: print 'Store to NetCDF file %s' %ptsname
+    # NetCDF file definition
+    outfile = NetCDFFile(ptsname, 'w')
+
+    #Create new file
+    outfile.institution = 'Geoscience Australia'
+    outfile.description = 'NetCDF pts format for compact and portable ' +\
+                          'storage of spatial point data derived from HEC-RAS'
+
+    #Georeferencing
+    outfile.zone = zone
+    outfile.xllcorner = 0.0
+    outfile.yllcorner = 0.0
+    outfile.false_easting = 500000    #FIXME: Use defaults from e.g. config.py
+    outfile.false_northing = 1000000
+
+    outfile.projection = projection
+    outfile.datum = datum
+    outfile.units = units
+
+
+    outfile.createDimension('number_of_points', len(points))
+    outfile.createDimension('number_of_dimensions', 2) #This is 2d data
+
+    # variable definitions
+    outfile.createVariable('points', Float, ('number_of_points',
+                                             'number_of_dimensions'))
+    outfile.createVariable('elevation', Float, ('number_of_points',))
+
+    # Get handles to the variables
+    outfile.variables['points'][:] = points
+    outfile.variables['elevation'][:] = elevation
+
+    outfile.close()
+
+
+
+def sww2dem(basename_in, basename_out = None,
+            quantity = None,
+            timestep = None,
+            reduction = None,
+            cellsize = 10,
+            NODATA_value = -9999,
+            easting_min = None,
+            easting_max = None,
+            northing_min = None,
+            northing_max = None,
+            verbose = False,
+            origin = None,
+            datum = 'WGS84',
+        format = 'ers'):
+
+    """Read SWW file and convert to Digitial Elevation model format (.asc or .ers)
+
+    Example (ASC):
+
+    ncols         3121
+    nrows         1800
+    xllcorner     722000
+    yllcorner     5893000
+    cellsize      25
+    NODATA_value  -9999
+    138.3698 137.4194 136.5062 135.5558 ..........
+
+    Also write accompanying file with same basename_in but extension .prj
+    used to fix the UTM zone, datum, false northings and eastings.
+
+    The prj format is assumed to be as
+
+    Projection    UTM
+    Zone          56
+    Datum         WGS84
+    Zunits        NO
+    Units         METERS
+    Spheroid      WGS84
+    Xshift        0.0000000000
+    Yshift        10000000.0000000000
+    Parameters
+
+
+    The parameter quantity must be the name of an existing quantity or
+    an expression involving existing quantities. The default is
+    'elevation'.
+
+    if timestep (an index) is given, output quantity at that timestep
+
+    if reduction is given use that to reduce quantity over all timesteps.
+
+    datum
+
+    format can be either 'asc' or 'ers'
+    """
+
+    import sys
+    from Numeric import array, Float, concatenate, NewAxis, zeros, reshape, sometrue
+    from Numeric import array2string
+
+    from anuga.utilities.polygon import inside_polygon, outside_polygon, separate_points_by_polygon
+    from anuga.abstract_2d_finite_volumes.util import apply_expression_to_dictionary
+
+    msg = 'Format must be either asc or ers'
+    assert format.lower() in ['asc', 'ers'], msg
+
+
+    false_easting = 500000
+    false_northing = 10000000
+
+    if quantity is None:
+        quantity = 'elevation'
+
+    if reduction is None:
+        reduction = max
+
+    if basename_out is None:
+        basename_out = basename_in + '_%s' %quantity
+
+    swwfile = basename_in + '.sww'
+    demfile = basename_out + '.' + format
+    # Note the use of a .ers extension is optional (write_ermapper_grid will
+    # deal with either option
+
+    #Read sww file
+    if verbose: print 'Reading from %s' %swwfile
+    from Scientific.IO.NetCDF import NetCDFFile
+    fid = NetCDFFile(swwfile)
+
+    #Get extent and reference
+    x = fid.variables['x'][:]
+    y = fid.variables['y'][:]
+    volumes = fid.variables['volumes'][:]
+
+    number_of_timesteps = fid.dimensions['number_of_timesteps']
+    number_of_points = fid.dimensions['number_of_points']
+    if origin is None:
+
+        #Get geo_reference
+        #sww files don't have to have a geo_ref
+        try:
+            geo_reference = Geo_reference(NetCDFObject=fid)
+        except AttributeError, e:
+            geo_reference = Geo_reference() #Default georef object
+
+        xllcorner = geo_reference.get_xllcorner()
+        yllcorner = geo_reference.get_yllcorner()
+        zone = geo_reference.get_zone()
+    else:
+        zone = origin[0]
+        xllcorner = origin[1]
+        yllcorner = origin[2]
+
+
+
+    #FIXME: Refactor using code from file_function.statistics
+    #Something like print swwstats(swwname)
+    if verbose:
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        times = fid.variables['time'][:]
+        print '------------------------------------------------'
+        print 'Statistics of SWW file:'
+        print '  Name: %s' %swwfile
+        print '  Reference:'
+        print '    Lower left corner: [%f, %f]'\
+              %(xllcorner, yllcorner)
+        print '    Start time: %f' %fid.starttime[0]
+        print '  Extent:'
+        print '    x [m] in [%f, %f], len(x) == %d'\
+              %(min(x.flat), max(x.flat), len(x.flat))
+        print '    y [m] in [%f, %f], len(y) == %d'\
+              %(min(y.flat), max(y.flat), len(y.flat))
+        print '    t [s] in [%f, %f], len(t) == %d'\
+              %(min(times), max(times), len(times))
+        print '  Quantities [SI units]:'
+        for name in ['stage', 'xmomentum', 'ymomentum', 'elevation']:
+            q = fid.variables[name][:].flat
+            print '    %s in [%f, %f]' %(name, min(q), max(q))
+
+
+
+
+
+    # Get quantity and reduce if applicable
+    if verbose: print 'Processing quantity %s' %quantity
+
+    # Turn NetCDF objects into Numeric arrays
+    quantity_dict = {}
+    for name in fid.variables.keys():
+        quantity_dict[name] = fid.variables[name][:]
+
+
+
+    # Convert quantity expression to quantities found in sww file    
+    q = apply_expression_to_dictionary(quantity, quantity_dict)
+
+
+
+    if len(q.shape) == 2:
+        #q has a time component and needs to be reduced along
+        #the temporal dimension
+        if verbose: print 'Reducing quantity %s' %quantity
+        q_reduced = zeros( number_of_points, Float )
+
+        for k in range(number_of_points):
+            q_reduced[k] = reduction( q[:,k] )
+
+        q = q_reduced
+
+    #Post condition: Now q has dimension: number_of_points
+    assert len(q.shape) == 1
+    assert q.shape[0] == number_of_points
+
+
+    if verbose:
+        print 'Processed values for %s are in [%f, %f]' %(quantity, min(q), max(q))
+
+
+    #Create grid and update xll/yll corner and x,y
+
+    #Relative extent
+    if easting_min is None:
+        xmin = min(x)
+    else:
+        xmin = easting_min - xllcorner
+
+    if easting_max is None:
+        xmax = max(x)
+    else:
+        xmax = easting_max - xllcorner
+
+    if northing_min is None:
+        ymin = min(y)
+    else:
+        ymin = northing_min - yllcorner
+
+    if northing_max is None:
+        ymax = max(y)
+    else:
+        ymax = northing_max - yllcorner
+
+
+
+    if verbose: print 'Creating grid'
+    ncols = int((xmax-xmin)/cellsize)+1
+    nrows = int((ymax-ymin)/cellsize)+1
+
+
+    #New absolute reference and coordinates
+    newxllcorner = xmin+xllcorner
+    newyllcorner = ymin+yllcorner
+
+    x = x+xllcorner-newxllcorner
+    y = y+yllcorner-newyllcorner
+
+    vertex_points = concatenate ((x[:, NewAxis] ,y[:, NewAxis]), axis = 1)
+    assert len(vertex_points.shape) == 2
+
+
+
+    grid_points = zeros ( (ncols*nrows, 2), Float )
+
+
+    for i in xrange(nrows):
+        if format.lower() == 'asc':
+            yg = i*cellsize
+        else:
+        #this will flip the order of the y values for ers
+            yg = (nrows-i)*cellsize
+
+        for j in xrange(ncols):
+            xg = j*cellsize
+            k = i*ncols + j
+
+            grid_points[k,0] = xg
+            grid_points[k,1] = yg
+
+    #Interpolate
+    #from least_squares import Interpolation
+    from anuga.fit_interpolate.interpolate import Interpolate
+
+
+    interp = Interpolate(vertex_points, volumes, verbose = verbose)
+
+
+
+    #Interpolate using quantity values
+    if verbose: print 'Interpolating'
+    grid_values = interp.interpolate(q, grid_points).flat
+
+
+    if verbose:
+        print 'Interpolated values are in [%f, %f]' %(min(grid_values),
+                                                      max(grid_values))
+
+    #Assign NODATA_value to all points outside bounding polygon (from interpolation mesh)
+    P = interp.mesh.get_boundary_polygon()
+    outside_indices = outside_polygon(grid_points, P, closed=True)
+
+    for i in outside_indices:
+        grid_values[i] = NODATA_value
+
+
+
+
+    if format.lower() == 'ers':
+        # setup ERS header information
+        grid_values = reshape(grid_values,(nrows, ncols))
+        header = {}
+        header['datum'] = '"' + datum + '"'
+        # FIXME The use of hardwired UTM and zone number needs to be made optional
+        # FIXME Also need an automatic test for coordinate type (i.e. EN or LL)
+        header['projection'] = '"UTM-' + str(zone) + '"'
+        header['coordinatetype'] = 'EN'
+        if header['coordinatetype'] == 'LL':
+            header['longitude'] = str(newxllcorner)
+            header['latitude'] = str(newyllcorner)
+        elif header['coordinatetype'] == 'EN':
+            header['eastings'] = str(newxllcorner)
+            header['northings'] = str(newyllcorner)
+        header['nullcellvalue'] = str(NODATA_value)
+        header['xdimension'] = str(cellsize)
+        header['ydimension'] = str(cellsize)
+        header['value'] = '"' + quantity + '"'
+        #header['celltype'] = 'IEEE8ByteReal'  #FIXME: Breaks unit test
+
+
+        #Write
+        if verbose: print 'Writing %s' %demfile
+        import ermapper_grids
+        ermapper_grids.write_ermapper_grid(demfile, grid_values, header)
+
+        fid.close()
+    else:
+        #Write to Ascii format
+
+        #Write prj file
+        prjfile = basename_out + '.prj'
+
+        if verbose: print 'Writing %s' %prjfile
+        prjid = open(prjfile, 'w')
+        prjid.write('Projection    %s\n' %'UTM')
+        prjid.write('Zone          %d\n' %zone)
+        prjid.write('Datum         %s\n' %datum)
+        prjid.write('Zunits        NO\n')
+        prjid.write('Units         METERS\n')
+        prjid.write('Spheroid      %s\n' %datum)
+        prjid.write('Xshift        %d\n' %false_easting)
+        prjid.write('Yshift        %d\n' %false_northing)
+        prjid.write('Parameters\n')
+        prjid.close()
+
+
+
+        if verbose: print 'Writing %s' %demfile
+
+        ascid = open(demfile, 'w')
+
+        ascid.write('ncols         %d\n' %ncols)
+        ascid.write('nrows         %d\n' %nrows)
+        ascid.write('xllcorner     %d\n' %newxllcorner)
+        ascid.write('yllcorner     %d\n' %newyllcorner)
+        ascid.write('cellsize      %f\n' %cellsize)
+        ascid.write('NODATA_value  %d\n' %NODATA_value)
+
+
+        #Get bounding polygon from mesh
+        #P = interp.mesh.get_boundary_polygon()
+        #inside_indices = inside_polygon(grid_points, P)
+
+        for i in range(nrows):
+            if verbose and i%((nrows+10)/10)==0:
+                print 'Doing row %d of %d' %(i, nrows)
+
+            base_index = (nrows-i-1)*ncols
+
+            slice = grid_values[base_index:base_index+ncols]
+            s = array2string(slice, max_line_width=sys.maxint)
+            ascid.write(s[1:-1] + '\n')
+
+
+            #print
+            #for j in range(ncols):
+            #    index = base_index+j#
+            #    print grid_values[index],
+            #    ascid.write('%f ' %grid_values[index])
+            #ascid.write('\n')
+
+        #Close
+        ascid.close()
+        fid.close()
+
+#Backwards compatibility
+def sww2asc(basename_in, basename_out = None,
+            quantity = None,
+            timestep = None,
+            reduction = None,
+            cellsize = 10,
+            verbose = False,
+            origin = None):
+    print 'sww2asc will soon be obsoleted - please use sww2dem'
+    sww2dem(basename_in,
+            basename_out = basename_out,
+            quantity = quantity,
+            timestep = timestep,
+            reduction = reduction,
+            cellsize = cellsize,
+            verbose = verbose,
+            origin = origin,
+        datum = 'WGS84',
+        format = 'asc')
+
+def sww2ers(basename_in, basename_out = None,
+            quantity = None,
+            timestep = None,
+            reduction = None,
+            cellsize = 10,
+            verbose = False,
+            origin = None,
+            datum = 'WGS84'):
+    print 'sww2ers will soon be obsoleted - please use sww2dem'
+    sww2dem(basename_in,
+            basename_out = basename_out,
+            quantity = quantity,
+            timestep = timestep,
+            reduction = reduction,
+            cellsize = cellsize,
+            verbose = verbose,
+            origin = origin,
+            datum = datum,
+            format = 'ers')
+################################# END COMPATIBILITY ##############
+
+
+
+def sww2pts(basename_in, basename_out=None,
+            data_points=None,
+            quantity=None,
+            timestep=None,
+            reduction=None,
+            NODATA_value=-9999,
+            verbose=False,
+            origin=None):
+            #datum = 'WGS84')
+
+
+    """Read SWW file and convert to interpolated values at selected points
+
+    The parameter quantity' must be the name of an existing quantity or
+    an expression involving existing quantities. The default is
+    'elevation'.
+
+    if timestep (an index) is given, output quantity at that timestep
+
+    if reduction is given use that to reduce quantity over all timesteps.
+
+    data_points (Nx2 array) give locations of points where quantity is to be computed.
+    
+    """
+
+    import sys
+    from Numeric import array, Float, concatenate, NewAxis, zeros, reshape, sometrue
+    from Numeric import array2string
+
+    from anuga.utilities.polygon import inside_polygon, outside_polygon, separate_points_by_polygon
+    from anuga.abstract_2d_finite_volumes.util import apply_expression_to_dictionary
+
+    from anuga.geospatial_data.geospatial_data import Geospatial_data
+
+    if quantity is None:
+        quantity = 'elevation'
+
+    if reduction is None:
+        reduction = max
+
+    if basename_out is None:
+        basename_out = basename_in + '_%s' %quantity
+
+    swwfile = basename_in + '.sww'
+    ptsfile = basename_out + '.pts'
+
+    # Read sww file
+    if verbose: print 'Reading from %s' %swwfile
+    from Scientific.IO.NetCDF import NetCDFFile
+    fid = NetCDFFile(swwfile)
+
+    # Get extent and reference
+    x = fid.variables['x'][:]
+    y = fid.variables['y'][:]
+    volumes = fid.variables['volumes'][:]
+
+    number_of_timesteps = fid.dimensions['number_of_timesteps']
+    number_of_points = fid.dimensions['number_of_points']
+    if origin is None:
+
+        # Get geo_reference
+        # sww files don't have to have a geo_ref
+        try:
+            geo_reference = Geo_reference(NetCDFObject=fid)
+        except AttributeError, e:
+            geo_reference = Geo_reference() #Default georef object
+
+        xllcorner = geo_reference.get_xllcorner()
+        yllcorner = geo_reference.get_yllcorner()
+        zone = geo_reference.get_zone()
+    else:
+        zone = origin[0]
+        xllcorner = origin[1]
+        yllcorner = origin[2]
+
+
+
+    # FIXME: Refactor using code from file_function.statistics
+    # Something like print swwstats(swwname)
+    if verbose:
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        times = fid.variables['time'][:]
+        print '------------------------------------------------'
+        print 'Statistics of SWW file:'
+        print '  Name: %s' %swwfile
+        print '  Reference:'
+        print '    Lower left corner: [%f, %f]'\
+              %(xllcorner, yllcorner)
+        print '    Start time: %f' %fid.starttime[0]
+        print '  Extent:'
+        print '    x [m] in [%f, %f], len(x) == %d'\
+              %(min(x.flat), max(x.flat), len(x.flat))
+        print '    y [m] in [%f, %f], len(y) == %d'\
+              %(min(y.flat), max(y.flat), len(y.flat))
+        print '    t [s] in [%f, %f], len(t) == %d'\
+              %(min(times), max(times), len(times))
+        print '  Quantities [SI units]:'
+        for name in ['stage', 'xmomentum', 'ymomentum', 'elevation']:
+            q = fid.variables[name][:].flat
+            print '    %s in [%f, %f]' %(name, min(q), max(q))
+
+
+
+    # Get quantity and reduce if applicable
+    if verbose: print 'Processing quantity %s' %quantity
+
+    # Turn NetCDF objects into Numeric arrays
+    quantity_dict = {}
+    for name in fid.variables.keys():
+        quantity_dict[name] = fid.variables[name][:]
+
+
+
+    # Convert quantity expression to quantities found in sww file    
+    q = apply_expression_to_dictionary(quantity, quantity_dict)
+
+
+
+    if len(q.shape) == 2:
+        # q has a time component and needs to be reduced along
+        # the temporal dimension
+        if verbose: print 'Reducing quantity %s' %quantity
+        q_reduced = zeros( number_of_points, Float )
+
+        for k in range(number_of_points):
+            q_reduced[k] = reduction( q[:,k] )
+
+        q = q_reduced
+
+    # Post condition: Now q has dimension: number_of_points
+    assert len(q.shape) == 1
+    assert q.shape[0] == number_of_points
+
+
+    if verbose:
+        print 'Processed values for %s are in [%f, %f]' %(quantity, min(q), max(q))
+
+
+    # Create grid and update xll/yll corner and x,y
+    vertex_points = concatenate ((x[:, NewAxis] ,y[:, NewAxis]), axis = 1)
+    assert len(vertex_points.shape) == 2
+
+    # Interpolate
+    from anuga.fit_interpolate.interpolate import Interpolate
+    interp = Interpolate(vertex_points, volumes, verbose = verbose)
+
+    # Interpolate using quantity values
+    if verbose: print 'Interpolating'
+    interpolated_values = interp.interpolate(q, data_points).flat
+
+
+    if verbose:
+        print 'Interpolated values are in [%f, %f]' %(min(interpolated_values),
+                                                      max(interpolated_values))
+
+    # Assign NODATA_value to all points outside bounding polygon (from interpolation mesh)
+    P = interp.mesh.get_boundary_polygon()
+    outside_indices = outside_polygon(data_points, P, closed=True)
+
+    for i in outside_indices:
+        interpolated_values[i] = NODATA_value
+
+
+    # Store results    
+    G = Geospatial_data(data_points=data_points,
+                        attributes=interpolated_values)
+
+    G.export_points_file(ptsfile, absolute = True)
+
+    fid.close()
+
+
+def convert_dem_from_ascii2netcdf(basename_in, basename_out = None,
+                                  use_cache = False,
+                                  verbose = False):
+    """Read Digitial Elevation model from the following ASCII format (.asc)
+
+    Example:
+
+    ncols         3121
+    nrows         1800
+    xllcorner     722000
+    yllcorner     5893000
+    cellsize      25
+    NODATA_value  -9999
+    138.3698 137.4194 136.5062 135.5558 ..........
+
+    Convert basename_in + '.asc' to NetCDF format (.dem)
+    mimicking the ASCII format closely.
+
+
+    An accompanying file with same basename_in but extension .prj must exist
+    and is used to fix the UTM zone, datum, false northings and eastings.
+
+    The prj format is assumed to be as
+
+    Projection    UTM
+    Zone          56
+    Datum         WGS84
+    Zunits        NO
+    Units         METERS
+    Spheroid      WGS84
+    Xshift        0.0000000000
+    Yshift        10000000.0000000000
+    Parameters
+    """
+
+
+
+    kwargs = {'basename_out': basename_out, 'verbose': verbose}
+
+    if use_cache is True:
+        from caching import cache
+        result = cache(_convert_dem_from_ascii2netcdf, basename_in, kwargs,
+                       dependencies = [basename_in + '.asc'],
+                       verbose = verbose)
+
+    else:
+        result = apply(_convert_dem_from_ascii2netcdf, [basename_in], kwargs)
+
+    return result
+
+
+
+
+
+
+def _convert_dem_from_ascii2netcdf(basename_in, basename_out = None,
+                                  verbose = False):
+    """Read Digitial Elevation model from the following ASCII format (.asc)
+
+    Internal function. See public function convert_dem_from_ascii2netcdf for details.
+    """
+
+    import os
+    from Scientific.IO.NetCDF import NetCDFFile
+    from Numeric import Float, array
+
+    #root, ext = os.path.splitext(basename_in)
+    root = basename_in
+
+    ###########################################
+    # Read Meta data
+    if verbose: print 'Reading METADATA from %s' %root + '.prj'
+    metadatafile = open(root + '.prj')
+    metalines = metadatafile.readlines()
+    metadatafile.close()
+
+    L = metalines[0].strip().split()
+    assert L[0].strip().lower() == 'projection'
+    projection = L[1].strip()                   #TEXT
+
+    L = metalines[1].strip().split()
+    assert L[0].strip().lower() == 'zone'
+    zone = int(L[1].strip())
+
+    L = metalines[2].strip().split()
+    assert L[0].strip().lower() == 'datum'
+    datum = L[1].strip()                        #TEXT
+
+    L = metalines[3].strip().split()
+    assert L[0].strip().lower() == 'zunits'     #IGNORE
+    zunits = L[1].strip()                       #TEXT
+
+    L = metalines[4].strip().split()
+    assert L[0].strip().lower() == 'units'
+    units = L[1].strip()                        #TEXT
+
+    L = metalines[5].strip().split()
+    assert L[0].strip().lower() == 'spheroid'   #IGNORE
+    spheroid = L[1].strip()                     #TEXT
+
+    L = metalines[6].strip().split()
+    assert L[0].strip().lower() == 'xshift'
+    false_easting = float(L[1].strip())
+
+    L = metalines[7].strip().split()
+    assert L[0].strip().lower() == 'yshift'
+    false_northing = float(L[1].strip())
+
+    #print false_easting, false_northing, zone, datum
+
+
+    ###########################################
+    #Read DEM data
+
+    datafile = open(basename_in + '.asc')
+
+    if verbose: print 'Reading DEM from %s' %(basename_in + '.asc')
+    lines = datafile.readlines()
+    datafile.close()
+
+    if verbose: print 'Got', len(lines), ' lines'
+
+    ncols = int(lines[0].split()[1].strip())
+    nrows = int(lines[1].split()[1].strip())
+    xllcorner = float(lines[2].split()[1].strip())
+    yllcorner = float(lines[3].split()[1].strip())
+    cellsize = float(lines[4].split()[1].strip())
+    NODATA_value = int(lines[5].split()[1].strip())
+
+    assert len(lines) == nrows + 6
+
+
+    ##########################################
+
+
+    if basename_out == None:
+        netcdfname = root + '.dem'
+    else:
+        netcdfname = basename_out + '.dem'
+
+    if verbose: print 'Store to NetCDF file %s' %netcdfname
+    # NetCDF file definition
+    fid = NetCDFFile(netcdfname, 'w')
+
+    #Create new file
+    fid.institution = 'Geoscience Australia'
+    fid.description = 'NetCDF DEM format for compact and portable storage ' +\
+                      'of spatial point data'
+
+    fid.ncols = ncols
+    fid.nrows = nrows
+    fid.xllcorner = xllcorner
+    fid.yllcorner = yllcorner
+    fid.cellsize = cellsize
+    fid.NODATA_value = NODATA_value
+
+    fid.zone = zone
+    fid.false_easting = false_easting
+    fid.false_northing = false_northing
+    fid.projection = projection
+    fid.datum = datum
+    fid.units = units
+
+
+    # dimension definitions
+    fid.createDimension('number_of_rows', nrows)
+    fid.createDimension('number_of_columns', ncols)
+
+    # variable definitions
+    fid.createVariable('elevation', Float, ('number_of_rows',
+                                            'number_of_columns'))
+
+    # Get handles to the variables
+    elevation = fid.variables['elevation']
+
+    #Store data
+    n = len(lines[6:])
+    for i, line in enumerate(lines[6:]):
+        fields = line.split()
+        if verbose and i%((n+10)/10)==0:
+            print 'Processing row %d of %d' %(i, nrows)
+
+        elevation[i, :] = array([float(x) for x in fields])
+
+    fid.close()
+
+
+
+
+
+def ferret2sww(basename_in, basename_out = None,
+               verbose = False,
+               minlat = None, maxlat = None,
+               minlon = None, maxlon = None,
+               mint = None, maxt = None, mean_stage = 0,
+               origin = None, zscale = 1,
+               fail_on_NaN = True,
+               NaN_filler = 0,
+               elevation = None,
+               inverted_bathymetry = False
+               ): #FIXME: Bathymetry should be obtained
+                                  #from MOST somehow.
+                                  #Alternatively from elsewhere
+                                  #or, as a last resort,
+                                  #specified here.
+                                  #The value of -100 will work
+                                  #for the Wollongong tsunami
+                                  #scenario but is very hacky
+    """Convert MOST and 'Ferret' NetCDF format for wave propagation to
+    sww format native to abstract_2d_finite_volumes.
+
+    Specify only basename_in and read files of the form
+    basefilename_ha.nc, basefilename_ua.nc, basefilename_va.nc containing
+    relative height, x-velocity and y-velocity, respectively.
+
+    Also convert latitude and longitude to UTM. All coordinates are
+    assumed to be given in the GDA94 datum.
+
+    min's and max's: If omitted - full extend is used.
+    To include a value min may equal it, while max must exceed it.
+    Lat and lon are assuemd to be in decimal degrees
+
+    origin is a 3-tuple with geo referenced
+    UTM coordinates (zone, easting, northing)
+
+    nc format has values organised as HA[TIME, LATITUDE, LONGITUDE]
+    which means that longitude is the fastest
+    varying dimension (row major order, so to speak)
+
+    ferret2sww uses grid points as vertices in a triangular grid
+    counting vertices from lower left corner upwards, then right
+    """
+
+    import os
+    from Scientific.IO.NetCDF import NetCDFFile
+    from Numeric import Float, Int, Int32, searchsorted, zeros, array
+    from Numeric import allclose, around
+
+    precision = Float
+
+    msg = 'Must use latitudes and longitudes for minlat, maxlon etc'
+
+    if minlat != None:
+        assert -90 < minlat < 90 , msg
+    if maxlat != None:
+        assert -90 < maxlat < 90 , msg
+    if minlon != None:
+        assert -180 < minlon < 180 , msg
+    if maxlon != None:
+        assert -180 < maxlon < 180 , msg
+
+
+    #Get NetCDF data
+    if verbose: print 'Reading files %s_*.nc' %basename_in
+    file_h = NetCDFFile(basename_in + '_ha.nc', 'r') #Wave amplitude (cm)
+    file_u = NetCDFFile(basename_in + '_ua.nc', 'r') #Velocity (x) (cm/s)
+    file_v = NetCDFFile(basename_in + '_va.nc', 'r') #Velocity (y) (cm/s)
+    file_e = NetCDFFile(basename_in + '_e.nc', 'r')  #Elevation (z) (m)
+
+    if basename_out is None:
+        swwname = basename_in + '.sww'
+    else:
+        swwname = basename_out + '.sww'
+
+#    Get dimensions of file_h
+    for dimension in file_h.dimensions.keys():
+        if dimension[:3] == 'LON':
+            dim_h_longitude = dimension
+        if dimension[:3] == 'LAT':
+            dim_h_latitude = dimension
+        if dimension[:4] == 'TIME':
+            dim_h_time = dimension
+
+#    print 'long:', dim_h_longitude
+#    print 'lats:', dim_h_latitude
+#    print 'times:', dim_h_time
+
+    times = file_h.variables[dim_h_time]
+    latitudes = file_h.variables[dim_h_latitude]
+    longitudes = file_h.variables[dim_h_longitude]
+    
+# get dimensions for file_e
+    for dimension in file_e.dimensions.keys():
+        if dimension[:3] == 'LON':
+            dim_e_longitude = dimension
+        if dimension[:3] == 'LAT':
+            dim_e_latitude = dimension
+        if dimension[:4] == 'TIME':
+            dim_e_time = dimension
+
+# get dimensions for file_u
+    for dimension in file_u.dimensions.keys():
+        if dimension[:3] == 'LON':
+            dim_u_longitude = dimension
+        if dimension[:3] == 'LAT':
+            dim_u_latitude = dimension
+        if dimension[:4] == 'TIME':
+            dim_u_time = dimension
+            
+# get dimensions for file_v
+    for dimension in file_v.dimensions.keys():
+        if dimension[:3] == 'LON':
+            dim_v_longitude = dimension
+        if dimension[:3] == 'LAT':
+            dim_v_latitude = dimension
+        if dimension[:4] == 'TIME':
+            dim_v_time = dimension
+
+
+    #Precision used by most for lat/lon is 4 or 5 decimals
+    e_lat = around(file_e.variables[dim_e_latitude][:], 5)
+    e_lon = around(file_e.variables[dim_e_longitude][:], 5)
+
+    #Check that files are compatible
+    assert allclose(latitudes, file_u.variables[dim_u_latitude])
+    assert allclose(latitudes, file_v.variables[dim_v_latitude])
+    assert allclose(latitudes, e_lat)
+
+    assert allclose(longitudes, file_u.variables[dim_u_longitude])
+    assert allclose(longitudes, file_v.variables[dim_v_longitude])
+    assert allclose(longitudes, e_lon)
+
+    if mint == None:
+        jmin = 0
+    else:
+        jmin = searchsorted(times, mint)
+
+    if maxt == None:
+        jmax=len(times)
+    else:
+        jmax = searchsorted(times, maxt)
+
+    if minlat == None:
+        kmin=0
+    else:
+        kmin = searchsorted(latitudes, minlat)
+
+    if maxlat == None:
+        kmax = len(latitudes)
+    else:
+        kmax = searchsorted(latitudes, maxlat)
+
+    if minlon == None:
+        lmin=0
+    else:
+        lmin = searchsorted(longitudes, minlon)
+
+    if maxlon == None:
+        lmax = len(longitudes)
+    else:
+        lmax = searchsorted(longitudes, maxlon)
+
+#    print' j', jmin, jmax
+    times = times[jmin:jmax]
+    latitudes = latitudes[kmin:kmax]
+    longitudes = longitudes[lmin:lmax]
+
+
+    if verbose: print 'cropping'
+    zname = 'ELEVATION'
+
+    amplitudes = file_h.variables['HA'][jmin:jmax, kmin:kmax, lmin:lmax]
+    uspeed = file_u.variables['UA'][jmin:jmax, kmin:kmax, lmin:lmax] #Lon
+    vspeed = file_v.variables['VA'][jmin:jmax, kmin:kmax, lmin:lmax] #Lat
+    elevations = file_e.variables[zname][kmin:kmax, lmin:lmax]
+
+    #    if latitudes2[0]==latitudes[0] and latitudes2[-1]==latitudes[-1]:
+    #        elevations = file_e.variables['ELEVATION'][kmin:kmax, lmin:lmax]
+    #    elif latitudes2[0]==latitudes[-1] and latitudes2[-1]==latitudes[0]:
+    #        from Numeric import asarray
+    #        elevations=elevations.tolist()
+    #        elevations.reverse()
+    #        elevations=asarray(elevations)
+    #    else:
+    #        from Numeric import asarray
+    #        elevations=elevations.tolist()
+    #        elevations.reverse()
+    #        elevations=asarray(elevations)
+    #        'print hmmm'
+
+
+
+    #Get missing values
+    nan_ha = file_h.variables['HA'].missing_value[0]
+    nan_ua = file_u.variables['UA'].missing_value[0]
+    nan_va = file_v.variables['VA'].missing_value[0]
+    if hasattr(file_e.variables[zname],'missing_value'):
+        nan_e  = file_e.variables[zname].missing_value[0]
+    else:
+        nan_e = None
+
+    #Cleanup
+    from Numeric import sometrue
+
+    missing = (amplitudes == nan_ha)
+    if sometrue (missing):
+        if fail_on_NaN:
+            msg = 'NetCDFFile %s contains missing values'\
+                  %(basename_in+'_ha.nc')
+            raise DataMissingValuesError, msg
+        else:
+            amplitudes = amplitudes*(missing==0) + missing*NaN_filler
+
+    missing = (uspeed == nan_ua)
+    if sometrue (missing):
+        if fail_on_NaN:
+            msg = 'NetCDFFile %s contains missing values'\
+                  %(basename_in+'_ua.nc')
+            raise DataMissingValuesError, msg
+        else:
+            uspeed = uspeed*(missing==0) + missing*NaN_filler
+
+    missing = (vspeed == nan_va)
+    if sometrue (missing):
+        if fail_on_NaN:
+            msg = 'NetCDFFile %s contains missing values'\
+                  %(basename_in+'_va.nc')
+            raise DataMissingValuesError, msg
+        else:
+            vspeed = vspeed*(missing==0) + missing*NaN_filler
+
+
+    missing = (elevations == nan_e)
+    if sometrue (missing):
+        if fail_on_NaN:
+            msg = 'NetCDFFile %s contains missing values'\
+                  %(basename_in+'_e.nc')
+            raise DataMissingValuesError, msg
+        else:
+            elevations = elevations*(missing==0) + missing*NaN_filler
+
+    #######
+
+
+
+    number_of_times = times.shape[0]
+    number_of_latitudes = latitudes.shape[0]
+    number_of_longitudes = longitudes.shape[0]
+
+    assert amplitudes.shape[0] == number_of_times
+    assert amplitudes.shape[1] == number_of_latitudes
+    assert amplitudes.shape[2] == number_of_longitudes
+
+    if verbose:
+        print '------------------------------------------------'
+        print 'Statistics:'
+        print '  Extent (lat/lon):'
+        print '    lat in [%f, %f], len(lat) == %d'\
+              %(min(latitudes.flat), max(latitudes.flat),
+                len(latitudes.flat))
+        print '    lon in [%f, %f], len(lon) == %d'\
+              %(min(longitudes.flat), max(longitudes.flat),
+                len(longitudes.flat))
+        print '    t in [%f, %f], len(t) == %d'\
+              %(min(times.flat), max(times.flat), len(times.flat))
+
+        q = amplitudes.flat
+        name = 'Amplitudes (ha) [cm]'
+        print '  %s in [%f, %f]' %(name, min(q), max(q))
+
+        q = uspeed.flat
+        name = 'Speeds (ua) [cm/s]'
+        print '  %s in [%f, %f]' %(name, min(q), max(q))
+
+        q = vspeed.flat
+        name = 'Speeds (va) [cm/s]'
+        print '  %s in [%f, %f]' %(name, min(q), max(q))
+
+        q = elevations.flat
+        name = 'Elevations (e) [m]'
+        print '  %s in [%f, %f]' %(name, min(q), max(q))
+
+
+    #print number_of_latitudes, number_of_longitudes
+    number_of_points = number_of_latitudes*number_of_longitudes
+    number_of_volumes = (number_of_latitudes-1)*(number_of_longitudes-1)*2
+
+
+    file_h.close()
+    file_u.close()
+    file_v.close()
+    file_e.close()
+
+
+    # NetCDF file definition
+    outfile = NetCDFFile(swwname, 'w')
+
+    #Create new file
+    outfile.institution = 'Geoscience Australia'
+    outfile.description = 'Converted from Ferret files: %s, %s, %s, %s'\
+                          %(basename_in + '_ha.nc',
+                            basename_in + '_ua.nc',
+                            basename_in + '_va.nc',
+                            basename_in + '_e.nc')
+
+
+    #For sww compatibility
+    outfile.smoothing = 'Yes'
+    outfile.order = 1
+
+    #Start time in seconds since the epoch (midnight 1/1/1970)
+    outfile.starttime = starttime = times[0]
+    times = times - starttime  #Store relative times
+
+    # dimension definitions
+    outfile.createDimension('number_of_volumes', number_of_volumes)
+
+    outfile.createDimension('number_of_vertices', 3)
+    outfile.createDimension('number_of_points', number_of_points)
+
+
+    #outfile.createDimension('number_of_timesteps', len(times))
+    outfile.createDimension('number_of_timesteps', len(times))
+
+    # variable definitions
+    outfile.createVariable('x', precision, ('number_of_points',))
+    outfile.createVariable('y', precision, ('number_of_points',))
+    outfile.createVariable('elevation', precision, ('number_of_points',))
+
+    #FIXME: Backwards compatibility
+    outfile.createVariable('z', precision, ('number_of_points',))
+    #################################
+
+    outfile.createVariable('volumes', Int, ('number_of_volumes',
+                                            'number_of_vertices'))
+
+    outfile.createVariable('time', precision,
+                           ('number_of_timesteps',))
+
+    outfile.createVariable('stage', precision,
+                           ('number_of_timesteps',
+                            'number_of_points'))
+
+    outfile.createVariable('xmomentum', precision,
+                           ('number_of_timesteps',
+                            'number_of_points'))
+
+    outfile.createVariable('ymomentum', precision,
+                           ('number_of_timesteps',
+                            'number_of_points'))
+
+
+    #Store
+    from anuga.coordinate_transforms.redfearn import redfearn
+    x = zeros(number_of_points, Float)  #Easting
+    y = zeros(number_of_points, Float)  #Northing
+
+
+    if verbose: print 'Making triangular grid'
+    #Check zone boundaries
+    refzone, _, _ = redfearn(latitudes[0],longitudes[0])
+
+    vertices = {}
+    i = 0
+    for k, lat in enumerate(latitudes):       #Y direction
+        for l, lon in enumerate(longitudes):  #X direction
+
+            vertices[l,k] = i
+
+            zone, easting, northing = redfearn(lat,lon)
+
+            msg = 'Zone boundary crossed at longitude =', lon
+            #assert zone == refzone, msg
+            #print '%7.2f %7.2f %8.2f %8.2f' %(lon, lat, easting, northing)
+            x[i] = easting
+            y[i] = northing
+            i += 1
+
+
+    #Construct 2 triangles per 'rectangular' element
+    volumes = []
+    for l in range(number_of_longitudes-1):    #X direction
+        for k in range(number_of_latitudes-1): #Y direction
+            v1 = vertices[l,k+1]
+            v2 = vertices[l,k]
+            v3 = vertices[l+1,k+1]
+            v4 = vertices[l+1,k]
+
+            volumes.append([v1,v2,v3]) #Upper element
+            volumes.append([v4,v3,v2]) #Lower element
+
+    volumes = array(volumes)
+
+    if origin == None:
+        zone = refzone
+        xllcorner = min(x)
+        yllcorner = min(y)
+    else:
+        zone = origin[0]
+        xllcorner = origin[1]
+        yllcorner = origin[2]
+
+
+    outfile.xllcorner = xllcorner
+    outfile.yllcorner = yllcorner
+    outfile.zone = zone
+
+
+    if elevation is not None:
+        z = elevation
+    else:
+        if inverted_bathymetry:
+            z = -1*elevations
+        else:
+            z = elevations
+    #FIXME: z should be obtained from MOST and passed in here
+
+    from Numeric import resize
+    z = resize(z,outfile.variables['z'][:].shape)
+    outfile.variables['x'][:] = x - xllcorner
+    outfile.variables['y'][:] = y - yllcorner
+    outfile.variables['z'][:] = z             #FIXME HACK
+    outfile.variables['elevation'][:] = z
+    outfile.variables['time'][:] = times   #Store time relative
+    outfile.variables['volumes'][:] = volumes.astype(Int32) #On Opteron 64
+
+
+
+    #Time stepping
+    stage = outfile.variables['stage']
+    xmomentum = outfile.variables['xmomentum']
+    ymomentum = outfile.variables['ymomentum']
+
+    if verbose: print 'Converting quantities'
+    n = len(times)
+    for j in range(n):
+        if verbose and j%((n+10)/10)==0: print '  Doing %d of %d' %(j, n)
+        i = 0
+        for k in range(number_of_latitudes):      #Y direction
+            for l in range(number_of_longitudes): #X direction
+                w = zscale*amplitudes[j,k,l]/100 + mean_stage
+                stage[j,i] = w
+                h = w - z[i]
+                xmomentum[j,i] = uspeed[j,k,l]/100*h
+                ymomentum[j,i] = vspeed[j,k,l]/100*h
+                i += 1
+
+    #outfile.close()
+
+    #FIXME: Refactor using code from file_function.statistics
+    #Something like print swwstats(swwname)
+    if verbose:
+        x = outfile.variables['x'][:]
+        y = outfile.variables['y'][:]
+        times = outfile.variables['time'][:]
+        print '------------------------------------------------'
+        print 'Statistics of output file:'
+        print '  Name: %s' %swwname
+        print '  Reference:'
+        print '    Lower left corner: [%f, %f]'\
+              %(xllcorner, yllcorner)
+        print '    Start time: %f' %starttime
+        print '  Extent:'
+        print '    x [m] in [%f, %f], len(x) == %d'\
+              %(min(x.flat), max(x.flat), len(x.flat))
+        print '    y [m] in [%f, %f], len(y) == %d'\
+              %(min(y.flat), max(y.flat), len(y.flat))
+        print '    t [s] in [%f, %f], len(t) == %d'\
+              %(min(times), max(times), len(times))
+        print '  Quantities [SI units]:'
+        for name in ['stage', 'xmomentum', 'ymomentum', 'elevation']:
+            q = outfile.variables[name][:].flat
+            print '    %s in [%f, %f]' %(name, min(q), max(q))
+
+
+
+    outfile.close()
+
+
+
+
+
+def timefile2netcdf(filename, quantity_names = None):
+    """Template for converting typical text files with time series to
+    NetCDF tms file.
+
+
+    The file format is assumed to be either two fields separated by a comma:
+
+        time [DD/MM/YY hh:mm:ss], value0 value1 value2 ...
+
+    E.g
+
+      31/08/04 00:00:00, 1.328223 0 0
+      31/08/04 00:15:00, 1.292912 0 0
+
+    will provide a time dependent function f(t) with three attributes
+
+    filename is assumed to be the rootname with extenisons .txt and .sww
+    """
+
+    import time, calendar
+    from Numeric import array
+    from anuga.config import time_format
+    from anuga.utilities.numerical_tools import ensure_numeric
+
+
+
+    fid = open(filename + '.txt')
+    line = fid.readline()
+    fid.close()
+
+    fields = line.split(',')
+    msg = 'File %s must have the format date, value0 value1 value2 ...'
+    assert len(fields) == 2, msg
+
+    try:
+        starttime = calendar.timegm(time.strptime(fields[0], time_format))
+    except ValueError:
+        msg = 'First field in file %s must be' %filename
+        msg += ' date-time with format %s.\n' %time_format
+        msg += 'I got %s instead.' %fields[0]
+        raise DataTimeError, msg
+
+
+    #Split values
+    values = []
+    for value in fields[1].split():
+        values.append(float(value))
+
+    q = ensure_numeric(values)
+
+    msg = 'ERROR: File must contain at least one independent value'
+    assert len(q.shape) == 1, msg
+
+
+
+    #Read times proper
+    from Numeric import zeros, Float, alltrue
+    from anuga.config import time_format
+    import time, calendar
+
+    fid = open(filename + '.txt')
+    lines = fid.readlines()
+    fid.close()
+
+    N = len(lines)
+    d = len(q)
+
+    T = zeros(N, Float)       #Time
+    Q = zeros((N, d), Float)  #Values
+
+    for i, line in enumerate(lines):
+        fields = line.split(',')
+        realtime = calendar.timegm(time.strptime(fields[0], time_format))
+
+        T[i] = realtime - starttime
+
+        for j, value in enumerate(fields[1].split()):
+            Q[i, j] = float(value)
+
+    msg = 'File %s must list time as a monotonuosly ' %filename
+    msg += 'increasing sequence'
+    assert alltrue( T[1:] - T[:-1] > 0 ), msg
+
+
+    #Create NetCDF file
+    from Scientific.IO.NetCDF import NetCDFFile
+
+    fid = NetCDFFile(filename + '.tms', 'w')
+
+
+    fid.institution = 'Geoscience Australia'
+    fid.description = 'Time series'
+
+
+    #Reference point
+    #Start time in seconds since the epoch (midnight 1/1/1970)
+    #FIXME: Use Georef
+    fid.starttime = starttime
+
+
+    # dimension definitions
+    #fid.createDimension('number_of_volumes', self.number_of_volumes)
+    #fid.createDimension('number_of_vertices', 3)
+
+
+    fid.createDimension('number_of_timesteps', len(T))
+
+    fid.createVariable('time', Float, ('number_of_timesteps',))
+
+    fid.variables['time'][:] = T
+
+    for i in range(Q.shape[1]):
+        try:
+            name = quantity_names[i]
+        except:
+            name = 'Attribute%d'%i
+
+        fid.createVariable(name, Float, ('number_of_timesteps',))
+        fid.variables[name][:] = Q[:,i]
+
+    fid.close()
+
+
+def extent_sww(file_name):
+    """
+    Read in an sww file.
+
+    Input;
+    file_name - the sww file
+
+    Output;
+    z - Vector of bed elevation
+    volumes - Array.  Each row has 3 values, representing
+    the vertices that define the volume
+    time - Vector of the times where there is stage information
+    stage - array with respect to time and vertices (x,y)
+    """
+
+
+    from Scientific.IO.NetCDF import NetCDFFile
+
+    #Check contents
+    #Get NetCDF
+    fid = NetCDFFile(file_name, 'r')
+
+    # Get the variables
+    x = fid.variables['x'][:]
+    y = fid.variables['y'][:]
+    stage = fid.variables['stage'][:]
+    #print "stage",stage
+    #print "stage.shap",stage.shape
+    #print "min(stage.flat), mpythonax(stage.flat)",min(stage.flat), max(stage.flat)
+    #print "min(stage)",min(stage)
+
+    fid.close()
+
+    return [min(x),max(x),min(y),max(y),min(stage.flat),max(stage.flat)]
+
+
+def sww2domain(filename,boundary=None,t=None,\
+               fail_if_NaN=True,NaN_filler=0\
+               ,verbose = False,very_verbose = False):
+    """
+    Usage: domain = sww2domain('file.sww',t=time (default = last time in file))
+
+    Boundary is not recommended if domain.smooth is not selected, as it
+    uses unique coordinates, but not unique boundaries. This means that
+    the boundary file will not be compatable with the coordinates, and will
+    give a different final boundary, or crash.
+    """
+    NaN=9.969209968386869e+036
+    #initialise NaN.
+
+    from Scientific.IO.NetCDF import NetCDFFile
+    from shallow_water import Domain
+    from Numeric import asarray, transpose, resize
+
+    if verbose: print 'Reading from ', filename
+    fid = NetCDFFile(filename, 'r')    #Open existing file for read
+    time = fid.variables['time']       #Timesteps
+    if t is None:
+        t = time[-1]
+    time_interp = get_time_interp(time,t)
+
+    # Get the variables as Numeric arrays
+    x = fid.variables['x'][:]             #x-coordinates of vertices
+    y = fid.variables['y'][:]             #y-coordinates of vertices
+    elevation = fid.variables['elevation']     #Elevation
+    stage = fid.variables['stage']     #Water level
+    xmomentum = fid.variables['xmomentum']   #Momentum in the x-direction
+    ymomentum = fid.variables['ymomentum']   #Momentum in the y-direction
+
+    starttime = fid.starttime[0]
+    volumes = fid.variables['volumes'][:] #Connectivity
+    coordinates=transpose(asarray([x.tolist(),y.tolist()]))
+
+    conserved_quantities = []
+    interpolated_quantities = {}
+    other_quantities = []
+
+    # get geo_reference
+    #sww files don't have to have a geo_ref
+    try:
+        geo_reference = Geo_reference(NetCDFObject=fid)
+    except: #AttributeError, e:
+        geo_reference = None
+
+    if verbose: print '    getting quantities'
+    for quantity in fid.variables.keys():
+        dimensions = fid.variables[quantity].dimensions
+        if 'number_of_timesteps' in dimensions:
+            conserved_quantities.append(quantity)
+            interpolated_quantities[quantity]=\
+                  interpolated_quantity(fid.variables[quantity][:],time_interp)
+        else: other_quantities.append(quantity)
+
+    other_quantities.remove('x')
+    other_quantities.remove('y')
+    other_quantities.remove('z')
+    other_quantities.remove('volumes')
+
+    conserved_quantities.remove('time')
+
+    if verbose: print '    building domain'
+    #    From domain.Domain:
+    #    domain = Domain(coordinates, volumes,\
+    #                    conserved_quantities = conserved_quantities,\
+    #                    other_quantities = other_quantities,zone=zone,\
+    #                    xllcorner=xllcorner, yllcorner=yllcorner)
+
+    #   From shallow_water.Domain:
+    coordinates=coordinates.tolist()
+    volumes=volumes.tolist()
+    #FIXME:should this be in mesh?(peter row)
+    if fid.smoothing == 'Yes': unique = False
+    else: unique = True
+    if unique:
+        coordinates,volumes,boundary=weed(coordinates,volumes,boundary)
+
+
+    try:
+        domain = Domain(coordinates, volumes, boundary)
+    except AssertionError, e:
+        fid.close()
+        msg = 'Domain could not be created: %s. Perhaps use "fail_if_NaN=False and NaN_filler = ..."' %e
+        raise DataDomainError, msg
+
+    if not boundary is None:
+        domain.boundary = boundary
+
+    domain.geo_reference = geo_reference
+
+    domain.starttime=float(starttime)+float(t)
+    domain.time=0.0
+
+    for quantity in other_quantities:
+        try:
+            NaN = fid.variables[quantity].missing_value
+        except:
+            pass #quantity has no missing_value number
+        X = fid.variables[quantity][:]
+        if very_verbose:
+            print '       ',quantity
+            print '        NaN =',NaN
+            print '        max(X)'
+            print '       ',max(X)
+            print '        max(X)==NaN'
+            print '       ',max(X)==NaN
+            print ''
+        if (max(X)==NaN) or (min(X)==NaN):
+            if fail_if_NaN:
+                msg = 'quantity "%s" contains no_data entry'%quantity
+                raise DataMissingValuesError, msg
+            else:
+                data = (X<>NaN)
+                X = (X*data)+(data==0)*NaN_filler
+        if unique:
+            X = resize(X,(len(X)/3,3))
+        domain.set_quantity(quantity,X)
+    #
+    for quantity in conserved_quantities:
+        try:
+            NaN = fid.variables[quantity].missing_value
+        except:
+            pass #quantity has no missing_value number
+        X = interpolated_quantities[quantity]
+        if very_verbose:
+            print '       ',quantity
+            print '        NaN =',NaN
+            print '        max(X)'
+            print '       ',max(X)
+            print '        max(X)==NaN'
+            print '       ',max(X)==NaN
+            print ''
+        if (max(X)==NaN) or (min(X)==NaN):
+            if fail_if_NaN:
+                msg = 'quantity "%s" contains no_data entry'%quantity
+                raise DataMissingValuesError, msg
+            else:
+                data = (X<>NaN)
+                X = (X*data)+(data==0)*NaN_filler
+        if unique:
+            X = resize(X,(X.shape[0]/3,3))
+        domain.set_quantity(quantity,X)
+
+    fid.close()
+    return domain
+
+def interpolated_quantity(saved_quantity,time_interp):
+
+    #given an index and ratio, interpolate quantity with respect to time.
+    index,ratio = time_interp
+    Q = saved_quantity
+    if ratio > 0:
+        q = (1-ratio)*Q[index]+ ratio*Q[index+1]
+    else:
+        q = Q[index]
+    #Return vector of interpolated values
+    return q
+
+def get_time_interp(time,t=None):
+    #Finds the ratio and index for time interpolation.
+    #It is borrowed from previous abstract_2d_finite_volumes code.
+    if t is None:
+        t=time[-1]
+        index = -1
+        ratio = 0.
+    else:
+        T = time
+        tau = t
+        index=0
+        msg = 'Time interval derived from file %s [%s:%s]'\
+            %('FIXMEfilename', T[0], T[-1])
+        msg += ' does not match model time: %s' %tau
+        if tau < time[0]: raise DataTimeError, msg
+        if tau > time[-1]: raise DataTimeError, msg
+        while tau > time[index]: index += 1
+        while tau < time[index]: index -= 1
+        if tau == time[index]:
+            #Protect against case where tau == time[-1] (last time)
+            # - also works in general when tau == time[i]
+            ratio = 0
+        else:
+            #t is now between index and index+1
+            ratio = (tau - time[index])/(time[index+1] - time[index])
+    return (index,ratio)
+
+
+def weed(coordinates,volumes,boundary = None):
+    if type(coordinates)=='array':
+        coordinates = coordinates.tolist()
+    if type(volumes)=='array':
+        volumes = volumes.tolist()
+
+    unique = False
+    point_dict = {}
+    same_point = {}
+    for i in range(len(coordinates)):
+        point = tuple(coordinates[i])
+        if point_dict.has_key(point):
+            unique = True
+            same_point[i]=point
+            #to change all point i references to point j
+        else:
+            point_dict[point]=i
+            same_point[i]=point
+
+    coordinates = []
+    i = 0
+    for point in point_dict.keys():
+        point = tuple(point)
+        coordinates.append(list(point))
+        point_dict[point]=i
+        i+=1
+
+
+    for volume in volumes:
+        for i in range(len(volume)):
+            index = volume[i]
+            if index>-1:
+                volume[i]=point_dict[same_point[index]]
+
+    new_boundary = {}
+    if not boundary is None:
+        for segment in boundary.keys():
+            point0 = point_dict[same_point[segment[0]]]
+            point1 = point_dict[same_point[segment[1]]]
+            label = boundary[segment]
+            #FIXME should the bounday attributes be concaterated
+            #('exterior, pond') or replaced ('pond')(peter row)
+
+            if new_boundary.has_key((point0,point1)):
+                new_boundary[(point0,point1)]=new_boundary[(point0,point1)]#\
+                                              #+','+label
+
+            elif new_boundary.has_key((point1,point0)):
+                new_boundary[(point1,point0)]=new_boundary[(point1,point0)]#\
+                                              #+','+label
+            else: new_boundary[(point0,point1)]=label
+
+        boundary = new_boundary
+
+    return coordinates,volumes,boundary
+
+
+def decimate_dem(basename_in, stencil, cellsize_new, basename_out=None,
+                 verbose=False):
+    """Read Digitial Elevation model from the following NetCDF format (.dem)
+
+    Example:
+
+    ncols         3121
+    nrows         1800
+    xllcorner     722000
+    yllcorner     5893000
+    cellsize      25
+    NODATA_value  -9999
+    138.3698 137.4194 136.5062 135.5558 ..........
+
+    Decimate data to cellsize_new using stencil and write to NetCDF dem format.
+    """
+
+    import os
+    from Scientific.IO.NetCDF import NetCDFFile
+    from Numeric import Float, zeros, sum, reshape, equal
+
+    root = basename_in
+    inname = root + '.dem'
+
+    #Open existing netcdf file to read
+    infile = NetCDFFile(inname, 'r')
+    if verbose: print 'Reading DEM from %s' %inname
+
+    #Read metadata
+    ncols = infile.ncols[0]
+    nrows = infile.nrows[0]
+    xllcorner = infile.xllcorner[0]
+    yllcorner = infile.yllcorner[0]
+    cellsize = infile.cellsize[0]
+    NODATA_value = infile.NODATA_value[0]
+    zone = infile.zone[0]
+    false_easting = infile.false_easting[0]
+    false_northing = infile.false_northing[0]
+    projection = infile.projection
+    datum = infile.datum
+    units = infile.units
+
+    dem_elevation = infile.variables['elevation']
+
+    #Get output file name
+    if basename_out == None:
+        outname = root + '_' + repr(cellsize_new) + '.dem'
+    else:
+        outname = basename_out + '.dem'
+
+    if verbose: print 'Write decimated NetCDF file to %s' %outname
+
+    #Determine some dimensions for decimated grid
+    (nrows_stencil, ncols_stencil) = stencil.shape
+    x_offset = ncols_stencil / 2
+    y_offset = nrows_stencil / 2
+    cellsize_ratio = int(cellsize_new / cellsize)
+    ncols_new = 1 + (ncols - ncols_stencil) / cellsize_ratio
+    nrows_new = 1 + (nrows - nrows_stencil) / cellsize_ratio
+
+    #Open netcdf file for output
+    outfile = NetCDFFile(outname, 'w')
+
+    #Create new file
+    outfile.institution = 'Geoscience Australia'
+    outfile.description = 'NetCDF DEM format for compact and portable storage ' +\
+                           'of spatial point data'
+    #Georeferencing
+    outfile.zone = zone
+    outfile.projection = projection
+    outfile.datum = datum
+    outfile.units = units
+
+    outfile.cellsize = cellsize_new
+    outfile.NODATA_value = NODATA_value
+    outfile.false_easting = false_easting
+    outfile.false_northing = false_northing
+
+    outfile.xllcorner = xllcorner + (x_offset * cellsize)
+    outfile.yllcorner = yllcorner + (y_offset * cellsize)
+    outfile.ncols = ncols_new
+    outfile.nrows = nrows_new
+
+    # dimension definition
+    outfile.createDimension('number_of_points', nrows_new*ncols_new)
+
+    # variable definition
+    outfile.createVariable('elevation', Float, ('number_of_points',))
+
+    # Get handle to the variable
+    elevation = outfile.variables['elevation']
+
+    dem_elevation_r = reshape(dem_elevation, (nrows, ncols))
+
+    #Store data
+    global_index = 0
+    for i in range(nrows_new):
+        if verbose: print 'Processing row %d of %d' %(i, nrows_new)
+        lower_index = global_index
+        telev =  zeros(ncols_new, Float)
+        local_index = 0
+        trow = i * cellsize_ratio
+
+        for j in range(ncols_new):
+            tcol = j * cellsize_ratio
+            tmp = dem_elevation_r[trow:trow+nrows_stencil, tcol:tcol+ncols_stencil]
+
+            #if dem contains 1 or more NODATA_values set value in
+            #decimated dem to NODATA_value, else compute decimated
+            #value using stencil
+            if sum(sum(equal(tmp, NODATA_value))) > 0:
+                telev[local_index] = NODATA_value
+            else:
+                telev[local_index] = sum(sum(tmp * stencil))
+
+            global_index += 1
+            local_index += 1
+
+        upper_index = global_index
+
+        elevation[lower_index:upper_index] = telev
+
+    assert global_index == nrows_new*ncols_new, 'index not equal to number of points'
+
+    infile.close()
+    outfile.close()
+
+
+
+
+def tsh2sww(filename, verbose=False): #test_tsh2sww
+    """
+    to check if a tsh/msh file 'looks' good.
+    """
+
+    from shallow_water import Domain
+    from anuga.abstract_2d_finite_volumes.pmesh2domain import pmesh_to_domain_instance
+    import time, os
+    from anuga.abstract_2d_finite_volumes.data_manager import get_dataobject
+    from os import sep, path
+    from anuga.utilities.numerical_tools import mean
+
+    if verbose == True:print 'Creating domain from', filename
+    domain = pmesh_to_domain_instance(filename, Domain)
+    if verbose == True:print "Number of triangles = ", len(domain)
+
+    domain.smooth = True
+    domain.format = 'sww'   #Native netcdf visualisation format
+    file_path, filename = path.split(filename)
+    filename, ext = path.splitext(filename)
+    domain.filename = filename
+    domain.reduction = mean
+    if verbose == True:print "file_path",file_path
+    if file_path == "":file_path = "."
+    domain.set_datadir(file_path)
+
+    if verbose == True:
+        print "Output written to " + domain.get_datadir() + sep + \
+              domain.filename + "." + domain.format
+    sww = get_dataobject(domain)
+    sww.store_connectivity()
+    sww.store_timestep('stage')
+
+
+def asc_csiro2sww(bath_dir,
+                  elevation_dir,
+                  ucur_dir,
+                  vcur_dir,
+                  sww_file,
+                  minlat = None, maxlat = None,
+                  minlon = None, maxlon = None,
+                  zscale=1,
+                  mean_stage = 0,
+                  fail_on_NaN = True,
+                  elevation_NaN_filler = 0,
+                  bath_prefix='ba',
+                  elevation_prefix='el',
+                  verbose=False):
+    """
+    Produce an sww boundary file, from esri ascii data from CSIRO.
+
+    Also convert latitude and longitude to UTM. All coordinates are
+    assumed to be given in the GDA94 datum.
+
+    assume:
+    All files are in esri ascii format
+
+    4 types of information
+    bathymetry
+    elevation
+    u velocity
+    v velocity
+
+    Assumptions
+    The metadata of all the files is the same
+    Each type is in a seperate directory
+    One bath file with extention .000
+    The time period is less than 24hrs and uniform.
+    """
+    from Scientific.IO.NetCDF import NetCDFFile
+
+    from anuga.coordinate_transforms.redfearn import redfearn
+
+    precision = Float # So if we want to change the precision its done here
+
+    # go in to the bath dir and load the only file,
+    bath_files = os.listdir(bath_dir)
+    #print "bath_files",bath_files
+
+    #fixme: make more general?
+    bath_file = bath_files[0]
+    bath_dir_file =  bath_dir + os.sep + bath_file
+    bath_metadata,bath_grid =  _read_asc(bath_dir_file)
+    #print "bath_metadata",bath_metadata
+    #print "bath_grid",bath_grid
+
+    #Use the date.time of the bath file as a basis for
+    #the start time for other files
+    base_start = bath_file[-12:]
+
+    #go into the elevation dir and load the 000 file
+    elevation_dir_file = elevation_dir  + os.sep + elevation_prefix \
+                         + base_start
+    #elevation_metadata,elevation_grid =  _read_asc(elevation_dir_file)
+    #print "elevation_dir_file",elevation_dir_file
+    #print "elevation_grid", elevation_grid
+
+    elevation_files = os.listdir(elevation_dir)
+    ucur_files = os.listdir(ucur_dir)
+    vcur_files = os.listdir(vcur_dir)
+
+    # the first elevation file should be the
+    # file with the same base name as the bath data
+    #print "elevation_files[0]",elevation_files[0]
+    #print "'el' + base_start",'el' + base_start
+    assert elevation_files[0] == 'el' + base_start
+
+    #assert bath_metadata == elevation_metadata
+
+
+
+    number_of_latitudes = bath_grid.shape[0]
+    number_of_longitudes = bath_grid.shape[1]
+    #number_of_times = len(os.listdir(elevation_dir))
+    #number_of_points = number_of_latitudes*number_of_longitudes
+    number_of_volumes = (number_of_latitudes-1)*(number_of_longitudes-1)*2
+
+    longitudes = [bath_metadata['xllcorner']+x*bath_metadata['cellsize'] \
+                  for x in range(number_of_longitudes)]
+    latitudes = [bath_metadata['yllcorner']+y*bath_metadata['cellsize'] \
+                 for y in range(number_of_latitudes)]
+
+     # reverse order of lat, so the fist lat represents the first grid row
+    latitudes.reverse()
+
+    #print "latitudes - before _get_min_max_indexes",latitudes
+    kmin, kmax, lmin, lmax = _get_min_max_indexes(latitudes,longitudes,
+                                                 minlat=minlat, maxlat=maxlat,
+                                                 minlon=minlon, maxlon=maxlon)
+
+
+    bath_grid = bath_grid[kmin:kmax,lmin:lmax]
+    #print "bath_grid",bath_grid
+    latitudes = latitudes[kmin:kmax]
+    longitudes = longitudes[lmin:lmax]
+    number_of_latitudes = len(latitudes)
+    number_of_longitudes = len(longitudes)
+    number_of_times = len(os.listdir(elevation_dir))
+    number_of_points = number_of_latitudes*number_of_longitudes
+    number_of_volumes = (number_of_latitudes-1)*(number_of_longitudes-1)*2
+    #print "number_of_points",number_of_points
+
+    #Work out the times
+    if len(elevation_files) > 1:
+        # Assume: The time period is less than 24hrs.
+        time_period = (int(elevation_files[1][-3:]) - \
+                      int(elevation_files[0][-3:]))*60*60
+        times = [x*time_period for x in range(len(elevation_files))]
+    else:
+        times = [0.0]
+    #print "times", times
+    #print "number_of_latitudes", number_of_latitudes
+    #print "number_of_longitudes", number_of_longitudes
+    #print "number_of_times", number_of_times
+    #print "latitudes", latitudes
+    #print "longitudes", longitudes
+
+
+    if verbose:
+        print '------------------------------------------------'
+        print 'Statistics:'
+        print '  Extent (lat/lon):'
+        print '    lat in [%f, %f], len(lat) == %d'\
+              %(min(latitudes), max(latitudes),
+                len(latitudes))
+        print '    lon in [%f, %f], len(lon) == %d'\
+              %(min(longitudes), max(longitudes),
+                len(longitudes))
+        print '    t in [%f, %f], len(t) == %d'\
+              %(min(times), max(times), len(times))
+
+    ######### WRITE THE SWW FILE #############
+    # NetCDF file definition
+    outfile = NetCDFFile(sww_file, 'w')
+
+    #Create new file
+    outfile.institution = 'Geoscience Australia'
+    outfile.description = 'Converted from XXX'
+
+
+    #For sww compatibility
+    outfile.smoothing = 'Yes'
+    outfile.order = 1
+
+    #Start time in seconds since the epoch (midnight 1/1/1970)
+    outfile.starttime = starttime = times[0]
+
+
+    # dimension definitions
+    outfile.createDimension('number_of_volumes', number_of_volumes)
+
+    outfile.createDimension('number_of_vertices', 3)
+    outfile.createDimension('number_of_points', number_of_points)
+    outfile.createDimension('number_of_timesteps', number_of_times)
+
+    # variable definitions
+    outfile.createVariable('x', precision, ('number_of_points',))
+    outfile.createVariable('y', precision, ('number_of_points',))
+    outfile.createVariable('elevation', precision, ('number_of_points',))
+
+    #FIXME: Backwards compatibility
+    outfile.createVariable('z', precision, ('number_of_points',))
+    #################################
+
+    outfile.createVariable('volumes', Int, ('number_of_volumes',
+                                            'number_of_vertices'))
+
+    outfile.createVariable('time', precision,
+                           ('number_of_timesteps',))
+
+    outfile.createVariable('stage', precision,
+                           ('number_of_timesteps',
+                            'number_of_points'))
+
+    outfile.createVariable('xmomentum', precision,
+                           ('number_of_timesteps',
+                            'number_of_points'))
+
+    outfile.createVariable('ymomentum', precision,
+                           ('number_of_timesteps',
+                            'number_of_points'))
+
+    #Store
+    from anuga.coordinate_transforms.redfearn import redfearn
+    x = zeros(number_of_points, Float)  #Easting
+    y = zeros(number_of_points, Float)  #Northing
+
+    if verbose: print 'Making triangular grid'
+    #Get zone of 1st point.
+    refzone, _, _ = redfearn(latitudes[0],longitudes[0])
+
+    vertices = {}
+    i = 0
+    for k, lat in enumerate(latitudes):
+        for l, lon in enumerate(longitudes):
+
+            vertices[l,k] = i
+
+            zone, easting, northing = redfearn(lat,lon)
+
+            msg = 'Zone boundary crossed at longitude =', lon
+            #assert zone == refzone, msg
+            #print '%7.2f %7.2f %8.2f %8.2f' %(lon, lat, easting, northing)
+            x[i] = easting
+            y[i] = northing
+            i += 1
+
+
+    #Construct 2 triangles per 'rectangular' element
+    volumes = []
+    for l in range(number_of_longitudes-1):    #X direction
+        for k in range(number_of_latitudes-1): #Y direction
+            v1 = vertices[l,k+1]
+            v2 = vertices[l,k]
+            v3 = vertices[l+1,k+1]
+            v4 = vertices[l+1,k]
+
+            #Note, this is different to the ferrit2sww code
+            #since the order of the lats is reversed.
+            volumes.append([v1,v3,v2]) #Upper element
+            volumes.append([v4,v2,v3]) #Lower element
+
+    volumes = array(volumes)
+
+    geo_ref = Geo_reference(refzone,min(x),min(y))
+    geo_ref.write_NetCDF(outfile)
+
+    # This will put the geo ref in the middle
+    #geo_ref = Geo_reference(refzone,(max(x)+min(x))/2.0,(max(x)+min(y))/2.)
+
+
+    if verbose:
+        print '------------------------------------------------'
+        print 'More Statistics:'
+        print '  Extent (/lon):'
+        print '    x in [%f, %f], len(lat) == %d'\
+              %(min(x), max(x),
+                len(x))
+        print '    y in [%f, %f], len(lon) == %d'\
+              %(min(y), max(y),
+                len(y))
+        print 'geo_ref: ',geo_ref
+
+    z = resize(bath_grid,outfile.variables['z'][:].shape)
+    outfile.variables['x'][:] = x - geo_ref.get_xllcorner()
+    outfile.variables['y'][:] = y - geo_ref.get_yllcorner()
+    outfile.variables['z'][:] = z
+    outfile.variables['elevation'][:] = z  #FIXME HACK
+    outfile.variables['volumes'][:] = volumes.astype(Int32) #On Opteron 64
+
+    # do this to create an ok sww file.
+    #outfile.variables['time'][:] = [0]   #Store time relative
+    #outfile.variables['stage'] = z
+    # put the next line up in the code after outfile.order = 1
+    #number_of_times = 1
+
+    stage = outfile.variables['stage']
+    xmomentum = outfile.variables['xmomentum']
+    ymomentum = outfile.variables['ymomentum']
+
+    outfile.variables['time'][:] = times   #Store time relative
+
+    if verbose: print 'Converting quantities'
+    n = number_of_times
+    for j in range(number_of_times):
+        # load in files
+        elevation_meta, elevation_grid = \
+           _read_asc(elevation_dir + os.sep + elevation_files[j])
+
+        _, u_momentum_grid =  _read_asc(ucur_dir + os.sep + ucur_files[j])
+        _, v_momentum_grid =  _read_asc(vcur_dir + os.sep + vcur_files[j])
+
+        #print "elevation_grid",elevation_grid
+        #cut matrix to desired size
+        elevation_grid = elevation_grid[kmin:kmax,lmin:lmax]
+        u_momentum_grid = u_momentum_grid[kmin:kmax,lmin:lmax]
+        v_momentum_grid = v_momentum_grid[kmin:kmax,lmin:lmax]
+        #print "elevation_grid",elevation_grid
+        # handle missing values
+        missing = (elevation_grid == elevation_meta['NODATA_value'])
+        if sometrue (missing):
+            if fail_on_NaN:
+                msg = 'File %s contains missing values'\
+                      %(elevation_files[j])
+                raise DataMissingValuesError, msg
+            else:
+                elevation_grid = elevation_grid*(missing==0) + \
+                                 missing*elevation_NaN_filler
+
+
+        if verbose and j%((n+10)/10)==0: print '  Doing %d of %d' %(j, n)
+        i = 0
+        for k in range(number_of_latitudes):      #Y direction
+            for l in range(number_of_longitudes): #X direction
+                w = zscale*elevation_grid[k,l] + mean_stage
+                stage[j,i] = w
+                h = w - z[i]
+                xmomentum[j,i] = u_momentum_grid[k,l]*h
+                ymomentum[j,i] = v_momentum_grid[k,l]*h
+                i += 1
+    outfile.close()
+
+def _get_min_max_indexes(latitudes,longitudes,
+                        minlat=None, maxlat=None,
+                        minlon=None, maxlon=None):
+    """
+    return max, min indexes (for slicing) of the lat and long arrays to cover the area
+    specified with min/max lat/long
+
+    Think of the latitudes and longitudes describing a 2d surface.
+    The area returned is, if possible, just big enough to cover the
+    inputed max/min area. (This will not be possible if the max/min area
+    has a section outside of the latitudes/longitudes area.)
+
+    assume latitudess & longitudes are sorted,
+    long - from low to high (west to east, eg 148 - 151)
+    lat - from high to low (north to south, eg -35 - -38)
+    """
+
+    # reverse order of lat, so it's in ascending order
+    latitudes.reverse()
+    largest_lat_index = len(latitudes)-1
+    #Cut out a smaller extent.
+    if minlat == None:
+        lat_min_index = 0
+    else:
+        lat_min_index = searchsorted(latitudes, minlat)-1
+        if lat_min_index <0:
+            lat_min_index = 0
+
+
+    if maxlat == None:
+        lat_max_index = largest_lat_index #len(latitudes)
+    else:
+        lat_max_index = searchsorted(latitudes, maxlat)
+        if lat_max_index > largest_lat_index:
+            lat_max_index = largest_lat_index
+
+    if minlon == None:
+        lon_min_index = 0
+    else:
+        lon_min_index = searchsorted(longitudes, minlon)-1
+        if lon_min_index <0:
+            lon_min_index = 0
+
+    if maxlon == None:
+        lon_max_index = len(longitudes)
+    else:
+        lon_max_index = searchsorted(longitudes, maxlon)
+
+    #Take into account that the latitude list was reversed
+    latitudes.reverse() # Python passes by reference, need to swap back
+    lat_min_index, lat_max_index = largest_lat_index - lat_max_index , \
+                                   largest_lat_index - lat_min_index
+    lat_max_index = lat_max_index + 1 # taking into account how slicing works
+    lon_max_index = lon_max_index + 1 # taking into account how slicing works
+
+    return lat_min_index, lat_max_index, lon_min_index, lon_max_index
+
+
+def _read_asc(filename, verbose=False):
+    """Read esri file from the following ASCII format (.asc)
+
+    Example:
+
+    ncols         3121
+    nrows         1800
+    xllcorner     722000
+    yllcorner     5893000
+    cellsize      25
+    NODATA_value  -9999
+    138.3698 137.4194 136.5062 135.5558 ..........
+
+    """
+
+    datafile = open(filename)
+
+    if verbose: print 'Reading DEM from %s' %(filename)
+    lines = datafile.readlines()
+    datafile.close()
+
+    if verbose: print 'Got', len(lines), ' lines'
+
+    ncols = int(lines.pop(0).split()[1].strip())
+    nrows = int(lines.pop(0).split()[1].strip())
+    xllcorner = float(lines.pop(0).split()[1].strip())
+    yllcorner = float(lines.pop(0).split()[1].strip())
+    cellsize = float(lines.pop(0).split()[1].strip())
+    NODATA_value = float(lines.pop(0).split()[1].strip())
+
+    assert len(lines) == nrows
+
+    #Store data
+    grid = []
+
+    n = len(lines)
+    for i, line in enumerate(lines):
+        cells = line.split()
+        assert len(cells) == ncols
+        grid.append(array([float(x) for x in cells]))
+    grid = array(grid)
+
+    return {'xllcorner':xllcorner,
+            'yllcorner':yllcorner,
+            'cellsize':cellsize,
+            'NODATA_value':NODATA_value}, grid
+
+
+# FIXME (Ole): Is this doing anything at all? 
+def sww2timeseries(swwfile,
+                   gauge_filename,
+                   gauge_data_outname,
+                   quantity = None,
+                   time_min = None,
+                   time_max = None,
+                   verbose = False):
+
+    """Read SWW file and extract time series for prescribed quantities at
+    gauge locations.
+
+    The gauge locations are defined in gauge_filename. This file should be
+    in the form: gaugename, easting, northing, and should be stored in a
+    .csv or .xya file.
+
+    Time series data at the gauges can be written to file (for example,
+    Benfield requested raw data) with the default being no data written.
+
+    The parameter quantity must be the name of an existing quantity or
+    an expression involving existing quantities. The default is
+    'depth'.
+
+    The user can define a list of quantities. The possibilities are
+    the conserved quantitues of the shallow water wave equation and other
+    quantities which can be derived from those, i.e.
+    ['depth', 'xmomentum', 'ymomentum', 'momentum', 'velocity', 'bearing'].
+
+    Momentum is the absolute momentum, sqrt(xmomentum^2 + ymomentum^2).
+    Note, units of momentum are m^2/s and depth is m.
+
+    Velocity is absolute momentum divided by depth. (Confirming correct units:
+    vel = abs mom / depth = (m^2/s)/m = m/s.)
+
+    Bearing returns the angle of the velocity vector from North.
+
+    If time_min and time_max is given, output plotted in that time range.
+    The default is to plot the entire range of the time evident in sww file.
+
+    The export graphic format in 'png' and will be stored in the same
+    directory as the input file.
+    """
+
+    if quantity is None: quantity = 'depth'
+
+    # extract gauge locations from gauge file
+
+    # extract all quantities from swwfile (f = file_function)
+    if time_min is None: time_min = min(f.get_time())
+    if time_max is None: time_max = max(f.get_time())
+
+    # loop through appropriate range of time
+    # plot prescribed quantities and export data if requested
+
+    #if gauge_data_outname is None:
+
+    return
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    pass
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/data_manager_obsolete_stuff.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/data_manager_obsolete_stuff.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/data_manager_obsolete_stuff.py	(revision 3560)
@@ -0,0 +1,395 @@
+
+
+
+
+
+
+
+###############################################
+#OBSOLETE STUFF
+#Native checkpoint format.
+#Information needed to recreate a state is preserved
+#FIXME: Rethink and maybe use netcdf format
+def cpt_variable_writer(filename, t, v0, v1, v2):
+    """Store all conserved quantities to file
+    """
+
+    M, N = v0.shape
+
+    FN = create_filename(filename, 'cpt', M, t)
+    #print 'Writing to %s' %FN
+
+    fid = open(FN, 'w')
+    for i in range(M):
+        for j in range(N):
+            fid.write('%.16e ' %v0[i,j])
+        for j in range(N):
+            fid.write('%.16e ' %v1[i,j])
+        for j in range(N):
+            fid.write('%.16e ' %v2[i,j])
+
+        fid.write('\n')
+    fid.close()
+
+
+def cpt_variable_reader(filename, t, v0, v1, v2):
+    """Store all conserved quantities to file
+    """
+
+    M, N = v0.shape
+
+    FN = create_filename(filename, 'cpt', M, t)
+    #print 'Reading from %s' %FN
+
+    fid = open(FN)
+
+
+    for i in range(M):
+        values = fid.readline().split() #Get one line
+
+        for j in range(N):
+            v0[i,j] = float(values[j])
+            v1[i,j] = float(values[3+j])
+            v2[i,j] = float(values[6+j])
+
+    fid.close()
+
+def cpt_constant_writer(filename, X0, X1, X2, v0, v1, v2):
+    """Writes x,y,z,z,z coordinates of triangles constituting the bed
+    elevation.
+    FIXME: Not in use pt
+    """
+
+    M, N = v0.shape
+
+
+    print X0
+    import sys; sys.exit()
+    FN = create_filename(filename, 'cpt', M)
+    print 'Writing to %s' %FN
+
+    fid = open(FN, 'w')
+    for i in range(M):
+        for j in range(2):
+            fid.write('%.16e ' %X0[i,j])   #x, y
+        for j in range(N):
+            fid.write('%.16e ' %v0[i,j])       #z,z,z,
+
+        for j in range(2):
+            fid.write('%.16e ' %X1[i,j])   #x, y
+        for j in range(N):
+            fid.write('%.16e ' %v1[i,j])
+
+        for j in range(2):
+            fid.write('%.16e ' %X2[i,j])   #x, y
+        for j in range(N):
+            fid.write('%.16e ' %v2[i,j])
+
+        fid.write('\n')
+    fid.close()
+
+
+
+#Function for storing out to e.g. visualisation
+#FIXME: Do we want this?
+#FIXME: Not done yet for this version
+def dat_constant_writer(filename, X0, X1, X2, v0, v1, v2):
+    """Writes x,y,z coordinates of triangles constituting the bed elevation.
+    """
+
+    M, N = v0.shape
+
+    FN = create_filename(filename, 'dat', M)
+    #print 'Writing to %s' %FN
+
+    fid = open(FN, 'w')
+    for i in range(M):
+        for j in range(2):
+            fid.write('%f ' %X0[i,j])   #x, y
+        fid.write('%f ' %v0[i,0])       #z
+
+        for j in range(2):
+            fid.write('%f ' %X1[i,j])   #x, y
+        fid.write('%f ' %v1[i,0])       #z
+
+        for j in range(2):
+            fid.write('%f ' %X2[i,j])   #x, y
+        fid.write('%f ' %v2[i,0])       #z
+
+        fid.write('\n')
+    fid.close()
+
+
+
+def dat_variable_writer(filename, t, v0, v1, v2):
+    """Store water height to file
+    """
+
+    M, N = v0.shape
+
+    FN = create_filename(filename, 'dat', M, t)
+    #print 'Writing to %s' %FN
+
+    fid = open(FN, 'w')
+    for i in range(M):
+        fid.write('%.4f ' %v0[i,0])
+        fid.write('%.4f ' %v1[i,0])
+        fid.write('%.4f ' %v2[i,0])
+
+        fid.write('\n')
+    fid.close()
+
+
+def read_sww(filename):
+    """Read sww Net CDF file containing Shallow Water Wave simulation
+
+    The integer array volumes is of shape Nx3 where N is the number of
+    triangles in the mesh.
+
+    Each entry in volumes is an index into the x,y arrays (the location).
+
+    Quantities stage, elevation, xmomentum and ymomentum are all in arrays of dimensions
+    number_of_timesteps, number_of_points.
+
+    The momentum is not always stored.
+
+    """
+    from Scientific.IO.NetCDF import NetCDFFile
+    print 'Reading from ', filename
+    fid = NetCDFFile(filename, 'r')    #Open existing file for read
+#latitude, longitude
+    # Get the variables as Numeric arrays
+    x = fid.variables['x']             #x-coordinates of vertices
+    y = fid.variables['y']             #y-coordinates of vertices
+    z = fid.variables['elevation']     #Elevation
+    time = fid.variables['time']       #Timesteps
+    stage = fid.variables['stage']     #Water level
+    #xmomentum = fid.variables['xmomentum']   #Momentum in the x-direction
+    #ymomentum = fid.variables['ymomentum']   #Momentum in the y-direction
+
+    volumes = fid.variables['volumes'] #Connectivity
+
+    #FIXME (Ole): What is this?
+    #             Why isn't anything returned?
+    #             Where's the unit test?
+
+
+
+def sww2asc_obsolete(basename_in, basename_out = None,
+            quantity = None,
+            timestep = None,
+            reduction = None,
+            cellsize = 10,
+            verbose = False,
+            origin = None):
+    """Read SWW file and convert to Digitial Elevation model format (.asc)
+
+    Example:
+
+    ncols         3121
+    nrows         1800
+    xllcorner     722000
+    yllcorner     5893000
+    cellsize      25
+    NODATA_value  -9999
+    138.3698 137.4194 136.5062 135.5558 ..........
+
+    Also write accompanying file with same basename_in but extension .prj
+    used to fix the UTM zone, datum, false northings and eastings.
+
+    The prj format is assumed to be as
+
+    Projection    UTM
+    Zone          56
+    Datum         WGS84
+    Zunits        NO
+    Units         METERS
+    Spheroid      WGS84
+    Xshift        0.0000000000
+    Yshift        10000000.0000000000
+    Parameters
+
+
+    if quantity is given, out values from quantity otherwise default to
+    elevation
+
+    if timestep (an index) is given, output quantity at that timestep
+
+    if reduction is given use that to reduce quantity over all timesteps.
+
+    """
+    from Numeric import array, Float, concatenate, NewAxis, zeros,\
+         sometrue
+    from anuga.utilities.polygon import inside_polygon
+
+    #FIXME: Should be variable
+    datum = 'WGS84'
+    false_easting = 500000
+    false_northing = 10000000
+
+    if quantity is None:
+        quantity = 'elevation'
+
+    if reduction is None:
+        reduction = max
+
+    if basename_out is None:
+        basename_out = basename_in + '_%s' %quantity
+
+    swwfile = basename_in + '.sww'
+    ascfile = basename_out + '.asc'
+    prjfile = basename_out + '.prj'
+
+
+    if verbose: print 'Reading from %s' %swwfile
+    #Read sww file
+    from Scientific.IO.NetCDF import NetCDFFile
+    fid = NetCDFFile(swwfile)
+
+    #Get extent and reference
+    x = fid.variables['x'][:]
+    y = fid.variables['y'][:]
+    volumes = fid.variables['volumes'][:]
+
+    ymin = min(y); ymax = max(y)
+    xmin = min(x); xmax = max(x)
+
+    number_of_timesteps = fid.dimensions['number_of_timesteps']
+    number_of_points = fid.dimensions['number_of_points']
+    if origin is None:
+
+        #Get geo_reference
+        #sww files don't have to have a geo_ref
+        try:
+            geo_reference = Geo_reference(NetCDFObject=fid)
+        except AttributeError, e:
+            geo_reference = Geo_reference() #Default georef object
+
+        xllcorner = geo_reference.get_xllcorner()
+        yllcorner = geo_reference.get_yllcorner()
+        zone = geo_reference.get_zone()
+    else:
+        zone = origin[0]
+        xllcorner = origin[1]
+        yllcorner = origin[2]
+
+
+    #Get quantity and reduce if applicable
+    if verbose: print 'Reading quantity %s' %quantity
+
+    if quantity.lower() == 'depth':
+        q = fid.variables['stage'][:] - fid.variables['elevation'][:]
+    else:
+        q = fid.variables[quantity][:]
+
+
+    if len(q.shape) == 2:
+        if verbose: print 'Reducing quantity %s' %quantity
+        q_reduced = zeros( number_of_points, Float )
+
+        for k in range(number_of_points):
+            q_reduced[k] = reduction( q[:,k] )
+
+        q = q_reduced
+
+    #Now q has dimension: number_of_points
+
+    #Create grid and update xll/yll corner and x,y
+    if verbose: print 'Creating grid'
+    ncols = int((xmax-xmin)/cellsize)+1
+    nrows = int((ymax-ymin)/cellsize)+1
+
+    newxllcorner = xmin+xllcorner
+    newyllcorner = ymin+yllcorner
+
+    x = x+xllcorner-newxllcorner
+    y = y+yllcorner-newyllcorner
+
+    vertex_points = concatenate ((x[:, NewAxis] ,y[:, NewAxis]), axis = 1)
+    assert len(vertex_points.shape) == 2
+
+
+    from Numeric import zeros, Float
+    grid_points = zeros ( (ncols*nrows, 2), Float )
+
+
+    for i in xrange(nrows):
+        yg = i*cellsize
+        for j in xrange(ncols):
+            xg = j*cellsize
+            k = i*ncols + j
+
+            grid_points[k,0] = xg
+            grid_points[k,1] = yg
+
+    #Interpolate
+    from least_squares import Interpolation
+
+
+    #FIXME: This should be done with precrop = True, otherwise it'll
+    #take forever. With expand_search  set to False, some grid points might
+    #miss out....
+
+    interp = Interpolation(vertex_points, volumes, grid_points, alpha=0.0,
+                           precrop = False, expand_search = True,
+                           verbose = verbose)
+
+    #Interpolate using quantity values
+    if verbose: print 'Interpolating'
+    grid_values = interp.interpolate(q).flat
+
+    #Write
+    #Write prj file
+    if verbose: print 'Writing %s' %prjfile
+    prjid = open(prjfile, 'w')
+    prjid.write('Projection    %s\n' %'UTM')
+    prjid.write('Zone          %d\n' %zone)
+    prjid.write('Datum         %s\n' %datum)
+    prjid.write('Zunits        NO\n')
+    prjid.write('Units         METERS\n')
+    prjid.write('Spheroid      %s\n' %datum)
+    prjid.write('Xshift        %d\n' %false_easting)
+    prjid.write('Yshift        %d\n' %false_northing)
+    prjid.write('Parameters\n')
+    prjid.close()
+
+
+
+    if verbose: print 'Writing %s' %ascfile
+    NODATA_value = -9999
+
+    ascid = open(ascfile, 'w')
+
+    ascid.write('ncols         %d\n' %ncols)
+    ascid.write('nrows         %d\n' %nrows)
+    ascid.write('xllcorner     %d\n' %newxllcorner)
+    ascid.write('yllcorner     %d\n' %newyllcorner)
+    ascid.write('cellsize      %f\n' %cellsize)
+    ascid.write('NODATA_value  %d\n' %NODATA_value)
+
+
+    #Get bounding polygon from mesh
+    P = interp.mesh.get_boundary_polygon()
+    inside_indices = inside_polygon(grid_points, P)
+
+    for i in range(nrows):
+        if verbose and i%((nrows+10)/10)==0:
+            print 'Doing row %d of %d' %(i, nrows)
+
+        for j in range(ncols):
+            index = (nrows-i-1)*ncols+j
+
+            if sometrue(inside_indices == index):
+                ascid.write('%f ' %grid_values[index])
+            else:
+                ascid.write('%d ' %NODATA_value)
+
+        ascid.write('\n')
+
+    #Close
+    ascid.close()
+    fid.close()
+
+#********************
+#*** END OF OBSOLETE FUNCTIONS
+#***************
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/doit.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/doit.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/doit.py	(revision 3560)
@@ -0,0 +1,13 @@
+import os
+
+#Clean up
+
+for file in os.listdir('.'):
+    if file[-1] == '~':
+    	os.remove(file)
+
+
+#os.system('python compile.py')
+os.system('python test_all.py')
+os.system('python run_profile.py')
+os.system('python show_balanced_limiters.py')
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/domain.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/domain.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/domain.py	(revision 3560)
@@ -0,0 +1,956 @@
+"""Class Domain - 2D triangular domains for finite-volume computations of
+   conservation laws.
+
+
+   Copyright 2004
+   Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+   Geoscience Australia
+"""
+
+from anuga.abstract_2d_finite_volumes.neighbour_mesh import Mesh
+from anuga.abstract_2d_finite_volumes.generic_boundary_conditions import Boundary
+from anuga.abstract_2d_finite_volumes.generic_boundary_conditions import File_boundary
+from anuga.abstract_2d_finite_volumes.generic_boundary_conditions import Dirichlet_boundary
+from anuga.abstract_2d_finite_volumes.generic_boundary_conditions import Time_boundary
+from anuga.abstract_2d_finite_volumes.generic_boundary_conditions import Transmissive_boundary
+from anuga.abstract_2d_finite_volumes.pmesh2domain import pmesh_to_domain
+from anuga.abstract_2d_finite_volumes.region import Set_region as region_set_region
+
+import types
+
+class Domain(Mesh):
+
+
+    def __init__(self,
+                 source=None,
+                 triangles=None,
+                 boundary=None,
+                 conserved_quantities=None,
+                 other_quantities=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,
+                 processor=0,
+                 numproc=1):
+
+
+        """Instantiate generic computational Domain.
+
+        Input:
+          source:    Either a mesh filename or coordinates of mesh vertices.
+                     If it is a filename values specified for triangles will
+                     be overridden.
+          triangles: Mesh connectivity (see mesh.py for more information)
+          boundary:  See mesh.py for more information
+
+          conserved_quantities: List of quantity names entering the
+                                conservation equations
+          other_quantities:     List of other quantity names
+
+          tagged_elements:
+          ...
+
+
+        """
+
+        # Determine whether source is a mesh filename or coordinates
+        if type(source) == types.StringType:
+            mesh_filename = source
+        else:
+            coordinates = source
+
+
+        # In case a filename has been specified, extract content
+        if mesh_filename is not None:
+            coordinates, triangles, boundary, vertex_quantity_dict, \
+                         tagged_elements, geo_reference = \
+                         pmesh_to_domain(file_name=mesh_filename,
+                                         use_cache=use_cache,
+                                         verbose=verbose)
+
+
+        # Initialise underlying mesh structure
+        Mesh.__init__(self, coordinates, triangles, boundary,
+                      tagged_elements, geo_reference, use_inscribed_circle,
+                      verbose=verbose)
+
+        if verbose: print 'Initialising Domain'
+        from Numeric import zeros, Float, Int, ones
+        from quantity import Quantity, Conserved_quantity
+
+        # List of quantity names entering
+        # the conservation equations
+        if conserved_quantities is None:
+            self.conserved_quantities = []
+        else:
+            self.conserved_quantities = conserved_quantities
+
+        # List of other quantity names
+        if other_quantities is None:
+            self.other_quantities = []
+        else:
+            self.other_quantities = other_quantities
+
+
+        #Build dictionary of Quantity instances keyed by quantity names
+        self.quantities = {}
+
+        #FIXME: remove later - maybe OK, though....
+        for name in self.conserved_quantities:
+            self.quantities[name] = Conserved_quantity(self)
+        for name in self.other_quantities:
+            self.quantities[name] = Quantity(self)
+
+        #Create an empty list for explicit forcing terms
+        self.forcing_terms = []
+
+        #Setup the ghost cell communication
+        if full_send_dict is None:
+            self.full_send_dict = {}
+        else:
+            self.full_send_dict  = full_send_dict
+
+        # List of other quantity names
+        if ghost_recv_dict  is None:
+            self.ghost_recv_dict  = {}
+        else:
+            self.ghost_recv_dict  = ghost_recv_dict
+
+        self.processor = processor
+        self.numproc   = numproc
+
+        # Setup Communication Buffers
+
+        if verbose: print 'Domain: Set up communication buffers (parallel)'
+        self.nsys = len(self.conserved_quantities)
+        for key in self.full_send_dict:
+            buffer_shape = self.full_send_dict[key][0].shape[0]
+            self.full_send_dict[key].append(zeros( (buffer_shape,self.nsys) ,Float))
+
+
+        for key in self.ghost_recv_dict:
+            buffer_shape = self.ghost_recv_dict[key][0].shape[0]
+            self.ghost_recv_dict[key].append(zeros( (buffer_shape,self.nsys) ,Float))
+
+
+        # Setup cell full flag
+        # =1 for full
+        # =0 for ghost
+        N=self.number_of_elements
+        self.tri_full_flag = ones(N, Int)
+        for i in self.ghost_recv_dict.keys():
+            for id in self.ghost_recv_dict[i][0]:
+                self.tri_full_flag[id] = 0
+
+
+        #Defaults
+        from anuga.config import max_smallsteps, beta_w, beta_h, epsilon, CFL
+        self.beta_w = beta_w
+        self.beta_h = beta_h
+        self.epsilon = epsilon
+
+        #FIXME: Maybe have separate orders for h-limiter and w-limiter?
+        #Or maybe get rid of order altogether and use beta_w and beta_h
+        self.set_default_order(1)
+        #self.default_order = 1
+        #self.order = self.default_order
+
+        self.smallsteps = 0
+        self.max_smallsteps = max_smallsteps
+        self.number_of_steps = 0
+        self.number_of_first_order_steps = 0
+        self.CFL = CFL
+
+        #Model time
+        self.time = 0.0
+        self.finaltime = None
+        self.min_timestep = self.max_timestep = 0.0
+        self.starttime = 0 #Physical starttime if any (0 is 1 Jan 1970 00:00:00)
+
+        ######OBSOLETE
+        #Origin in UTM coordinates
+        #FIXME: This should be set if read by a msh file
+        #self.zone = zone
+        #self.xllcorner = xllcorner
+        #self.yllcorner = yllcorner
+
+
+        #Checkpointing and storage
+        from anuga.config import default_datadir
+        self.datadir = default_datadir
+        self.filename = 'domain'
+        self.checkpoint = False
+
+        #MH310505 To avoid calculating the flux across each edge twice, keep an integer (boolean) array,
+        #to be used during the flux calculation
+        N=self.number_of_elements
+        self.already_computed_flux = zeros((N, 3), Int)
+
+        if mesh_filename is not None:
+            # If the mesh file passed any quantity values
+            # , initialise with these values.
+            if verbose: print 'Domain: Initialising quantity values'
+            self.set_quantity_vertices_dict(vertex_quantity_dict)
+
+
+        if verbose: print 'Domain: Done'
+
+
+
+
+    def set_default_order(self, n):
+        """Set default (spatial) order to either 1 or 2
+        """
+
+        msg = 'Default order must be either 1 or 2. I got %s' %n
+        assert n in [1,2], msg
+
+        self.default_order = n
+        self.order = self.default_order
+
+
+    #Public interface to Domain
+    def get_conserved_quantities(self, vol_id, vertex=None, edge=None):
+        """Get conserved quantities at volume vol_id
+
+        If vertex is specified use it as index for vertex values
+        If edge is specified use it as index for edge values
+        If neither are specified use centroid values
+        If both are specified an exeception is raised
+
+        Return value: Vector of length == number_of_conserved quantities
+
+        """
+
+        from Numeric import zeros, Float
+
+        if not (vertex is None or edge is None):
+            msg = 'Values for both vertex and edge was specified.'
+            msg += 'Only one (or none) is allowed.'
+            raise msg
+
+        q = zeros( len(self.conserved_quantities), Float)
+
+        for i, name in enumerate(self.conserved_quantities):
+            Q = self.quantities[name]
+            if vertex is not None:
+                q[i] = Q.vertex_values[vol_id, vertex]
+            elif edge is not None:
+                q[i] = Q.edge_values[vol_id, edge]
+            else:
+                q[i] = Q.centroid_values[vol_id]
+
+        return q
+
+    def set_time(self, time=0.0):
+        """Set the model time (seconds)"""
+
+        self.time = time
+
+    def set_quantity_vertices_dict(self, quantity_dict):
+        """Set values for named quantities.
+        The index is the quantity
+
+        name: Name of quantity
+        X: Compatible list, Numeric array, const or function (see below)
+
+        The values will be stored in elements following their
+        internal ordering.
+
+        """
+        for key in quantity_dict.keys():
+            self.set_quantity(key, quantity_dict[key], location='vertices')
+
+
+    def set_quantity(self, name, *args, **kwargs):
+        """Set values for named quantity
+
+
+        One keyword argument is documented here:
+        expression = None, # Arbitrary expression
+
+        expression:
+          Arbitrary expression involving quantity names
+
+        See Quantity.set_values for further documentation.
+        """
+
+        #FIXME (Ole): Allow new quantities here
+        #from quantity import Quantity, Conserved_quantity
+        #Create appropriate quantity object
+        ##if name in self.conserved_quantities:
+        ##    self.quantities[name] = Conserved_quantity(self)
+        ##else:
+        ##    self.quantities[name] = Quantity(self)
+
+
+        #Do the expression stuff
+        if kwargs.has_key('expression'):
+            expression = kwargs['expression']
+            del kwargs['expression']
+
+            Q = self.create_quantity_from_expression(expression)
+            kwargs['quantity'] = Q
+
+        #Assign values
+        self.quantities[name].set_values(*args, **kwargs)
+
+
+    def get_quantity(self, name, location='vertices', indices = None):
+        """Get quantity object.
+
+        name: Name of quantity
+
+        See methods inside the quantity object for more options
+        """
+
+        return self.quantities[name] #.get_values( location, indices = indices)
+
+
+    def get_quantity_object(self, name):
+        """Get object for named quantity
+
+        name: Name of quantity
+
+        FIXME: Obsolete
+        """
+
+        print 'get_quantity_object has been deprecated. Please use get_quantity'
+        return self.quantities[name]
+
+
+    def create_quantity_from_expression(self, expression):
+        """Create new quantity from other quantities using arbitrary expression
+
+        Combine existing quantities in domain using expression and return
+        result as a new quantity.
+
+        Note, the new quantity could e.g. be used in set_quantity
+
+        Valid expressions are limited to operators defined in class Quantity
+
+        Example:
+
+
+        """
+
+        from anuga.abstract_2d_finite_volumes.util import apply_expression_to_dictionary
+        return apply_expression_to_dictionary(expression, self.quantities)
+
+
+
+
+    def set_boundary(self, boundary_map):
+        """Associate boundary objects with tagged boundary segments.
+
+        Input boundary_map is a dictionary of boundary objects keyed
+        by symbolic tags to matched against tags in the internal dictionary
+        self.boundary.
+
+        As result one pointer to a boundary object is stored for each vertex
+        in the list self.boundary_objects.
+        More entries may point to the same boundary object
+
+        Schematically the mapping is from two dictionaries to one list
+        where the index is used as pointer to the boundary_values arrays
+        within each quantity.
+
+        self.boundary:          (vol_id, edge_id): tag
+        boundary_map (input):   tag: boundary_object
+        ----------------------------------------------
+        self.boundary_objects:  ((vol_id, edge_id), boundary_object)
+
+
+        Pre-condition:
+          self.boundary has been built.
+
+        Post-condition:
+          self.boundary_objects is built
+
+        If a tag from the domain doesn't appear in the input dictionary an
+        exception is raised.
+        However, if a tag is not used to the domain, no error is thrown.
+        FIXME: This would lead to implementation of a
+        default boundary condition
+
+        Note: If a segment is listed in the boundary dictionary and if it is
+        not None, it *will* become a boundary -
+        even if there is a neighbouring triangle.
+        This would be the case for internal boundaries
+
+        Boundary objects that are None will be skipped.
+
+        FIXME: If set_boundary is called multiple times and if Boundary
+        object is changed into None, the neighbour structure will not be
+        restored!!!
+
+
+        """
+
+        self.boundary_objects = []
+        self.boundary_map = boundary_map  #Store for use with eg. boundary_stats.
+
+        #FIXME: Try to remove the sorting and fix test_mesh.py
+        x = self.boundary.keys()
+        x.sort()
+
+        #Loop through edges that lie on the boundary and associate them with
+        #callable boundary objects depending on their tags
+        for k, (vol_id, edge_id) in enumerate(x):
+            tag = self.boundary[ (vol_id, edge_id) ]
+
+            if boundary_map.has_key(tag):
+                B = boundary_map[tag]  #Get callable boundary object
+
+                if B is not None:
+                    self.boundary_objects.append( ((vol_id, edge_id), B) )
+                    self.neighbours[vol_id, edge_id] = -len(self.boundary_objects)
+                else:
+                    pass
+                    #FIXME: Check and perhaps fix neighbour structure
+
+
+            else:
+                msg = 'ERROR (domain.py): Tag "%s" has not been ' %tag
+                msg += 'bound to a boundary object.\n'
+                msg += 'All boundary tags defined in domain must appear '
+                msg += 'in the supplied dictionary.\n'
+                msg += 'The tags are: %s' %self.get_boundary_tags()
+                raise msg
+
+
+    def set_region(self, *args, **kwargs):
+        """
+        This method is used to set quantities based on a regional tag.
+        
+        It is most often called with the following parameters;
+        (self, tag, quantity, X, location='vertices')
+        tag: the name of the regional tag used to specify the region 
+        quantity: Name of quantity to change
+        X: const or function - how the quantity is changed
+        location: Where values are to be stored.
+            Permissible options are: vertices, centroid and unique vertices
+
+        A callable region class or a list of callable region classes
+        can also be passed into this function.
+        """
+        #print "*args", args
+        #print "**kwargs", kwargs 
+        if len(args) == 1:
+            self._set_region(*args, **kwargs)
+        else:
+            #Assume it is arguments for the region.set_region function
+            func = region_set_region(*args, **kwargs)
+            self._set_region(func)
+            
+        
+    def _set_region(self, functions):
+        # The order of functions in the list is used.
+        if type(functions) not in [types.ListType,types.TupleType]:
+            functions = [functions]
+        for function in functions:
+            for tag in self.tagged_elements.keys():
+                function(tag, self.tagged_elements[tag], self)
+
+
+    #MISC
+    def check_integrity(self):
+        Mesh.check_integrity(self)
+
+        for quantity in self.conserved_quantities:
+            msg = 'Conserved quantities must be a subset of all quantities'
+            assert quantity in self.quantities, msg
+
+        ##assert hasattr(self, 'boundary_objects')
+
+    def write_time(self):
+        print self.timestepping_statistics()
+
+        #Old version
+        #if self.min_timestep == self.max_timestep:
+        #    print 'Time = %.4f, delta t = %.8f, steps=%d (%d)'\
+        #          %(self.time, self.min_timestep, self.number_of_steps,
+        #            self.number_of_first_order_steps)
+        #elif self.min_timestep > self.max_timestep:
+        #    print 'Time = %.4f, steps=%d (%d)'\
+        #          %(self.time, self.number_of_steps,
+        #            self.number_of_first_order_steps)
+        #else:
+        #    print 'Time = %.4f, delta t in [%.8f, %.8f], steps=%d (%d)'\
+        #          %(self.time, self.min_timestep,
+        #            self.max_timestep, self.number_of_steps,
+        #            self.number_of_first_order_steps)
+
+    def timestepping_statistics(self):
+        """Return string with time stepping statistics for printing or logging
+        """
+
+        msg = ''
+        if self.min_timestep == self.max_timestep:
+            msg += 'Time = %.4f, delta t = %.8f, steps=%d (%d)'\
+                   %(self.time, self.min_timestep, self.number_of_steps,
+                     self.number_of_first_order_steps)
+        elif self.min_timestep > self.max_timestep:
+            msg += 'Time = %.4f, steps=%d (%d)'\
+                   %(self.time, self.number_of_steps,
+                     self.number_of_first_order_steps)
+        else:
+            msg += 'Time = %.4f, delta t in [%.8f, %.8f], steps=%d (%d)'\
+                   %(self.time, self.min_timestep,
+                     self.max_timestep, self.number_of_steps,
+                     self.number_of_first_order_steps)
+
+        return msg
+
+
+    def write_boundary_statistics(self, quantities = None, tags = None):
+        print self.boundary_statistics(quantities, tags)
+
+    def boundary_statistics(self, quantities = None, tags = None):
+        """Output statistics about boundary forcing at each timestep
+
+
+        Input:
+          quantities: either None, a string or a list of strings naming the quantities to be reported
+          tags:       either None, a string or a list of strings naming the tags to be reported
+
+
+        Example output:
+        Tag 'wall':
+            stage in [2, 5.5]
+            xmomentum in []
+            ymomentum in []
+        Tag 'ocean'
+
+
+        If quantities are specified only report on those. Otherwise take all conserved quantities.
+        If tags are specified only report on those, otherwise take all tags.
+
+        """
+
+        #Input checks
+        import types, string
+
+        if quantities is None:
+            quantities = self.conserved_quantities
+        elif type(quantities) == types.StringType:
+            quantities = [quantities] #Turn it into a list
+
+        msg = 'Keyword argument quantities must be either None, '
+        msg += 'string or list. I got %s' %str(quantities)
+        assert type(quantities) == types.ListType, msg
+
+
+        if tags is None:
+            tags = self.get_boundary_tags()
+        elif type(tags) == types.StringType:
+            tags = [tags] #Turn it into a list
+
+        msg = 'Keyword argument tags must be either None, '
+        msg += 'string or list. I got %s' %str(tags)
+        assert type(tags) == types.ListType, msg
+
+        #Determine width of longest quantity name (for cosmetic purposes)
+        maxwidth = 0
+        for name in quantities:
+            w = len(name)
+            if w > maxwidth:
+                maxwidth = w
+
+        #Output stats
+        msg = 'Boundary values at time %.4f:\n' %self.time
+        for tag in tags:
+            msg += '    %s:\n' %tag
+
+            for name in quantities:
+                q = self.quantities[name]
+
+                #Find range of boundary values for tag and q
+                maxval = minval = None
+                for i, ((vol_id, edge_id), B) in\
+                        enumerate(self.boundary_objects):
+                    if self.boundary[(vol_id, edge_id)] == tag:
+                        v = q.boundary_values[i]
+                        if minval is None or v < minval: minval = v
+                        if maxval is None or v > maxval: maxval = v
+
+                if minval is None or maxval is None:
+                    msg += '        Sorry no information available about' +\
+                           ' tag %s and quantity %s\n' %(tag, name)
+                else:
+                    msg += '        %s in [%12.8f, %12.8f]\n'\
+                           %(string.ljust(name, maxwidth), minval, maxval)
+
+
+        return msg
+
+
+    def get_name(self):
+        return self.filename
+
+    def set_name(self, name):
+        self.filename = name
+
+    def get_datadir(self):
+        return self.datadir
+
+    def set_datadir(self, name):
+        self.datadir = name
+
+
+
+    #def set_defaults(self):
+    #    """Set default values for uninitialised quantities.
+    #    Should be overridden or specialised by specific modules
+    #    """#
+    #
+    #    for name in self.conserved_quantities + self.other_quantities:
+    #        self.set_quantity(name, 0.0)
+
+
+    ###########################
+    #Main components of evolve
+
+    def evolve(self,
+               yieldstep = None,
+               finaltime = None,
+               duration = None,
+               skip_initial_step = False):
+        """Evolve model through time starting from self.starttime.
+
+
+        yieldstep: Interval between yields where results are stored,
+                   statistics written and domain inspected or
+                   possibly modified. If omitted the internal predefined
+                   max timestep is used.
+                   Internally, smaller timesteps may be taken.
+
+        duration: Duration of simulation
+
+        finaltime: Time where simulation should end
+
+        If both duration and finaltime are given an exception is thrown.
+
+
+        skip_initial_step: Boolean flag that decides whether the first
+        yield step is skipped or not. This is useful for example to avoid
+        duplicate steps when multiple evolve processes are dove tailed.
+
+
+        Evolve is implemented as a generator and is to be called as such, e.g.
+
+        for t in domain.evolve(yieldstep, finaltime):
+            <Do something with domain and t>
+
+
+        All times are given in seconds
+
+        """
+
+        from anuga.config import min_timestep, max_timestep, epsilon
+
+        #FIXME: Maybe lump into a larger check prior to evolving
+        msg = 'Boundary tags must be bound to boundary objects before evolving system, '
+        msg += 'e.g. using the method set_boundary.\n'
+        msg += 'This system has the boundary tags %s '\
+               %self.get_boundary_tags()
+        assert hasattr(self, 'boundary_objects'), msg
+
+        ##self.set_defaults()
+
+        if yieldstep is None:
+            yieldstep = max_timestep
+        else:
+            yieldstep = float(yieldstep)
+
+        self.order = self.default_order
+
+
+        if finaltime is not None and duration is not None:
+            print 'F', finaltime, duration
+            msg = 'Only one of finaltime and duration may be specified'
+            raise msg
+        else:
+            if finaltime is not None:
+                self.finaltime = float(finaltime)
+            if duration is not None:
+                self.finaltime = self.starttime + float(duration)
+
+
+
+
+        self.yieldtime = 0.0 #Time between 'yields'
+
+        #Initialise interval of timestep sizes (for reporting only)
+        self.min_timestep = max_timestep
+        self.max_timestep = min_timestep
+        self.number_of_steps = 0
+        self.number_of_first_order_steps = 0
+
+        #update ghosts
+        self.update_ghosts()
+
+        #Initial update of vertex and edge values
+        self.distribute_to_vertices_and_edges()
+
+        #Initial update boundary values
+        self.update_boundary()
+
+        #Or maybe restore from latest checkpoint
+        if self.checkpoint is True:
+            self.goto_latest_checkpoint()
+
+        if skip_initial_step is False:
+            yield(self.time)  #Yield initial values
+
+        while True:
+
+            #Compute fluxes across each element edge
+            self.compute_fluxes()
+
+            #Update timestep to fit yieldstep and finaltime
+            self.update_timestep(yieldstep, finaltime)
+
+            #Update conserved quantities
+            self.update_conserved_quantities()
+
+            #update ghosts
+            self.update_ghosts()
+
+            #Update vertex and edge values
+            self.distribute_to_vertices_and_edges()
+
+            #Update boundary values
+            self.update_boundary()
+
+            #Update time
+            self.time += self.timestep
+            self.yieldtime += self.timestep
+            self.number_of_steps += 1
+            if self.order == 1:
+                self.number_of_first_order_steps += 1
+
+            #Yield results
+	    if finaltime is not None and self.time >= finaltime:
+
+		if self.time > finaltime:
+  		    #FIXME (Ole, 30 April 2006): Do we need this check?
+		    print 'WARNING (domain.py): time overshot finaltime. Contact Ole.Nielsen@ga.gov.au'
+                    self.time = finaltime
+
+                # Yield final time and stop
+                yield(self.time)
+                break
+
+
+	    if self.yieldtime >= yieldstep:
+                # Yield (intermediate) time and allow inspection of domain
+
+                if self.checkpoint is True:
+                    self.store_checkpoint()
+                    self.delete_old_checkpoints()
+
+                #Pass control on to outer loop for more specific actions
+                yield(self.time)
+
+                # Reinitialise
+                self.yieldtime = 0.0
+                self.min_timestep = max_timestep
+                self.max_timestep = min_timestep
+                self.number_of_steps = 0
+                self.number_of_first_order_steps = 0
+
+
+    def evolve_to_end(self, finaltime = 1.0):
+        """Iterate evolve all the way to the end
+        """
+
+        for _ in self.evolve(yieldstep=None, finaltime=finaltime):
+            pass
+
+
+
+    def update_boundary(self):
+        """Go through list of boundary objects and update boundary values
+        for all conserved quantities on boundary.
+        """
+
+        #FIXME: Update only those that change (if that can be worked out)
+        #FIXME: Boundary objects should not include ghost nodes.
+        for i, ((vol_id, edge_id), B) in enumerate(self.boundary_objects):
+	    if B is None:
+	        print 'WARNING: Ignored boundary segment %d (None)'
+	    else:
+                q = B.evaluate(vol_id, edge_id)
+
+                for j, name in enumerate(self.conserved_quantities):
+                    Q = self.quantities[name]
+                    Q.boundary_values[i] = q[j]
+
+
+    def compute_fluxes(self):
+        msg = 'Method compute_fluxes must be overridden by Domain subclass'
+        raise msg
+
+
+    def update_timestep(self, yieldstep, finaltime):
+
+        from anuga.config import min_timestep, max_timestep
+
+        # self.timestep is calculated from speed of characteristics
+        # Apply CFL condition here
+        timestep = min(self.CFL*self.timestep,max_timestep)
+
+        #Record maximal and minimal values of timestep for reporting
+        self.max_timestep = max(timestep, self.max_timestep)
+        self.min_timestep = min(timestep, self.min_timestep)
+
+        #Protect against degenerate time steps
+        if timestep < min_timestep:
+
+            #Number of consecutive small steps taken b4 taking action
+            self.smallsteps += 1
+
+            if self.smallsteps > self.max_smallsteps:
+                self.smallsteps = 0 #Reset
+
+                if self.order == 1:
+                    msg = 'WARNING: Too small timestep %.16f reached '\
+                          %timestep
+                    msg += 'even after %d steps of 1 order scheme'\
+                           %self.max_smallsteps
+                    print msg
+                    timestep = min_timestep  #Try enforcing min_step
+
+                    #raise msg
+                else:
+                    #Try to overcome situation by switching to 1 order
+                    self.order = 1
+
+        else:
+            self.smallsteps = 0
+            if self.order == 1 and self.default_order == 2:
+                self.order = 2
+
+
+        #Ensure that final time is not exceeded
+        if finaltime is not None and self.time + timestep > finaltime:
+            timestep = finaltime-self.time
+
+        #Ensure that model time is aligned with yieldsteps
+        if self.yieldtime + timestep > yieldstep:
+            timestep = yieldstep-self.yieldtime
+
+        self.timestep = timestep
+
+
+
+    def compute_forcing_terms(self):
+        """If there are any forcing functions driving the system
+        they should be defined in Domain subclass and appended to
+        the list self.forcing_terms
+        """
+
+        for f in self.forcing_terms:
+            f(self)
+
+
+
+    def update_conserved_quantities(self):
+        """Update vectors of conserved quantities using previously
+        computed fluxes specified forcing functions.
+        """
+
+        from Numeric import ones, sum, equal, Float
+
+        N = self.number_of_elements
+        d = len(self.conserved_quantities)
+
+        timestep = self.timestep
+
+        #Compute forcing terms
+        self.compute_forcing_terms()
+
+        #Update conserved_quantities
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            Q.update(timestep)
+
+            #Clean up
+            #Note that Q.explicit_update is reset by compute_fluxes
+
+            #MH090605 commented out the following since semi_implicit_update is now re-initialized
+            #at the end of the _update function in quantity_ext.c (This is called by the
+            #preceeding Q.update(timestep) statement above).
+            #For run_profile.py with N=128, the time of update_conserved_quantities is cut from 14.00 secs
+            #to 8.35 secs
+
+            #Q.semi_implicit_update[:] = 0.0
+
+    def update_ghosts(self):
+        pass
+
+    def distribute_to_vertices_and_edges(self):
+        """Extrapolate conserved quantities from centroid to
+        vertices and edge-midpoints for each volume
+
+        Default implementation is straight first order,
+        i.e. constant values throughout each element and
+        no reference to non-conserved quantities.
+        """
+
+        for name in self.conserved_quantities:
+            Q = self.quantities[name]
+            if self.order == 1:
+                Q.extrapolate_first_order()
+            elif self.order == 2:
+                Q.extrapolate_second_order()
+                Q.limit()
+            else:
+                raise 'Unknown order'
+            Q.interpolate_from_vertices_to_edges()
+
+
+    def centroid_norm(self, quantity, normfunc):
+        """Calculate the norm of the centroid values
+        of a specific quantity, using normfunc.
+
+        normfunc should take a list to a float.
+
+        common normfuncs are provided in the module utilities.norms
+        """
+        return normfunc(self.quantities[quantity].centroid_values)
+
+
+
+##############################################
+#Initialise module
+
+#Optimisation with psyco
+from anuga.config import use_psyco
+if use_psyco:
+    try:
+        import psyco
+    except:
+        import os
+        if os.name == 'posix' and os.uname()[4] == 'x86_64':
+            pass
+            #Psyco isn't supported on 64 bit systems, but it doesn't matter
+        else:
+            msg = 'WARNING: psyco (speedup) could not import'+\
+                  ', you may want to consider installing it'
+            print msg
+    else:
+        psyco.bind(Domain.update_boundary)
+        #psyco.bind(Domain.update_timestep)     #Not worth it
+        psyco.bind(Domain.update_conserved_quantities)
+        psyco.bind(Domain.distribute_to_vertices_and_edges)
+
+
+if __name__ == "__main__":
+    pass
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/ermapper_grids.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/ermapper_grids.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/ermapper_grids.py	(revision 3560)
@@ -0,0 +1,253 @@
+#!/usr/bin/env python
+
+# from os import open, write, read
+import Numeric
+
+celltype_map = {'IEEE4ByteReal': Numeric.Float32, 'IEEE8ByteReal': Numeric.Float64}
+
+
+def write_ermapper_grid(ofile, data, header = {}):
+    """
+    write_ermapper_grid(ofile, data, header = {}):
+    
+    Function to write a 2D Numeric array to an ERMapper grid.  There are a series of conventions adopted within
+    this code, specifically:
+    1)  The registration coordinate for the data is the SW (or lower-left) corner of the data
+    2)  The registration coordinates refer to cell centres
+    3)  The data is a 2D Numeric array with the NW-most data in element (0,0) and the SE-most data in element (N,M)
+        where N is the last line and M is the last column
+    4)  There has been no testng of the use of a rotated grid.  Best to keep data in an NS orientation
+    
+    Input Parameters:
+    ofile:      string - filename for output (note the output will consist of two files
+                ofile and ofile.ers.  Either of these can be entered into this function
+    data:       Numeric.array - 2D array containing the data to be output to the grid
+    header:     dictionary - contains spatial information about the grid, in particular:
+                    header['datum'] datum for the data ('"GDA94"')
+                    header['projection'] - either '"GEOGRAPHIC"' or '"PROJECTED"' 
+                    header['coordinatetype'] - either 'EN' (for eastings/northings) or
+                                                      'LL' (for lat/long)
+                    header['rotation'] - rotation of grid ('0:0:0.0')
+                    header['celltype'] - data type for writing data ('IEEE4ByteReal')
+                    header['nullcellvalue'] - value for null cells ('-99999')
+                    header['xdimension'] - cell size in x-dir in units dictated by 'coordinatetype' ('100')
+                    header['registrationcellx'] == '0'
+                    header['ydimension'] - cell size in y-dir in units dictated by 'coordinatetype' ('100')
+                    header['longitude'] - co-ordinate of registration cell ('0:0:0')
+                    header['latitude'] - co-ordinate of registration line ('0:0:0')
+                    header['nrofbands'] - number of bands ('1')
+                    header['value'] - name of grid ('"Default_Band"')
+
+                    Some entries are determined automatically from the data
+                    header['nroflines'] - number of lines in data
+                    header['nrofcellsperline'] - number of columns in data
+                    header['registrationcelly'] == last line of data
+
+    Written by Trevor Dhu, Geoscience Australia 2005 
+    """
+    # extract filenames for header and data files from ofile
+    ers_index = ofile.find('.ers')
+    if ers_index > 0:
+        data_file = ofile[0:ers_index]
+        header_file = ofile
+    else:
+        data_file = ofile
+        header_file = ofile + '.ers'
+
+
+    # Check that the data is a 2 dimensional array
+    data_size = Numeric.shape(data)
+    assert len(data_size) == 2
+    
+    header['nroflines'] = str(data_size[0])
+    header['nrofcellsperline'] = str(data_size[1])
+
+
+    header = create_default_header(header)
+    write_ermapper_header(header_file, header)
+    write_ermapper_data(data, data_file, data_format = header['celltype'])
+
+    
+def read_ermapper_grid(ifile):
+    ers_index = ifile.find('.ers')
+    if ers_index > 0:
+        data_file = ifile[0:ers_index]
+        header_file = ifile
+    else:
+        data_file = ifile
+        header_file = ifile + '.ers'
+        
+    header = read_ermapper_header(header_file)
+
+    nroflines = int(header['nroflines'])
+    nrofcellsperlines = int(header['nrofcellsperline'])
+    data = read_ermapper_data(data_file)
+    data = Numeric.reshape(data,(nroflines,nrofcellsperlines))
+    return data
+    
+
+def write_ermapper_header(ofile, header = {}):
+    
+    header = create_default_header(header)
+    # Determine if the dataset is in lats/longs or eastings/northings and set header parameters
+    # accordingly
+    if header['coordinatetype'] == 'LL':
+        X_Class = 'Longitude'
+        Y_Class = 'Latitude'
+    elif header['coordinatetype'] == 'EN':
+        X_Class = 'Eastings'
+        Y_Class = 'Northings'
+
+    # open the header file for writing to
+    fid = open(ofile,'wt')
+
+    # Begin writing the header
+    fid.write('DatasetHeader Begin\n')
+    fid.write('\tVersion\t\t= "6.4"\n')
+    fid.write('\tDatasetType\t= ERStorage\n')
+    fid.write('\tDataType\t= Raster\n')
+    fid.write('\tByteOrder\t= LSBFirst\n')
+
+    # Write the coordinate space information
+    fid.write('\tCoordinateSpace Begin\n')
+    fid.write('\t\tDatum\t\t\t = ' + header['datum'] + '\n')
+    fid.write('\t\tProjection\t\t = ' + header['projection'] + '\n')
+    fid.write('\t\tCoordinateType\t = ' + header['coordinatetype'] + '\n')
+    fid.write('\t\tRotation\t\t = ' + header['rotation'] + '\n')
+    fid.write('\t\tUnits\t\t = ' + header['units'] + '\n')
+    fid.write('\tCoordinateSpace End\n')
+
+    # Write the raster information
+    fid.write('\tRasterInfo Begin\n')
+    fid.write('\t\tCellType\t\t\t = ' + header['celltype'] + '\n')
+    fid.write('\t\tNullCellValue\t\t = ' + header['nullcellvalue'] + '\n')
+    fid.write('\t\tRegistrationCellX\t\t = ' + header['registrationcellx'] +'\n')
+    fid.write('\t\tRegistrationCellY\t\t = ' + header['registrationcelly'] +'\n')
+    # Write the cellsize information
+    fid.write('\t\tCellInfo Begin\n')
+    fid.write('\t\t\tXDimension\t\t\t = ' + header['xdimension'] + '\n')
+    fid.write('\t\t\tYDimension\t\t\t = ' + header['ydimension'] + '\n')
+    fid.write('\t\tCellInfo End\n')
+    # Continue with wrting the raster information
+    fid.write('\t\tNrOfLines\t\t\t = ' + header['nroflines'] + '\n')
+    fid.write('\t\tNrOfCellsPerLine\t = ' + header['nrofcellsperline'] + '\n')
+    # Write the registration coordinate information
+    fid.write('\t\tRegistrationCoord Begin\n')
+    ###print X_Class 
+    fid.write('\t\t\t' + X_Class + '\t\t\t = ' + header[X_Class.lower()] + '\n')
+    fid.write('\t\t\t' + Y_Class + '\t\t\t = ' + header[Y_Class.lower()] + '\n')
+    fid.write('\t\tRegistrationCoord End\n')
+    # Continue with wrting the raster information
+    fid.write('\t\tNrOfBands\t\t\t = ' + header['nrofbands'] + '\n')
+    fid.write('\t\tBandID Begin\n')
+    fid.write('\t\t\tValue\t\t\t\t = ' + header['value'] + '\n')
+    fid.write('\t\tBandID End\n')
+    fid.write('\tRasterInfo End\n')
+    fid.write('DatasetHeader End\n')
+    
+    fid.close
+
+def read_ermapper_header(ifile):
+    # function for reading an ERMapper header from file
+    header = {}
+
+    fid = open(ifile,'rt')
+    header_string = fid.readlines()
+    fid.close()
+
+    for line in header_string:
+        if line.find('=') > 0:
+            tmp_string = line.strip().split('=')
+            header[tmp_string[0].strip().lower()]= tmp_string[1].strip()
+
+    return header                      
+
+def write_ermapper_data(grid, ofile, data_format = Numeric.Float32):
+
+
+    try:
+        data_format = celltype_map[data_format]
+    except:
+        pass
+    
+
+    #if isinstance(data_format, basestring):
+    #    #celltype_map is defined at top of code
+    #    if celltype_map.has_key(data_format):
+    #        data_format = celltype_map[data_format]
+    #    else:
+    #        msg = 'Format %s is not yet defined by celltype_map' %data_format
+    #        raise msg
+        
+    
+    # Convert the array to data_format (default format is Float32)
+    grid_as_float = grid.astype(data_format)
+
+    # Convert array to a string for writing to output file
+    output_string = grid_as_float.tostring()
+
+    # open output file in a binary format and write the output string
+    fid = open(ofile,'wb')
+    fid.write(output_string)
+    fid.close()
+
+
+def read_ermapper_data(ifile, data_format = Numeric.Float32):
+    # open input file in a binary format and read the input string
+    fid = open(ifile,'rb')
+    input_string = fid.read()
+    fid.close()
+
+    # convert input string to required format (Note default format is Numeric.Float32)
+    grid_as_float = Numeric.fromstring(input_string,data_format)
+    return grid_as_float
+
+def create_default_header(header = {}):
+    # fill any blanks in a header dictionary with default values
+    # input parameters:
+    # header:   a dictionary containing fields that are not meant
+    #           to be filled with default values
+    
+ 
+    if not header.has_key('datum'):
+        header['datum'] = '"GDA94"'
+    if not header.has_key('projection'):
+        header['projection'] = '"GEOGRAPHIC"'        
+    if not header.has_key('coordinatetype'):
+        header['coordinatetype'] = 'LL'
+    if not header.has_key('rotation'):
+        header['rotation'] = '0:0:0.0'
+    if not header.has_key('units'):
+        header['units'] = '"METERS"'
+    if not header.has_key('celltype'):
+        header['celltype'] = 'IEEE4ByteReal'
+    if not header.has_key('nullcellvalue'):
+        header['nullcellvalue'] = '-99999'
+    if not header.has_key('xdimension'):
+        header['xdimension'] = '100'
+    if not header.has_key('latitude'):
+        header['latitude'] = '0:0:0'
+    if not header.has_key('longitude'):
+        header['longitude'] = '0:0:0'        
+    if not header.has_key('ydimension'):
+        header['ydimension'] = '100'
+    if not header.has_key('nroflines'):
+        header['nroflines'] = '3'    
+    if not header.has_key('nrofcellsperline'):
+        header['nrofcellsperline'] = '4'
+    if not header.has_key('registrationcellx'):
+        header['registrationcellx'] = '0'
+    if not header.has_key('registrationcelly'):
+        header['registrationcelly'] = str(int(header['nroflines'])-1)
+    if not header.has_key('nrofbands'):
+        header['nrofbands'] = '1'
+    if not header.has_key('value'):
+        header['value'] = '"Default_Band"'
+
+
+    return header    
+                          
+    
+
+
+    
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/flatbed.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/flatbed.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/flatbed.py	(revision 3560)
@@ -0,0 +1,78 @@
+"""Example of shallow water wave equation.
+
+Generate slope
+
+"""
+
+######################
+# Module imports 
+#
+from os import sep, path
+from mesh_factory import rectangular
+from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+     Constant_height
+from Numeric import array
+from anuga.pyvolution.util import Polygon_function, read_polygon
+
+
+#Create basic mesh
+N = 50
+points, vertices, boundary = rectangular(N, N, 100, 100)
+
+#Create shallow water domain
+domain = Domain(points, vertices, boundary)
+domain.store = True
+domain.set_name('polygons')
+print "Output being written to " + domain.get_datadir() + sep + \
+	      domain.filename + "_size%d." %len(domain) + domain.format
+	
+
+domain.default_order=2
+
+#Set driving forces
+manning = 0.07
+manning = 0.0
+inflow_stage = 10.0
+domain.set_quantity('friction', manning)
+
+def wiggle(x, y):
+    from Numeric import sin
+    from math import pi
+    return 10 + sin(2*pi*x/10)
+
+def slope(x, y):
+    return 20*(x/100+y/100)    
+
+#Define polynomials
+p0 = [[20,27], [30,25], [40,40], [20,40]]         
+p1 = [[80,19], [90,20], [85,50], [80,55], [75,58], [70,60], [60,24]]         
+p2 = read_polygon('testpoly.txt')
+
+
+#Set elevation  
+domain.set_quantity('elevation', 
+	Polygon_function([(p0,slope), (p1,wiggle), (p2,15)]))
+#domain.set_quantity('stage', 
+#	Polygon_function([(p0,slope), (p1,wiggle), (p2,15)]))	
+
+
+ 	  
+
+
+
+######################
+# Boundary conditions
+Br = Reflective_boundary(domain)
+Bd = Dirichlet_boundary([inflow_stage,0.,0.])
+
+domain.set_boundary({'left': Bd, 'right': Br, 'top': Br, 'bottom': Br})
+domain.check_integrity()
+
+
+######################
+#Evolution
+for t in domain.evolve(yieldstep = 1, finaltime = 1):
+    domain.write_time()
+
+print 'Done'    
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/flatbed_compare.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/flatbed_compare.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/flatbed_compare.py	(revision 3560)
@@ -0,0 +1,56 @@
+"""Example of shallow water wave equation.
+
+Generate slope
+
+"""
+
+######################
+# Module imports 
+#
+from mesh_factory import rectangular
+from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+     Constant_height
+from Numeric import array
+
+#Create basic mesh
+N = 8
+points, vertices, boundary = rectangular(N, N)
+
+#Create shallow water domain
+domain = Domain(points, vertices, boundary)
+domain.smooth = False
+domain.visualise = True
+domain.default_order=2
+
+
+######################
+# Boundary conditions
+Br = Reflective_boundary(domain)
+Bd = 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.05, finaltime = 1.):
+#    domain.write_time()
+
+
+#import sys; sys.exit()
+
+######################
+#Evolution
+for t in domain.evolve(yieldstep = 0.01, finaltime = 0.03):
+    domain.write_time()
+
+print domain.quantities['stage'].centroid_values[:4]
+print domain.quantities['xmomentum'].centroid_values[:4]
+print domain.quantities['ymomentum'].centroid_values[:4]
+domain.distribute_to_vertices_and_edges()
+print
+print domain.quantities['stage'].vertex_values[:4,0]
+print domain.quantities['xmomentum'].vertex_values[:4,0]
+print domain.quantities['ymomentum'].vertex_values[:4,0]  
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/general_mesh.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/general_mesh.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/general_mesh.py	(revision 3560)
@@ -0,0 +1,361 @@
+
+from Numeric import concatenate, reshape, take, allclose
+from Numeric import array, zeros, Int, Float, sqrt, sum
+
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+
+class General_mesh:
+    """Collection of triangular elements (purely geometric)
+
+    A triangular element is defined in terms of three vertex ids,
+    ordered counter clock-wise,
+    each corresponding to a given coordinate set.
+    Vertices from different elements can point to the same
+    coordinate set.
+
+    Coordinate sets are implemented as an N x 2 Numeric array containing
+    x and y coordinates.
+
+
+    To instantiate:
+       Mesh(coordinates, triangles)
+
+    where
+
+      coordinates is either a list of 2-tuples or an Mx2 Numeric array of
+      floats representing all x, y coordinates in the mesh.
+
+      triangles is either a list of 3-tuples or an Nx3 Numeric array of
+      integers representing indices of all vertices in the mesh.
+      Each vertex is identified by its index i in [0, M-1].
+
+
+    Example:
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0,0.0]
+        e = [2.0, 2.0]
+
+        points = [a, b, c, e]
+        triangles = [ [1,0,2], [1,2,3] ]   #bac, bce
+        mesh = Mesh(points, triangles)
+
+        #creates two triangles: bac and bce
+
+    Other:
+
+      In addition mesh computes an Nx6 array called vertex_coordinates.
+      This structure is derived from coordinates and contains for each
+      triangle the three x,y coordinates at the vertices.
+
+
+        This is a cut down version of mesh from mesh.py
+    """
+
+    #FIXME: It would be a good idea to use geospatial data as an alternative
+    #input
+    def __init__(self, coordinates, triangles,
+                 geo_reference=None,
+                 verbose=False):
+        """
+        Build triangles from x,y coordinates (sequence of 2-tuples or
+        Mx2 Numeric array of floats) and triangles (sequence of 3-tuples
+        or Nx3 Numeric array of non-negative integers).
+
+        origin is a 3-tuple consisting of UTM zone, easting and northing.
+        If specified coordinates are assumed to be relative to this origin.
+        """
+
+        if verbose: print 'General_mesh: Building basic mesh structure' 
+
+        self.triangles = array(triangles,Int)
+        self.coordinates = array(coordinates,Float)
+        
+
+        # FIXME: this stores a geo_reference, but when coords are returned
+        # This geo_ref is not taken into account!
+        if geo_reference is None:
+            self.geo_reference = Geo_reference() #Use defaults 
+        else:
+            self.geo_reference = geo_reference
+
+        #Input checks
+        msg = 'Triangles must an Nx3 Numeric array or a sequence of 3-tuples'
+        assert len(self.triangles.shape) == 2, msg
+
+        msg = 'Coordinates must an Mx2 Numeric array or a sequence of 2-tuples'
+        assert len(self.coordinates.shape) == 2, msg
+
+        msg = 'Vertex indices reference non-existing coordinate sets'
+        assert max(max(self.triangles)) <= self.coordinates.shape[0], msg
+
+
+        #Register number of elements (N)
+        self.number_of_elements = N = self.triangles.shape[0]
+
+        # FIXME: Maybe move to statistics?
+        # Or use with get_extent
+        xy_extent = [ min(self.coordinates[:,0]), min(self.coordinates[:,1]) ,
+                      max(self.coordinates[:,0]), max(self.coordinates[:,1]) ]
+
+        self.xy_extent = array(xy_extent, Float)
+
+
+        #Allocate space for geometric quantities
+        self.normals = zeros((N, 6), Float)
+        self.areas = zeros(N, Float)
+        self.edgelengths = zeros((N, 3), Float)
+
+        #Get x,y coordinates for all triangles and store
+        self.vertex_coordinates = V = self.compute_vertex_coordinates()
+
+
+        #Initialise each triangle
+        if verbose:
+            print 'General_mesh: Computing areas, normals and edgelenghts'
+            
+        for i in range(N):
+            if verbose and i % ((N+10)/10) == 0: print '(%d/%d)' %(i, N)
+           
+
+            x0 = V[i, 0]; y0 = V[i, 1]
+            x1 = V[i, 2]; y1 = V[i, 3]
+            x2 = V[i, 4]; y2 = V[i, 5]
+
+            #Area
+            self.areas[i] = abs((x1*y0-x0*y1)+(x2*y1-x1*y2)+(x0*y2-x2*y0))/2
+
+            msg = 'Triangle (%f,%f), (%f,%f), (%f, %f)' %(x0,y0,x1,y1,x2,y2)
+            msg += ' is degenerate:  area == %f' %self.areas[i]
+            assert self.areas[i] > 0.0, msg
+
+
+            #Normals
+            #The normal vectors
+            # - point outward from each edge
+            # - are orthogonal to the edge
+            # - have unit length
+            # - Are enumerated according to the opposite corner:
+            #   (First normal is associated with the edge opposite
+            #    the first vertex, etc)
+            # - Stored as six floats n0x,n0y,n1x,n1y,n2x,n2y per triangle
+
+            n0 = array([x2 - x1, y2 - y1])
+            l0 = sqrt(sum(n0**2))
+
+            n1 = array([x0 - x2, y0 - y2])
+            l1 = sqrt(sum(n1**2))
+
+            n2 = array([x1 - x0, y1 - y0])
+            l2 = sqrt(sum(n2**2))
+
+            #Normalise
+            n0 /= l0
+            n1 /= l1
+            n2 /= l2
+
+            #Compute and store
+            self.normals[i, :] = [n0[1], -n0[0],
+                                  n1[1], -n1[0],
+                                  n2[1], -n2[0]]
+
+            #Edgelengths
+            self.edgelengths[i, :] = [l0, l1, l2]
+
+        
+        #Build vertex list
+        if verbose: print 'Building vertex list'         
+        self.build_vertexlist()
+
+            
+
+    def __len__(self):
+        return self.number_of_elements
+
+    def __repr__(self):
+        return 'Mesh: %d triangles, %d elements'\
+               %(self.coordinates.shape[0], len(self))
+
+    def get_normals(self):
+        """Return all normal vectors.
+        Return normal vectors for all triangles as an Nx6 array
+        (ordered as x0, y0, x1, y1, x2, y2 for each triangle)
+        """
+        return self.normals
+
+
+    def get_normal(self, i, j):
+        """Return normal vector j of the i'th triangle.
+        Return value is the numeric array slice [x, y]
+        """
+        return self.normals[i, 2*j:2*j+2]
+
+
+
+    def get_vertex_coordinates(self, obj=False, absolute=False):
+        """Return all vertex coordinates.
+        Return all vertex coordinates for all triangles as an Nx6 array
+        (ordered as x0, y0, x1, y1, x2, y2 for each triangle)
+
+        if obj is True, the x/y pairs are returned in a 3*N x 2 array.
+        FIXME, we might make that the default.
+        FIXME Maybe use keyword: continuous = False for this condition?
+	FIXME - Maybe use something referring to unique vertices?
+
+        Boolean keyword argument absolute determines whether coordinates
+        are to be made absolute by taking georeference into account
+        Default is False as many parts of ANUGA expects relative coordinates.
+        (To see which, switch to default absolute=True and run tests).
+        """
+
+        V = self.vertex_coordinates
+        if absolute is True:
+            if not self.geo_reference.is_absolute():
+            
+                V0 = self.geo_reference.get_absolute(V[:,0:2])
+                V1 = self.geo_reference.get_absolute(V[:,2:4])
+                V2 = self.geo_reference.get_absolute(V[:,4:6])
+
+                # This does double the memory need 
+                V = concatenate( (V0, V1, V2), axis=1 )
+
+                
+        if obj is True:
+
+            N = V.shape[0]
+            return reshape(V, (3*N, 2))
+        else:    
+            return V
+
+
+    def get_vertex_coordinate(self, i, j, absolute=False):
+        """Return coordinates for vertex j of the i'th triangle.
+        Return value is the numeric array slice [x, y]
+        """
+
+        V = self.get_vertex_coordinates(absolute=absolute)
+        return V[i, 2*j:2*j+2]
+    
+        ##return self.vertex_coordinates[i, 2*j:2*j+2]
+
+
+    def compute_vertex_coordinates(self):
+        """Return vertex coordinates for all triangles as an Nx6 array
+        (ordered as x0, y0, x1, y1, x2, y2 for each triangle)
+        """
+
+        #FIXME (Ole): Perhaps they should be ordered as in obj files??
+        #See quantity.get_vertex_values
+        #FIXME (Ole) - oh yes they should
+
+        N = self.number_of_elements
+        vertex_coordinates = zeros((N, 6), Float)
+
+        for i in range(N):
+            for j in range(3):
+                k = self.triangles[i,j]  #Index of vertex 0
+                v_k = self.coordinates[k]
+                vertex_coordinates[i, 2*j+0] = v_k[0]
+                vertex_coordinates[i, 2*j+1] = v_k[1]
+
+        return vertex_coordinates
+
+    def get_vertices(self, indices=None):
+        """Get connectivity
+        indices is the set of element ids of interest
+        """
+
+        if (indices ==  None):
+            indices = range(len(self))  #len(self)=number of elements
+
+        return  take(self.triangles, indices)
+
+    #FIXME - merge these two (get_vertices and get_triangles)
+    def get_triangles(self, obj=False):
+        """Get connetivity
+        Return triangles (triplets of indices into point coordinates)
+        
+        If obj is True return structure commensurate with replicated
+        points, allowing for discontinuities
+        (FIXME: Need good name for this concept)
+        """
+
+        if obj is True:
+            m = len(self)  #Number of triangles
+            M = 3*m        #Total number of unique vertices
+            T = reshape(array(range(M)).astype(Int), (m,3))
+        else:
+            T = self.triangles
+
+        return T     
+
+    
+
+    def get_unique_vertices(self,  indices=None):
+        triangles = self.get_vertices(indices=indices)
+        unique_verts = {}
+        for triangle in triangles:
+           unique_verts[triangle[0]] = 0
+           unique_verts[triangle[1]] = 0
+           unique_verts[triangle[2]] = 0
+        return unique_verts.keys()
+
+    def build_vertexlist(self):
+        """Build vertexlist index by vertex ids and for each entry (point id)
+        build a list of (triangles, vertex_id) pairs that use the point
+        as vertex.
+
+        Preconditions:
+          self.coordinates and self.triangles are defined
+
+        Postcondition:
+          self.vertexlist is built
+        """
+
+        vertexlist = [None]*len(self.coordinates)
+        for i in range(self.number_of_elements):
+
+            a = self.triangles[i, 0]
+            b = self.triangles[i, 1]
+            c = self.triangles[i, 2]
+
+            #Register the vertices v as lists of
+            #(triangle_id, vertex_id) tuples associated with them
+            #This is used for averaging multiple vertex values.
+            for vertex_id, v in enumerate([a,b,c]):
+                if vertexlist[v] is None:
+                    vertexlist[v] = []
+
+                vertexlist[v].append( (i, vertex_id) )
+
+        self.vertexlist = vertexlist
+
+
+    def get_extent(self, absolute=False):
+        """Return min and max of all x and y coordinates
+
+        Boolean keyword argument absolute determines whether coordinates
+        are to be made absolute by taking georeference into account
+        """
+        
+
+
+        C = self.get_vertex_coordinates(absolute=absolute)
+        X = C[:,0:6:2].copy()
+        Y = C[:,1:6:2].copy()
+
+        xmin = min(X.flat)
+        xmax = max(X.flat)
+        ymin = min(Y.flat)
+        ymax = max(Y.flat)
+
+        return xmin, xmax, ymin, ymax
+
+
+    def get_area(self):
+    	"""Return total area of mesh
+        """
+
+        return sum(self.areas)
+
+        
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/generic_boundary_conditions.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/generic_boundary_conditions.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/generic_boundary_conditions.py	(revision 3560)
@@ -0,0 +1,365 @@
+"""boundary.py - Classes for implementing boundary conditions
+"""
+
+
+class Boundary:
+    """Base class for boundary conditions.
+       Specific boundary conditions must provide values for
+       the conserved_quantities
+
+       A boundary object has one neighbour; the one it
+       serves.
+    """
+
+    def __init__(self):
+        pass
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        msg = 'Generic class Boundary must be subclassed'
+        raise msg
+
+
+class Transmissive_boundary(Boundary):
+    """Transmissive boundary returns same conserved quantities as
+    those present in its neighbour volume.
+
+    Underlying domain must be specified when boundary is instantiated
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for transmissive boundary'
+            raise msg
+
+        self.domain = domain
+
+    def __repr__(self):
+        return 'Transmissive_boundary(%s)' %self.domain
+
+    def evaluate(self, vol_id, edge_id):
+        """Transmissive boundaries return the edge values
+        of the volume they serve.
+        """
+
+        q = self.domain.get_conserved_quantities(vol_id, edge = edge_id)
+        return q
+
+
+class Dirichlet_boundary(Boundary):
+    """Dirichlet boundary returns constant values for the
+    conserved quantities
+    """
+
+
+    def __init__(self, conserved_quantities=None):
+        Boundary.__init__(self)
+
+        if conserved_quantities is None:
+            msg = 'Must specify one value for each conserved quantity'
+            raise msg
+
+        from Numeric import array, Float
+        self.conserved_quantities=array(conserved_quantities).astype(Float)
+
+    def __repr__(self):
+        return 'Dirichlet boundary (%s)' %self.conserved_quantities
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.conserved_quantities
+
+
+
+class Time_boundary(Boundary):
+    """Time dependent boundary returns values for the
+    conserved quantities as a function of time.
+    Must specify domain to get access to model time and a function f(t)
+    which must return conserved quantities as a function time
+    """
+
+
+    def __init__(self, domain = None, f = None):
+        Boundary.__init__(self)
+
+        try:
+            q = f(0.0)
+        except Exception, e:
+            msg = 'Function for time boundary could not be executed:\n%s' %e
+            raise msg
+
+
+        from Numeric import array, Float
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from time boundary function could '
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        msg = 'ERROR: Time boundary function must return a 1d list or array '
+        assert len(q.shape) == 1, msg
+
+        d = len(domain.conserved_quantities)
+        msg = 'Return value for f must be a list or an array of length %d' %d
+        assert len(q) == d, msg
+
+        self.f = f
+        self.domain = domain
+
+    def __repr__(self):
+        return 'Time boundary'
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        return self.f(self.domain.time)
+
+
+class File_boundary_time(Boundary):
+    """Boundary values obtained from file and interpolated.
+    conserved quantities as a function of time.
+
+    Assumes that file contains a time series.
+
+    No spatial info assumed.
+    """
+
+    #FIXME: Is this still necessary
+
+    def __init__(self, filename, domain):
+        import time
+        from Numeric import array
+        from anuga.config import time_format
+        from anuga.abstract_2d_finite_volumes.util import File_function
+
+        Boundary.__init__(self)
+
+        self.F = File_function(filename, domain)
+        self.domain = domain
+
+        #Test
+        q = self.F(0)
+
+        d = len(domain.conserved_quantities)
+        msg = 'Values specified in file must be a list or an array of length %d' %d
+        assert len(q) == d, msg
+
+
+    def __repr__(self):
+        return 'File boundary'
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        """Return linearly interpolated values based on domain.time
+
+        vol_id and edge_id are ignored
+        """
+
+        t = self.domain.time
+        return self.F(t)
+
+
+
+
+class File_boundary(Boundary):
+    """Boundary values obtained from file and interpolated.
+    conserved quantities as a function of time.
+
+    Assumes that file contains a time series and possibly
+    also spatial info.
+    See docstring for File_function in util.py for details about
+    admissible file formats
+
+    The full solution history is not exactly the same as if
+    the models were coupled:
+    File boundary must read and interpolate from *smoothed* version
+    as stored in sww and cannot work with the discontinuos triangles.
+
+    """
+
+    def __init__(self, filename, domain, verbose = False):
+        import time
+        from Numeric import array, zeros, Float
+        from anuga.config import time_format
+        from anuga.abstract_2d_finite_volumes.util import file_function
+
+        Boundary.__init__(self)
+
+        #Get x,y vertex coordinates for all triangles
+        V = domain.vertex_coordinates
+
+        #Compute midpoint coordinates for all boundary elements
+        #Only a subset may be invoked when boundary is evaluated but
+        #we don't know which ones at this stage since this object can be attached to
+        #any tagged boundary later on.
+
+        if verbose: print 'Find midpoint coordinates of entire boundary'
+        self.midpoint_coordinates = zeros( (len(domain.boundary), 2), Float)
+        boundary_keys = domain.boundary.keys()
+
+
+        xllcorner = domain.geo_reference.get_xllcorner()
+        yllcorner = domain.geo_reference.get_yllcorner()        
+        
+
+        #Make ordering unique #FIXME: should this happen in domain.py?
+        boundary_keys.sort()
+
+
+        #Record ordering #FIXME: should this also happen in domain.py?
+        self.boundary_indices = {}
+        for i, (vol_id, edge_id) in enumerate(boundary_keys):
+
+            x0 = V[vol_id, 0]; y0 = V[vol_id, 1]
+            x1 = V[vol_id, 2]; y1 = V[vol_id, 3]
+            x2 = V[vol_id, 4]; y2 = V[vol_id, 5]
+
+            #Compute midpoints
+            if edge_id == 0: m = array([(x1 + x2)/2, (y1 + y2)/2])
+            if edge_id == 1: m = array([(x0 + x2)/2, (y0 + y2)/2])
+            if edge_id == 2: m = array([(x1 + x0)/2, (y1 + y0)/2])
+
+            #Convert to absolute UTM coordinates
+            m[0] += xllcorner
+            m[1] += yllcorner
+            
+            #Register point and index
+            self.midpoint_coordinates[i,:] = m
+            self.boundary_indices[(vol_id, edge_id)] = i
+
+
+        if verbose: print 'Initialise file_function'
+        self.F = file_function(filename, domain,
+	                       interpolation_points=self.midpoint_coordinates,
+                               verbose=verbose)
+        self.domain = domain
+
+        #Test
+        q = self.F(0, point_id=0)
+
+        d = len(domain.conserved_quantities)
+        msg = 'Values specified in file %s must be ' %filename
+        msg += ' a list or an array of length %d' %d
+        assert len(q) == d, msg
+
+
+    def __repr__(self):
+        return 'File boundary'
+
+
+    def evaluate(self, vol_id=None, edge_id=None):
+        """Return linearly interpolated values based on domain.time
+
+        vol_id and edge_id are ignored
+        """
+
+        t = self.domain.time
+
+        if vol_id is not None and edge_id is not None:
+            i = self.boundary_indices[ vol_id, edge_id ]
+            return self.F(t, point_id = i)
+        else:
+            #raise 'Boundary call without point_id not implemented'
+            #FIXME: What should the semantics be?
+            return self.F(t)
+
+
+
+
+
+
+
+
+#THIS FAR (10/8/4)
+class Connective_boundary(Boundary):
+    """Connective boundary returns values for the
+    conserved quantities from a volume as defined by a connection table
+    mapping between tuples of (volume id, face id) for volumes that
+    have their boundaries connected.
+
+    FIXME: Perhaps include possibility of mapping between
+    different domains as well
+
+    FIXME: In case of shallow water we may want to have a
+    special version that casts this in terms of height rather than stage
+    """
+
+
+    def __init__(self, table):
+        from domain import Volume
+
+        Boundary.__init__(self)
+
+        self.connection_table = table
+        self.Volume = Volume
+
+    def __repr__(self):
+        return 'Connective boundary'
+
+    #FIXME: IF we ever need to get field_values from connected volume,
+    #that method could be overridden here (using same idea as in
+    #get_conserved_quantities
+    #def get_field_values()
+
+    def get_conserved_quantities(self, volume, face=0):
+
+        id = volume.id
+        if self.connection_table.has_key((id, face)):
+            other_id, other_face = self.connection_table[(id, face)]
+
+            other_volume = self.Volume.instances[other_id]
+            cmd = 'q = other_volume.conserved_quantities_face%d' %face;
+            exec(cmd)
+            return q
+        else:
+            msg = 'Volume, face tuple ($d, %d) has not been mapped'\
+                  %(id, face)
+            raise msg
+
+
+
+
+
+#FIXME: Add a boundary with a general function of x,y, and t
+
+#FIXME: Add periodic boundaries e.g.:
+# Attempt at periodic conditions from advection_spik. Remember this
+#
+#first = 2*(N-1)*N
+#for i in range(1,2*N+1,2):
+#    k = first + i-1#
+#
+#    print i,k
+#
+#    domain[i].faces[2].neighbour = domain[k].faces[1]
+#    domain[k].faces[1].neighbour = domain[i].faces[2]
+
+
+
+class General_boundary(Boundary):
+    """General boundary which can compute conserved quantities based on
+    their previous value, conserved quantities of its neighbour and model time.
+
+    Must specify initial conserved quantities,
+    neighbour,
+    domain to get access to model time
+    a function f(q_old, neighbours_q, t) which must return
+    new conserved quantities q as a function time
+
+    FIXME: COMPLETE UNTESTED - JUST AN IDEA
+    """
+
+    def __init__(self, neighbour=None, conserved_quantities=None, domain=None, f=None):
+        Boundary.__init__(self, neighbour=neighbour, conserved_quantities=conserved_quantities)
+
+        self.f = f
+        self.domain = domain
+
+
+    def get_conserved_quantities(self, volume=None, face=0):
+        return self.f(self.conserved_quantities,
+                      neighbour.conserved_quantities,
+                      self.domain.time)
+
+
+
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/interface.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/interface.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/interface.py	(revision 3560)
@@ -0,0 +1,2 @@
+"""Public 
+"""
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/interpolate_sww.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/interpolate_sww.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/interpolate_sww.py	(revision 3560)
@@ -0,0 +1,221 @@
+""" Interpolation of a sww file.
+
+Used to interpolate height and other information from sww files.
+
+When using as a stand alone application,
+Input;
+ - The sww file with stage and bed elevation information
+ - An xya file specifying the points (x,y) where the height values
+   (w.r.t. time) are needed.
+
+Ouput;
+An xya file with x,y and height values w.r.t. time.
+
+The first row of the output xya file has the time value for each height
+Each following row has the format x,y,[height,]
+
+NOTE: stage = bed elevation + height
+
+   Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+   Geoscience Australia, 2004.   
+"""
+
+##FIXME (DSG-DSG)  no sww file? give a better error message.
+
+from Numeric import transpose
+from anuga.fit_interpolate.interpolate import Interpolate 
+
+DEFAULT_QUANTITY = "depth"
+
+def  interpolate_sww2xya(sww_file, quantity_name,point_file_in,
+                         point_file_out, verbose = True):
+    """
+    This function catches exceptions.
+    """
+    try:
+        interp = Interpolate_sww(sww_file, quantity_name)
+        interp.interpolate_xya(point_file_in)
+        interp.write_depth_xya(point_file_out)
+    except IOError,e: #need to convert key error to ioerror
+        if verbose:
+            print "Could not load bad file. ", e
+        import sys; sys.exit()
+
+        # FIXME (DSG-DSG): how are bad quantities caught?
+        #try:
+        #    interp = Interpolate_sww(sww_file, quantity_name)
+        #except KeyError:
+        #    print "Error: Unknown quantity"
+        #    sys.exit(1)
+
+        interp.interpolate_xya(point_file_in)
+        interp.write_depth_xya(point_file_out)
+
+
+
+class Interpolate_sww:
+    def __init__(self, file_name, quantity_name):
+
+        #It's bad to have the quantity_name passed in here.
+        # But it works with how the program is currently used.
+        # Refactor when necessary. - DSG
+
+        x, y, volumes, time, quantity = self.read_sww(file_name, quantity_name)
+        vertex_coordinates = transpose([x,y])
+        
+        if False:
+            print "****************************"
+            print "x "
+            print x
+            print "****************************"
+            print "Y "
+            print y
+            print "****************************"
+            print "V "
+            print volumes
+            print "****************************"
+            print "Time "
+            print time
+            print "****************************"
+            print "quantity "
+            print quantity
+            print "****************************"
+            print "vertex_coordinates"
+            print vertex_coordinates
+            print "****************************"
+        self.vertex_coordinates = vertex_coordinates
+        self.volumes = volumes
+        self.time = time
+
+        self.quantity_name = quantity_name
+        self.quantity = quantity 
+        
+    def interpolate_xya(self, file_name):
+        """
+        Given a point file, interpolate the height w.r.t. time at the points
+        specified in the point file.
+
+        Input;
+        file_name - the xya file
+        """
+        
+        from load_mesh.loadASCII import import_points_file
+        
+        interp = Interpolate(self.vertex_coordinates, self.volumes)
+        point_dict = import_points_file(file_name)
+        self.point_coordinates = point_dict['pointlist']
+        self.interpolated_quantity_raw = interp.interpolate(transpose(self.quantity),
+                                                            point_coordinates = self.point_coordinates)
+        #self.interpolated_quantity_raw = self.interp.interpolate(transpose(self.quantity))
+        self.interpolated_quantity = {}
+        for i,time_slice in enumerate(self.time):
+            self.interpolated_quantity[str(time_slice)] = self.interpolated_quantity_raw[:,i]
+        
+            
+    def read_sww(self, file_name, quantity_name):
+        """
+        Read in an sww file.
+
+        Input;
+        file_name - the sww file
+
+        Output;
+        x - Vector of x values
+        y - Vector of y values
+        z - Vector of bed elevation
+        volumes - Array.  Each row has 3 values, representing
+                  the vertices that define the volume
+        time - Vector of the times where there is stage information
+        stage - array with respect to time and vertices (x,y)
+        """
+        
+        #FIXME Have this reader as part of data_manager?
+
+        from Scientific.IO.NetCDF import NetCDFFile     
+        import tempfile
+  	import sys
+        import os
+            
+        #Check contents
+        #Get NetCDF
+    
+        # see if the file is there.  Throw a QUIET IO error if it isn't
+        fd = open(file_name,'r')
+        fd.close()
+
+        #throws prints to screen if file not present
+        
+        junk = tempfile.mktemp(".txt")
+        fd = open(junk,'w')
+        stdout = sys.stdout
+        sys.stdout = fd
+        fid = NetCDFFile(file_name, 'r') 
+        sys.stdout = stdout
+        fd.close()
+        #clean up
+        os.remove(junk)    	
+      
+        # Get the variables
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        volumes = fid.variables['volumes'][:] 
+        time = fid.variables['time'][:]
+        try:
+            if quantity_name == 'depth':
+                z = fid.variables['elevation'][:]
+                stage = fid.variables['stage'][:,:]
+                quantity = stage - z  # 2D, using broadcasting
+                #print quantity
+            else:
+                quantity = fid.variables[quantity_name][:,:]   # 2D 
+        except (KeyError, IndexError),e:
+            fid.close()
+            raise KeyError
+            
+        fid.close()
+        return x, y, volumes, time, quantity
+
+    def write_depth_xya(self,point_file, delimiter = ','):
+        """
+        pre condition:
+        point attributes have been determined
+        (interpolate_xya has been called)
+        The time list is defined
+        """
+        from load_mesh.loadASCII import export_points_file
+
+        xya_dict = {}
+        xya_dict['pointlist'] = self.point_coordinates
+        xya_dict['attributelist'] = self.interpolated_quantity
+        export_points_file(point_file, xya_dict)
+        
+        
+#-------------------------------------------------------------
+
+
+if __name__ == "__main__":
+    """
+    Load in an sww file and an xya file and return an xya file 
+    """
+    import os, sys
+    usage = "usage: %s pyvolution_results.sww points.xya depth.xya [depth|stage|(other quantities)]" %         os.path.basename(sys.argv[0])
+    if len(sys.argv) < 4:
+        print usage
+    else:
+        sww_file = sys.argv[1]
+        point_file_in = sys.argv[2]
+        point_file_out = sys.argv[3]
+        if len(sys.argv) == 5:
+            quantity_name = sys.argv[4]
+        else:
+            quantity_name = DEFAULT_QUANTITY   
+        #print "quantity",quantity
+        interpolate_sww2xya(sww_file, quantity_name,point_file_in,
+                            point_file_out)
+
+
+
+
+
+
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/least_squares.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/least_squares.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/least_squares.py	(revision 3560)
@@ -0,0 +1,1472 @@
+"""Least squares smooting and interpolation.
+
+   Implements a penalised least-squares fit and associated interpolations.
+
+   The penalty term (or smoothing term) is controlled by the smoothing
+   parameter alpha.
+   With a value of alpha=0, the fit function will attempt
+   to interpolate as closely as possible in the least-squares sense.
+   With values alpha > 0, a certain amount of smoothing will be applied.
+   A positive alpha is essential in cases where there are too few
+   data points.
+   A negative alpha is not allowed.
+   A typical value of alpha is 1.0e-6
+
+
+   Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+   Geoscience Australia, 2004.
+"""
+
+import exceptions
+class ShapeError(exceptions.Exception): pass
+class FittingError(exceptions.Exception): pass
+
+
+#from general_mesh import General_mesh
+from Numeric import zeros, array, Float, Int, transpose, concatenate, ArrayType, NewAxis
+from anuga.abstract_2d_finite_volumes.neighbour_mesh import Mesh
+
+from Numeric import dot, zeros, take, compress, array, Float, Int, transpose, concatenate, ArrayType
+from anuga.utilities.sparse import Sparse, Sparse_CSR
+from anuga.utilities.cg_solve import conjugate_gradient, VectorShapeError
+from anuga.utilities.numerical_tools import ensure_numeric, mean, gradient
+
+
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+
+import time
+
+DEFAULT_ALPHA = 0.001
+
+def fit_to_mesh_file(mesh_file, point_file, mesh_output_file,
+                     alpha=DEFAULT_ALPHA, verbose= False,
+                     expand_search = False,
+                     data_origin = None,
+                     mesh_origin = None,
+                     precrop = False,
+                     display_errors = True):
+    """
+    Given a mesh file (tsh) and a point attribute file (xya), fit
+    point attributes to the mesh and write a mesh file with the
+    results.
+
+
+    If data_origin is not None it is assumed to be
+    a 3-tuple with geo referenced
+    UTM coordinates (zone, easting, northing)
+
+    NOTE: Throws IOErrors, for a variety of file problems.
+    
+    mesh_origin is the same but refers to the input tsh file.
+    FIXME: When the tsh format contains it own origin, these parameters can go.
+    FIXME: And both origins should be obtained from the specified files.
+    """
+
+    from load_mesh.loadASCII import import_mesh_file, \
+                 import_points_file, export_mesh_file, \
+                 concatinate_attributelist
+
+
+    try:
+        mesh_dict = import_mesh_file(mesh_file)
+    except IOError,e:
+        if display_errors:
+            print "Could not load bad file. ", e
+        raise IOError  #Re-raise exception
+        
+    vertex_coordinates = mesh_dict['vertices']
+    triangles = mesh_dict['triangles']
+    if type(mesh_dict['vertex_attributes']) == ArrayType:
+        old_point_attributes = mesh_dict['vertex_attributes'].tolist()
+    else:
+        old_point_attributes = mesh_dict['vertex_attributes']
+
+    if type(mesh_dict['vertex_attribute_titles']) == ArrayType:
+        old_title_list = mesh_dict['vertex_attribute_titles'].tolist()
+    else:
+        old_title_list = mesh_dict['vertex_attribute_titles']
+
+    if verbose: print 'tsh file %s loaded' %mesh_file
+
+    # load in the .pts file
+    try:
+        point_dict = import_points_file(point_file, verbose=verbose)
+    except IOError,e:
+        if display_errors:
+            print "Could not load bad file. ", e
+        raise IOError  #Re-raise exception  
+
+    point_coordinates = point_dict['pointlist']
+    title_list,point_attributes = concatinate_attributelist(point_dict['attributelist'])
+
+    if point_dict.has_key('geo_reference') and not point_dict['geo_reference'] is None:
+        data_origin = point_dict['geo_reference'].get_origin()
+    else:
+        data_origin = (56, 0, 0) #FIXME(DSG-DSG)
+
+    if mesh_dict.has_key('geo_reference') and not mesh_dict['geo_reference'] is None:
+        mesh_origin = mesh_dict['geo_reference'].get_origin()
+    else:
+        mesh_origin = (56, 0, 0) #FIXME(DSG-DSG)
+
+    if verbose: print "points file loaded"
+    if verbose: print "fitting to mesh"
+    f = fit_to_mesh(vertex_coordinates,
+                    triangles,
+                    point_coordinates,
+                    point_attributes,
+                    alpha = alpha,
+                    verbose = verbose,
+                    expand_search = expand_search,
+                    data_origin = data_origin,
+                    mesh_origin = mesh_origin,
+                    precrop = precrop)
+    if verbose: print "finished fitting to mesh"
+
+    # convert array to list of lists
+    new_point_attributes = f.tolist()
+    #FIXME have this overwrite attributes with the same title - DSG
+    #Put the newer attributes last
+    if old_title_list <> []:
+        old_title_list.extend(title_list)
+        #FIXME can this be done a faster way? - DSG
+        for i in range(len(old_point_attributes)):
+            old_point_attributes[i].extend(new_point_attributes[i])
+        mesh_dict['vertex_attributes'] = old_point_attributes
+        mesh_dict['vertex_attribute_titles'] = old_title_list
+    else:
+        mesh_dict['vertex_attributes'] = new_point_attributes
+        mesh_dict['vertex_attribute_titles'] = title_list
+
+    #FIXME (Ole): Remember to output mesh_origin as well
+    if verbose: print "exporting to file ", mesh_output_file
+
+    try:
+        export_mesh_file(mesh_output_file, mesh_dict)
+    except IOError,e:
+        if display_errors:
+            print "Could not write file. ", e
+        raise IOError
+
+def fit_to_mesh(vertex_coordinates,
+                triangles,
+                point_coordinates,
+                point_attributes,
+                alpha = DEFAULT_ALPHA,
+                verbose = False,
+                acceptable_overshoot = 1.01,
+                expand_search = False,
+                data_origin = None,
+                mesh_origin = None,
+                precrop = False,
+                use_cache = False):
+    """
+    Fit a smooth surface to a triangulation,
+    given data points with attributes.
+
+
+        Inputs:
+
+          vertex_coordinates: List of coordinate pairs [xi, eta] of points
+          constituting mesh (or a an m x 2 Numeric array)
+
+          triangles: List of 3-tuples (or a Numeric array) of
+          integers representing indices of all vertices in the mesh.
+
+          point_coordinates: List of coordinate pairs [x, y] of data points
+          (or an nx2 Numeric array)
+
+          alpha: Smoothing parameter.
+
+          acceptable overshoot: controls the allowed factor by which fitted values
+          may exceed the value of input data. The lower limit is defined
+          as min(z) - acceptable_overshoot*delta z and upper limit
+          as max(z) + acceptable_overshoot*delta z
+          
+
+          point_attributes: Vector or array of data at the point_coordinates.
+
+          data_origin and mesh_origin are 3-tuples consisting of
+          UTM zone, easting and northing. If specified
+          point coordinates and vertex coordinates are assumed to be
+          relative to their respective origins.
+
+    """
+    if use_cache is True:
+        from anuga.caching.caching import cache
+        interp = cache(_interpolation,
+                       (vertex_coordinates,
+                        triangles,
+                        point_coordinates),
+                       {'alpha': alpha,
+                        'verbose': verbose,
+                        'expand_search': expand_search,
+                        'data_origin': data_origin,
+                        'mesh_origin': mesh_origin,
+                        'precrop': precrop},
+                       verbose = verbose)        
+        
+    else:
+        interp = Interpolation(vertex_coordinates,
+                               triangles,
+                               point_coordinates,
+                               alpha = alpha,
+                               verbose = verbose,
+                               expand_search = expand_search,
+                               data_origin = data_origin,
+                               mesh_origin = mesh_origin,
+                               precrop = precrop)
+
+    vertex_attributes = interp.fit_points(point_attributes, verbose = verbose)
+
+
+    #Sanity check
+    point_coordinates = ensure_numeric(point_coordinates)
+    vertex_coordinates = ensure_numeric(vertex_coordinates)
+
+    #Data points
+    X = point_coordinates[:,0]
+    Y = point_coordinates[:,1]	
+    Z = ensure_numeric(point_attributes)
+    if len(Z.shape) == 1:
+        Z = Z[:, NewAxis]
+        
+
+    #Data points inside mesh boundary
+    indices = interp.point_indices
+    if indices is not None:    
+        Xc = take(X, indices)
+        Yc = take(Y, indices)	
+        Zc = take(Z, indices)
+    else:
+        Xc = X
+        Yc = Y	
+        Zc = Z        
+    
+    #Vertex coordinates
+    Xi = vertex_coordinates[:,0]
+    Eta = vertex_coordinates[:,1]	
+    Zeta = ensure_numeric(vertex_attributes)
+    if len(Zeta.shape) == 1:
+        Zeta = Zeta[:, NewAxis]    
+
+    for i in range(Zeta.shape[1]): #For each attribute
+        zeta = Zeta[:,i]
+        z = Z[:,i]                
+        zc = Zc[:,i]
+
+        max_zc = max(zc)
+        min_zc = min(zc)
+        delta_zc = max_zc-min_zc
+        upper_limit = max_zc + delta_zc*acceptable_overshoot
+        lower_limit = min_zc - delta_zc*acceptable_overshoot        
+        
+
+        if max(zeta) > upper_limit or min(zeta) < lower_limit:
+            msg = 'Least sqares produced values outside the allowed '
+            msg += 'range [%f, %f].\n' %(lower_limit, upper_limit)
+            msg += 'z in [%f, %f], zeta in [%f, %f].\n' %(min_zc, max_zc,
+                                                          min(zeta), max(zeta))
+            msg += 'If greater range is needed, increase the value of '
+            msg += 'acceptable_fit_overshoot (currently %.2f).\n' %(acceptable_overshoot)
+
+
+            offending_vertices = (zeta > upper_limit or zeta < lower_limit)
+            Xi_c = compress(offending_vertices, Xi)
+            Eta_c = compress(offending_vertices, Eta)
+            offending_coordinates = concatenate((Xi_c[:, NewAxis],
+                                                 Eta_c[:, NewAxis]),
+                                                axis=1)
+
+            msg += 'Offending locations:\n %s' %(offending_coordinates)
+            
+            raise FittingError, msg
+
+
+    
+        if verbose:
+            print '+------------------------------------------------'
+            print 'Least squares statistics'
+            print '+------------------------------------------------'	
+            print 'points: %d points' %(len(z))
+            print '    x in [%f, %f]'%(min(X), max(X))
+            print '    y in [%f, %f]'%(min(Y), max(Y))
+            print '    z in [%f, %f]'%(min(z), max(z))
+            print
+
+            if indices is not None:
+                print 'Cropped points: %d points' %(len(zc))
+                print '    x in [%f, %f]'%(min(Xc), max(Xc))
+                print '    y in [%f, %f]'%(min(Yc), max(Yc))
+                print '    z in [%f, %f]'%(min(zc), max(zc))
+                print
+            
+
+            print 'Mesh: %d vertices' %(len(zeta))
+            print '    xi in [%f, %f]'%(min(Xi), max(Xi))
+            print '    eta in [%f, %f]'%(min(Eta), max(Eta))
+            print '    zeta in [%f, %f]'%(min(zeta), max(zeta))
+            print '+------------------------------------------------'
+
+    return vertex_attributes
+
+
+
+def pts2rectangular(pts_name, M, N, alpha = DEFAULT_ALPHA,
+                    verbose = False, reduction = 1):
+    """Fits attributes from pts file to MxN rectangular mesh
+
+    Read pts file and create rectangular mesh of resolution MxN such that
+    it covers all points specified in pts file.
+
+    FIXME: This may be a temporary function until we decide on
+    netcdf formats etc
+
+    FIXME: Uses elevation hardwired
+    """
+
+    import  mesh_factory
+    from load_mesh.loadASCII import import_points_file
+    
+    if verbose: print 'Read pts'
+    points_dict = import_points_file(pts_name)
+    #points, attributes = util.read_xya(pts_name)
+
+    #Reduce number of points a bit
+    points = points_dict['pointlist'][::reduction]
+    elevation = points_dict['attributelist']['elevation']  #Must be elevation
+    elevation = elevation[::reduction]
+
+    if verbose: print 'Got %d data points' %len(points)
+
+    if verbose: print 'Create mesh'
+    #Find extent
+    max_x = min_x = points[0][0]
+    max_y = min_y = points[0][1]
+    for point in points[1:]:
+        x = point[0]
+        if x > max_x: max_x = x
+        if x < min_x: min_x = x
+        y = point[1]
+        if y > max_y: max_y = y
+        if y < min_y: min_y = y
+
+    #Create appropriate mesh
+    vertex_coordinates, triangles, boundary =\
+    	 mesh_factory.rectangular(M, N, max_x-min_x, max_y-min_y,
+	 			(min_x, min_y))
+
+    #Fit attributes to mesh
+    vertex_attributes = fit_to_mesh(vertex_coordinates,
+                	triangles,
+                	points,
+                	elevation, alpha=alpha, verbose=verbose)
+
+
+
+    return vertex_coordinates, triangles, boundary, vertex_attributes
+
+
+def _interpolation(*args, **kwargs):
+    """Private function for use with caching. Reason is that classes
+    may change their byte code between runs which is annoying.
+    """
+    
+    return Interpolation(*args, **kwargs)
+
+
+class Interpolation:
+
+    def __init__(self,
+                 vertex_coordinates,
+                 triangles,
+                 point_coordinates = None,
+                 alpha = None,
+                 verbose = False,
+                 expand_search = True,
+                 interp_only = False,
+                 max_points_per_cell = 30,
+                 mesh_origin = None,
+                 data_origin = None,
+                 precrop = False):
+
+
+        """ Build interpolation matrix mapping from
+        function values at vertices to function values at data points
+
+        Inputs:
+
+          vertex_coordinates: List of coordinate pairs [xi, eta] of
+	  points constituting mesh (or a an m x 2 Numeric array)
+          Points may appear multiple times
+          (e.g. if vertices have discontinuities)
+
+          triangles: List of 3-tuples (or a Numeric array) of
+          integers representing indices of all vertices in the mesh.
+
+          point_coordinates: List of coordinate pairs [x, y] of
+	  data points (or an nx2 Numeric array)
+	  If point_coordinates is absent, only smoothing matrix will
+	  be built
+
+          alpha: Smoothing parameter
+
+          data_origin and mesh_origin are 3-tuples consisting of
+          UTM zone, easting and northing. If specified
+          point coordinates and vertex coordinates are assumed to be
+          relative to their respective origins.
+
+        """
+        #Convert input to Numeric arrays
+        triangles = ensure_numeric(triangles, Int)
+        vertex_coordinates = ensure_numeric(vertex_coordinates, Float)
+
+        #Build underlying mesh
+        if verbose: print 'Building mesh'
+        #self.mesh = General_mesh(vertex_coordinates, triangles,
+        #FIXME: Trying the normal mesh while testing precrop,
+        #       The functionality of boundary_polygon is needed for that
+
+        #FIXME - geo ref does not have to go into mesh.
+        # Change the point co-ords to conform to the
+        # mesh co-ords early in the code
+        if mesh_origin is None:
+            geo = None
+        else:
+            geo = Geo_reference(mesh_origin[0],mesh_origin[1],mesh_origin[2])
+
+                
+        self.mesh = Mesh(vertex_coordinates, triangles,
+                         geo_reference = geo)
+
+        if verbose: print 'Checking mesh integrity'
+        self.mesh.check_integrity()
+
+        if verbose: print 'Mesh integrity checked'
+        
+        self.data_origin = data_origin
+
+        self.point_indices = None
+
+        #Smoothing parameter
+        if alpha is None:
+            self.alpha = DEFAULT_ALPHA
+        else:    
+            self.alpha = alpha
+
+
+        if point_coordinates is not None:
+            if verbose: print 'Building interpolation matrix'
+            self.build_interpolation_matrix_A(point_coordinates,
+                                              verbose = verbose,
+                                              expand_search = expand_search,
+                                              interp_only = interp_only, 
+                                              max_points_per_cell =\
+                                              max_points_per_cell,
+                                              data_origin = data_origin,
+                                              precrop = precrop)
+        #Build coefficient matrices
+        if interp_only == False:
+            self.build_coefficient_matrix_B(point_coordinates,
+                                        verbose = verbose,
+                                        expand_search = expand_search,
+                                        max_points_per_cell =\
+                                        max_points_per_cell,
+                                        data_origin = data_origin,
+                                        precrop = precrop)
+        if verbose: print 'Finished interpolation'
+
+    def set_point_coordinates(self, point_coordinates,
+                              data_origin = None,
+                              verbose = False,
+                              precrop = True):
+        """
+        A public interface to setting the point co-ordinates.
+        """
+        if point_coordinates is not None:
+            if verbose: print 'Building interpolation matrix'
+            self.build_interpolation_matrix_A(point_coordinates,
+                                              verbose = verbose,
+                                              data_origin = data_origin,
+                                              precrop = precrop)
+        self.build_coefficient_matrix_B(point_coordinates, data_origin)
+
+    def build_coefficient_matrix_B(self, point_coordinates=None,
+                                   verbose = False, expand_search = True,
+                                   max_points_per_cell=30,
+                                   data_origin = None,
+                                   precrop = False):
+        """Build final coefficient matrix"""
+
+
+        if self.alpha <> 0:
+            if verbose: print 'Building smoothing matrix'
+            self.build_smoothing_matrix_D()
+
+        if point_coordinates is not None:
+            if self.alpha <> 0:
+                self.B = self.AtA + self.alpha*self.D
+            else:
+                self.B = self.AtA
+
+            #Convert self.B matrix to CSR format for faster matrix vector
+            self.B = Sparse_CSR(self.B)
+
+    def build_interpolation_matrix_A(self, point_coordinates,
+                                     verbose = False, expand_search = True,
+                                     max_points_per_cell=30,
+                                     data_origin = None,
+                                     precrop = False,
+                                     interp_only = False):
+        """Build n x m interpolation matrix, where
+        n is the number of data points and
+        m is the number of basis functions phi_k (one per vertex)
+
+        This algorithm uses a quad tree data structure for fast binning of data points
+        origin is a 3-tuple consisting of UTM zone, easting and northing.
+        If specified coordinates are assumed to be relative to this origin.
+
+        This one will override any data_origin that may be specified in
+        interpolation instance
+
+        """
+
+
+
+        #FIXME (Ole): Check that this function is memeory efficient.
+        #6 million datapoints and 300000 basis functions
+        #causes out-of-memory situation
+        #First thing to check is whether there is room for self.A and self.AtA
+        #
+        #Maybe we need some sort of blocking
+
+        from anuga.abstract_2d_finite_volumes.quad import build_quadtree
+        from anuga.utilities.polygon import inside_polygon
+	
+
+        if data_origin is None:
+            data_origin = self.data_origin #Use the one from
+                                           #interpolation instance
+
+        #Convert input to Numeric arrays just in case.
+        point_coordinates = ensure_numeric(point_coordinates, Float)
+
+        #Keep track of discarded points (if any).
+        #This is only registered if precrop is True
+        self.cropped_points = False
+
+        #Shift data points to same origin as mesh (if specified)
+
+        #FIXME this will shift if there was no geo_ref.
+        #But all this should be removed anyhow.
+        #change coords before this point
+        mesh_origin = self.mesh.geo_reference.get_origin()
+        if point_coordinates is not None:
+            if data_origin is not None:
+                if mesh_origin is not None:
+
+                    #Transformation:
+                    #
+                    #Let x_0 be the reference point of the point coordinates
+                    #and xi_0 the reference point of the mesh.
+                    #
+                    #A point coordinate (x + x_0) is then made relative
+                    #to xi_0 by
+                    #
+                    # x_new = x + x_0 - xi_0
+                    #
+                    #and similarly for eta
+
+                    x_offset = data_origin[1] - mesh_origin[1]
+                    y_offset = data_origin[2] - mesh_origin[2]
+                else: #Shift back to a zero origin
+                    x_offset = data_origin[1]
+                    y_offset = data_origin[2]
+
+                point_coordinates[:,0] += x_offset
+                point_coordinates[:,1] += y_offset
+            else:
+                if mesh_origin is not None:
+                    #Use mesh origin for data points
+                    point_coordinates[:,0] -= mesh_origin[1]
+                    point_coordinates[:,1] -= mesh_origin[2]
+
+
+
+        #Remove points falling outside mesh boundary
+        #This reduced one example from 1356 seconds to 825 seconds
+
+        
+        if precrop is True:
+            from Numeric import take
+
+            if verbose: print 'Getting boundary polygon'
+            P = self.mesh.get_boundary_polygon()
+
+            if verbose: print 'Getting indices inside mesh boundary'
+            indices = inside_polygon(point_coordinates, P, verbose = verbose)
+
+
+            if len(indices) != point_coordinates.shape[0]:
+                self.cropped_points = True
+                if verbose:
+                    print 'Done - %d points outside mesh have been cropped.'\
+                          %(point_coordinates.shape[0] - len(indices))
+
+            point_coordinates = take(point_coordinates, indices)
+            self.point_indices = indices
+
+
+
+
+        #Build n x m interpolation matrix
+        m = self.mesh.coordinates.shape[0] #Nbr of basis functions (1/vertex)
+        n = point_coordinates.shape[0]     #Nbr of data points
+
+        if verbose: print 'Number of datapoints: %d' %n
+        if verbose: print 'Number of basis functions: %d' %m
+
+        #FIXME (Ole): We should use CSR here since mat-mat mult is now OK.
+        #However, Sparse_CSR does not have the same methods as Sparse yet
+        #The tests will reveal what needs to be done
+
+        #
+        #self.A = Sparse_CSR(Sparse(n,m))
+        #self.AtA = Sparse_CSR(Sparse(m,m))
+        self.A = Sparse(n,m)
+        self.AtA = Sparse(m,m)
+
+        #Build quad tree of vertices (FIXME: Is this the right spot for that?)
+        root = build_quadtree(self.mesh,
+                              max_points_per_cell = max_points_per_cell)
+        #root.show()
+        self.expanded_quad_searches = []
+        #Compute matrix elements
+        for i in range(n):
+            #For each data_coordinate point
+
+            if verbose and i%((n+10)/10)==0: print 'Doing %d of %d' %(i, n)
+            x = point_coordinates[i]
+
+            #Find vertices near x
+            candidate_vertices = root.search(x[0], x[1])
+            is_more_elements = True
+
+
+            element_found, sigma0, sigma1, sigma2, k = \
+                           self.search_triangles_of_vertices(candidate_vertices, x)
+            first_expansion = True
+            while not element_found and is_more_elements and expand_search:
+                #if verbose: print 'Expanding search'
+                if first_expansion == True:
+                    self.expanded_quad_searches.append(1)
+                    first_expansion = False
+                else:
+                    end = len(self.expanded_quad_searches) - 1
+                    assert end >= 0
+                    self.expanded_quad_searches[end] += 1
+                candidate_vertices, branch = root.expand_search()
+                if branch == []:
+                    # Searching all the verts from the root cell that haven't
+                    # been searched.  This is the last try
+                    element_found, sigma0, sigma1, sigma2, k = \
+                      self.search_triangles_of_vertices(candidate_vertices, x)
+                    is_more_elements = False
+                else:
+                    element_found, sigma0, sigma1, sigma2, k = \
+                      self.search_triangles_of_vertices(candidate_vertices, x)
+
+                
+	    #Update interpolation matrix A if necessary
+            if element_found is True:
+                #Assign values to matrix A
+
+                j0 = self.mesh.triangles[k,0] #Global vertex id for sigma0
+                j1 = self.mesh.triangles[k,1] #Global vertex id for sigma1
+                j2 = self.mesh.triangles[k,2] #Global vertex id for sigma2
+
+                sigmas = {j0:sigma0, j1:sigma1, j2:sigma2}
+                js     = [j0,j1,j2]
+
+                for j in js:
+                    self.A[i,j] = sigmas[j]
+                    for k in js:
+                        if interp_only == False:
+                            self.AtA[j,k] += sigmas[j]*sigmas[k]
+            else:
+                pass
+                #Ok if there is no triangle for datapoint
+		#(as in brute force version)
+                #raise 'Could not find triangle for point', x
+
+
+
+    def search_triangles_of_vertices(self, candidate_vertices, x):
+
+            
+            #Find triangle containing x:
+            element_found = False
+
+            # This will be returned if element_found = False
+            sigma2 = -10.0
+            sigma0 = -10.0
+            sigma1 = -10.0
+            k = -10.0
+            #print "*$* candidate_vertices", candidate_vertices
+	    #For all vertices in same cell as point x
+            for v in candidate_vertices:
+                #FIXME (DSG-DSG): this catches verts with no triangle.
+                #Currently pmesh is producing these.
+                #this should be stopped, 
+                if self.mesh.vertexlist[v] is None:
+                    continue
+                #for each triangle id (k) which has v as a vertex
+		for k, _ in self.mesh.vertexlist[v]:
+
+                    #Get the three vertex_points of candidate triangle
+                    xi0 = self.mesh.get_vertex_coordinate(k, 0)
+                    xi1 = self.mesh.get_vertex_coordinate(k, 1)
+                    xi2 = self.mesh.get_vertex_coordinate(k, 2)
+
+                    #print "PDSG - k", k
+                    #print "PDSG - xi0", xi0
+                    #print "PDSG - xi1", xi1
+                    #print "PDSG - xi2", xi2
+                    #print "PDSG element %i verts((%f, %f),(%f, %f),(%f, %f))"\
+                    #   % (k, xi0[0], xi0[1], xi1[0], xi1[1], xi2[0], xi2[1])
+
+                    #Get the three normals
+                    n0 = self.mesh.get_normal(k, 0)
+                    n1 = self.mesh.get_normal(k, 1)
+                    n2 = self.mesh.get_normal(k, 2)
+
+
+                    #Compute interpolation
+                    sigma2 = dot((x-xi0), n2)/dot((xi2-xi0), n2)
+                    sigma0 = dot((x-xi1), n0)/dot((xi0-xi1), n0)
+                    sigma1 = dot((x-xi2), n1)/dot((xi1-xi2), n1)
+
+                    #print "PDSG - sigma0", sigma0
+                    #print "PDSG - sigma1", sigma1
+                    #print "PDSG - sigma2", sigma2
+
+                    #FIXME: Maybe move out to test or something
+                    epsilon = 1.0e-6
+                    assert abs(sigma0 + sigma1 + sigma2 - 1.0) < epsilon
+
+                    #Check that this triangle contains the data point
+
+                    #Sigmas can get negative within
+                    #machine precision on some machines (e.g nautilus)
+                    #Hence the small eps
+                    eps = 1.0e-15
+                    if sigma0 >= -eps and sigma1 >= -eps and sigma2 >= -eps:
+                        element_found = True
+                        break
+
+                if element_found is True:
+                    #Don't look for any other triangle
+                    break
+            return element_found, sigma0, sigma1, sigma2, k
+
+
+
+    def build_interpolation_matrix_A_brute(self, point_coordinates):
+        """Build n x m interpolation matrix, where
+        n is the number of data points and
+        m is the number of basis functions phi_k (one per vertex)
+
+        This is the brute force which is too slow for large problems,
+	but could be used for testing
+        """
+
+
+        #Convert input to Numeric arrays
+        point_coordinates = ensure_numeric(point_coordinates, Float)
+
+        #Build n x m interpolation matrix
+        m = self.mesh.coordinates.shape[0] #Nbr of basis functions (1/vertex)
+        n = point_coordinates.shape[0]     #Nbr of data points
+
+        self.A = Sparse(n,m)
+        self.AtA = Sparse(m,m)
+
+        #Compute matrix elements
+        for i in range(n):
+            #For each data_coordinate point
+
+            x = point_coordinates[i]
+            element_found = False
+            k = 0
+            while not element_found and k < len(self.mesh):
+                #For each triangle (brute force)
+                #FIXME: Real algorithm should only visit relevant triangles
+
+                #Get the three vertex_points
+                xi0 = self.mesh.get_vertex_coordinate(k, 0)
+                xi1 = self.mesh.get_vertex_coordinate(k, 1)
+                xi2 = self.mesh.get_vertex_coordinate(k, 2)
+
+                #Get the three normals
+                n0 = self.mesh.get_normal(k, 0)
+                n1 = self.mesh.get_normal(k, 1)
+                n2 = self.mesh.get_normal(k, 2)
+
+                #Compute interpolation
+                sigma2 = dot((x-xi0), n2)/dot((xi2-xi0), n2)
+                sigma0 = dot((x-xi1), n0)/dot((xi0-xi1), n0)
+                sigma1 = dot((x-xi2), n1)/dot((xi1-xi2), n1)
+
+                #FIXME: Maybe move out to test or something
+                epsilon = 1.0e-6
+                assert abs(sigma0 + sigma1 + sigma2 - 1.0) < epsilon
+
+                #Check that this triangle contains data point
+                if sigma0 >= 0 and sigma1 >= 0 and sigma2 >= 0:
+                    element_found = True
+                    #Assign values to matrix A
+
+                    j0 = self.mesh.triangles[k,0] #Global vertex id
+                    #self.A[i, j0] = sigma0
+
+                    j1 = self.mesh.triangles[k,1] #Global vertex id
+                    #self.A[i, j1] = sigma1
+
+                    j2 = self.mesh.triangles[k,2] #Global vertex id
+                    #self.A[i, j2] = sigma2
+
+                    sigmas = {j0:sigma0, j1:sigma1, j2:sigma2}
+                    js     = [j0,j1,j2]
+
+                    for j in js:
+                        self.A[i,j] = sigmas[j]
+                        for k in js:
+                            self.AtA[j,k] += sigmas[j]*sigmas[k]
+                k = k+1
+
+
+
+    def get_A(self):
+        return self.A.todense()
+
+    def get_B(self):
+        return self.B.todense()
+
+    def get_D(self):
+        return self.D.todense()
+
+        #FIXME: Remember to re-introduce the 1/n factor in the
+        #interpolation term
+
+    def build_smoothing_matrix_D(self):
+        """Build m x m smoothing matrix, where
+        m is the number of basis functions phi_k (one per vertex)
+
+        The smoothing matrix is defined as
+
+        D = D1 + D2
+
+        where
+
+        [D1]_{k,l} = \int_\Omega
+           \frac{\partial \phi_k}{\partial x}
+           \frac{\partial \phi_l}{\partial x}\,
+           dx dy
+
+        [D2]_{k,l} = \int_\Omega
+           \frac{\partial \phi_k}{\partial y}
+           \frac{\partial \phi_l}{\partial y}\,
+           dx dy
+
+
+        The derivatives \frac{\partial \phi_k}{\partial x},
+        \frac{\partial \phi_k}{\partial x} for a particular triangle
+        are obtained by computing the gradient a_k, b_k for basis function k
+        """
+
+        #FIXME: algorithm might be optimised by computing local 9x9
+        #"element stiffness matrices:
+
+        m = self.mesh.coordinates.shape[0] #Nbr of basis functions (1/vertex)
+
+        self.D = Sparse(m,m)
+
+        #For each triangle compute contributions to D = D1+D2
+        for i in range(len(self.mesh)):
+
+            #Get area
+            area = self.mesh.areas[i]
+
+            #Get global vertex indices
+            v0 = self.mesh.triangles[i,0]
+            v1 = self.mesh.triangles[i,1]
+            v2 = self.mesh.triangles[i,2]
+
+            #Get the three vertex_points
+            xi0 = self.mesh.get_vertex_coordinate(i, 0)
+            xi1 = self.mesh.get_vertex_coordinate(i, 1)
+            xi2 = self.mesh.get_vertex_coordinate(i, 2)
+
+            #Compute gradients for each vertex
+            a0, b0 = gradient(xi0[0], xi0[1], xi1[0], xi1[1], xi2[0], xi2[1],
+                              1, 0, 0)
+
+            a1, b1 = gradient(xi0[0], xi0[1], xi1[0], xi1[1], xi2[0], xi2[1],
+                              0, 1, 0)
+
+            a2, b2 = gradient(xi0[0], xi0[1], xi1[0], xi1[1], xi2[0], xi2[1],
+                              0, 0, 1)
+
+            #Compute diagonal contributions
+            self.D[v0,v0] += (a0*a0 + b0*b0)*area
+            self.D[v1,v1] += (a1*a1 + b1*b1)*area
+            self.D[v2,v2] += (a2*a2 + b2*b2)*area
+
+            #Compute contributions for basis functions sharing edges
+            e01 = (a0*a1 + b0*b1)*area
+            self.D[v0,v1] += e01
+            self.D[v1,v0] += e01
+
+            e12 = (a1*a2 + b1*b2)*area
+            self.D[v1,v2] += e12
+            self.D[v2,v1] += e12
+
+            e20 = (a2*a0 + b2*b0)*area
+            self.D[v2,v0] += e20
+            self.D[v0,v2] += e20
+
+
+    def fit(self, z):
+        """Fit a smooth surface to given 1d array of data points z.
+
+        The smooth surface is computed at each vertex in the underlying
+        mesh using the formula given in the module doc string.
+
+        Pre Condition:
+          self.A, self.AtA and self.B have been initialised
+
+        Inputs:
+          z: Single 1d vector or array of data at the point_coordinates.
+        """
+        
+        #Convert input to Numeric arrays
+        z = ensure_numeric(z, Float)
+
+        if len(z.shape) > 1 :
+            raise VectorShapeError, 'Can only deal with 1d data vector'
+
+        if self.point_indices is not None:
+            #Remove values for any points that were outside mesh
+            z = take(z, self.point_indices)
+
+        #Compute right hand side based on data
+        #FIXME (DSG-DsG): could Sparse_CSR be used here?  Use this format
+        # after a matrix is built, before calcs.
+        Atz = self.A.trans_mult(z)
+
+
+        #Check sanity
+        n, m = self.A.shape
+        if n<m and self.alpha == 0.0:
+            msg = 'ERROR (least_squares): Too few data points\n'
+            msg += 'There are only %d data points and alpha == 0. ' %n
+	    msg += 'Need at least %d\n' %m
+            msg += 'Alternatively, set smoothing parameter alpha to a small '
+	    msg += 'positive value,\ne.g. 1.0e-3.'
+            raise Exception(msg)
+
+
+
+        return conjugate_gradient(self.B, Atz, Atz, imax=2*len(Atz) )
+        #FIXME: Should we store the result here for later use? (ON)
+
+
+    def fit_points(self, z, verbose=False):
+        """Like fit, but more robust when each point has two or more attributes
+	FIXME (Ole): The name fit_points doesn't carry any meaning
+	for me. How about something like fit_multiple or fit_columns?
+        """
+
+        try:
+            if verbose: print 'Solving penalised least_squares problem'
+            return self.fit(z)
+        except VectorShapeError, e:
+            # broadcasting is not supported.
+
+            #Convert input to Numeric arrays
+            z = ensure_numeric(z, Float)
+
+            #Build n x m interpolation matrix
+            m = self.mesh.coordinates.shape[0] #Number of vertices
+            n = z.shape[1]                     #Number of data points
+
+            f = zeros((m,n), Float) #Resulting columns
+
+            for i in range(z.shape[1]):
+                f[:,i] = self.fit(z[:,i])
+
+            return f
+
+
+    def interpolate(self, f):
+        """Evaluate smooth surface f at data points implied in self.A.
+
+        The mesh values representing a smooth surface are
+        assumed to be specified in f. This argument could,
+        for example have been obtained from the method self.fit()
+
+        Pre Condition:
+          self.A has been initialised
+
+        Inputs:
+          f: Vector or array of data at the mesh vertices.
+          If f is an array, interpolation will be done for each column as
+          per underlying matrix-matrix multiplication
+
+	Output:
+	  Interpolated values at data points implied in self.A
+
+        """
+        print "obsolete in least_squares, use fit_interpolate.interpolate"
+        return self.A * f
+
+    def cull_outsiders(self, f):
+        pass
+
+
+
+
+class Interpolation_function:
+    """Interpolation_function - creates callable object f(t, id) or f(t,x,y)
+    which is interpolated from time series defined at vertices of
+    triangular mesh (such as those stored in sww files)
+
+    Let m be the number of vertices, n the number of triangles
+    and p the number of timesteps. 
+
+    Mandatory input
+        time:               px1 array of monotonously increasing times (Float)
+        quantities:         Dictionary of arrays or 1 array (Float) 
+                            The arrays must either have dimensions pxm or mx1.
+                            The resulting function will be time dependent in
+                            the former case while it will be constant with
+                            respect to time in the latter case.
+        
+    Optional input:
+        quantity_names:     List of keys into the quantities dictionary 
+        vertex_coordinates: mx2 array of coordinates (Float)
+        triangles:          nx3 array of indices into vertex_coordinates (Int)
+        interpolation_points: Nx2 array of coordinates to be interpolated to 
+        verbose:            Level of reporting
+    
+    
+    The quantities returned by the callable object are specified by
+    the list quantities which must contain the names of the
+    quantities to be returned and also reflect the order, e.g. for
+    the shallow water wave equation, on would have
+    quantities = ['stage', 'xmomentum', 'ymomentum']
+
+    The parameter interpolation_points decides at which points interpolated
+    quantities are to be computed whenever object is called.
+    If None, return average value
+    """
+
+    
+    
+    def __init__(self,
+                 time,
+                 quantities,
+                 quantity_names = None,  
+                 vertex_coordinates = None,
+                 triangles = None,
+                 interpolation_points = None,
+                 verbose = False):
+        """Initialise object and build spatial interpolation if required
+        """
+
+        from Numeric import array, zeros, Float, alltrue, concatenate,\
+             reshape, ArrayType
+
+
+        from anuga.config import time_format
+        import types
+
+
+
+	#Check temporal info
+        time = ensure_numeric(time)        
+        msg = 'Time must be a monotonuosly '
+        msg += 'increasing sequence %s' %time
+        assert alltrue(time[1:] - time[:-1] >= 0 ), msg
+
+
+        #Check if quantities is a single array only
+        if type(quantities) != types.DictType:
+            quantities = ensure_numeric(quantities)
+            quantity_names = ['Attribute']
+
+            #Make it a dictionary
+            quantities = {quantity_names[0]: quantities}
+
+
+        #Use keys if no names are specified
+        if quantity_names is None:
+            quantity_names = quantities.keys()
+
+
+        #Check spatial info
+        if vertex_coordinates is None:
+            self.spatial = False
+        else:    
+            vertex_coordinates = ensure_numeric(vertex_coordinates)
+
+            assert triangles is not None, 'Triangles array must be specified'
+            triangles = ensure_numeric(triangles)
+            self.spatial = True            
+            
+
+  
+        #Save for use with statistics
+        self.quantity_names = quantity_names        
+        self.quantities = quantities        
+        self.vertex_coordinates = vertex_coordinates 
+        self.interpolation_points = interpolation_points
+        self.time = time[:]  # Time assumed to be relative to starttime
+        self.index = 0    # Initial time index
+        self.precomputed_values = {}
+            
+
+
+        #Precomputed spatial interpolation if requested
+        if interpolation_points is not None:
+            if self.spatial is False:
+                raise 'Triangles and vertex_coordinates must be specified'
+            
+            try:
+	        self.interpolation_points = ensure_numeric(interpolation_points)
+            except:
+	        msg = 'Interpolation points must be an N x 2 Numeric array '+\
+                      'or a list of points\n'
+		msg += 'I got: %s.' %(str(self.interpolation_points)[:60] +\
+                                      '...')
+                raise msg
+
+
+            m = len(self.interpolation_points)
+            p = len(self.time)
+            
+	    for name in quantity_names:
+                self.precomputed_values[name] = zeros((p, m), Float)
+
+            #Build interpolator
+            interpol = Interpolation(vertex_coordinates,
+                                     triangles,
+                                     point_coordinates = \
+                                     self.interpolation_points,
+                                     alpha = 0,
+                                     precrop = False, 
+                                     verbose = verbose)
+
+            if verbose: print 'Interpolate'
+	    for i, t in enumerate(self.time):
+                #Interpolate quantities at this timestep
+                if verbose and i%((p+10)/10)==0:
+                    print ' time step %d of %d' %(i, p)
+                    
+                for name in quantity_names:
+                    if len(quantities[name].shape) == 2:
+                        result = interpol.interpolate(quantities[name][i,:])
+                    else:
+                       #Assume no time dependency 
+                       result = interpol.interpolate(quantities[name][:])
+                       
+                    self.precomputed_values[name][i, :] = result
+                   
+                        
+
+            #Report
+            if verbose:
+                print self.statistics()
+                #self.print_statistics()
+            
+        else:
+            #Store quantitites as is
+	    for name in quantity_names:
+                self.precomputed_values[name] = quantities[name]
+
+
+        #else:
+        #    #Return an average, making this a time series
+	#    for name in quantity_names:
+        #        self.values[name] = zeros(len(self.time), Float)
+        #
+        #    if verbose: print 'Compute mean values'
+	#    for i, t in enumerate(self.time):
+        #        if verbose: print ' time step %d of %d' %(i, len(self.time))
+        #        for name in quantity_names:
+	#	    self.values[name][i] = mean(quantities[name][i,:])
+
+
+
+
+    def __repr__(self):
+        #return 'Interpolation function (spatio-temporal)'
+        return self.statistics()
+    
+
+    def __call__(self, t, point_id = None, x = None, y = None):
+        """Evaluate f(t), f(t, point_id) or f(t, x, y)
+
+	Inputs:
+	  t: time - Model time. Must lie within existing timesteps
+	  point_id: index of one of the preprocessed points.
+          x, y:     Overrides location, point_id ignored
+          
+	  If spatial info is present and all of x,y,point_id
+          are None an exception is raised 
+                    
+          If no spatial info is present, point_id and x,y arguments are ignored
+          making f a function of time only.
+
+          
+	  FIXME: point_id could also be a slice
+	  FIXME: What if x and y are vectors?
+          FIXME: What about f(x,y) without t?
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import zeros, Float
+        from anuga.utilities.numerical_tools import mean        
+
+        if self.spatial is True:
+            if point_id is None:
+                if x is None or y is None:
+                    msg = 'Either point_id or x and y must be specified'
+                    raise Exception(msg)
+            else:
+                if self.interpolation_points is None:
+                    msg = 'Interpolation_function must be instantiated ' +\
+                          'with a list of interpolation points before parameter ' +\
+                          'point_id can be used'
+                    raise Exception(msg)
+
+
+        msg = 'Time interval [%s:%s]' %(self.time[0], self.time[-1])
+        msg += ' does not match model time: %s\n' %t
+        if t < self.time[0]: raise Exception(msg)
+        if t > self.time[-1]: raise Exception(msg)
+
+        oldindex = self.index #Time index
+
+        #Find current time slot
+        while t > self.time[self.index]: self.index += 1
+        while t < self.time[self.index]: self.index -= 1
+
+        if t == self.time[self.index]:
+            #Protect against case where t == T[-1] (last time)
+            # - also works in general when t == T[i]
+            ratio = 0
+        else:
+            #t is now between index and index+1
+            ratio = (t - self.time[self.index])/\
+                    (self.time[self.index+1] - self.time[self.index])
+
+        #Compute interpolated values
+        q = zeros(len(self.quantity_names), Float)
+
+	for i, name in enumerate(self.quantity_names):
+            Q = self.precomputed_values[name]
+
+            if self.spatial is False:
+                #If there is no spatial info                
+                assert len(Q.shape) == 1
+
+                Q0 = Q[self.index]
+                if ratio > 0: Q1 = Q[self.index+1]
+
+            else:
+                if x is not None and y is not None:
+                    #Interpolate to x, y
+                    
+                    raise 'x,y interpolation not yet implemented'
+                else:
+                    #Use precomputed point
+                    Q0 = Q[self.index, point_id]
+                    if ratio > 0: Q1 = Q[self.index+1, point_id]
+
+            #Linear temporal interpolation    
+            if ratio > 0:
+                q[i] = Q0 + ratio*(Q1 - Q0)
+            else:
+                q[i] = Q0
+
+
+        #Return vector of interpolated values
+        #if len(q) == 1:
+        #    return q[0]
+        #else:
+        #    return q
+
+
+        #Return vector of interpolated values
+        #FIXME:
+        if self.spatial is True:
+            return q
+        else:
+            #Replicate q according to x and y
+            #This is e.g used for Wind_stress
+            if x is None or y is None: 
+                return q
+            else:
+                try:
+                    N = len(x)
+                except:
+                    return q
+                else:
+                    from Numeric import ones, Float
+                    #x is a vector - Create one constant column for each value
+                    N = len(x)
+                    assert len(y) == N, 'x and y must have same length'
+                    res = []
+                    for col in q:
+                        res.append(col*ones(N, Float))
+                        
+                return res
+            
+    def get_time(self):
+        """Return model time as a vector of timesteps
+        """
+        return self.time
+
+
+    def statistics(self):
+        """Output statistics about interpolation_function
+        """
+        
+        vertex_coordinates = self.vertex_coordinates
+        interpolation_points = self.interpolation_points               
+        quantity_names = self.quantity_names
+        quantities = self.quantities
+        precomputed_values = self.precomputed_values                 
+                
+        x = vertex_coordinates[:,0]
+        y = vertex_coordinates[:,1]                
+
+        str =  '------------------------------------------------\n'
+        str += 'Interpolation_function (spatio-temporal) statistics:\n'
+        str += '  Extent:\n'
+        str += '    x in [%f, %f], len(x) == %d\n'\
+               %(min(x), max(x), len(x))
+        str += '    y in [%f, %f], len(y) == %d\n'\
+               %(min(y), max(y), len(y))
+        str += '    t in [%f, %f], len(t) == %d\n'\
+               %(min(self.time), max(self.time), len(self.time))
+        str += '  Quantities:\n'
+        for name in quantity_names:
+            q = quantities[name][:].flat
+            str += '    %s in [%f, %f]\n' %(name, min(q), max(q))
+
+        if interpolation_points is not None:    
+            str += '  Interpolation points (xi, eta):'\
+                   ' number of points == %d\n' %interpolation_points.shape[0]
+            str += '    xi in [%f, %f]\n' %(min(interpolation_points[:,0]),
+                                            max(interpolation_points[:,0]))
+            str += '    eta in [%f, %f]\n' %(min(interpolation_points[:,1]),
+                                             max(interpolation_points[:,1]))
+            str += '  Interpolated quantities (over all timesteps):\n'
+        
+            for name in quantity_names:
+                q = precomputed_values[name][:].flat
+                str += '    %s at interpolation points in [%f, %f]\n'\
+                       %(name, min(q), max(q))
+        str += '------------------------------------------------\n'
+
+        return str
+
+        #FIXME: Delete
+        #print '------------------------------------------------'
+        #print 'Interpolation_function statistics:'
+        #print '  Extent:'
+        #print '    x in [%f, %f], len(x) == %d'\
+        #      %(min(x), max(x), len(x))
+        #print '    y in [%f, %f], len(y) == %d'\
+        #      %(min(y), max(y), len(y))
+        #print '    t in [%f, %f], len(t) == %d'\
+        #      %(min(self.time), max(self.time), len(self.time))
+        #print '  Quantities:'
+        #for name in quantity_names:
+        #    q = quantities[name][:].flat
+        #    print '    %s in [%f, %f]' %(name, min(q), max(q))
+        #print '  Interpolation points (xi, eta):'\
+        #      ' number of points == %d ' %interpolation_points.shape[0]
+        #print '    xi in [%f, %f]' %(min(interpolation_points[:,0]),
+        #                             max(interpolation_points[:,0]))
+        #print '    eta in [%f, %f]' %(min(interpolation_points[:,1]),
+        #                              max(interpolation_points[:,1]))
+        #print '  Interpolated quantities (over all timesteps):'
+        #
+        #for name in quantity_names:
+        #    q = precomputed_values[name][:].flat
+        #    print '    %s at interpolation points in [%f, %f]'\
+        #          %(name, min(q), max(q))
+        #print '------------------------------------------------'
+
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    """
+    Load in a mesh and data points with attributes.
+    Fit the attributes to the mesh.
+    Save a new mesh file.
+    """
+    import os, sys
+    usage = "usage: %s mesh_input.tsh point.xya mesh_output.tsh [expand|no_expand][vervose|non_verbose] [alpha] [display_errors|no_display_errors]"\
+            %os.path.basename(sys.argv[0])
+
+    if len(sys.argv) < 4:
+        print usage
+    else:
+        mesh_file = sys.argv[1]
+        point_file = sys.argv[2]
+        mesh_output_file = sys.argv[3]
+
+        expand_search = False
+        if len(sys.argv) > 4:
+            if sys.argv[4][0] == "e" or sys.argv[4][0] == "E":
+                expand_search = True
+            else:
+                expand_search = False
+
+        verbose = False
+        if len(sys.argv) > 5:
+            if sys.argv[5][0] == "n" or sys.argv[5][0] == "N":
+                verbose = False
+            else:
+                verbose = True
+
+        if len(sys.argv) > 6:
+            alpha = sys.argv[6]
+        else:
+            alpha = DEFAULT_ALPHA
+
+        # This is used more for testing
+        if len(sys.argv) > 7:
+            if sys.argv[7][0] == "n" or sys.argv[5][0] == "N":
+                display_errors = False
+            else:
+                display_errors = True
+            
+        t0 = time.time()
+        try:
+            fit_to_mesh_file(mesh_file,
+                         point_file,
+                         mesh_output_file,
+                         alpha,
+                         verbose= verbose,
+                         expand_search = expand_search,
+                         display_errors = display_errors)
+        except IOError,e:
+            import sys; sys.exit(1)
+
+        print 'That took %.2f seconds' %(time.time()-t0)
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/log.ini
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/log.ini	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/log.ini	(revision 3560)
@@ -0,0 +1,41 @@
+
+[loggers]
+keys=root,cg_solve,least_squares
+
+[handlers]
+keys=hand01
+
+[formatters]
+keys=form01
+
+#-----------------------------------------------------------------------
+[logger_root]
+level=NOTSET
+handlers=hand01
+
+[logger_cg_solve]
+level=ERROR
+handlers=hand01
+propagate=0
+qualname=cg_solve
+
+[logger_least_squares]
+level=INFO
+handlers=hand01
+propagate=0
+qualname=least_squares
+
+#-----------------------------------------------------------------------
+# Handlers
+[handler_hand01]
+class=StreamHandler
+level=NOTSET
+formatter=form01
+args=(sys.stdout,)
+
+
+#-----------------------------------------------------------------------
+# Formats
+[formatter_form01]
+format=%(name)s_%(levelname)s: %(message)s
+datefmt=
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/lowres2.poly
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/lowres2.poly	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/lowres2.poly	(revision 3560)
@@ -0,0 +1,2904 @@
+POINTS
+1: 0 0 0 n(0, 4.37114e-008, -1)
+2: 0 -34.95 -1.52771e-006 n(0, 4.37114e-008, -1)
+3: 0 -69.9 -3.05543e-006 n(0, 4.37114e-008, -1)
+4: 0 -104.85 -4.58314e-006 n(2.34311e-015, 4.37114e-008, -1)
+5: 0 -139.8 -6.11085e-006 n(4.68622e-015, 4.37114e-008, -1)
+6: 0 -174.75 -7.63856e-006 n(0, 4.37114e-008, -1)
+7: 0 -209.7 -9.16628e-006 n(2.34566e-015, 4.37114e-008, -1)
+8: 0 -244.65 -1.0694e-005 n(4.69132e-015, 4.37114e-008, -1)
+9: 0 -279.6 -1.22217e-005 n(4.69473e-015, 4.37114e-008, -1)
+10: 0 -314.55 -1.37494e-005 n(9.38945e-015, 4.37114e-008, -1)
+11: 0 -349.5 -1.52771e-005 n(0, 4.37114e-008, -1)
+12: 0 -384.45 -1.68048e-005 n(0, 4.37114e-008, -1)
+13: 0 -419.4 -1.83326e-005 n(0, 4.37114e-008, -1)
+14: 0 -454.35 -1.98603e-005 n(0, 4.37114e-008, -1)
+15: 0 -489.3 -2.1388e-005 n(0, 4.37114e-008, -1)
+16: 0 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+17: 0 -559.2 -2.44434e-005 n(0, 4.37114e-008, -1)
+18: 34.55 0 0 n(0, 4.37114e-008, -1)
+19: 34.5375 -34.95 -1.52771e-006 n(0, 4.37114e-008, -1)
+20: 34.525 -69.9 -3.05543e-006 n(0, 4.37114e-008, -1)
+21: 34.5125 -104.85 -4.58314e-006 n(0, 4.37114e-008, -1)
+22: 34.5 -139.8 -6.11085e-006 n(2.34311e-015, 4.37114e-008, -1)
+23: 34.4875 -174.75 -7.63856e-006 n(1.17156e-015, 4.37114e-008, -1)
+24: 34.475 -209.7 -9.16628e-006 n(1.17283e-015, 4.37114e-008, -1)
+25: 34.4625 -244.65 -1.0694e-005 n(7.03782e-015, 4.37114e-008, -1)
+26: 34.45 -279.6 -1.22217e-005 n(5.86585e-015, 4.37114e-008, -1)
+27: 34.4375 -314.55 -1.37494e-005 n(4.69472e-015, 4.37114e-008, -1)
+28: 34.425 -349.5 -1.52771e-005 n(2.34736e-015, 4.37114e-008, -1)
+29: 34.4125 -384.45 -1.68048e-005 n(0, 4.37114e-008, -1)
+30: 34.4 -419.4 -1.83326e-005 n(0, 4.37114e-008, -1)
+31: 34.3875 -454.35 -1.98603e-005 n(0, 4.37114e-008, -1)
+32: 34.375 -489.3 -2.1388e-005 n(0, 4.37114e-008, -1)
+33: 34.3625 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+34: 34.35 -559.2 -2.44434e-005 n(0, 4.37114e-008, -1)
+35: 69.1 0 0 n(0, 4.37114e-008, -1)
+36: 69.075 -34.95 -1.52771e-006 n(0, 4.37114e-008, -1)
+37: 69.05 -69.9 -3.05543e-006 n(0, 4.37114e-008, -1)
+38: 69.025 -104.85 -4.58314e-006 n(0, 4.37114e-008, -1)
+39: 69 -139.8 -6.11085e-006 n(-1.60774e-015, 4.37114e-008, -1)
+40: 68.975 -174.75 -7.63856e-006 n(-1.57137e-016, 4.37114e-008, -1)
+41: 68.95 -209.7 -9.16628e-006 n(3.61246e-014, 4.37114e-008, -1)
+42: 68.925 -244.65 -1.0694e-005 n(-4.32124e-015, 4.37114e-008, -1)
+43: 68.9 -279.6 -1.22217e-005 n(1.75873e-015, 4.37114e-008, -1)
+44: 68.875 -314.55 -1.37494e-005 n(2.34651e-015, 4.37114e-008, -1)
+45: 68.85 -349.5 -1.52771e-005 n(0, 4.37114e-008, -1)
+46: 68.825 -384.45 -1.68048e-005 n(0, 4.37114e-008, -1)
+47: 68.8 -419.4 -1.83326e-005 n(0, 4.37114e-008, -1)
+48: 68.775 -454.35 -1.98603e-005 n(0, 4.37114e-008, -1)
+49: 68.75 -489.3 -2.1388e-005 n(0, 4.37114e-008, -1)
+50: 68.725 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+51: 68.7 -559.2 -2.44434e-005 n(0, 4.37114e-008, -1)
+52: 103.65 0 0 n(0, 4.37114e-008, -1)
+53: 103.613 -34.95 -1.52771e-006 n(7.32541e-015, 4.37114e-008, -1)
+54: 103.575 -69.9 -3.05543e-006 n(-5.47884e-016, 4.37114e-008, -1)
+55: 103.538 -104.85 -4.58314e-006 n(4.51931e-016, 4.37114e-008, -1)
+56: 103.5 -139.8 -6.11085e-006 n(4.48848e-015, 4.37114e-008, -1)
+57: 104.895 -174.217 165 n(-1.33357e-010, 2.45873e-007, -1)
+58: 104.853 -205.259 165 n(7.94903e-008, 2.27232e-007, -1)
+59: 103.387 -244.65 -1.0694e-005 n(5.01217e-014, 4.37114e-008, -1)
+60: 103.35 -279.6 -1.22217e-005 n(1.83524e-021, 4.37114e-008, -1)
+61: 103.312 -314.55 -1.37494e-005 n(-2.05356e-015, 4.37114e-008, -1)
+62: 103.275 -349.5 -1.52771e-005 n(0, 4.37114e-008, -1)
+63: 103.237 -384.45 -1.68048e-005 n(0, 4.37114e-008, -1)
+64: 103.2 -419.4 -1.83326e-005 n(0, 4.37114e-008, -1)
+65: 103.162 -454.35 -1.98603e-005 n(0, 4.37114e-008, -1)
+66: 103.125 -489.3 -2.1388e-005 n(0, 4.37114e-008, -1)
+67: 103.087 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+68: 103.05 -559.2 -2.44434e-005 n(0, 4.37114e-008, -1)
+69: 138.2 0 0 n(0, 4.37114e-008, -1)
+70: 138.15 -34.95 -1.52771e-006 n(-2.93141e-015, 4.37114e-008, -1)
+71: 138.873 -80.9828 165 n(0, 0, -1)
+72: 138.835 -112.162 165 n(0, 0, -1)
+73: 138.792 -143.216 165 n(0, 0, -1)
+74: 138.744 -174.212 165 n(-4.62262e-011, 1.84586e-007, -1)
+75: 138.692 -205.216 165 n(-1.20386e-010, 1.8448e-007, -1)
+76: 137.85 -244.65 -1.0694e-005 n(-4.78508e-015, 4.37114e-008, -1)
+77: 137.8 -279.6 -1.22217e-005 n(-1.55289e-021, 4.37114e-008, -1)
+78: 137.75 -314.55 -1.37494e-005 n(2.05356e-015, 4.37114e-008, -1)
+79: 137.7 -349.5 -1.52771e-005 n(0, 4.37114e-008, -1)
+80: 137.65 -384.45 -1.68048e-005 n(0, 4.37114e-008, -1)
+81: 137.6 -419.4 -1.83326e-005 n(0, 4.37114e-008, -1)
+82: 137.55 -454.35 -1.98603e-005 n(0, 4.37114e-008, -1)
+83: 137.5 -489.3 -2.1388e-005 n(0, 4.37114e-008, -1)
+84: 137.45 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+85: 137.4 -559.2 -2.44434e-005 n(0, 4.37114e-008, -1)
+86: 172.75 0 0 n(0, 4.37114e-008, -1)
+87: 172.688 -34.95 -1.52771e-006 n(0, 4.37114e-008, -1)
+88: 172.625 -69.9 -3.05543e-006 n(1.5312e-015, 4.37114e-008, -1)
+89: 172.702 -112.192 165 n(0, 0, -1)
+90: 172.642 -143.23 165 n(0, 0, -1)
+91: 172.581 -174.209 165 n(1.3773e-011, 2.46183e-007, -1)
+92: 172.519 -205.198 165 n(-3.21444e-011, 2.46157e-007, -1)
+93: 172.456 -236.264 165 n(0, 0, -1)
+94: 172.25 -279.6 -1.22217e-005 n(-1.20264e-015, 4.37114e-008, -1)
+95: 172.187 -314.55 -1.37494e-005 n(-2.05356e-015, 4.37114e-008, -1)
+96: 172.125 -349.5 -1.52771e-005 n(0, 4.37114e-008, -1)
+97: 172.062 -384.45 -1.68048e-005 n(0, 4.37114e-008, -1)
+98: 172 -419.4 -1.83326e-005 n(0, 4.37114e-008, -1)
+99: 171.938 -454.35 -1.98603e-005 n(0, 4.37114e-008, -1)
+100: 171.875 -489.3 -2.1388e-005 n(0, 4.37114e-008, -1)
+101: 171.813 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+102: 171.75 -559.2 -2.44434e-005 n(0, 4.37114e-008, -1)
+103: 207.3 0 0 n(0, 4.37114e-008, -1)
+104: 207.225 -34.95 -1.52771e-006 n(0, 4.37114e-008, -1)
+105: 207.15 -69.9 -3.05543e-006 n(5.36225e-016, 4.37114e-008, -1)
+106: 206.567 -112.18 165 n(0, 0, -1)
+107: 206.49 -143.225 165 n(0, 0, -1)
+108: 206.415 -174.21 165 n(8.90599e-011, 2.46075e-007, -1)
+109: 206.343 -205.205 165 n(9.67019e-011, 2.46166e-007, -1)
+110: 206.274 -236.277 165 n(0, 0, -1)
+111: 206.7 -279.6 -1.22217e-005 n(-4.33861e-015, 4.37114e-008, -1)
+112: 206.625 -314.55 -1.37494e-005 n(2.05356e-015, 4.37114e-008, -1)
+113: 206.55 -349.5 -1.52771e-005 n(0, 4.37114e-008, -1)
+114: 206.475 -384.45 -1.68048e-005 n(0, 4.37114e-008, -1)
+115: 206.4 -419.4 -1.83326e-005 n(0, 4.37114e-008, -1)
+116: 206.325 -454.35 -1.98603e-005 n(0, 4.37114e-008, -1)
+117: 206.25 -489.3 -2.1388e-005 n(0, 4.37114e-008, -1)
+118: 206.175 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+119: 206.1 -559.2 -2.44434e-005 n(0, 4.37113e-008, -1)
+120: 241.85 0 0 n(0, 4.37114e-008, -1)
+121: 241.762 -34.95 -1.52771e-006 n(-5.85353e-016, 4.37114e-008, -1)
+122: 241.675 -69.9 -3.05543e-006 n(-1.89496e-015, 4.37114e-008, -1)
+123: 240.441 -112.127 165 n(0, 0, -1)
+124: 240.346 -143.2 165 n(0, 0, -1)
+125: 240.258 -174.214 165 n(-7.53131e-008, 2.73541e-007, -1)
+126: 240.176 -205.237 165 n(1.80828e-010, 2.10858e-007, -1)
+127: 240.101 -236.337 165 n(0, 0, -1)
+128: 241.15 -279.6 -1.22217e-005 n(1.50732e-013, 4.37114e-008, -1)
+129: 241.062 -314.55 -1.37494e-005 n(-2.05356e-015, 4.37114e-008, -1)
+130: 240.975 -349.5 -1.52771e-005 n(0, 4.37114e-008, -1)
+131: 240.887 -384.45 -1.68048e-005 n(0, 4.37114e-008, -1)
+132: 240.8 -419.4 -1.83326e-005 n(0, 4.37114e-008, -1)
+133: 240.712 -454.35 -1.98603e-005 n(0, 4.37114e-008, -1)
+134: 240.625 -489.3 -2.1388e-005 n(0, 4.37114e-008, -1)
+135: 240.537 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+136: 240.45 -559.2 -2.44434e-005 n(0, 4.37114e-008, -1)
+137: 276.4 0 0 n(0, 4.37114e-008, -1)
+138: 276.3 -34.95 -1.52771e-006 n(5.85353e-016, 4.37114e-008, -1)
+139: 276.2 -69.9 -3.05543e-006 n(-3.88223e-022, 4.37114e-008, -1)
+140: 276.1 -104.85 -4.58314e-006 n(-2.66845e-015, 4.37114e-008, -1)
+141: 274.222 -143.157 165 n(0, 0, -1)
+142: 275.9 -174.75 -7.63856e-006 n(6.20015e-015, 4.37114e-008, -1)
+143: 275.8 -209.7 -9.16628e-006 n(1.78816e-015, 4.37114e-008, -1)
+144: 275.7 -244.65 -1.0694e-005 n(6.52847e-015, 4.37114e-008, -1)
+145: 275.6 -279.6 -1.22217e-005 n(-1.09892e-015, 4.37114e-008, -1)
+146: 284.727 -317.523 330 n(0, 0, -1)
+147: 275.4 -349.5 -1.52771e-005 n(-5.0644e-014, 4.37114e-008, -1)
+148: 275.3 -384.45 -1.68048e-005 n(-7.73044e-015, 4.37114e-008, -1)
+149: 275.2 -419.4 -1.83326e-005 n(0, 4.37114e-008, -1)
+150: 275.1 -454.35 -1.98603e-005 n(0, 4.37114e-008, -1)
+151: 275 -489.3 -2.1388e-005 n(0, 4.37114e-008, -1)
+152: 274.9 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+153: 274.8 -559.2 -2.44434e-005 n(0, 4.37114e-008, -1)
+154: 310.95 0 0 n(0, 4.37114e-008, -1)
+155: 310.838 -34.95 -1.52771e-006 n(0, 4.37114e-008, -1)
+156: 310.725 -69.9 -3.05543e-006 n(1.17071e-015, 4.37114e-008, -1)
+157: 310.612 -104.85 -4.58314e-006 n(-2.12809e-015, 4.37114e-008, -1)
+158: 310.5 -139.8 -6.11085e-006 n(-1.91266e-015, 4.37114e-008, -1)
+159: 310.388 -174.75 -7.63856e-006 n(-1.86232e-015, 4.37114e-008, -1)
+160: 310.275 -209.7 -9.16628e-006 n(0, 4.37114e-008, -1)
+161: 310.162 -244.65 -1.0694e-005 n(-1.60273e-015, 4.37114e-008, -1)
+162: 310.05 -279.6 -1.22217e-005 n(3.7029e-014, 4.37112e-008, -1)
+163: 315.842 -317.543 330 n(0, 0, -1)
+164: 315.747 -349.057 330 n(1.40084e-007, 9.30751e-007, -1)
+165: 315.634 -380.575 330 n(1.4014e-007, 2.76143e-007, -1)
+166: 315.503 -412.129 330 n(0, 0, -1)
+167: 309.487 -454.35 -1.98603e-005 n(-2.81115e-014, 4.37116e-008, -1)
+168: 309.375 -489.3 -2.1388e-005 n(0, 4.37114e-008, -1)
+169: 309.263 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+170: 309.15 -559.2 -2.44434e-005 n(0, 4.37114e-008, -1)
+171: 345.5 0 0 n(0, 4.37114e-008, -1)
+172: 345.375 -34.95 -1.52771e-006 n(0, 4.37114e-008, -1)
+173: 345.25 -69.9 -3.05543e-006 n(0, 4.37114e-008, -1)
+174: 345.125 -104.85 -4.58314e-006 n(1.17155e-015, 4.37114e-008, -1)
+175: 345 -139.8 -6.11085e-006 n(2.34311e-015, 4.37114e-008, -1)
+176: 344.875 -174.75 -7.63856e-006 n(0, 4.37114e-008, -1)
+177: 344.75 -209.7 -9.16628e-006 n(0, 4.37114e-008, -1)
+178: 344.625 -244.65 -1.0694e-005 n(2.0143e-014, 4.37114e-008, -1)
+179: 347.005 -286.026 330 n(0, 0, -1)
+180: 346.904 -317.555 330 n(0, 0, -1)
+181: 346.794 -349.055 330 n(-2.58819e-011, 4.84342e-007, -1)
+182: 346.676 -380.56 330 n(-1.00129e-010, 4.84263e-007, -1)
+183: 346.55 -412.102 330 n(0, 0, -1)
+184: 343.875 -454.35 -1.98603e-005 n(2.06789e-014, 4.37114e-008, -1)
+185: 343.75 -489.3 -2.1388e-005 n(-9.55298e-015, 4.37114e-008, -1)
+186: 343.625 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+187: 343.5 -559.2 -2.44434e-005 n(0, 4.37113e-008, -1)
+188: 380.05 0 0 n(0, 4.37114e-008, -1)
+189: 379.912 -34.95 -1.52771e-006 n(-5.85353e-016, 4.37114e-008, -1)
+190: 379.775 -69.9 -3.05543e-006 n(-1.17071e-015, 4.37114e-008, -1)
+191: 379.638 -104.85 -4.58314e-006 n(0, 4.37114e-008, -1)
+192: 379.5 -139.8 -6.11085e-006 n(2.34311e-015, 4.37114e-008, -1)
+193: 379.362 -174.75 -7.63856e-006 n(1.17156e-015, 4.37114e-008, -1)
+194: 379.225 -209.7 -9.16628e-006 n(0, 4.37114e-008, -1)
+195: 379.087 -244.65 -1.0694e-005 n(-5.71916e-015, 4.37114e-008, -1)
+196: 378.07 -286.031 330 n(0, 0, -1)
+197: 377.942 -317.557 330 n(0, 0, -1)
+198: 377.817 -349.055 330 n(4.90692e-011, 4.84329e-007, -1)
+199: 377.695 -380.558 330 n(2.84239e-011, 4.84355e-007, -1)
+200: 377.575 -412.096 330 n(0, 0, -1)
+201: 378.263 -454.35 -1.98603e-005 n(-2.57693e-015, 4.37113e-008, -1)
+202: 378.125 -489.3 -2.1388e-005 n(0, 4.37114e-008, -1)
+203: 377.987 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+204: 377.85 -559.2 -2.44434e-005 n(0, 4.37114e-008, -1)
+205: 414.6 0 0 n(0, 4.37114e-008, -1)
+206: 414.45 -34.95 -1.52771e-006 n(5.85353e-016, 4.37114e-008, -1)
+207: 414.3 -69.9 -3.05543e-006 n(-1.62348e-021, 4.37114e-008, -1)
+208: 414.15 -104.85 -4.58314e-006 n(-5.85354e-016, 4.37114e-008, -1)
+209: 414 -139.8 -6.11085e-006 n(0, 4.37114e-008, -1)
+210: 413.85 -174.75 -7.63856e-006 n(0, 4.37114e-008, -1)
+211: 413.7 -209.7 -9.16628e-006 n(0, 4.37114e-008, -1)
+212: 413.55 -244.65 -1.0694e-005 n(-7.90579e-015, 4.37115e-008, -1)
+213: 409.142 -286.016 330 n(0, 0, -1)
+214: 408.989 -317.55 330 n(0, 0, -1)
+215: 408.849 -349.056 330 n(1.23367e-010, 4.84157e-007, -1)
+216: 408.722 -380.566 330 n(1.34351e-010, 4.15105e-007, -1)
+217: 408.608 -412.112 330 n(0, 0, -1)
+218: 412.65 -454.35 -1.98603e-005 n(5.20581e-015, 4.37113e-008, -1)
+219: 412.5 -489.3 -2.1388e-005 n(0, 4.37114e-008, -1)
+220: 412.35 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+221: 412.2 -559.2 -2.44434e-005 n(0, 4.37114e-008, -1)
+222: 449.15 0 0 n(0, 4.37114e-008, -1)
+223: 448.987 -34.95 -1.52771e-006 n(0, 4.37114e-008, -1)
+224: 448.825 -69.9 -3.05543e-006 n(1.17071e-015, 4.37114e-008, -1)
+225: 448.662 -104.85 -4.58314e-006 n(5.85353e-016, 4.37114e-008, -1)
+226: 448.5 -139.8 -6.11085e-006 n(0, 4.37114e-008, -1)
+227: 448.337 -174.75 -7.63856e-006 n(0, 4.37114e-008, -1)
+228: 448.175 -209.7 -9.16628e-006 n(-1.17283e-015, 4.37114e-008, -1)
+229: 448.012 -244.65 -1.0694e-005 n(1.24414e-015, 4.37114e-008, -1)
+230: 447.85 -279.6 -1.22217e-005 n(3.2224e-015, 4.37114e-008, -1)
+231: 447.687 -314.55 -1.37494e-005 n(4.49643e-014, 4.37114e-008, -1)
+232: 439.918 -349.058 330 n(-5.71698e-007, 4.45777e-007, -1)
+233: 439.786 -380.587 330 n(2.31382e-010, 4.14912e-007, -1)
+234: 447.2 -419.4 -1.83326e-005 n(-2.02098e-014, 4.37114e-008, -1)
+235: 447.037 -454.35 -1.98603e-005 n(1.46853e-014, 4.37114e-008, -1)
+236: 446.875 -489.3 -2.1388e-005 n(0, 4.37114e-008, -1)
+237: 446.712 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+238: 446.55 -559.2 -2.44434e-005 n(0, 4.37114e-008, -1)
+239: 483.7 0 0 n(0, 4.37114e-008, -1)
+240: 483.525 -34.95 -1.52771e-006 n(0, 4.37114e-008, -1)
+241: 483.35 -69.9 -3.05543e-006 n(0, 4.37114e-008, -1)
+242: 483.175 -104.85 -4.58314e-006 n(0, 4.37114e-008, -1)
+243: 483 -139.8 -6.11085e-006 n(0, 4.37114e-008, -1)
+244: 482.825 -174.75 -7.63856e-006 n(0, 4.37114e-008, -1)
+245: 482.65 -209.7 -9.16628e-006 n(-1.17283e-015, 4.37114e-008, -1)
+246: 482.475 -244.65 -1.0694e-005 n(-7.03783e-015, 4.37114e-008, -1)
+247: 482.3 -279.6 -1.22217e-005 n(-4.10608e-015, 4.37114e-008, -1)
+248: 482.125 -314.55 -1.37494e-005 n(-2.64116e-015, 4.37114e-008, -1)
+249: 481.95 -349.5 -1.52771e-005 n(4.65172e-015, 4.37114e-008, -1)
+250: 481.775 -384.45 -1.68048e-005 n(-1.24439e-014, 4.37114e-008, -1)
+251: 481.6 -419.4 -1.83326e-005 n(-7.38139e-015, 4.37114e-008, -1)
+252: 481.425 -454.35 -1.98603e-005 n(0, 4.37114e-008, -1)
+253: 481.25 -489.3 -2.1388e-005 n(0, 4.37114e-008, -1)
+254: 481.075 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+255: 480.9 -559.2 -2.44434e-005 n(0, 4.37114e-008, -1)
+256: 518.25 0 0 n(0, 4.37114e-008, -1)
+257: 518.063 -34.95 -1.52771e-006 n(0, 4.37114e-008, -1)
+258: 517.875 -69.9 -3.05543e-006 n(0, 4.37114e-008, -1)
+259: 517.688 -104.85 -4.58314e-006 n(-1.17155e-015, 4.37114e-008, -1)
+260: 517.5 -139.8 -6.11085e-006 n(-2.34311e-015, 4.37114e-008, -1)
+261: 517.313 -174.75 -7.63856e-006 n(0, 4.37114e-008, -1)
+262: 517.125 -209.7 -9.16628e-006 n(0, 4.37114e-008, -1)
+263: 516.938 -244.65 -1.0694e-005 n(-2.34566e-015, 4.37114e-008, -1)
+264: 516.75 -279.6 -1.22217e-005 n(-5.86585e-015, 4.37114e-008, -1)
+265: 516.562 -314.55 -1.37494e-005 n(-7.04123e-015, 4.37114e-008, -1)
+266: 516.375 -349.5 -1.52771e-005 n(-2.34736e-015, 4.37114e-008, -1)
+267: 516.188 -384.45 -1.68048e-005 n(0, 4.37114e-008, -1)
+268: 516 -419.4 -1.83326e-005 n(0, 4.37114e-008, -1)
+269: 515.813 -454.35 -1.98603e-005 n(-2.35163e-015, 4.37114e-008, -1)
+270: 515.625 -489.3 -2.1388e-005 n(-4.70326e-015, 4.37114e-008, -1)
+271: 515.438 -524.25 -2.29157e-005 n(0, 4.37114e-008, -1)
+272: 515.25 -559.2 -2.44434e-005 n(0, 4.37114e-008, -1)
+273: 552.8 0 0 n(0, 4.37114e-008, -1)
+274: 552.6 -34.95 -1.52771e-006 n(0, 4.37114e-008, -1)
+275: 552.4 -69.9 -3.05543e-006 n(0, 4.37114e-008, -1)
+276: 552.2 -104.85 -4.58314e-006 n(0, 4.37114e-008, -1)
+277: 552 -139.8 -6.11085e-006 n(-4.68622e-015, 4.37114e-008, -1)
+278: 551.8 -174.75 -7.63856e-006 n(-2.34311e-015, 4.37114e-008, -1)
+279: 551.6 -209.7 -9.16628e-006 n(0, 4.37114e-008, -1)
+280: 551.4 -244.65 -1.0694e-005 n(0, 4.37114e-008, -1)
+281: 551.2 -279.6 -1.22217e-005 n(0, 4.37114e-008, -1)
+282: 551 -314.55 -1.37494e-005 n(0, 4.37114e-008, -1)
+283: 550.8 -349.5 -1.52771e-005 n(0, 4.37114e-008, -1)
+284: 550.6 -384.45 -1.68048e-005 n(0, 4.37114e-008, -1)
+285: 550.4 -419.4 -1.83326e-005 n(0, 4.37114e-008, -1)
+286: 550.2 -454.35 -1.98603e-005 n(0, 4.37114e-008, -1)
+287: 550 -489.3 -2.1388e-005 n(-9.40651e-015, 4.37114e-008, -1)
+288: 549.8 -524.25 -2.29157e-005 n(-4.70325e-015, 4.37114e-008, -1)
+289: 549.6 -559.2 -2.44434e-005 n(0, 4.37115e-008, -1)
+290: 98.407 -169.623 -7.41446e-006 n(0.675672, -0.206837, -0.707591)
+291: 99.9309 -169.665 165 n(0.784837, -0.262653, -0.561288)
+292: 96.8395 -174.75 -7.63856e-006 n(0.675769, -0.206865, -0.707491)
+293: 98.3917 -174.218 165 n(0.667339, -0.223327, -0.710481)
+294: 103.486 -153.011 -6.68831e-006 n(0.794978, -0.243357, -0.555687)
+295: 104.917 -154.917 165 n(0.66567, -0.222721, -0.712235)
+296: 90.2429 -196.327 -8.58171e-006 n(0.795395, -0.243477, -0.555036)
+297: 91.911 -193.391 165 n(0.786821, -0.263221, -0.558236)
+298: 86.1542 -209.7 -9.16628e-006 n(0.67606, -0.206941, -0.70719)
+299: 87.8916 -205.29 165 n(0.568296, -0.189987, -0.80059)
+300: 84.0966 -225.072 -9.83821e-006 n(0.242238, 0.793548, -0.558214)
+301: 85.8644 -218.981 165 n(0.184832, 0.665946, -0.72274)
+302: 82.0802 -223.026 -9.74876e-006 n(0.795613, -0.243533, -0.554699)
+303: 83.8844 -217.163 165 n(0.789205, -0.263659, -0.554652)
+304: 81.6803 -224.333 -9.80592e-006 n(0.335283, 0.352877, -0.873535)
+305: 83.491 -218.33 165 n(0.892307, 0.13728, -0.430049)
+306: 103.402 -230.974 -1.00962e-005 n(0.205754, 0.673975, -0.709523)
+307: 104.823 -224.188 165 n(0.184735, 0.664916, -0.723712)
+308: 134.378 -66.1277 -2.89053e-006 n(-0.205604, -0.672877, -0.710607)
+309: 135.217 -77.5984 165 n(-0.218938, -0.771285, -0.59765)
+310: 128.895 -69.9 -3.05543e-006 n(0.674899, -0.206538, -0.708416)
+311: 129.836 -80.9604 165 n(0.660446, -0.219394, -0.718107)
+312: 130.419 -64.9173 -2.83763e-006 n(0.381545, -0.717682, -0.582542)
+313: 131.33 -76.5043 165 n(0.264955, -0.49949, -0.824808)
+314: 138.104 -67.2669 -2.94033e-006 n(-0.242017, -0.792102, -0.560359)
+315: 138.876 -78.6269 165 n(-0.218764, -0.771612, -0.597292)
+316: 122.904 -89.4957 -3.91198e-006 n(0.7944, -0.243133, -0.55661)
+317: 123.963 -98.4519 165 n(0.778999, -0.259272, -0.57091)
+318: 118.21 -104.85 -4.58314e-006 n(0.675131, -0.206642, -0.708165)
+319: 119.36 -112.127 165 n(0.662351, -0.220865, -0.715898)
+320: 114.737 -116.208 -5.07963e-006 n(0.794652, -0.243241, -0.556204)
+321: 115.955 -122.23 165 n(0.780986, -0.260779, -0.567499)
+322: 107.525 -139.8 -6.11085e-006 n(0.675399, -0.206745, -0.707879)
+323: 108.88 -143.188 165 n(0.664457, -0.222122, -0.713553)
+324: 106.572 -142.917 -6.24708e-006 n(0.794858, -0.243317, -0.555875)
+325: 107.945 -145.955 165 n(0.783142, -0.261951, -0.563978)
+326: 133.419 -240.151 -1.04974e-005 n(0.242118, 0.793022, -0.559013)
+327: 134.288 -232.298 165 n(0.184533, 0.662946, -0.725569)
+328: 137.854 -241.507 -1.05566e-005 n(0.242107, 0.792951, -0.559118)
+329: 138.641 -233.498 165 n(0.217584, 0.780504, -0.586064)
+330: 146.716 -69.9 -3.05543e-006 n(-0.205586, -0.672992, -0.710504)
+331: 147.331 -80.9999 165 n(-0.185104, -0.654512, -0.733042)
+332: 172.611 -77.8167 -3.40148e-006 n(-0.242003, -0.792351, -0.560012)
+333: 172.748 -88.1012 165 n(-0.184767, -0.655995, -0.7318)
+334: 148.133 -244.65 -1.0694e-005 n(0.205672, 0.673538, -0.709962)
+335: 148.729 -236.283 165 n(0.184635, 0.661304, -0.72704)
+336: 172.299 -252.038 -1.10169e-005 n(0.205646, 0.673362, -0.710136)
+337: 172.443 -242.848 165 n(0.217846, 0.778149, -0.589091)
+338: 183.801 -81.2378 -3.55102e-006 n(-0.205599, -0.673259, -0.710248)
+339: 183.73 -91.156 165 n(-0.217538, -0.775259, -0.593002)
+340: 207.11 -88.3643 -3.86253e-006 n(-0.24204, -0.792735, -0.559453)
+341: 206.605 -97.4968 165 n(-0.184183, -0.658693, -0.72952)
+342: 182.715 -255.223 -1.11561e-005 n(0.242062, 0.792476, -0.559811)
+343: 182.664 -245.686 165 n(0.184975, 0.65867, -0.729341)
+344: 206.737 -262.567 -1.14772e-005 n(0.205647, 0.673086, -0.710398)
+345: 206.24 -252.257 165 n(0.218618, 0.775203, -0.592678)
+346: 233.204 -96.342 -4.21124e-006 n(-0.20567, -0.673685, -0.709823)
+347: 232.214 -104.565 165 n(-0.217098, -0.779002, -0.588238)
+348: 241.602 -98.9096 -4.32347e-006 n(-0.242111, -0.7931, -0.558905)
+349: 240.458 -106.835 165 n(-0.217014, -0.780219, -0.586654)
+350: 231.991 -270.288 -1.18147e-005 n(0.242081, 0.792188, -0.560209)
+351: 231.034 -259.21 165 n(0.185772, 0.655369, -0.732107)
+352: 241.17 -271.806 -1.1881e-005 n(-0.674801, 0.206491, -0.708523)
+353: 240.047 -260.597 165 n(-0.778104, 0.258511, -0.572474)
+354: 239.694 -261.65 165 n(-0.371717, 0.700452, -0.609257)
+355: 240.809 -272.984 -1.19325e-005 n(-0.269822, 0.507441, -0.818352)
+356: 261.033 -104.85 -4.58314e-006 n(-0.205745, -0.674018, -0.709485)
+357: 259.534 -112.08 165 n(-0.184119, -0.662881, -0.725733)
+358: 276.087 -109.453 -4.78432e-006 n(-0.242203, -0.79347, -0.558339)
+359: 274.318 -116.138 165 n(-0.18426, -0.66412, -0.724564)
+360: 272.041 -170.829 -7.46719e-006 n(-0.795013, 0.243365, -0.555633)
+361: 270.329 -170.737 165 n(-0.666952, 0.223147, -0.710902)
+362: 270.843 -174.75 -7.63856e-006 n(-0.675498, 0.206777, -0.707775)
+363: 269.152 -174.22 165 n(-0.666462, 0.222964, -0.711418)
+364: 275.948 -158.052 -6.90865e-006 n(-0.675677, 0.206836, -0.707587)
+365: 274.167 -159.382 165 n(-0.786162, 0.262993, -0.55927)
+366: 263.866 -197.57 -8.63608e-006 n(-0.79473, 0.243268, -0.55608)
+367: 262.303 -194.489 165 n(-0.783333, 0.261962, -0.563707)
+368: 260.157 -209.7 -9.16628e-006 n(-0.675219, 0.206678, -0.70807)
+369: 258.665 -205.265 165 n(-0.664231, 0.22197, -0.713811)
+370: 255.692 -224.307 -9.80476e-006 n(-0.794469, 0.243162, -0.556499)
+371: 254.285 -218.25 165 n(-0.781179, 0.260767, -0.567238)
+372: 249.472 -244.65 -1.0694e-005 n(-0.674969, 0.206571, -0.70834)
+373: 248.186 -236.358 165 n(-0.662131, 0.220697, -0.716153)
+374: 247.519 -251.039 -1.09732e-005 n(-0.79426, 0.243061, -0.556842)
+375: 246.271 -242.052 165 n(-0.779163, 0.2593, -0.570674)
+376: 268.604 -307.534 -1.34427e-005 n(0.780645, 0.243269, -0.575686)
+377: 278.482 -311.184 330 n(0.671373, 0.210287, -0.71066)
+378: 270.79 -314.55 -1.37494e-005 n(0.562534, 0.175283, -0.80798)
+379: 280.465 -317.52 330 n(0.79036, 0.24735, -0.56049)
+380: 275.562 -292.748 -1.27964e-005 n(0.243426, -0.781958, -0.573834)
+381: 284.762 -297.839 330 n(0.176711, -0.570616, -0.801979)
+382: 265.022 -296.031 -1.29399e-005 n(0.592213, -0.310964, -0.74336)
+383: 275.225 -300.791 330 n(0.717853, -0.376896, -0.585352)
+384: 275.457 -329.536 -1.44045e-005 n(0.780565, 0.243186, -0.575829)
+385: 284.696 -331.047 330 n(0.790433, 0.247097, -0.560498)
+386: 282.586 -111.439 -4.87117e-006 n(-0.205804, -0.674234, -0.709262)
+387: 280.703 -117.89 165 n(-0.184362, -0.66482, -0.723896)
+388: 288.394 -117.341 -5.12913e-006 n(-0.855109, 0.261901, -0.447433)
+389: 286.407 -123.133 165 n(-0.669934, 0.226001, -0.707186)
+390: 281.528 -139.8 -6.11085e-006 n(-0.675868, 0.206888, -0.70739)
+391: 279.652 -143.148 165 n(-0.568098, 0.189881, -0.800756)
+392: 289.548 -113.568 -4.96421e-006 n(-0.375869, -0.199848, -0.904866)
+393: 287.543 -119.766 165 n(-0.820785, -0.436244, -0.368786)
+394: 280.217 -144.086 -6.29822e-006 n(-0.795242, 0.243433, -0.555275)
+395: 278.363 -146.963 165 n(-0.787017, 0.263203, -0.557968)
+396: 285.482 -289.659 -1.26614e-005 n(0.206621, -0.663641, -0.718949)
+397: 293.731 -295.06 330 n(0.245314, -0.791361, -0.559972)
+398: 310.042 -282.009 -1.2327e-005 n(0.243441, -0.781821, -0.574014)
+399: 315.914 -288.178 330 n(0.208637, -0.672211, -0.710354)
+400: 281.675 -349.5 -1.52771e-005 n(0.780538, 0.243144, -0.575884)
+401: 290.322 -349.059 330 n(0.67156, 0.209638, -0.710675)
+402: 284.591 -358.862 -1.56864e-005 n(0.780541, 0.243108, -0.575894)
+403: 292.956 -357.504 330 n(0.671639, 0.209379, -0.710677)
+404: 292.561 -384.45 -1.68048e-005 n(0.662445, 0.206281, -0.720149)
+405: 300.144 -380.587 330 n(0.790741, 0.24608, -0.560512)
+406: 300.586 -410.215 -1.79311e-005 n(0.780634, 0.243046, -0.575794)
+407: 307.37 -403.841 330 n(0.671863, 0.208671, -0.710674)
+408: 303.447 -419.4 -1.83326e-005 n(0.562595, 0.175139, -0.807968)
+409: 309.944 -412.137 330 n(0.790986, 0.245322, -0.560498)
+410: 309.537 -438.954 -1.91873e-005 n(0.780796, 0.24303, -0.575581)
+411: 315.421 -429.811 330 n(0.791086, 0.245029, -0.560486)
+412: 338.239 -273.227 -1.19431e-005 n(0.206657, -0.663525, -0.719046)
+413: 341.354 -280.268 330 n(0.24612, -0.791094, -0.559996)
+414: 317.777 -279.6 -1.22217e-005 n(0.206642, -0.663549, -0.719028)
+415: 322.895 -286.009 330 n(0.208892, -0.672128, -0.710358)
+416: 344.53 -271.267 -1.18575e-005 n(0.243505, -0.781753, -0.574079)
+417: 347.029 -278.501 330 n(0.209289, -0.672, -0.710362)
+418: 311.86 -281.443 -1.23023e-005 n(0.243446, -0.781811, -0.574026)
+419: 317.555 -287.668 330 n(0.245762, -0.791209, -0.55999)
+420: 337.655 -448.007 -1.9583e-005 n(-0.243112, 0.780149, -0.576424)
+421: 340.806 -437.973 330 n(-0.178457, 0.569689, -0.802252)
+422: 317.291 -454.35 -1.98603e-005 n(-0.206357, 0.662132, -0.720415)
+423: 322.406 -443.739 330 n(-0.247759, 0.790102, -0.560672)
+424: 314.332 -454.35 -1.98603e-005 n(0.780863, 0.243038, -0.575486)
+425: 319.732 -443.744 330 n(0.570423, 0.176469, -0.80217)
+426: 343.905 -446.061 -1.94979e-005 n(-0.206277, 0.662028, -0.720534)
+427: 346.449 -436.206 330 n(-0.247255, 0.790243, -0.560697)
+428: 314.594 -455.19 -1.9897e-005 n(0.0937659, 0.575577, -0.812354)
+429: 319.967 -444.504 330 n(0.655367, 0.628355, -0.419124)
+430: 364.621 -265.01 -1.15839e-005 n(0.206707, -0.663528, -0.719029)
+431: 365.148 -272.854 330 n(0.246614, -0.79094, -0.559997)
+432: 379.025 -260.523 -1.13878e-005 n(0.243573, -0.781781, -0.574013)
+433: 378.141 -268.8 330 n(0.209747, -0.671861, -0.710359)
+434: 364 -439.802 -1.92243e-005 n(-0.243019, 0.780069, -0.576571)
+435: 364.587 -430.535 330 n(-0.209795, 0.671381, -0.710797)
+436: 378.337 -435.336 -1.90292e-005 n(-0.206203, 0.661971, -0.720607)
+437: 377.522 -426.497 330 n(-0.246646, 0.790421, -0.560714)
+438: 391.007 -256.791 -1.12247e-005 n(0.206776, -0.663587, -0.718955)
+439: 388.952 -265.422 330 n(0.247153, -0.790778, -0.559987)
+440: 413.528 -249.777 -1.09181e-005 n(0.24366, -0.781884, -0.573835)
+441: 409.284 -259.061 330 n(0.210202, -0.67173, -0.710348)
+442: 390.35 -431.595 -1.88656e-005 n(-0.24295, 0.780059, -0.576614)
+443: 388.358 -423.118 330 n(-0.209277, 0.671536, -0.710804)
+444: 412.778 -424.609 -1.85603e-005 n(-0.206154, 0.661989, -0.720604)
+445: 408.592 -416.819 330 n(-0.246036, 0.79061, -0.560716)
+446: 417.398 -248.571 -1.08654e-005 n(0.243677, -0.781904, -0.573802)
+447: 412.78 -257.967 330 n(0.210356, -0.671687, -0.710343)
+448: 426.302 -257.644 -1.1262e-005 n(-0.663401, -0.206538, -0.719195)
+449: 420.812 -266.163 330 n(-0.79131, -0.245213, -0.560088)
+450: 433.141 -279.6 -1.22217e-005 n(-0.781534, -0.243367, -0.574437)
+451: 426.963 -285.999 330 n(-0.57044, -0.177045, -0.802031)
+452: 422.939 -246.846 -1.079e-005 n(-0.421463, -0.404944, -0.811412)
+453: 417.787 -256.398 330 n(-0.145376, -0.896708, -0.418068)
+454: 442.324 -309.083 -1.35104e-005 n(-0.663274, -0.20657, -0.719303)
+455: 435.232 -312.605 330 n(-0.791058, -0.24597, -0.560113)
+456: 444.027 -314.55 -1.37494e-005 n(-0.781476, -0.243401, -0.574501)
+457: 436.767 -317.536 330 n(-0.570281, -0.177528, -0.802037)
+458: 447.634 -326.131 -1.42556e-005 n(-0.781475, -0.243435, -0.574488)
+459: 440.02 -327.981 330 n(-0.790909, -0.24644, -0.560117)
+460: 443.061 -415.177 -1.8148e-005 n(-0.242893, 0.780176, -0.576479)
+461: 435.931 -408.328 330 n(-0.208443, 0.671803, -0.710797)
+462: 429.503 -419.4 -1.83326e-005 n(-0.206129, 0.662044, -0.720561)
+463: 423.687 -412.128 330 n(-0.208641, 0.671738, -0.710801)
+464: 447.226 -413.88 -1.80913e-005 n(-0.206117, 0.662132, -0.720484)
+465: 439.693 -407.162 330 n(-0.245171, 0.79089, -0.5607)
+466: 416.705 -423.386 -1.85068e-005 n(-0.242913, 0.780094, -0.576582)
+467: 412.136 -415.717 330 n(-0.245805, 0.790682, -0.560715)
+468: 454.912 -349.5 -1.52771e-005 n(-0.663284, -0.206647, -0.719271)
+469: 446.594 -349.059 330 n(-0.790814, -0.246753, -0.560113)
+470: 458.354 -360.551 -1.57602e-005 n(-0.663321, -0.206687, -0.719226)
+471: 449.707 -359.029 330 n(-0.79072, -0.247065, -0.560107)
+472: 465.798 -384.45 -1.68048e-005 n(-0.781619, -0.243592, -0.574225)
+473: 456.455 -380.602 330 n(-0.570027, -0.17838, -0.802029)
+474: 469.42 -406.967 -1.77891e-005 n(-0.242884, 0.780321, -0.576286)
+475: 459.761 -400.946 330 n(-0.208055, 0.671936, -0.710785)
+476: 462.558 -400.081 330 n(-0.830818, 0.436287, -0.345535)
+477: 472.511 -406.004 -1.7747e-005 n(-0.370056, 0.19425, -0.908474)
+478: 272.361 -315.032 36.6667 n(0.954201, 0.297565, -0.0309082)
+479: 270.206 -308.126 36.6667 n(0.954183, 0.297631, -0.0308294)
+480: 273.417 -315.356 73.3333 n(0.954258, 0.297789, -0.0267171)
+481: 271.284 -308.524 73.3333 n(0.954228, 0.297887, -0.0266739)
+482: 274.631 -315.729 110 n(0.954141, 0.297911, -0.0293972)
+483: 272.524 -308.982 110 n(0.954103, 0.298036, -0.0293537)
+484: 275.915 -316.123 146.667 n(0.95408, 0.298047, -0.0299894)
+485: 273.835 -309.467 146.667 n(0.954034, 0.298198, -0.0299479)
+486: 277.18 -316.511 183.333 n(0.954081, 0.298192, -0.0284993)
+487: 275.127 -309.944 183.333 n(0.954027, 0.298368, -0.028461)
+488: 278.338 -316.867 220 n(0.954131, 0.298337, -0.0250728)
+489: 276.309 -310.381 220 n(0.95407, 0.298535, -0.0250396)
+490: 279.312 -317.166 256.667 n(0.954211, 0.298468, -0.0199769)
+491: 277.303 -310.748 256.667 n(0.954144, 0.298682, -0.0199512)
+492: 280.036 -317.388 293.333 n(0.954291, 0.298571, -0.0135705)
+493: 278.044 -311.022 293.333 n(0.95422, 0.298798, -0.0135529)
+494: 266.673 -296.802 36.6667 n(0.884706, -0.464526, -0.0388595)
+495: 267.786 -297.321 73.3333 n(0.884776, -0.46456, -0.0368249)
+496: 269.067 -297.918 110 n(0.884664, -0.46451, -0.03999)
+497: 270.422 -298.551 146.667 n(0.958715, -0.28155, -0.0399408)
+498: 271.757 -299.173 183.333 n(0.809968, -0.585271, -0.0375432)
+499: 272.98 -299.744 220 n(0.884899, -0.464623, -0.032845)
+500: 274.007 -300.223 256.667 n(0.88509, -0.464714, -0.0256376)
+501: 274.773 -300.58 293.333 n(0.88526, -0.464794, -0.0167475)
+502: 277.054 -293.574 36.6667 n(0.296855, -0.95451, -0.0280646)
+503: 278.059 -294.13 73.3333 n(0.29666, -0.954674, -0.0242795)
+504: 279.213 -294.768 110 n(0.296466, -0.95467, -0.0267179)
+505: 280.435 -295.444 146.667 n(0.296264, -0.954717, -0.0272413)
+506: 281.638 -296.11 183.333 n(0.296168, -0.954784, -0.0259183)
+507: 282.739 -296.719 220 n(0.296026, -0.954908, -0.0227884)
+508: 283.665 -297.232 256.667 n(0.295938, -0.955035, -0.0181559)
+509: 284.354 -297.613 293.333 n(0.295878, -0.955146, -0.0123328)
+510: 286.823 -290.536 36.6667 n(0.296937, -0.954482, -0.0281639)
+511: 287.723 -291.126 73.3333 n(0.296782, -0.954635, -0.0243378)
+512: 288.758 -291.804 110 n(0.296622, -0.954619, -0.0267757)
+513: 289.853 -292.521 146.667 n(0.296435, -0.954663, -0.0272915)
+514: 290.931 -293.226 183.333 n(0.296401, -0.95471, -0.025973)
+515: 291.918 -293.873 220 n(0.296271, -0.954831, -0.0228315)
+516: 292.748 -294.416 256.667 n(0.296206, -0.954951, -0.01819)
+517: 293.366 -294.82 293.333 n(0.296162, -0.955058, -0.0123562)
+518: 311 -283.015 36.6667 n(0.297021, -0.954452, -0.0282928)
+519: 311.641 -283.688 73.3333 n(0.296912, -0.954593, -0.0244058)
+520: 312.377 -284.462 110 n(0.296788, -0.954566, -0.0268438)
+521: 313.156 -285.281 146.667 n(0.296653, -0.954593, -0.0273637)
+522: 313.923 -286.086 183.333 n(0.296633, -0.954637, -0.0260261)
+523: 314.625 -286.823 220 n(0.296537, -0.954747, -0.022882)
+524: 315.215 -287.443 256.667 n(0.296495, -0.95486, -0.0182298)
+525: 315.654 -287.905 293.333 n(0.29647, -0.954962, -0.0123835)
+526: 312.789 -282.458 36.6667 n(0.297064, -0.954437, -0.0283399)
+527: 313.41 -283.138 73.3333 n(0.296989, -0.954569, -0.0244261)
+528: 314.125 -283.919 110 n(0.296882, -0.954536, -0.0268642)
+529: 314.88 -284.745 146.667 n(0.296789, -0.95455, -0.0273949)
+530: 315.624 -285.557 183.333 n(0.296745, -0.954602, -0.0260339)
+531: 316.304 -286.301 220 n(0.296691, -0.954699, -0.0228987)
+532: 316.877 -286.927 256.667 n(0.296661, -0.954808, -0.0182435)
+533: 317.302 -287.393 293.333 n(0.296645, -0.954907, -0.0123925)
+534: 318.612 -280.646 36.6667 n(0.297118, -0.954419, -0.0283638)
+535: 319.171 -281.346 73.3333 n(0.297065, -0.954544, -0.0244411)
+536: 319.813 -282.149 110 n(0.296986, -0.954503, -0.0268797)
+537: 320.492 -283 146.667 n(0.296885, -0.95452, -0.0274057)
+538: 321.16 -283.836 183.333 n(0.296903, -0.954552, -0.0260505)
+539: 321.771 -284.602 220 n(0.296846, -0.95465, -0.0229099)
+540: 322.286 -285.246 256.667 n(0.296833, -0.954755, -0.0182523)
+541: 322.668 -285.725 293.333 n(0.296827, -0.954851, -0.0123984)
+542: 338.747 -274.377 36.6667 n(0.297195, -0.954394, -0.0284048)
+543: 339.088 -275.146 73.3333 n(0.297184, -0.954507, -0.0244629)
+544: 339.479 -276.029 110 n(0.297136, -0.954456, -0.026901)
+545: 339.892 -276.963 146.667 n(0.297066, -0.954463, -0.0274286)
+546: 340.299 -277.882 183.333 n(0.297117, -0.954485, -0.0260681)
+547: 340.671 -278.723 220 n(0.297084, -0.954576, -0.0229264)
+548: 340.984 -279.43 256.667 n(0.297092, -0.954674, -0.018265)
+549: 341.217 -279.957 293.333 n(0.297102, -0.954765, -0.0124073)
+550: 344.938 -272.449 36.6667 n(0.297273, -0.95437, -0.0284186)
+551: 345.211 -273.239 73.3333 n(0.297303, -0.95447, -0.0244678)
+552: 345.524 -274.146 110 n(0.297288, -0.954409, -0.026906)
+553: 345.856 -275.106 146.667 n(0.297251, -0.954405, -0.0274391)
+554: 346.182 -276.05 183.333 n(0.297328, -0.954419, -0.0260665)
+555: 346.48 -276.914 220 n(0.297323, -0.954502, -0.0229305)
+556: 346.731 -277.641 256.667 n(0.297353, -0.954593, -0.0182682)
+557: 346.918 -278.181 293.333 n(0.29738, -0.954679, -0.0124098)
+558: 364.707 -266.291 36.6667 n(0.297363, -0.954342, -0.0284012)
+559: 364.764 -267.147 73.3333 n(0.297439, -0.954427, -0.024456)
+560: 364.831 -268.131 110 n(0.297461, -0.954355, -0.0268944)
+561: 364.901 -269.172 146.667 n(0.297449, -0.954343, -0.0274325)
+562: 364.969 -270.196 183.333 n(0.297581, -0.954341, -0.0260521)
+563: 365.032 -271.133 220 n(0.297596, -0.954417, -0.0229218)
+564: 365.085 -271.921 256.667 n(0.29765, -0.9545, -0.0182619)
+565: 365.125 -272.507 293.333 n(0.297695, -0.95458, -0.0124057)
+566: 378.881 -261.873 36.6667 n(0.297449, -0.954316, -0.0283581)
+567: 378.784 -262.777 73.3333 n(0.297575, -0.954386, -0.0244301)
+568: 378.673 -263.815 110 n(0.297633, -0.954302, -0.0268688)
+569: 378.556 -264.913 146.667 n(0.297668, -0.954276, -0.0274114)
+570: 378.441 -265.994 183.333 n(0.297815, -0.954269, -0.0260267)
+571: 378.335 -266.983 220 n(0.297869, -0.954332, -0.022903)
+572: 378.246 -267.814 256.667 n(0.297947, -0.954408, -0.0182468)
+573: 378.18 -268.433 293.333 n(0.298011, -0.954482, -0.0123958)
+574: 390.672 -258.197 36.6667 n(0.29754, -0.95429, -0.0282903)
+575: 390.448 -259.14 73.3333 n(0.297711, -0.954345, -0.0243871)
+576: 390.19 -260.222 110 n(0.297807, -0.954249, -0.0268262)
+577: 389.917 -261.368 146.667 n(0.297868, -0.954214, -0.0273806)
+578: 389.649 -262.495 183.333 n(0.298067, -0.954191, -0.02598)
+579: 389.403 -263.527 220 n(0.298142, -0.954247, -0.0228718)
+580: 389.197 -264.394 256.667 n(0.298245, -0.954315, -0.018223)
+581: 389.043 -265.04 293.333 n(0.298326, -0.954384, -0.0123797)
+582: 412.839 -251.284 36.6667 n(0.297623, -0.954268, -0.0281617)
+583: 412.376 -252.298 73.3333 n(0.297841, -0.954306, -0.0243169)
+584: 411.843 -253.463 110 n(0.297974, -0.954199, -0.0267561)
+585: 411.28 -254.695 146.667 n(0.298082, -0.954149, -0.0273118)
+586: 410.725 -255.909 183.333 n(0.298293, -0.954122, -0.0259211)
+587: 410.217 -257.02 220 n(0.298407, -0.954166, -0.0228193)
+588: 409.79 -257.954 256.667 n(0.298537, -0.954225, -0.018182)
+589: 409.472 -258.65 293.333 n(0.298636, -0.954287, -0.012352)
+590: 416.649 -250.095 36.6667 n(0.297669, -0.954256, -0.0280923)
+591: 416.145 -251.121 73.3333 n(0.297917, -0.954283, -0.024283)
+592: 415.566 -252.3 110 n(0.298072, -0.954169, -0.0267217)
+593: 414.953 -253.547 146.667 n(0.298223, -0.954107, -0.0272693)
+594: 414.349 -254.776 183.333 n(0.298415, -0.954085, -0.0258997)
+595: 413.796 -255.9 220 n(0.298564, -0.954117, -0.0227922)
+596: 413.331 -256.846 256.667 n(0.298708, -0.954172, -0.0181604)
+597: 412.985 -257.55 293.333 n(0.298819, -0.95423, -0.0123369)
+598: 422.104 -248.393 36.6667 n(-0.464596, -0.884614, -0.0400989)
+599: 421.542 -249.436 73.3333 n(-0.464585, -0.884847, -0.0347319)
+600: 420.895 -250.635 110 n(-0.464527, -0.884734, -0.0382205)
+601: 420.211 -251.903 146.667 n(-0.334429, -0.941634, -0.038501)
+602: 419.538 -253.153 183.333 n(-0.629409, -0.776236, -0.0360986)
+603: 418.921 -254.297 220 n(-0.464619, -0.88491, -0.0326078)
+604: 418.402 -255.258 256.667 n(-0.464702, -0.885086, -0.0259804)
+605: 418.016 -255.974 293.333 n(-0.464773, -0.885254, -0.0176456)
+606: 425.411 -259.027 36.6667 n(-0.954474, -0.296905, -0.0287597)
+607: 424.812 -259.957 73.3333 n(-0.954635, -0.296738, -0.0248654)
+608: 424.123 -261.026 110 n(-0.95462, -0.296566, -0.0273588)
+609: 423.394 -262.157 146.667 n(-0.954652, -0.296414, -0.0279082)
+610: 422.676 -263.271 183.333 n(-0.954731, -0.296287, -0.0265204)
+611: 422.019 -264.29 220 n(-0.954845, -0.296187, -0.0233318)
+612: 421.466 -265.148 256.667 n(-0.954971, -0.296115, -0.0185888)
+613: 421.055 -265.786 293.333 n(-0.955084, -0.296067, -0.0126273)
+614: 432.135 -280.642 36.6667 n(-0.954429, -0.297034, -0.0288997)
+615: 431.46 -281.341 73.3333 n(-0.954573, -0.29693, -0.0249433)
+616: 430.685 -282.144 110 n(-0.954542, -0.296812, -0.0274368)
+617: 429.865 -282.993 146.667 n(-0.954558, -0.29671, -0.027983)
+618: 429.059 -283.828 183.333 n(-0.954623, -0.296629, -0.0265884)
+619: 428.32 -284.594 220 n(-0.954724, -0.296572, -0.0233903)
+620: 427.699 -285.237 256.667 n(-0.95484, -0.296534, -0.0186349)
+621: 427.237 -285.715 293.333 n(-0.954945, -0.296511, -0.0126584)
+622: 441.166 -309.658 36.6667 n(-0.954389, -0.297154, -0.0290106)
+623: 440.391 -310.042 73.3333 n(-0.954512, -0.297123, -0.0249987)
+624: 439.502 -310.484 110 n(-0.954464, -0.297056, -0.0274916)
+625: 438.561 -310.951 146.667 n(-0.954463, -0.297008, -0.0280364)
+626: 437.636 -311.411 183.333 n(-0.954513, -0.296977, -0.0266374)
+627: 436.788 -311.832 220 n(-0.954601, -0.296964, -0.0234323)
+628: 436.076 -312.185 256.667 n(-0.954707, -0.296963, -0.0186681)
+629: 435.546 -312.449 293.333 n(-0.954804, -0.296967, -0.0126816)
+630: 442.841 -315.038 36.6667 n(-0.954366, -0.297225, -0.0290417)
+631: 442.048 -315.364 73.3333 n(-0.954476, -0.297239, -0.0250115)
+632: 441.138 -315.738 110 n(-0.954417, -0.297205, -0.0275047)
+633: 440.175 -316.134 146.667 n(-0.954407, -0.297187, -0.0280488)
+634: 439.227 -316.524 183.333 n(-0.954448, -0.297186, -0.0266489)
+635: 438.36 -316.881 220 n(-0.954527, -0.297201, -0.0234426)
+636: 437.631 -317.181 256.667 n(-0.954626, -0.297221, -0.0186764)
+637: 437.088 -317.404 293.333 n(-0.954718, -0.297242, -0.0126876)
+638: 446.39 -326.433 36.6667 n(-0.95434, -0.297309, -0.0290397)
+639: 445.559 -326.635 73.3333 n(-0.954438, -0.29736, -0.0250077)
+640: 444.604 -326.867 110 n(-0.954369, -0.297361, -0.0275013)
+641: 443.594 -327.112 146.667 n(-0.954349, -0.297375, -0.0280457)
+642: 442.6 -327.354 183.333 n(-0.95438, -0.297403, -0.0266461)
+643: 441.69 -327.575 220 n(-0.954452, -0.297442, -0.0234401)
+644: 440.926 -327.761 256.667 n(-0.954544, -0.297484, -0.018675)
+645: 440.357 -327.899 293.333 n(-0.954631, -0.29752, -0.0126868)
+646: 453.556 -349.428 36.6667 n(-0.954309, -0.297412, -0.0290002)
+647: 452.647 -349.38 73.3333 n(-0.954389, -0.297519, -0.0249837)
+648: 451.604 -349.325 110 n(-0.954307, -0.297562, -0.0274773)
+649: 450.5 -349.266 146.667 n(-0.954274, -0.297618, -0.028023)
+650: 449.414 -349.209 183.333 n(-0.954292, -0.297686, -0.0266256)
+651: 448.42 -349.156 220 n(-0.954353, -0.29776, -0.0234227)
+652: 447.584 -349.112 256.667 n(-0.954437, -0.297829, -0.0186612)
+653: 446.962 -349.079 293.333 n(-0.954517, -0.297887, -0.0126775)
+654: 456.945 -360.303 36.6667 n(-0.954278, -0.297515, -0.028938)
+655: 456.001 -360.136 73.3333 n(-0.954341, -0.297676, -0.0249444)
+656: 454.916 -359.946 110 n(-0.954245, -0.297763, -0.0274381)
+657: 453.769 -359.744 146.667 n(-0.954199, -0.297862, -0.0279855)
+658: 452.64 -359.545 183.333 n(-0.954205, -0.297968, -0.0265917)
+659: 451.606 -359.363 220 n(-0.954255, -0.298077, -0.0233937)
+660: 450.737 -359.21 256.667 n(-0.954329, -0.298176, -0.0186387)
+661: 450.09 -359.096 293.333 n(-0.954403, -0.298253, -0.0126622)
+662: 464.281 -383.825 36.6667 n(-0.954245, -0.297637, -0.0287944)
+663: 463.261 -383.405 73.3333 n(-0.954286, -0.297859, -0.0248577)
+664: 462.089 -382.922 110 n(-0.954175, -0.297996, -0.0273522)
+665: 460.848 -382.412 146.667 n(-0.954113, -0.298143, -0.0279034)
+666: 459.627 -381.909 183.333 n(-0.954105, -0.298296, -0.0265175)
+667: 458.509 -381.448 220 n(-0.954142, -0.298443, -0.02333)
+668: 457.569 -381.061 256.667 n(-0.954205, -0.298575, -0.0185892)
+669: 456.869 -380.773 293.333 n(-0.954271, -0.298677, -0.0126297)
+670: 470.903 -405.047 36.6666 n(-0.884495, 0.464326, -0.0455052)
+671: 469.816 -404.4 73.3333 n(-0.884815, 0.464538, -0.036155)
+672: 468.567 -403.657 110 n(-0.88467, 0.464466, -0.0403633)
+673: 467.245 -402.87 146.667 n(-0.809845, 0.585172, -0.0415238)
+674: 465.942 -402.095 183.333 n(-0.958767, 0.28155, -0.0386744)
+675: 464.749 -401.385 220 n(-0.884804, 0.464586, -0.0357977)
+676: 463.746 -400.788 256.667 n(-0.884988, 0.464704, -0.0290853)
+677: 463 -400.344 293.333 n(-0.885169, 0.464819, -0.0204558)
+678: 467.858 -405.993 36.6666 n(-0.296771, 0.954417, -0.0318616)
+679: 466.804 -405.336 73.3333 n(-0.296571, 0.954613, -0.0275717)
+680: 465.591 -404.58 110 n(-0.296359, 0.954594, -0.0303481)
+681: 464.308 -403.781 146.667 n(-0.296205, 0.954622, -0.030988)
+682: 463.044 -402.993 183.333 n(-0.295977, 0.954742, -0.0294139)
+683: 461.887 -402.272 220 n(-0.295886, 0.954872, -0.0258991)
+684: 460.914 -401.665 256.667 n(-0.295799, 0.955027, -0.0206376)
+685: 460.189 -401.214 293.333 n(-0.295743, 0.955165, -0.0140216)
+686: 446.003 -412.789 36.6666 n(-0.29685, 0.954387, -0.0320104)
+687: 445.18 -412.056 73.3333 n(-0.2967, 0.95457, -0.0276541)
+688: 444.235 -411.213 110 n(-0.29652, 0.954542, -0.0304306)
+689: 443.235 -410.321 146.667 n(-0.296408, 0.954556, -0.0310655)
+690: 442.251 -409.443 183.333 n(-0.296206, 0.954669, -0.0294857)
+691: 441.349 -408.639 220 n(-0.296148, 0.954789, -0.0259604)
+692: 440.591 -407.963 256.667 n(-0.296085, 0.954938, -0.0206857)
+693: 440.027 -407.459 293.333 n(-0.296046, 0.95507, -0.0140539)
+694: 441.903 -414.064 36.6666 n(-0.296925, 0.954362, -0.0320701)
+695: 441.125 -413.316 73.3333 n(-0.296812, 0.954534, -0.0276929)
+696: 440.23 -412.457 110 n(-0.296664, 0.954496, -0.0304693)
+697: 439.284 -411.548 146.667 n(-0.296566, 0.954506, -0.0310921)
+698: 438.352 -410.653 183.333 n(-0.29642, 0.954601, -0.0295294)
+699: 437.499 -409.834 220 n(-0.296373, 0.954719, -0.025989)
+700: 436.781 -409.145 256.667 n(-0.296329, 0.954861, -0.0207076)
+701: 436.247 -408.632 293.333 n(-0.296302, 0.954991, -0.0140691)
+702: 428.556 -418.217 36.6666 n(-0.29699, 0.954339, -0.0321401)
+703: 427.921 -417.423 73.3333 n(-0.296917, 0.9545, -0.0277309)
+704: 427.192 -416.51 110 n(-0.2968, 0.954452, -0.0305077)
+705: 426.42 -415.545 146.667 n(-0.296744, 0.95445, -0.0311303)
+706: 425.66 -414.595 183.333 n(-0.2966, 0.954544, -0.0295606)
+707: 424.965 -413.726 220 n(-0.296589, 0.954651, -0.0260169)
+708: 424.38 -412.995 256.667 n(-0.296567, 0.954787, -0.02073)
+709: 423.944 -412.45 293.333 n(-0.296557, 0.954911, -0.014084)
+710: 415.961 -422.137 36.6666 n(-0.297067, 0.954314, -0.0321848)
+711: 415.462 -421.3 73.3333 n(-0.297029, 0.954465, -0.0277587)
+712: 414.888 -420.338 110 n(-0.296943, 0.954407, -0.0305351)
+713: 414.282 -419.32 146.667 n(-0.296901, 0.9544, -0.0311507)
+714: 413.685 -418.318 183.333 n(-0.29681, 0.954478, -0.0295902)
+715: 413.139 -417.402 220 n(-0.296813, 0.954581, -0.0260372)
+716: 412.68 -416.631 256.667 n(-0.296807, 0.954712, -0.0207452)
+717: 412.338 -416.057 293.333 n(-0.296813, 0.954832, -0.0140938)
+718: 412.096 -423.34 36.6666 n(-0.297134, 0.954293, -0.0322011)
+719: 411.639 -422.49 73.3333 n(-0.297136, 0.954431, -0.027769)
+720: 411.114 -421.512 110 n(-0.29708, 0.954364, -0.0305456)
+721: 410.558 -420.479 146.667 n(-0.297081, 0.954344, -0.0311586)
+722: 410.012 -419.461 183.333 n(-0.296992, 0.954421, -0.0296029)
+723: 409.511 -418.53 220 n(-0.29703, 0.954513, -0.0260455)
+724: 409.09 -417.747 256.667 n(-0.297045, 0.954638, -0.0207522)
+725: 408.777 -417.164 293.333 n(-0.297066, 0.954753, -0.014098)
+726: 390.026 -430.213 36.6666 n(-0.297229, 0.954263, -0.0322084)
+727: 389.808 -429.288 73.3333 n(-0.297287, 0.954384, -0.0277746)
+728: 389.558 -428.224 110 n(-0.297273, 0.954304, -0.0305514)
+729: 389.294 -427.1 146.667 n(-0.297329, 0.954267, -0.0311603)
+730: 389.034 -425.993 183.333 n(-0.297256, 0.954339, -0.0296099)
+731: 388.796 -424.98 220 n(-0.297338, 0.954417, -0.0260502)
+732: 388.596 -424.128 256.667 n(-0.297383, 0.954533, -0.0207548)
+733: 388.447 -423.494 293.333 n(-0.297424, 0.954641, -0.0141001)
+734: 378.204 -433.896 36.6666 n(-0.297332, 0.954232, -0.0321819)
+735: 378.115 -432.931 73.3333 n(-0.297442, 0.954336, -0.0277635)
+736: 378.013 -431.822 110 n(-0.29747, 0.954243, -0.0305394)
+737: 377.905 -430.65 146.667 n(-0.297555, 0.954197, -0.0311427)
+738: 377.798 -429.495 183.333 n(-0.297542, 0.95425, -0.0296049)
+739: 377.701 -428.438 220 n(-0.29765, 0.95432, -0.0260397)
+740: 377.619 -427.55 256.667 n(-0.297722, 0.954427, -0.0207469)
+741: 377.558 -426.889 293.333 n(-0.297782, 0.95453, -0.0140948)
+742: 364.096 -438.294 36.6666 n(-0.297429, 0.954204, -0.0321121)
+743: 364.16 -437.282 73.3333 n(-0.297594, 0.95429, -0.0277287)
+744: 364.233 -436.119 110 n(-0.297664, 0.954183, -0.0305048)
+745: 364.311 -434.89 146.667 n(-0.297803, 0.954121, -0.031101)
+746: 364.388 -433.679 183.333 n(-0.297806, 0.954168, -0.0295833)
+747: 364.458 -432.571 220 n(-0.297957, 0.954225, -0.0260133)
+748: 364.517 -431.639 256.667 n(-0.298057, 0.954323, -0.0207264)
+749: 364.561 -430.946 293.333 n(-0.298139, 0.954419, -0.0140797)
+750: 344.318 -444.461 36.6666 n(-0.297533, 0.954175, -0.0320083)
+751: 344.596 -443.385 73.3333 n(-0.29775, 0.954243, -0.0276708)
+752: 344.915 -442.149 110 n(-0.297861, 0.954123, -0.0304467)
+753: 345.253 -440.84 146.667 n(-0.298028, 0.954052, -0.0310457)
+754: 345.585 -439.552 183.333 n(-0.298093, 0.95408, -0.0295332)
+755: 345.89 -438.373 220 n(-0.298266, 0.954129, -0.0259699)
+756: 346.146 -437.381 256.667 n(-0.298393, 0.954219, -0.0206921)
+757: 346.336 -436.643 293.333 n(-0.298495, 0.954308, -0.0140572)
+758: 338.166 -446.38 36.6666 n(-0.297622, 0.95415, -0.0319098)
+759: 338.51 -445.285 73.3333 n(-0.297883, 0.954203, -0.0276196)
+760: 338.905 -444.025 110 n(-0.298031, 0.954072, -0.0303951)
+761: 339.324 -442.693 146.667 n(-0.298235, 0.953989, -0.0309891)
+762: 339.736 -441.381 183.333 n(-0.298331, 0.954007, -0.0294931)
+763: 340.113 -440.18 220 n(-0.298534, 0.954047, -0.0259302)
+764: 340.43 -439.17 256.667 n(-0.298685, 0.954128, -0.0206612)
+765: 340.666 -438.418 293.333 n(-0.298806, 0.954211, -0.0140354)
+766: 318.117 -452.636 36.6666 n(-0.297699, 0.954131, -0.031756)
+767: 318.675 -451.478 73.3333 n(-0.298003, 0.954168, -0.0275338)
+768: 319.317 -450.146 110 n(-0.298184, 0.954027, -0.0303102)
+769: 319.997 -448.736 146.667 n(-0.298414, 0.953936, -0.0309094)
+770: 320.666 -447.348 183.333 n(-0.298554, 0.953939, -0.0294178)
+771: 321.279 -446.076 220 n(-0.298777, 0.953972, -0.0258672)
+772: 321.795 -445.007 256.667 n(-0.298958, 0.954044, -0.0206105)
+773: 322.179 -444.21 293.333 n(-0.299092, 0.954121, -0.014002)
+774: 315.461 -453.465 36.6666 n(0.464229, 0.88462, -0.0440343)
+775: 316.048 -452.299 73.3333 n(0.464474, 0.88476, -0.0382572)
+776: 316.722 -450.958 110 n(0.464396, 0.884626, -0.0421152)
+777: 317.436 -449.538 146.667 n(0.629279, 0.776041, -0.0420553)
+778: 318.139 -448.139 183.333 n(0.334285, 0.941588, -0.0408047)
+779: 318.784 -446.858 220 n(0.464498, 0.884844, -0.0359481)
+780: 319.325 -445.781 256.667 n(0.464607, 0.885053, -0.0286427)
+781: 319.728 -444.979 293.333 n(0.464736, 0.885235, -0.0194514)
+782: 315.204 -452.637 36.6666 n(0.954471, 0.296724, -0.0306686)
+783: 315.793 -451.48 73.3333 n(0.954669, 0.296481, -0.0265689)
+784: 316.471 -450.149 110 n(0.954664, 0.296247, -0.02925)
+785: 317.189 -448.739 146.667 n(0.954714, 0.296024, -0.0298496)
+786: 317.895 -447.351 183.333 n(0.954813, 0.295851, -0.0283715)
+787: 318.543 -446.08 220 n(0.954951, 0.295713, -0.0249642)
+788: 319.087 -445.011 256.667 n(0.955104, 0.295601, -0.0198928)
+789: 319.492 -444.215 293.333 n(0.955239, 0.295525, -0.0135152)
+790: 310.49 -437.473 36.6666 n(0.954444, 0.296793, -0.0308239)
+791: 311.133 -436.475 73.3333 n(0.954628, 0.296606, -0.0266491)
+792: 311.871 -435.327 110 n(0.954613, 0.296403, -0.0293302)
+793: 312.652 -434.113 146.667 n(0.95465, 0.296222, -0.0299261)
+794: 313.422 -432.917 183.333 n(0.954742, 0.296072, -0.0284421)
+795: 314.126 -431.822 220 n(0.954874, 0.295955, -0.0250251)
+796: 314.719 -430.902 256.667 n(0.95502, 0.29587, -0.0199414)
+797: 315.16 -430.216 293.333 n(0.955149, 0.295815, -0.0135484)
+798: 304.503 -418.219 36.6666 n(0.954408, 0.296894, -0.0309656)
+799: 305.212 -417.426 73.3333 n(0.954578, 0.296759, -0.0267327)
+800: 306.027 -416.515 110 n(0.954549, 0.296598, -0.0294131)
+801: 306.89 -415.551 146.667 n(0.954574, 0.296459, -0.0300056)
+802: 307.739 -414.602 183.333 n(0.954655, 0.296347, -0.0285141)
+803: 308.516 -413.733 220 n(0.954777, 0.296264, -0.0250868)
+804: 309.17 -413.002 256.667 n(0.954915, 0.296206, -0.0199896)
+805: 309.656 -412.458 293.333 n(0.955038, 0.296174, -0.0135801)
+806: 301.69 -409.178 36.6666 n(0.954375, 0.296991, -0.0310457)
+807: 302.431 -408.482 73.3333 n(0.954529, 0.296912, -0.0267801)
+808: 303.282 -407.682 110 n(0.954487, 0.296795, -0.0294606)
+809: 304.182 -406.836 146.667 n(0.954499, 0.296697, -0.0300512)
+810: 305.069 -406.004 183.333 n(0.954568, 0.296623, -0.028556)
+811: 305.88 -405.241 220 n(0.954679, 0.296574, -0.0251226)
+812: 306.562 -404.601 256.667 n(0.954808, 0.296547, -0.0200172)
+813: 307.07 -404.123 293.333 n(0.954925, 0.296535, -0.0135985)
+814: 293.797 -383.82 36.6667 n(0.954332, 0.297121, -0.0311198)
+815: 294.626 -383.398 73.3333 n(0.954463, 0.29712, -0.0268238)
+816: 295.577 -382.914 110 n(0.954403, 0.297059, -0.0295044)
+817: 296.583 -382.401 146.667 n(0.954398, 0.297018, -0.0300928)
+818: 297.573 -381.897 183.333 n(0.95445, 0.296998, -0.0285937)
+819: 298.48 -381.435 220 n(0.954547, 0.296996, -0.0251549)
+820: 299.242 -381.047 256.667 n(0.954665, 0.297008, -0.0200423)
+821: 299.809 -380.758 293.333 n(0.954773, 0.297024, -0.0136154)
+822: 285.955 -358.641 36.6667 n(0.954288, 0.297263, -0.0311268)
+823: 286.869 -358.492 73.3333 n(0.954397, 0.297332, -0.026833)
+824: 287.918 -358.322 110 n(0.954318, 0.297331, -0.0295127)
+825: 289.027 -358.142 146.667 n(0.954295, 0.297346, -0.0301005)
+826: 290.12 -357.965 183.333 n(0.954331, 0.297378, -0.0286009)
+827: 291.12 -357.802 220 n(0.954414, 0.297423, -0.0251607)
+828: 291.96 -357.666 256.667 n(0.95452, 0.297473, -0.0200462)
+829: 292.586 -357.564 293.333 n(0.95462, 0.297515, -0.0136179)
+830: 283.085 -349.428 36.6667 n(0.954256, 0.297369, -0.0310902)
+831: 284.029 -349.38 73.3333 n(0.954347, 0.297493, -0.0268161)
+832: 285.113 -349.325 110 n(0.954256, 0.297534, -0.0294957)
+833: 286.261 -349.266 146.667 n(0.95422, 0.297589, -0.0300845)
+834: 287.39 -349.209 183.333 n(0.954243, 0.297661, -0.0285857)
+835: 288.423 -349.156 220 n(0.954315, 0.297741, -0.0251471)
+836: 289.292 -349.112 256.667 n(0.954412, 0.297818, -0.0200356)
+837: 289.939 -349.079 293.333 n(0.954506, 0.297882, -0.0136104)
+838: 276.96 -329.782 36.6667 n(0.954228, 0.29747, -0.031002)
+839: 277.969 -329.947 73.3333 n(0.9543, 0.297648, -0.0267707)
+840: 279.128 -330.136 110 n(0.954195, 0.297733, -0.0294507)
+841: 280.354 -330.337 146.667 n(0.954145, 0.297832, -0.0300409)
+842: 281.561 -330.534 183.333 n(0.954157, 0.297943, -0.0285456)
+843: 282.667 -330.715 220 n(0.954218, 0.298056, -0.0251127)
+844: 283.596 -330.867 256.667 n(0.954305, 0.298163, -0.0200082)
+845: 284.287 -330.98 293.333 n(0.954391, 0.298249, -0.0135915)
+846: 96.9011 -174.729 41.25 n(0.955668, -0.294412, -0.00442353)
+847: 98.4676 -169.625 41.25 n(0.955385, -0.295291, -0.00657216)
+848: 97.3285 -174.582 82.5 n(0.953514, -0.301185, -0.00989365)
+849: 98.8873 -169.636 82.5 n(0.952994, -0.30275, -0.0120299)
+850: 97.9401 -174.373 123.75 n(0.950305, -0.311148, -0.0103691)
+851: 99.4877 -169.653 123.75 n(0.950274, -0.311155, -0.0127367)
+852: 103.543 -153.087 41.25 n(0.956038, -0.293173, -0.00631907)
+853: 103.937 -153.612 82.5 n(0.953355, -0.301462, -0.0153624)
+854: 104.501 -154.363 123.75 n(0.949562, -0.313219, -0.0150449)
+855: 106.627 -143.038 41.25 n(0.955375, -0.295253, -0.00918867)
+856: 107.005 -143.875 82.5 n(0.953626, -0.300452, -0.0180329)
+857: 107.546 -145.072 123.75 n(0.950717, -0.309511, -0.0184458)
+858: 107.579 -139.935 41.25 n(0.956038, -0.293145, -0.00756362)
+859: 107.952 -140.869 82.5 n(0.953779, -0.299928, -0.0186984)
+860: 108.486 -142.203 123.75 n(0.950227, -0.31089, -0.020406)
+861: 114.786 -116.447 41.25 n(0.95565, -0.294315, -0.0105626)
+862: 115.121 -118.105 82.5 n(0.953379, -0.300863, -0.0234354)
+863: 115.601 -120.478 123.75 n(0.95021, -0.310621, -0.0248233)
+864: 118.255 -105.137 41.25 n(0.955653, -0.294246, -0.0121032)
+865: 118.572 -107.139 82.5 n(0.953361, -0.300656, -0.0266382)
+866: 119.025 -110.008 123.75 n(0.950229, -0.31028, -0.0281206)
+867: 122.946 -89.845 41.25 n(0.955658, -0.294167, -0.0135253)
+868: 123.237 -92.307 82.5 n(0.953342, -0.300404, -0.0299574)
+869: 123.654 -95.8407 123.75 n(0.950255, -0.309849, -0.0317631)
+870: 128.931 -70.3236 41.25 n(0.955665, -0.294063, -0.0152366)
+871: 129.19 -73.3587 82.5 n(0.953317, -0.300099, -0.0335652)
+872: 129.561 -77.7284 123.75 n(0.950286, -0.30935, -0.0354806)
+873: 130.453 -65.3586 41.25 n(0.46924, -0.881646, -0.0501433)
+874: 130.703 -68.5366 82.5 n(0.468349, -0.878865, -0.090809)
+875: 131.063 -73.1161 123.75 n(0.467701, -0.879915, -0.083703)
+876: 134.41 -66.5663 41.25 n(-0.290838, -0.955914, -0.0405141)
+877: 134.64 -69.7136 82.5 n(-0.284749, -0.954658, -0.0868726)
+878: 134.972 -74.2458 123.75 n(-0.276775, -0.956756, -0.0895163)
+879: 138.133 -67.7028 41.25 n(-0.290778, -0.95595, -0.0400952)
+880: 138.345 -70.8208 82.5 n(-0.284599, -0.954783, -0.0859876)
+881: 138.65 -75.3082 123.75 n(-0.27652, -0.956913, -0.0886236)
+882: 146.74 -70.3292 41.25 n(-0.290636, -0.956041, -0.0389294)
+883: 146.909 -73.3779 82.5 n(-0.284257, -0.955081, -0.0837797)
+884: 147.152 -77.7602 123.75 n(-0.275947, -0.957269, -0.0865438)
+885: 172.616 -78.2209 41.25 n(-0.290472, -0.956165, -0.0370613)
+886: 172.654 -81.05 82.5 n(-0.28384, -0.955558, -0.0796532)
+887: 172.708 -85.1056 123.75 n(-0.2752, -0.957864, -0.0822291)
+888: 183.798 -81.6292 41.25 n(-0.290329, -0.956265, -0.0355855)
+889: 183.778 -84.3586 82.5 n(-0.283462, -0.955934, -0.0764097)
+890: 183.75 -88.2686 123.75 n(-0.274525, -0.958344, -0.0788207)
+891: 207.09 -88.7258 41.25 n(-0.290181, -0.956397, -0.033163)
+892: 206.951 -91.2397 82.5 n(-0.2831, -0.956416, -0.0715673)
+893: 206.752 -94.8392 123.75 n(-0.273871, -0.958915, -0.0740065)
+894: 233.165 -96.6658 41.25 n(-0.290077, -0.956503, -0.030924)
+895: 232.893 -98.9283 82.5 n(-0.282833, -0.956857, -0.0665566)
+896: 232.503 -102.171 123.75 n(-0.273355, -0.959458, -0.0686829)
+897: 241.557 -99.2205 41.25 n(-0.290015, -0.956566, -0.029543)
+898: 241.243 -101.4 82.5 n(-0.28267, -0.957109, -0.0635569)
+899: 240.791 -104.526 123.75 n(-0.273044, -0.959767, -0.0655381)
+900: 260.975 -105.13 41.25 n(-0.289969, -0.95664, -0.0275245)
+901: 260.563 -107.116 82.5 n(-0.282565, -0.957398, -0.0595422)
+902: 259.971 -109.97 123.75 n(-0.272826, -0.960093, -0.0615408)
+903: 276.019 -109.708 41.25 n(-0.289944, -0.956689, -0.0260363)
+904: 275.534 -111.543 82.5 n(-0.282505, -0.957618, -0.056207)
+905: 274.835 -114.184 123.75 n(-0.272686, -0.960354, -0.0579923)
+906: 282.514 -111.684 41.25 n(-0.289934, -0.956714, -0.0252106)
+907: 281.998 -113.453 82.5 n(-0.282483, -0.957732, -0.0543393)
+908: 281.253 -116.003 123.75 n(-0.272628, -0.960489, -0.0559957)
+909: 289.472 -113.801 41.25 n(-0.940904, -0.33848, -0.0114819)
+910: 288.923 -115.5 82.5 n(-0.883926, -0.466231, -0.0361176)
+911: 288.13 -117.951 123.75 n(-0.769652, -0.636609, -0.0486331)
+912: 288.319 -117.56 41.25 n(-0.956012, 0.293327, -0.000758823)
+913: 287.774 -119.148 82.5 n(-0.954566, 0.297994, -0.00186906)
+914: 286.989 -121.438 123.75 n(-0.950555, 0.31055, -0.00192579)
+915: 281.455 -139.929 41.25 n(-0.955421, 0.295233, -0.00280815)
+916: 280.94 -140.849 82.5 n(-0.953109, 0.302581, -0.00530208)
+917: 280.199 -142.171 123.75 n(-0.950409, 0.310935, -0.00654026)
+918: 280.146 -144.198 41.25 n(-0.956057, 0.293167, -0.00297529)
+919: 279.636 -144.988 82.5 n(-0.953454, 0.301436, -0.00784113)
+920: 278.904 -146.123 123.75 n(-0.949678, 0.313138, -0.00752809)
+921: 275.878 -158.104 41.25 n(-0.955397, 0.295274, -0.00542143)
+922: 275.389 -158.469 82.5 n(-0.953721, 0.300509, -0.0105362)
+923: 274.686 -158.994 123.75 n(-0.950809, 0.309574, -0.0112246)
+924: 271.974 -170.826 41.25 n(-0.956044, 0.293174, -0.0053207)
+925: 271.503 -170.8 82.5 n(-0.953388, 0.301469, -0.0129567)
+926: 270.828 -170.764 123.75 n(-0.94959, 0.313204, -0.0134995)
+927: 270.776 -174.729 41.25 n(-0.955382, 0.295265, -0.00795493)
+928: 270.311 -174.583 82.5 n(-0.953677, 0.300489, -0.0143727)
+929: 269.645 -174.374 123.75 n(-0.950745, 0.309537, -0.0164701)
+930: 263.804 -197.449 41.25 n(-0.956035, 0.293151, -0.00765275)
+931: 263.374 -196.601 82.5 n(-0.953321, 0.301358, -0.0190181)
+932: 262.758 -195.386 123.75 n(-0.949536, 0.313004, -0.0202191)
+933: 260.098 -209.525 41.25 n(-0.955371, 0.295181, -0.0115815)
+934: 259.688 -208.305 82.5 n(-0.953589, 0.30028, -0.022353)
+935: 259.099 -206.556 123.75 n(-0.950686, 0.309211, -0.0241808)
+936: 255.636 -224.069 41.25 n(-0.955649, 0.294246, -0.012468)
+937: 255.249 -222.403 82.5 n(-0.953378, 0.300775, -0.0245934)
+938: 254.694 -220.014 123.75 n(-0.950198, 0.310357, -0.0283279)
+939: 249.422 -244.328 41.25 n(-0.95603, 0.293036, -0.0117248)
+940: 249.069 -242.049 82.5 n(-0.953227, 0.300816, -0.0294595)
+941: 248.561 -238.777 123.75 n(-0.949566, 0.312035, -0.0309792)
+942: 247.471 -250.691 41.25 n(-0.955658, 0.294127, -0.0143896)
+943: 247.128 -248.223 82.5 n(-0.9533, 0.300211, -0.0330573)
+944: 246.635 -244.675 123.75 n(-0.950272, 0.309625, -0.0333919)
+945: 241.127 -271.381 41.25 n(-0.955391, 0.294803, -0.017869)
+946: 240.819 -268.308 82.5 n(-0.953459, 0.299376, -0.035918)
+947: 240.375 -263.876 123.75 n(-0.950708, 0.307786, -0.0377076)
+948: 240.767 -272.555 41.25 n(-0.46947, 0.882448, -0.029715)
+949: 240.461 -269.447 82.5 n(-0.585777, 0.806887, -0.076153)
+950: 240.02 -264.966 123.75 n(-0.289992, 0.952231, -0.0957117)
+951: 231.955 -269.864 41.25 n(0.290878, 0.955957, -0.0392054)
+952: 231.692 -266.824 82.5 n(0.284831, 0.954951, -0.0833117)
+953: 231.314 -262.448 123.75 n(0.276803, 0.957128, -0.0853614)
+954: 206.717 -262.164 41.25 n(0.290689, 0.956082, -0.0375208)
+955: 206.581 -259.329 82.5 n(0.284326, 0.95546, -0.0790949)
+956: 206.385 -255.262 123.75 n(0.275896, 0.957794, -0.08069)
+957: 182.713 -254.845 41.25 n(0.290484, 0.956226, -0.0353618)
+958: 182.699 -252.22 82.5 n(0.283825, 0.955975, -0.0745367)
+959: 182.679 -248.461 123.75 n(0.275032, 0.958421, -0.076067)
+960: 172.305 -251.673 41.25 n(0.290347, 0.95632, -0.033915)
+961: 172.345 -249.142 82.5 n(0.283481, 0.95632, -0.0713509)
+962: 172.401 -245.521 123.75 n(0.274431, 0.958852, -0.0727408)
+963: 148.157 -244.317 41.25 n(0.290235, 0.956424, -0.0319015)
+964: 148.321 -242.013 82.5 n(0.283211, 0.956711, -0.0670424)
+965: 148.555 -238.716 123.75 n(0.27394, 0.959319, -0.0682925)
+966: 137.886 -241.189 41.25 n(0.29015, 0.956498, -0.0304163)
+967: 138.102 -238.984 82.5 n(0.283018, 0.956956, -0.064308)
+968: 138.412 -235.828 123.75 n(0.273606, 0.959594, -0.0657222)
+969: 133.453 -239.84 41.25 n(0.290104, 0.956537, -0.0296194)
+970: 133.693 -237.678 82.5 n(0.282895, 0.957132, -0.0622071)
+971: 134.035 -234.583 123.75 n(0.273372, 0.959822, -0.0633207)
+972: 103.458 -230.709 41.25 n(0.29004, 0.95663, -0.0271262)
+973: 103.848 -228.844 82.5 n(0.282753, 0.957515, -0.0567036)
+974: 104.409 -226.167 123.75 n(0.273084, 0.960269, -0.0575205)
+975: 84.1645 -224.838 41.25 n(0.28999, 0.956712, -0.024659)
+976: 84.6497 -223.166 82.5 n(0.282648, 0.957802, -0.0522021)
+977: 85.348 -220.76 123.75 n(0.272879, 0.960571, -0.0532908)
+978: 81.7497 -224.103 41.25 n(0.882118, 0.470554, -0.0211329)
+979: 82.2466 -222.456 82.5 n(0.880989, 0.471582, -0.0383243)
+980: 82.9619 -220.084 123.75 n(0.88097, 0.471861, -0.0351935)
+981: 82.1494 -222.801 41.25 n(0.955702, -0.294336, 1.09669e-005)
+982: 82.6445 -221.192 82.5 n(0.953633, -0.30097, 2.75732e-005)
+983: 83.3573 -218.876 123.75 n(0.950488, -0.310763, 0.00028938)
+984: 86.2217 -209.529 41.25 n(0.955694, -0.294359, -0.00101517)
+985: 86.6991 -208.317 82.5 n(0.953606, -0.301048, -0.00247517)
+986: 87.3848 -206.576 123.75 n(0.950438, -0.310903, -0.00251972)
+987: 90.3083 -196.211 41.25 n(0.955682, -0.294391, -0.00245691)
+988: 90.7672 -195.404 82.5 n(0.953563, -0.301136, -0.00580026)
+989: 91.4251 -194.246 123.75 n(0.95037, -0.311061, -0.00615438)
+POLYS
+1: 1 2 19 <
+2: 1 19 18 <
+3: 2 3 20 <
+4: 2 20 19 <
+5: 3 4 21 <
+6: 3 21 20 <
+7: 4 5 22 <
+8: 4 22 21 <
+9: 5 6 23 <
+10: 5 23 22 <
+11: 6 7 24 <
+12: 6 24 23 <
+13: 7 8 25 <
+14: 7 25 24 <
+15: 8 9 26 <
+16: 8 26 25 <
+17: 9 10 27 <
+18: 9 27 26 <
+19: 10 11 28 <
+20: 10 28 27 <
+21: 11 12 29 <
+22: 11 29 28 <
+23: 12 13 30 <
+24: 12 30 29 <
+25: 13 14 31 <
+26: 13 31 30 <
+27: 14 15 32 <
+28: 14 32 31 <
+29: 15 16 33 <
+30: 15 33 32 <
+31: 16 17 34 <
+32: 16 34 33 <
+33: 18 19 36 <
+34: 18 36 35 <
+35: 19 20 37 <
+36: 19 37 36 <
+37: 20 21 38 <
+38: 20 38 37 <
+39: 21 22 39 <
+40: 21 39 38 <
+41: 22 23 40 <
+42: 22 40 39 <
+43: 23 24 41 <
+44: 23 41 40 <
+45: 24 25 42 <
+46: 24 42 41 <
+47: 25 26 43 <
+48: 25 43 42 <
+49: 26 27 44 <
+50: 26 44 43 <
+51: 27 28 45 <
+52: 27 45 44 <
+53: 28 29 46 <
+54: 28 46 45 <
+55: 29 30 47 <
+56: 29 47 46 <
+57: 30 31 48 <
+58: 30 48 47 <
+59: 31 32 49 <
+60: 31 49 48 <
+61: 32 33 50 <
+62: 32 50 49 <
+63: 33 34 51 <
+64: 33 51 50 <
+65: 35 36 53 <
+66: 35 53 52 <
+67: 36 37 54 <
+68: 36 54 53 <
+69: 37 38 55 <
+70: 37 55 54 <
+71: 38 39 56 <
+72: 38 56 55 <
+73: 42 43 60 <
+74: 42 60 59 <
+75: 43 44 61 <
+76: 43 61 60 <
+77: 44 45 62 <
+78: 44 62 61 <
+79: 45 46 63 <
+80: 45 63 62 <
+81: 46 47 64 <
+82: 46 64 63 <
+83: 47 48 65 <
+84: 47 65 64 <
+85: 48 49 66 <
+86: 48 66 65 <
+87: 49 50 67 <
+88: 49 67 66 <
+89: 50 51 68 <
+90: 50 68 67 <
+91: 52 53 70 <
+92: 52 70 69 <
+93: 57 58 75 <
+94: 57 75 74 <
+95: 59 60 77 <
+96: 59 77 76 <
+97: 60 61 78 <
+98: 60 78 77 <
+99: 61 62 79 <
+100: 61 79 78 <
+101: 62 63 80 <
+102: 62 80 79 <
+103: 63 64 81 <
+104: 63 81 80 <
+105: 64 65 82 <
+106: 64 82 81 <
+107: 65 66 83 <
+108: 65 83 82 <
+109: 66 67 84 <
+110: 66 84 83 <
+111: 67 68 85 <
+112: 67 85 84 <
+113: 69 70 87 <
+114: 69 87 86 <
+115: 70 88 87 <
+116: 71 72 89 <
+117: 72 73 90 <
+118: 72 90 89 <
+119: 73 74 91 <
+120: 73 91 90 <
+121: 74 75 92 <
+122: 74 92 91 <
+123: 75 93 92 <
+124: 76 77 94 <
+125: 77 78 95 <
+126: 77 95 94 <
+127: 78 79 96 <
+128: 78 96 95 <
+129: 79 80 97 <
+130: 79 97 96 <
+131: 80 81 98 <
+132: 80 98 97 <
+133: 81 82 99 <
+134: 81 99 98 <
+135: 82 83 100 <
+136: 82 100 99 <
+137: 83 84 101 <
+138: 83 101 100 <
+139: 84 85 102 <
+140: 84 102 101 <
+141: 86 87 104 <
+142: 86 104 103 <
+143: 87 88 105 <
+144: 87 105 104 <
+145: 89 90 107 <
+146: 89 107 106 <
+147: 90 91 108 <
+148: 90 108 107 <
+149: 91 92 109 <
+150: 91 109 108 <
+151: 92 93 110 <
+152: 92 110 109 <
+153: 94 95 112 <
+154: 94 112 111 <
+155: 95 96 113 <
+156: 95 113 112 <
+157: 96 97 114 <
+158: 96 114 113 <
+159: 97 98 115 <
+160: 97 115 114 <
+161: 98 99 116 <
+162: 98 116 115 <
+163: 99 100 117 <
+164: 99 117 116 <
+165: 100 101 118 <
+166: 100 118 117 <
+167: 101 102 119 <
+168: 101 119 118 <
+169: 103 104 121 <
+170: 103 121 120 <
+171: 104 105 122 <
+172: 104 122 121 <
+173: 106 107 124 <
+174: 106 124 123 <
+175: 107 108 125 <
+176: 107 125 124 <
+177: 108 109 126 <
+178: 108 126 125 <
+179: 109 110 127 <
+180: 109 127 126 <
+181: 111 112 129 <
+182: 111 129 128 <
+183: 112 113 130 <
+184: 112 130 129 <
+185: 113 114 131 <
+186: 113 131 130 <
+187: 114 115 132 <
+188: 114 132 131 <
+189: 115 116 133 <
+190: 115 133 132 <
+191: 116 117 134 <
+192: 116 134 133 <
+193: 117 118 135 <
+194: 117 135 134 <
+195: 118 119 136 <
+196: 118 136 135 <
+197: 120 121 138 <
+198: 120 138 137 <
+199: 121 122 139 <
+200: 121 139 138 <
+201: 122 140 139 <
+202: 123 124 141 <
+203: 129 130 147 <
+204: 130 131 148 <
+205: 130 148 147 <
+206: 131 132 149 <
+207: 131 149 148 <
+208: 132 133 150 <
+209: 132 150 149 <
+210: 133 134 151 <
+211: 133 151 150 <
+212: 134 135 152 <
+213: 134 152 151 <
+214: 135 136 153 <
+215: 135 153 152 <
+216: 137 138 155 <
+217: 137 155 154 <
+218: 138 139 156 <
+219: 138 156 155 <
+220: 139 140 157 <
+221: 139 157 156 <
+222: 142 143 160 <
+223: 142 160 159 <
+224: 143 144 161 <
+225: 143 161 160 <
+226: 144 145 162 <
+227: 144 162 161 <
+228: 146 164 163 <
+229: 149 150 167 <
+230: 150 151 168 <
+231: 150 168 167 <
+232: 151 152 169 <
+233: 151 169 168 <
+234: 152 153 170 <
+235: 152 170 169 <
+236: 154 155 172 <
+237: 154 172 171 <
+238: 155 156 173 <
+239: 155 173 172 <
+240: 156 157 174 <
+241: 156 174 173 <
+242: 157 158 175 <
+243: 157 175 174 <
+244: 158 159 176 <
+245: 158 176 175 <
+246: 159 160 177 <
+247: 159 177 176 <
+248: 160 161 178 <
+249: 160 178 177 <
+250: 163 164 181 <
+251: 163 181 180 <
+252: 164 165 182 <
+253: 164 182 181 <
+254: 165 166 183 <
+255: 165 183 182 <
+256: 167 168 185 <
+257: 168 169 186 <
+258: 168 186 185 <
+259: 169 170 187 <
+260: 169 187 186 <
+261: 171 172 189 <
+262: 171 189 188 <
+263: 172 173 190 <
+264: 172 190 189 <
+265: 173 174 191 <
+266: 173 191 190 <
+267: 174 175 192 <
+268: 174 192 191 <
+269: 175 176 193 <
+270: 175 193 192 <
+271: 176 177 194 <
+272: 176 194 193 <
+273: 177 178 195 <
+274: 177 195 194 <
+275: 179 180 197 <
+276: 179 197 196 <
+277: 180 181 198 <
+278: 180 198 197 <
+279: 181 182 199 <
+280: 181 199 198 <
+281: 182 183 200 <
+282: 182 200 199 <
+283: 184 185 202 <
+284: 184 202 201 <
+285: 185 186 203 <
+286: 185 203 202 <
+287: 186 187 204 <
+288: 186 204 203 <
+289: 188 189 206 <
+290: 188 206 205 <
+291: 189 190 207 <
+292: 189 207 206 <
+293: 190 191 208 <
+294: 190 208 207 <
+295: 191 192 209 <
+296: 191 209 208 <
+297: 192 193 210 <
+298: 192 210 209 <
+299: 193 194 211 <
+300: 193 211 210 <
+301: 194 195 212 <
+302: 194 212 211 <
+303: 196 197 214 <
+304: 196 214 213 <
+305: 197 198 215 <
+306: 197 215 214 <
+307: 198 199 216 <
+308: 198 216 215 <
+309: 199 200 217 <
+310: 199 217 216 <
+311: 201 202 219 <
+312: 201 219 218 <
+313: 202 203 220 <
+314: 202 220 219 <
+315: 203 204 221 <
+316: 203 221 220 <
+317: 205 206 223 <
+318: 205 223 222 <
+319: 206 207 224 <
+320: 206 224 223 <
+321: 207 208 225 <
+322: 207 225 224 <
+323: 208 209 226 <
+324: 208 226 225 <
+325: 209 210 227 <
+326: 209 227 226 <
+327: 210 211 228 <
+328: 210 228 227 <
+329: 211 212 229 <
+330: 211 229 228 <
+331: 214 215 232 <
+332: 215 216 233 <
+333: 215 233 232 <
+334: 218 219 236 <
+335: 218 236 235 <
+336: 219 220 237 <
+337: 219 237 236 <
+338: 220 221 238 <
+339: 220 238 237 <
+340: 222 223 240 <
+341: 222 240 239 <
+342: 223 224 241 <
+343: 223 241 240 <
+344: 224 225 242 <
+345: 224 242 241 <
+346: 225 226 243 <
+347: 225 243 242 <
+348: 226 227 244 <
+349: 226 244 243 <
+350: 227 228 245 <
+351: 227 245 244 <
+352: 228 229 246 <
+353: 228 246 245 <
+354: 229 230 247 <
+355: 229 247 246 <
+356: 230 231 248 <
+357: 230 248 247 <
+358: 231 249 248 <
+359: 234 235 252 <
+360: 234 252 251 <
+361: 235 236 253 <
+362: 235 253 252 <
+363: 236 237 254 <
+364: 236 254 253 <
+365: 237 238 255 <
+366: 237 255 254 <
+367: 239 240 257 <
+368: 239 257 256 <
+369: 240 241 258 <
+370: 240 258 257 <
+371: 241 242 259 <
+372: 241 259 258 <
+373: 242 243 260 <
+374: 242 260 259 <
+375: 243 244 261 <
+376: 243 261 260 <
+377: 244 245 262 <
+378: 244 262 261 <
+379: 245 246 263 <
+380: 245 263 262 <
+381: 246 247 264 <
+382: 246 264 263 <
+383: 247 248 265 <
+384: 247 265 264 <
+385: 248 249 266 <
+386: 248 266 265 <
+387: 249 250 267 <
+388: 249 267 266 <
+389: 250 251 268 <
+390: 250 268 267 <
+391: 251 252 269 <
+392: 251 269 268 <
+393: 252 253 270 <
+394: 252 270 269 <
+395: 253 254 271 <
+396: 253 271 270 <
+397: 254 255 272 <
+398: 254 272 271 <
+399: 256 257 274 <
+400: 256 274 273 <
+401: 257 258 275 <
+402: 257 275 274 <
+403: 258 259 276 <
+404: 258 276 275 <
+405: 259 260 277 <
+406: 259 277 276 <
+407: 260 261 278 <
+408: 260 278 277 <
+409: 261 262 279 <
+410: 261 279 278 <
+411: 262 263 280 <
+412: 262 280 279 <
+413: 263 264 281 <
+414: 263 281 280 <
+415: 264 265 282 <
+416: 264 282 281 <
+417: 265 266 283 <
+418: 265 283 282 <
+419: 266 267 284 <
+420: 266 284 283 <
+421: 267 268 285 <
+422: 267 285 284 <
+423: 268 269 286 <
+424: 268 286 285 <
+425: 269 270 287 <
+426: 269 287 286 <
+427: 270 271 288 <
+428: 270 288 287 <
+429: 271 272 289 <
+430: 271 289 288 <
+431: 39 40 292 <
+432: 293 57 291 <
+433: 290 294 56 <
+434: 291 57 295 <
+435: 40 41 298 <
+436: 299 58 297 <
+437: 40 296 292 <
+438: 58 57 293 <
+439: 59 300 304 <
+440: 301 303 305 <
+441: 41 302 298 <
+442: 307 58 299 <
+443: 300 59 306 <
+444: 53 54 310 <
+445: 71 309 313 <
+446: 308 314 70 <
+447: 309 71 315 <
+448: 54 55 318 <
+449: 319 72 317 <
+450: 54 316 310 <
+451: 72 71 311 <
+452: 55 56 322 <
+453: 323 73 321 <
+454: 55 320 318 <
+455: 73 72 319 <
+456: 56 294 324 <
+457: 295 57 74 <
+458: 56 324 322 <
+459: 74 73 323 <
+460: 58 307 327 <
+461: 306 59 76 <
+462: 327 329 75 <
+463: 326 76 328 <
+464: 70 314 330 <
+465: 315 71 331 <
+466: 89 333 331 <
+467: 332 88 330 <
+468: 75 329 335 <
+469: 328 76 334 <
+470: 94 336 334 <
+471: 337 93 335 <
+472: 88 332 338 <
+473: 333 89 106 <
+474: 338 340 105 <
+475: 339 106 341 <
+476: 93 337 343 <
+477: 336 94 111 <
+478: 343 345 110 <
+479: 342 111 344 <
+480: 105 340 346 <
+481: 341 106 123 <
+482: 346 348 122 <
+483: 347 123 349 <
+484: 110 345 351 <
+485: 344 111 128 <
+486: 354 353 127 <
+487: 128 352 355 <
+488: 122 348 356 <
+489: 349 123 357 <
+490: 141 359 357 <
+491: 358 140 356 <
+492: 124 125 363 <
+493: 362 142 360 <
+494: 361 365 141 <
+495: 360 142 364 <
+496: 125 126 369 <
+497: 368 143 366 <
+498: 125 367 363 <
+499: 143 142 362 <
+500: 126 127 373 <
+501: 372 144 370 <
+502: 126 371 369 <
+503: 144 143 368 <
+504: 127 353 375 <
+505: 352 128 145 <
+506: 127 375 373 <
+507: 145 144 372 <
+508: 128 129 378 <
+509: 379 146 377 <
+510: 128 376 382 <
+511: 377 146 381 <
+512: 147 384 378 <
+513: 385 146 379 <
+514: 140 358 386 <
+515: 359 141 391 <
+516: 390 158 388 <
+517: 392 388 158 <
+518: 387 389 393 <
+519: 141 365 395 <
+520: 364 142 159 <
+521: 141 395 391 <
+522: 159 158 390 <
+523: 145 380 396 <
+524: 381 146 163 <
+525: 396 398 162 <
+526: 397 163 399 <
+527: 146 385 401 <
+528: 384 147 400 <
+529: 147 148 404 <
+530: 405 165 403 <
+531: 147 402 400 <
+532: 403 165 164 <
+533: 148 149 408 <
+534: 409 166 407 <
+535: 148 406 404 <
+536: 407 166 165 <
+537: 167 410 408 <
+538: 411 166 409 <
+539: 161 162 414 <
+540: 415 179 413 <
+541: 412 416 178 <
+542: 413 179 417 <
+543: 162 398 418 <
+544: 399 163 180 <
+545: 162 418 414 <
+546: 180 179 415 <
+547: 166 411 425 <
+548: 410 167 424 <
+549: 422 184 420 <
+550: 421 427 183 <
+551: 420 184 426 <
+552: 185 184 422 <
+553: 423 425 429 <
+554: 178 416 430 <
+555: 417 179 196 <
+556: 430 432 195 <
+557: 431 196 433 <
+558: 183 427 435 <
+559: 426 184 201 <
+560: 435 437 200 <
+561: 434 201 436 <
+562: 195 432 438 <
+563: 433 196 213 <
+564: 438 440 212 <
+565: 439 213 441 <
+566: 200 437 443 <
+567: 436 201 218 <
+568: 443 445 217 <
+569: 442 218 444 <
+570: 212 440 446 <
+571: 441 213 451 <
+572: 450 230 448 <
+573: 212 446 452 <
+574: 447 449 453 <
+575: 213 214 457 <
+576: 456 231 454 <
+577: 213 455 451 <
+578: 454 231 230 <
+579: 232 459 457 <
+580: 458 231 456 <
+581: 216 217 463 <
+582: 462 234 460 <
+583: 461 465 233 <
+584: 460 234 464 <
+585: 217 445 467 <
+586: 444 218 235 <
+587: 217 467 463 <
+588: 235 234 462 <
+589: 231 458 468 <
+590: 459 232 469 <
+591: 232 233 473 <
+592: 472 250 470 <
+593: 232 471 469 <
+594: 470 250 249 <
+595: 233 465 475 <
+596: 464 234 251 <
+597: 475 476 473 <
+598: 250 472 477 <
+599: 474 251 477 <
+600: 251 250 477 <
+601: 233 475 473 <
+602: 464 251 474 <
+603: 470 249 468 <
+604: 232 473 471 <
+605: 231 468 249 <
+606: 466 235 462 <
+607: 444 235 466 <
+608: 216 461 233 <
+609: 216 463 461 <
+610: 214 232 457 <
+611: 454 230 450 <
+612: 213 457 455 <
+613: 212 452 229 <
+614: 452 448 229 <
+615: 448 230 229 <
+616: 441 451 447 <
+617: 451 449 447 <
+618: 200 443 217 <
+619: 436 218 442 <
+620: 195 438 212 <
+621: 433 213 439 <
+622: 183 435 200 <
+623: 426 201 434 <
+624: 178 430 195 <
+625: 417 196 431 <
+626: 167 428 424 <
+627: 167 185 428 <
+628: 185 422 428 <
+629: 166 421 183 <
+630: 166 425 421 <
+631: 425 423 421 <
+632: 419 180 415 <
+633: 399 180 419 <
+634: 161 412 178 <
+635: 161 414 412 <
+636: 149 167 408 <
+637: 407 165 405 <
+638: 148 408 406 <
+639: 403 164 401 <
+640: 147 404 402 <
+641: 146 401 164 <
+642: 145 396 162 <
+643: 381 163 397 <
+644: 394 159 390 <
+645: 364 159 394 <
+646: 140 386 157 <
+647: 386 392 157 <
+648: 392 158 157 <
+649: 359 391 387 <
+650: 391 389 387 <
+651: 129 147 378 <
+652: 377 381 383 <
+653: 128 382 145 <
+654: 382 380 145 <
+655: 128 378 376 <
+656: 374 145 372 <
+657: 352 145 374 <
+658: 370 144 368 <
+659: 126 373 371 <
+660: 366 143 362 <
+661: 125 369 367 <
+662: 124 361 141 <
+663: 124 363 361 <
+664: 123 141 357 <
+665: 122 356 140 <
+666: 350 128 355 <
+667: 110 351 127 <
+668: 351 354 127 <
+669: 344 128 350 <
+670: 105 346 122 <
+671: 341 123 347 <
+672: 93 343 110 <
+673: 336 111 342 <
+674: 88 338 105 <
+675: 333 106 339 <
+676: 76 94 334 <
+677: 75 335 93 <
+678: 71 89 331 <
+679: 70 330 88 <
+680: 58 327 75 <
+681: 306 76 326 <
+682: 325 74 323 <
+683: 295 74 325 <
+684: 321 73 319 <
+685: 55 322 320 <
+686: 317 72 311 <
+687: 54 318 316 <
+688: 53 308 70 <
+689: 311 71 313 <
+690: 53 312 308 <
+691: 53 310 312 <
+692: 303 301 299 <
+693: 301 307 299 <
+694: 41 304 302 <
+695: 41 42 304 <
+696: 42 59 304 <
+697: 297 58 293 <
+698: 40 298 296 <
+699: 39 290 56 <
+700: 39 292 290 <
+701: 376 478 479 <
+702: 479 480 481 <
+703: 481 482 483 <
+704: 483 484 485 <
+705: 485 486 487 <
+706: 487 488 489 <
+707: 489 490 491 <
+708: 491 492 493 <
+709: 493 379 377 <
+710: 382 479 494 <
+711: 494 481 495 <
+712: 495 483 496 <
+713: 496 485 497 <
+714: 497 487 498 <
+715: 498 489 499 <
+716: 499 491 500 <
+717: 500 493 501 <
+718: 501 377 383 <
+719: 382 502 380 <
+720: 494 503 502 <
+721: 495 504 503 <
+722: 496 505 504 <
+723: 505 498 506 <
+724: 498 507 506 <
+725: 499 508 507 <
+726: 500 509 508 <
+727: 501 381 509 <
+728: 380 510 396 <
+729: 502 511 510 <
+730: 503 512 511 <
+731: 504 513 512 <
+732: 513 506 514 <
+733: 506 515 514 <
+734: 507 516 515 <
+735: 508 517 516 <
+736: 509 397 517 <
+737: 396 518 398 <
+738: 510 519 518 <
+739: 511 520 519 <
+740: 512 521 520 <
+741: 521 514 522 <
+742: 514 523 522 <
+743: 515 524 523 <
+744: 516 525 524 <
+745: 517 399 525 <
+746: 398 526 418 <
+747: 518 527 526 <
+748: 519 528 527 <
+749: 520 529 528 <
+750: 529 522 530 <
+751: 522 531 530 <
+752: 523 532 531 <
+753: 524 533 532 <
+754: 525 419 533 <
+755: 418 534 414 <
+756: 526 535 534 <
+757: 527 536 535 <
+758: 528 537 536 <
+759: 537 530 538 <
+760: 530 539 538 <
+761: 531 540 539 <
+762: 532 541 540 <
+763: 533 415 541 <
+764: 414 542 412 <
+765: 534 543 542 <
+766: 535 544 543 <
+767: 536 545 544 <
+768: 545 538 546 <
+769: 538 547 546 <
+770: 539 548 547 <
+771: 540 549 548 <
+772: 541 413 549 <
+773: 412 550 416 <
+774: 542 551 550 <
+775: 543 552 551 <
+776: 544 553 552 <
+777: 553 546 554 <
+778: 546 555 554 <
+779: 547 556 555 <
+780: 548 557 556 <
+781: 549 417 557 <
+782: 416 558 430 <
+783: 550 559 558 <
+784: 551 560 559 <
+785: 552 561 560 <
+786: 561 554 562 <
+787: 554 563 562 <
+788: 555 564 563 <
+789: 556 565 564 <
+790: 557 431 565 <
+791: 430 566 432 <
+792: 558 567 566 <
+793: 559 568 567 <
+794: 560 569 568 <
+795: 569 562 570 <
+796: 562 571 570 <
+797: 563 572 571 <
+798: 564 573 572 <
+799: 565 433 573 <
+800: 432 574 438 <
+801: 566 575 574 <
+802: 567 576 575 <
+803: 568 577 576 <
+804: 577 570 578 <
+805: 570 579 578 <
+806: 571 580 579 <
+807: 572 581 580 <
+808: 573 439 581 <
+809: 438 582 440 <
+810: 574 583 582 <
+811: 575 584 583 <
+812: 576 585 584 <
+813: 585 578 586 <
+814: 578 587 586 <
+815: 579 588 587 <
+816: 580 589 588 <
+817: 581 441 589 <
+818: 440 590 446 <
+819: 582 591 590 <
+820: 583 592 591 <
+821: 584 593 592 <
+822: 593 586 594 <
+823: 586 595 594 <
+824: 587 596 595 <
+825: 588 597 596 <
+826: 589 447 597 <
+827: 446 598 452 <
+828: 590 599 598 <
+829: 591 600 599 <
+830: 592 601 600 <
+831: 601 594 602 <
+832: 594 603 602 <
+833: 595 604 603 <
+834: 596 605 604 <
+835: 597 453 605 <
+836: 452 606 448 <
+837: 598 607 606 <
+838: 599 608 607 <
+839: 600 609 608 <
+840: 601 610 609 <
+841: 602 611 610 <
+842: 603 612 611 <
+843: 604 613 612 <
+844: 605 449 613 <
+845: 448 614 450 <
+846: 606 615 614 <
+847: 607 616 615 <
+848: 608 617 616 <
+849: 609 618 617 <
+850: 610 619 618 <
+851: 611 620 619 <
+852: 612 621 620 <
+853: 613 451 621 <
+854: 450 622 454 <
+855: 614 623 622 <
+856: 615 624 623 <
+857: 616 625 624 <
+858: 617 626 625 <
+859: 618 627 626 <
+860: 619 628 627 <
+861: 620 629 628 <
+862: 621 455 629 <
+863: 454 630 456 <
+864: 622 631 630 <
+865: 623 632 631 <
+866: 624 633 632 <
+867: 625 634 633 <
+868: 626 635 634 <
+869: 627 636 635 <
+870: 628 637 636 <
+871: 629 457 637 <
+872: 456 638 458 <
+873: 630 639 638 <
+874: 631 640 639 <
+875: 632 641 640 <
+876: 633 642 641 <
+877: 634 643 642 <
+878: 635 644 643 <
+879: 636 645 644 <
+880: 637 459 645 <
+881: 458 646 468 <
+882: 638 647 646 <
+883: 639 648 647 <
+884: 640 649 648 <
+885: 641 650 649 <
+886: 642 651 650 <
+887: 643 652 651 <
+888: 644 653 652 <
+889: 645 469 653 <
+890: 468 654 470 <
+891: 646 655 654 <
+892: 647 656 655 <
+893: 648 657 656 <
+894: 649 658 657 <
+895: 650 659 658 <
+896: 651 660 659 <
+897: 652 661 660 <
+898: 653 471 661 <
+899: 470 662 472 <
+900: 654 663 662 <
+901: 655 664 663 <
+902: 656 665 664 <
+903: 657 666 665 <
+904: 658 667 666 <
+905: 659 668 667 <
+906: 660 669 668 <
+907: 661 473 669 <
+908: 472 670 477 <
+909: 662 671 670 <
+910: 663 672 671 <
+911: 664 673 672 <
+912: 665 674 673 <
+913: 666 675 674 <
+914: 667 676 675 <
+915: 668 677 676 <
+916: 669 476 677 <
+917: 474 670 678 <
+918: 678 671 679 <
+919: 679 672 680 <
+920: 680 673 681 <
+921: 673 682 681 <
+922: 682 675 683 <
+923: 683 676 684 <
+924: 684 677 685 <
+925: 685 476 475 <
+926: 464 678 686 <
+927: 686 679 687 <
+928: 687 680 688 <
+929: 688 681 689 <
+930: 681 690 689 <
+931: 690 683 691 <
+932: 691 684 692 <
+933: 692 685 693 <
+934: 693 475 465 <
+935: 460 686 694 <
+936: 694 687 695 <
+937: 695 688 696 <
+938: 696 689 697 <
+939: 689 698 697 <
+940: 698 691 699 <
+941: 699 692 700 <
+942: 700 693 701 <
+943: 701 465 461 <
+944: 462 694 702 <
+945: 702 695 703 <
+946: 703 696 704 <
+947: 704 697 705 <
+948: 697 706 705 <
+949: 706 699 707 <
+950: 707 700 708 <
+951: 708 701 709 <
+952: 709 461 463 <
+953: 466 702 710 <
+954: 710 703 711 <
+955: 711 704 712 <
+956: 712 705 713 <
+957: 705 714 713 <
+958: 714 707 715 <
+959: 715 708 716 <
+960: 716 709 717 <
+961: 717 463 467 <
+962: 444 710 718 <
+963: 718 711 719 <
+964: 719 712 720 <
+965: 720 713 721 <
+966: 713 722 721 <
+967: 722 715 723 <
+968: 723 716 724 <
+969: 724 717 725 <
+970: 725 467 445 <
+971: 442 718 726 <
+972: 726 719 727 <
+973: 727 720 728 <
+974: 728 721 729 <
+975: 721 730 729 <
+976: 730 723 731 <
+977: 731 724 732 <
+978: 732 725 733 <
+979: 733 445 443 <
+980: 436 726 734 <
+981: 734 727 735 <
+982: 735 728 736 <
+983: 736 729 737 <
+984: 729 738 737 <
+985: 738 731 739 <
+986: 739 732 740 <
+987: 740 733 741 <
+988: 741 443 437 <
+989: 434 734 742 <
+990: 742 735 743 <
+991: 743 736 744 <
+992: 744 737 745 <
+993: 737 746 745 <
+994: 746 739 747 <
+995: 747 740 748 <
+996: 748 741 749 <
+997: 749 437 435 <
+998: 426 742 750 <
+999: 750 743 751 <
+1000: 751 744 752 <
+1001: 752 745 753 <
+1002: 745 754 753 <
+1003: 754 747 755 <
+1004: 755 748 756 <
+1005: 756 749 757 <
+1006: 757 435 427 <
+1007: 420 750 758 <
+1008: 758 751 759 <
+1009: 759 752 760 <
+1010: 760 753 761 <
+1011: 753 762 761 <
+1012: 762 755 763 <
+1013: 763 756 764 <
+1014: 764 757 765 <
+1015: 765 427 421 <
+1016: 422 758 766 <
+1017: 766 759 767 <
+1018: 767 760 768 <
+1019: 768 761 769 <
+1020: 761 770 769 <
+1021: 770 763 771 <
+1022: 771 764 772 <
+1023: 772 765 773 <
+1024: 773 421 423 <
+1025: 428 766 774 <
+1026: 774 767 775 <
+1027: 775 768 776 <
+1028: 776 769 777 <
+1029: 769 778 777 <
+1030: 778 771 779 <
+1031: 779 772 780 <
+1032: 780 773 781 <
+1033: 781 423 429 <
+1034: 424 774 782 <
+1035: 782 775 783 <
+1036: 783 776 784 <
+1037: 784 777 785 <
+1038: 785 778 786 <
+1039: 786 779 787 <
+1040: 787 780 788 <
+1041: 788 781 789 <
+1042: 789 429 425 <
+1043: 410 782 790 <
+1044: 790 783 791 <
+1045: 791 784 792 <
+1046: 792 785 793 <
+1047: 793 786 794 <
+1048: 794 787 795 <
+1049: 795 788 796 <
+1050: 796 789 797 <
+1051: 797 425 411 <
+1052: 408 790 798 <
+1053: 798 791 799 <
+1054: 799 792 800 <
+1055: 800 793 801 <
+1056: 801 794 802 <
+1057: 802 795 803 <
+1058: 803 796 804 <
+1059: 804 797 805 <
+1060: 805 411 409 <
+1061: 406 798 806 <
+1062: 806 799 807 <
+1063: 807 800 808 <
+1064: 808 801 809 <
+1065: 809 802 810 <
+1066: 810 803 811 <
+1067: 811 804 812 <
+1068: 812 805 813 <
+1069: 813 409 407 <
+1070: 404 806 814 <
+1071: 814 807 815 <
+1072: 815 808 816 <
+1073: 816 809 817 <
+1074: 817 810 818 <
+1075: 818 811 819 <
+1076: 819 812 820 <
+1077: 820 813 821 <
+1078: 821 407 405 <
+1079: 402 814 822 <
+1080: 822 815 823 <
+1081: 823 816 824 <
+1082: 824 817 825 <
+1083: 825 818 826 <
+1084: 826 819 827 <
+1085: 827 820 828 <
+1086: 828 821 829 <
+1087: 829 405 403 <
+1088: 400 822 830 <
+1089: 830 823 831 <
+1090: 831 824 832 <
+1091: 832 825 833 <
+1092: 833 826 834 <
+1093: 834 827 835 <
+1094: 835 828 836 <
+1095: 836 829 837 <
+1096: 837 403 401 <
+1097: 384 830 838 <
+1098: 838 831 839 <
+1099: 839 832 840 <
+1100: 840 833 841 <
+1101: 841 834 842 <
+1102: 842 835 843 <
+1103: 843 836 844 <
+1104: 844 837 845 <
+1105: 845 401 385 <
+1106: 378 838 478 <
+1107: 478 839 480 <
+1108: 480 840 482 <
+1109: 482 841 484 <
+1110: 484 842 486 <
+1111: 486 843 488 <
+1112: 488 844 490 <
+1113: 490 845 492 <
+1114: 492 385 379 <
+1115: 290 846 847 <
+1116: 847 848 849 <
+1117: 849 850 851 <
+1118: 851 293 291 <
+1119: 294 847 852 <
+1120: 847 853 852 <
+1121: 853 851 854 <
+1122: 854 291 295 <
+1123: 324 852 855 <
+1124: 855 853 856 <
+1125: 853 857 856 <
+1126: 857 295 325 <
+1127: 322 855 858 <
+1128: 855 859 858 <
+1129: 859 857 860 <
+1130: 860 325 323 <
+1131: 320 858 861 <
+1132: 861 859 862 <
+1133: 862 860 863 <
+1134: 863 323 321 <
+1135: 318 861 864 <
+1136: 864 862 865 <
+1137: 865 863 866 <
+1138: 866 321 319 <
+1139: 316 864 867 <
+1140: 867 865 868 <
+1141: 868 866 869 <
+1142: 869 319 317 <
+1143: 310 867 870 <
+1144: 870 868 871 <
+1145: 871 869 872 <
+1146: 872 317 311 <
+1147: 312 870 873 <
+1148: 873 871 874 <
+1149: 874 872 875 <
+1150: 875 311 313 <
+1151: 312 876 308 <
+1152: 873 877 876 <
+1153: 874 878 877 <
+1154: 875 309 878 <
+1155: 308 879 314 <
+1156: 876 880 879 <
+1157: 877 881 880 <
+1158: 878 315 881 <
+1159: 314 882 330 <
+1160: 879 883 882 <
+1161: 880 884 883 <
+1162: 881 331 884 <
+1163: 330 885 332 <
+1164: 882 886 885 <
+1165: 883 887 886 <
+1166: 884 333 887 <
+1167: 332 888 338 <
+1168: 885 889 888 <
+1169: 886 890 889 <
+1170: 887 339 890 <
+1171: 338 891 340 <
+1172: 888 892 891 <
+1173: 889 893 892 <
+1174: 890 341 893 <
+1175: 340 894 346 <
+1176: 891 895 894 <
+1177: 892 896 895 <
+1178: 893 347 896 <
+1179: 346 897 348 <
+1180: 894 898 897 <
+1181: 895 899 898 <
+1182: 896 349 899 <
+1183: 348 900 356 <
+1184: 897 901 900 <
+1185: 898 902 901 <
+1186: 899 357 902 <
+1187: 356 903 358 <
+1188: 900 904 903 <
+1189: 901 905 904 <
+1190: 902 359 905 <
+1191: 358 906 386 <
+1192: 903 907 906 <
+1193: 904 908 907 <
+1194: 905 387 908 <
+1195: 386 909 392 <
+1196: 906 910 909 <
+1197: 907 911 910 <
+1198: 908 393 911 <
+1199: 388 909 912 <
+1200: 909 913 912 <
+1201: 910 914 913 <
+1202: 914 393 389 <
+1203: 388 915 390 <
+1204: 915 913 916 <
+1205: 916 914 917 <
+1206: 914 391 917 <
+1207: 390 918 394 <
+1208: 915 919 918 <
+1209: 919 917 920 <
+1210: 917 395 920 <
+1211: 394 921 364 <
+1212: 921 919 922 <
+1213: 919 923 922 <
+1214: 920 365 923 <
+1215: 364 924 360 <
+1216: 921 925 924 <
+1217: 925 923 926 <
+1218: 923 361 926 <
+1219: 360 927 362 <
+1220: 927 925 928 <
+1221: 925 929 928 <
+1222: 926 363 929 <
+1223: 362 930 366 <
+1224: 927 931 930 <
+1225: 931 929 932 <
+1226: 929 367 932 <
+1227: 366 933 368 <
+1228: 933 931 934 <
+1229: 931 935 934 <
+1230: 932 369 935 <
+1231: 368 936 370 <
+1232: 933 937 936 <
+1233: 937 935 938 <
+1234: 935 371 938 <
+1235: 370 939 372 <
+1236: 936 940 939 <
+1237: 940 938 941 <
+1238: 938 373 941 <
+1239: 372 942 374 <
+1240: 942 940 943 <
+1241: 940 944 943 <
+1242: 941 375 944 <
+1243: 374 945 352 <
+1244: 945 943 946 <
+1245: 943 947 946 <
+1246: 944 353 947 <
+1247: 352 948 355 <
+1248: 945 949 948 <
+1249: 949 947 950 <
+1250: 947 354 950 <
+1251: 350 948 951 <
+1252: 951 949 952 <
+1253: 952 950 953 <
+1254: 953 354 351 <
+1255: 344 951 954 <
+1256: 954 952 955 <
+1257: 955 953 956 <
+1258: 956 351 345 <
+1259: 342 954 957 <
+1260: 957 955 958 <
+1261: 958 956 959 <
+1262: 959 345 343 <
+1263: 336 957 960 <
+1264: 960 958 961 <
+1265: 961 959 962 <
+1266: 962 343 337 <
+1267: 334 960 963 <
+1268: 963 961 964 <
+1269: 964 962 965 <
+1270: 965 337 335 <
+1271: 328 963 966 <
+1272: 966 964 967 <
+1273: 967 965 968 <
+1274: 968 335 329 <
+1275: 326 966 969 <
+1276: 969 967 970 <
+1277: 970 968 971 <
+1278: 971 329 327 <
+1279: 306 969 972 <
+1280: 972 970 973 <
+1281: 973 971 974 <
+1282: 974 327 307 <
+1283: 300 972 975 <
+1284: 975 973 976 <
+1285: 976 974 977 <
+1286: 977 307 301 <
+1287: 304 975 978 <
+1288: 978 976 979 <
+1289: 979 977 980 <
+1290: 980 301 305 <
+1291: 302 978 981 <
+1292: 981 979 982 <
+1293: 982 980 983 <
+1294: 983 305 303 <
+1295: 298 981 984 <
+1296: 984 982 985 <
+1297: 985 983 986 <
+1298: 986 303 299 <
+1299: 296 984 987 <
+1300: 987 985 988 <
+1301: 988 986 989 <
+1302: 989 299 297 <
+1303: 292 987 846 <
+1304: 846 988 848 <
+1305: 848 989 850 <
+1306: 850 297 293 <
+1307: 989 297 850 <
+1308: 988 989 848 <
+1309: 987 988 846 <
+1310: 296 987 292 <
+1311: 986 299 989 <
+1312: 985 986 988 <
+1313: 984 985 987 <
+1314: 298 984 296 <
+1315: 983 303 986 <
+1316: 982 983 985 <
+1317: 981 982 984 <
+1318: 302 981 298 <
+1319: 980 305 983 <
+1320: 979 980 982 <
+1321: 978 979 981 <
+1322: 304 978 302 <
+1323: 977 301 980 <
+1324: 976 977 979 <
+1325: 975 976 978 <
+1326: 300 975 304 <
+1327: 974 307 977 <
+1328: 973 974 976 <
+1329: 972 973 975 <
+1330: 306 972 300 <
+1331: 971 327 974 <
+1332: 970 971 973 <
+1333: 969 970 972 <
+1334: 326 969 306 <
+1335: 968 329 971 <
+1336: 967 968 970 <
+1337: 966 967 969 <
+1338: 328 966 326 <
+1339: 965 335 968 <
+1340: 964 965 967 <
+1341: 963 964 966 <
+1342: 334 963 328 <
+1343: 962 337 965 <
+1344: 961 962 964 <
+1345: 960 961 963 <
+1346: 336 960 334 <
+1347: 959 343 962 <
+1348: 958 959 961 <
+1349: 957 958 960 <
+1350: 342 957 336 <
+1351: 956 345 959 <
+1352: 955 956 958 <
+1353: 954 955 957 <
+1354: 344 954 342 <
+1355: 953 351 956 <
+1356: 952 953 955 <
+1357: 951 952 954 <
+1358: 350 951 344 <
+1359: 950 354 953 <
+1360: 949 950 952 <
+1361: 948 949 951 <
+1362: 355 948 350 <
+1363: 947 353 354 <
+1364: 946 947 949 <
+1365: 945 946 949 <
+1366: 352 945 948 <
+1367: 944 375 353 <
+1368: 943 944 947 <
+1369: 942 943 945 <
+1370: 374 942 945 <
+1371: 941 373 375 <
+1372: 940 941 944 <
+1373: 939 940 942 <
+1374: 372 939 942 <
+1375: 938 371 373 <
+1376: 937 938 940 <
+1377: 936 937 940 <
+1378: 370 936 939 <
+1379: 935 369 371 <
+1380: 934 935 937 <
+1381: 933 934 937 <
+1382: 368 933 936 <
+1383: 932 367 369 <
+1384: 931 932 935 <
+1385: 930 931 933 <
+1386: 366 930 933 <
+1387: 929 363 367 <
+1388: 928 929 931 <
+1389: 927 928 931 <
+1390: 362 927 930 <
+1391: 926 361 363 <
+1392: 925 926 929 <
+1393: 924 925 927 <
+1394: 360 924 927 <
+1395: 923 365 361 <
+1396: 922 923 925 <
+1397: 921 922 925 <
+1398: 364 921 924 <
+1399: 920 395 365 <
+1400: 919 920 923 <
+1401: 918 919 921 <
+1402: 394 918 921 <
+1403: 917 391 395 <
+1404: 916 917 919 <
+1405: 915 916 919 <
+1406: 390 915 918 <
+1407: 914 389 391 <
+1408: 913 914 916 <
+1409: 912 913 915 <
+1410: 388 912 915 <
+1411: 911 393 914 <
+1412: 910 911 914 <
+1413: 909 910 913 <
+1414: 392 909 388 <
+1415: 908 387 393 <
+1416: 907 908 911 <
+1417: 906 907 910 <
+1418: 386 906 909 <
+1419: 905 359 387 <
+1420: 904 905 908 <
+1421: 903 904 907 <
+1422: 358 903 906 <
+1423: 902 357 359 <
+1424: 901 902 905 <
+1425: 900 901 904 <
+1426: 356 900 903 <
+1427: 899 349 357 <
+1428: 898 899 902 <
+1429: 897 898 901 <
+1430: 348 897 900 <
+1431: 896 347 349 <
+1432: 895 896 899 <
+1433: 894 895 898 <
+1434: 346 894 897 <
+1435: 893 341 347 <
+1436: 892 893 896 <
+1437: 891 892 895 <
+1438: 340 891 894 <
+1439: 890 339 341 <
+1440: 889 890 893 <
+1441: 888 889 892 <
+1442: 338 888 891 <
+1443: 887 333 339 <
+1444: 886 887 890 <
+1445: 885 886 889 <
+1446: 332 885 888 <
+1447: 884 331 333 <
+1448: 883 884 887 <
+1449: 882 883 886 <
+1450: 330 882 885 <
+1451: 881 315 331 <
+1452: 880 881 884 <
+1453: 879 880 883 <
+1454: 314 879 882 <
+1455: 878 309 315 <
+1456: 877 878 881 <
+1457: 876 877 880 <
+1458: 308 876 879 <
+1459: 875 313 309 <
+1460: 874 875 878 <
+1461: 873 874 877 <
+1462: 312 873 876 <
+1463: 872 311 875 <
+1464: 871 872 874 <
+1465: 870 871 873 <
+1466: 310 870 312 <
+1467: 869 317 872 <
+1468: 868 869 871 <
+1469: 867 868 870 <
+1470: 316 867 310 <
+1471: 866 319 869 <
+1472: 865 866 868 <
+1473: 864 865 867 <
+1474: 318 864 316 <
+1475: 863 321 866 <
+1476: 862 863 865 <
+1477: 861 862 864 <
+1478: 320 861 318 <
+1479: 860 323 863 <
+1480: 859 860 862 <
+1481: 858 859 861 <
+1482: 322 858 320 <
+1483: 857 325 860 <
+1484: 856 857 859 <
+1485: 855 856 859 <
+1486: 324 855 322 <
+1487: 854 295 857 <
+1488: 853 854 857 <
+1489: 852 853 855 <
+1490: 294 852 324 <
+1491: 851 291 854 <
+1492: 849 851 853 <
+1493: 847 849 853 <
+1494: 290 847 294 <
+1495: 850 293 851 <
+1496: 848 850 849 <
+1497: 846 848 847 <
+1498: 292 846 290 <
+1499: 845 385 492 <
+1500: 844 845 490 <
+1501: 843 844 488 <
+1502: 842 843 486 <
+1503: 841 842 484 <
+1504: 840 841 482 <
+1505: 839 840 480 <
+1506: 838 839 478 <
+1507: 384 838 378 <
+1508: 837 401 845 <
+1509: 836 837 844 <
+1510: 835 836 843 <
+1511: 834 835 842 <
+1512: 833 834 841 <
+1513: 832 833 840 <
+1514: 831 832 839 <
+1515: 830 831 838 <
+1516: 400 830 384 <
+1517: 829 403 837 <
+1518: 828 829 836 <
+1519: 827 828 835 <
+1520: 826 827 834 <
+1521: 825 826 833 <
+1522: 824 825 832 <
+1523: 823 824 831 <
+1524: 822 823 830 <
+1525: 402 822 400 <
+1526: 821 405 829 <
+1527: 820 821 828 <
+1528: 819 820 827 <
+1529: 818 819 826 <
+1530: 817 818 825 <
+1531: 816 817 824 <
+1532: 815 816 823 <
+1533: 814 815 822 <
+1534: 404 814 402 <
+1535: 813 407 821 <
+1536: 812 813 820 <
+1537: 811 812 819 <
+1538: 810 811 818 <
+1539: 809 810 817 <
+1540: 808 809 816 <
+1541: 807 808 815 <
+1542: 806 807 814 <
+1543: 406 806 404 <
+1544: 805 409 813 <
+1545: 804 805 812 <
+1546: 803 804 811 <
+1547: 802 803 810 <
+1548: 801 802 809 <
+1549: 800 801 808 <
+1550: 799 800 807 <
+1551: 798 799 806 <
+1552: 408 798 406 <
+1553: 797 411 805 <
+1554: 796 797 804 <
+1555: 795 796 803 <
+1556: 794 795 802 <
+1557: 793 794 801 <
+1558: 792 793 800 <
+1559: 791 792 799 <
+1560: 790 791 798 <
+1561: 410 790 408 <
+1562: 789 425 797 <
+1563: 788 789 796 <
+1564: 787 788 795 <
+1565: 786 787 794 <
+1566: 785 786 793 <
+1567: 784 785 792 <
+1568: 783 784 791 <
+1569: 782 783 790 <
+1570: 424 782 410 <
+1571: 781 429 789 <
+1572: 780 781 788 <
+1573: 779 780 787 <
+1574: 778 779 786 <
+1575: 777 778 785 <
+1576: 776 777 784 <
+1577: 775 776 783 <
+1578: 774 775 782 <
+1579: 428 774 424 <
+1580: 773 423 781 <
+1581: 772 773 780 <
+1582: 771 772 779 <
+1583: 770 771 778 <
+1584: 769 770 778 <
+1585: 768 769 776 <
+1586: 767 768 775 <
+1587: 766 767 774 <
+1588: 422 766 428 <
+1589: 765 421 773 <
+1590: 764 765 772 <
+1591: 763 764 771 <
+1592: 762 763 770 <
+1593: 761 762 770 <
+1594: 760 761 768 <
+1595: 759 760 767 <
+1596: 758 759 766 <
+1597: 420 758 422 <
+1598: 757 427 765 <
+1599: 756 757 764 <
+1600: 755 756 763 <
+1601: 754 755 762 <
+1602: 753 754 762 <
+1603: 752 753 760 <
+1604: 751 752 759 <
+1605: 750 751 758 <
+1606: 426 750 420 <
+1607: 749 435 757 <
+1608: 748 749 756 <
+1609: 747 748 755 <
+1610: 746 747 754 <
+1611: 745 746 754 <
+1612: 744 745 752 <
+1613: 743 744 751 <
+1614: 742 743 750 <
+1615: 434 742 426 <
+1616: 741 437 749 <
+1617: 740 741 748 <
+1618: 739 740 747 <
+1619: 738 739 746 <
+1620: 737 738 746 <
+1621: 736 737 744 <
+1622: 735 736 743 <
+1623: 734 735 742 <
+1624: 436 734 434 <
+1625: 733 443 741 <
+1626: 732 733 740 <
+1627: 731 732 739 <
+1628: 730 731 738 <
+1629: 729 730 738 <
+1630: 728 729 736 <
+1631: 727 728 735 <
+1632: 726 727 734 <
+1633: 442 726 436 <
+1634: 725 445 733 <
+1635: 724 725 732 <
+1636: 723 724 731 <
+1637: 722 723 730 <
+1638: 721 722 730 <
+1639: 720 721 728 <
+1640: 719 720 727 <
+1641: 718 719 726 <
+1642: 444 718 442 <
+1643: 717 467 725 <
+1644: 716 717 724 <
+1645: 715 716 723 <
+1646: 714 715 722 <
+1647: 713 714 722 <
+1648: 712 713 720 <
+1649: 711 712 719 <
+1650: 710 711 718 <
+1651: 466 710 444 <
+1652: 709 463 717 <
+1653: 708 709 716 <
+1654: 707 708 715 <
+1655: 706 707 714 <
+1656: 705 706 714 <
+1657: 704 705 712 <
+1658: 703 704 711 <
+1659: 702 703 710 <
+1660: 462 702 466 <
+1661: 701 461 709 <
+1662: 700 701 708 <
+1663: 699 700 707 <
+1664: 698 699 706 <
+1665: 697 698 706 <
+1666: 696 697 704 <
+1667: 695 696 703 <
+1668: 694 695 702 <
+1669: 460 694 462 <
+1670: 693 465 701 <
+1671: 692 693 700 <
+1672: 691 692 699 <
+1673: 690 691 698 <
+1674: 689 690 698 <
+1675: 688 689 696 <
+1676: 687 688 695 <
+1677: 686 687 694 <
+1678: 464 686 460 <
+1679: 685 475 693 <
+1680: 684 685 692 <
+1681: 683 684 691 <
+1682: 682 683 690 <
+1683: 681 682 690 <
+1684: 680 681 688 <
+1685: 679 680 687 <
+1686: 678 679 686 <
+1687: 474 678 464 <
+1688: 677 476 685 <
+1689: 676 677 684 <
+1690: 675 676 683 <
+1691: 674 675 682 <
+1692: 673 674 682 <
+1693: 672 673 680 <
+1694: 671 672 679 <
+1695: 670 671 678 <
+1696: 477 670 474 <
+1697: 669 473 476 <
+1698: 668 669 677 <
+1699: 667 668 676 <
+1700: 666 667 675 <
+1701: 665 666 674 <
+1702: 664 665 673 <
+1703: 663 664 672 <
+1704: 662 663 671 <
+1705: 472 662 670 <
+1706: 661 471 473 <
+1707: 660 661 669 <
+1708: 659 660 668 <
+1709: 658 659 667 <
+1710: 657 658 666 <
+1711: 656 657 665 <
+1712: 655 656 664 <
+1713: 654 655 663 <
+1714: 470 654 662 <
+1715: 653 469 471 <
+1716: 652 653 661 <
+1717: 651 652 660 <
+1718: 650 651 659 <
+1719: 649 650 658 <
+1720: 648 649 657 <
+1721: 647 648 656 <
+1722: 646 647 655 <
+1723: 468 646 654 <
+1724: 645 459 469 <
+1725: 644 645 653 <
+1726: 643 644 652 <
+1727: 642 643 651 <
+1728: 641 642 650 <
+1729: 640 641 649 <
+1730: 639 640 648 <
+1731: 638 639 647 <
+1732: 458 638 646 <
+1733: 637 457 459 <
+1734: 636 637 645 <
+1735: 635 636 644 <
+1736: 634 635 643 <
+1737: 633 634 642 <
+1738: 632 633 641 <
+1739: 631 632 640 <
+1740: 630 631 639 <
+1741: 456 630 638 <
+1742: 629 455 457 <
+1743: 628 629 637 <
+1744: 627 628 636 <
+1745: 626 627 635 <
+1746: 625 626 634 <
+1747: 624 625 633 <
+1748: 623 624 632 <
+1749: 622 623 631 <
+1750: 454 622 630 <
+1751: 621 451 455 <
+1752: 620 621 629 <
+1753: 619 620 628 <
+1754: 618 619 627 <
+1755: 617 618 626 <
+1756: 616 617 625 <
+1757: 615 616 624 <
+1758: 614 615 623 <
+1759: 450 614 622 <
+1760: 613 449 451 <
+1761: 612 613 621 <
+1762: 611 612 620 <
+1763: 610 611 619 <
+1764: 609 610 618 <
+1765: 608 609 617 <
+1766: 607 608 616 <
+1767: 606 607 615 <
+1768: 448 606 614 <
+1769: 605 453 449 <
+1770: 604 605 613 <
+1771: 603 604 612 <
+1772: 602 603 611 <
+1773: 601 602 610 <
+1774: 600 601 609 <
+1775: 599 600 608 <
+1776: 598 599 607 <
+1777: 452 598 606 <
+1778: 597 447 453 <
+1779: 596 597 605 <
+1780: 595 596 604 <
+1781: 594 595 603 <
+1782: 593 594 601 <
+1783: 592 593 601 <
+1784: 591 592 600 <
+1785: 590 591 599 <
+1786: 446 590 598 <
+1787: 589 441 447 <
+1788: 588 589 597 <
+1789: 587 588 596 <
+1790: 586 587 595 <
+1791: 585 586 593 <
+1792: 584 585 593 <
+1793: 583 584 592 <
+1794: 582 583 591 <
+1795: 440 582 590 <
+1796: 581 439 441 <
+1797: 580 581 589 <
+1798: 579 580 588 <
+1799: 578 579 587 <
+1800: 577 578 585 <
+1801: 576 577 585 <
+1802: 575 576 584 <
+1803: 574 575 583 <
+1804: 438 574 582 <
+1805: 573 433 439 <
+1806: 572 573 581 <
+1807: 571 572 580 <
+1808: 570 571 579 <
+1809: 569 570 577 <
+1810: 568 569 577 <
+1811: 567 568 576 <
+1812: 566 567 575 <
+1813: 432 566 574 <
+1814: 565 431 433 <
+1815: 564 565 573 <
+1816: 563 564 572 <
+1817: 562 563 571 <
+1818: 561 562 569 <
+1819: 560 561 569 <
+1820: 559 560 568 <
+1821: 558 559 567 <
+1822: 430 558 566 <
+1823: 557 417 431 <
+1824: 556 557 565 <
+1825: 555 556 564 <
+1826: 554 555 563 <
+1827: 553 554 561 <
+1828: 552 553 561 <
+1829: 551 552 560 <
+1830: 550 551 559 <
+1831: 416 550 558 <
+1832: 549 413 417 <
+1833: 548 549 557 <
+1834: 547 548 556 <
+1835: 546 547 555 <
+1836: 545 546 553 <
+1837: 544 545 553 <
+1838: 543 544 552 <
+1839: 542 543 551 <
+1840: 412 542 550 <
+1841: 541 415 413 <
+1842: 540 541 549 <
+1843: 539 540 548 <
+1844: 538 539 547 <
+1845: 537 538 545 <
+1846: 536 537 545 <
+1847: 535 536 544 <
+1848: 534 535 543 <
+1849: 414 534 542 <
+1850: 533 419 415 <
+1851: 532 533 541 <
+1852: 531 532 540 <
+1853: 530 531 539 <
+1854: 529 530 537 <
+1855: 528 529 537 <
+1856: 527 528 536 <
+1857: 526 527 535 <
+1858: 418 526 534 <
+1859: 525 399 419 <
+1860: 524 525 533 <
+1861: 523 524 532 <
+1862: 522 523 531 <
+1863: 521 522 529 <
+1864: 520 521 529 <
+1865: 519 520 528 <
+1866: 518 519 527 <
+1867: 398 518 526 <
+1868: 517 397 399 <
+1869: 516 517 525 <
+1870: 515 516 524 <
+1871: 514 515 523 <
+1872: 513 514 521 <
+1873: 512 513 521 <
+1874: 511 512 520 <
+1875: 510 511 519 <
+1876: 396 510 518 <
+1877: 509 381 397 <
+1878: 508 509 517 <
+1879: 507 508 516 <
+1880: 506 507 515 <
+1881: 505 506 513 <
+1882: 504 505 513 <
+1883: 503 504 512 <
+1884: 502 503 511 <
+1885: 380 502 510 <
+1886: 501 383 381 <
+1887: 500 501 509 <
+1888: 499 500 508 <
+1889: 498 499 507 <
+1890: 497 498 505 <
+1891: 496 497 505 <
+1892: 495 496 504 <
+1893: 494 495 503 <
+1894: 382 494 502 <
+1895: 493 377 501 <
+1896: 491 493 500 <
+1897: 489 491 499 <
+1898: 487 489 498 <
+1899: 485 487 497 <
+1900: 483 485 496 <
+1901: 481 483 495 <
+1902: 479 481 494 <
+1903: 376 479 382 <
+1904: 492 379 493 <
+1905: 490 492 491 <
+1906: 488 490 489 <
+1907: 486 488 487 <
+1908: 484 486 485 <
+1909: 482 484 483 <
+1910: 480 482 481 <
+1911: 478 480 479 <
+1912: 378 478 376 <
+END
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/mesh_factory.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/mesh_factory.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/mesh_factory.py	(revision 3560)
@@ -0,0 +1,760 @@
+"""Library of standard meshes and facilities for reading various
+mesh file formats
+"""
+
+
+def rectangular_old(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
+
+    """Setup a rectangular grid of triangles
+    with m+1 by n+1 grid points
+    and side lengths len1, len2. If side lengths are omitted
+    the mesh defaults to the unit square.
+
+    len1: x direction (left to right)
+    len2: y direction (bottom to top)
+
+    Return to lists: points and elements suitable for creating a Mesh or
+    FVMesh object, e.g. Mesh(points, elements)
+    """
+
+    from anuga.config import epsilon
+
+    deltax = float(len1)/m
+    deltay = float(len2)/n
+
+    #Dictionary of vertex objects
+    vertices = {}
+    points = []
+
+    for i in range(m+1):
+        for j in range(n+1):
+            vertices[i,j] = len(points)
+            points.append([i*delta1 + origin[0], j*delta2 + origin[1]])
+
+
+    #Construct 2 triangles per rectangular element and assign tags to boundary
+    elements = []
+    boundary = {}
+    for i in range(m):
+        for j in range(n):
+            v1 = vertices[i,j+1]
+            v2 = vertices[i,j]
+            v3 = vertices[i+1,j+1]
+            v4 = vertices[i+1,j]
+
+            #Update boundary dictionary and create elements
+            if i == m-1:
+                boundary[(len(elements), 2)] = 'right'
+            if j == 0:
+                boundary[(len(elements), 1)] = 'bottom'
+            elements.append([v4,v3,v2]) #Lower element
+
+            if i == 0:
+                boundary[(len(elements), 2)] = 'left'
+            if j == n-1:
+                boundary[(len(elements), 1)] = 'top'
+            elements.append([v1,v2,v3]) #Upper element
+
+    return points, elements, boundary
+
+def rectangular(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
+
+    """Setup a rectangular grid of triangles
+    with m+1 by n+1 grid points
+    and side lengths len1, len2. If side lengths are omitted
+    the mesh defaults to the unit square.
+
+    len1: x direction (left to right)
+    len2: y direction (bottom to top)
+
+    Return to lists: points and elements suitable for creating a Mesh or
+    FVMesh object, e.g. Mesh(points, elements)
+    """
+
+    from anuga.config import epsilon
+    from Numeric import zeros, Float, Int
+
+    delta1 = float(len1)/m
+    delta2 = float(len2)/n
+
+    #Calculate number of points
+    Np = (m+1)*(n+1)
+
+    class Index:
+
+        def __init__(self, n,m):
+            self.n = n
+            self.m = m
+
+        def __call__(self, i,j):
+            return j+i*(self.n+1)
+
+
+    index = Index(n,m)
+
+    points = zeros( (Np,2), Float)
+
+    for i in range(m+1):
+        for j in range(n+1):
+
+            points[index(i,j),:] = [i*delta1 + origin[0], j*delta2 + origin[1]]
+
+    #Construct 2 triangles per rectangular element and assign tags to boundary
+    #Calculate number of triangles
+    Nt = 2*m*n
+
+
+    elements = zeros( (Nt,3), Int)
+    boundary = {}
+    nt = -1
+    for i in range(m):
+        for j in range(n):
+            nt = nt + 1
+            i1 = index(i,j+1)
+            i2 = index(i,j)
+            i3 = index(i+1,j+1)
+            i4 = index(i+1,j)
+
+
+            #Update boundary dictionary and create elements
+            if i == m-1:
+                boundary[nt, 2] = 'right'
+            if j == 0:
+                boundary[nt, 1] = 'bottom'
+            elements[nt,:] = [i4,i3,i2] #Lower element
+            nt = nt + 1
+
+            if i == 0:
+                boundary[nt, 2] = 'left'
+            if j == n-1:
+                boundary[nt, 1] = 'top'
+            elements[nt,:] = [i1,i2,i3] #Upper element
+
+    return points, elements, boundary
+
+
+def rectangular_cross(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
+
+    """Setup a rectangular grid of triangles
+    with m+1 by n+1 grid points
+    and side lengths len1, len2. If side lengths are omitted
+    the mesh defaults to the unit square.
+
+    len1: x direction (left to right)
+    len2: y direction (bottom to top)
+
+    Return to lists: points and elements suitable for creating a Mesh or
+    FVMesh object, e.g. Mesh(points, elements)
+    """
+
+    from anuga.config import epsilon
+    from Numeric import zeros, Float, Int
+
+    delta1 = float(len1)/m
+    delta2 = float(len2)/n
+
+    #Dictionary of vertex objects
+    vertices = {}
+    points = []
+
+    for i in range(m+1):
+        for j in range(n+1):
+            vertices[i,j] = len(points)
+            points.append([delta1*i + origin[0], delta2*j  + origin[1]])
+
+    # Construct 4 triangles per element
+    elements = []
+    boundary = {}
+    for i in range(m):
+        for j in range(n):
+            v1 = vertices[i,j+1]
+            v2 = vertices[i,j]
+            v3 = vertices[i+1,j+1]
+            v4 = vertices[i+1,j]
+            x = (points[v1][0]+points[v2][0]+points[v3][0]+points[v4][0])*0.25
+            y = (points[v1][1]+points[v2][1]+points[v3][1]+points[v4][1])*0.25
+
+            # Create centre point
+            v5 = len(points)
+            points.append([x, y])
+
+            #Create left triangle
+            if i == 0:
+                boundary[(len(elements), 1)] = 'left'
+            elements.append([v2,v5,v1])
+
+            #Create bottom triangle
+            if j == 0:
+                boundary[(len(elements), 1)] = 'bottom'
+            elements.append([v4,v5,v2])
+
+            #Create right triangle
+            if i == m-1:
+                boundary[(len(elements), 1)] = 'right'
+            elements.append([v3,v5,v4])
+
+            #Create top triangle
+            if j == n-1:
+                boundary[(len(elements), 1)] = 'top'
+            elements.append([v1,v5,v3])
+
+
+    return points, elements, boundary
+
+def oblique(m, n, lenx = 1.0, leny = 1.0, theta = 8.95, origin = (0.0, 0.0)):
+    """Setup a oblique grid of triangles
+    with m segments in the x-direction and n segments in the y-direction
+
+    """
+
+    from Numeric import array
+    import math
+
+    from anuga.config import epsilon
+
+
+    deltax = lenx/float(m)
+    deltay = leny/float(n)
+    a = 0.75*lenx*math.tan(theta/180.*math.pi)
+    x1 = lenx
+    y1 = 0
+    x2 = lenx
+    y2 = leny
+    x3 = 0.25*lenx
+    y3 = leny
+    x4 = x3
+    y4 = 0
+    a2 = a/(x1-x4)
+    a1 = -a2*x4
+    a4 = ((a1 + a2*x3)/y3-(a1 + a2*x2)/y2)/(x2-x3)
+    a3 = 1. - (a1 + a2*x3)/y3 - a4*x3
+
+    # Dictionary of vertex objects
+    vertices = {}
+    points = []
+
+    for i in range(m+1):
+        x = deltax*i
+        for j in range(n+1):
+            y = deltay*j
+            if x > 0.25*lenx:
+                y = a1 + a2*x + a3*y + a4*x*y
+
+            vertices[i,j] = len(points)
+            points.append([x + origin[0], y + origin[1]])
+
+    # Construct 2 triangles per element
+    elements = []
+    boundary = {}
+    for i in range(m):
+        for j in range(n):
+            v1 = vertices[i,j+1]
+            v2 = vertices[i,j]
+            v3 = vertices[i+1,j+1]
+            v4 = vertices[i+1,j]
+
+            #Update boundary dictionary and create elements
+            if i == m-1:
+                boundary[(len(elements), 2)] = 'right'
+            if j == 0:
+                boundary[(len(elements), 1)] = 'bottom'
+            elements.append([v4,v3,v2]) #Lower
+
+            if i == 0:
+                boundary[(len(elements), 2)] = 'left'
+            if j == n-1:
+                boundary[(len(elements), 1)] = 'top'
+
+            elements.append([v1,v2,v3]) #Upper
+
+    return points, elements, boundary
+
+
+def circular(m, n, radius=1.0, center = (0.0, 0.0)):
+    """Setup a circular grid of triangles with m concentric circles and
+    with n radial segments. If radius is are omitted the mesh defaults to
+    the unit circle radius.
+
+    radius: radius of circle
+
+    #FIXME: The triangles become degenerate for large values of m or n.
+    """
+
+
+
+    from math import pi, cos, sin
+
+    radius = float(radius) #Ensure floating point format
+
+    #Dictionary of vertex objects and list of points
+    vertices = {}
+    points = [[0.0, 0.0]] #Center point
+    vertices[0, 0] = 0
+
+    for i in range(n):
+        theta = 2*i*pi/n
+        x = cos(theta)
+        y = sin(theta)
+        for j in range(1,m+1):
+            delta = j*radius/m
+            vertices[i,j] = len(points)
+            points.append([delta*x, delta*y])
+
+    #Construct 2 triangles per element
+    elements = []
+    for i in range(n):
+        for j in range(1,m):
+
+            i1 = (i + 1) % n  #Wrap around
+
+            v1 = vertices[i,j+1]
+            v2 = vertices[i,j]
+            v3 = vertices[i1,j+1]
+            v4 = vertices[i1,j]
+
+            elements.append([v4,v2,v3]) #Lower
+            elements.append([v1,v3,v2]) #Upper
+
+
+    #Do the center
+    v1 = vertices[0,0]
+    for i in range(n):
+        i1 = (i + 1) % n  #Wrap around
+        v2 = vertices[i,1]
+        v3 = vertices[i1,1]
+
+        elements.append([v1,v2,v3]) #center
+
+    return points, elements
+
+
+def from_polyfile(name):
+    """Read mesh from .poly file, an obj like file format
+    listing first vertex coordinates and then connectivity
+    """
+
+    from anuga.abstract_2d_finite_volumes.util import anglediff
+    from math import pi
+    import os.path
+    root, ext = os.path.splitext(name)
+
+    if ext == 'poly':
+        filename = name
+    else:
+        filename = name + '.poly'
+
+
+    fid = open(filename)
+
+    points = []    #x, y
+    values = []    #z
+    ##vertex_values = []    #Repeated z
+    triangles = [] #v0, v1, v2
+
+    lines = fid.readlines()
+
+    keyword = lines[0].strip()
+    msg = 'First line in .poly file must contain the keyword: POINTS'
+    assert keyword == 'POINTS', msg
+
+    offending = 0
+    i = 1
+    while keyword == 'POINTS':
+        line = lines[i].strip()
+        i += 1
+
+        if line == 'POLYS':
+            keyword = line
+            break
+
+        fields = line.split(':')
+        assert int(fields[0]) == i-1, 'Point indices not consecutive'
+
+        #Split the three floats
+        xyz = fields[1].split()
+
+        x = float(xyz[0])
+        y = float(xyz[1])
+        z = float(xyz[2])
+
+        points.append([x, y])
+        values.append(z)
+
+
+    k = i
+    while keyword == 'POLYS':
+        line = lines[i].strip()
+        i += 1
+
+        if line == 'END':
+            keyword = line
+            break
+
+
+        fields = line.split(':')
+        assert int(fields[0]) == i-k, 'Poly indices not consecutive'
+
+        #Split the three indices
+        vvv = fields[1].split()
+
+        i0 = int(vvv[0])-1
+        i1 = int(vvv[1])-1
+        i2 = int(vvv[2])-1
+
+        #Check for and exclude degenerate areas
+        x0 = points[i0][0]
+        y0 = points[i0][1]
+        x1 = points[i1][0]
+        y1 = points[i1][1]
+        x2 = points[i2][0]
+        y2 = points[i2][1]
+
+        area = abs((x1*y0-x0*y1)+(x2*y1-x1*y2)+(x0*y2-x2*y0))/2
+        if area > 0:
+
+            #Ensure that points are arranged in counter clock-wise order
+            v0 = [x1-x0, y1-y0]
+            v1 = [x2-x1, y2-y1]
+            v2 = [x0-x2, y0-y2]
+
+            a0 = anglediff(v1, v0)
+            a1 = anglediff(v2, v1)
+            a2 = anglediff(v0, v2)
+
+
+            if a0 < pi and a1 < pi and a2 < pi:
+                #all is well
+                j0 = i0
+                j1 = i1
+                j2 = i2
+            else:
+                #Swap two vertices
+                j0 = i1
+                j1 = i0
+                j2 = i2
+
+            triangles.append([j0, j1, j2])
+            ##vertex_values.append([values[j0], values[j1], values[j2]])
+        else:
+            offending +=1
+
+    print 'Removed %d offending triangles out of %d' %(offending, len(lines))
+    return points, triangles, values
+
+
+
+def strang_mesh(filename):
+    """Read Strang generated mesh.
+    """
+
+    from math import pi
+    from anuga.abstract_2d_finite_volumes.util import anglediff
+
+
+    fid = open(filename)
+    points = []    # List of x, y coordinates
+    triangles = [] # List of vertex ids as listed in the file
+
+    for line in fid.readlines():
+        fields = line.split()
+        if len(fields) == 2:
+            # we are reading vertex coordinates
+            points.append([float(fields[0]), float(fields[1])])
+        elif len(fields) == 3:
+            # we are reading triangle point id's (format ae+b)
+            triangles.append([int(float(fields[0]))-1,
+                              int(float(fields[1]))-1,
+                              int(float(fields[2]))-1])
+        else:
+            raise 'wrong format in ' + filename
+
+    elements = [] #Final list of elements
+
+    for t in triangles:
+        #Get vertex coordinates
+        v0 = t[0]
+        v1 = t[1]
+        v2 = t[2]
+
+        x0 = points[v0][0]
+        y0 = points[v0][1]
+        x1 = points[v1][0]
+        y1 = points[v1][1]
+        x2 = points[v2][0]
+        y2 = points[v2][1]
+
+        #Check that points are arranged in counter clock-wise order
+        vec0 = [x1-x0, y1-y0]
+        vec1 = [x2-x1, y2-y1]
+        vec2 = [x0-x2, y0-y2]
+
+        a0 = anglediff(vec1, vec0)
+        a1 = anglediff(vec2, vec1)
+        a2 = anglediff(vec0, vec2)
+
+        if a0 < pi and a1 < pi and a2 < pi:
+            elements.append([v0, v1, v2])
+        else:
+            elements.append([v0, v2, v1])
+
+    return points, elements
+
+# #Map from edge number to indices of associated vertices
+# edge_map = ((1,2), (0,2), (0,1))
+
+def contracting_channel(m, n, W_upstream = 1., W_downstream = 0.75,
+                            L_1 = 5.0, L_2 = 2.0, L_3 = 10, origin = (0.0, 0.0)):
+    """Setup a contracting channel grid of triangles
+    with m segments in the x-direction and n segments in the y-direction
+
+    """
+
+    from Numeric import array
+    import math
+
+    from anuga.config import epsilon
+
+
+    lenx = L_1 + L_2 + L_3
+    leny = W_upstream
+    deltax = lenx/float(m)
+    deltay = leny/float(n)
+
+    x1 = 0
+    y1 = 0
+    x2 = L_1
+    y2 = 0
+    x3 = L_1 + L_2
+    y3 = (W_upstream - W_downstream)/2
+    x4 = L_1 + L_2 + L_3
+    y4 = y3
+    x5 = x4
+    y5 = y4 + W_downstream
+    x6 = L_1 + L_2
+    y6 = y5
+    x7 = L_1
+    y7 = W_upstream
+    x8 = 0
+    y8 = W_upstream
+    a1 = 0
+    a2 = (W_upstream - W_downstream)/(2*L_2)
+    a3 = 1
+    a4 = (W_downstream - W_upstream)/(L_2*W_upstream)
+
+    # Dictionary of vertex objects
+    vertices = {}
+    points = []
+
+    for i in range(m+1):
+        x = deltax*i
+        for j in range(n+1):
+            y = deltay*j
+            if x > L_1 and x <= (L_1 + L_2):
+                y = a1 + a2*(x - L_1) + a3*y + a4*(x - L_1)*y
+            elif x > L_1 + L_2:
+                y = (W_upstream - W_downstream)/2 + deltay*j*W_downstream/W_upstream
+
+            vertices[i,j] = len(points)
+            points.append([x + origin[0], y + origin[1]])
+
+    # Construct 2 triangles per element
+    elements = []
+    boundary = {}
+    for i in range(m):
+        for j in range(n):
+            v1 = vertices[i,j+1]
+            v2 = vertices[i,j]
+            v3 = vertices[i+1,j+1]
+            v4 = vertices[i+1,j]
+
+            #Update boundary dictionary and create elements
+            if i == m-1:
+                boundary[(len(elements), 2)] = 'right'
+            if j == 0:
+                boundary[(len(elements), 1)] = 'bottom'
+            elements.append([v4,v3,v2]) #Lower
+
+            if i == 0:
+                boundary[(len(elements), 2)] = 'left'
+            if j == n-1:
+                boundary[(len(elements), 1)] = 'top'
+
+            elements.append([v1,v2,v3]) #Upper
+
+    return points, elements, boundary
+
+
+def contracting_channel_cross(m, n, W_upstream = 1., W_downstream = 0.75,
+                              L_1 = 5.0, L_2 = 2.0, L_3 = 10, origin = (0.0, 0.0)):
+    """Setup a contracting channel grid of triangles
+    with m segments in the x-direction and n segments in the y-direction
+
+    """
+
+    from Numeric import array
+    import math
+
+    from anuga.config import epsilon
+
+
+    lenx = L_1 + L_2 + L_3
+    leny = W_upstream
+    deltax = lenx/float(m)
+    deltay = leny/float(n)
+
+    x1 = 0
+    y1 = 0
+    x2 = L_1
+    y2 = 0
+    x3 = L_1 + L_2
+    y3 = (W_upstream - W_downstream)/2
+    x4 = L_1 + L_2 + L_3
+    y4 = y3
+    x5 = x4
+    y5 = y4 + W_downstream
+    x6 = L_1 + L_2
+    y6 = y5
+    x7 = L_1
+    y7 = W_upstream
+    x8 = 0
+    y8 = W_upstream
+    a1 = 0
+    a2 = (W_upstream - W_downstream)/(2*L_2)
+    a3 = 1
+    a4 = (W_downstream - W_upstream)/(L_2*W_upstream)
+
+    # Dictionary of vertex objects
+    vertices = {}
+    points = []
+
+    for i in range(m+1):
+        x = deltax*i
+        for j in range(n+1):
+            y = deltay*j
+            if x > L_1 and x <= (L_1 + L_2):
+                y = a1 + a2*(x - L_1) + a3*y + a4*(x - L_1)*y
+            elif x > L_1 + L_2:
+                y = (W_upstream - W_downstream)/2 + deltay*j*W_downstream/W_upstream
+
+            vertices[i,j] = len(points)
+            points.append([x + origin[0], y + origin[1]])
+
+    # Construct 4 triangles per element
+    elements = []
+    boundary = {}
+    for i in range(m):
+        for j in range(n):
+            v1 = vertices[i,j+1]
+            v2 = vertices[i,j]
+            v3 = vertices[i+1,j+1]
+            v4 = vertices[i+1,j]
+            x = (points[v1][0]+points[v2][0]+points[v3][0]+points[v4][0])*0.25
+            y = (points[v1][1]+points[v2][1]+points[v3][1]+points[v4][1])*0.25
+            v5 = len(points)
+            points.append([x, y])
+
+            #Create left triangle
+            if i == 0:
+                boundary[(len(elements), 1)] = 'left'
+            elements.append([v2,v5,v1])
+
+            #Create bottom triangle
+            if j == 0:
+                boundary[(len(elements), 1)] = 'bottom'
+            elements.append([v4,v5,v2])
+
+            #Create right triangle
+            if i == m-1:
+                boundary[(len(elements), 1)] = 'right'
+            elements.append([v3,v5,v4])
+
+            #Create top triangle
+            if j == n-1:
+                boundary[(len(elements), 1)] = 'top'
+            elements.append([v1,v5,v3])
+
+
+    return points, elements, boundary
+
+
+
+
+def oblique_cross(m, n, lenx = 1.0, leny = 1.0, theta = 8.95, origin = (0.0, 0.0)):
+    """Setup a oblique grid of triangles
+    with m segments in the x-direction and n segments in the y-direction
+
+    """
+
+    from Numeric import array
+    import math
+
+    from anuga.config import epsilon
+
+
+    deltax = lenx/float(m)
+    deltay = leny/float(n)
+    a = 0.75*lenx*math.tan(theta/180.*math.pi)
+    x1 = lenx
+    y1 = 0
+    x2 = lenx
+    y2 = leny
+    x3 = 0.25*lenx
+    y3 = leny
+    x4 = x3
+    y4 = 0
+    a2 = a/(x1-x4)
+    a1 = -a2*x4
+    a4 = ((a1 + a2*x3)/y3-(a1 + a2*x2)/y2)/(x2-x3)
+    a3 = 1. - (a1 + a2*x3)/y3 - a4*x3
+
+    # Dictionary of vertex objects
+    vertices = {}
+    points = []
+
+    for i in range(m+1):
+        x = deltax*i
+        for j in range(n+1):
+            y = deltay*j
+            if x > 0.25*lenx:
+                y = a1 + a2*x + a3*y + a4*x*y
+
+            vertices[i,j] = len(points)
+            points.append([x + origin[0], y + origin[1]])
+
+    # Construct 4 triangles per element
+    elements = []
+    boundary = {}
+    for i in range(m):
+        for j in range(n):
+            v1 = vertices[i,j+1]
+            v2 = vertices[i,j]
+            v3 = vertices[i+1,j+1]
+            v4 = vertices[i+1,j]
+            x = (points[v1][0]+points[v2][0]+points[v3][0]+points[v4][0])*0.25
+            y = (points[v1][1]+points[v2][1]+points[v3][1]+points[v4][1])*0.25
+            v5 = len(points)
+            points.append([x, y])
+
+            #Update boundary dictionary and create elements
+                        #Create left triangle
+            if i == 0:
+                boundary[(len(elements), 1)] = 'left'
+            elements.append([v2,v5,v1])
+
+            #Create bottom triangle
+            if j == 0:
+                boundary[(len(elements), 1)] = 'bottom'
+            elements.append([v4,v5,v2])
+
+            #Create right triangle
+            if i == m-1:
+                boundary[(len(elements), 1)] = 'right'
+            elements.append([v3,v5,v4])
+
+            #Create top triangle
+            if j == n-1:
+                boundary[(len(elements), 1)] = 'top'
+            elements.append([v1,v5,v3])
+
+
+    return points, elements, boundary
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/mesh_factory_all.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/mesh_factory_all.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/mesh_factory_all.py	(revision 3560)
@@ -0,0 +1,522 @@
+"""Library of standard meshes and facilities for reading various
+mesh file formats
+"""
+
+
+def rectangular_old(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
+
+    """Setup a rectangular grid of triangles
+    with m+1 by n+1 grid points
+    and side lengths len1, len2. If side lengths are omitted
+    the mesh defaults to the unit square.
+
+    len1: x direction (left to right)
+    len2: y direction (bottom to top)
+
+    Return to lists: points and elements suitable for creating a Mesh or
+    FVMesh object, e.g. Mesh(points, elements)
+    """
+
+    from anuga.config import epsilon
+
+    #E = m*n*2        #Number of triangular elements
+    #P = (m+1)*(n+1)  #Number of initial vertices
+
+    delta1 = float(len1)/m
+    delta2 = float(len2)/n
+
+    #Dictionary of vertex objects
+    vertices = {}
+    points = []
+
+    for i in range(m+1):
+        for j in range(n+1):
+            vertices[i,j] = len(points)
+            points.append([i*delta1 + origin[0], j*delta2 + origin[1]])
+
+
+
+    #Construct 2 triangles per rectangular element and assign tags to boundary
+    elements = []
+    boundary = {}
+    for i in range(m):
+        for j in range(n):
+            v1 = vertices[i,j+1]
+            v2 = vertices[i,j]
+            v3 = vertices[i+1,j+1]
+            v4 = vertices[i+1,j]
+
+            #Update boundary dictionary and create elements
+            if i == m-1:
+                boundary[(len(elements), 2)] = 'right'
+            if j == 0:
+                boundary[(len(elements), 1)] = 'bottom'
+            elements.append([v4,v3,v2]) #Lower element
+
+            if i == 0:
+                boundary[(len(elements), 2)] = 'left'
+            if j == n-1:
+                boundary[(len(elements), 1)] = 'top'
+            elements.append([v1,v2,v3]) #Upper element
+
+    return points, elements, boundary
+
+def rectangular(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
+
+    """Setup a rectangular grid of triangles
+    with m+1 by n+1 grid points
+    and side lengths len1, len2. If side lengths are omitted
+    the mesh defaults to the unit square.
+
+    len1: x direction (left to right)
+    len2: y direction (bottom to top)
+
+    Return to lists: points and elements suitable for creating a Mesh or
+    FVMesh object, e.g. Mesh(points, elements)
+    """
+
+    from anuga.config import epsilon
+    from Numeric import zeros, Float, Int
+
+    delta1 = float(len1)/m
+    delta2 = float(len2)/n
+
+    #Calculate number of points
+    Np = (m+1)*(n+1)
+
+    class Index:
+
+        def __init__(self, n,m):
+            self.n = n
+            self.m = m
+
+        def __call__(self, i,j):
+            return j+i*(self.n+1)
+
+
+    index = Index(n,m)
+
+    points = zeros( (Np,2), Float)
+
+    for i in range(m+1):
+        for j in range(n+1):
+
+            points[index(i,j),:] = [i*delta1 + origin[0], j*delta2 + origin[1]]
+
+    #Construct 2 triangles per rectangular element and assign tags to boundary
+    #Calculate number of triangles
+    Nt = 2*m*n
+
+
+    elements = zeros( (Nt,3), Int)
+    boundary = {}
+    nt = -1
+    for i in range(m):
+        for j in range(n):
+            nt = nt + 1
+            i1 = index(i,j+1)
+            i2 = index(i,j)
+            i3 = index(i+1,j+1)
+            i4 = index(i+1,j)
+
+            #Update boundary dictionary and create elements
+            if i == m-1:
+                boundary[nt, 2] = 'right'
+            if j == 0:
+                boundary[nt, 1] = 'bottom'
+            elements[nt,:] = [i4,i3,i2] #Lower element
+            nt = nt + 1
+
+            if i == 0:
+                boundary[nt, 2] = 'left'
+            if j == n-1:
+                boundary[nt, 1] = 'top'
+            elements[nt,:] = [i1,i2,i3] #Upper element
+
+    return points, elements, boundary
+
+def oblique(m, n, lenx = 1.0, leny = 1.0, theta = 8.95, origin = (0.0, 0.0)):
+    """Setup a oblique grid of triangles
+    with m segments in the x-direction and n segments in the y-direction
+
+    """
+
+    from Numeric import array
+    import math
+
+    from anuga.config import epsilon
+
+
+    deltax = lenx/float(m)
+    deltay = leny/float(n)
+    a = 0.75*lenx*math.tan(theta/180.*math.pi)
+    x1 = lenx
+    y1 = 0
+    x2 = lenx
+    y2 = leny
+    x3 = 0.25*lenx
+    y3 = leny
+    x4 = x3
+    y4 = 0
+    a2 = a/(x1-x4)
+    a1 = -a2*x4
+    a4 = ((a1 + a2*x3)/y3-(a1 + a2*x2)/y2)/(x2-x3)
+    a3 = 1. - (a1 + a2*x3)/y3 - a4*x3
+
+    # Dictionary of vertex objects
+    vertices = {}
+    points = []
+
+    for i in range(m+1):
+        x = deltax*i
+        for j in range(n+1):
+            y = deltay*j
+            if x > 0.25*lenx:
+                y = a1 + a2*x + a3*y + a4*x*y
+
+            vertices[i,j] = len(points)
+            points.append([x + origin[0], y + origin[1]])
+
+    # Construct 2 triangles per element
+    elements = []
+    boundary = {}
+    for i in range(m):
+        for j in range(n):
+            v1 = vertices[i,j+1]
+            v2 = vertices[i,j]
+            v3 = vertices[i+1,j+1]
+            v4 = vertices[i+1,j]
+
+            #Update boundary dictionary and create elements
+            if i == m-1:
+                boundary[(len(elements), 2)] = 'right'
+            if j == 0:
+                boundary[(len(elements), 1)] = 'bottom'
+            elements.append([v4,v3,v2]) #Lower
+
+            if i == 0:
+                boundary[(len(elements), 2)] = 'left'
+            if j == n-1:
+                boundary[(len(elements), 1)] = 'top'
+
+            elements.append([v1,v2,v3]) #Upper
+
+    return points, elements, boundary
+
+
+def contracting_channel(m, n, W_upstream = 1., W_downstream = 0.75,
+                            L_1 = 5.0, L_2 = 2.0, L_3 = 10, origin = (0.0, 0.0)):
+    """Setup a contracting channel grid of triangles
+    with m segments in the x-direction and n segments in the y-direction
+
+    """
+
+    from Numeric import array
+    import math
+
+    from anuga.config import epsilon
+
+
+    lenx = L_1 + L_2 + L_3
+    leny = W_upstream
+    deltax = lenx/float(m)
+    deltay = leny/float(n)
+    
+    x1 = 0
+    y1 = 0
+    x2 = L_1
+    y2 = 0
+    x3 = L_1 + L_2
+    y3 = (W_upstream - W_downstream)/2
+    x4 = L_1 + L_2 + L_3
+    y4 = y3
+    x5 = x4
+    y5 = y4 + W_downstream
+    x6 = L_1 + L_2
+    y6 = y5
+    x7 = L_1
+    y7 = W_upstream
+    x8 = 0
+    y8 = W_upstream
+    a1 = 0
+    a2 = (W_upstream - W_downstream)/(2*L_2)
+    a3 = 1
+    a4 = (W_downstream - W_upstream)/(L_2*W_upstream)
+    
+    # Dictionary of vertex objects
+    vertices = {}
+    points = []
+
+    for i in range(m+1):
+        x = deltax*i
+        for j in range(n+1):
+            y = deltay*j
+            if x > L_1 and x <= (L_1 + L_2):              
+                y = a1 + a2*(x - L_1) + a3*y + a4*(x - L_1)*y
+            elif x > L_1 + L_2:
+                y = (W_upstream - W_downstream)/2 + deltay*j*W_downstream/W_upstream
+
+            vertices[i,j] = len(points)
+            points.append([x + origin[0], y + origin[1]])
+
+    # Construct 2 triangles per element
+    elements = []
+    boundary = {}
+    for i in range(m):
+        for j in range(n):
+            v1 = vertices[i,j+1]
+            v2 = vertices[i,j]
+            v3 = vertices[i+1,j+1]
+            v4 = vertices[i+1,j]
+
+            #Update boundary dictionary and create elements
+            if i == m-1:
+                boundary[(len(elements), 2)] = 'right'
+            if j == 0:
+                boundary[(len(elements), 1)] = 'bottom'
+            elements.append([v4,v3,v2]) #Lower
+
+            if i == 0:
+                boundary[(len(elements), 2)] = 'left'
+            if j == n-1:
+                boundary[(len(elements), 1)] = 'top'
+
+            elements.append([v1,v2,v3]) #Upper
+
+    return points, elements, boundary
+
+
+
+def circular(m, n, radius=1.0, center = (0.0, 0.0)):
+    """Setup a circular grid of triangles with m concentric circles and
+    with n radial segments. If radius is are omitted the mesh defaults to
+    the unit circle radius.
+
+    radius: radius of circle
+
+    #FIXME: The triangles become degenerate for large values of m or n.
+    """
+
+
+
+    from math import pi, cos, sin
+
+    radius = float(radius) #Ensure floating point format
+
+    #Dictionary of vertex objects and list of points
+    vertices = {}
+    points = [[0.0, 0.0]] #Center point
+    vertices[0, 0] = 0
+
+    for i in range(n):
+        theta = 2*i*pi/n
+        x = cos(theta)
+        y = sin(theta)
+        for j in range(1,m+1):
+            delta = j*radius/m
+            vertices[i,j] = len(points)
+            points.append([delta*x, delta*y])
+
+    #Construct 2 triangles per element
+    elements = []
+    for i in range(n):
+        for j in range(1,m):
+
+            i1 = (i + 1) % n  #Wrap around
+
+            v1 = vertices[i,j+1]
+            v2 = vertices[i,j]
+            v3 = vertices[i1,j+1]
+            v4 = vertices[i1,j]
+
+            elements.append([v4,v2,v3]) #Lower
+            elements.append([v1,v3,v2]) #Upper
+
+
+    #Do the center
+    v1 = vertices[0,0]
+    for i in range(n):
+        i1 = (i + 1) % n  #Wrap around
+        v2 = vertices[i,1]
+        v3 = vertices[i1,1]
+
+        elements.append([v1,v2,v3]) #center
+
+    return points, elements
+
+
+def from_polyfile(name):
+    """Read mesh from .poly file, an obj like file format
+    listing first vertex coordinates and then connectivity
+    """
+
+    from anuga.pyvolution.util import anglediff
+    from math import pi
+    import os.path
+    root, ext = os.path.splitext(name)
+
+    if ext == 'poly':
+        filename = name
+    else:
+        filename = name + '.poly'
+
+
+    fid = open(filename)
+
+    points = []    #x, y
+    values = []    #z
+    ##vertex_values = []    #Repeated z
+    triangles = [] #v0, v1, v2
+
+    lines = fid.readlines()
+
+    keyword = lines[0].strip()
+    msg = 'First line in .poly file must contain the keyword: POINTS'
+    assert keyword == 'POINTS', msg
+
+    offending = 0
+    i = 1
+    while keyword == 'POINTS':
+        line = lines[i].strip()
+        i += 1
+
+        if line == 'POLYS':
+            keyword = line
+            break
+
+        fields = line.split(':')
+        assert int(fields[0]) == i-1, 'Point indices not consecutive'
+
+        #Split the three floats
+        xyz = fields[1].split()
+
+        x = float(xyz[0])
+        y = float(xyz[1])
+        z = float(xyz[2])
+
+        points.append([x, y])
+        values.append(z)
+
+
+    k = i
+    while keyword == 'POLYS':
+        line = lines[i].strip()
+        i += 1
+
+        if line == 'END':
+            keyword = line
+            break
+
+
+        fields = line.split(':')
+        assert int(fields[0]) == i-k, 'Poly indices not consecutive'
+
+        #Split the three indices
+        vvv = fields[1].split()
+
+        i0 = int(vvv[0])-1
+        i1 = int(vvv[1])-1
+        i2 = int(vvv[2])-1
+
+        #Check for and exclude degenerate areas
+        x0 = points[i0][0]
+        y0 = points[i0][1]
+        x1 = points[i1][0]
+        y1 = points[i1][1]
+        x2 = points[i2][0]
+        y2 = points[i2][1]
+
+        area = abs((x1*y0-x0*y1)+(x2*y1-x1*y2)+(x0*y2-x2*y0))/2
+        if area > 0:
+
+            #Ensure that points are arranged in counter clock-wise order
+            v0 = [x1-x0, y1-y0]
+            v1 = [x2-x1, y2-y1]
+            v2 = [x0-x2, y0-y2]
+
+            a0 = anglediff(v1, v0)
+            a1 = anglediff(v2, v1)
+            a2 = anglediff(v0, v2)
+
+
+            if a0 < pi and a1 < pi and a2 < pi:
+                #all is well
+                j0 = i0
+                j1 = i1
+                j2 = i2
+            else:
+                #Swap two vertices
+                j0 = i1
+                j1 = i0
+                j2 = i2
+
+            triangles.append([j0, j1, j2])
+            ##vertex_values.append([values[j0], values[j1], values[j2]])
+        else:
+            offending +=1
+
+    print 'Removed %d offending triangles out of %d' %(offending, len(lines))
+    return points, triangles, values
+
+
+
+def strang_mesh(filename):
+    """Read Strang generated mesh.
+    """
+
+    from math import pi
+    from anuga.pyvolution.util import anglediff
+
+
+    fid = open(filename)
+    points = []    # List of x, y coordinates
+    triangles = [] # List of vertex ids as listed in the file
+
+    for line in fid.readlines():
+        fields = line.split()
+        if len(fields) == 2:
+            # we are reading vertex coordinates
+            points.append([float(fields[0]), float(fields[1])])
+        elif len(fields) == 3:
+            # we are reading triangle point id's (format ae+b)
+            triangles.append([int(float(fields[0]))-1,
+                              int(float(fields[1]))-1,
+                              int(float(fields[2]))-1])
+        else:
+            raise 'wrong format in ' + filename
+
+    elements = [] #Final list of elements
+
+    for t in triangles:
+        #Get vertex coordinates
+        v0 = t[0]
+        v1 = t[1]
+        v2 = t[2]
+
+        x0 = points[v0][0]
+        y0 = points[v0][1]
+        x1 = points[v1][0]
+        y1 = points[v1][1]
+        x2 = points[v2][0]
+        y2 = points[v2][1]
+
+        #Check that points are arranged in counter clock-wise order
+        vec0 = [x1-x0, y1-y0]
+        vec1 = [x2-x1, y2-y1]
+        vec2 = [x0-x2, y0-y2]
+
+        a0 = anglediff(vec1, vec0)
+        a1 = anglediff(vec2, vec1)
+        a2 = anglediff(vec0, vec2)
+
+        if a0 < pi and a1 < pi and a2 < pi:
+            elements.append([v0, v1, v2])
+        else:
+            elements.append([v0, v2, v1])
+
+    return points, elements
+
+# #Map from edge number to indices of associated vertices
+# edge_map = ((1,2), (0,2), (0,1))
+
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/most2nc.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/most2nc.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/most2nc.py	(revision 3560)
@@ -0,0 +1,86 @@
+def most2nc(input_file=None,output_file=None,inverted_bathymetry = False,\
+            verbose = True):
+    #input_file = 'small.txt'
+    #output_file = 'small_e.nc'
+
+    long_name = 'LON'
+    lat_name = 'LAT'
+    if inverted_bathymetry:
+	up = -1.
+    else:
+	up = +1.
+
+    from Scientific.IO.NetCDF import NetCDFFile
+    import sys
+
+    try:
+	if input_file is None:
+	    input_file = sys.argv[1]
+	if output_file is None:
+	    output_file = sys.argv[2]
+    except:
+	raise 'usage is: most2nc input output'
+
+    in_file = open(input_file,'r')
+    if verbose: print 'reading header'
+    nx_ny_str = in_file.readline()
+    nx_str,ny_str = nx_ny_str.split()
+    nx = int(nx_str)
+    ny = int(ny_str)
+    h1_list=[]
+    for i in range(nx):
+	h1_list.append(float(in_file.readline()))
+
+    h2_list=[]
+    for j in range(ny):
+	h2_list.append(float(in_file.readline()))
+
+    h2_list.reverse()
+
+    if verbose: print 'reading depths'
+
+    in_depth_list = in_file.readlines()
+    in_file.close()
+
+    out_depth_list = [[]]
+
+    if verbose: print 'processing depths'
+
+    k=1
+    for in_line in in_depth_list:
+	for string in in_line.split():
+	    #j = k/nx
+	    out_depth_list[(k-1)/nx].append(float(string)*up)
+	    #print k,len(out_depth_list),(k-1)/nx,out_depth_list[(k-1)/nx][-1],len(out_depth_list[(k-1)/nx])
+	    if k==nx*ny:
+		break
+	    if k-(k/nx)*nx ==0:
+		out_depth_list.append([])
+	    k+=1
+
+    in_file.close()
+    out_depth_list.reverse()
+    depth_list = out_depth_list
+
+    if verbose: print 'writing results'
+
+    out_file = NetCDFFile(output_file,'w')
+
+    out_file.createDimension(long_name,nx)
+    out_file.createVariable(long_name,'d',(long_name,))
+    out_file.variables[long_name].point_spacing='uneven'
+    out_file.variables[long_name].units='degrees_east'
+    out_file.variables[long_name].assignValue(h1_list)
+
+    out_file.createDimension(lat_name,ny)
+    out_file.createVariable(lat_name,'d',(lat_name,))
+    out_file.variables[lat_name].point_spacing='uneven'
+    out_file.variables[lat_name].units='degrees_north'
+    out_file.variables[lat_name].assignValue(h2_list)
+
+    out_file.createVariable('ELEVATION','d',(lat_name,long_name))
+    out_file.variables['ELEVATION'].point_spacing='uneven'
+    out_file.variables['ELEVATION'].units='meters'
+    out_file.variables['ELEVATION'].assignValue(depth_list)
+
+    out_file.close()
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/neighbour_mesh.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/neighbour_mesh.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/neighbour_mesh.py	(revision 3560)
@@ -0,0 +1,773 @@
+"""Classes implementing general 2D triangular mesh with neighbour structure.
+
+   This structure is purely geometrical. Anything relating to quantities
+   or timestepping is implemented in subclass domain.py.
+
+   Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+   Geoscience Australia, 2004
+"""
+
+from general_mesh import General_mesh
+from math import pi, sqrt
+        
+
+class Mesh(General_mesh):
+    """Collection of triangular elements (purely geometric)
+
+    A triangular element is defined in terms of three vertex ids,
+    ordered counter clock-wise,
+    each corresponding to a given coordinate set.
+    Vertices from different elements can point to the same
+    coordinate set.
+
+    Coordinate sets are implemented as an N x 2 Numeric array containing
+    x and y coordinates.
+
+
+    To instantiate:
+       Mesh(coordinates, triangles)
+
+    where
+
+      coordinates is either a list of 2-tuples or an Mx2 Numeric array of
+      floats representing all x, y coordinates in the mesh.
+
+      triangles is either a list of 3-tuples or an Nx3 Numeric array of
+      integers representing indices of all vertices in the mesh.
+      Each vertex is identified by its index i in [0, M-1].
+
+
+    Example:
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0,0.0]
+        e = [2.0, 2.0]
+
+        points = [a, b, c, e]
+        triangles = [ [1,0,2], [1,2,3] ]   #bac, bce
+        mesh = Mesh(points, triangles)
+
+        #creates two triangles: bac and bce
+
+
+    Mesh takes the optional third argument boundary which is a
+    dictionary mapping from (element_id, edge_id) to boundary tag.
+    The default value is None which will assign the default_boundary_tag
+    as specified in config.py to all boundary edges.
+    """
+
+    #FIXME: Maybe rename coordinates to points (as in a poly file)
+    #But keep 'vertex_coordinates'
+
+    #FIXME: Put in check for angles less than a set minimum
+
+
+    def __init__(self, coordinates, triangles,
+                 boundary=None,
+                 tagged_elements=None,
+                 geo_reference=None,
+                 use_inscribed_circle=False,
+                 verbose=False):
+        """
+        Build triangles from x,y coordinates (sequence of 2-tuples or
+        Mx2 Numeric array of floats) and triangles (sequence of 3-tuples
+        or Nx3 Numeric array of non-negative integers).
+        """
+
+
+
+        from Numeric import array, zeros, Int, Float, maximum, sqrt, sum
+
+        General_mesh.__init__(self, coordinates, triangles,
+                              geo_reference, verbose=verbose)
+
+        if verbose: print 'Initialising mesh'         
+
+        N = self.number_of_elements
+
+        self.use_inscribed_circle = use_inscribed_circle
+
+        #Allocate space for geometric quantities
+        self.centroid_coordinates = zeros((N, 2), Float)
+
+        self.radii = zeros(N, Float)
+
+        self.neighbours = zeros((N, 3), Int)
+        self.neighbour_edges = zeros((N, 3), Int)
+        self.number_of_boundaries = zeros(N, Int)
+        self.surrogate_neighbours = zeros((N, 3), Int)
+
+        #Get x,y coordinates for all triangles and store
+        V = self.vertex_coordinates # Relative coordinates
+
+        #Initialise each triangle
+        if verbose: print 'Mesh: Computing centroids and radii'        
+        for i in range(N):
+            if verbose and i % ((N+10)/10) == 0: print '(%d/%d)' %(i, N)
+
+            x0 = V[i, 0]; y0 = V[i, 1]
+            x1 = V[i, 2]; y1 = V[i, 3]
+            x2 = V[i, 4]; y2 = V[i, 5]
+
+            #Compute centroid
+            centroid = array([(x0 + x1 + x2)/3, (y0 + y1 + y2)/3])
+            self.centroid_coordinates[i] = centroid
+
+
+            if self.use_inscribed_circle == False:
+                #OLD code. Computed radii may exceed that of an
+                #inscribed circle
+
+                #Midpoints
+                m0 = array([(x1 + x2)/2, (y1 + y2)/2])
+                m1 = array([(x0 + x2)/2, (y0 + y2)/2])
+                m2 = array([(x1 + x0)/2, (y1 + y0)/2])
+
+                #The radius is the distance from the centroid of
+                #a triangle to the midpoint of the side of the triangle
+                #closest to the centroid
+                d0 = sqrt(sum( (centroid-m0)**2 ))
+                d1 = sqrt(sum( (centroid-m1)**2 ))
+                d2 = sqrt(sum( (centroid-m2)**2 ))
+
+                self.radii[i] = min(d0, d1, d2)
+
+            else:
+                #NEW code added by Peter Row. True radius
+                #of inscribed circle is computed
+
+                a = sqrt((x0-x1)**2+(y0-y1)**2)
+                b = sqrt((x1-x2)**2+(y1-y2)**2)
+                c = sqrt((x2-x0)**2+(y2-y0)**2)
+
+                self.radii[i]=2.0*self.areas[i]/(a+b+c)
+
+
+            #Initialise Neighbours (-1 means that it is a boundary neighbour)
+            self.neighbours[i, :] = [-1, -1, -1]
+
+            #Initialise edge ids of neighbours
+            #In case of boundaries this slot is not used
+            self.neighbour_edges[i, :] = [-1, -1, -1]
+
+
+        #Build neighbour structure
+        if verbose: print 'Mesh: Building neigbour structure'                
+        self.build_neighbour_structure()
+
+        #Build surrogate neighbour structure
+        if verbose: print 'Mesh: Building surrogate neigbour structure'
+        self.build_surrogate_neighbour_structure()
+
+        #Build boundary dictionary mapping (id, edge) to symbolic tags
+        if verbose: print 'Mesh: Building boundary dictionary'
+        self.build_boundary_dictionary(boundary)
+
+        #Build tagged element  dictionary mapping (tag) to array of elements
+        if verbose: print 'Mesh: Building tagged elements dictionary'        
+        self.build_tagged_elements_dictionary(tagged_elements)
+
+        #Update boundary indices FIXME: OBSOLETE
+        #self.build_boundary_structure()
+
+        #FIXME check integrity?
+        if verbose: print 'Mesh: Done'                
+
+    def __repr__(self):
+        return 'Mesh: %d triangles, %d elements, %d boundary segments'\
+               %(self.coordinates.shape[0], len(self), len(self.boundary))
+
+
+    def set_to_inscribed_circle(self,safety_factor = 1):
+        #FIXME phase out eventually
+        N = self.number_of_elements
+        V = self.vertex_coordinates
+
+        #initialising min and max ratio
+        i=0
+        old_rad = self.radii[i]
+        x0 = V[i, 0]; y0 = V[i, 1]
+        x1 = V[i, 2]; y1 = V[i, 3]
+        x2 = V[i, 4]; y2 = V[i, 5]
+        a = sqrt((x0-x1)**2+(y0-y1)**2)
+        b = sqrt((x1-x2)**2+(y1-y2)**2)
+        c = sqrt((x2-x0)**2+(y2-y0)**2)
+        ratio = old_rad/self.radii[i]
+        max_ratio = ratio
+        min_ratio = ratio
+
+        for i in range(N):
+            old_rad = self.radii[i]
+            x0 = V[i, 0]; y0 = V[i, 1]
+            x1 = V[i, 2]; y1 = V[i, 3]
+            x2 = V[i, 4]; y2 = V[i, 5]
+            a = sqrt((x0-x1)**2+(y0-y1)**2)
+            b = sqrt((x1-x2)**2+(y1-y2)**2)
+            c = sqrt((x2-x0)**2+(y2-y0)**2)
+            self.radii[i]=self.areas[i]/(2*(a+b+c))*safety_factor
+            ratio = old_rad/self.radii[i]
+            if ratio >= max_ratio: max_ratio = ratio
+            if ratio <= min_ratio: min_ratio = ratio
+        return max_ratio,min_ratio
+
+    def build_neighbour_structure(self):
+        """Update all registered triangles to point to their neighbours.
+
+        Also, keep a tally of the number of boundaries for each triangle
+
+        Postconditions:
+          neighbours and neighbour_edges is populated
+          number_of_boundaries integer array is defined.
+        """
+
+        #Step 1:
+        #Build dictionary mapping from segments (2-tuple of points)
+        #to left hand side edge (facing neighbouring triangle)
+
+        N = self.number_of_elements
+        neighbourdict = {}
+        for i in range(N):
+
+            #Register all segments as keys mapping to current triangle
+            #and segment id
+            a = self.triangles[i, 0]
+            b = self.triangles[i, 1]
+            c = self.triangles[i, 2]
+            if neighbourdict.has_key((a,b)):
+                    msg = "Edge 2 of triangle %d is duplicating edge %d of triangle %d.\n" %(i,neighbourdict[a,b][1],neighbourdict[a,b][0])
+                    raise Exception, msg
+            if neighbourdict.has_key((b,c)):
+                    msg = "Edge 0 of triangle %d is duplicating edge %d of triangle %d.\n" %(i,neighbourdict[b,c][1],neighbourdict[b,c][0])
+                    raise msg
+            if neighbourdict.has_key((c,a)):
+                    msg = "Edge 1 of triangle %d is duplicating edge %d of triangle %d.\n" %(i,neighbourdict[c,a][1],neighbourdict[c,a][0])
+                    raise msg
+
+            neighbourdict[a,b] = (i, 2) #(id, edge)
+            neighbourdict[b,c] = (i, 0) #(id, edge)
+            neighbourdict[c,a] = (i, 1) #(id, edge)
+
+
+        #Step 2:
+        #Go through triangles again, but this time
+        #reverse direction of segments and lookup neighbours.
+        for i in range(N):
+            a = self.triangles[i, 0]
+            b = self.triangles[i, 1]
+            c = self.triangles[i, 2]
+
+            self.number_of_boundaries[i] = 3
+            if neighbourdict.has_key((b,a)):
+                self.neighbours[i, 2] = neighbourdict[b,a][0]
+                self.neighbour_edges[i, 2] = neighbourdict[b,a][1]
+                self.number_of_boundaries[i] -= 1
+
+            if neighbourdict.has_key((c,b)):
+                self.neighbours[i, 0] = neighbourdict[c,b][0]
+                self.neighbour_edges[i, 0] = neighbourdict[c,b][1]
+                self.number_of_boundaries[i] -= 1
+
+            if neighbourdict.has_key((a,c)):
+                self.neighbours[i, 1] = neighbourdict[a,c][0]
+                self.neighbour_edges[i, 1] = neighbourdict[a,c][1]
+                self.number_of_boundaries[i] -= 1
+
+
+    def build_surrogate_neighbour_structure(self):
+        """Build structure where each triangle edge points to its neighbours
+        if they exist. Otherwise point to the triangle itself.
+
+        The surrogate neighbour structure is useful for computing gradients
+        based on centroid values of neighbours.
+
+        Precondition: Neighbour structure is defined
+        Postcondition:
+          Surrogate neighbour structure is defined:
+          surrogate_neighbours: i0, i1, i2 where all i_k >= 0 point to
+          triangles.
+
+        """
+
+        N = self.number_of_elements
+        for i in range(N):
+            #Find all neighbouring volumes that are not boundaries
+            for k in range(3):
+                if self.neighbours[i, k] < 0:
+                    self.surrogate_neighbours[i, k] = i #Point this triangle
+                else:
+                    self.surrogate_neighbours[i, k] = self.neighbours[i, k]
+
+
+
+    def build_boundary_dictionary(self, boundary = None):
+        """Build or check the dictionary of boundary tags.
+         self.boundary is a dictionary of tags,
+         keyed by volume id and edge:
+         { (id, edge): tag, ... }
+
+         Postconditions:
+            self.boundary is defined.
+        """
+
+        from anuga.config import default_boundary_tag
+
+        if boundary is None:
+            boundary = {}
+            for vol_id in range(self.number_of_elements):
+                for edge_id in range(0, 3):
+                    if self.neighbours[vol_id, edge_id] < 0:
+                        boundary[(vol_id, edge_id)] = default_boundary_tag
+        else:
+            #Check that all keys in given boundary exist
+            for vol_id, edge_id in boundary.keys():
+                msg = 'Segment (%d, %d) does not exist' %(vol_id, edge_id)
+                a, b = self.neighbours.shape
+                assert vol_id < a and edge_id < b, msg
+
+                #FIXME: This assert violates internal boundaries (delete it)
+                #msg = 'Segment (%d, %d) is not a boundary' %(vol_id, edge_id)
+                #assert self.neighbours[vol_id, edge_id] < 0, msg
+
+            #Check that all boundary segments are assigned a tag
+            for vol_id in range(self.number_of_elements):
+                for edge_id in range(0, 3):
+                    if self.neighbours[vol_id, edge_id] < 0:
+                        if not boundary.has_key( (vol_id, edge_id) ):
+                            msg = 'WARNING: Given boundary does not contain '
+                            msg += 'tags for edge (%d, %d). '\
+                                   %(vol_id, edge_id)
+                            msg += 'Assigning default tag (%s).'\
+                                   %default_boundary_tag
+
+                            #FIXME: Print only as per verbosity
+                            #print msg
+
+                            #FIXME: Make this situation an error in the future
+                            #and make another function which will
+                            #enable default boundary-tags where
+                            #tags a not specified
+                            boundary[ (vol_id, edge_id) ] =\
+                                      default_boundary_tag
+
+
+
+        self.boundary = boundary
+
+
+    def build_tagged_elements_dictionary(self, tagged_elements = None):
+        """Build the dictionary of element tags.
+         self.tagged_elements is a dictionary of element arrays,
+         keyed by tag:
+         { (tag): [e1, e2, e3..] }
+
+         Postconditions:
+            self.element_tag is defined
+        """
+        from Numeric import array, Int
+
+        if tagged_elements is None:
+            tagged_elements = {}
+        else:
+            #Check that all keys in given boundary exist
+            for tag in tagged_elements.keys():
+                tagged_elements[tag] = array(tagged_elements[tag]).astype(Int)
+
+                msg = 'Not all elements exist. '
+                assert max(tagged_elements[tag]) < self.number_of_elements, msg
+        #print "tagged_elements", tagged_elements
+        self.tagged_elements = tagged_elements
+
+    def build_boundary_structure(self):
+        """Traverse boundary and
+        enumerate neighbour indices from -1 and
+        counting down.
+
+        Precondition:
+            self.boundary is defined.
+        Post condition:
+            neighbour array has unique negative indices for boundary
+            boundary_segments array imposes an ordering on segments
+            (not otherwise available from the dictionary)
+
+        Note: If a segment is listed in the boundary dictionary
+        it *will* become a boundary - even if there is a neighbouring triangle.
+        This would be the case for internal boundaries
+        """
+
+        #FIXME: Now Obsolete - maybe use some comments from here in
+        #domain.set_boundary
+
+        if self.boundary is None:
+            msg = 'Boundary dictionary must be defined before '
+            msg += 'building boundary structure'
+            raise msg
+
+
+        self.boundary_segments = self.boundary.keys()
+        self.boundary_segments.sort()
+
+        index = -1
+        for id, edge in self.boundary_segments:
+
+            #FIXME: One would detect internal boundaries as follows
+            #if self.neighbours[id, edge] > -1:
+            #    print 'Internal boundary'
+
+            self.neighbours[id, edge] = index
+            index -= 1
+
+
+    def get_boundary_tags(self):
+        """Return list of available boundary tags
+        """
+
+        tags = {}
+        for v in self.boundary.values():
+            tags[v] = 1
+
+        return tags.keys()
+
+
+    def get_boundary_polygon(self, verbose=False):
+        """Return bounding polygon for mesh (counter clockwise)
+
+        Using the mesh boundary, derive a bounding polygon for this mesh.
+        If multiple vertex values are present, the algorithm will select the
+        path that contains the mesh.
+
+        All points are in absolute UTM coordinates
+        """
+        
+        from Numeric import allclose, sqrt, array, minimum, maximum
+        from anuga.utilities.numerical_tools import angle, ensure_numeric        
+
+
+        # Get mesh extent
+        xmin, xmax, ymin, ymax = self.get_extent(absolute=True)
+        pmin = ensure_numeric([xmin, ymin])
+        pmax = ensure_numeric([xmax, ymax])        
+
+
+        # Assemble dictionary of boundary segments and choose starting point
+        segments = {}
+        inverse_segments = {}
+        p0 = None
+        mindist = sqrt(sum((pmax-pmin)**2)) #Start value across entire mesh
+        for i, edge_id in self.boundary.keys():
+            # Find vertex ids for boundary segment
+            if edge_id == 0: a = 1; b = 2
+            if edge_id == 1: a = 2; b = 0
+            if edge_id == 2: a = 0; b = 1
+
+            A = self.get_vertex_coordinate(i, a, absolute=True) # Start
+            B = self.get_vertex_coordinate(i, b, absolute=True) # End
+
+
+            # Take the point closest to pmin as starting point
+            # Note: Could be arbitrary, but nice to have
+            # a unique way of selecting
+            dist_A = sqrt(sum((A-pmin)**2))
+            dist_B = sqrt(sum((B-pmin)**2))
+
+            #Find lower leftmost point
+            if dist_A < mindist:
+                mindist = dist_A
+                p0 = A
+            if dist_B < mindist:
+                mindist = dist_B
+                p0 = B
+
+
+            # Sanity check
+            if p0 is None:
+                raise Exception('Impossible')
+
+
+            # Register potential paths from A to B
+            if not segments.has_key(tuple(A)):
+                segments[tuple(A)] = [] # Empty list for candidate points                
+                
+            segments[tuple(A)].append(B)                
+
+
+
+            
+        #Start with smallest point and follow boundary (counter clock wise)
+        polygon = [p0]      # Storage for final boundary polygon
+        point_registry = {} # Keep track of storage to avoid multiple runs around
+                            # boundary. This will only be the case if there are
+                            # more than one candidate.
+                            # FIXME (Ole): Perhaps we can do away with polygon
+                            # and use only point_registry to save space.
+
+        point_registry[tuple(p0)] = 0                            
+                            
+        #while len(polygon) < len(self.boundary):
+        while len(point_registry) < len(self.boundary):
+
+            candidate_list = segments[tuple(p0)]
+            if len(candidate_list) > 1:
+                # Multiple points detected
+                # Take the candidate that is furthest to the clockwise direction,
+                # as that will follow the boundary.
+
+
+                if verbose:
+                    print 'Point %s has multiple candidates: %s'\
+                          %(str(p0), candidate_list)
+
+
+                # Choose vector against which all angles will be measured
+                if len(polygon) > 1:    
+                    v_prev = p0 - polygon[-2] # Vector that leads to p0
+                else:
+                    # FIXME (Ole): What do we do if the first point has multiple
+                    # candidates?
+                    # Being the lower left corner, perhaps we can use the
+                    # vector [1, 0], but I really don't know if this is completely
+                    # watertight.
+                    # Another option might be v_prev = [1.0, 0.0]
+                    v_prev = [1.0, 0.0]
+                    
+
+                    
+                # Choose candidate with minimum angle    
+                minimum_angle = 2*pi
+                for pc in candidate_list:
+                    vc = pc-p0  # Candidate vector
+                    
+                    # Angle between each candidate and the previous vector
+                    # in [-pi, pi]
+                    ac = angle(vc, v_prev)
+                    if ac > pi: ac = pi-ac
+
+                    # take the minimal angle corresponding to the rightmost vector
+                    if ac < minimum_angle:
+                        minimum_angle = ac
+                        p1 = pc             # Best candidate 
+                        
+
+                if verbose is True:
+                    print '  Best candidate %s, angle %f' %(p1, minimum_angle*180/pi)
+                
+            else:
+                p1 = candidate_list[0]
+
+            if point_registry.has_key(tuple(p1)):
+                # We have completed the boundary polygon - yeehaa
+                break 
+            else:
+                point_registry[tuple(p1)] = len(point_registry)
+            
+            polygon.append(p1)
+            p0 = p1
+
+
+        return polygon
+
+
+    def check_integrity(self):
+        """Check that triangles are internally consistent e.g.
+        that area corresponds to edgelengths, that vertices
+        are arranged in a counter-clockwise order, etc etc
+        Neighbour structure will be checked by class Mesh
+        """
+
+        from anuga.config import epsilon
+        from anuga.utilities.numerical_tools import anglediff
+
+        N = self.number_of_elements
+        #Get x,y coordinates for all vertices for all triangles
+        V = self.get_vertex_coordinates()
+        #Check each triangle
+        for i in range(N):
+            
+            x0 = V[i, 0]; y0 = V[i, 1]
+            x1 = V[i, 2]; y1 = V[i, 3]
+            x2 = V[i, 4]; y2 = V[i, 5]
+
+            #Check that area hasn't been compromised
+            area = self.areas[i]
+            ref = abs((x1*y0-x0*y1)+(x2*y1-x1*y2)+(x0*y2-x2*y0))/2
+            msg = 'Wrong area for vertex coordinates: %f %f %f %f %f %f'\
+                  %(x0,y0,x1,y1,x2,y2)
+            assert abs((area - ref)/area) < epsilon, msg
+
+            #Check that points are arranged in counter clock-wise order
+            v0 = [x1-x0, y1-y0]
+            v1 = [x2-x1, y2-y1]
+            v2 = [x0-x2, y0-y2]
+
+            a0 = anglediff(v1, v0)
+            a1 = anglediff(v2, v1)
+            a2 = anglediff(v0, v2)
+
+            msg = '''Vertices (%s,%s), (%s,%s), (%s,%s) are not arranged
+            in counter clockwise order''' %(x0, y0, x1, y1, x2, y2)
+            assert a0 < pi and a1 < pi and a2 < pi, msg
+
+            #Check that normals are orthogonal to edge vectors
+            #Note that normal[k] lies opposite vertex k
+
+            normal0 = self.normals[i, 0:2]
+            normal1 = self.normals[i, 2:4]
+            normal2 = self.normals[i, 4:6]
+
+            for u, v in [ (v0, normal2), (v1, normal0), (v2, normal1) ]:
+
+                #Normalise
+                l_u = sqrt(u[0]*u[0] + u[1]*u[1])
+                l_v = sqrt(v[0]*v[0] + v[1]*v[1])                
+
+                x = (u[0]*v[0] + u[1]*v[1])/l_u/l_v #Inner product
+                
+                msg = 'Normal vector (%f,%f) is not perpendicular to' %tuple(v)
+                msg += ' edge (%f,%f) in triangle %d.' %(tuple(u) + (i,))
+                msg += ' Inner product is %e.' %x                
+                assert x < epsilon, msg
+
+        self.lone_vertices = []
+        #Check that all vertices have been registered
+        for v_id, v in enumerate(self.vertexlist):
+
+            #msg = 'Vertex %s does not belong to an element.'
+            #assert v is not None, msg
+            if v is None:
+                #print msg%v_id
+                self.lone_vertices.append(v_id)
+
+        #Check integrity of neighbour structure
+        for i in range(N):
+#            print i
+            for v in self.triangles[i, :]:
+                #Check that all vertices have been registered
+                assert self.vertexlist[v] is not None
+
+                #Check that this triangle is listed with at least one vertex
+                assert (i, 0) in self.vertexlist[v] or\
+                       (i, 1) in self.vertexlist[v] or\
+                       (i, 2) in self.vertexlist[v]
+
+
+
+            #Check neighbour structure
+            for k, neighbour_id in enumerate(self.neighbours[i,:]):
+
+                #Assert that my neighbour's neighbour is me
+                #Boundaries need not fulfill this
+                if neighbour_id >= 0:
+                    edge = self.neighbour_edges[i, k]
+                    msg = 'Triangle %d has neighbour %d but it does not point back. \n' %(i,neighbour_id)
+                    msg += 'Only points to (%s)' %(self.neighbours[neighbour_id,:])
+                    assert self.neighbours[neighbour_id, edge] == i ,msg
+
+
+
+        #Check that all boundaries have
+        # unique, consecutive, negative indices
+
+        #L = len(self.boundary)
+        #for i in range(L):
+        #    id, edge = self.boundary_segments[i]
+        #    assert self.neighbours[id, edge] == -i-1
+
+
+        #NOTE: This assert doesn't hold true if there are internal boundaries
+        #FIXME: Look into this further.
+        #FIXME (Ole): In pyvolution mark 3 this is OK again
+        #NOTE: No longer works because neighbour structure is modified by
+        #      domain set_boundary.
+        #for id, edge in self.boundary:
+        #    assert self.neighbours[id,edge] < 0
+        #
+        #NOTE (Ole): I reckon this was resolved late 2004?
+        #
+        #See domain.set_boundary
+
+    def get_lone_vertices(self):
+        """Return a list of vertices that are not connected to any triangles.
+
+        Precondition
+        FIXME(DSG - DSG) Pull the code out of check integrity that builds this
+                         structure.
+        check_integrity has to have been called. 
+        """
+        return self.lone_vertices
+
+    def get_centroid_coordinates(self):
+        """Return all centroid coordinates.
+        Return all centroid coordinates for all triangles as an Nx2 array
+        (ordered as x0, y0 for each triangle)
+        """
+        return self.centroid_coordinates
+
+
+
+    def statistics(self):
+        """Output statistics about mesh
+        """
+
+        from Numeric import arange
+        from anuga.utilities.numerical_tools import histogram, create_bins
+
+        vertex_coordinates = self.vertex_coordinates # Relative coordinates
+        areas = self.areas
+        x = vertex_coordinates[:,0]
+        y = vertex_coordinates[:,1]
+
+
+        #Setup 10 bins for area histogram
+        bins = create_bins(areas, 10)
+        #m = max(areas)
+        #bins = arange(0., m, m/10)
+        hist = histogram(areas, bins)
+
+        str =  '------------------------------------------------\n'
+        str += 'Mesh statistics:\n'
+        str += '  Number of triangles = %d\n' %self.number_of_elements
+        str += '  Extent:\n'
+        str += '    x in [%f, %f]\n' %(min(x), max(x))
+        str += '    y in [%f, %f]\n' %(min(y), max(y))
+        str += '  Areas:\n'
+        str += '    A in [%f, %f]\n' %(min(areas), max(areas))
+        str += '    number of distinct areas: %d\n' %(len(areas))        
+        str += '    Histogram:\n'
+
+        hi = bins[0]
+        for i, count in enumerate(hist):
+            lo = hi
+            if i+1 < len(bins):
+                #Open upper interval                
+                hi = bins[i+1]
+                str += '      [%f, %f[: %d\n' %(lo, hi, count)                
+            else:
+                #Closed upper interval
+                hi = max(areas)
+                str += '      [%f, %f]: %d\n' %(lo, hi, count)
+
+        N = len(areas)
+        if N > 10:
+            str += '    Percentiles (10%):\n'
+            areas = areas.tolist()
+            areas.sort()
+
+            k = 0
+            lower = min(areas)
+            for i, a in enumerate(areas):        
+                if i % (N/10) == 0 and i != 0: #For every 10% of the sorted areas                
+                    str += '      %d triangles in [%f, %f]\n' %(i-k, lower, a)
+                    lower = a
+                    k = i
+                    
+            str += '      %d triangles in [%f, %f]\n'\
+                   %(N-k, lower, max(areas))                    
+                
+                      
+        str += 'Boundary:\n'
+        str += '  Number of boundary segments == %d\n' %(len(self.boundary))
+        str += '  Boundary tags == %s\n' %self.get_boundary_tags()  
+        str += '------------------------------------------------\n'
+        
+
+        return str
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/netherlands-chris.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/netherlands-chris.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/netherlands-chris.py	(revision 3560)
@@ -0,0 +1,273 @@
+"""Example of shallow water wave equation.
+
+This is called Netherlands because it shows a dam with a gap in it and
+stylised housed behind it and below the water surface.
+
+"""
+
+######################
+# Module imports 
+#
+from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+     Transmissive_boundary, Constant_height
+
+from mesh_factory import rectangular
+from Numeric import array
+    
+
+class Weir:
+    """Set a bathymetry for simple weir with a hole.
+    x,y are assumed to be in the unit square
+    """
+    
+    def __init__(self, stage):
+        self.inflow_stage = stage
+
+    def __call__(self, x, y):    
+        from Numeric import zeros, Float 
+    
+        N = len(x)
+        assert N == len(y)    
+
+        z = zeros(N, Float)
+        for i in range(N):
+            z[i] = -x[i]/20  #General slope
+
+            #Flattish bit to the left
+            if x[i] <= 0.3:
+                #z[i] = -x[i]/5
+                z[i] = -x[i]/20
+                
+            
+            #Weir
+            if x[i] > 0.3 and x[i] < 0.4:
+                z[i] = -x[i]/20+1.2
+
+            #Dip
+            #if x[i] > 0.6 and x[i] < 0.9:
+            #    z[i] = -x[i]/20-0.5  #-y[i]/5
+
+            #Hole in weir
+            #if x[i] > 0.3 and x[i] < 0.4 and y[i] > 0.2 and y[i] < 0.4:
+            if x[i] > 0.3 and x[i] < 0.4 and y[i] > 0.4 and y[i] < 0.6:
+                #z[i] = -x[i]/5
+                z[i] = -x[i]/20
+            
+            #Poles
+            #if x[i] > 0.65 and x[i] < 0.8 and y[i] > 0.55 and y[i] < 0.65 or\
+            #       x[i] > 0.75 and x[i] < 0.9 and y[i] > 0.35 and y[i] < 0.45:
+            #    z[i] = -x[i]/20+0.4
+
+            if (x[i] - 0.72)**2 + (y[i] - 0.6)**2 < 0.05**2:# or\
+                   #x[i] > 0.75 and x[i] < 0.9 and y[i] > 0.35 and y[i] < 0.45:
+                z[i] = -x[i]/20+0.4
+
+            #Wall
+            if x[i] > 0.995:
+                z[i] = -x[i]/20+0.3                
+
+        return z/2
+        
+    
+    
+######################
+# Domain
+#
+
+N = 250
+#N= 8
+N = 16
+#N = 4
+#N = 102
+N = 25
+N = 16
+N = 60
+N = 150 #size = 45000
+N = 130 #size = 33800
+#N = 60
+#N = 40
+N = 260
+#N = 150
+N = 264
+
+N = 600 #Size = 720000
+N = 20
+#N = 150
+N = 110
+N = 60
+
+N = 4
+#N = 140
+#N = 15
+
+print 'Creating domain'
+#Create basic mesh
+points, vertices, boundary = rectangular(N, N)
+
+#Create shallow water domain
+domain = Domain(points, vertices, boundary)
+    
+domain.check_integrity()
+domain.default_order = 2
+#domain.beta_h=0
+
+#Output params
+domain.smooth = True
+domain.reduction = min  #Looks a lot better on top of steep slopes
+
+print "Number of triangles = ", len(domain)
+
+
+if N > 40:
+    domain.visualise = False
+    domain.checkpoint = False
+    domain.store = True    #Store for visualisation purposes
+    domain.format = 'sww'   #Native netcdf visualisation format
+    import sys, os
+    #FIXME: This was os.path.splitext but caused weird filenames based on root
+    base = os.path.basename(sys.argv[0])
+    domain.filename, _ = os.path.splitext(base)
+else:
+    domain.visualise = False
+    domain.checkpoint = False
+    domain.store = False    
+
+    
+#Set bed-slope and friction
+inflow_stage = 0.08
+manning = 0.02
+Z = Weir(inflow_stage)
+
+print 'Field values'
+domain.set_quantity('elevation', Z)
+domain.set_quantity('friction', manning)
+
+
+######################
+# Boundary conditions
+#
+print 'Boundaries'
+Br = Reflective_boundary(domain)
+Bt = Transmissive_boundary(domain)
+
+#Constant inflow
+Bd = Dirichlet_boundary([2*inflow_stage, 0.0, 0.0])
+
+
+#Set boundary conditions
+domain.set_boundary({'left': Bd, 'right': Br, 'bottom': Br, 'top': Br})
+                  
+
+######################
+#Initial condition
+#
+print 'Initial condition'
+domain.set_quantity('stage', Constant_height(Z, 0.))
+
+#Evolve
+import time
+t0 = time.time()
+
+for t in domain.evolve(yieldstep = 0.5, finaltime = 1.0):
+    domain.write_time()
+
+
+
+    
+print 'That took %.2f seconds' %(time.time()-t0)
+print 'time', domain.write_time()
+
+print domain.coordinates
+print '*****'
+print domain.vertex_coordinates
+print '*****'
+print domain.quantities['xmomentum'].centroid_values
+print '*****'
+print domain.quantities['xmomentum'].edge_values
+print '*****'
+print domain.quantities['stage'].vertex_values
+print '*****'
+print domain.quantities['stage'].explicit_update
+
+from shallow_water import *
+
+def compute_fluxes_python(domain):
+    """Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities 
+    stage, xmomentum and ymomentum    
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes. 
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Ymom = domain.quantities['ymomentum']
+    Bed = domain.quantities['elevation']        
+
+    #Arrays
+    stage = Stage.edge_values
+    xmom =  Xmom.edge_values
+    ymom =  Ymom.edge_values
+    bed =   Bed.edge_values    
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    ymom_bdry =  Ymom.boundary_values
+    
+    flux = zeros((N,3), Float) #Work array for summing up fluxes
+
+    #Loop
+    timestep = float(sys.maxint)    
+    for k in range(N):
+
+        for i in range(3):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i], ymom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i] 
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr = [stage_bdry[m], xmom_bdry[m], ymom_bdry[m]]
+                zr = zl #Extend bed elevation to boundary
+            else:    
+                m = domain.neighbour_edges[k,i]
+                qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                zr = bed[n, m]                
+
+                
+            #Outward pointing normal vector   
+            normal = domain.normals[k, 2*i:2*i+2]
+
+            #Flux computation using provided function
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+        
+            flux[k,:] = edgeflux
+
+    return flux
+    
+flux = compute_fluxes_python(domain)
+print 'flux'
+print flux
+
+   
+# THis was pulled out of 
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/netherlands.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/netherlands.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/netherlands.py	(revision 3560)
@@ -0,0 +1,194 @@
+"""Example of shallow water wave equation.
+
+This is called Netherlands because it shows a dam with a gap in it and
+stylised housed behind it and below the water surface.
+
+"""
+
+######################
+# Module imports
+#
+#import rpdb
+#rpdb.set_active()
+
+from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+     Transmissive_boundary, Constant_height, Constant_stage
+
+from mesh_factory import rectangular_cross
+from Numeric import array
+from vtk_realtime_visualiser import Visualiser
+
+class Weir:
+    """Set a bathymetry for simple weir with a hole.
+    x,y are assumed to be in the unit square
+    """
+
+    def __init__(self, stage):
+        self.inflow_stage = stage
+
+    def __call__(self, x, y):
+        from Numeric import zeros, Float
+
+        N = len(x)
+        assert N == len(y)
+
+        z = zeros(N, Float)
+        for i in range(N):
+            z[i] = -x[i]/20  #General slope
+
+            #Flattish bit to the left
+            if x[i] <= 0.3:
+                #z[i] = -x[i]/5
+                z[i] = -x[i]/20
+
+
+            #Weir
+            if x[i] > 0.3 and x[i] < 0.4:
+                z[i] = -x[i]/20+1.2
+
+            #Dip
+            #if x[i] > 0.6 and x[i] < 0.9:
+            #    z[i] = -x[i]/20-0.5  #-y[i]/5
+
+            #Hole in weir
+            #if x[i] > 0.3 and x[i] < 0.4 and y[i] > 0.2 and y[i] < 0.4:
+            if x[i] > 0.3 and x[i] < 0.4 and y[i] > 0.4 and y[i] < 0.6:
+                #z[i] = -x[i]/5
+                z[i] = -x[i]/20
+
+            #Poles
+            #if x[i] > 0.65 and x[i] < 0.8 and y[i] > 0.55 and y[i] < 0.65 or\
+            #       x[i] > 0.75 and x[i] < 0.9 and y[i] > 0.35 and y[i] < 0.45:
+            #    z[i] = -x[i]/20+0.4
+
+            if (x[i] - 0.72)**2 + (y[i] - 0.6)**2 < 0.05**2:# or\
+                   #x[i] > 0.75 and x[i] < 0.9 and y[i] > 0.35 and y[i] < 0.45:
+                z[i] = -x[i]/20+0.4
+
+
+            #Wall
+            if x[i] > 0.995:
+                z[i] = -x[i]/20+0.3
+
+        return z/2
+
+
+
+######################
+# Domain
+#
+
+
+N = 150 #size = 45000
+N = 130 #size = 33800
+N = 600 #Size = 720000
+N = 50
+
+
+#N = 15
+
+print 'Creating domain'
+#Create basic mesh
+points, elements, boundary = rectangular_cross(N, N)
+
+#Create shallow water domain
+domain = Domain(points, elements, boundary, use_inscribed_circle=True)
+
+domain.check_integrity()
+domain.default_order = 2
+#domain.beta_h=0
+
+#Output params
+domain.smooth = False
+domain.reduction = min  #Looks a lot better on top of steep slopes
+
+print "Number of triangles = ", len(domain)
+print "Extent = ", domain.get_extent()
+
+#Set bed-slope and friction
+inflow_stage = 0.5
+manning = 0.03
+Z = Weir(inflow_stage)
+
+if N > 150:
+    domain.visualise = False
+    domain.checkpoint = False
+    domain.store = True    #Store for visualisation purposes
+    domain.format = 'sww'   #Native netcdf visualisation format
+    import sys, os
+    #FIXME: This was os.path.splitext but caused weird filenames based on root
+    base = os.path.basename(sys.argv[0])
+    domain.filename, _ = os.path.splitext(base)
+else:
+    #domain.initialise_visualiser(rect=[0.0,0.0,1.0,1.0])
+    #domain.initialise_visualiser()
+    #domain.visualiser.coloring['stage'] = False
+    domain.visualise_timer = True
+    domain.checkpoint = False
+    domain.store = False
+    vis = Visualiser(domain,title="netherlands")
+    vis.setup['elevation'] = True
+    vis.updating['stage'] = True
+    vis.qcolor['stage'] = (0.0,0.0,0.8)
+    vis.coloring['stage']= True
+
+
+
+print 'Field values'
+domain.set_quantity('elevation', Z)
+domain.set_quantity('friction', manning)
+
+
+######################
+# Boundary conditions
+#
+print 'Boundaries'
+Br = Reflective_boundary(domain)
+Bt = Transmissive_boundary(domain)
+
+#Constant inflow
+Bd = Dirichlet_boundary([inflow_stage, 0.0, 0.0])
+
+
+#Set boundary conditions
+domain.set_boundary({'left': Bd, 'right': Br, 'bottom': Br, 'top': Br})
+
+
+######################
+#Initial condition
+#
+print 'Initial condition'
+domain.set_quantity('stage', Constant_height(Z, 0.0))
+#domain.set_quantity('stage', Constant_stage(inflow_stage/2.0))
+
+#Evolve
+import time
+t0 = time.time()
+
+
+#from realtime_visualisation_new import Visualiser
+#V = Visualiser(domain,title='netherlands')
+#V.update_quantity('stage')
+#V.update_quantity('elevation')
+
+
+
+
+for t in domain.evolve(yieldstep = 0.005, finaltime = None):
+    domain.write_time()
+    #domain.write_boundary()
+    vis.update()
+    print domain.quantities['stage'].get_values(location='centroids',
+                                                indices=[0])
+    #domain.visualiser.update_quantity('elevation')
+    #time.sleep(0.1)
+    #raw_input('pause>')
+    #V.update_quantity('stage')
+    #rpdb.set_active()
+    #domain.visualiser.scale_z = 1.0
+    #domain.visualiser.update_quantity_color('xmomentum',scale_z = 4.0)
+    #integral_label.text='Integral=%10.5e'%domain.quantities['stage'].get_integral()
+
+
+print 'That took %.2f seconds' %(time.time()-t0)
+vis.shutdown()
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/normalDate.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/normalDate.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/normalDate.py	(revision 3560)
@@ -0,0 +1,486 @@
+#!/usr/bin/env python
+# normalDate.py - version 1.3 - 2002/05/24
+# Author: Jeff Bauer, Rubicon Research - jbauer@rubic.com
+# License: Same as Python 2.1 or later
+
+import time
+from types import IntType, ListType, StringType, TupleType
+
+_bigBangScalar = -4345732  # based on (-9999, 1, 1) BC/BCE minimum
+_bigCrunchScalar = 2958463  # based on (9999,12,31) AD/CE maximum
+_daysInMonthNormal = [31,28,31,30,31,30,31,31,30,31,30,31]
+_daysInMonthLeapYear = [31,29,31,30,31,30,31,31,30,31,30,31]
+_dayOfWeekName = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
+                  'Friday', 'Saturday', 'Sunday']
+_monthName = ['January', 'February', 'March', 'April', 'May', 'June',
+              'July','August','September','October','November','December']
+
+class NormalDateException(Exception):
+    """Exception class for NormalDate"""
+    pass
+
+class NormalDate:
+    """
+    NormalDate is a specialized class to handle dates without
+    all the excess baggage (time zones, daylight savings, leap
+    seconds, etc.) of other date structures.  The minimalist
+    strategy greatly simplifies its implementation and use.
+
+    Internally, NormalDate is stored as an integer with values
+    in a discontinuous range of -99990101 to 99991231.  The
+    integer value is used principally for storage and to simplify
+    the user interface.  Internal calculations are performed by
+    a scalar based on Jan 1, 1900.
+
+    Valid NormalDate ranges include (-9999,1,1) B.C.E. through
+    (9999,12,31) C.E./A.D.
+
+    1.3 - Added weekOfYear() method submitted by Harri Pasanen.
+    1.2 - Bugfix for Python2.2, which changed localtime's type
+          to time.struct_time rather than a tuple.  Thanks to
+          Paul Weimer for reporting this problem.  Added some,
+          but not all, of Robin Becker's ideas he incorporated
+          into ReportLab's version of normalDate.
+    1.1 - Added exception in setNormalDate for bad integer;
+          range() returns a list of normalDates rather than
+          a list of integers.
+    1.0 - No changes, except the version number.  After 3 years of use
+            by various parties I think we can consider it stable.
+    0.8 - added Prof. Stephen Walton's suggestion for a range method 
+            - module author resisted the temptation to use lambda <0.5 wink>
+    0.7 - added Dan Winkler's suggestions for __add__, __sub__ methods
+    0.6 - modifications suggested by Kevin Digweed to fix:
+            - dayOfWeek, dayOfWeekAbbrev, clone methods
+            - permit NormalDate to be a better behaved superclass
+    0.5 - minor tweaking
+    0.4 - added methods __cmp__, __hash__
+        - added Epoch variable, scoped to the module
+        - added setDay, setMonth, setYear methods
+    0.3 - minor touch-ups
+    0.2 - fixed bug for certain B.C.E leap years
+        - added Jim Fulton's suggestions for short alias class name =ND
+          and __getstate__, __setstate__ methods
+
+    Special thanks for ideas and suggestions:  
+        Jim Fulton
+        Kevin Digweed
+        Paul Weimer
+        Robin Becker
+        Roedy Green
+        Stephen Walton
+    """
+    def __init__(self, normalDate=None):
+        """
+        Accept 1 of 4 values to initialize a NormalDate:
+            1. None - creates a NormalDate for the current day
+            2. integer in yyyymmdd format
+            3. string in yyyymmdd format
+            4. tuple in (yyyy, mm, dd) - localtime/gmtime can also be used
+        """
+        if normalDate is None:
+            self.setNormalDate(time.localtime(time.time()))
+        else:
+            self.setNormalDate(normalDate)
+
+    def add(self, days):
+        """add days to date; use negative integers to subtract"""
+        if not type(days) is IntType:
+            raise NormalDateException( \
+                'add method parameter must be integer type')
+        self.normalize(self.scalar() + days)
+
+    def __add__(self, days):
+        """add integer to normalDate and return a new, calculated value"""
+        if not type(days) is IntType:
+            raise NormalDateException( \
+                '__add__ parameter must be integer type')
+        cloned = self.clone()
+        cloned.add(days)
+        return cloned
+
+    def clone(self):
+        """return a cloned instance of this normalDate"""
+        return self.__class__(self.normalDate)
+
+    def __cmp__(self, target):
+        if target is None: 
+            return 1
+        elif not hasattr(target, 'normalDate'):
+            return 1
+        else:
+            return cmp(self.normalDate, target.normalDate)
+
+    def day(self):
+        """return the day as integer 1-31"""
+        return int(repr(self.normalDate)[-2:])
+
+    def dayOfWeek(self):
+        """return integer representing day of week, Mon=0, Tue=1, etc."""
+        return apply(dayOfWeek, self.toTuple())
+
+    def dayOfWeekAbbrev(self):
+        """return day of week abbreviation for current date: Mon, Tue, etc."""
+        return _dayOfWeekName[self.dayOfWeek()][:3]
+
+    def dayOfWeekName(self):
+        """return day of week name for current date: Monday, Tuesday, etc."""
+        return _dayOfWeekName[self.dayOfWeek()]
+
+    def dayOfYear(self):
+        """day of year"""
+        if self.isLeapYear():
+            daysByMonth = _daysInMonthLeapYear
+        else:
+            daysByMonth = _daysInMonthNormal
+        priorMonthDays = 0
+        for m in xrange(self.month() - 1):
+            priorMonthDays = priorMonthDays + daysByMonth[m]
+        return self.day() + priorMonthDays
+
+    def daysBetweenDates(self, normalDate):
+        """
+        return value may be negative, since calculation is 
+        self.scalar() - arg
+        """
+        if type(normalDate) is _NormalDateType:
+            return self.scalar() - normalDate.scalar()
+        else:
+            return self.scalar() - NormalDate(normalDate).scalar()
+
+    def daysInMonth(self, month):
+        """returns last day of the month as integer 28-31"""
+        if self.isLeapYear():
+            return _daysInMonthLeapYear[month - 1]
+        else:
+            return _daysInMonthNormal[month - 1]
+
+    def equals(self, target):
+        if type(target) is _NormalDateType:
+            if target is None:
+                return self.normalDate is None
+            else:
+                return self.normalDate == target.normalDate
+        else:
+            return 0
+
+    def endOfMonth(self):
+        """returns (cloned) last day of month"""
+        return self.__class__(self.__repr__()[-8:-2] + \
+                              str(self.lastDayOfMonth()))
+
+    def firstDayOfMonth(self):
+        """returns (cloned) first day of month"""
+        return self.__class__(self.__repr__()[-8:-2] + "01")
+
+    def formatUS(self):
+        """return date as string in common US format: MM/DD/YY"""
+        d = self.__repr__()
+        return "%s/%s/%s" % (d[-4:-2], d[-2:], d[-6:-4])
+
+    def formatUSCentury(self):
+        """return date as string in 4-digit year US format: MM/DD/YYYY"""
+        d = self.__repr__()
+        return "%s/%s/%s" % (d[-4:-2], d[-2:], d[-8:-4])
+
+    def __getstate__(self):
+        """minimize persistent storage requirements"""
+        return self.normalDate
+
+    def __hash__(self):
+        return hash(self.normalDate)
+
+    def __int__(self):
+        return self.normalDate
+
+    def isLeapYear(self):
+        """
+        determine if specified year is leap year, returning true (1) or 
+        false (0)
+        """
+        return isLeapYear(self.year())
+
+    def _isValidNormalDate(self, normalDate):
+        """checks for date validity in [-]yyyymmdd format"""
+        if type(normalDate) is not IntType:
+            return 0
+        if len(repr(normalDate)) > 9:
+            return 0
+        if normalDate < 0:
+            dateStr = "%09d" % normalDate
+        else:
+            dateStr = "%08d" % normalDate
+        if len(dateStr) < 8:
+            return 0
+        elif len(dateStr) == 9:
+            if (dateStr[0] != '-' and dateStr[0] != '+'):
+                return 0
+        year = int(dateStr[:-4])
+        if year < -9999 or year > 9999 or year == 0:
+            return 0    # note: zero (0) is not a valid year
+        month = int(dateStr[-4:-2])
+        if month < 1 or month > 12:
+            return 0
+        if isLeapYear(year):
+            maxDay = _daysInMonthLeapYear[month - 1]
+        else:
+            maxDay = _daysInMonthNormal[month - 1]
+        day = int(dateStr[-2:])
+        if day < 1 or day > maxDay:
+            return 0
+        if year == 1582 and month == 10 and day > 4 and day < 15:
+            return 0  # special case of 10 days dropped: Oct 5-14, 1582
+        return 1
+
+    def lastDayOfMonth(self):
+        """returns last day of the month as integer 28-31"""
+        if self.isLeapYear():
+            return _daysInMonthLeapYear[self.month() - 1]
+        else:
+            return _daysInMonthNormal[self.month() - 1]
+
+    def localeFormat(self):
+        """override this method to use your preferred locale format"""
+        return self.formatUS()
+
+    def month(self):
+        """returns month as integer 1-12"""
+        return int(repr(self.normalDate)[-4:-2])
+
+    def monthAbbrev(self):
+        """returns month as a 3-character abbreviation, i.e. Jan, Feb, etc."""
+        return _monthName[self.month() - 1][:3]
+
+    def monthName(self):
+        """returns month name, i.e. January, February, etc."""
+        return _monthName[self.month() - 1]
+
+    def normalize(self, scalar):
+        """convert scalar to normalDate"""
+        if scalar < _bigBangScalar:
+            msg = "normalize(%d): scalar below minimum" % \
+                  _bigBangScalar
+            raise NormalDateException(msg)
+        if scalar > _bigCrunchScalar:
+            msg = "normalize(%d): scalar exceeds maximum" % \
+                  _bigCrunchScalar
+            raise NormalDateException(msg)
+        from math import floor
+        if scalar >= -115860:
+            year = 1600 + int(floor((scalar + 109573) / 365.2425))
+        elif scalar >= -693597:
+            year = 4 + int(floor((scalar + 692502) / 365.2425))
+        else:
+            year = -4 + int(floor((scalar + 695058) / 365.2425))
+        days = scalar - firstDayOfYear(year) + 1
+        if days <= 0:
+            year = year - 1
+            days = scalar - firstDayOfYear(year) + 1
+        daysInYear = 365
+        if isLeapYear(year):
+            daysInYear = daysInYear + 1
+        if days > daysInYear:
+            year = year + 1
+            days = scalar - firstDayOfYear(year) + 1
+        # add 10 days if between Oct 15, 1582 and Dec 31, 1582
+        if (scalar >= -115860 and scalar <= -115783):
+            days = days + 10
+        if isLeapYear(year):
+            daysByMonth = _daysInMonthLeapYear
+        else:
+            daysByMonth = _daysInMonthNormal
+        dc = 0; month = 12
+        for m in xrange(len(daysByMonth)):
+            dc = dc + daysByMonth[m]
+            if dc >= days:
+                month = m + 1
+                break
+        # add up the days in prior months
+        priorMonthDays = 0
+        for m in xrange(month - 1):
+            priorMonthDays = priorMonthDays + daysByMonth[m]
+        day = days - priorMonthDays
+        self.setNormalDate((year, month, day))
+
+	def __radd__(self,days):
+		"""for completeness"""
+		return self.__add__(days)
+
+    def range(self, days):
+        """Return a range of normalDates as a list.  Parameter
+        may be an int or normalDate."""
+        if type(days) is not IntType:
+            days = days - self  # if not int, assume arg is normalDate type
+        r = []
+        for i in range(days):
+            r.append(self + i)
+        return r
+
+    def __repr__(self):
+        """print format: [-]yyyymmdd"""
+        # Note: When disassembling a NormalDate string, be sure to
+        # count from the right, i.e. epochMonth = int(`Epoch`[-4:-2]),
+        # or the slice won't work for dates B.C.
+        if self.normalDate < 0:
+            return "%09d" % self.normalDate
+        else:
+            return "%08d" % self.normalDate
+
+	def __rsub__(self, v):
+		if type(v) is IntType:
+			return NormalDate(v) - self
+		else:
+			return v.scalar() - self.scalar()
+
+    def scalar(self):
+        """days since baseline date: Jan 1, 1900"""
+        (year, month, day) = self.toTuple()
+        days = firstDayOfYear(year) + day - 1
+        if self.isLeapYear():
+            for m in xrange(month - 1):
+                days = days + _daysInMonthLeapYear[m]
+        else:
+            for m in xrange(month - 1):
+                days = days + _daysInMonthNormal[m]
+        if year == 1582:
+            if month > 10 or (month == 10 and day > 4):
+                days = days - 10
+        return days
+
+    def setDay(self, day):
+        """set the day of the month"""
+        maxDay = self.lastDayOfMonth()
+        if day < 1 or day > maxDay:
+            msg = "day is outside of range 1 to %d" % maxDay
+            raise NormalDateException(msg)
+        (y, m, d) = self.toTuple()
+        self.setNormalDate((y, m, day))
+
+    def setMonth(self, month):
+        """set the month [1-12]"""
+        if month < 1 or month > 12:
+            raise NormalDateException('month is outside range 1 to 12')
+        (y, m, d) = self.toTuple()
+        self.setNormalDate((y, month, d))
+
+    def setNormalDate(self, normalDate):
+        """
+        accepts date as scalar string/integer (yyyymmdd) or tuple 
+        (year, month, day, ...)"""
+        _type = type(normalDate)
+        if _type is IntType:
+            self.normalDate = normalDate
+        elif _type is StringType:
+            try:
+                self.normalDate = int(normalDate)
+            except ValueError:
+                raise NormalDateException("Bad integer: '%s'" % normalDate)
+        elif _type in (TupleType, ListType) or _type is _TimeType:
+            self.normalDate = int("%04d%02d%02d" % normalDate[:3])
+        elif _type is _NormalDateType:
+            self.normalDate = normalDate.normalDate
+        if not self._isValidNormalDate(self.normalDate):
+            msg = "unable to setNormalDate(%s)" % `normalDate`
+            raise NormalDateException(msg)
+
+    def setYear(self, year):
+        if year == 0:
+            raise NormalDateException('cannot set year to zero')
+        elif year < -9999:
+            raise NormalDateException('year cannot be less than -9999')
+        elif year > 9999:
+            raise NormalDateException('year cannot be greater than 9999')
+        (y, m, d) = self.toTuple()
+        self.setNormalDate((year, m, d))
+
+    __setstate__ = setNormalDate
+
+    def __sub__(self, v):
+        if type(v) is IntType:
+            return self.__add__(-v)
+        return self.scalar() - v.scalar()
+
+    def toTuple(self):
+        """return date as (year, month, day) tuple"""
+        return (self.year(), self.month(), self.day())
+
+    def weekOfYear(self):
+        """returns the week of the year: 1-52"""
+        week = self.dayOfYear() / 7 + 1
+        if week == 53:
+            week = 1
+        return week
+
+    def year(self):
+        """return year in yyyy format, negative values indicate B.C."""
+        return int(repr(self.normalDate)[:-4])
+
+#################  Utility functions  #################
+
+def bigBang():
+    """return lower boundary as a NormalDate"""
+    return NormalDate((-9999, 1, 1))
+
+def bigCrunch():
+    """return upper boundary as a NormalDate"""
+    return NormalDate((9999, 12, 31))
+
+def dayOfWeek(y, m, d):
+    """return integer representing day of week, Mon=0, Tue=1, etc."""
+    if m == 1 or m == 2:
+        m = m + 12
+        y = y - 1
+    return (d + 2*m + 3*(m+1)/5 + y + y/4 - y/100 + y/400) % 7
+
+def firstDayOfYear(year):
+    """number of days to the first of the year, relative to Jan 1, 1900"""
+    if type(year) is not IntType:
+        msg = "firstDayOfYear() expected integer, got %s" % type(year)
+        raise NormalDateException(msg)
+    if year == 0:
+        raise NormalDateException('first day of year cannot be zero (0)')
+    elif year < 0:  # BCE calculation
+        firstDay = (year * 365) + int((year - 1) / 4) - 693596
+    else:           # CE calculation
+        leapAdjust = int((year + 3) / 4)
+        if year > 1600:
+            leapAdjust = leapAdjust - int((year + 99 - 1600) / 100) + \
+                         int((year + 399 - 1600) / 400)
+        firstDay = year * 365 + leapAdjust - 693963
+        if year > 1582:
+            firstDay = firstDay - 10
+    return firstDay
+
+def isLeapYear(year):
+    """determine if specified year is leap year, returns Python boolean"""
+    if year < 1600:
+        if year % 4:
+            return 0
+        else:
+            return 1
+    elif year % 4 != 0:
+        return 0
+    elif year % 100 != 0:
+        return 1
+    elif year % 400 != 0:
+        return 0
+    else:
+        return 1
+
+ND=NormalDate
+Epoch=bigBang()
+_NormalDateType = type(Epoch)
+_TimeType = type(time.localtime(time.time()))
+
+if __name__ == '__main__':
+    today = ND()
+    print "NormalDate test:"
+    print "  Today (%s) is: %s %s" % \
+          (today, today.dayOfWeekAbbrev(), today.localeFormat())
+    yesterday = today - 1
+    print "  Yesterday was: %s %s" % \
+          (yesterday.dayOfWeekAbbrev(), yesterday.localeFormat())
+    tomorrow = today + 1
+    print "  Tomorrow will be: %s %s" % \
+          (tomorrow.dayOfWeekAbbrev(), tomorrow.localeFormat())
+    print "  Days between tomorrow and yesterday: %d" % \
+          (tomorrow - yesterday)
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/pmesh2domain.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/pmesh2domain.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/pmesh2domain.py	(revision 3560)
@@ -0,0 +1,216 @@
+"""Class pmesh2domain - Converting .tsh files to doamains
+
+
+   Copyright 2004
+   Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+   Geoscience Australia
+"""
+
+def pmesh_instance_to_domain_instance(mesh,
+                                      DomainClass):
+    """
+    Convert a pmesh instance/object into a domain instance.
+
+    Use pmesh_to_domain_instance to convert a mesh file to a domain instance.
+    """
+    import sys
+    from domain import Domain
+
+    vertex_coordinates, vertices, tag_dict, vertex_quantity_dict \
+                        ,tagged_elements_dict, geo_reference = \
+                        pmesh_to_domain(mesh_instance=mesh)
+
+
+    assert issubclass(DomainClass, Domain),"DomainClass is not a subclass of Domain."
+
+
+    domain = DomainClass(coordinates = vertex_coordinates,
+                         vertices = vertices,
+                         boundary = tag_dict,
+                         tagged_elements = tagged_elements_dict,
+                         geo_reference = geo_reference )
+
+    # set the water stage to be the elevation
+    if vertex_quantity_dict.has_key('elevation') and not vertex_quantity_dict.has_key('stage'):
+        vertex_quantity_dict['stage'] = vertex_quantity_dict['elevation']
+
+    domain.set_quantity_vertices_dict(vertex_quantity_dict)
+    #print "vertex_quantity_dict",vertex_quantity_dict
+    return domain
+
+
+
+def pmesh_to_domain_instance(file_name, DomainClass, use_cache = False, verbose = False):
+    """
+    Converts a mesh file(.tsh or .msh), to a Domain instance.
+
+    file_name is the name of the mesh file to convert, including the extension
+
+    DomainClass is the Class that will be returned.
+    It must be a subclass of Domain, with the same interface as domain.
+
+    use_cache: True means that caching is attempted for the computed domain.    
+    """
+
+    if use_cache is True:
+        from caching import cache
+        result = cache(_pmesh_to_domain_instance, (file_name, DomainClass),
+                       dependencies = [file_name],                     
+                       verbose = verbose)
+
+    else:
+        result = apply(_pmesh_to_domain_instance, (file_name, DomainClass))        
+        
+    return result
+
+
+
+
+def _pmesh_to_domain_instance(file_name, DomainClass):
+    """
+    Converts a mesh file(.tsh or .msh), to a Domain instance.
+
+    Internal function. See public interface pmesh_to_domain_instance for details
+    """
+    
+    import sys
+    from domain import Domain
+
+    vertex_coordinates, vertices, tag_dict, vertex_quantity_dict \
+                        ,tagged_elements_dict, geo_reference = \
+                        pmesh_to_domain(file_name=file_name)
+
+
+    assert issubclass(DomainClass, Domain),"DomainClass is not a subclass of Domain."
+
+
+    domain = DomainClass(coordinates = vertex_coordinates,
+                         vertices = vertices,
+                         boundary = tag_dict,
+                         tagged_elements = tagged_elements_dict,
+                         geo_reference = geo_reference )
+
+
+
+    #FIXME (Ole): Is this really the right place to apply the a default
+    #value specific to the shallow water wave equation?
+    #The 'assert' above indicates that any subclass of Domain is acceptable.
+    #Suggestion - module shallow_water.py will eventually take care of this
+    #(when I get around to it) so it should be removed from here.
+
+    # This doesn't work on the domain instance.
+    # This is still needed so -ve elevations don't cuase 'lakes'
+    # The fixme we discussed was to only create a quantity when its values
+    #are set.
+    # I think that's the way to go still
+
+    # set the water stage to be the elevation
+    if vertex_quantity_dict.has_key('elevation') and not vertex_quantity_dict.has_key('stage'):
+        vertex_quantity_dict['stage'] = vertex_quantity_dict['elevation']
+
+    domain.set_quantity_vertices_dict(vertex_quantity_dict)
+    #print "vertex_quantity_dict",vertex_quantity_dict
+    return domain
+
+
+def pmesh_to_domain(file_name=None,
+                    mesh_instance=None,
+                    use_cache=False,
+                    verbose=False):
+    """
+    Convert a pmesh file or a pmesh mesh instance to a bunch of lists
+    that can be used to instanciate a domain object.
+
+    use_cache: True means that caching is attempted for the computed domain.    
+    """
+ 
+    if use_cache is True:
+        from caching import cache
+        result = cache(_pmesh_to_domain, (file_name, mesh_instance),
+                       dependencies = [file_name],                     
+                       verbose = verbose)
+
+    else:
+        result = apply(_pmesh_to_domain, (file_name, mesh_instance))        
+        
+    return result
+
+
+def _pmesh_to_domain(file_name=None,
+                     mesh_instance=None,
+                     use_cache=False,
+                     verbose=False):
+    """
+    Convert a pmesh file or a pmesh mesh instance to a bunch of lists
+    that can be used to instanciate a domain object.
+    """
+
+    from Numeric import transpose
+    from load_mesh.loadASCII import import_mesh_file
+
+    if file_name is None:
+        mesh_dict = mesh_instance.Mesh2IODict()
+    else:
+        mesh_dict = import_mesh_file(file_name)
+    #print "mesh_dict",mesh_dict
+    vertex_coordinates = mesh_dict['vertices']
+    volumes = mesh_dict['triangles']
+    vertex_quantity_dict = {}
+    point_atts = transpose(mesh_dict['vertex_attributes'])
+    point_titles  = mesh_dict['vertex_attribute_titles']
+    geo_reference  = mesh_dict['geo_reference']
+    for quantity, value_vector in map (None, point_titles, point_atts):
+        vertex_quantity_dict[quantity] = value_vector
+    tag_dict = pmesh_dict_to_tag_dict(mesh_dict)
+    tagged_elements_dict = build_tagged_elements_dictionary(mesh_dict)
+    return vertex_coordinates, volumes, tag_dict, vertex_quantity_dict, tagged_elements_dict, geo_reference
+
+
+
+def build_tagged_elements_dictionary(mesh_dict):
+    """Build the dictionary of element tags.
+    tagged_elements is a dictionary of element arrays,
+    keyed by tag:
+    { (tag): [e1, e2, e3..] }
+    """
+    tri_atts = mesh_dict['triangle_tags']
+    #print "tri_atts", tri_atts
+    tagged_elements = {}
+    for tri_att_index in range(len(tri_atts)):
+        tagged_elements.setdefault(tri_atts[tri_att_index],[]).append(tri_att_index)
+    #print "DSG pm2do tagged_elements", tagged_elements
+    return tagged_elements
+
+def pmesh_dict_to_tag_dict(mesh_dict):
+    """ Convert the pmesh dictionary (mesh_dict) description of boundary tags
+    to a dictionary of tags, indexed with volume id and face number.
+    """
+    triangles = mesh_dict['triangles']
+    sides = calc_sides(triangles)
+    tag_dict = {}
+    for seg, tag in map(None, mesh_dict['segments'],
+                        mesh_dict['segment_tags']):
+        v1 = seg[0]
+        v2 = seg[1]
+        for key in [(v1,v2),(v2,v1)]:
+            if sides.has_key(key) and tag <> "":
+                #"" represents null.  Don't put these into the dictionary
+                #this creates a dict of lists of faces, indexed by tag
+                #tagged_edges.setdefault(tag,[]).append(sides[key])
+                tag_dict[sides[key]] = tag
+
+    return tag_dict
+
+
+def calc_sides(triangles):
+    #Build dictionary mapping from sides (2-tuple of points)
+    #to left hand side neighbouring triangle
+    sides = {}
+    for id, triangle in enumerate(triangles):
+        a = triangle[0]
+        b = triangle[1]
+        c = triangle[2]
+        sides[a,b] = (id, 2) #(id, face)
+        sides[b,c] = (id, 0) #(id, face)
+        sides[c,a] = (id, 1) #(id, face)
+    return sides
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/pressure_force.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/pressure_force.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/pressure_force.py	(revision 3560)
@@ -0,0 +1,99 @@
+"""Example of shallow water wave equation.
+
+This example applies a dummy forcing function mimicking a
+static cyclone
+"""
+
+######################
+# Module imports 
+#
+from shallow_water import Transmissive_boundary, Reflective_boundary,\
+     Dirichlet_boundary, Time_boundary
+from shallow_water import Domain, Constant_height
+from mesh_factory import rectangular
+
+from math import sin, pi
+
+
+#######################
+# Domain
+#
+N = 50
+elements, triangles, boundary = rectangular(N, N)
+domain = Domain(elements, triangles, boundary)
+
+domain.store = True
+domain.filename = 'pressure'
+
+#######################
+#Bed-slope and friction
+def x_slope(x, y):
+    #return -x/3
+    return 0.0*x
+
+domain.set_quantity('elevation', x_slope)
+domain.set_quantity('friction', 0.1)
+
+
+#######################
+#Forcing terms
+def pressure(x,y,t):
+    r=0.1
+    x0 = (1+sin(t*pi/5))/2
+    y0 = (1+sin(t*pi/5))/2
+    if x >= x0-r and x <= x0+r and y >= y0-r and y <= y0+r:
+        return 1000*(1+sin(t*pi))
+    else:
+        return 800
+
+def cyclone(domain):
+    from anuga.config import rho_w 
+    from anuga.pyvolution.util import gradient
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']    
+    h = Stage.vertex_values - Elevation.vertex_values
+    x = domain.get_vertex_coordinates()
+
+    for k in range(len(domain)):
+        avg_h = sum( h[k,:] )/3
+        
+        #Compute bed slope
+        x0, y0, x1, y1, x2, y2 = x[k,:]    
+
+        p0 = pressure(x0,y0,t)
+        p1 = pressure(x1,y1,t)
+        p2 = pressure(x2,y2,t)        
+        
+        px, py = gradient(x0, y0, x1, y1, x2, y2, p0, p1, p2)
+
+        #Update momentum
+        xmom[k] += -px*avg_h/rho_w
+        ymom[k] += -py*avg_h/rho_w        
+
+
+domain.forcing_terms.append(cyclone)
+
+######################
+# Boundary conditions
+Br = Reflective_boundary(domain)
+
+domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+
+######################
+#Initial condition
+h = 0.05
+domain.set_quantity('stage', Constant_height(x_slope, h))
+
+
+######################
+#Evolution
+for t in domain.evolve(yieldstep = 0.05, finaltime = 7):
+    domain.write_time()
+
+
+    
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/quad.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/quad.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/quad.py	(revision 3560)
@@ -0,0 +1,432 @@
+"""quad.py - quad tree data structure for fast indexing of points in the plane
+
+
+"""
+
+from treenode import TreeNode
+import string, types, sys
+
+#FIXME verts are added one at a time. 
+#FIXME add max min x y in general_mesh
+
+class Cell(TreeNode):
+    """class Cell
+
+    One cell in the plane delimited by southern, northern,
+    western, eastern boundaries.
+
+    Public Methods:
+        prune()
+        insert(point)
+        search(x, y)
+        collapse()
+        split()
+        store()
+        retrieve()
+        count()
+    """
+  
+    def __init__(self, southern, northern, western, eastern, 
+		 name = 'cell',
+    	         max_points_per_cell = 4):
+  
+        # Initialise base classes
+        TreeNode.__init__(self, string.lower(name))
+	
+        # Initialise cell
+        self.southern = round(southern,5)    
+        self.northern = round(northern,5)
+        self.western = round(western,5)    
+        self.eastern = round(eastern,5)
+
+        # The points in this cell     
+        self.points = []
+	
+	self.max_points_per_cell = max_points_per_cell
+        
+	
+    def __repr__(self):
+        return self.name  
+
+
+    def spawn(self):
+        """Create four child cells unless they already exist
+        """
+
+        if self.children:
+            return
+        else:
+            self.children = []
+
+        # convenience variables
+        cs = self.southern    
+        cn = self.northern
+        cw = self.western    
+        ce = self.eastern
+
+        # create 4 child cells
+        self.AddChild(Cell((cn+cs)/2,cn,cw,(cw+ce)/2,self.name+'_nw'))
+        self.AddChild(Cell((cn+cs)/2,cn,(cw+ce)/2,ce,self.name+'_ne'))
+        self.AddChild(Cell(cs,(cn+cs)/2,(cw+ce)/2,ce,self.name+'_se'))
+        self.AddChild(Cell(cs,(cn+cs)/2,cw,(cw+ce)/2,self.name+'_sw'))
+        
+ 
+    def search(self, x, y):
+    #def search_new(self, x, y):
+        """Find all point indices sharing the same cell as point (x, y)
+        """
+        branch = []
+        points = []
+        if self.children:
+            for child in self:
+                if child.contains(x,y):
+                    brothers = list(self.children)
+                    brothers.remove(child)
+                    branch.append(brothers)
+                    points, branch = child.search_branch(x,y, branch)
+        else:
+            # Leaf node: Get actual waypoints
+            points = self.retrieve()
+
+        self.branch = branch   
+        return points
+
+
+    def search_branch(self, x, y, branch):
+        """Find all point indices sharing the same cell as point (x, y)
+        """
+        points = []
+        if self.children:
+            for child in self:
+                if child.contains(x,y):
+                    brothers = list(self.children)
+                    brothers.remove(child)
+                    branch.append(brothers)
+                    points, branch = child.search_branch(x,y, branch)
+                    
+        else:
+            # Leaf node: Get actual waypoints
+            points = self.retrieve()      
+        return points, branch
+
+
+    def expand_search(self):
+        """Find all point indices 'up' one cell from the last search
+        """
+        points = []
+        if self.branch == []:
+            points = []
+        else:
+            three_cells = self.branch.pop()
+            for cell in three_cells:
+                #print "cell ", cell.show() 
+                points += cell.retrieve()
+        return points, self.branch
+
+
+    def contains(*args):    
+        """True only if P's coordinates lie within cell boundaries
+	This methods has two forms:
+	
+	cell.contains(index)
+	  #True if cell contains indexed point
+	cell.contains(x, y)
+	  #True if cell contains point (x,y)	
+
+        """
+	
+	self = args[0]
+	if len(args) == 2:
+	    point_id = int(args[1])
+            x = self.__class__.mesh.coordinates[point_id][0]
+            y = self.__class__.mesh.coordinates[point_id][1]
+
+            #print point_id, x, y
+	elif len(args) == 3:
+	    x = float(args[1])
+	    y = float(args[2])
+	else:
+	    msg = 'Number of arguments to method must be two or three'
+	    raise msg    		      
+	
+        if y <  self.southern: return False
+        if y >= self.northern: return False
+        if x <  self.western:  return False
+        if x >= self.eastern:  return False
+        return True
+    
+    
+    def insert(self, points, split = False):
+        """insert point(s) in existing tree structure below self
+           and split if requested
+        """
+
+        # Call insert for each element of a list of points
+        if type(points) == types.ListType:
+            for point in points:
+                self.insert(point, split)
+        else:
+            #Only one point given as argument	
+            point = points
+	
+            # Find appropriate cell
+            if self.children is not None:
+                for child in self:
+                    if child.contains(point):
+                        child.insert(point, split)
+                        break
+            else:
+                # self is a leaf cell: insert point into cell
+                if self.contains(point):
+                    self.store(point)
+                else:
+                    x = self.__class__.mesh.coordinates[point][0]
+                    y = self.__class__.mesh.coordinates[point][1]
+                    print "(" + str(x) + "," + str(y) + ")"
+                    raise 'point not in region: %s' %str(point)
+		
+		
+        #Split datastructure if requested        
+	if split is True:
+            self.split()
+		
+
+
+    def store(self,objects):
+        
+        if type(objects) not in [types.ListType,types.TupleType]:
+            self.points.append(objects)
+        else:
+            self.points.extend(objects)
+
+
+    def retrieve(self):
+         objects = []
+         if self.children is None:
+             objects = self.points
+         else:  
+             for child in self:
+                 objects += child.retrieve()
+         return objects  
+
+
+    def count(self, keywords=None):
+        """retrieve number of stored objects beneath this node inclusive
+        """
+        
+        num_waypoint = 0
+        if self.children:
+            for child in self:
+                num_waypoint = num_waypoint + child.count()
+        else:
+            num_waypoint = len(self.points)
+        return num_waypoint
+  
+
+    def clear(self):
+        self.Prune()   # TreeNode method
+
+
+    def clear_leaf_node(self):
+        """Clears storage in leaf node.
+	Called from Treenod.
+	Must exist.	
+	"""
+        self.points = []
+	
+	
+    def clear_internal_node(self):
+        """Called from Treenode.    
+	Must exist.
+	"""
+        pass
+
+
+
+    def split(self, threshold=None):
+        """
+        Partition cell when number of contained waypoints exceeds 
+        threshold.  All waypoints are then moved into correct 
+        child cell.
+        """
+        if threshold == None:
+           threshold = self.max_points_per_cell
+	    
+        #FIXME, mincellsize removed.  base it on side length, if needed
+        
+	#Protect against silly thresholds such as -1
+	if threshold < 1:
+	    return
+	
+        if not self.children:               # Leaf cell
+            if self.count() > threshold :   
+                #Split is needed
+                points = self.retrieve()    # Get points from leaf cell
+                self.clear()                # and remove them from storage
+                
+                self.spawn()                # Spawn child cells and move
+                for p in points:            # points to appropriate child
+                    for child in self:
+                        if child.contains(p):
+                            child.insert(p) 
+                            break
+    
+        if self.children:                   # Parent cell
+            for child in self:              # split (possibly newly created) 
+                child.split(threshold)      # child cells recursively
+                
+
+
+    def collapse(self,threshold=None):
+        """
+        collapse child cells into immediate parent if total number of contained waypoints
+        in subtree below is less than or equal to threshold.
+        All waypoints are then moved into parent cell and
+        children are removed. If self is a leaf node initially, do nothing.
+        """
+        
+        if threshold is None:
+            threshold = self.max_points_per_cell	
+
+
+        if self.children:                   # Parent cell    
+            if self.count() <= threshold:   # collapse
+                points = self.retrieve()    # Get all points from child cells
+                self.clear()                # Remove children, self is now a leaf node
+                self.insert(points)         # Insert all points in local storage
+            else:                          
+                for child in self:          # Check if any sub tree can be collapsed
+                    child.collapse(threshold)
+
+
+    def Get_tree(self,depth=0):
+        """Traverse tree below self
+           Print for each node the name and
+           if it is a leaf the number of objects
+        """
+        s = ''
+        if depth == 0:
+            s = '\n'
+            
+        s += "%s%s:" % ('  '*depth, self.name)
+        if self.children:
+            s += '\n'
+            for child in self.children:
+                s += child.Get_tree(depth+1)
+        else:
+            s += '(#wp=%d)\n' %(self.count())
+
+        return s
+
+	
+    def show(self, depth=0):
+        """Traverse tree below self
+           Print for each node the name and
+           if it is a leaf the number of objects
+        """
+        if depth == 0:
+            print 
+        print "%s%s" % ('  '*depth, self.name),
+        if self.children:
+            print
+            for child in self.children:
+                child.show(depth+1)
+        else:
+            print '(xmin=%.2f, xmax=%.2f, ymin=%.2f, ymax=%.2f): [%d]'\
+		  %(self.western, self.eastern,
+		    self.southern, self.northern,
+		    self.count()) 
+
+
+    def show_all(self,depth=0):
+        """Traverse tree below self
+           Print for each node the name and if it is a leaf all its objects
+        """
+        if depth == 0:
+            print 
+        print "%s%s:" % ('  '*depth, self.name),
+        if self.children:
+            print
+            for child in self.children:
+                child.show_all(depth+1)
+        else:
+            print '%s' %self.retrieve()
+
+
+    def stats(self,depth=0,min_rad=sys.maxint,max_depth=0,max_points=0):
+        """Traverse tree below self and find minimal cell radius,
+           maximumtree depth and maximum number of waypoints per leaf.
+        """
+
+        if self.children:
+            for child in self.children:
+                min_rad, max_depth, max_points =\
+                         child.Stats(depth+1,min_rad,max_depth,max_points)
+        else:
+            #FIXME remvoe radius stuff
+            #min_rad = sys.maxint
+            #if self.radius < min_rad:   min_rad = self.radius
+            if depth > max_depth: max_depth = depth
+            num_points = self.count()
+            if num_points > max_points: max_points = num_points
+
+        #return min_rad, max_depth, max_points    
+	return max_depth, max_points    
+	
+
+    #Class initialisation method	
+    def initialise(cls, mesh):
+        cls.mesh = mesh
+
+    initialise = classmethod(initialise)
+
+def build_quadtree(mesh, max_points_per_cell = 4):
+    """Build quad tree for mesh.
+
+    All vertices in mesh are stored in quadtree and a reference to the root is returned.
+    """
+
+    from Numeric import minimum, maximum
+
+    #Initialise
+    Cell.initialise(mesh)
+
+    #Make root cell
+    #print mesh.coordinates
+    
+    xmin = min(mesh.coordinates[:,0])
+    xmax = max(mesh.coordinates[:,0])
+    ymin = min(mesh.coordinates[:,1])
+    ymax = max(mesh.coordinates[:,1])
+
+    
+    #Ensure boundary points are fully contained in region
+    #It is a property of the cell structure that points on xmax or ymax of any given cell
+    #belong to the neighbouring cell.
+    #Hence, the root cell needs to be expanded slightly
+    ymax += (ymax-ymin)/10
+    xmax += (xmax-xmin)/10
+
+    # To avoid round off error
+    ymin -= (ymax-ymin)/10
+    xmin -= (xmax-xmin)/10   
+
+    #print "xmin", xmin 
+    #print "xmax", xmax
+    #print "ymin", ymin 
+    #print "ymax", ymax
+    
+    #FIXME: Use mesh.filename if it exists
+    root = Cell(ymin, ymax, xmin, xmax,
+                #name = .... 
+                max_points_per_cell = max_points_per_cell)
+
+    #root.show()
+    
+    #Insert indices of all vertices
+    root.insert( range(len(mesh.coordinates)) )
+
+    #Build quad tree and return
+    root.split()
+
+    return root
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/quantity.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/quantity.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/quantity.py	(revision 3560)
@@ -0,0 +1,1329 @@
+"""Class Quantity - Implements values at each triangular element
+
+To create:
+
+   Quantity(domain, vertex_values)
+
+   domain: Associated domain structure. Required.
+
+   vertex_values: N x 3 array of values at each vertex for each element.
+                  Default None
+
+   If vertex_values are None Create array of zeros compatible with domain.
+   Otherwise check that it is compatible with dimenions of domain.
+   Otherwise raise an exception
+"""
+
+
+class Quantity:
+
+    def __init__(self, domain, vertex_values=None):
+
+        from anuga.abstract_2d_finite_volumes.neighbour_mesh import Mesh
+        from Numeric import array, zeros, Float
+
+        msg = 'First argument in Quantity.__init__ '
+        msg += 'must be of class Mesh (or a subclass thereof)'
+        assert isinstance(domain, Mesh), msg
+
+        if vertex_values is None:
+            N = domain.number_of_elements
+            self.vertex_values = zeros((N, 3), Float)
+        else:
+            self.vertex_values = array(vertex_values).astype(Float)
+
+            N, V = self.vertex_values.shape
+            assert V == 3,\
+                   'Three vertex values per element must be specified'
+
+
+            msg = 'Number of vertex values (%d) must be consistent with'\
+                  %N
+            msg += 'number of elements in specified domain (%d).'\
+                   %domain.number_of_elements
+
+            assert N == domain.number_of_elements, msg
+
+        self.domain = domain
+
+        #Allocate space for other quantities
+        self.centroid_values = zeros(N, Float)
+        self.edge_values = zeros((N, 3), Float)
+
+        #Intialise centroid and edge_values
+        self.interpolate()
+
+
+
+    #Methods for operator overloading
+    def __len__(self):
+        return self.centroid_values.shape[0]
+
+
+    def __neg__(self):
+        """Negate all values in this quantity giving meaning to the
+        expression -Q where Q is an instance of class Quantity
+        """
+
+        Q = Quantity(self.domain)
+        Q.set_values(-self.vertex_values)
+        return Q
+
+
+    def __add__(self, other):
+        """Add to self anything that could populate a quantity
+
+        E.g other can be a constant, an array, a function, another quantity
+        (except for a filename or points, attributes (for now))
+        - see set_values for details
+        """
+
+        Q = Quantity(self.domain)
+        Q.set_values(other)
+
+        result = Quantity(self.domain)
+        result.set_values(self.vertex_values + Q.vertex_values)
+        return result
+
+    def __radd__(self, other):
+        """Handle cases like 7+Q, where Q is an instance of class Quantity
+        """
+        return self + other
+
+
+    def __sub__(self, other):
+        return self + -other  #Invoke __neg__
+
+    def __mul__(self, other):
+        """Multiply self with anything that could populate a quantity
+
+        E.g other can be a constant, an array, a function, another quantity
+        (except for a filename or points, attributes (for now))
+        - see set_values for details
+
+        Note that if two quantitites q1 and q2 are multiplied,
+        vertex values are multiplied entry by entry
+        while centroid and edge values are re-interpolated.
+        Hence they won't be the product of centroid or edge values
+        from q1 and q2.
+        """
+
+        Q = Quantity(self.domain)
+        Q.set_values(other)
+
+        result = Quantity(self.domain)
+        result.set_values(self.vertex_values * Q.vertex_values)
+        return result
+
+    def __rmul__(self, other):
+        """Handle cases like 3*Q, where Q is an instance of class Quantity
+        """
+        return self * other
+
+    def __pow__(self, other):
+        """Raise quantity to (numerical) power
+
+        As with __mul__ vertex values are processed entry by entry
+        while centroid and edge values are re-interpolated.
+
+        Example using __pow__:
+          Q = (Q1**2 + Q2**2)**0.5
+
+        """
+
+        result = Quantity(self.domain)
+        result.set_values(self.vertex_values**other)
+        return result
+
+
+
+    def interpolate(self):
+        """Compute interpolated values at edges and centroid
+        Pre-condition: vertex_values have been set
+        """
+
+        N = self.vertex_values.shape[0]
+        for i in range(N):
+            v0 = self.vertex_values[i, 0]
+            v1 = self.vertex_values[i, 1]
+            v2 = self.vertex_values[i, 2]
+
+            self.centroid_values[i] = (v0 + v1 + v2)/3
+
+        self.interpolate_from_vertices_to_edges()
+
+
+    def interpolate_from_vertices_to_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        interpolate_from_vertices_to_edges(self)
+
+
+
+
+    #New leaner interface to setting values
+    def set_values(self,
+                   numeric = None,    # List, numeric array or constant
+                   quantity = None,   # Another quantity
+                   function = None,   # Callable object: f(x,y)
+                   geospatial_data = None, #Arbitrary dataset
+                   points = None, values = None, data_georef = None, #Input for fit (obsoleted by use of geo_spatial object)
+                   filename = None, attribute_name = None, #Input from file
+                   alpha = None,
+                   location = 'vertices',
+                   indices = None,
+                   verbose = False,
+                   use_cache = False):
+
+        """Set values for quantity based on different sources.
+
+        numeric:
+          Compatible list, Numeric array (see below) or constant.
+          If callable it will treated as a function (see below)
+          If instance of another Quantity it will be treated as such.
+          If geo_spatial object it will be treated as such
+
+        quantity:
+          Another quantity (compatible quantity, e.g. obtained as a
+          linear combination of quantities)
+
+        function:
+          Any callable object that takes two 1d arrays x and y
+          each of length N and returns an array also of length N.
+          The function will be evaluated at points determined by
+          location and indices in the underlying mesh.
+
+        geospatial_data:
+          Arbitrary geo spatial dataset in the form of the class
+          Geospatial_data. Mesh points are populated using
+          fit_interpolate.fit fitting
+
+        points:
+          Nx2 array of data points for use with fit_interpolate.fit
+          If points are present, an N array of attribute
+          values corresponding to
+          each data point must be present.
+
+        values:
+          If points is specified, values is an array of length N containing
+          attribute values for each point.
+
+        data_georef:
+          If points is specified, geo_reference applies to each point.
+
+        filename:
+          Name of a .pts file containing data points and attributes for
+          use with fit_interpolate.fit.
+
+        attribute_name:
+          If specified, any array matching that name
+          will be used. from file or geospatial_data.
+          Otherwise a default will be used.
+
+        alpha:
+          Smoothing parameter to be used with fit_interpolate.fit.
+          See module fit_interpolate.fit for further details about alpha.
+          Alpha will only be used with points, values or filename.
+          Otherwise it will be ignored.
+
+
+        location: Where values are to be stored.
+                  Permissible options are: vertices, edges, centroids
+                  Default is 'vertices'
+
+                  In case of location == 'centroids' the dimension values must
+                  be a list of a Numerical array of length N,
+                  N being the number of elements.
+                  Otherwise it must be of dimension Nx3
+
+
+                  The values will be stored in elements following their
+                  internal ordering.
+
+                  If location is not 'unique vertices' Indices is the
+                  set of element ids that the operation applies to.
+                  If location is 'unique vertices' Indices is the set
+                  of vertex ids that the operation applies to.
+
+                  If selected location is vertices, values for
+                  centroid and edges will be assigned interpolated
+                  values.  In any other case, only values for the
+                  specified locations will be assigned and the others
+                  will be left undefined.
+
+        verbose: True means that output to stdout is generated
+
+        use_cache: True means that caching of intermediate results is
+                   attempted for fit_interpolate.fit.
+
+
+
+
+        Exactly one of the arguments
+          numeric, quantity, function, points, filename
+        must be present.
+        """
+
+        from anuga.geospatial_data.geospatial_data import Geospatial_data
+        from types import FloatType, IntType, LongType, ListType, NoneType
+        from Numeric import ArrayType
+
+        #General input checks
+        L = [numeric, quantity, function, geospatial_data, points, filename]
+        msg = 'Exactly one of the arguments '+\
+              'numeric, quantity, function, geospatial_data, points, or filename '+\
+              'must be present.'
+        assert L.count(None) == len(L)-1, msg
+
+
+        if location not in ['vertices', 'centroids', 'edges',
+                            'unique vertices']:
+            msg = 'Invalid location: %s' %location
+            raise msg
+
+
+        msg = 'Indices must be a list or None'
+        assert type(indices) in [ListType, NoneType, ArrayType], msg
+
+
+        if not(points is None and values is None and data_georef is None):
+            from warnings import warn
+
+            msg = 'Using points, values or data_georef with set_quantity '
+            msg += 'is obsolete. Please use a Geospatial_data object instead.'
+            warn(msg, DeprecationWarning)
+
+
+
+        #Determine which 'set_values_from_...' to use
+
+        if numeric is not None:
+            if type(numeric) in [FloatType, IntType, LongType]:
+                self.set_values_from_constant(numeric,
+                                              location, indices, verbose)
+            elif type(numeric) in [ArrayType, ListType]:
+                self.set_values_from_array(numeric,
+                                           location, indices, verbose)
+            elif callable(numeric):
+                self.set_values_from_function(numeric,
+                                              location, indices, verbose)
+            elif isinstance(numeric, Quantity):
+                self.set_values_from_quantity(numeric,
+                                              location, indices, verbose)
+            elif isinstance(numeric, Geospatial_data):
+                self.set_values_from_geospatial_data(numeric,
+                                                     alpha,
+                                                     location, indices,
+                                                     verbose = verbose,
+                                                     use_cache = use_cache)
+            else:
+                msg = 'Illegal type for argument numeric: %s' %str(numeric)
+                raise msg
+
+        elif quantity is not None:
+            self.set_values_from_quantity(quantity,
+                                          location, indices, verbose)
+        elif function is not None:
+            msg = 'Argument function must be callable'
+            assert callable(function), msg
+            self.set_values_from_function(function,
+                                          location, indices, verbose)
+        elif geospatial_data is not None:
+                self.set_values_from_geospatial_data(geospatial_data,
+                                                     alpha,
+                                                     location, indices,
+                                                     verbose = verbose,
+                                                     use_cache = use_cache)
+        elif points is not None:
+            print 'The usage of points in set_values will be deprecated.' +\
+                  'Please use the geospatial_data object.'
+
+            msg = 'When points are specified, associated values must also be.'
+            assert values is not None, msg
+            self.set_values_from_points(points, values, alpha,
+                                        location, indices,
+                                        data_georef = data_georef,
+                                        verbose = verbose,
+                                        use_cache = use_cache)
+        elif filename is not None:
+            self.set_values_from_file(filename, attribute_name, alpha,
+                                      location, indices,
+                                      verbose = verbose,
+                                      use_cache = use_cache)
+        else:
+            raise 'This can\'t happen :-)'
+
+
+        #Update all locations in triangles
+        if location == 'vertices' or location == 'unique vertices':
+            #Intialise centroid and edge_values
+            self.interpolate()
+
+        if location == 'centroids':
+            #Extrapolate 1st order - to capture notion of area being specified
+            self.extrapolate_first_order()
+
+
+
+    #Specific functions for setting values
+    def set_values_from_constant(self, X,
+                                 location, indices, verbose):
+        """Set quantity values from specified constant X
+        """
+
+
+        if location == 'centroids':
+            if (indices ==  None):
+                self.centroid_values[:] = X
+            else:
+                #Brute force
+                for i in indices:
+                    self.centroid_values[i,:] = X
+
+        elif location == 'edges':
+            if (indices ==  None):
+                self.edge_values[:] = X
+            else:
+                #Brute force
+                for i in indices:
+                    self.edge_values[i,:] = X
+
+        elif location == 'unique vertices':
+            if (indices ==  None):
+                self.edge_values[:] = X
+            else:
+
+                #Go through list of unique vertices
+                for unique_vert_id in indices:
+                    triangles = self.domain.vertexlist[unique_vert_id]
+
+                    #In case there are unused points
+                    if triangles is None: continue
+
+                    #Go through all triangle, vertex pairs
+                    #and set corresponding vertex value
+                    for triangle_id, vertex_id in triangles:
+                        self.vertex_values[triangle_id, vertex_id] = X
+
+                    #Intialise centroid and edge_values
+                    self.interpolate()
+        else:
+            if (indices ==  None):
+                self.vertex_values[:] = X
+            else:
+                #Brute force
+                for i_vertex in indices:
+                    self.vertex_values[i_vertex,:] = X
+
+
+
+
+
+
+    def set_values_from_array(self, values,
+                              location, indices, verbose):
+        """Set values for quantity
+
+        values: Numeric array
+        location: Where values are to be stored.
+        Permissible options are: vertices, edges, centroid, unique vertices
+        Default is 'vertices'
+
+        indices - if this action is carried out on a subset of
+        elements or unique vertices
+        The element/unique vertex indices are specified here.
+
+        In case of location == 'centroid' the dimension values must
+        be a list of a Numerical array of length N, N being the number
+        of elements.
+
+        Otherwise it must be of dimension Nx3
+
+        The values will be stored in elements following their
+        internal ordering.
+
+        If selected location is vertices, values for centroid and edges
+        will be assigned interpolated values.
+        In any other case, only values for the specified locations
+        will be assigned and the others will be left undefined.
+        """
+
+        from Numeric import array, Float, Int, allclose
+
+        values = array(values).astype(Float)
+
+        if indices is not None:
+            indices = array(indices).astype(Int)
+            msg = 'Number of values must match number of indices'
+            assert values.shape[0] == indices.shape[0], msg
+
+        N = self.centroid_values.shape[0]
+
+        if location == 'centroids':
+            assert len(values.shape) == 1, 'Values array must be 1d'
+
+            if indices is None:
+                msg = 'Number of values must match number of elements'
+                assert values.shape[0] == N, msg
+
+                self.centroid_values = values
+            else:
+                msg = 'Number of values must match number of indices'
+                assert values.shape[0] == indices.shape[0], msg
+
+                #Brute force
+                for i in range(len(indices)):
+                    self.centroid_values[indices[i]] = values[i]
+
+        elif location == 'edges':
+            assert len(values.shape) == 2, 'Values array must be 2d'
+
+            msg = 'Number of values must match number of elements'
+            assert values.shape[0] == N, msg
+
+            msg = 'Array must be N x 3'
+            assert values.shape[1] == 3, msg
+
+            self.edge_values = values
+
+        elif location == 'unique vertices':
+            assert len(values.shape) == 1 or allclose(values.shape[1:], 1),\
+                   'Values array must be 1d'
+
+            self.set_vertex_values(values.flat, indices = indices)
+        else:
+            if len(values.shape) == 1:
+                self.set_vertex_values(values, indices = indices)
+                #if indices == None:
+                    #Values are being specified once for each unique vertex
+                #    msg = 'Number of values must match number of vertices'
+                #    assert values.shape[0] == self.domain.coordinates.shape[0], msg
+                 #   self.set_vertex_values(values)
+                #else:
+                #    for element_index, value in map(None, indices, values):
+                #        self.vertex_values[element_index, :] = value
+
+            elif len(values.shape) == 2:
+                #Vertex values are given as a triplet for each triangle
+
+                msg = 'Array must be N x 3'
+                assert values.shape[1] == 3, msg
+
+                if indices == None:
+                    self.vertex_values = values
+                else:
+                    for element_index, value in map(None, indices, values):
+                        self.vertex_values[element_index] = value
+            else:
+                msg = 'Values array must be 1d or 2d'
+                raise msg
+
+    def set_values_from_quantity(self, q,
+                                 location, indices, verbose):
+        """Set quantity values from specified quantity instance q
+
+        Location is ignored
+        """
+
+
+        A = q.vertex_values
+
+        from Numeric import allclose
+        msg = 'Quantities are defined on different meshes. '+\
+              'This might be a case for implementing interpolation '+\
+              'between different meshes.'
+        assert allclose(A.shape, self.vertex_values.shape), msg
+
+        self.set_values(A, location='vertices',
+                        indices=indices,
+                        verbose=verbose)
+
+
+    def set_values_from_function(self, f,
+                                 location, indices, verbose):
+        """Set values for quantity using specified function
+
+        f: x, y -> z Function where x, y and z are arrays
+        location: Where values are to be stored.
+                  Permissible options are: vertices, centroid, edges,
+                  unique vertices
+                  Default is "vertices"
+        """
+
+        #FIXME: Should check that function returns something sensible and
+        #raise a meaningfull exception if it returns None for example
+
+        #FIXME: Should supply absolute coordinates
+
+        from Numeric import take
+
+        if (indices is None):
+            indices = range(len(self))
+            is_subset = False
+        else:
+            is_subset = True
+
+        if location == 'centroids':
+            P = take(self.domain.centroid_coordinates, indices)
+            if is_subset:
+                self.set_values(f(P[:,0], P[:,1]),
+                                location = location,
+                                indices = indices)
+            else:
+                self.set_values(f(P[:,0], P[:,1]), location = location)
+        elif location == 'vertices':
+            P = self.domain.vertex_coordinates
+            if is_subset:
+                #Brute force
+                for e in indices:
+                    for i in range(3):
+                        self.vertex_values[e,i] = f(P[e,2*i], P[e,2*i+1])
+            else:
+                for i in range(3):
+                    self.vertex_values[:,i] = f(P[:,2*i], P[:,2*i+1])
+        else:
+            raise 'Not implemented: %s' %location
+
+
+
+    def set_values_from_geospatial_data(self, geospatial_data, alpha,
+                                        location, indices,
+                                        verbose = False,
+                                        use_cache = False):
+
+        #FIXME: Use this function for the time being. Later move code in here
+
+        points = geospatial_data.get_data_points(absolute = False)
+        values = geospatial_data.get_attributes()
+        data_georef = geospatial_data.get_geo_reference()
+
+
+
+        self.set_values_from_points(points, values, alpha,
+                                    location, indices,
+                                    data_georef = data_georef,
+                                    verbose = verbose,
+                                    use_cache = use_cache)
+
+
+
+    def set_values_from_points(self, points, values, alpha,
+                               location, indices,
+                               data_georef = None,
+                               verbose = False,
+                               use_cache = False):
+        """
+        Set quantity values from arbitray data points using
+        fit_interpolate.fit
+        """
+
+
+        from Numeric import Float
+        from anuga.utilities.numerical_tools import ensure_numeric
+        #from anuga.abstract_2d_finite_volumes.least_squares import fit_to_mesh
+        from anuga.fit_interpolate.fit import fit_to_mesh
+        from anuga.coordinate_transforms.geo_reference import Geo_reference
+
+
+        points = ensure_numeric(points, Float)
+        values = ensure_numeric(values, Float)
+
+        if location != 'vertices':
+            msg = 'set_values_from_points is only defined for '+\
+                  'location=\'vertices\''
+            raise ms
+
+        coordinates = self.domain.coordinates
+        triangles = self.domain.triangles
+
+
+        #Take care of georeferencing
+        if data_georef is None:
+            data_georef = Geo_reference()
+
+
+        mesh_georef = self.domain.geo_reference
+
+        #print mesh_georef
+        #print data_georef
+        #print points
+
+
+        #Call fit_interpolate.fit function
+        args = (coordinates, triangles, points, values)
+        kwargs = {'data_origin': data_georef.get_origin(),
+                  'mesh_origin': mesh_georef.get_origin(),
+                  'alpha': alpha,
+                  'verbose': verbose}
+
+        #print kwargs
+
+        if use_cache is True:
+            try:
+                from caching import cache
+            except:
+                msg = 'Caching was requested, but caching module'+\
+                      'could not be imported'
+                raise msg
+
+            vertex_attributes = cache(fit_to_mesh,
+                                      args, kwargs,
+                                      verbose=verbose,
+                                      compression=False)
+        else:
+
+            vertex_attributes = apply(fit_to_mesh,
+                                      args, kwargs)
+
+        #Call underlying method using array values
+        self.set_values_from_array(vertex_attributes,
+                                   location, indices, verbose)
+
+
+
+    def set_values_from_file(self, filename, attribute_name, alpha,
+                             location, indices,
+                             verbose = False,
+                             use_cache = False):
+        """Set quantity based on arbitrary points in .pts file
+        using attribute_name selects name of attribute
+        present in file.
+        If not specified try to use whatever is available in file.
+        """
+
+        from load_mesh.loadASCII import import_points_file
+        from anuga.geospatial_data.geospatial_data import points_dictionary2geospatial_data
+
+        from types import StringType
+        msg = 'Filename must be a text string'
+        assert type(filename) == StringType, msg
+
+
+        #Read from (NetCDF) file
+        #FIXME (Ole): This function should really return a Geospatial_data object.
+        points_dict = import_points_file(filename)
+        points = points_dict['pointlist']
+        attributes = points_dict['attributelist']
+
+        if attribute_name is None:
+            names = attributes.keys()
+            attribute_name = names[0]
+
+        msg = 'Attribute_name must be a text string'
+        assert type(attribute_name) == StringType, msg
+
+
+        if verbose:
+            print 'Using attribute %s from file %s' %(attribute_name, filename)
+            print 'Available attributes: %s' %(names)
+
+        #try:
+        #    z = attributes[attribute_name]
+        #except:
+        #    msg = 'Could not extract attribute %s from file %s'\
+        #          %(attribute_name, filename)
+        #    raise msg
+
+
+        #Take care of georeferencing
+        if points_dict.has_key('geo_reference') and \
+               points_dict['geo_reference'] is not None:
+            data_georef = points_dict['geo_reference']
+        else:
+            data_georef = None
+
+
+
+        #Call underlying method for geospatial data
+        geospatial_data = points_dictionary2geospatial_data(points_dict)
+        geospatial_data.set_default_attribute_name(attribute_name)
+
+        self.set_values_from_geospatial_data(geospatial_data,
+                                             alpha,
+                                             location, indices,
+                                             verbose = verbose,
+                                             use_cache = use_cache)
+
+        #Call underlying method for points
+        #self.set_values_from_points(points, z, alpha,
+        #                            location, indices,
+        #                            data_georef = data_georef,
+        #                            verbose = verbose,
+        #                            use_cache = use_cache)
+
+
+
+    def get_values(self, location='vertices', indices = None):
+        """get values for quantity
+
+        return X, Compatible list, Numeric array (see below)
+        location: Where values are to be stored.
+                  Permissible options are: vertices, edges, centroid
+                  and unique vertices. Default is 'vertices'
+
+        In case of location == 'centroids' the dimension values must
+        be a list of a Numerical array of length N, N being the number
+        of elements. Otherwise it must be of dimension Nx3
+
+        The returned values with be a list the length of indices
+        (N if indices = None).  Each value will be a list of the three
+        vertex values for this quantity.
+
+        Indices is the set of element ids that the operation applies to.
+
+        The values will be stored in elements following their
+        internal ordering.
+
+        """
+        from Numeric import take
+
+        if location not in ['vertices', 'centroids', 'edges', 'unique vertices']:
+            msg = 'Invalid location: %s' %location
+            raise msg
+
+        import types, Numeric
+        assert type(indices) in [types.ListType, types.NoneType,
+                                 Numeric.ArrayType],\
+                                 'Indices must be a list or None'
+
+        if location == 'centroids':
+            if (indices ==  None):
+                indices = range(len(self))
+            return take(self.centroid_values,indices)
+        elif location == 'edges':
+            if (indices ==  None):
+                indices = range(len(self))
+            return take(self.edge_values,indices)
+        elif location == 'unique vertices':
+            if (indices ==  None):
+                indices=range(self.domain.coordinates.shape[0])
+            vert_values = []
+            #Go through list of unique vertices
+            for unique_vert_id in indices:
+                triangles = self.domain.vertexlist[unique_vert_id]
+
+                #In case there are unused points
+                if triangles is None:
+                    msg = 'Unique vertex not associated with triangles'
+                    raise msg
+
+                # Go through all triangle, vertex pairs
+                # Average the values
+                sum = 0
+                for triangle_id, vertex_id in triangles:
+                    sum += self.vertex_values[triangle_id, vertex_id]
+                vert_values.append(sum/len(triangles))
+            return Numeric.array(vert_values)
+        else:
+            if (indices ==  None):
+                indices = range(len(self))
+            return take(self.vertex_values,indices)
+
+
+
+    def set_vertex_values(self, A, indices = None):
+        """Set vertex values for all unique vertices based on input array A
+        which has one entry per unique vertex, i.e.
+        one value for each row in array self.domain.coordinates or
+        one value for each row in vertexlist.
+
+        indices is the list of vertex_id's that will be set.
+
+        This function is used by set_values_from_array
+        """
+
+        from Numeric import array, Float
+
+        #Assert that A can be converted to a Numeric array of appropriate dim
+        A = array(A, Float)
+
+        #print 'SHAPE A', A.shape
+        assert len(A.shape) == 1
+
+        if indices == None:
+            assert A.shape[0] == self.domain.coordinates.shape[0]
+            vertex_list = range(A.shape[0])
+        else:
+            assert A.shape[0] == len(indices)
+            vertex_list = indices
+
+        #Go through list of unique vertices
+        for i_index, unique_vert_id in enumerate(vertex_list):
+            triangles = self.domain.vertexlist[unique_vert_id]
+
+            if triangles is None: continue #In case there are unused points
+
+            #Go through all triangle, vertex pairs
+            #touching vertex unique_vert_id and set corresponding vertex value
+            for triangle_id, vertex_id in triangles:
+                self.vertex_values[triangle_id, vertex_id] = A[i_index]
+
+        #Intialise centroid and edge_values
+        self.interpolate()
+
+
+    def smooth_vertex_values(self, value_array='field_values',
+                             precision = None):
+        """ Smooths field_values or conserved_quantities data.
+        TODO: be able to smooth individual fields
+        NOTE:  This function does not have a test.
+        FIXME: NOT DONE - do we need it?
+        FIXME: this function isn't called by anything.
+               Maybe it should be removed..-DSG
+        """
+
+        from Numeric import concatenate, zeros, Float, Int, array, reshape
+
+
+        A,V = self.get_vertex_values(xy=False,
+                                     value_array=value_array,
+                                     smooth = True,
+                                     precision = precision)
+
+        #Set some field values
+        for volume in self:
+            for i,v in enumerate(volume.vertices):
+                if value_array == 'field_values':
+                    volume.set_field_values('vertex', i, A[v,:])
+                elif value_array == 'conserved_quantities':
+                    volume.set_conserved_quantities('vertex', i, A[v,:])
+
+        if value_array == 'field_values':
+            self.precompute()
+        elif value_array == 'conserved_quantities':
+            Volume.interpolate_conserved_quantities()
+
+
+    #Method for outputting model results
+    #FIXME: Split up into geometric and numeric stuff.
+    #FIXME: Geometric (X,Y,V) should live in mesh.py
+    #FIXME: STill remember to move XY to mesh
+    def get_vertex_values(self,
+                          xy=True,
+                          smooth = None,
+                          precision = None,
+                          reduction = None):
+        """Return vertex values like an OBJ format
+
+        The vertex values are returned as one sequence in the 1D float array A.
+        If requested the coordinates will be returned in 1D arrays X and Y.
+
+        The connectivity is represented as an integer array, V, of dimension
+        M x 3, where M is the number of volumes. Each row has three indices
+        into the X, Y, A arrays defining the triangle.
+
+        if smooth is True, vertex values corresponding to one common
+        coordinate set will be smoothed according to the given
+        reduction operator. In this case vertex coordinates will be
+        de-duplicated.
+
+        If no smoothings is required, vertex coordinates and values will
+        be aggregated as a concatenation of values at
+        vertices 0, vertices 1 and vertices 2
+
+
+        Calling convention
+        if xy is True:
+           X,Y,A,V = get_vertex_values
+        else:
+           A,V = get_vertex_values
+
+        """
+
+        from Numeric import concatenate, zeros, Float, Int, array, reshape
+
+
+        if smooth is None:
+            smooth = self.domain.smooth
+
+        if precision is None:
+            precision = Float
+
+        if reduction is None:
+            reduction = self.domain.reduction
+
+        #Create connectivity
+
+        if smooth == True:
+
+            V = self.domain.get_vertices()
+            N = len(self.domain.vertexlist)
+            A = zeros(N, precision)
+
+            #Smoothing loop
+            for k in range(N):
+                L = self.domain.vertexlist[k]
+
+                #Go through all triangle, vertex pairs
+                #contributing to vertex k and register vertex value
+
+                if L is None: continue #In case there are unused points
+
+                contributions = []
+                for volume_id, vertex_id in L:
+                    v = self.vertex_values[volume_id, vertex_id]
+                    contributions.append(v)
+
+                A[k] = reduction(contributions)
+
+
+            if xy is True:
+                X = self.domain.coordinates[:,0].astype(precision)
+                Y = self.domain.coordinates[:,1].astype(precision)
+
+                return X, Y, A, V
+            else:
+                return A, V
+        else:
+            #Don't smooth
+            #obj machinery moved to general_mesh
+
+            # Create a V like [[0 1 2], [3 4 5]....[3*m-2 3*m-1 3*m]]
+            # These vert_id's will relate to the verts created below
+            #m = len(self.domain)  #Number of volumes
+            #M = 3*m        #Total number of unique vertices
+            #V = reshape(array(range(M)).astype(Int), (m,3))
+
+            V = self.domain.get_triangles(obj=True)
+            #FIXME use get_vertices, when ready
+
+            A = self.vertex_values.flat
+
+            #Do vertex coordinates
+            if xy is True:
+                C = self.domain.get_vertex_coordinates()
+
+                X = C[:,0:6:2].copy()
+                Y = C[:,1:6:2].copy()
+
+                return X.flat, Y.flat, A, V
+            else:
+                return A, V
+
+
+    def extrapolate_first_order(self):
+        """Extrapolate conserved quantities from centroid to
+        vertices for each volume using
+        first order scheme.
+        """
+
+        qc = self.centroid_values
+        qv = self.vertex_values
+
+        for i in range(3):
+            qv[:,i] = qc
+
+
+    def get_integral(self):
+        """Compute the integral of quantity across entire domain
+        """
+        integral = 0
+        for k in range(self.domain.number_of_elements):
+            area = self.domain.areas[k]
+            qc = self.centroid_values[k]
+            integral += qc*area
+
+        return integral
+
+
+
+
+class Conserved_quantity(Quantity):
+    """Class conserved quantity adds to Quantity:
+
+    boundary values, storage and method for updating, and
+    methods for (second order) extrapolation from centroid to vertices inluding
+    gradients and limiters
+    """
+
+    def __init__(self, domain, vertex_values=None):
+        Quantity.__init__(self, domain, vertex_values)
+
+        from Numeric import zeros, Float
+
+        #Allocate space for boundary values
+        L = len(domain.boundary)
+        self.boundary_values = zeros(L, Float)
+
+        #Allocate space for updates of conserved quantities by
+        #flux calculations and forcing functions
+
+        N = domain.number_of_elements
+        self.explicit_update = zeros(N, Float )
+        self.semi_implicit_update = zeros(N, Float )
+
+
+    def update(self, timestep):
+        #Call correct module function
+        #(either from this module or C-extension)
+        return update(self, timestep)
+
+
+    def compute_gradients(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        return compute_gradients(self)
+
+
+    def limit(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        limit(self)
+
+
+    def extrapolate_second_order(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order(self)
+
+
+def update(quantity, timestep):
+    """Update centroid values based on values stored in
+    explicit_update and semi_implicit_update as well as given timestep
+
+    Function implementing forcing terms must take on argument
+    which is the domain and they must update either explicit
+    or implicit updates, e,g,:
+
+    def gravity(domain):
+        ....
+        domain.quantities['xmomentum'].explicit_update = ...
+        domain.quantities['ymomentum'].explicit_update = ...
+
+
+
+    Explicit terms must have the form
+
+        G(q, t)
+
+    and explicit scheme is
+
+       q^{(n+1}) = q^{(n)} + delta_t G(q^{n}, n delta_t)
+
+
+    Semi implicit forcing terms are assumed to have the form
+
+       G(q, t) = H(q, t) q
+
+    and the semi implicit scheme will then be
+
+      q^{(n+1}) = q^{(n)} + delta_t H(q^{n}, n delta_t) q^{(n+1})
+
+
+    """
+
+    from Numeric import sum, equal, ones, exp, Float
+
+    N = quantity.centroid_values.shape[0]
+
+
+    #Divide H by conserved quantity to obtain G (see docstring above)
+
+
+    for k in range(N):
+        x = quantity.centroid_values[k]
+        if x == 0.0:
+            #FIXME: Is this right
+            quantity.semi_implicit_update[k] = 0.0
+        else:
+            quantity.semi_implicit_update[k] /= x
+
+
+    #Semi implicit updates
+    denominator = ones(N, Float)-timestep*quantity.semi_implicit_update
+
+    if sum(less(denominator, 1.0)) > 0.0:
+        msg = 'denominator < 1.0 in semi implicit update. Call Stephen :-)'
+        raise msg
+
+    if sum(equal(denominator, 0.0)) > 0.0:
+        msg = 'Zero division in semi implicit update. Call Stephen :-)'
+        raise msg
+    else:
+        #Update conserved_quantities from semi implicit updates
+        quantity.centroid_values /= denominator
+
+#    quantity.centroid_values = exp(timestep*quantity.semi_implicit_update)*quantity.centroid_values
+
+    #Explicit updates
+    quantity.centroid_values += timestep*quantity.explicit_update
+
+def interpolate_from_vertices_to_edges(quantity):
+    """Compute edge values from vertex values using linear interpolation
+    """
+
+    for k in range(quantity.vertex_values.shape[0]):
+        q0 = quantity.vertex_values[k, 0]
+        q1 = quantity.vertex_values[k, 1]
+        q2 = quantity.vertex_values[k, 2]
+
+        quantity.edge_values[k, 0] = 0.5*(q1+q2)
+        quantity.edge_values[k, 1] = 0.5*(q0+q2)
+        quantity.edge_values[k, 2] = 0.5*(q0+q1)
+
+
+
+def extrapolate_second_order(quantity):
+    """Extrapolate conserved quantities from centroid to
+    vertices for each volume using
+    second order scheme.
+    """
+
+    a, b = quantity.compute_gradients()
+
+    X = quantity.domain.get_vertex_coordinates()
+    qc = quantity.centroid_values
+    qv = quantity.vertex_values
+
+    #Check each triangle
+    for k in range(quantity.domain.number_of_elements):
+        #Centroid coordinates
+        x, y = quantity.domain.centroid_coordinates[k]
+
+        #vertex coordinates
+        x0, y0, x1, y1, x2, y2 = X[k,:]
+
+        #Extrapolate
+        qv[k,0] = qc[k] + a[k]*(x0-x) + b[k]*(y0-y)
+        qv[k,1] = qc[k] + a[k]*(x1-x) + b[k]*(y1-y)
+        qv[k,2] = qc[k] + a[k]*(x2-x) + b[k]*(y2-y)
+
+
+def compute_gradients(quantity):
+    """Compute gradients of triangle surfaces defined by centroids of
+    neighbouring volumes.
+    If one edge is on the boundary, use own centroid as neighbour centroid.
+    If two or more are on the boundary, fall back to first order scheme.
+    """
+
+    from Numeric import zeros, Float
+    from utilitites.numerical_tools import gradient
+
+    centroid_coordinates = quantity.domain.centroid_coordinates
+    surrogate_neighbours = quantity.domain.surrogate_neighbours
+    centroid_values = quantity.centroid_values
+    number_of_boundaries = quantity.domain.number_of_boundaries
+
+    N = centroid_values.shape[0]
+
+    a = zeros(N, Float)
+    b = zeros(N, Float)
+
+    for k in range(N):
+    	if number_of_boundaries[k] < 2:
+            #Two or three true neighbours
+
+            #Get indices of neighbours (or self when used as surrogate)
+            k0, k1, k2 = surrogate_neighbours[k,:]
+
+            #Get data
+            q0 = centroid_values[k0]
+            q1 = centroid_values[k1]
+            q2 = centroid_values[k2]
+
+            x0, y0 = centroid_coordinates[k0] #V0 centroid
+            x1, y1 = centroid_coordinates[k1] #V1 centroid
+            x2, y2 = centroid_coordinates[k2] #V2 centroid
+
+            #Gradient
+            a[k], b[k] = gradient(x0, y0, x1, y1, x2, y2, q0, q1, q2)
+
+        elif number_of_boundaries[k] == 2:
+            #One true neighbour
+
+            #Get index of the one neighbour
+            for k0 in surrogate_neighbours[k,:]:
+	    	if k0 != k: break
+            assert k0 != k
+
+            k1 = k  #self
+
+            #Get data
+            q0 = centroid_values[k0]
+            q1 = centroid_values[k1]
+
+            x0, y0 = centroid_coordinates[k0] #V0 centroid
+            x1, y1 = centroid_coordinates[k1] #V1 centroid
+
+            #Gradient
+            a[k], b[k] = gradient2(x0, y0, x1, y1, q0, q1)
+        else:
+            #No true neighbours -
+            #Fall back to first order scheme
+            pass
+
+
+    return a, b
+
+
+
+def limit(quantity):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    This is an unsophisticated limiter as it does not take into
+    account dependencies among quantities.
+
+    precondition:
+    vertex values are estimated from gradient
+    postcondition:
+    vertex values are updated
+    """
+
+    from Numeric import zeros, Float
+
+    N = quantity.domain.number_of_elements
+
+    beta_w = quantity.domain.beta_w
+
+    qc = quantity.centroid_values
+    qv = quantity.vertex_values
+
+    #Find min and max of this and neighbour's centroid values
+    qmax = zeros(qc.shape, Float)
+    qmin = zeros(qc.shape, Float)
+
+    for k in range(N):
+        qmax[k] = qmin[k] = qc[k]
+        for i in range(3):
+            n = quantity.domain.neighbours[k,i]
+            if n >= 0:
+                qn = qc[n] #Neighbour's centroid value
+
+                qmin[k] = min(qmin[k], qn)
+                qmax[k] = max(qmax[k], qn)
+
+
+    #Diffences between centroids and maxima/minima
+    dqmax = qmax - qc
+    dqmin = qmin - qc
+
+    #Deltas between vertex and centroid values
+    dq = zeros(qv.shape, Float)
+    for i in range(3):
+        dq[:,i] = qv[:,i] - qc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        for i in range(3):
+            r = 1.0
+            if (dq[k,i] > 0): r = dqmax[k]/dq[k,i]
+            if (dq[k,i] < 0): r = dqmin[k]/dq[k,i]
+
+            phi = min( min(r*beta_w, 1), phi )
+
+        #Then update using phi limiter
+        for i in range(3):
+            qv[k,i] = qc[k] + phi*dq[k,i]
+
+
+
+from anuga.utilities import compile
+if compile.can_use_C_extension('quantity_ext.c'):
+    #Replace python version with c implementations
+
+    from quantity_ext import limit, compute_gradients,\
+    extrapolate_second_order, interpolate_from_vertices_to_edges, update
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/quantity_ext.c
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/quantity_ext.c	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/quantity_ext.c	(revision 3560)
@@ -0,0 +1,545 @@
+// Python - C extension for quantity module.
+//
+// To compile (Python2.3):
+//  gcc -c util_ext.c -I/usr/include/python2.3 -o util_ext.o -Wall -O
+//  gcc -shared util_ext.o  -o util_ext.so
+//
+// See the module quantity.py
+//
+//
+// Ole Nielsen, GA 2004
+
+#include "Python.h"
+#include "Numeric/arrayobject.h"
+#include "math.h"
+
+//Shared code snippets
+#include "util_ext.h"
+//#include "quantity_ext.h" //Obsolete
+
+
+
+int _compute_gradients(int N,
+			double* centroids,
+			double* centroid_values,
+			long* number_of_boundaries,
+			long* surrogate_neighbours,
+			double* a,
+			double* b) {
+
+  int i, k, k0, k1, k2, index3;
+  double x0, x1, x2, y0, y1, y2, q0, q1, q2; //, det;
+
+
+  for (k=0; k<N; k++) {
+    index3 = 3*k;
+
+    if (number_of_boundaries[k] < 2) {
+      //Two or three true neighbours
+
+      //Get indices of neighbours (or self when used as surrogate)
+      //k0, k1, k2 = surrogate_neighbours[k,:]
+
+      k0 = surrogate_neighbours[index3 + 0];
+      k1 = surrogate_neighbours[index3 + 1];
+      k2 = surrogate_neighbours[index3 + 2];
+
+
+      if (k0 == k1 || k1 == k2) return -1;
+
+      //Get data
+      q0 = centroid_values[k0];
+      q1 = centroid_values[k1];
+      q2 = centroid_values[k2];
+
+      x0 = centroids[k0*2]; y0 = centroids[k0*2+1];
+      x1 = centroids[k1*2]; y1 = centroids[k1*2+1];
+      x2 = centroids[k2*2]; y2 = centroids[k2*2+1];
+
+      //Gradient
+      _gradient(x0, y0, x1, y1, x2, y2, q0, q1, q2, &a[k], &b[k]);
+
+    } else if (number_of_boundaries[k] == 2) {
+      //One true neighbour
+
+      //#Get index of the one neighbour
+      i=0; k0 = k;
+      while (i<3 && k0==k) {
+	k0 = surrogate_neighbours[index3 + i];
+	i++;
+      }
+      if (k0 == k) return -1;
+
+      k1 = k; //self
+
+      //Get data
+      q0 = centroid_values[k0];
+      q1 = centroid_values[k1];
+
+      x0 = centroids[k0*2]; y0 = centroids[k0*2+1];
+      x1 = centroids[k1*2]; y1 = centroids[k1*2+1];
+
+      //Two point gradient
+      _gradient2(x0, y0, x1, y1, q0, q1, &a[k], &b[k]);
+
+
+      //Old (wrong code)
+      //det = x0*y1 - x1*y0;
+      //if (det != 0.0) {
+      //	a[k] = (y1*q0 - y0*q1)/det;
+      //	b[k] = (x0*q1 - x1*q0)/det;
+      //}
+    }
+    //    else:
+    //        #No true neighbours -
+    //        #Fall back to first order scheme
+    //        pass
+  }
+  return 0;
+}
+
+
+int _extrapolate(int N,
+		 double* centroids,
+		 double* centroid_values,
+		 double* vertex_coordinates,
+		 double* vertex_values,
+		 double* a,
+		 double* b) {
+
+  int k, k2, k3, k6;
+  double x, y, x0, y0, x1, y1, x2, y2;
+
+  for (k=0; k<N; k++) {
+    k6 = 6*k;
+    k3 = 3*k;
+    k2 = 2*k;
+
+    //Centroid coordinates
+    x = centroids[k2]; y = centroids[k2+1];
+
+    //vertex coordinates
+    //x0, y0, x1, y1, x2, y2 = X[k,:]
+    x0 = vertex_coordinates[k6 + 0];
+    y0 = vertex_coordinates[k6 + 1];
+    x1 = vertex_coordinates[k6 + 2];
+    y1 = vertex_coordinates[k6 + 3];
+    x2 = vertex_coordinates[k6 + 4];
+    y2 = vertex_coordinates[k6 + 5];
+
+    //Extrapolate
+    vertex_values[k3+0] = centroid_values[k] + a[k]*(x0-x) + b[k]*(y0-y);
+    vertex_values[k3+1] = centroid_values[k] + a[k]*(x1-x) + b[k]*(y1-y);
+    vertex_values[k3+2] = centroid_values[k] + a[k]*(x2-x) + b[k]*(y2-y);
+
+  }
+  return 0;
+}
+
+
+
+
+int _interpolate(int N,
+		 double* vertex_values,
+		 double* edge_values) {
+
+  int k, k3;
+  double q0, q1, q2;
+
+
+  for (k=0; k<N; k++) {
+    k3 = 3*k;
+
+    q0 = vertex_values[k3 + 0];
+    q1 = vertex_values[k3 + 1];
+    q2 = vertex_values[k3 + 2];
+
+    //printf("%f, %f, %f\n", q0, q1, q2);
+    edge_values[k3 + 0] = 0.5*(q1+q2);
+    edge_values[k3 + 1] = 0.5*(q0+q2);
+    edge_values[k3 + 2] = 0.5*(q0+q1);
+  }
+  return 0;
+}
+
+int _update(int N,
+	    double timestep,
+	    double* centroid_values,
+	    double* explicit_update,
+	    double* semi_implicit_update) {
+  //Update centroid values based on values stored in
+  //explicit_update and semi_implicit_update as well as given timestep
+
+
+  int k;
+  double denominator, x;
+
+
+  //Divide semi_implicit update by conserved quantity
+  for (k=0; k<N; k++) {
+    x = centroid_values[k];
+    if (x == 0.0) {
+      semi_implicit_update[k] = 0.0;
+    } else {
+      semi_implicit_update[k] /= x;
+    }
+  }
+
+
+  //Semi implicit updates
+  for (k=0; k<N; k++) {
+    denominator = 1.0 - timestep*semi_implicit_update[k];
+    if (denominator == 0.0) {
+      return -1;
+    } else {
+      //Update conserved_quantities from semi implicit updates
+      centroid_values[k] /= denominator;
+    }
+  }
+
+/*  for (k=0; k<N; k++) {*/
+/*    centroid_values[k] = exp(timestep*semi_implicit_update[k])*centroid_values[k];*/
+/*  }*/
+
+
+  //Explicit updates
+  for (k=0; k<N; k++) {
+    centroid_values[k] += timestep*explicit_update[k];
+  }
+
+
+  //MH080605 set semi_impliit_update[k] to 0.0 here, rather than in update_conserved_quantities.py
+  for (k=0;k<N;k++){
+    semi_implicit_update[k]=0.0;
+  }
+
+  return 0;
+}
+
+
+/////////////////////////////////////////////////
+// Gateways to Python
+PyObject *update(PyObject *self, PyObject *args) {
+
+  PyObject *quantity;
+  PyArrayObject *centroid_values, *explicit_update, *semi_implicit_update;
+
+  double timestep;
+  int N, err;
+
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "Od", &quantity, &timestep))
+    return NULL;
+
+  centroid_values = get_consecutive_array(quantity, "centroid_values");
+  explicit_update = get_consecutive_array(quantity, "explicit_update");
+  semi_implicit_update = get_consecutive_array(quantity, "semi_implicit_update");
+
+  N = centroid_values -> dimensions[0];
+
+  err = _update(N, timestep,
+		(double*) centroid_values -> data,
+		(double*) explicit_update -> data,
+		(double*) semi_implicit_update -> data);
+
+
+  if (err != 0) {
+    PyErr_SetString(PyExc_RuntimeError,
+		    "Zero division in semi implicit update - call Stephen :)");
+    return NULL;
+  }
+
+  //Release and return
+  Py_DECREF(centroid_values);
+  Py_DECREF(explicit_update);
+  Py_DECREF(semi_implicit_update);
+
+  return Py_BuildValue("");
+}
+
+
+PyObject *interpolate_from_vertices_to_edges(PyObject *self, PyObject *args) {
+
+  PyObject *quantity;
+  PyArrayObject *vertex_values, *edge_values;
+
+  int N, err;
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "O", &quantity))
+    return NULL;
+
+  vertex_values = get_consecutive_array(quantity, "vertex_values");
+  edge_values = get_consecutive_array(quantity, "edge_values");
+
+  N = vertex_values -> dimensions[0];
+
+  err = _interpolate(N,
+		     (double*) vertex_values -> data,
+		     (double*) edge_values -> data);
+
+  if (err != 0) {
+    PyErr_SetString(PyExc_RuntimeError, "Interpolate could not be computed");
+    return NULL;
+  }
+
+  //Release and return
+  Py_DECREF(vertex_values);
+  Py_DECREF(edge_values);
+
+  return Py_BuildValue("");
+}
+
+
+PyObject *compute_gradients(PyObject *self, PyObject *args) {
+
+  PyObject *quantity, *domain, *R;
+  PyArrayObject
+    *centroids,            //Coordinates at centroids
+    *centroid_values,      //Values at centroids
+    *number_of_boundaries, //Number of boundaries for each triangle
+    *surrogate_neighbours, //True neighbours or - if one missing - self
+    *a, *b;                //Return values
+
+  int dimensions[1], N, err;
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "O", &quantity))
+    return NULL;
+
+  domain = PyObject_GetAttrString(quantity, "domain");
+  if (!domain)
+    return NULL;
+
+  //Get pertinent variables
+
+  centroids = get_consecutive_array(domain, "centroid_coordinates");
+  centroid_values = get_consecutive_array(quantity, "centroid_values");
+  surrogate_neighbours = get_consecutive_array(domain, "surrogate_neighbours");
+  number_of_boundaries = get_consecutive_array(domain, "number_of_boundaries");
+
+  N = centroid_values -> dimensions[0];
+
+  //Release
+  Py_DECREF(domain);
+
+  //Allocate space for return vectors a and b (don't DECREF)
+  dimensions[0] = N;
+  a = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
+  b = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
+
+
+
+  err = _compute_gradients(N,
+			   (double*) centroids -> data,
+			   (double*) centroid_values -> data,
+			   (long*) number_of_boundaries -> data,
+			   (long*) surrogate_neighbours -> data,
+			   (double*) a -> data,
+			   (double*) b -> data);
+
+  if (err != 0) {
+    PyErr_SetString(PyExc_RuntimeError, "Gradient could not be computed");
+    return NULL;
+  }
+
+  //Release
+  Py_DECREF(centroids);
+  Py_DECREF(centroid_values);
+  Py_DECREF(number_of_boundaries);
+  Py_DECREF(surrogate_neighbours);
+
+  //Build result, release and return
+  R = Py_BuildValue("OO", PyArray_Return(a), PyArray_Return(b));
+  Py_DECREF(a);
+  Py_DECREF(b);
+  return R;
+}
+
+
+
+PyObject *extrapolate_second_order(PyObject *self, PyObject *args) {
+
+  PyObject *quantity, *domain;
+  PyArrayObject
+    *centroids,            //Coordinates at centroids
+    *centroid_values,      //Values at centroids
+    *vertex_coordinates,   //Coordinates at vertices
+    *vertex_values,        //Values at vertices
+    *number_of_boundaries, //Number of boundaries for each triangle
+    *surrogate_neighbours, //True neighbours or - if one missing - self
+    *a, *b;                //Gradients
+
+  //int N, err;
+  int dimensions[1], N, err;
+  //double *a, *b;  //Gradients
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "O", &quantity))
+    return NULL;
+
+  domain = PyObject_GetAttrString(quantity, "domain");
+  if (!domain)
+    return NULL;
+
+  //Get pertinent variables
+  centroids = get_consecutive_array(domain, "centroid_coordinates");
+  centroid_values = get_consecutive_array(quantity, "centroid_values");
+  surrogate_neighbours = get_consecutive_array(domain, "surrogate_neighbours");
+  number_of_boundaries = get_consecutive_array(domain, "number_of_boundaries");
+  vertex_coordinates = get_consecutive_array(domain, "vertex_coordinates");
+  vertex_values = get_consecutive_array(quantity, "vertex_values");
+
+  N = centroid_values -> dimensions[0];
+
+  //Release
+  Py_DECREF(domain);
+
+  //Allocate space for return vectors a and b (don't DECREF)
+  dimensions[0] = N;
+  a = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
+  b = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
+
+  //FIXME: Odd that I couldn't use normal arrays
+  //Allocate space for return vectors a and b (don't DECREF)
+  //a = (double*) malloc(N * sizeof(double));
+  //if (!a) return NULL;
+  //b = (double*) malloc(N * sizeof(double));
+  //if (!b) return NULL;
+
+
+  err = _compute_gradients(N,
+			   (double*) centroids -> data,
+			   (double*) centroid_values -> data,
+			   (long*) number_of_boundaries -> data,
+			   (long*) surrogate_neighbours -> data,
+			   (double*) a -> data,
+			   (double*) b -> data);
+
+  if (err != 0) {
+    PyErr_SetString(PyExc_RuntimeError, "Gradient could not be computed");
+    return NULL;
+  }
+
+  err = _extrapolate(N,
+		     (double*) centroids -> data,
+		     (double*) centroid_values -> data,
+		     (double*) vertex_coordinates -> data,
+		     (double*) vertex_values -> data,
+		     (double*) a -> data,
+		     (double*) b -> data);
+
+
+  if (err != 0) {
+    PyErr_SetString(PyExc_RuntimeError,
+		    "Internal function _extrapolate failed");
+    return NULL;
+  }
+
+
+
+  //Release
+  Py_DECREF(centroids);
+  Py_DECREF(centroid_values);
+  Py_DECREF(number_of_boundaries);
+  Py_DECREF(surrogate_neighbours);
+  Py_DECREF(vertex_coordinates);
+  Py_DECREF(vertex_values);
+  Py_DECREF(a);
+  Py_DECREF(b);
+
+  return Py_BuildValue("");
+}
+
+
+
+PyObject *limit(PyObject *self, PyObject *args) {
+
+  PyObject *quantity, *domain, *Tmp;
+  PyArrayObject
+    *qv, //Conserved quantities at vertices
+    *qc, //Conserved quantities at centroids
+    *neighbours;
+
+  int k, i, n, N, k3;
+  double beta_w; //Safety factor
+  double *qmin, *qmax, qn;
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "O", &quantity))
+    return NULL;
+
+  domain = PyObject_GetAttrString(quantity, "domain");
+  if (!domain)
+    return NULL;
+
+  //neighbours = (PyArrayObject*) PyObject_GetAttrString(domain, "neighbours");
+  neighbours = get_consecutive_array(domain, "neighbours");
+
+  //Get safety factor beta_w
+  Tmp = PyObject_GetAttrString(domain, "beta_w");
+  if (!Tmp)
+    return NULL;
+
+  beta_w = PyFloat_AsDouble(Tmp);
+
+  Py_DECREF(Tmp);
+  Py_DECREF(domain);
+
+
+  qc = get_consecutive_array(quantity, "centroid_values");
+  qv = get_consecutive_array(quantity, "vertex_values");
+
+
+  N = qc -> dimensions[0];
+
+  //Find min and max of this and neighbour's centroid values
+  qmin = malloc(N * sizeof(double));
+  qmax = malloc(N * sizeof(double));
+  for (k=0; k<N; k++) {
+    k3=k*3;
+
+    qmin[k] = ((double*) qc -> data)[k];
+    qmax[k] = qmin[k];
+
+    for (i=0; i<3; i++) {
+      n = ((long*) neighbours -> data)[k3+i];
+      if (n >= 0) {
+	qn = ((double*) qc -> data)[n]; //Neighbour's centroid value
+
+	qmin[k] = min(qmin[k], qn);
+	qmax[k] = max(qmax[k], qn);
+      }
+    }
+  }
+
+  // Call underlying routine
+  _limit(N, beta_w, (double*) qc -> data, (double*) qv -> data, qmin, qmax);
+
+  free(qmin);
+  free(qmax);
+  return Py_BuildValue("");
+}
+
+
+
+// Method table for python module
+static struct PyMethodDef MethodTable[] = {
+  {"limit", limit, METH_VARARGS, "Print out"},
+  {"update", update, METH_VARARGS, "Print out"},
+  {"compute_gradients", compute_gradients, METH_VARARGS, "Print out"},
+  {"extrapolate_second_order", extrapolate_second_order,
+   METH_VARARGS, "Print out"},
+  {"interpolate_from_vertices_to_edges",
+   interpolate_from_vertices_to_edges,
+   METH_VARARGS, "Print out"},
+  {NULL, NULL, 0, NULL}   // sentinel
+};
+
+// Module initialisation
+void initquantity_ext(void){
+  Py_InitModule("quantity_ext", MethodTable);
+
+  import_array();     //Necessary for handling of NumPY structures
+}
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/realtime_visualisation.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/realtime_visualisation.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/realtime_visualisation.py	(revision 3560)
@@ -0,0 +1,267 @@
+from visual import *
+
+def normal(v1,v2):
+    """Safe computation of normalised cross product
+    """
+    try:
+        n = norm(cross(v1, v2))
+    except ZeroDivisionError:
+        print v1, v2
+        raise Exception
+        #n = vector(0,0,0)
+
+    return n
+
+
+class Triangle:
+    def __init__(self,v0,v1,v2,color=(1,1,1), frame=None):
+        """Create one flat triangular panel with two sides
+        """
+
+        #Outward normal
+
+        self.normal=normal(v1-v0, v2-v0)
+
+        self.panel = faces(frame = frame)
+        self.backpanel = faces(frame = frame)
+        for v in (v0,v1,v2):
+            self.panel.append(pos=v, normal = self.normal, color=color)
+
+        for v in (v2,v1,v0):
+            self.backpanel.append(pos=v, normal = -self.normal, color=color)
+
+
+    def move(self,v):
+        """Move panel in direction given by vector v
+        """
+
+        for vertex in self.panel.pos:
+            vertex += v
+
+    def update_height(self,d,fix_baseline=False):
+        """Change height of triangle by displacing the third vertex by
+        d in the direction perpendicular to the baseline (v1-v0) and the
+        outward normal vector
+        """
+
+        v0 = self.panel.pos[0]
+        v1 = self.panel.pos[1]
+        v2 = self.panel.pos[2]
+
+        n = normal(v1-v0, self.normal)
+
+        if fix_baseline:
+            self.panel.pos[2] -= d*n
+        else:
+            self.panel.pos[:2] += d*n
+
+    def update_color(self, c):
+        """Change color to c
+        """
+
+        self.panel.color = c
+
+
+    def set_vertexheights(self, heights, floor_heights = None):
+        from Numeric import zeros, Float
+
+        from anuga.config import minimum_allowed_height as hmin
+        if floor_heights is None:
+            floor_heights = zeros(heights.shape, Float)
+
+        all_vertices_below_threshold = True
+        for k in range(3):
+            w = heights[k]
+            z = floor_heights[k]
+
+            if w-z >= hmin:
+                all_vertices_below_threshold = False
+
+            vertex = self.panel.pos[k]
+            vertex[2] = w
+
+            vertex = self.backpanel.pos[2-k]
+            vertex[2] = w
+
+
+        #Update color to visualise dry areas
+        if all_vertices_below_threshold:
+            self.panel.color = self.bottom_color
+            self.backpanel.color = self.bottom_color
+        else:
+            self.panel.color = self.top_color
+            self.backpanel.color = self.top_color
+
+
+        #update normal
+        v0 = self.panel.pos[0]
+        v1 = self.panel.pos[1]
+        v2 = self.panel.pos[2]
+
+
+        n = normal(v1-v0, v2-v0)
+        self.panel.normal=n
+        self.backpanel.normal=-n
+
+
+
+
+def create_surface(domain):
+    """Link surface of domains to their visual representations
+    """
+
+    fr = frame() #Default frame to contain all objects
+    s=0
+
+    Q = domain.quantities['stage']
+    try:
+        Z = domain.quantities['elevation']
+        bed = True
+    except:
+        bed = False
+
+    N = Q.vertex_values.shape[0]
+
+    domain.visuals = []
+    for i in range(N):
+
+        z0 = Q.vertex_values[i, 0]
+        z1 = Q.vertex_values[i, 1]
+        z2 = Q.vertex_values[i, 2]
+
+        x0, y0 = domain.get_vertex_coordinate(i,0)
+        x1, y1 = domain.get_vertex_coordinate(i,1)
+        x2, y2 = domain.get_vertex_coordinate(i,2)
+
+        V0 = vector(x0, y0, z0)
+        V1 = vector(x1, y1, z1)
+        V2 = vector(x2, y2, z2)
+
+
+        #Top surface
+        c0 = 0.1
+        c1 = 0.4
+        c2 = 0.99
+        if s:
+            c2 = 0.7*c2   #To show triangles in slightly different shades
+
+        s = 1-s
+
+        col = (c0,c1,c2)
+
+        visual_top = Triangle(V0,V1,V2,color=col,frame=fr)
+        visual_top.top_color = col
+
+
+        #Bottom surface
+        #v0, v1, v2 = volume.vertices
+        #v0 = vector(v0.x, v0.y, v0.field_values[index])
+        #v1 = vector(v1.x, v1.y, v1.field_values[index])
+        #v2 = vector(v2.x, v2.y, v2.field_values[index])
+        if bed:
+            z0 = Z.vertex_values[i, 0]
+            z1 = Z.vertex_values[i, 1]
+            z2 = Z.vertex_values[i, 2]
+        else:
+            z0 = z1 = z2 = 0.0
+
+        V0 = vector(x0, y0, z0)
+        V1 = vector(x1, y1, z1)
+        V2 = vector(x2, y2, z2)
+
+        c0 = 0.3
+        c1 = 0.3
+        c2 = 0.3
+        if s:
+            c2 = 0.4*c2   #To show triangles in slightly different shades
+
+        col = (c0,c1,c2)
+        visual_bottom = Triangle(V0, V1, V2, color=col,frame=fr)
+        visual_top.bottom_color=col
+
+        domain.visuals.append( (visual_top, visual_bottom) )
+
+    update(domain)
+    #print 'Scale', scene.scale
+
+
+def update(domain):
+    """Update vertex heights.
+    The argument index refers to which conserved quantity to visualise.
+    If domain.smooth is set True, vertex values will be averaged
+    yielding a smoother surface.
+    """
+
+    from Numeric import array
+
+
+    Q = domain.quantities['stage']
+    N = Q.vertex_values.shape[0]
+
+    #print scene.forward
+    #FIXME: Use smoother from anuga.pyvolution instead
+    if domain.smooth:
+        #Get all average point values
+        vertex_heights = {}
+
+        for k in range(N):
+            for i in range(3):
+                vertex = domain.triangles[k, i]
+                if vertex_heights.has_key(vertex):
+                    vertex_heights[vertex].append(
+                        Q.vertex_values[k, i])
+                else:
+                    vertex_heights[vertex] = []
+                    vertex_heights[vertex].append(
+                        Q.vertex_values[k, i])
+
+
+
+    for k in range(N):
+        if domain.smooth:
+            #The averages
+            x = zeros(3, Float)
+            for i in range(3):
+                vertex = domain.triangles[k, i]
+                A = array(vertex_heights[vertex])
+                x[i] = sum(A)/len(A)
+        else:
+            #The true values
+            x = [Q.vertex_values[k, 0],
+                 Q.vertex_values[k, 1],
+                 Q.vertex_values[k, 2]]
+
+
+        #Do it
+        floor_heights = array([pos[2] for pos in domain.visuals[k][1].panel.pos])
+
+        domain.visuals[k][0].set_vertexheights(x, floor_heights)
+
+
+
+
+scene.width = 1000
+scene.height = 800
+
+#Original
+scene.center = (0.5,0.5,0)
+scene.forward = vector(0.0, 0.5, -0.5)
+
+#Temporary (for bedslope)
+#scene.forward = vector(0.0006, 0.7, -0.03)
+
+
+#Temporary for hackett - begin
+#scene.autoscale = 0
+#scene.scale = (0.002, 0.002, 0.01) #Scale z so that countours stand out more
+#scene.center = (300.0,500.0,-10)
+#Temporary for hackett - end
+
+
+scene.ambient = 0.4
+scene.lights = [(0.6, 0.3, 0.2), (0.1, -0.5, 0.4), (-0.1, 0.1, -0.4),
+                (-0.2, 0.2, 0.1)]
+
+
+
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/realtime_visualisation_new.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/realtime_visualisation_new.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/realtime_visualisation_new.py	(revision 3560)
@@ -0,0 +1,665 @@
+
+from visual import *
+
+elevation_color = (0.3,0.4,0.5)
+stage_color     = (0.1,0.4,0.99)
+friction_color  = (0.1,0.99,0.1)
+other_color     = (0.99,0.4,0.1)
+
+
+class Visualiser:
+
+    def __init__(self,domain,scale_z=1.0,rect=None,title='Test'):
+        """Create visualisation of domain
+        """
+
+        self.scene = display(title=title)
+        self.scene.center = (0.5,0.5,0.0)
+        self.scene.forward = vector(-0.0, 0.5, -0.8)
+        self.scene.ambient = 0.4
+        self.scene.lights = [(0.6, 0.3, 0.2), (0.1, -0.5, 0.4)]
+
+        self.frame  = frame()
+
+        self.domain          = domain
+        self.default_scale_z = scale_z
+        self.vertices        = domain.vertex_coordinates
+
+
+        # models for each quantity
+        self.vpython_z_models = {}
+        #print keys
+        for key in self.domain.quantities:
+            self.vpython_z_models[key] = faces(frame=self.frame)
+
+        #print self.z_models
+
+        if rect is None:
+            self.max_x = max(max(self.vertices[:,0]),max(self.vertices[:,2]),max(self.vertices[:,4]))
+            self.min_x = min(min(self.vertices[:,0]),min(self.vertices[:,2]),min(self.vertices[:,4]))
+            self.max_y = max(max(self.vertices[:,1]),max(self.vertices[:,3]),max(self.vertices[:,5]))
+            self.min_y = min(min(self.vertices[:,1]),min(self.vertices[:,3]),min(self.vertices[:,5]))
+        else:
+            self.max_x = rect[2]
+            self.min_x = rect[0]
+            self.max_y = rect[3]
+            self.min_y = rect[1]
+
+
+        self.range_x = self.max_x - self.min_x
+        self.range_y = self.max_y - self.min_y
+        self.range_xy = max(self.range_x, self.range_y)
+
+
+#        print 'min_x=',self.min_x
+#        print 'max_x=',self.max_x
+#        print 'range_x=',self.range_x
+#        print 'min_y=',self.min_y
+#        print 'max_y=',self.max_y
+#        print 'range_y',self.range_y
+
+        self.stage_color     = stage_color
+        self.elevation_color = elevation_color
+        self.friction_color  = friction_color
+        self.other_color     = other_color
+
+        self.qcolor = {}
+        self.scale_z = {}
+        self.coloring = {}
+        self.updating = {}
+        self.setup = {}
+
+        self.qcolor['stage']  = self.stage_color
+        self.scale_z['stage']  = 1.0
+        self.coloring['stage'] = False
+        self.updating['stage'] = True
+        self.setup['stage'] = True
+
+        self.qcolor['elevation']  = self.elevation_color
+        self.scale_z['elevation']  = 1.0
+        self.coloring['elevation'] = False
+        self.updating['elevation'] = False
+        self.setup['elevation'] = False
+
+        #print self.max_x, self.min_x, self.max_y, self.min_y,
+        #self.min_bed print self.max_bed, self.range_x, self.range_y,
+        #self.range_xy, self.range_bed
+        #print 'Calculating triangles'
+
+        self.pos     = zeros( (6*len(domain),3), Float)
+        self.colour  = zeros( (6*len(domain),3), Float)
+        self.normals = zeros( (6*len(domain),3), Float)
+
+        #print 'keys',self.domain.quantities.keys()
+        #print 'shape of stage',shape(self.stage)
+
+        self.border_model = curve(frame = self.frame,
+                                  pos=[(0,0),(0,1),(1,1),(1,0),(0,0)])
+        self.timer=label(pos=(0.75,0.75,0.5),text='Time=%10.5e'%self.domain.time,
+                         visible=False)
+
+
+        scene.autoscale=0
+        #self.update_all()
+        #scene.uniform=0
+        self.range_z  = 1.0
+        if domain.visualise_range_z == None:
+            self.setup_range_z()
+        else:
+            self.range_z = domain.visualise_range_z
+
+        self.max_z = self.range_z/2.0
+        self.min_z = -self.range_z/2.0
+        self.range_z = max(self.max_z - self.min_z, 1.0e-10)
+
+#        print self.range_z
+#        print self.max_z
+#        print self.min_z
+
+    def setup_range_z(self,qname1='elevation',qname2='stage'):
+
+        #print qname1
+        #print qname2
+        range_z = 1.0e-10
+        try:
+            q1 = self.domain.quantities[qname1].vertex_values
+            max_z = max(max(q1))
+            min_z = min(min(q1))
+            print max_z, min_z
+            range_z = max(range_z, max_z - min_z)
+        except:
+            #print 'Visualisation: could not find range of '+qname1
+            pass
+
+        try:
+            q2 = self.domain.quantities[qname2].vertex_values
+            max_z = max(max(q2))
+            min_z = min(min(q2))
+            print max_z, min_z
+            range_z = max(range_z, max_z - min_z)
+        except:
+            #print 'Visualisation: could not find range of '+qname2
+            pass
+
+        self.range_z = max(range_z,self.range_z)
+
+
+    def setup_all(self):
+
+        self.scene.select()
+
+        for key in ['elevation','stage']:
+            if self.setup[key] | self.updating[key]:
+                self.update_quantity(key)
+
+
+
+    def update_all(self):
+
+        self.scene.select()
+
+        for key in ['elevation','stage']:
+            if self.updating[key]:
+                self.update_quantity(key)
+
+
+    def update_timer(self):
+
+        self.scene.select()
+
+        if self.domain.visualise_timer == True:
+            self.timer.visible = True
+            self.timer.text='Time=%10.5e'%self.domain.time
+
+
+    def update_quantity(self,qname):
+
+        #print 'update '+qname+' arrays'
+        try:
+            qcolor   = self.qcolor[qname]
+            scale_z  = self.scale_z[qname]
+            coloring = self.coloring[qname]
+            updating = self.updating[qname]
+        except:
+            qcolor   = None
+            scale_z  = None
+            coloring = False
+            updating = True
+
+
+        if qcolor is None:
+            qcolor = self.other_color
+
+            if qname=='elevation':
+                qcolor = self.elevation_color
+
+            if qname=='stage':
+                qcolor = self.stage_color
+
+            if qname=='friction':
+                qcolor = self.friction_color
+
+        if scale_z is None:
+            scale_z = self.default_scale_z
+
+        #try:
+        if coloring:
+            self.update_arrays_color(self.domain.quantities[qname].vertex_values, qcolor, scale_z)
+        else:
+            self.update_arrays(self.domain.quantities[qname].vertex_values, qcolor, scale_z)
+
+        #print 'update bed image'
+        if qname=='elevation':
+            self.pos[:,2] = self.pos[:,2]+1.0e-3
+
+        self.vpython_z_models[qname].pos    = self.pos
+        self.vpython_z_models[qname].color  = self.colour
+        self.vpython_z_models[qname].normal = self.normals
+        #except:
+        #    print 'Visualisation: Could not update quantity '+qname
+        #    pass
+
+    def update_quantity_color(self,qname,qcolor=None,scale_z=None):
+
+        #print 'update '+qname+' arrays'
+
+        if qcolor is None:
+            if qname=='elevation':
+                qcolor = self.elevation_color
+
+            if qname=='stage':
+                qcolor = self.stage_color
+
+            if qname=='friction':
+                qcolor = self.friction_color
+
+        if scale_z is None:
+            scale_z = self.scale_z
+
+        #try:
+        self.update_arrays_color(self.domain.quantities[qname].vertex_values, qcolor, scale_z)
+
+            #print 'update bed image'
+        self.vpython_z_models[qname].pos    = self.pos
+        self.vpython_z_models[qname].color  = self.colour
+        self.vpython_z_models[qname].normal = self.normals
+        #except:
+        #    print 'Visualisation: Could not update quantity '+qname
+        #    pass
+
+
+    def update_arrays(self,quantity,qcolor,scale_z):
+
+        col = asarray(qcolor)
+
+        N = len(self.domain)
+
+        min_x = self.min_x
+        min_y = self.min_y
+        range_xy = self.range_xy
+        range_z = self.range_z
+
+        vertices = self.vertices
+        pos      = self.pos
+        normals  = self.normals
+        colour   = self.colour
+
+        try:
+            update_arrays_weave(vertices,quantity,col,pos,normals,colour,N,
+                                min_x,min_y,range_xy,range_z,scale_z)
+        except:
+            update_arrays_python(vertices,quantity,col,pos,normals,colour,N,
+                                 min_x,min_y,range_xy,range_z,scale_z)
+
+
+
+    def update_arrays_color(self,quantity,qcolor,scale_z):
+
+        col = asarray(qcolor)
+
+        N = len(self.domain)
+
+        min_x = self.min_x
+        min_y = self.min_y
+        range_xy = self.range_xy
+        range_z = self.range_z
+
+        vertices = self.vertices
+        pos      = self.pos
+        normals  = self.normals
+        colour   = self.colour
+
+        #try:
+        update_arrays_color_python(vertices,quantity,col,pos,normals,colour,N,
+                                min_x,min_y,range_xy,range_z,scale_z)
+        #except:
+        #    update_arrays_color_python(vertices,quantity,col,pos,normals,colour,N,
+        #                         min_x,min_y,range_xy,range_z,scale_z)
+
+
+#==================================================================================
+
+def  update_arrays_python(vertices,quantity,col,pos,normals,colour,N,
+                          min_x,min_y,range_xy,range_z,scale_z):
+
+    from math import sqrt
+    normal = zeros( 3, Float)
+    v = zeros( (3,3), Float)
+    s = 1.0
+
+    for i in range( N ):
+
+        for j in range(3):
+            v[j,0] = (vertices[i,2*j  ]-min_x)/range_xy
+            v[j,1] = (vertices[i,2*j+1]-min_y)/range_xy
+            v[j,2] = quantity[i,j]/range_z*scale_z*0.5
+
+        v10 = v[1,:]-v[0,:]
+        v20 = v[2,:]-v[0,:]
+
+        normal[0] = v10[1]*v20[2] - v20[1]*v10[2]
+        normal[1] = v10[2]*v20[0] - v20[2]*v10[0]
+        normal[2] = v10[0]*v20[1] - v20[0]*v10[1]
+
+        norm = sqrt( normal[0]**2 + normal[1]**2 + normal[2]**2)
+
+        normal[0] = normal[0]/norm
+        normal[1] = normal[1]/norm
+        normal[2] = normal[2]/norm
+
+        pos[6*i  ,:] = v[0,:]
+        pos[6*i+1,:] = v[1,:]
+        pos[6*i+2,:] = v[2,:]
+        pos[6*i+3,:] = v[0,:]
+        pos[6*i+4,:] = v[2,:]
+        pos[6*i+5,:] = v[1,:]
+
+
+
+        colour[6*i  ,:] = s*col
+        colour[6*i+1,:] = s*col
+        colour[6*i+2,:] = s*col
+        colour[6*i+3,:] = s*col
+        colour[6*i+4,:] = s*col
+        colour[6*i+5,:] = s*col
+
+        s =  15.0/8.0 - s
+
+        normals[6*i  ,:] = normal
+        normals[6*i+1,:] = normal
+        normals[6*i+2,:] = normal
+        normals[6*i+3,:] = -normal
+        normals[6*i+4,:] = -normal
+        normals[6*i+5,:] = -normal
+
+
+
+def  update_arrays_weave(vertices,quantity,col,pos,normals,colour,
+                         N,min_x,min_y,range_xy,range_z,scale_z):
+
+    import weave
+    from weave import converters
+
+    from math import sqrt
+    normal = zeros( 3, Float)
+    v = zeros( (3,3), Float)
+    v10 = zeros( 3, Float)
+    v20 = zeros( 3, Float)
+
+    code1 = """
+
+        double s = 1.0;
+
+        for (int i=0; i<N ; i++ ) {
+            for (int j=0; j<3 ; j++) {
+                v(j,0) = (vertices(i,2*j  )-min_x)/range_xy;
+                v(j,1) = (vertices(i,2*j+1)-min_y)/range_xy;
+                v(j,2) = quantity(i,j)/range_z*scale_z*0.5;
+            }
+
+
+            for (int j=0; j<3; j++) {
+                v10(j) = v(1,j)-v(0,j);
+                v20(j) = v(2,j)-v(0,j);
+            }
+
+            normal(0) = v10(1)*v20(2) - v20(1)*v10(2);
+            normal(1) = v10(2)*v20(0) - v20(2)*v10(0);
+            normal(2) = v10(0)*v20(1) - v20(0)*v10(1);
+
+            double norm =  sqrt(normal(0)*normal(0) + normal(1)*normal(1) + normal(2)*normal(2));
+
+            normal(0) = normal(0)/norm;
+            normal(1) = normal(1)/norm;
+            normal(2) = normal(2)/norm;
+
+
+            for (int j=0; j<3; j++) {
+                pos(6*i  ,j) = v(0,j);
+                pos(6*i+1,j) = v(1,j);
+                pos(6*i+2,j) = v(2,j);
+                pos(6*i+3,j) = v(0,j);
+                pos(6*i+4,j) = v(2,j);
+                pos(6*i+5,j) = v(1,j);
+
+                colour(6*i  ,j) = s*col(j);
+                colour(6*i+1,j) = s*col(j);
+                colour(6*i+2,j) = s*col(j);
+                colour(6*i+3,j) = s*col(j);
+                colour(6*i+4,j) = s*col(j);
+                colour(6*i+5,j) = s*col(j);
+
+                normals(6*i  ,j) = normal(j);
+                normals(6*i+1,j) = normal(j);
+                normals(6*i+2,j) = normal(j);
+                normals(6*i+3,j) = -normal(j);
+                normals(6*i+4,j) = -normal(j);
+                normals(6*i+5,j) = -normal(j);
+                }
+
+            s =  15.0/8.0 - s;
+        }
+
+        """
+
+    weave.inline(code1, ['vertices','quantity','col','pos','normals','colour','N',
+                         'min_x','min_y','range_xy','range_z','scale_z','v','normal','v10','v20'],
+                 type_converters = converters.blitz, compiler='gcc');
+
+def  update_arrays_color_python(vertices,quantity,col,pos,normals,colour,N,
+                          min_x,min_y,range_xy,range_z,scale_z):
+
+    from math import sqrt
+    normal = zeros( 3, Float)
+    v = zeros( (3,3), Float)
+    s = 1.0
+
+    for i in range( N ):
+
+        for j in range(3):
+            v[j,0] = (vertices[i,2*j  ]-min_x)/range_xy
+            v[j,1] = (vertices[i,2*j+1]-min_y)/range_xy
+            v[j,2] = quantity[i,j]/range_z*scale_z*0.5
+
+        v10 = v[1,:]-v[0,:]
+        v20 = v[2,:]-v[0,:]
+
+        normal[0] = v10[1]*v20[2] - v20[1]*v10[2]
+        normal[1] = v10[2]*v20[0] - v20[2]*v10[0]
+        normal[2] = v10[0]*v20[1] - v20[0]*v10[1]
+
+        norm = sqrt( normal[0]**2 + normal[1]**2 + normal[2]**2)
+
+        normal[0] = normal[0]/norm
+        normal[1] = normal[1]/norm
+        normal[2] = normal[2]/norm
+
+        pos[6*i  ,:] = v[0,:]
+        pos[6*i+1,:] = v[1,:]
+        pos[6*i+2,:] = v[2,:]
+        pos[6*i+3,:] = v[0,:]
+        pos[6*i+4,:] = v[2,:]
+        pos[6*i+5,:] = v[1,:]
+
+        q0 = quantity[i,0]/0.4
+        q1 = quantity[i,1]/0.4
+        q2 = quantity[i,2]/0.4
+
+        q0r = min(q0,0.0)
+        q1r = min(q1,0.0)
+        q2r = min(q2,0.0)
+        q0b = max(q0,0.0)
+        q1b = max(q1,0.0)
+        q2b = max(q2,0.0)
+
+
+#        colour[6*i  ,:] = s*array([0.3 - q0r, 0.3 - q0, 0.3 + q0b])
+#        colour[6*i+1,:] = s*array([0.3 - q1r, 0.3 - q1, 0.3 + q1b])
+#        colour[6*i+2,:] = s*array([0.3 - q2r, 0.3 - q2, 0.3 + q2b])
+#        colour[6*i+3,:] = s*array([0.3 - q0r, 0.3 - q0, 0.3 + q0b])
+#        colour[6*i+4,:] = s*array([0.3 - q2r, 0.3 - q2, 0.3 + q2b])
+#        colour[6*i+5,:] = s*array([0.3 - q1r, 0.3 - q1, 0.3 + q1b])
+
+        s = 0.1
+        colour[6*i  ,:] = s*array([0.3 - q0r, 0.3, 0.3 + q0b])
+        colour[6*i+1,:] = s*array([0.3 - q1r, 0.3, 0.3 + q1b])
+        colour[6*i+2,:] = s*array([0.3 - q2r, 0.3, 0.3 + q2b])
+        colour[6*i+3,:] = s*array([0.3 - q0r, 0.3, 0.3 + q0b])
+        colour[6*i+4,:] = s*array([0.3 - q2r, 0.3, 0.3 + q2b])
+        colour[6*i+5,:] = s*array([0.3 - q1r, 0.3, 0.3 + q1b])
+
+
+        s =  15.0/8.0 - s
+
+        normals[6*i  ,:] = normal
+        normals[6*i+1,:] = normal
+        normals[6*i+2,:] = normal
+        normals[6*i+3,:] = -normal
+        normals[6*i+4,:] = -normal
+        normals[6*i+5,:] = -normal
+
+
+
+def  update_arrays_color_weave(vertices,quantity,col,pos,normals,colour,
+                         N,min_x,min_y,range_xy,range_z,scale_z):
+
+    import weave
+    from weave import converters
+
+    from math import sqrt
+    normal = zeros( 3, Float)
+    v = zeros( (3,3), Float)
+    v10 = zeros( 3, Float)
+    v20 = zeros( 3, Float)
+
+    code1 = """
+        double s = 1.0;
+
+        for (int i=0; i<N ; i++ ) {
+            for (int j=0; j<3 ; j++) {
+                v(j,0) = (vertices(i,2*j  )-min_x)/range_xy;
+                v(j,1) = (vertices(i,2*j+1)-min_y)/range_xy;
+                v(j,2) = quantity(i,j)/range_z*scale_z*0.5;
+            }
+
+
+            for (int j=0; j<3; j++) {
+                v10(j) = v(1,j)-v(0,j);
+                v20(j) = v(2,j)-v(0,j);
+            }
+
+            normal(0) = v10(1)*v20(2) - v20(1)*v10(2);
+            normal(1) = v10(2)*v20(0) - v20(2)*v10(0);
+            normal(2) = v10(0)*v20(1) - v20(0)*v10(1);
+
+            double norm =  sqrt(normal(0)*normal(0) + normal(1)*normal(1) + normal(2)*normal(2));
+
+            normal(0) = normal(0)/norm;
+            normal(1) = normal(1)/norm;
+            normal(2) = normal(2)/norm;
+
+
+
+            for (int j=0; j<3; j++) {
+                pos(6*i  ,j) = v(0,j);
+                pos(6*i+1,j) = v(1,j);
+                pos(6*i+2,j) = v(2,j);
+                pos(6*i+3,j) = v(0,j);
+                pos(6*i+4,j) = v(2,j);
+                pos(6*i+5,j) = v(1,j);
+
+                normals(6*i  ,j) = normal(j);
+                normals(6*i+1,j) = normal(j);
+                normals(6*i+2,j) = normal(j);
+                normals(6*i+3,j) = -normal(j);
+                normals(6*i+4,j) = -normal(j);
+                normals(6*i+5,j) = -normal(j);
+                }
+
+            s = 0.2+fabs((v(0,2)+v(1,2)+v(2,2))/3.0);
+            for (int j=0; j<3; j++) {
+                colour(6*i  ,j) = s*col(j);
+                colour(6*i+1,j) = s*col(j);
+                colour(6*i+2,j) = s*col(j);
+                colour(6*i+3,j) = s*col(j);
+                colour(6*i+4,j) = s*col(j);
+                colour(6*i+5,j) = s*col(j);
+                }
+            s =  15.0/8.0 - s;
+        }
+
+        """
+
+    weave.inline(code1, ['vertices','quantity','col','pos','normals','colour','N',
+                         'min_x','min_y','range_xy','range_z','scale_z','v','normal','v10','v20'],
+                 type_converters = converters.blitz, compiler='gcc');
+
+
+def setup_scene():
+
+    #scene.width = 1000
+    #scene.height = 800
+
+    #Original
+    scene.center = (0.5,0.5,0.0)
+    scene.forward = vector(-0.0, 0.5, -0.8)
+
+    #Temporary (for bedslope)
+    #scene.forward = vector(0.0006, 0.7, -0.03)
+
+
+    #Temporary for hackett - begin
+    #scene.autoscale = 0
+    #scene.scale = (0.002, 0.002, 0.01) #Scale z so that countours stand out more
+    #scene.center = (300.0,500.0,-10)
+    #Temporary for hackett - end
+
+
+    scene.ambient = 0.4
+    #scene.lights = [(0.6, 0.3, 0.2), (0.1, -0.5, 0.4), (-0.1, 0.1, -0.4),
+    #               (-0.2, 0.2, 0.1)]
+
+    scene.lights = [(0.6, 0.3, 0.2), (0.1, -0.5, 0.4)]
+
+
+
+def create_surface(domain,scale_z=1.0):
+
+    domain.initialise_visualiser(scale_z)
+
+    domain.visualiser.update_quantity('elevation')
+    domain.visualiser.update_quantity('stage')
+    domain.visualiser.update_timer()
+
+def update(domain):
+
+    if domain.visualise_color_stage:
+        domain.visualiser.update_quantity_color('stage')
+    else:
+        domain.visualiser.update_quantity('stage')
+
+    domain.visualiser.update_timer()
+
+
+
+if __name__ == '__main__':
+
+    from advection import Domain as A_Domain
+    from shallow_water import Domain as SW_Domain
+    from shallow_water import Constant_height, Constant_stage
+    from mesh_factory import rectangular
+
+    points, vertices, boundary = rectangular(60, 60, len1=200, len2=200)
+    a_domain  = A_Domain(points, vertices, boundary)
+    print 'No of Elements' , a_domain.number_of_elements
+    #sw_domain = SW_Domain(points, vertices, boundary)
+    #sw_domain.set_quantity('elevation', Constant_stage(0.0))
+    #sw_domain.set_quantity('stage', Constant_stage(0.0))
+
+    a_domain.initialise_visualiser()
+    a_domain.visualiser.setup_all()
+
+
+    #sw_domain.initialise_visualiser()
+    #sw_domain.visualiser.setup['elevation']=True
+    #sw_domain.visualiser.setup_all()
+
+    time = 0.0
+    while (True):
+        time = time+0.001
+        #print 'Time = ',time
+        #sw_domain.set_quantity('stage', time)
+        a_domain.set_quantity('stage',time)
+
+        #sw_domain.visualiser.update_quantity('stage')
+        a_domain.visualiser.update_quantity('stage')
+
+        if time>1.0 :
+            break
+
+    #a_v = Visualiser(domain=a_domain, title='advection')
+    #a_v.update_all()
+
+
+    #sw_v = Visualiser(domain=sw_domain, title='shallow water')
+    #sw_v.update_all()
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/region.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/region.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/region.py	(revision 3560)
@@ -0,0 +1,148 @@
+"""boundary.py - Classes for implementing region conditions
+
+NOTE: I've only set it up for testing X values of constants and functions.
+Although it should work for vectors/arrays of values, that implies
+knowing info about the actual triangles, and that is not how the user should
+operate.
+"""
+# FIXME (DSG-DSG) add better comments
+
+class Region:
+    """Base class for modifying quantities based on a region.
+    """   
+
+    def __init__(self, location='vertices'):
+        self.location = location
+        
+    def __call__(self, tag, elements, domain):
+        msg = 'Generic class Boundary must be subclassed'
+        raise msg
+
+
+    def build_indices(self, elements, domain):
+        """
+        Return a list of triangle_id or vertex_id, depending on the location
+        """
+        if self.location == 'unique vertices':
+            return domain.get_unique_vertices(elements)
+        else:
+            return elements
+                
+class Set_region(Region):
+    
+    def __init__(self, tag, quantity, X, location='vertices'):
+        """ 
+        name: Name of quantity
+        X: const or function 
+        location: Where values are to be stored.
+        Permissible options are: vertices, centroid
+        """
+        
+        Region.__init__(self)
+        self.tag = tag 
+        self.quantity = quantity
+        self.location = location
+        self.X = X
+
+    def __repr__(self):
+        pass
+    
+    def __call__(self, tag, elements, domain):
+        """
+        """    
+        if tag == self.tag:
+            domain.set_quantity(self.quantity,
+                                self.X,
+                                location=self.location,
+                                indices=self.build_indices(elements, domain))
+
+        
+class Add_value_to_region(Region):
+    """
+    Will add a value to the current quantity value.
+    """
+    
+    def __init__(self, tag, quantity, X, location='vertices', initial_quantity=None):
+        #I have to get this going!
+        #Region.__init__(self)
+        self.tag = tag 
+        self.quantity_answer = quantity
+        self.location = location
+        self.X = X
+        if initial_quantity is None:
+            self.quantity_initial_value = quantity
+        else:
+            self.quantity_initial_value = initial_quantity
+        if callable(X):
+            raise 'This class does not work with functions'  
+
+    def __repr__(self):
+        pass
+    
+    def __call__(self, tag, elements, domain):
+        """
+        """    
+        if tag == self.tag:
+            #new_values = domain.get_quantity(self.quantity_initial_value,
+            #              indices=self.build_indices(elements, domain),
+            #              location=self.location) + self.X
+
+            Q = domain.get_quantity(self.quantity_initial_value)
+            new_values = Q.get_values(indices=self.build_indices(elements, domain),
+                                      location=self.location) + self.X            
+            domain.set_quantity(self.quantity_answer, new_values,
+                                indices=self.build_indices(elements, domain),
+                                location=self.location)
+
+class Add_quantities(Region):
+    """
+    Will add a value to the current quantity value.
+    """
+    
+    def __init__(self, tag, quantity_answer, adding_quantity, location='vertices'):
+        #I have to get this going!
+        #Region.__init__(self)
+        self.tag = tag 
+        self.quantity_answer = quantity_answer
+        self.adding_quantity = adding_quantity
+        self.location = location
+
+    def __repr__(self):
+        pass
+    
+    def __call__(self, tag, elements, domain):
+        """
+        """    
+        if tag == self.tag:
+
+            #new_values = domain.get_quantity(self.quantity_answer,
+            #              indices=self.build_indices(elements, domain),
+            #              location=self.location) \
+            #              + domain.get_quantity(self.adding_quantity,
+            #              indices=self.build_indices(elements, domain),
+            #              location=self.location)
+
+
+
+            indices = self.build_indices(elements, domain)
+            location = self.location
+            Q1 = domain.get_quantity(self.quantity_answer)
+            Q2 = domain.get_quantity(self.adding_quantity)            
+            new_values = Q1.get_values(indices=indices, location=location) +\
+                         Q2.get_values(indices=indices, location=location)
+
+            
+            domain.set_quantity(self.quantity_answer, new_values,
+                                indices=self.build_indices(elements, domain),
+                                location=self.location)
+
+
+class Stage_no_less_than_elevation(Region):
+    """
+    Will set the stage to not be less than the elevation.
+    This would be good, but it's not region dependent.
+    Wait for it to become a default for pyvolution.
+    """
+    
+    def __init__(self):
+        pass
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/run_profile.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/run_profile.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/run_profile.py	(revision 3560)
@@ -0,0 +1,71 @@
+"""Example of shallow water wave equation.
+
+This version is for profiling of timestepping
+"""
+
+######################
+# Module imports
+from shallow_water import Domain, Reflective_boundary
+from mesh_factory import rectangular
+from Numeric import array
+
+
+######################
+# Domain
+
+#N = 16   #Should take less than 0.1 s
+#N = 64  #Should take less than 3s
+N = 128  #Should take less than 20s
+
+
+print 'Creating domain'
+#Create basic mesh
+points, vertices, boundary = rectangular(N, N)
+
+#Create shallow water domain
+domain = Domain(points, vertices, boundary)
+domain.set_default_order(2)        
+domain.set_quantities_to_be_stored(None)
+
+
+print 'Setting initial conditions'
+
+def slope(x, y):
+    return -x
+
+domain.set_quantity('elevation', slope)
+domain.set_quantity('friction', 0.03)
+domain.set_quantity('stage', expression = 'elevation + 0.5')
+
+
+
+print 'Setting boundary conditions'
+Br = Reflective_boundary(domain)
+domain.set_boundary({'left': Br, 'right': Br, 'bottom': Br, 'top': Br})
+
+
+print 'Checking integrity'
+domain.check_integrity()
+
+
+######################
+#Evolution
+
+import time
+t0 = time.time()
+
+s = 'for t in domain.evolve(yieldstep = 0.02, finaltime = 0.2): domain.write_time()'
+
+
+import profile, pstats
+FN = 'profile.dat'
+
+profile.run(s, FN)
+
+print 'That took %.2f seconds' %(time.time()-t0)
+
+S = pstats.Stats(FN)
+#S.sort_stats('time').print_stats(20)
+s = S.sort_stats('cumulative').print_stats(30)
+
+print s
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/run_profile2.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/run_profile2.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/run_profile2.py	(revision 3560)
@@ -0,0 +1,80 @@
+"""Example of shallow water wave equation.
+
+This version is for profiling
+(The original)
+
+
+FIXME: This should really measure something else, such as profiling the set up of domains.
+"""
+
+######################
+# Module imports 
+#
+from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+     Transmissive_boundary, Time_boundary,\
+     Weir_simple as Weir, Constant_height
+
+from mesh_factory import rectangular
+from Numeric import array
+    
+
+######################
+# Domain
+#
+
+N = 128
+
+print 'Creating domain'
+#Create basic mesh
+points, vertices, boundary = rectangular(N, N)
+
+#Create shallow water domain
+domain = Domain(points, vertices, boundary)
+domain.default_order = 2
+domain.set_quantities_to_be_stored(None)
+#domain.visualise = True
+
+
+print 'Field values'
+def slope(x, y):
+    return -x
+    
+domain.set_quantity('elevation', slope)
+domain.set_quantity('friction', 0.3)
+
+
+# Boundary conditions
+#
+Br = Reflective_boundary(domain)
+domain.set_boundary({'left': Br, 'right': Br, 'bottom': Br, 'top': Br})
+
+
+######################
+#Initial condition
+domain.set_quantity('stage', Constant_height(slope, 0.3))
+
+domain.check_integrity()
+ 
+
+######################
+#Evolution
+
+import time
+t0 = time.time()
+
+s = 'for t in domain.evolve(yieldstep = 0.02, finaltime = 0.2): domain.write_time()'
+
+
+
+import profile, pstats
+FN = 'profile.dat'
+
+profile.run(s, FN)
+    
+print 'That took %.2f seconds' %(time.time()-t0)
+
+S = pstats.Stats(FN)
+#S.sort_stats('time').print_stats(20)
+s = S.sort_stats('cumulative').print_stats(30)
+
+print s
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/run_tsh_weir.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/run_tsh_weir.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/run_tsh_weir.py	(revision 3560)
@@ -0,0 +1,99 @@
+"""Example of shallow water wave equation.
+
+Specific methods pertaining to the 2D shallow water equation
+are imported from shallow_water
+for use with the generic finite volume framework
+
+Conserved quantities are h, uh and vh stored as elements 0, 1 and 2 in the
+numerical vector named conserved_quantities.
+"""
+
+######################
+# Module imports 
+#
+from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+     Transmissive_boundary, Time_boundary, Constant_height, Weir
+
+from mesh_factory import rectangular
+from anuga.pyvolution.pmesh2domain import pmesh_to_domain
+
+from Numeric import array
+
+######################
+# Domain
+
+import sys
+if len(sys.argv) > 1: 
+    filename = sys.argv[1]
+else:
+    filename = 'weir_domain_refined.tsh'
+
+print 'Creating domain from', filename
+domain_list = pmesh_to_domain(filename)
+vertex_coordinates = domain_list[0]
+volumes = domain_list[1]
+marker_dict = domain_list[2]
+vertex_quantity_dict = domain_list[3]
+
+domain = Domain(vertex_coordinates, volumes, marker_dict)
+print "Number of triangles = ", len(domain)
+
+domain.store = False #True
+domain.format = 'sww'
+domain.filename = 'weir'
+domain.checkpoint = False #True
+domain.visualise = True #False
+domain.default_order = 2
+
+#Set bed-slope and friction
+inflow_stage = 0.15
+manning = 0.07
+W = Weir(inflow_stage)
+
+print 'Field values'
+
+domain.set_quantity('elevation', W)
+domain.set_quantity('friction', manning)
+
+
+
+######################
+# Boundary conditions
+#
+print 'Boundaries'
+Br = Reflective_boundary(domain)
+Bt = Transmissive_boundary(domain)
+
+#Constant inflow
+Bd = Dirichlet_boundary(array([inflow_stage, 0.0, 0.0]))
+
+#Time dependent inflow
+from math import sin, pi
+Bw = Time_boundary(domain=domain,
+                   f=lambda x: array([(1 + sin(x*pi/4))*\
+                                      (inflow_stage*(sin(2.5*x*pi)+0.7)),0,0]))
+
+
+print 'Available boundary tags are', domain.get_boundary_tags()
+
+#Set boundary conditions
+domain.set_boundary({'left': Bw, '0': Br, '1':Bw, 'external':Br})
+
+
+#print domain.quantities['elevation'].vertex_values
+#print domain.quantities['stage'].vertex_values
+         
+######################
+#Initial condition
+print 'Initial condition'
+domain.set_quantity('stage', Constant_height(W, 0.))
+domain.check_integrity()
+
+######################
+#Evolution
+for t in domain.evolve(yieldstep = 0.01, finaltime = 5):
+    domain.write_time()
+    
+print 'Done'
+
+    
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/shallow_water.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/shallow_water.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/shallow_water.py	(revision 3560)
@@ -0,0 +1,1904 @@
+"""Class Domain -
+2D triangular domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x + G_y = S
+
+where
+
+U = [w, uh, vh]
+E = [uh, u^2h + gh^2/2, uvh]
+G = [vh, uvh, v^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectively.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+y         y                vertical distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+v                          speed in the y direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+vh        ymomentum        momentum in the y direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh, vh
+
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2004
+"""
+
+#Subversion keywords:
+#
+#$LastChangedDate$
+#$LastChangedRevision$
+#$LastChangedBy$
+
+
+from domain import Domain as Generic_Domain
+from generic_boundary_conditions import Boundary
+from generic_boundary_conditions import File_boundary
+from generic_boundary_conditions import Dirichlet_boundary
+from generic_boundary_conditions import Time_boundary
+from generic_boundary_conditions import Transmissive_boundary
+
+from anuga.utilities.numerical_tools import gradient, mean
+from anuga.config import minimum_sww_depth
+
+
+#Shallow water domain
+class Domain(Generic_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,
+                 processor=0,
+                 numproc=1):
+
+
+        conserved_quantities = ['stage', 'xmomentum', 'ymomentum']
+        other_quantities = ['elevation', 'friction']
+        Generic_Domain.__init__(self,
+                                coordinates,
+                                vertices,
+                                boundary,
+                                conserved_quantities,
+                                other_quantities,
+                                tagged_elements,
+                                geo_reference,
+                                use_inscribed_circle,
+                                mesh_filename,
+                                use_cache,
+                                verbose,
+                                full_send_dict,
+                                ghost_recv_dict,
+                                processor,
+                                numproc)
+
+
+        from anuga.config import minimum_allowed_height, maximum_allowed_speed, g
+        self.minimum_allowed_height = minimum_allowed_height
+        self.maximum_allowed_speed = maximum_allowed_speed
+        self.g = g
+
+
+        self.forcing_terms.append(manning_friction)
+        self.forcing_terms.append(gravity)
+
+        #Realtime visualisation
+        self.visualiser = None
+        self.visualise  = False
+        self.visualise_color_stage = False
+        self.visualise_stage_range = 1.0
+        self.visualise_timer = True
+        self.visualise_range_z = None
+
+        #Stored output
+        self.store = True
+        self.format = 'sww'
+        self.set_store_vertices_uniquely(False)
+        self.minimum_sww_depth = minimum_sww_depth
+        self.quantities_to_be_stored = ['stage','xmomentum','ymomentum']
+
+
+    def set_store_vertices_uniquely(self, flag, reduction=None):
+        """Decide whether vertex values should be stored uniquely as
+        computed in the model or whether they should be reduced to one
+        value per vertex using self.reduction.
+        """
+        self.smooth = not flag
+
+        #Reduction operation for get_vertex_values
+        if reduction is None:
+            self.reduction = mean
+            #self.reduction = min  #Looks better near steep slopes
+
+
+    def set_minimum_sww_depth(self, minimum_sww_depth):
+        """
+        Set the minimum depth that will be recognised when writing
+        to an sww file. This is useful for removing thin water layers
+        that seems to be caused by friction creep.
+
+        The minimum allowed sww depth is in meters.
+        """
+        self.minimum_sww_depth = minimum_sww_depth
+
+
+
+    def set_quantities_to_be_stored(self, q):
+        """Specify which quantities will be stored in the sww file.
+
+        q must be either:
+          - the name of a quantity
+          - a list of quantity names
+          - None
+
+        In the two first cases, the named quantities will be stored at each yieldstep
+        (This is in addition to the quantities elevation and friction)
+        If q is None, storage will be switched off altogether.
+        """
+
+
+        if q is None:
+            self.quantities_to_be_stored = []
+            self.store = False
+            return
+
+        if isinstance(q, basestring):
+            q = [q] # Turn argument into a list
+
+        #Check correcness
+        for quantity_name in q:
+            msg = 'Quantity %s is not a valid conserved quantity' %quantity_name
+            assert quantity_name in self.conserved_quantities, msg
+
+        self.quantities_to_be_stored = q
+
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from realtime_visualisation_new import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+            self.visualiser.setup['elevation']=True
+            self.visualiser.updating['stage']=True
+        self.visualise = True
+        if self.visualise_color_stage == True:
+            self.visualiser.coloring['stage'] = True
+            self.visualiser.qcolor['stage'] = (0.0, 0.0, 0.8)
+        print 'initialise visualiser'
+        print self.visualiser.setup
+        print self.visualiser.updating
+
+    def check_integrity(self):
+        Generic_Domain.check_integrity(self)
+
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+        msg = 'Third conserved quantity must be "ymomentum"'
+        assert self.conserved_quantities[2] == 'ymomentum', msg
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+
+
+    #FIXME: Under construction
+#     def set_defaults(self):
+#         """Set default values for uninitialised quantities.
+#         This is specific to the shallow water wave equation
+#         Defaults for 'elevation', 'friction', 'xmomentum' and 'ymomentum'
+#         are 0.0. Default for 'stage' is whatever the value of 'elevation'.
+#         """
+
+#         for name in self.other_quantities + self.conserved_quantities:
+#             print name
+#             print self.quantities.keys()
+#             if not self.quantities.has_key(name):
+#                 if name == 'stage':
+
+#                     if self.quantities.has_key('elevation'):
+#                         z = self.quantities['elevation'].vertex_values
+#                         self.set_quantity(name, z)
+#                     else:
+#                         self.set_quantity(name, 0.0)
+#                 else:
+#                     self.set_quantity(name, 0.0)
+
+
+
+#         #Lift negative heights up
+#         #z = self.quantities['elevation'].vertex_values
+#         #w = self.quantities['stage'].vertex_values
+
+#         #h = w-z
+
+#         #for k in range(h.shape[0]):
+#         #    for i in range(3):
+#         #        if h[k, i] < 0.0:
+#         #            w[k, i] = z[k, i]
+
+
+#         #self.quantities['stage'].interpolate()
+
+
+    def evolve(self,
+               yieldstep = None,
+               finaltime = None,
+               duration = None,
+               skip_initial_step = False):
+        """Specialisation of basic evolve method from parent class
+        """
+
+        #Call check integrity here rather than from user scripts
+        #self.check_integrity()
+
+        msg = 'Parameter beta_h must be in the interval [0, 1['
+        assert 0 <= self.beta_h < 1.0, msg
+        msg = 'Parameter beta_w must be in the interval [0, 1['
+        assert 0 <= self.beta_w < 1.0, msg
+
+
+        #Initial update of vertex and edge values before any storage
+        #and or visualisation
+        self.distribute_to_vertices_and_edges()
+
+        #Initialise real time viz if requested
+        if self.visualise is True and self.time == 0.0:
+            if self.visualiser is None:
+                self.initialise_visualiser()
+
+            self.visualiser.update_timer()
+            self.visualiser.setup_all()
+
+        #Store model data, e.g. for visualisation
+        if self.store is True and self.time == 0.0:
+            self.initialise_storage()
+            #print 'Storing results in ' + self.writer.filename
+        else:
+            pass
+            #print 'Results will not be stored.'
+            #print 'To store results set domain.store = True'
+            #FIXME: Diagnostic output should be controlled by
+            # a 'verbose' flag living in domain (or in a parent class)
+
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self,
+                                       yieldstep=yieldstep,
+                                       finaltime=finaltime,
+                                       duration=duration,
+                                       skip_initial_step=skip_initial_step):
+            #Real time viz
+            if self.visualise is True:
+                self.visualiser.update_all()
+                self.visualiser.update_timer()
+
+
+            #Store model data, e.g. for subsequent visualisation
+            if self.store is True:
+                self.store_timestep(self.quantities_to_be_stored)
+
+            #FIXME: Could maybe be taken from specified list
+            #of 'store every step' quantities
+
+            #Pass control on to outer loop for more specific actions
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x,y and bed elevation
+        """
+
+        from anuga.abstract_2d_finite_volumes.data_manager import get_dataobject
+
+        #Initialise writer
+        self.writer = get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+
+
+
+#Rotation of momentum vector
+def rotate(q, normal, direction = 1):
+    """Rotate the momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector.
+
+    If direction is negative the rotation is inverted.
+
+    Input vector is preserved
+
+    This function is specific to the shallow water wave equation
+    """
+
+    from Numeric import zeros, Float
+
+    assert len(q) == 3,\
+           'Vector of conserved quantities must have length 3'\
+           'for 2D shallow water equation'
+
+    try:
+        l = len(normal)
+    except:
+        raise 'Normal vector must be an Numeric array'
+
+    assert l == 2, 'Normal vector must have 2 components'
+
+
+    n1 = normal[0]
+    n2 = normal[1]
+
+    r = zeros(len(q), Float) #Rotated quantities
+    r[0] = q[0]              #First quantity, height, is not rotated
+
+    if direction == -1:
+        n2 = -n2
+
+
+    r[1] =  n1*q[1] + n2*q[2]
+    r[2] = -n2*q[1] + n1*q[2]
+
+    return r
+
+
+
+####################################
+# Flux computation
+def flux_function(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, vh are stored as elements 0, 1 and 2
+    in the numerical vectors ql and qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from anuga.config import g, epsilon
+    from math import sqrt
+    from Numeric import array
+
+    #Align momentums with x-axis
+    q_left  = rotate(ql, normal, direction = 1)
+    q_right = rotate(qr, normal, direction = 1)
+
+    z = (zl+zr)/2 #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/h_right
+
+    vh_left  = q_left[2]
+    vh_right = q_right[2]
+
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+
+    #Flux computation
+
+    #FIXME(Ole): Why is it again that we don't
+    #use uh_left and uh_right directly in the first entries?
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left**2,
+                        u_left*vh_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right**2,
+                        u_right*vh_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+
+        edgeflux = rotate(edgeflux, normal, direction=-1)
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+
+
+def compute_fluxes(domain):
+    """Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Ymom = domain.quantities['ymomentum']
+    Bed = domain.quantities['elevation']
+
+    #Arrays
+    stage = Stage.edge_values
+    xmom =  Xmom.edge_values
+    ymom =  Ymom.edge_values
+    bed =   Bed.edge_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    ymom_bdry =  Ymom.boundary_values
+
+    flux = zeros(3, Float) #Work array for summing up fluxes
+
+
+    #Loop
+    timestep = float(sys.maxint)
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(3):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i], ymom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr = [stage_bdry[m], xmom_bdry[m], ymom_bdry[m]]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                m = domain.neighbour_edges[k,i]
+                qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, 2*i:2*i+2]
+
+            #Flux computation using provided function
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+            flux -= edgeflux * domain.edgelengths[k,i]
+
+            #Update optimal_timestep on full cells
+            if  domain.tri_full_flag[k] == 1:
+                try:
+                    timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+                except ZeroDivisionError:
+                    pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+        Stage.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k] = flux[1]
+        Ymom.explicit_update[k] = flux[2]
+
+
+    domain.timestep = timestep
+
+#MH090605 The following method belongs to the shallow_water domain class
+#see comments in the corresponding method in shallow_water_ext.c
+def extrapolate_second_order_sw_c(domain):
+    """Wrapper calling C version of extrapolate_second_order_sw
+    """
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Ymom = domain.quantities['ymomentum']
+    from shallow_water_ext import extrapolate_second_order_sw
+    extrapolate_second_order_sw(domain,domain.surrogate_neighbours,
+                                domain.number_of_boundaries,
+                                domain.centroid_coordinates,
+                                Stage.centroid_values,
+                                Xmom.centroid_values,
+                                Ymom.centroid_values,
+                                domain.vertex_coordinates,
+                                Stage.vertex_values,
+                                Xmom.vertex_values,
+                                Ymom.vertex_values)
+
+def compute_fluxes_c(domain):
+    """Wrapper calling C version of compute fluxes
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Ymom = domain.quantities['ymomentum']
+    Bed = domain.quantities['elevation']
+
+    timestep = float(sys.maxint)
+    from shallow_water_ext import compute_fluxes
+    domain.timestep = compute_fluxes(timestep, domain.epsilon, domain.g,
+                                     domain.neighbours,
+                                     domain.neighbour_edges,
+                                     domain.normals,
+                                     domain.edgelengths,
+                                     domain.radii,
+                                     domain.areas,
+                                     domain.tri_full_flag,
+                                     Stage.edge_values,
+                                     Xmom.edge_values,
+                                     Ymom.edge_values,
+                                     Bed.edge_values,
+                                     Stage.boundary_values,
+                                     Xmom.boundary_values,
+                                     Ymom.boundary_values,
+                                     Stage.explicit_update,
+                                     Xmom.explicit_update,
+                                     Ymom.explicit_update,
+                                     domain.already_computed_flux)
+
+
+####################################
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    from anuga.config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    protect_against_infinitesimal_and_negative_heights(domain)
+
+    #Extrapolate all conserved quantities
+    if optimised_gradient_limiter:
+        #MH090605 if second order,
+        #perform the extrapolation and limiting on
+        #all of the conserved quantitie
+
+        if (domain.order == 1):
+            for name in domain.conserved_quantities:
+                Q = domain.quantities[name]
+                Q.extrapolate_first_order()
+        elif domain.order == 2:
+            domain.extrapolate_second_order_sw()
+        else:
+            raise 'Unknown order'
+    else:
+        #old code:
+        for name in domain.conserved_quantities:
+            Q = domain.quantities[name]
+            if domain.order == 1:
+                Q.extrapolate_first_order()
+            elif domain.order == 2:
+                Q.extrapolate_second_order()
+                Q.limit()
+            else:
+                raise 'Unknown order'
+
+
+    #Take bed elevation into account when water heights are small
+    balance_deep_and_shallow(domain)
+
+    #Compute edge values by interpolation
+    for name in domain.conserved_quantities:
+        Q = domain.quantities[name]
+        Q.interpolate_from_vertices_to_edges()
+
+
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+    ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    #Update
+    #FIXME: Modify accroditg to c-version - or discard altogether.
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+
+            #Control momentum
+            xmomc[k] = ymomc[k] = 0.0
+
+
+def protect_against_infinitesimal_and_negative_heights_c(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+    ymomc = domain.quantities['ymomentum'].centroid_values
+
+    from shallow_water_ext import protect
+
+    protect(domain.minimum_allowed_height, domain.maximum_allowed_speed,
+            domain.epsilon, wc, zc, xmomc, ymomc)
+
+
+
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        for i in range(3):
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    for i in range(3):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        for i in range(3):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        for i in range(3):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+
+
+def h_limiter_c(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+
+    Wrapper for c-extension
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv - zv
+
+    #Call C-extension
+    from shallow_water_ext import h_limiter_sw as h_limiter
+    hvbar = h_limiter(domain, hc, hv)
+
+    return hvbar
+
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]),
+                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using the h-limited
+        #stage and alpha==1 means using the w-limited stage as
+        #computed by the gradient limiter (both 1st or 2nd order)
+
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+	#Let
+	#
+	#  wvi be the w-limited stage (wvi = zvi + hvi)
+	#  wvi- be the h-limited state (wvi- = zvi + hvi-)
+	#
+	#
+	#where i=0,1,2 denotes the vertex ids
+	#
+        #Weighted balance between w-limited and h-limited stage is
+        #
+	#  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+	#
+        #It follows that the updated wvi is
+        #  wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+        #
+	# Momentum is balanced between constant and limited
+
+
+        #for i in range(3):
+        #    wv[k,i] = zv[k,i] + hvbar[k,i]
+
+	#return
+
+	if alpha < 1:
+
+            for i in range(3):
+                wv[k,i] = zv[k,i] + (1-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+            ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1-alpha)*xmomc[k] + alpha*xmomv[k,:]
+            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+def balance_deep_and_shallow_c(domain):
+    """Wrapper for C implementation
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv - zv
+
+    #Momentums at centroids
+    xmomc = domain.quantities['xmomentum'].centroid_values
+    ymomc = domain.quantities['ymomentum'].centroid_values
+
+    #Momentums at vertices
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    ymomv = domain.quantities['ymomentum'].vertex_values
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    #This is how one would make a first order h_limited value
+    #as in the old balancer (pre 17 Feb 2005):
+    #from Numeric import zeros, Float
+    #hvbar = zeros( (len(hc), 3), Float)
+    #for i in range(3):
+    #    hvbar[:,i] = hc[:]
+
+    from shallow_water_ext import balance_deep_and_shallow
+    balance_deep_and_shallow(wc, zc, hc, wv, zv, hv, hvbar,
+                             xmomc, ymomc, xmomv, ymomv)
+
+
+
+
+###############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        self.stage   = domain.quantities['stage'].edge_values
+        self.xmom    = domain.quantities['xmomentum'].edge_values
+        self.ymom    = domain.quantities['ymomentum'].edge_values
+        self.normals = domain.normals
+
+        from Numeric import zeros, Float
+        self.conserved_quantities = zeros(3, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+
+        q = self.conserved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = self.xmom[vol_id, edge_id]
+        q[2] = self.ymom[vol_id, edge_id]
+
+        normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
+
+
+        r = rotate(q, normal, direction = 1)
+        r[1] = -r[1]
+        q = rotate(r, normal, direction = -1)
+
+        return q
+
+
+
+class Transmissive_Momentum_Set_Stage_boundary(Boundary):
+    """Returns same momentum conserved quantities as
+    those present in its neighbour volume. Sets stage
+
+    Underlying domain must be specified when boundary is instantiated
+    """
+
+    def __init__(self, domain = None, function=None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for this type boundary'
+            raise msg
+
+        if function is None:
+            msg = 'Function must be specified for this type boundary'
+            raise msg
+
+        self.domain   = domain
+        self.function = function
+
+    def __repr__(self):
+        return 'Transmissive_Momentum_Set_Stage_boundary(%s)' %self.domain
+
+    def evaluate(self, vol_id, edge_id):
+        """Transmissive Momentum Set Stage boundaries return the edge momentum
+        values of the volume they serve.
+        """
+
+        q = self.domain.get_conserved_quantities(vol_id, edge = edge_id)
+        value = self.function(self.domain.time)
+        q[0] = value[0]
+        return q
+
+
+        #FIXME: Consider this (taken from File_boundary) to allow
+        #spatial variation
+        #if vol_id is not None and edge_id is not None:
+        #    i = self.boundary_indices[ vol_id, edge_id ]
+        #    return self.F(t, point_id = i)
+        #else:
+        #    return self.F(t)
+
+
+
+class Dirichlet_Discharge_boundary(Boundary):
+    """
+    Sets stage (stage0)
+    Sets momentum (wh0) in the inward normal direction.
+
+    Underlying domain must be specified when boundary is instantiated
+    """
+
+    def __init__(self, domain = None, stage0=None, wh0=None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for this type boundary'
+            raise msg
+
+        if stage0 is None:
+            raise 'set stage'
+
+        if wh0 is None:
+            wh0 = 0.0
+
+        self.domain   = domain
+        self.stage0  = stage0
+        self.wh0 = wh0
+
+    def __repr__(self):
+        return 'Dirichlet_Discharge_boundary(%s)' %self.domain
+
+    def evaluate(self, vol_id, edge_id):
+        """Set discharge in the (inward) normal direction
+        """
+
+        normal = self.domain.get_normal(vol_id,edge_id)
+        q = [self.stage0, -self.wh0*normal[0], -self.wh0*normal[1]]
+        return q
+
+
+        #FIXME: Consider this (taken from File_boundary) to allow
+        #spatial variation
+        #if vol_id is not None and edge_id is not None:
+        #    i = self.boundary_indices[ vol_id, edge_id ]
+        #    return self.F(t, point_id = i)
+        #else:
+        #    return self.F(t)
+
+
+
+#class Spatio_temporal_boundary(Boundary):
+#    """The spatio-temporal boundary, reads values for the conserved
+#    quantities from an sww NetCDF file, and returns interpolated values
+#    at the midpoints of each associated boundaty segment.
+#    Time dependency is interpolated linearly as in util.File_function.#
+#
+#    Example:
+#    Bf = Spatio_temporal_boundary('source_file.sww', domain)
+#
+#    """
+Spatio_temporal_boundary = File_boundary
+
+
+
+
+#########################
+#Standard forcing terms:
+#
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    h = Stage.edge_values - Elevation.edge_values
+    v = Elevation.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+        avg_h = sum( h[k,:] )/3
+
+        #Compute bed slope
+        x0, y0, x1, y1, x2, y2 = x[k,:]
+        z0, z1, z2 = v[k,:]
+
+        zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+
+        #Update momentum
+        xmom[k] += -g*zx*avg_h
+        ymom[k] += -g*zy*avg_h
+
+
+def gravity_c(domain):
+    """Wrapper calling C version
+    """
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    h = Stage.edge_values - Elevation.edge_values
+    v = Elevation.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+
+    from shallow_water_ext import gravity
+    gravity(g, h, v, x, xmom, ymom)
+
+
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    (Python version)
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	ymom_update[k] += S*vh[k]
+
+
+def manning_friction_implicit_c(domain):
+    """Wrapper for c version
+    """
+
+
+    #print 'Implicit friction'
+
+    xmom = domain.quantities['xmomentum']
+    ymom = domain.quantities['ymomentum']
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+
+    uh = xmom.centroid_values
+    vh = ymom.centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = xmom.semi_implicit_update
+    ymom_update = ymom.semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    from shallow_water_ext import manning_friction
+    manning_friction(g, eps, w, z, uh, vh, eta, xmom_update, ymom_update)
+
+
+def manning_friction_explicit_c(domain):
+    """Wrapper for c version
+    """
+
+    #print 'Explicit friction'
+
+    xmom = domain.quantities['xmomentum']
+    ymom = domain.quantities['ymomentum']
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+
+    uh = xmom.centroid_values
+    vh = ymom.centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = xmom.explicit_update
+    ymom_update = ymom.explicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    from shallow_water_ext import manning_friction
+    manning_friction(g, eps, w, z, uh, vh, eta, xmom_update, ymom_update)
+
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    vh = domain.quantities['ymomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g #Not necessary? Why was this added?
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	ymom_update[k] += S*vh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        N = 3
+        x = ones(3, Float)
+        y = ones(3, Float)
+        try:
+            q = f(1.0, x=x, y=y)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise Exception(msg)
+    return f
+
+
+class Wind_stress:
+    """Apply wind stress to water momentum in terms of
+    wind speed [m/s] and wind direction [degrees]
+    """
+
+    def __init__(self, *args, **kwargs):
+        """Initialise windfield from wind speed s [m/s]
+        and wind direction phi [degrees]
+
+        Inputs v and phi can be either scalars or Python functions, e.g.
+
+        W = Wind_stress(10, 178)
+
+        #FIXME - 'normal' degrees are assumed for now, i.e. the
+        vector (1,0) has zero degrees.
+        We may need to convert from 'compass' degrees later on and also
+        map from True north to grid north.
+
+        Arguments can also be Python functions of t,x,y as in
+
+        def speed(t,x,y):
+            ...
+            return s
+
+        def angle(t,x,y):
+            ...
+            return phi
+
+        where x and y are vectors.
+
+        and then pass the functions in
+
+        W = Wind_stress(speed, angle)
+
+        The instantiated object W can be appended to the list of
+        forcing_terms as in
+
+        Alternatively, one vector valued function for (speed, angle)
+        can be applied, providing both quantities simultaneously.
+        As in
+        W = Wind_stress(F), where returns (speed, angle) for each t.
+
+        domain.forcing_terms.append(W)
+        """
+
+        from anuga.config import rho_a, rho_w, eta_w
+        from Numeric import array, Float
+
+        if len(args) == 2:
+            s = args[0]
+            phi = args[1]
+        elif len(args) == 1:
+            #Assume vector function returning (s, phi)(t,x,y)
+            vector_function = args[0]
+            s = lambda t,x,y: vector_function(t,x=x,y=y)[0]
+            phi = lambda t,x,y: vector_function(t,x=x,y=y)[1]
+        else:
+           #Assume info is in 2 keyword arguments
+
+           if len(kwargs) == 2:
+               s = kwargs['s']
+               phi = kwargs['phi']
+           else:
+               raise 'Assumes two keyword arguments: s=..., phi=....'
+
+        self.speed = check_forcefield(s)
+        self.phi = check_forcefield(phi)
+
+        self.const = eta_w*rho_a/rho_w
+
+
+    def __call__(self, domain):
+        """Evaluate windfield based on values found in domain
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import Float, ones, ArrayType
+
+        xmom_update = domain.quantities['xmomentum'].explicit_update
+        ymom_update = domain.quantities['ymomentum'].explicit_update
+
+        N = domain.number_of_elements
+        t = domain.time
+
+        if callable(self.speed):
+            xc = domain.get_centroid_coordinates()
+            s_vec = self.speed(t, xc[:,0], xc[:,1])
+        else:
+            #Assume s is a scalar
+
+            try:
+                s_vec = self.speed * ones(N, Float)
+            except:
+                msg = 'Speed must be either callable or a scalar: %s' %self.s
+                raise msg
+
+
+        if callable(self.phi):
+            xc = domain.get_centroid_coordinates()
+            phi_vec = self.phi(t, xc[:,0], xc[:,1])
+        else:
+            #Assume phi is a scalar
+
+            try:
+                phi_vec = self.phi * ones(N, Float)
+            except:
+                msg = 'Angle must be either callable or a scalar: %s' %self.phi
+                raise msg
+
+        assign_windfield_values(xmom_update, ymom_update,
+                                s_vec, phi_vec, self.const)
+
+
+def assign_windfield_values(xmom_update, ymom_update,
+                            s_vec, phi_vec, const):
+    """Python version of assigning wind field to update vectors.
+    A c version also exists (for speed)
+    """
+    from math import pi, cos, sin, sqrt
+
+    N = len(s_vec)
+    for k in range(N):
+        s = s_vec[k]
+        phi = phi_vec[k]
+
+        #Convert to radians
+        phi = phi*pi/180
+
+        #Compute velocity vector (u, v)
+        u = s*cos(phi)
+        v = s*sin(phi)
+
+        #Compute wind stress
+        S = const * sqrt(u**2 + v**2)
+        xmom_update[k] += S*u
+        ymom_update[k] += S*v
+
+
+
+##############################
+#OBSOLETE STUFF
+
+def balance_deep_and_shallow_old(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters and stage computed as constant height above bed.
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+    """
+
+    #OBSOLETE
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+
+    #Computed linear combination between constant stages and and
+    #stages parallel to the bed elevation.
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]),
+                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using shallow
+        #first order scheme and alpha==1 means using the stage w as
+        #computed by the gradient limiter (1st or 2nd order)
+        #
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        #Weighted balance between stage parallel to bed elevation
+        #(wvi = zvi + hc) and stage as computed by 1st or 2nd
+	#order gradient limiter
+        #(wvi = zvi + hvi) where i=0,1,2 denotes the vertex ids
+        #
+        #It follows that the updated wvi is
+        #  wvi := (1-alpha)*(zvi+hc) + alpha*(zvi+hvi) =
+        #  zvi + hc + alpha*(hvi - hc)
+        #
+        #Note that hvi = zc+hc-zvi in the first order case (constant).
+
+	if alpha < 1:
+            for i in range(3):
+                wv[k,i] = zv[k,i] + hc[k] + alpha*(hv[k,i]-hc[k])
+
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+            ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1-alpha)*xmomc[k] + alpha*xmomv[k,:]
+            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+
+
+
+###########################
+###########################
+#Geometries
+
+
+#FIXME: Rethink this way of creating values.
+
+
+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):
+        from Numeric import zeros, Float
+        from math import sqrt
+
+        N = len(x)
+        assert N == len(y)
+
+        z = zeros(N, 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.3
+            depth = -1.0
+            #plateaux = -0.9
+            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)
+                    #z[i] = depth-y[i]/5
+                    #z[i] = depth
+                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 x[i] < -0.2 and y < 0.5:
+            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)-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 Weir_simple:
+    """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):
+        from Numeric import zeros, Float
+
+        N = len(x)
+        assert N == len(y)
+
+        z = zeros(N, Float)
+        for i in range(N):
+            z[i] = -x[i]  #General slope
+
+            #Flat bit to the left
+            if x[i] < 0.3:
+                z[i] = -x[i]/10  #General slope
+
+            #Weir
+            if x[i] > 0.3 and x[i] < 0.4:
+                z[i] = -x[i]+0.9
+
+            #Dip
+            if x[i] > 0.6 and x[i] < 0.9:
+                z[i] = -x[i]-0.5  #-y[i]/5
+
+            #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.05
+
+
+        return z/2
+
+
+
+class Constant_stage:
+    """Set an initial condition with constant stage
+    """
+    def __init__(self, s):
+        self.s = s
+
+    def __call__(self, x, y):
+        return self.s
+
+class Constant_height:
+    """Set an initial condition with constant water height, e.g
+    stage s = z+h
+    """
+
+    def __init__(self, W, h):
+        self.W = W
+        self.h = h
+
+    def __call__(self, x, y):
+        if self.W is None:
+            from Numeric import ones, Float
+            return self.h*ones(len(x), Float)
+        else:
+            return self.W(x,y) + self.h
+
+
+
+
+def compute_fluxes_python(domain):
+    """Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Ymom = domain.quantities['ymomentum']
+    Bed = domain.quantities['elevation']
+
+    #Arrays
+    stage = Stage.edge_values
+    xmom =  Xmom.edge_values
+    ymom =  Ymom.edge_values
+    bed =   Bed.edge_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    ymom_bdry =  Ymom.boundary_values
+
+    flux = zeros((N,3), Float) #Work array for summing up fluxes
+
+    #Loop
+    timestep = float(sys.maxint)
+    for k in range(N):
+
+        for i in range(3):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i], ymom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr = [stage_bdry[m], xmom_bdry[m], ymom_bdry[m]]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                m = domain.neighbour_edges[k,i]
+                qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, 2*i:2*i+2]
+
+            #Flux computation using provided function
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+            flux[k,:] = edgeflux
+
+    return flux
+
+
+
+
+
+
+
+##############################################
+#Initialise module
+
+
+from anuga.utilities import compile
+if compile.can_use_C_extension('shallow_water_ext.c'):
+    #Replace python version with c implementations
+
+    from shallow_water_ext import rotate, assign_windfield_values
+    compute_fluxes = compute_fluxes_c
+    extrapolate_second_order_sw=extrapolate_second_order_sw_c
+    gravity = gravity_c
+    manning_friction = manning_friction_implicit_c
+    h_limiter = h_limiter_c
+    balance_deep_and_shallow = balance_deep_and_shallow_c
+    protect_against_infinitesimal_and_negative_heights = protect_against_infinitesimal_and_negative_heights_c
+
+
+    #distribute_to_vertices_and_edges = distribute_to_vertices_and_edges_c #(like MH's)
+
+
+
+#Optimisation with psyco
+from anuga.config import use_psyco
+if use_psyco:
+    try:
+        import psyco
+    except:
+        import os
+        if os.name == 'posix' and os.uname()[4] == 'x86_64':
+            pass
+            #Psyco isn't supported on 64 bit systems, but it doesn't matter
+        else:
+            msg = 'WARNING: psyco (speedup) could not import'+\
+                  ', you may want to consider installing it'
+            print msg
+    else:
+        psyco.bind(Domain.distribute_to_vertices_and_edges)
+        psyco.bind(Domain.compute_fluxes)
+
+if __name__ == "__main__":
+    pass
+
+# Profiling stuff
+import profile
+profiler = profile.Profile()
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/shallow_water_ext.c
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/shallow_water_ext.c	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/shallow_water_ext.c	(revision 3560)
@@ -0,0 +1,1413 @@
+// Python - C extension module for shallow_water.py
+//
+// To compile (Python2.3):
+//  gcc -c domain_ext.c -I/usr/include/python2.3 -o domain_ext.o -Wall -O
+//  gcc -shared domain_ext.o  -o domain_ext.so
+//
+// or use python compile.py
+//
+// See the module shallow_water.py
+//
+//
+// Ole Nielsen, GA 2004
+
+
+#include "Python.h"
+#include "Numeric/arrayobject.h"
+#include "math.h"
+#include <stdio.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 momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector (n1, n2).
+
+    Result is returned in array 3x1 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];  //uh momentum
+  q2 = q[2];  //vh momentum
+
+  //Rotate
+  q[1] =  n1*q1 + n2*q2;
+  q[2] = -n2*q1 + n1*q2;
+
+  return 0;
+}
+
+int find_qmin_and_qmax(double dq0, double dq1, double dq2, double *qmin, double *qmax){
+  //Considering the centroid of an FV triangle and the vertices of its auxiliary triangle, find
+  //qmin=min(q)-qc and qmax=max(q)-qc, where min(q) and max(q) are respectively min and max over the
+  //four values (at the centroid of the FV triangle and the auxiliary triangle vertices),
+  //and qc is the centroid
+  //dq0=q(vertex0)-q(centroid of FV triangle)
+  //dq1=q(vertex1)-q(vertex0)
+  //dq2=q(vertex2)-q(vertex0)
+  if (dq0>=0.0){
+    if (dq1>=dq2){
+      if (dq1>=0.0)
+	*qmax=dq0+dq1;
+      else
+	*qmax=dq0;
+      if ((*qmin=dq0+dq2)<0)
+	;//qmin is already set to correct value
+      else
+	*qmin=0.0;
+    }
+    else{//dq1<dq2
+      if (dq2>0)
+	*qmax=dq0+dq2;
+      else
+	*qmax=dq0;
+      if ((*qmin=dq0+dq1)<0)
+	;//qmin is the correct value
+      else
+	*qmin=0.0;
+    }
+  }
+  else{//dq0<0
+    if (dq1<=dq2){
+      if (dq1<0.0)
+	*qmin=dq0+dq1;
+      else
+	*qmin=dq0;
+      if ((*qmax=dq0+dq2)>0.0)
+	;//qmax is already set to the correct value
+      else
+	*qmax=0.0;
+    }
+    else{//dq1>dq2
+      if (dq2<0.0)
+	*qmin=dq0+dq2;
+      else
+	*qmin=dq0;
+      if ((*qmax=dq0+dq1)>0.0)
+	;//qmax is already set to the correct value
+      else
+	*qmax=0.0;
+    }
+  }
+  return 0;
+}
+
+int limit_gradient(double *dqv, double qmin, double qmax, double beta_w){
+  //given provisional jumps dqv from the FV triangle centroid to its vertices and
+  //jumps qmin (qmax) between the centroid of the FV triangle and the
+  //minimum (maximum) of the values at the centroid of the FV triangle and the auxiliary triangle vertices,
+  //calculate a multiplicative factor phi by which the provisional vertex jumps are to be limited
+  int i;
+  double r=1000.0, r0=1.0, phi=1.0;
+  static double TINY = 1.0e-100;//to avoid machine accuracy problems.
+  //Any provisional jump with magnitude < TINY does not contribute to the limiting process.
+  for (i=0;i<3;i++){
+    if (dqv[i]<-TINY)
+      r0=qmin/dqv[i];
+    if (dqv[i]>TINY)
+      r0=qmax/dqv[i];
+    r=min(r0,r);
+    //
+  }
+  phi=min(r*beta_w,1.0);
+  for (i=0;i<3;i++)
+    dqv[i]=dqv[i]*phi;
+  return 0;
+}
+
+// Computational function for flux computation (using stage w=z+h)
+int flux_function(double *q_left, double *q_right,
+		  double z_left, double z_right,
+		  double n1, double n2,
+		  double epsilon, double g,
+		  double *edgeflux, double *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 w_left, h_left, uh_left, vh_left, u_left;
+  double w_right, h_right, uh_right, vh_right, u_right;
+  double s_min, s_max, soundspeed_left, soundspeed_right;
+  double denom, z;
+  double q_left_copy[3], q_right_copy[3];
+  double flux_right[3], flux_left[3];
+
+  //Copy conserved quantities to protect from modification
+  for (i=0; i<3; i++) {
+    q_left_copy[i] = q_left[i];
+    q_right_copy[i] = q_right[i];
+  }
+
+  //Align x- and y-momentum with x-axis
+  _rotate(q_left_copy, n1, n2);
+  _rotate(q_right_copy, n1, n2);
+
+  z = (z_left+z_right)/2; //Take average of field values
+
+  //Compute speeds in x-direction
+  w_left = q_left_copy[0];              // h+z
+  h_left = w_left-z;
+  uh_left = q_left_copy[1];
+
+  if (h_left < epsilon) {
+    h_left = 0.0;  //Could have been negative
+    u_left = 0.0;
+  } else {
+    u_left = uh_left/h_left;
+  }
+
+  w_right = q_right_copy[0];
+  h_right = w_right-z;
+  uh_right = q_right_copy[1];
+
+  if (h_right < epsilon) {
+    h_right = 0.0; //Could have been negative
+    u_right = 0.0;
+  } else {
+    u_right = uh_right/h_right;
+  }
+
+  //Momentum in y-direction
+  vh_left  = q_left_copy[2];
+  vh_right = q_right_copy[2];
+
+
+  //Maximal and minimal wave speeds
+  soundspeed_left  = sqrt(g*h_left);
+  soundspeed_right = sqrt(g*h_right);
+
+  s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
+  if (s_max < 0.0) s_max = 0.0;
+
+  s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
+  if (s_min > 0.0) s_min = 0.0;
+
+  //Flux formulas
+  flux_left[0] = u_left*h_left;
+  flux_left[1] = u_left*uh_left + 0.5*g*h_left*h_left;
+  flux_left[2] = u_left*vh_left;
+
+  flux_right[0] = u_right*h_right;
+  flux_right[1] = u_right*uh_right + 0.5*g*h_right*h_right;
+  flux_right[2] = u_right*vh_right;
+
+
+  //Flux computation
+  denom = s_max-s_min;
+  if (denom == 0.0) {
+    for (i=0; i<3; i++) edgeflux[i] = 0.0;
+    *max_speed = 0.0;
+  } else {
+    for (i=0; i<3; i++) {
+      edgeflux[i] = s_max*flux_left[i] - s_min*flux_right[i];
+      edgeflux[i] += s_max*s_min*(q_right_copy[i]-q_left_copy[i]);
+      edgeflux[i] /= denom;
+    }
+
+    //Maximal wavespeed
+    *max_speed = max(fabs(s_max), fabs(s_min));
+
+    //Rotate back
+    _rotate(edgeflux, n1, -n2);
+  }
+  return 0;
+}
+
+void _manning_friction(double g, double eps, int N,
+		       double* w, double* z,
+		       double* uh, double* vh,
+		       double* eta, double* xmom, double* ymom) {
+
+  int k;
+  double S, h;
+
+  for (k=0; k<N; k++) {
+    if (eta[k] > eps) {
+      h = w[k]-z[k];
+      if (h >= eps) {
+        S = -g * eta[k]*eta[k] * sqrt((uh[k]*uh[k] + vh[k]*vh[k]));
+        S /= pow(h, 7.0/3);      //Expensive (on Ole's home computer)
+        //S /= exp(7.0/3.0*log(h));      //seems to save about 15% over manning_friction
+        //S /= h*h*(1 + h/3.0 - h*h/9.0); //FIXME: Could use a Taylor expansion
+
+
+        //Update momentum
+        xmom[k] += S*uh[k];
+        ymom[k] += S*vh[k];
+      }
+    }
+  }
+}
+
+
+/*
+void _manning_friction_explicit(double g, double eps, int N,
+		       double* w, double* z,
+		       double* uh, double* vh,
+		       double* eta, double* xmom, double* ymom) {
+
+  int k;
+  double S, h;
+
+  for (k=0; k<N; k++) {
+    if (eta[k] > eps) {
+      h = w[k]-z[k];
+      if (h >= eps) {
+	S = -g * eta[k]*eta[k] * sqrt((uh[k]*uh[k] + vh[k]*vh[k]));
+	S /= pow(h, 7.0/3);      //Expensive (on Ole's home computer)
+	//S /= exp(7.0/3.0*log(h));      //seems to save about 15% over manning_friction
+	//S /= h*h*(1 + h/3.0 - h*h/9.0); //FIXME: Could use a Taylor expansion
+
+
+	//Update momentum
+	xmom[k] += S*uh[k];
+	ymom[k] += S*vh[k];
+      }
+    }
+  }
+}
+*/
+
+int _balance_deep_and_shallow(int N,
+			      double* wc,
+			      double* zc,
+			      double* hc,
+			      double* wv,
+			      double* zv,
+			      double* hv,
+			      double* hvbar,
+			      double* xmomc,
+			      double* ymomc,
+			      double* xmomv,
+			      double* ymomv) {
+
+  int k, k3, i;
+  double dz, hmin, alpha;
+
+  //Compute linear combination between w-limited stages and
+  //h-limited stages close to the bed elevation.
+
+  for (k=0; k<N; k++) {
+    // Compute maximal variation in bed elevation
+    // This quantitiy is
+    //     dz = max_i abs(z_i - z_c)
+    // and it is independent of dimension
+    // In the 1d case zc = (z0+z1)/2
+    // In the 2d case zc = (z0+z1+z2)/3
+
+    k3 = 3*k;
+
+    //FIXME: Try with this one precomputed
+    dz = 0.0;
+    hmin = hv[k3];
+    for (i=0; i<3; i++) {
+      dz = max(dz, fabs(zv[k3+i]-zc[k]));
+      hmin = min(hmin, hv[k3+i]);
+    }
+
+
+    //Create alpha in [0,1], where alpha==0 means using the h-limited
+    //stage and alpha==1 means using the w-limited stage as
+    //computed by the gradient limiter (both 1st or 2nd order)
+    //
+    //If hmin > dz/2 then alpha = 1 and the bed will have no effect
+    //If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+
+    if (dz > 0.0)
+      //if (hmin<0.0)
+      //	alpha = 0.0;
+      //else
+      //  alpha = max( min( hc[k]/dz, 1.0), 0.0 );
+      alpha = max( min( 2.0*hmin/dz, 1.0), 0.0 );
+    else
+      alpha = 1.0;  //Flat bed
+
+
+    //printf("dz = %.3f, alpha = %.8f\n", dz, alpha);
+
+    //	Let
+    //
+    //	  wvi be the w-limited stage (wvi = zvi + hvi)
+    //	  wvi- be the h-limited state (wvi- = zvi + hvi-)
+    //
+    //
+    //	where i=0,1,2 denotes the vertex ids
+    //
+    //  Weighted balance between w-limited and h-limited stage is
+    //
+    //	  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+    //
+    //  It follows that the updated wvi is
+    //    wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+    //
+    //	 Momentum is balanced between constant and limited
+
+    if (alpha < 1) {
+      for (i=0; i<3; i++) {
+         wv[k3+i] = zv[k3+i] + (1-alpha)*hvbar[k3+i] + alpha*hv[k3+i];
+
+	//Update momentum as a linear combination of
+	//xmomc and ymomc (shallow) and momentum
+	//from extrapolator xmomv and ymomv (deep).
+	xmomv[k3+i] = (1-alpha)*xmomc[k] + alpha*xmomv[k3+i];
+	ymomv[k3+i] = (1-alpha)*ymomc[k] + alpha*ymomv[k3+i];
+      }
+    }
+  }
+  return 0;
+}
+
+
+
+int _protect(int N,
+	     double minimum_allowed_height,
+	     double maximum_allowed_speed,
+	     double epsilon,
+	     double* wc,
+	     double* zc,
+	     double* xmomc,
+	     double* ymomc) {
+
+  int k;
+  double hc;
+  double u, v, reduced_speed;
+
+  //Protect against initesimal and negative heights
+  for (k=0; k<N; k++) {
+    hc = wc[k] - zc[k];
+
+    if (hc < minimum_allowed_height) {
+
+      //Old code: Set momentum to zero and ensure h is non negative
+      //xmomc[k] = 0.0;
+      //ymomc[k] = 0.0;
+      //if (hc <= 0.0) wc[k] = zc[k];
+
+
+      //New code: Adjust momentum to guarantee speeds are physical
+      //          ensure h is non negative
+      //FIXME (Ole): This is only implemented in this C extension and
+      //             has no Python equivalent
+      if (hc <= 0.0) {
+	wc[k] = zc[k];
+	xmomc[k] = 0.0;
+	ymomc[k] = 0.0;
+      } else {
+        //Reduce excessive speeds derived from division by small hc
+        u = xmomc[k]/hc;
+	if (fabs(u) > maximum_allowed_speed) {
+	  reduced_speed = maximum_allowed_speed * u/fabs(u);
+	  //printf("Speed (u) has been reduced from %.3f to %.3f\n",
+	  //	 u, reduced_speed);
+	  xmomc[k] = reduced_speed * hc;
+	}
+
+        v = ymomc[k]/hc;
+	if (fabs(v) > maximum_allowed_speed) {
+	  reduced_speed = maximum_allowed_speed * v/fabs(v);
+	  //printf("Speed (v) has been reduced from %.3f to %.3f\n",
+	  //	 v, reduced_speed);
+	  ymomc[k] = reduced_speed * hc;
+	}
+      }
+    }
+  }
+  return 0;
+}
+
+
+
+
+int _assign_wind_field_values(int N,
+			      double* xmom_update,
+			      double* ymom_update,
+			      double* s_vec,
+			      double* phi_vec,
+			      double cw) {
+
+  //Assign windfield values to momentum updates
+
+  int k;
+  double S, s, phi, u, v;
+
+  for (k=0; k<N; k++) {
+
+    s = s_vec[k];
+    phi = phi_vec[k];
+
+    //Convert to radians
+    phi = phi*pi/180;
+
+    //Compute velocity vector (u, v)
+    u = s*cos(phi);
+    v = s*sin(phi);
+
+    //Compute wind stress
+    S = cw * sqrt(u*u + v*v);
+    xmom_update[k] += S*u;
+    ymom_update[k] += S*v;
+  }
+  return 0;
+}
+
+
+
+///////////////////////////////////////////////////////////////////
+// Gateways to Python
+
+PyObject *gravity(PyObject *self, PyObject *args) {
+  //
+  //  gravity(g, h, v, x, xmom, ymom)
+  //
+
+
+  PyArrayObject *h, *v, *x, *xmom, *ymom;
+  int k, i, N, k3, k6;
+  double g, avg_h, zx, zy;
+  double x0, y0, x1, y1, x2, y2, z0, z1, z2;
+
+  if (!PyArg_ParseTuple(args, "dOOOOO",
+			&g, &h, &v, &x,
+			&xmom, &ymom))
+    return NULL;
+
+  N = h -> dimensions[0];
+  for (k=0; k<N; k++) {
+    k3 = 3*k;  // base index
+    k6 = 6*k;  // base index
+
+    avg_h = 0.0;
+    for (i=0; i<3; i++) {
+      avg_h += ((double *) h -> data)[k3+i];
+    }
+    avg_h /= 3;
+
+
+    //Compute bed slope
+    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];
+
+
+    z0 = ((double*) v -> data)[k3 + 0];
+    z1 = ((double*) v -> data)[k3 + 1];
+    z2 = ((double*) v -> data)[k3 + 2];
+
+    _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy);
+
+    //Update momentum
+    ((double*) xmom -> data)[k] += -g*zx*avg_h;
+    ((double*) ymom -> data)[k] += -g*zy*avg_h;
+  }
+
+  return Py_BuildValue("");
+}
+
+
+PyObject *manning_friction(PyObject *self, PyObject *args) {
+  //
+  // manning_friction(g, eps, h, uh, vh, eta, xmom_update, ymom_update)
+  //
+
+
+  PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom;
+  int N;
+  double g, eps;
+
+  if (!PyArg_ParseTuple(args, "ddOOOOOOO",
+			&g, &eps, &w, &z, &uh, &vh, &eta,
+			&xmom, &ymom))
+    return NULL;
+
+  N = w -> dimensions[0];
+  _manning_friction(g, eps, N,
+		    (double*) w -> data,
+		    (double*) z -> data,
+		    (double*) uh -> data,
+		    (double*) vh -> data,
+		    (double*) eta -> data,
+		    (double*) xmom -> data,
+		    (double*) ymom -> data);
+
+  return Py_BuildValue("");
+}
+
+
+/*
+PyObject *manning_friction_explicit(PyObject *self, PyObject *args) {
+  //
+  // manning_friction_explicit(g, eps, h, uh, vh, eta, xmom_update, ymom_update)
+  //
+
+
+  PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom;
+  int N;
+  double g, eps;
+
+  if (!PyArg_ParseTuple(args, "ddOOOOOOO",
+			&g, &eps, &w, &z, &uh, &vh, &eta,
+			&xmom, &ymom))
+    return NULL;
+
+  N = w -> dimensions[0];
+  _manning_friction_explicit(g, eps, N,
+		    (double*) w -> data,
+		    (double*) z -> data,
+		    (double*) uh -> data,
+		    (double*) vh -> data,
+		    (double*) eta -> data,
+		    (double*) xmom -> data,
+		    (double*) ymom -> data);
+
+  return Py_BuildValue("");
+}
+*/
+
+PyObject *extrapolate_second_order_sw(PyObject *self, PyObject *args) {
+  /*Compute the vertex values based on a linear reconstruction on each triangle
+    These values are calculated as follows:
+    1) For each triangle not adjacent to a boundary, we consider the auxiliary triangle
+    formed by the centroids of its three neighbours.
+    2) For each conserved quantity, we integrate around the auxiliary triangle's boundary the product
+    of the quantity and the outward normal vector. Dividing by the triangle area gives (a,b), the average
+    of the vector (q_x,q_y) on the auxiliary triangle. We suppose that the linear reconstruction on the
+    original triangle has gradient (a,b).
+    3) Provisional vertex junmps dqv[0,1,2] are computed and these are then limited by calling the functions
+    find_qmin_and_qmax and limit_gradient
+
+    Python call:
+    extrapolate_second_order_sw(domain.surrogate_neighbours,
+                                domain.number_of_boundaries
+                                domain.centroid_coordinates,
+                                Stage.centroid_values
+                                Xmom.centroid_values
+                                Ymom.centroid_values
+                                domain.vertex_coordinates,
+                                Stage.vertex_values,
+                                Xmom.vertex_values,
+                                Ymom.vertex_values)
+
+    Post conditions:
+            The vertices of each triangle have values from a limited linear reconstruction
+	    based on centroid values
+
+  */
+  PyArrayObject *surrogate_neighbours,
+    *number_of_boundaries,
+    *centroid_coordinates,
+    *stage_centroid_values,
+    *xmom_centroid_values,
+    *ymom_centroid_values,
+    *vertex_coordinates,
+    *stage_vertex_values,
+    *xmom_vertex_values,
+    *ymom_vertex_values;
+  PyObject *domain, *Tmp;
+  //Local variables
+  double a, b;//gradient vector, not stored but used to calculate vertex values from centroids
+  int number_of_elements,k,k0,k1,k2,k3,k6,coord_index,i;
+  double x,y,x0,y0,x1,y1,x2,y2,xv0,yv0,xv1,yv1,xv2,yv2;//vertices of the auxiliary triangle
+  double dx1,dx2,dy1,dy2,dxv0,dxv1,dxv2,dyv0,dyv1,dyv2,dq0,dq1,dq2,area2;
+  double dqv[3], qmin, qmax, beta_w;//provisional jumps from centroids to v'tices and safety factor re limiting
+  //by which these jumps are limited
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "OOOOOOOOOOO",
+			&domain,
+			&surrogate_neighbours,
+			&number_of_boundaries,
+			&centroid_coordinates,
+			&stage_centroid_values,
+			&xmom_centroid_values,
+			&ymom_centroid_values,
+			&vertex_coordinates,
+			&stage_vertex_values,
+			&xmom_vertex_values,
+			&ymom_vertex_values)) {
+    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
+    return NULL;
+  }
+
+  //get the safety factor beta_w, set in the config.py file. This is used in the limiting process
+  Tmp = PyObject_GetAttrString(domain, "beta_w");
+  if (!Tmp)
+    return NULL;
+  beta_w = PyFloat_AsDouble(Tmp);
+  Py_DECREF(Tmp);
+  number_of_elements = stage_centroid_values -> dimensions[0];
+  for (k=0; k<number_of_elements; k++) {
+    k3=k*3;
+    k6=k*6;
+
+    if (((long *) number_of_boundaries->data)[k]==3){/*no neighbours, set gradient on the triangle to zero*/
+      ((double *) stage_vertex_values->data)[k3]=((double *)stage_centroid_values->data)[k];
+      ((double *) stage_vertex_values->data)[k3+1]=((double *)stage_centroid_values->data)[k];
+      ((double *) stage_vertex_values->data)[k3+2]=((double *)stage_centroid_values->data)[k];
+      ((double *) xmom_vertex_values->data)[k3]=((double *)xmom_centroid_values->data)[k];
+      ((double *) xmom_vertex_values->data)[k3+1]=((double *)xmom_centroid_values->data)[k];
+      ((double *) xmom_vertex_values->data)[k3+2]=((double *)xmom_centroid_values->data)[k];
+      ((double *) ymom_vertex_values->data)[k3]=((double *)ymom_centroid_values->data)[k];
+      ((double *) ymom_vertex_values->data)[k3+1]=((double *)ymom_centroid_values->data)[k];
+      ((double *) ymom_vertex_values->data)[k3+2]=((double *)ymom_centroid_values->data)[k];
+      continue;
+    }
+    else {//we will need centroid coordinates and vertex coordinates of the triangle
+      //get the vertex coordinates of the FV triangle
+      xv0=((double *)vertex_coordinates->data)[k6]; yv0=((double *)vertex_coordinates->data)[k6+1];
+      xv1=((double *)vertex_coordinates->data)[k6+2]; yv1=((double *)vertex_coordinates->data)[k6+3];
+      xv2=((double *)vertex_coordinates->data)[k6+4]; yv2=((double *)vertex_coordinates->data)[k6+5];
+      //get the centroid coordinates of the FV triangle
+      coord_index=2*k;
+      x=((double *)centroid_coordinates->data)[coord_index];
+      y=((double *)centroid_coordinates->data)[coord_index+1];
+      //store x- and y- differentials for the vertices of the FV triangle relative to the centroid
+      dxv0=xv0-x; dxv1=xv1-x; dxv2=xv2-x;
+      dyv0=yv0-y; dyv1=yv1-y; dyv2=yv2-y;
+    }
+    if (((long *)number_of_boundaries->data)[k]<=1){
+      //if no boundaries, auxiliary triangle is formed from the centroids of the three neighbours
+      //if one boundary, auxiliary triangle is formed from this centroid and its two neighbours
+      k0=((long *)surrogate_neighbours->data)[k3];
+      k1=((long *)surrogate_neighbours->data)[k3+1];
+      k2=((long *)surrogate_neighbours->data)[k3+2];
+      //get the auxiliary triangle's vertex coordinates (really the centroids of neighbouring triangles)
+      coord_index=2*k0;
+      x0=((double *)centroid_coordinates->data)[coord_index];
+      y0=((double *)centroid_coordinates->data)[coord_index+1];
+      coord_index=2*k1;
+      x1=((double *)centroid_coordinates->data)[coord_index];
+      y1=((double *)centroid_coordinates->data)[coord_index+1];
+      coord_index=2*k2;
+      x2=((double *)centroid_coordinates->data)[coord_index];
+      y2=((double *)centroid_coordinates->data)[coord_index+1];
+      //store x- and y- differentials for the vertices of the auxiliary triangle
+      dx1=x1-x0; dx2=x2-x0;
+      dy1=y1-y0; dy2=y2-y0;
+      //calculate 2*area of the auxiliary triangle
+      area2 = dy2*dx1 - dy1*dx2;//the triangle is guaranteed to be counter-clockwise
+      //If the mesh is 'weird' near the boundary, the trianlge might be flat or clockwise:
+      if (area2<=0)
+	return NULL;
+
+      //### stage ###
+      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
+      dq0=((double *)stage_centroid_values->data)[k0]-((double *)stage_centroid_values->data)[k];
+      //calculate differentials between the vertices of the auxiliary triangle
+      dq1=((double *)stage_centroid_values->data)[k1]-((double *)stage_centroid_values->data)[k0];
+      dq2=((double *)stage_centroid_values->data)[k2]-((double *)stage_centroid_values->data)[k0];
+      //calculate the gradient of stage on the auxiliary triangle
+      a = dy2*dq1 - dy1*dq2;
+      a /= area2;
+      b = dx1*dq2 - dx2*dq1;
+      b /= area2;
+      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
+      dqv[0]=a*dxv0+b*dyv0;
+      dqv[1]=a*dxv1+b*dyv1;
+      dqv[2]=a*dxv2+b*dyv2;
+      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
+      //and compute jumps from the centroid to the min and max
+      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
+      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
+      for (i=0;i<3;i++)
+	((double *)stage_vertex_values->data)[k3+i]=((double *)stage_centroid_values->data)[k]+dqv[i];
+
+      //### xmom ###
+      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
+      dq0=((double *)xmom_centroid_values->data)[k0]-((double *)xmom_centroid_values->data)[k];
+      //calculate differentials between the vertices of the auxiliary triangle
+      dq1=((double *)xmom_centroid_values->data)[k1]-((double *)xmom_centroid_values->data)[k0];
+      dq2=((double *)xmom_centroid_values->data)[k2]-((double *)xmom_centroid_values->data)[k0];
+      //calculate the gradient of xmom on the auxiliary triangle
+      a = dy2*dq1 - dy1*dq2;
+      a /= area2;
+      b = dx1*dq2 - dx2*dq1;
+      b /= area2;
+      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
+      dqv[0]=a*dxv0+b*dyv0;
+      dqv[1]=a*dxv1+b*dyv1;
+      dqv[2]=a*dxv2+b*dyv2;
+      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
+      //and compute jumps from the centroid to the min and max
+      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
+      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
+      for (i=0;i<3;i++)
+	((double *)xmom_vertex_values->data)[k3+i]=((double *)xmom_centroid_values->data)[k]+dqv[i];
+
+      //### ymom ###
+      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
+      dq0=((double *)ymom_centroid_values->data)[k0]-((double *)ymom_centroid_values->data)[k];
+      //calculate differentials between the vertices of the auxiliary triangle
+      dq1=((double *)ymom_centroid_values->data)[k1]-((double *)ymom_centroid_values->data)[k0];
+      dq2=((double *)ymom_centroid_values->data)[k2]-((double *)ymom_centroid_values->data)[k0];
+      //calculate the gradient of xmom on the auxiliary triangle
+      a = dy2*dq1 - dy1*dq2;
+      a /= area2;
+      b = dx1*dq2 - dx2*dq1;
+      b /= area2;
+      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
+      dqv[0]=a*dxv0+b*dyv0;
+      dqv[1]=a*dxv1+b*dyv1;
+      dqv[2]=a*dxv2+b*dyv2;
+      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
+      //and compute jumps from the centroid to the min and max
+      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
+      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
+      for (i=0;i<3;i++)
+	((double *)ymom_vertex_values->data)[k3+i]=((double *)ymom_centroid_values->data)[k]+dqv[i];
+    }//if (number_of_boundaries[k]<=1)
+    else{//number_of_boundaries==2
+      //one internal neighbour and gradient is in direction of the neighbour's centroid
+      //find the only internal neighbour
+      for (k2=k3;k2<k3+3;k2++){//k2 just indexes the edges of triangle k
+	if (((long *)surrogate_neighbours->data)[k2]!=k)//find internal neighbour of triabngle k
+	  break;
+      }
+      if ((k2==k3+3))//if we didn't find an internal neighbour
+	return NULL;//error
+      k1=((long *)surrogate_neighbours->data)[k2];
+      //the coordinates of the triangle are already (x,y). Get centroid of the neighbour (x1,y1)
+      coord_index=2*k1;
+      x1=((double *)centroid_coordinates->data)[coord_index];
+      y1=((double *)centroid_coordinates->data)[coord_index+1];
+      //compute x- and y- distances between the centroid of the FV triangle and that of its neighbour
+      dx1=x1-x; dy1=y1-y;
+      //set area2 as the square of the distance
+      area2=dx1*dx1+dy1*dy1;
+      //set dx2=(x1-x0)/((x1-x0)^2+(y1-y0)^2) and dy2=(y1-y0)/((x1-x0)^2+(y1-y0)^2) which
+      //respectively correspond to the x- and y- gradients of the conserved quantities
+      dx2=1.0/area2;
+      dy2=dx2*dy1;
+      dx2*=dx1;
+
+      //## stage ###
+      //compute differentials
+      dq1=((double *)stage_centroid_values->data)[k1]-((double *)stage_centroid_values->data)[k];
+      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
+      a=dq1*dx2;
+      b=dq1*dy2;
+      //calculate provisional vertex jumps, to be limited
+      dqv[0]=a*dxv0+b*dyv0;
+      dqv[1]=a*dxv1+b*dyv1;
+      dqv[2]=a*dxv2+b*dyv2;
+      //now limit the jumps
+      if (dq1>=0.0){
+	qmin=0.0;
+	qmax=dq1;
+      }
+      else{
+	qmin=dq1;
+	qmax=0.0;
+      }
+      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
+      for (i=0;i<3;i++)
+	((double *)stage_vertex_values->data)[k3+i]=((double *)stage_centroid_values->data)[k]+dqv[i];
+
+      //## xmom ###
+      //compute differentials
+      dq1=((double *)xmom_centroid_values->data)[k1]-((double *)xmom_centroid_values->data)[k];
+      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
+      a=dq1*dx2;
+      b=dq1*dy2;
+      //calculate provisional vertex jumps, to be limited
+      dqv[0]=a*dxv0+b*dyv0;
+      dqv[1]=a*dxv1+b*dyv1;
+      dqv[2]=a*dxv2+b*dyv2;
+      //now limit the jumps
+      if (dq1>=0.0){
+	qmin=0.0;
+	qmax=dq1;
+      }
+      else{
+	qmin=dq1;
+	qmax=0.0;
+      }
+      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
+      for (i=0;i<3;i++)
+	((double *)xmom_vertex_values->data)[k3+i]=((double *)xmom_centroid_values->data)[k]+dqv[i];
+
+      //## ymom ###
+      //compute differentials
+      dq1=((double *)ymom_centroid_values->data)[k1]-((double *)ymom_centroid_values->data)[k];
+      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
+      a=dq1*dx2;
+      b=dq1*dy2;
+      //calculate provisional vertex jumps, to be limited
+      dqv[0]=a*dxv0+b*dyv0;
+      dqv[1]=a*dxv1+b*dyv1;
+      dqv[2]=a*dxv2+b*dyv2;
+      //now limit the jumps
+      if (dq1>=0.0){
+	qmin=0.0;
+	qmax=dq1;
+      }
+      else{
+	qmin=dq1;
+	qmax=0.0;
+      }
+      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
+      for (i=0;i<3;i++)
+	((double *)ymom_vertex_values->data)[k3+i]=((double *)ymom_centroid_values->data)[k]+dqv[i];
+    }//else [number_of_boudaries==2]
+  }//for k=0 to number_of_elements-1
+  return Py_BuildValue("");
+}//extrapolate_second-order_sw
+
+PyObject *rotate(PyObject *self, PyObject *args, PyObject *kwargs) {
+  //
+  // r = rotate(q, normal, direction=1)
+  //
+  // Where q is assumed to be a Float numeric array of length 3 and
+  // normal a Float numeric array of length 2.
+
+
+  PyObject *Q, *Normal;
+  PyArrayObject *q, *r, *normal;
+
+  static char *argnames[] = {"q", "normal", "direction", NULL};
+  int dimensions[1], i, direction=1;
+  double n1, n2;
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames,
+				   &Q, &Normal, &direction))
+    return NULL;
+
+  //Input checks (convert sequences into numeric arrays)
+  q = (PyArrayObject *)
+    PyArray_ContiguousFromObject(Q, PyArray_DOUBLE, 0, 0);
+  normal = (PyArrayObject *)
+    PyArray_ContiguousFromObject(Normal, PyArray_DOUBLE, 0, 0);
+
+
+  if (normal -> dimensions[0] != 2) {
+    PyErr_SetString(PyExc_RuntimeError, "Normal vector must have 2 components");
+    return NULL;
+  }
+
+  //Allocate space for return vector r (don't DECREF)
+  dimensions[0] = 3;
+  r = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
+
+  //Copy
+  for (i=0; i<3; i++) {
+    ((double *) (r -> data))[i] = ((double *) (q -> data))[i];
+  }
+
+  //Get normal and direction
+  n1 = ((double *) normal -> data)[0];
+  n2 = ((double *) normal -> data)[1];
+  if (direction == -1) n2 = -n2;
+
+  //Rotate
+  _rotate((double *) r -> data, n1, n2);
+
+  //Release numeric arrays
+  Py_DECREF(q);
+  Py_DECREF(normal);
+
+  //return result using PyArray to avoid memory leak
+  return PyArray_Return(r);
+}
+
+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"
+
+    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:
+    domain.timestep = compute_fluxes(timestep,
+                                     domain.epsilon,
+                                     domain.g,
+                                     domain.neighbours,
+                                     domain.neighbour_edges,
+                                     domain.normals,
+                                     domain.edgelengths,
+                                     domain.radii,
+                                     domain.areas,
+                                     Stage.edge_values,
+                                     Xmom.edge_values,
+                                     Ymom.edge_values,
+                                     Bed.edge_values,
+                                     Stage.boundary_values,
+                                     Xmom.boundary_values,
+                                     Ymom.boundary_values,
+                                     Stage.explicit_update,
+                                     Xmom.explicit_update,
+                                     Ymom.explicit_update,
+                                     already_computed_flux)
+
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+
+
+  */
+
+
+  PyArrayObject *neighbours, *neighbour_edges,
+    *normals, *edgelengths, *radii, *areas,
+    *tri_full_flag,
+    *stage_edge_values,
+    *xmom_edge_values,
+    *ymom_edge_values,
+    *bed_edge_values,
+    *stage_boundary_values,
+    *xmom_boundary_values,
+    *ymom_boundary_values,
+    *stage_explicit_update,
+    *xmom_explicit_update,
+    *ymom_explicit_update,
+    *already_computed_flux;//tracks whether the flux across an edge has already been computed
+
+
+  //Local variables
+  double timestep, max_speed, epsilon, g;
+  double normal[2], ql[3], qr[3], zl, zr;
+  double edgeflux[3]; //Work arrays for summing up fluxes
+
+  int number_of_elements, k, i, m, n;
+  int ki, nm=0, ki2; //Index shorthands
+  static long call=1;
+
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOOOOOOOO",
+			&timestep,
+			&epsilon,
+			&g,
+			&neighbours,
+			&neighbour_edges,
+			&normals,
+			&edgelengths, &radii, &areas,
+			&tri_full_flag,
+			&stage_edge_values,
+			&xmom_edge_values,
+			&ymom_edge_values,
+			&bed_edge_values,
+			&stage_boundary_values,
+			&xmom_boundary_values,
+			&ymom_boundary_values,
+			&stage_explicit_update,
+			&xmom_explicit_update,
+			&ymom_explicit_update,
+			&already_computed_flux)) {
+    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
+    return NULL;
+  }
+  number_of_elements = stage_edge_values -> dimensions[0];
+  call++;//a static local variable to which already_computed_flux is compared
+  //set explicit_update to zero for all conserved_quantities.
+  //This assumes compute_fluxes called before forcing terms
+  for (k=0; k<number_of_elements; k++) {
+    ((double *) stage_explicit_update -> data)[k]=0.0;
+    ((double *) xmom_explicit_update -> data)[k]=0.0;
+    ((double *) ymom_explicit_update -> data)[k]=0.0;
+  }
+  //Loop through neighbours and compute edge flux for each
+  for (k=0; k<number_of_elements; k++) {
+    for (i=0; i<3; i++) {
+      ki = k*3+i;
+      if (((long *) already_computed_flux->data)[ki]==call)//we've already computed the flux across this edge
+	continue;
+      ql[0] = ((double *) stage_edge_values -> data)[ki];
+      ql[1] = ((double *) xmom_edge_values -> data)[ki];
+      ql[2] = ((double *) ymom_edge_values -> data)[ki];
+      zl =    ((double *) bed_edge_values -> data)[ki];
+
+      //Quantities at neighbour on nearest face
+      n = ((long *) neighbours -> data)[ki];
+      if (n < 0) {
+	m = -n-1; //Convert negative flag to index
+	qr[0] = ((double *) stage_boundary_values -> data)[m];
+	qr[1] = ((double *) xmom_boundary_values -> data)[m];
+	qr[2] = ((double *) ymom_boundary_values -> data)[m];
+	zr = zl; //Extend bed elevation to boundary
+      } else {
+	m = ((long *) neighbour_edges -> data)[ki];
+	nm = n*3+m;
+	qr[0] = ((double *) stage_edge_values -> data)[nm];
+	qr[1] = ((double *) xmom_edge_values -> data)[nm];
+	qr[2] = ((double *) ymom_edge_values -> data)[nm];
+	zr =    ((double *) bed_edge_values -> data)[nm];
+      }
+      // Outward pointing normal vector
+      // normal = domain.normals[k, 2*i:2*i+2]
+      ki2 = 2*ki; //k*6 + i*2
+      normal[0] = ((double *) normals -> data)[ki2];
+      normal[1] = ((double *) normals -> data)[ki2+1];
+      //Edge flux computation
+      flux_function(ql, qr, zl, zr,
+		    normal[0], normal[1],
+		    epsilon, g,
+		    edgeflux, &max_speed);
+      //update triangle k
+      ((long *) already_computed_flux->data)[ki]=call;
+      ((double *) stage_explicit_update -> data)[k] -= edgeflux[0]*((double *) edgelengths -> data)[ki];
+      ((double *) xmom_explicit_update -> data)[k] -= edgeflux[1]*((double *) edgelengths -> data)[ki];
+      ((double *) ymom_explicit_update -> data)[k] -= edgeflux[2]*((double *) edgelengths -> data)[ki];
+      //update the neighbour n
+      if (n>=0){
+	((long *) already_computed_flux->data)[nm]=call;
+	((double *) stage_explicit_update -> data)[n] += edgeflux[0]*((double *) edgelengths -> data)[nm];
+	((double *) xmom_explicit_update -> data)[n] += edgeflux[1]*((double *) edgelengths -> data)[nm];
+	((double *) ymom_explicit_update -> data)[n] += edgeflux[2]*((double *) edgelengths -> data)[nm];
+      }
+      ///for (j=0; j<3; j++) {
+	///flux[j] -= edgeflux[j]*((double *) edgelengths -> data)[ki];
+	///}
+	//Update timestep
+	//timestep = min(timestep, domain.radii[k]/max_speed)
+	//FIXME: SR Add parameter for CFL condition
+    if ( ((long *) tri_full_flag -> data)[k] == 1) {
+	    if (max_speed > epsilon) {
+	        timestep = min(timestep, ((double *) radii -> data)[k]/max_speed);
+	        //maxspeed in flux_function is calculated as max(|u+a|,|u-a|)
+	        if (n>=0)
+	            timestep = min(timestep, ((double *) radii -> data)[n]/max_speed);
+	    }
+    }
+    } // end for i
+    //Normalise by area and store for when all conserved
+    //quantities get updated
+    ((double *) stage_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
+    ((double *) xmom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
+    ((double *) ymom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
+  } //end for k
+  return Py_BuildValue("d", timestep);
+}
+
+PyObject *protect(PyObject *self, PyObject *args) {
+  //
+  //    protect(minimum_allowed_height, maximum_allowed_speed, wc, zc, xmomc, ymomc)
+
+
+  PyArrayObject
+  *wc,            //Stage at centroids
+  *zc,            //Elevation at centroids
+  *xmomc,         //Momentums at centroids
+  *ymomc;
+
+
+  int N;
+  double minimum_allowed_height, maximum_allowed_speed, epsilon;
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "dddOOOO",
+			&minimum_allowed_height,
+			&maximum_allowed_speed,
+			&epsilon,
+			&wc, &zc, &xmomc, &ymomc))
+    return NULL;
+
+  N = wc -> dimensions[0];
+
+  _protect(N,
+	   minimum_allowed_height,
+	   maximum_allowed_speed,
+	   epsilon,
+	   (double*) wc -> data,
+	   (double*) zc -> data,
+	   (double*) xmomc -> data,
+	   (double*) ymomc -> data);
+
+  return Py_BuildValue("");
+}
+
+
+
+PyObject *balance_deep_and_shallow(PyObject *self, PyObject *args) {
+  //
+  //    balance_deep_and_shallow(wc, zc, hc, wv, zv, hv,
+  //                             xmomc, ymomc, xmomv, ymomv)
+
+
+  PyArrayObject
+    *wc,            //Stage at centroids
+    *zc,            //Elevation at centroids
+    *hc,            //Height at centroids
+    *wv,            //Stage at vertices
+    *zv,            //Elevation at vertices
+    *hv,            //Depths at vertices
+    *hvbar,         //h-Limited depths at vertices
+    *xmomc,         //Momentums at centroids and vertices
+    *ymomc,
+    *xmomv,
+    *ymomv;
+
+  int N; //, err;
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "OOOOOOOOOOO",
+			&wc, &zc, &hc,
+			&wv, &zv, &hv, &hvbar,
+			&xmomc, &ymomc, &xmomv, &ymomv))
+    return NULL;
+
+  N = wc -> dimensions[0];
+
+  _balance_deep_and_shallow(N,
+			    (double*) wc -> data,
+			    (double*) zc -> data,
+			    (double*) hc -> data,
+			    (double*) wv -> data,
+			    (double*) zv -> data,
+			    (double*) hv -> data,
+			    (double*) hvbar -> data,
+                            (double*) xmomc -> data,
+			    (double*) ymomc -> data,
+			    (double*) xmomv -> data,
+			    (double*) ymomv -> data);
+
+
+  return Py_BuildValue("");
+}
+
+
+
+PyObject *h_limiter(PyObject *self, PyObject *args) {
+
+  PyObject *domain, *Tmp;
+  PyArrayObject
+    *hv, *hc, //Depth at vertices and centroids
+    *hvbar,   //Limited depth at vertices (return values)
+    *neighbours;
+
+  int k, i, n, N, k3;
+  int dimensions[2];
+  double beta_h; //Safety factor (see config.py)
+  double *hmin, *hmax, hn;
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv))
+    return NULL;
+
+  neighbours = get_consecutive_array(domain, "neighbours");
+
+  //Get safety factor beta_h
+  Tmp = PyObject_GetAttrString(domain, "beta_h");
+  if (!Tmp)
+    return NULL;
+
+  beta_h = PyFloat_AsDouble(Tmp);
+
+  Py_DECREF(Tmp);
+
+  N = hc -> dimensions[0];
+
+  //Create hvbar
+  dimensions[0] = N;
+  dimensions[1] = 3;
+  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
+
+
+  //Find min and max of this and neighbour's centroid values
+  hmin = malloc(N * sizeof(double));
+  hmax = malloc(N * sizeof(double));
+  for (k=0; k<N; k++) {
+    k3=k*3;
+
+    hmin[k] = ((double*) hc -> data)[k];
+    hmax[k] = hmin[k];
+
+    for (i=0; i<3; i++) {
+      n = ((long*) neighbours -> data)[k3+i];
+
+      //Initialise hvbar with values from hv
+      ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i];
+
+      if (n >= 0) {
+	hn = ((double*) hc -> data)[n]; //Neighbour's centroid value
+
+	hmin[k] = min(hmin[k], hn);
+	hmax[k] = max(hmax[k], hn);
+      }
+    }
+  }
+
+  // Call underlying standard routine
+  _limit(N, beta_h, (double*) hc -> data, (double*) hvbar -> data, hmin, hmax);
+
+  // // //Py_DECREF(domain); //FIXME: NEcessary?
+  free(hmin);
+  free(hmax);
+
+  //return result using PyArray to avoid memory leak
+  return PyArray_Return(hvbar);
+  //return Py_BuildValue("");
+}
+
+PyObject *h_limiter_sw(PyObject *self, PyObject *args) {
+  //a faster version of h_limiter above
+  PyObject *domain, *Tmp;
+  PyArrayObject
+    *hv, *hc, //Depth at vertices and centroids
+    *hvbar,   //Limited depth at vertices (return values)
+    *neighbours;
+
+  int k, i, N, k3,k0,k1,k2;
+  int dimensions[2];
+  double beta_h; //Safety factor (see config.py)
+  double hmin, hmax, dh[3];
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv))
+    return NULL;
+  neighbours = get_consecutive_array(domain, "neighbours");
+
+  //Get safety factor beta_h
+  Tmp = PyObject_GetAttrString(domain, "beta_h");
+  if (!Tmp)
+    return NULL;
+  beta_h = PyFloat_AsDouble(Tmp);
+
+  Py_DECREF(Tmp);
+
+  N = hc -> dimensions[0];
+
+  //Create hvbar
+  dimensions[0] = N;
+  dimensions[1] = 3;
+  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
+  for (k=0;k<N;k++){
+    k3=k*3;
+    //get the ids of the neighbours
+    k0 = ((long*) neighbours -> data)[k3];
+    k1 = ((long*) neighbours -> data)[k3+1];
+    k2 = ((long*) neighbours -> data)[k3+2];
+    //set hvbar provisionally
+    for (i=0;i<3;i++){
+      ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i];
+      dh[i]=((double*) hvbar -> data)[k3+i]-((double*) hc -> data)[k];
+    }
+    hmin=((double*) hc -> data)[k];
+    hmax=hmin;
+    if (k0>=0){
+      hmin=min(hmin,((double*) hc -> data)[k0]);
+      hmax=max(hmax,((double*) hc -> data)[k0]);
+    }
+    if (k1>=0){
+      hmin=min(hmin,((double*) hc -> data)[k1]);
+      hmax=max(hmax,((double*) hc -> data)[k1]);
+    }
+    if (k2>=0){
+      hmin=min(hmin,((double*) hc -> data)[k2]);
+      hmax=max(hmax,((double*) hc -> data)[k2]);
+    }
+    hmin-=((double*) hc -> data)[k];
+    hmax-=((double*) hc -> data)[k];
+    limit_gradient(dh,hmin,hmax,beta_h);
+    for (i=0;i<3;i++)
+      ((double*) hvbar -> data)[k3+i] = ((double*) hc -> data)[k]+dh[i];
+  }
+  return PyArray_Return(hvbar);
+}
+
+PyObject *assign_windfield_values(PyObject *self, PyObject *args) {
+  //
+  //      assign_windfield_values(xmom_update, ymom_update,
+  //                              s_vec, phi_vec, self.const)
+
+
+
+  PyArrayObject   //(one element per triangle)
+  *s_vec,         //Speeds
+  *phi_vec,       //Bearings
+  *xmom_update,   //Momentum updates
+  *ymom_update;
+
+
+  int N;
+  double cw;
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "OOOOd",
+			&xmom_update,
+			&ymom_update,
+			&s_vec, &phi_vec,
+			&cw))
+    return NULL;
+
+  N = xmom_update -> dimensions[0];
+
+  _assign_wind_field_values(N,
+	   (double*) xmom_update -> data,
+	   (double*) ymom_update -> data,
+	   (double*) s_vec -> data,
+	   (double*) phi_vec -> data,
+	   cw);
+
+  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.
+   */
+
+  {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
+  {"extrapolate_second_order_sw", extrapolate_second_order_sw, METH_VARARGS, "Print out"},
+  {"compute_fluxes", compute_fluxes, METH_VARARGS, "Print out"},
+  {"gravity", gravity, METH_VARARGS, "Print out"},
+  {"manning_friction", manning_friction, METH_VARARGS, "Print out"},
+  {"balance_deep_and_shallow", balance_deep_and_shallow,
+   METH_VARARGS, "Print out"},
+  {"h_limiter", h_limiter,
+   METH_VARARGS, "Print out"},
+  {"h_limiter_sw", h_limiter_sw,
+   METH_VARARGS, "Print out"},
+  {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"},
+  {"assign_windfield_values", assign_windfield_values,
+   METH_VARARGS | METH_KEYWORDS, "Print out"},
+  //{"distribute_to_vertices_and_edges",
+  // distribute_to_vertices_and_edges, METH_VARARGS},
+  //{"update_conserved_quantities",
+  // update_conserved_quantities, METH_VARARGS},
+  //{"set_initialcondition",
+  // set_initialcondition, METH_VARARGS},
+  {NULL, NULL}
+};
+
+// Module initialisation
+void initshallow_water_ext(void){
+  Py_InitModule("shallow_water_ext", MethodTable);
+
+  import_array();     //Necessary for handling of NumPY structures
+}
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/shallow_water_kinetic.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/shallow_water_kinetic.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/shallow_water_kinetic.py	(revision 3560)
@@ -0,0 +1,1815 @@
+"""Class Domain -
+2D triangular domains for finite-volume computations of
+the shallow water wave equation.
+
+This module contains a specialisation of class Domain from module domain.py
+consisting of methods specific to the Shallow Water Wave Equation
+
+
+U_t + E_x + G_y = S
+
+where
+
+U = [w, uh, vh]
+E = [uh, u^2h + gh^2/2, uvh]
+G = [vh, uvh, v^2h + gh^2/2]
+S represents source terms forcing the system
+(e.g. gravity, friction, wind stress, ...)
+
+and _t, _x, _y denote the derivative with respect to t, x and y respectively.
+
+The quantities are
+
+symbol    variable name    explanation
+x         x                horizontal distance from origin [m]
+y         y                vertical distance from origin [m]
+z         elevation        elevation of bed on which flow is modelled [m]
+h         height           water height above z [m]
+w         stage            absolute water level, w = z+h [m]
+u                          speed in the x direction [m/s]
+v                          speed in the y direction [m/s]
+uh        xmomentum        momentum in the x direction [m^2/s]
+vh        ymomentum        momentum in the y direction [m^2/s]
+
+eta                        mannings friction coefficient [to appear]
+nu                         wind stress coefficient [to appear]
+
+The conserved quantities are w, uh, vh
+
+
+For details see e.g.
+Christopher Zoppou and Stephen Roberts,
+Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
+Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
+
+
+Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
+Geoscience Australia, 2004
+"""
+
+#Subversion keywords:
+#
+#$LastChangedDate: 2006-01-13 16:43:01 +1100 (Fri, 13 Jan 2006) $
+#$LastChangedRevision: 2206 $
+#$LastChangedBy: steve $
+
+
+from domain import *
+from region import *
+
+Generic_Domain = Domain #Rename
+
+#Shallow water domain
+class Domain(Generic_Domain):
+
+    def __init__(self, coordinates, vertices, boundary = None,
+                 tagged_elements = None, geo_reference = None,
+                 use_inscribed_circle=False):
+
+        conserved_quantities = ['stage', 'xmomentum', 'ymomentum']
+        other_quantities = ['elevation', 'friction']
+        Generic_Domain.__init__(self, coordinates, vertices, boundary,
+                                conserved_quantities, other_quantities,
+                                tagged_elements, geo_reference, use_inscribed_circle)
+
+        from anuga.config import minimum_allowed_height, g
+        self.minimum_allowed_height = minimum_allowed_height
+        self.g = g
+
+        self.forcing_terms.append(gravity)
+        self.forcing_terms.append(manning_friction)
+
+        #Realtime visualisation
+        self.visualiser = None
+        self.visualise  = False
+        self.visualise_color_stage = False
+        self.visualise_stage_range = 1.0
+        self.visualise_timer = True
+        self.visualise_range_z = None
+
+        #Stored output
+        self.store = False
+        self.format = 'sww'
+        self.smooth = True
+
+        #Reduction operation for get_vertex_values
+        from anuga.pyvolution.util import mean
+        self.reduction = mean
+        #self.reduction = min  #Looks better near steep slopes
+
+        self.quantities_to_be_stored = ['stage','xmomentum','ymomentum']
+
+
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from realtime_visualisation_new import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+            self.visualiser.setup['elevation']=True
+            self.visualiser.updating['stage']=True
+        self.visualise = True
+        if self.visualise_color_stage == True:
+            self.visualiser.coloring['stage'] = True
+            self.visualiser.qcolor['stage'] = (0.0, 0.0, 0.8)
+        print 'initialise visualiser'
+        print self.visualiser.setup
+        print self.visualiser.updating
+
+    def check_integrity(self):
+        Generic_Domain.check_integrity(self)
+
+        #Check that we are solving the shallow water wave equation
+
+        msg = 'First conserved quantity must be "stage"'
+        assert self.conserved_quantities[0] == 'stage', msg
+        msg = 'Second conserved quantity must be "xmomentum"'
+        assert self.conserved_quantities[1] == 'xmomentum', msg
+        msg = 'Third conserved quantity must be "ymomentum"'
+        assert self.conserved_quantities[2] == 'ymomentum', msg
+
+    def extrapolate_second_order_sw(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        extrapolate_second_order_sw(self)
+
+    def compute_fluxes(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        compute_fluxes(self)
+
+    def distribute_to_vertices_and_edges(self):
+        #Call correct module function
+        #(either from this module or C-extension)
+        distribute_to_vertices_and_edges(self)
+
+
+    #FIXME: Under construction
+#     def set_defaults(self):
+#         """Set default values for uninitialised quantities.
+#         This is specific to the shallow water wave equation
+#         Defaults for 'elevation', 'friction', 'xmomentum' and 'ymomentum'
+#         are 0.0. Default for 'stage' is whatever the value of 'elevation'.
+#         """
+
+#         for name in self.other_quantities + self.conserved_quantities:
+#             print name
+#             print self.quantities.keys()
+#             if not self.quantities.has_key(name):
+#                 if name == 'stage':
+
+#                     if self.quantities.has_key('elevation'):
+#                         z = self.quantities['elevation'].vertex_values
+#                         self.set_quantity(name, z)
+#                     else:
+#                         self.set_quantity(name, 0.0)
+#                 else:
+#                     self.set_quantity(name, 0.0)
+
+
+
+#         #Lift negative heights up
+#         #z = self.quantities['elevation'].vertex_values
+#         #w = self.quantities['stage'].vertex_values
+
+#         #h = w-z
+
+#         #for k in range(h.shape[0]):
+#         #    for i in range(3):
+#         #        if h[k, i] < 0.0:
+#         #            w[k, i] = z[k, i]
+
+
+#         #self.quantities['stage'].interpolate()
+
+
+    def evolve(self, yieldstep = None, finaltime = None,
+               skip_initial_step = False):
+        """Specialisation of basic evolve method from parent class
+        """
+
+        #Call check integrity here rather than from user scripts
+        #self.check_integrity()
+
+        msg = 'Parameter beta_h must be in the interval [0, 1['
+        assert 0 <= self.beta_h < 1.0, msg
+        msg = 'Parameter beta_w must be in the interval [0, 1['
+        assert 0 <= self.beta_w < 1.0, msg
+
+
+        #Initial update of vertex and edge values before any storage
+        #and or visualisation
+        self.distribute_to_vertices_and_edges()
+
+        #Initialise real time viz if requested
+        if self.visualise is True and self.time == 0.0:
+            if self.visualiser is None:
+                self.initialise_visualiser()
+
+            self.visualiser.update_timer()
+            self.visualiser.setup_all()
+
+        #Store model data, e.g. for visualisation
+        if self.store is True and self.time == 0.0:
+            self.initialise_storage()
+            #print 'Storing results in ' + self.writer.filename
+        else:
+            pass
+            #print 'Results will not be stored.'
+            #print 'To store results set domain.store = True'
+            #FIXME: Diagnostic output should be controlled by
+            # a 'verbose' flag living in domain (or in a parent class)
+
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self, yieldstep, finaltime,
+                                       skip_initial_step):
+            #Real time viz
+            if self.visualise is True:
+                self.visualiser.update_all()
+                self.visualiser.update_timer()
+
+
+            #Store model data, e.g. for subsequent visualisation
+            if self.store is True:
+                self.store_timestep(self.quantities_to_be_stored)
+
+            #FIXME: Could maybe be taken from specified list
+            #of 'store every step' quantities
+
+            #Pass control on to outer loop for more specific actions
+            yield(t)
+
+    def initialise_storage(self):
+        """Create and initialise self.writer object for storing data.
+        Also, save x,y and bed elevation
+        """
+
+        import anuga.pyvolution.data_manager
+
+        #Initialise writer
+        self.writer = data_manager.get_dataobject(self, mode = 'w')
+
+        #Store vertices and connectivity
+        self.writer.store_connectivity()
+
+
+    def store_timestep(self, name):
+        """Store named quantity and time.
+
+        Precondition:
+           self.write has been initialised
+        """
+        self.writer.store_timestep(name)
+
+
+#=============== End of Shallow Water Domain ===============================
+
+
+
+#Rotation of momentum vector
+def rotate(q, normal, direction = 1):
+    """Rotate the momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector.
+
+    If direction is negative the rotation is inverted.
+
+    Input vector is preserved
+
+    This function is specific to the shallow water wave equation
+    """
+
+    from Numeric import zeros, Float
+
+    assert len(q) == 3,\
+           'Vector of conserved quantities must have length 3'\
+           'for 2D shallow water equation'
+
+    try:
+        l = len(normal)
+    except:
+        raise 'Normal vector must be an Numeric array'
+
+    assert l == 2, 'Normal vector must have 2 components'
+
+
+    n1 = normal[0]
+    n2 = normal[1]
+
+    r = zeros(len(q), Float) #Rotated quantities
+    r[0] = q[0]              #First quantity, height, is not rotated
+
+    if direction == -1:
+        n2 = -n2
+
+
+    r[1] =  n1*q[1] + n2*q[2]
+    r[2] = -n2*q[1] + n1*q[2]
+
+    return r
+
+
+
+####################################
+# Flux computation
+def flux_function_central(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
+    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
+    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
+
+    The implemented formula is given in equation (3.15) on page 714
+
+    Conserved quantities w, uh, vh are stored as elements 0, 1 and 2
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from anuga.config import g, epsilon
+    from math import sqrt
+    from Numeric import array
+
+
+    #Align momentums with x-axis
+    q_left  = rotate(ql, normal, direction = 1)
+    q_right = rotate(qr, normal, direction = 1)
+
+    z = (zl+zr)/2 #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/h_right
+
+    vh_left  = q_left[2]
+    vh_right = q_right[2]
+
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+
+    #Flux computation
+
+    #FIXME(Ole): Why is it again that we don't
+    #use uh_left and uh_right directly in the first entries?
+    flux_left  = array([u_left*h_left,
+                        u_left*uh_left + 0.5*g*h_left**2,
+                        u_left*vh_left])
+    flux_right = array([u_right*h_right,
+                        u_right*uh_right + 0.5*g*h_right**2,
+                        u_right*vh_right])
+
+    denom = s_max-s_min
+    if denom == 0.0:
+        edgeflux = array([0.0, 0.0, 0.0])
+        max_speed = 0.0
+    else:
+        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
+        edgeflux += s_max*s_min*(q_right-q_left)/denom
+
+        edgeflux = rotate(edgeflux, normal, direction=-1)
+        max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+
+
+def erfcc(x):
+
+    from math import fabs, exp
+
+    z=fabs(x)
+    t=1.0/(1.0+0.5*z)
+    result=t*exp(-z*z-1.26551223+t*(1.00002368+t*(.37409196+
+         t*(.09678418+t*(-.18628806+t*(.27886807+t*(-1.13520398+
+         t*(1.48851587+t*(-.82215223+t*.17087277)))))))))
+    if x < 0.0:
+        result = 2.0-result
+
+    return result
+
+def flux_function_kinetic(normal, ql, qr, zl, zr):
+    """Compute fluxes between volumes for the shallow water wave equation
+    cast in terms of w = h+z using the 'central scheme' as described in
+
+    Zhang et. al., Advances in Water Resources, 26(6), 2003, 635-647.
+
+
+    Conserved quantities w, uh, vh are stored as elements 0, 1 and 2
+    in the numerical vectors ql an qr.
+
+    Bed elevations zl and zr.
+    """
+
+    from anuga.config import g, epsilon
+    from math import sqrt
+    from Numeric import array
+
+    #Align momentums with x-axis
+    q_left  = rotate(ql, normal, direction = 1)
+    q_right = rotate(qr, normal, direction = 1)
+
+    z = (zl+zr)/2 #Take average of field values
+
+    w_left  = q_left[0]   #w=h+z
+    h_left  = w_left-z
+    uh_left = q_left[1]
+
+    if h_left < epsilon:
+        u_left = 0.0  #Could have been negative
+        h_left = 0.0
+    else:
+        u_left  = uh_left/h_left
+
+
+    w_right  = q_right[0]  #w=h+z
+    h_right  = w_right-z
+    uh_right = q_right[1]
+
+
+    if h_right < epsilon:
+        u_right = 0.0  #Could have been negative
+        h_right = 0.0
+    else:
+        u_right  = uh_right/h_right
+
+    vh_left  = q_left[2]
+    vh_right = q_right[2]
+
+    soundspeed_left  = sqrt(g*h_left)
+    soundspeed_right = sqrt(g*h_right)
+
+    #Maximal wave speed
+    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
+
+    #Minimal wave speed
+    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
+
+    #Flux computation
+
+    F_left  = 0.0
+    F_right = 0.0
+    from math import sqrt, pi, exp
+    if h_left > 0.0:
+        F_left = u_left/sqrt(g*h_left)
+    if h_right > 0.0:
+        F_right = u_right/sqrt(g*h_right)
+
+    edgeflux = array([0.0, 0.0, 0.0])
+
+    edgeflux[0] = h_left*u_left/2.0*erfcc(-F_left) +  \
+          h_left*sqrt(g*h_left)/2.0/sqrt(pi)*exp(-(F_left**2)) + \
+          h_right*u_right/2.0*erfcc(F_right) -  \
+          h_right*sqrt(g*h_right)/2.0/sqrt(pi)*exp(-(F_right**2))
+
+    edgeflux[1] = (h_left*u_left**2 + g/2.0*h_left**2)/2.0*erfcc(-F_left) + \
+          u_left*h_left*sqrt(g*h_left)/2.0/sqrt(pi)*exp(-(F_left**2)) + \
+          (h_right*u_right**2 + g/2.0*h_right**2)/2.0*erfcc(F_right) -  \
+          u_right*h_right*sqrt(g*h_right)/2.0/sqrt(pi)*exp(-(F_right**2))
+
+    edgeflux[2] = vh_left*u_left/2.0*erfcc(-F_left) + \
+          vh_left*sqrt(g*h_left)/2.0/sqrt(pi)*exp(-(F_left**2)) + \
+          vh_right*u_right/2.0*erfcc(F_right) - \
+          vh_right*sqrt(g*h_right)/2.0/sqrt(pi)*exp(-(F_right**2))
+
+
+    edgeflux = rotate(edgeflux, normal, direction=-1)
+    max_speed = max(abs(s_max), abs(s_min))
+
+    return edgeflux, max_speed
+
+
+flux_function = flux_function_kinetic
+
+def compute_fluxes(domain):
+    """Compute all fluxes and the timestep suitable for all volumes
+    in domain.
+
+    Compute total flux for each conserved quantity using "flux_function"
+
+    Fluxes across each edge are scaled by edgelengths and summed up
+    Resulting flux is then scaled by area and stored in
+    explicit_update for each of the three conserved quantities
+    stage, xmomentum and ymomentum
+
+    The maximal allowable speed computed by the flux_function for each volume
+    is converted to a timestep that must not be exceeded. The minimum of
+    those is computed as the next overall timestep.
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Ymom = domain.quantities['ymomentum']
+    Bed = domain.quantities['elevation']
+
+    #Arrays
+    stage = Stage.edge_values
+    xmom =  Xmom.edge_values
+    ymom =  Ymom.edge_values
+    bed =   Bed.edge_values
+
+    stage_bdry = Stage.boundary_values
+    xmom_bdry =  Xmom.boundary_values
+    ymom_bdry =  Ymom.boundary_values
+
+    flux = zeros(3, Float) #Work array for summing up fluxes
+
+
+    #Loop
+    timestep = float(sys.maxint)
+    for k in range(N):
+
+        flux[:] = 0.  #Reset work array
+        for i in range(3):
+            #Quantities inside volume facing neighbour i
+            ql = [stage[k, i], xmom[k, i], ymom[k, i]]
+            zl = bed[k, i]
+
+            #Quantities at neighbour on nearest face
+            n = domain.neighbours[k,i]
+            if n < 0:
+                m = -n-1 #Convert negative flag to index
+                qr = [stage_bdry[m], xmom_bdry[m], ymom_bdry[m]]
+                zr = zl #Extend bed elevation to boundary
+            else:
+                m = domain.neighbour_edges[k,i]
+                qr = [stage[n, m], xmom[n, m], ymom[n, m]]
+                zr = bed[n, m]
+
+
+            #Outward pointing normal vector
+            normal = domain.normals[k, 2*i:2*i+2]
+
+            #Flux computation using provided function
+            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
+            flux -= edgeflux * domain.edgelengths[k,i]
+
+            #Update optimal_timestep
+            try:
+                timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
+            except ZeroDivisionError:
+                pass
+
+        #Normalise by area and store for when all conserved
+        #quantities get updated
+        flux /= domain.areas[k]
+        Stage.explicit_update[k] = flux[0]
+        Xmom.explicit_update[k] = flux[1]
+        Ymom.explicit_update[k] = flux[2]
+
+
+    domain.timestep = timestep
+
+#MH090605 The following method belongs to the shallow_water domain class
+#see comments in the corresponding method in shallow_water_ext.c
+def extrapolate_second_order_sw_c(domain):
+    """Wrapper calling C version of extrapolate_second_order_sw
+    """
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Ymom = domain.quantities['ymomentum']
+    from shallow_water_ext import extrapolate_second_order_sw
+    extrapolate_second_order_sw(domain,domain.surrogate_neighbours,
+                                domain.number_of_boundaries,
+                                domain.centroid_coordinates,
+                                Stage.centroid_values,
+                                Xmom.centroid_values,
+                                Ymom.centroid_values,
+                                domain.vertex_coordinates,
+                                Stage.vertex_values,
+                                Xmom.vertex_values,
+                                Ymom.vertex_values)
+
+def compute_fluxes_c(domain):
+    """Wrapper calling C version of compute fluxes
+    """
+
+    import sys
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+
+    #Shortcuts
+    Stage = domain.quantities['stage']
+    Xmom = domain.quantities['xmomentum']
+    Ymom = domain.quantities['ymomentum']
+    Bed = domain.quantities['elevation']
+
+    timestep = float(sys.maxint)
+    from shallow_water_ext import compute_fluxes
+    domain.timestep = compute_fluxes(timestep, domain.epsilon, domain.g,
+                                     domain.neighbours,
+                                     domain.neighbour_edges,
+                                     domain.normals,
+                                     domain.edgelengths,
+                                     domain.radii,
+                                     domain.areas,
+                                     Stage.edge_values,
+                                     Xmom.edge_values,
+                                     Ymom.edge_values,
+                                     Bed.edge_values,
+                                     Stage.boundary_values,
+                                     Xmom.boundary_values,
+                                     Ymom.boundary_values,
+                                     Stage.explicit_update,
+                                     Xmom.explicit_update,
+                                     Ymom.explicit_update,
+                                     domain.already_computed_flux)
+
+
+####################################
+# Module functions for gradient limiting (distribute_to_vertices_and_edges)
+
+def distribute_to_vertices_and_edges(domain):
+    """Distribution from centroids to vertices specific to the
+    shallow water wave
+    equation.
+
+    It will ensure that h (w-z) is always non-negative even in the
+    presence of steep bed-slopes by taking a weighted average between shallow
+    and deep cases.
+
+    In addition, all conserved quantities get distributed as per either a
+    constant (order==1) or a piecewise linear function (order==2).
+
+    FIXME: more explanation about removal of artificial variability etc
+
+    Precondition:
+      All quantities defined at centroids and bed elevation defined at
+      vertices.
+
+    Postcondition
+      Conserved quantities defined at vertices
+
+    """
+
+    from anuga.config import optimised_gradient_limiter
+
+    #Remove very thin layers of water
+    protect_against_infinitesimal_and_negative_heights(domain)
+
+    #Extrapolate all conserved quantities
+    if optimised_gradient_limiter:
+        #MH090605 if second order,
+        #perform the extrapolation and limiting on
+        #all of the conserved quantitie
+
+        if (domain.order == 1):
+            for name in domain.conserved_quantities:
+                Q = domain.quantities[name]
+                Q.extrapolate_first_order()
+        elif domain.order == 2:
+            domain.extrapolate_second_order_sw()
+        else:
+            raise 'Unknown order'
+    else:
+        #old code:
+        for name in domain.conserved_quantities:
+            Q = domain.quantities[name]
+            if domain.order == 1:
+                Q.extrapolate_first_order()
+            elif domain.order == 2:
+                Q.extrapolate_second_order()
+                Q.limit()
+            else:
+                raise 'Unknown order'
+
+
+    #Take bed elevation into account when water heights are small
+    balance_deep_and_shallow(domain)
+
+    #Compute edge values by interpolation
+    for name in domain.conserved_quantities:
+        Q = domain.quantities[name]
+        Q.interpolate_from_vertices_to_edges()
+
+
+def protect_against_infinitesimal_and_negative_heights(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+    ymomc = domain.quantities['ymomentum'].centroid_values
+    hc = wc - zc  #Water depths at centroids
+
+    #Update
+    for k in range(domain.number_of_elements):
+
+        if hc[k] < domain.minimum_allowed_height:
+            #Control stage
+            if hc[k] < domain.epsilon:
+                wc[k] = zc[k] # Contain 'lost mass' error
+
+            #Control momentum
+            xmomc[k] = ymomc[k] = 0.0
+
+
+def protect_against_infinitesimal_and_negative_heights_c(domain):
+    """Protect against infinitesimal heights and associated high velocities
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    xmomc = domain.quantities['xmomentum'].centroid_values
+    ymomc = domain.quantities['ymomentum'].centroid_values
+
+    from shallow_water_ext import protect
+
+    protect(domain.minimum_allowed_height, domain.epsilon,
+            wc, zc, xmomc, ymomc)
+
+
+
+def h_limiter(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    hvbar = zeros(hv.shape, Float) #h-limited values
+
+    #Find min and max of this and neighbour's centroid values
+    hmax = zeros(hc.shape, Float)
+    hmin = zeros(hc.shape, Float)
+
+    for k in range(N):
+        hmax[k] = hmin[k] = hc[k]
+        for i in range(3):
+            n = domain.neighbours[k,i]
+            if n >= 0:
+                hn = hc[n] #Neighbour's centroid value
+
+                hmin[k] = min(hmin[k], hn)
+                hmax[k] = max(hmax[k], hn)
+
+
+    #Diffences between centroids and maxima/minima
+    dhmax = hmax - hc
+    dhmin = hmin - hc
+
+    #Deltas between vertex and centroid values
+    dh = zeros(hv.shape, Float)
+    for i in range(3):
+        dh[:,i] = hv[:,i] - hc
+
+    #Phi limiter
+    for k in range(N):
+
+        #Find the gradient limiter (phi) across vertices
+        phi = 1.0
+        for i in range(3):
+            r = 1.0
+            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
+            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
+
+            phi = min( min(r*beta_h, 1), phi )
+
+        #Then update using phi limiter
+        for i in range(3):
+            hvbar[k,i] = hc[k] + phi*dh[k,i]
+
+    return hvbar
+
+
+
+def h_limiter_c(domain):
+    """Limit slopes for each volume to eliminate artificial variance
+    introduced by e.g. second order extrapolator
+
+    limit on h = w-z
+
+    This limiter depends on two quantities (w,z) so it resides within
+    this module rather than within quantity.py
+
+    Wrapper for c-extension
+    """
+
+    from Numeric import zeros, Float
+
+    N = domain.number_of_elements
+    beta_h = domain.beta_h
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv - zv
+
+    #Call C-extension
+    from shallow_water_ext import h_limiter_sw as h_limiter
+    hvbar = h_limiter(domain, hc, hv)
+
+    return hvbar
+
+
+def balance_deep_and_shallow(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters limiting using w, and stage computed by
+    gradient-limiters limiting using h (h-limiter).
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+
+    The h-limiter is always applied irrespective of the order.
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]),
+                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using the h-limited
+        #stage and alpha==1 means using the w-limited stage as
+        #computed by the gradient limiter (both 1st or 2nd order)
+
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+	#Let
+	#
+	#  wvi be the w-limited stage (wvi = zvi + hvi)
+	#  wvi- be the h-limited state (wvi- = zvi + hvi-)
+	#
+	#
+	#where i=0,1,2 denotes the vertex ids
+	#
+        #Weighted balance between w-limited and h-limited stage is
+        #
+	#  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+	#
+        #It follows that the updated wvi is
+        #  wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+        #
+	# Momentum is balanced between constant and limited
+
+
+        #for i in range(3):
+        #    wv[k,i] = zv[k,i] + hvbar[k,i]
+
+	#return
+
+	if alpha < 1:
+
+            for i in range(3):
+                wv[k,i] = zv[k,i] + (1-alpha)*hvbar[k,i] + alpha*hv[k,i]
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+            ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1-alpha)*xmomc[k] + alpha*xmomv[k,:]
+            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+def balance_deep_and_shallow_c(domain):
+    """Wrapper for C implementation
+    """
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv - zv
+
+    #Momentums at centroids
+    xmomc = domain.quantities['xmomentum'].centroid_values
+    ymomc = domain.quantities['ymomentum'].centroid_values
+
+    #Momentums at vertices
+    xmomv = domain.quantities['xmomentum'].vertex_values
+    ymomv = domain.quantities['ymomentum'].vertex_values
+
+    #Limit h
+    hvbar = h_limiter(domain)
+
+    #This is how one would make a first order h_limited value
+    #as in the old balancer (pre 17 Feb 2005):
+    #from Numeric import zeros, Float
+    #hvbar = zeros( (len(hc), 3), Float)
+    #for i in range(3):
+    #    hvbar[:,i] = hc[:]
+
+    from shallow_water_ext import balance_deep_and_shallow
+    balance_deep_and_shallow(wc, zc, hc, wv, zv, hv, hvbar,
+                             xmomc, ymomc, xmomv, ymomv)
+
+
+
+
+###############################################
+#Boundaries - specific to the shallow water wave equation
+class Reflective_boundary(Boundary):
+    """Reflective boundary returns same conserved quantities as
+    those present in its neighbour volume but reflected.
+
+    This class is specific to the shallow water equation as it
+    works with the momentum quantities assumed to be the second
+    and third conserved quantities.
+    """
+
+    def __init__(self, domain = None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for reflective boundary'
+            raise msg
+
+        #Handy shorthands
+        self.stage   = domain.quantities['stage'].edge_values
+        self.xmom    = domain.quantities['xmomentum'].edge_values
+        self.ymom    = domain.quantities['ymomentum'].edge_values
+        self.normals = domain.normals
+
+        from Numeric import zeros, Float
+        self.conserved_quantities = zeros(3, Float)
+
+    def __repr__(self):
+        return 'Reflective_boundary'
+
+
+    def evaluate(self, vol_id, edge_id):
+        """Reflective boundaries reverses the outward momentum
+        of the volume they serve.
+        """
+
+        q = self.conserved_quantities
+        q[0] = self.stage[vol_id, edge_id]
+        q[1] = self.xmom[vol_id, edge_id]
+        q[2] = self.ymom[vol_id, edge_id]
+
+        normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
+
+
+        r = rotate(q, normal, direction = 1)
+        r[1] = -r[1]
+        q = rotate(r, normal, direction = -1)
+
+        return q
+
+
+
+class Transmissive_Momentum_Set_Stage_boundary(Boundary):
+    """Returns same momentum conserved quantities as
+    those present in its neighbour volume. Sets stage
+
+    Underlying domain must be specified when boundary is instantiated
+    """
+
+    def __init__(self, domain = None, function=None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for this type boundary'
+            raise msg
+
+        if function is None:
+            msg = 'Function must be specified for this type boundary'
+            raise msg
+
+        self.domain   = domain
+        self.function = function
+
+    def __repr__(self):
+        return 'Transmissive_Momentum_Set_Stage_boundary(%s)' %self.domain
+
+    def evaluate(self, vol_id, edge_id):
+        """Transmissive Momentum Set Stage boundaries return the edge momentum
+        values of the volume they serve.
+        """
+
+        q = self.domain.get_conserved_quantities(vol_id, edge = edge_id)
+        value = self.function(self.domain.time)
+        q[0] = value[0]
+        return q
+
+
+        #FIXME: Consider this (taken from File_boundary) to allow
+        #spatial variation
+        #if vol_id is not None and edge_id is not None:
+        #    i = self.boundary_indices[ vol_id, edge_id ]
+        #    return self.F(t, point_id = i)
+        #else:
+        #    return self.F(t)
+
+
+
+class Dirichlet_Discharge_boundary(Boundary):
+    """
+    Sets stage (stage0)
+    Sets momentum (wh0) in the inward normal direction.
+
+    Underlying domain must be specified when boundary is instantiated
+    """
+
+    def __init__(self, domain = None, stage0=None, wh0=None):
+        Boundary.__init__(self)
+
+        if domain is None:
+            msg = 'Domain must be specified for this type boundary'
+            raise msg
+
+        if stage0 is None:
+            raise 'set stage'
+
+        if wh0 is None:
+            wh0 = 0.0
+
+        self.domain   = domain
+        self.stage0  = stage0
+        self.wh0 = wh0
+
+    def __repr__(self):
+        return 'Dirichlet_Discharge_boundary(%s)' %self.domain
+
+    def evaluate(self, vol_id, edge_id):
+        """Set discharge in the (inward) normal direction
+        """
+
+        normal = self.domain.get_normal(vol_id,edge_id)
+        q = [self.stage0, -self.wh0*normal[0], -self.wh0*normal[1]]
+        return q
+
+
+        #FIXME: Consider this (taken from File_boundary) to allow
+        #spatial variation
+        #if vol_id is not None and edge_id is not None:
+        #    i = self.boundary_indices[ vol_id, edge_id ]
+        #    return self.F(t, point_id = i)
+        #else:
+        #    return self.F(t)
+
+
+
+#class Spatio_temporal_boundary(Boundary):
+#    """The spatio-temporal boundary, reads values for the conserved
+#    quantities from an sww NetCDF file, and returns interpolated values
+#    at the midpoints of each associated boundaty segment.
+#    Time dependency is interpolated linearly as in util.File_function.#
+#
+#    Example:
+#    Bf = Spatio_temporal_boundary('source_file.sww', domain)
+#
+#    """
+Spatio_temporal_boundary = File_boundary
+
+
+
+
+#########################
+#Standard forcing terms:
+#
+def gravity(domain):
+    """Apply gravitational pull in the presence of bed slope
+    """
+
+    from anuga.pyvolution.util import gradient
+    from Numeric import zeros, Float, array, sum
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    h = Stage.edge_values - Elevation.edge_values
+    v = Elevation.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+    for k in range(domain.number_of_elements):
+        avg_h = sum( h[k,:] )/3
+
+        #Compute bed slope
+        x0, y0, x1, y1, x2, y2 = x[k,:]
+        z0, z1, z2 = v[k,:]
+
+        zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
+
+        #Update momentum
+        xmom[k] += -g*zx*avg_h
+        ymom[k] += -g*zy*avg_h
+
+
+def gravity_c(domain):
+    """Wrapper calling C version
+    """
+
+    xmom = domain.quantities['xmomentum'].explicit_update
+    ymom = domain.quantities['ymomentum'].explicit_update
+
+    Stage = domain.quantities['stage']
+    Elevation = domain.quantities['elevation']
+    h = Stage.edge_values - Elevation.edge_values
+    v = Elevation.vertex_values
+
+    x = domain.get_vertex_coordinates()
+    g = domain.g
+
+
+    from shallow_water_ext import gravity
+    gravity(g, h, v, x, xmom, ymom)
+
+
+def manning_friction(domain):
+    """Apply (Manning) friction to water momentum
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    vh = domain.quantities['ymomentum'].centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    for k in range(N):
+        if eta[k] >= eps:
+            if h[k] >= eps:
+            	S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
+            	S /= h[k]**(7.0/3)
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	ymom_update[k] += S*vh[k]
+
+
+def manning_friction_c(domain):
+    """Wrapper for c version
+    """
+
+
+    xmom = domain.quantities['xmomentum']
+    ymom = domain.quantities['ymomentum']
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+
+    uh = xmom.centroid_values
+    vh = ymom.centroid_values
+    eta = domain.quantities['friction'].centroid_values
+
+    xmom_update = xmom.semi_implicit_update
+    ymom_update = ymom.semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g
+
+    from shallow_water_ext import manning_friction
+    manning_friction(g, eps, w, z, uh, vh, eta, xmom_update, ymom_update)
+
+
+def linear_friction(domain):
+    """Apply linear friction to water momentum
+
+    Assumes quantity: 'linear_friction' to be present
+    """
+
+    from math import sqrt
+
+    w = domain.quantities['stage'].centroid_values
+    z = domain.quantities['elevation'].centroid_values
+    h = w-z
+
+    uh = domain.quantities['xmomentum'].centroid_values
+    vh = domain.quantities['ymomentum'].centroid_values
+    tau = domain.quantities['linear_friction'].centroid_values
+
+    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
+    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
+
+    N = domain.number_of_elements
+    eps = domain.minimum_allowed_height
+    g = domain.g #Not necessary? Why was this added?
+
+    for k in range(N):
+        if tau[k] >= eps:
+            if h[k] >= eps:
+            	S = -tau[k]/h[k]
+
+            	#Update momentum
+            	xmom_update[k] += S*uh[k]
+            	ymom_update[k] += S*vh[k]
+
+
+
+def check_forcefield(f):
+    """Check that f is either
+    1: a callable object f(t,x,y), where x and y are vectors
+       and that it returns an array or a list of same length
+       as x and y
+    2: a scalar
+    """
+
+    from Numeric import ones, Float, array
+
+
+    if callable(f):
+        N = 3
+        x = ones(3, Float)
+        y = ones(3, Float)
+        try:
+            q = f(1.0, x=x, y=y)
+        except Exception, e:
+            msg = 'Function %s could not be executed:\n%s' %(f, e)
+	    #FIXME: Reconsider this semantics
+            raise msg
+
+        try:
+            q = array(q).astype(Float)
+        except:
+            msg = 'Return value from vector function %s could ' %f
+            msg += 'not be converted into a Numeric array of floats.\n'
+            msg += 'Specified function should return either list or array.'
+            raise msg
+
+        #Is this really what we want?
+        msg = 'Return vector from function %s ' %f
+        msg += 'must have same lenght as input vectors'
+        assert len(q) == N, msg
+
+    else:
+        try:
+            f = float(f)
+        except:
+            msg = 'Force field %s must be either a scalar' %f
+            msg += ' or a vector function'
+            raise msg
+    return f
+
+
+class Wind_stress:
+    """Apply wind stress to water momentum in terms of
+    wind speed [m/s] and wind direction [degrees]
+    """
+
+    def __init__(self, *args, **kwargs):
+        """Initialise windfield from wind speed s [m/s]
+        and wind direction phi [degrees]
+
+        Inputs v and phi can be either scalars or Python functions, e.g.
+
+        W = Wind_stress(10, 178)
+
+        #FIXME - 'normal' degrees are assumed for now, i.e. the
+        vector (1,0) has zero degrees.
+        We may need to convert from 'compass' degrees later on and also
+        map from True north to grid north.
+
+        Arguments can also be Python functions of t,x,y as in
+
+        def speed(t,x,y):
+            ...
+            return s
+
+        def angle(t,x,y):
+            ...
+            return phi
+
+        where x and y are vectors.
+
+        and then pass the functions in
+
+        W = Wind_stress(speed, angle)
+
+        The instantiated object W can be appended to the list of
+        forcing_terms as in
+
+        Alternatively, one vector valued function for (speed, angle)
+        can be applied, providing both quantities simultaneously.
+        As in
+        W = Wind_stress(F), where returns (speed, angle) for each t.
+
+        domain.forcing_terms.append(W)
+        """
+
+        from anuga.config import rho_a, rho_w, eta_w
+        from Numeric import array, Float
+
+        if len(args) == 2:
+            s = args[0]
+            phi = args[1]
+        elif len(args) == 1:
+            #Assume vector function returning (s, phi)(t,x,y)
+            vector_function = args[0]
+            s = lambda t,x,y: vector_function(t,x=x,y=y)[0]
+            phi = lambda t,x,y: vector_function(t,x=x,y=y)[1]
+        else:
+           #Assume info is in 2 keyword arguments
+
+           if len(kwargs) == 2:
+               s = kwargs['s']
+               phi = kwargs['phi']
+           else:
+               raise 'Assumes two keyword arguments: s=..., phi=....'
+
+        self.speed = check_forcefield(s)
+        self.phi = check_forcefield(phi)
+
+        self.const = eta_w*rho_a/rho_w
+
+
+    def __call__(self, domain):
+        """Evaluate windfield based on values found in domain
+        """
+
+        from math import pi, cos, sin, sqrt
+        from Numeric import Float, ones, ArrayType
+
+        xmom_update = domain.quantities['xmomentum'].explicit_update
+        ymom_update = domain.quantities['ymomentum'].explicit_update
+
+        N = domain.number_of_elements
+        t = domain.time
+
+        if callable(self.speed):
+            xc = domain.get_centroid_coordinates()
+            s_vec = self.speed(t, xc[:,0], xc[:,1])
+        else:
+            #Assume s is a scalar
+
+            try:
+                s_vec = self.speed * ones(N, Float)
+            except:
+                msg = 'Speed must be either callable or a scalar: %s' %self.s
+                raise msg
+
+
+        if callable(self.phi):
+            xc = domain.get_centroid_coordinates()
+            phi_vec = self.phi(t, xc[:,0], xc[:,1])
+        else:
+            #Assume phi is a scalar
+
+            try:
+                phi_vec = self.phi * ones(N, Float)
+            except:
+                msg = 'Angle must be either callable or a scalar: %s' %self.phi
+                raise msg
+
+        assign_windfield_values(xmom_update, ymom_update,
+                                s_vec, phi_vec, self.const)
+
+
+def assign_windfield_values(xmom_update, ymom_update,
+                            s_vec, phi_vec, const):
+    """Python version of assigning wind field to update vectors.
+    A c version also exists (for speed)
+    """
+    from math import pi, cos, sin, sqrt
+
+    N = len(s_vec)
+    for k in range(N):
+        s = s_vec[k]
+        phi = phi_vec[k]
+
+        #Convert to radians
+        phi = phi*pi/180
+
+        #Compute velocity vector (u, v)
+        u = s*cos(phi)
+        v = s*sin(phi)
+
+        #Compute wind stress
+        S = const * sqrt(u**2 + v**2)
+        xmom_update[k] += S*u
+        ymom_update[k] += S*v
+
+
+
+##############################
+#OBSOLETE STUFF
+
+def balance_deep_and_shallow_old(domain):
+    """Compute linear combination between stage as computed by
+    gradient-limiters and stage computed as constant height above bed.
+    The former takes precedence when heights are large compared to the
+    bed slope while the latter takes precedence when heights are
+    relatively small.  Anything in between is computed as a balanced
+    linear combination in order to avoid numerical disturbances which
+    would otherwise appear as a result of hard switching between
+    modes.
+    """
+
+    #OBSOLETE
+
+    #Shortcuts
+    wc = domain.quantities['stage'].centroid_values
+    zc = domain.quantities['elevation'].centroid_values
+    hc = wc - zc
+
+    wv = domain.quantities['stage'].vertex_values
+    zv = domain.quantities['elevation'].vertex_values
+    hv = wv-zv
+
+
+    #Computed linear combination between constant stages and and
+    #stages parallel to the bed elevation.
+    for k in range(domain.number_of_elements):
+        #Compute maximal variation in bed elevation
+        #  This quantitiy is
+        #    dz = max_i abs(z_i - z_c)
+        #  and it is independent of dimension
+        #  In the 1d case zc = (z0+z1)/2
+        #  In the 2d case zc = (z0+z1+z2)/3
+
+        dz = max(abs(zv[k,0]-zc[k]),
+                 abs(zv[k,1]-zc[k]),
+                 abs(zv[k,2]-zc[k]))
+
+
+        hmin = min( hv[k,:] )
+
+        #Create alpha in [0,1], where alpha==0 means using shallow
+        #first order scheme and alpha==1 means using the stage w as
+        #computed by the gradient limiter (1st or 2nd order)
+        #
+        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
+        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+        if dz > 0.0:
+            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
+        else:
+            #Flat bed
+            alpha = 1.0
+
+        #Weighted balance between stage parallel to bed elevation
+        #(wvi = zvi + hc) and stage as computed by 1st or 2nd
+	#order gradient limiter
+        #(wvi = zvi + hvi) where i=0,1,2 denotes the vertex ids
+        #
+        #It follows that the updated wvi is
+        #  wvi := (1-alpha)*(zvi+hc) + alpha*(zvi+hvi) =
+        #  zvi + hc + alpha*(hvi - hc)
+        #
+        #Note that hvi = zc+hc-zvi in the first order case (constant).
+
+	if alpha < 1:
+            for i in range(3):
+                wv[k,i] = zv[k,i] + hc[k] + alpha*(hv[k,i]-hc[k])
+
+
+            #Momentums at centroids
+            xmomc = domain.quantities['xmomentum'].centroid_values
+            ymomc = domain.quantities['ymomentum'].centroid_values
+
+            #Momentums at vertices
+            xmomv = domain.quantities['xmomentum'].vertex_values
+            ymomv = domain.quantities['ymomentum'].vertex_values
+
+            # Update momentum as a linear combination of
+            # xmomc and ymomc (shallow) and momentum
+            # from extrapolator xmomv and ymomv (deep).
+            xmomv[k,:] = (1-alpha)*xmomc[k] + alpha*xmomv[k,:]
+            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
+
+
+
+
+
+###########################
+###########################
+#Geometries
+
+
+#FIXME: Rethink this way of creating values.
+
+
+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):
+        from Numeric import zeros, Float
+        from math import sqrt
+
+        N = len(x)
+        assert N == len(y)
+
+        z = zeros(N, 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.3
+            depth = -1.0
+            #plateaux = -0.9
+            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)
+                    #z[i] = depth-y[i]/5
+                    #z[i] = depth
+                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 x[i] < -0.2 and y < 0.5:
+            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)-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 Weir_simple:
+    """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):
+        from Numeric import zeros, Float
+
+        N = len(x)
+        assert N == len(y)
+
+        z = zeros(N, Float)
+        for i in range(N):
+            z[i] = -x[i]  #General slope
+
+            #Flat bit to the left
+            if x[i] < 0.3:
+                z[i] = -x[i]/10  #General slope
+
+            #Weir
+            if x[i] > 0.3 and x[i] < 0.4:
+                z[i] = -x[i]+0.9
+
+            #Dip
+            if x[i] > 0.6 and x[i] < 0.9:
+                z[i] = -x[i]-0.5  #-y[i]/5
+
+            #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.05
+
+
+        return z/2
+
+
+
+class Constant_stage:
+    """Set an initial condition with constant stage
+    """
+    def __init__(self, s):
+        self.s = s
+
+    def __call__(self, x, y):
+        return self.s
+
+class Constant_height:
+    """Set an initial condition with constant water height, e.g
+    stage s = z+h
+    """
+
+    def __init__(self, W, h):
+        self.W = W
+        self.h = h
+
+    def __call__(self, x, y):
+        if self.W is None:
+            from Numeric import ones, Float
+            return self.h*ones(len(x), Float)
+        else:
+            return self.W(x,y) + self.h
+
+
+
+
+
+
+
+##############################################
+#Initialise module
+
+
+from anuga.utilities import compile
+if compile.can_use_C_extension('shallow_water_kinetic_ext.c'):
+    #Replace python version with c implementations
+
+    from shallow_water_kinetic_ext import rotate, assign_windfield_values
+    compute_fluxes = compute_fluxes_c
+    extrapolate_second_order_sw=extrapolate_second_order_sw_c
+    gravity = gravity_c
+    manning_friction = manning_friction_c
+    h_limiter = h_limiter_c
+    balance_deep_and_shallow = balance_deep_and_shallow_c
+    protect_against_infinitesimal_and_negative_heights = protect_against_infinitesimal_and_negative_heights_c
+
+
+    #distribute_to_vertices_and_edges = distribute_to_vertices_and_edges_c #(like MH's)
+
+
+
+#Optimisation with psyco
+from anuga.config import use_psyco
+if use_psyco:
+    try:
+        import psyco
+    except:
+        import os
+        if os.name == 'posix' and os.uname()[4] == 'x86_64':
+            pass
+            #Psyco isn't supported on 64 bit systems, but it doesn't matter
+        else:
+            msg = 'WARNING: psyco (speedup) could not import'+\
+                  ', you may want to consider installing it'
+            print msg
+    else:
+        psyco.bind(Domain.distribute_to_vertices_and_edges)
+        psyco.bind(Domain.compute_fluxes)
+
+if __name__ == "__main__":
+    pass
+
+# Profiling stuff
+import profile
+profiler = profile.Profile()
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/shallow_water_kinetic_ext.c
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/shallow_water_kinetic_ext.c	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/shallow_water_kinetic_ext.c	(revision 3560)
@@ -0,0 +1,1442 @@
+// Python - C extension module for shallow_water.py
+//
+// To compile (Python2.3):
+//  gcc -c domain_ext.c -I/usr/include/python2.3 -o domain_ext.o -Wall -O
+//  gcc -shared domain_ext.o  -o domain_ext.so
+//
+// or use python compile.py
+//
+// See the module shallow_water.py
+//
+//
+// Ole Nielsen, GA 2004
+
+
+#include "Python.h"
+#include "Numeric/arrayobject.h"
+#include "math.h"
+#include <stdio.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 momentum component q (q[1], q[2])
+    from x,y coordinates to coordinates based on normal vector (n1, n2).
+
+    Result is returned in array 3x1 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];  //uh momentum
+  q2 = q[2];  //vh momentum
+
+  //Rotate
+  q[1] =  n1*q1 + n2*q2;
+  q[2] = -n2*q1 + n1*q2;
+
+  return 0;
+}
+
+int find_qmin_and_qmax(double dq0, double dq1, double dq2, double *qmin, double *qmax){
+  //Considering the centroid of an FV triangle and the vertices of its auxiliary triangle, find
+  //qmin=min(q)-qc and qmax=max(q)-qc, where min(q) and max(q) are respectively min and max over the
+  //four values (at the centroid of the FV triangle and the auxiliary triangle vertices),
+  //and qc is the centroid
+  //dq0=q(vertex0)-q(centroid of FV triangle)
+  //dq1=q(vertex1)-q(vertex0)
+  //dq2=q(vertex2)-q(vertex0)
+  if (dq0>=0.0){
+    if (dq1>=dq2){
+      if (dq1>=0.0)
+	*qmax=dq0+dq1;
+      else
+	*qmax=dq0;
+      if ((*qmin=dq0+dq2)<0)
+	;//qmin is already set to correct value
+      else
+	*qmin=0.0;
+    }
+    else{//dq1<dq2
+      if (dq2>0)
+	*qmax=dq0+dq2;
+      else
+	*qmax=dq0;
+      if ((*qmin=dq0+dq1)<0)
+	;//qmin is the correct value
+      else
+	*qmin=0.0;
+    }
+  }
+  else{//dq0<0
+    if (dq1<=dq2){
+      if (dq1<0.0)
+	*qmin=dq0+dq1;
+      else
+	*qmin=dq0;
+      if ((*qmax=dq0+dq2)>0.0)
+	;//qmax is already set to the correct value
+      else
+	*qmax=0.0;
+    }
+    else{//dq1>dq2
+      if (dq2<0.0)
+	*qmin=dq0+dq2;
+      else
+	*qmin=dq0;
+      if ((*qmax=dq0+dq1)>0.0)
+	;//qmax is already set to the correct value
+      else
+	*qmax=0.0;
+    }
+  }
+  return 0;
+}
+
+int limit_gradient(double *dqv, double qmin, double qmax, double beta_w){
+  //given provisional jumps dqv from the FV triangle centroid to its vertices and
+  //jumps qmin (qmax) between the centroid of the FV triangle and the
+  //minimum (maximum) of the values at the centroid of the FV triangle and the auxiliary triangle vertices,
+  //calculate a multiplicative factor phi by which the provisional vertex jumps are to be limited
+  int i;
+  double r=1000.0, r0=1.0, phi=1.0;
+  static double TINY = 1.0e-100;//to avoid machine accuracy problems.
+  //Any provisional jump with magnitude < TINY does not contribute to the limiting process.
+  for (i=0;i<3;i++){
+    if (dqv[i]<-TINY)
+      r0=qmin/dqv[i];
+    if (dqv[i]>TINY)
+      r0=qmax/dqv[i];
+    r=min(r0,r);
+    //
+  }
+  phi=min(r*beta_w,1.0);
+  for (i=0;i<3;i++)
+    dqv[i]=dqv[i]*phi;
+  return 0;
+}
+
+// Computational function for flux computation (using stage w=z+h)
+int flux_function_central(double *q_left, double *q_right,
+		  double z_left, double z_right,
+		  double n1, double n2,
+		  double epsilon, double g,
+		  double *edgeflux, double *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 w_left, h_left, uh_left, vh_left, u_left;
+  double w_right, h_right, uh_right, vh_right, u_right;
+  double s_min, s_max, soundspeed_left, soundspeed_right;
+  double denom, z;
+  double q_left_copy[3], q_right_copy[3];
+  double flux_right[3], flux_left[3];
+
+  //Copy conserved quantities to protect from modification
+  for (i=0; i<3; i++) {
+    q_left_copy[i] = q_left[i];
+    q_right_copy[i] = q_right[i];
+  }
+
+  //Align x- and y-momentum with x-axis
+  _rotate(q_left_copy, n1, n2);
+  _rotate(q_right_copy, n1, n2);
+
+  z = (z_left+z_right)/2; //Take average of field values
+
+  //Compute speeds in x-direction
+  w_left = q_left_copy[0];              // h+z
+  h_left = w_left-z;
+  uh_left = q_left_copy[1];
+
+  if (h_left < epsilon) {
+    h_left = 0.0;  //Could have been negative
+    u_left = 0.0;
+  } else {
+    u_left = uh_left/h_left;
+  }
+
+  w_right = q_right_copy[0];
+  h_right = w_right-z;
+  uh_right = q_right_copy[1];
+
+  if (h_right < epsilon) {
+    h_right = 0.0; //Could have been negative
+    u_right = 0.0;
+  } else {
+    u_right = uh_right/h_right;
+  }
+
+  //Momentum in y-direction
+  vh_left  = q_left_copy[2];
+  vh_right = q_right_copy[2];
+
+
+  //Maximal and minimal wave speeds
+  soundspeed_left  = sqrt(g*h_left);
+  soundspeed_right = sqrt(g*h_right);
+
+  s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
+  if (s_max < 0.0) s_max = 0.0;
+
+  s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
+  if (s_min > 0.0) s_min = 0.0;
+
+  //Flux formulas
+  flux_left[0] = u_left*h_left;
+  flux_left[1] = u_left*uh_left + 0.5*g*h_left*h_left;
+  flux_left[2] = u_left*vh_left;
+
+  flux_right[0] = u_right*h_right;
+  flux_right[1] = u_right*uh_right + 0.5*g*h_right*h_right;
+  flux_right[2] = u_right*vh_right;
+
+
+  //Flux computation
+  denom = s_max-s_min;
+  if (denom == 0.0) {
+    for (i=0; i<3; i++) edgeflux[i] = 0.0;
+    *max_speed = 0.0;
+  } else {
+    for (i=0; i<3; i++) {
+      edgeflux[i] = s_max*flux_left[i] - s_min*flux_right[i];
+      edgeflux[i] += s_max*s_min*(q_right_copy[i]-q_left_copy[i]);
+      edgeflux[i] /= denom;
+    }
+
+    //Maximal wavespeed
+    *max_speed = max(fabs(s_max), fabs(s_min));
+
+    //Rotate back
+    _rotate(edgeflux, n1, -n2);
+  }
+  return 0;
+}
+
+double erfcc(double x){
+    double z,t,result;
+
+    z=fabs(x);
+    t=1.0/(1.0+0.5*z);
+    result=t*exp(-z*z-1.26551223+t*(1.00002368+t*(.37409196+
+         t*(.09678418+t*(-.18628806+t*(.27886807+t*(-1.13520398+
+         t*(1.48851587+t*(-.82215223+t*.17087277)))))))));
+    if (x < 0.0) result = 2.0-result;
+
+    return result;
+    }
+
+
+
+// Computational function for flux computation (using stage w=z+h)
+int flux_function_kinetic(double *q_left, double *q_right,
+		  double z_left, double z_right,
+		  double n1, double n2,
+		  double epsilon, double g,
+		  double *edgeflux, double *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
+
+    Zhang et. al., Advances in Water Resources, 26(6), 2003, 635-647.
+  */
+
+  int i;
+
+  double w_left, h_left, uh_left, vh_left, u_left, F_left;
+  double w_right, h_right, uh_right, vh_right, u_right, F_right;
+  double s_min, s_max, soundspeed_left, soundspeed_right;
+  double z;
+  double q_left_copy[3], q_right_copy[3];
+
+
+  //Copy conserved quantities to protect from modification
+  for (i=0; i<3; i++) {
+    q_left_copy[i] = q_left[i];
+    q_right_copy[i] = q_right[i];
+  }
+
+  //Align x- and y-momentum with x-axis
+  _rotate(q_left_copy, n1, n2);
+  _rotate(q_right_copy, n1, n2);
+
+  z = (z_left+z_right)/2; //Take average of field values
+
+  //Compute speeds in x-direction
+  w_left = q_left_copy[0];              // h+z
+  h_left = w_left-z;
+  uh_left = q_left_copy[1];
+
+  if (h_left < epsilon) {
+    h_left = 0.0;  //Could have been negative
+    u_left = 0.0;
+  } else {
+    u_left = uh_left/h_left;
+  }
+
+  w_right = q_right_copy[0];
+  h_right = w_right-z;
+  uh_right = q_right_copy[1];
+
+  if (h_right < epsilon) {
+    h_right = 0.0; //Could have been negative
+    u_right = 0.0;
+  } else {
+    u_right = uh_right/h_right;
+  }
+
+  //Momentum in y-direction
+  vh_left  = q_left_copy[2];
+  vh_right = q_right_copy[2];
+
+
+  //Maximal and minimal wave speeds
+  soundspeed_left  = sqrt(g*h_left);
+  soundspeed_right = sqrt(g*h_right);
+
+  s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
+  if (s_max < 0.0) s_max = 0.0;
+
+  s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
+  if (s_min > 0.0) s_min = 0.0;
+
+
+  F_left  = 0.0;
+  F_right = 0.0;
+  if (h_left > 0.0) F_left = u_left/sqrt(g*h_left);
+  if (h_right > 0.0) F_right = u_right/sqrt(g*h_right);
+
+  for (i=0; i<3; i++) edgeflux[i] = 0.0;
+  *max_speed = 0.0;
+
+  edgeflux[0] = h_left*u_left/2.0*erfcc(-F_left) +  \
+          h_left*sqrt(g*h_left)/2.0/sqrt(pi)*exp(-(F_left*F_left)) + \
+          h_right*u_right/2.0*erfcc(F_right) -  \
+          h_right*sqrt(g*h_right)/2.0/sqrt(pi)*exp(-(F_right*F_right));
+
+  edgeflux[1] = (h_left*u_left*u_left + g/2.0*h_left*h_left)/2.0*erfcc(-F_left) + \
+          u_left*h_left*sqrt(g*h_left)/2.0/sqrt(pi)*exp(-(F_left*F_left)) + \
+          (h_right*u_right*u_right + g/2.0*h_right*h_right)/2.0*erfcc(F_right) -  \
+          u_right*h_right*sqrt(g*h_right)/2.0/sqrt(pi)*exp(-(F_right*F_right));
+
+  edgeflux[2] = vh_left*u_left/2.0*erfcc(-F_left) + \
+          vh_left*sqrt(g*h_left)/2.0/sqrt(pi)*exp(-(F_left*F_left)) + \
+          vh_right*u_right/2.0*erfcc(F_right) - \
+          vh_right*sqrt(g*h_right)/2.0/sqrt(pi)*exp(-(F_right*F_right));
+
+  //Maximal wavespeed
+  *max_speed = max(fabs(s_max), fabs(s_min));
+
+  //Rotate back
+  _rotate(edgeflux, n1, -n2);
+
+  return 0;
+}
+
+
+void _manning_friction(double g, double eps, int N,
+		       double* w, double* z,
+		       double* uh, double* vh,
+		       double* eta, double* xmom, double* ymom) {
+
+  int k;
+  double S, h;
+
+  for (k=0; k<N; k++) {
+    if (eta[k] > eps) {
+      h = w[k]-z[k];
+      if (h >= eps) {
+	S = -g * eta[k]*eta[k] * sqrt((uh[k]*uh[k] + vh[k]*vh[k]));
+	//S /= pow(h, 7.0/3);      //Expensive (on Ole's home computer)
+	S /= exp(7.0/3.0*log(h));      //seems to save about 15% over manning_friction
+	//S /= h*h*(1 + h/3.0 - h*h/9.0); //FIXME: Could use a Taylor expansion
+
+
+	//Update momentum
+	xmom[k] += S*uh[k];
+	ymom[k] += S*vh[k];
+      }
+    }
+  }
+}
+
+
+
+int _balance_deep_and_shallow(int N,
+			      double* wc,
+			      double* zc,
+			      double* hc,
+			      double* wv,
+			      double* zv,
+			      double* hv,
+			      double* hvbar,
+			      double* xmomc,
+			      double* ymomc,
+			      double* xmomv,
+			      double* ymomv) {
+
+  int k, k3, i;
+  double dz, hmin, alpha;
+
+  //Compute linear combination between w-limited stages and
+  //h-limited stages close to the bed elevation.
+
+  for (k=0; k<N; k++) {
+    // Compute maximal variation in bed elevation
+    // This quantitiy is
+    //     dz = max_i abs(z_i - z_c)
+    // and it is independent of dimension
+    // In the 1d case zc = (z0+z1)/2
+    // In the 2d case zc = (z0+z1+z2)/3
+
+    k3 = 3*k;
+
+    //FIXME: Try with this one precomputed
+    dz = 0.0;
+    hmin = hv[k3];
+    for (i=0; i<3; i++) {
+      dz = max(dz, fabs(zv[k3+i]-zc[k]));
+      hmin = min(hmin, hv[k3+i]);
+    }
+
+
+    //Create alpha in [0,1], where alpha==0 means using the h-limited
+    //stage and alpha==1 means using the w-limited stage as
+    //computed by the gradient limiter (both 1st or 2nd order)
+    //
+    //If hmin > dz/2 then alpha = 1 and the bed will have no effect
+    //If hmin < 0 then alpha = 0 reverting to constant height above bed.
+
+
+    if (dz > 0.0)
+      //if (hmin<0.0)
+      //	alpha = 0.0;
+      //else
+      //  alpha = max( min( hc[k]/dz, 1.0), 0.0 );
+      alpha = max( min( 2.0*hmin/dz, 1.0), 0.0 );
+    else
+      alpha = 1.0;  //Flat bed
+
+    //alpha = 1.0;
+
+    //printf("dz = %.3f, alpha = %.8f\n", dz, alpha);
+
+    //	Let
+    //
+    //	  wvi be the w-limited stage (wvi = zvi + hvi)
+    //	  wvi- be the h-limited state (wvi- = zvi + hvi-)
+    //
+    //
+    //	where i=0,1,2 denotes the vertex ids
+    //
+    //  Weighted balance between w-limited and h-limited stage is
+    //
+    //	  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
+    //
+    //  It follows that the updated wvi is
+    //    wvi := zvi + (1-alpha)*hvi- + alpha*hvi
+    //
+    //	 Momentum is balanced between constant and limited
+
+    if (alpha < 1) {
+      for (i=0; i<3; i++) {
+         wv[k3+i] = zv[k3+i] + (1-alpha)*hvbar[k3+i] + alpha*hv[k3+i];
+
+	//Update momentum as a linear combination of
+	//xmomc and ymomc (shallow) and momentum
+	//from extrapolator xmomv and ymomv (deep).
+	xmomv[k3+i] = (1-alpha)*xmomc[k] + alpha*xmomv[k3+i];
+	ymomv[k3+i] = (1-alpha)*ymomc[k] + alpha*ymomv[k3+i];
+      }
+    }
+  }
+  return 0;
+}
+
+
+
+int _protect(int N,
+	     double minimum_allowed_height,
+	     double epsilon,
+	     double* wc,
+	     double* zc,
+	     double* xmomc,
+	     double* ymomc) {
+
+  int k;
+  double hc;
+
+  //Protect against initesimal and negative heights
+
+  for (k=0; k<N; k++) {
+    hc = wc[k] - zc[k];
+
+    if (hc < minimum_allowed_height) {
+      if (hc < epsilon) wc[k] = zc[k]; //Contain 'lost mass' error
+      xmomc[k] = 0.0;
+      ymomc[k] = 0.0;
+    }
+
+  }
+  return 0;
+}
+
+
+
+
+int _assign_wind_field_values(int N,
+			      double* xmom_update,
+			      double* ymom_update,
+			      double* s_vec,
+			      double* phi_vec,
+			      double cw) {
+
+  //Assign windfield values to momentum updates
+
+  int k;
+  double S, s, phi, u, v;
+
+  for (k=0; k<N; k++) {
+
+    s = s_vec[k];
+    phi = phi_vec[k];
+
+    //Convert to radians
+    phi = phi*pi/180;
+
+    //Compute velocity vector (u, v)
+    u = s*cos(phi);
+    v = s*sin(phi);
+
+    //Compute wind stress
+    S = cw * sqrt(u*u + v*v);
+    xmom_update[k] += S*u;
+    ymom_update[k] += S*v;
+  }
+  return 0;
+}
+
+
+
+///////////////////////////////////////////////////////////////////
+// Gateways to Python
+
+PyObject *gravity(PyObject *self, PyObject *args) {
+  //
+  //  gravity(g, h, v, x, xmom, ymom)
+  //
+
+
+  PyArrayObject *h, *v, *x, *xmom, *ymom;
+  int k, i, N, k3, k6;
+  double g, avg_h, zx, zy;
+  double x0, y0, x1, y1, x2, y2, z0, z1, z2;
+
+  if (!PyArg_ParseTuple(args, "dOOOOO",
+			&g, &h, &v, &x,
+			&xmom, &ymom))
+    return NULL;
+
+  N = h -> dimensions[0];
+  for (k=0; k<N; k++) {
+    k3 = 3*k;  // base index
+    k6 = 6*k;  // base index
+
+    avg_h = 0.0;
+    for (i=0; i<3; i++) {
+      avg_h += ((double *) h -> data)[k3+i];
+    }
+    avg_h /= 3;
+
+
+    //Compute bed slope
+    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];
+
+
+    z0 = ((double*) v -> data)[k3 + 0];
+    z1 = ((double*) v -> data)[k3 + 1];
+    z2 = ((double*) v -> data)[k3 + 2];
+
+    _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy);
+
+    //Update momentum
+    ((double*) xmom -> data)[k] += -g*zx*avg_h;
+    ((double*) ymom -> data)[k] += -g*zy*avg_h;
+  }
+
+  return Py_BuildValue("");
+}
+
+
+PyObject *manning_friction(PyObject *self, PyObject *args) {
+  //
+  // manning_friction(g, eps, h, uh, vh, eta, xmom_update, ymom_update)
+  //
+
+
+  PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom;
+  int N;
+  double g, eps;
+
+  if (!PyArg_ParseTuple(args, "ddOOOOOOO",
+			&g, &eps, &w, &z, &uh, &vh, &eta,
+			&xmom, &ymom))
+    return NULL;
+
+  N = w -> dimensions[0];
+  _manning_friction(g, eps, N,
+		    (double*) w -> data,
+		    (double*) z -> data,
+		    (double*) uh -> data,
+		    (double*) vh -> data,
+		    (double*) eta -> data,
+		    (double*) xmom -> data,
+		    (double*) ymom -> data);
+
+  return Py_BuildValue("");
+}
+
+PyObject *extrapolate_second_order_sw(PyObject *self, PyObject *args) {
+  /*Compute the vertex values based on a linear reconstruction on each triangle
+    These values are calculated as follows:
+    1) For each triangle not adjacent to a boundary, we consider the auxiliary triangle
+    formed by the centroids of its three neighbours.
+    2) For each conserved quantity, we integrate around the auxiliary triangle's boundary the product
+    of the quantity and the outward normal vector. Dividing by the triangle area gives (a,b), the average
+    of the vector (q_x,q_y) on the auxiliary triangle. We suppose that the linear reconstruction on the
+    original triangle has gradient (a,b).
+    3) Provisional vertex junmps dqv[0,1,2] are computed and these are then limited by calling the functions
+    find_qmin_and_qmax and limit_gradient
+
+    Python call:
+    extrapolate_second_order_sw(domain.surrogate_neighbours,
+                                domain.number_of_boundaries
+                                domain.centroid_coordinates,
+                                Stage.centroid_values
+                                Xmom.centroid_values
+                                Ymom.centroid_values
+                                domain.vertex_coordinates,
+                                Stage.vertex_values,
+                                Xmom.vertex_values,
+                                Ymom.vertex_values)
+
+    Post conditions:
+            The vertices of each triangle have values from a limited linear reconstruction
+	    based on centroid values
+
+  */
+  PyArrayObject *surrogate_neighbours,
+    *number_of_boundaries,
+    *centroid_coordinates,
+    *stage_centroid_values,
+    *xmom_centroid_values,
+    *ymom_centroid_values,
+    *vertex_coordinates,
+    *stage_vertex_values,
+    *xmom_vertex_values,
+    *ymom_vertex_values;
+  PyObject *domain, *Tmp;
+  //Local variables
+  double a, b;//gradient vector, not stored but used to calculate vertex values from centroids
+  int number_of_elements,k,k0,k1,k2,k3,k6,coord_index,i;
+  double x,y,x0,y0,x1,y1,x2,y2,xv0,yv0,xv1,yv1,xv2,yv2;//vertices of the auxiliary triangle
+  double dx1,dx2,dy1,dy2,dxv0,dxv1,dxv2,dyv0,dyv1,dyv2,dq0,dq1,dq2,area2;
+  double dqv[3], qmin, qmax, beta_w;//provisional jumps from centroids to v'tices and safety factor re limiting
+  //by which these jumps are limited
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "OOOOOOOOOOO",
+			&domain,
+			&surrogate_neighbours,
+			&number_of_boundaries,
+			&centroid_coordinates,
+			&stage_centroid_values,
+			&xmom_centroid_values,
+			&ymom_centroid_values,
+			&vertex_coordinates,
+			&stage_vertex_values,
+			&xmom_vertex_values,
+			&ymom_vertex_values)) {
+    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
+    return NULL;
+  }
+
+  //get the safety factor beta_w, set in the config.py file. This is used in the limiting process
+  Tmp = PyObject_GetAttrString(domain, "beta_w");
+  if (!Tmp)
+    return NULL;
+  beta_w = PyFloat_AsDouble(Tmp);
+  Py_DECREF(Tmp);
+  number_of_elements = stage_centroid_values -> dimensions[0];
+  for (k=0; k<number_of_elements; k++) {
+    k3=k*3;
+    k6=k*6;
+
+    if (((long *) number_of_boundaries->data)[k]==3){/*no neighbours, set gradient on the triangle to zero*/
+      ((double *) stage_vertex_values->data)[k3]=((double *)stage_centroid_values->data)[k];
+      ((double *) stage_vertex_values->data)[k3+1]=((double *)stage_centroid_values->data)[k];
+      ((double *) stage_vertex_values->data)[k3+2]=((double *)stage_centroid_values->data)[k];
+      ((double *) xmom_vertex_values->data)[k3]=((double *)xmom_centroid_values->data)[k];
+      ((double *) xmom_vertex_values->data)[k3+1]=((double *)xmom_centroid_values->data)[k];
+      ((double *) xmom_vertex_values->data)[k3+2]=((double *)xmom_centroid_values->data)[k];
+      ((double *) ymom_vertex_values->data)[k3]=((double *)ymom_centroid_values->data)[k];
+      ((double *) ymom_vertex_values->data)[k3+1]=((double *)ymom_centroid_values->data)[k];
+      ((double *) ymom_vertex_values->data)[k3+2]=((double *)ymom_centroid_values->data)[k];
+      continue;
+    }
+    else {//we will need centroid coordinates and vertex coordinates of the triangle
+      //get the vertex coordinates of the FV triangle
+      xv0=((double *)vertex_coordinates->data)[k6]; yv0=((double *)vertex_coordinates->data)[k6+1];
+      xv1=((double *)vertex_coordinates->data)[k6+2]; yv1=((double *)vertex_coordinates->data)[k6+3];
+      xv2=((double *)vertex_coordinates->data)[k6+4]; yv2=((double *)vertex_coordinates->data)[k6+5];
+      //get the centroid coordinates of the FV triangle
+      coord_index=2*k;
+      x=((double *)centroid_coordinates->data)[coord_index];
+      y=((double *)centroid_coordinates->data)[coord_index+1];
+      //store x- and y- differentials for the vertices of the FV triangle relative to the centroid
+      dxv0=xv0-x; dxv1=xv1-x; dxv2=xv2-x;
+      dyv0=yv0-y; dyv1=yv1-y; dyv2=yv2-y;
+    }
+    if (((long *)number_of_boundaries->data)[k]<=1){
+      //if no boundaries, auxiliary triangle is formed from the centroids of the three neighbours
+      //if one boundary, auxiliary triangle is formed from this centroid and its two neighbours
+      k0=((long *)surrogate_neighbours->data)[k3];
+      k1=((long *)surrogate_neighbours->data)[k3+1];
+      k2=((long *)surrogate_neighbours->data)[k3+2];
+      //get the auxiliary triangle's vertex coordinates (really the centroids of neighbouring triangles)
+      coord_index=2*k0;
+      x0=((double *)centroid_coordinates->data)[coord_index];
+      y0=((double *)centroid_coordinates->data)[coord_index+1];
+      coord_index=2*k1;
+      x1=((double *)centroid_coordinates->data)[coord_index];
+      y1=((double *)centroid_coordinates->data)[coord_index+1];
+      coord_index=2*k2;
+      x2=((double *)centroid_coordinates->data)[coord_index];
+      y2=((double *)centroid_coordinates->data)[coord_index+1];
+      //store x- and y- differentials for the vertices of the auxiliary triangle
+      dx1=x1-x0; dx2=x2-x0;
+      dy1=y1-y0; dy2=y2-y0;
+      //calculate 2*area of the auxiliary triangle
+      area2 = dy2*dx1 - dy1*dx2;//the triangle is guaranteed to be counter-clockwise
+      //If the mesh is 'weird' near the boundary, the trianlge might be flat or clockwise:
+      if (area2<=0)
+	return NULL;
+
+      //### stage ###
+      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
+      dq0=((double *)stage_centroid_values->data)[k0]-((double *)stage_centroid_values->data)[k];
+      //calculate differentials between the vertices of the auxiliary triangle
+      dq1=((double *)stage_centroid_values->data)[k1]-((double *)stage_centroid_values->data)[k0];
+      dq2=((double *)stage_centroid_values->data)[k2]-((double *)stage_centroid_values->data)[k0];
+      //calculate the gradient of stage on the auxiliary triangle
+      a = dy2*dq1 - dy1*dq2;
+      a /= area2;
+      b = dx1*dq2 - dx2*dq1;
+      b /= area2;
+      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
+      dqv[0]=a*dxv0+b*dyv0;
+      dqv[1]=a*dxv1+b*dyv1;
+      dqv[2]=a*dxv2+b*dyv2;
+      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
+      //and compute jumps from the centroid to the min and max
+      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
+      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
+      for (i=0;i<3;i++)
+	((double *)stage_vertex_values->data)[k3+i]=((double *)stage_centroid_values->data)[k]+dqv[i];
+
+      //### xmom ###
+      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
+      dq0=((double *)xmom_centroid_values->data)[k0]-((double *)xmom_centroid_values->data)[k];
+      //calculate differentials between the vertices of the auxiliary triangle
+      dq1=((double *)xmom_centroid_values->data)[k1]-((double *)xmom_centroid_values->data)[k0];
+      dq2=((double *)xmom_centroid_values->data)[k2]-((double *)xmom_centroid_values->data)[k0];
+      //calculate the gradient of xmom on the auxiliary triangle
+      a = dy2*dq1 - dy1*dq2;
+      a /= area2;
+      b = dx1*dq2 - dx2*dq1;
+      b /= area2;
+      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
+      dqv[0]=a*dxv0+b*dyv0;
+      dqv[1]=a*dxv1+b*dyv1;
+      dqv[2]=a*dxv2+b*dyv2;
+      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
+      //and compute jumps from the centroid to the min and max
+      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
+      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
+      for (i=0;i<3;i++)
+	((double *)xmom_vertex_values->data)[k3+i]=((double *)xmom_centroid_values->data)[k]+dqv[i];
+
+      //### ymom ###
+      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
+      dq0=((double *)ymom_centroid_values->data)[k0]-((double *)ymom_centroid_values->data)[k];
+      //calculate differentials between the vertices of the auxiliary triangle
+      dq1=((double *)ymom_centroid_values->data)[k1]-((double *)ymom_centroid_values->data)[k0];
+      dq2=((double *)ymom_centroid_values->data)[k2]-((double *)ymom_centroid_values->data)[k0];
+      //calculate the gradient of xmom on the auxiliary triangle
+      a = dy2*dq1 - dy1*dq2;
+      a /= area2;
+      b = dx1*dq2 - dx2*dq1;
+      b /= area2;
+      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
+      dqv[0]=a*dxv0+b*dyv0;
+      dqv[1]=a*dxv1+b*dyv1;
+      dqv[2]=a*dxv2+b*dyv2;
+      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
+      //and compute jumps from the centroid to the min and max
+      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
+      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
+      for (i=0;i<3;i++)
+	((double *)ymom_vertex_values->data)[k3+i]=((double *)ymom_centroid_values->data)[k]+dqv[i];
+    }//if (number_of_boundaries[k]<=1)
+    else{//number_of_boundaries==2
+      //one internal neighbour and gradient is in direction of the neighbour's centroid
+      //find the only internal neighbour
+      for (k2=k3;k2<k3+3;k2++){//k2 just indexes the edges of triangle k
+	if (((long *)surrogate_neighbours->data)[k2]!=k)//find internal neighbour of triabngle k
+	  break;
+      }
+      if ((k2==k3+3))//if we didn't find an internal neighbour
+	return NULL;//error
+      k1=((long *)surrogate_neighbours->data)[k2];
+      //the coordinates of the triangle are already (x,y). Get centroid of the neighbour (x1,y1)
+      coord_index=2*k1;
+      x1=((double *)centroid_coordinates->data)[coord_index];
+      y1=((double *)centroid_coordinates->data)[coord_index+1];
+      //compute x- and y- distances between the centroid of the FV triangle and that of its neighbour
+      dx1=x1-x; dy1=y1-y;
+      //set area2 as the square of the distance
+      area2=dx1*dx1+dy1*dy1;
+      //set dx2=(x1-x0)/((x1-x0)^2+(y1-y0)^2) and dy2=(y1-y0)/((x1-x0)^2+(y1-y0)^2) which
+      //respectively correspond to the x- and y- gradients of the conserved quantities
+      dx2=1.0/area2;
+      dy2=dx2*dy1;
+      dx2*=dx1;
+
+      //## stage ###
+      //compute differentials
+      dq1=((double *)stage_centroid_values->data)[k1]-((double *)stage_centroid_values->data)[k];
+      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
+      a=dq1*dx2;
+      b=dq1*dy2;
+      //calculate provisional vertex jumps, to be limited
+      dqv[0]=a*dxv0+b*dyv0;
+      dqv[1]=a*dxv1+b*dyv1;
+      dqv[2]=a*dxv2+b*dyv2;
+      //now limit the jumps
+      if (dq1>=0.0){
+	qmin=0.0;
+	qmax=dq1;
+      }
+      else{
+	qmin=dq1;
+	qmax=0.0;
+      }
+      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
+      for (i=0;i<3;i++)
+	((double *)stage_vertex_values->data)[k3+i]=((double *)stage_centroid_values->data)[k]+dqv[i];
+
+      //## xmom ###
+      //compute differentials
+      dq1=((double *)xmom_centroid_values->data)[k1]-((double *)xmom_centroid_values->data)[k];
+      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
+      a=dq1*dx2;
+      b=dq1*dy2;
+      //calculate provisional vertex jumps, to be limited
+      dqv[0]=a*dxv0+b*dyv0;
+      dqv[1]=a*dxv1+b*dyv1;
+      dqv[2]=a*dxv2+b*dyv2;
+      //now limit the jumps
+      if (dq1>=0.0){
+	qmin=0.0;
+	qmax=dq1;
+      }
+      else{
+	qmin=dq1;
+	qmax=0.0;
+      }
+      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
+      for (i=0;i<3;i++)
+	((double *)xmom_vertex_values->data)[k3+i]=((double *)xmom_centroid_values->data)[k]+dqv[i];
+
+      //## ymom ###
+      //compute differentials
+      dq1=((double *)ymom_centroid_values->data)[k1]-((double *)ymom_centroid_values->data)[k];
+      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
+      a=dq1*dx2;
+      b=dq1*dy2;
+      //calculate provisional vertex jumps, to be limited
+      dqv[0]=a*dxv0+b*dyv0;
+      dqv[1]=a*dxv1+b*dyv1;
+      dqv[2]=a*dxv2+b*dyv2;
+      //now limit the jumps
+      if (dq1>=0.0){
+	qmin=0.0;
+	qmax=dq1;
+      }
+      else{
+	qmin=dq1;
+	qmax=0.0;
+      }
+      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
+      for (i=0;i<3;i++)
+	((double *)ymom_vertex_values->data)[k3+i]=((double *)ymom_centroid_values->data)[k]+dqv[i];
+    }//else [number_of_boudaries==2]
+  }//for k=0 to number_of_elements-1
+  return Py_BuildValue("");
+}//extrapolate_second-order_sw
+
+PyObject *rotate(PyObject *self, PyObject *args, PyObject *kwargs) {
+  //
+  // r = rotate(q, normal, direction=1)
+  //
+  // Where q is assumed to be a Float numeric array of length 3 and
+  // normal a Float numeric array of length 2.
+
+
+  PyObject *Q, *Normal;
+  PyArrayObject *q, *r, *normal;
+
+  static char *argnames[] = {"q", "normal", "direction", NULL};
+  int dimensions[1], i, direction=1;
+  double n1, n2;
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames,
+				   &Q, &Normal, &direction))
+    return NULL;
+
+  //Input checks (convert sequences into numeric arrays)
+  q = (PyArrayObject *)
+    PyArray_ContiguousFromObject(Q, PyArray_DOUBLE, 0, 0);
+  normal = (PyArrayObject *)
+    PyArray_ContiguousFromObject(Normal, PyArray_DOUBLE, 0, 0);
+
+
+  if (normal -> dimensions[0] != 2) {
+    PyErr_SetString(PyExc_RuntimeError, "Normal vector must have 2 components");
+    return NULL;
+  }
+
+  //Allocate space for return vector r (don't DECREF)
+  dimensions[0] = 3;
+  r = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
+
+  //Copy
+  for (i=0; i<3; i++) {
+    ((double *) (r -> data))[i] = ((double *) (q -> data))[i];
+  }
+
+  //Get normal and direction
+  n1 = ((double *) normal -> data)[0];
+  n2 = ((double *) normal -> data)[1];
+  if (direction == -1) n2 = -n2;
+
+  //Rotate
+  _rotate((double *) r -> data, n1, n2);
+
+  //Release numeric arrays
+  Py_DECREF(q);
+  Py_DECREF(normal);
+
+  //return result using PyArray to avoid memory leak
+  return PyArray_Return(r);
+}
+
+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"
+
+    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:
+    domain.timestep = compute_fluxes(timestep,
+                                     domain.epsilon,
+                                     domain.g,
+                                     domain.neighbours,
+                                     domain.neighbour_edges,
+                                     domain.normals,
+                                     domain.edgelengths,
+                                     domain.radii,
+                                     domain.areas,
+                                     Stage.edge_values,
+                                     Xmom.edge_values,
+                                     Ymom.edge_values,
+                                     Bed.edge_values,
+                                     Stage.boundary_values,
+                                     Xmom.boundary_values,
+                                     Ymom.boundary_values,
+                                     Stage.explicit_update,
+                                     Xmom.explicit_update,
+                                     Ymom.explicit_update,
+                                     already_computed_flux)
+
+
+    Post conditions:
+      domain.explicit_update is reset to computed flux values
+      domain.timestep is set to the largest step satisfying all volumes.
+
+
+  */
+
+
+  PyArrayObject *neighbours, *neighbour_edges,
+    *normals, *edgelengths, *radii, *areas,
+    *stage_edge_values,
+    *xmom_edge_values,
+    *ymom_edge_values,
+    *bed_edge_values,
+    *stage_boundary_values,
+    *xmom_boundary_values,
+    *ymom_boundary_values,
+    *stage_explicit_update,
+    *xmom_explicit_update,
+    *ymom_explicit_update,
+    *already_computed_flux;//tracks whether the flux across an edge has already been computed
+
+
+  //Local variables
+  double timestep, max_speed, epsilon, g;
+  double normal[2], ql[3], qr[3], zl, zr;
+  double edgeflux[3]; //Work arrays for summing up fluxes
+
+  int number_of_elements, k, i, m, n;
+  int ki, nm=0, ki2; //Index shorthands
+  static long call=1;
+
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOOOOOOO",
+			&timestep,
+			&epsilon,
+			&g,
+			&neighbours,
+			&neighbour_edges,
+			&normals,
+			&edgelengths, &radii, &areas,
+			&stage_edge_values,
+			&xmom_edge_values,
+			&ymom_edge_values,
+			&bed_edge_values,
+			&stage_boundary_values,
+			&xmom_boundary_values,
+			&ymom_boundary_values,
+			&stage_explicit_update,
+			&xmom_explicit_update,
+			&ymom_explicit_update,
+			&already_computed_flux)) {
+    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
+    return NULL;
+  }
+  number_of_elements = stage_edge_values -> dimensions[0];
+  call++;//a static local variable to which already_computed_flux is compared
+  //set explicit_update to zero for all conserved_quantities.
+  //This assumes compute_fluxes called before forcing terms
+  for (k=0; k<number_of_elements; k++) {
+    ((double *) stage_explicit_update -> data)[k]=0.0;
+    ((double *) xmom_explicit_update -> data)[k]=0.0;
+    ((double *) ymom_explicit_update -> data)[k]=0.0;
+  }
+  //Loop through neighbours and compute edge flux for each
+  for (k=0; k<number_of_elements; k++) {
+    for (i=0; i<3; i++) {
+      ki = k*3+i;
+      if (((long *) already_computed_flux->data)[ki]==call)//we've already computed the flux across this edge
+	continue;
+      ql[0] = ((double *) stage_edge_values -> data)[ki];
+      ql[1] = ((double *) xmom_edge_values -> data)[ki];
+      ql[2] = ((double *) ymom_edge_values -> data)[ki];
+      zl =    ((double *) bed_edge_values -> data)[ki];
+
+      //Quantities at neighbour on nearest face
+      n = ((long *) neighbours -> data)[ki];
+      if (n < 0) {
+	m = -n-1; //Convert negative flag to index
+	qr[0] = ((double *) stage_boundary_values -> data)[m];
+	qr[1] = ((double *) xmom_boundary_values -> data)[m];
+	qr[2] = ((double *) ymom_boundary_values -> data)[m];
+	zr = zl; //Extend bed elevation to boundary
+      } else {
+	m = ((long *) neighbour_edges -> data)[ki];
+	nm = n*3+m;
+	qr[0] = ((double *) stage_edge_values -> data)[nm];
+	qr[1] = ((double *) xmom_edge_values -> data)[nm];
+	qr[2] = ((double *) ymom_edge_values -> data)[nm];
+	zr =    ((double *) bed_edge_values -> data)[nm];
+      }
+      // Outward pointing normal vector
+      // normal = domain.normals[k, 2*i:2*i+2]
+      ki2 = 2*ki; //k*6 + i*2
+      normal[0] = ((double *) normals -> data)[ki2];
+      normal[1] = ((double *) normals -> data)[ki2+1];
+      //Edge flux computation
+      flux_function_kinetic(ql, qr, zl, zr,
+		    normal[0], normal[1],
+		    epsilon, g,
+		    edgeflux, &max_speed);
+      //update triangle k
+      ((long *) already_computed_flux->data)[ki]=call;
+      ((double *) stage_explicit_update -> data)[k] -= edgeflux[0]*((double *) edgelengths -> data)[ki];
+      ((double *) xmom_explicit_update -> data)[k] -= edgeflux[1]*((double *) edgelengths -> data)[ki];
+      ((double *) ymom_explicit_update -> data)[k] -= edgeflux[2]*((double *) edgelengths -> data)[ki];
+      //update the neighbour n
+      if (n>=0){
+	((long *) already_computed_flux->data)[nm]=call;
+	((double *) stage_explicit_update -> data)[n] += edgeflux[0]*((double *) edgelengths -> data)[nm];
+	((double *) xmom_explicit_update -> data)[n] += edgeflux[1]*((double *) edgelengths -> data)[nm];
+	((double *) ymom_explicit_update -> data)[n] += edgeflux[2]*((double *) edgelengths -> data)[nm];
+      }
+      ///for (j=0; j<3; j++) {
+	///flux[j] -= edgeflux[j]*((double *) edgelengths -> data)[ki];
+	///}
+	//Update timestep
+	//timestep = min(timestep, domain.radii[k]/max_speed)
+	//FIXME: SR Add parameter for CFL condition
+	if (max_speed > epsilon) {
+	  timestep = min(timestep, ((double *) radii -> data)[k]/max_speed);
+	  //maxspeed in flux_function is calculated as max(|u+a|,|u-a|)
+	  if (n>=0)
+	    timestep = min(timestep, ((double *) radii -> data)[n]/max_speed);
+	}
+    } // end for i
+    //Normalise by area and store for when all conserved
+    //quantities get updated
+    ((double *) stage_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
+    ((double *) xmom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
+    ((double *) ymom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
+  } //end for k
+  return Py_BuildValue("d", timestep);
+}
+
+PyObject *protect(PyObject *self, PyObject *args) {
+  //
+  //    protect(minimum_allowed_height, wc, zc, xmomc, ymomc)
+
+
+  PyArrayObject
+  *wc,            //Stage at centroids
+  *zc,            //Elevation at centroids
+  *xmomc,         //Momentums at centroids
+  *ymomc;
+
+
+  int N;
+  double minimum_allowed_height, epsilon;
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "ddOOOO",
+			&minimum_allowed_height,
+			&epsilon,
+			&wc, &zc, &xmomc, &ymomc))
+    return NULL;
+
+  N = wc -> dimensions[0];
+
+  _protect(N,
+	   minimum_allowed_height,
+	   epsilon,
+	   (double*) wc -> data,
+	   (double*) zc -> data,
+	   (double*) xmomc -> data,
+	   (double*) ymomc -> data);
+
+  return Py_BuildValue("");
+}
+
+
+
+PyObject *balance_deep_and_shallow(PyObject *self, PyObject *args) {
+  //
+  //    balance_deep_and_shallow(wc, zc, hc, wv, zv, hv,
+  //                             xmomc, ymomc, xmomv, ymomv)
+
+
+  PyArrayObject
+    *wc,            //Stage at centroids
+    *zc,            //Elevation at centroids
+    *hc,            //Height at centroids
+    *wv,            //Stage at vertices
+    *zv,            //Elevation at vertices
+    *hv,            //Depths at vertices
+    *hvbar,         //h-Limited depths at vertices
+    *xmomc,         //Momentums at centroids and vertices
+    *ymomc,
+    *xmomv,
+    *ymomv;
+
+  int N; //, err;
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "OOOOOOOOOOO",
+			&wc, &zc, &hc,
+			&wv, &zv, &hv, &hvbar,
+			&xmomc, &ymomc, &xmomv, &ymomv))
+    return NULL;
+
+  N = wc -> dimensions[0];
+
+  _balance_deep_and_shallow(N,
+			    (double*) wc -> data,
+			    (double*) zc -> data,
+			    (double*) hc -> data,
+			    (double*) wv -> data,
+			    (double*) zv -> data,
+			    (double*) hv -> data,
+			    (double*) hvbar -> data,
+                            (double*) xmomc -> data,
+			    (double*) ymomc -> data,
+			    (double*) xmomv -> data,
+			    (double*) ymomv -> data);
+
+
+  return Py_BuildValue("");
+}
+
+
+
+PyObject *h_limiter(PyObject *self, PyObject *args) {
+
+  PyObject *domain, *Tmp;
+  PyArrayObject
+    *hv, *hc, //Depth at vertices and centroids
+    *hvbar,   //Limited depth at vertices (return values)
+    *neighbours;
+
+  int k, i, n, N, k3;
+  int dimensions[2];
+  double beta_h; //Safety factor (see config.py)
+  double *hmin, *hmax, hn;
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv))
+    return NULL;
+
+  neighbours = get_consecutive_array(domain, "neighbours");
+
+  //Get safety factor beta_h
+  Tmp = PyObject_GetAttrString(domain, "beta_h");
+  if (!Tmp)
+    return NULL;
+
+  beta_h = PyFloat_AsDouble(Tmp);
+
+  Py_DECREF(Tmp);
+
+  N = hc -> dimensions[0];
+
+  //Create hvbar
+  dimensions[0] = N;
+  dimensions[1] = 3;
+  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
+
+
+  //Find min and max of this and neighbour's centroid values
+  hmin = malloc(N * sizeof(double));
+  hmax = malloc(N * sizeof(double));
+  for (k=0; k<N; k++) {
+    k3=k*3;
+
+    hmin[k] = ((double*) hc -> data)[k];
+    hmax[k] = hmin[k];
+
+    for (i=0; i<3; i++) {
+      n = ((long*) neighbours -> data)[k3+i];
+
+      //Initialise hvbar with values from hv
+      ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i];
+
+      if (n >= 0) {
+	hn = ((double*) hc -> data)[n]; //Neighbour's centroid value
+
+	hmin[k] = min(hmin[k], hn);
+	hmax[k] = max(hmax[k], hn);
+      }
+    }
+  }
+
+  // Call underlying standard routine
+  _limit(N, beta_h, (double*) hc -> data, (double*) hvbar -> data, hmin, hmax);
+
+  // // //Py_DECREF(domain); //FIXME: NEcessary?
+  free(hmin);
+  free(hmax);
+
+  //return result using PyArray to avoid memory leak
+  return PyArray_Return(hvbar);
+  //return Py_BuildValue("");
+}
+
+PyObject *h_limiter_sw(PyObject *self, PyObject *args) {
+  //a faster version of h_limiter above
+  PyObject *domain, *Tmp;
+  PyArrayObject
+    *hv, *hc, //Depth at vertices and centroids
+    *hvbar,   //Limited depth at vertices (return values)
+    *neighbours;
+
+  int k, i, N, k3,k0,k1,k2;
+  int dimensions[2];
+  double beta_h; //Safety factor (see config.py)
+  double hmin, hmax, dh[3];
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv))
+    return NULL;
+  neighbours = get_consecutive_array(domain, "neighbours");
+
+  //Get safety factor beta_h
+  Tmp = PyObject_GetAttrString(domain, "beta_h");
+  if (!Tmp)
+    return NULL;
+  beta_h = PyFloat_AsDouble(Tmp);
+
+  Py_DECREF(Tmp);
+
+  N = hc -> dimensions[0];
+
+  //Create hvbar
+  dimensions[0] = N;
+  dimensions[1] = 3;
+  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
+  for (k=0;k<N;k++){
+    k3=k*3;
+    //get the ids of the neighbours
+    k0 = ((long*) neighbours -> data)[k3];
+    k1 = ((long*) neighbours -> data)[k3+1];
+    k2 = ((long*) neighbours -> data)[k3+2];
+    //set hvbar provisionally
+    for (i=0;i<3;i++){
+      ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i];
+      dh[i]=((double*) hvbar -> data)[k3+i]-((double*) hc -> data)[k];
+    }
+    hmin=((double*) hc -> data)[k];
+    hmax=hmin;
+    if (k0>=0){
+      hmin=min(hmin,((double*) hc -> data)[k0]);
+      hmax=max(hmax,((double*) hc -> data)[k0]);
+    }
+    if (k1>=0){
+      hmin=min(hmin,((double*) hc -> data)[k1]);
+      hmax=max(hmax,((double*) hc -> data)[k1]);
+    }
+    if (k2>=0){
+      hmin=min(hmin,((double*) hc -> data)[k2]);
+      hmax=max(hmax,((double*) hc -> data)[k2]);
+    }
+    hmin-=((double*) hc -> data)[k];
+    hmax-=((double*) hc -> data)[k];
+    limit_gradient(dh,hmin,hmax,beta_h);
+    for (i=0;i<3;i++)
+      ((double*) hvbar -> data)[k3+i] = ((double*) hc -> data)[k]+dh[i];
+  }
+  return PyArray_Return(hvbar);
+}
+
+PyObject *assign_windfield_values(PyObject *self, PyObject *args) {
+  //
+  //      assign_windfield_values(xmom_update, ymom_update,
+  //                              s_vec, phi_vec, self.const)
+
+
+
+  PyArrayObject   //(one element per triangle)
+  *s_vec,         //Speeds
+  *phi_vec,       //Bearings
+  *xmom_update,   //Momentum updates
+  *ymom_update;
+
+
+  int N;
+  double cw;
+
+  // Convert Python arguments to C
+  if (!PyArg_ParseTuple(args, "OOOOd",
+			&xmom_update,
+			&ymom_update,
+			&s_vec, &phi_vec,
+			&cw))
+    return NULL;
+
+  N = xmom_update -> dimensions[0];
+
+  _assign_wind_field_values(N,
+	   (double*) xmom_update -> data,
+	   (double*) ymom_update -> data,
+	   (double*) s_vec -> data,
+	   (double*) phi_vec -> data,
+	   cw);
+
+  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.
+   */
+
+  {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
+  {"extrapolate_second_order_sw", extrapolate_second_order_sw, METH_VARARGS, "Print out"},
+  {"compute_fluxes", compute_fluxes, METH_VARARGS, "Print out"},
+  {"gravity", gravity, METH_VARARGS, "Print out"},
+  {"manning_friction", manning_friction, METH_VARARGS, "Print out"},
+  {"balance_deep_and_shallow", balance_deep_and_shallow,
+   METH_VARARGS, "Print out"},
+  {"h_limiter", h_limiter,
+   METH_VARARGS, "Print out"},
+  {"h_limiter_sw", h_limiter_sw,
+   METH_VARARGS, "Print out"},
+  {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"},
+  {"assign_windfield_values", assign_windfield_values,
+   METH_VARARGS | METH_KEYWORDS, "Print out"},
+  //{"distribute_to_vertices_and_edges",
+  // distribute_to_vertices_and_edges, METH_VARARGS},
+  //{"update_conserved_quantities",
+  // update_conserved_quantities, METH_VARARGS},
+  //{"set_initialcondition",
+  // set_initialcondition, METH_VARARGS},
+  {NULL, NULL}
+};
+
+// Module initialisation
+void initshallow_water_kinetic_ext(void){
+  Py_InitModule("shallow_water_kinetic_ext", MethodTable);
+
+  import_array();     //Necessary for handling of NumPY structures
+}
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/shallow_water_vtk.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/shallow_water_vtk.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/shallow_water_vtk.py	(revision 3560)
@@ -0,0 +1,120 @@
+"""
+Shallow water domain with VTK viewer. We are just over
+
+Ole Nielsen, Duncan Gray
+Geoscience Australia, 2006
+
+Stephen Roberts,  Jack Kelly
+ANU 2006
+"""
+
+#Subversion keywords:
+#
+#$LastChangedDate: 2006-01-13 12:33:38 +1100 (Fri, 13 Jan 2006) $
+#$LastChangedRevision: 2205 $
+#$LastChangedBy: steve $
+
+
+from shallow_water import *
+Shallow_Water_Domain = Domain #Rename
+
+#Shallow water domain with VTK viewer
+class Domain(Shallow_Water_Domain):
+
+    def __init__(self, coordinates, vertices, boundary = None,
+                 tagged_elements = None, geo_reference = None,
+                 use_inscribed_circle=False):
+
+        Shallow_Water_Domain.__init__(self, coordinates, vertices, boundary,
+                                tagged_elements, geo_reference, use_inscribed_circle)
+
+
+
+    def initialise_visualiser(self,scale_z=1.0,rect=None):
+        #Realtime visualisation
+        if self.visualiser is None:
+            from vtk_realtime_visualiser import Visualiser
+            self.visualiser = Visualiser(self,scale_z,rect)
+            self.visualiser.coloring['stage'] = False
+            self.visualiser.coloring['elevation'] = False
+            self.visualiser.setup['elevation']=True
+            self.visualiser.updating['stage']=True
+            self.visualiser.qcolor['stage'] = (0.1,0.4,0.99)
+        self.visualise = True
+        if self.visualise_color_stage == True:
+            self.visualiser.coloring['stage'] = True
+            
+
+
+
+    def evolve(self,
+               yieldstep = None,
+               finaltime = None,
+               duration = None,
+               skip_initial_step = False):
+        """Specialisation of basic evolve method from parent class
+        """
+
+        import time
+        first = True
+        #Call check integrity here rather than from user scripts
+        #self.check_integrity()
+
+        msg = 'Parameter beta_h must be in the interval [0, 1['
+        assert 0 <= self.beta_h < 1.0, msg
+        msg = 'Parameter beta_w must be in the interval [0, 1['
+        assert 0 <= self.beta_w < 1.0, msg
+
+        self.distribute_to_vertices_and_edges()
+
+        #Initialise real time viz if requested
+        if self.visualise is True and self.time == 0.0 and self.visualiser is None:
+            self.initialise_visualiser()
+            #self.visualiser.update_timer()
+            print "Warning: Enabling the visualiser with domain.visualise is not"
+            print "recommended. Controlling the visualiser manually allows for much better"
+            print "control over visualiser parameters."
+
+        if self.visualise is True:
+            self.visualiser.start()
+            # Things go haywire if we start evolving before the vis is ready
+            self.visualiser.idle.wait()
+            self.visualiser.idle.clear()
+
+        #Store model data, e.g. for visualisation
+        if self.store is True and self.time == 0.0:
+            self.initialise_storage()
+            #print 'Storing results in ' + self.writer.filename
+        else:
+            pass
+
+        #Call basic machinery from parent class
+        for t in Generic_Domain.evolve(self,
+                                       yieldstep=yieldstep,
+                                       finaltime = finaltime,
+                                       duration = duration,
+                                       skip_initial_step = skip_initial_step):
+            #Real time viz
+            if self.visualise is True:
+                self.visualiser.redraw_ready.set()
+                self.visualiser.idle.wait()
+                self.visualiser.idle.clear()
+                self.visualiser.unpaused.wait()
+
+            #Store model data, e.g. for subsequent visualisation
+            if self.store is True:
+                self.store_timestep(self.quantities_to_be_stored)
+
+            #FIXME: Could maybe be taken from specified list
+            #of 'store every step' quantities
+
+            #Pass control on to outer loop for more specific actions
+            yield(t)
+
+#==================================== End of Updated Shallow Water VTK domain =============
+if __name__ == "__main__":
+    pass
+
+# Profiling stuff
+import profile
+profiler = profile.Profile()
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/show_balanced_limiters.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/show_balanced_limiters.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/show_balanced_limiters.py	(revision 3560)
@@ -0,0 +1,90 @@
+"""Example of shallow water wave equation.
+
+Specific methods pertaining to the 2D shallow water equation
+are imported from shallow_water
+for use with the generic finite volume framework
+
+Conserved quantities are h, uh and vh stored as elements 0, 1 and 2 in the
+numerical vector named conserved_quantities.
+"""
+
+######################
+# Module imports 
+#
+from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+     Transmissive_boundary, Time_boundary,\
+     Weir_simple as Weir, Constant_height
+
+from mesh_factory import rectangular
+from Numeric import array
+    
+
+######################
+# Domain
+#
+
+N = 12
+
+print 'Creating domain'
+#Create basic mesh
+points, vertices, boundary = rectangular(N, N/2, len1=1.2,len2=0.6,
+                                         origin=(-0.07, 0))
+
+print 'Number of elements', len(vertices)
+#Create shallow water domain
+domain = Domain(points, vertices, boundary)
+domain.smooth = False
+domain.visualise = False
+domain.visualise = True
+domain.default_order = 2
+domain.filename = 'test_of_pyvolution'
+domain.store = True
+domain.format = 'sww'   #Native netcdf visualisation format
+
+#Set bed-slope and friction
+inflow_stage = 0.1
+manning = 0.1
+Z = Weir(inflow_stage)
+
+print 'Field values'
+domain.set_quantity('elevation', Z)
+domain.set_quantity('friction', manning)
+
+
+######################
+# Boundary conditions
+#
+print 'Boundaries'
+Br = Reflective_boundary(domain)
+Bt = Transmissive_boundary(domain)
+
+#Constant inflow
+Bd = Dirichlet_boundary([inflow_stage, 0.0, 0.0])
+
+#Time dependent inflow
+from math import sin, pi
+Bw = Time_boundary(domain=domain,
+                   f=lambda x: [(1 + sin(x*pi/4))*\
+                                (inflow_stage*(sin(2.5*x*pi)+0.7)),0,0])
+
+#Set boundary conditions
+domain.set_boundary({'left': Bd, 'right': Br, 'bottom': Br, 'top': Br})
+
+                    
+
+######################
+#Initial condition
+#
+print 'Initial condition'
+domain.set_quantity('stage', Constant_height(Z, 0.))
+
+from Numeric import allclose
+
+#Evolve
+for t in domain.evolve(yieldstep = 0.1, finaltime = 30):
+    domain.write_time()
+    domain.boundary_stats(['stage'],'left')
+
+print 'Done'    
+    
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/smf.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/smf.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/smf.py	(revision 3560)
@@ -0,0 +1,426 @@
+#
+# slide_tsunami function
+#
+
+"""This function returns a callable object representing an initial water
+   displacement generated by a submarine sediment slide.
+
+Using input parameters:
+
+Required
+ length  downslope slide length
+ depth   water depth to slide centre of mass
+ slope   bathymetric slope
+
+Optional
+ x0      x origin (0)
+ y0      y origin (0)
+ alpha   angular orientation of slide in xy plane (0)
+ w       slide width (0.25*length)
+ T       slide thickness (0.01*length)
+ g       acceleration due to gravity (9.8)
+ gamma   specific density of sediments (1.85)
+ Cm      added mass coefficient (1)
+ Cd      drag coefficient (1)
+ Cn      friction coefficient (0)
+ psi     (0)
+ dx      offset of second Gaussian (0.2*width of first Gaussian)
+ kappa   multiplier for sech^2 function (3.0)
+ kappad  multiplier for second Gaussian function (0.8)
+ zsmall  an amount near to zero (0.01)
+
+The following parameters are calculated:
+
+ a0      initial acceleration
+ ut      theoretical terminal velocity
+ s0      charactistic distance of motion
+ t0      characteristic time of motion
+ w       initial wavelength of tsunami
+ a2D     2D initial amplitude of tsunami
+ a3D     3D initial amplitude of tsunami
+
+The returned object is a callable double Gaussian function that represents
+the initial water displacement generated by a submarine sediment slide.
+
+Adrian Hitchman
+Geoscience Australia, June 2005
+"""
+
+def slide_tsunami(length, depth, slope, width=None, thickness=None, \
+                  x0=0.0, y0=0.0, alpha=0.0, \
+                  gravity=9.8, gamma=1.85, \
+                  massco=1, dragco=1, frictionco=0, psi=0, \
+                  dx=None, kappa=3.0, kappad=0.8, zsmall=0.01, \
+                  domain=None,
+                  verbose=False):
+
+    from math import sin, tan, radians, pi, sqrt, exp
+
+    if domain is not None:
+        xllcorner = domain.geo_reference.get_xllcorner()
+        yllcorner = domain.geo_reference.get_yllcorner()
+        x0 = x0 - xllcorner  # slump origin (relative)
+        y0 = y0 - yllcorner
+        
+    #if width not provided, set to typical value
+    if width is None:
+        width = 0.25 * length
+
+    #if thickness not provided, set to typical value
+    if thickness is None:
+        thickness = 0.01 * length
+
+    #calculate some parameters of the slide
+
+    sint = sin(radians(slope))
+    tant = tan(radians(slope))
+    tanp = tan(radians(psi))
+
+    a0 = gravity * sint * ((gamma-1)/(gamma+massco)) * (1-(tanp/tant))
+    ut = sqrt((gravity*depth) * (length*sint/depth) \
+                    * (pi*(gamma-1)/(2*dragco)) * (1-(tanp/tant)))
+    s0 = ut**2 / a0
+    t0 = ut / a0
+
+    #calculate some parameters of the water displacement produced by the slide
+
+    w = t0 * sqrt(gravity*depth)
+    a2D = s0 * (0.0574 - (0.0431*sint)) \
+             * (thickness/length) \
+             * ((length*sint/depth)**1.25) \
+             * (1 - exp(-2.2*(gamma-1)))
+    a3D = a2D / (1 + (15.5*sqrt(depth/(length*sint))))
+
+    #a few temporary print statements
+    if verbose is True:
+        print '\nThe slide ...'
+        print '\tLength: ', length
+        print '\tDepth: ', depth
+        print '\tSlope: ', slope
+        print '\tWidth: ', width
+        print '\tThickness: ', thickness
+        print '\tx0: ', x0
+        print '\ty0: ', y0
+        print '\tAlpha: ', alpha
+        print '\tAcceleration: ', a0
+        print '\tTerminal velocity: ', ut
+        print '\tChar time: ', t0
+        print '\tChar distance: ', s0
+        print '\nThe tsunami ...'
+        print '\tWavelength: ', w
+        print '\t2D amplitude: ', a2D
+        print '\t3D amplitude: ', a3D
+
+    #keep an eye on some of the assumptions built into the maths
+
+    if ((slope < 5) or (slope > 30)):
+        if verbose is True:
+            print 'WARNING: slope out of range (5 - 30 degrees) ', slope
+    if ((depth/length < 0.06) or (depth/length > 1.5)):
+        if verbose is True:
+            print  'WARNING: d/b out of range (0.06 - 1.5) ', depth/length
+    if ((thickness/length < 0.008) or (thickness/length > 0.2)):
+        if verbose is True:
+            print 'WARNING: T/b out of range (0.008 - 0.2) ', thickness/length
+    if ((gamma < 1.46) or (gamma > 2.93)):
+        if verbose is True:
+            print 'WARNING: gamma out of range (1.46 - 2.93) ', gamma
+
+    return Double_gaussian(a3D=a3D, wavelength=w, width=width, \
+                           x0=x0, y0=y0, alpha=alpha, \
+                           dx=dx, kappa=kappa, kappad=kappad, zsmall=zsmall)
+
+#
+# slump_tsunami function
+#
+
+"""This function returns a callable object representing an initial water
+   displacement generated by a submarine sediment slump.
+
+Using input parameters:
+
+Required
+ length  downslope slump length
+ depth   water depth to slump centre of mass
+ slope   bathymetric slope
+
+Optional
+ x0      x origin (0)
+ y0      y origin (0)
+ alpha   angular orientation of slide in xy plane (0)
+ w       slump width (1.0*length)
+ T       slump thickness (0.1*length)
+ R       slump radius of curvature (b^2/(8*T))
+ del_phi slump angular displacement (0.48)
+ g       acceleration due to gravity (9.8)
+ gamma   specific density of sediments (1.85)
+ Cm      added mass coefficient (1)
+ Cd      drag coefficient (1)
+ Cn      friction coefficient (0)
+ dx      offset of second Gaussian (0.2*width of first Gaussian)
+ kappa   multiplier for sech^2 function (3.0)
+ kappad  multiplier for second Gaussian function (0.8)
+ zsmall  an amount near to zero (0.01)
+
+The following parameters are calculated:
+
+ a0      initial acceleration
+ um      maximum velocity
+ s0      charactistic distance of motion
+ t0      characteristic time of motion
+ w       initial wavelength of tsunami
+ a2D     2D initial amplitude of tsunami
+ a3D     3D initial amplitude of tsunami
+
+The returned object is a callable double Gaussian function that represents
+the initial water displacement generated by a submarine sediment slump.
+
+Adrian Hitchman
+Geoscience Australia, June 2005
+"""
+
+def slump_tsunami(length, depth, slope, width=None, thickness=None, \
+                  radius=None, dphi=0.48, x0=0.0, y0=0.0, alpha=0.0, \
+                  gravity=9.8, gamma=1.85, \
+                  massco=1, dragco=1, frictionco=0, \
+                  dx=None, kappa=3.0, kappad=1.0, zsmall=0.01, \
+                  domain=None,
+                  verbose=False):
+
+    from math import sin, radians, sqrt
+
+    if domain is not None:
+        xllcorner = domain.geo_reference.get_xllcorner()
+        yllcorner = domain.geo_reference.get_yllcorner()
+        x0 = x0 - xllcorner  # slump origin (relative)
+        y0 = y0 - yllcorner
+
+    #if width not provided, set to typical value
+    if width is None:
+        width = length
+
+    #if thickness not provided, set to typical value
+    if thickness is None:
+        thickness = 0.1 * length
+
+    #if radius not provided, set to typical value
+    if radius is None:
+        radius = length**2 / (8.0 * thickness)
+
+    #calculate some parameters of the slump
+
+    sint = sin(radians(slope))
+
+    s0 = radius * dphi / 2
+    t0 = sqrt((radius*(gamma+massco)) / (gravity*(gamma-1)))
+    a0 = s0 / t0**2
+    um = s0 / t0
+
+    #calculate some parameters of the water displacement produced by the slump
+
+    w = t0 * sqrt(gravity*depth)
+    a2D = s0 * (0.131/sint) \
+             * (thickness/length) \
+             * (length*sint/depth)**1.25 \
+             * (length/radius)**0.63 * dphi**0.39 \
+             * (1.47 - (0.35*(gamma-1))) * (gamma-1)
+    a3D = a2D / (1 + (2.06*sqrt(depth/length)))
+
+    #a few temporary print statements
+    if verbose is True:
+        print '\nThe slump ...'
+        print '\tLength: ', length
+        print '\tDepth: ', depth
+        print '\tSlope: ', slope
+        print '\tWidth: ', width
+        print '\tThickness: ', thickness
+        print '\tRadius: ', radius
+        print '\tDphi: ', dphi
+        print '\tx0: ', x0
+        print '\ty0: ', y0
+        print '\tAlpha: ', alpha
+        print '\tAcceleration: ', a0
+        print '\tMaximum velocity: ', um
+        print '\tChar time: ', t0
+        print '\tChar distance: ', s0
+        print '\nThe tsunami ...'
+        print '\tWavelength: ', w
+        print '\t2D amplitude: ', a2D
+        print '\t3D amplitude: ', a3D
+        print '\tDelta x ', dx
+        print '\tsmall ', zsmall
+        print '\tKappa d ', kappad
+
+    #keep an eye on some of the assumptions built into the maths
+
+    if ((slope < 10) or (slope > 30)):        
+        if verbose is True:
+            print 'WARNING: slope out of range (10 - 30 degrees) ', slope
+    if ((depth/length < 0.34) or (depth/length > 0.5)):     
+        if verbose is True:
+            print  'WARNING: d/b out of range (0.34 - 0.5) ', depth/length
+    if ((thickness/length < 0.10) or (thickness/length > 0.15)):     
+        if verbose is True:
+            print 'WARNING: T/b out of range (0.10 - 0.15) ', thickness/length
+    if ((radius/length < 1.0) or (radius/length > 2.0)):     
+        if verbose is True:
+            print 'WARNING: R/b out of range (1 - 2) ', radius/length
+    if ((dphi < 0.10) or (dphi > 0.52)):     
+        if verbose is True:
+            print 'WARNING: del_phi out of range (0.10 - 0.52) ', dphi
+    if ((gamma < 1.46) or (gamma > 2.93)):     
+        if verbose is True:
+            print 'WARNING: gamma out of range (1.46 - 2.93) ', gamma
+
+    return Double_gaussian(a3D=a3D, wavelength=w, width=width, \
+                           x0=x0, y0=y0, alpha=alpha, \
+                           dx=dx, kappa=kappa, kappad=kappad, zsmall=zsmall)
+
+#
+# Double_gaussian class
+#
+
+"""This is a callable class representing the initial water displacment 
+   generated by a sediment slide or slump.
+
+Using input parameters:
+
+Required
+ w       initial wavelength of tsunami
+ a3D     3D initial amplitude of tsunami
+ width   width of smf
+
+Optional
+ x0      x origin of smf
+ y0      y origin of smf
+ alpha   angular orientation of smf in xy plane (0)
+ dx      offset of second Gaussian (0.2*width of first Gaussian)
+ kappa   multiplier for sech^2 function (3.0)
+ kappad  multiplier for second Gaussian function (0.8)
+ zsmall  an amount near to zero (0.01)
+
+Adrian Hitchman
+Geoscience Australia, June 2005
+"""
+
+class Double_gaussian:
+
+    def __init__(self, a3D, wavelength, width, x0, y0, alpha, \
+                 dx, kappa, kappad, zsmall):
+        self.a3D = a3D
+        self.wavelength = wavelength
+        self.width = width
+        self.x0 = x0
+        self.y0 = y0
+        self.alpha = alpha
+        self.kappa = kappa
+        self.kappad = kappad
+
+        if dx is None:
+            self.determineDX(zsmall=zsmall)
+        else:
+            self.dx = dx
+
+    def __call__(self, x, y):
+        """Make Double_gaussian a callable object.
+
+        If called as a function, this object returns z values representing
+        the initial 3D distribution of water heights at the points (x,y)
+        produced by a submarine mass failure.
+        """
+
+        from math import sin, cos, radians, exp, cosh
+        from Numeric import zeros, Float
+
+        #ensure vectors x and y have the same length
+        N = len(x)
+        assert N == len(y)
+
+        am = self.a3D
+        wa = self.wavelength
+        wi = self.width
+        x0 = self.x0
+        y0 = self.y0
+        alpha = self.alpha
+        dx = self.dx
+        kappa = self.kappa
+        kappad = self.kappad
+        amin = self.find_min(x0,wa,kappad,kappa,dx,am)
+        print 'hello amin', amin
+        #amin = 1.0
+
+        #double Gaussian calculation assumes water displacement is oriented
+        #E-W, so, for displacement at some angle alpha clockwise from the E-W
+        #direction, rotate (x,y) coordinates anti-clockwise by alpha
+
+        cosa = cos(radians(alpha))
+        sina = sin(radians(alpha))
+
+        xr = ((x-x0) * cosa - (y-y0) * sina) + x0
+        yr = ((x-x0) * sina + (y-y0) * cosa) + y0
+
+        z = zeros(N, Float)
+        maxz = 0.0
+        minz = 0.0
+        for i in range(N):
+            try:
+                z[i] =  -am / (amin*(cosh(kappa*(yr[i]-y0)/(wi+wa)))**2) \
+                            * (exp(-((xr[i]-x0)/wa)**2) - \
+                                kappad*exp(-((xr[i]-dx-x0)/wa)**2))
+                if z[i] > maxz: maxz = z[i]
+                if z[i] < minz: minz = z[i]
+                
+            except OverflowError:
+                pass
+
+        print 'max z', maxz
+        print 'min z', minz
+                
+        return z
+
+    def determineDX(self, zsmall):
+        """Determine a suitable offset for the second Gaussian function.
+
+        A suitable offset for the second Gaussian function is taken to
+        be some fraction of the 'width' of the first Gaussian function.
+
+        The 'width' of the first Gaussian is obtained from the range of
+        the x coordinates over which the function takes values from
+        'near zero', through 1, and back to 'near zero'.
+
+        The parameter zsmall passed to this function specifies how much
+        'near zero' is.
+        """
+
+        from math import sqrt, log, e
+
+        a = self.a3D
+        c = self.wavelength
+
+        self.dx = 2.0 * (c * sqrt(-log((zsmall/a),e))) / 5.0
+
+    def find_min(self, x0, wa, kappad, kappa, dx, am):
+        """Determine eta_min to scale eta(x,y)
+        """
+
+        from math import exp, cosh
+
+        step = 10.0
+        x = x0
+        deriv = 10.0
+        tol = 0.001
+        count_max = 1000000
+        c = 0
+        am = 1.0
+
+        while c < count_max and deriv > 0:
+            deriv = (x-x0)*exp(-((x-x0)/wa)**2.0) - \
+                    kappad*(x-dx-x0)*exp(-((x-dx-x0)/wa)**2.0)
+            if deriv < 0: xstar = x
+            x -= step
+            c += 1
+        
+        etastar = -am * (exp(-((xstar-x0)/wa)**2) - \
+                   kappad*exp(-((xstar-dx-x0)/wa)**2))
+
+        return etastar
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_advection.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_advection.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_advection.py	(revision 3560)
@@ -0,0 +1,178 @@
+import sys
+from os import sep
+sys.path.append('..'+sep+'pyvolution')
+
+import unittest
+from math import sqrt, pi
+
+from anuga.config import g, epsilon
+from Numeric import allclose, array, zeros, ones, Float
+from advection import *
+
+
+class Test_Advection(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_init(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, daf, dae
+        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        domain = Domain(points, vertices)
+        domain.check_integrity()
+
+        assert domain.quantities.has_key('stage')
+
+        assert domain.get_conserved_quantities(0, edge=1) == 0.
+
+
+    def test_flux_1_triangle0(self):
+        a = [0.0, 0.5]
+        b = [0.0, 0.0]
+        c = [0.5, 0.5]
+
+        points = [a, b, c]
+        vertices = [ [0,1,2] ]
+        domain = Domain(points, vertices)
+        domain.check_integrity()
+
+
+        #Populate boundary array with dirichlet conditions.
+ 	domain.neighbours = array([[-1,-2,-3]])
+        domain.quantities['stage'].boundary_values[:] = 1.0
+
+	domain.order = 1
+
+	domain.distribute_to_vertices_and_edges() #Use first order default
+
+        domain.check_integrity()
+
+	domain.compute_fluxes()
+        U = -domain.quantities['stage'].explicit_update
+        R = -0.5/domain.areas[0]
+
+        assert U==R, '%s %s' %(U, R)
+
+
+    def test_flux_1_triangle1(self):
+
+        a = [0.0, 0.5]
+        b = [0.0, 0.0]
+        c = [0.5, 0.5]
+
+        points = [a, b, c]
+        vertices = [ [0,1,2] ]
+        domain = Domain(points, vertices)
+        domain.check_integrity()
+
+        domain.set_quantity('stage', [1.0], location='centroids')
+
+	domain.distribute_to_vertices_and_edges()
+        domain.check_integrity()
+
+
+	domain.compute_fluxes()
+        U = -domain.quantities['stage'].explicit_update
+        R = 0.5/domain.areas[0]
+
+        assert U==R, '%s %s' %(U, R)
+
+
+
+    def test_flux_1_triangle2(self):
+
+        a = [0.0, 0.5]
+        b = [0.0, 0.0]
+        c = [0.5, 0.5]
+
+        points = [a, b, c]
+        vertices = [ [0,1,2] ]
+        domain = Domain(points, vertices)
+        domain.check_integrity()
+
+
+        #Populate boundary array with dirichlet conditions.
+        domain.neighbours = array([[-1,-2,-3]])
+        domain.quantities['stage'].boundary_values[0] = 1.0
+
+        domain.distribute_to_vertices_and_edges() #Use first order default
+
+        domain.check_integrity()
+
+        domain.compute_fluxes()
+        U = domain.quantities['stage'].explicit_update
+        assert allclose(U, 0)
+
+
+
+
+    def test_flux_2_triangles(self):
+        """Flow between two triangles
+        Check that fluxes have opposite signs
+        """
+
+        a = [0.0, 0.5]
+        b = [0.0, 0.0]
+        c = [0.5, 0.5]
+        d = [0.5, 0.0]
+
+        points = [a, b, c, d]
+        vertices = [ [0,1,2], [3,2,1] ]
+        domain = Domain(points, vertices)
+        domain.check_integrity()
+
+
+        #Populate boundary array with dirichlet conditions.
+        domain.neighbours = array([[1,-1,-2], [0,-3,-4]])
+        domain.set_quantity('stage', [1.0, 0.0], location='centroids')
+        domain.distribute_to_vertices_and_edges()
+
+        domain.compute_fluxes()
+
+        X = domain.quantities['stage'].explicit_update
+        assert X[0] == -X[1]
+
+
+    def test_advection_example(self):
+        #Test that system can evolve
+
+        from mesh_factory import rectangular
+
+        points, vertices, boundary = rectangular(6, 6)
+
+        #Create advection domain with direction (1,-1)
+        domain = Domain(points, vertices, boundary, velocity=[1.0, -1.0])
+
+        # Initial condition is zero by default
+
+        #Boundaries
+        T = Transmissive_boundary(domain)
+        D = Dirichlet_boundary(array([3.1415]))
+
+        domain.set_boundary( {'left': D, 'right': T, 'bottom': T, 'top': T} )
+        domain.check_integrity()
+
+        #Check that the boundary value gets propagated to all elements
+        for t in domain.evolve(yieldstep = 0.05, finaltime = 10):
+            if allclose(domain.quantities['stage'].centroid_values, 3.1415):
+                break
+
+        assert allclose(domain.quantities['stage'].centroid_values, 3.1415)
+
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_Advection,'test')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_all.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_all.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_all.py	(revision 3560)
@@ -0,0 +1,102 @@
+"""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 = ['test_interpolate_sww.py'] 
+
+
+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__':
+
+    from os import sep
+
+    #Attempt to compile all extensions
+    #execfile('..' + sep + 'utilities' + sep + 'compile.py')
+
+    #FIXME: Temporary measure
+    #os.chdir('..' + sep + 'utilities')
+    #execfile('compile.py')
+    #os.chdir('..' + sep + 'pyvolution')    
+    
+    #FIXME: Temporary measure
+    #os.chdir('..' + sep + 'triangle')
+    #execfile('compile.py')
+    #os.chdir('..' + sep + 'pyvolution')   
+    
+    #os.system('python compile.py') 
+
+    #print regressionTest()
+    #unittest.main(defaultTest='regressionTest')
+    
+    suite = regressionTest()
+    runner = unittest.TextTestRunner() #(verbosity=2)
+    runner.run(suite)
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_combine_pts.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_combine_pts.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_combine_pts.py	(revision 3560)
@@ -0,0 +1,284 @@
+#!/usr/bin/env python
+
+#TEST
+
+import unittest
+from math import sqrt
+
+
+#from least_squares import *
+from Numeric import allclose, array, transpose
+
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+from combine_pts import *
+from load_mesh.loadASCII import import_points_file
+#from anuga.geospatial_data.geospatial_data import import_points_file
+
+class Test_combine_pts(unittest.TestCase):
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+
+    def test_combine_rectangular_points_files(self):
+        from load_mesh.loadASCII import export_points_file
+        import tempfile
+        import os
+
+
+        # create a fine .pts file
+        fine_dict = {}
+        fine_dict['pointlist']=[[0,1],[0,4],[4,4],[4,1]]
+        att_dict = {}
+        att_dict['elevation'] = [10,40,80,50]
+        att_dict['sonic'] = [1,4,8,5]
+        fine_dict['attributelist'] = att_dict
+        fine_dict['geo_reference'] = Geo_reference(56,2.0,1.0)
+        
+        fine_file = tempfile.mktemp('.pts')
+        export_points_file(fine_file, fine_dict)
+
+
+        # create a coarse .pts file
+        coarse_dict = {}
+        coarse_dict['pointlist']=[[0,1],[2,1],[0,-2]]
+        att_dict = {}
+        att_dict['elevation'] = [10,30,-20]
+        att_dict['sonic'] = [1,3,-2]
+        coarse_dict['attributelist'] = att_dict
+        coarse_dict['geo_reference'] = Geo_reference(56,4.0,3.0)
+        
+        coarse_file = tempfile.mktemp('.pts')
+        export_points_file(coarse_file, coarse_dict)
+        
+        out_file = tempfile.mktemp('.pts')
+
+        combine_rectangular_points_files(fine_file,coarse_file,out_file)
+
+        #clean up
+        os.remove(fine_file)
+        os.remove(coarse_file)
+
+        results = import_points_file(out_file,
+                                     delimiter = ',')
+        answer = [[2.0, 0.0],
+                  [0.0, 1.0],
+                  [0.0, 4.0],
+                  [4.0, 4.0],
+                  [4.0, 1.0]]
+        #print "results",results 
+        #print "answer",answer
+        
+        self.failUnless(len(results['pointlist']) == len(answer),
+                        'final number of points wrong. failed.')
+        
+	assert allclose(results['pointlist'], answer)
+	assert allclose(results['attributelist']['sonic'], [ -2.,
+                                                             1.,  4.,
+                                                             8.,  5.])
+	assert allclose(results['attributelist']['elevation'],[ -20.,
+                                                               10.,  40.,
+                                                               80.,  50.])
+        
+        self.failUnless(results['geo_reference'] == fine_dict['geo_reference'],
+                        ' failed.')
+        #clean up
+        os.remove(out_file)
+
+    def test_combine_rectangular_points_filesII(self):
+        from load_mesh.loadASCII import export_points_file
+        import tempfile
+        import os
+
+        # create a fine .pts file
+        fine_dict = {}
+        fine_dict['pointlist']=[[0,1],[0,4],[4,4],[4,1],[3,1],[2,2],[1,3],[3,4]]
+        att_dict = {}
+        fine_dict['attributelist'] = att_dict
+        fine_dict['geo_reference'] = Geo_reference(56,2.0,1.0)
+        
+        fine_file = tempfile.mktemp('.pts')
+        export_points_file(fine_file, fine_dict)
+
+
+        # create a coarse .pts file
+        coarse_dict = {}
+        coarse_dict['pointlist']=[[0,1],[0,0],[0.5,0.5],[1,1],
+                                  [1.5,1.5],[2,1],[0,-2],[100,10],
+                                  [-20,4],[-50,5],[60,70]]
+        att_dict = {}
+        coarse_dict['attributelist'] = att_dict
+        coarse_dict['geo_reference'] = Geo_reference(56,4.0,3.0)
+        
+        coarse_file = tempfile.mktemp('.pts')
+        export_points_file(coarse_file, coarse_dict)
+        
+        out_file = tempfile.mktemp('.pts')
+
+        combine_rectangular_points_files(fine_file,coarse_file,out_file)
+
+        #clean up
+        os.remove(fine_file)
+        os.remove(coarse_file)
+
+        results = import_points_file(out_file,
+                                  delimiter = ',')
+        answer = [[2.0, 0.0],
+                  [102.,12.],
+                  [-18.,6.],
+                  [-48.,7.],
+                  [62.,72.],
+                  [0.0, 1.0],
+                  [0.0, 4.0],
+                  [4.0, 4.0],
+                  [4.0, 1.0],
+                  [3.,1.],
+                  [2.,2.],
+                  [1.,3.],
+                  [3.,4.]]
+        #print "results",results['pointlist']
+        #print "answer",answer
+        #print "len(results['pointlist']",len(results['pointlist'])
+        #print "len(answer)",len(answer)
+        
+        self.failUnless(len(results['pointlist']) == len(answer),
+                         'final number of points wrong. failed.')
+	assert allclose(results['pointlist'], answer)
+        
+        self.failUnless(results['geo_reference'] == fine_dict['geo_reference'],
+                        ' failed.')
+        #clean up
+        os.remove(out_file)
+
+    def test_combine_rectangular_points_files_errors(self):
+        from load_mesh.loadASCII import export_points_file
+        import tempfile
+        import os
+
+        # create a fine .pts file
+        fine_dict = {}
+        fine_dict['pointlist']=[[0,1],[0,4],[4,4],[4,1]]
+        att_dict = {}
+        att_dict['elevation'] = [1,4,8,5]
+        att_dict['pneumonic'] = [1,4,8,5]
+        fine_dict['attributelist'] = att_dict
+        fine_dict['geo_reference'] = Geo_reference(56,2.0,1.0)
+        
+        fine_file = tempfile.mktemp('.pts')
+        export_points_file(fine_file, fine_dict)
+
+
+        # create a coarse .pts file
+        coarse_dict = {}
+        coarse_dict['pointlist']=[[0,1],[2,1],[0,-2]]
+        att_dict = {}
+        att_dict['elevation'] = [1,3,-2]
+        att_dict['sonic'] = [1,3,-2]
+        coarse_dict['attributelist'] = att_dict
+        coarse_dict['geo_reference'] = Geo_reference(56,4.0,3.0)
+        
+        coarse_file = tempfile.mktemp('.pts')
+        export_points_file(coarse_file, coarse_dict)
+        
+        out_file = tempfile.mktemp('.pts')
+        try:
+            combine_rectangular_points_files(fine_file,coarse_file,out_file)
+        except AttributeError:
+            pass
+        else:
+            self.failUnless(0 == 1,
+                            'bad pts files did not raise error!')
+        #clean up
+        os.remove(fine_file)
+        os.remove(coarse_file)
+      
+    def test_reduce_points_to_mesh_extent(self):
+        from load_mesh.loadASCII import export_points_file, export_mesh_file
+        import tempfile
+        import os
+        x_origin = -45435345.
+        y_origin = 433432432.
+        # create a fine .pts file
+        fine_dict = {}
+        fine_dict['pointlist']=[[1.,1.],
+                                [1.,7.],
+                                [7.,1.],
+                                [11.,11.],
+                                [7.,8.],
+                                [8.,8.],
+                                [9.,8.]]
+        att_dict = {}
+        att_dict['elevation'] = [10,40,80,50,78,78,45]
+        att_dict['sonic'] = [1,4,8,5,56,34,213]
+        fine_dict['attributelist'] = att_dict
+        fine_dict['geo_reference'] = Geo_reference(56,x_origin,y_origin)
+        
+        points_file = tempfile.mktemp('.pts')
+        export_points_file(points_file, fine_dict)
+
+
+        # create a coarse .pts file
+        mesh = {}
+        mesh['vertices']=[[0,0],
+                          [0,3],
+                          [3,3],
+                          [3,0],
+                          [1,2]
+                          ]
+        mesh['vertex_attributes']=[[],
+                          [],
+                          [],
+                          [],
+                          []
+                          ]
+        mesh['geo_reference'] = Geo_reference(56,x_origin+7.,y_origin+7.)
+        
+        mesh_file = tempfile.mktemp('.tsh')
+        export_mesh_file(mesh_file, mesh)
+        
+        out_file = tempfile.mktemp('.pts')
+
+        reduce_points_to_mesh_extent(points_file,mesh_file,out_file)
+
+        results = import_points_file(out_file,
+                                  delimiter = ',')
+        answer = [
+            [7.,8.], 
+            [8.,8.],
+            [9.,8.]]
+        #print "results",results['pointlist']
+        #print "answer",answer
+        
+        self.failUnless(len(results['pointlist']) == len(answer),
+                         'final number of points wrong. failed.')
+	assert allclose(results['pointlist'],answer)
+
+        answer = [78., 78.,45.]
+        
+        self.failUnless(len(results['attributelist']['elevation']) == len(answer),
+                         'final number of points wrong. failed.')
+	assert allclose(results['attributelist']['elevation'], answer)
+       
+        #clean up
+        os.remove(points_file)
+        os.remove(mesh_file)
+        
+        #clean up
+        os.remove(out_file)
+
+        #FIXME do test for add points files
+        
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_combine_pts,'test')
+    #suite = unittest.makeSuite(Test_combine_pts,'test_reduce_points_to_mesh_extent')
+    runner = unittest.TextTestRunner(verbosity=1)
+    runner.run(suite)
+
+
+
+
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_data_manager.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_data_manager.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_data_manager.py	(revision 3560)
@@ -0,0 +1,4999 @@
+#!/usr/bin/env python
+#
+
+import unittest
+import copy
+from Numeric import zeros, array, allclose, Float
+from anuga.utilities.numerical_tools import mean
+import tempfile
+import os
+from Scientific.IO.NetCDF import NetCDFFile
+
+from anuga.abstract_2d_finite_volumes.data_manager import *
+from anuga.abstract_2d_finite_volumes.shallow_water import *
+from anuga.config import epsilon
+
+# This is needed to run the tests of local functions
+import anuga.abstract_2d_finite_volumes.data_manager
+
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+
+class Test_Data_Manager(unittest.TestCase):
+    def setUp(self):
+        import time
+        from mesh_factory import rectangular
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(2, 2)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.default_order=2
+
+
+        #Set some field values
+        domain.set_quantity('elevation', lambda x,y: -x)
+        domain.set_quantity('friction', 0.03)
+
+
+        ######################
+        # Boundary conditions
+        B = Transmissive_boundary(domain)
+        domain.set_boundary( {'left': B, 'right': B, 'top': B, 'bottom': B})
+
+
+        ######################
+        #Initial condition - with jumps
+
+
+        bed = domain.quantities['elevation'].vertex_values
+        stage = zeros(bed.shape, Float)
+
+        h = 0.3
+        for i in range(stage.shape[0]):
+            if i % 2 == 0:
+                stage[i,:] = bed[i,:] + h
+            else:
+                stage[i,:] = bed[i,:]
+
+        domain.set_quantity('stage', stage)
+        self.initial_stage = copy.copy(domain.quantities['stage'].vertex_values)
+
+        domain.distribute_to_vertices_and_edges()
+
+
+        self.domain = domain
+
+        C = domain.get_vertex_coordinates()
+        self.X = C[:,0:6:2].copy()
+        self.Y = C[:,1:6:2].copy()
+
+        self.F = bed
+
+
+
+
+        #Write A testfile (not realistic. Values aren't realistic)
+
+        self.test_MOST_file = 'most_small'
+
+        longitudes = [150.66667, 150.83334, 151., 151.16667]
+        latitudes = [-34.5, -34.33333, -34.16667, -34]
+
+        long_name = 'LON'
+        lat_name = 'LAT'
+
+        nx = 4
+        ny = 4
+        six = 6
+
+
+        for ext in ['_ha.nc', '_ua.nc', '_va.nc', '_e.nc']:
+            fid = NetCDFFile(self.test_MOST_file + ext, 'w')
+
+            fid.createDimension(long_name,nx)
+            fid.createVariable(long_name,'d',(long_name,))
+            fid.variables[long_name].point_spacing='uneven'
+            fid.variables[long_name].units='degrees_east'
+            fid.variables[long_name].assignValue(longitudes)
+
+            fid.createDimension(lat_name,ny)
+            fid.createVariable(lat_name,'d',(lat_name,))
+            fid.variables[lat_name].point_spacing='uneven'
+            fid.variables[lat_name].units='degrees_north'
+            fid.variables[lat_name].assignValue(latitudes)
+
+            fid.createDimension('TIME',six)
+            fid.createVariable('TIME','d',('TIME',))
+            fid.variables['TIME'].point_spacing='uneven'
+            fid.variables['TIME'].units='seconds'
+            fid.variables['TIME'].assignValue([0.0, 0.1, 0.6, 1.1, 1.6, 2.1])
+
+
+            name = ext[1:3].upper()
+            if name == 'E.': name = 'ELEVATION'
+            fid.createVariable(name,'d',('TIME', lat_name, long_name))
+            fid.variables[name].units='CENTIMETERS'
+            fid.variables[name].missing_value=-1.e+034
+
+            fid.variables[name].assignValue([[[0.3400644, 0, -46.63519, -6.50198],
+                                              [-0.1214216, 0, 0, 0],
+                                              [0, 0, 0, 0],
+                                              [0, 0, 0, 0]],
+                                             [[0.3400644, 2.291054e-005, -23.33335, -6.50198],
+                                              [-0.1213987, 4.581959e-005, -1.594838e-007, 1.421085e-012],
+                                              [2.291054e-005, 4.582107e-005, 4.581715e-005, 1.854517e-009],
+                                              [0, 2.291054e-005, 2.291054e-005, 0]],
+                                             [[0.3400644, 0.0001374632, -23.31503, -6.50198],
+                                              [-0.1212842, 0.0002756907, 0.006325484, 1.380492e-006],
+                                              [0.0001374632, 0.0002749264, 0.0002742863, 6.665601e-008],
+                                              [0, 0.0001374632, 0.0001374632, 0]],
+                                             [[0.3400644, 0.0002520159, -23.29672, -6.50198],
+                                              [-0.1211696, 0.0005075303, 0.01264618, 6.208276e-006],
+                                              [0.0002520159, 0.0005040318, 0.0005027961, 2.23865e-007],
+                                              [0, 0.0002520159, 0.0002520159, 0]],
+                                             [[0.3400644, 0.0003665686, -23.27842, -6.50198],
+                                              [-0.1210551, 0.0007413362, 0.01896192, 1.447638e-005],
+                                              [0.0003665686, 0.0007331371, 0.0007313463, 4.734126e-007],
+                                              [0, 0.0003665686, 0.0003665686, 0]],
+                                             [[0.3400644, 0.0004811212, -23.26012, -6.50198],
+                                              [-0.1209405, 0.0009771062, 0.02527271, 2.617787e-005],
+                                              [0.0004811212, 0.0009622425, 0.0009599366, 8.152277e-007],
+                                              [0, 0.0004811212, 0.0004811212, 0]]])
+
+
+            fid.close()
+
+
+
+
+    def tearDown(self):
+        import os
+        for ext in ['_ha.nc', '_ua.nc', '_va.nc', '_e.nc']:
+            #print 'Trying to remove', self.test_MOST_file + ext
+            os.remove(self.test_MOST_file + ext)
+
+    def test_sww_constant(self):
+        """Test that constant sww information can be written correctly
+        (non smooth)
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        self.domain.filename = 'datatest' + str(id(self))
+        self.domain.format = 'sww'
+        self.domain.smooth = False
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(sww.filename, 'r')  #Open existing file for append
+
+        # Get the variables
+        x = fid.variables['x']
+        y = fid.variables['y']
+        z = fid.variables['elevation']
+
+        volumes = fid.variables['volumes']
+
+
+        assert allclose (x[:], self.X.flat)
+        assert allclose (y[:], self.Y.flat)
+        assert allclose (z[:], self.F.flat)
+
+        V = volumes
+
+        P = len(self.domain)
+        for k in range(P):
+            assert V[k, 0] == 3*k
+            assert V[k, 1] == 3*k+1
+            assert V[k, 2] == 3*k+2
+
+
+        fid.close()
+
+        #Cleanup
+        os.remove(sww.filename)
+
+
+    def test_sww_constant_smooth(self):
+        """Test that constant sww information can be written correctly
+        (non smooth)
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        self.domain.filename = 'datatest' + str(id(self))
+        self.domain.format = 'sww'
+        self.domain.smooth = True
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(sww.filename, 'r')  #Open existing file for append
+
+        # Get the variables
+        x = fid.variables['x']
+        y = fid.variables['y']
+        z = fid.variables['elevation']
+
+        volumes = fid.variables['volumes']
+
+        X = x[:]
+        Y = y[:]
+
+        assert allclose([X[0], Y[0]], array([0.0, 0.0]))
+        assert allclose([X[1], Y[1]], array([0.0, 0.5]))
+        assert allclose([X[2], Y[2]], array([0.0, 1.0]))
+
+        assert allclose([X[4], Y[4]], array([0.5, 0.5]))
+
+        assert allclose([X[7], Y[7]], array([1.0, 0.5]))
+
+        Z = z[:]
+        assert Z[4] == -0.5
+
+        V = volumes
+        assert V[2,0] == 4
+        assert V[2,1] == 5
+        assert V[2,2] == 1
+
+        assert V[4,0] == 6
+        assert V[4,1] == 7
+        assert V[4,2] == 3
+
+
+        fid.close()
+
+        #Cleanup
+        os.remove(sww.filename)
+
+
+
+    def test_sww_variable(self):
+        """Test that sww information can be written correctly
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        self.domain.filename = 'datatest' + str(id(self))
+        self.domain.format = 'sww'
+        self.domain.smooth = True
+        self.domain.reduction = mean
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(sww.filename, 'r')  #Open existing file for append
+
+
+        # Get the variables
+        x = fid.variables['x']
+        y = fid.variables['y']
+        z = fid.variables['elevation']
+        time = fid.variables['time']
+        stage = fid.variables['stage']
+
+
+        Q = self.domain.quantities['stage']
+        Q0 = Q.vertex_values[:,0]
+        Q1 = Q.vertex_values[:,1]
+        Q2 = Q.vertex_values[:,2]
+
+        A = stage[0,:]
+        #print A[0], (Q2[0,0] + Q1[1,0])/2
+        assert allclose(A[0], (Q2[0] + Q1[1])/2)
+        assert allclose(A[1], (Q0[1] + Q1[3] + Q2[2])/3)
+        assert allclose(A[2], Q0[3])
+        assert allclose(A[3], (Q0[0] + Q1[5] + Q2[4])/3)
+
+        #Center point
+        assert allclose(A[4], (Q1[0] + Q2[1] + Q0[2] +\
+                                 Q0[5] + Q2[6] + Q1[7])/6)
+
+
+
+        fid.close()
+
+        #Cleanup
+        os.remove(sww.filename)
+
+
+    def test_sww_variable2(self):
+        """Test that sww information can be written correctly
+        multiple timesteps. Use average as reduction operator
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        self.domain.filename = 'datatest' + str(id(self))
+        self.domain.format = 'sww'
+        self.domain.smooth = True
+
+        self.domain.reduction = mean
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+        self.domain.evolve_to_end(finaltime = 0.01)
+        sww.store_timestep('stage')
+
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(sww.filename, 'r')  #Open existing file for append
+
+        # Get the variables
+        x = fid.variables['x']
+        y = fid.variables['y']
+        z = fid.variables['elevation']
+        time = fid.variables['time']
+        stage = fid.variables['stage']
+
+        #Check values
+        Q = self.domain.quantities['stage']
+        Q0 = Q.vertex_values[:,0]
+        Q1 = Q.vertex_values[:,1]
+        Q2 = Q.vertex_values[:,2]
+
+        A = stage[1,:]
+        assert allclose(A[0], (Q2[0] + Q1[1])/2)
+        assert allclose(A[1], (Q0[1] + Q1[3] + Q2[2])/3)
+        assert allclose(A[2], Q0[3])
+        assert allclose(A[3], (Q0[0] + Q1[5] + Q2[4])/3)
+
+        #Center point
+        assert allclose(A[4], (Q1[0] + Q2[1] + Q0[2] +\
+                                 Q0[5] + Q2[6] + Q1[7])/6)
+
+
+        fid.close()
+
+        #Cleanup
+        os.remove(sww.filename)
+
+    def test_sww_variable3(self):
+        """Test that sww information can be written correctly
+        multiple timesteps using a different reduction operator (min)
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        self.domain.filename = 'datatest' + str(id(self))
+        self.domain.format = 'sww'
+        self.domain.smooth = True
+        self.domain.reduction = min
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+
+        self.domain.evolve_to_end(finaltime = 0.01)
+        sww.store_timestep('stage')
+
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(sww.filename, 'r')
+
+
+        # Get the variables
+        x = fid.variables['x']
+        y = fid.variables['y']
+        z = fid.variables['elevation']
+        time = fid.variables['time']
+        stage = fid.variables['stage']
+
+        #Check values
+        Q = self.domain.quantities['stage']
+        Q0 = Q.vertex_values[:,0]
+        Q1 = Q.vertex_values[:,1]
+        Q2 = Q.vertex_values[:,2]
+
+        A = stage[1,:]
+        assert allclose(A[0], min(Q2[0], Q1[1]))
+        assert allclose(A[1], min(Q0[1], Q1[3], Q2[2]))
+        assert allclose(A[2], Q0[3])
+        assert allclose(A[3], min(Q0[0], Q1[5], Q2[4]))
+
+        #Center point
+        assert allclose(A[4], min(Q1[0], Q2[1], Q0[2],\
+                                  Q0[5], Q2[6], Q1[7]))
+
+
+        fid.close()
+
+        #Cleanup
+        os.remove(sww.filename)
+
+
+    def test_sync(self):
+        """Test info stored at each timestep is as expected (incl initial condition)
+        """
+
+        import time, os, config
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        self.domain.filename = 'synctest'
+        self.domain.format = 'sww'
+        self.domain.smooth = False
+        self.domain.store = True
+        self.domain.beta_h = 0
+
+        #Evolution
+        for t in self.domain.evolve(yieldstep = 1.0, finaltime = 4.0):
+            stage = self.domain.quantities['stage'].vertex_values
+
+            #Get NetCDF
+            fid = NetCDFFile(self.domain.writer.filename, 'r')
+            stage_file = fid.variables['stage']
+
+            if t == 0.0:
+                assert allclose(stage, self.initial_stage)
+                assert allclose(stage_file[:], stage.flat)
+            else:
+                assert not allclose(stage, self.initial_stage)
+                assert not allclose(stage_file[:], stage.flat)
+
+            fid.close()
+
+        os.remove(self.domain.writer.filename)
+
+
+    def test_sww_minimum_sww_depth(self):
+        """Test that sww information can be written correctly
+        multiple timesteps using a different reduction operator (min)
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        self.domain.filename = 'datatest' + str(id(self))
+        self.domain.format = 'sww'
+        self.domain.smooth = True
+        self.domain.reduction = min
+        self.domain.minimum_sww_depth = 100
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+
+        self.domain.evolve_to_end(finaltime = 0.01)
+        sww.store_timestep('stage')
+
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(sww.filename, 'r')
+
+
+        # Get the variables
+        x = fid.variables['x']
+        y = fid.variables['y']
+        z = fid.variables['elevation']
+        time = fid.variables['time']
+        stage = fid.variables['stage']
+
+        #Check values
+        Q = self.domain.quantities['stage']
+        Q0 = Q.vertex_values[:,0]
+        Q1 = Q.vertex_values[:,1]
+        Q2 = Q.vertex_values[:,2]
+
+        A = stage[1,:]
+        assert allclose(stage[1,:], z[:])
+        fid.close()
+
+        #Cleanup
+        os.remove(sww.filename)
+
+
+    def Not_a_test_sww_DSG(self):
+        """Not a test, rather a look at the sww format
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        self.domain.filename = 'datatest' + str(id(self))
+        self.domain.format = 'sww'
+        self.domain.smooth = True
+        self.domain.reduction = mean
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(sww.filename, 'r')
+
+        # Get the variables
+        x = fid.variables['x']
+        y = fid.variables['y']
+        z = fid.variables['elevation']
+
+        volumes = fid.variables['volumes']
+        time = fid.variables['time']
+
+        # 2D
+        stage = fid.variables['stage']
+
+        X = x[:]
+        Y = y[:]
+        Z = z[:]
+        V = volumes[:]
+        T = time[:]
+        S = stage[:,:]
+
+#         print "****************************"
+#         print "X ",X
+#         print "****************************"
+#         print "Y ",Y
+#         print "****************************"
+#         print "Z ",Z
+#         print "****************************"
+#         print "V ",V
+#         print "****************************"
+#         print "Time ",T
+#         print "****************************"
+#         print "Stage ",S
+#         print "****************************"
+
+
+        fid.close()
+
+        #Cleanup
+        os.remove(sww.filename)
+
+
+    #def test_write_pts(self):
+    #    #Obsolete
+    #
+    #    #Get (enough) datapoints
+    #
+    #    from Numeric import array
+    #    points = array([[ 0.66666667, 0.66666667],
+    #                    [ 1.33333333, 1.33333333],
+    #                    [ 2.66666667, 0.66666667],
+    #                    [ 0.66666667, 2.66666667],
+    #                    [ 0.0, 1.0],
+    #                    [ 0.0, 3.0],
+    #                    [ 1.0, 0.0],
+    #                    [ 1.0, 1.0],
+    #                    [ 1.0, 2.0],
+    #                    [ 1.0, 3.0],
+    #                    [ 2.0, 1.0],
+    #                    [ 3.0, 0.0],
+    #                    [ 3.0, 1.0]])
+    #
+    #    z = points[:,0] + 2*points[:,1]
+    #
+    #    ptsfile = 'testptsfile.pts'
+    #    write_ptsfile(ptsfile, points, z,
+    #                  attribute_name = 'linear_combination')
+    #
+    #    #Check contents
+    #    #Get NetCDF
+    #    from Scientific.IO.NetCDF import NetCDFFile
+    #    fid = NetCDFFile(ptsfile, 'r')
+    #
+    #    # Get the variables
+    #    #print fid.variables.keys()
+    #    points1 = fid.variables['points']
+    #    z1 = fid.variables['linear_combination']
+    #
+    #    #Check values#
+    #
+    #    #print points[:]
+    #    #print ref_points
+    #    assert allclose(points, points1)
+    #
+    #    #print attributes[:]
+    #    #print ref_elevation
+    #    assert allclose(z, z1)
+    #
+    #    #Cleanup
+    #    fid.close()
+    #
+    #    import os
+    #    os.remove(ptsfile)
+
+
+    def test_dem2pts_bounding_box_v2(self):
+        """Test conversion from dem in ascii format to native NetCDF xya format
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate, ones
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Write test asc file
+        root = 'demtest'
+
+        filename = root+'.asc'
+        fid = open(filename, 'w')
+        fid.write("""ncols         10
+nrows         10
+xllcorner     2000
+yllcorner     3000
+cellsize      1
+NODATA_value  -9999
+""")
+        #Create linear function
+        ref_points = []
+        ref_elevation = []
+        x0 = 2000
+        y = 3010
+        yvec = range(10)
+        xvec = range(10)
+        z = -1
+        for i in range(10):
+            y = y - 1
+            for j in range(10):
+                x = x0 + xvec[j]
+                z += 1
+                ref_points.append ([x,y])
+                ref_elevation.append(z)
+                fid.write('%f ' %z)
+            fid.write('\n')
+
+        fid.close()
+
+        #print 'sending pts', ref_points
+        #print 'sending elev', ref_elevation
+
+        #Write prj file with metadata
+        metafilename = root+'.prj'
+        fid = open(metafilename, 'w')
+
+
+        fid.write("""Projection UTM
+Zone 56
+Datum WGS84
+Zunits NO
+Units METERS
+Spheroid WGS84
+Xshift 0.0000000000
+Yshift 10000000.0000000000
+Parameters
+""")
+        fid.close()
+
+        #Convert to NetCDF pts
+        convert_dem_from_ascii2netcdf(root)
+        dem2pts(root, easting_min=2002.0, easting_max=2007.0,
+                northing_min=3003.0, northing_max=3006.0)
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(root+'.pts', 'r')
+
+        # Get the variables
+        #print fid.variables.keys()
+        points = fid.variables['points']
+        elevation = fid.variables['elevation']
+
+        #Check values
+        assert fid.xllcorner[0] == 2002.0
+        assert fid.yllcorner[0] == 3003.0
+
+        #create new reference points
+        newz = []
+        newz[0:5] = ref_elevation[32:38]
+        newz[6:11] = ref_elevation[42:48]
+        newz[12:17] = ref_elevation[52:58]
+        newz[18:23] = ref_elevation[62:68]
+        ref_elevation = []
+        ref_elevation = newz
+        ref_points = []
+        x0 = 2002
+        y = 3007
+        yvec = range(4)
+        xvec = range(6)
+        for i in range(4):
+            y = y - 1
+            ynew = y - 3003.0
+            for j in range(6):
+                x = x0 + xvec[j]
+                xnew = x - 2002.0
+                ref_points.append ([xnew,ynew]) #Relative point values
+
+        assert allclose(points, ref_points)
+
+        assert allclose(elevation, ref_elevation)
+
+        #Cleanup
+        fid.close()
+
+
+        os.remove(root + '.pts')
+        os.remove(root + '.dem')
+        os.remove(root + '.asc')
+        os.remove(root + '.prj')
+
+
+    def test_dem2pts_bounding_box_removeNullvalues_v2(self):
+        """Test conversion from dem in ascii format to native NetCDF xya format
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate, ones
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Write test asc file
+        root = 'demtest'
+
+        filename = root+'.asc'
+        fid = open(filename, 'w')
+        fid.write("""ncols         10
+nrows         10
+xllcorner     2000
+yllcorner     3000
+cellsize      1
+NODATA_value  -9999
+""")
+        #Create linear function
+        ref_points = []
+        ref_elevation = []
+        x0 = 2000
+        y = 3010
+        yvec = range(10)
+        xvec = range(10)
+        #z = range(100)
+        z = zeros(100)
+        NODATA_value = -9999
+        count = -1
+        for i in range(10):
+            y = y - 1
+            for j in range(10):
+                x = x0 + xvec[j]
+                ref_points.append ([x,y])
+                count += 1
+                z[count] = (4*i - 3*j)%13
+                if j == 4: z[count] = NODATA_value #column inside clipping region
+                if j == 8: z[count] = NODATA_value #column outside clipping region
+                if i == 9: z[count] = NODATA_value #row outside clipping region
+                if i == 4 and j == 6: z[count] = NODATA_value #arbitrary point inside clipping region
+                ref_elevation.append( z[count] )
+                fid.write('%f ' %z[count])
+            fid.write('\n')
+
+        fid.close()
+
+        #print 'sending elev', ref_elevation
+
+        #Write prj file with metadata
+        metafilename = root+'.prj'
+        fid = open(metafilename, 'w')
+
+
+        fid.write("""Projection UTM
+Zone 56
+Datum WGS84
+Zunits NO
+Units METERS
+Spheroid WGS84
+Xshift 0.0000000000
+Yshift 10000000.0000000000
+Parameters
+""")
+        fid.close()
+
+        #Convert to NetCDF pts
+        convert_dem_from_ascii2netcdf(root)
+        dem2pts(root, easting_min=2002.0, easting_max=2007.0,
+                northing_min=3003.0, northing_max=3006.0)
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(root+'.pts', 'r')
+
+        # Get the variables
+        #print fid.variables.keys()
+        points = fid.variables['points']
+        elevation = fid.variables['elevation']
+
+        #Check values
+        assert fid.xllcorner[0] == 2002.0
+        assert fid.yllcorner[0] == 3003.0
+
+        #create new reference points
+        newz = zeros(19)
+        newz[0:2] = ref_elevation[32:34]
+        newz[2:5] = ref_elevation[35:38]
+        newz[5:7] = ref_elevation[42:44]
+        newz[7] = ref_elevation[45]
+        newz[8] = ref_elevation[47]
+        newz[9:11] = ref_elevation[52:54]
+        newz[11:14] = ref_elevation[55:58]
+        newz[14:16] = ref_elevation[62:64]
+        newz[16:19] = ref_elevation[65:68]
+
+
+        ref_elevation = newz
+        ref_points = []
+        new_ref_points = []
+        x0 = 2002
+        y = 3007
+        yvec = range(4)
+        xvec = range(6)
+        for i in range(4):
+            y = y - 1
+            ynew = y - 3003.0
+            for j in range(6):
+                x = x0 + xvec[j]
+                xnew = x - 2002.0
+                if j <> 2 and (i<>1 or j<>4):
+                    ref_points.append([x,y])
+                    new_ref_points.append ([xnew,ynew])
+
+
+        assert allclose(points, new_ref_points)
+        assert allclose(elevation, ref_elevation)
+
+        #Cleanup
+        fid.close()
+
+
+        os.remove(root + '.pts')
+        os.remove(root + '.dem')
+        os.remove(root + '.asc')
+        os.remove(root + '.prj')
+
+
+    def test_dem2pts_bounding_box_removeNullvalues_v3(self):
+        """Test conversion from dem in ascii format to native NetCDF xya format
+        Check missing values on clipping boundary
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate, ones
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Write test asc file
+        root = 'demtest'
+
+        filename = root+'.asc'
+        fid = open(filename, 'w')
+        fid.write("""ncols         10
+nrows         10
+xllcorner     2000
+yllcorner     3000
+cellsize      1
+NODATA_value  -9999
+""")
+        #Create linear function
+        ref_points = []
+        ref_elevation = []
+        x0 = 2000
+        y = 3010
+        yvec = range(10)
+        xvec = range(10)
+        #z = range(100)
+        z = zeros(100)
+        NODATA_value = -9999
+        count = -1
+        for i in range(10):
+            y = y - 1
+            for j in range(10):
+                x = x0 + xvec[j]
+                ref_points.append ([x,y])
+                count += 1
+                z[count] = (4*i - 3*j)%13
+                if j == 4: z[count] = NODATA_value #column inside clipping region
+                if j == 8: z[count] = NODATA_value #column outside clipping region
+                if i == 6: z[count] = NODATA_value #row on clipping boundary
+                if i == 4 and j == 6: z[count] = NODATA_value #arbitrary point inside clipping region
+                ref_elevation.append( z[count] )
+                fid.write('%f ' %z[count])
+            fid.write('\n')
+
+        fid.close()
+
+        #print 'sending elev', ref_elevation
+
+        #Write prj file with metadata
+        metafilename = root+'.prj'
+        fid = open(metafilename, 'w')
+
+
+        fid.write("""Projection UTM
+Zone 56
+Datum WGS84
+Zunits NO
+Units METERS
+Spheroid WGS84
+Xshift 0.0000000000
+Yshift 10000000.0000000000
+Parameters
+""")
+        fid.close()
+
+        #Convert to NetCDF pts
+        convert_dem_from_ascii2netcdf(root)
+        dem2pts(root, easting_min=2002.0, easting_max=2007.0,
+                northing_min=3003.0, northing_max=3006.0)
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(root+'.pts', 'r')
+
+        # Get the variables
+        #print fid.variables.keys()
+        points = fid.variables['points']
+        elevation = fid.variables['elevation']
+
+        #Check values
+        assert fid.xllcorner[0] == 2002.0
+        assert fid.yllcorner[0] == 3003.0
+
+        #create new reference points
+        newz = zeros(14)
+        newz[0:2] = ref_elevation[32:34]
+        newz[2:5] = ref_elevation[35:38]
+        newz[5:7] = ref_elevation[42:44]
+        newz[7] = ref_elevation[45]
+        newz[8] = ref_elevation[47]
+        newz[9:11] = ref_elevation[52:54]
+        newz[11:14] = ref_elevation[55:58]
+
+
+
+        ref_elevation = newz
+        ref_points = []
+        new_ref_points = []
+        x0 = 2002
+        y = 3007
+        yvec = range(4)
+        xvec = range(6)
+        for i in range(4):
+            y = y - 1
+            ynew = y - 3003.0
+            for j in range(6):
+                x = x0 + xvec[j]
+                xnew = x - 2002.0
+                if j <> 2 and (i<>1 or j<>4) and i<>3:
+                    ref_points.append([x,y])
+                    new_ref_points.append ([xnew,ynew])
+
+
+        #print points[:],points[:].shape
+        #print new_ref_points, len(new_ref_points)
+
+        assert allclose(elevation, ref_elevation)
+        assert allclose(points, new_ref_points)
+
+
+        #Cleanup
+        fid.close()
+
+
+        os.remove(root + '.pts')
+        os.remove(root + '.dem')
+        os.remove(root + '.asc')
+        os.remove(root + '.prj')
+
+
+    def test_hecras_cross_sections2pts(self):
+        """Test conversion from HECRAS cross sections in ascii format
+        to native NetCDF pts format
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Write test asc file
+        root = 'hecrastest'
+
+        filename = root+'.sdf'
+        fid = open(filename, 'w')
+        fid.write("""
+# RAS export file created on Mon 15Aug2005 11:42
+# by HEC-RAS Version 3.1.1
+
+BEGIN HEADER:
+  UNITS: METRIC
+  DTM TYPE: TIN
+  DTM: v:\1\cit\perth_topo\river_tin
+  STREAM LAYER: c:\\x_local\hecras\21_02_03\up_canning_cent3d.shp
+  CROSS-SECTION LAYER: c:\\x_local\hecras\21_02_03\up_can_xs3d.shp
+  MAP PROJECTION: UTM
+  PROJECTION ZONE: 50
+  DATUM: AGD66
+  VERTICAL DATUM:
+  NUMBER OF REACHES:  19
+  NUMBER OF CROSS-SECTIONS:  2
+END HEADER:
+
+
+BEGIN CROSS-SECTIONS:
+
+  CROSS-SECTION:
+    STREAM ID:Southern-Wungong
+    REACH ID:Southern-Wungong
+    STATION:21410
+    CUT LINE:
+      407546.08 , 6437277.542
+      407329.32 , 6437489.482
+      407283.11 , 6437541.232
+    SURFACE LINE:
+     407546.08,   6437277.54,   52.14
+     407538.88,   6437284.58,   51.07
+     407531.68,   6437291.62,   50.56
+     407524.48,   6437298.66,   49.58
+     407517.28,   6437305.70,   49.09
+     407510.08,   6437312.74,   48.76
+  END:
+
+  CROSS-SECTION:
+    STREAM ID:Swan River
+    REACH ID:Swan Mouth
+    STATION:840.*
+    CUT LINE:
+      381178.0855 , 6452559.0685
+      380485.4755 , 6453169.272
+    SURFACE LINE:
+     381178.09,   6452559.07,   4.17
+     381169.49,   6452566.64,   4.26
+     381157.78,   6452576.96,   4.34
+     381155.97,   6452578.56,   4.35
+     381143.72,   6452589.35,   4.43
+     381136.69,   6452595.54,   4.58
+     381114.74,   6452614.88,   4.41
+     381075.53,   6452649.43,   4.17
+     381071.47,   6452653.00,   3.99
+     381063.46,   6452660.06,   3.67
+     381054.41,   6452668.03,   3.67
+  END:
+END CROSS-SECTIONS:
+""")
+
+        fid.close()
+
+
+        #Convert to NetCDF pts
+        hecras_cross_sections2pts(root)
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(root+'.pts', 'r')
+
+        # Get the variables
+        #print fid.variables.keys()
+        points = fid.variables['points']
+        elevation = fid.variables['elevation']
+
+        #Check values
+        ref_points = [[407546.08, 6437277.54],
+                      [407538.88, 6437284.58],
+                      [407531.68, 6437291.62],
+                      [407524.48, 6437298.66],
+                      [407517.28, 6437305.70],
+                      [407510.08, 6437312.74]]
+
+        ref_points += [[381178.09, 6452559.07],
+                       [381169.49, 6452566.64],
+                       [381157.78, 6452576.96],
+                       [381155.97, 6452578.56],
+                       [381143.72, 6452589.35],
+                       [381136.69, 6452595.54],
+                       [381114.74, 6452614.88],
+                       [381075.53, 6452649.43],
+                       [381071.47, 6452653.00],
+                       [381063.46, 6452660.06],
+                       [381054.41, 6452668.03]]
+
+
+        ref_elevation = [52.14, 51.07, 50.56, 49.58, 49.09, 48.76]
+        ref_elevation += [4.17, 4.26, 4.34, 4.35, 4.43, 4.58, 4.41, 4.17, 3.99, 3.67, 3.67]
+
+        #print points[:]
+        #print ref_points
+        assert allclose(points, ref_points)
+
+        #print attributes[:]
+        #print ref_elevation
+        assert allclose(elevation, ref_elevation)
+
+        #Cleanup
+        fid.close()
+
+
+        os.remove(root + '.sdf')
+        os.remove(root + '.pts')
+
+
+
+    def test_sww2dem_asc_elevation(self):
+        """Test that sww information can be converted correctly to asc/prj
+        format readable by e.g. ArcView
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Setup
+        self.domain.filename = 'datatest'
+
+        prjfile = self.domain.filename + '_elevation.prj'
+        ascfile = self.domain.filename + '_elevation.asc'
+        swwfile = self.domain.filename + '.sww'
+
+        self.domain.set_datadir('.')
+        self.domain.format = 'sww'
+        self.domain.smooth = True
+        self.domain.set_quantity('elevation', lambda x,y: -x-y)
+
+        self.domain.geo_reference = Geo_reference(56,308500,6189000)
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+
+        self.domain.evolve_to_end(finaltime = 0.01)
+        sww.store_timestep('stage')
+
+        cellsize = 0.25
+        #Check contents
+        #Get NetCDF
+
+        fid = NetCDFFile(sww.filename, 'r')
+
+        # Get the variables
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        z = fid.variables['elevation'][:]
+        time = fid.variables['time'][:]
+        stage = fid.variables['stage'][:]
+
+
+        #Export to ascii/prj files
+        sww2dem(self.domain.filename,
+                quantity = 'elevation',
+                cellsize = cellsize,
+                verbose = False,
+                format = 'asc')
+
+        #Check prj (meta data)
+        prjid = open(prjfile)
+        lines = prjid.readlines()
+        prjid.close()
+
+        L = lines[0].strip().split()
+        assert L[0].strip().lower() == 'projection'
+        assert L[1].strip().lower() == 'utm'
+
+        L = lines[1].strip().split()
+        assert L[0].strip().lower() == 'zone'
+        assert L[1].strip().lower() == '56'
+
+        L = lines[2].strip().split()
+        assert L[0].strip().lower() == 'datum'
+        assert L[1].strip().lower() == 'wgs84'
+
+        L = lines[3].strip().split()
+        assert L[0].strip().lower() == 'zunits'
+        assert L[1].strip().lower() == 'no'
+
+        L = lines[4].strip().split()
+        assert L[0].strip().lower() == 'units'
+        assert L[1].strip().lower() == 'meters'
+
+        L = lines[5].strip().split()
+        assert L[0].strip().lower() == 'spheroid'
+        assert L[1].strip().lower() == 'wgs84'
+
+        L = lines[6].strip().split()
+        assert L[0].strip().lower() == 'xshift'
+        assert L[1].strip().lower() == '500000'
+
+        L = lines[7].strip().split()
+        assert L[0].strip().lower() == 'yshift'
+        assert L[1].strip().lower() == '10000000'
+
+        L = lines[8].strip().split()
+        assert L[0].strip().lower() == 'parameters'
+
+
+        #Check asc file
+        ascid = open(ascfile)
+        lines = ascid.readlines()
+        ascid.close()
+
+        L = lines[0].strip().split()
+        assert L[0].strip().lower() == 'ncols'
+        assert L[1].strip().lower() == '5'
+
+        L = lines[1].strip().split()
+        assert L[0].strip().lower() == 'nrows'
+        assert L[1].strip().lower() == '5'
+
+        L = lines[2].strip().split()
+        assert L[0].strip().lower() == 'xllcorner'
+        assert allclose(float(L[1].strip().lower()), 308500)
+
+        L = lines[3].strip().split()
+        assert L[0].strip().lower() == 'yllcorner'
+        assert allclose(float(L[1].strip().lower()), 6189000)
+
+        L = lines[4].strip().split()
+        assert L[0].strip().lower() == 'cellsize'
+        assert allclose(float(L[1].strip().lower()), cellsize)
+
+        L = lines[5].strip().split()
+        assert L[0].strip() == 'NODATA_value'
+        assert L[1].strip().lower() == '-9999'
+
+        #Check grid values
+        for j in range(5):
+            L = lines[6+j].strip().split()
+            y = (4-j) * cellsize
+            for i in range(5):
+                assert allclose(float(L[i]), -i*cellsize - y)
+
+
+        fid.close()
+
+        #Cleanup
+        os.remove(prjfile)
+        os.remove(ascfile)
+        os.remove(swwfile)
+
+
+
+    def test_sww2dem_larger(self):
+        """Test that sww information can be converted correctly to asc/prj
+        format readable by e.g. ArcView. Here:
+
+        ncols         11
+        nrows         11
+        xllcorner     308500
+        yllcorner     6189000
+        cellsize      10.000000
+        NODATA_value  -9999
+        -100 -110 -120 -130 -140 -150 -160 -170 -180 -190 -200
+         -90 -100 -110 -120 -130 -140 -150 -160 -170 -180 -190
+         -80  -90 -100 -110 -120 -130 -140 -150 -160 -170 -180
+         -70  -80  -90 -100 -110 -120 -130 -140 -150 -160 -170
+         -60  -70  -80  -90 -100 -110 -120 -130 -140 -150 -160
+         -50  -60  -70  -80  -90 -100 -110 -120 -130 -140 -150
+         -40  -50  -60  -70  -80  -90 -100 -110 -120 -130 -140
+         -30  -40  -50  -60  -70  -80  -90 -100 -110 -120 -130
+         -20  -30  -40  -50  -60  -70  -80  -90 -100 -110 -120
+         -10  -20  -30  -40  -50  -60  -70  -80  -90 -100 -110
+           0  -10  -20  -30  -40  -50  -60  -70  -80  -90 -100
+
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Setup
+
+        from mesh_factory import rectangular
+
+        #Create basic mesh (100m x 100m)
+        points, vertices, boundary = rectangular(2, 2, 100, 100)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.default_order = 2
+
+        domain.filename = 'datatest'
+
+        prjfile = domain.filename + '_elevation.prj'
+        ascfile = domain.filename + '_elevation.asc'
+        swwfile = domain.filename + '.sww'
+
+        domain.set_datadir('.')
+        domain.format = 'sww'
+        domain.smooth = True
+        domain.geo_reference = Geo_reference(56, 308500, 6189000)
+
+        #
+        domain.set_quantity('elevation', lambda x,y: -x-y)
+        domain.set_quantity('stage', 0)
+
+        B = Transmissive_boundary(domain)
+        domain.set_boundary( {'left': B, 'right': B, 'top': B, 'bottom': B})
+
+
+        #
+        sww = get_dataobject(domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+
+        domain.evolve_to_end(finaltime = 0.01)
+        sww.store_timestep('stage')
+
+        cellsize = 10  #10m grid
+
+
+        #Check contents
+        #Get NetCDF
+
+        fid = NetCDFFile(sww.filename, 'r')
+
+        # Get the variables
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        z = fid.variables['elevation'][:]
+        time = fid.variables['time'][:]
+        stage = fid.variables['stage'][:]
+
+
+        #Export to ascii/prj files
+        sww2dem(domain.filename,
+                quantity = 'elevation',
+                cellsize = cellsize,
+                verbose = False,
+                format = 'asc')
+
+
+        #Check prj (meta data)
+        prjid = open(prjfile)
+        lines = prjid.readlines()
+        prjid.close()
+
+        L = lines[0].strip().split()
+        assert L[0].strip().lower() == 'projection'
+        assert L[1].strip().lower() == 'utm'
+
+        L = lines[1].strip().split()
+        assert L[0].strip().lower() == 'zone'
+        assert L[1].strip().lower() == '56'
+
+        L = lines[2].strip().split()
+        assert L[0].strip().lower() == 'datum'
+        assert L[1].strip().lower() == 'wgs84'
+
+        L = lines[3].strip().split()
+        assert L[0].strip().lower() == 'zunits'
+        assert L[1].strip().lower() == 'no'
+
+        L = lines[4].strip().split()
+        assert L[0].strip().lower() == 'units'
+        assert L[1].strip().lower() == 'meters'
+
+        L = lines[5].strip().split()
+        assert L[0].strip().lower() == 'spheroid'
+        assert L[1].strip().lower() == 'wgs84'
+
+        L = lines[6].strip().split()
+        assert L[0].strip().lower() == 'xshift'
+        assert L[1].strip().lower() == '500000'
+
+        L = lines[7].strip().split()
+        assert L[0].strip().lower() == 'yshift'
+        assert L[1].strip().lower() == '10000000'
+
+        L = lines[8].strip().split()
+        assert L[0].strip().lower() == 'parameters'
+
+
+        #Check asc file
+        ascid = open(ascfile)
+        lines = ascid.readlines()
+        ascid.close()
+
+        L = lines[0].strip().split()
+        assert L[0].strip().lower() == 'ncols'
+        assert L[1].strip().lower() == '11'
+
+        L = lines[1].strip().split()
+        assert L[0].strip().lower() == 'nrows'
+        assert L[1].strip().lower() == '11'
+
+        L = lines[2].strip().split()
+        assert L[0].strip().lower() == 'xllcorner'
+        assert allclose(float(L[1].strip().lower()), 308500)
+
+        L = lines[3].strip().split()
+        assert L[0].strip().lower() == 'yllcorner'
+        assert allclose(float(L[1].strip().lower()), 6189000)
+
+        L = lines[4].strip().split()
+        assert L[0].strip().lower() == 'cellsize'
+        assert allclose(float(L[1].strip().lower()), cellsize)
+
+        L = lines[5].strip().split()
+        assert L[0].strip() == 'NODATA_value'
+        assert L[1].strip().lower() == '-9999'
+
+        #Check grid values (FIXME: Use same strategy for other sww2dem tests)
+        for i, line in enumerate(lines[6:]):
+            for j, value in enumerate( line.split() ):
+                #assert allclose(float(value), -(10-i+j)*cellsize)
+                assert float(value) == -(10-i+j)*cellsize
+
+
+        fid.close()
+
+        #Cleanup
+        os.remove(prjfile)
+        os.remove(ascfile)
+        os.remove(swwfile)
+
+
+
+    def test_sww2dem_boundingbox(self):
+        """Test that sww information can be converted correctly to asc/prj
+        format readable by e.g. ArcView.
+        This will test that mesh can be restricted by bounding box
+
+        Original extent is 100m x 100m:
+
+        Eastings:   308500 -  308600
+        Northings: 6189000 - 6189100
+
+        Bounding box changes this to the 50m x 50m square defined by
+
+        Eastings:   308530 -  308570
+        Northings: 6189050 - 6189100
+
+        The cropped values should be
+
+         -130 -140 -150 -160 -170
+         -120 -130 -140 -150 -160
+         -110 -120 -130 -140 -150
+         -100 -110 -120 -130 -140
+          -90 -100 -110 -120 -130
+          -80  -90 -100 -110 -120
+
+        and the new lower reference point should be
+        Eastings:   308530
+        Northings: 6189050
+
+        Original dataset is the same as in test_sww2dem_larger()
+
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Setup
+
+        from mesh_factory import rectangular
+
+        #Create basic mesh (100m x 100m)
+        points, vertices, boundary = rectangular(2, 2, 100, 100)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.default_order = 2
+
+        domain.filename = 'datatest'
+
+        prjfile = domain.filename + '_elevation.prj'
+        ascfile = domain.filename + '_elevation.asc'
+        swwfile = domain.filename + '.sww'
+
+        domain.set_datadir('.')
+        domain.format = 'sww'
+        domain.smooth = True
+        domain.geo_reference = Geo_reference(56, 308500, 6189000)
+
+        #
+        domain.set_quantity('elevation', lambda x,y: -x-y)
+        domain.set_quantity('stage', 0)
+
+        B = Transmissive_boundary(domain)
+        domain.set_boundary( {'left': B, 'right': B, 'top': B, 'bottom': B})
+
+
+        #
+        sww = get_dataobject(domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+
+        domain.evolve_to_end(finaltime = 0.01)
+        sww.store_timestep('stage')
+
+        cellsize = 10  #10m grid
+
+
+        #Check contents
+        #Get NetCDF
+
+        fid = NetCDFFile(sww.filename, 'r')
+
+        # Get the variables
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        z = fid.variables['elevation'][:]
+        time = fid.variables['time'][:]
+        stage = fid.variables['stage'][:]
+
+
+        #Export to ascii/prj files
+        sww2dem(domain.filename,
+                quantity = 'elevation',
+                cellsize = cellsize,
+                easting_min = 308530,
+                easting_max = 308570,
+                northing_min = 6189050,
+                northing_max = 6189100,
+                verbose = False,
+                format = 'asc')
+
+        fid.close()
+
+
+        #Check prj (meta data)
+        prjid = open(prjfile)
+        lines = prjid.readlines()
+        prjid.close()
+
+        L = lines[0].strip().split()
+        assert L[0].strip().lower() == 'projection'
+        assert L[1].strip().lower() == 'utm'
+
+        L = lines[1].strip().split()
+        assert L[0].strip().lower() == 'zone'
+        assert L[1].strip().lower() == '56'
+
+        L = lines[2].strip().split()
+        assert L[0].strip().lower() == 'datum'
+        assert L[1].strip().lower() == 'wgs84'
+
+        L = lines[3].strip().split()
+        assert L[0].strip().lower() == 'zunits'
+        assert L[1].strip().lower() == 'no'
+
+        L = lines[4].strip().split()
+        assert L[0].strip().lower() == 'units'
+        assert L[1].strip().lower() == 'meters'
+
+        L = lines[5].strip().split()
+        assert L[0].strip().lower() == 'spheroid'
+        assert L[1].strip().lower() == 'wgs84'
+
+        L = lines[6].strip().split()
+        assert L[0].strip().lower() == 'xshift'
+        assert L[1].strip().lower() == '500000'
+
+        L = lines[7].strip().split()
+        assert L[0].strip().lower() == 'yshift'
+        assert L[1].strip().lower() == '10000000'
+
+        L = lines[8].strip().split()
+        assert L[0].strip().lower() == 'parameters'
+
+
+        #Check asc file
+        ascid = open(ascfile)
+        lines = ascid.readlines()
+        ascid.close()
+
+        L = lines[0].strip().split()
+        assert L[0].strip().lower() == 'ncols'
+        assert L[1].strip().lower() == '5'
+
+        L = lines[1].strip().split()
+        assert L[0].strip().lower() == 'nrows'
+        assert L[1].strip().lower() == '6'
+
+        L = lines[2].strip().split()
+        assert L[0].strip().lower() == 'xllcorner'
+        assert allclose(float(L[1].strip().lower()), 308530)
+
+        L = lines[3].strip().split()
+        assert L[0].strip().lower() == 'yllcorner'
+        assert allclose(float(L[1].strip().lower()), 6189050)
+
+        L = lines[4].strip().split()
+        assert L[0].strip().lower() == 'cellsize'
+        assert allclose(float(L[1].strip().lower()), cellsize)
+
+        L = lines[5].strip().split()
+        assert L[0].strip() == 'NODATA_value'
+        assert L[1].strip().lower() == '-9999'
+
+        #Check grid values
+        for i, line in enumerate(lines[6:]):
+            for j, value in enumerate( line.split() ):
+                #assert float(value) == -(10-i+j)*cellsize
+                assert float(value) == -(10-i+j+3)*cellsize
+
+
+
+        #Cleanup
+        os.remove(prjfile)
+        os.remove(ascfile)
+        os.remove(swwfile)
+
+
+
+    def test_sww2dem_asc_stage_reduction(self):
+        """Test that sww information can be converted correctly to asc/prj
+        format readable by e.g. ArcView
+
+        This tests the reduction of quantity stage using min
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Setup
+        self.domain.filename = 'datatest'
+
+        prjfile = self.domain.filename + '_stage.prj'
+        ascfile = self.domain.filename + '_stage.asc'
+        swwfile = self.domain.filename + '.sww'
+
+        self.domain.set_datadir('.')
+        self.domain.format = 'sww'
+        self.domain.smooth = True
+        self.domain.set_quantity('elevation', lambda x,y: -x-y)
+
+        self.domain.geo_reference = Geo_reference(56,308500,6189000)
+
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+
+        self.domain.evolve_to_end(finaltime = 0.01)
+        sww.store_timestep('stage')
+
+        cellsize = 0.25
+        #Check contents
+        #Get NetCDF
+
+        fid = NetCDFFile(sww.filename, 'r')
+
+        # Get the variables
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        z = fid.variables['elevation'][:]
+        time = fid.variables['time'][:]
+        stage = fid.variables['stage'][:]
+
+
+        #Export to ascii/prj files
+        sww2dem(self.domain.filename,
+                quantity = 'stage',
+                cellsize = cellsize,
+                reduction = min,
+		format = 'asc')
+
+
+        #Check asc file
+        ascid = open(ascfile)
+        lines = ascid.readlines()
+        ascid.close()
+
+        L = lines[0].strip().split()
+        assert L[0].strip().lower() == 'ncols'
+        assert L[1].strip().lower() == '5'
+
+        L = lines[1].strip().split()
+        assert L[0].strip().lower() == 'nrows'
+        assert L[1].strip().lower() == '5'
+
+        L = lines[2].strip().split()
+        assert L[0].strip().lower() == 'xllcorner'
+        assert allclose(float(L[1].strip().lower()), 308500)
+
+        L = lines[3].strip().split()
+        assert L[0].strip().lower() == 'yllcorner'
+        assert allclose(float(L[1].strip().lower()), 6189000)
+
+        L = lines[4].strip().split()
+        assert L[0].strip().lower() == 'cellsize'
+        assert allclose(float(L[1].strip().lower()), cellsize)
+
+        L = lines[5].strip().split()
+        assert L[0].strip() == 'NODATA_value'
+        assert L[1].strip().lower() == '-9999'
+
+
+        #Check grid values (where applicable)
+        for j in range(5):
+            if j%2 == 0:
+                L = lines[6+j].strip().split()
+                jj = 4-j
+                for i in range(5):
+                    if i%2 == 0:
+                        index = jj/2 + i/2*3
+                        val0 = stage[0,index]
+                        val1 = stage[1,index]
+
+                        #print i, j, index, ':', L[i], val0, val1
+                        assert allclose(float(L[i]), min(val0, val1))
+
+
+        fid.close()
+
+        #Cleanup
+        os.remove(prjfile)
+        os.remove(ascfile)
+        #os.remove(swwfile)
+
+
+
+    def test_sww2dem_asc_derived_quantity(self):
+        """Test that sww information can be converted correctly to asc/prj
+        format readable by e.g. ArcView
+
+        This tests the use of derived quantities
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Setup
+        self.domain.filename = 'datatest'
+
+        prjfile = self.domain.filename + '_depth.prj'
+        ascfile = self.domain.filename + '_depth.asc'
+        swwfile = self.domain.filename + '.sww'
+
+        self.domain.set_datadir('.')
+        self.domain.format = 'sww'
+        self.domain.smooth = True
+        self.domain.set_quantity('elevation', lambda x,y: -x-y)
+        self.domain.set_quantity('stage', 0.0)
+
+        self.domain.geo_reference = Geo_reference(56,308500,6189000)
+
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+
+        self.domain.evolve_to_end(finaltime = 0.01)
+        sww.store_timestep('stage')
+
+        cellsize = 0.25
+        #Check contents
+        #Get NetCDF
+
+        fid = NetCDFFile(sww.filename, 'r')
+
+        # Get the variables
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        z = fid.variables['elevation'][:]
+        time = fid.variables['time'][:]
+        stage = fid.variables['stage'][:]
+
+
+        #Export to ascii/prj files
+        sww2dem(self.domain.filename,
+                basename_out = 'datatest_depth',
+                quantity = 'stage - elevation',
+                cellsize = cellsize,
+                reduction = min,
+		format = 'asc',
+                verbose = False)
+
+
+        #Check asc file
+        ascid = open(ascfile)
+        lines = ascid.readlines()
+        ascid.close()
+
+        L = lines[0].strip().split()
+        assert L[0].strip().lower() == 'ncols'
+        assert L[1].strip().lower() == '5'
+
+        L = lines[1].strip().split()
+        assert L[0].strip().lower() == 'nrows'
+        assert L[1].strip().lower() == '5'
+
+        L = lines[2].strip().split()
+        assert L[0].strip().lower() == 'xllcorner'
+        assert allclose(float(L[1].strip().lower()), 308500)
+
+        L = lines[3].strip().split()
+        assert L[0].strip().lower() == 'yllcorner'
+        assert allclose(float(L[1].strip().lower()), 6189000)
+
+        L = lines[4].strip().split()
+        assert L[0].strip().lower() == 'cellsize'
+        assert allclose(float(L[1].strip().lower()), cellsize)
+
+        L = lines[5].strip().split()
+        assert L[0].strip() == 'NODATA_value'
+        assert L[1].strip().lower() == '-9999'
+
+
+        #Check grid values (where applicable)
+        for j in range(5):
+            if j%2 == 0:
+                L = lines[6+j].strip().split()
+                jj = 4-j
+                for i in range(5):
+                    if i%2 == 0:
+                        index = jj/2 + i/2*3
+                        val0 = stage[0,index] - z[index]
+                        val1 = stage[1,index] - z[index]
+
+                        #print i, j, index, ':', L[i], val0, val1
+                        assert allclose(float(L[i]), min(val0, val1))
+
+
+        fid.close()
+
+        #Cleanup
+        os.remove(prjfile)
+        os.remove(ascfile)
+        #os.remove(swwfile)
+
+
+
+
+
+    def test_sww2dem_asc_missing_points(self):
+        """Test that sww information can be converted correctly to asc/prj
+        format readable by e.g. ArcView
+
+        This test includes the writing of missing values
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Setup mesh not coinciding with rectangle.
+        #This will cause missing values to occur in gridded data
+
+
+        points = [                        [1.0, 1.0],
+                              [0.5, 0.5], [1.0, 0.5],
+                  [0.0, 0.0], [0.5, 0.0], [1.0, 0.0]]
+
+        vertices = [ [4,1,3], [5,2,4], [1,4,2], [2,0,1]]
+
+        #Create shallow water domain
+        domain = Domain(points, vertices)
+        domain.default_order=2
+
+
+        #Set some field values
+        domain.set_quantity('elevation', lambda x,y: -x-y)
+        domain.set_quantity('friction', 0.03)
+
+
+        ######################
+        # Boundary conditions
+        B = Transmissive_boundary(domain)
+        domain.set_boundary( {'exterior': B} )
+
+
+        ######################
+        #Initial condition - with jumps
+
+        bed = domain.quantities['elevation'].vertex_values
+        stage = zeros(bed.shape, Float)
+
+        h = 0.3
+        for i in range(stage.shape[0]):
+            if i % 2 == 0:
+                stage[i,:] = bed[i,:] + h
+            else:
+                stage[i,:] = bed[i,:]
+
+        domain.set_quantity('stage', stage)
+        domain.distribute_to_vertices_and_edges()
+
+        domain.filename = 'datatest'
+
+        prjfile = domain.filename + '_elevation.prj'
+        ascfile = domain.filename + '_elevation.asc'
+        swwfile = domain.filename + '.sww'
+
+        domain.set_datadir('.')
+        domain.format = 'sww'
+        domain.smooth = True
+
+        domain.geo_reference = Geo_reference(56,308500,6189000)
+
+        sww = get_dataobject(domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+
+        cellsize = 0.25
+        #Check contents
+        #Get NetCDF
+
+        fid = NetCDFFile(swwfile, 'r')
+
+        # Get the variables
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        z = fid.variables['elevation'][:]
+        time = fid.variables['time'][:]
+
+        try:
+            geo_reference = Geo_reference(NetCDFObject=fid)
+        except AttributeError, e:
+            geo_reference = Geo_reference(DEFAULT_ZONE,0,0)
+
+        #Export to ascii/prj files
+        sww2dem(domain.filename,
+                quantity = 'elevation',
+                cellsize = cellsize,
+                verbose = False,
+		format = 'asc')
+
+
+        #Check asc file
+        ascid = open(ascfile)
+        lines = ascid.readlines()
+        ascid.close()
+
+        L = lines[0].strip().split()
+        assert L[0].strip().lower() == 'ncols'
+        assert L[1].strip().lower() == '5'
+
+        L = lines[1].strip().split()
+        assert L[0].strip().lower() == 'nrows'
+        assert L[1].strip().lower() == '5'
+
+        L = lines[2].strip().split()
+        assert L[0].strip().lower() == 'xllcorner'
+        assert allclose(float(L[1].strip().lower()), 308500)
+
+        L = lines[3].strip().split()
+        assert L[0].strip().lower() == 'yllcorner'
+        assert allclose(float(L[1].strip().lower()), 6189000)
+
+        L = lines[4].strip().split()
+        assert L[0].strip().lower() == 'cellsize'
+        assert allclose(float(L[1].strip().lower()), cellsize)
+
+        L = lines[5].strip().split()
+        assert L[0].strip() == 'NODATA_value'
+        assert L[1].strip().lower() == '-9999'
+
+        #Check grid values
+        for j in range(5):
+            L = lines[6+j].strip().split()
+            assert len(L) == 5
+            y = (4-j) * cellsize
+
+            for i in range(5):
+                #print i
+                if i+j >= 4:
+                    assert allclose(float(L[i]), -i*cellsize - y)
+                else:
+                    #Missing values
+                    assert allclose(float(L[i]), -9999)
+
+
+
+        fid.close()
+
+        #Cleanup
+        os.remove(prjfile)
+        os.remove(ascfile)
+        os.remove(swwfile)
+
+    def test_sww2ers_simple(self):
+        """Test that sww information can be converted correctly to asc/prj
+        format readable by e.g. ArcView
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+
+        NODATA_value = 1758323
+
+        #Setup
+        self.domain.filename = 'datatest'
+
+        headerfile = self.domain.filename + '.ers'
+        swwfile = self.domain.filename + '.sww'
+
+        self.domain.set_datadir('.')
+        self.domain.format = 'sww'
+        self.domain.smooth = True
+        self.domain.set_quantity('elevation', lambda x,y: -x-y)
+
+        self.domain.geo_reference = Geo_reference(56,308500,6189000)
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+
+        self.domain.evolve_to_end(finaltime = 0.01)
+        sww.store_timestep('stage')
+
+        cellsize = 0.25
+        #Check contents
+        #Get NetCDF
+
+        fid = NetCDFFile(sww.filename, 'r')
+
+        # Get the variables
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        z = fid.variables['elevation'][:]
+        time = fid.variables['time'][:]
+        stage = fid.variables['stage'][:]
+
+
+        #Export to ers files
+        sww2dem(self.domain.filename,
+                quantity = 'elevation',
+                cellsize = cellsize,
+                NODATA_value = NODATA_value,
+                verbose = False,
+		format = 'ers')
+
+        #Check header data
+	from ermapper_grids import read_ermapper_header, read_ermapper_data
+
+	header = read_ermapper_header(self.domain.filename + '_elevation.ers')
+        #print header
+        assert header['projection'].lower() == '"utm-56"'
+        assert header['datum'].lower() == '"wgs84"'
+        assert header['units'].lower() == '"meters"'
+        assert header['value'].lower() == '"elevation"'
+        assert header['xdimension'] == '0.25'
+        assert header['ydimension'] == '0.25'
+        assert float(header['eastings']) == 308500.0   #xllcorner
+        assert float(header['northings']) == 6189000.0 #yllcorner
+        assert int(header['nroflines']) == 5
+        assert int(header['nrofcellsperline']) == 5
+        assert int(header['nullcellvalue']) == NODATA_value
+	#FIXME - there is more in the header
+
+
+        #Check grid data
+        grid = read_ermapper_data(self.domain.filename + '_elevation')
+
+	#FIXME (Ole): Why is this the desired reference grid for -x-y?
+	ref_grid = [NODATA_value, NODATA_value, NODATA_value, NODATA_value, NODATA_value,
+	            -1,    -1.25, -1.5,  -1.75, -2.0,
+	            -0.75, -1.0,  -1.25, -1.5,  -1.75,
+		    -0.5,  -0.75, -1.0,  -1.25, -1.5,
+		    -0.25, -0.5,  -0.75, -1.0,  -1.25]
+
+
+        #print grid
+	assert allclose(grid, ref_grid)
+
+        fid.close()
+
+        #Cleanup
+        #FIXME the file clean-up doesn't work (eg Permission Denied Error)
+        #Done (Ole) - it was because sww2ers didn't close it's sww file
+        os.remove(sww.filename)
+        os.remove(self.domain.filename + '_elevation')
+        os.remove(self.domain.filename + '_elevation.ers')
+
+
+
+    def test_sww2pts_centroids(self):
+        """Test that sww information can be converted correctly to pts data at specified coordinates
+        - in this case, the centroids.
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate, NewAxis
+        from Scientific.IO.NetCDF import NetCDFFile
+        from anuga.geospatial_data.geospatial_data import Geospatial_data
+
+        # Used for points that lie outside mesh
+        NODATA_value = 1758323
+
+        # Setup
+        self.domain.filename = 'datatest'
+
+        ptsfile = self.domain.filename + '_elevation.pts'
+        swwfile = self.domain.filename + '.sww'
+
+        self.domain.set_datadir('.')
+        self.domain.format = 'sww'
+        self.smooth = True #self.set_store_vertices_uniquely(False)
+        self.domain.set_quantity('elevation', lambda x,y: -x-y)
+
+        self.domain.geo_reference = Geo_reference(56,308500,6189000)
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+
+        self.domain.evolve_to_end(finaltime = 0.01)
+        sww.store_timestep('stage')
+
+        # Check contents in NetCDF
+        fid = NetCDFFile(sww.filename, 'r')
+
+        # Get the variables
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        elevation = fid.variables['elevation'][:]
+        time = fid.variables['time'][:]
+        stage = fid.variables['stage'][:]
+
+        volumes = fid.variables['volumes'][:]
+
+
+        # Invoke interpolation for vertex points       
+        points = concatenate( (x[:,NewAxis],y[:,NewAxis]), axis=1 )
+        sww2pts(self.domain.filename,
+                quantity = 'elevation',
+                data_points = points,
+                NODATA_value = NODATA_value,
+                verbose = False)
+        ref_point_values = elevation
+        point_values = Geospatial_data(ptsfile).get_attributes()
+        #print 'P', point_values
+        #print 'Ref', ref_point_values        
+	assert allclose(point_values, ref_point_values)        
+
+
+
+        # Invoke interpolation for centroids
+        points = self.domain.get_centroid_coordinates()
+        #print points
+        sww2pts(self.domain.filename,
+                quantity = 'elevation',
+                data_points = points,
+                NODATA_value = NODATA_value,
+                verbose = False)
+        ref_point_values = [-0.5, -0.5, -1, -1, -1, -1, -1.5, -1.5]   #At centroids
+
+        
+        point_values = Geospatial_data(ptsfile).get_attributes()
+        #print 'P', point_values
+        #print 'Ref', ref_point_values        
+	assert allclose(point_values, ref_point_values)        
+
+
+
+        fid.close()
+
+        #Cleanup
+        os.remove(sww.filename)
+        os.remove(ptsfile)
+
+
+
+
+    def test_ferret2sww1(self):
+        """Test that georeferencing etc works when converting from
+        ferret format (lat/lon) to sww format (UTM)
+        """
+        from Scientific.IO.NetCDF import NetCDFFile
+        import os, sys
+
+        #The test file has
+        # LON = 150.66667, 150.83334, 151, 151.16667
+        # LAT = -34.5, -34.33333, -34.16667, -34 ;
+        # TIME = 0, 0.1, 0.6, 1.1, 1.6, 2.1 ;
+        #
+        # First value (index=0) in small_ha.nc is 0.3400644 cm,
+        # Fourth value (index==3) is -6.50198 cm
+
+
+
+        #Read
+        from anuga.coordinate_transforms.redfearn import redfearn
+        #fid = NetCDFFile(self.test_MOST_file)
+        fid = NetCDFFile(self.test_MOST_file + '_ha.nc')
+        first_value = fid.variables['HA'][:][0,0,0]
+        fourth_value = fid.variables['HA'][:][0,0,3]
+        fid.close()
+
+
+        #Call conversion (with zero origin)
+        #ferret2sww('small', verbose=False,
+        #           origin = (56, 0, 0))
+        ferret2sww(self.test_MOST_file, verbose=False,
+                   origin = (56, 0, 0))
+
+        #Work out the UTM coordinates for first point
+        zone, e, n = redfearn(-34.5, 150.66667)
+        #print zone, e, n
+
+        #Read output file 'small.sww'
+        #fid = NetCDFFile('small.sww')
+        fid = NetCDFFile(self.test_MOST_file + '.sww')
+
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+
+        #Check that first coordinate is correctly represented
+        assert allclose(x[0], e)
+        assert allclose(y[0], n)
+
+        #Check first value
+        stage = fid.variables['stage'][:]
+	xmomentum = fid.variables['xmomentum'][:]
+	ymomentum = fid.variables['ymomentum'][:]
+
+	#print ymomentum
+
+        assert allclose(stage[0,0], first_value/100)  #Meters
+
+        #Check fourth value
+        assert allclose(stage[0,3], fourth_value/100)  #Meters
+
+        fid.close()
+
+        #Cleanup
+        import os
+        os.remove(self.test_MOST_file + '.sww')
+
+
+    def test_ferret2sww_2(self):
+        """Test that georeferencing etc works when converting from
+        ferret format (lat/lon) to sww format (UTM)
+        """
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #The test file has
+        # LON = 150.66667, 150.83334, 151, 151.16667
+        # LAT = -34.5, -34.33333, -34.16667, -34 ;
+        # TIME = 0, 0.1, 0.6, 1.1, 1.6, 2.1 ;
+        #
+        # First value (index=0) in small_ha.nc is 0.3400644 cm,
+        # Fourth value (index==3) is -6.50198 cm
+
+
+        from anuga.coordinate_transforms.redfearn import redfearn
+
+        #fid = NetCDFFile('small_ha.nc')
+        fid = NetCDFFile(self.test_MOST_file + '_ha.nc')
+
+        #Pick a coordinate and a value
+
+        time_index = 1
+        lat_index = 0
+        lon_index = 2
+
+        test_value = fid.variables['HA'][:][time_index, lat_index, lon_index]
+        test_time = fid.variables['TIME'][:][time_index]
+        test_lat = fid.variables['LAT'][:][lat_index]
+        test_lon = fid.variables['LON'][:][lon_index]
+
+        linear_point_index = lat_index*4 + lon_index
+        fid.close()
+
+        #Call conversion (with zero origin)
+        ferret2sww(self.test_MOST_file, verbose=False,
+                   origin = (56, 0, 0))
+
+
+        #Work out the UTM coordinates for test point
+        zone, e, n = redfearn(test_lat, test_lon)
+
+        #Read output file 'small.sww'
+        fid = NetCDFFile(self.test_MOST_file + '.sww')
+
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+
+        #Check that test coordinate is correctly represented
+        assert allclose(x[linear_point_index], e)
+        assert allclose(y[linear_point_index], n)
+
+        #Check test value
+        stage = fid.variables['stage'][:]
+
+        assert allclose(stage[time_index, linear_point_index], test_value/100)
+
+        fid.close()
+
+        #Cleanup
+        import os
+        os.remove(self.test_MOST_file + '.sww')
+
+
+
+    def test_ferret2sww3(self):
+        """Elevation included
+        """
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #The test file has
+        # LON = 150.66667, 150.83334, 151, 151.16667
+        # LAT = -34.5, -34.33333, -34.16667, -34 ;
+        # ELEVATION = [-1 -2 -3 -4
+        #             -5 -6 -7 -8
+        #              ...
+        #              ...      -16]
+        # where the top left corner is -1m,
+        # and the ll corner is -13.0m
+        #
+        # First value (index=0) in small_ha.nc is 0.3400644 cm,
+        # Fourth value (index==3) is -6.50198 cm
+
+        from anuga.coordinate_transforms.redfearn import redfearn
+        import os
+        fid1 = NetCDFFile('test_ha.nc','w')
+        fid2 = NetCDFFile('test_ua.nc','w')
+        fid3 = NetCDFFile('test_va.nc','w')
+        fid4 = NetCDFFile('test_e.nc','w')
+
+        h1_list = [150.66667,150.83334,151.]
+        h2_list = [-34.5,-34.33333]
+
+        long_name = 'LON'
+        lat_name = 'LAT'
+        time_name = 'TIME'
+
+        nx = 3
+        ny = 2
+
+        for fid in [fid1,fid2,fid3]:
+	    fid.createDimension(long_name,nx)
+	    fid.createVariable(long_name,'d',(long_name,))
+	    fid.variables[long_name].point_spacing='uneven'
+	    fid.variables[long_name].units='degrees_east'
+	    fid.variables[long_name].assignValue(h1_list)
+
+	    fid.createDimension(lat_name,ny)
+	    fid.createVariable(lat_name,'d',(lat_name,))
+	    fid.variables[lat_name].point_spacing='uneven'
+	    fid.variables[lat_name].units='degrees_north'
+	    fid.variables[lat_name].assignValue(h2_list)
+
+	    fid.createDimension(time_name,2)
+	    fid.createVariable(time_name,'d',(time_name,))
+	    fid.variables[time_name].point_spacing='uneven'
+	    fid.variables[time_name].units='seconds'
+	    fid.variables[time_name].assignValue([0.,1.])
+	    if fid == fid3: break
+
+
+        for fid in [fid4]:
+	    fid.createDimension(long_name,nx)
+	    fid.createVariable(long_name,'d',(long_name,))
+	    fid.variables[long_name].point_spacing='uneven'
+	    fid.variables[long_name].units='degrees_east'
+	    fid.variables[long_name].assignValue(h1_list)
+
+	    fid.createDimension(lat_name,ny)
+	    fid.createVariable(lat_name,'d',(lat_name,))
+	    fid.variables[lat_name].point_spacing='uneven'
+	    fid.variables[lat_name].units='degrees_north'
+	    fid.variables[lat_name].assignValue(h2_list)
+
+        name = {}
+        name[fid1]='HA'
+        name[fid2]='UA'
+        name[fid3]='VA'
+        name[fid4]='ELEVATION'
+
+        units = {}
+        units[fid1]='cm'
+        units[fid2]='cm/s'
+        units[fid3]='cm/s'
+        units[fid4]='m'
+
+        values = {}
+        values[fid1]=[[[5., 10.,15.], [13.,18.,23.]],[[50.,100.,150.],[130.,180.,230.]]]
+        values[fid2]=[[[1., 2.,3.], [4.,5.,6.]],[[7.,8.,9.],[10.,11.,12.]]]
+        values[fid3]=[[[13., 12.,11.], [10.,9.,8.]],[[7.,6.,5.],[4.,3.,2.]]]
+        values[fid4]=[[-3000,-3100,-3200],[-4000,-5000,-6000]]
+
+        for fid in [fid1,fid2,fid3]:
+          fid.createVariable(name[fid],'d',(time_name,lat_name,long_name))
+          fid.variables[name[fid]].point_spacing='uneven'
+          fid.variables[name[fid]].units=units[fid]
+          fid.variables[name[fid]].assignValue(values[fid])
+          fid.variables[name[fid]].missing_value = -99999999.
+          if fid == fid3: break
+
+        for fid in [fid4]:
+            fid.createVariable(name[fid],'d',(lat_name,long_name))
+            fid.variables[name[fid]].point_spacing='uneven'
+            fid.variables[name[fid]].units=units[fid]
+            fid.variables[name[fid]].assignValue(values[fid])
+            fid.variables[name[fid]].missing_value = -99999999.
+
+
+        fid1.sync(); fid1.close()
+        fid2.sync(); fid2.close()
+        fid3.sync(); fid3.close()
+        fid4.sync(); fid4.close()
+
+        fid1 = NetCDFFile('test_ha.nc','r')
+        fid2 = NetCDFFile('test_e.nc','r')
+        fid3 = NetCDFFile('test_va.nc','r')
+
+
+        first_amp = fid1.variables['HA'][:][0,0,0]
+        third_amp = fid1.variables['HA'][:][0,0,2]
+        first_elevation = fid2.variables['ELEVATION'][0,0]
+        third_elevation= fid2.variables['ELEVATION'][:][0,2]
+        first_speed = fid3.variables['VA'][0,0,0]
+        third_speed = fid3.variables['VA'][:][0,0,2]
+
+        fid1.close()
+        fid2.close()
+        fid3.close()
+
+        #Call conversion (with zero origin)
+        ferret2sww('test', verbose=False,
+                   origin = (56, 0, 0))
+
+        os.remove('test_va.nc')
+        os.remove('test_ua.nc')
+        os.remove('test_ha.nc')
+        os.remove('test_e.nc')
+
+        #Read output file 'test.sww'
+        fid = NetCDFFile('test.sww')
+
+
+        #Check first value
+        elevation = fid.variables['elevation'][:]
+        stage = fid.variables['stage'][:]
+        xmomentum = fid.variables['xmomentum'][:]
+        ymomentum = fid.variables['ymomentum'][:]
+
+        #print ymomentum
+        first_height = first_amp/100 - first_elevation
+        third_height = third_amp/100 - third_elevation
+        first_momentum=first_speed*first_height/100
+        third_momentum=third_speed*third_height/100
+
+        assert allclose(ymomentum[0][0],first_momentum)  #Meters
+        assert allclose(ymomentum[0][2],third_momentum)  #Meters
+
+        fid.close()
+
+        #Cleanup
+        os.remove('test.sww')
+
+
+
+    def test_ferret2sww4(self):
+        """Like previous but with augmented variable names as
+        in files produced by ferret as opposed to MOST
+        """
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #The test file has
+        # LON = 150.66667, 150.83334, 151, 151.16667
+        # LAT = -34.5, -34.33333, -34.16667, -34 ;
+        # ELEVATION = [-1 -2 -3 -4
+        #             -5 -6 -7 -8
+        #              ...
+        #              ...      -16]
+        # where the top left corner is -1m,
+        # and the ll corner is -13.0m
+        #
+        # First value (index=0) in small_ha.nc is 0.3400644 cm,
+        # Fourth value (index==3) is -6.50198 cm
+
+        from anuga.coordinate_transforms.redfearn import redfearn
+        import os
+        fid1 = NetCDFFile('test_ha.nc','w')
+        fid2 = NetCDFFile('test_ua.nc','w')
+        fid3 = NetCDFFile('test_va.nc','w')
+        fid4 = NetCDFFile('test_e.nc','w')
+
+        h1_list = [150.66667,150.83334,151.]
+        h2_list = [-34.5,-34.33333]
+
+#        long_name = 'LON961_1261'
+#        lat_name = 'LAT481_841'
+#        time_name = 'TIME1'
+
+        long_name = 'LON'
+        lat_name = 'LAT'
+        time_name = 'TIME'
+
+        nx = 3
+        ny = 2
+
+        for fid in [fid1,fid2,fid3]:
+	    fid.createDimension(long_name,nx)
+	    fid.createVariable(long_name,'d',(long_name,))
+	    fid.variables[long_name].point_spacing='uneven'
+	    fid.variables[long_name].units='degrees_east'
+	    fid.variables[long_name].assignValue(h1_list)
+
+	    fid.createDimension(lat_name,ny)
+	    fid.createVariable(lat_name,'d',(lat_name,))
+	    fid.variables[lat_name].point_spacing='uneven'
+	    fid.variables[lat_name].units='degrees_north'
+	    fid.variables[lat_name].assignValue(h2_list)
+
+	    fid.createDimension(time_name,2)
+	    fid.createVariable(time_name,'d',(time_name,))
+	    fid.variables[time_name].point_spacing='uneven'
+	    fid.variables[time_name].units='seconds'
+	    fid.variables[time_name].assignValue([0.,1.])
+	    if fid == fid3: break
+
+
+        for fid in [fid4]:
+	    fid.createDimension(long_name,nx)
+	    fid.createVariable(long_name,'d',(long_name,))
+	    fid.variables[long_name].point_spacing='uneven'
+	    fid.variables[long_name].units='degrees_east'
+	    fid.variables[long_name].assignValue(h1_list)
+
+	    fid.createDimension(lat_name,ny)
+	    fid.createVariable(lat_name,'d',(lat_name,))
+	    fid.variables[lat_name].point_spacing='uneven'
+	    fid.variables[lat_name].units='degrees_north'
+	    fid.variables[lat_name].assignValue(h2_list)
+
+        name = {}
+        name[fid1]='HA'
+        name[fid2]='UA'
+        name[fid3]='VA'
+        name[fid4]='ELEVATION'
+
+        units = {}
+        units[fid1]='cm'
+        units[fid2]='cm/s'
+        units[fid3]='cm/s'
+        units[fid4]='m'
+
+        values = {}
+        values[fid1]=[[[5., 10.,15.], [13.,18.,23.]],[[50.,100.,150.],[130.,180.,230.]]]
+        values[fid2]=[[[1., 2.,3.], [4.,5.,6.]],[[7.,8.,9.],[10.,11.,12.]]]
+        values[fid3]=[[[13., 12.,11.], [10.,9.,8.]],[[7.,6.,5.],[4.,3.,2.]]]
+        values[fid4]=[[-3000,-3100,-3200],[-4000,-5000,-6000]]
+
+        for fid in [fid1,fid2,fid3]:
+          fid.createVariable(name[fid],'d',(time_name,lat_name,long_name))
+          fid.variables[name[fid]].point_spacing='uneven'
+          fid.variables[name[fid]].units=units[fid]
+          fid.variables[name[fid]].assignValue(values[fid])
+          fid.variables[name[fid]].missing_value = -99999999.
+          if fid == fid3: break
+
+        for fid in [fid4]:
+	    fid.createVariable(name[fid],'d',(lat_name,long_name))
+            fid.variables[name[fid]].point_spacing='uneven'
+            fid.variables[name[fid]].units=units[fid]
+            fid.variables[name[fid]].assignValue(values[fid])
+            fid.variables[name[fid]].missing_value = -99999999.
+
+
+        fid1.sync(); fid1.close()
+        fid2.sync(); fid2.close()
+        fid3.sync(); fid3.close()
+        fid4.sync(); fid4.close()
+
+        fid1 = NetCDFFile('test_ha.nc','r')
+        fid2 = NetCDFFile('test_e.nc','r')
+        fid3 = NetCDFFile('test_va.nc','r')
+
+
+        first_amp = fid1.variables['HA'][:][0,0,0]
+        third_amp = fid1.variables['HA'][:][0,0,2]
+        first_elevation = fid2.variables['ELEVATION'][0,0]
+        third_elevation= fid2.variables['ELEVATION'][:][0,2]
+        first_speed = fid3.variables['VA'][0,0,0]
+        third_speed = fid3.variables['VA'][:][0,0,2]
+
+        fid1.close()
+        fid2.close()
+        fid3.close()
+
+        #Call conversion (with zero origin)
+        ferret2sww('test', verbose=False, origin = (56, 0, 0))
+
+        os.remove('test_va.nc')
+        os.remove('test_ua.nc')
+        os.remove('test_ha.nc')
+        os.remove('test_e.nc')
+
+        #Read output file 'test.sww'
+        fid = NetCDFFile('test.sww')
+
+
+        #Check first value
+        elevation = fid.variables['elevation'][:]
+        stage = fid.variables['stage'][:]
+        xmomentum = fid.variables['xmomentum'][:]
+        ymomentum = fid.variables['ymomentum'][:]
+
+        #print ymomentum
+        first_height = first_amp/100 - first_elevation
+        third_height = third_amp/100 - third_elevation
+        first_momentum=first_speed*first_height/100
+        third_momentum=third_speed*third_height/100
+
+        assert allclose(ymomentum[0][0],first_momentum)  #Meters
+        assert allclose(ymomentum[0][2],third_momentum)  #Meters
+
+        fid.close()
+
+        #Cleanup
+        os.remove('test.sww')
+
+
+
+
+    def test_ferret2sww_nz_origin(self):
+        from Scientific.IO.NetCDF import NetCDFFile
+        from anuga.coordinate_transforms.redfearn import redfearn
+
+        #Call conversion (with nonzero origin)
+        ferret2sww(self.test_MOST_file, verbose=False,
+                   origin = (56, 100000, 200000))
+
+
+        #Work out the UTM coordinates for first point
+        zone, e, n = redfearn(-34.5, 150.66667)
+
+        #Read output file 'small.sww'
+        #fid = NetCDFFile('small.sww', 'r')
+        fid = NetCDFFile(self.test_MOST_file + '.sww')
+
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+
+        #Check that first coordinate is correctly represented
+        assert allclose(x[0], e-100000)
+        assert allclose(y[0], n-200000)
+
+        fid.close()
+
+        #Cleanup
+        os.remove(self.test_MOST_file + '.sww')
+
+
+
+    def test_sww_extent(self):
+        """Not a test, rather a look at the sww format
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        self.domain.filename = 'datatest' + str(id(self))
+        self.domain.format = 'sww'
+        self.domain.smooth = True
+        self.domain.reduction = mean
+        self.domain.set_datadir('.')
+
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+        self.domain.time = 2.
+
+        #Modify stage at second timestep
+        stage = self.domain.quantities['stage'].vertex_values
+        self.domain.set_quantity('stage', stage/2)
+
+        sww.store_timestep('stage')
+
+        file_and_extension_name = self.domain.filename + ".sww"
+        #print "file_and_extension_name",file_and_extension_name
+        [xmin, xmax, ymin, ymax, stagemin, stagemax] = \
+               extent_sww(file_and_extension_name )
+
+        assert allclose(xmin, 0.0)
+        assert allclose(xmax, 1.0)
+        assert allclose(ymin, 0.0)
+        assert allclose(ymax, 1.0)
+        assert allclose(stagemin, -0.85)
+        assert allclose(stagemax, 0.15)
+
+
+        #Cleanup
+        os.remove(sww.filename)
+
+
+
+    def test_sww2domain1(self):
+        ################################################
+        #Create a test domain, and evolve and save it.
+        ################################################
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+            Constant_height, Time_boundary, Transmissive_boundary
+        from Numeric import array
+
+        #Create basic mesh
+
+        yiel=0.01
+        points, vertices, boundary = rectangular(10,10)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.geo_reference = Geo_reference(56,11,11)
+        domain.smooth = False
+        domain.visualise = False
+        domain.store = True
+        domain.filename = 'bedslope'
+        domain.default_order=2
+        #Bed-slope and friction
+        domain.set_quantity('elevation', lambda x,y: -x/3)
+        domain.set_quantity('friction', 0.1)
+        # Boundary conditions
+        from math import sin, pi
+        Br = Reflective_boundary(domain)
+        Bt = Transmissive_boundary(domain)
+        Bd = Dirichlet_boundary([0.2,0.,0.])
+        Bw = Time_boundary(domain=domain,f=lambda t: [(0.1*sin(t*2*pi)), 0.0, 0.0])
+
+        #domain.set_boundary({'left': Bd, 'right': Br, 'top': Br, 'bottom': Br})
+        domain.set_boundary({'left': Bd, 'right': Bd, 'top': Bd, 'bottom': Bd})
+
+        domain.quantities_to_be_stored.extend(['xmomentum','ymomentum'])
+        #Initial condition
+        h = 0.05
+        elevation = domain.quantities['elevation'].vertex_values
+        domain.set_quantity('stage', elevation + h)
+
+        domain.check_integrity()
+        #Evolution
+        for t in domain.evolve(yieldstep = yiel, finaltime = 0.05):
+            #domain.write_time()
+            pass
+
+
+        ##########################################
+        #Import the example's file as a new domain
+        ##########################################
+        from anuga.abstract_2d_finite_volumes.data_manager import sww2domain
+        from Numeric import allclose
+        import os
+
+        filename = domain.datadir+os.sep+domain.filename+'.sww'
+        domain2 = sww2domain(filename,None,fail_if_NaN=False,verbose = False)
+        #points, vertices, boundary = rectangular(15,15)
+        #domain2.boundary = boundary
+        ###################
+        ##NOW TEST IT!!!
+        ###################
+
+        #os.remove(domain.filename + '.sww')
+        os.remove(filename)
+
+        bits = ['vertex_coordinates']
+        for quantity in ['elevation']+domain.quantities_to_be_stored:
+            bits.append('get_quantity("%s").get_integral()' %quantity)
+            bits.append('get_quantity("%s").get_values()' %quantity)
+
+        for bit in bits:
+            #print 'testing that domain.'+bit+' has been restored'
+            #print bit
+            #print 'done'
+            assert allclose(eval('domain.'+bit),eval('domain2.'+bit))
+
+        ######################################
+        #Now evolve them both, just to be sure
+        ######################################x
+        visualise = False
+        #visualise = True
+        domain.visualise = visualise
+        domain.time = 0.
+        from time import sleep
+
+        final = .1
+        domain.set_quantity('friction', 0.1)
+        domain.store = False
+        domain.set_boundary({'left': Bd, 'right': Bd, 'top': Bd, 'bottom': Bd})
+
+
+        for t in domain.evolve(yieldstep = yiel, finaltime = final):
+            if visualise: sleep(1.)
+            #domain.write_time()
+            pass
+
+        final = final - (domain2.starttime-domain.starttime)
+        #BUT since domain1 gets time hacked back to 0:
+        final = final + (domain2.starttime-domain.starttime)
+
+        domain2.smooth = False
+        domain2.visualise = visualise
+        domain2.store = False
+        domain2.default_order=2
+        domain2.set_quantity('friction', 0.1)
+        #Bed-slope and friction
+        # Boundary conditions
+        Bd2=Dirichlet_boundary([0.2,0.,0.])
+        domain2.boundary = domain.boundary
+        #print 'domain2.boundary'
+        #print domain2.boundary
+        domain2.set_boundary({'left': Bd, 'right': Bd, 'top': Bd, 'bottom': Bd})
+        #domain2.set_boundary({'exterior': Bd})
+
+        domain2.check_integrity()
+
+        for t in domain2.evolve(yieldstep = yiel, finaltime = final):
+            if visualise: sleep(1.)
+            #domain2.write_time()
+            pass
+
+        ###################
+        ##NOW TEST IT!!!
+        ##################
+
+        bits = ['vertex_coordinates']
+
+        for quantity in ['elevation','stage', 'ymomentum','xmomentum']:
+            bits.append('get_quantity("%s").get_integral()' %quantity)
+            bits.append('get_quantity("%s").get_values()' %quantity)
+
+        #print bits
+        for bit in bits:
+            #print bit
+            #print eval('domain.'+bit)
+            #print eval('domain2.'+bit)
+            
+            #print eval('domain.'+bit+'-domain2.'+bit)
+            msg = 'Values in the two domains are different for ' + bit
+            assert allclose(eval('domain.'+bit),eval('domain2.'+bit),
+                            rtol=1.e-5, atol=3.e-8), msg
+
+
+    def test_sww2domain2(self):
+	##################################################################
+	#Same as previous test, but this checks how NaNs are handled.
+	##################################################################
+
+
+	from mesh_factory import rectangular
+	from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+	     Constant_height, Time_boundary, Transmissive_boundary
+	from Numeric import array
+
+	#Create basic mesh
+	points, vertices, boundary = rectangular(2,2)
+
+	#Create shallow water domain
+	domain = Domain(points, vertices, boundary)
+	domain.smooth = False
+	domain.visualise = False
+	domain.store = True
+	domain.set_name('test_file')
+        domain.set_datadir('.')
+	domain.default_order=2
+	domain.quantities_to_be_stored=['stage']
+
+	domain.set_quantity('elevation', lambda x,y: -x/3)
+	domain.set_quantity('friction', 0.1)
+
+	from math import sin, pi
+	Br = Reflective_boundary(domain)
+	Bt = Transmissive_boundary(domain)
+	Bd = Dirichlet_boundary([0.2,0.,0.])
+	Bw = Time_boundary(domain=domain,
+			   f=lambda t: [(0.1*sin(t*2*pi)), 0.0, 0.0])
+
+	domain.set_boundary({'left': Bd, 'right': Br, 'top': Br, 'bottom': Br})
+
+	h = 0.05
+	elevation = domain.quantities['elevation'].vertex_values
+	domain.set_quantity('stage', elevation + h)
+
+	domain.check_integrity()
+
+	for t in domain.evolve(yieldstep = 1, finaltime = 2.0):
+	    pass
+	    #domain.write_time()
+
+
+
+        ##################################
+	#Import the file as a new domain
+        ##################################
+	from anuga.abstract_2d_finite_volumes.data_manager import sww2domain
+	from Numeric import allclose
+        import os
+
+	filename = domain.datadir+os.sep+domain.filename+'.sww'
+
+	#Fail because NaNs are present
+	try:
+	    domain2 = sww2domain(filename,boundary,fail_if_NaN=True,verbose=False)
+	except:
+	    #Now import it, filling NaNs to be 0
+	    filler = 0
+	    domain2 = sww2domain(filename,None,fail_if_NaN=False,NaN_filler = filler,verbose=False)
+
+        #Clean up
+        os.remove(filename)
+
+
+        bits = [ 'geo_reference.get_xllcorner()',
+                'geo_reference.get_yllcorner()',
+                'vertex_coordinates']
+
+	for quantity in ['elevation']+domain.quantities_to_be_stored:
+	    bits.append('get_quantity("%s").get_integral()' %quantity)
+	    bits.append('get_quantity("%s").get_values()' %quantity)
+
+	for bit in bits:
+	#    print 'testing that domain.'+bit+' has been restored'
+	    assert allclose(eval('domain.'+bit),eval('domain2.'+bit))
+
+	assert max(max(domain2.get_quantity('xmomentum').get_values()))==filler
+	assert min(min(domain2.get_quantity('xmomentum').get_values()))==filler
+	assert max(max(domain2.get_quantity('ymomentum').get_values()))==filler
+	assert min(min(domain2.get_quantity('ymomentum').get_values()))==filler
+
+
+
+    #def test_weed(self):
+	from anuga.abstract_2d_finite_volumes.data_manager import weed
+
+        coordinates1 = [[0.,0.],[1.,0.],[1.,1.],[1.,0.],[2.,0.],[1.,1.]]
+        volumes1 = [[0,1,2],[3,4,5]]
+        boundary1= {(0,1): 'external',(1,2): 'not external',(2,0): 'external',(3,4): 'external',(4,5): 'external',(5,3): 'not external'}
+        coordinates2,volumes2,boundary2=weed(coordinates1,volumes1,boundary1)
+
+        points2 = {(0.,0.):None,(1.,0.):None,(1.,1.):None,(2.,0.):None}
+
+        assert len(points2)==len(coordinates2)
+        for i in range(len(coordinates2)):
+            coordinate = tuple(coordinates2[i])
+            assert points2.has_key(coordinate)
+            points2[coordinate]=i
+
+        for triangle in volumes1:
+            for coordinate in triangle:
+                assert coordinates2[points2[tuple(coordinates1[coordinate])]][0]==coordinates1[coordinate][0]
+                assert coordinates2[points2[tuple(coordinates1[coordinate])]][1]==coordinates1[coordinate][1]
+
+
+    #FIXME This fails - smooth makes the comparism too hard for allclose
+    def ztest_sww2domain3(self):
+	################################################
+	#DOMAIN.SMOOTH = TRUE !!!!!!!!!!!!!!!!!!!!!!!!!!
+	################################################
+	from mesh_factory import rectangular
+	from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+	     Constant_height, Time_boundary, Transmissive_boundary
+	from Numeric import array
+	#Create basic mesh
+
+        yiel=0.01
+	points, vertices, boundary = rectangular(10,10)
+
+	#Create shallow water domain
+	domain = Domain(points, vertices, boundary)
+        domain.geo_reference = Geo_reference(56,11,11)
+	domain.smooth = True
+	domain.visualise = False
+	domain.store = True
+	domain.filename = 'bedslope'
+	domain.default_order=2
+	#Bed-slope and friction
+	domain.set_quantity('elevation', lambda x,y: -x/3)
+	domain.set_quantity('friction', 0.1)
+	# Boundary conditions
+	from math import sin, pi
+	Br = Reflective_boundary(domain)
+	Bt = Transmissive_boundary(domain)
+	Bd = Dirichlet_boundary([0.2,0.,0.])
+ 	Bw = Time_boundary(domain=domain,
+			   f=lambda t: [(0.1*sin(t*2*pi)), 0.0, 0.0])
+
+	domain.set_boundary({'left': Bd, 'right': Bd, 'top': Bd, 'bottom': Bd})
+
+	domain.quantities_to_be_stored.extend(['xmomentum','ymomentum'])
+	#Initial condition
+	h = 0.05
+	elevation = domain.quantities['elevation'].vertex_values
+	domain.set_quantity('stage', elevation + h)
+
+
+	domain.check_integrity()
+	#Evolution
+	for t in domain.evolve(yieldstep = yiel, finaltime = 0.05):
+	#    domain.write_time()
+	    pass
+
+
+	##########################################
+	#Import the example's file as a new domain
+	##########################################
+	from anuga.abstract_2d_finite_volumes.data_manager import sww2domain
+	from Numeric import allclose
+        import os
+
+	filename = domain.datadir+os.sep+domain.filename+'.sww'
+	domain2 = sww2domain(filename,None,fail_if_NaN=False,verbose = False)
+	#points, vertices, boundary = rectangular(15,15)
+        #domain2.boundary = boundary
+        ###################
+	##NOW TEST IT!!!
+        ###################
+
+        os.remove(domain.filename + '.sww')
+
+        #FIXME smooth domain so that they can be compared
+
+
+	bits = []#'vertex_coordinates']
+	for quantity in ['elevation']+domain.quantities_to_be_stored:
+	    bits.append('quantities["%s"].get_integral()'%quantity)
+
+
+	for bit in bits:
+	    #print 'testing that domain.'+bit+' has been restored'
+            #print bit
+            #print 'done'
+            #print ('domain.'+bit), eval('domain.'+bit)
+            #print ('domain2.'+bit), eval('domain2.'+bit)
+	    assert allclose(eval('domain.'+bit),eval('domain2.'+bit),rtol=1.0e-1,atol=1.e-3)
+            pass
+
+        ######################################
+        #Now evolve them both, just to be sure
+        ######################################x
+        visualise = False
+        visualise = True
+	domain.visualise = visualise
+        domain.time = 0.
+        from time import sleep
+
+        final = .5
+        domain.set_quantity('friction', 0.1)
+	domain.store = False
+	domain.set_boundary({'left': Bd, 'right': Bd, 'top': Bd, 'bottom': Br})
+
+	for t in domain.evolve(yieldstep = yiel, finaltime = final):
+            if visualise: sleep(.03)
+	    #domain.write_time()
+	    pass
+
+	domain2.smooth = True
+	domain2.visualise = visualise
+	domain2.store = False
+	domain2.default_order=2
+	domain2.set_quantity('friction', 0.1)
+	#Bed-slope and friction
+	# Boundary conditions
+        Bd2=Dirichlet_boundary([0.2,0.,0.])
+	Br2 = Reflective_boundary(domain2)
+        domain2.boundary = domain.boundary
+        #print 'domain2.boundary'
+        #print domain2.boundary
+	domain2.set_boundary({'left': Bd2, 'right': Bd2, 'top': Bd2, 'bottom': Br2})
+        #domain2.boundary = domain.boundary
+	#domain2.set_boundary({'exterior': Bd})
+
+	domain2.check_integrity()
+
+	for t in domain2.evolve(yieldstep = yiel, finaltime = final):
+            if visualise: sleep(.03)
+	    #domain2.write_time()
+	    pass
+
+        ###################
+	##NOW TEST IT!!!
+        ##################
+
+        print '><><><><>>'
+	bits = [ 'vertex_coordinates']
+
+	for quantity in ['elevation','xmomentum','ymomentum']:#+domain.quantities_to_be_stored:
+	    #bits.append('quantities["%s"].get_integral()'%quantity)
+	    bits.append('get_quantity("%s").get_values()' %quantity)
+
+	for bit in bits:
+            print bit
+	    assert allclose(eval('domain.'+bit),eval('domain2.'+bit))
+
+
+    def test_decimate_dem(self):
+        """Test decimation of dem file
+        """
+
+        import os
+        from Numeric import ones, allclose, Float, arange
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Write test dem file
+        root = 'decdemtest'
+
+        filename = root + '.dem'
+        fid = NetCDFFile(filename, 'w')
+
+        fid.institution = 'Geoscience Australia'
+        fid.description = 'NetCDF DEM format for compact and portable ' +\
+                          'storage of spatial point data'
+
+        nrows = 15
+        ncols = 18
+
+        fid.ncols = ncols
+        fid.nrows = nrows
+        fid.xllcorner = 2000.5
+        fid.yllcorner = 3000.5
+        fid.cellsize = 25
+        fid.NODATA_value = -9999
+
+        fid.zone = 56
+        fid.false_easting = 0.0
+        fid.false_northing = 0.0
+        fid.projection = 'UTM'
+        fid.datum = 'WGS84'
+        fid.units = 'METERS'
+
+        fid.createDimension('number_of_points', nrows*ncols)
+
+        fid.createVariable('elevation', Float, ('number_of_points',))
+
+        elevation = fid.variables['elevation']
+
+        elevation[:] = (arange(nrows*ncols))
+
+        fid.close()
+
+        #generate the elevation values expected in the decimated file
+        ref_elevation = [(  0+  1+  2+ 18+ 19+ 20+ 36+ 37+ 38) / 9.0,
+                         (  4+  5+  6+ 22+ 23+ 24+ 40+ 41+ 42) / 9.0,
+                         (  8+  9+ 10+ 26+ 27+ 28+ 44+ 45+ 46) / 9.0,
+                         ( 12+ 13+ 14+ 30+ 31+ 32+ 48+ 49+ 50) / 9.0,
+                         ( 72+ 73+ 74+ 90+ 91+ 92+108+109+110) / 9.0,
+                         ( 76+ 77+ 78+ 94+ 95+ 96+112+113+114) / 9.0,
+                         ( 80+ 81+ 82+ 98+ 99+100+116+117+118) / 9.0,
+                         ( 84+ 85+ 86+102+103+104+120+121+122) / 9.0,
+                         (144+145+146+162+163+164+180+181+182) / 9.0,
+                         (148+149+150+166+167+168+184+185+186) / 9.0,
+                         (152+153+154+170+171+172+188+189+190) / 9.0,
+                         (156+157+158+174+175+176+192+193+194) / 9.0,
+                         (216+217+218+234+235+236+252+253+254) / 9.0,
+                         (220+221+222+238+239+240+256+257+258) / 9.0,
+                         (224+225+226+242+243+244+260+261+262) / 9.0,
+                         (228+229+230+246+247+248+264+265+266) / 9.0]
+
+        #generate a stencil for computing the decimated values
+        stencil = ones((3,3), Float) / 9.0
+
+        decimate_dem(root, stencil=stencil, cellsize_new=100)
+
+        #Open decimated NetCDF file
+        fid = NetCDFFile(root + '_100.dem', 'r')
+
+        # Get decimated elevation
+        elevation = fid.variables['elevation']
+
+        #Check values
+        assert allclose(elevation, ref_elevation)
+
+        #Cleanup
+        fid.close()
+
+        os.remove(root + '.dem')
+        os.remove(root + '_100.dem')
+
+    def test_decimate_dem_NODATA(self):
+        """Test decimation of dem file that includes NODATA values
+        """
+
+        import os
+        from Numeric import ones, allclose, Float, arange, reshape
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Write test dem file
+        root = 'decdemtest'
+
+        filename = root + '.dem'
+        fid = NetCDFFile(filename, 'w')
+
+        fid.institution = 'Geoscience Australia'
+        fid.description = 'NetCDF DEM format for compact and portable ' +\
+                          'storage of spatial point data'
+
+        nrows = 15
+        ncols = 18
+        NODATA_value = -9999
+
+        fid.ncols = ncols
+        fid.nrows = nrows
+        fid.xllcorner = 2000.5
+        fid.yllcorner = 3000.5
+        fid.cellsize = 25
+        fid.NODATA_value = NODATA_value
+
+        fid.zone = 56
+        fid.false_easting = 0.0
+        fid.false_northing = 0.0
+        fid.projection = 'UTM'
+        fid.datum = 'WGS84'
+        fid.units = 'METERS'
+
+        fid.createDimension('number_of_points', nrows*ncols)
+
+        fid.createVariable('elevation', Float, ('number_of_points',))
+
+        elevation = fid.variables['elevation']
+
+        #generate initial elevation values
+        elevation_tmp = (arange(nrows*ncols))
+        #add some NODATA values
+        elevation_tmp[0]   = NODATA_value
+        elevation_tmp[95]  = NODATA_value
+        elevation_tmp[188] = NODATA_value
+        elevation_tmp[189] = NODATA_value
+        elevation_tmp[190] = NODATA_value
+        elevation_tmp[209] = NODATA_value
+        elevation_tmp[252] = NODATA_value
+
+        elevation[:] = elevation_tmp
+
+        fid.close()
+
+        #generate the elevation values expected in the decimated file
+        ref_elevation = [NODATA_value,
+                         (  4+  5+  6+ 22+ 23+ 24+ 40+ 41+ 42) / 9.0,
+                         (  8+  9+ 10+ 26+ 27+ 28+ 44+ 45+ 46) / 9.0,
+                         ( 12+ 13+ 14+ 30+ 31+ 32+ 48+ 49+ 50) / 9.0,
+                         ( 72+ 73+ 74+ 90+ 91+ 92+108+109+110) / 9.0,
+                         NODATA_value,
+                         ( 80+ 81+ 82+ 98+ 99+100+116+117+118) / 9.0,
+                         ( 84+ 85+ 86+102+103+104+120+121+122) / 9.0,
+                         (144+145+146+162+163+164+180+181+182) / 9.0,
+                         (148+149+150+166+167+168+184+185+186) / 9.0,
+                         NODATA_value,
+                         (156+157+158+174+175+176+192+193+194) / 9.0,
+                         NODATA_value,
+                         (220+221+222+238+239+240+256+257+258) / 9.0,
+                         (224+225+226+242+243+244+260+261+262) / 9.0,
+                         (228+229+230+246+247+248+264+265+266) / 9.0]
+
+        #generate a stencil for computing the decimated values
+        stencil = ones((3,3), Float) / 9.0
+
+        decimate_dem(root, stencil=stencil, cellsize_new=100)
+
+        #Open decimated NetCDF file
+        fid = NetCDFFile(root + '_100.dem', 'r')
+
+        # Get decimated elevation
+        elevation = fid.variables['elevation']
+
+        #Check values
+        assert allclose(elevation, ref_elevation)
+
+        #Cleanup
+        fid.close()
+
+        os.remove(root + '.dem')
+        os.remove(root + '_100.dem')
+
+    def xxxtestz_sww2ers_real(self):
+        """Test that sww information can be converted correctly to asc/prj
+        format readable by e.g. ArcView
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+	# the memory optimised least squares
+	#  cellsize = 20,   # this one seems to hang
+	#  cellsize = 200000, # Ran 1 test in 269.703s
+				#Ran 1 test in 267.344s
+	#  cellsize = 20000,  # Ran 1 test in 460.922s
+	#  cellsize = 2000   #Ran 1 test in 5340.250s
+	#  cellsize = 200   #this one seems to hang, building matirx A
+
+	# not optimised
+	# seems to hang
+	#  cellsize = 2000   # Ran 1 test in 5334.563s
+        #Export to ascii/prj files
+        sww2dem('karratha_100m',
+                quantity = 'depth',
+                cellsize = 200000,
+                verbose = True)
+
+    def test_read_asc(self):
+        """Test conversion from dem in ascii format to native NetCDF xya format
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        from anuga.abstract_2d_finite_volumes.data_manager import _read_asc
+        #Write test asc file
+        filename = tempfile.mktemp(".000")
+        fid = open(filename, 'w')
+        fid.write("""ncols         7
+nrows         4
+xllcorner     2000.5
+yllcorner     3000.5
+cellsize      25
+NODATA_value  -9999
+    97.921    99.285   125.588   180.830   258.645   342.872   415.836
+   473.157   514.391   553.893   607.120   678.125   777.283   883.038
+   984.494  1040.349  1008.161   900.738   730.882   581.430   514.980
+   502.645   516.230   504.739   450.604   388.500   338.097   514.980
+""")
+        fid.close()
+        bath_metadata, grid = _read_asc(filename, verbose=False)
+        self.failUnless(bath_metadata['xllcorner']  == 2000.5,  'Failed')
+        self.failUnless(bath_metadata['yllcorner']  == 3000.5,  'Failed')
+        self.failUnless(bath_metadata['cellsize']  == 25,  'Failed')
+        self.failUnless(bath_metadata['NODATA_value']  == -9999,  'Failed')
+        self.failUnless(grid[0][0]  == 97.921,  'Failed')
+        self.failUnless(grid[3][6]  == 514.980,  'Failed')
+
+        os.remove(filename)
+
+    def test_asc_csiro2sww(self):
+        import tempfile
+
+        bath_dir = tempfile.mkdtemp()
+        bath_dir_filename = bath_dir + os.sep +'ba19940524.000'
+        #bath_dir = 'bath_data_manager_test'
+        #print "os.getcwd( )",os.getcwd( )
+        elevation_dir =  tempfile.mkdtemp()
+        #elevation_dir = 'elev_expanded'
+        elevation_dir_filename1 = elevation_dir + os.sep +'el19940524.000'
+        elevation_dir_filename2 = elevation_dir + os.sep +'el19940524.001'
+
+        fid = open(bath_dir_filename, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    9000.000    -1000.000    3000.0
+   -1000.000    9000.000  -1000.000
+""")
+        fid.close()
+
+        fid = open(elevation_dir_filename1, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    9000.000    0.000    3000.0
+     0.000     9000.000     0.000
+""")
+        fid.close()
+
+        fid = open(elevation_dir_filename2, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    9000.000    4000.000    4000.0
+    4000.000    9000.000    4000.000
+""")
+        fid.close()
+
+        ucur_dir =  tempfile.mkdtemp()
+        ucur_dir_filename1 = ucur_dir + os.sep +'uc19940524.000'
+        ucur_dir_filename2 = ucur_dir + os.sep +'uc19940524.001'
+
+        fid = open(ucur_dir_filename1, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    90.000    60.000    30.0
+    10.000    10.000    10.000
+""")
+        fid.close()
+        fid = open(ucur_dir_filename2, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    90.000    60.000    30.0
+    10.000    10.000    10.000
+""")
+        fid.close()
+
+        vcur_dir =  tempfile.mkdtemp()
+        vcur_dir_filename1 = vcur_dir + os.sep +'vc19940524.000'
+        vcur_dir_filename2 = vcur_dir + os.sep +'vc19940524.001'
+
+        fid = open(vcur_dir_filename1, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    90.000    60.000    30.0
+    10.000    10.000    10.000
+""")
+        fid.close()
+        fid = open(vcur_dir_filename2, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    90.000    60.000    30.0
+    10.000    10.000    10.000
+""")
+        fid.close()
+
+        sww_file = 'a_test.sww'
+        asc_csiro2sww(bath_dir,elevation_dir, ucur_dir, vcur_dir, sww_file)
+
+        # check the sww file
+
+        fid = NetCDFFile(sww_file, 'r')    #Open existing file for read
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        z = fid.variables['z'][:]
+        stage = fid.variables['stage'][:]
+        xmomentum = fid.variables['xmomentum'][:]
+        geo_ref = Geo_reference(NetCDFObject=fid)
+        #print "geo_ref",geo_ref
+        x_ref = geo_ref.get_xllcorner()
+        y_ref = geo_ref.get_yllcorner()
+        self.failUnless(geo_ref.get_zone() == 55,  'Failed')
+        assert allclose(x_ref, 587798.418) # (-38, 148)
+        assert allclose(y_ref, 5793123.477)# (-38, 148.5)
+
+        #Zone:   55
+        #Easting:  588095.674  Northing: 5821451.722
+        #Latitude:   -37  45 ' 0.00000 ''  Longitude: 148 0 ' 0.00000 ''
+        assert allclose((x[0],y[0]), (588095.674 - x_ref, 5821451.722 - y_ref))
+
+        #Zone:   55
+        #Easting:  632145.632  Northing: 5820863.269
+        #Latitude:   -37  45 ' 0.00000 ''  Longitude: 148  30 ' 0.00000 ''
+        assert allclose((x[2],y[2]), (632145.632 - x_ref, 5820863.269 - y_ref))
+
+        #Zone:   55
+        #Easting:  609748.788  Northing: 5793447.860
+        #Latitude:   -38  0 ' 0.00000 ''  Longitude: 148  15 ' 0.00000 ''
+        assert allclose((x[4],y[4]), (609748.788  - x_ref, 5793447.86 - y_ref))
+
+        assert allclose(z[0],9000.0 )
+        assert allclose(stage[0][1],0.0 )
+
+        #(4000+1000)*60
+        assert allclose(xmomentum[1][1],300000.0 )
+
+
+        fid.close()
+
+        #tidy up
+        os.remove(bath_dir_filename)
+        os.rmdir(bath_dir)
+
+        os.remove(elevation_dir_filename1)
+        os.remove(elevation_dir_filename2)
+        os.rmdir(elevation_dir)
+
+        os.remove(ucur_dir_filename1)
+        os.remove(ucur_dir_filename2)
+        os.rmdir(ucur_dir)
+
+        os.remove(vcur_dir_filename1)
+        os.remove(vcur_dir_filename2)
+        os.rmdir(vcur_dir)
+
+
+        # remove sww file
+        os.remove(sww_file)
+
+    def test_asc_csiro2sww2(self):
+        import tempfile
+
+        bath_dir = tempfile.mkdtemp()
+        bath_dir_filename = bath_dir + os.sep +'ba19940524.000'
+        #bath_dir = 'bath_data_manager_test'
+        #print "os.getcwd( )",os.getcwd( )
+        elevation_dir =  tempfile.mkdtemp()
+        #elevation_dir = 'elev_expanded'
+        elevation_dir_filename1 = elevation_dir + os.sep +'el19940524.000'
+        elevation_dir_filename2 = elevation_dir + os.sep +'el19940524.001'
+
+        fid = open(bath_dir_filename, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    9000.000    -1000.000    3000.0
+   -1000.000    9000.000  -1000.000
+""")
+        fid.close()
+
+        fid = open(elevation_dir_filename1, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    9000.000    0.000    3000.0
+     0.000     -9999.000     -9999.000
+""")
+        fid.close()
+
+        fid = open(elevation_dir_filename2, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    9000.000    4000.000    4000.0
+    4000.000    9000.000    4000.000
+""")
+        fid.close()
+
+        ucur_dir =  tempfile.mkdtemp()
+        ucur_dir_filename1 = ucur_dir + os.sep +'uc19940524.000'
+        ucur_dir_filename2 = ucur_dir + os.sep +'uc19940524.001'
+
+        fid = open(ucur_dir_filename1, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    90.000    60.000    30.0
+    10.000    10.000    10.000
+""")
+        fid.close()
+        fid = open(ucur_dir_filename2, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    90.000    60.000    30.0
+    10.000    10.000    10.000
+""")
+        fid.close()
+
+        vcur_dir =  tempfile.mkdtemp()
+        vcur_dir_filename1 = vcur_dir + os.sep +'vc19940524.000'
+        vcur_dir_filename2 = vcur_dir + os.sep +'vc19940524.001'
+
+        fid = open(vcur_dir_filename1, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    90.000    60.000    30.0
+    10.000    10.000    10.000
+""")
+        fid.close()
+        fid = open(vcur_dir_filename2, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    90.000    60.000    30.0
+    10.000    10.000    10.000
+""")
+        fid.close()
+
+        try:
+            asc_csiro2sww(bath_dir,elevation_dir, ucur_dir,
+                          vcur_dir, sww_file)
+        except:
+            #tidy up
+            os.remove(bath_dir_filename)
+            os.rmdir(bath_dir)
+
+            os.remove(elevation_dir_filename1)
+            os.remove(elevation_dir_filename2)
+            os.rmdir(elevation_dir)
+
+            os.remove(ucur_dir_filename1)
+            os.remove(ucur_dir_filename2)
+            os.rmdir(ucur_dir)
+
+            os.remove(vcur_dir_filename1)
+            os.remove(vcur_dir_filename2)
+            os.rmdir(vcur_dir)
+        else:
+            #tidy up
+            os.remove(bath_dir_filename)
+            os.rmdir(bath_dir)
+
+            os.remove(elevation_dir_filename1)
+            os.remove(elevation_dir_filename2)
+            os.rmdir(elevation_dir)
+            raise 'Should raise exception'
+
+            os.remove(ucur_dir_filename1)
+            os.remove(ucur_dir_filename2)
+            os.rmdir(ucur_dir)
+
+            os.remove(vcur_dir_filename1)
+            os.remove(vcur_dir_filename2)
+            os.rmdir(vcur_dir)
+
+
+
+    def test_asc_csiro2sww3(self):
+        import tempfile
+
+        bath_dir = tempfile.mkdtemp()
+        bath_dir_filename = bath_dir + os.sep +'ba19940524.000'
+        #bath_dir = 'bath_data_manager_test'
+        #print "os.getcwd( )",os.getcwd( )
+        elevation_dir =  tempfile.mkdtemp()
+        #elevation_dir = 'elev_expanded'
+        elevation_dir_filename1 = elevation_dir + os.sep +'el19940524.000'
+        elevation_dir_filename2 = elevation_dir + os.sep +'el19940524.001'
+
+        fid = open(bath_dir_filename, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    9000.000    -1000.000    3000.0
+   -1000.000    9000.000  -1000.000
+""")
+        fid.close()
+
+        fid = open(elevation_dir_filename1, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    9000.000    0.000    3000.0
+     0.000     -9999.000     -9999.000
+""")
+        fid.close()
+
+        fid = open(elevation_dir_filename2, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    9000.000    4000.000    4000.0
+    4000.000    9000.000    4000.000
+""")
+        fid.close()
+
+        ucur_dir =  tempfile.mkdtemp()
+        ucur_dir_filename1 = ucur_dir + os.sep +'uc19940524.000'
+        ucur_dir_filename2 = ucur_dir + os.sep +'uc19940524.001'
+
+        fid = open(ucur_dir_filename1, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    90.000    60.000    30.0
+    10.000    10.000    10.000
+""")
+        fid.close()
+        fid = open(ucur_dir_filename2, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    90.000    60.000    30.0
+    10.000    10.000    10.000
+""")
+        fid.close()
+
+        vcur_dir =  tempfile.mkdtemp()
+        vcur_dir_filename1 = vcur_dir + os.sep +'vc19940524.000'
+        vcur_dir_filename2 = vcur_dir + os.sep +'vc19940524.001'
+
+        fid = open(vcur_dir_filename1, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    90.000    60.000    30.0
+    10.000    10.000    10.000
+""")
+        fid.close()
+        fid = open(vcur_dir_filename2, 'w')
+        fid.write(""" ncols             3
+ nrows             2
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+    90.000    60.000    30.0
+    10.000    10.000    10.000
+""")
+        fid.close()
+
+        sww_file = 'a_test.sww'
+        asc_csiro2sww(bath_dir,elevation_dir, ucur_dir, vcur_dir,
+                      sww_file, fail_on_NaN = False, elevation_NaN_filler = 0,
+                      mean_stage = 100)
+
+        # check the sww file
+
+        fid = NetCDFFile(sww_file, 'r')    #Open existing file for read
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        z = fid.variables['z'][:]
+        stage = fid.variables['stage'][:]
+        xmomentum = fid.variables['xmomentum'][:]
+        geo_ref = Geo_reference(NetCDFObject=fid)
+        #print "geo_ref",geo_ref
+        x_ref = geo_ref.get_xllcorner()
+        y_ref = geo_ref.get_yllcorner()
+        self.failUnless(geo_ref.get_zone() == 55,  'Failed')
+        assert allclose(x_ref, 587798.418) # (-38, 148)
+        assert allclose(y_ref, 5793123.477)# (-38, 148.5)
+
+        #Zone:   55
+        #Easting:  588095.674  Northing: 5821451.722
+        #Latitude:   -37  45 ' 0.00000 ''  Longitude: 148 0 ' 0.00000 ''
+        assert allclose((x[0],y[0]), (588095.674 - x_ref, 5821451.722 - y_ref))
+
+        #Zone:   55
+        #Easting:  632145.632  Northing: 5820863.269
+        #Latitude:   -37  45 ' 0.00000 ''  Longitude: 148  30 ' 0.00000 ''
+        assert allclose((x[2],y[2]), (632145.632 - x_ref, 5820863.269 - y_ref))
+
+        #Zone:   55
+        #Easting:  609748.788  Northing: 5793447.860
+        #Latitude:   -38  0 ' 0.00000 ''  Longitude: 148  15 ' 0.00000 ''
+        assert allclose((x[4],y[4]), (609748.788  - x_ref, 5793447.86 - y_ref))
+
+        assert allclose(z[0],9000.0 )
+        assert allclose(stage[0][4],100.0 )
+        assert allclose(stage[0][5],100.0 )
+
+        #(100.0 - 9000)*10
+        assert allclose(xmomentum[0][4], -89000.0 )
+
+        #(100.0 - -1000.000)*10
+        assert allclose(xmomentum[0][5], 11000.0 )
+
+        fid.close()
+
+        #tidy up
+        os.remove(bath_dir_filename)
+        os.rmdir(bath_dir)
+
+        os.remove(elevation_dir_filename1)
+        os.remove(elevation_dir_filename2)
+        os.rmdir(elevation_dir)
+
+        os.remove(ucur_dir_filename1)
+        os.remove(ucur_dir_filename2)
+        os.rmdir(ucur_dir)
+
+        os.remove(vcur_dir_filename1)
+        os.remove(vcur_dir_filename2)
+        os.rmdir(vcur_dir)
+
+        # remove sww file
+        os.remove(sww_file)
+
+
+    def test_asc_csiro2sww4(self):
+        """
+        Test specifying the extent
+        """
+
+        import tempfile
+
+        bath_dir = tempfile.mkdtemp()
+        bath_dir_filename = bath_dir + os.sep +'ba19940524.000'
+        #bath_dir = 'bath_data_manager_test'
+        #print "os.getcwd( )",os.getcwd( )
+        elevation_dir =  tempfile.mkdtemp()
+        #elevation_dir = 'elev_expanded'
+        elevation_dir_filename1 = elevation_dir + os.sep +'el19940524.000'
+        elevation_dir_filename2 = elevation_dir + os.sep +'el19940524.001'
+
+        fid = open(bath_dir_filename, 'w')
+        fid.write(""" ncols             4
+ nrows             4
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+   -9000.000    -1000.000   -3000.0 -2000.000
+   -1000.000    9000.000  -1000.000 -3000.000
+   -4000.000    6000.000   2000.000 -5000.000
+   -9000.000    -1000.000   -3000.0 -2000.000
+""")
+        fid.close()
+
+        fid = open(elevation_dir_filename1, 'w')
+        fid.write(""" ncols             4
+ nrows             4
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+   -900.000    -100.000   -300.0 -200.000
+   -100.000    900.000  -100.000 -300.000
+   -400.000    600.000   200.000 -500.000
+   -900.000    -100.000   -300.0 -200.000
+""")
+        fid.close()
+
+        fid = open(elevation_dir_filename2, 'w')
+        fid.write(""" ncols             4
+ nrows             4
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+   -990.000    -110.000   -330.0 -220.000
+   -110.000    990.000  -110.000 -330.000
+   -440.000    660.000   220.000 -550.000
+   -990.000    -110.000   -330.0 -220.000
+""")
+        fid.close()
+
+        ucur_dir =  tempfile.mkdtemp()
+        ucur_dir_filename1 = ucur_dir + os.sep +'uc19940524.000'
+        ucur_dir_filename2 = ucur_dir + os.sep +'uc19940524.001'
+
+        fid = open(ucur_dir_filename1, 'w')
+        fid.write(""" ncols             4
+ nrows             4
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+   -90.000    -10.000   -30.0 -20.000
+   -10.000    90.000  -10.000 -30.000
+   -40.000    60.000   20.000 -50.000
+   -90.000    -10.000   -30.0 -20.000
+""")
+        fid.close()
+        fid = open(ucur_dir_filename2, 'w')
+        fid.write(""" ncols             4
+ nrows             4
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+   -90.000    -10.000   -30.0 -20.000
+   -10.000    99.000  -11.000 -30.000
+   -40.000    66.000   22.000 -50.000
+   -90.000    -10.000   -30.0 -20.000
+""")
+        fid.close()
+
+        vcur_dir =  tempfile.mkdtemp()
+        vcur_dir_filename1 = vcur_dir + os.sep +'vc19940524.000'
+        vcur_dir_filename2 = vcur_dir + os.sep +'vc19940524.001'
+
+        fid = open(vcur_dir_filename1, 'w')
+        fid.write(""" ncols             4
+ nrows             4
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+   -90.000    -10.000   -30.0 -20.000
+   -10.000    80.000  -20.000 -30.000
+   -40.000    50.000   10.000 -50.000
+   -90.000    -10.000   -30.0 -20.000
+""")
+        fid.close()
+        fid = open(vcur_dir_filename2, 'w')
+        fid.write(""" ncols             4
+ nrows             4
+ xllcorner    148.00000
+ yllcorner    -38.00000
+ cellsize       0.25
+ nodata_value   -9999.0
+   -90.000    -10.000   -30.0 -20.000
+   -10.000    88.000  -22.000 -30.000
+   -40.000    55.000   11.000 -50.000
+   -90.000    -10.000   -30.0 -20.000
+""")
+        fid.close()
+
+        sww_file = tempfile.mktemp(".sww")
+        #sww_file = 'a_test.sww'
+        asc_csiro2sww(bath_dir,elevation_dir, ucur_dir, vcur_dir,
+                      sww_file, fail_on_NaN = False, elevation_NaN_filler = 0,
+                      mean_stage = 100,
+                       minlat = -37.6, maxlat = -37.6,
+                  minlon = 148.3, maxlon = 148.3
+                      #,verbose = True
+                      )
+
+        # check the sww file
+
+        fid = NetCDFFile(sww_file, 'r')    #Open existing file for read
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        z = fid.variables['z'][:]
+        stage = fid.variables['stage'][:]
+        xmomentum = fid.variables['xmomentum'][:]
+        ymomentum = fid.variables['ymomentum'][:]
+        geo_ref = Geo_reference(NetCDFObject=fid)
+        #print "geo_ref",geo_ref
+        x_ref = geo_ref.get_xllcorner()
+        y_ref = geo_ref.get_yllcorner()
+        self.failUnless(geo_ref.get_zone() == 55,  'Failed')
+
+        assert allclose(fid.starttime, 0.0) # (-37.45, 148.25)
+        assert allclose(x_ref, 610120.388) # (-37.45, 148.25)
+        assert allclose(y_ref,  5820863.269 )# (-37.45, 148.5)
+
+        #Easting:  632145.632  Northing: 5820863.269
+        #Latitude:   -37 45 ' 0.00000 ''  Longitude: 148  30 ' 0.00000 ''
+
+        #print "x",x
+        #print "y",y
+        self.failUnless(len(x) == 4,'failed') # 2*2
+        self.failUnless(len(x) == 4,'failed') # 2*2
+
+        #Zone:   55
+        #Easting:  632145.632  Northing: 5820863.269
+        #Latitude:   -37 45 ' 0.00000 ''  Longitude: 148  30 ' 0.00000 ''
+        # magic number - y is close enough for me.
+        assert allclose(x[3], 632145.63 - x_ref)
+        assert allclose(y[3], 5820863.269  - y_ref + 5.22155314684e-005)
+
+        assert allclose(z[0],9000.0 ) #z is elevation info
+        #print "z",z
+        # 2 time steps, 4 points
+        self.failUnless(xmomentum.shape == (2,4), 'failed')
+        self.failUnless(ymomentum.shape == (2,4), 'failed')
+
+        #(100.0 - -1000.000)*10
+        #assert allclose(xmomentum[0][5], 11000.0 )
+
+        fid.close()
+
+        # is the sww file readable?
+        #Lets see if we can convert it to a dem!
+        #print "sww_file",sww_file
+        #dem_file = tempfile.mktemp(".dem")
+        domain = sww2domain(sww_file) ###, dem_file)
+        domain.check_integrity()
+
+        #tidy up
+        os.remove(bath_dir_filename)
+        os.rmdir(bath_dir)
+
+        os.remove(elevation_dir_filename1)
+        os.remove(elevation_dir_filename2)
+        os.rmdir(elevation_dir)
+
+        os.remove(ucur_dir_filename1)
+        os.remove(ucur_dir_filename2)
+        os.rmdir(ucur_dir)
+
+        os.remove(vcur_dir_filename1)
+        os.remove(vcur_dir_filename2)
+        os.rmdir(vcur_dir)
+
+
+
+
+        # remove sww file
+        os.remove(sww_file)
+
+        # remove dem file
+        #os.remove(dem_file)
+
+    def test_get_min_max_indexes(self):
+        latitudes = [3,2,1,0]
+        longitudes = [0,10,20,30]
+
+        # k - lat
+        # l - lon
+        kmin, kmax, lmin, lmax = anuga.abstract_2d_finite_volumes.data_manager._get_min_max_indexes(
+            latitudes,longitudes,
+            -10,4,-10,31)
+
+        #print "kmin",kmin;print "kmax",kmax
+        #print "lmin",lmin;print "lmax",lmax
+        latitudes_new = latitudes[kmin:kmax]
+        longitudes_news = longitudes[lmin:lmax]
+        #print "latitudes_new", latitudes_new
+        #print "longitudes_news",longitudes_news
+        self.failUnless(latitudes == latitudes_new and \
+                        longitudes == longitudes_news,
+                         'failed')
+
+        ## 2nd test
+        kmin, kmax, lmin, lmax = anuga.abstract_2d_finite_volumes.data_manager._get_min_max_indexes(
+            latitudes,longitudes,
+            0.5,2.5,5,25)
+        #print "kmin",kmin;print "kmax",kmax
+        #print "lmin",lmin;print "lmax",lmax
+        latitudes_new = latitudes[kmin:kmax]
+        longitudes_news = longitudes[lmin:lmax]
+        #print "latitudes_new", latitudes_new
+        #print "longitudes_news",longitudes_news
+
+        self.failUnless(latitudes == latitudes_new and \
+                        longitudes == longitudes_news,
+                         'failed')
+
+        ## 3rd test
+        kmin, kmax, lmin, lmax = anuga.abstract_2d_finite_volumes.data_manager._get_min_max_indexes(\
+            latitudes,
+            longitudes,
+            1.1,1.9,12,17)
+        #print "kmin",kmin;print "kmax",kmax
+        #print "lmin",lmin;print "lmax",lmax
+        latitudes_new = latitudes[kmin:kmax]
+        longitudes_news = longitudes[lmin:lmax]
+        #print "latitudes_new", latitudes_new
+        #print "longitudes_news",longitudes_news
+
+        self.failUnless(latitudes_new == [2, 1] and \
+                        longitudes_news == [10, 20],
+                         'failed')
+
+
+        ## 4th test
+        kmin, kmax, lmin, lmax = anuga.abstract_2d_finite_volumes.data_manager._get_min_max_indexes(
+            latitudes,longitudes,
+                                                      -0.1,1.9,-2,17)
+        #print "kmin",kmin;print "kmax",kmax
+        #print "lmin",lmin;print "lmax",lmax
+        latitudes_new = latitudes[kmin:kmax]
+        longitudes_news = longitudes[lmin:lmax]
+        #print "latitudes_new", latitudes_new
+        #print "longitudes_news",longitudes_news
+
+        self.failUnless(latitudes_new == [2, 1, 0] and \
+                        longitudes_news == [0, 10, 20],
+                         'failed')
+        ## 5th test
+        kmin, kmax, lmin, lmax = anuga.abstract_2d_finite_volumes.data_manager._get_min_max_indexes(
+            latitudes,longitudes,
+            0.1,1.9,2,17)
+        #print "kmin",kmin;print "kmax",kmax
+        #print "lmin",lmin;print "lmax",lmax
+        latitudes_new = latitudes[kmin:kmax]
+        longitudes_news = longitudes[lmin:lmax]
+        #print "latitudes_new", latitudes_new
+        #print "longitudes_news",longitudes_news
+
+        self.failUnless(latitudes_new == [2, 1, 0] and \
+                        longitudes_news == [0, 10, 20],
+                         'failed')
+
+        ## 6th test
+
+        kmin, kmax, lmin, lmax = anuga.abstract_2d_finite_volumes.data_manager._get_min_max_indexes(
+            latitudes,longitudes,
+            1.5,4,18,32)
+        #print "kmin",kmin;print "kmax",kmax
+        #print "lmin",lmin;print "lmax",lmax
+        latitudes_new = latitudes[kmin:kmax]
+        longitudes_news = longitudes[lmin:lmax]
+        #print "latitudes_new", latitudes_new
+        #print "longitudes_news",longitudes_news
+
+        self.failUnless(latitudes_new == [3, 2, 1] and \
+                        longitudes_news == [10, 20, 30],
+                         'failed')
+
+
+        ## 7th test
+        m2d = array([[0,1,2,3],[4,5,6,7],[8,9,10,11],[12,13,14,15]])
+        kmin, kmax, lmin, lmax = anuga.abstract_2d_finite_volumes.data_manager._get_min_max_indexes(
+            latitudes,longitudes,
+            1.5,1.5,15,15)
+        #print "kmin",kmin;print "kmax",kmax
+        #print "lmin",lmin;print "lmax",lmax
+        latitudes_new = latitudes[kmin:kmax]
+        longitudes_news = longitudes[lmin:lmax]
+        m2d = m2d[kmin:kmax,lmin:lmax]
+        #print "m2d", m2d
+        #print "latitudes_new", latitudes_new
+        #print "longitudes_news",longitudes_news
+
+        self.failUnless(latitudes_new == [2, 1] and \
+                        longitudes_news == [10, 20],
+                         'failed')
+
+        self.failUnless(m2d == [[5,6],[9,10]],
+                         'failed')
+
+    def test_get_min_max_indexes2(self):
+        latitudes = [-30,-35,-40,-45]
+        longitudes = [148,149,150,151]
+
+        m2d = array([[0,1,2,3],[4,5,6,7],[8,9,10,11],[12,13,14,15]])
+
+        # k - lat
+        # l - lon
+        kmin, kmax, lmin, lmax = anuga.abstract_2d_finite_volumes.data_manager._get_min_max_indexes(
+            latitudes,longitudes,
+            -37,-27,147,149.5)
+
+        #print "kmin",kmin;print "kmax",kmax
+        #print "lmin",lmin;print "lmax",lmax
+        #print "m2d", m2d
+        #print "latitudes", latitudes
+        #print "longitudes",longitudes
+        #print "latitudes[kmax]", latitudes[kmax]
+        latitudes_new = latitudes[kmin:kmax]
+        longitudes_new = longitudes[lmin:lmax]
+        m2d = m2d[kmin:kmax,lmin:lmax]
+        #print "m2d", m2d
+        #print "latitudes_new", latitudes_new
+        #print "longitudes_new",longitudes_new
+
+        self.failUnless(latitudes_new == [-30, -35, -40] and \
+                        longitudes_new == [148, 149,150],
+                         'failed')
+        self.failUnless(m2d == [[0,1,2],[4,5,6],[8,9,10]],
+                         'failed')
+
+    def test_get_min_max_indexes3(self):
+        latitudes = [-30,-35,-40,-45,-50,-55,-60]
+        longitudes = [148,149,150,151]
+
+        # k - lat
+        # l - lon
+        kmin, kmax, lmin, lmax = anuga.abstract_2d_finite_volumes.data_manager._get_min_max_indexes(
+            latitudes,longitudes,
+            -43,-37,148.5,149.5)
+
+
+        #print "kmin",kmin;print "kmax",kmax
+        #print "lmin",lmin;print "lmax",lmax
+        #print "latitudes", latitudes
+        #print "longitudes",longitudes
+        latitudes_new = latitudes[kmin:kmax]
+        longitudes_news = longitudes[lmin:lmax]
+        #print "latitudes_new", latitudes_new
+        #print "longitudes_news",longitudes_news
+
+        self.failUnless(latitudes_new == [-35, -40, -45] and \
+                        longitudes_news == [148, 149,150],
+                         'failed')
+
+    def test_get_min_max_indexes4(self):
+        latitudes = [-30,-35,-40,-45,-50,-55,-60]
+        longitudes = [148,149,150,151]
+
+        # k - lat
+        # l - lon
+        kmin, kmax, lmin, lmax = anuga.abstract_2d_finite_volumes.data_manager._get_min_max_indexes(
+            latitudes,longitudes)
+
+        #print "kmin",kmin;print "kmax",kmax
+        #print "lmin",lmin;print "lmax",lmax
+        #print "latitudes", latitudes
+        #print "longitudes",longitudes
+        latitudes_new = latitudes[kmin:kmax]
+        longitudes_news = longitudes[lmin:lmax]
+        #print "latitudes_new", latitudes_new
+        #print "longitudes_news",longitudes_news
+
+        self.failUnless(latitudes_new == latitudes  and \
+                        longitudes_news == longitudes,
+                         'failed')
+
+    def test_tsh2sww(self):
+        import os
+        import tempfile
+
+        tsh_file = tempfile.mktemp(".tsh")
+        file = open(tsh_file,"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()
+
+        #sww_file = tempfile.mktemp(".sww")
+        #print "sww_file",sww_file
+        #print "sww_file",tsh_file
+        tsh2sww(tsh_file)
+
+        os.remove(tsh_file)
+        os.remove(tsh_file[:-4] + '.sww')
+        
+
+
+    def NOT_test_dem2pts(self):
+        """Test conversion from dem in ascii format to native NetCDF xya format
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Write test asc file
+        root = 'demtest'
+
+        filename = root+'.asc'
+        fid = open(filename, 'w')
+        fid.write("""ncols         5
+nrows         6
+xllcorner     2000.5
+yllcorner     3000.5
+cellsize      25
+NODATA_value  -9999
+""")
+        #Create linear function
+
+        ref_points = []
+        ref_elevation = []
+        for i in range(6):
+            y = (6-i)*25.0
+            for j in range(5):
+                x = j*25.0
+                z = x+2*y
+
+                ref_points.append( [x,y] )
+                ref_elevation.append(z)
+                fid.write('%f ' %z)
+            fid.write('\n')
+
+        fid.close()
+
+        #Write prj file with metadata
+        metafilename = root+'.prj'
+        fid = open(metafilename, 'w')
+
+
+        fid.write("""Projection UTM
+Zone 56
+Datum WGS84
+Zunits NO
+Units METERS
+Spheroid WGS84
+Xshift 0.0000000000
+Yshift 10000000.0000000000
+Parameters
+""")
+        fid.close()
+
+        #Convert to NetCDF pts
+        convert_dem_from_ascii2netcdf(root)
+        dem2pts(root)
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(root+'.pts', 'r')
+
+        # Get the variables
+        #print fid.variables.keys()
+        points = fid.variables['points']
+        elevation = fid.variables['elevation']
+
+        #Check values
+
+        #print points[:]
+        #print ref_points
+        assert allclose(points, ref_points)
+
+        #print attributes[:]
+        #print ref_elevation
+        assert allclose(elevation, ref_elevation)
+
+        #Cleanup
+        fid.close()
+
+
+        os.remove(root + '.pts')
+        os.remove(root + '.dem')
+        os.remove(root + '.asc')
+        os.remove(root + '.prj')
+
+
+
+    def NOT_test_dem2pts_bounding_box(self):
+        """Test conversion from dem in ascii format to native NetCDF xya format
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Write test asc file
+        root = 'demtest'
+
+        filename = root+'.asc'
+        fid = open(filename, 'w')
+        fid.write("""ncols         5
+nrows         6
+xllcorner     2000.5
+yllcorner     3000.5
+cellsize      25
+NODATA_value  -9999
+""")
+        #Create linear function
+
+        ref_points = []
+        ref_elevation = []
+        for i in range(6):
+            y = (6-i)*25.0
+            for j in range(5):
+                x = j*25.0
+                z = x+2*y
+
+                ref_points.append( [x,y] )
+                ref_elevation.append(z)
+                fid.write('%f ' %z)
+            fid.write('\n')
+
+        fid.close()
+
+        #Write prj file with metadata
+        metafilename = root+'.prj'
+        fid = open(metafilename, 'w')
+
+
+        fid.write("""Projection UTM
+Zone 56
+Datum WGS84
+Zunits NO
+Units METERS
+Spheroid WGS84
+Xshift 0.0000000000
+Yshift 10000000.0000000000
+Parameters
+""")
+        fid.close()
+
+        #Convert to NetCDF pts
+        convert_dem_from_ascii2netcdf(root)
+        dem2pts(root, easting_min=2010.0, easting_max=2110.0,
+                northing_min=3035.0, northing_max=3125.5)
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(root+'.pts', 'r')
+
+        # Get the variables
+        #print fid.variables.keys()
+        points = fid.variables['points']
+        elevation = fid.variables['elevation']
+
+        #Check values
+        assert fid.xllcorner[0] == 2010.0
+        assert fid.yllcorner[0] == 3035.0
+
+        #create new reference points
+        ref_points = []
+        ref_elevation = []
+        for i in range(4):
+            y = (4-i)*25.0 + 25.0
+            y_new = y + 3000.5 - 3035.0
+            for j in range(4):
+                x = j*25.0 + 25.0
+                x_new = x + 2000.5 - 2010.0
+                z = x+2*y
+
+                ref_points.append( [x_new,y_new] )
+                ref_elevation.append(z)
+
+        #print points[:]
+        #print ref_points
+        assert allclose(points, ref_points)
+
+        #print attributes[:]
+        #print ref_elevation
+        assert allclose(elevation, ref_elevation)
+
+        #Cleanup
+        fid.close()
+
+
+        os.remove(root + '.pts')
+        os.remove(root + '.dem')
+        os.remove(root + '.asc')
+        os.remove(root + '.prj')
+
+
+
+    def NOT_test_dem2pts_remove_Nullvalues(self):
+        """Test conversion from dem in ascii format to native NetCDF xya format
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Write test asc file
+        root = 'demtest'
+
+        filename = root+'.asc'
+        fid = open(filename, 'w')
+        fid.write("""ncols         5
+nrows         6
+xllcorner     2000.5
+yllcorner     3000.5
+cellsize      25
+NODATA_value  -9999
+""")
+        #Create linear function
+        # ref_ will write all the values
+        # new_ref_ will write the values except for NODATA_values
+        ref_points = []
+        ref_elevation = []
+        new_ref_pts = []
+        new_ref_elev = []
+        NODATA_value = -9999
+        for i in range(6):
+            y = (6-i)*25.0
+            for j in range(5):
+                x = j*25.0
+                z = x+2*y
+                if j == 4: z = NODATA_value # column
+                if i == 2 and j == 2: z = NODATA_value # random
+                if i == 5 and j == 1: z = NODATA_value
+                if i == 1: z = NODATA_value # row
+                if i == 3 and j == 1: z = NODATA_value # two pts/row
+                if i == 3 and j == 3: z = NODATA_value
+
+
+                if z <> NODATA_value:
+                    new_ref_elev.append(z)
+                    new_ref_pts.append( [x,y] )
+
+                ref_points.append( [x,y] )
+                ref_elevation.append(z)
+
+                fid.write('%f ' %z)
+            fid.write('\n')
+
+        fid.close()
+
+
+        #Write prj file with metadata
+        metafilename = root+'.prj'
+        fid = open(metafilename, 'w')
+
+
+        fid.write("""Projection UTM
+Zone 56
+Datum WGS84
+Zunits NO
+Units METERS
+Spheroid WGS84
+Xshift 0.0000000000
+Yshift 10000000.0000000000
+Parameters
+""")
+        fid.close()
+
+        #Convert to NetCDF pts
+        convert_dem_from_ascii2netcdf(root)
+        dem2pts(root)
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(root+'.pts', 'r')
+
+        # Get the variables
+        #print fid.variables.keys()
+        points = fid.variables['points']
+        elevation = fid.variables['elevation']
+
+        #Check values
+        #print 'points', points[:]
+        assert len(points) == len(new_ref_pts), 'length of returned points not correct'
+        assert allclose(points, new_ref_pts), 'points do not align'
+
+        #print 'elevation', elevation[:]
+        assert len(elevation) == len(new_ref_elev), 'length of returned elevation not correct'
+        assert allclose(elevation, new_ref_elev), 'elevations do not align'
+
+        #Cleanup
+        fid.close()
+
+
+        os.remove(root + '.pts')
+        os.remove(root + '.dem')
+        os.remove(root + '.asc')
+        os.remove(root + '.prj')
+
+    def NOT_test_dem2pts_bounding_box_Nullvalues(self):
+        """Test conversion from dem in ascii format to native NetCDF xya format
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        #Write test asc file
+        root = 'demtest'
+
+        filename = root+'.asc'
+        fid = open(filename, 'w')
+        fid.write("""ncols         5
+nrows         6
+xllcorner     2000.5
+yllcorner     3000.5
+cellsize      25
+NODATA_value  -9999
+""")
+        #Create linear function
+
+        ref_points = []
+        ref_elevation = []
+        new_ref_pts1 = []
+        new_ref_elev1 = []
+        NODATA_value = -9999
+        for i in range(6):
+            y = (6-i)*25.0
+            for j in range(5):
+                x = j*25.0
+                z = x+2*y
+                if j == 4: z = NODATA_value # column
+                if i == 2 and j == 2: z = NODATA_value # random
+                if i == 5 and j == 1: z = NODATA_value
+                if i == 1: z = NODATA_value # row
+                if i == 3 and j == 1: z = NODATA_value # two pts/row
+                if i == 3 and j == 3: z = NODATA_value
+
+                if z <> NODATA_value:
+                    new_ref_elev1.append(z)
+                    new_ref_pts1.append( [x,y] )
+
+                ref_points.append( [x,y] )
+                ref_elevation.append(z)
+                fid.write('%f ' %z)
+            fid.write('\n')
+
+        fid.close()
+
+        #Write prj file with metadata
+        metafilename = root+'.prj'
+        fid = open(metafilename, 'w')
+
+
+        fid.write("""Projection UTM
+Zone 56
+Datum WGS84
+Zunits NO
+Units METERS
+Spheroid WGS84
+Xshift 0.0000000000
+Yshift 10000000.0000000000
+Parameters
+""")
+        fid.close()
+
+        #Convert to NetCDF pts
+        convert_dem_from_ascii2netcdf(root)
+        dem2pts(root, easting_min=2010.0, easting_max=2110.0,
+                northing_min=3035.0, northing_max=3125.5)
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(root+'.pts', 'r')
+
+        # Get the variables
+        #print fid.variables.keys()
+        points = fid.variables['points']
+        elevation = fid.variables['elevation']
+
+        #Check values
+        assert fid.xllcorner[0] == 2010.0
+        assert fid.yllcorner[0] == 3035.0
+
+        #create new reference points
+        ref_points = []
+        ref_elevation = []
+        new_ref_pts2 = []
+        new_ref_elev2 = []
+        for i in range(4):
+            y = (4-i)*25.0 + 25.0
+            y_new = y + 3000.5 - 3035.0
+            for j in range(4):
+                x = j*25.0 + 25.0
+                x_new = x + 2000.5 - 2010.0
+                z = x+2*y
+
+                if j == 3: z = NODATA_value # column
+                if i == 1 and j == 1: z = NODATA_value # random
+                if i == 4 and j == 0: z = NODATA_value
+                if i == 0: z = NODATA_value # row
+                if i == 2 and j == 0: z = NODATA_value # two pts/row
+                if i == 2 and j == 2: z = NODATA_value
+
+                if z <> NODATA_value:
+                    new_ref_elev2.append(z)
+                    new_ref_pts2.append( [x_new,y_new] )
+
+
+                ref_points.append( [x_new,y_new] )
+                ref_elevation.append(z)
+
+        #print points[:]
+        #print ref_points
+        #assert allclose(points, ref_points)
+
+        #print attributes[:]
+        #print ref_elevation
+        #assert allclose(elevation, ref_elevation)
+
+
+        assert len(points) == len(new_ref_pts2), 'length of returned points not correct'
+        assert allclose(points, new_ref_pts2), 'points do not align'
+
+        #print 'elevation', elevation[:]
+        assert len(elevation) == len(new_ref_elev2), 'length of returned elevation not correct'
+        assert allclose(elevation, new_ref_elev2), 'elevations do not align'
+        #Cleanup
+        fid.close()
+
+
+        os.remove(root + '.pts')
+        os.remove(root + '.dem')
+        os.remove(root + '.asc')
+        os.remove(root + '.prj')
+
+
+########## testing nbed class ##################
+    def test_exposure_csv_loading(self):
+        
+
+        file_name = tempfile.mktemp(".xya")
+        file = open(file_name,"w")
+        file.write("LATITUDE, LONGITUDE ,sound  , speed \n\
+115.0, -21.0, splat, 0.0\n\
+114.0, -21.7, pow, 10.0\n\
+114.5, -21.4, bang, 40.0\n")
+        file.close()
+        exposure = Exposure_csv(file_name)
+        exposure.get_column("sound")
+       
+        self.failUnless(exposure._attribute_dic['sound'][2]==' bang',
+                        'FAILED!')
+        self.failUnless(exposure._attribute_dic['speed'][2]==' 40.0',
+                        'FAILED!')
+        
+        os.remove(file_name)
+        
+    def test_exposure_csv_loading(self):
+        
+
+        file_name = tempfile.mktemp(".xya")
+        file = open(file_name,"w")
+        file.write("LATITUDE, LONGITUDE ,sound  , speed \n\
+115.0, -21.0, splat, 0.0\n\
+114.0, -21.7, pow, 10.0\n\
+114.5, -21.4, bang, 40.0\n")
+        file.close()
+        exposure = Exposure_csv(file_name)
+        exposure.get_column("sound")
+       
+        self.failUnless(exposure._attribute_dic['sound'][2]==' bang',
+                        'FAILED!')
+        self.failUnless(exposure._attribute_dic['speed'][2]==' 40.0',
+                        'FAILED!')
+        
+        os.remove(file_name)
+
+    def test_exposure_csv_cmp(self):
+        file_name = tempfile.mktemp(".xya")
+        file = open(file_name,"w")
+        file.write("LATITUDE, LONGITUDE ,sound  , speed \n\
+115.0, -21.0, splat, 0.0\n\
+114.0, -21.7, pow, 10.0\n\
+114.5, -21.4, bang, 40.0\n")
+        file.close()
+        
+        e1 = Exposure_csv(file_name)
+        e2 = Exposure_csv(file_name)
+        os.remove(file_name)
+
+        self.failUnless(cmp(e1,e2)==0,
+                        'FAILED!')
+        
+        self.failUnless(cmp(e1,"hey")==1,
+                        'FAILED!')
+        
+        file_name = tempfile.mktemp(".xya")
+        file = open(file_name,"w")
+        # Note, this has less spaces in the title,
+        # the instances will be the same.
+        file.write("LATITUDE,LONGITUDE ,sound, speed \n\
+115.0, -21.0, splat, 0.0\n\
+114.0, -21.7, pow, 10.0\n\
+114.5, -21.4, bang, 40.0\n")
+        file.close()
+        e3 = Exposure_csv(file_name)
+        os.remove(file_name)
+
+        self.failUnless(cmp(e3,e2)==0,
+                        'FAILED!')
+        
+        file_name = tempfile.mktemp(".xya")
+        file = open(file_name,"w")
+        # Note, 40 changed to 44 .
+        file.write("LATITUDE,LONGITUDE ,sound, speed \n\
+115.0, -21.0, splat, 0.0\n\
+114.0, -21.7, pow, 10.0\n\
+114.5, -21.4, bang, 44.0\n")
+        file.close()
+        e4 = Exposure_csv(file_name)
+        os.remove(file_name)
+        #print "e4",e4._attribute_dic 
+        #print "e2",e2._attribute_dic 
+        self.failUnless(cmp(e4,e2)<>0,
+                        'FAILED!')
+        
+        file_name = tempfile.mktemp(".xya")
+        file = open(file_name,"w")
+        # Note, the first two columns are swapped.
+        file.write("LONGITUDE,LATITUDE ,sound, speed \n\
+ -21.0,115.0, splat, 0.0\n\
+ -21.7,114.0, pow, 10.0\n\
+ -21.4,114.5, bang, 40.0\n")
+        file.close()
+        e5 = Exposure_csv(file_name)
+        os.remove(file_name)
+
+        self.failUnless(cmp(e3,e5)<>0,
+                        'FAILED!')
+        
+    def test_exposure_csv_saving(self):
+        
+
+        file_name = tempfile.mktemp(".xya")
+        file = open(file_name,"w")
+        file.write("LATITUDE, LONGITUDE ,sound  , speed \n\
+115.0, -21.0, splat, 0.0\n\
+114.0, -21.7, pow, 10.0\n\
+114.5, -21.4, bang, 40.0\n")
+        file.close()
+        e1 = Exposure_csv(file_name)
+        
+        file_name2 = tempfile.mktemp(".xya")
+        e1.save(file_name = file_name2)
+        e2 = Exposure_csv(file_name2)
+       
+        self.failUnless(cmp(e1,e2)==0,
+                        'FAILED!')
+        os.remove(file_name)
+        os.remove(file_name2)
+
+    def test_exposure_csv_get_location(self):
+        file_name = tempfile.mktemp(".xya")
+        file = open(file_name,"w")
+        file.write("LONGITUDE , LATITUDE, sound  , speed \n\
+150.916666667, -34.5, splat, 0.0\n\
+150.0, -34.0, pow, 10.0\n")
+        file.close()
+        e1 = Exposure_csv(file_name)
+
+        gsd = e1.get_location()
+        
+        points = gsd.get_data_points(absolute=True)
+        
+        assert allclose(points[0][0], 308728.009)
+        assert allclose(points[0][1], 6180432.601)
+        assert allclose(points[1][0],  222908.705)
+        assert allclose(points[1][1], 6233785.284)
+        self.failUnless(gsd.get_geo_reference().get_zone() == 56,
+                        'Bad zone error!')
+
+        os.remove(file_name)
+        
+    def test_exposure_csv_set_column_get_column(self):
+        file_name = tempfile.mktemp(".xya")
+        file = open(file_name,"w")
+        file.write("LONGITUDE , LATITUDE, sound  , speed \n\
+150.916666667, -34.5, splat, 0.0\n\
+150.0, -34.0, pow, 10.0\n")
+        file.close()
+        e1 = Exposure_csv(file_name)      
+        os.remove(file_name)
+
+        new_title = "feast"
+        new_values = ["chicken","soup"]
+        e1.set_column(new_title, new_values)
+        returned_values = e1.get_column(new_title)
+        self.failUnless(returned_values == new_values,
+                        ' Error!')
+        
+        file_name2 = tempfile.mktemp(".xya")
+        e1.save(file_name = file_name2)
+        e2 = Exposure_csv(file_name2)
+        returned_values = e2.get_column(new_title)
+        self.failUnless(returned_values == new_values,
+                        ' Error!')       
+        os.remove(file_name2)
+
+    def test_exposure_csv_set_column_get_column_error_checking(self):
+        file_name = tempfile.mktemp(".xya")
+        file = open(file_name,"w")
+        file.write("LONGITUDE , LATITUDE, sound  , speed \n\
+150.916666667, -34.5, splat, 0.0\n\
+150.0, -34.0, pow, 10.0\n")
+        file.close()
+        e1 = Exposure_csv(file_name)      
+        os.remove(file_name)
+
+        new_title = "sound"
+        new_values = [12.5,7.6]
+        try:
+            e1.set_column(new_title, new_values)
+        except TitleValueError:
+            pass
+        else:
+            self.failUnless(0 ==1,  'Error not thrown error!')
+            
+        e1.set_column(new_title, new_values, overwrite=True)
+        returned_values = e1.get_column(new_title)
+        self.failUnless(returned_values == new_values,
+                        ' Error!')       
+        
+        new2_title = "short list"
+        new2_values = [12.5]
+        try:
+            e1.set_column(new2_title, new2_values)
+        except DataMissingValuesError:
+            pass
+        else:
+            self.failUnless(0 ==1,  'Error not thrown error!')
+            
+        new2_title = "long list"
+        new2_values = [12.5, 7,8]
+        try:
+            e1.set_column(new2_title, new2_values)
+        except DataMissingValuesError:
+            pass
+        else:
+            self.failUnless(0 ==1,  'Error not thrown error!')
+        file_name2 = tempfile.mktemp(".xya")
+        e1.save(file_name = file_name2)
+        e2 = Exposure_csv(file_name2)
+        returned_values = e2.get_column(new_title)
+        for returned, new in map(None, returned_values, new_values):
+            self.failUnless(returned == str(new), ' Error!')
+        #self.failUnless(returned_values == new_values, ' Error!')       
+        os.remove(file_name2)
+        
+        try:
+            e1.get_column("toe jam")
+        except TitleValueError:
+            pass
+        else:
+            self.failUnless(0 ==1,  'Error not thrown error!')
+            
+    def test_exposure_csv_loading_x_y(self):
+        
+
+        file_name = tempfile.mktemp(".xya")
+        file = open(file_name,"w")
+        file.write("x, y ,sound  , speed \n\
+115.0, 7, splat, 0.0\n\
+114.0, 8.0, pow, 10.0\n\
+114.5, 9., bang, 40.0\n")
+        file.close()
+        e1 = Exposure_csv(file_name, is_x_y_locations=True)
+        gsd = e1.get_location()
+        
+        points = gsd.get_data_points(absolute=True)
+        
+        assert allclose(points[0][0], 115)
+        assert allclose(points[0][1], 7)
+        assert allclose(points[1][0], 114)
+        assert allclose(points[1][1], 8)
+        assert allclose(points[2][0], 114.5)
+        assert allclose(points[2][1], 9)
+        self.failUnless(gsd.get_geo_reference().get_zone() == -1,
+                        'Bad zone error!')
+
+        os.remove(file_name)
+
+           
+    def test_exposure_csv_loading_x_y2(self):
+        
+        csv_file = tempfile.mktemp(".csv")
+        fd = open(csv_file,'wb')
+        writer = csv.writer(fd)
+        writer.writerow(['x','y','STR_VALUE','C_VALUE','ROOF_TYPE','WALLS', 'SHORE_DIST'])
+        writer.writerow([5.5,0.5,'199770','130000','Metal','Timber',20])
+        writer.writerow([4.5,1.0,'150000','76000','Metal','Double Brick',20])
+        writer.writerow([4.5,1.5,'150000','76000','Metal','Brick Veneer',20])
+        fd.close()
+
+        e1 = Exposure_csv(csv_file)
+        gsd = e1.get_location()
+        
+        points = gsd.get_data_points(absolute=True)
+        assert allclose(points[0][0], 5.5)
+        assert allclose(points[0][1], 0.5)
+        assert allclose(points[1][0], 4.5)
+        assert allclose(points[1][1], 1.0)
+        assert allclose(points[2][0], 4.5)
+        assert allclose(points[2][1], 1.5)
+        self.failUnless(gsd.get_geo_reference().get_zone() == -1,
+                        'Bad zone error!')
+
+        os.remove(csv_file)
+        
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    #suite = unittest.makeSuite(Test_Data_Manager,'test_sww_minimum_sww_depth')
+    suite = unittest.makeSuite(Test_Data_Manager,'test')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
+
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_domain.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_domain.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_domain.py	(revision 3560)
@@ -0,0 +1,596 @@
+#!/usr/bin/env python
+
+import unittest
+from math import sqrt
+
+from domain import *
+from anuga.config import epsilon
+from Numeric import allclose, array, ones, Float
+
+
+def add_to_verts(tag, elements, domain):
+    if tag == "mound":
+        domain.test = "Mound"
+
+
+def set_bottom_friction(tag, elements, domain):
+    if tag == "bottom":
+        #print 'bottom - indices',elements
+        domain.set_quantity('friction', 0.09, indices = elements)
+
+def set_top_friction(tag, elements, domain):
+    if tag == "top":
+        #print 'top - indices',elements
+        domain.set_quantity('friction', 1., indices = elements)
+
+
+def set_all_friction(tag, elements, domain):
+    if tag == 'all':
+        new_values = domain.get_quantity('friction').get_values(indices = elements) + 10.0
+
+        domain.set_quantity('friction', new_values, indices = elements)
+
+
+class Test_Domain(unittest.TestCase):
+    def setUp(self):
+        pass
+
+
+    def tearDown(self):
+        pass
+
+
+    def test_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, daf, dae
+        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        conserved_quantities = ['stage', 'xmomentum', 'ymomentum']
+        other_quantities = ['elevation', 'friction']
+
+        domain = Domain(points, vertices, None,
+                        conserved_quantities, other_quantities)
+        domain.check_integrity()
+
+        for name in conserved_quantities + other_quantities:
+            assert domain.quantities.has_key(name)
+
+
+        assert domain.get_conserved_quantities(0, edge=1) == 0.
+
+
+    def test_conserved_quantities(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, daf, dae
+        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        domain = Domain(points, vertices, boundary=None,
+                        conserved_quantities =\
+                        ['stage', 'xmomentum', 'ymomentum'])
+
+
+        domain.set_quantity('stage', [[1,2,3], [5,5,5],
+                                      [0,0,9], [-6, 3, 3]])
+
+        domain.set_quantity('xmomentum', [[1,2,3], [5,5,5],
+                                          [0,0,9], [-6, 3, 3]])
+
+        domain.check_integrity()
+
+        #Centroids
+        q = domain.get_conserved_quantities(0)
+        assert allclose(q, [2., 2., 0.])
+
+        q = domain.get_conserved_quantities(1)
+        assert allclose(q, [5., 5., 0.])
+
+        q = domain.get_conserved_quantities(2)
+        assert allclose(q, [3., 3., 0.])
+
+        q = domain.get_conserved_quantities(3)
+        assert allclose(q, [0., 0., 0.])
+
+
+        #Edges
+        q = domain.get_conserved_quantities(0, edge=0)
+        assert allclose(q, [2.5, 2.5, 0.])
+        q = domain.get_conserved_quantities(0, edge=1)
+        assert allclose(q, [2., 2., 0.])
+        q = domain.get_conserved_quantities(0, edge=2)
+        assert allclose(q, [1.5, 1.5, 0.])
+
+        for i in range(3):
+            q = domain.get_conserved_quantities(1, edge=i)
+            assert allclose(q, [5, 5, 0.])
+
+
+        q = domain.get_conserved_quantities(2, edge=0)
+        assert allclose(q, [4.5, 4.5, 0.])
+        q = domain.get_conserved_quantities(2, edge=1)
+        assert allclose(q, [4.5, 4.5, 0.])
+        q = domain.get_conserved_quantities(2, edge=2)
+        assert allclose(q, [0., 0., 0.])
+
+
+        q = domain.get_conserved_quantities(3, edge=0)
+        assert allclose(q, [3., 3., 0.])
+        q = domain.get_conserved_quantities(3, edge=1)
+        assert allclose(q, [-1.5, -1.5, 0.])
+        q = domain.get_conserved_quantities(3, edge=2)
+        assert allclose(q, [-1.5, -1.5, 0.])
+
+
+
+    def test_create_quantity_from_expression(self):
+        """Quantity created from other quantities using arbitrary expression
+
+        """
+
+
+        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, daf, dae
+        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        domain = Domain(points, vertices, boundary=None,
+                        conserved_quantities =\
+                        ['stage', 'xmomentum', 'ymomentum'],
+                        other_quantities = ['elevation', 'friction'])
+
+
+        domain.set_quantity('elevation', -1)
+
+
+        domain.set_quantity('stage', [[1,2,3], [5,5,5],
+                                      [0,0,9], [-6, 3, 3]])
+
+        domain.set_quantity('xmomentum', [[1,2,3], [5,5,5],
+                                          [0,0,9], [-6, 3, 3]])
+
+        domain.set_quantity('ymomentum', [[3,3,3], [4,2,1],
+                                          [2,4,-1], [1, 0, 1]])
+
+        domain.check_integrity()
+
+
+
+        expression = 'stage - elevation'
+        Q = domain.create_quantity_from_expression(expression)
+
+        assert allclose(Q.vertex_values, [[2,3,4], [6,6,6],
+                                      [1,1,10], [-5, 4, 4]])
+
+        expression = '(xmomentum*xmomentum + ymomentum*ymomentum)**0.5'
+        Q = domain.create_quantity_from_expression(expression)
+
+        X = domain.quantities['xmomentum'].vertex_values
+        Y = domain.quantities['ymomentum'].vertex_values
+
+        assert allclose(Q.vertex_values, (X**2 + Y**2)**0.5)
+
+
+
+
+
+    def test_set_quantity_from_expression(self):
+        """Quantity set using arbitrary expression
+
+        """
+
+
+        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, daf, dae
+        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        domain = Domain(points, vertices, boundary=None,
+                        conserved_quantities =\
+                        ['stage', 'xmomentum', 'ymomentum'],
+                        other_quantities = ['elevation', 'friction', 'depth'])
+
+
+        domain.set_quantity('elevation', -1)
+
+
+        domain.set_quantity('stage', [[1,2,3], [5,5,5],
+                                      [0,0,9], [-6, 3, 3]])
+
+        domain.set_quantity('xmomentum', [[1,2,3], [5,5,5],
+                                          [0,0,9], [-6, 3, 3]])
+
+        domain.set_quantity('ymomentum', [[3,3,3], [4,2,1],
+                                          [2,4,-1], [1, 0, 1]])
+
+
+
+
+        domain.set_quantity('depth', expression = 'stage - elevation')
+
+        domain.check_integrity()
+
+
+
+
+        Q = domain.quantities['depth']
+
+        assert allclose(Q.vertex_values, [[2,3,4], [6,6,6],
+                                      [1,1,10], [-5, 4, 4]])
+
+
+
+
+
+
+
+
+
+    def test_boundary_indices(self):
+
+        from anuga.config import default_boundary_tag
+
+
+        a = [0.0, 0.5]
+        b = [0.0, 0.0]
+        c = [0.5, 0.5]
+
+        points = [a, b, c]
+        vertices = [ [0,1,2] ]
+        domain = Domain(points, vertices)
+
+        domain.set_boundary( {default_boundary_tag: Dirichlet_boundary([5,2,1])} )
+
+
+        domain.check_integrity()
+
+ 	assert allclose(domain.neighbours, [[-1,-2,-3]])
+
+
+
+    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): 'First',
+                     (0, 2): 'First',
+                     (2, 0): 'Second',
+                     (2, 1): 'Second',
+                     (3, 1): 'Second',
+                     (3, 2): 'Second'}
+
+
+        domain = Domain(points, vertices, boundary,
+                        conserved_quantities =\
+                        ['stage', 'xmomentum', 'ymomentum'])
+        domain.check_integrity()
+
+
+
+        domain.set_quantity('stage', [[1,2,3], [5,5,5],
+                                      [0,0,9], [-6, 3, 3]])
+
+
+        domain.set_boundary( {'First': Dirichlet_boundary([5,2,1]),
+                              'Second': Transmissive_boundary(domain)} )
+
+        domain.update_boundary()
+
+        assert domain.quantities['stage'].boundary_values[0] == 5. #Dirichlet
+        assert domain.quantities['stage'].boundary_values[1] == 5. #Dirichlet
+        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 (4.5)
+        assert domain.quantities['stage'].boundary_values[4] ==\
+               domain.get_conserved_quantities(3, edge=1)[0] #Transmissive (-1.5)
+        assert domain.quantities['stage'].boundary_values[5] ==\
+               domain.get_conserved_quantities(3, edge=2)[0] #Transmissive (-1.5)
+
+        #Check enumeration
+        for k, ((vol_id, edge_id), _) in enumerate(domain.boundary_objects):
+            assert domain.neighbours[vol_id, edge_id] == -k-1
+
+
+
+
+    def test_distribute_first_order(self):
+        """Domain implements a default first order gradient limiter
+        """
+
+        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,
+                        conserved_quantities =\
+                        ['stage', 'xmomentum', 'ymomentum'])
+        domain.check_integrity()
+
+
+        domain.set_quantity('stage', [[1,2,3], [5,5,5],
+                                      [0,0,9], [-6, 3, 3]])
+
+        assert allclose( domain.quantities['stage'].centroid_values,
+                         [2,5,3,0] )
+
+        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]])
+
+
+        domain.distribute_to_vertices_and_edges()
+
+        #First order extrapolation
+        assert allclose( domain.quantities['stage'].vertex_values,
+                         [[ 2.,  2.,  2.],
+                          [ 5.,  5.,  5.],
+                          [ 3.,  3.,  3.],
+                          [ 0.,  0.,  0.]])
+
+
+
+
+    def test_update_conserved_quantities(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,
+                        conserved_quantities =\
+                        ['stage', 'xmomentum', 'ymomentum'])
+        domain.check_integrity()
+
+
+        domain.set_quantity('stage', [1,2,3,4], location='centroids')
+        domain.set_quantity('xmomentum', [1,2,3,4], location='centroids')
+        domain.set_quantity('ymomentum', [1,2,3,4], location='centroids')
+
+
+        #Assign some values to update vectors
+        #Set explicit_update
+
+        for name in domain.conserved_quantities:
+            domain.quantities[name].explicit_update = array([4.,3.,2.,1.])
+            domain.quantities[name].semi_implicit_update = array([1.,1.,1.,1.])
+
+
+        #Update with given timestep (assuming no other forcing terms)
+        domain.timestep = 0.1
+        domain.update_conserved_quantities()
+
+        sem = array([1.,1.,1.,1.])/array([1, 2, 3, 4])
+        denom = ones(4, Float)-domain.timestep*sem
+
+#        x = array([1, 2, 3, 4]) + array( [.4,.3,.2,.1] )
+#        x /= denom
+
+        x = array([1., 2., 3., 4.])
+        x /= denom
+        x += domain.timestep*array( [4,3,2,1] )
+
+        for name in domain.conserved_quantities:
+            assert allclose(domain.quantities[name].centroid_values, x)
+
+
+    def test_set_region(self):
+        """Set quantities for sub region
+        """
+
+        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,
+                        conserved_quantities =\
+                        ['stage', 'xmomentum', 'ymomentum'])
+        domain.check_integrity()
+
+        domain.set_quantity('stage', [[1,2,3], [5,5,5],
+                                      [0,0,9], [-6, 3, 3]])
+
+        assert allclose( domain.quantities['stage'].centroid_values,
+                         [2,5,3,0] )
+
+        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]])
+
+
+        domain.distribute_to_vertices_and_edges()
+
+        #First order extrapolation
+        assert allclose( domain.quantities['stage'].vertex_values,
+                         [[ 2.,  2.,  2.],
+                          [ 5.,  5.,  5.],
+                          [ 3.,  3.,  3.],
+                          [ 0.,  0.,  0.]])
+
+        domain.build_tagged_elements_dictionary({'mound':[0,1]})
+        domain.set_region([add_to_verts])
+
+        self.failUnless(domain.test == "Mound",
+                        'set region failed')
+
+
+
+    def test_region_tags(self):
+        """
+        get values based on triangle lists.
+        """
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.build_tagged_elements_dictionary({'bottom':[0,1],
+                                                 'top':[4,5],
+                                                 'all':[0,1,2,3,4,5]})
+
+
+        #Set friction
+        manning = 0.07
+        domain.set_quantity('friction', manning)
+
+        domain.set_region([set_bottom_friction, set_top_friction])
+        #print domain.quantities['friction'].get_values()
+        assert allclose(domain.quantities['friction'].get_values(),\
+                        [[ 0.09,  0.09,  0.09],
+                         [ 0.09,  0.09,  0.09],
+                         [ 0.07,  0.07,  0.07],
+                         [ 0.07,  0.07,  0.07],
+                         [ 1.0,  1.0,  1.0],
+                         [ 1.0,  1.0,  1.0]])
+
+        domain.set_region([set_all_friction])
+        #print domain.quantities['friction'].get_values()
+        assert allclose(domain.quantities['friction'].get_values(),
+                        [[ 10.09, 10.09, 10.09],
+                         [ 10.09, 10.09, 10.09],
+                         [ 10.07, 10.07, 10.07],
+                         [ 10.07, 10.07, 10.07],
+                         [ 11.0,  11.0,  11.0],
+                         [ 11.0,  11.0,  11.0]])
+
+
+    def test_region_tags2(self):
+        """
+        get values based on triangle lists.
+        """
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.build_tagged_elements_dictionary({'bottom':[0,1],
+                                                 'top':[4,5],
+                                                 'all':[0,1,2,3,4,5]})
+
+
+        #Set friction
+        manning = 0.07
+        domain.set_quantity('friction', manning)
+
+        domain.set_region('top', 'friction', 1.0)
+        domain.set_region('bottom', 'friction', 0.09)
+        
+        #print domain.quantities['friction'].get_values()
+        assert allclose(domain.quantities['friction'].get_values(),\
+                        [[ 0.09,  0.09,  0.09],
+                         [ 0.09,  0.09,  0.09],
+                         [ 0.07,  0.07,  0.07],
+                         [ 0.07,  0.07,  0.07],
+                         [ 1.0,  1.0,  1.0],
+                         [ 1.0,  1.0,  1.0]])
+        
+        domain.set_region([set_bottom_friction, set_top_friction])
+        #print domain.quantities['friction'].get_values()
+        assert allclose(domain.quantities['friction'].get_values(),\
+                        [[ 0.09,  0.09,  0.09],
+                         [ 0.09,  0.09,  0.09],
+                         [ 0.07,  0.07,  0.07],
+                         [ 0.07,  0.07,  0.07],
+                         [ 1.0,  1.0,  1.0],
+                         [ 1.0,  1.0,  1.0]])
+
+        domain.set_region([set_all_friction])
+        #print domain.quantities['friction'].get_values()
+        assert allclose(domain.quantities['friction'].get_values(),
+                        [[ 10.09, 10.09, 10.09],
+                         [ 10.09, 10.09, 10.09],
+                         [ 10.07, 10.07, 10.07],
+                         [ 10.07, 10.07, 10.07],
+                         [ 11.0,  11.0,  11.0],
+                         [ 11.0,  11.0,  11.0]])
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_Domain,'test')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_ermapper.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_ermapper.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_ermapper.py	(revision 3560)
@@ -0,0 +1,190 @@
+#!/usr/bin/env python
+
+import unittest
+
+
+import ermapper_grids
+import Numeric
+from os import remove
+
+class Test_ERMapper(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_write_grid(self):
+        header_filename = 'test_write_ermapper_grid.ers'
+        data_filename = 'test_write_ermapper_grid'
+        
+        original_grid = Numeric.array([[0.0, 0.1, 1.0], [2.0, 3.0, 4.0]])
+
+        # Check that the function works when passing the filename without
+        # a '.ers' extension
+        ermapper_grids.write_ermapper_grid(data_filename, original_grid)
+        new_grid = ermapper_grids.read_ermapper_grid(data_filename)
+        assert Numeric.allclose(original_grid, new_grid)
+
+        # Check that the function works when passing the filename with
+        # a '.ers' extension
+        ermapper_grids.write_ermapper_grid(header_filename, original_grid)
+        new_grid = ermapper_grids.read_ermapper_grid(header_filename)
+        assert Numeric.allclose(original_grid, new_grid)
+
+        # Clean up created files
+        remove(data_filename)
+        remove(header_filename)
+        
+    def test_basic_single_line_grid(self):
+        # Setup test data
+        filename = 'test_write_ermapper_grid'
+        original_grid = Numeric.array([0.0, 0.1, 1.0, 2.0, 3.0, 4.0])
+
+        # Write test data
+        ermapper_grids.write_ermapper_data(original_grid, filename, Numeric.Float64)
+
+        # Read in the test data
+        new_grid = ermapper_grids.read_ermapper_data(filename, Numeric.Float64)
+
+        # Check that the test data that has been read in matches the original data
+        assert Numeric.allclose(original_grid, new_grid)
+
+        # Clean up created files
+        remove(filename)
+        
+    def test_basic_single_line_grid_default_format(self):
+        # Setup test data
+        filename = 'test_write_ermapper_grid'
+        original_grid = Numeric.array([0.0, 0.1, 1.0, 2.0, 3.0, 4.0])
+
+        # Write test data
+        ermapper_grids.write_ermapper_data(original_grid, filename)
+
+        # Read in the test data
+        new_grid = ermapper_grids.read_ermapper_data(filename)
+
+        # Check that the test data that has been read in matches the original data
+        assert Numeric.allclose(original_grid, new_grid)
+
+        # Clean up created files
+        remove(filename)
+        
+    def test_write_default_header(self):
+        data_filename = 'test_write_ermapper_grid'
+
+        # setup test data
+        original_grid = Numeric.array([[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]])
+        # Write test data
+        ermapper_grids.write_ermapper_data(original_grid, data_filename)
+        # Write test header using all default values
+        header_filename = data_filename + '.ers'                              
+        ermapper_grids.write_ermapper_header(header_filename)
+
+        # Check that the read in values match the default values
+        header = ermapper_grids.read_ermapper_header(header_filename)
+
+        assert header['datum'] == '"GDA94"'
+        assert header['projection'] == '"GEOGRAPHIC"'  
+        assert header['coordinatetype'] == 'LL'
+        assert header['rotation'] == '0:0:0.0'
+        assert header['celltype'] == 'IEEE4ByteReal'
+        assert header['nullcellvalue'] == '-99999'
+        assert header['xdimension'] == '100'
+        assert header['registrationcellx'] == '0'
+        assert header['ydimension'] == '100'
+        assert header['registrationcelly'] == '2'
+        assert header['nroflines'] == '3'
+        assert header['nrofcellsperline'] == '4'
+        assert header['longitude'] == '0:0:0'
+        assert header['latitude'] == '0:0:0'
+        assert header['nrofbands'] == '1'
+        assert header['value'] == '"Default_Band"'
+
+        # Clean up created files
+        remove(data_filename)
+        remove(header_filename)
+        
+    def test_header_creation(self):
+        header = {}
+        # have some values that aren't defaults
+        header['nroflines'] = '2'
+        header['nrofcellsperline'] = '3'
+
+        header = ermapper_grids.create_default_header(header)
+
+
+        # default values
+        assert header['datum'] == '"GDA94"'
+        assert header['projection'] == '"GEOGRAPHIC"'  
+        assert header['coordinatetype'] == 'LL'
+        assert header['rotation'] == '0:0:0.0'
+        assert header['celltype'] == 'IEEE4ByteReal'
+        assert header['nullcellvalue'] == '-99999'
+        assert header['xdimension'] == '100'
+        assert header['registrationcellx'] == '0'
+        assert header['ydimension'] == '100'
+        assert header['longitude'] == '0:0:0'
+        assert header['latitude'] == '0:0:0'
+        assert header['nrofbands'] == '1'
+        assert header['value'] == '"Default_Band"'
+
+        # non-default values
+        assert header['nroflines'] == '2'
+        assert header['nrofcellsperline'] == '3'
+        assert header['registrationcelly'] == '1'
+
+
+    def test_write_non_default_header(self):
+        header_filename = 'test_write_ermapper_grid.ers'
+
+        # setup test data
+        header = {}
+        # have some values that aren't defaults
+        header['nroflines'] = '2'
+        header['nrofcellsperline'] = '3'
+        
+        # Write test header using non-default values                           
+        ermapper_grids.write_ermapper_header(header_filename, header)
+
+        # Check that the read in values match the default values
+        header = ermapper_grids.read_ermapper_header(header_filename)
+
+        # default values
+        assert header['datum'] == '"GDA94"'
+        assert header['projection'] == '"GEOGRAPHIC"'  
+        assert header['coordinatetype'] == 'LL'
+        assert header['rotation'] == '0:0:0.0'
+        assert header['celltype'] == 'IEEE4ByteReal'
+        assert header['nullcellvalue'] == '-99999'
+        assert header['xdimension'] == '100'
+        assert header['registrationcellx'] == '0'
+        assert header['ydimension'] == '100'
+        assert header['longitude'] == '0:0:0'
+        assert header['latitude'] == '0:0:0'
+        assert header['nrofbands'] == '1'
+        assert header['value'] == '"Default_Band"'
+
+        # non-default values
+        assert header['nroflines'] == '2'
+        assert header['nrofcellsperline'] == '3'
+        assert header['registrationcelly'] == '1'
+
+        # Clean up created files
+        remove(header_filename)        
+
+
+# def test_default_filenames
+# def test_write_header
+# def test_multi_band_grid
+
+       
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_ERMapper,'test')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
+
+
+
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_general_mesh.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_general_mesh.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_general_mesh.py	(revision 3560)
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+
+
+import unittest
+from math import sqrt, pi
+
+
+from anuga.config import epsilon
+from Numeric import allclose, array, ones, Float
+from general_mesh import General_mesh
+
+
+
+class Test_General_Mesh(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_get_vertex_values(self):
+        """Get connectivity based on triangle lists.
+        """
+        from mesh_factory import rectangular
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+        domain = General_mesh(points, vertices, boundary)
+
+        value = [7]
+        #indexes = [1]  #FIXME (Ole): Should this be used
+        assert  domain.get_vertices() == domain.triangles
+        assert domain.get_vertices([0,4]) == [domain.triangles[0],
+                                              domain.triangles[4]]
+    def test_areas(self):
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+        domain = General_mesh(points, vertices, boundary)        
+
+	assert domain.get_area() == 1.0
+
+
+    def test_get_unique_vertex_values(self):
+        """
+        get unique_vertex based on triangle lists.
+        """
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+        domain = General_mesh(points, vertices, boundary)                
+
+        assert  domain.get_unique_vertices() == [0,1,2,3,4,5,6,7]
+        unique_vertices = domain.get_unique_vertices([0,1,4])
+        unique_vertices.sort()
+        assert unique_vertices == [0,1,2,4,5,6,7]
+
+        unique_vertices = domain.get_unique_vertices([0,4])
+        unique_vertices.sort()
+        assert unique_vertices == [0,2,4,5,6,7]
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_General_Mesh,'test')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_generic_boundary_conditions.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_generic_boundary_conditions.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_generic_boundary_conditions.py	(revision 3560)
@@ -0,0 +1,273 @@
+#!/usr/bin/env python
+
+import unittest
+from math import sqrt, pi
+
+from generic_boundary_conditions import *
+from anuga.config import epsilon
+from Numeric import allclose, array
+
+
+class Test_Generic_Boundary_Conditions(unittest.TestCase):
+    def setUp(self):
+        pass
+        #print "  Setting up"
+
+    def tearDown(self):
+        pass
+        #print "  Tearing down"
+
+
+    def test_generic(self):
+        b = Boundary()
+
+        try:
+            b.evaluate()
+        except:
+            pass
+        else:
+            raise 'Should have raised exception'
+
+
+    def test_dirichlet_empty(self):
+
+        try:
+            Bd = Dirichlet_boundary()
+        except:
+            pass
+        else:
+            raise 'Should have raised exception'
+
+    def test_dirichlet(self):
+        x = [3.14,0,0.1]
+        Bd = Dirichlet_boundary(x)
+
+        q = Bd.evaluate()
+        assert allclose(q, x)
+
+
+    def test_transmissive(self):
+        from domain import Domain
+        from quantity import Quantity
+
+        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.conserved_quantities = ['stage', 'ymomentum']
+        domain.quantities['stage'] =\
+                                   Quantity(domain, [[1,2,3], [5,5,5],
+                                                     [0,0,9], [-6, 3, 3]])
+
+        domain.quantities['ymomentum'] =\
+                                   Quantity(domain, [[2,3,4], [5,5,5],
+                                                     [0,0,9], [-6, 3, 3]])
+
+
+        domain.check_integrity()
+
+        #Test transmissve bdry
+        try:
+            T = Transmissive_boundary()
+        except:
+            pass
+        else:
+            raise 'Should have raised exception'
+
+        T = Transmissive_boundary(domain)
+
+        from anuga.config import default_boundary_tag
+        domain.set_boundary( {default_boundary_tag: T} )
+
+
+        #FIXME: should not necessarily be true always.
+        #E.g. with None as a boundary object.
+        assert len(domain.boundary) == len(domain.boundary_objects)
+
+        q = T.evaluate(0, 2)  #Vol=0, edge=2
+
+        assert allclose(q, [1.5, 2.5])
+
+
+    def test_fileboundary_time_only(self):
+        """Test that boundary values can be read from file and interpolated
+        This is using the .tms file format
+        """
+
+        from domain import Domain
+        from quantity import Quantity
+        import time, os
+        from math import sin, pi
+        from anuga.config import time_format
+
+        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.conserved_quantities = ['stage', 'ymomentum']
+        domain.quantities['stage'] =\
+                                   Quantity(domain, [[1,2,3], [5,5,5],
+                                                     [0,0,9], [-6, 3, 3]])
+
+        domain.quantities['ymomentum'] =\
+                                   Quantity(domain, [[2,3,4], [5,5,5],
+                                                     [0,0,9], [-6, 3, 3]])
+
+        domain.check_integrity()
+
+
+        #Write file
+        filename = 'boundarytest' + str(time.time())
+        fid = open(filename + '.txt', 'w')
+        start = time.mktime(time.strptime('2000', '%Y'))
+        dt = 5*60  #Five minute intervals
+        for i in range(10):
+            t = start + i*dt
+            t_string = time.strftime(time_format, time.gmtime(t))
+
+            fid.write('%s,%f %f\n' %(t_string, 1.0*i, sin(i*2*pi/10)))
+        fid.close()
+
+
+        #Convert ASCII file to NetCDF (Which is what we really like!)
+        
+        from anuga.abstract_2d_finite_volumes.data_manager import timefile2netcdf                
+        timefile2netcdf(filename, quantity_names = ['stage', 'ymomentum'])
+        
+
+
+        F = File_boundary(filename + '.tms', domain)
+
+        
+        os.remove(filename + '.txt')
+        os.remove(filename + '.tms')        
+
+
+        
+
+        #Check that midpoint coordinates at boundary are correctly computed
+	assert allclose( F.midpoint_coordinates,
+                         [[1.0, 0.0], [0.0, 1.0], [3.0, 0.0],
+                          [3.0, 1.0], [1.0, 3.0], [0.0, 3.0]])
+
+        #assert allclose(F.midpoint_coordinates[(3,2)], [0.0, 3.0])
+        #assert allclose(F.midpoint_coordinates[(3,1)], [1.0, 3.0])
+        #assert allclose(F.midpoint_coordinates[(0,2)], [0.0, 1.0])
+        #assert allclose(F.midpoint_coordinates[(0,0)], [1.0, 0.0])
+        #assert allclose(F.midpoint_coordinates[(2,0)], [3.0, 0.0])
+        #assert allclose(F.midpoint_coordinates[(2,1)], [3.0, 1.0])
+
+
+        #Check time interpolation
+        from anuga.config import default_boundary_tag
+        domain.set_boundary( {default_boundary_tag: F} )
+
+        domain.time = 5*30/2  #A quarter way through first step
+        q = F.evaluate()
+        assert allclose(q, [1.0/4, sin(2*pi/10)/4])
+
+
+        domain.time = 2.5*5*60  #Half way between steps 2 and 3
+        q = F.evaluate()
+        assert allclose(q, [2.5, (sin(2*2*pi/10) + sin(3*2*pi/10))/2])
+
+
+
+    def test_fileboundary_exception(self):
+        """Test that boundary object complains if number of
+        conserved quantities are wrong
+        """
+
+        from domain import Domain
+        from quantity import Quantity
+        import time, os
+        from math import sin, pi
+        from anuga.config import time_format
+
+        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.conserved_quantities = ['stage', 'xmomentum', 'ymomentum']
+        domain.quantities['stage'] =\
+                                   Quantity(domain, [[1,2,3], [5,5,5],
+                                                     [0,0,9], [-6, 3, 3]])
+
+        domain.quantities['xmomentum'] =\
+                                   Quantity(domain, [[2,3,4], [5,5,5],
+                                                     [0,0,9], [-6, 3, 3]])
+        domain.quantities['ymomentum'] =\
+                                   Quantity(domain, [[2,3,4], [5,5,5],
+                                                     [0,0,9], [-6, 3, 3]])
+
+        domain.check_integrity()
+
+        #Write file (with only two values)
+        filename = 'boundarytest' + str(time.time())
+        fid = open(filename + '.txt', 'w')
+        start = time.mktime(time.strptime('2000', '%Y'))
+        dt = 5*60  #Five minute intervals
+        for i in range(10):
+            t = start + i*dt
+            t_string = time.strftime(time_format, time.gmtime(t))
+
+            fid.write('%s,%f %f\n' %(t_string, 1.0*i, sin(i*2*pi/10)))
+        fid.close()
+
+
+        #Convert ASCII file to NetCDF (Which is what we really like!)
+        from anuga.abstract_2d_finite_volumes.data_manager import timefile2netcdf               
+        timefile2netcdf(filename, quantity_names = ['stage', 'xmomentum'])
+
+        
+        try:
+            F = File_boundary(filename + '.tms', domain)            
+        except:
+            pass
+        else:
+            raise 'Should have raised an exception'        
+        
+        os.remove(filename + '.txt')
+        os.remove(filename + '.tms')        
+
+
+
+
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_Generic_Boundary_Conditions,'test')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
+
+
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_ghost.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_ghost.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_ghost.py	(revision 3560)
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+import unittest
+from math import sqrt
+
+from domain import *
+from anuga.config import epsilon
+from Numeric import allclose, array, ones, Float
+
+
+
+
+class Test_Domain(unittest.TestCase):
+    def setUp(self):
+        pass
+
+
+    def tearDown(self):
+        pass
+
+
+    def test_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, daf, dae
+        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        conserved_quantities = ['stage', 'xmomentum', 'ymomentum']
+        other_quantities = ['elevation', 'friction']
+
+        domain = Domain(points, vertices, None,
+                        conserved_quantities, other_quantities)
+        domain.check_integrity()
+
+        for name in conserved_quantities + other_quantities:
+            assert domain.quantities.has_key(name)
+
+
+        assert domain.get_conserved_quantities(0, edge=1) == 0.
+
+
+
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_Domain,'test')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_interpolate_sww.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_interpolate_sww.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_interpolate_sww.py	(revision 3560)
@@ -0,0 +1,293 @@
+#!/usr/bin/env python
+#
+"""
+Testing interpolate_sww, based on test_data_manageer, so there maybe code
+that isn't needed, eg in the setup file
+"""
+
+import unittest
+from Numeric import zeros, array, allclose, Float
+from anuga.utilities.numerical_tools import mean
+
+from interpolate_sww import *
+from anuga.abstract_2d_finite_volumes.shallow_water import Domain, Transmissive_boundary
+from anuga.abstract_2d_finite_volumes.data_manager import get_dataobject
+
+
+class Test_Interpolate_sww(unittest.TestCase):
+    def setUp(self):
+
+        import time
+        from mesh_factory import rectangular
+
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(2, 2)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.default_order=2
+        domain.beta_h = 0
+
+
+        #Set some field values
+        domain.set_quantity('elevation', lambda x,y: -x)
+        domain.set_quantity('friction', 0.03)
+
+
+        ######################
+        # Boundary conditions
+        B = Transmissive_boundary(domain)
+        domain.set_boundary( {'left': B, 'right': B, 'top': B, 'bottom': B})
+
+
+        ######################
+        #Initial condition - with jumps
+
+        bed = domain.quantities['elevation'].vertex_values
+        stage = zeros(bed.shape, Float)
+
+        h = 0.3
+        for i in range(stage.shape[0]):
+            if i % 2 == 0:
+                stage[i,:] = bed[i,:] + h
+            else:
+                stage[i,:] = bed[i,:]
+
+        domain.set_quantity('stage', stage)
+
+        domain.distribute_to_vertices_and_edges()
+
+
+        self.domain = domain
+
+        C = domain.get_vertex_coordinates()
+        self.X = C[:,0:6:2].copy()
+        self.Y = C[:,1:6:2].copy()
+
+        self.F = bed
+
+
+    def tearDown(self):
+        pass
+
+    def test_sww_DSG(self):
+        """Not a test, rather a look at the sww format
+        """
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate
+        from Scientific.IO.NetCDF import NetCDFFile
+
+        self.domain.filename = 'datatest' + str(time.time())
+        self.domain.format = 'sww'
+        self.domain.smooth = True
+        self.domain.reduction = mean
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+        self.domain.time = 2.
+        sww.store_timestep('stage')
+
+        #Check contents
+        #Get NetCDF
+        fid = NetCDFFile(sww.filename, 'r')
+
+        # Get the variables
+        x = fid.variables['x']
+        y = fid.variables['y']
+        z = fid.variables['elevation']
+
+        volumes = fid.variables['volumes']
+        time = fid.variables['time']
+
+        # 2D
+        stage = fid.variables['stage']
+
+        X = x[:]
+        Y = y[:]
+        Z = z[:]
+        V = volumes[:]
+        T = time[:]
+        S = stage[:,:]
+
+        if False:
+            print "****************************"
+            print "X ",X
+            print "****************************"
+            print "Y ",Y
+            print "****************************"
+            print "Z ",Z
+            print "****************************"
+            print "V ",V
+            print "****************************"
+            print "Time ",T
+            print "****************************"
+            print "Stage ",S
+            print "****************************"
+
+
+
+
+        fid.close()
+
+        #Cleanup
+        os.remove(sww.filename)
+
+    def test_interpolate_sww(self):
+        ### Not really a unit test, rather a system test for
+        ###  
+
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate, \
+             transpose
+        from Scientific.IO.NetCDF import NetCDFFile
+        import tempfile
+        from load_mesh.loadASCII import  import_points_file, \
+             concatinate_attributelist
+
+        self.domain.filename = 'datatest' + str(time.time())
+        self.domain.format = 'sww'
+        self.domain.smooth = True
+        self.domain.reduction = mean
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+        self.domain.time = 2.
+        sww.store_timestep('stage')
+
+        #print "self.domain.filename",self.domain.filename
+        interp = Interpolate_sww(sww.filename, 'depth')
+
+        assert allclose(interp.time,[0.0,2.0])
+
+        # create an .xya file
+        point_file = tempfile.mktemp(".xya")
+        fd = open(point_file,'w')
+        fd.write("colour, thickness \n 0.0, 0.6,2.,4 \n 0.0, 0.9,4,8 \n 0.0,0.1,4.,8 \n 0.4,1.0,4.,8 \n")
+        fd.close()
+
+        interp.interpolate_xya(point_file)
+
+        answer = {}
+        answer['0.0'] =  [ 0.08, 0.02, 0.14,0.08]
+        answer['2.0'] =  [ 0.08, 0.02, 0.14,0.08]
+        
+        #print "answer",answer
+        #print "interp.interpolated_quantity",interp.interpolated_quantity
+        assert allclose(interp.interpolated_quantity['0.0'],answer['0.0'])
+        assert allclose(interp.interpolated_quantity['2.0'],answer['2.0'])
+
+        # create an output .xya file
+        point_file_out = tempfile.mktemp(".xya")
+        interp.write_depth_xya(point_file_out)
+
+        #check the output file
+        xya_dict = import_points_file(point_file_out)
+        assert allclose(xya_dict['attributelist']['0.0'],answer['0.0'])
+        assert allclose(xya_dict['attributelist']['2.0'],answer['2.0'])
+        assert allclose(xya_dict['pointlist'],[[ 0.0, 0.6],[0.0, 0.9],[ 0.0,0.1],[ 0.4,1.0]])
+
+        # Try another quantity
+        interp = Interpolate_sww(sww.filename, 'stage')
+        interp.interpolate_xya(point_file)
+
+        answer['0.0'] =  [ 0.08, 0.02, 0.14,-0.32]
+        answer['2.0'] =  [ 0.08, 0.02, 0.14,-0.32]        
+        #print "answer",answer
+        #print "interp.interpolated_quantity",interp.interpolated_quantity
+        assert allclose(interp.interpolated_quantity['0.0'],answer['0.0'])
+        assert allclose(interp.interpolated_quantity['2.0'],answer['2.0'])
+
+        # look at error catching
+        try:
+            interp = Interpolate_sww(sww.filename, 'funky!')
+        except KeyError:
+            pass
+        else:
+            self.failUnless(0==1,
+                        'bad key did not raise an error!')
+
+        # look at error catching
+        try:
+            interp = Interpolate_sww(sww.filename, 'elevation')
+        except KeyError:
+            pass
+        else:
+            self.failUnless(0==1,
+                        'bad key did not raise an error!')
+
+        #Cleanup
+        os.remove(sww.filename)
+        os.remove(point_file_out)
+        os.remove(point_file)
+
+    def test_Interpolate_sww_errors(self):
+        import tempfile
+        import os
+        try:
+            interpolate_sww2xya('??ffd??', 'stage','yeah','yeah.x',
+                                verbose = False)
+        except SystemExit:  pass
+        else:
+            self.failUnless(0 ==1,  'Bad file did not raise error!') 
+        
+    def DISABLED_TEST_test_Interpolate_sww_errorsII(self):
+        """
+        THIS TEST HAS BEEN DISABLED, SINCE IT PRINTS TO SCREEN,
+        but is should still work.  test it sometimes!
+        """
+        import tempfile
+        import os
+        import sys
+       
+        sww_file = tempfile.mktemp(".sww")
+        fd = open(sww_file,'w')
+        fd.write("unit testing a bad .sww file \n")
+        fd.close()
+        
+        try:
+            interpolate_sww2xya(sww_file, 'stage','yeah','yeah.x',
+                                verbose = False)
+            
+        except SystemExit:  pass
+        else:
+            self.failUnless(0 ==1,  'Bad file did not raise error!')        
+        #clean up
+        os.remove(sww_file)
+        
+    def test_Interpolate_sww_errorsIII(self):
+        import time, os
+        from Numeric import array, zeros, allclose, Float, concatenate, \
+             transpose
+        from Scientific.IO.NetCDF import NetCDFFile
+        from load_mesh.loadASCII import  import_points_file, \
+             concatinate_attributelist
+
+        self.domain.filename = 'datatest' + str(time.time())
+        self.domain.format = 'sww'
+        self.domain.smooth = True
+        self.domain.reduction = mean
+
+        sww = get_dataobject(self.domain)
+        sww.store_connectivity()
+        sww.store_timestep('stage')
+        self.domain.time = 2.
+        sww.store_timestep('stage')
+        
+        try:
+            interpolate_sww2xya(self.domain.filename,
+                                'stage','yeah','yeah.x',
+                                verbose = False)
+        except SystemExit:  pass
+        else:
+            self.failUnless(0 ==1,  'Bad file did not raise error!')        
+        #clean up
+        os.remove(sww.filename)
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_Interpolate_sww,'test')
+    runner = unittest.TextTestRunner(verbosity=1)
+    runner.run(suite)
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_least_squares.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_least_squares.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_least_squares.py	(revision 3560)
@@ -0,0 +1,1924 @@
+#!/usr/bin/env python
+
+#TEST
+import sys
+import unittest
+from math import sqrt
+
+
+from anuga.abstract_2d_finite_volumes.least_squares import *
+from anuga.abstract_2d_finite_volumes.neighbour_mesh import Mesh
+
+from Numeric import allclose, array, transpose
+
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+
+def distance(x, y):
+    return sqrt( sum( (array(x)-array(y))**2 ))
+
+def linear_function(point):
+    point = array(point)
+    return point[:,0]+point[:,1]
+
+
+class Test_Least_Squares(unittest.TestCase):
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_datapoint_at_centroid(self):
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0,0.0]
+        points = [a, b, c]
+        vertices = [ [1,0,2] ]   #bac
+
+        data = [ [2.0/3, 2.0/3] ] #Use centroid as one data point
+
+        
+        interp = Interpolation(points, vertices, data)
+        assert allclose(interp.get_A(), [[1./3, 1./3, 1./3]])
+
+
+    def test_quad_tree(self):
+        p0 = [-10.0, -10.0]
+        p1 = [20.0, -10.0]
+        p2 = [-10.0, 20.0]
+        p3 = [10.0, 50.0]
+        p4 = [30.0, 30.0]
+        p5 = [50.0, 10.0]
+        p6 = [40.0, 60.0]
+        p7 = [60.0, 40.0]
+        p8 = [-66.0, 20.0]
+        p9 = [10.0, -66.0]
+
+        points = [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9]
+        triangles = [ [0, 1, 2],
+                      [3, 2, 4],
+                      [4, 2, 1],
+                      [4, 1, 5],
+                      [3, 4, 6],
+                      [6, 4, 7],
+                      [7, 4, 5],
+                      [8, 0, 2],
+                      [0, 9, 1]]
+
+        data = [ [4,4] ]
+        interp = Interpolation(points, triangles, data, alpha = 0.0,
+                               max_points_per_cell = 4)
+        #print "PDSG - interp.get_A()", interp.get_A()
+        answer =  [ [ 0.06666667,  0.46666667,  0.46666667,  0.,
+                      0., 0. , 0., 0., 0., 0.]]
+        assert allclose(interp.get_A(), answer)
+        interp.set_point_coordinates([[-30, -30]]) #point outside of mesh
+        #print "PDSG - interp.get_A()", interp.get_A()
+        answer =  [ [ 0.0,  0.0,  0.0,  0.,
+                      0., 0. , 0., 0., 0., 0.]]
+        assert allclose(interp.get_A(), answer)
+
+
+        #point outside of quad tree root cell
+        interp.set_point_coordinates([[-70, -70]])
+        #print "PDSG - interp.get_A()", interp.get_A()
+        answer =  [ [ 0.0,  0.0,  0.0,  0.,
+                      0., 0. , 0., 0., 0., 0.]]
+        assert allclose(interp.get_A(), answer)
+
+    def test_expand_search(self):
+        p0 = [-10.0, -10.0]
+        p1 = [20.0, -10.0]
+        p2 = [-10.0, 20.0]
+        p3 = [10.0, 50.0]
+        p4 = [30.0, 30.0]
+        p5 = [50.0, 10.0]
+        p6 = [40.0, 60.0]
+        p7 = [60.0, 40.0]
+        p8 = [-66.0, 20.0]
+        p9 = [10.0, -66.0]
+
+        points = [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9]
+        triangles = [ [0, 1, 2],
+                      [3, 2, 4],
+                      [4, 2, 1],
+                      [4, 1, 5],
+                      [3, 4, 6],
+                      [6, 4, 7],
+                      [7, 4, 5],
+                      [8, 0, 2],
+                      [0, 9, 1]]
+
+        data = [ [4,4],
+                 [-30,10],
+                 [-20,0],
+                 [-20,10],
+                 [0,30],
+                 [10,-40],
+                 [10,-30],
+                 [10,-20],
+                 [10,10],
+                 [10,20],
+                 [10,30],
+                 [10,40],
+                 [20,10],
+                 [25,45],
+                 [30,0],
+                 [30,10],
+                 [30,30],
+                 [30,40],
+                 [30,50],
+                 [40,10],
+                 [40,30],
+                 [40,40],
+                 [40,50],
+                 [50,20],
+                 [50,30],
+                 [50,40],
+                 [50,50],
+                 [30,0],
+                 [-20,-20]]
+        point_attributes = [ -400000,
+                     10,
+                     10,
+                     10,
+                    10,
+                     10,
+                     10,
+                     10,
+                     10,
+                     10,
+                     10,
+                     10,
+                     10,
+                     10,
+                    10,
+                     10,
+                     10,
+                     10,
+                     10,
+                     10,
+                     10,
+                     10,
+                     10,
+                     10,
+                     10,
+                     10,
+                     10,
+                   10,
+                   99]
+
+        interp = Interpolation(points, triangles, data,
+                               alpha=0.0, expand_search=False, #verbose = True, #False,
+                               max_points_per_cell = 4)
+        calc = interp.fit_points(point_attributes, )
+        #print "calc",calc
+
+        # the point at 4,4 is ignored.  An expanded search has to be done
+        # to fine which triangel it's in.
+        # An expanded search isn't done to find that the last point
+        # isn't in the mesh.  But this isn't tested.
+        answer= [ 10,
+                     10,
+                     10,
+                     10,
+                    10,
+                     10,
+                     10,
+                     10,
+                     10,
+                     10]
+        assert allclose(calc, answer)
+
+    def test_quad_treeII(self):
+        p0 = [-66.0, 14.0]
+        p1 = [14.0, -66.0]
+        p2 = [14.0, 14.0]
+        p3 = [60.0, 20.0]
+        p4 = [10.0, 60.0]
+        p5 = [60.0, 60.0]
+
+        points = [p0, p1, p2, p3, p4, p5]
+        triangles = [ [0, 1, 2],
+                      [3, 2, 1],
+                      [0, 2, 4],
+                      [4, 2, 5],
+                      [5, 2, 3]]
+
+        data = [ [-26.0,-26.0] ]
+        interp = Interpolation(points, triangles, data, alpha = 0.0,
+                 max_points_per_cell = 4)
+        #print "PDSG - interp.get_A()", interp.get_A()
+        answer =  [ [ 0.5,  0.5,  0.0,  0.,
+                      0., 0.]]
+        assert allclose(interp.get_A(), answer)
+        interp.set_point_coordinates([[-30, -30]]) #point outside of mesh
+        #print "PDSG -30,-30 - interp.get_A()", interp.get_A()
+        answer =  [ [ 0.0,  0.0,  0.0,  0.,
+                      0., 0.]]
+        assert allclose(interp.get_A(), answer)
+
+
+        #point outside of quad tree root cell
+        interp.set_point_coordinates([[-70, -70]])
+        #print "PDSG -70,-70 interp.get_A()", interp.get_A()
+        answer =  [ [ 0.0,  0.0,  0.0,  0.,
+                      0., 0. ]]
+        assert allclose(interp.get_A(), answer)
+
+
+    def test_datapoints_at_vertices(self):
+        """Test that data points coinciding with vertices yield a diagonal matrix
+        """
+
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0,0.0]
+        points = [a, b, c]
+        vertices = [ [1,0,2] ]   #bac
+
+        data = points #Use data at vertices
+
+        interp = Interpolation(points, vertices, data)
+        assert allclose(interp.get_A(), [[1., 0., 0.],
+                                   [0., 1., 0.],
+                                   [0., 0., 1.]])
+
+
+
+    def test_datapoints_on_edge_midpoints(self):
+        """Try datapoints midway on edges -
+        each point should affect two matrix entries equally
+        """
+
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0,0.0]
+        points = [a, b, c]
+        vertices = [ [1,0,2] ]   #bac
+
+        data = [ [0., 1.], [1., 0.], [1., 1.] ]
+
+        interp = Interpolation(points, vertices, data)
+
+        assert allclose(interp.get_A(), [[0.5, 0.5, 0.0],  #Affects vertex 1 and 0
+                                   [0.5, 0.0, 0.5],  #Affects vertex 0 and 2
+                                   [0.0, 0.5, 0.5]]) #Affects vertex 1 and 2
+
+
+    def test_datapoints_on_edges(self):
+        """Try datapoints on edges -
+        each point should affect two matrix entries in proportion
+        """
+
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0,0.0]
+        points = [a, b, c]
+        vertices = [ [1,0,2] ]   #bac
+
+        data = [ [0., 1.5], [1.5, 0.], [1.5, 0.5] ]
+
+        interp = Interpolation(points, vertices, data)
+
+        assert allclose(interp.get_A(), [[0.25, 0.75, 0.0],  #Affects vertex 1 and 0
+                                   [0.25, 0.0, 0.75],  #Affects vertex 0 and 2
+                                   [0.0, 0.25, 0.75]]) #Affects vertex 1 and 2
+
+    def test_arbitrary_datapoints(self):
+        """Try arbitrary datapoints
+        """
+
+        from Numeric import sum
+
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0,0.0]
+        points = [a, b, c]
+        vertices = [ [1,0,2] ]   #bac
+
+        data = [ [0.2, 1.5], [0.123, 1.768], [1.43, 0.44] ]
+
+        interp = Interpolation(points, vertices, data)
+        #print "interp.get_A()", interp.get_A()
+        assert allclose(sum(interp.get_A(), axis=1), 1.0)
+
+    def test_arbitrary_datapoints_some_outside(self):
+        """Try arbitrary datapoints one outside the triangle.
+        That one should be ignored
+        """
+
+        from Numeric import sum
+
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0,0.0]
+        points = [a, b, c]
+        vertices = [ [1,0,2] ]   #bac
+
+        data = [ [0.2, 1.5], [0.123, 1.768], [1.43, 0.44], [5.0, 7.0]]
+
+
+        interp = Interpolation(points, vertices, data, precrop = True)
+        assert allclose(sum(interp.get_A(), axis=1), 1.0)
+
+        interp = Interpolation(points, vertices, data, precrop = False)
+        assert allclose(sum(interp.get_A(), axis=1), [1,1,1,0])
+
+
+
+    # this causes a memory error in scipy.sparse
+    def test_more_triangles(self):
+
+        a = [-1.0, 0.0]
+        b = [3.0, 4.0]
+        c = [4.0,1.0]
+        d = [-3.0, 2.0] #3
+        e = [-1.0,-2.0]
+        f = [1.0, -2.0] #5
+
+        points = [a, b, c, d,e,f]
+        triangles = [[0,1,3],[1,0,2],[0,4,5], [0,5,2]] #abd bac aef afc
+
+        #Data points
+        data_points = [ [-3., 2.0], [-2, 1], [0.0, 1], [0, 3], [2, 3], [-1.0/3,-4./3] ]
+        interp = Interpolation(points, triangles, data_points)
+
+        answer = [[0.0, 0.0, 0.0, 1.0, 0.0, 0.0],    #Affects point d
+                  [0.5, 0.0, 0.0, 0.5, 0.0, 0.0],    #Affects points a and d
+                  [0.75, 0.25, 0.0, 0.0, 0.0, 0.0],  #Affects points a and b
+                  [0.0, 0.5, 0.0, 0.5, 0.0, 0.0],    #Affects points a and d
+                  [0.25, 0.75, 0.0, 0.0, 0.0, 0.0],  #Affects points a and b
+                  [1./3, 0.0, 0.0, 0.0, 1./3, 1./3]] #Affects points a, e and f
+
+
+        A = interp.get_A()
+        for i in range(A.shape[0]):
+            for j in range(A.shape[1]):
+                if not allclose(A[i,j], answer[i][j]):
+                    print i,j,':',A[i,j], answer[i][j]
+
+
+        assert allclose(interp.get_A(), answer)
+
+
+
+
+    def test_smooth_attributes_to_mesh(self):
+        a = [0.0, 0.0]
+        b = [0.0, 5.0]
+        c = [5.0, 0.0]
+        points = [a, b, c]
+        triangles = [ [1,0,2] ]   #bac
+
+        d1 = [1.0, 1.0]
+        d2 = [1.0, 3.0]
+        d3 = [3.0,1.0]
+        z1 = 2
+        z2 = 4
+        z3 = 4
+        data_coords = [d1, d2, d3]
+
+        interp = Interpolation(points, triangles, data_coords, alpha=5.0e-20)
+        z = [z1, z2, z3]
+        f = interp.fit(z)
+        answer = [0, 5., 5.]
+
+        #print "f\n",f
+        #print "answer\n",answer
+
+        assert allclose(f, answer, atol=1e-7)
+
+
+    def test_smooth_att_to_meshII(self):
+
+        a = [0.0, 0.0]
+        b = [0.0, 5.0]
+        c = [5.0, 0.0]
+        points = [a, b, c]
+        triangles = [ [1,0,2] ]   #bac
+
+        d1 = [1.0, 1.0]
+        d2 = [1.0, 2.0]
+        d3 = [3.0,1.0]
+        data_coords = [d1, d2, d3]
+        z = linear_function(data_coords)
+        interp = Interpolation(points, triangles, data_coords, alpha=0.0)
+        f = interp.fit(z)
+        answer = linear_function(points)
+
+        assert allclose(f, answer)
+
+    def test_smooth_attributes_to_meshIII(self):
+
+        a = [-1.0, 0.0]
+        b = [3.0, 4.0]
+        c = [4.0,1.0]
+        d = [-3.0, 2.0] #3
+        e = [-1.0,-2.0]
+        f = [1.0, -2.0] #5
+
+        vertices = [a, b, c, d,e,f]
+        triangles = [[0,1,3], [1,0,2], [0,4,5], [0,5,2]] #abd bac aef afc
+
+        point_coords = [[-2.0, 2.0],
+                        [-1.0, 1.0],
+                        [0.0,2.0],
+                        [1.0, 1.0],
+                        [2.0, 1.0],
+                        [0.0,0.0],
+                        [1.0, 0.0],
+                        [0.0, -1.0],
+                        [-0.2,-0.5],
+                        [-0.9, -1.5],
+                        [0.5, -1.9],
+                        [3.0,1.0]]
+
+        z = linear_function(point_coords)
+        interp = Interpolation(vertices, triangles, point_coords, alpha=0.0)
+
+        #print 'z',z
+        f = interp.fit(z)
+        answer = linear_function(vertices)
+        #print "f\n",f
+        #print "answer\n",answer
+        assert allclose(f, answer)
+
+
+    def test_smooth_attributes_to_meshIV(self):
+        """ Testing 2 attributes smoothed to the mesh
+        """
+
+        a = [0.0, 0.0]
+        b = [0.0, 5.0]
+        c = [5.0, 0.0]
+        points = [a, b, c]
+        triangles = [ [1,0,2] ]   #bac
+
+        d1 = [1.0, 1.0]
+        d2 = [1.0, 3.0]
+        d3 = [3.0, 1.0]
+        z1 = [2, 4]
+        z2 = [4, 8]
+        z3 = [4, 8]
+        data_coords = [d1, d2, d3]
+
+        interp = Interpolation(points, triangles, data_coords, alpha=0.0)
+        z = [z1, z2, z3]
+        f =  interp.fit_points(z)
+        answer = [[0,0], [5., 10.], [5., 10.]]
+        assert allclose(f, answer)
+
+    def test_interpolate_attributes_to_points(self):
+        v0 = [0.0, 0.0]
+        v1 = [0.0, 5.0]
+        v2 = [5.0, 0.0]
+
+        vertices = [v0, v1, v2]
+        triangles = [ [1,0,2] ]   #bac
+
+        d0 = [1.0, 1.0]
+        d1 = [1.0, 2.0]
+        d2 = [3.0, 1.0]
+        point_coords = [ d0, d1, d2]
+
+        interp = Interpolation(vertices, triangles, point_coords)
+        f = linear_function(vertices)
+        #z = interp.interpolate(f)
+        answer = linear_function(point_coords)
+
+
+        #assert allclose(z, answer)
+
+
+    def test_interpolate_attributes_to_points_interp_only(self):
+        v0 = [0.0, 0.0]
+        v1 = [0.0, 5.0]
+        v2 = [5.0, 0.0]
+
+        vertices = [v0, v1, v2]
+        triangles = [ [1,0,2] ]   #bac
+
+        d0 = [1.0, 1.0]
+        d1 = [1.0, 2.0]
+        d2 = [3.0, 1.0]
+        point_coords = [ d0, d1, d2]
+
+        interp = Interpolation(vertices, triangles, point_coords,
+                               interp_only = True)
+        
+        f = linear_function(vertices)
+        #z = interp.interpolate(f)
+        answer = linear_function(point_coords)
+        #print "answer", answer
+        #print "z", z 
+
+        #assert allclose(z, answer)
+
+    def test_interpolate_attributes_to_pointsII(self):
+        a = [-1.0, 0.0]
+        b = [3.0, 4.0]
+        c = [4.0, 1.0]
+        d = [-3.0, 2.0] #3
+        e = [-1.0, -2.0]
+        f = [1.0, -2.0] #5
+
+        vertices = [a, b, c, d,e,f]
+        triangles = [[0,1,3], [1,0,2], [0,4,5], [0,5,2]] #abd bac aef afc
+
+
+        point_coords = [[-2.0, 2.0],
+                        [-1.0, 1.0],
+                        [0.0, 2.0],
+                        [1.0, 1.0],
+                        [2.0, 1.0],
+                        [0.0, 0.0],
+                        [1.0, 0.0],
+                        [0.0, -1.0],
+                        [-0.2, -0.5],
+                        [-0.9, -1.5],
+                        [0.5, -1.9],
+                        [3.0, 1.0]]
+
+        interp = Interpolation(vertices, triangles, point_coords)
+        f = linear_function(vertices)
+        #z = interp.interpolate(f)
+        answer = linear_function(point_coords)
+        #print "z",z
+        #print "answer",answer
+        #assert allclose(z, answer)
+
+    def test_interpolate_attributes_to_pointsIII(self):
+        """Test linear interpolation of known values at vertices to
+        new points inside a triangle
+        """
+        a = [0.0, 0.0]
+        b = [0.0, 5.0]
+        c = [5.0, 0.0]
+        d = [5.0, 5.0]
+
+        vertices = [a, b, c, d]
+        triangles = [ [1,0,2], [2,3,1] ]   #bac, cdb
+
+        #Points within triangle 1
+        d0 = [1.0, 1.0]
+        d1 = [1.0, 2.0]
+        d2 = [3.0, 1.0]
+
+        #Point within triangle 2
+        d3 = [4.0, 3.0]
+
+        #Points on common edge
+        d4 = [2.5, 2.5]
+        d5 = [4.0, 1.0]
+
+        #Point on common vertex
+        d6 = [0., 5.]
+        
+        point_coords = [d0, d1, d2, d3, d4, d5, d6]
+
+        interp = Interpolation(vertices, triangles, point_coords)
+
+        #Known values at vertices
+        #Functions are x+y, x+2y, 2x+y, x-y-5
+        f = [ [0., 0., 0., -5.],        # (0,0)
+              [5., 10., 5., -10.],      # (0,5)
+              [5., 5., 10.0, 0.],       # (5,0)
+              [10., 15., 15., -5.]]     # (5,5)
+
+        #z = interp.interpolate(f)
+        answer = [ [2., 3., 3., -5.],   # (1,1)
+                   [3., 5., 4., -6.],   # (1,2)
+                   [4., 5., 7., -3.],   # (3,1)
+                   [7., 10., 11., -4.], # (4,3)
+                   [5., 7.5, 7.5, -5.], # (2.5, 2.5)
+                   [5., 6., 9., -2.],   # (4,1)
+                   [5., 10., 5., -10.]]  # (0,5)
+
+        #print "***********"
+        #print "z",z
+        #print "answer",answer
+        #print "***********"
+
+        #Should an error message be returned if points are outside
+        # of the mesh? Not currently.  
+
+        #assert allclose(z, answer)
+
+
+    def test_interpolate_point_outside_of_mesh(self):
+        """Test linear interpolation of known values at vertices to
+        new points inside a triangle
+        """
+        a = [0.0, 0.0]
+        b = [0.0, 5.0]
+        c = [5.0, 0.0]
+        d = [5.0, 5.0]
+
+        vertices = [a, b, c, d]
+        triangles = [ [1,0,2], [2,3,1] ]   #bac, cdb
+
+        #Far away point
+        d7 = [-1., -1.]
+        
+        point_coords = [ d7]
+
+        interp = Interpolation(vertices, triangles, point_coords)
+
+        #Known values at vertices
+        #Functions are x+y, x+2y, 2x+y, x-y-5
+        f = [ [0., 0., 0., -5.],        # (0,0)
+              [5., 10., 5., -10.],      # (0,5)
+              [5., 5., 10.0, 0.],       # (5,0)
+              [10., 15., 15., -5.]]     # (5,5)
+
+
+        #z = interp.interpolate(f)
+        #answer = [ [0., 0., 0., 0.]] # (-1,-1)
+
+        #print "***********"
+        #print "z",z
+        #print "answer",answer
+        #print "***********"
+
+        #Should an error message be returned if points are outside
+        # of the mesh? Not currently.  
+
+        #assert allclose(z, answer)
+
+    def test_interpolate_attributes_to_pointsIV(self):
+        a = [-1.0, 0.0]
+        b = [3.0, 4.0]
+        c = [4.0, 1.0]
+        d = [-3.0, 2.0] #3
+        e = [-1.0, -2.0]
+        f = [1.0, -2.0] #5
+
+        vertices = [a, b, c, d,e,f]
+        triangles = [[0,1,3], [1,0,2], [0,4,5], [0,5,2]] #abd bac aef afc
+
+
+        point_coords = [[-2.0, 2.0],
+                        [-1.0, 1.0],
+                        [0.0, 2.0],
+                        [1.0, 1.0],
+                        [2.0, 1.0],
+                        [0.0, 0.0],
+                        [1.0, 0.0],
+                        [0.0, -1.0],
+                        [-0.2, -0.5],
+                        [-0.9, -1.5],
+                        [0.5, -1.9],
+                        [3.0, 1.0]]
+
+        interp = Interpolation(vertices, triangles, point_coords)
+        f = array([linear_function(vertices),2*linear_function(vertices) ])
+        f = transpose(f)
+        #print "f",f
+        #z = interp.interpolate(f)
+        answer = [linear_function(point_coords),
+                  2*linear_function(point_coords) ]
+        answer = transpose(answer)
+        #print "z",z
+        #print "answer",answer
+        #assert allclose(z, answer)
+
+    def test_smooth_attributes_to_mesh_function(self):
+        """ Testing 2 attributes smoothed to the mesh
+        """
+
+        a = [0.0, 0.0]
+        b = [0.0, 5.0]
+        c = [5.0, 0.0]
+        points = [a, b, c]
+        triangles = [ [1,0,2] ]   #bac
+
+        d1 = [1.0, 1.0]
+        d2 = [1.0, 3.0]
+        d3 = [3.0, 1.0]
+        z1 = [2, 4]
+        z2 = [4, 8]
+        z3 = [4, 8]
+        data_coords = [d1, d2, d3]
+        z = [z1, z2, z3]
+
+        f = fit_to_mesh(points, triangles, data_coords, z, alpha=0.0)
+        answer = [[0, 0], [5., 10.], [5., 10.]]
+
+        assert allclose(f, answer)
+
+
+
+    def test_pts2rectangular(self):
+
+    	import time, os
+        FN = 'xyatest' + str(time.time()) + '.xya'
+    	fid = open(FN, 'w')
+	fid.write(' %s \n' %('elevation'))
+	fid.write('%f %f %f\n' %(1,1,2) )
+	fid.write('%f %f %f\n' %(1,3,4) )
+	fid.write('%f %f %f\n' %(3,1,4) )
+	fid.close()
+
+	points, triangles, boundary, attributes =\
+                pts2rectangular(FN, 4, 4)
+
+
+        data_coords = [ [1,1], [1,3], [3,1] ]
+        z = [2, 4, 4]
+
+        ref = fit_to_mesh(points, triangles, data_coords, z, verbose=False)
+
+        #print attributes
+        #print ref
+	assert allclose(attributes, ref)
+
+        os.remove(FN)
+
+
+    #Tests of smoothing matrix
+    def test_smoothing_matrix_one_triangle(self):
+        from Numeric import dot
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0,0.0]
+        points = [a, b, c]
+
+        vertices = [ [1,0,2] ]   #bac
+
+        interp = Interpolation(points, vertices)
+
+        assert allclose(interp.get_D(), [[1, -0.5, -0.5],
+                                   [-0.5, 0.5, 0],
+                                   [-0.5, 0, 0.5]])
+
+        #Define f(x,y) = x
+        f = array([0,0,2]) #Value at global vertex 2
+
+        #Check that int (df/dx)**2 + (df/dy)**2 dx dy =
+        #           int 1 dx dy = area = 2
+        assert dot(dot(f, interp.get_D()), f) == 2
+
+        #Define f(x,y) = y
+        f = array([0,2,0])  #Value at global vertex 1
+
+        #Check that int (df/dx)**2 + (df/dy)**2 dx dy =
+        #           int 1 dx dy = area = 2
+        assert dot(dot(f, interp.get_D()), f) == 2
+
+        #Define f(x,y) = x+y
+        f = array([0,2,2])  #Values at global vertex 1 and 2
+
+        #Check that int (df/dx)**2 + (df/dy)**2 dx dy =
+        #           int 2 dx dy = 2*area = 4
+        assert dot(dot(f, interp.get_D()), f) == 4
+
+
+
+    def test_smoothing_matrix_more_triangles(self):
+        from Numeric import dot
+
+        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, daf, dae
+        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        interp = Interpolation(points, vertices)
+
+
+        #assert allclose(interp.get_D(), [[1, -0.5, -0.5],
+        #                           [-0.5, 0.5, 0],
+        #                           [-0.5, 0, 0.5]])
+
+        #Define f(x,y) = x
+        f = array([0,0,2,0,2,4]) #f evaluated at points a-f
+
+        #Check that int (df/dx)**2 + (df/dy)**2 dx dy =
+        #           int 1 dx dy = total area = 8
+        assert dot(dot(f, interp.get_D()), f) == 8
+
+        #Define f(x,y) = y
+        f = array([0,2,0,4,2,0]) #f evaluated at points a-f
+
+        #Check that int (df/dx)**2 + (df/dy)**2 dx dy =
+        #           int 1 dx dy = area = 8
+        assert dot(dot(f, interp.get_D()), f) == 8
+
+        #Define f(x,y) = x+y
+        f = array([0,2,2,4,4,4])  #f evaluated at points a-f
+
+        #Check that int (df/dx)**2 + (df/dy)**2 dx dy =
+        #           int 2 dx dy = 2*area = 16
+        assert dot(dot(f, interp.get_D()), f) == 16
+
+
+    def test_fit_and_interpolation(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, daf, dae
+        triangles = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        #Get (enough) datapoints
+        data_points = [[ 0.66666667, 0.66666667],
+                       [ 1.33333333, 1.33333333],
+                       [ 2.66666667, 0.66666667],
+                       [ 0.66666667, 2.66666667],
+                       [ 0.0, 1.0],
+                       [ 0.0, 3.0],
+                       [ 1.0, 0.0],
+                       [ 1.0, 1.0],
+                       [ 1.0, 2.0],
+                       [ 1.0, 3.0],
+                       [ 2.0, 1.0],
+                       [ 3.0, 0.0],
+                       [ 3.0, 1.0]]
+
+        interp = Interpolation(points, triangles, data_points, alpha=0.0)
+
+        z = linear_function(data_points)
+        answer = linear_function(points)
+
+        f = interp.fit(z)
+
+        #print "f",f
+        #print "answer",answer
+        assert allclose(f, answer)
+
+        #Map back
+        #z1 = interp.interpolate(f)
+        #print "z1\n", z1
+        #print "z\n",z
+        #assert allclose(z, z1)
+
+
+    def test_smoothing_and_interpolation(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, daf, dae
+        triangles = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        #Get (too few!) datapoints
+        data_points = [[ 0.66666667, 0.66666667],
+                       [ 1.33333333, 1.33333333],
+                       [ 2.66666667, 0.66666667],
+                       [ 0.66666667, 2.66666667]]
+
+        z = linear_function(data_points)
+        answer = linear_function(points)
+
+        #Make interpolator with too few data points and no smoothing
+        interp = Interpolation(points, triangles, data_points, alpha=0.0)
+        #Must raise an exception
+        try:
+            f = interp.fit(z)
+        except:
+            pass
+
+        #Now try with smoothing parameter
+        interp = Interpolation(points, triangles, data_points, alpha=1.0e-13)
+
+        f = interp.fit(z)
+        #f will be different from answer due to smoothing
+        assert allclose(f, answer,atol=5)
+
+        #Map back
+        #z1 = interp.interpolate(f)
+        #assert allclose(z, z1)
+
+
+
+    def test_fit_and_interpolation_with_new_points(self):
+        """Fit a surface to one set of points. Then interpolate that surface
+        using another set of points.
+        """
+
+        #Setup mesh used to represent fitted 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, daf, dae
+        triangles = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        #Datapoints to fit from
+        data_points1 = [[ 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],
+                        [ 15, -17],   #Outside mesh
+                        [ 1.0, 2.0],
+                        [ 1.0, 3.0],
+                        [ 2.0, 1.0],
+                        [ 3.0, 0.0],
+                        [ 3.0, 1.0]]
+
+        #Fit surface to mesh
+        interp = Interpolation(points, triangles, data_points1, alpha=0.0,
+                               precrop = True, verbose=False)
+        z = linear_function(data_points1) #Example z-values
+        f = interp.fit(z)                 #Fitted values at vertices
+
+
+
+        #New datapoints where interpolated values are sought
+        data_points2 = [[ 0.0, 0.0],
+                        [ 0.5, 0.5],
+                        [ 0.7, 0.7],
+                        [-13, 65],  #Outside
+                        [ 1.0, 0.5],
+                        [ 2.0, 0.4],
+                        [ 2.8, 1.2]]
+
+
+
+        #Build new A matrix based on new points (without precrop)
+        interp.build_interpolation_matrix_A(data_points2, precrop = False)
+
+        #Interpolate using fitted surface
+        #z1 = interp.interpolate(f)
+
+        #import Numeric
+        #data_points2 = Numeric.take(data_points2, interp.point_indices)
+
+        #Desired result (OK for points inside)
+
+        answer = linear_function(data_points2)
+        import Numeric
+        #z1 = Numeric.take(z1, [0,1,2,4,5,6])
+        answer = Numeric.take(answer, [0,1,2,4,5,6])
+        #assert allclose(z1, answer)
+
+        #Build new A matrix based on new points (with precrop)
+        interp.build_interpolation_matrix_A(data_points2, precrop = True)
+
+        #Interpolate using fitted surface
+        #z1 = interp.interpolate(f)
+
+        import Numeric
+        data_points2 = Numeric.take(data_points2, interp.point_indices)
+
+        #Desired result
+        answer = linear_function(data_points2)
+        #assert allclose(z1, answer)
+
+
+
+
+
+
+    def test_interpolation_from_discontinuous_vertex_values(self):
+        """test_interpolation_from_discontinuous_vertex_values.
+        This will test the format used internally in abstract_2d_finite_volumes and also
+        interpolation from sww files
+        """
+        
+        #Setup mesh used to represent discontinuous 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 = [b, a, c,
+                  b, c, e,
+                  e, c, f,
+                  d, b, e]
+        
+        #bac, bce, ecf, dbe
+        triangles = [[0,1,2], [3,4,5], [6,7,8], [9,10,11]]
+
+        
+        vertex_values = [0.,0.,0.,1.,1.,1.,2.,2.,2.,7.,3.,3.]
+                          
+        
+
+        #New datapoints where interpolated values are sought
+        data_points = [[0.0, 0.0],  #T0
+                       [0.5, 0.5],  #T0
+                       [1.5, 1.5],  #T1
+                       [2.5, 0.5],  #T2
+                       [0.0, 3.0],  #T3
+                       [1.0, 2.0],  #In between T1 and T3 (T1 is used) FIXME?
+                       [2.0, 1.0],  #In between T1 and T2 (T1 is used) FIXME?
+                       [1.0, 1.0]]  #In between T1 and T0 (T0 is used) FIXME?
+        
+
+
+
+        #Build interpolation matrix
+        interp = Interpolation(points, triangles, data_points)
+                               #, alpha=0.0, precrop = True)
+
+        #print interp.A.todense()
+        #print vertex_values
+
+        #Interpolate using fitted surface
+        #z = interp.interpolate(vertex_values)
+
+        #print z
+
+        #assert allclose(z, [0,0,1,2,5,1,1,0])
+
+
+
+
+    def test_interpolation_function_time_only(self):
+        """Test spatio-temporal interpolation
+        Test that spatio temporal function performs the correct
+        interpolations in both time and space
+        """
+
+
+        #Three timesteps
+        time = [1.0, 5.0, 6.0]
+        
+
+        #One quantity
+        Q = zeros( (3,6), Float )
+
+        #Linear in time and space
+        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]
+        
+        for i, t in enumerate(time):
+            Q[i, :] = t*linear_function(points)
+
+            
+        #Check basic interpolation of one quantity using averaging
+        #(no interpolation points or spatial info)
+        from anuga.utilities.numerical_tools import mean        
+        I = Interpolation_function(time, [mean(Q[0,:]),
+                                          mean(Q[1,:]),
+                                          mean(Q[2,:])])
+
+
+
+        #Check temporal interpolation
+        for i in [0,1,2]:
+            assert allclose(I(time[i]), mean(Q[i,:]))
+
+        #Midway    
+        assert allclose(I( (time[0] + time[1])/2 ),
+                        (I(time[0]) + I(time[1]))/2 )
+
+        assert allclose(I( (time[1] + time[2])/2 ),
+                        (I(time[1]) + I(time[2]))/2 )
+
+        assert allclose(I( (time[0] + time[2])/2 ),
+                        (I(time[0]) + I(time[2]))/2 )                 
+
+        #1/3
+        assert allclose(I( (time[0] + time[2])/3 ),
+                        (I(time[0]) + I(time[2]))/3 )                         
+
+
+        #Out of bounds checks
+        try:
+            I(time[0]-1) 
+        except:
+            pass
+        else:
+            raise 'Should raise exception'
+
+        try:
+            I(time[-1]+1) 
+        except:
+            pass
+        else:
+            raise 'Should raise exception'        
+
+
+        
+
+    def interpolation_test_interpolation_function_spatial_only(self):
+        """Test spatio-temporal interpolation with constant time
+        """
+
+        #Three timesteps
+        time = [1.0, 5.0, 6.0]
+        
+        
+        #Setup mesh used to represent fitted 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
+        triangles = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+
+        #New datapoints where interpolated values are sought
+        interpolation_points = [[ 0.0, 0.0],
+                                [ 0.5, 0.5],
+                                [ 0.7, 0.7],
+                                [ 1.0, 0.5],
+                                [ 2.0, 0.4],
+                                [ 2.8, 1.2]]
+
+
+        #One quantity linear in space
+        Q = linear_function(points)
+
+
+        #Check interpolation of one quantity using interpolaton points
+        I = Interpolation_function(time, Q,
+                                   vertex_coordinates = points,
+                                   triangles = triangles, 
+                                   interpolation_points = interpolation_points,
+                                   verbose = False)
+
+
+        answer = linear_function(interpolation_points)
+
+        t = time[0]
+        for j in range(50): #t in [1, 6]
+            for id in range(len(interpolation_points)):
+                assert allclose(I(t, id), answer[id])
+
+            t += 0.1    
+
+
+        try:    
+            I(1)
+        except:
+            pass
+        else:
+            raise 'Should raise exception'
+            
+
+
+    def interpolation_test_interpolation_function(self):
+        """Test spatio-temporal interpolation
+        Test that spatio temporal function performs the correct
+        interpolations in both time and space
+        """
+
+
+        #Three timesteps
+        time = [1.0, 5.0, 6.0]
+        
+
+        #Setup mesh used to represent fitted 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
+        triangles = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+
+        #New datapoints where interpolated values are sought
+        interpolation_points = [[ 0.0, 0.0],
+                                [ 0.5, 0.5],
+                                [ 0.7, 0.7],
+                                [ 1.0, 0.5],
+                                [ 2.0, 0.4],
+                                [ 2.8, 1.2]]
+
+
+        #One quantity
+        Q = zeros( (3,6), Float )
+
+        #Linear in time and space
+        for i, t in enumerate(time):
+            Q[i, :] = t*linear_function(points)
+
+
+        #Check interpolation of one quantity using interpolaton points)
+        I = Interpolation_function(time, Q,
+                                   vertex_coordinates = points,
+                                   triangles = triangles, 
+                                   interpolation_points = interpolation_points,
+                                   verbose = False)
+
+
+        answer = linear_function(interpolation_points)
+
+        t = time[0]
+        for j in range(50): #t in [1, 6]
+            for id in range(len(interpolation_points)):
+                assert allclose(I(t, id), t*answer[id])
+
+            t += 0.1    
+
+
+        try:    
+            I(1)
+        except:
+            pass
+        else:
+            raise 'Should raise exception'
+            
+        #
+        #interpolation_points = [[ 0.0, 0.0],
+        #                        [ 0.5, 0.5],
+        #                        [ 0.7, 0.7],
+        #                        [-13, 65],  #Outside
+        #                        [ 1.0, 0.5],
+        #                        [ 2.0, 0.4],
+        #                        [ 2.8, 1.2]]
+        #
+        #try:
+        #    I = Interpolation_function(time, Q,
+        #                               vertex_coordinates = points,
+        #                               triangles = triangles, 
+        #                               interpolation_points = interpolation_points,
+        #                               verbose = False)
+        #except:
+        #    pass
+        #else:
+        #    raise 'Should raise exception'
+
+
+
+
+
+    def test_fit_and_interpolation_with_different_origins(self):
+        """Fit a surface to one set of points. Then interpolate that surface
+        using another set of points.
+        This test tests situtaion where points and mesh belong to a different
+        coordinate system as defined by origin.
+        """
+
+        #Setup mesh used to represent fitted 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, daf, dae
+        triangles = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        #Datapoints to fit from
+        data_points1 = [[ 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]]
+
+
+        #First check that things are OK when using same origin
+        mesh_origin = (56, 290000, 618000) #zone, easting, northing
+        data_origin = (56, 290000, 618000) #zone, easting, northing
+
+
+        #Fit surface to mesh
+        interp = Interpolation(points, triangles, data_points1,
+                               alpha=0.0,
+                               data_origin = data_origin,
+                               mesh_origin = mesh_origin)
+
+        z = linear_function(data_points1) #Example z-values
+        f = interp.fit(z)                 #Fitted values at vertices
+
+
+        #New datapoints where interpolated values are sought
+        data_points2 = [[ 0.0, 0.0],
+                        [ 0.5, 0.5],
+                        [ 0.7, 0.7],
+                        [ 1.0, 0.5],
+                        [ 2.0, 0.4],
+                        [ 2.8, 1.2]]
+
+
+        #Build new A matrix based on new points
+        interp.build_interpolation_matrix_A(data_points2)
+
+        #Interpolate using fitted surface
+        #z1 = interp.interpolate(f)
+
+        #Desired result
+        #answer = linear_function(data_points2)
+        #assert allclose(z1, answer)
+
+
+        ##############################################
+
+        #Then check situation where points are relative to a different
+        #origin (same zone, though, until we figure that out (FIXME))
+
+        mesh_origin = (56, 290000, 618000) #zone, easting, northing
+        data_origin = (56, 10000, 10000) #zone, easting, northing
+
+        #Shift datapoints according to new origin
+
+        for k in range(len(data_points1)):
+            data_points1[k][0] += mesh_origin[1] - data_origin[1]
+            data_points1[k][1] += mesh_origin[2] - data_origin[2]
+
+        for k in range(len(data_points2)):
+            data_points2[k][0] += mesh_origin[1] - data_origin[1]
+            data_points2[k][1] += mesh_origin[2] - data_origin[2]
+
+
+
+        #Fit surface to mesh
+        interp = Interpolation(points, triangles, data_points1,
+                               alpha=0.0,
+                               data_origin = data_origin,
+                               mesh_origin = mesh_origin)
+
+        f1 = interp.fit(z) #Fitted values at vertices (using same z as before)
+
+        assert allclose(f,f1), 'Fit should have been unaltered'
+
+
+        #Build new A matrix based on new points
+        interp.build_interpolation_matrix_A(data_points2)
+
+        #Interpolate using fitted surface
+        #z1 = interp.interpolate(f)
+        #assert allclose(z1, answer)
+
+
+        #########################################################
+        #Finally try to relate data_points2 to new origin without
+        #rebuilding matrix
+
+        data_origin = (56, 2000, 2000) #zone, easting, northing
+        for k in range(len(data_points2)):
+            data_points2[k][0] += 8000
+            data_points2[k][1] += 8000
+
+        #Build new A matrix based on new points
+        interp.build_interpolation_matrix_A(data_points2,
+                                            data_origin = data_origin)
+
+        #Interpolate using fitted surface
+        #z1 = interp.interpolate(f)
+        #assert allclose(z1, answer)
+
+
+
+    def test_fit_to_mesh_w_georef(self):
+        """Simple check that georef works at the fit_to_mesh level
+        """
+        
+        from anuga.coordinate_transforms.geo_reference import Geo_reference
+
+        #Mesh
+        vertex_coordinates = [[0.76, 0.76],
+                              [0.76, 5.76],
+                              [5.76, 0.76]]
+        triangles = [[0,2,1]]
+
+        mesh_geo = Geo_reference(56,-0.76,-0.76)
+
+
+        #Data                       
+        data_points = [[ 201.0, 401.0],
+                       [ 201.0, 403.0],
+                       [ 203.0, 401.0]]
+
+        z = [2, 4, 4]
+        
+        data_geo = Geo_reference(56,-200,-400)
+        
+        #Fit
+        zz = fit_to_mesh(vertex_coordinates, triangles, data_points, z,
+                         data_origin = data_geo.get_origin(),
+                         mesh_origin = mesh_geo.get_origin(),
+                         alpha = 0)
+        assert allclose( zz, [0,5,5] )
+
+
+    def test_fit_to_mesh_file(self):
+        from load_mesh.loadASCII import import_mesh_file, \
+             export_mesh_file
+        import tempfile
+        import os
+
+        # create a .tsh file, no user outline
+        mesh_dic = {}
+        mesh_dic['vertices'] = [[0.0, 0.0],
+                                          [0.0, 5.0],
+                                          [5.0, 0.0]]
+        mesh_dic['triangles'] =  [[0, 2, 1]]
+        mesh_dic['segments'] = [[0, 1], [2, 0], [1, 2]]
+        mesh_dic['triangle_tags'] = ['']
+        mesh_dic['vertex_attributes'] = [[], [], []]
+        mesh_dic['vertiex_attribute_titles'] = []
+        mesh_dic['triangle_neighbors'] = [[-1, -1, -1]]
+        mesh_dic['segment_tags'] = ['external',
+                                                  'external',
+                                                  'external']
+        mesh_file = tempfile.mktemp(".tsh")
+        export_mesh_file(mesh_file,mesh_dic)
+
+        # create an .xya file
+        point_file = tempfile.mktemp(".xya")
+        fd = open(point_file,'w')
+        fd.write("elevation, stage \n 1.0, 1.0,2.,4 \n 1.0, 3.0,4,8 \n 3.0,1.0,4.,8 \n")
+        fd.close()
+
+        mesh_output_file = tempfile.mktemp(".tsh") 
+        fit_to_mesh_file(mesh_file,
+                         point_file,
+                         mesh_output_file,
+                         alpha = 0.0)
+        # load in the .tsh file we just wrote
+        mesh_dic = import_mesh_file(mesh_output_file)
+        #print "mesh_dic",mesh_dic
+        ans =[[0.0, 0.0],
+              [5.0, 10.0],
+              [5.0,10.0]]
+        assert allclose(mesh_dic['vertex_attributes'],ans)
+
+        self.failUnless(mesh_dic['vertex_attribute_titles']  ==
+                        ['elevation','stage'],
+                        'test_fit_to_mesh_file failed')
+
+        #clean up
+        os.remove(mesh_file)
+        os.remove(point_file)
+        os.remove(mesh_output_file)
+
+    def test_fit_to_mesh_file3(self):
+        from load_mesh.loadASCII import import_mesh_file, \
+             export_mesh_file
+        import tempfile
+        import os
+
+        # create a .tsh file, no user outline
+        mesh_dic = {}
+        mesh_dic['vertices'] = [[0.76, 0.76],
+                                          [0.76, 5.76],
+                                          [5.76, 0.76]]
+        mesh_dic['triangles'] =  [[0, 2, 1]]
+        mesh_dic['segments'] = [[0, 1], [2, 0], [1, 2]]
+        mesh_dic['triangle_tags'] = ['']
+        mesh_dic['vertex_attributes'] = [[], [], []]
+        mesh_dic['vertiex_attribute_titles'] = []
+        mesh_dic['triangle_neighbors'] = [[-1, -1, -1]]
+        mesh_dic['segment_tags'] = ['external',
+                                                  'external',
+                                                  'external']
+        mesh_dic['geo_reference'] = Geo_reference(56,-0.76,-0.76)
+        mesh_file = tempfile.mktemp(".tsh")
+        export_mesh_file(mesh_file,mesh_dic)
+
+        # create an .xya file
+        point_file = tempfile.mktemp(".xya")
+        fd = open(point_file,'w')
+        fd.write("elevation, stage \n 1.0, 1.0,2.,4 \n 1.0, 3.0,4,8 \n 3.0,1.0,4.,8 \n")
+        fd.close()
+
+        mesh_output_file = tempfile.mktemp(".tsh")
+        fit_to_mesh_file(mesh_file,
+                         point_file,
+                         mesh_output_file,
+                         alpha = 0.0)
+        # load in the .tsh file we just wrote
+        mesh_dic = import_mesh_file(mesh_output_file)
+        #print "mesh_dic",mesh_dic
+        ans =[[0.0, 0.0],
+              [5.0, 10.0],
+              [5.0,10.0]]
+        assert allclose(mesh_dic['vertex_attributes'],ans)
+
+        self.failUnless(mesh_dic['vertex_attribute_titles']  ==
+                        ['elevation','stage'],
+                        'test_fit_to_mesh_file failed')
+
+        #clean up
+        os.remove(mesh_file)
+        os.remove(point_file)
+        os.remove(mesh_output_file)
+
+    def test_fit_to_mesh_file4(self):
+        from load_mesh.loadASCII import import_mesh_file, \
+             export_mesh_file
+        import tempfile
+        import os
+
+        # create a .tsh file, no user outline
+        mesh_dic = {}
+        mesh_dic['vertices'] = [[0.76, 0.76],
+                                [0.76, 5.76],
+                                [5.76, 0.76]]
+        mesh_dic['triangles'] =  [[0, 2, 1]]
+        mesh_dic['segments'] = [[0, 1], [2, 0], [1, 2]]
+        mesh_dic['triangle_tags'] = ['']
+        mesh_dic['vertex_attributes'] = [[], [], []]
+        mesh_dic['vertiex_attribute_titles'] = []
+        mesh_dic['triangle_neighbors'] = [[-1, -1, -1]]
+        mesh_dic['segment_tags'] = ['external',
+                                    'external',
+                                    'external']
+        mesh_dic['geo_reference'] = Geo_reference(56,-0.76,-0.76)
+        mesh_file = tempfile.mktemp(".tsh")
+        export_mesh_file(mesh_file,mesh_dic)
+
+        geo_ref = Geo_reference(56,-200,-400)
+        # create an .xya file
+        point_file = tempfile.mktemp(".xya")
+        fd = open(point_file,'w')
+        fd.write("elevation, stage \n 201.0, 401.0,2.,4 \n 201.0, 403.0,4,8 \n 203.0, 401.0,4.,8 \n")
+        geo_ref.write_ASCII(fd)
+        fd.close()
+
+        mesh_output_file = tempfile.mktemp(".tsh")
+        fit_to_mesh_file(mesh_file,
+                         point_file,
+                         mesh_output_file,
+                         alpha = 0.0)
+        # load in the .tsh file we just wrote
+        mesh_dic = import_mesh_file(mesh_output_file)
+        #print "mesh_dic",mesh_dic
+        ans =[[0.0, 0.0],
+              [5.0, 10.0],
+              [5.0, 10.0]]
+        assert allclose(mesh_dic['vertex_attributes'],ans)
+
+        self.failUnless(mesh_dic['vertex_attribute_titles']  ==
+                        ['elevation','stage'],
+                        'test_fit_to_mesh_file failed')
+
+        #clean up
+        os.remove(mesh_file)
+        os.remove(point_file)
+        os.remove(mesh_output_file)
+
+    def test_fit_to_mesh_fileII(self):
+        from load_mesh.loadASCII import import_mesh_file, \
+             export_mesh_file
+        import tempfile
+        import os
+
+        # create a .tsh file, no user outline
+        mesh_dic = {}
+        mesh_dic['vertices'] = [[0.0, 0.0],
+                                [0.0, 5.0],
+                                [5.0, 0.0]]
+        mesh_dic['triangles'] =  [[0, 2, 1]]
+        mesh_dic['segments'] = [[0, 1], [2, 0], [1, 2]]
+        mesh_dic['triangle_tags'] = ['']
+        mesh_dic['vertex_attributes'] = [[1,2], [1,2], [1,2]]
+        mesh_dic['vertex_attribute_titles'] = ['density', 'temp']
+        mesh_dic['triangle_neighbors'] = [[-1, -1, -1]]
+        mesh_dic['segment_tags'] = ['external',
+                                                  'external',
+                                                  'external']
+        mesh_file = tempfile.mktemp(".tsh")
+        export_mesh_file(mesh_file,mesh_dic)
+
+        # create an .xya file
+        point_file = tempfile.mktemp(".xya")
+        fd = open(point_file,'w')
+        fd.write("elevation, stage \n 1.0, 1.0,2.,4 \n 1.0, 3.0,4,8 \n 3.0,1.0,4.,8 \n")
+        fd.close()
+
+        mesh_output_file = "new_triangle.tsh"
+        fit_to_mesh_file(mesh_file,
+                         point_file,
+                         mesh_output_file,
+                         alpha = 0.0)
+        # load in the .tsh file we just wrote
+        mesh_dic = import_mesh_file(mesh_output_file)
+
+        assert allclose(mesh_dic['vertex_attributes'],
+                        [[1.0, 2.0,0.0, 0.0],
+                         [1.0, 2.0,5.0, 10.0],
+                         [1.0, 2.0,5.0,10.0]])
+
+        self.failUnless(mesh_dic['vertex_attribute_titles']  ==
+                        ['density', 'temp','elevation','stage'],
+                        'test_fit_to_mesh_file failed')
+
+        #clean up
+        os.remove(mesh_file)
+        os.remove(mesh_output_file)
+        os.remove(point_file)
+
+    def test_fit_to_mesh_file_errors(self):
+        from load_mesh.loadASCII import import_mesh_file, export_mesh_file
+        import tempfile
+        import os
+
+        # create a .tsh file, no user outline
+        mesh_dic = {}
+        mesh_dic['vertices'] = [[0.0, 0.0],[0.0, 5.0],[5.0, 0.0]]
+        mesh_dic['triangles'] =  [[0, 2, 1]]
+        mesh_dic['segments'] = [[0, 1], [2, 0], [1, 2]]
+        mesh_dic['triangle_tags'] = ['']
+        mesh_dic['vertex_attributes'] = [[1,2], [1,2], [1,2]]
+        mesh_dic['vertex_attribute_titles'] = ['density', 'temp']
+        mesh_dic['triangle_neighbors'] = [[-1, -1, -1]]
+        mesh_dic['segment_tags'] = ['external', 'external','external']
+        mesh_file = tempfile.mktemp(".tsh")
+        export_mesh_file(mesh_file,mesh_dic)
+
+        # create an .xya file
+        point_file = tempfile.mktemp(".xya")
+        fd = open(point_file,'w')
+        fd.write("elevation stage \n 1.0, 1.0,2.,4 \n 1.0, 3.0,4,8 \n 3.0,1.0,4.,8 \n")
+        fd.close()
+
+        mesh_output_file = "new_triangle.tsh"
+        try:
+            fit_to_mesh_file(mesh_file, point_file,
+                             mesh_output_file, display_errors = False)
+        except IOError:
+            pass
+        else:
+            #self.failUnless(0 ==1,  'Bad file did not raise error!')
+            raise 'Bad file did not raise error!'
+            
+        #clean up
+        os.remove(mesh_file)
+        os.remove(point_file)
+
+    def test_fit_to_mesh_file_errorsII(self):
+        from load_mesh.loadASCII import import_mesh_file, export_mesh_file
+        import tempfile
+        import os
+
+        # create a .tsh file, no user outline
+        mesh_file = tempfile.mktemp(".tsh")
+        fd = open(mesh_file,'w')
+        fd.write("unit testing a bad .tsh file \n")
+        fd.close()
+
+        # create an .xya file
+        point_file = tempfile.mktemp(".xya")
+        fd = open(point_file,'w')
+        fd.write("elevation, stage \n 1.0, 1.0,2.,4 \n 1.0, 3.0,4,8 \n 3.0,1.0,4.,8 \n")
+        fd.close()
+
+        mesh_output_file = "new_triangle.tsh"
+        try:
+            fit_to_mesh_file(mesh_file, point_file,
+                             mesh_output_file, display_errors = False)
+        except IOError:
+            pass
+        else:
+            raise 'Bad file did not raise error!'
+            
+        #clean up
+        os.remove(mesh_file)
+        os.remove(point_file)
+
+    def test_fit_to_mesh_file_errorsIII(self):
+        from load_mesh.loadASCII import import_mesh_file, export_mesh_file
+        import tempfile
+        import os
+
+        # create a .tsh file, no user outline
+        mesh_dic = {}
+        mesh_dic['vertices'] = [[0.0, 0.0],[0.0, 5.0],[5.0, 0.0]]
+        mesh_dic['triangles'] =  [[0, 2, 1]]
+        mesh_dic['segments'] = [[0, 1], [2, 0], [1, 2]]
+        mesh_dic['triangle_tags'] = ['']
+        mesh_dic['vertex_attributes'] = [[1,2], [1,2], [1,2]]
+        mesh_dic['vertex_attribute_titles'] = ['density', 'temp']
+        mesh_dic['triangle_neighbors'] = [[-1, -1, -1]]
+        mesh_dic['segment_tags'] = ['external', 'external','external']
+        mesh_file = tempfile.mktemp(".tsh")
+        export_mesh_file(mesh_file,mesh_dic)
+
+        # create an .xya file
+        point_file = tempfile.mktemp(".xya")
+        fd = open(point_file,'w')
+        fd.write("elevation, stage \n 1.0, 1.0,2.,4 \n 1.0, 3.0,4,8 \n 3.0,1.0,4.,8 \n")
+        fd.close()
+
+        #This a deliberately illegal filename to invoke the error.
+        mesh_output_file = ".../\z\z:ya.tsh"        
+
+        try:
+            fit_to_mesh_file(mesh_file, point_file,
+                             mesh_output_file, display_errors = False)
+        except IOError:
+            pass
+        else:
+            raise 'Bad file did not raise error!'
+        
+        #clean up
+        os.remove(mesh_file)
+        os.remove(point_file)
+  
+## FIXME?  Running from the Comand line isn't in vogue these days
+#  The test was breaking when test_all at the inundation level was running
+# was running it.issue - not running the test in this directory
+    def Bad_test_fit_to_mesh_file_errorsIV(self):
+        import os
+        command = '%s least_squares.py q q q e n 0.9 n'  %(sys.executable)
+        status = os.system(command) 
+        self.failUnless(status%255  == 1,
+                        'command prompt least_squares.py failed.  Incorect exit status.')
+        
+    def test_fit_to_msh_netcdf_fileII(self):
+        from load_mesh.loadASCII import import_mesh_file, export_mesh_file
+        import tempfile
+        import os
+
+        # create a .tsh file, no user outline
+        mesh_dic = {}
+        mesh_dic['vertices'] = [[0.0, 0.0],
+                                [0.0, 5.0],
+                                [5.0, 0.0]]
+        mesh_dic['triangles'] =  [[0, 2, 1]]
+        mesh_dic['segments'] = [[0, 1], [2, 0], [1, 2]]
+        mesh_dic['triangle_tags'] = ['']
+        mesh_dic['vertex_attributes'] = [[1,2], [1,2], [1,2]]
+        mesh_dic['vertex_attribute_titles'] = ['density', 'temp']
+        mesh_dic['triangle_neighbors'] = [[-1, -1, -1]]
+        mesh_dic['segment_tags'] = ['external',
+                                                  'external',
+                                                  'external']
+        mesh_file = tempfile.mktemp(".msh")
+        export_mesh_file(mesh_file,mesh_dic)
+
+        # create an .xya file
+        point_file = tempfile.mktemp(".xya")
+        fd = open(point_file,'w')
+        fd.write("elevation, stage \n 1.0, 1.0,2.,4 \n 1.0, 3.0,4,8 \n 3.0,1.0,4.,8 \n")
+        fd.close()
+
+        mesh_output_file = "new_triangle.msh"
+        fit_to_mesh_file(mesh_file,
+                         point_file,
+                         mesh_output_file,
+                         alpha = 0.0)
+        # load in the .tsh file we just wrote
+        mesh_dic = import_mesh_file(mesh_output_file)
+
+        assert allclose(mesh_dic['vertex_attributes'],
+                        [[1.0, 2.0,0.0, 0.0],
+                         [1.0, 2.0,5.0, 10.0],
+                         [1.0, 2.0,5.0,10.0]])
+
+        self.failUnless(mesh_dic['vertex_attribute_titles']  ==
+                        ['density', 'temp','elevation','stage'],
+                        'test_fit_to_mesh_file failed')
+
+        #clean up
+        os.remove(mesh_file)
+        os.remove(mesh_output_file)
+        os.remove(point_file)
+
+	
+	
+    def test_fit_using_fit_to_mesh(self):
+        """Fit a surface to one set of points. Then interpolate that surface
+        using another set of points.
+        """
+
+        #Setup mesh used to represent fitted 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, daf, dae
+        triangles = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        #Datapoints to fit from
+        data_points1 = [[ 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],
+                        [ 15, -17],   #Outside mesh
+                        [ 1.0, 2.0],
+                        [ 1.0, 3.0],
+                        [ 2.0, 1.0],
+                        [ 3.0, 0.0],
+                        [ 3.0, 1.0]]
+
+        #Fit surface to mesh
+        z = linear_function(data_points1) #Example z-values
+	v = fit_to_mesh(points, triangles, data_points1, z, alpha=0.0,
+                        precrop=True, verbose=False)
+
+	assert allclose(linear_function(points), v)
+
+
+	
+    def test_acceptable_overshoot(self):
+        """Fit a surface to one set of points. Then interpolate that surface
+        using another set of points.
+        Check that exceedance in fitted values are caught.
+        """
+
+        #Setup mesh used to represent fitted 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, daf, dae
+        triangles = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        #Datapoints to fit from
+        data_points1 = [[ 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],
+                        [ 15, -17],   #Outside mesh
+                        [ 1.0, 2.0],
+                        [ 1.0, 3.0],
+                        [ 2.0, 1.0],
+                        [ 3.0, 0.0],
+                        [ 3.0, 1.0]]
+
+        #Fit surface to mesh
+        z = linear_function(data_points1) #Example z-values
+
+        try:
+            v = fit_to_mesh(points, triangles, data_points1, z, alpha=0.0,
+                            acceptable_overshoot = 0.2,
+                            precrop=True, verbose=False)
+        except FittingError, e:
+            pass
+        else:
+            raise 'Should have raised exception'
+            
+
+	#assert allclose(linear_function(points), v)
+        
+
+	
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    #suite = unittest.makeSuite(Test_Least_Squares,'test_smooth_attributes_to_mesh_function')
+    #suite = unittest.makeSuite(Test_Least_Squares,'test_datapoint_at_centroid')
+    suite = unittest.makeSuite(Test_Least_Squares,'test')
+
+    #suite = unittest.makeSuite(Test_Least_Squares,'test_fit_to_msh_netcdf_fileII')
+    #suite = unittest.makeSuite(Test_Least_Squares,'test_fit_to_mesh_fileII')
+    runner = unittest.TextTestRunner(verbosity=1)
+    runner.run(suite)
+
+
+
+
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_most2nc.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_most2nc.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_most2nc.py	(revision 3560)
@@ -0,0 +1,52 @@
+import unittest
+from Numeric import allclose, asarray
+import most2nc
+from Scientific.IO.NetCDF import NetCDFFile
+import os
+
+FN = 'small___.txt'
+
+class Test_most2nc(unittest.TestCase):
+    def setUp(self):
+        fid = open(FN, 'w')
+        fid.write("""4 4 
+150.66667
+150.83334
+151.
+151.16667
+-34.
+-34.16667
+-34.33333
+-34.5
+-1. -2. -3. -4.
+-5. -6. -7. -8.
+-9. -10. -11. -12.
+-13. -14. -15. -16.
+""")
+        fid.close()
+                  
+    def tearDown(self):
+        os.remove(FN)
+
+    def test_small_nxn(self):
+        most2nc.most2nc(input_file=FN,output_file='test.nc'\
+                        ,inverted_bathymetry = False,verbose = False)
+
+        fid = NetCDFFile('test.nc')
+        elevation = fid.variables['ELEVATION'][:]
+        fid.close()
+
+        z=[[-13., -14., -15., -16.]\
+           ,[-9., -10., -11., -12.]\
+           ,[-5.,  -6.,  -7.,  -8.]\
+           ,[-1.,  -2.,  -3.,  -4.]]
+        z = asarray(z)
+
+        assert allclose(z,elevation)
+        import os
+        os.remove('test.nc')
+        
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_most2nc,'test')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_neighbour_mesh.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_neighbour_mesh.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_neighbour_mesh.py	(revision 3560)
@@ -0,0 +1,972 @@
+#!/usr/bin/env python
+
+
+
+#FIXME: Seperate the tests for mesh and general_mesh
+
+#FIXME (Ole): Maxe this test independent of anything that inherits from General_mesh (namely shallow_water)
+
+import unittest
+from math import sqrt
+
+from neighbour_mesh import *
+from mesh_factory import rectangular
+from anuga.config import epsilon
+from Numeric import allclose, array
+
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+from anuga.utilities.polygon import is_inside_polygon
+
+def distance(x, y):
+    return sqrt( sum( (array(x)-array(y))**2 ))
+
+class Test_Mesh(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_triangle_inputs(self):
+        points = [[0.0, 0.0], [4.0, 0.0], [0.0, 3.0]]
+        vertices = [0,1,2] #Wrong
+
+        try:
+            mesh = Mesh(points, vertices)
+        except:
+            pass
+        else:
+            msg = 'Should have raised exception'
+            raise msg
+
+
+    def test_basic_triangle(self):
+
+        a = [0.0, 0.0]
+        b = [4.0, 0.0]
+        c = [0.0, 3.0]
+
+        points = [a, b, c]
+        vertices = [[0,1,2]]
+        mesh = Mesh(points, vertices)
+
+        #Centroid
+        centroid = mesh.centroid_coordinates[0]
+        assert centroid[0] == 4.0/3
+        assert centroid[1] == 1.0
+
+        #Area
+        assert mesh.areas[0] == 6.0,\
+               'Area was %f, should have been 6.0' %mesh.areas[0]
+
+        #Normals
+        normals = mesh.get_normals()
+        assert allclose(normals[0, 0:2], [3.0/5, 4.0/5])
+        assert allclose(normals[0, 2:4], [-1.0, 0.0])
+        assert allclose(normals[0, 4:6], [0.0, -1.0])
+
+        assert allclose(mesh.get_normal(0,0), [3.0/5, 4.0/5])
+        assert allclose(mesh.get_normal(0,1), [-1.0, 0.0])
+        assert allclose(mesh.get_normal(0,2), [0.0, -1.0])
+
+        #Edge lengths
+        assert allclose(mesh.edgelengths[0], [5.0, 3.0, 4.0])
+
+
+        #Vertex coordinates
+        V = mesh.get_vertex_coordinates()
+        assert allclose(V[0], [0.0, 0.0, 4.0, 0.0, 0.0, 3.0])
+
+        V = mesh.get_vertex_coordinates(obj=True)
+        assert allclose(V, [ [0.0, 0.0],
+                             [4.0, 0.0],
+                             [0.0, 3.0] ])
+
+        V0 = mesh.get_vertex_coordinate(0, 0)
+        assert allclose(V0, [0.0, 0.0])
+
+        V1 = mesh.get_vertex_coordinate(0, 1)
+        assert allclose(V1, [4.0, 0.0])
+
+        V2 = mesh.get_vertex_coordinate(0, 2)
+        assert allclose(V2, [0.0, 3.0])
+
+
+        #General tests:
+
+        #Test that points are arranged in a counter clock wise order etc
+        mesh.check_integrity()
+
+
+        #Test that the centroid is located 2/3 of the way
+        #from each vertex to the midpoint of the opposite side
+
+        V = mesh.get_vertex_coordinates()
+
+        x0 = V[0,0]
+        y0 = V[0,1]
+        x1 = V[0,2]
+        y1 = V[0,3]
+        x2 = V[0,4]
+        y2 = V[0,5]
+
+        m0 = [(x1 + x2)/2, (y1 + y2)/2]
+        m1 = [(x0 + x2)/2, (y0 + y2)/2]
+        m2 = [(x1 + x0)/2, (y1 + y0)/2]
+
+        d0 = distance(centroid, [x0, y0])
+        d1 = distance(m0, [x0, y0])
+        assert d0 == 2*d1/3
+        #
+        d0 = distance(centroid, [x1, y1])
+        d1 = distance(m1, [x1, y1])
+        assert abs(d0 - 2*d1/3) < epsilon, '%e, %e' %(d0, 2*d1/3)
+
+        d0 = distance(centroid, [x2, y2])
+        d1 = distance(m2, [x2, y2])
+        assert abs(d0 - 2*d1/3) < epsilon, '%e, %e' %(d0, 2*d1/3)
+
+        #Radius
+        d0 = distance(centroid, m0)
+        assert d0 == 5.0/6
+
+        d1 = distance(centroid, m1)
+        assert d1 == sqrt(73.0/36)
+
+        d2 = distance(centroid, m2)
+        assert d2 == sqrt(13.0/9)
+
+        assert mesh.radii[0] == min(d0, d1, d2)
+        assert mesh.radii[0] == 5.0/6
+
+
+        #Let x be the centroid of triangle abc.
+        #Test that areas of the three triangles axc, cxb, and bxa are equal.
+        points = [a, b, c, centroid]
+        vertices = [[0,3,2], [2,3,1], [1,3,0]]
+        new_mesh = Mesh(points, vertices)
+
+        assert new_mesh.areas[0] == new_mesh.areas[1]
+        assert new_mesh.areas[1] == new_mesh.areas[2]
+        assert new_mesh.areas[1] == new_mesh.areas[2]
+
+        assert new_mesh.areas[1] == mesh.areas[0]/3
+
+
+
+    def test_general_triangle(self):
+        a = [2.0, 1.0]
+        b = [6.0, 2.0]
+        c = [1.0, 3.0]
+
+        points = [a, b, c]
+        vertices = [[0,1,2]]
+
+        mesh = Mesh(points, vertices)
+        centroid = mesh.centroid_coordinates[0]
+
+
+        #Test that the centroid is located 2/3 of the way
+        #from each vertex to the midpoint of the opposite side
+
+        V = mesh.get_vertex_coordinates()
+
+        x0 = V[0,0]
+        y0 = V[0,1]
+        x1 = V[0,2]
+        y1 = V[0,3]
+        x2 = V[0,4]
+        y2 = V[0,5]
+
+        m0 = [(x1 + x2)/2, (y1 + y2)/2]
+        m1 = [(x0 + x2)/2, (y0 + y2)/2]
+        m2 = [(x1 + x0)/2, (y1 + y0)/2]
+
+        d0 = distance(centroid, [x0, y0])
+        d1 = distance(m0, [x0, y0])
+        assert abs(d0 - 2*d1/3) < epsilon, '%e, %e' %(d0, 2*d1/3)
+        #
+        d0 = distance(centroid, [x1, y1])
+        d1 = distance(m1, [x1, y1])
+        assert abs(d0 - 2*d1/3) < epsilon, '%e, %e' %(d0, 2*d1/3)
+
+        d0 = distance(centroid, [x2, y2])
+        d1 = distance(m2, [x2, y2])
+        assert abs(d0 - 2*d1/3) < epsilon, '%e, %e' %(d0, 2*d1/3)
+
+        #Radius
+        d0 = distance(centroid, m0)
+        d1 = distance(centroid, m1)
+        d2 = distance(centroid, m2)
+        assert mesh.radii[0] == min(d0, d1, d2)
+
+
+
+        #Let x be the centroid of triangle abc.
+        #Test that areas of the three triangles axc, cxb, and bxa are equal.
+
+        points = [a, b, c, centroid]
+        vertices = [[0,3,2], [2,3,1], [1,3,0]]
+        new_mesh = Mesh(points, vertices)
+
+        assert new_mesh.areas[0] == new_mesh.areas[1]
+        assert new_mesh.areas[1] == new_mesh.areas[2]
+        assert new_mesh.areas[1] == new_mesh.areas[2]
+
+        assert new_mesh.areas[1] == mesh.areas[0]/3
+
+
+        #Test that points are arranged in a counter clock wise order
+        mesh.check_integrity()
+
+    def test_inscribed_circle_equilateral(self):
+        """test that the radius is calculated correctly by mesh in the case of an equilateral triangle"""
+        a = [0.0, 0.0]
+        b = [2.0, 0.0]
+        c = [1.0, sqrt(3.0)]
+
+        points = [a, b, c]
+        vertices = [[0,1,2]]
+
+        mesh = Mesh(points, vertices,use_inscribed_circle=False)
+        assert allclose(mesh.radii[0],sqrt(3.0)/3),'Steve''s doesn''t work'
+
+        mesh = Mesh(points, vertices,use_inscribed_circle=True)
+        assert allclose(mesh.radii[0],sqrt(3.0)/3),'inscribed circle doesn''t work'
+
+    def test_inscribed_circle_rightangle_triangle(self):
+        """test that the radius is calculated correctly by mesh in the case of a right-angled triangle"""
+        a = [0.0, 0.0]
+        b = [4.0, 0.0]
+        c = [0.0, 3.0]
+
+        points = [a, b, c]
+        vertices = [[0,1,2]]
+
+        mesh = Mesh(points, vertices,use_inscribed_circle=False)
+        assert allclose(mesh.radii[0],5.0/6),'Steve''s doesn''t work'
+
+        mesh = Mesh(points, vertices,use_inscribed_circle=True)
+        assert allclose(mesh.radii[0],1.0),'inscribed circle doesn''t work'
+
+
+    def test_two_triangles(self):
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0,0.0]
+        e = [2.0, 2.0]
+        points = [a, b, c, e]
+        vertices = [ [1,0,2], [1,2,3] ]   #bac, bce
+        mesh = Mesh(points, vertices)
+
+        assert mesh.areas[0] == 2.0
+
+        assert allclose(mesh.centroid_coordinates[0], [2.0/3, 2.0/3])
+
+
+        #Test that points are arranged in a counter clock wise order
+        mesh.check_integrity()
+
+
+
+    def test_more_triangles(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, daf, dae
+        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+        mesh = Mesh(points, vertices)
+
+        #Test that points are arranged in a counter clock wise order
+        mesh.check_integrity()
+
+        assert mesh.areas[0] == 2.0
+        assert mesh.areas[1] == 2.0
+        assert mesh.areas[2] == 2.0
+        assert mesh.areas[3] == 2.0
+
+        assert mesh.edgelengths[1,0] == 2.0
+        assert mesh.edgelengths[1,1] == 2.0
+        assert mesh.edgelengths[1,2] == sqrt(8.0)
+
+        assert allclose(mesh.centroid_coordinates[0], [2.0/3, 2.0/3])
+        assert allclose(mesh.centroid_coordinates[1], [4.0/3, 4.0/3])
+        assert allclose(mesh.centroid_coordinates[2], [8.0/3, 2.0/3])
+        assert allclose(mesh.centroid_coordinates[3], [2.0/3, 8.0/3])
+
+    def test_mesh_and_neighbours(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] ]
+        mesh = Mesh(points, vertices)
+
+        mesh.check_integrity()
+
+
+        T = mesh
+        tid = 0
+        assert T.number_of_boundaries[tid] == 2
+        assert T.neighbours[tid, 0] < 0  #Opposite point b (0,2)
+        assert T.neighbours[tid, 1] == 1 #Opposite point a (0,0)
+        assert T.neighbours[tid, 2] < 0  #Opposite point c (2,0)
+
+        tid = 1
+        assert T.number_of_boundaries[tid] == 0
+        assert T.neighbours[tid, 0] == 2  #Opposite point b (0,2)
+        assert T.neighbours[tid, 1] == 3  #Opposite point c (2,0)
+        assert T.neighbours[tid, 2] == 0  #Opposite point e (2,2)
+
+        tid = 2
+        assert T.number_of_boundaries[tid] == 2
+        assert T.neighbours[tid, 0] < 0   #Opposite point e (2,2)
+        assert T.neighbours[tid, 1] < 0   #Opposite point c (2,0)
+        assert T.neighbours[tid, 2] == 1  #Opposite point f (4,0)
+
+        tid = 3
+        assert T.number_of_boundaries[tid] == 2
+        assert T.neighbours[tid, 0] == 1  #Opposite point d (0,4)
+        assert T.neighbours[tid, 1] < 0   #Opposite point b (0,3)
+        assert T.neighbours[tid, 2] < 0   #Opposite point e (2,2)
+
+        #Neighbouring edges
+        tid = 0
+        assert T.neighbour_edges[tid, 0] < 0  #Opposite point b (0,2)
+        assert T.neighbour_edges[tid, 1] == 2 #Opposite point a (0,0)
+        assert T.neighbour_edges[tid, 2] < 0  #Opposite point c (2,0)
+
+        tid = 1
+        assert T.neighbour_edges[tid, 0] == 2 #Opposite point b (0,2)
+        assert T.neighbour_edges[tid, 1] == 0 #Opposite point c (2,0)
+        assert T.neighbour_edges[tid, 2] == 1 #Opposite point e (2,2)
+
+        tid = 2
+        assert T.neighbour_edges[tid, 0] < 0  #Opposite point e (2,2)
+        assert T.neighbour_edges[tid, 1] < 0  #Opposite point c (2,0)
+        assert T.neighbour_edges[tid, 2] == 0 #Opposite point f (4,0)
+
+        tid = 3
+        assert T.neighbour_edges[tid, 0] == 1 #Opposite point d (0,4)
+        assert T.neighbour_edges[tid, 1] < 0  #Opposite point b (0,3)
+        assert T.neighbour_edges[tid, 2] < 0  #Opposite point e (2,2)
+
+
+    def test_build_neighbour_structure_duplicates(self):
+        p0 = [-66.0, 14.0]
+        p1 = [14.0, -66.0]
+        p2 = [14.0, 14.0]
+        p3 = [60.0, 20.0]
+        p4 = [10.0, 60.0]
+        p5 = [60.0, 60.0]
+
+        points = [p0, p1, p2, p3, p4, p5]
+        triangles = [ [0, 1, 2],
+                      [3, 2, 1],
+                      [0, 2, 4],
+                      [0, 2, 4],
+                      [4, 2, 5],
+                      [5, 2, 3]]
+        try:
+            mesh = Mesh(points, triangles)
+        except:
+            pass
+        else:
+            raise "triangle edge duplicates not caught"
+
+    def test_rectangular_mesh_basic(self):
+        M=1
+        N=1
+
+        points, vertices, boundary = rectangular(M, N)
+	mesh = Mesh(points, vertices, boundary)
+
+        #Test that points are arranged in a counter clock wise order
+        mesh.check_integrity()
+
+        M=2
+        N=2
+        points, vertices, boundary = rectangular(M, N)
+	mesh = Mesh(points, vertices, boundary)
+
+        #Test that points are arranged in a counter clock wise order
+        mesh.check_integrity()
+
+        #assert mesh.boundary[(7,1)] == 2 # top
+        assert mesh.boundary[(7,1)] == 'top' # top
+        assert mesh.boundary[(3,1)] == 'top' # top
+
+
+    def test_boundary_tags(self):
+
+
+        points, vertices, boundary = rectangular(4, 4)
+	mesh = Mesh(points, vertices, boundary)
+
+
+        #Test that points are arranged in a counter clock wise order
+        mesh.check_integrity()
+
+        #print mesh.get_boundary_tags()
+        #print mesh.boundary
+
+        for k in [1, 3, 5, 7]:
+            assert mesh.boundary[(k,2)] == 'left'
+
+        for k in [24, 26, 28, 30]:
+            assert mesh.boundary[(k,2)] == 'right'
+
+        for k in [7, 15, 23, 31]:
+            assert mesh.boundary[(k,1)] == 'top'
+        for k in [0, 8, 16, 24]:
+            assert mesh.boundary[(k,1)] == 'bottom'
+
+
+
+    def test_rectangular_mesh(self):
+        M=4
+        N=16
+        len1 = 100.0
+        len2 = 17.0
+
+        points, vertices, boundary = rectangular(M, N, len1, len2)
+	mesh = Mesh(points, vertices, boundary)
+
+        assert len(mesh) == 2*M*N
+
+        for i in range(len(mesh)):
+            assert mesh.areas[i] == len1*len2/(2*M*N)
+
+            hypo = sqrt((len1/M)**2 + (len2/N)**2) #hypothenuse
+            assert mesh.edgelengths[i, 0] == hypo
+            assert mesh.edgelengths[i, 1] == len1/M #x direction
+            assert mesh.edgelengths[i, 2] == len2/N #y direction
+
+        #Test that points are arranged in a counter clock wise order
+        mesh.check_integrity()
+
+
+    def test_rectangular_mesh2(self):
+        #Check that integers don't cause trouble
+        N = 16
+
+        points, vertices, boundary = rectangular(2*N, N, len1=10, len2=10)
+	mesh = Mesh(points, vertices, boundary)
+
+
+
+    def test_surrogate_neighbours(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] ]
+        mesh = Mesh(points, vertices)
+        mesh.check_integrity()
+
+
+        T = mesh
+        tid = 0
+        assert T.number_of_boundaries[tid] == 2
+        assert T.surrogate_neighbours[tid, 0] == tid
+        assert T.surrogate_neighbours[tid, 1] == 1
+        assert T.surrogate_neighbours[tid, 2] == tid
+
+        tid = 1
+        assert T.number_of_boundaries[tid] == 0
+        assert T.surrogate_neighbours[tid, 0] == 2
+        assert T.surrogate_neighbours[tid, 1] == 3
+        assert T.surrogate_neighbours[tid, 2] == 0
+
+        tid = 2
+        assert T.number_of_boundaries[tid] == 2
+        assert T.surrogate_neighbours[tid, 0] == tid
+        assert T.surrogate_neighbours[tid, 1] == tid
+        assert T.surrogate_neighbours[tid, 2] == 1
+
+        tid = 3
+        assert T.number_of_boundaries[tid] == 2
+        assert T.surrogate_neighbours[tid, 0] == 1
+        assert T.surrogate_neighbours[tid, 1] == tid
+        assert T.surrogate_neighbours[tid, 2] == tid
+
+
+    def test_boundary_inputs(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): 'First',
+                     (0, 2): 'Second',
+                     (2, 0): 'Third',
+                     (2, 1): 'Fourth',
+                     (3, 1): 'Fifth',
+                     (3, 2): 'Sixth'}
+
+
+        mesh = Mesh(points, vertices, boundary)
+        mesh.check_integrity()
+
+
+        #Check enumeration
+        #for k, (vol_id, edge_id) in enumerate(mesh.boundary_segments):
+        #    b = -k-1
+        #    assert mesh.neighbours[vol_id, edge_id] == b
+
+
+
+    def test_boundary_inputs_using_one_default(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): 'First',
+                     (0, 2): 'Second',
+                     (2, 0): 'Third',
+                     (2, 1): 'Fourth',
+                     #(3, 1): 'Fifth',  #Skip this
+                     (3, 2): 'Sixth'}
+
+
+        mesh = Mesh(points, vertices, boundary)
+        mesh.check_integrity()
+
+        from anuga.config import default_boundary_tag
+        assert mesh.boundary[ (3, 1) ] == default_boundary_tag
+
+
+        #Check enumeration
+        #for k, (vol_id, edge_id) in enumerate(mesh.boundary_segments):
+        #    b = -k-1
+        #    assert mesh.neighbours[vol_id, edge_id] == b
+
+    def test_boundary_inputs_using_all_defaults(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): 'First',
+                     (0, 2): 'Second',
+                     (2, 0): 'Third',
+                     (2, 1): 'Fourth',
+                     #(3, 1): 'Fifth',  #Skip this
+                     (3, 2): 'Sixth'}
+
+
+        mesh = Mesh(points, vertices) #, boundary)
+        mesh.check_integrity()
+
+        from anuga.config import default_boundary_tag
+        assert mesh.boundary[ (0, 0) ] == default_boundary_tag
+        assert mesh.boundary[ (0, 2) ] == default_boundary_tag
+        assert mesh.boundary[ (2, 0) ] == default_boundary_tag
+        assert mesh.boundary[ (2, 1) ] == default_boundary_tag
+        assert mesh.boundary[ (3, 1) ] == default_boundary_tag
+        assert mesh.boundary[ (3, 2) ] == default_boundary_tag
+
+
+        #Check enumeration
+        #for k, (vol_id, edge_id) in enumerate(mesh.boundary_segments):
+        #    b = -k-1
+        #    assert mesh.neighbours[vol_id, edge_id] == b
+
+
+
+
+
+
+    def test_inputs(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] ]
+
+        #Too few points
+        try:
+            mesh = Mesh([points[0]], vertices)
+        except AssertionError:
+            pass
+        else:
+            raise 'Should have raised an exception'
+
+        #Too few points - 1 element
+        try:
+            mesh = Mesh([points[0]], [vertices[0]])
+        except AssertionError:
+            pass
+        else:
+            raise 'Should have raised an exception'
+
+        #Wrong dimension of vertices
+        try:
+            mesh = Mesh(points, vertices[0])
+        except AssertionError:
+            pass
+        else:
+            raise 'Should have raised an exception'
+
+        #Unsubscriptable coordinates object raises exception
+        try:
+            mesh = Mesh(points[0], [vertices[0]])
+        except AssertionError:
+            pass
+        else:
+            raise 'Should have raised an exception'
+
+        #FIXME: This has been commented out pending a decision
+        #whether to allow partial boundary tags or not
+        #
+        #Not specifying all boundary tags
+        #try:
+        #    mesh = Mesh(points, vertices, {(3,0): 'x'})
+        #except AssertionError:
+        #    pass
+        #else:
+        #    raise 'Should have raised an exception'
+
+        #Specifying wrong non existing segment
+        try:
+            mesh = Mesh(points, vertices, {(5,0): 'x'})
+        except AssertionError:
+            pass
+        else:
+            raise 'Should have raised an exception'
+
+
+
+
+    def test_internal_boundaries(self):
+        """
+        get values based on triangle lists.
+        """
+        from mesh_factory import rectangular
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+
+        # Add an internal boundary
+        boundary[(2,0)] = 'internal'
+        boundary[(1,0)] = 'internal'
+
+        #Create shallow water domain
+        domain = Mesh(points, vertices, boundary)
+        domain.build_tagged_elements_dictionary({'bottom':[0,1],
+                                                 'top':[4,5],
+                                                 'all':[0,1,2,3,4,5]})
+
+
+    def test_boundary_polygon(self):
+        from mesh_factory import rectangular
+        #from mesh import Mesh
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(2, 2)
+        mesh = Mesh(points, vertices, boundary)
+
+
+        P = mesh.get_boundary_polygon()
+
+        assert len(P) == 8
+        assert allclose(P, [[0.0, 0.0], [0.5, 0.0], [1.0, 0.0],
+                            [1.0, 0.5], [1.0, 1.0], [0.5, 1.0],
+                            [0.0, 1.0], [0.0, 0.5]])
+        for p in points:
+            #print p, P
+            assert is_inside_polygon(p, P)
+
+
+    def test_boundary_polygon_II(self):
+        from Numeric import zeros, Float
+        
+
+        #Points
+        a = [0.0, 0.0] #0
+        b = [0.0, 0.5] #1
+        c = [0.0, 1.0] #2
+        d = [0.5, 0.0] #3
+        e = [0.5, 0.5] #4
+        f = [1.0, 0.0] #5
+        g = [1.0, 0.5] #6
+        h = [1.0, 1.0] #7
+        i = [1.5, 0.5] #8
+
+        points = [a, b, c, d, e, f, g, h, i]
+
+        #dea, bae, bec, fgd,
+        #edg, ghe, gfi, gih
+        vertices = [ [3,4,0], [1,0,4], [1,4,2], [5,6,3],
+                     [4,3,6], [6,7,4], [6,5,8], [6,8,7]]
+
+        mesh = Mesh(points, vertices)
+
+        mesh.check_integrity()
+
+        P = mesh.get_boundary_polygon()
+
+        assert len(P) == 8
+        assert allclose(P, [a, d, f, i, h, e, c, b])
+
+        for p in points:
+            #print p, P
+            assert is_inside_polygon(p, P)
+
+
+    def test_boundary_polygon_III(self):
+        """Same as II but vertices ordered differently
+        """
+
+        from Numeric import zeros, Float
+
+
+        #Points
+        a = [0.0, 0.0] #0
+        b = [0.0, 0.5] #1
+        c = [0.0, 1.0] #2
+        d = [0.5, 0.0] #3
+        e = [0.5, 0.5] #4
+        f = [1.0, 0.0] #5
+        g = [1.0, 0.5] #6
+        h = [1.0, 1.0] #7
+        i = [1.5, 0.5] #8
+
+        points = [a, b, c, d, e, f, g, h, i]
+
+        #edg, ghe, gfi, gih
+        #dea, bae, bec, fgd,
+        vertices = [[4,3,6], [6,7,4], [6,5,8], [6,8,7],
+                    [3,4,0], [1,0,4], [1,4,2], [5,6,3]]
+
+
+        mesh = Mesh(points, vertices)
+        mesh.check_integrity()
+
+
+        P = mesh.get_boundary_polygon()
+
+        assert len(P) == 8
+        assert allclose(P, [a, d, f, i, h, e, c, b])
+
+        for p in points:
+            assert is_inside_polygon(p, P)
+
+
+    def test_boundary_polygon_IV(self):
+        """Reproduce test test_spatio_temporal_file_function_time
+        from test_util.py that looked as if it produced the wrong boundary
+        """
+
+        from Numeric import zeros, Float
+        from mesh_factory import rectangular        
+
+        #Create a domain to hold test grid
+        #(0:15, -20:10)
+        points, vertices, boundary =\
+                rectangular(4, 4, 15, 30, origin = (0, -20))        
+
+        #####
+        mesh = Mesh(points, vertices)
+        mesh.check_integrity()
+
+        P = mesh.get_boundary_polygon()
+
+        #print P
+        assert len(P) == 16
+        for p in points:
+            assert is_inside_polygon(p, P)
+
+
+
+        #####
+        mesh = Mesh(points, vertices, boundary)
+        mesh.check_integrity()
+
+        P = mesh.get_boundary_polygon()
+
+        
+        #print P, len(P)
+        assert len(P) == 16
+
+        for p in points:
+            assert is_inside_polygon(p, P)
+
+        #print mesh.statistics()    
+
+
+
+    def test_boundary_polygon_V(self):
+        """Create a discontinuous mesh (duplicate vertices)
+        and check that boundary is as expected
+        
+        """
+        from Numeric import zeros, Float
+        
+
+        #Points
+        a = [0.0, 0.0] #0
+        b = [0.0, 0.5] #1
+        c = [0.0, 1.0] #2
+        d = [0.5, 0.0] #3
+        e = [0.5, 0.5] #4
+        f = [1.0, 0.0] #5
+        g = [1.0, 0.5] #6
+        h = [1.0, 1.0] #7
+        i = [1.5, 0.5] #8
+
+        #Duplicate points for triangles edg [4,3,6] (central) and
+        #gid [6,8,7] (top right boundary) to them disconnected
+        #from the others
+
+        e0 = [0.5, 0.5] #9 
+        d0 = [0.5, 0.0] #10
+        g0 = [1.0, 0.5] #11
+        i0 = [1.5, 0.5] #12        
+        
+
+        points = [a, b, c, d, e, f, g, h, i, e0, d0, g0, i0]
+
+
+
+        #dea, bae, bec, fgd,
+        #edg, ghe, gfi, gih
+        #vertices = [ [3,4,0], [1,0,4], [1,4,2], [5,6,3],
+        #             [4,3,6], [6,7,4], [6,5,8], [6,8,7]]
+
+
+        #dea, bae, bec, fgd,
+        #e0d0g0, ghe, gfi, g0i0h
+        vertices = [[3,4,0], [1,0,4], [1,4,2], [5,6,3],
+                    [9,10,11], [6,7,4], [6,5,8], [11,12,7]]        
+
+        mesh = Mesh(points, vertices)
+
+        mesh.check_integrity()
+
+        P = mesh.get_boundary_polygon()
+
+        #print P
+        
+        assert len(P) == 8
+        assert allclose(P, [a, d, f, i, h, e, c, b])
+        assert allclose(P, [(0.0, 0.0), (0.5, 0.0), (1.0, 0.0), (1.5, 0.5), (1.0, 1.0), (0.5, 0.5), (0.0, 1.0), (0.0, 0.5)])
+        
+
+        for p in points:
+            #print p, P
+            assert is_inside_polygon(p, P)
+
+
+
+    def test_lone_vertices(self):
+        a = [2.0, 1.0]
+        b = [6.0, 2.0]
+        c = [1.0, 3.0]
+        d = [2.0, 4.0]
+
+        points = [a, b, c, d]
+        vertices = [[0,1,2]]
+
+        mesh = Mesh(points, vertices)
+        mesh.check_integrity()
+        loners = mesh.get_lone_vertices()
+        self.failUnless(loners==[3],
+                        'FAILED!')
+
+        
+        a = [2.0, 1.0]
+        b = [6.0, 2.0]
+        c = [1.0, 3.0]
+        d = [2.0, 4.0]
+
+        points = [d, a, b, c]
+        vertices = [[3,1,2]]
+
+        mesh = Mesh(points, vertices)
+        mesh.check_integrity()
+        loners = mesh.get_lone_vertices()
+        self.failUnless(loners==[0],
+                        'FAILED!') 
+
+    def test_mesh_get_boundary_polygon_with_georeferencing(self):
+     
+        # test
+        a = [0.0, 0.0]
+        b = [4.0, 0.0]
+        c = [0.0, 4.0]
+
+        absolute_points = [a, b, c]
+        vertices = [[0,1,2]]
+        
+        geo = Geo_reference(56,67,-56)
+
+        relative_points = geo.change_points_geo_ref(absolute_points)
+
+        #print 'Relative', relative_points
+        #print 'Absolute', absolute_points       
+
+        mesh = Mesh(relative_points, vertices, geo_reference=geo)
+        boundary_polygon = mesh.get_boundary_polygon()
+
+        assert allclose(absolute_points, boundary_polygon)
+        
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    #suite = unittest.makeSuite(Test_Mesh,'test_mesh_get_boundary_polygon_with_georeferencing')
+    suite = unittest.makeSuite(Test_Mesh,'test')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
+
+
+
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_pmesh2domain.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_pmesh2domain.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_pmesh2domain.py	(revision 3560)
@@ -0,0 +1,263 @@
+#!/usr/bin/env python
+#
+
+import unittest
+
+from Numeric import allclose, array
+
+from shallow_water import Domain
+
+#from anuga.pyvolution.pmesh2domain import *
+
+from pmesh2domain import *
+
+from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+     Transmissive_boundary
+
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+from anuga.pmesh.mesh import importMeshFromFile
+
+class Test_pmesh2domain(unittest.TestCase):
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    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 =  Dirichlet_boundary(conserved_quantities = array([0.0]))
+         b2 =  Dirichlet_boundary(conserved_quantities = array([1.0]))
+         b3 =  Dirichlet_boundary(conserved_quantities = array([2.0]))
+         tags["1"] = b1
+         tags["2"] = b2
+         tags["3"] = b3
+
+         domain = pmesh_to_domain_instance(fileName, Domain)
+         os.remove(fileName)
+         #print "domain.tagged_elements", domain.tagged_elements
+         ## check the quantities
+         #print domain.quantities['elevation'].vertex_values
+         answer = [[0., 8., 0.],
+                   [0., 10., 8.]]
+         assert allclose(domain.quantities['elevation'].vertex_values,
+                        answer)
+
+         #print domain.quantities['stage'].vertex_values
+         answer = [[0., 12., 10.],
+                   [0., 10., 12.]]
+         assert allclose(domain.quantities['stage'].vertex_values,
+                        answer)
+
+         #print domain.quantities['friction'].vertex_values
+         answer = [[0.01, 0.04, 0.03],
+                   [0.01, 0.02, 0.04]]
+         assert allclose(domain.quantities['friction'].vertex_values,
+                        answer)
+
+         #print domain.quantities['friction'].vertex_values
+         assert allclose(domain.tagged_elements['dsg'][0],0)
+         assert allclose(domain.tagged_elements['ole nielsen'][0],1)
+
+         self.failUnless( domain.boundary[(1, 0)]  == '1',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         self.failUnless( domain.boundary[(1, 2)]  == '2',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         self.failUnless( domain.boundary[(0, 1)]  == '3',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         self.failUnless( domain.boundary[(0, 0)]  == 'exterior',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         #print "domain.boundary",domain.boundary
+         self.failUnless( len(domain.boundary)  == 4,
+                          "test_pmesh2Domain Too many boundaries")
+         #FIXME change to use get_xllcorner
+         #print "d.geo_reference.xllcorner",domain.geo_reference.xllcorner 
+         self.failUnless(domain.geo_reference.xllcorner  == 140.0,
+                          "bad geo_referece")
+    #************
+    
+    def test_pmesh2Domain_instance(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()
+
+         mesh_instance = importMeshFromFile(fileName)
+        
+         tags = {}
+         b1 =  Dirichlet_boundary(conserved_quantities = array([0.0]))
+         b2 =  Dirichlet_boundary(conserved_quantities = array([1.0]))
+         b3 =  Dirichlet_boundary(conserved_quantities = array([2.0]))
+         tags["1"] = b1
+         tags["2"] = b2
+         tags["3"] = b3
+
+         domain = pmesh_instance_to_domain_instance(mesh_instance, Domain)
+
+         os.remove(fileName)
+         #print "domain.tagged_elements", domain.tagged_elements
+         ## check the quantities
+         #print domain.quantities['elevation'].vertex_values
+         answer = [[0., 8., 0.],
+                   [0., 10., 8.]]
+         assert allclose(domain.quantities['elevation'].vertex_values,
+                        answer)
+
+         #print domain.quantities['stage'].vertex_values
+         answer = [[0., 12., 10.],
+                   [0., 10., 12.]]
+         assert allclose(domain.quantities['stage'].vertex_values,
+                        answer)
+
+         #print domain.quantities['friction'].vertex_values
+         answer = [[0.01, 0.04, 0.03],
+                   [0.01, 0.02, 0.04]]
+         assert allclose(domain.quantities['friction'].vertex_values,
+                        answer)
+
+         #print domain.quantities['friction'].vertex_values
+         assert allclose(domain.tagged_elements['dsg'][0],0)
+         assert allclose(domain.tagged_elements['ole nielsen'][0],1)
+
+         self.failUnless( domain.boundary[(1, 0)]  == '1',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         self.failUnless( domain.boundary[(1, 2)]  == '2',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         self.failUnless( domain.boundary[(0, 1)]  == '3',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         self.failUnless( domain.boundary[(0, 0)]  == 'exterior',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         #print "domain.boundary",domain.boundary
+         self.failUnless( len(domain.boundary)  == 4,
+                          "test_pmesh2Domain Too many boundaries")
+         #FIXME change to use get_xllcorner
+         #print "d.geo_reference.xllcorner",domain.geo_reference.xllcorner 
+         self.failUnless(domain.geo_reference.xllcorner  == 140.0,
+                          "bad geo_referece")
+         
+    #***********
+    def old_test_tags_to_boundaries (self):
+         meshDict = {}
+         p0 = [0.0, 0.0]
+         p1 = [1.0, 0.0]
+         p2 = [0.0, 1.0]
+         p3 = [0.646446609407, 0.353553390593]
+         meshDict['vertices'] = [p0,p1,p2,p3]
+         meshDict['vertex_attributes'] = [[0.0, 0.0,7.0],[10.0, 0.0,7.0],[0.0, 10.0,7.0],[6.46446609407, 3.53553390593,7.0]]
+         meshDict['triangles'] = [[0,3,2],[0,1,3]]
+         meshDict['triangle_tags'] = [6.6,6.6]
+         meshDict['triangle_neighbors'] = [[-1,-1,1],[-1,0,-1]]
+         meshDict['segments'] = [[1,0],[0,2],[2,3],[3,1]]
+         meshDict['segment_tags'] = [2,3,1,1]
+
+         domain = Domain.pmesh_dictionary_to_domain(meshDict)
+
+         #domain.set_tag_dict(tag_dict)
+         #Boundary tests
+         b1 =  Dirichlet_boundary(conserved_quantities = array([0.0]))
+         b2 =  Dirichlet_boundary(conserved_quantities = array([1.0]))
+         b3 =  Dirichlet_boundary(conserved_quantities = array([1.0]))
+         #test adding a boundary
+         tags = {}
+         tags[1] = b1
+         tags[2] = b2
+         tags[3] = b3
+         domain.set_boundary(tags)
+         inverted_id = Volume.instances[0].neighbours[0]
+         id = -(inverted_id+1)
+         boundary_value = Boundary_value.instances[id]
+         boundary_obj = boundary_value.boundary_object
+
+         self.failUnless( boundary_obj  == b1,
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+
+         inverted_id = Volume.instances[0].neighbours[1]
+         id = -(inverted_id+1)
+         boundary_value = Boundary_value.instances[id]
+         boundary_obj = boundary_value.boundary_object
+         self.failUnless( boundary_obj  == b3,
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_pmesh2domain, 'test')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
+
+
+
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_quad.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_quad.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_quad.py	(revision 3560)
@@ -0,0 +1,156 @@
+import unittest
+from quad import Cell, build_quadtree
+
+#from domain import *
+from general_mesh import General_mesh as Mesh
+
+import types, sys
+
+#-------------------------------------------------------------
+
+class Test_Quad(unittest.TestCase):
+
+    def setUp(self):
+        self.cell = Cell(100, 140, 0, 40, 'cell')
+
+        a = [3, 107]
+        b = [5, 107]
+        c = [5, 105]
+        d = [7, 107]
+        e = [15, 115]
+        f = [15, 130]
+        g = [30, 110]
+        h = [30, 130]
+
+        points = [a, b, c, d, e, f, g, h]
+        #bac, bce, ecf, dbe, daf, dae
+        vertices = [[1,0,2], [1,3,4], [1,2,3], [5,4,7], [4,6,7]]
+
+	mesh = Mesh(points, vertices)
+        self.mesh = mesh
+        Cell.initialise(mesh)
+
+    def tearDown(self):
+        pass
+
+    def test_add_points_2_cell(self):
+        self.cell.insert(0)
+        self.cell.insert(1)
+
+        result = self.cell.retrieve()
+        assert type(result) in [types.ListType,types.TupleType],\
+                                'should be a list'
+        self.assertEqual(len(result),2)
+
+    def test_add_points_2_cellII(self):
+        self.cell.insert([0,1,2,3,4,5,6,7])
+
+        result = self.cell.retrieve()
+        assert type(result) in [types.ListType,types.TupleType],\
+	                        'should be a list'
+        self.assertEqual(len(result),8)
+
+
+    def test_search(self):
+        self.cell.insert([0,1,2,3,4,5,6,7])
+	self.cell.split(4)
+
+        result =  self.cell.search(x = 1, y = 101)
+        assert type(result) in [types.ListType,types.TupleType],\
+	                        'should be a list'
+        self.assertEqual(result, [0,1,2,3])
+
+
+    def test_clear_1(self):
+        self.cell.insert([0,1,2,3,4,5,6,7])
+	assert self.cell.count() == 8
+	self.cell.clear()
+
+        #This one actually revealed a bug :-)
+	assert self.cell.count() == 0
+
+    def test_clear_2(self):
+        self.cell.insert([0,1,2,3,4,5,6,7])
+	assert self.cell.count() == 8
+	self.cell.split(2)
+	assert self.cell.count() == 8
+
+	self.cell.clear()
+	assert self.cell.count() == 0
+
+
+
+    def test_split(self):
+        self.cell.insert([0,1,2,3,4,5,6,7], split = False)
+
+	#No children yet
+	assert self.cell.children is None
+	assert self.cell.count() == 8
+
+        #Split
+	self.cell.split(4)
+	#self.cell.show()
+	#self.cell.show_all()
+
+
+	#Now there are children
+	assert self.cell.children is not None
+	assert self.cell.count() == 8
+
+
+
+    def test_collapse(self):
+        self.cell.insert([0,1,2,3,4,5,6,7], split = False)
+
+        #Split maximally
+	self.cell.split(1)
+
+	#Now there are children
+	assert self.cell.children is not None
+	assert self.cell.count() == 8
+
+	#Collapse
+	self.cell.collapse(8)
+
+	#No children
+	assert self.cell.children is None
+	assert self.cell.count() == 8
+
+    def test_build_quadtree(self):
+
+        Q = build_quadtree(self.mesh)
+	assert Q.count() == 8
+
+        #Q.show()
+
+        result = Q.search(3, 105)
+        assert type(result) in [types.ListType,types.TupleType],\
+	                        'should be a list'
+        #print "result",result
+        self.assertEqual(result, [0,1,2,3])
+
+
+    def test_build_quadtreeII(self):
+
+        self.cell = Cell(100, 140, 0, 40, 'cell')
+
+        p0 = [34.6292076111,-7999.92529297]
+        p1 = [8000.0, 7999.0]
+        p2 = [-7999.96630859, 7999.0]
+        p3 = [34, 7999.97021484]
+
+        points = [p0,p1,p2, p3]
+        #bac, bce, ecf, dbe, daf, dae
+        vertices = [[0,1,2],[0,2,3]]
+
+	mesh = Mesh(points, vertices)
+
+        #This was causing round off error
+        Q = build_quadtree(mesh)
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+
+    mysuite = unittest.makeSuite(Test_Quad,'test')
+    runner = unittest.TextTestRunner()
+    runner.run(mysuite)
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_quantity.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_quantity.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_quantity.py	(revision 3560)
@@ -0,0 +1,1456 @@
+#!/usr/bin/env python
+
+import unittest
+from math import sqrt, pi
+
+
+from quantity import *
+from anuga.config import epsilon
+from Numeric import allclose, array, ones, Float
+
+from anuga.fit_interpolate.fit import fit_to_mesh
+#from anuga.pyvolution.least_squares import fit_to_mesh		
+from domain import Domain
+from anuga.geospatial_data.geospatial_data import Geospatial_data
+from anuga.coordinate_transforms.geo_reference import Geo_reference
+
+#Aux for fit_interpolate.fit example
+def linear_function(point):
+    point = array(point)
+    return point[:,0]+point[:,1]
+
+
+class Test_Quantity(unittest.TestCase):
+    def setUp(self):
+        from domain import Domain
+
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0, 0.0]
+        d = [0.0, 4.0]
+        e = [2.0, 2.0]
+        f = [4.0, 0.0]
+
+        points = [a, b, c, d, e, f]
+
+        #bac, bce, ecf, dbe
+        elements = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4] ]
+
+        self.mesh1 = Domain(points[:3], [elements[0]])
+        self.mesh1.check_integrity()
+
+        self.mesh4 = Domain(points, elements)
+        self.mesh4.check_integrity()
+
+    def tearDown(self):
+        pass
+        #print "  Tearing down"
+
+
+    def test_creation(self):
+
+        quantity = Quantity(self.mesh1, [[1,2,3]])
+        assert allclose(quantity.vertex_values, [[1.,2.,3.]])
+
+        try:
+            quantity = Quantity()
+        except:
+            pass
+        else:
+            raise 'Should have raised empty quantity exception'
+
+
+        try:
+            quantity = Quantity([1,2,3])
+        except AssertionError:
+            pass
+        except:
+            raise 'Should have raised "mising mesh object" error'
+
+
+    def test_creation_zeros(self):
+
+        quantity = Quantity(self.mesh1)
+        assert allclose(quantity.vertex_values, [[0.,0.,0.]])
+
+
+        quantity = Quantity(self.mesh4)
+        assert allclose(quantity.vertex_values, [[0.,0.,0.], [0.,0.,0.],
+                                                 [0.,0.,0.], [0.,0.,0.]])
+
+
+    def test_interpolation(self):
+        quantity = Quantity(self.mesh1, [[1,2,3]])
+        assert allclose(quantity.centroid_values, [2.0]) #Centroid
+
+        assert allclose(quantity.edge_values, [[2.5, 2.0, 1.5]])
+
+
+    def test_interpolation2(self):
+        quantity = Conserved_quantity(self.mesh4,
+                            [[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]])
+        assert allclose(quantity.centroid_values, [2., 5., 3., 0.]) #Centroid
+
+
+        quantity.extrapolate_second_order()
+
+        #print quantity.vertex_values
+        #assert allclose(quantity.vertex_values, [[2., 2., 2.],
+        #                                         [3.+2./3, 6.+2./3, 4.+2./3],
+        #                                         [7.5, 0.5, 1.],
+        #                                         [-5, -2.5, 7.5]])
+
+        assert allclose(quantity.vertex_values[1,:],[3.+2./3, 6.+2./3, 4.+2./3])
+        #FIXME: Work out the others
+
+
+        #print quantity.edge_values
+        assert allclose(quantity.edge_values, [[2.5, 2.0, 1.5],
+                                               [5., 5., 5.],
+                                               [4.5, 4.5, 0.],
+                                               [3.0, -1.5, -1.5]])
+
+    def test_boundary_allocation(self):
+        quantity = Conserved_quantity(self.mesh4,
+                            [[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]])
+
+        assert quantity.boundary_values.shape[0] == len(self.mesh4.boundary)
+
+
+    def test_set_values(self):
+        quantity = Quantity(self.mesh4)
+
+
+        quantity.set_values([[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]],
+                            location = 'vertices')
+        assert allclose(quantity.vertex_values,
+                        [[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]])
+        assert allclose(quantity.centroid_values, [2., 5., 3., 0.]) #Centroid
+        assert allclose(quantity.edge_values, [[2.5, 2.0, 1.5],
+                                               [5., 5., 5.],
+                                               [4.5, 4.5, 0.],
+                                               [3.0, -1.5, -1.5]])
+
+
+        #Test default
+        quantity.set_values([[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]])
+        assert allclose(quantity.vertex_values,
+                        [[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]])
+        assert allclose(quantity.centroid_values, [2., 5., 3., 0.]) #Centroid
+        assert allclose(quantity.edge_values, [[2.5, 2.0, 1.5],
+                                               [5., 5., 5.],
+                                               [4.5, 4.5, 0.],
+                                               [3.0, -1.5, -1.5]])
+
+        #Test centroids
+        quantity.set_values([1,2,3,4], location = 'centroids')
+        assert allclose(quantity.centroid_values, [1., 2., 3., 4.]) #Centroid
+
+        #Test edges
+        quantity.set_values([[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]],
+                            location = 'edges')
+        assert allclose(quantity.edge_values,
+                        [[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]])
+
+        #Test exceptions
+        try:
+            quantity.set_values([[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]],
+                                location = 'bas kamel tuba')
+        except:
+            pass
+
+
+        try:
+            quantity.set_values([[1,2,3], [0,0,9]])
+        except AssertionError:
+            pass
+        except:
+            raise 'should have raised Assertionerror'
+
+
+
+    def test_set_values_const(self):
+        quantity = Quantity(self.mesh4)
+
+        quantity.set_values(1.0, location = 'vertices')
+        assert allclose(quantity.vertex_values,
+                        [[1,1,1], [1,1,1], [1,1,1], [1, 1, 1]])
+
+        assert allclose(quantity.centroid_values, [1, 1, 1, 1]) #Centroid
+        assert allclose(quantity.edge_values, [[1, 1, 1],
+                                               [1, 1, 1],
+                                               [1, 1, 1],
+                                               [1, 1, 1]])
+
+
+        quantity.set_values(2.0, location = 'centroids')
+        assert allclose(quantity.centroid_values, [2, 2, 2, 2])
+
+        quantity.set_values(3.0, location = 'edges')
+        assert allclose(quantity.edge_values, [[3, 3, 3],
+                                               [3, 3, 3],
+                                               [3, 3, 3],
+                                               [3, 3, 3]])
+
+
+    def test_set_values_func(self):
+        quantity = Quantity(self.mesh4)
+
+        def f(x, y):
+            return x+y
+
+        quantity.set_values(f, location = 'vertices')
+        #print "quantity.vertex_values",quantity.vertex_values
+        assert allclose(quantity.vertex_values,
+                        [[2,0,2], [2,2,4], [4,2,4], [4,2,4]])
+        assert allclose(quantity.centroid_values,
+                        [4.0/3, 8.0/3, 10.0/3, 10.0/3])
+        assert allclose(quantity.edge_values,
+                        [[1,2,1], [3,3,2], [3,4,3], [3,4,3]])
+
+
+        quantity.set_values(f, location = 'centroids')
+        assert allclose(quantity.centroid_values,
+                        [4.0/3, 8.0/3, 10.0/3, 10.0/3])
+
+
+    def test_integral(self):
+        quantity = Quantity(self.mesh4)
+
+        #Try constants first
+        const = 5
+        quantity.set_values(const, location = 'vertices')
+        #print 'Q', quantity.get_integral()
+
+        assert allclose(quantity.get_integral(), self.mesh4.get_area() * const)
+
+        #Try with a linear function
+        def f(x, y):
+            return x+y
+
+        quantity.set_values(f, location = 'vertices')
+
+
+        ref_integral = (4.0/3 + 8.0/3 + 10.0/3 + 10.0/3) * 2
+
+        assert allclose (quantity.get_integral(), ref_integral)
+
+
+
+    def test_set_vertex_values(self):
+        quantity = Quantity(self.mesh4)
+        quantity.set_vertex_values([0,1,2,3,4,5])
+
+        assert allclose(quantity.vertex_values,
+                        [[1,0,2], [1,2,4], [4,2,5], [3,1,4]])
+        assert allclose(quantity.centroid_values,
+                        [1., 7./3, 11./3, 8./3]) #Centroid
+        assert allclose(quantity.edge_values, [[1., 1.5, 0.5],
+                                               [3., 2.5, 1.5],
+                                               [3.5, 4.5, 3.],
+                                               [2.5, 3.5, 2]])
+
+
+    def test_set_vertex_values_subset(self):
+        quantity = Quantity(self.mesh4)
+        quantity.set_vertex_values([0,1,2,3,4,5])
+        quantity.set_vertex_values([0,20,30,50], indices = [0,2,3,5])
+
+        assert allclose(quantity.vertex_values,
+                        [[1,0,20], [1,20,4], [4,20,50], [30,1,4]])
+
+
+    def test_set_vertex_values_using_general_interface(self):
+        quantity = Quantity(self.mesh4)
+
+
+        quantity.set_values([0,1,2,3,4,5])
+
+
+        assert allclose(quantity.vertex_values,
+                        [[1,0,2], [1,2,4], [4,2,5], [3,1,4]])
+
+        #Centroid
+        assert allclose(quantity.centroid_values, [1., 7./3, 11./3, 8./3])
+
+        assert allclose(quantity.edge_values, [[1., 1.5, 0.5],
+                                               [3., 2.5, 1.5],
+                                               [3.5, 4.5, 3.],
+                                               [2.5, 3.5, 2]])
+
+
+
+
+
+    def test_set_values_using_fit(self):
+
+
+        quantity = Quantity(self.mesh4)
+
+        #Get (enough) datapoints
+        data_points = [[ 0.66666667, 0.66666667],
+                       [ 1.33333333, 1.33333333],
+                       [ 2.66666667, 0.66666667],
+                       [ 0.66666667, 2.66666667],
+                       [ 0.0, 1.0],
+                       [ 0.0, 3.0],
+                       [ 1.0, 0.0],
+                       [ 1.0, 1.0],
+                       [ 1.0, 2.0],
+                       [ 1.0, 3.0],
+                       [ 2.0, 1.0],
+                       [ 3.0, 0.0],
+                       [ 3.0, 1.0]]
+
+        z = linear_function(data_points)
+
+        #Use built-in fit_interpolate.fit
+        quantity.set_values( Geospatial_data(data_points, z), alpha = 0 )
+        #quantity.set_values(points = data_points, values = z, alpha = 0)
+
+
+        answer = linear_function(quantity.domain.get_vertex_coordinates(obj = True))
+        #print quantity.vertex_values, answer
+        assert allclose(quantity.vertex_values.flat, answer)
+
+
+        #Now try by setting the same values directly
+        vertex_attributes = fit_to_mesh(quantity.domain.coordinates,
+                                        quantity.domain.triangles,
+                                        data_points,
+                                        z,
+                                        alpha = 0,
+                                        verbose=False)
+
+        #print vertex_attributes
+        quantity.set_values(vertex_attributes)
+        assert allclose(quantity.vertex_values.flat, answer)
+
+
+
+
+
+    def test_test_set_values_using_fit_w_geo(self):
+
+
+        #Mesh
+        vertex_coordinates = [[0.76, 0.76],
+                              [0.76, 5.76],
+                              [5.76, 0.76]]
+        triangles = [[0,2,1]]
+
+        mesh_georef = Geo_reference(56,-0.76,-0.76)
+        mesh1 = Domain(vertex_coordinates, triangles,
+                       geo_reference = mesh_georef)
+        mesh1.check_integrity()
+
+        #Quantity
+        quantity = Quantity(mesh1)
+
+        #Data
+        data_points = [[ 201.0, 401.0],
+                       [ 201.0, 403.0],
+                       [ 203.0, 401.0]]
+
+        z = [2, 4, 4]
+
+        data_georef = Geo_reference(56,-200,-400)
+
+
+        #Reference
+        ref = fit_to_mesh(vertex_coordinates, triangles, data_points, z,
+                          data_origin = data_georef.get_origin(),
+                          mesh_origin = mesh_georef.get_origin(),
+                          alpha = 0)
+
+        assert allclose( ref, [0,5,5] )
+
+
+        #Test set_values
+
+        quantity.set_values( Geospatial_data(data_points, z, data_georef), alpha = 0 )
+
+        #quantity.set_values(points = data_points,
+        #                    values = z,
+        #                    data_georef = data_georef,
+        #                    alpha = 0)
+
+
+        #quantity.set_values(points = data_points,
+        #                    values = z,
+        #                    data_georef = data_georef,
+        #                    alpha = 0)
+        assert allclose(quantity.vertex_values.flat, ref)
+
+
+
+        #Test set_values using geospatial data object
+        quantity.vertex_values[:] = 0.0
+
+        geo = Geospatial_data(data_points, z, data_georef)
+
+
+        quantity.set_values(geospatial_data = geo, alpha = 0)
+        assert allclose(quantity.vertex_values.flat, ref)
+
+
+
+    def test_set_values_from_file1(self):
+        quantity = Quantity(self.mesh4)
+
+        #Get (enough) datapoints
+        data_points = [[ 0.66666667, 0.66666667],
+                       [ 1.33333333, 1.33333333],
+                       [ 2.66666667, 0.66666667],
+                       [ 0.66666667, 2.66666667],
+                       [ 0.0, 1.0],
+                       [ 0.0, 3.0],
+                       [ 1.0, 0.0],
+                       [ 1.0, 1.0],
+                       [ 1.0, 2.0],
+                       [ 1.0, 3.0],
+                       [ 2.0, 1.0],
+                       [ 3.0, 0.0],
+                       [ 3.0, 1.0]]
+
+        z = linear_function(data_points)
+
+
+        #Create pts file
+        from load_mesh.loadASCII import export_points_file
+        ptsfile = 'testptsfile.pts'
+        att = 'spam_and_eggs'
+        points_dict = {'pointlist': data_points,
+                       'attributelist': {att: z}}
+
+        export_points_file(ptsfile, points_dict)
+
+        #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(obj = True))
+
+        #print quantity.vertex_values.flat
+        #print answer
+
+
+        assert allclose(quantity.vertex_values.flat, answer)
+
+
+        #Check that values can be set from file using default attribute
+        quantity.set_values(filename = ptsfile, alpha = 0)
+        assert allclose(quantity.vertex_values.flat, answer)
+
+        #Cleanup
+        import os
+        os.remove(ptsfile)
+
+
+    def test_set_values_from_file_with_georef1(self):
+
+        #Mesh in zone 56 (absolute coords)
+
+        x0 = 314036.58727982
+        y0 = 6224951.2960092
+
+        a = [x0+0.0, y0+0.0]
+        b = [x0+0.0, y0+2.0]
+        c = [x0+2.0, y0+0.0]
+        d = [x0+0.0, y0+4.0]
+        e = [x0+2.0, y0+2.0]
+        f = [x0+4.0, y0+0.0]
+
+        points = [a, b, c, d, e, f]
+
+        #bac, bce, ecf, dbe
+        elements = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4] ]
+
+        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 = [[ 0.66666667, 0.66666667],
+                       [ 1.33333333, 1.33333333],
+                       [ 2.66666667, 0.66666667],
+                       [ 0.66666667, 2.66666667],
+                       [ 0.0, 1.0],
+                       [ 0.0, 3.0],
+                       [ 1.0, 0.0],
+                       [ 1.0, 1.0],
+                       [ 1.0, 2.0],
+                       [ 1.0, 3.0],
+                       [ 2.0, 1.0],
+                       [ 3.0, 0.0],
+                       [ 3.0, 1.0]]
+
+        z = linear_function(data_points)
+
+
+        #Create pts file
+        from load_mesh.loadASCII import export_points_file
+
+        ptsfile = 'testptsfile.pts'
+        att = 'spam_and_eggs'
+
+        points_dict = {'pointlist': data_points,
+                       'attributelist': {att: z},
+                       'geo_reference': Geo_reference(zone = 56,
+                                                      xllcorner = x0,
+                                                      yllcorner = y0)}
+
+        export_points_file(ptsfile, points_dict)
+
+
+        #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(obj = True) - [x0, y0])
+
+        assert allclose(quantity.vertex_values.flat, answer)
+
+
+        #Check that values can be set from file using default attribute
+        quantity.set_values(filename = ptsfile, alpha = 0)
+        assert allclose(quantity.vertex_values.flat, answer)
+
+        #Cleanup
+        import os
+        os.remove(ptsfile)
+
+
+    def test_set_values_from_file_with_georef2(self):
+
+        #Mesh in zone 56 (relative coords)
+
+        x0 = 314036.58727982
+        y0 = 6224951.2960092
+
+        a = [0.0, 0.0]
+        b = [0.0, 2.0]
+        c = [2.0, 0.0]
+        d = [0.0, 4.0]
+        e = [2.0, 2.0]
+        f = [4.0, 0.0]
+
+        points = [a, b, c, d, e, f]
+
+        #bac, bce, ecf, dbe
+        elements = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4] ]
+
+        mesh4 = Domain(points, elements,
+                       geo_reference = Geo_reference(56, x0, y0))
+        mesh4.check_integrity()
+        quantity = Quantity(mesh4)
+
+        #Get (enough) datapoints (relative to georef)
+        data_points = [[ x0+0.66666667, y0+0.66666667],
+                       [ x0+1.33333333, y0+1.33333333],
+                       [ x0+2.66666667, y0+0.66666667],
+                       [ x0+0.66666667, y0+2.66666667],
+                       [ x0+0.0, y0+1.0],
+                       [ x0+0.0, y0+3.0],
+                       [ x0+1.0, y0+0.0],
+                       [ x0+1.0, y0+1.0],
+                       [ x0+1.0, y0+2.0],
+                       [ x0+1.0, y0+3.0],
+                       [ x0+2.0, y0+1.0],
+                       [ x0+3.0, y0+0.0],
+                       [ x0+3.0, y0+1.0]]
+
+        z = linear_function(data_points)
+
+
+        #Create pts file
+        from load_mesh.loadASCII import export_points_file
+
+        ptsfile = 'testptsfile.pts'
+        att = 'spam_and_eggs'
+
+        points_dict = {'pointlist': data_points,
+                       'attributelist': {att: z},
+                       'geo_reference': Geo_reference(zone = 56,
+                                                      xllcorner = 0,
+                                                      yllcorner = 0)}
+
+        export_points_file(ptsfile, points_dict)
+
+
+        #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(obj = True) + [x0, y0])
+
+
+        assert allclose(quantity.vertex_values.flat, answer)
+
+
+        #Check that values can be set from file using default attribute
+        quantity.set_values(filename = ptsfile, alpha = 0)
+        assert allclose(quantity.vertex_values.flat, answer)
+
+        #Cleanup
+        import os
+        os.remove(ptsfile)
+
+
+
+
+    def test_set_values_from_quantity(self):
+
+        quantity1 = Quantity(self.mesh4)
+        quantity1.set_vertex_values([0,1,2,3,4,5])
+
+        assert allclose(quantity1.vertex_values,
+                        [[1,0,2], [1,2,4], [4,2,5], [3,1,4]])
+
+
+        quantity2 = Quantity(self.mesh4)
+        quantity2.set_values(quantity = quantity1)
+        assert allclose(quantity2.vertex_values,
+                        [[1,0,2], [1,2,4], [4,2,5], [3,1,4]])
+
+        quantity2.set_values(quantity = 2*quantity1)
+        assert allclose(quantity2.vertex_values,
+                        [[2,0,4], [2,4,8], [8,4,10], [6,2,8]])
+
+        quantity2.set_values(quantity = 2*quantity1 + 3)
+        assert allclose(quantity2.vertex_values,
+                        [[5,3,7], [5,7,11], [11,7,13], [9,5,11]])
+
+
+        #Check detection of quantity as first orgument
+        quantity2.set_values(2*quantity1 + 3)
+        assert allclose(quantity2.vertex_values,
+                        [[5,3,7], [5,7,11], [11,7,13], [9,5,11]])
+
+
+
+
+
+    def test_overloading(self):
+
+        quantity1 = Quantity(self.mesh4)
+        quantity1.set_vertex_values([0,1,2,3,4,5])
+
+        assert allclose(quantity1.vertex_values,
+                        [[1,0,2], [1,2,4], [4,2,5], [3,1,4]])
+
+
+        quantity2 = Quantity(self.mesh4)
+        quantity2.set_values([[1,2,3], [5,5,5], [0,0,9], [-6, 3, 3]],
+                             location = 'vertices')
+
+
+
+        quantity3 = Quantity(self.mesh4)
+        quantity3.set_values([[2,2,2], [7,8,9], [7,6,3], [3, 8, -8]],
+                             location = 'vertices')
+
+
+        #Negation
+        Q = -quantity1
+        assert allclose(Q.vertex_values, -quantity1.vertex_values)
+        assert allclose(Q.centroid_values, -quantity1.centroid_values)
+        assert allclose(Q.edge_values, -quantity1.edge_values)
+
+        #Addition
+        Q = quantity1 + 7
+        assert allclose(Q.vertex_values, quantity1.vertex_values + 7)
+        assert allclose(Q.centroid_values, quantity1.centroid_values + 7)
+        assert allclose(Q.edge_values, quantity1.edge_values + 7)
+
+        Q = 7 + quantity1
+        assert allclose(Q.vertex_values, quantity1.vertex_values + 7)
+        assert allclose(Q.centroid_values, quantity1.centroid_values + 7)
+        assert allclose(Q.edge_values, quantity1.edge_values + 7)
+
+        Q = quantity1 + quantity2
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values + quantity2.vertex_values)
+        assert allclose(Q.centroid_values,
+                        quantity1.centroid_values + quantity2.centroid_values)
+        assert allclose(Q.edge_values,
+                        quantity1.edge_values + quantity2.edge_values)
+
+
+        Q = quantity1 + quantity2 - 3
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values + quantity2.vertex_values - 3)
+
+        Q = quantity1 - quantity2
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values - quantity2.vertex_values)
+
+        #Scaling
+        Q = quantity1*3
+        assert allclose(Q.vertex_values, quantity1.vertex_values*3)
+        assert allclose(Q.centroid_values, quantity1.centroid_values*3)
+        assert allclose(Q.edge_values, quantity1.edge_values*3)
+        Q = 3*quantity1
+        assert allclose(Q.vertex_values, quantity1.vertex_values*3)
+
+        #Multiplication
+        Q = quantity1 * quantity2
+        #print Q.vertex_values
+        #print Q.centroid_values
+        #print quantity1.centroid_values
+        #print quantity2.centroid_values
+
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values * quantity2.vertex_values)
+
+        #Linear combinations
+        Q = 4*quantity1 + 2
+        assert allclose(Q.vertex_values,
+                        4*quantity1.vertex_values + 2)
+
+        Q = quantity1*quantity2 + 2
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values * quantity2.vertex_values + 2)
+
+        Q = quantity1*quantity2 + quantity3
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values * quantity2.vertex_values +
+                        quantity3.vertex_values)
+        Q = quantity1*quantity2 + 3*quantity3
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values * quantity2.vertex_values +
+                        3*quantity3.vertex_values)
+        Q = quantity1*quantity2 + 3*quantity3 + 5.0
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values * quantity2.vertex_values +
+                        3*quantity3.vertex_values + 5)
+
+        Q = quantity1*quantity2 - quantity3
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values * quantity2.vertex_values -
+                        quantity3.vertex_values)
+        Q = 1.5*quantity1*quantity2 - 3*quantity3 + 5.0
+        assert allclose(Q.vertex_values,
+                        1.5*quantity1.vertex_values * quantity2.vertex_values -
+                        3*quantity3.vertex_values + 5)
+
+        #Try combining quantities and arrays and scalars
+        Q = 1.5*quantity1*quantity2.vertex_values -\
+            3*quantity3.vertex_values + 5.0
+        assert allclose(Q.vertex_values,
+                        1.5*quantity1.vertex_values * quantity2.vertex_values -
+                        3*quantity3.vertex_values + 5)
+
+
+        #Powers
+        Q = quantity1**2
+        assert allclose(Q.vertex_values, quantity1.vertex_values**2)
+
+        Q = quantity1**2 +quantity2**2
+        assert allclose(Q.vertex_values,
+                        quantity1.vertex_values**2 + \
+                        quantity2.vertex_values**2)
+
+        Q = (quantity1**2 +quantity2**2)**0.5
+        assert allclose(Q.vertex_values,
+                        (quantity1.vertex_values**2 + \
+                        quantity2.vertex_values**2)**0.5)
+
+
+
+
+
+
+
+    def test_gradient(self):
+        quantity = Conserved_quantity(self.mesh4)
+
+        #Set up for a gradient of (2,0) at mid triangle
+        quantity.set_values([2.0, 4.0, 6.0, 2.0],
+                            location = 'centroids')
+
+
+        #Gradients
+        a, b = quantity.compute_gradients()
+
+        #print self.mesh4.centroid_coordinates
+        #print a, b
+
+        #The central triangle (1)
+        #(using standard gradient based on neigbours controid values)
+        assert allclose(a[1], 2.0)
+        assert allclose(b[1], 0.0)
+
+
+        #Left triangle (0) using two point gradient
+        #q0 = q1 + a*(x0-x1) + b*(y0-y1)  <=>
+        #2  = 4  + a*(-2/3)  + b*(-2/3)
+        assert allclose(a[0] + b[0], 3)
+        #From orthogonality (a*(y0-y1) + b*(x0-x1) == 0)
+        assert allclose(a[0] - b[0], 0)
+
+
+        #Right triangle (2) using two point gradient
+        #q2 = q1 + a*(x2-x1) + b*(y2-y1)  <=>
+        #6  = 4  + a*(4/3)  + b*(-2/3)
+        assert allclose(2*a[2] - b[2], 3)
+        #From orthogonality (a*(y1-y2) + b*(x2-x1) == 0)
+        assert allclose(a[2] + 2*b[2], 0)
+
+
+        #Top triangle (3) using two point gradient
+        #q3 = q1 + a*(x3-x1) + b*(y3-y1)  <=>
+        #2  = 4  + a*(-2/3)  + b*(4/3)
+        assert allclose(a[3] - 2*b[3], 3)
+        #From orthogonality (a*(y1-y3) + b*(x3-x1) == 0)
+        assert allclose(2*a[3] + b[3], 0)
+
+
+
+        #print a, b
+        quantity.extrapolate_second_order()
+
+        #Apply q(x,y) = qc + a*(x-xc) + b*(y-yc)
+        assert allclose(quantity.vertex_values[0,:], [3., 0.,  3.])
+        assert allclose(quantity.vertex_values[1,:], [4./3, 16./3,  16./3])
+
+
+        #a = 1.2, b=-0.6
+        #q(4,0) = 6 + a*(4 - 8/3) + b*(-2/3)
+        assert allclose(quantity.vertex_values[2,2], 8)
+
+
+    def test_second_order_extrapolation2(self):
+        quantity = Conserved_quantity(self.mesh4)
+
+        #Set up for a gradient of (3,1), f(x) = 3x+y
+        quantity.set_values([2.0+2.0/3, 4.0+4.0/3, 8.0+2.0/3, 2.0+8.0/3],
+                            location = 'centroids')
+
+        #Gradients
+        a, b = quantity.compute_gradients()
+
+        #print a, b
+
+        assert allclose(a[1], 3.0)
+        assert allclose(b[1], 1.0)
+
+        #Work out the others
+
+        quantity.extrapolate_second_order()
+
+        #print quantity.vertex_values
+        assert allclose(quantity.vertex_values[1,0], 2.0)
+        assert allclose(quantity.vertex_values[1,1], 6.0)
+        assert allclose(quantity.vertex_values[1,2], 8.0)
+
+
+
+    def test_first_order_extrapolator(self):
+        quantity = Conserved_quantity(self.mesh4)
+
+        #Test centroids
+        quantity.set_values([1.,2.,3.,4.], location = 'centroids')
+        assert allclose(quantity.centroid_values, [1, 2, 3, 4]) #Centroid
+
+        #Extrapolate
+        quantity.extrapolate_first_order()
+
+        #Check vertices but not edge values
+        assert allclose(quantity.vertex_values,
+                        [[1,1,1], [2,2,2], [3,3,3], [4, 4, 4]])
+
+
+    def test_second_order_extrapolator(self):
+        quantity = Conserved_quantity(self.mesh4)
+
+        #Set up for a gradient of (3,0) at mid triangle
+        quantity.set_values([2.0, 4.0, 8.0, 2.0],
+                            location = 'centroids')
+
+
+
+        quantity.extrapolate_second_order()
+        quantity.limit()
+
+
+        #Assert that central triangle is limited by neighbours
+        assert quantity.vertex_values[1,0] >= quantity.vertex_values[0,0]
+        assert quantity.vertex_values[1,0] >= quantity.vertex_values[3,1]
+
+        assert quantity.vertex_values[1,1] <= quantity.vertex_values[2,1]
+        assert quantity.vertex_values[1,1] >= quantity.vertex_values[0,2]
+
+        assert quantity.vertex_values[1,2] <= quantity.vertex_values[2,0]
+        assert quantity.vertex_values[1,2] >= quantity.vertex_values[3,1]
+
+
+        #Assert that quantities are conserved
+        from Numeric import sum
+        for k in range(quantity.centroid_values.shape[0]):
+            assert allclose (quantity.centroid_values[k],
+                             sum(quantity.vertex_values[k,:])/3)
+
+
+
+
+
+    def test_limiter(self):
+        quantity = Conserved_quantity(self.mesh4)
+
+        #Create a deliberate overshoot (e.g. from gradient computation)
+        quantity.set_values([[3,0,3], [2,2,6], [5,3,8], [8,3,5]])
+
+
+        #Limit
+        quantity.limit()
+
+        #Assert that central triangle is limited by neighbours
+        assert quantity.vertex_values[1,0] >= quantity.vertex_values[0,0]
+        assert quantity.vertex_values[1,0] <= quantity.vertex_values[3,1]
+
+        assert quantity.vertex_values[1,1] <= quantity.vertex_values[2,1]
+        assert quantity.vertex_values[1,1] >= quantity.vertex_values[0,2]
+
+        assert quantity.vertex_values[1,2] <= quantity.vertex_values[2,0]
+        assert quantity.vertex_values[1,2] <= quantity.vertex_values[3,1]
+
+
+
+        #Assert that quantities are conserved
+        from Numeric import sum
+        for k in range(quantity.centroid_values.shape[0]):
+            assert allclose (quantity.centroid_values[k],
+                             sum(quantity.vertex_values[k,:])/3)
+
+
+    def test_limiter2(self):
+        """Taken from test_shallow_water
+        """
+        quantity = Conserved_quantity(self.mesh4)
+
+        #Test centroids
+        quantity.set_values([2.,4.,8.,2.], location = 'centroids')
+        assert allclose(quantity.centroid_values, [2, 4, 8, 2]) #Centroid
+
+
+        #Extrapolate
+        quantity.extrapolate_second_order()
+
+        assert allclose(quantity.vertex_values[1,:], [0.0, 6, 6])
+
+        #Limit
+        quantity.limit()
+
+
+        assert allclose(quantity.vertex_values[1,:], [2.2, 4.9, 4.9])
+
+
+        #Assert that quantities are conserved
+        from Numeric import sum
+        for k in range(quantity.centroid_values.shape[0]):
+            assert allclose (quantity.centroid_values[k],
+                             sum(quantity.vertex_values[k,:])/3)
+
+
+
+
+
+    def test_distribute_first_order(self):
+        quantity = Conserved_quantity(self.mesh4)
+
+        #Test centroids
+        quantity.set_values([1.,2.,3.,4.], location = 'centroids')
+        assert allclose(quantity.centroid_values, [1, 2, 3, 4]) #Centroid
+
+
+        #Extrapolate
+        quantity.extrapolate_first_order()
+
+        #Interpolate
+        quantity.interpolate_from_vertices_to_edges()
+
+        assert allclose(quantity.vertex_values,
+                        [[1,1,1], [2,2,2], [3,3,3], [4, 4, 4]])
+        assert allclose(quantity.edge_values, [[1,1,1], [2,2,2],
+                                               [3,3,3], [4, 4, 4]])
+
+
+    def test_distribute_second_order(self):
+        quantity = Conserved_quantity(self.mesh4)
+
+        #Test centroids
+        quantity.set_values([2.,4.,8.,2.], location = 'centroids')
+        assert allclose(quantity.centroid_values, [2, 4, 8, 2]) #Centroid
+
+
+        #Extrapolate
+        quantity.extrapolate_second_order()
+
+        assert allclose(quantity.vertex_values[1,:], [0.0, 6, 6])
+
+
+    def test_update_explicit(self):
+        quantity = Conserved_quantity(self.mesh4)
+
+        #Test centroids
+        quantity.set_values([1.,2.,3.,4.], location = 'centroids')
+        assert allclose(quantity.centroid_values, [1, 2, 3, 4]) #Centroid
+
+        #Set explicit_update
+        quantity.explicit_update = array( [1.,1.,1.,1.] )
+
+        #Update with given timestep
+        quantity.update(0.1)
+
+        x = array([1, 2, 3, 4]) + array( [.1,.1,.1,.1] )
+        assert allclose( quantity.centroid_values, x)
+
+    def test_update_semi_implicit(self):
+        quantity = Conserved_quantity(self.mesh4)
+
+        #Test centroids
+        quantity.set_values([1.,2.,3.,4.], location = 'centroids')
+        assert allclose(quantity.centroid_values, [1, 2, 3, 4]) #Centroid
+
+        #Set semi implicit update
+        quantity.semi_implicit_update = array([1.,1.,1.,1.])
+
+        #Update with given timestep
+        timestep = 0.1
+        quantity.update(timestep)
+
+        sem = array([1.,1.,1.,1.])/array([1, 2, 3, 4])
+        denom = ones(4, Float)-timestep*sem
+
+        x = array([1, 2, 3, 4])/denom
+        assert allclose( quantity.centroid_values, x)
+
+
+    def test_both_updates(self):
+        quantity = Conserved_quantity(self.mesh4)
+
+        #Test centroids
+        quantity.set_values([1.,2.,3.,4.], location = 'centroids')
+        assert allclose(quantity.centroid_values, [1, 2, 3, 4]) #Centroid
+
+        #Set explicit_update
+        quantity.explicit_update = array( [4.,3.,2.,1.] )
+
+        #Set semi implicit update
+        quantity.semi_implicit_update = array( [1.,1.,1.,1.] )
+
+        #Update with given timestep
+        timestep = 0.1
+        quantity.update(0.1)
+
+        sem = array([1.,1.,1.,1.])/array([1, 2, 3, 4])
+        denom = ones(4, Float)-timestep*sem
+
+        x = array([1., 2., 3., 4.])
+        x /= denom
+        x += timestep*array( [4.0, 3.0, 2.0, 1.0] )
+
+        assert allclose( quantity.centroid_values, x)
+
+
+
+
+    #Test smoothing
+    def test_smoothing(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Transmissive_boundary
+        from Numeric import zeros, Float
+        from anuga.utilities.numerical_tools import mean
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(2, 2)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.default_order=2
+        domain.reduction = mean
+
+
+        #Set some field values
+        domain.set_quantity('elevation', lambda x,y: x)
+        domain.set_quantity('friction', 0.03)
+
+
+        ######################
+        # Boundary conditions
+        B = Transmissive_boundary(domain)
+        domain.set_boundary( {'left': B, 'right': B, 'top': B, 'bottom': B})
+
+
+        ######################
+        #Initial condition - with jumps
+
+        bed = domain.quantities['elevation'].vertex_values
+        stage = zeros(bed.shape, Float)
+
+        h = 0.03
+        for i in range(stage.shape[0]):
+            if i % 2 == 0:
+                stage[i,:] = bed[i,:] + h
+            else:
+                stage[i,:] = bed[i,:]
+
+        domain.set_quantity('stage', stage)
+
+        stage = domain.quantities['stage']
+
+        #Get smoothed stage
+        A, V = stage.get_vertex_values(xy=False, smooth=True)
+        Q = stage.vertex_values
+
+
+	assert A.shape[0] == 9
+	assert V.shape[0] == 8
+	assert V.shape[1] == 3
+
+        #First four points
+        assert allclose(A[0], (Q[0,2] + Q[1,1])/2)
+        assert allclose(A[1], (Q[1,0] + Q[3,1] + Q[2,2])/3)
+        assert allclose(A[2], Q[3,0])
+        assert allclose(A[3], (Q[0,0] + Q[5,1] + Q[4,2])/3)
+
+        #Center point
+        assert allclose(A[4], (Q[0,1] + Q[1,2] + Q[2,0] +\
+                               Q[5,0] + Q[6,2] + Q[7,1])/6)
+
+
+        #Check V
+        assert allclose(V[0,:], [3,4,0])
+        assert allclose(V[1,:], [1,0,4])
+        assert allclose(V[2,:], [4,5,1])
+        assert allclose(V[3,:], [2,1,5])
+        assert allclose(V[4,:], [6,7,3])
+        assert allclose(V[5,:], [4,3,7])
+        assert allclose(V[6,:], [7,8,4])
+        assert allclose(V[7,:], [5,4,8])
+
+        #Get smoothed stage with XY
+        X, Y, A1, V1 = stage.get_vertex_values(xy=True, smooth=True)
+
+        assert allclose(A, A1)
+        assert allclose(V, V1)
+
+        #Check XY
+        assert allclose(X[4], 0.5)
+        assert allclose(Y[4], 0.5)
+
+        assert allclose(X[7], 1.0)
+        assert allclose(Y[7], 0.5)
+
+
+
+
+    def test_vertex_values_no_smoothing(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Transmissive_boundary
+        from Numeric import zeros, Float
+        from anuga.utilities.numerical_tools import mean
+
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(2, 2)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.default_order=2
+        domain.reduction = mean
+
+
+        #Set some field values
+        domain.set_quantity('elevation', lambda x,y: x)
+        domain.set_quantity('friction', 0.03)
+
+
+        ######################
+        #Initial condition - with jumps
+
+        bed = domain.quantities['elevation'].vertex_values
+        stage = zeros(bed.shape, Float)
+
+        h = 0.03
+        for i in range(stage.shape[0]):
+            if i % 2 == 0:
+                stage[i,:] = bed[i,:] + h
+            else:
+                stage[i,:] = bed[i,:]
+
+        domain.set_quantity('stage', stage)
+
+        #Get stage
+        stage = domain.quantities['stage']
+        A, V = stage.get_vertex_values(xy=False, smooth=False)
+        Q = stage.vertex_values.flat
+
+        for k in range(8):
+            assert allclose(A[k], Q[k])
+
+
+        for k in range(8):
+            assert V[k, 0] == 3*k
+            assert V[k, 1] == 3*k+1
+            assert V[k, 2] == 3*k+2
+
+
+
+        X, Y, A1, V1 = stage.get_vertex_values(xy=True, smooth=False)
+
+
+        assert allclose(A, A1)
+        assert allclose(V, V1)
+
+        #Check XY
+        assert allclose(X[1], 0.5)
+        assert allclose(Y[1], 0.5)
+        assert allclose(X[4], 0.0)
+        assert allclose(Y[4], 0.0)
+        assert allclose(X[12], 1.0)
+        assert allclose(Y[12], 0.0)
+
+
+
+    def set_array_values_by_index(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 1)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        #print "domain.number_of_elements ",domain.number_of_elements
+        quantity = Quantity(domain,[[1,1,1],[2,2,2]])
+        value = [7]
+        indices = [1]
+        quantity.set_array_values_by_index(value,
+                                           location = 'centroids',
+                                           indices = indices)
+        #print "quantity.centroid_values",quantity.centroid_values
+
+        assert allclose(quantity.centroid_values, [1,7])
+
+        quantity.set_array_values([15,20,25], indices = indices)
+        assert allclose(quantity.centroid_values, [1,20])
+
+        quantity.set_array_values([15,20,25], indices = indices)
+        assert allclose(quantity.centroid_values, [1,20])
+
+    def test_setting_some_vertex_values(self):
+        """
+        set values based on triangle lists.
+        """
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+        #print "vertices",vertices
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        #print "domain.number_of_elements ",domain.number_of_elements
+        quantity = Quantity(domain,[[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5],[6,6,6]])
+        value = [7]
+        indices = [1]
+        quantity.set_values(value,
+                            location = 'centroids',
+                            indices = indices)
+        #print "quantity.centroid_values",quantity.centroid_values
+        assert allclose(quantity.centroid_values, [1,7,3,4,5,6])
+
+        value = [[15,20,25]]
+        quantity.set_values(value, indices = indices)
+        #print "1 quantity.vertex_values",quantity.vertex_values
+        assert allclose(quantity.vertex_values[1], value[0])
+
+
+        #print "quantity",quantity.vertex_values
+        values = [10,100,50]
+        quantity.set_values(values, indices = [0,1,5], location = 'centroids')
+        #print "2 quantity.vertex_values",quantity.vertex_values
+        assert allclose(quantity.vertex_values[0], [10,10,10])
+        assert allclose(quantity.vertex_values[5], [50,50,50])
+        #quantity.interpolate()
+        #print "quantity.centroid_values",quantity.centroid_values
+        assert allclose(quantity.centroid_values, [10,100,3,4,5,50])
+
+
+        quantity = Quantity(domain,[[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5],[6,6,6]])
+        values = [10,100,50]
+        #this will be per unique vertex, indexing the vertices
+        #print "quantity.vertex_values",quantity.vertex_values
+        quantity.set_values(values, indices = [0,1,5])
+        #print "quantity.vertex_values",quantity.vertex_values
+        assert allclose(quantity.vertex_values[0], [1,50,10])
+        assert allclose(quantity.vertex_values[5], [6,6,6])
+        assert allclose(quantity.vertex_values[1], [100,10,50])
+
+        quantity = Quantity(domain,[[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5],[6,6,6]])
+        values = [[31,30,29],[400,400,400],[1000,999,998]]
+        quantity.set_values(values, indices = [3,3,5])
+        quantity.interpolate()
+        assert allclose(quantity.centroid_values, [1,2,3,400,5,999])
+
+        values = [[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5],[6,6,6]]
+        quantity.set_values(values)
+
+        # testing the standard set values by vertex
+        # indexed by vertex_id in general_mesh.coordinates
+        values = [0,1,2,3,4,5,6,7]
+
+        quantity.set_values(values)
+        #print "1 quantity.vertex_values",quantity.vertex_values
+        assert allclose(quantity.vertex_values,[[ 4.,  5.,  0.],
+                                                [ 1.,  0.,  5.],
+                                                [ 5.,  6.,  1.],
+                                                [ 2.,  1.,  6.],
+                                                [ 6.,  7.,  2.],
+                                                [ 3.,  2.,  7.]])
+
+    def test_setting_unique_vertex_values(self):
+        """
+        set values based on unique_vertex lists.
+        """
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+        #print "vertices",vertices
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        #print "domain.number_of_elements ",domain.number_of_elements
+        quantity = Quantity(domain,[[0,0,0],[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5]])
+        value = 7
+        indices = [1,5]
+        quantity.set_values(value,
+                            location = 'unique vertices',
+                            indices = indices)
+        #print "quantity.centroid_values",quantity.centroid_values
+        assert allclose(quantity.vertex_values[0], [0,7,0])
+        assert allclose(quantity.vertex_values[1], [7,1,7])
+        assert allclose(quantity.vertex_values[2], [7,2,7])
+
+
+    def test_get_values(self):
+        """
+        get values based on triangle lists.
+        """
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+
+        #print "points",points
+        #print "vertices",vertices
+        #print "boundary",boundary
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        #print "domain.number_of_elements ",domain.number_of_elements
+        quantity = Quantity(domain,[[0,0,0],[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5]])
+
+        #print "quantity.get_values(location = 'unique vertices')", \
+        #      quantity.get_values(location = 'unique vertices')
+
+        #print "quantity.get_values(location = 'unique vertices')", \
+        #      quantity.get_values(indices=[0,1,2,3,4,5,6,7], \
+        #                          location = 'unique vertices')
+
+        answer = [0.5,2,4,5,0,1,3,4.5]
+        assert allclose(answer,
+                        quantity.get_values(location = 'unique vertices'))
+
+        indices = [0,5,3]
+        answer = [0.5,1,5]
+        assert allclose(answer,
+                        quantity.get_values(indices=indices, \
+                                            location = 'unique vertices'))
+        #print "quantity.centroid_values",quantity.centroid_values
+        #print "quantity.get_values(location = 'centroids') ",\
+        #      quantity.get_values(location = 'centroids')
+
+    def test_getting_some_vertex_values(self):
+        """
+        get values based on triangle lists.
+        """
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+
+        #print "points",points
+        #print "vertices",vertices
+        #print "boundary",boundary
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        #print "domain.number_of_elements ",domain.number_of_elements
+        quantity = Quantity(domain,[[1,1,1],[2,2,2],[3,3,3],
+                                    [4,4,4],[5,5,5],[6,6,6]])
+        value = [7]
+        indices = [1]
+        quantity.set_values(value,
+                            location = 'centroids',
+                            indices = indices)
+        #print "quantity.centroid_values",quantity.centroid_values
+        #print "quantity.get_values(location = 'centroids') ",\
+        #      quantity.get_values(location = 'centroids')
+        assert allclose(quantity.centroid_values,
+                        quantity.get_values(location = 'centroids'))
+
+
+        value = [[15,20,25]]
+        quantity.set_values(value, indices = indices)
+        #print "1 quantity.vertex_values",quantity.vertex_values
+        assert allclose(quantity.vertex_values, quantity.get_values())
+
+        assert allclose(quantity.edge_values,
+                        quantity.get_values(location = 'edges'))
+
+        # get a subset of elements
+        subset = quantity.get_values(location='centroids', indices=[0,5])
+        answer = [quantity.centroid_values[0],quantity.centroid_values[5]]
+        assert allclose(subset, answer)
+
+
+        subset = quantity.get_values(location='edges', indices=[0,5])
+        answer = [quantity.edge_values[0],quantity.edge_values[5]]
+        #print "subset",subset
+        #print "answer",answer
+        assert allclose(subset, answer)
+
+        subset = quantity.get_values( indices=[1,5])
+        answer = [quantity.vertex_values[1],quantity.vertex_values[5]]
+        #print "subset",subset
+        #print "answer",answer
+        assert allclose(subset, answer)
+
+
+
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_Quantity, 'test')
+    #print "restricted test"
+    #suite = unittest.makeSuite(Test_Quantity,'test_set_values_func')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_region.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_region.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_region.py	(revision 3560)
@@ -0,0 +1,180 @@
+#!/usr/bin/env python
+
+import unittest
+from math import sqrt
+
+from domain import *
+from region import *
+#from anuga.config import epsilon
+from Numeric import allclose #, array, ones, Float
+
+
+def add_x_y(x, y):
+    return x+y
+
+def give_me_23(x, y):
+    return 23.0
+
+class Test_Region(unittest.TestCase):
+    def setUp(self):
+        pass
+
+
+    def tearDown(self):
+        pass
+
+
+    def test_region_tags(self):
+        """
+        get values based on triangle lists.
+        """
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.build_tagged_elements_dictionary({'bottom':[0,1],
+                                                 'top':[4,5],
+                                                 'all':[0,1,2,3,4,5]})
+
+
+        #Set friction
+        manning = 0.07
+        domain.set_quantity('friction', manning)
+
+        a = Set_region('bottom', 'friction', 0.09)
+        b = Set_region('top', 'friction', 1.0)
+        domain.set_region([a, b])
+        #print domain.quantities['friction'].get_values()
+        assert allclose(domain.quantities['friction'].get_values(),\
+                        [[ 0.09,  0.09,  0.09],
+                         [ 0.09,  0.09,  0.09],
+                         [ 0.07,  0.07,  0.07],
+                         [ 0.07,  0.07,  0.07],
+                         [ 1.0,  1.0,  1.0],
+                         [ 1.0,  1.0,  1.0]])
+
+        #c = Add_Value_To_region('all', 'friction', 10.0)
+        domain.set_region(Add_value_to_region('all', 'friction', 10.0))
+        #print domain.quantities['friction'].get_values()
+        assert allclose(domain.quantities['friction'].get_values(),
+                        [[ 10.09, 10.09, 10.09],
+                         [ 10.09, 10.09, 10.09],
+                         [ 10.07, 10.07, 10.07],
+                         [ 10.07, 10.07, 10.07],
+                         [ 11.0,  11.0,  11.0],
+                         [ 11.0,  11.0,  11.0]])
+
+        # trying a function
+        domain.set_region(Set_region('top', 'friction', add_x_y))
+        #print domain.quantities['friction'].get_values()
+        assert allclose(domain.quantities['friction'].get_values(),
+                        [[ 10.09, 10.09, 10.09],
+                         [ 10.09, 10.09, 10.09],
+                         [ 10.07, 10.07, 10.07],
+                         [ 10.07, 10.07, 10.07],
+                         [ 5./3,  2.0,  2./3],
+                         [ 1.0,  2./3,  2.0]])
+
+        domain.set_quantity('elevation', 10.0)
+        domain.set_quantity('stage', 10.0)
+        domain.set_region(Add_value_to_region('top', 'stage', 1.0,initial_quantity='elevation'))
+        #print domain.quantities['stage'].get_values()
+        assert allclose(domain.quantities['stage'].get_values(),
+                        [[ 10., 10., 10.],
+                         [ 10., 10., 10.],
+                         [ 10., 10., 10.],
+                         [ 10., 10., 10.],
+                         [ 11.0,  11.0,  11.0],
+                         [ 11.0,  11.0,  11.0]])
+
+        
+        domain.set_quantity('elevation', 10.0)
+        domain.set_quantity('stage', give_me_23)
+        #this works as well, (is cleaner, but doesn't work for regions)
+        #domain.set_quantity('stage',
+        #                    domain.quantities['stage'].vertex_values+ \
+        #                    domain.quantities['elevation'].vertex_values)
+        domain.set_region(Add_quantities('top', 'elevation','stage'))
+        #print domain.quantities['stage'].get_values()
+        assert allclose(domain.quantities['elevation'].get_values(),
+                        [[ 10., 10., 10.],
+                         [ 10., 10., 10.],
+                         [ 10., 10., 10.],
+                         [ 10., 10., 10.],
+                         [ 33.,  33.0,  33.],
+                         [ 33.0,  33.,  33.]])
+        
+    def test_unique_vertices(self):
+        """
+        get values based on triangle lists.
+        """
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.build_tagged_elements_dictionary({'bottom':[0,1],
+                                                 'top':[4,5],
+                                                 'all':[0,1,2,3,4,5]})
+
+        #Set friction
+        manning = 0.07
+        domain.set_quantity('friction', manning)
+
+        a = Set_region('bottom', 'friction', 0.09, location = 'unique vertices')
+        domain.set_region(a)
+        #print domain.quantities['friction'].get_values()
+        assert allclose(domain.quantities['friction'].get_values(),\
+                        [[ 0.09,  0.09,  0.09],
+                         [ 0.09,  0.09,  0.09],
+                         [ 0.09,  0.07,  0.09],
+                         [ 0.07,  0.09,  0.07],
+                         [ 0.07,  0.07,  0.07],
+                         [ 0.07,  0.07,  0.07]])
+
+
+    def test_unique_verticesII(self):
+        """
+        get values based on triangle lists.
+        """
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        from Numeric import zeros, Float
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(1, 3)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.build_tagged_elements_dictionary({'bottom':[0,1],
+                                                 'top':[4,5],
+                                                 'all':[0,1,2,3,4,5]})
+
+        #Set friction
+        manning = 0.07
+        domain.set_quantity('friction', manning)
+
+        domain.set_region(Add_value_to_region('bottom', 'friction', 1.0,initial_quantity='friction', location = 'unique vertices'))
+
+        #print domain.quantities['friction'].get_values()
+        assert allclose(domain.quantities['friction'].get_values(),\
+                        [[ 1.07,  1.07,  1.07],
+                         [ 1.07,  1.07,  1.07],
+                         [ 1.07,  0.07,  1.07],
+                         [ 0.07,  1.07,  0.07],
+                         [ 0.07,  0.07,  0.07],
+                         [ 0.07,  0.07,  0.07]])
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_Region,'test')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_shallow_water.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_shallow_water.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_shallow_water.py	(revision 3560)
@@ -0,0 +1,3439 @@
+#!/usr/bin/env python
+
+import unittest, os
+from math import sqrt, pi
+
+from anuga.config import g, epsilon
+from Numeric import allclose, array, zeros, ones, Float, take
+from anuga.utilities.numerical_tools import mean
+
+from shallow_water import *
+
+
+
+#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 sqrt, exp, cos, pi
+
+    x = array(x)
+    y = array(y)
+
+    N = len(x)
+    s = 0*x  #New array
+
+    for k in range(N):
+
+        r = 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 angle(t,x,y):
+    """Rotating field
+    """
+    from math import sqrt, atan, pi
+
+    x = array(x)
+    y = array(y)
+
+    N = len(x)
+    a = 0*x  #New array
+
+    for k in range(N):
+        r = sqrt(x[k]**2 + y[k]**2)
+
+        angle = atan(y[k]/x[k])
+
+        if x[k] < 0:
+            angle+=pi #atan in ]-pi/2; pi/2[
+
+        #Take normal direction
+        angle -= pi/2
+
+        #Ensure positive radians
+        if angle < 0:
+            angle += 2*pi
+
+        a[k] = angle/pi*180
+
+    return a
+
+
+class Test_Shallow_Water(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_rotate(self):
+        normal = array([0.0,-1.0])
+
+        q = 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 allclose(w, q)
+
+        #Check error check
+        try:
+            rotate(r, array([1,1,1]) )
+        except:
+            pass
+        else:
+            raise 'Should have raised an exception'
+
+    def test_flux_zero_case(self):
+        ql = zeros( 3, Float )
+        qr = zeros( 3, Float )
+        normal = zeros( 2, Float )
+        zl = zr = 0.
+        flux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        assert allclose(flux, [0,0,0])
+        assert max_speed == 0.
+
+    def test_flux_constants(self):
+        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_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 = array([1.,0])
+        ql = array([-0.2, 2, 3])
+        qr = array([-0.2, 2, 3])
+        zl = zr = -0.5
+        flux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        assert allclose(flux, [2.,13.77433333, 20.])
+        assert allclose(max_speed, 8.38130948661)
+
+
+    def test_flux2(self):
+        #Use data from previous version of abstract_2d_finite_volumes
+        normal = array([0., -1.])
+        ql = array([-0.075, 2, 3])
+        qr = array([-0.075, 2, 3])
+        zl = zr = -0.375
+        flux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        assert allclose(flux, [-3.,-20.0, -30.441])
+        assert allclose(max_speed, 11.7146428199)
+
+    def test_flux3(self):
+        #Use data from previous version of abstract_2d_finite_volumes
+        normal = array([-sqrt(2)/2, sqrt(2)/2])
+        ql = array([-0.075, 2, 3])
+        qr = array([-0.075, 2, 3])
+        zl = zr = -0.375
+        flux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        assert allclose(flux, [sqrt(2)/2, 4.40221112, 7.3829019])
+        assert allclose(max_speed, 4.0716654239)
+
+    def test_flux4(self):
+        #Use data from previous version of abstract_2d_finite_volumes
+        normal = array([-sqrt(2)/2, sqrt(2)/2])
+        ql = array([-0.34319278, 0.10254161, 0.07273855])
+        qr = array([-0.30683287, 0.1071986, 0.05930515])
+        zl = zr = -0.375
+        flux, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        assert allclose(flux, [-0.04072676, -0.07096636, -0.01604364])
+        assert allclose(max_speed, 1.31414103233)
+
+    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, daf, dae
+        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
+
+        domain = Domain(points, vertices)
+        domain.check_integrity()
+
+        for name in ['stage', 'xmomentum', 'ymomentum',
+                     'elevation', 'friction']:
+            assert domain.quantities.has_key(name)
+
+
+        assert domain.get_conserved_quantities(0, edge=1) == 0.
+
+
+    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 = Dirichlet_boundary([5,2,1])
+        T = Transmissive_boundary(domain)
+        R = Reflective_boundary(domain)
+        domain.set_boundary( {'First': D, 'Second': T, 'Third': R})
+
+        domain.update_boundary()
+
+        #Stage
+        assert domain.quantities['stage'].boundary_values[0] == 2.5
+        assert domain.quantities['stage'].boundary_values[0] ==\
+               domain.get_conserved_quantities(0, edge=0)[0] #Reflective (2.5)
+        assert domain.quantities['stage'].boundary_values[1] == 5. #Dirichlet
+        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 (4.5)
+        assert domain.quantities['stage'].boundary_values[4] ==\
+               domain.get_conserved_quantities(3, edge=1)[0] #Transmissive (-1.5)
+        assert domain.quantities['stage'].boundary_values[5] ==\
+               domain.get_conserved_quantities(3, edge=2)[0] #Reflective (-1.5)
+
+        #Xmomentum
+        assert domain.quantities['xmomentum'].boundary_values[0] == 1.0 #Reflective
+        assert domain.quantities['xmomentum'].boundary_values[1] == 2. #Dirichlet
+        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] #Transmissive
+        assert domain.quantities['xmomentum'].boundary_values[5] == -4.0  #Reflective
+
+        #Ymomentum
+        assert domain.quantities['ymomentum'].boundary_values[0] == -10.0 #Reflective
+        assert domain.quantities['ymomentum'].boundary_values[1] == 1.  #Dirichlet
+        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. #Transmissive
+        assert domain.quantities['ymomentum'].boundary_values[5] == 40. #Reflective
+
+
+    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'}
+
+
+        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 = Dirichlet_boundary([5,2,1])
+        T = Transmissive_boundary(domain)
+        R = Reflective_boundary(domain)
+        domain.set_boundary( {'First': D, 'Second': T,
+                              'Third': R, 'Internal': None})
+
+        domain.update_boundary()
+        domain.check_integrity()
+
+
+    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()
+
+        assert allclose(domain.neighbours, [[-1,1,-1], [2,3,0], [-1,-1,1],[1,-1,-1]])
+        assert allclose(domain.neighbour_edges, [[-1,2,-1], [2,0,1], [-1,-1,0],[1,-1,-1]])
+
+        zl=zr=0. #Assume flat bed
+
+        #Flux across right edge of volume 1
+        normal = domain.get_normal(1,0)
+        ql = domain.get_conserved_quantities(vol_id=1, edge=0)
+        qr = domain.get_conserved_quantities(vol_id=2, edge=2)
+        flux0, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        #Check that flux seen from other triangles is inverse
+        tmp = qr; qr=ql; ql=tmp
+        normal = domain.get_normal(2,2)
+        flux, max_speed = flux_function(normal, ql, qr, zl, zr)
+        assert allclose(flux + flux0, 0.)
+
+        #Flux across upper edge of volume 1
+        normal = domain.get_normal(1,1)
+        ql = domain.get_conserved_quantities(vol_id=1, edge=1)
+        qr = domain.get_conserved_quantities(vol_id=3, edge=0)
+        flux1, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        #Check that flux seen from other triangles is inverse
+        tmp = qr; qr=ql; ql=tmp
+        normal = domain.get_normal(3,0)
+        flux, max_speed = flux_function(normal, ql, qr, zl, zr)
+        assert allclose(flux + flux1, 0.)
+
+        #Flux across lower left hypotenuse of volume 1
+        normal = domain.get_normal(1,2)
+        ql = domain.get_conserved_quantities(vol_id=1, edge=2)
+        qr = domain.get_conserved_quantities(vol_id=0, edge=1)
+        flux2, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        #Check that flux seen from other triangles is inverse
+        tmp = qr; qr=ql; ql=tmp
+        normal = domain.get_normal(0,1)
+        flux, max_speed = flux_function(normal, ql, qr, zl, zr)
+        assert allclose(flux + flux2, 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 allclose(e0*flux0+e1*flux1+e2*flux2, 0.)
+
+        #Now check that compute_flux yields zeros as well
+        domain.compute_fluxes()
+
+        for name in ['stage', 'xmomentum', 'ymomentum']:
+            #print name, domain.quantities[name].explicit_update
+            assert allclose(domain.quantities[name].explicit_update[1], 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()
+
+        zl=zr=0. #Assume flat bed
+
+        #Flux across right edge of volume 1
+        normal = domain.get_normal(1,0) #Get normal 0 of triangle 1
+        assert allclose(normal, [1, 0])
+        
+        ql = domain.get_conserved_quantities(vol_id=1, edge=0)
+        assert allclose(ql, [val1, 0, 0])
+        
+        qr = domain.get_conserved_quantities(vol_id=2, edge=2)
+        assert allclose(qr, [val2, 0, 0])
+        
+        flux0, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        #Flux across edge in the east direction (as per normal vector)
+        assert allclose(flux0, [-15.3598804, 253.71111111, 0.])
+        assert allclose(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 allclose(normal_opposite, [-1, 0])
+        flux_opposite, max_speed = flux_function([-1, 0], ql, qr, zl, zr)
+        assert allclose(flux_opposite, [-15.3598804, -253.71111111, 0.])
+        
+
+        #Flux across upper edge of volume 1
+        normal = domain.get_normal(1,1)
+        ql = domain.get_conserved_quantities(vol_id=1, edge=1)
+        qr = domain.get_conserved_quantities(vol_id=3, edge=0)
+        flux1, max_speed = flux_function(normal, ql, qr, zl, zr)
+        assert allclose(flux1, [2.4098563, 0., 123.04444444])
+        assert allclose(max_speed, 7.22956891292)
+
+        #Flux across lower left hypotenuse of volume 1
+        normal = domain.get_normal(1,2)
+        ql = domain.get_conserved_quantities(vol_id=1, edge=2)
+        qr = domain.get_conserved_quantities(vol_id=0, edge=1)
+        flux2, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        assert allclose(flux2, [9.63942522, -61.59685738, -61.59685738])
+        assert 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*flux0+e1*flux1+e2*flux2)/domain.areas[1]
+        assert allclose(total_flux, [-0.68218178, -166.6, -35.93333333])
+
+
+        domain.compute_fluxes()
+
+        #assert allclose(total_flux, domain.explicit_update[1,:])
+        for i, name in enumerate(['stage', 'xmomentum', 'ymomentum']):
+            assert allclose(total_flux[i],
+                            domain.quantities[name].explicit_update[1])
+
+        #assert allclose(domain.explicit_update, [
+        #    [0., -69.68888889, -69.68888889],
+        #    [-0.68218178, -166.6, -35.93333333],
+        #    [-111.77316251, 69.68888889, 0.],
+        #    [-35.68522449, 0., 69.68888889]])
+
+        assert allclose(domain.quantities['stage'].explicit_update,
+                        [0., -0.68218178, -111.77316251, -35.68522449])
+        assert allclose(domain.quantities['xmomentum'].explicit_update,
+                        [-69.68888889, -166.6, 69.68888889, 0])
+        assert allclose(domain.quantities['ymomentum'].explicit_update,
+                        [-69.68888889, -35.93333333, 0., 69.68888889])
+
+
+        #assert allclose(domain.quantities[name].explicit_update
+
+
+
+
+
+    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)
+        val0 = 2.+2.0/3
+        val1 = 4.+4.0/3
+        val2 = 8.+2.0/3
+        val3 = 2.+8.0/3
+
+        zl=zr=0 #Assume flat zero bed
+
+        domain.set_quantity('elevation', zl*ones( (4,3) ))
+
+
+        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()
+
+
+
+        #Flux across right edge of volume 1
+        normal = domain.get_normal(1,0)
+        ql = domain.get_conserved_quantities(vol_id=1, edge=0)
+        qr = domain.get_conserved_quantities(vol_id=2, edge=2)
+        flux0, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        #Flux across upper edge of volume 1
+        normal = domain.get_normal(1,1)
+        ql = domain.get_conserved_quantities(vol_id=1, edge=1)
+        qr = domain.get_conserved_quantities(vol_id=3, edge=0)
+        flux1, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        #Flux across lower left hypotenuse of volume 1
+        normal = domain.get_normal(1,2)
+        ql = domain.get_conserved_quantities(vol_id=1, edge=2)
+        qr = domain.get_conserved_quantities(vol_id=0, edge=1)
+        flux2, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        #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*flux0+e1*flux1+e2*flux2)/domain.areas[1]
+
+
+        domain.compute_fluxes()
+        for i, name in enumerate(['stage', 'xmomentum', 'ymomentum']):
+            assert allclose(total_flux[i],
+                            domain.quantities[name].explicit_update[1])
+        #assert allclose(total_flux, domain.explicit_update[1,:])
+
+
+    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)
+        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*ones( (4,3) ))
+
+
+        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()
+
+
+
+        #Flux across right edge of volume 1
+        normal = domain.get_normal(1,0)
+        ql = domain.get_conserved_quantities(vol_id=1, edge=0)
+        qr = domain.get_conserved_quantities(vol_id=2, edge=2)
+        flux0, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        #Flux across upper edge of volume 1
+        normal = domain.get_normal(1,1)
+        ql = domain.get_conserved_quantities(vol_id=1, edge=1)
+        qr = domain.get_conserved_quantities(vol_id=3, edge=0)
+        flux1, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        #Flux across lower left hypotenuse of volume 1
+        normal = domain.get_normal(1,2)
+        ql = domain.get_conserved_quantities(vol_id=1, edge=2)
+        qr = domain.get_conserved_quantities(vol_id=0, edge=1)
+        flux2, max_speed = flux_function(normal, ql, qr, zl, zr)
+
+        #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*flux0+e1*flux1+e2*flux2)/domain.areas[1]
+
+        domain.compute_fluxes()
+        for i, name in enumerate(['stage', 'xmomentum', 'ymomentum']):
+            assert allclose(total_flux[i],
+                            domain.quantities[name].explicit_update[1])
+
+
+
+    def test_catching_negative_heights(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=4  #Too large
+        domain.set_quantity('elevation', zl*ones( (4,3) ))
+        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_initial_condition(self):
+        """Test that initial condition is output at time == 0
+        """
+
+        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 = Domain(points, vertices)
+
+        #Set up for a gradient of (3,0) at mid triangle
+        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)
+
+        initial_stage = copy.copy(domain.quantities['stage'].vertex_values)
+
+        domain.set_boundary({'exterior': Reflective_boundary(domain)})
+
+        #Evolution
+        for t in domain.evolve(yieldstep = 1.0, finaltime = 2.0):
+            stage = domain.quantities['stage'].vertex_values
+
+            if t == 0.0:
+                assert allclose(stage, initial_stage)
+            else:
+                assert not allclose(stage, initial_stage)
+
+        os.remove(domain.filename + '.sww')
+
+
+
+    #####################################################
+    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
+        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 allclose(domain.quantities[name].explicit_update, 0)
+            assert allclose(domain.quantities[name].semi_implicit_update, 0)
+
+        domain.compute_forcing_terms()
+
+        assert allclose(domain.quantities['stage'].explicit_update, 0)
+        assert allclose(domain.quantities['xmomentum'].explicit_update, -g*h*3)
+        assert 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
+        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 allclose(domain.quantities[name].explicit_update, 0)
+            assert allclose(domain.quantities[name].semi_implicit_update, 0)
+
+        domain.compute_forcing_terms()
+
+        assert allclose(domain.quantities['stage'].explicit_update, 0)
+        assert allclose(domain.quantities['xmomentum'].explicit_update, -g*h*3)
+        assert allclose(domain.quantities['ymomentum'].explicit_update, 0)
+
+        assert allclose(domain.quantities['stage'].semi_implicit_update, 0)
+        assert allclose(domain.quantities['xmomentum'].semi_implicit_update, 0)
+        assert 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 allclose(domain.quantities['stage'].semi_implicit_update, 0)
+        assert allclose(domain.quantities['xmomentum'].semi_implicit_update, S)
+        assert 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 allclose(domain.quantities['stage'].semi_implicit_update, 0)
+        assert allclose(domain.quantities['xmomentum'].semi_implicit_update, 3*S)
+        assert 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, sqrt
+
+        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 = 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( 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 * sqrt(u**2 + v**2)
+
+        assert allclose(domain.quantities['stage'].explicit_update, 0)
+        assert allclose(domain.quantities['xmomentum'].explicit_update, S*u)
+        assert 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, sqrt
+
+        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 = 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( Wind_stress(s = speed, phi = angle) )
+
+        domain.compute_forcing_terms()
+
+        #Compute reference solution
+        const = eta_w*rho_a/rho_w
+
+        N = domain.number_of_elements
+
+        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 * sqrt(u**2 + v**2)
+
+            assert allclose(domain.quantities['stage'].explicit_update[k], 0)
+            assert allclose(domain.quantities['xmomentum'].explicit_update[k], S*u)
+            assert allclose(domain.quantities['ymomentum'].explicit_update[k], S*v)
+
+
+
+
+    def test_windfield_from_file(self):
+        from anuga.config import rho_a, rho_w, eta_w
+        from math import pi, cos, sin, sqrt
+        from anuga.config import time_format
+        from anuga.abstract_2d_finite_volumes.util import file_function
+        import time
+
+
+        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 = 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()
+
+
+        #Convert ASCII file to NetCDF (Which is what we really like!)
+        from anuga.abstract_2d_finite_volumes.data_manager import timefile2netcdf        
+        timefile2netcdf(filename)
+        os.remove(filename + '.txt')
+
+        
+        #Setup wind stress
+        F = file_function(filename + '.tms', quantities = ['Attribute0',
+                                                           'Attribute1'])
+        os.remove(filename + '.tms')
+        
+
+        #print 'F(5)', F(5)
+
+        #print 'F(5,x,y)', F(5,x=zeros(3),y=zeros(3))
+        
+        #print dir(F)
+        #print F.T
+        #print F.precomputed_values
+        #
+        #F = file_function(filename + '.txt')        
+        #
+        #print dir(F)
+        #print F.T        
+        #print F.Q
+        
+        W = 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 = domain.number_of_elements
+
+        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 * sqrt(u**2 + v**2)
+
+        for k in range(N):
+            assert allclose(domain.quantities['stage'].explicit_update[k], 0)
+            assert allclose(domain.quantities['xmomentum'].explicit_update[k], S*u)
+            assert 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 anuga.config import rho_a, rho_w, eta_w
+        from math import pi, cos, sin, sqrt
+
+        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 = 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(Wind_stress(s = scalar_func,
+                                                    phi = angle))
+        except AssertionError:
+            pass
+        else:
+            msg = 'Should have raised exception'
+            raise msg
+
+
+        try:
+            domain.forcing_terms.append(Wind_stress(s = speed,
+                                                    phi = scalar_func))
+        except AssertionError:
+            pass
+        else:
+            msg = 'Should have raised exception'
+            raise msg
+
+        try:
+            domain.forcing_terms.append(Wind_stress(s = speed,
+                                                    phi = 'xx'))
+        except:
+            pass
+        else:
+            msg = 'Should have raised exception'
+            raise msg
+
+
+    #####################################################
+    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*ones( (4,3) ))
+        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 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 Numeric import alltrue, greater_equal
+        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 alltrue(alltrue(greater_equal(L,E-epsilon)))
+
+        domain.order = 1
+        domain.distribute_to_vertices_and_edges()
+
+        #Check that all stages are above elevation (within eps)
+        assert alltrue(alltrue(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.order = 1
+        domain.distribute_to_vertices_and_edges()
+	assert allclose(L[1], val1)
+
+	#Second order
+        domain.order = 2
+        domain.distribute_to_vertices_and_edges()
+	assert allclose(L[1], [2.2, 4.9, 4.9])
+
+
+
+    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')
+
+        a, b = domain.quantities['stage'].compute_gradients()
+	assert allclose(a[1], 3.33333334)
+	assert allclose(b[1], 0.0)
+
+        domain.order = 1
+        domain.distribute_to_vertices_and_edges()
+        assert allclose(L[1], 1.77777778)
+
+        domain.order = 2
+        domain.distribute_to_vertices_and_edges()
+        assert allclose(L[1], [0.57777777, 2.37777778, 2.37777778])
+
+
+
+    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')
+        #print domain.quantities['stage'].centroid_values
+
+        a, b = domain.quantities['stage'].compute_gradients()
+	assert allclose(a[1], 25.18518519)
+	assert allclose(b[1], 3.33333333)
+
+        domain.order = 1
+        domain.distribute_to_vertices_and_edges()
+        assert allclose(L[1], 4.9382716)
+
+        domain.order = 2
+        domain.distribute_to_vertices_and_edges()
+        assert allclose(L[1], [1.07160494, 6.46058131, 7.28262855])
+
+
+
+    def test_distribute_near_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)
+
+
+        #Set up for a gradient of (3,0) at mid triangle
+        def slope(x, y):
+            return 10*x
+
+        h = 0.1
+        def stage(x,y):
+            return slope(x,y)+h
+
+        domain.set_quantity('elevation', slope)
+        domain.set_quantity('stage', stage, location='centroids')
+
+        #print domain.quantities['elevation'].centroid_values
+        #print domain.quantities['stage'].centroid_values
+
+        E = domain.quantities['elevation'].vertex_values
+        L = domain.quantities['stage'].vertex_values
+
+        #print E
+        domain.order = 1
+        domain.distribute_to_vertices_and_edges()
+	##assert allclose(L[1], [0.19999999, 20.05, 20.05])
+	assert allclose(L[1], [0.1, 20.1, 20.1])
+
+        domain.order = 2
+        domain.distribute_to_vertices_and_edges()
+	assert allclose(L[1], [0.1, 20.1, 20.1])
+
+    def test_distribute_near_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)
+
+
+        #Set up for a gradient of (3,0) at mid triangle
+        def slope(x, y):
+            return x**4+y**2
+
+        h = 0.1
+        def stage(x,y):
+            return slope(x,y)+h
+
+        domain.set_quantity('elevation', slope)
+        domain.set_quantity('stage', stage)
+
+        #print domain.quantities['elevation'].centroid_values
+        #print domain.quantities['stage'].centroid_values
+
+        E = domain.quantities['elevation'].vertex_values
+        L = domain.quantities['stage'].vertex_values
+
+        #print E
+        domain.order = 1
+        domain.distribute_to_vertices_and_edges()
+	##assert allclose(L[1], [4.19999999, 16.07142857, 20.02857143])
+	assert allclose(L[1], [4.1, 16.1, 20.1])
+
+        domain.order = 2
+        domain.distribute_to_vertices_and_edges()
+	assert allclose(L[1], [4.1, 16.1, 20.1])
+
+
+
+    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
+
+        #print E
+        domain.order = 2
+        domain.beta_h = 0.0 #Use first order in h-limiter
+        domain.distribute_to_vertices_and_edges()
+
+        #print L[1,:]
+	#print X[1,:]
+	#print Y[1,:]
+
+        assert allclose(L[1,:], [-0.00825735775384,
+                                 -0.00801881482869,
+                                 0.0272445025825])
+	assert allclose(X[1,:], [0.0143507718962,
+                                 0.0142502147066,
+                                 0.00931268339717])
+	assert allclose(Y[1,:], [-0.000117062180693,
+                                 7.94434448109e-005,
+                                 -0.000151505429018])
+
+
+
+    def test_balance_deep_and_shallow(self):
+        """Test that balanced limiters preserve conserved quantites.
+	"""
+        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] ]
+
+        mesh = Domain(points, elements)
+        mesh.check_integrity()
+
+        #Create a deliberate overshoot
+        mesh.set_quantity('stage', [[3,0,3], [2,2,6], [5,3,8], [8,3,5]])
+        mesh.set_quantity('elevation', 0) #Flat bed
+	stage = mesh.quantities['stage']
+
+	ref_centroid_values = copy.copy(stage.centroid_values[:]) #Copy
+
+        #Limit
+	mesh.distribute_to_vertices_and_edges()
+
+        #Assert that quantities are conserved
+        from Numeric import sum
+        for k in range(mesh.number_of_elements):
+            assert allclose (ref_centroid_values[k],
+                             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]
+        mesh.set_quantity('stage', [[3,0,3], [2,2,6], [5,3,8], [8,3,5]])
+        mesh.set_quantity('elevation', [[0,0,0],
+					[1.8,1.9,5.9],
+					[4.6,0,0],
+					[0,2,4]])
+	stage = mesh.quantities['stage']
+
+	ref_centroid_values = copy.copy(stage.centroid_values[:]) #Copy
+	ref_vertex_values = copy.copy(stage.vertex_values[:]) #Copy
+
+        #Limit
+	mesh.distribute_to_vertices_and_edges()
+
+
+        #Assert that all vertex quantities have changed
+        for k in range(mesh.number_of_elements):
+	    #print ref_vertex_values[k,:], stage.vertex_values[k,:]
+            assert not allclose (ref_vertex_values[k,:], stage.vertex_values[k,:])
+        #and assert that quantities are still conserved
+        from Numeric import sum
+        for k in range(mesh.number_of_elements):
+            assert allclose (ref_centroid_values[k],
+                             sum(stage.vertex_values[k,:])/3)
+
+
+        #Also check that Python and C version produce the same
+        assert allclose (stage.vertex_values,
+			 [[2,2,2],
+			  [1.93333333, 2.03333333, 6.03333333],
+			  [6.93333333, 4.53333333, 4.53333333],
+			  [5.33333333, 5.33333333, 5.33333333]])
+
+
+
+
+    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
+        from shallow_water import Domain, Reflective_boundary,\
+             Dirichlet_boundary, Constant_height
+        from Numeric import array
+
+        #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 = Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        domain.check_integrity()
+
+	#domain.visualise = True #If you want to take a sticky beak
+
+	initial_volume = domain.quantities['stage'].get_integral()
+	initial_xmom = domain.quantities['xmomentum'].get_integral()
+
+	#print initial_xmom
+
+        #Evolution
+        for t in domain.evolve(yieldstep = 0.05, finaltime = 5.0):
+            volume =  domain.quantities['stage'].get_integral()
+	    assert 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.filename + '.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
+	"""
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Reflective_boundary,\
+             Dirichlet_boundary, Constant_height
+        from Numeric import array
+
+        #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', x_slope)
+        domain.set_quantity('friction', 0)
+        domain.set_quantity('stage', 0.4) #Steady
+
+        # Boundary conditions (reflective everywhere)
+        Br = Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        domain.check_integrity()
+
+	#domain.visualise = True #If you want to take a sticky beak
+
+	initial_volume = domain.quantities['stage'].get_integral()
+	initial_xmom = domain.quantities['xmomentum'].get_integral()
+
+	#print initial_xmom
+
+        #Evolution
+        for t in domain.evolve(yieldstep = 0.05, finaltime = 5.0):
+            volume =  domain.quantities['stage'].get_integral()
+	    assert 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.filename + '.sww')
+
+    def test_conservation_3(self):
+        """Test that stage is conserved globally
+
+	This one uses a larger grid, convoluted bed, reflective bdries and a suitable
+	initial condition
+	"""
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Reflective_boundary,\
+             Dirichlet_boundary, Constant_height
+        from Numeric import array
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(2, 1)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.default_order = 2
+	domain.beta_h = 0.2
+	domain.set_quantities_to_be_stored(['stage'])
+
+	#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 = Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        domain.check_integrity()
+
+	#domain.visualise = True #If you want to take a sticky beak
+
+	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)
+
+	#print 'ORG', domain.quantities['stage'].centroid_values
+	domain.distribute_to_vertices_and_edges()
+
+
+	#print domain.quantities['stage'].centroid_values
+	assert allclose(domain.quantities['stage'].centroid_values,
+	                ref_centroid_values)
+
+
+	#Check that initial limiter doesn't violate cons quan
+	assert 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()
+            #print t, volume, initial_volume
+	    assert allclose (volume, initial_volume)
+
+        os.remove(domain.filename + '.sww')
+
+    def test_conservation_4(self):
+        """Test that stage is conserved globally
+
+	This one uses a larger grid, convoluted bed, reflective bdries and a suitable
+	initial condition
+	"""
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Reflective_boundary,\
+             Dirichlet_boundary, Constant_height
+        from Numeric import array
+
+        #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
+	domain.beta_h = 0.0
+
+	#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 = Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        domain.check_integrity()
+
+	#domain.visualise = True #If you want to take a sticky beak
+
+	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 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
+        for t in domain.evolve(yieldstep = 0.05, finaltime = 10.0):
+            volume =  domain.quantities['stage'].get_integral()
+
+            #print t, volume, initial_volume
+
+
+	    #if not allclose (volume, initial_volume):
+	    #    print 't==4.05'
+            #    for k in range(domain.number_of_elements):
+	    # 	    pass
+	    #	    print domain.quantities['stage'].centroid_values[k] -\
+            #             ref_centroid_values[k]
+
+	    assert allclose (volume, initial_volume)
+
+
+        os.remove(domain.filename + '.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
+	"""
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Reflective_boundary,\
+             Dirichlet_boundary, Constant_height
+        from Numeric import array
+
+        #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', x_slope)
+        domain.set_quantity('friction', 0)
+        domain.set_quantity('stage', 0.4) #Steady
+
+        # Boundary conditions (reflective everywhere)
+        Br = Reflective_boundary(domain)
+        Bleft = Dirichlet_boundary([0.5,0,0])
+        Bright = Dirichlet_boundary([0.1,0,0])
+        domain.set_boundary({'left': Bleft, 'right': Bright,
+			     'top': Br, 'bottom': Br})
+
+        domain.check_integrity()
+
+	#domain.visualise = True #If you want to take a sticky beak
+
+	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 allclose(t, 6):  #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 > 6:
+                #print '%.2f %14.8f %14.8f' %(t, ymom, steady_ymom)
+                assert allclose(xmom, steady_xmom)
+                assert allclose(ymom, steady_ymom)
+                assert allclose(stage, steady_stage)
+
+
+        os.remove(domain.filename + '.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
+	"""
+
+        yieldstep = 0.01
+        finaltime = 0.05
+        min_depth = 1.0e-2
+
+
+        import sys
+        from os import sep; sys.path.append('..'+sep+'abstract_2d_finite_volumes')
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Reflective_boundary
+
+
+        #Create shallow water domain
+        points, vertices, boundary = rectangular(10, 10, len1=500, len2=500)
+        domain = Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.visualise = 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 = 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
+            #print 'Integral stage = ',\
+            #      domain.quantities['stage'].get_integral(),\
+            #      ' Time = ',domain.time
+
+
+        now = domain.quantities['stage'].get_integral()
+
+        msg = 'Stage not conserved: was %f, now %f' %(ref, now)
+        assert allclose(ref, now), msg 
+
+        os.remove(domain.filename + '.sww')
+
+    def test_second_order_flat_bed_onestep(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Reflective_boundary,\
+             Dirichlet_boundary, Constant_height
+        from Numeric import array
+
+        #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
+
+        # Boundary conditions
+        Br = Reflective_boundary(domain)
+        Bd = 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# domain.write_time()
+
+        #Data from earlier version of abstract_2d_finite_volumes
+        assert allclose(domain.min_timestep, 0.0396825396825)
+        assert allclose(domain.max_timestep, 0.0396825396825)
+
+        assert 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])
+
+        domain.distribute_to_vertices_and_edges()
+        assert allclose(domain.quantities['stage'].vertex_values[:12,0],
+                        [0.0001714, 0.02656103, 0.00024152,
+                        0.02656103, 0.00024152, 0.02656103,
+                        0.00024152, 0.02656103, 0.00024152,
+                        0.02656103, 0.00024152, 0.0272623])
+
+        assert allclose(domain.quantities['stage'].vertex_values[:12,1],
+                        [0.00315012, 0.02656103, 0.00024152, 0.02656103,
+                         0.00024152, 0.02656103, 0.00024152, 0.02656103,
+                         0.00024152, 0.02656103, 0.00040506, 0.0272623])
+
+        assert allclose(domain.quantities['stage'].vertex_values[:12,2],
+                        [0.00182037, 0.02656103, 0.00676264,
+                         0.02656103, 0.00676264, 0.02656103,
+                         0.00676264, 0.02656103, 0.00676264,
+                         0.02656103, 0.0065991, 0.0272623])
+
+        assert 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])
+
+        assert 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])
+
+        os.remove(domain.filename + '.sww')
+
+
+    def test_second_order_flat_bed_moresteps(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Reflective_boundary,\
+             Dirichlet_boundary, Constant_height
+        from Numeric import array
+
+        #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
+
+        # Boundary conditions
+        Br = Reflective_boundary(domain)
+        Bd = 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.min_timestep, 0.0396825396825)
+        #assert allclose(domain.max_timestep, 0.0396825396825)
+        #print domain.quantities['stage'].centroid_values
+
+        os.remove(domain.filename + '.sww')        
+
+
+    def test_flatbed_first_order(self):
+        from mesh_factory import rectangular
+        from shallow_water import Domain,\
+             Reflective_boundary, Dirichlet_boundary
+
+        from Numeric import array
+
+        #Create basic mesh
+        N = 8
+        points, vertices, boundary = rectangular(N, N)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.visualise = False
+        domain.default_order=1
+
+        # Boundary conditions
+        Br = Reflective_boundary(domain)
+        Bd = 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
+            #domain.write_time()
+
+        #FIXME: These numbers were from version before 25/10
+        #assert allclose(domain.min_timestep, 0.0140413643926)
+        #assert allclose(domain.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 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.filename + '.sww')            
+
+    def test_flatbed_second_order(self):
+        from mesh_factory import rectangular
+        from shallow_water import Domain,\
+             Reflective_boundary, Dirichlet_boundary
+
+        from Numeric import array
+
+        #Create basic mesh
+        N = 8
+        points, vertices, boundary = rectangular(N, N)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.visualise = False
+        domain.default_order=2
+        #domain.minimum_allowed_height = 0.0 #Makes it like the 'oldstyle' balance
+
+        # Boundary conditions
+        Br = Reflective_boundary(domain)
+        Bd = 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 allclose(domain.min_timestep, 0.0210448446782)
+        assert allclose(domain.max_timestep, 0.0210448446782)
+
+        #print domain.quantities['stage'].vertex_values[:4,0]
+        #print domain.quantities['xmomentum'].vertex_values[:4,0]
+        #print domain.quantities['ymomentum'].vertex_values[:4,0]
+
+        #FIXME: These numbers were from version before 25/10
+        #assert allclose(domain.quantities['stage'].vertex_values[:4,0],
+        #                [0.00101913,0.05352143,0.00104852,0.05354394])
+
+        #FIXME: These numbers were from version before 21/3/6 - 
+	#could be recreated by setting maximum_allowed_speed to 0 maybe	
+        #assert allclose(domain.quantities['xmomentum'].vertex_values[:4,0],
+        #                [ 0.00064835, 0.03685719, 0.00085073, 0.03687313]) 
+	
+        assert allclose(domain.quantities['xmomentum'].vertex_values[:4,0],
+                        [ 0.00090581, 0.03685719, 0.00088303, 0.03687313])
+			
+			
+
+        #assert allclose(domain.quantities['xmomentum'].vertex_values[:4,0],
+        #                [0.00090581,0.03685719,0.00088303,0.03687313])
+
+        assert allclose(domain.quantities['ymomentum'].vertex_values[:4,0],
+                        [-0.00139463,0.0006156,-0.00060364,0.00061827])
+
+
+        os.remove(domain.filename + '.sww')
+
+	
+    def test_flatbed_second_order_vmax_0(self):
+        from mesh_factory import rectangular
+        from shallow_water import Domain,\
+             Reflective_boundary, Dirichlet_boundary
+
+        from Numeric import array
+
+        #Create basic mesh
+        N = 8
+        points, vertices, boundary = rectangular(N, N)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.visualise = False
+        domain.default_order=2
+        domain.maximum_allowed_speed = 0.0 #Makes it like the 'oldstyle'
+
+        # Boundary conditions
+        Br = Reflective_boundary(domain)
+        Bd = 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 allclose(domain.min_timestep, 0.0210448446782)
+        assert allclose(domain.max_timestep, 0.0210448446782)
+
+        #FIXME: These numbers were from version before 21/3/6 - 
+	#could be recreated by setting maximum_allowed_speed to 0 maybe	
+        assert allclose(domain.quantities['xmomentum'].vertex_values[:4,0],
+                        [ 0.00064835, 0.03685719, 0.00085073, 0.03687313]) 
+	
+
+        assert allclose(domain.quantities['ymomentum'].vertex_values[:4,0],
+                        [-0.00139463,0.0006156,-0.00060364,0.00061827])
+
+
+        os.remove(domain.filename + '.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
+        from shallow_water import Domain,\
+             Reflective_boundary, Dirichlet_boundary
+
+        from Numeric import array
+
+        #Create basic mesh
+        N = 8
+        points, vertices, boundary = rectangular(N, N)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.visualise = False
+        domain.default_order=domain.order=2
+
+        # Boundary conditions
+        Br = Reflective_boundary(domain)
+        Bd = 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 = zeros(2*N*N, 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 = zeros(2*N*N, 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 = zeros(2*N*N, 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 allclose(domain.min_timestep, 0.0210448446782)
+                assert allclose(domain.max_timestep, 0.0210448446782)
+
+
+            #Centroids were correct but not vertices.
+            #Hence the check of distribute below.
+            assert allclose(domain.quantities['stage'].centroid_values[:4],
+                            [0.00721206,0.05352143,0.01009108,0.05354394])
+
+            assert allclose(domain.quantities['xmomentum'].centroid_values[:4],
+                            [0.00648352,0.03685719,0.00850733,0.03687313])
+
+            assert allclose(domain.quantities['ymomentum'].centroid_values[:4],
+                            [-0.00139463,0.0006156,-0.00060364,0.00061827])
+
+            #print 'C17=', domain.quantities['xmomentum'].centroid_values[17]
+            #print 'C19=', domain.quantities['xmomentum'].centroid_values[19]
+
+            #assert allclose(domain.quantities['xmomentum'].centroid_values[17],0.00028606084)
+            ##print domain.quantities['xmomentum'].centroid_values[17], V
+            ##print
+            if not V:
+                #FIXME: These numbers were from version before 21/3/6 - 
+	        #could be recreated by setting maximum_allowed_speed to 0 maybe		  
+		
+                #assert allclose(domain.quantities['xmomentum'].centroid_values[17], 0.0)		 
+                assert allclose(domain.quantities['xmomentum'].centroid_values[17], 0.000286060839592)    	 		
+
+            else:
+                assert allclose(domain.quantities['xmomentum'].centroid_values[17], 0.00028606084)
+
+            import copy
+            XX = copy.copy(domain.quantities['xmomentum'].centroid_values)
+            assert allclose(domain.quantities['xmomentum'].centroid_values, XX)
+
+            domain.distribute_to_vertices_and_edges()
+
+            #assert allclose(domain.quantities['xmomentum'].centroid_values, XX)
+
+            #assert allclose(domain.quantities['xmomentum'].centroid_values[17],
+            #                0.0)
+            assert allclose(domain.quantities['xmomentum'].centroid_values[17], 0.000286060839592)    	 					    
+
+
+            #FIXME: These numbers were from version before 25/10
+            #assert allclose(domain.quantities['stage'].vertex_values[:4,0],
+            #                [0.00101913,0.05352143,0.00104852,0.05354394])
+
+            assert allclose(domain.quantities['ymomentum'].vertex_values[:4,0],
+                            [-0.00139463,0.0006156,-0.00060364,0.00061827])
+
+
+            assert allclose(domain.quantities['xmomentum'].vertex_values[:4,0],
+                            [0.00090581,0.03685719,0.00088303,0.03687313])
+
+
+            #NB NO longer relvant:
+
+            #This was the culprit. First triangles vertex 0 had an
+            #x-momentum of 0.0064835 instead of 0.00090581 and
+            #third triangle had 0.00850733 instead of 0.00088303
+            #print domain.quantities['xmomentum'].vertex_values[:4,0]
+
+            #print domain.quantities['xmomentum'].vertex_values[:4,0]
+            #assert allclose(domain.quantities['xmomentum'].vertex_values[:4,0],
+            #                [0.00090581,0.03685719,0.00088303,0.03687313])
+
+        os.remove(domain.filename + '.sww')
+
+
+
+    def test_bedslope_problem_first_order(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Reflective_boundary, Constant_height
+        from Numeric import array
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(6, 6)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.default_order=1
+
+        #Bed-slope and friction
+        def x_slope(x, y):
+            return -x/3
+
+        domain.set_quantity('elevation', x_slope)
+
+        # Boundary conditions
+        Br = Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        #Initial condition
+        domain.set_quantity('stage', Constant_height(x_slope, 0.05))
+        domain.check_integrity()
+
+        #Evolution
+        for t in domain.evolve(yieldstep = 0.05, finaltime = 0.05):
+            pass# domain.write_time()
+
+        assert allclose(domain.min_timestep, 0.050010003001)
+        assert allclose(domain.max_timestep, 0.050010003001)
+
+
+        os.remove(domain.filename + '.sww')
+        
+    def test_bedslope_problem_first_order_moresteps(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Reflective_boundary, Constant_height
+        from Numeric import array
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(6, 6)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.default_order=1
+        domain.beta_h = 0.0 #Use first order in h-limiter
+
+        #Bed-slope and friction
+        def x_slope(x, y):
+            return -x/3
+
+        domain.set_quantity('elevation', x_slope)
+
+        # Boundary conditions
+        Br = Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        #Initial condition
+        domain.set_quantity('stage', Constant_height(x_slope, 0.05))
+        domain.check_integrity()
+
+        #Evolution
+        for t in domain.evolve(yieldstep = 0.05, finaltime = 0.5):
+            pass# domain.write_time()
+
+        #Data from earlier version of abstract_2d_finite_volumes
+        #print domain.quantities['stage'].centroid_values
+
+        assert allclose(domain.quantities['stage'].centroid_values,
+                        [-0.02998628, -0.01520652, -0.03043492,
+                        -0.0149132, -0.03004706, -0.01476251,
+                        -0.0298215, -0.01467976, -0.02988158,
+                        -0.01474662, -0.03036161, -0.01442995,
+                        -0.07624583, -0.06297061, -0.07733792,
+                        -0.06342237, -0.07695439, -0.06289595,
+                        -0.07635559, -0.0626065, -0.07633628,
+                        -0.06280072, -0.07739632, -0.06386738,
+                        -0.12161738, -0.11028239, -0.1223796,
+                        -0.11095953, -0.12189744, -0.11048616,
+                        -0.12074535, -0.10987605, -0.12014311,
+                        -0.10976691, -0.12096859, -0.11087692,
+                        -0.16868259, -0.15868061, -0.16801135,
+                        -0.1588003, -0.16674343, -0.15813323,
+                        -0.16457595, -0.15693826, -0.16281096,
+                        -0.15585154, -0.16283873, -0.15540068,
+                        -0.17450362, -0.19919913, -0.18062882,
+                        -0.19764131, -0.17783111, -0.19407213,
+                        -0.1736915, -0.19053624, -0.17228678,
+                        -0.19105634, -0.17920133, -0.1968828,
+                        -0.14244395, -0.14604641, -0.14473537,
+                        -0.1506107, -0.14510055, -0.14919522,
+                        -0.14175896, -0.14560798, -0.13911658,
+                        -0.14439383, -0.13924047, -0.14829043])
+
+        os.remove(domain.filename + '.sww')
+        
+    def test_bedslope_problem_second_order_one_step(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Reflective_boundary, Constant_height
+        from Numeric import array
+
+        #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
+
+        #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 = Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        #Initial condition
+        domain.set_quantity('stage', Constant_height(x_slope, 0.05))
+        domain.check_integrity()
+
+        assert 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])
+
+
+        #print domain.quantities['stage'].extrapolate_second_order()
+        #domain.distribute_to_vertices_and_edges()
+        #print domain.quantities['stage'].vertex_values[:,0]
+
+        #Evolution
+        for t in domain.evolve(yieldstep = 0.05, finaltime = 0.05):
+            #domain.write_time()
+            pass
+
+
+        #print domain.quantities['stage'].centroid_values
+	assert allclose(domain.quantities['stage'].centroid_values,
+		 [0.01290985, 0.02356019, 0.01619096, 0.02356019, 0.01619096,
+		  0.02356019, 0.01619096, 0.02356019, 0.01619096, 0.02356019,
+		  0.01619096, 0.0268413, -0.04411074, -0.0248011, -0.04186556,
+		  -0.0248011, -0.04186556, -0.0248011, -0.04186556, -0.0248011,
+		  -0.04186556, -0.0248011, -0.04186556, -0.02255593,
+		  -0.09966629, -0.08035666, -0.09742112, -0.08035666,
+		  -0.09742112, -0.08035666, -0.09742112, -0.08035666,
+		  -0.09742112, -0.08035666, -0.09742112, -0.07811149,
+		  -0.15522185, -0.13591222, -0.15297667, -0.13591222,
+		  -0.15297667, -0.13591222, -0.15297667, -0.13591222,
+		  -0.15297667, -0.13591222, -0.15297667, -0.13366704,
+		  -0.2107774, -0.19146777, -0.20853223, -0.19146777,
+		  -0.20853223, -0.19146777, -0.20853223, -0.19146777,
+		  -0.20853223, -0.19146777, -0.20853223, -0.1892226,
+		  -0.26120669, -0.24776246, -0.25865535, -0.24776246,
+		  -0.25865535, -0.24776246, -0.25865535, -0.24776246,
+		  -0.25865535, -0.24776246, -0.25865535, -0.24521113])
+
+        os.remove(domain.filename + '.sww')
+
+    def test_bedslope_problem_second_order_two_steps(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Reflective_boundary, Constant_height
+        from Numeric import array
+
+        #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
+        domain.beta_h = 0.0 #Use first order in h-limiter
+
+        #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 = Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        #Initial condition
+        domain.set_quantity('stage', Constant_height(x_slope, 0.05))
+        domain.check_integrity()
+
+        assert 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])
+
+
+        #print domain.quantities['stage'].extrapolate_second_order()
+        #domain.distribute_to_vertices_and_edges()
+        #print domain.quantities['stage'].vertex_values[:,0]
+
+        #Evolution
+        for t in domain.evolve(yieldstep = 0.05, finaltime = 0.1):
+            pass
+
+
+        #Data from earlier version of abstract_2d_finite_volumes ft=0.1
+        assert allclose(domain.min_timestep, 0.0376895634803)
+        assert allclose(domain.max_timestep, 0.0415635655309)
+
+
+        assert allclose(domain.quantities['stage'].centroid_values,
+                        [0.00855788, 0.01575204, 0.00994606, 0.01717072,
+                         0.01005985, 0.01716362, 0.01005985, 0.01716299,
+                         0.01007098, 0.01736248, 0.01216452, 0.02026776,
+                         -0.04462374, -0.02479045, -0.04199789, -0.0229465,
+                         -0.04184033, -0.02295693, -0.04184013, -0.02295675,
+                         -0.04184486, -0.0228168, -0.04028876, -0.02036486,
+                         -0.10029444, -0.08170809, -0.09772846, -0.08021704,
+                         -0.09760006, -0.08022143, -0.09759984, -0.08022124,
+                         -0.09760261, -0.08008893, -0.09603914, -0.07758209,
+                         -0.15584152, -0.13723138, -0.15327266, -0.13572906,
+                         -0.15314427, -0.13573349, -0.15314405, -0.13573331,
+                         -0.15314679, -0.13560104, -0.15158523, -0.13310701,
+                         -0.21208605, -0.19283913, -0.20955631, -0.19134189,
+                         -0.20942821, -0.19134598, -0.20942799, -0.1913458,
+                         -0.20943005, -0.19120952, -0.20781177, -0.18869401,
+                         -0.25384082, -0.2463294, -0.25047649, -0.24464654,
+                         -0.25031159, -0.24464253, -0.25031112, -0.24464253,
+                         -0.25031463, -0.24454764, -0.24885323, -0.24286438])
+
+
+        os.remove(domain.filename + '.sww')
+
+    def test_bedslope_problem_second_order_two_yieldsteps(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Reflective_boundary, Constant_height
+        from Numeric import array
+
+        #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
+        domain.beta_h = 0.0 #Use first order in h-limiter
+
+        #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 = Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        #Initial condition
+        domain.set_quantity('stage', Constant_height(x_slope, 0.05))
+        domain.check_integrity()
+
+        assert 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])
+
+
+        #print domain.quantities['stage'].extrapolate_second_order()
+        #domain.distribute_to_vertices_and_edges()
+        #print domain.quantities['stage'].vertex_values[:,0]
+
+        #Evolution
+        for t in domain.evolve(yieldstep = 0.05, finaltime = 0.1):   #0.05??
+            #domain.write_time()
+            pass
+
+
+
+	assert allclose(domain.quantities['stage'].centroid_values,
+		 [0.00855788, 0.01575204, 0.00994606, 0.01717072, 0.01005985,
+		  0.01716362, 0.01005985, 0.01716299, 0.01007098, 0.01736248,
+		  0.01216452, 0.02026776, -0.04462374, -0.02479045, -0.04199789,
+		  -0.0229465, -0.04184033, -0.02295693, -0.04184013,
+		  -0.02295675, -0.04184486, -0.0228168, -0.04028876,
+		  -0.02036486, -0.10029444, -0.08170809, -0.09772846,
+		  -0.08021704, -0.09760006, -0.08022143, -0.09759984,
+		  -0.08022124, -0.09760261, -0.08008893, -0.09603914,
+		  -0.07758209, -0.15584152, -0.13723138, -0.15327266,
+		  -0.13572906, -0.15314427, -0.13573349, -0.15314405,
+		  -0.13573331, -0.15314679, -0.13560104, -0.15158523,
+		  -0.13310701, -0.21208605, -0.19283913, -0.20955631,
+		  -0.19134189, -0.20942821, -0.19134598, -0.20942799,
+		  -0.1913458, -0.20943005, -0.19120952, -0.20781177,
+		  -0.18869401, -0.25384082, -0.2463294, -0.25047649,
+		  -0.24464654, -0.25031159, -0.24464253, -0.25031112,
+		  -0.24464253, -0.25031463, -0.24454764, -0.24885323,
+		  -0.24286438])
+
+        os.remove(domain.filename + '.sww')
+
+    def test_bedslope_problem_second_order_more_steps(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Reflective_boundary, Constant_height
+        from Numeric import array
+
+        #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
+        domain.beta_h = 0.0 #Use first order in h-limiter
+
+        #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 = Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        #Initial condition
+        domain.set_quantity('stage', Constant_height(x_slope, 0.05))
+        domain.check_integrity()
+
+        assert 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])
+
+
+        #print domain.quantities['stage'].extrapolate_second_order()
+        #domain.distribute_to_vertices_and_edges()
+        #print domain.quantities['stage'].vertex_values[:,0]
+
+        #Evolution
+        for t in domain.evolve(yieldstep = 0.05, finaltime = 0.5):
+            pass
+
+
+        assert allclose(domain.quantities['stage'].centroid_values,
+     [-0.02907028, -0.01475478, -0.02973417, -0.01447186, -0.02932665, -0.01428285,
+      -0.02901975, -0.0141361,  -0.02898816, -0.01418135, -0.02961409, -0.01403487,
+      -0.07597998, -0.06252591, -0.07664854, -0.06312532, -0.07638287, -0.06265139,
+      -0.07571145, -0.06235231, -0.0756817,  -0.06245309, -0.07652292, -0.06289946,
+      -0.12367464, -0.11088981, -0.12237277, -0.11115338, -0.1218934,  -0.1107174,
+      -0.12081485, -0.11000491, -0.12038451, -0.11010335, -0.12102113, -0.11012105,
+      -0.16909116, -0.15831543, -0.16730214, -0.15786249, -0.1665493,  -0.15697919,
+      -0.16496618, -0.15559852, -0.16338679, -0.15509088, -0.16364092, -0.15424423,
+      -0.18771107, -0.19903904, -0.18903759, -0.19858437, -0.18701552, -0.19697797,
+      -0.1833593,  -0.19505871, -0.1818806,  -0.19418042, -0.18586159, -0.19576946,
+      -0.13986873, -0.14170053, -0.14132188, -0.14560674, -0.14095617, -0.14373292,
+      -0.13785933, -0.14033364, -0.13592955, -0.13936356, -0.13596008, -0.14216296])
+
+        assert allclose(domain.quantities['xmomentum'].centroid_values,
+     [ 0.00831121,  0.00317948,  0.00731797,  0.00334939,  0.00764717,  0.00348053,
+       0.00788729,  0.00356522,  0.00780649,  0.00341919,  0.00693525,  0.00310375,
+       0.02166196,  0.01421475,  0.02017737,  0.01316839,  0.02037015,  0.01368659,
+       0.02106,     0.01399161,  0.02074514,  0.01354935,  0.01887407,  0.0123113,
+       0.03775083,  0.02855197,  0.03689337,  0.02759782,  0.03732848,  0.02812072,
+       0.03872545,  0.02913348,  0.03880939,  0.02803804,  0.03546499,  0.0260039,
+       0.0632131,   0.04730634,  0.0576324,   0.04592336,  0.05790921,  0.04690514,
+       0.05986467,  0.04871165,  0.06170068,  0.04811572,  0.05657041,  0.04416292,
+       0.08489642,  0.07188097,  0.07835261,  0.06843406,  0.07986412,  0.0698247,
+       0.08201071,  0.07216756,  0.08378418,  0.07273624,  0.080399,    0.06645841,
+       0.01631548,  0.04691608,  0.0206632,   0.044409,    0.02115518,  0.04560305,
+       0.02160608,  0.04663725,  0.02174734,  0.04795559,  0.02281427,  0.05667111])
+
+
+        assert allclose(domain.quantities['ymomentum'].centroid_values,
+     [ 1.45876601e-004, -3.24627393e-004, -1.57572719e-004, -2.92790187e-004,
+      -9.90988382e-005, -3.06677335e-004, -1.62493106e-004, -3.71310004e-004,
+      -1.99445058e-004, -3.28493467e-004,  6.68217349e-005, -8.42042805e-006,
+       5.05093371e-004, -1.42842214e-004, -6.81454718e-005, -5.02084057e-004,
+      -8.50583861e-005, -4.65443981e-004, -1.96406564e-004, -5.88889562e-004,
+      -2.70160173e-004, -5.35485454e-004,  2.60780997e-004,  3.12145471e-005,
+       5.16189608e-004,  1.07069062e-004,  9.29989252e-005, -3.71211119e-004,
+       1.16350246e-004, -3.82407830e-004, -1.62077969e-004, -6.30906636e-004,
+      -4.74025708e-004, -6.94463009e-004,  6.15092843e-005,  2.22106820e-004,
+      -6.29589294e-004,  2.43611937e-004, -5.88125094e-004, -6.94293192e-005,
+      -4.17914641e-004,  6.64609019e-005, -7.68334577e-004, -3.40232101e-004,
+      -1.67424308e-003, -7.39485066e-004, -1.59966988e-003,  5.68262838e-005,
+      -1.48470633e-003, -1.84554882e-003, -2.27200099e-003, -1.67506848e-003,
+      -1.95610258e-003, -1.47638801e-003, -1.73779477e-003, -1.85498791e-003,
+      -2.01357843e-003, -2.17675471e-003, -1.65783870e-003, -1.15818681e-003,
+      -1.18663036e-003, -2.94229849e-003, -3.59309018e-003, -5.13496584e-003,
+      -6.17359400e-003, -5.98761937e-003, -6.00540116e-003, -5.01121966e-003,
+      -4.50964850e-003, -3.06319963e-003,  6.08950810e-004, -4.79537921e-004])
+
+        os.remove(domain.filename + '.sww')
+
+
+    def test_temp_play(self):
+
+        from mesh_factory import rectangular
+        from shallow_water import Domain, Reflective_boundary, Constant_height
+        from Numeric import array
+
+        #Create basic mesh
+        points, vertices, boundary = rectangular(5, 5)
+
+        #Create shallow water domain
+        domain = Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.default_order=2
+        domain.beta_h = 0.0 #Use first order in h-limiter
+
+        #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 = Reflective_boundary(domain)
+        domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+        #Initial condition
+        domain.set_quantity('stage', Constant_height(x_slope, 0.05))
+        domain.check_integrity()
+
+        #Evolution
+        for t in domain.evolve(yieldstep = 0.05, finaltime = 0.1):
+            pass
+
+	assert allclose(domain.quantities['stage'].centroid_values[:4],
+			[0.00206836, 0.01296714, 0.00363415, 0.01438924])
+	assert allclose(domain.quantities['xmomentum'].centroid_values[:4],
+			[0.01360154, 0.00671133, 0.01264578, 0.00648503])
+	assert allclose(domain.quantities['ymomentum'].centroid_values[:4],
+			[-1.19201077e-003, -7.23647546e-004,
+			-6.39083123e-005, 6.29815168e-005])
+
+        os.remove(domain.filename + '.sww')
+
+    def test_complex_bed(self):
+        #No friction is tested here
+
+        from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+             Transmissive_boundary, Time_boundary,\
+             Weir_simple as Weir, Constant_height
+
+        from mesh_factory import rectangular
+        from Numeric import array
+
+        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.visualise = False
+        domain.default_order=2
+
+
+        inflow_stage = 0.1
+        Z = Weir(inflow_stage)
+        domain.set_quantity('elevation', Z)
+
+        Br = Reflective_boundary(domain)
+        Bd = Dirichlet_boundary([inflow_stage, 0.0, 0.0])
+        domain.set_boundary({'left': Bd, 'right': Br, 'bottom': Br, 'top': Br})
+
+        domain.set_quantity('stage', Constant_height(Z, 0.))
+
+        for t in domain.evolve(yieldstep = 0.02, finaltime = 0.2):
+            pass
+
+
+        #print domain.quantities['stage'].centroid_values
+
+        #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.filename + '.sww')
+
+    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.
+        """
+        import time
+
+        #Create sww file of simple propagation from left to right
+        #through rectangular domain
+
+        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?
+        domain1.quantities_to_be_stored = ['stage', 'xmomentum', 'ymomentum']
+
+
+        #Bed-slope and friction at vertices (and interpolated elsewhere)
+        domain1.set_quantity('elevation', 0)
+        domain1.set_quantity('friction', 0)
+
+        # Boundary conditions
+        Br = Reflective_boundary(domain1)
+        Bd = 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
+            #domain1.write_time()
+
+        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 = Reflective_boundary(domain2)
+        Bf = Spatio_temporal_boundary(domain1.filename + '.' + domain1.format,
+				      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
+
+        #print take(cv1, (12,14,16))  #Right
+        #print take(cv2, (4,6,8))
+        #print take(cv1, (0,6,12))  #Bottom
+        #print take(cv2, (0,1,4))
+        #print take(cv1, (0,8,16))  #Diag
+        #print take(cv2, (0,3,8))
+
+        assert allclose( take(cv1, (0,8,16)), take(cv2, (0,3,8))) #Diag
+        assert allclose( take(cv1, (0,6,12)), take(cv2, (0,1,4))) #Bottom
+        assert allclose( take(cv1, (12,14,16)), take(cv2, (4,6,8))) #RHS
+
+        #Cleanup
+        os.remove(domain1.filename + '.' + domain1.format)
+        os.remove(domain2.filename + '.' + domain2.format)        
+
+
+
+    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
+
+        #Create sww file of simple propagation from left to right
+        #through rectangular domain
+
+        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 = 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 = ['stage', 'xmomentum', 'ymomentum']
+
+
+        #Bed-slope and friction at vertices (and interpolated elsewhere)
+        domain1.set_quantity('elevation', 0)
+        domain1.set_quantity('friction', 0)
+
+        # Boundary conditions
+        Br = Reflective_boundary(domain1)
+        Bd = 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
+            #domain1.write_time()
+
+
+        #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.filename + '.' + domain1.format)
+
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        s1 = fid.variables['stage'][1,:]
+        s2 = fid.variables['stage'][2,:]
+        fid.close()
+
+        from Numeric import take, reshape, concatenate
+        shp = (len(x), 1)
+        points = concatenate( (reshape(x, shp), reshape(y, shp)), axis=1)
+        #The diagonal points of domain 1 are 0, 5, 10, 15
+
+        #print points[0], points[5], points[10], points[15]
+        assert allclose( take(points, [0,5,10,15]),
+	                 [[0,0], [1.0/3, 1.0/3], [2.0/3, 2.0/3], [1,1]])
+
+
+        # Boundary conditions
+        Br = Reflective_boundary(domain2)
+        Bf = Spatio_temporal_boundary(domain1.filename + '.' + domain1.format,
+				      domain2)
+        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 allclose(boundary_midpoints, R)
+
+        #Check spatially interpolated output at time == 1
+        domain2.time = 1
+
+        #First diagonal midpoint
+        R0 = Bf.evaluate(0,0)
+        assert allclose(R0[0], (s1[0] + s1[5])/2)
+
+        #Second diagonal midpoint
+        R0 = Bf.evaluate(3,0)
+        assert allclose(R0[0], (s1[5] + s1[10])/2)
+
+        #First diagonal midpoint
+        R0 = Bf.evaluate(8,0)
+        assert 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 allclose(R0[0], (s2[0] + s2[5])/2)
+
+        #Second diagonal midpoint
+        R0 = Bf.evaluate(3,0)
+        assert allclose(R0[0], (s2[5] + s2[10])/2)
+
+        #First diagonal midpoint
+        R0 = Bf.evaluate(8,0)
+        assert 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 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 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 allclose(R0[0], ((s1[10] + s1[15])/2 + 2.0*(s2[10] + s2[15])/2)/3)
+
+
+
+        #Cleanup
+        os.remove(domain1.filename + '.' + domain1.format)
+
+
+    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 =  Dirichlet_boundary(conserved_quantities = array([0.0]))
+         b2 =  Dirichlet_boundary(conserved_quantities = array([1.0]))
+         b3 =  Dirichlet_boundary(conserved_quantities = array([2.0]))
+         tags["1"] = b1
+         tags["2"] = b2
+         tags["3"] = b3
+
+         #from anuga.abstract_2d_finite_volumes.pmesh2domain import pmesh_to_domain_instance
+         #domain = pmesh_to_domain_instance(fileName, Domain)
+
+         domain = Domain(mesh_filename=fileName)
+                         #verbose=True, use_cache=True)
+         
+         #print "domain.tagged_elements", domain.tagged_elements
+         ## check the quantities
+         #print domain.quantities['elevation'].vertex_values
+         answer = [[0., 8., 0.],
+                   [0., 10., 8.]]
+         assert allclose(domain.quantities['elevation'].vertex_values,
+                        answer)
+
+         #print domain.quantities['stage'].vertex_values
+         answer = [[0., 12., 10.],
+                   [0., 10., 12.]]
+         assert allclose(domain.quantities['stage'].vertex_values,
+                        answer)
+
+         #print domain.quantities['friction'].vertex_values
+         answer = [[0.01, 0.04, 0.03],
+                   [0.01, 0.02, 0.04]]
+         assert allclose(domain.quantities['friction'].vertex_values,
+                        answer)
+
+         #print domain.quantities['friction'].vertex_values
+         assert allclose(domain.tagged_elements['dsg'][0],0)
+         assert allclose(domain.tagged_elements['ole nielsen'][0],1)
+
+         self.failUnless( domain.boundary[(1, 0)]  == '1',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         self.failUnless( domain.boundary[(1, 2)]  == '2',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         self.failUnless( domain.boundary[(0, 1)]  == '3',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         self.failUnless( domain.boundary[(0, 0)]  == 'exterior',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         #print "domain.boundary",domain.boundary
+         self.failUnless( len(domain.boundary)  == 4,
+                          "test_pmesh2Domain Too many boundaries")
+         #FIXME change to use get_xllcorner
+         #print "d.geo_reference.xllcorner",domain.geo_reference.xllcorner 
+         self.failUnless(domain.geo_reference.xllcorner  == 140.0,
+                          "bad geo_referece")
+    #************
+
+    
+         domain = Domain(fileName)
+         
+         #print "domain.tagged_elements", domain.tagged_elements
+         ## check the quantities
+         #print domain.quantities['elevation'].vertex_values
+         answer = [[0., 8., 0.],
+                   [0., 10., 8.]]
+         assert allclose(domain.quantities['elevation'].vertex_values,
+                        answer)
+
+         #print domain.quantities['stage'].vertex_values
+         answer = [[0., 12., 10.],
+                   [0., 10., 12.]]
+         assert allclose(domain.quantities['stage'].vertex_values,
+                        answer)
+
+         #print domain.quantities['friction'].vertex_values
+         answer = [[0.01, 0.04, 0.03],
+                   [0.01, 0.02, 0.04]]
+         assert allclose(domain.quantities['friction'].vertex_values,
+                        answer)
+
+         #print domain.quantities['friction'].vertex_values
+         assert allclose(domain.tagged_elements['dsg'][0],0)
+         assert allclose(domain.tagged_elements['ole nielsen'][0],1)
+
+         self.failUnless( domain.boundary[(1, 0)]  == '1',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         self.failUnless( domain.boundary[(1, 2)]  == '2',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         self.failUnless( domain.boundary[(0, 1)]  == '3',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         self.failUnless( domain.boundary[(0, 0)]  == 'exterior',
+                          "test_tags_to_boundaries  failed. Single boundary wasn't added.")
+         #print "domain.boundary",domain.boundary
+         self.failUnless( len(domain.boundary)  == 4,
+                          "test_pmesh2Domain Too many boundaries")
+         #FIXME change to use get_xllcorner
+         #print "d.geo_reference.xllcorner",domain.geo_reference.xllcorner 
+         self.failUnless(domain.geo_reference.xllcorner  == 140.0,
+                          "bad geo_referece")
+    #************
+         os.remove(fileName)
+
+        #-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_Shallow_Water,'test')
+    runner = unittest.TextTestRunner(verbosity=1)    
+    runner.run(suite)
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_smf.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_smf.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_smf.py	(revision 3560)
@@ -0,0 +1,92 @@
+import unittest
+from Numeric import allclose
+from smf import slide_tsunami, slump_tsunami, Double_gaussian
+
+class Test_smf(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+
+    def test_Double_gaussian(self):
+        a3D = 5.6
+        wavelength = 10.2
+        width = 6.6
+        x0 = 0.0
+        y0 = 0.0
+        alpha = 0.0
+        kappa = 3.0
+        kappad = 0.8
+        dx = 0.5
+        zsmall = 0.01
+
+        dg = Double_gaussian(a3D=a3D, wavelength=wavelength, width=width, \
+                             x0=x0, y0=y0, alpha=alpha, dx = dx, \
+                             kappa=kappa, kappad = kappad, zsmall = zsmall)
+
+        assert allclose(dg.a3D, a3D)
+        assert allclose(dg.wavelength, wavelength)
+        assert allclose(dg.width, width)
+        assert allclose(dg.x0, x0)
+        assert allclose(dg.y0, y0)
+        assert allclose(dg.alpha, alpha)
+        assert allclose(dg.kappa, kappa)
+        assert allclose(dg.kappad, kappad)
+        assert allclose(dg.dx, dx)
+
+
+    def test_slide_tsunami(self):
+
+        len = 600.0
+        dep = 150.0
+        th = 9.0
+        thk = 15.0
+        wid = 340.0
+
+        slide = slide_tsunami(length=len, depth=dep, slope=th, \
+                              width = wid, thickness=thk)
+
+        assert allclose(slide.a3D, 0.07775819)
+        assert allclose(slide.wavelength, 2938.66695708)
+        assert allclose(slide.width, 340.0)
+        assert allclose(slide.x0, 0.0)
+        assert allclose(slide.y0, 0.0)
+        assert allclose(slide.alpha, 0.0)
+        assert allclose(slide.kappa, 3.0)
+        assert allclose(slide.kappad, 0.8)
+
+
+    def test_slump_tsunami(self):
+
+        len = 4500.0
+        thk = 760.0
+        wid = 4500.0
+        dep = 1200.0
+        rad = 3330
+        dp = 0.23
+        th = 12
+        alpha = 0.0
+        x0 = 0
+        y0 = 0
+
+        slump = slump_tsunami(length=len, depth=dep, slope=th, thickness=thk,\
+                  radius=rad, dphi=dp, x0=x0, y0=y0, alpha=alpha)
+
+        assert allclose(slump.a3D, 9.82538623)
+        assert allclose(slump.wavelength, 3660.37606554)
+        assert allclose(slump.width, 4500.0)
+        assert allclose(slump.x0, 0.0)
+        assert allclose(slump.y0, 0.0)
+        assert allclose(slump.alpha, 0.0)
+        assert allclose(slump.kappa, 3.0)
+        assert allclose(slump.kappad, 1.0)
+
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_smf,'test_Double_gaussian')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/test_util.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/test_util.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/test_util.py	(revision 3560)
@@ -0,0 +1,1167 @@
+#!/usr/bin/env python
+
+
+import unittest
+from Numeric import zeros, array, allclose, Float
+from math import sqrt, pi
+import tempfile
+
+from anuga.abstract_2d_finite_volumes.util import *
+from anuga.config import epsilon
+from anuga.abstract_2d_finite_volumes.data_manager import timefile2netcdf
+
+from anuga.utilities.numerical_tools import NAN
+
+def test_function(x, y):
+    return x+y
+
+class Test_Util(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+
+
+
+    #Geometric
+    #def test_distance(self):
+    #    from anuga.abstract_2d_finite_volumes.util import distance#
+    #
+    #    self.failUnless( distance([4,2],[7,6]) == 5.0,
+    #                     'Distance is wrong!')
+    #    self.failUnless( allclose(distance([7,6],[9,8]), 2.82842712475),
+    #                    'distance is wrong!')
+    #    self.failUnless( allclose(distance([9,8],[4,2]), 7.81024967591),
+    #                    'distance is wrong!')
+    #
+    #    self.failUnless( distance([9,8],[4,2]) == distance([4,2],[9,8]),
+    #                    'distance is wrong!')
+
+
+    def test_file_function_time1(self):
+        """Test that File function interpolates correctly
+        between given times. No x,y dependency here.
+        """
+
+        #Write file
+        import os, time
+        from anuga.config import time_format
+        from math import sin, pi
+
+        #Typical ASCII file
+        finaltime = 1200
+        filename = 'test_file_function'
+        fid = open(filename + '.txt', 'w')
+        start = time.mktime(time.strptime('2000', '%Y'))
+        dt = 60  #One minute intervals
+        t = 0.0
+        while t <= finaltime:
+            t_string = time.strftime(time_format, time.gmtime(t+start))
+            fid.write('%s, %f %f %f\n' %(t_string, 2*t, t**2, sin(t*pi/600)))
+            t += dt
+
+        fid.close()
+
+        #Convert ASCII file to NetCDF (Which is what we really like!)
+        timefile2netcdf(filename)
+
+
+        #Create file function from time series
+        F = file_function(filename + '.tms',
+                          quantities = ['Attribute0',
+                                        'Attribute1',
+                                        'Attribute2'])
+        
+        #Now try interpolation
+        for i in range(20):
+            t = i*10
+            q = F(t)
+
+            #Exact linear intpolation
+            assert allclose(q[0], 2*t)
+            if i%6 == 0:
+                assert allclose(q[1], t**2)
+                assert allclose(q[2], sin(t*pi/600))
+
+        #Check non-exact
+
+        t = 90 #Halfway between 60 and 120
+        q = F(t)
+        assert allclose( (120**2 + 60**2)/2, q[1] )
+        assert allclose( (sin(120*pi/600) + sin(60*pi/600))/2, q[2] )
+
+
+        t = 100 #Two thirds of the way between between 60 and 120
+        q = F(t)
+        assert allclose( 2*120**2/3 + 60**2/3, q[1] )
+        assert allclose( 2*sin(120*pi/600)/3 + sin(60*pi/600)/3, q[2] )
+
+        os.remove(filename + '.txt')
+        os.remove(filename + '.tms')        
+
+
+        
+    def test_spatio_temporal_file_function_basic(self):
+        """Test that spatio temporal file function performs the correct
+        interpolations in both time and space
+        NetCDF version (x,y,t dependency)        
+        """
+        import time
+
+	#Create sww file of simple propagation from left to right
+	#through rectangular domain
+	from shallow_water import Domain, Dirichlet_boundary
+        from mesh_factory import rectangular
+        from Numeric import take, concatenate, reshape
+
+        #Create basic mesh and shallow water domain
+        points, vertices, boundary = rectangular(3, 3)
+        domain1 = Domain(points, vertices, boundary)
+
+        from anuga.utilities.numerical_tools import mean
+        domain1.reduction = mean
+        domain1.smooth = True #NOTE: Mimic sww output where each vertex has
+                              # only one value.
+
+        domain1.default_order = 2
+	domain1.store = True
+        domain1.set_datadir('.')
+        domain1.set_name('spatio_temporal_boundary_source_%d' %(id(self)))
+        domain1.quantities_to_be_stored = ['stage', 'xmomentum', 'ymomentum']
+
+        #Bed-slope, friction and IC at vertices (and interpolated elsewhere)
+        domain1.set_quantity('elevation', 0)
+        domain1.set_quantity('friction', 0)
+        domain1.set_quantity('stage', 0)
+
+        # Boundary conditions
+        B0 = Dirichlet_boundary([0,0,0])
+        B6 = Dirichlet_boundary([0.6,0,0])
+        domain1.set_boundary({'left': B6, 'top': B6, 'right': B0, 'bottom': B0})
+        domain1.check_integrity()
+
+        finaltime = 8
+        #Evolution
+	t0 = -1
+        for t in domain1.evolve(yieldstep = 0.1, finaltime = finaltime):
+            #print 'Timesteps: %.16f, %.16f' %(t0, t)
+            #if t == t0:
+            #    msg = 'Duplicate timestep found: %f, %f' %(t0, t)
+	    #	raise msg
+	    t0 = t
+	     
+            #domain1.write_time()
+
+
+        #Now read data from sww and check
+        from Scientific.IO.NetCDF import NetCDFFile
+        filename = domain1.get_name() + '.' + domain1.format
+        fid = NetCDFFile(filename)
+
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        stage = fid.variables['stage'][:]
+        xmomentum = fid.variables['xmomentum'][:]
+        ymomentum = fid.variables['ymomentum'][:]
+        time = fid.variables['time'][:]
+
+        #Take stage vertex values at last timestep on diagonal
+        #Diagonal is identified by vertices: 0, 5, 10, 15
+
+        last_time_index = len(time)-1 #Last last_time_index
+        d_stage = reshape(take(stage[last_time_index, :], [0,5,10,15]), (4,1))
+        d_uh = reshape(take(xmomentum[last_time_index, :], [0,5,10,15]), (4,1))
+        d_vh = reshape(take(ymomentum[last_time_index, :], [0,5,10,15]), (4,1))
+        D = concatenate( (d_stage, d_uh, d_vh), axis=1)
+
+        #Reference interpolated values at midpoints on diagonal at
+        #this timestep are
+        r0 = (D[0] + D[1])/2
+        r1 = (D[1] + D[2])/2
+        r2 = (D[2] + D[3])/2
+
+        #And the midpoints are found now
+        Dx = take(reshape(x, (16,1)), [0,5,10,15])
+        Dy = take(reshape(y, (16,1)), [0,5,10,15])
+
+        diag = concatenate( (Dx, Dy), axis=1)
+        d_midpoints = (diag[1:] + diag[:-1])/2
+
+        #Let us see if the file function can find the correct
+        #values at the midpoints at the last timestep:
+        f = file_function(filename, domain1,
+                          interpolation_points = d_midpoints)
+
+        T = f.get_time()
+        msg = 'duplicate timesteps: %.16f and %.16f' %(T[-1], T[-2])
+        assert not T[-1] == T[-2], msg
+	t = time[last_time_index]
+        q = f(t, point_id=0); assert allclose(r0, q)
+        q = f(t, point_id=1); assert allclose(r1, q)
+        q = f(t, point_id=2); assert allclose(r2, q)
+
+
+        ##################
+        #Now do the same for the first timestep
+
+        timestep = 0 #First timestep
+        d_stage = reshape(take(stage[timestep, :], [0,5,10,15]), (4,1))
+        d_uh = reshape(take(xmomentum[timestep, :], [0,5,10,15]), (4,1))
+        d_vh = reshape(take(ymomentum[timestep, :], [0,5,10,15]), (4,1))
+        D = concatenate( (d_stage, d_uh, d_vh), axis=1)
+
+        #Reference interpolated values at midpoints on diagonal at
+        #this timestep are
+        r0 = (D[0] + D[1])/2
+        r1 = (D[1] + D[2])/2
+        r2 = (D[2] + D[3])/2
+
+        #Let us see if the file function can find the correct
+        #values
+        q = f(0, point_id=0); assert allclose(r0, q)
+        q = f(0, point_id=1); assert allclose(r1, q)
+        q = f(0, point_id=2); assert allclose(r2, q)
+
+
+        ##################
+        #Now do it again for a timestep in the middle
+
+        timestep = 33
+        d_stage = reshape(take(stage[timestep, :], [0,5,10,15]), (4,1))
+        d_uh = reshape(take(xmomentum[timestep, :], [0,5,10,15]), (4,1))
+        d_vh = reshape(take(ymomentum[timestep, :], [0,5,10,15]), (4,1))
+        D = concatenate( (d_stage, d_uh, d_vh), axis=1)
+
+        #Reference interpolated values at midpoints on diagonal at
+        #this timestep are
+        r0 = (D[0] + D[1])/2
+        r1 = (D[1] + D[2])/2
+        r2 = (D[2] + D[3])/2
+
+        q = f(timestep/10., point_id=0); assert allclose(r0, q)
+        q = f(timestep/10., point_id=1); assert allclose(r1, q)
+        q = f(timestep/10., point_id=2); assert allclose(r2, q)
+
+
+        ##################
+        #Now check temporal interpolation
+        #Halfway between timestep 15 and 16
+
+        timestep = 15
+        d_stage = reshape(take(stage[timestep, :], [0,5,10,15]), (4,1))
+        d_uh = reshape(take(xmomentum[timestep, :], [0,5,10,15]), (4,1))
+        d_vh = reshape(take(ymomentum[timestep, :], [0,5,10,15]), (4,1))
+        D = concatenate( (d_stage, d_uh, d_vh), axis=1)
+
+        #Reference interpolated values at midpoints on diagonal at
+        #this timestep are
+        r0_0 = (D[0] + D[1])/2
+        r1_0 = (D[1] + D[2])/2
+        r2_0 = (D[2] + D[3])/2
+
+        #
+        timestep = 16
+        d_stage = reshape(take(stage[timestep, :], [0,5,10,15]), (4,1))
+        d_uh = reshape(take(xmomentum[timestep, :], [0,5,10,15]), (4,1))
+        d_vh = reshape(take(ymomentum[timestep, :], [0,5,10,15]), (4,1))
+        D = concatenate( (d_stage, d_uh, d_vh), axis=1)
+
+        #Reference interpolated values at midpoints on diagonal at
+        #this timestep are
+        r0_1 = (D[0] + D[1])/2
+        r1_1 = (D[1] + D[2])/2
+        r2_1 = (D[2] + D[3])/2
+
+        # The reference values are
+        r0 = (r0_0 + r0_1)/2
+        r1 = (r1_0 + r1_1)/2
+        r2 = (r2_0 + r2_1)/2
+
+        q = f((timestep - 0.5)/10., point_id=0); assert allclose(r0, q)
+        q = f((timestep - 0.5)/10., point_id=1); assert allclose(r1, q)
+        q = f((timestep - 0.5)/10., point_id=2); assert allclose(r2, q)
+
+        ##################
+        #Finally check interpolation 2 thirds of the way
+        #between timestep 15 and 16
+
+        # The reference values are
+        r0 = (r0_0 + 2*r0_1)/3
+        r1 = (r1_0 + 2*r1_1)/3
+        r2 = (r2_0 + 2*r2_1)/3
+
+        #And the file function gives
+        q = f((timestep - 1.0/3)/10., point_id=0); assert allclose(r0, q)
+        q = f((timestep - 1.0/3)/10., point_id=1); assert allclose(r1, q)
+        q = f((timestep - 1.0/3)/10., point_id=2); assert allclose(r2, q)
+
+        fid.close()
+        import os
+        os.remove(filename)
+
+
+
+    def test_spatio_temporal_file_function_different_origin(self):
+        """Test that spatio temporal file function performs the correct
+        interpolations in both time and space where space is offset by
+        xllcorner and yllcorner
+        NetCDF version (x,y,t dependency)        
+        """
+        import time
+
+	#Create sww file of simple propagation from left to right
+	#through rectangular domain
+	from shallow_water import Domain, Dirichlet_boundary
+        from mesh_factory import rectangular
+        from Numeric import take, concatenate, reshape
+
+
+        from anuga.coordinate_transforms.geo_reference import Geo_reference
+        xllcorner = 2048
+        yllcorner = 11000
+        zone = 2
+
+        #Create basic mesh and shallow water domain
+        points, vertices, boundary = rectangular(3, 3)
+        domain1 = Domain(points, vertices, boundary,
+                         geo_reference = Geo_reference(xllcorner = xllcorner,
+                                                       yllcorner = yllcorner))
+        
+
+        from anuga.utilities.numerical_tools import mean	
+        domain1.reduction = mean
+        domain1.smooth = True #NOTE: Mimic sww output where each vertex has
+                              # only one value.
+
+        domain1.default_order = 2
+	domain1.store = True
+        domain1.set_datadir('.')
+        domain1.set_name('spatio_temporal_boundary_source_%d' %(id(self)))
+        domain1.quantities_to_be_stored = ['stage', 'xmomentum', 'ymomentum']
+
+        #Bed-slope, friction and IC at vertices (and interpolated elsewhere)
+        domain1.set_quantity('elevation', 0)
+        domain1.set_quantity('friction', 0)
+        domain1.set_quantity('stage', 0)
+
+        # Boundary conditions
+        B0 = Dirichlet_boundary([0,0,0])
+        B6 = Dirichlet_boundary([0.6,0,0])
+        domain1.set_boundary({'left': B6, 'top': B6, 'right': B0, 'bottom': B0})
+        domain1.check_integrity()
+
+        finaltime = 8
+        #Evolution
+        for t in domain1.evolve(yieldstep = 0.1, finaltime = finaltime):
+            pass
+            #domain1.write_time()
+
+
+        #Now read data from sww and check
+        from Scientific.IO.NetCDF import NetCDFFile
+        filename = domain1.get_name() + '.' + domain1.format
+        fid = NetCDFFile(filename)
+
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        stage = fid.variables['stage'][:]
+        xmomentum = fid.variables['xmomentum'][:]
+        ymomentum = fid.variables['ymomentum'][:]
+        time = fid.variables['time'][:]
+
+        #Take stage vertex values at last timestep on diagonal
+        #Diagonal is identified by vertices: 0, 5, 10, 15
+
+        last_time_index = len(time)-1 #Last last_time_index	
+        d_stage = reshape(take(stage[last_time_index, :], [0,5,10,15]), (4,1))
+        d_uh = reshape(take(xmomentum[last_time_index, :], [0,5,10,15]), (4,1))
+        d_vh = reshape(take(ymomentum[last_time_index, :], [0,5,10,15]), (4,1))
+        D = concatenate( (d_stage, d_uh, d_vh), axis=1)
+
+        #Reference interpolated values at midpoints on diagonal at
+        #this timestep are
+        r0 = (D[0] + D[1])/2
+        r1 = (D[1] + D[2])/2
+        r2 = (D[2] + D[3])/2
+
+        #And the midpoints are found now
+        Dx = take(reshape(x, (16,1)), [0,5,10,15])
+        Dy = take(reshape(y, (16,1)), [0,5,10,15])
+
+        diag = concatenate( (Dx, Dy), axis=1)
+        d_midpoints = (diag[1:] + diag[:-1])/2
+
+
+        #Adjust for georef - make interpolation points absolute
+        d_midpoints[:,0] += xllcorner
+        d_midpoints[:,1] += yllcorner                
+
+        #Let us see if the file function can find the correct
+        #values at the midpoints at the last timestep:
+        f = file_function(filename, domain1,
+                          interpolation_points = d_midpoints)
+
+	t = time[last_time_index]			  
+        q = f(t, point_id=0); assert allclose(r0, q)
+        q = f(t, point_id=1); assert allclose(r1, q)
+        q = f(t, point_id=2); assert allclose(r2, q)
+
+
+        ##################
+        #Now do the same for the first timestep
+
+        timestep = 0 #First timestep
+        d_stage = reshape(take(stage[timestep, :], [0,5,10,15]), (4,1))
+        d_uh = reshape(take(xmomentum[timestep, :], [0,5,10,15]), (4,1))
+        d_vh = reshape(take(ymomentum[timestep, :], [0,5,10,15]), (4,1))
+        D = concatenate( (d_stage, d_uh, d_vh), axis=1)
+
+        #Reference interpolated values at midpoints on diagonal at
+        #this timestep are
+        r0 = (D[0] + D[1])/2
+        r1 = (D[1] + D[2])/2
+        r2 = (D[2] + D[3])/2
+
+        #Let us see if the file function can find the correct
+        #values
+        q = f(0, point_id=0); assert allclose(r0, q)
+        q = f(0, point_id=1); assert allclose(r1, q)
+        q = f(0, point_id=2); assert allclose(r2, q)
+
+
+        ##################
+        #Now do it again for a timestep in the middle
+
+        timestep = 33
+        d_stage = reshape(take(stage[timestep, :], [0,5,10,15]), (4,1))
+        d_uh = reshape(take(xmomentum[timestep, :], [0,5,10,15]), (4,1))
+        d_vh = reshape(take(ymomentum[timestep, :], [0,5,10,15]), (4,1))
+        D = concatenate( (d_stage, d_uh, d_vh), axis=1)
+
+        #Reference interpolated values at midpoints on diagonal at
+        #this timestep are
+        r0 = (D[0] + D[1])/2
+        r1 = (D[1] + D[2])/2
+        r2 = (D[2] + D[3])/2
+
+        q = f(timestep/10., point_id=0); assert allclose(r0, q)
+        q = f(timestep/10., point_id=1); assert allclose(r1, q)
+        q = f(timestep/10., point_id=2); assert allclose(r2, q)
+
+
+        ##################
+        #Now check temporal interpolation
+        #Halfway between timestep 15 and 16
+
+        timestep = 15
+        d_stage = reshape(take(stage[timestep, :], [0,5,10,15]), (4,1))
+        d_uh = reshape(take(xmomentum[timestep, :], [0,5,10,15]), (4,1))
+        d_vh = reshape(take(ymomentum[timestep, :], [0,5,10,15]), (4,1))
+        D = concatenate( (d_stage, d_uh, d_vh), axis=1)
+
+        #Reference interpolated values at midpoints on diagonal at
+        #this timestep are
+        r0_0 = (D[0] + D[1])/2
+        r1_0 = (D[1] + D[2])/2
+        r2_0 = (D[2] + D[3])/2
+
+        #
+        timestep = 16
+        d_stage = reshape(take(stage[timestep, :], [0,5,10,15]), (4,1))
+        d_uh = reshape(take(xmomentum[timestep, :], [0,5,10,15]), (4,1))
+        d_vh = reshape(take(ymomentum[timestep, :], [0,5,10,15]), (4,1))
+        D = concatenate( (d_stage, d_uh, d_vh), axis=1)
+
+        #Reference interpolated values at midpoints on diagonal at
+        #this timestep are
+        r0_1 = (D[0] + D[1])/2
+        r1_1 = (D[1] + D[2])/2
+        r2_1 = (D[2] + D[3])/2
+
+        # The reference values are
+        r0 = (r0_0 + r0_1)/2
+        r1 = (r1_0 + r1_1)/2
+        r2 = (r2_0 + r2_1)/2
+
+        q = f((timestep - 0.5)/10., point_id=0); assert allclose(r0, q)
+        q = f((timestep - 0.5)/10., point_id=1); assert allclose(r1, q)
+        q = f((timestep - 0.5)/10., point_id=2); assert allclose(r2, q)
+
+        ##################
+        #Finally check interpolation 2 thirds of the way
+        #between timestep 15 and 16
+
+        # The reference values are
+        r0 = (r0_0 + 2*r0_1)/3
+        r1 = (r1_0 + 2*r1_1)/3
+        r2 = (r2_0 + 2*r2_1)/3
+
+        #And the file function gives
+        q = f((timestep - 1.0/3)/10., point_id=0); assert allclose(r0, q)
+        q = f((timestep - 1.0/3)/10., point_id=1); assert allclose(r1, q)
+        q = f((timestep - 1.0/3)/10., point_id=2); assert allclose(r2, q)
+
+        fid.close()
+        import os
+        os.remove(filename)
+
+        
+
+
+    def qtest_spatio_temporal_file_function_time(self):
+        """Test that File function interpolates correctly
+        between given times.
+        NetCDF version (x,y,t dependency)
+        """
+
+        #Create NetCDF (sww) file to be read
+        # x: 0, 5, 10, 15
+        # y: -20, -10, 0, 10
+        # t: 0, 60, 120, ...., 1200
+        #
+        # test quantities (arbitrary but non-trivial expressions):
+        #
+        #   stage     = 3*x - y**2 + 2*t
+        #   xmomentum = exp( -((x-7)**2 + (y+5)**2)/20 ) * t**2
+        #   ymomentum = x**2 + y**2 * sin(t*pi/600)
+
+        #NOTE: Nice test that may render some of the others redundant.
+
+        import os, time
+        from anuga.config import time_format
+        from Numeric import sin, pi, exp
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        import anuga.abstract_2d_finite_volumes.data_manager
+
+        finaltime = 1200
+        filename = 'test_file_function'
+
+        #Create a domain to hold test grid
+        #(0:15, -20:10)
+        points, vertices, boundary =\
+                rectangular(4, 4, 15, 30, origin = (0, -20))
+        print "points", points
+
+        #print 'Number of elements', len(vertices)
+        domain = Domain(points, vertices, boundary)
+        domain.smooth = False
+        domain.default_order = 2
+        domain.set_datadir('.')
+        domain.set_name(filename)
+        domain.store = True
+        domain.format = 'sww'   #Native netcdf visualisation format
+
+        #print points
+        start = time.mktime(time.strptime('2000', '%Y'))
+        domain.starttime = start
+
+
+        #Store structure
+        domain.initialise_storage()
+
+        #Compute artificial time steps and store
+        dt = 60  #One minute intervals
+        t = 0.0
+        while t <= finaltime:
+            #Compute quantities
+            f1 = lambda x,y: 3*x - y**2 + 2*t + 4
+            domain.set_quantity('stage', f1)
+
+            f2 = lambda x,y: x+y+t**2
+            domain.set_quantity('xmomentum', f2)
+
+            f3 = lambda x,y: x**2 + y**2 * sin(t*pi/600)
+            domain.set_quantity('ymomentum', f3)
+
+            #Store and advance time
+            domain.time = t
+            domain.store_timestep(domain.conserved_quantities)
+            t += dt
+
+
+        interpolation_points = [[0,-20], [1,0], [0,1], [1.1, 3.14], [10,-12.5]]
+      
+        #Deliberately set domain.starttime to too early
+        domain.starttime = start - 1
+
+        #Create file function
+        F = file_function(filename + '.sww', domain,
+                          quantities = domain.conserved_quantities,
+                          interpolation_points = interpolation_points)
+
+        #Check that FF updates fixes domain starttime
+        assert allclose(domain.starttime, start)
+
+        #Check that domain.starttime isn't updated if later
+        domain.starttime = start + 1
+        F = file_function(filename + '.sww', domain,
+                          quantities = domain.conserved_quantities,
+                          interpolation_points = interpolation_points)
+        assert allclose(domain.starttime, start+1)
+        domain.starttime = start
+
+
+        #Check linear interpolation in time
+        F = file_function(filename + '.sww', domain,
+                          quantities = domain.conserved_quantities,
+                          interpolation_points = interpolation_points)                
+        for id in range(len(interpolation_points)):
+            x = interpolation_points[id][0]
+            y = interpolation_points[id][1]
+
+            for i in range(20):
+                t = i*10
+                k = i%6
+
+                if k == 0:
+                    q0 = F(t, point_id=id)
+                    q1 = F(t+60, point_id=id)
+
+                if q0 == NAN:
+                    actual = q0
+                else:
+                    actual = (k*q1 + (6-k)*q0)/6
+                q = F(t, point_id=id)
+                #print i, k, t, q
+                #print ' ', q0
+                #print ' ', q1
+                print "q",q
+                print "actual", actual
+                #print
+                if q0 == NAN:
+                     self.failUnless( q == actual, 'Fail!')
+                else:
+                    assert allclose(q, actual)
+
+
+        #Another check of linear interpolation in time
+        for id in range(len(interpolation_points)):
+            q60 = F(60, point_id=id)
+            q120 = F(120, point_id=id)
+
+            t = 90 #Halfway between 60 and 120
+            q = F(t, point_id=id)
+            assert allclose( (q120+q60)/2, q )
+
+            t = 100 #Two thirds of the way between between 60 and 120
+            q = F(t, point_id=id)
+            assert allclose(q60/3 + 2*q120/3, q)
+
+
+
+        #Check that domain.starttime isn't updated if later than file starttime but earlier
+        #than file end time
+	delta = 23
+        domain.starttime = start + delta
+        F = file_function(filename + '.sww', domain,
+                          quantities = domain.conserved_quantities,
+                          interpolation_points = interpolation_points)
+        assert allclose(domain.starttime, start+delta)
+
+
+
+
+        #Now try interpolation with delta offset
+        for id in range(len(interpolation_points)):            
+            x = interpolation_points[id][0]
+            y = interpolation_points[id][1]
+
+            for i in range(20):
+                t = i*10
+                k = i%6
+
+                if k == 0:
+                    q0 = F(t-delta, point_id=id)
+                    q1 = F(t+60-delta, point_id=id)
+
+                q = F(t-delta, point_id=id)
+                assert allclose(q, (k*q1 + (6-k)*q0)/6)
+
+
+        os.remove(filename + '.sww')
+
+
+
+    def xtest_spatio_temporal_file_function_time(self):
+        # Test that File function interpolates correctly
+        # When some points are outside the mesh
+
+        import os, time
+        from anuga.config import time_format
+        from Numeric import sin, pi, exp
+        from mesh_factory import rectangular
+        from shallow_water import Domain
+        import anuga.abstract_2d_finite_volumes.data_manager 
+        from anuga.pmesh.mesh_interface import create_mesh_from_regions
+        finaltime = 1200
+        
+        filename = tempfile.mktemp()
+        #print "filename",filename 
+        filename = 'test_file_function'
+
+        meshfilename = tempfile.mktemp(".tsh")
+
+        boundary_tags = {'walls':[0,1],'bom':[2]}
+        
+        polygon_absolute = [[0,-20],[10,-20],[10,15],[-20,15]]
+        
+        create_mesh_from_regions(polygon_absolute,
+                                 boundary_tags,
+                                 10000000,
+                                 filename=meshfilename)
+        domain = Domain(mesh_filename=meshfilename)
+        domain.smooth = False
+        domain.default_order = 2
+        domain.set_datadir('.')
+        domain.set_name(filename)
+        domain.store = True
+        domain.format = 'sww'   #Native netcdf visualisation format
+
+        #print points
+        start = time.mktime(time.strptime('2000', '%Y'))
+        domain.starttime = start
+        
+
+        #Store structure
+        domain.initialise_storage()
+
+        #Compute artificial time steps and store
+        dt = 60  #One minute intervals
+        t = 0.0
+        while t <= finaltime:
+            #Compute quantities
+            f1 = lambda x,y: 3*x - y**2 + 2*t + 4
+            domain.set_quantity('stage', f1)
+
+            f2 = lambda x,y: x+y+t**2
+            domain.set_quantity('xmomentum', f2)
+
+            f3 = lambda x,y: x**2 + y**2 * sin(t*pi/600)
+            domain.set_quantity('ymomentum', f3)
+
+            #Store and advance time
+            domain.time = t
+            domain.store_timestep(domain.conserved_quantities)
+            t += dt
+
+        interpolation_points = [[1,0]]
+        interpolation_points = [[100,1000]]
+        
+        interpolation_points = [[0,-20], [1,0], [0,1], [1.1, 3.14], [10,-12.5],
+                                [78787,78787],[7878,3432]]
+            
+        #Deliberately set domain.starttime to too early
+        domain.starttime = start - 1
+
+        #Create file function
+        F = file_function(filename + '.sww', domain,
+                          quantities = domain.conserved_quantities,
+                          interpolation_points = interpolation_points)
+
+        #Check that FF updates fixes domain starttime
+        assert allclose(domain.starttime, start)
+
+        #Check that domain.starttime isn't updated if later
+        domain.starttime = start + 1
+        F = file_function(filename + '.sww', domain,
+                          quantities = domain.conserved_quantities,
+                          interpolation_points = interpolation_points)
+        assert allclose(domain.starttime, start+1)
+        domain.starttime = start
+
+
+        #Check linear interpolation in time
+        # checking points inside and outside the mesh
+        F = file_function(filename + '.sww', domain,
+                          quantities = domain.conserved_quantities,
+                          interpolation_points = interpolation_points)
+        
+        for id in range(len(interpolation_points)):
+            x = interpolation_points[id][0]
+            y = interpolation_points[id][1]
+
+            for i in range(20):
+                t = i*10
+                k = i%6
+
+                if k == 0:
+                    q0 = F(t, point_id=id)
+                    q1 = F(t+60, point_id=id)
+
+                if q0 == NAN:
+                    actual = q0
+                else:
+                    actual = (k*q1 + (6-k)*q0)/6
+                q = F(t, point_id=id)
+                #print i, k, t, q
+                #print ' ', q0
+                #print ' ', q1
+                #print "q",q
+                #print "actual", actual
+                #print
+                if q0 == NAN:
+                     self.failUnless( q == actual, 'Fail!')
+                else:
+                    assert allclose(q, actual)
+
+        # now lets check points inside the mesh
+        interpolation_points = [[0,-20], [1,0], [0,1], [1.1, 3.14]] #, [10,-12.5]] - this point doesn't work WHY?
+        interpolation_points = [[10,-12.5]]
+            
+        print "len(interpolation_points)",len(interpolation_points) 
+        F = file_function(filename + '.sww', domain,
+                          quantities = domain.conserved_quantities,
+                          interpolation_points = interpolation_points)
+
+        domain.starttime = start
+
+
+        #Check linear interpolation in time
+        F = file_function(filename + '.sww', domain,
+                          quantities = domain.conserved_quantities,
+                          interpolation_points = interpolation_points)                
+        for id in range(len(interpolation_points)):
+            x = interpolation_points[id][0]
+            y = interpolation_points[id][1]
+
+            for i in range(20):
+                t = i*10
+                k = i%6
+
+                if k == 0:
+                    q0 = F(t, point_id=id)
+                    q1 = F(t+60, point_id=id)
+
+                if q0 == NAN:
+                    actual = q0
+                else:
+                    actual = (k*q1 + (6-k)*q0)/6
+                q = F(t, point_id=id)
+                print "############"
+                print "id, x, y ", id, x, y #k, t, q
+                print "t", t
+                #print ' ', q0
+                #print ' ', q1
+                print "q",q
+                print "actual", actual
+                #print
+                if q0 == NAN:
+                     self.failUnless( q == actual, 'Fail!')
+                else:
+                    assert allclose(q, actual)
+
+
+        #Another check of linear interpolation in time
+        for id in range(len(interpolation_points)):
+            q60 = F(60, point_id=id)
+            q120 = F(120, point_id=id)
+
+            t = 90 #Halfway between 60 and 120
+            q = F(t, point_id=id)
+            assert allclose( (q120+q60)/2, q )
+
+            t = 100 #Two thirds of the way between between 60 and 120
+            q = F(t, point_id=id)
+            assert allclose(q60/3 + 2*q120/3, q)
+
+
+
+        #Check that domain.starttime isn't updated if later than file starttime but earlier
+        #than file end time
+	delta = 23
+        domain.starttime = start + delta
+        F = file_function(filename + '.sww', domain,
+                          quantities = domain.conserved_quantities,
+                          interpolation_points = interpolation_points)
+        assert allclose(domain.starttime, start+delta)
+
+
+
+
+        #Now try interpolation with delta offset
+        for id in range(len(interpolation_points)):            
+            x = interpolation_points[id][0]
+            y = interpolation_points[id][1]
+
+            for i in range(20):
+                t = i*10
+                k = i%6
+
+                if k == 0:
+                    q0 = F(t-delta, point_id=id)
+                    q1 = F(t+60-delta, point_id=id)
+
+                q = F(t-delta, point_id=id)
+                assert allclose(q, (k*q1 + (6-k)*q0)/6)
+
+
+        os.remove(filename + '.sww')
+
+    def test_file_function_time_with_domain(self):
+        """Test that File function interpolates correctly
+        between given times. No x,y dependency here.
+        Use domain with starttime
+        """
+
+        #Write file
+        import os, time, calendar
+        from anuga.config import time_format
+        from math import sin, pi
+        from domain import Domain
+
+        finaltime = 1200
+        filename = 'test_file_function'
+        fid = open(filename + '.txt', 'w')
+        start = time.mktime(time.strptime('2000', '%Y'))
+        dt = 60  #One minute intervals
+        t = 0.0
+        while t <= finaltime:
+            t_string = time.strftime(time_format, time.gmtime(t+start))
+            fid.write('%s, %f %f %f\n' %(t_string, 2*t, t**2, sin(t*pi/600)))
+            t += dt
+
+        fid.close()
+
+
+        #Convert ASCII file to NetCDF (Which is what we really like!)
+        timefile2netcdf(filename)
+
+
+
+        a = [0.0, 0.0]
+        b = [4.0, 0.0]
+        c = [0.0, 3.0]
+
+        points = [a, b, c]
+        vertices = [[0,1,2]]
+        domain = Domain(points, vertices)
+
+        #Check that domain.starttime is updated if non-existing
+        F = file_function(filename + '.tms', domain)
+        
+        assert allclose(domain.starttime, start)
+
+        #Check that domain.starttime is updated if too early
+        domain.starttime = start - 1
+        F = file_function(filename + '.tms', domain)
+        assert allclose(domain.starttime, start)
+
+        #Check that domain.starttime isn't updated if later
+        domain.starttime = start + 1
+        F = file_function(filename + '.tms', domain)        
+        assert allclose(domain.starttime, start+1)
+
+        domain.starttime = start
+        F = file_function(filename + '.tms', domain,
+                          quantities = ['Attribute0', 'Attribute1', 'Attribute2'])
+        
+
+        #print F.T
+        #print F.precomputed_values
+        #print 'F(60)', F(60)
+        
+        #Now try interpolation
+        for i in range(20):
+            t = i*10
+            q = F(t)
+
+            #Exact linear intpolation
+            assert allclose(q[0], 2*t)
+            if i%6 == 0:
+                assert allclose(q[1], t**2)
+                assert allclose(q[2], sin(t*pi/600))
+
+        #Check non-exact
+
+        t = 90 #Halfway between 60 and 120
+        q = F(t)
+        assert allclose( (120**2 + 60**2)/2, q[1] )
+        assert allclose( (sin(120*pi/600) + sin(60*pi/600))/2, q[2] )
+
+
+        t = 100 #Two thirds of the way between between 60 and 120
+        q = F(t)
+        assert allclose( 2*120**2/3 + 60**2/3, q[1] )
+        assert allclose( 2*sin(120*pi/600)/3 + sin(60*pi/600)/3, q[2] )
+
+        os.remove(filename + '.tms')
+        os.remove(filename + '.txt')        
+
+    def test_file_function_time_with_domain_different_start(self):
+        """Test that File function interpolates correctly
+        between given times. No x,y dependency here.
+        Use domain with a starttime later than that of file
+
+        ASCII version
+        """
+
+        #Write file
+        import os, time, calendar
+        from anuga.config import time_format
+        from math import sin, pi
+        from domain import Domain
+
+        finaltime = 1200
+        filename = 'test_file_function'
+        fid = open(filename + '.txt', 'w')
+        start = time.mktime(time.strptime('2000', '%Y'))
+        dt = 60  #One minute intervals
+        t = 0.0
+        while t <= finaltime:
+            t_string = time.strftime(time_format, time.gmtime(t+start))
+            fid.write('%s, %f %f %f\n' %(t_string, 2*t, t**2, sin(t*pi/600)))
+            t += dt
+
+        fid.close()
+
+        #Convert ASCII file to NetCDF (Which is what we really like!)
+        timefile2netcdf(filename)        
+
+        a = [0.0, 0.0]
+        b = [4.0, 0.0]
+        c = [0.0, 3.0]
+
+        points = [a, b, c]
+        vertices = [[0,1,2]]
+        domain = Domain(points, vertices)
+
+        #Check that domain.starttime isn't updated if later than file starttime but earlier
+        #than file end time
+	delta = 23
+        domain.starttime = start + delta
+        F = file_function(filename + '.tms', domain,
+                          quantities = ['Attribute0', 'Attribute1', 'Attribute2'])        
+        assert allclose(domain.starttime, start+delta)
+
+
+
+
+        #Now try interpolation with delta offset
+        for i in range(20):
+            t = i*10
+            q = F(t-delta)
+
+            #Exact linear intpolation
+            assert allclose(q[0], 2*t)
+            if i%6 == 0:
+                assert allclose(q[1], t**2)
+                assert allclose(q[2], sin(t*pi/600))
+
+        #Check non-exact
+
+        t = 90 #Halfway between 60 and 120
+        q = F(t-delta)
+        assert allclose( (120**2 + 60**2)/2, q[1] )
+        assert allclose( (sin(120*pi/600) + sin(60*pi/600))/2, q[2] )
+
+
+        t = 100 #Two thirds of the way between between 60 and 120
+        q = F(t-delta)
+        assert allclose( 2*120**2/3 + 60**2/3, q[1] )
+        assert allclose( 2*sin(120*pi/600)/3 + sin(60*pi/600)/3, q[2] )
+
+
+        os.remove(filename + '.tms')
+        os.remove(filename + '.txt')                
+
+
+
+    def test_apply_expression_to_dictionary(self):
+
+        #FIXME: Division is not expected to work for integers.
+        #This must be caught.
+        foo = array([[1,2,3],
+                     [4,5,6]], Float)
+
+        bar = array([[-1,0,5],
+                     [6,1,1]], Float)                  
+
+        D = {'X': foo, 'Y': bar}
+
+        Z = apply_expression_to_dictionary('X+Y', D)        
+        assert allclose(Z, foo+bar)
+
+        Z = apply_expression_to_dictionary('X*Y', D)        
+        assert allclose(Z, foo*bar)        
+
+        Z = apply_expression_to_dictionary('4*X+Y', D)        
+        assert allclose(Z, 4*foo+bar)        
+
+        # test zero division is OK
+        Z = apply_expression_to_dictionary('X/Y', D)
+        assert allclose(1/Z, 1/(foo/bar)) # can't compare inf to inf
+
+        # make an error for zero on zero
+        # this is really an error in Numeric, SciPy core can handle it
+        # Z = apply_expression_to_dictionary('0/Y', D)
+
+        #Check exceptions
+        try:
+            #Wrong name
+            Z = apply_expression_to_dictionary('4*X+A', D)        
+        except NameError:
+            pass
+        else:
+            msg = 'Should have raised a NameError Exception'
+            raise msg
+
+
+        try:
+            #Wrong order
+            Z = apply_expression_to_dictionary(D, '4*X+A')        
+        except AssertionError:
+            pass
+        else:
+            msg = 'Should have raised a AssertionError Exception'
+            raise msg        
+        
+
+    def test_multiple_replace(self):
+        """Hard test that checks a true word-by-word simultaneous replace
+        """
+        
+        D = {'x': 'xi', 'y': 'eta', 'xi':'lam'}
+        exp = '3*x+y + xi'
+        
+        new = multiple_replace(exp, D)
+        
+        assert new == '3*xi+eta + lam'
+                          
+
+
+    def test_point_on_line_obsolete(self):
+        """Test that obsolete call issues appropriate warning"""
+
+	#Turn warning into an exception
+        import warnings
+	warnings.filterwarnings('error')
+
+        try:
+	    assert point_on_line( 0, 0.5, 0,1, 0,0 )
+	except DeprecationWarning:
+	    pass
+	else:
+	    msg = 'point_on_line should have issued a DeprecationWarning'
+	    raise Exception(msg)    
+
+	warnings.resetwarnings()
+    
+    def test_get_version_info(self):
+        info = get_version_info()
+        assert info.startswith('Revision')
+    			  
+			  
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    suite = unittest.makeSuite(Test_Util,'test')
+    #suite = unittest.makeSuite(Test_Util,'test_apply')
+    runner = unittest.TextTestRunner()
+    runner.run(suite)
+
+
+
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/testpoly.txt
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/testpoly.txt	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/testpoly.txt	(revision 3560)
@@ -0,0 +1,7 @@
+40, 70
+50, 70
+60, 80
+50, 90
+45, 95
+40, 90
+30, 80
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/treenode.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/treenode.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/treenode.py	(revision 3560)
@@ -0,0 +1,145 @@
+
+import string
+import exceptions
+import types
+
+
+class TreeNode:
+    """class TreeNode
+
+    Base class for nodes in a tree-like structure.
+    Public Methods:
+        GetChildren()
+        GetParent()
+        AddChild(child)
+        GetLeaves()
+        DeleteChild(child)
+        Prune(children)
+        Show()
+    """
+
+
+    def __init__(self,name=None):
+        self.children = None
+        self.parent = None
+
+        # subclasses can implement these attributes as functions, called
+        # when a node (either leaf or internal) is deleted
+        if not hasattr(self,'ClearLeafNode'):
+            self.ClearLeafNode = None
+        if not hasattr(self,'ClearInternalNode'):
+            self.ClearInternalNode = None
+
+        # when not already set by derived class, set unique instance name
+        if not hasattr(self,"name"):
+            if name:
+                self.name = name
+            else:
+                self.name = id(self)
+
+
+    #Make treenode elements appear as sequences such thta on
+    #can iterate over them             
+    def __iter__(self):
+        self.index = -1   # incremented on first call to next()
+        return self
+
+    def next(self):
+        try:
+            self.index += 1
+            return self.children[self.index]
+        except IndexError:
+            self.index = -1
+            raise StopIteration
+
+
+
+    #---- public methods ------------------------------------
+
+    def GetChildren(self):
+        return self.children
+
+
+    def GetParent(self):
+        return self.parent
+
+
+    def AddChild(self,child):
+        child.parent = self
+        if hasattr(self,'storage'):
+            child.storage = self.storage
+        if self.children is None:
+            self.children = []
+        self.children.append(child)
+
+
+    def DeleteChild(self,child):
+        try:
+            index = self.children.index(child)
+            child.Prune()
+            del self.children[index]
+            if self.children == []:
+                self.children = None
+        except ValueError:
+            raise TreeNodeError
+
+
+    def Prune(self):
+        if self.children is None:                  # Leaf node
+            if callable(self.clear_leaf_node):
+                self.clear_leaf_node()
+	    else:
+	        msg = 'Node must have a method named "clear_leaf_node"' 
+		raise msg	
+        else:
+            if callable(self.clear_internal_node):   # Internal node
+                self.clear_internal_node()
+	    else:
+	        msg = 'Node must have a method named "clear_internal_node"' 
+		raise msg	
+				
+            for child in self.children:
+                child.Prune()
+            self.children = None
+
+
+    #FIXME: I think this one is redundant and should could be removed (OMN)
+    # Really?  Where is the equivalent method? (DEE)
+    # OK - I reliased that we can use it for testing and statistics (OMN)
+    def GetLeaves(self):
+        if self.children is None:
+            myleaves = [self]
+        else:
+            myleaves = []
+            for child in self.children:
+                myleaves += child.GetLeaves()
+
+        return myleaves
+
+
+    def CountLeaves(self):
+        if self.children is None:
+            count = 1
+        else:
+            count = 0
+            for child in self.children:
+                count += child.CountLeaves()
+
+        return count
+
+
+    def Show(self,depth=0):
+        """Traverse tree and print node names.
+        """        
+        print "%s%s" % ('  '*depth, self.name)
+        if self.children:
+            for child in self.children:
+                child.Show(depth+1)
+        else:
+            print ': %d' %self.Count()
+
+         
+#----------------------------------------------------------------
+class TreeNodeError(exceptions.Exception):
+    pass
+ 
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/tsh2sww.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/tsh2sww.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/tsh2sww.py	(revision 3560)
@@ -0,0 +1,63 @@
+"""Given a .tsh, print an sww
+"""
+
+######################
+# Module imports 
+#
+
+import sys
+from os import sep, path
+sys.path.append('..'+sep+'pyvolution')
+
+from shallow_water import Domain
+from anuga.pyvolution.pmesh2domain import pmesh_to_domain_instance
+import time, os 
+from anuga.pyvolution.data_manager import get_dataobject   
+from anuga.utilities.numerical_tools import mean
+
+def tsh2sww(infilename, sww_file_name = None, verbose = False):
+    """
+    This converts a mesh file (.tsh/.msh) to an .sww file.
+    This is usefull to visualise the mesh.
+    
+    Note: This currently just writes the output file in the input file dir.
+    """
+    if verbose == True:print 'Creating domain from', infilename
+    domain = pmesh_to_domain_instance(infilename, Domain)
+    if verbose == True:print "Number of triangles = ", len(domain)
+
+    domain.smooth = True
+    domain.format = 'sww'   #Native netcdf visualisation format
+        
+    file_path, filename = path.split(infilename)
+    filename, ext = path.splitext(filename)
+    
+    if not (sww_file_name == None):
+        file_path, filename = path.split(sww_file_name)
+        filename, ext = path.splitext(filename)
+    domain.filename = filename
+        
+    domain.reduction = mean
+    if verbose == True:print "file_path",file_path
+    if file_path == "":file_path = "."
+    domain.set_datadir(file_path)
+
+    if verbose == True:
+        print "Output written to " + domain.get_datadir() + sep + \
+              domain.filename + "." + domain.format  
+    sww = get_dataobject(domain)
+    sww.store_connectivity()
+    sww.store_timestep('stage')
+
+if __name__ == "__main__":
+    usage = "usage:python %s pmesh_file_name [verbose|non_verbose]" %         path.basename(sys.argv[0])
+    if len(sys.argv) < 2:
+        print usage
+    else:
+        filename = sys.argv[1]
+        verbose = False
+    if len(sys.argv) > 2:
+        if sys.argv[2][0] == "v" or sys.argv[2][0] == "V":
+            verbose = True
+        tsh2sww(filename, verbose = verbose)
+    
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/twolevels.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/twolevels.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/twolevels.py	(revision 3560)
@@ -0,0 +1,78 @@
+"""Example of shallow water wave equation.
+
+Two levels - testing that momentum is not genearted in the upward direction
+
+"""
+
+######################
+# Module imports 
+#
+from os import sep, path
+from mesh_factory import rectangular
+from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\
+     Constant_height
+from Numeric import array
+from anuga.pyvolution.util import Polygon_function, read_polygon
+
+
+#Create basic mesh
+N = 2
+points, vertices, boundary = rectangular(3, N, 20, 10)
+
+#Create shallow water domain
+domain = Domain(points, vertices, boundary)
+domain.store = True
+domain.set_name('two_levels')
+print "Output being written to " + domain.get_datadir() + sep + \
+	      domain.filename + "_size%d." %len(domain) + domain.format
+	
+
+domain.default_order=2
+domain.smooth = False
+domain.visualise = True
+
+#PLAY WITH THIS [0;1]: 
+#
+# beta_h == 0.0 reveals the problem
+# beta_h > 0.2 alleviates it
+domain.beta_h = 0.2    
+
+#IC
+domain.set_quantity('friction', 0.0)
+domain.set_quantity('stage', 3.0)
+
+def twostage(x, y):  
+    z = 0*x	 
+    for i in range(len(x)):	 	
+	if x[i]<10:	
+    	    z[i] = 4.
+
+    return z			
+#Set elevation  
+domain.set_quantity('elevation', twostage)
+
+
+######################
+# Boundary conditions
+Br = Reflective_boundary(domain)
+
+domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+domain.check_integrity()
+
+
+#print domain.quantities['elevation'].vertex_values    
+######################
+#Evolution
+for t in domain.evolve(yieldstep = 0.01, finaltime = 0.05):
+    domain.write_time()
+    print domain.quantities['xmomentum'].edge_values    
+    #print domain.quantities['stage'].centroid_values    
+
+#print domain.quantities['stage'].vertex_values
+#print
+#print domain.quantities['xmomentum'].vertex_values
+#print
+#print domain.quantities['ymomentum'].vertex_values
+    
+print 'Done'    
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/util.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/util.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/util.py	(revision 3560)
@@ -0,0 +1,1124 @@
+"""This module contains various auxiliary function used by pyvolution.
+
+It is also a clearing house for functions that may later earn a module
+of their own.
+"""
+
+import anuga.utilities.polygon
+from warnings import warn
+
+from anuga.geospatial_data.geospatial_data import ensure_absolute
+
+
+
+def file_function(filename,
+                  domain = None,
+                  quantities = None,
+                  interpolation_points = None,
+                  verbose = False,
+                  use_cache = False):
+    """Read time history of spatial data from NetCDF file and return
+    a callable object.
+
+    Input variables:
+    
+    filename - Name of sww or tms file
+       
+       If the file has extension 'sww' then it is assumed to be spatio-temporal
+       or temporal and the callable object will have the form f(t,x,y) or f(t)
+       depending on whether the file contains spatial data
+
+       If the file has extension 'tms' then it is assumed to be temporal only
+       and the callable object will have the form f(t)
+
+       Either form will return interpolated values based on the input file
+       using the underlying interpolation_function.
+
+    domain - Associated domain object   
+       If domain is specified, model time (domain.starttime)
+       will be checked and possibly modified.
+    
+       All times are assumed to be in UTC
+       
+       All spatial information is assumed to be in absolute UTM coordinates.
+
+    quantities - the name of the quantity to be interpolated or a
+                 list of quantity names. The resulting function will return
+                 a tuple of values - one for each quantity  
+
+    interpolation_points - list of absolute UTM coordinates for points (N x 2)
+    or geospatial object or points file name at which values are sought
+    
+    use_cache: True means that caching of intermediate result of
+               Interpolation_function is attempted
+
+    
+    See Interpolation function for further documentation
+    """
+
+
+    if use_cache is True:
+        try:
+            from caching import cache
+        except:
+            msg = 'Caching was requested, but caching module'+\
+                  'could not be imported'
+            raise msg
+
+
+        f = cache(_file_function,
+                  filename,
+                  {'domain': domain,
+                   'quantities': quantities,
+                   'interpolation_points': interpolation_points,
+                   'verbose': verbose},
+                  dependencies = [filename],
+                  compression = False,
+                  verbose = verbose)
+        #FIXME (Ole): Pass cache arguments, such as compression, in some sort of
+        #structure
+        
+    else:
+        f = _file_function(filename,
+                           domain,
+                           quantities,
+                           interpolation_points,
+                           verbose)            
+
+    return f
+
+
+
+def _file_function(filename,
+                   domain = None,
+                   quantities = None,
+                   interpolation_points = None,
+                   verbose = False):
+    """Internal function
+    
+    See file_function for documentatiton
+    """
+    
+
+    #FIXME (OLE): Should check origin of domain against that of file
+    #In fact, this is where origin should be converted to that of domain
+    #Also, check that file covers domain fully.
+
+    #Take into account:
+    #- domain's georef
+    #- sww file's georef
+    #- interpolation points as absolute UTM coordinates
+
+
+    assert type(filename) == type(''),\
+               'First argument to File_function must be a string'
+
+    try:
+        fid = open(filename)
+    except Exception, e:
+        msg = 'File "%s" could not be opened: Error="%s"'\
+                  %(filename, e)
+        raise msg
+
+    line = fid.readline()
+    fid.close()
+
+    if quantities is None: 
+        if domain is not None:
+            quantities = domain.conserved_quantities
+
+
+
+    if line[:3] == 'CDF':
+        return get_netcdf_file_function(filename, domain, quantities,
+                                        interpolation_points,
+                                        verbose = verbose)
+    else:
+        raise 'Must be a NetCDF File'
+
+
+
+def get_netcdf_file_function(filename,
+                             domain=None,
+                             quantity_names=None,
+                             interpolation_points=None,
+                             verbose = False):
+    """Read time history of spatial data from NetCDF sww file and
+    return a callable object f(t,x,y)
+    which will return interpolated values based on the input file.
+
+    If domain is specified, model time (domain.starttime)
+    will be checked and possibly modified
+    
+    All times are assumed to be in UTC
+
+    See Interpolation function for further documetation
+    
+    """
+    
+    
+    #FIXME: Check that model origin is the same as file's origin
+    #(both in UTM coordinates)
+    #If not - modify those from file to match domain
+    #Take this code from e.g. dem2pts in data_manager.py
+    #FIXME: Use geo_reference to read and write xllcorner...
+        
+
+    #FIXME: Maybe move caching out to this level rather than at the
+    #Interpolation_function level (below)
+
+    import time, calendar, types
+    from anuga.config import time_format
+    from Scientific.IO.NetCDF import NetCDFFile
+    from Numeric import array, zeros, Float, alltrue, concatenate, reshape
+
+    #Open NetCDF file
+    if verbose: print 'Reading', filename
+    fid = NetCDFFile(filename, 'r')
+
+    if type(quantity_names) == types.StringType:
+        quantity_names = [quantity_names]        
+    
+    if quantity_names is None or len(quantity_names) < 1:
+        #If no quantities are specified get quantities from file
+        #x, y, time are assumed as the independent variables so
+        #they are excluded as potentiol quantities
+        quantity_names = []
+        for name in fid.variables.keys():
+            if name not in ['x', 'y', 'time']:
+                quantity_names.append(name)
+
+    if len(quantity_names) < 1:                
+        msg = 'ERROR: At least one independent value must be specified'
+        raise msg
+
+
+    if interpolation_points is not None:
+        interpolation_points = ensure_absolute(interpolation_points)
+        msg = 'Points must by N x 2. I got %d' %interpolation_points.shape[1]
+        assert interpolation_points.shape[1] == 2, msg
+
+
+    #Now assert that requested quantitites (and the independent ones)
+    #are present in file 
+    missing = []
+    for quantity in ['time'] + quantity_names:
+        if not fid.variables.has_key(quantity):
+            missing.append(quantity)
+
+    if len(missing) > 0:
+        msg = 'Quantities %s could not be found in file %s'\
+              %(str(missing), filename)
+        fid.close()
+        raise msg
+
+    #Decide whether this data has a spatial dimension
+    spatial = True
+    for quantity in ['x', 'y']:
+        if not fid.variables.has_key(quantity):
+            spatial = False
+
+    if filename[-3:] == 'tms' and spatial is True:
+        msg = 'Files of type tms must not contain spatial information'
+        raise msg
+
+    if filename[-3:] == 'sww' and spatial is False:
+        msg = 'Files of type sww must contain spatial information'        
+        raise msg        
+
+    #Get first timestep
+    try:
+        starttime = fid.starttime[0]
+    except ValueError:
+        msg = 'Could not read starttime from file %s' %filename
+        raise msg
+
+    #Get variables
+    if verbose: print 'Get variables'    
+    time = fid.variables['time'][:]    
+
+    if spatial:
+        #Get origin
+        xllcorner = fid.xllcorner[0]
+        yllcorner = fid.yllcorner[0]
+        zone = fid.zone[0]        
+
+        x = fid.variables['x'][:]
+        y = fid.variables['y'][:]
+        triangles = fid.variables['volumes'][:]
+
+        x = reshape(x, (len(x),1))
+        y = reshape(y, (len(y),1))
+        vertex_coordinates = concatenate((x,y), axis=1) #m x 2 array
+
+        if interpolation_points is not None:
+            #Adjust for georef
+            interpolation_points[:,0] -= xllcorner
+            interpolation_points[:,1] -= yllcorner        
+        
+
+
+
+    if domain is not None:
+        #Update domain.startime if it is *earlier* than starttime
+        if starttime > domain.starttime:
+            msg = 'WARNING: Start time as specified in domain (%f)'\
+                  %domain.starttime
+            msg += ' is earlier than the starttime of file %s (%f).'\
+                     %(filename, starttime)
+            msg += ' Modifying domain starttime accordingly.'
+            
+            if verbose: print msg
+            domain.starttime = starttime #Modifying model time
+            if verbose: print 'Domain starttime is now set to %f'\
+               %domain.starttime
+
+
+        #If domain.startime is *later* than starttime,
+        #move time back - relative to domain's time
+        if domain.starttime > starttime:
+            time = time - domain.starttime + starttime
+
+        #FIXME Use method in geo to reconcile
+        #if spatial:
+        #assert domain.geo_reference.xllcorner == xllcorner
+        #assert domain.geo_reference.yllcorner == yllcorner
+        #assert domain.geo_reference.zone == zone        
+        
+    if verbose:
+        print 'File_function data obtained from: %s' %filename
+        print '  References:'
+        #print '    Datum ....' #FIXME
+        if spatial:
+            print '    Lower left corner: [%f, %f]'\
+                  %(xllcorner, yllcorner)
+        print '    Start time:   %f' %starttime                
+        
+    
+    #Produce values for desired data points at
+    #each timestep
+
+    quantities = {}
+    for i, name in enumerate(quantity_names):
+        quantities[name] = fid.variables[name][:]
+    fid.close()
+    
+
+    #from least_squares import Interpolation_function
+    from anuga.fit_interpolate.interpolate import Interpolation_function
+
+    if not spatial:
+        vertex_coordinates = triangles = interpolation_points = None         
+
+
+    return Interpolation_function(time,
+                                  quantities,
+                                  quantity_names,
+                                  vertex_coordinates,
+                                  triangles,
+                                  interpolation_points,
+                                  verbose = verbose)
+
+
+
+
+
+def multiple_replace(text, dictionary):
+    """Multiple replace of words in text
+
+    text:       String to be modified
+    dictionary: Mapping of words that are to be substituted
+
+    Python Cookbook 3.14 page 88 and page 90
+    """
+
+    import re
+    
+    #Create a regular expression from all of the dictionary keys
+    #matching only entire words
+    regex = re.compile(r'\b'+ \
+                       r'\b|\b'.join(map(re.escape, dictionary.keys()))+ \
+                       r'\b' )
+
+    #For each match, lookup the corresponding value in the dictionary
+    return regex.sub(lambda match: dictionary[match.group(0)], text)
+
+
+
+
+def apply_expression_to_dictionary(expression, dictionary):#dictionary):
+    """Apply arbitrary expression to values of dictionary
+
+    Given an expression in terms of the keys, replace key by the
+    corresponding values and evaluate.
+   
+
+    expression: Arbitrary, e.g. arithmetric, expression relating keys
+                from dictionary. 
+
+    dictionary: Mapping between symbols in expression and objects that
+                will be evaluated by expression.
+                Values in dictionary must support operators given in
+                expression e.g. by overloading
+
+    due to a limitation with Numeric, this can not evaluate 0/0
+    In general, the user can fix by adding 1e-30 to the numerator.
+    SciPy core can handle this situation.
+    """
+
+    import types
+    import re
+
+    assert isinstance(expression, basestring)
+    assert type(dictionary) == types.DictType
+
+    #Convert dictionary values to textual representations suitable for eval
+    D = {}
+    for key in dictionary:
+        D[key] = 'dictionary["%s"]' %key
+
+    #Perform substitution of variables    
+    expression = multiple_replace(expression, D)
+
+    #Evaluate and return
+    try:
+        return eval(expression)
+    except NameError, e:
+        msg = 'Expression "%s" could not be evaluated: %s' %(expression, e)
+        raise NameError, msg
+    except ValueError, e:
+        msg = 'Expression "%s" could not be evaluated: %s' %(expression, e)
+        raise ValueError, msg
+    
+
+
+
+####################################
+####OBSOLETE STUFF
+
+
+def angle(v1, v2):
+    """Temporary Interface to new location"""
+
+    import anuga.utilities.numerical_tools as NT	
+    
+    msg = 'angle has moved from util.py.  '
+    msg += 'Please use "from anuga.utilities.numerical_tools import angle"'
+    warn(msg, DeprecationWarning) 
+
+    return NT.angle(v1, v2)
+    
+def anglediff(v0, v1):
+    """Temporary Interface to new location"""
+
+    import anuga.utilities.numerical_tools as NT
+    
+    msg = 'anglediff has moved from util.py.  '
+    msg += 'Please use "from anuga.utilities.numerical_tools import anglediff"'
+    warn(msg, DeprecationWarning) 
+
+    return NT.anglediff(v0, v1)    
+
+    
+def mean(x):
+    """Temporary Interface to new location"""
+
+    import anuga.utilities.numerical_tools as NT    
+    
+    msg = 'mean has moved from util.py.  '
+    msg += 'Please use "from anuga.utilities.numerical_tools import mean"'
+    warn(msg, DeprecationWarning) 
+
+    return NT.mean(x)    
+
+def point_on_line(*args, **kwargs):
+    """Temporary Interface to new location"""
+
+    msg = 'point_on_line has moved from util.py.  '
+    msg += 'Please use "from anuga.utilities.polygon import point_on_line"'
+    warn(msg, DeprecationWarning) 
+
+    return utilities.polygon.point_on_line(*args, **kwargs)	
+    
+def inside_polygon(*args, **kwargs):
+    """Temporary Interface to new location"""
+
+    print 'inside_polygon has moved from util.py.  ',
+    print 'Please use "from anuga.utilities.polygon import inside_polygon"'
+
+    return utilities.polygon.inside_polygon(*args, **kwargs)    
+    
+def outside_polygon(*args, **kwargs):
+    """Temporary Interface to new location"""
+
+    print 'outside_polygon has moved from util.py.  ',
+    print 'Please use "from anuga.utilities.polygon import outside_polygon"'
+
+    return utilities.polygon.outside_polygon(*args, **kwargs)    
+
+
+def separate_points_by_polygon(*args, **kwargs):
+    """Temporary Interface to new location"""
+
+    print 'separate_points_by_polygon has moved from util.py.  ',
+    print 'Please use "from anuga.utilities.polygon import separate_points_by_polygon"'
+
+    return utilities.polygon.separate_points_by_polygon(*args, **kwargs)    
+
+
+
+def read_polygon(*args, **kwargs):
+    """Temporary Interface to new location"""
+
+    print 'read_polygon has moved from util.py.  ',
+    print 'Please use "from anuga.utilities.polygon import read_polygon"'
+
+    return utilities.polygon.read_polygon(*args, **kwargs)    
+
+
+def populate_polygon(*args, **kwargs):
+    """Temporary Interface to new location"""
+
+    print 'populate_polygon has moved from util.py.  ',
+    print 'Please use "from anuga.utilities.polygon import populate_polygon"'
+
+    return utilities.polygon.populate_polygon(*args, **kwargs)    
+
+##################### end of obsolete stuff ? ############
+'''
+this simply catches the screen output and files it to a file
+'''
+from os import sep
+
+class Screen_Catcher:
+
+    def __init__(self, filename):
+#        self.data = ''
+        self.filename = filename
+
+    def write(self, stuff):
+        fid = open(self.filename, 'a')
+#        fid = open(self.filename, 'w')
+#        self.data = self.data + stuff
+        fid.write(stuff)
+        fid.close()
+        
+def get_version_info():
+    """gets the version number of the SVN
+    """
+    
+    import os, sys
+
+    # Create dummy info 
+    info = 'Revision: Version info could not be obtained.'
+    info += 'A command line version of svn and access to the '
+    info += 'repository is necessary and the output must '
+    info += 'contain a line starting with "Revision:"'
+
+    try:
+        fid = os.popen('svn info')
+    except:
+        msg = 'svn is not recognised'
+        warn(msg, UserWarning)
+    else:    
+        lines = fid.readlines()
+        fid.close()
+        for line in lines:
+            if line.startswith('Revision:'):
+                info = line
+                break
+       
+    return info
+    
+    #if sys.platform == 'win32':
+    #    msg = 'does not work in Windows .... yet'
+    #    raise OSError, msg
+    #else:    
+    #    fid = os.popen('svn -info')
+    #    info = fid.readlines()
+    #    fid.close()
+    #    return info
+    
+    
+def sww2timeseries(swwfiles,
+                   gauge_filename,
+                   production_dirs,
+                   report = None,
+                   reportname = None,
+                   plot_quantity = None,
+                   surface = None,
+                   time_min = None,
+                   time_max = None,
+                   title_on = None,
+                   verbose = False):
+    
+    """ Read sww file and plot the time series for the
+    prescribed quantities at defined gauge locations and
+    prescribed time range.
+
+    Input variables:
+
+    swwfiles        - dictionary of sww files with label_ids (used in
+                      generating latex output. It will be part of
+                      the directory name of file_loc (typically the timestamp).
+                      Helps to differentiate latex files for different simulations
+                      for a particular scenario.  
+                    - assume that all conserved quantities have been stored
+                    - assume each sww file has been simulated with same timestep
+    
+    gauge_filename  - name of file containing gauge data
+                        - easting, northing, name , elevation?
+                    - OR (this is not yet done)
+                        - structure which can be converted to a Numeric array,
+                          such as a geospatial data object
+                      
+    report          - if True, then write figures to report_figures directory in
+                      relevant production directory
+                    - if False, figures are already stored with sww file
+                    - default to False
+
+    reportname      - name for report if wishing to generate report
+    
+    plot_quantity   - list containing quantities to plot, they must
+                      be the name of an existing quantity or one of
+                      the following possibilities
+                    - possibilities:
+                        - stage; 'stage'
+                        - depth; 'depth'
+                        - speed; calculated as absolute momentum
+                         (pointwise) divided by depth; 'speed'
+                        - bearing; calculated as the angle of the momentum
+                          vector (xmomentum, ymomentum) from the North; 'bearing'
+                        - absolute momentum; calculated as
+                          sqrt(xmomentum^2 + ymomentum^2); 'momentum'
+                        - x momentum; 'xmomentum'
+                        - y momentum; 'ymomentum'
+                    - default will be ['stage', 'speed', 'bearing']
+
+    surface          - if True, then generate solution surface with 3d plot
+                       and save to current working directory
+                     - default = False
+    
+    time_min         - beginning of user defined time range for plotting purposes
+                        - default will be first available time found in swwfile
+                        
+    time_max         - end of user defined time range for plotting purposes
+                        - default will be last available time found in swwfile
+                        
+    title_on        - if True, export standard graphics with title
+                    - if False, export standard graphics without title
+
+
+                      
+    Output:
+    
+    - time series data stored in .csv for later use if required.
+      Name = gauges_timeseries followed by gauge name 
+    - latex file will be generated in same directory as where script is
+      run (usually production scenario directory.
+      Name = latexoutputlabel_id.tex
+
+    Other important information:
+    
+    It is assumed that the used has stored all the conserved quantities
+    and elevation during the scenario run, i.e.
+    ['stage', 'elevation', 'xmomentum', 'ymomentum']
+    If this has not occurred then sww2timeseries will not work.
+                      
+    """
+
+    
+    k = _sww2timeseries(swwfiles,
+                        gauge_filename,
+                        production_dirs,
+                        report,
+                        reportname,
+                        plot_quantity,
+                        surface,
+                        time_min,
+                        time_max,
+                        title_on,
+                        verbose)
+
+    return k
+
+def _sww2timeseries(swwfiles,
+                    gauge_filename,
+                    production_dirs,
+                    report = None,
+                    reportname = None,
+                    plot_quantity = None,
+                    surface = None,
+                    time_min = None,
+                    time_max = None,
+                    title_on = None,
+                    verbose = False):   
+        
+    assert type(gauge_filename) == type(''),\
+               'Gauge filename must be a string'
+    
+    try:
+        fid = open(gauge_filename)
+    except Exception, e:
+        msg = 'File "%s" could not be opened: Error="%s"'\
+                  %(gauge_filename, e)
+        raise msg
+
+    if report is None:
+        report = False
+        
+    
+    if plot_quantity is None:
+        plot_quantity = ['depth', 'speed', 'bearing']
+    else:
+        assert type(plot_quantity) == list,\
+               'plot_quantity must be a list'
+        check_list(plot_quantity)
+
+    if surface is None:
+        surface = False
+        
+    if title_on is None:
+        title_on = True
+    
+    if verbose: print '\n Gauges obtained from: %s \n' %gauge_filename
+    gauges, locations, elev = get_gauges_from_file(gauge_filename)
+
+    sww_quantity = ['stage', 'elevation', 'xmomentum', 'ymomentum']
+
+    file_loc = []
+    f_list = []
+    label_id = []
+    leg_label = []
+    themaxT = 0.0
+    theminT = 0.0
+    
+    for swwfile in swwfiles.keys():
+
+        try:
+            fid = open(swwfile)
+        except Exception, e:
+            msg = 'File "%s" could not be opened: Error="%s"'\
+                  %(swwfile, e)
+            raise msg
+
+        f = file_function(swwfile,
+                          quantities = sww_quantity,
+                          interpolation_points = gauges,
+                          verbose = True,
+                          use_cache = True)
+ 
+        index = swwfile.rfind(sep)
+        file_loc.append(swwfile[:index+1])
+        label_id.append(swwfiles[swwfile])
+        leg_label.append(production_dirs[swwfiles[swwfile]])
+        
+        f_list.append(f)
+        maxT = max(f.get_time())
+        minT = min(f.get_time())
+        if maxT > themaxT: themaxT = maxT
+        if minT > theminT: theminT = minT
+
+    if time_min is None:
+        time_min = theminT # min(T)
+    else:
+        if time_min < theminT: # min(T):
+            msg = 'Minimum time entered not correct - please try again'
+            raise Exception, msg
+
+    if time_max is None:
+        time_max = themaxT # max(T)
+    else:
+        if time_max > themaxT: # max(T):
+            msg = 'Maximum time entered not correct - please try again'
+            raise Exception, msg
+
+    if verbose: print 'Inputs OK - going to generate figures'
+
+    return generate_figures(plot_quantity, file_loc, report, reportname, surface,
+                            leg_label, f_list, gauges, locations, elev, production_dirs,
+                            time_min, time_max, title_on, label_id, verbose)
+                         
+#Fixme - Use geospatial to read this file - it's an xya file
+def get_gauges_from_file(filename):
+    from os import sep, getcwd, access, F_OK, mkdir
+    fid = open(filename)
+    lines = fid.readlines()
+    fid.close()
+    
+    gauges = []
+    gaugelocation = []
+    elev = []
+    line1 = lines[0]
+    line11 = line1.split(',')
+    for i in range(len(line11)):
+        if line11[i].strip('\n').strip(' ') == 'Easting': east_index = i
+        if line11[i].strip('\n').strip(' ') == 'Northing': north_index = i
+        if line11[i].strip('\n').strip(' ') == 'Name': name_index = i
+        if line11[i].strip('\n').strip(' ') == 'Elevation': elev_index = i
+
+    for line in lines[1:]:
+        fields = line.split(',')
+        gauges.append([float(fields[east_index]), float(fields[north_index])])
+        elev.append(float(fields[elev_index]))
+        loc = fields[name_index]
+        gaugelocation.append(loc.strip('\n'))
+
+    return gauges, gaugelocation, elev
+
+def check_list(quantity):
+
+    all_quantity = ['stage', 'depth', 'momentum', 'xmomentum',
+                    'ymomentum', 'speed', 'bearing', 'elevation']
+
+    p = list(set(quantity).difference(set(all_quantity)))
+    if len(p) <> 0:
+        msg = 'Quantities %s do not exist - please try again' %p
+        raise Exception, msg
+        
+    return 
+
+def calc_bearing(uh, vh):
+
+    from math import atan, degrees
+    
+    angle = degrees(atan(vh/(uh+1.e-15)))
+    if (0 < angle < 90.0):
+        if vh > 0:
+            bearing = 90.0 - abs(angle)
+        if vh < 0:
+            bearing = 270.0 - abs(angle)
+    if (-90 < angle < 0):
+        if vh < 0:
+            bearing = 90.0 - abs(angle)
+        if vh > 0:
+            bearing = 270.0 - abs(angle)
+    if angle == 0: bearing = 0.0
+            
+    return bearing
+
+def generate_figures(plot_quantity, file_loc, report, reportname, surface,
+                     leg_label, f_list,
+                     gauges, locations, elev, production_dirs, time_min, time_max,
+                     title_on, label_id, verbose):
+
+    from math import sqrt, atan, degrees
+    from Numeric import ones, allclose, zeros, Float, ravel
+    from os import sep, altsep, getcwd, mkdir, access, F_OK, environ
+    from pylab import ion, hold, plot, axis, figure, legend, savefig, \
+         xlabel, ylabel, title, close, subplot
+
+    import pylab as p1
+    import mpl3d.mplot3d as p3
+
+    if report == True:    
+        texdir = getcwd()+sep+'report'+sep
+        if access(texdir,F_OK) == 0:
+            mkdir (texdir)
+        if len(label_id) == 1:
+            label_id1 = label_id[0].replace(sep,'')
+            label_id2 = label_id1.replace('_','')
+            texfile = texdir+reportname+'%s' %(label_id2)
+            texfile2 = reportname+'%s' %(label_id2)
+            texfilename = texfile + '.tex'
+            if verbose: print '\n Latex output printed to %s \n' %texfilename
+            fid = open(texfilename, 'w')
+        else:
+            texfile = texdir+reportname 
+            texfile2 = reportname
+            texfilename = texfile + '.tex' 
+            if verbose: print '\n Latex output printed to %s \n' %texfilename
+            fid = open(texfilename, 'w')
+    else:
+        texfile = ''
+
+    p = len(f_list)
+    n = []
+    n0 = 0
+    for i in range(len(f_list)):
+        n.append(len(f_list[i].get_time()))
+        if n[i] > n0: n0 = n[i]  
+    n0 = int(n0)
+    m = len(locations)
+    model_time = zeros((n0,m,p), Float) 
+    stages = zeros((n0,m,p), Float)
+    elevations = zeros((n0,m,p), Float) 
+    momenta = zeros((n0,m,p), Float)
+    xmom = zeros((n0,m,p), Float)
+    ymom = zeros((n0,m,p), Float)
+    speed = zeros((n0,m,p), Float)
+    bearings = zeros((n0,m,p), Float)
+    depths = zeros((n0,m,p), Float)
+    eastings = zeros((n0,m,p), Float)
+    min_stages = []
+    max_stages = []
+    max_momentums = []
+    max_speeds = []
+    c = 0
+    model_time_plot3d = zeros((n0,m), Float)
+    stages_plot3d = zeros((n0,m), Float)
+    eastings_plot3d = zeros((n0,m),Float)
+    ##### loop over each swwfile #####
+    for j, f in enumerate(f_list):
+        if verbose: print 'swwfile %d of %d' %(j, len(f_list))
+        comparefile = file_loc[j]+sep+'gauges_maxmins'+'.csv'
+        fid_compare = open(comparefile, 'w')
+        ##### loop over each gauge #####
+        for k, g in enumerate(gauges):
+            if verbose: print 'Gauge %d of %d' %(k, len(gauges))
+            min_stage = 10
+            max_stage = 0
+            max_momentum = 0
+            max_speed = 0   
+            gaugeloc = locations[k]
+            thisfile = file_loc[j]+sep+'gauges_time_series'+'_'+gaugeloc+'.csv'
+            fid_out = open(thisfile, 'w')
+            s = 'Time, Stage, Momentum, Speed \n'
+            fid_out.write(s)
+            
+            #### generate quantities #######
+            for i, t in enumerate(f.get_time()):
+                if time_min <= t <= time_max:
+                    w = f(t, point_id = k)[0]
+                    z = f(t, point_id = k)[1]
+                    uh = f(t, point_id = k)[2]
+                    vh = f(t, point_id = k)[3]
+                    depth = w-z      
+                    m = sqrt(uh*uh + vh*vh)   
+                    if depth < 0.001:
+                        vel = 0.0
+                    else:
+                        vel = m / (depth + 1.e-30) 
+                    bearing = calc_bearing(uh, vh)
+                    model_time[i,k,j] = t/60.0
+                    stages[i,k,j] = w
+                    elevations[i,k,j] = z 
+                    xmom[i,k,j] = uh 
+                    ymom[i,k,j] = vh 
+                    momenta[i,k,j] = m 
+                    speed[i,k,j] = vel 
+                    bearings[i,k,j] = bearing 
+                    depths[i,k,j] = depth
+                    thisgauge = gauges[k]
+                    eastings[i,k,j] = thisgauge[0]
+                    s = '%.2f, %.2f, %.2f, %.2f\n' %(t, w, m, vel)
+                    fid_out.write(s)
+                    if t/60.0 <= 13920: tindex = i
+                    if w > max_stage: max_stage = w
+                    if w < min_stage: min_stage = w
+                    if m > max_momentum: max_momentum = m
+                    if vel > max_speed: max_speed = vel
+                    
+                    
+            s = '%.2f, %.2f, %.2f, %s\n' %(max_stage, min_stage, z, leg_label[j])
+            fid_compare.write(s)
+            max_stages.append(max_stage)
+            min_stages.append(min_stage)
+            max_momentums.append(max_momentum)
+            max_speeds.append(max_speed)     
+            #### finished generating quantities for each swwfile #####
+        
+        model_time_plot3d[:,:] = model_time[:,:,j]
+        stages_plot3d[:,:] = stages[:,:,j]
+        eastings_plot3d[:,] = eastings[:,:,j]
+            
+        if surface ==  True:
+            print 'Printing surface figure'
+            for i in range(2):
+                fig = p1.figure(10)
+                ax = p3.Axes3D(fig)
+                if len(gauges) > 80:
+                    ax.plot_surface(model_time[:,:,j],eastings[:,:,j],stages[:,:,j])
+                else:
+                    ax.plot_wireframe(model_time[:,:,j],eastings[:,:,j],stages[:,:,j])
+                    #ax.plot3D(ravel(eastings[:,:,j]),ravel(model_time[:,:,j]),ravel(stages[:,:,j]))
+                ax.set_xlabel('time')
+                ax.set_ylabel('x')
+                ax.set_zlabel('stage')
+                fig.add_axes(ax)
+                p1.show()
+                surfacefig = 'solution_surface%s' %leg_label[j]
+                p1.savefig(surfacefig)
+                p1.close()
+            
+    #### finished generating quantities for all swwfiles #####
+
+    # x profile for given time
+    if surface == True:
+        figure(11)
+        plot(eastings[tindex,:,j],stages[tindex,:,j])
+        xlabel('x')
+        ylabel('stage')
+        profilefig = 'solution_xprofile' 
+        savefig('profilefig')
+                
+    stage_axis = axis([time_min/60.0, time_max/60.0, min(min_stages), max(max_stages)*1.1])
+    vel_axis = axis([time_min/60.0, time_max/60.0, min(max_speeds), max(max_speeds)*1.1])
+    mom_axis = axis([time_min/60.0, time_max/60.0, min(max_momentums), max(max_momentums)*1.1])  
+    
+    cstr = ['g', 'r', 'b', 'c', 'm', 'y', 'k']
+    nn = len(plot_quantity)
+    no_cols = 2
+    elev_output = []
+    if len(label_id) > 1: graphname_report = []
+    for k, g in enumerate(gauges):
+        count1 = 0
+        if report == True and len(label_id) > 1:
+            s = '\\begin{figure}[hbt] \n \\centering \n \\begin{tabular}{cc} \n'
+            fid.write(s)
+        if len(label_id) > 1: graphname_report = []
+        #### generate figures for each gauge ###
+        for j, f in enumerate(f_list):
+            ion()
+            hold(True)
+            count = 0
+            where1 = 0
+            where2 = 0
+            word_quantity = ''
+            if report == True and len(label_id) == 1:
+                s = '\\begin{figure}[hbt] \n \\centering \n \\begin{tabular}{cc} \n'
+                fid.write(s)
+                
+            for which_quantity in plot_quantity:
+                count += 1
+                where1 += 1
+                figure(count, frameon = False)
+                if which_quantity == 'depth':
+                    plot(model_time[0:n[j]-1,k,j], depths[0:n[j]-1,k,j], '-', c = cstr[j])
+                    units = 'm'
+                if which_quantity == 'stage':
+                    plot(model_time[0:n[j]-1,k,j], stages[0:n[j]-1,k,j], '-', c = cstr[j])
+                    axis(stage_axis)
+                    units = 'm'
+                if which_quantity == 'momentum':
+                    plot(model_time[0:n[j]-1,k,j], momenta[0:n[j]-1,k,j], '-', c = cstr[j])
+                    axis(mom_axis)
+                    units = 'm^2 / sec'
+                if which_quantity == 'xmomentum':
+                    plot(model_time[0:n[j]-1,k,j], xmom[0:n[j]-1,k,j], '-', c = cstr[j])
+                    axis(mom_axis)
+                    units = 'm^2 / sec'
+                if which_quantity == 'ymomentum':
+                    plot(model_time[0:n[j]-1,k,j], ymom[0:n[j]-1,k,j], '-', c = cstr[j])
+                    axis(mom_axis)
+                    units = 'm^2 / sec'
+                if which_quantity == 'speed':
+                    plot(model_time[0:n[j]-1,k,j], speed[0:n[j]-1,k,j], '-', c = cstr[j])
+                    axis(vel_axis)
+                    units = 'm / sec'
+                if which_quantity == 'bearing':
+                    due_east = 90.0*ones(shape(model_time[0:n[j]-1,k,j],Float))
+                    due_west = 270.0*ones(shape(model_time[0:n[j]-1,k,j],Float))
+                    plot(model_time[0:n[j]-1,k,j], bearings, '-', 
+                         model_time[0:n[j]-1,k,j], due_west, '-.', 
+                         model_time[0:n[j]-1,k,j], due_east, '-.')
+                    units = 'degrees from North'
+                    ax = axis([time_min, time_max, 0.0, 360.0])
+                    legend(('Bearing','West','East'))
+
+                xlabel('time (mins)')
+                ylabel('%s (%s)' %(which_quantity, units))
+                if len(label_id) > 1: legend((leg_label),loc='upper right')
+
+                gaugeloc1 = gaugeloc.replace(' ','')
+                #gaugeloc2 = gaugeloc1.replace('_','')
+                gaugeloc2 = locations[k].replace(' ','')
+                graphname = '%sgauge%s_%s' %(file_loc[j], gaugeloc2, which_quantity)
+
+                if report == True and len(label_id) > 1:
+                    figdir = getcwd()+sep+'report_figures'+sep
+                    if access(figdir,F_OK) == 0 :
+                        mkdir (figdir)
+                    latex_file_loc = figdir.replace(sep,altsep) 
+                    graphname_latex = '%sgauge%s%s' %(latex_file_loc, gaugeloc2, which_quantity) # storing files in production directory    
+                    graphname_report_input = '%sgauge%s%s' %('..'+altsep+'report_figures'+altsep, gaugeloc2, which_quantity) # giving location in latex output file
+                    graphname_report.append(graphname_report_input)
+                    
+                    savefig(graphname_latex) # save figures in production directory for report generation
+
+                if report == True:
+
+                    figdir = getcwd()+sep+'report_figures'+sep
+                    if access(figdir,F_OK) == 0 :
+                        mkdir (figdir)
+                    latex_file_loc = figdir.replace(sep,altsep)    
+
+                    if len(label_id) == 1: 
+                        graphname_latex = '%sgauge%s%s%s' %(latex_file_loc, gaugeloc2, which_quantity, label_id2) # storing files in production directory  
+                        graphname_report = '%sgauge%s%s%s' %('..'+altsep+'report_figures'+altsep, gaugeloc2, which_quantity, label_id2) # giving location in latex output file
+                        s = '\includegraphics[width=0.49\linewidth, height=50mm]{%s%s}' %(graphname_report, '.png')
+                        fid.write(s)
+                        if where1 % 2 == 0:
+                            s = '\\\\ \n'
+                            where1 = 0
+                        else:
+                            s = '& \n'
+                        fid.write(s)
+                        savefig(graphname_latex)
+                
+                if title_on == True:
+                    title('%s scenario: %s at %s gauge' %(label_id, which_quantity, gaugeloc))
+
+                savefig(graphname) # save figures with sww file
+
+            if report == True and len(label_id) == 1:
+                for i in range(nn-1):
+                    if nn > 2:
+                        word_quantity += plot_quantity[i] + ', '
+                    else:
+                        word_quantity += plot_quantity[i]
+                    
+                word_quantity += ' and ' + plot_quantity[nn-1]                
+                caption = 'Time series for %s at %s location (elevation %.2fm)' %(word_quantity, locations[k], elev[k]) #gaugeloc.replace('_',' '))
+                if elev[k] == 0.0:
+                    caption = 'Time series for %s at %s location (elevation %.2fm)' %(word_quantity, locations[k], elevations[0,k,j])
+                    east = gauges[0]
+                    north = gauges[1]
+                    elev_output.append([locations[k],east,north,elevations[0,k,j]])
+                label = '%sgauge%s' %(label_id2, gaugeloc2)
+                s = '\end{tabular} \n \\caption{%s} \n \label{fig:%s} \n \end{figure} \n \n' %(caption, label)
+                fid.write(s)
+                c += 1
+                if c % 25 == 0: fid.write('\\clearpage \n')
+                savefig(graphname_latex)               
+                
+        if report == True and len(label_id) > 1:
+            for i in range(nn-1):
+                if nn > 2:
+                    word_quantity += plot_quantity[i] + ', '
+                else:
+                    word_quantity += plot_quantity[i]
+                where1 = 0
+                count1 += 1
+                index = j*len(plot_quantity)
+                for which_quantity in plot_quantity:
+                    where1 += 1
+                    s = '\includegraphics[width=0.49\linewidth, height=50mm]{%s%s}' %(graphname_report[index], '.png')
+                    index += 1
+                    fid.write(s)
+                    if where1 % 2 == 0:
+                        s = '\\\\ \n'
+                        where1 = 0
+                    else:
+                        s = '& \n'
+                    fid.write(s)
+            word_quantity += ' and ' + plot_quantity[nn-1]            
+            label = 'gauge%s' %(gaugeloc2) 
+            caption = 'Time series for %s at %s location (elevation %.2fm)' %(word_quantity, locations[k], elev[k])
+            if elev[k] == 0.0:
+                    caption = 'Time series for %s at %s location (elevation %.2fm)' %(word_quantity, locations[k], elevations[0,k,j])
+                    thisgauge = gauges[k]
+                    east = thisgauge[0]
+                    north = thisgauge[1]
+                    elev_output.append([locations[k],east,north,elevations[0,k,j]])
+            
+            s = '\end{tabular} \n \\caption{%s} \n \label{fig:%s} \n \end{figure} \n \n' %(caption, label)
+            fid.write(s)
+            c += 1
+            if c % 25 == 0: fid.write('\\clearpage \n')          
+            
+            #### finished generating figures ###
+
+        close('all')
+    
+    return texfile2, elev_output
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/version.txt
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/version.txt	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/version.txt	(revision 3560)
@@ -0,0 +1,16 @@
+This is a file containing version info as expanded by subversion
+It is read by config.py to obtain the version number for pyvolution.
+
+
+------------------------------------- 	
+To set subversion keyword expansion:
+
+svn propset svn:keywords "LastChangedDate LastChangedRevision LastChangedBy HeadURL Id" version.txt
+
+Subversion keywords:
+
+$LastChangedDate$
+$LastChangedRevision$
+$LastChangedBy$
+$HeadURL$
+$Id$
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/view_tsh.bat
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/view_tsh.bat	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/view_tsh.bat	(revision 3560)
@@ -0,0 +1,1 @@
+python C:\Home\Projects\anuga\inundation\pyvolution\view_tsh.py %1  %2
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/view_tsh.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/view_tsh.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/view_tsh.py	(revision 3560)
@@ -0,0 +1,47 @@
+"""
+Script to view tsh file using faster vpython graphics
+"""
+import sys
+from os import sep, path
+sys.path.append('..'+sep+'pyvolution')
+
+
+from shallow_water import Domain
+from anuga.pyvolution.pmesh2domain import pmesh_to_domain_instance
+from anuga.pyvolution.util import file_function
+from anuga.utilities.polygon import Polygon_function, read_polygon
+from Numeric import zeros, Float, maximum, minimum
+from realtime_visualisation_new import *
+
+#-------
+# Domain
+
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+    """
+    View a mesh and data points with attributes.
+    """
+    import os, sys
+    usage = "usage: %s mesh_input.tsh scale_z"%os.path.basename(sys.argv[0])
+
+    #print len(sys.argv)
+    #print sys.argv
+
+    if len(sys.argv) < 2:
+        print usage
+    else:
+        mesh_file = sys.argv[1]
+
+        scale_z = 1.0
+        if len(sys.argv) > 2:
+            scale_z = float(sys.argv[2])
+
+
+
+    print 'Creating domain from', mesh_file
+    domain = pmesh_to_domain_instance(mesh_file, Domain)
+    print "Number of triangles = ", len(domain)
+
+    visualiser =  Visualiser(domain, scale_z = scale_z)
+    visualiser.update_quantity('stage')
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/weir_domain_refined.tsh
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/weir_domain_refined.tsh	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/weir_domain_refined.tsh	(revision 3560)
@@ -0,0 +1,12603 @@
+1580 0 # <vertex #> <x> <y> [attributes] ...Triangulation Vertices...
+
+0 0.136205637824 0.0726430068393 
+
+1 1.03062265953 0.944359088911 
+
+2 1.20314980078 0.154366389534 
+
+3 1.04878341124 0.0181607517098 
+
+4 0.758211383886 -0.059022443057 
+
+5 0.295112215285 -0.0317813154922 
+
+6 0.51758142373 1.89779855368 
+
+7 0.472179544456 1.77521347964 
+
+8 0.476719732383 1.5209629557 
+
+9 0.549362739223 1.10326566637 
+
+10 0.217929020518 0.0363215034197 
+
+11 0.177067329171 0.767291759741 
+
+12 0.0272411275648 0.753671195958 
+
+13 0.390456161761 0.867175894145 
+
+14 0.308732779067 0.80361326316 
+
+15 0.998841344041 1.68894990901 
+
+16 0.989760968186 1.29849374725 
+
+17 0.417697289326 2.56066599109 
+
+18 0.444938416891 2.73319313233 
+
+19 0.862635706217 2.75135388404 
+
+20 0.435858041036 2.08848644663 
+
+21 1.17136848528 1.86147705026 
+
+22 1.23493111627 2.19745095689 
+
+23 1.21677036456 2.61514824622 
+
+24 1.07148435088 2.76043425989 
+
+25 -0.145151029646 0.445463504777 
+
+26 -0.135140613809 0.505525999803 
+
+27 1.2763280193 0.56058328691 
+
+28 1.31636968265 0.385401009751 
+
+29 1.28133322722 0.250260395942 
+
+30 -0.135140613809 0.385401009751 
+
+31 -0.105109366296 0.320333306806 
+
+32 -0.0200208316754 0.21522394051 
+
+33 0.0600624950261 0.140145821728 
+
+34 0.460479128533 0.885921801635 
+
+35 0.540562455235 0.915953049148 
+
+36 0.56058328691 0.981020752093 
+
+37 1.15119782133 0.780812435339 
+
+38 1.23128114803 0.720749940313 
+
+39 0.30031247513 0.720749940313 
+
+40 0.395411425588 0.715744732394 
+
+41 0.295307267212 0.585609326504 
+
+42 0.390406217669 0.600624950261 
+
+43 0.30031247513 0.450468712696 
+
+44 0.385401009751 0.440458296858 
+
+45 0.290302059293 0.330343722643 
+
+46 0.385401009751 0.315328098887 
+
+47 0.270281227617 0.200208316754 
+
+48 0.355369762238 0.185192692997 
+
+49 0.265276019698 0.105109366296 
+
+50 0.340354138481 0.100104158377 
+
+51 0.47549475229 0.325338514725 
+
+52 0.580604118585 0.315328098887 
+
+53 0.485505168127 0.455473920614 
+
+54 0.585609326504 0.455473920614 
+
+55 0.665692653206 0.455473920614 
+
+56 0.680708276962 0.340354138481 
+
+57 0.960999920417 0.685713484881 
+
+58 1.02606762336 0.685713484881 
+
+59 1.09113532631 0.680708276962 
+
+60 1.15119782133 0.655682237368 
+
+61 1.18623427676 0.585609326504 
+
+62 1.20124990052 0.505525999803 
+
+63 1.20124990052 0.435453088939 
+
+64 1.21626552428 0.330343722643 
+
+65 1.17622386093 0.270281227617 
+
+66 1.08112491047 0.230239564267 
+
+67 1.02106241544 0.230239564267 
+
+68 0.966005128336 0.30031247513 
+
+69 0.971010336255 0.370385385994 
+
+70 1.00104158377 0.420437465183 
+
+71 1.08613011839 0.435453088939 
+
+72 1.1411874055 0.390406217669 
+
+73 1.08112491047 0.335348930562 
+
+74 0.940979088742 0.460479128533 
+
+75 1.09614053423 0.505525999803 
+
+76 1.10114574214 0.56058328691 
+
+77 1.00104158377 0.575598910667 
+
+78 0.910947841229 0.590614534423 
+
+79 1.06110407879 0.615640574017 
+
+80 0.981020752093 0.630656197774 
+
+81 0.825859306609 0.966005128336 
+
+82 0.885921801635 1.00104158377 
+
+83 0.830864514527 1.07111449463 
+
+84 0.855890554122 1.1411874055 
+
+85 0.805838474933 1.21626552428 
+
+86 0.845880138284 1.29134364306 
+
+87 0.785817643258 1.35140613809 
+
+88 0.835869722446 1.44650508854 
+
+89 0.825859306609 1.59165611819 
+
+90 0.830864514527 1.71178110824 
+
+91 0.835869722446 1.82690089038 
+
+92 0.780812435339 1.92199984083 
+
+93 0.850885346203 1.51657799941 
+
+94 0.770802019501 1.43148946479 
+
+95 0.865900969959 1.37142696976 
+
+96 0.705734316556 1.82690089038 
+
+97 0.685713484881 1.72179152408 
+
+98 0.710739524475 1.57664049443 
+
+99 0.710739524475 1.43649467271 
+
+100 0.715744732394 1.32638009849 
+
+101 0.735765564069 1.26131239555 
+
+102 0.750781187826 1.15620302925 
+
+103 0.755786395745 1.07611970255 
+
+104 0.770802019501 1.00604679169 
+
+105 0.95098950458 0.745775979907 
+
+106 0.90594263331 0.745775979907 
+
+107 0.875911385797 0.695723900719 
+
+108 0.865900969959 0.890927009553 
+
+109 0.900937425391 0.825859306609 
+
+110 0.870906177878 0.795828059095 
+
+111 0.660687445287 0.405421841426 
+
+112 0.620645781936 0.400416633507 
+
+113 0.540562455235 0.395411425588 
+
+114 0.470489544371 0.400416633507 
+
+115 0.385401009751 0.400416633507 
+
+116 0.330343722643 0.405421841426 
+
+117 0.265276019698 0.370385385994 
+
+118 0.3453593464 0.370385385994 
+
+119 0.390406217669 0.370385385994 
+
+120 0.435453088939 0.355369762238 
+
+121 0.485505168127 0.365380178075 
+
+122 0.530552039397 0.365380178075 
+
+123 0.590614534423 0.360374970156 
+
+124 0.730760356151 0.385401009751 
+
+125 0.730760356151 0.315328098887 
+
+126 0.740770771988 0.470489544371 
+
+127 0.320333306806 0.550572871072 
+
+128 0.380395801832 0.540562455235 
+
+129 0.240249980104 0.585609326504 
+
+130 0.275286435536 0.64567182153 
+
+131 0.26027081178 0.730760356151 
+
+132 0.230239564267 0.440458296858 
+
+133 0.220229148429 0.385401009751 
+
+134 0.220229148429 0.330343722643 
+
+135 0.225234356348 0.290302059293 
+
+136 0.240249980104 0.240249980104 
+
+137 0.235244772185 0.185192692997 
+
+138 0.220229148429 0.105109366296 
+
+139 0.290302059293 0.285296851374 
+
+140 0.320333306806 0.220229148429 
+
+141 0.305317683049 0.160166653403 
+
+142 0.310322890968 0.0600624950261 
+
+143 0.725755148232 1.49655716773 
+
+144 0.790822851177 1.29885145494 
+
+145 0.765796811582 1.21626552428 
+
+146 0.798330663055 1.15620302925 
+
+147 0.81835149473 1.02106241544 
+
+148 0.873408781838 1.06610928671 
+
+149 0.865900969959 1.23378375199 
+
+150 0.833367118487 0.865900969959 
+
+151 1.04108324712 0.380395801832 
+
+152 1.02606762336 0.340354138481 
+
+153 1.03357543524 0.287799455333 
+
+154 1.10114574214 0.282794247414 
+
+155 1.15119782133 0.325338514725 
+
+156 1.18873688072 0.392908821629 
+
+157 1.14369000945 0.460479128533 
+
+158 1.15620302925 0.523044227519 
+
+159 1.1411874055 0.588111930464 
+
+160 1.1161613659 0.630656197774 
+
+161 1.05109366296 0.563085890869 
+
+162 0.986025960011 0.528049435438 
+
+163 0.953492108539 0.630656197774 
+
+164 0.930968672904 0.528049435438 
+
+165 0.540562455235 0.43295048498 
+
+166 0.545567663154 0.477997356249 
+
+167 0.610635366098 0.483002564168 
+
+168 0.663190049246 0.495515583965 
+
+169 0.723252544272 0.503023395843 
+
+170 0.780812435339 0.513033811681 
+
+171 0.810843682852 0.540562455235 
+
+172 0.838372326406 0.590614534423 
+
+173 0.713242128435 0.43295048498 
+
+174 0.768299415542 0.422940069142 
+
+175 0.793325455136 0.445463504777 
+
+176 0.883419197675 0.545567663154 
+
+177 0.883419197675 0.510531207722 
+
+178 0.903440029351 0.455473920614 
+
+179 0.908445237269 0.405421841426 
+
+180 0.920958257066 0.357872366197 
+
+181 0.928466068945 0.312825494927 
+
+182 0.923460861026 0.26027081178 
+
+183 0.858393158081 0.285296851374 
+
+184 0.853387950162 0.337851534522 
+
+185 0.86089576204 0.402919237467 
+
+186 0.838372326406 0.457976524574 
+
+187 0.830864514527 0.498018187925 
+
+188 0.810843682852 0.412929653304 
+
+189 0.773304623461 0.365380178075 
+
+190 0.823356702649 0.380395801832 
+
+191 0.798330663055 0.327841118684 
+
+192 0.803335870974 0.292804663252 
+
+193 0.638164009652 0.362877574116 
+
+194 0.635661405693 0.327841118684 
+
+195 0.6907186928 0.30281507909 
+
+196 0.628153593814 0.290302059293 
+
+197 0.508028603762 0.30031247513 
+
+198 0.530552039397 0.337851534522 
+
+199 0.593117138382 0.280291643455 
+
+200 0.427945277061 0.315328098887 
+
+201 0.347861950359 0.340354138481 
+
+202 0.332846326603 0.312825494927 
+
+203 0.340354138481 0.265276019698 
+
+204 0.425442673101 0.437955692898 
+
+205 0.445463504777 0.410427049345 
+
+206 0.457976524574 0.455473920614 
+
+207 0.488007772087 0.485505168127 
+
+208 0.583106722545 0.415432257264 
+
+209 0.623148385896 0.440458296858 
+
+210 0.30281507909 0.417934861223 
+
+211 0.252762999901 0.415432257264 
+
+212 0.535557247316 0.315328098887 
+
+213 0.875911385797 0.370385385994 
+
+214 0.888424405594 0.327841118684 
+
+215 0.895932217472 0.297809871171 
+
+216 0.971010336255 0.275286435536 
+
+217 1.00854939565 0.26027081178 
+
+218 0.996036375849 0.315328098887 
+
+219 0.978518148133 0.3453593464 
+
+220 0.958497316458 0.412929653304 
+
+221 0.976015544174 0.460479128533 
+
+222 0.963502524377 0.503023395843 
+
+223 0.943481692701 0.550572871072 
+
+224 0.953492108539 0.593117138382 
+
+225 1.0360780392 0.610635366098 
+
+226 1.02106241544 0.64567182153 
+
+227 1.08112491047 0.638164009652 
+
+228 1.05609887088 0.653179633409 
+
+229 1.09614053423 0.60563015818 
+
+230 1.08112491047 0.575598910667 
+
+231 1.03357543524 0.543065059194 
+
+232 1.05609887088 0.525546831478 
+
+233 1.10615095006 0.470489544371 
+
+234 1.1161613659 0.405421841426 
+
+235 1.08112491047 0.385401009751 
+
+236 1.12116657382 0.352867158278 
+
+237 1.12617178174 0.307820287009 
+
+238 1.06110407879 0.295307267212 
+
+239 1.13618219758 0.277789039496 
+
+240 1.18122906885 0.357872366197 
+
+241 1.16120823717 0.435453088939 
+
+242 1.12366917778 0.435453088939 
+
+243 1.17121865301 0.490510376046 
+
+244 1.13618219758 0.503023395843 
+
+245 1.12617178174 0.533054643356 
+
+246 1.15370042529 0.563085890869 
+
+247 0.685713484881 0.410427049345 
+
+248 0.6907186928 0.382898405791 
+
+249 0.715744732394 0.355369762238 
+
+250 0.745775979907 0.347861950359 
+
+251 0.748278583867 0.275286435536 
+
+252 0.673200465084 0.235244772185 
+
+253 0.550572871072 0.187695296956 
+
+254 0.823356702649 0.170177069241 
+
+255 0.755786395745 0.150156237565 
+
+256 0.90594263331 0.175182277159 
+
+257 0.77580722742 0.64817442549 
+
+258 0.723252544272 0.600624950261 
+
+259 0.630656197774 0.585609326504 
+
+260 0.575598910667 0.665692653206 
+
+261 0.680708276962 0.728257752191 
+
+262 0.760791603664 0.795828059095 
+
+263 0.77580722742 1.04358585108 
+
+264 0.77580722742 1.11115615798 
+
+265 0.758288999704 1.29134364306 
+
+266 0.790822851177 0.955994712498 
+
+267 0.790822851177 0.900937425391 
+
+268 0.805838474933 0.86089576204 
+
+269 0.810843682852 0.82085409869 
+
+270 0.828361910568 0.773304623461 
+
+271 0.835869722446 0.725755148232 
+
+272 0.773304623461 0.760791603664 
+
+273 0.728257752191 0.68821608884 
+
+274 0.723252544272 0.925963464985 
+
+275 0.618143177977 0.850885346203 
+
+276 0.175182277159 0.633158801733 
+
+277 0.190197900916 0.535557247316 
+
+278 0.187695296956 0.480499960209 
+
+279 0.187695296956 0.427945277061 
+
+280 0.162669257362 0.380395801832 
+
+281 0.162669257362 0.315328098887 
+
+282 0.150156237565 0.242752584064 
+
+283 0.157664049443 0.162669257362 
+
+284 0.142648425687 0.678205673003 
+
+285 0.117622386093 0.608132762139 
+
+286 0.122627594012 0.538059851275 
+
+287 0.117622386093 0.47549475229 
+
+288 0.102606762336 0.392908821629 
+
+289 0.0875911385797 0.327841118684 
+
+290 0.0850885346203 0.255265603861 
+
+291 0.0875911385797 0.680708276962 
+
+292 0.0650677029449 0.608132762139 
+
+293 0.0550572871072 0.545567663154 
+
+294 0.0375390593913 0.480499960209 
+
+295 0.030031247513 0.420437465183 
+
+296 0.0125130197971 0.347861950359 
+
+297 0.0125130197971 0.282794247414 
+
+298 0.0325338514725 0.680708276962 
+
+299 0.00250260395942 0.623148385896 
+
+300 -0.0200208316754 0.540562455235 
+
+301 -0.0500520791884 0.47549475229 
+
+302 -0.0250260395942 0.415432257264 
+
+303 -0.0500520791884 0.330343722643 
+
+304 0.235244772185 0.490510376046 
+
+305 0.240249980104 0.535557247316 
+
+306 0.21772654447 0.633158801733 
+
+307 0.232742168226 0.68821608884 
+
+308 0.225234356348 0.743273375948 
+
+309 0.285296851374 0.698226504678 
+
+310 0.325338514725 0.68821608884 
+
+311 0.312825494927 0.633158801733 
+
+312 0.275286435536 0.613137970058 
+
+313 0.267778623658 0.563085890869 
+
+314 0.287799455333 0.490510376046 
+
+315 0.192700504875 0.352867158278 
+
+316 0.197705712794 0.30281507909 
+
+317 0.195203108835 0.252762999901 
+
+318 0.187695296956 0.21522394051 
+
+319 0.207716128632 0.165171861322 
+
+320 0.185192692997 0.12763280193 
+
+321 0.112617178174 0.155161445484 
+
+322 1.12116657382 0.700729108638 
+
+323 1.15370042529 0.700729108638 
+
+324 1.18873688072 0.668195257165 
+
+325 1.1962446926 0.640666613611 
+
+326 1.22377333616 0.588111930464 
+
+327 1.22627594012 0.545567663154 
+
+328 1.23378375199 0.503023395843 
+
+329 1.24129156387 0.450468712696 
+
+330 1.23878895991 0.402919237467 
+
+331 1.22377333616 0.367882782035 
+
+332 1.23628635595 0.635661405693 
+
+333 1.16871604905 0.618143177977 
+
+334 1.21376292032 0.618143177977 
+
+335 1.20625510844 0.703231712597 
+
+336 1.18373167281 0.720749940313 
+
+337 1.13117698966 0.753283791785 
+
+338 1.08613011839 0.748278583867 
+
+339 1.03107283128 0.745775979907 
+
+340 1.00354418773 0.728257752191 
+
+341 1.04608845504 0.715744732394 
+
+342 0.935973880823 0.658184841327 
+
+343 0.90594263331 0.643169217571 
+
+344 0.875911385797 0.623148385896 
+
+345 0.82085409869 0.653179633409 
+
+346 0.848382742243 0.640666613611 
+
+347 0.840874930365 0.695723900719 
+
+348 0.790822851177 0.610635366098 
+
+349 0.698226504678 0.845880138284 
+
+350 0.675703069043 0.920958257066 
+
+351 0.660687445287 1.00354418773 
+
+352 0.64817442549 1.06861189067 
+
+353 0.643169217571 1.13117698966 
+
+354 0.620645781936 1.19374208864 
+
+355 0.625650989855 1.25130197971 
+
+356 0.618143177977 1.30635926682 
+
+357 0.598122346301 1.36642176184 
+
+358 0.558080682951 1.33889311829 
+
+359 0.56058328691 1.27132281139 
+
+360 0.585609326504 1.22877854408 
+
+361 0.583106722545 1.15870563321 
+
+362 0.608132762139 1.08863272235 
+
+363 0.610635366098 1.0360780392 
+
+364 0.618143177977 0.978518148133 
+
+365 0.705734316556 1.09363793027 
+
+366 0.693221296759 1.15870563321 
+
+367 0.6907186928 1.21376292032 
+
+368 0.675703069043 1.2763280193 
+
+369 0.673200465084 1.33388791037 
+
+370 0.670697861124 1.37392957372 
+
+371 0.715744732394 1.02857022732 
+
+372 0.633158801733 0.913450445188 
+
+373 0.658184841327 0.825859306609 
+
+374 0.643169217571 0.770802019501 
+
+375 0.623148385896 0.718247336353 
+
+376 0.580604118585 0.750781187826 
+
+377 0.595619742342 0.803335870974 
+
+378 0.680708276962 0.785817643258 
+
+379 0.73326296011 0.763294207623 
+
+380 0.755786395745 0.725755148232 
+
+381 0.698226504678 0.6907186928 
+
+382 0.653179633409 0.663190049246 
+
+383 0.60312755422 0.633158801733 
+
+384 0.583106722545 0.568091098788 
+
+385 0.595619742342 0.548070267113 
+
+386 0.635661405693 0.528049435438 
+
+387 0.685713484881 0.538059851275 
+
+388 0.740770771988 0.543065059194 
+
+389 0.77580722742 0.568091098788 
+
+390 0.675703069043 0.580604118585 
+
+391 0.68821608884 0.623148385896 
+
+392 0.743273375948 0.64817442549 
+
+393 0.728257752191 0.573096306707 
+
+394 0.783315039298 0.708236920516 
+
+395 0.94848690062 0.798330663055 
+
+396 0.903440029351 0.863398366 
+
+397 0.913450445188 0.935973880823 
+
+398 0.638164009652 0.167674465281 
+
+399 0.748278583867 0.0875911385797 
+
+400 0.848382742243 0.0825859306609 
+
+401 0.64817442549 0.0825859306609 
+
+402 0.575598910667 0.0875911385797 
+
+403 0.525546831478 0.640666613611 
+
+404 0.523044227519 0.765796811582 
+
+405 0.535557247316 0.833367118487 
+
+406 0.208967430612 0.583106722545 
+
+407 0.212721336551 0.510531207722 
+
+408 0.208967430612 0.460479128533 
+
+409 0.197705712794 0.407924445385 
+
+410 0.25776820782 0.335348930562 
+
+411 0.262773415739 0.30031247513 
+
+412 0.267778623658 0.25776820782 
+
+413 0.292804663252 0.223983054368 
+
+414 0.275286435536 0.168925767261 
+
+415 0.155161445484 0.579352816606 
+
+416 0.155161445484 0.504274697823 
+
+417 0.145151029646 0.439206994878 
+
+418 0.12763280193 0.351615856298 
+
+419 0.132638009849 0.291553361272 
+
+420 0.115119782133 0.201459618733 
+
+421 0.319082004826 0.359123668177 
+
+422 0.30031247513 0.385401009751 
+
+423 0.415432257264 0.55933198493 
+
+424 0.342856742441 0.588111930464 
+
+425 0.325338514725 0.485505168127 
+
+426 0.425442673101 0.520541623559 
+
+427 0.425442673101 0.686964786861 
+
+428 0.421688767162 0.765796811582 
+
+429 0.364128876096 0.814597588791 
+
+430 0.365380178075 0.755786395745 
+
+431 0.391657519649 0.660687445287 
+
+432 0.43044788102 0.598122346301 
+
+433 0.436704390919 0.491761678026 
+
+434 0.381647103812 0.26027081178 
+
+435 0.42919657904 0.277789039496 
+
+436 0.405421841426 0.225234356348 
+
+437 0.477997356249 0.261522113759 
+
+438 0.431699183 0.205213524672 
+
+439 0.397914029548 0.17393097518 
+
+440 0.531803341377 0.242752584064 
+
+441 0.513033811681 0.465484336452 
+
+442 0.506777301783 0.422940069142 
+
+443 0.504274697823 0.38915491569 
+
+444 0.505525999803 0.341605440461 
+
+445 0.565588494829 0.335348930562 
+
+446 0.56183458889 0.381647103812 
+
+447 0.564337192849 0.425442673101 
+
+448 0.574347608687 0.514285113661 
+
+449 0.573096306707 0.479248658229 
+
+450 0.638164009652 0.47299214833 
+
+451 0.651928331429 0.43044788102 
+
+452 0.644420519551 0.38915491569 
+
+453 0.663190049246 0.359123668177 
+
+454 0.606881460159 0.336600232542 
+
+455 0.609384064119 0.305317683049 
+
+456 0.654430935388 0.309071588988 
+
+457 0.709488222496 0.330343722643 
+
+458 0.706985618536 0.400416633507 
+
+459 0.708236920516 0.456725222594 
+
+460 0.696975202698 0.479248658229 
+
+461 0.6907186928 0.513033811681 
+
+462 0.654430935388 0.548070267113 
+
+463 0.626902291835 0.56058328691 
+
+464 0.656933539348 0.610635366098 
+
+465 0.636912707672 0.633158801733 
+
+466 0.723252544272 0.533054643356 
+
+467 0.750781187826 0.505525999803 
+
+468 0.764545509603 0.484253866148 
+
+469 0.769550717522 0.450468712696 
+
+470 0.745775979907 0.431699183 
+
+471 0.750781187826 0.404170539446 
+
+472 0.789571549197 0.400416633507 
+
+473 0.799581965035 0.369134084014 
+
+474 0.77830983138 0.340354138481 
+
+475 0.763294207623 0.320333306806 
+
+476 0.763294207623 0.30031247513 
+
+477 0.828361910568 0.317830702846 
+
+478 0.824608004629 0.352867158278 
+
+479 0.835869722446 0.400416633507 
+
+480 0.823356702649 0.439206994878 
+
+481 0.808341078893 0.464233034472 
+
+482 0.805838474933 0.493012980006 
+
+483 0.795828059095 0.534305945336 
+
+484 0.77580722742 0.546818965133 
+
+485 0.752032489806 0.575598910667 
+
+486 0.747027281887 0.599373648281 
+
+487 0.723252544272 0.625650989855 
+
+488 0.700729108638 0.654430935388 
+
+489 0.700729108638 0.60187625224 
+
+490 0.701980410617 0.563085890869 
+
+491 0.599373648281 0.598122346301 
+
+492 0.568091098788 0.620645781936 
+
+493 0.558080682951 0.586860628484 
+
+494 0.554326777011 0.549321569093 
+
+495 0.60312755422 0.514285113661 
+
+496 0.548070267113 0.508028603762 
+
+497 0.549321569093 0.284045549394 
+
+498 0.51553641564 0.262773415739 
+
+499 0.500520791884 0.225234356348 
+
+500 0.544316361174 0.212721336551 
+
+501 0.575598910667 0.238998678125 
+
+502 0.594368440362 0.210218732591 
+
+503 0.608132762139 0.251511697922 
+
+504 0.621897083916 0.200208316754 
+
+505 0.641917915591 0.250260395942 
+
+506 0.64692312351 0.226485658327 
+
+507 0.673200465084 0.196454410814 
+
+508 0.716996034374 0.201459618733 
+
+509 0.699477806658 0.237747376145 
+
+510 0.680708276962 0.275286435536 
+
+511 0.701980410617 0.284045549394 
+
+512 0.73451426209 0.251511697922 
+
+513 0.739519470009 0.220229148429 
+
+514 0.763294207623 0.190197900916 
+
+515 0.780812435339 0.212721336551 
+
+516 0.783315039298 0.242752584064 
+
+517 0.782063737319 0.275286435536 
+
+518 0.758288999704 0.242752584064 
+
+519 0.803335870974 0.197705712794 
+
+520 0.81835149473 0.269029925638 
+
+521 0.850885346203 0.246506490003 
+
+522 0.863398366 0.210218732591 
+
+523 0.854639252142 0.374139291933 
+
+524 0.852136648182 0.43295048498 
+
+525 0.869654875898 0.465484336452 
+
+526 0.86089576204 0.493012980006 
+
+527 0.842126232345 0.529300737417 
+
+528 0.830864514527 0.56058328691 
+
+529 0.809592380872 0.580604118585 
+
+530 0.825859306609 0.626902291835 
+
+531 0.792074153156 0.636912707672 
+
+532 0.759540301684 0.631907499753 
+
+533 0.797079361075 0.683210880922 
+
+534 0.754535093765 0.676954371023 
+
+535 0.843377534324 0.678205673003 
+
+536 0.859644460061 0.613137970058 
+
+537 0.872157479858 0.590614534423 
+
+538 0.878413989756 0.56183458889 
+
+539 0.899686123411 0.51553641564 
+
+540 0.917204351127 0.494264281985 
+
+541 0.925963464985 0.459227826554 
+
+542 0.887173103614 0.431699183 
+
+543 0.934722578843 0.431699183 
+
+544 0.933471276864 0.402919237467 
+
+545 0.885921801635 0.385401009751 
+
+546 0.902188727371 0.354118460258 
+
+547 0.938476484782 0.341605440461 
+
+548 0.942230390722 0.370385385994 
+
+549 0.94723559864 0.311574192948 
+
+550 0.939727786762 0.294055965232 
+
+551 0.915953049148 0.285296851374 
+
+552 0.857141856101 0.311574192948 
+
+553 0.894680915493 0.261522113759 
+
+554 0.912199143209 0.232742168226 
+
+555 0.9497382026 0.223983054368 
+
+556 0.919706955087 0.56183458889 
+
+557 0.914701747168 0.540562455235 
+
+558 0.910947841229 0.624399687875 
+
+559 0.930968672904 0.609384064119 
+
+560 0.914701747168 0.676954371023 
+
+561 0.878413989756 0.668195257165 
+
+562 0.902188727371 0.706985618536 
+
+563 0.94723559864 0.574347608687 
+
+564 0.969759034275 0.564337192849 
+
+565 0.969759034275 0.543065059194 
+
+566 0.979769450113 0.495515583965 
+
+567 0.945984296661 0.493012980006 
+
+568 0.960999920417 0.460479128533 
+
+569 0.984774658032 0.439206994878 
+
+570 0.981020752093 0.410427049345 
+
+571 0.998538979808 0.381647103812 
+
+572 0.86464966798 0.193951806855 
+
+573 0.450468712696 0.30031247513 
+
+574 0.397914029548 0.299061173151 
+
+575 0.365380178075 0.294055965232 
+
+576 0.316579400867 0.292804663252 
+
+577 0.286548153354 0.357872366197 
+
+578 0.377893197872 0.351615856298 
+
+579 0.404170539446 0.3453593464 
+
+580 0.406673143406 0.382898405791 
+
+581 0.412929653304 0.419186163203 
+
+582 0.374139291933 0.421688767162 
+
+583 0.352867158278 0.405421841426 
+
+584 0.371636687974 0.513033811681 
+
+585 0.374139291933 0.636912707672 
+
+586 0.462981732493 0.545567663154 
+
+587 0.459227826554 0.590614534423 
+
+588 0.445463504777 0.638164009652 
+
+589 0.350364554319 0.714493430414 
+
+590 0.280291643455 0.673200465084 
+
+591 0.246506490003 0.661938747267 
+
+592 0.249009093962 0.626902291835 
+
+593 0.227736960307 0.554326777011 
+
+594 0.251511697922 0.467986940411 
+
+595 0.269029925638 0.427945277061 
+
+596 0.241501282084 0.379144499852 
+
+597 0.270281227617 0.394160123609 
+
+598 0.232742168226 0.347861950359 
+
+599 0.235244772185 0.312825494927 
+
+600 0.249009093962 0.275286435536 
+
+601 0.294055965232 0.244003886043 
+
+602 0.319082004826 0.252762999901 
+
+603 0.347861950359 0.235244772185 
+
+604 0.30281507909 0.191449202896 
+
+605 0.218977846449 0.223983054368 
+
+606 0.17142837122 0.275286435536 
+
+607 0.17142837122 0.220229148429 
+
+608 0.372887989954 0.231490866246 
+
+609 0.38915491569 0.211470034571 
+
+610 0.43295048498 0.238998678125 
+
+611 0.471740846351 0.21647524249 
+
+612 0.450468712696 0.341605440461 
+
+613 0.471740846351 0.504274697823 
+
+614 0.494264281985 0.534305945336 
+
+615 0.464233034472 0.267778623658 
+
+616 0.47424345031 0.185192692997 
+
+617 0.427945277061 0.176433579139 
+
+618 0.523044227519 0.196454410814 
+
+619 0.588111930464 0.182690089038 
+
+620 0.520541623559 0.505525999803 
+
+621 0.521792925539 0.556829380971 
+
+622 0.489259074067 0.566839796809 
+
+623 1.00479548971 0.455473920614 
+
+624 1.02731892534 0.51929032158 
+
+625 1.02731892534 0.583106722545 
+
+626 1.00604679169 0.60312755422 
+
+627 0.979769450113 0.60187625224 
+
+628 0.998538979808 0.631907499753 
+
+629 0.99353377189 0.664441351226 
+
+630 0.988528563971 0.703231712597 
+
+631 0.963502524377 0.718247336353 
+
+632 0.932219974884 0.716996034374 
+
+633 0.743273375948 0.86214706402 
+
+634 0.684462182901 0.132638009849 
+
+635 0.551824173052 0.136391915788 
+
+636 0.610635366098 0.132638009849 
+
+637 0.807089776913 0.113868480154 
+
+638 0.334097628583 0.201459618733 
+
+639 0.361626272136 0.210218732591 
+
+640 0.376641895893 0.158915351423 
+
+641 0.347861950359 0.162669257362 
+
+642 0.414180955284 0.153910143504 
+
+643 0.455473920614 0.161417955383 
+
+644 0.236496074165 0.161417955383 
+
+645 0.275286435536 0.147653633606 
+
+646 0.297809871171 0.147653633606 
+
+647 0.325338514725 0.141397123707 
+
+648 0.351615856298 0.137643217768 
+
+649 0.372887989954 0.136391915788 
+
+650 0.402919237467 0.132638009849 
+
+651 0.43295048498 0.13138670787 
+
+652 0.470489544371 0.132638009849 
+
+653 0.503023395843 0.162669257362 
+
+654 0.395411425588 0.276537737516 
+
+655 0.406673143406 0.2590195098 
+
+656 0.43295048498 0.385401009751 
+
+657 0.455473920614 0.382898405791 
+
+658 0.447966108736 0.434201786959 
+
+659 0.47299214833 0.42919657904 
+
+660 0.457976524574 0.479248658229 
+
+661 0.434201786959 0.466735638432 
+
+662 0.449217410716 0.523044227519 
+
+663 0.544316361174 0.456725222594 
+
+664 0.514285113661 0.449217410716 
+
+665 0.5180390196 0.406673143406 
+
+666 0.538059851275 0.415432257264 
+
+667 0.573096306707 0.400416633507 
+
+668 0.595619742342 0.384149707771 
+
+669 0.619394479956 0.377893197872 
+
+670 0.616891875997 0.427945277061 
+
+671 0.673200465084 0.382898405791 
+
+672 0.6907186928 0.360374970156 
+
+673 0.670697861124 0.324087212745 
+
+674 0.650677029449 0.341605440461 
+
+675 0.624399687875 0.351615856298 
+
+676 0.56183458889 0.355369762238 
+
+677 0.555578078991 0.310322890968 
+
+678 0.571845004727 0.284045549394 
+
+679 0.565588494829 0.26027081178 
+
+680 0.539311153255 0.26027081178 
+
+681 0.524295529498 0.285296851374 
+
+682 0.658184841327 0.276537737516 
+
+683 0.641917915591 0.269029925638 
+
+684 0.705734316556 0.25776820782 
+
+685 0.724503846252 0.281542945435 
+
+686 0.606881460159 0.272783831577 
+
+687 0.686964786861 0.435453088939 
+
+688 0.714493430414 0.419186163203 
+
+689 0.636912707672 0.452971316655 
+
+690 0.613137970058 0.462981732493 
+
+691 0.598122346301 0.439206994878 
+
+692 0.600624950261 0.415432257264 
+
+693 0.638164009652 0.416683559243 
+
+694 0.685713484881 0.457976524574 
+
+695 0.661938747267 0.476746054269 
+
+696 0.634410103713 0.498018187925 
+
+697 1.05985277681 0.681959578942 
+
+698 1.08237621245 0.706985618536 
+
+699 1.11240745996 0.724503846252 
+
+700 1.1286743857 0.681959578942 
+
+701 1.10740225204 0.658184841327 
+
+702 1.14744391539 0.633158801733 
+
+703 1.12617178174 0.60563015818 
+
+704 1.17997776687 0.565588494829 
+
+705 1.18748557874 0.534305945336 
+
+706 1.12742308372 0.555578078991 
+
+707 1.11991527184 0.578101514626 
+
+708 1.08362751443 0.531803341377 
+
+709 1.07111449463 0.499269489904 
+
+710 1.09113532631 0.486756470107 
+
+711 1.03858064316 0.407924445385 
+
+712 1.06736058869 0.410427049345 
+
+713 1.09488923225 0.415432257264 
+
+714 1.14619261341 0.420437465183 
+
+715 1.17747516291 0.415432257264 
+
+716 1.18248037083 0.466735638432 
+
+717 1.21000901438 0.47549475229 
+
+718 1.21876812824 0.528049435438 
+
+719 1.19749599458 0.56183458889 
+
+720 1.18748557874 0.611886668078 
+
+721 1.16996735103 0.650677029449 
+
+722 1.16871604905 0.686964786861 
+
+723 1.15495172727 0.728257752191 
+
+724 1.05985277681 0.724503846252 
+
+725 1.11866396986 0.376641895893 
+
+726 1.07987360849 0.367882782035 
+
+727 1.04483715306 0.364128876096 
+
+728 1.16746474707 0.376641895893 
+
+729 1.17622386093 0.339102836501 
+
+730 1.14243870748 0.34410804442 
+
+731 1.10489964808 0.326589816704 
+
+732 1.07862230651 0.312825494927 
+
+733 1.05359626692 0.329092420664 
+
+734 1.05359626692 0.351615856298 
+
+735 0.715744732394 0.484253866148 
+
+736 0.737016866049 0.457976524574 
+
+737 0.727006450211 0.436704390919 
+
+738 0.73326296011 0.414180955284 
+
+739 0.759540301684 0.381647103812 
+
+740 0.735765564069 0.365380178075 
+
+741 0.793325455136 0.483002564168 
+
+742 0.790822851177 0.425442673101 
+
+743 0.81835149473 0.336600232542 
+
+744 0.829613212548 0.295307267212 
+
+745 0.837121024426 0.267778623658 
+
+746 0.808341078893 0.246506490003 
+
+747 0.795828059095 0.261522113759 
+
+748 0.614389272038 0.227736960307 
+
+749 0.576850212646 0.222731752388 
+
+750 0.491761678026 0.0838372326406 
+
+751 0.411678351325 0.0863398366 
+
+752 0.409175747365 0.0337851534522 
+
+753 0.531803341377 0.0187695296956 
+
+754 0.6907186928 0.0125130197971 
+
+755 0.815848890771 0.0212721336551 
+
+756 0.485505168127 0.624399687875 
+
+757 0.183941391017 0.718247336353 
+
+758 0.107611970255 0.727006450211 
+
+759 0.498018187925 0.509279905742 
+
+760 0.523044227519 0.594368440362 
+
+761 0.489259074067 0.414180955284 
+
+762 0.494264281985 0.341605440461 
+
+763 0.466735638432 0.350364554319 
+
+764 0.485505168127 0.291553361272 
+
+765 0.499269489904 0.246506490003 
+
+766 0.499269489904 0.195203108835 
+
+767 0.564337192849 0.455473920614 
+
+768 0.528049435438 0.531803341377 
+
+769 0.56058328691 0.536808549296 
+
+770 0.536808549296 0.576850212646 
+
+771 1.31261577672 0.256516905841 
+
+772 0.459227826554 0.241501282084 
+
+773 0.466735638432 0.296558569191 
+
+774 0.508028603762 0.366631480055 
+
+775 0.47424345031 0.381647103812 
+
+776 0.452971316655 0.362877574116 
+
+777 0.489259074067 0.392908821629 
+
+778 0.524295529498 0.38790361371 
+
+779 0.545567663154 0.372887989954 
+
+780 0.546818965133 0.349113252339 
+
+781 0.508028603762 0.321584608785 
+
+782 0.424191371122 0.335348930562 
+
+783 0.451720014675 0.321584608785 
+
+784 0.420437465183 0.365380178075 
+
+785 0.421688767162 0.399165331527 
+
+786 0.404170539446 0.322835910765 
+
+787 0.416683559243 0.30031247513 
+
+788 0.586860628484 0.337851534522 
+
+789 0.578101514626 0.377893197872 
+
+790 0.520541623559 0.436704390919 
+
+791 0.494264281985 0.439206994878 
+
+792 0.506777301783 0.485505168127 
+
+793 0.530552039397 0.495515583965 
+
+794 0.556829380971 0.491761678026 
+
+795 0.585609326504 0.496766885945 
+
+796 0.558080682951 0.409175747365 
+
+797 0.480499960209 0.312825494927 
+
+798 0.447966108736 0.279040341475 
+
+799 0.442960900817 0.26027081178 
+
+800 0.494264281985 0.272783831577 
+
+801 0.594368440362 0.315328098887 
+
+802 1.05735017285 0.590614534423 
+
+803 1.01105199961 0.554326777011 
+
+804 1.07361709859 0.553075475032 
+
+805 1.07987360849 0.594368440362 
+
+806 1.109904856 0.530552039397 
+
+807 0.0575598910667 0.711990826455 
+
+808 0.0450468712696 0.644420519551 
+
+809 0.0275286435536 0.578101514626 
+
+810 0.00750781187826 0.5180390196 
+
+811 -0.00625650989855 0.455473920614 
+
+812 -0.0100104158377 0.382898405791 
+
+813 -0.0200208316754 0.30281507909 
+
+814 0.0400416633507 0.21772654447 
+
+815 0.0425442673101 0.309071588988 
+
+816 0.0550572871072 0.374139291933 
+
+817 0.0650677029449 0.445463504777 
+
+818 0.0825859306609 0.513033811681 
+
+819 0.0913450445188 0.570593702748 
+
+820 0.0976015544174 0.640666613611 
+
+821 0.186443994977 0.675703069043 
+
+822 0.147653633606 0.639415311632 
+
+823 0.160166653403 0.540562455235 
+
+824 0.147653633606 0.466735638432 
+
+825 0.133889311829 0.400416633507 
+
+826 0.112617178174 0.309071588988 
+
+827 0.121376292032 0.254014301881 
+
+828 0.163920559342 0.347861950359 
+
+829 0.167674465281 0.445463504777 
+
+830 0.182690089038 0.576850212646 
+
+831 0.210218732591 0.661938747267 
+
+832 0.220229148429 0.709488222496 
+
+833 0.152658841525 0.709488222496 
+
+834 0.111365876194 0.675703069043 
+
+835 0.0888424405594 0.421688767162 
+
+836 0.0863398366 0.466735638432 
+
+837 0.0588111930464 0.499269489904 
+
+838 0.103858064316 0.51929032158 
+
+839 0.0237747376145 0.394160123609 
+
+840 0.0638164009652 0.34661064838 
+
+841 -0.00875911385797 0.485505168127 
+
+842 0.00875911385797 0.556829380971 
+
+843 -0.0187695296956 0.591865836403 
+
+844 -0.0437955692898 0.511782509701 
+
+845 -0.0488007772087 0.401667935487 
+
+846 -0.0450468712696 0.369134084014 
+
+847 -0.0162669257362 0.336600232542 
+
+848 0.0325338514725 0.25776820782 
+
+849 0.0575598910667 0.280291643455 
+
+850 0.0750781187826 0.406673143406 
+
+851 0.0938476484782 0.361626272136 
+
+852 0.341605440461 0.618143177977 
+
+853 0.340354138481 0.654430935388 
+
+854 0.320333306806 0.588111930464 
+
+855 0.370385385994 0.380395801832 
+
+856 0.317830702846 0.330343722643 
+
+857 0.350364554319 0.311574192948 
+
+858 0.342856742441 0.287799455333 
+
+859 0.364128876096 0.274035133556 
+
+860 0.364128876096 0.450468712696 
+
+861 0.407924445385 0.455473920614 
+
+862 0.575598910667 0.359123668177 
+
+863 0.606881460159 0.365380178075 
+
+864 0.596871044322 0.400416633507 
+
+865 0.570593702748 0.445463504777 
+
+866 0.554326777011 0.440458296858 
+
+867 0.581855420565 0.434201786959 
+
+868 0.523044227519 0.420437465183 
+
+869 0.505525999803 0.404170539446 
+
+870 0.461730430513 0.416683559243 
+
+871 0.451720014675 0.397914029548 
+
+872 0.470489544371 0.370385385994 
+
+873 0.476746054269 0.341605440461 
+
+874 0.531803341377 0.305317683049 
+
+875 0.543065059194 0.299061173151 
+
+876 0.568091098788 0.30031247513 
+
+877 0.546818965133 0.327841118684 
+
+878 0.524295529498 0.354118460258 
+
+879 0.520541623559 0.330343722643 
+
+880 0.615640574017 0.321584608785 
+
+881 0.633158801733 0.310322890968 
+
+882 0.625650989855 0.340354138481 
+
+883 0.609384064119 0.351615856298 
+
+884 0.650677029449 0.374139291933 
+
+885 0.628153593814 0.38665231173 
+
+886 0.650677029449 0.294055965232 
+
+887 0.674451767064 0.294055965232 
+
+888 0.591865836403 0.264024717719 
+
+889 0.545567663154 0.274035133556 
+
+890 1.04733975702 0.203962222693 
+
+891 0.998538979808 0.178936183099 
+
+892 0.942230390722 0.140145821728 
+
+893 0.979769450113 0.191449202896 
+
+894 0.982272054072 0.247757791983 
+
+895 1.03732934118 0.251511697922 
+
+896 0.996036375849 0.281542945435 
+
+897 1.12992568768 0.245255188023 
+
+898 1.08362751443 0.251511697922 
+
+899 1.07361709859 0.200208316754 
+
+900 1.05985277681 0.222731752388 
+
+901 0.99103116793 0.21397263853 
+
+902 0.940979088742 0.186443994977 
+
+903 0.661938747267 0.392908821629 
+
+904 0.593117138382 0.476746054269 
+
+905 0.671949163104 0.425442673101 
+
+906 0.327841118684 0.531803341377 
+
+907 0.351615856298 0.556829380971 
+
+908 0.374139291933 0.568091098788 
+
+909 0.451720014675 0.611886668078 
+
+910 0.2590195098 0.0513033811681 
+
+911 0.312825494927 0.00750781187826 
+
+912 0.406673143406 -0.00500520791884 
+
+913 0.0638164009652 0.181438787058 
+
+914 0.146402331626 0.111365876194 
+
+915 0.203962222693 0.0675703069043 
+
+916 0.969759034275 0.0713242128435 
+
+917 0.849634044223 0.565588494829 
+
+918 0.863398366 0.529300737417 
+
+919 0.889675707574 0.488007772087 
+
+920 0.885921801635 0.459227826554 
+
+921 1.11115615798 0.0675703069043 
+
+922 0.579352816606 -0.0187695296956 
+
+923 0.649425727469 -0.0312825494927 
+
+924 0.580604118585 0.038790361371 
+
+925 0.636912707672 0.0400416633507 
+
+926 0.454222618635 0.047549475229 
+
+927 0.520541623559 0.0450468712696 
+
+928 0.445463504777 -0.00375390593913 
+
+929 0.513033811681 -0.0150156237565 
+
+930 0.723252544272 -0.0162669257362 
+
+931 0.742022073968 0.0262773415739 
+
+932 0.699477806658 0.0437955692898 
+
+933 0.60312755422 0.00500520791884 
+
+934 0.369134084014 0.0675703069043 
+
+935 0.360374970156 0.0212721336551 
+
+936 0.355369762238 -0.0100104158377 
+
+937 0.500520791884 0.0137643217768 
+
+938 0.523044227519 0.112617178174 
+
+939 0.608132762139 0.106360668275 
+
+940 0.694472598739 0.103858064316 
+
+941 0.772053321481 0.112617178174 
+
+942 0.788320247217 0.077580722742 
+
+943 0.447966108736 0.0888424405594 
+
+944 0.30406638107 0.0963502524377 
+
+945 0.86089576204 0.126381499951 
+
+946 0.908445237269 0.0400416633507 
+
+947 0.296558569191 0.548070267113 
+
+948 0.269029925638 0.534305945336 
+
+949 0.237747376145 0.510531207722 
+
+950 0.208967430612 0.485505168127 
+
+951 0.21522394051 0.427945277061 
+
+952 0.356621064217 0.356621064217 
+
+953 0.350364554319 0.38790361371 
+
+954 0.325338514725 0.385401009751 
+
+955 0.330343722643 0.351615856298 
+
+956 0.30406638107 0.3453593464 
+
+957 0.299061173151 0.314076796907 
+
+958 0.275286435536 0.315328098887 
+
+959 0.362877574116 0.329092420664 
+
+960 0.315328098887 0.276537737516 
+
+961 0.290302059293 0.265276019698 
+
+962 0.218977846449 0.262773415739 
+
+963 0.249009093962 0.264024717719 
+
+964 0.246506490003 0.296558569191 
+
+965 0.220229148429 0.360374970156 
+
+966 0.228988262287 0.410427049345 
+
+967 0.192700504875 0.381647103812 
+
+968 0.309071588988 0.435453088939 
+
+969 0.271532529597 0.445463504777 
+
+970 0.233993470206 0.460479128533 
+
+971 0.279040341475 0.476746054269 
+
+972 0.26027081178 0.493012980006 
+
+973 0.30406638107 0.503023395843 
+
+974 0.329092420664 0.506777301783 
+
+975 0.361626272136 0.476746054269 
+
+976 0.377893197872 0.496766885945 
+
+977 0.395411425588 0.485505168127 
+
+978 0.417934861223 0.494264281985 
+
+979 0.401667935487 0.407924445385 
+
+980 0.352867158278 0.425442673101 
+
+981 0.331595024623 0.422940069142 
+
+982 0.324087212745 0.456725222594 
+
+983 0.312825494927 0.401667935487 
+
+984 0.287799455333 0.409175747365 
+
+985 0.289050757313 0.43044788102 
+
+986 0.30281507909 0.366631480055 
+
+987 0.276537737516 0.3453593464 
+
+988 0.315328098887 0.312825494927 
+
+989 0.297809871171 0.30281507909 
+
+990 0.269029925638 0.286548153354 
+
+991 0.284045549394 0.25776820782 
+
+992 0.307820287009 0.262773415739 
+
+993 0.327841118684 0.269029925638 
+
+994 0.334097628583 0.250260395942 
+
+995 0.317830702846 0.240249980104 
+
+996 0.356621064217 0.255265603861 
+
+997 0.379144499852 0.247757791983 
+
+998 0.407924445385 0.247757791983 
+
+999 0.414180955284 0.279040341475 
+
+1000 0.376641895893 0.30156377711 
+
+1001 0.379144499852 0.334097628583 
+
+1002 0.391657519649 0.245255188023 
+
+1003 0.420437465183 0.227736960307 
+
+1004 0.425442673101 0.252762999901 
+
+1005 0.445463504777 0.232742168226 
+
+1006 0.457976524574 0.21772654447 
+
+1007 0.47549475229 0.232742168226 
+
+1008 0.414180955284 0.205213524672 
+
+1009 0.399165331527 0.195203108835 
+
+1010 0.379144499852 0.190197900916 
+
+1011 0.349113252339 0.201459618733 
+
+1012 0.34661064838 0.218977846449 
+
+1013 0.316579400867 0.205213524672 
+
+1014 0.299061173151 0.211470034571 
+
+1015 0.30156377711 0.230239564267 
+
+1016 0.270281227617 0.236496074165 
+
+1017 0.267778623658 0.220229148429 
+
+1018 0.317830702846 0.182690089038 
+
+1019 0.335348930562 0.177684881119 
+
+1020 0.370385385994 0.207716128632 
+
+1021 0.427945277061 0.190197900916 
+
+1022 0.450468712696 0.190197900916 
+
+1023 0.469238242391 0.201459618733 
+
+1024 0.437955692898 0.21772654447 
+
+1025 0.486756470107 0.203962222693 
+
+1026 0.511782509701 0.208967430612 
+
+1027 0.529300737417 0.231490866246 
+
+1028 0.51929032158 0.21772654447 
+
+1029 0.520541623559 0.242752584064 
+
+1030 0.504274697823 0.26027081178 
+
+1031 0.509279905742 0.279040341475 
+
+1032 0.499269489904 0.292804663252 
+
+1033 0.495515583965 0.320333306806 
+
+1034 0.553075475032 0.236496074165 
+
+1035 0.569342400768 0.202710920713 
+
+1036 0.525546831478 0.182690089038 
+
+1037 0.495515583965 0.178936183099 
+
+1038 0.558080682951 0.163920559342 
+
+1039 0.614389272038 0.188946598936 
+
+1040 0.630656197774 0.21772654447 
+
+1041 0.593117138382 0.237747376145 
+
+1042 0.585609326504 0.291553361272 
+
+1043 0.624399687875 0.277789039496 
+
+1044 0.624399687875 0.255265603861 
+
+1045 0.631907499753 0.235244772185 
+
+1046 0.649425727469 0.205213524672 
+
+1047 0.669446559145 0.1726796732 
+
+1048 0.703231712597 0.165171861322 
+
+1049 0.696975202698 0.201459618733 
+
+1050 0.678205673003 0.226485658327 
+
+1051 0.684462182901 0.251511697922 
+
+1052 0.668195257165 0.2590195098 
+
+1053 0.719498638333 0.227736960307 
+
+1054 0.730760356151 0.175182277159 
+
+1055 0.724503846252 0.12888410391 
+
+1056 0.650677029449 0.12888410391 
+
+1057 0.509279905742 0.12888410391 
+
+1058 0.43044788102 0.30156377711 
+
+1059 0.444212202797 0.331595024623 
+
+1060 0.381021452822 0.287173804343 
+
+1061 0.410427049345 0.290302059293 
+
+1062 0.436704390919 0.291553361272 
+
+1063 0.467986940411 0.284045549394 
+
+1064 0.477997356249 0.249009093962 
+
+1065 0.455473920614 0.255891254851 
+
+1066 0.422940069142 0.264650368709 
+
+1067 0.402293586477 0.270281227617 
+
+1068 0.38915491569 0.233993470206 
+
+1069 0.417934861223 0.21647524249 
+
+1070 0.564337192849 0.272783831577 
+
+1071 0.549947220082 0.25776820782 
+
+1072 0.56183458889 0.248383442972 
+
+1073 0.579352816606 0.254639952871 
+
+1074 0.578727165616 0.268404274648 
+
+1075 0.588737581454 0.310948541958 
+
+1076 0.570593702748 0.323461561755 
+
+1077 0.588111930464 0.324087212745 
+
+1078 0.60375320521 0.328466769674 
+
+1079 0.626902291835 0.304692032059 
+
+1080 0.611886668078 0.289676408303 
+
+1081 0.56246023988 0.368508433025 
+
+1082 0.547444616123 0.360374970156 
+
+1083 0.5180390196 0.376016244903 
+
+1084 0.541188106225 0.384775358761 
+
+1085 0.55995763592 0.396037076578 
+
+1086 0.501772093864 0.379144499852 
+
+1087 0.493638630996 0.355369762238 
+
+1088 0.456099571604 0.372262338964 
+
+1089 0.436704390919 0.371636687974 
+
+1090 0.413555304294 0.354744111248 
+
+1091 0.399165331527 0.357872366197 
+
+1092 0.391031868659 0.337225883532 
+
+1093 0.442960900817 0.312825494927 
+
+1094 0.469863893381 0.311574192948 
+
+1095 0.493638630996 0.305943334039 
+
+1096 0.508654254752 0.311574192948 
+
+1097 0.463607383483 0.332220675613 
+
+1098 0.483002564168 0.272783831577 
+
+1099 0.491136027036 0.250886046932 
+
+1100 0.489259074067 0.233993470206 
+
+1101 0.506151650793 0.236496074165 
+
+1102 0.525546831478 0.25839385881 
+
+1103 0.532428992367 0.274660784546 
+
+1104 0.535557247316 0.294055965232 
+
+1105 0.51929032158 0.30093812612 
+
+1106 0.523044227519 0.319707655816 
+
+1107 0.549947220082 0.319082004826 
+
+1108 0.555578078991 0.296558569191 
+
+1109 0.546193314143 0.242752584064 
+
+1110 0.543690710184 0.231490866246 
+
+1111 0.56058328691 0.229613913277 
+
+1112 0.55870633394 0.213346987541 
+
+1113 0.585609326504 0.21710089348 
+
+1114 0.598747997291 0.225234356348 
+
+1115 0.610635366098 0.2158495915 
+
+1116 0.612512319068 0.240875631094 
+
+1117 0.606255809169 0.203336571703 
+
+1118 0.586860628484 0.198957014774 
+
+1119 0.572470655717 0.192074853885 
+
+1120 0.545567663154 0.200833967743 
+
+1121 0.503023395843 0.2158495915 
+
+1122 0.554326777011 0.337225883532 
+
+1123 0.556203729981 0.320958957796 
+
+1124 0.629404895794 0.327215467694 
+
+1125 0.643794868561 0.315953749877 
+
+1126 0.653805284398 0.325338514725 
+
+1127 0.663815700236 0.335348930562 
+
+1128 0.672574814094 0.350364554319 
+
+1129 0.677580022013 0.365380178075 
+
+1130 0.69196999478 0.373513640943 
+
+1131 0.706985618536 0.371636687974 
+
+1132 0.723252544272 0.366005829065 
+
+1133 0.725755148232 0.352241507288 
+
+1134 0.723878195262 0.339102836501 
+
+1135 0.706985618536 0.34410804442 
+
+1136 0.696349551709 0.34348239343 
+
+1137 0.6907186928 0.330969373633 
+
+1138 0.687590437851 0.322835910765 
+
+1139 0.682585229932 0.313451145917 
+
+1140 0.671323512114 0.308445937998 
+
+1141 0.660687445287 0.3021894281 
+
+1142 0.662564398256 0.292804663252 
+
+1143 0.665692653206 0.284671200384 
+
+1144 0.668195257165 0.275912086526 
+
+1145 0.661313096277 0.265901670688 
+
+1146 0.658184841327 0.25839385881 
+
+1147 0.657559190338 0.250260395942 
+
+1148 0.658184841327 0.238373027135 
+
+1149 0.660687445287 0.233367819216 
+
+1150 0.698226504678 0.325338514725 
+
+1151 0.701980410617 0.314702447897 
+
+1152 0.706359967546 0.309071588988 
+
+1153 0.700729108638 0.30156377711 
+
+1154 0.695098249729 0.292804663252 
+
+1155 0.69134434379 0.284045549394 
+
+1156 0.693846947749 0.275912086526 
+
+1157 0.695098249729 0.266527321678 
+
+1158 0.696349551709 0.256516905841 
+
+1159 0.694472598739 0.245880839013 
+
+1160 0.69196999478 0.234619121196 
+
+1161 0.735765564069 0.34661064838 
+
+1162 0.729509054171 0.330969373633 
+
+1163 0.722626893282 0.325338514725 
+
+1164 0.720749940313 0.313451145917 
+
+1165 0.718247336353 0.298435522161 
+
+1166 0.718872987343 0.282794247414 
+
+1167 0.720749940313 0.271532529597 
+
+1168 0.722626893282 0.25964516079 
+
+1169 0.724503846252 0.249634744952 
+
+1170 0.746401630897 0.335974581552 
+
+1171 0.742647724958 0.317830702846 
+
+1172 0.740770771988 0.30281507909 
+
+1173 0.741396422978 0.290302059293 
+
+1174 0.737016866049 0.280291643455 
+
+1175 0.738893819019 0.270906878607 
+
+1176 0.701354759627 0.42982223003 
+
+1177 0.703857363587 0.416057908254 
+
+1178 0.712616477445 0.409175747365 
+
+1179 0.725129497242 0.400416633507 
+
+1180 0.737642517039 0.396037076578 
+
+1181 0.69196999478 0.400416633507 
+
+1182 0.701980410617 0.38978056668 
+
+1183 0.712616477445 0.384775358761 
+
+1184 0.730134705161 0.377893197872 
+
+1185 0.745150328917 0.374764942923 
+
+1186 0.659436143307 0.442335249827 
+
+1187 0.673200465084 0.442960900817 
+
+1188 0.685087833891 0.445463504777 
+
+1189 0.696349551709 0.445463504777 
+
+1190 0.718247336353 0.443586551807 
+
+1191 0.740145120998 0.443586551807 
+
+1192 0.757663348714 0.440458296858 
+
+1193 0.626902291835 0.43232483399 
+
+1194 0.641292264601 0.422940069142 
+
+1195 0.660061794297 0.417934861223 
+
+1196 0.672574814094 0.413555304294 
+
+1197 0.644420519551 0.466735638432 
+
+1198 0.665692653206 0.466109987442 
+
+1199 0.676328720033 0.468612591401 
+
+1200 0.699477806658 0.469238242391 
+
+1201 0.713242128435 0.471115195361 
+
+1202 0.656933539348 0.485505168127 
+
+1203 0.675077418053 0.489884725056 
+
+1204 0.695098249729 0.494264281985 
+
+1205 0.708236920516 0.493638630996 
+
+1206 0.729509054171 0.491761678026 
+
+1207 0.640666613611 0.51616206663 
+
+1208 0.658184841327 0.51678771762 
+
+1209 0.675077418053 0.51866467059 
+
+1210 0.697600853688 0.5180390196 
+
+1211 0.716370383384 0.51678771762 
+
+1212 0.625650989855 0.412929653304 
+
+1213 0.615014923027 0.451720014675 
+
+1214 0.624399687875 0.478623007239 
+
+1215 0.620645781936 0.498643838914 
+
+1216 0.544942012164 0.158289700433 
+
+1217 0.599373648281 0.297809871171 
+
+1218 0.608132762139 0.390406217669 
+
+1219 0.626902291835 0.366631480055 
+
+1220 0.643169217571 0.352867158278 
+
+1221 0.639415311632 0.402919237467 
+
+1222 0.640666613611 0.279040341475 
+
+1223 0.616891875997 0.271532529597 
+
+1224 0.534305945336 0.208967430612 
+
+1225 0.411678351325 0.317830702846 
+
+1226 0.422940069142 0.324087212745 
+
+1227 0.355369762238 0.297809871171 
+
+1228 0.357872366197 0.241501282084 
+
+1229 0.412929653304 0.177684881119 
+
+1230 0.434201786959 0.161417955383 
+
+1231 0.459227826554 0.178936183099 
+
+1232 0.481751262188 0.163920559342 
+
+1233 0.47549475229 0.152658841525 
+
+1234 0.450468712696 0.146402331626 
+
+1235 0.503023395843 0.145151029646 
+
+1236 0.525546831478 0.166423163301 
+
+1237 0.528049435438 0.147653633606 
+
+1238 0.569342400768 0.150156237565 
+
+1239 0.583106722545 0.166423163301 
+
+1240 0.606881460159 0.17142837122 
+
+1241 0.628153593814 0.152658841525 
+
+1242 0.600624950261 0.151407539545 
+
+1243 0.580604118585 0.137643217768 
+
+1244 0.626902291835 0.133889311829 
+
+1245 0.656933539348 0.153910143504 
+
+1246 0.64692312351 0.187695296956 
+
+1247 0.626902291835 0.185192692997 
+
+1248 0.666943955185 0.210218732591 
+
+1249 0.663190049246 0.188946598936 
+
+1250 0.392283170639 0.149530586575 
+
+1251 0.386026660741 0.110114574214 
+
+1252 0.457976524574 0.106986319265 
+
+1253 0.556829380971 0.107611970255 
+
+1254 0.546193314143 0.0794576757116 
+
+1255 0.55870633394 0.181438787058 
+
+1256 0.679456974982 0.153910143504 
+
+1257 0.700729108638 0.181438787058 
+
+1258 0.716996034374 0.153284492514 
+
+1259 0.763294207623 0.165797512312 
+
+1260 0.747027281887 0.181438787058 
+
+1261 0.755786395745 0.208967430612 
+
+1262 0.785817643258 0.17142837122 
+
+1263 0.737642517039 0.111991527184 
+
+1264 0.716370383384 0.081960279671 
+
+1265 0.678205673003 0.0700729108638 
+
+1266 0.582481071555 0.0613137970058 
+
+1267 0.435453088939 0.0600624950261 
+
+1268 0.668195257165 2.00708837545 
+
+1269 0.600624950261 1.4615207123 
+
+1270 0.625650989855 2.35495032581 
+
+1271 0.635661405693 2.63524196927 
+
+1272 0.910947841229 2.62022634551 
+
+1273 0.913450445188 2.30740085059 
+
+1274 0.900937425391 1.98957014774 
+
+1275 0.417934861223 0.197705712794 
+
+1276 0.747027281887 0.490510376046 
+
+1277 0.757037697724 0.464858685462 
+
+1278 0.77643287841 0.466109987442 
+
+1279 0.780186784349 0.435453088939 
+
+1280 0.755786395745 0.414180955284 
+
+1281 0.77768418039 0.411678351325 
+
+1282 0.77580722742 0.396662727568 
+
+1283 0.786443294248 0.381021452822 
+
+1284 0.788320247217 0.355369762238 
+
+1285 0.789571549197 0.334723279572 
+
+1286 0.785817643258 0.312825494927 
+
+1287 0.785191992268 0.289676408303 
+
+1288 0.767673764552 0.279040341475 
+
+1289 0.758288999704 0.359123668177 
+
+1290 0.763294207623 0.339728487491 
+
+1291 0.764545509603 0.263399066729 
+
+1292 0.770176368511 0.232116517236 
+
+1293 0.746401630897 0.228988262287 
+
+1294 0.793325455136 0.225860007338 
+
+1295 0.788320247217 0.196454410814 
+
+1296 0.780812435339 0.182064438048 
+
+1297 0.744524677927 0.197080061804 
+
+1298 0.722626893282 0.185818343987 
+
+1299 0.695098249729 0.211470034571 
+
+1300 0.718247336353 0.21459828952 
+
+1301 0.813346286811 0.306568985029 
+
+1302 0.823982353639 0.232116517236 
+
+1303 0.825859306609 0.191449202896 
+
+1304 0.851510997193 0.160792304393 
+
+1305 0.851510997193 0.227111309317 
+
+1306 0.869029224909 0.245880839013 
+
+1307 0.869029224909 0.267152972668 
+
+1308 0.849008393233 0.285922502364 
+
+1309 0.842126232345 0.317830702846 
+
+1310 0.837746675416 0.34348239343 
+
+1311 0.836495373436 0.369134084014 
+
+1312 0.835869722446 0.38790361371 
+
+1313 0.808966729882 0.396037076578 
+
+1314 0.808966729882 0.371011036984 
+
+1315 0.808341078893 0.349113252339 
+
+1316 0.809592380872 0.322210259775 
+
+1317 0.797079361075 0.309071588988 
+
+1318 0.805838474933 0.433576135969 
+
+1319 0.824608004629 0.421688767162 
+
+1320 0.845880138284 0.421688767162 
+
+1321 0.843377534324 0.442960900817 
+
+1322 0.81835149473 0.449843061706 
+
+1323 0.797705012065 0.456725222594 
+
+1324 0.791448502167 0.47236649734 
+
+1325 0.77580722742 0.493012980006 
+
+1326 0.789571549197 0.488007772087 
+
+1327 0.81835149473 0.4748691013 
+
+1328 0.830864514527 0.247757791983 
+
+1329 0.838372326406 0.212721336551 
+
+1330 0.811469333842 0.21522394051 
+
+1331 0.871531828868 0.320958957796 
+
+1332 0.877788338766 0.290302059293 
+
+1333 0.890301358564 0.240875631094 
+
+1334 0.880290942726 0.192074853885 
+
+1335 0.885296150645 0.122001943022 
+
+1336 0.908445237269 0.142648425687 
+
+1337 0.9065682843 0.0932219974884 
+
+1338 0.784566341278 0.135140613809 
+
+1339 0.81897714572 0.143899727667 
+
+1340 0.879039640746 0.0538059851275 
+
+1341 0.958497316458 0.100104158377 
+
+1342 0.784566341278 0.047549475229 
+
+1343 0.822105400669 0.0488007772087 
+
+1344 0.830238863538 -0.0156412747464 
+
+1345 0.921583908056 0.0193951806855 
+
+1346 1.0054211407 0.0556829380971 
+
+1347 0.896557868462 0.208341779622 
+
+1348 0.880916593716 0.355995413227 
+
+1349 0.913450445188 0.378518848862 
+
+1350 0.952866457549 0.38790361371 
+
+1351 0.984149007042 0.394160123609 
+
+1352 0.960374269427 0.42982223003 
+
+1353 0.909070888259 0.420437465183 
+
+1354 0.880916593716 0.412929653304 
+
+1355 0.90719393529 0.438581343888 
+
+1356 0.850885346203 0.480499960209 
+
+1357 0.886547452624 0.4748691013 
+
+1358 0.925337813995 0.476746054269 
+
+1359 0.957871665468 0.479874309219 
+
+1360 0.944107343691 0.514910764651 
+
+1361 0.910947841229 0.501772093864 
+
+1362 0.871531828868 0.504274697823 
+
+1363 0.852136648182 0.512408160691 
+
+1364 0.81960279671 0.513659462671 
+
+1365 0.832115816507 0.543065059194 
+
+1366 0.859644460061 0.550572871072 
+
+1367 0.885296150645 0.527423784448 
+
+1368 0.919706955087 0.528049435438 
+
+1369 0.926589115975 0.51553641564 
+
+1370 0.960999920417 0.526798133458 
+
+1371 0.996662026839 0.539311153255 
+
+1372 0.994785073869 0.55995763592 
+
+1373 1.00104158377 0.521167274549 
+
+1374 1.01855981148 0.534931596326 
+
+1375 1.0298215293 0.5612089379 
+
+1376 1.05860147483 0.548070267113 
+
+1377 1.04421150207 0.531177690387 
+
+1378 1.08112491047 0.543065059194 
+
+1379 1.10740225204 0.542439408204 
+
+1380 1.13931045253 0.543690710184 
+
+1381 1.16245953915 0.541813757214 
+
+1382 1.17434690796 0.514285113661 
+
+1383 1.13680784857 0.51616206663 
+
+1384 1.12366917778 0.51616206663 
+
+1385 1.09238662829 0.521167274549 
+
+1386 1.11178180897 0.486756470107 
+
+1387 1.1411874055 0.477997356249 
+
+1388 1.16871604905 0.477371705259 
+
+1389 1.19561904161 0.486130819117 
+
+1390 1.1899881827 0.445463504777 
+
+1391 1.16496214311 0.451094363685 
+
+1392 1.1349308956 0.449217410716 
+
+1393 1.12116657382 0.417934861223 
+
+1394 1.17059300202 0.404170539446 
+
+1395 1.15370042529 0.399165331527 
+
+1396 1.14869521737 0.367882782035 
+
+1397 1.12492047976 0.384149707771 
+
+1398 1.10177139313 0.392908821629 
+
+1399 1.09864313819 0.377893197872 
+
+1400 1.09488923225 0.355369762238 
+
+1401 1.09238662829 0.332846326603 
+
+1402 1.08675576938 0.306568985029 
+
+1403 1.11053050699 0.305317683049 
+
+1404 1.13743349956 0.3021894281 
+
+1405 1.1655877941 0.304692032059 
+
+1406 1.18748557874 0.315328098887 
+
+1407 1.16058258618 0.355995413227 
+
+1408 1.14181305649 0.331595024623 
+
+1409 1.11991527184 0.333471977593 
+
+1410 1.01480590554 0.374764942923 
+
+1411 1.00792374466 0.359123668177 
+
+1412 1.00980069763 0.335974581552 
+
+1413 1.01292895258 0.321584608785 
+
+1414 1.01105199961 0.30281507909 
+
+1415 1.0116776506 0.275286435536 
+
+1416 1.03983194514 0.272783831577 
+
+1417 1.06423233374 0.272783831577 
+
+1418 1.04045759613 0.313451145917 
+
+1419 1.06110407879 0.310322890968 
+
+1420 1.20437815547 0.364754527085 
+
+1421 1.21188596735 0.406673143406 
+
+1422 1.21876812824 0.469238242391 
+
+1423 1.16683909608 0.579978467596 
+
+1424 1.14994651935 0.608758413129 
+
+1425 1.12554613075 0.616266225007 
+
+1426 1.09426358126 0.620645781936 
+
+1427 1.06736058869 0.627527942825 
+
+1428 1.04671410603 0.630030546784 
+
+1429 1.02606762336 0.626276640845 
+
+1430 1.00354418773 0.618768828967 
+
+1431 0.980395101103 0.618143177977 
+
+1432 0.977892497143 0.581855420565 
+
+1433 1.01918546247 0.595619742342 
+
+1434 1.04608845504 0.60187625224 
+
+1435 1.04921670999 0.579352816606 
+
+1436 1.1161613659 0.588111930464 
+
+1437 1.16746474707 0.596245393332 
+
+1438 1.20312685349 0.600624950261 
+
+1439 1.2150142223 0.573721957697 
+
+1440 1.19999859854 0.524921180488 
+
+1441 1.22627594012 0.437955692898 
+
+1442 1.12992568768 0.47361779932 
+
+1443 1.11866396986 0.451720014675 
+
+1444 1.04608845504 0.670697861124 
+
+1445 1.02419067039 0.664441351226 
+
+1446 0.994785073869 0.681959578942 
+
+1447 0.969759034275 0.663815700236 
+
+1448 0.935348229833 0.633784452723 
+
+1449 0.911573492219 0.610635366098 
+
+1450 0.895306566482 0.6043788562 
+
+1451 0.897183519452 0.579352816606 
+
+1452 0.902814378361 0.552449824042 
+
+1453 0.827736259578 0.611261017088 
+
+1454 0.877788338766 0.64567182153 
+
+1455 0.903440029351 0.665067002216 
+
+1456 0.900311774401 0.685087833891 
+
+1457 0.920958257066 0.730760356151 
+
+1458 0.859018809071 0.753283791785 
+
+1459 0.912824794198 0.771427670491 
+
+1460 0.884670499655 0.748278583867 
+
+1461 0.798956314045 0.736391215059 
+
+1462 0.816474541761 0.752658140795 
+
+1463 0.77580722742 0.589988883433 
+
+1464 0.792074153156 0.586860628484 
+
+1465 0.803335870974 0.563711541859 
+
+1466 0.767673764552 0.529926388407 
+
+1467 0.750781187826 0.307194636019 
+
+1468 0.751406838816 0.291553361272 
+
+1469 0.767673764552 0.289676408303 
+
+1470 0.773930274451 0.30093812612 
+
+1471 0.768299415542 0.314076796907 
+
+1472 0.755160744755 0.312199843938 
+
+1473 0.753909442775 0.329092420664 
+
+1474 0.765796811582 0.328466769674 
+
+1475 0.77580722742 0.324712863735 
+
+1476 0.778935482369 0.354744111248 
+
+1477 0.765796811582 0.349738903329 
+
+1478 0.753283791785 0.366631480055 
+
+1479 0.767048113562 0.373513640943 
+
+1480 0.773930274451 0.38665231173 
+
+1481 0.760165952674 0.395411425588 
+
+1482 0.748278583867 0.38915491569 
+
+1483 0.660061794297 0.369134084014 
+
+1484 0.700729108638 0.148904935585 
+
+1485 0.69009304181 0.17142837122 
+
+1486 0.68821608884 0.191449202896 
+
+1487 0.653805284398 0.176433579139 
+
+1488 0.641917915591 0.153910143504 
+
+1489 0.658184841327 0.140145821728 
+
+1490 0.629404895794 0.262147764749 
+
+1491 0.638164009652 0.25839385881 
+
+1492 0.687590437851 0.218352195459 
+
+1493 0.703857363587 0.232116517236 
+
+1494 0.716370383384 0.241501282084 
+
+1495 0.737016866049 0.240249980104 
+
+1496 0.711365175465 0.248383442972 
+
+1497 0.713867779424 0.266527321678 
+
+1498 0.758288999704 0.252137348912 
+
+1499 0.77768418039 0.250260395942 
+
+1500 0.783315039298 0.26089646277 
+
+1501 0.591240185413 0.348487601349 
+
+1502 0.577475863636 0.347236299369 
+
+1503 0.575598910667 0.331595024623 
+
+1504 0.573096306707 0.311574192948 
+
+1505 0.576224561656 0.297184220181 
+
+1506 0.563711541859 0.284671200384 
+
+1507 0.508654254752 0.183941391017 
+
+1508 0.567465447798 0.17142837122 
+
+1509 0.582481071555 0.153284492514 
+
+1510 0.488633423077 0.284045549394 
+
+1511 0.636287056682 0.205213524672 
+
+1512 0.635661405693 0.187695296956 
+
+1513 0.73513991308 0.158289700433 
+
+1514 0.761417254653 0.223983054368 
+
+1515 0.797705012065 0.237121725155 
+
+1516 0.810218031862 0.228988262287 
+
+1517 0.68821608884 0.350990205309 
+
+1518 0.676328720033 0.332846326603 
+
+1519 0.665692653206 0.316579400867 
+
+1520 0.637538358662 0.296558569191 
+
+1521 0.526661799585 -0.0454018792746 
+
+1522 0.903497397563 -0.0204308456736 
+
+1523 0.513041235803 1.31211431104 
+
+1524 0.349594470414 0.835394578653 
+
+1525 0.102154228368 0.76048147785 
+
+1526 0.653787061554 2.74227350818 
+
+1527 -0.0539497431221 0.62959859788 
+
+1528 1.25380458367 0.640666613612 
+
+1529 0.642436591736 -0.0522121611658 
+
+1530 0.410887007435 -0.0385915973834 
+
+1531 0.830854390725 -0.0397266443653 
+
+1532 0.531201987513 1.2076899887 
+
+1533 0.584549195661 -0.0488070202202 
+
+1534 0.35299961136 -0.0351864564378 
+
+1535 1.05111113924 0.13651424978 
+
+1536 0.700323987811 -0.0556173021114 
+
+1537 1.24254286585 0.680708276962 
+
+1538 0.494880484093 1.41653863337 
+
+1539 1.01019181386 1.12142641808 
+
+1540 1.26506630148 0.600624950261 
+
+1541 0.976140404402 -0.0011350469819 
+
+1542 1.09091024043 0.862585762125 
+
+1543 0.171001525217 0.18990554064 
+
+1544 -0.0945451784656 0.567562298842 
+
+1545 0.794532887305 -0.0493745437112 
+
+1546 0.994301156114 1.49372182813 
+
+1547 0.783185936712 0.479308244037 
+
+1548 1.22471558162 0.48682431178 
+
+1549 1.29634885097 0.472992148331 
+
+1550 1.2568049678 0.479498527109 
+
+1551 1.20399469196 0.457815066251 
+
+1552 0.46877440351 -0.041996738329 
+
+1553 0.85269615105 0.270540307763 
+
+1554 0.275912086526 0.270906878608 
+
+1555 0.649241712472 0.41505502652 
+
+1556 0.723610259523 0.290816888695 
+
+1557 1.13326365804 0.370836274137 
+
+1558 1.29885145493 0.317830702847 
+
+1559 1.10296090242 0.577452691377 
+
+1560 0.398902961757 0.51418420221 
+
+1561 0.614623307332 -0.0312925589168 
+
+1562 0.867175894144 -0.0300787450194 
+
+1563 1.06275989651 0.463628957655 
+
+1564 1.24097873838 0.567778273294 
+
+1565 0.971232562016 0.158310213581 
+
+1566 0.801584048201 0.383524056781 
+
+1567 0.701369347345 0.505623251252 
+
+1568 0.687049200089 0.525313453728 
+
+1569 0.992396224634 0.77616474227 
+
+1570 1.0067468132 0.859166168238 
+
+1571 0.177067329171 0.0544822551295 
+
+1572 0.362502183522 0.19670467121 
+
+1573 0.545995622711 0.173329868272 
+
+1574 0.652553982419 0.232429342731 
+
+1575 0.886257388402 0.0114183956703 
+
+1576 1.00421074223 0.101398668297 
+
+1577 1.22289742476 0.282543987028 
+
+1578 1.11115615799 0.610083321107 
+
+1579 0.65791111902 0.221715069529 
+
+#title
+3086 # <triangle #> [<vertex #>] [<neigbouring triangle #>] [attribute of region] ...Triangulation Triangles...
+
+0 0 914 33 9 -1  1  0.0
+
+1 0 1571 914 3069 0 -1   0.0
+
+2 138 915 910 18 41 7  0.0
+
+3 10 915 1571 3069 -1  18  0.0
+
+4 644 138 49 41 33 13  0.0
+
+5 914 915 320 7 16 3069  0.0
+
+6 420 1543 607 49 54 53  0.0
+
+7 320 915 138 2 12 5  0.0
+
+8 914 283 321 10 9 16  0.0
+
+9 321 33 914 0 8 11  0.0
+
+10 321 283 420 53 46 8  0.0
+
+11 33 321 913 46 45 9  0.0
+
+12 138 319 320 15 7 13  0.0
+
+13 319 138 644 4 14 12  0.0
+
+14 137 319 644 13 88 52  0.0
+
+15 320 319 283 3021 16 12  0.0
+
+16 320 283 914 8 5 15  0.0
+
+17 319 318 1543 49 3021 52  0.0
+
+18 910 915 10 3 21 2  0.0
+
+19 521 1553 745 1956 1946 1960  0.0
+
+20 944 910 142 25 27 23  0.0
+
+21 5 910 10 18 -1  22  0.0
+
+22 911 910 5 21 28 25  0.0
+
+23 910 944 49 31 41 20  0.0
+
+24 50 142 934 95 94 27  0.0
+
+25 911 142 910 20 22 26  0.0
+
+26 935 142 911 25 185 95  0.0
+
+27 142 50 944 29 20 24  0.0
+
+28 1534 911 5 22 -1  1383  0.0
+
+29 944 50 647 40 38 27  0.0
+
+30 49 646 645 32 33 31  0.0
+
+31 49 944 646 38 30 23  0.0
+
+32 414 645 646 30 37 39  0.0
+
+33 49 645 644 39 4 30  0.0
+
+34 1019 141 647 35 43 74  0.0
+
+35 647 141 646 37 38 34  0.0
+
+36 648 641 647 43 40 113  0.0
+
+37 646 141 414 67 32 35  0.0
+
+38 944 647 646 35 31 29  0.0
+
+39 644 645 414 32 88 33  0.0
+
+40 647 50 648 103 36 29  0.0
+
+41 910 49 138 4 2 23  0.0
+
+42 928 1530 1552 -1  384 136  0.0
+
+43 641 1019 647 34 36 90  0.0
+
+44 814 32 913 45 47 63  0.0
+
+45 913 32 33 -1  11 44  0.0
+
+46 913 321 420 10 55 11  0.0
+
+47 913 290 814 189 44 55  0.0
+
+48 605 318 137 52 62 57  0.0
+
+49 607 1543 318 17 56 6  0.0
+
+50 47 137 414 88 87 51  0.0
+
+51 1017 137 47 50 64 62  0.0
+
+52 318 319 137 14 48 17  0.0
+
+53 283 1543 420 6 10 3021  0.0
+
+54 420 607 282 206 194 6  0.0
+
+55 420 290 913 47 46 191  0.0
+
+56 317 607 318 49 57 206  0.0
+
+57 318 605 317 192 56 48  0.0
+
+58 136 1017 1016 60 61 59  0.0
+
+59 1017 136 605 65 62 58  0.0
+
+60 413 1016 1017 58 64 79  0.0
+
+61 412 136 1016 58 208 209  0.0
+
+62 1017 605 137 48 51 59  0.0
+
+63 32 814 848 189 279 44  0.0
+
+64 1017 47 413 77 60 51  0.0
+
+65 605 136 962 201 192 59  0.0
+
+66 47 604 1014 69 77 87  0.0
+
+67 414 141 604 71 87 37  0.0
+
+68 1013 604 1018 71 73 69  0.0
+
+69 1014 604 1013 68 81 66  0.0
+
+70 1018 1019 638 86 73 74  0.0
+
+71 604 141 1018 74 68 67  0.0
+
+72 1012 638 1011 86 159 84  0.0
+
+73 1018 638 1013 75 68 70  0.0
+
+74 141 1019 1018 70 71 34  0.0
+
+75 1013 638 140 84 81 73  0.0
+
+76 413 1014 1015 78 85 77  0.0
+
+77 413 47 1014 66 76 64  0.0
+
+78 1015 1014 140 81 83 76  0.0
+
+79 1016 413 601 85 216 60  0.0
+
+80 140 1012 603 82 89 84  0.0
+
+81 140 1014 1013 69 75 78  0.0
+
+82 608 603 1012 80 151 157  0.0
+
+83 1015 140 995 89 230 78  0.0
+
+84 638 1012 140 80 75 72  0.0
+
+85 601 413 1015 76 230 79  0.0
+
+86 1011 638 1019 70 139 72  0.0
+
+87 47 414 604 67 66 50  0.0
+
+88 644 414 137 50 14 39  0.0
+
+89 995 140 603 80 213 83  0.0
+
+90 48 1019 641 43 105 139  0.0
+
+91 1307 183 1553 1974 1960 1975  0.0
+
+92 935 752 934 112 95 97  0.0
+
+93 912 935 936 185 186 97  0.0
+
+94 1251 50 934 24 96 101  0.0
+
+95 934 142 935 26 92 24  0.0
+
+96 1251 934 751 112 99 94  0.0
+
+97 752 935 912 93 98 92  0.0
+
+98 752 912 928 136 115 97  0.0
+
+99 650 1251 751 96 135 110  0.0
+
+100 1521 929 1552 564 -1  514  0.0
+
+101 649 50 1251 94 110 103  0.0
+
+102 648 649 640 104 113 103  0.0
+
+103 50 649 648 102 40 101  0.0
+
+104 640 649 1250 107 109 102  0.0
+
+105 640 48 641 90 113 140  0.0
+
+106 439 1250 642 108 127 109  0.0
+
+107 650 1250 649 104 110 108  0.0
+
+108 642 1250 650 107 125 106  0.0
+
+109 1250 439 640 111 104 106  0.0
+
+110 1251 650 649 107 101 99  0.0
+
+111 640 439 1010 143 140 109  0.0
+
+112 751 934 752 92 114 96  0.0
+
+113 641 648 640 102 105 36  0.0
+
+114 752 1267 751 117 112 116  0.0
+
+115 752 928 926 122 116 98  0.0
+
+116 752 926 1267 119 114 115  0.0
+
+117 751 1267 943 119 121 114  0.0
+
+118 1252 943 750 184 379 123  0.0
+
+119 926 943 1267 117 116 184  0.0
+
+120 651 1252 652 379 132 123  0.0
+
+121 751 943 651 123 135 117  0.0
+
+122 928 937 926 397 115 384  0.0
+
+123 651 943 1252 118 120 121  0.0
+
+124 617 642 1230 126 131 137  0.0
+
+125 642 650 651 135 126 108  0.0
+
+126 1230 642 651 125 129 124  0.0
+
+127 439 642 1229 137 146 106  0.0
+
+128 1230 1234 643 130 133 129  0.0
+
+129 1234 1230 651 126 132 128  0.0
+
+130 1233 643 1234 128 469 389  0.0
+
+131 617 1230 1231 133 182 124  0.0
+
+132 1234 651 652 120 469 129  0.0
+
+133 1231 1230 643 128 134 131  0.0
+
+134 1231 643 1232 389 388 133  0.0
+
+135 651 650 751 99 121 125  0.0
+
+136 928 912 1530 186 42 98  0.0
+
+137 1229 642 617 124 168 127  0.0
+
+138 1011 48 1572 3071 3070 139  0.0
+
+139 1011 1019 48 90 138 86  0.0
+
+140 48 640 1010 111 3071 105  0.0
+
+141 1020 1572 1010 3071 156 149  0.0
+
+142 1008 1009 1275 144 181 147  0.0
+
+143 1009 1010 439 111 146 145  0.0
+
+144 1275 1009 1229 146 161 142  0.0
+
+145 609 1010 1009 143 147 156  0.0
+
+146 1229 1009 439 143 127 144  0.0
+
+147 609 1009 1008 142 153 145  0.0
+
+148 639 1020 608 150 151 149  0.0
+
+149 1020 639 1572 3070 141 148  0.0
+
+150 608 1020 609 156 155 148  0.0
+
+151 608 1012 639 159 148 82  0.0
+
+152 609 436 1068 154 155 153  0.0
+
+153 436 609 1008 147 158 152  0.0
+
+154 998 1068 436 152 172 310  0.0
+
+155 609 1068 608 183 150 152  0.0
+
+156 1020 1010 609 145 150 141  0.0
+
+157 603 608 1228 282 324 82  0.0
+
+158 1008 1069 436 173 153 163  0.0
+
+159 639 1012 1011 72 3070 151  0.0
+
+160 1275 1021 438 162 181 161  0.0
+
+161 1021 1275 1229 144 168 160  0.0
+
+162 438 1021 1022 165 167 160  0.0
+
+163 438 1069 1008 158 181 175  0.0
+
+164 1022 1231 1023 166 169 182  0.0
+
+165 1022 1021 617 168 182 162  0.0
+
+166 616 1023 1231 164 388 443  0.0
+
+167 438 1022 1024 178 175 162  0.0
+
+168 1229 617 1021 165 161 137  0.0
+
+169 1006 1022 1023 164 376 178  0.0
+
+170 1003 1024 610 177 187 171  0.0
+
+171 1024 1003 1069 173 175 170  0.0
+
+172 998 436 1003 173 303 154  0.0
+
+173 1069 1003 436 172 158 171  0.0
+
+174 1024 1006 1005 176 177 178  0.0
+
+175 1024 1069 438 163 167 171  0.0
+
+176 1005 1006 772 180 374 174  0.0
+
+177 1024 1005 610 179 170 174  0.0
+
+178 1022 1006 1024 174 167 169  0.0
+
+179 610 1005 799 306 307 177  0.0
+
+180 1006 1007 772 435 176 755  0.0
+
+181 438 1008 1275 142 160 163  0.0
+
+182 1231 1022 617 165 131 164  0.0
+
+183 997 608 1068 155 288 282  0.0
+
+184 750 943 926 119 378 118  0.0
+
+185 911 936 935 93 26 1383  0.0
+
+186 912 936 1530 2929 136 93  0.0
+
+187 1003 610 1004 307 303 170  0.0
+
+188 849 848 290 189 193 197  0.0
+
+189 848 814 290 47 188 63  0.0
+
+190 282 419 827 240 194 199  0.0
+
+191 827 290 420 55 194 198  0.0
+
+192 962 317 605 57 65 203  0.0
+
+193 849 290 826 198 232 188  0.0
+
+194 282 827 420 191 54 190  0.0
+
+195 282 317 606 204 199 206  0.0
+
+196 297 849 815 234 247 197  0.0
+
+197 297 848 849 188 196 279  0.0
+
+198 827 826 290 193 191 240  0.0
+
+199 606 419 282 190 195 241  0.0
+
+200 962 963 600 202 205 201  0.0
+
+201 963 962 136 65 209 200  0.0
+
+202 600 963 412 209 229 200  0.0
+
+203 316 317 962 192 237 204  0.0
+
+204 317 316 606 236 195 203  0.0
+
+205 135 962 600 200 262 237  0.0
+
+206 282 607 317 56 195 54  0.0
+
+207 297 813 32 253 279 233  0.0
+
+208 1016 991 412 219 61 216  0.0
+
+209 136 412 963 202 201 61  0.0
+
+210 961 991 601 216 226 211  0.0
+
+211 991 961 1554 377 219 210  0.0
+
+212 995 994 602 214 215 213  0.0
+
+213 995 603 994 301 212 89  0.0
+
+214 602 994 993 278 223 212  0.0
+
+215 995 602 601 217 230 212  0.0
+
+216 991 1016 601 79 210 208  0.0
+
+217 992 601 602 215 223 226  0.0
+
+218 1554 139 990 221 1517 377  0.0
+
+219 1554 412 991 208 211 229  0.0
+
+220 139 961 992 226 225 377  0.0
+
+221 990 139 958 259 261 218  0.0
+
+222 992 993 960 224 225 223  0.0
+
+223 993 992 602 217 214 222  0.0
+
+224 960 993 576 228 227 222  0.0
+
+225 992 960 139 227 220 222  0.0
+
+226 961 601 992 217 220 210  0.0
+
+227 139 960 576 224 276 225  0.0
+
+228 576 993 858 293 274 224  0.0
+
+229 1554 600 412 202 219 1517  0.0
+
+230 1015 995 601 215 85 83  0.0
+
+231 600 990 964 256 262 1517  0.0
+
+232 826 289 849 234 193 250  0.0
+
+233 297 296 813 235 207 247  0.0
+
+234 849 289 815 249 196 232  0.0
+
+235 847 813 296 233 777 244  0.0
+
+236 316 281 606 241 204 248  0.0
+
+237 316 962 135 205 252 203  0.0
+
+238 134 316 599 252 275 251  0.0
+
+239 826 419 281 241 246 240  0.0
+
+240 419 826 827 198 190 239  0.0
+
+241 419 606 281 236 239 199  0.0
+
+242 846 31 303 243 245 759  0.0
+
+243 31 813 303 244 242 253  0.0
+
+244 303 813 847 235 245 243  0.0
+
+245 846 303 847 244 758 242  0.0
+
+246 281 418 826 250 239 800  0.0
+
+247 815 296 297 233 196 764  0.0
+
+248 316 315 281 780 236 251  0.0
+
+249 289 840 815 764 234 762  0.0
+
+250 289 826 418 246 779 232  0.0
+
+251 315 316 134 238 783 248  0.0
+
+252 316 135 599 255 238 237  0.0
+
+253 31 32 813 207 243 -1   0.0
+
+254 599 964 411 256 257 255  0.0
+
+255 964 599 135 252 262 254  0.0
+
+256 964 990 411 261 254 231  0.0
+
+257 410 599 411 254 265 277  0.0
+
+258 989 576 988 260 263 276  0.0
+
+259 958 139 989 276 272 221  0.0
+
+260 988 576 202 274 269 258  0.0
+
+261 990 958 411 265 256 221  0.0
+
+262 135 600 964 231 255 205  0.0
+
+263 988 957 989 272 258 268  0.0
+
+264 987 410 958 265 267 858  0.0
+
+265 958 410 411 257 261 264  0.0
+
+266 45 958 957 272 271 267  0.0
+
+267 45 987 958 264 266 851  0.0
+
+268 988 856 957 271 263 269  0.0
+
+269 856 988 202 260 270 268  0.0
+
+270 201 856 202 269 347 944  0.0
+
+271 957 856 45 273 266 268  0.0
+
+272 958 989 957 263 266 259  0.0
+
+273 856 956 45 851 271 856  0.0
+
+274 202 576 858 228 373 260  0.0
+
+275 134 599 598 277 786 238  0.0
+
+276 989 139 576 227 258 259  0.0
+
+277 598 599 410 257 784 275  0.0
+
+278 993 994 203 281 293 214  0.0
+
+279 32 848 297 197 207 63  0.0
+
+280 996 1228 997 282 283 324  0.0
+
+281 996 203 994 278 301 291  0.0
+
+282 1228 608 997 183 280 157  0.0
+
+283 996 997 434 285 289 280  0.0
+
+284 434 1002 655 286 287 285  0.0
+
+285 1002 434 997 283 288 284  0.0
+
+286 655 1002 998 310 323 284  0.0
+
+287 434 655 1067 300 298 284  0.0
+
+288 1002 997 1068 183 310 285  0.0
+
+289 996 434 859 294 291 283  0.0
+
+290 203 859 858 292 293 291  0.0
+
+291 203 996 859 289 290 281  0.0
+
+292 1227 858 859 290 328 327  0.0
+
+293 203 858 993 228 278 290  0.0
+
+294 434 1060 859 299 289 295  0.0
+
+295 434 654 1060 297 294 298  0.0
+
+296 654 1067 999 305 313 298  0.0
+
+297 574 1060 654 295 325 334  0.0
+
+298 1067 654 434 295 287 296  0.0
+
+299 1060 575 859 328 294 331  0.0
+
+300 655 1066 1067 305 287 302  0.0
+
+301 994 603 996 324 281 213  0.0
+
+302 1004 1066 655 300 323 304  0.0
+
+303 998 1003 1004 187 323 172  0.0
+
+304 1066 1004 799 307 311 302  0.0
+
+305 1066 999 1067 296 300 314  0.0
+
+306 1005 1065 799 309 179 374  0.0
+
+307 799 1004 610 187 179 304  0.0
+
+308 615 1065 437 657 585 309  0.0
+
+309 799 1065 615 308 320 306  0.0
+
+310 1002 1068 998 154 286 288  0.0
+
+311 1066 799 435 317 314 304  0.0
+
+312 1061 999 435 314 315 313  0.0
+
+313 1061 654 999 296 312 325  0.0
+
+314 999 1066 435 311 312 305  0.0
+
+315 787 1061 435 312 370 332  0.0
+
+316 798 615 1063 322 321 320  0.0
+
+317 798 435 799 311 320 319  0.0
+
+318 772 1064 1065 657 374 435  0.0
+
+319 1062 435 798 317 353 370  0.0
+
+320 615 798 799 317 309 316  0.0
+
+321 573 798 1063 316 356 353  0.0
+
+322 615 1098 1063 577 316 585  0.0
+
+323 998 1004 655 302 286 303  0.0
+
+324 1228 996 603 301 157 280  0.0
+
+325 1061 574 654 297 313 332  0.0
+
+326 1000 857 1227 327 329 333  0.0
+
+327 1227 857 858 373 292 326  0.0
+
+328 575 1227 859 292 299 329  0.0
+
+329 1000 1227 575 328 331 326  0.0
+
+330 46 1000 574 334 342 337  0.0
+
+331 1000 575 1060 299 334 329  0.0
+
+332 787 574 1061 325 315 335  0.0
+
+333 1000 959 857 339 326 337  0.0
+
+334 1060 574 1000 330 331 297  0.0
+
+335 1225 574 787 332 346 344  0.0
+
+336 959 46 1001 338 345 337  0.0
+
+337 46 959 1000 333 330 336  0.0
+
+338 1001 46 1092 341 375 336  0.0
+
+339 959 201 857 347 333 873  0.0
+
+340 786 579 1092 894 341 371  0.0
+
+341 786 1092 46 338 342 340  0.0
+
+342 786 46 574 330 344 341  0.0
+
+343 1226 786 1225 344 359 361  0.0
+
+344 574 1225 786 343 342 335  0.0
+
+345 578 959 1001 336 375 880  0.0
+
+346 787 200 1225 359 335 369  0.0
+
+347 202 857 201 339 270 373  0.0
+
+348 1093 1058 573 350 355 351  0.0
+
+349 1062 1058 787 369 370 350  0.0
+
+350 573 1058 1062 349 353 348  0.0
+
+351 1058 1093 200 363 369 348  0.0
+
+352 573 773 1094 354 357 356  0.0
+
+353 573 1062 798 319 321 350  0.0
+
+354 797 1094 773 352 631 621  0.0
+
+355 1093 573 783 357 366 348  0.0
+
+356 1063 773 573 352 321 372  0.0
+
+357 783 573 1094 352 364 355  0.0
+
+358 782 1226 1059 360 365 361  0.0
+
+359 1226 1225 200 346 360 343  0.0
+
+360 1059 1226 200 359 363 358  0.0
+
+361 1226 782 786 371 343 358  0.0
+
+362 1059 783 1097 364 367 366  0.0
+
+363 1059 200 1093 351 366 360  0.0
+
+364 1097 783 1094 357 368 362  0.0
+
+365 782 1059 120 1178 877 358  0.0
+
+366 1093 783 1059 362 363 355  0.0
+
+367 1097 612 1059 1178 362 1139  0.0
+
+368 1094 51 1097 655 364 621  0.0
+
+369 200 787 1058 349 351 346  0.0
+
+370 1062 787 435 315 319 349  0.0
+
+371 782 579 786 340 361 876  0.0
+
+372 764 773 1063 356 576 631  0.0
+
+373 858 857 202 347 274 327  0.0
+
+374 1065 1005 772 176 318 306  0.0
+
+375 1001 1092 578 874 345 338  0.0
+
+376 1006 1023 611 425 755 169  0.0
+
+377 139 1554 961 211 220 218  0.0
+
+378 926 927 750 383 184 397  0.0
+
+379 750 652 1252 120 118 385  0.0
+
+380 1057 750 938 400 419 385  0.0
+
+381 753 927 937 397 382 418  0.0
+
+382 753 937 929 564 420 381  0.0
+
+383 1254 750 927 378 399 400  0.0
+
+384 928 1552 937 564 122 42  0.0
+
+385 750 1057 652 394 379 380  0.0
+
+386 1233 1235 1232 391 389 387  0.0
+
+387 1235 1233 652 469 394 386  0.0
+
+388 1232 616 1231 166 134 395  0.0
+
+389 1232 643 1233 130 386 134  0.0
+
+390 1232 653 1037 393 395 391  0.0
+
+391 653 1232 1235 386 392 390  0.0
+
+392 1237 653 1235 391 396 401  0.0
+
+393 1507 1037 653 390 417 430  0.0
+
+394 652 1057 1235 396 387 385  0.0
+
+395 1232 1037 616 423 388 390  0.0
+
+396 1235 1057 1237 419 392 394  0.0
+
+397 926 937 927 381 378 122  0.0
+
+398 1237 938 635 402 407 419  0.0
+
+399 924 1254 927 383 418 470  0.0
+
+400 938 750 1254 383 405 380  0.0
+
+401 1237 1236 653 417 392 409  0.0
+
+402 1253 635 938 398 405 406  0.0
+
+403 402 1253 1254 405 473 563  0.0
+
+404 1238 635 1243 406 483 416  0.0
+
+405 1253 938 1254 400 403 402  0.0
+
+406 635 1253 1243 563 404 402  0.0
+
+407 1237 635 1216 416 409 398  0.0
+
+408 1573 1216 1038 410 411 3073  0.0
+
+409 1216 1236 1237 401 407 3073  0.0
+
+410 1038 1216 1238 416 413 408  0.0
+
+411 1573 1038 1255 412 421 408  0.0
+
+412 1038 1508 1255 414 411 413  0.0
+
+413 1508 1038 1238 410 468 412  0.0
+
+414 1119 1255 1508 412 489 415  0.0
+
+415 1119 253 1255 421 414 450  0.0
+
+416 1216 635 1238 404 410 407  0.0
+
+417 1507 653 1236 401 466 393  0.0
+
+418 753 924 927 399 381 471  0.0
+
+419 1237 1057 938 380 398 396  0.0
+
+420 929 922 753 471 382 514  0.0
+
+421 253 1573 1255 411 415 3072  0.0
+
+422 616 766 1025 424 443 423  0.0
+
+423 616 1037 766 430 422 395  0.0
+
+424 1025 766 1121 426 431 422  0.0
+
+425 1025 611 1023 376 443 433  0.0
+
+426 766 1026 1121 429 424 427  0.0
+
+427 618 1026 766 426 442 428  0.0
+
+428 1028 1026 618 427 465 429  0.0
+
+429 1121 1026 1028 428 440 426  0.0
+
+430 1507 766 1037 423 393 442  0.0
+
+431 1025 1121 499 440 437 424  0.0
+
+432 611 1100 1007 434 755 433  0.0
+
+433 611 1025 1100 437 432 425  0.0
+
+434 1064 1007 1100 432 567 435  0.0
+
+435 1064 772 1007 180 434 318  0.0
+
+436 499 1028 1101 438 439 440  0.0
+
+437 1100 1025 499 431 439 433  0.0
+
+438 1101 1028 1027 447 463 436  0.0
+
+439 499 1101 1100 441 437 436  0.0
+
+440 1121 1028 499 436 431 429  0.0
+
+441 765 1100 1101 439 572 569  0.0
+
+442 618 766 1507 430 445 427  0.0
+
+443 1023 616 1025 422 425 166  0.0
+
+444 1224 618 1120 446 451 465  0.0
+
+445 1036 618 1507 442 466 446  0.0
+
+446 1120 618 1036 445 449 444  0.0
+
+447 1224 1027 1028 438 465 455  0.0
+
+448 1120 253 1035 450 453 449  0.0
+
+449 253 1120 1036 446 3072 448  0.0
+
+450 1119 1035 253 448 415 537  0.0
+
+451 1224 1120 500 462 455 444  0.0
+
+452 1236 1573 1036 3072 466 3073  0.0
+
+453 1112 1120 1035 448 464 462  0.0
+
+454 1027 500 1110 456 457 455  0.0
+
+455 500 1027 1224 447 451 454  0.0
+
+456 1110 500 1112 462 459 454  0.0
+
+457 440 1027 1110 454 594 608  0.0
+
+458 1110 1111 1034 461 467 459  0.0
+
+459 1111 1110 1112 456 460 458  0.0
+
+460 749 1111 1112 459 464 527  0.0
+
+461 1072 1034 1111 458 565 591  0.0
+
+462 500 1120 1112 453 456 451  0.0
+
+463 1101 1027 1029 608 572 438  0.0
+
+464 1112 1035 749 528 460 453  0.0
+
+465 1224 1028 618 428 444 447  0.0
+
+466 1236 1036 1507 445 417 452  0.0
+
+467 1110 1034 1109 591 594 458  0.0
+
+468 1508 1238 1239 480 491 413  0.0
+
+469 1234 652 1233 387 130 132  0.0
+
+470 924 1266 1254 473 399 475  0.0
+
+471 924 753 922 420 472 418  0.0
+
+472 924 922 933 3051 476 471  0.0
+
+473 1254 1266 402 477 403 470  0.0
+
+474 939 1266 401 493 494 477  0.0
+
+475 924 925 1266 493 470 476  0.0
+
+476 933 925 924 475 472 500  0.0
+
+477 1266 939 402 479 473 474  0.0
+
+478 1561 922 1533 3014 2922 3051  0.0
+
+479 402 939 1243 490 563 477  0.0
+
+480 1509 1239 1238 468 483 482  0.0
+
+481 1509 1243 1242 488 482 483  0.0
+
+482 1239 1509 1242 481 485 480  0.0
+
+483 1509 1238 1243 404 481 480  0.0
+
+484 1239 1240 619 487 491 485  0.0
+
+485 1240 1239 1242 482 486 484  0.0
+
+486 1241 1240 1242 485 513 505  0.0
+
+487 1039 619 1240 484 560 524  0.0
+
+488 1242 1243 636 490 513 481  0.0
+
+489 619 1119 1508 414 491 517  0.0
+
+490 636 1243 939 479 492 488  0.0
+
+491 1508 1239 619 484 489 468  0.0
+
+492 636 939 1244 499 495 490  0.0
+
+493 1266 925 401 497 474 475  0.0
+
+494 401 1056 939 499 474 498  0.0
+
+495 636 1244 1241 503 513 492  0.0
+
+496 1489 1056 634 1521 1519 510  0.0
+
+497 925 1265 401 1537 493 1522  0.0
+
+498 401 940 1056 1521 494 1537  0.0
+
+499 1056 1244 939 492 494 501  0.0
+
+500 933 923 925 562 476 3050  0.0
+
+501 1244 1056 1488 510 503 499  0.0
+
+502 1241 1488 398 504 505 503  0.0
+
+503 1241 1244 1488 501 502 495  0.0
+
+504 398 1488 1245 507 506 502  0.0
+
+505 398 1240 1241 486 502 511  0.0
+
+506 398 1245 1487 508 515 504  0.0
+
+507 1245 1488 1489 510 512 504  0.0
+
+508 1047 1487 1245 506 1518 509  0.0
+
+509 1249 1487 1047 508 1527 546  0.0
+
+510 1056 1489 1488 507 501 496  0.0
+
+511 1240 398 1247 540 560 505  0.0
+
+512 1245 1489 1256 1519 1518 507  0.0
+
+513 1241 1242 636 488 495 486  0.0
+
+514 929 1521 922 3014 420 100  0.0
+
+515 1487 1246 398 544 506 546  0.0
+
+516 1035 1118 1113 519 528 537  0.0
+
+517 1119 619 1118 521 537 489  0.0
+
+518 502 1118 1117 521 523 519  0.0
+
+519 1113 1118 502 518 532 516  0.0
+
+520 1115 1117 504 536 559 523  0.0
+
+521 1117 1118 619 517 524 518  0.0
+
+522 748 1115 1040 559 551 534  0.0
+
+523 1117 1115 502 525 518 520  0.0
+
+524 1117 619 1039 487 536 521  0.0
+
+525 502 1115 1114 534 532 523  0.0
+
+526 1041 501 749 527 529 535  0.0
+
+527 501 1111 749 460 526 565  0.0
+
+528 749 1035 1113 516 529 464  0.0
+
+529 1041 749 1113 528 531 526  0.0
+
+530 1116 1041 1114 531 533 752  0.0
+
+531 1114 1041 1113 529 532 530  0.0
+
+532 1114 1113 502 519 525 531  0.0
+
+533 748 1116 1114 530 534 557  0.0
+
+534 1115 748 1114 533 525 522  0.0
+
+535 1073 501 1041 526 660 666  0.0
+
+536 504 1117 1039 524 539 520  0.0
+
+537 1119 1118 1035 516 450 517  0.0
+
+538 504 1247 1512 540 541 539  0.0
+
+539 1247 504 1039 536 560 538  0.0
+
+540 1247 398 1512 544 538 511  0.0
+
+541 504 1512 1511 543 547 538  0.0
+
+542 1046 1511 1246 543 545 556  0.0
+
+543 1246 1511 1512 541 544 542  0.0
+
+544 1512 398 1246 515 543 540  0.0
+
+545 1046 1246 1249 546 1516 542  0.0
+
+546 1487 1249 1246 545 515 509  0.0
+
+547 504 1511 1040 549 559 541  0.0
+
+548 1040 506 1045 550 551 549  0.0
+
+549 1040 1511 506 556 548 547  0.0
+
+550 1045 506 1574 3075 561 548  0.0
+
+551 1045 748 1040 522 548 557  0.0
+
+552 1149 1148 1574 3074 555 558  0.0
+
+553 1248 1579 1046 3084 1516 3085  0.0
+
+554 1147 1148 252 558 1563 702  0.0
+
+555 1149 1574 1579 3075 1895 552  0.0
+
+556 1511 1046 506 3084 549 542  0.0
+
+557 1116 748 1045 551 664 533  0.0
+
+558 252 1148 1149 552 1535 554  0.0
+
+559 1040 1115 504 520 547 522  0.0
+
+560 1240 1247 1039 539 487 511  0.0
+
+561 505 1045 1574 550 3074 688  0.0
+
+562 923 754 925 1524 500 1654  0.0
+
+563 1243 1253 402 403 479 406  0.0
+
+564 1552 929 937 382 384 100  0.0
+
+565 501 1072 1111 461 527 666  0.0
+
+566 437 1064 1099 567 579 657  0.0
+
+567 1064 1100 1099 569 566 434  0.0
+
+568 765 1029 1030 570 571 572  0.0
+
+569 1099 1100 765 441 571 567  0.0
+
+570 1030 1029 498 584 582 568  0.0
+
+571 765 1030 1099 573 569 568  0.0
+
+572 1101 1029 765 568 441 463  0.0
+
+573 800 1099 1030 571 578 579  0.0
+
+574 1098 800 1510 581 577 575  0.0
+
+575 800 1098 437 585 579 574  0.0
+
+576 1510 764 1063 372 577 611  0.0
+
+577 1510 1063 1098 322 574 576  0.0
+
+578 1030 1031 800 583 573 582  0.0
+
+579 800 437 1099 566 573 575  0.0
+
+580 681 1031 498 582 599 654  0.0
+
+581 1510 800 1032 583 611 574  0.0
+
+582 498 1031 1030 578 570 580  0.0
+
+583 1031 1032 800 581 578 618  0.0
+
+584 1029 1102 498 607 570 587  0.0
+
+585 1098 615 437 308 575 322  0.0
+
+586 1102 440 680 588 589 587  0.0
+
+587 440 1102 1029 584 608 586  0.0
+
+588 680 440 1109 594 593 586  0.0
+
+589 1102 680 1103 597 607 586  0.0
+
+590 1109 1072 1071 592 593 591  0.0
+
+591 1109 1034 1072 461 590 467  0.0
+
+592 1071 1072 679 606 604 590  0.0
+
+593 1109 1071 680 595 588 590  0.0
+
+594 1110 1109 440 588 457 467  0.0
+
+595 680 1071 889 602 597 593  0.0
+
+596 1103 889 497 598 605 597  0.0
+
+597 1103 680 889 595 596 589  0.0
+
+598 497 889 1070 602 601 596  0.0
+
+599 681 498 1103 607 633 580  0.0
+
+600 678 1506 1070 601 659 751  0.0
+
+601 1070 1506 497 609 598 600  0.0
+
+602 1070 889 1071 595 604 598  0.0
+
+603 1506 876 1108 638 609 751  0.0
+
+604 679 1070 1071 602 592 656  0.0
+
+605 497 1104 1103 633 596 637  0.0
+
+606 1072 1073 679 679 592 666  0.0
+
+607 1102 1103 498 599 584 589  0.0
+
+608 1027 440 1029 587 463 457  0.0
+
+609 1108 497 1506 601 603 640  0.0
+
+610 764 1032 1095 612 613 611  0.0
+
+611 764 1510 1032 581 610 576  0.0
+
+612 1095 1032 197 618 617 610  0.0
+
+613 764 1095 797 622 631 610  0.0
+
+614 197 1105 1096 616 617 615  0.0
+
+615 681 1105 197 614 654 653  0.0
+
+616 1096 1105 1106 630 628 614  0.0
+
+617 197 1096 1095 619 612 614  0.0
+
+618 1032 1031 197 654 612 583  0.0
+
+619 1095 1096 1033 625 622 617  0.0
+
+620 51 797 1033 622 623 621  0.0
+
+621 1094 797 51 620 368 354  0.0
+
+622 797 1095 1033 619 620 613  0.0
+
+623 762 51 1033 620 1157 1164  0.0
+
+624 781 1106 879 626 629 628  0.0
+
+625 1033 1096 781 628 627 619  0.0
+
+626 198 879 1106 624 651 1514  0.0
+
+627 1033 781 444 629 1157 625  0.0
+
+628 1096 1106 781 624 625 616  0.0
+
+629 781 879 444 1158 627 624  0.0
+
+630 1105 874 1106 635 616 632  0.0
+
+631 773 764 797 613 354 372  0.0
+
+632 1104 874 1105 630 653 634  0.0
+
+633 681 1103 1104 605 653 599  0.0
+
+634 874 1104 875 637 639 632  0.0
+
+635 874 212 1106 651 630 639  0.0
+
+636 875 1108 677 638 641 640  0.0
+
+637 875 1104 497 605 640 634  0.0
+
+638 677 1108 876 603 725 636  0.0
+
+639 874 875 212 643 635 634  0.0
+
+640 1108 875 497 637 609 636  0.0
+
+641 1107 875 677 636 650 643  0.0
+
+642 212 1107 877 644 645 643  0.0
+
+643 1107 212 875 639 641 642  0.0
+
+644 877 1107 1123 650 647 642  0.0
+
+645 198 212 877 642 1161 651  0.0
+
+646 1122 1123 445 648 649 647  0.0
+
+647 1123 1122 877 757 644 646  0.0
+
+648 1076 445 1123 646 707 717  0.0
+
+649 676 1122 445 646 1236 1229  0.0
+
+650 1107 677 1123 652 644 641  0.0
+
+651 1106 212 198 645 626 635  0.0
+
+652 1123 677 1504 725 707 650  0.0
+
+653 1105 681 1104 633 632 615  0.0
+
+654 681 197 1031 618 580 615  0.0
+
+655 51 873 1097 1142 368 1164  0.0
+
+656 1074 1070 679 604 679 659  0.0
+
+657 1065 1064 437 566 308 318  0.0
+
+658 1074 1073 888 660 661 679  0.0
+
+659 1074 678 1070 600 656 669  0.0
+
+660 1073 1041 888 663 658 535  0.0
+
+661 199 1074 888 658 676 669  0.0
+
+662 503 1116 1044 664 667 752  0.0
+
+663 888 1041 503 752 665 660  0.0
+
+664 1116 1045 1044 688 662 557  0.0
+
+665 888 503 686 673 676 663  0.0
+
+666 1072 501 1073 535 606 565  0.0
+
+667 1044 1223 503 673 662 678  0.0
+
+668 678 199 1042 670 671 669  0.0
+
+669 678 1074 199 661 668 659  0.0
+
+670 1217 1042 199 668 677 712  0.0
+
+671 678 1042 1505 709 705 668  0.0
+
+672 686 1223 1080 674 675 673  0.0
+
+673 1223 686 503 665 667 672  0.0
+
+674 1043 1080 1223 672 701 693  0.0
+
+675 686 1080 199 677 676 672  0.0
+
+676 888 686 199 675 661 665  0.0
+
+677 1080 1217 199 670 675 726  0.0
+
+678 1223 1044 1490 680 701 667  0.0
+
+679 1074 679 1073 606 658 656  0.0
+
+680 1044 1491 1490 683 678 681  0.0
+
+681 1491 1044 505 688 682 680  0.0
+
+682 1491 505 1146 687 686 681  0.0
+
+683 683 1490 1491 680 686 698  0.0
+
+684 1146 1052 1145 1583 689 685  0.0
+
+685 1147 1052 1146 684 687 1563  0.0
+
+686 1491 1146 683 689 683 682  0.0
+
+687 1147 1146 505 682 702 685  0.0
+
+688 1045 505 1044 681 664 561  0.0
+
+689 1145 683 1146 686 684 695  0.0
+
+690 1043 1222 196 692 693 691  0.0
+
+691 1222 1043 683 698 697 690  0.0
+
+692 1520 196 1222 690 748 734  0.0
+
+693 1043 196 1080 699 674 690  0.0
+
+694 1222 682 886 703 748 697  0.0
+
+695 682 683 1145 689 700 697  0.0
+
+696 1143 1142 682 703 1573 1609  0.0
+
+697 682 1222 683 691 695 694  0.0
+
+698 1043 1490 683 683 691 701  0.0
+
+699 1079 1080 196 693 734 727  0.0
+
+700 1144 682 1145 695 1583 1573  0.0
+
+701 1490 1043 1223 674 678 698  0.0
+
+702 1148 1147 505 687 3074 554  0.0
+
+703 682 1142 886 731 694 696  0.0
+
+704 876 1505 1504 706 725 705  0.0
+
+705 1505 876 678 751 671 704  0.0
+
+706 1504 1505 1075 709 708 704  0.0
+
+707 1504 1076 1123 648 652 713  0.0
+
+708 1504 1075 52 711 713 706  0.0
+
+709 1505 1042 1075 712 706 671  0.0
+
+710 1075 1217 801 724 722 712  0.0
+
+711 52 1075 1077 722 715 708  0.0
+
+712 1217 1075 1042 709 670 710  0.0
+
+713 1504 52 1076 714 707 708  0.0
+
+714 52 1503 1076 717 713 715  0.0
+
+715 52 1077 1503 716 714 711  0.0
+
+716 788 1503 1077 715 718 1322  0.0
+
+717 1076 1503 445 723 648 714  0.0
+
+718 1077 1078 788 753 716 721  0.0
+
+719 880 1078 801 721 747 720  0.0
+
+720 880 454 1078 753 719 739  0.0
+
+721 1078 1077 801 722 719 718  0.0
+
+722 1075 801 1077 721 711 710  0.0
+
+723 445 1503 1502 1322 1236 717  0.0
+
+724 455 801 1217 710 726 747  0.0
+
+725 1504 677 876 638 704 652  0.0
+
+726 1080 455 1217 724 677 727  0.0
+
+727 1080 1079 455 729 726 699  0.0
+
+728 881 1079 1520 734 744 737  0.0
+
+729 880 455 1079 727 737 747  0.0
+
+730 886 1141 456 750 733 731  0.0
+
+731 1141 886 1142 703 754 730  0.0
+
+732 1126 456 1519 750 1725 742  0.0
+
+733 886 456 1520 735 748 730  0.0
+
+734 196 1520 1079 728 699 692  0.0
+
+735 456 1125 1520 744 733 742  0.0
+
+736 880 881 1124 738 745 737  0.0
+
+737 881 880 1079 729 728 736  0.0
+
+738 1124 881 194 741 743 736  0.0
+
+739 454 880 882 745 1258 720  0.0
+
+740 194 1125 1126 742 749 741  0.0
+
+741 1125 194 881 738 744 740  0.0
+
+742 1126 1125 456 735 732 740  0.0
+
+743 882 1124 194 738 1272 745  0.0
+
+744 881 1520 1125 735 741 728  0.0
+
+745 882 880 1124 736 743 739  0.0
+
+746 674 1126 1127 1715 1797 749  0.0
+
+747 455 880 801 719 724 729  0.0
+
+748 886 1520 1222 692 694 733  0.0
+
+749 674 194 1126 740 746 1272  0.0
+
+750 1519 456 1141 730 1707 732  0.0
+
+751 678 876 1506 603 600 705  0.0
+
+752 1116 503 1041 663 530 662  0.0
+
+753 788 1078 454 720 1248 718  0.0
+
+754 1142 887 1141 1712 731 1609  0.0
+
+755 1006 611 1007 432 180 376  0.0
+
+756 4 930 1536 3028 -1  1618  0.0
+
+757 780 877 1122 647 1229 1161  0.0
+
+758 846 847 812 777 767 245  0.0
+
+759 846 30 31 -1  242 766  0.0
+
+760 816 840 851 762 763 761  0.0
+
+761 840 816 296 765 764 760  0.0
+
+762 840 289 851 779 760 249  0.0
+
+763 816 851 850 774 770 760  0.0
+
+764 296 815 840 249 761 247  0.0
+
+765 839 296 816 761 770 771  0.0
+
+766 846 845 30 769 759 767  0.0
+
+767 845 846 812 758 768 766  0.0
+
+768 302 845 812 767 773 803  0.0
+
+769 30 845 25 802 -1  766  0.0
+
+770 816 850 839 775 765 763  0.0
+
+771 839 812 296 777 765 773  0.0
+
+772 835 850 288 774 797 810  0.0
+
+773 302 812 839 771 804 768  0.0
+
+774 288 850 851 763 776 772  0.0
+
+775 295 839 850 770 807 804  0.0
+
+776 851 418 288 799 774 779  0.0
+
+777 847 296 812 771 758 235  0.0
+
+778 280 418 828 800 781 789  0.0
+
+779 851 289 418 250 776 762  0.0
+
+780 828 281 315 248 781 800  0.0
+
+781 315 280 828 778 780 790  0.0
+
+782 596 965 598 786 787 796  0.0
+
+783 965 315 134 251 786 785  0.0
+
+784 598 410 117 858 787 277  0.0
+
+785 967 315 965 783 794 790  0.0
+
+786 598 965 134 783 275 782  0.0
+
+787 117 596 598 782 784 848  0.0
+
+788 280 279 825 832 789 801  0.0
+
+789 280 825 418 799 778 788  0.0
+
+790 280 315 967 785 791 781  0.0
+
+791 409 280 967 790 793 801  0.0
+
+792 966 409 133 793 795 846  0.0
+
+793 133 409 967 791 794 792  0.0
+
+794 133 967 965 785 796 793  0.0
+
+795 596 966 133 792 796 829  0.0
+
+796 596 133 965 794 782 795  0.0
+
+797 835 288 825 799 808 772  0.0
+
+798 211 596 597 848 943 829  0.0
+
+799 418 825 288 797 776 789  0.0
+
+800 281 828 418 778 246 780  0.0
+
+801 409 279 280 788 791 826  0.0
+
+802 301 25 845 769 803 823  0.0
+
+803 301 845 302 768 813 802  0.0
+
+804 302 839 295 775 805 773  0.0
+
+805 295 811 302 813 804 817  0.0
+
+806 836 817 835 810 818 820  0.0
+
+807 817 295 850 775 810 811  0.0
+
+808 835 825 417 832 809 797  0.0
+
+809 287 835 417 808 822 818  0.0
+
+810 817 850 835 772 806 807  0.0
+
+811 817 294 295 817 807 820  0.0
+
+812 301 811 841 814 815 813  0.0
+
+813 811 301 302 803 805 812  0.0
+
+814 841 811 294 817 819 812  0.0
+
+815 301 841 844 949 947 812  0.0
+
+816 837 294 836 820 964 952  0.0
+
+817 294 811 295 805 811 814  0.0
+
+818 287 836 835 806 809 821  0.0
+
+819 810 841 294 814 952 949  0.0
+
+820 817 836 294 816 811 806  0.0
+
+821 836 287 818 950 964 818  0.0
+
+822 417 824 287 837 809 845  0.0
+
+823 25 301 26 947 -1  802  0.0
+
+824 279 408 829 835 825 827  0.0
+
+825 279 829 417 845 832 824  0.0
+
+826 279 409 951 846 827 801  0.0
+
+827 951 408 279 824 826 833  0.0
+
+828 966 211 132 844 831 829  0.0
+
+829 211 966 596 795 798 828  0.0
+
+830 594 132 969 917 909 840  0.0
+
+831 966 132 951 833 846 828  0.0
+
+832 825 279 417 825 808 788  0.0
+
+833 132 408 951 827 831 842  0.0
+
+834 829 278 824 843 845 835  0.0
+
+835 278 829 408 824 836 834  0.0
+
+836 278 408 950 839 847 835  0.0
+
+837 287 824 416 843 974 822  0.0
+
+838 304 950 970 839 841 988  0.0
+
+839 970 950 408 836 842 838  0.0
+
+840 594 970 132 842 830 841  0.0
+
+841 594 304 970 838 840 1039  0.0
+
+842 408 132 970 840 839 833  0.0
+
+843 416 824 278 834 966 837  0.0
+
+844 595 132 211 828 943 917  0.0
+
+845 829 824 417 822 825 834  0.0
+
+846 951 409 966 792 831 826  0.0
+
+847 278 950 407 988 967 836  0.0
+
+848 597 596 117 787 860 798  0.0
+
+849 1221 1555 693 1305 1296 1298  0.0
+
+850 987 956 577 852 871 851  0.0
+
+851 987 45 956 273 850 267  0.0
+
+852 986 577 956 850 859 861  0.0
+
+853 422 117 577 871 861 860  0.0
+
+854 118 421 955 855 857 868  0.0
+
+855 955 421 956 859 856 854  0.0
+
+856 955 956 856 273 944 855  0.0
+
+857 952 118 955 854 870 893  0.0
+
+858 987 117 410 784 264 871  0.0
+
+859 986 956 421 855 865 852  0.0
+
+860 422 597 117 848 853 863  0.0
+
+861 422 577 986 852 862 853  0.0
+
+862 422 986 954 865 867 861  0.0
+
+863 984 597 422 860 904 897  0.0
+
+864 954 118 953 866 869 868  0.0
+
+865 954 986 421 859 868 862  0.0
+
+866 855 953 118 864 893 891  0.0
+
+867 983 422 954 862 901 904  0.0
+
+868 421 118 954 864 865 854  0.0
+
+869 953 116 954 901 864 926  0.0
+
+870 952 955 201 944 873 857  0.0
+
+871 577 117 987 858 850 853  0.0
+
+872 855 952 578 880 883 893  0.0
+
+873 201 959 952 880 870 339  0.0
+
+874 578 1092 1091 894 875 375  0.0
+
+875 119 578 1091 874 884 883  0.0
+
+876 782 1090 579 879 371 877  0.0
+
+877 782 120 1090 881 876 365  0.0
+
+878 1091 1090 784 881 890 879  0.0
+
+879 579 1090 1091 878 894 876  0.0
+
+880 578 952 959 873 345 872  0.0
+
+881 784 1090 120 877 1134 878  0.0
+
+882 115 855 119 883 885 940  0.0
+
+883 119 855 578 872 875 882  0.0
+
+884 119 1091 580 890 885 875  0.0
+
+885 580 115 119 882 884 923  0.0
+
+886 656 785 580 895 889 892  0.0
+
+887 1089 656 784 889 1134 1513  0.0
+
+888 205 581 785 924 892 938  0.0
+
+889 656 580 784 890 887 886  0.0
+
+890 1091 784 580 889 884 878  0.0
+
+891 953 855 583 940 926 866  0.0
+
+892 205 785 656 886 1181 888  0.0
+
+893 952 855 118 866 857 872  0.0
+
+894 1091 1092 579 340 879 874  0.0
+
+895 580 785 979 924 923 886  0.0
+
+896 985 595 984 897 899 907  0.0
+
+897 984 595 597 943 863 896  0.0
+
+898 210 984 983 904 903 899  0.0
+
+899 210 985 984 896 898 914  0.0
+
+900 983 116 981 902 903 901  0.0
+
+901 983 954 116 869 900 867  0.0
+
+902 981 116 583 926 921 900  0.0
+
+903 983 981 210 905 898 900  0.0
+
+904 984 422 983 867 898 863  0.0
+
+905 968 210 981 903 912 914  0.0
+
+906 971 969 43 908 913 909  0.0
+
+907 985 969 595 917 896 908  0.0
+
+908 43 969 985 907 911 906  0.0
+
+909 969 971 594 941 830 906  0.0
+
+910 43 968 982 912 915 911  0.0
+
+911 968 43 985 908 914 910  0.0
+
+912 982 968 981 905 916 910  0.0
+
+913 971 43 314 1132 1046 906  0.0
+
+914 985 210 968 905 911 899  0.0
+
+915 982 425 43 1132 910 945  0.0
+
+916 981 980 982 939 912 921  0.0
+
+917 595 969 132 830 844 907  0.0
+
+918 583 582 980 920 921 919  0.0
+
+919 582 583 115 940 925 918  0.0
+
+920 860 980 582 918 930 939  0.0
+
+921 583 980 981 916 902 918  0.0
+
+922 582 979 44 927 930 925  0.0
+
+923 979 115 580 885 895 925  0.0
+
+924 581 979 785 895 888 927  0.0
+
+925 979 582 115 919 923 922  0.0
+
+926 953 583 116 902 869 891  0.0
+
+927 581 44 979 922 924 933  0.0
+
+928 977 975 860 929 931 1082  0.0
+
+929 975 982 860 939 928 945  0.0
+
+930 44 860 582 920 922 931  0.0
+
+931 44 977 860 928 930 935  0.0
+
+932 861 204 661 934 937 936  0.0
+
+933 861 44 581 927 936 935  0.0
+
+934 658 661 204 932 1201 1227  0.0
+
+935 977 44 861 933 1065 931  0.0
+
+936 581 204 861 932 933 938  0.0
+
+937 978 861 661 932 942 1065  0.0
+
+938 204 581 205 888 1201 936  0.0
+
+939 860 982 980 916 920 929  0.0
+
+940 855 115 583 919 891 882  0.0
+
+941 972 594 971 909 1046 1039  0.0
+
+942 661 433 978 1066 937 1325  0.0
+
+943 597 595 211 844 798 897  0.0
+
+944 856 201 955 870 856 270  0.0
+
+945 975 425 982 915 929 1061  0.0
+
+946 1527 1544 843 957 3017 -1   0.0
+
+947 26 301 844 815 1011 823  0.0
+
+948 293 810 837 952 951 959  0.0
+
+949 810 844 841 815 819 953  0.0
+
+950 818 287 838 974 962 821  0.0
+
+951 293 837 818 964 958 948  0.0
+
+952 810 294 837 816 948 819  0.0
+
+953 300 844 810 949 955 1135  0.0
+
+954 843 300 842 955 965 957  0.0
+
+955 300 810 842 959 954 953  0.0
+
+956 809 842 293 959 961 965  0.0
+
+957 1544 300 843 954 946 1135  0.0
+
+958 818 819 293 963 951 962  0.0
+
+959 842 810 293 948 956 955  0.0
+
+960 819 838 286 987 979 962  0.0
+
+961 809 293 292 963 995 956  0.0
+
+962 838 819 818 958 950 960  0.0
+
+963 819 292 293 961 958 998  0.0
+
+964 837 836 818 821 951 816  0.0
+
+965 809 843 842 954 956 991  0.0
+
+966 278 277 416 969 843 967  0.0
+
+967 278 407 277 968 966 847  0.0
+
+968 593 277 407 967 975 984  0.0
+
+969 416 277 823 981 977 966  0.0
+
+970 949 305 407 975 973 972  0.0
+
+971 949 304 972 1039 1059 973  0.0
+
+972 305 949 948 1059 1041 970  0.0
+
+973 949 407 304 988 971 970  0.0
+
+974 416 838 287 950 837 987  0.0
+
+975 593 407 305 970 1036 968  0.0
+
+976 286 823 415 978 979 977  0.0
+
+977 823 286 416 987 969 976  0.0
+
+978 415 823 830 981 983 976  0.0
+
+979 286 415 819 985 960 976  0.0
+
+980 277 406 830 989 981 984  0.0
+
+981 830 823 277 969 980 978  0.0
+
+982 129 306 406 1034 986 1131  0.0
+
+983 415 830 276 989 1020 978  0.0
+
+984 593 406 277 980 968 986  0.0
+
+985 285 819 415 979 1014 998  0.0
+
+986 129 406 593 984 1049 982  0.0
+
+987 416 286 838 960 974 977  0.0
+
+988 950 304 407 973 847 838  0.0
+
+989 406 276 830 983 980 1034  0.0
+
+990 299 292 808 997 992 995  0.0
+
+991 299 843 809 965 995 3017  0.0
+
+992 299 808 298 1005 993 990  0.0
+
+993 298 1527 299 3017 992 1001  0.0
+
+994 292 285 820 1010 997 998  0.0
+
+995 299 809 292 961 990 991  0.0
+
+996 834 820 822 1010 1013 1008  0.0
+
+997 292 820 808 999 990 994  0.0
+
+998 819 285 292 994 963 985  0.0
+
+999 808 820 291 1008 1005 997  0.0
+
+1000 12 298 807 1002 1009 1001  0.0
+
+1001 12 1527 298 993 1000 -1   0.0
+
+1002 807 298 291 1005 1007 1000  0.0
+
+1003 807 758 1525 1103 1009 1007  0.0
+
+1004 291 834 758 1006 1007 1008  0.0
+
+1005 291 298 808 992 999 1002  0.0
+
+1006 833 758 834 1004 1033 1025  0.0
+
+1007 291 758 807 1003 1002 1004  0.0
+
+1008 820 834 291 1004 999 996  0.0
+
+1009 807 1525 12 -1  1000 1003  0.0
+
+1010 822 820 285 994 1014 996  0.0
+
+1011 1544 26 844 947 1135 -1   0.0
+
+1012 821 284 822 1013 1015 1021  0.0
+
+1013 822 284 834 1033 996 1012  0.0
+
+1014 822 285 415 985 1020 1010  0.0
+
+1015 821 822 276 1020 1016 1012  0.0
+
+1016 276 831 821 1019 1015 1017  0.0
+
+1017 831 276 306 1034 1032 1016  0.0
+
+1018 307 831 591 1032 1129 1019  0.0
+
+1019 821 831 307 1018 1030 1016  0.0
+
+1020 415 276 822 1015 1014 983  0.0
+
+1021 284 821 833 1023 1033 1012  0.0
+
+1022 833 757 11 1024 1025 1023  0.0
+
+1023 833 821 757 1027 1022 1021  0.0
+
+1024 11 757 308 1029 1031 1022  0.0
+
+1025 833 11 758 1103 1006 1022  0.0
+
+1026 308 832 131 1028 1105 1029  0.0
+
+1027 832 757 821 1023 1030 1029  0.0
+
+1028 131 832 307 1030 1094 1026  0.0
+
+1029 832 308 757 1024 1027 1026  0.0
+
+1030 307 832 821 1027 1019 1028  0.0
+
+1031 11 308 14 1105 -1  1024  0.0
+
+1032 591 831 306 1017 1085 1018  0.0
+
+1033 284 833 834 1006 1013 1021  0.0
+
+1034 406 306 276 1017 989 982  0.0
+
+1035 1540 332 326 2974 2031 2978  0.0
+
+1036 313 593 305 975 1041 1049  0.0
+
+1037 1538 358 357 1472 1474 1404  0.0
+
+1038 972 314 948 1040 1059 1046  0.0
+
+1039 304 594 972 941 971 841  0.0
+
+1040 948 314 973 1043 1045 1038  0.0
+
+1041 313 305 948 972 1056 1036  0.0
+
+1042 906 973 974 1044 1081 1047  0.0
+
+1043 425 973 314 1040 1132 1044  0.0
+
+1044 974 973 425 1043 1061 1042  0.0
+
+1045 948 973 947 1047 1056 1040  0.0
+
+1046 314 972 971 941 913 1038  0.0
+
+1047 947 973 906 1042 1053 1045  0.0
+
+1048 312 129 313 1049 1051 1086  0.0
+
+1049 129 593 313 1036 1048 986  0.0
+
+1050 41 313 947 1056 1055 1051  0.0
+
+1051 41 312 313 1048 1050 1092  0.0
+
+1052 127 854 41 1057 1055 1054  0.0
+
+1053 127 947 906 1047 1058 1055  0.0
+
+1054 424 854 127 1052 1071 1079  0.0
+
+1055 127 41 947 1050 1053 1052  0.0
+
+1056 313 948 947 1045 1050 1041  0.0
+
+1057 854 311 41 1092 1052 1114  0.0
+
+1058 127 906 907 1063 1071 1053  0.0
+
+1059 948 949 972 971 1038 972  0.0
+
+1060 975 584 974 1081 1061 1068  0.0
+
+1061 425 975 974 1060 1044 945  0.0
+
+1062 584 976 1560 3048 1069 1068  0.0
+
+1063 584 907 906 1058 1081 1078  0.0
+
+1064 426 1560 978 1067 1066 3049  0.0
+
+1065 978 977 861 935 937 1067  0.0
+
+1066 433 426 978 1064 942 1415  0.0
+
+1067 1560 977 978 1065 1064 3048  0.0
+
+1068 584 975 976 1082 1062 1060  0.0
+
+1069 1560 128 584 1078 1062 1075  0.0
+
+1070 424 907 908 1072 1073 1071  0.0
+
+1071 424 127 907 1058 1070 1054  0.0
+
+1072 908 907 128 1078 1077 1070  0.0
+
+1073 42 424 908 1070 1074 1128  0.0
+
+1074 908 423 42 1083 1073 1077  0.0
+
+1075 128 1560 423 3049 1077 1069  0.0
+
+1076 587 432 423 1083 1335 1370  0.0
+
+1077 423 908 128 1072 1075 1074  0.0
+
+1078 907 584 128 1069 1072 1063  0.0
+
+1079 854 424 852 1128 1114 1054  0.0
+
+1080 662 423 426 3049 1415 1343  0.0
+
+1081 906 974 584 1060 1063 1042  0.0
+
+1082 975 977 976 3048 1068 928  0.0
+
+1083 42 423 432 1076 1130 1074  0.0
+
+1084 130 591 592 1085 1087 1091  0.0
+
+1085 591 306 592 1131 1084 1032  0.0
+
+1086 312 592 129 1131 1048 1087  0.0
+
+1087 130 592 312 1086 1089 1084  0.0
+
+1088 590 130 311 1089 1102 1091  0.0
+
+1089 311 130 312 1087 1092 1088  0.0
+
+1090 853 311 852 1114 1127 1093  0.0
+
+1091 591 130 590 1088 1129 1084  0.0
+
+1092 41 311 312 1089 1051 1057  0.0
+
+1093 853 310 311 1102 1090 1104  0.0
+
+1094 309 131 307 1028 1095 1097  0.0
+
+1095 307 590 309 1096 1094 1129  0.0
+
+1096 309 590 310 1102 1099 1095  0.0
+
+1097 131 309 39 1099 1101 1094  0.0
+
+1098 14 39 430 1109 1117 1101  0.0
+
+1099 310 39 309 1097 1096 1100  0.0
+
+1100 310 589 39 1109 1099 1104  0.0
+
+1101 39 14 131 1105 1097 1098  0.0
+
+1102 590 311 310 1093 1096 1088  0.0
+
+1103 758 11 1525 -1  1003 1025  0.0
+
+1104 310 853 589 1108 1100 1093  0.0
+
+1105 14 308 131 1026 1101 1031  0.0
+
+1106 431 853 585 1127 1113 1108  0.0
+
+1107 585 852 42 1128 1113 1127  0.0
+
+1108 853 431 589 1112 1104 1106  0.0
+
+1109 39 589 430 1124 1098 1100  0.0
+
+1110 42 588 431 1111 1113 1130  0.0
+
+1111 427 431 588 1110 1389 1115  0.0
+
+1112 589 431 40 1115 1124 1108  0.0
+
+1113 42 431 585 1106 1107 1110  0.0
+
+1114 854 852 311 1090 1057 1079  0.0
+
+1115 40 431 427 1111 1121 1112  0.0
+
+1116 13 429 428 1118 1126 1120  0.0
+
+1117 429 14 430 1098 1118 1125  0.0
+
+1118 428 429 430 1117 1123 1116  0.0
+
+1119 2 1535 3 3019 -1  2014  0.0
+
+1120 429 13 1524 -1  1125 1116  0.0
+
+1121 428 40 427 1115 1122 1123  0.0
+
+1122 404 428 427 1121 1391 1377  0.0
+
+1123 428 430 40 1124 1121 1118  0.0
+
+1124 430 589 40 1112 1123 1109  0.0
+
+1125 14 429 1524 1120 -1  1117  0.0
+
+1126 13 428 34 1411 -1  1116  0.0
+
+1127 853 852 585 1107 1106 1090  0.0
+
+1128 424 42 852 1107 1079 1073  0.0
+
+1129 591 590 307 1095 1018 1091  0.0
+
+1130 588 42 432 1083 1369 1110  0.0
+
+1131 592 306 129 982 1086 1085  0.0
+
+1132 425 314 43 913 915 1043  0.0
+
+1133 338 37 1542 -1  2926 3001  0.0
+
+1134 120 1089 784 887 881 1136  0.0
+
+1135 1544 844 300 953 957 1011  0.0
+
+1136 776 1089 120 1134 1155 1145  0.0
+
+1137 776 612 763 1139 1141 1155  0.0
+
+1138 121 763 873 1142 1143 1152  0.0
+
+1139 763 612 1097 367 1142 1137  0.0
+
+1140 1087 873 762 1164 1177 1143  0.0
+
+1141 776 763 872 1152 1149 1137  0.0
+
+1142 873 763 1097 1139 655 1138  0.0
+
+1143 1087 121 873 1138 1140 1154  0.0
+
+1144 1089 1088 657 1146 1513 1145  0.0
+
+1145 1089 776 1088 1149 1144 1136  0.0
+
+1146 657 1088 872 1149 1151 1144  0.0
+
+1147 657 871 656 1181 1513 1182  0.0
+
+1148 872 121 775 1150 1151 1152  0.0
+
+1149 872 1088 776 1145 1141 1146  0.0
+
+1150 1086 775 121 1148 1167 1175  0.0
+
+1151 872 775 657 1153 1146 1148  0.0
+
+1152 121 872 763 1141 1138 1148  0.0
+
+1153 114 657 775 1151 1185 1182  0.0
+
+1154 121 1087 774 1156 1167 1143  0.0
+
+1155 776 120 612 1178 1137 1136  0.0
+
+1156 1087 444 774 1159 1154 1177  0.0
+
+1157 762 1033 444 627 1177 623  0.0
+
+1158 444 879 878 1514 1159 629  0.0
+
+1159 774 444 878 1158 1174 1156  0.0
+
+1160 878 780 122 1165 1174 1163  0.0
+
+1161 198 877 780 757 1163 645  0.0
+
+1162 1081 779 1082 1171 1321 1239  0.0
+
+1163 780 878 198 1514 1161 1160  0.0
+
+1164 873 51 762 623 1140 655  0.0
+
+1165 122 780 1082 1226 1171 1160  0.0
+
+1166 1086 774 1083 1168 1169 1167  0.0
+
+1167 1086 121 774 1154 1166 1150  0.0
+
+1168 1083 774 122 1174 1173 1166  0.0
+
+1169 443 1086 1083 1166 1224 1188  0.0
+
+1170 122 779 1084 1176 1179 1171  0.0
+
+1171 779 122 1082 1165 1162 1170  0.0
+
+1172 1085 113 1084 1210 1249 1208  0.0
+
+1173 1083 122 778 1179 1224 1168  0.0
+
+1174 774 878 122 1160 1168 1159  0.0
+
+1175 775 1086 777 1188 1185 1150  0.0
+
+1176 1084 779 446 1239 1249 1170  0.0
+
+1177 1087 762 444 1157 1156 1140  0.0
+
+1178 612 120 1059 365 367 1155  0.0
+
+1179 778 122 1084 1170 1210 1173  0.0
+
+1180 870 205 871 1181 1183 1191  0.0
+
+1181 205 656 871 1147 1180 892  0.0
+
+1182 871 657 114 1153 1183 1147  0.0
+
+1183 114 870 871 1180 1182 1189  0.0
+
+1184 761 777 869 1200 1223 1187  0.0
+
+1185 114 775 777 1175 1187 1153  0.0
+
+1186 791 761 442 1223 1215 1198  0.0
+
+1187 777 761 114 1189 1185 1184  0.0
+
+1188 1086 443 777 1200 1175 1169  0.0
+
+1189 870 114 761 1187 1195 1183  0.0
+
+1190 206 658 659 1192 1197 1227  0.0
+
+1191 870 658 205 1201 1180 1192  0.0
+
+1192 659 658 870 1191 1195 1190  0.0
+
+1193 660 661 206 1227 1199 1325  0.0
+
+1194 659 791 53 1196 1197 1198  0.0
+
+1195 659 870 761 1189 1198 1192  0.0
+
+1196 53 791 664 1212 1225 1194  0.0
+
+1197 659 53 206 1199 1190 1194  0.0
+
+1198 761 791 659 1194 1195 1186  0.0
+
+1199 206 53 660 1327 1193 1197  0.0
+
+1200 869 777 443 1188 1202 1184  0.0
+
+1201 658 204 205 938 1191 934  0.0
+
+1202 443 665 869 1205 1200 1203  0.0
+
+1203 665 443 778 1224 1204 1202  0.0
+
+1204 665 778 113 1210 1207 1203  0.0
+
+1205 442 869 665 1202 1220 1223  0.0
+
+1206 666 113 796 1208 1222 1207  0.0
+
+1207 113 666 665 1211 1204 1206  0.0
+
+1208 1085 796 113 1206 1172 1295  0.0
+
+1209 165 666 447 1222 1217 1216  0.0
+
+1210 778 1084 113 1172 1204 1179  0.0
+
+1211 868 665 666 1207 1216 1220  0.0
+
+1212 790 664 791 1196 1215 1214  0.0
+
+1213 790 442 868 1220 1219 1215  0.0
+
+1214 663 664 790 1212 1218 1366  0.0
+
+1215 790 791 442 1186 1213 1212  0.0
+
+1216 666 165 868 1219 1211 1209  0.0
+
+1217 866 165 447 1209 1287 1221  0.0
+
+1218 663 790 165 1219 1221 1214  0.0
+
+1219 868 165 790 1218 1213 1216  0.0
+
+1220 442 665 868 1211 1213 1205  0.0
+
+1221 866 663 165 1218 1217 1352  0.0
+
+1222 447 666 796 1206 1277 1209  0.0
+
+1223 869 442 761 1186 1184 1205  0.0
+
+1224 443 1083 778 1173 1203 1169  0.0
+
+1225 441 53 664 1196 1366 1330  0.0
+
+1226 1082 780 676 1229 1321 1165  0.0
+
+1227 658 206 661 1193 934 1190  0.0
+
+1228 676 1502 862 1230 1231 1236  0.0
+
+1229 780 1122 676 649 1226 757  0.0
+
+1230 862 1502 123 1232 1237 1228  0.0
+
+1231 676 862 1081 1240 1321 1228  0.0
+
+1232 1501 123 1502 1230 1235 1233  0.0
+
+1233 883 123 1501 1232 1251 1234  0.0
+
+1234 863 123 883 1233 1271 1246  0.0
+
+1235 1501 1502 788 1322 1248 1232  0.0
+
+1236 1502 676 445 649 723 1228  0.0
+
+1237 862 123 789 1243 1240 1230  0.0
+
+1238 446 1081 789 1240 1241 1239  0.0
+
+1239 446 779 1081 1162 1238 1176  0.0
+
+1240 1081 862 789 1237 1238 1231  0.0
+
+1241 667 446 789 1238 1245 1275  0.0
+
+1242 668 863 1218 1244 1247 1246  0.0
+
+1243 668 789 123 1237 1246 1245  0.0
+
+1244 1218 863 669 1261 1263 1242  0.0
+
+1245 667 789 668 1243 1282 1241  0.0
+
+1246 863 668 123 1243 1234 1242  0.0
+
+1247 864 668 1218 1242 1279 1282  0.0
+
+1248 788 454 1501 1251 1235 753  0.0
+
+1249 446 1085 1084 1172 1176 1275  0.0
+
+1250 883 882 675 1252 1271 1258  0.0
+
+1251 1501 454 883 1258 1233 1248  0.0
+
+1252 675 882 1220 1256 1255 1250  0.0
+
+1253 863 675 1219 1259 1261 1271  0.0
+
+1254 884 193 1220 1255 1268 1266  0.0
+
+1255 1220 193 675 1259 1252 1254  0.0
+
+1256 674 1220 882 1252 1272 1270  0.0
+
+1257 453 1483 1220 1268 1270 3037  0.0
+
+1258 454 882 883 1250 1251 739  0.0
+
+1259 1219 675 193 1255 1262 1253  0.0
+
+1260 669 1219 885 1262 1263 1261  0.0
+
+1261 669 863 1219 1253 1260 1244  0.0
+
+1262 1219 193 885 1266 1260 1259  0.0
+
+1263 669 885 1218 1269 1244 1260  0.0
+
+1264 903 452 884 1265 1267 1318  0.0
+
+1265 884 452 885 1273 1266 1264  0.0
+
+1266 885 193 884 1254 1265 1262  0.0
+
+1267 903 884 1483 1268 1320 1264  0.0
+
+1268 1220 1483 884 1267 1254 1257  0.0
+
+1269 1218 885 112 1304 1279 1263  0.0
+
+1270 453 1220 674 1256 1717 1257  0.0
+
+1271 863 883 675 1250 1253 1234  0.0
+
+1272 194 674 882 1256 743 749  0.0
+
+1273 1221 885 452 1265 1302 1304  0.0
+
+1274 667 208 796 1277 1295 1276  0.0
+
+1275 1085 446 667 1241 1295 1249  0.0
+
+1276 208 667 864 1282 1281 1274  0.0
+
+1277 796 208 447 1285 1222 1274  0.0
+
+1278 864 112 692 1294 1281 1279  0.0
+
+1279 112 864 1218 1247 1269 1278  0.0
+
+1280 670 692 1212 1294 1317 1292  0.0
+
+1281 864 692 208 1283 1276 1278  0.0
+
+1282 668 864 667 1276 1245 1247  0.0
+
+1283 208 692 867 1289 1285 1281  0.0
+
+1284 447 867 865 1286 1287 1285  0.0
+
+1285 447 208 867 1283 1284 1277  0.0
+
+1286 54 865 867 1284 1291 1510  0.0
+
+1287 447 865 866 1293 1217 1284  0.0
+
+1288 1213 691 209 1290 1309 1319  0.0
+
+1289 691 867 692 1283 1292 1291  0.0
+
+1290 670 209 691 1288 1292 1307  0.0
+
+1291 54 867 691 1289 1319 1286  0.0
+
+1292 670 691 692 1289 1280 1290  0.0
+
+1293 767 866 865 1287 1510 1352  0.0
+
+1294 1212 692 112 1278 1297 1280  0.0
+
+1295 667 796 1085 1208 1275 1274  0.0
+
+1296 1212 1221 693 849 1299 1297  0.0
+
+1297 1221 1212 112 1294 1304 1296  0.0
+
+1298 1221 111 1555 3040 849 1302  0.0
+
+1299 1212 693 1193 1314 1317 1296  0.0
+
+1300 1196 1195 111 3040 1512 1761  0.0
+
+1301 451 1555 1195 3040 1316 1311  0.0
+
+1302 111 1221 452 1273 1318 1298  0.0
+
+1303 55 1197 1186 1315 2277 2367  0.0
+
+1304 112 885 1221 1273 1297 1269  0.0
+
+1305 1555 1194 693 1314 849 1311  0.0
+
+1306 209 1193 689 1308 1309 1307  0.0
+
+1307 209 670 1193 1317 1306 1290  0.0
+
+1308 689 1193 451 1313 1310 1306  0.0
+
+1309 209 689 1213 1323 1288 1306  0.0
+
+1310 451 1186 689 1315 1308 1312  0.0
+
+1311 1194 1555 451 1301 1313 1305  0.0
+
+1312 905 1186 451 1310 1316 1771  0.0
+
+1313 451 1193 1194 1314 1311 1308  0.0
+
+1314 1193 693 1194 1305 1313 1299  0.0
+
+1315 689 1186 1197 1303 1460 1310  0.0
+
+1316 1195 905 451 1312 1301 1761  0.0
+
+1317 1193 670 1212 1280 1299 1307  0.0
+
+1318 452 903 111 1512 1302 1264  0.0
+
+1319 691 1213 54 1424 1291 1288  0.0
+
+1320 903 1483 671 1750 1753 1267  0.0
+
+1321 1082 676 1081 1231 1162 1226  0.0
+
+1322 788 1502 1503 723 716 1235  0.0
+
+1323 690 1213 689 1309 1446 1424  0.0
+
+1324 613 433 660 1325 1329 1333  0.0
+
+1325 433 661 660 1193 1324 942  0.0
+
+1326 207 441 792 1342 1331 1330  0.0
+
+1327 207 660 53 1199 1330 1329  0.0
+
+1328 620 792 793 1342 1365 1340  0.0
+
+1329 613 660 207 1327 1338 1324  0.0
+
+1330 441 207 53 1327 1225 1326  0.0
+
+1331 759 207 792 1326 1340 1338  0.0
+
+1332 662 613 586 1334 1343 1333  0.0
+
+1333 613 662 433 1415 1324 1332  0.0
+
+1334 586 613 614 1337 1341 1332  0.0
+
+1335 586 587 423 1076 1343 1376  0.0
+
+1336 768 614 759 1337 1339 1355  0.0
+
+1337 759 614 613 1334 1338 1336  0.0
+
+1338 759 613 207 1329 1331 1337  0.0
+
+1339 768 759 620 1340 1356 1336  0.0
+
+1340 792 620 759 1339 1331 1328  0.0
+
+1341 622 586 614 1334 1367 1376  0.0
+
+1342 792 441 793 1344 1328 1326  0.0
+
+1343 423 662 586 1332 1335 1080  0.0
+
+1344 441 166 793 1347 1342 1345  0.0
+
+1345 166 441 663 1366 1346 1344  0.0
+
+1346 166 663 767 1352 1349 1345  0.0
+
+1347 793 166 794 1348 1353 1344  0.0
+
+1348 166 449 794 1364 1347 1349  0.0
+
+1349 449 166 767 1346 1350 1348  0.0
+
+1350 449 767 54 1510 1437 1349  0.0
+
+1351 448 794 795 1364 1419 1362  0.0
+
+1352 663 866 767 1293 1346 1221  0.0
+
+1353 793 794 496 1362 1365 1347  0.0
+
+1354 494 621 768 1355 1359 1363  0.0
+
+1355 621 614 768 1336 1354 1367  0.0
+
+1356 768 620 496 1365 1357 1339  0.0
+
+1357 769 768 496 1356 1360 1359  0.0
+
+1358 384 493 494 1398 1361 1509  0.0
+
+1359 769 494 768 1354 1357 1361  0.0
+
+1360 448 769 496 1357 1362 1414  0.0
+
+1361 769 384 494 1358 1359 1427  0.0
+
+1362 496 794 448 1351 1360 1353  0.0
+
+1363 621 494 770 1398 1412 1354  0.0
+
+1364 794 449 795 1416 1351 1348  0.0
+
+1365 620 793 496 1353 1356 1328  0.0
+
+1366 664 663 441 1345 1225 1214  0.0
+
+1367 622 614 621 1355 1374 1341  0.0
+
+1368 756 588 909 1369 1371 1389  0.0
+
+1369 588 432 909 1370 1368 1130  0.0
+
+1370 909 432 587 1076 1371 1369  0.0
+
+1371 756 909 587 1370 1373 1368  0.0
+
+1372 756 622 760 1374 1388 1373  0.0
+
+1373 622 756 587 1371 1376 1372  0.0
+
+1374 622 621 760 1412 1372 1367  0.0
+
+1375 427 756 403 1388 1391 1389  0.0
+
+1376 587 586 622 1341 1373 1335  0.0
+
+1377 404 405 428 1411 1122 1399  0.0
+
+1378 17 1270 1271 1494 1496 1381  0.0
+
+1379 358 1523 359 1385 1407 1404  0.0
+
+1380 1344 1545 1531 -1  3053 1515  0.0
+
+1381 1270 17 20 -1  1387 1378  0.0
+
+1382 96 6 7 -1  2518 2521  0.0
+
+1383 911 1534 936 2929 185 28  0.0
+
+1384 1532 9 361 1465 1405 -1   0.0
+
+1385 359 1523 1532 -1  1507 1379  0.0
+
+1386 8 97 7 2518 -1  2520  0.0
+
+1387 1268 1270 20 1381 1481 2651  0.0
+
+1388 760 403 756 1375 1372 1397  0.0
+
+1389 427 588 756 1368 1375 1111  0.0
+
+1390 260 404 403 1391 1394 1410  0.0
+
+1391 404 427 403 1375 1390 1122  0.0
+
+1392 493 760 770 1412 1398 1393  0.0
+
+1393 760 493 492 1395 1397 1392  0.0
+
+1394 492 260 403 1390 1397 1396  0.0
+
+1395 491 492 493 1393 1509 1429  0.0
+
+1396 383 260 492 1394 1429 1435  0.0
+
+1397 403 760 492 1393 1394 1388  0.0
+
+1398 770 494 493 1358 1392 1363  0.0
+
+1399 405 404 377 1483 1464 1377  0.0
+
+1400 1561 1529 923 1704 3050 2922  0.0
+
+1401 36 35 372 1467 1482 -1   0.0
+
+1402 1345 1575 1522 3077 2016 1938  0.0
+
+1403 1271 19 1526 -1  1511 2638  0.0
+
+1404 358 1538 1523 -1  1379 1037  0.0
+
+1405 1532 361 360 1473 1507 1384  0.0
+
+1406 36 363 9 1462 -1  1466  0.0
+
+1407 358 359 356 1477 1472 1379  0.0
+
+1408 275 35 405 1409 1464 1467  0.0
+
+1409 405 35 34 -1  1411 1408  0.0
+
+1410 260 376 404 1483 1390 1485  0.0
+
+1411 405 34 428 1126 1377 1409  0.0
+
+1412 621 770 760 1392 1374 1363  0.0
+
+1413 8 1538 1269 1474 1479 -1   0.0
+
+1414 448 385 769 1427 1360 1434  0.0
+
+1415 662 426 433 1066 1333 1080  0.0
+
+1416 904 795 449 1364 1437 1418  0.0
+
+1417 904 54 690 1424 1421 1437  0.0
+
+1418 795 904 167 1421 1423 1416  0.0
+
+1419 448 795 495 1423 1434 1351  0.0
+
+1420 167 690 1214 1422 1425 1421  0.0
+
+1421 690 167 904 1418 1417 1420  0.0
+
+1422 1214 690 450 1446 1439 1420  0.0
+
+1423 795 167 495 1431 1419 1418  0.0
+
+1424 1213 690 54 1417 1319 1323  0.0
+
+1425 1215 167 1214 1420 1436 1431  0.0
+
+1426 491 384 463 1428 1451 1509  0.0
+
+1427 769 385 384 1428 1361 1414  0.0
+
+1428 385 463 384 1426 1427 1449  0.0
+
+1429 491 383 492 1396 1395 1430  0.0
+
+1430 383 491 465 1457 1506 1429  0.0
+
+1431 1215 495 167 1423 1425 1432  0.0
+
+1432 386 495 1215 1431 1441 1433  0.0
+
+1433 495 386 385 1449 1434 1432  0.0
+
+1434 495 385 448 1414 1419 1433  0.0
+
+1435 260 383 382 1506 1486 1396  0.0
+
+1436 1215 1214 696 1439 1459 1425  0.0
+
+1437 449 54 904 1417 1416 1350  0.0
+
+1438 168 1208 1207 1456 1444 2653  0.0
+
+1439 450 696 1214 1436 1422 1440  0.0
+
+1440 1202 696 450 1439 1445 1447  0.0
+
+1441 1207 386 1215 1432 1459 1456  0.0
+
+1442 1197 695 1202 1508 1445 1443  0.0
+
+1443 1198 695 1197 1442 2367 2295  0.0
+
+1444 696 168 1207 1438 1459 1447  0.0
+
+1445 1197 1202 450 1440 1460 1442  0.0
+
+1446 690 689 450 1460 1422 1323  0.0
+
+1447 1202 168 696 1444 1440 2287  0.0
+
+1448 259 463 462 1450 1452 1451  0.0
+
+1449 463 385 386 1433 1450 1428  0.0
+
+1450 462 463 386 1449 1453 1448  0.0
+
+1451 463 259 491 1457 1426 1448  0.0
+
+1452 390 259 462 1448 2330 1455  0.0
+
+1453 1208 462 386 1450 1456 1454  0.0
+
+1454 1208 1209 462 2333 1453 2653  0.0
+
+1455 259 390 464 2341 1461 1452  0.0
+
+1456 386 1207 1208 1438 1453 1441  0.0
+
+1457 465 491 259 1451 1461 1430  0.0
+
+1458 391 465 464 1461 2341 1492  0.0
+
+1459 1215 696 1207 1444 1441 1436  0.0
+
+1460 1197 450 689 1446 1315 1445  0.0
+
+1461 465 259 464 1455 1458 1457  0.0
+
+1462 362 9 363 1406 1471 1465  0.0
+
+1463 275 377 373 1484 1504 1464  0.0
+
+1464 275 405 377 1399 1463 1408  0.0
+
+1465 9 362 361 1469 1384 1462  0.0
+
+1466 364 363 36 1406 1482 1468  0.0
+
+1467 275 372 35 1401 1408 1491  0.0
+
+1468 351 363 364 1466 1487 1500  0.0
+
+1469 353 361 362 1465 1502 1480  0.0
+
+1470 377 376 374 1505 1484 1483  0.0
+
+1471 363 352 362 1502 1462 1500  0.0
+
+1472 356 357 358 1037 1407 1497  0.0
+
+1473 354 360 361 1405 1480 1478  0.0
+
+1474 1269 1538 357 1037 1476 1413  0.0
+
+1475 355 359 360 1507 1478 1477  0.0
+
+1476 1269 357 370 2509 2519 1474  0.0
+
+1477 356 359 355 1475 1495 1407  0.0
+
+1478 355 360 354 1473 1499 1475  0.0
+
+1479 8 1269 98 2524 2520 1413  0.0
+
+1480 354 361 353 1469 1501 1473  0.0
+
+1481 20 6 1268 2521 1387 -1   0.0
+
+1482 36 372 364 1493 1466 1401  0.0
+
+1483 377 404 376 1410 1470 1399  0.0
+
+1484 374 373 377 1463 1470 1488  0.0
+
+1485 376 260 375 1486 1505 1410  0.0
+
+1486 260 382 375 1490 1485 1435  0.0
+
+1487 364 350 351 2555 1468 1493  0.0
+
+1488 373 374 378 2473 2472 1484  0.0
+
+1489 375 261 374 2473 1505 1490  0.0
+
+1490 375 382 261 2464 1489 1486  0.0
+
+1491 275 349 372 2475 1467 1504  0.0
+
+1492 382 465 391 1458 2483 1506  0.0
+
+1493 350 364 372 1482 2475 1487  0.0
+
+1494 1271 1270 1272 2898 2638 1378  0.0
+
+1495 356 355 368 2510 2529 1477  0.0
+
+1496 1271 18 17 -1  1378 1511  0.0
+
+1497 357 356 369 2529 2509 1472  0.0
+
+1498 365 353 352 1502 2513 2512  0.0
+
+1499 367 355 354 1478 2516 2510  0.0
+
+1500 352 363 351 1468 1503 1471  0.0
+
+1501 353 366 354 2516 1480 2512  0.0
+
+1502 352 353 362 1469 1471 1498  0.0
+
+1503 352 351 371 2481 2513 1500  0.0
+
+1504 373 349 275 1491 1463 2472  0.0
+
+1505 375 374 376 1470 1485 1489  0.0
+
+1506 465 382 383 1435 1430 1492  0.0
+
+1507 359 1532 360 1405 1475 1385  0.0
+
+1508 1203 1202 695 1442 2284 2287  0.0
+
+1509 493 384 491 1426 1395 1358  0.0
+
+1510 767 865 54 1286 1350 1293  0.0
+
+1511 18 1271 1526 1403 -1  1496  0.0
+
+1512 903 1196 111 1300 1318 1762  0.0
+
+1513 657 656 1089 887 1144 1147  0.0
+
+1514 198 878 879 1158 626 1163  0.0
+
+1515 755 1545 1344 1380 1900 1902  0.0
+
+1516 1248 1046 1249 545 1526 553  0.0
+
+1517 600 1554 990 218 231 229  0.0
+
+1518 1245 1256 1047 1525 508 512  0.0
+
+1519 1489 634 1256 1520 512 496  0.0
+
+1520 1484 1256 634 1519 1559 1523  0.0
+
+1521 940 634 1056 496 498 1543  0.0
+
+1522 932 1265 925 497 1524 1539  0.0
+
+1523 1256 1484 1485 1541 1525 1520  0.0
+
+1524 925 754 932 1560 1522 562  0.0
+
+1525 1256 1485 1047 1534 1518 1523  0.0
+
+1526 1249 507 1248 1529 1516 1527  0.0
+
+1527 507 1249 1047 509 1528 1526  0.0
+
+1528 507 1047 1486 1534 1532 1527  0.0
+
+1529 1248 507 1492 1531 1530 1526  0.0
+
+1530 1248 1492 1050 1533 3085 1529  0.0
+
+1531 1299 1492 507 1529 1549 1557  0.0
+
+1532 1486 1049 507 1549 1528 1550  0.0
+
+1533 1160 1050 1492 1530 1592 1570  0.0
+
+1534 1047 1485 1486 1536 1528 1525  0.0
+
+1535 1050 252 1149 558 1895 1570  0.0
+
+1536 1486 1485 1257 1547 1550 1534  0.0
+
+1537 401 1265 940 1540 498 497  0.0
+
+1538 1258 1484 1055 1559 1613 1542  0.0
+
+1539 1264 1265 932 1522 1546 1540  0.0
+
+1540 940 1265 1264 1539 1558 1537  0.0
+
+1541 1485 1484 1048 1542 1547 1523  0.0
+
+1542 1484 1258 1048 1544 1541 1538  0.0
+
+1543 634 940 1055 1610 1559 1521  0.0
+
+1544 1054 1048 1258 1542 1621 1545  0.0
+
+1545 1298 1048 1054 1544 1631 1556  0.0
+
+1546 1264 932 931 1560 1611 1539  0.0
+
+1547 1048 1257 1485 1536 1541 1556  0.0
+
+1548 508 1299 1049 1549 1551 1555  0.0
+
+1549 1299 507 1049 1532 1548 1531  0.0
+
+1550 1049 1486 1257 1536 1551 1532  0.0
+
+1551 508 1049 1257 1550 1553 1548  0.0
+
+1552 1300 508 513 1620 1554 1555  0.0
+
+1553 1298 508 1257 1551 1556 1608  0.0
+
+1554 1053 1300 513 1552 1623 1606  0.0
+
+1555 508 1300 1299 1561 1548 1552  0.0
+
+1556 1257 1048 1298 1545 1553 1547  0.0
+
+1557 1492 1299 1493 1561 1592 1531  0.0
+
+1558 1263 940 1264 1540 1617 1610  0.0
+
+1559 1484 634 1055 1543 1538 1520  0.0
+
+1560 932 754 931 1703 1546 1524  0.0
+
+1561 1300 1493 1299 1557 1555 1606  0.0
+
+1562 1052 252 1051 1564 1565 1563  0.0
+
+1563 1052 1147 252 554 1562 685  0.0
+
+1564 1051 252 1160 1570 1569 1562  0.0
+
+1565 510 1052 1051 1562 1571 1574  0.0
+
+1566 1051 1158 1157 1605 1571 1568  0.0
+
+1567 1159 1160 509 1586 1585 1569  0.0
+
+1568 1158 1051 1159 1569 1593 1566  0.0
+
+1569 1159 1051 1160 1564 1567 1568  0.0
+
+1570 1050 1160 252 1564 1535 1533  0.0
+
+1571 510 1051 1157 1566 1580 1565  0.0
+
+1572 1143 1144 510 1574 1575 1573  0.0
+
+1573 1143 682 1144 700 1572 696  0.0
+
+1574 510 1144 1052 1583 1565 1572  0.0
+
+1575 887 1143 510 1572 1579 1609  0.0
+
+1576 1154 1155 511 1578 1603 1581  0.0
+
+1577 1156 1155 510 1579 1580 1578  0.0
+
+1578 1156 511 1155 1576 1577 1594  0.0
+
+1579 887 510 1155 1577 1581 1575  0.0
+
+1580 510 1157 1156 1582 1577 1571  0.0
+
+1581 887 1155 1154 1576 1709 1579  0.0
+
+1582 1156 1157 1497 1595 1594 1580  0.0
+
+1583 1145 1052 1144 1574 700 684  0.0
+
+1584 1159 1496 684 1602 1593 1585  0.0
+
+1585 1496 1159 509 1567 1588 1584  0.0
+
+1586 1493 509 1160 1567 1592 1587  0.0
+
+1587 1494 509 1493 1586 1589 1588  0.0
+
+1588 509 1494 1496 1590 1585 1587  0.0
+
+1589 1494 1493 1053 1606 1604 1587  0.0
+
+1590 1169 1496 1494 1588 1657 1591  0.0
+
+1591 1168 1496 1169 1590 1677 1602  0.0
+
+1592 1492 1493 1160 1586 1533 1557  0.0
+
+1593 1159 684 1158 1605 1568 1584  0.0
+
+1594 1156 1497 511 1597 1578 1582  0.0
+
+1595 1157 684 1497 1596 1582 1605  0.0
+
+1596 1497 684 1168 1602 1599 1595  0.0
+
+1597 511 1497 1166 1598 1607 1594  0.0
+
+1598 1497 1167 1166 1601 1597 1599  0.0
+
+1599 1167 1497 1168 1596 1600 1598  0.0
+
+1600 1167 1168 1175 1659 1667 1599  0.0
+
+1601 1166 1167 685 1667 1675 1598  0.0
+
+1602 684 1496 1168 1591 1596 1584  0.0
+
+1603 1154 511 1153 1748 1734 1576  0.0
+
+1604 1495 1494 1053 1589 1623 1657  0.0
+
+1605 684 1157 1158 1566 1593 1595  0.0
+
+1606 1300 1053 1493 1589 1561 1554  0.0
+
+1607 1166 1165 511 1748 1597 1673  0.0
+
+1608 1298 1297 508 1620 1553 1625  0.0
+
+1609 1143 887 1142 754 696 1575  0.0
+
+1610 940 1263 1055 1612 1543 1558  0.0
+
+1611 931 399 1264 1617 1546 1615  0.0
+
+1612 1055 1263 255 1616 1619 1610  0.0
+
+1613 1258 1055 1513 1619 1621 1538  0.0
+
+1614 1263 399 941 1639 1616 1617  0.0
+
+1615 1342 399 931 1611 1653 1633  0.0
+
+1616 1263 941 255 1632 1612 1614  0.0
+
+1617 399 1263 1264 1558 1611 1614  0.0
+
+1618 4 1545 930 1640 756 -1   0.0
+
+1619 1055 255 1513 1630 1613 1612  0.0
+
+1620 508 1297 513 1627 1552 1608  0.0
+
+1621 1054 1258 1513 1613 1622 1544  0.0
+
+1622 1260 1054 1513 1621 1628 1631  0.0
+
+1623 1495 1053 513 1554 1664 1604  0.0
+
+1624 1261 1297 514 1626 1643 1627  0.0
+
+1625 1297 1298 1260 1631 1626 1608  0.0
+
+1626 1260 514 1297 1624 1625 1635  0.0
+
+1627 1297 1261 513 1629 1620 1624  0.0
+
+1628 1260 1513 1259 1630 1635 1622  0.0
+
+1629 1293 513 1261 1627 1655 1664  0.0
+
+1630 1259 1513 255 1619 1634 1628  0.0
+
+1631 1054 1260 1298 1625 1545 1622  0.0
+
+1632 1338 255 941 1616 1636 1634  0.0
+
+1633 1342 942 399 1639 1615 1637  0.0
+
+1634 255 1338 1259 1641 1630 1632  0.0
+
+1635 514 1260 1259 1628 1644 1626  0.0
+
+1636 941 637 1338 1915 1632 1702  0.0
+
+1637 942 1342 1343 1897 1896 1633  0.0
+
+1638 1262 519 1295 1648 1647 1904  0.0
+
+1639 941 399 942 1633 1702 1614  0.0
+
+1640 1545 931 930 1703 1618 1902  0.0
+
+1641 1259 1338 1262 1652 1650 1634  0.0
+
+1642 1514 1261 515 1643 1651 1655  0.0
+
+1643 1261 514 515 1646 1642 1624  0.0
+
+1644 514 1259 1296 1650 1645 1635  0.0
+
+1645 1295 514 1296 1644 1647 1646  0.0
+
+1646 514 1295 515 1648 1643 1645  0.0
+
+1647 1295 1296 1262 1650 1638 1645  0.0
+
+1648 515 1295 519 1638 1649 1646  0.0
+
+1649 1294 515 519 1648 2273 1700  0.0
+
+1650 1259 1262 1296 1647 1644 1641  0.0
+
+1651 1514 515 1292 1700 1686 1642  0.0
+
+1652 1339 1262 1338 1641 1915 1905  0.0
+
+1653 931 755 1342 1897 1615 1902  0.0
+
+1654 923 1536 754 3028 562 1704  0.0
+
+1655 1293 1261 1514 1642 1661 1629  0.0
+
+1656 1169 1495 512 1658 1677 1657  0.0
+
+1657 1494 1495 1169 1656 1590 1604  0.0
+
+1658 512 1495 1498 1660 1665 1656  0.0
+
+1659 512 1175 1168 1600 1677 1665  0.0
+
+1660 518 1498 1495 1658 1663 1662  0.0
+
+1661 1293 1514 518 1686 1663 1655  0.0
+
+1662 1498 518 1499 1699 1681 1660  0.0
+
+1663 518 1495 1293 1664 1661 1660  0.0
+
+1664 513 1293 1495 1663 1623 1629  0.0
+
+1665 512 1498 1175 1674 1659 1658  0.0
+
+1666 685 1175 1174 1668 3041 1667  0.0
+
+1667 685 1167 1175 1600 1666 1601  0.0
+
+1668 1174 1175 251 1674 1671 1666  0.0
+
+1669 1174 1173 1556 3042 3041 1671  0.0
+
+1670 1173 251 1468 1672 1705 1671  0.0
+
+1671 251 1173 1174 1669 1668 1670  0.0
+
+1672 1288 1468 251 1670 1691 1688  0.0
+
+1673 1165 1166 1556 1675 1806 1607  0.0
+
+1674 1175 1498 251 1676 1668 1665  0.0
+
+1675 685 1556 1166 1673 1601 3041  0.0
+
+1676 251 1498 1291 1681 1691 1674  0.0
+
+1677 1169 512 1168 1659 1591 1656  0.0
+
+1678 1292 516 1499 1680 1699 1679  0.0
+
+1679 516 1292 1294 1700 1683 1678  0.0
+
+1680 1499 516 1500 1682 1687 1678  0.0
+
+1681 1499 1291 1498 1676 1662 1687  0.0
+
+1682 1500 516 747 1685 1696 1680  0.0
+
+1683 1515 516 1294 1679 1684 1685  0.0
+
+1684 1516 1515 1294 1683 1961 1940  0.0
+
+1685 747 516 1515 1683 1894 1682  0.0
+
+1686 1514 1292 518 1699 1661 1651  0.0
+
+1687 1499 1500 1291 1693 1681 1680  0.0
+
+1688 1288 1469 1468 1697 1672 1690  0.0
+
+1689 1288 1291 517 1693 1695 1691  0.0
+
+1690 1469 1288 1287 1695 1701 1688  0.0
+
+1691 1288 251 1291 1676 1689 1672  0.0
+
+1692 1287 517 192 1698 1694 1695  0.0
+
+1693 517 1291 1500 1687 1696 1689  0.0
+
+1694 1317 1287 192 1692 1987 1828  0.0
+
+1695 517 1287 1288 1690 1689 1692  0.0
+
+1696 1500 747 517 1698 1693 1682  0.0
+
+1697 1468 1469 476 1892 1842 1688  0.0
+
+1698 192 517 747 1696 1951 1692  0.0
+
+1699 1499 518 1292 1686 1678 1662  0.0
+
+1700 515 1294 1292 1679 1651 1649  0.0
+
+1701 1470 1469 1287 1690 1826 1892  0.0
+
+1702 637 941 942 1639 1901 1636  0.0
+
+1703 930 931 754 1560 3028 1640  0.0
+
+1704 1536 923 1529 1400 -1  1654  0.0
+
+1705 1172 1173 1468 1670 1803 3042  0.0
+
+1706 673 1519 1140 1707 1713 1725  0.0
+
+1707 1141 1140 1519 1706 750 1712  0.0
+
+1708 195 1139 1140 1713 1711 1724  0.0
+
+1709 887 1154 195 1734 1711 1581  0.0
+
+1710 1138 1139 1151 1724 1726 1722  0.0
+
+1711 195 1140 887 1712 1709 1708  0.0
+
+1712 887 1140 1141 1707 754 1711  0.0
+
+1713 673 1140 1139 1708 1722 1706  0.0
+
+1714 1128 1127 56 1721 1723 1797  0.0
+
+1715 1127 1126 673 1725 1716 746  0.0
+
+1716 1518 1127 673 1715 1719 1721  0.0
+
+1717 1128 453 674 1270 1797 1751  0.0
+
+1718 56 1518 1137 1720 1739 1721  0.0
+
+1719 1138 1518 673 1716 1722 1720  0.0
+
+1720 1137 1518 1138 1719 1727 1718  0.0
+
+1721 1518 56 1127 1714 1716 1718  0.0
+
+1722 673 1139 1138 1710 1719 1713  0.0
+
+1723 1517 1128 56 1714 1738 1758  0.0
+
+1724 1139 195 1151 1747 1710 1708  0.0
+
+1725 1126 1519 673 1706 1715 732  0.0
+
+1726 1138 1151 1150 1729 1727 1710  0.0
+
+1727 1138 1150 1137 1737 1720 1726  0.0
+
+1728 1151 1153 1152 1731 1733 1747  0.0
+
+1729 457 1150 1151 1726 1735 1741  0.0
+
+1730 1152 1165 1164 1732 1733 1731  0.0
+
+1731 1165 1152 1153 1728 1748 1730  0.0
+
+1732 1164 1165 125 1799 1746 1730  0.0
+
+1733 1152 1164 1151 1735 1728 1730  0.0
+
+1734 1154 1153 195 1747 1709 1603  0.0
+
+1735 457 1151 1164 1733 1744 1729  0.0
+
+1736 1136 457 1135 1743 1749 1741  0.0
+
+1737 1136 1137 1150 1727 1741 1739  0.0
+
+1738 1517 56 1136 1739 1755 1723  0.0
+
+1739 1137 1136 56 1738 1718 1737  0.0
+
+1740 457 1163 1134 1742 1743 1744  0.0
+
+1741 1136 1150 457 1729 1736 1737  0.0
+
+1742 1134 1163 1162 1819 1809 1740  0.0
+
+1743 457 1134 1135 1745 1736 1740  0.0
+
+1744 1164 1163 457 1740 1735 1746  0.0
+
+1745 1135 1134 249 1796 1794 1743  0.0
+
+1746 1164 125 1163 1819 1744 1732  0.0
+
+1747 1151 195 1153 1734 1728 1724  0.0
+
+1748 1165 1153 511 1603 1607 1731  0.0
+
+1749 672 1136 1135 1736 1794 1755  0.0
+
+1750 1129 671 1483 1320 3037 1752  0.0
+
+1751 453 1128 1129 1758 3037 1717  0.0
+
+1752 671 1129 1130 1754 1759 1750  0.0
+
+1753 247 903 671 1320 1765 1762  0.0
+
+1754 672 1130 1129 1752 1757 1756  0.0
+
+1755 1517 1136 672 1749 1757 1738  0.0
+
+1756 1130 672 1131 1780 1770 1754  0.0
+
+1757 672 1129 1517 1758 1755 1754  0.0
+
+1758 1128 1517 1129 1757 1751 1723  0.0
+
+1759 671 1130 248 1770 1768 1752  0.0
+
+1760 905 1196 247 1762 1763 1761  0.0
+
+1761 905 1195 1196 1300 1760 1316  0.0
+
+1762 903 247 1196 1760 1512 1753  0.0
+
+1763 905 247 687 1764 1769 1760  0.0
+
+1764 687 247 1176 1783 1791 1763  0.0
+
+1765 671 1181 247 1767 1753 1768  0.0
+
+1766 1182 1181 248 1768 1773 1793  0.0
+
+1767 1177 247 1181 1765 1775 1783  0.0
+
+1768 671 248 1181 1766 1765 1759  0.0
+
+1769 905 687 1187 2279 1771 1763  0.0
+
+1770 248 1130 1131 1756 1773 1759  0.0
+
+1771 905 1187 1186 2277 1312 1769  0.0
+
+1772 458 1182 1183 1774 1779 1793  0.0
+
+1773 1131 1182 248 1766 1770 1774  0.0
+
+1774 1183 1182 1131 1773 1776 1772  0.0
+
+1775 458 1177 1181 1767 1793 1784  0.0
+
+1776 1131 1132 1183 1792 1774 1777  0.0
+
+1777 1132 1131 249 1780 1778 1776  0.0
+
+1778 1133 1132 249 1777 1796 1891  0.0
+
+1779 458 1183 1179 1781 1790 1772  0.0
+
+1780 1131 672 249 1794 1777 1756  0.0
+
+1781 124 1179 1183 1779 1847 1865  0.0
+
+1782 688 1176 1177 1783 1785 1787  0.0
+
+1783 1176 247 1177 1767 1782 1764  0.0
+
+1784 1178 1177 458 1775 1790 1785  0.0
+
+1785 688 1177 1178 1784 1788 1782  0.0
+
+1786 688 737 173 2318 1787 1857  0.0
+
+1787 688 173 1176 1795 1782 1786  0.0
+
+1788 1178 738 688 1857 1785 1789  0.0
+
+1789 1179 738 1178 1788 1790 1855  0.0
+
+1790 1178 458 1179 1779 1789 1784  0.0
+
+1791 687 1176 1189 1795 2282 1764  0.0
+
+1792 1184 1183 1132 1776 1845 1847  0.0
+
+1793 1181 1182 458 1772 1775 1766  0.0
+
+1794 1135 249 672 1780 1749 1745  0.0
+
+1795 173 1189 1176 1791 1787 2297  0.0
+
+1796 1133 249 1134 1745 1808 1778  0.0
+
+1797 674 1127 1128 1714 1717 746  0.0
+
+1798 125 1172 1171 1800 1801 1799  0.0
+
+1799 1172 125 1165 1732 1806 1798  0.0
+
+1800 1171 1172 1467 1803 1805 1798  0.0
+
+1801 125 1171 1162 1814 1819 1798  0.0
+
+1802 1467 476 1472 1818 1805 1842  0.0
+
+1803 1467 1172 1468 1705 1842 1800  0.0
+
+1804 1473 1472 475 1820 1841 1807  0.0
+
+1805 1467 1472 1171 1807 1800 1802  0.0
+
+1806 1556 1172 1165 1799 1673 3042  0.0
+
+1807 1171 1472 1473 1804 1816 1805  0.0
+
+1808 1134 1161 1133 1811 1796 1809  0.0
+
+1809 1134 1162 1161 1810 1808 1742  0.0
+
+1810 1161 1162 1170 1814 1813 1809  0.0
+
+1811 740 1133 1161 1808 1817 1891  0.0
+
+1812 1290 250 1170 1813 1815 1833  0.0
+
+1813 1170 250 1161 1817 1810 1812  0.0
+
+1814 1170 1162 1171 1801 1816 1810  0.0
+
+1815 1290 1170 1473 1816 1831 1812  0.0
+
+1816 1171 1473 1170 1815 1814 1807  0.0
+
+1817 250 740 1161 1811 1813 1849  0.0
+
+1818 1472 476 1471 1821 1820 1802  0.0
+
+1819 1162 1163 125 1746 1801 1742  0.0
+
+1820 1472 1471 475 1823 1804 1818  0.0
+
+1821 1471 476 1470 1892 1822 1818  0.0
+
+1822 1471 1470 1286 1826 1825 1821  0.0
+
+1823 475 1471 1475 1825 1829 1820  0.0
+
+1824 1285 1475 1286 1825 1827 1838  0.0
+
+1825 1286 1475 1471 1823 1822 1824  0.0
+
+1826 1286 1470 1287 1701 1828 1822  0.0
+
+1827 191 1285 1286 1824 1890 2103  0.0
+
+1828 1287 1317 1286 1890 1826 1694  0.0
+
+1829 475 1475 1474 1835 1841 1823  0.0
+
+1830 1477 1290 474 1832 1837 1833  0.0
+
+1831 1290 1473 1474 1841 1832 1815  0.0
+
+1832 474 1290 1474 1831 1835 1830  0.0
+
+1833 1290 1477 250 1839 1812 1830  0.0
+
+1834 1476 474 1284 1836 1888 1837  0.0
+
+1835 474 1474 1475 1829 1838 1832  0.0
+
+1836 1284 474 1285 1838 1840 1834  0.0
+
+1837 474 1476 1477 1843 1830 1834  0.0
+
+1838 1475 1285 474 1836 1835 1824  0.0
+
+1839 250 1477 1289 1874 1852 1833  0.0
+
+1840 1285 1315 1284 2093 1836 2103  0.0
+
+1841 1474 1473 475 1804 1829 1831  0.0
+
+1842 1467 1468 476 1697 1802 1803  0.0
+
+1843 1476 189 1477 1874 1837 1888  0.0
+
+1844 124 1184 1185 1846 1853 1847  0.0
+
+1845 1184 1132 740 1891 1846 1792  0.0
+
+1846 1185 1184 740 1845 1848 1844  0.0
+
+1847 124 1183 1184 1792 1844 1781  0.0
+
+1848 740 1478 1185 1850 1846 1849  0.0
+
+1849 740 250 1478 1852 1848 1817  0.0
+
+1850 739 1185 1478 1848 1866 1851  0.0
+
+1851 1482 1185 739 1850 1887 1853  0.0
+
+1852 250 1289 1478 1864 1849 1839  0.0
+
+1853 124 1185 1482 1851 1862 1844  0.0
+
+1854 470 738 1280 1860 1863 1893  0.0
+
+1855 738 1179 1180 1865 1856 1789  0.0
+
+1856 471 738 1180 1855 1861 1860  0.0
+
+1857 737 688 738 1788 1893 1786  0.0
+
+1858 471 1481 1280 1879 1860 1859  0.0
+
+1859 1482 1481 471 1858 1861 1887  0.0
+
+1860 471 1280 738 1854 1856 1858  0.0
+
+1861 1482 471 1180 1856 1862 1859  0.0
+
+1862 1180 124 1482 1853 1861 1865  0.0
+
+1863 470 1280 174 1876 1885 1854  0.0
+
+1864 1479 1478 1289 1852 1867 1866  0.0
+
+1865 1179 124 1180 1862 1855 1781  0.0
+
+1866 1478 1479 739 1869 1850 1864  0.0
+
+1867 1479 1289 189 1874 1868 1864  0.0
+
+1868 1479 189 1283 1871 1870 1867  0.0
+
+1869 739 1479 1480 1870 1875 1866  0.0
+
+1870 1479 1283 1480 1873 1869 1868  0.0
+
+1871 1283 189 1284 1888 1882 1868  0.0
+
+1872 1283 1566 472 3059 1884 3060  0.0
+
+1873 1480 1283 1282 1884 1877 1870  0.0
+
+1874 1289 1477 189 1843 1867 1839  0.0
+
+1875 739 1480 1481 1877 1887 1869  0.0
+
+1876 1280 1281 174 1883 1863 1879  0.0
+
+1877 1282 1481 1480 1875 1873 1878  0.0
+
+1878 1281 1481 1282 1877 1881 1879  0.0
+
+1879 1281 1280 1481 1858 1878 1876  0.0
+
+1880 1281 472 742 1886 1883 1881  0.0
+
+1881 472 1281 1282 1878 1884 1880  0.0
+
+1882 1284 473 1283 3060 1871 2093  0.0
+
+1883 1281 742 174 1889 1876 1880  0.0
+
+1884 1282 1283 472 1872 1881 1873  0.0
+
+1885 470 174 1192 2462 2304 1863  0.0
+
+1886 472 188 742 2139 1880 2149  0.0
+
+1887 739 1481 1482 1859 1851 1875  0.0
+
+1888 1476 1284 189 1871 1843 1834  0.0
+
+1889 742 1279 174 2462 1883 2369  0.0
+
+1890 1286 1317 191 2085 1827 1828  0.0
+
+1891 1133 740 1132 1845 1778 1811  0.0
+
+1892 1469 1470 476 1821 1697 1701  0.0
+
+1893 738 470 737 2301 1857 1854  0.0
+
+1894 747 1515 746 1940 1941 1685  0.0
+
+1895 1579 1050 1149 1535 555 3085  0.0
+
+1896 1343 400 942 1901 1637 1898  0.0
+
+1897 1343 1342 755 1653 1899 1637  0.0
+
+1898 400 1343 1340 3076 1917 1896  0.0
+
+1899 1575 1343 755 1897 1900 3076  0.0
+
+1900 1575 755 1344 1515 1922 1899  0.0
+
+1901 400 637 942 1702 1896 1914  0.0
+
+1902 1545 755 931 1653 1640 1515  0.0
+
+1903 1339 637 945 1914 1912 1915  0.0
+
+1904 1262 254 519 1907 1638 1905  0.0
+
+1905 1262 1339 254 1906 1904 1652  0.0
+
+1906 254 1339 1304 1912 1909 1905  0.0
+
+1907 519 254 1303 1909 1911 1904  0.0
+
+1908 1329 1303 572 1910 1927 1913  0.0
+
+1909 1304 1303 254 1907 1906 1910  0.0
+
+1910 572 1303 1304 1909 1928 1908  0.0
+
+1911 519 1303 1330 1913 2273 1907  0.0
+
+1912 1304 1339 945 1903 1937 1906  0.0
+
+1913 1330 1303 1329 1908 1948 1911  0.0
+
+1914 945 637 400 1901 1916 1903  0.0
+
+1915 1339 1338 637 1636 1903 1652  0.0
+
+1916 400 1335 945 1937 1914 1918  0.0
+
+1917 400 1340 1337 1921 1918 1898  0.0
+
+1918 400 1337 1335 1925 1916 1917  0.0
+
+1919 1335 1336 1304 1934 1937 1925  0.0
+
+1920 916 1337 946 1921 1986 1996  0.0
+
+1921 946 1337 1340 1917 1924 1920  0.0
+
+1922 1562 1575 1344 1900 3053 3077  0.0
+
+1923 1336 1337 892 1990 1936 1925  0.0
+
+1924 1340 1575 946 1938 1921 3076  0.0
+
+1925 1335 1337 1336 1923 1919 1918  0.0
+
+1926 522 572 1334 1928 1929 1927  0.0
+
+1927 522 1329 572 1908 1926 1935  0.0
+
+1928 1304 1334 572 1926 1910 1931  0.0
+
+1929 522 1334 1347 1930 1939 1926  0.0
+
+1930 1334 256 1347 1932 1929 1931  0.0
+
+1931 1304 256 1334 1930 1928 1934  0.0
+
+1932 1347 256 902 2081 1933 1930  0.0
+
+1933 554 1347 902 1932 1989 1984  0.0
+
+1934 256 1304 1336 1919 1936 1931  0.0
+
+1935 1329 522 1305 1962 1970 1927  0.0
+
+1936 892 256 1336 1934 1923 2081  0.0
+
+1937 1304 945 1335 1916 1919 1912  0.0
+
+1938 946 1575 1345 1402 1986 1924  0.0
+
+1939 1333 522 1347 1929 1984 1963  0.0
+
+1940 1516 746 1515 1894 1684 1943  0.0
+
+1941 747 746 520 1949 1951 1894  0.0
+
+1942 1516 1330 1302 1948 1943 1961  0.0
+
+1943 746 1516 1302 1942 1947 1940  0.0
+
+1944 1328 1305 521 1983 1946 1945  0.0
+
+1945 1302 1305 1328 1944 1947 1970  0.0
+
+1946 1328 521 745 19 1958 1944  0.0
+
+1947 1302 1328 746 1949 1943 1945  0.0
+
+1948 1330 1329 1302 1970 1942 1913  0.0
+
+1949 746 1328 520 1958 1941 1947  0.0
+
+1950 1301 192 744 1952 1957 1987  0.0
+
+1951 192 747 520 1941 1952 1698  0.0
+
+1952 744 192 520 1951 1955 1950  0.0
+
+1953 1316 1317 1301 1987 2090 2085  0.0
+
+1954 744 745 1308 1956 1959 1955  0.0
+
+1955 745 744 520 1952 1958 1954  0.0
+
+1956 1308 745 1553 19 1974 1954  0.0
+
+1957 477 1301 744 1950 2088 2090  0.0
+
+1958 520 1328 745 1946 1955 1949  0.0
+
+1959 552 744 1308 1954 1973 1985  0.0
+
+1960 521 1307 1553 91 19 1965  0.0
+
+1961 1330 1516 1294 1684 2273 1942  0.0
+
+1962 522 1306 1305 1983 1935 1963  0.0
+
+1963 522 1333 1306 1964 1962 1939  0.0
+
+1964 1306 1333 553 1967 1971 1963  0.0
+
+1965 1306 1307 521 1960 1983 1971  0.0
+
+1966 553 554 182 1968 1969 1967  0.0
+
+1967 554 553 1333 1964 1984 1966  0.0
+
+1968 555 182 554 1966 1989 2009  0.0
+
+1969 553 182 551 1982 1980 1966  0.0
+
+1970 1329 1305 1302 1945 1948 1935  0.0
+
+1971 1306 553 1307 1977 1965 1964  0.0
+
+1972 1332 552 183 1973 1975 1979  0.0
+
+1973 552 1308 183 1974 1972 1959  0.0
+
+1974 1308 1553 183 91 1973 1956  0.0
+
+1975 1332 183 1307 91 1977 1972  0.0
+
+1976 553 215 1332 1981 1977 1980  0.0
+
+1977 1332 1307 553 1971 1976 1975  0.0
+
+1978 215 551 181 2055 2053 1980  0.0
+
+1979 552 1332 1331 1981 2126 1972  0.0
+
+1980 551 215 553 1976 1969 1978  0.0
+
+1981 215 1331 1332 1979 1976 2112  0.0
+
+1982 182 550 551 2055 1969 2035  0.0
+
+1983 1305 1306 521 1965 1944 1962  0.0
+
+1984 554 1333 1347 1939 1933 1967  0.0
+
+1985 1309 744 552 1959 2105 2088  0.0
+
+1986 1345 916 946 1920 1938 1993  0.0
+
+1987 1301 1317 192 1694 1950 1953  0.0
+
+1988 1565 902 892 2081 3057 1997  0.0
+
+1989 555 554 902 1933 1999 1968  0.0
+
+1990 892 1337 1341 1996 3057 1923  0.0
+
+1991 893 1565 891 2012 2003 1997  0.0
+
+1992 1341 916 1576 1995 3058 1996  0.0
+
+1993 1345 1541 916 2032 1986 2016  0.0
+
+1994 67 891 890 2015 2011 2006  0.0
+
+1995 1576 916 1346 2032 3078 1992  0.0
+
+1996 1337 916 1341 1992 1990 1920  0.0
+
+1997 1565 893 902 1999 1988 1991  0.0
+
+1998 894 555 901 2000 2005 2001  0.0
+
+1999 893 555 902 1989 1997 2000  0.0
+
+2000 901 555 893 1999 2003 1998  0.0
+
+2001 555 894 216 2036 2009 1998  0.0
+
+2002 67 217 894 2007 2005 2004  0.0
+
+2003 901 893 891 1991 2006 2000  0.0
+
+2004 217 67 895 2013 2029 2002  0.0
+
+2005 67 894 901 1998 2006 2002  0.0
+
+2006 891 67 901 2005 2003 1994  0.0
+
+2007 894 217 896 2039 2036 2002  0.0
+
+2008 890 1535 899 2014 2010 2015  0.0
+
+2009 182 555 216 2001 2035 1968  0.0
+
+2010 900 890 899 2008 2017 2011  0.0
+
+2011 900 67 890 1994 2010 2013  0.0
+
+2012 891 1565 1576 3058 3079 1991  0.0
+
+2013 900 895 67 2004 2011 2020  0.0
+
+2014 2 899 1535 2008 1119 2019  0.0
+
+2015 890 891 1535 3079 2008 1994  0.0
+
+2016 1345 1522 1541 -1  1993 1402  0.0
+
+2017 900 899 66 2025 2021 2010  0.0
+
+2018 27 1550 1549 2272 -1  2838  0.0
+
+2019 897 899 2 2014 2028 2025  0.0
+
+2020 900 898 895 2023 2013 2021  0.0
+
+2021 898 900 66 2017 2022 2020  0.0
+
+2022 898 66 897 2025 2027 2021  0.0
+
+2023 1417 895 898 2020 2058 2064  0.0
+
+2024 1577 2 29 -1  3081 3080  0.0
+
+2025 897 66 899 2017 2019 2022  0.0
+
+2026 82 1539 148 2631 2628 2630  0.0
+
+2027 898 897 154 2061 2058 2022  0.0
+
+2028 897 2 65 3080 2078 2019  0.0
+
+2029 895 1416 217 2042 2004 2064  0.0
+
+2030 330 1549 329 2272 2774 2264  0.0
+
+2031 1564 1540 326 1035 2831 3056  0.0
+
+2032 1346 916 1541 1993 2082 1995  0.0
+
+2033 1406 1577 64 3046 2202 2204  0.0
+
+2034 68 550 216 2035 2037 2045  0.0
+
+2035 550 182 216 2009 2034 1982  0.0
+
+2036 216 894 896 2007 2037 2001  0.0
+
+2037 896 68 216 2034 2036 2049  0.0
+
+2038 1415 1416 153 2054 2043 2042  0.0
+
+2039 896 217 1415 2042 2041 2007  0.0
+
+2040 1418 153 238 2054 2077 2050  0.0
+
+2041 896 1415 1414 2043 2052 2039  0.0
+
+2042 217 1416 1415 2038 2039 2029  0.0
+
+2043 153 1414 1415 2041 2038 2050  0.0
+
+2044 550 549 181 2047 2055 2045  0.0
+
+2045 549 550 68 2034 2046 2044  0.0
+
+2046 219 549 68 2045 2083 2110  0.0
+
+2047 547 181 549 2044 2110 2106  0.0
+
+2048 1413 218 1414 2052 2051 2220  0.0
+
+2049 218 68 896 2037 2052 2083  0.0
+
+2050 1418 1414 153 2043 2040 2051  0.0
+
+2051 1418 1413 1414 2048 2050 2179  0.0
+
+2052 896 1414 218 2048 2049 2041  0.0
+
+2053 214 215 181 1978 2109 2112  0.0
+
+2054 153 1416 238 2057 2040 2038  0.0
+
+2055 181 551 550 1982 2044 1978  0.0
+
+2056 1402 238 1417 2057 2059 2067  0.0
+
+2057 1417 238 1416 2054 2064 2056  0.0
+
+2058 1417 898 154 2027 2059 2023  0.0
+
+2059 154 1402 1417 2056 2058 2074  0.0
+
+2060 1404 239 1405 2062 2075 2065  0.0
+
+2061 154 897 239 2078 2063 2027  0.0
+
+2062 1405 239 65 2078 2076 2060  0.0
+
+2063 154 239 1403 2070 2074 2061  0.0
+
+2064 1416 895 1417 2023 2057 2029  0.0
+
+2065 1404 237 239 2070 2060 2071  0.0
+
+2066 238 732 1419 2079 2077 2067  0.0
+
+2067 732 238 1402 2056 2068 2066  0.0
+
+2068 1401 732 1402 2067 2184 2181  0.0
+
+2069 1418 1419 733 2079 2178 2077  0.0
+
+2070 239 237 1403 2072 2063 2065  0.0
+
+2071 1408 237 1404 2065 2206 2198  0.0
+
+2072 731 1403 237 2070 2199 2073  0.0
+
+2073 731 1402 1403 2074 2072 2184  0.0
+
+2074 1402 154 1403 2063 2073 2059  0.0
+
+2075 1405 155 1404 2206 2060 2203  0.0
+
+2076 1405 65 1406 2204 2270 2062  0.0
+
+2077 238 1419 1418 2069 2040 2066  0.0
+
+2078 65 239 897 2061 2028 2062  0.0
+
+2079 732 733 1419 2069 2066 2180  0.0
+
+2080 1326 1325 1547 3035 2380 2381  0.0
+
+2081 902 256 892 1936 1988 1932  0.0
+
+2082 3 1346 1541 2032 -1  3019  0.0
+
+2083 68 218 219 2177 2046 2049  0.0
+
+2084 191 1316 743 2087 2091 2085  0.0
+
+2085 191 1317 1316 1953 2084 1890  0.0
+
+2086 1310 743 477 2087 2089 2100  0.0
+
+2087 477 743 1316 2084 2090 2086  0.0
+
+2088 477 744 1309 1985 2089 1957  0.0
+
+2089 1310 477 1309 2088 2102 2086  0.0
+
+2090 1316 1301 477 1957 2087 1953  0.0
+
+2091 191 743 1315 2097 2103 2084  0.0
+
+2092 473 1315 1314 2094 2175 2093  0.0
+
+2093 473 1284 1315 1840 2092 1882  0.0
+
+2094 1314 1315 478 2097 2099 2092  0.0
+
+2095 190 1566 1314 2175 2099 2129  0.0
+
+2096 478 1310 1311 2098 2101 2100  0.0
+
+2097 478 1315 743 2091 2100 2094  0.0
+
+2098 523 1311 1310 2096 2125 2127  0.0
+
+2099 1314 478 190 2101 2095 2094  0.0
+
+2100 743 1310 478 2096 2097 2086  0.0
+
+2101 1311 190 478 2099 2096 2130  0.0
+
+2102 1310 1309 184 2105 2125 2089  0.0
+
+2103 1315 1285 191 1827 2091 1840  0.0
+
+2104 1348 184 1331 2126 2107 2115  0.0
+
+2105 184 1309 552 1985 2126 2102  0.0
+
+2106 546 181 547 2047 2108 2109  0.0
+
+2107 214 1348 1331 2104 2112 2113  0.0
+
+2108 180 546 547 2106 2118 2121  0.0
+
+2109 546 214 181 2053 2106 2113  0.0
+
+2110 219 547 549 2047 2046 2111  0.0
+
+2111 69 547 219 2110 2174 2119  0.0
+
+2112 1331 215 214 2053 2107 1981  0.0
+
+2113 1348 214 546 2109 2116 2107  0.0
+
+2114 523 1348 213 2116 2117 2115  0.0
+
+2115 1348 523 184 2125 2104 2114  0.0
+
+2116 1348 546 213 2122 2114 2113  0.0
+
+2117 185 523 213 2114 2136 2133  0.0
+
+2118 547 548 180 2120 2108 2119  0.0
+
+2119 548 547 69 2111 2123 2118  0.0
+
+2120 548 1349 180 2121 2118 2152  0.0
+
+2121 1349 546 180 2108 2120 2172  0.0
+
+2122 213 546 545 2172 2136 2116  0.0
+
+2123 1350 548 69 2119 2154 2155  0.0
+
+2124 69 1411 571 2197 2158 2174  0.0
+
+2125 184 523 1310 2098 2102 2115  0.0
+
+2126 1331 184 552 2105 1979 2104  0.0
+
+2127 1312 1311 523 2098 2133 2130  0.0
+
+2128 479 1313 190 2129 2131 2137  0.0
+
+2129 1313 1566 190 2095 2128 3059  0.0
+
+2130 190 1311 1312 2127 2131 2101  0.0
+
+2131 479 190 1312 2130 2132 2128  0.0
+
+2132 1312 185 479 2135 2131 2133  0.0
+
+2133 1312 523 185 2117 2132 2127  0.0
+
+2134 185 545 1354 2148 2146 2136  0.0
+
+2135 479 185 1320 2142 2143 2132  0.0
+
+2136 185 213 545 2122 2134 2117  0.0
+
+2137 1313 479 188 2140 2149 2128  0.0
+
+2138 1318 188 1319 2140 2141 2139  0.0
+
+2139 1318 742 188 1886 2138 2147  0.0
+
+2140 188 479 1319 2143 2138 2137  0.0
+
+2141 480 1318 1319 2138 2412 2376  0.0
+
+2142 185 524 1320 2275 2135 2146  0.0
+
+2143 1319 479 1320 2135 2145 2140  0.0
+
+2144 524 1354 542 2161 2163 2146  0.0
+
+2145 1319 1320 1321 2275 2412 2143  0.0
+
+2146 1354 524 185 2142 2134 2144  0.0
+
+2147 1318 175 742 2369 2139 2373  0.0
+
+2148 545 179 1354 2151 2134 2171  0.0
+
+2149 472 1313 188 2137 1886 3059  0.0
+
+2150 179 1349 544 2152 2153 2171  0.0
+
+2151 1353 1354 179 2148 2153 2161  0.0
+
+2152 1349 548 544 2155 2150 2120  0.0
+
+2153 179 544 1353 2162 2151 2150  0.0
+
+2154 69 1351 1350 2159 2123 2158  0.0
+
+2155 544 548 1350 2123 2157 2152  0.0
+
+2156 570 1351 70 2170 2267 2165  0.0
+
+2157 544 1350 220 2159 2168 2155  0.0
+
+2158 571 1351 69 2154 2124 2170  0.0
+
+2159 220 1350 1351 2154 2165 2157  0.0
+
+2160 1355 542 1353 2161 2173 2696  0.0
+
+2161 542 1354 1353 2151 2160 2144  0.0
+
+2162 1353 544 543 2168 2173 2153  0.0
+
+2163 524 542 525 2398 2392 2144  0.0
+
+2164 220 570 1352 2166 2167 2165  0.0
+
+2165 570 220 1351 2159 2156 2164  0.0
+
+2166 569 1352 570 2164 2267 2679  0.0
+
+2167 220 1352 543 2169 2168 2164  0.0
+
+2168 544 220 543 2167 2162 2157  0.0
+
+2169 74 543 1352 2167 2682 2660  0.0
+
+2170 1351 571 70 2233 2156 2158  0.0
+
+2171 179 545 1349 2172 2150 2148  0.0
+
+2172 546 1349 545 2171 2122 2121  0.0
+
+2173 543 1355 1353 2160 2162 2657  0.0
+
+2174 69 219 1411 2269 2124 2111  0.0
+
+2175 1566 473 1314 2092 2095 3060  0.0
+
+2176 152 1412 1413 2220 2179 2187  0.0
+
+2177 1412 219 218 2083 2220 2269  0.0
+
+2178 1418 733 152 2191 2179 2069  0.0
+
+2179 152 1413 1418 2051 2178 2176  0.0
+
+2180 732 73 733 2185 2079 2181  0.0
+
+2181 732 1401 73 2183 2180 2068  0.0
+
+2182 1401 731 1400 2196 2183 2184  0.0
+
+2183 73 1401 1400 2182 2194 2181  0.0
+
+2184 1401 1402 731 2073 2182 2068  0.0
+
+2185 734 733 73 2180 2190 2191  0.0
+
+2186 1411 152 727 2188 2189 2187  0.0
+
+2187 152 1411 1412 2269 2176 2186  0.0
+
+2188 727 152 734 2191 2193 2186  0.0
+
+2189 1411 727 1410 2223 2197 2186  0.0
+
+2190 73 726 734 2193 2185 2194  0.0
+
+2191 734 152 733 2178 2185 2188  0.0
+
+2192 1399 726 1400 2194 2230 2227  0.0
+
+2193 734 726 727 2195 2188 2190  0.0
+
+2194 1400 726 73 2190 2183 2192  0.0
+
+2195 727 726 151 2222 2223 2193  0.0
+
+2196 731 1409 1400 2219 2182 2199  0.0
+
+2197 1410 571 1411 2124 2189 2243  0.0
+
+2198 237 1408 1409 2201 2199 2071  0.0
+
+2199 731 237 1409 2198 2196 2072  0.0
+
+2200 730 1408 155 2206 2213 2201  0.0
+
+2201 730 1409 1408 2198 2200 2209  0.0
+
+2202 729 1406 64 2033 2205 2270  0.0
+
+2203 729 155 1405 2075 2270 2207  0.0
+
+2204 1406 65 1577 3080 2033 2076  0.0
+
+2205 729 64 240 2216 2214 2202  0.0
+
+2206 1408 1404 155 2075 2200 2071  0.0
+
+2207 729 1407 155 2213 2203 2214  0.0
+
+2208 730 1396 1557 2221 3044 2210  0.0
+
+2209 730 236 1409 2219 2201 3044  0.0
+
+2210 1396 730 1407 2213 2215 2208  0.0
+
+2211 725 1400 236 2219 3043 2230  0.0
+
+2212 728 1407 240 2214 2249 2215  0.0
+
+2213 1407 730 155 2200 2207 2210  0.0
+
+2214 1407 729 240 2205 2212 2207  0.0
+
+2215 1407 728 1396 2252 2210 2212  0.0
+
+2216 64 1420 240 2217 2205 2218  0.0
+
+2217 156 240 1420 2216 2248 2249  0.0
+
+2218 64 331 1420 2266 2216 2250  0.0
+
+2219 1409 236 1400 2211 2196 2209  0.0
+
+2220 1413 1412 218 2177 2048 2176  0.0
+
+2221 1396 72 1557 2245 2208 2252  0.0
+
+2222 726 235 151 2224 2195 2227  0.0
+
+2223 151 1410 727 2189 2195 2225  0.0
+
+2224 712 151 235 2222 2237 2234  0.0
+
+2225 1410 151 711 2234 2243 2223  0.0
+
+2226 1399 725 1398 2242 2229 2230  0.0
+
+2227 726 1399 235 2229 2222 2192  0.0
+
+2228 234 1398 1397 2242 2265 2240  0.0
+
+2229 1399 1398 235 2231 2227 2226  0.0
+
+2230 725 1399 1400 2192 2211 2226  0.0
+
+2231 713 235 1398 2229 2240 2237  0.0
+
+2232 623 70 711 2233 3054 2678  0.0
+
+2233 70 571 711 2243 2232 2170  0.0
+
+2234 711 151 712 2224 3034 2225  0.0
+
+2235 71 1563 712 3034 2239 2683  0.0
+
+2236 713 234 1393 2238 2241 2240  0.0
+
+2237 713 712 235 2224 2231 2239  0.0
+
+2238 72 1393 234 2236 2265 2247  0.0
+
+2239 71 712 713 2237 2840 2235  0.0
+
+2240 234 713 1398 2231 2228 2236  0.0
+
+2241 242 713 1393 2236 2271 2840  0.0
+
+2242 1397 1398 725 2226 2244 2228  0.0
+
+2243 571 1410 711 2225 2233 2197  0.0
+
+2244 1397 725 1557 3043 2245 2242  0.0
+
+2245 72 1397 1557 2244 2221 2265  0.0
+
+2246 1395 72 728 2252 2256 2255  0.0
+
+2247 72 714 1393 2271 2238 2255  0.0
+
+2248 156 1420 1421 2266 2260 2217  0.0
+
+2249 156 728 240 2212 2217 2253  0.0
+
+2250 331 64 1558 3046 2268 2218  0.0
+
+2251 330 331 28 2268 2264 2262  0.0
+
+2252 1396 728 72 2246 2221 2215  0.0
+
+2253 1394 728 156 2249 2259 2256  0.0
+
+2254 714 1395 1394 2256 2257 2255  0.0
+
+2255 1395 714 72 2247 2246 2254  0.0
+
+2256 1395 728 1394 2253 2254 2246  0.0
+
+2257 714 1394 715 2259 2263 2254  0.0
+
+2258 63 715 1421 2260 2773 2790  0.0
+
+2259 715 1394 156 2253 2260 2257  0.0
+
+2260 156 1421 715 2258 2259 2248  0.0
+
+2261 1441 1421 330 2262 2774 2773  0.0
+
+2262 331 330 1421 2261 2266 2251  0.0
+
+2263 714 715 241 2776 2754 2257  0.0
+
+2264 1549 330 28 2251 -1  2030  0.0
+
+2265 72 234 1397 2228 2245 2238  0.0
+
+2266 1420 331 1421 2262 2248 2218  0.0
+
+2267 70 569 570 2166 2156 2678  0.0
+
+2268 28 331 1558 2250 -1  2251  0.0
+
+2269 1411 219 1412 2177 2187 2174  0.0
+
+2270 1406 729 1405 2203 2076 2202  0.0
+
+2271 714 242 1393 2241 2247 2751  0.0
+
+2272 329 1549 1550 2018 3027 2030  0.0
+
+2273 1330 1294 519 1649 1911 1961  0.0
+
+2274 63 1551 1390 2770 2790 2775  0.0
+
+2275 1320 524 1321 2392 2145 2142  0.0
+
+2276 694 55 1187 2277 2281 2292  0.0
+
+2277 55 1186 1187 1771 2276 1303  0.0
+
+2278 694 1188 1189 2282 2283 2281  0.0
+
+2279 1188 1187 687 1769 2282 2281  0.0
+
+2280 459 1189 1190 2297 2317 2283  0.0
+
+2281 694 1187 1188 2279 2278 2276  0.0
+
+2282 1189 1188 687 2279 1791 2278  0.0
+
+2283 459 694 1189 2278 2280 2289  0.0
+
+2284 1199 1203 695 1508 2295 2286  0.0
+
+2285 1198 55 1199 2292 2295 2367  0.0
+
+2286 1203 1199 460 2288 2293 2284  0.0
+
+2287 1203 168 1202 1447 1508 2323  0.0
+
+2288 1200 460 1199 2286 2291 2290  0.0
+
+2289 1200 694 459 2283 2294 2291  0.0
+
+2290 1201 460 1200 2288 2294 2309  0.0
+
+2291 1200 1199 694 2292 2289 2288  0.0
+
+2292 55 694 1199 2291 2285 2276  0.0
+
+2293 1204 1203 460 2286 2321 2328  0.0
+
+2294 1200 459 1201 2299 2290 2289  0.0
+
+2295 695 1198 1199 2285 2284 1443  0.0
+
+2296 736 1190 1191 2298 2303 2317  0.0
+
+2297 1190 1189 173 1795 2318 2280  0.0
+
+2298 1191 1190 737 2318 2301 2296  0.0
+
+2299 736 1201 459 2294 2317 2307  0.0
+
+2300 1277 1191 1192 2304 2305 2303  0.0
+
+2301 1191 737 470 1893 2304 2298  0.0
+
+2302 469 1192 1279 2462 2389 2305  0.0
+
+2303 1191 1277 736 2314 2296 2300  0.0
+
+2304 1192 1191 470 2301 1885 2300  0.0
+
+2305 1277 1192 469 2302 2366 2300  0.0
+
+2306 1201 126 735 2308 2309 2307  0.0
+
+2307 1201 736 126 2314 2306 2299  0.0
+
+2308 1206 735 126 2306 2319 2364  0.0
+
+2309 1201 735 460 2315 2290 2306  0.0
+
+2310 126 468 1276 2313 2319 2311  0.0
+
+2311 468 126 1277 2314 2312 2310  0.0
+
+2312 1278 468 1277 2311 2366 2316  0.0
+
+2313 1276 468 467 2350 2347 2310  0.0
+
+2314 736 1277 126 2311 2307 2303  0.0
+
+2315 1205 460 735 2309 2325 2321  0.0
+
+2316 1278 1547 468 3035 2312 2461  0.0
+
+2317 736 459 1190 2280 2296 2299  0.0
+
+2318 737 1190 173 2297 1786 2298  0.0
+
+2319 1276 1206 126 2308 2310 2347  0.0
+
+2320 461 1209 1203 2323 2328 3064  0.0
+
+2321 1204 460 1205 2315 3061 2293  0.0
+
+2322 461 1204 1567 3061 2327 2328  0.0
+
+2323 1203 1209 168 2653 2287 2320  0.0
+
+2324 169 1211 1567 2329 3062 2340  0.0
+
+2325 1205 735 169 2364 3062 2315  0.0
+
+2326 1210 1211 466 2344 2337 2329  0.0
+
+2327 461 1567 1210 2329 2331 2322  0.0
+
+2328 1203 1204 461 2322 2320 2293  0.0
+
+2329 1567 1211 1210 2326 2327 2324  0.0
+
+2330 387 390 462 1452 2333 2332  0.0
+
+2331 461 1210 1568 2338 3064 2327  0.0
+
+2332 390 387 490 2335 2334 2330  0.0
+
+2333 462 1209 387 3063 2330 1454  0.0
+
+2334 490 489 390 2339 2332 2336  0.0
+
+2335 490 387 466 2337 2363 2332  0.0
+
+2336 393 489 490 2334 2363 2353  0.0
+
+2337 466 387 1210 2338 2326 2335  0.0
+
+2338 1210 387 1568 3063 2331 2337  0.0
+
+2339 390 489 391 2470 2341 2334  0.0
+
+2340 1211 169 467 2343 2344 2324  0.0
+
+2341 391 464 390 1455 2339 1458  0.0
+
+2342 388 466 467 2344 2349 2345  0.0
+
+2343 467 169 1206 2364 2347 2340  0.0
+
+2344 466 1211 467 2340 2342 2326  0.0
+
+2345 466 388 393 2357 2363 2342  0.0
+
+2346 1466 467 170 2362 2435 2349  0.0
+
+2347 467 1206 1276 2319 2313 2343  0.0
+
+2348 484 1466 483 2435 2417 2351  0.0
+
+2349 467 1466 388 2351 2342 2346  0.0
+
+2350 468 1325 467 2362 2313 3035  0.0
+
+2351 388 1466 484 2348 2360 2349  0.0
+
+2352 258 393 486 2354 2365 2353  0.0
+
+2353 258 489 393 2336 2352 2355  0.0
+
+2354 486 393 485 2357 2359 2352  0.0
+
+2355 487 489 258 2353 2365 2470  0.0
+
+2356 485 484 389 2358 2361 2360  0.0
+
+2357 485 393 388 2345 2360 2354  0.0
+
+2358 389 484 1465 2417 2425 2356  0.0
+
+2359 486 485 1463 2361 2459 2354  0.0
+
+2360 388 484 485 2356 2357 2351  0.0
+
+2361 1463 485 389 2356 2424 2359  0.0
+
+2362 170 467 1325 2350 2381 2346  0.0
+
+2363 393 490 466 2335 2345 2336  0.0
+
+2364 169 735 1206 2308 2343 2325  0.0
+
+2365 486 487 258 2355 2352 2492  0.0
+
+2366 1278 1277 469 2305 2368 2312  0.0
+
+2367 1197 55 1198 2285 1443 1303  0.0
+
+2368 469 175 1278 2371 2366 2389  0.0
+
+2369 1279 742 175 2147 2389 1889  0.0
+
+2370 1323 175 1322 2373 2372 2371  0.0
+
+2371 1278 175 1323 2370 2379 2368  0.0
+
+2372 1323 1322 481 2375 2377 2370  0.0
+
+2373 175 1318 1322 2376 2370 2147  0.0
+
+2374 1327 1322 186 2388 2411 2375  0.0
+
+2375 481 1322 1327 2374 2386 2372  0.0
+
+2376 1322 1318 480 2141 2388 2373  0.0
+
+2377 1323 481 1324 2383 2379 2372  0.0
+
+2378 741 1547 1324 2461 2383 2380  0.0
+
+2379 1278 1323 1324 2377 2461 2371  0.0
+
+2380 1547 741 1326 2385 2080 2378  0.0
+
+2381 1326 170 1325 2362 2080 2387  0.0
+
+2382 741 1327 482 2384 2385 2386  0.0
+
+2383 741 1324 481 2377 2386 2378  0.0
+
+2384 482 1327 187 2401 2409 2382  0.0
+
+2385 741 482 1326 2387 2380 2382  0.0
+
+2386 1327 741 481 2383 2375 2382  0.0
+
+2387 1326 482 170 2422 2381 2385  0.0
+
+2388 1322 480 186 2391 2374 2376  0.0
+
+2389 175 469 1279 2302 2369 2368  0.0
+
+2390 186 1321 525 2392 2393 2391  0.0
+
+2391 1321 186 480 2388 2412 2390  0.0
+
+2392 1321 524 525 2163 2390 2275  0.0
+
+2393 1356 186 525 2390 2402 2411  0.0
+
+2394 920 178 1357 2652 2397 2395  0.0
+
+2395 178 920 542 2398 2696 2394  0.0
+
+2396 919 1357 1358 2652 2654 2408  0.0
+
+2397 920 1357 525 2399 2398 2394  0.0
+
+2398 542 920 525 2397 2163 2395  0.0
+
+2399 526 525 1357 2397 2408 2402  0.0
+
+2400 187 1356 526 2402 2403 2401  0.0
+
+2401 187 1327 1356 2411 2400 2384  0.0
+
+2402 1356 525 526 2399 2400 2393  0.0
+
+2403 1363 187 526 2400 2407 2458  0.0
+
+2404 1362 919 177 2406 2413 2405  0.0
+
+2405 919 1362 526 2407 2408 2404  0.0
+
+2406 539 177 919 2404 2410 2444  0.0
+
+2407 1363 526 1362 2405 2437 2403  0.0
+
+2408 1357 919 526 2405 2399 2396  0.0
+
+2409 482 187 1364 2458 2422 2384  0.0
+
+2410 539 919 1361 2663 2673 2406  0.0
+
+2411 1356 1327 186 2374 2393 2401  0.0
+
+2412 1319 1321 480 2391 2141 2145  0.0
+
+2413 177 918 1362 2437 2404 2442  0.0
+
+2414 483 1364 171 2421 2416 2415  0.0
+
+2415 1364 483 170 2435 2422 2414  0.0
+
+2416 483 171 1465 2432 2417 2414  0.0
+
+2417 1465 484 483 2348 2416 2358  0.0
+
+2418 1364 527 1365 2434 2421 2419  0.0
+
+2419 527 1364 1363 2458 2457 2418  0.0
+
+2420 528 1365 917 2439 2430 2423  0.0
+
+2421 1364 1365 171 2423 2414 2418  0.0
+
+2422 482 1364 170 2415 2387 2409  0.0
+
+2423 171 1365 528 2420 2432 2421  0.0
+
+2424 389 1464 1463 2427 2361 2425  0.0
+
+2425 389 1465 1464 2426 2424 2358  0.0
+
+2426 1464 1465 529 2429 2431 2425  0.0
+
+2427 348 1463 1464 2424 2431 2506  0.0
+
+2428 529 528 172 2430 2433 2429  0.0
+
+2429 528 529 1465 2426 2432 2428  0.0
+
+2430 917 172 528 2428 2420 2449  0.0
+
+2431 1464 529 348 2650 2427 2426  0.0
+
+2432 1465 171 528 2423 2429 2416  0.0
+
+2433 529 172 1453 2600 2650 2428  0.0
+
+2434 1366 1365 527 2418 2436 2439  0.0
+
+2435 1466 170 483 2415 2348 2346  0.0
+
+2436 918 1366 527 2434 2457 2438  0.0
+
+2437 1363 1362 918 2413 2457 2407  0.0
+
+2438 1366 918 176 2441 2445 2436  0.0
+
+2439 1366 917 1365 2420 2434 2447  0.0
+
+2440 1452 176 1367 2441 2443 2454  0.0
+
+2441 1367 176 918 2438 2442 2440  0.0
+
+2442 918 177 1367 2444 2441 2413  0.0
+
+2443 557 1452 1367 2440 2456 2745  0.0
+
+2444 177 539 1367 2456 2442 2406  0.0
+
+2445 1366 176 538 2454 2447 2438  0.0
+
+2446 917 538 537 2448 2449 2447  0.0
+
+2447 917 1366 538 2445 2446 2439  0.0
+
+2448 537 538 1451 2452 2451 2446  0.0
+
+2449 917 537 172 2455 2430 2446  0.0
+
+2450 78 1450 1451 2451 2719 2863  0.0
+
+2451 1451 1450 537 2463 2448 2450  0.0
+
+2452 1452 1451 538 2448 2454 2460  0.0
+
+2453 1450 558 344 2853 2463 2845  0.0
+
+2454 176 1452 538 2452 2445 2440  0.0
+
+2455 172 537 536 2580 2600 2449  0.0
+
+2456 557 1367 539 2444 2665 2443  0.0
+
+2457 527 1363 918 2437 2436 2419  0.0
+
+2458 187 1363 1364 2419 2409 2403  0.0
+
+2459 1463 532 486 2492 2359 2506  0.0
+
+2460 556 1451 1452 2452 2745 2719  0.0
+
+2461 1278 1324 1547 2378 2316 2379  0.0
+
+2462 174 1279 1192 2302 1885 1889  0.0
+
+2463 344 537 1450 2451 2453 2580  0.0
+
+2464 381 261 382 1490 2465 2471  0.0
+
+2465 382 488 381 2469 2464 2483  0.0
+
+2466 273 488 392 2468 2505 2469  0.0
+
+2467 487 488 391 2483 2470 2468  0.0
+
+2468 392 488 487 2467 2485 2466  0.0
+
+2469 488 273 381 2471 2465 2466  0.0
+
+2470 489 487 391 2467 2339 2355  0.0
+
+2471 381 273 261 2482 2464 2469  0.0
+
+2472 349 373 378 1488 2477 1504  0.0
+
+2473 374 261 378 2474 1488 1489  0.0
+
+2474 378 261 379 2480 2478 2473  0.0
+
+2475 372 349 350 2479 1493 1491  0.0
+
+2476 274 349 633 2494 2503 2479  0.0
+
+2477 378 262 349 2494 2472 2478  0.0
+
+2478 379 262 378 2477 2474 2496  0.0
+
+2479 349 274 350 2555 2475 2476  0.0
+
+2480 379 261 380 2482 2495 2474  0.0
+
+2481 351 274 371 2507 1503 2555  0.0
+
+2482 261 273 380 2487 2480 2471  0.0
+
+2483 391 488 382 2465 1492 2467  0.0
+
+2484 534 392 257 2486 2488 2505  0.0
+
+2485 532 392 487 2468 2492 2486  0.0
+
+2486 257 392 532 2485 2489 2484  0.0
+
+2487 534 380 273 2482 2505 2493  0.0
+
+2488 533 534 257 2484 2649 2491  0.0
+
+2489 532 531 257 2649 2486 2504  0.0
+
+2490 394 1461 380 2502 2493 2572  0.0
+
+2491 534 533 394 2559 2493 2488  0.0
+
+2492 487 486 532 2459 2485 2365  0.0
+
+2493 534 394 380 2490 2487 2491  0.0
+
+2494 349 262 633 2499 2476 2477  0.0
+
+2495 380 272 379 2496 2480 2502  0.0
+
+2496 379 272 262 2500 2478 2495  0.0
+
+2497 267 633 268 2569 2603 2503  0.0
+
+2498 274 266 104 2623 2507 2554  0.0
+
+2499 262 269 633 2569 2494 2500  0.0
+
+2500 272 269 262 2499 2496 2568  0.0
+
+2501 263 104 147 2602 2605 2552  0.0
+
+2502 272 380 1461 2490 2577 2495  0.0
+
+2503 267 274 633 2476 2497 2554  0.0
+
+2504 348 531 532 2489 2506 2561  0.0
+
+2505 273 392 534 2484 2487 2466  0.0
+
+2506 348 532 1463 2459 2427 2504  0.0
+
+2507 371 274 104 2498 2552 2481  0.0
+
+2508 369 100 370 2526 2509 2511  0.0
+
+2509 369 370 357 1476 1497 2508  0.0
+
+2510 368 355 367 1499 2514 1495  0.0
+
+2511 368 100 369 2508 2529 2531  0.0
+
+2512 365 366 353 1501 1498 2517  0.0
+
+2513 352 371 365 2528 1498 1503  0.0
+
+2514 101 368 367 2510 2533 2531  0.0
+
+2515 367 366 102 2517 2530 2516  0.0
+
+2516 366 367 354 1499 1501 2515  0.0
+
+2517 366 365 102 2532 2515 2512  0.0
+
+2518 97 96 7 1382 1386 2525  0.0
+
+2519 99 1269 370 1476 2526 2523  0.0
+
+2520 8 98 97 2547 1386 1479  0.0
+
+2521 6 96 1268 2527 1481 1382  0.0
+
+2522 92 96 91 2621 2643 2527  0.0
+
+2523 99 143 1269 2524 2519 2540  0.0
+
+2524 98 1269 143 2523 2549 1479  0.0
+
+2525 97 90 96 2621 2518 2547  0.0
+
+2526 99 370 100 2508 2543 2519  0.0
+
+2527 1268 96 92 2522 2553 2521  0.0
+
+2528 103 365 371 2513 2538 2551  0.0
+
+2529 356 368 369 2511 1497 1495  0.0
+
+2530 102 145 367 2533 2515 2534  0.0
+
+2531 368 101 100 2541 2511 2514  0.0
+
+2532 365 264 102 2550 2517 2551  0.0
+
+2533 367 145 101 2539 2514 2530  0.0
+
+2534 145 102 146 2550 2613 2530  0.0
+
+2535 83 264 103 2551 2536 2611  0.0
+
+2536 83 103 263 2538 2605 2535  0.0
+
+2537 144 265 145 2539 2612 2548  0.0
+
+2538 103 371 263 2552 2536 2528  0.0
+
+2539 101 145 265 2537 2541 2533  0.0
+
+2540 99 94 143 2544 2523 2545  0.0
+
+2541 265 100 101 2531 2539 2542  0.0
+
+2542 87 100 265 2541 2548 2543  0.0
+
+2543 99 100 87 2542 2545 2526  0.0
+
+2544 94 93 143 2618 2540 2617  0.0
+
+2545 94 99 87 2543 2546 2540  0.0
+
+2546 87 88 94 2617 2545 2615  0.0
+
+2547 98 90 97 2525 2520 2619  0.0
+
+2548 87 265 144 2537 2647 2542  0.0
+
+2549 143 89 98 2619 2524 2618  0.0
+
+2550 146 102 264 2532 2608 2534  0.0
+
+2551 365 103 264 2535 2532 2528  0.0
+
+2552 371 104 263 2501 2538 2507  0.0
+
+2553 1268 92 1274 2643 2641 2527  0.0
+
+2554 266 274 267 2503 2607 2498  0.0
+
+2555 350 274 351 2481 1487 2479  0.0
+
+2556 531 345 533 2558 2649 2557  0.0
+
+2557 345 531 530 2561 2560 2556  0.0
+
+2558 533 345 535 2563 2565 2556  0.0
+
+2559 271 394 533 2491 2574 2572  0.0
+
+2560 346 345 530 2557 2579 2563  0.0
+
+2561 530 531 348 2504 2564 2557  0.0
+
+2562 536 530 1453 2564 2600 2579  0.0
+
+2563 345 346 535 2599 2558 2560  0.0
+
+2564 348 1453 530 2562 2561 2650  0.0
+
+2565 533 535 347 2576 2574 2558  0.0
+
+2566 270 272 1462 2577 2571 2568  0.0
+
+2567 1462 1461 271 2572 2570 2577  0.0
+
+2568 272 270 269 2575 2500 2566  0.0
+
+2569 269 268 633 2497 2499 2610  0.0
+
+2570 271 1458 1462 2571 2567 2589  0.0
+
+2571 1462 1458 270 2591 2566 2570  0.0
+
+2572 1461 394 271 2559 2567 2490  0.0
+
+2573 107 271 347 2574 2576 2589  0.0
+
+2574 533 347 271 2573 2559 2565  0.0
+
+2575 269 270 110 2591 2601 2568  0.0
+
+2576 535 107 347 2573 2565 2587  0.0
+
+2577 1461 1462 272 2566 2502 2567  0.0
+
+2578 346 536 344 2580 2581 2579  0.0
+
+2579 536 346 530 2560 2562 2578  0.0
+
+2580 344 536 537 2455 2463 2578  0.0
+
+2581 346 344 1454 2583 2585 2578  0.0
+
+2582 1454 1455 561 2584 2585 2586  0.0
+
+2583 343 1454 344 2581 2853 2586  0.0
+
+2584 561 1455 1456 2648 2596 2582  0.0
+
+2585 1454 561 346 2599 2581 2582  0.0
+
+2586 1454 343 1455 2935 2582 2583  0.0
+
+2587 561 107 535 2576 2599 2596  0.0
+
+2588 110 1458 1460 2590 2597 2591  0.0
+
+2589 1458 271 107 2573 2590 2570  0.0
+
+2590 1460 1458 107 2589 2592 2588  0.0
+
+2591 1458 110 270 2575 2571 2588  0.0
+
+2592 107 562 1460 2598 2590 2593  0.0
+
+2593 562 107 1456 2596 2594 2592  0.0
+
+2594 560 562 1456 2593 2648 2889  0.0
+
+2595 109 110 1459 2597 2899 2646  0.0
+
+2596 107 561 1456 2584 2593 2587  0.0
+
+2597 1460 1459 110 2595 2588 2909  0.0
+
+2598 1460 562 106 2888 2909 2592  0.0
+
+2599 535 346 561 2585 2587 2563  0.0
+
+2600 1453 172 536 2455 2562 2433  0.0
+
+2601 269 110 150 2646 2610 2575  0.0
+
+2602 104 81 147 2606 2501 2623  0.0
+
+2603 267 268 150 2610 2604 2497  0.0
+
+2604 267 150 108 2632 2622 2603  0.0
+
+2605 147 83 263 2536 2501 2609  0.0
+
+2606 82 147 81 2602 2645 2628  0.0
+
+2607 267 81 266 2623 2554 2622  0.0
+
+2608 84 146 264 2550 2611 2614  0.0
+
+2609 147 148 83 2626 2605 2628  0.0
+
+2610 269 150 268 2603 2569 2601  0.0
+
+2611 83 84 264 2608 2535 2626  0.0
+
+2612 145 85 144 2620 2537 2613  0.0
+
+2613 145 146 85 2614 2612 2534  0.0
+
+2614 85 146 84 2608 2625 2613  0.0
+
+2615 87 95 88 2636 2546 2635  0.0
+
+2616 15 90 89 2619 2920 2634  0.0
+
+2617 94 88 93 3039 2544 2546  0.0
+
+2618 89 143 93 2544 2639 2549  0.0
+
+2619 90 98 89 2549 2616 2547  0.0
+
+2620 144 85 86 2627 2647 2612  0.0
+
+2621 90 91 96 2522 2525 2634  0.0
+
+2622 81 267 108 2604 2629 2607  0.0
+
+2623 266 81 104 2602 2498 2607  0.0
+
+2624 149 84 1539 2631 2921 2625  0.0
+
+2625 149 85 84 2614 2624 2627  0.0
+
+2626 84 83 148 2609 2631 2611  0.0
+
+2627 149 86 85 2620 2625 2633  0.0
+
+2628 82 148 147 2609 2606 2026  0.0
+
+2629 108 397 81 2645 2622 2901  0.0
+
+2630 82 1 1539 -1  2026 2905  0.0
+
+2631 84 148 1539 2026 2624 2626  0.0
+
+2632 396 108 150 2604 2644 2901  0.0
+
+2633 16 86 149 2627 2921 2642  0.0
+
+2634 91 90 15 2616 2637 2621  0.0
+
+2635 86 95 87 2615 2647 2642  0.0
+
+2636 95 1546 88 3039 2615 2640  0.0
+
+2637 91 15 1274 2902 2643 2634  0.0
+
+2638 1272 19 1271 1403 1494 3031  0.0
+
+2639 93 1546 89 2920 2618 3039  0.0
+
+2640 16 1546 95 2636 2642 -1   0.0
+
+2641 1273 1268 1274 2553 2992 2651  0.0
+
+2642 95 86 16 2633 2640 2635  0.0
+
+2643 92 91 1274 2637 2553 2522  0.0
+
+2644 150 109 396 2900 2632 2646  0.0
+
+2645 81 397 82 2905 2606 2629  0.0
+
+2646 110 109 150 2644 2601 2595  0.0
+
+2647 144 86 87 2635 2548 2620  0.0
+
+2648 1455 560 1456 2594 2584 2861  0.0
+
+2649 257 531 533 2556 2488 2489  0.0
+
+2650 348 529 1453 2433 2564 2431  0.0
+
+2651 1270 1268 1273 2641 2898 1387  0.0
+
+2652 1357 178 1358 2655 2396 2394  0.0
+
+2653 168 1209 1208 1454 1438 2323  0.0
+
+2654 1358 540 919 2663 2396 2670  0.0
+
+2655 178 541 1358 2659 2652 3033  0.0
+
+2656 74 1359 1358 2661 2659 2658  0.0
+
+2657 541 1355 543 2173 2660 3033  0.0
+
+2658 1359 74 568 2682 2695 2656  0.0
+
+2659 74 1358 541 2655 2660 2656  0.0
+
+2660 74 541 543 2657 2169 2659  0.0
+
+2661 1358 1359 567 2672 2670 2656  0.0
+
+2662 539 1369 1368 2669 2665 2673  0.0
+
+2663 1361 919 540 2654 2664 2410  0.0
+
+2664 1369 1361 540 2663 2667 2673  0.0
+
+2665 1368 557 539 2456 2662 2699  0.0
+
+2666 1369 567 1360 2668 2671 2667  0.0
+
+2667 567 1369 540 2664 2670 2666  0.0
+
+2668 222 1360 567 2666 2672 2685  0.0
+
+2669 1368 1369 164 2671 2699 2662  0.0
+
+2670 540 1358 567 2661 2667 2654  0.0
+
+2671 1360 164 1369 2669 2666 2693  0.0
+
+2672 567 1359 222 2677 2668 2661  0.0
+
+2673 1369 539 1361 2410 2664 2662  0.0
+
+2674 221 566 1359 2677 2695 2676  0.0
+
+2675 568 1352 221 2679 2695 2682  0.0
+
+2676 566 221 623 2681 2680 2674  0.0
+
+2677 566 222 1359 2672 2674 2686  0.0
+
+2678 70 623 569 2681 2267 2232  0.0
+
+2679 569 221 1352 2675 2166 2681  0.0
+
+2680 566 623 624 2692 2689 2676  0.0
+
+2681 569 623 221 2676 2679 2678  0.0
+
+2682 74 1352 568 2675 2658 2169  0.0
+
+2683 71 233 1563 2747 2235 2746  0.0
+
+2684 1370 222 162 2686 2706 2685  0.0
+
+2685 1370 1360 222 2668 2684 2693  0.0
+
+2686 162 222 566 2677 2687 2684  0.0
+
+2687 1373 162 566 2686 2689 2704  0.0
+
+2688 624 709 232 2690 2697 3052  0.0
+
+2689 1373 566 624 2680 2691 2687  0.0
+
+2690 232 709 708 2694 2742 2688  0.0
+
+2691 1373 624 1374 2720 2721 2689  0.0
+
+2692 1563 624 623 2680 3054 3052  0.0
+
+2693 164 1360 1370 2685 2700 2671  0.0
+
+2694 709 1385 708 2813 2690 2759  0.0
+
+2695 568 221 1359 2674 2658 2675  0.0
+
+2696 542 1355 178 3033 2395 2160  0.0
+
+2697 624 232 1377 2725 2728 2688  0.0
+
+2698 557 164 223 2700 2701 2699  0.0
+
+2699 164 557 1368 2665 2669 2698  0.0
+
+2700 164 1370 223 2703 2698 2693  0.0
+
+2701 557 223 556 2708 2745 2698  0.0
+
+2702 565 162 1371 2704 2707 2706  0.0
+
+2703 223 1370 565 2706 2705 2700  0.0
+
+2704 162 1373 1371 2721 2702 2687  0.0
+
+2705 223 565 564 2716 2709 2703  0.0
+
+2706 1370 162 565 2702 2703 2684  0.0
+
+2707 1372 565 1371 2702 2718 2716  0.0
+
+2708 223 563 556 2711 2701 2709  0.0
+
+2709 223 564 563 2710 2708 2705  0.0
+
+2710 563 564 1432 2713 2717 2709  0.0
+
+2711 556 563 78 2843 2719 2708  0.0
+
+2712 1432 1372 77 2714 2715 2713  0.0
+
+2713 1372 1432 564 2710 2716 2712  0.0
+
+2714 803 77 1372 2712 2718 2733  0.0
+
+2715 627 1432 77 2712 2872 2847  0.0
+
+2716 565 1372 564 2713 2705 2707  0.0
+
+2717 563 1432 224 2847 2850 2710  0.0
+
+2718 1372 1371 803 2741 2714 2707  0.0
+
+2719 556 78 1451 2450 2460 2711  0.0
+
+2720 624 231 1374 2723 2691 2728  0.0
+
+2721 1371 1373 1374 2691 2741 2704  0.0
+
+2722 231 1377 1376 2725 2729 2728  0.0
+
+2723 1374 231 803 2731 2741 2720  0.0
+
+2724 232 1378 1376 2727 2725 2742  0.0
+
+2725 1376 1377 232 2697 2724 2722  0.0
+
+2726 76 804 1378 2727 2803 2736  0.0
+
+2727 1376 1378 804 2726 2738 2724  0.0
+
+2728 1377 231 624 2720 2697 2722  0.0
+
+2729 231 1376 161 2738 2735 2722  0.0
+
+2730 77 1375 625 2743 2886 2733  0.0
+
+2731 803 231 1375 2735 2733 2723  0.0
+
+2732 1435 1375 161 2735 2737 2743  0.0
+
+2733 1375 77 803 2714 2731 2730  0.0
+
+2734 161 804 230 2736 2737 2738  0.0
+
+2735 161 1375 231 2731 2729 2732  0.0
+
+2736 76 230 804 2734 2726 3047  0.0
+
+2737 161 230 1435 2739 2732 2734  0.0
+
+2738 804 161 1376 2729 2727 2734  0.0
+
+2739 802 1435 230 2737 2937 2944  0.0
+
+2740 1378 708 1379 2795 2803 2742  0.0
+
+2741 1374 803 1371 2718 2721 2723  0.0
+
+2742 1378 232 708 2690 2740 2724  0.0
+
+2743 1375 1435 625 2869 2730 2732  0.0
+
+2744 1563 710 709 2839 3052 2747  0.0
+
+2745 556 1452 557 2443 2701 2460  0.0
+
+2746 71 1443 233 2749 2683 2767  0.0
+
+2747 710 1563 233 2683 2757 2744  0.0
+
+2748 1443 242 1392 2751 2753 2767  0.0
+
+2749 1442 233 1443 2746 2753 2764  0.0
+
+2750 157 1392 1391 2766 2789 2755  0.0
+
+2751 1392 242 714 2271 2754 2748  0.0
+
+2752 1387 157 1388 2789 2781 2761  0.0
+
+2753 1443 1392 1442 2755 2749 2748  0.0
+
+2754 714 241 1392 2766 2751 2263  0.0
+
+2755 157 1442 1392 2753 2750 2761  0.0
+
+2756 710 1386 75 2758 2839 2757  0.0
+
+2757 710 233 1386 2764 2756 2747  0.0
+
+2758 1384 75 1386 2756 2765 2793  0.0
+
+2759 75 1385 709 2694 2839 2792  0.0
+
+2760 1442 1387 244 2762 2763 2761  0.0
+
+2761 1387 1442 157 2755 2752 2760  0.0
+
+2762 243 244 1387 2760 2781 2787  0.0
+
+2763 1442 244 1386 2765 2764 2760  0.0
+
+2764 233 1442 1386 2763 2757 2749  0.0
+
+2765 244 1384 1386 2758 2763 2800  0.0
+
+2766 241 1391 1392 2750 2754 2769  0.0
+
+2767 71 242 1443 2748 2746 2840  0.0
+
+2768 1391 1390 716 2770 2771 2769  0.0
+
+2769 1391 241 1390 2776 2768 2766  0.0
+
+2770 716 1390 1551 2274 2786 2768  0.0
+
+2771 1391 716 1388 2779 2789 2768  0.0
+
+2772 1422 1551 1441 2775 2777 3038  0.0
+
+2773 1441 63 1421 2258 2261 2775  0.0
+
+2774 329 1441 330 2261 2030 2777  0.0
+
+2775 1551 63 1441 2773 2772 2274  0.0
+
+2776 715 1390 241 2769 2263 2790  0.0
+
+2777 1422 1441 329 2774 3027 2772  0.0
+
+2778 1388 1389 243 2780 2781 2779  0.0
+
+2779 1388 716 1389 2783 2778 2771  0.0
+
+2780 62 243 1389 2778 2791 2836  0.0
+
+2781 1388 243 1387 2762 2752 2778  0.0
+
+2782 717 1422 1548 2784 2785 3038  0.0
+
+2783 1389 716 717 2786 2785 2779  0.0
+
+2784 1550 1548 1422 2782 3027 2788  0.0
+
+2785 717 1548 1389 2791 2783 2782  0.0
+
+2786 1551 717 716 2783 2770 3038  0.0
+
+2787 244 243 158 2822 2798 2762  0.0
+
+2788 328 1548 1550 2784 2838 3036  0.0
+
+2789 1391 1388 157 2752 2750 2771  0.0
+
+2790 715 63 1390 2274 2776 2258  0.0
+
+2791 1548 62 1389 2780 2785 3036  0.0
+
+2792 75 806 1385 2813 2759 2793  0.0
+
+2793 806 75 1384 2758 2794 2792  0.0
+
+2794 806 1384 245 2797 2801 2793  0.0
+
+2795 806 1379 708 2740 2813 2801  0.0
+
+2796 1380 245 1383 2797 2799 2810  0.0
+
+2797 1383 245 1384 2794 2800 2796  0.0
+
+2798 1383 244 158 2787 2799 2800  0.0
+
+2799 1380 1383 158 2798 2812 2796  0.0
+
+2800 244 1383 1384 2797 2765 2798  0.0
+
+2801 806 245 1379 2807 2795 2794  0.0
+
+2802 707 76 706 2804 2809 2805  0.0
+
+2803 76 1378 1379 2740 2804 2726  0.0
+
+2804 706 76 1379 2803 2807 2802  0.0
+
+2805 76 707 1559 2837 3047 2802  0.0
+
+2806 706 1380 246 2808 2811 2810  0.0
+
+2807 706 1379 245 2801 2810 2804  0.0
+
+2808 1381 246 1380 2806 2812 2835  0.0
+
+2809 707 706 159 2811 2941 2802  0.0
+
+2810 245 1380 706 2806 2807 2796  0.0
+
+2811 246 159 706 2809 2806 2841  0.0
+
+2812 1380 158 1381 2815 2808 2799  0.0
+
+2813 708 1385 806 2792 2795 2694  0.0
+
+2814 1381 1382 705 2816 2817 2815  0.0
+
+2815 1382 1381 158 2812 2822 2814  0.0
+
+2816 705 1382 1440 2819 2821 2814  0.0
+
+2817 704 1381 705 2814 2826 2835  0.0
+
+2818 1440 62 718 2820 2823 2819  0.0
+
+2819 62 1440 1382 2816 2836 2818  0.0
+
+2820 62 328 718 2830 2818 3036  0.0
+
+2821 705 1440 719 2832 2826 2816  0.0
+
+2822 243 1382 158 2815 2787 2836  0.0
+
+2823 718 327 1440 2832 2818 2830  0.0
+
+2824 704 61 1423 3030 2825 2827  0.0
+
+2825 1423 246 704 2835 2824 2841  0.0
+
+2826 704 705 719 2821 2827 2817  0.0
+
+2827 719 61 704 2824 2826 2833  0.0
+
+2828 1439 327 1564 3055 2831 2829  0.0
+
+2829 327 1439 719 2833 2832 2828  0.0
+
+2830 327 718 328 2820 2834 2823  0.0
+
+2831 1439 1564 326 2031 2966 2828  0.0
+
+2832 1440 327 719 2829 2821 2823  0.0
+
+2833 1439 61 719 2827 2829 2964  0.0
+
+2834 27 327 328 2830 2838 3055  0.0
+
+2835 704 246 1381 2808 2817 2825  0.0
+
+2836 62 1382 243 2822 2780 2819  0.0
+
+2837 1436 1559 707 2805 2941 3045  0.0
+
+2838 27 328 1550 2788 2018 2834  0.0
+
+2839 75 709 710 2744 2756 2759  0.0
+
+2840 71 713 242 2241 2767 2239  0.0
+
+2841 246 1423 159 2960 2811 2825  0.0
+
+2842 78 559 1449 2844 2863 2843  0.0
+
+2843 78 563 559 2850 2842 2711  0.0
+
+2844 558 1449 559 2842 2854 2845  0.0
+
+2845 558 1450 1449 2863 2844 2453  0.0
+
+2846 224 627 1431 2848 2851 2847  0.0
+
+2847 224 1432 627 2715 2846 2717  0.0
+
+2848 1431 627 1430 2885 2865 2846  0.0
+
+2849 559 224 163 2851 2860 2850  0.0
+
+2850 224 559 563 2843 2717 2849  0.0
+
+2851 1431 163 224 2849 2846 2862  0.0
+
+2852 343 558 1448 2854 2855 2853  0.0
+
+2853 343 344 558 2453 2852 2583  0.0
+
+2854 558 559 1448 2860 2852 2844  0.0
+
+2855 343 1448 342 2857 2935 2852  0.0
+
+2856 342 163 1447 2858 2859 2857  0.0
+
+2857 163 342 1448 2855 2860 2856  0.0
+
+2858 80 1447 163 2856 2862 2877  0.0
+
+2859 342 1447 57 2912 2896 2856  0.0
+
+2860 559 163 1448 2857 2854 2849  0.0
+
+2861 342 560 1455 2648 2935 2896  0.0
+
+2862 163 1431 80 2875 2858 2851  0.0
+
+2863 1450 78 1449 2842 2845 2450  0.0
+
+2864 626 1429 1430 2882 2885 2867  0.0
+
+2865 628 1431 1430 2848 2882 2875  0.0
+
+2866 626 77 1433 2886 2867 2872  0.0
+
+2867 1433 1429 626 2864 2866 2873  0.0
+
+2868 1434 225 1433 2873 2871 2884  0.0
+
+2869 625 1435 1434 2944 2871 2743  0.0
+
+2870 1428 225 79 2884 2957 2880  0.0
+
+2871 1434 1433 625 2886 2869 2868  0.0
+
+2872 627 77 626 2866 2885 2715  0.0
+
+2873 225 1429 1433 2867 2868 2880  0.0
+
+2874 80 628 629 2876 2877 2875  0.0
+
+2875 1431 628 80 2874 2862 2865  0.0
+
+2876 629 628 226 2879 2881 2874  0.0
+
+2877 80 629 1447 2887 2858 2874  0.0
+
+2878 226 1429 1428 2880 2934 2879  0.0
+
+2879 1429 226 628 2876 2882 2878  0.0
+
+2880 1428 1429 225 2873 2870 2878  0.0
+
+2881 629 226 1445 2883 2932 2876  0.0
+
+2882 1430 1429 628 2879 2865 2864  0.0
+
+2883 226 228 1445 2918 2881 2934  0.0
+
+2884 225 1434 79 3029 2870 2868  0.0
+
+2885 1430 627 626 2872 2864 2848  0.0
+
+2886 77 625 1433 2871 2866 2730  0.0
+
+2887 1447 629 1446 2932 2912 2877  0.0
+
+2888 562 1457 106 2891 2598 2890  0.0
+
+2889 560 632 562 2890 2594 2893  0.0
+
+2890 562 632 1457 2895 2888 2889  0.0
+
+2891 106 1457 105 2895 2897 2888  0.0
+
+2892 105 632 631 2908 2923 2895  0.0
+
+2893 57 632 560 2889 2896 2908  0.0
+
+2894 105 340 1569 2927 2924 2923  0.0
+
+2895 632 105 1457 2891 2890 2892  0.0
+
+2896 342 57 560 2893 2861 2859  0.0
+
+2897 106 105 1459 2906 2909 2891  0.0
+
+2898 1273 1272 1270 1494 2651 2907  0.0
+
+2899 109 1459 395 2906 2900 2595  0.0
+
+2900 396 109 395 2899 2904 2644  0.0
+
+2901 108 396 397 2903 2629 2632  0.0
+
+2902 15 21 1274 2933 2637 -1   0.0
+
+2903 1570 397 396 2901 2904 3068  0.0
+
+2904 1570 396 395 2900 2999 2903  0.0
+
+2905 1 82 397 2645 3068 2630  0.0
+
+2906 1459 105 395 2924 2899 2897  0.0
+
+2907 23 1272 1273 2898 3023 3018  0.0
+
+2908 632 57 631 2911 2892 2893  0.0
+
+2909 1460 106 1459 2897 2597 2598  0.0
+
+2910 58 630 1446 2931 2913 2917  0.0
+
+2911 630 631 57 2908 2931 2928  0.0
+
+2912 1446 57 1447 2859 2887 2931  0.0
+
+2913 58 1446 1445 2932 2915 2910  0.0
+
+2914 341 58 697 2916 2985 2919  0.0
+
+2915 1444 58 1445 2913 2918 2916  0.0
+
+2916 1444 697 58 2914 2915 3003  0.0
+
+2917 630 58 340 2919 2928 2910  0.0
+
+2918 1444 1445 228 2883 3003 2915  0.0
+
+2919 340 58 341 2914 2925 2917  0.0
+
+2920 89 1546 15 -1  2616 2639  0.0
+
+2921 149 1539 16 -1  2633 2624  0.0
+
+2922 1561 1533 1529 -1  1400 478  0.0
+
+2923 340 105 631 2892 2928 2894  0.0
+
+2924 1569 395 105 2906 2894 2999  0.0
+
+2925 339 340 341 2919 2930 2927  0.0
+
+2926 1542 339 338 2995 1133 3065  0.0
+
+2927 340 339 1569 3066 2894 2925  0.0
+
+2928 631 630 340 2917 2923 2911  0.0
+
+2929 936 1534 1530 -1  186 1383  0.0
+
+2930 724 339 341 2925 2993 2995  0.0
+
+2931 630 57 1446 2912 2910 2911  0.0
+
+2932 1445 1446 629 2887 2881 2913  0.0
+
+2933 1274 21 22 -1  2992 2902  0.0
+
+2934 228 226 1428 2878 2949 2883  0.0
+
+2935 342 1455 343 2586 2855 2861  0.0
+
+2936 79 802 805 2937 2951 3029  0.0
+
+2937 802 230 805 2980 2936 2739  0.0
+
+2938 805 1559 229 3045 2939 2980  0.0
+
+2939 1426 805 229 2938 2954 2951  0.0
+
+2940 1436 159 703 2956 2943 2941  0.0
+
+2941 1436 707 159 2809 2940 2837  0.0
+
+2942 1425 703 1424 2956 2979 3082  0.0
+
+2943 703 1578 1436 2945 2940 3082  0.0
+
+2944 1435 802 1434 3029 2869 2739  0.0
+
+2945 1436 1578 229 2954 3045 2943  0.0
+
+2946 1427 1426 227 2953 2948 2947  0.0
+
+2947 1426 1427 79 2957 2951 2946  0.0
+
+2948 1427 227 228 2983 2949 2946  0.0
+
+2949 1427 228 1428 2934 2957 2948  0.0
+
+2950 1578 160 1426 2953 2954 3083  0.0
+
+2951 1426 79 805 2936 2939 2947  0.0
+
+2952 160 1425 702 2979 2971 3083  0.0
+
+2953 1426 160 227 2955 2946 2950  0.0
+
+2954 1578 1426 229 2939 2945 2950  0.0
+
+2955 701 227 160 2953 3026 2990  0.0
+
+2956 703 159 1424 2959 2942 2940  0.0
+
+2957 1427 1428 79 2870 2947 2949  0.0
+
+2958 1437 333 1424 2969 2959 2967  0.0
+
+2959 1437 1424 159 2956 2960 2958  0.0
+
+2960 1437 159 1423 2841 3030 2959  0.0
+
+2961 720 1437 61 3030 2963 2967  0.0
+
+2962 334 720 1438 2963 2965 2976  0.0
+
+2963 1438 720 61 2961 2964 2962  0.0
+
+2964 1438 61 1439 2833 2966 2963  0.0
+
+2965 334 1438 326 2966 2974 2962  0.0
+
+2966 1439 326 1438 2965 2964 2831  0.0
+
+2967 333 1437 720 2961 2973 2958  0.0
+
+2968 702 333 721 2970 2981 2969  0.0
+
+2969 333 702 1424 2979 2958 2968  0.0
+
+2970 721 333 325 2973 2975 2968  0.0
+
+2971 160 702 60 2981 3026 2952  0.0
+
+2972 325 334 332 2974 2977 2976  0.0
+
+2973 325 333 720 2967 2976 2970  0.0
+
+2974 332 334 326 2965 1035 2972  0.0
+
+2975 721 325 324 3010 3012 2970  0.0
+
+2976 720 334 325 2972 2973 2962  0.0
+
+2977 325 332 1537 3024 3010 2972  0.0
+
+2978 1528 332 1540 1035 -1  3024  0.0
+
+2979 1424 702 1425 2952 2942 2969  0.0
+
+2980 805 230 1559 3047 2938 2937  0.0
+
+2981 721 60 702 2971 2968 3005  0.0
+
+2982 228 59 697 2984 3003 2983  0.0
+
+2983 228 227 59 2990 2982 2948  0.0
+
+2984 698 697 59 2982 2991 2985  0.0
+
+2985 698 341 697 2914 2984 2993  0.0
+
+2986 700 322 59 2991 2989 3002  0.0
+
+2987 700 701 60 3026 3025 2989  0.0
+
+2988 723 699 322 3000 3007 2998  0.0
+
+2989 700 59 701 2990 2987 2986  0.0
+
+2990 701 59 227 2983 2955 2989  0.0
+
+2991 698 59 322 2986 3000 2984  0.0
+
+2992 1274 22 1273 3023 2641 2933  0.0
+
+2993 724 341 698 2985 2994 2930  0.0
+
+2994 338 724 698 2993 2997 2995  0.0
+
+2995 724 338 339 2926 2930 2994  0.0
+
+2996 338 699 337 2998 3001 2997  0.0
+
+2997 699 338 698 2994 3000 2996  0.0
+
+2998 723 337 699 2996 2988 3015  0.0
+
+2999 395 1569 1570 3066 2904 2924  0.0
+
+3000 698 322 699 2988 2997 2991  0.0
+
+3001 37 338 337 2996 3015 1133  0.0
+
+3002 322 700 323 3004 3007 2986  0.0
+
+3003 1444 228 697 2982 2916 2918  0.0
+
+3004 722 323 700 3002 3025 3006  0.0
+
+3005 60 721 722 3012 3025 2981  0.0
+
+3006 323 722 336 3008 3013 3004  0.0
+
+3007 723 322 323 3002 3013 2988  0.0
+
+3008 722 335 336 3011 3006 3009  0.0
+
+3009 335 722 324 3012 3032 3008  0.0
+
+3010 1537 324 325 2975 2977 3032  0.0
+
+3011 336 335 38 3020 3022 3008  0.0
+
+3012 721 324 722 3009 3005 2975  0.0
+
+3013 323 336 723 3016 3007 3006  0.0
+
+3014 922 1521 1533 -1  478 514  0.0
+
+3015 37 337 723 2998 3016 3001  0.0
+
+3016 37 723 336 3013 3022 3015  0.0
+
+3017 299 1527 843 946 991 993  0.0
+
+3018 23 24 1272 3031 2907 -1   0.0
+
+3019 1346 3 1535 1119 3078 2082  0.0
+
+3020 335 1537 38 -1  3011 3032  0.0
+
+3021 319 1543 283 53 15 17  0.0
+
+3022 336 38 37 -1  3016 3011  0.0
+
+3023 1273 22 23 -1  2907 2992  0.0
+
+3024 1537 332 1528 2978 -1  2977  0.0
+
+3025 700 60 722 3005 3004 2987  0.0
+
+3026 160 60 701 2987 2955 2971  0.0
+
+3027 1550 1422 329 2777 2272 2784  0.0
+
+3028 1536 930 754 1703 1654 756  0.0
+
+3029 79 1434 802 2944 2936 2884  0.0
+
+3030 1437 1423 61 2824 2961 2960  0.0
+
+3031 1272 24 19 -1  2638 3018  0.0
+
+3032 1537 335 324 3009 3010 3020  0.0
+
+3033 178 1355 541 2657 2655 2696  0.0
+
+3034 712 1563 711 3054 2234 2235  0.0
+
+3035 468 1547 1325 2080 2350 2316  0.0
+
+3036 62 1548 328 2788 2820 2791  0.0
+
+3037 1129 1483 453 1257 1751 1750  0.0
+
+3038 1422 717 1551 2786 2772 2782  0.0
+
+3039 1546 93 88 2617 2636 2639  0.0
+
+3040 111 1195 1555 1301 1298 1300  0.0
+
+3041 1174 1556 685 1675 1666 1669  0.0
+
+3042 1172 1556 1173 1669 1705 1806  0.0
+
+3043 725 236 1557 3044 2244 2211  0.0
+
+3044 730 1557 236 3043 2209 2208  0.0
+
+3045 1559 1436 229 2945 2938 2837  0.0
+
+3046 1577 1558 64 2250 2033 3081  0.0
+
+3047 230 76 1559 2805 2980 2736  0.0
+
+3048 1560 976 977 1082 1067 1062  0.0
+
+3049 1560 426 423 1080 1075 1064  0.0
+
+3050 923 933 1561 3051 1400 500  0.0
+
+3051 922 1561 933 3050 472 478  0.0
+
+3052 624 1563 709 2744 2688 2692  0.0
+
+3053 1344 1531 1562 -1  1922 1380  0.0
+
+3054 711 1563 623 2692 2232 3034  0.0
+
+3055 327 27 1564 3056 2828 2834  0.0
+
+3056 1540 1564 27 3055 -1  2031  0.0
+
+3057 892 1341 1565 3058 1988 1990  0.0
+
+3058 1565 1341 1576 1992 2012 3057  0.0
+
+3059 472 1566 1313 2129 2149 1872  0.0
+
+3060 1283 473 1566 2175 1872 1882  0.0
+
+3061 1204 1205 1567 3062 2322 2321  0.0
+
+3062 1567 1205 169 2325 2324 3061  0.0
+
+3063 387 1209 1568 3064 2338 2333  0.0
+
+3064 1209 461 1568 2331 3063 2320  0.0
+
+3065 1542 1570 339 3066 2926 3067  0.0
+
+3066 1569 339 1570 3065 2999 2927  0.0
+
+3067 1542 1 1570 3068 3065 -1   0.0
+
+3068 1570 1 397 2905 2903 3067  0.0
+
+3069 914 1571 915 3 5 1  0.0
+
+3070 1011 1572 639 149 159 138  0.0
+
+3071 1010 1572 48 138 140 141  0.0
+
+3072 1036 1573 253 421 449 452  0.0
+
+3073 1236 1216 1573 408 452 409  0.0
+
+3074 505 1574 1148 552 702 561  0.0
+
+3075 1579 1574 506 550 3084 555  0.0
+
+3076 1340 1343 1575 1899 1924 1898  0.0
+
+3077 1562 1522 1575 1402 1922 -1   0.0
+
+3078 1346 1535 1576 3079 1995 3019  0.0
+
+3079 1576 1535 891 2015 2012 3078  0.0
+
+3080 2 1577 65 2204 2028 2024  0.0
+
+3081 1558 1577 29 2024 -1  3046  0.0
+
+3082 703 1425 1578 3083 2943 2942  0.0
+
+3083 1578 1425 160 2952 2950 3082  0.0
+
+3084 1046 1579 506 3075 556 553  0.0
+
+3085 1050 1579 1248 553 1530 1895  0.0
+
+68 # <segment #> <vertex #>  <vertex #> [boundary marker] ...Triangulation Segments...
+
+0 3 2 0
+
+1 4 1536 0
+
+2 3 1541 0
+
+3 7 6 0
+
+4 8 7 0
+
+5 9 1532 0
+
+6 5 10 0
+
+7 1571 10 0
+
+8 14 1524 0
+
+9 11 14 0
+
+10 1525 12 0
+
+11 1546 15 0
+
+12 1539 16 0
+
+13 6 20 0
+
+14 20 17 0
+
+15 17 18 0
+
+16 18 1526 0
+
+17 21 22 0
+
+18 21 15 0
+
+19 23 22 0
+
+20 24 23 0
+
+21 19 24 0
+
+22 25 26 0
+
+23 1549 27 0
+
+24 1558 28 0
+
+25 29 2 0
+
+26 1544 26 left
+
+27 30 25 0
+
+28 31 30 0
+
+29 32 31 0
+
+30 33 32 0
+
+31 0 33 0
+
+32 13 34 0
+
+33 34 35 0
+
+34 35 36 0
+
+35 36 9 0
+
+36 1542 1 0
+
+37 37 38 0
+
+38 1537 38 0
+
+39 1521 1552 0
+
+40 1522 1562 0
+
+41 1523 1538 0
+
+42 1524 13 0
+
+43 1525 11 0
+
+44 1526 19 0
+
+45 1527 12 left
+
+46 1528 1540 0
+
+47 1529 1533 0
+
+48 1530 1534 0
+
+49 1531 1545 0
+
+50 1532 1523 0
+
+51 1533 1521 0
+
+52 1534 5 0
+
+53 1536 1529 0
+
+54 1537 1528 0
+
+55 1538 8 0
+
+56 1539 1 0
+
+57 1540 27 0
+
+58 1541 1522 0
+
+59 1542 37 0
+
+60 1544 1527 left
+
+61 1545 4 0
+
+62 1546 16 0
+
+63 1549 28 0
+
+64 1552 1530 0
+
+65 1558 29 0
+
+66 1562 1531 0
+
+67 1571 0 0
+
+1521 0 # <vertex #> <x> <y> [attributes] ...Mesh Vertices...
+
+0 0.136205637824 0.0726430068393 
+
+1 1.03062265953 0.944359088911 
+
+2 1.20314980078 0.154366389534 
+
+3 1.04878341124 0.0181607517098 
+
+4 0.758211383886 -0.059022443057 
+
+5 0.295112215285 -0.0317813154922 
+
+6 0.51758142373 1.89779855368 
+
+7 0.472179544456 1.77521347964 
+
+8 0.476719732383 1.5209629557 
+
+9 0.549362739223 1.10326566637 
+
+10 0.217929020518 0.0363215034197 
+
+11 0.177067329171 0.767291759741 
+
+12 0.0272411275648 0.753671195958 
+
+13 0.390456161761 0.867175894145 
+
+14 0.308732779067 0.80361326316 
+
+15 0.998841344041 1.68894990901 
+
+16 0.989760968186 1.29849374725 
+
+17 0.417697289326 2.56066599109 
+
+18 0.444938416891 2.73319313233 
+
+19 0.862635706217 2.75135388404 
+
+20 0.435858041036 2.08848644663 
+
+21 1.17136848528 1.86147705026 
+
+22 1.23493111627 2.19745095689 
+
+23 1.21677036456 2.61514824622 
+
+24 1.07148435088 2.76043425989 
+
+25 -0.145151029646 0.445463504777 
+
+26 -0.135140613809 0.505525999803 
+
+27 1.2763280193 0.56058328691 
+
+28 1.31636968265 0.385401009751 
+
+29 1.28133322722 0.250260395942 
+
+30 -0.135140613809 0.385401009751 
+
+31 -0.105109366296 0.320333306806 
+
+32 -0.0200208316754 0.21522394051 
+
+33 0.0600624950261 0.140145821728 
+
+34 0.460479128533 0.885921801635 
+
+35 0.540562455235 0.915953049148 
+
+36 0.56058328691 0.981020752093 
+
+37 1.15119782133 0.780812435339 
+
+38 1.23128114803 0.720749940313 
+
+39 0.30031247513 0.720749940313 
+
+40 0.395411425588 0.715744732394 
+
+41 0.295307267212 0.585609326504 
+
+42 0.390406217669 0.600624950261 
+
+43 0.30031247513 0.450468712696 
+
+44 0.385401009751 0.440458296858 
+
+45 0.290302059293 0.330343722643 
+
+46 0.385401009751 0.315328098887 
+
+47 0.270281227617 0.200208316754 
+
+48 0.355369762238 0.185192692997 
+
+49 0.265276019698 0.105109366296 
+
+50 0.340354138481 0.100104158377 
+
+51 0.47549475229 0.325338514725 
+
+52 0.580604118585 0.315328098887 
+
+53 0.485505168127 0.455473920614 
+
+54 0.585609326504 0.455473920614 
+
+55 0.665692653206 0.455473920614 
+
+56 0.680708276962 0.340354138481 
+
+57 0.960999920417 0.685713484881 
+
+58 1.02606762336 0.685713484881 
+
+59 1.09113532631 0.680708276962 
+
+60 1.15119782133 0.655682237368 
+
+61 1.18623427676 0.585609326504 
+
+62 1.20124990052 0.505525999803 
+
+63 1.20124990052 0.435453088939 
+
+64 1.21626552428 0.330343722643 
+
+65 1.17622386093 0.270281227617 
+
+66 1.08112491047 0.230239564267 
+
+67 1.02106241544 0.230239564267 
+
+68 0.966005128336 0.30031247513 
+
+69 0.971010336255 0.370385385994 
+
+70 1.00104158377 0.420437465183 
+
+71 1.08613011839 0.435453088939 
+
+72 1.1411874055 0.390406217669 
+
+73 1.08112491047 0.335348930562 
+
+74 0.940979088742 0.460479128533 
+
+75 1.09614053423 0.505525999803 
+
+76 1.10114574214 0.56058328691 
+
+77 1.00104158377 0.575598910667 
+
+78 0.910947841229 0.590614534423 
+
+79 1.06110407879 0.615640574017 
+
+80 0.981020752093 0.630656197774 
+
+81 0.825859306609 0.966005128336 
+
+82 0.885921801635 1.00104158377 
+
+83 0.830864514527 1.07111449463 
+
+84 0.855890554122 1.1411874055 
+
+85 0.805838474933 1.21626552428 
+
+86 0.845880138284 1.29134364306 
+
+87 0.785817643258 1.35140613809 
+
+88 0.835869722446 1.44650508854 
+
+89 0.825859306609 1.59165611819 
+
+90 0.830864514527 1.71178110824 
+
+91 0.835869722446 1.82690089038 
+
+92 0.780812435339 1.92199984083 
+
+93 0.850885346203 1.51657799941 
+
+94 0.770802019501 1.43148946479 
+
+95 0.865900969959 1.37142696976 
+
+96 0.705734316556 1.82690089038 
+
+97 0.685713484881 1.72179152408 
+
+98 0.710739524475 1.57664049443 
+
+99 0.710739524475 1.43649467271 
+
+100 0.715744732394 1.32638009849 
+
+101 0.735765564069 1.26131239555 
+
+102 0.750781187826 1.15620302925 
+
+103 0.755786395745 1.07611970255 
+
+104 0.770802019501 1.00604679169 
+
+105 0.95098950458 0.745775979907 
+
+106 0.90594263331 0.745775979907 
+
+107 0.875911385797 0.695723900719 
+
+108 0.865900969959 0.890927009553 
+
+109 0.900937425391 0.825859306609 
+
+110 0.870906177878 0.795828059095 
+
+111 0.660687445287 0.405421841426 
+
+112 0.620645781936 0.400416633507 
+
+113 0.540562455235 0.395411425588 
+
+114 0.470489544371 0.400416633507 
+
+115 0.385401009751 0.400416633507 
+
+116 0.330343722643 0.405421841426 
+
+117 0.265276019698 0.370385385994 
+
+118 0.3453593464 0.370385385994 
+
+119 0.390406217669 0.370385385994 
+
+120 0.435453088939 0.355369762238 
+
+121 0.485505168127 0.365380178075 
+
+122 0.530552039397 0.365380178075 
+
+123 0.590614534423 0.360374970156 
+
+124 0.730760356151 0.385401009751 
+
+125 0.730760356151 0.315328098887 
+
+126 0.740770771988 0.470489544371 
+
+127 0.320333306806 0.550572871072 
+
+128 0.380395801832 0.540562455235 
+
+129 0.240249980104 0.585609326504 
+
+130 0.275286435536 0.64567182153 
+
+131 0.26027081178 0.730760356151 
+
+132 0.230239564267 0.440458296858 
+
+133 0.220229148429 0.385401009751 
+
+134 0.220229148429 0.330343722643 
+
+135 0.225234356348 0.290302059293 
+
+136 0.240249980104 0.240249980104 
+
+137 0.235244772185 0.185192692997 
+
+138 0.220229148429 0.105109366296 
+
+139 0.290302059293 0.285296851374 
+
+140 0.320333306806 0.220229148429 
+
+141 0.305317683049 0.160166653403 
+
+142 0.310322890968 0.0600624950261 
+
+143 0.725755148232 1.49655716773 
+
+144 0.790822851177 1.29885145494 
+
+145 0.765796811582 1.21626552428 
+
+146 0.798330663055 1.15620302925 
+
+147 0.81835149473 1.02106241544 
+
+148 0.873408781838 1.06610928671 
+
+149 0.865900969959 1.23378375199 
+
+150 0.833367118487 0.865900969959 
+
+151 1.04108324712 0.380395801832 
+
+152 1.02606762336 0.340354138481 
+
+153 1.03357543524 0.287799455333 
+
+154 1.10114574214 0.282794247414 
+
+155 1.15119782133 0.325338514725 
+
+156 1.18873688072 0.392908821629 
+
+157 1.14369000945 0.460479128533 
+
+158 1.15620302925 0.523044227519 
+
+159 1.1411874055 0.588111930464 
+
+160 1.1161613659 0.630656197774 
+
+161 1.05109366296 0.563085890869 
+
+162 0.986025960011 0.528049435438 
+
+163 0.953492108539 0.630656197774 
+
+164 0.930968672904 0.528049435438 
+
+165 0.540562455235 0.43295048498 
+
+166 0.545567663154 0.477997356249 
+
+167 0.610635366098 0.483002564168 
+
+168 0.663190049246 0.495515583965 
+
+169 0.723252544272 0.503023395843 
+
+170 0.780812435339 0.513033811681 
+
+171 0.810843682852 0.540562455235 
+
+172 0.838372326406 0.590614534423 
+
+173 0.713242128435 0.43295048498 
+
+174 0.768299415542 0.422940069142 
+
+175 0.793325455136 0.445463504777 
+
+176 0.883419197675 0.545567663154 
+
+177 0.883419197675 0.510531207722 
+
+178 0.903440029351 0.455473920614 
+
+179 0.908445237269 0.405421841426 
+
+180 0.920958257066 0.357872366197 
+
+181 0.928466068945 0.312825494927 
+
+182 0.923460861026 0.26027081178 
+
+183 0.858393158081 0.285296851374 
+
+184 0.853387950162 0.337851534522 
+
+185 0.86089576204 0.402919237467 
+
+186 0.838372326406 0.457976524574 
+
+187 0.830864514527 0.498018187925 
+
+188 0.810843682852 0.412929653304 
+
+189 0.773304623461 0.365380178075 
+
+190 0.823356702649 0.380395801832 
+
+191 0.798330663055 0.327841118684 
+
+192 0.803335870974 0.292804663252 
+
+193 0.638164009652 0.362877574116 
+
+194 0.635661405693 0.327841118684 
+
+195 0.6907186928 0.30281507909 
+
+196 0.628153593814 0.290302059293 
+
+197 0.508028603762 0.30031247513 
+
+198 0.530552039397 0.337851534522 
+
+199 0.593117138382 0.280291643455 
+
+200 0.427945277061 0.315328098887 
+
+201 0.347861950359 0.340354138481 
+
+202 0.332846326603 0.312825494927 
+
+203 0.340354138481 0.265276019698 
+
+204 0.425442673101 0.437955692898 
+
+205 0.445463504777 0.410427049345 
+
+206 0.457976524574 0.455473920614 
+
+207 0.488007772087 0.485505168127 
+
+208 0.583106722545 0.415432257264 
+
+209 0.623148385896 0.440458296858 
+
+210 0.30281507909 0.417934861223 
+
+211 0.252762999901 0.415432257264 
+
+212 0.535557247316 0.315328098887 
+
+213 0.875911385797 0.370385385994 
+
+214 0.888424405594 0.327841118684 
+
+215 0.895932217472 0.297809871171 
+
+216 0.971010336255 0.275286435536 
+
+217 1.00854939565 0.26027081178 
+
+218 0.996036375849 0.315328098887 
+
+219 0.978518148133 0.3453593464 
+
+220 0.958497316458 0.412929653304 
+
+221 0.976015544174 0.460479128533 
+
+222 0.963502524377 0.503023395843 
+
+223 0.943481692701 0.550572871072 
+
+224 0.953492108539 0.593117138382 
+
+225 1.0360780392 0.610635366098 
+
+226 1.02106241544 0.64567182153 
+
+227 1.08112491047 0.638164009652 
+
+228 1.05609887088 0.653179633409 
+
+229 1.09614053423 0.60563015818 
+
+230 1.08112491047 0.575598910667 
+
+231 1.03357543524 0.543065059194 
+
+232 1.05609887088 0.525546831478 
+
+233 1.10615095006 0.470489544371 
+
+234 1.1161613659 0.405421841426 
+
+235 1.08112491047 0.385401009751 
+
+236 1.12116657382 0.352867158278 
+
+237 1.12617178174 0.307820287009 
+
+238 1.06110407879 0.295307267212 
+
+239 1.13618219758 0.277789039496 
+
+240 1.18122906885 0.357872366197 
+
+241 1.16120823717 0.435453088939 
+
+242 1.12366917778 0.435453088939 
+
+243 1.17121865301 0.490510376046 
+
+244 1.13618219758 0.503023395843 
+
+245 1.12617178174 0.533054643356 
+
+246 1.15370042529 0.563085890869 
+
+247 0.685713484881 0.410427049345 
+
+248 0.6907186928 0.382898405791 
+
+249 0.715744732394 0.355369762238 
+
+250 0.745775979907 0.347861950359 
+
+251 0.748278583867 0.275286435536 
+
+252 0.673200465084 0.235244772185 
+
+253 0.550572871072 0.187695296956 
+
+254 0.823356702649 0.170177069241 
+
+255 0.755786395745 0.150156237565 
+
+256 0.90594263331 0.175182277159 
+
+257 0.77580722742 0.64817442549 
+
+258 0.723252544272 0.600624950261 
+
+259 0.630656197774 0.585609326504 
+
+260 0.575598910667 0.665692653206 
+
+261 0.680708276962 0.728257752191 
+
+262 0.760791603664 0.795828059095 
+
+263 0.77580722742 1.04358585108 
+
+264 0.77580722742 1.11115615798 
+
+265 0.758288999704 1.29134364306 
+
+266 0.790822851177 0.955994712498 
+
+267 0.790822851177 0.900937425391 
+
+268 0.805838474933 0.86089576204 
+
+269 0.810843682852 0.82085409869 
+
+270 0.828361910568 0.773304623461 
+
+271 0.835869722446 0.725755148232 
+
+272 0.773304623461 0.760791603664 
+
+273 0.728257752191 0.68821608884 
+
+274 0.723252544272 0.925963464985 
+
+275 0.618143177977 0.850885346203 
+
+276 0.175182277159 0.633158801733 
+
+277 0.190197900916 0.535557247316 
+
+278 0.187695296956 0.480499960209 
+
+279 0.187695296956 0.427945277061 
+
+280 0.162669257362 0.380395801832 
+
+281 0.162669257362 0.315328098887 
+
+282 0.150156237565 0.242752584064 
+
+283 0.157664049443 0.162669257362 
+
+284 0.142648425687 0.678205673003 
+
+285 0.117622386093 0.608132762139 
+
+286 0.122627594012 0.538059851275 
+
+287 0.117622386093 0.47549475229 
+
+288 0.102606762336 0.392908821629 
+
+289 0.0875911385797 0.327841118684 
+
+290 0.0850885346203 0.255265603861 
+
+291 0.0875911385797 0.680708276962 
+
+292 0.0650677029449 0.608132762139 
+
+293 0.0550572871072 0.545567663154 
+
+294 0.0375390593913 0.480499960209 
+
+295 0.030031247513 0.420437465183 
+
+296 0.0125130197971 0.347861950359 
+
+297 0.0125130197971 0.282794247414 
+
+298 0.0325338514725 0.680708276962 
+
+299 0.00250260395942 0.623148385896 
+
+300 -0.0200208316754 0.540562455235 
+
+301 -0.0500520791884 0.47549475229 
+
+302 -0.0250260395942 0.415432257264 
+
+303 -0.0500520791884 0.330343722643 
+
+304 0.235244772185 0.490510376046 
+
+305 0.240249980104 0.535557247316 
+
+306 0.21772654447 0.633158801733 
+
+307 0.232742168226 0.68821608884 
+
+308 0.225234356348 0.743273375948 
+
+309 0.285296851374 0.698226504678 
+
+310 0.325338514725 0.68821608884 
+
+311 0.312825494927 0.633158801733 
+
+312 0.275286435536 0.613137970058 
+
+313 0.267778623658 0.563085890869 
+
+314 0.287799455333 0.490510376046 
+
+315 0.192700504875 0.352867158278 
+
+316 0.197705712794 0.30281507909 
+
+317 0.195203108835 0.252762999901 
+
+318 0.187695296956 0.21522394051 
+
+319 0.207716128632 0.165171861322 
+
+320 0.185192692997 0.12763280193 
+
+321 0.112617178174 0.155161445484 
+
+322 1.12116657382 0.700729108638 
+
+323 1.15370042529 0.700729108638 
+
+324 1.18873688072 0.668195257165 
+
+325 1.1962446926 0.640666613611 
+
+326 1.22377333616 0.588111930464 
+
+327 1.22627594012 0.545567663154 
+
+328 1.23378375199 0.503023395843 
+
+329 1.24129156387 0.450468712696 
+
+330 1.23878895991 0.402919237467 
+
+331 1.22377333616 0.367882782035 
+
+332 1.23628635595 0.635661405693 
+
+333 1.16871604905 0.618143177977 
+
+334 1.21376292032 0.618143177977 
+
+335 1.20625510844 0.703231712597 
+
+336 1.18373167281 0.720749940313 
+
+337 1.13117698966 0.753283791785 
+
+338 1.08613011839 0.748278583867 
+
+339 1.03107283128 0.745775979907 
+
+340 1.00354418773 0.728257752191 
+
+341 1.04608845504 0.715744732394 
+
+342 0.935973880823 0.658184841327 
+
+343 0.90594263331 0.643169217571 
+
+344 0.875911385797 0.623148385896 
+
+345 0.82085409869 0.653179633409 
+
+346 0.848382742243 0.640666613611 
+
+347 0.840874930365 0.695723900719 
+
+348 0.790822851177 0.610635366098 
+
+349 0.698226504678 0.845880138284 
+
+350 0.675703069043 0.920958257066 
+
+351 0.660687445287 1.00354418773 
+
+352 0.64817442549 1.06861189067 
+
+353 0.643169217571 1.13117698966 
+
+354 0.620645781936 1.19374208864 
+
+355 0.625650989855 1.25130197971 
+
+356 0.618143177977 1.30635926682 
+
+357 0.598122346301 1.36642176184 
+
+358 0.558080682951 1.33889311829 
+
+359 0.56058328691 1.27132281139 
+
+360 0.585609326504 1.22877854408 
+
+361 0.583106722545 1.15870563321 
+
+362 0.608132762139 1.08863272235 
+
+363 0.610635366098 1.0360780392 
+
+364 0.618143177977 0.978518148133 
+
+365 0.705734316556 1.09363793027 
+
+366 0.693221296759 1.15870563321 
+
+367 0.6907186928 1.21376292032 
+
+368 0.675703069043 1.2763280193 
+
+369 0.673200465084 1.33388791037 
+
+370 0.670697861124 1.37392957372 
+
+371 0.715744732394 1.02857022732 
+
+372 0.633158801733 0.913450445188 
+
+373 0.658184841327 0.825859306609 
+
+374 0.643169217571 0.770802019501 
+
+375 0.623148385896 0.718247336353 
+
+376 0.580604118585 0.750781187826 
+
+377 0.595619742342 0.803335870974 
+
+378 0.680708276962 0.785817643258 
+
+379 0.73326296011 0.763294207623 
+
+380 0.755786395745 0.725755148232 
+
+381 0.698226504678 0.6907186928 
+
+382 0.653179633409 0.663190049246 
+
+383 0.60312755422 0.633158801733 
+
+384 0.583106722545 0.568091098788 
+
+385 0.595619742342 0.548070267113 
+
+386 0.635661405693 0.528049435438 
+
+387 0.685713484881 0.538059851275 
+
+388 0.740770771988 0.543065059194 
+
+389 0.77580722742 0.568091098788 
+
+390 0.675703069043 0.580604118585 
+
+391 0.68821608884 0.623148385896 
+
+392 0.743273375948 0.64817442549 
+
+393 0.728257752191 0.573096306707 
+
+394 0.783315039298 0.708236920516 
+
+395 0.94848690062 0.798330663055 
+
+396 0.903440029351 0.863398366 
+
+397 0.913450445188 0.935973880823 
+
+398 0.638164009652 0.167674465281 
+
+399 0.748278583867 0.0875911385797 
+
+400 0.848382742243 0.0825859306609 
+
+401 0.64817442549 0.0825859306609 
+
+402 0.575598910667 0.0875911385797 
+
+403 0.525546831478 0.640666613611 
+
+404 0.523044227519 0.765796811582 
+
+405 0.535557247316 0.833367118487 
+
+406 0.208967430612 0.583106722545 
+
+407 0.212721336551 0.510531207722 
+
+408 0.208967430612 0.460479128533 
+
+409 0.197705712794 0.407924445385 
+
+410 0.25776820782 0.335348930562 
+
+411 0.262773415739 0.30031247513 
+
+412 0.267778623658 0.25776820782 
+
+413 0.292804663252 0.223983054368 
+
+414 0.275286435536 0.168925767261 
+
+415 0.155161445484 0.579352816606 
+
+416 0.155161445484 0.504274697823 
+
+417 0.145151029646 0.439206994878 
+
+418 0.12763280193 0.351615856298 
+
+419 0.132638009849 0.291553361272 
+
+420 0.115119782133 0.201459618733 
+
+421 0.319082004826 0.359123668177 
+
+422 0.30031247513 0.385401009751 
+
+423 0.415432257264 0.55933198493 
+
+424 0.342856742441 0.588111930464 
+
+425 0.325338514725 0.485505168127 
+
+426 0.425442673101 0.520541623559 
+
+427 0.425442673101 0.686964786861 
+
+428 0.421688767162 0.765796811582 
+
+429 0.364128876096 0.814597588791 
+
+430 0.365380178075 0.755786395745 
+
+431 0.391657519649 0.660687445287 
+
+432 0.43044788102 0.598122346301 
+
+433 0.436704390919 0.491761678026 
+
+434 0.381647103812 0.26027081178 
+
+435 0.42919657904 0.277789039496 
+
+436 0.405421841426 0.225234356348 
+
+437 0.477997356249 0.261522113759 
+
+438 0.431699183 0.205213524672 
+
+439 0.397914029548 0.17393097518 
+
+440 0.531803341377 0.242752584064 
+
+441 0.513033811681 0.465484336452 
+
+442 0.506777301783 0.422940069142 
+
+443 0.504274697823 0.38915491569 
+
+444 0.505525999803 0.341605440461 
+
+445 0.565588494829 0.335348930562 
+
+446 0.56183458889 0.381647103812 
+
+447 0.564337192849 0.425442673101 
+
+448 0.574347608687 0.514285113661 
+
+449 0.573096306707 0.479248658229 
+
+450 0.638164009652 0.47299214833 
+
+451 0.651928331429 0.43044788102 
+
+452 0.644420519551 0.38915491569 
+
+453 0.663190049246 0.359123668177 
+
+454 0.606881460159 0.336600232542 
+
+455 0.609384064119 0.305317683049 
+
+456 0.654430935388 0.309071588988 
+
+457 0.709488222496 0.330343722643 
+
+458 0.706985618536 0.400416633507 
+
+459 0.708236920516 0.456725222594 
+
+460 0.696975202698 0.479248658229 
+
+461 0.6907186928 0.513033811681 
+
+462 0.654430935388 0.548070267113 
+
+463 0.626902291835 0.56058328691 
+
+464 0.656933539348 0.610635366098 
+
+465 0.636912707672 0.633158801733 
+
+466 0.723252544272 0.533054643356 
+
+467 0.750781187826 0.505525999803 
+
+468 0.764545509603 0.484253866148 
+
+469 0.769550717522 0.450468712696 
+
+470 0.745775979907 0.431699183 
+
+471 0.750781187826 0.404170539446 
+
+472 0.789571549197 0.400416633507 
+
+473 0.799581965035 0.369134084014 
+
+474 0.77830983138 0.340354138481 
+
+475 0.763294207623 0.320333306806 
+
+476 0.763294207623 0.30031247513 
+
+477 0.828361910568 0.317830702846 
+
+478 0.824608004629 0.352867158278 
+
+479 0.835869722446 0.400416633507 
+
+480 0.823356702649 0.439206994878 
+
+481 0.808341078893 0.464233034472 
+
+482 0.805838474933 0.493012980006 
+
+483 0.795828059095 0.534305945336 
+
+484 0.77580722742 0.546818965133 
+
+485 0.752032489806 0.575598910667 
+
+486 0.747027281887 0.599373648281 
+
+487 0.723252544272 0.625650989855 
+
+488 0.700729108638 0.654430935388 
+
+489 0.700729108638 0.60187625224 
+
+490 0.701980410617 0.563085890869 
+
+491 0.599373648281 0.598122346301 
+
+492 0.568091098788 0.620645781936 
+
+493 0.558080682951 0.586860628484 
+
+494 0.554326777011 0.549321569093 
+
+495 0.60312755422 0.514285113661 
+
+496 0.548070267113 0.508028603762 
+
+497 0.549321569093 0.284045549394 
+
+498 0.51553641564 0.262773415739 
+
+499 0.500520791884 0.225234356348 
+
+500 0.544316361174 0.212721336551 
+
+501 0.575598910667 0.238998678125 
+
+502 0.594368440362 0.210218732591 
+
+503 0.608132762139 0.251511697922 
+
+504 0.621897083916 0.200208316754 
+
+505 0.641917915591 0.250260395942 
+
+506 0.64692312351 0.226485658327 
+
+507 0.673200465084 0.196454410814 
+
+508 0.716996034374 0.201459618733 
+
+509 0.699477806658 0.237747376145 
+
+510 0.680708276962 0.275286435536 
+
+511 0.701980410617 0.284045549394 
+
+512 0.73451426209 0.251511697922 
+
+513 0.739519470009 0.220229148429 
+
+514 0.763294207623 0.190197900916 
+
+515 0.780812435339 0.212721336551 
+
+516 0.783315039298 0.242752584064 
+
+517 0.782063737319 0.275286435536 
+
+518 0.758288999704 0.242752584064 
+
+519 0.803335870974 0.197705712794 
+
+520 0.81835149473 0.269029925638 
+
+521 0.850885346203 0.246506490003 
+
+522 0.863398366 0.210218732591 
+
+523 0.854639252142 0.374139291933 
+
+524 0.852136648182 0.43295048498 
+
+525 0.869654875898 0.465484336452 
+
+526 0.86089576204 0.493012980006 
+
+527 0.842126232345 0.529300737417 
+
+528 0.830864514527 0.56058328691 
+
+529 0.809592380872 0.580604118585 
+
+530 0.825859306609 0.626902291835 
+
+531 0.792074153156 0.636912707672 
+
+532 0.759540301684 0.631907499753 
+
+533 0.797079361075 0.683210880922 
+
+534 0.754535093765 0.676954371023 
+
+535 0.843377534324 0.678205673003 
+
+536 0.859644460061 0.613137970058 
+
+537 0.872157479858 0.590614534423 
+
+538 0.878413989756 0.56183458889 
+
+539 0.899686123411 0.51553641564 
+
+540 0.917204351127 0.494264281985 
+
+541 0.925963464985 0.459227826554 
+
+542 0.887173103614 0.431699183 
+
+543 0.934722578843 0.431699183 
+
+544 0.933471276864 0.402919237467 
+
+545 0.885921801635 0.385401009751 
+
+546 0.902188727371 0.354118460258 
+
+547 0.938476484782 0.341605440461 
+
+548 0.942230390722 0.370385385994 
+
+549 0.94723559864 0.311574192948 
+
+550 0.939727786762 0.294055965232 
+
+551 0.915953049148 0.285296851374 
+
+552 0.857141856101 0.311574192948 
+
+553 0.894680915493 0.261522113759 
+
+554 0.912199143209 0.232742168226 
+
+555 0.9497382026 0.223983054368 
+
+556 0.919706955087 0.56183458889 
+
+557 0.914701747168 0.540562455235 
+
+558 0.910947841229 0.624399687875 
+
+559 0.930968672904 0.609384064119 
+
+560 0.914701747168 0.676954371023 
+
+561 0.878413989756 0.668195257165 
+
+562 0.902188727371 0.706985618536 
+
+563 0.94723559864 0.574347608687 
+
+564 0.969759034275 0.564337192849 
+
+565 0.969759034275 0.543065059194 
+
+566 0.979769450113 0.495515583965 
+
+567 0.945984296661 0.493012980006 
+
+568 0.960999920417 0.460479128533 
+
+569 0.984774658032 0.439206994878 
+
+570 0.981020752093 0.410427049345 
+
+571 0.998538979808 0.381647103812 
+
+572 0.86464966798 0.193951806855 
+
+573 0.450468712696 0.30031247513 
+
+574 0.397914029548 0.299061173151 
+
+575 0.365380178075 0.294055965232 
+
+576 0.316579400867 0.292804663252 
+
+577 0.286548153354 0.357872366197 
+
+578 0.377893197872 0.351615856298 
+
+579 0.404170539446 0.3453593464 
+
+580 0.406673143406 0.382898405791 
+
+581 0.412929653304 0.419186163203 
+
+582 0.374139291933 0.421688767162 
+
+583 0.352867158278 0.405421841426 
+
+584 0.371636687974 0.513033811681 
+
+585 0.374139291933 0.636912707672 
+
+586 0.462981732493 0.545567663154 
+
+587 0.459227826554 0.590614534423 
+
+588 0.445463504777 0.638164009652 
+
+589 0.350364554319 0.714493430414 
+
+590 0.280291643455 0.673200465084 
+
+591 0.246506490003 0.661938747267 
+
+592 0.249009093962 0.626902291835 
+
+593 0.227736960307 0.554326777011 
+
+594 0.251511697922 0.467986940411 
+
+595 0.269029925638 0.427945277061 
+
+596 0.241501282084 0.379144499852 
+
+597 0.270281227617 0.394160123609 
+
+598 0.232742168226 0.347861950359 
+
+599 0.235244772185 0.312825494927 
+
+600 0.249009093962 0.275286435536 
+
+601 0.294055965232 0.244003886043 
+
+602 0.319082004826 0.252762999901 
+
+603 0.347861950359 0.235244772185 
+
+604 0.30281507909 0.191449202896 
+
+605 0.218977846449 0.223983054368 
+
+606 0.17142837122 0.275286435536 
+
+607 0.17142837122 0.220229148429 
+
+608 0.372887989954 0.231490866246 
+
+609 0.38915491569 0.211470034571 
+
+610 0.43295048498 0.238998678125 
+
+611 0.471740846351 0.21647524249 
+
+612 0.450468712696 0.341605440461 
+
+613 0.471740846351 0.504274697823 
+
+614 0.494264281985 0.534305945336 
+
+615 0.464233034472 0.267778623658 
+
+616 0.47424345031 0.185192692997 
+
+617 0.427945277061 0.176433579139 
+
+618 0.523044227519 0.196454410814 
+
+619 0.588111930464 0.182690089038 
+
+620 0.520541623559 0.505525999803 
+
+621 0.521792925539 0.556829380971 
+
+622 0.489259074067 0.566839796809 
+
+623 1.00479548971 0.455473920614 
+
+624 1.02731892534 0.51929032158 
+
+625 1.02731892534 0.583106722545 
+
+626 1.00604679169 0.60312755422 
+
+627 0.979769450113 0.60187625224 
+
+628 0.998538979808 0.631907499753 
+
+629 0.99353377189 0.664441351226 
+
+630 0.988528563971 0.703231712597 
+
+631 0.963502524377 0.718247336353 
+
+632 0.932219974884 0.716996034374 
+
+633 0.743273375948 0.86214706402 
+
+634 0.684462182901 0.132638009849 
+
+635 0.551824173052 0.136391915788 
+
+636 0.610635366098 0.132638009849 
+
+637 0.807089776913 0.113868480154 
+
+638 0.334097628583 0.201459618733 
+
+639 0.361626272136 0.210218732591 
+
+640 0.376641895893 0.158915351423 
+
+641 0.347861950359 0.162669257362 
+
+642 0.414180955284 0.153910143504 
+
+643 0.455473920614 0.161417955383 
+
+644 0.236496074165 0.161417955383 
+
+645 0.275286435536 0.147653633606 
+
+646 0.297809871171 0.147653633606 
+
+647 0.325338514725 0.141397123707 
+
+648 0.351615856298 0.137643217768 
+
+649 0.372887989954 0.136391915788 
+
+650 0.402919237467 0.132638009849 
+
+651 0.43295048498 0.13138670787 
+
+652 0.470489544371 0.132638009849 
+
+653 0.503023395843 0.162669257362 
+
+654 0.395411425588 0.276537737516 
+
+655 0.406673143406 0.2590195098 
+
+656 0.43295048498 0.385401009751 
+
+657 0.455473920614 0.382898405791 
+
+658 0.447966108736 0.434201786959 
+
+659 0.47299214833 0.42919657904 
+
+660 0.457976524574 0.479248658229 
+
+661 0.434201786959 0.466735638432 
+
+662 0.449217410716 0.523044227519 
+
+663 0.544316361174 0.456725222594 
+
+664 0.514285113661 0.449217410716 
+
+665 0.5180390196 0.406673143406 
+
+666 0.538059851275 0.415432257264 
+
+667 0.573096306707 0.400416633507 
+
+668 0.595619742342 0.384149707771 
+
+669 0.619394479956 0.377893197872 
+
+670 0.616891875997 0.427945277061 
+
+671 0.673200465084 0.382898405791 
+
+672 0.6907186928 0.360374970156 
+
+673 0.670697861124 0.324087212745 
+
+674 0.650677029449 0.341605440461 
+
+675 0.624399687875 0.351615856298 
+
+676 0.56183458889 0.355369762238 
+
+677 0.555578078991 0.310322890968 
+
+678 0.571845004727 0.284045549394 
+
+679 0.565588494829 0.26027081178 
+
+680 0.539311153255 0.26027081178 
+
+681 0.524295529498 0.285296851374 
+
+682 0.658184841327 0.276537737516 
+
+683 0.641917915591 0.269029925638 
+
+684 0.705734316556 0.25776820782 
+
+685 0.724503846252 0.281542945435 
+
+686 0.606881460159 0.272783831577 
+
+687 0.686964786861 0.435453088939 
+
+688 0.714493430414 0.419186163203 
+
+689 0.636912707672 0.452971316655 
+
+690 0.613137970058 0.462981732493 
+
+691 0.598122346301 0.439206994878 
+
+692 0.600624950261 0.415432257264 
+
+693 0.638164009652 0.416683559243 
+
+694 0.685713484881 0.457976524574 
+
+695 0.661938747267 0.476746054269 
+
+696 0.634410103713 0.498018187925 
+
+697 1.05985277681 0.681959578942 
+
+698 1.08237621245 0.706985618536 
+
+699 1.11240745996 0.724503846252 
+
+700 1.1286743857 0.681959578942 
+
+701 1.10740225204 0.658184841327 
+
+702 1.14744391539 0.633158801733 
+
+703 1.12617178174 0.60563015818 
+
+704 1.17997776687 0.565588494829 
+
+705 1.18748557874 0.534305945336 
+
+706 1.12742308372 0.555578078991 
+
+707 1.11991527184 0.578101514626 
+
+708 1.08362751443 0.531803341377 
+
+709 1.07111449463 0.499269489904 
+
+710 1.09113532631 0.486756470107 
+
+711 1.03858064316 0.407924445385 
+
+712 1.06736058869 0.410427049345 
+
+713 1.09488923225 0.415432257264 
+
+714 1.14619261341 0.420437465183 
+
+715 1.17747516291 0.415432257264 
+
+716 1.18248037083 0.466735638432 
+
+717 1.21000901438 0.47549475229 
+
+718 1.21876812824 0.528049435438 
+
+719 1.19749599458 0.56183458889 
+
+720 1.18748557874 0.611886668078 
+
+721 1.16996735103 0.650677029449 
+
+722 1.16871604905 0.686964786861 
+
+723 1.15495172727 0.728257752191 
+
+724 1.05985277681 0.724503846252 
+
+725 1.11866396986 0.376641895893 
+
+726 1.07987360849 0.367882782035 
+
+727 1.04483715306 0.364128876096 
+
+728 1.16746474707 0.376641895893 
+
+729 1.17622386093 0.339102836501 
+
+730 1.14243870748 0.34410804442 
+
+731 1.10489964808 0.326589816704 
+
+732 1.07862230651 0.312825494927 
+
+733 1.05359626692 0.329092420664 
+
+734 1.05359626692 0.351615856298 
+
+735 0.715744732394 0.484253866148 
+
+736 0.737016866049 0.457976524574 
+
+737 0.727006450211 0.436704390919 
+
+738 0.73326296011 0.414180955284 
+
+739 0.759540301684 0.381647103812 
+
+740 0.735765564069 0.365380178075 
+
+741 0.793325455136 0.483002564168 
+
+742 0.790822851177 0.425442673101 
+
+743 0.81835149473 0.336600232542 
+
+744 0.829613212548 0.295307267212 
+
+745 0.837121024426 0.267778623658 
+
+746 0.808341078893 0.246506490003 
+
+747 0.795828059095 0.261522113759 
+
+748 0.614389272038 0.227736960307 
+
+749 0.576850212646 0.222731752388 
+
+750 0.491761678026 0.0838372326406 
+
+751 0.411678351325 0.0863398366 
+
+752 0.409175747365 0.0337851534522 
+
+753 0.531803341377 0.0187695296956 
+
+754 0.6907186928 0.0125130197971 
+
+755 0.815848890771 0.0212721336551 
+
+756 0.485505168127 0.624399687875 
+
+757 0.183941391017 0.718247336353 
+
+758 0.107611970255 0.727006450211 
+
+759 0.498018187925 0.509279905742 
+
+760 0.523044227519 0.594368440362 
+
+761 0.489259074067 0.414180955284 
+
+762 0.494264281985 0.341605440461 
+
+763 0.466735638432 0.350364554319 
+
+764 0.485505168127 0.291553361272 
+
+765 0.499269489904 0.246506490003 
+
+766 0.499269489904 0.195203108835 
+
+767 0.564337192849 0.455473920614 
+
+768 0.528049435438 0.531803341377 
+
+769 0.56058328691 0.536808549296 
+
+770 0.536808549296 0.576850212646 
+
+771 1.31261577672 0.256516905841 
+
+772 0.459227826554 0.241501282084 
+
+773 0.466735638432 0.296558569191 
+
+774 0.508028603762 0.366631480055 
+
+775 0.47424345031 0.381647103812 
+
+776 0.452971316655 0.362877574116 
+
+777 0.489259074067 0.392908821629 
+
+778 0.524295529498 0.38790361371 
+
+779 0.545567663154 0.372887989954 
+
+780 0.546818965133 0.349113252339 
+
+781 0.508028603762 0.321584608785 
+
+782 0.424191371122 0.335348930562 
+
+783 0.451720014675 0.321584608785 
+
+784 0.420437465183 0.365380178075 
+
+785 0.421688767162 0.399165331527 
+
+786 0.404170539446 0.322835910765 
+
+787 0.416683559243 0.30031247513 
+
+788 0.586860628484 0.337851534522 
+
+789 0.578101514626 0.377893197872 
+
+790 0.520541623559 0.436704390919 
+
+791 0.494264281985 0.439206994878 
+
+792 0.506777301783 0.485505168127 
+
+793 0.530552039397 0.495515583965 
+
+794 0.556829380971 0.491761678026 
+
+795 0.585609326504 0.496766885945 
+
+796 0.558080682951 0.409175747365 
+
+797 0.480499960209 0.312825494927 
+
+798 0.447966108736 0.279040341475 
+
+799 0.442960900817 0.26027081178 
+
+800 0.494264281985 0.272783831577 
+
+801 0.594368440362 0.315328098887 
+
+802 1.05735017285 0.590614534423 
+
+803 1.01105199961 0.554326777011 
+
+804 1.07361709859 0.553075475032 
+
+805 1.07987360849 0.594368440362 
+
+806 1.109904856 0.530552039397 
+
+807 0.0575598910667 0.711990826455 
+
+808 0.0450468712696 0.644420519551 
+
+809 0.0275286435536 0.578101514626 
+
+810 0.00750781187826 0.5180390196 
+
+811 -0.00625650989855 0.455473920614 
+
+812 -0.0100104158377 0.382898405791 
+
+813 -0.0200208316754 0.30281507909 
+
+814 0.0400416633507 0.21772654447 
+
+815 0.0425442673101 0.309071588988 
+
+816 0.0550572871072 0.374139291933 
+
+817 0.0650677029449 0.445463504777 
+
+818 0.0825859306609 0.513033811681 
+
+819 0.0913450445188 0.570593702748 
+
+820 0.0976015544174 0.640666613611 
+
+821 0.186443994977 0.675703069043 
+
+822 0.147653633606 0.639415311632 
+
+823 0.160166653403 0.540562455235 
+
+824 0.147653633606 0.466735638432 
+
+825 0.133889311829 0.400416633507 
+
+826 0.112617178174 0.309071588988 
+
+827 0.121376292032 0.254014301881 
+
+828 0.163920559342 0.347861950359 
+
+829 0.167674465281 0.445463504777 
+
+830 0.182690089038 0.576850212646 
+
+831 0.210218732591 0.661938747267 
+
+832 0.220229148429 0.709488222496 
+
+833 0.152658841525 0.709488222496 
+
+834 0.111365876194 0.675703069043 
+
+835 0.0888424405594 0.421688767162 
+
+836 0.0863398366 0.466735638432 
+
+837 0.0588111930464 0.499269489904 
+
+838 0.103858064316 0.51929032158 
+
+839 0.0237747376145 0.394160123609 
+
+840 0.0638164009652 0.34661064838 
+
+841 -0.00875911385797 0.485505168127 
+
+842 0.00875911385797 0.556829380971 
+
+843 -0.0187695296956 0.591865836403 
+
+844 -0.0437955692898 0.511782509701 
+
+845 -0.0488007772087 0.401667935487 
+
+846 -0.0450468712696 0.369134084014 
+
+847 -0.0162669257362 0.336600232542 
+
+848 0.0325338514725 0.25776820782 
+
+849 0.0575598910667 0.280291643455 
+
+850 0.0750781187826 0.406673143406 
+
+851 0.0938476484782 0.361626272136 
+
+852 0.341605440461 0.618143177977 
+
+853 0.340354138481 0.654430935388 
+
+854 0.320333306806 0.588111930464 
+
+855 0.370385385994 0.380395801832 
+
+856 0.317830702846 0.330343722643 
+
+857 0.350364554319 0.311574192948 
+
+858 0.342856742441 0.287799455333 
+
+859 0.364128876096 0.274035133556 
+
+860 0.364128876096 0.450468712696 
+
+861 0.407924445385 0.455473920614 
+
+862 0.575598910667 0.359123668177 
+
+863 0.606881460159 0.365380178075 
+
+864 0.596871044322 0.400416633507 
+
+865 0.570593702748 0.445463504777 
+
+866 0.554326777011 0.440458296858 
+
+867 0.581855420565 0.434201786959 
+
+868 0.523044227519 0.420437465183 
+
+869 0.505525999803 0.404170539446 
+
+870 0.461730430513 0.416683559243 
+
+871 0.451720014675 0.397914029548 
+
+872 0.470489544371 0.370385385994 
+
+873 0.476746054269 0.341605440461 
+
+874 0.531803341377 0.305317683049 
+
+875 0.543065059194 0.299061173151 
+
+876 0.568091098788 0.30031247513 
+
+877 0.546818965133 0.327841118684 
+
+878 0.524295529498 0.354118460258 
+
+879 0.520541623559 0.330343722643 
+
+880 0.615640574017 0.321584608785 
+
+881 0.633158801733 0.310322890968 
+
+882 0.625650989855 0.340354138481 
+
+883 0.609384064119 0.351615856298 
+
+884 0.650677029449 0.374139291933 
+
+885 0.628153593814 0.38665231173 
+
+886 0.650677029449 0.294055965232 
+
+887 0.674451767064 0.294055965232 
+
+888 0.591865836403 0.264024717719 
+
+889 0.545567663154 0.274035133556 
+
+890 1.04733975702 0.203962222693 
+
+891 0.998538979808 0.178936183099 
+
+892 0.942230390722 0.140145821728 
+
+893 0.979769450113 0.191449202896 
+
+894 0.982272054072 0.247757791983 
+
+895 1.03732934118 0.251511697922 
+
+896 0.996036375849 0.281542945435 
+
+897 1.12992568768 0.245255188023 
+
+898 1.08362751443 0.251511697922 
+
+899 1.07361709859 0.200208316754 
+
+900 1.05985277681 0.222731752388 
+
+901 0.99103116793 0.21397263853 
+
+902 0.940979088742 0.186443994977 
+
+903 0.661938747267 0.392908821629 
+
+904 0.593117138382 0.476746054269 
+
+905 0.671949163104 0.425442673101 
+
+906 0.327841118684 0.531803341377 
+
+907 0.351615856298 0.556829380971 
+
+908 0.374139291933 0.568091098788 
+
+909 0.451720014675 0.611886668078 
+
+910 0.2590195098 0.0513033811681 
+
+911 0.312825494927 0.00750781187826 
+
+912 0.406673143406 -0.00500520791884 
+
+913 0.0638164009652 0.181438787058 
+
+914 0.146402331626 0.111365876194 
+
+915 0.203962222693 0.0675703069043 
+
+916 0.969759034275 0.0713242128435 
+
+917 0.849634044223 0.565588494829 
+
+918 0.863398366 0.529300737417 
+
+919 0.889675707574 0.488007772087 
+
+920 0.885921801635 0.459227826554 
+
+921 1.11115615798 0.0675703069043 
+
+922 0.579352816606 -0.0187695296956 
+
+923 0.649425727469 -0.0312825494927 
+
+924 0.580604118585 0.038790361371 
+
+925 0.636912707672 0.0400416633507 
+
+926 0.454222618635 0.047549475229 
+
+927 0.520541623559 0.0450468712696 
+
+928 0.445463504777 -0.00375390593913 
+
+929 0.513033811681 -0.0150156237565 
+
+930 0.723252544272 -0.0162669257362 
+
+931 0.742022073968 0.0262773415739 
+
+932 0.699477806658 0.0437955692898 
+
+933 0.60312755422 0.00500520791884 
+
+934 0.369134084014 0.0675703069043 
+
+935 0.360374970156 0.0212721336551 
+
+936 0.355369762238 -0.0100104158377 
+
+937 0.500520791884 0.0137643217768 
+
+938 0.523044227519 0.112617178174 
+
+939 0.608132762139 0.106360668275 
+
+940 0.694472598739 0.103858064316 
+
+941 0.772053321481 0.112617178174 
+
+942 0.788320247217 0.077580722742 
+
+943 0.447966108736 0.0888424405594 
+
+944 0.30406638107 0.0963502524377 
+
+945 0.86089576204 0.126381499951 
+
+946 0.908445237269 0.0400416633507 
+
+947 0.296558569191 0.548070267113 
+
+948 0.269029925638 0.534305945336 
+
+949 0.237747376145 0.510531207722 
+
+950 0.208967430612 0.485505168127 
+
+951 0.21522394051 0.427945277061 
+
+952 0.356621064217 0.356621064217 
+
+953 0.350364554319 0.38790361371 
+
+954 0.325338514725 0.385401009751 
+
+955 0.330343722643 0.351615856298 
+
+956 0.30406638107 0.3453593464 
+
+957 0.299061173151 0.314076796907 
+
+958 0.275286435536 0.315328098887 
+
+959 0.362877574116 0.329092420664 
+
+960 0.315328098887 0.276537737516 
+
+961 0.290302059293 0.265276019698 
+
+962 0.218977846449 0.262773415739 
+
+963 0.249009093962 0.264024717719 
+
+964 0.246506490003 0.296558569191 
+
+965 0.220229148429 0.360374970156 
+
+966 0.228988262287 0.410427049345 
+
+967 0.192700504875 0.381647103812 
+
+968 0.309071588988 0.435453088939 
+
+969 0.271532529597 0.445463504777 
+
+970 0.233993470206 0.460479128533 
+
+971 0.279040341475 0.476746054269 
+
+972 0.26027081178 0.493012980006 
+
+973 0.30406638107 0.503023395843 
+
+974 0.329092420664 0.506777301783 
+
+975 0.361626272136 0.476746054269 
+
+976 0.377893197872 0.496766885945 
+
+977 0.395411425588 0.485505168127 
+
+978 0.417934861223 0.494264281985 
+
+979 0.401667935487 0.407924445385 
+
+980 0.352867158278 0.425442673101 
+
+981 0.331595024623 0.422940069142 
+
+982 0.324087212745 0.456725222594 
+
+983 0.312825494927 0.401667935487 
+
+984 0.287799455333 0.409175747365 
+
+985 0.289050757313 0.43044788102 
+
+986 0.30281507909 0.366631480055 
+
+987 0.276537737516 0.3453593464 
+
+988 0.315328098887 0.312825494927 
+
+989 0.297809871171 0.30281507909 
+
+990 0.269029925638 0.286548153354 
+
+991 0.284045549394 0.25776820782 
+
+992 0.307820287009 0.262773415739 
+
+993 0.327841118684 0.269029925638 
+
+994 0.334097628583 0.250260395942 
+
+995 0.317830702846 0.240249980104 
+
+996 0.356621064217 0.255265603861 
+
+997 0.379144499852 0.247757791983 
+
+998 0.407924445385 0.247757791983 
+
+999 0.414180955284 0.279040341475 
+
+1000 0.376641895893 0.30156377711 
+
+1001 0.379144499852 0.334097628583 
+
+1002 0.391657519649 0.245255188023 
+
+1003 0.420437465183 0.227736960307 
+
+1004 0.425442673101 0.252762999901 
+
+1005 0.445463504777 0.232742168226 
+
+1006 0.457976524574 0.21772654447 
+
+1007 0.47549475229 0.232742168226 
+
+1008 0.414180955284 0.205213524672 
+
+1009 0.399165331527 0.195203108835 
+
+1010 0.379144499852 0.190197900916 
+
+1011 0.349113252339 0.201459618733 
+
+1012 0.34661064838 0.218977846449 
+
+1013 0.316579400867 0.205213524672 
+
+1014 0.299061173151 0.211470034571 
+
+1015 0.30156377711 0.230239564267 
+
+1016 0.270281227617 0.236496074165 
+
+1017 0.267778623658 0.220229148429 
+
+1018 0.317830702846 0.182690089038 
+
+1019 0.335348930562 0.177684881119 
+
+1020 0.370385385994 0.207716128632 
+
+1021 0.427945277061 0.190197900916 
+
+1022 0.450468712696 0.190197900916 
+
+1023 0.469238242391 0.201459618733 
+
+1024 0.437955692898 0.21772654447 
+
+1025 0.486756470107 0.203962222693 
+
+1026 0.511782509701 0.208967430612 
+
+1027 0.529300737417 0.231490866246 
+
+1028 0.51929032158 0.21772654447 
+
+1029 0.520541623559 0.242752584064 
+
+1030 0.504274697823 0.26027081178 
+
+1031 0.509279905742 0.279040341475 
+
+1032 0.499269489904 0.292804663252 
+
+1033 0.495515583965 0.320333306806 
+
+1034 0.553075475032 0.236496074165 
+
+1035 0.569342400768 0.202710920713 
+
+1036 0.525546831478 0.182690089038 
+
+1037 0.495515583965 0.178936183099 
+
+1038 0.558080682951 0.163920559342 
+
+1039 0.614389272038 0.188946598936 
+
+1040 0.630656197774 0.21772654447 
+
+1041 0.593117138382 0.237747376145 
+
+1042 0.585609326504 0.291553361272 
+
+1043 0.624399687875 0.277789039496 
+
+1044 0.624399687875 0.255265603861 
+
+1045 0.631907499753 0.235244772185 
+
+1046 0.649425727469 0.205213524672 
+
+1047 0.669446559145 0.1726796732 
+
+1048 0.703231712597 0.165171861322 
+
+1049 0.696975202698 0.201459618733 
+
+1050 0.678205673003 0.226485658327 
+
+1051 0.684462182901 0.251511697922 
+
+1052 0.668195257165 0.2590195098 
+
+1053 0.719498638333 0.227736960307 
+
+1054 0.730760356151 0.175182277159 
+
+1055 0.724503846252 0.12888410391 
+
+1056 0.650677029449 0.12888410391 
+
+1057 0.509279905742 0.12888410391 
+
+1058 0.43044788102 0.30156377711 
+
+1059 0.444212202797 0.331595024623 
+
+1060 0.381021452822 0.287173804343 
+
+1061 0.410427049345 0.290302059293 
+
+1062 0.436704390919 0.291553361272 
+
+1063 0.467986940411 0.284045549394 
+
+1064 0.477997356249 0.249009093962 
+
+1065 0.455473920614 0.255891254851 
+
+1066 0.422940069142 0.264650368709 
+
+1067 0.402293586477 0.270281227617 
+
+1068 0.38915491569 0.233993470206 
+
+1069 0.417934861223 0.21647524249 
+
+1070 0.564337192849 0.272783831577 
+
+1071 0.549947220082 0.25776820782 
+
+1072 0.56183458889 0.248383442972 
+
+1073 0.579352816606 0.254639952871 
+
+1074 0.578727165616 0.268404274648 
+
+1075 0.588737581454 0.310948541958 
+
+1076 0.570593702748 0.323461561755 
+
+1077 0.588111930464 0.324087212745 
+
+1078 0.60375320521 0.328466769674 
+
+1079 0.626902291835 0.304692032059 
+
+1080 0.611886668078 0.289676408303 
+
+1081 0.56246023988 0.368508433025 
+
+1082 0.547444616123 0.360374970156 
+
+1083 0.5180390196 0.376016244903 
+
+1084 0.541188106225 0.384775358761 
+
+1085 0.55995763592 0.396037076578 
+
+1086 0.501772093864 0.379144499852 
+
+1087 0.493638630996 0.355369762238 
+
+1088 0.456099571604 0.372262338964 
+
+1089 0.436704390919 0.371636687974 
+
+1090 0.413555304294 0.354744111248 
+
+1091 0.399165331527 0.357872366197 
+
+1092 0.391031868659 0.337225883532 
+
+1093 0.442960900817 0.312825494927 
+
+1094 0.469863893381 0.311574192948 
+
+1095 0.493638630996 0.305943334039 
+
+1096 0.508654254752 0.311574192948 
+
+1097 0.463607383483 0.332220675613 
+
+1098 0.483002564168 0.272783831577 
+
+1099 0.491136027036 0.250886046932 
+
+1100 0.489259074067 0.233993470206 
+
+1101 0.506151650793 0.236496074165 
+
+1102 0.525546831478 0.25839385881 
+
+1103 0.532428992367 0.274660784546 
+
+1104 0.535557247316 0.294055965232 
+
+1105 0.51929032158 0.30093812612 
+
+1106 0.523044227519 0.319707655816 
+
+1107 0.549947220082 0.319082004826 
+
+1108 0.555578078991 0.296558569191 
+
+1109 0.546193314143 0.242752584064 
+
+1110 0.543690710184 0.231490866246 
+
+1111 0.56058328691 0.229613913277 
+
+1112 0.55870633394 0.213346987541 
+
+1113 0.585609326504 0.21710089348 
+
+1114 0.598747997291 0.225234356348 
+
+1115 0.610635366098 0.2158495915 
+
+1116 0.612512319068 0.240875631094 
+
+1117 0.606255809169 0.203336571703 
+
+1118 0.586860628484 0.198957014774 
+
+1119 0.572470655717 0.192074853885 
+
+1120 0.545567663154 0.200833967743 
+
+1121 0.503023395843 0.2158495915 
+
+1122 0.554326777011 0.337225883532 
+
+1123 0.556203729981 0.320958957796 
+
+1124 0.629404895794 0.327215467694 
+
+1125 0.643794868561 0.315953749877 
+
+1126 0.653805284398 0.325338514725 
+
+1127 0.663815700236 0.335348930562 
+
+1128 0.672574814094 0.350364554319 
+
+1129 0.677580022013 0.365380178075 
+
+1130 0.69196999478 0.373513640943 
+
+1131 0.706985618536 0.371636687974 
+
+1132 0.723252544272 0.366005829065 
+
+1133 0.725755148232 0.352241507288 
+
+1134 0.723878195262 0.339102836501 
+
+1135 0.706985618536 0.34410804442 
+
+1136 0.696349551709 0.34348239343 
+
+1137 0.6907186928 0.330969373633 
+
+1138 0.687590437851 0.322835910765 
+
+1139 0.682585229932 0.313451145917 
+
+1140 0.671323512114 0.308445937998 
+
+1141 0.660687445287 0.3021894281 
+
+1142 0.662564398256 0.292804663252 
+
+1143 0.665692653206 0.284671200384 
+
+1144 0.668195257165 0.275912086526 
+
+1145 0.661313096277 0.265901670688 
+
+1146 0.658184841327 0.25839385881 
+
+1147 0.657559190338 0.250260395942 
+
+1148 0.658184841327 0.238373027135 
+
+1149 0.660687445287 0.233367819216 
+
+1150 0.698226504678 0.325338514725 
+
+1151 0.701980410617 0.314702447897 
+
+1152 0.706359967546 0.309071588988 
+
+1153 0.700729108638 0.30156377711 
+
+1154 0.695098249729 0.292804663252 
+
+1155 0.69134434379 0.284045549394 
+
+1156 0.693846947749 0.275912086526 
+
+1157 0.695098249729 0.266527321678 
+
+1158 0.696349551709 0.256516905841 
+
+1159 0.694472598739 0.245880839013 
+
+1160 0.69196999478 0.234619121196 
+
+1161 0.735765564069 0.34661064838 
+
+1162 0.729509054171 0.330969373633 
+
+1163 0.722626893282 0.325338514725 
+
+1164 0.720749940313 0.313451145917 
+
+1165 0.718247336353 0.298435522161 
+
+1166 0.718872987343 0.282794247414 
+
+1167 0.720749940313 0.271532529597 
+
+1168 0.722626893282 0.25964516079 
+
+1169 0.724503846252 0.249634744952 
+
+1170 0.746401630897 0.335974581552 
+
+1171 0.742647724958 0.317830702846 
+
+1172 0.740770771988 0.30281507909 
+
+1173 0.741396422978 0.290302059293 
+
+1174 0.737016866049 0.280291643455 
+
+1175 0.738893819019 0.270906878607 
+
+1176 0.701354759627 0.42982223003 
+
+1177 0.703857363587 0.416057908254 
+
+1178 0.712616477445 0.409175747365 
+
+1179 0.725129497242 0.400416633507 
+
+1180 0.737642517039 0.396037076578 
+
+1181 0.69196999478 0.400416633507 
+
+1182 0.701980410617 0.38978056668 
+
+1183 0.712616477445 0.384775358761 
+
+1184 0.730134705161 0.377893197872 
+
+1185 0.745150328917 0.374764942923 
+
+1186 0.659436143307 0.442335249827 
+
+1187 0.673200465084 0.442960900817 
+
+1188 0.685087833891 0.445463504777 
+
+1189 0.696349551709 0.445463504777 
+
+1190 0.718247336353 0.443586551807 
+
+1191 0.740145120998 0.443586551807 
+
+1192 0.757663348714 0.440458296858 
+
+1193 0.626902291835 0.43232483399 
+
+1194 0.641292264601 0.422940069142 
+
+1195 0.660061794297 0.417934861223 
+
+1196 0.672574814094 0.413555304294 
+
+1197 0.644420519551 0.466735638432 
+
+1198 0.665692653206 0.466109987442 
+
+1199 0.676328720033 0.468612591401 
+
+1200 0.699477806658 0.469238242391 
+
+1201 0.713242128435 0.471115195361 
+
+1202 0.656933539348 0.485505168127 
+
+1203 0.675077418053 0.489884725056 
+
+1204 0.695098249729 0.494264281985 
+
+1205 0.708236920516 0.493638630996 
+
+1206 0.729509054171 0.491761678026 
+
+1207 0.640666613611 0.51616206663 
+
+1208 0.658184841327 0.51678771762 
+
+1209 0.675077418053 0.51866467059 
+
+1210 0.697600853688 0.5180390196 
+
+1211 0.716370383384 0.51678771762 
+
+1212 0.625650989855 0.412929653304 
+
+1213 0.615014923027 0.451720014675 
+
+1214 0.624399687875 0.478623007239 
+
+1215 0.620645781936 0.498643838914 
+
+1216 0.544942012164 0.158289700433 
+
+1217 0.599373648281 0.297809871171 
+
+1218 0.608132762139 0.390406217669 
+
+1219 0.626902291835 0.366631480055 
+
+1220 0.643169217571 0.352867158278 
+
+1221 0.639415311632 0.402919237467 
+
+1222 0.640666613611 0.279040341475 
+
+1223 0.616891875997 0.271532529597 
+
+1224 0.534305945336 0.208967430612 
+
+1225 0.411678351325 0.317830702846 
+
+1226 0.422940069142 0.324087212745 
+
+1227 0.355369762238 0.297809871171 
+
+1228 0.357872366197 0.241501282084 
+
+1229 0.412929653304 0.177684881119 
+
+1230 0.434201786959 0.161417955383 
+
+1231 0.459227826554 0.178936183099 
+
+1232 0.481751262188 0.163920559342 
+
+1233 0.47549475229 0.152658841525 
+
+1234 0.450468712696 0.146402331626 
+
+1235 0.503023395843 0.145151029646 
+
+1236 0.525546831478 0.166423163301 
+
+1237 0.528049435438 0.147653633606 
+
+1238 0.569342400768 0.150156237565 
+
+1239 0.583106722545 0.166423163301 
+
+1240 0.606881460159 0.17142837122 
+
+1241 0.628153593814 0.152658841525 
+
+1242 0.600624950261 0.151407539545 
+
+1243 0.580604118585 0.137643217768 
+
+1244 0.626902291835 0.133889311829 
+
+1245 0.656933539348 0.153910143504 
+
+1246 0.64692312351 0.187695296956 
+
+1247 0.626902291835 0.185192692997 
+
+1248 0.666943955185 0.210218732591 
+
+1249 0.663190049246 0.188946598936 
+
+1250 0.392283170639 0.149530586575 
+
+1251 0.386026660741 0.110114574214 
+
+1252 0.457976524574 0.106986319265 
+
+1253 0.556829380971 0.107611970255 
+
+1254 0.546193314143 0.0794576757116 
+
+1255 0.55870633394 0.181438787058 
+
+1256 0.679456974982 0.153910143504 
+
+1257 0.700729108638 0.181438787058 
+
+1258 0.716996034374 0.153284492514 
+
+1259 0.763294207623 0.165797512312 
+
+1260 0.747027281887 0.181438787058 
+
+1261 0.755786395745 0.208967430612 
+
+1262 0.785817643258 0.17142837122 
+
+1263 0.737642517039 0.111991527184 
+
+1264 0.716370383384 0.081960279671 
+
+1265 0.678205673003 0.0700729108638 
+
+1266 0.582481071555 0.0613137970058 
+
+1267 0.435453088939 0.0600624950261 
+
+1268 0.668195257165 2.00708837545 
+
+1269 0.600624950261 1.4615207123 
+
+1270 0.625650989855 2.35495032581 
+
+1271 0.635661405693 2.63524196927 
+
+1272 0.910947841229 2.62022634551 
+
+1273 0.913450445188 2.30740085059 
+
+1274 0.900937425391 1.98957014774 
+
+1275 0.417934861223 0.197705712794 
+
+1276 0.747027281887 0.490510376046 
+
+1277 0.757037697724 0.464858685462 
+
+1278 0.77643287841 0.466109987442 
+
+1279 0.780186784349 0.435453088939 
+
+1280 0.755786395745 0.414180955284 
+
+1281 0.77768418039 0.411678351325 
+
+1282 0.77580722742 0.396662727568 
+
+1283 0.786443294248 0.381021452822 
+
+1284 0.788320247217 0.355369762238 
+
+1285 0.789571549197 0.334723279572 
+
+1286 0.785817643258 0.312825494927 
+
+1287 0.785191992268 0.289676408303 
+
+1288 0.767673764552 0.279040341475 
+
+1289 0.758288999704 0.359123668177 
+
+1290 0.763294207623 0.339728487491 
+
+1291 0.764545509603 0.263399066729 
+
+1292 0.770176368511 0.232116517236 
+
+1293 0.746401630897 0.228988262287 
+
+1294 0.793325455136 0.225860007338 
+
+1295 0.788320247217 0.196454410814 
+
+1296 0.780812435339 0.182064438048 
+
+1297 0.744524677927 0.197080061804 
+
+1298 0.722626893282 0.185818343987 
+
+1299 0.695098249729 0.211470034571 
+
+1300 0.718247336353 0.21459828952 
+
+1301 0.813346286811 0.306568985029 
+
+1302 0.823982353639 0.232116517236 
+
+1303 0.825859306609 0.191449202896 
+
+1304 0.851510997193 0.160792304393 
+
+1305 0.851510997193 0.227111309317 
+
+1306 0.869029224909 0.245880839013 
+
+1307 0.869029224909 0.267152972668 
+
+1308 0.849008393233 0.285922502364 
+
+1309 0.842126232345 0.317830702846 
+
+1310 0.837746675416 0.34348239343 
+
+1311 0.836495373436 0.369134084014 
+
+1312 0.835869722446 0.38790361371 
+
+1313 0.808966729882 0.396037076578 
+
+1314 0.808966729882 0.371011036984 
+
+1315 0.808341078893 0.349113252339 
+
+1316 0.809592380872 0.322210259775 
+
+1317 0.797079361075 0.309071588988 
+
+1318 0.805838474933 0.433576135969 
+
+1319 0.824608004629 0.421688767162 
+
+1320 0.845880138284 0.421688767162 
+
+1321 0.843377534324 0.442960900817 
+
+1322 0.81835149473 0.449843061706 
+
+1323 0.797705012065 0.456725222594 
+
+1324 0.791448502167 0.47236649734 
+
+1325 0.77580722742 0.493012980006 
+
+1326 0.789571549197 0.488007772087 
+
+1327 0.81835149473 0.4748691013 
+
+1328 0.830864514527 0.247757791983 
+
+1329 0.838372326406 0.212721336551 
+
+1330 0.811469333842 0.21522394051 
+
+1331 0.871531828868 0.320958957796 
+
+1332 0.877788338766 0.290302059293 
+
+1333 0.890301358564 0.240875631094 
+
+1334 0.880290942726 0.192074853885 
+
+1335 0.885296150645 0.122001943022 
+
+1336 0.908445237269 0.142648425687 
+
+1337 0.9065682843 0.0932219974884 
+
+1338 0.784566341278 0.135140613809 
+
+1339 0.81897714572 0.143899727667 
+
+1340 0.879039640746 0.0538059851275 
+
+1341 0.958497316458 0.100104158377 
+
+1342 0.784566341278 0.047549475229 
+
+1343 0.822105400669 0.0488007772087 
+
+1344 0.830238863538 -0.0156412747464 
+
+1345 0.921583908056 0.0193951806855 
+
+1346 1.0054211407 0.0556829380971 
+
+1347 0.896557868462 0.208341779622 
+
+1348 0.880916593716 0.355995413227 
+
+1349 0.913450445188 0.378518848862 
+
+1350 0.952866457549 0.38790361371 
+
+1351 0.984149007042 0.394160123609 
+
+1352 0.960374269427 0.42982223003 
+
+1353 0.909070888259 0.420437465183 
+
+1354 0.880916593716 0.412929653304 
+
+1355 0.90719393529 0.438581343888 
+
+1356 0.850885346203 0.480499960209 
+
+1357 0.886547452624 0.4748691013 
+
+1358 0.925337813995 0.476746054269 
+
+1359 0.957871665468 0.479874309219 
+
+1360 0.944107343691 0.514910764651 
+
+1361 0.910947841229 0.501772093864 
+
+1362 0.871531828868 0.504274697823 
+
+1363 0.852136648182 0.512408160691 
+
+1364 0.81960279671 0.513659462671 
+
+1365 0.832115816507 0.543065059194 
+
+1366 0.859644460061 0.550572871072 
+
+1367 0.885296150645 0.527423784448 
+
+1368 0.919706955087 0.528049435438 
+
+1369 0.926589115975 0.51553641564 
+
+1370 0.960999920417 0.526798133458 
+
+1371 0.996662026839 0.539311153255 
+
+1372 0.994785073869 0.55995763592 
+
+1373 1.00104158377 0.521167274549 
+
+1374 1.01855981148 0.534931596326 
+
+1375 1.0298215293 0.5612089379 
+
+1376 1.05860147483 0.548070267113 
+
+1377 1.04421150207 0.531177690387 
+
+1378 1.08112491047 0.543065059194 
+
+1379 1.10740225204 0.542439408204 
+
+1380 1.13931045253 0.543690710184 
+
+1381 1.16245953915 0.541813757214 
+
+1382 1.17434690796 0.514285113661 
+
+1383 1.13680784857 0.51616206663 
+
+1384 1.12366917778 0.51616206663 
+
+1385 1.09238662829 0.521167274549 
+
+1386 1.11178180897 0.486756470107 
+
+1387 1.1411874055 0.477997356249 
+
+1388 1.16871604905 0.477371705259 
+
+1389 1.19561904161 0.486130819117 
+
+1390 1.1899881827 0.445463504777 
+
+1391 1.16496214311 0.451094363685 
+
+1392 1.1349308956 0.449217410716 
+
+1393 1.12116657382 0.417934861223 
+
+1394 1.17059300202 0.404170539446 
+
+1395 1.15370042529 0.399165331527 
+
+1396 1.14869521737 0.367882782035 
+
+1397 1.12492047976 0.384149707771 
+
+1398 1.10177139313 0.392908821629 
+
+1399 1.09864313819 0.377893197872 
+
+1400 1.09488923225 0.355369762238 
+
+1401 1.09238662829 0.332846326603 
+
+1402 1.08675576938 0.306568985029 
+
+1403 1.11053050699 0.305317683049 
+
+1404 1.13743349956 0.3021894281 
+
+1405 1.1655877941 0.304692032059 
+
+1406 1.18748557874 0.315328098887 
+
+1407 1.16058258618 0.355995413227 
+
+1408 1.14181305649 0.331595024623 
+
+1409 1.11991527184 0.333471977593 
+
+1410 1.01480590554 0.374764942923 
+
+1411 1.00792374466 0.359123668177 
+
+1412 1.00980069763 0.335974581552 
+
+1413 1.01292895258 0.321584608785 
+
+1414 1.01105199961 0.30281507909 
+
+1415 1.0116776506 0.275286435536 
+
+1416 1.03983194514 0.272783831577 
+
+1417 1.06423233374 0.272783831577 
+
+1418 1.04045759613 0.313451145917 
+
+1419 1.06110407879 0.310322890968 
+
+1420 1.20437815547 0.364754527085 
+
+1421 1.21188596735 0.406673143406 
+
+1422 1.21876812824 0.469238242391 
+
+1423 1.16683909608 0.579978467596 
+
+1424 1.14994651935 0.608758413129 
+
+1425 1.12554613075 0.616266225007 
+
+1426 1.09426358126 0.620645781936 
+
+1427 1.06736058869 0.627527942825 
+
+1428 1.04671410603 0.630030546784 
+
+1429 1.02606762336 0.626276640845 
+
+1430 1.00354418773 0.618768828967 
+
+1431 0.980395101103 0.618143177977 
+
+1432 0.977892497143 0.581855420565 
+
+1433 1.01918546247 0.595619742342 
+
+1434 1.04608845504 0.60187625224 
+
+1435 1.04921670999 0.579352816606 
+
+1436 1.1161613659 0.588111930464 
+
+1437 1.16746474707 0.596245393332 
+
+1438 1.20312685349 0.600624950261 
+
+1439 1.2150142223 0.573721957697 
+
+1440 1.19999859854 0.524921180488 
+
+1441 1.22627594012 0.437955692898 
+
+1442 1.12992568768 0.47361779932 
+
+1443 1.11866396986 0.451720014675 
+
+1444 1.04608845504 0.670697861124 
+
+1445 1.02419067039 0.664441351226 
+
+1446 0.994785073869 0.681959578942 
+
+1447 0.969759034275 0.663815700236 
+
+1448 0.935348229833 0.633784452723 
+
+1449 0.911573492219 0.610635366098 
+
+1450 0.895306566482 0.6043788562 
+
+1451 0.897183519452 0.579352816606 
+
+1452 0.902814378361 0.552449824042 
+
+1453 0.827736259578 0.611261017088 
+
+1454 0.877788338766 0.64567182153 
+
+1455 0.903440029351 0.665067002216 
+
+1456 0.900311774401 0.685087833891 
+
+1457 0.920958257066 0.730760356151 
+
+1458 0.859018809071 0.753283791785 
+
+1459 0.912824794198 0.771427670491 
+
+1460 0.884670499655 0.748278583867 
+
+1461 0.798956314045 0.736391215059 
+
+1462 0.816474541761 0.752658140795 
+
+1463 0.77580722742 0.589988883433 
+
+1464 0.792074153156 0.586860628484 
+
+1465 0.803335870974 0.563711541859 
+
+1466 0.767673764552 0.529926388407 
+
+1467 0.750781187826 0.307194636019 
+
+1468 0.751406838816 0.291553361272 
+
+1469 0.767673764552 0.289676408303 
+
+1470 0.773930274451 0.30093812612 
+
+1471 0.768299415542 0.314076796907 
+
+1472 0.755160744755 0.312199843938 
+
+1473 0.753909442775 0.329092420664 
+
+1474 0.765796811582 0.328466769674 
+
+1475 0.77580722742 0.324712863735 
+
+1476 0.778935482369 0.354744111248 
+
+1477 0.765796811582 0.349738903329 
+
+1478 0.753283791785 0.366631480055 
+
+1479 0.767048113562 0.373513640943 
+
+1480 0.773930274451 0.38665231173 
+
+1481 0.760165952674 0.395411425588 
+
+1482 0.748278583867 0.38915491569 
+
+1483 0.660061794297 0.369134084014 
+
+1484 0.700729108638 0.148904935585 
+
+1485 0.69009304181 0.17142837122 
+
+1486 0.68821608884 0.191449202896 
+
+1487 0.653805284398 0.176433579139 
+
+1488 0.641917915591 0.153910143504 
+
+1489 0.658184841327 0.140145821728 
+
+1490 0.629404895794 0.262147764749 
+
+1491 0.638164009652 0.25839385881 
+
+1492 0.687590437851 0.218352195459 
+
+1493 0.703857363587 0.232116517236 
+
+1494 0.716370383384 0.241501282084 
+
+1495 0.737016866049 0.240249980104 
+
+1496 0.711365175465 0.248383442972 
+
+1497 0.713867779424 0.266527321678 
+
+1498 0.758288999704 0.252137348912 
+
+1499 0.77768418039 0.250260395942 
+
+1500 0.783315039298 0.26089646277 
+
+1501 0.591240185413 0.348487601349 
+
+1502 0.577475863636 0.347236299369 
+
+1503 0.575598910667 0.331595024623 
+
+1504 0.573096306707 0.311574192948 
+
+1505 0.576224561656 0.297184220181 
+
+1506 0.563711541859 0.284671200384 
+
+1507 0.508654254752 0.183941391017 
+
+1508 0.567465447798 0.17142837122 
+
+1509 0.582481071555 0.153284492514 
+
+1510 0.488633423077 0.284045549394 
+
+1511 0.636287056682 0.205213524672 
+
+1512 0.635661405693 0.187695296956 
+
+1513 0.73513991308 0.158289700433 
+
+1514 0.761417254653 0.223983054368 
+
+1515 0.797705012065 0.237121725155 
+
+1516 0.810218031862 0.228988262287 
+
+1517 0.68821608884 0.350990205309 
+
+1518 0.676328720033 0.332846326603 
+
+1519 0.665692653206 0.316579400867 
+
+1520 0.637538358662 0.296558569191 
+
+39 # <segment #> <vertex #>  <vertex #> [boundary marker] ...Mesh Segments...
+
+0 3 2 0
+
+1 4 5 0
+
+2 3 4 0
+
+3 7 6 0
+
+4 8 7 0
+
+5 9 8 0
+
+6 10 5 0
+
+7 0 10 0
+
+8 14 13 0
+
+9 11 14 0
+
+10 12 11 0
+
+11 16 15 0
+
+12 1 16 0
+
+13 20 6 0
+
+14 17 20 0
+
+15 18 17 0
+
+16 19 18 0
+
+17 22 21 0
+
+18 21 15 0
+
+19 23 22 0
+
+20 24 23 0
+
+21 19 24 0
+
+22 26 25 0
+
+23 28 27 0
+
+24 29 28 0
+
+25 2 29 0
+
+26 12 26 left
+
+27 30 25 0
+
+28 31 30 0
+
+29 32 31 0
+
+30 33 32 0
+
+31 0 33 0
+
+32 34 13 0
+
+33 35 34 0
+
+34 36 35 0
+
+35 9 36 0
+
+36 37 1 0
+
+37 38 37 0
+
+38 27 38 0
+
+0 # <Hole #> <x> <y> ...Mesh Holes...
+
+0 # <Region #> <x> <y> <attribute>...Mesh Regions...
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/wind_example_scalar.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/wind_example_scalar.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/wind_example_scalar.py	(revision 3560)
@@ -0,0 +1,41 @@
+"""Example of shallow water wave equation.
+
+Flat bed with constant wind stress
+"""
+
+######################
+# Module imports 
+from mesh_factory import rectangular
+from shallow_water import Domain, Reflective_boundary, Constant_height, Wind_stress
+
+#Create basic mesh (100m x 100m)
+N = 100     
+len = 100
+points, vertices, boundary = rectangular(N, N, len, len)
+
+#Create shallow water domain
+domain = Domain(points, vertices, boundary)
+domain.default_order = 2
+domain.store = True
+domain.set_name('wind_laminar')
+
+#Set initial conditions
+domain.set_quantity('elevation', 0.0)
+domain.set_quantity('stage', 1.0)
+domain.set_quantity('friction', 0.03)
+
+#Constant (quite extreme :-) windfield: 9000 m/s, bearing 120 degrees
+domain.forcing_terms.append( Wind_stress(s=9000, phi=120) )
+
+######################
+# Boundary conditions
+Br = Reflective_boundary(domain)
+domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br})
+
+######################
+#Evolution
+for t in domain.evolve(yieldstep = 0.5, finaltime = 1000):
+    domain.write_time()
+
+print 'Done'    
+
Index: /anuga_core/source/anuga/abstract_2d_finite_volumes/wind_example_variable.py
===================================================================
--- /anuga_core/source/anuga/abstract_2d_finite_volumes/wind_example_variable.py	(revision 3560)
+++ /anuga_core/source/anuga/abstract_2d_finite_volumes/wind_example_variable.py	(revision 3560)
@@ -0,0 +1,106 @@
+"""Example of shallow water wave equation.
+
+Flat bed with rotational wind stress
+
+"""
+
+######################
+# Module imports 
+#
+from mesh_factory import rectangular
+from shallow_water import Domain, Dirichlet_boundary, Wind_stress
+
+#Create basic mesh
+N = 20
+length = 200
+points, vertices, boundary = rectangular(N, N, length, length)
+
+#Create shallow water domain
+domain = Domain(points, vertices, boundary)
+domain.smooth = True
+domain.visualise = False
+domain.store = True
+domain.default_order=2
+domain.set_name('wind_rotation')
+
+#Set initial conditions
+h = 1.0
+domain.set_quantity('elevation', 0.0)
+domain.set_quantity('stage', h)
+domain.set_quantity('friction', 0.01)
+
+
+#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 pi
+    from Numeric import sqrt, exp, cos
+
+    c = (length/2, length/2)
+    r = sqrt((x - c[0])**2 + (y - c[1])**2)/length
+    factor = exp( -(r-0.15)**2 )
+
+    #return 9000 * factor
+    return 4000 * factor * (cos(t*2*pi/150) + 2)
+
+
+def phi(t,x,y):
+    """Rotating field
+    """
+    
+    from math import pi
+    from Numeric import sqrt, exp, cos, arctan2, choose, less
+
+    c = (length/2, length/2)
+    xx = (x - c[0])/length
+    yy = (y - c[1])/length
+    angle = arctan2(yy,xx)
+
+    #Take normal direction (but reverse direction every 50 seconds)
+    #if sin(t*2*pi/100) < 0:
+    #    sgn = -1
+    #else:
+    #    sgn = 1
+    #angle += sgn*pi/2
+    angle -= pi/2    
+
+    #Convert to degrees and return
+    return angle/pi*180
+
+    
+domain.forcing_terms.append( Wind_stress(speed, phi) )
+
+
+#Add lateral wind gusts bearing 25 deg
+def gust(t,x,y): 
+    from math import sin, pi
+    from Numeric import zeros, ones, Float
+
+    N = len(x)
+
+    tt = sin(2*pi*t/200)
+
+    if tt > 0.9:
+        return 6000*tt*ones(N, Float)
+    else:
+        return zeros(N, Float)
+    
+domain.forcing_terms.append(Wind_stress(gust, 25))
+
+
+######################
+# Boundary conditions
+#Br = Reflective_boundary(domain)
+Bd = Dirichlet_boundary([h, 0, 0])
+domain.set_boundary({'left': Bd, 'right': Bd, 'top': Bd, 'bottom': Bd})
+
+######################
+#Evolution
+for t in domain.evolve(yieldstep = 0.5, finaltime = 1000):
+    domain.write_time()
+
+print 'Done'    
+
Index: /anuga_core/source/anuga/compile_all.py
===================================================================
--- /anuga_core/source/anuga/compile_all.py	(revision 3559)
+++ /anuga_core/source/anuga/compile_all.py	(revision 3560)
@@ -9,5 +9,5 @@
 
 os.chdir('..')
-os.chdir('pyvolution')
+os.chdir('abstract_2d_finite_volumes')
 execfile('..' + os.sep + 'utilities' + os.sep + 'compile.py')
 
Index: /anuga_core/source/anuga/damage/inundation_damage.py
===================================================================
--- /anuga_core/source/anuga/damage/inundation_damage.py	(revision 3559)
+++ /anuga_core/source/anuga/damage/inundation_damage.py	(revision 3560)
@@ -28,6 +28,6 @@
 
 from anuga.utilities.numerical_tools import ensure_numeric
-from anuga.pyvolution.data_manager import Exposure_csv
-from anuga.pyvolution.util import file_function
+from anuga.abstract_2d_finite_volumes.data_manager import Exposure_csv
+from anuga.abstract_2d_finite_volumes.util import file_function
 from anuga.geospatial_data.geospatial_data import ensure_absolute
 from anuga.utilities.numerical_tools import NAN
Index: /anuga_core/source/anuga/damage/test_inundation_damage.py
===================================================================
--- /anuga_core/source/anuga/damage/test_inundation_damage.py	(revision 3559)
+++ /anuga_core/source/anuga/damage/test_inundation_damage.py	(revision 3560)
@@ -13,7 +13,7 @@
 from anuga.pmesh.mesh import Mesh
 from anuga.coordinate_transforms.geo_reference import Geo_reference
-from anuga.pyvolution.shallow_water import Domain, Transmissive_boundary
+from anuga.abstract_2d_finite_volumes.shallow_water import Domain, Transmissive_boundary
 from anuga.utilities.numerical_tools import mean
-from anuga.pyvolution.data_manager import get_dataobject
+from anuga.abstract_2d_finite_volumes.data_manager import get_dataobject
 
 from Numeric import zeros, Float, allclose
Index: /anuga_core/source/anuga/examples/advection_dirichlet.py
===================================================================
--- /anuga_core/source/anuga/examples/advection_dirichlet.py	(revision 3559)
+++ /anuga_core/source/anuga/examples/advection_dirichlet.py	(revision 3560)
@@ -6,5 +6,5 @@
 import sys
 from os import sep
-sys.path.append('..'+sep+'pyvolution')
+sys.path.append('..'+sep+'abstract_2d_finite_volumes')
 
 from mesh_factory import rectangular
Index: /anuga_core/source/anuga/examples/advection_waves.py
===================================================================
--- /anuga_core/source/anuga/examples/advection_waves.py	(revision 3559)
+++ /anuga_core/source/anuga/examples/advection_waves.py	(revision 3560)
@@ -7,5 +7,5 @@
 import sys
 from os import sep
-sys.path.append('..'+sep+'pyvolution')
+sys.path.append('..'+sep+'abstract_2d_finite_volumes')
 
 from mesh_factory import rectangular
Index: /anuga_core/source/anuga/examples/bedslope.py
===================================================================
--- /anuga_core/source/anuga/examples/bedslope.py	(revision 3559)
+++ /anuga_core/source/anuga/examples/bedslope.py	(revision 3560)
@@ -1,3 +1,3 @@
-"""Simple example of shallow water wave equation using Pyvolution
+"""Simple example of shallow water wave equation using Abstract_2d_finite_volumes
 
 Water driven up a linear slope with a time varying boundary,
@@ -8,6 +8,6 @@
 ######################
 # Module imports 
-from anuga.pyvolution.mesh_factory import rectangular
-from anuga.pyvolution.shallow_water import Domain, Reflective_boundary,\
+from anuga.abstract_2d_finite_volumes.mesh_factory import rectangular
+from anuga.abstract_2d_finite_volumes.shallow_water import Domain, Reflective_boundary,\
      Dirichlet_boundary, Time_boundary, Transmissive_boundary
 
Index: /anuga_core/source/anuga/examples/island.py
===================================================================
--- /anuga_core/source/anuga/examples/island.py	(revision 3559)
+++ /anuga_core/source/anuga/examples/island.py	(revision 3560)
@@ -15,10 +15,10 @@
 
 # Application specific imports
-from anuga.pyvolution.mesh_factory import rectangular
-from anuga.pyvolution.shallow_water import Domain, Reflective_boundary, Dirichlet_boundary
+from anuga.abstract_2d_finite_volumes.mesh_factory import rectangular
+from anuga.abstract_2d_finite_volumes.shallow_water import Domain, Reflective_boundary, Dirichlet_boundary
 from anuga.pmesh.mesh_interface import create_mesh_from_regions
 from anuga.utilities.polygon import Polygon_function, read_polygon
 
-from anuga.pyvolution.quantity import Quantity
+from anuga.abstract_2d_finite_volumes.quantity import Quantity
 from Numeric import allclose
 
Index: /anuga_core/source/anuga/examples/runup.py
===================================================================
--- /anuga_core/source/anuga/examples/runup.py	(revision 3559)
+++ /anuga_core/source/anuga/examples/runup.py	(revision 3560)
@@ -10,10 +10,10 @@
 #------------------------------------------------------------------------------
 
-from anuga.pyvolution.mesh_factory import rectangular_cross
-from anuga.pyvolution.shallow_water import Domain
-from anuga.pyvolution.shallow_water import Reflective_boundary
-from anuga.pyvolution.shallow_water import Dirichlet_boundary
-from anuga.pyvolution.shallow_water import Time_boundary
-from anuga.pyvolution.shallow_water import Transmissive_boundary
+from anuga.abstract_2d_finite_volumes.mesh_factory import rectangular_cross
+from anuga.abstract_2d_finite_volumes.shallow_water import Domain
+from anuga.abstract_2d_finite_volumes.shallow_water import Reflective_boundary
+from anuga.abstract_2d_finite_volumes.shallow_water import Dirichlet_boundary
+from anuga.abstract_2d_finite_volumes.shallow_water import Time_boundary
+from anuga.abstract_2d_finite_volumes.shallow_water import Transmissive_boundary
 
 
Index: /anuga_core/source/anuga/examples/runup_convergence.py
===================================================================
--- /anuga_core/source/anuga/examples/runup_convergence.py	(revision 3559)
+++ /anuga_core/source/anuga/examples/runup_convergence.py	(revision 3560)
@@ -15,11 +15,11 @@
 
 from anuga.pmesh.mesh_interface import create_mesh_from_regions
-from pyvolution.mesh_factory import rectangular_cross
-from pyvolution.shallow_water import Domain
-from pyvolution.shallow_water import Reflective_boundary
-from pyvolution.shallow_water import Dirichlet_boundary
-from pyvolution.shallow_water import Time_boundary
-from pyvolution.shallow_water import Transmissive_Momentum_Set_Stage_boundary
-from pyvolution.util import file_function
+from abstract_2d_finite_volumes.mesh_factory import rectangular_cross
+from abstract_2d_finite_volumes.shallow_water import Domain
+from abstract_2d_finite_volumes.shallow_water import Reflective_boundary
+from abstract_2d_finite_volumes.shallow_water import Dirichlet_boundary
+from abstract_2d_finite_volumes.shallow_water import Time_boundary
+from abstract_2d_finite_volumes.shallow_water import Transmissive_Momentum_Set_Stage_boundary
+from abstract_2d_finite_volumes.util import file_function
 from pylab import plot, xlabel, ylabel, title, ion, close, savefig, figure, axis, legend, grid, hold
 
Index: /anuga_core/source/anuga/fit_interpolate/general_fit_interpolate.py
===================================================================
--- /anuga_core/source/anuga/fit_interpolate/general_fit_interpolate.py	(revision 3559)
+++ /anuga_core/source/anuga/fit_interpolate/general_fit_interpolate.py	(revision 3560)
@@ -25,9 +25,9 @@
 
 from anuga.caching.caching import cache
-from anuga.pyvolution.neighbour_mesh import Mesh
+from anuga.abstract_2d_finite_volumes.neighbour_mesh import Mesh
 from anuga.utilities.sparse import Sparse, Sparse_CSR
 from anuga.utilities.cg_solve import conjugate_gradient, VectorShapeError
 from anuga.coordinate_transforms.geo_reference import Geo_reference
-from anuga.pyvolution.quad import build_quadtree
+from anuga.abstract_2d_finite_volumes.quad import build_quadtree
 from anuga.utilities.numerical_tools import ensure_numeric
 from anuga.utilities.polygon import in_and_outside_polygon
Index: /anuga_core/source/anuga/fit_interpolate/interpolate.py
===================================================================
--- /anuga_core/source/anuga/fit_interpolate/interpolate.py	(revision 3559)
+++ /anuga_core/source/anuga/fit_interpolate/interpolate.py	(revision 3560)
@@ -28,9 +28,9 @@
 
 from anuga.caching.caching import cache
-from anuga.pyvolution.neighbour_mesh import Mesh
+from anuga.abstract_2d_finite_volumes.neighbour_mesh import Mesh
 from anuga.utilities.sparse import Sparse, Sparse_CSR
 from anuga.utilities.cg_solve import conjugate_gradient, VectorShapeError
 from anuga.coordinate_transforms.geo_reference import Geo_reference
-from anuga.pyvolution.quad import build_quadtree
+from anuga.abstract_2d_finite_volumes.quad import build_quadtree
 from anuga.utilities.numerical_tools import ensure_numeric, mean, NAN
 from anuga.utilities.polygon import in_and_outside_polygon
@@ -38,5 +38,5 @@
 from anuga.fit_interpolate.search_functions import search_tree_of_vertices
 from anuga.fit_interpolate.general_fit_interpolate import FitInterpolate
-from anuga.pyvolution.util import file_function
+from anuga.abstract_2d_finite_volumes.util import file_function
 
 
@@ -406,5 +406,5 @@
 
 
-        #from anuga.pyvolution.util import mean, ensure_numeric
+        #from anuga.abstract_2d_finite_volumes.util import mean, ensure_numeric
         from anuga.config import time_format
         import types
@@ -549,5 +549,5 @@
         from math import pi, cos, sin, sqrt
         from Numeric import zeros, Float
-        from anuga.pyvolution.util import mean        
+        from anuga.abstract_2d_finite_volumes.util import mean        
 
         if self.spatial is True:
Index: /anuga_core/source/anuga/fit_interpolate/test_fit.py
===================================================================
--- /anuga_core/source/anuga/fit_interpolate/test_fit.py	(revision 3559)
+++ /anuga_core/source/anuga/fit_interpolate/test_fit.py	(revision 3560)
@@ -10,5 +10,5 @@
 
 from fit import *
-from anuga.pyvolution.neighbour_mesh import Mesh
+from anuga.abstract_2d_finite_volumes.neighbour_mesh import Mesh
 from anuga.utilities.sparse import Sparse, Sparse_CSR
 from anuga.coordinate_transforms.geo_reference import Geo_reference
Index: /anuga_core/source/anuga/fit_interpolate/test_interpolate.py
===================================================================
--- /anuga_core/source/anuga/fit_interpolate/test_interpolate.py	(revision 3559)
+++ /anuga_core/source/anuga/fit_interpolate/test_interpolate.py	(revision 3560)
@@ -22,5 +22,5 @@
 from shallow_water import Domain, Transmissive_boundary
 from anuga.utilities.numerical_tools import mean, NAN
-from anuga.pyvolution.data_manager import get_dataobject
+from anuga.abstract_2d_finite_volumes.data_manager import get_dataobject
 from anuga.geospatial_data.geospatial_data import Geospatial_data
 from anuga.pmesh.mesh import Mesh
Index: /anuga_core/source/anuga/utilities/compile.py
===================================================================
--- /anuga_core/source/anuga/utilities/compile.py	(revision 3559)
+++ /anuga_core/source/anuga/utilities/compile.py	(revision 3560)
@@ -193,6 +193,13 @@
   # This is hacky since it
   # assumes the location of the compile_all that determines buildroot
-  utilities_include_dir = buildroot + os.sep + "source" + os.sep + "anuga" \
-                          + os.sep + 'utilities'  
+  try:
+    utilities_include_dir = buildroot + os.sep + "source" + os.sep + "anuga" \
+                            + os.sep + 'utilities'
+  except:
+    # This will make compile work locally
+    utilities_include_dir = '.'
+
+
+    
   try:
     os.stat(utilities_include_dir)
@@ -295,5 +302,5 @@
             print '------- Trying to compile c-extension %s' %filename
 
-            #compile(filename)        
+            compile(filename)        
             try:
                 compile(filename)
@@ -357,4 +364,5 @@
                 %(filename, os.getcwd())
 
+          compile(filename)          
           try:
               compile(filename)
Index: /development/okushiri_2005/lwru2.py
===================================================================
--- /development/okushiri_2005/lwru2.py	(revision 3559)
+++ /development/okushiri_2005/lwru2.py	(revision 3560)
@@ -76,8 +76,8 @@
 
 # Module imports
-from anuga.pyvolution.shallow_water import Domain, Reflective_boundary,\
+from anuga.abstract_2d_finite_volumes.shallow_water import Domain, Reflective_boundary,\
      File_boundary, Transmissive_Momentum_Set_Stage_boundary
-from anuga.pyvolution.mesh_factory import rectangular_cross
-from anuga.pyvolution.pmesh2domain import pmesh_to_domain_instance
+from anuga.abstract_2d_finite_volumes.mesh_factory import rectangular_cross
+from anuga.abstract_2d_finite_volumes.pmesh2domain import pmesh_to_domain_instance
 from Numeric import array, zeros, Float, allclose
 import project
@@ -88,5 +88,5 @@
 
 #Preparing points (Only when using original Benchmark_2_Bathymetry.txt file)
-#from anuga.pyvolution.data_manager import xya2pts
+#from anuga.abstract_2d_finite_volumes.data_manager import xya2pts
 #xya2pts(project.bathymetry_filename, verbose = True,
 #        z_func = lambda z: -z)
@@ -148,5 +148,5 @@
 Br = Reflective_boundary(domain)
 
-from anuga.pyvolution.util import file_function
+from anuga.abstract_2d_finite_volumes.util import file_function
 function = file_function(project.boundary_filename[:-4] + '.tms',
                          domain,
