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

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

Windfield as explicit update

File size: 15.2 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, x;
170
171  //Divide semi_implicit update by conserved quantity 
172  for (k=0; k<N; k++) { 
173    x = centroid_values[k];
174    if (x == 0.0) {
175      //FIXME: Is this right
176      semi_implicit_update[k] = 0.0;
177    } else {
178      semi_implicit_update[k] /= x;
179    }   
180  }             
181 
182 
183  //Explicit updates
184  for (k=0; k<N; k++) {
185    centroid_values[k] += timestep*explicit_update[k];
186  }
187           
188  //Semi implicit updates
189  for (k=0; k<N; k++) { 
190    denominator = 1.0 - timestep*semi_implicit_update[k]; 
191   
192    if (denominator == 0.0) {
193      return -1;
194    } else {
195      //Update conserved_quantities from semi implicit updates
196      centroid_values[k] /= denominator;
197    }
198  }
199  return 0;
200}
201                     
202 
203/////////////////////////////////////////////////
204// Gateways to Python
205PyObject *update(PyObject *self, PyObject *args) {
206 
207  PyObject *quantity;
208  PyArrayObject *centroid_values, *explicit_update, *semi_implicit_update; 
209 
210  double timestep; 
211  int N, err;
212 
213  // Convert Python arguments to C 
214  if (!PyArg_ParseTuple(args, "Od", &quantity, &timestep)) 
215    return NULL;
216
217  centroid_values = (PyArrayObject*) 
218    PyObject_GetAttrString(quantity, "centroid_values");           
219  if (!centroid_values) return NULL;               
220
221  explicit_update = (PyArrayObject*) 
222    PyObject_GetAttrString(quantity, "explicit_update");   
223  if (!explicit_update) return NULL;         
224 
225  semi_implicit_update = (PyArrayObject*) 
226    PyObject_GetAttrString(quantity, "semi_implicit_update");   
227  if (!semi_implicit_update) return NULL;           
228
229  N = centroid_values -> dimensions[0]; 
230 
231 
232  err = _update(N, timestep,
233                (double*) centroid_values -> data,
234                (double*) explicit_update -> data,
235                (double*) semi_implicit_update -> data);               
236               
237                     
238  if (err != 0) {
239    PyErr_SetString(PyExc_RuntimeError, 
240                    "Zero division in semi implicit update - call Stephen :)");
241    return NULL;
242  }                 
243 
244  //Release and return               
245  Py_DECREF(centroid_values);   
246  Py_DECREF(explicit_update); 
247  Py_DECREF(semi_implicit_update);   
248
249  return Py_BuildValue("");
250}
251
252
253PyObject *interpolate_from_vertices_to_edges(PyObject *self, PyObject *args) {
254 
255  PyObject *quantity;
256  PyArrayObject *vertex_values, *edge_values;
257   
258  int N, err;
259 
260  // Convert Python arguments to C 
261  if (!PyArg_ParseTuple(args, "O", &quantity)) 
262    return NULL;
263
264  vertex_values = (PyArrayObject*) 
265    PyObject_GetAttrString(quantity, "vertex_values");           
266  if (!vertex_values) return NULL;               
267
268  edge_values = (PyArrayObject*) 
269    PyObject_GetAttrString(quantity, "edge_values");   
270  if (!edge_values) return NULL;         
271
272  N = vertex_values -> dimensions[0]; 
273 
274  err = _interpolate(N,
275                     (double*) vertex_values -> data,
276                     (double*) edge_values -> data);
277                     
278  if (err != 0) {
279    PyErr_SetString(PyExc_RuntimeError, "Interpolate could not be computed");
280    return NULL;
281  }                 
282 
283  //Release and return               
284  Py_DECREF(vertex_values);   
285  Py_DECREF(edge_values); 
286
287  return Py_BuildValue("");
288}
289
290
291PyObject *compute_gradients(PyObject *self, PyObject *args) {
292 
293  PyObject *quantity, *domain, *R;
294  PyArrayObject
295    *centroids,            //Coordinates at centroids
296    *centroid_values,      //Values at centroids   
297    *number_of_boundaries, //Number of boundaries for each triangle
298    *surrogate_neighbours, //True neighbours or - if one missing - self
299    *a, *b;                //Return values
300   
301  int dimensions[1], N, err;
302 
303  // Convert Python arguments to C 
304  if (!PyArg_ParseTuple(args, "O", &quantity)) 
305    return NULL;
306
307  domain = PyObject_GetAttrString(quantity, "domain");     
308  if (!domain) 
309    return NULL; 
310
311  //Get pertinent variables
312  centroids = (PyArrayObject*) 
313    PyObject_GetAttrString(domain, "centroid_coordinates"); 
314  if (!centroids) return NULL;   
315 
316  centroid_values = (PyArrayObject*) 
317    PyObject_GetAttrString(quantity, "centroid_values");   
318  if (!centroid_values) return NULL;       
319 
320  surrogate_neighbours = (PyArrayObject*) 
321    PyObject_GetAttrString(domain, "surrogate_neighbours");
322  if (!surrogate_neighbours) return NULL;       
323 
324  number_of_boundaries = (PyArrayObject*) 
325    PyObject_GetAttrString(domain, "number_of_boundaries");           
326  if (!number_of_boundaries) return NULL;           
327 
328  N = centroid_values -> dimensions[0];
329   
330  //Release
331  Py_DECREF(domain);     
332         
333  //Allocate space for return vectors a and b (don't DECREF)
334  dimensions[0] = N;
335  a = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
336  b = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE); 
337       
338
339 
340  err = _compute_gradients(N,
341                           (double*) centroids -> data, 
342                           (double*) centroid_values -> data,
343                           (int*) number_of_boundaries -> data,
344                           (int*) surrogate_neighbours -> data,
345                           (double*) a -> data,
346                           (double*) b -> data);     
347                           
348  if (err != 0) {
349    PyErr_SetString(PyExc_RuntimeError, "Gradient could not be computed");
350    return NULL;
351  }
352                     
353  //Release                 
354  Py_DECREF(centroids);   
355  Py_DECREF(centroid_values);   
356  Py_DECREF(number_of_boundaries); 
357  Py_DECREF(surrogate_neighbours);           
358         
359  //Build result, release and return
360  R = Py_BuildValue("OO", PyArray_Return(a), PyArray_Return(b)); 
361  Py_DECREF(a);     
362  Py_DECREF(b);       
363  return R;
364}
365
366
367
368PyObject *extrapolate_second_order(PyObject *self, PyObject *args) {
369 
370  PyObject *quantity, *domain;
371  PyArrayObject
372    *centroids,            //Coordinates at centroids
373    *centroid_values,      //Values at centroids   
374    *vertex_coordinates,   //Coordinates at vertices           
375    *vertex_values,        //Values at vertices       
376    *number_of_boundaries, //Number of boundaries for each triangle
377    *surrogate_neighbours, //True neighbours or - if one missing - self
378    *a, *b;                //Gradients
379   
380  //int N, err;
381  int dimensions[1], N, err; 
382  //double *a, *b;  //Gradients
383 
384  // Convert Python arguments to C 
385  if (!PyArg_ParseTuple(args, "O", &quantity)) 
386    return NULL;
387
388  domain = PyObject_GetAttrString(quantity, "domain");     
389  if (!domain) 
390    return NULL; 
391
392  //Get pertinent variables
393  centroids = (PyArrayObject*) 
394    PyObject_GetAttrString(domain, "centroid_coordinates"); 
395  if (!centroids) return NULL;   
396 
397  centroid_values = (PyArrayObject*) 
398    PyObject_GetAttrString(quantity, "centroid_values");   
399  if (!centroid_values) return NULL;       
400 
401  surrogate_neighbours = (PyArrayObject*) 
402    PyObject_GetAttrString(domain, "surrogate_neighbours");
403  if (!surrogate_neighbours) return NULL;       
404 
405  number_of_boundaries = (PyArrayObject*) 
406    PyObject_GetAttrString(domain, "number_of_boundaries");           
407  if (!number_of_boundaries) return NULL;           
408 
409  vertex_coordinates = (PyArrayObject*) 
410    PyObject_GetAttrString(domain, "vertex_coordinates");           
411  if (!vertex_coordinates) return NULL;             
412 
413  vertex_values = (PyArrayObject*) 
414    PyObject_GetAttrString(quantity, "vertex_values");           
415  if (!vertex_values) return NULL;               
416
417 
418  /*
419  printf("In extrapolate C routine\n"); 
420  printf("d0=%d, d1=%d\n",
421         vertex_values -> dimensions[0],
422         vertex_values -> dimensions[1]);
423  */
424 
425  vertex_values = (PyArrayObject*) 
426    PyObject_GetAttrString(quantity, "vertex_values");           
427  if (!vertex_values) return NULL;               
428 
429  N = centroid_values -> dimensions[0];
430   
431  //Release
432  Py_DECREF(domain);     
433         
434  //Allocate space for return vectors a and b (don't DECREF)
435  dimensions[0] = N;
436  a = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
437  b = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE); 
438
439  //FIXME: Odd that I couldn't use normal arrays         
440  //Allocate space for return vectors a and b (don't DECREF)
441  //a = (double*) malloc(N * sizeof(double));
442  //if (!a) return NULL; 
443  //b = (double*) malloc(N * sizeof(double)); 
444  //if (!b) return NULL;
445
446 
447  err = _compute_gradients(N,
448                           (double*) centroids -> data, 
449                           (double*) centroid_values -> data,
450                           (int*) number_of_boundaries -> data,
451                           (int*) surrogate_neighbours -> data,
452                           (double*) a -> data,
453                           (double*) b -> data);
454                           
455  if (err != 0) {
456    PyErr_SetString(PyExc_RuntimeError, "Gradient could not be computed");
457    return NULL;
458  }
459 
460  err = _extrapolate(N, 
461                     (double*) centroids -> data, 
462                     (double*) centroid_values -> data,             
463                     (double*) vertex_coordinates -> data,
464                     (double*) vertex_values -> data,
465                     (double*) a -> data,
466                     (double*) b -> data);                   
467  //a, b);
468                     
469                     
470  if (err != 0) {
471    PyErr_SetString(PyExc_RuntimeError, 
472                    "Internal function _extrapolate failed");
473    return NULL;
474  }                 
475               
476 
477
478  //Release 
479  Py_DECREF(centroids);   
480  Py_DECREF(centroid_values);   
481  Py_DECREF(number_of_boundaries); 
482  Py_DECREF(surrogate_neighbours);
483  Py_DECREF(vertex_coordinates);                   
484  Py_DECREF(vertex_values);                 
485  Py_DECREF(a);                   
486  Py_DECREF(b);                     
487  //free(a);     
488  //free(b);       
489 
490  return Py_BuildValue("");   
491}   
492
493
494
495PyObject *limit(PyObject *self, PyObject *args) {
496 
497  PyObject *quantity, *domain, *Tmp;
498  PyArrayObject
499    *qv, //Conserved quantities at vertices
500    *qc, //Conserved quantities at centroids
501    *neighbours;
502   
503  int k, i, n, N, k3;
504  double beta; //Safety factor
505  double *qmin, *qmax, qn;
506 
507  // Convert Python arguments to C 
508  if (!PyArg_ParseTuple(args, "O", &quantity)) 
509    return NULL;
510
511  domain = PyObject_GetAttrString(quantity, "domain");     
512  if (!domain) 
513    return NULL; 
514   
515  neighbours = (PyArrayObject*) PyObject_GetAttrString(domain, "neighbours");
516
517  //Get safety factor beta
518  Tmp = PyObject_GetAttrString(domain, "beta"); 
519  if (!Tmp) 
520    return NULL;
521     
522  beta = PyFloat_AsDouble(Tmp); 
523 
524  Py_DECREF(Tmp);   
525  Py_DECREF(domain);     
526
527  qc = (PyArrayObject*) PyObject_GetAttrString(quantity, "centroid_values"); 
528  qv = (PyArrayObject*) PyObject_GetAttrString(quantity, "vertex_values");   
529  N = qc -> dimensions[0];
530   
531  //Find min and max of this and neighbour's centroid values
532  qmin = malloc(N * sizeof(double));
533  qmax = malloc(N * sizeof(double)); 
534  for (k=0; k<N; k++) {
535    k3=k*3;
536   
537    qmin[k] = ((double*) qc -> data)[k];
538    qmax[k] = qmin[k];
539   
540    for (i=0; i<3; i++) {
541      n = ((int*) neighbours -> data)[k3+i];
542      if (n >= 0) {
543        qn = ((double*) qc -> data)[n]; //Neighbour's centroid value
544         
545        qmin[k] = min(qmin[k], qn);
546        qmax[k] = max(qmax[k], qn);
547      }
548    }
549  }
550 
551  // Call underlying routine
552  _limit(N, beta, (double*) qc -> data, (double*) qv -> data, qmin, qmax);
553         
554  free(qmin);
555  free(qmax); 
556  return Py_BuildValue(""); 
557}
558
559
560
561// Method table for python module
562static struct PyMethodDef MethodTable[] = {
563  {"limit", limit, METH_VARARGS, "Print out"},   
564  {"update", update, METH_VARARGS, "Print out"},     
565  {"compute_gradients", compute_gradients, METH_VARARGS, "Print out"},     
566  {"extrapolate_second_order", extrapolate_second_order, 
567   METH_VARARGS, "Print out"},       
568  {"interpolate_from_vertices_to_edges", 
569   interpolate_from_vertices_to_edges,
570   METH_VARARGS, "Print out"},           
571  {NULL, NULL, 0, NULL}   /* sentinel */
572};
573
574// Module initialisation   
575void initquantity_ext(void){
576  Py_InitModule("quantity_ext", MethodTable);
577 
578  import_array();     //Necessary for handling of NumPY structures 
579}
580
Note: See TracBrowser for help on using the repository browser.