source: anuga_work/development/anuga_1d/test_shallow_water.py @ 5738

Last change on this file since 5738 was 5738, checked in by steve, 16 years ago

Copied evolve code from anuga_2d

File size: 13.3 KB
Line 
1#!/usr/bin/env python
2
3import unittest
4from math import sqrt, pi
5
6
7from shallow_water_domain import *
8from shallow_water_domain import flux_function as domain_flux_function
9
10from Numeric import allclose, array, ones, Float, maximum, zeros
11
12
13class Test_Shallow_Water(unittest.TestCase):
14    def setUp(self):
15        self.points = [0.0, 1.0, 2.0, 3.0]
16        self.vertex_values = [[1.0,2.0],[4.0,5.0],[-1.0,2.0]]
17        self.points2 = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
18       
19    def tearDown(self):
20        pass
21        #print "  Tearing down"
22
23
24    def test_creation(self):
25        domain = Domain(self.points)
26        assert allclose(domain.centroids, [0.5, 1.5, 2.5])
27
28    def test_compute_fluxes(self):
29        """
30        Compare shallow_water_domain flux calculation against a previous
31        Python implementation (defined in this file)
32        """
33        domain = Domain(self.points)
34        domain.set_quantity('stage',2.0)
35        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
36
37        stage_ud, xmom_ud = local_compute_fluxes(domain)
38       
39        domain.compute_fluxes()
40
41        #print domain.quantities['stage'].explicit_update
42        #print domain.quantities['xmomentum'].explicit_update
43        #print stage_ud
44
45        assert allclose( domain.quantities['stage'].explicit_update, stage_ud )
46        assert allclose( domain.quantities['xmomentum'].explicit_update, xmom_ud )
47
48
49    def test_local_flux_function(self):
50        normal = 1.0
51        ql = array([1.0, 2.0],Float)
52        qr = array([1.0, 2.0],Float)
53        zl = 0.0
54        zr = 0.0
55
56        #This assumes h0 = 1.0e-3!!
57        edgeflux, maxspeed = local_flux_function(normal, ql,qr,zl,zr)
58        #print maxspeed
59        #print edgeflux
60       
61        assert allclose(array([2.0, 8.9],Float), edgeflux, rtol=1.0e-005)
62        assert allclose(5.1305, maxspeed, rtol=1.0e-005)
63
64        normal = -1.0
65        ql = array([1.0, 2.0],Float)
66        qr = array([1.0, 2.0],Float)
67        zl = 0.0
68        zr = 0.0
69
70        edgeflux, maxspeed = local_flux_function(normal, ql,qr,zl,zr)
71
72
73        #print maxspeed
74        #print edgeflux       
75       
76        assert allclose(array([-2.0, -8.9],Float), edgeflux, rtol=1.0e-005)
77        assert allclose(5.1305, maxspeed, rtol=1.0e-005)
78
79    def test_domain_flux_function(self):
80        normal = 1.0
81        ql = array([1.0, 2.0],Float)
82        qr = array([1.0, 2.0],Float)
83        zl = 0.0
84        zr = 0.0
85
86        edgeflux, maxspeed = local_flux_function(normal, ql,qr,zl,zr)
87
88        #print edgeflux
89
90
91
92        domainedgeflux, domainmaxspeed = domain_flux_function(normal, ql,qr,zl,zr)
93
94        #print domainedgeflux
95
96        assert allclose(domainedgeflux, edgeflux)
97        assert allclose(domainmaxspeed, maxspeed)
98
99    def test_gravity(self):
100        """
101        Compare shallow_water_domain gravity calculation
102        """
103               
104        def slope_one(x):
105            return x
106                       
107        domain = Domain(self.points)
108        domain.set_quantity('stage',4.0)
109        domain.set_quantity('elevation',slope_one)
110        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
111
112        gravity(domain)
113       
114        #print domain.quantities['stage'].vertex_values
115        #print domain.quantities['elevation'].vertex_values
116        #print domain.quantities['xmomentum'].explicit_update       
117
118        assert allclose( array([-34.3, -24.5, -14.7], Float), domain.quantities['xmomentum'].explicit_update )
119
120
121    def test_evolve_first_order(self):
122        """
123        Compare still lake solution for various versions of shallow_water_domain
124        """
125               
126        def slope_square(x):
127            return maximum(4.0-(x-5.0)*(x-5.0), 0.0)
128                       
129        domain = Domain(self.points2)
130        domain.set_quantity('stage',10.0)
131        domain.set_quantity('elevation',slope_square)
132        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
133
134        domain.default_order = 1
135        domain.default_time_order = 1
136        yieldstep=1.0
137        finaltime=1.0
138
139        for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
140            pass
141       
142##      print domain.quantities['stage'].vertex_values
143##      print domain.quantities['elevation'].vertex_values
144##        print domain.quantities['xmomentum'].vertex_values
145##
146##
147##        print domain.quantities['stage'].centroid_values
148##      print domain.quantities['elevation'].centroid_values
149##        print domain.quantities['xmomentum'].centroid_values   
150
151        assert allclose( 10.0*ones(10), domain.quantities['stage'].centroid_values )
152        assert allclose( zeros(10), domain.quantities['xmomentum'].centroid_values )
153
154
155    def test_evolve_euler_second_order_space(self):
156        """
157        Compare still lake solution for various versions of shallow_water_domain
158        """
159               
160        def slope_square(x):
161            return maximum(4.0-(x-5.0)*(x-5.0), 0.0)
162                       
163        domain = Domain(self.points2)
164        domain.set_quantity('stage',10.0)
165        domain.set_quantity('elevation',slope_square)
166        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
167
168        domain.default_order = 2
169        domain.default_time_order = 1
170        yieldstep=1.0
171        finaltime=1.0
172
173        for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
174            pass
175       
176        assert allclose( 10.0*ones(10), domain.quantities['stage'].centroid_values )
177        assert allclose( zeros(10), domain.quantities['xmomentum'].centroid_values )
178
179    def test_evolve_second_order_space_time(self):
180        """
181        Compare still lake solution for various versions of shallow_water_domain
182        """
183               
184        def slope_square(x):
185            return maximum(4.0-(x-5.0)*(x-5.0), 0.0)
186                       
187        domain = Domain(self.points2)
188        domain.set_quantity('stage',10.0)
189        domain.set_quantity('elevation',slope_square)
190        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
191
192        domain.default_order = 2
193        domain.default_time_order = 2
194        yieldstep=1.0
195        finaltime=1.0
196
197        for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
198            pass
199       
200        assert allclose( 10.0*ones(10), domain.quantities['stage'].centroid_values )
201        assert allclose( zeros(10), domain.quantities['xmomentum'].centroid_values )
202
203
204
205#==============================================================================
206
207def local_compute_fluxes(domain):
208    """Compute all fluxes and the timestep suitable for all volumes
209    in domain.
210
211    Compute total flux for each conserved quantity using "flux_function"
212
213    Fluxes across each edge are scaled by edgelengths and summed up
214    Resulting flux is then scaled by area and stored in
215    explicit_update for each of the three conserved quantities
216    stage, xmomentum and ymomentum
217
218    The maximal allowable speed computed by the flux_function for each volume
219    is converted to a timestep that must not be exceeded. The minimum of
220    those is computed as the next overall timestep.
221
222    Post conditions:
223      domain.explicit_update is reset to computed flux values
224      domain.timestep is set to the largest step satisfying all volumes.
225    """
226
227    import sys
228    from Numeric import zeros, Float
229
230    N = domain.number_of_elements
231
232    tmp0 = zeros(N,Float)
233    tmp1 = zeros(N,Float)
234
235    #Shortcuts
236    Stage = domain.quantities['stage']
237    Xmom = domain.quantities['xmomentum']
238#    Ymom = domain.quantities['ymomentum']
239    Bed = domain.quantities['elevation']
240
241    #Arrays
242    #stage = Stage.edge_values
243    #xmom =  Xmom.edge_values
244 #   ymom =  Ymom.edge_values
245    #bed =   Bed.edge_values
246   
247    stage = Stage.vertex_values
248    xmom =  Xmom.vertex_values
249    bed =   Bed.vertex_values
250   
251    #print 'stage edge values', stage
252    #print 'xmom edge values', xmom
253    #print 'bed values', bed
254
255    stage_bdry = Stage.boundary_values
256    xmom_bdry =  Xmom.boundary_values
257    #print 'stage_bdry',stage_bdry
258    #print 'xmom_bdry', xmom_bdry
259#    ymom_bdry =  Ymom.boundary_values
260
261#    flux = zeros(3, Float) #Work array for summing up fluxes
262    flux = zeros(2, Float) #Work array for summing up fluxes
263    ql = zeros(2, Float)
264    qr = zeros(2, Float)
265
266    #Loop
267    timestep = float(sys.maxint)
268    enter = True
269    for k in range(N):
270
271        flux[:] = 0.  #Reset work array
272        #for i in range(3):
273        for i in range(2):
274            #Quantities inside volume facing neighbour i
275            #ql[0] = stage[k, i]
276            #ql[1] = xmom[k, i]
277            ql = [stage[k, i], xmom[k, i]]
278            zl = bed[k, i]
279
280            #Quantities at neighbour on nearest face
281            n = domain.neighbours[k,i]
282            if n < 0:
283                m = -n-1 #Convert negative flag to index
284                qr[0] = stage_bdry[m]
285                qr[1] = xmom_bdry[m]
286                zr = zl #Extend bed elevation to boundary
287            else:
288                #m = domain.neighbour_edges[k,i]
289                m = domain.neighbour_vertices[k,i]
290                #print i, ' ' , m
291                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
292                qr[0] = stage[n, m]
293                qr[1] = xmom[n, m]
294                zr = bed[n, m]
295
296
297            #Outward pointing normal vector
298            normal = domain.normals[k, i]
299       
300            #Flux computation using provided function
301            #edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
302            #print 'ql',ql
303            #print 'qr',qr
304           
305
306            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
307
308            #print 'edgeflux', edgeflux
309
310            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
311            # flux = edgefluxleft - edgefluxright
312            flux -= edgeflux #* domain.edgelengths[k,i]
313            #Update optimal_timestep
314            try:
315                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
316                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
317            except ZeroDivisionError:
318                pass
319
320        #Normalise by area and store for when all conserved
321        #quantities get updated
322        flux /= domain.areas[k]
323
324        #Stage.explicit_update[k] = flux[0]
325        tmp0[k] = flux[0]
326        tmp1[k] = flux[1]
327
328
329    return tmp0, tmp1
330
331
332def local_flux_function(normal, ql, qr, zl, zr):
333    """Compute fluxes between volumes for the shallow water wave equation
334    cast in terms of w = h+z using the 'central scheme' as described in
335
336    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
337    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
338    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
339
340    The implemented formula is given in equation (3.15) on page 714
341
342    Conserved quantities w, uh, are stored as elements 0 and 1
343    in the numerical vectors ql an qr.
344
345    Bed elevations zl and zr.
346    """
347
348    from config import g, epsilon, h0
349    from math import sqrt
350    from Numeric import array
351
352    #print 'ql',ql
353
354    #Align momentums with x-axis
355    #q_left  = rotate(ql, normal, direction = 1)
356    #q_right = rotate(qr, normal, direction = 1)
357    q_left = ql
358    q_left[1] = q_left[1]*normal
359    q_right = qr
360    q_right[1] = q_right[1]*normal
361
362    #z = (zl+zr)/2 #Take average of field values
363    z = 0.5*(zl+zr) #Take average of field values
364
365    w_left  = q_left[0]   #w=h+z
366    h_left  = w_left-z
367    uh_left = q_left[1]
368
369    if h_left < epsilon:
370        u_left = 0.0  #Could have been negative
371        h_left = 0.0
372    else:
373        u_left  = uh_left/(h_left +  h0/h_left)
374
375
376    uh_left = u_left*h_left
377
378    w_right  = q_right[0]  #w=h+z
379    h_right  = w_right-z
380    uh_right = q_right[1]
381
382
383    if h_right < epsilon:
384        u_right = 0.0  #Could have been negative
385        h_right = 0.0
386    else:
387        u_right  = uh_right/(h_right + h0/h_right)
388
389    uh_right = u_right*h_right
390   
391    #vh_left  = q_left[2]
392    #vh_right = q_right[2]
393
394    #print h_right
395    #print u_right
396    #print h_left
397    #print u_right
398
399    soundspeed_left  = sqrt(g*h_left)
400    soundspeed_right = sqrt(g*h_right)
401
402    #Maximal wave speed
403    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
404   
405    #Minimal wave speed
406    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
407   
408    #Flux computation
409
410    #flux_left  = array([u_left*h_left,
411    #                    u_left*uh_left + 0.5*g*h_left**2])
412    #flux_right = array([u_right*h_right,
413    #                    u_right*uh_right + 0.5*g*h_right**2])
414    flux_left  = array([u_left*h_left,
415                        u_left*uh_left + 0.5*g*h_left*h_left])
416    flux_right = array([u_right*h_right,
417                        u_right*uh_right + 0.5*g*h_right*h_right])
418
419    denom = s_max-s_min
420    if denom == 0.0:
421        edgeflux = array([0.0, 0.0])
422        max_speed = 0.0
423    else:
424        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
425        edgeflux += s_max*s_min*(q_right-q_left)/denom
426       
427        edgeflux[1] = edgeflux[1]*normal
428
429        max_speed = max(abs(s_max), abs(s_min))
430
431    return edgeflux, max_speed
432
433
434#-------------------------------------------------------------
435if __name__ == "__main__":
436    suite = unittest.makeSuite(Test_Shallow_Water, 'test')   
437    #suite = unittest.makeSuite(Test_Quantity, 'test_set_values_from_file_using_polygon')
438
439    #suite = unittest.makeSuite(Test_Quantity, 'test_set_vertex_values_using_general_interface_with_subset')
440    #print "restricted test"
441    #suite = unittest.makeSuite(Test_Quantity,'verbose_test_set_values_from_UTM_pts')
442    runner = unittest.TextTestRunner()
443    runner.run(suite)
Note: See TracBrowser for help on using the repository browser.