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

Last change on this file since 947 was 907, checked in by ole, 20 years ago

Addressed problem with artificial momentum generated by discontinuous water depths in the presence of steep slopes.
Now very shallow water is limited with a separate h-limiter controlled by beta_h
(see config.py) for details.

File size: 22.6 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      if (max_speed > epsilon) {
628        timestep = min(timestep, ((double *) radii -> data)[k]/max_speed);
629      }   
630    } // end for i
631   
632    //Normalise by area and store for when all conserved
633    //quantities get updated
634    // flux /= areas[k]
635    for (j=0; j<3; j++) { 
636      flux[j] /= ((double *) areas -> data)[k];
637    }
638
639    ((double *) stage_explicit_update -> data)[k] = flux[0];
640    ((double *) xmom_explicit_update -> data)[k] = flux[1];
641    ((double *) ymom_explicit_update -> data)[k] = flux[2];       
642
643  } //end for k
644
645  return Py_BuildValue("d", timestep);
646}   
647
648
649
650PyObject *protect(PyObject *self, PyObject *args) {
651  //
652  //    protect(minimum_allowed_height, wc, zc, xmomc, ymomc)
653 
654
655  PyArrayObject
656  *wc,            //Stage at centroids
657  *zc,            //Elevation at centroids   
658  *xmomc,         //Momentums at centroids
659  *ymomc; 
660
661   
662  int N; 
663  double minimum_allowed_height;
664 
665  // Convert Python arguments to C 
666  if (!PyArg_ParseTuple(args, "dOOOO", 
667                        &minimum_allowed_height,
668                        &wc, &zc, &xmomc, &ymomc))
669    return NULL;
670
671  N = wc -> dimensions[0];
672   
673  _protect(N,
674           minimum_allowed_height,
675           (double*) wc -> data,
676           (double*) zc -> data, 
677           (double*) xmomc -> data, 
678           (double*) ymomc -> data);
679 
680  return Py_BuildValue(""); 
681}
682
683
684
685PyObject *balance_deep_and_shallow(PyObject *self, PyObject *args) {
686  //
687  //    balance_deep_and_shallow(wc, zc, hc, wv, zv, hv,
688  //                             xmomc, ymomc, xmomv, ymomv)
689 
690
691  PyArrayObject
692    *wc,            //Stage at centroids
693    *zc,            //Elevation at centroids   
694    *hc,            //Height at centroids       
695    *wv,            //Stage at vertices
696    *zv,            //Elevation at vertices
697    *hv,            //Depths at vertices   
698    *hvbar,         //h-Limited depths at vertices       
699    *xmomc,         //Momentums at centroids and vertices
700    *ymomc, 
701    *xmomv, 
702    *ymomv;   
703   
704  int N; //, err;
705 
706  // Convert Python arguments to C 
707  if (!PyArg_ParseTuple(args, "OOOOOOOOOOO", 
708                        &wc, &zc, &hc, 
709                        &wv, &zv, &hv, &hvbar,
710                        &xmomc, &ymomc, &xmomv, &ymomv))
711    return NULL;
712
713  N = wc -> dimensions[0];
714   
715  _balance_deep_and_shallow(N,
716                            (double*) wc -> data,
717                            (double*) zc -> data, 
718                            (double*) hc -> data,                           
719                            (double*) wv -> data, 
720                            (double*) zv -> data, 
721                            (double*) hv -> data,
722                            (double*) hvbar -> data,                       
723                            (double*) xmomc -> data, 
724                            (double*) ymomc -> data, 
725                            (double*) xmomv -> data, 
726                            (double*) ymomv -> data); 
727 
728 
729  return Py_BuildValue(""); 
730}
731
732
733
734PyObject *h_limiter(PyObject *self, PyObject *args) {
735 
736  PyObject *domain, *Tmp;
737  PyArrayObject
738    *hv, *hc, //Depth at vertices and centroids       
739    *hvbar,   //Limited depth at vertices (return values)
740    *neighbours;
741   
742  int k, i, n, N, k3;
743  int dimensions[2];
744  double beta_h; //Safety factor (see config.py)
745  double *hmin, *hmax, hn;
746 
747  // Convert Python arguments to C 
748  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv)) 
749    return NULL;
750
751  neighbours = get_consecutive_array(domain, "neighbours");
752
753  //Get safety factor beta_h
754  Tmp = PyObject_GetAttrString(domain, "beta_h"); 
755  if (!Tmp) 
756    return NULL;
757     
758  beta_h = PyFloat_AsDouble(Tmp); 
759 
760  Py_DECREF(Tmp);   
761
762  N = hc -> dimensions[0];
763 
764  //Create hvbar
765  dimensions[0] = N;
766  dimensions[1] = 3; 
767  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
768
769     
770  //Find min and max of this and neighbour's centroid values
771  hmin = malloc(N * sizeof(double));
772  hmax = malloc(N * sizeof(double)); 
773  for (k=0; k<N; k++) {
774    k3=k*3;
775   
776    hmin[k] = ((double*) hc -> data)[k];
777    hmax[k] = hmin[k];
778   
779    for (i=0; i<3; i++) {
780      n = ((long*) neighbours -> data)[k3+i];
781      if (n >= 0) {
782        hn = ((double*) hc -> data)[n]; //Neighbour's centroid value
783         
784        hmin[k] = min(hmin[k], hn);
785        hmax[k] = max(hmax[k], hn);
786      }
787    }
788  }
789 
790 
791  // Call underlying routine
792  _limit(N, beta_h, (double*) hc -> data, (double*) hvbar -> data, hmin, hmax);
793         
794  // // //Py_DECREF(domain); //FIXME: NEcessary?         
795  free(hmin);
796  free(hmax); 
797 
798  //return result using PyArray to avoid memory leak 
799  return PyArray_Return(hvbar);
800}
801
802
803
804
805PyObject *assign_windfield_values(PyObject *self, PyObject *args) {
806  //
807  //      assign_windfield_values(xmom_update, ymom_update,
808  //                              s_vec, phi_vec, self.const)
809
810 
811
812  PyArrayObject   //(one element per triangle)
813  *s_vec,         //Speeds
814  *phi_vec,       //Bearings
815  *xmom_update,   //Momentum updates
816  *ymom_update; 
817
818   
819  int N; 
820  double cw;
821 
822  // Convert Python arguments to C 
823  if (!PyArg_ParseTuple(args, "OOOOd", 
824                        &xmom_update,
825                        &ymom_update,                   
826                        &s_vec, &phi_vec, 
827                        &cw))
828    return NULL;
829
830  N = xmom_update -> dimensions[0];
831   
832  _assign_wind_field_values(N,
833           (double*) xmom_update -> data,
834           (double*) ymom_update -> data, 
835           (double*) s_vec -> data, 
836           (double*) phi_vec -> data,
837           cw);
838 
839  return Py_BuildValue(""); 
840}
841
842
843
844
845//////////////////////////////////////////     
846// Method table for python module
847static struct PyMethodDef MethodTable[] = {
848  /* The cast of the function is necessary since PyCFunction values
849   * only take two PyObject* parameters, and rotate() takes
850   * three.
851   */
852 
853  {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
854  {"compute_fluxes", compute_fluxes, METH_VARARGS, "Print out"},   
855  {"gravity", gravity, METH_VARARGS, "Print out"},     
856  {"manning_friction", manning_friction, METH_VARARGS, "Print out"},       
857  {"balance_deep_and_shallow", balance_deep_and_shallow, 
858   METH_VARARGS, "Print out"},         
859  {"h_limiter", h_limiter, 
860   METH_VARARGS, "Print out"},             
861  {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"},   
862  {"assign_windfield_values", assign_windfield_values, 
863   METH_VARARGS | METH_KEYWORDS, "Print out"},     
864  //{"distribute_to_vertices_and_edges",
865  // distribute_to_vertices_and_edges, METH_VARARGS},   
866  //{"update_conserved_quantities",
867  // update_conserved_quantities, METH_VARARGS},       
868  //{"set_initialcondition",
869  // set_initialcondition, METH_VARARGS},   
870  {NULL, NULL}
871};
872       
873// Module initialisation   
874void initshallow_water_ext(void){
875  Py_InitModule("shallow_water_ext", MethodTable);
876 
877  import_array();     //Necessary for handling of NumPY structures 
878}
Note: See TracBrowser for help on using the repository browser.