// Python - C extension for quantity module. // // To compile (Python2.3): // gcc -c util_ext.c -I/usr/include/python2.3 -o util_ext.o -Wall -O // gcc -shared util_ext.o -o util_ext.so // // See the module quantity.py // // // Ole Nielsen, GA 2004 #include "Python.h" #include "Numeric/arrayobject.h" #include "math.h" //Shared code snippets #include "util_ext.h" //#include "quantity_ext.h" //Obsolete int _compute_gradients(int N, double* centroids, double* centroid_values, long* number_of_boundaries, long* surrogate_neighbours, double* a, double* b){ int i, k, k0, k1, k2, index3; double x0, x1, x2, y0, y1, y2, q0, q1, q2; //, det; for (k=0; k dimensions[0]; err = _update(N, timestep, (double*) centroid_values -> data, (double*) explicit_update -> data, (double*) semi_implicit_update -> data); if (err != 0) { PyErr_SetString(PyExc_RuntimeError, "Zero division in semi implicit update - call Stephen :)"); return NULL; } //Release and return Py_DECREF(centroid_values); Py_DECREF(explicit_update); Py_DECREF(semi_implicit_update); return Py_BuildValue(""); } PyObject *backup_centroid_values(PyObject *self, PyObject *args) { PyObject *quantity; PyArrayObject *centroid_values, *centroid_backup_values; int N, err; // Convert Python arguments to C if (!PyArg_ParseTuple(args, "O", &quantity)) { PyErr_SetString(PyExc_RuntimeError, "quantity_ext.c: backup_centroid_values could not parse input"); return NULL; } centroid_values = get_consecutive_array(quantity, "centroid_values"); centroid_backup_values = get_consecutive_array(quantity, "centroid_backup_values"); N = centroid_values -> dimensions[0]; err = _backup_centroid_values(N, (double*) centroid_values -> data, (double*) centroid_backup_values -> data); //Release and return Py_DECREF(centroid_values); Py_DECREF(centroid_backup_values); return Py_BuildValue(""); } PyObject *saxpy_centroid_values(PyObject *self, PyObject *args) { PyObject *quantity; PyArrayObject *centroid_values, *centroid_backup_values; double a,b; int N, err; // Convert Python arguments to C if (!PyArg_ParseTuple(args, "Odd", &quantity, &a, &b)) { PyErr_SetString(PyExc_RuntimeError, "quantity_ext.c: saxpy_centroid_values could not parse input"); return NULL; } centroid_values = get_consecutive_array(quantity, "centroid_values"); centroid_backup_values = get_consecutive_array(quantity, "centroid_backup_values"); N = centroid_values -> dimensions[0]; err = _saxpy_centroid_values(N,a,b, (double*) centroid_values -> data, (double*) centroid_backup_values -> data); //Release and return Py_DECREF(centroid_values); Py_DECREF(centroid_backup_values); return Py_BuildValue(""); } PyObject *interpolate_from_vertices_to_edges(PyObject *self, PyObject *args) { PyObject *quantity; PyArrayObject *vertex_values, *edge_values; int N, err; // Convert Python arguments to C if (!PyArg_ParseTuple(args, "O", &quantity)) { PyErr_SetString(PyExc_RuntimeError, "quantity_ext.c: interpolate_from_vertices_to_edges could not parse input"); return NULL; } vertex_values = get_consecutive_array(quantity, "vertex_values"); edge_values = get_consecutive_array(quantity, "edge_values"); N = vertex_values -> dimensions[0]; err = _interpolate(N, (double*) vertex_values -> data, (double*) edge_values -> data); if (err != 0) { PyErr_SetString(PyExc_RuntimeError, "Interpolate could not be computed"); return NULL; } //Release and return Py_DECREF(vertex_values); Py_DECREF(edge_values); return Py_BuildValue(""); } PyObject *average_vertex_values(PyObject *self, PyObject *args) { PyArrayObject *vertex_value_indices, *number_of_triangles_per_node, *vertex_values, *A; int N, err; // Convert Python arguments to C if (!PyArg_ParseTuple(args, "OOOO", &vertex_value_indices, &number_of_triangles_per_node, &vertex_values, &A)) { PyErr_SetString(PyExc_RuntimeError, "quantity_ext.c: average_vertex_values could not parse input"); return NULL; } N = vertex_value_indices -> dimensions[0]; // printf("Got parameters, N=%d\n", N); err = _average_vertex_values(N, (long*) vertex_value_indices -> data, (long*) number_of_triangles_per_node -> data, (double*) vertex_values -> data, (double*) A -> data); //printf("Error %d", err); if (err != 0) { PyErr_SetString(PyExc_RuntimeError, "average_vertex_values could not be computed"); return NULL; } return Py_BuildValue(""); } PyObject *compute_gradients(PyObject *self, PyObject *args) { PyObject *quantity, *domain, *R; PyArrayObject *centroids, //Coordinates at centroids *centroid_values, //Values at centroids *number_of_boundaries, //Number of boundaries for each triangle *surrogate_neighbours, //True neighbours or - if one missing - self *a, *b; //Return values int dimensions[1], N, err; // Convert Python arguments to C if (!PyArg_ParseTuple(args, "O", &quantity)) { PyErr_SetString(PyExc_RuntimeError, "quantity_ext.c: compute_gradients could not parse input"); return NULL; } domain = PyObject_GetAttrString(quantity, "domain"); if (!domain) { PyErr_SetString(PyExc_RuntimeError, "compute_gradients could not obtain domain object from quantity"); return NULL; } //Get pertinent variables centroids = get_consecutive_array(domain, "centroid_coordinates"); centroid_values = get_consecutive_array(quantity, "centroid_values"); surrogate_neighbours = get_consecutive_array(domain, "surrogate_neighbours"); number_of_boundaries = get_consecutive_array(domain, "number_of_boundaries"); N = centroid_values -> dimensions[0]; //Release Py_DECREF(domain); //Allocate space for return vectors a and b (don't DECREF) dimensions[0] = N; a = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE); b = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE); err = _compute_gradients(N, (double*) centroids -> data, (double*) centroid_values -> data, (long*) number_of_boundaries -> data, (long*) surrogate_neighbours -> data, (double*) a -> data, (double*) b -> data); if (err != 0) { PyErr_SetString(PyExc_RuntimeError, "Gradient could not be computed"); return NULL; } //Release Py_DECREF(centroids); Py_DECREF(centroid_values); Py_DECREF(number_of_boundaries); Py_DECREF(surrogate_neighbours); //Build result, release and return R = Py_BuildValue("OO", PyArray_Return(a), PyArray_Return(b)); Py_DECREF(a); Py_DECREF(b); return R; } PyObject *extrapolate_second_order(PyObject *self, PyObject *args) { PyObject *quantity, *domain; PyArrayObject *centroids, //Coordinates at centroids *centroid_values, //Values at centroids *vertex_coordinates, //Coordinates at vertices *vertex_values, //Values at vertices *number_of_boundaries, //Number of boundaries for each triangle *surrogate_neighbours, //True neighbours or - if one missing - self *a, *b; //Gradients //int N, err; int dimensions[1], N, err; //double *a, *b; //Gradients // Convert Python arguments to C if (!PyArg_ParseTuple(args, "O", &quantity)) { PyErr_SetString(PyExc_RuntimeError, "extrapolate_second_order could not parse input"); return NULL; } domain = PyObject_GetAttrString(quantity, "domain"); if (!domain) { PyErr_SetString(PyExc_RuntimeError, "extrapolate_second_order could not obtain domain object from quantity"); return NULL; } //Get pertinent variables centroids = get_consecutive_array(domain, "centroid_coordinates"); centroid_values = get_consecutive_array(quantity, "centroid_values"); surrogate_neighbours = get_consecutive_array(domain, "surrogate_neighbours"); number_of_boundaries = get_consecutive_array(domain, "number_of_boundaries"); vertex_coordinates = get_consecutive_array(domain, "vertex_coordinates"); vertex_values = get_consecutive_array(quantity, "vertex_values"); N = centroid_values -> dimensions[0]; //Release Py_DECREF(domain); //Allocate space for return vectors a and b (don't DECREF) dimensions[0] = N; a = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE); b = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE); //FIXME: Odd that I couldn't use normal arrays //Allocate space for return vectors a and b (don't DECREF) //a = (double*) malloc(N * sizeof(double)); //if (!a) return NULL; //b = (double*) malloc(N * sizeof(double)); //if (!b) return NULL; err = _compute_gradients(N, (double*) centroids -> data, (double*) centroid_values -> data, (long*) number_of_boundaries -> data, (long*) surrogate_neighbours -> data, (double*) a -> data, (double*) b -> data); if (err != 0) { PyErr_SetString(PyExc_RuntimeError, "Gradient could not be computed"); return NULL; } err = _extrapolate(N, (double*) centroids -> data, (double*) centroid_values -> data, (double*) vertex_coordinates -> data, (double*) vertex_values -> data, (double*) a -> data, (double*) b -> data); if (err != 0) { PyErr_SetString(PyExc_RuntimeError, "Internal function _extrapolate failed"); return NULL; } //Release Py_DECREF(centroids); Py_DECREF(centroid_values); Py_DECREF(number_of_boundaries); Py_DECREF(surrogate_neighbours); Py_DECREF(vertex_coordinates); Py_DECREF(vertex_values); Py_DECREF(a); Py_DECREF(b); return Py_BuildValue(""); } PyObject *limit(PyObject *self, PyObject *args) { PyObject *quantity, *domain, *Tmp; PyArrayObject *qv, //Conserved quantities at vertices *qc, //Conserved quantities at centroids *neighbours; int k, i, n, N, k3; double beta_w; //Safety factor double *qmin, *qmax, qn; // Convert Python arguments to C if (!PyArg_ParseTuple(args, "O", &quantity)) { PyErr_SetString(PyExc_RuntimeError, "quantity_ext.c: limit could not parse input"); return NULL; } domain = PyObject_GetAttrString(quantity, "domain"); if (!domain) { PyErr_SetString(PyExc_RuntimeError, "quantity_ext.c: limit could not obtain domain object from quantity"); return NULL; } //neighbours = (PyArrayObject*) PyObject_GetAttrString(domain, "neighbours"); neighbours = get_consecutive_array(domain, "neighbours"); //Get safety factor beta_w Tmp = PyObject_GetAttrString(domain, "beta_w"); if (!Tmp) { PyErr_SetString(PyExc_RuntimeError, "quantity_ext.c: limit could not obtain beta_w object from domain"); return NULL; } beta_w = PyFloat_AsDouble(Tmp); Py_DECREF(Tmp); Py_DECREF(domain); qc = get_consecutive_array(quantity, "centroid_values"); qv = get_consecutive_array(quantity, "vertex_values"); N = qc -> dimensions[0]; //Find min and max of this and neighbour's centroid values qmin = malloc(N * sizeof(double)); qmax = malloc(N * sizeof(double)); for (k=0; k data)[k]; qmax[k] = qmin[k]; for (i=0; i<3; i++) { n = ((long*) neighbours -> data)[k3+i]; if (n >= 0) { qn = ((double*) qc -> data)[n]; //Neighbour's centroid value qmin[k] = min(qmin[k], qn); qmax[k] = max(qmax[k], qn); } //qmin[k] = max(qmin[k],0.5*((double*) qc -> data)[k]); //qmax[k] = min(qmax[k],2.0*((double*) qc -> data)[k]); } } // Call underlying routine _limit(N, beta_w, (double*) qc -> data, (double*) qv -> data, qmin, qmax); free(qmin); free(qmax); return Py_BuildValue(""); } // Method table for python module static struct PyMethodDef MethodTable[] = { {"limit", limit, METH_VARARGS, "Print out"}, {"update", update, METH_VARARGS, "Print out"}, {"backup_centroid_values", backup_centroid_values, METH_VARARGS, "Print out"}, {"saxpy_centroid_values", saxpy_centroid_values, METH_VARARGS, "Print out"}, {"compute_gradients", compute_gradients, METH_VARARGS, "Print out"}, {"extrapolate_second_order", extrapolate_second_order, METH_VARARGS, "Print out"}, {"interpolate_from_vertices_to_edges", interpolate_from_vertices_to_edges, METH_VARARGS, "Print out"}, {"average_vertex_values", average_vertex_values, METH_VARARGS, "Print out"}, {NULL, NULL, 0, NULL} // sentinel }; // Module initialisation void initquantity_ext(void){ Py_InitModule("quantity_ext", MethodTable); import_array(); //Necessary for handling of NumPY structures }