Changeset 8376


Ignore:
Timestamp:
Apr 1, 2012, 11:46:38 PM (13 years ago)
Author:
steve
Message:

Added well balanced flux calc

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  
    6464SeeAlso:
    6565    TRAC administration of ANUGA (User Manuals etc) at
    66     https://datamining.anu.edu.au/anuga and Subversion repository at
    67     $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/
    6868                anuga/shallow_water/shallow_water_domain.py $
    6969
     
    165165        self.set_defaults()
    166166
     167
    167168        #-------------------------------
    168169        # Operators and Forcing Terms
    169170        #-------------------------------
    170171        self.forcing_terms.append(manning_friction_implicit)
    171         #self.forcing_terms.append(gravity_)
     172        #self.forcing_terms.append(gravity_wb)
    172173        self.forcing_terms.append(gravity)
    173174
     
    219220        from anuga.config import use_edge_limiter
    220221        from anuga.config import use_centroid_velocities
     222        from anuga.config import compute_fluxes_method
    221223       
    222224
     
    246248        self.use_edge_limiter = use_edge_limiter
    247249        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)
    249253
    250254
     
    274278
    275279
    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
    283291        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
    285306
    286307
     
    580601
    581602    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')
    585631
    586632
     
    11371183
    11381184
    1139     compute_fluxes_ext_central_structure(domain)
     1185    domain.flux_timestep = compute_fluxes_ext_central_structure(domain)
    11401186
    11411187
     
    13581404    """
    13591405
    1360     from shallow_water_ext import gravity_wb_c
     1406    from shallow_water_ext import gravity_wb as gravity_wb_c
    13611407
    13621408    gravity_wb_c(domain)
  • trunk/anuga_core/source/anuga/shallow_water/shallow_water_ext.c

    r8374 r8376  
    400400  }
    401401 
     402  return 0;
     403}
     404
     405// Innermost flux function (using stage w=z+h)
     406int _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)
     580int _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
    402699  return 0;
    403700}
     
    12431540    double g, avg_h, wx, wy, fact;
    12441541    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;
    12471545    double sidex, sidey;
    12481546    double n0, n1;
     
    12691567        //------------------------------------
    12701568
    1271         // Get vertex bed values for gradient calculation
    1272         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];
    12751573
    12761574        // Compute stage slope
     
    12851583
    12861584        //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);
    12881586
    12891587        avg_h = D.stage_centroid_values[k] - D.bed_centroid_values[k];
     
    12981596       
    12991597        // 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       
    13041605        // Calculate the side correction term
    13051606        sidex = 0.0;
     
    13081609            n0 = D.normals[k6+2*i];
    13091610            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;
    13131616        }
    13141617
    13151618        // 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;
    13181621
    13191622    }
     
    24312734
    24322735
    2433 int _compute_fluxes_central_structure(struct domain *D) {
     2736double _compute_fluxes_central_structure(struct domain *D) {
    24342737
    24352738    // Local variables
     
    26032906
    26042907
    2605     D->flux_timestep = timestep;
    2606 
    2607     return 0;
     2908    return timestep;
    26082909}
     2910
     2911double _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
    26093125
    26103126
     
    29493465    struct domain D;
    29503466    PyObject *domain;
     3467    double timestep;
    29513468   
    29523469    if (!PyArg_ParseTuple(args, "O", &domain)) {
     
    29613478    // Call underlying flux computation routine and update
    29623479    // 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);
    29673484}
     3485
     3486
     3487
     3488PyObject *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
    29683539
    29693540
     
    33553926  {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
    33563927  {"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"},
    33573929  {"compute_fluxes_ext_central", compute_fluxes_ext_central, METH_VARARGS, "Print out"},
    33583930  {"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  
    1111// structure
    1212struct domain {
     13    // Changing these don't change the data in python object
    1314    long    number_of_elements;
    1415    double  epsilon;
     
    1718    long    optimise_dry_cells;
    1819    double  evolve_max_timestep;
    19     double  flux_timestep;
    2020
     21    // The values in the python object will be changed
    2122    long*   neighbours;
    2223    long*   neighbour_edges;
     
    8283    D->evolve_max_timestep = get_python_double(domain, "evolve_max_timestep");
    8384
    84     D->flux_timestep = get_python_double(domain, "flux_timestep");
    85 
    8685    neighbours = get_consecutive_array(domain, "neighbours");
    8786    D->neighbours = (long *) neighbours->data;
  • trunk/anuga_core/source/anuga/shallow_water/test_shallow_water_domain.py

    r8164 r8376  
    692692            assert num.allclose(t, q[0]), msg
    693693
    694     def test_compute_fluxes0(self):
     694    def test_compute_fluxes_structure_0(self):
    695695        # Do a full triangle and check that fluxes cancel out for
    696696        # the constant stage case
     
    775775        assert num.allclose(e0*edgeflux0 + e1*edgeflux1 + e2*edgeflux2, 0.)
    776776
     777
     778        from shallow_water_ext import compute_fluxes_ext_central_structure as compute_fluxes
    777779        # Now check that compute_flux yields zeros as well
    778         domain.compute_fluxes()
     780        compute_fluxes(domain)
    779781
    780782        for name in ['stage', 'xmomentum', 'ymomentum']:
    781783            assert num.allclose(domain.quantities[name].explicit_update[1], 0)
    782784
    783     def test_compute_fluxes1(self):
     785    def test_compute_fluxes_structure_1(self):
    784786        #Use values from previous version
    785787        a = [0.0, 0.0]
     
    868870        assert num.allclose(total_flux, [-0.68218178, -166.6, -35.93333333])
    869871
    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
    871878
    872879        for i, name in enumerate(['stage', 'xmomentum', 'ymomentum']):
     
    881888                            [-69.68888889, -35.93333333, 0., 69.68888889])
    882889
    883     def test_compute_fluxes2(self):
     890    def test_compute_fluxes_structure_2(self):
    884891        #Random values, incl momentum
    885892        a = [0.0, 0.0]
     
    952959                       e2*edgeflux2) / domain.areas[1]
    953960
    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)
    955965
    956966        for i, name in enumerate(['stage', 'xmomentum', 'ymomentum']):
     
    959969
    960970    # FIXME (Ole): Need test like this for fluxes in very shallow water.
    961     def test_compute_fluxes3(self):
     971    def test_compute_fluxes_structure_3(self):
    962972        #Random values, incl momentum
    963973        a = [0.0, 0.0]
     
    980990
    981991        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#
    983993
    984994        edgeflux = num.zeros(3, num.float)
     
    10311041                       e2*edgeflux2) / domain.areas[1]
    10321042
     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
    10331237        domain.compute_fluxes()
    10341238
     
    10361240            assert num.allclose(total_flux[i],
    10371241                                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
    10381407
    10391408    def xtest_catching_negative_heights(self):
     
    17892158        h = 0.1
    17902159        def stage(x, y):
    1791             return slope(x, y) + h
     2160            return slope(x,y) + h
    17922161
    17932162        domain.set_quantity('elevation', slope)
     
    17992168
    18002169        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
    18012176
    18022177        assert num.allclose(domain.quantities['stage'].explicit_update, 0)
     
    18042179                            -g*h*3)
    18052180        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
    18062274
    18072275    def test_manning_friction(self):
     
    62006668
    62016669       
    6202         verbose = False
     6670        verbose = True
    62036671       
    62046672        #----------------------------------------------------------------------
     
    62946762                #--------------------------------------------------------------
    62956763
    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()                                   
    63026769
    63036770
Note: See TracChangeset for help on using the changeset viewer.