source: inundation/ga/storm_surge/pyvolution/quantity_ext.c @ 333

Last change on this file since 333 was 305, checked in by ole, 20 years ago

Some renaming
Added tidal cycle data

File size: 15.0 KB
Line 
1// Python - C extension for quantity 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 quantity.py
8//
9//
10// Ole Nielsen, GA 2004
11       
12#include "Python.h"
13#include "Numeric/arrayobject.h"
14#include "math.h"
15
16//Shared code snippets
17#include "util_ext.h"
18#include "quantity_ext.h"
19
20
21
22int _compute_gradients(int N,
23                        double* centroids, 
24                        double* centroid_values,
25                        int* number_of_boundaries,
26                        int* surrogate_neighbours,
27                        double* a,
28                        double* b) {
29                       
30  int i, k, k0, k1, k2, index3;
31  double x0, x1, x2, y0, y1, y2, q0, q1, q2, det;
32 
33 
34  for (k=0; k<N; k++) {
35    index3 = 3*k;
36   
37    if (number_of_boundaries[k] < 2) {
38      //Two or three true neighbours
39
40      //Get indices of neighbours (or self when used as surrogate)         
41      //k0, k1, k2 = surrogate_neighbours[k,:]
42     
43      k0 = surrogate_neighbours[index3 + 0];
44      k1 = surrogate_neighbours[index3 + 1];
45      k2 = surrogate_neighbours[index3 + 2];           
46      if (k0 == k1 || k1 == k2) return -1;     
47
48      //Get data
49      q0 = centroid_values[k0];
50      q1 = centroid_values[k1];
51      q2 = centroid_values[k2];                   
52
53      x0 = centroids[k0*2]; y0 = centroids[k0*2+1]; 
54      x1 = centroids[k1*2]; y1 = centroids[k1*2+1]; 
55      x2 = centroids[k2*2]; y2 = centroids[k2*2+1];             
56
57      //Gradient
58      _gradient(x0, y0, x1, y1, x2, y2, q0, q1, q2, &a[k], &b[k]);
59     
60    } else if (number_of_boundaries[k] == 2) {
61      //One true neighbour
62
63      //#Get index of the one neighbour
64      i=0; k0 = k;
65      while (i<3 && k0==k) {
66        k0 = surrogate_neighbours[index3 + i];
67        i++;
68      }
69      if (k0 == k) return -1;
70     
71      k1 = k; //self
72
73      //Get data
74      q0 = centroid_values[k0];
75      q1 = centroid_values[k1];
76           
77      x0 = centroids[k0*2]; y0 = centroids[k0*2+1]; 
78      x1 = centroids[k1*2]; y1 = centroids[k1*2+1]; 
79
80      //Gradient
81      det = x0*y1 - x1*y0;
82      if (det != 0.0) {
83        a[k] = (y1*q0 - y0*q1)/det;
84        b[k] = (x0*q1 - x1*q0)/det;
85      }
86    } 
87    //    else:
88    //        #No true neighbours -     
89    //        #Fall back to first order scheme
90    //        pass
91  }
92  return 0;
93}           
94
95
96int _extrapolate(int N,
97                 double* centroids, 
98                 double* centroid_values,               
99                 double* vertex_coordinates,
100                 double* vertex_values,
101                 double* a,
102                 double* b) {
103 
104  int k, k2, k3, k6;
105  double x, y, x0, y0, x1, y1, x2, y2;
106                     
107  for (k=0; k<N; k++) {
108    k6 = 6*k;
109    k3 = 3*k;   
110    k2 = 2*k;
111       
112    //Centroid coordinates           
113    x = centroids[k2]; y = centroids[k2+1]; 
114
115    //vertex coordinates
116    //x0, y0, x1, y1, x2, y2 = X[k,:]
117    x0 = vertex_coordinates[k6 + 0];
118    y0 = vertex_coordinates[k6 + 1];   
119    x1 = vertex_coordinates[k6 + 2];
120    y1 = vertex_coordinates[k6 + 3];       
121    x2 = vertex_coordinates[k6 + 4];
122    y2 = vertex_coordinates[k6 + 5];           
123
124    //Extrapolate
125    vertex_values[k3+0] = centroid_values[k] + a[k]*(x0-x) + b[k]*(y0-y);
126    vertex_values[k3+1] = centroid_values[k] + a[k]*(x1-x) + b[k]*(y1-y);
127    vertex_values[k3+2] = centroid_values[k] + a[k]*(x2-x) + b[k]*(y2-y);
128   
129  }
130  return 0;
131}
132
133
134
135
136int _interpolate(int N,
137                 double* vertex_values,
138                 double* edge_values) {
139 
140  int k, k3;
141  double q0, q1, q2;
142
143                     
144  for (k=0; k<N; k++) {
145    k3 = 3*k;   
146   
147    q0 = vertex_values[k3 + 0];
148    q1 = vertex_values[k3 + 1];
149    q2 = vertex_values[k3 + 2];
150           
151    //printf("%f, %f, %f\n", q0, q1, q2);
152    edge_values[k3 + 0] = 0.5*(q1+q2);
153    edge_values[k3 + 1] = 0.5*(q0+q2); 
154    edge_values[k3 + 2] = 0.5*(q0+q1);
155  } 
156  return 0;
157}
158
159int _update(int N, 
160            double timestep,
161            double* centroid_values,
162            double* explicit_update,
163            double* semi_implicit_update) {
164  //Update centroid values based on values stored in
165  //explicit_update and semi_implicit_update as well as given timestep
166 
167 
168  int k;
169  double denominator;
170 
171  //Explicit updates
172  for (k=0; k<N; k++) {
173    centroid_values[k] += timestep*explicit_update[k];
174  }
175           
176  //Semi implicit updates
177  for (k=0; k<N; k++) { 
178    denominator = 1.0 - timestep*semi_implicit_update[k]; 
179   
180    if (denominator == 0.0) {
181      return -1;
182    } else {
183      //Update conserved_quantities from semi implicit updates
184      centroid_values[k] /= denominator;
185    }
186  }
187  return 0;
188}
189                     
190 
191/////////////////////////////////////////////////
192// Gateways to Python
193PyObject *update(PyObject *self, PyObject *args) {
194 
195  PyObject *quantity;
196  PyArrayObject *centroid_values, *explicit_update, *semi_implicit_update; 
197 
198  double timestep; 
199  int N, err;
200 
201  // Convert Python arguments to C 
202  if (!PyArg_ParseTuple(args, "Od", &quantity, &timestep)) 
203    return NULL;
204
205  centroid_values = (PyArrayObject*) 
206    PyObject_GetAttrString(quantity, "centroid_values");           
207  if (!centroid_values) return NULL;               
208
209  explicit_update = (PyArrayObject*) 
210    PyObject_GetAttrString(quantity, "explicit_update");   
211  if (!explicit_update) return NULL;         
212 
213  semi_implicit_update = (PyArrayObject*) 
214    PyObject_GetAttrString(quantity, "semi_implicit_update");   
215  if (!semi_implicit_update) return NULL;           
216
217  N = centroid_values -> dimensions[0]; 
218 
219 
220  err = _update(N, timestep,
221                (double*) centroid_values -> data,
222                (double*) explicit_update -> data,
223                (double*) semi_implicit_update -> data);               
224               
225                     
226  if (err != 0) {
227    PyErr_SetString(PyExc_RuntimeError, 
228                    "Zero division in semi implicit update - call Stephen :)");
229    return NULL;
230  }                 
231 
232  //Release and return               
233  Py_DECREF(centroid_values);   
234  Py_DECREF(explicit_update); 
235  Py_DECREF(semi_implicit_update);   
236
237  return Py_BuildValue("");
238}
239
240
241PyObject *interpolate_from_vertices_to_edges(PyObject *self, PyObject *args) {
242 
243  PyObject *quantity;
244  PyArrayObject *vertex_values, *edge_values;
245   
246  int N, err;
247 
248  // Convert Python arguments to C 
249  if (!PyArg_ParseTuple(args, "O", &quantity)) 
250    return NULL;
251
252  vertex_values = (PyArrayObject*) 
253    PyObject_GetAttrString(quantity, "vertex_values");           
254  if (!vertex_values) return NULL;               
255
256  edge_values = (PyArrayObject*) 
257    PyObject_GetAttrString(quantity, "edge_values");   
258  if (!edge_values) return NULL;         
259
260  N = vertex_values -> dimensions[0]; 
261 
262  err = _interpolate(N,
263                     (double*) vertex_values -> data,
264                     (double*) edge_values -> data);
265                     
266  if (err != 0) {
267    PyErr_SetString(PyExc_RuntimeError, "Interpolate could not be computed");
268    return NULL;
269  }                 
270 
271  //Release and return               
272  Py_DECREF(vertex_values);   
273  Py_DECREF(edge_values); 
274
275  return Py_BuildValue("");
276}
277
278
279PyObject *compute_gradients(PyObject *self, PyObject *args) {
280 
281  PyObject *quantity, *domain, *R;
282  PyArrayObject
283    *centroids,            //Coordinates at centroids
284    *centroid_values,      //Values at centroids   
285    *number_of_boundaries, //Number of boundaries for each triangle
286    *surrogate_neighbours, //True neighbours or - if one missing - self
287    *a, *b;                //Return values
288   
289  int dimensions[1], N, err;
290 
291  // Convert Python arguments to C 
292  if (!PyArg_ParseTuple(args, "O", &quantity)) 
293    return NULL;
294
295  domain = PyObject_GetAttrString(quantity, "domain");     
296  if (!domain) 
297    return NULL; 
298
299  //Get pertinent variables
300  centroids = (PyArrayObject*) 
301    PyObject_GetAttrString(domain, "centroid_coordinates"); 
302  if (!centroids) return NULL;   
303 
304  centroid_values = (PyArrayObject*) 
305    PyObject_GetAttrString(quantity, "centroid_values");   
306  if (!centroid_values) return NULL;       
307 
308  surrogate_neighbours = (PyArrayObject*) 
309    PyObject_GetAttrString(domain, "surrogate_neighbours");
310  if (!surrogate_neighbours) return NULL;       
311 
312  number_of_boundaries = (PyArrayObject*) 
313    PyObject_GetAttrString(domain, "number_of_boundaries");           
314  if (!number_of_boundaries) return NULL;           
315 
316  N = centroid_values -> dimensions[0];
317   
318  //Release
319  Py_DECREF(domain);     
320         
321  //Allocate space for return vectors a and b (don't DECREF)
322  dimensions[0] = N;
323  a = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
324  b = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE); 
325       
326
327 
328  err = _compute_gradients(N,
329                           (double*) centroids -> data, 
330                           (double*) centroid_values -> data,
331                           (int*) number_of_boundaries -> data,
332                           (int*) surrogate_neighbours -> data,
333                           (double*) a -> data,
334                           (double*) b -> data);     
335                           
336  if (err != 0) {
337    PyErr_SetString(PyExc_RuntimeError, "Gradient could not be computed");
338    return NULL;
339  }
340                     
341  //Release                 
342  Py_DECREF(centroids);   
343  Py_DECREF(centroid_values);   
344  Py_DECREF(number_of_boundaries); 
345  Py_DECREF(surrogate_neighbours);           
346         
347  //Build result, release and return
348  R = Py_BuildValue("OO", PyArray_Return(a), PyArray_Return(b)); 
349  Py_DECREF(a);     
350  Py_DECREF(b);       
351  return R;
352}
353
354
355
356PyObject *extrapolate_second_order(PyObject *self, PyObject *args) {
357 
358  PyObject *quantity, *domain;
359  PyArrayObject
360    *centroids,            //Coordinates at centroids
361    *centroid_values,      //Values at centroids   
362    *vertex_coordinates,   //Coordinates at vertices           
363    *vertex_values,        //Values at vertices       
364    *number_of_boundaries, //Number of boundaries for each triangle
365    *surrogate_neighbours, //True neighbours or - if one missing - self
366    *a, *b;                //Gradients
367   
368  //int N, err;
369  int dimensions[1], N, err; 
370  //double *a, *b;  //Gradients
371 
372  // Convert Python arguments to C 
373  if (!PyArg_ParseTuple(args, "O", &quantity)) 
374    return NULL;
375
376  domain = PyObject_GetAttrString(quantity, "domain");     
377  if (!domain) 
378    return NULL; 
379
380  //Get pertinent variables
381  centroids = (PyArrayObject*) 
382    PyObject_GetAttrString(domain, "centroid_coordinates"); 
383  if (!centroids) return NULL;   
384 
385  centroid_values = (PyArrayObject*) 
386    PyObject_GetAttrString(quantity, "centroid_values");   
387  if (!centroid_values) return NULL;       
388 
389  surrogate_neighbours = (PyArrayObject*) 
390    PyObject_GetAttrString(domain, "surrogate_neighbours");
391  if (!surrogate_neighbours) return NULL;       
392 
393  number_of_boundaries = (PyArrayObject*) 
394    PyObject_GetAttrString(domain, "number_of_boundaries");           
395  if (!number_of_boundaries) return NULL;           
396 
397  vertex_coordinates = (PyArrayObject*) 
398    PyObject_GetAttrString(domain, "vertex_coordinates");           
399  if (!vertex_coordinates) return NULL;             
400 
401  vertex_values = (PyArrayObject*) 
402    PyObject_GetAttrString(quantity, "vertex_values");           
403  if (!vertex_values) return NULL;               
404
405 
406  /*
407  printf("In extrapolate C routine\n"); 
408  printf("d0=%d, d1=%d\n",
409         vertex_values -> dimensions[0],
410         vertex_values -> dimensions[1]);
411  */
412 
413  vertex_values = (PyArrayObject*) 
414    PyObject_GetAttrString(quantity, "vertex_values");           
415  if (!vertex_values) return NULL;               
416 
417  N = centroid_values -> dimensions[0];
418   
419  //Release
420  Py_DECREF(domain);     
421         
422  //Allocate space for return vectors a and b (don't DECREF)
423  dimensions[0] = N;
424  a = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
425  b = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE); 
426
427  //FIXME: Odd that I couldn't use normal arrays         
428  //Allocate space for return vectors a and b (don't DECREF)
429  //a = (double*) malloc(N * sizeof(double));
430  //if (!a) return NULL; 
431  //b = (double*) malloc(N * sizeof(double)); 
432  //if (!b) return NULL;
433
434 
435  err = _compute_gradients(N,
436                           (double*) centroids -> data, 
437                           (double*) centroid_values -> data,
438                           (int*) number_of_boundaries -> data,
439                           (int*) surrogate_neighbours -> data,
440                           (double*) a -> data,
441                           (double*) b -> data);
442                           
443  if (err != 0) {
444    PyErr_SetString(PyExc_RuntimeError, "Gradient could not be computed");
445    return NULL;
446  }
447 
448  err = _extrapolate(N, 
449                     (double*) centroids -> data, 
450                     (double*) centroid_values -> data,             
451                     (double*) vertex_coordinates -> data,
452                     (double*) vertex_values -> data,
453                     (double*) a -> data,
454                     (double*) b -> data);                   
455  //a, b);
456                     
457                     
458  if (err != 0) {
459    PyErr_SetString(PyExc_RuntimeError, 
460                    "Internal function _extrapolate failed");
461    return NULL;
462  }                 
463               
464 
465
466  //Release 
467  Py_DECREF(centroids);   
468  Py_DECREF(centroid_values);   
469  Py_DECREF(number_of_boundaries); 
470  Py_DECREF(surrogate_neighbours);
471  Py_DECREF(vertex_coordinates);                   
472  Py_DECREF(vertex_values);                 
473  Py_DECREF(a);                   
474  Py_DECREF(b);                     
475  //free(a);     
476  //free(b);       
477 
478  return Py_BuildValue("");   
479}   
480
481
482
483PyObject *limit(PyObject *self, PyObject *args) {
484 
485  PyObject *quantity, *domain, *Tmp;
486  PyArrayObject
487    *qv, //Conserved quantities at vertices
488    *qc, //Conserved quantities at centroids
489    *neighbours;
490   
491  int k, i, n, N, k3;
492  double beta; //Safety factor
493  double *qmin, *qmax, qn;
494 
495  // Convert Python arguments to C 
496  if (!PyArg_ParseTuple(args, "O", &quantity)) 
497    return NULL;
498
499  domain = PyObject_GetAttrString(quantity, "domain");     
500  if (!domain) 
501    return NULL; 
502   
503  neighbours = (PyArrayObject*) PyObject_GetAttrString(domain, "neighbours");
504
505  //Get safety factor beta
506  Tmp = PyObject_GetAttrString(domain, "beta"); 
507  if (!Tmp) 
508    return NULL;
509     
510  beta = PyFloat_AsDouble(Tmp); 
511 
512  Py_DECREF(Tmp);   
513  Py_DECREF(domain);     
514
515  qc = (PyArrayObject*) PyObject_GetAttrString(quantity, "centroid_values"); 
516  qv = (PyArrayObject*) PyObject_GetAttrString(quantity, "vertex_values");   
517  N = qc -> dimensions[0];
518   
519  //Find min and max of this and neighbour's centroid values
520  qmin = malloc(N * sizeof(double));
521  qmax = malloc(N * sizeof(double)); 
522  for (k=0; k<N; k++) {
523    k3=k*3;
524   
525    qmin[k] = ((double*) qc -> data)[k];
526    qmax[k] = qmin[k];
527   
528    for (i=0; i<3; i++) {
529      n = ((int*) neighbours -> data)[k3+i];
530      if (n >= 0) {
531        qn = ((double*) qc -> data)[n]; //Neighbour's centroid value
532         
533        qmin[k] = min(qmin[k], qn);
534        qmax[k] = max(qmax[k], qn);
535      }
536    }
537  }
538 
539  // Call underlying routine
540  _limit(N, beta, (double*) qc -> data, (double*) qv -> data, qmin, qmax);
541         
542  free(qmin);
543  free(qmax); 
544  return Py_BuildValue(""); 
545}
546
547
548
549// Method table for python module
550static struct PyMethodDef MethodTable[] = {
551  {"limit", limit, METH_VARARGS, "Print out"},   
552  {"update", update, METH_VARARGS, "Print out"},     
553  {"compute_gradients", compute_gradients, METH_VARARGS, "Print out"},     
554  {"extrapolate_second_order", extrapolate_second_order, 
555   METH_VARARGS, "Print out"},       
556  {"interpolate_from_vertices_to_edges", 
557   interpolate_from_vertices_to_edges,
558   METH_VARARGS, "Print out"},           
559  {NULL, NULL, 0, NULL}   /* sentinel */
560};
561
562// Module initialisation   
563void initquantity_ext(void){
564  Py_InitModule("quantity_ext", MethodTable);
565 
566  import_array();     //Necessary for handling of NumPY structures 
567}
568
Note: See TracBrowser for help on using the repository browser.