source: inundation/ga/storm_surge/pyvolution/test_util.py @ 1278

Last change on this file since 1278 was 1137, checked in by ole, 20 years ago

Work on sww2asc export, ensure_numeric and other minor stuff

File size: 31.6 KB
Line 
1#!/usr/bin/env python
2
3
4import unittest
5from Numeric import zeros, array, allclose
6from math import sqrt, pi
7
8from util import *
9from config import epsilon
10
11
12def test_function(x, y):
13    return x+y
14
15class Test_Util(unittest.TestCase):
16    def setUp(self):
17        pass
18
19    def tearDown(self):
20        pass
21
22
23    def test_gradient(self):
24        x0 = 0.0; y0 = 0.0; z0 = 0.0
25        x1 = 1.0; y1 = 0.0; z1 = -1.0
26        x2 = 0.0; y2 = 1.0; z2 = 0.0
27
28        zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2)
29
30        assert zx == -1.0
31        assert zy == 0.0
32
33
34
35
36    def test_gradient2(self):
37
38        from util import gradient
39        x0 = 2.0/3; y0 = 2.0/3
40        x1=  8.0/3; y1 = 2.0/3
41        x2 = 2.0/3; y2 = 8.0/3
42
43        q0 = 2.0+2.0/3
44        q1 = 8.0+2.0/3
45        q2 = 2.0+8.0/3
46
47        #Gradient of fitted pwl surface
48        a, b = gradient(x0, y0, x1, y1, x2, y2, q0, q1, q2)
49
50        assert abs(a - 3.0) < epsilon
51        assert abs(b - 1.0) < epsilon
52
53
54
55    def test_that_C_extension_compiles(self):
56        FN = 'util_ext.c'
57        try:
58            import util_ext
59        except:
60            from compile import compile
61
62            try:
63                compile(FN)
64            except:
65                raise 'Could not compile %s' %FN
66            else:
67                import util_ext
68
69
70    def test_gradient_C_extension(self):
71        from util_ext import gradient as gradient_c
72
73        x0 = 2.0/3; y0 = 2.0/3
74        x1=  8.0/3; y1 = 2.0/3
75        x2 = 2.0/3; y2 = 8.0/3
76
77        q0 = 2.0+2.0/3
78        q1 = 8.0+2.0/3
79        q2 = 2.0+8.0/3
80
81        #Gradient of fitted pwl surface
82        a, b = gradient_c(x0, y0, x1, y1, x2, y2, q0, q1, q2)
83
84        assert abs(a - 3.0) < epsilon
85        assert abs(b - 1.0) < epsilon
86
87
88    def test_gradient_C_extension3(self):
89        from util_ext import gradient as gradient_c
90
91        from RandomArray import uniform, seed
92        seed(17, 53)
93
94        x0, x1, x2, y0, y1, y2 = uniform(0.0,3.0,6)
95
96        q0 = uniform(0.0, 10.0, 4)
97        q1 = uniform(1.0, 3.0, 4)
98        q2 = uniform(7.0, 20.0, 4)
99
100
101        for i in range(4):
102            #Gradient of fitted pwl surface
103            from util import gradient_python
104            a_ref, b_ref = gradient(x0, y0, x1, y1, x2, y2,
105                                    q0[i], q1[i], q2[i])
106
107            #print a_ref, b_ref
108            a, b = gradient_c(x0, y0, x1, y1, x2, y2,
109                              q0[i], q1[i], q2[i])
110
111            #print a, a_ref, b, b_ref
112            assert abs(a - a_ref) < epsilon
113            assert abs(b - b_ref) < epsilon
114
115
116
117    #Geometric
118    #def test_distance(self):
119    #    from util import distance#
120    #
121    #    self.failUnless( distance([4,2],[7,6]) == 5.0,
122    #                     'Distance is wrong!')
123    #    self.failUnless( allclose(distance([7,6],[9,8]), 2.82842712475),
124    #                    'distance is wrong!')
125    #    self.failUnless( allclose(distance([9,8],[4,2]), 7.81024967591),
126    #                    'distance is wrong!')
127    #
128    #    self.failUnless( distance([9,8],[4,2]) == distance([4,2],[9,8]),
129    #                    'distance is wrong!')
130
131    def test_angle(self):
132        from util import angle
133
134        assert allclose(angle([1.0, 1.0])/pi*180, 45.0)
135
136
137    def test_anglediff(self):
138        from util import anglediff
139
140        assert allclose(anglediff([0.0, 1.], [1.0, 1.0])/pi*180, 45.0)
141
142
143
144
145    def test_file_function_time(self):
146        """Test that File function interpolates correctly
147        between given times. No x,y dependency here.
148        """
149
150        #Write file
151        import os, time
152        from config import time_format
153        from math import sin, pi
154
155        finaltime = 1200
156        filename = 'test_file_function.txt'
157        fid = open(filename, 'w')
158        start = time.mktime(time.strptime('2000', '%Y'))
159        dt = 60  #One minute intervals
160        t = 0.0
161        while t <= finaltime:
162            t_string = time.strftime(time_format, time.gmtime(t+start))
163            fid.write('%s, %f %f %f\n' %(t_string, 2*t, t**2, sin(t*pi/600)))
164            t += dt
165
166        fid.close()
167
168        F = file_function(filename)
169
170        #Now try interpolation
171        for i in range(20):
172            t = i*10
173            q = F(t)
174
175            #Exact linear intpolation
176            assert allclose(q[0], 2*t)
177            if i%6 == 0:
178                assert allclose(q[1], t**2)
179                assert allclose(q[2], sin(t*pi/600))
180
181        #Check non-exact
182
183        t = 90 #Halfway between 60 and 120
184        q = F(t)
185        assert allclose( (120**2 + 60**2)/2, q[1] )
186        assert allclose( (sin(120*pi/600) + sin(60*pi/600))/2, q[2] )
187
188
189        t = 100 #Two thirds of the way between between 60 and 120
190        q = F(t)
191        assert allclose( 2*120**2/3 + 60**2/3, q[1] )
192        assert allclose( 2*sin(120*pi/600)/3 + sin(60*pi/600)/3, q[2] )
193
194        os.remove(filename)
195
196
197    def test_ensure_numeric(self):
198        from util import ensure_numeric
199        from Numeric import ArrayType, Float, array
200
201        A = [1,2,3,4]
202        B = ensure_numeric(A)
203        assert type(B) == ArrayType
204        assert B.typecode() == 'l'
205        assert B[0] == 1 and B[1] == 2 and B[2] == 3 and B[3] == 4
206
207
208        A = [1,2,3.14,4]
209        B = ensure_numeric(A)
210        assert type(B) == ArrayType
211        assert B.typecode() == 'd'
212        assert B[0] == 1 and B[1] == 2 and B[2] == 3.14 and B[3] == 4
213
214
215        A = [1,2,3,4]
216        B = ensure_numeric(A, Float)
217        assert type(B) == ArrayType
218        assert B.typecode() == 'd'
219        assert B[0] == 1.0 and B[1] == 2.0 and B[2] == 3.0 and B[3] == 4.0
220
221
222        A = [1,2,3,4]
223        B = ensure_numeric(A, Float)
224        assert type(B) == ArrayType
225        assert B.typecode() == 'd'
226        assert B[0] == 1.0 and B[1] == 2.0 and B[2] == 3.0 and B[3] == 4.0
227
228
229        A = array([1,2,3,4])
230        B = ensure_numeric(A)
231        assert type(B) == ArrayType
232        assert B.typecode() == 'l'       
233        assert A == B   
234        assert A is B   #Same object
235
236
237        A = array([1,2,3,4])
238        B = ensure_numeric(A, Float)
239        assert type(B) == ArrayType
240        assert B.typecode() == 'd'       
241        assert A == B   
242        assert A is not B   #Not the same object       
243
244
245       
246       
247
248    def test_spatio_temporal_file_function_time(self):
249        """Test that File function interpolates correctly
250        between given times.
251        NetCDF version (x,y,t dependency)
252        """
253
254        #Create NetCDF (sww) file to be read
255        # x: 0, 5, 10, 15
256        # y: -20, -10, 0, 10
257        # t: 0, 60, 120, ...., 1200
258        #
259        # test quantities (arbitrary but non-trivial expressions):
260        #
261        #   stage     = 3*x - y**2 + 2*t
262        #   xmomentum = exp( -((x-7)**2 + (y+5)**2)/20 ) * t**2
263        #   ymomentum = x**2 + y**2 * sin(t*pi/600)
264
265        #Nice test that may render some of the others redundant.
266
267        import os, time
268        from config import time_format
269        from Numeric import sin, pi, exp
270        from mesh_factory import rectangular
271        from shallow_water import Domain
272        import data_manager
273
274        finaltime = 1200
275        filename = 'test_file_function'
276
277        #Create a domain to hold test grid
278
279        points, vertices, boundary =\
280                rectangular(4, 4, 15, 30, origin = (0, -20))
281
282
283        #print 'Number of elements', len(vertices)
284        domain = Domain(points, vertices, boundary)
285        domain.smooth = False
286        domain.default_order = 2
287        domain.set_datadir('.')
288        domain.set_name(filename)
289        domain.store = True
290        domain.format = 'sww'   #Native netcdf visualisation format
291
292        #print 'E', domain.get_extent()
293        #print points
294        start = time.mktime(time.strptime('2000', '%Y'))
295        domain.starttime = start
296
297
298        #Store structure
299        domain.initialise_storage()
300
301        #Compute artificial time steps and store
302        dt = 60  #One minute intervals
303        t = 0.0
304        while t <= finaltime:
305            #Compute quantities
306            f1 = lambda x,y: 3*x - y**2 + 2*t + 4
307            domain.set_quantity('stage', f1)
308
309            f2 = lambda x,y: x+y+t**2
310            domain.set_quantity('xmomentum', f2)
311
312            f3 = lambda x,y: x**2 + y**2 * sin(t*pi/600)
313            domain.set_quantity('ymomentum', f3)
314
315            #Store and advance time
316            domain.time = t
317            domain.store_timestep(domain.conserved_quantities)
318            t += dt
319
320
321        interpolation_points = [[0,-20], [1,0], [0,1], [1.1, 3.14], [10,-12.5]]
322
323
324
325        #Set domain.starttime to too early
326        domain.starttime = start - 1
327
328        #Create file function
329        F = file_function(filename + '.sww', domain,
330                          quantities = domain.conserved_quantities,
331                          interpolation_points = interpolation_points)
332
333        #Check that FF updates fixes domain starttime
334        assert allclose(domain.starttime, start)
335
336        #Check that domain.starttime isn't updated if later
337        domain.starttime = start + 1
338        F = file_function(filename + '.sww', domain,
339                          quantities = domain.conserved_quantities,
340                          interpolation_points = interpolation_points)
341        assert allclose(domain.starttime, start+1)
342
343        domain.starttime = start
344
345
346
347        #Check linear interpolation in time
348        #for id in range(len(interpolation_points)):
349        for id in [1]:
350            x = interpolation_points[id][0]
351            y = interpolation_points[id][1]
352
353            for i in range(20):
354                t = i*10
355                k = i%6
356
357                if k == 0:
358                    q0 = F(t, point_id=id)
359                    q1 = F(t+60, point_id=id)
360
361
362                q = F(t, point_id=id)
363                assert allclose(q, (k*q1 + (6-k)*q0)/6)
364
365
366        #Another check of linear interpolation in time
367        for id in range(len(interpolation_points)):
368            q60 = F(60, point_id=id)
369            q120 = F(120, point_id=id)
370
371            t = 90 #Halfway between 60 and 120
372            q = F(t,point_id=id)
373            assert allclose( (q120+q60)/2, q )
374
375            t = 100 #Two thirds of the way between between 60 and 120
376            q = F(t, point_id=id)
377            assert allclose(q60/3 + 2*q120/3, q)
378
379
380
381        #Check that domain.starttime isn't updated if later than file starttime but earlier
382        #than file end time
383        delta = 23
384        domain.starttime = start + delta
385        F = file_function(filename + '.sww', domain,
386                          quantities = domain.conserved_quantities,
387                          interpolation_points = interpolation_points)
388        assert allclose(domain.starttime, start+delta)
389
390
391
392
393        #Now try interpolation with delta offset
394        for id in [1]:
395            x = interpolation_points[id][0]
396            y = interpolation_points[id][1]
397
398            for i in range(20):
399                t = i*10
400                k = i%6
401
402                if k == 0:
403                    q0 = F(t-delta, point_id=id)
404                    q1 = F(t+60-delta, point_id=id)
405
406                q = F(t-delta, point_id=id)
407                assert allclose(q, (k*q1 + (6-k)*q0)/6)
408
409
410        os.remove(filename + '.sww')
411
412
413
414    def test_file_function_time_with_domain(self):
415        """Test that File function interpolates correctly
416        between given times. No x,y dependency here.
417        Use domain with starttime
418        """
419
420        #Write file
421        import os, time, calendar
422        from config import time_format
423        from math import sin, pi
424        from domain import Domain
425
426        finaltime = 1200
427        filename = 'test_file_function.txt'
428        fid = open(filename, 'w')
429        start = time.mktime(time.strptime('2000', '%Y'))
430        dt = 60  #One minute intervals
431        t = 0.0
432        while t <= finaltime:
433            t_string = time.strftime(time_format, time.gmtime(t+start))
434            fid.write('%s, %f %f %f\n' %(t_string, 2*t, t**2, sin(t*pi/600)))
435            t += dt
436
437        fid.close()
438
439        a = [0.0, 0.0]
440        b = [4.0, 0.0]
441        c = [0.0, 3.0]
442
443        points = [a, b, c]
444        vertices = [[0,1,2]]
445        domain = Domain(points, vertices)
446
447        #Check that domain.starttime is updated if non-existing
448        F = file_function(filename, domain)
449        assert allclose(domain.starttime, start)
450
451        #Check that domain.starttime is updated if too early
452        domain.starttime = start - 1
453        F = file_function(filename, domain)
454        assert allclose(domain.starttime, start)
455
456        #Check that domain.starttime isn't updated if later
457        domain.starttime = start + 1
458        F = file_function(filename, domain)
459        assert allclose(domain.starttime, start+1)
460
461        domain.starttime = start
462
463
464        #Now try interpolation
465        for i in range(20):
466            t = i*10
467            q = F(t)
468
469            #Exact linear intpolation
470            assert allclose(q[0], 2*t)
471            if i%6 == 0:
472                assert allclose(q[1], t**2)
473                assert allclose(q[2], sin(t*pi/600))
474
475        #Check non-exact
476
477        t = 90 #Halfway between 60 and 120
478        q = F(t)
479        assert allclose( (120**2 + 60**2)/2, q[1] )
480        assert allclose( (sin(120*pi/600) + sin(60*pi/600))/2, q[2] )
481
482
483        t = 100 #Two thirds of the way between between 60 and 120
484        q = F(t)
485        assert allclose( 2*120**2/3 + 60**2/3, q[1] )
486        assert allclose( 2*sin(120*pi/600)/3 + sin(60*pi/600)/3, q[2] )
487
488        os.remove(filename)
489
490
491    def test_file_function_time_with_domain_different_start(self):
492        """Test that File function interpolates correctly
493        between given times. No x,y dependency here.
494        Use domain with a starttime later than that of file
495
496        ASCII version
497        """
498
499        #Write file
500        import os, time, calendar
501        from config import time_format
502        from math import sin, pi
503        from domain import Domain
504
505        finaltime = 1200
506        filename = 'test_file_function.txt'
507        fid = open(filename, 'w')
508        start = time.mktime(time.strptime('2000', '%Y'))
509        dt = 60  #One minute intervals
510        t = 0.0
511        while t <= finaltime:
512            t_string = time.strftime(time_format, time.gmtime(t+start))
513            fid.write('%s, %f %f %f\n' %(t_string, 2*t, t**2, sin(t*pi/600)))
514            t += dt
515
516        fid.close()
517
518        a = [0.0, 0.0]
519        b = [4.0, 0.0]
520        c = [0.0, 3.0]
521
522        points = [a, b, c]
523        vertices = [[0,1,2]]
524        domain = Domain(points, vertices)
525
526        #Check that domain.starttime isn't updated if later than file starttime but earlier
527        #than file end time
528        delta = 23
529        domain.starttime = start + delta
530        F = file_function(filename, domain)
531        assert allclose(domain.starttime, start+delta)
532
533
534
535
536        #Now try interpolation with delta offset
537        for i in range(20):
538            t = i*10
539            q = F(t-delta)
540
541            #Exact linear intpolation
542            assert allclose(q[0], 2*t)
543            if i%6 == 0:
544                assert allclose(q[1], t**2)
545                assert allclose(q[2], sin(t*pi/600))
546
547        #Check non-exact
548
549        t = 90 #Halfway between 60 and 120
550        q = F(t-delta)
551        assert allclose( (120**2 + 60**2)/2, q[1] )
552        assert allclose( (sin(120*pi/600) + sin(60*pi/600))/2, q[2] )
553
554
555        t = 100 #Two thirds of the way between between 60 and 120
556        q = F(t-delta)
557        assert allclose( 2*120**2/3 + 60**2/3, q[1] )
558        assert allclose( 2*sin(120*pi/600)/3 + sin(60*pi/600)/3, q[2] )
559
560        os.remove(filename)
561
562
563    def test_spatio_temporal_file_function(self):
564        """Test that spatio temporal file function performs the correct
565        interpolations in both time and space
566        """
567        import time
568
569        #Create sww file of simple propagation from left to right
570        #through rectangular domain
571        from shallow_water import Domain, Dirichlet_boundary
572        from mesh_factory import rectangular
573        from Numeric import take, concatenate, reshape
574
575        #Create basic mesh and shallow water domain
576        points, vertices, boundary = rectangular(3, 3)
577        domain1 = Domain(points, vertices, boundary)
578
579        from util import mean
580        domain1.reduction = mean
581        domain1.smooth = True #NOTE: Mimic sww output where each vertex has
582                              # only one value.
583
584        domain1.default_order = 2
585        domain1.store = True
586        domain1.set_datadir('.')
587        domain1.set_name('spatio_temporal_boundary_source_%d' %(id(self)))
588        domain1.quantities_to_be_stored = ['stage', 'xmomentum', 'ymomentum']
589
590        #Bed-slope, friction and IC at vertices (and interpolated elsewhere)
591        domain1.set_quantity('elevation', 0)
592        domain1.set_quantity('friction', 0)
593        domain1.set_quantity('stage', 0)
594
595        # Boundary conditions
596        B0 = Dirichlet_boundary([0,0,0])
597        B6 = Dirichlet_boundary([0.6,0,0])
598        domain1.set_boundary({'left': B6, 'top': B6, 'right': B0, 'bottom': B0})
599        domain1.check_integrity()
600
601        finaltime = 8
602        #Evolution
603        for t in domain1.evolve(yieldstep = 0.1, finaltime = finaltime):
604            pass
605            #domain1.write_time()
606
607
608        #Now read data from sww and check
609        from Scientific.IO.NetCDF import NetCDFFile
610        filename = domain1.get_name() + '.' + domain1.format
611        fid = NetCDFFile(filename)
612
613        x = fid.variables['x'][:]
614        y = fid.variables['y'][:]
615        stage = fid.variables['stage'][:]
616        xmomentum = fid.variables['xmomentum'][:]
617        ymomentum = fid.variables['ymomentum'][:]
618        time = fid.variables['time'][:]
619
620        #Take stage vertex values at last timestep on diagonal
621        #Diagonal is identified by vertices: 0, 5, 10, 15
622
623        timestep = len(time)-1 #Last timestep
624        d_stage = reshape(take(stage[timestep, :], [0,5,10,15]), (4,1))
625        d_uh = reshape(take(xmomentum[timestep, :], [0,5,10,15]), (4,1))
626        d_vh = reshape(take(ymomentum[timestep, :], [0,5,10,15]), (4,1))
627        D = concatenate( (d_stage, d_uh, d_vh), axis=1)
628
629        #Reference interpolated values at midpoints on diagonal at
630        #this timestep are
631        r0 = (D[0] + D[1])/2
632        r1 = (D[1] + D[2])/2
633        r2 = (D[2] + D[3])/2
634
635        #And the midpoints are found now
636        Dx = take(reshape(x, (16,1)), [0,5,10,15])
637        Dy = take(reshape(y, (16,1)), [0,5,10,15])
638
639        diag = concatenate( (Dx, Dy), axis=1)
640        d_midpoints = (diag[1:] + diag[:-1])/2
641
642        #Let us see if the file function can find the correct
643        #values at the midpoints at the last timestep:
644        f = file_function(filename, domain1,
645                          interpolation_points = d_midpoints)
646
647        q = f(timestep/10., point_id=0); assert allclose(r0, q)
648        q = f(timestep/10., point_id=1); assert allclose(r1, q)
649        q = f(timestep/10., point_id=2); assert allclose(r2, q)
650
651
652        ##################
653        #Now do the same for the first timestep
654
655        timestep = 0 #First timestep
656        d_stage = reshape(take(stage[timestep, :], [0,5,10,15]), (4,1))
657        d_uh = reshape(take(xmomentum[timestep, :], [0,5,10,15]), (4,1))
658        d_vh = reshape(take(ymomentum[timestep, :], [0,5,10,15]), (4,1))
659        D = concatenate( (d_stage, d_uh, d_vh), axis=1)
660
661        #Reference interpolated values at midpoints on diagonal at
662        #this timestep are
663        r0 = (D[0] + D[1])/2
664        r1 = (D[1] + D[2])/2
665        r2 = (D[2] + D[3])/2
666
667        #Let us see if the file function can find the correct
668        #values
669        q = f(0, point_id=0); assert allclose(r0, q)
670        q = f(0, point_id=1); assert allclose(r1, q)
671        q = f(0, point_id=2); assert allclose(r2, q)
672
673
674        ##################
675        #Now do it again for a timestep in the middle
676
677        timestep = 33
678        d_stage = reshape(take(stage[timestep, :], [0,5,10,15]), (4,1))
679        d_uh = reshape(take(xmomentum[timestep, :], [0,5,10,15]), (4,1))
680        d_vh = reshape(take(ymomentum[timestep, :], [0,5,10,15]), (4,1))
681        D = concatenate( (d_stage, d_uh, d_vh), axis=1)
682
683        #Reference interpolated values at midpoints on diagonal at
684        #this timestep are
685        r0 = (D[0] + D[1])/2
686        r1 = (D[1] + D[2])/2
687        r2 = (D[2] + D[3])/2
688
689        q = f(timestep/10., point_id=0); assert allclose(r0, q)
690        q = f(timestep/10., point_id=1); assert allclose(r1, q)
691        q = f(timestep/10., point_id=2); assert allclose(r2, q)
692
693
694        ##################
695        #Now check temporal interpolation
696        #Halfway between timestep 15 and 16
697
698        timestep = 15
699        d_stage = reshape(take(stage[timestep, :], [0,5,10,15]), (4,1))
700        d_uh = reshape(take(xmomentum[timestep, :], [0,5,10,15]), (4,1))
701        d_vh = reshape(take(ymomentum[timestep, :], [0,5,10,15]), (4,1))
702        D = concatenate( (d_stage, d_uh, d_vh), axis=1)
703
704        #Reference interpolated values at midpoints on diagonal at
705        #this timestep are
706        r0_0 = (D[0] + D[1])/2
707        r1_0 = (D[1] + D[2])/2
708        r2_0 = (D[2] + D[3])/2
709
710        #
711        timestep = 16
712        d_stage = reshape(take(stage[timestep, :], [0,5,10,15]), (4,1))
713        d_uh = reshape(take(xmomentum[timestep, :], [0,5,10,15]), (4,1))
714        d_vh = reshape(take(ymomentum[timestep, :], [0,5,10,15]), (4,1))
715        D = concatenate( (d_stage, d_uh, d_vh), axis=1)
716
717        #Reference interpolated values at midpoints on diagonal at
718        #this timestep are
719        r0_1 = (D[0] + D[1])/2
720        r1_1 = (D[1] + D[2])/2
721        r2_1 = (D[2] + D[3])/2
722
723        # The reference values are
724        r0 = (r0_0 + r0_1)/2
725        r1 = (r1_0 + r1_1)/2
726        r2 = (r2_0 + r2_1)/2
727
728        q = f((timestep - 0.5)/10., point_id=0); assert allclose(r0, q)
729        q = f((timestep - 0.5)/10., point_id=1); assert allclose(r1, q)
730        q = f((timestep - 0.5)/10., point_id=2); assert allclose(r2, q)
731
732        ##################
733        #Finally check interpolation 2 thirds of the way
734        #between timestep 15 and 16
735
736        # The reference values are
737        r0 = (r0_0 + 2*r0_1)/3
738        r1 = (r1_0 + 2*r1_1)/3
739        r2 = (r2_0 + 2*r2_1)/3
740
741        #And the file function gives
742        q = f((timestep - 1.0/3)/10., point_id=0); assert allclose(r0, q)
743        q = f((timestep - 1.0/3)/10., point_id=1); assert allclose(r1, q)
744        q = f((timestep - 1.0/3)/10., point_id=2); assert allclose(r2, q)
745
746        fid.close()
747        import os
748        os.remove(filename)
749
750
751    def test_xya_ascii(self):
752        import time, os
753        FN = 'xyatest' + str(time.time()) + '.xya'
754        fid = open(FN, 'w')
755        fid.write('      %s %s %s\n' %('a1', 'a2', 'a3') )
756        fid.write('%f %f %f %f %f\n' %(0,1,10,20,30) )
757        fid.write('%f %f %f %f %f\n' %(1,0,30,20,10) )
758        fid.write('%f %f %f %f %f\n' %(1,1,40.2,40.3,40.4) )
759        fid.close()
760
761        points, attributes = read_xya(FN, format = 'asc')
762
763        assert allclose(points, [ [0,1], [1,0], [1,1] ])
764        assert allclose(attributes['a1'], [10,30,40.2])
765        assert allclose(attributes['a2'], [20,20,40.3])
766        assert allclose(attributes['a3'], [30,10,40.4])
767
768        os.remove(FN)
769
770    def test_xya_ascii_w_names(self):
771        import time, os
772        FN = 'xyatest' + str(time.time()) + '.xya'
773        fid = open(FN, 'w')
774        fid.write('      %s %s %s\n' %('a1', 'a2', 'a3') )
775        fid.write('%f %f %f %f %f\n' %(0,1,10,20,30) )
776        fid.write('%f %f %f %f %f\n' %(1,0,30,20,10) )
777        fid.write('%f %f %f %f %f\n' %(1,1,40.2,40.3,40.4) )
778        fid.close()
779
780        points, attributes = read_xya(FN, format = 'asc')
781
782        assert allclose(points, [ [0,1], [1,0], [1,1] ])
783
784        assert allclose(attributes['a1'], [10,30,40.2])
785        assert allclose(attributes['a2'], [20,20,40.3])
786        assert allclose(attributes['a3'], [30,10,40.4])
787
788
789        os.remove(FN)
790
791
792
793
794    #Polygon stuff
795    def test_polygon_function_constants(self):
796        p1 = [[0,0], [10,0], [10,10], [0,10]]
797        p2 = [[0,0], [10,10], [15,5], [20, 10], [25,0], [30,10], [40,-10]]
798
799        f = Polygon_function( [(p1, 1.0)] )
800        z = f([5, 5, 27, 35], [5, 9, 8, -5]) #Two first inside p1
801        assert allclose(z, [1,1,0,0])
802
803
804        f = Polygon_function( [(p2, 2.0)] )
805        z = f([5, 5, 27, 35], [5, 9, 8, -5]) #First and last inside p2
806        assert allclose(z, [2,0,0,2])
807
808
809        #Combined
810        f = Polygon_function( [(p1, 1.0), (p2, 2.0)] )
811        z = f([5, 5, 27, 35], [5, 9, 8, -5])
812        assert allclose(z, [2,1,0,2])
813
814
815    def test_polygon_function_callable(self):
816        """Check that values passed into Polygon_function can be callable
817        themselves.
818        """
819        p1 = [[0,0], [10,0], [10,10], [0,10]]
820        p2 = [[0,0], [10,10], [15,5], [20, 10], [25,0], [30,10], [40,-10]]
821
822        f = Polygon_function( [(p1, test_function)] )
823        z = f([5, 5, 27, 35], [5, 9, 8, -5]) #Two first inside p1
824        assert allclose(z, [10,14,0,0])
825
826        #Combined
827        f = Polygon_function( [(p1, test_function), (p2, 2.0)] )
828        z = f([5, 5, 27, 35], [5, 9, 8, -5])
829        assert allclose(z, [2,14,0,2])
830
831
832        #Combined w default
833        f = Polygon_function( [(p1, test_function), (p2, 2.0)], default = 3.14)
834        z = f([5, 5, 27, 35], [5, 9, 8, -5])
835        assert allclose(z, [2,14,3.14,2])
836
837
838        #Combined w default func
839        f = Polygon_function( [(p1, test_function), (p2, 2.0)],
840                              default = test_function)
841        z = f([5, 5, 27, 35], [5, 9, 8, -5])
842        assert allclose(z, [2,14,35,2])
843
844
845    def test_point_on_line(self):
846
847        #Endpoints first
848        assert point_on_line( 0, 0, 0,0, 1,0 )
849        assert point_on_line( 1, 0, 0,0, 1,0 )
850
851        #Then points on line
852        assert point_on_line( 0.5, 0, 0,0, 1,0 )
853        assert point_on_line( 0, 0.5, 0,1, 0,0 )
854        assert point_on_line( 1, 0.5, 1,1, 1,0 )
855        assert point_on_line( 0.5, 0.5, 0,0, 1,1 )
856
857        #Then points not on line
858        assert not point_on_line( 0.5, 0, 0,1, 1,1 )
859        assert not point_on_line( 0, 0.5, 0,0, 1,1 )
860
861        #From real example that failed
862        assert not point_on_line( 40,50, 40,20, 40,40 )
863
864
865        #From real example that failed
866        assert not point_on_line( 40,19, 40,20, 40,40 )
867
868
869
870
871    def test_inside_polygon_main(self):
872
873
874        #Simplest case: Polygon is the unit square
875        polygon = [[0,0], [1,0], [1,1], [0,1]]
876
877        assert inside_polygon( (0.5, 0.5), polygon )
878        assert not inside_polygon( (0.5, 1.5), polygon )
879        assert not inside_polygon( (0.5, -0.5), polygon )
880        assert not inside_polygon( (-0.5, 0.5), polygon )
881        assert not inside_polygon( (1.5, 0.5), polygon )
882
883        #Try point on borders
884        assert inside_polygon( (1., 0.5), polygon, closed=True)
885        assert inside_polygon( (0.5, 1), polygon, closed=True)
886        assert inside_polygon( (0., 0.5), polygon, closed=True)
887        assert inside_polygon( (0.5, 0.), polygon, closed=True)
888
889        assert not inside_polygon( (0.5, 1), polygon, closed=False)
890        assert not inside_polygon( (0., 0.5), polygon, closed=False)
891        assert not inside_polygon( (0.5, 0.), polygon, closed=False)
892        assert not inside_polygon( (1., 0.5), polygon, closed=False)
893
894
895
896        #From real example (that failed)
897        polygon = [[20,20], [40,20], [40,40], [20,40]]
898        points = [ [40, 50] ]
899        res = inside_polygon(points, polygon)
900        assert len(res) == 0
901
902        polygon = [[20,20], [40,20], [40,40], [20,40]]
903        points = [ [25, 25], [30, 20], [40, 50], [90, 20], [40, 90] ]
904        res = inside_polygon(points, polygon)
905        assert len(res) == 2
906        assert allclose(res, [0,1])
907
908
909
910        #More convoluted and non convex polygon
911        polygon = [[0,0], [1,0], [0.5,-1], [2, -1], [2,1], [0,1]]
912        assert inside_polygon( (0.5, 0.5), polygon )
913        assert inside_polygon( (1, -0.5), polygon )
914        assert inside_polygon( (1.5, 0), polygon )
915
916        assert not inside_polygon( (0.5, 1.5), polygon )
917        assert not inside_polygon( (0.5, -0.5), polygon )
918
919
920        #Very convoluted polygon
921        polygon = [[0,0], [10,10], [15,5], [20, 10], [25,0], [30,10], [40,-10]]
922        assert inside_polygon( (5, 5), polygon )
923        assert inside_polygon( (17, 7), polygon )
924        assert inside_polygon( (27, 2), polygon )
925        assert inside_polygon( (35, -5), polygon )
926        assert not inside_polygon( (15, 7), polygon )
927        assert not inside_polygon( (24, 3), polygon )
928        assert not inside_polygon( (25, -10), polygon )
929
930
931
932        #Another combination (that failed)
933        polygon = [[0,0], [10,0], [10,10], [0,10]]
934        assert inside_polygon( (5, 5), polygon )
935        assert inside_polygon( (7, 7), polygon )
936        assert not inside_polygon( (-17, 7), polygon )
937        assert not inside_polygon( (7, 17), polygon )
938        assert not inside_polygon( (17, 7), polygon )
939        assert not inside_polygon( (27, 8), polygon )
940        assert not inside_polygon( (35, -5), polygon )
941
942
943
944
945        #Multiple polygons
946
947        polygon = [[0,0], [1,0], [1,1], [0,1], [0,0],
948                   [10,10], [11,10], [11,11], [10,11], [10,10]]
949        assert inside_polygon( (0.5, 0.5), polygon )
950        assert inside_polygon( (10.5, 10.5), polygon )
951
952        #FIXME: Fails if point is 5.5, 5.5
953        assert not inside_polygon( (0, 5.5), polygon )
954
955        #Polygon with a hole
956        polygon = [[-1,-1], [2,-1], [2,2], [-1,2], [-1,-1],
957                   [0,0], [1,0], [1,1], [0,1], [0,0]]
958
959        assert inside_polygon( (0, -0.5), polygon )
960        assert not inside_polygon( (0.5, 0.5), polygon )
961
962    def test_inside_polygon_vector_version(self):
963        #Now try the vector formulation returning indices
964        polygon = [[0,0], [1,0], [0.5,-1], [2, -1], [2,1], [0,1]]
965        points = [ [0.5, 0.5], [1, -0.5], [1.5, 0], [0.5, 1.5], [0.5, -0.5]]
966        res = inside_polygon( points, polygon, verbose=False )
967
968        assert allclose( res, [0,1,2] )
969
970    def test_outside_polygon(self):
971        U = [[0,0], [1,0], [1,1], [0,1]] #Unit square   
972
973        assert not outside_polygon( [0.5, 0.5], U )
974        #evaluate to False as the point 0.5, 0.5 is inside the unit square
975       
976        assert outside_polygon( [1.5, 0.5], U )
977        #evaluate to True as the point 1.5, 0.5 is outside the unit square
978       
979        indices = outside_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U )
980        assert allclose( indices, [1] )
981       
982        #One more test of vector formulation returning indices
983        polygon = [[0,0], [1,0], [0.5,-1], [2, -1], [2,1], [0,1]]
984        points = [ [0.5, 0.5], [1, -0.5], [1.5, 0], [0.5, 1.5], [0.5, -0.5]]
985        res = outside_polygon( points, polygon )
986
987        assert allclose( res, [3, 4] )
988
989
990
991        polygon = [[0,0], [1,0], [0.5,-1], [2, -1], [2,1], [0,1]]
992        points = [ [0.5, 1.4], [0.5, 0.5], [1, -0.5], [1.5, 0], [0.5, 1.5], [0.5, -0.5]]
993        res = outside_polygon( points, polygon )
994
995        assert allclose( res, [0, 4, 5] )       
996     
997    def test_outside_polygon2(self):
998        U = [[0,0], [1,0], [1,1], [0,1]] #Unit square   
999   
1000        assert not outside_polygon( [0.5, 1.0], U, closed = True )
1001        #evaluate to False as the point 0.5, 1.0 is inside the unit square
1002       
1003        assert outside_polygon( [0.5, 1.0], U, closed = False )
1004        #evaluate to True as the point 0.5, 1.0 is outside the unit square
1005
1006    def test_separate_points_by_polygon(self):
1007        U = [[0,0], [1,0], [1,1], [0,1]] #Unit square   
1008
1009        indices, count = separate_points_by_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U )
1010        assert allclose( indices, [0,2,1] )
1011        assert count == 2
1012       
1013        #One more test of vector formulation returning indices
1014        polygon = [[0,0], [1,0], [0.5,-1], [2, -1], [2,1], [0,1]]
1015        points = [ [0.5, 0.5], [1, -0.5], [1.5, 0], [0.5, 1.5], [0.5, -0.5]]
1016        res, count = separate_points_by_polygon( points, polygon )
1017
1018        assert allclose( res, [0,1,2,4,3] )
1019        assert count == 3
1020
1021
1022        polygon = [[0,0], [1,0], [0.5,-1], [2, -1], [2,1], [0,1]]
1023        points = [ [0.5, 1.4], [0.5, 0.5], [1, -0.5], [1.5, 0], [0.5, 1.5], [0.5, -0.5]]
1024        res, count = separate_points_by_polygon( points, polygon )
1025
1026        assert allclose( res, [1,2,3,5,4,0] )       
1027        assert count == 3
1028       
1029
1030    def test_populate_polygon(self):
1031
1032        polygon = [[0,0], [1,0], [1,1], [0,1]]
1033        points = populate_polygon(polygon, 5)
1034
1035        assert len(points) == 5
1036        for point in points:
1037            assert inside_polygon(point, polygon)
1038
1039
1040        #Very convoluted polygon
1041        polygon = [[0,0], [10,10], [15,5], [20, 10], [25,0], [30,10], [40,-10]]
1042
1043        points = populate_polygon(polygon, 5)
1044
1045        assert len(points) == 5
1046        for point in points:
1047            assert inside_polygon(point, polygon)
1048
1049
1050
1051#-------------------------------------------------------------
1052if __name__ == "__main__":
1053    #suite = unittest.makeSuite(TestCase,'test_inside_polygon_main')
1054    suite = unittest.makeSuite(Test_Util,'test')
1055    runner = unittest.TextTestRunner()
1056    runner.run(suite)
1057
1058
1059
1060
Note: See TracBrowser for help on using the repository browser.