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

Last change on this file since 3750 was 3730, checked in by ole, 18 years ago

Added proper error messages to return NULL in c extensions.
Fixed up some indentation issues as well

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