source: anuga_core/source/anuga/shallow_water/smf.py @ 5675

Last change on this file since 5675 was 5675, checked in by sexton, 16 years ago

updates to smf to incorporate a scaling parameter

File size: 14.0 KB
Line 
1#
2# slide_tsunami function
3#
4
5"""This function returns a callable object representing an initial water
6   displacement generated by a submarine sediment slide.
7
8Using input parameters:
9
10Required
11 length  downslope slide length
12 depth   water depth to slide centre of mass
13 slope   bathymetric slope
14
15Optional
16 x0      x origin (0)
17 y0      y origin (0)
18 alpha   angular orientation of slide in xy plane (0)
19 w       slide width (0.25*length)
20 T       slide thickness (0.01*length)
21 g       acceleration due to gravity (9.8)
22 gamma   specific density of sediments (1.85)
23 Cm      added mass coefficient (1)
24 Cd      drag coefficient (1)
25 Cn      friction coefficient (0)
26 psi     (0)
27 dx      offset of second Gaussian (0.2*width of first Gaussian)
28 kappa   multiplier for sech^2 function (3.0)
29 kappad  multiplier for second Gaussian function (0.8)
30 zsmall  an amount near to zero (0.01)
31
32The following parameters are calculated:
33
34 a0      initial acceleration
35 ut      theoretical terminal velocity
36 s0      charactistic distance of motion
37 t0      characteristic time of motion
38 w       initial wavelength of tsunami
39 a2D     2D initial amplitude of tsunami
40 a3D     3D initial amplitude of tsunami
41
42The returned object is a callable double Gaussian function that represents
43the initial water displacement generated by a submarine sediment slide.
44
45Adrian Hitchman
46Geoscience Australia, June 2005
47"""
48def find_min(x0, wa, kappad, dx):
49    """Determine eta_min to scale eta(x,y)
50
51       eta(x,y) = n03d/nmin*[-f(y)]*g(x)
52
53       nmin = min (-f(y)*g(x) )
54            = -f(ystar)*g(xstar)
55
56       ystar = min (-f(y) ), i.e. diff(-f(y))=0
57       xstar = min ( g(x) ), i.e. diff(g(x))=0
58
59       ystar = y0 and -f(ystar)=1.0
60    """
61    from math import exp, cosh
62
63    step = 0.05
64    x = x0+50.
65    deriv = 10.0
66    count_max = 1000000
67    c = 0
68    deriv = 10.
69    f_ystar = 1.
70   
71    while c < count_max and deriv > 0:
72        deriv = (x-x0)*exp(-((x-x0)/wa)**2.0) - \
73                kappad*(x-dx-x0)*exp(-((x-dx-x0)/wa)**2.0)
74       
75        if deriv <= 0: xstar = x
76        x -= step
77        c += 1
78   
79    g_xstar = exp(-((xstar-x0)/wa)**2)-kappad*exp(-((xstar-dx-x0)/wa)**2)
80
81    etastar = g_xstar*f_ystar
82
83    return etastar
84
85def slide_tsunami(length, depth, slope, width=None, thickness=None, \
86                  x0=0.0, y0=0.0, alpha=0.0, \
87                  gravity=9.8, gamma=1.85, \
88                  massco=1, dragco=1, frictionco=0, psi=0, \
89                  dx=None, kappa=3.0, kappad=0.8, zsmall=0.01, \
90                  scale=None,
91                  domain=None, verbose=False):
92
93    from math import sin, tan, radians, pi, sqrt, exp
94   
95    if domain is not None:
96        xllcorner = domain.geo_reference.get_xllcorner()
97        yllcorner = domain.geo_reference.get_yllcorner()
98        x0 = x0 - xllcorner  # slump origin (relative)
99        y0 = y0 - yllcorner
100       
101    #if width not provided, set to typical value
102    if width is None:
103        width = 0.25 * length
104
105    #if thickness not provided, set to typical value
106    if thickness is None:
107        thickness = 0.01 * length
108
109    #calculate some parameters of the slide
110
111    sint = sin(radians(slope))
112    tant = tan(radians(slope))
113    tanp = tan(radians(psi))
114
115    a0 = gravity * sint * ((gamma-1)/(gamma+massco)) * (1-(tanp/tant))
116    ut = sqrt((gravity*depth) * (length*sint/depth) \
117                    * (pi*(gamma-1)/(2*dragco)) * (1-(tanp/tant)))
118    s0 = ut**2 / a0
119    t0 = ut / a0
120
121    #calculate some parameters of the water displacement produced by the slide
122
123    w = t0 * sqrt(gravity*depth)
124    a2D = s0 * (0.0574 - (0.0431*sint)) \
125             * (thickness/length) \
126             * ((length*sint/depth)**1.25) \
127             * (1 - exp(-2.2*(gamma-1)))
128    a3D = a2D / (1 + (15.5*sqrt(depth/(length*sint))))
129
130    from math import sqrt, log, e
131    dx = 2.0 * (w * sqrt(-log((zsmall/a3D),e))) / 5.0
132       
133    # determine nmin for scaling of eta(x,y)
134    nmin = find_min(x0,w,kappad,dx) 
135   
136    if scale is None:
137        scale = a3D/nmin
138       
139    #a few temporary print statements
140    if verbose is True:
141        print '\nThe slide ...'
142        print '\tLength: ', length
143        print '\tDepth: ', depth
144        print '\tSlope: ', slope
145        print '\tWidth: ', width
146        print '\tThickness: ', thickness
147        print '\tx0: ', x0
148        print '\ty0: ', y0
149        print '\tAlpha: ', alpha
150        print '\tAcceleration: ', a0
151        print '\tTerminal velocity: ', ut
152        print '\tChar time: ', t0
153        print '\tChar distance: ', s0
154        print '\nThe tsunami ...'
155        print '\tWavelength: ', w
156        print '\t2D amplitude: ', a2D
157        print '\t3D amplitude: ', a3D
158        print '\tscale for eta(x,y):', scale
159
160    #keep an eye on some of the assumptions built into the maths
161
162    if ((slope < 5) or (slope > 30)):
163        if verbose is True:
164            print 'WARNING: slope out of range (5 - 30 degrees) ', slope
165    if ((depth/length < 0.06) or (depth/length > 1.5)):
166        if verbose is True:
167            print  'WARNING: d/b out of range (0.06 - 1.5) ', depth/length
168    if ((thickness/length < 0.008) or (thickness/length > 0.2)):
169        if verbose is True:
170            print 'WARNING: T/b out of range (0.008 - 0.2) ', thickness/length
171    if ((gamma < 1.46) or (gamma > 2.93)):
172        if verbose is True:
173            print 'WARNING: gamma out of range (1.46 - 2.93) ', gamma
174
175    return Double_gaussian(a3D, w, width, x0, y0, alpha, kappa, kappad, zsmall, dx, scale)
176
177#
178# slump_tsunami function
179#
180
181"""This function returns a callable object representing an initial water
182   displacement generated by a submarine sediment slump.
183
184Using input parameters:
185
186Required
187 length  downslope slump length
188 depth   water depth to slump centre of mass
189 slope   bathymetric slope
190
191Optional
192 x0      x origin (0)
193 y0      y origin (0)
194 alpha   angular orientation of slide in xy plane (0)
195 w       slump width (1.0*length)
196 T       slump thickness (0.1*length)
197 R       slump radius of curvature (b^2/(8*T))
198 del_phi slump angular displacement (0.48)
199 g       acceleration due to gravity (9.8)
200 gamma   specific density of sediments (1.85)
201 Cm      added mass coefficient (1)
202 Cd      drag coefficient (1)
203 Cn      friction coefficient (0)
204 dx      offset of second Gaussian (0.2*width of first Gaussian)
205 kappa   multiplier for sech^2 function (3.0)
206 kappad  multiplier for second Gaussian function (0.8)
207 zsmall  an amount near to zero (0.01)
208
209The following parameters are calculated:
210
211 a0      initial acceleration
212 um      maximum velocity
213 s0      charactistic distance of motion
214 t0      characteristic time of motion
215 w       initial wavelength of tsunami
216 a2D     2D initial amplitude of tsunami
217 a3D     3D initial amplitude of tsunami
218
219The returned object is a callable double Gaussian function that represents
220the initial water displacement generated by a submarine sediment slump.
221
222Adrian Hitchman
223Geoscience Australia, June 2005
224"""
225
226def slump_tsunami(length, depth, slope, width=None, thickness=None, \
227                  radius=None, dphi=0.48, x0=0.0, y0=0.0, alpha=0.0, \
228                  gravity=9.8, gamma=1.85, \
229                  massco=1, dragco=1, frictionco=0, \
230                  dx=None, kappa=3.0, kappad=1.0, zsmall=0.01, scale=None, \
231                  domain=None,
232                  verbose=False):
233
234    from math import sin, radians, sqrt
235
236    if domain is not None:
237        xllcorner = domain.geo_reference.get_xllcorner()
238        yllcorner = domain.geo_reference.get_yllcorner()
239        x0 = x0 - xllcorner  # slump origin (relative)
240        y0 = y0 - yllcorner
241
242    #if width not provided, set to typical value
243    if width is None:
244        width = length
245
246    #if thickness not provided, set to typical value
247    if thickness is None:
248        thickness = 0.1 * length
249
250    #if radius not provided, set to typical value
251    if radius is None:
252        radius = length**2 / (8.0 * thickness)
253
254    #calculate some parameters of the slump
255
256    sint = sin(radians(slope))
257
258    s0 = radius * dphi / 2
259    t0 = sqrt((radius*(gamma+massco)) / (gravity*(gamma-1)))
260    a0 = s0 / t0**2
261    um = s0 / t0
262
263    #calculate some parameters of the water displacement produced by the slump
264
265    w = t0 * sqrt(gravity*depth)
266    a2D = s0 * (0.131/sint) \
267             * (thickness/length) \
268             * (length*sint/depth)**1.25 \
269             * (length/radius)**0.63 * dphi**0.39 \
270             * (1.47 - (0.35*(gamma-1))) * (gamma-1)
271    a3D = a2D / (1 + (2.06*sqrt(depth/length)))
272
273    from math import sqrt, log, e
274    dx = 2.0 * (w * sqrt(-log((zsmall/a3D),e))) / 5.0
275       
276    # determine nmin for scaling of eta(x,y)
277    nmin = find_min(x0,w,kappad,dx) 
278   
279    if scale is None:
280        scale = a3D/nmin
281       
282    #a few temporary print statements
283    if verbose is True:
284        print '\nThe slump ...'
285        print '\tLength: ', length
286        print '\tDepth: ', depth
287        print '\tSlope: ', slope
288        print '\tWidth: ', width
289        print '\tThickness: ', thickness
290        print '\tRadius: ', radius
291        print '\tDphi: ', dphi
292        print '\tx0: ', x0
293        print '\ty0: ', y0
294        print '\tAlpha: ', alpha
295        print '\tAcceleration: ', a0
296        print '\tMaximum velocity: ', um
297        print '\tChar time: ', t0
298        print '\tChar distance: ', s0
299        print '\nThe tsunami ...'
300        print '\tWavelength: ', w
301        print '\t2D amplitude: ', a2D
302        print '\t3D amplitude: ', a3D
303        print '\tDelta x ', dx
304        print '\tsmall ', zsmall
305        print '\tKappa d ', kappad
306        print '\tscale for eta(x,y):', scale
307
308    #keep an eye on some of the assumptions built into the maths
309
310    if ((slope < 10) or (slope > 30)):       
311        if verbose is True:
312            print 'WARNING: slope out of range (10 - 30 degrees) ', slope
313    if ((depth/length < 0.34) or (depth/length > 0.5)):     
314        if verbose is True:
315            print  'WARNING: d/b out of range (0.34 - 0.5) ', depth/length
316    if ((thickness/length < 0.10) or (thickness/length > 0.15)):     
317        if verbose is True:
318            print 'WARNING: T/b out of range (0.10 - 0.15) ', thickness/length
319    if ((radius/length < 1.0) or (radius/length > 2.0)):     
320        if verbose is True:
321            print 'WARNING: R/b out of range (1 - 2) ', radius/length
322    if ((dphi < 0.10) or (dphi > 0.52)):     
323        if verbose is True:
324            print 'WARNING: del_phi out of range (0.10 - 0.52) ', dphi
325    if ((gamma < 1.46) or (gamma > 2.93)):     
326        if verbose is True:
327            print 'WARNING: gamma out of range (1.46 - 2.93) ', gamma
328
329    return Double_gaussian(a3D, w, width, x0, y0, alpha, kappa, kappad, zsmall, dx, scale)
330
331#
332# Double_gaussian class
333#
334
335"""This is a callable class representing the initial water displacment
336   generated by a sediment slide or slump.
337
338Using input parameters:
339
340Required
341 w       initial wavelength of tsunami
342 a3D     3D initial amplitude of tsunami
343 width   width of smf
344
345Optional
346 x0      x origin of smf
347 y0      y origin of smf
348 alpha   angular orientation of smf in xy plane (0)
349 dx      offset of second Gaussian (0.2*width of first Gaussian)
350 kappa   multiplier for sech^2 function (3.0)
351 kappad  multiplier for second Gaussian function (0.8)
352 zsmall  an amount near to zero (0.01)
353
354Adrian Hitchman
355Geoscience Australia, June 2005
356"""
357
358class Double_gaussian:
359
360    def __init__(self, a3D, wavelength, width, x0, y0, alpha, \
361                 kappa, kappad, zsmall, dx, scale):
362        self.a3D = a3D
363        self.wavelength = wavelength
364        self.width = width
365        self.x0 = x0
366        self.y0 = y0
367        self.alpha = alpha
368        self.kappa = kappa
369        self.kappad = kappad
370        self.scale = scale
371
372        if dx is None:
373            from math import sqrt, log, e
374            dx = 2.0 * (self.wavelength * sqrt(-log((zsmall/self.a3D),e))) / 5.0
375        self.dx = dx
376
377    def __call__(self, x, y):
378        """Make Double_gaussian a callable object.
379
380        If called as a function, this object returns z values representing
381        the initial 3D distribution of water heights at the points (x,y)
382        produced by a submarine mass failure.
383        """
384
385        from math import sin, cos, radians, exp, cosh
386        from Numeric import zeros, Float
387
388        #ensure vectors x and y have the same length
389        N = len(x)
390        assert N == len(y)
391
392        am = self.a3D
393        am2 = 1.0
394        wa = self.wavelength
395        wi = self.width
396        x0 = self.x0
397        y0 = self.y0
398        alpha = self.alpha
399        dx = self.dx
400        kappa = self.kappa
401        kappad = self.kappad
402        scale = self.scale
403
404        #double Gaussian calculation assumes water displacement is oriented
405        #E-W, so, for displacement at some angle alpha clockwise from the E-W
406        #direction, rotate (x,y) coordinates anti-clockwise by alpha
407
408        cosa = cos(radians(alpha))
409        sina = sin(radians(alpha))
410
411        xr = ((x-x0) * cosa - (y-y0) * sina) + x0
412        yr = ((x-x0) * sina + (y-y0) * cosa) + y0
413
414        z = zeros(N, Float)
415        maxz = 0.0
416        minz = 0.0
417        for i in range(N):
418            try:
419                z[i] =  -scale / ((cosh(kappa*(yr[i]-y0)/(wi+wa)))**2) \
420                            * (exp(-((xr[i]-x0)/wa)**2) - \
421                                kappad*exp(-((xr[i]-dx-x0)/wa)**2))
422                if z[i] > maxz: maxz = z[i]
423                if z[i] < minz: minz = z[i]
424               
425            except OverflowError:
426                pass
427               
428        return z
429
430    def determineDX(self, zsmall):
431        """Determine a suitable offset for the second Gaussian function.
432
433        A suitable offset for the second Gaussian function is taken to
434        be some fraction of the 'width' of the first Gaussian function.
435
436        The 'width' of the first Gaussian is obtained from the range of
437        the x coordinates over which the function takes values from
438        'near zero', through 1, and back to 'near zero'.
439
440        The parameter zsmall passed to this function specifies how much
441        'near zero' is.
442        """
443
444        from math import sqrt, log, e
445       
446        a = self.a3D
447        c = self.wavelength
448
449        self.dx = 2.0 * (c * sqrt(-log((zsmall/a),e))) / 5.0
450
451        return self.dx
452
Note: See TracBrowser for help on using the repository browser.