Changeset 8386
- Timestamp:
- Apr 9, 2012, 10:02:28 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
r8381 r8386 231 231 self.maximum_allowed_speed = maximum_allowed_speed 232 232 233 self. extrapolate_velocity_second_order=extrapolate_velocity_second_order233 self.set_extrapolate_velocity(extrapolate_velocity_second_order) 234 234 235 235 self.g = g … … 288 288 289 289 Currently 290 'original' 291 'well_balanced_1 292 """ 293 compute_fluxes_methods = ['original', 'wb_1', 'wb_2'] 290 original 291 wb_1 292 wb_2 293 wb_3 294 """ 295 compute_fluxes_methods = ['original', 'wb_1', 'wb_2', 'wb_3'] 294 296 295 297 if flag in compute_fluxes_methods: … … 331 333 raise Exception('undefined compute_fluxes method') 332 334 333 334 335 def set_extrapolate_velocity(self, flag=True): 336 """ Extrapolation routine uses momentum by default, 337 can change to velocity extrapolation which 338 seems to work better. 339 """ 340 341 if flag is True: 342 self.extrapolate_velocity_second_order = True 343 elif flag is False: 344 self.extrapolate_velocity_second_order = False 345 335 346 336 347 def set_use_kinematic_viscosity(self, flag=True): … … 656 667 gravity_c(self) 657 668 658 659 669 elif self.compute_fluxes_method == 'wb_1': 660 670 from shallow_water_ext import compute_fluxes_ext_wb … … 670 680 self.flux_timestep = compute_fluxes_ext_central_structure(self) 671 681 gravity_wb_c(self) 682 683 elif self.compute_fluxes_method == 'wb_3': 684 from shallow_water_ext import compute_fluxes_ext_wb_3 685 from shallow_water_ext import gravity as gravity_c 686 687 self.flux_timestep = compute_fluxes_ext_wb_3(self) 688 gravity_c(self) 672 689 673 690 else: -
trunk/anuga_core/source/anuga/shallow_water/shallow_water_ext.c
r8382 r8386 55 55 return 0; 56 56 } 57 58 59 // Computational function for rotation using edge structure 60 int _rotate_edge(struct edge *E, double n1, double n2) { 61 /*Rotate the momentum components 62 from x,y coordinates to coordinates based on normal vector (n1, n2) 63 64 To rotate in opposite direction, call rotate_edge with (E, n1, -n2) 65 66 Contents of E are changed by this function */ 67 68 69 double q1, q2; 70 71 // Shorthands 72 q1 = E->uh; // uh momentum 73 q2 = E->vh; // vh momentum 74 75 // Rotate 76 E->uh = n1*q1 + n2*q2; 77 E->vh = -n2*q1 + n1*q2; 78 79 q1 = E->uh1; // uh momentum 80 q2 = E->vh1; // vh momentum 81 82 // Rotate 83 E->uh1 = n1*q1 + n2*q2; 84 E->vh1 = -n2*q1 + n1*q2; 85 86 q1 = E->uh2; // uh momentum 87 q2 = E->vh2; // vh momentum 88 89 // Rotate 90 E->uh2 = n1*q1 + n2*q2; 91 E->vh2 = -n2*q1 + n1*q2; 92 93 return 0; 94 } 95 96 57 97 58 98 int find_qmin_and_qmax(double dq0, double dq1, double dq2, … … 429 469 430 470 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;471 //double hl, hr; 472 double uh_left, vh_left, u_left; 473 double uh_right, vh_right, u_right; 434 474 double s_min, s_max, soundspeed_left, soundspeed_right; 435 double denom, inverse_denominator , z;475 double denom, inverse_denominator; 436 476 double p_left, p_right; 437 477 … … 451 491 _rotate(q_right_rotated, n1, n2); 452 492 453 z = 0.5*(z_left + z_right); // Average elevation values.493 //z = 0.5*(z_left + z_right); // Average elevation values. 454 494 // Even though this will nominally allow 455 495 // for discontinuities in the elevation data, … … 471 511 472 512 // Compute speeds in x-direction 473 w_left = q_left_rotated[0];474 hl = w_left - z;513 //w_left = q_left_rotated[0]; 514 //hl = w_left - z; 475 515 /* 476 516 printf("w_left %g\n",w_left); … … 482 522 epsilon, h0, limiting_threshold); 483 523 484 w_right = q_right_rotated[0];485 h_right = w_right - z;524 //w_right = q_right_rotated[0]; 525 //h_right = w_right - z; 486 526 uh_right = q_right_rotated[1]; 487 527 u_right = _compute_speed(&uh_right, &h_right, … … 495 535 // Leaving this out, improves speed significantly (Ole 27/5/2009) 496 536 // 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 537 //_compute_speed(&vh_left, &h_left, 538 // epsilon, h0, limiting_threshold); 539 //_compute_speed(&vh_right, &h_right, 540 // epsilon, h0, limiting_threshold); 501 541 502 542 // Maximal and minimal wave speeds … … 576 616 } 577 617 618 // Innermost flux function (using stage w=z+h) 619 int _flux_function_central_wb_3(struct edge *E_left, struct edge *E_right, 620 double n1, double n2, 621 double epsilon, 622 double h0, 623 double limiting_threshold, 624 double g, 625 double *edgeflux, 626 double *max_speed) 627 { 628 629 /*Compute fluxes between volumes for the shallow water wave equation 630 cast in terms of the 'stage', w = h+z using 631 the 'central scheme' as described in 632 633 Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For 634 Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'. 635 Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740. 636 637 The implemented formula is given in equation (3.15) on page 714 638 */ 639 640 int i; 641 double h_left, h_right; 642 double uh_left, vh_left, u_left; 643 double uh_right, vh_right, u_right; 644 double h1_left, h2_left, h1_right, h2_right; 645 double p_left, p_right; 646 647 double s_min, s_max, soundspeed_left, soundspeed_right; 648 double denom, inverse_denominator; 649 650 static double q_left[3], q_right[3], flux_right[3], flux_left[3]; 651 652 653 // Align x- and y-momentum with x-axis 654 _rotate_edge(E_left, n1, n2); 655 _rotate_edge(E_right, n1, n2); 656 657 658 q_left[0] = E_left->w; 659 q_left[1] = E_left->uh; 660 q_left[2] = E_left->vh; 661 662 q_right[0] = E_right->w; 663 q_right[1] = E_right->uh; 664 q_right[2] = E_right->vh; 665 666 //z = 0.5*(E_left->z + E_right->z); // Average elevation values. 667 // Even though this will nominally allow 668 // for discontinuities in the elevation data, 669 // there is currently no numerical support for 670 // this so results may be strange near 671 // jumps in the bed. 672 673 // Compute speeds in x-direction 674 uh_left = E_left->uh; 675 h_left = E_left->h; 676 u_left = _compute_speed(&uh_left, &h_left, 677 epsilon, h0, limiting_threshold); 678 679 h_right = E_right->h; 680 uh_right = E_right->uh; 681 u_right = _compute_speed(&uh_right, &h_right, 682 epsilon, h0, limiting_threshold); 683 684 // Momentum in y-direction 685 vh_left = E_left->vh; 686 vh_right = E_right->vh; 687 688 // Maximal and minimal wave speeds 689 soundspeed_left = sqrt(g*h_left); 690 soundspeed_right = sqrt(g*h_right); 691 692 693 s_max = max(u_left + soundspeed_left, u_right + soundspeed_right); 694 if (s_max < 0.0) 695 { 696 s_max = 0.0; 697 } 698 699 s_min = min(u_left - soundspeed_left, u_right - soundspeed_right); 700 if (s_min > 0.0) 701 { 702 s_min = 0.0; 703 } 704 705 h1_left = E_left->h1; 706 h2_left = E_left->h2; 707 h1_right = E_right->h1; 708 h2_right = E_right->h2; 709 710 p_left = 0.5*g/6.0*(h1_left*h1_left + 4.0*h_left*h_left + h2_left*h2_left); 711 p_right = 0.5*g/6.0*(h1_right*h1_right + 4.0*h_right*h_right + h2_right*h2_right); 712 713 // Flux formulas 714 flux_left[0] = u_left*h_left; 715 flux_left[1] = u_left*uh_left + p_left; 716 flux_left[2] = u_left*vh_left; 717 718 flux_right[0] = u_right*h_right; 719 flux_right[1] = u_right*uh_right + p_right; 720 flux_right[2] = u_right*vh_right; 721 722 // Flux computation 723 denom = s_max - s_min; 724 if (denom < epsilon) 725 { // FIXME (Ole): Try using h0 here 726 memset(edgeflux, 0, 3*sizeof(double)); 727 *max_speed = 0.0; 728 } 729 else 730 { 731 inverse_denominator = 1.0/denom; 732 for (i = 0; i < 3; i++) 733 { 734 edgeflux[i] = s_max*flux_left[i] - s_min*flux_right[i]; 735 edgeflux[i] += s_max*s_min*(q_right[i] - q_left[i]); 736 edgeflux[i] *= inverse_denominator; 737 } 738 739 // Maximal wavespeed 740 *max_speed = max(fabs(s_max), fabs(s_min)); 741 742 // Rotate back 743 _rotate(edgeflux, n1, -n2); 744 } 745 746 return 0; 747 } 578 748 579 749 // Innermost flux function (using stage w=z+h) … … 1080 1250 1081 1251 dz = 0.0; 1082 if (tight_slope_limiters == 0) { 1252 if (tight_slope_limiters == 0) { 1083 1253 // FIXME: Try with this one precomputed 1084 1254 for (i=0; i<3; i++) { … … 1103 1273 // stage and alpha==1 means using the w-limited stage as 1104 1274 // computed by the gradient limiter (both 1st or 2nd order) 1105 if (tight_slope_limiters == 0) { 1275 if (tight_slope_limiters == 0) { 1106 1276 // If hmin > dz/alpha_balance then alpha = 1 and the bed will have no 1107 1277 // effect … … 1540 1710 double g, avg_h, wx, wy, fact; 1541 1711 double x0, y0, x1, y1, x2, y2; 1542 double h0,h1,h2;1543 1712 double hh[3]; 1544 1713 double w0,w1,w2; … … 2928 3097 double hr, hr1, hr2; 2929 3098 double zl, zl1, zl2; 2930 double zr , zr1, zr2;3099 double zr; 2931 3100 double wr; 2932 3101 … … 3137 3306 } 3138 3307 3308 3309 double _compute_fluxes_central_wb_3(struct domain *D) { 3310 3311 // Local variables 3312 double max_speed, length, inv_area; 3313 double timestep = 1.0e30; 3314 double h0 = D->H0*D->H0; // This ensures a good balance when h approaches H0. 3315 3316 double limiting_threshold = 10 * D->H0; // Avoid applying limiter below this 3317 // threshold for performance reasons. 3318 // See ANUGA manual under flux limiting 3319 int k, i, m, n; 3320 int k3, k3i, k2i; // Index short hands 3321 int n3m = 0; // Index short hand for neightbours 3322 3323 struct edge E_left; 3324 struct edge E_right; 3325 3326 double edgeflux[3]; // Work array for summing up fluxes 3327 3328 static long call = 1; // Static local variable flagging already computed flux 3329 3330 // Start computation 3331 call++; // Flag 'id' of flux calculation for this timestep 3332 3333 3334 timestep = D->evolve_max_timestep; 3335 3336 // Set explicit_update to zero for all conserved_quantities. 3337 // This assumes compute_fluxes called before forcing terms 3338 memset((char*) D->stage_explicit_update, 0, D->number_of_elements * sizeof (double)); 3339 memset((char*) D->xmom_explicit_update, 0, D->number_of_elements * sizeof (double)); 3340 memset((char*) D->ymom_explicit_update, 0, D->number_of_elements * sizeof (double)); 3341 3342 // For all triangles 3343 for (k = 0; k < D->number_of_elements; k++) { 3344 // Loop through neighbours and compute edge flux for each 3345 for (i = 0; i < 3; i++) { 3346 k3 = 3*k; 3347 k3i = k3 + i; // Linear index to edge i of triangle k 3348 3349 if (D->already_computed_flux[k3i] == call) { 3350 // We've already computed the flux across this edge 3351 continue; 3352 } 3353 3354 // Get the "left" values at the edge vertices and midpont 3355 // from the triangle k, edge i 3356 get_edge_data(&E_left, D, k, i); 3357 3358 3359 // Get right hand side values either from neighbouring triangle 3360 // or from boundary array (Quantities at neighbour on nearest face). 3361 n = D->neighbours[k3i]; 3362 if (n < 0) { 3363 // Neighbour is a boundary condition 3364 m = -n - 1; // Convert negative flag to boundary index 3365 3366 3367 // Midpoint Values provided by the boundary conditions 3368 E_right.w = D->stage_edge_values[m]; 3369 E_right.uh = D->xmom_edge_values[m]; 3370 E_right.vh = D->ymom_edge_values[m]; 3371 3372 // Set bed and height as equal to neighbour 3373 E_right.z = E_left.z; 3374 E_right.h = E_right.w - E_right.z; 3375 3376 // vertex values same as midpoint values 3377 E_right.w1 = E_right.w; 3378 E_right.uh1 = E_right.uh; 3379 E_right.vh1 = E_right.vh; 3380 E_right.z1 = E_right.z; 3381 E_right.h1 = E_right.h; 3382 3383 3384 E_right.w2 = E_right.w; 3385 E_right.uh2 = E_right.uh; 3386 E_right.vh2 = E_right.vh; 3387 E_right.z2 = E_right.z; 3388 E_right.h2 = E_right.h; 3389 3390 3391 } 3392 else { 3393 // Neighbour is a real triangle 3394 m = D->neighbour_edges[k3i]; 3395 3396 get_edge_data(&E_right, D, n, m); 3397 3398 } 3399 3400 // Now we have values for this edge - both from left and right side. 3401 3402 if (D->optimise_dry_cells) { 3403 // Check if flux calculation is necessary across this edge 3404 // This check will exclude dry cells. 3405 // This will also optimise cases where zl != zr as 3406 // long as both are dry 3407 3408 if (fabs(E_left.h) < D->epsilon && 3409 fabs(E_right.h) < D->epsilon) { 3410 // Cell boundary is dry 3411 3412 D->already_computed_flux[k3i] = call; // #k Done 3413 if (n >= 0) { 3414 D->already_computed_flux[n3m] = call; // #n Done 3415 } 3416 3417 max_speed = 0.0; 3418 continue; 3419 } 3420 } 3421 3422 3423 if (fabs(E_left.z-E_right.z)>1.0e-10) { 3424 report_python_error(AT,"Discontinuous Elevation"); 3425 return 0.0; 3426 } 3427 3428 // Outward pointing normal vector (domain.normals[k, 2*i:2*i+2]) 3429 k2i = 2 * k3i; //k*6 + i*2 3430 3431 3432 3433 // Edge flux computation (triangle k, edge i) 3434 _flux_function_central_wb_3(&E_left, &E_right, 3435 D->normals[k2i], D->normals[k2i + 1], 3436 D->epsilon, h0, limiting_threshold, D->g, 3437 edgeflux, &max_speed); 3438 3439 3440 3441 // Multiply edgeflux by edgelength 3442 length = D->edgelengths[k3i]; 3443 edgeflux[0] *= length; 3444 edgeflux[1] *= length; 3445 edgeflux[2] *= length; 3446 3447 3448 // Update triangle k with flux from edge i 3449 D->stage_explicit_update[k] -= edgeflux[0]; 3450 D->xmom_explicit_update[k] -= edgeflux[1]; 3451 D->ymom_explicit_update[k] -= edgeflux[2]; 3452 3453 D->already_computed_flux[k3i] = call; // #k Done 3454 3455 3456 // Update neighbour n with same flux but reversed sign 3457 if (n >= 0) { 3458 D->stage_explicit_update[n] += edgeflux[0]; 3459 D->xmom_explicit_update[n] += edgeflux[1]; 3460 D->ymom_explicit_update[n] += edgeflux[2]; 3461 3462 D->already_computed_flux[n3m] = call; // #n Done 3463 } 3464 3465 // Update timestep based on edge i and possibly neighbour n 3466 if (D->tri_full_flag[k] == 1) { 3467 if (max_speed > D->epsilon) { 3468 // Apply CFL condition for triangles joining this edge (triangle k and triangle n) 3469 3470 // CFL for triangle k 3471 timestep = min(timestep, D->radii[k] / max_speed); 3472 3473 if (n >= 0) { 3474 // Apply CFL condition for neigbour n (which is on the ith edge of triangle k) 3475 timestep = min(timestep, D->radii[n] / max_speed); 3476 } 3477 3478 // Ted Rigby's suggested less conservative version 3479 //if (n>=0) { 3480 // timestep = min(timestep, (radii[k]+radii[n])/max_speed); 3481 //} else { 3482 // timestep = min(timestep, radii[k]/max_speed); 3483 // } 3484 } 3485 } 3486 3487 } // End edge i (and neighbour n) 3488 3489 3490 // Normalise triangle k by area and store for when all conserved 3491 // quantities get updated 3492 inv_area = 1.0 / D->areas[k]; 3493 D->stage_explicit_update[k] *= inv_area; 3494 D->xmom_explicit_update[k] *= inv_area; 3495 D->ymom_explicit_update[k] *= inv_area; 3496 3497 3498 // Keep track of maximal speeds 3499 D->max_speed[k] = max_speed; 3500 3501 } // End triangle k 3502 3503 3504 return timestep; 3505 } 3139 3506 3140 3507 … … 3216 3583 neighbour_edges = get_consecutive_array(domain, "neighbour_edges"); 3217 3584 normals = get_consecutive_array(domain, "normals"); 3218 edgelengths = get_consecutive_array(domain, "edge_lengths"); 3585 edgelengths = get_consecutive_array(domain, "edge_lengths"); 3219 3586 radii = get_consecutive_array(domain, "radii"); 3220 3587 areas = get_consecutive_array(domain, "areas"); … … 3552 3919 3553 3920 3921 PyObject *compute_fluxes_ext_wb_3(PyObject *self, PyObject *args) { 3922 /*Compute all fluxes and the timestep suitable for all volumes 3923 in domain. 3924 3925 Compute total flux for each conserved quantity using "flux_function_central" 3926 3927 Fluxes across each edge are scaled by edgelengths and summed up 3928 Resulting flux is then scaled by area and stored in 3929 explicit_update for each of the three conserved quantities 3930 stage, xmomentum and ymomentum 3931 3932 The 3933 3934 The maximal allowable speed computed by the flux_function for each volume 3935 is converted to a timestep that must not be exceeded. The minimum of 3936 those is computed as the next overall timestep. 3937 3938 Python call: 3939 domain.timestep = compute_fluxes_ext_wb_3(domain, timestep) 3940 3941 3942 Post conditions: 3943 domain.explicit_update is reset to computed flux values 3944 3945 Returns: 3946 timestep which is the largest step satisfying all volumes. 3947 3948 3949 */ 3950 3951 struct domain D; 3952 PyObject *domain; 3953 double timestep; 3954 3955 if (!PyArg_ParseTuple(args, "O", &domain)) { 3956 report_python_error(AT, "could not parse input arguments"); 3957 return NULL; 3958 } 3959 3960 // populate the C domain structure with pointers 3961 // to the python domain data 3962 get_python_domain(&D,domain); 3963 3964 // Call underlying flux computation routine and update 3965 // the explicit update arrays 3966 timestep = _compute_fluxes_central_wb_3(&D); 3967 3968 3969 return Py_BuildValue("d", timestep); 3970 } 3554 3971 3555 3972 … … 3941 4358 {"extrapolate_second_order_sw", extrapolate_second_order_sw, METH_VARARGS, "Print out"}, 3942 4359 {"compute_fluxes_ext_wb", compute_fluxes_ext_wb, METH_VARARGS, "Print out"}, 4360 {"compute_fluxes_ext_wb_3", compute_fluxes_ext_wb_3, METH_VARARGS, "Print out"}, 3943 4361 {"compute_fluxes_ext_central", compute_fluxes_ext_central, METH_VARARGS, "Print out"}, 3944 4362 {"compute_fluxes_ext_central_structure", compute_fluxes_ext_central_structure, METH_VARARGS, "Print out"}, -
trunk/anuga_core/source/anuga/shallow_water/sw_domain.h
r8376 r8386 9 9 10 10 11 // structure 11 // structures 12 12 struct domain { 13 13 // Changing these don't change the data in python object … … 59 59 }; 60 60 61 62 struct edge { 63 64 // mid point values 65 double w; 66 double h; 67 double z; 68 double uh; 69 double vh; 70 double u; 71 double v; 72 73 // vertex values 74 double w1; 75 double h1; 76 double z1; 77 double uh1; 78 double vh1; 79 double u1; 80 double v1; 81 82 double w2; 83 double h2; 84 double z2; 85 double uh2; 86 double vh2; 87 double u2; 88 double v2; 89 90 }; 91 92 93 void get_edge_data(struct edge *E, struct domain *D, int k, int i) { 94 // fill edge data (conserved and bed) for ith edge of kth triangle 95 96 int k3i, k3i1, k3i2; 97 98 k3i = 3 * k + i; 99 k3i1 = 3 * k + (i + 1) % 3; 100 k3i2 = 3 * k + (i + 2) % 3; 101 102 E->w = D->stage_edge_values[k3i]; 103 E->z = D->bed_edge_values[k3i]; 104 E->h = E->w - E->z; 105 E->uh = D->xmom_edge_values[k3i]; 106 E->vh = D->ymom_edge_values[k3i]; 107 108 E->w1 = D->stage_vertex_values[k3i1]; 109 E->z1 = D->bed_vertex_values[k3i1]; 110 E->h1 = E->w1 - E->z1; 111 E->uh1 = D->xmom_edge_values[k3i1]; 112 E->vh1 = D->ymom_edge_values[k3i1]; 113 114 115 E->w2 = D->stage_vertex_values[k3i2]; 116 E->z2 = D->bed_vertex_values[k3i2]; 117 E->h2 = E->w2 - E->z2; 118 E->uh2 = D->xmom_edge_values[k3i2]; 119 E->vh2 = D->ymom_edge_values[k3i2]; 120 121 } 61 122 62 123 -
trunk/anuga_core/source/anuga/shallow_water/test_shallow_water_domain.py
r8382 r8386 2274 2274 2275 2275 2276 print domain.quantities['xmomentum'].explicit_update2277 print domain.quantities['stage'].vertex_values2278 print domain.quantities['elevation'].vertex_values2279 print domain.quantities['ymomentum'].explicit_update2276 #print domain.quantities['xmomentum'].explicit_update 2277 #print domain.quantities['stage'].vertex_values 2278 #print domain.quantities['elevation'].vertex_values 2279 #print domain.quantities['ymomentum'].explicit_update 2280 2280 2281 2281 … … 2330 2330 2331 2331 2332 print domain.quantities['xmomentum'].explicit_update2333 print domain.quantities['stage'].vertex_values2334 print domain.quantities['elevation'].vertex_values2335 print domain.quantities['ymomentum'].explicit_update2332 #print domain.quantities['xmomentum'].explicit_update 2333 #print domain.quantities['stage'].vertex_values 2334 #print domain.quantities['elevation'].vertex_values 2335 #print domain.quantities['ymomentum'].explicit_update 2336 2336 2337 2337
Note: See TracChangeset
for help on using the changeset viewer.