source: inundation-numpy-branch/pyvolution/quantity_ext.c @ 3236

Last change on this file since 3236 was 2547, checked in by ole, 19 years ago

Got everything to compile under numpy

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