source: inundation/pyvolution/shallow_water_ext.c @ 2715

Last change on this file since 2715 was 2715, checked in by ole, 18 years ago

Comments regarding friction

File size: 44.8 KB
Line 
1// Python - C extension module for shallow_water.py
2//
3// To compile (Python2.3):
4//  gcc -c domain_ext.c -I/usr/include/python2.3 -o domain_ext.o -Wall -O
5//  gcc -shared domain_ext.o  -o domain_ext.so
6//
7// or use python compile.py
8//
9// See the module shallow_water.py
10//
11//
12// Ole Nielsen, GA 2004
13
14
15#include "Python.h"
16#include "Numeric/arrayobject.h"
17#include "math.h"
18#include <stdio.h>
19
20//Shared code snippets
21#include "util_ext.h"
22
23const double pi = 3.14159265358979;
24
25// Computational function for rotation
26int _rotate(double *q, double n1, double n2) {
27  /*Rotate the momentum component q (q[1], q[2])
28    from x,y coordinates to coordinates based on normal vector (n1, n2).
29
30    Result is returned in array 3x1 r
31    To rotate in opposite direction, call rotate with (q, n1, -n2)
32
33    Contents of q are changed by this function */
34
35
36  double q1, q2;
37
38  //Shorthands
39  q1 = q[1];  //uh momentum
40  q2 = q[2];  //vh momentum
41
42  //Rotate
43  q[1] =  n1*q1 + n2*q2;
44  q[2] = -n2*q1 + n1*q2;
45
46  return 0;
47}
48
49int find_qmin_and_qmax(double dq0, double dq1, double dq2, double *qmin, double *qmax){
50  //Considering the centroid of an FV triangle and the vertices of its auxiliary triangle, find
51  //qmin=min(q)-qc and qmax=max(q)-qc, where min(q) and max(q) are respectively min and max over the
52  //four values (at the centroid of the FV triangle and the auxiliary triangle vertices),
53  //and qc is the centroid
54  //dq0=q(vertex0)-q(centroid of FV triangle)
55  //dq1=q(vertex1)-q(vertex0)
56  //dq2=q(vertex2)-q(vertex0)
57  if (dq0>=0.0){
58    if (dq1>=dq2){
59      if (dq1>=0.0)
60        *qmax=dq0+dq1;
61      else
62        *qmax=dq0;
63      if ((*qmin=dq0+dq2)<0)
64        ;//qmin is already set to correct value
65      else
66        *qmin=0.0;
67    }
68    else{//dq1<dq2
69      if (dq2>0)
70        *qmax=dq0+dq2;
71      else
72        *qmax=dq0;
73      if ((*qmin=dq0+dq1)<0)
74        ;//qmin is the correct value
75      else
76        *qmin=0.0;
77    }
78  }
79  else{//dq0<0
80    if (dq1<=dq2){
81      if (dq1<0.0)
82        *qmin=dq0+dq1;
83      else
84        *qmin=dq0;
85      if ((*qmax=dq0+dq2)>0.0)
86        ;//qmax is already set to the correct value
87      else
88        *qmax=0.0;
89    }
90    else{//dq1>dq2
91      if (dq2<0.0)
92        *qmin=dq0+dq2;
93      else
94        *qmin=dq0;
95      if ((*qmax=dq0+dq1)>0.0)
96        ;//qmax is already set to the correct value
97      else
98        *qmax=0.0;
99    }
100  }
101  return 0;
102}
103
104int limit_gradient(double *dqv, double qmin, double qmax, double beta_w){
105  //given provisional jumps dqv from the FV triangle centroid to its vertices and
106  //jumps qmin (qmax) between the centroid of the FV triangle and the
107  //minimum (maximum) of the values at the centroid of the FV triangle and the auxiliary triangle vertices,
108  //calculate a multiplicative factor phi by which the provisional vertex jumps are to be limited
109  int i;
110  double r=1000.0, r0=1.0, phi=1.0;
111  static double TINY = 1.0e-100;//to avoid machine accuracy problems.
112  //Any provisional jump with magnitude < TINY does not contribute to the limiting process.
113  for (i=0;i<3;i++){
114    if (dqv[i]<-TINY)
115      r0=qmin/dqv[i];
116    if (dqv[i]>TINY)
117      r0=qmax/dqv[i];
118    r=min(r0,r);
119    //
120  }
121  phi=min(r*beta_w,1.0);
122  for (i=0;i<3;i++)
123    dqv[i]=dqv[i]*phi;
124  return 0;
125}
126
127// Computational function for flux computation (using stage w=z+h)
128int flux_function(double *q_left, double *q_right,
129                  double z_left, double z_right,
130                  double n1, double n2,
131                  double epsilon, double g,
132                  double *edgeflux, double *max_speed) {
133
134  /*Compute fluxes between volumes for the shallow water wave equation
135    cast in terms of the 'stage', w = h+z using
136    the 'central scheme' as described in
137
138    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
139    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
140    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
141
142    The implemented formula is given in equation (3.15) on page 714
143  */
144
145  int i;
146
147  double w_left, h_left, uh_left, vh_left, u_left;
148  double w_right, h_right, uh_right, vh_right, u_right;
149  double s_min, s_max, soundspeed_left, soundspeed_right;
150  double denom, z;
151  double q_left_copy[3], q_right_copy[3];
152  double flux_right[3], flux_left[3];
153
154  //Copy conserved quantities to protect from modification
155  for (i=0; i<3; i++) {
156    q_left_copy[i] = q_left[i];
157    q_right_copy[i] = q_right[i];
158  }
159
160  //Align x- and y-momentum with x-axis
161  _rotate(q_left_copy, n1, n2);
162  _rotate(q_right_copy, n1, n2);
163
164  z = (z_left+z_right)/2; //Take average of field values
165
166  //Compute speeds in x-direction
167  w_left = q_left_copy[0];              // h+z
168  h_left = w_left-z;
169  uh_left = q_left_copy[1];
170
171  if (h_left < epsilon) {
172    h_left = 0.0;  //Could have been negative
173    u_left = 0.0;
174  } else {
175    u_left = uh_left/h_left;
176  }
177
178  w_right = q_right_copy[0];
179  h_right = w_right-z;
180  uh_right = q_right_copy[1];
181
182  if (h_right < epsilon) {
183    h_right = 0.0; //Could have been negative
184    u_right = 0.0;
185  } else {
186    u_right = uh_right/h_right;
187  }
188
189  //Momentum in y-direction
190  vh_left  = q_left_copy[2];
191  vh_right = q_right_copy[2];
192
193
194  //Maximal and minimal wave speeds
195  soundspeed_left  = sqrt(g*h_left);
196  soundspeed_right = sqrt(g*h_right);
197
198  s_max = max(u_left+soundspeed_left, u_right+soundspeed_right);
199  if (s_max < 0.0) s_max = 0.0;
200
201  s_min = min(u_left-soundspeed_left, u_right-soundspeed_right);
202  if (s_min > 0.0) s_min = 0.0;
203
204  //Flux formulas
205  flux_left[0] = u_left*h_left;
206  flux_left[1] = u_left*uh_left + 0.5*g*h_left*h_left;
207  flux_left[2] = u_left*vh_left;
208
209  flux_right[0] = u_right*h_right;
210  flux_right[1] = u_right*uh_right + 0.5*g*h_right*h_right;
211  flux_right[2] = u_right*vh_right;
212
213
214  //Flux computation
215  denom = s_max-s_min;
216  if (denom == 0.0) {
217    for (i=0; i<3; i++) edgeflux[i] = 0.0;
218    *max_speed = 0.0;
219  } else {
220    for (i=0; i<3; i++) {
221      edgeflux[i] = s_max*flux_left[i] - s_min*flux_right[i];
222      edgeflux[i] += s_max*s_min*(q_right_copy[i]-q_left_copy[i]);
223      edgeflux[i] /= denom;
224    }
225
226    //Maximal wavespeed
227    *max_speed = max(fabs(s_max), fabs(s_min));
228
229    //Rotate back
230    _rotate(edgeflux, n1, -n2);
231  }
232  return 0;
233}
234
235void _manning_friction(double g, double eps, int N,
236                       double* w, double* z,
237                       double* uh, double* vh,
238                       double* eta, double* xmom, double* ymom) {
239
240  int k;
241  double S, h;
242
243  for (k=0; k<N; k++) {
244    if (eta[k] > eps) {
245      h = w[k]-z[k];
246      if (h >= eps) {
247        S = -g * eta[k]*eta[k] * sqrt((uh[k]*uh[k] + vh[k]*vh[k]));
248        S /= pow(h, 7.0/3);      //Expensive (on Ole's home computer)
249        //S /= exp(7.0/3.0*log(h));      //seems to save about 15% over manning_friction
250        //S /= h*h*(1 + h/3.0 - h*h/9.0); //FIXME: Could use a Taylor expansion
251
252
253        //Update momentum
254        xmom[k] += S*uh[k];
255        ymom[k] += S*vh[k];
256      }
257    }
258  }
259}
260
261
262/*
263void _manning_friction_explicit(double g, double eps, int N,
264                       double* w, double* z,
265                       double* uh, double* vh,
266                       double* eta, double* xmom, double* ymom) {
267
268  int k;
269  double S, h;
270
271  for (k=0; k<N; k++) {
272    if (eta[k] > eps) {
273      h = w[k]-z[k];
274      if (h >= eps) {
275        S = -g * eta[k]*eta[k] * sqrt((uh[k]*uh[k] + vh[k]*vh[k]));
276        S /= pow(h, 7.0/3);      //Expensive (on Ole's home computer)
277        //S /= exp(7.0/3.0*log(h));      //seems to save about 15% over manning_friction
278        //S /= h*h*(1 + h/3.0 - h*h/9.0); //FIXME: Could use a Taylor expansion
279
280
281        //Update momentum
282        xmom[k] += S*uh[k];
283        ymom[k] += S*vh[k];
284      }
285    }
286  }
287}
288*/
289
290int _balance_deep_and_shallow(int N,
291                              double* wc,
292                              double* zc,
293                              double* hc,
294                              double* wv,
295                              double* zv,
296                              double* hv,
297                              double* hvbar,
298                              double* xmomc,
299                              double* ymomc,
300                              double* xmomv,
301                              double* ymomv) {
302
303  int k, k3, i;
304  double dz, hmin, alpha;
305
306  //Compute linear combination between w-limited stages and
307  //h-limited stages close to the bed elevation.
308
309  for (k=0; k<N; k++) {
310    // Compute maximal variation in bed elevation
311    // This quantitiy is
312    //     dz = max_i abs(z_i - z_c)
313    // and it is independent of dimension
314    // In the 1d case zc = (z0+z1)/2
315    // In the 2d case zc = (z0+z1+z2)/3
316
317    k3 = 3*k;
318
319    //FIXME: Try with this one precomputed
320    dz = 0.0;
321    hmin = hv[k3];
322    for (i=0; i<3; i++) {
323      dz = max(dz, fabs(zv[k3+i]-zc[k]));
324      hmin = min(hmin, hv[k3+i]);
325    }
326
327
328    //Create alpha in [0,1], where alpha==0 means using the h-limited
329    //stage and alpha==1 means using the w-limited stage as
330    //computed by the gradient limiter (both 1st or 2nd order)
331    //
332    //If hmin > dz/2 then alpha = 1 and the bed will have no effect
333    //If hmin < 0 then alpha = 0 reverting to constant height above bed.
334
335
336    if (dz > 0.0)
337      //if (hmin<0.0)
338      //        alpha = 0.0;
339      //else
340      //  alpha = max( min( hc[k]/dz, 1.0), 0.0 );
341      alpha = max( min( 2.0*hmin/dz, 1.0), 0.0 );
342    else
343      alpha = 1.0;  //Flat bed
344
345    //alpha = 1.0;
346
347    //printf("dz = %.3f, alpha = %.8f\n", dz, alpha);
348
349    //  Let
350    //
351    //    wvi be the w-limited stage (wvi = zvi + hvi)
352    //    wvi- be the h-limited state (wvi- = zvi + hvi-)
353    //
354    //
355    //  where i=0,1,2 denotes the vertex ids
356    //
357    //  Weighted balance between w-limited and h-limited stage is
358    //
359    //    wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
360    //
361    //  It follows that the updated wvi is
362    //    wvi := zvi + (1-alpha)*hvi- + alpha*hvi
363    //
364    //   Momentum is balanced between constant and limited
365
366    if (alpha < 1) {
367      for (i=0; i<3; i++) {
368         wv[k3+i] = zv[k3+i] + (1-alpha)*hvbar[k3+i] + alpha*hv[k3+i];
369
370        //Update momentum as a linear combination of
371        //xmomc and ymomc (shallow) and momentum
372        //from extrapolator xmomv and ymomv (deep).
373        xmomv[k3+i] = (1-alpha)*xmomc[k] + alpha*xmomv[k3+i];
374        ymomv[k3+i] = (1-alpha)*ymomc[k] + alpha*ymomv[k3+i];
375      }
376    }
377  }
378  return 0;
379}
380
381
382
383int _protect(int N,
384             double minimum_allowed_height,
385             double maximum_allowed_speed,
386             double epsilon,
387             double* wc,
388             double* zc,
389             double* xmomc,
390             double* ymomc) {
391
392  int k;
393  double hc;
394  double u, v, reduced_speed;
395
396  //Protect against initesimal and negative heights
397  for (k=0; k<N; k++) {
398    hc = wc[k] - zc[k];
399
400    if (hc < minimum_allowed_height) {
401
402      //Old code: Set momentum to zero and ensure h is non negative
403      //xmomc[k] = 0.0;
404      //ymomc[k] = 0.0;
405      //if (hc <= 0.0) wc[k] = zc[k];
406
407
408      //New code: Adjust momentum to guarantee speeds are physical
409      //          ensure h is non negative
410      //FIXME (Ole): This is only implemented in this C extension and
411      //             has no Python equivalent
412      if (hc <= 0.0) {
413        wc[k] = zc[k];
414        xmomc[k] = 0.0;
415        ymomc[k] = 0.0;
416      } else {
417        //Reduce excessive speeds derived from division by small hc
418        u = xmomc[k]/hc;
419        if (fabs(u) > maximum_allowed_speed) {
420          reduced_speed = maximum_allowed_speed * u/fabs(u);
421          //printf("Speed (u) has been reduced from %.3f to %.3f\n",
422          //     u, reduced_speed);
423          xmomc[k] = reduced_speed * hc;
424        }
425
426        v = ymomc[k]/hc;
427        if (fabs(v) > maximum_allowed_speed) {
428          reduced_speed = maximum_allowed_speed * v/fabs(v);
429          //printf("Speed (v) has been reduced from %.3f to %.3f\n",
430          //     v, reduced_speed);
431          ymomc[k] = reduced_speed * hc;
432        }
433      }
434    }
435  }
436  return 0;
437}
438
439
440
441
442int _assign_wind_field_values(int N,
443                              double* xmom_update,
444                              double* ymom_update,
445                              double* s_vec,
446                              double* phi_vec,
447                              double cw) {
448
449  //Assign windfield values to momentum updates
450
451  int k;
452  double S, s, phi, u, v;
453
454  for (k=0; k<N; k++) {
455
456    s = s_vec[k];
457    phi = phi_vec[k];
458
459    //Convert to radians
460    phi = phi*pi/180;
461
462    //Compute velocity vector (u, v)
463    u = s*cos(phi);
464    v = s*sin(phi);
465
466    //Compute wind stress
467    S = cw * sqrt(u*u + v*v);
468    xmom_update[k] += S*u;
469    ymom_update[k] += S*v;
470  }
471  return 0;
472}
473
474
475
476///////////////////////////////////////////////////////////////////
477// Gateways to Python
478
479PyObject *gravity(PyObject *self, PyObject *args) {
480  //
481  //  gravity(g, h, v, x, xmom, ymom)
482  //
483
484
485  PyArrayObject *h, *v, *x, *xmom, *ymom;
486  int k, i, N, k3, k6;
487  double g, avg_h, zx, zy;
488  double x0, y0, x1, y1, x2, y2, z0, z1, z2;
489
490  if (!PyArg_ParseTuple(args, "dOOOOO",
491                        &g, &h, &v, &x,
492                        &xmom, &ymom))
493    return NULL;
494
495  N = h -> dimensions[0];
496  for (k=0; k<N; k++) {
497    k3 = 3*k;  // base index
498    k6 = 6*k;  // base index
499
500    avg_h = 0.0;
501    for (i=0; i<3; i++) {
502      avg_h += ((double *) h -> data)[k3+i];
503    }
504    avg_h /= 3;
505
506
507    //Compute bed slope
508    x0 = ((double*) x -> data)[k6 + 0];
509    y0 = ((double*) x -> data)[k6 + 1];
510    x1 = ((double*) x -> data)[k6 + 2];
511    y1 = ((double*) x -> data)[k6 + 3];
512    x2 = ((double*) x -> data)[k6 + 4];
513    y2 = ((double*) x -> data)[k6 + 5];
514
515
516    z0 = ((double*) v -> data)[k3 + 0];
517    z1 = ((double*) v -> data)[k3 + 1];
518    z2 = ((double*) v -> data)[k3 + 2];
519
520    _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy);
521
522    //Update momentum
523    ((double*) xmom -> data)[k] += -g*zx*avg_h;
524    ((double*) ymom -> data)[k] += -g*zy*avg_h;
525  }
526
527  return Py_BuildValue("");
528}
529
530
531PyObject *manning_friction(PyObject *self, PyObject *args) {
532  //
533  // manning_friction(g, eps, h, uh, vh, eta, xmom_update, ymom_update)
534  //
535
536
537  PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom;
538  int N;
539  double g, eps;
540
541  if (!PyArg_ParseTuple(args, "ddOOOOOOO",
542                        &g, &eps, &w, &z, &uh, &vh, &eta,
543                        &xmom, &ymom))
544    return NULL;
545
546  N = w -> dimensions[0];
547  _manning_friction(g, eps, N,
548                    (double*) w -> data,
549                    (double*) z -> data,
550                    (double*) uh -> data,
551                    (double*) vh -> data,
552                    (double*) eta -> data,
553                    (double*) xmom -> data,
554                    (double*) ymom -> data);
555
556  return Py_BuildValue("");
557}
558
559
560/*
561PyObject *manning_friction_explicit(PyObject *self, PyObject *args) {
562  //
563  // manning_friction_explicit(g, eps, h, uh, vh, eta, xmom_update, ymom_update)
564  //
565
566
567  PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom;
568  int N;
569  double g, eps;
570
571  if (!PyArg_ParseTuple(args, "ddOOOOOOO",
572                        &g, &eps, &w, &z, &uh, &vh, &eta,
573                        &xmom, &ymom))
574    return NULL;
575
576  N = w -> dimensions[0];
577  _manning_friction_explicit(g, eps, N,
578                    (double*) w -> data,
579                    (double*) z -> data,
580                    (double*) uh -> data,
581                    (double*) vh -> data,
582                    (double*) eta -> data,
583                    (double*) xmom -> data,
584                    (double*) ymom -> data);
585
586  return Py_BuildValue("");
587}
588*/
589
590PyObject *extrapolate_second_order_sw(PyObject *self, PyObject *args) {
591  /*Compute the vertex values based on a linear reconstruction on each triangle
592    These values are calculated as follows:
593    1) For each triangle not adjacent to a boundary, we consider the auxiliary triangle
594    formed by the centroids of its three neighbours.
595    2) For each conserved quantity, we integrate around the auxiliary triangle's boundary the product
596    of the quantity and the outward normal vector. Dividing by the triangle area gives (a,b), the average
597    of the vector (q_x,q_y) on the auxiliary triangle. We suppose that the linear reconstruction on the
598    original triangle has gradient (a,b).
599    3) Provisional vertex junmps dqv[0,1,2] are computed and these are then limited by calling the functions
600    find_qmin_and_qmax and limit_gradient
601
602    Python call:
603    extrapolate_second_order_sw(domain.surrogate_neighbours,
604                                domain.number_of_boundaries
605                                domain.centroid_coordinates,
606                                Stage.centroid_values
607                                Xmom.centroid_values
608                                Ymom.centroid_values
609                                domain.vertex_coordinates,
610                                Stage.vertex_values,
611                                Xmom.vertex_values,
612                                Ymom.vertex_values)
613
614    Post conditions:
615            The vertices of each triangle have values from a limited linear reconstruction
616            based on centroid values
617
618  */
619  PyArrayObject *surrogate_neighbours,
620    *number_of_boundaries,
621    *centroid_coordinates,
622    *stage_centroid_values,
623    *xmom_centroid_values,
624    *ymom_centroid_values,
625    *vertex_coordinates,
626    *stage_vertex_values,
627    *xmom_vertex_values,
628    *ymom_vertex_values;
629  PyObject *domain, *Tmp;
630  //Local variables
631  double a, b;//gradient vector, not stored but used to calculate vertex values from centroids
632  int number_of_elements,k,k0,k1,k2,k3,k6,coord_index,i;
633  double x,y,x0,y0,x1,y1,x2,y2,xv0,yv0,xv1,yv1,xv2,yv2;//vertices of the auxiliary triangle
634  double dx1,dx2,dy1,dy2,dxv0,dxv1,dxv2,dyv0,dyv1,dyv2,dq0,dq1,dq2,area2;
635  double dqv[3], qmin, qmax, beta_w;//provisional jumps from centroids to v'tices and safety factor re limiting
636  //by which these jumps are limited
637  // Convert Python arguments to C
638  if (!PyArg_ParseTuple(args, "OOOOOOOOOOO",
639                        &domain,
640                        &surrogate_neighbours,
641                        &number_of_boundaries,
642                        &centroid_coordinates,
643                        &stage_centroid_values,
644                        &xmom_centroid_values,
645                        &ymom_centroid_values,
646                        &vertex_coordinates,
647                        &stage_vertex_values,
648                        &xmom_vertex_values,
649                        &ymom_vertex_values)) {
650    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
651    return NULL;
652  }
653
654  //get the safety factor beta_w, set in the config.py file. This is used in the limiting process
655  Tmp = PyObject_GetAttrString(domain, "beta_w");
656  if (!Tmp)
657    return NULL;
658  beta_w = PyFloat_AsDouble(Tmp);
659  Py_DECREF(Tmp);
660  number_of_elements = stage_centroid_values -> dimensions[0];
661  for (k=0; k<number_of_elements; k++) {
662    k3=k*3;
663    k6=k*6;
664
665    if (((long *) number_of_boundaries->data)[k]==3){/*no neighbours, set gradient on the triangle to zero*/
666      ((double *) stage_vertex_values->data)[k3]=((double *)stage_centroid_values->data)[k];
667      ((double *) stage_vertex_values->data)[k3+1]=((double *)stage_centroid_values->data)[k];
668      ((double *) stage_vertex_values->data)[k3+2]=((double *)stage_centroid_values->data)[k];
669      ((double *) xmom_vertex_values->data)[k3]=((double *)xmom_centroid_values->data)[k];
670      ((double *) xmom_vertex_values->data)[k3+1]=((double *)xmom_centroid_values->data)[k];
671      ((double *) xmom_vertex_values->data)[k3+2]=((double *)xmom_centroid_values->data)[k];
672      ((double *) ymom_vertex_values->data)[k3]=((double *)ymom_centroid_values->data)[k];
673      ((double *) ymom_vertex_values->data)[k3+1]=((double *)ymom_centroid_values->data)[k];
674      ((double *) ymom_vertex_values->data)[k3+2]=((double *)ymom_centroid_values->data)[k];
675      continue;
676    }
677    else {//we will need centroid coordinates and vertex coordinates of the triangle
678      //get the vertex coordinates of the FV triangle
679      xv0=((double *)vertex_coordinates->data)[k6]; yv0=((double *)vertex_coordinates->data)[k6+1];
680      xv1=((double *)vertex_coordinates->data)[k6+2]; yv1=((double *)vertex_coordinates->data)[k6+3];
681      xv2=((double *)vertex_coordinates->data)[k6+4]; yv2=((double *)vertex_coordinates->data)[k6+5];
682      //get the centroid coordinates of the FV triangle
683      coord_index=2*k;
684      x=((double *)centroid_coordinates->data)[coord_index];
685      y=((double *)centroid_coordinates->data)[coord_index+1];
686      //store x- and y- differentials for the vertices of the FV triangle relative to the centroid
687      dxv0=xv0-x; dxv1=xv1-x; dxv2=xv2-x;
688      dyv0=yv0-y; dyv1=yv1-y; dyv2=yv2-y;
689    }
690    if (((long *)number_of_boundaries->data)[k]<=1){
691      //if no boundaries, auxiliary triangle is formed from the centroids of the three neighbours
692      //if one boundary, auxiliary triangle is formed from this centroid and its two neighbours
693      k0=((long *)surrogate_neighbours->data)[k3];
694      k1=((long *)surrogate_neighbours->data)[k3+1];
695      k2=((long *)surrogate_neighbours->data)[k3+2];
696      //get the auxiliary triangle's vertex coordinates (really the centroids of neighbouring triangles)
697      coord_index=2*k0;
698      x0=((double *)centroid_coordinates->data)[coord_index];
699      y0=((double *)centroid_coordinates->data)[coord_index+1];
700      coord_index=2*k1;
701      x1=((double *)centroid_coordinates->data)[coord_index];
702      y1=((double *)centroid_coordinates->data)[coord_index+1];
703      coord_index=2*k2;
704      x2=((double *)centroid_coordinates->data)[coord_index];
705      y2=((double *)centroid_coordinates->data)[coord_index+1];
706      //store x- and y- differentials for the vertices of the auxiliary triangle
707      dx1=x1-x0; dx2=x2-x0;
708      dy1=y1-y0; dy2=y2-y0;
709      //calculate 2*area of the auxiliary triangle
710      area2 = dy2*dx1 - dy1*dx2;//the triangle is guaranteed to be counter-clockwise
711      //If the mesh is 'weird' near the boundary, the trianlge might be flat or clockwise:
712      if (area2<=0)
713        return NULL;
714
715      //### stage ###
716      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
717      dq0=((double *)stage_centroid_values->data)[k0]-((double *)stage_centroid_values->data)[k];
718      //calculate differentials between the vertices of the auxiliary triangle
719      dq1=((double *)stage_centroid_values->data)[k1]-((double *)stage_centroid_values->data)[k0];
720      dq2=((double *)stage_centroid_values->data)[k2]-((double *)stage_centroid_values->data)[k0];
721      //calculate the gradient of stage on the auxiliary triangle
722      a = dy2*dq1 - dy1*dq2;
723      a /= area2;
724      b = dx1*dq2 - dx2*dq1;
725      b /= area2;
726      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
727      dqv[0]=a*dxv0+b*dyv0;
728      dqv[1]=a*dxv1+b*dyv1;
729      dqv[2]=a*dxv2+b*dyv2;
730      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
731      //and compute jumps from the centroid to the min and max
732      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
733      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
734      for (i=0;i<3;i++)
735        ((double *)stage_vertex_values->data)[k3+i]=((double *)stage_centroid_values->data)[k]+dqv[i];
736
737      //### xmom ###
738      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
739      dq0=((double *)xmom_centroid_values->data)[k0]-((double *)xmom_centroid_values->data)[k];
740      //calculate differentials between the vertices of the auxiliary triangle
741      dq1=((double *)xmom_centroid_values->data)[k1]-((double *)xmom_centroid_values->data)[k0];
742      dq2=((double *)xmom_centroid_values->data)[k2]-((double *)xmom_centroid_values->data)[k0];
743      //calculate the gradient of xmom on the auxiliary triangle
744      a = dy2*dq1 - dy1*dq2;
745      a /= area2;
746      b = dx1*dq2 - dx2*dq1;
747      b /= area2;
748      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
749      dqv[0]=a*dxv0+b*dyv0;
750      dqv[1]=a*dxv1+b*dyv1;
751      dqv[2]=a*dxv2+b*dyv2;
752      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
753      //and compute jumps from the centroid to the min and max
754      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
755      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
756      for (i=0;i<3;i++)
757        ((double *)xmom_vertex_values->data)[k3+i]=((double *)xmom_centroid_values->data)[k]+dqv[i];
758
759      //### ymom ###
760      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
761      dq0=((double *)ymom_centroid_values->data)[k0]-((double *)ymom_centroid_values->data)[k];
762      //calculate differentials between the vertices of the auxiliary triangle
763      dq1=((double *)ymom_centroid_values->data)[k1]-((double *)ymom_centroid_values->data)[k0];
764      dq2=((double *)ymom_centroid_values->data)[k2]-((double *)ymom_centroid_values->data)[k0];
765      //calculate the gradient of xmom on the auxiliary triangle
766      a = dy2*dq1 - dy1*dq2;
767      a /= area2;
768      b = dx1*dq2 - dx2*dq1;
769      b /= area2;
770      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
771      dqv[0]=a*dxv0+b*dyv0;
772      dqv[1]=a*dxv1+b*dyv1;
773      dqv[2]=a*dxv2+b*dyv2;
774      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
775      //and compute jumps from the centroid to the min and max
776      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
777      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
778      for (i=0;i<3;i++)
779        ((double *)ymom_vertex_values->data)[k3+i]=((double *)ymom_centroid_values->data)[k]+dqv[i];
780    }//if (number_of_boundaries[k]<=1)
781    else{//number_of_boundaries==2
782      //one internal neighbour and gradient is in direction of the neighbour's centroid
783      //find the only internal neighbour
784      for (k2=k3;k2<k3+3;k2++){//k2 just indexes the edges of triangle k
785        if (((long *)surrogate_neighbours->data)[k2]!=k)//find internal neighbour of triabngle k
786          break;
787      }
788      if ((k2==k3+3))//if we didn't find an internal neighbour
789        return NULL;//error
790      k1=((long *)surrogate_neighbours->data)[k2];
791      //the coordinates of the triangle are already (x,y). Get centroid of the neighbour (x1,y1)
792      coord_index=2*k1;
793      x1=((double *)centroid_coordinates->data)[coord_index];
794      y1=((double *)centroid_coordinates->data)[coord_index+1];
795      //compute x- and y- distances between the centroid of the FV triangle and that of its neighbour
796      dx1=x1-x; dy1=y1-y;
797      //set area2 as the square of the distance
798      area2=dx1*dx1+dy1*dy1;
799      //set dx2=(x1-x0)/((x1-x0)^2+(y1-y0)^2) and dy2=(y1-y0)/((x1-x0)^2+(y1-y0)^2) which
800      //respectively correspond to the x- and y- gradients of the conserved quantities
801      dx2=1.0/area2;
802      dy2=dx2*dy1;
803      dx2*=dx1;
804
805      //## stage ###
806      //compute differentials
807      dq1=((double *)stage_centroid_values->data)[k1]-((double *)stage_centroid_values->data)[k];
808      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
809      a=dq1*dx2;
810      b=dq1*dy2;
811      //calculate provisional vertex jumps, to be limited
812      dqv[0]=a*dxv0+b*dyv0;
813      dqv[1]=a*dxv1+b*dyv1;
814      dqv[2]=a*dxv2+b*dyv2;
815      //now limit the jumps
816      if (dq1>=0.0){
817        qmin=0.0;
818        qmax=dq1;
819      }
820      else{
821        qmin=dq1;
822        qmax=0.0;
823      }
824      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
825      for (i=0;i<3;i++)
826        ((double *)stage_vertex_values->data)[k3+i]=((double *)stage_centroid_values->data)[k]+dqv[i];
827
828      //## xmom ###
829      //compute differentials
830      dq1=((double *)xmom_centroid_values->data)[k1]-((double *)xmom_centroid_values->data)[k];
831      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
832      a=dq1*dx2;
833      b=dq1*dy2;
834      //calculate provisional vertex jumps, to be limited
835      dqv[0]=a*dxv0+b*dyv0;
836      dqv[1]=a*dxv1+b*dyv1;
837      dqv[2]=a*dxv2+b*dyv2;
838      //now limit the jumps
839      if (dq1>=0.0){
840        qmin=0.0;
841        qmax=dq1;
842      }
843      else{
844        qmin=dq1;
845        qmax=0.0;
846      }
847      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
848      for (i=0;i<3;i++)
849        ((double *)xmom_vertex_values->data)[k3+i]=((double *)xmom_centroid_values->data)[k]+dqv[i];
850
851      //## ymom ###
852      //compute differentials
853      dq1=((double *)ymom_centroid_values->data)[k1]-((double *)ymom_centroid_values->data)[k];
854      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
855      a=dq1*dx2;
856      b=dq1*dy2;
857      //calculate provisional vertex jumps, to be limited
858      dqv[0]=a*dxv0+b*dyv0;
859      dqv[1]=a*dxv1+b*dyv1;
860      dqv[2]=a*dxv2+b*dyv2;
861      //now limit the jumps
862      if (dq1>=0.0){
863        qmin=0.0;
864        qmax=dq1;
865      }
866      else{
867        qmin=dq1;
868        qmax=0.0;
869      }
870      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
871      for (i=0;i<3;i++)
872        ((double *)ymom_vertex_values->data)[k3+i]=((double *)ymom_centroid_values->data)[k]+dqv[i];
873    }//else [number_of_boudaries==2]
874  }//for k=0 to number_of_elements-1
875  return Py_BuildValue("");
876}//extrapolate_second-order_sw
877
878PyObject *rotate(PyObject *self, PyObject *args, PyObject *kwargs) {
879  //
880  // r = rotate(q, normal, direction=1)
881  //
882  // Where q is assumed to be a Float numeric array of length 3 and
883  // normal a Float numeric array of length 2.
884
885
886  PyObject *Q, *Normal;
887  PyArrayObject *q, *r, *normal;
888
889  static char *argnames[] = {"q", "normal", "direction", NULL};
890  int dimensions[1], i, direction=1;
891  double n1, n2;
892
893  // Convert Python arguments to C
894  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames,
895                                   &Q, &Normal, &direction))
896    return NULL;
897
898  //Input checks (convert sequences into numeric arrays)
899  q = (PyArrayObject *)
900    PyArray_ContiguousFromObject(Q, PyArray_DOUBLE, 0, 0);
901  normal = (PyArrayObject *)
902    PyArray_ContiguousFromObject(Normal, PyArray_DOUBLE, 0, 0);
903
904
905  if (normal -> dimensions[0] != 2) {
906    PyErr_SetString(PyExc_RuntimeError, "Normal vector must have 2 components");
907    return NULL;
908  }
909
910  //Allocate space for return vector r (don't DECREF)
911  dimensions[0] = 3;
912  r = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
913
914  //Copy
915  for (i=0; i<3; i++) {
916    ((double *) (r -> data))[i] = ((double *) (q -> data))[i];
917  }
918
919  //Get normal and direction
920  n1 = ((double *) normal -> data)[0];
921  n2 = ((double *) normal -> data)[1];
922  if (direction == -1) n2 = -n2;
923
924  //Rotate
925  _rotate((double *) r -> data, n1, n2);
926
927  //Release numeric arrays
928  Py_DECREF(q);
929  Py_DECREF(normal);
930
931  //return result using PyArray to avoid memory leak
932  return PyArray_Return(r);
933}
934
935PyObject *compute_fluxes(PyObject *self, PyObject *args) {
936  /*Compute all fluxes and the timestep suitable for all volumes
937    in domain.
938
939    Compute total flux for each conserved quantity using "flux_function"
940
941    Fluxes across each edge are scaled by edgelengths and summed up
942    Resulting flux is then scaled by area and stored in
943    explicit_update for each of the three conserved quantities
944    stage, xmomentum and ymomentum
945
946    The maximal allowable speed computed by the flux_function for each volume
947    is converted to a timestep that must not be exceeded. The minimum of
948    those is computed as the next overall timestep.
949
950    Python call:
951    domain.timestep = compute_fluxes(timestep,
952                                     domain.epsilon,
953                                     domain.g,
954                                     domain.neighbours,
955                                     domain.neighbour_edges,
956                                     domain.normals,
957                                     domain.edgelengths,
958                                     domain.radii,
959                                     domain.areas,
960                                     Stage.edge_values,
961                                     Xmom.edge_values,
962                                     Ymom.edge_values,
963                                     Bed.edge_values,
964                                     Stage.boundary_values,
965                                     Xmom.boundary_values,
966                                     Ymom.boundary_values,
967                                     Stage.explicit_update,
968                                     Xmom.explicit_update,
969                                     Ymom.explicit_update,
970                                     already_computed_flux)
971
972
973    Post conditions:
974      domain.explicit_update is reset to computed flux values
975      domain.timestep is set to the largest step satisfying all volumes.
976
977
978  */
979
980
981  PyArrayObject *neighbours, *neighbour_edges,
982    *normals, *edgelengths, *radii, *areas,
983    *stage_edge_values,
984    *xmom_edge_values,
985    *ymom_edge_values,
986    *bed_edge_values,
987    *stage_boundary_values,
988    *xmom_boundary_values,
989    *ymom_boundary_values,
990    *stage_explicit_update,
991    *xmom_explicit_update,
992    *ymom_explicit_update,
993    *already_computed_flux;//tracks whether the flux across an edge has already been computed
994
995
996  //Local variables
997  double timestep, max_speed, epsilon, g;
998  double normal[2], ql[3], qr[3], zl, zr;
999  double edgeflux[3]; //Work arrays for summing up fluxes
1000
1001  int number_of_elements, k, i, m, n;
1002  int ki, nm=0, ki2; //Index shorthands
1003  static long call=1;
1004
1005
1006  // Convert Python arguments to C
1007  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOOOOOOO",
1008                        &timestep,
1009                        &epsilon,
1010                        &g,
1011                        &neighbours,
1012                        &neighbour_edges,
1013                        &normals,
1014                        &edgelengths, &radii, &areas,
1015                        &stage_edge_values,
1016                        &xmom_edge_values,
1017                        &ymom_edge_values,
1018                        &bed_edge_values,
1019                        &stage_boundary_values,
1020                        &xmom_boundary_values,
1021                        &ymom_boundary_values,
1022                        &stage_explicit_update,
1023                        &xmom_explicit_update,
1024                        &ymom_explicit_update,
1025                        &already_computed_flux)) {
1026    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
1027    return NULL;
1028  }
1029  number_of_elements = stage_edge_values -> dimensions[0];
1030  call++;//a static local variable to which already_computed_flux is compared
1031  //set explicit_update to zero for all conserved_quantities.
1032  //This assumes compute_fluxes called before forcing terms
1033  for (k=0; k<number_of_elements; k++) {
1034    ((double *) stage_explicit_update -> data)[k]=0.0;
1035    ((double *) xmom_explicit_update -> data)[k]=0.0;
1036    ((double *) ymom_explicit_update -> data)[k]=0.0;
1037  }
1038  //Loop through neighbours and compute edge flux for each
1039  for (k=0; k<number_of_elements; k++) {
1040    for (i=0; i<3; i++) {
1041      ki = k*3+i;
1042      if (((long *) already_computed_flux->data)[ki]==call)//we've already computed the flux across this edge
1043        continue;
1044      ql[0] = ((double *) stage_edge_values -> data)[ki];
1045      ql[1] = ((double *) xmom_edge_values -> data)[ki];
1046      ql[2] = ((double *) ymom_edge_values -> data)[ki];
1047      zl =    ((double *) bed_edge_values -> data)[ki];
1048
1049      //Quantities at neighbour on nearest face
1050      n = ((long *) neighbours -> data)[ki];
1051      if (n < 0) {
1052        m = -n-1; //Convert negative flag to index
1053        qr[0] = ((double *) stage_boundary_values -> data)[m];
1054        qr[1] = ((double *) xmom_boundary_values -> data)[m];
1055        qr[2] = ((double *) ymom_boundary_values -> data)[m];
1056        zr = zl; //Extend bed elevation to boundary
1057      } else {
1058        m = ((long *) neighbour_edges -> data)[ki];
1059        nm = n*3+m;
1060        qr[0] = ((double *) stage_edge_values -> data)[nm];
1061        qr[1] = ((double *) xmom_edge_values -> data)[nm];
1062        qr[2] = ((double *) ymom_edge_values -> data)[nm];
1063        zr =    ((double *) bed_edge_values -> data)[nm];
1064      }
1065      // Outward pointing normal vector
1066      // normal = domain.normals[k, 2*i:2*i+2]
1067      ki2 = 2*ki; //k*6 + i*2
1068      normal[0] = ((double *) normals -> data)[ki2];
1069      normal[1] = ((double *) normals -> data)[ki2+1];
1070      //Edge flux computation
1071      flux_function(ql, qr, zl, zr,
1072                    normal[0], normal[1],
1073                    epsilon, g,
1074                    edgeflux, &max_speed);
1075      //update triangle k
1076      ((long *) already_computed_flux->data)[ki]=call;
1077      ((double *) stage_explicit_update -> data)[k] -= edgeflux[0]*((double *) edgelengths -> data)[ki];
1078      ((double *) xmom_explicit_update -> data)[k] -= edgeflux[1]*((double *) edgelengths -> data)[ki];
1079      ((double *) ymom_explicit_update -> data)[k] -= edgeflux[2]*((double *) edgelengths -> data)[ki];
1080      //update the neighbour n
1081      if (n>=0){
1082        ((long *) already_computed_flux->data)[nm]=call;
1083        ((double *) stage_explicit_update -> data)[n] += edgeflux[0]*((double *) edgelengths -> data)[nm];
1084        ((double *) xmom_explicit_update -> data)[n] += edgeflux[1]*((double *) edgelengths -> data)[nm];
1085        ((double *) ymom_explicit_update -> data)[n] += edgeflux[2]*((double *) edgelengths -> data)[nm];
1086      }
1087      ///for (j=0; j<3; j++) {
1088        ///flux[j] -= edgeflux[j]*((double *) edgelengths -> data)[ki];
1089        ///}
1090        //Update timestep
1091        //timestep = min(timestep, domain.radii[k]/max_speed)
1092        //FIXME: SR Add parameter for CFL condition
1093        if (max_speed > epsilon) {
1094          timestep = min(timestep, ((double *) radii -> data)[k]/max_speed);
1095          //maxspeed in flux_function is calculated as max(|u+a|,|u-a|)
1096          if (n>=0)
1097            timestep = min(timestep, ((double *) radii -> data)[n]/max_speed);
1098        }
1099    } // end for i
1100    //Normalise by area and store for when all conserved
1101    //quantities get updated
1102    ((double *) stage_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
1103    ((double *) xmom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
1104    ((double *) ymom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
1105  } //end for k
1106  return Py_BuildValue("d", timestep);
1107}
1108
1109PyObject *protect(PyObject *self, PyObject *args) {
1110  //
1111  //    protect(minimum_allowed_height, maximum_allowed_speed, wc, zc, xmomc, ymomc)
1112
1113
1114  PyArrayObject
1115  *wc,            //Stage at centroids
1116  *zc,            //Elevation at centroids
1117  *xmomc,         //Momentums at centroids
1118  *ymomc;
1119
1120
1121  int N;
1122  double minimum_allowed_height, maximum_allowed_speed, epsilon;
1123
1124  // Convert Python arguments to C
1125  if (!PyArg_ParseTuple(args, "dddOOOO",
1126                        &minimum_allowed_height,
1127                        &maximum_allowed_speed,
1128                        &epsilon,
1129                        &wc, &zc, &xmomc, &ymomc))
1130    return NULL;
1131
1132  N = wc -> dimensions[0];
1133
1134  _protect(N,
1135           minimum_allowed_height,
1136           maximum_allowed_speed,
1137           epsilon,
1138           (double*) wc -> data,
1139           (double*) zc -> data,
1140           (double*) xmomc -> data,
1141           (double*) ymomc -> data);
1142
1143  return Py_BuildValue("");
1144}
1145
1146
1147
1148PyObject *balance_deep_and_shallow(PyObject *self, PyObject *args) {
1149  //
1150  //    balance_deep_and_shallow(wc, zc, hc, wv, zv, hv,
1151  //                             xmomc, ymomc, xmomv, ymomv)
1152
1153
1154  PyArrayObject
1155    *wc,            //Stage at centroids
1156    *zc,            //Elevation at centroids
1157    *hc,            //Height at centroids
1158    *wv,            //Stage at vertices
1159    *zv,            //Elevation at vertices
1160    *hv,            //Depths at vertices
1161    *hvbar,         //h-Limited depths at vertices
1162    *xmomc,         //Momentums at centroids and vertices
1163    *ymomc,
1164    *xmomv,
1165    *ymomv;
1166
1167  int N; //, err;
1168
1169  // Convert Python arguments to C
1170  if (!PyArg_ParseTuple(args, "OOOOOOOOOOO",
1171                        &wc, &zc, &hc,
1172                        &wv, &zv, &hv, &hvbar,
1173                        &xmomc, &ymomc, &xmomv, &ymomv))
1174    return NULL;
1175
1176  N = wc -> dimensions[0];
1177
1178  _balance_deep_and_shallow(N,
1179                            (double*) wc -> data,
1180                            (double*) zc -> data,
1181                            (double*) hc -> data,
1182                            (double*) wv -> data,
1183                            (double*) zv -> data,
1184                            (double*) hv -> data,
1185                            (double*) hvbar -> data,
1186                            (double*) xmomc -> data,
1187                            (double*) ymomc -> data,
1188                            (double*) xmomv -> data,
1189                            (double*) ymomv -> data);
1190
1191
1192  return Py_BuildValue("");
1193}
1194
1195
1196
1197PyObject *h_limiter(PyObject *self, PyObject *args) {
1198
1199  PyObject *domain, *Tmp;
1200  PyArrayObject
1201    *hv, *hc, //Depth at vertices and centroids
1202    *hvbar,   //Limited depth at vertices (return values)
1203    *neighbours;
1204
1205  int k, i, n, N, k3;
1206  int dimensions[2];
1207  double beta_h; //Safety factor (see config.py)
1208  double *hmin, *hmax, hn;
1209
1210  // Convert Python arguments to C
1211  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv))
1212    return NULL;
1213
1214  neighbours = get_consecutive_array(domain, "neighbours");
1215
1216  //Get safety factor beta_h
1217  Tmp = PyObject_GetAttrString(domain, "beta_h");
1218  if (!Tmp)
1219    return NULL;
1220
1221  beta_h = PyFloat_AsDouble(Tmp);
1222
1223  Py_DECREF(Tmp);
1224
1225  N = hc -> dimensions[0];
1226
1227  //Create hvbar
1228  dimensions[0] = N;
1229  dimensions[1] = 3;
1230  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
1231
1232
1233  //Find min and max of this and neighbour's centroid values
1234  hmin = malloc(N * sizeof(double));
1235  hmax = malloc(N * sizeof(double));
1236  for (k=0; k<N; k++) {
1237    k3=k*3;
1238
1239    hmin[k] = ((double*) hc -> data)[k];
1240    hmax[k] = hmin[k];
1241
1242    for (i=0; i<3; i++) {
1243      n = ((long*) neighbours -> data)[k3+i];
1244
1245      //Initialise hvbar with values from hv
1246      ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i];
1247
1248      if (n >= 0) {
1249        hn = ((double*) hc -> data)[n]; //Neighbour's centroid value
1250
1251        hmin[k] = min(hmin[k], hn);
1252        hmax[k] = max(hmax[k], hn);
1253      }
1254    }
1255  }
1256
1257  // Call underlying standard routine
1258  _limit(N, beta_h, (double*) hc -> data, (double*) hvbar -> data, hmin, hmax);
1259
1260  // // //Py_DECREF(domain); //FIXME: NEcessary?
1261  free(hmin);
1262  free(hmax);
1263
1264  //return result using PyArray to avoid memory leak
1265  return PyArray_Return(hvbar);
1266  //return Py_BuildValue("");
1267}
1268
1269PyObject *h_limiter_sw(PyObject *self, PyObject *args) {
1270  //a faster version of h_limiter above
1271  PyObject *domain, *Tmp;
1272  PyArrayObject
1273    *hv, *hc, //Depth at vertices and centroids
1274    *hvbar,   //Limited depth at vertices (return values)
1275    *neighbours;
1276
1277  int k, i, N, k3,k0,k1,k2;
1278  int dimensions[2];
1279  double beta_h; //Safety factor (see config.py)
1280  double hmin, hmax, dh[3];
1281  // Convert Python arguments to C
1282  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv))
1283    return NULL;
1284  neighbours = get_consecutive_array(domain, "neighbours");
1285
1286  //Get safety factor beta_h
1287  Tmp = PyObject_GetAttrString(domain, "beta_h");
1288  if (!Tmp)
1289    return NULL;
1290  beta_h = PyFloat_AsDouble(Tmp);
1291
1292  Py_DECREF(Tmp);
1293
1294  N = hc -> dimensions[0];
1295
1296  //Create hvbar
1297  dimensions[0] = N;
1298  dimensions[1] = 3;
1299  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
1300  for (k=0;k<N;k++){
1301    k3=k*3;
1302    //get the ids of the neighbours
1303    k0 = ((long*) neighbours -> data)[k3];
1304    k1 = ((long*) neighbours -> data)[k3+1];
1305    k2 = ((long*) neighbours -> data)[k3+2];
1306    //set hvbar provisionally
1307    for (i=0;i<3;i++){
1308      ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i];
1309      dh[i]=((double*) hvbar -> data)[k3+i]-((double*) hc -> data)[k];
1310    }
1311    hmin=((double*) hc -> data)[k];
1312    hmax=hmin;
1313    if (k0>=0){
1314      hmin=min(hmin,((double*) hc -> data)[k0]);
1315      hmax=max(hmax,((double*) hc -> data)[k0]);
1316    }
1317    if (k1>=0){
1318      hmin=min(hmin,((double*) hc -> data)[k1]);
1319      hmax=max(hmax,((double*) hc -> data)[k1]);
1320    }
1321    if (k2>=0){
1322      hmin=min(hmin,((double*) hc -> data)[k2]);
1323      hmax=max(hmax,((double*) hc -> data)[k2]);
1324    }
1325    hmin-=((double*) hc -> data)[k];
1326    hmax-=((double*) hc -> data)[k];
1327    limit_gradient(dh,hmin,hmax,beta_h);
1328    for (i=0;i<3;i++)
1329      ((double*) hvbar -> data)[k3+i] = ((double*) hc -> data)[k]+dh[i];
1330  }
1331  return PyArray_Return(hvbar);
1332}
1333
1334PyObject *assign_windfield_values(PyObject *self, PyObject *args) {
1335  //
1336  //      assign_windfield_values(xmom_update, ymom_update,
1337  //                              s_vec, phi_vec, self.const)
1338
1339
1340
1341  PyArrayObject   //(one element per triangle)
1342  *s_vec,         //Speeds
1343  *phi_vec,       //Bearings
1344  *xmom_update,   //Momentum updates
1345  *ymom_update;
1346
1347
1348  int N;
1349  double cw;
1350
1351  // Convert Python arguments to C
1352  if (!PyArg_ParseTuple(args, "OOOOd",
1353                        &xmom_update,
1354                        &ymom_update,
1355                        &s_vec, &phi_vec,
1356                        &cw))
1357    return NULL;
1358
1359  N = xmom_update -> dimensions[0];
1360
1361  _assign_wind_field_values(N,
1362           (double*) xmom_update -> data,
1363           (double*) ymom_update -> data,
1364           (double*) s_vec -> data,
1365           (double*) phi_vec -> data,
1366           cw);
1367
1368  return Py_BuildValue("");
1369}
1370
1371
1372
1373
1374//////////////////////////////////////////
1375// Method table for python module
1376static struct PyMethodDef MethodTable[] = {
1377  /* The cast of the function is necessary since PyCFunction values
1378   * only take two PyObject* parameters, and rotate() takes
1379   * three.
1380   */
1381
1382  {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
1383  {"extrapolate_second_order_sw", extrapolate_second_order_sw, METH_VARARGS, "Print out"},
1384  {"compute_fluxes", compute_fluxes, METH_VARARGS, "Print out"},
1385  {"gravity", gravity, METH_VARARGS, "Print out"},
1386  {"manning_friction", manning_friction, METH_VARARGS, "Print out"},
1387  {"balance_deep_and_shallow", balance_deep_and_shallow,
1388   METH_VARARGS, "Print out"},
1389  {"h_limiter", h_limiter,
1390   METH_VARARGS, "Print out"},
1391  {"h_limiter_sw", h_limiter_sw,
1392   METH_VARARGS, "Print out"},
1393  {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"},
1394  {"assign_windfield_values", assign_windfield_values,
1395   METH_VARARGS | METH_KEYWORDS, "Print out"},
1396  //{"distribute_to_vertices_and_edges",
1397  // distribute_to_vertices_and_edges, METH_VARARGS},
1398  //{"update_conserved_quantities",
1399  // update_conserved_quantities, METH_VARARGS},
1400  //{"set_initialcondition",
1401  // set_initialcondition, METH_VARARGS},
1402  {NULL, NULL}
1403};
1404
1405// Module initialisation
1406void initshallow_water_ext(void){
1407  Py_InitModule("shallow_water_ext", MethodTable);
1408
1409  import_array();     //Necessary for handling of NumPY structures
1410}
Note: See TracBrowser for help on using the repository browser.