Changeset 820 for inundation/ga
- Timestamp:
- Feb 1, 2005, 5:06:54 AM (20 years ago)
- Location:
- inundation/ga/storm_surge/pyvolution
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
inundation/ga/storm_surge/pyvolution/least_squares.py
r797 r820 143 143 return vertex_attributes 144 144 145 146 147 def xya2rectangular(xya_name, M, N, alpha = DEFAULT_ALPHA): 148 """Fits attributes from xya file to MxN rectangular mesh 149 150 Read xya file and create rectangular mesh of resolution MxN such that 151 it covers all points specified in xya file. 152 153 FIXME: This may be a temporary function until we decide on 154 netcdf formats etc 155 """ 156 157 import util, mesh_factory 158 159 points, attributes = util.read_xya(xya_name) 160 161 #Find extent 162 max_x = min_x = points[0][0] 163 max_y = min_y = points[0][1] 164 for point in points[1:]: 165 x = point[0] 166 if x > max_x: max_x = x 167 if x < min_x: min_x = x 168 y = point[1] 169 if y > max_y: max_y = y 170 if y < min_y: min_y = y 171 172 #Create appropriate mesh 173 vertex_coordinates, triangles, boundary =\ 174 mesh_factory.rectangular(M, N, max_x-min_x, max_y-min_y, 175 (min_x, min_y)) 176 177 #Fit attributes to mesh 178 vertex_attributes = fit_to_mesh(vertex_coordinates, 179 triangles, 180 points, 181 attributes, alpha=alpha) 182 183 184 185 return vertex_coordinates, triangles, boundary, vertex_attributes 186 187 145 188 146 189 class Interpolation: … … 548 591 if n<m and self.alpha == 0.0: 549 592 msg = 'ERROR (least_squares): Too few data points\n' 550 msg += 'There only %d data points. Need at least %d\n' %(n,m) 551 msg += 'Alternatively, increase smoothing parameter alpha' 593 msg += 'There are only %d data points and alpha == 0. ' %n 594 msg += 'Need at least %d\n' %m 595 msg += 'Alternatively, set smoothing parameter alpha to a small ' 596 msg += 'positive value,\ne.g. 1.0e-3.' 552 597 raise msg 553 598 -
inundation/ga/storm_surge/pyvolution/mesh_factory.py
r543 r820 131 131 return points, elements, boundary 132 132 133 #OLD FORMULA FOR SETTING BOUNDARY TAGS - OBSOLETE NOW134 # for id, face in M.boundary:135 136 # e = element_class.instances[id]137 # x0, y0, x1, y1, x2, y2 = e.get_instance_vertex_coordinates()138 139 # if face==2:140 # #Left or right#141 # if abs(x0-origin[0]) < epsilon:142 # M.boundary[(id,face)] = 'left'143 # elif abs(origin[0]+lenx-x0) < epsilon:144 # M.boundary[(id,face)] = 'right'145 # else:146 # print face, id, id%m, m, n147 # raise 'Left or Right Unknown boundary'148 # elif face==1:149 # #Top or bottom150 # if x0 > 0.25*lenx and abs(y0-a1-a2*x0-origin[1]) < epsilon or\151 # x0 <= 0.25*lenx and abs(y0-origin[1]) < epsilon:152 # M.boundary[(id,face)] = 'bottom'153 # elif abs(origin[1]+leny-y0) < epsilon:154 # M.boundary[(id,face)] = 'top'155 # else:156 # print face, id, id%m, m, n157 # raise 'Top or Bottom Unknown boundary'158 # else:159 # print face, id, id%m, m, n160 # raise 'Unknown boundary'161 #162 # return M163 164 165 166 133 167 134 def circular(m, n, radius=1.0, center = (0.0, 0.0)): … … 394 361 return points, elements 395 362 396 397 398 # def contracting_channel_mesh(m, n, x1 = 0.0, x2 = 1./3., x3 = 2./3., x4 = 1.0,399 # y1 =0.0, y4 = -1./4., y8 = 1.0,400 # origin = (0.0, 0.0), point_class=Point,401 # element_class=Triangle, mesh_class=Mesh):402 # """Setup a oblique grid of triangles403 # with m segments in the x-direction and n segments in the y-direction404 405 # Triangle refers to the actual class or subclass to be instantiated:406 # e.g. if Volume is a subclass of Triangle,407 # this function can be invoked with the keywords408 # oblique_mesh(...,Triangle=Volume, Mesh=Domain)409 # """410 411 # from Numeric import array412 # from visual import rate#413 414 # import math415 416 # from config import epsilon417 418 # E = m*n*2 #Number of triangular elements419 # P = (m+1)*(n+1) #Number of initial vertices420 421 # initialise_consecutive_datastructure(P+E, E,422 # point_class,423 # element_class,424 # mesh_class)425 426 # deltax = (x4 - x1)/float(m)427 # deltay = (y8 - y1)/float(n)428 # a = y4 - y1429 430 # if y8 - a <= y1 + a:431 # print a,y1,y4432 # raise 'Constriction is too large reduce a'433 434 # y2 = y1435 # y3 = y4436 # x5 = x4437 # y5 = y8 - a438 # x6 = x3439 # y6 = y5440 # x7 = x2441 # y7 = y8442 # x8 = x1443 444 # a2 = a/(x3 - x2)445 # a1 = a - a*x3/(x3 - x2)446 # a4 = (-a + a2*(x7 - x6))/(x6 - x7)/y7447 # a3 = (y7 - a1 - x7*a2 - a4*x7*y7)/y7448 449 # # Dictionary of vertex objects450 # vertices = {}451 452 # for i in range(m+1):453 # x = deltax*i454 # for j in range(n+1):455 # y = deltay*j456 # if x > x2:457 # if x < x3:458 # y = a1 + a2*x + a3*y + a4*x*y459 # else:460 # y = a + y*(y5 - y4)/(y8 - y1)461 462 # vertices[i,j] = Point(x + origin[0],y + origin[1])463 464 # # Construct 2 elements per element465 # elements = []466 # for i in range(m):467 # for j in range(n):468 # v1 = vertices[i,j+1]469 # v2 = vertices[i,j]470 # v3 = vertices[i+1,j+1]471 # v4 = vertices[i+1,j]472 473 # elements.append(element_class(v4,v3,v2)) #Lower474 # elements.append(element_class(v1,v2,v3)) #Upper475 476 # M = mesh_class(elements)477 478 # #Set a default tagging479 480 # for id, face in M.boundary:481 482 # e = element_class.instances[id]483 # x_0, y_0, x_1, y_1, x_2, y_2 = e.get_instance_vertex_coordinates()484 # lenx = x4 - x1485 # if face==2:486 # #Left or right#487 # if abs(x_0-origin[0]) < epsilon:488 # M.boundary[(id,face)] = 'left'489 # elif abs(origin[0]+lenx-x_0) < epsilon:490 # M.boundary[(id,face)] = 'right'491 # else:492 # print face, id, id%m, m, n493 # raise 'Left or Right Unknown boundary'494 # elif face==1:495 # #Top or bottom496 # if x_0 <= x2 and abs(y_0-y1-origin[1]) < epsilon or\497 # x_0 > x3 and abs(y_0-y3-origin[1]) < epsilon or\498 # x_0 > x2 and x_0 <= x3 and abs(y_0-(y2+(y3-y2)*(x_0-x2)/(x3-x2)+origin[1])) < epsilon:499 # M.boundary[(id,face)] = 'bottom'500 # elif x_0 <= x7 and abs(y_0-y8-origin[1]) < epsilon or\501 # x_0 > x6 and abs(y_0-y6-origin[1]) < epsilon or\502 # x_0 > x7 and x_0 <= x6 and abs(y_0-(y7+(y6-y7)*(x_0-x7)/(x6-x7)+origin[1])) < epsilon:503 # M.boundary[(id,face)] = 'top'504 # else:505 # print face, id, id%m, m, n506 # raise 'Top or Bottom Unknown boundary'507 # else:508 # print face, id, id%m, m, n509 # raise 'Unknown boundary'510 511 512 # # print id, face, M.boundary[(id,face)],x_0,y_0,x_1,y_1,x_2,y_2513 514 # return M515 516 517 518 363 # #Map from edge number to indices of associated vertices 519 364 # edge_map = ((1,2), (0,2), (0,1)) -
inundation/ga/storm_surge/pyvolution/test_least_squares.py
r705 r820 488 488 489 489 490 491 def test_xya2rectangular(self): 492 493 import time, os 494 FN = 'xyatest' + str(time.time()) + '.xya' 495 fid = open(FN, 'w') 496 fid.write('%f %f %f %f\n' %(1,1,2,4) ) 497 fid.write('%f %f %f %f\n' %(1,3,4,8) ) 498 fid.write('%f %f %f %f\n' %(3,1,4,8) ) 499 fid.close() 500 501 points, triangles, boundary, attributes = xya2rectangular(FN, 4, 4) 502 503 504 505 506 z1 = [2, 4] 507 z2 = [4, 8] 508 z3 = [4, 8] 509 data_coords = [ [1,1], [1,3], [3,1] ] 510 z = [z1, z2, z3] 511 512 ref = fit_to_mesh(points, triangles, data_coords, z) 513 514 assert allclose(attributes, ref) 515 516 517 490 518 491 519 #Tests of smoothing matrix -
inundation/ga/storm_surge/pyvolution/test_util.py
r799 r820 336 336 assert allclose( 2*sin(120*pi/600)/3 + sin(60*pi/600)/3, q[2] ) 337 337 338 339 def test_xya(self): 340 import time, os 341 FN = 'xyatest' + str(time.time()) + '.xya' 342 fid = open(FN, 'w') 343 fid.write('%f %f %f %f %f\n' %(0,1,10,20,30) ) 344 fid.write('%f %f %f %f %f\n' %(1,0,30,20,10) ) 345 fid.write('%f %f %f %f %f\n' %(1,1,40.2,40.3,40.4) ) 346 fid.close() 347 348 points, attributes = read_xya(FN) 349 350 assert allclose(points, [ [0,1], [1,0], [1,1] ]) 351 assert allclose(attributes, [ [10,20,30], [30,20,10], 352 [40.2,40.3,40.4] ]) 353 354 os.remove(FN) 338 355 339 356 -
inundation/ga/storm_surge/pyvolution/util.py
r799 r820 80 80 return False 81 81 82 83 class File_function: 84 """Read time series from file and return a callable object: 85 f(t,x,y) 86 which will return interpolated values based on the input file. 87 88 The file format is assumed to be either two fields separated by a comma: 89 90 time [DD/MM/YY hh:mm:ss], value0 value1 value2 ... 91 92 or four comma separated fields 93 94 time [DD/MM/YY hh:mm:ss], x, y, value0 value1 value2 ... 95 96 In either case, the callable object will return a tuple of 97 interpolated values, one each value stated in the file. 98 99 100 E.g 101 102 31/08/04 00:00:00, 1.328223 0 0 103 31/08/04 00:15:00, 1.292912 0 0 104 105 will provide a time dependent function f(t,x=None,y=None), 106 ignoring x and y, which returns three values per call. 107 108 109 NOTE: At this stage the function is assumed to depend on 110 time only, i.e no spatial dependency!!!!! 111 When that is need we can use the least_squares interpolation. 112 """ 113 114 115 def __init__(self, filename, domain=None): 116 """Initialise callable object from a file. 117 See docstring for class File_function 118 119 If domain is specified, model time (domain,starttime) 120 will be checked and possibly modified 121 122 ALl times are assumed to be in UTC 123 """ 124 125 import time, calendar 126 from Numeric import array 127 from config import time_format 128 129 assert type(filename) == type(''),\ 130 'First argument to File_function must be a string' 131 132 133 try: 134 fid = open(filename) 135 except Exception, e: 136 msg = 'File "%s" could not be opened: Error="%s"'\ 137 %(filename, e) 138 raise msg 139 140 141 line = fid.readline() 142 fid.close() 143 fields = line.split(',') 144 msg = 'File %s must have the format date, value0 value1 value2 ...' 145 msg += ' or date, x, y, value0 value1 value2 ...' 146 mode = len(fields) 147 assert mode in [2,4], msg 148 149 try: 150 starttime = calendar.timegm(time.strptime(fields[0], time_format)) 151 except ValueError: 152 msg = 'First field in file %s must be' %filename 153 msg += ' date-time with format %s.\n' %time_format 154 msg += 'I got %s instead.' %fields[0] 155 raise msg 156 157 158 #Split values 159 values = [] 160 for value in fields[mode-1].split(): 161 values.append(float(value)) 162 163 q = array(values) 164 165 msg = 'ERROR: File must contain at least one independent value' 166 assert len(q.shape) == 1, msg 167 168 self.number_of_values = len(q) 169 170 self.filename = filename 171 self.starttime = starttime 172 self.domain = domain 173 174 if domain is not None: 175 if domain.starttime is None: 176 domain.starttime = self.starttime 177 else: 178 msg = 'WARNING: Start time as specified in domain (%s)'\ 179 %domain.starttime 180 msg += ' is earlier than the starttime of file %s: %s.'\ 181 %(self.filename, self.starttime) 182 msg += 'Modifying starttime accordingly.' 183 if self.starttime > domain.starttime: 184 #FIXME: Print depending on some verbosity setting 185 #print msg 186 domain.starttime = self.starttime #Modifying model time 187 188 if mode == 2: 189 self.read_times() #Now read all times in. 190 else: 191 raise 'x,y dependecy not yet implemented' 192 193 194 def read_times(self): 195 """Read time and values 196 """ 197 from Numeric import zeros, Float, alltrue 198 from config import time_format 199 import time, calendar 200 201 fid = open(self.filename) 202 lines = fid.readlines() 203 fid.close() 204 205 N = len(lines) 206 d = self.number_of_values 207 208 T = zeros(N, Float) #Time 209 Q = zeros((N, d), Float) #Values 210 211 for i, line in enumerate(lines): 212 fields = line.split(',') 213 realtime = calendar.timegm(time.strptime(fields[0], time_format)) 214 215 T[i] = realtime - self.starttime 216 217 for j, value in enumerate(fields[1].split()): 218 Q[i, j] = float(value) 219 220 msg = 'File %s must list time as a monotonuosly ' %self.filename 221 msg += 'increasing sequence' 222 assert alltrue( T[1:] - T[:-1] > 0 ), msg 223 224 self.T = T #Time 225 self.Q = Q #Values 226 self.index = 0 #Initial index 227 228 229 def __repr__(self): 230 return 'File function' 231 232 233 234 def __call__(self, t, x=None, y=None): 235 """Evaluate f(t,x,y) 236 237 FIXME: x, y dependency not yet implemented except that 238 result is a vector of same length as x and y 239 """ 240 241 from math import pi, cos, sin, sqrt 242 243 244 #Find time tau such that 245 # 246 # domain.starttime + t == self.starttime + tau 247 248 if self.domain is not None: 249 tau = self.domain.starttime-self.starttime+t 250 else: 251 tau = t 252 253 254 msg = 'Time interval derived from file %s (%s:%s) does not match model time: %s'\ 255 %(self.filename, self.T[0], self.T[1], tau) 256 if tau < self.T[0]: raise msg 257 if tau > self.T[-1]: raise msg 258 259 oldindex = self.index 260 261 #Find slot 262 while tau > self.T[self.index]: self.index += 1 263 while tau < self.T[self.index]: self.index -= 1 264 265 #t is now between index and index+1 266 ratio = (tau - self.T[self.index])/\ 267 (self.T[self.index+1] - self.T[self.index]) 268 269 #Compute interpolated values 270 q = self.Q[self.index,:] +\ 271 ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 272 273 #Return vector of interpolated values 274 if x == None and y == None: 275 return q 276 else: 277 from Numeric import ones, Float 278 #Create one constant column for each value 279 N = len(x) 280 assert len(y) == N, 'x and y must have same length' 281 282 res = [] 283 for col in q: 284 res.append(col*ones(N, Float)) 285 286 return res 287 288 def read_xya(file_name): 289 """Read simple xya file, no header, just 290 x y [attributes] 291 separated by whitespace 292 293 Return list of points and list of attributes 294 """ 295 296 fid = open(file_name) 297 lines = fid.readlines() 298 299 points = [] 300 attributes = [] 301 for line in lines: 302 fields = line.strip().split() 303 304 points.append( (float(fields[0]), float(fields[1])) ) 305 attributes.append( [float(z) for z in fields[2:] ] ) 306 307 return points, attributes 308 309 310 ##################################### 311 #POLYFON STUFF 312 # 313 #FIXME: ALl these should be put into new module polygon.py 82 314 83 315 def inside_polygon(point, polygon, closed = True): … … 286 518 287 519 return polygon 288 289 290 class File_function: 291 """Read time series from file and return a callable object: 292 f(t,x,y) 293 which will return interpolated values based on the input file. 294 295 The file format is assumed to be either two fields separated by a comma: 296 297 time [DD/MM/YY hh:mm:ss], value0 value1 value2 ... 298 299 or four comma separated fields 300 301 time [DD/MM/YY hh:mm:ss], x, y, value0 value1 value2 ... 302 303 In either case, the callable object will return a tuple of 304 interpolated values, one each value stated in the file. 305 306 307 E.g 308 309 31/08/04 00:00:00, 1.328223 0 0 310 31/08/04 00:15:00, 1.292912 0 0 311 312 will provide a time dependent function f(t,x=None,y=None), 313 ignoring x and y, which returns three values per call. 314 315 316 NOTE: At this stage the function is assumed to depend on 317 time only, i.e no spatial dependency!!!!! 318 When that is need we can use the least_squares interpolation. 319 """ 320 321 322 def __init__(self, filename, domain=None): 323 """Initialise callable object from a file. 324 See docstring for class File_function 325 326 If domain is specified, model time (domain,starttime) 327 will be checked and possibly modified 328 329 ALl times are assumed to be in UTC 330 """ 331 332 import time, calendar 333 from Numeric import array 334 from config import time_format 335 336 assert type(filename) == type(''),\ 337 'First argument to File_function must be a string' 338 339 340 try: 341 fid = open(filename) 342 except Exception, e: 343 msg = 'File "%s" could not be opened: Error="%s"'\ 344 %(filename, e) 345 raise msg 346 347 348 line = fid.readline() 349 fid.close() 350 fields = line.split(',') 351 msg = 'File %s must have the format date, value0 value1 value2 ...' 352 msg += ' or date, x, y, value0 value1 value2 ...' 353 mode = len(fields) 354 assert mode in [2,4], msg 355 356 try: 357 starttime = calendar.timegm(time.strptime(fields[0], time_format)) 358 except ValueError: 359 msg = 'First field in file %s must be' %filename 360 msg += ' date-time with format %s.\n' %time_format 361 msg += 'I got %s instead.' %fields[0] 362 raise msg 363 364 365 #Split values 366 values = [] 367 for value in fields[mode-1].split(): 368 values.append(float(value)) 369 370 q = array(values) 371 372 msg = 'ERROR: File must contain at least one independent value' 373 assert len(q.shape) == 1, msg 374 375 self.number_of_values = len(q) 376 377 self.filename = filename 378 self.starttime = starttime 379 self.domain = domain 380 381 if domain is not None: 382 if domain.starttime is None: 383 domain.starttime = self.starttime 384 else: 385 msg = 'WARNING: Start time as specified in domain (%s)'\ 386 %domain.starttime 387 msg += ' is earlier than the starttime of file %s: %s.'\ 388 %(self.filename, self.starttime) 389 msg += 'Modifying starttime accordingly.' 390 if self.starttime > domain.starttime: 391 #FIXME: Print depending on some verbosity setting 392 #print msg 393 domain.starttime = self.starttime #Modifying model time 394 395 if mode == 2: 396 self.read_times() #Now read all times in. 397 else: 398 raise 'x,y dependecy not yet implemented' 399 400 401 def read_times(self): 402 """Read time and values 403 """ 404 from Numeric import zeros, Float, alltrue 405 from config import time_format 406 import time, calendar 407 408 fid = open(self.filename) 409 lines = fid.readlines() 410 fid.close() 411 412 N = len(lines) 413 d = self.number_of_values 414 415 T = zeros(N, Float) #Time 416 Q = zeros((N, d), Float) #Values 417 418 for i, line in enumerate(lines): 419 fields = line.split(',') 420 realtime = calendar.timegm(time.strptime(fields[0], time_format)) 421 422 T[i] = realtime - self.starttime 423 424 for j, value in enumerate(fields[1].split()): 425 Q[i, j] = float(value) 426 427 msg = 'File %s must list time as a monotonuosly ' %self.filename 428 msg += 'increasing sequence' 429 assert alltrue( T[1:] - T[:-1] > 0 ), msg 430 431 self.T = T #Time 432 self.Q = Q #Values 433 self.index = 0 #Initial index 434 435 436 def __repr__(self): 437 return 'File function' 438 439 440 441 def __call__(self, t, x=None, y=None): 442 """Evaluate f(t,x,y) 443 444 FIXME: x, y dependency not yet implemented except that 445 result is a vector of same length as x and y 446 """ 447 448 from math import pi, cos, sin, sqrt 449 450 451 #Find time tau such that 452 # 453 # domain.starttime + t == self.starttime + tau 454 455 if self.domain is not None: 456 tau = self.domain.starttime-self.starttime+t 457 else: 458 tau = t 459 460 461 msg = 'Time interval derived from file %s (%s:%s) does not match model time: %s'\ 462 %(self.filename, self.T[0], self.T[1], tau) 463 if tau < self.T[0]: raise msg 464 if tau > self.T[-1]: raise msg 465 466 oldindex = self.index 467 468 #Find slot 469 while tau > self.T[self.index]: self.index += 1 470 while tau < self.T[self.index]: self.index -= 1 471 472 #t is now between index and index+1 473 ratio = (tau - self.T[self.index])/\ 474 (self.T[self.index+1] - self.T[self.index]) 475 476 #Compute interpolated values 477 q = self.Q[self.index,:] +\ 478 ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 479 480 #Return vector of interpolated values 481 if x == None and y == None: 482 return q 483 else: 484 from Numeric import ones, Float 485 #Create one constant column for each value 486 N = len(x) 487 assert len(y) == N, 'x and y must have same length' 488 489 res = [] 490 for col in q: 491 res.append(col*ones(N, Float)) 492 493 return res 494 495 520 496 521 def populate_polygon(polygon, number_of_points, seed = None): 497 522 """Populate given polygon with uniformly distributed points.
Note: See TracChangeset
for help on using the changeset viewer.