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

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

Prepared tests for making new slope limiters default. Still a few unprepared tests remaining and
one example in test_data_manager where small timesteps are generated.

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