Changeset 1387
- Timestamp:
- May 13, 2005, 6:15:08 PM (19 years ago)
- Location:
- inundation/ga/storm_surge
- Files:
-
- 17 edited
Legend:
- Unmodified
- Added
- Removed
-
inundation/ga/storm_surge/parallel/parallel_advection.py
r1363 r1387 14 14 """ 15 15 16 #Subversion keywords: 17 # 18 #$LastChangedDate: $ 19 #$LastChangedRevision: $ 20 #$LastChangedBy: $ 16 from advection import * 17 Advection_Domain = Domain 18 from Numeric import zeros, Float, Int 21 19 22 class Parallel_Domain( Domain):20 class Parallel_Domain(Advection_Domain): 23 21 24 def __init__(self, coordinates, vertices, boundary = None, velocity = None): 22 def __init__(self, coordinates, vertices, boundary = None, velocity = None, 23 processor = 0, global_ids = None): 25 24 25 Advection_Domain.__init__(self, coordinates, vertices, boundary, velocity) 26 26 27 Generic_domain.__init__(self, coordinates, vertices, boundary, 28 ['stage']) 27 self.processor = processor 29 28 30 if velocity is None: 31 self.velocity = [1,0] 29 N = self.number_of_elements 30 31 if global_ids == None: 32 self.global_ids = global_ids 32 33 else: 33 self.velocity = velocity 34 35 #Only first is implemented for advection 36 self.default_order = self.order = 1 37 38 #Realtime visualisation 39 self.visualise = False 40 self.visualise_color_stage = False 41 self.visualise_timer = True 42 self.visualise_range_z = None 43 self.smooth = True 44 34 self.global_ids = zeros(N, Int) 45 35 46 36 47 37 def check_integrity(self): 48 Generic_domain.check_integrity(self)38 Advection_Domain.check_integrity(self) 49 39 50 msg = ' Conserved quantity must be "stage"'40 msg = 'Will need to check global and local numbering' 51 41 assert self.conserved_quantities[0] == 'stage', msg 52 42 53 54 def flux_function(self, normal, ql, qr, zl=None, zr=None):55 """Compute outward flux as inner product between velocity56 vector v=(v_1, v_2) and normal vector n.57 58 if <n,v> > 0 flux direction is outward bound and its magnitude is59 determined by the quantity inside volume: ql.60 Otherwise it is inbound and magnitude is determined by the61 quantity outside the volume: qr.62 """63 64 v1 = self.velocity[0]65 v2 = self.velocity[1]66 67 68 normal_velocity = v1*normal[0] + v2*normal[1]69 70 if normal_velocity < 0:71 flux = qr * normal_velocity72 else:73 flux = ql * normal_velocity74 75 max_speed = abs(normal_velocity)76 return flux, max_speed77 78 79 def compute_fluxes(self):80 """Compute all fluxes and the timestep suitable for all volumes81 in domain.82 83 Compute total flux for each conserved quantity using "flux_function"84 85 Fluxes across each edge are scaled by edgelengths and summed up86 Resulting flux is then scaled by area and stored in87 domain.explicit_update88 89 The maximal allowable speed computed by the flux_function90 for each volume91 is converted to a timestep that must not be exceeded. The minimum of92 those is computed as the next overall timestep.93 94 Post conditions:95 domain.explicit_update is reset to computed flux values96 domain.timestep is set to the largest step satisfying all volumes.97 """98 99 import sys100 from Numeric import zeros, Float101 from config import max_timestep102 103 N = self.number_of_elements104 105 neighbours = self.neighbours106 neighbour_edges = self.neighbour_edges107 normals = self.normals108 109 areas = self.areas110 radii = self.radii111 edgelengths = self.edgelengths112 113 timestep = max_timestep #FIXME: Get rid of this114 115 #Shortcuts116 Stage = self.quantities['stage']117 118 #Arrays119 stage = Stage.edge_values120 121 stage_bdry = Stage.boundary_values122 123 flux = zeros(1, Float) #Work array for summing up fluxes124 125 #Loop126 for k in range(N):127 optimal_timestep = float(sys.maxint)128 129 flux[:] = 0. #Reset work array130 for i in range(3):131 #Quantities inside volume facing neighbour i132 ql = stage[k, i]133 134 #Quantities at neighbour on nearest face135 n = neighbours[k,i]136 if n < 0:137 m = -n-1 #Convert neg flag to index138 qr = stage_bdry[m]139 else:140 m = neighbour_edges[k,i]141 qr = stage[n, m]142 143 144 #Outward pointing normal vector145 normal = normals[k, 2*i:2*i+2]146 147 #Flux computation using provided function148 edgeflux, max_speed = self.flux_function(normal, ql, qr)149 flux -= edgeflux * edgelengths[k,i]150 151 #Update optimal_timestep152 try:153 optimal_timestep = min(optimal_timestep, radii[k]/max_speed)154 except ZeroDivisionError:155 pass156 157 #Normalise by area and store for when all conserved158 #quantities get updated159 flux /= areas[k]160 Stage.explicit_update[k] = flux[0]161 162 timestep = min(timestep, optimal_timestep)163 164 self.timestep = timestep165 43 166 44 … … 173 51 if self.visualise is True and self.time == 0.0: 174 52 import realtime_visualisation_new as visualise 175 visualise.create_surface(self)53 self.visualiser = visualise.Visualiser(self) 176 54 177 55 #Call basic machinery from parent class 178 for t in Generic_domain.evolve(self, yieldstep, finaltime):56 for t in Advection_Domain.evolve(self, yieldstep, finaltime): 179 57 #Real time viz 180 58 if self.visualise is True: 181 visualise.update(self)59 self.visualiser.update_quantity('stage') 182 60 183 61 #Pass control on to outer loop for more specific actions 184 62 yield(t) 63 64 65 66 def rectangular_with_ghosts(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)): 67 68 """Setup a rectangular grid of triangles 69 with m+1 by n+1 grid points 70 and side lengths len1, len2. If side lengths are omitted 71 the mesh defaults to the unit square. 72 73 len1: x direction (left to right) 74 len2: y direction (bottom to top) 75 76 Also returns a list of 77 78 Return to lists: points and elements suitable for creating a Mesh or 79 FVMesh object, e.g. Mesh(points, elements) 80 """ 81 82 from config import epsilon 83 84 #E = m*n*2 #Number of triangular elements 85 #P = (m+1)*(n+1) #Number of initial vertices 86 87 delta1 = float(len1)/m 88 delta2 = float(len2)/n 89 90 #Dictionary of vertex objects 91 vertices = {} 92 points = [] 93 94 for i in range(m+1): 95 for j in range(n+1): 96 vertices[i,j] = len(points) 97 points.append([i*delta1 + origin[0], j*delta2 + origin[1]]) 98 99 100 101 #Construct 2 triangles per rectangular element and assign tags to boundary 102 elements = [] 103 boundary = {} 104 for i in range(m): 105 for j in range(n): 106 v1 = vertices[i,j+1] 107 v2 = vertices[i,j] 108 v3 = vertices[i+1,j+1] 109 v4 = vertices[i+1,j] 110 111 #Update boundary dictionary and create elements 112 if i == m-1: 113 boundary[(len(elements), 2)] = 'right' 114 if j == 0: 115 boundary[(len(elements), 1)] = 'bottom' 116 elements.append([v4,v3,v2]) #Lower element 117 118 if i == 0: 119 boundary[(len(elements), 2)] = 'left' 120 if j == n-1: 121 boundary[(len(elements), 1)] = 'top' 122 elements.append([v1,v2,v3]) #Upper element 123 124 ghosts = {} 125 i=0 126 for j in range(n): 127 v1 = vertices[i,j+1] 128 v2 = vertices[i,j] 129 v3 = vertices[i+1,j+1] 130 v4 = vertices[i+1,j] 131 ghosts.append(elements.index([ 132 133 return points, elements, boundary -
inundation/ga/storm_surge/parallel/run_advection.py
r1363 r1387 19 19 20 20 domain.visualise = True 21 #domain.visualise_range_z = 1.0 22 domain.visualise_color_stage = True21 domain.visualise_range_z = 0.5 22 #domain.visualise_color_stage = True 23 23 24 24 -
inundation/ga/storm_surge/parallel/run_parallel_advection.py
r1363 r1387 6 6 from config import g, epsilon 7 7 from Numeric import allclose, array, zeros, ones, Float 8 from advection import *8 from parallel_advection import * 9 9 from Numeric import array 10 10 11 11 from mesh_factory import rectangular 12 12 13 points, vertices, boundary = rectangular( 60, 60)13 points, vertices, boundary = rectangular(30, 30) 14 14 15 15 #Create advection domain with direction (1,-1) 16 domain = Domain(points, vertices, boundary, velocity=[1.0, 0.0])16 domain = Parallel_Domain(points, vertices, boundary, velocity=[1.0, 0.0]) 17 17 18 18 # Initial condition is zero by default … … 29 29 30 30 31 domain.set_boundary( {'left': D, 'right': T, 'bottom': T, 'top': T} )31 domain.set_boundary( {'left': T, 'right': T, 'bottom': T, 'top': T} ) 32 32 domain.check_integrity() 33 34 class Set_Stage: 35 """Set an initial condition with constant water height, for x<x0 36 """ 37 38 def __init__(self, x0=0.25, x1=0.5, h=1.0): 39 self.x0 = x0 40 self.x1 = x1 41 self.h = h 42 43 def __call__(self, x, y): 44 return self.h*((x>self.x0)&(x<self.x1)) 45 46 domain.set_quantity('stage', Set_Stage(0.2,0.4,1.0)) 33 47 34 48 #Check that the boundary value gets propagated to all elements -
inundation/ga/storm_surge/parallel/small.tsh
r1363 r1387 1 1 31 0 # <# of verts> <# of vert attributes>, next lines <vertex #> <x> <y> [attributes] ...Triangulation Vertices... 2 0 554.0 -242.0 3 1 443.0 -190.0 4 2 340.0 -184.0 5 3 276.0 -237.0 6 4 281.0 -347.0 7 5 282.0 -380.0 8 6 312.0 -425.0 9 7 387.0 -472.0 10 8 465.0 -487.0 11 9 549.0 -469.0 12 10 566.0 -413.0 13 11 589.0 -359.0 14 12 472.0 -258.0 15 13 377.0 -411.0 16 14 428.0 -257.0 17 15 386.0 -278.0 18 16 372.0 -325.0 19 17 369.0 -371.0 20 18 433.0 -422.0 21 19 476.0 -361.0 22 20 502.0 -304.0 23 21 333.0 -225.0 24 22 305.0 -244.0 25 23 333.0 -270.0 26 24 369.0 -237.0 27 25 278.5 -292.0 28 26 499.90712817 -423.516449623 29 27 532.621862616 -366.885237781 30 28 498.5 -216.0 31 29 322.359287054 -318.872505543 32 30 571.5 -300.5 2 0 554.0 -242.0 3 1 443.0 -190.0 4 2 340.0 -184.0 5 3 276.0 -237.0 6 4 281.0 -347.0 7 5 282.0 -380.0 8 6 312.0 -425.0 9 7 387.0 -472.0 10 8 465.0 -487.0 11 9 549.0 -469.0 12 10 566.0 -413.0 13 11 589.0 -359.0 14 12 472.0 -258.0 15 13 377.0 -411.0 16 14 428.0 -257.0 17 15 386.0 -278.0 18 16 372.0 -325.0 19 17 369.0 -371.0 20 18 433.0 -422.0 21 19 476.0 -361.0 22 20 502.0 -304.0 23 21 333.0 -225.0 24 22 305.0 -244.0 25 23 333.0 -270.0 26 24 369.0 -237.0 27 25 278.5 -292.0 28 26 499.90712817 -423.516449623 29 27 532.621862616 -366.885237781 30 28 498.5 -216.0 31 29 322.359287054 -318.872505543 32 30 571.5 -300.5 33 33 # attribute column titles ...Triangulation Vertex Titles... 34 34 38 # <# of triangles>, next lines <triangle #> [<vertex #>] [<neigbouring triangle #>] [attribute of region] ...Triangulation Triangles... 35 0 29 5 17 1 5 26 36 1 17 5 6 -1 3 0 37 2 10 11 27 28 21 -1 38 3 13 17 6 1 6 -1 39 4 15 23 16 24 -1 16 40 5 16 29 17 0 -1 24 41 6 6 7 13 37 3 -1 42 7 29 23 25 9 8 24 43 8 25 4 29 26 7 -1 44 9 25 23 22 10 18 7 45 10 22 23 21 13 11 9 46 11 3 22 21 10 15 18 47 12 21 24 2 14 15 13 48 13 24 21 23 10 16 12 49 14 2 24 1 27 -1 12 50 15 21 2 3 -1 11 12 51 16 24 23 15 4 30 13 52 17 27 30 20 31 36 28 53 18 22 3 25 -1 9 11 54 19 7 8 18 35 37 -1 55 20 8 9 26 23 35 -1 56 21 26 10 27 2 25 23 57 22 26 19 18 -1 35 25 58 23 10 26 9 20 -1 21 59 24 16 23 29 7 5 4 60 25 26 27 19 36 22 21 61 26 29 4 5 -1 0 8 62 27 14 1 24 14 30 29 63 28 27 11 30 -1 17 2 64 29 1 14 12 -1 33 27 65 30 14 24 15 16 -1 27 66 31 20 30 0 -1 34 17 67 32 12 0 28 -1 33 34 68 33 12 28 1 -1 29 32 69 34 0 12 20 -1 31 32 70 35 8 26 18 22 19 20 71 36 27 20 19 -1 25 17 72 37 18 13 7 6 19 -1 35 0 29 5 17 1 5 26 building 36 1 17 5 6 -1 3 0 37 2 10 11 27 28 21 -1 38 3 13 17 6 1 6 -1 39 4 15 23 16 24 -1 16 40 5 16 29 17 0 -1 24 41 6 6 7 13 37 3 -1 42 7 29 23 25 9 8 24 43 8 25 4 29 26 7 -1 44 9 25 23 22 10 18 7 45 10 22 23 21 13 11 9 building 46 11 3 22 21 10 15 18 47 12 21 24 2 14 15 13 48 13 24 21 23 10 16 12 49 14 2 24 1 27 -1 12 50 15 21 2 3 -1 11 12 51 16 24 23 15 4 30 13 52 17 27 30 20 31 36 28 house 53 18 22 3 25 -1 9 11 54 19 7 8 18 35 37 -1 55 20 8 9 26 23 35 -1 56 21 26 10 27 2 25 23 57 22 26 19 18 -1 35 25 building 58 23 10 26 9 20 -1 21 59 24 16 23 29 7 5 4 60 25 26 27 19 36 22 21 61 26 29 4 5 -1 0 8 62 27 14 1 24 14 30 29 house 63 28 27 11 30 -1 17 2 64 29 1 14 12 -1 33 27 oval 65 30 14 24 15 16 -1 27 66 31 20 30 0 -1 34 17 67 32 12 0 28 -1 33 34 68 33 12 28 1 -1 29 32 69 34 0 12 20 -1 31 32 70 35 8 26 18 22 19 20 71 36 27 20 19 -1 25 17 72 37 18 13 7 6 19 -1 73 73 28 # <# of segments>, next lines <segment #> <vertex #> <vertex #> [boundary tag] ...Triangulation Segments... 74 74 0 14 12 exterior … … 81 81 7 19 20 exterior 82 82 8 12 20 exterior 83 9 21 22 84 10 23 22 85 11 23 24 86 12 21 24 83 9 21 22 84 10 23 22 85 11 23 24 86 12 21 24 87 87 13 4 25 exterior 88 88 14 7 6 exterior … … 101 101 27 30 11 exterior 102 102 25 0 # <# of verts> <# of vert attributes>, next lines <vertex #> <x> <y> [attributes] ...Mesh Vertices... 103 0 554.0 -242.0 104 1 443.0 -190.0 105 2 340.0 -184.0 106 3 276.0 -237.0 107 4 281.0 -347.0 108 5 282.0 -380.0 109 6 312.0 -425.0 110 7 387.0 -472.0 111 8 465.0 -487.0 112 9 549.0 -469.0 113 10 566.0 -413.0 114 11 589.0 -359.0 115 12 472.0 -258.0 116 13 377.0 -411.0 117 14 428.0 -257.0 118 15 386.0 -278.0 119 16 372.0 -325.0 120 17 369.0 -371.0 121 18 433.0 -422.0 122 19 476.0 -361.0 123 20 502.0 -304.0 124 21 333.0 -225.0 125 22 305.0 -244.0 126 23 333.0 -270.0 127 24 369.0 -237.0 103 0 554.0 -242.0 104 1 443.0 -190.0 105 2 340.0 -184.0 106 3 276.0 -237.0 107 4 281.0 -347.0 108 5 282.0 -380.0 109 6 312.0 -425.0 110 7 387.0 -472.0 111 8 465.0 -487.0 112 9 549.0 -469.0 113 10 566.0 -413.0 114 11 589.0 -359.0 115 12 472.0 -258.0 116 13 377.0 -411.0 117 14 428.0 -257.0 118 15 386.0 -278.0 119 16 372.0 -325.0 120 17 369.0 -371.0 121 18 433.0 -422.0 122 19 476.0 -361.0 123 20 502.0 -304.0 124 21 333.0 -225.0 125 22 305.0 -244.0 126 23 333.0 -270.0 127 24 369.0 -237.0 128 128 25 # <# of segments>, next lines <segment #> <vertex #> <vertex #> [boundary tag] ...Mesh Segments... 129 0 14 12 130 1 15 14 131 2 16 15 132 3 17 16 133 4 13 17 134 5 18 13 135 6 19 18 136 7 20 19 137 8 12 20 138 9 22 21 139 10 23 22 140 11 24 23 141 12 21 24 142 13 3 4 143 14 6 7 144 15 5 6 145 16 2 3 146 17 4 5 147 18 7 8 148 19 9 10 149 20 8 9 150 21 0 1 151 22 1 2 152 23 11 0 153 24 10 11 129 0 14 12 130 1 15 14 131 2 16 15 132 3 17 16 133 4 13 17 134 5 18 13 135 6 19 18 136 7 20 19 137 8 12 20 138 9 22 21 139 10 23 22 140 11 24 23 141 12 21 24 142 13 3 4 143 14 6 7 144 15 5 6 145 16 2 3 146 17 4 5 147 18 7 8 148 19 9 10 149 20 8 9 150 21 0 1 151 22 1 2 152 23 11 0 153 24 10 11 154 154 1 # <# of holes>, next lines <Hole #> <x> <y> ...Mesh Holes... 155 155 0 418.0 -332.0 156 156 1 # <# of regions>, next lines <Region #> <x> <y> <tag>...Mesh Regions... 157 0 334.0 -243.0 157 0 334.0 -243.0 158 158 1 # <# of regions>, next lines <Region #> [Max Area] ...Mesh Regions... 159 0 159 0 160 160 # Geo reference 161 161 56 -
inundation/ga/storm_surge/pyvolution/domain.py
r1360 r1387 260 260 x = self.boundary.keys() 261 261 x.sort() 262 262 263 for k, (vol_id, edge_id) in enumerate(x): 263 264 tag = self.boundary[ (vol_id, edge_id) ] -
inundation/ga/storm_surge/pyvolution/general_mesh.py
r1178 r1387 6 6 7 7 A triangular element is defined in terms of three vertex ids, 8 ordered counter clock-wise, 8 ordered counter clock-wise, 9 9 each corresponding to a given coordinate set. 10 10 Vertices from different elements can point to the same … … 12 12 13 13 Coordinate sets are implemented as an N x 2 Numeric array containing 14 x and y coordinates. 15 14 x and y coordinates. 15 16 16 17 17 To instantiate: … … 33 33 c = [2.0,0.0] 34 34 e = [2.0, 2.0] 35 35 36 36 points = [a, b, c, e] 37 triangles = [ [1,0,2], [1,2,3] ] #bac, bce 37 triangles = [ [1,0,2], [1,2,3] ] #bac, bce 38 38 mesh = Mesh(points, triangles) 39 39 40 40 #creates two triangles: bac and bce 41 41 42 42 Other: 43 43 44 44 In addition mesh computes an Nx6 array called vertex_coordinates. 45 This structure is derived from coordinates and contains for each 45 This structure is derived from coordinates and contains for each 46 46 triangle the three x,y coordinates at the vertices. 47 48 49 This is a cut down version of mesh from pyvolution \mesh.py47 48 49 This is a cut down version of mesh from pyvolution mesh.py 50 50 """ 51 51 … … 58 58 59 59 origin is a 3-tuple consisting of UTM zone, easting and northing. 60 If specified coordinates are assumed to be relative to this origin. 60 If specified coordinates are assumed to be relative to this origin. 61 61 """ 62 62 … … 67 67 68 68 if geo_reference is None: 69 self.geo_reference = Geo_reference(DEFAULT_ZONE,0.0,0.0) 69 self.geo_reference = Geo_reference(DEFAULT_ZONE,0.0,0.0) 70 70 else: 71 71 self.geo_reference = geo_reference 72 72 73 73 #Input checks 74 msg = 'Triangles must an Nx 2 Numeric array or a sequence of 2-tuples'74 msg = 'Triangles must an Nx3 Numeric array or a sequence of 3-tuples' 75 75 assert len(self.triangles.shape) == 2, msg 76 76 77 77 msg = 'Coordinates must an Mx2 Numeric array or a sequence of 2-tuples' 78 assert len(self.coordinates.shape) == 2, msg 78 assert len(self.coordinates.shape) == 2, msg 79 79 80 80 msg = 'Vertex indices reference non-existing coordinate sets' … … 84 84 #Register number of elements (N) 85 85 self.number_of_elements = N = self.triangles.shape[0] 86 87 #Allocate space for geometric quantities 86 87 #Allocate space for geometric quantities 88 88 self.normals = zeros((N, 6), Float) 89 89 self.areas = zeros(N, Float) … … 92 92 #Get x,y coordinates for all triangles and store 93 93 self.vertex_coordinates = V = self.compute_vertex_coordinates() 94 94 95 95 #Initialise each triangle 96 96 for i in range(N): 97 97 #if i % (N/10) == 0: print '(%d/%d)' %(i, N) 98 98 99 99 x0 = V[i, 0]; y0 = V[i, 1] 100 100 x1 = V[i, 2]; y1 = V[i, 3] 101 x2 = V[i, 4]; y2 = V[i, 5] 101 x2 = V[i, 4]; y2 = V[i, 5] 102 102 103 103 #Area … … 107 107 msg += ' is degenerate: area == %f' %self.areas[i] 108 108 assert self.areas[i] > 0.0, msg 109 109 110 110 111 111 #Normals … … 120 120 121 121 n0 = array([x2 - x1, y2 - y1]) 122 122 l0 = sqrt(sum(n0**2)) 123 123 124 124 n1 = array([x0 - x2, y0 - y2]) … … 137 137 n1[1], -n1[0], 138 138 n2[1], -n2[0]] 139 139 140 140 #Edgelengths 141 141 self.edgelengths[i, :] = [l0, l1, l2] 142 142 143 143 #Build vertex list 144 self.build_vertexlist() 145 144 self.build_vertexlist() 145 146 146 def __len__(self): 147 147 return self.number_of_elements … … 154 154 """Return all normal vectors. 155 155 Return normal vectors for all triangles as an Nx6 array 156 (ordered as x0, y0, x1, y1, x2, y2 for each triangle) 156 (ordered as x0, y0, x1, y1, x2, y2 for each triangle) 157 157 """ 158 158 return self.normals … … 163 163 Return value is the numeric array slice [x, y] 164 164 """ 165 return self.normals[i, 2*j:2*j+2] 166 167 168 165 return self.normals[i, 2*j:2*j+2] 166 167 168 169 169 def get_vertex_coordinates(self): 170 170 """Return all vertex coordinates. 171 171 Return all vertex coordinates for all triangles as an Nx6 array 172 (ordered as x0, y0, x1, y1, x2, y2 for each triangle) 172 (ordered as x0, y0, x1, y1, x2, y2 for each triangle) 173 173 """ 174 174 return self.vertex_coordinates … … 179 179 Return value is the numeric array slice [x, y] 180 180 """ 181 return self.vertex_coordinates[i, 2*j:2*j+2] 181 return self.vertex_coordinates[i, 2*j:2*j+2] 182 182 183 183 … … 189 189 #FIXME: Perhaps they should be ordered as in obj files?? 190 190 #See quantity.get_vertex_values 191 191 192 192 from Numeric import zeros, Float 193 193 194 194 N = self.number_of_elements 195 vertex_coordinates = zeros((N, 6), Float) 195 vertex_coordinates = zeros((N, 6), Float) 196 196 197 197 for i in range(N): … … 203 203 204 204 return vertex_coordinates 205 205 206 206 def get_vertices(self, indexes=None): 207 207 """Get connectivity 208 208 indexes is the set of element ids of interest 209 209 """ 210 210 211 211 from Numeric import take 212 212 213 213 if (indexes == None): 214 214 indexes = range(len(self)) #len(self)=number of elements 215 215 216 216 return take(self.triangles, indexes) 217 217 … … 220 220 unique_verts = {} 221 221 for triangle in triangles: 222 unique_verts[triangle[0]] = 0 223 unique_verts[triangle[1]] = 0 222 unique_verts[triangle[0]] = 0 223 unique_verts[triangle[1]] = 0 224 224 unique_verts[triangle[2]] = 0 225 return unique_verts.keys() 226 225 return unique_verts.keys() 226 227 227 def build_vertexlist(self): 228 228 """Build vertexlist index by vertex ids and for each entry (point id) … … 231 231 232 232 Preconditions: 233 self.coordinates and self.triangles are defined 234 233 self.coordinates and self.triangles are defined 234 235 235 Postcondition: 236 236 self.vertexlist is built … … 242 242 a = self.triangles[i, 0] 243 243 b = self.triangles[i, 1] 244 c = self.triangles[i, 2] 244 c = self.triangles[i, 2] 245 245 246 246 #Register the vertices v as lists of … … 251 251 vertexlist[v] = [] 252 252 253 vertexlist[v].append( (i, vertex_id) ) 253 vertexlist[v].append( (i, vertex_id) ) 254 254 255 255 self.vertexlist = vertexlist 256 256 257 257 258 258 def get_extent(self): … … 264 264 X = C[:,0:6:2].copy() 265 265 Y = C[:,1:6:2].copy() 266 266 267 267 xmin = min(X.flat) 268 268 xmax = max(X.flat) 269 269 ymin = min(Y.flat) 270 ymax = max(Y.flat) 271 270 ymax = max(Y.flat) 271 272 272 return xmin, xmax, ymin, ymax 273 273 … … 277 277 """ 278 278 279 return sum(self.areas) 280 279 return sum(self.areas) -
inundation/ga/storm_surge/pyvolution/mesh.py
r1360 r1387 130 130 c = sqrt((x2-x0)**2+(y2-y0)**2) 131 131 132 self.radii[i]= 2.0*self.areas[i]/(a+b+c)132 self.radii[i]=self.areas[i]/(a+b+c) 133 133 134 134 -
inundation/ga/storm_surge/pyvolution/mesh_factory.py
r820 r1387 4 4 5 5 6 def rectangular (m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):6 def rectangular_old(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)): 7 7 8 8 """Setup a rectangular grid of triangles … … 10 10 and side lengths len1, len2. If side lengths are omitted 11 11 the mesh defaults to the unit square. 12 12 13 13 len1: x direction (left to right) 14 14 len2: y direction (bottom to top) 15 15 16 16 Return to lists: points and elements suitable for creating a Mesh or 17 FVMesh object, e.g. Mesh(points, elements) 17 FVMesh object, e.g. Mesh(points, elements) 18 18 """ 19 19 20 20 from config import epsilon 21 21 22 22 #E = m*n*2 #Number of triangular elements 23 23 #P = (m+1)*(n+1) #Number of initial vertices 24 24 25 25 delta1 = float(len1)/m 26 delta2 = float(len2)/n 26 delta2 = float(len2)/n 27 27 28 28 #Dictionary of vertex objects … … 43 43 for j in range(n): 44 44 v1 = vertices[i,j+1] 45 v2 = vertices[i,j] 46 v3 = vertices[i+1,j+1] 47 v4 = vertices[i+1,j] 45 v2 = vertices[i,j] 46 v3 = vertices[i+1,j+1] 47 v4 = vertices[i+1,j] 48 48 49 49 #Update boundary dictionary and create elements … … 51 51 boundary[(len(elements), 2)] = 'right' 52 52 if j == 0: 53 boundary[(len(elements), 1)] = 'bottom' 53 boundary[(len(elements), 1)] = 'bottom' 54 54 elements.append([v4,v3,v2]) #Lower element 55 55 … … 57 57 boundary[(len(elements), 2)] = 'left' 58 58 if j == n-1: 59 boundary[(len(elements), 1)] = 'top' 60 elements.append([v1,v2,v3]) #Upper element 61 62 return points, elements, boundary 63 59 boundary[(len(elements), 1)] = 'top' 60 elements.append([v1,v2,v3]) #Upper element 61 62 return points, elements, boundary 63 64 def rectangular(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)): 65 66 """Setup a rectangular grid of triangles 67 with m+1 by n+1 grid points 68 and side lengths len1, len2. If side lengths are omitted 69 the mesh defaults to the unit square. 70 71 len1: x direction (left to right) 72 len2: y direction (bottom to top) 73 74 Return to lists: points and elements suitable for creating a Mesh or 75 FVMesh object, e.g. Mesh(points, elements) 76 """ 77 78 from config import epsilon 79 from Numeric import zeros, Float, Int 80 81 delta1 = float(len1)/m 82 delta2 = float(len2)/n 83 84 #Calculate number of points 85 Np = (m+1)*(n+1) 86 87 class Index: 88 89 def __init__(self, n,m): 90 self.n = n 91 self.m = m 92 93 def __call__(self, i,j): 94 return j+i*(self.n+1) 95 96 97 index = Index(n,m) 98 99 points = zeros( (Np,2), Float) 100 101 for i in range(m+1): 102 for j in range(n+1): 103 104 points[index(i,j),:] = [i*delta1 + origin[0], j*delta2 + origin[1]] 105 106 #Construct 2 triangles per rectangular element and assign tags to boundary 107 #Calculate number of triangles 108 Nt = 2*m*n 109 110 111 elements = zeros( (Nt,3), Int) 112 boundary = {} 113 nt = -1 114 for i in range(m): 115 for j in range(n): 116 nt = nt + 1 117 i1 = index(i,j+1) 118 i2 = index(i,j) 119 i3 = index(i+1,j+1) 120 i4 = index(i+1,j) 121 122 #Update boundary dictionary and create elements 123 if i == m-1: 124 boundary[nt, 2] = 'right' 125 if j == 0: 126 boundary[nt, 1] = 'bottom' 127 elements[nt,:] = [i4,i3,i2] #Lower element 128 nt = nt + 1 129 130 if i == 0: 131 boundary[nt, 2] = 'left' 132 if j == n-1: 133 boundary[nt, 1] = 'top' 134 elements[nt,:] = [i1,i2,i3] #Upper element 135 136 return points, elements, boundary 64 137 65 138 def oblique(m, n, lenx = 1.0, leny = 1.0, theta = 8.95, origin = (0.0, 0.0)): … … 97 170 for i in range(m+1): 98 171 x = deltax*i 99 for j in range(n+1): 172 for j in range(n+1): 100 173 y = deltay*j 101 174 if x > 0.25*lenx: 102 175 y = a1 + a2*x + a3*y + a4*x*y 103 176 104 177 vertices[i,j] = len(points) 105 178 points.append([x + origin[0], y + origin[1]]) 106 179 107 # Construct 2 triangles per element 180 # Construct 2 triangles per element 108 181 elements = [] 109 182 boundary = {} … … 111 184 for j in range(n): 112 185 v1 = vertices[i,j+1] 113 v2 = vertices[i,j] 114 v3 = vertices[i+1,j+1] 186 v2 = vertices[i,j] 187 v3 = vertices[i+1,j+1] 115 188 v4 = vertices[i+1,j] 116 189 117 190 #Update boundary dictionary and create elements 118 191 if i == m-1: 119 192 boundary[(len(elements), 2)] = 'right' 120 193 if j == 0: 121 boundary[(len(elements), 1)] = 'bottom' 194 boundary[(len(elements), 1)] = 'bottom' 122 195 elements.append([v4,v3,v2]) #Lower 123 196 … … 125 198 boundary[(len(elements), 2)] = 'left' 126 199 if j == n-1: 127 boundary[(len(elements), 1)] = 'top' 128 200 boundary[(len(elements), 1)] = 'top' 201 129 202 elements.append([v1,v2,v3]) #Upper 130 203 131 return points, elements, boundary 204 return points, elements, boundary 132 205 133 206 … … 136 209 with n radial segments. If radius is are omitted the mesh defaults to 137 210 the unit circle radius. 138 211 139 212 radius: radius of circle 140 213 141 214 #FIXME: The triangles become degenerate for large values of m or n. 142 215 """ 143 216 144 217 145 218 146 219 from math import pi, cos, sin 147 220 … … 152 225 points = [[0.0, 0.0]] #Center point 153 226 vertices[0, 0] = 0 154 227 155 228 for i in range(n): 156 229 theta = 2*i*pi/n … … 162 235 points.append([delta*x, delta*y]) 163 236 164 #Construct 2 triangles per element 237 #Construct 2 triangles per element 165 238 elements = [] 166 239 for i in range(n): 167 240 for j in range(1,m): 168 241 169 i1 = (i + 1) % n #Wrap around 170 242 i1 = (i + 1) % n #Wrap around 243 171 244 v1 = vertices[i,j+1] 172 v2 = vertices[i,j] 173 v3 = vertices[i1,j+1] 245 v2 = vertices[i,j] 246 v3 = vertices[i1,j+1] 174 247 v4 = vertices[i1,j] 175 248 176 elements.append([v4,v2,v3]) #Lower 249 elements.append([v4,v2,v3]) #Lower 177 250 elements.append([v1,v3,v2]) #Upper 178 251 … … 181 254 v1 = vertices[0,0] 182 255 for i in range(n): 183 i1 = (i + 1) % n #Wrap around 256 i1 = (i + 1) % n #Wrap around 184 257 v2 = vertices[i,1] 185 258 v3 = vertices[i1,1] 186 259 187 260 elements.append([v1,v2,v3]) #center 188 261 189 262 return points, elements 190 263 … … 205 278 filename = name + '.poly' 206 279 207 280 208 281 fid = open(filename) 209 282 210 283 points = [] #x, y 211 284 values = [] #z 212 ##vertex_values = [] #Repeated z 285 ##vertex_values = [] #Repeated z 213 286 triangles = [] #v0, v1, v2 214 287 215 288 lines = fid.readlines() 216 289 … … 237 310 x = float(xyz[0]) 238 311 y = float(xyz[1]) 239 z = float(xyz[2]) 312 z = float(xyz[2]) 240 313 241 314 points.append([x, y]) 242 315 values.append(z) 243 244 245 k = i 316 317 318 k = i 246 319 while keyword == 'POLYS': 247 320 line = lines[i].strip() … … 251 324 keyword = line 252 325 break 253 326 254 327 255 328 fields = line.split(':') … … 269 342 y1 = points[i1][1] 270 343 x2 = points[i2][0] 271 y2 = points[i2][1] 344 y2 = points[i2][1] 272 345 273 346 area = abs((x1*y0-x0*y1)+(x2*y1-x1*y2)+(x0*y2-x2*y0))/2 … … 281 354 a0 = anglediff(v1, v0) 282 355 a1 = anglediff(v2, v1) 283 a2 = anglediff(v0, v2) 284 285 356 a2 = anglediff(v0, v2) 357 358 286 359 if a0 < pi and a1 < pi and a2 < pi: 287 360 #all is well … … 294 367 j1 = i0 295 368 j2 = i2 296 369 297 370 triangles.append([j0, j1, j2]) 298 371 ##vertex_values.append([values[j0], values[j1], values[j2]]) 299 372 else: 300 offending +=1 373 offending +=1 301 374 302 375 print 'Removed %d offending triangles out of %d' %(offending, len(lines)) … … 311 384 from math import pi 312 385 from util import anglediff 313 314 386 387 315 388 fid = open(filename) 316 389 points = [] # List of x, y coordinates 317 390 triangles = [] # List of vertex ids as listed in the file 318 391 319 392 for line in fid.readlines(): 320 393 fields = line.split() … … 337 410 v1 = t[1] 338 411 v2 = t[2] 339 412 340 413 x0 = points[v0][0] 341 414 y0 = points[v0][1] … … 343 416 y1 = points[v1][1] 344 417 x2 = points[v2][0] 345 y2 = points[v2][1] 418 y2 = points[v2][1] 346 419 347 420 #Check that points are arranged in counter clock-wise order … … 352 425 a0 = anglediff(vec1, vec0) 353 426 a1 = anglediff(vec2, vec1) 354 a2 = anglediff(vec0, vec2) 427 a2 = anglediff(vec0, vec2) 355 428 356 429 if a0 < pi and a1 < pi and a2 < pi: 357 430 elements.append([v0, v1, v2]) 358 431 else: 359 elements.append([v0, v2, v1]) 360 361 return points, elements 432 elements.append([v0, v2, v1]) 433 434 return points, elements 362 435 363 436 # #Map from edge number to indices of associated vertices … … 365 438 366 439 367 368 -
inundation/ga/storm_surge/pyvolution/netherlands.py
r1360 r1387 10 10 # 11 11 from shallow_water import Domain, Reflective_boundary, Dirichlet_boundary,\ 12 Transmissive_boundary, Constant_height 12 Transmissive_boundary, Constant_height, Constant_stage 13 13 14 14 from mesh_factory import rectangular … … 80 80 N = 130 #size = 33800 81 81 N = 600 #Size = 720000 82 N = 60 82 N = 50 83 M = 40 83 84 84 85 #N = 15 … … 86 87 print 'Creating domain' 87 88 #Create basic mesh 88 points, vertices, boundary = rectangular(N, N)89 points, vertices, boundary = rectangular(N, M) 89 90 90 91 #Create shallow water domain … … 102 103 103 104 #Set bed-slope and friction 104 inflow_stage = 0. 1105 manning = 0.0 2105 inflow_stage = 0.2 106 manning = 0.00 106 107 Z = Weir(inflow_stage) 107 108 … … 148 149 # 149 150 print 'Initial condition' 150 domain.set_quantity('stage', Constant_height(Z, 0.)) 151 domain.set_quantity('stage', Constant_height(Z, 0.0)) 152 #domain.set_quantity('stage', Constant_stage(-1.0)) 151 153 152 154 #Evolve … … 154 156 t0 = time.time() 155 157 156 for t in domain.evolve(yieldstep = 0.0 5, finaltime = 10.0):158 for t in domain.evolve(yieldstep = 0.01, finaltime = 5.0): 157 159 domain.write_time() 160 #domain.visualiser.scale_z = 1.0 161 domain.visualiser.update_quantity_color('xmomentum',scale_z = 4.0) 158 162 159 163 -
inundation/ga/storm_surge/pyvolution/realtime_visualisation_new.py
r1363 r1387 3 3 elevation_color = (0.3,0.4,0.5) 4 4 stage_color = (0.1,0.4,0.99) 5 other_color = (0.99,0.4,0.1) 5 6 6 7 class Visualiser: … … 117 118 118 119 119 def update_quantity(self,qname,qcolor=None ):120 def update_quantity(self,qname,qcolor=None,scale_z=None): 120 121 121 122 #print 'update '+qname+' arrays' 122 123 123 124 if qcolor is None: 125 qcolor = other_color 126 124 127 if qname=='elevation': 125 128 qcolor = elevation_color … … 128 131 qcolor = stage_color 129 132 133 if scale_z is None: 134 scale_z = self.scale_z 130 135 131 136 try: 132 self.update_arrays(self.domain.quantities[qname].vertex_values, qcolor )137 self.update_arrays(self.domain.quantities[qname].vertex_values, qcolor, scale_z) 133 138 134 139 #print 'update bed image' … … 140 145 pass 141 146 142 def update_quantity_color(self,qname,qcolor=None ):147 def update_quantity_color(self,qname,qcolor=None,scale_z=None): 143 148 144 149 #print 'update '+qname+' arrays' … … 151 156 qcolor = stage_color 152 157 158 if scale_z is None: 159 scale_z = self.scale_z 153 160 154 161 #try: 155 self.update_arrays_color(self.domain.quantities[qname].vertex_values, qcolor )162 self.update_arrays_color(self.domain.quantities[qname].vertex_values, qcolor, scale_z) 156 163 157 164 #print 'update bed image' … … 164 171 165 172 166 def update_arrays(self,quantity,qcolor ):173 def update_arrays(self,quantity,qcolor,scale_z): 167 174 168 175 col = asarray(qcolor) … … 170 177 N = len(self.domain) 171 178 172 scale_z = self.scale_z173 179 min_x = self.min_x 174 180 min_y = self.min_y … … 189 195 190 196 191 def update_arrays_color(self,quantity,qcolor ):197 def update_arrays_color(self,quantity,qcolor,scale_z): 192 198 193 199 col = asarray(qcolor) … … 195 201 N = len(self.domain) 196 202 197 scale_z = self.scale_z198 203 min_x = self.min_x 199 204 min_y = self.min_y … … 308 313 normal(1) = normal(1)/norm; 309 314 normal(2) = normal(2)/norm; 315 310 316 311 317 for (int j=0; j<3; j++) { -
inundation/ga/storm_surge/pyvolution/shallow_water.py
r1363 r1387 1507 1507 1508 1508 1509 class Constant_stage: 1510 """Set an initial condition with constant stage 1511 """ 1512 def __init__(self, s): 1513 self.s = s 1514 1515 def __call__(self, x, y): 1516 return self.s 1517 1509 1518 class Constant_height: 1510 1519 """Set an initial condition with constant water height, e.g 1511 1520 stage s = z+h 1512 1521 """ 1522 1513 1523 def __init__(self, W, h): 1514 1524 self.W = W -
inundation/ga/storm_surge/pyvolution/shallow_water_ext.c
r1017 r1387 2 2 // 3 3 // To compile (Python2.3): 4 // gcc -c domain_ext.c -I/usr/include/python2.3 -o domain_ext.o -Wall -O 5 // gcc -shared domain_ext.o -o domain_ext.so 4 // gcc -c domain_ext.c -I/usr/include/python2.3 -o domain_ext.o -Wall -O 5 // gcc -shared domain_ext.o -o domain_ext.so 6 6 // 7 7 // or use python compile.py … … 11 11 // 12 12 // Ole Nielsen, GA 2004 13 14 13 14 15 15 #include "Python.h" 16 16 #include "Numeric/arrayobject.h" 17 17 #include "math.h" 18 #include <stdio.h> 18 19 19 20 //Shared code snippets … … 26 27 /*Rotate the momentum component q (q[1], q[2]) 27 28 from x,y coordinates to coordinates based on normal vector (n1, n2). 28 29 Result is returned in array 3x1 r 29 30 Result is returned in array 3x1 r 30 31 To rotate in opposite direction, call rotate with (q, n1, -n2) 31 32 Contents of q are changed by this function */ 32 33 Contents of q are changed by this function */ 33 34 34 35 35 36 double q1, q2; 36 37 37 38 //Shorthands 38 39 q1 = q[1]; //uh momentum … … 41 42 //Rotate 42 43 q[1] = n1*q1 + n2*q2; 43 q[2] = -n2*q1 + n1*q2; 44 q[2] = -n2*q1 + n1*q2; 44 45 45 46 return 0; 46 } 47 48 49 47 } 48 49 50 50 51 // Computational function for flux computation (using stage w=z+h) 51 int flux_function(double *q_left, double *q_right, 52 double z_left, double z_right, 53 double n1, double n2, 54 double epsilon, double g, 52 int flux_function(double *q_left, double *q_right, 53 double z_left, double z_right, 54 double n1, double n2, 55 double epsilon, double g, 55 56 double *edgeflux, double *max_speed) { 56 57 57 58 /*Compute fluxes between volumes for the shallow water wave equation 58 cast in terms of the 'stage', w = h+z using 59 cast in terms of the 'stage', w = h+z using 59 60 the 'central scheme' as described in 60 61 61 62 Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For 62 63 Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'. 63 64 Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740. 64 65 The implemented formula is given in equation (3.15) on page 714 65 66 The implemented formula is given in equation (3.15) on page 714 66 67 */ 67 68 68 69 int i; 69 70 70 71 double w_left, h_left, uh_left, vh_left, u_left; 71 72 double w_right, h_right, uh_right, vh_right, u_right; 72 73 double s_min, s_max, soundspeed_left, soundspeed_right; 73 74 double denom, z; 74 double q_left_copy[3], q_right_copy[3]; 75 double q_left_copy[3], q_right_copy[3]; 75 76 double flux_right[3], flux_left[3]; 76 77 77 78 //Copy conserved quantities to protect from modification 78 79 for (i=0; i<3; i++) { 79 80 q_left_copy[i] = q_left[i]; 80 81 q_right_copy[i] = q_right[i]; 81 } 82 82 } 83 83 84 //Align x- and y-momentum with x-axis 84 85 _rotate(q_left_copy, n1, n2); 85 _rotate(q_right_copy, n1, n2); 86 _rotate(q_right_copy, n1, n2); 86 87 87 88 z = (z_left+z_right)/2; //Take average of field values … … 95 96 h_left = 0.0; //Could have been negative 96 97 u_left = 0.0; 97 } else { 98 } else { 98 99 u_left = uh_left/h_left; 99 100 } 100 101 101 102 w_right = q_right_copy[0]; 102 103 h_right = w_right-z; … … 106 107 h_right = 0.0; //Could have been negative 107 108 u_right = 0.0; 108 } else { 109 } else { 109 110 u_right = uh_right/h_right; 110 111 } 111 112 112 //Momentum in y-direction 113 //Momentum in y-direction 113 114 vh_left = q_left_copy[2]; 114 vh_right = q_right_copy[2]; 115 115 vh_right = q_right_copy[2]; 116 116 117 117 118 //Maximal and minimal wave speeds 118 soundspeed_left = sqrt(g*h_left); 119 soundspeed_left = sqrt(g*h_left); 119 120 soundspeed_right = sqrt(g*h_right); 120 121 121 122 s_max = max(u_left+soundspeed_left, u_right+soundspeed_right); 122 if (s_max < 0.0) s_max = 0.0; 123 123 if (s_max < 0.0) s_max = 0.0; 124 124 125 s_min = min(u_left-soundspeed_left, u_right-soundspeed_right); 125 if (s_min > 0.0) s_min = 0.0; 126 127 //Flux formulas 126 if (s_min > 0.0) s_min = 0.0; 127 128 //Flux formulas 128 129 flux_left[0] = u_left*h_left; 129 130 flux_left[1] = u_left*uh_left + 0.5*g*h_left*h_left; 130 131 flux_left[2] = u_left*vh_left; 131 132 132 133 flux_right[0] = u_right*h_right; 133 134 flux_right[1] = u_right*uh_right + 0.5*g*h_right*h_right; 134 135 flux_right[2] = u_right*vh_right; 135 136 137 //Flux computation 136 137 138 //Flux computation 138 139 denom = s_max-s_min; 139 140 if (denom == 0.0) { 140 141 for (i=0; i<3; i++) edgeflux[i] = 0.0; 141 142 *max_speed = 0.0; 142 } else { 143 } else { 143 144 for (i=0; i<3; i++) { 144 145 edgeflux[i] = s_max*flux_left[i] - s_min*flux_right[i]; 145 146 edgeflux[i] += s_max*s_min*(q_right_copy[i]-q_left_copy[i]); 146 147 edgeflux[i] /= denom; 147 } 148 148 } 149 149 150 //Maximal wavespeed 150 151 *max_speed = max(fabs(s_max), fabs(s_min)); 151 152 //Rotate back 152 153 //Rotate back 153 154 _rotate(edgeflux, n1, -n2); 154 155 } 155 156 return 0; 156 157 } 157 158 void _manning_friction(double g, double eps, int N, 159 double* w, double* z, 160 double* uh, double* vh, 161 double* eta, double* xmom, double* ymom) { 158 159 void _manning_friction(double g, double eps, int N, 160 double* w, double* z, 161 double* uh, double* vh, 162 double* eta, double* xmom, double* ymom) { 162 163 163 164 int k; 164 165 double S, h; 165 166 166 167 for (k=0; k<N; k++) { 167 168 if (eta[k] > eps) { … … 180 181 } 181 182 } 182 183 183 184 184 185 185 186 int _balance_deep_and_shallow(int N, 186 187 double* wc, 187 double* zc, 188 double* hc, 189 double* wv, 190 double* zv, 188 double* zc, 189 double* hc, 190 double* wv, 191 double* zv, 191 192 double* hv, 192 double* hvbar, 193 double* xmomc, 194 double* ymomc, 195 double* xmomv, 196 double* ymomv) { 197 193 double* hvbar, 194 double* xmomc, 195 double* ymomc, 196 double* xmomv, 197 double* ymomv) { 198 198 199 int k, k3, i; 199 200 double dz, hmin, alpha; 200 201 201 202 //Compute linear combination between w-limited stages and 202 //h-limited stages close to the bed elevation. 203 203 //h-limited stages close to the bed elevation. 204 204 205 for (k=0; k<N; k++) { 205 206 // Compute maximal variation in bed elevation … … 211 212 212 213 k3 = 3*k; 213 214 214 215 //FIXME: Try with this one precomputed 215 216 dz = 0.0; … … 220 221 } 221 222 222 223 //Create alpha in [0,1], where alpha==0 means using the h-limited 223 224 //Create alpha in [0,1], where alpha==0 means using the h-limited 224 225 //stage and alpha==1 means using the w-limited stage as 225 226 //computed by the gradient limiter (both 1st or 2nd order) … … 227 228 //If hmin > dz/2 then alpha = 1 and the bed will have no effect 228 229 //If hmin < 0 then alpha = 0 reverting to constant height above bed. 229 230 230 231 231 232 if (dz > 0.0) 232 //if (hmin<0.0) 233 //if (hmin<0.0) 233 234 // alpha = 0.0; 234 235 //else 235 236 // alpha = max( min( hc[k]/dz, 1.0), 0.0 ); 236 237 alpha = max( min( 2.0*hmin/dz, 1.0), 0.0 ); 237 238 238 else 239 239 alpha = 1.0; //Flat bed 240 240 241 //alpha = 1.0; 242 241 243 //printf("dz = %.3f, alpha = %.8f\n", dz, alpha); 242 244 243 // Let 244 // 245 // wvi be the w-limited stage (wvi = zvi + hvi) 245 // Let 246 // 247 // wvi be the w-limited stage (wvi = zvi + hvi) 246 248 // wvi- be the h-limited state (wvi- = zvi + hvi-) 247 // 248 // 249 // 250 // 249 251 // where i=0,1,2 denotes the vertex ids 250 // 251 // Weighted balance between w-limited and h-limited stage is 252 // 253 // wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi) 254 // 252 // 253 // Weighted balance between w-limited and h-limited stage is 254 // 255 // wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi) 256 // 255 257 // It follows that the updated wvi is 256 258 // wvi := zvi + (1-alpha)*hvi- + alpha*hvi 257 // 259 // 258 260 // Momentum is balanced between constant and limited 259 261 260 if (alpha < 1) { 262 if (alpha < 1) { 261 263 for (i=0; i<3; i++) { 262 264 wv[k3+i] = zv[k3+i] + (1-alpha)*hvbar[k3+i] + alpha*hv[k3+i]; 263 264 //Update momentum as a linear combination of 265 266 //Update momentum as a linear combination of 265 267 //xmomc and ymomc (shallow) and momentum 266 268 //from extrapolator xmomv and ymomv (deep). 267 xmomv[k3+i] = (1-alpha)*xmomc[k] + alpha*xmomv[k3+i]; 269 xmomv[k3+i] = (1-alpha)*xmomc[k] + alpha*xmomv[k3+i]; 268 270 ymomv[k3+i] = (1-alpha)*ymomc[k] + alpha*ymomv[k3+i]; 269 } 271 } 270 272 } 271 } 273 } 272 274 return 0; 273 275 } … … 275 277 276 278 277 int _protect(int N, 278 double minimum_allowed_height, 279 int _protect(int N, 280 double minimum_allowed_height, 279 281 double* wc, 280 double* zc, 281 double* xmomc, 282 double* zc, 283 double* xmomc, 282 284 double* ymomc) { 283 284 int k; 285 286 int k; 285 287 double hc; 286 288 287 289 //Protect against initesimal and negative heights 288 290 289 291 for (k=0; k<N; k++) { 290 292 hc = wc[k] - zc[k]; 291 292 if (hc < minimum_allowed_height) { 293 wc[k] = zc[k]; 293 294 if (hc < minimum_allowed_height) { 295 wc[k] = zc[k]; 294 296 xmomc[k] = 0.0; 295 ymomc[k] = 0.0; 297 ymomc[k] = 0.0; 296 298 } 297 299 298 300 } 299 301 return 0; … … 309 311 int _assign_wind_field_values(int N, 310 312 double* xmom_update, 311 double* ymom_update, 313 double* ymom_update, 312 314 double* s_vec, 313 315 double* phi_vec, … … 318 320 int k; 319 321 double S, s, phi, u, v; 320 322 321 323 for (k=0; k<N; k++) { 322 324 323 325 s = s_vec[k]; 324 326 phi = phi_vec[k]; … … 330 332 u = s*cos(phi); 331 333 v = s*sin(phi); 332 334 333 335 //Compute wind stress 334 336 S = cw * sqrt(u*u + v*v); 335 337 xmom_update[k] += S*u; 336 ymom_update[k] += S*v; 337 } 338 return 0; 339 } 338 ymom_update[k] += S*v; 339 } 340 return 0; 341 } 340 342 341 343 … … 348 350 // gravity(g, h, v, x, xmom, ymom) 349 351 // 350 351 352 353 352 354 PyArrayObject *h, *v, *x, *xmom, *ymom; 353 355 int k, i, N, k3, k6; 354 356 double g, avg_h, zx, zy; 355 357 double x0, y0, x1, y1, x2, y2, z0, z1, z2; 356 358 357 359 if (!PyArg_ParseTuple(args, "dOOOOO", 358 &g, &h, &v, &x, 359 &xmom, &ymom)) 360 return NULL; 360 &g, &h, &v, &x, 361 &xmom, &ymom)) 362 return NULL; 361 363 362 364 N = h -> dimensions[0]; 363 365 for (k=0; k<N; k++) { 364 366 k3 = 3*k; // base index 365 k6 = 6*k; // base index 366 367 k6 = 6*k; // base index 368 367 369 avg_h = 0.0; 368 370 for (i=0; i<3; i++) { 369 371 avg_h += ((double *) h -> data)[k3+i]; 370 } 372 } 371 373 avg_h /= 3; 372 373 374 375 374 376 //Compute bed slope 375 377 x0 = ((double*) x -> data)[k6 + 0]; 376 y0 = ((double*) x -> data)[k6 + 1]; 378 y0 = ((double*) x -> data)[k6 + 1]; 377 379 x1 = ((double*) x -> data)[k6 + 2]; 378 y1 = ((double*) x -> data)[k6 + 3]; 380 y1 = ((double*) x -> data)[k6 + 3]; 379 381 x2 = ((double*) x -> data)[k6 + 4]; 380 y2 = ((double*) x -> data)[k6 + 5]; 382 y2 = ((double*) x -> data)[k6 + 5]; 381 383 382 384 383 385 z0 = ((double*) v -> data)[k3 + 0]; 384 386 z1 = ((double*) v -> data)[k3 + 1]; 385 z2 = ((double*) v -> data)[k3 + 2]; 387 z2 = ((double*) v -> data)[k3 + 2]; 386 388 387 389 _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy); … … 389 391 //Update momentum 390 392 ((double*) xmom -> data)[k] += -g*zx*avg_h; 391 ((double*) ymom -> data)[k] += -g*zy*avg_h; 392 } 393 393 ((double*) ymom -> data)[k] += -g*zy*avg_h; 394 } 395 394 396 return Py_BuildValue(""); 395 397 } … … 400 402 // manning_friction(g, eps, h, uh, vh, eta, xmom_update, ymom_update) 401 403 // 402 403 404 405 404 406 PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom; 405 407 int N; 406 408 double g, eps; 407 409 408 410 if (!PyArg_ParseTuple(args, "ddOOOOOOO", 409 &g, &eps, &w, &z, &uh, &vh, &eta, 410 &xmom, &ymom)) 411 return NULL; 412 413 N = w -> dimensions[0]; 411 &g, &eps, &w, &z, &uh, &vh, &eta, 412 &xmom, &ymom)) 413 return NULL; 414 415 N = w -> dimensions[0]; 414 416 _manning_friction(g, eps, N, 415 417 (double*) w -> data, 416 (double*) z -> data, 417 (double*) uh -> data, 418 (double*) vh -> data, 418 (double*) z -> data, 419 (double*) uh -> data, 420 (double*) vh -> data, 419 421 (double*) eta -> data, 420 (double*) xmom -> data, 422 (double*) xmom -> data, 421 423 (double*) ymom -> data); 422 424 423 425 return Py_BuildValue(""); 424 } 426 } 425 427 426 428 PyObject *rotate(PyObject *self, PyObject *args, PyObject *kwargs) { … … 431 433 // normal a Float numeric array of length 2. 432 434 433 435 434 436 PyObject *Q, *Normal; 435 437 PyArrayObject *q, *r, *normal; 436 438 437 439 static char *argnames[] = {"q", "normal", "direction", NULL}; 438 440 int dimensions[1], i, direction=1; 439 441 double n1, n2; 440 442 441 // Convert Python arguments to C 442 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames, 443 &Q, &Normal, &direction)) 444 return NULL; 443 // Convert Python arguments to C 444 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames, 445 &Q, &Normal, &direction)) 446 return NULL; 445 447 446 448 //Input checks (convert sequences into numeric arrays) 447 q = (PyArrayObject *) 449 q = (PyArrayObject *) 448 450 PyArray_ContiguousFromObject(Q, PyArray_DOUBLE, 0, 0); 449 normal = (PyArrayObject *) 451 normal = (PyArrayObject *) 450 452 PyArray_ContiguousFromObject(Normal, PyArray_DOUBLE, 0, 0); 451 453 452 454 453 455 if (normal -> dimensions[0] != 2) { 454 456 PyErr_SetString(PyExc_RuntimeError, "Normal vector must have 2 components"); … … 456 458 } 457 459 458 //Allocate space for return vector r (don't DECREF) 460 //Allocate space for return vector r (don't DECREF) 459 461 dimensions[0] = 3; 460 462 r = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE); … … 462 464 //Copy 463 465 for (i=0; i<3; i++) { 464 ((double *) (r -> data))[i] = ((double *) (q -> data))[i]; 465 } 466 466 ((double *) (r -> data))[i] = ((double *) (q -> data))[i]; 467 } 468 467 469 //Get normal and direction 468 n1 = ((double *) normal -> data)[0]; 469 n2 = ((double *) normal -> data)[1]; 470 n1 = ((double *) normal -> data)[0]; 471 n2 = ((double *) normal -> data)[1]; 470 472 if (direction == -1) n2 = -n2; 471 473 … … 474 476 475 477 //Release numeric arrays 476 Py_DECREF(q); 478 Py_DECREF(q); 477 479 Py_DECREF(normal); 478 480 479 481 //return result using PyArray to avoid memory leak 480 482 return PyArray_Return(r); 481 } 483 } 482 484 483 485 … … 490 492 Fluxes across each edge are scaled by edgelengths and summed up 491 493 Resulting flux is then scaled by area and stored in 492 explicit_update for each of the three conserved quantities 494 explicit_update for each of the three conserved quantities 493 495 stage, xmomentum and ymomentum 494 496 … … 496 498 is converted to a timestep that must not be exceeded. The minimum of 497 499 those is computed as the next overall timestep. 498 500 499 501 Python call: 500 domain.timestep = compute_fluxes(timestep, 501 domain.epsilon, 502 domain.timestep = compute_fluxes(timestep, 503 domain.epsilon, 502 504 domain.g, 503 505 domain.neighbours, 504 506 domain.neighbour_edges, 505 507 domain.normals, 506 domain.edgelengths, 508 domain.edgelengths, 507 509 domain.radii, 508 510 domain.areas, 509 Stage.edge_values, 510 Xmom.edge_values, 511 Ymom.edge_values, 512 Bed.edge_values, 511 Stage.edge_values, 512 Xmom.edge_values, 513 Ymom.edge_values, 514 Bed.edge_values, 513 515 Stage.boundary_values, 514 516 Xmom.boundary_values, … … 517 519 Xmom.explicit_update, 518 520 Ymom.explicit_update) 519 521 520 522 521 523 Post conditions: 522 524 domain.explicit_update is reset to computed flux values 523 domain.timestep is set to the largest step satisfying all volumes. 524 525 525 domain.timestep is set to the largest step satisfying all volumes. 526 527 526 528 */ 527 529 528 530 529 531 PyArrayObject *neighbours, *neighbour_edges, 530 532 *normals, *edgelengths, *radii, *areas, 531 *stage_edge_values, 532 *xmom_edge_values, 533 *ymom_edge_values, 534 *bed_edge_values, 533 *stage_edge_values, 534 *xmom_edge_values, 535 *ymom_edge_values, 536 *bed_edge_values, 535 537 *stage_boundary_values, 536 538 *xmom_boundary_values, … … 540 542 *ymom_explicit_update; 541 543 542 543 //Local variables 544 545 //Local variables 544 546 double timestep, max_speed, epsilon, g; 545 547 double normal[2], ql[3], qr[3], zl, zr; … … 548 550 int number_of_elements, k, i, j, m, n; 549 551 int ki, nm, ki2; //Index shorthands 550 551 552 // Convert Python arguments to C 552 553 554 // Convert Python arguments to C 553 555 if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOOOOOO", 554 556 ×tep, 555 557 &epsilon, 556 558 &g, 557 &neighbours, 559 &neighbours, 558 560 &neighbour_edges, 559 &normals, 561 &normals, 560 562 &edgelengths, &radii, &areas, 561 &stage_edge_values, 562 &xmom_edge_values, 563 &ymom_edge_values, 564 &bed_edge_values, 563 &stage_edge_values, 564 &xmom_edge_values, 565 &ymom_edge_values, 566 &bed_edge_values, 565 567 &stage_boundary_values, 566 568 &xmom_boundary_values, … … 574 576 575 577 number_of_elements = stage_edge_values -> dimensions[0]; 576 577 578 579 578 580 for (k=0; k<number_of_elements; k++) { 579 581 580 582 //Reset work array 581 583 for (j=0; j<3; j++) flux[j] = 0.0; 582 584 583 585 //Loop through neighbours and compute edge flux for each 584 586 for (i=0; i<3; i++) { … … 586 588 ql[0] = ((double *) stage_edge_values -> data)[ki]; 587 589 ql[1] = ((double *) xmom_edge_values -> data)[ki]; 588 ql[2] = ((double *) ymom_edge_values -> data)[ki]; 589 zl = ((double *) bed_edge_values -> data)[ki]; 590 ql[2] = ((double *) ymom_edge_values -> data)[ki]; 591 zl = ((double *) bed_edge_values -> data)[ki]; 590 592 591 593 //Quantities at neighbour on nearest face … … 593 595 if (n < 0) { 594 596 m = -n-1; //Convert negative flag to index 595 qr[0] = ((double *) stage_boundary_values -> data)[m]; 596 qr[1] = ((double *) xmom_boundary_values -> data)[m]; 597 qr[2] = ((double *) ymom_boundary_values -> data)[m]; 597 qr[0] = ((double *) stage_boundary_values -> data)[m]; 598 qr[1] = ((double *) xmom_boundary_values -> data)[m]; 599 qr[2] = ((double *) ymom_boundary_values -> data)[m]; 598 600 zr = zl; //Extend bed elevation to boundary 599 } else { 601 } else { 600 602 m = ((long *) neighbour_edges -> data)[ki]; 601 602 nm = n*3+m; 603 604 nm = n*3+m; 603 605 qr[0] = ((double *) stage_edge_values -> data)[nm]; 604 606 qr[1] = ((double *) xmom_edge_values -> data)[nm]; 605 qr[2] = ((double *) ymom_edge_values -> data)[nm]; 606 zr = ((double *) bed_edge_values -> data)[nm]; 607 qr[2] = ((double *) ymom_edge_values -> data)[nm]; 608 zr = ((double *) bed_edge_values -> data)[nm]; 607 609 } 608 610 609 611 //printf("%d %d [%d] (%d, %d): %.2f %.2f %.2f\n", k, i, ki, n, m, 610 // ql[0], ql[1], ql[2]); 611 612 613 // Outward pointing normal vector 612 // ql[0], ql[1], ql[2]); 613 614 615 // Outward pointing normal vector 614 616 // normal = domain.normals[k, 2*i:2*i+2] 615 617 ki2 = 2*ki; //k*6 + i*2 616 618 normal[0] = ((double *) normals -> data)[ki2]; 617 normal[1] = ((double *) normals -> data)[ki2+1]; 619 normal[1] = ((double *) normals -> data)[ki2+1]; 618 620 619 621 //Edge flux computation 620 flux_function(ql, qr, zl, zr, 622 flux_function(ql, qr, zl, zr, 621 623 normal[0], normal[1], 622 epsilon, g, 624 epsilon, g, 623 625 edgeflux, &max_speed); 624 626 625 627 626 628 //flux -= edgeflux * edgelengths[k,i] 627 for (j=0; j<3; j++) { 629 for (j=0; j<3; j++) { 628 630 flux[j] -= edgeflux[j]*((double *) edgelengths -> data)[ki]; 629 631 } 630 632 631 633 //Update timestep 632 634 //timestep = min(timestep, domain.radii[k]/max_speed) … … 634 636 if (max_speed > epsilon) { 635 637 timestep = min(timestep, ((double *) radii -> data)[k]/max_speed); 636 } 638 } 637 639 } // end for i 638 640 639 641 //Normalise by area and store for when all conserved 640 642 //quantities get updated 641 643 // flux /= areas[k] 642 for (j=0; j<3; j++) { 644 for (j=0; j<3; j++) { 643 645 flux[j] /= ((double *) areas -> data)[k]; 644 646 } … … 646 648 ((double *) stage_explicit_update -> data)[k] = flux[0]; 647 649 ((double *) xmom_explicit_update -> data)[k] = flux[1]; 648 ((double *) ymom_explicit_update -> data)[k] = flux[2]; 650 ((double *) ymom_explicit_update -> data)[k] = flux[2]; 649 651 650 652 } //end for k 651 653 652 654 return Py_BuildValue("d", timestep); 653 } 655 } 654 656 655 657 … … 658 660 // 659 661 // protect(minimum_allowed_height, wc, zc, xmomc, ymomc) 660 661 662 PyArrayObject 662 663 664 PyArrayObject 663 665 *wc, //Stage at centroids 664 *zc, //Elevation at centroids 666 *zc, //Elevation at centroids 665 667 *xmomc, //Momentums at centroids 666 *ymomc; 667 668 669 int N; 668 *ymomc; 669 670 671 int N; 670 672 double minimum_allowed_height; 671 672 // Convert Python arguments to C 673 if (!PyArg_ParseTuple(args, "dOOOO", 673 674 // Convert Python arguments to C 675 if (!PyArg_ParseTuple(args, "dOOOO", 674 676 &minimum_allowed_height, 675 677 &wc, &zc, &xmomc, &ymomc)) … … 677 679 678 680 N = wc -> dimensions[0]; 679 681 680 682 _protect(N, 681 683 minimum_allowed_height, 682 684 (double*) wc -> data, 683 (double*) zc -> data, 684 (double*) xmomc -> data, 685 (double*) zc -> data, 686 (double*) xmomc -> data, 685 687 (double*) ymomc -> data); 686 687 return Py_BuildValue(""); 688 689 return Py_BuildValue(""); 688 690 } 689 691 … … 694 696 // balance_deep_and_shallow(wc, zc, hc, wv, zv, hv, 695 697 // xmomc, ymomc, xmomv, ymomv) 696 697 698 PyArrayObject 698 699 700 PyArrayObject 699 701 *wc, //Stage at centroids 700 *zc, //Elevation at centroids 701 *hc, //Height at centroids 702 *zc, //Elevation at centroids 703 *hc, //Height at centroids 702 704 *wv, //Stage at vertices 703 705 *zv, //Elevation at vertices 704 *hv, //Depths at vertices 705 *hvbar, //h-Limited depths at vertices 706 *hv, //Depths at vertices 707 *hvbar, //h-Limited depths at vertices 706 708 *xmomc, //Momentums at centroids and vertices 707 *ymomc, 708 *xmomv, 709 *ymomv; 710 709 *ymomc, 710 *xmomv, 711 *ymomv; 712 711 713 int N; //, err; 712 713 // Convert Python arguments to C 714 if (!PyArg_ParseTuple(args, "OOOOOOOOOOO", 715 &wc, &zc, &hc, 714 715 // Convert Python arguments to C 716 if (!PyArg_ParseTuple(args, "OOOOOOOOOOO", 717 &wc, &zc, &hc, 716 718 &wv, &zv, &hv, &hvbar, 717 719 &xmomc, &ymomc, &xmomv, &ymomv)) … … 719 721 720 722 N = wc -> dimensions[0]; 721 723 722 724 _balance_deep_and_shallow(N, 723 725 (double*) wc -> data, 724 (double*) zc -> data, 725 (double*) hc -> data, 726 (double*) wv -> data, 727 (double*) zv -> data, 726 (double*) zc -> data, 727 (double*) hc -> data, 728 (double*) wv -> data, 729 (double*) zv -> data, 728 730 (double*) hv -> data, 729 (double*) hvbar -> data, 730 (double*) xmomc -> data, 731 (double*) ymomc -> data, 732 (double*) xmomv -> data, 733 (double*) ymomv -> data); 734 735 736 return Py_BuildValue(""); 731 (double*) hvbar -> data, 732 (double*) xmomc -> data, 733 (double*) ymomc -> data, 734 (double*) xmomv -> data, 735 (double*) ymomv -> data); 736 737 738 return Py_BuildValue(""); 737 739 } 738 740 … … 740 742 741 743 PyObject *h_limiter(PyObject *self, PyObject *args) { 742 744 743 745 PyObject *domain, *Tmp; 744 PyArrayObject 745 *hv, *hc, //Depth at vertices and centroids 746 PyArrayObject 747 *hv, *hc, //Depth at vertices and centroids 746 748 *hvbar, //Limited depth at vertices (return values) 747 749 *neighbours; 748 750 749 751 int k, i, n, N, k3; 750 752 int dimensions[2]; 751 753 double beta_h; //Safety factor (see config.py) 752 754 double *hmin, *hmax, hn; 753 754 // Convert Python arguments to C 755 if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv)) 755 756 // Convert Python arguments to C 757 if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv)) 756 758 return NULL; 757 759 … … 759 761 760 762 //Get safety factor beta_h 761 Tmp = PyObject_GetAttrString(domain, "beta_h"); 762 if (!Tmp) 763 return NULL; 764 765 beta_h = PyFloat_AsDouble(Tmp); 766 767 Py_DECREF(Tmp); 763 Tmp = PyObject_GetAttrString(domain, "beta_h"); 764 if (!Tmp) 765 return NULL; 766 767 beta_h = PyFloat_AsDouble(Tmp); 768 769 Py_DECREF(Tmp); 768 770 769 771 N = hc -> dimensions[0]; 770 772 771 773 //Create hvbar 772 774 dimensions[0] = N; 773 dimensions[1] = 3; 775 dimensions[1] = 3; 774 776 hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE); 775 777 776 778 777 779 //Find min and max of this and neighbour's centroid values 778 780 hmin = malloc(N * sizeof(double)); 779 hmax = malloc(N * sizeof(double)); 781 hmax = malloc(N * sizeof(double)); 780 782 for (k=0; k<N; k++) { 781 783 k3=k*3; 782 784 783 785 hmin[k] = ((double*) hc -> data)[k]; 784 786 hmax[k] = hmin[k]; 785 787 786 788 for (i=0; i<3; i++) { 787 789 n = ((long*) neighbours -> data)[k3+i]; 788 790 789 791 //Initialise hvbar with values from hv 790 ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i]; 791 792 ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i]; 793 792 794 if (n >= 0) { 793 795 hn = ((double*) hc -> data)[n]; //Neighbour's centroid value 794 796 795 797 hmin[k] = min(hmin[k], hn); 796 798 hmax[k] = max(hmax[k], hn); … … 798 800 } 799 801 } 800 802 801 803 // Call underlying standard routine 802 804 _limit(N, beta_h, (double*) hc -> data, (double*) hvbar -> data, hmin, hmax); 803 804 // // //Py_DECREF(domain); //FIXME: NEcessary? 805 806 // // //Py_DECREF(domain); //FIXME: NEcessary? 805 807 free(hmin); 806 free(hmax); 807 808 //return result using PyArray to avoid memory leak 808 free(hmax); 809 810 //return result using PyArray to avoid memory leak 809 811 return PyArray_Return(hvbar); 810 //return Py_BuildValue(""); 812 //return Py_BuildValue(""); 811 813 } 812 814 … … 819 821 // s_vec, phi_vec, self.const) 820 822 821 823 822 824 823 825 PyArrayObject //(one element per triangle) 824 *s_vec, //Speeds 825 *phi_vec, //Bearings 826 *s_vec, //Speeds 827 *phi_vec, //Bearings 826 828 *xmom_update, //Momentum updates 827 *ymom_update; 828 829 830 int N; 829 *ymom_update; 830 831 832 int N; 831 833 double cw; 832 833 // Convert Python arguments to C 834 if (!PyArg_ParseTuple(args, "OOOOd", 834 835 // Convert Python arguments to C 836 if (!PyArg_ParseTuple(args, "OOOOd", 835 837 &xmom_update, 836 &ymom_update, 837 &s_vec, &phi_vec, 838 &ymom_update, 839 &s_vec, &phi_vec, 838 840 &cw)) 839 841 return NULL; 840 842 841 843 N = xmom_update -> dimensions[0]; 842 844 843 845 _assign_wind_field_values(N, 844 846 (double*) xmom_update -> data, 845 (double*) ymom_update -> data, 846 (double*) s_vec -> data, 847 (double*) ymom_update -> data, 848 (double*) s_vec -> data, 847 849 (double*) phi_vec -> data, 848 850 cw); 849 850 return Py_BuildValue(""); 851 } 852 853 854 855 856 ////////////////////////////////////////// 851 852 return Py_BuildValue(""); 853 } 854 855 856 857 858 ////////////////////////////////////////// 857 859 // Method table for python module 858 860 static struct PyMethodDef MethodTable[] = { … … 861 863 * three. 862 864 */ 863 865 864 866 {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"}, 865 {"compute_fluxes", compute_fluxes, METH_VARARGS, "Print out"}, 866 {"gravity", gravity, METH_VARARGS, "Print out"}, 867 {"manning_friction", manning_friction, METH_VARARGS, "Print out"}, 868 {"balance_deep_and_shallow", balance_deep_and_shallow, 869 METH_VARARGS, "Print out"}, 870 {"h_limiter", h_limiter, 871 METH_VARARGS, "Print out"}, 872 {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"}, 873 {"assign_windfield_values", assign_windfield_values, 874 METH_VARARGS | METH_KEYWORDS, "Print out"}, 875 //{"distribute_to_vertices_and_edges", 876 // distribute_to_vertices_and_edges, METH_VARARGS}, 877 //{"update_conserved_quantities", 878 // update_conserved_quantities, METH_VARARGS}, 879 //{"set_initialcondition", 880 // set_initialcondition, METH_VARARGS}, 867 {"compute_fluxes", compute_fluxes, METH_VARARGS, "Print out"}, 868 {"gravity", gravity, METH_VARARGS, "Print out"}, 869 {"manning_friction", manning_friction, METH_VARARGS, "Print out"}, 870 {"balance_deep_and_shallow", balance_deep_and_shallow, 871 METH_VARARGS, "Print out"}, 872 {"h_limiter", h_limiter, 873 METH_VARARGS, "Print out"}, 874 {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"}, 875 {"assign_windfield_values", assign_windfield_values, 876 METH_VARARGS | METH_KEYWORDS, "Print out"}, 877 //{"distribute_to_vertices_and_edges", 878 // distribute_to_vertices_and_edges, METH_VARARGS}, 879 //{"update_conserved_quantities", 880 // update_conserved_quantities, METH_VARARGS}, 881 //{"set_initialcondition", 882 // set_initialcondition, METH_VARARGS}, 881 883 {NULL, NULL} 882 884 }; 883 884 // Module initialisation 885 886 // Module initialisation 885 887 void initshallow_water_ext(void){ 886 888 Py_InitModule("shallow_water_ext", MethodTable); 887 888 import_array(); //Necessary for handling of NumPY structures 889 } 889 890 import_array(); //Necessary for handling of NumPY structures 891 } -
inundation/ga/storm_surge/pyvolution/util.py
r1289 r1387 2 2 3 3 It is also a clearing house for functions that may later earn a module 4 of their own. 4 of their own. 5 5 """ 6 6 … … 17 17 v2 = v[1]/l 18 18 19 try: 19 try: 20 20 theta = acos(v1) 21 21 except ValueError, e: … … 31 31 theta = 3.1415926535897931 32 32 print 'WARNING (util.py): angle v1 is %f, setting acos to %f '\ 33 %(v1, theta) 34 33 %(v1, theta) 34 35 35 if v2 < 0: 36 36 #Quadrant 3 or 4 … … 43 43 """Compute difference between angle of vector x0, y0 and x1, y1. 44 44 This is used for determining the ordering of vertices, 45 e.g. for checking if they are counter clockwise. 46 45 e.g. for checking if they are counter clockwise. 46 47 47 Always return a positive value 48 48 """ 49 49 50 50 from math import pi 51 51 52 52 a0 = angle(v0) 53 53 a1 = angle(v1) … … 56 56 if a0 < a1: 57 57 a0 += 2*pi 58 58 59 59 return a0-a1 60 60 … … 65 65 66 66 67 def point_on_line(x, y, x0, y0, x1, y1): 68 """Determine whether a point is on a line segment 69 67 def point_on_line(x, y, x0, y0, x1, y1): 68 """Determine whether a point is on a line segment 69 70 70 Input: x, y, x0, x0, x1, y1: where 71 71 point is given by x, y 72 72 line is given by (x0, y0) and (x1, y1) 73 74 """ 75 73 74 """ 75 76 76 from Numeric import array, dot, allclose 77 77 from math import sqrt 78 78 79 a = array([x - x0, y - y0]) 79 a = array([x - x0, y - y0]) 80 80 a_normal = array([a[1], -a[0]]) 81 81 82 82 b = array([x1 - x0, y1 - y0]) 83 83 84 84 if dot(a_normal, b) == 0: 85 85 #Point is somewhere on the infinite extension of the line 86 86 87 len_a = sqrt(sum(a**2)) 88 len_b = sqrt(sum(b**2)) 87 len_a = sqrt(sum(a**2)) 88 len_b = sqrt(sum(b**2)) 89 89 if dot(a, b) >= 0 and len_a <= len_b: 90 90 return True 91 else: 91 else: 92 92 return False 93 93 else: 94 return False 95 94 return False 95 96 96 def ensure_numeric(A, typecode = None): 97 97 """Ensure that sequence is a Numeric array. … … 117 117 if type(A) == ArrayType: 118 118 if A.typecode == typecode: 119 return array(A) 119 return array(A) 120 120 else: 121 121 return A.astype(typecode) 122 122 else: 123 123 return array(A).astype(typecode) 124 125 124 125 126 126 127 127 def file_function(filename, domain=None, quantities = None, interpolation_points = None, verbose = False): … … 133 133 #In fact, this is where origin should be converted to that of domain 134 134 #Also, check that file covers domain fully. 135 135 136 136 assert type(filename) == type(''),\ 137 137 'First argument to File_function must be a string' … … 148 148 149 149 if domain is not None: 150 quantities = domain.conserved_quantities 150 quantities = domain.conserved_quantities 151 151 else: 152 152 quantities = None 153 154 #Choose format 153 154 #Choose format 155 155 #FIXME: Maybe these can be merged later on 156 156 if line[:3] == 'CDF': 157 157 return File_function_NetCDF(filename, domain, quantities, interpolation_points, verbose = verbose) 158 158 else: 159 return File_function_ASCII(filename, domain, quantities, interpolation_points) 160 161 159 return File_function_ASCII(filename, domain, quantities, interpolation_points) 160 161 162 162 class File_function_NetCDF: 163 """Read time history of spatial data from NetCDF sww file and 164 return a callable object f(t,x,y) 165 which will return interpolated values based on the input file. 166 163 """Read time history of spatial data from NetCDF sww file and 164 return a callable object f(t,x,y) 165 which will return interpolated values based on the input file. 166 167 167 x, y may be either scalars or vectors 168 168 169 169 #FIXME: More about format, interpolation and order of quantities 170 170 171 171 The quantities returned by the callable objects are specified by 172 the list quantities which must contain the names of the 172 the list quantities which must contain the names of the 173 173 quantities to be returned and also reflect the order, e.g. for 174 the shallow water wave equation, on would have 174 the shallow water wave equation, on would have 175 175 quantities = ['stage', 'xmomentum', 'ymomentum'] 176 177 interpolation_points decides at which points interpolated 176 177 interpolation_points decides at which points interpolated 178 178 quantities are to be computed whenever object is called. 179 180 181 179 180 181 182 182 If None, return average value 183 183 """ 184 184 185 185 def __init__(self, filename, domain=None, quantities=None, 186 186 interpolation_points=None, verbose = False): … … 189 189 If domain is specified, model time (domain.starttime) 190 190 will be checked and possibly modified 191 191 192 192 All times are assumed to be in UTC 193 193 """ … … 196 196 #(both in UTM coordinates) 197 197 #If not - modify those from file to match domain 198 198 199 199 import time, calendar 200 200 from config import time_format 201 from Scientific.IO.NetCDF import NetCDFFile 201 from Scientific.IO.NetCDF import NetCDFFile 202 202 203 203 #Open NetCDF file … … 213 213 if not fid.variables.has_key(quantity): 214 214 missing.append(quantity) 215 215 216 216 if len(missing) > 0: 217 217 msg = 'Quantities %s could not be found in file %s'\ 218 218 %(str(missing), filename) 219 219 raise msg 220 220 221 221 222 222 #Get first timestep 223 223 try: 224 224 self.starttime = fid.starttime[0] 225 except ValueError: 225 except ValueError: 226 226 msg = 'Could not read starttime from file %s' %filename 227 227 raise msg … … 229 229 #Get origin 230 230 self.xllcorner = fid.xllcorner[0] 231 self.yllcorner = fid.yllcorner[0] 232 231 self.yllcorner = fid.yllcorner[0] 232 233 233 self.number_of_values = len(quantities) 234 234 self.fid = fid … … 249 249 if verbose: print 'Domain starttime is now set to %f' %domain.starttime 250 250 251 #Read all data in and produce values for desired data points at each timestep 252 self.spatial_interpolation(interpolation_points, verbose = verbose) 251 #Read all data in and produce values for desired data points at each timestep 252 self.spatial_interpolation(interpolation_points, verbose = verbose) 253 253 fid.close() 254 254 255 255 def spatial_interpolation(self, interpolation_points, verbose = False): 256 """For each timestep in fid: read surface, interpolate to desired points 256 """For each timestep in fid: read surface, interpolate to desired points 257 257 and store values for use when object is called. 258 258 """ 259 259 260 260 from Numeric import array, zeros, Float, alltrue, concatenate, reshape 261 261 … … 263 263 from least_squares import Interpolation 264 264 import time, calendar 265 265 266 266 fid = self.fid 267 267 … … 273 273 triangles = fid.variables['volumes'][:] 274 274 time = fid.variables['time'][:] 275 275 276 276 #Check 277 277 msg = 'File %s must list time as a monotonuosly ' %self.filename 278 278 msg += 'increasing sequence' 279 assert alltrue(time[1:] - time[:-1] > 0 ), msg 280 281 282 if interpolation_points is not None: 283 279 assert alltrue(time[1:] - time[:-1] > 0 ), msg 280 281 282 if interpolation_points is not None: 283 284 284 try: 285 P = ensure_numeric(interpolation_points) 285 P = ensure_numeric(interpolation_points) 286 286 except: 287 287 msg = 'Interpolation points must be an N x 2 Numeric array or a list of points\n' 288 288 msg += 'I got: %s.' %( str(interpolation_points)[:60] + '...') 289 289 raise msg 290 291 290 291 292 292 self.T = time[:] #Time assumed to be relative to starttime 293 self.index = 0 #Initial time index 294 295 self.values = {} 293 self.index = 0 #Initial time index 294 295 self.values = {} 296 296 for name in self.quantities: 297 self.values[name] = zeros( (len(self.T), 298 len(interpolation_points)), 299 Float) 297 self.values[name] = zeros( (len(self.T), 298 len(interpolation_points)), 299 Float) 300 300 301 301 #Build interpolator 302 302 if verbose: print 'Build interpolation matrix' 303 303 x = reshape(x, (len(x),1)) 304 y = reshape(y, (len(y),1)) 304 y = reshape(y, (len(y),1)) 305 305 vertex_coordinates = concatenate((x,y), axis=1) #m x 2 array 306 306 307 interpol = Interpolation(vertex_coordinates, 307 interpol = Interpolation(vertex_coordinates, 308 308 triangles, 309 309 point_coordinates = P, 310 alpha = 0, 310 alpha = 0, 311 311 verbose = verbose) 312 312 … … 318 318 for name in self.quantities: 319 319 self.values[name][i, :] =\ 320 interpol.interpolate(fid.variables[name][i,:]) 320 interpol.interpolate(fid.variables[name][i,:]) 321 321 322 322 #Report … … 327 327 print ' Reference:' 328 328 print ' Lower left corner: [%f, %f]'\ 329 %(self.xllcorner, self.yllcorner) 329 %(self.xllcorner, self.yllcorner) 330 330 print ' Start time (file): %f' %self.starttime 331 331 #print ' Start time (domain): %f' %domain.starttime … … 342 342 print ' %s in [%f, %f]' %(name, min(q), max(q)) 343 343 344 344 345 345 print ' Interpolation points (xi, eta):'\ 346 346 'number of points == %d ' %P.shape[0] … … 349 349 print ' Interpolated quantities (over all timesteps):' 350 350 for name in self.quantities: 351 q = self.values[name][:].flat 351 q = self.values[name][:].flat 352 352 print ' %s at interpolation points in [%f, %f]'\ 353 %(name, min(q), max(q)) 354 355 356 353 %(name, min(q), max(q)) 354 355 356 357 357 358 358 print '------------------------------------------------' … … 367 367 def __call__(self, t, x=None, y=None, point_id = None): 368 368 """Evaluate f(t, point_id) 369 369 370 370 Inputs: 371 t: time - Model time (tau = domain.starttime-self.starttime+t) 372 must lie within existing timesteps 373 point_id: index of one of the preprocessed points. 371 t: time - Model time (tau = domain.starttime-self.starttime+t) 372 must lie within existing timesteps 373 point_id: index of one of the preprocessed points. 374 374 If point_id is None all preprocessed points are computed 375 375 376 FIXME: point_id could also be a slice 377 FIXME: One could allow arbitrary x, y coordinates 376 FIXME: point_id could also be a slice 377 FIXME: One could allow arbitrary x, y coordinates 378 378 (requires computation of a new interpolator) 379 379 Maybe not,.,. 380 FIXME: What if x and y are vectors? 380 FIXME: What if x and y are vectors? 381 381 """ 382 382 … … 393 393 # 394 394 # domain.starttime + t == self.starttime + tau 395 395 396 396 if self.domain is not None: 397 397 tau = self.domain.starttime-self.starttime+t … … 403 403 #print 'S start', self.starttime 404 404 #print 't', t 405 #print 'tau', tau 406 405 #print 'tau', tau 406 407 407 msg = 'Time interval derived from file %s [%s:%s]'\ 408 408 %(self.filename, self.T[0], self.T[1]) … … 411 411 412 412 if tau < self.T[0]: raise msg 413 if tau > self.T[-1]: raise msg 413 if tau > self.T[-1]: raise msg 414 414 415 415 … … 424 424 #Protect against case where tau == T[-1] (last time) 425 425 # - also works in general when tau == T[i] 426 ratio = 0 426 ratio = 0 427 427 else: 428 #t is now between index and index+1 428 #t is now between index and index+1 429 429 ratio = (tau - self.T[self.index])/\ 430 430 (self.T[self.index+1] - self.T[self.index]) … … 432 432 433 433 434 434 435 435 #Compute interpolated values 436 436 q = zeros( len(self.quantities), Float) 437 437 438 438 for i, name in enumerate(self.quantities): 439 Q = self.values[name] 439 Q = self.values[name] 440 440 441 441 if ratio > 0: … … 450 450 #Return vector of interpolated values 451 451 return q 452 453 452 453 454 454 class File_function_ASCII: 455 455 """Read time series from file and return a callable object: … … 468 468 interpolated values, one each value stated in the file. 469 469 470 470 471 471 E.g 472 472 … … 477 477 ignoring x and y, which returns three values per call. 478 478 479 479 480 480 NOTE: At this stage the function is assumed to depend on 481 481 time only, i.e no spatial dependency!!!!! 482 482 When that is needed we can use the least_squares interpolation. 483 484 #FIXME: This should work with netcdf (e.g. sww) and thus render the 483 484 #FIXME: This should work with netcdf (e.g. sww) and thus render the 485 485 #spatio-temporal boundary condition in shallow water fully general 486 487 #FIXME: Specified quantites not used here - 486 487 #FIXME: Specified quantites not used here - 488 488 #always return whatever is in the file 489 489 """ 490 490 491 491 492 492 def __init__(self, filename, domain=None, quantities = None, interpolation_points=None): 493 493 """Initialise callable object from a file. … … 507 507 line = fid.readline() 508 508 fid.close() 509 509 510 510 fields = line.split(',') 511 511 msg = 'File %s must have the format date, value0 value1 value2 ...' … … 516 516 try: 517 517 starttime = calendar.timegm(time.strptime(fields[0], time_format)) 518 except ValueError: 518 except ValueError: 519 519 msg = 'First field in file %s must be' %filename 520 520 msg += ' date-time with format %s.\n' %time_format 521 msg += 'I got %s instead.' %fields[0] 521 msg += 'I got %s instead.' %fields[0] 522 522 raise msg 523 523 … … 529 529 530 530 q = ensure_numeric(values) 531 531 532 532 msg = 'ERROR: File must contain at least one independent value' 533 533 assert len(q.shape) == 1, msg 534 534 535 535 self.number_of_values = len(q) 536 536 … … 549 549 ##if verbose: print msg 550 550 domain.starttime = self.starttime #Modifying model time 551 551 552 552 #if domain.starttime is None: 553 553 # domain.starttime = self.starttime … … 563 563 # domain.starttime = self.starttime #Modifying model time 564 564 565 if mode == 2: 565 if mode == 2: 566 566 self.read_times() #Now read all times in. 567 567 else: 568 568 raise 'x,y dependency not yet implemented' 569 569 570 570 571 571 def read_times(self): 572 """Read time and values 572 """Read time and values 573 573 """ 574 574 from Numeric import zeros, Float, alltrue 575 575 from config import time_format 576 576 import time, calendar 577 578 fid = open(self.filename) 577 578 fid = open(self.filename) 579 579 lines = fid.readlines() 580 580 fid.close() 581 581 582 582 N = len(lines) 583 583 d = self.number_of_values … … 585 585 T = zeros(N, Float) #Time 586 586 Q = zeros((N, d), Float) #Values 587 587 588 588 for i, line in enumerate(lines): 589 589 fields = line.split(',') … … 603 603 self.index = 0 #Initial index 604 604 605 605 606 606 def __repr__(self): 607 607 return 'File function' … … 613 613 result is a vector of same length as x and y 614 614 FIXME: Naaaa 615 615 616 616 FIXME: Rethink semantics when x,y are vectors. 617 617 """ 618 618 619 619 from math import pi, cos, sin, sqrt 620 620 621 621 622 622 #Find time tau such that 623 623 # 624 624 # domain.starttime + t == self.starttime + tau 625 625 626 626 if self.domain is not None: 627 627 tau = self.domain.starttime-self.starttime+t 628 628 else: 629 629 tau = t 630 631 630 631 632 632 msg = 'Time interval derived from file %s (%s:%s) does not match model time: %s'\ 633 633 %(self.filename, self.T[0], self.T[1], tau) 634 634 if tau < self.T[0]: raise msg 635 if tau > self.T[-1]: raise msg 635 if tau > self.T[-1]: raise msg 636 636 637 637 oldindex = self.index … … 647 647 #Compute interpolated values 648 648 q = self.Q[self.index,:] +\ 649 ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 649 ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 650 650 651 651 #Return vector of interpolated values … … 662 662 N = len(x) 663 663 assert len(y) == N, 'x and y must have same length' 664 664 665 665 res = [] 666 666 for col in q: 667 667 res.append(col*ones(N, Float)) 668 668 669 669 return res 670 671 672 #FIXME: TEMP 670 671 672 #FIXME: TEMP 673 673 class File_function_copy: 674 674 """Read time series from file and return a callable object: … … 687 687 interpolated values, one each value stated in the file. 688 688 689 689 690 690 E.g 691 691 … … 696 696 ignoring x and y, which returns three values per call. 697 697 698 698 699 699 NOTE: At this stage the function is assumed to depend on 700 700 time only, i.e no spatial dependency!!!!! 701 701 When that is needed we can use the least_squares interpolation. 702 703 #FIXME: This should work with netcdf (e.g. sww) and thus render the 702 703 #FIXME: This should work with netcdf (e.g. sww) and thus render the 704 704 #spatio-temporal boundary condition in shallow water fully general 705 705 """ 706 706 707 707 708 708 def __init__(self, filename, domain=None): 709 709 """Initialise callable object from a file. … … 742 742 try: 743 743 starttime = calendar.timegm(time.strptime(fields[0], time_format)) 744 except ValueError: 744 except ValueError: 745 745 msg = 'First field in file %s must be' %filename 746 746 msg += ' date-time with format %s.\n' %time_format 747 msg += 'I got %s instead.' %fields[0] 747 msg += 'I got %s instead.' %fields[0] 748 748 raise msg 749 749 … … 755 755 756 756 q = ensure_numeric(values) 757 757 758 758 msg = 'ERROR: File must contain at least one independent value' 759 759 assert len(q.shape) == 1, msg 760 760 761 761 self.number_of_values = len(q) 762 762 … … 779 779 domain.starttime = self.starttime #Modifying model time 780 780 781 if mode == 2: 781 if mode == 2: 782 782 self.read_times() #Now read all times in. 783 783 else: 784 784 raise 'x,y dependency not yet implemented' 785 785 786 786 787 787 def read_times(self): 788 """Read time and values 788 """Read time and values 789 789 """ 790 790 from Numeric import zeros, Float, alltrue 791 791 from config import time_format 792 792 import time, calendar 793 794 fid = open(self.filename) 793 794 fid = open(self.filename) 795 795 lines = fid.readlines() 796 796 fid.close() 797 797 798 798 N = len(lines) 799 799 d = self.number_of_values … … 801 801 T = zeros(N, Float) #Time 802 802 Q = zeros((N, d), Float) #Values 803 803 804 804 for i, line in enumerate(lines): 805 805 fields = line.split(',') … … 819 819 self.index = 0 #Initial index 820 820 821 821 822 822 def __repr__(self): 823 823 return 'File function' 824 824 825 825 826 826 827 827 def __call__(self, t, x=None, y=None): … … 834 834 835 835 from math import pi, cos, sin, sqrt 836 836 837 837 838 838 #Find time tau such that 839 839 # 840 840 # domain.starttime + t == self.starttime + tau 841 841 842 842 if self.domain is not None: 843 843 tau = self.domain.starttime-self.starttime+t 844 844 else: 845 845 tau = t 846 847 846 847 848 848 msg = 'Time interval derived from file %s (%s:%s) does not match model time: %s'\ 849 849 %(self.filename, self.T[0], self.T[1], tau) 850 850 if tau < self.T[0]: raise msg 851 if tau > self.T[-1]: raise msg 851 if tau > self.T[-1]: raise msg 852 852 853 853 oldindex = self.index … … 863 863 #Compute interpolated values 864 864 q = self.Q[self.index,:] +\ 865 ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 865 ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 866 866 867 867 #Return vector of interpolated values … … 878 878 N = len(x) 879 879 assert len(y) == N, 'x and y must have same length' 880 880 881 881 res = [] 882 882 for col in q: 883 883 res.append(col*ones(N, Float)) 884 884 885 885 return res 886 886 887 887 888 888 def read_xya(filename, format = 'netcdf'): … … 892 892 893 893 Format can be either ASCII or NetCDF 894 894 895 895 Return list of points, list of attributes and 896 896 attribute names if present otherwise None 897 897 """ 898 898 #FIXME: Probably obsoleted by similar function in load_ASCII 899 899 900 900 from Scientific.IO.NetCDF import NetCDFFile 901 901 902 if format.lower() == 'netcdf': 902 if format.lower() == 'netcdf': 903 903 #Get NetCDF 904 905 fid = NetCDFFile(filename, 'r') 906 904 905 fid = NetCDFFile(filename, 'r') 906 907 907 # Get the variables 908 908 points = fid.variables['points'] … … 913 913 #Don't close - arrays are needed outside this function, 914 914 #alternatively take a copy here 915 else: 915 else: 916 916 #Read as ASCII file assuming that it is separated by whitespace 917 917 fid = open(filename) … … 930 930 attribute_names = ['elevation'] #HACK 931 931 932 attributes = {} 932 attributes = {} 933 933 for key in attribute_names: 934 934 attributes[key] = [] … … 940 940 for i, key in enumerate(attribute_names): 941 941 attributes[key].append( float(fields[2+i]) ) 942 942 943 943 return points, attributes 944 944 945 945 946 946 ##################################### … … 950 950 951 951 952 953 #Redefine these to use separate_by_polygon which will put all inside indices 952 953 #Redefine these to use separate_by_polygon which will put all inside indices 954 954 #in the first part of the indices array and outside indices in the last 955 955 … … 957 957 """See separate_points_by_polygon for documentation 958 958 """ 959 960 from Numeric import array, Float, reshape 961 962 if verbose: print 'Checking input to inside_polygon' 959 960 from Numeric import array, Float, reshape 961 962 if verbose: print 'Checking input to inside_polygon' 963 963 try: 964 points = ensure_numeric(points, Float) 964 points = ensure_numeric(points, Float) 965 965 except: 966 966 msg = 'Points could not be converted to Numeric array' 967 raise msg 968 967 raise msg 968 969 969 try: 970 polygon = ensure_numeric(polygon, Float) 970 polygon = ensure_numeric(polygon, Float) 971 971 except: 972 972 msg = 'Polygon could not be converted to Numeric array' 973 raise msg 974 975 976 973 raise msg 974 975 976 977 977 if len(points.shape) == 1: 978 978 one_point = True 979 979 points = reshape(points, (1,2)) 980 else: 980 else: 981 981 one_point = False 982 982 983 indices, count = separate_points_by_polygon(points, polygon, 984 closed, verbose) 985 983 indices, count = separate_points_by_polygon(points, polygon, 984 closed, verbose) 985 986 986 if one_point: 987 987 return count == 1 988 988 else: 989 return indices[:count] 990 989 return indices[:count] 990 991 991 def outside_polygon(points, polygon, closed = True, verbose = False): 992 992 """See separate_points_by_polygon for documentation 993 993 """ 994 995 from Numeric import array, Float, reshape 996 997 if verbose: print 'Checking input to outside_polygon' 994 995 from Numeric import array, Float, reshape 996 997 if verbose: print 'Checking input to outside_polygon' 998 998 try: 999 points = ensure_numeric(points, Float) 999 points = ensure_numeric(points, Float) 1000 1000 except: 1001 1001 msg = 'Points could not be converted to Numeric array' 1002 raise msg 1003 1002 raise msg 1003 1004 1004 try: 1005 polygon = ensure_numeric(polygon, Float) 1005 polygon = ensure_numeric(polygon, Float) 1006 1006 except: 1007 1007 msg = 'Polygon could not be converted to Numeric array' 1008 raise msg 1009 1010 1011 1008 raise msg 1009 1010 1011 1012 1012 if len(points.shape) == 1: 1013 1013 one_point = True 1014 1014 points = reshape(points, (1,2)) 1015 else: 1015 else: 1016 1016 one_point = False 1017 1017 1018 indices, count = separate_points_by_polygon(points, polygon, 1019 closed, verbose) 1020 1018 indices, count = separate_points_by_polygon(points, polygon, 1019 closed, verbose) 1020 1021 1021 if one_point: 1022 1022 return count != 1 1023 1023 else: 1024 return indices[count:][::-1] #return reversed 1025 1026 1027 def separate_points_by_polygon(points, polygon, 1024 return indices[count:][::-1] #return reversed 1025 1026 1027 def separate_points_by_polygon(points, polygon, 1028 1028 closed = True, verbose = False): 1029 1029 """Determine whether points are inside or outside a polygon 1030 1030 1031 1031 Input: 1032 1032 points - Tuple of (x, y) coordinates, or list of tuples 1033 1033 polygon - list of vertices of polygon 1034 closed - (optional) determine whether points on boundary should be 1035 regarded as belonging to the polygon (closed = True) 1036 or not (closed = False) 1037 1034 closed - (optional) determine whether points on boundary should be 1035 regarded as belonging to the polygon (closed = True) 1036 or not (closed = False) 1037 1038 1038 Outputs: 1039 indices: array of same length as points with indices of points falling 1040 inside the polygon listed from the beginning and indices of points 1039 indices: array of same length as points with indices of points falling 1040 inside the polygon listed from the beginning and indices of points 1041 1041 falling outside listed from the end. 1042 1042 1043 1043 count: count of points falling inside the polygon 1044 1044 1045 1045 The indices of points inside are obtained as indices[:count] 1046 The indices of points outside are obtained as indices[count:] 1047 1048 1046 The indices of points outside are obtained as indices[count:] 1047 1048 1049 1049 Examples: 1050 1050 U = [[0,0], [1,0], [1,1], [0,1]] #Unit square 1051 1051 1052 1052 separate_points_by_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U) 1053 will return the indices [0, 2, 1] and count == 2 as only the first 1053 will return the indices [0, 2, 1] and count == 2 as only the first 1054 1054 and the last point are inside the unit square 1055 1055 1056 1056 Remarks: 1057 1057 The vertices may be listed clockwise or counterclockwise and 1058 the first point may optionally be repeated. 1058 the first point may optionally be repeated. 1059 1059 Polygons do not need to be convex. 1060 Polygons can have holes in them and points inside a hole is 1061 regarded as being outside the polygon. 1062 1063 Algorithm is based on work by Darel Finley, 1064 http://www.alienryderflex.com/polygon/ 1065 1066 """ 1060 Polygons can have holes in them and points inside a hole is 1061 regarded as being outside the polygon. 1062 1063 Algorithm is based on work by Darel Finley, 1064 http://www.alienryderflex.com/polygon/ 1065 1066 """ 1067 1067 1068 1068 from Numeric import array, Float, reshape, Int, zeros 1069 1070 1071 #Input checks 1072 try: 1073 points = ensure_numeric(points, Float) 1074 except: 1075 msg = 'Points could not be converted to Numeric array' 1076 raise msg 1077 1078 try: 1079 polygon = ensure_numeric(polygon, Float) 1080 except: 1081 msg = 'Polygon could not be converted to Numeric array' 1082 raise msg 1083 1084 assert len(polygon.shape) == 2,\ 1085 'Polygon array must be a 2d array of vertices' 1086 1087 assert polygon.shape[1] == 2,\ 1088 'Polygon array must have two columns' 1089 1090 assert len(points.shape) == 2,\ 1091 'Points array must be a 2d array' 1092 1093 assert points.shape[1] == 2,\ 1094 'Points array must have two columns' 1095 1096 N = polygon.shape[0] #Number of vertices in polygon 1097 M = points.shape[0] #Number of points 1098 1099 px = polygon[:,0] 1100 py = polygon[:,1] 1101 1102 #Used for an optimisation when points are far away from polygon 1103 minpx = min(px); maxpx = max(px) 1104 minpy = min(py); maxpy = max(py) 1105 1106 1107 #Begin main loop 1108 indices = zeros(M, Int) 1109 1110 inside_index = 0 #Keep track of points inside 1111 outside_index = M-1 #Keep track of points outside (starting from end) 1112 1113 for k in range(M): 1114 1115 if verbose: 1116 if k %((M+10)/10)==0: print 'Doing %d of %d' %(k, M) 1117 1118 #for each point 1119 x = points[k, 0] 1120 y = points[k, 1] 1121 1122 inside = False 1123 1124 if not x > maxpx or x < minpx or y > maxpy or y < minpy: 1125 #Check polygon 1126 for i in range(N): 1127 j = (i+1)%N 1128 1129 #Check for case where point is contained in line segment 1130 if point_on_line(x, y, px[i], py[i], px[j], py[j]): 1131 if closed: 1132 inside = True 1133 else: 1134 inside = False 1135 break 1136 else: 1137 #Check if truly inside polygon 1138 if py[i] < y and py[j] >= y or\ 1139 py[j] < y and py[i] >= y: 1140 if px[i] + (y-py[i])/(py[j]-py[i])*(px[j]-px[i]) < x: 1141 inside = not inside 1142 1143 if inside: 1144 indices[inside_index] = k 1145 inside_index += 1 1146 else: 1147 indices[outside_index] = k 1148 outside_index -= 1 1149 1150 return indices, inside_index 1151 1152 1153 def separate_points_by_polygon_c(points, polygon, 1154 closed = True, verbose = False): 1155 """Determine whether points are inside or outside a polygon 1156 1157 C-wrapper 1158 """ 1159 1160 from Numeric import array, Float, reshape, zeros, Int 1161 1162 1163 if verbose: print 'Checking input to separate_points_by_polygon' 1069 1070 1164 1071 #Input checks 1165 1072 try: … … 1169 1076 raise msg 1170 1077 1171 #if verbose: print 'Checking input to separate_points_by_polygon 2'1172 1078 try: 1173 1079 polygon = ensure_numeric(polygon, Float) 1174 1080 except: 1175 1081 msg = 'Polygon could not be converted to Numeric array' 1176 raise msg 1177 1178 if verbose: print 'check' 1179 1082 raise msg 1083 1180 1084 assert len(polygon.shape) == 2,\ 1181 1085 'Polygon array must be a 2d array of vertices' … … 1186 1090 assert len(points.shape) == 2,\ 1187 1091 'Points array must be a 2d array' 1188 1092 1189 1093 assert points.shape[1] == 2,\ 1190 1094 'Points array must have two columns' 1191 1192 N = polygon.shape[0] #Number of vertices in polygon 1095 1096 N = polygon.shape[0] #Number of vertices in polygon 1193 1097 M = points.shape[0] #Number of points 1194 1098 1099 px = polygon[:,0] 1100 py = polygon[:,1] 1101 1102 #Used for an optimisation when points are far away from polygon 1103 minpx = min(px); maxpx = max(px) 1104 minpy = min(py); maxpy = max(py) 1105 1106 1107 #Begin main loop 1108 indices = zeros(M, Int) 1109 1110 inside_index = 0 #Keep track of points inside 1111 outside_index = M-1 #Keep track of points outside (starting from end) 1112 1113 for k in range(M): 1114 1115 if verbose: 1116 if k %((M+10)/10)==0: print 'Doing %d of %d' %(k, M) 1117 1118 #for each point 1119 x = points[k, 0] 1120 y = points[k, 1] 1121 1122 inside = False 1123 1124 if not x > maxpx or x < minpx or y > maxpy or y < minpy: 1125 #Check polygon 1126 for i in range(N): 1127 j = (i+1)%N 1128 1129 #Check for case where point is contained in line segment 1130 if point_on_line(x, y, px[i], py[i], px[j], py[j]): 1131 if closed: 1132 inside = True 1133 else: 1134 inside = False 1135 break 1136 else: 1137 #Check if truly inside polygon 1138 if py[i] < y and py[j] >= y or\ 1139 py[j] < y and py[i] >= y: 1140 if px[i] + (y-py[i])/(py[j]-py[i])*(px[j]-px[i]) < x: 1141 inside = not inside 1142 1143 if inside: 1144 indices[inside_index] = k 1145 inside_index += 1 1146 else: 1147 indices[outside_index] = k 1148 outside_index -= 1 1149 1150 return indices, inside_index 1151 1152 1153 def separate_points_by_polygon_c(points, polygon, 1154 closed = True, verbose = False): 1155 """Determine whether points are inside or outside a polygon 1156 1157 C-wrapper 1158 """ 1159 1160 from Numeric import array, Float, reshape, zeros, Int 1161 1162 1163 if verbose: print 'Checking input to separate_points_by_polygon' 1164 #Input checks 1165 try: 1166 points = ensure_numeric(points, Float) 1167 except: 1168 msg = 'Points could not be converted to Numeric array' 1169 raise msg 1170 1171 #if verbose: print 'Checking input to separate_points_by_polygon 2' 1172 try: 1173 polygon = ensure_numeric(polygon, Float) 1174 except: 1175 msg = 'Polygon could not be converted to Numeric array' 1176 raise msg 1177 1178 if verbose: print 'check' 1179 1180 assert len(polygon.shape) == 2,\ 1181 'Polygon array must be a 2d array of vertices' 1182 1183 assert polygon.shape[1] == 2,\ 1184 'Polygon array must have two columns' 1185 1186 assert len(points.shape) == 2,\ 1187 'Points array must be a 2d array' 1188 1189 assert points.shape[1] == 2,\ 1190 'Points array must have two columns' 1191 1192 N = polygon.shape[0] #Number of vertices in polygon 1193 M = points.shape[0] #Number of points 1194 1195 1195 from util_ext import separate_points_by_polygon 1196 1196 … … 1199 1199 indices = zeros( M, Int ) 1200 1200 1201 if verbose: print 'Calling C-version of inside poly' 1201 if verbose: print 'Calling C-version of inside poly' 1202 1202 count = separate_points_by_polygon(points, polygon, indices, 1203 1203 int(closed), int(verbose)) 1204 1204 1205 return indices, count 1205 return indices, count 1206 1206 1207 1207 1208 1208 1209 1209 class Polygon_function: 1210 """Create callable object f: x,y -> z, where a,y,z are vectors and 1211 where f will return different values depending on whether x,y belongs 1210 """Create callable object f: x,y -> z, where a,y,z are vectors and 1211 where f will return different values depending on whether x,y belongs 1212 1212 to specified polygons. 1213 1213 1214 1214 To instantiate: 1215 1215 1216 1216 Polygon_function(polygons) 1217 1217 1218 1218 where polygons is a list of tuples of the form 1219 1219 1220 1220 [ (P0, v0), (P1, v1), ...] 1221 1222 with Pi being lists of vertices defining polygons and vi either 1221 1222 with Pi being lists of vertices defining polygons and vi either 1223 1223 constants or functions of x,y to be applied to points with the polygon. 1224 1225 The function takes an optional argument, default which is the value 1224 1225 The function takes an optional argument, default which is the value 1226 1226 (or function) to used for points not belonging to any polygon. 1227 1227 For example: 1228 1229 Polygon_function(polygons, default = 0.03) 1230 1231 If omitted the default value will be 0.0 1232 1228 1229 Polygon_function(polygons, default = 0.03) 1230 1231 If omitted the default value will be 0.0 1232 1233 1233 Note: If two polygons overlap, the one last in the list takes precedence 1234 1234 … … 1236 1236 1237 1237 """ 1238 1238 1239 1239 def __init__(self, regions, default = 0.0): 1240 1240 1241 1241 try: 1242 1242 len(regions) 1243 1243 except: 1244 msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons 1244 msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons 1245 1245 raise msg 1246 1246 1247 1247 1248 T = regions[0] 1248 T = regions[0] 1249 1249 try: 1250 1250 a = len(T) 1251 except: 1252 msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons 1253 raise msg 1254 1255 assert a == 2, 'Must have two component each: %s' %T 1256 1257 self.regions = regions 1251 except: 1252 msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons 1253 raise msg 1254 1255 assert a == 2, 'Must have two component each: %s' %T 1256 1257 self.regions = regions 1258 1258 self.default = default 1259 1260 1259 1260 1261 1261 def __call__(self, x, y): 1262 1262 from util import inside_polygon 1263 1263 from Numeric import ones, Float, concatenate, array, reshape, choose 1264 1264 1265 1265 x = array(x).astype(Float) 1266 y = array(y).astype(Float) 1267 1266 y = array(y).astype(Float) 1267 1268 1268 N = len(x) 1269 1269 assert len(y) == N 1270 1271 points = concatenate( (reshape(x, (N, 1)), 1270 1271 points = concatenate( (reshape(x, (N, 1)), 1272 1272 reshape(y, (N, 1))), axis=1 ) 1273 1273 1274 1274 if callable(self.default): 1275 1275 z = self.default(x,y) 1276 else: 1276 else: 1277 1277 z = ones(N, Float) * self.default 1278 1278 1279 1279 for polygon, value in self.regions: 1280 1280 indices = inside_polygon(points, polygon) 1281 1282 #FIXME: This needs to be vectorised 1281 1282 #FIXME: This needs to be vectorised 1283 1283 if callable(value): 1284 1284 for i in indices: … … 1286 1286 yy = array([y[i]]) 1287 1287 z[i] = value(xx, yy)[0] 1288 else: 1288 else: 1289 1289 for i in indices: 1290 z[i] = value 1291 1292 return z 1290 z[i] = value 1291 1292 return z 1293 1293 1294 1294 def read_polygon(filename): 1295 1295 """Read points assumed to form a polygon 1296 1296 There must be exactly two numbers in each line 1297 """ 1298 1297 """ 1298 1299 1299 #Get polygon 1300 1300 fid = open(filename) … … 1306 1306 polygon.append( [float(fields[0]), float(fields[1])] ) 1307 1307 1308 return polygon 1309 1308 return polygon 1309 1310 1310 def populate_polygon(polygon, number_of_points, seed = None): 1311 1311 """Populate given polygon with uniformly distributed points. … … 1313 1313 Input: 1314 1314 polygon - list of vertices of polygon 1315 number_of_points - (optional) number of points 1315 number_of_points - (optional) number of points 1316 1316 seed - seed for random number generator (default=None) 1317 1317 1318 1318 Output: 1319 1319 points - list of points inside polygon 1320 1320 1321 1321 Examples: 1322 1322 populate_polygon( [[0,0], [1,0], [1,1], [0,1]], 5 ) 1323 will return five randomly selected points inside the unit square 1323 will return five randomly selected points inside the unit square 1324 1324 """ 1325 1325 … … 1334 1334 max_y = min_y = polygon[0][1] 1335 1335 for point in polygon[1:]: 1336 x = point[0] 1336 x = point[0] 1337 1337 if x > max_x: max_x = x 1338 if x < min_x: min_x = x 1339 y = point[1] 1338 if x < min_x: min_x = x 1339 y = point[1] 1340 1340 if y > max_y: max_y = y 1341 if y < min_y: min_y = y 1342 1343 1344 while len(points) < number_of_points: 1341 if y < min_y: min_y = y 1342 1343 1344 while len(points) < number_of_points: 1345 1345 x = uniform(min_x, max_x) 1346 y = uniform(min_y, max_y) 1346 y = uniform(min_y, max_y) 1347 1347 1348 1348 if inside_polygon( [x,y], polygon ): … … 1353 1353 def tsh2sww(filename, verbose=True): 1354 1354 """ 1355 to check if a tsh/msh file 'looks' good. 1355 to check if a tsh/msh file 'looks' good. 1356 1356 """ 1357 1357 from shallow_water import Domain 1358 1358 from pmesh2domain import pmesh_to_domain_instance 1359 import time, os 1360 from data_manager import get_dataobject 1361 from os import sep, path 1359 import time, os 1360 from data_manager import get_dataobject 1361 from os import sep, path 1362 1362 #from util import mean 1363 1363 1364 1364 if verbose == True:print 'Creating domain from', filename 1365 1365 domain = pmesh_to_domain_instance(filename, Domain) … … 1378 1378 if verbose == True: 1379 1379 print "Output written to " + domain.get_datadir() + sep + \ 1380 domain.filename + "." + domain.format 1380 domain.filename + "." + domain.format 1381 1381 sww = get_dataobject(domain) 1382 1382 sww.store_connectivity() … … 1390 1390 """ 1391 1391 """ 1392 1393 det = (y2-y0)*(x1-x0) - (y1-y0)*(x2-x0) 1392 1393 det = (y2-y0)*(x1-x0) - (y1-y0)*(x2-x0) 1394 1394 a = (y2-y0)*(q1-q0) - (y1-y0)*(q2-q0) 1395 1395 a /= det 1396 1396 1397 1397 b = (x1-x0)*(q2-q0) - (x2-x0)*(q1-q0) 1398 b /= det 1398 b /= det 1399 1399 1400 1400 return a, b … … 1416 1416 pass 1417 1417 1418 1419 1420 1421 1422 1423 #OBSOLETED STUFF 1418 1419 1420 1421 1422 1423 #OBSOLETED STUFF 1424 1424 def inside_polygon_old(point, polygon, closed = True, verbose = False): 1425 1425 #FIXME Obsoleted 1426 1426 """Determine whether points are inside or outside a polygon 1427 1427 1428 1428 Input: 1429 1429 point - Tuple of (x, y) coordinates, or list of tuples 1430 1430 polygon - list of vertices of polygon 1431 closed - (optional) determine whether points on boundary should be 1432 regarded as belonging to the polygon (closed = True) 1433 or not (closed = False) 1434 1431 closed - (optional) determine whether points on boundary should be 1432 regarded as belonging to the polygon (closed = True) 1433 or not (closed = False) 1434 1435 1435 Output: 1436 1436 If one point is considered, True or False is returned. 1437 If multiple points are passed in, the function returns indices 1438 of those points that fall inside the polygon 1439 1437 If multiple points are passed in, the function returns indices 1438 of those points that fall inside the polygon 1439 1440 1440 Examples: 1441 1441 U = [[0,0], [1,0], [1,1], [0,1]] #Unit square 1442 1442 inside_polygon( [0.5, 0.5], U) 1443 will evaluate to True as the point 0.5, 0.5 is inside the unit square 1444 1443 will evaluate to True as the point 0.5, 0.5 is inside the unit square 1444 1445 1445 inside_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U) 1446 will return the indices [0, 2] as only the first and the last point 1446 will return the indices [0, 2] as only the first and the last point 1447 1447 is inside the unit square 1448 1448 1449 1449 Remarks: 1450 1450 The vertices may be listed clockwise or counterclockwise and 1451 the first point may optionally be repeated. 1451 the first point may optionally be repeated. 1452 1452 Polygons do not need to be convex. 1453 Polygons can have holes in them and points inside a hole is 1454 regarded as being outside the polygon. 1455 1456 1457 Algorithm is based on work by Darel Finley, 1458 http://www.alienryderflex.com/polygon/ 1459 1460 """ 1453 Polygons can have holes in them and points inside a hole is 1454 regarded as being outside the polygon. 1455 1456 1457 Algorithm is based on work by Darel Finley, 1458 http://www.alienryderflex.com/polygon/ 1459 1460 """ 1461 1461 1462 1462 from Numeric import array, Float, reshape 1463 1464 1463 1464 1465 1465 #Input checks 1466 1466 try: 1467 point = array(point).astype(Float) 1467 point = array(point).astype(Float) 1468 1468 except: 1469 1469 msg = 'Point %s could not be converted to Numeric array' %point 1470 raise msg 1471 1470 raise msg 1471 1472 1472 try: 1473 polygon = array(polygon).astype(Float) 1473 polygon = array(polygon).astype(Float) 1474 1474 except: 1475 1475 msg = 'Polygon %s could not be converted to Numeric array' %polygon 1476 raise msg 1477 1476 raise msg 1477 1478 1478 assert len(polygon.shape) == 2,\ 1479 1479 'Polygon array must be a 2d array of vertices: %s' %polygon 1480 1480 1481 1481 1482 1482 assert polygon.shape[1] == 2,\ 1483 'Polygon array must have two columns: %s' %polygon 1483 'Polygon array must have two columns: %s' %polygon 1484 1484 1485 1485 … … 1487 1487 one_point = True 1488 1488 points = reshape(point, (1,2)) 1489 else: 1489 else: 1490 1490 one_point = False 1491 1491 points = point 1492 1492 1493 N = polygon.shape[0] #Number of vertices in polygon 1493 N = polygon.shape[0] #Number of vertices in polygon 1494 1494 M = points.shape[0] #Number of points 1495 1495 1496 1496 px = polygon[:,0] 1497 py = polygon[:,1] 1497 py = polygon[:,1] 1498 1498 1499 1499 #Used for an optimisation when points are far away from polygon 1500 1500 minpx = min(px); maxpx = max(px) 1501 minpy = min(py); maxpy = max(py) 1501 minpy = min(py); maxpy = max(py) 1502 1502 1503 1503 … … 1508 1508 if verbose: 1509 1509 if k %((M+10)/10)==0: print 'Doing %d of %d' %(k, M) 1510 1511 #for each point 1512 1513 y = points[k, 1] 1510 1511 #for each point 1512 x = points[k, 0] 1513 y = points[k, 1] 1514 1514 1515 1515 inside = False … … 1517 1517 #Optimisation 1518 1518 if x > maxpx or x < minpx: continue 1519 if y > maxpy or y < minpy: continue 1520 1521 #Check polygon 1519 if y > maxpy or y < minpy: continue 1520 1521 #Check polygon 1522 1522 for i in range(N): 1523 1523 j = (i+1)%N 1524 1525 #Check for case where point is contained in line segment 1524 1525 #Check for case where point is contained in line segment 1526 1526 if point_on_line(x, y, px[i], py[i], px[j], py[j]): 1527 1527 if closed: 1528 1528 inside = True 1529 else: 1529 else: 1530 1530 inside = False 1531 1531 break 1532 else: 1533 #Check if truly inside polygon 1532 else: 1533 #Check if truly inside polygon 1534 1534 if py[i] < y and py[j] >= y or\ 1535 1535 py[j] < y and py[i] >= y: 1536 1536 if px[i] + (y-py[i])/(py[j]-py[i])*(px[j]-px[i]) < x: 1537 1537 inside = not inside 1538 1538 1539 1539 if inside: indices.append(k) 1540 1540 1541 if one_point: 1541 if one_point: 1542 1542 return inside 1543 1543 else: 1544 1544 return indices 1545 1545 1546 1546 1547 1547 #def remove_from(A, B): … … 1552 1552 # ind = search_sorted(A, B) 1553 1553 1554 1554 1555 1555 1556 1556 def outside_polygon_old(point, polygon, closed = True, verbose = False): 1557 1557 #OBSOLETED 1558 1558 """Determine whether points are outside a polygon 1559 1559 1560 1560 Input: 1561 1561 point - Tuple of (x, y) coordinates, or list of tuples 1562 1562 polygon - list of vertices of polygon 1563 closed - (optional) determine whether points on boundary should be 1564 regarded as belonging to the polygon (closed = True) 1565 or not (closed = False) 1566 1563 closed - (optional) determine whether points on boundary should be 1564 regarded as belonging to the polygon (closed = True) 1565 or not (closed = False) 1566 1567 1567 Output: 1568 1568 If one point is considered, True or False is returned. 1569 If multiple points are passed in, the function returns indices 1570 of those points that fall outside the polygon 1571 1569 If multiple points are passed in, the function returns indices 1570 of those points that fall outside the polygon 1571 1572 1572 Examples: 1573 U = [[0,0], [1,0], [1,1], [0,1]] #Unit square 1573 U = [[0,0], [1,0], [1,1], [0,1]] #Unit square 1574 1574 outside_polygon( [0.5, 0.5], U ) 1575 1575 will evaluate to False as the point 0.5, 0.5 is inside the unit square … … 1577 1577 ouside_polygon( [1.5, 0.5], U ) 1578 1578 will evaluate to True as the point 1.5, 0.5 is outside the unit square 1579 1579 1580 1580 outside_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U ) 1581 will return the indices [1] as only the first and the last point 1581 will return the indices [1] as only the first and the last point 1582 1582 is inside the unit square 1583 1583 """ 1584 1584 1585 1585 #FIXME: This is too slow 1586 1586 1587 1587 res = inside_polygon(point, polygon, closed, verbose) 1588 1588 … … 1602 1602 1603 1603 C-wrapper 1604 """ 1604 """ 1605 1605 1606 1606 from Numeric import array, Float, reshape, zeros, Int 1607 1608 1609 if verbose: print 'Checking input to inside_polygon' 1607 1608 1609 if verbose: print 'Checking input to inside_polygon' 1610 1610 #Input checks 1611 1611 try: 1612 point = array(point).astype(Float) 1612 point = array(point).astype(Float) 1613 1613 except: 1614 1614 msg = 'Point %s could not be converted to Numeric array' %point 1615 raise msg 1616 1615 raise msg 1616 1617 1617 try: 1618 polygon = array(polygon).astype(Float) 1618 polygon = array(polygon).astype(Float) 1619 1619 except: 1620 1620 msg = 'Polygon %s could not be converted to Numeric array' %polygon 1621 raise msg 1622 1621 raise msg 1622 1623 1623 assert len(polygon.shape) == 2,\ 1624 1624 'Polygon array must be a 2d array of vertices: %s' %polygon 1625 1625 1626 1626 1627 1627 assert polygon.shape[1] == 2,\ 1628 'Polygon array must have two columns: %s' %polygon 1628 'Polygon array must have two columns: %s' %polygon 1629 1629 1630 1630 … … 1632 1632 one_point = True 1633 1633 points = reshape(point, (1,2)) 1634 else: 1634 else: 1635 1635 one_point = False 1636 1636 points = point … … 1642 1642 indices = zeros( points.shape[0], Int ) 1643 1643 1644 if verbose: print 'Calling C-version of inside poly' 1644 if verbose: print 'Calling C-version of inside poly' 1645 1645 count = inside_polygon(points, polygon, indices, 1646 1646 int(closed), int(verbose)) … … 1650 1650 else: 1651 1651 if verbose: print 'Got %d points' %count 1652 1652 1653 1653 return indices[:count] #Return those indices that were inside 1654 -
inundation/ga/storm_surge/zeus/anuga-workspace.zwi
r1363 r1387 2 2 <workspace name="anuga-workspace"> 3 3 <mode>Debug</mode> 4 <active> parallel</active>4 <active>steve</active> 5 5 <project name="Merimbula">Merimbula.zpi</project> 6 6 <project name="parallel">parallel.zpi</project> -
inundation/ga/storm_surge/zeus/parallel.zpi
r1363 r1387 74 74 <ReleaseProjectReload>Off</ReleaseProjectReload> 75 75 <file>..\parallel\advection.py</file> 76 <file>..\parallel\domain.py</file> 76 77 <file>..\parallel\parallel_advection.py</file> 77 78 <file>..\parallel\run_advection.py</file> -
inundation/ga/storm_surge/zeus/steve.zpi
r1290 r1387 73 73 <ReleaseProjectSaveAll>Off</ReleaseProjectSaveAll> 74 74 <ReleaseProjectReload>Off</ReleaseProjectReload> 75 <file>..\steve\get_triangle_attribute.py</file> 75 76 <file>..\steve\get_triangle_data.py</file> 76 77 <file>..\steve\get_triangle_data_new.py</file> 78 <file>..\hobart\run_hobart_buildings.py</file> 77 79 <file>..\pyvolution-parallel\vtk-pylab.py</file> 78 80 <folder name="Header Files" />
Note: See TracChangeset
for help on using the changeset viewer.