source: anuga_core/source/anuga/shallow_water/shallow_water_ext.c @ 3678

Last change on this file since 3678 was 3678, checked in by steve, 18 years ago

Added more limiting to cells near dry cells, use beta_*_dry

File size: 46.7 KB
Line 
1// Python - C extension module for shallow_water.py
2//
3// To compile (Python2.3):
4//  gcc -c domain_ext.c -I/usr/include/python2.3 -o domain_ext.o -Wall -O
5//  gcc -shared domain_ext.o  -o domain_ext.so
6//
7// or use python compile.py
8//
9// See the module shallow_water.py
10//
11//
12// Ole Nielsen, GA 2004
13
14
15#include "Python.h"
16#include "Numeric/arrayobject.h"
17#include "math.h"
18#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
346    //printf("dz = %.3f, alpha = %.8f\n", dz, alpha);
347
348    //  Let
349    //
350    //    wvi be the w-limited stage (wvi = zvi + hvi)
351    //    wvi- be the h-limited state (wvi- = zvi + hvi-)
352    //
353    //
354    //  where i=0,1,2 denotes the vertex ids
355    //
356    //  Weighted balance between w-limited and h-limited stage is
357    //
358    //    wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
359    //
360    //  It follows that the updated wvi is
361    //    wvi := zvi + (1-alpha)*hvi- + alpha*hvi
362    //
363    //   Momentum is balanced between constant and limited
364
365    if (alpha < 1) {
366      for (i=0; i<3; i++) {
367         wv[k3+i] = zv[k3+i] + (1-alpha)*hvbar[k3+i] + alpha*hv[k3+i];
368
369        //Update momentum as a linear combination of
370        //xmomc and ymomc (shallow) and momentum
371        //from extrapolator xmomv and ymomv (deep).
372        xmomv[k3+i] = (1-alpha)*xmomc[k] + alpha*xmomv[k3+i];
373        ymomv[k3+i] = (1-alpha)*ymomc[k] + alpha*ymomv[k3+i];
374      }
375    }
376  }
377  return 0;
378}
379
380
381
382int _protect(int N,
383             double minimum_allowed_height,
384             double maximum_allowed_speed,
385             double epsilon,
386             double* wc,
387             double* zc,
388             double* xmomc,
389             double* ymomc) {
390
391  int k;
392  double hc;
393  double u, v, reduced_speed;
394
395  //Protect against initesimal and negative heights
396  for (k=0; k<N; k++) {
397    hc = wc[k] - zc[k];
398
399    if (hc < minimum_allowed_height) {
400
401      //Old code: Set momentum to zero and ensure h is non negative
402      //xmomc[k] = 0.0;
403      //ymomc[k] = 0.0;
404      //if (hc <= 0.0) wc[k] = zc[k];
405
406
407      //New code: Adjust momentum to guarantee speeds are physical
408      //          ensure h is non negative
409      //FIXME (Ole): This is only implemented in this C extension and
410      //             has no Python equivalent
411      if (hc <= 0.0) {
412        wc[k] = zc[k];
413        xmomc[k] = 0.0;
414        ymomc[k] = 0.0;
415      } else {
416        //Reduce excessive speeds derived from division by small hc
417        u = xmomc[k]/hc;
418        if (fabs(u) > maximum_allowed_speed) {
419          reduced_speed = maximum_allowed_speed * u/fabs(u);
420          //printf("Speed (u) has been reduced from %.3f to %.3f\n",
421          //     u, reduced_speed);
422          xmomc[k] = reduced_speed * hc;
423        }
424
425        v = ymomc[k]/hc;
426        if (fabs(v) > maximum_allowed_speed) {
427          reduced_speed = maximum_allowed_speed * v/fabs(v);
428          //printf("Speed (v) has been reduced from %.3f to %.3f\n",
429          //     v, reduced_speed);
430          ymomc[k] = reduced_speed * hc;
431        }
432      }
433    }
434  }
435  return 0;
436}
437
438
439
440
441int _assign_wind_field_values(int N,
442                              double* xmom_update,
443                              double* ymom_update,
444                              double* s_vec,
445                              double* phi_vec,
446                              double cw) {
447
448  //Assign windfield values to momentum updates
449
450  int k;
451  double S, s, phi, u, v;
452
453  for (k=0; k<N; k++) {
454
455    s = s_vec[k];
456    phi = phi_vec[k];
457
458    //Convert to radians
459    phi = phi*pi/180;
460
461    //Compute velocity vector (u, v)
462    u = s*cos(phi);
463    v = s*sin(phi);
464
465    //Compute wind stress
466    S = cw * sqrt(u*u + v*v);
467    xmom_update[k] += S*u;
468    ymom_update[k] += S*v;
469  }
470  return 0;
471}
472
473
474
475///////////////////////////////////////////////////////////////////
476// Gateways to Python
477
478PyObject *gravity(PyObject *self, PyObject *args) {
479  //
480  //  gravity(g, h, v, x, xmom, ymom)
481  //
482
483
484  PyArrayObject *h, *v, *x, *xmom, *ymom;
485  int k, i, N, k3, k6;
486  double g, avg_h, zx, zy;
487  double x0, y0, x1, y1, x2, y2, z0, z1, z2;
488
489  if (!PyArg_ParseTuple(args, "dOOOOO",
490                        &g, &h, &v, &x,
491                        &xmom, &ymom))
492    return NULL;
493
494  N = h -> dimensions[0];
495  for (k=0; k<N; k++) {
496    k3 = 3*k;  // base index
497    k6 = 6*k;  // base index
498
499    avg_h = 0.0;
500    for (i=0; i<3; i++) {
501      avg_h += ((double *) h -> data)[k3+i];
502    }
503    avg_h /= 3;
504
505
506    //Compute bed slope
507    x0 = ((double*) x -> data)[k6 + 0];
508    y0 = ((double*) x -> data)[k6 + 1];
509    x1 = ((double*) x -> data)[k6 + 2];
510    y1 = ((double*) x -> data)[k6 + 3];
511    x2 = ((double*) x -> data)[k6 + 4];
512    y2 = ((double*) x -> data)[k6 + 5];
513
514
515    z0 = ((double*) v -> data)[k3 + 0];
516    z1 = ((double*) v -> data)[k3 + 1];
517    z2 = ((double*) v -> data)[k3 + 2];
518
519    _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy);
520
521    //Update momentum
522    ((double*) xmom -> data)[k] += -g*zx*avg_h;
523    ((double*) ymom -> data)[k] += -g*zy*avg_h;
524  }
525
526  return Py_BuildValue("");
527}
528
529
530PyObject *manning_friction(PyObject *self, PyObject *args) {
531  //
532  // manning_friction(g, eps, h, uh, vh, eta, xmom_update, ymom_update)
533  //
534
535
536  PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom;
537  int N;
538  double g, eps;
539
540  if (!PyArg_ParseTuple(args, "ddOOOOOOO",
541                        &g, &eps, &w, &z, &uh, &vh, &eta,
542                        &xmom, &ymom))
543    return NULL;
544
545  N = w -> dimensions[0];
546  _manning_friction(g, eps, N,
547                    (double*) w -> data,
548                    (double*) z -> data,
549                    (double*) uh -> data,
550                    (double*) vh -> data,
551                    (double*) eta -> data,
552                    (double*) xmom -> data,
553                    (double*) ymom -> data);
554
555  return Py_BuildValue("");
556}
557
558
559/*
560PyObject *manning_friction_explicit(PyObject *self, PyObject *args) {
561  //
562  // manning_friction_explicit(g, eps, h, uh, vh, eta, xmom_update, ymom_update)
563  //
564
565
566  PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom;
567  int N;
568  double g, eps;
569
570  if (!PyArg_ParseTuple(args, "ddOOOOOOO",
571                        &g, &eps, &w, &z, &uh, &vh, &eta,
572                        &xmom, &ymom))
573    return NULL;
574
575  N = w -> dimensions[0];
576  _manning_friction_explicit(g, eps, N,
577                    (double*) w -> data,
578                    (double*) z -> data,
579                    (double*) uh -> data,
580                    (double*) vh -> data,
581                    (double*) eta -> data,
582                    (double*) xmom -> data,
583                    (double*) ymom -> data);
584
585  return Py_BuildValue("");
586}
587*/
588
589PyObject *extrapolate_second_order_sw(PyObject *self, PyObject *args) {
590  /*Compute the vertex values based on a linear reconstruction on each triangle
591    These values are calculated as follows:
592    1) For each triangle not adjacent to a boundary, we consider the auxiliary triangle
593    formed by the centroids of its three neighbours.
594    2) For each conserved quantity, we integrate around the auxiliary triangle's boundary the product
595    of the quantity and the outward normal vector. Dividing by the triangle area gives (a,b), the average
596    of the vector (q_x,q_y) on the auxiliary triangle. We suppose that the linear reconstruction on the
597    original triangle has gradient (a,b).
598    3) Provisional vertex junmps dqv[0,1,2] are computed and these are then limited by calling the functions
599    find_qmin_and_qmax and limit_gradient
600
601    Python call:
602    extrapolate_second_order_sw(domain.surrogate_neighbours,
603                                domain.number_of_boundaries
604                                domain.centroid_coordinates,
605                                Stage.centroid_values
606                                Xmom.centroid_values
607                                Ymom.centroid_values
608                                domain.vertex_coordinates,
609                                Stage.vertex_values,
610                                Xmom.vertex_values,
611                                Ymom.vertex_values)
612
613    Post conditions:
614            The vertices of each triangle have values from a limited linear reconstruction
615            based on centroid values
616
617  */
618  PyArrayObject *surrogate_neighbours,
619    *number_of_boundaries,
620    *centroid_coordinates,
621    *stage_centroid_values,
622    *xmom_centroid_values,
623    *ymom_centroid_values,
624        *elevation_centroid_values,
625    *vertex_coordinates,
626    *stage_vertex_values,
627    *xmom_vertex_values,
628    *ymom_vertex_values,
629        *elevation_vertex_values;
630  PyObject *domain, *Tmp_w, *Tmp_w_dry, *Tmp_uh, *Tmp_uh_dry, *Tmp_vh, *Tmp_vh_dry;
631  //Local variables
632  double a, b;//gradient vector, not stored but used to calculate vertex values from centroids
633  int number_of_elements,k,k0,k1,k2,k3,k6,coord_index,i;
634  double x,y,x0,y0,x1,y1,x2,y2,xv0,yv0,xv1,yv1,xv2,yv2;//vertices of the auxiliary triangle
635  double dx1,dx2,dy1,dy2,dxv0,dxv1,dxv2,dyv0,dyv1,dyv2,dq0,dq1,dq2,area2;
636  double dqv[3], qmin, qmax, hmin;
637  double hc, h0, h1, h2;
638  double beta_w, beta_w_dry, beta_uh, beta_uh_dry, beta_vh, beta_vh_dry, beta_tmp;
639  //provisional jumps from centroids to v'tices and safety factor re limiting
640  //by which these jumps are limited
641  // Convert Python arguments to C
642  if (!PyArg_ParseTuple(args, "OOOOOOOOOOOOO",
643                        &domain,
644                        &surrogate_neighbours,
645                        &number_of_boundaries,
646                        &centroid_coordinates,
647                        &stage_centroid_values,
648                        &xmom_centroid_values,
649                        &ymom_centroid_values,
650                        &elevation_centroid_values,
651                        &vertex_coordinates,
652                        &stage_vertex_values,
653                        &xmom_vertex_values,
654                        &ymom_vertex_values,
655                        &elevation_vertex_values)) {
656    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
657    return NULL;
658  }
659
660  //get the safety factor beta_w, set in the config.py file. This is used in the limiting process
661  Tmp_w = PyObject_GetAttrString(domain, "beta_w");
662  if (!Tmp_w)
663    return NULL;
664  beta_w = PyFloat_AsDouble(Tmp_w);
665  Py_DECREF(Tmp_w);
666 
667  Tmp_w_dry = PyObject_GetAttrString(domain, "beta_w_dry");
668  if (!Tmp_w_dry)
669    return NULL;
670  beta_w_dry = PyFloat_AsDouble(Tmp_w_dry);
671  Py_DECREF(Tmp_w_dry);
672 
673  Tmp_uh = PyObject_GetAttrString(domain, "beta_uh");
674  if (!Tmp_uh)
675    return NULL;
676  beta_uh = PyFloat_AsDouble(Tmp_uh);
677  Py_DECREF(Tmp_uh);
678 
679  Tmp_uh_dry = PyObject_GetAttrString(domain, "beta_uh_dry");
680  if (!Tmp_uh_dry)
681    return NULL;
682  beta_uh_dry = PyFloat_AsDouble(Tmp_uh_dry);
683  Py_DECREF(Tmp_uh_dry); 
684
685  Tmp_vh = PyObject_GetAttrString(domain, "beta_vh");
686  if (!Tmp_vh)
687    return NULL;
688  beta_vh = PyFloat_AsDouble(Tmp_vh);
689  Py_DECREF(Tmp_vh);
690 
691  Tmp_vh_dry = PyObject_GetAttrString(domain, "beta_vh_dry");
692  if (!Tmp_vh_dry)
693    return NULL;
694  beta_vh_dry = PyFloat_AsDouble(Tmp_vh_dry);
695  Py_DECREF(Tmp_vh_dry);
696 
697  number_of_elements = stage_centroid_values -> dimensions[0];
698  for (k=0; k<number_of_elements; k++) {
699    k3=k*3;
700    k6=k*6;
701
702    if (((long *) number_of_boundaries->data)[k]==3){/*no neighbours, set gradient on the triangle to zero*/
703      ((double *) stage_vertex_values->data)[k3]=((double *)stage_centroid_values->data)[k];
704      ((double *) stage_vertex_values->data)[k3+1]=((double *)stage_centroid_values->data)[k];
705      ((double *) stage_vertex_values->data)[k3+2]=((double *)stage_centroid_values->data)[k];
706      ((double *) xmom_vertex_values->data)[k3]=((double *)xmom_centroid_values->data)[k];
707      ((double *) xmom_vertex_values->data)[k3+1]=((double *)xmom_centroid_values->data)[k];
708      ((double *) xmom_vertex_values->data)[k3+2]=((double *)xmom_centroid_values->data)[k];
709      ((double *) ymom_vertex_values->data)[k3]=((double *)ymom_centroid_values->data)[k];
710      ((double *) ymom_vertex_values->data)[k3+1]=((double *)ymom_centroid_values->data)[k];
711      ((double *) ymom_vertex_values->data)[k3+2]=((double *)ymom_centroid_values->data)[k];
712      continue;
713    }
714    else {//we will need centroid coordinates and vertex coordinates of the triangle
715      //get the vertex coordinates of the FV triangle
716      xv0=((double *)vertex_coordinates->data)[k6]; yv0=((double *)vertex_coordinates->data)[k6+1];
717      xv1=((double *)vertex_coordinates->data)[k6+2]; yv1=((double *)vertex_coordinates->data)[k6+3];
718      xv2=((double *)vertex_coordinates->data)[k6+4]; yv2=((double *)vertex_coordinates->data)[k6+5];
719      //get the centroid coordinates of the FV triangle
720      coord_index=2*k;
721      x=((double *)centroid_coordinates->data)[coord_index];
722      y=((double *)centroid_coordinates->data)[coord_index+1];
723      //store x- and y- differentials for the vertices of the FV triangle relative to the centroid
724      dxv0=xv0-x; dxv1=xv1-x; dxv2=xv2-x;
725      dyv0=yv0-y; dyv1=yv1-y; dyv2=yv2-y;
726    }
727    if (((long *)number_of_boundaries->data)[k]<=1){
728      //if no boundaries, auxiliary triangle is formed from the centroids of the three neighbours
729      //if one boundary, auxiliary triangle is formed from this centroid and its two neighbours
730      k0=((long *)surrogate_neighbours->data)[k3];
731      k1=((long *)surrogate_neighbours->data)[k3+1];
732      k2=((long *)surrogate_neighbours->data)[k3+2];
733      //get the auxiliary triangle's vertex coordinates (really the centroids of neighbouring triangles)
734      coord_index=2*k0;
735      x0=((double *)centroid_coordinates->data)[coord_index];
736      y0=((double *)centroid_coordinates->data)[coord_index+1];
737      coord_index=2*k1;
738      x1=((double *)centroid_coordinates->data)[coord_index];
739      y1=((double *)centroid_coordinates->data)[coord_index+1];
740      coord_index=2*k2;
741      x2=((double *)centroid_coordinates->data)[coord_index];
742      y2=((double *)centroid_coordinates->data)[coord_index+1];
743      //store x- and y- differentials for the vertices of the auxiliary triangle
744      dx1=x1-x0; dx2=x2-x0;
745      dy1=y1-y0; dy2=y2-y0;
746      //calculate 2*area of the auxiliary triangle
747      area2 = dy2*dx1 - dy1*dx2;//the triangle is guaranteed to be counter-clockwise
748      //If the mesh is 'weird' near the boundary, the trianlge might be flat or clockwise:
749      if (area2<=0)
750                return NULL;
751
752          //### Calculate heights of neighbouring cells
753          hc = ((double *)stage_centroid_values->data)[k]  - ((double *)elevation_centroid_values->data)[k];
754          h0 = ((double *)stage_centroid_values->data)[k0] - ((double *)elevation_centroid_values->data)[k0];
755          h1 = ((double *)stage_centroid_values->data)[k1] - ((double *)elevation_centroid_values->data)[k1];
756          h2 = ((double *)stage_centroid_values->data)[k2] - ((double *)elevation_centroid_values->data)[k2];
757          hmin = min(hc,min(h0,min(h1,h2)));
758      //### stage ###
759      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
760      dq0=((double *)stage_centroid_values->data)[k0]-((double *)stage_centroid_values->data)[k];
761      //calculate differentials between the vertices of the auxiliary triangle
762      dq1=((double *)stage_centroid_values->data)[k1]-((double *)stage_centroid_values->data)[k0];
763      dq2=((double *)stage_centroid_values->data)[k2]-((double *)stage_centroid_values->data)[k0];
764      //calculate the gradient of stage on the auxiliary triangle
765      a = dy2*dq1 - dy1*dq2;
766      a /= area2;
767      b = dx1*dq2 - dx2*dq1;
768      b /= area2;
769      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
770      dqv[0]=a*dxv0+b*dyv0;
771      dqv[1]=a*dxv1+b*dyv1;
772      dqv[2]=a*dxv2+b*dyv2;
773      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
774      //and compute jumps from the centroid to the min and max
775      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
776          // Playing with dry wet interface
777          hmin = qmin;
778          beta_tmp = beta_w;
779          if (hmin<0.001)
780                beta_tmp = beta_w_dry;
781      limit_gradient(dqv,qmin,qmax,beta_tmp);//the gradient will be limited
782      for (i=0;i<3;i++)
783        ((double *)stage_vertex_values->data)[k3+i]=((double *)stage_centroid_values->data)[k]+dqv[i];
784
785      //### xmom ###
786      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
787      dq0=((double *)xmom_centroid_values->data)[k0]-((double *)xmom_centroid_values->data)[k];
788      //calculate differentials between the vertices of the auxiliary triangle
789      dq1=((double *)xmom_centroid_values->data)[k1]-((double *)xmom_centroid_values->data)[k0];
790      dq2=((double *)xmom_centroid_values->data)[k2]-((double *)xmom_centroid_values->data)[k0];
791      //calculate the gradient of xmom on the auxiliary triangle
792      a = dy2*dq1 - dy1*dq2;
793      a /= area2;
794      b = dx1*dq2 - dx2*dq1;
795      b /= area2;
796      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
797      dqv[0]=a*dxv0+b*dyv0;
798      dqv[1]=a*dxv1+b*dyv1;
799      dqv[2]=a*dxv2+b*dyv2;
800      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
801      //and compute jumps from the centroid to the min and max
802      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
803          beta_tmp = beta_uh;
804          if (hmin<0.001)
805                beta_tmp = beta_uh_dry;
806      limit_gradient(dqv,qmin,qmax,beta_tmp);//the gradient will be limited
807      for (i=0;i<3;i++)
808        ((double *)xmom_vertex_values->data)[k3+i]=((double *)xmom_centroid_values->data)[k]+dqv[i];
809
810      //### ymom ###
811      //calculate the difference between vertex 0 of the auxiliary triangle and the FV triangle centroid
812      dq0=((double *)ymom_centroid_values->data)[k0]-((double *)ymom_centroid_values->data)[k];
813      //calculate differentials between the vertices of the auxiliary triangle
814      dq1=((double *)ymom_centroid_values->data)[k1]-((double *)ymom_centroid_values->data)[k0];
815      dq2=((double *)ymom_centroid_values->data)[k2]-((double *)ymom_centroid_values->data)[k0];
816      //calculate the gradient of xmom on the auxiliary triangle
817      a = dy2*dq1 - dy1*dq2;
818      a /= area2;
819      b = dx1*dq2 - dx2*dq1;
820      b /= area2;
821      //calculate provisional jumps in stage from the centroid of the FV tri to its vertices, to be limited
822      dqv[0]=a*dxv0+b*dyv0;
823      dqv[1]=a*dxv1+b*dyv1;
824      dqv[2]=a*dxv2+b*dyv2;
825      //now we want to find min and max of the centroid and the vertices of the auxiliary triangle
826      //and compute jumps from the centroid to the min and max
827      find_qmin_and_qmax(dq0,dq1,dq2,&qmin,&qmax);
828          beta_tmp = beta_vh;
829          if (hmin<0.001)
830                beta_tmp = beta_vh_dry;
831      limit_gradient(dqv,qmin,qmax,beta_tmp);//the gradient will be limited
832      for (i=0;i<3;i++)
833        ((double *)ymom_vertex_values->data)[k3+i]=((double *)ymom_centroid_values->data)[k]+dqv[i];
834    }//if (number_of_boundaries[k]<=1)
835    else{//number_of_boundaries==2
836      //one internal neighbour and gradient is in direction of the neighbour's centroid
837      //find the only internal neighbour
838      for (k2=k3;k2<k3+3;k2++){//k2 just indexes the edges of triangle k
839        if (((long *)surrogate_neighbours->data)[k2]!=k)//find internal neighbour of triabngle k
840          break;
841      }
842      if ((k2==k3+3))//if we didn't find an internal neighbour
843        return NULL;//error
844      k1=((long *)surrogate_neighbours->data)[k2];
845      //the coordinates of the triangle are already (x,y). Get centroid of the neighbour (x1,y1)
846      coord_index=2*k1;
847      x1=((double *)centroid_coordinates->data)[coord_index];
848      y1=((double *)centroid_coordinates->data)[coord_index+1];
849      //compute x- and y- distances between the centroid of the FV triangle and that of its neighbour
850      dx1=x1-x; dy1=y1-y;
851      //set area2 as the square of the distance
852      area2=dx1*dx1+dy1*dy1;
853      //set dx2=(x1-x0)/((x1-x0)^2+(y1-y0)^2) and dy2=(y1-y0)/((x1-x0)^2+(y1-y0)^2) which
854      //respectively correspond to the x- and y- gradients of the conserved quantities
855      dx2=1.0/area2;
856      dy2=dx2*dy1;
857      dx2*=dx1;
858
859      //## stage ###
860      //compute differentials
861      dq1=((double *)stage_centroid_values->data)[k1]-((double *)stage_centroid_values->data)[k];
862      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
863      a=dq1*dx2;
864      b=dq1*dy2;
865      //calculate provisional vertex jumps, to be limited
866      dqv[0]=a*dxv0+b*dyv0;
867      dqv[1]=a*dxv1+b*dyv1;
868      dqv[2]=a*dxv2+b*dyv2;
869      //now limit the jumps
870      if (dq1>=0.0){
871        qmin=0.0;
872        qmax=dq1;
873      }
874      else{
875        qmin=dq1;
876        qmax=0.0;
877      }
878      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
879      for (i=0;i<3;i++)
880        ((double *)stage_vertex_values->data)[k3+i]=((double *)stage_centroid_values->data)[k]+dqv[i];
881
882      //## xmom ###
883      //compute differentials
884      dq1=((double *)xmom_centroid_values->data)[k1]-((double *)xmom_centroid_values->data)[k];
885      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
886      a=dq1*dx2;
887      b=dq1*dy2;
888      //calculate provisional vertex jumps, to be limited
889      dqv[0]=a*dxv0+b*dyv0;
890      dqv[1]=a*dxv1+b*dyv1;
891      dqv[2]=a*dxv2+b*dyv2;
892      //now limit the jumps
893      if (dq1>=0.0){
894        qmin=0.0;
895        qmax=dq1;
896      }
897      else{
898        qmin=dq1;
899        qmax=0.0;
900      }
901      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
902      for (i=0;i<3;i++)
903        ((double *)xmom_vertex_values->data)[k3+i]=((double *)xmom_centroid_values->data)[k]+dqv[i];
904
905      //## ymom ###
906      //compute differentials
907      dq1=((double *)ymom_centroid_values->data)[k1]-((double *)ymom_centroid_values->data)[k];
908      //calculate the gradient between the centroid of the FV triangle and that of its neighbour
909      a=dq1*dx2;
910      b=dq1*dy2;
911      //calculate provisional vertex jumps, to be limited
912      dqv[0]=a*dxv0+b*dyv0;
913      dqv[1]=a*dxv1+b*dyv1;
914      dqv[2]=a*dxv2+b*dyv2;
915      //now limit the jumps
916      if (dq1>=0.0){
917        qmin=0.0;
918        qmax=dq1;
919      }
920      else{
921        qmin=dq1;
922        qmax=0.0;
923      }
924      limit_gradient(dqv,qmin,qmax,beta_w);//the gradient will be limited
925      for (i=0;i<3;i++)
926        ((double *)ymom_vertex_values->data)[k3+i]=((double *)ymom_centroid_values->data)[k]+dqv[i];
927    }//else [number_of_boudaries==2]
928  }//for k=0 to number_of_elements-1
929  return Py_BuildValue("");
930}//extrapolate_second-order_sw
931
932PyObject *rotate(PyObject *self, PyObject *args, PyObject *kwargs) {
933  //
934  // r = rotate(q, normal, direction=1)
935  //
936  // Where q is assumed to be a Float numeric array of length 3 and
937  // normal a Float numeric array of length 2.
938
939
940  PyObject *Q, *Normal;
941  PyArrayObject *q, *r, *normal;
942
943  static char *argnames[] = {"q", "normal", "direction", NULL};
944  int dimensions[1], i, direction=1;
945  double n1, n2;
946
947  // Convert Python arguments to C
948  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames,
949                                   &Q, &Normal, &direction))
950    return NULL;
951
952  //Input checks (convert sequences into numeric arrays)
953  q = (PyArrayObject *)
954    PyArray_ContiguousFromObject(Q, PyArray_DOUBLE, 0, 0);
955  normal = (PyArrayObject *)
956    PyArray_ContiguousFromObject(Normal, PyArray_DOUBLE, 0, 0);
957
958
959  if (normal -> dimensions[0] != 2) {
960    PyErr_SetString(PyExc_RuntimeError, "Normal vector must have 2 components");
961    return NULL;
962  }
963
964  //Allocate space for return vector r (don't DECREF)
965  dimensions[0] = 3;
966  r = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
967
968  //Copy
969  for (i=0; i<3; i++) {
970    ((double *) (r -> data))[i] = ((double *) (q -> data))[i];
971  }
972
973  //Get normal and direction
974  n1 = ((double *) normal -> data)[0];
975  n2 = ((double *) normal -> data)[1];
976  if (direction == -1) n2 = -n2;
977
978  //Rotate
979  _rotate((double *) r -> data, n1, n2);
980
981  //Release numeric arrays
982  Py_DECREF(q);
983  Py_DECREF(normal);
984
985  //return result using PyArray to avoid memory leak
986  return PyArray_Return(r);
987}
988
989PyObject *compute_fluxes(PyObject *self, PyObject *args) {
990  /*Compute all fluxes and the timestep suitable for all volumes
991    in domain.
992
993    Compute total flux for each conserved quantity using "flux_function"
994
995    Fluxes across each edge are scaled by edgelengths and summed up
996    Resulting flux is then scaled by area and stored in
997    explicit_update for each of the three conserved quantities
998    stage, xmomentum and ymomentum
999
1000    The maximal allowable speed computed by the flux_function for each volume
1001    is converted to a timestep that must not be exceeded. The minimum of
1002    those is computed as the next overall timestep.
1003
1004    Python call:
1005    domain.timestep = compute_fluxes(timestep,
1006                                     domain.epsilon,
1007                                     domain.g,
1008                                     domain.neighbours,
1009                                     domain.neighbour_edges,
1010                                     domain.normals,
1011                                     domain.edgelengths,
1012                                     domain.radii,
1013                                     domain.areas,
1014                                     Stage.edge_values,
1015                                     Xmom.edge_values,
1016                                     Ymom.edge_values,
1017                                     Bed.edge_values,
1018                                     Stage.boundary_values,
1019                                     Xmom.boundary_values,
1020                                     Ymom.boundary_values,
1021                                     Stage.explicit_update,
1022                                     Xmom.explicit_update,
1023                                     Ymom.explicit_update,
1024                                     already_computed_flux)
1025
1026
1027    Post conditions:
1028      domain.explicit_update is reset to computed flux values
1029      domain.timestep is set to the largest step satisfying all volumes.
1030
1031
1032  */
1033
1034
1035  PyArrayObject *neighbours, *neighbour_edges,
1036    *normals, *edgelengths, *radii, *areas,
1037    *tri_full_flag,
1038    *stage_edge_values,
1039    *xmom_edge_values,
1040    *ymom_edge_values,
1041    *bed_edge_values,
1042    *stage_boundary_values,
1043    *xmom_boundary_values,
1044    *ymom_boundary_values,
1045    *stage_explicit_update,
1046    *xmom_explicit_update,
1047    *ymom_explicit_update,
1048    *already_computed_flux;//tracks whether the flux across an edge has already been computed
1049
1050
1051  //Local variables
1052  double timestep, max_speed, epsilon, g;
1053  double normal[2], ql[3], qr[3], zl, zr;
1054  double edgeflux[3]; //Work arrays for summing up fluxes
1055
1056  int number_of_elements, k, i, m, n;
1057  int ki, nm=0, ki2; //Index shorthands
1058  static long call=1;
1059
1060
1061  // Convert Python arguments to C
1062  if (!PyArg_ParseTuple(args, "dddOOOOOOOOOOOOOOOOOO",
1063                        &timestep,
1064                        &epsilon,
1065                        &g,
1066                        &neighbours,
1067                        &neighbour_edges,
1068                        &normals,
1069                        &edgelengths, &radii, &areas,
1070                        &tri_full_flag,
1071                        &stage_edge_values,
1072                        &xmom_edge_values,
1073                        &ymom_edge_values,
1074                        &bed_edge_values,
1075                        &stage_boundary_values,
1076                        &xmom_boundary_values,
1077                        &ymom_boundary_values,
1078                        &stage_explicit_update,
1079                        &xmom_explicit_update,
1080                        &ymom_explicit_update,
1081                        &already_computed_flux)) {
1082    PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
1083    return NULL;
1084  }
1085  number_of_elements = stage_edge_values -> dimensions[0];
1086  call++;//a static local variable to which already_computed_flux is compared
1087  //set explicit_update to zero for all conserved_quantities.
1088  //This assumes compute_fluxes called before forcing terms
1089  for (k=0; k<number_of_elements; k++) {
1090    ((double *) stage_explicit_update -> data)[k]=0.0;
1091    ((double *) xmom_explicit_update -> data)[k]=0.0;
1092    ((double *) ymom_explicit_update -> data)[k]=0.0;
1093  }
1094  //Loop through neighbours and compute edge flux for each
1095  for (k=0; k<number_of_elements; k++) {
1096    for (i=0; i<3; i++) {
1097      ki = k*3+i;
1098      if (((long *) already_computed_flux->data)[ki]==call)//we've already computed the flux across this edge
1099        continue;
1100      ql[0] = ((double *) stage_edge_values -> data)[ki];
1101      ql[1] = ((double *) xmom_edge_values -> data)[ki];
1102      ql[2] = ((double *) ymom_edge_values -> data)[ki];
1103      zl =    ((double *) bed_edge_values -> data)[ki];
1104
1105      //Quantities at neighbour on nearest face
1106      n = ((long *) neighbours -> data)[ki];
1107      if (n < 0) {
1108        m = -n-1; //Convert negative flag to index
1109        qr[0] = ((double *) stage_boundary_values -> data)[m];
1110        qr[1] = ((double *) xmom_boundary_values -> data)[m];
1111        qr[2] = ((double *) ymom_boundary_values -> data)[m];
1112        zr = zl; //Extend bed elevation to boundary
1113      } else {
1114        m = ((long *) neighbour_edges -> data)[ki];
1115        nm = n*3+m;
1116        qr[0] = ((double *) stage_edge_values -> data)[nm];
1117        qr[1] = ((double *) xmom_edge_values -> data)[nm];
1118        qr[2] = ((double *) ymom_edge_values -> data)[nm];
1119        zr =    ((double *) bed_edge_values -> data)[nm];
1120      }
1121      // Outward pointing normal vector
1122      // normal = domain.normals[k, 2*i:2*i+2]
1123      ki2 = 2*ki; //k*6 + i*2
1124      normal[0] = ((double *) normals -> data)[ki2];
1125      normal[1] = ((double *) normals -> data)[ki2+1];
1126      //Edge flux computation
1127      flux_function(ql, qr, zl, zr,
1128                    normal[0], normal[1],
1129                    epsilon, g,
1130                    edgeflux, &max_speed);
1131      //update triangle k
1132      ((long *) already_computed_flux->data)[ki]=call;
1133      ((double *) stage_explicit_update -> data)[k] -= edgeflux[0]*((double *) edgelengths -> data)[ki];
1134      ((double *) xmom_explicit_update -> data)[k] -= edgeflux[1]*((double *) edgelengths -> data)[ki];
1135      ((double *) ymom_explicit_update -> data)[k] -= edgeflux[2]*((double *) edgelengths -> data)[ki];
1136      //update the neighbour n
1137      if (n>=0){
1138        ((long *) already_computed_flux->data)[nm]=call;
1139        ((double *) stage_explicit_update -> data)[n] += edgeflux[0]*((double *) edgelengths -> data)[nm];
1140        ((double *) xmom_explicit_update -> data)[n] += edgeflux[1]*((double *) edgelengths -> data)[nm];
1141        ((double *) ymom_explicit_update -> data)[n] += edgeflux[2]*((double *) edgelengths -> data)[nm];
1142      }
1143      ///for (j=0; j<3; j++) {
1144        ///flux[j] -= edgeflux[j]*((double *) edgelengths -> data)[ki];
1145        ///}
1146        //Update timestep
1147        //timestep = min(timestep, domain.radii[k]/max_speed)
1148        //FIXME: SR Add parameter for CFL condition
1149    if ( ((long *) tri_full_flag -> data)[k] == 1) {
1150            if (max_speed > epsilon) {
1151                timestep = min(timestep, ((double *) radii -> data)[k]/max_speed);
1152                //maxspeed in flux_function is calculated as max(|u+a|,|u-a|)
1153                if (n>=0)
1154                    timestep = min(timestep, ((double *) radii -> data)[n]/max_speed);
1155            }
1156    }
1157    } // end for i
1158    //Normalise by area and store for when all conserved
1159    //quantities get updated
1160    ((double *) stage_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
1161    ((double *) xmom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
1162    ((double *) ymom_explicit_update -> data)[k] /= ((double *) areas -> data)[k];
1163  } //end for k
1164  return Py_BuildValue("d", timestep);
1165}
1166
1167PyObject *protect(PyObject *self, PyObject *args) {
1168  //
1169  //    protect(minimum_allowed_height, maximum_allowed_speed, wc, zc, xmomc, ymomc)
1170
1171
1172  PyArrayObject
1173  *wc,            //Stage at centroids
1174  *zc,            //Elevation at centroids
1175  *xmomc,         //Momentums at centroids
1176  *ymomc;
1177
1178
1179  int N;
1180  double minimum_allowed_height, maximum_allowed_speed, epsilon;
1181
1182  // Convert Python arguments to C
1183  if (!PyArg_ParseTuple(args, "dddOOOO",
1184                        &minimum_allowed_height,
1185                        &maximum_allowed_speed,
1186                        &epsilon,
1187                        &wc, &zc, &xmomc, &ymomc))
1188    return NULL;
1189
1190  N = wc -> dimensions[0];
1191
1192  _protect(N,
1193           minimum_allowed_height,
1194           maximum_allowed_speed,
1195           epsilon,
1196           (double*) wc -> data,
1197           (double*) zc -> data,
1198           (double*) xmomc -> data,
1199           (double*) ymomc -> data);
1200
1201  return Py_BuildValue("");
1202}
1203
1204
1205
1206PyObject *balance_deep_and_shallow(PyObject *self, PyObject *args) {
1207  //
1208  //    balance_deep_and_shallow(wc, zc, hc, wv, zv, hv,
1209  //                             xmomc, ymomc, xmomv, ymomv)
1210
1211
1212  PyArrayObject
1213    *wc,            //Stage at centroids
1214    *zc,            //Elevation at centroids
1215    *hc,            //Height at centroids
1216    *wv,            //Stage at vertices
1217    *zv,            //Elevation at vertices
1218    *hv,            //Depths at vertices
1219    *hvbar,         //h-Limited depths at vertices
1220    *xmomc,         //Momentums at centroids and vertices
1221    *ymomc,
1222    *xmomv,
1223    *ymomv;
1224
1225  int N; //, err;
1226
1227  // Convert Python arguments to C
1228  if (!PyArg_ParseTuple(args, "OOOOOOOOOOO",
1229                        &wc, &zc, &hc,
1230                        &wv, &zv, &hv, &hvbar,
1231                        &xmomc, &ymomc, &xmomv, &ymomv))
1232    return NULL;
1233
1234  N = wc -> dimensions[0];
1235
1236  _balance_deep_and_shallow(N,
1237                            (double*) wc -> data,
1238                            (double*) zc -> data,
1239                            (double*) hc -> data,
1240                            (double*) wv -> data,
1241                            (double*) zv -> data,
1242                            (double*) hv -> data,
1243                            (double*) hvbar -> data,
1244                            (double*) xmomc -> data,
1245                            (double*) ymomc -> data,
1246                            (double*) xmomv -> data,
1247                            (double*) ymomv -> data);
1248
1249
1250  return Py_BuildValue("");
1251}
1252
1253
1254
1255PyObject *h_limiter(PyObject *self, PyObject *args) {
1256
1257  PyObject *domain, *Tmp;
1258  PyArrayObject
1259    *hv, *hc, //Depth at vertices and centroids
1260    *hvbar,   //Limited depth at vertices (return values)
1261    *neighbours;
1262
1263  int k, i, n, N, k3;
1264  int dimensions[2];
1265  double beta_h; //Safety factor (see config.py)
1266  double *hmin, *hmax, hn;
1267
1268  // Convert Python arguments to C
1269  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv))
1270    return NULL;
1271
1272  neighbours = get_consecutive_array(domain, "neighbours");
1273
1274  //Get safety factor beta_h
1275  Tmp = PyObject_GetAttrString(domain, "beta_h");
1276  if (!Tmp)
1277    return NULL;
1278
1279  beta_h = PyFloat_AsDouble(Tmp);
1280
1281  Py_DECREF(Tmp);
1282
1283  N = hc -> dimensions[0];
1284
1285  //Create hvbar
1286  dimensions[0] = N;
1287  dimensions[1] = 3;
1288  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
1289
1290
1291  //Find min and max of this and neighbour's centroid values
1292  hmin = malloc(N * sizeof(double));
1293  hmax = malloc(N * sizeof(double));
1294  for (k=0; k<N; k++) {
1295    k3=k*3;
1296
1297    hmin[k] = ((double*) hc -> data)[k];
1298    hmax[k] = hmin[k];
1299
1300    for (i=0; i<3; i++) {
1301      n = ((long*) neighbours -> data)[k3+i];
1302
1303      //Initialise hvbar with values from hv
1304      ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i];
1305
1306      if (n >= 0) {
1307        hn = ((double*) hc -> data)[n]; //Neighbour's centroid value
1308
1309        hmin[k] = min(hmin[k], hn);
1310        hmax[k] = max(hmax[k], hn);
1311      }
1312    }
1313  }
1314
1315  // Call underlying standard routine
1316  _limit(N, beta_h, (double*) hc -> data, (double*) hvbar -> data, hmin, hmax);
1317
1318  // // //Py_DECREF(domain); //FIXME: NEcessary?
1319  free(hmin);
1320  free(hmax);
1321
1322  //return result using PyArray to avoid memory leak
1323  return PyArray_Return(hvbar);
1324  //return Py_BuildValue("");
1325}
1326
1327PyObject *h_limiter_sw(PyObject *self, PyObject *args) {
1328  //a faster version of h_limiter above
1329  PyObject *domain, *Tmp;
1330  PyArrayObject
1331    *hv, *hc, //Depth at vertices and centroids
1332    *hvbar,   //Limited depth at vertices (return values)
1333    *neighbours;
1334
1335  int k, i, N, k3,k0,k1,k2;
1336  int dimensions[2];
1337  double beta_h; //Safety factor (see config.py)
1338  double hmin, hmax, dh[3];
1339  // Convert Python arguments to C
1340  if (!PyArg_ParseTuple(args, "OOO", &domain, &hc, &hv))
1341    return NULL;
1342  neighbours = get_consecutive_array(domain, "neighbours");
1343
1344  //Get safety factor beta_h
1345  Tmp = PyObject_GetAttrString(domain, "beta_h");
1346  if (!Tmp)
1347    return NULL;
1348  beta_h = PyFloat_AsDouble(Tmp);
1349
1350  Py_DECREF(Tmp);
1351
1352  N = hc -> dimensions[0];
1353
1354  //Create hvbar
1355  dimensions[0] = N;
1356  dimensions[1] = 3;
1357  hvbar = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
1358  for (k=0;k<N;k++){
1359    k3=k*3;
1360    //get the ids of the neighbours
1361    k0 = ((long*) neighbours -> data)[k3];
1362    k1 = ((long*) neighbours -> data)[k3+1];
1363    k2 = ((long*) neighbours -> data)[k3+2];
1364    //set hvbar provisionally
1365    for (i=0;i<3;i++){
1366      ((double*) hvbar -> data)[k3+i] = ((double*) hv -> data)[k3+i];
1367      dh[i]=((double*) hvbar -> data)[k3+i]-((double*) hc -> data)[k];
1368    }
1369    hmin=((double*) hc -> data)[k];
1370    hmax=hmin;
1371    if (k0>=0){
1372      hmin=min(hmin,((double*) hc -> data)[k0]);
1373      hmax=max(hmax,((double*) hc -> data)[k0]);
1374    }
1375    if (k1>=0){
1376      hmin=min(hmin,((double*) hc -> data)[k1]);
1377      hmax=max(hmax,((double*) hc -> data)[k1]);
1378    }
1379    if (k2>=0){
1380      hmin=min(hmin,((double*) hc -> data)[k2]);
1381      hmax=max(hmax,((double*) hc -> data)[k2]);
1382    }
1383    hmin-=((double*) hc -> data)[k];
1384    hmax-=((double*) hc -> data)[k];
1385    limit_gradient(dh,hmin,hmax,beta_h);
1386    for (i=0;i<3;i++)
1387      ((double*) hvbar -> data)[k3+i] = ((double*) hc -> data)[k]+dh[i];
1388  }
1389  return PyArray_Return(hvbar);
1390}
1391
1392PyObject *assign_windfield_values(PyObject *self, PyObject *args) {
1393  //
1394  //      assign_windfield_values(xmom_update, ymom_update,
1395  //                              s_vec, phi_vec, self.const)
1396
1397
1398
1399  PyArrayObject   //(one element per triangle)
1400  *s_vec,         //Speeds
1401  *phi_vec,       //Bearings
1402  *xmom_update,   //Momentum updates
1403  *ymom_update;
1404
1405
1406  int N;
1407  double cw;
1408
1409  // Convert Python arguments to C
1410  if (!PyArg_ParseTuple(args, "OOOOd",
1411                        &xmom_update,
1412                        &ymom_update,
1413                        &s_vec, &phi_vec,
1414                        &cw))
1415    return NULL;
1416
1417  N = xmom_update -> dimensions[0];
1418
1419  _assign_wind_field_values(N,
1420           (double*) xmom_update -> data,
1421           (double*) ymom_update -> data,
1422           (double*) s_vec -> data,
1423           (double*) phi_vec -> data,
1424           cw);
1425
1426  return Py_BuildValue("");
1427}
1428
1429
1430
1431
1432//////////////////////////////////////////
1433// Method table for python module
1434static struct PyMethodDef MethodTable[] = {
1435  /* The cast of the function is necessary since PyCFunction values
1436   * only take two PyObject* parameters, and rotate() takes
1437   * three.
1438   */
1439
1440  {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
1441  {"extrapolate_second_order_sw", extrapolate_second_order_sw, METH_VARARGS, "Print out"},
1442  {"compute_fluxes", compute_fluxes, METH_VARARGS, "Print out"},
1443  {"gravity", gravity, METH_VARARGS, "Print out"},
1444  {"manning_friction", manning_friction, METH_VARARGS, "Print out"},
1445  {"balance_deep_and_shallow", balance_deep_and_shallow,
1446   METH_VARARGS, "Print out"},
1447  {"h_limiter", h_limiter,
1448   METH_VARARGS, "Print out"},
1449  {"h_limiter_sw", h_limiter_sw,
1450   METH_VARARGS, "Print out"},
1451  {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"},
1452  {"assign_windfield_values", assign_windfield_values,
1453   METH_VARARGS | METH_KEYWORDS, "Print out"},
1454  //{"distribute_to_vertices_and_edges",
1455  // distribute_to_vertices_and_edges, METH_VARARGS},
1456  //{"update_conserved_quantities",
1457  // update_conserved_quantities, METH_VARARGS},
1458  //{"set_initialcondition",
1459  // set_initialcondition, METH_VARARGS},
1460  {NULL, NULL}
1461};
1462
1463// Module initialisation
1464void initshallow_water_ext(void){
1465  Py_InitModule("shallow_water_ext", MethodTable);
1466
1467  import_array();     //Necessary for handling of NumPY structures
1468}
Note: See TracBrowser for help on using the repository browser.