Changeset 1750
- Timestamp:
- Aug 24, 2005, 11:45:12 AM (19 years ago)
- Location:
- inundation
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
inundation/pyvolution/quantity.py
r1749 r1750 82 82 83 83 #New leaner interface to setting values 84 def set_ quantity(self,85 86 87 88 89 90 91 indices = None,92 location = None, #Really needed93 84 def set_values_new(self, 85 numeric = None, #List, numeric array or constant 86 quantity = None, #Another quantity 87 function = None, #Callable object: f(x,y) 88 points = None, values = None, #Input for least squares 89 filename = None, attribute_name = None, #Input from file 90 alpha = None, 91 location = None, 92 indices = None, 93 verbose = None): 94 94 95 95 """Set values for quantity based on different sources. 96 96 97 97 numeric: 98 98 … … 109 109 Any callable object that takes two 1d arrays x and y 110 110 each of length N and returns an array also of length N. 111 The function will be evaluated at points determined by 112 location and indices. 111 113 112 114 points: … … 125 127 Smoothing parameter to be used with least squares fits. 126 128 See module least_squares for further details about alpha. 129 Alpha will only be used with points, values or filename. 130 Otherwise it will be ignored. 127 131 128 132 … … 131 135 Default is 'vertices' 132 136 133 In case of location == 'centroids' the dimension values must 134 be a list of a Numerical array of length N, N being the number 135 of elements. Otherwise it must be of dimension Nx3 136 137 The values will be stored in elements following their 138 internal ordering. 139 140 If values are described a function, it will be evaluated at 141 specified points 142 143 If location is not 'unique vertices' Indices is the set of element ids 144 that the operation applies to. 145 If location is 'unique vertices' Indices is the set of vertex ids 146 that the operation applies to. 147 148 If selected location is vertices, values for centroid and edges 149 will be assigned interpolated values. 150 In any other case, only values for the specified locations 151 will be assigned and the others will be left undefined. 152 153 """ 154 pass 155 156 157 158 159 160 161 #Old interface to setting values 162 def set_values(self, X, 163 location='vertices', 164 indexes = None): 165 """Set values for quantity 166 167 X: Compatible list, Numeric array (see below), constant or function 168 location: Where values are to be stored. 169 Permissible options are: vertices, edges, centroids 170 Default is "vertices" 171 172 In case of location == 'centroids' the dimension values must 173 be a list of a Numerical array of length N, N being the number 174 of elements. Otherwise it must be of dimension Nx3 175 176 The values will be stored in elements following their 177 internal ordering. 178 179 If values are described a function, it will be evaluated at 180 specified points 181 182 If indexex is not 'unique vertices' Indexes is the set of element ids 183 that the operation applies to. 184 If indexex is 'unique vertices' Indexes is the set of vertex ids 185 that the operation applies to. 186 187 If selected location is 'vertices', values for centroid and edges 188 will be assigned interpolated values. 189 In any other case, only values for the specified locations 190 will be assigned and the others will be left undefined. 191 192 """ 137 In case of location == 'centroids' the dimension values must 138 be a list of a Numerical array of length N, 139 N being the number of elements. 140 Otherwise it must be of dimension Nx3 141 142 143 The values will be stored in elements following their 144 internal ordering. 145 146 If location is not 'unique vertices' Indices is the 147 set of element ids that the operation applies to. 148 If location is 'unique vertices' Indices is the set 149 of vertex ids that the operation applies to. 150 151 If selected location is vertices, values for 152 centroid and edges will be assigned interpolated 153 values. In any other case, only values for the 154 specified locations will be assigned and the others 155 will be left undefined. 156 157 158 Exactly one of the arguments 159 numeric, quantity, function, points, filename 160 must be present. 161 """ 162 163 from types import FloatType, IntType, LongType, ListType, NoneType 164 from Numeric import ArrayType 165 166 #General input checks 167 msg = 'Exactly one of the arguments '+\ 168 'numeric, quantity, function, points, or filename '+\ 169 'must be present.' 170 L = [numeric, quantity, function, points, filename] 171 assert L.count(None) == len(L)-1, msg 172 193 173 194 174 if location not in ['vertices', 'centroids', 'edges', … … 198 178 199 179 200 if X is None: 201 msg = 'Given values are None' 202 raise msg 203 204 import types, Numeric 205 assert type(indexes) in [types.ListType, types.NoneType, 206 Numeric.ArrayType],\ 207 'Indices must be a list or None' 208 209 210 if callable(X): 211 #Use function specific method 212 self.set_function_values(X, location, indexes = indexes) 213 elif type(X) in [types.FloatType, types.IntType, types.LongType]: 214 if location == 'centroids': 215 if (indexes == None): 216 self.centroid_values[:] = X 217 else: 218 #Brute force 219 for i in indexes: 220 self.centroid_values[i,:] = X 221 222 elif location == 'edges': 223 if (indexes == None): 224 self.edge_values[:] = X 225 else: 226 #Brute force 227 for i in indexes: 228 self.edge_values[i,:] = X 229 230 elif location == 'unique vertices': 231 if (indexes == None): 232 self.edge_values[:] = X 233 else: 234 235 #Go through list of unique vertices 236 for unique_vert_id in indexes: 237 triangles = self.domain.vertexlist[unique_vert_id] 238 239 #In case there are unused points 240 if triangles is None: continue 241 242 #Go through all triangle, vertex pairs 243 #and set corresponding vertex value 244 for triangle_id, vertex_id in triangles: 245 self.vertex_values[triangle_id, vertex_id] = X 246 247 #Intialise centroid and edge_values 248 self.interpolate() 180 msg = 'Indices must be a list or None' 181 assert type(indices) in [ListType, NoneType, ArrayType], msg 182 183 184 185 #Determine which 'set_values_from_...' to use 186 187 if numeric is not None: 188 if type(numeric) in [FloatType, IntType, LongType]: 189 self.set_values_from_constant(numeric, 190 location, indices, verbose) 191 elif type(numeric) in [ArrayType, ListType]: 192 self.set_values_from_array(numeric, 193 location, indices, verbose) 194 elif callable(numeric): 195 self.set_values_from_function(numeric, 196 location, indices, verbose) 249 197 else: 250 if (indexes == None): 251 self.vertex_values[:] = X 252 else: 253 #Brute force 254 for i_vertex in indexes: 255 self.vertex_values[i_vertex,:] = X 256 257 elif type(X) in [Numeric.ArrayType, types.ListType]: 258 #Use array specific method 259 self.set_array_values(X, location, indexes = indexes) 260 elif type(X) == types.StringType: 261 #Assume X is a filename 262 self.set_values_from_file(X) #FIXME: More parameters 263 264 265 if location == 'vertices' or location == 'unique vertices': 266 #Intialise centroid and edge_values 267 self.interpolate() 268 269 if location == 'centroids': 270 #Extrapolate 1st order - to capture notion of area being specified 271 self.extrapolate_first_order() 272 273 def get_values(self, location='vertices', indexes = None): 274 """get values for quantity 275 276 return X, Compatible list, Numeric array (see below) 277 location: Where values are to be stored. 278 Permissible options are: vertices, edges, centroid 279 Default is "vertices" 280 281 In case of location == 'centroids' the dimension values must 282 be a list of a Numerical array of length N, N being the number 283 of elements. Otherwise it must be of dimension Nx3 284 285 The returned values with be a list the length of indexes 286 (N if indexes = None). Each value will be a list of the three 287 vertex values for this quantity. 288 289 Indexes is the set of element ids that the operation applies to. 290 291 """ 292 from Numeric import take 293 294 if location not in ['vertices', 'centroids', 'edges', 'unique vertices']: 295 msg = 'Invalid location: %s' %location 296 raise msg 297 298 import types, Numeric 299 assert type(indexes) in [types.ListType, types.NoneType, 300 Numeric.ArrayType],\ 301 'Indices must be a list or None' 302 303 if location == 'centroids': 304 if (indexes == None): 305 indexes = range(len(self)) 306 return take(self.centroid_values,indexes) 307 elif location == 'edges': 308 if (indexes == None): 309 indexes = range(len(self)) 310 return take(self.edge_values,indexes) 311 elif location == 'unique vertices': 312 if (indexes == None): 313 indexes=range(self.domain.coordinates.shape[0]) 314 vert_values = [] 315 #Go through list of unique vertices 316 for unique_vert_id in indexes: 317 triangles = self.domain.vertexlist[unique_vert_id] 318 319 #In case there are unused points 320 if triangles is None: 321 msg = 'Unique vertex not associated with triangles' 322 raise msg 323 324 # Go through all triangle, vertex pairs 325 # Average the values 326 sum = 0 327 for triangle_id, vertex_id in triangles: 328 sum += self.vertex_values[triangle_id, vertex_id] 329 vert_values.append(sum/len(triangles)) 330 return Numeric.array(vert_values) 331 else: 332 if (indexes == None): 333 indexes = range(len(self)) 334 return take(self.vertex_values,indexes) 335 336 337 def set_function_values(self, f, location='vertices', indexes = None): 198 msg = 'Illegal type for argument numeric: %s' %str(numeric) 199 raise msg 200 elif quantity is not None: 201 self.set_values_from_quantity(quantity, 202 location, indices, verbose) 203 elif function is not None: 204 msg = 'Argument function must be callable' 205 assert callable(function), msg 206 self.set_values_from_function(function, 207 location, indices, verbose) 208 elif points is not None: 209 msg = 'When points are specified, associated values must also be.' 210 assert values is not None, msg 211 self.set_values_from_points(points, values, alpha, 212 location, indices, verbose) 213 elif filename is not None: 214 self.set_values_from_file(filename, attribute_name, alpha, 215 location, indices, verbose) 216 else: 217 raise 'This can\'t happen :-)' 218 219 220 221 #Specific functions for setting values 222 def set_values_from_function(self, function, 223 location, indices, verbose): 338 224 """Set values for quantity using specified function 339 225 340 226 f: x, y -> z Function where x, y and z are arrays 341 227 location: Where values are to be stored. 342 Permissible options are: vertices, centroid 228 Permissible options are: vertices, centroid, edges, 229 unique vertices 343 230 Default is "vertices" 344 231 """ 345 232 346 233 #FIXME: Should check that function returns something sensible and 347 #raise a meaningf ol exception if it returns None for example234 #raise a meaningfull exception if it returns None for example 348 235 349 236 from Numeric import take 350 237 351 if (indexes ==None):238 if (indexes is None): 352 239 indexes = range(len(self)) 353 240 is_subset = False … … 473 360 474 361 475 def set_values_from_file(self, filename, 476 attribute_name = None, 477 verbose = False): 478 """Set quantity based on arbitrary points in .pts file using least_squares 479 480 attribute_name selects name of attribute present in file. 362 def set_values_from_points(self, points, values, alpha, 363 location, indices, verbose): 364 """ 365 """ 366 367 368 #FIXME: Needs unit test 369 from util import ensure_numeric 370 from least_squares import fit_to_mesh 371 372 points = ensure_numeric(points, Float) 373 values = ensure_numeric(values, Float) 374 375 if location != 'vertices': 376 msg = 'set_values_from_points is only defined for'+\ 377 'location=\'vertices\'' 378 raise msg 379 380 coordinates = self.domain.coordinates 381 triangles = self.domain.triangles 382 383 #FIXME Pass and use caching here 384 vertex_attributes = fit_to_mesh(coordinates, 385 triangles, 386 points, 387 values, 388 alpha = alpha, 389 verbose = verbose) 390 391 self.set_values_from_array(vertex_attributes, 392 location, indices, verbose) 393 394 395 396 397 398 def set_values_from_file(self, filename, attribute_name, alpha, 399 location, indices, verbose): 400 """Set quantity based on arbitrary points in .pts file 401 using least_squares attribute_name selects name of attribute 402 present in file. 481 403 If not specified try to use whatever is available in file. 482 404 """ 483 405 484 #FIXME location, indices 485 486 487 import util, least_squares 488 406 407 #FIXME: Needs unit test 408 from types import StringType 409 msg = 'Filename must be a text string' 410 assert type(filename) == StringType, msg 411 412 413 #Read from (NetCDF) file 414 import util 489 415 points, attributes = util.read_xya(filename) 490 416 491 417 if attribute_name is None: 492 418 names = attributes.keys() 493 419 attribute_name = names[0] 494 420 421 msg = 'Attribute_name must be a text string' 422 assert type(attribute_name) == StringType, msg 423 495 424 496 425 if verbose: 497 426 print 'Using attribute %s from file %s' %(attribute_name, filename) 498 427 print 'Available attributes: %s' %(names) 499 500 428 501 429 try: … … 506 434 raise msg 507 435 508 509 #Fit attributes to mesh 510 X = least_squares.fit_to_mesh(self.domain.coordinates, 511 self.domain.triangles, 512 points, 513 z, 514 verbose=verbose) 515 516 517 518 #Recursively set value using fitted array 519 print 'shape', X.shape 520 self.set_values(X, location='vertices') #FIXME, indexes = None): 436 437 #Call least squares method 438 self.set_values_from_points(points, z, alpha, 439 location, indices, verbose) 440 441 442 443 444 445 #Old interface to setting values 446 def set_values(self, X, 447 location='vertices', 448 indexes = None): 449 """Set values for quantity 450 451 X: Compatible list, Numeric array (see below), constant or function 452 location: Where values are to be stored. 453 Permissible options are: vertices, edges, centroids 454 Default is "vertices" 455 456 In case of location == 'centroids' the dimension values must 457 be a list of a Numerical array of length N, N being the number 458 of elements. Otherwise it must be of dimension Nx3 459 460 The values will be stored in elements following their 461 internal ordering. 462 463 If values are described a function, it will be evaluated at 464 specified points 465 466 If indexex is not 'unique vertices' Indexes is the set of element ids 467 that the operation applies to. 468 If indexex is 'unique vertices' Indexes is the set of vertex ids 469 that the operation applies to. 470 471 If selected location is 'vertices', values for centroid and edges 472 will be assigned interpolated values. 473 In any other case, only values for the specified locations 474 will be assigned and the others will be left undefined. 475 476 """ 477 478 if location not in ['vertices', 'centroids', 'edges', 479 'unique vertices']: 480 msg = 'Invalid location: %s' %location 481 raise msg 482 483 484 if X is None: 485 msg = 'Given values are None' 486 raise msg 487 488 import types, Numeric 489 assert type(indexes) in [types.ListType, types.NoneType, 490 Numeric.ArrayType],\ 491 'Indices must be a list or None' 492 493 494 if callable(X): 495 #Use function specific method 496 self.set_function_values(X, location, indexes = indexes) 497 elif type(X) in [types.FloatType, types.IntType, types.LongType]: 498 if location == 'centroids': 499 if (indexes == None): 500 self.centroid_values[:] = X 501 else: 502 #Brute force 503 for i in indexes: 504 self.centroid_values[i,:] = X 505 506 elif location == 'edges': 507 if (indexes == None): 508 self.edge_values[:] = X 509 else: 510 #Brute force 511 for i in indexes: 512 self.edge_values[i,:] = X 513 514 elif location == 'unique vertices': 515 if (indexes == None): 516 self.edge_values[:] = X 517 else: 518 519 #Go through list of unique vertices 520 for unique_vert_id in indexes: 521 triangles = self.domain.vertexlist[unique_vert_id] 522 523 #In case there are unused points 524 if triangles is None: continue 525 526 #Go through all triangle, vertex pairs 527 #and set corresponding vertex value 528 for triangle_id, vertex_id in triangles: 529 self.vertex_values[triangle_id, vertex_id] = X 530 531 #Intialise centroid and edge_values 532 self.interpolate() 533 else: 534 if (indexes == None): 535 self.vertex_values[:] = X 536 else: 537 #Brute force 538 for i_vertex in indexes: 539 self.vertex_values[i_vertex,:] = X 540 541 elif type(X) in [Numeric.ArrayType, types.ListType]: 542 #Use array specific method 543 self.set_array_values(X, location, indexes = indexes) 544 elif type(X) == types.StringType: 545 #Assume X is a filename 546 self.set_values_from_file(X) #FIXME: More parameters 547 548 549 if location == 'vertices' or location == 'unique vertices': 550 #Intialise centroid and edge_values 551 self.interpolate() 552 553 if location == 'centroids': 554 #Extrapolate 1st order - to capture notion of area being specified 555 self.extrapolate_first_order() 556 557 558 559 def get_values(self, location='vertices', indexes = None): 560 """get values for quantity 561 562 return X, Compatible list, Numeric array (see below) 563 location: Where values are to be stored. 564 Permissible options are: vertices, edges, centroid 565 Default is "vertices" 566 567 In case of location == 'centroids' the dimension values must 568 be a list of a Numerical array of length N, N being the number 569 of elements. Otherwise it must be of dimension Nx3 570 571 The returned values with be a list the length of indexes 572 (N if indexes = None). Each value will be a list of the three 573 vertex values for this quantity. 574 575 Indexes is the set of element ids that the operation applies to. 576 577 """ 578 from Numeric import take 579 580 if location not in ['vertices', 'centroids', 'edges', 'unique vertices']: 581 msg = 'Invalid location: %s' %location 582 raise msg 583 584 import types, Numeric 585 assert type(indexes) in [types.ListType, types.NoneType, 586 Numeric.ArrayType],\ 587 'Indices must be a list or None' 588 589 if location == 'centroids': 590 if (indexes == None): 591 indexes = range(len(self)) 592 return take(self.centroid_values,indexes) 593 elif location == 'edges': 594 if (indexes == None): 595 indexes = range(len(self)) 596 return take(self.edge_values,indexes) 597 elif location == 'unique vertices': 598 if (indexes == None): 599 indexes=range(self.domain.coordinates.shape[0]) 600 vert_values = [] 601 #Go through list of unique vertices 602 for unique_vert_id in indexes: 603 triangles = self.domain.vertexlist[unique_vert_id] 604 605 #In case there are unused points 606 if triangles is None: 607 msg = 'Unique vertex not associated with triangles' 608 raise msg 609 610 # Go through all triangle, vertex pairs 611 # Average the values 612 sum = 0 613 for triangle_id, vertex_id in triangles: 614 sum += self.vertex_values[triangle_id, vertex_id] 615 vert_values.append(sum/len(triangles)) 616 return Numeric.array(vert_values) 617 else: 618 if (indexes == None): 619 indexes = range(len(self)) 620 return take(self.vertex_values,indexes) 621 622 623 def set_function_values(self, f, location='vertices', indexes = None): 624 """Set values for quantity using specified function 625 626 f: x, y -> z Function where x, y and z are arrays 627 location: Where values are to be stored. 628 Permissible options are: vertices, centroid 629 Default is "vertices" 630 """ 631 632 #FIXME: Should check that function returns something sensible and 633 #raise a meaningfol exception if it returns None for example 634 635 from Numeric import take 636 637 if (indexes == None): 638 indexes = range(len(self)) 639 is_subset = False 640 else: 641 is_subset = True 642 if location == 'centroids': 643 P = take(self.domain.centroid_coordinates,indexes) 644 if is_subset: 645 self.set_values(f(P[:,0], P[:,1]), location, indexes = indexes) 646 else: 647 self.set_values(f(P[:,0], P[:,1]), location) 648 elif location == 'vertices': 649 P = self.domain.vertex_coordinates 650 if is_subset: 651 #Brute force 652 for e in indexes: 653 for i in range(3): 654 self.vertex_values[e,i] = f(P[e,2*i], P[e,2*i+1]) 655 else: 656 for i in range(3): 657 self.vertex_values[:,i] = f(P[:,2*i], P[:,2*i+1]) 658 else: 659 raise 'Not implemented: %s' %location 660 661 662 def set_array_values(self, values, location='vertices', indexes = None): 663 """Set values for quantity 664 665 values: Numeric array 666 location: Where values are to be stored. 667 Permissible options are: vertices, edges, centroid, unique vertices 668 Default is "vertices" 669 670 indexes - if this action is carried out on a subset of 671 elements or unique vertices 672 The element/unique vertex indexes are specified here. 673 674 In case of location == 'centroid' the dimension values must 675 be a list of a Numerical array of length N, N being the number 676 of elements. 677 678 Otherwise it must be of dimension Nx3 679 680 The values will be stored in elements following their 681 internal ordering. 682 683 If selected location is vertices, values for centroid and edges 684 will be assigned interpolated values. 685 In any other case, only values for the specified locations 686 will be assigned and the others will be left undefined. 687 """ 688 689 from Numeric import array, Float, Int, allclose 690 691 values = array(values).astype(Float) 692 693 if (indexes <> None): 694 indexes = array(indexes).astype(Int) 695 msg = 'Number of values must match number of indexes' 696 assert values.shape[0] == indexes.shape[0], msg 697 698 N = self.centroid_values.shape[0] 699 700 if location == 'centroids': 701 assert len(values.shape) == 1, 'Values array must be 1d' 702 703 if indexes == None: 704 msg = 'Number of values must match number of elements' 705 assert values.shape[0] == N, msg 706 707 self.centroid_values = values 708 else: 709 msg = 'Number of values must match number of indexes' 710 assert values.shape[0] == indexes.shape[0], msg 711 712 #Brute force 713 for i in range(len(indexes)): 714 self.centroid_values[indexes[i]] = values[i] 715 716 elif location == 'edges': 717 assert len(values.shape) == 2, 'Values array must be 2d' 718 719 msg = 'Number of values must match number of elements' 720 assert values.shape[0] == N, msg 721 722 msg = 'Array must be N x 3' 723 assert values.shape[1] == 3, msg 724 725 self.edge_values = values 726 727 elif location == 'unique vertices': 728 assert len(values.shape) == 1 or allclose(values.shape[1:], 1),\ 729 'Values array must be 1d' 730 731 self.set_vertex_values(values.flat, indexes = indexes) 732 else: 733 if len(values.shape) == 1: 734 self.set_vertex_values(values, indexes = indexes) 735 #if indexes == None: 736 #Values are being specified once for each unique vertex 737 # msg = 'Number of values must match number of vertices' 738 # assert values.shape[0] == self.domain.coordinates.shape[0], msg 739 # self.set_vertex_values(values) 740 #else: 741 # for element_index, value in map(None, indexes, values): 742 # self.vertex_values[element_index, :] = value 743 744 elif len(values.shape) == 2: 745 #Vertex values are given as a triplet for each triangle 746 747 msg = 'Array must be N x 3' 748 assert values.shape[1] == 3, msg 749 750 if indexes == None: 751 self.vertex_values = values 752 else: 753 for element_index, value in map(None, indexes, values): 754 self.vertex_values[element_index] = value 755 else: 756 msg = 'Values array must be 1d or 2d' 757 raise msg 758 759 760 521 761 522 762 … … 729 969 730 970 971 972 731 973 class Conserved_quantity(Quantity): 732 974 """Class conserved quantity adds to Quantity: -
inundation/pyvolution/test_quantity.py
r1749 r1750 979 979 indexes = [1] 980 980 quantity.set_values(value, 981 982 981 location = 'centroids', 982 indexes = indexes) 983 983 #print "quantity.centroid_values",quantity.centroid_values 984 984 #print "quantity.get_values(location = 'centroids') ",\ -
inundation/pyvolution/util.py
r1743 r1750 125 125 if type(A) == ArrayType: 126 126 if A.typecode == typecode: 127 return array(A) 127 return array(A) #FIXME: Shouldn't this be just return A? 128 128 else: 129 129 return A.astype(typecode) -
inundation/wiki/future_directions.txt
r1749 r1750 156 156 157 157 158 Introduce create_quantity in domain.py: 159 It will make a new named instance and populate it by calling set_quantity 160 if desired. 161 Create_quantity would be called automatically by shallow_water. 162 163 158 164 Make stage appear as any other quantity: 159 165 Either … … 171 177 172 178 179 173 180 Boundary (Dirichlet): Think about specifying values by quantity name (and having defaults) 174 181 Dirichlet(stage = 1.0, ymomentum = 0.2)
Note: See TracChangeset
for help on using the changeset viewer.