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

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