source: inundation/ga/storm_surge/pyvolution-parallel/quantity_ext.c @ 1453

Last change on this file since 1453 was 1156, checked in by steve, 20 years ago

Moved zeus files to separate directory.

Hopefully fixed up logging to not casue error if no log.ini file exists in cureent directory

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