Changeset 6737
- Timestamp:
- Apr 7, 2009, 9:38:40 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
anuga_core/source/anuga/shallow_water/shallow_water_ext.c
r6703 r6737 52 52 53 53 int find_qmin_and_qmax(double dq0, double dq1, double dq2, 54 54 double *qmin, double *qmax){ 55 55 // Considering the centroid of an FV triangle and the vertices of its 56 56 // auxiliary triangle, find … … 67 67 if (dq1>=dq2){ 68 68 if (dq1>=0.0) 69 69 *qmax=dq0+dq1; 70 70 else 71 72 71 *qmax=dq0; 72 73 73 *qmin=dq0+dq2; 74 74 if (*qmin>=0.0) *qmin = 0.0; … … 76 76 else{// dq1<dq2 77 77 if (dq2>0) 78 78 *qmax=dq0+dq2; 79 79 else 80 81 82 *qmin=dq0+dq1; 80 *qmax=dq0; 81 82 *qmin=dq0+dq1; 83 83 if (*qmin>=0.0) *qmin=0.0; 84 84 } … … 87 87 if (dq1<=dq2){ 88 88 if (dq1<0.0) 89 89 *qmin=dq0+dq1; 90 90 else 91 92 93 *qmax=dq0+dq2; 91 *qmin=dq0; 92 93 *qmax=dq0+dq2; 94 94 if (*qmax<=0.0) *qmax=0.0; 95 95 } 96 96 else{// dq1>dq2 97 97 if (dq2<0.0) 98 98 *qmin=dq0+dq2; 99 99 else 100 101 100 *qmin=dq0; 101 102 102 *qmax=dq0+dq1; 103 103 if (*qmax<=0.0) *qmax=0.0; … … 141 141 142 142 double compute_froude_number(double uh, 143 144 145 146 143 double h, 144 double g, 145 double epsilon) { 146 147 147 // Compute Froude number; v/sqrt(gh) 148 148 // FIXME (Ole): Not currently in use … … 169 169 // FIXME: Perhaps inline this and profile 170 170 double _compute_speed(double *uh, 171 172 173 171 double *h, 172 double epsilon, 173 double h0) { 174 174 175 175 double u; … … 192 192 // Innermost flux function (using stage w=z+h) 193 193 int _flux_function_central(double *q_left, double *q_right, 194 double z_left, double z_right, 195 double n1, double n2, 196 double epsilon, double H0, double g, 197 double *edgeflux, double *max_speed) { 194 double z_left, double z_right, 195 double n1, double n2, 196 double epsilon, double H0, double g, 197 double *edgeflux, double *max_speed) 198 { 198 199 199 200 /*Compute fluxes between volumes for the shallow water wave equation … … 221 222 double h0 = H0*H0; // This ensures a good balance when h approaches H0. 222 223 // But evidence suggests that h0 can be as little as 223 224 // epsilon! 224 225 225 226 // Copy conserved quantities to protect from modification 226 for (i=0; i<3; i++) { 227 q_left_rotated[i] = q_left[i]; 228 q_right_rotated[i] = q_right[i]; 229 } 227 q_left_rotated[0] = q_left[0]; 228 q_right_rotated[0] = q_right[0]; 229 q_left_rotated[1] = q_left[1]; 230 q_right_rotated[1] = q_right[1]; 231 q_left_rotated[2] = q_left[2]; 232 q_right_rotated[2] = q_right[2]; 230 233 231 234 // Align x- and y-momentum with x-axis … … 233 236 _rotate(q_right_rotated, n1, n2); 234 237 235 z = 0.5*(z_left +z_right); // Average elevation values.238 z = 0.5*(z_left + z_right); // Average elevation values. 236 239 // Even though this will nominally allow for discontinuities 237 238 240 // in the elevation data, there is currently no numerical 241 // support for this so results may be strange near jumps in the bed. 239 242 240 243 // Compute speeds in x-direction 241 244 w_left = q_left_rotated[0]; 242 h_left = w_left -z;245 h_left = w_left - z; 243 246 uh_left = q_left_rotated[1]; 244 247 u_left = _compute_speed(&uh_left, &h_left, epsilon, h0); 245 248 246 249 w_right = q_right_rotated[0]; 247 h_right = w_right -z;250 h_right = w_right - z; 248 251 uh_right = q_right_rotated[1]; 249 252 u_right = _compute_speed(&uh_right, &h_right, epsilon, h0); … … 261 264 soundspeed_right = sqrt(g*h_right); 262 265 263 s_max = max(u_left+soundspeed_left, u_right+soundspeed_right); 264 if (s_max < 0.0) s_max = 0.0; 265 266 s_min = min(u_left-soundspeed_left, u_right-soundspeed_right); 267 if (s_min > 0.0) s_min = 0.0; 268 266 s_max = max(u_left + soundspeed_left, u_right + soundspeed_right); 267 if (s_max < 0.0) 268 { 269 s_max = 0.0; 270 } 271 272 s_min = min(u_left - soundspeed_left, u_right - soundspeed_right); 273 if (s_min > 0.0) 274 { 275 s_min = 0.0; 276 } 269 277 270 278 // Flux formulas … … 277 285 flux_right[2] = u_right*vh_right; 278 286 279 280 287 // Flux computation 281 denom = s_max-s_min; 282 if (denom < epsilon) { // FIXME (Ole): Try using H0 here 283 for (i=0; i<3; i++) edgeflux[i] = 0.0; 288 denom = s_max - s_min; 289 if (denom < epsilon) 290 { // FIXME (Ole): Try using H0 here 291 memset(edgeflux, 0, 3*sizeof(double)); 284 292 *max_speed = 0.0; 285 } else { 293 } 294 else 295 { 286 296 inverse_denominator = 1.0/denom; 287 for (i=0; i<3; i++) { 297 for (i = 0; i < 3; i++) 298 { 288 299 edgeflux[i] = s_max*flux_left[i] - s_min*flux_right[i]; 289 edgeflux[i] += s_max*s_min*(q_right_rotated[i] -q_left_rotated[i]);300 edgeflux[i] += s_max*s_min*(q_right_rotated[i] - q_left_rotated[i]); 290 301 edgeflux[i] *= inverse_denominator; 291 302 } … … 318 329 // Computational function for flux computation (using stage w=z+h) 319 330 int flux_function_kinetic(double *q_left, double *q_right, 320 321 322 323 331 double z_left, double z_right, 332 double n1, double n2, 333 double epsilon, double H0, double g, 334 double *edgeflux, double *max_speed) { 324 335 325 336 /*Compute fluxes between volumes for the shallow water wave equation … … 416 427 417 428 void _manning_friction(double g, double eps, int N, 418 419 420 429 double* w, double* z, 430 double* uh, double* vh, 431 double* eta, double* xmom, double* ymom) { 421 432 422 433 int k; … … 444 455 /* 445 456 void _manning_friction_explicit(double g, double eps, int N, 446 447 448 457 double* w, double* z, 458 double* uh, double* vh, 459 double* eta, double* xmom, double* ymom) { 449 460 450 461 int k; … … 455 466 h = w[k]-z[k]; 456 467 if (h >= eps) { 457 458 459 460 461 462 463 464 465 468 S = -g * eta[k]*eta[k] * sqrt((uh[k]*uh[k] + vh[k]*vh[k])); 469 S /= pow(h, 7.0/3); //Expensive (on Ole's home computer) 470 //S /= exp(7.0/3.0*log(h)); //seems to save about 15% over manning_friction 471 //S /= h*h*(1 + h/3.0 - h*h/9.0); //FIXME: Could use a Taylor expansion 472 473 474 //Update momentum 475 xmom[k] += S*uh[k]; 476 ymom[k] += S*vh[k]; 466 477 } 467 478 } … … 474 485 475 486 double velocity_balance(double uh_i, 476 477 478 479 480 487 double uh, 488 double h_i, 489 double h, 490 double alpha, 491 double epsilon) { 481 492 // Find alpha such that speed at the vertex is within one 482 // order of magnitude of the centroid speed 493 // order of magnitude of the centroid speed 483 494 484 495 // FIXME(Ole): Work in progress … … 489 500 490 501 printf("alpha = %f, uh_i=%f, uh=%f, h_i=%f, h=%f\n", 491 502 alpha, uh_i, uh, h_i, h); 492 503 493 504 … … 503 514 if (h < epsilon) { 504 515 b = 1.0e10; // Limit 505 } else { 516 } else { 506 517 b = m*fabs(h_i - h)/h; 507 518 } … … 510 521 511 522 if (a > b) { 512 estimate = (m-1)/(a-b); 523 estimate = (m-1)/(a-b); 513 524 514 525 printf("Alpha %f, estimate %f\n", 515 516 526 alpha, estimate); 527 517 528 if (alpha < estimate) { 518 529 printf("Adjusting alpha from %f to %f\n", 519 530 alpha, estimate); 520 531 alpha = estimate; 521 532 } … … 523 534 524 535 if (h < h_i) { 525 estimate = (m-1)/(a-b); 536 estimate = (m-1)/(a-b); 526 537 527 538 printf("Alpha %f, estimate %f\n", 528 529 539 alpha, estimate); 540 530 541 if (alpha < estimate) { 531 532 533 542 printf("Adjusting alpha from %f to %f\n", 543 alpha, estimate); 544 alpha = estimate; 534 545 } 535 546 } … … 543 554 544 555 int _balance_deep_and_shallow(int N, 545 546 547 548 549 550 551 552 553 554 555 556 557 556 double* wc, 557 double* zc, 558 double* wv, 559 double* zv, 560 double* hvbar, // Retire this 561 double* xmomc, 562 double* ymomc, 563 double* xmomv, 564 double* ymomv, 565 double H0, 566 int tight_slope_limiters, 567 int use_centroid_velocities, 568 double alpha_balance) { 558 569 559 570 int k, k3, i; … … 582 593 // FIXME: Try with this one precomputed 583 594 for (i=0; i<3; i++) { 584 595 dz = max(dz, fabs(zv[k3+i]-zc[k])); 585 596 } 586 597 } … … 595 606 596 607 //if (hmin < 0.0 ) { 597 // 608 // printf("hmin = %f\n",hmin); 598 609 //} 599 610 … … 610 621 611 622 if (dz > 0.0) { 612 623 alpha = max( min( alpha_balance*hmin/dz, 1.0), 0.0 ); 613 624 } else { 614 625 alpha = 1.0; // Flat bed 615 626 } 616 627 //printf("Using old style limiter\n"); … … 625 636 626 637 if (hmin < H0) { 627 628 629 630 h_diff = hc_k - hv[i];631 632 633 634 635 636 637 638 639 alpha = min(alpha, (hc_k - H0)/h_diff);640 641 642 643 644 645 646 638 alpha = 1.0; 639 for (i=0; i<3; i++) { 640 641 h_diff = hc_k - hv[i]; 642 if (h_diff <= 0) { 643 // Deep water triangle is further away from bed than 644 // shallow water (hbar < h). Any alpha will do 645 646 } else { 647 // Denominator is positive which means that we need some of the 648 // h-limited stage. 649 650 alpha = min(alpha, (hc_k - H0)/h_diff); 651 } 652 } 653 654 // Ensure alpha in [0,1] 655 if (alpha>1.0) alpha=1.0; 656 if (alpha<0.0) alpha=0.0; 657 647 658 } else { 648 649 659 // Use w-limited stage exclusively in deeper water. 660 alpha = 1.0; 650 661 } 651 662 } 652 663 653 664 654 // 665 // Let 655 666 // 656 // 657 // 667 // wvi be the w-limited stage (wvi = zvi + hvi) 668 // wvi- be the h-limited state (wvi- = zvi + hvi-) 658 669 // 659 670 // 660 // 671 // where i=0,1,2 denotes the vertex ids 661 672 // 662 673 // Weighted balance between w-limited and h-limited stage is 663 674 // 664 // 675 // wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi) 665 676 // 666 677 // It follows that the updated wvi is 667 678 // wvi := zvi + (1-alpha)*hvi- + alpha*hvi 668 679 // 669 // 680 // Momentum is balanced between constant and limited 670 681 671 682 … … 673 684 for (i=0; i<3; i++) { 674 685 675 wv[k3+i] = zv[k3+i] + (1-alpha)*hc_k + alpha*hv[i]; 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 686 wv[k3+i] = zv[k3+i] + (1-alpha)*hc_k + alpha*hv[i]; 687 688 // Update momentum at vertices 689 if (use_centroid_velocities == 1) { 690 // This is a simple, efficient and robust option 691 // It uses first order approximation of velocities, but retains 692 // the order used by stage. 693 694 // Speeds at centroids 695 if (hc_k > epsilon) { 696 uc = xmomc[k]/hc_k; 697 vc = ymomc[k]/hc_k; 698 } else { 699 uc = 0.0; 700 vc = 0.0; 701 } 702 703 // Vertex momenta guaranteed to be consistent with depth guaranteeing 704 // controlled speed 705 hv[i] = wv[k3+i] - zv[k3+i]; // Recompute (balanced) vertex depth 706 xmomv[k3+i] = uc*hv[i]; 707 ymomv[k3+i] = vc*hv[i]; 708 709 } else { 710 // Update momentum as a linear combination of 711 // xmomc and ymomc (shallow) and momentum 712 // from extrapolator xmomv and ymomv (deep). 713 // This assumes that values from xmomv and ymomv have 714 // been established e.g. by the gradient limiter. 715 716 // FIXME (Ole): I think this should be used with vertex momenta 717 // computed above using centroid_velocities instead of xmomc 718 // and ymomc as they'll be more representative first order 719 // values. 720 721 xmomv[k3+i] = (1-alpha)*xmomc[k] + alpha*xmomv[k3+i]; 722 ymomv[k3+i] = (1-alpha)*ymomc[k] + alpha*ymomv[k3+i]; 723 724 } 714 725 } 715 726 } … … 722 733 723 734 int _protect(int N, 724 725 726 727 728 729 730 735 double minimum_allowed_height, 736 double maximum_allowed_speed, 737 double epsilon, 738 double* wc, 739 double* zc, 740 double* xmomc, 741 double* ymomc) { 731 742 732 743 int k; … … 741 752 742 753 if (hc < minimum_allowed_height) { 743 744 745 746 747 754 755 // Set momentum to zero and ensure h is non negative 756 xmomc[k] = 0.0; 757 ymomc[k] = 0.0; 758 if (hc <= 0.0) wc[k] = zc[k]; 748 759 } 749 760 } … … 760 771 761 772 if (hc <= 0.0) { 762 763 764 773 wc[k] = zc[k]; 774 xmomc[k] = 0.0; 775 ymomc[k] = 0.0; 765 776 } else { 766 777 //Reduce excessive speeds derived from division by small hc 767 768 778 //FIXME (Ole): This may be unnecessary with new slope limiters 779 //in effect. 769 780 770 781 u = xmomc[k]/hc; 771 772 773 774 //u, reduced_speed);775 776 782 if (fabs(u) > maximum_allowed_speed) { 783 reduced_speed = maximum_allowed_speed * u/fabs(u); 784 //printf("Speed (u) has been reduced from %.3f to %.3f\n", 785 // u, reduced_speed); 786 xmomc[k] = reduced_speed * hc; 787 } 777 788 778 789 v = ymomc[k]/hc; 779 780 781 782 //v, reduced_speed);783 784 790 if (fabs(v) > maximum_allowed_speed) { 791 reduced_speed = maximum_allowed_speed * v/fabs(v); 792 //printf("Speed (v) has been reduced from %.3f to %.3f\n", 793 // v, reduced_speed); 794 ymomc[k] = reduced_speed * hc; 795 } 785 796 } 786 797 } … … 793 804 794 805 int _assign_wind_field_values(int N, 795 796 797 798 799 806 double* xmom_update, 807 double* ymom_update, 808 double* s_vec, 809 double* phi_vec, 810 double cw) { 800 811 801 812 // Assign windfield values to momentum updates … … 842 853 843 854 if (!PyArg_ParseTuple(args, "OOOddOddd", 844 845 855 &normal, &ql, &qr, &zl, &zr, &edgeflux, 856 &epsilon, &g, &H0)) { 846 857 PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: flux_function_central could not parse input arguments"); 847 858 return NULL; … … 850 861 851 862 _flux_function_central((double*) ql -> data, 852 853 854 zr,855 856 ((double*) normal -> data)[1],857 858 859 863 (double*) qr -> data, 864 zl, 865 zr, 866 ((double*) normal -> data)[0], 867 ((double*) normal -> data)[1], 868 epsilon, H0, g, 869 (double*) edgeflux -> data, 870 &max_speed); 860 871 861 872 return Py_BuildValue("d", max_speed); … … 877 888 878 889 if (!PyArg_ParseTuple(args, "dOOOOO", 879 880 890 &g, &h, &v, &x, 891 &xmom, &ymom)) { 881 892 //&epsilon)) { 882 893 PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: gravity could not parse input arguments"); … … 936 947 937 948 if (!PyArg_ParseTuple(args, "ddOOOOOOO", 938 939 949 &g, &eps, &w, &z, &uh, &vh, &eta, 950 &xmom, &ymom)) { 940 951 PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: manning_friction could not parse input arguments"); 941 952 return NULL; … … 945 956 N = w -> dimensions[0]; 946 957 _manning_friction(g, eps, N, 947 948 949 950 951 952 953 958 (double*) w -> data, 959 (double*) z -> data, 960 (double*) uh -> data, 961 (double*) vh -> data, 962 (double*) eta -> data, 963 (double*) xmom -> data, 964 (double*) ymom -> data); 954 965 955 966 return Py_BuildValue(""); … … 969 980 970 981 if (!PyArg_ParseTuple(args, "ddOOOOOOO", 971 972 982 &g, &eps, &w, &z, &uh, &vh, &eta, 983 &xmom, &ymom)) 973 984 return NULL; 974 985 975 986 N = w -> dimensions[0]; 976 987 _manning_friction_explicit(g, eps, N, 977 978 979 980 981 982 983 988 (double*) w -> data, 989 (double*) z -> data, 990 (double*) uh -> data, 991 (double*) vh -> data, 992 (double*) eta -> data, 993 (double*) xmom -> data, 994 (double*) ymom -> data); 984 995 985 996 return Py_BuildValue(""); … … 991 1002 // Computational routine 992 1003 int _extrapolate_second_order_sw(int number_of_elements, 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1004 double epsilon, 1005 double minimum_allowed_height, 1006 double beta_w, 1007 double beta_w_dry, 1008 double beta_uh, 1009 double beta_uh_dry, 1010 double beta_vh, 1011 double beta_vh_dry, 1012 long* surrogate_neighbours, 1013 long* number_of_boundaries, 1014 double* centroid_coordinates, 1015 double* stage_centroid_values, 1016 double* xmom_centroid_values, 1017 double* ymom_centroid_values, 1018 double* elevation_centroid_values, 1019 double* vertex_coordinates, 1020 double* stage_vertex_values, 1021 double* xmom_vertex_values, 1022 double* ymom_vertex_values, 1023 double* elevation_vertex_values, 1024 int optimise_dry_cells) { 1025 1026 1016 1027 1017 1028 // Local variables … … 1023 1034 double hc, h0, h1, h2, beta_tmp, hfactor; 1024 1035 1025 1036 1026 1037 for (k=0; k<number_of_elements; k++) { 1027 1038 k3=k*3; … … 1108 1119 // the triangle might be flat or clockwise: 1109 1120 if (area2<=0) { 1110 1111 1112 1121 PyErr_SetString(PyExc_RuntimeError, 1122 "shallow_water_ext.c: negative triangle area encountered"); 1123 return -1; 1113 1124 } 1114 1125 … … 1123 1134 hfactor = 0.0; 1124 1135 if (hmin > 0.001 ) { 1125 1136 hfactor = (hmin-0.001)/(hmin+0.004); 1126 1137 } 1127 1138 1128 1139 if (optimise_dry_cells) { 1129 1130 1131 1132 1133 1134 1135 1140 // Check if linear reconstruction is necessary for triangle k 1141 // This check will exclude dry cells. 1142 1143 hmax = max(h0,max(h1,h2)); 1144 if (hmax < epsilon) { 1145 continue; 1146 } 1136 1147 } 1137 1148 … … 1172 1183 //if (hmin>minimum_allowed_height) 1173 1184 beta_tmp = beta_w_dry + (beta_w - beta_w_dry) * hfactor; 1174 1185 1175 1186 //printf("min_alled_height = %f\n",minimum_allowed_height); 1176 1187 //printf("hmin = %f\n",hmin); … … 1181 1192 1182 1193 for (i=0;i<3;i++) 1183 1194 stage_vertex_values[k3+i]=stage_centroid_values[k]+dqv[i]; 1184 1195 1185 1196 … … 1222 1233 1223 1234 for (i=0;i<3;i++) 1224 1235 xmom_vertex_values[k3+i]=xmom_centroid_values[k]+dqv[i]; 1225 1236 1226 1237 … … 1259 1270 //if (hmin<minimum_allowed_height) 1260 1271 //beta_tmp = beta_vh_dry; 1261 beta_tmp = beta_vh_dry + (beta_vh - beta_vh_dry) * hfactor; 1272 beta_tmp = beta_vh_dry + (beta_vh - beta_vh_dry) * hfactor; 1262 1273 1263 1274 // Limit the gradient … … 1265 1276 1266 1277 for (i=0;i<3;i++) 1267 1268 1278 ymom_vertex_values[k3+i]=ymom_centroid_values[k]+dqv[i]; 1279 1269 1280 } // End number_of_boundaries <=1 1270 1281 else{ … … 1278 1289 // Find the only internal neighbour (k1?) 1279 1290 for (k2=k3;k2<k3+3;k2++){ 1280 1281 // k2 indexes the edges of triangle k 1282 1283 1284 1291 // Find internal neighbour of triangle k 1292 // k2 indexes the edges of triangle k 1293 1294 if (surrogate_neighbours[k2]!=k) 1295 break; 1285 1296 } 1286 1297 1287 1298 if ((k2==k3+3)) { 1288 1289 1290 1291 1299 // If we didn't find an internal neighbour 1300 PyErr_SetString(PyExc_RuntimeError, 1301 "shallow_water_ext.c: Internal neighbour not found"); 1302 return -1; 1292 1303 } 1293 1304 … … 1335 1346 // Now limit the jumps 1336 1347 if (dq1>=0.0){ 1337 1338 1348 qmin=0.0; 1349 qmax=dq1; 1339 1350 } 1340 1351 else{ 1341 1342 1352 qmin=dq1; 1353 qmax=0.0; 1343 1354 } 1344 1355 … … 1347 1358 1348 1359 for (i=0;i<3;i++) 1349 1360 stage_vertex_values[k3+i]=stage_centroid_values[k]+dqv[i]; 1350 1361 1351 1362 … … 1369 1380 // Now limit the jumps 1370 1381 if (dq1>=0.0){ 1371 1372 1382 qmin=0.0; 1383 qmax=dq1; 1373 1384 } 1374 1385 else{ 1375 1376 1386 qmin=dq1; 1387 qmax=0.0; 1377 1388 } 1378 1389 … … 1381 1392 1382 1393 for (i=0;i<3;i++) 1383 1394 xmom_vertex_values[k3+i]=xmom_centroid_values[k]+dqv[i]; 1384 1395 1385 1396 … … 1403 1414 // Now limit the jumps 1404 1415 if (dq1>=0.0){ 1405 1406 1416 qmin=0.0; 1417 qmax=dq1; 1407 1418 } 1408 1419 else{ 1409 1410 1420 qmin=dq1; 1421 qmax=0.0; 1411 1422 } 1412 1423 … … 1415 1426 1416 1427 for (i=0;i<3;i++) 1417 1418 1428 ymom_vertex_values[k3+i]=ymom_centroid_values[k]+dqv[i]; 1429 1419 1430 } // else [number_of_boundaries==2] 1420 1431 } // for k=0 to number_of_elements-1 1421 1432 1422 1433 return 0; 1423 } 1434 } 1424 1435 1425 1436 … … 1456 1467 Post conditions: 1457 1468 The vertices of each triangle have values from a 1458 1459 1469 limited linear reconstruction 1470 based on centroid values 1460 1471 1461 1472 */ … … 1484 1495 // Convert Python arguments to C 1485 1496 if (!PyArg_ParseTuple(args, "OOOOOOOOOOOOOi", 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 &optimise_dry_cells)) { 1500 1497 &domain, 1498 &surrogate_neighbours, 1499 &number_of_boundaries, 1500 ¢roid_coordinates, 1501 &stage_centroid_values, 1502 &xmom_centroid_values, 1503 &ymom_centroid_values, 1504 &elevation_centroid_values, 1505 &vertex_coordinates, 1506 &stage_vertex_values, 1507 &xmom_vertex_values, 1508 &ymom_vertex_values, 1509 &elevation_vertex_values, 1510 &optimise_dry_cells)) { 1511 1501 1512 PyErr_SetString(PyExc_RuntimeError, 1502 1513 "Input arguments to extrapolate_second_order_sw failed"); 1503 1514 return NULL; 1504 1515 } … … 1522 1533 // Call underlying computational routine 1523 1534 e = _extrapolate_second_order_sw(number_of_elements, 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1535 epsilon, 1536 minimum_allowed_height, 1537 beta_w, 1538 beta_w_dry, 1539 beta_uh, 1540 beta_uh_dry, 1541 beta_vh, 1542 beta_vh_dry, 1543 (long*) surrogate_neighbours -> data, 1544 (long*) number_of_boundaries -> data, 1545 (double*) centroid_coordinates -> data, 1546 (double*) stage_centroid_values -> data, 1547 (double*) xmom_centroid_values -> data, 1548 (double*) ymom_centroid_values -> data, 1549 (double*) elevation_centroid_values -> data, 1550 (double*) vertex_coordinates -> data, 1551 (double*) stage_vertex_values -> data, 1552 (double*) xmom_vertex_values -> data, 1553 (double*) ymom_vertex_values -> data, 1554 (double*) elevation_vertex_values -> data, 1555 optimise_dry_cells); 1545 1556 if (e == -1) { 1546 1557 // Use error string set inside computational routine 1547 1558 return NULL; 1548 } 1559 } 1549 1560 1550 1561 … … 1574 1585 // Convert Python arguments to C 1575 1586 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames, 1576 1587 &Q, &Normal, &direction)) { 1577 1588 PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: rotate could not parse input arguments"); 1578 1589 return NULL; … … 1619 1630 // Computational function for flux computation 1620 1631 double _compute_fluxes_central(int number_of_elements, 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 int optimise_dry_cells) { 1645 1632 double timestep, 1633 double epsilon, 1634 double H0, 1635 double g, 1636 long* neighbours, 1637 long* neighbour_edges, 1638 double* normals, 1639 double* edgelengths, 1640 double* radii, 1641 double* areas, 1642 long* tri_full_flag, 1643 double* stage_edge_values, 1644 double* xmom_edge_values, 1645 double* ymom_edge_values, 1646 double* bed_edge_values, 1647 double* stage_boundary_values, 1648 double* xmom_boundary_values, 1649 double* ymom_boundary_values, 1650 double* stage_explicit_update, 1651 double* xmom_explicit_update, 1652 double* ymom_explicit_update, 1653 long* already_computed_flux, 1654 double* max_speed_array, 1655 int optimise_dry_cells) 1656 { 1646 1657 // Local variables 1647 double max_speed, length, area, zl, zr;1658 double max_speed, length, inv_area, zl, zr; 1648 1659 int k, i, m, n; 1649 1660 int ki, nm=0, ki2; // Index shorthands … … 1652 1663 double ql[3], qr[3], edgeflux[3]; // Work array for summing up fluxes 1653 1664 1654 static long call=1; // Static local variable flagging already computed flux 1655 1656 1665 static long call = 1; // Static local variable flagging already computed flux 1666 1657 1667 // Start computation 1658 1668 call++; // Flag 'id' of flux calculation for this timestep 1659 1669 1660 1661 1670 // Set explicit_update to zero for all conserved_quantities. 1662 1671 // This assumes compute_fluxes called before forcing terms … … 1665 1674 memset((char*) ymom_explicit_update, 0, number_of_elements*sizeof(double)); 1666 1675 1667 1668 1676 // For all triangles 1669 for (k =0; k<number_of_elements; k++) {1670 1677 for (k = 0; k < number_of_elements; k++) 1678 { 1671 1679 // Loop through neighbours and compute edge flux for each 1672 for (i=0; i<3; i++) { 1673 ki = k*3+i; // Linear index to edge i of triangle k 1680 for (i = 0; i < 3; i++) 1681 { 1682 ki = k*3 + i; // Linear index to edge i of triangle k 1674 1683 1675 1684 if (already_computed_flux[ki] == call) 1685 { 1676 1686 // We've already computed the flux across this edge 1677 continue; 1678 1687 continue; 1688 } 1689 1679 1690 // Get left hand side values from triangle k, edge i 1680 1691 ql[0] = stage_edge_values[ki]; … … 1686 1697 // or from boundary array (Quantities at neighbour on nearest face). 1687 1698 n = neighbours[ki]; 1688 if (n < 0) { 1699 if (n < 0) 1700 { 1689 1701 // Neighbour is a boundary condition 1690 m = -n-1; // Convert negative flag to boundary index 1691 1692 qr[0] = stage_boundary_values[m]; 1693 qr[1] = xmom_boundary_values[m]; 1694 qr[2] = ymom_boundary_values[m]; 1695 zr = zl; // Extend bed elevation to boundary 1696 } else { 1702 m = -n - 1; // Convert negative flag to boundary index 1703 1704 qr[0] = stage_boundary_values[m]; 1705 qr[1] = xmom_boundary_values[m]; 1706 qr[2] = ymom_boundary_values[m]; 1707 zr = zl; // Extend bed elevation to boundary 1708 } 1709 else 1710 { 1697 1711 // Neighbour is a real triangle 1698 1699 nm = n*3+m; // Linear index (triangle n, edge m)1700 1701 1702 1703 1704 1712 m = neighbour_edges[ki]; 1713 nm = n*3 + m; // Linear index (triangle n, edge m) 1714 1715 qr[0] = stage_edge_values[nm]; 1716 qr[1] = xmom_edge_values[nm]; 1717 qr[2] = ymom_edge_values[nm]; 1718 zr = bed_edge_values[nm]; 1705 1719 } 1706 1720 1707 1721 // Now we have values for this edge - both from left and right side. 1708 1722 1709 if (optimise_dry_cells) { 1710 // Check if flux calculation is necessary across this edge 1711 // This check will exclude dry cells. 1712 // This will also optimise cases where zl != zr as 1713 // long as both are dry 1714 1715 if ( fabs(ql[0] - zl) < epsilon && 1716 fabs(qr[0] - zr) < epsilon ) { 1717 // Cell boundary is dry 1718 1719 already_computed_flux[ki] = call; // #k Done 1720 if (n>=0) 1721 already_computed_flux[nm] = call; // #n Done 1722 1723 max_speed = 0.0; 1724 continue; 1725 } 1726 } 1727 1723 if (optimise_dry_cells) 1724 { 1725 // Check if flux calculation is necessary across this edge 1726 // This check will exclude dry cells. 1727 // This will also optimise cases where zl != zr as 1728 // long as both are dry 1729 1730 if (fabs(ql[0] - zl) < epsilon && 1731 fabs(qr[0] - zr) < epsilon) 1732 { 1733 // Cell boundary is dry 1734 1735 already_computed_flux[ki] = call; // #k Done 1736 if (n >= 0) 1737 { 1738 already_computed_flux[nm] = call; // #n Done 1739 } 1740 1741 max_speed = 0.0; 1742 continue; 1743 } 1744 } 1728 1745 1729 1746 // Outward pointing normal vector (domain.normals[k, 2*i:2*i+2]) … … 1732 1749 // Edge flux computation (triangle k, edge i) 1733 1750 _flux_function_central(ql, qr, zl, zr, 1734 1735 1736 1751 normals[ki2], normals[ki2+1], 1752 epsilon, H0, g, 1753 edgeflux, &max_speed); 1737 1754 1738 1755 … … 1753 1770 1754 1771 // Update neighbour n with same flux but reversed sign 1755 if (n >=0) {1756 stage_explicit_update[n] += edgeflux[0]; 1757 xmom_explicit_update[n] += edgeflux[1];1758 ymom_explicit_update[n] += edgeflux[2];1759 1760 already_computed_flux[nm] = call; // #n Done 1761 }1762 1772 if (n >= 0) 1773 { 1774 stage_explicit_update[n] += edgeflux[0]; 1775 xmom_explicit_update[n] += edgeflux[1]; 1776 ymom_explicit_update[n] += edgeflux[2]; 1777 1778 already_computed_flux[nm] = call; // #n Done 1779 } 1763 1780 1764 1781 // Update timestep based on edge i and possibly neighbour n 1765 if (tri_full_flag[k] == 1) { 1766 if (max_speed > epsilon) { 1767 1768 // Apply CFL condition for triangles joining this edge (triangle k and triangle n) 1769 1770 // CFL for triangle k 1771 timestep = min(timestep, radii[k]/max_speed); 1772 1773 if (n>=0) 1774 // Apply CFL condition for neigbour n (which is on the ith edge of triangle k) 1775 timestep = min(timestep, radii[n]/max_speed); 1776 1777 // Ted Rigby's suggested less conservative version 1778 //if (n>=0) { 1779 // timestep = min(timestep, (radii[k]+radii[n])/max_speed); 1780 //} else { 1781 // timestep = min(timestep, radii[k]/max_speed); 1782 // } 1783 } 1782 if (tri_full_flag[k] == 1) 1783 { 1784 if (max_speed > epsilon) 1785 { 1786 // Apply CFL condition for triangles joining this edge (triangle k and triangle n) 1787 1788 // CFL for triangle k 1789 timestep = min(timestep, radii[k]/max_speed); 1790 1791 if (n >= 0) 1792 { 1793 // Apply CFL condition for neigbour n (which is on the ith edge of triangle k) 1794 timestep = min(timestep, radii[n]/max_speed); 1795 } 1796 1797 // Ted Rigby's suggested less conservative version 1798 //if (n>=0) { 1799 // timestep = min(timestep, (radii[k]+radii[n])/max_speed); 1800 //} else { 1801 // timestep = min(timestep, radii[k]/max_speed); 1802 // } 1803 } 1784 1804 } 1785 1805 … … 1789 1809 // Normalise triangle k by area and store for when all conserved 1790 1810 // quantities get updated 1791 area =areas[k];1792 stage_explicit_update[k] /=area;1793 xmom_explicit_update[k] /=area;1794 ymom_explicit_update[k] /=area;1811 inv_area = 1.0/areas[k]; 1812 stage_explicit_update[k] *= inv_area; 1813 xmom_explicit_update[k] *= inv_area; 1814 ymom_explicit_update[k] *= inv_area; 1795 1815 1796 1816 … … 1799 1819 1800 1820 } // End triangle k 1801 1802 1803 1821 1804 1822 return timestep; 1805 1823 } … … 1836 1854 1837 1855 PyObject 1838 1839 1840 1841 1842 1856 *domain, 1857 *stage, 1858 *xmom, 1859 *ymom, 1860 *bed; 1843 1861 1844 1862 PyArrayObject 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1863 *neighbours, 1864 *neighbour_edges, 1865 *normals, 1866 *edgelengths, 1867 *radii, 1868 *areas, 1869 *tri_full_flag, 1870 *stage_edge_values, 1871 *xmom_edge_values, 1872 *ymom_edge_values, 1873 *bed_edge_values, 1874 *stage_boundary_values, 1875 *xmom_boundary_values, 1876 *ymom_boundary_values, 1877 *stage_explicit_update, 1878 *xmom_explicit_update, 1879 *ymom_explicit_update, 1880 *already_computed_flux, //Tracks whether the flux across an edge has already been computed 1881 *max_speed_array; //Keeps track of max speeds for each triangle 1864 1882 1865 1883 … … 1869 1887 // Convert Python arguments to C 1870 1888 if (!PyArg_ParseTuple(args, "dOOOO", ×tep, &domain, &stage, &xmom, &ymom, &bed )) { 1871 1872 1889 PyErr_SetString(PyExc_RuntimeError, "Input arguments failed"); 1890 return NULL; 1873 1891 } 1874 1892 … … 1907 1925 // the explicit update arrays 1908 1926 timestep = _compute_fluxes_central(number_of_elements, 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1927 timestep, 1928 epsilon, 1929 H0, 1930 g, 1931 (long*) neighbours -> data, 1932 (long*) neighbour_edges -> data, 1933 (double*) normals -> data, 1934 (double*) edgelengths -> data, 1935 (double*) radii -> data, 1936 (double*) areas -> data, 1937 (long*) tri_full_flag -> data, 1938 (double*) stage_edge_values -> data, 1939 (double*) xmom_edge_values -> data, 1940 (double*) ymom_edge_values -> data, 1941 (double*) bed_edge_values -> data, 1942 (double*) stage_boundary_values -> data, 1943 (double*) xmom_boundary_values -> data, 1944 (double*) ymom_boundary_values -> data, 1945 (double*) stage_explicit_update -> data, 1946 (double*) xmom_explicit_update -> data, 1947 (double*) ymom_explicit_update -> data, 1948 (long*) already_computed_flux -> data, 1949 (double*) max_speed_array -> data, 1950 optimise_dry_cells); 1933 1951 1934 1952 Py_DECREF(neighbours); … … 1980 1998 domain.timestep = compute_fluxes(timestep, 1981 1999 domain.epsilon, 1982 2000 domain.H0, 1983 2001 domain.g, 1984 2002 domain.neighbours, … … 2000 2018 Ymom.explicit_update, 2001 2019 already_computed_flux, 2002 optimise_dry_cells)2020 optimise_dry_cells) 2003 2021 2004 2022 … … 2033 2051 // Convert Python arguments to C 2034 2052 if (!PyArg_ParseTuple(args, "ddddOOOOOOOOOOOOOOOOOOOi", 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2053 ×tep, 2054 &epsilon, 2055 &H0, 2056 &g, 2057 &neighbours, 2058 &neighbour_edges, 2059 &normals, 2060 &edgelengths, &radii, &areas, 2061 &tri_full_flag, 2062 &stage_edge_values, 2063 &xmom_edge_values, 2064 &ymom_edge_values, 2065 &bed_edge_values, 2066 &stage_boundary_values, 2067 &xmom_boundary_values, 2068 &ymom_boundary_values, 2069 &stage_explicit_update, 2070 &xmom_explicit_update, 2071 &ymom_explicit_update, 2072 &already_computed_flux, 2073 &max_speed_array, 2074 &optimise_dry_cells)) { 2057 2075 PyErr_SetString(PyExc_RuntimeError, "Input arguments failed"); 2058 2076 return NULL; … … 2065 2083 // the explicit update arrays 2066 2084 timestep = _compute_fluxes_central(number_of_elements, 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2085 timestep, 2086 epsilon, 2087 H0, 2088 g, 2089 (long*) neighbours -> data, 2090 (long*) neighbour_edges -> data, 2091 (double*) normals -> data, 2092 (double*) edgelengths -> data, 2093 (double*) radii -> data, 2094 (double*) areas -> data, 2095 (long*) tri_full_flag -> data, 2096 (double*) stage_edge_values -> data, 2097 (double*) xmom_edge_values -> data, 2098 (double*) ymom_edge_values -> data, 2099 (double*) bed_edge_values -> data, 2100 (double*) stage_boundary_values -> data, 2101 (double*) xmom_boundary_values -> data, 2102 (double*) ymom_boundary_values -> data, 2103 (double*) stage_explicit_update -> data, 2104 (double*) xmom_explicit_update -> data, 2105 (double*) ymom_explicit_update -> data, 2106 (long*) already_computed_flux -> data, 2107 (double*) max_speed_array -> data, 2108 optimise_dry_cells); 2091 2109 2092 2110 // Return updated flux timestep … … 2175 2193 // Convert Python arguments to C 2176 2194 if (!PyArg_ParseTuple(args, "ddddOOOOOOOOOOOOOOOOOO", 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2195 ×tep, 2196 &epsilon, 2197 &H0, 2198 &g, 2199 &neighbours, 2200 &neighbour_edges, 2201 &normals, 2202 &edgelengths, &radii, &areas, 2203 &tri_full_flag, 2204 &stage_edge_values, 2205 &xmom_edge_values, 2206 &ymom_edge_values, 2207 &bed_edge_values, 2208 &stage_boundary_values, 2209 &xmom_boundary_values, 2210 &ymom_boundary_values, 2211 &stage_explicit_update, 2212 &xmom_explicit_update, 2213 &ymom_explicit_update, 2214 &already_computed_flux)) { 2197 2215 PyErr_SetString(PyExc_RuntimeError, "Input arguments failed"); 2198 2216 return NULL; … … 2212 2230 ki = k*3+i; 2213 2231 if (((long *) already_computed_flux->data)[ki]==call)//we've already computed the flux across this edge 2214 2232 continue; 2215 2233 ql[0] = ((double *) stage_edge_values -> data)[ki]; 2216 2234 ql[1] = ((double *) xmom_edge_values -> data)[ki]; … … 2221 2239 n = ((long *) neighbours -> data)[ki]; 2222 2240 if (n < 0) { 2223 2224 2225 2226 2227 2241 m = -n-1; //Convert negative flag to index 2242 qr[0] = ((double *) stage_boundary_values -> data)[m]; 2243 qr[1] = ((double *) xmom_boundary_values -> data)[m]; 2244 qr[2] = ((double *) ymom_boundary_values -> data)[m]; 2245 zr = zl; //Extend bed elevation to boundary 2228 2246 } else { 2229 2230 2231 2232 2233 2234 2247 m = ((long *) neighbour_edges -> data)[ki]; 2248 nm = n*3+m; 2249 qr[0] = ((double *) stage_edge_values -> data)[nm]; 2250 qr[1] = ((double *) xmom_edge_values -> data)[nm]; 2251 qr[2] = ((double *) ymom_edge_values -> data)[nm]; 2252 zr = ((double *) bed_edge_values -> data)[nm]; 2235 2253 } 2236 2254 // Outward pointing normal vector … … 2241 2259 //Edge flux computation 2242 2260 flux_function_kinetic(ql, qr, zl, zr, 2243 2244 2245 2261 normal[0], normal[1], 2262 epsilon, H0, g, 2263 edgeflux, &max_speed); 2246 2264 //update triangle k 2247 2265 ((long *) already_computed_flux->data)[ki]=call; … … 2251 2269 //update the neighbour n 2252 2270 if (n>=0){ 2253 2254 2255 2256 2271 ((long *) already_computed_flux->data)[nm]=call; 2272 ((double *) stage_explicit_update -> data)[n] += edgeflux[0]*((double *) edgelengths -> data)[nm]; 2273 ((double *) xmom_explicit_update -> data)[n] += edgeflux[1]*((double *) edgelengths -> data)[nm]; 2274 ((double *) ymom_explicit_update -> data)[n] += edgeflux[2]*((double *) edgelengths -> data)[nm]; 2257 2275 } 2258 2276 ///for (j=0; j<3; j++) { 2259 2260 2261 2262 2263 2277 ///flux[j] -= edgeflux[j]*((double *) edgelengths -> data)[ki]; 2278 ///} 2279 //Update timestep 2280 //timestep = min(timestep, domain.radii[k]/max_speed) 2281 //FIXME: SR Add parameter for CFL condition 2264 2282 if ( ((long *) tri_full_flag -> data)[k] == 1) { 2265 2266 2267 2268 2269 2270 2283 if (max_speed > epsilon) { 2284 timestep = min(timestep, ((double *) radii -> data)[k]/max_speed); 2285 //maxspeed in flux_function is calculated as max(|u+a|,|u-a|) 2286 if (n>=0) 2287 timestep = min(timestep, ((double *) radii -> data)[n]/max_speed); 2288 } 2271 2289 } 2272 2290 } // end for i … … 2297 2315 // Convert Python arguments to C 2298 2316 if (!PyArg_ParseTuple(args, "dddOOOO", 2299 2300 2301 2302 2317 &minimum_allowed_height, 2318 &maximum_allowed_speed, 2319 &epsilon, 2320 &wc, &zc, &xmomc, &ymomc)) { 2303 2321 PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: protect could not parse input arguments"); 2304 2322 return NULL; … … 2308 2326 2309 2327 _protect(N, 2310 2311 2312 2313 2314 2315 2316 2328 minimum_allowed_height, 2329 maximum_allowed_speed, 2330 epsilon, 2331 (double*) wc -> data, 2332 (double*) zc -> data, 2333 (double*) xmomc -> data, 2334 (double*) ymomc -> data); 2317 2335 2318 2336 return Py_BuildValue(""); … … 2356 2374 // Convert Python arguments to C 2357 2375 if (!PyArg_ParseTuple(args, "OOOOOOOOOO", 2358 2359 2360 2361 2376 &domain, 2377 &wc, &zc, 2378 &wv, &zv, &hvbar, 2379 &xmomc, &ymomc, &xmomv, &ymomv)) { 2362 2380 PyErr_SetString(PyExc_RuntimeError, 2363 2381 "shallow_water_ext.c: balance_deep_and_shallow could not parse input arguments"); 2364 2382 return NULL; 2365 2383 } 2366 2367 2384 2385 2368 2386 // FIXME (Ole): I tested this without GetAttrString and got time down 2369 2387 // marginally from 4.0s to 3.8s. Consider passing everything in … … 2410 2428 N = wc -> dimensions[0]; 2411 2429 _balance_deep_and_shallow(N, 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 (int) use_centroid_velocities,2424 2430 (double*) wc -> data, 2431 (double*) zc -> data, 2432 (double*) wv -> data, 2433 (double*) zv -> data, 2434 (double*) hvbar -> data, 2435 (double*) xmomc -> data, 2436 (double*) ymomc -> data, 2437 (double*) xmomv -> data, 2438 (double*) ymomv -> data, 2439 H0, 2440 (int) tight_slope_limiters, 2441 (int) use_centroid_velocities, 2442 alpha_balance); 2425 2443 2426 2444 … … 2450 2468 // Convert Python arguments to C 2451 2469 if (!PyArg_ParseTuple(args, "OOOOd", 2452 2453 2454 2455 2470 &xmom_update, 2471 &ymom_update, 2472 &s_vec, &phi_vec, 2473 &cw)) { 2456 2474 PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: assign_windfield_values could not parse input arguments"); 2457 2475 return NULL; 2458 2476 } 2459 2477 2460 2478 2461 2479 N = xmom_update -> dimensions[0]; 2462 2480 2463 2481 _assign_wind_field_values(N, 2464 2465 2466 2467 2468 2482 (double*) xmom_update -> data, 2483 (double*) ymom_update -> data, 2484 (double*) s_vec -> data, 2485 (double*) phi_vec -> data, 2486 cw); 2469 2487 2470 2488 return Py_BuildValue("");
Note: See TracChangeset
for help on using the changeset viewer.