source: trunk/anuga_core/source/anuga/utilities/util_ext.h @ 8272

Last change on this file since 8272 was 8017, checked in by steve, 15 years ago

Added code to pickup if elevation is discontinuous. compute_fluxes now produces an error in this case

File size: 8.9 KB
Line 
1// Python - C extension for finite_volumes util module.
2//
3// To compile (Python2.3):
4//  gcc -c util_ext.c -I/usr/include/python2.3 -o util_ext.o -Wall -O
5//  gcc -shared util_ext.o  -o util_ext.so     
6//
7// See the module util.py
8//
9//
10// Ole Nielsen, GA 2004
11       
12#include "Python.h"     
13#include "numpy/arrayobject.h"
14#include "math.h"
15
16#include <stdio.h>
17#define STRINGIFY(x) #x
18#define TOSTRING(x) STRINGIFY(x)
19#define AT __FILE__ ":" TOSTRING(__LINE__)
20#define P_ERROR_BUFFER_SIZE 65
21void report_python_error(const char *location, const char *msg)
22{
23
24    char buf[P_ERROR_BUFFER_SIZE];
25    int n;
26    n = snprintf(buf, P_ERROR_BUFFER_SIZE, "Error at %s: %s\n", location, msg);
27
28    PyErr_SetString(PyExc_RuntimeError, buf);
29}
30
31
32
33double max(double x, double y) { 
34  //Return maximum of two doubles
35 
36  if (x > y) return x;
37  else return y;
38}
39
40
41double min(double x, double y) { 
42  //Return minimum of two doubles
43 
44  if (x < y) return x;
45  else return y;
46}
47
48
49double sign(double x) {
50  //Return sign of a double
51
52  if (x>0.0) return 1.0;
53  else if (x<0.0) return -1.0;
54  else return 0.0;
55}
56
57int _gradient(double x0, double y0, 
58              double x1, double y1, 
59              double x2, double y2, 
60              double q0, double q1, double q2, 
61              double *a, double *b) {
62             
63  /*Compute gradient (a,b) based on three points (x0,y0), (x1,y1) and (x2,y2)
64  with values q0, q1 and q2.
65 
66  Extrapolation formula (q0 is selected as an arbitrary origin)
67    q(x,y) = q0 + a*(x-x0) + b*(y-y0)                    (1)
68 
69  Substituting the known values for q1 and q2 into (1) yield the
70  equations for a and b
71 
72      q1-q0 = a*(x1-x0) + b*(y1-y0)                      (2)
73      q2-q0 = a*(x2-x0) + b*(y2-y0)                      (3)     
74     
75  or in matrix form
76 
77  /               \  /   \   /       \ 
78  |  x1-x0  y1-y0 |  | a |   | q1-q0 |
79  |               |  |   | = |       |
80  |  x2-x0  y2-y0 |  | b |   | q2-q0 |
81  \               /  \   /   \       /
82   
83  which is solved using the standard determinant technique   
84     
85  */
86             
87
88  double det;
89 
90  det = (y2-y0)*(x1-x0) - (y1-y0)*(x2-x0);
91
92  *a = (y2-y0)*(q1-q0) - (y1-y0)*(q2-q0);
93  *a /= det;
94
95  *b = (x1-x0)*(q2-q0) - (x2-x0)*(q1-q0);
96  *b /= det;
97
98  return 0;
99}
100
101
102int _gradient2(double x0, double y0, 
103               double x1, double y1, 
104               double q0, double q1, 
105               double *a, double *b) {
106  /*Compute gradient (a,b) between two points (x0,y0) and (x1,y1)
107  with values q0 and q1 such that the plane is constant in the direction
108  orthogonal to (x1-x0, y1-y0).
109 
110  Extrapolation formula
111    q(x,y) = q0 + a*(x-x0) + b*(y-y0)                    (1)
112 
113  Substituting the known values for q1 into (1) yields an
114  under determined  equation for a and b
115      q1-q0 = a*(x1-x0) + b*(y1-y0)                      (2)
116     
117     
118  Now add the additional requirement that the gradient in the direction
119  orthogonal to (x1-x0, y1-y0) should be zero. The orthogonal direction
120  is given by the vector (y0-y1, x1-x0).
121 
122  Define the point (x2, y2) = (x0 + y0-y1, y0 + x1-x0) on the orthognal line.
123  Then we know that the corresponding value q2 should be equal to q0 in order
124  to obtain the zero gradient, hence applying (1) again   
125      q0 = q2 = q(x2, y2) = q0 + a*(x2-x0) + b*(y2-y0)
126                          = q0 + a*(x0 + y0-y1-x0) + b*(y0 + x1-x0 - y0)
127                          = q0 + a*(y0-y1) + b*(x1-x0)
128                         
129  leads to the orthogonality constraint
130     a*(y0-y1) + b*(x1-x0) = 0                           (3)
131     
132  which closes the system and yields
133 
134  /               \  /   \   /       \ 
135  |  x1-x0  y1-y0 |  | a |   | q1-q0 |
136  |               |  |   | = |       |
137  |  y0-y1  x1-x0 |  | b |   |   0   |
138  \               /  \   /   \       /
139   
140  which is solved using the standard determinant technique   
141     
142  */
143
144  double det, xx, yy, qq;
145 
146  xx = x1-x0;
147  yy = y1-y0;
148  qq = q1-q0;
149   
150  det = xx*xx + yy*yy;  //FIXME  catch det == 0
151  *a = xx*qq/det;
152  *b = yy*qq/det;
153       
154  return 0;
155}
156
157
158void _limit_old(int N, double beta, double* qc, double* qv, 
159            double* qmin, double* qmax) { 
160
161  //N are the number of elements
162  int k, i, k3;
163  double dq, dqa[3], phi, r;
164 
165  //printf("INSIDE\n");
166  for (k=0; k<N; k++) {
167    k3 = k*3;
168   
169    //Find the gradient limiter (phi) across vertices 
170    phi = 1.0;
171    for (i=0; i<3; i++) {   
172      r = 1.0;
173     
174      dq = qv[k3+i] - qc[k];    //Delta between vertex and centroid values
175      dqa[i] = dq;              //Save dq for use in the next loop
176     
177      if (dq > 0.0) r = (qmax[k] - qc[k])/dq;
178      if (dq < 0.0) r = (qmin[k] - qc[k])/dq;     
179 
180 
181      phi = min( min(r*beta, 1.0), phi);   
182    }
183   
184    //Then update using phi limiter
185    for (i=0; i<3; i++) {   
186      qv[k3+i] = qc[k] + phi*dqa[i];
187    }
188  }
189}
190
191
192void  print_double_array(char* name, double* array, int n, int m){
193
194    int k,i,km;
195
196    printf("%s = [",name);
197    for (k=0; k<n; k++){
198        km = m*k;
199        printf("[");
200        for (i=0; i<m ; i++){
201            printf("%g ",array[km+i]);
202        }
203        if (k==(n-1))
204            printf("]");
205        else
206            printf("]\n");
207    }
208    printf("]\n");
209}
210
211void  print_int_array(char* name, int* array, int n, int m){
212
213    int k,i,km;
214
215    printf("%s = [",name);
216    for (k=0; k<n; k++){
217        km = m*k;
218        printf("[");
219        for (i=0; i<m ; i++){
220            printf("%i ",array[km+i]);
221        }
222        if (k==(n-1))
223            printf("]");
224        else
225            printf("]\n");
226    }
227    printf("]\n");
228}
229
230
231void  print_long_array(char* name, long* array, int n, int m){
232
233    int k,i,km;
234
235    printf("%s = [",name);
236    for (k=0; k<n; k++){
237        km = m*k;
238        printf("[");
239        for (i=0; i<m ; i++){
240          printf("%i ",(int) array[km+i]);
241        }
242        if (k==(n-1))
243            printf("]");
244        else
245            printf("]\n");
246    }
247    printf("]\n");
248}
249
250void print_numeric_array(PyArrayObject *x) { 
251  int i, j;
252  for (i=0; i<x->dimensions[0]; i++) { 
253    for (j=0; j<x->dimensions[1]; j++) {
254      printf("%f ", *(double*) (x->data + i*x->strides[0] + j*x->strides[1]));
255    }
256    printf("\n"); 
257  }
258  printf("\n");   
259}
260
261void print_numeric_vector(PyArrayObject *x) { 
262  int i;
263  for (i=0; i<x->dimensions[0]; i++) {
264    printf("%f ", *(double*) (x->data + i*x->strides[0])); 
265  }
266  printf("\n"); 
267}
268
269PyArrayObject *get_consecutive_array(PyObject *O, char *name) {
270  PyArrayObject *A, *B;
271 
272
273  //Get array object from attribute
274 
275  /*
276  //FIXME: THE TEST DOESN't WORK
277  printf("Err = %d\n", PyObject_HasAttrString(O, name));
278  if (PyObject_HasAttrString(O, name) == 1) {
279    B = (PyArrayObject*) PyObject_GetAttrString(O, name);
280    if (!B) return NULL;
281  } else {
282    return NULL;
283    }
284  */
285   
286  B = (PyArrayObject*) PyObject_GetAttrString(O, name);
287
288  //printf("B = %p\n",(void*)B);
289  if (!B) {
290    printf("util_ext.h: get_consecutive_array could not obtain python object");
291    printf(" %s\n",name);
292    fflush(stdout);
293    PyErr_SetString(PyExc_RuntimeError, "util_ext.h: get_consecutive_array could not obtain python object");
294    return NULL;
295  }     
296 
297  //Convert to consecutive array
298  A = (PyArrayObject*) PyArray_ContiguousFromObject((PyObject*) B, 
299                                                    B -> descr -> type, 0, 0);
300 
301  Py_DECREF(B); //FIXME: Is this really needed??
302 
303  if (!A) {
304    printf("util_ext.h: get_consecutive_array could not obtain array object");
305    printf(" %s \n",name);
306    fflush(stdout);
307    PyErr_SetString(PyExc_RuntimeError, "util_ext.h: get_consecutive_array could not obtain array");
308    return NULL;
309  }
310
311
312  return A;
313}
314
315double get_python_double(PyObject *O, char *name) {
316  PyObject *TObject;
317  #define BUFFER_SIZE 80
318  char buf[BUFFER_SIZE];
319  double tmp;
320  int n;
321 
322
323  //Get double from attribute
324  TObject = PyObject_GetAttrString(O, name);
325  if (!TObject) {
326        n =  snprintf(buf, BUFFER_SIZE, "util_ext.h: get_python_double could not obtain double %s.\n", name);
327        //printf("name = %s",name);
328    PyErr_SetString(PyExc_RuntimeError, buf);
329
330    return 0.0;
331  } 
332 
333  tmp = PyFloat_AsDouble(TObject);
334 
335  Py_DECREF(TObject);
336 
337  return tmp;
338}
339
340
341
342
343int get_python_integer(PyObject *O, char *name) {
344  PyObject *TObject;
345  #define BUFFER_SIZE 80
346  char buf[BUFFER_SIZE];
347  long tmp;
348  int n;
349 
350
351  //Get double from attribute
352  TObject = PyObject_GetAttrString(O, name);
353  if (!TObject) {
354        n =  snprintf(buf, BUFFER_SIZE, "util_ext.h: get_python_integer could not obtain double %s.\n", name);
355        //printf("name = %s",name);
356    PyErr_SetString(PyExc_RuntimeError, buf);
357    return 0;
358  } 
359 
360  tmp = PyInt_AsLong(TObject);
361 
362  Py_DECREF(TObject);
363 
364  return tmp;
365}
366
367
368PyObject *get_python_object(PyObject *O, char *name) {
369  PyObject *Oout;
370
371  Oout = PyObject_GetAttrString(O, name);
372  if (!Oout) {
373    PyErr_SetString(PyExc_RuntimeError, "util_ext.h: get_python_object could not obtain object");
374    return NULL;
375  }
376
377  return Oout;
378
379}
380
381
382// check that numpy array objects are C contiguous memory
383#define CHECK_C_CONTIG(varname) if (!PyArray_ISCONTIGUOUS(varname)) { \
384                                    char msg[1024]; \
385                                    sprintf(msg, \
386                                            "%s(): file %s, line %d: " \
387                                            "'%s' object is not C contiguous memory", \
388                                             __func__, __FILE__, __LINE__, #varname); \
389                                    PyErr_SetString(PyExc_RuntimeError, msg); \
390                                    return NULL; \
391                                }
Note: See TracBrowser for help on using the repository browser.