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

Last change on this file since 1018 was 1017, checked in by ole, 20 years ago
File size: 23.0 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
231    if (dz > 0.0)
232      //if (hmin<0.0)
233      //        alpha = 0.0;
234      //else
235      //  alpha = max( min( hc[k]/dz, 1.0), 0.0 );
236      alpha = max( min( 2.0*hmin/dz, 1.0), 0.0 );
237   
238    else
239      alpha = 1.0;  //Flat bed
240
241    //printf("dz = %.3f, alpha = %.8f\n", dz, alpha);
242
243    //  Let
244    // 
245    //    wvi be the w-limited stage (wvi = zvi + hvi)       
246    //    wvi- be the h-limited state (wvi- = zvi + hvi-)
247    //     
248    //     
249    //  where i=0,1,2 denotes the vertex ids
250    // 
251    //  Weighted balance between w-limited and h-limited stage is 
252    //   
253    //    wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)   
254    // 
255    //  It follows that the updated wvi is
256    //    wvi := zvi + (1-alpha)*hvi- + alpha*hvi
257    //   
258    //   Momentum is balanced between constant and limited
259
260    if (alpha < 1) {         
261      for (i=0; i<3; i++) {
262        wv[k3+i] = zv[k3+i] + (1-alpha)*hvbar[k3+i] + alpha*hv[k3+i];
263           
264        //Update momentum as a linear combination of
265        //xmomc and ymomc (shallow) and momentum
266        //from extrapolator xmomv and ymomv (deep).
267        xmomv[k3+i] = (1-alpha)*xmomc[k] + alpha*xmomv[k3+i];           
268        ymomv[k3+i] = (1-alpha)*ymomc[k] + alpha*ymomv[k3+i];
269      } 
270    }
271  }         
272  return 0;
273}
274
275
276
277int _protect(int N, 
278             double minimum_allowed_height,       
279             double* wc,
280             double* zc, 
281             double* xmomc, 
282             double* ymomc) {
283 
284  int k; 
285  double hc;
286 
287  //Protect against initesimal and negative heights
288 
289  for (k=0; k<N; k++) {
290    hc = wc[k] - zc[k];
291   
292    if (hc < minimum_allowed_height) {   
293      wc[k] = zc[k];       
294      xmomc[k] = 0.0;
295      ymomc[k] = 0.0;     
296    }
297   
298  }
299  return 0;
300}
301
302
303
304
305
306
307
308
309int _assign_wind_field_values(int N,
310                              double* xmom_update,
311                              double* ymom_update, 
312                              double* s_vec,
313                              double* phi_vec,
314                              double cw) {
315
316  //Assign windfield values to momentum updates
317
318  int k;
319  double S, s, phi, u, v;
320 
321  for (k=0; k<N; k++) {
322   
323    s = s_vec[k];
324    phi = phi_vec[k];
325
326    //Convert to radians
327    phi = phi*pi/180;
328
329    //Compute velocity vector (u, v)
330    u = s*cos(phi);
331    v = s*sin(phi);
332       
333    //Compute wind stress
334    S = cw * sqrt(u*u + v*v);
335    xmom_update[k] += S*u;
336    ymom_update[k] += S*v;       
337  }
338  return 0; 
339}           
340
341
342
343///////////////////////////////////////////////////////////////////
344// Gateways to Python
345
346PyObject *gravity(PyObject *self, PyObject *args) {
347  //
348  //  gravity(g, h, v, x, xmom, ymom)
349  //
350 
351 
352  PyArrayObject *h, *v, *x, *xmom, *ymom;
353  int k, i, N, k3, k6;
354  double g, avg_h, zx, zy;
355  double x0, y0, x1, y1, x2, y2, z0, z1, z2;
356   
357  if (!PyArg_ParseTuple(args, "dOOOOO",
358                        &g, &h, &v, &x, 
359                        &xmom, &ymom)) 
360    return NULL; 
361
362  N = h -> dimensions[0];
363  for (k=0; k<N; k++) {
364    k3 = 3*k;  // base index
365    k6 = 6*k;  // base index   
366   
367    avg_h = 0.0;
368    for (i=0; i<3; i++) {
369      avg_h += ((double *) h -> data)[k3+i];
370    }   
371    avg_h /= 3;
372       
373   
374    //Compute bed slope
375    x0 = ((double*) x -> data)[k6 + 0];
376    y0 = ((double*) x -> data)[k6 + 1];   
377    x1 = ((double*) x -> data)[k6 + 2];
378    y1 = ((double*) x -> data)[k6 + 3];       
379    x2 = ((double*) x -> data)[k6 + 4];
380    y2 = ((double*) x -> data)[k6 + 5];           
381
382
383    z0 = ((double*) v -> data)[k3 + 0];
384    z1 = ((double*) v -> data)[k3 + 1];
385    z2 = ((double*) v -> data)[k3 + 2];       
386
387    _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy);
388
389    //Update momentum
390    ((double*) xmom -> data)[k] += -g*zx*avg_h;
391    ((double*) ymom -> data)[k] += -g*zy*avg_h;       
392  }
393   
394  return Py_BuildValue("");
395}
396
397
398PyObject *manning_friction(PyObject *self, PyObject *args) {
399  //
400  // manning_friction(g, eps, h, uh, vh, eta, xmom_update, ymom_update)
401  //
402 
403 
404  PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom;
405  int N;
406  double g, eps;
407   
408  if (!PyArg_ParseTuple(args, "ddOOOOOOO",
409                        &g, &eps, &w, &z, &uh, &vh, &eta, 
410                        &xmom, &ymom)) 
411    return NULL; 
412
413  N = w -> dimensions[0];   
414  _manning_friction(g, eps, N,
415                    (double*) w -> data,
416                    (double*) z -> data,                   
417                    (double*) uh -> data, 
418                    (double*) vh -> data, 
419                    (double*) eta -> data,
420                    (double*) xmom -> data, 
421                    (double*) ymom -> data);
422
423  return Py_BuildValue("");
424}                   
425
426PyObject *rotate(PyObject *self, PyObject *args, PyObject *kwargs) {
427  //
428  // r = rotate(q, normal, direction=1)
429  //
430  // Where q is assumed to be a Float numeric array of length 3 and
431  // normal a Float numeric array of length 2.
432
433 
434  PyObject *Q, *Normal;
435  PyArrayObject *q, *r, *normal;
436 
437  static char *argnames[] = {"q", "normal", "direction", NULL};
438  int dimensions[1], i, direction=1;
439  double n1, n2;
440
441  // Convert Python arguments to C 
442  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames, 
443                                   &Q, &Normal, &direction)) 
444    return NULL; 
445
446  //Input checks (convert sequences into numeric arrays)
447  q = (PyArrayObject *) 
448    PyArray_ContiguousFromObject(Q, PyArray_DOUBLE, 0, 0);
449  normal = (PyArrayObject *) 
450    PyArray_ContiguousFromObject(Normal, PyArray_DOUBLE, 0, 0);
451
452 
453  if (normal -> dimensions[0] != 2) {
454    PyErr_SetString(PyExc_RuntimeError, "Normal vector must have 2 components");
455    return NULL;
456  }
457
458  //Allocate space for return vector r (don't DECREF)
459  dimensions[0] = 3;
460  r = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
461
462  //Copy
463  for (i=0; i<3; i++) {
464    ((double *) (r -> data))[i] = ((double *) (q -> data))[i]; 
465  }
466 
467  //Get normal and direction
468  n1 = ((double *) normal -> data)[0]; 
469  n2 = ((double *) normal -> data)[1];   
470  if (direction == -1) n2 = -n2;
471
472  //Rotate
473  _rotate((double *) r -> data, n1, n2);
474
475  //Release numeric arrays
476  Py_DECREF(q);   
477  Py_DECREF(normal);
478       
479  //return result using PyArray to avoid memory leak
480  return PyArray_Return(r);
481}   
482
483
484PyObject *compute_fluxes(PyObject *self, PyObject *args) {
485  /*Compute all fluxes and the timestep suitable for all volumes
486    in domain.
487
488    Compute total flux for each conserved quantity using "flux_function"
489
490    Fluxes across each edge are scaled by edgelengths and summed up
491    Resulting flux is then scaled by area and stored in
492    explicit_update for each of the three conserved quantities
493    stage, xmomentum and ymomentum
494
495    The maximal allowable speed computed by the flux_function for each volume
496    is converted to a timestep that must not be exceeded. The minimum of
497    those is computed as the next overall timestep.
498   
499    Python call:
500    domain.timestep = compute_fluxes(timestep,
501                                     domain.epsilon,
502                                     domain.g,
503                                     domain.neighbours,
504                                     domain.neighbour_edges,
505                                     domain.normals,
506                                     domain.edgelengths,                       
507                                     domain.radii,
508                                     domain.areas,
509                                     Stage.edge_values,
510                                     Xmom.edge_values,
511                                     Ymom.edge_values, 
512                                     Bed.edge_values,   
513                                     Stage.boundary_values,
514                                     Xmom.boundary_values,
515                                     Ymom.boundary_values,
516                                     Stage.explicit_update,
517                                     Xmom.explicit_update,
518                                     Ymom.explicit_update)
519       
520
521    Post conditions:
522      domain.explicit_update is reset to computed flux values
523      domain.timestep is set to the largest step satisfying all volumes.
524
525           
526  */
527
528 
529  PyArrayObject *neighbours, *neighbour_edges,
530    *normals, *edgelengths, *radii, *areas,
531    *stage_edge_values, 
532    *xmom_edge_values, 
533    *ymom_edge_values, 
534    *bed_edge_values,   
535    *stage_boundary_values,
536    *xmom_boundary_values,
537    *ymom_boundary_values,
538    *stage_explicit_update,
539    *xmom_explicit_update,
540    *ymom_explicit_update;
541
542   
543  //Local variables 
544  double timestep, max_speed, epsilon, g;
545  double normal[2], ql[3], qr[3], zl, zr;
546  double flux[3], edgeflux[3]; //Work arrays for summing up fluxes
547
548  int number_of_elements, k, i, j, m, n;
549  int ki, nm, ki2; //Index shorthands
550 
551 
552  // Convert Python arguments to C 
553  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOOOOOO",
554                        &timestep,
555                        &epsilon,
556                        &g,
557                        &neighbours, 
558                        &neighbour_edges,
559                        &normals, 
560                        &edgelengths, &radii, &areas,
561                        &stage_edge_values, 
562                        &xmom_edge_values, 
563                        &ymom_edge_values, 
564                        &bed_edge_values,   
565                        &stage_boundary_values,
566                        &xmom_boundary_values,
567                        &ymom_boundary_values,
568                        &stage_explicit_update,
569                        &xmom_explicit_update,
570                        &ymom_explicit_update)) {
571    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
572    return NULL;
573  }
574
575  number_of_elements = stage_edge_values -> dimensions[0];
576 
577   
578  for (k=0; k<number_of_elements; k++) {
579
580    //Reset work array
581    for (j=0; j<3; j++) flux[j] = 0.0;
582                         
583    //Loop through neighbours and compute edge flux for each
584    for (i=0; i<3; i++) {
585      ki = k*3+i;
586      ql[0] = ((double *) stage_edge_values -> data)[ki];
587      ql[1] = ((double *) xmom_edge_values -> data)[ki];
588      ql[2] = ((double *) ymom_edge_values -> data)[ki];           
589      zl =    ((double *) bed_edge_values -> data)[ki];                 
590
591      //Quantities at neighbour on nearest face
592      n = ((long *) neighbours -> data)[ki];
593      if (n < 0) {
594        m = -n-1; //Convert negative flag to index
595        qr[0] = ((double *) stage_boundary_values -> data)[m]; 
596        qr[1] = ((double *) xmom_boundary_values -> data)[m];   
597        qr[2] = ((double *) ymom_boundary_values -> data)[m];   
598        zr = zl; //Extend bed elevation to boundary
599      } else {   
600        m = ((long *) neighbour_edges -> data)[ki];
601       
602        nm = n*3+m;     
603        qr[0] = ((double *) stage_edge_values -> data)[nm];
604        qr[1] = ((double *) xmom_edge_values -> data)[nm];
605        qr[2] = ((double *) ymom_edge_values -> data)[nm];           
606        zr =    ((double *) bed_edge_values -> data)[nm];                 
607      }
608
609      //printf("%d %d [%d] (%d, %d): %.2f %.2f %.2f\n", k, i, ki, n, m,
610      //             ql[0], ql[1], ql[2]);       
611
612     
613      // Outward pointing normal vector   
614      // normal = domain.normals[k, 2*i:2*i+2]
615      ki2 = 2*ki; //k*6 + i*2
616      normal[0] = ((double *) normals -> data)[ki2];
617      normal[1] = ((double *) normals -> data)[ki2+1];     
618
619      //Edge flux computation
620      flux_function(ql, qr, zl, zr, 
621                    normal[0], normal[1],
622                    epsilon, g, 
623                    edgeflux, &max_speed);
624
625                   
626      //flux -= edgeflux * edgelengths[k,i]
627      for (j=0; j<3; j++) { 
628        flux[j] -= edgeflux[j]*((double *) edgelengths -> data)[ki];
629      }
630     
631      //Update timestep
632      //timestep = min(timestep, domain.radii[k]/max_speed)
633      //FIXME: SR Add parameter for CFL condition
634      if (max_speed > epsilon) {
635        timestep = min(timestep, ((double *) radii -> data)[k]/max_speed);
636      }   
637    } // end for i
638   
639    //Normalise by area and store for when all conserved
640    //quantities get updated
641    // flux /= areas[k]
642    for (j=0; j<3; j++) { 
643      flux[j] /= ((double *) areas -> data)[k];
644    }
645
646    ((double *) stage_explicit_update -> data)[k] = flux[0];
647    ((double *) xmom_explicit_update -> data)[k] = flux[1];
648    ((double *) ymom_explicit_update -> data)[k] = flux[2];       
649
650  } //end for k
651
652  return Py_BuildValue("d", timestep);
653}   
654
655
656
657PyObject *protect(PyObject *self, PyObject *args) {
658  //
659  //    protect(minimum_allowed_height, wc, zc, xmomc, ymomc)
660 
661
662  PyArrayObject
663  *wc,            //Stage at centroids
664  *zc,            //Elevation at centroids   
665  *xmomc,         //Momentums at centroids
666  *ymomc; 
667
668   
669  int N; 
670  double minimum_allowed_height;
671 
672  // Convert Python arguments to C 
673  if (!PyArg_ParseTuple(args, "dOOOO", 
674                        &minimum_allowed_height,
675                        &wc, &zc, &xmomc, &ymomc))
676    return NULL;
677
678  N = wc -> dimensions[0];
679   
680  _protect(N,
681           minimum_allowed_height,
682           (double*) wc -> data,
683           (double*) zc -> data, 
684           (double*) xmomc -> data, 
685           (double*) ymomc -> data);
686 
687  return Py_BuildValue(""); 
688}
689
690
691
692PyObject *balance_deep_and_shallow(PyObject *self, PyObject *args) {
693  //
694  //    balance_deep_and_shallow(wc, zc, hc, wv, zv, hv,
695  //                             xmomc, ymomc, xmomv, ymomv)
696 
697
698  PyArrayObject
699    *wc,            //Stage at centroids
700    *zc,            //Elevation at centroids   
701    *hc,            //Height at centroids       
702    *wv,            //Stage at vertices
703    *zv,            //Elevation at vertices
704    *hv,            //Depths at vertices   
705    *hvbar,         //h-Limited depths at vertices       
706    *xmomc,         //Momentums at centroids and vertices
707    *ymomc, 
708    *xmomv, 
709    *ymomv;   
710   
711  int N; //, err;
712 
713  // Convert Python arguments to C 
714  if (!PyArg_ParseTuple(args, "OOOOOOOOOOO", 
715                        &wc, &zc, &hc, 
716                        &wv, &zv, &hv, &hvbar,
717                        &xmomc, &ymomc, &xmomv, &ymomv))
718    return NULL;
719
720  N = wc -> dimensions[0];
721   
722  _balance_deep_and_shallow(N,
723                            (double*) wc -> data,
724                            (double*) zc -> data, 
725                            (double*) hc -> data,                           
726                            (double*) wv -> data, 
727                            (double*) zv -> data, 
728                            (double*) hv -> data,
729                            (double*) hvbar -> data,                       
730                            (double*) xmomc -> data, 
731                            (double*) ymomc -> data, 
732                            (double*) xmomv -> data, 
733                            (double*) ymomv -> data); 
734 
735 
736  return Py_BuildValue(""); 
737}
738
739
740
741PyObject *h_limiter(PyObject *self, PyObject *args) {
742 
743  PyObject *domain, *Tmp;
744  PyArrayObject
745    *hv, *hc, //Depth at vertices and centroids       
746    *hvbar,   //Limited depth at vertices (return values)
747    *neighbours;
748   
749  int k, i, n, N, k3;
750  int dimensions[2];
751  double beta_h; //Safety factor (see config.py)
752  double *hmin, *hmax, hn;
753 
754  // Convert Python arguments to C 
755  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv)) 
756    return NULL;
757
758  neighbours = get_consecutive_array(domain, "neighbours");
759
760  //Get safety factor beta_h
761  Tmp = PyObject_GetAttrString(domain, "beta_h"); 
762  if (!Tmp) 
763    return NULL;
764     
765  beta_h = PyFloat_AsDouble(Tmp); 
766 
767  Py_DECREF(Tmp);   
768
769  N = hc -> dimensions[0];
770 
771  //Create hvbar
772  dimensions[0] = N;
773  dimensions[1] = 3; 
774  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
775 
776
777  //Find min and max of this and neighbour's centroid values
778  hmin = malloc(N * sizeof(double));
779  hmax = malloc(N * sizeof(double)); 
780  for (k=0; k<N; k++) {
781    k3=k*3;
782   
783    hmin[k] = ((double*) hc -> data)[k];
784    hmax[k] = hmin[k];
785   
786    for (i=0; i<3; i++) {
787      n = ((long*) neighbours -> data)[k3+i];
788     
789      //Initialise hvbar with values from hv
790      ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i]; 
791     
792      if (n >= 0) {
793        hn = ((double*) hc -> data)[n]; //Neighbour's centroid value
794         
795        hmin[k] = min(hmin[k], hn);
796        hmax[k] = max(hmax[k], hn);
797      }
798    }
799  }
800 
801  // Call underlying standard routine
802  _limit(N, beta_h, (double*) hc -> data, (double*) hvbar -> data, hmin, hmax);
803         
804  // // //Py_DECREF(domain); //FIXME: NEcessary?         
805  free(hmin);
806  free(hmax); 
807 
808  //return result using PyArray to avoid memory leak 
809  return PyArray_Return(hvbar);
810  //return Py_BuildValue("");   
811}
812
813
814
815
816PyObject *assign_windfield_values(PyObject *self, PyObject *args) {
817  //
818  //      assign_windfield_values(xmom_update, ymom_update,
819  //                              s_vec, phi_vec, self.const)
820
821 
822
823  PyArrayObject   //(one element per triangle)
824  *s_vec,         //Speeds
825  *phi_vec,       //Bearings
826  *xmom_update,   //Momentum updates
827  *ymom_update; 
828
829   
830  int N; 
831  double cw;
832 
833  // Convert Python arguments to C 
834  if (!PyArg_ParseTuple(args, "OOOOd", 
835                        &xmom_update,
836                        &ymom_update,                   
837                        &s_vec, &phi_vec, 
838                        &cw))
839    return NULL;
840
841  N = xmom_update -> dimensions[0];
842   
843  _assign_wind_field_values(N,
844           (double*) xmom_update -> data,
845           (double*) ymom_update -> data, 
846           (double*) s_vec -> data, 
847           (double*) phi_vec -> data,
848           cw);
849 
850  return Py_BuildValue(""); 
851}
852
853
854
855
856//////////////////////////////////////////     
857// Method table for python module
858static struct PyMethodDef MethodTable[] = {
859  /* The cast of the function is necessary since PyCFunction values
860   * only take two PyObject* parameters, and rotate() takes
861   * three.
862   */
863 
864  {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
865  {"compute_fluxes", compute_fluxes, METH_VARARGS, "Print out"},   
866  {"gravity", gravity, METH_VARARGS, "Print out"},     
867  {"manning_friction", manning_friction, METH_VARARGS, "Print out"},       
868  {"balance_deep_and_shallow", balance_deep_and_shallow, 
869   METH_VARARGS, "Print out"},         
870  {"h_limiter", h_limiter, 
871   METH_VARARGS, "Print out"},             
872  {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"},   
873  {"assign_windfield_values", assign_windfield_values, 
874   METH_VARARGS | METH_KEYWORDS, "Print out"},     
875  //{"distribute_to_vertices_and_edges",
876  // distribute_to_vertices_and_edges, METH_VARARGS},   
877  //{"update_conserved_quantities",
878  // update_conserved_quantities, METH_VARARGS},       
879  //{"set_initialcondition",
880  // set_initialcondition, METH_VARARGS},   
881  {NULL, NULL}
882};
883       
884// Module initialisation   
885void initshallow_water_ext(void){
886  Py_InitModule("shallow_water_ext", MethodTable);
887 
888  import_array();     //Necessary for handling of NumPY structures 
889}
Note: See TracBrowser for help on using the repository browser.