Changeset 4769
- Timestamp:
- Oct 30, 2007, 5:13:17 PM (17 years ago)
- Location:
- anuga_core/source/anuga
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
anuga_core/source/anuga/abstract_2d_finite_volumes/quantity.py
r4768 r4769 332 332 333 333 334 # General input checks334 # General input checks 335 335 L = [numeric, quantity, function, geospatial_data, points, filename] 336 336 msg = 'Exactly one of the arguments '+\ … … 360 360 361 361 362 # Determine which 'set_values_from_...' to use362 # Determine which 'set_values_from_...' to use 363 363 364 364 if numeric is not None: … … 1337 1337 1338 1338 1339 def update(quantity, timestep):1340 """Update centroid values based on values stored in1341 explicit_update and semi_implicit_update as well as given timestep1342 1343 Function implementing forcing terms must take on argument1344 which is the domain and they must update either explicit1345 or implicit updates, e,g,:1346 1347 def gravity(domain):1348 ....1349 domain.quantities['xmomentum'].explicit_update = ...1350 domain.quantities['ymomentum'].explicit_update = ...1351 1352 1353 1354 Explicit terms must have the form1355 1356 G(q, t)1357 1358 and explicit scheme is1359 1360 q^{(n+1}) = q^{(n)} + delta_t G(q^{n}, n delta_t)1361 1362 1363 Semi implicit forcing terms are assumed to have the form1364 1365 G(q, t) = H(q, t) q1366 1367 and the semi implicit scheme will then be1368 1369 q^{(n+1}) = q^{(n)} + delta_t H(q^{n}, n delta_t) q^{(n+1})1370 1371 1372 """1373 1374 from Numeric import sum, equal, ones, exp, Float1375 1376 N = quantity.centroid_values.shape[0]1377 1378 1379 # Divide H by conserved quantity to obtain G (see docstring above)1380 1381 1382 for k in range(N):1383 x = quantity.centroid_values[k]1384 if x == 0.0:1385 #FIXME: Is this right1386 quantity.semi_implicit_update[k] = 0.01387 else:1388 quantity.semi_implicit_update[k] /= x1389 1390 1391 # Semi implicit updates1392 denominator = ones(N, Float)-timestep*quantity.semi_implicit_update1393 1394 if sum(less(denominator, 1.0)) > 0.0:1395 msg = 'denominator < 1.0 in semi implicit update. Call Stephen :-)'1396 raise msg1397 1398 if sum(equal(denominator, 0.0)) > 0.0:1399 msg = 'Zero division in semi implicit update. Call Stephen :-)'1400 raise msg1401 else:1402 #Update conserved_quantities from semi implicit updates1403 quantity.centroid_values /= denominator1404 1405 # quantity.centroid_values = exp(timestep*quantity.semi_implicit_update)*quantity.centroid_values1406 1407 #Explicit updates1408 quantity.centroid_values += timestep*quantity.explicit_update1409 1410 def interpolate_from_vertices_to_edges(quantity):1411 """Compute edge values from vertex values using linear interpolation1412 """1413 1414 for k in range(quantity.vertex_values.shape[0]):1415 q0 = quantity.vertex_values[k, 0]1416 q1 = quantity.vertex_values[k, 1]1417 q2 = quantity.vertex_values[k, 2]1418 1419 quantity.edge_values[k, 0] = 0.5*(q1+q2)1420 quantity.edge_values[k, 1] = 0.5*(q0+q2)1421 quantity.edge_values[k, 2] = 0.5*(q0+q1)1422 1423 1424 1425 def backup_centroid_values(quantity):1426 """Copy centroid values to backup array"""1427 1428 qc = quantity.centroid_values1429 qb = quantity.centroid_backup_values1430 1431 #Check each triangle1432 for k in range(len(quantity.domain)):1433 qb[k] = qc[k]1434 1435 1436 def saxpy_centroid_values(quantity,a,b):1437 """saxpy operation between centroid value and backup"""1438 1439 qc = quantity.centroid_values1440 qb = quantity.centroid_backup_values1441 1442 #Check each triangle1443 for k in range(len(quantity.domain)):1444 qc[k] = a*qc[k]+b*qb[k]1445 1446 1447 def compute_gradients(quantity):1448 """Compute gradients of triangle surfaces defined by centroids of1449 neighbouring volumes.1450 If one edge is on the boundary, use own centroid as neighbour centroid.1451 If two or more are on the boundary, fall back to first order scheme.1452 """1453 1454 from Numeric import zeros, Float1455 from utilitites.numerical_tools import gradient1456 1457 centroid_coordinates = quantity.domain.centroid_coordinates1458 surrogate_neighbours = quantity.domain.surrogate_neighbours1459 centroid_values = quantity.centroid_values1460 number_of_boundaries = quantity.domain.number_of_boundaries1461 1462 N = centroid_values.shape[0]1463 1464 a = zeros(N, Float)1465 b = zeros(N, Float)1466 1467 for k in range(N):1468 if number_of_boundaries[k] < 2:1469 #Two or three true neighbours1470 1471 #Get indices of neighbours (or self when used as surrogate)1472 k0, k1, k2 = surrogate_neighbours[k,:]1473 1474 #Get data1475 q0 = centroid_values[k0]1476 q1 = centroid_values[k1]1477 q2 = centroid_values[k2]1478 1479 x0, y0 = centroid_coordinates[k0] #V0 centroid1480 x1, y1 = centroid_coordinates[k1] #V1 centroid1481 x2, y2 = centroid_coordinates[k2] #V2 centroid1482 1483 #Gradient1484 a[k], b[k] = gradient(x0, y0, x1, y1, x2, y2, q0, q1, q2)1485 1486 elif number_of_boundaries[k] == 2:1487 #One true neighbour1488 1489 #Get index of the one neighbour1490 for k0 in surrogate_neighbours[k,:]:1491 if k0 != k: break1492 assert k0 != k1493 1494 k1 = k #self1495 1496 #Get data1497 q0 = centroid_values[k0]1498 q1 = centroid_values[k1]1499 1500 x0, y0 = centroid_coordinates[k0] #V0 centroid1501 x1, y1 = centroid_coordinates[k1] #V1 centroid1502 1503 #Gradient1504 a[k], b[k] = gradient2(x0, y0, x1, y1, q0, q1)1505 else:1506 #No true neighbours -1507 #Fall back to first order scheme1508 pass1509 1510 1511 return a, b1512 1513 1514 1515 def limit(quantity):1516 """Limit slopes for each volume to eliminate artificial variance1517 introduced by e.g. second order extrapolator1518 1519 This is an unsophisticated limiter as it does not take into1520 account dependencies among quantities.1521 1522 precondition:1523 vertex values are estimated from gradient1524 postcondition:1525 vertex values are updated1526 """1527 1528 from Numeric import zeros, Float1529 1530 N = quantity.domain.number_of_nodes1531 1532 beta_w = quantity.domain.beta_w1533 1534 qc = quantity.centroid_values1535 qv = quantity.vertex_values1536 1537 #Find min and max of this and neighbour's centroid values1538 qmax = zeros(qc.shape, Float)1539 qmin = zeros(qc.shape, Float)1540 1541 for k in range(N):1542 qmax[k] = qc[k]1543 qmin[k] = qc[k]1544 for i in range(3):1545 n = quantity.domain.neighbours[k,i]1546 if n >= 0:1547 qn = qc[n] #Neighbour's centroid value1548 1549 qmin[k] = min(qmin[k], qn)1550 qmax[k] = max(qmax[k], qn)1551 qmax[k] = min(qmax[k], 2.0*qc[k])1552 qmin[k] = max(qmin[k], 0.5*qc[k])1553 1554 1555 #Diffences between centroids and maxima/minima1556 dqmax = qmax - qc1557 dqmin = qmin - qc1558 1559 #Deltas between vertex and centroid values1560 dq = zeros(qv.shape, Float)1561 for i in range(3):1562 dq[:,i] = qv[:,i] - qc1563 1564 #Phi limiter1565 for k in range(N):1566 1567 #Find the gradient limiter (phi) across vertices1568 phi = 1.01569 for i in range(3):1570 r = 1.01571 if (dq[k,i] > 0): r = dqmax[k]/dq[k,i]1572 if (dq[k,i] < 0): r = dqmin[k]/dq[k,i]1573 1574 phi = min( min(r*beta_w, 1), phi )1575 1576 #Then update using phi limiter1577 for i in range(3):1578 qv[k,i] = qc[k] + phi*dq[k,i]1579 1580 1581 1339 1582 1340 from anuga.utilities import compile 1583 if compile.can_use_C_extension('quantity_ext.c'): 1584 # Replace python version with c implementations1341 if compile.can_use_C_extension('quantity_ext.c'): 1342 # Underlying C implementations can be accessed 1585 1343 1586 1344 from quantity_ext import average_vertex_values, backup_centroid_values, \ … … 1588 1346 1589 1347 from quantity_ext import compute_gradients, limit,\ 1590 extrapolate_second_order, interpolate_from_vertices_to_edges, update 1348 extrapolate_second_order, interpolate_from_vertices_to_edges, update 1349 else: 1350 msg = 'C implementations could not be accessed by %s.\n ' %__file__ 1351 msg += 'Make sure compile_all.py has been run as described in ' 1352 msg += 'the ANUGA installation guide.' 1353 raise Exception, msg 1354 1355 1356 -
anuga_core/source/anuga/abstract_2d_finite_volumes/quantity_ext.c
r4728 r4769 288 288 // Gateways to Python 289 289 PyObject *update(PyObject *self, PyObject *args) { 290 // FIXME (Ole): It would be great to turn this text into a Python DOC string 291 292 /*"""Update centroid values based on values stored in 293 explicit_update and semi_implicit_update as well as given timestep 294 295 Function implementing forcing terms must take on argument 296 which is the domain and they must update either explicit 297 or implicit updates, e,g,: 298 299 def gravity(domain): 300 .... 301 domain.quantities['xmomentum'].explicit_update = ... 302 domain.quantities['ymomentum'].explicit_update = ... 303 304 305 306 Explicit terms must have the form 307 308 G(q, t) 309 310 and explicit scheme is 311 312 q^{(n+1}) = q^{(n)} + delta_t G(q^{n}, n delta_t) 313 314 315 Semi implicit forcing terms are assumed to have the form 316 317 G(q, t) = H(q, t) q 318 319 and the semi implicit scheme will then be 320 321 q^{(n+1}) = q^{(n)} + delta_t H(q^{n}, n delta_t) q^{(n+1}) 322 323 */ 290 324 291 325 PyObject *quantity; … … 397 431 398 432 PyObject *interpolate_from_vertices_to_edges(PyObject *self, PyObject *args) { 399 433 // 434 //Compute edge values from vertex values using linear interpolation 435 // 436 400 437 PyObject *quantity; 401 438 PyArrayObject *vertex_values, *edge_values; … … 476 513 477 514 PyObject *compute_gradients(PyObject *self, PyObject *args) { 515 //"""Compute gradients of triangle surfaces defined by centroids of 516 //neighbouring volumes. 517 //If one edge is on the boundary, use own centroid as neighbour centroid. 518 //If two or more are on the boundary, fall back to first order scheme. 519 //""" 520 478 521 479 522 PyObject *quantity, *domain, *R; … … 650 693 651 694 PyObject *limit(PyObject *self, PyObject *args) { 695 //Limit slopes for each volume to eliminate artificial variance 696 //introduced by e.g. second order extrapolator 697 698 //This is an unsophisticated limiter as it does not take into 699 //account dependencies among quantities. 700 701 //precondition: 702 // vertex values are estimated from gradient 703 //postcondition: 704 // vertex values are updated 705 // 652 706 653 707 PyObject *quantity, *domain, *Tmp; -
anuga_core/source/anuga/shallow_water/shallow_water_domain.py
r4754 r4769 74 74 """ 75 75 76 # Subversion keywords:76 # Subversion keywords: 77 77 # 78 # $LastChangedDate$79 # $LastChangedRevision$80 # $LastChangedBy$78 # $LastChangedDate$ 79 # $LastChangedRevision$ 80 # $LastChangedBy$ 81 81 82 82 from Numeric import zeros, ones, Float, array, sum, size … … 104 104 from anuga.config import optimise_dry_cells 105 105 106 107 #Shallow water domain 106 #--------------------- 107 # Shallow water domain 108 #--------------------- 108 109 class Domain(Generic_Domain): 109 110 … … 149 150 number_of_full_triangles=number_of_full_triangles) 150 151 151 #self.minimum_allowed_height = minimum_allowed_height 152 #self.H0 = minimum_allowed_height 152 153 153 self.set_minimum_allowed_height(minimum_allowed_height) 154 154 … … 167 167 self.optimise_dry_cells = optimise_dry_cells 168 168 169 self.flux_function = flux_function_central 170 #self.flux_function = flux_function_kinetic 171 172 self.forcing_terms.append(manning_friction) 169 self.forcing_terms.append(manning_friction_implicit) 173 170 self.forcing_terms.append(gravity) 174 171 … … 385 382 386 383 def distribute_to_vertices_and_edges(self): 387 # Call correct module function388 # (either from this module or C-extension)384 # Call correct module function 385 # (either from this module or C-extension) 389 386 distribute_to_vertices_and_edges(self) 390 387 391 392 #FIXME: Under construction393 # def set_defaults(self):394 # """Set default values for uninitialised quantities.395 # This is specific to the shallow water wave equation396 # Defaults for 'elevation', 'friction', 'xmomentum' and 'ymomentum'397 # are 0.0. Default for 'stage' is whatever the value of 'elevation'.398 # """399 400 # for name in self.other_quantities + self.conserved_quantities:401 # print name402 # print self.quantities.keys()403 # if not self.quantities.has_key(name):404 # if name == 'stage':405 406 # if self.quantities.has_key('elevation'):407 # z = self.quantities['elevation'].vertex_values408 # self.set_quantity(name, z)409 # else:410 # self.set_quantity(name, 0.0)411 # else:412 # self.set_quantity(name, 0.0)413 414 415 416 # #Lift negative heights up417 # #z = self.quantities['elevation'].vertex_values418 # #w = self.quantities['stage'].vertex_values419 420 # #h = w-z421 422 # #for k in range(h.shape[0]):423 # # for i in range(3):424 # # if h[k, i] < 0.0:425 # # w[k, i] = z[k, i]426 427 428 # #self.quantities['stage'].interpolate()429 388 430 389 … … 437 396 """ 438 397 439 # Call check integrity here rather than from user scripts440 # self.check_integrity()398 # Call check integrity here rather than from user scripts 399 # self.check_integrity() 441 400 442 401 msg = 'Parameter beta_h must be in the interval [0, 1[' … … 446 405 447 406 448 # Initial update of vertex and edge values before any STORAGE449 # and or visualisation450 # This is done again in the initialisation of the Generic_Domain451 # evolve loop but we do it here to ensure the values are ok for storage407 # Initial update of vertex and edge values before any STORAGE 408 # and or visualisation 409 # This is done again in the initialisation of the Generic_Domain 410 # evolve loop but we do it here to ensure the values are ok for storage 452 411 self.distribute_to_vertices_and_edges() 453 412 454 413 if self.store is True and self.time == 0.0: 455 414 self.initialise_storage() 456 # print 'Storing results in ' + self.writer.filename415 # print 'Storing results in ' + self.writer.filename 457 416 else: 458 417 pass 459 # print 'Results will not be stored.'460 # print 'To store results set domain.store = True'461 # FIXME: Diagnostic output should be controlled by418 # print 'Results will not be stored.' 419 # print 'To store results set domain.store = True' 420 # FIXME: Diagnostic output should be controlled by 462 421 # a 'verbose' flag living in domain (or in a parent class) 463 422 464 # Call basic machinery from parent class423 # Call basic machinery from parent class 465 424 for t in Generic_Domain.evolve(self, 466 425 yieldstep=yieldstep, … … 469 428 skip_initial_step=skip_initial_step): 470 429 471 # Store model data, e.g. for subsequent visualisation430 # Store model data, e.g. for subsequent visualisation 472 431 if self.store is True: 473 432 self.store_timestep(self.quantities_to_be_stored) 474 433 475 # FIXME: Could maybe be taken from specified list476 # of 'store every step' quantities477 478 # Pass control on to outer loop for more specific actions434 # FIXME: Could maybe be taken from specified list 435 # of 'store every step' quantities 436 437 # Pass control on to outer loop for more specific actions 479 438 yield(t) 439 480 440 481 441 def initialise_storage(self): … … 486 446 from anuga.shallow_water.data_manager import get_dataobject 487 447 488 # Initialise writer448 # Initialise writer 489 449 self.writer = get_dataobject(self, mode = 'w') 490 450 491 # Store vertices and connectivity451 # Store vertices and connectivity 492 452 self.writer.store_connectivity() 493 453 … … 502 462 503 463 504 #=============== End of Shallow Water Domain =============================== 505 506 507 508 # Rotation of momentum vector 509 def rotate(q, normal, direction = 1): 510 """Rotate the momentum component q (q[1], q[2]) 511 from x,y coordinates to coordinates based on normal vector. 512 513 If direction is negative the rotation is inverted. 514 515 Input vector is preserved 516 517 This function is specific to the shallow water wave equation 518 """ 519 520 assert len(q) == 3,\ 521 'Vector of conserved quantities must have length 3'\ 522 'for 2D shallow water equation' 523 524 try: 525 l = len(normal) 526 except: 527 raise 'Normal vector must be an Numeric array' 528 529 assert l == 2, 'Normal vector must have 2 components' 530 531 532 n1 = normal[0] 533 n2 = normal[1] 534 535 r = zeros(len(q), Float) #Rotated quantities 536 r[0] = q[0] #First quantity, height, is not rotated 537 538 if direction == -1: 539 n2 = -n2 540 541 542 r[1] = n1*q[1] + n2*q[2] 543 r[2] = -n2*q[1] + n1*q[2] 544 545 return r 546 547 548 549 #################################### 464 #=============== End of class Shallow Water Domain =============================== 465 466 467 #----------------- 550 468 # Flux computation 551 # FIXME (Ole): Delete Python versions of code that is 552 # always used in C-extensions - they get out of sync anyway 553 def flux_function_central(normal, ql, qr, zl, zr): 554 """Compute fluxes between volumes for the shallow water wave equation 555 cast in terms of w = h+z using the 'central scheme' as described in 556 557 Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For 558 Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'. 559 Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740. 560 561 The implemented formula is given in equation (3.15) on page 714 562 563 Conserved quantities w, uh, vh are stored as elements 0, 1 and 2 564 in the numerical vectors ql and qr. 565 566 Bed elevations zl and zr. 567 """ 568 569 from math import sqrt 570 571 #Align momentums with x-axis 572 q_left = rotate(ql, normal, direction = 1) 573 q_right = rotate(qr, normal, direction = 1) 574 575 z = (zl+zr)/2 #Take average of field values 576 577 w_left = q_left[0] #w=h+z 578 h_left = w_left-z 579 uh_left = q_left[1] 580 581 if h_left < epsilon: 582 u_left = 0.0 #Could have been negative 583 h_left = 0.0 584 else: 585 u_left = uh_left/h_left 586 587 588 w_right = q_right[0] #w=h+z 589 h_right = w_right-z 590 uh_right = q_right[1] 591 592 593 if h_right < epsilon: 594 u_right = 0.0 #Could have been negative 595 h_right = 0.0 596 else: 597 u_right = uh_right/h_right 598 599 vh_left = q_left[2] 600 vh_right = q_right[2] 601 602 soundspeed_left = sqrt(g*h_left) 603 soundspeed_right = sqrt(g*h_right) 604 605 #Maximal wave speed 606 s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0) 607 608 #Minimal wave speed 609 s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0) 610 611 #Flux computation 612 613 #FIXME(Ole): Why is it again that we don't 614 #use uh_left and uh_right directly in the first entries? 615 flux_left = array([u_left*h_left, 616 u_left*uh_left + 0.5*g*h_left**2, 617 u_left*vh_left]) 618 flux_right = array([u_right*h_right, 619 u_right*uh_right + 0.5*g*h_right**2, 620 u_right*vh_right]) 621 622 denom = s_max-s_min 623 if denom == 0.0: 624 edgeflux = array([0.0, 0.0, 0.0]) 625 max_speed = 0.0 626 else: 627 edgeflux = (s_max*flux_left - s_min*flux_right)/denom 628 edgeflux += s_max*s_min*(q_right-q_left)/denom 629 630 edgeflux = rotate(edgeflux, normal, direction=-1) 631 max_speed = max(abs(s_max), abs(s_min)) 632 633 return edgeflux, max_speed 634 635 def erfcc(x): 636 637 from math import fabs, exp 638 639 z=fabs(x) 640 t=1.0/(1.0+0.5*z) 641 result=t*exp(-z*z-1.26551223+t*(1.00002368+t*(.37409196+ 642 t*(.09678418+t*(-.18628806+t*(.27886807+t*(-1.13520398+ 643 t*(1.48851587+t*(-.82215223+t*.17087277))))))))) 644 if x < 0.0: 645 result = 2.0-result 646 647 return result 648 649 def flux_function_kinetic(normal, ql, qr, zl, zr): 650 """Compute fluxes between volumes for the shallow water wave equation 651 cast in terms of w = h+z using the 'central scheme' as described in 652 653 Zhang et. al., Advances in Water Resources, 26(6), 2003, 635-647. 654 655 656 Conserved quantities w, uh, vh are stored as elements 0, 1 and 2 657 in the numerical vectors ql an qr. 658 659 Bed elevations zl and zr. 660 """ 661 662 from math import sqrt 663 from Numeric import array 664 665 #Align momentums with x-axis 666 q_left = rotate(ql, normal, direction = 1) 667 q_right = rotate(qr, normal, direction = 1) 668 669 z = (zl+zr)/2 #Take average of field values 670 671 w_left = q_left[0] #w=h+z 672 h_left = w_left-z 673 uh_left = q_left[1] 674 675 if h_left < epsilon: 676 u_left = 0.0 #Could have been negative 677 h_left = 0.0 678 else: 679 u_left = uh_left/h_left 680 681 682 w_right = q_right[0] #w=h+z 683 h_right = w_right-z 684 uh_right = q_right[1] 685 686 687 if h_right < epsilon: 688 u_right = 0.0 #Could have been negative 689 h_right = 0.0 690 else: 691 u_right = uh_right/h_right 692 693 vh_left = q_left[2] 694 vh_right = q_right[2] 695 696 soundspeed_left = sqrt(g*h_left) 697 soundspeed_right = sqrt(g*h_right) 698 699 #Maximal wave speed 700 s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0) 701 702 #Minimal wave speed 703 s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0) 704 705 #Flux computation 706 707 F_left = 0.0 708 F_right = 0.0 709 from math import sqrt, pi, exp 710 if h_left > 0.0: 711 F_left = u_left/sqrt(g*h_left) 712 if h_right > 0.0: 713 F_right = u_right/sqrt(g*h_right) 714 715 edgeflux = array([0.0, 0.0, 0.0]) 716 717 edgeflux[0] = h_left*u_left/2.0*erfcc(-F_left) + \ 718 h_left*sqrt(g*h_left)/2.0/sqrt(pi)*exp(-(F_left**2)) + \ 719 h_right*u_right/2.0*erfcc(F_right) - \ 720 h_right*sqrt(g*h_right)/2.0/sqrt(pi)*exp(-(F_right**2)) 721 722 edgeflux[1] = (h_left*u_left**2 + g/2.0*h_left**2)/2.0*erfcc(-F_left) + \ 723 u_left*h_left*sqrt(g*h_left)/2.0/sqrt(pi)*exp(-(F_left**2)) + \ 724 (h_right*u_right**2 + g/2.0*h_right**2)/2.0*erfcc(F_right) - \ 725 u_right*h_right*sqrt(g*h_right)/2.0/sqrt(pi)*exp(-(F_right**2)) 726 727 edgeflux[2] = vh_left*u_left/2.0*erfcc(-F_left) + \ 728 vh_left*sqrt(g*h_left)/2.0/sqrt(pi)*exp(-(F_left**2)) + \ 729 vh_right*u_right/2.0*erfcc(F_right) - \ 730 vh_right*sqrt(g*h_right)/2.0/sqrt(pi)*exp(-(F_right**2)) 731 732 733 edgeflux = rotate(edgeflux, normal, direction=-1) 734 max_speed = max(abs(s_max), abs(s_min)) 735 736 return edgeflux, max_speed 737 738 469 #----------------- 739 470 740 471 def compute_fluxes(domain): … … 756 487 domain.explicit_update is reset to computed flux values 757 488 domain.timestep is set to the largest step satisfying all volumes. 489 490 491 This wrapper calls the underlying C version of compute fluxes 758 492 """ 759 493 … … 762 496 N = len(domain) # number_of_triangles 763 497 764 # Shortcuts498 # Shortcuts 765 499 Stage = domain.quantities['stage'] 766 500 Xmom = domain.quantities['xmomentum'] … … 768 502 Bed = domain.quantities['elevation'] 769 503 770 #Arrays771 stage = Stage.edge_values772 xmom = Xmom.edge_values773 ymom = Ymom.edge_values774 bed = Bed.edge_values775 776 stage_bdry = Stage.boundary_values777 xmom_bdry = Xmom.boundary_values778 ymom_bdry = Ymom.boundary_values779 780 flux = zeros(3, Float) #Work array for summing up fluxes781 782 783 #Loop784 504 timestep = float(sys.maxint) 785 for k in range(N): 786 787 flux[:] = 0. #Reset work array 788 for i in range(3): 789 #Quantities inside volume facing neighbour i 790 ql = [stage[k, i], xmom[k, i], ymom[k, i]] 791 zl = bed[k, i] 792 793 #Quantities at neighbour on nearest face 794 n = domain.neighbours[k,i] 795 if n < 0: 796 m = -n-1 #Convert negative flag to index 797 qr = [stage_bdry[m], xmom_bdry[m], ymom_bdry[m]] 798 zr = zl #Extend bed elevation to boundary 799 else: 800 m = domain.neighbour_edges[k,i] 801 qr = [stage[n, m], xmom[n, m], ymom[n, m]] 802 zr = bed[n, m] 803 804 805 #Outward pointing normal vector 806 normal = domain.normals[k, 2*i:2*i+2] 807 808 #Flux computation using provided function 809 edgeflux, max_speed = domain.flux_function(normal, ql, qr, zl, zr) 810 flux -= edgeflux * domain.edgelengths[k,i] 811 812 #Update optimal_timestep on full cells 813 if domain.tri_full_flag[k] == 1: 814 try: 815 timestep = min(timestep, 0.5*domain.radii[k]/max_speed) 816 except ZeroDivisionError: 817 pass 818 819 #Normalise by area and store for when all conserved 820 #quantities get updated 821 flux /= domain.areas[k] 822 Stage.explicit_update[k] = flux[0] 823 Xmom.explicit_update[k] = flux[1] 824 Ymom.explicit_update[k] = flux[2] 825 domain.max_speed[k] = max_speed 826 827 828 domain.flux_timestep = timestep 829 830 #MH090605 The following method belongs to the shallow_water domain class 831 #see comments in the corresponding method in shallow_water_ext.c 832 def extrapolate_second_order_sw_c(domain): 505 from shallow_water_ext import\ 506 compute_fluxes_ext_central as compute_fluxes_ext 507 508 509 flux_timestep = compute_fluxes_ext(timestep, 510 domain.epsilon, 511 domain.H0, 512 domain.g, 513 domain.neighbours, 514 domain.neighbour_edges, 515 domain.normals, 516 domain.edgelengths, 517 domain.radii, 518 domain.areas, 519 domain.tri_full_flag, 520 Stage.edge_values, 521 Xmom.edge_values, 522 Ymom.edge_values, 523 Bed.edge_values, 524 Stage.boundary_values, 525 Xmom.boundary_values, 526 Ymom.boundary_values, 527 Stage.explicit_update, 528 Xmom.explicit_update, 529 Ymom.explicit_update, 530 domain.already_computed_flux, 531 domain.max_speed, 532 int(domain.optimise_dry_cells)) 533 534 domain.flux_timestep = flux_timestep 535 536 537 538 #--------------------------------------- 539 # Module functions for gradient limiting 540 #--------------------------------------- 541 542 543 # MH090605 The following method belongs to the shallow_water domain class 544 # see comments in the corresponding method in shallow_water_ext.c 545 def extrapolate_second_order_sw(domain): 833 546 """Wrapper calling C version of extrapolate_second_order_sw 834 547 """ … … 843 556 Elevation = domain.quantities['elevation'] 844 557 845 from shallow_water_ext import extrapolate_second_order_sw 846 extrapolate_second_order_sw(domain, 847 domain.surrogate_neighbours, 848 domain.number_of_boundaries, 849 domain.centroid_coordinates, 850 Stage.centroid_values, 851 Xmom.centroid_values, 852 Ymom.centroid_values, 853 Elevation.centroid_values, 854 domain.vertex_coordinates, 855 Stage.vertex_values, 856 Xmom.vertex_values, 857 Ymom.vertex_values, 858 Elevation.vertex_values, 859 int(domain.optimise_dry_cells)) 860 861 def compute_fluxes_c(domain): 862 """Wrapper calling C version of compute fluxes 863 """ 864 865 import sys 866 867 N = len(domain) # number_of_triangles 868 869 #Shortcuts 870 Stage = domain.quantities['stage'] 871 Xmom = domain.quantities['xmomentum'] 872 Ymom = domain.quantities['ymomentum'] 873 Bed = domain.quantities['elevation'] 874 875 timestep = float(sys.maxint) 876 from shallow_water_ext import\ 877 compute_fluxes_ext_central as compute_fluxes_ext 878 879 domain.flux_timestep = compute_fluxes_ext(timestep, domain.epsilon, 880 domain.H0, 881 domain.g, 882 domain.neighbours, 883 domain.neighbour_edges, 884 domain.normals, 885 domain.edgelengths, 886 domain.radii, 887 domain.areas, 888 domain.tri_full_flag, 889 Stage.edge_values, 890 Xmom.edge_values, 891 Ymom.edge_values, 892 Bed.edge_values, 893 Stage.boundary_values, 894 Xmom.boundary_values, 895 Ymom.boundary_values, 896 Stage.explicit_update, 897 Xmom.explicit_update, 898 Ymom.explicit_update, 899 domain.already_computed_flux, 900 domain.max_speed, 901 int(domain.optimise_dry_cells)) 902 903 904 #################################### 905 # Module functions for gradient limiting (distribute_to_vertices_and_edges) 558 from shallow_water_ext import extrapolate_second_order_sw as extrapol2 559 extrapol2(domain, 560 domain.surrogate_neighbours, 561 domain.number_of_boundaries, 562 domain.centroid_coordinates, 563 Stage.centroid_values, 564 Xmom.centroid_values, 565 Ymom.centroid_values, 566 Elevation.centroid_values, 567 domain.vertex_coordinates, 568 Stage.vertex_values, 569 Xmom.vertex_values, 570 Ymom.vertex_values, 571 Elevation.vertex_values, 572 int(domain.optimise_dry_cells)) 573 906 574 907 575 def distribute_to_vertices_and_edges(domain): … … 930 598 from anuga.config import optimised_gradient_limiter 931 599 932 # Remove very thin layers of water600 # Remove very thin layers of water 933 601 protect_against_infinitesimal_and_negative_heights(domain) 934 602 935 # Extrapolate all conserved quantities603 # Extrapolate all conserved quantities 936 604 if optimised_gradient_limiter: 937 # MH090605 if second order,938 # perform the extrapolation and limiting on939 # all of the conserved quantities605 # MH090605 if second order, 606 # perform the extrapolation and limiting on 607 # all of the conserved quantities 940 608 941 609 if (domain._order_ == 1): … … 948 616 raise 'Unknown order' 949 617 else: 950 # old code:618 # Old code: 951 619 for name in domain.conserved_quantities: 952 620 Q = domain.quantities[name] … … 986 654 """ 987 655 988 # Shortcuts656 # Shortcuts 989 657 wc = domain.quantities['stage'].centroid_values 990 658 zc = domain.quantities['elevation'].centroid_values 991 659 xmomc = domain.quantities['xmomentum'].centroid_values 992 660 ymomc = domain.quantities['ymomentum'].centroid_values 993 hc = wc - zc #Water depths at centroids994 995 #Update996 #FIXME: Modify according to c-version - or discard altogether.997 for k in range(len(domain)):998 999 if hc[k] < domain.minimum_allowed_height:1000 #Control stage1001 if hc[k] < domain.epsilon:1002 wc[k] = zc[k] # Contain 'lost mass' error1003 1004 #Control momentum1005 xmomc[k] = ymomc[k] = 0.01006 1007 1008 def protect_against_infinitesimal_and_negative_heights_c(domain):1009 """Protect against infinitesimal heights and associated high velocities1010 """1011 1012 #Shortcuts1013 wc = domain.quantities['stage'].centroid_values1014 zc = domain.quantities['elevation'].centroid_values1015 xmomc = domain.quantities['xmomentum'].centroid_values1016 ymomc = domain.quantities['ymomentum'].centroid_values1017 661 1018 662 from shallow_water_ext import protect … … 1020 664 protect(domain.minimum_allowed_height, domain.maximum_allowed_speed, 1021 665 domain.epsilon, wc, zc, xmomc, ymomc) 1022 1023 666 1024 667 … … 1031 674 This limiter depends on two quantities (w,z) so it resides within 1032 675 this module rather than within quantity.py 1033 """ 1034 1035 N = len(domain) 676 677 Wrapper for c-extension 678 """ 679 680 N = len(domain) # number_of_triangles 1036 681 beta_h = domain.beta_h 1037 682 1038 # Shortcuts683 # Shortcuts 1039 684 wc = domain.quantities['stage'].centroid_values 1040 685 zc = domain.quantities['elevation'].centroid_values … … 1043 688 wv = domain.quantities['stage'].vertex_values 1044 689 zv = domain.quantities['elevation'].vertex_values 1045 hv = wv-zv1046 1047 hvbar = zeros(hv.shape, Float) #h-limited values1048 1049 #Find min and max of this and neighbour's centroid values1050 hmax = zeros(hc.shape, Float)1051 hmin = zeros(hc.shape, Float)1052 1053 for k in range(N):1054 hmax[k] = hmin[k] = hc[k]1055 for i in range(3):1056 n = domain.neighbours[k,i]1057 if n >= 0:1058 hn = hc[n] #Neighbour's centroid value1059 1060 hmin[k] = min(hmin[k], hn)1061 hmax[k] = max(hmax[k], hn)1062 1063 1064 #Diffences between centroids and maxima/minima1065 dhmax = hmax - hc1066 dhmin = hmin - hc1067 1068 #Deltas between vertex and centroid values1069 dh = zeros(hv.shape, Float)1070 for i in range(3):1071 dh[:,i] = hv[:,i] - hc1072 1073 #Phi limiter1074 for k in range(N):1075 1076 #Find the gradient limiter (phi) across vertices1077 phi = 1.01078 for i in range(3):1079 r = 1.01080 if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]1081 if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]1082 1083 phi = min( min(r*beta_h, 1), phi )1084 1085 #Then update using phi limiter1086 for i in range(3):1087 hvbar[k,i] = hc[k] + phi*dh[k,i]1088 1089 return hvbar1090 1091 1092 1093 def h_limiter_c(domain):1094 """Limit slopes for each volume to eliminate artificial variance1095 introduced by e.g. second order extrapolator1096 1097 limit on h = w-z1098 1099 This limiter depends on two quantities (w,z) so it resides within1100 this module rather than within quantity.py1101 1102 Wrapper for c-extension1103 """1104 1105 N = len(domain) # number_of_triangles1106 beta_h = domain.beta_h1107 1108 #Shortcuts1109 wc = domain.quantities['stage'].centroid_values1110 zc = domain.quantities['elevation'].centroid_values1111 hc = wc - zc1112 1113 wv = domain.quantities['stage'].vertex_values1114 zv = domain.quantities['elevation'].vertex_values1115 690 hv = wv - zv 1116 691 1117 692 #Call C-extension 1118 from shallow_water_ext import h_limiter_sw as h_limiter1119 hvbar = h_limiter (domain, hc, hv)693 from shallow_water_ext import h_limiter_sw 694 hvbar = h_limiter_sw(domain, hc, hv) 1120 695 1121 696 return hvbar … … 1133 708 modes. 1134 709 1135 The h-limiter is always applied irrespective of the order. 1136 """ 1137 1138 #Shortcuts 1139 wc = domain.quantities['stage'].centroid_values 1140 zc = domain.quantities['elevation'].centroid_values 1141 hc = wc - zc 1142 1143 wv = domain.quantities['stage'].vertex_values 1144 zv = domain.quantities['elevation'].vertex_values 1145 hv = wv-zv 1146 1147 #Limit h 1148 hvbar = h_limiter(domain) 1149 1150 for k in range(len(domain)): 1151 #Compute maximal variation in bed elevation 1152 # This quantitiy is 1153 # dz = max_i abs(z_i - z_c) 1154 # and it is independent of dimension 1155 # In the 1d case zc = (z0+z1)/2 1156 # In the 2d case zc = (z0+z1+z2)/3 1157 1158 dz = max(abs(zv[k,0]-zc[k]), 1159 abs(zv[k,1]-zc[k]), 1160 abs(zv[k,2]-zc[k])) 1161 1162 1163 hmin = min( hv[k,:] ) 1164 1165 #Create alpha in [0,1], where alpha==0 means using the h-limited 1166 #stage and alpha==1 means using the w-limited stage as 1167 #computed by the gradient limiter (both 1st or 2nd order) 1168 1169 #If hmin > dz/2 then alpha = 1 and the bed will have no effect 1170 #If hmin < 0 then alpha = 0 reverting to constant height above bed. 1171 1172 if dz > 0.0: 1173 alpha = max( min( 2*hmin/dz, 1.0), 0.0 ) 1174 else: 1175 #Flat bed 1176 alpha = 1.0 1177 1178 #Let 1179 # 1180 # wvi be the w-limited stage (wvi = zvi + hvi) 1181 # wvi- be the h-limited state (wvi- = zvi + hvi-) 1182 # 1183 # 1184 #where i=0,1,2 denotes the vertex ids 1185 # 1186 #Weighted balance between w-limited and h-limited stage is 1187 # 1188 # wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi) 1189 # 1190 #It follows that the updated wvi is 1191 # wvi := zvi + (1-alpha)*hvi- + alpha*hvi 1192 # 1193 # Momentum is balanced between constant and limited 1194 1195 1196 #for i in range(3): 1197 # wv[k,i] = zv[k,i] + hvbar[k,i] 1198 1199 #return 1200 1201 if alpha < 1: 1202 1203 for i in range(3): 1204 wv[k,i] = zv[k,i] + (1-alpha)*hvbar[k,i] + alpha*hv[k,i] 1205 1206 #Momentums at centroids 1207 xmomc = domain.quantities['xmomentum'].centroid_values 1208 ymomc = domain.quantities['ymomentum'].centroid_values 1209 1210 #Momentums at vertices 1211 xmomv = domain.quantities['xmomentum'].vertex_values 1212 ymomv = domain.quantities['ymomentum'].vertex_values 1213 1214 # Update momentum as a linear combination of 1215 # xmomc and ymomc (shallow) and momentum 1216 # from extrapolator xmomv and ymomv (deep). 1217 xmomv[k,:] = (1-alpha)*xmomc[k] + alpha*xmomv[k,:] 1218 ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:] 1219 1220 1221 def balance_deep_and_shallow_c(domain): 1222 """Wrapper for C implementation 710 Wrapper for C implementation 1223 711 """ 1224 712 … … 1229 717 # Omit updating xmomv 1230 718 # 1231 from shallow_water_ext import balance_deep_and_shallow 719 from shallow_water_ext import balance_deep_and_shallow as balance_deep_and_shallow_c 1232 720 1233 721 # Shortcuts 1234 722 wc = domain.quantities['stage'].centroid_values 1235 723 zc = domain.quantities['elevation'].centroid_values 1236 #hc = wc - zc1237 724 1238 725 wv = domain.quantities['stage'].vertex_values 1239 726 zv = domain.quantities['elevation'].vertex_values 1240 #hv = wv - zv1241 727 1242 728 # Momentums at centroids … … 1248 734 ymomv = domain.quantities['ymomentum'].vertex_values 1249 735 1250 # Limit h736 # Limit h 1251 737 if domain.beta_h > 0: 1252 738 hvbar = h_limiter(domain) 1253 739 1254 balance_deep_and_shallow (domain, domain.beta_h,1255 wc, zc, wv, zv, hvbar,1256 xmomc, ymomc, xmomv, ymomv)740 balance_deep_and_shallow_c(domain, domain.beta_h, 741 wc, zc, wv, zv, hvbar, 742 xmomc, ymomc, xmomv, ymomv) 1257 743 else: 1258 744 # print 'Using first order h-limiter' 1259 745 # FIXME: Pass wc in for now - it will be ignored. 1260 746 1261 # This is how one would make a first order h_limited value1262 # as in the old balancer (pre 17 Feb 2005):1263 # If we wish to hard wire this, one should modify the C-code1264 # from Numeric import zeros, Float1265 # hvbar = zeros( (len(wc), 3), Float)1266 # for i in range(3):1267 # hvbar[:,i] = wc[:] - zc[:]1268 1269 balance_deep_and_shallow (domain, domain.beta_h,1270 wc, zc, wv, zv, wc,1271 xmomc, ymomc, xmomv, ymomv)1272 1273 1274 1275 1276 1277 # ##############################################1278 # Boundaries - specific to the shallow water wave equation747 # This is how one would make a first order h_limited value 748 # as in the old balancer (pre 17 Feb 2005): 749 # If we wish to hard wire this, one should modify the C-code 750 # from Numeric import zeros, Float 751 # hvbar = zeros( (len(wc), 3), Float) 752 # for i in range(3): 753 # hvbar[:,i] = wc[:] - zc[:] 754 755 balance_deep_and_shallow_c(domain, domain.beta_h, 756 wc, zc, wv, zv, wc, 757 xmomc, ymomc, xmomv, ymomv) 758 759 760 761 762 #------------------------------------------------------------------ 763 # Boundary conditions - specific to the shallow water wave equation 764 #------------------------------------------------------------------ 1279 765 class Reflective_boundary(Boundary): 1280 766 """Reflective boundary returns same conserved quantities as … … 1293 779 raise msg 1294 780 1295 # Handy shorthands781 # Handy shorthands 1296 782 self.stage = domain.quantities['stage'].edge_values 1297 783 self.xmom = domain.quantities['xmomentum'].edge_values … … 1377 863 1378 864 1379 # FIXME: Consider this (taken from File_boundary) to allow1380 # spatial variation1381 # if vol_id is not None and edge_id is not None:1382 # i = self.boundary_indices[ vol_id, edge_id ]1383 # return self.F(t, point_id = i)1384 # else:1385 # return self.F(t)865 # FIXME: Consider this (taken from File_boundary) to allow 866 # spatial variation 867 # if vol_id is not None and edge_id is not None: 868 # i = self.boundary_indices[ vol_id, edge_id ] 869 # return self.F(t, point_id = i) 870 # else: 871 # return self.F(t) 1386 872 1387 873 … … 1424 910 1425 911 1426 # FIXME: Consider this (taken from File_boundary) to allow1427 # spatial variation1428 # if vol_id is not None and edge_id is not None:1429 # i = self.boundary_indices[ vol_id, edge_id ]1430 # return self.F(t, point_id = i)1431 # else:1432 # return self.F(t)912 # FIXME: Consider this (taken from File_boundary) to allow 913 # spatial variation 914 # if vol_id is not None and edge_id is not None: 915 # i = self.boundary_indices[ vol_id, edge_id ] 916 # return self.F(t, point_id = i) 917 # else: 918 # return self.F(t) 1433 919 1434 920 … … 1511 997 1512 998 1513 ######################### 1514 #Standard forcing terms: 1515 # 999 #----------------------- 1000 # Standard forcing terms 1001 #----------------------- 1002 1516 1003 def gravity(domain): 1517 1004 """Apply gravitational pull in the presence of bed slope 1005 Wrapper calls underlying C implementation 1518 1006 """ 1519 1007 … … 1521 1009 ymom = domain.quantities['ymomentum'].explicit_update 1522 1010 1523 Stage = domain.quantities['stage'] 1524 Elevation = domain.quantities['elevation'] 1525 h = Stage.edge_values - Elevation.edge_values 1526 v = Elevation.vertex_values 1011 stage = domain.quantities['stage'] 1012 elevation = domain.quantities['elevation'] 1013 1014 h = stage.centroid_values - elevation.centroid_values 1015 z = elevation.vertex_values 1527 1016 1528 1017 x = domain.get_vertex_coordinates() 1529 1018 g = domain.g 1530 1531 for k in range(len(domain)): 1532 avg_h = sum( h[k,:] )/3 1533 1534 #Compute bed slope 1535 x0, y0, x1, y1, x2, y2 = x[k,:] 1536 z0, z1, z2 = v[k,:] 1537 1538 zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2) 1539 1540 #Update momentum 1541 xmom[k] += -g*zx*avg_h 1542 ymom[k] += -g*zy*avg_h 1543 1544 1545 def gravity_c(domain): 1546 """Wrapper calling C version 1547 """ 1548 1549 xmom = domain.quantities['xmomentum'].explicit_update 1550 ymom = domain.quantities['ymomentum'].explicit_update 1551 1552 stage = domain.quantities['stage'] 1553 elevation = domain.quantities['elevation'] 1554 1555 h = stage.centroid_values - elevation.centroid_values 1556 z = elevation.vertex_values 1557 1558 x = domain.get_vertex_coordinates() 1559 g = domain.g 1560 1561 1562 from shallow_water_ext import gravity 1563 gravity(g, h, z, x, xmom, ymom) #, 1.0e-6) 1564 1565 1566 1567 def manning_friction(domain): 1568 """Apply (Manning) friction to water momentum 1569 (Python version) 1570 """ 1571 1572 from math import sqrt 1019 1020 1021 from shallow_water_ext import gravity as gravity_c 1022 gravity_c(g, h, z, x, xmom, ymom) #, 1.0e-6) 1023 1024 1025 1026 def manning_friction_implicit(domain): 1027 """Apply (Manning) friction to water momentum 1028 Wrapper for c version 1029 """ 1030 1031 1032 #print 'Implicit friction' 1033 1034 xmom = domain.quantities['xmomentum'] 1035 ymom = domain.quantities['ymomentum'] 1573 1036 1574 1037 w = domain.quantities['stage'].centroid_values 1575 1038 z = domain.quantities['elevation'].centroid_values 1576 h = w-z 1577 1578 uh = domain.quantities['xmomentum'].centroid_values 1579 vh = domain.quantities['ymomentum'].centroid_values 1039 1040 uh = xmom.centroid_values 1041 vh = ymom.centroid_values 1580 1042 eta = domain.quantities['friction'].centroid_values 1581 1043 1582 xmom_update = domain.quantities['xmomentum'].semi_implicit_update1583 ymom_update = domain.quantities['ymomentum'].semi_implicit_update1044 xmom_update = xmom.semi_implicit_update 1045 ymom_update = ymom.semi_implicit_update 1584 1046 1585 1047 N = len(domain) … … 1587 1049 g = domain.g 1588 1050 1589 for k in range(N): 1590 if eta[k] >= eps: 1591 if h[k] >= eps: 1592 S = -g * eta[k]**2 * sqrt((uh[k]**2 + vh[k]**2)) 1593 S /= h[k]**(7.0/3) 1594 1595 #Update momentum 1596 xmom_update[k] += S*uh[k] 1597 ymom_update[k] += S*vh[k] 1598 1599 1600 def manning_friction_implicit_c(domain): 1601 """Wrapper for c version 1602 """ 1603 1604 1605 #print 'Implicit friction' 1051 from shallow_water_ext import manning_friction as manning_friction_c 1052 manning_friction_c(g, eps, w, z, uh, vh, eta, xmom_update, ymom_update) 1053 1054 1055 def manning_friction_explicit(domain): 1056 """Apply (Manning) friction to water momentum 1057 Wrapper for c version 1058 """ 1059 1060 # print 'Explicit friction' 1606 1061 1607 1062 xmom = domain.quantities['xmomentum'] … … 1615 1070 eta = domain.quantities['friction'].centroid_values 1616 1071 1617 xmom_update = xmom. semi_implicit_update1618 ymom_update = ymom. semi_implicit_update1072 xmom_update = xmom.explicit_update 1073 ymom_update = ymom.explicit_update 1619 1074 1620 1075 N = len(domain) … … 1622 1077 g = domain.g 1623 1078 1624 from shallow_water_ext import manning_friction 1625 manning_friction(g, eps, w, z, uh, vh, eta, xmom_update, ymom_update) 1626 1627 1628 def manning_friction_explicit_c(domain): 1629 """Wrapper for c version 1630 """ 1631 1632 #print 'Explicit friction' 1633 1634 xmom = domain.quantities['xmomentum'] 1635 ymom = domain.quantities['ymomentum'] 1636 1637 w = domain.quantities['stage'].centroid_values 1638 z = domain.quantities['elevation'].centroid_values 1639 1640 uh = xmom.centroid_values 1641 vh = ymom.centroid_values 1642 eta = domain.quantities['friction'].centroid_values 1643 1644 xmom_update = xmom.explicit_update 1645 ymom_update = ymom.explicit_update 1646 1647 N = len(domain) 1648 eps = domain.minimum_allowed_height 1649 g = domain.g 1650 1651 from shallow_water_ext import manning_friction 1652 manning_friction(g, eps, w, z, uh, vh, eta, xmom_update, ymom_update) 1653 1654 1079 from shallow_water_ext import manning_friction as manning_friction_c 1080 manning_friction_c(g, eps, w, z, uh, vh, eta, xmom_update, ymom_update) 1081 1082 1083 # FIXME (Ole): This was implemented for use with one of the analytical solutions (Sampson?) 1084 # Is it still needed (30 Oct 2007)? 1655 1085 def linear_friction(domain): 1656 1086 """Apply linear friction to water momentum … … 1687 1117 1688 1118 1119 #--------------------------------- 1120 # Experimental auxiliary functions 1121 #--------------------------------- 1689 1122 def check_forcefield(f): 1690 1123 """Check that f is either … … 1703 1136 except Exception, e: 1704 1137 msg = 'Function %s could not be executed:\n%s' %(f, e) 1705 # FIXME: Reconsider this semantics1138 # FIXME: Reconsider this semantics 1706 1139 raise msg 1707 1140 … … 1714 1147 raise msg 1715 1148 1716 # Is this really what we want?1149 # Is this really what we want? 1717 1150 msg = 'Return vector from function %s ' %f 1718 1151 msg += 'must have same lenght as input vectors' … … 1781 1214 phi = args[1] 1782 1215 elif len(args) == 1: 1783 # Assume vector function returning (s, phi)(t,x,y)1216 # Assume vector function returning (s, phi)(t,x,y) 1784 1217 vector_function = args[0] 1785 1218 s = lambda t,x,y: vector_function(t,x=x,y=y)[0] 1786 1219 phi = lambda t,x,y: vector_function(t,x=x,y=y)[1] 1787 1220 else: 1788 # Assume info is in 2 keyword arguments1221 # Assume info is in 2 keyword arguments 1789 1222 1790 1223 if len(kwargs) == 2: … … 1817 1250 s_vec = self.speed(t, xc[:,0], xc[:,1]) 1818 1251 else: 1819 # Assume s is a scalar1252 # Assume s is a scalar 1820 1253 1821 1254 try: … … 1830 1263 phi_vec = self.phi(t, xc[:,0], xc[:,1]) 1831 1264 else: 1832 # Assume phi is a scalar1265 # Assume phi is a scalar 1833 1266 1834 1267 try: … … 1854 1287 phi = phi_vec[k] 1855 1288 1856 # Convert to radians1289 # Convert to radians 1857 1290 phi = phi*pi/180 1858 1291 1859 # Compute velocity vector (u, v)1292 # Compute velocity vector (u, v) 1860 1293 u = s*cos(phi) 1861 1294 v = s*sin(phi) 1862 1295 1863 # Compute wind stress1296 # Compute wind stress 1864 1297 S = const * sqrt(u**2 + v**2) 1865 1298 xmom_update[k] += S*u … … 2041 1474 #------------------ 2042 1475 1476 2043 1477 from anuga.utilities import compile 2044 1478 if compile.can_use_C_extension('shallow_water_ext.c'): 2045 # Replace python version with c implementations1479 # Underlying C implementations can be accessed 2046 1480 2047 1481 from shallow_water_ext import rotate, assign_windfield_values 2048 compute_fluxes = compute_fluxes_c 2049 extrapolate_second_order_sw=extrapolate_second_order_sw_c 2050 gravity = gravity_c 2051 manning_friction = manning_friction_implicit_c 2052 h_limiter = h_limiter_c 2053 balance_deep_and_shallow = balance_deep_and_shallow_c 2054 protect_against_infinitesimal_and_negative_heights =\ 2055 protect_against_infinitesimal_and_negative_heights_c 2056 2057 #distribute_to_vertices_and_edges =\ 2058 # distribute_to_vertices_and_edges_c #(like MH's) 2059 1482 else: 1483 msg = 'C implementations could not be accessed by %s.\n ' %__file__ 1484 msg += 'Make sure compile_all.py has been run as described in ' 1485 msg += 'the ANUGA installation guide.' 1486 raise Exception, msg 2060 1487 2061 1488 -
anuga_core/source/anuga/shallow_water/shallow_water_ext.c
r4733 r4769 194 194 195 195 // Innermost flux function (using stage w=z+h) 196 int flux_function_central(double *q_left, double *q_right,197 double z_left, double z_right,198 double n1, double n2,199 double epsilon, double H0, double g,200 double *edgeflux, double *max_speed) {196 int _flux_function_central(double *q_left, double *q_right, 197 double z_left, double z_right, 198 double n1, double n2, 199 double epsilon, double H0, double g, 200 double *edgeflux, double *max_speed) { 201 201 202 202 /*Compute fluxes between volumes for the shallow water wave equation … … 737 737 /////////////////////////////////////////////////////////////////// 738 738 // Gateways to Python 739 740 741 742 PyObject *flux_function_central(PyObject *self, PyObject *args) { 743 // 744 // Gateway to innermost flux function. 745 // This is only used by the unit tests as the c implementation is 746 // normally called by compute_fluxes in this module. 747 748 749 PyArrayObject *normal, *ql, *qr, *edgeflux; 750 double g, epsilon, max_speed, H0, zl, zr; 751 752 if (!PyArg_ParseTuple(args, "OOOddOddd", 753 &normal, &ql, &qr, &zl, &zr, &edgeflux, 754 &epsilon, &g, &H0)) { 755 PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: flux_function_central could not parse input arguments"); 756 return NULL; 757 } 758 759 760 _flux_function_central((double*) ql -> data, 761 (double*) qr -> data, 762 zl, 763 zr, 764 ((double*) normal -> data)[0], 765 ((double*) normal -> data)[1], 766 epsilon, H0, g, 767 (double*) edgeflux -> data, 768 &max_speed); 769 770 return Py_BuildValue("d", max_speed); 771 } 772 773 739 774 740 775 PyObject *gravity(PyObject *self, PyObject *args) { … … 1494 1529 } 1495 1530 1496 // Input checks (convert sequences into numeric arrays)1531 // Input checks (convert sequences into numeric arrays) 1497 1532 q = (PyArrayObject *) 1498 1533 PyArray_ContiguousFromObject(Q, PyArray_DOUBLE, 0, 0); … … 1506 1541 } 1507 1542 1508 // Allocate space for return vector r (don't DECREF)1543 // Allocate space for return vector r (don't DECREF) 1509 1544 dimensions[0] = 3; 1510 1545 r = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE); 1511 1546 1512 // Copy1547 // Copy 1513 1548 for (i=0; i<3; i++) { 1514 1549 ((double *) (r -> data))[i] = ((double *) (q -> data))[i]; 1515 1550 } 1516 1551 1517 // Get normal and direction1552 // Get normal and direction 1518 1553 n1 = ((double *) normal -> data)[0]; 1519 1554 n2 = ((double *) normal -> data)[1]; 1520 1555 if (direction == -1) n2 = -n2; 1521 1556 1522 // Rotate1557 // Rotate 1523 1558 _rotate((double *) r -> data, n1, n2); 1524 1559 1525 // Release numeric arrays1560 // Release numeric arrays 1526 1561 Py_DECREF(q); 1527 1562 Py_DECREF(normal); 1528 1563 1529 // return result using PyArray to avoid memory leak1564 // Return result using PyArray to avoid memory leak 1530 1565 return PyArray_Return(r); 1531 1566 } … … 1642 1677 1643 1678 // Edge flux computation (triangle k, edge i) 1644 flux_function_central(ql, qr, zl, zr,1645 normals[ki2], normals[ki2+1],1646 epsilon, H0, g,1647 edgeflux, &max_speed);1679 _flux_function_central(ql, qr, zl, zr, 1680 normals[ki2], normals[ki2+1], 1681 epsilon, H0, g, 1682 edgeflux, &max_speed); 1648 1683 1649 1684 … … 1898 1933 *xmom_explicit_update, 1899 1934 *ymom_explicit_update, 1900 *already_computed_flux; //tracks whether the flux across an edge has already been computed1901 1902 1903 // Local variables1935 *already_computed_flux; // Tracks whether the flux across an edge has already been computed 1936 1937 1938 // Local variables 1904 1939 double timestep, max_speed, epsilon, g, H0; 1905 1940 double normal[2], ql[3], qr[3], zl, zr; … … 2060 2095 2061 2096 PyObject *balance_deep_and_shallow(PyObject *self, PyObject *args) { 2097 // Compute linear combination between stage as computed by 2098 // gradient-limiters limiting using w, and stage computed by 2099 // gradient-limiters limiting using h (h-limiter). 2100 // The former takes precedence when heights are large compared to the 2101 // bed slope while the latter takes precedence when heights are 2102 // relatively small. Anything in between is computed as a balanced 2103 // linear combination in order to avoid numerical disturbances which 2104 // would otherwise appear as a result of hard switching between 2105 // modes. 2062 2106 // 2063 2107 // balance_deep_and_shallow(beta_h, wc, zc, wv, zv, … … 2160 2204 int k, i, n, N, k3; 2161 2205 int dimensions[2]; 2162 double beta_h; // Safety factor (see config.py)2206 double beta_h; // Safety factor (see config.py) 2163 2207 double *hmin, *hmax, hn; 2164 2208 … … 2201 2245 n = ((long*) neighbours -> data)[k3+i]; 2202 2246 2203 // Initialise hvbar with values from hv2247 // Initialise hvbar with values from hv 2204 2248 ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i]; 2205 2249 2206 2250 if (n >= 0) { 2207 hn = ((double*) hc -> data)[n]; // Neighbour's centroid value2251 hn = ((double*) hc -> data)[n]; // Neighbour's centroid value 2208 2252 2209 2253 hmin[k] = min(hmin[k], hn); … … 2216 2260 _limit(N, beta_h, (double*) hc -> data, (double*) hvbar -> data, hmin, hmax); 2217 2261 2218 // // //Py_DECREF(domain); //FIXME: N Ecessary?2262 // // //Py_DECREF(domain); //FIXME: Necessary? 2219 2263 free(hmin); 2220 2264 free(hmax); 2221 2265 2222 // return result using PyArray to avoid memory leak2266 // Return result using PyArray to avoid memory leak 2223 2267 return PyArray_Return(hvbar); 2224 //return Py_BuildValue("");2225 2268 } 2226 2269 … … 2337 2380 2338 2381 2339 // ////////////////////////////////////////2382 //------------------------------- 2340 2383 // Method table for python module 2384 //------------------------------- 2341 2385 static struct PyMethodDef MethodTable[] = { 2342 2386 /* The cast of the function is necessary since PyCFunction values … … 2351 2395 {"gravity", gravity, METH_VARARGS, "Print out"}, 2352 2396 {"manning_friction", manning_friction, METH_VARARGS, "Print out"}, 2397 {"flux_function_central", flux_function_central, METH_VARARGS, "Print out"}, 2353 2398 {"balance_deep_and_shallow", balance_deep_and_shallow, 2354 2399 METH_VARARGS, "Print out"}, … … 2360 2405 {"assign_windfield_values", assign_windfield_values, 2361 2406 METH_VARARGS | METH_KEYWORDS, "Print out"}, 2362 //{"distribute_to_vertices_and_edges",2363 // distribute_to_vertices_and_edges, METH_VARARGS},2364 //{"update_conserved_quantities",2365 // update_conserved_quantities, METH_VARARGS},2366 //{"set_initialcondition",2367 // set_initialcondition, METH_VARARGS},2368 2407 {NULL, NULL} 2369 2408 }; -
anuga_core/source/anuga/shallow_water/test_shallow_water_domain.py
r4733 r4769 10 10 11 11 from shallow_water_domain import * 12 from shallow_water_domain import flux_function_central as flux_function 12 13 # Get gateway to C implementation of flux function for direct testing 14 from shallow_water_ext import flux_function_central as flux_function 13 15 14 16 class Weir: … … 252 254 253 255 254 # FIXME (Ole): Individual flux tests do NOT test C implementation directly.256 # Individual flux tests 255 257 def test_flux_zero_case(self): 256 258 ql = zeros( 3, Float ) 257 259 qr = zeros( 3, Float ) 258 260 normal = zeros( 2, Float ) 261 edgeflux = zeros( 3, Float ) 259 262 zl = zr = 0. 260 flux, max_speed = flux_function(normal, ql, qr, zl, zr) 261 262 assert allclose(flux, [0,0,0]) 263 H0 = 0.0 264 265 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux, epsilon, g, H0) 266 267 assert allclose(edgeflux, [0,0,0]) 263 268 assert max_speed == 0. 264 269 … … 269 274 ql = array([w, 0, 0]) 270 275 qr = array([w, 0, 0]) 276 edgeflux = zeros(3, Float) 271 277 zl = zr = 0. 272 278 h = w - (zl+zr)/2 273 274 flux, max_speed = flux_function(normal, ql, qr, zl, zr) 275 276 assert allclose( flux, [0., 0.5*g*h**2, 0.])279 H0 = 0.0 280 281 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux, epsilon, g, H0) 282 assert allclose(edgeflux, [0., 0.5*g*h**2, 0.]) 277 283 assert max_speed == sqrt(g*h) 278 284 … … 299 305 qr = array([-0.2, 2, 3]) 300 306 zl = zr = -0.5 301 flux, max_speed = flux_function(normal, ql, qr, zl, zr) 302 303 assert allclose(flux, [2.,13.77433333, 20.]) 307 edgeflux = zeros(3, Float) 308 309 H0 = 0.0 310 311 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux, epsilon, g, H0) 312 313 assert allclose(edgeflux, [2.,13.77433333, 20.]) 304 314 assert allclose(max_speed, 8.38130948661) 305 315 … … 311 321 qr = array([-0.075, 2, 3]) 312 322 zl = zr = -0.375 313 flux, max_speed = flux_function(normal, ql, qr, zl, zr) 314 315 assert allclose(flux, [-3.,-20.0, -30.441]) 323 324 edgeflux = zeros(3, Float) 325 H0 = 0.0 326 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux, epsilon, g, H0) 327 328 assert allclose(edgeflux, [-3.,-20.0, -30.441]) 316 329 assert allclose(max_speed, 11.7146428199) 317 330 … … 322 335 qr = array([-0.075, 2, 3]) 323 336 zl = zr = -0.375 324 flux, max_speed = flux_function(normal, ql, qr, zl, zr) 325 326 assert allclose(flux, [sqrt(2)/2, 4.40221112, 7.3829019]) 337 338 edgeflux = zeros(3, Float) 339 H0 = 0.0 340 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux, epsilon, g, H0) 341 342 assert allclose(edgeflux, [sqrt(2)/2, 4.40221112, 7.3829019]) 327 343 assert allclose(max_speed, 4.0716654239) 328 344 … … 333 349 qr = array([-0.30683287, 0.1071986, 0.05930515]) 334 350 zl = zr = -0.375 335 flux, max_speed = flux_function(normal, ql, qr, zl, zr) 336 337 assert allclose(flux, [-0.04072676, -0.07096636, -0.01604364]) 351 352 edgeflux = zeros(3, Float) 353 H0 = 0.0 354 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux, epsilon, g, H0) 355 356 assert allclose(edgeflux, [-0.04072676, -0.07096636, -0.01604364]) 338 357 assert allclose(max_speed, 1.31414103233) 339 358 … … 532 551 533 552 def test_compute_fluxes0(self): 534 # Do a full triangle and check that fluxes cancel out for535 # the constant stage case553 # Do a full triangle and check that fluxes cancel out for 554 # the constant stage case 536 555 537 556 a = [0.0, 0.0] … … 554 573 assert allclose(domain.neighbour_edges, [[-1,2,-1], [2,0,1], [-1,-1,0],[1,-1,-1]]) 555 574 556 zl=zr=0. #Assume flat bed 557 558 #Flux across right edge of volume 1 575 zl=zr=0. # Assume flat bed 576 577 edgeflux = zeros(3, Float) 578 edgeflux0 = zeros(3, Float) 579 edgeflux1 = zeros(3, Float) 580 edgeflux2 = zeros(3, Float) 581 H0 = 0.0 582 583 # Flux across right edge of volume 1 559 584 normal = domain.get_normal(1,0) 560 585 ql = domain.get_conserved_quantities(vol_id=1, edge=0) 561 586 qr = domain.get_conserved_quantities(vol_id=2, edge=2) 562 flux0, max_speed = flux_function(normal, ql, qr, zl, zr)563 564 # Check that flux seen from other triangles is inverse587 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux0, epsilon, g, H0) 588 589 # Check that flux seen from other triangles is inverse 565 590 tmp = qr; qr=ql; ql=tmp 566 591 normal = domain.get_normal(2,2) 567 flux, max_speed = flux_function(normal, ql, qr, zl, zr) 568 assert allclose(flux + flux0, 0.) 569 570 #Flux across upper edge of volume 1 592 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux, epsilon, g, H0) 593 594 assert allclose(edgeflux0 + edgeflux, 0.) 595 596 # Flux across upper edge of volume 1 571 597 normal = domain.get_normal(1,1) 572 598 ql = domain.get_conserved_quantities(vol_id=1, edge=1) 573 599 qr = domain.get_conserved_quantities(vol_id=3, edge=0) 574 flux1, max_speed = flux_function(normal, ql, qr, zl, zr)575 576 # Check that flux seen from other triangles is inverse600 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux1, epsilon, g, H0) 601 602 # Check that flux seen from other triangles is inverse 577 603 tmp = qr; qr=ql; ql=tmp 578 604 normal = domain.get_normal(3,0) 579 flux, max_speed = flux_function(normal, ql, qr, zl, zr) 580 assert allclose(flux + flux1, 0.) 581 582 #Flux across lower left hypotenuse of volume 1 605 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux, epsilon, g, H0) 606 607 assert allclose(edgeflux1 + edgeflux, 0.) 608 609 610 # Flux across lower left hypotenuse of volume 1 583 611 normal = domain.get_normal(1,2) 584 612 ql = domain.get_conserved_quantities(vol_id=1, edge=2) 585 613 qr = domain.get_conserved_quantities(vol_id=0, edge=1) 586 flux2, max_speed = flux_function(normal, ql, qr, zl, zr)587 588 # Check that flux seen from other triangles is inverse614 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux2, epsilon, g, H0) 615 616 # Check that flux seen from other triangles is inverse 589 617 tmp = qr; qr=ql; ql=tmp 590 618 normal = domain.get_normal(0,1) 591 flux, max_speed = flux_function(normal, ql, qr, zl, zr)592 assert allclose( flux + flux2, 0.)593 594 595 # Scale by edgelengths, add up anc check that total flux is zero619 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux, epsilon, g, H0) 620 assert allclose(edgeflux2 + edgeflux, 0.) 621 622 623 # Scale by edgelengths, add up anc check that total flux is zero 596 624 e0 = domain.edgelengths[1, 0] 597 625 e1 = domain.edgelengths[1, 1] 598 626 e2 = domain.edgelengths[1, 2] 599 627 600 assert allclose(e0* flux0+e1*flux1+e2*flux2, 0.)601 602 # Now check that compute_flux yields zeros as well628 assert allclose(e0*edgeflux0+e1*edgeflux1+e2*edgeflux2, 0.) 629 630 # Now check that compute_flux yields zeros as well 603 631 domain.compute_fluxes() 604 632 … … 635 663 zl=zr=0. #Assume flat bed 636 664 637 #Flux across right edge of volume 1 665 edgeflux = zeros(3, Float) 666 edgeflux0 = zeros(3, Float) 667 edgeflux1 = zeros(3, Float) 668 edgeflux2 = zeros(3, Float) 669 H0 = 0.0 670 671 672 # Flux across right edge of volume 1 638 673 normal = domain.get_normal(1,0) #Get normal 0 of triangle 1 639 674 assert allclose(normal, [1, 0]) … … 644 679 qr = domain.get_conserved_quantities(vol_id=2, edge=2) 645 680 assert allclose(qr, [val2, 0, 0]) 646 647 flux0, max_speed = flux_function(normal, ql, qr, zl, zr)648 649 # Flux across edge in the east direction (as per normal vector)650 assert allclose( flux0, [-15.3598804, 253.71111111, 0.])681 682 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux0, epsilon, g, H0) 683 684 # Flux across edge in the east direction (as per normal vector) 685 assert allclose(edgeflux0, [-15.3598804, 253.71111111, 0.]) 651 686 assert allclose(max_speed, 9.21592824046) 652 687 … … 655 690 normal_opposite = domain.get_normal(2,2) #Get normal 2 of triangle 2 656 691 assert allclose(normal_opposite, [-1, 0]) 657 flux_opposite, max_speed = flux_function([-1, 0], ql, qr, zl, zr) 658 assert allclose(flux_opposite, [-15.3598804, -253.71111111, 0.]) 692 693 max_speed = flux_function(normal_opposite, ql, qr, zl, zr, edgeflux, epsilon, g, H0) 694 #flux_opposite, max_speed = flux_function([-1, 0], ql, qr, zl, zr) 695 assert allclose(edgeflux, [-15.3598804, -253.71111111, 0.]) 659 696 660 697 … … 663 700 ql = domain.get_conserved_quantities(vol_id=1, edge=1) 664 701 qr = domain.get_conserved_quantities(vol_id=3, edge=0) 665 flux1, max_speed = flux_function(normal, ql, qr, zl, zr) 666 assert allclose(flux1, [2.4098563, 0., 123.04444444]) 702 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux1, epsilon, g, H0) 703 704 assert allclose(edgeflux1, [2.4098563, 0., 123.04444444]) 667 705 assert allclose(max_speed, 7.22956891292) 668 706 … … 671 709 ql = domain.get_conserved_quantities(vol_id=1, edge=2) 672 710 qr = domain.get_conserved_quantities(vol_id=0, edge=1) 673 flux2, max_speed = flux_function(normal, ql, qr, zl, zr)674 675 assert allclose( flux2, [9.63942522, -61.59685738, -61.59685738])711 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux2, epsilon, g, H0) 712 713 assert allclose(edgeflux2, [9.63942522, -61.59685738, -61.59685738]) 676 714 assert allclose(max_speed, 7.22956891292) 677 715 … … 681 719 e2 = domain.edgelengths[1, 2] 682 720 683 total_flux = -(e0* flux0+e1*flux1+e2*flux2)/domain.areas[1]721 total_flux = -(e0*edgeflux0+e1*edgeflux1+e2*edgeflux2)/domain.areas[1] 684 722 assert allclose(total_flux, [-0.68218178, -166.6, -35.93333333]) 685 723 … … 733 771 734 772 zl=zr=0 #Assume flat zero bed 773 edgeflux = zeros(3, Float) 774 edgeflux0 = zeros(3, Float) 775 edgeflux1 = zeros(3, Float) 776 edgeflux2 = zeros(3, Float) 777 H0 = 0.0 778 735 779 736 780 domain.set_quantity('elevation', zl*ones( (4,3) )) … … 759 803 ql = domain.get_conserved_quantities(vol_id=1, edge=0) 760 804 qr = domain.get_conserved_quantities(vol_id=2, edge=2) 761 flux0, max_speed = flux_function(normal, ql, qr, zl, zr)805 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux0, epsilon, g, H0) 762 806 763 807 #Flux across upper edge of volume 1 … … 765 809 ql = domain.get_conserved_quantities(vol_id=1, edge=1) 766 810 qr = domain.get_conserved_quantities(vol_id=3, edge=0) 767 flux1, max_speed = flux_function(normal, ql, qr, zl, zr)811 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux1, epsilon, g, H0) 768 812 769 813 #Flux across lower left hypotenuse of volume 1 … … 771 815 ql = domain.get_conserved_quantities(vol_id=1, edge=2) 772 816 qr = domain.get_conserved_quantities(vol_id=0, edge=1) 773 flux2, max_speed = flux_function(normal, ql, qr, zl, zr)817 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux2, epsilon, g, H0) 774 818 775 819 #Scale, add up and check that compute_fluxes is correct for vol 1 … … 778 822 e2 = domain.edgelengths[1, 2] 779 823 780 total_flux = -(e0* flux0+e1*flux1+e2*flux2)/domain.areas[1]824 total_flux = -(e0*edgeflux0+e1*edgeflux1+e2*edgeflux2)/domain.areas[1] 781 825 782 826 … … 813 857 814 858 859 edgeflux = zeros(3, Float) 860 edgeflux0 = zeros(3, Float) 861 edgeflux1 = zeros(3, Float) 862 edgeflux2 = zeros(3, Float) 863 H0 = 0.0 864 865 866 815 867 domain.set_quantity('stage', [[val0, val0-1, val0-2], 816 868 [val1, val1+1, val1], … … 835 887 ql = domain.get_conserved_quantities(vol_id=1, edge=0) 836 888 qr = domain.get_conserved_quantities(vol_id=2, edge=2) 837 flux0, max_speed = flux_function(normal, ql, qr, zl, zr)889 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux0, epsilon, g, H0) 838 890 839 891 #Flux across upper edge of volume 1 … … 841 893 ql = domain.get_conserved_quantities(vol_id=1, edge=1) 842 894 qr = domain.get_conserved_quantities(vol_id=3, edge=0) 843 flux1, max_speed = flux_function(normal, ql, qr, zl, zr)895 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux1, epsilon, g, H0) 844 896 845 897 #Flux across lower left hypotenuse of volume 1 … … 847 899 ql = domain.get_conserved_quantities(vol_id=1, edge=2) 848 900 qr = domain.get_conserved_quantities(vol_id=0, edge=1) 849 flux2, max_speed = flux_function(normal, ql, qr, zl, zr)901 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux2, epsilon, g, H0) 850 902 851 903 #Scale, add up and check that compute_fluxes is correct for vol 1 … … 854 906 e2 = domain.edgelengths[1, 2] 855 907 856 total_flux = -(e0* flux0+e1*flux1+e2*flux2)/domain.areas[1]908 total_flux = -(e0*edgeflux0+e1*edgeflux1+e2*edgeflux2)/domain.areas[1] 857 909 858 910 domain.compute_fluxes() … … 5136 5188 if __name__ == "__main__": 5137 5189 5138 suite = unittest.makeSuite(Test_Shallow_Water,'test') 5190 suite = unittest.makeSuite(Test_Shallow_Water,'test') 5139 5191 #suite = unittest.makeSuite(Test_Shallow_Water,'test_extrema') 5140 5192 #suite = unittest.makeSuite(Test_Shallow_Water,'test_tight_slope_limiters') -
anuga_core/source/anuga/utilities/polygon.py
r4768 r4769 254 254 http://www.alienryderflex.com/polygon/ 255 255 256 """ 256 Uses underlying C-implementation in polygon_ext.c 257 """ 258 259 260 if verbose: print 'Checking input to separate_points_by_polygon' 261 257 262 258 263 #Input checks 264 265 assert isinstance(closed, bool), 'Keyword argument "closed" must be boolean' 266 assert isinstance(verbose, bool), 'Keyword argument "verbose" must be boolean' 259 267 260 268 … … 267 275 raise msg 268 276 277 #if verbose: print 'Checking input to separate_points_by_polygon 2' 269 278 try: 270 279 polygon = ensure_numeric(polygon, Float) … … 275 284 raise msg 276 285 286 #if verbose: print 'check' 287 277 288 assert len(polygon.shape) == 2,\ 278 289 'Polygon array must be a 2d array of vertices' … … 290 301 M = points.shape[0] #Number of points 291 302 292 px = polygon[:,0] 293 py = polygon[:,1] 294 295 #Used for an optimisation when points are far away from polygon 296 minpx = min(px); maxpx = max(px) 297 minpy = min(py); maxpy = max(py) 298 299 300 #Begin main loop 301 indices = zeros(M, Int) 302 303 inside_index = 0 #Keep track of points inside 304 outside_index = M-1 #Keep track of points outside (starting from end) 305 306 if verbose: print 'Separating %d points' %M 307 for k in range(M): 308 309 if verbose: 310 if k %((M+10)/10)==0: print 'Doing %d of %d' %(k, M) 311 312 #for each point 313 x = points[k, 0] 314 y = points[k, 1] 315 316 inside = False 317 318 if not x > maxpx or x < minpx or y > maxpy or y < minpy: 319 #Check polygon 320 for i in range(N): 321 j = (i+1)%N 322 323 #Check for case where point is contained in line segment 324 if point_on_line(x, y, px[i], py[i], px[j], py[j]): 325 if closed: 326 inside = True 327 else: 328 inside = False 329 break 330 else: 331 #Check if truly inside polygon 332 if py[i] < y and py[j] >= y or\ 333 py[j] < y and py[i] >= y: 334 if px[i] + (y-py[i])/(py[j]-py[i])*(px[j]-px[i]) < x: 335 inside = not inside 336 337 if inside: 338 indices[inside_index] = k 339 inside_index += 1 340 else: 341 indices[outside_index] = k 342 outside_index -= 1 343 344 return indices, inside_index 345 346 347 def separate_points_by_polygon_c(points, polygon, 348 closed = True, verbose = False): 349 """Determine whether points are inside or outside a polygon 350 351 C-wrapper 352 """ 353 354 355 if verbose: print 'Checking input to separate_points_by_polygon' 356 357 358 #Input checks 359 360 assert isinstance(closed, bool), 'Keyword argument "closed" must be boolean' 361 assert isinstance(verbose, bool), 'Keyword argument "verbose" must be boolean' 362 363 364 try: 365 points = ensure_numeric(points, Float) 366 except NameError, e: 367 raise NameError, e 368 except: 369 msg = 'Points could not be converted to Numeric array' 370 raise msg 371 372 #if verbose: print 'Checking input to separate_points_by_polygon 2' 373 try: 374 polygon = ensure_numeric(polygon, Float) 375 except NameError, e: 376 raise NameError, e 377 except: 378 msg = 'Polygon could not be converted to Numeric array' 379 raise msg 380 381 #if verbose: print 'check' 382 383 assert len(polygon.shape) == 2,\ 384 'Polygon array must be a 2d array of vertices' 385 386 assert polygon.shape[1] == 2,\ 387 'Polygon array must have two columns' 388 389 assert len(points.shape) == 2,\ 390 'Points array must be a 2d array' 391 392 assert points.shape[1] == 2,\ 393 'Points array must have two columns' 394 395 N = polygon.shape[0] #Number of vertices in polygon 396 M = points.shape[0] #Number of points 397 398 from polygon_ext import separate_points_by_polygon 303 399 304 400 305 if verbose: print 'Allocating array for indices' … … 404 309 #if verbose: print 'Calling C-version of inside poly' 405 310 406 count = separate_points_by_polygon(points, polygon, indices, 407 int(closed), int(verbose)) 311 from polygon_ext import separate_points_by_polygon as sep_points 312 count = sep_points(points, polygon, indices, 313 int(closed), int(verbose)) 408 314 409 315 if verbose: print 'Found %d points (out of %d) inside polygon'\ … … 792 698 from anuga.utilities.compile import can_use_C_extension 793 699 if can_use_C_extension('polygon_ext.c'): 700 # Underlying C implementations can be accessed 701 794 702 from polygon_ext import point_on_line 795 separate_points_by_polygon = separate_points_by_polygon_c 703 else: 704 msg = 'C implementations could not be accessed by %s.\n ' %__file__ 705 msg += 'Make sure compile_all.py has been run as described in ' 706 msg += 'the ANUGA installation guide.' 707 raise Exception, msg 796 708 797 709 -
anuga_core/source/anuga/utilities/sparse.py
r3832 r4769 320 320 321 321 322 323 def csr_mv(self, B): 324 """Python version of sparse (CSR) matrix multiplication 325 """ 326 327 from Numeric import zeros, Float 328 329 330 #Assume numeric types from now on 331 332 if len(B.shape) == 0: 333 #Scalar - use __rmul__ method 334 R = B*self 335 336 elif len(B.shape) == 1: 337 #Vector 338 assert B.shape[0] == self.N, 'Mismatching dimensions' 339 340 R = zeros(self.M, Float) #Result 341 342 #Multiply nonzero elements 343 for i in range(self.M): 344 for ckey in range(self.row_ptr[i],self.row_ptr[i+1]): 345 j = self.colind[ckey] 346 R[i] += self.data[ckey]*B[j] 347 348 elif len(B.shape) == 2: 349 350 R = zeros((self.M, B.shape[1]), Float) #Result matrix 351 352 #Multiply nonzero elements 353 354 for col in range(R.shape[1]): 355 #For each column 356 for i in range(self.M): 357 for ckey in range(self.row_ptr[i],self.row_ptr[i+1]): 358 j = self.colind[ckey] 359 R[i, col] += self.data[ckey]*B[j,col] 360 361 else: 362 raise ValueError, 'Dimension too high: d=%d' %len(B.shape) 363 364 return R 365 366 367 368 #Setup for C extensions 322 # Setup for C extensions 369 323 from anuga.utilities import compile 370 324 if compile.can_use_C_extension('sparse_ext.c'): 371 # Replace python version with c implementation325 # Access underlying c implementations 372 326 from sparse_ext import csr_mv 373 327 328 374 329 if __name__ == '__main__': 375 330 # A little selftest 331 376 332 from Numeric import allclose, array, Float 377 333
Note: See TracChangeset
for help on using the changeset viewer.