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

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

In manning_friction, the line S /= pow(h,7.0/3) has been replaced by S /= exp(7.0/3.0*log(h)). On run_pofile.py, with N=128, the running time is 59.21 secs (averaged over 3 runs). Making the above change to manning_friction means that the time consumed by manning_friction is reduced from 4.51 secs to 3.79 secs.

File size: 22.9 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
49
50
51// Computational function for flux computation (using stage w=z+h)
52int flux_function(double *q_left, double *q_right,
53                  double z_left, double z_right,
54                  double n1, double n2,
55                  double epsilon, double g,
56                  double *edgeflux, double *max_speed) {
57
58  /*Compute fluxes between volumes for the shallow water wave equation
59    cast in terms of the 'stage', w = h+z using
60    the 'central scheme' as described in
61
62    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
63    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
64    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
65
66    The implemented formula is given in equation (3.15) on page 714
67  */
68
69  int i;
70
71  double w_left, h_left, uh_left, vh_left, u_left;
72  double w_right, h_right, uh_right, vh_right, u_right;
73  double s_min, s_max, soundspeed_left, soundspeed_right;
74  double denom, z;
75  double q_left_copy[3], q_right_copy[3];
76  double flux_right[3], flux_left[3];
77
78  //Copy conserved quantities to protect from modification
79  for (i=0; i<3; i++) {
80    q_left_copy[i] = q_left[i];
81    q_right_copy[i] = q_right[i];
82  }
83
84  //Align x- and y-momentum with x-axis
85  _rotate(q_left_copy, n1, n2);
86  _rotate(q_right_copy, n1, n2);
87
88  z = (z_left+z_right)/2; //Take average of field values
89
90  //Compute speeds in x-direction
91  w_left = q_left_copy[0];              // h+z
92  h_left = w_left-z;
93  uh_left = q_left_copy[1];
94
95  if (h_left < epsilon) {
96    h_left = 0.0;  //Could have been negative
97    u_left = 0.0;
98  } else {
99    u_left = uh_left/h_left;
100  }
101
102  w_right = q_right_copy[0];
103  h_right = w_right-z;
104  uh_right = q_right_copy[1];
105
106  if (h_right < epsilon) {
107    h_right = 0.0; //Could have been negative
108    u_right = 0.0;
109  } else {
110    u_right = uh_right/h_right;
111  }
112
113  //Momentum in y-direction
114  vh_left  = q_left_copy[2];
115  vh_right = q_right_copy[2];
116
117
118  //Maximal and minimal wave speeds
119  soundspeed_left  = sqrt(g*h_left);
120  soundspeed_right = sqrt(g*h_right);
121
122  s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
123  if (s_max < 0.0) s_max = 0.0;
124
125  s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
126  if (s_min > 0.0) s_min = 0.0;
127
128  //Flux formulas
129  flux_left[0] = u_left*h_left;
130  flux_left[1] = u_left*uh_left + 0.5*g*h_left*h_left;
131  flux_left[2] = u_left*vh_left;
132
133  flux_right[0] = u_right*h_right;
134  flux_right[1] = u_right*uh_right + 0.5*g*h_right*h_right;
135  flux_right[2] = u_right*vh_right;
136
137
138  //Flux computation
139  denom = s_max-s_min;
140  if (denom == 0.0) {
141    for (i=0; i<3; i++) edgeflux[i] = 0.0;
142    *max_speed = 0.0;
143  } else {
144    for (i=0; i<3; i++) {
145      edgeflux[i] = s_max*flux_left[i] - s_min*flux_right[i];
146      edgeflux[i] += s_max*s_min*(q_right_copy[i]-q_left_copy[i]);
147      edgeflux[i] /= denom;
148    }
149
150    //Maximal wavespeed
151    *max_speed = max(fabs(s_max), fabs(s_min));
152
153    //Rotate back
154    _rotate(edgeflux, n1, -n2);
155  }
156  return 0;
157}
158
159void _manning_friction(double g, double eps, int N,
160                       double* w, double* z,
161                       double* uh, double* vh,
162                       double* eta, double* xmom, double* ymom) {
163
164  int k;
165  double S, h;
166
167  for (k=0; k<N; k++) {
168    if (eta[k] > eps) {
169      h = w[k]-z[k];
170      if (h >= eps) {
171        S = -g * eta[k]*eta[k] * sqrt((uh[k]*uh[k] + vh[k]*vh[k]));
172        //S /= pow(h, 7.0/3);      //Expensive (on Ole's home computer)
173        S /= exp(7.0/3.0*log(h));      //seems to save about 15% over manning_friction
174        //S /= h*h*(1 + h/3.0 - h*h/9.0); //FIXME: Could use a Taylor expansion
175
176
177        //Update momentum
178        xmom[k] += S*uh[k];
179        ymom[k] += S*vh[k];
180      }
181    }
182  }
183}
184
185
186
187int _balance_deep_and_shallow(int N,
188                              double* wc,
189                              double* zc,
190                              double* hc,
191                              double* wv,
192                              double* zv,
193                              double* hv,
194                              double* hvbar,
195                              double* xmomc,
196                              double* ymomc,
197                              double* xmomv,
198                              double* ymomv) {
199
200  int k, k3, i;
201  double dz, hmin, alpha;
202
203  //Compute linear combination between w-limited stages and
204  //h-limited stages close to the bed elevation.
205
206  for (k=0; k<N; k++) {
207    // Compute maximal variation in bed elevation
208    // This quantitiy is
209    //     dz = max_i abs(z_i - z_c)
210    // and it is independent of dimension
211    // In the 1d case zc = (z0+z1)/2
212    // In the 2d case zc = (z0+z1+z2)/3
213
214    k3 = 3*k;
215
216    //FIXME: Try with this one precomputed
217    dz = 0.0;
218    hmin = hv[k3];
219    for (i=0; i<3; i++) {
220      dz = max(dz, fabs(zv[k3+i]-zc[k]));
221      hmin = min(hmin, hv[k3+i]);
222    }
223
224
225    //Create alpha in [0,1], where alpha==0 means using the h-limited
226    //stage and alpha==1 means using the w-limited stage as
227    //computed by the gradient limiter (both 1st or 2nd order)
228    //
229    //If hmin > dz/2 then alpha = 1 and the bed will have no effect
230    //If hmin < 0 then alpha = 0 reverting to constant height above bed.
231
232
233    if (dz > 0.0)
234      //if (hmin<0.0)
235      //        alpha = 0.0;
236      //else
237      //  alpha = max( min( hc[k]/dz, 1.0), 0.0 );
238      alpha = max( min( 2.0*hmin/dz, 1.0), 0.0 );
239    else
240      alpha = 1.0;  //Flat bed
241
242    //alpha = 1.0;
243
244    //printf("dz = %.3f, alpha = %.8f\n", dz, alpha);
245
246    //  Let
247    //
248    //    wvi be the w-limited stage (wvi = zvi + hvi)
249    //    wvi- be the h-limited state (wvi- = zvi + hvi-)
250    //
251    //
252    //  where i=0,1,2 denotes the vertex ids
253    //
254    //  Weighted balance between w-limited and h-limited stage is
255    //
256    //    wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
257    //
258    //  It follows that the updated wvi is
259    //    wvi := zvi + (1-alpha)*hvi- + alpha*hvi
260    //
261    //   Momentum is balanced between constant and limited
262
263    if (alpha < 1) {
264      for (i=0; i<3; i++) {
265        wv[k3+i] = zv[k3+i] + (1-alpha)*hvbar[k3+i] + alpha*hv[k3+i];
266
267        //Update momentum as a linear combination of
268        //xmomc and ymomc (shallow) and momentum
269        //from extrapolator xmomv and ymomv (deep).
270        xmomv[k3+i] = (1-alpha)*xmomc[k] + alpha*xmomv[k3+i];
271        ymomv[k3+i] = (1-alpha)*ymomc[k] + alpha*ymomv[k3+i];
272      }
273    }
274  }
275  return 0;
276}
277
278
279
280int _protect(int N,
281             double minimum_allowed_height,
282             double* wc,
283             double* zc,
284             double* xmomc,
285             double* ymomc) {
286
287  int k;
288  double hc;
289
290  //Protect against initesimal and negative heights
291
292  for (k=0; k<N; k++) {
293    hc = wc[k] - zc[k];
294
295    if (hc < minimum_allowed_height) {
296      wc[k] = zc[k];
297      xmomc[k] = 0.0;
298      ymomc[k] = 0.0;
299    }
300
301  }
302  return 0;
303}
304
305
306
307
308
309
310
311
312int _assign_wind_field_values(int N,
313                              double* xmom_update,
314                              double* ymom_update,
315                              double* s_vec,
316                              double* phi_vec,
317                              double cw) {
318
319  //Assign windfield values to momentum updates
320
321  int k;
322  double S, s, phi, u, v;
323
324  for (k=0; k<N; k++) {
325
326    s = s_vec[k];
327    phi = phi_vec[k];
328
329    //Convert to radians
330    phi = phi*pi/180;
331
332    //Compute velocity vector (u, v)
333    u = s*cos(phi);
334    v = s*sin(phi);
335
336    //Compute wind stress
337    S = cw * sqrt(u*u + v*v);
338    xmom_update[k] += S*u;
339    ymom_update[k] += S*v;
340  }
341  return 0;
342}
343
344
345
346///////////////////////////////////////////////////////////////////
347// Gateways to Python
348
349PyObject *gravity(PyObject *self, PyObject *args) {
350  //
351  //  gravity(g, h, v, x, xmom, ymom)
352  //
353
354
355  PyArrayObject *h, *v, *x, *xmom, *ymom;
356  int k, i, N, k3, k6;
357  double g, avg_h, zx, zy;
358  double x0, y0, x1, y1, x2, y2, z0, z1, z2;
359
360  if (!PyArg_ParseTuple(args, "dOOOOO",
361                        &g, &h, &v, &x,
362                        &xmom, &ymom))
363    return NULL;
364
365  N = h -> dimensions[0];
366  for (k=0; k<N; k++) {
367    k3 = 3*k;  // base index
368    k6 = 6*k;  // base index
369
370    avg_h = 0.0;
371    for (i=0; i<3; i++) {
372      avg_h += ((double *) h -> data)[k3+i];
373    }
374    avg_h /= 3;
375
376
377    //Compute bed slope
378    x0 = ((double*) x -> data)[k6 + 0];
379    y0 = ((double*) x -> data)[k6 + 1];
380    x1 = ((double*) x -> data)[k6 + 2];
381    y1 = ((double*) x -> data)[k6 + 3];
382    x2 = ((double*) x -> data)[k6 + 4];
383    y2 = ((double*) x -> data)[k6 + 5];
384
385
386    z0 = ((double*) v -> data)[k3 + 0];
387    z1 = ((double*) v -> data)[k3 + 1];
388    z2 = ((double*) v -> data)[k3 + 2];
389
390    _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy);
391
392    //Update momentum
393    ((double*) xmom -> data)[k] += -g*zx*avg_h;
394    ((double*) ymom -> data)[k] += -g*zy*avg_h;
395  }
396
397  return Py_BuildValue("");
398}
399
400
401PyObject *manning_friction(PyObject *self, PyObject *args) {
402  //
403  // manning_friction(g, eps, h, uh, vh, eta, xmom_update, ymom_update)
404  //
405
406
407  PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom;
408  int N;
409  double g, eps;
410
411  if (!PyArg_ParseTuple(args, "ddOOOOOOO",
412                        &g, &eps, &w, &z, &uh, &vh, &eta,
413                        &xmom, &ymom))
414    return NULL;
415
416  N = w -> dimensions[0];
417  _manning_friction(g, eps, N,
418                    (double*) w -> data,
419                    (double*) z -> data,
420                    (double*) uh -> data,
421                    (double*) vh -> data,
422                    (double*) eta -> data,
423                    (double*) xmom -> data,
424                    (double*) ymom -> data);
425
426  return Py_BuildValue("");
427}
428
429PyObject *rotate(PyObject *self, PyObject *args, PyObject *kwargs) {
430  //
431  // r = rotate(q, normal, direction=1)
432  //
433  // Where q is assumed to be a Float numeric array of length 3 and
434  // normal a Float numeric array of length 2.
435
436
437  PyObject *Q, *Normal;
438  PyArrayObject *q, *r, *normal;
439
440  static char *argnames[] = {"q", "normal", "direction", NULL};
441  int dimensions[1], i, direction=1;
442  double n1, n2;
443
444  // Convert Python arguments to C
445  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames,
446                                   &Q, &Normal, &direction))
447    return NULL;
448
449  //Input checks (convert sequences into numeric arrays)
450  q = (PyArrayObject *)
451    PyArray_ContiguousFromObject(Q, PyArray_DOUBLE, 0, 0);
452  normal = (PyArrayObject *)
453    PyArray_ContiguousFromObject(Normal, PyArray_DOUBLE, 0, 0);
454
455
456  if (normal -> dimensions[0] != 2) {
457    PyErr_SetString(PyExc_RuntimeError, "Normal vector must have 2 components");
458    return NULL;
459  }
460
461  //Allocate space for return vector r (don't DECREF)
462  dimensions[0] = 3;
463  r = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
464
465  //Copy
466  for (i=0; i<3; i++) {
467    ((double *) (r -> data))[i] = ((double *) (q -> data))[i];
468  }
469
470  //Get normal and direction
471  n1 = ((double *) normal -> data)[0];
472  n2 = ((double *) normal -> data)[1];
473  if (direction == -1) n2 = -n2;
474
475  //Rotate
476  _rotate((double *) r -> data, n1, n2);
477
478  //Release numeric arrays
479  Py_DECREF(q);
480  Py_DECREF(normal);
481
482  //return result using PyArray to avoid memory leak
483  return PyArray_Return(r);
484}
485
486
487PyObject *compute_fluxes(PyObject *self, PyObject *args) {
488  /*Compute all fluxes and the timestep suitable for all volumes
489    in domain.
490
491    Compute total flux for each conserved quantity using "flux_function"
492
493    Fluxes across each edge are scaled by edgelengths and summed up
494    Resulting flux is then scaled by area and stored in
495    explicit_update for each of the three conserved quantities
496    stage, xmomentum and ymomentum
497
498    The maximal allowable speed computed by the flux_function for each volume
499    is converted to a timestep that must not be exceeded. The minimum of
500    those is computed as the next overall timestep.
501
502    Python call:
503    domain.timestep = compute_fluxes(timestep,
504                                     domain.epsilon,
505                                     domain.g,
506                                     domain.neighbours,
507                                     domain.neighbour_edges,
508                                     domain.normals,
509                                     domain.edgelengths,
510                                     domain.radii,
511                                     domain.areas,
512                                     Stage.edge_values,
513                                     Xmom.edge_values,
514                                     Ymom.edge_values,
515                                     Bed.edge_values,
516                                     Stage.boundary_values,
517                                     Xmom.boundary_values,
518                                     Ymom.boundary_values,
519                                     Stage.explicit_update,
520                                     Xmom.explicit_update,
521                                     Ymom.explicit_update)
522
523
524    Post conditions:
525      domain.explicit_update is reset to computed flux values
526      domain.timestep is set to the largest step satisfying all volumes.
527
528
529  */
530
531
532  PyArrayObject *neighbours, *neighbour_edges,
533    *normals, *edgelengths, *radii, *areas,
534    *stage_edge_values,
535    *xmom_edge_values,
536    *ymom_edge_values,
537    *bed_edge_values,
538    *stage_boundary_values,
539    *xmom_boundary_values,
540    *ymom_boundary_values,
541    *stage_explicit_update,
542    *xmom_explicit_update,
543    *ymom_explicit_update;
544
545
546  //Local variables
547  double timestep, max_speed, epsilon, g;
548  double normal[2], ql[3], qr[3], zl, zr;
549  double flux[3], edgeflux[3]; //Work arrays for summing up fluxes
550
551  int number_of_elements, k, i, j, m, n;
552  int ki, nm, ki2; //Index shorthands
553
554
555  // Convert Python arguments to C
556  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOOOOOO",
557                        &timestep,
558                        &epsilon,
559                        &g,
560                        &neighbours,
561                        &neighbour_edges,
562                        &normals,
563                        &edgelengths, &radii, &areas,
564                        &stage_edge_values,
565                        &xmom_edge_values,
566                        &ymom_edge_values,
567                        &bed_edge_values,
568                        &stage_boundary_values,
569                        &xmom_boundary_values,
570                        &ymom_boundary_values,
571                        &stage_explicit_update,
572                        &xmom_explicit_update,
573                        &ymom_explicit_update)) {
574    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
575    return NULL;
576  }
577
578  number_of_elements = stage_edge_values -> dimensions[0];
579
580
581  for (k=0; k<number_of_elements; k++) {
582
583    //Reset work array
584    for (j=0; j<3; j++) flux[j] = 0.0;
585
586    //Loop through neighbours and compute edge flux for each
587    for (i=0; i<3; i++) {
588      ki = k*3+i;
589      ql[0] = ((double *) stage_edge_values -> data)[ki];
590      ql[1] = ((double *) xmom_edge_values -> data)[ki];
591      ql[2] = ((double *) ymom_edge_values -> data)[ki];
592      zl =    ((double *) bed_edge_values -> data)[ki];
593
594      //Quantities at neighbour on nearest face
595      n = ((long *) neighbours -> data)[ki];
596      if (n < 0) {
597        m = -n-1; //Convert negative flag to index
598        qr[0] = ((double *) stage_boundary_values -> data)[m];
599        qr[1] = ((double *) xmom_boundary_values -> data)[m];
600        qr[2] = ((double *) ymom_boundary_values -> data)[m];
601        zr = zl; //Extend bed elevation to boundary
602      } else {
603        m = ((long *) neighbour_edges -> data)[ki];
604
605        nm = n*3+m;
606        qr[0] = ((double *) stage_edge_values -> data)[nm];
607        qr[1] = ((double *) xmom_edge_values -> data)[nm];
608        qr[2] = ((double *) ymom_edge_values -> data)[nm];
609        zr =    ((double *) bed_edge_values -> data)[nm];
610      }
611
612      //printf("%d %d [%d] (%d, %d): %.2f %.2f %.2f\n", k, i, ki, n, m,
613      //             ql[0], ql[1], ql[2]);
614
615
616      // Outward pointing normal vector
617      // normal = domain.normals[k, 2*i:2*i+2]
618      ki2 = 2*ki; //k*6 + i*2
619      normal[0] = ((double *) normals -> data)[ki2];
620      normal[1] = ((double *) normals -> data)[ki2+1];
621
622      //Edge flux computation
623      flux_function(ql, qr, zl, zr,
624                    normal[0], normal[1],
625                    epsilon, g,
626                    edgeflux, &max_speed);
627
628
629      //flux -= edgeflux * edgelengths[k,i]
630      for (j=0; j<3; j++) {
631        flux[j] -= edgeflux[j]*((double *) edgelengths -> data)[ki];
632      }
633
634      //Update timestep
635      //timestep = min(timestep, domain.radii[k]/max_speed)
636      //FIXME: SR Add parameter for CFL condition
637      if (max_speed > epsilon) {
638        timestep = min(timestep, ((double *) radii -> data)[k]/max_speed);
639      }
640    } // end for i
641
642    //Normalise by area and store for when all conserved
643    //quantities get updated
644    // flux /= areas[k]
645    for (j=0; j<3; j++) {
646      flux[j] /= ((double *) areas -> data)[k];
647    }
648
649    ((double *) stage_explicit_update -> data)[k] = flux[0];
650    ((double *) xmom_explicit_update -> data)[k] = flux[1];
651    ((double *) ymom_explicit_update -> data)[k] = flux[2];
652
653  } //end for k
654
655  return Py_BuildValue("d", timestep);
656}
657
658
659
660PyObject *protect(PyObject *self, PyObject *args) {
661  //
662  //    protect(minimum_allowed_height, wc, zc, xmomc, ymomc)
663
664
665  PyArrayObject
666  *wc,            //Stage at centroids
667  *zc,            //Elevation at centroids
668  *xmomc,         //Momentums at centroids
669  *ymomc;
670
671
672  int N;
673  double minimum_allowed_height;
674
675  // Convert Python arguments to C
676  if (!PyArg_ParseTuple(args, "dOOOO",
677                        &minimum_allowed_height,
678                        &wc, &zc, &xmomc, &ymomc))
679    return NULL;
680
681  N = wc -> dimensions[0];
682
683  _protect(N,
684           minimum_allowed_height,
685           (double*) wc -> data,
686           (double*) zc -> data,
687           (double*) xmomc -> data,
688           (double*) ymomc -> data);
689
690  return Py_BuildValue("");
691}
692
693
694
695PyObject *balance_deep_and_shallow(PyObject *self, PyObject *args) {
696  //
697  //    balance_deep_and_shallow(wc, zc, hc, wv, zv, hv,
698  //                             xmomc, ymomc, xmomv, ymomv)
699
700
701  PyArrayObject
702    *wc,            //Stage at centroids
703    *zc,            //Elevation at centroids
704    *hc,            //Height at centroids
705    *wv,            //Stage at vertices
706    *zv,            //Elevation at vertices
707    *hv,            //Depths at vertices
708    *hvbar,         //h-Limited depths at vertices
709    *xmomc,         //Momentums at centroids and vertices
710    *ymomc,
711    *xmomv,
712    *ymomv;
713
714  int N; //, err;
715
716  // Convert Python arguments to C
717  if (!PyArg_ParseTuple(args, "OOOOOOOOOOO",
718                        &wc, &zc, &hc,
719                        &wv, &zv, &hv, &hvbar,
720                        &xmomc, &ymomc, &xmomv, &ymomv))
721    return NULL;
722
723  N = wc -> dimensions[0];
724
725  _balance_deep_and_shallow(N,
726                            (double*) wc -> data,
727                            (double*) zc -> data,
728                            (double*) hc -> data,
729                            (double*) wv -> data,
730                            (double*) zv -> data,
731                            (double*) hv -> data,
732                            (double*) hvbar -> data,
733                            (double*) xmomc -> data,
734                            (double*) ymomc -> data,
735                            (double*) xmomv -> data,
736                            (double*) ymomv -> data);
737
738
739  return Py_BuildValue("");
740}
741
742
743
744PyObject *h_limiter(PyObject *self, PyObject *args) {
745
746  PyObject *domain, *Tmp;
747  PyArrayObject
748    *hv, *hc, //Depth at vertices and centroids
749    *hvbar,   //Limited depth at vertices (return values)
750    *neighbours;
751
752  int k, i, n, N, k3;
753  int dimensions[2];
754  double beta_h; //Safety factor (see config.py)
755  double *hmin, *hmax, hn;
756
757  // Convert Python arguments to C
758  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv))
759    return NULL;
760
761  neighbours = get_consecutive_array(domain, "neighbours");
762
763  //Get safety factor beta_h
764  Tmp = PyObject_GetAttrString(domain, "beta_h");
765  if (!Tmp)
766    return NULL;
767
768  beta_h = PyFloat_AsDouble(Tmp);
769
770  Py_DECREF(Tmp);
771
772  N = hc -> dimensions[0];
773
774  //Create hvbar
775  dimensions[0] = N;
776  dimensions[1] = 3;
777  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
778
779
780  //Find min and max of this and neighbour's centroid values
781  hmin = malloc(N * sizeof(double));
782  hmax = malloc(N * sizeof(double));
783  for (k=0; k<N; k++) {
784    k3=k*3;
785
786    hmin[k] = ((double*) hc -> data)[k];
787    hmax[k] = hmin[k];
788
789    for (i=0; i<3; i++) {
790      n = ((long*) neighbours -> data)[k3+i];
791
792      //Initialise hvbar with values from hv
793      ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i];
794
795      if (n >= 0) {
796        hn = ((double*) hc -> data)[n]; //Neighbour's centroid value
797
798        hmin[k] = min(hmin[k], hn);
799        hmax[k] = max(hmax[k], hn);
800      }
801    }
802  }
803
804  // Call underlying standard routine
805  _limit(N, beta_h, (double*) hc -> data, (double*) hvbar -> data, hmin, hmax);
806
807  // // //Py_DECREF(domain); //FIXME: NEcessary?
808  free(hmin);
809  free(hmax);
810
811  //return result using PyArray to avoid memory leak
812  return PyArray_Return(hvbar);
813  //return Py_BuildValue("");
814}
815
816
817
818
819PyObject *assign_windfield_values(PyObject *self, PyObject *args) {
820  //
821  //      assign_windfield_values(xmom_update, ymom_update,
822  //                              s_vec, phi_vec, self.const)
823
824
825
826  PyArrayObject   //(one element per triangle)
827  *s_vec,         //Speeds
828  *phi_vec,       //Bearings
829  *xmom_update,   //Momentum updates
830  *ymom_update;
831
832
833  int N;
834  double cw;
835
836  // Convert Python arguments to C
837  if (!PyArg_ParseTuple(args, "OOOOd",
838                        &xmom_update,
839                        &ymom_update,
840                        &s_vec, &phi_vec,
841                        &cw))
842    return NULL;
843
844  N = xmom_update -> dimensions[0];
845
846  _assign_wind_field_values(N,
847           (double*) xmom_update -> data,
848           (double*) ymom_update -> data,
849           (double*) s_vec -> data,
850           (double*) phi_vec -> data,
851           cw);
852
853  return Py_BuildValue("");
854}
855
856
857
858
859//////////////////////////////////////////
860// Method table for python module
861static struct PyMethodDef MethodTable[] = {
862  /* The cast of the function is necessary since PyCFunction values
863   * only take two PyObject* parameters, and rotate() takes
864   * three.
865   */
866
867  {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
868  {"compute_fluxes", compute_fluxes, METH_VARARGS, "Print out"},
869  {"gravity", gravity, METH_VARARGS, "Print out"},
870  {"manning_friction", manning_friction, METH_VARARGS, "Print out"},
871  {"balance_deep_and_shallow", balance_deep_and_shallow,
872   METH_VARARGS, "Print out"},
873  {"h_limiter", h_limiter,
874   METH_VARARGS, "Print out"},
875  {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"},
876  {"assign_windfield_values", assign_windfield_values,
877   METH_VARARGS | METH_KEYWORDS, "Print out"},
878  //{"distribute_to_vertices_and_edges",
879  // distribute_to_vertices_and_edges, METH_VARARGS},
880  //{"update_conserved_quantities",
881  // update_conserved_quantities, METH_VARARGS},
882  //{"set_initialcondition",
883  // set_initialcondition, METH_VARARGS},
884  {NULL, NULL}
885};
886
887// Module initialisation
888void initshallow_water_ext(void){
889  Py_InitModule("shallow_water_ext", MethodTable);
890
891  import_array();     //Necessary for handling of NumPY structures
892}
Note: See TracBrowser for help on using the repository browser.