Changeset 8376
- Timestamp:
- Apr 1, 2012, 11:46:38 PM (13 years ago)
- Location:
- trunk/anuga_core/source/anuga/shallow_water
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/anuga_core/source/anuga/shallow_water/shallow_water_domain.py
r8374 r8376 64 64 SeeAlso: 65 65 TRAC administration of ANUGA (User Manuals etc) at 66 https:// datamining.anu.edu.au/anugaand Subversion repository at67 $HeadURL: https:// datamining.anu.edu.au/svn/anuga/trunk/anuga_core/source/66 https://anuga.anu.edu.au and Subversion repository at 67 $HeadURL: https://anuga.anu.edu.au/svn/anuga/trunk/anuga_core/source/ 68 68 anuga/shallow_water/shallow_water_domain.py $ 69 69 … … 165 165 self.set_defaults() 166 166 167 167 168 #------------------------------- 168 169 # Operators and Forcing Terms 169 170 #------------------------------- 170 171 self.forcing_terms.append(manning_friction_implicit) 171 #self.forcing_terms.append(gravity_ )172 #self.forcing_terms.append(gravity_wb) 172 173 self.forcing_terms.append(gravity) 173 174 … … 219 220 from anuga.config import use_edge_limiter 220 221 from anuga.config import use_centroid_velocities 222 from anuga.config import compute_fluxes_method 221 223 222 224 … … 246 248 self.use_edge_limiter = use_edge_limiter 247 249 self.optimised_gradient_limiter = optimised_gradient_limiter 248 self.use_centroid_velocities = use_centroid_velocities 250 self.use_centroid_velocities = use_centroid_velocities 251 252 self.set_compute_fluxes_method(compute_fluxes_method) 249 253 250 254 … … 274 278 275 279 276 def set_use_edge_limiter(self, flag=True): 277 """Cludge to allow unit test to pass, but to 278 also introduce new edge limiting. The flag is 279 tested in distribute_to_vertices_and_edges. 280 """ 281 if flag: 282 self.use_edge_limiter = True 280 def set_compute_fluxes_method(self, flag='original'): 281 """Set method for computing fluxes. 282 283 Currently 284 'original' 285 'well_balanced_1 286 """ 287 compute_fluxes_methods = ['original', 'well_balanced_1'] 288 289 if flag in compute_fluxes_methods: 290 self.compute_fluxes_method = flag 283 291 else: 284 self.use_edge_limiter = False 292 raise Exception('Unknown compute_fluxes_method') 293 294 295 def get_compute_fluxes_method(self): 296 """Get method for computing fluxes. 297 298 Currently 299 'original' 300 'well_balanced_1 301 """ 302 303 return self.compute_fluxes_method 304 305 285 306 286 307 … … 580 601 581 602 def compute_fluxes(self): 582 """Call correct module function 583 (either from this module or C-extension)""" 584 compute_fluxes(self) 603 """Compute fluxes and timestep suitable for all volumes in domain. 604 605 Compute total flux for each conserved quantity using "flux_function" 606 607 Fluxes across each edge are scaled by edgelengths and summed up 608 Resulting flux is then scaled by area and stored in 609 explicit_update for each of the three conserved quantities 610 stage, xmomentum and ymomentum 611 612 The maximal allowable speed computed by the flux_function for each volume 613 is converted to a timestep that must not be exceeded. The minimum of 614 those is computed as the next overall timestep. 615 616 Post conditions: 617 domain.explicit_update is reset to computed flux values 618 domain.flux_timestep is set to the largest step satisfying all volumes. 619 620 This wrapper calls the underlying C version of compute fluxes 621 """ 622 623 if self.compute_fluxes_method == 'original': 624 from shallow_water_ext import compute_fluxes_ext_central_structure 625 self.flux_timestep = compute_fluxes_ext_central_structure(self) 626 elif self.compute_fluxes_method == 'well_balanced_1': 627 from shallow_water_ext import compute_fluxes_ext_wb 628 self.flux_timestep = compute_fluxes_ext_wb(self) 629 else: 630 raise Exception('unknown compute_fluxes_method') 585 631 586 632 … … 1137 1183 1138 1184 1139 compute_fluxes_ext_central_structure(domain)1185 domain.flux_timestep = compute_fluxes_ext_central_structure(domain) 1140 1186 1141 1187 … … 1358 1404 """ 1359 1405 1360 from shallow_water_ext import gravity_wb _c1406 from shallow_water_ext import gravity_wb as gravity_wb_c 1361 1407 1362 1408 gravity_wb_c(domain) -
trunk/anuga_core/source/anuga/shallow_water/shallow_water_ext.c
r8374 r8376 400 400 } 401 401 402 return 0; 403 } 404 405 // Innermost flux function (using stage w=z+h) 406 int _flux_function_central_wb(double *q_left, double *q_right, 407 double z_left, double h_left, double h1_left, double h2_left, 408 double z_right, double h_right, double h1_right, double h2_right, 409 double n1, double n2, 410 double epsilon, 411 double h0, 412 double limiting_threshold, 413 double g, 414 double *edgeflux, 415 double *max_speed) 416 { 417 418 /*Compute fluxes between volumes for the shallow water wave equation 419 cast in terms of the 'stage', w = h+z using 420 the 'central scheme' as described in 421 422 Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For 423 Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'. 424 Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740. 425 426 The implemented formula is given in equation (3.15) on page 714 427 */ 428 429 430 int i; 431 double hl, hr; 432 double w_left, uh_left, vh_left, u_left; 433 double w_right, uh_right, vh_right, u_right; 434 double s_min, s_max, soundspeed_left, soundspeed_right; 435 double denom, inverse_denominator, z; 436 double p_left, p_right; 437 438 // Workspace (allocate once, use many) 439 static double q_left_rotated[3], q_right_rotated[3], flux_right[3], flux_left[3]; 440 441 // Copy conserved quantities to protect from modification 442 q_left_rotated[0] = q_left[0]; 443 q_right_rotated[0] = q_right[0]; 444 q_left_rotated[1] = q_left[1]; 445 q_right_rotated[1] = q_right[1]; 446 q_left_rotated[2] = q_left[2]; 447 q_right_rotated[2] = q_right[2]; 448 449 // Align x- and y-momentum with x-axis 450 _rotate(q_left_rotated, n1, n2); 451 _rotate(q_right_rotated, n1, n2); 452 453 z = 0.5*(z_left + z_right); // Average elevation values. 454 // Even though this will nominally allow 455 // for discontinuities in the elevation data, 456 // there is currently no numerical support for 457 // this so results may be strange near 458 // jumps in the bed. 459 460 /* 461 printf("ql[0] %g\n",q_left[0]); 462 printf("ql[1] %g\n",q_left[1]); 463 printf("ql[2] %g\n",q_left[2]); 464 printf("h_left %g\n",h_left); 465 printf("z_left %g\n",z_left); 466 printf("z %g\n",z); 467 printf("qlr[0] %g\n",q_left_rotated[0]); 468 printf("qlr[1] %g\n",q_left_rotated[1]); 469 printf("qlr[2] %g\n",q_left_rotated[2]); 470 */ 471 472 // Compute speeds in x-direction 473 w_left = q_left_rotated[0]; 474 hl = w_left - z; 475 /* 476 printf("w_left %g\n",w_left); 477 printf("hl %g\n",hl); 478 printf("hl-h_left %g\n",hl-h_left); 479 */ 480 uh_left = q_left_rotated[1]; 481 u_left = _compute_speed(&uh_left, &h_left, 482 epsilon, h0, limiting_threshold); 483 484 w_right = q_right_rotated[0]; 485 h_right = w_right - z; 486 uh_right = q_right_rotated[1]; 487 u_right = _compute_speed(&uh_right, &h_right, 488 epsilon, h0, limiting_threshold); 489 490 // Momentum in y-direction 491 vh_left = q_left_rotated[2]; 492 vh_right = q_right_rotated[2]; 493 494 // Limit y-momentum if necessary 495 // Leaving this out, improves speed significantly (Ole 27/5/2009) 496 // All validation tests pass, so do we really need it anymore? 497 _compute_speed(&vh_left, &h_left, 498 epsilon, h0, limiting_threshold); 499 _compute_speed(&vh_right, &h_right, 500 epsilon, h0, limiting_threshold); 501 502 // Maximal and minimal wave speeds 503 soundspeed_left = sqrt(g*h_left); 504 soundspeed_right = sqrt(g*h_right); 505 506 // Code to use fast square root optimisation if desired. 507 // Timings on AMD 64 for the Okushiri profile gave the following timings 508 // 509 // SQRT Total Flux 510 //============================= 511 // 512 // Ref 405s 152s 513 // Fast (dbl) 453s 173s 514 // Fast (sng) 437s 171s 515 // 516 // Consequently, there is currently (14/5/2009) no reason to use this 517 // approximation. 518 519 //soundspeed_left = fast_squareroot_approximation(g*h_left); 520 //soundspeed_right = fast_squareroot_approximation(g*h_right); 521 522 s_max = max(u_left + soundspeed_left, u_right + soundspeed_right); 523 if (s_max < 0.0) 524 { 525 s_max = 0.0; 526 } 527 528 s_min = min(u_left - soundspeed_left, u_right - soundspeed_right); 529 if (s_min > 0.0) 530 { 531 s_min = 0.0; 532 } 533 534 535 536 //p_left = 0.5*g*h_left*h_left; 537 //p_right = 0.5*g*h_right*h_right; 538 539 p_left = 0.5*g/6.0*(h1_left*h1_left + 4.0*h_left*h_left + h2_left*h2_left); 540 p_right = 0.5*g/6.0*(h1_right*h1_right + 4.0*h_right*h_right + h2_right*h2_right); 541 542 // Flux formulas 543 flux_left[0] = u_left*h_left; 544 flux_left[1] = u_left*uh_left + p_left; 545 flux_left[2] = u_left*vh_left; 546 547 flux_right[0] = u_right*h_right; 548 flux_right[1] = u_right*uh_right + p_right; 549 flux_right[2] = u_right*vh_right; 550 551 // Flux computation 552 denom = s_max - s_min; 553 if (denom < epsilon) 554 { // FIXME (Ole): Try using h0 here 555 memset(edgeflux, 0, 3*sizeof(double)); 556 *max_speed = 0.0; 557 } 558 else 559 { 560 inverse_denominator = 1.0/denom; 561 for (i = 0; i < 3; i++) 562 { 563 edgeflux[i] = s_max*flux_left[i] - s_min*flux_right[i]; 564 edgeflux[i] += s_max*s_min*(q_right_rotated[i] - q_left_rotated[i]); 565 edgeflux[i] *= inverse_denominator; 566 } 567 568 // Maximal wavespeed 569 *max_speed = max(fabs(s_max), fabs(s_min)); 570 571 // Rotate back 572 _rotate(edgeflux, n1, -n2); 573 } 574 575 return 0; 576 } 577 578 579 // Innermost flux function (using stage w=z+h) 580 int _flux_function_central_wb_old(double *q_left, double *q_right, 581 double z_left, double h_left, double h1_left, double h2_left, 582 double z_right, double h_right, double h1_right, double h2_right, 583 double n1, double n2, 584 double epsilon, 585 double h0, 586 double limiting_threshold, 587 double g, 588 double *edgeflux, 589 double *max_speed) 590 { 591 592 /*Compute fluxes between volumes for the shallow water wave equation 593 cast in terms of the 'stage', w = h+z using 594 the 'central scheme' as described in 595 596 Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For 597 Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'. 598 Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740. 599 600 The implemented formula is given in equation (3.15) on page 714 601 */ 602 603 int i; 604 605 double uh_left, vh_left, u_left; 606 double uh_right, vh_right, u_right; 607 double p_left, p_right; 608 double s_min, s_max, soundspeed_left, soundspeed_right; 609 double denom, inverse_denominator; 610 611 // Workspace (allocate once, use many) 612 static double q_left_rotated[3], q_right_rotated[3], flux_right[3], flux_left[3]; 613 614 // Copy conserved quantities to protect from modification 615 q_left_rotated[0] = q_left[0]; 616 q_right_rotated[0] = q_right[0]; 617 q_left_rotated[1] = q_left[1]; 618 q_right_rotated[1] = q_right[1]; 619 q_left_rotated[2] = q_left[2]; 620 q_right_rotated[2] = q_right[2]; 621 622 // Align x- and y-momentum with x-axis 623 _rotate(q_left_rotated, n1, n2); 624 _rotate(q_right_rotated, n1, n2); 625 626 //printf("zr-zl %g\n",z_right-z_left); 627 628 // Compute left and right speeds in x-direction 629 uh_left = q_left_rotated[1]; 630 u_left = _compute_speed(&uh_left, &h_left, 631 epsilon, h0, limiting_threshold); 632 633 uh_right = q_right_rotated[1]; 634 u_right = _compute_speed(&uh_right, &h_right, 635 epsilon, h0, limiting_threshold); 636 637 // Momentum in y-direction 638 vh_left = q_left_rotated[2]; 639 vh_right = q_right_rotated[2]; 640 641 642 // Maximal and minimal wave speeds 643 soundspeed_left = sqrt(g*h_left); 644 soundspeed_right = sqrt(g*h_right); 645 646 647 s_max = max(u_left + soundspeed_left, u_right + soundspeed_right); 648 if (s_max < 0.0) 649 { 650 s_max = 0.0; 651 } 652 653 s_min = min(u_left - soundspeed_left, u_right - soundspeed_right); 654 if (s_min > 0.0) 655 { 656 s_min = 0.0; 657 } 658 659 // Calculate pressure terms using Simpson's rule (exact for pw linear) 660 p_left = 0.5*g/6.0*(h1_left*h1_left + 4.0*h_left*h_left + h2_left*h2_left); 661 p_right = 0.5*g/6.0*(h1_right*h1_right + 4.0*h_right*h_right + h2_right*h2_right); 662 663 p_left = 0.5*g*h_left*h_left; 664 p_right = 0.5*g*h_right*h_right; 665 666 // Flux formulas 667 flux_left[0] = u_left*h_left; 668 flux_left[1] = u_left*uh_left + p_left; 669 flux_left[2] = u_left*vh_left; 670 671 flux_right[0] = u_right*h_right; 672 flux_right[1] = u_right*uh_right + p_right; 673 flux_right[2] = u_right*vh_right; 674 675 // Flux computation 676 denom = s_max - s_min; 677 if (denom < epsilon) 678 { // FIXME (Ole): Try using h0 here 679 memset(edgeflux, 0, 3*sizeof(double)); 680 *max_speed = 0.0; 681 } 682 else 683 { 684 inverse_denominator = 1.0/denom; 685 for (i = 0; i < 3; i++) 686 { 687 edgeflux[i] = s_max*flux_left[i] - s_min*flux_right[i]; 688 edgeflux[i] += s_max*s_min*(q_right_rotated[i] - q_left_rotated[i]); 689 edgeflux[i] *= inverse_denominator; 690 } 691 692 // Maximal wavespeed 693 *max_speed = max(fabs(s_max), fabs(s_min)); 694 695 // Rotate back 696 _rotate(edgeflux, n1, -n2); 697 } 698 402 699 return 0; 403 700 } … … 1243 1540 double g, avg_h, wx, wy, fact; 1244 1541 double x0, y0, x1, y1, x2, y2; 1245 double h[3]; 1246 double w[3]; 1542 double h0,h1,h2; 1543 double hh[3]; 1544 double w0,w1,w2; 1247 1545 double sidex, sidey; 1248 1546 double n0, n1; … … 1269 1567 //------------------------------------ 1270 1568 1271 // Get vertex bedvalues for gradient calculation1272 w [0]= D.stage_vertex_values[k3 + 0];1273 w [1]= D.stage_vertex_values[k3 + 1];1274 w [2]= D.stage_vertex_values[k3 + 2];1569 // Get vertex stage values for gradient calculation 1570 w0 = D.stage_vertex_values[k3 + 0]; 1571 w1 = D.stage_vertex_values[k3 + 1]; 1572 w2 = D.stage_vertex_values[k3 + 2]; 1275 1573 1276 1574 // Compute stage slope … … 1285 1583 1286 1584 //printf("x0 %g, y0 %g, x1 %g, y1 %g, x2 %g, y2 %g \n",x0,y0,x1,y1,x2,y2); 1287 _gradient(x0, y0, x1, y1, x2, y2, w [0], w[1], w[2], &wx, &wy);1585 _gradient(x0, y0, x1, y1, x2, y2, w0, w1, w2, &wx, &wy); 1288 1586 1289 1587 avg_h = D.stage_centroid_values[k] - D.bed_centroid_values[k]; … … 1298 1596 1299 1597 // Get edge depths 1300 h[0] = D.stage_edge_values[k3 + 0] - D.bed_edge_values[k3 + 0]; 1301 h[1] = D.stage_edge_values[k3 + 1] - D.bed_edge_values[k3 + 1]; 1302 h[2] = D.stage_edge_values[k3 + 2] - D.bed_edge_values[k3 + 2]; 1303 1598 hh[0] = D.stage_edge_values[k3 + 0] - D.bed_edge_values[k3 + 0]; 1599 hh[1] = D.stage_edge_values[k3 + 1] - D.bed_edge_values[k3 + 1]; 1600 hh[2] = D.stage_edge_values[k3 + 2] - D.bed_edge_values[k3 + 2]; 1601 1602 1603 printf("h0,1,2 %f %f %f\n",hh[0],hh[1],hh[2]); 1604 1304 1605 // Calculate the side correction term 1305 1606 sidex = 0.0; … … 1308 1609 n0 = D.normals[k6+2*i]; 1309 1610 n1 = D.normals[k6+2*i+1]; 1310 fact = 0.5*g*D.edgelengths[k3+i]*h[i]*h[i]; 1311 sidex += fact*n0; 1312 sidey += fact*n1; 1611 1612 printf("n0, n1 %i %g %g\n",i,n0,n1); 1613 fact = 0.5*g*hh[i]*hh[i]*D.edgelengths[k3+i]; 1614 sidex = sidex + fact*n0; 1615 sidey = sidey + fact*n1; 1313 1616 } 1314 1617 1315 1618 // Update momentum with side terms 1316 D.xmom_explicit_update[k] +=sidex;1317 D.ymom_explicit_update[k] +=sidey;1619 D.xmom_explicit_update[k] =- sidex; 1620 D.ymom_explicit_update[k] =- sidey; 1318 1621 1319 1622 } … … 2431 2734 2432 2735 2433 int_compute_fluxes_central_structure(struct domain *D) {2736 double _compute_fluxes_central_structure(struct domain *D) { 2434 2737 2435 2738 // Local variables … … 2603 2906 2604 2907 2605 D->flux_timestep = timestep; 2606 2607 return 0; 2908 return timestep; 2608 2909 } 2910 2911 double _compute_fluxes_central_wb(struct domain *D) { 2912 2913 // Local variables 2914 double max_speed, length, inv_area, zl, zr; 2915 double timestep = 1.0e30; 2916 double h0 = D->H0*D->H0; // This ensures a good balance when h approaches H0. 2917 2918 double limiting_threshold = 10 * D->H0; // Avoid applying limiter below this 2919 // threshold for performance reasons. 2920 // See ANUGA manual under flux limiting 2921 int k, i, m, n; 2922 int k3, k3i, k3i1, k3i2, k2i; // Index short hands 2923 2924 int n3m = 0, n3m1, n3m2; // Index short hand for neightbours 2925 2926 double hl, hl1, hl2; 2927 double hr, hr1, hr2; 2928 2929 // Workspace (making them static actually made function slightly slower (Ole)) 2930 double ql[3], qr[3], edgeflux[3]; // Work array for summing up fluxes 2931 2932 static long call = 1; // Static local variable flagging already computed flux 2933 2934 // Start computation 2935 call++; // Flag 'id' of flux calculation for this timestep 2936 2937 2938 timestep = D->evolve_max_timestep; 2939 2940 // Set explicit_update to zero for all conserved_quantities. 2941 // This assumes compute_fluxes called before forcing terms 2942 memset((char*) D->stage_explicit_update, 0, D->number_of_elements * sizeof (double)); 2943 memset((char*) D->xmom_explicit_update, 0, D->number_of_elements * sizeof (double)); 2944 memset((char*) D->ymom_explicit_update, 0, D->number_of_elements * sizeof (double)); 2945 2946 // For all triangles 2947 for (k = 0; k < D->number_of_elements; k++) { 2948 // Loop through neighbours and compute edge flux for each 2949 for (i = 0; i < 3; i++) { 2950 k3 = 3*k; 2951 k3i = k3 + i; // Linear index to edge i of triangle k 2952 k3i1 = k3 + (i+1)%3; 2953 k3i2 = k3 + (i+2)%3; 2954 2955 if (D->already_computed_flux[k3i] == call) { 2956 // We've already computed the flux across this edge 2957 continue; 2958 } 2959 2960 2961 // Get the inside values at the vertices from the triangle k, edge i 2962 ql[0] = D->stage_edge_values[k3i]; 2963 ql[1] = D->xmom_edge_values[k3i]; 2964 ql[2] = D->ymom_edge_values[k3i]; 2965 2966 zl = D->bed_edge_values[k3i]; 2967 hl = D->stage_edge_values[k3i] - zl; 2968 2969 hl1 = D->stage_vertex_values[k3i1] - D->bed_vertex_values[k3i1]; 2970 hl2 = D->stage_vertex_values[k3i2] - D->bed_vertex_values[k3i2]; 2971 2972 // Get right hand side values either from neighbouring triangle 2973 // or from boundary array (Quantities at neighbour on nearest face). 2974 n = D->neighbours[k3i]; 2975 if (n < 0) { 2976 // Neighbour is a boundary condition 2977 m = -n - 1; // Convert negative flag to boundary index 2978 2979 qr[0] = D->stage_boundary_values[m]; 2980 qr[1] = D->xmom_boundary_values[m]; 2981 qr[2] = D->ymom_boundary_values[m]; 2982 2983 zr = zl; // Extend bed elevation to boundary and assume flat 2984 hr = D->stage_boundary_values[m] - zr; 2985 hr1 = hr; 2986 hr2 = hr; 2987 2988 } 2989 else { 2990 // Neighbour is a real triangle 2991 m = D->neighbour_edges[k3i]; 2992 n3m = 3*n + m; // Linear index (triangle n, edge m) 2993 n3m1 = 3*n + (m+1)%3; 2994 n3m2 = 3*n + (m+2)%3; 2995 2996 qr[0] = D->stage_edge_values[n3m]; 2997 qr[1] = D->xmom_edge_values[n3m]; 2998 qr[2] = D->ymom_edge_values[n3m]; 2999 3000 zr = D->bed_edge_values[n3m]; 3001 hr = D->stage_edge_values[n3m] - zr; 3002 3003 hr1 = D->stage_vertex_values[n3m2] - D->bed_vertex_values[n3m2]; 3004 hr2 = D->stage_vertex_values[n3m1] - D->bed_vertex_values[n3m1]; 3005 3006 } 3007 3008 // Now we have values for this edge - both from left and right side. 3009 3010 if (D->optimise_dry_cells) { 3011 // Check if flux calculation is necessary across this edge 3012 // This check will exclude dry cells. 3013 // This will also optimise cases where zl != zr as 3014 // long as both are dry 3015 3016 if (fabs(ql[0] - zl) < D->epsilon && 3017 fabs(qr[0] - zr) < D->epsilon) { 3018 // Cell boundary is dry 3019 3020 D->already_computed_flux[k3i] = call; // #k Done 3021 if (n >= 0) { 3022 D->already_computed_flux[n3m] = call; // #n Done 3023 } 3024 3025 max_speed = 0.0; 3026 continue; 3027 } 3028 } 3029 3030 3031 if (fabs(zl-zr)>1.0e-10) { 3032 report_python_error(AT,"Discontinuous Elevation"); 3033 return 0.0; 3034 } 3035 3036 // Outward pointing normal vector (domain.normals[k, 2*i:2*i+2]) 3037 k2i = 2 * k3i; //k*6 + i*2 3038 3039 3040 3041 /* 3042 _flux_function_central(ql, qr, zl, zr, 3043 D->normals[k2i], D->normals[k2i + 1], 3044 D->epsilon, h0, limiting_threshold, D->g, 3045 edgeflux, &max_speed); 3046 */ 3047 3048 // Edge flux computation (triangle k, edge i) 3049 3050 _flux_function_central_wb(ql, qr, 3051 zl, hl, hl1, hl2, 3052 zr, hr, hr1, hr2, 3053 D->normals[k2i], D->normals[k2i + 1], 3054 D->epsilon, h0, limiting_threshold, D->g, 3055 edgeflux, &max_speed); 3056 3057 3058 3059 // Multiply edgeflux by edgelength 3060 length = D->edgelengths[k3i]; 3061 edgeflux[0] *= length; 3062 edgeflux[1] *= length; 3063 edgeflux[2] *= length; 3064 3065 3066 // Update triangle k with flux from edge i 3067 D->stage_explicit_update[k] -= edgeflux[0]; 3068 D->xmom_explicit_update[k] -= edgeflux[1]; 3069 D->ymom_explicit_update[k] -= edgeflux[2]; 3070 3071 D->already_computed_flux[k3i] = call; // #k Done 3072 3073 3074 // Update neighbour n with same flux but reversed sign 3075 if (n >= 0) { 3076 D->stage_explicit_update[n] += edgeflux[0]; 3077 D->xmom_explicit_update[n] += edgeflux[1]; 3078 D->ymom_explicit_update[n] += edgeflux[2]; 3079 3080 D->already_computed_flux[n3m] = call; // #n Done 3081 } 3082 3083 // Update timestep based on edge i and possibly neighbour n 3084 if (D->tri_full_flag[k] == 1) { 3085 if (max_speed > D->epsilon) { 3086 // Apply CFL condition for triangles joining this edge (triangle k and triangle n) 3087 3088 // CFL for triangle k 3089 timestep = min(timestep, D->radii[k] / max_speed); 3090 3091 if (n >= 0) { 3092 // Apply CFL condition for neigbour n (which is on the ith edge of triangle k) 3093 timestep = min(timestep, D->radii[n] / max_speed); 3094 } 3095 3096 // Ted Rigby's suggested less conservative version 3097 //if (n>=0) { 3098 // timestep = min(timestep, (radii[k]+radii[n])/max_speed); 3099 //} else { 3100 // timestep = min(timestep, radii[k]/max_speed); 3101 // } 3102 } 3103 } 3104 3105 } // End edge i (and neighbour n) 3106 3107 3108 // Normalise triangle k by area and store for when all conserved 3109 // quantities get updated 3110 inv_area = 1.0 / D->areas[k]; 3111 D->stage_explicit_update[k] *= inv_area; 3112 D->xmom_explicit_update[k] *= inv_area; 3113 D->ymom_explicit_update[k] *= inv_area; 3114 3115 3116 // Keep track of maximal speeds 3117 D->max_speed[k] = max_speed; 3118 3119 } // End triangle k 3120 3121 3122 return timestep; 3123 } 3124 2609 3125 2610 3126 … … 2949 3465 struct domain D; 2950 3466 PyObject *domain; 3467 double timestep; 2951 3468 2952 3469 if (!PyArg_ParseTuple(args, "O", &domain)) { … … 2961 3478 // Call underlying flux computation routine and update 2962 3479 // the explicit update arrays 2963 _compute_fluxes_central_structure(&D);2964 2965 2966 return Py_BuildValue(" ");3480 timestep = _compute_fluxes_central_structure(&D); 3481 3482 3483 return Py_BuildValue("d", timestep); 2967 3484 } 3485 3486 3487 3488 PyObject *compute_fluxes_ext_wb(PyObject *self, PyObject *args) { 3489 /*Compute all fluxes and the timestep suitable for all volumes 3490 in domain. 3491 3492 Compute total flux for each conserved quantity using "flux_function_central" 3493 3494 Fluxes across each edge are scaled by edgelengths and summed up 3495 Resulting flux is then scaled by area and stored in 3496 explicit_update for each of the three conserved quantities 3497 stage, xmomentum and ymomentum 3498 3499 The 3500 3501 The maximal allowable speed computed by the flux_function for each volume 3502 is converted to a timestep that must not be exceeded. The minimum of 3503 those is computed as the next overall timestep. 3504 3505 Python call: 3506 domain.timestep = compute_fluxes_ext_wb(domain, timestep) 3507 3508 3509 Post conditions: 3510 domain.explicit_update is reset to computed flux values 3511 3512 Returns: 3513 timestep which is the largest step satisfying all volumes. 3514 3515 3516 */ 3517 3518 struct domain D; 3519 PyObject *domain; 3520 double timestep; 3521 3522 if (!PyArg_ParseTuple(args, "O", &domain)) { 3523 report_python_error(AT, "could not parse input arguments"); 3524 return NULL; 3525 } 3526 3527 // populate the C domain structure with pointers 3528 // to the python domain data 3529 get_python_domain(&D,domain); 3530 3531 // Call underlying flux computation routine and update 3532 // the explicit update arrays 3533 timestep = _compute_fluxes_central_wb(&D); 3534 3535 3536 return Py_BuildValue("d", timestep); 3537 } 3538 2968 3539 2969 3540 … … 3355 3926 {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"}, 3356 3927 {"extrapolate_second_order_sw", extrapolate_second_order_sw, METH_VARARGS, "Print out"}, 3928 {"compute_fluxes_ext_wb", compute_fluxes_ext_wb, METH_VARARGS, "Print out"}, 3357 3929 {"compute_fluxes_ext_central", compute_fluxes_ext_central, METH_VARARGS, "Print out"}, 3358 3930 {"compute_fluxes_ext_central_structure", compute_fluxes_ext_central_structure, METH_VARARGS, "Print out"}, -
trunk/anuga_core/source/anuga/shallow_water/sw_domain.h
r8374 r8376 11 11 // structure 12 12 struct domain { 13 // Changing these don't change the data in python object 13 14 long number_of_elements; 14 15 double epsilon; … … 17 18 long optimise_dry_cells; 18 19 double evolve_max_timestep; 19 double flux_timestep;20 20 21 // The values in the python object will be changed 21 22 long* neighbours; 22 23 long* neighbour_edges; … … 82 83 D->evolve_max_timestep = get_python_double(domain, "evolve_max_timestep"); 83 84 84 D->flux_timestep = get_python_double(domain, "flux_timestep");85 86 85 neighbours = get_consecutive_array(domain, "neighbours"); 87 86 D->neighbours = (long *) neighbours->data; -
trunk/anuga_core/source/anuga/shallow_water/test_shallow_water_domain.py
r8164 r8376 692 692 assert num.allclose(t, q[0]), msg 693 693 694 def test_compute_fluxes 0(self):694 def test_compute_fluxes_structure_0(self): 695 695 # Do a full triangle and check that fluxes cancel out for 696 696 # the constant stage case … … 775 775 assert num.allclose(e0*edgeflux0 + e1*edgeflux1 + e2*edgeflux2, 0.) 776 776 777 778 from shallow_water_ext import compute_fluxes_ext_central_structure as compute_fluxes 777 779 # Now check that compute_flux yields zeros as well 778 domain.compute_fluxes()780 compute_fluxes(domain) 779 781 780 782 for name in ['stage', 'xmomentum', 'ymomentum']: 781 783 assert num.allclose(domain.quantities[name].explicit_update[1], 0) 782 784 783 def test_compute_fluxes 1(self):785 def test_compute_fluxes_structure_1(self): 784 786 #Use values from previous version 785 787 a = [0.0, 0.0] … … 868 870 assert num.allclose(total_flux, [-0.68218178, -166.6, -35.93333333]) 869 871 870 domain.compute_fluxes() 872 873 874 from shallow_water_ext import compute_fluxes_ext_central_structure as compute_fluxes 875 # Now check that compute_flux yields zeros as well 876 compute_fluxes(domain) 877 871 878 872 879 for i, name in enumerate(['stage', 'xmomentum', 'ymomentum']): … … 881 888 [-69.68888889, -35.93333333, 0., 69.68888889]) 882 889 883 def test_compute_fluxes 2(self):890 def test_compute_fluxes_structure_2(self): 884 891 #Random values, incl momentum 885 892 a = [0.0, 0.0] … … 952 959 e2*edgeflux2) / domain.areas[1] 953 960 954 domain.compute_fluxes() 961 962 from shallow_water_ext import compute_fluxes_ext_central_structure as compute_fluxes 963 # Now check that compute_flux yields zeros as well 964 compute_fluxes(domain) 955 965 956 966 for i, name in enumerate(['stage', 'xmomentum', 'ymomentum']): … … 959 969 960 970 # FIXME (Ole): Need test like this for fluxes in very shallow water. 961 def test_compute_fluxes 3(self):971 def test_compute_fluxes_structure_3(self): 962 972 #Random values, incl momentum 963 973 a = [0.0, 0.0] … … 980 990 981 991 zl = zr = -3.75 # Assume constant bed (must be less than stage) 982 domain.set_quantity('elevation', zl*num.ones((4, 3), num. int)) #array default#992 domain.set_quantity('elevation', zl*num.ones((4, 3), num.float)) #array default# 983 993 984 994 edgeflux = num.zeros(3, num.float) … … 1031 1041 e2*edgeflux2) / domain.areas[1] 1032 1042 1043 1044 from shallow_water_ext import compute_fluxes_ext_central_structure as compute_fluxes 1045 # Now check that compute_flux yields zeros as well 1046 flux_timestep = compute_fluxes(domain) 1047 1048 #domain.compute_fluxes() 1049 1050 #print domain.flux_timestep 1051 assert num.allclose(flux_timestep, 0.0426244319785) 1052 1053 1054 1055 for i, name in enumerate(['stage', 'xmomentum', 'ymomentum']): 1056 #print total_flux[i] 1057 assert num.allclose(total_flux[i], 1058 domain.quantities[name].explicit_update[1]) 1059 1060 1061 def test_compute_fluxes_old_0(self): 1062 # Do a full triangle and check that fluxes cancel out for 1063 # the constant stage case 1064 1065 a = [0.0, 0.0] 1066 b = [0.0, 2.0] 1067 c = [2.0, 0.0] 1068 d = [0.0, 4.0] 1069 e = [2.0, 2.0] 1070 f = [4.0, 0.0] 1071 1072 points = [a, b, c, d, e, f] 1073 # bac, bce, ecf, dbe 1074 vertices = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]] 1075 1076 domain = Domain(points, vertices) 1077 domain.set_quantity('stage', [[2,2,2], [2,2,2], [2,2,2], [2,2,2]]) 1078 domain.check_integrity() 1079 1080 assert num.allclose(domain.neighbours, 1081 [[-1,1,-2], [2,3,0], [-3,-4,1],[1,-5,-6]]) 1082 assert num.allclose(domain.neighbour_edges, 1083 [[-1,2,-1], [2,0,1], [-1,-1,0],[1,-1,-1]]) 1084 1085 zl = zr = 0. # Assume flat bed 1086 1087 edgeflux = num.zeros(3, num.float) 1088 edgeflux0 = num.zeros(3, num.float) 1089 edgeflux1 = num.zeros(3, num.float) 1090 edgeflux2 = num.zeros(3, num.float) 1091 H0 = 0.0 1092 1093 # Flux across right edge of volume 1 1094 normal = domain.get_normal(1, 0) 1095 ql = domain.get_conserved_quantities(vol_id=1, edge=0) 1096 qr = domain.get_conserved_quantities(vol_id=2, edge=2) 1097 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux0, 1098 epsilon, g, H0) 1099 1100 # Check that flux seen from other triangles is inverse 1101 (ql, qr) = (qr, ql) 1102 normal = domain.get_normal(2, 2) 1103 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux, 1104 epsilon, g, H0) 1105 1106 assert num.allclose(edgeflux0 + edgeflux, 0.) 1107 1108 # Flux across upper edge of volume 1 1109 normal = domain.get_normal(1, 1) 1110 ql = domain.get_conserved_quantities(vol_id=1, edge=1) 1111 qr = domain.get_conserved_quantities(vol_id=3, edge=0) 1112 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux1, 1113 epsilon, g, H0) 1114 1115 # Check that flux seen from other triangles is inverse 1116 (ql, qr) = (qr, ql) 1117 normal = domain.get_normal(3, 0) 1118 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux, 1119 epsilon, g, H0) 1120 1121 assert num.allclose(edgeflux1 + edgeflux, 0.) 1122 1123 # Flux across lower left hypotenuse of volume 1 1124 normal = domain.get_normal(1, 2) 1125 ql = domain.get_conserved_quantities(vol_id=1, edge=2) 1126 qr = domain.get_conserved_quantities(vol_id=0, edge=1) 1127 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux2, 1128 epsilon, g, H0) 1129 1130 # Check that flux seen from other triangles is inverse 1131 (ql, qr) = (qr, ql) 1132 normal = domain.get_normal(0, 1) 1133 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux, 1134 epsilon, g, H0) 1135 assert num.allclose(edgeflux2 + edgeflux, 0.) 1136 1137 # Scale by edgelengths, add up anc check that total flux is zero 1138 e0 = domain.edgelengths[1, 0] 1139 e1 = domain.edgelengths[1, 1] 1140 e2 = domain.edgelengths[1, 2] 1141 1142 assert num.allclose(e0*edgeflux0 + e1*edgeflux1 + e2*edgeflux2, 0.) 1143 1144 # Now check that compute_flux yields zeros as well 1145 domain.compute_fluxes() 1146 1147 for name in ['stage', 'xmomentum', 'ymomentum']: 1148 assert num.allclose(domain.quantities[name].explicit_update[1], 0) 1149 1150 def test_compute_fluxes_old_1(self): 1151 #Use values from previous version 1152 a = [0.0, 0.0] 1153 b = [0.0, 2.0] 1154 c = [2.0, 0.0] 1155 d = [0.0, 4.0] 1156 e = [2.0, 2.0] 1157 f = [4.0, 0.0] 1158 1159 points = [a, b, c, d, e, f] 1160 # bac, bce, ecf, dbe 1161 vertices = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]] 1162 1163 domain = Domain(points, vertices) 1164 val0 = 2. + 2.0/3 1165 val1 = 4. + 4.0/3 1166 val2 = 8. + 2.0/3 1167 val3 = 2. + 8.0/3 1168 1169 domain.set_quantity('stage', [[val0, val0, val0], [val1, val1, val1], 1170 [val2, val2, val2], [val3, val3, val3]]) 1171 domain.check_integrity() 1172 1173 zl = zr = 0. # Assume flat bed 1174 1175 edgeflux = num.zeros(3, num.float) 1176 edgeflux0 = num.zeros(3, num.float) 1177 edgeflux1 = num.zeros(3, num.float) 1178 edgeflux2 = num.zeros(3, num.float) 1179 H0 = 0.0 1180 1181 # Flux across right edge of volume 1 1182 normal = domain.get_normal(1, 0) # Get normal 0 of triangle 1 1183 assert num.allclose(normal, [1, 0]) 1184 1185 ql = domain.get_conserved_quantities(vol_id=1, edge=0) 1186 assert num.allclose(ql, [val1, 0, 0]) 1187 1188 qr = domain.get_conserved_quantities(vol_id=2, edge=2) 1189 assert num.allclose(qr, [val2, 0, 0]) 1190 1191 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux0, 1192 epsilon, g, H0) 1193 1194 # Flux across edge in the east direction (as per normal vector) 1195 assert num.allclose(edgeflux0, [-15.3598804, 253.71111111, 0.]) 1196 assert num.allclose(max_speed, 9.21592824046) 1197 1198 #Flux across edge in the west direction (opposite sign for xmomentum) 1199 normal_opposite = domain.get_normal(2, 2) # Get normal 2 of triangle 2 1200 assert num.allclose(normal_opposite, [-1, 0]) 1201 1202 max_speed = flux_function(normal_opposite, ql, qr, zl, zr, edgeflux, 1203 epsilon, g, H0) 1204 assert num.allclose(edgeflux, [-15.3598804, -253.71111111, 0.]) 1205 1206 #Flux across upper edge of volume 1 1207 normal = domain.get_normal(1, 1) 1208 ql = domain.get_conserved_quantities(vol_id=1, edge=1) 1209 qr = domain.get_conserved_quantities(vol_id=3, edge=0) 1210 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux1, 1211 epsilon, g, H0) 1212 1213 assert num.allclose(edgeflux1, [2.4098563, 0., 123.04444444]) 1214 assert num.allclose(max_speed, 7.22956891292) 1215 1216 #Flux across lower left hypotenuse of volume 1 1217 normal = domain.get_normal(1, 2) 1218 ql = domain.get_conserved_quantities(vol_id=1, edge=2) 1219 qr = domain.get_conserved_quantities(vol_id=0, edge=1) 1220 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux2, 1221 epsilon, g, H0) 1222 1223 assert num.allclose(edgeflux2, [9.63942522, -61.59685738, -61.59685738]) 1224 assert num.allclose(max_speed, 7.22956891292) 1225 1226 #Scale, add up and check that compute_fluxes is correct for vol 1 1227 e0 = domain.edgelengths[1, 0] 1228 e1 = domain.edgelengths[1, 1] 1229 e2 = domain.edgelengths[1, 2] 1230 1231 total_flux = -(e0*edgeflux0 + 1232 e1*edgeflux1 + 1233 e2*edgeflux2) / domain.areas[1] 1234 1235 assert num.allclose(total_flux, [-0.68218178, -166.6, -35.93333333]) 1236 1033 1237 domain.compute_fluxes() 1034 1238 … … 1036 1240 assert num.allclose(total_flux[i], 1037 1241 domain.quantities[name].explicit_update[1]) 1242 1243 assert num.allclose(domain.quantities['stage'].explicit_update, 1244 [0., -0.68218178, -111.77316251, -35.68522449]) 1245 assert num.allclose(domain.quantities['xmomentum'].explicit_update, 1246 [-69.68888889, -166.6, 69.68888889, 0]) 1247 assert num.allclose(domain.quantities['ymomentum'].explicit_update, 1248 [-69.68888889, -35.93333333, 0., 69.68888889]) 1249 1250 def test_compute_fluxes_old_2(self): 1251 #Random values, incl momentum 1252 a = [0.0, 0.0] 1253 b = [0.0, 2.0] 1254 c = [2.0, 0.0] 1255 d = [0.0, 4.0] 1256 e = [2.0, 2.0] 1257 f = [4.0, 0.0] 1258 1259 points = [a, b, c, d, e, f] 1260 # bac, bce, ecf, dbe 1261 vertices = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]] 1262 1263 domain = Domain(points, vertices) 1264 val0 = 2. + 2.0/3 1265 val1 = 4. + 4.0/3 1266 val2 = 8. + 2.0/3 1267 val3 = 2. + 8.0/3 1268 1269 zl = zr = 0 # Assume flat zero bed 1270 edgeflux = num.zeros(3, num.float) 1271 edgeflux0 = num.zeros(3, num.float) 1272 edgeflux1 = num.zeros(3, num.float) 1273 edgeflux2 = num.zeros(3, num.float) 1274 H0 = 0.0 1275 1276 domain.set_quantity('elevation', zl*num.ones((4, 3), num.int)) #array default# 1277 1278 domain.set_quantity('stage', [[val0, val0-1, val0-2], 1279 [val1, val1+1, val1], 1280 [val2, val2-2, val2], 1281 [val3-0.5, val3, val3]]) 1282 1283 domain.set_quantity('xmomentum', 1284 [[1,2,3], [3,4,5], [1,-1,0], [0,-2,2]]) 1285 1286 domain.set_quantity('ymomentum', 1287 [[1,-1,0], [0,-3,2], [0,1,0], [-1,2,2]]) 1288 1289 domain.check_integrity() 1290 1291 # Flux across right edge of volume 1 1292 normal = domain.get_normal(1, 0) 1293 ql = domain.get_conserved_quantities(vol_id=1, edge=0) 1294 qr = domain.get_conserved_quantities(vol_id=2, edge=2) 1295 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux0, 1296 epsilon, g, H0) 1297 1298 # Flux across upper edge of volume 1 1299 normal = domain.get_normal(1, 1) 1300 ql = domain.get_conserved_quantities(vol_id=1, edge=1) 1301 qr = domain.get_conserved_quantities(vol_id=3, edge=0) 1302 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux1, 1303 epsilon, g, H0) 1304 1305 # Flux across lower left hypotenuse of volume 1 1306 normal = domain.get_normal(1, 2) 1307 ql = domain.get_conserved_quantities(vol_id=1, edge=2) 1308 qr = domain.get_conserved_quantities(vol_id=0, edge=1) 1309 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux2, 1310 epsilon, g, H0) 1311 1312 # Scale, add up and check that compute_fluxes is correct for vol 1 1313 e0 = domain.edgelengths[1, 0] 1314 e1 = domain.edgelengths[1, 1] 1315 e2 = domain.edgelengths[1, 2] 1316 1317 total_flux = -(e0*edgeflux0 + 1318 e1*edgeflux1 + 1319 e2*edgeflux2) / domain.areas[1] 1320 1321 domain.compute_fluxes() 1322 1323 for i, name in enumerate(['stage', 'xmomentum', 'ymomentum']): 1324 assert num.allclose(total_flux[i], 1325 domain.quantities[name].explicit_update[1]) 1326 1327 # FIXME (Ole): Need test like this for fluxes in very shallow water. 1328 def test_compute_fluxes_old_3(self): 1329 #Random values, incl momentum 1330 a = [0.0, 0.0] 1331 b = [0.0, 2.0] 1332 c = [2.0, 0.0] 1333 d = [0.0, 4.0] 1334 e = [2.0, 2.0] 1335 f = [4.0, 0.0] 1336 1337 points = [a, b, c, d, e, f] 1338 # bac, bce, ecf, dbe 1339 vertices = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]] 1340 1341 domain = Domain(points, vertices) 1342 1343 val0 = 2.+2.0/3 1344 val1 = 4.+4.0/3 1345 val2 = 8.+2.0/3 1346 val3 = 2.+8.0/3 1347 1348 zl = zr = -3.75 # Assume constant bed (must be less than stage) 1349 domain.set_quantity('elevation', zl*num.ones((4, 3), num.int)) #array default# 1350 1351 edgeflux = num.zeros(3, num.float) 1352 edgeflux0 = num.zeros(3, num.float) 1353 edgeflux1 = num.zeros(3, num.float) 1354 edgeflux2 = num.zeros(3, num.float) 1355 H0 = 0.0 1356 1357 domain.set_quantity('stage', [[val0, val0-1, val0-2], 1358 [val1, val1+1, val1], 1359 [val2, val2-2, val2], 1360 [val3-0.5, val3, val3]]) 1361 1362 domain.set_quantity('xmomentum', 1363 [[1,2,3], [3,4,5], [1,-1,0], [0,-2,2]]) 1364 1365 domain.set_quantity('ymomentum', 1366 [[1,-1,0], [0,-3,2], [0,1,0], [-1,2,2]]) 1367 1368 domain.check_integrity() 1369 1370 # Flux across right edge of volume 1 1371 normal = domain.get_normal(1, 0) 1372 ql = domain.get_conserved_quantities(vol_id=1, edge=0) 1373 qr = domain.get_conserved_quantities(vol_id=2, edge=2) 1374 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux0, 1375 epsilon, g, H0) 1376 1377 # Flux across upper edge of volume 1 1378 normal = domain.get_normal(1, 1) 1379 ql = domain.get_conserved_quantities(vol_id=1, edge=1) 1380 qr = domain.get_conserved_quantities(vol_id=3, edge=0) 1381 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux1, 1382 epsilon, g, H0) 1383 1384 # Flux across lower left hypotenuse of volume 1 1385 normal = domain.get_normal(1, 2) 1386 ql = domain.get_conserved_quantities(vol_id=1, edge=2) 1387 qr = domain.get_conserved_quantities(vol_id=0, edge=1) 1388 max_speed = flux_function(normal, ql, qr, zl, zr, edgeflux2, 1389 epsilon, g, H0) 1390 1391 # Scale, add up and check that compute_fluxes is correct for vol 1 1392 e0 = domain.edgelengths[1, 0] 1393 e1 = domain.edgelengths[1, 1] 1394 e2 = domain.edgelengths[1, 2] 1395 1396 total_flux = -(e0*edgeflux0 + 1397 e1*edgeflux1 + 1398 e2*edgeflux2) / domain.areas[1] 1399 1400 domain.compute_fluxes() 1401 1402 for i, name in enumerate(['stage', 'xmomentum', 'ymomentum']): 1403 assert num.allclose(total_flux[i], 1404 domain.quantities[name].explicit_update[1]) 1405 1406 1038 1407 1039 1408 def xtest_catching_negative_heights(self): … … 1789 2158 h = 0.1 1790 2159 def stage(x, y): 1791 return slope(x, 2160 return slope(x,y) + h 1792 2161 1793 2162 domain.set_quantity('elevation', slope) … … 1799 2168 1800 2169 domain.compute_forcing_terms() 2170 #from shallow_water_ext import gravity 2171 #gravity(domain) 2172 2173 #print domain.quantities['xmomentum'].explicit_update 2174 #print domain.quantities['ymomentum'].explicit_update 2175 1801 2176 1802 2177 assert num.allclose(domain.quantities['stage'].explicit_update, 0) … … 1804 2179 -g*h*3) 1805 2180 assert num.allclose(domain.quantities['ymomentum'].explicit_update, 0) 2181 2182 2183 2184 def Xtest_gravity_wb(self): 2185 #Assuming no friction 2186 2187 from anuga.config import g 2188 2189 a = [0.0, 0.0] 2190 b = [0.0, 2.0] 2191 c = [2.0, 0.0] 2192 d = [0.0, 4.0] 2193 e = [2.0, 2.0] 2194 f = [4.0, 0.0] 2195 2196 points = [a, b, c, d, e, f] 2197 # bac, bce, ecf, dbe 2198 vertices = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]] 2199 2200 domain = Domain(points, vertices) 2201 2202 #Set up for a gradient of (3,0) at mid triangle (bce) 2203 def slope(x, y): 2204 return 3*x 2205 2206 h = 0.1 2207 def stage(x, y): 2208 return slope(x,y)+h 2209 2210 domain.set_quantity('elevation', slope) 2211 domain.set_quantity('stage', stage) 2212 2213 for name in domain.conserved_quantities: 2214 assert num.allclose(domain.quantities[name].explicit_update, 0) 2215 assert num.allclose(domain.quantities[name].semi_implicit_update, 0) 2216 2217 from shallow_water_ext import gravity_wb 2218 gravity_wb(domain) 2219 2220 2221 print domain.quantities['xmomentum'].explicit_update 2222 print domain.quantities['ymomentum'].explicit_update 2223 assert num.allclose(domain.quantities['stage'].explicit_update, 0) 2224 assert num.allclose(domain.quantities['xmomentum'].explicit_update, 2225 -g*h*3) 2226 assert num.allclose(domain.quantities['ymomentum'].explicit_update, 0) 2227 2228 2229 def Xtest_gravity_wb_2(self): 2230 #Assuming no friction 2231 2232 from anuga.config import g 2233 2234 a = [0.0, 0.0] 2235 b = [0.0, 2.0] 2236 c = [2.0, 0.0] 2237 d = [0.0, 4.0] 2238 e = [2.0, 2.0] 2239 f = [4.0, 0.0] 2240 2241 points = [a, b, c, d, e, f] 2242 # bac, bce, ecf, dbe 2243 vertices = [[1,0,2], [1,2,4], [4,2,5], [3,1,4]] 2244 2245 domain = Domain(points, vertices) 2246 2247 #Set up for a gradient of (3,0) at mid triangle (bce) 2248 def slope(x, y): 2249 return 3*x 2250 2251 h = 15.0 2252 def stage(x, y): 2253 return h 2254 2255 domain.set_quantity('elevation', slope) 2256 domain.set_quantity('stage', stage) 2257 2258 for name in domain.conserved_quantities: 2259 assert num.allclose(domain.quantities[name].explicit_update, 0) 2260 assert num.allclose(domain.quantities[name].semi_implicit_update, 0) 2261 2262 from shallow_water_ext import gravity_wb 2263 gravity_wb(domain) 2264 2265 2266 print domain.quantities['xmomentum'].explicit_update 2267 print domain.quantities['ymomentum'].explicit_update 2268 2269 assert num.allclose(domain.quantities['stage'].explicit_update, 0) 2270 assert num.allclose(domain.quantities['xmomentum'].explicit_update, 2271 -g*h*3) 2272 assert num.allclose(domain.quantities['ymomentum'].explicit_update, 0) 2273 1806 2274 1807 2275 def test_manning_friction(self): … … 6200 6668 6201 6669 6202 verbose = False6670 verbose = True 6203 6671 6204 6672 #---------------------------------------------------------------------- … … 6294 6762 #-------------------------------------------------------------- 6295 6763 6296 for t in domain.evolve(yieldstep=100.0, finaltime=finaltime): 6297 pass 6298 #if verbose : 6299 # print domain.timestepping_statistics() 6300 6301 # print domain.volumetric_balance_statistics() 6764 for t in domain.evolve(yieldstep=10.0, finaltime=finaltime): 6765 #pass 6766 if verbose : 6767 print domain.timestepping_statistics() 6768 print domain.volumetric_balance_statistics() 6302 6769 6303 6770
Note: See TracChangeset
for help on using the changeset viewer.