Changeset 205 for inundation/ga/storm_surge/pyvolution/shallow_water.py
- Timestamp:
- Aug 23, 2004, 2:45:42 PM (21 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
inundation/ga/storm_surge/pyvolution/shallow_water.py
r198 r205 71 71 compute_fluxes(self) 72 72 73 def first_order_limiter(self):73 def distribute_to_vertices_and_edges(self): 74 74 #Call correct module function 75 first_order_limiter(self) 75 #(either from this module or C-extension) 76 distribute_to_vertices_and_edges(self) 76 77 77 78 #################################### … … 259 260 Xmom.explicit_update[k] = flux[1] 260 261 Ymom.explicit_update[k] = flux[2] 261 262 262 263 timestep = min(timestep, optimal_timestep) 263 264 264 265 domain.timestep = timestep 266 265 267 266 268 267 269 #################################### 268 # Functions for gradient limiting (distribute_to_vertices_and_edges) 270 # Module functions for gradient limiting (distribute_to_vertices_and_edges) 271 272 def distribute_to_vertices_and_edges(domain): 273 274 protect_against_infinitesimal_heights_centroid(domain) 275 if domain.order == 1: 276 first_order_extrapolator(domain) 277 elif domain.order == 2: 278 second_order_extrapolator(domain) 279 else: 280 raise 'Unknown order' 269 281 270 282 def protect_against_infinitesimal_heights_centroid(domain): … … 297 309 298 310 299 300 301 def first_order_limiter(domain): 302 """First order limiter function, specific to the shallow water wave 303 equation. 311 312 313 314 def first_order_extrapolator(domain): 315 """First order extrapolator function, specific 316 to the shallow water wave equation. 304 317 305 318 It will ensure that h (w-z) is always non-negative even in the … … 315 328 """ 316 329 317 #FIXME: Might go elsewhere318 protect_against_infinitesimal_heights_centroid(domain)319 330 320 331 #Update conserved quantities using straight first order 321 332 for name in domain.conserved_quantities: 322 333 Q = domain.quantities[name] 323 Q.first_order_limiter() 324 325 334 Q.first_order_extrapolator() 335 Q.interpolate_from_vertices_to_edges() 336 337 326 338 #Water levels at centroids 327 339 wc = domain.quantities['level'].centroid_values … … 377 389 alpha = 1.0 378 390 379 #Update stage391 #Update water levels 380 392 for i in range(3): 381 393 #wv[k,i] = zv[k,i] + hc[k] + alpha*(zc[k]-zv[k,i]) … … 384 396 385 397 386 def second_order_ limiter(domain):398 def second_order_extrapolator(domain): 387 399 """Second order limiter function, specific to the shallow water wave 388 400 equation. … … 406 418 407 419 """ 408 409 #FIXME: Might go elsewhere 410 protect_against_infinitesimal_heights_centroid(domain) 420 421 #FIXME: first and second order migh merge 422 423 from Numeric import minimum, maximum 411 424 412 425 #Update conserved quantities using straight second order 413 426 for name in domain.conserved_quantities: 414 427 Q = domain.quantities[name] 415 Q.second_order_limiter() 416 417 428 429 Q.second_order_extrapolator() 430 Q.limiter() 431 Q.interpolate_from_vertices_to_edges() 432 433 418 434 #Water levels at centroids 419 435 wc = domain.quantities['level'].centroid_values … … 425 441 hc = wc - zc 426 442 427 #Momentums at centroids428 xmomc = domain.quantities['xmomentum'].centroid_values429 ymomc = domain.quantities['ymomentum'].centroid_values430 431 443 #Water levels at vertices 432 #wv = domain.quantities['level'].vertex_values433 # 444 wv = domain.quantities['level'].vertex_values 445 434 446 #Bed elevations at vertices 435 #zv = domain.quantities['elevation'].vertex_values 436 # 437 #Momentums at vertices 438 #xmomv = domain.quantities['xmomentum'].vertex_values 439 #ymomv = domain.quantities['ymomentum'].vertex_values 440 447 zv = domain.quantities['elevation'].vertex_values 448 449 #Water depths at vertices 450 hv = wv-zv 451 452 453 454 #Computed linear combination between constant levels and and 455 #levels parallel to the bed elevation. 456 for k in range(domain.number_of_elements): 457 458 #Compute maximal variation in bed elevation 459 # This quantitiy is 460 # dz = max_i abs(z_i - z_c) 461 # and it is independent of dimension 462 # In the 1d case zc = (z0+z1)/2 463 # In the 2d case zc = (z0+z1+z2)/3 464 # 465 466 z_range = max(abs(zv[k,0]-zc[k]), 467 abs(zv[k,1]-zc[k]), 468 abs(zv[k,2]-zc[k])) 469 470 471 hmin = minimum( hv[k, :] ) 472 473 #Create alpha in [0,1], where alpha==0 means using shallow 474 #first order scheme and alpha==1 means using the limited 475 #second order scheme for the stage w 476 #If hmin < 0 then alpha=0 reverrting to first order. 477 478 if z_range > 0.0: 479 alpha = max( min( 2*hmin/z_range, 1.0), 0.0) 480 else: 481 alpha = 1.0 482 483 #Update water levels 484 # (1-alpha)*(zvi+hc) + alpha*(zvi+hvi) = 485 # zvi + hc + alpha*(hvi - hc) 486 for i in range(3): 487 wv[k,i] = zv[k,i] + hc[k] + alpha*(hv[k,i]-hc[k]) 488 489 490 #Momentums at centroids 491 xmomc = domain.quantities['xmomentum'].centroid_values 492 ymomc = domain.quantities['ymomentum'].centroid_values 493 494 #Momentums at vertices 495 xmomv = domain.quantities['xmomentum'].vertex_values 496 ymomv = domain.quantities['ymomentum'].vertex_values 497 498 # Update momentum as a linear combination of 499 # xmomc and ymomc (shallow) and momentum 500 # from extrapolator xmomv and ymomv (deep). 501 502 503 ##f##or i in range(3): 504 ##### xmomv[k,i] = (1-alpha)*xmomc[k] + alpha*xmomv[k,i]; 505 506 xmomv[k,:] = (1-alpha)*xmomc[k] + alpha*xmomv[k,:]; 507 508 509 #Finally, protect against infinitesimal heights and high speeds 510 #Water depths at vertices 511 hv = wv-zv 512 hc = wc-zc 441 513 for k in range(domain.number_of_elements): 442 #Protect against infinitesimal heights and high velocities 443 if hc[k] < domain.minimum_allowed_height: 444 #Control level and height 514 hmax = maximum(hv[k,:]) 515 516 if hmax < minimum_allowed_height: 517 #Reset negative heights to bed elevation 445 518 if hc[k] < 0.0: 446 wc[k] = zc[k]; hc[k] = 0.0 447 448 #Control momentum as well! 449 xmomc[k] = ymomc[k] = 0.0 450 451 452 #Compute second order limiter for each conserved quantity 453 for name in domain.conserved_quantities: 454 domain.quantities[name].second_order_limiter() 455 456 457 # //Adjusted water heights at vertices 458 # hv0 = qv0[0]-zv0; 459 # hv1 = qv1[0]-zv1; 460 # hv2 = qv2[0]-zv2; 461 462 # hmin = min( min(hv0, hv1), hv2 ); 463 464 # // ----------------------------------- 465 # // Second run - Linear combination with 466 # // first order scheme for shallow depths 467 # // ----------------------------------- 468 469 470 # //Compute maximal variation in bed elevation 471 # // 472 # //This quantitiy is 473 # // dz = max_i abs(z_i - z_c) 474 # //and it is independent of dimension 475 # //In the 1d case zc = (z0+z1)/2 476 # //In the 2d case zc = (z0+z1+z2)/3 477 # // 478 # z_range = max( max(fabs(zv0-zc), fabs(zv1-zc)), fabs(zv2-zc) ); 479 480 # //Create alpha in [0,1], where alpha==0 means using shallow 481 # //first order scheme and alpha==1 means using the limited 482 # //second order scheme for the stage w 483 # //If hmin < 0 then alpha=0 and first order method is 484 # if (z_range>0.0) { 485 # alpha = max( min(2*hmin/z_range, 1.0), 0.0); 486 # } else { 487 # alpha = 1.0; 488 # } 489 490 # if (alpha < 1) { 491 # //Update stage 492 # // 493 # //(1-alpha)*(zvi+hc) + alpha*(zvi+hvi) = 494 # //zvi + hc + alpha*(hvi - hc) 495 # // 496 # qv0[0] = zv0 + hc + alpha*(hv0-hc); 497 # qv1[0] = zv1 + hc + alpha*(hv1-hc); 498 # qv2[0] = zv2 + hc + alpha*(hv2-hc); 499 500 501 # //Update momentum as a linear combination of 502 # //qc[j] (shallow) and momentum from gradient limiter (deep). 503 # for (j=1; j<number_of_conserved_quantities; j++) { 504 # qv0[j] = (1-alpha)*qc[j] + alpha*qv0[j]; 505 # qv1[j] = (1-alpha)*qc[j] + alpha*qv1[j]; 506 # qv2[j] = (1-alpha)*qc[j] + alpha*qv2[j]; 507 # } 508 # } 509 510 511 # //Finally, protect against infinitesimal heights and high speeds 512 # hv0 = qv0[0]-zv0; hv1 = qv1[0]-zv1; hv2 = qv2[0]-zv2; 513 # hmax = max(hv0, max(hv1, hv2)); 514 # if (hmax < minimum_allowed_height) { 515 516 # //Set negative heights to bed elevation 517 # if (hc < 0.0) {qc[0] = zc; hc = 0.0;} 518 # if (hv0 < 0.0) {qv0[0] = zv0; hv0 = 0.0;} 519 # if (hv1 < 0.0) {qv1[0] = zv1; hv1 = 0.0;} 520 # if (hv2 < 0.0) {qv2[0] = zv2; hv2 = 0.0;} 521 522 523 # //FIXME: Do we need this desperately?? 524 # //FIXME: We definitely do encounter negative heights, 525 # //but what about momentum? 526 527 # //Control momentum 528 # //qc[1] = 0.0; qc[2] = 0.0; 529 # //qv0[1] = 0.0; qv0[2] = 0.0; 530 # //qv1[1] = 0.0; qv1[2] = 0.0; 531 # //qv2[1] = 0.0; qv2[2] = 0.0; 532 # } 533 # } 534 535 536 537 538 def limiter_org(k): 539 """limiter function, specific to the shallow water wave equation. 540 It will ensure that h is always non-negative. 541 This version works on the consecutive data structure 542 """ 543 544 #This version should be used to reproduce the bad limiting when levels 545 #are close to bed elevation 546 547 import sys 548 from config import beta 549 from Numeric import ones, Float 550 551 #conserved quantities at centroid 552 qc = Volume.conserved_quantities_centroid[k, :] 553 N = len(qc) 554 555 zc = Volume.field_values_centroid[k,0] #bed elevation at centroid 556 wc = qc[0] #Stage at centroid 557 hc = wc - zc #Water depth at centroid 558 559 #conserved quant. at vertices 560 qv0 = Volume.conserved_quantities_vertex0[k,:] 561 qv1 = Volume.conserved_quantities_vertex1[k,:] 562 qv2 = Volume.conserved_quantities_vertex2[k,:] 563 564 565 #Bed elevation at vertices 566 zv0 = Volume.field_values_vertex0[k,0] 567 zv1 = Volume.field_values_vertex1[k,0] 568 zv2 = Volume.field_values_vertex2[k,0] 569 570 #deltas 571 dq0 = qv0-qc 572 dq1 = qv1-qc 573 dq2 = qv2-qc 574 575 576 #------------------------------------- 577 hmin = hc 578 qmin = qmax = qc 579 for i in range(3): 580 n = Volume.neighbours[k,i] 581 if n >= 0: 582 qn = Volume.conserved_quantities_centroid[n,:] 583 zn = Volume.field_values_centroid[n,0] 584 hn = qn[0]-zn 585 586 hmin = min(hmin, hn) 587 qmin = minimum(qmin, qn) 588 qmax = maximum(qmax, qn) 589 590 hmin = max(hmin,0.0) 591 592 593 #----------------------------------- 594 # First run - limit on conserved quantities 595 # based on neighbouring heights 596 #----------------------------------- 597 598 dqmax = qmax - qc 599 dqmin = qmin - qc 600 phi = ones(len(qc), Float) 601 for j in range(N): 602 #First find the gradient limiter (phi) 603 604 #Vertex0: 605 r = 1.0 606 if dq0[j] > 0: r = dqmax[j]/dq0[j] 607 if dq0[j] < 0: r = dqmin[j]/dq0[j] 608 phi[j] = min( min(r*beta, 1), phi[j] ) 609 610 #Vertex1: 611 r = 1.0 612 if dq1[j] > 0: r = dqmax[j]/dq1[j] 613 if dq1[j] < 0: r = dqmin[j]/dq1[j] 614 phi[j] = min( min(r*beta, 1), phi[j] ) 615 616 #Vertex2: 617 r = 1.0 618 if dq2[j] > 0: r = dqmax[j]/dq2[j] 619 if dq2[j] < 0: r = dqmin[j]/dq2[j] 620 phi[j] = min( min(r*beta, 1), phi[j] ) 621 622 #The update using phi limiter 623 qv0[j] = qc[j] + phi[j]*dq0[j] #Vertex0 624 qv1[j] = qc[j] + phi[j]*dq1[j] #Vertex1 625 qv2[j] = qc[j] + phi[j]*dq2[j] #Vertex2 626 627 628 629 #----------------------------------- 630 # Second run - lower limit on height 631 # based on neighbouring heights for 632 # surfaces constructed below bed 633 #----------------------------------- 634 635 #Adjusted water heights at vertices 636 hv0 = qv0[0]-zv0 637 hv1 = qv1[0]-zv1 638 hv2 = qv2[0]-zv2 639 640 #Deltas 641 dhmin = hmin - hc 642 dh0 = hv0 - hc 643 dh1 = hv1 - hc 644 dh2 = hv2 - hc 645 646 647 #Work out if update is needed and calculate phi limiter 648 phi = 1.0 649 update_needed = False 650 if hv0 < 0.0: 651 update_needed = True 652 r = 1.0 653 if dh0 < 0: r = dhmin/dh0 654 phi = min( min(beta*r, 1), phi ) 655 656 if hv1 < 0.0: 657 update_needed = True 658 r = 1.0 659 if dh1 < 0: r = dhmin/dh1 660 phi = min( min(beta*r, 1), phi ) 661 662 if hv2 < 0.0: 663 update_needed = True 664 r = 1.0 665 if dh2 < 0: r = dhmin/dh2 666 phi = min( min(beta*r, 1), phi ) 667 668 669 #Update stage at vertices 670 if update_needed: 671 hv0 = hc + phi*dh0 672 if hv0 < 0.0: raise 'hv0 = %12f hc = %12f ' % (hv0 , hc) 673 qv0[0] = zv0 + hv0 674 675 hv1 = hc + phi*dh1 676 if hv1 < 0.0: raise 'hv1 = %12f hc = %12f ' % (hv1 , hc) 677 qv1[0] = zv1 + hv1 678 679 hv2 = hc + phi*dh2 680 if hv2 < 0.0: raise 'hv2 = %12f hc = %12f ' % (hv2 , hc) 681 qv2[0] = zv2 + hv2 682 683 684 #In either case protect against infinitesimal heights 685 dry(k) 686 687 def dry(k): 688 """Protect agains infinitesimal heights (and high speeds) 689 There are no states for any conserved quantity when h is 690 between minimum allowed height and 0. 691 """ 692 693 #volume = Volume.instances[k] 694 695 maxhv = 0.0 696 697 wv0 = Volume.conserved_quantities_vertex0[k,0] 698 zv0 = Volume.field_values_vertex0[k,0] 699 hv0 = wv0-zv0 700 701 wv1 = Volume.conserved_quantities_vertex1[k,0] 702 zv1 = Volume.field_values_vertex1[k,0] 703 hv1 = wv1-zv1 704 705 wv2 = Volume.conserved_quantities_vertex2[k,0] 706 zv2 = Volume.field_values_vertex2[k,0] 707 hv2 = wv2-zv2 708 709 maxhv = max(hv0, hv1, hv2) 710 711 if maxhv < minimum_allowed_height: 712 #Set water level to bed elevation and zero momentums. 713 Volume.conserved_quantities_vertex0[k,:] =\ 714 array([Volume.field_values_vertex0[k,0], 0, 0]) 715 716 Volume.conserved_quantities_vertex1[k,:] =\ 717 array([Volume.field_values_vertex1[k,0], 0, 0]) 718 719 Volume.conserved_quantities_vertex2[k,:] =\ 720 array([Volume.field_values_vertex2[k,0], 0, 0]) 721 722 #Set only momentums to zero 723 #Volume.conserved_quantities_vertex0[k,1:] = array([0., 0.]) 724 #Volume.conserved_quantities_vertex1[k,1:] = array([0., 0.]) 725 #Volume.conserved_quantities_vertex2[k,1:] = array([0., 0.]) 726 727 728 729 730 def distribute_to_vertices_and_edges(domain): 731 """Extrapolate conserved quantities from centroid to 732 vertices and edge-midpoints for each volume 733 """ 734 735 from config import minimum_allowed_height 736 737 from mesh import Point 738 order = domain.order 739 740 limiter = domain.limiter 741 if limiter is None: 742 from shallow_water import limit_on_w_then_h as limiter 743 744 745 for k in range(Volume.number_of_instances): 746 747 #conserved quantities at centroid 748 q = Volume.conserved_quantities_centroid[k,:] 749 750 if order == 1: 751 ######################## 752 #NOTE: This is now specific to the shallow water wave equation 753 754 zc = Volume.field_values_centroid[k,0] #bed elevation at centroid 755 wc = q[0] #Stage at centroid 756 hc = wc - zc #Water depth at centroid 757 758 #Protect against infinitesimal heights and high velocities 759 if hc < minimum_allowed_height: 760 #Set momentums to zero 761 q[0] = zc 762 q[1] = 0.0 763 q[2] = 0.0 764 765 766 #Bed elevation at vertices 767 zv0 = Volume.field_values_vertex0[k,0] 768 zv1 = Volume.field_values_vertex1[k,0] 769 zv2 = Volume.field_values_vertex2[k,0] 770 771 #Update conserved quant. at vertices 772 Volume.conserved_quantities_vertex0[k,1:] = q[1:] #Momentum 773 Volume.conserved_quantities_vertex1[k,1:] = q[1:] #Momentum 774 Volume.conserved_quantities_vertex2[k,1:] = q[1:] #Momentum 775 776 #Stage 777 z_range = max( max(abs(zv0-zv1), abs(zv0-zv2)), abs(zv1-zv2) ) 778 if z_range>0: 779 alpha = min(hc/z_range, 1.0) 780 else: 781 alpha = 1 782 783 zz = hc+alpha*zc 784 Volume.conserved_quantities_vertex0[k,0] = zz + (1-alpha)*zv0 785 Volume.conserved_quantities_vertex1[k,0] = zz + (1-alpha)*zv1 786 Volume.conserved_quantities_vertex2[k,0] = zz + (1-alpha)*zv2 787 788 elif order == 2: 789 a, b = compute_gradient(k) 790 791 #Compute extrapolated values at vertices 792 x,y = Point.coordinates[Volume.points[k,3]] #Centroid 793 794 #Get vertex coordinates 795 i = Volume.points[k,0] 796 x0 = Point.coordinates[i,0] 797 y0 = Point.coordinates[i,1] 798 799 i = Volume.points[k,1] 800 x1 = Point.coordinates[i,0] 801 y1 = Point.coordinates[i,1] 802 803 i = Volume.points[k,2] 804 x2 = Point.coordinates[i,0] 805 y2 = Point.coordinates[i,1] 806 807 808 #Extrapolate 809 Volume.conserved_quantities_vertex0[k, :] = q + a*(x0-x) + b*(y0-y) 810 Volume.conserved_quantities_vertex1[k, :] = q + a*(x1-x) + b*(y1-y) 811 Volume.conserved_quantities_vertex2[k, :] = q + a*(x2-x) + b*(y2-y) 812 813 814 if limiter is not None: 815 limiter(k) 816 else: 817 raise 'Unknown order' 818 819 820 #Compute conserved quantities as interpolated 821 #quantities at each edge midpoint 822 q0 = Volume.conserved_quantities_vertex0[k,:] 823 q1 = Volume.conserved_quantities_vertex1[k,:] 824 q2 = Volume.conserved_quantities_vertex2[k,:] 825 826 Volume.conserved_quantities_face0[k,:] = 0.5*(q1 + q2) 827 Volume.conserved_quantities_face1[k,:] = 0.5*(q0 + q2) 828 Volume.conserved_quantities_face2[k,:] = 0.5*(q0 + q1) 519 wc[k] = zc[k] 520 ###hc[k] = 0.0 521 for i in range(3): 522 if hv[k,i] < 0.0: 523 wv[k,i] = zv[k,i] 524 ##hv0 = 0.0;} 525 526 829 527 830 528 … … 869 567 870 568 569 ######################### 570 #Standard forcing terms: 571 572 def gravity(domain): 573 """Implement forcing function for bed slope working with 574 consecutive data structures of class Volume 575 """ 576 577 from config import g 578 from util import gradient 579 from Numeric import zeros, Float, array, sum 580 581 Level = domain.quantities['level'] 582 Xmom = domain.quantities['xmomentum'] 583 Ymom = domain.quantities['ymomentum'] 584 585 Elevation = domain.quantities['elevation'] 586 h = Level.edge_values - Elevation.edge_values 587 V = domain.get_vertex_coordinates() 588 589 for k in range(domain.number_of_elements): 590 avg_h = sum( h[k,:] )/3 591 592 #Compute bed slope 593 x0, y0, x1, y1, x2, y2 = V[k,:] 594 z0, z1, z2 = Elevation.vertex_values[k,:] 595 zx, zy = gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2) 596 597 #Update momentum 598 Xmom.explicit_update[k] += -g*zx*avg_h 599 Ymom.explicit_update[k] += -g*zy*avg_h 600 601 602 def manning_friction(domain): 603 """Apply (Manning) friction to water momentum 604 """ 605 606 import Numeric 607 from math import sqrt 608 from config import g, minimum_allowed_height 609 610 Level = domain.quantities['level'] 611 Xmom = domain.quantities['xmomentum'] 612 Ymom = domain.quantities['ymomentum'] 613 614 Friction = domain.quantities['friction'] 615 616 for k in range(domain.number_of_elements): 617 w = Level.centroid_values[k] 618 uh = Xmom.centroid_values[k] 619 vh = Ymom.centroid_values[k] 620 manning = Friction.centroid_values[k] 621 622 if w >= minimum_allowed_height: 623 S = -g * manning**2 * sqrt((uh**2 + vh**2)) 624 S /= w**(7.0/3) 625 626 #Update momentum 627 Xmom.explicit_update[k] += S*uh 628 Ymom.explicit_update[k] += S*vh 629 871 630 872 631 ##############################################
Note: See TracChangeset
for help on using the changeset viewer.