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

Last change on this file since 5741 was 5741, checked in by steve, 15 years ago

Updated timestepping

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_new import *
8from shallow_water_domain_new 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.set_timestepping_method('euler')
136       
137        yieldstep=1.0
138        finaltime=1.0
139
140        for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
141            pass
142       
143##      print domain.quantities['stage'].vertex_values
144##      print domain.quantities['elevation'].vertex_values
145##        print domain.quantities['xmomentum'].vertex_values
146##
147##
148##        print domain.quantities['stage'].centroid_values
149##      print domain.quantities['elevation'].centroid_values
150##        print domain.quantities['xmomentum'].centroid_values   
151
152        assert allclose( 10.0*ones(10), domain.quantities['stage'].centroid_values )
153        assert allclose( zeros(10), domain.quantities['xmomentum'].centroid_values )
154
155
156    def test_evolve_euler_second_order_space(self):
157        """
158        Compare still lake solution for various versions of shallow_water_domain
159        """
160               
161        def slope_square(x):
162            return maximum(4.0-(x-5.0)*(x-5.0), 0.0)
163                       
164        domain = Domain(self.points2)
165        domain.set_quantity('stage',10.0)
166        domain.set_quantity('elevation',slope_square)
167        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
168
169        domain.default_order = 2
170        domain.set_timestepping_method('rk2')
171        yieldstep=1.0
172        finaltime=1.0
173
174        for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
175            pass
176       
177        assert allclose( 10.0*ones(10), domain.quantities['stage'].centroid_values )
178        assert allclose( zeros(10), domain.quantities['xmomentum'].centroid_values )
179
180    def test_evolve_second_order_space_time(self):
181        """
182        Compare still lake solution for various versions of shallow_water_domain
183        """
184               
185        def slope_square(x):
186            return maximum(4.0-(x-5.0)*(x-5.0), 0.0)
187                       
188        domain = Domain(self.points2)
189        domain.set_quantity('stage',10.0)
190        domain.set_quantity('elevation',slope_square)
191        domain.set_boundary({'exterior' : Reflective_boundary(domain)})
192
193        domain.default_order = 2
194        domain.set_timestepping_method('rk3')
195
196        yieldstep=1.0
197        finaltime=1.0
198
199        for t in domain.evolve(yieldstep=yieldstep, finaltime=finaltime):
200            pass
201       
202        assert allclose( 10.0*ones(10), domain.quantities['stage'].centroid_values )
203        assert allclose( zeros(10), domain.quantities['xmomentum'].centroid_values )
204
205
206
207#==============================================================================
208
209def local_compute_fluxes(domain):
210    """Compute all fluxes and the timestep suitable for all volumes
211    in domain.
212
213    Compute total flux for each conserved quantity using "flux_function"
214
215    Fluxes across each edge are scaled by edgelengths and summed up
216    Resulting flux is then scaled by area and stored in
217    explicit_update for each of the three conserved quantities
218    stage, xmomentum and ymomentum
219
220    The maximal allowable speed computed by the flux_function for each volume
221    is converted to a timestep that must not be exceeded. The minimum of
222    those is computed as the next overall timestep.
223
224    Post conditions:
225      domain.explicit_update is reset to computed flux values
226      domain.timestep is set to the largest step satisfying all volumes.
227    """
228
229    import sys
230    from Numeric import zeros, Float
231
232    N = domain.number_of_elements
233
234    tmp0 = zeros(N,Float)
235    tmp1 = zeros(N,Float)
236
237    #Shortcuts
238    Stage = domain.quantities['stage']
239    Xmom = domain.quantities['xmomentum']
240#    Ymom = domain.quantities['ymomentum']
241    Bed = domain.quantities['elevation']
242
243    #Arrays
244    #stage = Stage.edge_values
245    #xmom =  Xmom.edge_values
246 #   ymom =  Ymom.edge_values
247    #bed =   Bed.edge_values
248   
249    stage = Stage.vertex_values
250    xmom =  Xmom.vertex_values
251    bed =   Bed.vertex_values
252   
253    #print 'stage edge values', stage
254    #print 'xmom edge values', xmom
255    #print 'bed values', bed
256
257    stage_bdry = Stage.boundary_values
258    xmom_bdry =  Xmom.boundary_values
259    #print 'stage_bdry',stage_bdry
260    #print 'xmom_bdry', xmom_bdry
261#    ymom_bdry =  Ymom.boundary_values
262
263#    flux = zeros(3, Float) #Work array for summing up fluxes
264    flux = zeros(2, Float) #Work array for summing up fluxes
265    ql = zeros(2, Float)
266    qr = zeros(2, Float)
267
268    #Loop
269    timestep = float(sys.maxint)
270    enter = True
271    for k in range(N):
272
273        flux[:] = 0.  #Reset work array
274        #for i in range(3):
275        for i in range(2):
276            #Quantities inside volume facing neighbour i
277            #ql[0] = stage[k, i]
278            #ql[1] = xmom[k, i]
279            ql = [stage[k, i], xmom[k, i]]
280            zl = bed[k, i]
281
282            #Quantities at neighbour on nearest face
283            n = domain.neighbours[k,i]
284            if n < 0:
285                m = -n-1 #Convert negative flag to index
286                qr[0] = stage_bdry[m]
287                qr[1] = xmom_bdry[m]
288                zr = zl #Extend bed elevation to boundary
289            else:
290                #m = domain.neighbour_edges[k,i]
291                m = domain.neighbour_vertices[k,i]
292                #print i, ' ' , m
293                #qr = [stage[n, m], xmom[n, m], ymom[n, m]]
294                qr[0] = stage[n, m]
295                qr[1] = xmom[n, m]
296                zr = bed[n, m]
297
298
299            #Outward pointing normal vector
300            normal = domain.normals[k, i]
301       
302            #Flux computation using provided function
303            #edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
304            #print 'ql',ql
305            #print 'qr',qr
306           
307
308            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
309
310            #print 'edgeflux', edgeflux
311
312            # THIS IS THE LINE TO DEAL WITH LEFT AND RIGHT FLUXES
313            # flux = edgefluxleft - edgefluxright
314            flux -= edgeflux #* domain.edgelengths[k,i]
315            #Update optimal_timestep
316            try:
317                #timestep = min(timestep, 0.5*domain.radii[k]/max_speed)
318                timestep = min(timestep, domain.cfl*0.5*domain.areas[k]/max_speed)
319            except ZeroDivisionError:
320                pass
321
322        #Normalise by area and store for when all conserved
323        #quantities get updated
324        flux /= domain.areas[k]
325
326        #Stage.explicit_update[k] = flux[0]
327        tmp0[k] = flux[0]
328        tmp1[k] = flux[1]
329
330
331    return tmp0, tmp1
332
333
334def local_flux_function(normal, ql, qr, zl, zr):
335    """Compute fluxes between volumes for the shallow water wave equation
336    cast in terms of w = h+z using the 'central scheme' as described in
337
338    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
339    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
340    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
341
342    The implemented formula is given in equation (3.15) on page 714
343
344    Conserved quantities w, uh, are stored as elements 0 and 1
345    in the numerical vectors ql an qr.
346
347    Bed elevations zl and zr.
348    """
349
350    from config import g, epsilon, h0
351    from math import sqrt
352    from Numeric import array
353
354    #print 'ql',ql
355
356    #Align momentums with x-axis
357    #q_left  = rotate(ql, normal, direction = 1)
358    #q_right = rotate(qr, normal, direction = 1)
359    q_left = ql
360    q_left[1] = q_left[1]*normal
361    q_right = qr
362    q_right[1] = q_right[1]*normal
363
364    #z = (zl+zr)/2 #Take average of field values
365    z = 0.5*(zl+zr) #Take average of field values
366
367    w_left  = q_left[0]   #w=h+z
368    h_left  = w_left-z
369    uh_left = q_left[1]
370
371    if h_left < epsilon:
372        u_left = 0.0  #Could have been negative
373        h_left = 0.0
374    else:
375        u_left  = uh_left/(h_left +  h0/h_left)
376
377
378    uh_left = u_left*h_left
379
380    w_right  = q_right[0]  #w=h+z
381    h_right  = w_right-z
382    uh_right = q_right[1]
383
384
385    if h_right < epsilon:
386        u_right = 0.0  #Could have been negative
387        h_right = 0.0
388    else:
389        u_right  = uh_right/(h_right + h0/h_right)
390
391    uh_right = u_right*h_right
392   
393    #vh_left  = q_left[2]
394    #vh_right = q_right[2]
395
396    #print h_right
397    #print u_right
398    #print h_left
399    #print u_right
400
401    soundspeed_left  = sqrt(g*h_left)
402    soundspeed_right = sqrt(g*h_right)
403
404    #Maximal wave speed
405    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
406   
407    #Minimal wave speed
408    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
409   
410    #Flux computation
411
412    #flux_left  = array([u_left*h_left,
413    #                    u_left*uh_left + 0.5*g*h_left**2])
414    #flux_right = array([u_right*h_right,
415    #                    u_right*uh_right + 0.5*g*h_right**2])
416    flux_left  = array([u_left*h_left,
417                        u_left*uh_left + 0.5*g*h_left*h_left])
418    flux_right = array([u_right*h_right,
419                        u_right*uh_right + 0.5*g*h_right*h_right])
420
421    denom = s_max-s_min
422    if denom == 0.0:
423        edgeflux = array([0.0, 0.0])
424        max_speed = 0.0
425    else:
426        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
427        edgeflux += s_max*s_min*(q_right-q_left)/denom
428       
429        edgeflux[1] = edgeflux[1]*normal
430
431        max_speed = max(abs(s_max), abs(s_min))
432
433    return edgeflux, max_speed
434
435
436#-------------------------------------------------------------
437if __name__ == "__main__":
438    suite = unittest.makeSuite(Test_Shallow_Water, 'test')   
439    #suite = unittest.makeSuite(Test_Quantity, 'test_set_values_from_file_using_polygon')
440
441    #suite = unittest.makeSuite(Test_Quantity, 'test_set_vertex_values_using_general_interface_with_subset')
442    #print "restricted test"
443    #suite = unittest.makeSuite(Test_Quantity,'verbose_test_set_values_from_UTM_pts')
444    runner = unittest.TextTestRunner()
445    runner.run(suite)
Note: See TracBrowser for help on using the repository browser.