source: trunk/anuga_work/development/2010-projects/anuga_1d/pipe/pipe_domain.py @ 8153

Last change on this file since 8153 was 8153, checked in by paul, 14 years ago

Added initial pipe code copied from channel code

File size: 14.4 KB
Line 
1"""Class Domain -
21D interval domains for finite-volume computations of the shallow water wave equation.
3
4This module contains a specialisation of class Generic_domain from module generic_domain.py consisting of methods specific to mixed rectangular Pipe/Channel flow using the Shallow Water Wave Equation.
5
6This particular modification of the Domain class implements the ability to
7vary the width of the 1D pipe that the water flows in. As a result the
8conserved variables are different than previous implementations and so are the
9equations. In particular, the conserved quantites generalise the open channel flow conserved quantities.
10
11U_t + E_x = S
12
13where
14
15U = [A, Q] = [b*h, u*b*h]
16E = [Q, Q^2/A + g*b*h^2/2]
17S represents source terms forcing the system
18(e.g. gravity, boundary_stree, friction, wind stress, ...)
19gravity = -g*b*h*z_x
20boundary_stress = 1/2*g*b_x*h^2
21
22and _t, _x, _y denote the derivative with respect to t, x and y respectiely.
23
24The quantities are
25
26symbol    variable name    explanation
27A         area             equivalent Wetted area = b*h
28Q         discharge        flux of water = u*b*h
29x         x                horizontal distance from origin [m]
30z         elevation        elevation of bottom of pipe [m]
31h         height           water height above z [m]
32w         stage            equivalent absolute water level, w = z+h [m]
33u                          speed in the x direction [m/s]
34uh        xmomentum        momentum in the x direction [m^2/s]
35b         width            width of pipe
36eta                        mannings friction coefficient [to appear]
37
38The conserved quantities are A, Q
39--------------------------------------------------------------------------
40For details see e.g.
41Christopher Zoppou and Stephen Roberts,
42Catastrophic Collapse of Water Supply Reservoirs in Urban Areas,
43Journal of Hydraulic Engineering, vol. 127, No. 7 July 1999
44
45Add paper details here
46
47John Jakeman, Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou,
48Padarn Wilson, Geoscience Australia, 2008
49"""
50
51
52from anuga_1d.base.generic_domain import *
53import numpy
54
55
56#Shallow water pipe domain
57class Domain(Generic_domain):
58
59    def __init__(self, coordinates, boundary = None, tagged_elements = None):
60
61        conserved_quantities = ['area', 'discharge']
62        evolved_quantities = ['area', 'discharge', 'elevation', 'height', 'velocity','width','stage']
63        other_quantities = ['friction']
64        Generic_domain.__init__(self,
65                                coordinates = coordinates,
66                                boundary = boundary,
67                                conserved_quantities = conserved_quantities,
68                                evolved_quantities = evolved_quantities,
69                                other_quantities = other_quantities,
70                                tagged_elements = tagged_elements)
71       
72        from anuga_1d.config import minimum_allowed_height, g, h0
73        self.minimum_allowed_height = minimum_allowed_height
74        self.g = g
75        self.h0 = h0
76        self.setstageflag = False
77        self.discontinousb = False
78
79
80        # forcing terms gravity and boundary stress are included in the flux calculation
81        #self.forcing_terms.append(gravity)
82        #self.forcing_terms.append(boundary_stress)
83        #self.forcing_terms.append(manning_friction)
84       
85
86       
87        #Stored output
88        self.store = True
89        self.format = 'sww'
90        self.smooth = True
91
92       
93        #Reduction operation for get_vertex_values
94        from anuga_1d.base.util import mean
95        self.reduction = mean
96        #self.reduction = min  #Looks better near steep slopes
97
98        self.set_quantities_to_be_stored(['area','discharge'])
99
100        self.__doc__ = 'channel_domain'
101
102        self.check_integrity()
103
104
105    def check_integrity(self):
106
107        #Check that we are solving the shallow water wave equation
108
109        msg = 'First conserved quantity must be "area"'
110        assert self.conserved_quantities[0] == 'area', msg
111        msg = 'Second conserved quantity must be "discharge"'
112        assert self.conserved_quantities[1] == 'discharge', msg
113
114        msg = 'First evolved quantity must be "area"'
115        assert self.evolved_quantities[0] == 'area', msg
116        msg = 'Second evolved quantity must be "discharge"'
117        assert self.evolved_quantities[1] == 'discharge', msg
118        msg = 'Third evolved quantity must be "elevation"'
119        assert self.evolved_quantities[2] == 'elevation', msg
120        msg = 'Fourth evolved quantity must be "height"'
121        assert self.evolved_quantities[3] == 'height', msg
122        msg = 'Fifth evolved quantity must be "velocity"'
123        assert self.evolved_quantities[4] == 'velocity', msg
124        msg = 'Sixth evolved quantity must be "width"'
125        assert self.evolved_quantities[5] == 'width', msg
126        msg = 'Seventh evolved quantity must be "stage"'
127        assert self.evolved_quantities[6] == 'stage', msg
128
129        Generic_domain.check_integrity(self)
130
131    def compute_fluxes(self):
132        #Call correct module function
133        #(either from this module or C-extension)
134        compute_fluxes_pipe(self)
135
136    def distribute_to_vertices_and_edges(self):
137        #Call correct module function
138        #(either from this module or C-extension)
139        distribute_to_vertices_and_edges_limit_a_d(self)
140       
141
142#=============== End of Pipe Domain ===============================
143
144#-----------------------------------
145# Compute flux definition with pipe
146#-----------------------------------
147def compute_fluxes_pipe(domain):
148    import sys
149    timestep = float(sys.maxint)
150
151    area       = domain.quantities['area']
152    discharge  = domain.quantities['discharge']
153    bed        = domain.quantities['elevation']
154    height     = domain.quantities['height']
155    velocity   = domain.quantities['velocity']
156    width      = domain.quantities['width']
157
158
159    from anuga_1d.pipe.pipe_domain_ext import compute_fluxes_pipe_ext
160    domain.flux_timestep = compute_fluxes_pipe_ext(timestep,domain,area,discharge,bed,height,velocity,width)
161
162#-----------------------------------------------------------------------
163# Distribute to verticies with stage reconstructed and then extrapolated
164#-----------------------------------------------------------------------
165def distribute_to_vertices_and_edges_limit_a_d(domain):
166   
167    #Remove very thin layers of water
168    #protect_against_infinitesimal_and_negative_heights(domain) 
169
170
171
172    import sys
173    from anuga_1d.config import epsilon, h0
174
175   
176    N = domain.number_of_elements
177
178    #Shortcuts
179    area      = domain.quantities['area']
180    discharge = domain.quantities['discharge']
181    bed       = domain.quantities['elevation']
182    height    = domain.quantities['height']
183    velocity  = domain.quantities['velocity']
184    width     = domain.quantities['width']
185    stage     = domain.quantities['stage']
186
187    #Arrays   
188    a_C   = area.centroid_values
189    d_C   = discharge.centroid_values
190    z_C   = bed.centroid_values
191    h_C   = height.centroid_values
192    u_C   = velocity.centroid_values
193    b_C   = width.centroid_values
194    w_C   = stage.centroid_values
195
196    if domain.setstageflag:
197        a_C[:,] = (w_C-z_C)*b_C
198        domain.setstageflag = False
199
200    if domain.discontinousb:
201        width.extrapolate_second_order()
202       
203
204    h0 = 1.0e-12
205
206    h_C[:] = numpy.where( (a_C>h0) | (b_C>h0), a_C/(b_C+h0/b_C), 0.0 )
207    u_C[:] = numpy.where( (a_C>h0) | (b_C>h0), d_C/(a_C+h0/a_C), 0.0 )
208
209    a_C[:] = numpy.where( (a_C>h0) | (b_C>h0), a_C, 0.0 )
210    b_C[:] = numpy.where( (a_C>h0) | (b_C>h0), b_C, 0.0 )
211    d_C[:] = numpy.where( (a_C>h0) | (b_C>h0), d_C, 0.0 )
212
213    w_C[:] = h_C + z_C
214   
215               
216
217    bed.extrapolate_second_order()
218   
219    for name in ['velocity','stage']:
220        Q = domain.quantities[name]
221        if domain.order == 1:
222            Q.extrapolate_first_order()
223        elif domain.order == 2:
224            Q.extrapolate_second_order()
225        else:
226            raise 'Unknown order'
227
228
229    a_V  = area.vertex_values
230    w_V  = stage.vertex_values
231    z_V  = bed.vertex_values
232    h_V  = height.vertex_values
233    u_V  = velocity.vertex_values
234    d_V  = discharge.vertex_values
235    b_V  = width.vertex_values
236
237
238    h_V[:] = w_V-z_V
239
240    w_V[:] = numpy.where(h_V > h0, w_V, z_V)
241    h_V[:] = numpy.where(h_V > h0, h_V, 0.0)
242    a_V[:] = b_V*h_V
243    d_V[:] = u_V*a_V
244
245   
246    return
247
248
249#--------------------------------------------------------
250#Boundaries - specific to the pipe_domain
251#--------------------------------------------------------
252class Reflective_boundary(Boundary):
253    """Reflective boundary returns same conserved quantities as
254    those present in its neighbour volume but reflected.
255
256    This class is specific to the shallow water equation as it
257    works with the momentum quantities assumed to be the second
258    and third conserved quantities.
259    """
260
261    def __init__(self, domain = None):
262        Boundary.__init__(self)
263
264        if domain is None:
265            msg = 'Domain must be specified for reflective boundary'
266            raise msg
267
268        #Handy shorthands
269        self.normals  = domain.normals
270        self.area     = domain.quantities['area'].vertex_values
271        self.discharge     = domain.quantities['discharge'].vertex_values
272        self.bed      = domain.quantities['elevation'].vertex_values
273        self.height   = domain.quantities['height'].vertex_values
274        self.velocity = domain.quantities['velocity'].vertex_values
275        self.width    = domain.quantities['width'].vertex_values
276        self.stage    = domain.quantities['stage'].vertex_values
277
278        self.evolved_quantities = numpy.zeros(7, numpy.float)
279
280    def __repr__(self):
281        return 'Reflective_boundary'
282
283
284    def evaluate(self, vol_id, edge_id):
285        """Reflective boundaries reverses the outward momentum
286        of the volume they serve.
287        """
288
289        q = self.evolved_quantities
290        q[0] =  self.area[vol_id, edge_id]
291        q[1] = -self.discharge[vol_id, edge_id]
292        q[2] =  self.bed[vol_id, edge_id]
293        q[3] =  self.height[vol_id, edge_id]
294        q[4] = -self.velocity[vol_id, edge_id]
295        q[5] =  self.width[vol_id,edge_id]
296        q[6] =  self.stage[vol_id,edge_id]
297
298        return q
299
300class Dirichlet_boundary(Boundary):
301    """Dirichlet boundary returns constant values for the
302    conserved quantities
303if k>5 and k<15:
304            print discharge_ud[k],-g*zx*avg_h*avg_b
305        discharge_ud[k] +=-g*zx*avg_h*avg_b    """
306
307
308    def __init__(self, evolved_quantities=None):
309        Boundary.__init__(self)
310
311        if evolved_quantities is None:
312            msg = 'Must specify one value for each evolved quantity'
313            raise msg
314
315        assert len(evolved_quantities) == 7
316
317        self.evolved_quantities=numpy.array(evolved_quantities,numpy.float)
318
319    def __repr__(self):
320        return 'Dirichlet boundary (%s)' %self.evolved_quantities
321
322    def evaluate(self, vol_id=None, edge_id=None):
323        return self.evolved_quantities
324
325
326#----------------------------
327#Standard forcing terms:
328#---------------------------
329def gravity(domain):
330    """Apply gravitational pull in the presence of bed slope
331    """
332
333    from util import gradient
334    from Numeric import zeros, Float, array, sum
335
336
337
338    Area      = domain.quantities['area']
339    Discharge  = domain.quantities['discharge']
340    Elevation = domain.quantities['elevation']
341    Height    = domain.quantities['height']
342    Width     = domain.quantities['width']
343
344    discharge_ud  = Discharge.explicit_update
345
346
347       
348    h = Height.vertex_values
349    b = Width.vertex_values
350    a = Area.vertex_values
351    z = Elevation.vertex_values
352
353    x = domain.get_vertex_coordinates()
354    g = domain.g
355    for k in range(domain.number_of_elements):
356        avg_h = 0.5*(h[k,0] + h[k,1])
357        avg_b = 0.5*(b[k,0] + b[k,1])
358       
359        #Compute bed slope
360        x0, x1 = x[k,:]
361        z0, z1 = z[k,:]
362        zx = gradient(x0, x1, z0, z1)
363       
364        #Update momentum (explicit update is reset to source values)
365        discharge_ud[k]+= -g*zx*avg_h*avg_b
366     
367
368def boundary_stress(domain):
369
370    from util import gradient
371    from Numeric import zeros, Float, array, sum
372
373    Area     = domain.quantities['area']
374    Discharge  = domain.quantities['discharge']
375    Elevation = domain.quantities['elevation']
376    Height    = domain.quantities['height']
377    Width     = domain.quantities['width']
378
379    discharge_ud  = Discharge.explicit_update
380 
381    h = Height.vertex_values
382    b = Width.vertex_values
383    a = Area.vertex_values
384    z = Elevation.vertex_values
385
386    x = domain.get_vertex_coordinates()
387    g = domain.g
388
389    for k in range(domain.number_of_elements):
390        avg_h = 0.5*(h[k,0] + h[k,1])
391       
392
393        #Compute bed slope
394        x0, x1 = x[k,:]
395        b0, b1 = b[k,:]
396        bx = gradient(x0, x1, b0, b1)
397       
398        #Update momentum (explicit update is reset to source values)
399        discharge_ud[k] += 0.5*g*bx*avg_h*avg_h
400        #stage_ud[k] = 0.0
401 
402 
403def manning_friction(domain):
404    """Apply (Manning) friction to water momentum
405    """
406
407    from math import sqrt
408
409    w = domain.quantities['stage'].centroid_values
410    z = domain.quantities['elevation'].centroid_values
411    h = w-z
412
413    uh = domain.quantities['xmomentum'].centroid_values
414    eta = domain.quantities['friction'].centroid_values
415
416    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
417
418    N = domain.number_of_elements
419    eps = domain.minimum_allowed_height
420    g = domain.g
421
422    for k in range(N):
423        if eta[k] >= eps:
424            if h[k] >= eps:
425                #S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2))
426                S = -g * eta[k]**2 * uh[k]
427                S /= h[k]**(7.0/3)
428
429                #Update momentum
430                xmom_update[k] += S*uh[k]
431                #ymom_update[k] += S*vh[k]
432
433def linear_friction(domain):
434    """Apply linear friction to water momentum
435
436    Assumes quantity: 'linear_friction' to be present
437    """
438
439    from math import sqrt
440
441    w = domain.quantities['stage'].centroid_values
442    z = domain.quantities['elevation'].centroid_values
443    h = w-z
444
445    uh = domain.quantities['xmomentum'].centroid_values
446    tau = domain.quantities['linear_friction'].centroid_values
447
448    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
449
450    N = domain.number_of_elements
451    eps = domain.minimum_allowed_height
452
453    for k in range(N):
454        if tau[k] >= eps:
455            if h[k] >= eps:
456                S = -tau[k]/h[k]
457
458                #Update momentum
459                xmom_update[k] += S*uh[k]
460
461
462
463
464def linearb(domain):
465
466    bC = domain.quantities['width'].vertex_values
467   
468    for i in range(len(bC)-1):
469        temp= 0.5*(bC[i,1]+bC[i+1,0])
470        bC[i,1]=temp
471        bC[i+1,0]=temp
472
473
474
Note: See TracBrowser for help on using the repository browser.