source: inundation/ga/storm_surge/pyvolution/shallow_water_ext.c @ 1508

Last change on this file since 1508 was 1508, checked in by matthew, 19 years ago

To avoid computing the flux function at each internal edge twice, we now call the C implementation of compute_fluxes with the extra integer vector argument already_computed_flux. This is an array of dimension (N,3) in python (or 3N in C) and thus each entry corresponds to a triangle-edge pair. If triangle t has neighbour n across its i-th edge, and this edge is the m-th edge of triangle n, then we update this edge's flux contribution to explicit_update for both triangle n and triangle t. Both corresponding entries of already_computed_flux will be incremented so that, when we come to edge m of triangle n, we know that the update across this edge has already been done.
The array already_computed_flux is defined and initialised to zero in domain.py.

For run_profile.py, with N=128, the version of compute_fluxes in which each edge was computed twice consumed 13.64 seconds (averaged over 3 runs). By keeping track of which edges have been computed, compute_fluxes now consumes 8.68 seconds.

File size: 40.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// Computational function for flux computation (using stage w=z+h)
128int flux_function(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
235void _manning_friction(double g, double eps, int N,
236                       double* w, double* z,
237                       double* uh, double* vh,
238                       double* eta, double* xmom, double* ymom) {
239
240  int k;
241  double S, h;
242
243  for (k=0; k<N; k++) {
244    if (eta[k] > eps) {
245      h = w[k]-z[k];
246      if (h >= eps) {
247        S = -g * eta[k]*eta[k] * sqrt((uh[k]*uh[k] + vh[k]*vh[k]));
248        //S /= pow(h, 7.0/3);      //Expensive (on Ole's home computer)
249        S /= exp(7.0/3.0*log(h));      //seems to save about 15% over manning_friction
250        //S /= h*h*(1 + h/3.0 - h*h/9.0); //FIXME: Could use a Taylor expansion
251
252
253        //Update momentum
254        xmom[k] += S*uh[k];
255        ymom[k] += S*vh[k];
256      }
257    }
258  }
259}
260
261
262
263int _balance_deep_and_shallow(int N,
264                              double* wc,
265                              double* zc,
266                              double* hc,
267                              double* wv,
268                              double* zv,
269                              double* hv,
270                              double* hvbar,
271                              double* xmomc,
272                              double* ymomc,
273                              double* xmomv,
274                              double* ymomv) {
275
276  int k, k3, i;
277  double dz, hmin, alpha;
278
279  //Compute linear combination between w-limited stages and
280  //h-limited stages close to the bed elevation.
281
282  for (k=0; k<N; k++) {
283    // Compute maximal variation in bed elevation
284    // This quantitiy is
285    //     dz = max_i abs(z_i - z_c)
286    // and it is independent of dimension
287    // In the 1d case zc = (z0+z1)/2
288    // In the 2d case zc = (z0+z1+z2)/3
289
290    k3 = 3*k;
291
292    //FIXME: Try with this one precomputed
293    dz = 0.0;
294    hmin = hv[k3];
295    for (i=0; i<3; i++) {
296      dz = max(dz, fabs(zv[k3+i]-zc[k]));
297      hmin = min(hmin, hv[k3+i]);
298    }
299
300
301    //Create alpha in [0,1], where alpha==0 means using the h-limited
302    //stage and alpha==1 means using the w-limited stage as
303    //computed by the gradient limiter (both 1st or 2nd order)
304    //
305    //If hmin > dz/2 then alpha = 1 and the bed will have no effect
306    //If hmin < 0 then alpha = 0 reverting to constant height above bed.
307
308
309    if (dz > 0.0)
310      //if (hmin<0.0)
311      //        alpha = 0.0;
312      //else
313      //  alpha = max( min( hc[k]/dz, 1.0), 0.0 );
314      alpha = max( min( 2.0*hmin/dz, 1.0), 0.0 );
315    else
316      alpha = 1.0;  //Flat bed
317
318    //alpha = 1.0;
319
320    //printf("dz = %.3f, alpha = %.8f\n", dz, alpha);
321
322    //  Let
323    //
324    //    wvi be the w-limited stage (wvi = zvi + hvi)
325    //    wvi- be the h-limited state (wvi- = zvi + hvi-)
326    //
327    //
328    //  where i=0,1,2 denotes the vertex ids
329    //
330    //  Weighted balance between w-limited and h-limited stage is
331    //
332    //    wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
333    //
334    //  It follows that the updated wvi is
335    //    wvi := zvi + (1-alpha)*hvi- + alpha*hvi
336    //
337    //   Momentum is balanced between constant and limited
338
339    if (alpha < 1) {
340      for (i=0; i<3; i++) {
341        wv[k3+i] = zv[k3+i] + (1-alpha)*hvbar[k3+i] + alpha*hv[k3+i];
342
343        //Update momentum as a linear combination of
344        //xmomc and ymomc (shallow) and momentum
345        //from extrapolator xmomv and ymomv (deep).
346        xmomv[k3+i] = (1-alpha)*xmomc[k] + alpha*xmomv[k3+i];
347        ymomv[k3+i] = (1-alpha)*ymomc[k] + alpha*ymomv[k3+i];
348      }
349    }
350  }
351  return 0;
352}
353
354
355
356int _protect(int N,
357             double minimum_allowed_height,
358             double* wc,
359             double* zc,
360             double* xmomc,
361             double* ymomc) {
362
363  int k;
364  double hc;
365
366  //Protect against initesimal and negative heights
367
368  for (k=0; k<N; k++) {
369    hc = wc[k] - zc[k];
370
371    if (hc < minimum_allowed_height) {
372      wc[k] = zc[k];
373      xmomc[k] = 0.0;
374      ymomc[k] = 0.0;
375    }
376
377  }
378  return 0;
379}
380
381
382
383
384
385
386
387
388int _assign_wind_field_values(int N,
389                              double* xmom_update,
390                              double* ymom_update,
391                              double* s_vec,
392                              double* phi_vec,
393                              double cw) {
394
395  //Assign windfield values to momentum updates
396
397  int k;
398  double S, s, phi, u, v;
399
400  for (k=0; k<N; k++) {
401
402    s = s_vec[k];
403    phi = phi_vec[k];
404
405    //Convert to radians
406    phi = phi*pi/180;
407
408    //Compute velocity vector (u, v)
409    u = s*cos(phi);
410    v = s*sin(phi);
411
412    //Compute wind stress
413    S = cw * sqrt(u*u + v*v);
414    xmom_update[k] += S*u;
415    ymom_update[k] += S*v;
416  }
417  return 0;
418}
419
420
421
422///////////////////////////////////////////////////////////////////
423// Gateways to Python
424
425PyObject *gravity(PyObject *self, PyObject *args) {
426  //
427  //  gravity(g, h, v, x, xmom, ymom)
428  //
429
430
431  PyArrayObject *h, *v, *x, *xmom, *ymom;
432  int k, i, N, k3, k6;
433  double g, avg_h, zx, zy;
434  double x0, y0, x1, y1, x2, y2, z0, z1, z2;
435
436  if (!PyArg_ParseTuple(args, "dOOOOO",
437                        &g, &h, &v, &x,
438                        &xmom, &ymom))
439    return NULL;
440
441  N = h -> dimensions[0];
442  for (k=0; k<N; k++) {
443    k3 = 3*k;  // base index
444    k6 = 6*k;  // base index
445
446    avg_h = 0.0;
447    for (i=0; i<3; i++) {
448      avg_h += ((double *) h -> data)[k3+i];
449    }
450    avg_h /= 3;
451
452
453    //Compute bed slope
454    x0 = ((double*) x -> data)[k6 + 0];
455    y0 = ((double*) x -> data)[k6 + 1];
456    x1 = ((double*) x -> data)[k6 + 2];
457    y1 = ((double*) x -> data)[k6 + 3];
458    x2 = ((double*) x -> data)[k6 + 4];
459    y2 = ((double*) x -> data)[k6 + 5];
460
461
462    z0 = ((double*) v -> data)[k3 + 0];
463    z1 = ((double*) v -> data)[k3 + 1];
464    z2 = ((double*) v -> data)[k3 + 2];
465
466    _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy);
467
468    //Update momentum
469    ((double*) xmom -> data)[k] += -g*zx*avg_h;
470    ((double*) ymom -> data)[k] += -g*zy*avg_h;
471  }
472
473  return Py_BuildValue("");
474}
475
476
477PyObject *manning_friction(PyObject *self, PyObject *args) {
478  //
479  // manning_friction(g, eps, h, uh, vh, eta, xmom_update, ymom_update)
480  //
481
482
483  PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom;
484  int N;
485  double g, eps;
486
487  if (!PyArg_ParseTuple(args, "ddOOOOOOO",
488                        &g, &eps, &w, &z, &uh, &vh, &eta,
489                        &xmom, &ymom))
490    return NULL;
491
492  N = w -> dimensions[0];
493  _manning_friction(g, eps, N,
494                    (double*) w -> data,
495                    (double*) z -> data,
496                    (double*) uh -> data,
497                    (double*) vh -> data,
498                    (double*) eta -> data,
499                    (double*) xmom -> data,
500                    (double*) ymom -> data);
501
502  return Py_BuildValue("");
503}
504
505PyObject *extrapolate_second_order_sw(PyObject *self, PyObject *args) {
506  /*Compute the vertex values based on a linear reconstruction on each triangle
507    These values are calculated as follows:
508    1) For each triangle not adjacent to a boundary, we consider the auxiliary triangle
509    formed by the centroids of its three neighbours.
510    2) For each conserved quantity, we integrate around the auxiliary triangle's boundary the product
511    of the quantity and the outward normal vector. Dividing by the triangle area gives (a,b), the average
512    of the vector (q_x,q_y) on the auxiliary triangle. We suppose that the linear reconstruction on the
513    original triangle has gradient (a,b).
514    3) Provisional vertex junmps dqv[0,1,2] are computed and these are then limited by calling the functions
515    find_qmin_and_qmax and limit_gradient
516
517    Python call:
518    extrapolate_second_order_sw(domain.surrogate_neighbours,
519                                domain.number_of_boundaries
520                                domain.centroid_coordinates,
521                                Stage.centroid_values
522                                Xmom.centroid_values
523                                Ymom.centroid_values
524                                domain.vertex_coordinates,
525                                Stage.vertex_values,
526                                Xmom.vertex_values,
527                                Ymom.vertex_values)   
528
529    Post conditions:
530            The vertices of each triangle have values from a limited linear reconstruction
531            based on centroid values
532
533  */
534  PyArrayObject *surrogate_neighbours, 
535    *number_of_boundaries,
536    *centroid_coordinates,
537    *stage_centroid_values,
538    *xmom_centroid_values,
539    *ymom_centroid_values,
540    *vertex_coordinates,
541    *stage_vertex_values,
542    *xmom_vertex_values,
543    *ymom_vertex_values;
544  PyObject *domain, *Tmp;
545  //Local variables
546  double a, b;//gradient vector, not stored but used to calculate vertex values from centroids
547  int number_of_elements,k,k0,k1,k2,k3,k6,coord_index,i;
548  double x,y,x0,y0,x1,y1,x2,y2,xv0,yv0,xv1,yv1,xv2,yv2;//vertices of the auxiliary triangle
549  double dx1,dx2,dy1,dy2,dxv0,dxv1,dxv2,dyv0,dyv1,dyv2,dq0,dq1,dq2,area2;
550  double dqv[3], qmin, qmax, beta_w;//provisional jumps from centroids to v'tices and safety factor re limiting
551  //by which these jumps are limited
552  // Convert Python arguments to C
553  if (!PyArg_ParseTuple(args, "OOOOOOOOOOO",
554                        &domain,
555                        &surrogate_neighbours,
556                        &number_of_boundaries,
557                        &centroid_coordinates,
558                        &stage_centroid_values,
559                        &xmom_centroid_values,
560                        &ymom_centroid_values,
561                        &vertex_coordinates,
562                        &stage_vertex_values,
563                        &xmom_vertex_values,
564                        &ymom_vertex_values)) {
565    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
566    return NULL;
567  }
568
569  //get the safety factor beta_w, set in the config.py file. This is used in the limiting process
570  Tmp = PyObject_GetAttrString(domain, "beta_w");
571  if (!Tmp)
572    return NULL;
573  beta_w = PyFloat_AsDouble(Tmp);
574  Py_DECREF(Tmp);
575  number_of_elements = stage_centroid_values -> dimensions[0];
576  for (k=0; k<number_of_elements; k++) {
577    k3=k*3;
578    k6=k*6;
579
580    if (((long *) number_of_boundaries->data)[k]==3){/*no neighbours, set gradient on the triangle to zero*/
581      ((double *) stage_vertex_values->data)[k3]=((double *)stage_centroid_values->data)[k];
582      ((double *) stage_vertex_values->data)[k3+1]=((double *)stage_centroid_values->data)[k];
583      ((double *) stage_vertex_values->data)[k3+2]=((double *)stage_centroid_values->data)[k];
584      ((double *) xmom_vertex_values->data)[k3]=((double *)xmom_centroid_values->data)[k];
585      ((double *) xmom_vertex_values->data)[k3+1]=((double *)xmom_centroid_values->data)[k];
586      ((double *) xmom_vertex_values->data)[k3+2]=((double *)xmom_centroid_values->data)[k];
587      ((double *) ymom_vertex_values->data)[k3]=((double *)ymom_centroid_values->data)[k];
588      ((double *) ymom_vertex_values->data)[k3+1]=((double *)ymom_centroid_values->data)[k];
589      ((double *) ymom_vertex_values->data)[k3+2]=((double *)ymom_centroid_values->data)[k];
590      continue;
591    }
592    else {//we will need centroid coordinates and vertex coordinates of the triangle
593      //get the vertex coordinates of the FV triangle
594      xv0=((double *)vertex_coordinates->data)[k6]; yv0=((double *)vertex_coordinates->data)[k6+1]; 
595      xv1=((double *)vertex_coordinates->data)[k6+2]; yv1=((double *)vertex_coordinates->data)[k6+3]; 
596      xv2=((double *)vertex_coordinates->data)[k6+4]; yv2=((double *)vertex_coordinates->data)[k6+5]; 
597      //get the centroid coordinates of the FV triangle
598      coord_index=2*k; 
599      x=((double *)centroid_coordinates->data)[coord_index]; 
600      y=((double *)centroid_coordinates->data)[coord_index+1]; 
601      //store x- and y- differentials for the vertices of the FV triangle relative to the centroid
602      dxv0=xv0-x; dxv1=xv1-x; dxv2=xv2-x;
603      dyv0=yv0-y; dyv1=yv1-y; dyv2=yv2-y;
604    }
605    if (((long *)number_of_boundaries->data)[k]<=1){
606      //if no boundaries, auxiliary triangle is formed from the centroids of the three neighbours
607      //if one boundary, auxiliary triangle is formed from this centroid and its two neighbours
608      k0=((long *)surrogate_neighbours->data)[k3];
609      k1=((long *)surrogate_neighbours->data)[k3+1];
610      k2=((long *)surrogate_neighbours->data)[k3+2];
611      //get the auxiliary triangle's vertex coordinates (really the centroids of neighbouring triangles)
612      coord_index=2*k0;
613      x0=((double *)centroid_coordinates->data)[coord_index];
614      y0=((double *)centroid_coordinates->data)[coord_index+1];
615      coord_index=2*k1;
616      x1=((double *)centroid_coordinates->data)[coord_index];
617      y1=((double *)centroid_coordinates->data)[coord_index+1];
618      coord_index=2*k2;
619      x2=((double *)centroid_coordinates->data)[coord_index];
620      y2=((double *)centroid_coordinates->data)[coord_index+1];
621      //store x- and y- differentials for the vertices of the auxiliary triangle
622      dx1=x1-x0; dx2=x2-x0;
623      dy1=y1-y0; dy2=y2-y0;
624      //calculate 2*area of the auxiliary triangle
625      area2 = dy2*dx1 - dy1*dx2;//the triangle is guaranteed to be counter-clockwise
626      //If the mesh is 'weird' near the boundary, the trianlge might be flat or clockwise:
627      if (area2<=0)
628        return NULL;
629
630      //### stage ###
631      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
632      dq0=((double *)stage_centroid_values->data)[k0]-((double *)stage_centroid_values->data)[k];
633      //calculate differentials between the vertices of the auxiliary triangle
634      dq1=((double *)stage_centroid_values->data)[k1]-((double *)stage_centroid_values->data)[k0];
635      dq2=((double *)stage_centroid_values->data)[k2]-((double *)stage_centroid_values->data)[k0];
636      //calculate the gradient of stage on the auxiliary triangle
637      a = dy2*dq1 - dy1*dq2;
638      a /= area2;
639      b = dx1*dq2 - dx2*dq1;
640      b /= area2;
641      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
642      dqv[0]=a*dxv0+b*dyv0;
643      dqv[1]=a*dxv1+b*dyv1;
644      dqv[2]=a*dxv2+b*dyv2;
645      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
646      //and compute jumps from the centroid to the min and max
647      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
648      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
649      for (i=0;i<3;i++)
650        ((double *)stage_vertex_values->data)[k3+i]=((double *)stage_centroid_values->data)[k]+dqv[i];
651
652      //### xmom ###
653      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
654      dq0=((double *)xmom_centroid_values->data)[k0]-((double *)xmom_centroid_values->data)[k];
655      //calculate differentials between the vertices of the auxiliary triangle
656      dq1=((double *)xmom_centroid_values->data)[k1]-((double *)xmom_centroid_values->data)[k0];
657      dq2=((double *)xmom_centroid_values->data)[k2]-((double *)xmom_centroid_values->data)[k0];
658      //calculate the gradient of xmom on the auxiliary triangle
659      a = dy2*dq1 - dy1*dq2;
660      a /= area2;
661      b = dx1*dq2 - dx2*dq1;
662      b /= area2;
663      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
664      dqv[0]=a*dxv0+b*dyv0;
665      dqv[1]=a*dxv1+b*dyv1;
666      dqv[2]=a*dxv2+b*dyv2;
667      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
668      //and compute jumps from the centroid to the min and max
669      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
670      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited   
671      for (i=0;i<3;i++)
672        ((double *)xmom_vertex_values->data)[k3+i]=((double *)xmom_centroid_values->data)[k]+dqv[i];
673
674      //### ymom ###
675      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
676      dq0=((double *)ymom_centroid_values->data)[k0]-((double *)ymom_centroid_values->data)[k];
677      //calculate differentials between the vertices of the auxiliary triangle
678      dq1=((double *)ymom_centroid_values->data)[k1]-((double *)ymom_centroid_values->data)[k0];
679      dq2=((double *)ymom_centroid_values->data)[k2]-((double *)ymom_centroid_values->data)[k0];
680      //calculate the gradient of xmom on the auxiliary triangle
681      a = dy2*dq1 - dy1*dq2;
682      a /= area2;
683      b = dx1*dq2 - dx2*dq1;
684      b /= area2;
685      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
686      dqv[0]=a*dxv0+b*dyv0;
687      dqv[1]=a*dxv1+b*dyv1;
688      dqv[2]=a*dxv2+b*dyv2;
689      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
690      //and compute jumps from the centroid to the min and max
691      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
692      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited   
693      for (i=0;i<3;i++)
694        ((double *)ymom_vertex_values->data)[k3+i]=((double *)ymom_centroid_values->data)[k]+dqv[i];
695    }//if (number_of_boundaries[k]<=1)
696    else{//number_of_boundaries==2
697      //one internal neighbour and gradient is in direction of the neighbour's centroid
698      //find the only internal neighbour
699      for (k2=k3;k2<k3+3;k2++){//k2 just indexes the edges of triangle k
700        if (((long *)surrogate_neighbours->data)[k2]!=k)//find internal neighbour of triabngle k
701          break;
702      }
703      if ((k2==k3+3))//if we didn't find an internal neighbour
704        return NULL;//error
705      k1=((long *)surrogate_neighbours->data)[k2];
706      //the coordinates of the triangle are already (x,y). Get centroid of the neighbour (x1,y1)
707      coord_index=2*k1;
708      x1=((double *)centroid_coordinates->data)[coord_index]; 
709      y1=((double *)centroid_coordinates->data)[coord_index+1];
710      //compute x- and y- distances between the centroid of the FV triangle and that of its neighbour
711      dx1=x1-x; dy1=y1-y;
712      //set area2 as the square of the distance
713      area2=dx1*dx1+dy1*dy1;
714      //set dx2=(x1-x0)/((x1-x0)^2+(y1-y0)^2) and dy2=(y1-y0)/((x1-x0)^2+(y1-y0)^2) which
715      //respectively correspond to the x- and y- gradients of the conserved quantities
716      dx2=1.0/area2;
717      dy2=dx2*dy1;
718      dx2*=dx1;
719     
720      //## stage ###
721      //compute differentials
722      dq1=((double *)stage_centroid_values->data)[k1]-((double *)stage_centroid_values->data)[k];
723      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
724      a=dq1*dx2;
725      b=dq1*dy2;
726      //calculate provisional vertex jumps, to be limited
727      dqv[0]=a*dxv0+b*dyv0;
728      dqv[1]=a*dxv1+b*dyv1;
729      dqv[2]=a*dxv2+b*dyv2;
730      //now limit the jumps
731      if (dq1>=0.0){
732        qmin=0.0;
733        qmax=dq1;
734      }
735      else{
736        qmin=dq1;
737        qmax=0.0;
738      }
739      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited   
740      for (i=0;i<3;i++)
741        ((double *)stage_vertex_values->data)[k3+i]=((double *)stage_centroid_values->data)[k]+dqv[i];
742
743      //## xmom ###
744      //compute differentials
745      dq1=((double *)xmom_centroid_values->data)[k1]-((double *)xmom_centroid_values->data)[k];
746      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
747      a=dq1*dx2;
748      b=dq1*dy2;
749      //calculate provisional vertex jumps, to be limited
750      dqv[0]=a*dxv0+b*dyv0;
751      dqv[1]=a*dxv1+b*dyv1;
752      dqv[2]=a*dxv2+b*dyv2;
753      //now limit the jumps
754      if (dq1>=0.0){
755        qmin=0.0;
756        qmax=dq1;
757      }
758      else{
759        qmin=dq1;
760        qmax=0.0;
761      }
762      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited   
763      for (i=0;i<3;i++)
764        ((double *)xmom_vertex_values->data)[k3+i]=((double *)xmom_centroid_values->data)[k]+dqv[i];
765
766      //## ymom ###
767      //compute differentials
768      dq1=((double *)ymom_centroid_values->data)[k1]-((double *)ymom_centroid_values->data)[k];
769      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
770      a=dq1*dx2;
771      b=dq1*dy2;
772      //calculate provisional vertex jumps, to be limited
773      dqv[0]=a*dxv0+b*dyv0;
774      dqv[1]=a*dxv1+b*dyv1;
775      dqv[2]=a*dxv2+b*dyv2;
776      //now limit the jumps
777      if (dq1>=0.0){
778        qmin=0.0;
779        qmax=dq1;
780      }
781      else{
782        qmin=dq1;
783        qmax=0.0;
784      }
785      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited   
786      for (i=0;i<3;i++)
787        ((double *)ymom_vertex_values->data)[k3+i]=((double *)ymom_centroid_values->data)[k]+dqv[i];
788    }//else [number_of_boudaries==2]
789  }//for k=0 to number_of_elements-1
790  return Py_BuildValue("");
791}//extrapolate_second-order_sw
792
793PyObject *rotate(PyObject *self, PyObject *args, PyObject *kwargs) {
794  //
795  // r = rotate(q, normal, direction=1)
796  //
797  // Where q is assumed to be a Float numeric array of length 3 and
798  // normal a Float numeric array of length 2.
799
800
801  PyObject *Q, *Normal;
802  PyArrayObject *q, *r, *normal;
803
804  static char *argnames[] = {"q", "normal", "direction", NULL};
805  int dimensions[1], i, direction=1;
806  double n1, n2;
807
808  // Convert Python arguments to C
809  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames,
810                                   &Q, &Normal, &direction))
811    return NULL;
812
813  //Input checks (convert sequences into numeric arrays)
814  q = (PyArrayObject *)
815    PyArray_ContiguousFromObject(Q, PyArray_DOUBLE, 0, 0);
816  normal = (PyArrayObject *)
817    PyArray_ContiguousFromObject(Normal, PyArray_DOUBLE, 0, 0);
818
819
820  if (normal -> dimensions[0] != 2) {
821    PyErr_SetString(PyExc_RuntimeError, "Normal vector must have 2 components");
822    return NULL;
823  }
824
825  //Allocate space for return vector r (don't DECREF)
826  dimensions[0] = 3;
827  r = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
828
829  //Copy
830  for (i=0; i<3; i++) {
831    ((double *) (r -> data))[i] = ((double *) (q -> data))[i];
832  }
833
834  //Get normal and direction
835  n1 = ((double *) normal -> data)[0];
836  n2 = ((double *) normal -> data)[1];
837  if (direction == -1) n2 = -n2;
838
839  //Rotate
840  _rotate((double *) r -> data, n1, n2);
841
842  //Release numeric arrays
843  Py_DECREF(q);
844  Py_DECREF(normal);
845
846  //return result using PyArray to avoid memory leak
847  return PyArray_Return(r);
848}
849
850PyObject *compute_fluxes(PyObject *self, PyObject *args) {
851  /*Compute all fluxes and the timestep suitable for all volumes
852    in domain.
853
854    Compute total flux for each conserved quantity using "flux_function"
855
856    Fluxes across each edge are scaled by edgelengths and summed up
857    Resulting flux is then scaled by area and stored in
858    explicit_update for each of the three conserved quantities
859    stage, xmomentum and ymomentum
860
861    The maximal allowable speed computed by the flux_function for each volume
862    is converted to a timestep that must not be exceeded. The minimum of
863    those is computed as the next overall timestep.
864
865    Python call:
866    domain.timestep = compute_fluxes(timestep,
867                                     domain.epsilon,
868                                     domain.g,
869                                     domain.neighbours,
870                                     domain.neighbour_edges,
871                                     domain.normals,
872                                     domain.edgelengths,
873                                     domain.radii,
874                                     domain.areas,
875                                     Stage.edge_values,
876                                     Xmom.edge_values,
877                                     Ymom.edge_values,
878                                     Bed.edge_values,
879                                     Stage.boundary_values,
880                                     Xmom.boundary_values,
881                                     Ymom.boundary_values,
882                                     Stage.explicit_update,
883                                     Xmom.explicit_update,
884                                     Ymom.explicit_update,
885                                     already_computed_flux)
886
887
888    Post conditions:
889      domain.explicit_update is reset to computed flux values
890      domain.timestep is set to the largest step satisfying all volumes.
891
892
893  */
894
895
896  PyArrayObject *neighbours, *neighbour_edges,
897    *normals, *edgelengths, *radii, *areas,
898    *stage_edge_values,
899    *xmom_edge_values,
900    *ymom_edge_values,
901    *bed_edge_values,
902    *stage_boundary_values,
903    *xmom_boundary_values,
904    *ymom_boundary_values,
905    *stage_explicit_update,
906    *xmom_explicit_update,
907    *ymom_explicit_update,
908    *already_computed_flux;//tracks whether the flux across an edge has already been computed
909
910
911  //Local variables
912  double timestep, max_speed, epsilon, g;
913  double normal[2], ql[3], qr[3], zl, zr;
914  double edgeflux[3]; //Work arrays for summing up fluxes
915
916  int number_of_elements, k, i, m, n;
917  int ki, nm, ki2; //Index shorthands
918  static long call=1;
919
920
921  // Convert Python arguments to C
922  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOOOOOOO",
923                        &timestep,
924                        &epsilon,
925                        &g,
926                        &neighbours,
927                        &neighbour_edges,
928                        &normals,
929                        &edgelengths, &radii, &areas,
930                        &stage_edge_values,
931                        &xmom_edge_values,
932                        &ymom_edge_values,
933                        &bed_edge_values,
934                        &stage_boundary_values,
935                        &xmom_boundary_values,
936                        &ymom_boundary_values,
937                        &stage_explicit_update,
938                        &xmom_explicit_update,
939                        &ymom_explicit_update,
940                        &already_computed_flux)) {
941    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
942    return NULL;
943  }
944  number_of_elements = stage_edge_values -> dimensions[0];
945  call++;//a static local variable to which already_computed_flux is compared
946  //set explicit_update to zero for all conserved_quantities.
947  //This assumes compute_fluxes called before forcing terms
948  for (k=0; k<number_of_elements; k++) {
949    ((double *) stage_explicit_update -> data)[k]=0.0;
950    ((double *) xmom_explicit_update -> data)[k]=0.0;
951    ((double *) ymom_explicit_update -> data)[k]=0.0;
952  }
953  //Loop through neighbours and compute edge flux for each
954  for (k=0; k<number_of_elements; k++) {
955    for (i=0; i<3; i++) {
956      ki = k*3+i;
957      if (((long *) already_computed_flux->data)[ki]==call)//we've already computed the flux across this edge
958        continue;
959      ql[0] = ((double *) stage_edge_values -> data)[ki];
960      ql[1] = ((double *) xmom_edge_values -> data)[ki];
961      ql[2] = ((double *) ymom_edge_values -> data)[ki];
962      zl =    ((double *) bed_edge_values -> data)[ki];
963     
964      //Quantities at neighbour on nearest face
965      n = ((long *) neighbours -> data)[ki];
966      if (n < 0) {
967        m = -n-1; //Convert negative flag to index
968        qr[0] = ((double *) stage_boundary_values -> data)[m];
969        qr[1] = ((double *) xmom_boundary_values -> data)[m];
970        qr[2] = ((double *) ymom_boundary_values -> data)[m];
971        zr = zl; //Extend bed elevation to boundary
972      } else {
973        m = ((long *) neighbour_edges -> data)[ki];
974        nm = n*3+m;
975        qr[0] = ((double *) stage_edge_values -> data)[nm];
976        qr[1] = ((double *) xmom_edge_values -> data)[nm];
977        qr[2] = ((double *) ymom_edge_values -> data)[nm];
978        zr =    ((double *) bed_edge_values -> data)[nm];
979      }
980      // Outward pointing normal vector
981      // normal = domain.normals[k, 2*i:2*i+2]
982      ki2 = 2*ki; //k*6 + i*2
983      normal[0] = ((double *) normals -> data)[ki2];
984      normal[1] = ((double *) normals -> data)[ki2+1];
985      //Edge flux computation
986      flux_function(ql, qr, zl, zr,
987                    normal[0], normal[1],
988                    epsilon, g,
989                    edgeflux, &max_speed);
990      //update triangle k
991      ((long *) already_computed_flux->data)[ki]=call;
992      ((double *) stage_explicit_update -> data)[k] -= edgeflux[0]*((double *) edgelengths -> data)[ki];
993      ((double *) xmom_explicit_update -> data)[k] -= edgeflux[1]*((double *) edgelengths -> data)[ki];
994      ((double *) ymom_explicit_update -> data)[k] -= edgeflux[2]*((double *) edgelengths -> data)[ki];
995      //update the neighbour n
996      if (n>=0){
997        ((long *) already_computed_flux->data)[nm]=call;
998        ((double *) stage_explicit_update -> data)[n] += edgeflux[0]*((double *) edgelengths -> data)[nm];
999        ((double *) xmom_explicit_update -> data)[n] += edgeflux[1]*((double *) edgelengths -> data)[nm];
1000        ((double *) ymom_explicit_update -> data)[n] += edgeflux[2]*((double *) edgelengths -> data)[nm];
1001      }
1002      ///for (j=0; j<3; j++) {
1003        ///flux[j] -= edgeflux[j]*((double *) edgelengths -> data)[ki];
1004        ///}
1005        //Update timestep
1006        //timestep = min(timestep, domain.radii[k]/max_speed)
1007        //FIXME: SR Add parameter for CFL condition
1008        if (max_speed > epsilon) {
1009          timestep = min(timestep, ((double *) radii -> data)[k]/max_speed);
1010          //maxspeed in flux_function is calculated as max(|u+a|,|u-a|)
1011          if (n>=0)
1012            timestep = min(timestep, ((double *) radii -> data)[n]/max_speed);
1013        }
1014    } // end for i
1015    //Normalise by area and store for when all conserved
1016    //quantities get updated
1017    ((double *) stage_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
1018    ((double *) xmom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
1019    ((double *) ymom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];   
1020  } //end for k
1021  return Py_BuildValue("d", timestep);
1022}
1023
1024PyObject *protect(PyObject *self, PyObject *args) {
1025  //
1026  //    protect(minimum_allowed_height, wc, zc, xmomc, ymomc)
1027
1028
1029  PyArrayObject
1030  *wc,            //Stage at centroids
1031  *zc,            //Elevation at centroids
1032  *xmomc,         //Momentums at centroids
1033  *ymomc;
1034
1035
1036  int N;
1037  double minimum_allowed_height;
1038
1039  // Convert Python arguments to C
1040  if (!PyArg_ParseTuple(args, "dOOOO",
1041                        &minimum_allowed_height,
1042                        &wc, &zc, &xmomc, &ymomc))
1043    return NULL;
1044
1045  N = wc -> dimensions[0];
1046
1047  _protect(N,
1048           minimum_allowed_height,
1049           (double*) wc -> data,
1050           (double*) zc -> data,
1051           (double*) xmomc -> data,
1052           (double*) ymomc -> data);
1053
1054  return Py_BuildValue("");
1055}
1056
1057
1058
1059PyObject *balance_deep_and_shallow(PyObject *self, PyObject *args) {
1060  //
1061  //    balance_deep_and_shallow(wc, zc, hc, wv, zv, hv,
1062  //                             xmomc, ymomc, xmomv, ymomv)
1063
1064
1065  PyArrayObject
1066    *wc,            //Stage at centroids
1067    *zc,            //Elevation at centroids
1068    *hc,            //Height at centroids
1069    *wv,            //Stage at vertices
1070    *zv,            //Elevation at vertices
1071    *hv,            //Depths at vertices
1072    *hvbar,         //h-Limited depths at vertices
1073    *xmomc,         //Momentums at centroids and vertices
1074    *ymomc,
1075    *xmomv,
1076    *ymomv;
1077
1078  int N; //, err;
1079
1080  // Convert Python arguments to C
1081  if (!PyArg_ParseTuple(args, "OOOOOOOOOOO",
1082                        &wc, &zc, &hc,
1083                        &wv, &zv, &hv, &hvbar,
1084                        &xmomc, &ymomc, &xmomv, &ymomv))
1085    return NULL;
1086
1087  N = wc -> dimensions[0];
1088
1089  _balance_deep_and_shallow(N,
1090                            (double*) wc -> data,
1091                            (double*) zc -> data,
1092                            (double*) hc -> data,
1093                            (double*) wv -> data,
1094                            (double*) zv -> data,
1095                            (double*) hv -> data,
1096                            (double*) hvbar -> data,
1097                            (double*) xmomc -> data,
1098                            (double*) ymomc -> data,
1099                            (double*) xmomv -> data,
1100                            (double*) ymomv -> data);
1101
1102
1103  return Py_BuildValue("");
1104}
1105
1106
1107
1108PyObject *h_limiter(PyObject *self, PyObject *args) {
1109
1110  PyObject *domain, *Tmp;
1111  PyArrayObject
1112    *hv, *hc, //Depth at vertices and centroids
1113    *hvbar,   //Limited depth at vertices (return values)
1114    *neighbours;
1115
1116  int k, i, n, N, k3;
1117  int dimensions[2];
1118  double beta_h; //Safety factor (see config.py)
1119  double *hmin, *hmax, hn;
1120
1121  // Convert Python arguments to C
1122  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv))
1123    return NULL;
1124
1125  neighbours = get_consecutive_array(domain, "neighbours");
1126
1127  //Get safety factor beta_h
1128  Tmp = PyObject_GetAttrString(domain, "beta_h");
1129  if (!Tmp)
1130    return NULL;
1131
1132  beta_h = PyFloat_AsDouble(Tmp);
1133
1134  Py_DECREF(Tmp);
1135
1136  N = hc -> dimensions[0];
1137
1138  //Create hvbar
1139  dimensions[0] = N;
1140  dimensions[1] = 3;
1141  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
1142
1143
1144  //Find min and max of this and neighbour's centroid values
1145  hmin = malloc(N * sizeof(double));
1146  hmax = malloc(N * sizeof(double));
1147  for (k=0; k<N; k++) {
1148    k3=k*3;
1149
1150    hmin[k] = ((double*) hc -> data)[k];
1151    hmax[k] = hmin[k];
1152
1153    for (i=0; i<3; i++) {
1154      n = ((long*) neighbours -> data)[k3+i];
1155
1156      //Initialise hvbar with values from hv
1157      ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i];
1158
1159      if (n >= 0) {
1160        hn = ((double*) hc -> data)[n]; //Neighbour's centroid value
1161
1162        hmin[k] = min(hmin[k], hn);
1163        hmax[k] = max(hmax[k], hn);
1164      }
1165    }
1166  }
1167
1168  // Call underlying standard routine
1169  _limit(N, beta_h, (double*) hc -> data, (double*) hvbar -> data, hmin, hmax);
1170
1171  // // //Py_DECREF(domain); //FIXME: NEcessary?
1172  free(hmin);
1173  free(hmax);
1174
1175  //return result using PyArray to avoid memory leak
1176  return PyArray_Return(hvbar);
1177  //return Py_BuildValue("");
1178}
1179
1180
1181
1182
1183PyObject *assign_windfield_values(PyObject *self, PyObject *args) {
1184  //
1185  //      assign_windfield_values(xmom_update, ymom_update,
1186  //                              s_vec, phi_vec, self.const)
1187
1188
1189
1190  PyArrayObject   //(one element per triangle)
1191  *s_vec,         //Speeds
1192  *phi_vec,       //Bearings
1193  *xmom_update,   //Momentum updates
1194  *ymom_update;
1195
1196
1197  int N;
1198  double cw;
1199
1200  // Convert Python arguments to C
1201  if (!PyArg_ParseTuple(args, "OOOOd",
1202                        &xmom_update,
1203                        &ymom_update,
1204                        &s_vec, &phi_vec,
1205                        &cw))
1206    return NULL;
1207
1208  N = xmom_update -> dimensions[0];
1209
1210  _assign_wind_field_values(N,
1211           (double*) xmom_update -> data,
1212           (double*) ymom_update -> data,
1213           (double*) s_vec -> data,
1214           (double*) phi_vec -> data,
1215           cw);
1216
1217  return Py_BuildValue("");
1218}
1219
1220
1221
1222
1223//////////////////////////////////////////
1224// Method table for python module
1225static struct PyMethodDef MethodTable[] = {
1226  /* The cast of the function is necessary since PyCFunction values
1227   * only take two PyObject* parameters, and rotate() takes
1228   * three.
1229   */
1230
1231  {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
1232  {"extrapolate_second_order_sw", extrapolate_second_order_sw, METH_VARARGS, "Print out"},
1233  {"compute_fluxes", compute_fluxes, METH_VARARGS, "Print out"},
1234  {"gravity", gravity, METH_VARARGS, "Print out"},
1235  {"manning_friction", manning_friction, METH_VARARGS, "Print out"},
1236  {"balance_deep_and_shallow", balance_deep_and_shallow,
1237   METH_VARARGS, "Print out"},
1238  {"h_limiter", h_limiter,
1239   METH_VARARGS, "Print out"},
1240  {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"},
1241  {"assign_windfield_values", assign_windfield_values,
1242   METH_VARARGS | METH_KEYWORDS, "Print out"},
1243  //{"distribute_to_vertices_and_edges",
1244  // distribute_to_vertices_and_edges, METH_VARARGS},
1245  //{"update_conserved_quantities",
1246  // update_conserved_quantities, METH_VARARGS},
1247  //{"set_initialcondition",
1248  // set_initialcondition, METH_VARARGS},
1249  {NULL, NULL}
1250};
1251
1252// Module initialisation
1253void initshallow_water_ext(void){
1254  Py_InitModule("shallow_water_ext", MethodTable);
1255
1256  import_array();     //Necessary for handling of NumPY structures
1257}
Note: See TracBrowser for help on using the repository browser.