source: trunk/anuga_work/development/gareth/experimental/balanced_dev/swb2_domain_ext.c

Last change on this file was 8893, checked in by davies, 12 years ago

Updates to bal_dev

File size: 93.9 KB
Line 
1// Python - C extension module for shallow_water.py
2//
3// To compile (Python2.6):
4//  gcc -c swb2_domain_ext.c -I/usr/include/python2.6 -o domain_ext.o -Wall -O
5//  gcc -shared swb2_domain_ext.o  -o swb2_domain_ext.so
6//
7// or use python compile.py
8//
9// See the module swb_domain.py for more documentation on
10// how to use this module
11//
12//
13// Stephen Roberts, ANU 2009
14// Ole Nielsen, GA 2004
15// Gareth Davies, GA 2011
16
17#include "Python.h"
18#include "numpy/arrayobject.h"
19#include "math.h"
20#include <stdio.h>
21//#include "numpy_shim.h"
22
23// Shared code snippets
24#include "util_ext.h"
25
26
27const double pi = 3.14159265358979;
28
29// Computational function for rotation
30int _rotate(double *q, double n1, double n2) {
31  /*Rotate the last  2 coordinates of q (q[1], q[2])
32    from x,y coordinates to coordinates based on normal vector (n1, n2).
33
34    Result is returned in array 2x1 r
35    To rotate in opposite direction, call rotate with (q, n1, -n2)
36
37    Contents of q are changed by this function */
38
39
40  double q1, q2;
41
42  // Shorthands
43  q1 = q[1];  // x coordinate
44  q2 = q[2];  // y coordinate
45
46  // Rotate
47  q[1] =  n1*q1 + n2*q2;
48  q[2] = -n2*q1 + n1*q2;
49
50  return 0;
51}
52
53// Function to obtain speed from momentum and depth.
54// This is used by flux functions
55// Input parameters uh and h may be modified by this function.
56// Tried to inline, but no speedup was achieved 27th May 2009 (Ole)
57//static inline double _compute_speed(double *uh,
58double _compute_speed(double *uh, 
59                      double *h, 
60                      double epsilon, 
61                      double h0,
62                      double limiting_threshold) {
63 
64  double u;
65
66  if (*h < limiting_threshold) {   
67    // Apply limiting of speeds according to the ANUGA manual
68    if (*h < epsilon) {
69      *h = max(0.0,*h);  // Could have been negative
70      //*h = 0.0;  // Could have been negative
71      u = 0.0;
72    } else {
73      u = *uh/(*h + h0/ *h);   
74    }
75 
76
77    // Adjust momentum to be consistent with speed
78    *uh = u * *h;
79  } else {
80    // We are in deep water - no need for limiting
81    u = *uh/ *h;
82  }
83 
84  return u;
85}
86
87// minmod limiter
88int _minmod(double a, double b){
89    // Compute minmod
90
91    if(sign(a)!=sign(b)){
92        return 0.0;
93    }else{
94        return min(fabs(a), fabs(b))*sign(a);
95    }
96
97
98}
99
100// Innermost flux function (using stage w=z+h)
101int _flux_function_central(double *q_left, double *q_right,
102                           double z_left, double z_right,
103                           double n1, double n2,
104                           double epsilon, 
105                           double h0,
106                           double limiting_threshold, 
107                           double g,
108                           double *edgeflux, double *max_speed, 
109                           double *pressure_flux, double hc, 
110                           double hc_n, double speed_max_last, 
111                           double smooth) 
112{
113
114  /*Compute fluxes between volumes for the shallow water wave equation
115    cast in terms of the 'stage', w = h+z using
116    the 'central scheme' as described in
117
118    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
119    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
120    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
121
122    The implemented formula is given in equation (3.15) on page 714
123  */
124
125  int i;
126
127  double w_left, h_left, uh_left, vh_left, u_left;
128  double w_right, h_right, uh_right, vh_right, u_right;
129  double s_min, s_max, soundspeed_left, soundspeed_right;
130  double denom, inverse_denominator, z;
131  double uint, t1, t2, t3, min_speed, tmp;
132  // Workspace (allocate once, use many)
133  static double q_left_rotated[3], q_right_rotated[3], flux_right[3], flux_left[3];
134
135  // Copy conserved quantities to protect from modification
136  q_left_rotated[0] = q_left[0];
137  q_right_rotated[0] = q_right[0];
138  q_left_rotated[1] = q_left[1];
139  q_right_rotated[1] = q_right[1];
140  q_left_rotated[2] = q_left[2];
141  q_right_rotated[2] = q_right[2];
142
143  // Align x- and y-momentum with x-axis
144  _rotate(q_left_rotated, n1, n2);
145  _rotate(q_right_rotated, n1, n2);
146
147  z = 0.5*(z_left + z_right); // Average elevation values.
148                              // Even though this will nominally allow
149                              // for discontinuities in the elevation data,
150                              // there is currently no numerical support for
151                              // this so results may be strange near
152                              // jumps in the bed.
153
154  // Compute speeds in x-direction
155  w_left = q_left_rotated[0];         
156  h_left = max(w_left - z,0.);
157  uh_left = q_left_rotated[1];
158  if(h_left>h0){
159    u_left = uh_left/max(h_left, 1.0e-06);
160    uh_left=h_left*u_left;
161  }else{
162    u_left=0.;
163    uh_left=h_left*u_left;
164  }
165  //u_left = _compute_speed(&uh_left, &h_left,
166  //                      epsilon, h0, limiting_threshold);
167
168  w_right = q_right_rotated[0];
169  h_right = max(w_right - z, 0.);
170  uh_right = q_right_rotated[1];
171  //u_right = _compute_speed(&uh_right, &h_right,
172  //                       epsilon, h0, limiting_threshold);
173  if(h_right>h0){
174    u_right = uh_right/max(h_right, 1.0e-06);
175    uh_right=h_right*u_right;
176  }else{
177    u_right=0.;
178    uh_right=h_right*u_right;
179  }
180
181  // Momentum in y-direction
182  vh_left  = q_left_rotated[2];
183  vh_right = q_right_rotated[2];
184
185  // Limit y-momentum if necessary
186  // Leaving this out, improves speed significantly (Ole 27/5/2009)
187  // All validation tests pass, so do we really need it anymore?
188  //_compute_speed(&vh_left, &h_left,
189  //             epsilon, h0, limiting_threshold);
190  //_compute_speed(&vh_right, &h_right,
191  //             epsilon, h0, limiting_threshold);
192
193  // Maximal and minimal wave speeds
194  soundspeed_left  = sqrt(g*h_left);
195  soundspeed_right = sqrt(g*h_right); 
196 
197  // Code to use fast square root optimisation if desired.
198  // Timings on AMD 64 for the Okushiri profile gave the following timings
199  //
200  // SQRT           Total    Flux
201  //=============================
202  //
203  // Ref            405s     152s
204  // Fast (dbl)     453s     173s
205  // Fast (sng)     437s     171s
206  //
207  // Consequently, there is currently (14/5/2009) no reason to use this
208  // approximation.
209 
210  //soundspeed_left  = fast_squareroot_approximation(g*h_left);
211  //soundspeed_right = fast_squareroot_approximation(g*h_right);
212
213  s_max = max(u_left + soundspeed_left, u_right + soundspeed_right);
214  if (s_max < 0.0) 
215  {
216    s_max = 0.0;
217  }
218
219  if( hc < h0){
220    s_max = 0.0;
221  }
222
223
224  s_min = min(u_left - soundspeed_left, u_right - soundspeed_right);
225  if (s_min > 0.0)
226  {
227    s_min = 0.0;
228  }
229 
230  if( hc_n < h0){
231    s_min = 0.0;
232  }
233 
234  // Flux formulas
235  flux_left[0] = u_left*h_left;
236  //if(hc>h0 & hc_n > h0){
237  //if(w_left>z+h0 & w_right>z+h0){
238    flux_left[1] = u_left*uh_left; //+ 0.5*g*h_left*h_left;
239    flux_left[2] = u_left*vh_left;
240  //}else{
241  //  flux_left[1] = 0.;//u_left*uh_left; //+ 0.5*g*h_left*h_left;
242  //  flux_left[2] = 0.;//u_left*vh_left;
243  //} 
244
245  flux_right[0] = u_right*h_right;
246  //if(w_left>z+h0 & w_right>z+h0){
247    flux_right[1] = u_right*uh_right ; //+ 0.5*g*h_right*h_right;
248    flux_right[2] = u_right*vh_right;
249  //}else{
250  //  flux_right[1] = 0.; //u_right*uh_right ; //+ 0.5*g*h_right*h_right;
251  //  flux_right[2] = 0.; //u_right*vh_right;
252  //}
253
254  // Flux computation
255  denom = s_max - s_min;
256  //if (denom < epsilon)
257  if (0==1) 
258  { 
259    // Both wave speeds are very small
260    memset(edgeflux, 0, 3*sizeof(double));
261
262    *max_speed = 0.0;
263    //*pressure_flux = 0.0;
264    *pressure_flux = 0.5*g*0.5*(h_left*h_left+h_right*h_right);
265  } 
266  else 
267  {
268    // Maximal wavespeed
269    *max_speed = max(s_max, -s_min);
270    //min_speed=min(s_max, -s_min);
271 
272    inverse_denominator = 1.0/max(denom,1.0e-100);
273    for (i = 0; i < 3; i++) 
274    {
275      edgeflux[i] = s_max*flux_left[i] - s_min*flux_right[i];
276
277      // Standard smoothing term
278      edgeflux[i] += (s_max*s_min)*(q_right_rotated[i] - q_left_rotated[i]);
279
280      // Standard smoothing term, scaled
281      //edgeflux[i] += (s_max*s_min)*(q_right_rotated[i] - q_left_rotated[i])*smooth;
282
283      // Adjustment to the scheme by Kurganov and Lin 2007 Communications in Computational
284      // Physics 2:141-163
285      //uint = (s_max*q_right_rotated[i] - s_min*q_left_rotated[i] - (flux_right[i] - flux_left[i]))*inverse_denominator;
286      //t1 = (q_right_rotated[i] - uint);
287      //t2 = (-q_left_rotated[i] + uint);
288      //t3 = _minmod(t1,t2);
289      //edgeflux[i] += (s_max*s_min)*(q_right_rotated[i] - q_left_rotated[i]-t3);
290
291      // test this
292      //edgeflux[i] += (s_max*s_min)*(q_right_rotated[i] - q_left_rotated[i])*pow(min(hc/(hc_n+epsilon), hc_n/(hc+epsilon)),1.0);
293   
294      // test this
295      //tmp=min(fabs(q_right_rotated[i])/(fabs(q_left_rotated[i])+epsilon) , fabs(q_left_rotated[i])/(fabs(q_right_rotated[i])+epsilon));
296      //edgeflux[i] += (s_max*s_min)*(q_right_rotated[i] - q_left_rotated[i]-t3)*pow(tmp,1.0);
297
298      //GD HACK: Here, we supress the 'smoothing' part of the flux -- like scaling diffusion by local wave speed
299      // This is a bad idea! E.g. oscillations in landslide wave runup case
300      // However, it does supress the growth of some wet-dry instabilities (e.g. PNG).
301      //if(i!=2){
302      //edgeflux[i] += (s_max*s_min)*(q_right_rotated[i] - q_left_rotated[i])*
303      //               (min(*max_speed/(max(speed_max_last,1.0e-100)),1.0));//(min(hc/h_left,min(hc_n/h_right,1.0)));
304      //}
305
306      edgeflux[i] *= inverse_denominator;
307    }
308    // Separate pressure flux, so we can apply different wet-dry hacks to it
309    *pressure_flux = 0.5*g*( s_max*h_left*h_left -s_min*h_right*h_right)*inverse_denominator;
310   
311
312    // Rotate back
313    _rotate(edgeflux, n1, -n2);
314  }
315 
316  return 0;
317}
318
319
320// Computational function for flux computation
321double _compute_fluxes_central(int number_of_elements,
322        double timestep,
323        double epsilon,
324        double H0,
325        double g,
326        double* boundary_flux_sum,
327        long* neighbours,
328        long* neighbour_edges,
329        double* normals,
330        double* edgelengths,
331        double* radii,
332        double* areas,
333        long* tri_full_flag,
334        double* stage_edge_values,
335        double* xmom_edge_values,
336        double* ymom_edge_values,
337        double* bed_edge_values,
338        double* stage_boundary_values,
339        double* xmom_boundary_values,
340        double* ymom_boundary_values,
341        long*   boundary_flux_type,
342        double* stage_explicit_update,
343        double* xmom_explicit_update,
344        double* ymom_explicit_update,
345        long* already_computed_flux,
346        double* max_speed_array,
347        int optimise_dry_cells, 
348        int timestep_order,
349        double* stage_centroid_values,
350        double* xmom_centroid_values,
351        double* ymom_centroid_values,
352        double* bed_centroid_values,
353        double* bed_vertex_values) {
354    // Local variables
355    double max_speed, length, inv_area, zl, zr;
356    double h0 = H0*2.0;//H0*H0;//H0*H0; // This ensures a good balance when h approaches H0.
357
358    double limiting_threshold = 10 * H0 ;//H0; //10 * H0; // Avoid applying limiter below this
359    // threshold for performance reasons.
360    // See ANUGA manual under flux limiting
361    int k, i, m, n,j, ii;
362    int ki, nm = 0, ki2,ki3, nm3; // Index shorthands
363
364    // Workspace (making them static actually made function slightly slower (Ole))
365    double ql[3], qr[3], edgeflux[3]; // Work array for summing up fluxes
366    double stage_edges[3];//Work array
367    double bedslope_work, local_timestep;
368    int neighbours_wet[3];//Work array
369    int useint;
370    double stage_edge_lim, outgoing_mass_edges, bedtop, bedbot, pressure_flux, hc, hc_n, tmp, tmp2;
371    static long call = 1; // Static local variable flagging already computed flux
372    double speed_max_last, vol, smooth;
373
374    double *count_wet_edges, *count_wet_neighbours, *edgeflux_store, *pressuregrad_store;
375
376    count_wet_neighbours = malloc(number_of_elements*sizeof(double));
377    count_wet_edges = malloc(number_of_elements*sizeof(double));
378    edgeflux_store = malloc(number_of_elements*9*sizeof(double));
379    pressuregrad_store = malloc(number_of_elements*3*sizeof(double));
380
381    call++; // Flag 'id' of flux calculation for this timestep
382
383    // Set explicit_update to zero for all conserved_quantities.
384    // This assumes compute_fluxes called before forcing terms
385    memset((char*) stage_explicit_update, 0, number_of_elements * sizeof (double));
386    memset((char*) xmom_explicit_update, 0, number_of_elements * sizeof (double));
387    memset((char*) ymom_explicit_update, 0, number_of_elements * sizeof (double));
388
389    local_timestep=timestep;
390
391    //printf("timestep_order %lf \n", timestep_order*1.0);
392    // Compute minimum bed edge value on each triangle
393    speed_max_last=0.0;
394    for (k = 0; k < number_of_elements; k++){
395       
396        count_wet_edges[k] = 0.;
397        count_wet_neighbours[k] = 0.;
398        for (i =0; i<3; i++){
399            ki=3*k+i;
400            if(stage_edge_values[ki] > bed_edge_values[ki]+epsilon) count_wet_edges[k]+=1.0;
401           
402            n=neighbours[ki];
403            if(n<0 || stage_centroid_values[n] > bed_centroid_values[n]+h0+epsilon) count_wet_neighbours[k]+=1.0;
404        }
405
406        speed_max_last=max(speed_max_last, max_speed_array[k]);
407    }
408
409    // For all triangles
410    for (k = 0; k < number_of_elements; k++) {
411        // Loop through neighbours and compute edge flux for each
412        for (i = 0; i < 3; i++) {
413            ki = k * 3 + i; // Linear index to edge i of triangle k
414            ki2 = 2 * ki; //k*6 + i*2
415            ki3 = 3*ki; 
416
417            if (already_computed_flux[ki] == call) {
418                // We've already computed the flux across this edge
419                continue;
420            }
421
422            // Get left hand side values from triangle k, edge i
423            ql[0] = stage_edge_values[ki];
424            ql[1] = xmom_edge_values[ki];
425            ql[2] = ymom_edge_values[ki];
426            zl = bed_edge_values[ki];
427            hc = max(stage_centroid_values[k] - bed_centroid_values[k],0.0);
428
429            // Get right hand side values either from neighbouring triangle
430            // or from boundary array (Quantities at neighbour on nearest face).
431            n = neighbours[ki];
432            hc_n = hc;
433            if (n < 0) {
434                // Neighbour is a boundary condition
435                m = -n - 1; // Convert negative flag to boundary index
436
437                qr[0] = stage_boundary_values[m];
438                qr[1] = xmom_boundary_values[m];
439                qr[2] = ymom_boundary_values[m];
440                zr = zl; // Extend bed elevation to boundary
441            }
442            else {
443                // Neighbour is a real triangle
444                hc_n = max(stage_centroid_values[n] - bed_centroid_values[n],0.0);
445                m = neighbour_edges[ki];
446                nm = n * 3 + m; // Linear index (triangle n, edge m)
447                nm3 = nm*3;
448
449                qr[0] = stage_edge_values[nm];
450                qr[1] = xmom_edge_values[nm];
451                qr[2] = ymom_edge_values[nm];
452                zr = bed_edge_values[nm];
453            }
454           
455            if (fabs(zl-zr)>1.0e-10) {
456                report_python_error(AT,"Discontinuous Elevation");
457                return 0.0;
458            }
459           
460
461            smooth=1.0;
462            //if((count_wet_edges[k]<=1.0 | count_wet_neighbours[k]<=1.0) &
463            //    (n>=0 && (count_wet_edges[n]<=1.0 | count_wet_neighbours[n]<=1.0))){
464            //    smooth=0.0;
465            //}
466           
467            // Edge flux computation (triangle k, edge i)
468            _flux_function_central(ql, qr, zl, zr,
469                    normals[ki2], normals[ki2 + 1],
470                    epsilon, h0, limiting_threshold, g,
471                    edgeflux, &max_speed, &pressure_flux, hc, hc_n, 
472                    speed_max_last, smooth);
473
474           
475            // Multiply edgeflux by edgelength
476            length = edgelengths[ki];
477            edgeflux[0] *= length;
478            edgeflux[1] *= length;
479            edgeflux[2] *= length;
480
481            edgeflux_store[ki3 + 0 ] = -edgeflux[0];
482            edgeflux_store[ki3 + 1 ] = -edgeflux[1];
483            edgeflux_store[ki3 + 2 ] = -edgeflux[2];
484
485            // Update triangle k with flux from edge i
486            // bedslope_work contains all gravity related terms -- weighting of
487            // conservative and non-conservative versions.
488
489            if(ql[0]>zl){
490               tmp=1.0;
491            }else{
492               tmp=1.;
493            }
494            if(hc> h0){
495            //if(stage_centroid_values[k] > count_wet_edges[k]){
496              bedslope_work = length*(g*(hc*ql[0]-0.5*max(ql[0]-zl,0.)*(ql[0]-zl))*tmp + pressure_flux);
497              //bedslope_work = length*(g*(hc*stage_centroid_values[k]*0.-
498              //                           0.5*max(stage_centroid_values[k]-zl,0.)*(stage_centroid_values[k]-zl))
499              //                        + pressure_flux);
500              //bedslope_work+= (1.0-tmp)*length*g*hc*ql[0]; // Non-conservative water surface slope
501              pressuregrad_store[ki] = bedslope_work;
502            }else{
503              // NOTE: When hc<h0, local contribution to the pressure_flux is
504              // entirely computed from the other side of the edge. Hence, we
505              // can't necessarily satisfy well-balancing by just assuming that
506              // the 2nd and 3rd terms in bedslope_work cancel. So, we force it
507              // here -- equivalent to using the water surface gravity term
508              bedslope_work = length*(g*(hc*ql[0]*tmp-0.0*max(ql[0]-zl,0.)*(ql[0]-zl))*tmp + 0.0*pressure_flux);
509              //bedslope_work = length*(g*(hc*stage_centroid_values[k]-0.0*max(ql[0]-zl,0.)*(ql[0]-zl)) + 0.0*pressure_flux);
510              //bedslope_work+= (1.0-tmp)*length*g*hc*ql[0]; // Non-conservative water surface slope
511              pressuregrad_store[ki] = bedslope_work;
512            }
513
514            //if(count_wet_edges[k]<=1.0) pressuregrad_store[ki]=0.0;
515
516            already_computed_flux[ki] = call; // #k Done
517
518
519            // Update neighbour n with same flux but reversed sign
520            if (n >= 0) {
521
522                edgeflux_store[nm3 + 0 ] = edgeflux[0];
523                edgeflux_store[nm3 + 1 ] = edgeflux[1];
524                edgeflux_store[nm3 + 2 ] = edgeflux[2];
525
526                if(qr[0]>zr){
527                   tmp=1.0;
528                }else{
529                   tmp=1.;
530                }
531                if(hc_n> h0){
532                //if(stage_centroid_values[n] > count_wet_edges[n]){
533                  bedslope_work = length*(g*(hc_n*qr[0]*tmp-0.5*max(qr[0]-zr,0.)*(qr[0]-zr))*tmp + pressure_flux);
534                  //bedslope_work = length*(g*(hc_n*stage_centroid_values[n]*0.-0.5*max(stage_centroid_values[n]-zr,0.)*
535                  //                                (stage_centroid_values[n]-zr)) + pressure_flux);
536                  //bedslope_work+= (1.-tmp)*length*g*hc_n*qr[0]; 
537                  pressuregrad_store[nm] = bedslope_work;
538                }else{
539                  // NOTE: When hc<h0, pressure_flux is entirely computed from the
540                  // other side of the edge. Hence, we can't necessarily satisfy
541                  // well-balancing by just assuming that the 2nd and 3rd terms in
542                  // bedslope_work cancel. So, we force it here -- equivalent to
543                  // using the water surface gravity term
544                  bedslope_work = length*(g*(hc_n*qr[0]*tmp-0.0*max(qr[0]-zr,0.)*(qr[0]-zr))*tmp + 0.0*pressure_flux);
545                  //bedslope_work = length*(g*(hc_n*stage_centroid_values[n]-0.0*max(qr[0]-zr,0.)*(qr[0]-zr)) + 0.0*pressure_flux);
546                  //bedslope_work+= (1.-tmp)*length*g*hc_n*qr[0]; 
547                  pressuregrad_store[nm] = bedslope_work;
548                }
549           
550                //if(count_wet_edges[n]<=1.0) pressuregrad_store[nm]=0.0;
551
552                already_computed_flux[nm] = call; // #n Done
553            }
554
555            //if(n==576 | n==579) pressuregrad_store[nm]=0.;
556            // Update timestep based on edge i and possibly neighbour n
557            // GD HACK:
558            // FIXME: Presently this 'hacked' to only update the timestep on
559            // every 2nd call.  This works for rk2 timestepping only, and is
560            // needed for correct wetting and drying treatment
561            if ((tri_full_flag[k] == 1) ) {
562
563                if((call-2)%timestep_order!=0) max_speed = max_speed_array[k]; // HACK to Ensure that local timestep is the same as the last timestep
564
565                if (max_speed > epsilon) {
566                    // Apply CFL condition for triangles joining this edge (triangle k and triangle n)
567
568                    // CFL for triangle k
569                    local_timestep = min(local_timestep, radii[k] / max_speed);
570
571                    if (n >= 0) {
572                        // Apply CFL condition for neigbour n (which is on the ith edge of triangle k)
573                        local_timestep = min(local_timestep, radii[n] / max_speed);
574                    }
575
576                }
577            }
578
579        } // End edge i (and neighbour n)
580
581        // Keep track of maximal speeds
582        max_speed_array[k] = max_speed;
583
584    } // End triangle k
585 
586    // GD HACK
587    // Limit edgefluxes, for mass conservation near wet/dry cells
588    for(k=0; k< number_of_elements; k++){
589            //continue;
590            hc = max(stage_centroid_values[k] - bed_centroid_values[k],0.);
591            // Loop over every edge
592            for(i = 0; i<3; i++){
593                if(i==0){
594                    // Add up the outgoing flux through the cell
595                    outgoing_mass_edges=0.0;
596                    for(useint=0; useint<3; useint++){
597                        if(edgeflux_store[3*(3*k+useint)]< 0.){
598                            //outgoing_mass_edges+=1.0;
599                            outgoing_mass_edges+=(edgeflux_store[3*(3*k+useint)]);
600                        }
601                    }
602                    outgoing_mass_edges*=local_timestep;
603                }
604
605                ki=3*k+i;   
606                ki2=ki*2;
607                ki3 = ki*3;
608               
609                // Prevent outflow from 'seriously' dry cells
610                // Idea: The cell will not go dry if:
611                // total_outgoing_flux <= cell volume = Area_triangle*hc
612                vol=areas[k]*hc;
613                if((edgeflux_store[ki3]< 0.0) && (-outgoing_mass_edges> vol)){
614                   
615                    // This bound could be improved (e.g. we could actually sum
616                    // the + and - fluxes and check if they are too large).
617                    // However, the advantage is that we don't have to worry
618                    // about subsequent changes to the + edgeflux caused by
619                    // constraints associated with neighbouring triangles.
620                    tmp = vol/(-(outgoing_mass_edges)) ;
621                    if(tmp< 1.0){
622                        edgeflux_store[ki3+0]*=tmp;
623                        edgeflux_store[ki3+1]*=tmp;
624                        edgeflux_store[ki3+2]*=tmp;
625
626                        // Compute neighbour edge index
627                        n = neighbours[ki];
628                        if(n>=0){
629                            nm = 3*n + neighbour_edges[ki];
630                            nm3 = nm*3;
631                            edgeflux_store[nm3+0]*=tmp;
632                            edgeflux_store[nm3+1]*=tmp;
633                            edgeflux_store[nm3+2]*=tmp;
634                        }
635                    }
636                }
637        }
638     }
639
640    // Now add up stage, xmom, ymom explicit updates
641    for(k=0; k<number_of_elements; k++){
642        hc = max(stage_centroid_values[k] - bed_centroid_values[k],0.);
643        stage_explicit_update[k]=0.;
644        xmom_explicit_update[k]=0.;
645        ymom_explicit_update[k]=0.;
646
647        for(i=0;i<3;i++){
648            ki=3*k+i;   
649            ki2=ki*2;
650            ki3 = ki*3;
651            n=neighbours[ki];
652
653            // GD HACK
654            // Option to limit advective fluxes
655            if(hc > -h0){
656                stage_explicit_update[k] += edgeflux_store[ki3+0];
657                // Cut these terms for shallow flows, and protect stationary states from round-off error
658                xmom_explicit_update[k] += edgeflux_store[ki3+1];
659                ymom_explicit_update[k] += edgeflux_store[ki3+2];
660            }else{
661                stage_explicit_update[k] += edgeflux_store[ki3+0];
662            }
663
664
665            // If neighbour is a boundary condition, add the flux to the boundary_flux_integral
666            if(n<0){ 
667                boundary_flux_sum[0] += edgeflux_store[ki3];
668            }
669
670            // GD HACK
671            // Compute bed slope term
672            if(hc > -h0){
673                xmom_explicit_update[k] -= normals[ki2]*pressuregrad_store[ki];
674                ymom_explicit_update[k] -= normals[ki2+1]*pressuregrad_store[ki];
675            }else{
676                xmom_explicit_update[k] *= 0.;
677                ymom_explicit_update[k] *= 0.;
678            }
679
680        } // end edge i
681
682        // Normalise triangle k by area and store for when all conserved
683        // quantities get updated
684        inv_area = 1.0 / areas[k];
685        stage_explicit_update[k] *= inv_area;
686        xmom_explicit_update[k] *= inv_area;
687        ymom_explicit_update[k] *= inv_area;
688    }  // end cell k
689
690    if((call-2)%timestep_order==0) timestep=local_timestep; // Hack to ensure we only update the timestep on the first call within each rk2/rk3 step
691
692    // Look for 'dry' edges, and set momentum (& component of momentum_update)
693    // in that direction to zero. If we don't do this, then it is possible for
694    // the bedslope term normal to that edge to be nonzero, and for momentum to
695    // keep 'building' up in the cell without being able to flow out.
696    //
697    //for(k=0; k<number_of_elements; k++){
698    //    // Ignore "Dry" centroid cells, which will automatically have their
699    //    // momentum set to zero (in _protect)
700    //    if(stage_centroid_values[k] - bed_centroid_values[k] > H0){
701    //        for(i=0;i<3;i++){
702    //            ki=3*k+i;
703    //            if(stage_edge_values[ki] - bed_edge_values[ki] <=0.){
704    //              // Compute magnitude of momentum_update in direction normal to edge
705    //              tmp =  xmom_explicit_update[k]*normals[2*ki] + ymom_explicit_update[k]*normals[2*ki+1];
706    //              if(tmp > 0.){
707    //                  // Set component of momentum_update normal to edge to zero
708    //                  // [equivalently, subtract component of momentum_update normal to edge]
709    //                  xmom_explicit_update[k] -= tmp*normals[2*ki];
710    //                  ymom_explicit_update[k] -= tmp*normals[2*ki+1]; 
711    //                 
712    //              }
713    //             
714    //              // Compute magnitude of momentum in direction normal to edge
715    //              //tmp =  xmom_centroid_values[k]*normals[2*ki] + ymom_centroid_values[k]*normals[2*ki+1];
716    //              //if(tmp > 0.){
717    //              //    // Set component of momentum normal to edge to zero
718    //              //    // [equivalently, subtract component of momentum normal to edge]
719    //              //    xmom_centroid_values[k] -= tmp*normals[2*ki];
720    //              //    ymom_centroid_values[k] -= tmp*normals[2*ki+1]; 
721    //              //   
722    //              //}
723    //           }
724    //        }
725    //    }
726    //}
727       
728    //   
729    //   
730    //    if((fabs(xmom_explicit_update[k])>1.0e-06)|fabs(ymom_explicit_update[k])>1.0e-06){
731    //        printf(" %e, %e, %e,%e,%e,%e, %e,%e,%e,%d,%e,%e,%e\n", stage_explicit_update[k], xmom_explicit_update[k], ymom_explicit_update[k],
732    //                                    stage_centroid_values[k], bed_centroid_values[k],
733    //                                    stage_centroid_values[k]- bed_centroid_values[k],
734    //                                    stage_edge_values[3*neighbours[3*k+0]+neighbour_edges[3*k+0]],
735    //                                    stage_edge_values[3*neighbours[3*k+1]+neighbour_edges[3*k+1]],
736    //                                    stage_edge_values[3*neighbours[3*k+2]+neighbour_edges[3*k+2]],
737    //                                    k,
738    //                                    stage_edge_values[3*k+0],
739    //                                    stage_edge_values[3*k+1],
740    //                                    stage_edge_values[3*k+2]);
741    //    }
742    //}
743    //printf("max ymom edge value is: %e \n", bedtop);
744    //report_python_error(AT, "Written out stage, xmom and ymom updates");
745    //return -1;
746//
747    free(count_wet_edges);
748    free(count_wet_neighbours);
749    free(edgeflux_store);
750    free(pressuregrad_store);
751
752    return timestep;
753}
754
755// Protect against the water elevation falling below the triangle bed
756int _protect(int N,
757         double minimum_allowed_height,
758         double maximum_allowed_speed,
759         double epsilon,
760         double* wc,
761         double* wv,
762         double* zc,
763         double* zv,
764         double* xmomc,
765         double* ymomc,
766         double* areas,
767         double* xc,
768         double* yc) {
769
770  int k;
771  double hc, bmin, bmax;
772  double u, v, reduced_speed;
773  static double mass_error=0.; 
774  // This acts like minimum_allowed height, but scales with the vertical
775  // distance between the bed_centroid_value and the max bed_edge_value of
776  // every triangle.
777  double minimum_relative_height=0.05; 
778  int mass_added=0;
779
780  // Protect against inifintesimal and negative heights 
781  //if (maximum_allowed_speed < epsilon) {
782    for (k=0; k<N; k++) {
783      hc = wc[k] - zc[k];
784      // Definine the maximum bed edge value on triangle k.
785      //bmax = 0.5*max((zv[3*k]+zv[3*k+1]),max((zv[3*k+1]+zv[3*k+2]),(zv[3*k+2]+zv[3*k])));
786      bmax = max(zv[3*k],max(zv[3*k+2],zv[3*k+1]));
787
788      //if (hc < max(minimum_relative_height*(bmax-zc[k]), minimum_allowed_height)) {
789      //  xmomc[k]*=0.1;
790      //  ymomc[k]*=0.1;
791      //}
792
793
794      //if (hc < minimum_allowed_height*2.0 | hc < minimum_relative_height*(bmax-zc[k]) ){
795      if (hc < minimum_allowed_height*2.0 ){
796      //if (hc < minimum_allowed_height*2.0 ){
797            // Set momentum to zero and ensure h is non negative
798            //xmomc[k] = 0.;//xmomc[k]*hc*max(hc-minimum_allowed_height,0.)/(2.0*minimum_allowed_height*minimum_allowed_height);// 0.0;
799            //ymomc[k] = 0.;//ymomc[k]*hc*max(hc-minimum_allowed_height,0.)/(2.0*minimum_allowed_height*minimum_allowed_height);// 0.0;
800            //xmomc[k] = xmomc[k]*hc*max(hc-minimum_allowed_height,0.)/(2.0*minimum_allowed_height*minimum_allowed_height);// 0.0;
801            //ymomc[k] = ymomc[k]*hc*max(hc-minimum_allowed_height,0.)/(2.0*minimum_allowed_height*minimum_allowed_height);// 0.0;
802            //xmomc[k] = xmomc[k]*max(hc-minimum_allowed_height,0.)/(minimum_allowed_height);// 0.0;
803            //ymomc[k] = ymomc[k]*max(hc-minimum_allowed_height,0.)/(minimum_allowed_height);// 0.0;
804
805        if (hc <= 0.0){
806             // Definine the minimum bed edge value on triangle k.
807             //bmin = 0.5*min((zv[3*k]+zv[3*k+1]),min((zv[3*k+1]+zv[3*k+2]),(zv[3*k+2]+zv[3*k])));
808             //bmin =0.5*bmin + 0.5*min(zv[3*k],min(zv[3*k+1],zv[3*k+2]));
809             //bmin =min(zv[3*k],min(zv[3*k+1],zv[3*k+2])) -minimum_allowed_height;
810             bmin=zc[k]-minimum_allowed_height;//-1.0e-03;
811             // Minimum allowed stage = bmin
812
813             // WARNING: ADDING MASS if wc[k]<bmin
814             if(wc[k]<bmin){
815                 mass_error+=(bmin-wc[k])*areas[k];
816                 mass_added=1; //Flag to warn of added mass               
817
818                 wc[k] = max(wc[k], bmin); 
819                 //printf(" mass_add, %f, %f, %f,%f,%f,%d\n", xc[k], yc[k], wc[k],zc[k],wc[k]-zc[k], k) ;
820             
821
822                 // FIXME: Set vertex values as well. Seems that this shouldn't be
823                 // needed. However, from memory this is important at the first
824                 // time step, for 'dry' areas where the designated stage is
825                 // less than the bed centroid value
826                 //wv[3*k] = max(wv[3*k], min(bmin, zv[3*k]-minimum_allowed_height));
827                 //wv[3*k+1] = max(wv[3*k+1], min(bmin, zv[3*k+1]-minimum_allowed_height));
828                 //wv[3*k+2] = max(wv[3*k+2], min(bmin, zv[3*k+2]-minimum_allowed_height));
829                 wv[3*k] = min(bmin, wc[3*k]); //zv[3*k]-minimum_allowed_height);
830                 wv[3*k+1] = min(bmin, wc[3*k+1]); //zv[3*k+1]-minimum_allowed_height);
831                 wv[3*k+2] = min(bmin, wc[3*k+2]); //zv[3*k+2]-minimum_allowed_height);
832            }
833        }
834      }
835    }
836
837  if(mass_added==1){
838     printf("Cumulative mass protection: %f m^3 \n", mass_error);
839  }
840  return 0;
841}
842
843int find_qmin_and_qmax(double dq0, double dq1, double dq2, 
844               double *qmin, double *qmax){
845  // Considering the centroid of an FV triangle and the vertices of its
846  // auxiliary triangle, find
847  // qmin=min(q)-qc and qmax=max(q)-qc,
848  // where min(q) and max(q) are respectively min and max over the
849  // four values (at the centroid of the FV triangle and the auxiliary
850  // triangle vertices),
851  // and qc is the centroid
852  // dq0=q(vertex0)-q(centroid of FV triangle)
853  // dq1=q(vertex1)-q(vertex0)
854  // dq2=q(vertex2)-q(vertex0)
855
856  // This is a simple implementation
857  *qmax = max(max(dq0, max(dq0+dq1, dq0+dq2)), 0.0) ;
858  *qmin = min(min(dq0, min(dq0+dq1, dq0+dq2)), 0.0) ;
859 
860  return 0;
861}
862
863int limit_gradient(double *dqv, double qmin, double qmax, double beta_w){
864  // Given provisional jumps dqv from the FV triangle centroid to its
865  // vertices and jumps qmin (qmax) between the centroid of the FV
866  // triangle and the minimum (maximum) of the values at the centroid of
867  // the FV triangle and the auxiliary triangle vertices,
868  // calculate a multiplicative factor phi by which the provisional
869  // vertex jumps are to be limited
870 
871  int i;
872  double r=1000.0, r0=1.0, phi=1.0;
873  static double TINY = 1.0e-100; // to avoid machine accuracy problems.
874  // FIXME: Perhaps use the epsilon used elsewhere.
875 
876  // Any provisional jump with magnitude < TINY does not contribute to
877  // the limiting process.
878  //return 0;
879 
880  for (i=0;i<3;i++){
881    if (dqv[i]<-TINY)
882      r0=qmin/dqv[i];
883     
884    if (dqv[i]>TINY)
885      r0=qmax/dqv[i];
886     
887    r=min(r0,r);
888  }
889 
890  phi=min(r*beta_w,1.0);
891  //phi=1.;
892  dqv[0]=dqv[0]*phi;
893  dqv[1]=dqv[1]*phi;
894  dqv[2]=dqv[2]*phi;
895
896 
897  //printf("%lf \n ", beta_w);
898   
899  return 0;
900}
901
902// Computational routine
903int _extrapolate_second_order_edge_sw(int number_of_elements,
904                                 double epsilon,
905                                 double minimum_allowed_height,
906                                 double beta_w,
907                                 double beta_w_dry,
908                                 double beta_uh,
909                                 double beta_uh_dry,
910                                 double beta_vh,
911                                 double beta_vh_dry,
912                                 long* surrogate_neighbours,
913                                 long* neighbour_edges,
914                                 long* number_of_boundaries,
915                                 double* centroid_coordinates,
916                                 double* stage_centroid_values,
917                                 double* xmom_centroid_values,
918                                 double* ymom_centroid_values,
919                                 double* elevation_centroid_values,
920                                 double* edge_coordinates,
921                                 double* stage_edge_values,
922                                 double* xmom_edge_values,
923                                 double* ymom_edge_values,
924                                 double* elevation_edge_values,
925                                 double* stage_vertex_values,
926                                 double* xmom_vertex_values,
927                                 double* ymom_vertex_values,
928                                 double* elevation_vertex_values,
929                                 int optimise_dry_cells, 
930                                 int extrapolate_velocity_second_order) {
931                 
932  // Local variables
933  double a, b; // Gradient vector used to calculate edge values from centroids
934  int k, k0, k1, k2, k3, k6, coord_index, i, ii, ktmp, k_wetdry;
935  double x, y, x0, y0, x1, y1, x2, y2, xv0, yv0, xv1, yv1, xv2, yv2; // Vertices of the auxiliary triangle
936  double dx1, dx2, dy1, dy2, dxv0, dxv1, dxv2, dyv0, dyv1, dyv2, dq0, dq1, dq2, area2, inv_area2;
937  double dqv[3], qmin, qmax, hmin, hmax, bedmax,bedmin, stagemin;
938  double hc, h0, h1, h2, beta_tmp, hfactor, xtmp, ytmp, weight, tmp;
939  double dk, dv0, dv1, dv2, de[3], demin, dcmax, r0scale, vect_norm, l1, l2, a_bs, b_bs, area_e, inv_area_e;
940 
941  double *xmom_centroid_store, *ymom_centroid_store, *stage_centroid_store, *min_elevation_edgevalue, *max_elevation_edgevalue;
942  double *cell_wetness_scale;
943  int *count_wet_neighbours;
944
945  // Use malloc to avoid putting these variables on the stack, which can cause
946  // segfaults in large model runs
947  xmom_centroid_store = malloc(number_of_elements*sizeof(double));
948  ymom_centroid_store = malloc(number_of_elements*sizeof(double));
949  stage_centroid_store = malloc(number_of_elements*sizeof(double));
950  min_elevation_edgevalue = malloc(number_of_elements*sizeof(double));
951  max_elevation_edgevalue = malloc(number_of_elements*sizeof(double));
952  cell_wetness_scale = malloc(number_of_elements*sizeof(double));
953  count_wet_neighbours = malloc(number_of_elements*sizeof(int));
954 
955  if(extrapolate_velocity_second_order==1){
956      // Replace momentum centroid with velocity centroid to allow velocity
957      // extrapolation This will be changed back at the end of the routine
958      for (k=0; k<number_of_elements; k++){
959
960          dk = max(stage_centroid_values[k]-elevation_centroid_values[k],minimum_allowed_height);
961          xmom_centroid_store[k] = xmom_centroid_values[k];
962          xmom_centroid_values[k] = xmom_centroid_values[k]/dk;
963
964          ymom_centroid_store[k] = ymom_centroid_values[k];
965          ymom_centroid_values[k] = ymom_centroid_values[k]/dk;
966
967          min_elevation_edgevalue[k] = min(elevation_edge_values[3*k], 
968                                           min(elevation_edge_values[3*k+1],
969                                               elevation_edge_values[3*k+2]));
970          max_elevation_edgevalue[k] = max(elevation_edge_values[3*k], 
971                                           max(elevation_edge_values[3*k+1],
972                                               elevation_edge_values[3*k+2]));
973           
974          }
975
976      }
977
978  //
979  // Compute some useful statistics on wetness/dryness
980  //
981  for(k=0; k<number_of_elements;k++){ 
982      cell_wetness_scale[k] = 0.;
983      // Check if cell k is wet
984      //if(stage_centroid_values[k] > elevation_centroid_values[k]){
985      if(stage_centroid_values[k] > elevation_centroid_values[k] + 2*minimum_allowed_height+epsilon){
986      //if(stage_centroid_values[k] > max_elevation_edgevalue[k] + minimum_allowed_height+epsilon){
987          cell_wetness_scale[k] = 1.; 
988      }
989  }
990  //
991  for(k=0; k<number_of_elements;k++){ 
992      // Count the wet neighbours
993      count_wet_neighbours[k]=0;
994      for (i=0; i<3; i++){
995        ktmp = surrogate_neighbours[3*k+i];             
996        if( (ktmp >= 0) && cell_wetness_scale[ktmp]>0.){
997            count_wet_neighbours[k]+=1;
998        }else if(ktmp<=0){
999            // Boundary condition -- FIXME: assume wet
1000            count_wet_neighbours[k]+=1;
1001        }
1002         
1003       
1004      }
1005  }
1006
1007  // Alternative 'PROTECT' step
1008  for(k=0; k<number_of_elements;k++){ 
1009    //if(count_wet_neighbours[k]<=3){
1010    if(1==1){
1011        bedmax = max(elevation_vertex_values[3*k],
1012                         max(elevation_vertex_values[3*k+1], 
1013                             elevation_vertex_values[3*k+2]));
1014        if((cell_wetness_scale[k]==0. ) ||
1015            ((stage_centroid_values[k] - elevation_centroid_values[k] < 0.05*(bedmax-elevation_centroid_values[k])) &
1016             count_wet_neighbours[k]<=3) ){
1017            xmom_centroid_store[k]=0.;
1018            xmom_centroid_values[k]=0.;
1019            ymom_centroid_store[k]=0.;
1020            ymom_centroid_values[k]=0.;
1021        }
1022    } 
1023  }
1024 
1025  // First treat all 'fully wet' cells, then treat 'partially dry' cells
1026  for(k_wetdry=0; k_wetdry<2; k_wetdry++){
1027
1028      // Begin extrapolation routine
1029      for (k = 0; k < number_of_elements; k++) 
1030      {
1031
1032        // First treat all 'fully wet' cells, then treat 'partially dry' cells
1033        // For partially wet cells, we now know that the edges of neighbouring
1034        // fully wet cells have been defined
1035        if( cell_wetness_scale[k]==1.0*(1-k_wetdry) ){
1036          continue;
1037        }
1038
1039        // Useful indices
1040        k3=k*3;
1041        k6=k*6;
1042
1043        if (number_of_boundaries[k]==3)
1044        {
1045          // No neighbours, set gradient on the triangle to zero
1046         
1047          stage_edge_values[k3]   = stage_centroid_values[k];
1048          stage_edge_values[k3+1] = stage_centroid_values[k];
1049          stage_edge_values[k3+2] = stage_centroid_values[k];
1050          xmom_edge_values[k3]    = xmom_centroid_values[k];
1051          xmom_edge_values[k3+1]  = xmom_centroid_values[k];
1052          xmom_edge_values[k3+2]  = xmom_centroid_values[k];
1053          ymom_edge_values[k3]    = ymom_centroid_values[k];
1054          ymom_edge_values[k3+1]  = ymom_centroid_values[k];
1055          ymom_edge_values[k3+2]  = ymom_centroid_values[k];
1056         
1057          continue;
1058        }
1059        else 
1060        {
1061          // Triangle k has one or more neighbours.
1062          // Get centroid and edge coordinates of the triangle
1063         
1064          // Get the edge coordinates
1065          xv0 = edge_coordinates[k6];   
1066          yv0 = edge_coordinates[k6+1];
1067          xv1 = edge_coordinates[k6+2]; 
1068          yv1 = edge_coordinates[k6+3];
1069          xv2 = edge_coordinates[k6+4]; 
1070          yv2 = edge_coordinates[k6+5];
1071         
1072          // Get the centroid coordinates
1073          coord_index = 2*k;
1074          x = centroid_coordinates[coord_index];
1075          y = centroid_coordinates[coord_index+1];
1076         
1077          // Store x- and y- differentials for the edges of
1078          // triangle k relative to the centroid
1079          dxv0 = xv0 - x; 
1080          dxv1 = xv1 - x; 
1081          dxv2 = xv2 - x;
1082          dyv0 = yv0 - y; 
1083          dyv1 = yv1 - y; 
1084          dyv2 = yv2 - y;
1085
1086
1087          // Compute bed slope as a reference
1088          //area_e = (yv2-yv0)*(xv1-xv0) - (yv1-yv0)*(xv2-xv0);
1089          //inv_area_e=1.0/area_e;
1090          //a_bs = (yv2 - yv0)*(elevation_edge_values[k3+1]-elevation_edge_values[k3+0]) -
1091          //       (yv1 - yv0)*(elevation_edge_values[k3+2]-elevation_edge_values[k3+0]);
1092          //a_bs *= inv_area_e;
1093
1094          //b_bs = -(xv2 - xv0)*(elevation_edge_values[k3+1]-elevation_edge_values[k3+0]) +
1095          //       (xv1 - xv0)*(elevation_edge_values[k3+2]-elevation_edge_values[k3+0]);
1096          //b_bs *= inv_area_e;
1097
1098          //printf("slopes: %f, %f \n", a_bs, b_bs);
1099        }
1100
1101
1102               
1103        if (number_of_boundaries[k]<=1)
1104        {
1105          //==============================================
1106          // Number of boundaries <= 1
1107          // 'Typical case'
1108          //==============================================   
1109       
1110       
1111          // If no boundaries, auxiliary triangle is formed
1112          // from the centroids of the three neighbours
1113          // If one boundary, auxiliary triangle is formed
1114          // from this centroid and its two neighbours
1115         
1116          k0 = surrogate_neighbours[k3];
1117          k1 = surrogate_neighbours[k3 + 1];
1118          k2 = surrogate_neighbours[k3 + 2];
1119         
1120          // Test to see whether we accept the surrogate neighbours
1121          // Note that if ki is replaced with k in more than 1 neighbour, then the
1122          // triangle area will be zero, and a first order extrapolation will be
1123          // used
1124          //if(stage_centroid_values[k2]<=max_elevation_edgevalue[k2]+epsilon){
1125          //if(stage_centroid_values[k2]<=elevation_centroid_values[k2]+minimum_allowed_height+epsilon){
1126          if(k2<0 || cell_wetness_scale[k2]==0.0){
1127              k2 = k ;
1128          }
1129          //if(stage_centroid_values[k0]<=max_elevation_edgevalue[k0]+epsilon){
1130          //if(stage_centroid_values[k0]<=elevation_centroid_values[k0]+minimum_allowed_height+epsilon){
1131          if(k0 < 0 || cell_wetness_scale[k0]==0.0){
1132              k0 = k ;
1133          }
1134          //if(stage_centroid_values[k1]<=max_elevation_edgevalue[k1]+epsilon){
1135          //if(stage_centroid_values[k1]<=elevation_centroid_values[k1]+minimum_allowed_height+epsilon){
1136          if(k1 < 0 || cell_wetness_scale[k1]==0.0){
1137              k1 = k ;
1138          }
1139
1140          // Take note if the max neighbour bed elevation is greater than the min
1141          // neighbour stage -- suggests a 'steep' bed relative to the flow
1142          bedmax = max(elevation_centroid_values[k], 
1143                       max(elevation_centroid_values[k0],
1144                           max(elevation_centroid_values[k1], 
1145                               elevation_centroid_values[k2])));
1146          bedmin = min(elevation_centroid_values[k], 
1147                       min(elevation_centroid_values[k0],
1148                           min(elevation_centroid_values[k1], 
1149                               elevation_centroid_values[k2])));
1150          stagemin = min(max(stage_centroid_values[k], elevation_centroid_values[k]), 
1151                         min(max(stage_centroid_values[k0], elevation_centroid_values[k0]),
1152                             min(max(stage_centroid_values[k1], elevation_centroid_values[k1]),
1153                                 max(stage_centroid_values[k2], elevation_centroid_values[k2]))));
1154
1155          // Get the auxiliary triangle's vertex coordinates
1156          // (really the centroids of neighbouring triangles)
1157          coord_index = 2*k0;
1158          x0 = centroid_coordinates[coord_index];
1159          y0 = centroid_coordinates[coord_index+1];
1160         
1161          coord_index = 2*k1;
1162          x1 = centroid_coordinates[coord_index];
1163          y1 = centroid_coordinates[coord_index+1];
1164         
1165          coord_index = 2*k2;
1166          x2 = centroid_coordinates[coord_index];
1167          y2 = centroid_coordinates[coord_index+1];
1168
1169          // Store x- and y- differentials for the vertices
1170          // of the auxiliary triangle
1171          dx1 = x1 - x0; 
1172          dx2 = x2 - x0;
1173          dy1 = y1 - y0; 
1174          dy2 = y2 - y0;
1175         
1176          // Calculate 2*area of the auxiliary triangle
1177          // The triangle is guaranteed to be counter-clockwise     
1178          area2 = dy2*dx1 - dy1*dx2; 
1179           
1180          //// Treat triangles with zero or 1 wet neighbours (area2 <=0.)
1181          if ((area2 <= 0.) )// || (cell_wetness_scale[k]==0.)) //|(count_wet_neighbours[k]==0))
1182          {
1183
1184              if(0==1){
1185                //// Friction slope type extrapolation -- emulating steady flow
1186                //// d(stage)/dx = - u*sqrt(u**2 + v**2)*n**2/depth**(4/3)
1187                //hc=max(stage_centroid_values[k] - elevation_centroid_values[k],0.0);
1188                //if(hc>1.0e-06){
1189                //  tmp = sqrt(xmom_centroid_values[k]*xmom_centroid_values[k] +
1190                //             ymom_centroid_values[k]*ymom_centroid_values[k])*0.03*0.03;
1191                //  tmp /=pow(hc,10.0/3.0);
1192                //}else{
1193                //  tmp=0.0;
1194                //}
1195                //a = -xmom_centroid_values[k]*tmp;
1196                //b = -ymom_centroid_values[k]*tmp;
1197           
1198                //// Limit gradient to be between the bed slope, and zero
1199                //if(a*a_bs<0.) a=0.;
1200                //if(fabs(a)>fabs(a_bs)) a=a_bs;
1201                //if(b*b_bs<0.) b=0.;
1202                //if(fabs(b)>fabs(b_bs)) b=b_bs;
1203
1204
1205                //dqv[0] = a*dxv0 + b*dyv0;
1206                //dqv[1] = a*dxv1 + b*dyv1;
1207                //dqv[2] = a*dxv2 + b*dyv2;
1208
1209                //stage_edge_values[k3+0] = stage_centroid_values[k] + dqv[0];
1210                //stage_edge_values[k3+1] = stage_centroid_values[k] + dqv[1];
1211                //stage_edge_values[k3+2] = stage_centroid_values[k] + dqv[2];
1212              }else{
1213                // Constant stage extrapolation
1214                //stage_edge_values[k3]   = stage_centroid_values[k];
1215                //stage_edge_values[k3+1] = stage_centroid_values[k];
1216                //stage_edge_values[k3+2] = stage_centroid_values[k];
1217              }
1218            //}else{
1219            //}else{
1220              // Dry cell with a single 'wet' neighbour
1221
1222              // Compute indices of neighbouring wet cell / edge
1223              //ktmp = k0*(1-(k0==k)) + k1*(1-(k1==k)) + k2*(1-(k2==k));
1224              //ii = 0*(1-(k0==k)) + 1*(1-(k1==k)) + 2*(1-(k2==k));
1225              //if((ii<0)|(ii>2)){
1226              //  printf("Invalid ii value \n");
1227              //}
1228           
1229              //ktmp = 3*ktmp+neighbour_edges[3*k+ii];
1230              //stage_edge_values[k3]= stage_edge_values[ktmp];//max(stage_edge_values[3*ktmp+neighbour_edges[3*ktmp+i]], elevation_edge_values[k3]) ;
1231              //stage_edge_values[k3+1]= stage_edge_values[ktmp];//max(stage_edge_values[3*ktmp+neighbour_edges[3*ktmp+i]], elevation_edge_values[k3+1]);
1232              //stage_edge_values[k3+2]= stage_edge_values[ktmp];//max(stage_edge_values[3*ktmp+neighbour_edges[3*ktmp +i]], elevation_edge_values[k3+2]);
1233
1234            //}   
1235              if( (k==k0) & (k==k1) & (k==k2)){
1236              //    // Isolated wet cell  -- use constant depth extrapolation for stage
1237              //    stage_edge_values[k3]   = stage_centroid_values[k]- elevation_centroid_values[k] + elevation_edge_values[k3];
1238              //    stage_edge_values[k3+1] = stage_centroid_values[k]- elevation_centroid_values[k] + elevation_edge_values[k3+1];
1239              //    stage_edge_values[k3+2] = stage_centroid_values[k]- elevation_centroid_values[k] + elevation_edge_values[k3+2];
1240              //}
1241              //    // Isolated wet cell -- constant depth extrapolation, but don't let water flow uphill
1242              //    //stage_edge_values[k3]   = min(stage_centroid_values[k], stage_centroid_values[k]- elevation_centroid_values[k] + elevation_edge_values[k3]);
1243              //    //stage_edge_values[k3+1] = min(stage_centroid_values[k], stage_centroid_values[k]- elevation_centroid_values[k] + elevation_edge_values[k3+1]);
1244              //    //stage_edge_values[k3+2] = min(stage_centroid_values[k], stage_centroid_values[k]- elevation_centroid_values[k] + elevation_edge_values[k3+2]);
1245              //    // Isolated wet cell -- constant stage extrapolation
1246                  stage_edge_values[k3]   = stage_centroid_values[k];
1247                  stage_edge_values[k3+1] = stage_centroid_values[k];
1248                  stage_edge_values[k3+2] = stage_centroid_values[k];
1249              }else{
1250              //    // Cell with one wet neighbour.
1251              //    // Find which neighbour is wet [if k!=k0, then k0 is wet]
1252                  if(k!=k0){
1253                    ktmp=k0;
1254                    ii=0;
1255                    xtmp = x0;
1256                    ytmp = y0;
1257                  }else if(k!=k1){
1258                    ktmp=k1;
1259                    ii=1;
1260                    xtmp = x1;
1261                    ytmp = y1;
1262                  }else if(k!=k2){
1263                    ktmp=k2;
1264                    ii=2;
1265                    xtmp = x2;
1266                    ytmp = y2;
1267                  }else{
1268                      printf("ERROR in extrapolation routine: Should have had one ki == k \n");
1269                      report_python_error(AT, "Negative triangle area");
1270                      return -1;
1271                  }
1272
1273              //    //if(stage_centroid_values[k]>elevation_centroid_values[k]+minimum_allowed_height){
1274              //    if(k_wetdry==0){
1275              //    //    // Cell is wet
1276              //    //    //if(count_wet_neighbours[ktmp]>0){
1277              //    //    //    stage_edge_values[k3]= stage_centroid_values[k];
1278              //    //    //    stage_edge_values[k3+1]= stage_centroid_values[k];
1279              //    //    //    stage_edge_values[k3+2]= stage_centroid_values[k];
1280              //    //    //}else{
1281              //    //        // Constant depth extrapolation
1282                    if(stage_centroid_values[k]<stage_centroid_values[ktmp]){
1283                      // Constant stage extrapolation reduces the issue of having the bed-slope term playing up on nearly dry cells
1284                      // stage_edge_values[k3]= stage_centroid_values[k]-elevation_centroid_values[k]+elevation_edge_values[k3];
1285                      // stage_edge_values[k3+1]= stage_centroid_values[k] -elevation_centroid_values[k]+elevation_edge_values[k3+1];
1286                      // stage_edge_values[k3+2]= stage_centroid_values[k] -elevation_centroid_values[k]+elevation_edge_values[k3+2];
1287                      stage_edge_values[k3] = stage_centroid_values[k];
1288                      stage_edge_values[k3+1] = stage_centroid_values[k];
1289                      stage_edge_values[k3+2] = stage_centroid_values[k];
1290                    }else{
1291              //           // stage_edge_values[k3] = stage_centroid_values[ktmp];
1292              //           // stage_edge_values[k3+1] = stage_centroid_values[ktmp];
1293              //           // stage_edge_values[k3+2] = stage_centroid_values[ktmp];
1294                     //stage_edge_values[k3]= max(stage_centroid_values[k]-elevation_centroid_values[k]+elevation_edge_values[k3], stage_centroid_values[ktmp]);
1295                     //stage_edge_values[k3+1]= max(stage_centroid_values[k] -elevation_centroid_values[k]+elevation_edge_values[k3+1],stage_centroid_values[ktmp]);
1296                     //stage_edge_values[k3+2]= max(stage_centroid_values[k] -elevation_centroid_values[k]+elevation_edge_values[k3+2], stage_centroid_values[ktmp]);
1297                     ktmp = 3*ktmp+neighbour_edges[k3+ii];
1298                     stage_edge_values[k3]= max(stage_centroid_values[k]-elevation_centroid_values[k]+elevation_edge_values[k3], stage_edge_values[ktmp]);
1299                     stage_edge_values[k3+1]= max(stage_centroid_values[k] -elevation_centroid_values[k]+elevation_edge_values[k3+1],stage_edge_values[ktmp]);
1300                     stage_edge_values[k3+2]= max(stage_centroid_values[k] -elevation_centroid_values[k]+elevation_edge_values[k3+2], stage_edge_values[ktmp]);
1301                    }
1302
1303              //    }else{
1304              //       
1305              //    //    // This cell is 'dry'.
1306              //    //    // Extrapolate using the neighbouring wet cell if appropriate
1307              //    //    // This needs to preserve a wet-dry interface
1308              //        //ktmp = 3*ktmp+neighbour_edges[3*k+ii];
1309              //        //stage_edge_values[k3]= stage_edge_values[ktmp];//max(stage_edge_values[3*ktmp+neighbour_edges[3*ktmp+i]], elevation_edge_values[k3]) ;
1310              //        //stage_edge_values[k3+1]= stage_edge_values[ktmp];//max(stage_edge_values[3*ktmp+neighbour_edges[3*ktmp+i]], elevation_edge_values[k3+1]);
1311              //        //stage_edge_values[k3+2]= stage_edge_values[ktmp];//max(stage_edge_values[3*ktmp+neighbour_edges[3*ktmp +i]], elevation_edge_values[k3+2]);
1312              //    //    stage_edge_values[k3]= stage_centroid_values[ktmp] ;
1313              //    //    stage_edge_values[k3+1]= stage_centroid_values[ktmp];
1314              //    //    stage_edge_values[k3+2]= stage_centroid_values[ktmp];
1315              //        stage_edge_values[k3]= stage_centroid_values[k] ;
1316              //        stage_edge_values[k3+1]= stage_centroid_values[k];
1317              //        stage_edge_values[k3+2]= stage_centroid_values[k];
1318              //    }
1319              //
1320              }
1321              // First order momentum / velocity extrapolation
1322             //if(stagemin>=bedmax){
1323             //   stage_edge_values[k3]    = stage_centroid_values[k];
1324             //   stage_edge_values[k3+1]  = stage_centroid_values[k];
1325             //   stage_edge_values[k3+2]  = stage_centroid_values[k];
1326             //}else{
1327             //   stage_edge_values[k3]= stage_centroid_values[k]-elevation_centroid_values[k]+elevation_edge_values[k3];
1328             //   stage_edge_values[k3+1]= stage_centroid_values[k] -elevation_centroid_values[k]+elevation_edge_values[k3+1];
1329             //   stage_edge_values[k3+2]= stage_centroid_values[k] -elevation_centroid_values[k]+elevation_edge_values[k3+2];
1330             //}
1331              xmom_edge_values[k3]    = xmom_centroid_values[k];
1332              xmom_edge_values[k3+1]  = xmom_centroid_values[k];
1333              xmom_edge_values[k3+2]  = xmom_centroid_values[k];
1334              ymom_edge_values[k3]    = ymom_centroid_values[k];
1335              ymom_edge_values[k3+1]  = ymom_centroid_values[k];
1336              ymom_edge_values[k3+2]  = ymom_centroid_values[k];
1337
1338              continue;
1339          } 
1340         
1341          // Calculate heights of neighbouring cells
1342          hc = stage_centroid_values[k]  - elevation_centroid_values[k];
1343          h0 = stage_centroid_values[k0] - elevation_centroid_values[k0];
1344          h1 = stage_centroid_values[k1] - elevation_centroid_values[k1];
1345          h2 = stage_centroid_values[k2] - elevation_centroid_values[k2];
1346          hmin = min(min(h0, min(h1, h2)), hc);
1347          //// GD FIXME: No longer needed?
1348          //hfactor = 0.0;
1349          ////if (hmin > 0.001)
1350          //if (hmin > 0.)
1351          ////if (hc>0.0)
1352          //{
1353          //  hfactor = 1.0 ;//hmin/(hmin + 0.004);
1354            //hfactor=hmin/(hmin + 0.004);
1355          //}
1356          //hfactor= min(2.0*max(hmin,0.0)/max(hc,max(0.5*(bedmax-bedmin),minimum_allowed_height)), 1.0);
1357          hfactor= min(2.0*max(hmin,0.0)/max(hc,minimum_allowed_height*0.1), 1.0);
1358         
1359          //-----------------------------------
1360          // stage
1361          //-----------------------------------     
1362         
1363          // Calculate the difference between vertex 0 of the auxiliary
1364          // triangle and the centroid of triangle k
1365          dq0 = stage_centroid_values[k0] - stage_centroid_values[k];
1366         
1367          // Calculate differentials between the vertices
1368          // of the auxiliary triangle (centroids of neighbouring triangles)
1369          dq1 = stage_centroid_values[k1] - stage_centroid_values[k0];
1370          dq2 = stage_centroid_values[k2] - stage_centroid_values[k0];
1371         
1372          //if( (area2>0.0) ){
1373
1374          inv_area2 = 1.0/area2;
1375          //if(count_wet_neighbours[k] > 1){
1376          //if(1==1){
1377          //    // Calculate the gradient of stage on the auxiliary triangle
1378              a = dy2*dq1 - dy1*dq2;
1379              a *= inv_area2;
1380              b = dx1*dq2 - dx2*dq1;
1381              b *= inv_area2;
1382          //}else{
1383          ////    //// Friction slope type extrapolation -- emulating steady flow
1384          ////    //// d(stage)/dx = - u*sqrt(u**2 + v**2)*n**2/depth**(4/3)
1385          //    hc=max(stage_centroid_values[k] - elevation_centroid_values[k],0.0);
1386          //    if(hc>1.0e-06){
1387          //      tmp = sqrt(xmom_centroid_values[k]*xmom_centroid_values[k] +
1388          //               ymom_centroid_values[k]*ymom_centroid_values[k])*0.03*0.03;
1389          //      tmp /=max(pow(hc,10.0/3.0), 1.0e-30);
1390          //    }else{
1391          //      tmp=0.0;
1392          //    }
1393          //    a = -xmom_centroid_values[k]*tmp;
1394          //    b = -ymom_centroid_values[k]*tmp;
1395          ////    // Limit gradient to be between the bed slope, and zero
1396          ////    if(a*a_bs<0.) a=0.;
1397          ////    if(fabs(a)>fabs(a_bs)) a=a_bs;
1398          ////    if(b*b_bs<0.) b=0.;
1399          ////    if(fabs(b)>fabs(b_bs)) b=b_bs;
1400          //}
1401          // Calculate provisional jumps in stage from the centroid
1402          // of triangle k to its vertices, to be limited
1403          dqv[0] = a*dxv0 + b*dyv0;
1404          dqv[1] = a*dxv1 + b*dyv1;
1405          dqv[2] = a*dxv2 + b*dyv2;
1406       
1407          // Now we want to find min and max of the centroid and the
1408          // vertices of the auxiliary triangle and compute jumps
1409          // from the centroid to the min and max
1410          find_qmin_and_qmax(dq0, dq1, dq2, &qmin, &qmax);
1411       
1412          beta_tmp = beta_w_dry + (beta_w - beta_w_dry) * hfactor;
1413       
1414         
1415          // Limit the gradient
1416          // This is more complex for stage than other quantities
1417          //if((count_wet_neighbours[k]>0)&&(cell_wetness_scale[k]=1.0)){//&&(k_wetdry==0)){
1418          //if(stage_centroid_values[k] > max_elevation_edgevalue[k]){
1419          //if( (area2>0) ){
1420          //if(count_wet_neighbours[k]>0){
1421          //if(min_elevation_edgevalue[k]<=stagemin ){
1422          //if(bedmax<=stagemin ){
1423             limit_gradient(dqv, qmin, qmax, beta_tmp);
1424          //}else{
1425          //  dqv[0]=-elevation_centroid_values[k] + elevation_edge_values[k3+0];
1426          //  dqv[1]=-elevation_centroid_values[k] + elevation_edge_values[k3+1];
1427          //  dqv[2]=-elevation_centroid_values[k] + elevation_edge_values[k3+2];
1428          //}
1429          //printf("%lf \n ", beta_tmp);
1430          //}
1431          //}
1432          stage_edge_values[k3+0] = stage_centroid_values[k] + dqv[0];
1433          stage_edge_values[k3+1] = stage_centroid_values[k] + dqv[1];
1434          stage_edge_values[k3+2] = stage_centroid_values[k] + dqv[2];
1435          // IDEA: extrapolate assuming slope is that of steady flow??
1436          // GD HACK - FIXME
1437          // Note that 'near-dry' cells which don't exchange mass with
1438          // neighbouring cells have to revert to having a constant stage
1439          // extrapolation, or else they will have a residual bed slope term.
1440          // This helps! -- But probably makes rainfall-runoff problems worse.
1441          //ii = (stage_edge_values[k3+0] > elevation_edge_values[k3+0])+
1442          //     (stage_edge_values[k3+1] > elevation_edge_values[k3+1])+
1443          //     (stage_edge_values[k3+2] > elevation_edge_values[k3+2]);
1444          //if(ii<2){
1445          //    stage_edge_values[k3+0] = stage_centroid_values[k] ;
1446          //    stage_edge_values[k3+1] = stage_centroid_values[k] ;
1447          //    stage_edge_values[k3+2] = stage_centroid_values[k] ;
1448          //}
1449          //}else{
1450          // d(stage)/dx = - u*sqrt(u**2 + v**2)*n**2/depth**(4/3)
1451          //    hc=max(stage_centroid_values[k] - elevation_centroid_values[k],0.0);
1452          //    tmp = sqrt(xmom_centroid_values[k]*xmom_centroid_values[k] +
1453          //               ymom_centroid_values[k]*ymom_centroid_values[k])*0.03*0.03;
1454          //    tmp /=max(hc*hc*hc, 1.0e-09);
1455          //    a = -xmom_centroid_values[k]*tmp;
1456          //    b = -ymom_centroid_values[k]*tmp;
1457          //    dqv[0] = a*dxv0 + b*dyv0;
1458          //    dqv[1] = a*dxv1 + b*dyv1;
1459          //    dqv[2] = a*dxv2 + b*dyv2;
1460          //////if(count_wet_neighbours[k]==0){
1461          ////    //weight=max(cell_wetness_scale[k] - (stage_centroid_values[k]-elevation_centroid_values[k]), 0.);
1462          ////    //weight/=(max_elevation_edgevalue[k] - elevation_centroid_values[k]);
1463          ////    //weight=min(weight, 1.0);
1464          ////    //weight==0;
1465          //      weight=0.;
1466          ////    // 'Shallow flow on steep slope'
1467              //limit_gradient(dqv, qmin, qmax, beta_tmp);
1468              //stage_edge_values[k3+0] =stage_centroid_values[k] + dqv[0];
1469              //stage_edge_values[k3+1] =stage_centroid_values[k] + dqv[1];
1470              //stage_edge_values[k3+2] =stage_centroid_values[k] + dqv[2];
1471          //
1472          ////    // There exists a neighbouring bed cell with elevation > minimum
1473          ////    // neighbouring stage value
1474
1475          ////    // We have to be careful in this situation. Limiting the stage gradient can
1476          ////    // cause problems for shallow flows down steep slopes (rainfall-runoff type problems)
1477          ////    // Previously 'balance_deep_and_shallow' was used to deal with this issue
1478          //    for(i=0; i<3; i++){
1479          //        stage_edge_values[k3+i] = weight*stage_edge_values[k3+i] +
1480          //                                 (1.0-weight)*(stage_centroid_values[k] -elevation_centroid_values[k]
1481          //                                               +elevation_edge_values[k3+i]);
1482          //    }
1483          //}
1484           
1485          //-----------------------------------
1486          // xmomentum
1487          //-----------------------------------           
1488
1489          // Calculate the difference between vertex 0 of the auxiliary
1490          // triangle and the centroid of triangle k     
1491          dq0 = xmom_centroid_values[k0] - xmom_centroid_values[k];
1492         
1493          // Calculate differentials between the vertices
1494          // of the auxiliary triangle
1495          dq1 = xmom_centroid_values[k1] - xmom_centroid_values[k0];
1496          dq2 = xmom_centroid_values[k2] - xmom_centroid_values[k0];
1497         
1498          // Calculate the gradient of xmom on the auxiliary triangle
1499          a = dy2*dq1 - dy1*dq2;
1500          a *= inv_area2;
1501          b = dx1*dq2 - dx2*dq1;
1502          b *= inv_area2;
1503         
1504          // Calculate provisional jumps in stage from the centroid
1505          // of triangle k to its vertices, to be limited     
1506          dqv[0] = a*dxv0+b*dyv0;
1507          dqv[1] = a*dxv1+b*dyv1;
1508          dqv[2] = a*dxv2+b*dyv2;
1509         
1510          // Now we want to find min and max of the centroid and the
1511          // vertices of the auxiliary triangle and compute jumps
1512          // from the centroid to the min and max
1513          //
1514          find_qmin_and_qmax(dq0, dq1, dq2, &qmin, &qmax);
1515
1516          beta_tmp = beta_uh_dry + (beta_uh - beta_uh_dry) * hfactor;
1517
1518          // Limit the gradient
1519          //if((k!=k0)&(k!=k1)&(k!=k2))
1520          //if(stagemin>=bedmax){
1521          //if((count_wet_neighbours[k]>0)){ // &&
1522            // (cell_wetness_scale[k]==1.0)){
1523          //if(stage_centroid_values[k]>(minimum_allowed_height+max_elevation_edgevalue[k])){
1524         
1525            limit_gradient(dqv, qmin, qmax, beta_tmp);
1526          //}else{
1527          //  dqv[0]=0.;
1528          //  dqv[1]=0.;
1529          //  dqv[2]=0.;
1530          ////  limit_gradient(dqv, qmin, qmax, 0.);
1531          //}
1532          //limit_gradient2(dqv, qmin, qmax, beta_tmp,r0scale);
1533         
1534
1535          for (i=0; i < 3; i++)
1536          {
1537            xmom_edge_values[k3+i] = xmom_centroid_values[k] + dqv[i];
1538          }
1539         
1540          //-----------------------------------
1541          // ymomentum
1542          //-----------------------------------                 
1543
1544          // Calculate the difference between vertex 0 of the auxiliary
1545          // triangle and the centroid of triangle k
1546          dq0 = ymom_centroid_values[k0] - ymom_centroid_values[k];
1547         
1548          // Calculate differentials between the vertices
1549          // of the auxiliary triangle
1550          dq1 = ymom_centroid_values[k1] - ymom_centroid_values[k0];
1551          dq2 = ymom_centroid_values[k2] - ymom_centroid_values[k0];
1552         
1553          // Calculate the gradient of xmom on the auxiliary triangle
1554          a = dy2*dq1 - dy1*dq2;
1555          a *= inv_area2;
1556          b = dx1*dq2 - dx2*dq1;
1557          b *= inv_area2;
1558         
1559          // Calculate provisional jumps in stage from the centroid
1560          // of triangle k to its vertices, to be limited
1561          dqv[0] = a*dxv0 + b*dyv0;
1562          dqv[1] = a*dxv1 + b*dyv1;
1563          dqv[2] = a*dxv2 + b*dyv2;
1564         
1565          // Now we want to find min and max of the centroid and the
1566          // vertices of the auxiliary triangle and compute jumps
1567          // from the centroid to the min and max
1568          //
1569          find_qmin_and_qmax(dq0, dq1, dq2, &qmin, &qmax);
1570         
1571          beta_tmp = beta_vh_dry + (beta_vh - beta_vh_dry) * hfactor;   
1572
1573          // Limit the gradient
1574          //if(stagemin>=bedmax){
1575          //if((count_wet_neighbours[k]>0)){//&&
1576             //(cell_wetness_scale[k]==1.0)){
1577            //(stage_centroid_values[k]>(minimum_allowed_height+elevation_centroid_values[k]))){
1578          //if(stage_centroid_values[k]>(minimum_allowed_height+max_elevation_edgevalue[k])){
1579            limit_gradient(dqv, qmin, qmax, beta_tmp);
1580          //}else{
1581          //  dqv[0]=0.;
1582          //  dqv[1]=0.;
1583          //  dqv[2]=0.;
1584          //}
1585         
1586          for (i=0;i<3;i++)
1587          {
1588            ymom_edge_values[k3 + i] = ymom_centroid_values[k] + dqv[i];
1589          }
1590         
1591        } // End number_of_boundaries <=1
1592        else
1593        {
1594
1595          //==============================================
1596          // Number of boundaries == 2
1597          //==============================================       
1598           
1599          // One internal neighbour and gradient is in direction of the neighbour's centroid
1600         
1601          // Find the only internal neighbour (k1?)
1602          for (k2 = k3; k2 < k3 + 3; k2++)
1603          {
1604          // Find internal neighbour of triangle k     
1605          // k2 indexes the edges of triangle k   
1606         
1607              if (surrogate_neighbours[k2] != k)
1608              {
1609                 break;
1610              }
1611          }
1612         
1613          if ((k2 == k3 + 3)) 
1614          {
1615            // If we didn't find an internal neighbour
1616            report_python_error(AT, "Internal neighbour not found");
1617            return -1;
1618          }
1619         
1620          k1 = surrogate_neighbours[k2];
1621         
1622          // The coordinates of the triangle are already (x,y).
1623          // Get centroid of the neighbour (x1,y1)
1624          coord_index = 2*k1;
1625          x1 = centroid_coordinates[coord_index];
1626          y1 = centroid_coordinates[coord_index + 1];
1627         
1628          // Compute x- and y- distances between the centroid of
1629          // triangle k and that of its neighbour
1630          dx1 = x1 - x; 
1631          dy1 = y1 - y;
1632         
1633          // Set area2 as the square of the distance
1634          area2 = dx1*dx1 + dy1*dy1;
1635         
1636          // Set dx2=(x1-x0)/((x1-x0)^2+(y1-y0)^2)
1637          // and dy2=(y1-y0)/((x1-x0)^2+(y1-y0)^2) which
1638          // respectively correspond to the x- and y- gradients
1639          // of the conserved quantities
1640          dx2 = 1.0/area2;
1641          dy2 = dx2*dy1;
1642          dx2 *= dx1;
1643         
1644         
1645          //-----------------------------------
1646          // stage
1647          //-----------------------------------           
1648
1649          // Compute differentials
1650          dq1 = stage_centroid_values[k1] - stage_centroid_values[k];
1651         
1652          // Calculate the gradient between the centroid of triangle k
1653          // and that of its neighbour
1654          a = dq1*dx2;
1655          b = dq1*dy2;
1656         
1657          // Calculate provisional edge jumps, to be limited
1658          dqv[0] = a*dxv0 + b*dyv0;
1659          dqv[1] = a*dxv1 + b*dyv1;
1660          dqv[2] = a*dxv2 + b*dyv2;
1661         
1662          // Now limit the jumps
1663          if (dq1>=0.0)
1664          {
1665            qmin=0.0;
1666            qmax=dq1;
1667          }
1668          else
1669          {
1670            qmin = dq1;
1671            qmax = 0.0;
1672          }
1673         
1674          // Limit the gradient
1675          limit_gradient(dqv, qmin, qmax, beta_w);
1676         
1677          //for (i=0; i < 3; i++)
1678          //{
1679          stage_edge_values[k3] = stage_centroid_values[k] + dqv[0];
1680          stage_edge_values[k3 + 1] = stage_centroid_values[k] + dqv[1];
1681          stage_edge_values[k3 + 2] = stage_centroid_values[k] + dqv[2];
1682          //}
1683         
1684          //-----------------------------------
1685          // xmomentum
1686          //-----------------------------------                       
1687         
1688          // Compute differentials
1689          dq1 = xmom_centroid_values[k1] - xmom_centroid_values[k];
1690         
1691          // Calculate the gradient between the centroid of triangle k
1692          // and that of its neighbour
1693          a = dq1*dx2;
1694          b = dq1*dy2;
1695         
1696          // Calculate provisional edge jumps, to be limited
1697          dqv[0] = a*dxv0+b*dyv0;
1698          dqv[1] = a*dxv1+b*dyv1;
1699          dqv[2] = a*dxv2+b*dyv2;
1700         
1701          // Now limit the jumps
1702          if (dq1 >= 0.0)
1703          {
1704            qmin = 0.0;
1705            qmax = dq1;
1706          }
1707          else
1708          {
1709            qmin = dq1;
1710            qmax = 0.0;
1711          }
1712         
1713          // Limit the gradient     
1714          limit_gradient(dqv, qmin, qmax, beta_w);
1715         
1716          //for (i=0;i<3;i++)
1717          //xmom_edge_values[k3] = xmom_centroid_values[k] + dqv[0];
1718          //xmom_edge_values[k3 + 1] = xmom_centroid_values[k] + dqv[1];
1719          //xmom_edge_values[k3 + 2] = xmom_centroid_values[k] + dqv[2];
1720         
1721          for (i = 0; i < 3;i++)
1722          {
1723              xmom_edge_values[k3 + i] = xmom_centroid_values[k] + dqv[i];
1724          }
1725         
1726          //-----------------------------------
1727          // ymomentum
1728          //-----------------------------------                       
1729
1730          // Compute differentials
1731          dq1 = ymom_centroid_values[k1] - ymom_centroid_values[k];
1732         
1733          // Calculate the gradient between the centroid of triangle k
1734          // and that of its neighbour
1735          a = dq1*dx2;
1736          b = dq1*dy2;
1737         
1738          // Calculate provisional edge jumps, to be limited
1739          dqv[0] = a*dxv0 + b*dyv0;
1740          dqv[1] = a*dxv1 + b*dyv1;
1741          dqv[2] = a*dxv2 + b*dyv2;
1742         
1743          // Now limit the jumps
1744          if (dq1>=0.0)
1745          {
1746            qmin = 0.0;
1747            qmax = dq1;
1748          } 
1749          else
1750          {
1751            qmin = dq1;
1752            qmax = 0.0;
1753          }
1754         
1755          // Limit the gradient
1756          limit_gradient(dqv, qmin, qmax, beta_w);
1757         
1758          for (i=0;i<3;i++)
1759                  {
1760                  ymom_edge_values[k3 + i] = ymom_centroid_values[k] + dqv[i];
1761                  }
1762        } // else [number_of_boundaries==2]
1763      } // for k=0 to number_of_elements-1
1764  } 
1765
1766  //for(k=0;k<number_of_elements; k++){
1767  //    // Hack for 'dry' cells
1768  //    // Make sure edge value is not greater than neighbour edge value
1769  //    //if(stage_centroid_values[k] - elevation_centroid_values[k] < minimum_allowed_height+epsilon){
1770  //    if(cell_wetness_scale[k]==0.0){
1771  //      for(i=0; i<3;i++){
1772  //          if(surrogate_neighbours[3*k+i] >= 0){
1773  //              ktmp=3*surrogate_neighbours[3*k+i] + neighbour_edges[3*k+i];
1774  //          //if(cell_wetness_scale[surrogate_neighbours[3*k+i]]>0.){
1775  //              stage_edge_values[3*k+i] = min(stage_edge_values[3*k+i], stage_edge_values[ktmp]);
1776  //          }
1777  //      }
1778  //    }
1779  //}
1780
1781  // Compute vertex values of quantities
1782  for (k=0; k<number_of_elements; k++){
1783      k3=3*k;
1784
1785      // Compute stage vertex values
1786      stage_vertex_values[k3] = stage_edge_values[k3+1] + stage_edge_values[k3+2] -stage_edge_values[k3] ; 
1787      stage_vertex_values[k3+1] =  stage_edge_values[k3] + stage_edge_values[k3+2]-stage_edge_values[k3+1]; 
1788      stage_vertex_values[k3+2] =  stage_edge_values[k3] + stage_edge_values[k3+1]-stage_edge_values[k3+2]; 
1789     
1790     // Compute xmom vertex values
1791      xmom_vertex_values[k3] = xmom_edge_values[k3+1] + xmom_edge_values[k3+2] -xmom_edge_values[k3] ; 
1792      xmom_vertex_values[k3+1] =  xmom_edge_values[k3] + xmom_edge_values[k3+2]-xmom_edge_values[k3+1]; 
1793      xmom_vertex_values[k3+2] =  xmom_edge_values[k3] + xmom_edge_values[k3+1]-xmom_edge_values[k3+2]; 
1794
1795      // Compute ymom vertex values
1796      ymom_vertex_values[k3] = ymom_edge_values[k3+1] + ymom_edge_values[k3+2] -ymom_edge_values[k3] ; 
1797      ymom_vertex_values[k3+1] =  ymom_edge_values[k3] + ymom_edge_values[k3+2]-ymom_edge_values[k3+1]; 
1798      ymom_vertex_values[k3+2] =  ymom_edge_values[k3] + ymom_edge_values[k3+1]-ymom_edge_values[k3+2]; 
1799
1800      // If needed, convert from velocity to momenta
1801      if(extrapolate_velocity_second_order==1){
1802          //Convert velocity back to momenta at centroids
1803          xmom_centroid_values[k] = xmom_centroid_store[k];
1804          ymom_centroid_values[k] = ymom_centroid_store[k];
1805
1806          // Re-compute momenta at edges
1807          for (i=0; i<3; i++){
1808              de[i] = max(stage_edge_values[k3+i]-elevation_edge_values[k3+i],0.0);
1809              //if(de[i]<minimum_allowed_height){
1810              //  de[i]=0.;
1811              //}
1812              xmom_edge_values[k3+i]=xmom_edge_values[k3+i]*de[i];
1813              ymom_edge_values[k3+i]=ymom_edge_values[k3+i]*de[i];
1814          }
1815
1816          // Re-compute momenta at vertices
1817          for (i=0; i<3; i++){
1818              de[i] = max(stage_vertex_values[k3+i]-elevation_vertex_values[k3+i],0.0);
1819              xmom_vertex_values[k3+i]=xmom_vertex_values[k3+i]*de[i];
1820              ymom_vertex_values[k3+i]=ymom_vertex_values[k3+i]*de[i];
1821          }
1822
1823      }
1824
1825   
1826  } 
1827
1828  free(xmom_centroid_store);
1829  free(ymom_centroid_store);
1830  free(stage_centroid_store);
1831  free(min_elevation_edgevalue);
1832  free(max_elevation_edgevalue);
1833  free(cell_wetness_scale);
1834  free(count_wet_neighbours);
1835
1836  return 0;
1837}           
1838
1839//=========================================================================
1840// Python Glue
1841//=========================================================================
1842
1843
1844//========================================================================
1845// Compute fluxes
1846//========================================================================
1847
1848// Modified central flux function
1849
1850PyObject *compute_fluxes_ext_central(PyObject *self, PyObject *args) {
1851  /*Compute all fluxes and the timestep suitable for all volumes
1852    in domain.
1853
1854    Compute total flux for each conserved quantity using "flux_function_central"
1855
1856    Fluxes across each edge are scaled by edgelengths and summed up
1857    Resulting flux is then scaled by area and stored in
1858    explicit_update for each of the three conserved quantities
1859    stage, xmomentum and ymomentum
1860
1861    The maximal allowable speed computed by the flux_function for each volume
1862    is converted to a timestep that must not be exceeded. The minimum of
1863    those is computed as the next overall timestep.
1864
1865    Python call:
1866    domain.timestep = compute_fluxes(timestep,
1867                                     domain.epsilon,
1868                     domain.H0,
1869                                     domain.g,
1870                                     domain.neighbours,
1871                                     domain.neighbour_edges,
1872                                     domain.normals,
1873                                     domain.edgelengths,
1874                                     domain.radii,
1875                                     domain.areas,
1876                                     tri_full_flag,
1877                                     Stage.edge_values,
1878                                     Xmom.edge_values,
1879                                     Ymom.edge_values,
1880                                     Bed.edge_values,
1881                                     Stage.boundary_values,
1882                                     Xmom.boundary_values,
1883                                     Ymom.boundary_values,
1884                                     Stage.explicit_update,
1885                                     Xmom.explicit_update,
1886                                     Ymom.explicit_update,
1887                                     already_computed_flux,
1888                                     optimise_dry_cells,
1889                                     stage.centroid_values,
1890                                     bed.centroid_values)
1891
1892
1893    Post conditions:
1894      domain.explicit_update is reset to computed flux values
1895      domain.timestep is set to the largest step satisfying all volumes.
1896
1897
1898  */
1899
1900
1901  PyArrayObject *boundary_flux_sum, *neighbours, *neighbour_edges,
1902    *normals, *edgelengths, *radii, *areas,
1903    *tri_full_flag,
1904    *stage_edge_values,
1905    *xmom_edge_values,
1906    *ymom_edge_values,
1907    *bed_edge_values,
1908    *stage_boundary_values,
1909    *xmom_boundary_values,
1910    *ymom_boundary_values,
1911    *boundary_flux_type,
1912    *stage_explicit_update,
1913    *xmom_explicit_update,
1914    *ymom_explicit_update,
1915    *already_computed_flux, //Tracks whether the flux across an edge has already been computed
1916    *max_speed_array, //Keeps track of max speeds for each triangle
1917    *stage_centroid_values,
1918    *xmom_centroid_values,
1919    *ymom_centroid_values,
1920    *bed_centroid_values,
1921    *bed_vertex_values;
1922   
1923  double timestep, epsilon, H0, g;
1924  int optimise_dry_cells, timestep_order;
1925   
1926  // Convert Python arguments to C
1927  if (!PyArg_ParseTuple(args, "ddddOOOOOOOOOOOOOOOOOOOOOiiOOOOO",
1928            &timestep,
1929            &epsilon,
1930            &H0,
1931            &g,
1932            &boundary_flux_sum,
1933            &neighbours,
1934            &neighbour_edges,
1935            &normals,
1936            &edgelengths, &radii, &areas,
1937            &tri_full_flag,
1938            &stage_edge_values,
1939            &xmom_edge_values,
1940            &ymom_edge_values,
1941            &bed_edge_values,
1942            &stage_boundary_values,
1943            &xmom_boundary_values,
1944            &ymom_boundary_values,
1945            &boundary_flux_type,
1946            &stage_explicit_update,
1947            &xmom_explicit_update,
1948            &ymom_explicit_update,
1949            &already_computed_flux,
1950            &max_speed_array,
1951            &optimise_dry_cells,
1952            &timestep_order,
1953            &stage_centroid_values,
1954            &xmom_centroid_values,
1955            &ymom_centroid_values,
1956            &bed_centroid_values,
1957            &bed_vertex_values)) {
1958    report_python_error(AT, "could not parse input arguments");
1959    return NULL;
1960  }
1961
1962  // check that numpy array objects arrays are C contiguous memory
1963  CHECK_C_CONTIG(neighbours);
1964  CHECK_C_CONTIG(neighbour_edges);
1965  CHECK_C_CONTIG(normals);
1966  CHECK_C_CONTIG(edgelengths);
1967  CHECK_C_CONTIG(radii);
1968  CHECK_C_CONTIG(areas);
1969  CHECK_C_CONTIG(tri_full_flag);
1970  CHECK_C_CONTIG(stage_edge_values);
1971  CHECK_C_CONTIG(xmom_edge_values);
1972  CHECK_C_CONTIG(ymom_edge_values);
1973  CHECK_C_CONTIG(bed_edge_values);
1974  CHECK_C_CONTIG(stage_boundary_values);
1975  CHECK_C_CONTIG(xmom_boundary_values);
1976  CHECK_C_CONTIG(ymom_boundary_values);
1977  CHECK_C_CONTIG(boundary_flux_type);
1978  CHECK_C_CONTIG(stage_explicit_update);
1979  CHECK_C_CONTIG(xmom_explicit_update);
1980  CHECK_C_CONTIG(ymom_explicit_update);
1981  CHECK_C_CONTIG(already_computed_flux);
1982  CHECK_C_CONTIG(max_speed_array);
1983  CHECK_C_CONTIG(stage_centroid_values);
1984  CHECK_C_CONTIG(xmom_centroid_values);
1985  CHECK_C_CONTIG(ymom_centroid_values);
1986  CHECK_C_CONTIG(bed_centroid_values);
1987  CHECK_C_CONTIG(bed_vertex_values);
1988
1989  int number_of_elements = stage_edge_values -> dimensions[0];
1990
1991  // Call underlying flux computation routine and update
1992  // the explicit update arrays
1993  timestep = _compute_fluxes_central(number_of_elements,
1994                     timestep,
1995                     epsilon,
1996                     H0,
1997                     g,
1998                     (double*) boundary_flux_sum -> data,
1999                     (long*) neighbours -> data,
2000                     (long*) neighbour_edges -> data,
2001                     (double*) normals -> data,
2002                     (double*) edgelengths -> data, 
2003                     (double*) radii -> data, 
2004                     (double*) areas -> data,
2005                     (long*) tri_full_flag -> data,
2006                     (double*) stage_edge_values -> data,
2007                     (double*) xmom_edge_values -> data,
2008                     (double*) ymom_edge_values -> data,
2009                     (double*) bed_edge_values -> data,
2010                     (double*) stage_boundary_values -> data,
2011                     (double*) xmom_boundary_values -> data,
2012                     (double*) ymom_boundary_values -> data,
2013                     (long*)   boundary_flux_type -> data,
2014                     (double*) stage_explicit_update -> data,
2015                     (double*) xmom_explicit_update -> data,
2016                     (double*) ymom_explicit_update -> data,
2017                     (long*) already_computed_flux -> data,
2018                     (double*) max_speed_array -> data,
2019                     optimise_dry_cells, 
2020                     timestep_order,
2021                     (double*) stage_centroid_values -> data, 
2022                     (double*) xmom_centroid_values -> data, 
2023                     (double*) ymom_centroid_values -> data, 
2024                     (double*) bed_centroid_values -> data,
2025                     (double*) bed_vertex_values -> data);
2026 
2027  // Return updated flux timestep
2028  return Py_BuildValue("d", timestep);
2029}
2030
2031
2032PyObject *flux_function_central(PyObject *self, PyObject *args) {
2033  //
2034  // Gateway to innermost flux function.
2035  // This is only used by the unit tests as the c implementation is
2036  // normally called by compute_fluxes in this module.
2037
2038
2039  PyArrayObject *normal, *ql, *qr,  *edgeflux;
2040  double g, epsilon, max_speed, H0, zl, zr;
2041  double h0, limiting_threshold, pressure_flux, smooth;
2042
2043  if (!PyArg_ParseTuple(args, "OOOddOddd",
2044            &normal, &ql, &qr, &zl, &zr, &edgeflux,
2045            &epsilon, &g, &H0)) {
2046      report_python_error(AT, "could not parse input arguments");
2047      return NULL;
2048  }
2049
2050 
2051  h0 = H0;           
2052  limiting_threshold = 10*H0; // Avoid applying limiter below this
2053                              // threshold for performance reasons.
2054                              // See ANUGA manual under flux limiting 
2055 
2056  pressure_flux = 0.0; // Store the water pressure related component of the flux
2057  smooth = 1.0 ; // term to scale diffusion in riemann solver
2058
2059  _flux_function_central((double*) ql -> data, 
2060                         (double*) qr -> data, 
2061                         zl, 
2062                         zr,                         
2063                         ((double*) normal -> data)[0],
2064                         ((double*) normal -> data)[1],         
2065                         epsilon, h0, limiting_threshold,
2066                         g,
2067                         (double*) edgeflux -> data, 
2068                         &max_speed,
2069             &pressure_flux,
2070                         ((double*) normal -> data)[0],
2071                         ((double*) normal -> data)[1], 
2072                         ((double*) normal -> data)[1],
2073             smooth
2074             );
2075 
2076  return Py_BuildValue("d", max_speed); 
2077}
2078
2079//========================================================================
2080// Gravity
2081//========================================================================
2082
2083PyObject *gravity(PyObject *self, PyObject *args) {
2084  //
2085  //  gravity(g, h, v, x, xmom, ymom)
2086  //
2087 
2088 
2089  PyArrayObject *h, *v, *x, *xmom, *ymom;
2090  int k, N, k3, k6;
2091  double g, avg_h, zx, zy;
2092  double x0, y0, x1, y1, x2, y2, z0, z1, z2;
2093  //double epsilon;
2094 
2095  if (!PyArg_ParseTuple(args, "dOOOOO",
2096                        &g, &h, &v, &x,
2097                        &xmom, &ymom)) {
2098    //&epsilon)) {
2099    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: gravity could not parse input arguments");
2100    return NULL;
2101  }
2102 
2103  // check that numpy array objects arrays are C contiguous memory
2104  CHECK_C_CONTIG(h);
2105  CHECK_C_CONTIG(v);
2106  CHECK_C_CONTIG(x);
2107  CHECK_C_CONTIG(xmom);
2108  CHECK_C_CONTIG(ymom);
2109 
2110  N = h -> dimensions[0];
2111  for (k=0; k<N; k++) {
2112    k3 = 3*k;  // base index
2113   
2114    // Get bathymetry
2115    z0 = ((double*) v -> data)[k3 + 0];
2116    z1 = ((double*) v -> data)[k3 + 1];
2117    z2 = ((double*) v -> data)[k3 + 2];
2118   
2119    // Optimise for flat bed
2120    // Note (Ole): This didn't produce measurable speed up.
2121    // Revisit later
2122    //if (fabs(z0-z1)<epsilon && fabs(z1-z2)<epsilon) {
2123    //  continue;
2124    //}
2125   
2126    // Get average depth from centroid values
2127    avg_h = ((double *) h -> data)[k];
2128   
2129    // Compute bed slope
2130    k6 = 6*k;  // base index
2131   
2132    x0 = ((double*) x -> data)[k6 + 0];
2133    y0 = ((double*) x -> data)[k6 + 1];
2134    x1 = ((double*) x -> data)[k6 + 2];
2135    y1 = ((double*) x -> data)[k6 + 3];
2136    x2 = ((double*) x -> data)[k6 + 4];
2137    y2 = ((double*) x -> data)[k6 + 5];
2138   
2139   
2140    _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy);
2141   
2142    // Update momentum
2143    ((double*) xmom -> data)[k] += -g*zx*avg_h;
2144    ((double*) ymom -> data)[k] += -g*zy*avg_h;
2145  }
2146 
2147  return Py_BuildValue("");
2148}
2149
2150
2151PyObject *extrapolate_second_order_edge_sw(PyObject *self, PyObject *args) {
2152  /*Compute the edge values based on a linear reconstruction
2153    on each triangle
2154   
2155    Python call:
2156    extrapolate_second_order_sw(domain.surrogate_neighbours,
2157                                domain.number_of_boundaries
2158                                domain.centroid_coordinates,
2159                                Stage.centroid_values
2160                                Xmom.centroid_values
2161                                Ymom.centroid_values
2162                                domain.edge_coordinates,
2163                                Stage.edge_values,
2164                                Xmom.edge_values,
2165                                Ymom.edge_values)
2166
2167    Post conditions:
2168        The edges of each triangle have values from a
2169        limited linear reconstruction
2170        based on centroid values
2171
2172  */
2173  PyArrayObject *surrogate_neighbours,
2174    *neighbour_edges,
2175    *number_of_boundaries,
2176    *centroid_coordinates,
2177    *stage_centroid_values,
2178    *xmom_centroid_values,
2179    *ymom_centroid_values,
2180    *elevation_centroid_values,
2181    *edge_coordinates,
2182    *stage_edge_values,
2183    *xmom_edge_values,
2184    *ymom_edge_values,
2185    *elevation_edge_values,
2186    *stage_vertex_values,
2187    *xmom_vertex_values,
2188    *ymom_vertex_values,
2189    *elevation_vertex_values;
2190 
2191  PyObject *domain;
2192
2193 
2194  double beta_w, beta_w_dry, beta_uh, beta_uh_dry, beta_vh, beta_vh_dry;   
2195  double minimum_allowed_height, epsilon;
2196  int optimise_dry_cells, number_of_elements, extrapolate_velocity_second_order, e, e2;
2197 
2198  // Convert Python arguments to C
2199  if (!PyArg_ParseTuple(args, "OOOOOOOOOOOOOOOOOOii",
2200            &domain,
2201            &surrogate_neighbours,
2202            &neighbour_edges,
2203            &number_of_boundaries,
2204            &centroid_coordinates,
2205            &stage_centroid_values,
2206            &xmom_centroid_values,
2207            &ymom_centroid_values,
2208            &elevation_centroid_values,
2209            &edge_coordinates,
2210            &stage_edge_values,
2211            &xmom_edge_values,
2212            &ymom_edge_values,
2213            &elevation_edge_values,
2214            &stage_vertex_values,
2215            &xmom_vertex_values,
2216            &ymom_vertex_values,
2217            &elevation_vertex_values,
2218            &optimise_dry_cells,
2219            &extrapolate_velocity_second_order)) {         
2220
2221    report_python_error(AT, "could not parse input arguments");
2222    return NULL;
2223  }
2224
2225  // check that numpy array objects arrays are C contiguous memory
2226  CHECK_C_CONTIG(surrogate_neighbours);
2227  CHECK_C_CONTIG(neighbour_edges);
2228  CHECK_C_CONTIG(number_of_boundaries);
2229  CHECK_C_CONTIG(centroid_coordinates);
2230  CHECK_C_CONTIG(stage_centroid_values);
2231  CHECK_C_CONTIG(xmom_centroid_values);
2232  CHECK_C_CONTIG(ymom_centroid_values);
2233  CHECK_C_CONTIG(elevation_centroid_values);
2234  CHECK_C_CONTIG(edge_coordinates);
2235  CHECK_C_CONTIG(stage_edge_values);
2236  CHECK_C_CONTIG(xmom_edge_values);
2237  CHECK_C_CONTIG(ymom_edge_values);
2238  CHECK_C_CONTIG(elevation_edge_values);
2239  CHECK_C_CONTIG(stage_vertex_values);
2240  CHECK_C_CONTIG(xmom_vertex_values);
2241  CHECK_C_CONTIG(ymom_vertex_values);
2242  CHECK_C_CONTIG(elevation_vertex_values);
2243 
2244  // Get the safety factor beta_w, set in the config.py file.
2245  // This is used in the limiting process
2246 
2247
2248  beta_w                 = get_python_double(domain,"beta_w");
2249  beta_w_dry             = get_python_double(domain,"beta_w_dry");
2250  beta_uh                = get_python_double(domain,"beta_uh");
2251  beta_uh_dry            = get_python_double(domain,"beta_uh_dry");
2252  beta_vh                = get_python_double(domain,"beta_vh");
2253  beta_vh_dry            = get_python_double(domain,"beta_vh_dry"); 
2254
2255  minimum_allowed_height = get_python_double(domain,"minimum_allowed_height");
2256  epsilon                = get_python_double(domain,"epsilon");
2257
2258  number_of_elements = stage_centroid_values -> dimensions[0]; 
2259
2260  //printf("In C before Extrapolate");
2261  //e=1;
2262  // Call underlying computational routine
2263  e = _extrapolate_second_order_edge_sw(number_of_elements,
2264                   epsilon,
2265                   minimum_allowed_height,
2266                   beta_w,
2267                   beta_w_dry,
2268                   beta_uh,
2269                   beta_uh_dry,
2270                   beta_vh,
2271                   beta_vh_dry,
2272                   (long*) surrogate_neighbours -> data,
2273                   (long*) neighbour_edges -> data,
2274                   (long*) number_of_boundaries -> data,
2275                   (double*) centroid_coordinates -> data,
2276                   (double*) stage_centroid_values -> data,
2277                   (double*) xmom_centroid_values -> data,
2278                   (double*) ymom_centroid_values -> data,
2279                   (double*) elevation_centroid_values -> data,
2280                   (double*) edge_coordinates -> data,
2281                   (double*) stage_edge_values -> data,
2282                   (double*) xmom_edge_values -> data,
2283                   (double*) ymom_edge_values -> data,
2284                   (double*) elevation_edge_values -> data,
2285                   (double*) stage_vertex_values -> data,
2286                   (double*) xmom_vertex_values -> data,
2287                   (double*) ymom_vertex_values -> data,
2288                   (double*) elevation_vertex_values -> data,
2289                   optimise_dry_cells, 
2290                   extrapolate_velocity_second_order);
2291
2292  if (e == -1) {
2293    // Use error string set inside computational routine
2294    return NULL;
2295  }                   
2296 
2297 
2298  return Py_BuildValue("");
2299 
2300}// extrapolate_second-order_edge_sw
2301//========================================================================
2302// Protect -- to prevent the water level from falling below the minimum
2303// bed_edge_value
2304//========================================================================
2305
2306PyObject *protect(PyObject *self, PyObject *args) {
2307  //
2308  //    protect(minimum_allowed_height, maximum_allowed_speed, wc, zc, xmomc, ymomc)
2309
2310
2311  PyArrayObject
2312  *wc,            //Stage at centroids
2313  *wv,            //Stage at vertices
2314  *zc,            //Elevation at centroids
2315  *zv,            //Elevation at vertices
2316  *xmomc,         //Momentums at centroids
2317  *ymomc,
2318  *areas,         // Triangle areas
2319  *xc,
2320  *yc;
2321
2322  int N;
2323  double minimum_allowed_height, maximum_allowed_speed, epsilon;
2324
2325  // Convert Python arguments to C
2326  if (!PyArg_ParseTuple(args, "dddOOOOOOOOO",
2327            &minimum_allowed_height,
2328            &maximum_allowed_speed,
2329            &epsilon,
2330            &wc, &wv, &zc, &zv, &xmomc, &ymomc, &areas, &xc, &yc)) {
2331    report_python_error(AT, "could not parse input arguments");
2332    return NULL;
2333  } 
2334
2335  N = wc -> dimensions[0];
2336
2337  _protect(N,
2338       minimum_allowed_height,
2339       maximum_allowed_speed,
2340       epsilon,
2341       (double*) wc -> data,
2342       (double*) wv -> data,
2343       (double*) zc -> data,
2344       (double*) zv -> data,
2345       (double*) xmomc -> data,
2346       (double*) ymomc -> data,
2347       (double*) areas -> data,
2348       (double*) xc -> data,
2349       (double*) yc -> data );
2350
2351  return Py_BuildValue("");
2352}
2353
2354//========================================================================
2355// Method table for python module
2356//========================================================================
2357
2358static struct PyMethodDef MethodTable[] = {
2359  /* The cast of the function is necessary since PyCFunction values
2360   * only take two PyObject* parameters, and rotate() takes
2361   * three.
2362   */
2363  //{"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
2364  {"compute_fluxes_ext_central", compute_fluxes_ext_central, METH_VARARGS, "Print out"},
2365  {"gravity_c",        gravity,            METH_VARARGS, "Print out"},
2366  {"flux_function_central", flux_function_central, METH_VARARGS, "Print out"}, 
2367  {"extrapolate_second_order_edge_sw", extrapolate_second_order_edge_sw, METH_VARARGS, "Print out"},
2368  {"protect",          protect, METH_VARARGS | METH_KEYWORDS, "Print out"},
2369  {NULL, NULL, 0, NULL}
2370};
2371
2372// Module initialisation
2373void initswb2_domain_ext(void){
2374  Py_InitModule("swb2_domain_ext", MethodTable);
2375
2376  import_array(); // Necessary for handling of NumPY structures
2377}
Note: See TracBrowser for help on using the repository browser.