source: trunk/anuga_core/source/anuga/shallow_water/shallow_water_ext.c @ 8219

Last change on this file since 8219 was 8219, checked in by steve, 13 years ago

Rudy created a mesh which produced a degenerate surrogate triangle. Changed throwing an error to defaulting to a first order reconstruction

File size: 88.6 KB
Line 
1// Python - C extension module for shallow_water.py
2//
3// To compile (Python2.3):
4//  gcc -c domain_ext.c -I/usr/include/python2.3 -o domain_ext.o -Wall -O
5//  gcc -shared domain_ext.o  -o domain_ext.so
6//
7// or use python compile.py
8//
9// See the module shallow_water_domain.py for more documentation on
10// how to use this module
11//
12//
13// Ole Nielsen, GA 2004
14
15
16#include "Python.h"
17#include "numpy/arrayobject.h"
18#include "math.h"
19#include <stdio.h>
20#include "numpy_shim.h"
21
22// Shared code snippets
23#include "util_ext.h"
24
25
26
27
28
29const double pi = 3.14159265358979;
30
31// Computational function for rotation
32// Tried to inline, but no speedup was achieved 27th May 2009 (Ole)
33// static inline int _rotate(double *q, double n1, double n2) {
34int _rotate(double *q, double n1, double n2) {
35  /*Rotate the momentum component q (q[1], q[2])
36    from x,y coordinates to coordinates based on normal vector (n1, n2).
37
38    Result is returned in array 3x1 r
39    To rotate in opposite direction, call rotate with (q, n1, -n2)
40
41    Contents of q are changed by this function */
42
43
44  double q1, q2;
45
46  // Shorthands
47  q1 = q[1];  // uh momentum
48  q2 = q[2];  // vh momentum
49
50  // Rotate
51  q[1] =  n1*q1 + n2*q2;
52  q[2] = -n2*q1 + n1*q2;
53
54  return 0;
55}
56
57int find_qmin_and_qmax(double dq0, double dq1, double dq2, 
58               double *qmin, double *qmax){
59  // Considering the centroid of an FV triangle and the vertices of its
60  // auxiliary triangle, find
61  // qmin=min(q)-qc and qmax=max(q)-qc,
62  // where min(q) and max(q) are respectively min and max over the
63  // four values (at the centroid of the FV triangle and the auxiliary
64  // triangle vertices),
65  // and qc is the centroid
66  // dq0=q(vertex0)-q(centroid of FV triangle)
67  // dq1=q(vertex1)-q(vertex0)
68  // dq2=q(vertex2)-q(vertex0)
69 
70  if (dq0>=0.0){
71    if (dq1>=dq2){
72      if (dq1>=0.0)
73    *qmax=dq0+dq1;
74      else
75    *qmax=dq0;
76     
77      *qmin=dq0+dq2;
78      if (*qmin>=0.0) *qmin = 0.0;
79    }
80    else{// dq1<dq2
81      if (dq2>0)
82    *qmax=dq0+dq2;
83      else
84    *qmax=dq0;
85     
86      *qmin=dq0+dq1;   
87      if (*qmin>=0.0) *qmin=0.0;
88    }
89  }
90  else{//dq0<0
91    if (dq1<=dq2){
92      if (dq1<0.0)
93    *qmin=dq0+dq1;
94      else
95    *qmin=dq0;
96     
97      *qmax=dq0+dq2;   
98      if (*qmax<=0.0) *qmax=0.0;
99    }
100    else{// dq1>dq2
101      if (dq2<0.0)
102    *qmin=dq0+dq2;
103      else
104    *qmin=dq0;
105     
106      *qmax=dq0+dq1;
107      if (*qmax<=0.0) *qmax=0.0;
108    }
109  }
110  return 0;
111}
112
113int limit_gradient(double *dqv, double qmin, double qmax, double beta_w){
114  // Given provisional jumps dqv from the FV triangle centroid to its
115  // vertices and jumps qmin (qmax) between the centroid of the FV
116  // triangle and the minimum (maximum) of the values at the centroid of
117  // the FV triangle and the auxiliary triangle vertices,
118  // calculate a multiplicative factor phi by which the provisional
119  // vertex jumps are to be limited
120 
121  int i;
122  double r=1000.0, r0=1.0, phi=1.0;
123  static double TINY = 1.0e-100; // to avoid machine accuracy problems.
124  // FIXME: Perhaps use the epsilon used elsewhere.
125 
126  // Any provisional jump with magnitude < TINY does not contribute to
127  // the limiting process.
128  for (i=0;i<3;i++){
129    if (dqv[i]<-TINY)
130      r0=qmin/dqv[i];
131     
132    if (dqv[i]>TINY)
133      r0=qmax/dqv[i];
134     
135    r=min(r0,r);
136  }
137 
138  phi=min(r*beta_w,1.0);
139  //for (i=0;i<3;i++)
140  dqv[0]=dqv[0]*phi;
141  dqv[1]=dqv[1]*phi;
142  dqv[2]=dqv[2]*phi;
143   
144  return 0;
145}
146
147
148double compute_froude_number(double uh,
149                 double h, 
150                 double g,
151                 double epsilon) {
152             
153  // Compute Froude number; v/sqrt(gh)
154  // FIXME (Ole): Not currently in use
155   
156  double froude_number;
157 
158  //Compute Froude number (stability diagnostics)
159  if (h > epsilon) { 
160    froude_number = uh/sqrt(g*h)/h;
161  } else {
162    froude_number = 0.0;
163    // FIXME (Ole): What should it be when dry??
164  }
165 
166  return froude_number;
167}
168
169
170
171// Function to obtain speed from momentum and depth.
172// This is used by flux functions
173// Input parameters uh and h may be modified by this function.
174// Tried to inline, but no speedup was achieved 27th May 2009 (Ole)
175//static inline double _compute_speed(double *uh,
176double _compute_speed(double *uh, 
177              double *h,
178              double epsilon,
179              double h0,
180              double limiting_threshold) {
181 
182  double u;
183
184  if (*h < limiting_threshold) {   
185    // Apply limiting of speeds according to the ANUGA manual
186    if (*h < epsilon) {
187      *h = 0.0;  // Could have been negative
188      u = 0.0;
189    } else {
190      u = *uh/(*h + h0/ *h);   
191    }
192 
193
194    // Adjust momentum to be consistent with speed
195    *uh = u * *h;
196  } else {
197    // We are in deep water - no need for limiting
198    u = *uh/ *h;
199  }
200 
201  return u;
202}
203
204
205// Optimised squareroot computation
206//
207//See
208//http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf
209//and http://mail.opensolaris.org/pipermail/tools-gcc/2005-August/000047.html
210float fast_squareroot_approximation(float number) {
211  float x; 
212  const float f = 1.5;
213
214  // Allow i and y to occupy the same memory
215  union
216  {
217    long i;
218    float y;
219  } u;
220 
221  // Good initial guess 
222  x = number * 0.5; 
223  u.= number;
224  u.= 0x5f3759df - ( u.i >> 1 );
225 
226  // Take a few iterations
227  u.= u.y * ( f - ( x * u.y * u.y ) );
228  u.= u.y * ( f - ( x * u.y * u.y ) );
229   
230  return number * u.y;
231}
232
233
234
235// Optimised squareroot computation (double version)
236double Xfast_squareroot_approximation(double number) {
237  double x;
238  const double f = 1.5;
239   
240  // Allow i and y to occupy the same memory   
241  union
242  {
243    long long i;
244    double y;
245  } u;
246
247  // Good initial guess
248  x = number * 0.5;
249  u.= number;
250  u.= 0x5fe6ec85e7de30daLL - ( u.i >> 1 );
251 
252  // Take a few iterations 
253  u.= u.y * ( f - ( x * u.y * u.y ) );
254  u.= u.y * ( f - ( x * u.y * u.y ) );
255
256  return number * u.y;
257}
258
259
260// Innermost flux function (using stage w=z+h)
261int _flux_function_central(double *q_left, double *q_right,
262                           double z_left, double z_right,
263                           double n1, double n2,
264                           double epsilon, 
265               double h0,
266               double limiting_threshold,
267               double g,
268                           double *edgeflux, double *max_speed) 
269{
270
271  /*Compute fluxes between volumes for the shallow water wave equation
272    cast in terms of the 'stage', w = h+z using
273    the 'central scheme' as described in
274
275    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
276    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
277    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
278
279    The implemented formula is given in equation (3.15) on page 714
280  */
281
282  int i;
283
284  double w_left, h_left, uh_left, vh_left, u_left;
285  double w_right, h_right, uh_right, vh_right, u_right;
286  double s_min, s_max, soundspeed_left, soundspeed_right;
287  double denom, inverse_denominator, z;
288
289  // Workspace (allocate once, use many)
290  static double q_left_rotated[3], q_right_rotated[3], flux_right[3], flux_left[3];
291
292  // Copy conserved quantities to protect from modification
293  q_left_rotated[0] = q_left[0];
294  q_right_rotated[0] = q_right[0];
295  q_left_rotated[1] = q_left[1];
296  q_right_rotated[1] = q_right[1];
297  q_left_rotated[2] = q_left[2];
298  q_right_rotated[2] = q_right[2];
299
300  // Align x- and y-momentum with x-axis
301  _rotate(q_left_rotated, n1, n2);
302  _rotate(q_right_rotated, n1, n2);
303
304  z = 0.5*(z_left + z_right); // Average elevation values.
305                              // Even though this will nominally allow
306                  // for discontinuities in the elevation data,
307                  // there is currently no numerical support for
308                  // this so results may be strange near
309                  // jumps in the bed.
310
311  // Compute speeds in x-direction
312  w_left = q_left_rotated[0];         
313  h_left = w_left - z;
314  uh_left = q_left_rotated[1];
315  u_left = _compute_speed(&uh_left, &h_left, 
316              epsilon, h0, limiting_threshold);
317
318  w_right = q_right_rotated[0];
319  h_right = w_right - z;
320  uh_right = q_right_rotated[1];
321  u_right = _compute_speed(&uh_right, &h_right, 
322               epsilon, h0, limiting_threshold);
323
324  // Momentum in y-direction
325  vh_left  = q_left_rotated[2];
326  vh_right = q_right_rotated[2];
327
328  // Limit y-momentum if necessary
329  // Leaving this out, improves speed significantly (Ole 27/5/2009)
330  // All validation tests pass, so do we really need it anymore?
331  _compute_speed(&vh_left, &h_left, 
332         epsilon, h0, limiting_threshold);
333  _compute_speed(&vh_right, &h_right, 
334         epsilon, h0, limiting_threshold);
335
336  // Maximal and minimal wave speeds
337  soundspeed_left  = sqrt(g*h_left);
338  soundspeed_right = sqrt(g*h_right); 
339 
340  // Code to use fast square root optimisation if desired.
341  // Timings on AMD 64 for the Okushiri profile gave the following timings
342  //
343  // SQRT           Total    Flux
344  //=============================
345  //
346  // Ref            405s     152s
347  // Fast (dbl)     453s     173s
348  // Fast (sng)     437s     171s
349  //
350  // Consequently, there is currently (14/5/2009) no reason to use this
351  // approximation.
352 
353  //soundspeed_left  = fast_squareroot_approximation(g*h_left);
354  //soundspeed_right = fast_squareroot_approximation(g*h_right);
355
356  s_max = max(u_left + soundspeed_left, u_right + soundspeed_right);
357  if (s_max < 0.0) 
358  {
359    s_max = 0.0;
360  }
361
362  s_min = min(u_left - soundspeed_left, u_right - soundspeed_right);
363  if (s_min > 0.0)
364  {
365    s_min = 0.0;
366  }
367 
368  // Flux formulas
369  flux_left[0] = u_left*h_left;
370  flux_left[1] = u_left*uh_left + 0.5*g*h_left*h_left;
371  flux_left[2] = u_left*vh_left;
372
373  flux_right[0] = u_right*h_right;
374  flux_right[1] = u_right*uh_right + 0.5*g*h_right*h_right;
375  flux_right[2] = u_right*vh_right;
376
377  // Flux computation
378  denom = s_max - s_min;
379  if (denom < epsilon) 
380  { // FIXME (Ole): Try using h0 here
381    memset(edgeflux, 0, 3*sizeof(double));
382    *max_speed = 0.0;
383  } 
384  else 
385  {
386    inverse_denominator = 1.0/denom;
387    for (i = 0; i < 3; i++) 
388    {
389      edgeflux[i] = s_max*flux_left[i] - s_min*flux_right[i];
390      edgeflux[i] += s_max*s_min*(q_right_rotated[i] - q_left_rotated[i]);
391      edgeflux[i] *= inverse_denominator;
392    }
393
394    // Maximal wavespeed
395    *max_speed = max(fabs(s_max), fabs(s_min));
396
397    // Rotate back
398    _rotate(edgeflux, n1, -n2);
399  }
400 
401  return 0;
402}
403
404double erfcc(double x){
405    double z,t,result;
406
407    z=fabs(x);
408    t=1.0/(1.0+0.5*z);
409    result=t*exp(-z*z-1.26551223+t*(1.00002368+t*(.37409196+
410         t*(.09678418+t*(-.18628806+t*(.27886807+t*(-1.13520398+
411         t*(1.48851587+t*(-.82215223+t*.17087277)))))))));
412    if (x < 0.0) result = 2.0-result;
413
414    return result;
415    }
416
417
418
419// Computational function for flux computation (using stage w=z+h)
420int flux_function_kinetic(double *q_left, double *q_right,
421          double z_left, double z_right,
422          double n1, double n2,
423          double epsilon, double H0, double g,
424          double *edgeflux, double *max_speed) {
425
426  /*Compute fluxes between volumes for the shallow water wave equation
427    cast in terms of the 'stage', w = h+z using
428    the 'central scheme' as described in
429
430    Zhang et. al., Advances in Water Resources, 26(6), 2003, 635-647.
431  */
432
433  int i;
434
435  double w_left, h_left, uh_left, vh_left, u_left, F_left;
436  double w_right, h_right, uh_right, vh_right, u_right, F_right;
437  double s_min, s_max, soundspeed_left, soundspeed_right;
438  double z;
439  double q_left_rotated[3], q_right_rotated[3];
440
441  double h0 = H0*H0; //This ensures a good balance when h approaches H0.
442  double limiting_threshold = 10*H0; // Avoid applying limiter below this 
443 
444  //Copy conserved quantities to protect from modification
445  for (i=0; i<3; i++) {
446    q_left_rotated[i] = q_left[i];
447    q_right_rotated[i] = q_right[i];
448  }
449
450  //Align x- and y-momentum with x-axis
451  _rotate(q_left_rotated, n1, n2);
452  _rotate(q_right_rotated, n1, n2);
453
454  z = (z_left+z_right)/2; //Take average of field values
455
456  //Compute speeds in x-direction
457  w_left = q_left_rotated[0];         
458  h_left = w_left-z;
459  uh_left = q_left_rotated[1];
460  u_left =_compute_speed(&uh_left, &h_left, 
461             epsilon, h0, limiting_threshold);
462
463  w_right = q_right_rotated[0];
464  h_right = w_right-z;
465  uh_right = q_right_rotated[1];
466  u_right =_compute_speed(&uh_right, &h_right,
467              epsilon, h0, limiting_threshold);
468
469
470  //Momentum in y-direction
471  vh_left  = q_left_rotated[2];
472  vh_right = q_right_rotated[2];
473
474
475  //Maximal and minimal wave speeds
476  soundspeed_left  = sqrt(g*h_left);
477  soundspeed_right = sqrt(g*h_right);
478
479  s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
480  if (s_max < 0.0) s_max = 0.0;
481
482  s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
483  if (s_min > 0.0) s_min = 0.0;
484
485
486  F_left  = 0.0;
487  F_right = 0.0;
488  if (h_left > 0.0) F_left = u_left/sqrt(g*h_left);
489  if (h_right > 0.0) F_right = u_right/sqrt(g*h_right);
490
491  for (i=0; i<3; i++) edgeflux[i] = 0.0;
492  *max_speed = 0.0;
493
494  edgeflux[0] = h_left*u_left/2.0*erfcc(-F_left) +  \
495          h_left*sqrt(g*h_left)/2.0/sqrt(pi)*exp(-(F_left*F_left)) + \
496          h_right*u_right/2.0*erfcc(F_right) -  \
497          h_right*sqrt(g*h_right)/2.0/sqrt(pi)*exp(-(F_right*F_right));
498
499  edgeflux[1] = (h_left*u_left*u_left + g/2.0*h_left*h_left)/2.0*erfcc(-F_left) + \
500          u_left*h_left*sqrt(g*h_left)/2.0/sqrt(pi)*exp(-(F_left*F_left)) + \
501          (h_right*u_right*u_right + g/2.0*h_right*h_right)/2.0*erfcc(F_right) -  \
502          u_right*h_right*sqrt(g*h_right)/2.0/sqrt(pi)*exp(-(F_right*F_right));
503
504  edgeflux[2] = vh_left*u_left/2.0*erfcc(-F_left) + \
505          vh_left*sqrt(g*h_left)/2.0/sqrt(pi)*exp(-(F_left*F_left)) + \
506          vh_right*u_right/2.0*erfcc(F_right) - \
507          vh_right*sqrt(g*h_right)/2.0/sqrt(pi)*exp(-(F_right*F_right));
508
509  //Maximal wavespeed
510  *max_speed = max(fabs(s_max), fabs(s_min));
511
512  //Rotate back
513  _rotate(edgeflux, n1, -n2);
514
515  return 0;
516}
517
518
519
520
521void _manning_friction_flat(double g, double eps, int N,
522               double* w, double* zv,
523               double* uh, double* vh,
524               double* eta, double* xmom, double* ymom) {
525
526  int k, k3;
527  double S, h, z, z0, z1, z2;
528
529  for (k=0; k<N; k++) {
530    if (eta[k] > eps) {
531      k3 = 3*k;
532      // Get bathymetry
533      z0 = zv[k3 + 0];
534      z1 = zv[k3 + 1];
535      z2 = zv[k3 + 2];
536      z = (z0+z1+z2)/3.0;
537      h = w[k]-z;
538      if (h >= eps) {
539        S = -g * eta[k]*eta[k] * sqrt((uh[k]*uh[k] + vh[k]*vh[k]));
540        S /= pow(h, 7.0/3);      //Expensive (on Ole's home computer)
541        //S /= exp((7.0/3.0)*log(h));      //seems to save about 15% over manning_friction
542        //S /= h*h*(1 + h/3.0 - h*h/9.0); //FIXME: Could use a Taylor expansion
543
544
545        //Update momentum
546        xmom[k] += S*uh[k];
547        ymom[k] += S*vh[k];
548      }
549    }
550  }
551}
552
553
554void _manning_friction_sloped(double g, double eps, int N,
555               double* x, double* w, double* zv,
556               double* uh, double* vh,
557               double* eta, double* xmom_update, double* ymom_update) {
558
559  int k, k3, k6;
560  double S, h, z, z0, z1, z2, zs, zx, zy;
561  double x0,y0,x1,y1,x2,y2;
562
563  for (k=0; k<N; k++) {
564    if (eta[k] > eps) {
565      k3 = 3*k;
566      // Get bathymetry
567      z0 = zv[k3 + 0];
568      z1 = zv[k3 + 1];
569      z2 = zv[k3 + 2];
570
571      // Compute bed slope
572      k6 = 6*k;  // base index
573 
574      x0 = x[k6 + 0];
575      y0 = x[k6 + 1];
576      x1 = x[k6 + 2];
577      y1 = x[k6 + 3];
578      x2 = x[k6 + 4];
579      y2 = x[k6 + 5];
580
581      _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy);
582
583      zs = sqrt(1.0 + zx*zx + zy*zy);
584      z = (z0+z1+z2)/3.0;
585      h = w[k]-z;
586      if (h >= eps) {
587        S = -g * eta[k]*eta[k] * zs * sqrt((uh[k]*uh[k] + vh[k]*vh[k]));
588        S /= pow(h, 7.0/3);      //Expensive (on Ole's home computer)
589        //S /= exp((7.0/3.0)*log(h));      //seems to save about 15% over manning_friction
590        //S /= h*h*(1 + h/3.0 - h*h/9.0); //FIXME: Could use a Taylor expansion
591
592
593        //Update momentum
594        xmom_update[k] += S*uh[k];
595        ymom_update[k] += S*vh[k];
596      }
597    }
598  }
599}
600
601
602
603void _chezy_friction(double g, double eps, int N,
604               double* x, double* w, double* zv,
605               double* uh, double* vh,
606               double* chezy, double* xmom_update, double* ymom_update) {
607
608  int k, k3, k6;
609  double S, h, z, z0, z1, z2, zs, zx, zy;
610  double x0,y0,x1,y1,x2,y2;
611
612  for (k=0; k<N; k++) {
613    if (chezy[k] > eps) {
614      k3 = 3*k;
615      // Get bathymetry
616      z0 = zv[k3 + 0];
617      z1 = zv[k3 + 1];
618      z2 = zv[k3 + 2];
619
620      // Compute bed slope
621      k6 = 6*k;  // base index
622
623      x0 = x[k6 + 0];
624      y0 = x[k6 + 1];
625      x1 = x[k6 + 2];
626      y1 = x[k6 + 3];
627      x2 = x[k6 + 4];
628      y2 = x[k6 + 5];
629
630      _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy);
631
632      zs = sqrt(1.0 + zx*zx + zy*zy);
633      z = (z0+z1+z2)/3.0;
634      h = w[k]-z;
635      if (h >= eps) {
636        S = -g * chezy[k] * zs * sqrt((uh[k]*uh[k] + vh[k]*vh[k]));
637        S /= pow(h, 2.0);
638
639        //Update momentum
640        xmom_update[k] += S*uh[k];
641        ymom_update[k] += S*vh[k];
642      }
643    }
644  }
645}
646
647/*
648void _manning_friction_explicit(double g, double eps, int N,
649               double* w, double* z,
650               double* uh, double* vh,
651               double* eta, double* xmom, double* ymom) {
652
653  int k;
654  double S, h;
655
656  for (k=0; k<N; k++) {
657    if (eta[k] > eps) {
658      h = w[k]-z[k];
659      if (h >= eps) {
660    S = -g * eta[k]*eta[k] * sqrt((uh[k]*uh[k] + vh[k]*vh[k]));
661    S /= pow(h, 7.0/3);      //Expensive (on Ole's home computer)
662    //S /= exp(7.0/3.0*log(h));      //seems to save about 15% over manning_friction
663    //S /= h*h*(1 + h/3.0 - h*h/9.0); //FIXME: Could use a Taylor expansion
664
665
666    //Update momentum
667    xmom[k] += S*uh[k];
668    ymom[k] += S*vh[k];
669      }
670    }
671  }
672}
673*/
674
675
676
677
678double velocity_balance(double uh_i, 
679            double uh,
680            double h_i, 
681            double h, 
682            double alpha,
683            double epsilon) {
684  // Find alpha such that speed at the vertex is within one
685  // order of magnitude of the centroid speed   
686
687  // FIXME(Ole): Work in progress
688 
689  double a, b, estimate;
690  double m=10; // One order of magnitude - allow for velocity deviations at vertices
691
692 
693  printf("alpha = %f, uh_i=%f, uh=%f, h_i=%f, h=%f\n",
694     alpha, uh_i, uh, h_i, h);
695     
696 
697 
698   
699  // Shorthands and determine inequality
700  if (fabs(uh) < epsilon) {
701    a = 1.0e10; // Limit
702  } else {
703    a = fabs(uh_i - uh)/fabs(uh);
704  }
705     
706  if (h < epsilon) {
707    b = 1.0e10; // Limit
708  } else {   
709    b = m*fabs(h_i - h)/h;
710  }
711
712  printf("a %f, b %f\n", a, b); 
713
714  if (a > b) {
715    estimate = (m-1)/(a-b);     
716   
717    printf("Alpha %f, estimate %f\n", 
718       alpha, estimate);   
719       
720    if (alpha < estimate) {
721      printf("Adjusting alpha from %f to %f\n", 
722         alpha, estimate);
723      alpha = estimate;
724    }
725  } else {
726 
727    if (h < h_i) {
728      estimate = (m-1)/(a-b);             
729   
730      printf("Alpha %f, estimate %f\n", 
731         alpha, estimate);   
732       
733      if (alpha < estimate) {
734    printf("Adjusting alpha from %f to %f\n", 
735           alpha, estimate);
736    alpha = estimate;
737      }   
738    }
739    // Always fulfilled as alpha and m-1 are non negative
740  }
741 
742 
743  return alpha;
744}
745
746
747int _balance_deep_and_shallow(int N,
748                  double* wc,
749                  double* zc,
750                  double* wv,
751                  double* zv,
752                  double* hvbar, // Retire this
753                  double* xmomc,
754                  double* ymomc,
755                  double* xmomv,
756                  double* ymomv,
757                  double H0,
758                  int tight_slope_limiters,
759                  int use_centroid_velocities,
760                  double alpha_balance) {
761
762  int k, k3, i; 
763
764  double dz, hmin, alpha, h_diff, hc_k;
765  double epsilon = 1.0e-6; // FIXME: Temporary measure
766  double hv[3]; // Depths at vertices
767  double uc, vc; // Centroid speeds
768
769  // Compute linear combination between w-limited stages and
770  // h-limited stages close to the bed elevation.
771
772  for (k=0; k<N; k++) {
773    // Compute maximal variation in bed elevation
774    // This quantitiy is
775    //     dz = max_i abs(z_i - z_c)
776    // and it is independent of dimension
777    // In the 1d case zc = (z0+z1)/2
778    // In the 2d case zc = (z0+z1+z2)/3
779
780    k3 = 3*k;
781    hc_k = wc[k] - zc[k]; // Centroid value at triangle k
782   
783    dz = 0.0;
784    if (tight_slope_limiters == 0) {     
785      // FIXME: Try with this one precomputed
786      for (i=0; i<3; i++) {
787    dz = max(dz, fabs(zv[k3+i]-zc[k]));
788      }
789    }
790
791    // Calculate depth at vertices (possibly negative here!)
792    hv[0] = wv[k3] -   zv[k3];
793    hv[1] = wv[k3+1] - zv[k3+1];
794    hv[2] = wv[k3+2] - zv[k3+2];       
795   
796    // Calculate minimal depth across all three vertices
797    hmin = min(hv[0], min(hv[1], hv[2]));
798
799    //if (hmin < 0.0 ) {
800    //  printf("hmin = %f\n",hmin);
801    //}
802   
803
804    // Create alpha in [0,1], where alpha==0 means using the h-limited
805    // stage and alpha==1 means using the w-limited stage as
806    // computed by the gradient limiter (both 1st or 2nd order)
807    if (tight_slope_limiters == 0) {     
808      // If hmin > dz/alpha_balance then alpha = 1 and the bed will have no
809      // effect
810      // If hmin < 0 then alpha = 0 reverting to constant height above bed.
811      // The parameter alpha_balance==2 by default
812
813     
814      if (dz > 0.0) {
815    alpha = max( min( alpha_balance*hmin/dz, 1.0), 0.0 );
816      } else {
817    alpha = 1.0;  // Flat bed
818      }
819      //printf("Using old style limiter\n");
820     
821    } else {
822
823      // Tight Slope Limiter (2007)
824   
825      // Make alpha as large as possible but still ensure that
826      // final depth is positive and that velocities at vertices
827      // are controlled
828   
829      if (hmin < H0) {
830    alpha = 1.0;
831    for (i=0; i<3; i++) {
832
833      h_diff = hc_k - hv[i];
834      if (h_diff <= 0) {
835        // Deep water triangle is further away from bed than
836        // shallow water (hbar < h). Any alpha will do
837     
838      } else {
839        // Denominator is positive which means that we need some of the
840        // h-limited stage.
841
842        alpha = min(alpha, (hc_k - H0)/h_diff);
843      }
844    }
845
846    // Ensure alpha in [0,1]
847    if (alpha>1.0) alpha=1.0;
848    if (alpha<0.0) alpha=0.0;
849
850      } else {
851    // Use w-limited stage exclusively in deeper water.
852    alpha = 1.0;
853      }
854    }
855   
856   
857    //  Let
858    //
859    //    wvi be the w-limited stage (wvi = zvi + hvi)
860    //    wvi- be the h-limited state (wvi- = zvi + hvi-)
861    //
862    //
863    //  where i=0,1,2 denotes the vertex ids
864    //
865    //  Weighted balance between w-limited and h-limited stage is
866    //
867    //    wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
868    //
869    //  It follows that the updated wvi is
870    //    wvi := zvi + (1-alpha)*hvi- + alpha*hvi
871    //
872    //   Momentum is balanced between constant and limited
873
874   
875    if (alpha < 1) {     
876      for (i=0; i<3; i++) {
877
878    wv[k3+i] = zv[k3+i] + (1-alpha)*hc_k + alpha*hv[i];
879
880    // Update momentum at vertices
881    if (use_centroid_velocities == 1) {
882      // This is a simple, efficient and robust option
883      // It uses first order approximation of velocities, but retains
884      // the order used by stage.
885   
886      // Speeds at centroids
887      if (hc_k > epsilon) {
888        uc = xmomc[k]/hc_k;
889        vc = ymomc[k]/hc_k;
890      } else {
891        uc = 0.0;
892        vc = 0.0;
893      }
894
895      // Vertex momenta guaranteed to be consistent with depth guaranteeing
896      // controlled speed
897      hv[i] = wv[k3+i] - zv[k3+i]; // Recompute (balanced) vertex depth
898      xmomv[k3+i] = uc*hv[i];
899      ymomv[k3+i] = vc*hv[i];
900     
901    } else {
902      // Update momentum as a linear combination of
903      // xmomc and ymomc (shallow) and momentum
904      // from extrapolator xmomv and ymomv (deep).
905      // This assumes that values from xmomv and ymomv have
906      // been established e.g. by the gradient limiter.
907
908      // FIXME (Ole): I think this should be used with vertex momenta
909      // computed above using centroid_velocities instead of xmomc
910      // and ymomc as they'll be more representative first order
911      // values.
912
913      xmomv[k3+i] = (1-alpha)*xmomc[k] + alpha*xmomv[k3+i];
914      ymomv[k3+i] = (1-alpha)*ymomc[k] + alpha*ymomv[k3+i];
915
916    }
917      }
918    }
919  }
920  return 0;
921}
922 
923
924
925
926int _protect(int N,
927         double minimum_allowed_height,
928         double maximum_allowed_speed,
929         double epsilon,
930         double* wc,
931         double* zc,
932         double* xmomc,
933         double* ymomc) {
934
935  int k;
936  double hc;
937  double u, v, reduced_speed;
938
939
940  // Protect against initesimal and negative heights 
941  if (maximum_allowed_speed < epsilon) {
942    for (k=0; k<N; k++) {
943      hc = wc[k] - zc[k];
944
945      if (hc < minimum_allowed_height) {
946       
947    // Set momentum to zero and ensure h is non negative
948    xmomc[k] = 0.0;
949    ymomc[k] = 0.0;
950    if (hc <= 0.0) wc[k] = zc[k];
951      }
952    }
953  } else {
954   
955    // Protect against initesimal and negative heights
956    for (k=0; k<N; k++) {
957      hc = wc[k] - zc[k];
958     
959      if (hc < minimum_allowed_height) {
960
961        //New code: Adjust momentum to guarantee speeds are physical
962        //          ensure h is non negative
963             
964        if (hc <= 0.0) {
965            wc[k] = zc[k];
966        xmomc[k] = 0.0;
967        ymomc[k] = 0.0;
968        } else {
969          //Reduce excessive speeds derived from division by small hc
970      //FIXME (Ole): This may be unnecessary with new slope limiters
971      //in effect.
972         
973          u = xmomc[k]/hc;
974      if (fabs(u) > maximum_allowed_speed) {
975        reduced_speed = maximum_allowed_speed * u/fabs(u);
976        //printf("Speed (u) has been reduced from %.3f to %.3f\n",
977        //   u, reduced_speed);
978        xmomc[k] = reduced_speed * hc;
979      }
980
981          v = ymomc[k]/hc;
982      if (fabs(v) > maximum_allowed_speed) {
983        reduced_speed = maximum_allowed_speed * v/fabs(v);
984        //printf("Speed (v) has been reduced from %.3f to %.3f\n",
985        //   v, reduced_speed);
986        ymomc[k] = reduced_speed * hc;
987      }
988        }
989      }
990    }
991  }
992  return 0;
993}
994
995
996
997int _assign_wind_field_values(int N,
998                  double* xmom_update,
999                  double* ymom_update,
1000                  double* s_vec,
1001                  double* phi_vec,
1002                  double cw) {
1003
1004  // Assign windfield values to momentum updates
1005
1006  int k;
1007  double S, s, phi, u, v;
1008
1009  for (k=0; k<N; k++) {
1010
1011    s = s_vec[k];
1012    phi = phi_vec[k];
1013
1014    //Convert to radians
1015    phi = phi*pi/180;
1016
1017    //Compute velocity vector (u, v)
1018    u = s*cos(phi);
1019    v = s*sin(phi);
1020
1021    //Compute wind stress
1022    S = cw * sqrt(u*u + v*v);
1023    xmom_update[k] += S*u;
1024    ymom_update[k] += S*v;
1025  }
1026  return 0;
1027}
1028
1029
1030
1031///////////////////////////////////////////////////////////////////
1032// Gateways to Python
1033
1034
1035
1036PyObject *flux_function_central(PyObject *self, PyObject *args) {
1037  //
1038  // Gateway to innermost flux function.
1039  // This is only used by the unit tests as the c implementation is
1040  // normally called by compute_fluxes in this module.
1041
1042
1043  PyArrayObject *normal, *ql, *qr,  *edgeflux;
1044  double g, epsilon, max_speed, H0, zl, zr;
1045  double h0, limiting_threshold;
1046
1047  if (!PyArg_ParseTuple(args, "OOOddOddd",
1048            &normal, &ql, &qr, &zl, &zr, &edgeflux,
1049            &epsilon, &g, &H0)) {
1050      report_python_error(AT, "could not parse input arguments");
1051      return NULL;
1052  }
1053
1054 
1055  h0 = H0*H0; // This ensures a good balance when h approaches H0.
1056              // But evidence suggests that h0 can be as little as
1057              // epsilon!
1058
1059  limiting_threshold = 10*H0; // Avoid applying limiter below this
1060                              // threshold for performance reasons.
1061                              // See ANUGA manual under flux limiting 
1062 
1063  _flux_function_central((double*) ql -> data, 
1064             (double*) qr -> data,
1065             zl,
1066             zr,
1067             ((double*) normal -> data)[0],
1068             ((double*) normal -> data)[1],
1069             epsilon, h0, limiting_threshold,
1070             g,
1071             (double*) edgeflux -> data,
1072             &max_speed);
1073 
1074  return Py_BuildValue("d", max_speed); 
1075}
1076
1077
1078
1079PyObject *gravity(PyObject *self, PyObject *args) {
1080  //
1081  //  gravity(g, h, v, x, xmom, ymom)
1082  //
1083
1084
1085  PyArrayObject *h, *z, *x, *xmom, *ymom;
1086  int k, N, k3, k6;
1087  double g, avg_h, zx, zy;
1088  double x0, y0, x1, y1, x2, y2, z0, z1, z2;
1089  //double epsilon;
1090
1091  if (!PyArg_ParseTuple(args, "dOOOOO",
1092            &g, &h, &z, &x,
1093            &xmom, &ymom)) {
1094    //&epsilon)) {
1095      report_python_error(AT, "could not parse input arguments");
1096      return NULL;
1097  }
1098
1099  // check that numpy array objects arrays are C contiguous memory
1100  CHECK_C_CONTIG(h);
1101  CHECK_C_CONTIG(z);
1102  CHECK_C_CONTIG(x);
1103  CHECK_C_CONTIG(xmom);
1104  CHECK_C_CONTIG(ymom);
1105
1106  N = h -> dimensions[0];
1107  for (k=0; k<N; k++) {
1108    k3 = 3*k;  // base index
1109
1110    // Get bathymetry
1111    z0 = ((double*) z -> data)[k3 + 0];
1112    z1 = ((double*) z -> data)[k3 + 1];
1113    z2 = ((double*) z -> data)[k3 + 2];
1114
1115    // Optimise for flat bed
1116    // Note (Ole): This didn't produce measurable speed up.
1117    // Revisit later
1118    //if (fabs(z0-z1)<epsilon && fabs(z1-z2)<epsilon) {
1119    //  continue;
1120    //}
1121
1122    // Get average depth from centroid values
1123    avg_h = ((double *) h -> data)[k];
1124
1125    // Compute bed slope
1126    k6 = 6*k;  // base index
1127 
1128    x0 = ((double*) x -> data)[k6 + 0];
1129    y0 = ((double*) x -> data)[k6 + 1];
1130    x1 = ((double*) x -> data)[k6 + 2];
1131    y1 = ((double*) x -> data)[k6 + 3];
1132    x2 = ((double*) x -> data)[k6 + 4];
1133    y2 = ((double*) x -> data)[k6 + 5];
1134
1135
1136    _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy);
1137
1138    // Update momentum
1139    ((double*) xmom -> data)[k] += -g*zx*avg_h;
1140    ((double*) ymom -> data)[k] += -g*zy*avg_h;
1141  }
1142
1143  return Py_BuildValue("");
1144}
1145
1146
1147PyObject *manning_friction_sloped(PyObject *self, PyObject *args) {
1148  //
1149  // manning_friction_sloped(g, eps, x, h, uh, vh, z, eta, xmom_update, ymom_update)
1150  //
1151
1152
1153  PyArrayObject *x, *w, *z, *uh, *vh, *eta, *xmom, *ymom;
1154  int N;
1155  double g, eps;
1156
1157  if (!PyArg_ParseTuple(args, "ddOOOOOOOO",
1158            &g, &eps, &x, &w, &uh, &vh, &z,  &eta, &xmom, &ymom)) {
1159      report_python_error(AT, "could not parse input arguments");
1160      return NULL;
1161  }
1162
1163  // check that numpy array objects arrays are C contiguous memory
1164  CHECK_C_CONTIG(x);
1165  CHECK_C_CONTIG(w);
1166  CHECK_C_CONTIG(z);
1167  CHECK_C_CONTIG(uh);
1168  CHECK_C_CONTIG(vh);
1169  CHECK_C_CONTIG(eta);
1170  CHECK_C_CONTIG(xmom);
1171  CHECK_C_CONTIG(ymom);
1172
1173  N = w -> dimensions[0];
1174
1175  _manning_friction_sloped(g, eps, N,
1176            (double*) x -> data,
1177            (double*) w -> data,
1178            (double*) z -> data,
1179            (double*) uh -> data,
1180            (double*) vh -> data,
1181            (double*) eta -> data,
1182            (double*) xmom -> data,
1183            (double*) ymom -> data);
1184
1185  return Py_BuildValue("");
1186}
1187
1188
1189PyObject *chezy_friction(PyObject *self, PyObject *args) {
1190  //
1191  // chezy_friction(g, eps, x, h, uh, vh, z, chezy, xmom_update, ymom_update)
1192  //
1193
1194
1195  PyArrayObject *x, *w, *z, *uh, *vh, *chezy, *xmom, *ymom;
1196  int N;
1197  double g, eps;
1198
1199  if (!PyArg_ParseTuple(args, "ddOOOOOOOO",
1200            &g, &eps, &x, &w, &uh, &vh, &z,  &chezy, &xmom, &ymom)) {
1201      report_python_error(AT, "could not parse input arguments");
1202      return NULL;
1203  }
1204
1205  // check that numpy array objects arrays are C contiguous memory
1206  CHECK_C_CONTIG(x);
1207  CHECK_C_CONTIG(w);
1208  CHECK_C_CONTIG(z);
1209  CHECK_C_CONTIG(uh);
1210  CHECK_C_CONTIG(vh);
1211  CHECK_C_CONTIG(chezy);
1212  CHECK_C_CONTIG(xmom);
1213  CHECK_C_CONTIG(ymom);
1214
1215  N = w -> dimensions[0];
1216
1217  _chezy_friction(g, eps, N,
1218            (double*) x -> data,
1219            (double*) w -> data,
1220            (double*) z -> data,
1221            (double*) uh -> data,
1222            (double*) vh -> data,
1223            (double*) chezy -> data,
1224            (double*) xmom -> data,
1225            (double*) ymom -> data);
1226
1227  return Py_BuildValue("");
1228}
1229
1230
1231PyObject *manning_friction_flat(PyObject *self, PyObject *args) {
1232  //
1233  // manning_friction_flat(g, eps, h, uh, vh, z, eta, xmom_update, ymom_update)
1234  //
1235
1236
1237  PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom;
1238  int N;
1239  double g, eps;
1240
1241  if (!PyArg_ParseTuple(args, "ddOOOOOOO",
1242            &g, &eps, &w, &uh, &vh, &z,  &eta, &xmom, &ymom)) {
1243      report_python_error(AT, "could not parse input arguments");
1244      return NULL;
1245  }
1246
1247  // check that numpy array objects arrays are C contiguous memory
1248  CHECK_C_CONTIG(w);
1249  CHECK_C_CONTIG(z);
1250  CHECK_C_CONTIG(uh);
1251  CHECK_C_CONTIG(vh);
1252  CHECK_C_CONTIG(eta);
1253  CHECK_C_CONTIG(xmom);
1254  CHECK_C_CONTIG(ymom);
1255
1256  N = w -> dimensions[0];
1257
1258  _manning_friction_flat(g, eps, N,
1259            (double*) w -> data,
1260            (double*) z -> data,
1261            (double*) uh -> data,
1262            (double*) vh -> data,
1263            (double*) eta -> data,
1264            (double*) xmom -> data,
1265            (double*) ymom -> data);
1266
1267  return Py_BuildValue("");
1268}
1269
1270
1271/*
1272PyObject *manning_friction_explicit(PyObject *self, PyObject *args) {
1273  //
1274  // manning_friction_explicit(g, eps, h, uh, vh, eta, xmom_update, ymom_update)
1275  //
1276
1277
1278  PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom;
1279  int N;
1280  double g, eps;
1281
1282  if (!PyArg_ParseTuple(args, "ddOOOOOOO",
1283            &g, &eps, &w, &z, &uh, &vh, &eta,
1284            &xmom, &ymom))
1285    return NULL;
1286
1287  // check that numpy array objects arrays are C contiguous memory
1288  CHECK_C_CONTIG(w);
1289  CHECK_C_CONTIG(z);
1290  CHECK_C_CONTIG(uh);
1291  CHECK_C_CONTIG(vh);
1292  CHECK_C_CONTIG(eta);
1293  CHECK_C_CONTIG(xmom);
1294  CHECK_C_CONTIG(ymom);
1295
1296  N = w -> dimensions[0];
1297  _manning_friction_explicit(g, eps, N,
1298            (double*) w -> data,
1299            (double*) z -> data,
1300            (double*) uh -> data,
1301            (double*) vh -> data,
1302            (double*) eta -> data,
1303            (double*) xmom -> data,
1304            (double*) ymom -> data);
1305
1306  return Py_BuildValue("");
1307}
1308*/
1309
1310
1311
1312// Computational routine
1313int _extrapolate_second_order_sw(int number_of_elements,
1314                                 double epsilon,
1315                                 double minimum_allowed_height,
1316                                 double beta_w,
1317                                 double beta_w_dry,
1318                                 double beta_uh,
1319                                 double beta_uh_dry,
1320                                 double beta_vh,
1321                                 double beta_vh_dry,
1322                                 long* surrogate_neighbours,
1323                                 long* number_of_boundaries,
1324                                 double* centroid_coordinates,
1325                                 double* stage_centroid_values,
1326                                 double* xmom_centroid_values,
1327                                 double* ymom_centroid_values,
1328                                 double* elevation_centroid_values,
1329                                 double* vertex_coordinates,
1330                                 double* stage_vertex_values,
1331                                 double* xmom_vertex_values,
1332                                 double* ymom_vertex_values,
1333                                 double* elevation_vertex_values,
1334                                 int optimise_dry_cells) {
1335                 
1336                 
1337
1338  // Local variables
1339  double a, b; // Gradient vector used to calculate vertex values from centroids
1340  int k, k0, k1, k2, k3, k6, coord_index, i;
1341  double x, y, x0, y0, x1, y1, x2, y2, xv0, yv0, xv1, yv1, xv2, yv2; // Vertices of the auxiliary triangle
1342  double dx1, dx2, dy1, dy2, dxv0, dxv1, dxv2, dyv0, dyv1, dyv2, dq0, dq1, dq2, area2, inv_area2;
1343  double dqv[3], qmin, qmax, hmin, hmax;
1344  double hc, h0, h1, h2, beta_tmp, hfactor;
1345
1346   
1347  for (k = 0; k < number_of_elements; k++) 
1348  {
1349    k3=k*3;
1350    k6=k*6;
1351
1352    if (number_of_boundaries[k]==3)
1353    {
1354      // No neighbours, set gradient on the triangle to zero
1355     
1356      stage_vertex_values[k3]   = stage_centroid_values[k];
1357      stage_vertex_values[k3+1] = stage_centroid_values[k];
1358      stage_vertex_values[k3+2] = stage_centroid_values[k];
1359      xmom_vertex_values[k3]    = xmom_centroid_values[k];
1360      xmom_vertex_values[k3+1]  = xmom_centroid_values[k];
1361      xmom_vertex_values[k3+2]  = xmom_centroid_values[k];
1362      ymom_vertex_values[k3]    = ymom_centroid_values[k];
1363      ymom_vertex_values[k3+1]  = ymom_centroid_values[k];
1364      ymom_vertex_values[k3+2]  = ymom_centroid_values[k];
1365     
1366      continue;
1367    }
1368    else 
1369    {
1370      // Triangle k has one or more neighbours.
1371      // Get centroid and vertex coordinates of the triangle
1372     
1373      // Get the vertex coordinates
1374      xv0 = vertex_coordinates[k6];   
1375      yv0 = vertex_coordinates[k6+1];
1376      xv1 = vertex_coordinates[k6+2]; 
1377      yv1 = vertex_coordinates[k6+3];
1378      xv2 = vertex_coordinates[k6+4]; 
1379      yv2 = vertex_coordinates[k6+5];
1380     
1381      // Get the centroid coordinates
1382      coord_index = 2*k;
1383      x = centroid_coordinates[coord_index];
1384      y = centroid_coordinates[coord_index+1];
1385     
1386      // Store x- and y- differentials for the vertices of
1387      // triangle k relative to the centroid
1388      dxv0 = xv0 - x; 
1389      dxv1 = xv1 - x; 
1390      dxv2 = xv2 - x;
1391      dyv0 = yv0 - y; 
1392      dyv1 = yv1 - y; 
1393      dyv2 = yv2 - y;
1394    }
1395
1396
1397           
1398    if (number_of_boundaries[k]<=1)
1399    {
1400      //==============================================
1401      // Number of boundaries <= 1
1402      //==============================================   
1403   
1404   
1405      // If no boundaries, auxiliary triangle is formed
1406      // from the centroids of the three neighbours
1407      // If one boundary, auxiliary triangle is formed
1408      // from this centroid and its two neighbours
1409     
1410      k0 = surrogate_neighbours[k3];
1411      k1 = surrogate_neighbours[k3 + 1];
1412      k2 = surrogate_neighbours[k3 + 2];
1413     
1414      // Get the auxiliary triangle's vertex coordinates
1415      // (really the centroids of neighbouring triangles)
1416      coord_index = 2*k0;
1417      x0 = centroid_coordinates[coord_index];
1418      y0 = centroid_coordinates[coord_index+1];
1419     
1420      coord_index = 2*k1;
1421      x1 = centroid_coordinates[coord_index];
1422      y1 = centroid_coordinates[coord_index+1];
1423     
1424      coord_index = 2*k2;
1425      x2 = centroid_coordinates[coord_index];
1426      y2 = centroid_coordinates[coord_index+1];
1427     
1428      // Store x- and y- differentials for the vertices
1429      // of the auxiliary triangle
1430      dx1 = x1 - x0; 
1431      dx2 = x2 - x0;
1432      dy1 = y1 - y0; 
1433      dy2 = y2 - y0;
1434     
1435      // Calculate 2*area of the auxiliary triangle
1436      // The triangle is guaranteed to be counter-clockwise     
1437      area2 = dy2*dx1 - dy1*dx2; 
1438     
1439      // If the mesh is 'weird' near the boundary,
1440      // the triangle might be flat or clockwise
1441      // Default to zero gradient
1442      if (area2 <= 0) 
1443      {
1444          //printf("Error negative triangle area \n");
1445          //report_python_error(AT, "Negative triangle area");
1446          //return -1;
1447
1448          stage_vertex_values[k3]   = stage_centroid_values[k];
1449          stage_vertex_values[k3+1] = stage_centroid_values[k];
1450          stage_vertex_values[k3+2] = stage_centroid_values[k];
1451          xmom_vertex_values[k3]    = xmom_centroid_values[k];
1452          xmom_vertex_values[k3+1]  = xmom_centroid_values[k];
1453          xmom_vertex_values[k3+2]  = xmom_centroid_values[k];
1454          ymom_vertex_values[k3]    = ymom_centroid_values[k];
1455          ymom_vertex_values[k3+1]  = ymom_centroid_values[k];
1456          ymom_vertex_values[k3+2]  = ymom_centroid_values[k];
1457
1458          continue;
1459      } 
1460     
1461      // Calculate heights of neighbouring cells
1462      hc = stage_centroid_values[k]  - elevation_centroid_values[k];
1463      h0 = stage_centroid_values[k0] - elevation_centroid_values[k0];
1464      h1 = stage_centroid_values[k1] - elevation_centroid_values[k1];
1465      h2 = stage_centroid_values[k2] - elevation_centroid_values[k2];
1466      hmin = min(min(h0, min(h1, h2)), hc);
1467      //hfactor = hc/(hc + 1.0);
1468
1469      hfactor = 0.0;
1470      if (hmin > 0.001) 
1471      {
1472        hfactor = (hmin - 0.001)/(hmin + 0.004);
1473      }
1474     
1475      if (optimise_dry_cells) 
1476      {     
1477        // Check if linear reconstruction is necessary for triangle k
1478        // This check will exclude dry cells.
1479
1480        hmax = max(h0, max(h1, h2));     
1481        if (hmax < epsilon) 
1482        {
1483            continue;
1484        }
1485      }
1486   
1487      //-----------------------------------
1488      // stage
1489      //-----------------------------------     
1490     
1491      // Calculate the difference between vertex 0 of the auxiliary
1492      // triangle and the centroid of triangle k
1493      dq0 = stage_centroid_values[k0] - stage_centroid_values[k];
1494     
1495      // Calculate differentials between the vertices
1496      // of the auxiliary triangle (centroids of neighbouring triangles)
1497      dq1 = stage_centroid_values[k1] - stage_centroid_values[k0];
1498      dq2 = stage_centroid_values[k2] - stage_centroid_values[k0];
1499     
1500      inv_area2 = 1.0/area2;
1501      // Calculate the gradient of stage on the auxiliary triangle
1502      a = dy2*dq1 - dy1*dq2;
1503      a *= inv_area2;
1504      b = dx1*dq2 - dx2*dq1;
1505      b *= inv_area2;
1506     
1507      // Calculate provisional jumps in stage from the centroid
1508      // of triangle k to its vertices, to be limited
1509      dqv[0] = a*dxv0 + b*dyv0;
1510      dqv[1] = a*dxv1 + b*dyv1;
1511      dqv[2] = a*dxv2 + b*dyv2;
1512     
1513      // Now we want to find min and max of the centroid and the
1514      // vertices of the auxiliary triangle and compute jumps
1515      // from the centroid to the min and max
1516      find_qmin_and_qmax(dq0, dq1, dq2, &qmin, &qmax);
1517     
1518      // Playing with dry wet interface
1519      //hmin = qmin;
1520      //beta_tmp = beta_w_dry;
1521      //if (hmin>minimum_allowed_height)
1522      beta_tmp = beta_w_dry + (beta_w - beta_w_dry) * hfactor;
1523   
1524      //printf("min_alled_height = %f\n",minimum_allowed_height);
1525      //printf("hmin = %f\n",hmin);
1526      //printf("beta_w = %f\n",beta_w);
1527      //printf("beta_tmp = %f\n",beta_tmp);
1528      // Limit the gradient
1529      limit_gradient(dqv, qmin, qmax, beta_tmp); 
1530     
1531      //for (i=0;i<3;i++)
1532      stage_vertex_values[k3+0] = stage_centroid_values[k] + dqv[0];
1533      stage_vertex_values[k3+1] = stage_centroid_values[k] + dqv[1];
1534      stage_vertex_values[k3+2] = stage_centroid_values[k] + dqv[2];
1535     
1536     
1537      //-----------------------------------
1538      // xmomentum
1539      //-----------------------------------           
1540
1541      // Calculate the difference between vertex 0 of the auxiliary
1542      // triangle and the centroid of triangle k     
1543      dq0 = xmom_centroid_values[k0] - xmom_centroid_values[k];
1544     
1545      // Calculate differentials between the vertices
1546      // of the auxiliary triangle
1547      dq1 = xmom_centroid_values[k1] - xmom_centroid_values[k0];
1548      dq2 = xmom_centroid_values[k2] - xmom_centroid_values[k0];
1549     
1550      // Calculate the gradient of xmom on the auxiliary triangle
1551      a = dy2*dq1 - dy1*dq2;
1552      a *= inv_area2;
1553      b = dx1*dq2 - dx2*dq1;
1554      b *= inv_area2;
1555     
1556      // Calculate provisional jumps in stage from the centroid
1557      // of triangle k to its vertices, to be limited     
1558      dqv[0] = a*dxv0+b*dyv0;
1559      dqv[1] = a*dxv1+b*dyv1;
1560      dqv[2] = a*dxv2+b*dyv2;
1561     
1562      // Now we want to find min and max of the centroid and the
1563      // vertices of the auxiliary triangle and compute jumps
1564      // from the centroid to the min and max
1565      find_qmin_and_qmax(dq0, dq1, dq2, &qmin, &qmax);
1566      //beta_tmp = beta_uh;
1567      //if (hmin<minimum_allowed_height)
1568      //beta_tmp = beta_uh_dry;
1569      beta_tmp = beta_uh_dry + (beta_uh - beta_uh_dry) * hfactor;
1570
1571      // Limit the gradient
1572      limit_gradient(dqv, qmin, qmax, beta_tmp);
1573
1574      for (i=0; i < 3; i++)
1575      {
1576        xmom_vertex_values[k3+i] = xmom_centroid_values[k] + dqv[i];
1577      }
1578     
1579      //-----------------------------------
1580      // ymomentum
1581      //-----------------------------------                 
1582
1583      // Calculate the difference between vertex 0 of the auxiliary
1584      // triangle and the centroid of triangle k
1585      dq0 = ymom_centroid_values[k0] - ymom_centroid_values[k];
1586     
1587      // Calculate differentials between the vertices
1588      // of the auxiliary triangle
1589      dq1 = ymom_centroid_values[k1] - ymom_centroid_values[k0];
1590      dq2 = ymom_centroid_values[k2] - ymom_centroid_values[k0];
1591     
1592      // Calculate the gradient of xmom on the auxiliary triangle
1593      a = dy2*dq1 - dy1*dq2;
1594      a *= inv_area2;
1595      b = dx1*dq2 - dx2*dq1;
1596      b *= inv_area2;
1597     
1598      // Calculate provisional jumps in stage from the centroid
1599      // of triangle k to its vertices, to be limited
1600      dqv[0] = a*dxv0 + b*dyv0;
1601      dqv[1] = a*dxv1 + b*dyv1;
1602      dqv[2] = a*dxv2 + b*dyv2;
1603     
1604      // Now we want to find min and max of the centroid and the
1605      // vertices of the auxiliary triangle and compute jumps
1606      // from the centroid to the min and max
1607      find_qmin_and_qmax(dq0, dq1, dq2, &qmin, &qmax);
1608     
1609      //beta_tmp = beta_vh;
1610      //
1611      //if (hmin<minimum_allowed_height)
1612      //beta_tmp = beta_vh_dry;
1613      beta_tmp = beta_vh_dry + (beta_vh - beta_vh_dry) * hfactor;   
1614
1615      // Limit the gradient
1616      limit_gradient(dqv, qmin, qmax, beta_tmp);
1617     
1618      for (i=0;i<3;i++)
1619      {
1620        ymom_vertex_values[k3 + i] = ymom_centroid_values[k] + dqv[i];
1621      }
1622    } // End number_of_boundaries <=1
1623    else
1624    {
1625
1626      //==============================================
1627      // Number of boundaries == 2
1628      //==============================================       
1629       
1630      // One internal neighbour and gradient is in direction of the neighbour's centroid
1631     
1632      // Find the only internal neighbour (k1?)
1633      for (k2 = k3; k2 < k3 + 3; k2++)
1634      {
1635      // Find internal neighbour of triangle k     
1636      // k2 indexes the edges of triangle k   
1637     
1638          if (surrogate_neighbours[k2] != k)
1639          {
1640             break;
1641          }
1642      }
1643     
1644      if ((k2 == k3 + 3)) 
1645      {
1646        // If we didn't find an internal neighbour
1647        report_python_error(AT, "Internal neighbour not found");
1648        return -1;
1649      }
1650     
1651      k1 = surrogate_neighbours[k2];
1652     
1653      // The coordinates of the triangle are already (x,y).
1654      // Get centroid of the neighbour (x1,y1)
1655      coord_index = 2*k1;
1656      x1 = centroid_coordinates[coord_index];
1657      y1 = centroid_coordinates[coord_index + 1];
1658     
1659      // Compute x- and y- distances between the centroid of
1660      // triangle k and that of its neighbour
1661      dx1 = x1 - x; 
1662      dy1 = y1 - y;
1663     
1664      // Set area2 as the square of the distance
1665      area2 = dx1*dx1 + dy1*dy1;
1666     
1667      // Set dx2=(x1-x0)/((x1-x0)^2+(y1-y0)^2)
1668      // and dy2=(y1-y0)/((x1-x0)^2+(y1-y0)^2) which
1669      // respectively correspond to the x- and y- gradients
1670      // of the conserved quantities
1671      dx2 = 1.0/area2;
1672      dy2 = dx2*dy1;
1673      dx2 *= dx1;
1674     
1675     
1676      //-----------------------------------
1677      // stage
1678      //-----------------------------------           
1679
1680      // Compute differentials
1681      dq1 = stage_centroid_values[k1] - stage_centroid_values[k];
1682     
1683      // Calculate the gradient between the centroid of triangle k
1684      // and that of its neighbour
1685      a = dq1*dx2;
1686      b = dq1*dy2;
1687     
1688      // Calculate provisional vertex jumps, to be limited
1689      dqv[0] = a*dxv0 + b*dyv0;
1690      dqv[1] = a*dxv1 + b*dyv1;
1691      dqv[2] = a*dxv2 + b*dyv2;
1692     
1693      // Now limit the jumps
1694      if (dq1>=0.0)
1695      {
1696        qmin=0.0;
1697        qmax=dq1;
1698      }
1699      else
1700      {
1701        qmin = dq1;
1702        qmax = 0.0;
1703      }
1704     
1705      // Limit the gradient
1706      limit_gradient(dqv, qmin, qmax, beta_w);
1707     
1708      //for (i=0; i < 3; i++)
1709      //{
1710      stage_vertex_values[k3] = stage_centroid_values[k] + dqv[0];
1711      stage_vertex_values[k3 + 1] = stage_centroid_values[k] + dqv[1];
1712      stage_vertex_values[k3 + 2] = stage_centroid_values[k] + dqv[2];
1713      //}
1714     
1715      //-----------------------------------
1716      // xmomentum
1717      //-----------------------------------                       
1718     
1719      // Compute differentials
1720      dq1 = xmom_centroid_values[k1] - xmom_centroid_values[k];
1721     
1722      // Calculate the gradient between the centroid of triangle k
1723      // and that of its neighbour
1724      a = dq1*dx2;
1725      b = dq1*dy2;
1726     
1727      // Calculate provisional vertex jumps, to be limited
1728      dqv[0] = a*dxv0+b*dyv0;
1729      dqv[1] = a*dxv1+b*dyv1;
1730      dqv[2] = a*dxv2+b*dyv2;
1731     
1732      // Now limit the jumps
1733      if (dq1 >= 0.0)
1734      {
1735        qmin = 0.0;
1736        qmax = dq1;
1737      }
1738      else
1739      {
1740        qmin = dq1;
1741        qmax = 0.0;
1742      }
1743     
1744      // Limit the gradient     
1745      limit_gradient(dqv, qmin, qmax, beta_w);
1746     
1747      //for (i=0;i<3;i++)
1748      //xmom_vertex_values[k3] = xmom_centroid_values[k] + dqv[0];
1749      //xmom_vertex_values[k3 + 1] = xmom_centroid_values[k] + dqv[1];
1750      //xmom_vertex_values[k3 + 2] = xmom_centroid_values[k] + dqv[2];
1751     
1752      for (i = 0; i < 3;i++)
1753      {
1754          xmom_vertex_values[k3 + i] = xmom_centroid_values[k] + dqv[i];
1755      }
1756     
1757      //-----------------------------------
1758      // ymomentum
1759      //-----------------------------------                       
1760
1761      // Compute differentials
1762      dq1 = ymom_centroid_values[k1] - ymom_centroid_values[k];
1763     
1764      // Calculate the gradient between the centroid of triangle k
1765      // and that of its neighbour
1766      a = dq1*dx2;
1767      b = dq1*dy2;
1768     
1769      // Calculate provisional vertex jumps, to be limited
1770      dqv[0] = a*dxv0 + b*dyv0;
1771      dqv[1] = a*dxv1 + b*dyv1;
1772      dqv[2] = a*dxv2 + b*dyv2;
1773     
1774      // Now limit the jumps
1775      if (dq1>=0.0)
1776      {
1777        qmin = 0.0;
1778        qmax = dq1;
1779      } 
1780      else
1781      {
1782        qmin = dq1;
1783        qmax = 0.0;
1784      }
1785     
1786      // Limit the gradient
1787      limit_gradient(dqv, qmin, qmax, beta_w);
1788     
1789      //for (i=0;i<3;i++)
1790      //ymom_vertex_values[k3] = ymom_centroid_values[k] + dqv[0];
1791      //ymom_vertex_values[k3 + 1] = ymom_centroid_values[k] + dqv[1];
1792      //ymom_vertex_values[k3 + 2] = ymom_centroid_values[k] + dqv[2];
1793
1794for (i=0;i<3;i++)
1795        {
1796ymom_vertex_values[k3 + i] = ymom_centroid_values[k] + dqv[i];
1797        }
1798//ymom_vertex_values[k3] = ymom_centroid_values[k] + dqv[0];
1799//ymom_vertex_values[k3 + 1] = ymom_centroid_values[k] + dqv[1];
1800//ymom_vertex_values[k3 + 2] = ymom_centroid_values[k] + dqv[2];
1801    } // else [number_of_boundaries==2]
1802  } // for k=0 to number_of_elements-1
1803 
1804  return 0;
1805}           
1806
1807
1808PyObject *extrapolate_second_order_sw(PyObject *self, PyObject *args) {
1809  /*Compute the vertex values based on a linear reconstruction
1810    on each triangle
1811   
1812    These values are calculated as follows:
1813    1) For each triangle not adjacent to a boundary, we consider the
1814       auxiliary triangle formed by the centroids of its three
1815       neighbours.
1816    2) For each conserved quantity, we integrate around the auxiliary
1817       triangle's boundary the product of the quantity and the outward
1818       normal vector. Dividing by the triangle area gives (a,b), the
1819       average of the vector (q_x,q_y) on the auxiliary triangle.
1820       We suppose that the linear reconstruction on the original
1821       triangle has gradient (a,b).
1822    3) Provisional vertex jumps dqv[0,1,2] are computed and these are
1823       then limited by calling the functions find_qmin_and_qmax and
1824       limit_gradient
1825
1826    Python call:
1827    extrapolate_second_order_sw(domain.surrogate_neighbours,
1828                                domain.number_of_boundaries
1829                                domain.centroid_coordinates,
1830                                Stage.centroid_values
1831                                Xmom.centroid_values
1832                                Ymom.centroid_values
1833                                domain.vertex_coordinates,
1834                                Stage.vertex_values,
1835                                Xmom.vertex_values,
1836                                Ymom.vertex_values)
1837
1838    Post conditions:
1839            The vertices of each triangle have values from a
1840        limited linear reconstruction
1841        based on centroid values
1842
1843  */
1844  PyArrayObject *surrogate_neighbours,
1845    *number_of_boundaries,
1846    *centroid_coordinates,
1847    *stage_centroid_values,
1848    *xmom_centroid_values,
1849    *ymom_centroid_values,
1850    *elevation_centroid_values,
1851    *vertex_coordinates,
1852    *stage_vertex_values,
1853    *xmom_vertex_values,
1854    *ymom_vertex_values,
1855    *elevation_vertex_values;
1856 
1857  PyObject *domain;
1858
1859 
1860  double beta_w, beta_w_dry, beta_uh, beta_uh_dry, beta_vh, beta_vh_dry;   
1861  double minimum_allowed_height, epsilon;
1862  int optimise_dry_cells, number_of_elements, e;
1863 
1864  // Provisional jumps from centroids to v'tices and safety factor re limiting
1865  // by which these jumps are limited
1866  // Convert Python arguments to C
1867  if (!PyArg_ParseTuple(args, "OOOOOOOOOOOOOi",
1868            &domain,
1869            &surrogate_neighbours,
1870            &number_of_boundaries,
1871            &centroid_coordinates,
1872            &stage_centroid_values,
1873            &xmom_centroid_values,
1874            &ymom_centroid_values,
1875            &elevation_centroid_values,
1876            &vertex_coordinates,
1877            &stage_vertex_values,
1878            &xmom_vertex_values,
1879            &ymom_vertex_values,
1880            &elevation_vertex_values,
1881            &optimise_dry_cells)) {         
1882
1883    report_python_error(AT, "could not parse input arguments");
1884    return NULL;
1885  }
1886
1887  // check that numpy array objects arrays are C contiguous memory
1888  CHECK_C_CONTIG(surrogate_neighbours);
1889  CHECK_C_CONTIG(number_of_boundaries);
1890  CHECK_C_CONTIG(centroid_coordinates);
1891  CHECK_C_CONTIG(stage_centroid_values);
1892  CHECK_C_CONTIG(xmom_centroid_values);
1893  CHECK_C_CONTIG(ymom_centroid_values);
1894  CHECK_C_CONTIG(elevation_centroid_values);
1895  CHECK_C_CONTIG(vertex_coordinates);
1896  CHECK_C_CONTIG(stage_vertex_values);
1897  CHECK_C_CONTIG(xmom_vertex_values);
1898  CHECK_C_CONTIG(ymom_vertex_values);
1899  CHECK_C_CONTIG(elevation_vertex_values);
1900 
1901  // Get the safety factor beta_w, set in the config.py file.
1902  // This is used in the limiting process
1903 
1904
1905  beta_w                 = get_python_double(domain,"beta_w");
1906  beta_w_dry             = get_python_double(domain,"beta_w_dry");
1907  beta_uh                = get_python_double(domain,"beta_uh");
1908  beta_uh_dry            = get_python_double(domain,"beta_uh_dry");
1909  beta_vh                = get_python_double(domain,"beta_vh");
1910  beta_vh_dry            = get_python_double(domain,"beta_vh_dry"); 
1911
1912  minimum_allowed_height = get_python_double(domain,"minimum_allowed_height");
1913  epsilon                = get_python_double(domain,"epsilon");
1914
1915  number_of_elements = stage_centroid_values -> dimensions[0]; 
1916
1917  // Call underlying computational routine
1918  e = _extrapolate_second_order_sw(number_of_elements,
1919                   epsilon,
1920                   minimum_allowed_height,
1921                   beta_w,
1922                   beta_w_dry,
1923                   beta_uh,
1924                   beta_uh_dry,
1925                   beta_vh,
1926                   beta_vh_dry,
1927                   (long*) surrogate_neighbours -> data,
1928                   (long*) number_of_boundaries -> data,
1929                   (double*) centroid_coordinates -> data,
1930                   (double*) stage_centroid_values -> data,
1931                   (double*) xmom_centroid_values -> data,
1932                   (double*) ymom_centroid_values -> data,
1933                   (double*) elevation_centroid_values -> data,
1934                   (double*) vertex_coordinates -> data,
1935                   (double*) stage_vertex_values -> data,
1936                   (double*) xmom_vertex_values -> data,
1937                   (double*) ymom_vertex_values -> data,
1938                   (double*) elevation_vertex_values -> data,
1939                   optimise_dry_cells);
1940  if (e == -1) {
1941    // Use error string set inside computational routine
1942    return NULL;
1943  }                   
1944 
1945 
1946  return Py_BuildValue("");
1947 
1948}// extrapolate_second-order_sw
1949
1950
1951
1952
1953PyObject *rotate(PyObject *self, PyObject *args, PyObject *kwargs) {
1954  //
1955  // r = rotate(q, normal, direction=1)
1956  //
1957  // Where q is assumed to be a Float numeric array of length 3 and
1958  // normal a Float numeric array of length 2.
1959
1960  // FIXME(Ole): I don't think this is used anymore
1961
1962  PyObject *Q, *Normal;
1963  PyArrayObject *q, *r, *normal;
1964
1965  static char *argnames[] = {"q", "normal", "direction", NULL};
1966  int dimensions[1], i, direction=1;
1967  double n1, n2;
1968
1969  // Convert Python arguments to C
1970  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames,
1971                   &Q, &Normal, &direction)) {
1972    report_python_error(AT, "could not parse input arguments");
1973    return NULL;
1974  } 
1975
1976  // Input checks (convert sequences into numeric arrays)
1977  q = (PyArrayObject *)
1978    PyArray_ContiguousFromObject(Q, PyArray_DOUBLE, 0, 0);
1979  normal = (PyArrayObject *)
1980    PyArray_ContiguousFromObject(Normal, PyArray_DOUBLE, 0, 0);
1981
1982
1983  if (normal -> dimensions[0] != 2) {
1984    report_python_error(AT, "Normal vector must have 2 components");
1985    return NULL;
1986  }
1987
1988  // Allocate space for return vector r (don't DECREF)
1989  dimensions[0] = 3;
1990  r = (PyArrayObject *) anuga_FromDims(1, dimensions, PyArray_DOUBLE);
1991
1992  // Copy
1993  for (i=0; i<3; i++) {
1994    ((double *) (r -> data))[i] = ((double *) (q -> data))[i];
1995  }
1996
1997  // Get normal and direction
1998  n1 = ((double *) normal -> data)[0];
1999  n2 = ((double *) normal -> data)[1];
2000  if (direction == -1) n2 = -n2;
2001
2002  // Rotate
2003  _rotate((double *) r -> data, n1, n2);
2004
2005  // Release numeric arrays
2006  Py_DECREF(q);
2007  Py_DECREF(normal);
2008
2009  // Return result using PyArray to avoid memory leak
2010  return PyArray_Return(r);
2011}
2012
2013
2014// Computational function for flux computation
2015
2016double _compute_fluxes_central(int number_of_elements,
2017        double timestep,
2018        double epsilon,
2019        double H0,
2020        double g,
2021        long* neighbours,
2022        long* neighbour_edges,
2023        double* normals,
2024        double* edgelengths,
2025        double* radii,
2026        double* areas,
2027        long* tri_full_flag,
2028        double* stage_edge_values,
2029        double* xmom_edge_values,
2030        double* ymom_edge_values,
2031        double* bed_edge_values,
2032        double* stage_boundary_values,
2033        double* xmom_boundary_values,
2034        double* ymom_boundary_values,
2035        double* stage_explicit_update,
2036        double* xmom_explicit_update,
2037        double* ymom_explicit_update,
2038        long* already_computed_flux,
2039        double* max_speed_array,
2040        int optimise_dry_cells) {
2041    // Local variables
2042    double max_speed, length, inv_area, zl, zr;
2043    double h0 = H0*H0; // This ensures a good balance when h approaches H0.
2044
2045    double limiting_threshold = 10 * H0; // Avoid applying limiter below this
2046    // threshold for performance reasons.
2047    // See ANUGA manual under flux limiting
2048    int k, i, m, n;
2049    int ki, nm = 0, ki2; // Index shorthands
2050
2051
2052    // Workspace (making them static actually made function slightly slower (Ole))
2053    double ql[3], qr[3], edgeflux[3]; // Work array for summing up fluxes
2054
2055    static long call = 1; // Static local variable flagging already computed flux
2056
2057    // Start computation
2058    call++; // Flag 'id' of flux calculation for this timestep
2059
2060    // Set explicit_update to zero for all conserved_quantities.
2061    // This assumes compute_fluxes called before forcing terms
2062    memset((char*) stage_explicit_update, 0, number_of_elements * sizeof (double));
2063    memset((char*) xmom_explicit_update, 0, number_of_elements * sizeof (double));
2064    memset((char*) ymom_explicit_update, 0, number_of_elements * sizeof (double));
2065
2066    // For all triangles
2067    for (k = 0; k < number_of_elements; k++) {
2068        // Loop through neighbours and compute edge flux for each
2069        for (i = 0; i < 3; i++) {
2070            ki = k * 3 + i; // Linear index to edge i of triangle k
2071
2072            if (already_computed_flux[ki] == call) {
2073                // We've already computed the flux across this edge
2074                continue;
2075            }
2076
2077            // Get left hand side values from triangle k, edge i
2078            ql[0] = stage_edge_values[ki];
2079            ql[1] = xmom_edge_values[ki];
2080            ql[2] = ymom_edge_values[ki];
2081            zl = bed_edge_values[ki];
2082
2083            // Get right hand side values either from neighbouring triangle
2084            // or from boundary array (Quantities at neighbour on nearest face).
2085            n = neighbours[ki];
2086            if (n < 0) {
2087                // Neighbour is a boundary condition
2088                m = -n - 1; // Convert negative flag to boundary index
2089
2090                qr[0] = stage_boundary_values[m];
2091                qr[1] = xmom_boundary_values[m];
2092                qr[2] = ymom_boundary_values[m];
2093                zr = zl; // Extend bed elevation to boundary
2094            }
2095            else {
2096                // Neighbour is a real triangle
2097                m = neighbour_edges[ki];
2098                nm = n * 3 + m; // Linear index (triangle n, edge m)
2099
2100                qr[0] = stage_edge_values[nm];
2101                qr[1] = xmom_edge_values[nm];
2102                qr[2] = ymom_edge_values[nm];
2103                zr = bed_edge_values[nm];
2104            }
2105
2106            // Now we have values for this edge - both from left and right side.
2107
2108            if (optimise_dry_cells) {
2109                // Check if flux calculation is necessary across this edge
2110                // This check will exclude dry cells.
2111                // This will also optimise cases where zl != zr as
2112                // long as both are dry
2113
2114                if (fabs(ql[0] - zl) < epsilon &&
2115                        fabs(qr[0] - zr) < epsilon) {
2116                    // Cell boundary is dry
2117
2118                    already_computed_flux[ki] = call; // #k Done
2119                    if (n >= 0) {
2120                        already_computed_flux[nm] = call; // #n Done
2121                    }
2122
2123                    max_speed = 0.0;
2124                    continue;
2125                }
2126            }
2127
2128
2129            if (fabs(zl-zr)>1.0e-10) {
2130                report_python_error(AT,"Discontinuous Elevation");
2131                return 0.0;
2132            }
2133           
2134            // Outward pointing normal vector (domain.normals[k, 2*i:2*i+2])
2135            ki2 = 2 * ki; //k*6 + i*2
2136
2137            // Edge flux computation (triangle k, edge i)
2138            _flux_function_central(ql, qr, zl, zr,
2139                    normals[ki2], normals[ki2 + 1],
2140                    epsilon, h0, limiting_threshold, g,
2141                    edgeflux, &max_speed);
2142
2143
2144            // Multiply edgeflux by edgelength
2145            length = edgelengths[ki];
2146            edgeflux[0] *= length;
2147            edgeflux[1] *= length;
2148            edgeflux[2] *= length;
2149
2150
2151            // Update triangle k with flux from edge i
2152            stage_explicit_update[k] -= edgeflux[0];
2153            xmom_explicit_update[k] -= edgeflux[1];
2154            ymom_explicit_update[k] -= edgeflux[2];
2155
2156            already_computed_flux[ki] = call; // #k Done
2157
2158
2159            // Update neighbour n with same flux but reversed sign
2160            if (n >= 0) {
2161                stage_explicit_update[n] += edgeflux[0];
2162                xmom_explicit_update[n] += edgeflux[1];
2163                ymom_explicit_update[n] += edgeflux[2];
2164
2165                already_computed_flux[nm] = call; // #n Done
2166            }
2167
2168            // Update timestep based on edge i and possibly neighbour n
2169            if (tri_full_flag[k] == 1) {
2170                if (max_speed > epsilon) {
2171                    // Apply CFL condition for triangles joining this edge (triangle k and triangle n)
2172
2173                    // CFL for triangle k
2174                    timestep = min(timestep, radii[k] / max_speed);
2175
2176                    if (n >= 0) {
2177                        // Apply CFL condition for neigbour n (which is on the ith edge of triangle k)
2178                        timestep = min(timestep, radii[n] / max_speed);
2179                    }
2180
2181                    // Ted Rigby's suggested less conservative version
2182                    //if (n>=0) {
2183                    //  timestep = min(timestep, (radii[k]+radii[n])/max_speed);
2184                    //} else {
2185                    //  timestep = min(timestep, radii[k]/max_speed);
2186                    // }
2187                }
2188            }
2189
2190        } // End edge i (and neighbour n)
2191
2192
2193        // Normalise triangle k by area and store for when all conserved
2194        // quantities get updated
2195        inv_area = 1.0 / areas[k];
2196        stage_explicit_update[k] *= inv_area;
2197        xmom_explicit_update[k] *= inv_area;
2198        ymom_explicit_update[k] *= inv_area;
2199
2200
2201        // Keep track of maximal speeds
2202        max_speed_array[k] = max_speed;
2203
2204    } // End triangle k
2205
2206    return timestep;
2207}
2208
2209//=========================================================================
2210// Python Glue
2211//=========================================================================
2212
2213PyObject *compute_fluxes_ext_central_new(PyObject *self, PyObject *args) {
2214  /*Compute all fluxes and the timestep suitable for all volumes
2215    in domain.
2216
2217    Compute total flux for each conserved quantity using "flux_function_central"
2218
2219    Fluxes across each edge are scaled by edgelengths and summed up
2220    Resulting flux is then scaled by area and stored in
2221    explicit_update for each of the three conserved quantities
2222    stage, xmomentum and ymomentum
2223
2224    The maximal allowable speed computed by the flux_function for each volume
2225    is converted to a timestep that must not be exceeded. The minimum of
2226    those is computed as the next overall timestep.
2227
2228    Python call:
2229    timestep = compute_fluxes(timestep, domain, stage, xmom, ymom, bed)
2230
2231
2232    Post conditions:
2233      domain.explicit_update is reset to computed flux values
2234      returns timestep which is the largest step satisfying all volumes.
2235
2236
2237  */
2238
2239    PyObject
2240    *domain,
2241    *stage, 
2242    *xmom, 
2243    *ymom, 
2244    *bed;
2245
2246    PyArrayObject
2247    *neighbours, 
2248    *neighbour_edges,
2249    *normals, 
2250    *edgelengths, 
2251    *radii, 
2252    *areas,
2253    *tri_full_flag,
2254    *stage_edge_values,
2255    *xmom_edge_values,
2256    *ymom_edge_values,
2257    *bed_edge_values,
2258    *stage_boundary_values,
2259    *xmom_boundary_values,
2260    *ymom_boundary_values,
2261    *stage_explicit_update,
2262    *xmom_explicit_update,
2263    *ymom_explicit_update,
2264    *already_computed_flux, //Tracks whether the flux across an edge has already been computed
2265    *max_speed_array; //Keeps track of max speeds for each triangle
2266
2267   
2268    double timestep, epsilon, H0, g;
2269    int optimise_dry_cells;
2270   
2271    // Convert Python arguments to C
2272    if (!PyArg_ParseTuple(args, "dOOOO", &timestep, &domain, &stage, &xmom, &ymom, &bed )) {
2273      report_python_error(AT, "could not parse input arguments");
2274      return NULL;
2275    }
2276
2277    epsilon           = get_python_double(domain,"epsilon");
2278    H0                = get_python_double(domain,"H0");
2279    g                 = get_python_double(domain,"g");
2280    optimise_dry_cells = get_python_integer(domain,"optimse_dry_cells");
2281   
2282    neighbours        = get_consecutive_array(domain, "neighbours");
2283    neighbour_edges   = get_consecutive_array(domain, "neighbour_edges"); 
2284    normals           = get_consecutive_array(domain, "normals");
2285    edgelengths       = get_consecutive_array(domain, "edge_lengths");   
2286    radii             = get_consecutive_array(domain, "radii");   
2287    areas             = get_consecutive_array(domain, "areas");   
2288    tri_full_flag     = get_consecutive_array(domain, "tri_full_flag");
2289    already_computed_flux  = get_consecutive_array(domain, "already_computed_flux");
2290    max_speed_array   = get_consecutive_array(domain, "max_speed");
2291   
2292    stage_edge_values = get_consecutive_array(stage, "edge_values");   
2293    xmom_edge_values  = get_consecutive_array(xmom, "edge_values");   
2294    ymom_edge_values  = get_consecutive_array(ymom, "edge_values"); 
2295    bed_edge_values   = get_consecutive_array(bed, "edge_values");   
2296
2297    stage_boundary_values = get_consecutive_array(stage, "boundary_values");   
2298    xmom_boundary_values  = get_consecutive_array(xmom, "boundary_values");   
2299    ymom_boundary_values  = get_consecutive_array(ymom, "boundary_values"); 
2300
2301    stage_explicit_update = get_consecutive_array(stage, "explicit_update");   
2302    xmom_explicit_update  = get_consecutive_array(xmom, "explicit_update");   
2303    ymom_explicit_update  = get_consecutive_array(ymom, "explicit_update"); 
2304
2305
2306  int number_of_elements = stage_edge_values -> dimensions[0];
2307
2308  // Call underlying flux computation routine and update
2309  // the explicit update arrays
2310  timestep = _compute_fluxes_central(number_of_elements,
2311                     timestep,
2312                     epsilon,
2313                     H0,
2314                     g,
2315                     (long*) neighbours -> data,
2316                     (long*) neighbour_edges -> data,
2317                     (double*) normals -> data,
2318                     (double*) edgelengths -> data, 
2319                     (double*) radii -> data, 
2320                     (double*) areas -> data,
2321                     (long*) tri_full_flag -> data,
2322                     (double*) stage_edge_values -> data,
2323                     (double*) xmom_edge_values -> data,
2324                     (double*) ymom_edge_values -> data,
2325                     (double*) bed_edge_values -> data,
2326                     (double*) stage_boundary_values -> data,
2327                     (double*) xmom_boundary_values -> data,
2328                     (double*) ymom_boundary_values -> data,
2329                     (double*) stage_explicit_update -> data,
2330                     (double*) xmom_explicit_update -> data,
2331                     (double*) ymom_explicit_update -> data,
2332                     (long*) already_computed_flux -> data,
2333                     (double*) max_speed_array -> data,
2334                     optimise_dry_cells);
2335
2336  Py_DECREF(neighbours);
2337  Py_DECREF(neighbour_edges);
2338  Py_DECREF(normals);
2339  Py_DECREF(edgelengths);
2340  Py_DECREF(radii);
2341  Py_DECREF(areas);
2342  Py_DECREF(tri_full_flag);
2343  Py_DECREF(already_computed_flux);
2344  Py_DECREF(max_speed_array);
2345  Py_DECREF(stage_edge_values);
2346  Py_DECREF(xmom_edge_values);
2347  Py_DECREF(ymom_edge_values);
2348  Py_DECREF(bed_edge_values);
2349  Py_DECREF(stage_boundary_values);
2350  Py_DECREF(xmom_boundary_values);
2351  Py_DECREF(ymom_boundary_values);
2352  Py_DECREF(stage_explicit_update);
2353  Py_DECREF(xmom_explicit_update);
2354  Py_DECREF(ymom_explicit_update);
2355
2356 
2357  // Return updated flux timestep
2358  return Py_BuildValue("d", timestep);
2359}
2360
2361
2362
2363
2364
2365
2366PyObject *compute_fluxes_ext_central(PyObject *self, PyObject *args) {
2367  /*Compute all fluxes and the timestep suitable for all volumes
2368    in domain.
2369
2370    Compute total flux for each conserved quantity using "flux_function_central"
2371
2372    Fluxes across each edge are scaled by edgelengths and summed up
2373    Resulting flux is then scaled by area and stored in
2374    explicit_update for each of the three conserved quantities
2375    stage, xmomentum and ymomentum
2376
2377    The maximal allowable speed computed by the flux_function for each volume
2378    is converted to a timestep that must not be exceeded. The minimum of
2379    those is computed as the next overall timestep.
2380
2381    Python call:
2382    domain.timestep = compute_fluxes(timestep,
2383                                     domain.epsilon,
2384                     domain.H0,
2385                                     domain.g,
2386                                     domain.neighbours,
2387                                     domain.neighbour_edges,
2388                                     domain.normals,
2389                                     domain.edgelengths,
2390                                     domain.radii,
2391                                     domain.areas,
2392                                     tri_full_flag,
2393                                     Stage.edge_values,
2394                                     Xmom.edge_values,
2395                                     Ymom.edge_values,
2396                                     Bed.edge_values,
2397                                     Stage.boundary_values,
2398                                     Xmom.boundary_values,
2399                                     Ymom.boundary_values,
2400                                     Stage.explicit_update,
2401                                     Xmom.explicit_update,
2402                                     Ymom.explicit_update,
2403                                     already_computed_flux,
2404                     optimise_dry_cells)                     
2405
2406
2407    Post conditions:
2408      domain.explicit_update is reset to computed flux values
2409      domain.timestep is set to the largest step satisfying all volumes.
2410
2411
2412  */
2413
2414
2415  PyArrayObject *neighbours, *neighbour_edges,
2416    *normals, *edgelengths, *radii, *areas,
2417    *tri_full_flag,
2418    *stage_edge_values,
2419    *xmom_edge_values,
2420    *ymom_edge_values,
2421    *bed_edge_values,
2422    *stage_boundary_values,
2423    *xmom_boundary_values,
2424    *ymom_boundary_values,
2425    *stage_explicit_update,
2426    *xmom_explicit_update,
2427    *ymom_explicit_update,
2428    *already_computed_flux, //Tracks whether the flux across an edge has already been computed
2429    *max_speed_array; //Keeps track of max speeds for each triangle
2430
2431   
2432  double timestep, epsilon, H0, g;
2433  int optimise_dry_cells;
2434   
2435  // Convert Python arguments to C
2436  if (!PyArg_ParseTuple(args, "ddddOOOOOOOOOOOOOOOOOOOi",
2437            &timestep,
2438            &epsilon,
2439            &H0,
2440            &g,
2441            &neighbours,
2442            &neighbour_edges,
2443            &normals,
2444            &edgelengths, &radii, &areas,
2445            &tri_full_flag,
2446            &stage_edge_values,
2447            &xmom_edge_values,
2448            &ymom_edge_values,
2449            &bed_edge_values,
2450            &stage_boundary_values,
2451            &xmom_boundary_values,
2452            &ymom_boundary_values,
2453            &stage_explicit_update,
2454            &xmom_explicit_update,
2455            &ymom_explicit_update,
2456            &already_computed_flux,
2457            &max_speed_array,
2458            &optimise_dry_cells)) {
2459    report_python_error(AT, "could not parse input arguments");
2460    return NULL;
2461  }
2462
2463  // check that numpy array objects arrays are C contiguous memory
2464  CHECK_C_CONTIG(neighbours);
2465  CHECK_C_CONTIG(neighbour_edges);
2466  CHECK_C_CONTIG(normals);
2467  CHECK_C_CONTIG(edgelengths);
2468  CHECK_C_CONTIG(radii);
2469  CHECK_C_CONTIG(areas);
2470  CHECK_C_CONTIG(tri_full_flag);
2471  CHECK_C_CONTIG(stage_edge_values);
2472  CHECK_C_CONTIG(xmom_edge_values);
2473  CHECK_C_CONTIG(ymom_edge_values);
2474  CHECK_C_CONTIG(bed_edge_values);
2475  CHECK_C_CONTIG(stage_boundary_values);
2476  CHECK_C_CONTIG(xmom_boundary_values);
2477  CHECK_C_CONTIG(ymom_boundary_values);
2478  CHECK_C_CONTIG(stage_explicit_update);
2479  CHECK_C_CONTIG(xmom_explicit_update);
2480  CHECK_C_CONTIG(ymom_explicit_update);
2481  CHECK_C_CONTIG(already_computed_flux);
2482  CHECK_C_CONTIG(max_speed_array);
2483
2484  int number_of_elements = stage_edge_values -> dimensions[0];
2485
2486  // Call underlying flux computation routine and update
2487  // the explicit update arrays
2488  timestep = _compute_fluxes_central(number_of_elements,
2489                     timestep,
2490                     epsilon,
2491                     H0,
2492                     g,
2493                     (long*) neighbours -> data,
2494                     (long*) neighbour_edges -> data,
2495                     (double*) normals -> data,
2496                     (double*) edgelengths -> data, 
2497                     (double*) radii -> data, 
2498                     (double*) areas -> data,
2499                     (long*) tri_full_flag -> data,
2500                     (double*) stage_edge_values -> data,
2501                     (double*) xmom_edge_values -> data,
2502                     (double*) ymom_edge_values -> data,
2503                     (double*) bed_edge_values -> data,
2504                     (double*) stage_boundary_values -> data,
2505                     (double*) xmom_boundary_values -> data,
2506                     (double*) ymom_boundary_values -> data,
2507                     (double*) stage_explicit_update -> data,
2508                     (double*) xmom_explicit_update -> data,
2509                     (double*) ymom_explicit_update -> data,
2510                     (long*) already_computed_flux -> data,
2511                     (double*) max_speed_array -> data,
2512                     optimise_dry_cells);
2513 
2514  // Return updated flux timestep
2515  return Py_BuildValue("d", timestep);
2516}
2517
2518
2519
2520
2521
2522PyObject *compute_fluxes_ext_kinetic(PyObject *self, PyObject *args) {
2523  /*Compute all fluxes and the timestep suitable for all volumes
2524    in domain.
2525
2526    THIS IS AN EXPERIMENTAL FUNCTION - NORMALLY flux_function_central IS USED.
2527   
2528    Compute total flux for each conserved quantity using "flux_function_kinetic"
2529
2530    Fluxes across each edge are scaled by edgelengths and summed up
2531    Resulting flux is then scaled by area and stored in
2532    explicit_update for each of the three conserved quantities
2533    stage, xmomentum and ymomentum
2534
2535    The maximal allowable speed computed by the flux_function for each volume
2536    is converted to a timestep that must not be exceeded. The minimum of
2537    those is computed as the next overall timestep.
2538
2539    Python call:
2540    domain.timestep = compute_fluxes(timestep,
2541                                     domain.epsilon,
2542                                     domain.H0,
2543                                     domain.g,
2544                                     domain.neighbours,
2545                                     domain.neighbour_edges,
2546                                     domain.normals,
2547                                     domain.edgelengths,
2548                                     domain.radii,
2549                                     domain.areas,
2550                                     Stage.edge_values,
2551                                     Xmom.edge_values,
2552                                     Ymom.edge_values,
2553                                     Bed.edge_values,
2554                                     Stage.boundary_values,
2555                                     Xmom.boundary_values,
2556                                     Ymom.boundary_values,
2557                                     Stage.explicit_update,
2558                                     Xmom.explicit_update,
2559                                     Ymom.explicit_update,
2560                                     already_computed_flux)
2561
2562
2563    Post conditions:
2564      domain.explicit_update is reset to computed flux values
2565      domain.timestep is set to the largest step satisfying all volumes.
2566
2567
2568  */
2569
2570
2571  PyArrayObject *neighbours, *neighbour_edges,
2572    *normals, *edgelengths, *radii, *areas,
2573    *tri_full_flag,
2574    *stage_edge_values,
2575    *xmom_edge_values,
2576    *ymom_edge_values,
2577    *bed_edge_values,
2578    *stage_boundary_values,
2579    *xmom_boundary_values,
2580    *ymom_boundary_values,
2581    *stage_explicit_update,
2582    *xmom_explicit_update,
2583    *ymom_explicit_update,
2584    *already_computed_flux; // Tracks whether the flux across an edge has already been computed
2585
2586
2587  // Local variables
2588  double timestep, max_speed, epsilon, g, H0;
2589  double normal[2], ql[3], qr[3], zl, zr;
2590  double edgeflux[3]; //Work arrays for summing up fluxes
2591
2592  int number_of_elements, k, i, m, n;
2593  int ki, nm=0, ki2; //Index shorthands
2594  static long call=1;
2595
2596
2597  // Convert Python arguments to C
2598  if (!PyArg_ParseTuple(args, "ddddOOOOOOOOOOOOOOOOOO",
2599            &timestep,
2600            &epsilon,
2601            &H0,
2602            &g,
2603            &neighbours,
2604            &neighbour_edges,
2605            &normals,
2606            &edgelengths, &radii, &areas,
2607            &tri_full_flag,
2608            &stage_edge_values,
2609            &xmom_edge_values,
2610            &ymom_edge_values,
2611            &bed_edge_values,
2612            &stage_boundary_values,
2613            &xmom_boundary_values,
2614            &ymom_boundary_values,
2615            &stage_explicit_update,
2616            &xmom_explicit_update,
2617            &ymom_explicit_update,
2618            &already_computed_flux)) {
2619    report_python_error(AT, "could not parse input arguments");
2620    return NULL;
2621  }
2622  number_of_elements = stage_edge_values -> dimensions[0];
2623  call++;//a static local variable to which already_computed_flux is compared
2624  //set explicit_update to zero for all conserved_quantities.
2625  //This assumes compute_fluxes called before forcing terms
2626  for (k=0; k<number_of_elements; k++) {
2627    ((double *) stage_explicit_update -> data)[k]=0.0;
2628    ((double *) xmom_explicit_update -> data)[k]=0.0;
2629    ((double *) ymom_explicit_update -> data)[k]=0.0;
2630  }
2631  //Loop through neighbours and compute edge flux for each
2632  for (k=0; k<number_of_elements; k++) {
2633    for (i=0; i<3; i++) {
2634      ki = k*3+i;
2635      if (((long *) already_computed_flux->data)[ki]==call)//we've already computed the flux across this edge
2636    continue;
2637      ql[0] = ((double *) stage_edge_values -> data)[ki];
2638      ql[1] = ((double *) xmom_edge_values -> data)[ki];
2639      ql[2] = ((double *) ymom_edge_values -> data)[ki];
2640      zl =    ((double *) bed_edge_values -> data)[ki];
2641
2642      //Quantities at neighbour on nearest face
2643      n = ((long *) neighbours -> data)[ki];
2644      if (n < 0) {
2645    m = -n-1; //Convert negative flag to index
2646    qr[0] = ((double *) stage_boundary_values -> data)[m];
2647    qr[1] = ((double *) xmom_boundary_values -> data)[m];
2648    qr[2] = ((double *) ymom_boundary_values -> data)[m];
2649    zr = zl; //Extend bed elevation to boundary
2650      } else {
2651    m = ((long *) neighbour_edges -> data)[ki];
2652    nm = n*3+m;
2653    qr[0] = ((double *) stage_edge_values -> data)[nm];
2654    qr[1] = ((double *) xmom_edge_values -> data)[nm];
2655    qr[2] = ((double *) ymom_edge_values -> data)[nm];
2656    zr =    ((double *) bed_edge_values -> data)[nm];
2657      }
2658      // Outward pointing normal vector
2659      // normal = domain.normals[k, 2*i:2*i+2]
2660      ki2 = 2*ki; //k*6 + i*2
2661      normal[0] = ((double *) normals -> data)[ki2];
2662      normal[1] = ((double *) normals -> data)[ki2+1];
2663      //Edge flux computation
2664      flux_function_kinetic(ql, qr, zl, zr,
2665            normal[0], normal[1],
2666            epsilon, H0, g,
2667            edgeflux, &max_speed);
2668      //update triangle k
2669      ((long *) already_computed_flux->data)[ki]=call;
2670      ((double *) stage_explicit_update -> data)[k] -= edgeflux[0]*((double *) edgelengths -> data)[ki];
2671      ((double *) xmom_explicit_update -> data)[k] -= edgeflux[1]*((double *) edgelengths -> data)[ki];
2672      ((double *) ymom_explicit_update -> data)[k] -= edgeflux[2]*((double *) edgelengths -> data)[ki];
2673      //update the neighbour n
2674      if (n>=0){
2675    ((long *) already_computed_flux->data)[nm]=call;
2676    ((double *) stage_explicit_update -> data)[n] += edgeflux[0]*((double *) edgelengths -> data)[nm];
2677    ((double *) xmom_explicit_update -> data)[n] += edgeflux[1]*((double *) edgelengths -> data)[nm];
2678    ((double *) ymom_explicit_update -> data)[n] += edgeflux[2]*((double *) edgelengths -> data)[nm];
2679      }
2680      ///for (j=0; j<3; j++) {
2681    ///flux[j] -= edgeflux[j]*((double *) edgelengths -> data)[ki];
2682    ///}
2683    //Update timestep
2684    //timestep = min(timestep, domain.radii[k]/max_speed)
2685    //FIXME: SR Add parameter for CFL condition
2686    if ( ((long *) tri_full_flag -> data)[k] == 1) {
2687        if (max_speed > epsilon) {
2688            timestep = min(timestep, ((double *) radii -> data)[k]/max_speed);
2689            //maxspeed in flux_function is calculated as max(|u+a|,|u-a|)
2690            if (n>=0)
2691                timestep = min(timestep, ((double *) radii -> data)[n]/max_speed);
2692        }
2693    }
2694    } // end for i
2695    //Normalise by area and store for when all conserved
2696    //quantities get updated
2697    ((double *) stage_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
2698    ((double *) xmom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
2699    ((double *) ymom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
2700  } //end for k
2701  return Py_BuildValue("d", timestep);
2702}
2703
2704PyObject *protect(PyObject *self, PyObject *args) {
2705  //
2706  //    protect(minimum_allowed_height, maximum_allowed_speed, wc, zc, xmomc, ymomc)
2707
2708
2709  PyArrayObject
2710  *wc,            //Stage at centroids
2711  *zc,            //Elevation at centroids
2712  *xmomc,         //Momentums at centroids
2713  *ymomc;
2714
2715
2716  int N;
2717  double minimum_allowed_height, maximum_allowed_speed, epsilon;
2718
2719  // Convert Python arguments to C
2720  if (!PyArg_ParseTuple(args, "dddOOOO",
2721            &minimum_allowed_height,
2722            &maximum_allowed_speed,
2723            &epsilon,
2724            &wc, &zc, &xmomc, &ymomc)) {
2725    report_python_error(AT, "could not parse input arguments");
2726    return NULL;
2727  } 
2728
2729  N = wc -> dimensions[0];
2730
2731  _protect(N,
2732       minimum_allowed_height,
2733       maximum_allowed_speed,
2734       epsilon,
2735       (double*) wc -> data,
2736       (double*) zc -> data,
2737       (double*) xmomc -> data,
2738       (double*) ymomc -> data);
2739
2740  return Py_BuildValue("");
2741}
2742
2743
2744
2745PyObject *balance_deep_and_shallow(PyObject *self, PyObject *args) {
2746  // Compute linear combination between stage as computed by
2747  // gradient-limiters limiting using w, and stage computed by
2748  // gradient-limiters limiting using h (h-limiter).
2749  // The former takes precedence when heights are large compared to the
2750  // bed slope while the latter takes precedence when heights are
2751  // relatively small.  Anything in between is computed as a balanced
2752  // linear combination in order to avoid numerical disturbances which
2753  // would otherwise appear as a result of hard switching between
2754  // modes.
2755  //
2756  //    balance_deep_and_shallow(wc, zc, wv, zv,
2757  //                             xmomc, ymomc, xmomv, ymomv)
2758
2759
2760  PyArrayObject
2761    *wc,            //Stage at centroids
2762    *zc,            //Elevation at centroids
2763    *wv,            //Stage at vertices
2764    *zv,            //Elevation at vertices
2765    *hvbar,         //h-Limited depths at vertices
2766    *xmomc,         //Momentums at centroids and vertices
2767    *ymomc,
2768    *xmomv,
2769    *ymomv;
2770 
2771  PyObject *domain, *Tmp;
2772   
2773  double alpha_balance = 2.0;
2774  double H0;
2775
2776  int N, tight_slope_limiters, use_centroid_velocities; //, err;
2777
2778  // Convert Python arguments to C
2779  if (!PyArg_ParseTuple(args, "OOOOOOOOOO",
2780            &domain,
2781            &wc, &zc, 
2782            &wv, &zv, &hvbar,
2783            &xmomc, &ymomc, &xmomv, &ymomv)) {
2784    report_python_error(AT, "could not parse input arguments");
2785    return NULL;
2786  } 
2787     
2788     
2789  // FIXME (Ole): I tested this without GetAttrString and got time down
2790  // marginally from 4.0s to 3.8s. Consider passing everything in
2791  // through ParseTuple and profile.
2792 
2793  // Pull out parameters
2794  Tmp = PyObject_GetAttrString(domain, "alpha_balance");
2795  if (!Tmp) {
2796    report_python_error(AT, "could not obtain object alpha_balance from domain");
2797    return NULL;
2798  } 
2799  alpha_balance = PyFloat_AsDouble(Tmp);
2800  Py_DECREF(Tmp);
2801
2802 
2803  Tmp = PyObject_GetAttrString(domain, "H0");
2804  if (!Tmp) {
2805    report_python_error(AT, "could not obtain object H0 from domain");
2806    return NULL;
2807  } 
2808  H0 = PyFloat_AsDouble(Tmp);
2809  Py_DECREF(Tmp);
2810
2811 
2812  Tmp = PyObject_GetAttrString(domain, "tight_slope_limiters");
2813  if (!Tmp) {
2814    report_python_error(AT, "could not obtain object tight_slope_limiters from domain");
2815    return NULL;
2816  } 
2817  tight_slope_limiters = PyInt_AsLong(Tmp);
2818  Py_DECREF(Tmp);
2819 
2820 
2821  Tmp = PyObject_GetAttrString(domain, "use_centroid_velocities");
2822  if (!Tmp) {
2823    report_python_error(AT, "could not obtain object use_centroid_velocities from domain");
2824    return NULL;
2825  } 
2826  use_centroid_velocities = PyInt_AsLong(Tmp);
2827  Py_DECREF(Tmp);
2828 
2829 
2830 
2831  N = wc -> dimensions[0];
2832  _balance_deep_and_shallow(N,
2833                (double*) wc -> data,
2834                (double*) zc -> data,
2835                (double*) wv -> data,
2836                (double*) zv -> data,
2837                (double*) hvbar -> data,
2838                (double*) xmomc -> data,
2839                (double*) ymomc -> data,
2840                (double*) xmomv -> data,
2841                (double*) ymomv -> data,
2842                H0,
2843                (int) tight_slope_limiters,
2844                (int) use_centroid_velocities,             
2845                alpha_balance);
2846
2847
2848  return Py_BuildValue("");
2849}
2850
2851
2852
2853
2854PyObject *assign_windfield_values(PyObject *self, PyObject *args) {
2855  //
2856  //      assign_windfield_values(xmom_update, ymom_update,
2857  //                              s_vec, phi_vec, self.const)
2858
2859
2860
2861  PyArrayObject   //(one element per triangle)
2862  *s_vec,         //Speeds
2863  *phi_vec,       //Bearings
2864  *xmom_update,   //Momentum updates
2865  *ymom_update;
2866
2867
2868  int N;
2869  double cw;
2870
2871  // Convert Python arguments to C
2872  if (!PyArg_ParseTuple(args, "OOOOd",
2873            &xmom_update,
2874            &ymom_update,
2875            &s_vec, &phi_vec,
2876            &cw)) {
2877    report_python_error(AT, "could not parse input arguments");
2878    return NULL;
2879  } 
2880           
2881
2882  N = xmom_update -> dimensions[0];
2883
2884  _assign_wind_field_values(N,
2885       (double*) xmom_update -> data,
2886       (double*) ymom_update -> data,
2887       (double*) s_vec -> data,
2888       (double*) phi_vec -> data,
2889       cw);
2890
2891  return Py_BuildValue("");
2892}
2893
2894
2895
2896
2897//-------------------------------
2898// Method table for python module
2899//-------------------------------
2900static struct PyMethodDef MethodTable[] = {
2901  /* The cast of the function is necessary since PyCFunction values
2902   * only take two PyObject* parameters, and rotate() takes
2903   * three.
2904   */
2905
2906  {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
2907  {"extrapolate_second_order_sw", extrapolate_second_order_sw, METH_VARARGS, "Print out"},
2908  {"compute_fluxes_ext_central", compute_fluxes_ext_central, METH_VARARGS, "Print out"},
2909  {"compute_fluxes_ext_central_new", compute_fluxes_ext_central_new, METH_VARARGS, "Print out"},
2910  {"compute_fluxes_ext_kinetic", compute_fluxes_ext_kinetic, METH_VARARGS, "Print out"},
2911  {"gravity", gravity, METH_VARARGS, "Print out"},
2912  {"manning_friction_flat", manning_friction_flat, METH_VARARGS, "Print out"},
2913  {"manning_friction_sloped", manning_friction_sloped, METH_VARARGS, "Print out"},
2914  {"chezy_friction", chezy_friction, METH_VARARGS, "Print out"},
2915  {"flux_function_central", flux_function_central, METH_VARARGS, "Print out"}, 
2916  {"balance_deep_and_shallow", balance_deep_and_shallow,
2917   METH_VARARGS, "Print out"},
2918  {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"},
2919  {"assign_windfield_values", assign_windfield_values,
2920   METH_VARARGS | METH_KEYWORDS, "Print out"},
2921  {NULL, NULL}
2922};
2923
2924// Module initialisation
2925void initshallow_water_ext(void){
2926  Py_InitModule("shallow_water_ext", MethodTable);
2927
2928  import_array(); // Necessary for handling of NumPY structures
2929}
Note: See TracBrowser for help on using the repository browser.