source: anuga_core/source/anuga/shallow_water/shallow_water_ext.c @ 4690

Last change on this file since 4690 was 4690, checked in by ole, 17 years ago

Code prettyfication and dry cell experiment (commented out) in extrapolate_second_order_sww

File size: 65.0 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.py
10//
11//
12// Ole Nielsen, GA 2004
13
14
15#include "Python.h"
16#include "Numeric/arrayobject.h"
17#include "math.h"
18#include <stdio.h>
19
20//Shared code snippets
21#include "util_ext.h"
22
23
24const double pi = 3.14159265358979;
25
26// Computational function for rotation
27int _rotate(double *q, double n1, double n2) {
28  /*Rotate the momentum component q (q[1], q[2])
29    from x,y coordinates to coordinates based on normal vector (n1, n2).
30
31    Result is returned in array 3x1 r
32    To rotate in opposite direction, call rotate with (q, n1, -n2)
33
34    Contents of q are changed by this function */
35
36
37  double q1, q2;
38
39  //Shorthands
40  q1 = q[1];  //uh momentum
41  q2 = q[2];  //vh momentum
42
43  //Rotate
44  q[1] =  n1*q1 + n2*q2;
45  q[2] = -n2*q1 + n1*q2;
46
47  return 0;
48}
49
50int find_qmin_and_qmax(double dq0, double dq1, double dq2, double *qmin, double *qmax){
51  //Considering the centroid of an FV triangle and the vertices of its auxiliary triangle, find
52  //qmin=min(q)-qc and qmax=max(q)-qc, where min(q) and max(q) are respectively min and max over the
53  //four values (at the centroid of the FV triangle and the auxiliary triangle vertices),
54  //and qc is the centroid
55  //dq0=q(vertex0)-q(centroid of FV triangle)
56  //dq1=q(vertex1)-q(vertex0)
57  //dq2=q(vertex2)-q(vertex0)
58  if (dq0>=0.0){
59    if (dq1>=dq2){
60      if (dq1>=0.0)
61        *qmax=dq0+dq1;
62      else
63        *qmax=dq0;
64      if ((*qmin=dq0+dq2)<0)
65        ;//qmin is already set to correct value
66      else
67        *qmin=0.0;
68    }
69    else{//dq1<dq2
70      if (dq2>0)
71        *qmax=dq0+dq2;
72      else
73        *qmax=dq0;
74      if ((*qmin=dq0+dq1)<0)
75        ;//qmin is the correct value
76      else
77        *qmin=0.0;
78    }
79  }
80  else{//dq0<0
81    if (dq1<=dq2){
82      if (dq1<0.0)
83        *qmin=dq0+dq1;
84      else
85        *qmin=dq0;
86      if ((*qmax=dq0+dq2)>0.0)
87        ;//qmax is already set to the correct value
88      else
89        *qmax=0.0;
90    }
91    else{//dq1>dq2
92      if (dq2<0.0)
93        *qmin=dq0+dq2;
94      else
95        *qmin=dq0;
96      if ((*qmax=dq0+dq1)>0.0)
97        ;//qmax is already set to the correct value
98      else
99        *qmax=0.0;
100    }
101  }
102  return 0;
103}
104
105int limit_gradient(double *dqv, double qmin, double qmax, double beta_w){
106  //given provisional jumps dqv from the FV triangle centroid to its vertices and
107  //jumps qmin (qmax) between the centroid of the FV triangle and the
108  //minimum (maximum) of the values at the centroid of the FV triangle and the auxiliary triangle vertices,
109  //calculate a multiplicative factor phi by which the provisional vertex jumps are to be limited
110  int i;
111  double r=1000.0, r0=1.0, phi=1.0;
112  static double TINY = 1.0e-100;//to avoid machine accuracy problems.
113  //Any provisional jump with magnitude < TINY does not contribute to the limiting process.
114  for (i=0;i<3;i++){
115    if (dqv[i]<-TINY)
116      r0=qmin/dqv[i];
117    if (dqv[i]>TINY)
118      r0=qmax/dqv[i];
119    r=min(r0,r);
120    //
121  }
122  phi=min(r*beta_w,1.0);
123  for (i=0;i<3;i++)
124    dqv[i]=dqv[i]*phi;
125  return 0;
126}
127
128
129void adjust_froude_number(double *uh,
130                          double h, 
131                          double g) {
132                         
133  // Adjust momentum if Froude number is excessive
134  double max_froude_number = 20.0;                       
135  double froude_number;
136 
137  //Compute Froude number (stability diagnostics)
138  froude_number = *uh/sqrt(g*h)/h;
139
140  if (froude_number > max_froude_number) {
141    printf("---------------------------------------------\n");
142    printf("froude_number=%f (uh=%f, h=%f)\n", froude_number, *uh, h);
143   
144    *uh = *uh/fabs(*uh) * max_froude_number * sqrt(g*h)*h;
145   
146    froude_number = *uh/sqrt(g*h)/h;   
147    printf("Adjusted froude_number=%f (uh=%f, h=%f)\n", froude_number, *uh, h);
148    printf("---------------------------------------------\n");   
149  }
150}
151
152
153
154// Function to obtain speed from momentum and depth.
155// This is used by flux functions
156// Input parameters uh and h may be modified by this function.
157double _compute_speed(double *uh, 
158                      double *h, 
159                      double epsilon, 
160                      double h0) {
161 
162  double u;
163
164  //adjust_froude_number(uh, *h, 9.81); // Highly experimental and
165                                        // probably unneccessary
166 
167  if (*h < epsilon) {
168    *h = 0.0;  //Could have been negative
169    u = 0.0;
170  } else {
171    u = *uh/(*h + h0/ *h);   
172  }
173 
174
175  // Adjust momentum to be consistent with speed
176  *uh = u * *h;
177 
178  return u;
179}
180
181// Computational function for flux computation (using stage w=z+h)
182int flux_function_central(double *q_left, double *q_right,
183                          double z_left, double z_right,
184                          double n1, double n2,
185                          double epsilon, double H0, double g,
186                          double *edgeflux, double *max_speed) {
187
188  /*Compute fluxes between volumes for the shallow water wave equation
189    cast in terms of the 'stage', w = h+z using
190    the 'central scheme' as described in
191
192    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
193    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
194    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
195
196    The implemented formula is given in equation (3.15) on page 714
197  */
198
199  int i;
200
201  double w_left, h_left, uh_left, vh_left, u_left;
202  double w_right, h_right, uh_right, vh_right, u_right;
203  double v_left, v_right; 
204  double s_min, s_max, soundspeed_left, soundspeed_right;
205  double denom, z;
206  double q_left_rotated[3], q_right_rotated[3];
207  double flux_right[3], flux_left[3];
208
209  double h0 = H0*H0; //This ensures a good balance when h approaches H0.
210                     //But evidence suggests that h0 can be as little as
211                     //epsilon!
212 
213  // Copy conserved quantities to protect from modification
214  for (i=0; i<3; i++) {
215    q_left_rotated[i] = q_left[i];
216    q_right_rotated[i] = q_right[i];
217  }
218
219  // Align x- and y-momentum with x-axis
220  _rotate(q_left_rotated, n1, n2);
221  _rotate(q_right_rotated, n1, n2);
222
223  z = (z_left+z_right)/2; // Average elevation values
224
225  // Compute speeds in x-direction
226  w_left = q_left_rotated[0];         
227  h_left = w_left-z;
228  uh_left = q_left_rotated[1];
229  u_left = _compute_speed(&uh_left, &h_left, epsilon, h0);
230
231  w_right = q_right_rotated[0];
232  h_right = w_right-z;
233  uh_right = q_right_rotated[1];
234  u_right = _compute_speed(&uh_right, &h_right, epsilon, h0); 
235
236  // Momentum in y-direction
237  vh_left  = q_left_rotated[2];
238  vh_right = q_right_rotated[2];
239
240  // Limit y-momentum if necessary 
241  v_left = _compute_speed(&vh_left, &h_left, epsilon, h0);
242  v_right = _compute_speed(&vh_right, &h_right, epsilon, h0);
243
244  // Maximal and minimal wave speeds
245  soundspeed_left  = sqrt(g*h_left);
246  soundspeed_right = sqrt(g*h_right);
247
248  s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
249  if (s_max < 0.0) s_max = 0.0;
250
251  s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
252   if (s_min > 0.0) s_min = 0.0;
253
254 
255  // Flux formulas
256  flux_left[0] = u_left*h_left;
257  flux_left[1] = u_left*uh_left + 0.5*g*h_left*h_left;
258  flux_left[2] = u_left*vh_left;
259
260  flux_right[0] = u_right*h_right;
261  flux_right[1] = u_right*uh_right + 0.5*g*h_right*h_right;
262  flux_right[2] = u_right*vh_right;
263
264 
265 
266  // Flux computation
267  denom = s_max-s_min;
268  if (denom == 0.0) {
269    for (i=0; i<3; i++) edgeflux[i] = 0.0;
270    *max_speed = 0.0;
271  } else {
272    for (i=0; i<3; i++) {
273      edgeflux[i] = s_max*flux_left[i] - s_min*flux_right[i];
274      edgeflux[i] += s_max*s_min*(q_right_rotated[i]-q_left_rotated[i]);
275      edgeflux[i] /= denom;
276    }
277
278    // Maximal wavespeed
279    *max_speed = max(fabs(s_max), fabs(s_min));
280
281    // Rotate back
282    _rotate(edgeflux, n1, -n2);
283  }
284 
285  return 0;
286}
287
288double erfcc(double x){
289    double z,t,result;
290
291    z=fabs(x);
292    t=1.0/(1.0+0.5*z);
293    result=t*exp(-z*z-1.26551223+t*(1.00002368+t*(.37409196+
294         t*(.09678418+t*(-.18628806+t*(.27886807+t*(-1.13520398+
295         t*(1.48851587+t*(-.82215223+t*.17087277)))))))));
296    if (x < 0.0) result = 2.0-result;
297
298    return result;
299    }
300
301
302
303// Computational function for flux computation (using stage w=z+h)
304// FIXME (Ole): Is this used anywhere??
305int flux_function_kinetic(double *q_left, double *q_right,
306                  double z_left, double z_right,
307                  double n1, double n2,
308                  double epsilon, double H0, double g,
309                  double *edgeflux, double *max_speed) {
310
311  /*Compute fluxes between volumes for the shallow water wave equation
312    cast in terms of the 'stage', w = h+z using
313    the 'central scheme' as described in
314
315    Zhang et. al., Advances in Water Resources, 26(6), 2003, 635-647.
316  */
317
318  int i;
319
320  double w_left, h_left, uh_left, vh_left, u_left, F_left;
321  double w_right, h_right, uh_right, vh_right, u_right, F_right;
322  double s_min, s_max, soundspeed_left, soundspeed_right;
323  double z;
324  double q_left_rotated[3], q_right_rotated[3];
325
326  double h0 = H0*H0; //This ensures a good balance when h approaches H0.
327
328  //Copy conserved quantities to protect from modification
329  for (i=0; i<3; i++) {
330    q_left_rotated[i] = q_left[i];
331    q_right_rotated[i] = q_right[i];
332  }
333
334  //Align x- and y-momentum with x-axis
335  _rotate(q_left_rotated, n1, n2);
336  _rotate(q_right_rotated, n1, n2);
337
338  z = (z_left+z_right)/2; //Take average of field values
339
340  //Compute speeds in x-direction
341  w_left = q_left_rotated[0];         
342  h_left = w_left-z;
343  uh_left = q_left_rotated[1];
344  u_left =_compute_speed(&uh_left, &h_left, epsilon, h0);
345
346  w_right = q_right_rotated[0];
347  h_right = w_right-z;
348  uh_right = q_right_rotated[1];
349  u_right =_compute_speed(&uh_right, &h_right, epsilon, h0); 
350
351
352  //Momentum in y-direction
353  vh_left  = q_left_rotated[2];
354  vh_right = q_right_rotated[2];
355
356
357  //Maximal and minimal wave speeds
358  soundspeed_left  = sqrt(g*h_left);
359  soundspeed_right = sqrt(g*h_right);
360
361  s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
362  if (s_max < 0.0) s_max = 0.0;
363
364  s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
365  if (s_min > 0.0) s_min = 0.0;
366
367
368  F_left  = 0.0;
369  F_right = 0.0;
370  if (h_left > 0.0) F_left = u_left/sqrt(g*h_left);
371  if (h_right > 0.0) F_right = u_right/sqrt(g*h_right);
372
373  for (i=0; i<3; i++) edgeflux[i] = 0.0;
374  *max_speed = 0.0;
375
376  edgeflux[0] = h_left*u_left/2.0*erfcc(-F_left) +  \
377          h_left*sqrt(g*h_left)/2.0/sqrt(pi)*exp(-(F_left*F_left)) + \
378          h_right*u_right/2.0*erfcc(F_right) -  \
379          h_right*sqrt(g*h_right)/2.0/sqrt(pi)*exp(-(F_right*F_right));
380
381  edgeflux[1] = (h_left*u_left*u_left + g/2.0*h_left*h_left)/2.0*erfcc(-F_left) + \
382          u_left*h_left*sqrt(g*h_left)/2.0/sqrt(pi)*exp(-(F_left*F_left)) + \
383          (h_right*u_right*u_right + g/2.0*h_right*h_right)/2.0*erfcc(F_right) -  \
384          u_right*h_right*sqrt(g*h_right)/2.0/sqrt(pi)*exp(-(F_right*F_right));
385
386  edgeflux[2] = vh_left*u_left/2.0*erfcc(-F_left) + \
387          vh_left*sqrt(g*h_left)/2.0/sqrt(pi)*exp(-(F_left*F_left)) + \
388          vh_right*u_right/2.0*erfcc(F_right) - \
389          vh_right*sqrt(g*h_right)/2.0/sqrt(pi)*exp(-(F_right*F_right));
390
391  //Maximal wavespeed
392  *max_speed = max(fabs(s_max), fabs(s_min));
393
394  //Rotate back
395  _rotate(edgeflux, n1, -n2);
396
397  return 0;
398}
399
400
401
402
403void _manning_friction(double g, double eps, int N,
404                       double* w, double* z,
405                       double* uh, double* vh,
406                       double* eta, double* xmom, double* ymom) {
407
408  int k;
409  double S, h;
410
411  for (k=0; k<N; k++) {
412    if (eta[k] > eps) {
413      h = w[k]-z[k];
414      if (h >= eps) {
415        S = -g * eta[k]*eta[k] * sqrt((uh[k]*uh[k] + vh[k]*vh[k]));
416        S /= pow(h, 7.0/3);      //Expensive (on Ole's home computer)
417        //S /= exp(7.0/3.0*log(h));      //seems to save about 15% over manning_friction
418        //S /= h*h*(1 + h/3.0 - h*h/9.0); //FIXME: Could use a Taylor expansion
419
420
421        //Update momentum
422        xmom[k] += S*uh[k];
423        ymom[k] += S*vh[k];
424      }
425    }
426  }
427}
428
429
430/*
431void _manning_friction_explicit(double g, double eps, int N,
432                       double* w, double* z,
433                       double* uh, double* vh,
434                       double* eta, double* xmom, double* ymom) {
435
436  int k;
437  double S, h;
438
439  for (k=0; k<N; k++) {
440    if (eta[k] > eps) {
441      h = w[k]-z[k];
442      if (h >= eps) {
443        S = -g * eta[k]*eta[k] * sqrt((uh[k]*uh[k] + vh[k]*vh[k]));
444        S /= pow(h, 7.0/3);      //Expensive (on Ole's home computer)
445        //S /= exp(7.0/3.0*log(h));      //seems to save about 15% over manning_friction
446        //S /= h*h*(1 + h/3.0 - h*h/9.0); //FIXME: Could use a Taylor expansion
447
448
449        //Update momentum
450        xmom[k] += S*uh[k];
451        ymom[k] += S*vh[k];
452      }
453    }
454  }
455}
456*/
457
458int _balance_deep_and_shallow(int N,
459                              double* wc,
460                              double* zc,
461                              double* hc,
462                              double* wv,
463                              double* zv,
464                              double* hv,
465                              double* hvbar,
466                              double* xmomc,
467                              double* ymomc,
468                              double* xmomv,
469                              double* ymomv,
470                              double H0,
471                              int tight_slope_limiters,
472                              double alpha_balance) {
473
474  int k, k3, i;
475  double dz, hmin, alpha, h_diff;
476
477  //Compute linear combination between w-limited stages and
478  //h-limited stages close to the bed elevation.
479
480  for (k=0; k<N; k++) {
481    // Compute maximal variation in bed elevation
482    // This quantitiy is
483    //     dz = max_i abs(z_i - z_c)
484    // and it is independent of dimension
485    // In the 1d case zc = (z0+z1)/2
486    // In the 2d case zc = (z0+z1+z2)/3
487
488    k3 = 3*k;
489
490    //FIXME: Try with this one precomputed
491    dz = 0.0;
492    hmin = hv[k3];
493    for (i=0; i<3; i++) {
494      if (tight_slope_limiters == 0) { 
495        dz = max(dz, fabs(zv[k3+i]-zc[k]));
496      }
497     
498      hmin = min(hmin, hv[k3+i]);
499    }
500
501
502    //Create alpha in [0,1], where alpha==0 means using the h-limited
503    //stage and alpha==1 means using the w-limited stage as
504    //computed by the gradient limiter (both 1st or 2nd order)
505   
506   
507    if (tight_slope_limiters == 0) {     
508      //If hmin > dz/alpha_balance then alpha = 1 and the bed will have no
509      //effect
510      //If hmin < 0 then alpha = 0 reverting to constant height above bed.
511      //The parameter alpha_balance==2 by default
512
513     
514      if (dz > 0.0) {
515        alpha = max( min( alpha_balance*hmin/dz, 1.0), 0.0 );     
516      } else {
517        alpha = 1.0;  //Flat bed
518      }
519      //printf("Using old style limiter\n");
520     
521    } else {
522
523      // 2007 Balanced Limiter
524   
525      // Make alpha as large as possible but still ensure that
526      // final depth is positive
527   
528      if (hmin < H0) {
529        alpha = 1.0;
530        for (i=0; i<3; i++) {
531
532          h_diff = hvbar[k3+i] - hv[k3+i];
533       
534          if (h_diff <= 0) {
535            // Deep water triangle is further away from bed than
536            // shallow water (hbar < h). Any alpha will do
537         
538          } else { 
539            // Denominator is positive which means that we need some of the
540            // h-limited stage.
541           
542            alpha = min(alpha, (hvbar[k3+i] - H0)/h_diff);
543          }
544        }
545
546        // Ensure alpha in [0,1]
547        if (alpha>1.0) alpha=1.0;
548        if (alpha<0.0) alpha=0.0;
549       
550      } else {
551        // Use w-limited stage exclusively
552        alpha = 1.0;       
553      }
554    }
555       
556   
557       
558    //printf("k=%d, hmin=%.2f, dz=%.2f, alpha=%.2f, alpha_balance=%.2f\n",
559    //     k, hmin, dz, alpha, alpha_balance);
560
561    //printf("dz = %.3f, alpha = %.8f\n", dz, alpha);
562
563    //  Let
564    //
565    //    wvi be the w-limited stage (wvi = zvi + hvi)
566    //    wvi- be the h-limited state (wvi- = zvi + hvi-)
567    //
568    //
569    //  where i=0,1,2 denotes the vertex ids
570    //
571    //  Weighted balance between w-limited and h-limited stage is
572    //
573    //    wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
574    //
575    //  It follows that the updated wvi is
576    //    wvi := zvi + (1-alpha)*hvi- + alpha*hvi
577    //
578    //   Momentum is balanced between constant and limited
579
580    if (alpha < 1) {
581      for (i=0; i<3; i++) {
582        wv[k3+i] = zv[k3+i] + (1-alpha)*hvbar[k3+i] + alpha*hv[k3+i];
583
584        //Update momentum as a linear combination of
585        //xmomc and ymomc (shallow) and momentum
586        //from extrapolator xmomv and ymomv (deep).
587        //FIXME (Ole): Is this really needed?
588        xmomv[k3+i] = (1-alpha)*xmomc[k] + alpha*xmomv[k3+i];
589        ymomv[k3+i] = (1-alpha)*ymomc[k] + alpha*ymomv[k3+i];
590      }
591    }
592  }
593  return 0;
594}
595
596
597
598int _protect(int N,
599             double minimum_allowed_height,
600             double maximum_allowed_speed,
601             double epsilon,
602             double* wc,
603             double* zc,
604             double* xmomc,
605             double* ymomc) {
606
607  int k;
608  double hc;
609  double u, v, reduced_speed;
610
611  //Protect against initesimal and negative heights
612  for (k=0; k<N; k++) {
613    hc = wc[k] - zc[k];
614
615    if (hc < minimum_allowed_height) {
616       
617      //Old code: Set momentum to zero and ensure h is non negative
618      //xmomc[k] = 0.0;
619      //ymomc[k] = 0.0;
620      //if (hc <= 0.0) wc[k] = zc[k];
621
622
623      //New code: Adjust momentum to guarantee speeds are physical
624      //          ensure h is non negative
625      //FIXME (Ole): This is only implemented in this C extension and
626      //             has no Python equivalent
627           
628      if (hc <= 0.0) {
629        wc[k] = zc[k];
630        xmomc[k] = 0.0;
631        ymomc[k] = 0.0;
632      } else {
633        //Reduce excessive speeds derived from division by small hc
634        //FIXME (Ole): This may be unnecessary with new slope limiters
635        //in effect.
636       
637        u = xmomc[k]/hc;
638        if (fabs(u) > maximum_allowed_speed) {
639          reduced_speed = maximum_allowed_speed * u/fabs(u);
640          //printf("Speed (u) has been reduced from %.3f to %.3f\n",
641          //     u, reduced_speed);
642          xmomc[k] = reduced_speed * hc;
643        }
644
645        v = ymomc[k]/hc;
646        if (fabs(v) > maximum_allowed_speed) {
647          reduced_speed = maximum_allowed_speed * v/fabs(v);
648          //printf("Speed (v) has been reduced from %.3f to %.3f\n",
649          //     v, reduced_speed);
650          ymomc[k] = reduced_speed * hc;
651        }
652      }
653    }
654  }
655  return 0;
656}
657
658
659
660
661int _assign_wind_field_values(int N,
662                              double* xmom_update,
663                              double* ymom_update,
664                              double* s_vec,
665                              double* phi_vec,
666                              double cw) {
667
668  //Assign windfield values to momentum updates
669
670  int k;
671  double S, s, phi, u, v;
672
673  for (k=0; k<N; k++) {
674
675    s = s_vec[k];
676    phi = phi_vec[k];
677
678    //Convert to radians
679    phi = phi*pi/180;
680
681    //Compute velocity vector (u, v)
682    u = s*cos(phi);
683    v = s*sin(phi);
684
685    //Compute wind stress
686    S = cw * sqrt(u*u + v*v);
687    xmom_update[k] += S*u;
688    ymom_update[k] += S*v;
689  }
690  return 0;
691}
692
693
694
695///////////////////////////////////////////////////////////////////
696// Gateways to Python
697
698PyObject *gravity(PyObject *self, PyObject *args) {
699  //
700  //  gravity(g, h, v, x, xmom, ymom)
701  //
702
703
704  PyArrayObject *h, *v, *x, *xmom, *ymom;
705  int k, N, k3, k6;
706  double g, avg_h, zx, zy;
707  double x0, y0, x1, y1, x2, y2, z0, z1, z2;
708  //double epsilon;
709
710  if (!PyArg_ParseTuple(args, "dOOOOO",
711                        &g, &h, &v, &x,
712                        &xmom, &ymom)) {
713    //&epsilon)) {
714    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: gravity could not parse input arguments");
715    return NULL;
716  }
717
718  N = h -> dimensions[0];
719  for (k=0; k<N; k++) {
720    k3 = 3*k;  // base index
721
722    // Get bathymetry
723    z0 = ((double*) v -> data)[k3 + 0];
724    z1 = ((double*) v -> data)[k3 + 1];
725    z2 = ((double*) v -> data)[k3 + 2];
726
727    // Optimise for flat bed
728    // Note (Ole): This didn't produce measurable speed up.
729    // Revisit later
730    //if (fabs(z0-z1)<epsilon && fabs(z1-z2)<epsilon) {
731    //  continue;
732    //}
733
734    // Get average depth from centroid values
735    avg_h = ((double *) h -> data)[k];
736
737    // Compute bed slope
738    k6 = 6*k;  // base index
739 
740    x0 = ((double*) x -> data)[k6 + 0];
741    y0 = ((double*) x -> data)[k6 + 1];
742    x1 = ((double*) x -> data)[k6 + 2];
743    y1 = ((double*) x -> data)[k6 + 3];
744    x2 = ((double*) x -> data)[k6 + 4];
745    y2 = ((double*) x -> data)[k6 + 5];
746
747
748    _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy);
749
750    // Update momentum
751    ((double*) xmom -> data)[k] += -g*zx*avg_h;
752    ((double*) ymom -> data)[k] += -g*zy*avg_h;
753  }
754
755  return Py_BuildValue("");
756}
757
758
759PyObject *manning_friction(PyObject *self, PyObject *args) {
760  //
761  // manning_friction(g, eps, h, uh, vh, eta, xmom_update, ymom_update)
762  //
763
764
765  PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom;
766  int N;
767  double g, eps;
768
769  if (!PyArg_ParseTuple(args, "ddOOOOOOO",
770                        &g, &eps, &w, &z, &uh, &vh, &eta,
771                        &xmom, &ymom)) {
772    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: manning_friction could not parse input arguments");
773    return NULL;
774  }
775
776
777  N = w -> dimensions[0];
778  _manning_friction(g, eps, N,
779                    (double*) w -> data,
780                    (double*) z -> data,
781                    (double*) uh -> data,
782                    (double*) vh -> data,
783                    (double*) eta -> data,
784                    (double*) xmom -> data,
785                    (double*) ymom -> data);
786
787  return Py_BuildValue("");
788}
789
790
791/*
792PyObject *manning_friction_explicit(PyObject *self, PyObject *args) {
793  //
794  // manning_friction_explicit(g, eps, h, uh, vh, eta, xmom_update, ymom_update)
795  //
796
797
798  PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom;
799  int N;
800  double g, eps;
801
802  if (!PyArg_ParseTuple(args, "ddOOOOOOO",
803                        &g, &eps, &w, &z, &uh, &vh, &eta,
804                        &xmom, &ymom))
805    return NULL;
806
807  N = w -> dimensions[0];
808  _manning_friction_explicit(g, eps, N,
809                    (double*) w -> data,
810                    (double*) z -> data,
811                    (double*) uh -> data,
812                    (double*) vh -> data,
813                    (double*) eta -> data,
814                    (double*) xmom -> data,
815                    (double*) ymom -> data);
816
817  return Py_BuildValue("");
818}
819*/
820
821PyObject *extrapolate_second_order_sw(PyObject *self, PyObject *args) {
822  /*Compute the vertex values based on a linear reconstruction on each triangle
823    These values are calculated as follows:
824    1) For each triangle not adjacent to a boundary, we consider the auxiliary triangle
825    formed by the centroids of its three neighbours.
826    2) For each conserved quantity, we integrate around the auxiliary triangle's boundary the product
827    of the quantity and the outward normal vector. Dividing by the triangle area gives (a,b), the average
828    of the vector (q_x,q_y) on the auxiliary triangle. We suppose that the linear reconstruction on the
829    original triangle has gradient (a,b).
830    3) Provisional vertex jumps dqv[0,1,2] are computed and these are then limited by calling the functions
831    find_qmin_and_qmax and limit_gradient
832
833    Python call:
834    extrapolate_second_order_sw(domain.surrogate_neighbours,
835                                domain.number_of_boundaries
836                                domain.centroid_coordinates,
837                                Stage.centroid_values
838                                Xmom.centroid_values
839                                Ymom.centroid_values
840                                domain.vertex_coordinates,
841                                Stage.vertex_values,
842                                Xmom.vertex_values,
843                                Ymom.vertex_values)
844
845    Post conditions:
846            The vertices of each triangle have values from a limited linear reconstruction
847            based on centroid values
848
849  */
850  PyArrayObject *surrogate_neighbours,
851    *number_of_boundaries,
852    *centroid_coordinates,
853    *stage_centroid_values,
854    *xmom_centroid_values,
855    *ymom_centroid_values,
856        *elevation_centroid_values,
857    *vertex_coordinates,
858    *stage_vertex_values,
859    *xmom_vertex_values,
860    *ymom_vertex_values,
861        *elevation_vertex_values;
862  PyObject *domain, *Tmp;
863  //Local variables
864  double a, b;//gradient vector, not stored but used to calculate vertex values from centroids
865  int number_of_elements,k,k0,k1,k2,k3,k6,coord_index,i;
866  double x,y,x0,y0,x1,y1,x2,y2,xv0,yv0,xv1,yv1,xv2,yv2;//vertices of the auxiliary triangle
867  double dx1,dx2,dy1,dy2,dxv0,dxv1,dxv2,dyv0,dyv1,dyv2,dq0,dq1,dq2,area2;
868  double dqv[3], qmin, qmax, hmin;
869  double hc, h0, h1, h2;
870  double epsilon=1.0e-12; // FIXME Pass in
871  double beta_w, beta_w_dry, beta_uh, beta_uh_dry, beta_vh, beta_vh_dry, beta_tmp;
872  double minimum_allowed_height;
873  //provisional jumps from centroids to v'tices and safety factor re limiting
874  //by which these jumps are limited
875  // Convert Python arguments to C
876  if (!PyArg_ParseTuple(args, "OOOOOOOOOOOOO",
877                        &domain,
878                        &surrogate_neighbours,
879                        &number_of_boundaries,
880                        &centroid_coordinates,
881                        &stage_centroid_values,
882                        &xmom_centroid_values,
883                        &ymom_centroid_values,
884                        &elevation_centroid_values,
885                        &vertex_coordinates,
886                        &stage_vertex_values,
887                        &xmom_vertex_values,
888                        &ymom_vertex_values,
889                        &elevation_vertex_values)) {
890    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
891    return NULL;
892  }
893
894  //get the safety factor beta_w, set in the config.py file. This is used in the limiting process
895  Tmp = PyObject_GetAttrString(domain, "beta_w");
896  if (!Tmp) {
897    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: extrapolate_second_order_sw could not obtain object beta_w from domain");
898    return NULL;
899  } 
900  beta_w = PyFloat_AsDouble(Tmp);
901  Py_DECREF(Tmp);
902 
903  Tmp = PyObject_GetAttrString(domain, "beta_w_dry");
904  if (!Tmp) {
905    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: extrapolate_second_order_sw could not obtain object beta_w_dry from domain");
906    return NULL;
907  } 
908  beta_w_dry = PyFloat_AsDouble(Tmp);
909  Py_DECREF(Tmp);
910 
911  Tmp = PyObject_GetAttrString(domain, "beta_uh");
912  if (!Tmp) {
913    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: extrapolate_second_order_sw could not obtain object beta_uh from domain");
914    return NULL;
915  } 
916  beta_uh = PyFloat_AsDouble(Tmp);
917  Py_DECREF(Tmp);
918 
919  Tmp = PyObject_GetAttrString(domain, "beta_uh_dry");
920  if (!Tmp) {
921    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: extrapolate_second_order_sw could not obtain object beta_uh_dry from domain");
922    return NULL;
923  } 
924  beta_uh_dry = PyFloat_AsDouble(Tmp);
925  Py_DECREF(Tmp); 
926
927  Tmp = PyObject_GetAttrString(domain, "beta_vh");
928  if (!Tmp) {
929    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: extrapolate_second_order_sw could not obtain object beta_vh from domain");
930    return NULL;
931  } 
932  beta_vh = PyFloat_AsDouble(Tmp);
933  Py_DECREF(Tmp);
934 
935  Tmp = PyObject_GetAttrString(domain, "beta_vh_dry");
936  if (!Tmp) {
937    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: extrapolate_second_order_sw could not obtain object beta_vh_dry from domain");
938    return NULL;
939  } 
940  beta_vh_dry = PyFloat_AsDouble(Tmp);
941  Py_DECREF(Tmp);
942 
943  Tmp = PyObject_GetAttrString(domain, "minimum_allowed_height");
944  if (!Tmp) {
945    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: extrapolate_second_order_sw could not obtain object minimum_allowed_heigt");
946    return NULL;
947  } 
948  minimum_allowed_height = PyFloat_AsDouble(Tmp);
949  Py_DECREF(Tmp); 
950 
951  number_of_elements = stage_centroid_values -> dimensions[0];
952  for (k=0; k<number_of_elements; k++) {
953    k3=k*3;
954    k6=k*6;
955
956   
957    if (((long *) number_of_boundaries->data)[k]==3){
958      // No neighbours, set gradient on the triangle to zero*/
959      ((double *) stage_vertex_values->data)[k3]=((double *)stage_centroid_values->data)[k];
960      ((double *) stage_vertex_values->data)[k3+1]=((double *)stage_centroid_values->data)[k];
961      ((double *) stage_vertex_values->data)[k3+2]=((double *)stage_centroid_values->data)[k];
962      ((double *) xmom_vertex_values->data)[k3]=((double *)xmom_centroid_values->data)[k];
963      ((double *) xmom_vertex_values->data)[k3+1]=((double *)xmom_centroid_values->data)[k];
964      ((double *) xmom_vertex_values->data)[k3+2]=((double *)xmom_centroid_values->data)[k];
965      ((double *) ymom_vertex_values->data)[k3]=((double *)ymom_centroid_values->data)[k];
966      ((double *) ymom_vertex_values->data)[k3+1]=((double *)ymom_centroid_values->data)[k];
967      ((double *) ymom_vertex_values->data)[k3+2]=((double *)ymom_centroid_values->data)[k];
968      continue;
969    }
970    else {
971      // Triangle k has one or more neighbours.
972      // Get centroid and vertex coordinates of the triangle
973     
974      // Get the vertex coordinates
975      xv0=((double *)vertex_coordinates->data)[k6]; yv0=((double *)vertex_coordinates->data)[k6+1];
976      xv1=((double *)vertex_coordinates->data)[k6+2]; yv1=((double *)vertex_coordinates->data)[k6+3];
977      xv2=((double *)vertex_coordinates->data)[k6+4]; yv2=((double *)vertex_coordinates->data)[k6+5];
978     
979      // Get the centroid coordinates
980      coord_index=2*k;
981      x=((double *)centroid_coordinates->data)[coord_index];
982      y=((double *)centroid_coordinates->data)[coord_index+1];
983     
984      // Store x- and y- differentials for the vertices of the FV triangle relative to the centroid
985      dxv0=xv0-x; dxv1=xv1-x; dxv2=xv2-x;
986      dyv0=yv0-y; dyv1=yv1-y; dyv2=yv2-y;
987    }
988
989
990   
991   
992   
993           
994    if (((long *)number_of_boundaries->data)[k]<=1){
995   
996      //==============================================
997      // Number of boundaries <= 1
998      //==============================================   
999   
1000   
1001      // If no boundaries, auxiliary triangle is formed from the centroids of the three neighbours
1002      // If one boundary, auxiliary triangle is formed from this centroid and its two neighbours
1003      k0=((long *)surrogate_neighbours->data)[k3];
1004      k1=((long *)surrogate_neighbours->data)[k3+1];
1005      k2=((long *)surrogate_neighbours->data)[k3+2];
1006     
1007      // Get the auxiliary triangle's vertex coordinates (really the centroids of neighbouring triangles)
1008      coord_index=2*k0;
1009      x0=((double *)centroid_coordinates->data)[coord_index];
1010      y0=((double *)centroid_coordinates->data)[coord_index+1];
1011      coord_index=2*k1;
1012      x1=((double *)centroid_coordinates->data)[coord_index];
1013      y1=((double *)centroid_coordinates->data)[coord_index+1];
1014      coord_index=2*k2;
1015      x2=((double *)centroid_coordinates->data)[coord_index];
1016      y2=((double *)centroid_coordinates->data)[coord_index+1];
1017     
1018      // Store x- and y- differentials for the vertices of the auxiliary triangle
1019      dx1=x1-x0; dx2=x2-x0;
1020      dy1=y1-y0; dy2=y2-y0;
1021     
1022      // Calculate 2*area of the auxiliary triangle
1023      area2 = dy2*dx1 - dy1*dx2;//the triangle is guaranteed to be counter-clockwise
1024     
1025      // If the mesh is 'weird' near the boundary, the triangle might be flat or clockwise:
1026      if (area2<=0) {
1027        PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: negative triangle area encountered");
1028        return NULL;
1029      } 
1030     
1031      // Calculate heights of neighbouring cells
1032      hc = ((double *)stage_centroid_values->data)[k]  - ((double *)elevation_centroid_values->data)[k];
1033      h0 = ((double *)stage_centroid_values->data)[k0] - ((double *)elevation_centroid_values->data)[k0];
1034      h1 = ((double *)stage_centroid_values->data)[k1] - ((double *)elevation_centroid_values->data)[k1];
1035      h2 = ((double *)stage_centroid_values->data)[k2] - ((double *)elevation_centroid_values->data)[k2];
1036      hmin = min(hc,min(h0,min(h1,h2)));
1037     
1038     
1039      // Dry cell optimisation experiment
1040      //printf("hmin = %e\n", hmin);     
1041      //if (hmin < epsilon) {
1042        //printf("Dry\n");
1043        //continue;
1044      //}
1045
1046           
1047      //-----------------------------------
1048      // stage
1049      //-----------------------------------     
1050     
1051      // Calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
1052      dq0=((double *)stage_centroid_values->data)[k0]-((double *)stage_centroid_values->data)[k];
1053     
1054      // Calculate differentials between the vertices of the auxiliary triangle
1055      dq1=((double *)stage_centroid_values->data)[k1]-((double *)stage_centroid_values->data)[k0];
1056      dq2=((double *)stage_centroid_values->data)[k2]-((double *)stage_centroid_values->data)[k0];
1057     
1058      // Calculate the gradient of stage on the auxiliary triangle
1059      a = dy2*dq1 - dy1*dq2;
1060      a /= area2;
1061      b = dx1*dq2 - dx2*dq1;
1062      b /= area2;
1063     
1064      // Calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
1065      dqv[0]=a*dxv0+b*dyv0;
1066      dqv[1]=a*dxv1+b*dyv1;
1067      dqv[2]=a*dxv2+b*dyv2;
1068     
1069      // Now we want to find min and max of the centroid and the vertices of the auxiliary triangle
1070      // and compute jumps from the centroid to the min and max
1071      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
1072     
1073      // Playing with dry wet interface
1074      hmin = qmin;
1075      beta_tmp = beta_w;
1076      if (hmin<minimum_allowed_height)
1077        beta_tmp = beta_w_dry;
1078      limit_gradient(dqv,qmin,qmax,beta_tmp);//the gradient will be limited
1079      for (i=0;i<3;i++)
1080        ((double *)stage_vertex_values->data)[k3+i]=((double *)stage_centroid_values->data)[k]+dqv[i];
1081     
1082     
1083      //-----------------------------------
1084      // xmomentum
1085      //-----------------------------------           
1086
1087      // Calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
1088      dq0=((double *)xmom_centroid_values->data)[k0]-((double *)xmom_centroid_values->data)[k];
1089     
1090      // Calculate differentials between the vertices of the auxiliary triangle
1091      dq1=((double *)xmom_centroid_values->data)[k1]-((double *)xmom_centroid_values->data)[k0];
1092      dq2=((double *)xmom_centroid_values->data)[k2]-((double *)xmom_centroid_values->data)[k0];
1093     
1094      // Calculate the gradient of xmom on the auxiliary triangle
1095      a = dy2*dq1 - dy1*dq2;
1096      a /= area2;
1097      b = dx1*dq2 - dx2*dq1;
1098      b /= area2;
1099     
1100      // Calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
1101      dqv[0]=a*dxv0+b*dyv0;
1102      dqv[1]=a*dxv1+b*dyv1;
1103      dqv[2]=a*dxv2+b*dyv2;
1104     
1105      // Now we want to find min and max of the centroid and the vertices of the auxiliary triangle
1106      // and compute jumps from the centroid to the min and max
1107      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
1108      beta_tmp = beta_uh;
1109      if (hmin<minimum_allowed_height)
1110        beta_tmp = beta_uh_dry;
1111      limit_gradient(dqv,qmin,qmax,beta_tmp);//the gradient will be limited
1112      for (i=0;i<3;i++)
1113        ((double *)xmom_vertex_values->data)[k3+i]=((double *)xmom_centroid_values->data)[k]+dqv[i];
1114     
1115     
1116      //-----------------------------------
1117      // ymomentum
1118      //-----------------------------------                 
1119
1120      // Calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
1121      dq0=((double *)ymom_centroid_values->data)[k0]-((double *)ymom_centroid_values->data)[k];
1122     
1123      // Calculate differentials between the vertices of the auxiliary triangle
1124      dq1=((double *)ymom_centroid_values->data)[k1]-((double *)ymom_centroid_values->data)[k0];
1125      dq2=((double *)ymom_centroid_values->data)[k2]-((double *)ymom_centroid_values->data)[k0];
1126     
1127      // Calculate the gradient of xmom on the auxiliary triangle
1128      a = dy2*dq1 - dy1*dq2;
1129      a /= area2;
1130      b = dx1*dq2 - dx2*dq1;
1131      b /= area2;
1132     
1133      // Calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
1134      dqv[0]=a*dxv0+b*dyv0;
1135      dqv[1]=a*dxv1+b*dyv1;
1136      dqv[2]=a*dxv2+b*dyv2;
1137     
1138      // Now we want to find min and max of the centroid and the vertices of the auxiliary triangle
1139      // and compute jumps from the centroid to the min and max
1140      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
1141      beta_tmp = beta_vh;
1142      if (hmin<minimum_allowed_height)
1143        beta_tmp = beta_vh_dry;
1144      limit_gradient(dqv,qmin,qmax,beta_tmp);//the gradient will be limited
1145      for (i=0;i<3;i++)
1146        ((double *)ymom_vertex_values->data)[k3+i]=((double *)ymom_centroid_values->data)[k]+dqv[i];
1147    } // End number_of_boundaries <=1
1148    else{
1149
1150      //==============================================
1151      // Number of boundaries == 2
1152      //==============================================       
1153       
1154      // One internal neighbour and gradient is in direction of the neighbour's centroid
1155     
1156      // Find the only internal neighbour
1157      for (k2=k3;k2<k3+3;k2++){//k2 just indexes the edges of triangle k
1158        if (((long *)surrogate_neighbours->data)[k2]!=k)//find internal neighbour of triabngle k
1159          break;
1160      }
1161      if ((k2==k3+3)) {//if we didn't find an internal neighbour
1162        PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: Internal neighbour not found");     
1163        return NULL;//error
1164      }
1165     
1166      k1=((long *)surrogate_neighbours->data)[k2];
1167     
1168      // The coordinates of the triangle are already (x,y). Get centroid of the neighbour (x1,y1)
1169      coord_index=2*k1;
1170      x1=((double *)centroid_coordinates->data)[coord_index];
1171      y1=((double *)centroid_coordinates->data)[coord_index+1];
1172     
1173      // Compute x- and y- distances between the centroid of the FV triangle and that of its neighbour
1174      dx1=x1-x; dy1=y1-y;
1175     
1176      // Set area2 as the square of the distance
1177      area2=dx1*dx1+dy1*dy1;
1178     
1179      // Set dx2=(x1-x0)/((x1-x0)^2+(y1-y0)^2) and dy2=(y1-y0)/((x1-x0)^2+(y1-y0)^2) which
1180      // respectively correspond to the x- and y- gradients of the conserved quantities
1181      dx2=1.0/area2;
1182      dy2=dx2*dy1;
1183      dx2*=dx1;
1184     
1185     
1186     
1187      //-----------------------------------
1188      // stage
1189      //-----------------------------------           
1190
1191      // Compute differentials
1192      dq1=((double *)stage_centroid_values->data)[k1]-((double *)stage_centroid_values->data)[k];
1193     
1194      // Calculate the gradient between the centroid of the FV triangle and that of its neighbour
1195      a=dq1*dx2;
1196      b=dq1*dy2;
1197     
1198      // Calculate provisional vertex jumps, to be limited
1199      dqv[0]=a*dxv0+b*dyv0;
1200      dqv[1]=a*dxv1+b*dyv1;
1201      dqv[2]=a*dxv2+b*dyv2;
1202     
1203      // Now limit the jumps
1204      if (dq1>=0.0){
1205        qmin=0.0;
1206        qmax=dq1;
1207      }
1208      else{
1209        qmin=dq1;
1210        qmax=0.0;
1211      }
1212     
1213     
1214      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
1215      for (i=0;i<3;i++)
1216        ((double *)stage_vertex_values->data)[k3+i]=((double *)stage_centroid_values->data)[k]+dqv[i];
1217     
1218      //-----------------------------------
1219      // xmomentum
1220      //-----------------------------------                       
1221     
1222      // Compute differentials
1223      dq1=((double *)xmom_centroid_values->data)[k1]-((double *)xmom_centroid_values->data)[k];
1224     
1225      // Calculate the gradient between the centroid of the FV triangle and that of its neighbour
1226      a=dq1*dx2;
1227      b=dq1*dy2;
1228     
1229      // Calculate provisional vertex jumps, to be limited
1230      dqv[0]=a*dxv0+b*dyv0;
1231      dqv[1]=a*dxv1+b*dyv1;
1232      dqv[2]=a*dxv2+b*dyv2;
1233     
1234      // Now limit the jumps
1235      if (dq1>=0.0){
1236        qmin=0.0;
1237        qmax=dq1;
1238      }
1239      else{
1240        qmin=dq1;
1241        qmax=0.0;
1242      }
1243      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
1244      for (i=0;i<3;i++)
1245        ((double *)xmom_vertex_values->data)[k3+i]=((double *)xmom_centroid_values->data)[k]+dqv[i];
1246     
1247      //-----------------------------------
1248      // ymomentum
1249      //-----------------------------------                       
1250
1251      // Compute differentials
1252      dq1=((double *)ymom_centroid_values->data)[k1]-((double *)ymom_centroid_values->data)[k];
1253     
1254      // Calculate the gradient between the centroid of the FV triangle and that of its neighbour
1255      a=dq1*dx2;
1256      b=dq1*dy2;
1257     
1258      // Calculate provisional vertex jumps, to be limited
1259      dqv[0]=a*dxv0+b*dyv0;
1260      dqv[1]=a*dxv1+b*dyv1;
1261      dqv[2]=a*dxv2+b*dyv2;
1262     
1263      // Now limit the jumps
1264      if (dq1>=0.0){
1265        qmin=0.0;
1266        qmax=dq1;
1267      }
1268      else{
1269        qmin=dq1;
1270        qmax=0.0;
1271      }
1272      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
1273      for (i=0;i<3;i++)
1274        ((double *)ymom_vertex_values->data)[k3+i]=((double *)ymom_centroid_values->data)[k]+dqv[i];
1275    }//else [number_of_boundaries==2]
1276  }//for k=0 to number_of_elements-1
1277 
1278  return Py_BuildValue("");
1279}//extrapolate_second-order_sw
1280
1281
1282PyObject *rotate(PyObject *self, PyObject *args, PyObject *kwargs) {
1283  //
1284  // r = rotate(q, normal, direction=1)
1285  //
1286  // Where q is assumed to be a Float numeric array of length 3 and
1287  // normal a Float numeric array of length 2.
1288
1289  // FIXME(Ole): I don't think this is used anymore
1290
1291  PyObject *Q, *Normal;
1292  PyArrayObject *q, *r, *normal;
1293
1294  static char *argnames[] = {"q", "normal", "direction", NULL};
1295  int dimensions[1], i, direction=1;
1296  double n1, n2;
1297
1298  // Convert Python arguments to C
1299  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames,
1300                                   &Q, &Normal, &direction)) {
1301    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: rotate could not parse input arguments");
1302    return NULL;
1303  } 
1304
1305  //Input checks (convert sequences into numeric arrays)
1306  q = (PyArrayObject *)
1307    PyArray_ContiguousFromObject(Q, PyArray_DOUBLE, 0, 0);
1308  normal = (PyArrayObject *)
1309    PyArray_ContiguousFromObject(Normal, PyArray_DOUBLE, 0, 0);
1310
1311
1312  if (normal -> dimensions[0] != 2) {
1313    PyErr_SetString(PyExc_RuntimeError, "Normal vector must have 2 components");
1314    return NULL;
1315  }
1316
1317  //Allocate space for return vector r (don't DECREF)
1318  dimensions[0] = 3;
1319  r = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
1320
1321  //Copy
1322  for (i=0; i<3; i++) {
1323    ((double *) (r -> data))[i] = ((double *) (q -> data))[i];
1324  }
1325
1326  //Get normal and direction
1327  n1 = ((double *) normal -> data)[0];
1328  n2 = ((double *) normal -> data)[1];
1329  if (direction == -1) n2 = -n2;
1330
1331  //Rotate
1332  _rotate((double *) r -> data, n1, n2);
1333
1334  //Release numeric arrays
1335  Py_DECREF(q);
1336  Py_DECREF(normal);
1337
1338  //return result using PyArray to avoid memory leak
1339  return PyArray_Return(r);
1340}
1341
1342PyObject *compute_fluxes_ext_central(PyObject *self, PyObject *args) {
1343  /*Compute all fluxes and the timestep suitable for all volumes
1344    in domain.
1345
1346    Compute total flux for each conserved quantity using "flux_function_central"
1347
1348    Fluxes across each edge are scaled by edgelengths and summed up
1349    Resulting flux is then scaled by area and stored in
1350    explicit_update for each of the three conserved quantities
1351    stage, xmomentum and ymomentum
1352
1353    The maximal allowable speed computed by the flux_function for each volume
1354    is converted to a timestep that must not be exceeded. The minimum of
1355    those is computed as the next overall timestep.
1356
1357    Python call:
1358    domain.timestep = compute_fluxes(timestep,
1359                                     domain.epsilon,
1360                                     domain.H0,
1361                                     domain.g,
1362                                     domain.neighbours,
1363                                     domain.neighbour_edges,
1364                                     domain.normals,
1365                                     domain.edgelengths,
1366                                     domain.radii,
1367                                     domain.areas,
1368                                     tri_full_flag,
1369                                     Stage.edge_values,
1370                                     Xmom.edge_values,
1371                                     Ymom.edge_values,
1372                                     Bed.edge_values,
1373                                     Stage.boundary_values,
1374                                     Xmom.boundary_values,
1375                                     Ymom.boundary_values,
1376                                     Stage.explicit_update,
1377                                     Xmom.explicit_update,
1378                                     Ymom.explicit_update,
1379                                     already_computed_flux,
1380                                     optimise_dry_cells)                                     
1381
1382
1383    Post conditions:
1384      domain.explicit_update is reset to computed flux values
1385      domain.timestep is set to the largest step satisfying all volumes.
1386
1387
1388  */
1389
1390
1391  PyArrayObject *neighbours, *neighbour_edges,
1392    *normals, *edgelengths, *radii, *areas,
1393    *tri_full_flag,
1394    *stage_edge_values,
1395    *xmom_edge_values,
1396    *ymom_edge_values,
1397    *bed_edge_values,
1398    *stage_boundary_values,
1399    *xmom_boundary_values,
1400    *ymom_boundary_values,
1401    *stage_explicit_update,
1402    *xmom_explicit_update,
1403    *ymom_explicit_update,
1404    *already_computed_flux, //Tracks whether the flux across an edge has already been computed
1405    *max_speed_array; //Keeps track of max speeds for each triangle
1406
1407
1408  // Local variables
1409  double timestep, max_speed, epsilon, g, H0, length, area;
1410  int optimise_dry_cells=0; // Optimisation flag 
1411  double normal[2], ql[3], qr[3], zl, zr;
1412  double edgeflux[3]; // Work array for summing up fluxes
1413
1414  int number_of_elements, k, i, m, n;
1415
1416  int ki, nm=0, ki2; // Index shorthands
1417  static long call=1; // Static local variable flagging already computed flux
1418
1419
1420  // Convert Python arguments to C
1421  if (!PyArg_ParseTuple(args, "ddddOOOOOOOOOOOOOOOOOOOi",
1422                        &timestep,
1423                        &epsilon,
1424                        &H0,
1425                        &g,
1426                        &neighbours,
1427                        &neighbour_edges,
1428                        &normals,
1429                        &edgelengths, &radii, &areas,
1430                        &tri_full_flag,
1431                        &stage_edge_values,
1432                        &xmom_edge_values,
1433                        &ymom_edge_values,
1434                        &bed_edge_values,
1435                        &stage_boundary_values,
1436                        &xmom_boundary_values,
1437                        &ymom_boundary_values,
1438                        &stage_explicit_update,
1439                        &xmom_explicit_update,
1440                        &ymom_explicit_update,
1441                        &already_computed_flux,
1442                        &max_speed_array,
1443                        &optimise_dry_cells)) {
1444    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
1445    return NULL;
1446  }
1447 
1448 
1449  number_of_elements = stage_edge_values -> dimensions[0];
1450
1451  call++; // Flag 'id' of flux calculation for this timestep
1452 
1453  // Set explicit_update to zero for all conserved_quantities.
1454  // This assumes compute_fluxes called before forcing terms
1455  for (k=0; k<number_of_elements; k++) {
1456    ((double *) stage_explicit_update -> data)[k]=0.0;
1457    ((double *) xmom_explicit_update -> data)[k]=0.0;
1458    ((double *) ymom_explicit_update -> data)[k]=0.0; 
1459  }
1460 
1461  // For all triangles
1462  for (k=0; k<number_of_elements; k++) {
1463 
1464    // Loop through neighbours and compute edge flux for each 
1465    for (i=0; i<3; i++) {
1466      ki = k*3+i; // Linear index (triangle k, edge i)
1467     
1468      if (((long *) already_computed_flux->data)[ki] == call)
1469        // We've already computed the flux across this edge
1470        continue;
1471       
1472       
1473      ql[0] = ((double *) stage_edge_values -> data)[ki];
1474      ql[1] = ((double *) xmom_edge_values -> data)[ki];
1475      ql[2] = ((double *) ymom_edge_values -> data)[ki];
1476      zl =    ((double *) bed_edge_values -> data)[ki];
1477
1478      // Quantities at neighbour on nearest face
1479      n = ((long *) neighbours -> data)[ki];
1480      if (n < 0) {
1481        m = -n-1; // Convert negative flag to index
1482       
1483        qr[0] = ((double *) stage_boundary_values -> data)[m];
1484        qr[1] = ((double *) xmom_boundary_values -> data)[m];
1485        qr[2] = ((double *) ymom_boundary_values -> data)[m];
1486        zr = zl; //Extend bed elevation to boundary
1487      } else {
1488        m = ((long *) neighbour_edges -> data)[ki];
1489        nm = n*3+m; // Linear index (triangle n, edge m)
1490       
1491        qr[0] = ((double *) stage_edge_values -> data)[nm];
1492        qr[1] = ((double *) xmom_edge_values -> data)[nm];
1493        qr[2] = ((double *) ymom_edge_values -> data)[nm];
1494        zr =    ((double *) bed_edge_values -> data)[nm];
1495      }
1496     
1497     
1498      if (optimise_dry_cells) {     
1499        // Check if flux calculation is necessary across this edge
1500        // This check will exclude dry cells.
1501        // This will also optimise cases where zl != zr as
1502        // long as both are dry
1503
1504        if ( fabs(ql[0] - zl) < epsilon && 
1505             fabs(qr[0] - zr) < epsilon ) {
1506          // Cell boundary is dry
1507         
1508          ((long *) already_computed_flux -> data)[ki] = call; // #k Done       
1509          if (n>=0)
1510            ((long *) already_computed_flux -> data)[nm] = call; // #n Done
1511       
1512          max_speed = 0.0;
1513          continue;
1514        }
1515      }
1516     
1517           
1518      // Outward pointing normal vector (domain.normals[k, 2*i:2*i+2])
1519      ki2 = 2*ki; //k*6 + i*2
1520      normal[0] = ((double *) normals -> data)[ki2];
1521      normal[1] = ((double *) normals -> data)[ki2+1];
1522     
1523
1524      // Edge flux computation (triangle k, edge i)
1525      flux_function_central(ql, qr, zl, zr,
1526                            normal[0], normal[1],
1527                            epsilon, H0, g,
1528                            edgeflux, &max_speed);
1529     
1530     
1531      // Multiply edgeflux by edgelength
1532      length = ((double *) edgelengths -> data)[ki];
1533      edgeflux[0] *= length;           
1534      edgeflux[1] *= length;           
1535      edgeflux[2] *= length;                       
1536     
1537     
1538      // Update triangle k with flux from edge i
1539      ((double *) stage_explicit_update -> data)[k] -= edgeflux[0];
1540      ((double *) xmom_explicit_update -> data)[k] -= edgeflux[1];
1541      ((double *) ymom_explicit_update -> data)[k] -= edgeflux[2];
1542     
1543      ((long *) already_computed_flux -> data)[ki] = call; // #k Done
1544     
1545     
1546      // Update neighbour n with same flux but reversed sign
1547      if (n>=0){
1548        ((double *) stage_explicit_update -> data)[n] += edgeflux[0];
1549        ((double *) xmom_explicit_update -> data)[n] += edgeflux[1];
1550        ((double *) ymom_explicit_update -> data)[n] += edgeflux[2];
1551       
1552        ((long *) already_computed_flux -> data)[nm] = call; // #n Done
1553      }
1554     
1555     
1556      // Update timestep based on edge i and possibly neighbour n
1557      if ( ((long *) tri_full_flag -> data)[k] == 1) {
1558        if (max_speed > epsilon) {
1559          timestep = min(timestep, ((double *) radii -> data)[k]/max_speed);
1560          if (n>=0) 
1561            timestep = min(timestep, ((double *) radii -> data)[n]/max_speed);
1562        }
1563      }
1564     
1565    } // End edge i
1566   
1567   
1568    // Normalise triangle k by area and store for when all conserved
1569    // quantities get updated
1570    area = ((double *) areas -> data)[k];
1571    ((double *) stage_explicit_update -> data)[k] /= area;
1572    ((double *) xmom_explicit_update -> data)[k] /= area;
1573    ((double *) ymom_explicit_update -> data)[k] /= area;
1574   
1575   
1576    // Keep track of maximal speeds
1577    ((double *) max_speed_array -> data)[k] = max_speed;   
1578   
1579  } // End triangle k
1580 
1581  return Py_BuildValue("d", timestep);
1582}
1583
1584
1585PyObject *compute_fluxes_ext_kinetic(PyObject *self, PyObject *args) {
1586  /*Compute all fluxes and the timestep suitable for all volumes
1587    in domain.
1588
1589    Compute total flux for each conserved quantity using "flux_function_central"
1590
1591    Fluxes across each edge are scaled by edgelengths and summed up
1592    Resulting flux is then scaled by area and stored in
1593    explicit_update for each of the three conserved quantities
1594    stage, xmomentum and ymomentum
1595
1596    The maximal allowable speed computed by the flux_function for each volume
1597    is converted to a timestep that must not be exceeded. The minimum of
1598    those is computed as the next overall timestep.
1599
1600    Python call:
1601    domain.timestep = compute_fluxes(timestep,
1602                                     domain.epsilon,
1603                                     domain.H0,
1604                                     domain.g,
1605                                     domain.neighbours,
1606                                     domain.neighbour_edges,
1607                                     domain.normals,
1608                                     domain.edgelengths,
1609                                     domain.radii,
1610                                     domain.areas,
1611                                     Stage.edge_values,
1612                                     Xmom.edge_values,
1613                                     Ymom.edge_values,
1614                                     Bed.edge_values,
1615                                     Stage.boundary_values,
1616                                     Xmom.boundary_values,
1617                                     Ymom.boundary_values,
1618                                     Stage.explicit_update,
1619                                     Xmom.explicit_update,
1620                                     Ymom.explicit_update,
1621                                     already_computed_flux)
1622
1623
1624    Post conditions:
1625      domain.explicit_update is reset to computed flux values
1626      domain.timestep is set to the largest step satisfying all volumes.
1627
1628
1629  */
1630
1631
1632  PyArrayObject *neighbours, *neighbour_edges,
1633    *normals, *edgelengths, *radii, *areas,
1634    *tri_full_flag,
1635    *stage_edge_values,
1636    *xmom_edge_values,
1637    *ymom_edge_values,
1638    *bed_edge_values,
1639    *stage_boundary_values,
1640    *xmom_boundary_values,
1641    *ymom_boundary_values,
1642    *stage_explicit_update,
1643    *xmom_explicit_update,
1644    *ymom_explicit_update,
1645    *already_computed_flux;//tracks whether the flux across an edge has already been computed
1646
1647
1648  //Local variables
1649  double timestep, max_speed, epsilon, g, H0;
1650  double normal[2], ql[3], qr[3], zl, zr;
1651  double edgeflux[3]; //Work arrays for summing up fluxes
1652
1653  int number_of_elements, k, i, m, n;
1654  int ki, nm=0, ki2; //Index shorthands
1655  static long call=1;
1656
1657
1658  // Convert Python arguments to C
1659  if (!PyArg_ParseTuple(args, "ddddOOOOOOOOOOOOOOOOOO",
1660                        &timestep,
1661                        &epsilon,
1662                        &H0,
1663                        &g,
1664                        &neighbours,
1665                        &neighbour_edges,
1666                        &normals,
1667                        &edgelengths, &radii, &areas,
1668                        &tri_full_flag,
1669                        &stage_edge_values,
1670                        &xmom_edge_values,
1671                        &ymom_edge_values,
1672                        &bed_edge_values,
1673                        &stage_boundary_values,
1674                        &xmom_boundary_values,
1675                        &ymom_boundary_values,
1676                        &stage_explicit_update,
1677                        &xmom_explicit_update,
1678                        &ymom_explicit_update,
1679                        &already_computed_flux)) {
1680    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
1681    return NULL;
1682  }
1683  number_of_elements = stage_edge_values -> dimensions[0];
1684  call++;//a static local variable to which already_computed_flux is compared
1685  //set explicit_update to zero for all conserved_quantities.
1686  //This assumes compute_fluxes called before forcing terms
1687  for (k=0; k<number_of_elements; k++) {
1688    ((double *) stage_explicit_update -> data)[k]=0.0;
1689    ((double *) xmom_explicit_update -> data)[k]=0.0;
1690    ((double *) ymom_explicit_update -> data)[k]=0.0;
1691  }
1692  //Loop through neighbours and compute edge flux for each
1693  for (k=0; k<number_of_elements; k++) {
1694    for (i=0; i<3; i++) {
1695      ki = k*3+i;
1696      if (((long *) already_computed_flux->data)[ki]==call)//we've already computed the flux across this edge
1697        continue;
1698      ql[0] = ((double *) stage_edge_values -> data)[ki];
1699      ql[1] = ((double *) xmom_edge_values -> data)[ki];
1700      ql[2] = ((double *) ymom_edge_values -> data)[ki];
1701      zl =    ((double *) bed_edge_values -> data)[ki];
1702
1703      //Quantities at neighbour on nearest face
1704      n = ((long *) neighbours -> data)[ki];
1705      if (n < 0) {
1706        m = -n-1; //Convert negative flag to index
1707        qr[0] = ((double *) stage_boundary_values -> data)[m];
1708        qr[1] = ((double *) xmom_boundary_values -> data)[m];
1709        qr[2] = ((double *) ymom_boundary_values -> data)[m];
1710        zr = zl; //Extend bed elevation to boundary
1711      } else {
1712        m = ((long *) neighbour_edges -> data)[ki];
1713        nm = n*3+m;
1714        qr[0] = ((double *) stage_edge_values -> data)[nm];
1715        qr[1] = ((double *) xmom_edge_values -> data)[nm];
1716        qr[2] = ((double *) ymom_edge_values -> data)[nm];
1717        zr =    ((double *) bed_edge_values -> data)[nm];
1718      }
1719      // Outward pointing normal vector
1720      // normal = domain.normals[k, 2*i:2*i+2]
1721      ki2 = 2*ki; //k*6 + i*2
1722      normal[0] = ((double *) normals -> data)[ki2];
1723      normal[1] = ((double *) normals -> data)[ki2+1];
1724      //Edge flux computation
1725      flux_function_kinetic(ql, qr, zl, zr,
1726                    normal[0], normal[1],
1727                    epsilon, H0, g,
1728                    edgeflux, &max_speed);
1729      //update triangle k
1730      ((long *) already_computed_flux->data)[ki]=call;
1731      ((double *) stage_explicit_update -> data)[k] -= edgeflux[0]*((double *) edgelengths -> data)[ki];
1732      ((double *) xmom_explicit_update -> data)[k] -= edgeflux[1]*((double *) edgelengths -> data)[ki];
1733      ((double *) ymom_explicit_update -> data)[k] -= edgeflux[2]*((double *) edgelengths -> data)[ki];
1734      //update the neighbour n
1735      if (n>=0){
1736        ((long *) already_computed_flux->data)[nm]=call;
1737        ((double *) stage_explicit_update -> data)[n] += edgeflux[0]*((double *) edgelengths -> data)[nm];
1738        ((double *) xmom_explicit_update -> data)[n] += edgeflux[1]*((double *) edgelengths -> data)[nm];
1739        ((double *) ymom_explicit_update -> data)[n] += edgeflux[2]*((double *) edgelengths -> data)[nm];
1740      }
1741      ///for (j=0; j<3; j++) {
1742        ///flux[j] -= edgeflux[j]*((double *) edgelengths -> data)[ki];
1743        ///}
1744        //Update timestep
1745        //timestep = min(timestep, domain.radii[k]/max_speed)
1746        //FIXME: SR Add parameter for CFL condition
1747    if ( ((long *) tri_full_flag -> data)[k] == 1) {
1748            if (max_speed > epsilon) {
1749                timestep = min(timestep, ((double *) radii -> data)[k]/max_speed);
1750                //maxspeed in flux_function is calculated as max(|u+a|,|u-a|)
1751                if (n>=0)
1752                    timestep = min(timestep, ((double *) radii -> data)[n]/max_speed);
1753            }
1754    }
1755    } // end for i
1756    //Normalise by area and store for when all conserved
1757    //quantities get updated
1758    ((double *) stage_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
1759    ((double *) xmom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
1760    ((double *) ymom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
1761  } //end for k
1762  return Py_BuildValue("d", timestep);
1763}
1764
1765PyObject *protect(PyObject *self, PyObject *args) {
1766  //
1767  //    protect(minimum_allowed_height, maximum_allowed_speed, wc, zc, xmomc, ymomc)
1768
1769
1770  PyArrayObject
1771  *wc,            //Stage at centroids
1772  *zc,            //Elevation at centroids
1773  *xmomc,         //Momentums at centroids
1774  *ymomc;
1775
1776
1777  int N;
1778  double minimum_allowed_height, maximum_allowed_speed, epsilon;
1779
1780  // Convert Python arguments to C
1781  if (!PyArg_ParseTuple(args, "dddOOOO",
1782                        &minimum_allowed_height,
1783                        &maximum_allowed_speed,
1784                        &epsilon,
1785                        &wc, &zc, &xmomc, &ymomc)) {
1786    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: protect could not parse input arguments");
1787    return NULL;
1788  } 
1789
1790  N = wc -> dimensions[0];
1791
1792  _protect(N,
1793           minimum_allowed_height,
1794           maximum_allowed_speed,
1795           epsilon,
1796           (double*) wc -> data,
1797           (double*) zc -> data,
1798           (double*) xmomc -> data,
1799           (double*) ymomc -> data);
1800
1801  return Py_BuildValue("");
1802}
1803
1804
1805
1806PyObject *balance_deep_and_shallow(PyObject *self, PyObject *args) {
1807  //
1808  //    balance_deep_and_shallow(wc, zc, hc, wv, zv, hv,
1809  //                             xmomc, ymomc, xmomv, ymomv)
1810
1811
1812  PyArrayObject
1813    *wc,            //Stage at centroids
1814    *zc,            //Elevation at centroids
1815    *hc,            //Height at centroids
1816    *wv,            //Stage at vertices
1817    *zv,            //Elevation at vertices
1818    *hv,            //Depths at vertices
1819    *hvbar,         //h-Limited depths at vertices
1820    *xmomc,         //Momentums at centroids and vertices
1821    *ymomc,
1822    *xmomv,
1823    *ymomv;
1824 
1825  PyObject *domain, *Tmp;
1826   
1827  double alpha_balance = 2.0;
1828  double H0;
1829
1830  int N, tight_slope_limiters; //, err;
1831
1832  // Convert Python arguments to C
1833  if (!PyArg_ParseTuple(args, "OOOOOOOOOOOO",
1834                        &domain,
1835                        &wc, &zc, &hc,
1836                        &wv, &zv, &hv, &hvbar,
1837                        &xmomc, &ymomc, &xmomv, &ymomv)) {
1838    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: balance_deep_and_shallow could not parse input arguments");
1839    return NULL;
1840  } 
1841         
1842  // Pull out parameters
1843  Tmp = PyObject_GetAttrString(domain, "alpha_balance");
1844  if (!Tmp) {
1845    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: balance_deep_and_shallow could not obtain object alpha_balance from domain");
1846    return NULL;
1847  } 
1848  alpha_balance = PyFloat_AsDouble(Tmp);
1849  Py_DECREF(Tmp);
1850
1851 
1852  Tmp = PyObject_GetAttrString(domain, "H0");
1853  if (!Tmp) {
1854    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: balance_deep_and_shallow could not obtain object H0 from domain");
1855    return NULL;
1856  } 
1857  H0 = PyFloat_AsDouble(Tmp);
1858  Py_DECREF(Tmp);
1859
1860 
1861  Tmp = PyObject_GetAttrString(domain, "tight_slope_limiters");
1862  if (!Tmp) {
1863    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: balance_deep_and_shallow could not obtain object tight_slope_limiters from domain");
1864    return NULL;
1865  } 
1866  tight_slope_limiters = PyInt_AsLong(Tmp);
1867  Py_DECREF(Tmp);
1868   
1869
1870 
1871 
1872  N = wc -> dimensions[0];
1873
1874  _balance_deep_and_shallow(N,
1875                            (double*) wc -> data,
1876                            (double*) zc -> data,
1877                            (double*) hc -> data,
1878                            (double*) wv -> data,
1879                            (double*) zv -> data,
1880                            (double*) hv -> data,
1881                            (double*) hvbar -> data,
1882                            (double*) xmomc -> data,
1883                            (double*) ymomc -> data,
1884                            (double*) xmomv -> data,
1885                            (double*) ymomv -> data,
1886                            H0,
1887                            (int) tight_slope_limiters,
1888                            alpha_balance);
1889
1890
1891  return Py_BuildValue("");
1892}
1893
1894
1895
1896PyObject *h_limiter(PyObject *self, PyObject *args) {
1897
1898  PyObject *domain, *Tmp;
1899  PyArrayObject
1900    *hv, *hc, //Depth at vertices and centroids
1901    *hvbar,   //Limited depth at vertices (return values)
1902    *neighbours;
1903
1904  int k, i, n, N, k3;
1905  int dimensions[2];
1906  double beta_h; //Safety factor (see config.py)
1907  double *hmin, *hmax, hn;
1908
1909  // Convert Python arguments to C
1910  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv)) {
1911    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: h_limiter could not parse input arguments");
1912    return NULL;
1913  } 
1914 
1915  neighbours = get_consecutive_array(domain, "neighbours");
1916
1917  //Get safety factor beta_h
1918  Tmp = PyObject_GetAttrString(domain, "beta_h");
1919  if (!Tmp) {
1920    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: h_limiter could not obtain object beta_h from domain");
1921    return NULL;
1922  } 
1923  beta_h = PyFloat_AsDouble(Tmp);
1924
1925  Py_DECREF(Tmp);
1926
1927  N = hc -> dimensions[0];
1928
1929  //Create hvbar
1930  dimensions[0] = N;
1931  dimensions[1] = 3;
1932  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
1933
1934
1935  //Find min and max of this and neighbour's centroid values
1936  hmin = malloc(N * sizeof(double));
1937  hmax = malloc(N * sizeof(double));
1938  for (k=0; k<N; k++) {
1939    k3=k*3;
1940
1941    hmin[k] = ((double*) hc -> data)[k];
1942    hmax[k] = hmin[k];
1943
1944    for (i=0; i<3; i++) {
1945      n = ((long*) neighbours -> data)[k3+i];
1946
1947      //Initialise hvbar with values from hv
1948      ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i];
1949
1950      if (n >= 0) {
1951        hn = ((double*) hc -> data)[n]; //Neighbour's centroid value
1952
1953        hmin[k] = min(hmin[k], hn);
1954        hmax[k] = max(hmax[k], hn);
1955      }
1956    }
1957  }
1958
1959  // Call underlying standard routine
1960  _limit(N, beta_h, (double*) hc -> data, (double*) hvbar -> data, hmin, hmax);
1961
1962  // // //Py_DECREF(domain); //FIXME: NEcessary?
1963  free(hmin);
1964  free(hmax);
1965
1966  //return result using PyArray to avoid memory leak
1967  return PyArray_Return(hvbar);
1968  //return Py_BuildValue("");
1969}
1970
1971PyObject *h_limiter_sw(PyObject *self, PyObject *args) {
1972  //a faster version of h_limiter above
1973  PyObject *domain, *Tmp;
1974  PyArrayObject
1975    *hv, *hc, //Depth at vertices and centroids
1976    *hvbar,   //Limited depth at vertices (return values)
1977    *neighbours;
1978
1979  int k, i, N, k3,k0,k1,k2;
1980  int dimensions[2];
1981  double beta_h; //Safety factor (see config.py)
1982  double hmin, hmax, dh[3];
1983// Convert Python arguments to C
1984  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv)) {
1985    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: h_limiter_sw could not parse input arguments");
1986    return NULL;
1987  } 
1988  neighbours = get_consecutive_array(domain, "neighbours");
1989
1990  //Get safety factor beta_h
1991  Tmp = PyObject_GetAttrString(domain, "beta_h");
1992  if (!Tmp) {
1993    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: h_limiter_sw could not obtain object beta_h from domain");
1994    return NULL;
1995  } 
1996  beta_h = PyFloat_AsDouble(Tmp);
1997
1998  Py_DECREF(Tmp);
1999
2000  N = hc -> dimensions[0];
2001
2002  //Create hvbar
2003  dimensions[0] = N;
2004  dimensions[1] = 3;
2005  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
2006  for (k=0;k<N;k++){
2007    k3=k*3;
2008    //get the ids of the neighbours
2009    k0 = ((long*) neighbours -> data)[k3];
2010    k1 = ((long*) neighbours -> data)[k3+1];
2011    k2 = ((long*) neighbours -> data)[k3+2];
2012    //set hvbar provisionally
2013    for (i=0;i<3;i++){
2014      ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i];
2015      dh[i]=((double*) hvbar -> data)[k3+i]-((double*) hc -> data)[k];
2016    }
2017    hmin=((double*) hc -> data)[k];
2018    hmax=hmin;
2019    if (k0>=0){
2020      hmin=min(hmin,((double*) hc -> data)[k0]);
2021      hmax=max(hmax,((double*) hc -> data)[k0]);
2022    }
2023    if (k1>=0){
2024      hmin=min(hmin,((double*) hc -> data)[k1]);
2025      hmax=max(hmax,((double*) hc -> data)[k1]);
2026    }
2027    if (k2>=0){
2028      hmin=min(hmin,((double*) hc -> data)[k2]);
2029      hmax=max(hmax,((double*) hc -> data)[k2]);
2030    }
2031    hmin-=((double*) hc -> data)[k];
2032    hmax-=((double*) hc -> data)[k];
2033    limit_gradient(dh,hmin,hmax,beta_h);
2034    for (i=0;i<3;i++)
2035      ((double*) hvbar -> data)[k3+i] = ((double*) hc -> data)[k]+dh[i];
2036  }
2037  return PyArray_Return(hvbar);
2038}
2039
2040PyObject *assign_windfield_values(PyObject *self, PyObject *args) {
2041  //
2042  //      assign_windfield_values(xmom_update, ymom_update,
2043  //                              s_vec, phi_vec, self.const)
2044
2045
2046
2047  PyArrayObject   //(one element per triangle)
2048  *s_vec,         //Speeds
2049  *phi_vec,       //Bearings
2050  *xmom_update,   //Momentum updates
2051  *ymom_update;
2052
2053
2054  int N;
2055  double cw;
2056
2057  // Convert Python arguments to C
2058  if (!PyArg_ParseTuple(args, "OOOOd",
2059                        &xmom_update,
2060                        &ymom_update,
2061                        &s_vec, &phi_vec,
2062                        &cw)) {
2063    PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: assign_windfield_values could not parse input arguments");
2064    return NULL;
2065  } 
2066                       
2067
2068  N = xmom_update -> dimensions[0];
2069
2070  _assign_wind_field_values(N,
2071           (double*) xmom_update -> data,
2072           (double*) ymom_update -> data,
2073           (double*) s_vec -> data,
2074           (double*) phi_vec -> data,
2075           cw);
2076
2077  return Py_BuildValue("");
2078}
2079
2080
2081
2082
2083//////////////////////////////////////////
2084// Method table for python module
2085static struct PyMethodDef MethodTable[] = {
2086  /* The cast of the function is necessary since PyCFunction values
2087   * only take two PyObject* parameters, and rotate() takes
2088   * three.
2089   */
2090
2091  {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
2092  {"extrapolate_second_order_sw", extrapolate_second_order_sw, METH_VARARGS, "Print out"},
2093  {"compute_fluxes_ext_central", compute_fluxes_ext_central, METH_VARARGS, "Print out"},
2094  {"compute_fluxes_ext_kinetic", compute_fluxes_ext_kinetic, METH_VARARGS, "Print out"},
2095  {"gravity", gravity, METH_VARARGS, "Print out"},
2096  {"manning_friction", manning_friction, METH_VARARGS, "Print out"},
2097  {"balance_deep_and_shallow", balance_deep_and_shallow,
2098   METH_VARARGS, "Print out"},
2099  {"h_limiter", h_limiter,
2100   METH_VARARGS, "Print out"},
2101  {"h_limiter_sw", h_limiter_sw,
2102   METH_VARARGS, "Print out"},
2103  {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"},
2104  {"assign_windfield_values", assign_windfield_values,
2105   METH_VARARGS | METH_KEYWORDS, "Print out"},
2106  //{"distribute_to_vertices_and_edges",
2107  // distribute_to_vertices_and_edges, METH_VARARGS},
2108  //{"update_conserved_quantities",
2109  // update_conserved_quantities, METH_VARARGS},
2110  //{"set_initialcondition",
2111  // set_initialcondition, METH_VARARGS},
2112  {NULL, NULL}
2113};
2114
2115// Module initialisation
2116void initshallow_water_ext(void){
2117  Py_InitModule("shallow_water_ext", MethodTable);
2118
2119  import_array();     //Necessary for handling of NumPY structures
2120}
Note: See TracBrowser for help on using the repository browser.