Changeset 1237
- Timestamp:
- Apr 20, 2005, 5:41:03 PM (20 years ago)
- Location:
- inundation/ga/storm_surge
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
inundation/ga/storm_surge/pyvolution-parallel/domain.py
r1232 r1237 430 430 self.distribute_to_vertices_and_edges() 431 431 432 #Initialize boundary values 433 self.update_boundary() 432 434 433 435 #Or maybe restore from latest checkpoint … … 439 441 440 442 while True: 443 444 #Compute fluxes across each element edge 445 self.compute_fluxes() 446 447 #Update timestep to fit yieldstep and finaltime 448 self.update_timestep(yieldstep, finaltime) 449 450 #Update conserved quantities 451 self.update_conserved_quantities() 452 453 #Update vertex and edge values 454 self.distribute_to_vertices_and_edges() 455 441 456 #Update boundary values 442 457 self.update_boundary() 443 444 #Compute fluxes across each element edge445 self.compute_fluxes()446 447 #Update timestep to fit yieldstep and finaltime448 self.update_timestep(yieldstep, finaltime)449 450 #Update conserved quantities451 self.update_conserved_quantities()452 453 #Update vertex and edge values454 self.distribute_to_vertices_and_edges()455 458 456 459 #Update time -
inundation/ga/storm_surge/pyvolution-parallel/general_mesh.py
r1178 r1237 6 6 7 7 A triangular element is defined in terms of three vertex ids, 8 ordered counter clock-wise, 8 ordered counter clock-wise, 9 9 each corresponding to a given coordinate set. 10 10 Vertices from different elements can point to the same … … 12 12 13 13 Coordinate sets are implemented as an N x 2 Numeric array containing 14 x and y coordinates. 15 14 x and y coordinates. 15 16 16 17 17 To instantiate: … … 33 33 c = [2.0,0.0] 34 34 e = [2.0, 2.0] 35 35 36 36 points = [a, b, c, e] 37 triangles = [ [1,0,2], [1,2,3] ] #bac, bce 37 triangles = [ [1,0,2], [1,2,3] ] #bac, bce 38 38 mesh = Mesh(points, triangles) 39 39 40 40 #creates two triangles: bac and bce 41 41 42 42 Other: 43 43 44 44 In addition mesh computes an Nx6 array called vertex_coordinates. 45 This structure is derived from coordinates and contains for each 45 This structure is derived from coordinates and contains for each 46 46 triangle the three x,y coordinates at the vertices. 47 47 48 48 49 49 This is a cut down version of mesh from pyvolution\mesh.py … … 58 58 59 59 origin is a 3-tuple consisting of UTM zone, easting and northing. 60 If specified coordinates are assumed to be relative to this origin. 60 If specified coordinates are assumed to be relative to this origin. 61 61 """ 62 62 … … 67 67 68 68 if geo_reference is None: 69 self.geo_reference = Geo_reference(DEFAULT_ZONE,0.0,0.0) 69 self.geo_reference = Geo_reference(DEFAULT_ZONE,0.0,0.0) 70 70 else: 71 71 self.geo_reference = geo_reference … … 76 76 77 77 msg = 'Coordinates must an Mx2 Numeric array or a sequence of 2-tuples' 78 assert len(self.coordinates.shape) == 2, msg 78 assert len(self.coordinates.shape) == 2, msg 79 79 80 80 msg = 'Vertex indices reference non-existing coordinate sets' … … 84 84 #Register number of elements (N) 85 85 self.number_of_elements = N = self.triangles.shape[0] 86 87 #Allocate space for geometric quantities 86 87 #Allocate space for geometric quantities 88 88 self.normals = zeros((N, 6), Float) 89 89 self.areas = zeros(N, Float) … … 92 92 #Get x,y coordinates for all triangles and store 93 93 self.vertex_coordinates = V = self.compute_vertex_coordinates() 94 94 95 95 #Initialise each triangle 96 96 for i in range(N): 97 97 #if i % (N/10) == 0: print '(%d/%d)' %(i, N) 98 98 99 99 x0 = V[i, 0]; y0 = V[i, 1] 100 100 x1 = V[i, 2]; y1 = V[i, 3] 101 x2 = V[i, 4]; y2 = V[i, 5] 101 x2 = V[i, 4]; y2 = V[i, 5] 102 102 103 103 #Area … … 107 107 msg += ' is degenerate: area == %f' %self.areas[i] 108 108 assert self.areas[i] > 0.0, msg 109 109 110 110 111 111 #Normals … … 120 120 121 121 n0 = array([x2 - x1, y2 - y1]) 122 122 l0 = sqrt(sum(n0**2)) 123 123 124 124 n1 = array([x0 - x2, y0 - y2]) … … 137 137 n1[1], -n1[0], 138 138 n2[1], -n2[0]] 139 139 140 140 #Edgelengths 141 141 self.edgelengths[i, :] = [l0, l1, l2] 142 142 143 143 #Build vertex list 144 self.build_vertexlist() 145 144 self.build_vertexlist() 145 146 146 def __len__(self): 147 147 return self.number_of_elements … … 154 154 """Return all normal vectors. 155 155 Return normal vectors for all triangles as an Nx6 array 156 (ordered as x0, y0, x1, y1, x2, y2 for each triangle) 156 (ordered as x0, y0, x1, y1, x2, y2 for each triangle) 157 157 """ 158 158 return self.normals … … 163 163 Return value is the numeric array slice [x, y] 164 164 """ 165 return self.normals[i, 2*j:2*j+2] 166 167 168 165 return self.normals[i, 2*j:2*j+2] 166 167 168 169 169 def get_vertex_coordinates(self): 170 170 """Return all vertex coordinates. 171 171 Return all vertex coordinates for all triangles as an Nx6 array 172 (ordered as x0, y0, x1, y1, x2, y2 for each triangle) 172 (ordered as x0, y0, x1, y1, x2, y2 for each triangle) 173 173 """ 174 174 return self.vertex_coordinates … … 179 179 Return value is the numeric array slice [x, y] 180 180 """ 181 return self.vertex_coordinates[i, 2*j:2*j+2] 181 return self.vertex_coordinates[i, 2*j:2*j+2] 182 182 183 183 … … 189 189 #FIXME: Perhaps they should be ordered as in obj files?? 190 190 #See quantity.get_vertex_values 191 191 192 192 from Numeric import zeros, Float 193 193 194 194 N = self.number_of_elements 195 vertex_coordinates = zeros((N, 6), Float) 195 vertex_coordinates = zeros((N, 6), Float) 196 196 197 197 for i in range(N): … … 203 203 204 204 return vertex_coordinates 205 205 206 206 def get_vertices(self, indexes=None): 207 207 """Get connectivity 208 208 indexes is the set of element ids of interest 209 209 """ 210 210 211 211 from Numeric import take 212 212 213 213 if (indexes == None): 214 214 indexes = range(len(self)) #len(self)=number of elements 215 215 216 216 return take(self.triangles, indexes) 217 217 … … 220 220 unique_verts = {} 221 221 for triangle in triangles: 222 unique_verts[triangle[0]] = 0 223 unique_verts[triangle[1]] = 0 222 unique_verts[triangle[0]] = 0 223 unique_verts[triangle[1]] = 0 224 224 unique_verts[triangle[2]] = 0 225 return unique_verts.keys() 226 225 return unique_verts.keys() 226 227 227 def build_vertexlist(self): 228 228 """Build vertexlist index by vertex ids and for each entry (point id) … … 231 231 232 232 Preconditions: 233 self.coordinates and self.triangles are defined 234 233 self.coordinates and self.triangles are defined 234 235 235 Postcondition: 236 236 self.vertexlist is built … … 242 242 a = self.triangles[i, 0] 243 243 b = self.triangles[i, 1] 244 c = self.triangles[i, 2] 244 c = self.triangles[i, 2] 245 245 246 246 #Register the vertices v as lists of … … 251 251 vertexlist[v] = [] 252 252 253 vertexlist[v].append( (i, vertex_id) ) 253 vertexlist[v].append( (i, vertex_id) ) 254 254 255 255 self.vertexlist = vertexlist 256 256 257 257 258 258 def get_extent(self): … … 264 264 X = C[:,0:6:2].copy() 265 265 Y = C[:,1:6:2].copy() 266 266 267 267 xmin = min(X.flat) 268 268 xmax = max(X.flat) 269 269 ymin = min(Y.flat) 270 ymax = max(Y.flat) 271 270 ymax = max(Y.flat) 271 272 272 return xmin, xmax, ymin, ymax 273 273 … … 275 275 def get_area(self): 276 276 """Return total area of mesh 277 278 279 return sum(self.areas) 280 277 """ 278 279 return sum(self.areas) 280 -
inundation/ga/storm_surge/pyvolution-parallel/mesh.py
r1193 r1237 67 67 """ 68 68 69 69 70 70 71 71 from Numeric import array, zeros, Int, Float, maximum, sqrt, sum … … 113 113 #a triangle to the midpoint of the side of the triangle 114 114 #closest to the centroid 115 115 d0 = sqrt(sum( (centroid-m0)**2 )) 116 116 d1 = sqrt(sum( (centroid-m1)**2 )) 117 117 d2 = sqrt(sum( (centroid-m2)**2 )) … … 129 129 130 130 self.radii[i]=self.areas[i]/(2*(a+b+c)) 131 131 132 132 133 133 #Initialise Neighbours (-1 means that it is a boundary neighbour) … … 446 446 #Note: Could be arbitrary, but nice to have 447 447 #a unique way of selecting 448 449 448 dist_A = sqrt(sum( (A-pmin)**2 )) 449 dist_B = sqrt(sum( (B-pmin)**2 )) 450 450 451 451 #Find minimal point … … 584 584 # assert self.neighbours[id,edge] < 0 585 585 # 586 587 588 586 #NOTE (Ole): I reckon this was resolved late 2004? 587 # 588 #See domain.set_boundary 589 589 590 590 -
inundation/ga/storm_surge/pyvolution-parallel/quantity.py
r1011 r1237 6 6 7 7 domain: Associated domain structure. Required. 8 8 9 9 vertex_values: N x 3 array of values at each vertex for each element. 10 10 Default None … … 28 28 29 29 if vertex_values is None: 30 N = domain.number_of_elements 30 N = domain.number_of_elements 31 31 self.vertex_values = zeros((N, 3), Float) 32 else: 32 else: 33 33 self.vertex_values = array(vertex_values).astype(Float) 34 34 … … 36 36 assert V == 3,\ 37 37 'Three vertex values per element must be specified' 38 38 39 39 40 40 msg = 'Number of vertex values (%d) must be consistent with'\ … … 42 42 msg += 'number of elements in specified domain (%d).'\ 43 43 %domain.number_of_elements 44 44 45 45 assert N == domain.number_of_elements, msg 46 46 47 self.domain = domain 47 self.domain = domain 48 48 49 49 #Allocate space for other quantities 50 50 self.centroid_values = zeros(N, Float) 51 self.edge_values = zeros((N, 3), Float) 51 self.edge_values = zeros((N, 3), Float) 52 52 53 53 #Intialise centroid and edge_values … … 56 56 def __len__(self): 57 57 return self.centroid_values.shape[0] 58 58 59 59 def interpolate(self): 60 60 """Compute interpolated values at edges and centroid … … 62 62 """ 63 63 64 N = self.vertex_values.shape[0] 64 N = self.vertex_values.shape[0] 65 65 for i in range(N): 66 66 v0 = self.vertex_values[i, 0] 67 67 v1 = self.vertex_values[i, 1] 68 68 v2 = self.vertex_values[i, 2] 69 69 70 70 self.centroid_values[i] = (v0 + v1 + v2)/3 71 71 … … 77 77 #(either from this module or C-extension) 78 78 interpolate_from_vertices_to_edges(self) 79 80 79 80 81 81 82 def set_values(self, X, location='vertices', indexes = None): 82 83 """Set values for quantity … … 96 97 If values are described a function, it will be evaluated at 97 98 specified points 98 99 99 100 If indexex is not 'unique vertices' Indexes is the set of element ids 100 101 that the operation applies to. 101 102 If indexex is 'unique vertices' Indexes is the set of vertex ids 102 103 that the operation applies to. 103 104 104 105 105 106 If selected location is vertices, values for centroid and edges 106 107 will be assigned interpolated values. … … 115 116 if X is None: 116 117 msg = 'Given values are None' 117 raise msg 118 raise msg 118 119 119 120 import types, Numeric … … 122 123 'Indices must be a list or None' 123 124 124 125 125 126 if callable(X): 126 127 #Use function specific method 127 self.set_function_values(X, location, indexes = indexes) 128 self.set_function_values(X, location, indexes = indexes) 128 129 elif type(X) in [types.FloatType, types.IntType, types.LongType]: 129 130 if location == 'centroids': … … 134 135 for i in indexes: 135 136 self.centroid_values[i,:] = X 136 137 137 138 elif location == 'edges': 138 139 if (indexes == None): … … 142 143 for i in indexes: 143 144 self.edge_values[i,:] = X 144 145 145 146 elif location == 'unique vertices': 146 147 if (indexes == None): … … 151 152 for unique_vert_id in indexes: 152 153 triangles = self.domain.vertexlist[unique_vert_id] 153 154 154 155 #In case there are unused points 155 if triangles is None: continue 156 if triangles is None: continue 156 157 157 158 #Go through all triangle, vertex pairs … … 159 160 for triangle_id, vertex_id in triangles: 160 161 self.vertex_values[triangle_id, vertex_id] = X 161 162 162 163 #Intialise centroid and edge_values 163 164 self.interpolate() … … 168 169 #Brute force 169 170 for i_vertex in indexes: 170 self.vertex_values[i_vertex,:] = X 171 self.vertex_values[i_vertex,:] = X 171 172 172 173 else: … … 177 178 #Intialise centroid and edge_values 178 179 self.interpolate() 179 180 180 181 if location == 'centroids': 181 182 #Extrapolate 1st order - to capture notion of area being specified 182 self.extrapolate_first_order() 183 183 self.extrapolate_first_order() 184 185 184 186 def get_values(self, location='vertices', indexes = None): 185 187 """get values for quantity … … 197 199 (N if indexes = None). Each value will be a list of the three 198 200 vertex values for this quantity. 199 201 200 202 Indexes is the set of element ids that the operation applies to. 201 203 202 204 """ 203 205 from Numeric import take … … 205 207 if location not in ['vertices', 'centroids', 'edges', 'unique vertices']: 206 208 msg = 'Invalid location: %s' %location 207 raise msg 208 209 raise msg 210 209 211 import types, Numeric 210 212 assert type(indexes) in [types.ListType, types.NoneType, 211 213 Numeric.ArrayType],\ 212 214 'Indices must be a list or None' 213 215 214 216 if location == 'centroids': 215 217 if (indexes == None): 216 218 indexes = range(len(self)) 217 return take(self.centroid_values,indexes) 219 return take(self.centroid_values,indexes) 218 220 elif location == 'edges': 219 221 if (indexes == None): 220 222 indexes = range(len(self)) 221 return take(self.edge_values,indexes) 223 return take(self.edge_values,indexes) 222 224 elif location == 'unique vertices': 223 225 if (indexes == None): … … 227 229 for unique_vert_id in indexes: 228 230 triangles = self.domain.vertexlist[unique_vert_id] 229 231 230 232 #In case there are unused points 231 if triangles is None: 232 msg = 'Unique vertex not associated with triangles' 233 raise msg 233 if triangles is None: 234 msg = 'Unique vertex not associated with triangles' 235 raise msg 234 236 235 237 # Go through all triangle, vertex pairs … … 280 282 raise 'Not implemented: %s' %location 281 283 282 283 284 def set_array_values(self, values, location='vertices', indexes = None): 284 285 """Set values for quantity … … 288 289 Permissible options are: vertices, edges, centroid, unique vertices 289 290 Default is "vertices" 290 291 291 292 indexes - if this action is carried out on a subset of 292 293 elements or unique vertices 293 294 The element/unique vertex indexes are specified here. 294 295 295 296 In case of location == 'centroid' the dimension values must 296 297 be a list of a Numerical array of length N, N being the number … … 315 316 indexes = array(indexes).astype(Int) 316 317 msg = 'Number of values must match number of indexes' 317 assert values.shape[0] == indexes.shape[0], msg 318 318 assert values.shape[0] == indexes.shape[0], msg 319 319 320 N = self.centroid_values.shape[0] 320 321 321 322 if location == 'centroids': 322 323 assert len(values.shape) == 1, 'Values array must be 1d' … … 325 326 msg = 'Number of values must match number of elements' 326 327 assert values.shape[0] == N, msg 327 328 328 329 self.centroid_values = values 329 330 else: 330 331 msg = 'Number of values must match number of indexes' 331 332 assert values.shape[0] == indexes.shape[0], msg 332 333 333 334 #Brute force 334 335 for i in range(len(indexes)): 335 336 self.centroid_values[indexes[i]] = values[i] 336 337 337 338 elif location == 'edges': 338 339 assert len(values.shape) == 2, 'Values array must be 2d' … … 340 341 msg = 'Number of values must match number of elements' 341 342 assert values.shape[0] == N, msg 342 343 msg = 'Array must be N x 3' 343 344 msg = 'Array must be N x 3' 344 345 assert values.shape[1] == 3, msg 345 346 346 347 self.edge_values = values 347 348 348 349 elif location == 'unique vertices': 349 350 assert len(values.shape) == 1 or allclose(values.shape[1:], 1),\ … … 360 361 # self.set_vertex_values(values) 361 362 #else: 362 # for element_index, value in map(None, indexes, values): 363 # for element_index, value in map(None, indexes, values): 363 364 # self.vertex_values[element_index, :] = value 364 365 365 366 elif len(values.shape) == 2: 366 367 #Vertex values are given as a triplet for each triangle 367 368 msg = 'Array must be N x 3' 368 369 msg = 'Array must be N x 3' 369 370 assert values.shape[1] == 3, msg 370 371 371 372 if indexes == None: 372 373 self.vertex_values = values 373 374 else: 374 for element_index, value in map(None, indexes, values): 375 for element_index, value in map(None, indexes, values): 375 376 self.vertex_values[element_index] = value 376 else: 377 else: 377 378 msg = 'Values array must be 1d or 2d' 378 379 raise msg 379 380 381 # FIXME have a get_vertex_values as well, so the 'stage' quantity can be 382 # set, based on the elevation 380 381 382 #FIXME have a get_vertex_values as well, so the 'stage' quantity can be 383 # set, based on the elevation 384 383 385 def set_vertex_values(self, A, indexes = None): 384 386 """Set vertex values for all unique vertices based on input array A … … 387 389 one value for each row in vertexlist. 388 390 389 indexes is the list of vertex_id's that will be set. 391 indexes is the list of vertex_id's that will be set. 390 392 391 393 Note: Functions not allowed … … 409 411 for i_index,unique_vert_id in enumerate(vertex_list): 410 412 triangles = self.domain.vertexlist[unique_vert_id] 411 413 412 414 if triangles is None: continue #In case there are unused points 413 415 … … 416 418 for triangle_id, vertex_id in triangles: 417 419 self.vertex_values[triangle_id, vertex_id] = A[i_index] 418 420 419 421 #Intialise centroid and edge_values 420 422 self.interpolate() 421 423 422 424 def smooth_vertex_values(self, value_array='field_values', 423 425 precision = None): … … 432 434 from Numeric import concatenate, zeros, Float, Int, array, reshape 433 435 434 436 435 437 A,V = self.get_vertex_values(xy=False, 436 438 value_array=value_array, … … 450 452 elif value_array == 'conserved_quantities': 451 453 Volume.interpolate_conserved_quantities() 452 453 454 #Method for outputting model results 455 #FIXME: Split up into geometric and numeric stuff. 456 #FIXME: Geometric (X,Y,V) should live in mesh.py 457 #FIXME: STill remember to move XY to mesh 454 455 458 456 def get_vertex_values(self, 459 xy=True, 457 xy=True, 460 458 smooth = None, 461 459 precision = None, … … 465 463 The vertex values are returned as one sequence in the 1D float array A. 466 464 If requested the coordinates will be returned in 1D arrays X and Y. 467 465 468 466 The connectivity is represented as an integer array, V, of dimension 469 467 M x 3, where M is the number of volumes. Each row has three indices … … 474 472 reduction operator. In this case vertex coordinates will be 475 473 de-duplicated. 476 474 477 475 If no smoothings is required, vertex coordinates and values will 478 476 be aggregated as a concatenation of values at 479 477 vertices 0, vertices 1 and vertices 2 480 478 481 479 482 480 Calling convention 483 481 if xy is True: 484 482 X,Y,A,V = get_vertex_values 485 483 else: 486 A,V = get_vertex_values 487 488 """ 484 A,V = get_vertex_values 485 """ 486 #Method for outputting model results 487 #FIXME: Split up into geometric and numeric stuff. 488 #FIXME: Geometric (X,Y,V) should live in mesh.py 489 #FIXME: STill remember to move XY to mesh 489 490 490 491 from Numeric import concatenate, zeros, Float, Int, array, reshape 491 492 492 493 493 if smooth is None: … … 499 499 if reduction is None: 500 500 reduction = self.domain.reduction 501 501 502 502 #Create connectivity 503 503 504 504 if smooth == True: 505 505 … … 511 511 for k in range(N): 512 512 L = self.domain.vertexlist[k] 513 513 514 514 #Go through all triangle, vertex pairs 515 515 #contributing to vertex k and register vertex value 516 516 517 517 if L is None: continue #In case there are unused points 518 518 519 519 contributions = [] 520 520 for volume_id, vertex_id in L: … … 522 522 contributions.append(v) 523 523 524 A[k] = reduction(contributions) 524 A[k] = reduction(contributions) 525 525 526 526 … … 528 528 X = self.domain.coordinates[:,0].astype(precision) 529 529 Y = self.domain.coordinates[:,1].astype(precision) 530 530 531 531 return X, Y, A, V 532 532 else: … … 540 540 M = 3*m #Total number of unique vertices 541 541 V = reshape(array(range(M)).astype(Int), (m,3)) 542 542 543 543 A = self.vertex_values.flat 544 544 545 #Do vertex coordinates 546 if xy is True: 545 #Do vertex coordinates 546 if xy is True: 547 547 C = self.domain.get_vertex_coordinates() 548 548 549 549 X = C[:,0:6:2].copy() 550 Y = C[:,1:6:2].copy() 551 552 return X.flat, Y.flat, A, V 550 Y = C[:,1:6:2].copy() 551 552 return X.flat, Y.flat, A, V 553 553 else: 554 554 return A, V 555 555 556 557 556 def extrapolate_first_order(self): 558 557 """Extrapolate conserved quantities from centroid to … … 560 559 first order scheme. 561 560 """ 562 561 563 562 qc = self.centroid_values 564 563 qv = self.vertex_values … … 566 565 for i in range(3): 567 566 qv[:,i] = qc 568 567 569 568 570 569 def get_integral(self): 571 570 """Compute the integral of quantity across entire domain 572 573 574 571 """ 572 integral = 0 573 for k in range(self.domain.number_of_elements): 575 574 area = self.domain.areas[k] 576 qc = self.centroid_values[k] 575 qc = self.centroid_values[k] 577 576 integral += qc*area 578 579 return integral 580 577 578 return integral 579 581 580 582 581 class Conserved_quantity(Quantity): … … 590 589 def __init__(self, domain, vertex_values=None): 591 590 Quantity.__init__(self, domain, vertex_values) 592 591 593 592 from Numeric import zeros, Float 594 593 … … 603 602 self.explicit_update = zeros(N, Float ) 604 603 self.semi_implicit_update = zeros(N, Float ) 605 604 606 605 607 606 def update(self, timestep): … … 615 614 #(either from this module or C-extension) 616 615 return compute_gradients(self) 617 616 618 617 619 618 def limit(self): … … 621 620 #(either from this module or C-extension) 622 621 limit(self) 623 624 622 623 625 624 def extrapolate_second_order(self): 626 625 #Call correct module function … … 629 628 630 629 631 def update(quantity, timestep): 630 def update(quantity, timestep): 632 631 """Update centroid values based on values stored in 633 632 explicit_update and semi_implicit_update as well as given timestep … … 642 641 domain.quantities['ymomentum'].explicit_update = ... 643 642 644 643 645 644 646 645 Explicit terms must have the form 647 646 648 647 G(q, t) 649 648 650 649 and explicit scheme is 651 650 652 651 q^{(n+1}) = q^{(n)} + delta_t G(q^{n}, n delta_t) 653 652 654 653 655 654 Semi implicit forcing terms are assumed to have the form 656 655 657 656 G(q, t) = H(q, t) q 658 657 659 658 and the semi implicit scheme will then be 660 659 661 660 q^{(n+1}) = q^{(n)} + delta_t H(q^{n}, n delta_t) q^{(n+1}) 662 661 663 662 664 663 """ 665 664 666 665 from Numeric import sum, equal, ones, Float 667 666 668 667 N = quantity.centroid_values.shape[0] 669 668 … … 673 672 674 673 for k in range(N): 675 x = quantity.centroid_values[k] 674 x = quantity.centroid_values[k] 676 675 if x == 0.0: 677 676 #FIXME: Is this right 678 quantity.semi_implicit_update[k] = 0.0 679 else: 680 quantity.semi_implicit_update[k] /= x 681 677 quantity.semi_implicit_update[k] = 0.0 678 else: 679 quantity.semi_implicit_update[k] /= x 680 682 681 #Explicit updates 683 682 quantity.centroid_values += timestep*quantity.explicit_update 684 683 685 684 #Semi implicit updates 686 685 denominator = ones(N, Float)-timestep*quantity.semi_implicit_update … … 702 701 q1 = quantity.vertex_values[k, 1] 703 702 q2 = quantity.vertex_values[k, 2] 704 703 705 704 quantity.edge_values[k, 0] = 0.5*(q1+q2) 706 quantity.edge_values[k, 1] = 0.5*(q0+q2) 705 quantity.edge_values[k, 1] = 0.5*(q0+q2) 707 706 quantity.edge_values[k, 2] = 0.5*(q0+q1) 708 707 709 708 710 709 711 def extrapolate_second_order(quantity): 710 def extrapolate_second_order(quantity): 712 711 """Extrapolate conserved quantities from centroid to 713 712 vertices for each volume using 714 713 second order scheme. 715 714 """ 716 715 717 716 a, b = quantity.compute_gradients() 718 717 … … 720 719 qc = quantity.centroid_values 721 720 qv = quantity.vertex_values 722 721 723 722 #Check each triangle 724 723 for k in range(quantity.domain.number_of_elements): 725 #Centroid coordinates 724 #Centroid coordinates 726 725 x, y = quantity.domain.centroid_coordinates[k] 727 726 728 727 #vertex coordinates 729 728 x0, y0, x1, y1, x2, y2 = X[k,:] 730 729 731 730 #Extrapolate 732 731 qv[k,0] = qc[k] + a[k]*(x0-x) + b[k]*(y0-y) 733 732 qv[k,1] = qc[k] + a[k]*(x1-x) + b[k]*(y1-y) 734 qv[k,2] = qc[k] + a[k]*(x2-x) + b[k]*(y2-y) 735 736 737 def compute_gradients(quantity): 733 qv[k,2] = qc[k] + a[k]*(x2-x) + b[k]*(y2-y) 734 735 736 def compute_gradients(quantity): 738 737 """Compute gradients of triangle surfaces defined by centroids of 739 738 neighbouring volumes. … … 744 743 from Numeric import zeros, Float 745 744 from util import gradient 746 745 747 746 centroid_coordinates = quantity.domain.centroid_coordinates 748 surrogate_neighbours = quantity.domain.surrogate_neighbours 749 centroid_values = quantity.centroid_values 750 number_of_boundaries = quantity.domain.number_of_boundaries 751 747 surrogate_neighbours = quantity.domain.surrogate_neighbours 748 centroid_values = quantity.centroid_values 749 number_of_boundaries = quantity.domain.number_of_boundaries 750 752 751 N = centroid_values.shape[0] 753 752 754 753 a = zeros(N, Float) 755 754 b = zeros(N, Float) 756 755 757 756 for k in range(N): 758 757 if number_of_boundaries[k] < 2: 759 758 #Two or three true neighbours 760 759 761 #Get indices of neighbours (or self when used as surrogate) 760 #Get indices of neighbours (or self when used as surrogate) 762 761 k0, k1, k2 = surrogate_neighbours[k,:] 763 762 764 #Get data 763 #Get data 765 764 q0 = centroid_values[k0] 766 765 q1 = centroid_values[k1] 767 q2 = centroid_values[k2] 766 q2 = centroid_values[k2] 768 767 769 768 x0, y0 = centroid_coordinates[k0] #V0 centroid … … 773 772 #Gradient 774 773 a[k], b[k] = gradient(x0, y0, x1, y1, x2, y2, q0, q1, q2) 775 774 776 775 elif number_of_boundaries[k] == 2: 777 776 #One true neighbour … … 789 788 790 789 x0, y0 = centroid_coordinates[k0] #V0 centroid 791 x1, y1 = centroid_coordinates[k1] #V1 centroid 790 x1, y1 = centroid_coordinates[k1] #V1 centroid 792 791 793 792 #Gradient … … 798 797 799 798 else: 800 #No true neighbours - 799 #No true neighbours - 801 800 #Fall back to first order scheme 802 801 pass 803 804 802 803 805 804 return a, b 806 807 808 809 def limit(quantity): 805 806 807 808 def limit(quantity): 810 809 """Limit slopes for each volume to eliminate artificial variance 811 810 introduced by e.g. second order extrapolator 812 811 813 812 This is an unsophisticated limiter as it does not take into 814 813 account dependencies among quantities. 815 814 816 815 precondition: 817 816 vertex values are estimated from gradient … … 823 822 824 823 N = quantity.domain.number_of_elements 825 824 826 825 beta_w = quantity.domain.beta_w 827 826 828 827 qc = quantity.centroid_values 829 828 qv = quantity.vertex_values 830 829 831 830 #Find min and max of this and neighbour's centroid values 832 831 qmax = zeros(qc.shape, Float) 833 qmin = zeros(qc.shape, Float) 834 832 qmin = zeros(qc.shape, Float) 833 835 834 for k in range(N): 836 835 qmax[k] = qmin[k] = qc[k] … … 839 838 if n >= 0: 840 839 qn = qc[n] #Neighbour's centroid value 841 840 842 841 qmin[k] = min(qmin[k], qn) 843 842 qmax[k] = max(qmax[k], qn) 844 845 843 844 846 845 #Diffences between centroids and maxima/minima 847 dqmax = qmax - qc 846 dqmax = qmax - qc 848 847 dqmin = qmin - qc 849 848 850 849 #Deltas between vertex and centroid values 851 850 dq = zeros(qv.shape, Float) … … 853 852 dq[:,i] = qv[:,i] - qc 854 853 855 #Phi limiter 854 #Phi limiter 856 855 for k in range(N): 857 856 858 857 #Find the gradient limiter (phi) across vertices 859 858 phi = 1.0 … … 862 861 if (dq[k,i] > 0): r = dqmax[k]/dq[k,i] 863 862 if (dq[k,i] < 0): r = dqmin[k]/dq[k,i] 864 865 phi = min( min(r*beta_w, 1), phi ) 863 864 phi = min( min(r*beta_w, 1), phi ) 866 865 867 866 #Then update using phi limiter 868 for i in range(3): 867 for i in range(3): 869 868 qv[k,i] = qc[k] + phi*dq[k,i] 870 869 … … 874 873 if compile.can_use_C_extension('quantity_ext.c'): 875 874 #Replace python version with c implementations 876 875 877 876 from quantity_ext import limit, compute_gradients,\ 878 extrapolate_second_order, interpolate_from_vertices_to_edges, update 879 877 extrapolate_second_order, interpolate_from_vertices_to_edges, update
Note: See TracChangeset
for help on using the changeset viewer.