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

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

Fixed friction bug

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