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

Last change on this file since 9072 was 8968, checked in by steve, 11 years ago

Changes to util_ext for contiguous tests

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