1 | #!/usr/bin/env python |
---|
2 | |
---|
3 | import unittest, os |
---|
4 | import os.path |
---|
5 | from math import pi, sqrt |
---|
6 | import tempfile |
---|
7 | |
---|
8 | from anuga.config import g, epsilon |
---|
9 | from anuga.config import netcdf_mode_r, netcdf_mode_w, netcdf_mode_a |
---|
10 | from anuga.utilities.numerical_tools import mean |
---|
11 | from anuga.geometry.polygon import is_inside_polygon |
---|
12 | from anuga.coordinate_transforms.geo_reference import Geo_reference |
---|
13 | from anuga.abstract_2d_finite_volumes.quantity import Quantity |
---|
14 | from anuga.geospatial_data.geospatial_data import Geospatial_data |
---|
15 | from anuga.abstract_2d_finite_volumes.mesh_factory import rectangular_cross |
---|
16 | |
---|
17 | from anuga.utilities.system_tools import get_pathname_from_package |
---|
18 | from swb_domain import * |
---|
19 | |
---|
20 | import numpy as num |
---|
21 | |
---|
22 | # Get gateway to C implementation of flux function for direct testing |
---|
23 | from shallow_water_ext import flux_function_central as flux_function |
---|
24 | |
---|
25 | |
---|
26 | |
---|
27 | |
---|
28 | class Test_swb_clean(unittest.TestCase): |
---|
29 | def setUp(self): |
---|
30 | pass |
---|
31 | |
---|
32 | def tearDown(self): |
---|
33 | pass |
---|
34 | |
---|
35 | |
---|
36 | def test_balance_deep_and_shallow(self): |
---|
37 | """Test that balanced limiters preserve conserved quantites. |
---|
38 | This test is using old depth based balanced limiters |
---|
39 | """ |
---|
40 | |
---|
41 | import copy |
---|
42 | |
---|
43 | a = [0.0, 0.0] |
---|
44 | b = [0.0, 2.0] |
---|
45 | c = [2.0, 0.0] |
---|
46 | d = [0.0, 4.0] |
---|
47 | e = [2.0, 2.0] |
---|
48 | f = [4.0, 0.0] |
---|
49 | |
---|
50 | points = [a, b, c, d, e, f] |
---|
51 | # bac, bce, ecf, dbe |
---|
52 | elements = [[1,0,2], [1,2,4], [4,2,5], [3,1,4] ] |
---|
53 | |
---|
54 | domain = Domain(points, elements) |
---|
55 | domain.check_integrity() |
---|
56 | |
---|
57 | # Create a deliberate overshoot |
---|
58 | domain.set_quantity('stage', [[3,0,3], [2,2,6], [5,3,8], [8,3,5]]) |
---|
59 | domain.set_quantity('elevation', 0) # Flat bed |
---|
60 | stage = domain.quantities['stage'] |
---|
61 | |
---|
62 | ref_centroid_values = copy.copy(stage.centroid_values[:]) # Copy |
---|
63 | |
---|
64 | # Limit |
---|
65 | domain.distribute_to_vertices_and_edges() |
---|
66 | |
---|
67 | # Assert that quantities are conserved |
---|
68 | for k in range(len(domain)): |
---|
69 | assert num.allclose(ref_centroid_values[k], |
---|
70 | num.sum(stage.vertex_values[k,:])/3) |
---|
71 | |
---|
72 | # Now try with a non-flat bed - closely hugging initial stage in places |
---|
73 | domain.set_quantity('stage', [[3,0,3], [2,2,6], [5,3,8], [8,3,5]]) |
---|
74 | domain.set_quantity('elevation', [[0,0,0], |
---|
75 | [1.8,1.9,5.9], |
---|
76 | [4.6,0,0], |
---|
77 | [0,2,4]]) |
---|
78 | stage = domain.quantities['stage'] |
---|
79 | #elevation = domain.quantities['elevation'] |
---|
80 | #height = domain.quantities['height'] |
---|
81 | |
---|
82 | ref_centroid_values = copy.copy(stage.centroid_values[:]) # Copy |
---|
83 | ref_vertex_values = copy.copy(stage.vertex_values[:]) # Copy |
---|
84 | |
---|
85 | # Limit |
---|
86 | domain.distribute_to_vertices_and_edges() |
---|
87 | |
---|
88 | # Assert that all vertex quantities have changed |
---|
89 | for k in range(len(domain)): |
---|
90 | assert not num.allclose(ref_vertex_values[k,:], |
---|
91 | stage.vertex_values[k,:]) |
---|
92 | # and assert that quantities are still conserved |
---|
93 | for k in range(len(domain)): |
---|
94 | assert num.allclose(ref_centroid_values[k], |
---|
95 | num.sum(stage.vertex_values[k,:])/3) |
---|
96 | |
---|
97 | # Check actual results |
---|
98 | |
---|
99 | #print stage.vertex_values |
---|
100 | |
---|
101 | assert num.allclose(stage.vertex_values, |
---|
102 | [[ 2. , 2. , 2. ], |
---|
103 | [ 2.22222222 , 2.22222222 , 5.55555556], |
---|
104 | [ 5.33333333 , 5.33333333 , 5.33333333], |
---|
105 | [ 5.33333333 , 5.33333333 , 5.33333333]]) |
---|
106 | |
---|
107 | |
---|
108 | def test_balance_deep_and_shallow_tight_SL(self): |
---|
109 | """Test that balanced limiters preserve conserved quantites. |
---|
110 | This test is using Tight Slope Limiters |
---|
111 | """ |
---|
112 | |
---|
113 | import copy |
---|
114 | |
---|
115 | a = [0.0, 0.0] |
---|
116 | b = [0.0, 2.0] |
---|
117 | c = [2.0, 0.0] |
---|
118 | d = [0.0, 4.0] |
---|
119 | e = [2.0, 2.0] |
---|
120 | f = [4.0, 0.0] |
---|
121 | |
---|
122 | points = [a, b, c, d, e, f] |
---|
123 | # bac, bce, ecf, dbe |
---|
124 | elements = [[1,0,2], [1,2,4], [4,2,5], [3,1,4] ] |
---|
125 | |
---|
126 | domain = Domain(points, elements) |
---|
127 | domain.check_integrity() |
---|
128 | |
---|
129 | # Create a deliberate overshoot |
---|
130 | domain.set_quantity('stage', [[3,0,3], [2,2,6], [5,3,8], [8,3,5]]) |
---|
131 | domain.set_quantity('elevation', 0) # Flat bed |
---|
132 | stage = domain.quantities['stage'] |
---|
133 | |
---|
134 | ref_centroid_values = copy.copy(stage.centroid_values[:]) # Copy |
---|
135 | |
---|
136 | # Limit |
---|
137 | domain.tight_slope_limiters = 1 |
---|
138 | domain.distribute_to_vertices_and_edges() |
---|
139 | |
---|
140 | # Assert that quantities are conserved |
---|
141 | for k in range(len(domain)): |
---|
142 | assert num.allclose (ref_centroid_values[k], |
---|
143 | num.sum(stage.vertex_values[k,:])/3) |
---|
144 | |
---|
145 | # Now try with a non-flat bed - closely hugging initial stage in places |
---|
146 | # This will create alphas in the range [0, 0.478260, 1] |
---|
147 | domain.set_quantity('stage', [[3,0,3], [2,2,6], [5,3,8], [8,3,5]]) |
---|
148 | domain.set_quantity('elevation', [[0,0,0], |
---|
149 | [1.8,1.9,5.9], |
---|
150 | [4.6,0,0], |
---|
151 | [0,2,4]]) |
---|
152 | stage = domain.quantities['stage'] |
---|
153 | |
---|
154 | ref_centroid_values = copy.copy(stage.centroid_values[:]) # Copy |
---|
155 | ref_vertex_values = copy.copy(stage.vertex_values[:]) # Copy |
---|
156 | |
---|
157 | # Limit |
---|
158 | domain.tight_slope_limiters = 1 |
---|
159 | domain.distribute_to_vertices_and_edges() |
---|
160 | |
---|
161 | # Assert that all vertex quantities have changed |
---|
162 | for k in range(len(domain)): |
---|
163 | assert not num.allclose(ref_vertex_values[k,:], |
---|
164 | stage.vertex_values[k,:]) |
---|
165 | # and assert that quantities are still conserved |
---|
166 | for k in range(len(domain)): |
---|
167 | assert num.allclose(ref_centroid_values[k], |
---|
168 | num.sum(stage.vertex_values[k,:])/3) |
---|
169 | |
---|
170 | def test_balance_deep_and_shallow_Froude(self): |
---|
171 | """Test that balanced limiters preserve conserved quantites - |
---|
172 | and also that excessive Froude numbers are dealt with. |
---|
173 | This test is using tight slope limiters. |
---|
174 | """ |
---|
175 | |
---|
176 | import copy |
---|
177 | |
---|
178 | a = [0.0, 0.0] |
---|
179 | b = [0.0, 2.0] |
---|
180 | c = [2.0, 0.0] |
---|
181 | d = [0.0, 4.0] |
---|
182 | e = [2.0, 2.0] |
---|
183 | f = [4.0, 0.0] |
---|
184 | |
---|
185 | points = [a, b, c, d, e, f] |
---|
186 | # bac, bce, ecf, dbe |
---|
187 | elements = [[1,0,2], [1,2,4], [4,2,5], [3,1,4] ] |
---|
188 | |
---|
189 | domain = Domain(points, elements) |
---|
190 | domain.check_integrity() |
---|
191 | domain.tight_slope_limiters = True |
---|
192 | domain.use_centroid_velocities = True |
---|
193 | |
---|
194 | # Create non-flat bed - closely hugging initial stage in places |
---|
195 | # This will create alphas in the range [0, 0.478260, 1] |
---|
196 | domain.set_quantity('stage', [[3,0,3], [2,2,6], [5,3,8], [8,3,5]]) |
---|
197 | domain.set_quantity('elevation', [[0,0,0], |
---|
198 | [1.8,1.999,5.999], |
---|
199 | [4.6,0,0], |
---|
200 | [0,2,4]]) |
---|
201 | |
---|
202 | # Create small momenta, that nonetheless will generate large speeds |
---|
203 | # due to shallow depth at isolated vertices |
---|
204 | domain.set_quantity('xmomentum', -0.0058) |
---|
205 | domain.set_quantity('ymomentum', 0.0890) |
---|
206 | |
---|
207 | stage = domain.quantities['stage'] |
---|
208 | elevation = domain.quantities['elevation'] |
---|
209 | xmomentum = domain.quantities['xmomentum'] |
---|
210 | ymomentum = domain.quantities['ymomentum'] |
---|
211 | |
---|
212 | # Setup triangle #1 to mimick real Froude explosion observed |
---|
213 | # in the Onslow example 13 Nov 2007. |
---|
214 | stage.vertex_values[1,:] = [1.6385, 1.6361, 1.2953] |
---|
215 | elevation.vertex_values[1,:] = [1.6375, 1.6336, 0.4647] |
---|
216 | xmomentum.vertex_values[1,:] = [-0.0058, -0.0050, -0.0066] |
---|
217 | ymomentum.vertex_values[1,:] = [0.0890, 0.0890, 0.0890] |
---|
218 | |
---|
219 | xmomentum.interpolate() |
---|
220 | ymomentum.interpolate() |
---|
221 | stage.interpolate() |
---|
222 | elevation.interpolate() |
---|
223 | |
---|
224 | # Verify interpolation |
---|
225 | assert num.allclose(stage.centroid_values[1], 1.5233) |
---|
226 | assert num.allclose(elevation.centroid_values[1], 1.2452667) |
---|
227 | assert num.allclose(xmomentum.centroid_values[1], -0.0058) |
---|
228 | assert num.allclose(ymomentum.centroid_values[1], 0.089) |
---|
229 | |
---|
230 | # Derived quantities |
---|
231 | depth = stage-elevation |
---|
232 | u = xmomentum/depth |
---|
233 | v = ymomentum/depth |
---|
234 | |
---|
235 | denom = (depth*g)**0.5 |
---|
236 | Fx = u/denom |
---|
237 | Fy = v/denom |
---|
238 | |
---|
239 | # Verify against Onslow example (14 Nov 2007) |
---|
240 | assert num.allclose(depth.centroid_values[1], 0.278033) |
---|
241 | assert num.allclose(u.centroid_values[1], -0.0208608) |
---|
242 | assert num.allclose(v.centroid_values[1], 0.3201055) |
---|
243 | |
---|
244 | assert num.allclose(denom.centroid_values[1], |
---|
245 | num.sqrt(depth.centroid_values[1]*g)) |
---|
246 | |
---|
247 | assert num.allclose(u.centroid_values[1]/denom.centroid_values[1], |
---|
248 | -0.012637746977) |
---|
249 | assert num.allclose(Fx.centroid_values[1], |
---|
250 | u.centroid_values[1]/denom.centroid_values[1]) |
---|
251 | |
---|
252 | # Check that Froude numbers are small at centroids. |
---|
253 | assert num.allclose(Fx.centroid_values[1], -0.012637746977) |
---|
254 | assert num.allclose(Fy.centroid_values[1], 0.193924048435) |
---|
255 | |
---|
256 | # But Froude numbers are huge at some vertices and edges |
---|
257 | assert num.allclose(Fx.vertex_values[1,:], [-5.85888475e+01, |
---|
258 | -1.27775313e+01, |
---|
259 | -2.78511420e-03]) |
---|
260 | |
---|
261 | assert num.allclose(Fx.edge_values[1,:], [-6.89150773e-03, |
---|
262 | -7.38672488e-03, |
---|
263 | -2.35626238e+01]) |
---|
264 | |
---|
265 | assert num.allclose(Fy.vertex_values[1,:], [8.99035764e+02, |
---|
266 | 2.27440057e+02, |
---|
267 | 3.75568430e-02]) |
---|
268 | |
---|
269 | assert num.allclose(Fy.edge_values[1,:], [1.05748998e-01, |
---|
270 | 1.06035244e-01, |
---|
271 | 3.88346947e+02]) |
---|
272 | |
---|
273 | |
---|
274 | # The task is now to arrange the limiters such that Froude numbers |
---|
275 | # remain under control whil at the same time obeying the conservation |
---|
276 | # laws. |
---|
277 | ref_centroid_values = copy.copy(stage.centroid_values[:]) # Copy |
---|
278 | ref_vertex_values = copy.copy(stage.vertex_values[:]) # Copy |
---|
279 | |
---|
280 | # Limit (and invoke balance_deep_and_shallow) |
---|
281 | domain.tight_slope_limiters = 1 |
---|
282 | domain.distribute_to_vertices_and_edges() |
---|
283 | |
---|
284 | # Redo derived quantities |
---|
285 | depth = stage - elevation |
---|
286 | u = xmomentum/depth |
---|
287 | v = ymomentum/depth |
---|
288 | |
---|
289 | # Assert that all vertex velocities stay within one |
---|
290 | # order of magnitude of centroid velocities. |
---|
291 | assert num.alltrue(num.absolute(u.vertex_values[1,:]) <= |
---|
292 | num.absolute(u.centroid_values[1])*10) |
---|
293 | assert num.alltrue(num.absolute(v.vertex_values[1,:]) <= |
---|
294 | num.absolute(v.centroid_values[1])*10) |
---|
295 | |
---|
296 | denom = (depth*g)**0.5 |
---|
297 | Fx = u/denom |
---|
298 | Fy = v/denom |
---|
299 | |
---|
300 | # Assert that Froude numbers are less than max value (TBA) |
---|
301 | # at vertices, edges and centroids. |
---|
302 | from anuga.config import maximum_froude_number |
---|
303 | |
---|
304 | assert num.alltrue(num.absolute(Fx.vertex_values[1,:]) < |
---|
305 | maximum_froude_number) |
---|
306 | assert num.alltrue(num.absolute(Fy.vertex_values[1,:]) < |
---|
307 | maximum_froude_number) |
---|
308 | |
---|
309 | # Assert that all vertex quantities have changed |
---|
310 | for k in range(len(domain)): |
---|
311 | assert not num.allclose(ref_vertex_values[k,:], |
---|
312 | stage.vertex_values[k,:]) |
---|
313 | |
---|
314 | # Assert that quantities are still conserved |
---|
315 | for k in range(len(domain)): |
---|
316 | assert num.allclose(ref_centroid_values[k], |
---|
317 | num.sum(stage.vertex_values[k,:])/3) |
---|
318 | |
---|
319 | return |
---|
320 | |
---|
321 | qwidth = 12 |
---|
322 | for k in [1]: # range(len(domain)): |
---|
323 | print 'Triangle %d (C, V, E)' % k |
---|
324 | |
---|
325 | print ('stage'.ljust(qwidth), stage.centroid_values[k], |
---|
326 | stage.vertex_values[k,:], stage.edge_values[k,:]) |
---|
327 | print ('elevation'.ljust(qwidth), elevation.centroid_values[k], |
---|
328 | elevation.vertex_values[k,:], elevation.edge_values[k,:]) |
---|
329 | print ('depth'.ljust(qwidth), depth.centroid_values[k], |
---|
330 | depth.vertex_values[k,:], depth.edge_values[k,:]) |
---|
331 | print ('xmomentum'.ljust(qwidth), xmomentum.centroid_values[k], |
---|
332 | xmomentum.vertex_values[k,:], xmomentum.edge_values[k,:]) |
---|
333 | print ('ymomentum'.ljust(qwidth), ymomentum.centroid_values[k], |
---|
334 | ymomentum.vertex_values[k,:], ymomentum.edge_values[k,:]) |
---|
335 | print ('u'.ljust(qwidth),u.centroid_values[k], |
---|
336 | u.vertex_values[k,:], u.edge_values[k,:]) |
---|
337 | print ('v'.ljust(qwidth), v.centroid_values[k], |
---|
338 | v.vertex_values[k,:], v.edge_values[k,:]) |
---|
339 | print ('Fx'.ljust(qwidth), Fx.centroid_values[k], |
---|
340 | Fx.vertex_values[k,:], Fx.edge_values[k,:]) |
---|
341 | print ('Fy'.ljust(qwidth), Fy.centroid_values[k], |
---|
342 | Fy.vertex_values[k,:], Fy.edge_values[k,:]) |
---|
343 | |
---|
344 | |
---|
345 | ################################################################################# |
---|
346 | |
---|
347 | if __name__ == "__main__": |
---|
348 | suite = unittest.makeSuite(Test_swb_clean, 'test') |
---|
349 | runner = unittest.TextTestRunner(verbosity=1) |
---|
350 | runner.run(suite) |
---|