Changeset 1280
- Timestamp:
- May 3, 2005, 5:33:04 PM (20 years ago)
- Location:
- inundation/ga/storm_surge
- Files:
-
- 6 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
inundation/ga/storm_surge/pyvolution/domain.py
r1187 r1280 81 81 #Checkpointing and storage 82 82 from config import default_datadir 83 84 85 83 self.datadir = default_datadir 84 self.filename = 'domain' 85 self.checkpoint = False 86 86 87 87 … … 322 322 """Output statistics about boundary forcing 323 323 324 325 """ 326 324 325 """ 326 327 327 if quantities is None: 328 328 quantities = self.conserved_quantities … … 344 344 v = q.boundary_values[i] 345 345 if minval is None or v < minval: minval = v 346 if maxval is None or v > maxval: maxval = v 346 if maxval is None or v > maxval: maxval = v 347 347 348 348 if minval is None or maxval is None: 349 349 print 'Sorry no information about tag %s' %tag 350 else: 350 else: 351 351 print ' Quantity %s, tag %s: min = %12.8f, max = %12.8f'\ 352 352 %(name, tag, minval, maxval) 353 354 355 356 357 358 359 360 361 353 354 355 356 357 358 359 360 361 362 362 363 363 def get_name(self): … … 412 412 if yieldstep is None: 413 413 yieldstep = max_timestep 414 414 else: 415 415 yieldstep = float(yieldstep) 416 416 … … 463 463 #Yield results 464 464 if finaltime is not None and abs(self.time - finaltime) < epsilon: 465 466 #FIXME: There is a rare situation where the 465 466 #FIXME: There is a rare situation where the 467 467 #final time step is stored twice. Can we make a test? 468 468 … … 637 637 except: 638 638 import os 639 if os.name == 'posix' and os.uname()[4] == 'x86_64': 639 if os.name == 'posix' and os.uname()[4] == 'x86_64': 640 640 pass 641 641 #Psyco isn't supported on 64 bit systems, but it doesn't matter -
inundation/ga/storm_surge/pyvolution/island.py
r912 r1280 6 6 7 7 ###################### 8 # Module imports 8 # Module imports 9 9 # 10 10 from os import sep, path … … 18 18 19 19 #Create basic mesh 20 N = 2020 N = 40 21 21 points, vertices, boundary = rectangular(N, N, 100, 100) 22 22 23 23 #Create shallow water domain 24 24 domain = Domain(points, vertices, boundary) 25 domain.store = True25 domain.store = False 26 26 domain.smooth = False 27 domain.visualise = False27 domain.visualise = True 28 28 domain.set_name('island') 29 29 print 'Output being written to ' + domain.get_datadir() + sep + \ 30 30 domain.get_name() + '.' + domain.format 31 31 32 32 33 33 domain.default_order=2 … … 39 39 # 40 40 # beta_h == 1.0 means that the largest gradients (on h) are allowed 41 # beta_h == 0.0 means that constant (1st order) gradients are introduced 41 # beta_h == 0.0 means that constant (1st order) gradients are introduced 42 42 # on h. This is equivalent to the constant depth used previously. 43 domain.beta_h = 0. 243 domain.beta_h = 0.9 44 44 45 45 … … 49 49 z = 0*x 50 50 for i in range(len(x)): 51 z[i] = 8*exp( -((x[i]-50)**2 + (y[i]-50)**2)/100 ) 52 return z 51 z[i] = 8*exp( -((x[i]-50)**2 + (y[i]-50)**2)/100 ) 52 return z 53 53 54 54 domain.set_quantity('friction', 0.0) 55 55 domain.set_quantity('elevation', island) 56 56 domain.set_quantity('stage', 1) 57 57 58 58 59 59 … … 69 69 #Evolution 70 70 import time 71 for t in domain.evolve(yieldstep = 1, finaltime = 20):71 for t in domain.evolve(yieldstep = 1, finaltime = 40): 72 72 domain.write_time() 73 73 74 print 'Done' 75 74 print 'Done' -
inundation/ga/storm_surge/pyvolution/netherlands.py
r1276 r1280 79 79 N = 130 #size = 33800 80 80 N = 600 #Size = 720000 81 N = 6081 N = 30 82 82 83 83 #N = 15 -
inundation/ga/storm_surge/pyvolution/realtime_visualisation_new.py
r1278 r1280 2 2 3 3 class Surface: 4 def __init__(self,domain,scale_z=1.0 ):4 def __init__(self,domain,scale_z=1.0,range_z=None): 5 5 """Create visualisation of domain 6 6 """ 7 7 8 8 self.frame = frame() 9 autoscale=0 9 10 10 self.bed_model = faces(frame=self.frame) 11 11 self.stage_model = faces(frame=self.frame) … … 14 14 15 15 self.vertices = domain.vertex_coordinates 16 self.bed = domain.quantities['elevation'].vertex_values 16 17 17 self.stage = domain.quantities['stage'].vertex_values 18 self.xmomentum = domain.quantities['xmomentum'].vertex_values 19 self.ymomentum = domain.quantities['ymomentum'].vertex_values 18 19 try: 20 self.bed = domain.quantities['elevation'].vertex_values 21 22 self.xmomentum = domain.quantities['xmomentum'].vertex_values 23 self.ymomentum = domain.quantities['ymomentum'].vertex_values 24 except: 25 self.bed = None 26 self.xmomentum = None 27 self.ymomentum = None 28 20 29 21 30 self.max_x = max(max(self.vertices[:,0],self.vertices[:,2],self.vertices[:,4])) … … 28 37 self.range_xy = max(self.range_x, self.range_y) 29 38 30 self.max_bed = max(max(self.bed)) 31 self.min_bed = min(min(self.bed)) 32 self.range_bed = max(self.max_bed - self.min_bed, 1e-10)*2.0 33 34 print 'min_bed=',self.min_bed 35 print 'max_bed=',self.max_bed 36 print 'range_bed=',self.range_bed 39 if self.bed != None and range_z == None: 40 self.max_z = max(max(self.bed)) 41 self.min_z = min(min(self.bed)) 42 self.range_z = max(self.max_z - self.min_z, 1.0e-10) 43 44 print 'min_bed=',self.min_z 45 print 'max_bed=',self.max_z 46 print 'range_z=',self.range_z 47 else: 48 self.max_z = range_z/2.0 49 self.min_z = -range_z/2.0 50 self.range_z = max(self.max_z - self.min_z, 1.0e-10) 51 37 52 38 53 #print self.max_x, self.min_x, self.max_y, self.min_y, … … 48 63 #print 'shape of stage',shape(self.stage) 49 64 50 self.border_model = curve(frame = self.frame, pos=[(0,0),(0,1),(1,1),(1,0),(0,0)]) 65 self.border_model = curve(frame = self.frame, 66 pos=[(0,0),(0,1),(1,1),(1,0),(0,0)]) 51 67 self.timer=label(pos=(0.75,0.5,0.5),text='Time=%10.5e'%self.domain.time) 52 68 69 #scene.autoscale=0 53 70 #self.update_all() 54 71 … … 67 84 c1 = 0.3 68 85 c2 = 0.3 69 self.update_arrays(self.bed, (c0,c1,c2) ) 86 try: 87 self.update_arrays(self.bed, (c0,c1,c2) ) 88 except: 89 pass 70 90 71 91 #print 'update bed image' … … 118 138 min_y = self.min_y 119 139 range_xy = self.range_xy 120 range_ bed = self.range_bed140 range_z = self.range_z 121 141 122 142 vertices = self.vertices … … 127 147 try: 128 148 update_arrays_weave(vertices,quantity,col,pos,normals,colour,N, 129 min_x,min_y,range_xy,range_ bed,scale_z)149 min_x,min_y,range_xy,range_z,scale_z) 130 150 except: 131 151 update_arrays_python(vertices,quantity,col,pos,normals,colour,N, 132 min_x,min_y,range_xy,range_ bed,scale_z)152 min_x,min_y,range_xy,range_z,scale_z) 133 153 134 154 135 155 136 156 def update_arrays_python(vertices,quantity,col,pos,normals,colour,N, 137 min_x,min_y,range_xy,range_ bed,scale_z):157 min_x,min_y,range_xy,range_z,scale_z): 138 158 139 159 from math import sqrt … … 147 167 v[j,0] = (vertices[i,2*j ]-min_x)/range_xy 148 168 v[j,1] = (vertices[i,2*j+1]-min_y)/range_xy 149 v[j,2] = quantity[i,j]/range_ bed*scale_z169 v[j,2] = quantity[i,j]/range_z*scale_z*0.5 150 170 151 171 v10 = v[1,:]-v[0,:] … … 190 210 191 211 def update_arrays_weave(vertices,quantity,col,pos,normals,colour, 192 N,min_x,min_y,range_xy,range_ bed,scale_z):212 N,min_x,min_y,range_xy,range_z,scale_z): 193 213 194 214 import weave … … 208 228 v(j,0) = (vertices(i,2*j )-min_x)/range_xy; 209 229 v(j,1) = (vertices(i,2*j+1)-min_y)/range_xy; 210 v(j,2) = quantity(i,j)/range_ bed*scale_z;230 v(j,2) = quantity(i,j)/range_z*scale_z*0.5; 211 231 } 212 232 … … 256 276 257 277 weave.inline(code1, ['vertices','quantity','col','pos','normals','colour','N', 258 'min_x','min_y','range_xy','range_ bed','scale_z','v','normal','v10','v20'],278 'min_x','min_y','range_xy','range_z','scale_z','v','normal','v10','v20'], 259 279 type_converters = converters.blitz, compiler='gcc'); 260 280 … … 286 306 287 307 288 def create_surface(domain ):289 290 surface = Surface(domain )308 def create_surface(domain,range_z=None): 309 310 surface = Surface(domain,range_z=range_z) 291 311 domain.surface = surface 292 312 293 surface.update_bed()313 #surface.update_bed() 294 314 surface.update_stage() 295 315 #surface.update_xmomentum() -
inundation/ga/storm_surge/pyvolution/util.py
r1207 r1280 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 235 235 self.filename = filename 236 237 238 236 self.quantities = quantities 237 self.domain = domain 238 self.interpolation_points = interpolation_points 239 239 240 240 if domain is not None: … … 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 257 256 """For each timestep in fid: read surface, interpolate to desired points 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 262 262 from config import time_format 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 276 275 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 313 313 314 314 if verbose: print 'Interpolate' 315 315 for i, t in enumerate(self.T): 316 316 #Interpolate quantities at this timestep 317 317 #print ' time step %d of %d' %(i, len(self.T)) 318 318 for name in self.quantities: 319 320 interpol.interpolate(fid.variables[name][i,:])319 self.values[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)) 357 354 358 355 print '------------------------------------------------' … … 367 364 def __call__(self, t, x=None, y=None, point_id = None): 368 365 """Evaluate f(t, point_id) 369 370 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 375 376 FIXME: point_id could also be a slice 377 FIXME: One could allow arbitrary x, y coordinates 378 379 Maybe not,.,.380 FIXME: What if x and y are vectors? 366 367 Inputs: 368 t: time - Model time (tau = domain.starttime-self.starttime+t) 369 must lie within existing timesteps 370 point_id: index of one of the preprocessed points. 371 If point_id is None all preprocessed points are computed 372 373 FIXME: point_id could also be a slice 374 FIXME: One could allow arbitrary x, y coordinates 375 (requires computation of a new interpolator) 376 Maybe not,.,. 377 FIXME: What if x and y are vectors? 381 378 """ 382 379 … … 391 388 392 389 #Find time tau such that 393 394 395 396 390 # 391 # domain.starttime + t == self.starttime + tau 392 393 if self.domain is not None: 397 394 tau = self.domain.starttime-self.starttime+t 398 395 else: 399 396 #print 'DOMAIN IS NONE!!!!!!!!!' 400 397 tau = t … … 403 400 #print 'S start', self.starttime 404 401 #print 't', t 405 #print 'tau', tau 406 402 #print 'tau', tau 403 407 404 msg = 'Time interval derived from file %s [%s:%s]'\ 408 405 %(self.filename, self.T[0], self.T[1]) … … 411 408 412 409 if tau < self.T[0]: raise msg 413 if tau > self.T[-1]: raise msg 410 if tau > self.T[-1]: raise msg 414 411 415 412 … … 424 421 #Protect against case where tau == T[-1] (last time) 425 422 # - also works in general when tau == T[i] 426 ratio = 0 423 ratio = 0 427 424 else: 428 #t is now between index and index+1 425 #t is now between index and index+1 429 426 ratio = (tau - self.T[self.index])/\ 430 427 (self.T[self.index+1] - self.T[self.index]) … … 432 429 433 430 434 431 435 432 #Compute interpolated values 436 433 q = zeros( len(self.quantities), Float) 437 434 438 435 for i, name in enumerate(self.quantities): 439 Q = self.values[name] 436 Q = self.values[name] 440 437 441 438 if ratio > 0: … … 450 447 #Return vector of interpolated values 451 448 return q 452 453 449 450 454 451 class File_function_ASCII: 455 452 """Read time series from file and return a callable object: 456 f(t,x,y)457 which will return interpolated values based on the input file.458 459 The file format is assumed to be either two fields separated by a comma:460 461 462 463 or four comma separated fields464 465 466 467 In either case, the callable object will return a tuple of468 interpolated values, one each value stated in the file.469 470 471 E.g472 473 31/08/04 00:00:00, 1.328223 0 0474 31/08/04 00:15:00, 1.292912 0 0475 476 will provide a time dependent function f(t,x=None,y=None),477 ignoring x and y, which returns three values per call.478 479 480 NOTE: At this stage the function is assumed to depend on481 time only, i.e no spatial dependency!!!!!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 the485 #spatio-temporal boundary condition in shallow water fully general486 487 #FIXME: Specified quantites not used here -488 #always return whatever is in the file489 """ 490 491 453 f(t,x,y) 454 which will return interpolated values based on the input file. 455 456 The file format is assumed to be either two fields separated by a comma: 457 458 time [DD/MM/YY hh:mm:ss], value0 value1 value2 ... 459 460 or four comma separated fields 461 462 time [DD/MM/YY hh:mm:ss], x, y, value0 value1 value2 ... 463 464 In either case, the callable object will return a tuple of 465 interpolated values, one each value stated in the file. 466 467 468 E.g 469 470 31/08/04 00:00:00, 1.328223 0 0 471 31/08/04 00:15:00, 1.292912 0 0 472 473 will provide a time dependent function f(t,x=None,y=None), 474 ignoring x and y, which returns three values per call. 475 476 477 NOTE: At this stage the function is assumed to depend on 478 time only, i.e no spatial dependency!!!!! 479 When that is needed we can use the least_squares interpolation. 480 481 #FIXME: This should work with netcdf (e.g. sww) and thus render the 482 #spatio-temporal boundary condition in shallow water fully general 483 484 #FIXME: Specified quantites not used here - 485 #always return whatever is in the file 486 """ 487 488 492 489 def __init__(self, filename, domain=None, quantities = None, interpolation_points=None): 493 490 """Initialise callable object from a file. … … 507 504 line = fid.readline() 508 505 fid.close() 509 506 510 507 fields = line.split(',') 511 508 msg = 'File %s must have the format date, value0 value1 value2 ...' … … 516 513 try: 517 514 starttime = calendar.timegm(time.strptime(fields[0], time_format)) 518 except ValueError: 515 except ValueError: 519 516 msg = 'First field in file %s must be' %filename 520 517 msg += ' date-time with format %s.\n' %time_format 521 msg += 'I got %s instead.' %fields[0] 518 msg += 'I got %s instead.' %fields[0] 522 519 raise msg 523 520 … … 529 526 530 527 q = ensure_numeric(values) 531 528 532 529 msg = 'ERROR: File must contain at least one independent value' 533 530 assert len(q.shape) == 1, msg 534 531 535 532 self.number_of_values = len(q) 536 533 537 534 self.filename = filename 538 535 self.starttime = starttime 539 536 self.domain = domain 540 537 541 538 if domain is not None: … … 549 546 ##if verbose: print msg 550 547 domain.starttime = self.starttime #Modifying model time 551 548 552 549 #if domain.starttime is None: 553 550 # domain.starttime = self.starttime … … 563 560 # domain.starttime = self.starttime #Modifying model time 564 561 565 if mode == 2: 562 if mode == 2: 566 563 self.read_times() #Now read all times in. 567 564 else: 568 565 raise 'x,y dependency not yet implemented' 569 566 570 567 571 568 def read_times(self): 572 """Read time and values 569 """Read time and values 573 570 """ 574 571 from Numeric import zeros, Float, alltrue 575 572 from config import time_format 576 573 import time, calendar 577 578 fid = open(self.filename) 574 575 fid = open(self.filename) 579 576 lines = fid.readlines() 580 577 fid.close() 581 578 582 579 N = len(lines) 583 580 d = self.number_of_values … … 585 582 T = zeros(N, Float) #Time 586 583 Q = zeros((N, d), Float) #Values 587 584 588 585 for i, line in enumerate(lines): 589 586 fields = line.split(',') … … 603 600 self.index = 0 #Initial index 604 601 605 602 606 603 def __repr__(self): 607 604 return 'File function' … … 613 610 result is a vector of same length as x and y 614 611 FIXME: Naaaa 615 616 612 613 FIXME: Rethink semantics when x,y are vectors. 617 614 """ 618 615 619 616 from math import pi, cos, sin, sqrt 620 617 621 618 622 619 #Find time tau such that 623 624 625 626 620 # 621 # domain.starttime + t == self.starttime + tau 622 623 if self.domain is not None: 627 624 tau = self.domain.starttime-self.starttime+t 628 625 else: 629 626 tau = t 630 631 627 628 632 629 msg = 'Time interval derived from file %s (%s:%s) does not match model time: %s'\ 633 630 %(self.filename, self.T[0], self.T[1], tau) 634 631 if tau < self.T[0]: raise msg 635 if tau > self.T[-1]: raise msg 632 if tau > self.T[-1]: raise msg 636 633 637 634 oldindex = self.index … … 647 644 #Compute interpolated values 648 645 q = self.Q[self.index,:] +\ 649 ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 646 ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 650 647 651 648 #Return vector of interpolated values … … 662 659 N = len(x) 663 660 assert len(y) == N, 'x and y must have same length' 664 661 665 662 res = [] 666 663 for col in q: 667 664 res.append(col*ones(N, Float)) 668 665 669 666 return res 670 671 672 #FIXME: TEMP 667 668 669 #FIXME: TEMP 673 670 class File_function_copy: 674 671 """Read time series from file and return a callable object: 675 f(t,x,y)676 which will return interpolated values based on the input file.677 678 The file format is assumed to be either two fields separated by a comma:679 680 time [DD/MM/YY hh:mm:ss], value0 value1 value2 ...681 682 or four comma separated fields683 684 time [DD/MM/YY hh:mm:ss], x, y, value0 value1 value2 ...685 686 In either case, the callable object will return a tuple of687 interpolated values, one each value stated in the file.688 689 690 E.g691 692 31/08/04 00:00:00, 1.328223 0 0693 31/08/04 00:15:00, 1.292912 0 0694 695 will provide a time dependent function f(t,x=None,y=None),696 ignoring x and y, which returns three values per call.697 698 699 NOTE: At this stage the function is assumed to depend on700 time only, i.e no spatial dependency!!!!!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 the704 #spatio-temporal boundary condition in shallow water fully general705 """ 706 707 672 f(t,x,y) 673 which will return interpolated values based on the input file. 674 675 The file format is assumed to be either two fields separated by a comma: 676 677 time [DD/MM/YY hh:mm:ss], value0 value1 value2 ... 678 679 or four comma separated fields 680 681 time [DD/MM/YY hh:mm:ss], x, y, value0 value1 value2 ... 682 683 In either case, the callable object will return a tuple of 684 interpolated values, one each value stated in the file. 685 686 687 E.g 688 689 31/08/04 00:00:00, 1.328223 0 0 690 31/08/04 00:15:00, 1.292912 0 0 691 692 will provide a time dependent function f(t,x=None,y=None), 693 ignoring x and y, which returns three values per call. 694 695 696 NOTE: At this stage the function is assumed to depend on 697 time only, i.e no spatial dependency!!!!! 698 When that is needed we can use the least_squares interpolation. 699 700 #FIXME: This should work with netcdf (e.g. sww) and thus render the 701 #spatio-temporal boundary condition in shallow water fully general 702 """ 703 704 708 705 def __init__(self, filename, domain=None): 709 706 """Initialise callable object from a file. … … 742 739 try: 743 740 starttime = calendar.timegm(time.strptime(fields[0], time_format)) 744 except ValueError: 741 except ValueError: 745 742 msg = 'First field in file %s must be' %filename 746 743 msg += ' date-time with format %s.\n' %time_format 747 msg += 'I got %s instead.' %fields[0] 744 msg += 'I got %s instead.' %fields[0] 748 745 raise msg 749 746 … … 755 752 756 753 q = ensure_numeric(values) 757 754 758 755 msg = 'ERROR: File must contain at least one independent value' 759 756 assert len(q.shape) == 1, msg 760 757 761 758 self.number_of_values = len(q) 762 759 763 760 self.filename = filename 764 761 self.starttime = starttime 765 762 self.domain = domain 766 763 767 764 if domain is not None: … … 779 776 domain.starttime = self.starttime #Modifying model time 780 777 781 if mode == 2: 778 if mode == 2: 782 779 self.read_times() #Now read all times in. 783 780 else: 784 781 raise 'x,y dependency not yet implemented' 785 782 786 783 787 784 def read_times(self): 788 """Read time and values 785 """Read time and values 789 786 """ 790 787 from Numeric import zeros, Float, alltrue 791 788 from config import time_format 792 789 import time, calendar 793 794 fid = open(self.filename) 790 791 fid = open(self.filename) 795 792 lines = fid.readlines() 796 793 fid.close() 797 794 798 795 N = len(lines) 799 796 d = self.number_of_values … … 801 798 T = zeros(N, Float) #Time 802 799 Q = zeros((N, d), Float) #Values 803 800 804 801 for i, line in enumerate(lines): 805 802 fields = line.split(',') … … 819 816 self.index = 0 #Initial index 820 817 821 818 822 819 def __repr__(self): 823 820 return 'File function' 824 821 825 822 826 823 827 824 def __call__(self, t, x=None, y=None): … … 834 831 835 832 from math import pi, cos, sin, sqrt 836 833 837 834 838 835 #Find time tau such that 839 840 841 842 836 # 837 # domain.starttime + t == self.starttime + tau 838 839 if self.domain is not None: 843 840 tau = self.domain.starttime-self.starttime+t 844 841 else: 845 842 tau = t 846 847 843 844 848 845 msg = 'Time interval derived from file %s (%s:%s) does not match model time: %s'\ 849 846 %(self.filename, self.T[0], self.T[1], tau) 850 847 if tau < self.T[0]: raise msg 851 if tau > self.T[-1]: raise msg 848 if tau > self.T[-1]: raise msg 852 849 853 850 oldindex = self.index … … 863 860 #Compute interpolated values 864 861 q = self.Q[self.index,:] +\ 865 ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 862 ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 866 863 867 864 #Return vector of interpolated values … … 878 875 N = len(x) 879 876 assert len(y) == N, 'x and y must have same length' 880 877 881 878 res = [] 882 879 for col in q: 883 880 res.append(col*ones(N, Float)) 884 881 885 882 return res 886 883 887 884 888 885 def read_xya(filename, format = 'netcdf'): … … 892 889 893 890 Format can be either ASCII or NetCDF 894 891 895 892 Return list of points, list of attributes and 896 893 attribute names if present otherwise None 897 894 """ 898 895 #FIXME: Probably obsoleted by similar function in load_ASCII 899 896 900 897 from Scientific.IO.NetCDF import NetCDFFile 901 898 902 if format.lower() == 'netcdf': 899 if format.lower() == 'netcdf': 903 900 #Get NetCDF 904 905 fid = NetCDFFile(filename, 'r') 906 901 902 fid = NetCDFFile(filename, 'r') 903 907 904 # Get the variables 908 905 points = fid.variables['points'] … … 913 910 #Don't close - arrays are needed outside this function, 914 911 #alternatively take a copy here 915 else: 912 else: 916 913 #Read as ASCII file assuming that it is separated by whitespace 917 914 fid = open(filename) … … 930 927 attribute_names = ['elevation'] #HACK 931 928 932 attributes = {} 929 attributes = {} 933 930 for key in attribute_names: 934 931 attributes[key] = [] … … 940 937 for i, key in enumerate(attribute_names): 941 938 attributes[key].append( float(fields[2+i]) ) 942 939 943 940 return points, attributes 944 941 945 942 946 943 ##################################### … … 950 947 951 948 952 953 #Redefine these to use separate_by_polygon which will put all inside indices 949 950 #Redefine these to use separate_by_polygon which will put all inside indices 954 951 #in the first part of the indices array and outside indices in the last 955 952 … … 957 954 """See separate_points_by_polygon for documentation 958 955 """ 959 960 from Numeric import array, Float, reshape 961 962 if verbose: print 'Checking input to inside_polygon' 956 957 from Numeric import array, Float, reshape 958 959 if verbose: print 'Checking input to inside_polygon' 963 960 try: 964 points = ensure_numeric(points, Float) 961 points = ensure_numeric(points, Float) 965 962 except: 966 963 msg = 'Points could not be converted to Numeric array' 967 raise msg 968 964 raise msg 965 969 966 try: 970 polygon = ensure_numeric(polygon, Float) 967 polygon = ensure_numeric(polygon, Float) 971 968 except: 972 969 msg = 'Polygon could not be converted to Numeric array' 973 raise msg 974 975 976 970 raise msg 971 972 973 977 974 if len(points.shape) == 1: 978 975 one_point = True 979 976 points = reshape(points, (1,2)) 980 else: 977 else: 981 978 one_point = False 982 979 983 indices, count = separate_points_by_polygon(points, polygon, 984 closed, verbose) 985 980 indices, count = separate_points_by_polygon(points, polygon, 981 closed, verbose) 982 986 983 if one_point: 987 984 return count == 1 988 985 else: 989 return indices[:count] 990 986 return indices[:count] 987 991 988 def outside_polygon(points, polygon, closed = True, verbose = False): 992 989 """See separate_points_by_polygon for documentation 993 990 """ 994 995 from Numeric import array, Float, reshape 996 997 if verbose: print 'Checking input to outside_polygon' 991 992 from Numeric import array, Float, reshape 993 994 if verbose: print 'Checking input to outside_polygon' 998 995 try: 999 points = ensure_numeric(points, Float) 996 points = ensure_numeric(points, Float) 1000 997 except: 1001 998 msg = 'Points could not be converted to Numeric array' 1002 raise msg 1003 999 raise msg 1000 1004 1001 try: 1005 polygon = ensure_numeric(polygon, Float) 1002 polygon = ensure_numeric(polygon, Float) 1006 1003 except: 1007 1004 msg = 'Polygon could not be converted to Numeric array' 1008 raise msg 1009 1010 1011 1005 raise msg 1006 1007 1008 1012 1009 if len(points.shape) == 1: 1013 1010 one_point = True 1014 1011 points = reshape(points, (1,2)) 1015 else: 1012 else: 1016 1013 one_point = False 1017 1014 1018 indices, count = separate_points_by_polygon(points, polygon, 1019 closed, verbose) 1020 1015 indices, count = separate_points_by_polygon(points, polygon, 1016 closed, verbose) 1017 1021 1018 if one_point: 1022 1019 return count != 1 1023 1020 else: 1024 return indices[count:][::-1] #return reversed 1025 1026 1027 def separate_points_by_polygon(points, polygon, 1021 return indices[count:][::-1] #return reversed 1022 1023 1024 def separate_points_by_polygon(points, polygon, 1028 1025 closed = True, verbose = False): 1029 1026 """Determine whether points are inside or outside a polygon 1030 1027 1031 1028 Input: 1032 1029 points - Tuple of (x, y) coordinates, or list of tuples 1033 1030 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 1031 closed - (optional) determine whether points on boundary should be 1032 regarded as belonging to the polygon (closed = True) 1033 or not (closed = False) 1034 1038 1035 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 1036 indices: array of same length as points with indices of points falling 1037 inside the polygon listed from the beginning and indices of points 1041 1038 falling outside listed from the end. 1042 1039 1043 1040 count: count of points falling inside the polygon 1044 1041 1045 1042 The indices of points inside are obtained as indices[:count] 1046 The indices of points outside are obtained as indices[count:] 1047 1048 1043 The indices of points outside are obtained as indices[count:] 1044 1045 1049 1046 Examples: 1050 1047 U = [[0,0], [1,0], [1,1], [0,1]] #Unit square 1051 1048 1052 1049 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 1050 will return the indices [0, 2, 1] and count == 2 as only the first 1054 1051 and the last point are inside the unit square 1055 1052 1056 1053 Remarks: 1057 1054 The vertices may be listed clockwise or counterclockwise and 1058 the first point may optionally be repeated. 1055 the first point may optionally be repeated. 1059 1056 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 """ 1057 Polygons can have holes in them and points inside a hole is 1058 regarded as being outside the polygon. 1059 1060 Algorithm is based on work by Darel Finley, 1061 http://www.alienryderflex.com/polygon/ 1062 1063 """ 1067 1064 1068 1065 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' 1066 1067 1164 1068 #Input checks 1165 1069 try: … … 1169 1073 raise msg 1170 1074 1171 #if verbose: print 'Checking input to separate_points_by_polygon 2'1172 1075 try: 1173 1076 polygon = ensure_numeric(polygon, Float) 1174 1077 except: 1175 1078 msg = 'Polygon could not be converted to Numeric array' 1176 raise msg 1177 1178 if verbose: print 'check' 1179 1079 raise msg 1080 1180 1081 assert len(polygon.shape) == 2,\ 1181 1082 'Polygon array must be a 2d array of vertices' … … 1186 1087 assert len(points.shape) == 2,\ 1187 1088 'Points array must be a 2d array' 1188 1089 1189 1090 assert points.shape[1] == 2,\ 1190 1091 'Points array must have two columns' 1191 1192 N = polygon.shape[0] #Number of vertices in polygon 1092 1093 N = polygon.shape[0] #Number of vertices in polygon 1193 1094 M = points.shape[0] #Number of points 1194 1095 1096 px = polygon[:,0] 1097 py = polygon[:,1] 1098 1099 #Used for an optimisation when points are far away from polygon 1100 minpx = min(px); maxpx = max(px) 1101 minpy = min(py); maxpy = max(py) 1102 1103 1104 #Begin main loop 1105 indices = zeros(M, Int) 1106 1107 inside_index = 0 #Keep track of points inside 1108 outside_index = M-1 #Keep track of points outside (starting from end) 1109 1110 for k in range(M): 1111 1112 if verbose: 1113 if k %((M+10)/10)==0: print 'Doing %d of %d' %(k, M) 1114 1115 #for each point 1116 x = points[k, 0] 1117 y = points[k, 1] 1118 1119 inside = False 1120 1121 if not x > maxpx or x < minpx or y > maxpy or y < minpy: 1122 #Check polygon 1123 for i in range(N): 1124 j = (i+1)%N 1125 1126 #Check for case where point is contained in line segment 1127 if point_on_line(x, y, px[i], py[i], px[j], py[j]): 1128 if closed: 1129 inside = True 1130 else: 1131 inside = False 1132 break 1133 else: 1134 #Check if truly inside polygon 1135 if py[i] < y and py[j] >= y or\ 1136 py[j] < y and py[i] >= y: 1137 if px[i] + (y-py[i])/(py[j]-py[i])*(px[j]-px[i]) < x: 1138 inside = not inside 1139 1140 if inside: 1141 indices[inside_index] = k 1142 inside_index += 1 1143 else: 1144 indices[outside_index] = k 1145 outside_index -= 1 1146 1147 return indices, inside_index 1148 1149 1150 def separate_points_by_polygon_c(points, polygon, 1151 closed = True, verbose = False): 1152 """Determine whether points are inside or outside a polygon 1153 1154 C-wrapper 1155 """ 1156 1157 from Numeric import array, Float, reshape, zeros, Int 1158 1159 1160 if verbose: print 'Checking input to separate_points_by_polygon' 1161 #Input checks 1162 try: 1163 points = ensure_numeric(points, Float) 1164 except: 1165 msg = 'Points could not be converted to Numeric array' 1166 raise msg 1167 1168 #if verbose: print 'Checking input to separate_points_by_polygon 2' 1169 try: 1170 polygon = ensure_numeric(polygon, Float) 1171 except: 1172 msg = 'Polygon could not be converted to Numeric array' 1173 raise msg 1174 1175 if verbose: print 'check' 1176 1177 assert len(polygon.shape) == 2,\ 1178 'Polygon array must be a 2d array of vertices' 1179 1180 assert polygon.shape[1] == 2,\ 1181 'Polygon array must have two columns' 1182 1183 assert len(points.shape) == 2,\ 1184 'Points array must be a 2d array' 1185 1186 assert points.shape[1] == 2,\ 1187 'Points array must have two columns' 1188 1189 N = polygon.shape[0] #Number of vertices in polygon 1190 M = points.shape[0] #Number of points 1191 1195 1192 from util_ext import separate_points_by_polygon 1196 1193 … … 1199 1196 indices = zeros( M, Int ) 1200 1197 1201 if verbose: print 'Calling C-version of inside poly' 1198 if verbose: print 'Calling C-version of inside poly' 1202 1199 count = separate_points_by_polygon(points, polygon, indices, 1203 1200 int(closed), int(verbose)) 1204 1201 1205 return indices, count 1202 return indices, count 1206 1203 1207 1204 1208 1205 1209 1206 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 1207 """Create callable object f: x,y -> z, where a,y,z are vectors and 1208 where f will return different values depending on whether x,y belongs 1212 1209 to specified polygons. 1213 1210 1214 1211 To instantiate: 1215 1212 1216 1213 Polygon_function(polygons) 1217 1214 1218 1215 where polygons is a list of tuples of the form 1219 1216 1220 1217 [ (P0, v0), (P1, v1), ...] 1221 1222 with Pi being lists of vertices defining polygons and vi either 1218 1219 with Pi being lists of vertices defining polygons and vi either 1223 1220 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 1221 1222 The function takes an optional argument, default which is the value 1226 1223 (or function) to used for points not belonging to any polygon. 1227 1224 For example: 1228 1229 Polygon_function(polygons, default = 0.03) 1230 1231 If omitted the default value will be 0.0 1232 1225 1226 Polygon_function(polygons, default = 0.03) 1227 1228 If omitted the default value will be 0.0 1229 1233 1230 Note: If two polygons overlap, the one last in the list takes precedence 1234 1231 1235 1232 """ 1236 1233 1237 1234 def __init__(self, regions, default = 0.0): 1238 1235 1239 1236 try: 1240 1237 len(regions) 1241 1238 except: 1242 msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons 1239 msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons 1243 1240 raise msg 1244 1241 1245 1242 1246 T = regions[0] 1243 T = regions[0] 1247 1244 try: 1248 1245 a = len(T) 1249 except: 1250 msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons 1251 raise msg 1252 1253 assert a == 2, 'Must have two component each: %s' %T 1254 1255 self.regions = regions 1246 except: 1247 msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons 1248 raise msg 1249 1250 assert a == 2, 'Must have two component each: %s' %T 1251 1252 self.regions = regions 1256 1253 self.default = default 1257 1258 1254 1255 1259 1256 def __call__(self, x, y): 1260 1257 from util import inside_polygon 1261 1258 from Numeric import ones, Float, concatenate, array, reshape, choose 1262 1259 1263 1260 x = array(x).astype(Float) 1264 y = array(y).astype(Float) 1265 1261 y = array(y).astype(Float) 1262 1266 1263 N = len(x) 1267 1264 assert len(y) == N 1268 1269 points = concatenate( (reshape(x, (N, 1)), 1265 1266 points = concatenate( (reshape(x, (N, 1)), 1270 1267 reshape(y, (N, 1))), axis=1 ) 1271 1268 1272 1269 if callable(self.default): 1273 1270 z = self.default(x,y) 1274 else: 1271 else: 1275 1272 z = ones(N, Float) * self.default 1276 1273 1277 1274 for polygon, value in self.regions: 1278 1275 indices = inside_polygon(points, polygon) 1279 1280 #FIXME: This needs to be vectorised 1276 1277 #FIXME: This needs to be vectorised 1281 1278 if callable(value): 1282 1279 for i in indices: … … 1284 1281 yy = array([y[i]]) 1285 1282 z[i] = value(xx, yy)[0] 1286 else: 1283 else: 1287 1284 for i in indices: 1288 z[i] = value 1289 1290 return z 1285 z[i] = value 1286 1287 return z 1291 1288 1292 1289 def read_polygon(filename): 1293 1290 """Read points assumed to form a polygon 1294 1291 There must be exactly two numbers in each line 1295 """ 1296 1292 """ 1293 1297 1294 #Get polygon 1298 1295 fid = open(filename) … … 1304 1301 polygon.append( [float(fields[0]), float(fields[1])] ) 1305 1302 1306 return polygon 1307 1303 return polygon 1304 1308 1305 def populate_polygon(polygon, number_of_points, seed = None): 1309 1306 """Populate given polygon with uniformly distributed points. … … 1311 1308 Input: 1312 1309 polygon - list of vertices of polygon 1313 number_of_points - (optional) number of points 1310 number_of_points - (optional) number of points 1314 1311 seed - seed for random number generator (default=None) 1315 1312 1316 1313 Output: 1317 1314 points - list of points inside polygon 1318 1315 1319 1316 Examples: 1320 1317 populate_polygon( [[0,0], [1,0], [1,1], [0,1]], 5 ) 1321 will return five randomly selected points inside the unit square 1318 will return five randomly selected points inside the unit square 1322 1319 """ 1323 1320 … … 1332 1329 max_y = min_y = polygon[0][1] 1333 1330 for point in polygon[1:]: 1334 x = point[0] 1331 x = point[0] 1335 1332 if x > max_x: max_x = x 1336 if x < min_x: min_x = x 1337 y = point[1] 1333 if x < min_x: min_x = x 1334 y = point[1] 1338 1335 if y > max_y: max_y = y 1339 if y < min_y: min_y = y 1340 1341 1342 while len(points) < number_of_points: 1336 if y < min_y: min_y = y 1337 1338 1339 while len(points) < number_of_points: 1343 1340 x = uniform(min_x, max_x) 1344 y = uniform(min_y, max_y) 1341 y = uniform(min_y, max_y) 1345 1342 1346 1343 if inside_polygon( [x,y], polygon ): … … 1351 1348 def tsh2sww(filename, verbose=True): 1352 1349 """ 1353 to check if a tsh/msh file 'looks' good. 1350 to check if a tsh/msh file 'looks' good. 1354 1351 """ 1355 1352 from shallow_water import Domain 1356 1353 from pmesh2domain import pmesh_to_domain_instance 1357 import time, os 1358 from data_manager import get_dataobject 1359 from os import sep, path 1354 import time, os 1355 from data_manager import get_dataobject 1356 from os import sep, path 1360 1357 #from util import mean 1361 1358 1362 1359 if verbose == True:print 'Creating domain from', filename 1363 1360 domain = pmesh_to_domain_instance(filename, Domain) … … 1376 1373 if verbose == True: 1377 1374 print "Output written to " + domain.get_datadir() + sep + \ 1378 domain.filename + "." + domain.format 1375 domain.filename + "." + domain.format 1379 1376 sww = get_dataobject(domain) 1380 1377 sww.store_connectivity() … … 1388 1385 """ 1389 1386 """ 1390 1391 det = (y2-y0)*(x1-x0) - (y1-y0)*(x2-x0) 1387 1388 det = (y2-y0)*(x1-x0) - (y1-y0)*(x2-x0) 1392 1389 a = (y2-y0)*(q1-q0) - (y1-y0)*(q2-q0) 1393 1390 a /= det 1394 1391 1395 1392 b = (x1-x0)*(q2-q0) - (x2-x0)*(q1-q0) 1396 b /= det 1393 b /= det 1397 1394 1398 1395 return a, b … … 1414 1411 pass 1415 1412 1416 1417 1418 1419 1420 1421 #OBSOLETED STUFF 1413 1414 1415 1416 1417 1418 #OBSOLETED STUFF 1422 1419 def inside_polygon_old(point, polygon, closed = True, verbose = False): 1423 1420 #FIXME Obsoleted 1424 1421 """Determine whether points are inside or outside a polygon 1425 1422 1426 1423 Input: 1427 1424 point - Tuple of (x, y) coordinates, or list of tuples 1428 1425 polygon - list of vertices of polygon 1429 closed - (optional) determine whether points on boundary should be 1430 regarded as belonging to the polygon (closed = True) 1431 or not (closed = False) 1432 1426 closed - (optional) determine whether points on boundary should be 1427 regarded as belonging to the polygon (closed = True) 1428 or not (closed = False) 1429 1433 1430 Output: 1434 1431 If one point is considered, True or False is returned. 1435 If multiple points are passed in, the function returns indices 1436 of those points that fall inside the polygon 1437 1432 If multiple points are passed in, the function returns indices 1433 of those points that fall inside the polygon 1434 1438 1435 Examples: 1439 1436 U = [[0,0], [1,0], [1,1], [0,1]] #Unit square 1440 1437 inside_polygon( [0.5, 0.5], U) 1441 will evaluate to True as the point 0.5, 0.5 is inside the unit square 1442 1438 will evaluate to True as the point 0.5, 0.5 is inside the unit square 1439 1443 1440 inside_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U) 1444 will return the indices [0, 2] as only the first and the last point 1441 will return the indices [0, 2] as only the first and the last point 1445 1442 is inside the unit square 1446 1443 1447 1444 Remarks: 1448 1445 The vertices may be listed clockwise or counterclockwise and 1449 the first point may optionally be repeated. 1446 the first point may optionally be repeated. 1450 1447 Polygons do not need to be convex. 1451 Polygons can have holes in them and points inside a hole is 1452 regarded as being outside the polygon. 1453 1454 1455 Algorithm is based on work by Darel Finley, 1456 http://www.alienryderflex.com/polygon/ 1457 1458 """ 1448 Polygons can have holes in them and points inside a hole is 1449 regarded as being outside the polygon. 1450 1451 1452 Algorithm is based on work by Darel Finley, 1453 http://www.alienryderflex.com/polygon/ 1454 1455 """ 1459 1456 1460 1457 from Numeric import array, Float, reshape 1461 1462 1458 1459 1463 1460 #Input checks 1464 1461 try: 1465 point = array(point).astype(Float) 1462 point = array(point).astype(Float) 1466 1463 except: 1467 1464 msg = 'Point %s could not be converted to Numeric array' %point 1468 raise msg 1469 1465 raise msg 1466 1470 1467 try: 1471 polygon = array(polygon).astype(Float) 1468 polygon = array(polygon).astype(Float) 1472 1469 except: 1473 1470 msg = 'Polygon %s could not be converted to Numeric array' %polygon 1474 raise msg 1475 1471 raise msg 1472 1476 1473 assert len(polygon.shape) == 2,\ 1477 1474 'Polygon array must be a 2d array of vertices: %s' %polygon 1478 1475 1479 1476 1480 1477 assert polygon.shape[1] == 2,\ 1481 'Polygon array must have two columns: %s' %polygon 1478 'Polygon array must have two columns: %s' %polygon 1482 1479 1483 1480 … … 1485 1482 one_point = True 1486 1483 points = reshape(point, (1,2)) 1487 else: 1484 else: 1488 1485 one_point = False 1489 1486 points = point 1490 1487 1491 N = polygon.shape[0] #Number of vertices in polygon 1488 N = polygon.shape[0] #Number of vertices in polygon 1492 1489 M = points.shape[0] #Number of points 1493 1490 1494 1491 px = polygon[:,0] 1495 py = polygon[:,1] 1492 py = polygon[:,1] 1496 1493 1497 1494 #Used for an optimisation when points are far away from polygon 1498 1495 minpx = min(px); maxpx = max(px) 1499 minpy = min(py); maxpy = max(py) 1496 minpy = min(py); maxpy = max(py) 1500 1497 1501 1498 … … 1506 1503 if verbose: 1507 1504 if k %((M+10)/10)==0: print 'Doing %d of %d' %(k, M) 1508 1509 #for each point 1505 1506 #for each point 1510 1507 x = points[k, 0] 1511 y = points[k, 1] 1508 y = points[k, 1] 1512 1509 1513 1510 inside = False … … 1515 1512 #Optimisation 1516 1513 if x > maxpx or x < minpx: continue 1517 if y > maxpy or y < minpy: continue 1518 1519 #Check polygon 1514 if y > maxpy or y < minpy: continue 1515 1516 #Check polygon 1520 1517 for i in range(N): 1521 1518 j = (i+1)%N 1522 1523 #Check for case where point is contained in line segment 1519 1520 #Check for case where point is contained in line segment 1524 1521 if point_on_line(x, y, px[i], py[i], px[j], py[j]): 1525 1522 if closed: 1526 1523 inside = True 1527 else: 1524 else: 1528 1525 inside = False 1529 1526 break 1530 else: 1531 #Check if truly inside polygon 1527 else: 1528 #Check if truly inside polygon 1532 1529 if py[i] < y and py[j] >= y or\ 1533 1530 py[j] < y and py[i] >= y: 1534 1531 if px[i] + (y-py[i])/(py[j]-py[i])*(px[j]-px[i]) < x: 1535 1532 inside = not inside 1536 1533 1537 1534 if inside: indices.append(k) 1538 1535 1539 if one_point: 1536 if one_point: 1540 1537 return inside 1541 1538 else: 1542 1539 return indices 1543 1540 1544 1541 1545 1542 #def remove_from(A, B): … … 1550 1547 # ind = search_sorted(A, B) 1551 1548 1552 1549 1553 1550 1554 1551 def outside_polygon_old(point, polygon, closed = True, verbose = False): 1555 1552 #OBSOLETED 1556 1553 """Determine whether points are outside a polygon 1557 1554 1558 1555 Input: 1559 1556 point - Tuple of (x, y) coordinates, or list of tuples 1560 1557 polygon - list of vertices of polygon 1561 closed - (optional) determine whether points on boundary should be 1562 regarded as belonging to the polygon (closed = True) 1563 or not (closed = False) 1564 1558 closed - (optional) determine whether points on boundary should be 1559 regarded as belonging to the polygon (closed = True) 1560 or not (closed = False) 1561 1565 1562 Output: 1566 1563 If one point is considered, True or False is returned. 1567 If multiple points are passed in, the function returns indices 1568 of those points that fall outside the polygon 1569 1564 If multiple points are passed in, the function returns indices 1565 of those points that fall outside the polygon 1566 1570 1567 Examples: 1571 U = [[0,0], [1,0], [1,1], [0,1]] #Unit square 1568 U = [[0,0], [1,0], [1,1], [0,1]] #Unit square 1572 1569 outside_polygon( [0.5, 0.5], U ) 1573 1570 will evaluate to False as the point 0.5, 0.5 is inside the unit square … … 1575 1572 ouside_polygon( [1.5, 0.5], U ) 1576 1573 will evaluate to True as the point 1.5, 0.5 is outside the unit square 1577 1574 1578 1575 outside_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U ) 1579 will return the indices [1] as only the first and the last point 1576 will return the indices [1] as only the first and the last point 1580 1577 is inside the unit square 1581 1578 """ 1582 1579 1583 1580 #FIXME: This is too slow 1584 1581 1585 1582 res = inside_polygon(point, polygon, closed, verbose) 1586 1583 … … 1600 1597 1601 1598 C-wrapper 1602 """ 1599 """ 1603 1600 1604 1601 from Numeric import array, Float, reshape, zeros, Int 1605 1606 1607 if verbose: print 'Checking input to inside_polygon' 1602 1603 1604 if verbose: print 'Checking input to inside_polygon' 1608 1605 #Input checks 1609 1606 try: 1610 point = array(point).astype(Float) 1607 point = array(point).astype(Float) 1611 1608 except: 1612 1609 msg = 'Point %s could not be converted to Numeric array' %point 1613 raise msg 1614 1610 raise msg 1611 1615 1612 try: 1616 polygon = array(polygon).astype(Float) 1613 polygon = array(polygon).astype(Float) 1617 1614 except: 1618 1615 msg = 'Polygon %s could not be converted to Numeric array' %polygon 1619 raise msg 1620 1616 raise msg 1617 1621 1618 assert len(polygon.shape) == 2,\ 1622 1619 'Polygon array must be a 2d array of vertices: %s' %polygon 1623 1620 1624 1621 1625 1622 assert polygon.shape[1] == 2,\ 1626 'Polygon array must have two columns: %s' %polygon 1623 'Polygon array must have two columns: %s' %polygon 1627 1624 1628 1625 … … 1630 1627 one_point = True 1631 1628 points = reshape(point, (1,2)) 1632 else: 1629 else: 1633 1630 one_point = False 1634 1631 points = point … … 1640 1637 indices = zeros( points.shape[0], Int ) 1641 1638 1642 if verbose: print 'Calling C-version of inside poly' 1639 if verbose: print 'Calling C-version of inside poly' 1643 1640 count = inside_polygon(points, polygon, indices, 1644 1641 int(closed), int(verbose)) … … 1648 1645 else: 1649 1646 if verbose: print 'Got %d points' %count 1650 1647 1651 1648 return indices[:count] #Return those indices that were inside 1652 -
inundation/ga/storm_surge/zeus/anuga-workspace.zwi
r1271 r1280 2 2 <workspace name="anuga-workspace"> 3 3 <mode>Debug</mode> 4 <active>steve</active> 4 <active>parallel</active> 5 <project name="parallel">parallel.zpi</project> 5 6 <project name="pyvolution">pyvolution.zpi</project> 6 7 <project name="steve">steve.zpi</project> 7 <project name="pyvolution-parallel">pyvolution-parallel.zpi</project>8 8 </workspace>
Note: See TracChangeset
for help on using the changeset viewer.