[195] | 1 | // Python - C extension for finite_volumes util 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 util.py |
---|
| 8 | // |
---|
| 9 | // |
---|
| 10 | // Ole Nielsen, GA 2004 |
---|
| 11 | |
---|
| 12 | #include "Python.h" |
---|
| 13 | #include "Numeric/arrayobject.h" |
---|
| 14 | #include "math.h" |
---|
| 15 | |
---|
| 16 | |
---|
| 17 | int _gradient(double x0, double y0, |
---|
| 18 | double x1, double y1, |
---|
| 19 | double x2, double y2, |
---|
| 20 | double *q0, double *q1, double *q2, |
---|
| 21 | double *a, double *b, |
---|
| 22 | int N) { |
---|
| 23 | |
---|
| 24 | double det; |
---|
| 25 | int i; |
---|
| 26 | |
---|
| 27 | det = (y2-y0)*(x1-x0) - (y1-y0)*(x2-x0); |
---|
| 28 | |
---|
| 29 | for (i=0; i<N; i++) { |
---|
| 30 | a[i] = (y2-y0)*(q1[i]-q0[i]) - (y1-y0)*(q2[i]-q0[i]); |
---|
| 31 | a[i] /= det; |
---|
| 32 | |
---|
| 33 | b[i] = (x1-x0)*(q2[i]-q0[i]) - (x2-x0)*(q1[i]-q0[i]); |
---|
| 34 | b[i] /= det; |
---|
| 35 | } |
---|
| 36 | |
---|
| 37 | return 0; |
---|
| 38 | } |
---|
| 39 | |
---|
| 40 | |
---|
| 41 | |
---|
| 42 | // Computational function for rotation |
---|
| 43 | int _rotate(double *q, double *r, double *normal, int direction) { |
---|
| 44 | /*Rotate the momentum component q (q[1], q[2]) |
---|
| 45 | from x,y coordinates to coordinates based on normal vector. |
---|
| 46 | |
---|
| 47 | To rotate in opposite direction, call rotate with direction=1 |
---|
| 48 | Result is returned in r |
---|
| 49 | |
---|
| 50 | q and r are assumed to have three components each*/ |
---|
| 51 | |
---|
| 52 | |
---|
| 53 | double n0, n1, q1, q2; |
---|
| 54 | |
---|
| 55 | //Determine normal and direction |
---|
| 56 | n0 = normal[0]; |
---|
| 57 | if (direction == 1) { |
---|
| 58 | n1 = normal[1]; |
---|
| 59 | } else { |
---|
| 60 | n1 = -normal[1]; |
---|
| 61 | } |
---|
| 62 | |
---|
| 63 | //Shorthands |
---|
| 64 | q1 = q[1]; //uh momentum |
---|
| 65 | q2 = q[2]; //vh momentum |
---|
| 66 | |
---|
| 67 | //Rotate |
---|
| 68 | r[0] = q[0]; |
---|
| 69 | r[1] = n0*q1 + n1*q2; |
---|
| 70 | r[2] = n0*q2 - n1*q1; |
---|
| 71 | |
---|
| 72 | return 0; |
---|
| 73 | } |
---|
| 74 | |
---|
| 75 | |
---|
| 76 | |
---|
| 77 | // Gateway to Python |
---|
| 78 | PyObject *gradient(PyObject *self, PyObject *args) { |
---|
| 79 | // |
---|
| 80 | // a,b = gradient(x0, y0, x1, y1, x2, y2, q0, q1, q2) |
---|
| 81 | // |
---|
| 82 | |
---|
| 83 | double x0, y0, x1, y1, x2, y2; |
---|
| 84 | PyObject *Q0, *Q1, *Q2, *result; |
---|
| 85 | PyArrayObject *q0, *q1, *q2, *a, *b; |
---|
| 86 | int dimensions[1]; |
---|
| 87 | int N; |
---|
| 88 | |
---|
| 89 | |
---|
| 90 | // Convert Python arguments to C |
---|
| 91 | if (!PyArg_ParseTuple(args, "ddddddOOO", &x0, &y0, &x1, &y1, &x2, &y2, |
---|
| 92 | &Q0, &Q1, &Q2)) |
---|
| 93 | return NULL; |
---|
| 94 | |
---|
| 95 | //Input check |
---|
| 96 | if PyArray_Check(Q0) { |
---|
| 97 | q0 = (PyArrayObject *) |
---|
| 98 | PyArray_ContiguousFromObject(Q0, PyArray_DOUBLE, 0, 0); |
---|
| 99 | } else { |
---|
| 100 | PyErr_SetString(PyExc_TypeError, "q0 must be a numeric array"); |
---|
| 101 | return NULL; |
---|
| 102 | } |
---|
| 103 | |
---|
| 104 | if PyArray_Check(Q1) { |
---|
| 105 | q1 = (PyArrayObject *) |
---|
| 106 | PyArray_ContiguousFromObject(Q1, PyArray_DOUBLE, 0, 0); |
---|
| 107 | } else { |
---|
| 108 | PyErr_SetString(PyExc_TypeError, "q1 must be a numeric array"); |
---|
| 109 | return NULL; |
---|
| 110 | } |
---|
| 111 | |
---|
| 112 | if PyArray_Check(Q2) { |
---|
| 113 | q2 = (PyArrayObject *) |
---|
| 114 | PyArray_ContiguousFromObject(Q2, PyArray_DOUBLE, 0, 0); |
---|
| 115 | } else { |
---|
| 116 | PyErr_SetString(PyExc_TypeError, "q2 must be a numeric array"); |
---|
| 117 | return NULL; |
---|
| 118 | } |
---|
[198] | 119 | |
---|
[195] | 120 | //Allocate space for return vectors a and b |
---|
| 121 | |
---|
| 122 | N = q0 -> dimensions[0]; |
---|
| 123 | dimensions[0] = N; |
---|
| 124 | a = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE); |
---|
| 125 | b = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE); |
---|
| 126 | |
---|
| 127 | |
---|
| 128 | // Call underlying routine |
---|
| 129 | _gradient(x0, y0, x1, y1, x2, y2, |
---|
| 130 | (double *) q0 -> data, |
---|
| 131 | (double *) q1 -> data, |
---|
| 132 | (double *) q2 -> data, |
---|
| 133 | (double *) a -> data, |
---|
| 134 | (double *) b-> data, N); |
---|
| 135 | |
---|
| 136 | Py_DECREF(q0); |
---|
| 137 | Py_DECREF(q1); |
---|
| 138 | Py_DECREF(q2); |
---|
| 139 | |
---|
| 140 | // Return arrays a and b |
---|
| 141 | result = Py_BuildValue("OO", a, b); |
---|
| 142 | Py_DECREF(a); |
---|
| 143 | Py_DECREF(b); |
---|
| 144 | return result; |
---|
| 145 | } |
---|
| 146 | |
---|
| 147 | |
---|
| 148 | // Gateway to Python |
---|
| 149 | PyObject *rotate(PyObject *self, PyObject *args, PyObject *kwargs) { |
---|
| 150 | // |
---|
| 151 | // r = rotate(q, normal, direction=0) |
---|
| 152 | // |
---|
| 153 | // Where q is assumed to be a Float numeric array of length 3 and |
---|
| 154 | // normal a Float numeric array of length 2. |
---|
| 155 | |
---|
| 156 | //FIXME: Input checks and unit tests |
---|
| 157 | |
---|
| 158 | PyObject *Q, *Normal; |
---|
| 159 | PyArrayObject *q, *r, *normal; |
---|
| 160 | |
---|
| 161 | static char *argnames[] = {"q", "normal", "direction", NULL}; |
---|
| 162 | int dimensions[1]; |
---|
| 163 | int N, direction=0; |
---|
| 164 | |
---|
| 165 | // Convert Python arguments to C |
---|
| 166 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames, |
---|
| 167 | &Q, &Normal, &direction)) |
---|
| 168 | return NULL; |
---|
| 169 | |
---|
| 170 | //Input checks (convert sequenced into numeric arrays) |
---|
| 171 | |
---|
| 172 | q = (PyArrayObject *) |
---|
| 173 | PyArray_ContiguousFromObject(Q, PyArray_DOUBLE, 0, 0); |
---|
| 174 | normal = (PyArrayObject *) |
---|
| 175 | PyArray_ContiguousFromObject(Normal, PyArray_DOUBLE, 0, 0); |
---|
| 176 | |
---|
| 177 | //Allocate space for return vector r (don't DECREF) |
---|
| 178 | N = q -> dimensions[0]; |
---|
| 179 | dimensions[0] = N; |
---|
| 180 | r = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE); |
---|
| 181 | |
---|
| 182 | //Rotate |
---|
| 183 | _rotate((double *) q -> data, |
---|
| 184 | (double *) r -> data, |
---|
| 185 | (double *) normal -> data, |
---|
| 186 | direction); |
---|
| 187 | |
---|
| 188 | //Build result and DECREF r - returning r directly causes memory leak |
---|
| 189 | //result = Py_BuildValue("O", r); |
---|
| 190 | //Py_DECREF(r); |
---|
| 191 | |
---|
| 192 | //return result; |
---|
| 193 | return PyArray_Return(r); |
---|
| 194 | } |
---|
| 195 | |
---|
| 196 | |
---|
| 197 | // Method table for python module |
---|
| 198 | //static struct PyMethodDef MethodTable[] = { |
---|
| 199 | // {"gradient", gradient, METH_VARARGS}, |
---|
| 200 | // {NULL, NULL} |
---|
| 201 | //}; |
---|
| 202 | |
---|
| 203 | |
---|
| 204 | |
---|
| 205 | // Method table for python module |
---|
| 206 | static struct PyMethodDef MethodTable[] = { |
---|
| 207 | /* The cast of the function is necessary since PyCFunction values |
---|
| 208 | * only take two PyObject* parameters, and rotate() takes |
---|
| 209 | * three. |
---|
| 210 | */ |
---|
| 211 | |
---|
| 212 | {"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"}, |
---|
| 213 | {"gradient", gradient, METH_VARARGS, "Print out"}, |
---|
| 214 | {NULL, NULL, 0, NULL} /* sentinel */ |
---|
| 215 | }; |
---|
| 216 | |
---|
| 217 | |
---|
| 218 | |
---|
| 219 | // Module initialisation |
---|
| 220 | void initutil_ext(void){ |
---|
| 221 | Py_InitModule("util_ext", MethodTable); |
---|
| 222 | |
---|
| 223 | import_array(); //Necessary for handling of NumPY structures |
---|
| 224 | } |
---|
| 225 | |
---|