From 8be867578302e0b242ba69eec30e706cf760501e Mon Sep 17 00:00:00 2001 From: Stephen Roberts Date: Wed, 4 Dec 2019 23:34:18 +1100 Subject: [PATCH] Revert "Anuga py3" --- .gitignore | 1 - anuga/__config__.py | 21 + .../mesh_factory_ext.c | 135 + .../mesh_factory_ext.pyx | 89 - .../neighbour_mesh_ext.c | 284 ++ .../neighbour_mesh_ext.pyx | 76 - ...bour_table.cpp => neighbour_table_ext.cpp} | 89 +- .../neighbour_table_ext.pyx | 30 - .../abstract_2d_finite_volumes/pmesh2domain.c | 85 - .../pmesh2domain_ext.c | 386 +++ .../pmesh2domain_ext.pyx | 168 -- anuga/abstract_2d_finite_volumes/quantity.c | 985 ------- .../abstract_2d_finite_volumes/quantity_ext.c | 2484 +++++++++++++++++ .../quantity_ext.pyx | 745 ----- anuga/abstract_2d_finite_volumes/setup.py | 67 +- anuga/advection/advection.c | 114 - anuga/advection/advection_ext.c | 248 ++ anuga/advection/advection_ext.pyx | 61 - anuga/advection/setup.py | 9 +- anuga/shallow_water/setup.py | 17 +- .../{shallow_water.c => shallow_water_ext.c} | 1739 +++++++++++- anuga/shallow_water/shallow_water_ext.pyx | 526 ---- .../{swDE1_domain.c => swDE1_domain_ext.c} | 664 ++++- anuga/shallow_water/swDE1_domain_ext.pyx | 371 --- anuga/shallow_water/sw_domain.h | 219 +- .../{swb2_domain.c => swb2_domain_ext.c} | 706 ++++- anuga/shallow_water/swb2_domain_ext.pyx | 180 -- anuga/structures/riverwall.py | 2 +- anuga/utilities/argparsing.py | 5 +- appveyor.yml | 2 +- install_everything.sh | 27 + tools/install_conda.sh | 2 +- tools/install_conda_macos.sh | 2 +- tools/install_ubuntu.sh | 5 - .../experimental_data/okushiri/project.py | 5 - .../okushiri/run_okushiri.py | 26 +- 36 files changed, 6782 insertions(+), 3793 deletions(-) create mode 100644 anuga/__config__.py create mode 100644 anuga/abstract_2d_finite_volumes/mesh_factory_ext.c delete mode 100644 anuga/abstract_2d_finite_volumes/mesh_factory_ext.pyx create mode 100644 anuga/abstract_2d_finite_volumes/neighbour_mesh_ext.c delete mode 100644 anuga/abstract_2d_finite_volumes/neighbour_mesh_ext.pyx rename anuga/abstract_2d_finite_volumes/{neighbour_table.cpp => neighbour_table_ext.cpp} (69%) delete mode 100644 anuga/abstract_2d_finite_volumes/neighbour_table_ext.pyx delete mode 100644 anuga/abstract_2d_finite_volumes/pmesh2domain.c create mode 100644 anuga/abstract_2d_finite_volumes/pmesh2domain_ext.c delete mode 100644 anuga/abstract_2d_finite_volumes/pmesh2domain_ext.pyx delete mode 100644 anuga/abstract_2d_finite_volumes/quantity.c create mode 100644 anuga/abstract_2d_finite_volumes/quantity_ext.c delete mode 100644 anuga/abstract_2d_finite_volumes/quantity_ext.pyx delete mode 100644 anuga/advection/advection.c create mode 100644 anuga/advection/advection_ext.c delete mode 100644 anuga/advection/advection_ext.pyx rename anuga/shallow_water/{shallow_water.c => shallow_water_ext.c} (73%) delete mode 100644 anuga/shallow_water/shallow_water_ext.pyx rename anuga/shallow_water/{swDE1_domain.c => swDE1_domain_ext.c} (78%) delete mode 100644 anuga/shallow_water/swDE1_domain_ext.pyx rename anuga/shallow_water/{swb2_domain.c => swb2_domain_ext.c} (61%) delete mode 100644 anuga/shallow_water/swb2_domain_ext.pyx create mode 100644 install_everything.sh diff --git a/.gitignore b/.gitignore index e6181422a..ca9b057f2 100644 --- a/.gitignore +++ b/.gitignore @@ -193,5 +193,4 @@ doc/source/generated # Things specific to this project # ################################### -anuga/__config__.py anuga/version.py diff --git a/anuga/__config__.py b/anuga/__config__.py new file mode 100644 index 000000000..7909f58f5 --- /dev/null +++ b/anuga/__config__.py @@ -0,0 +1,21 @@ +# This file is generated by /home/steve/anuga/anuga_core/setup.py +# It contains system_info results at the time of building this package. +__all__ = ["get_info","show"] + + +def get_info(name): + g = globals() + return g.get(name, g.get(name + "_info", {})) + +def show(): + for name,info_dict in globals().items(): + if name[0] == "_" or type(info_dict) is not type({}): continue + print(name + ":") + if not info_dict: + print(" NOT AVAILABLE") + for k,v in info_dict.items(): + v = str(v) + if k == "sources" and len(v) > 200: + v = v[:60] + " ...\n... " + v[-60:] + print(" %s = %s" % (k,v)) + \ No newline at end of file diff --git a/anuga/abstract_2d_finite_volumes/mesh_factory_ext.c b/anuga/abstract_2d_finite_volumes/mesh_factory_ext.c new file mode 100644 index 000000000..be300070a --- /dev/null +++ b/anuga/abstract_2d_finite_volumes/mesh_factory_ext.c @@ -0,0 +1,135 @@ + +#include "Python.h" +#include "numpy/arrayobject.h" +#include + +#define DDATA(p) ((double*)(((PyArrayObject *)p)->data)) +#define IDATA(p) ((long*)(((PyArrayObject *)p)->data)) + +static PyObject *RectangularCrossConstruct( PyObject *self, PyObject *args ) +{ + int m, n, i, j, v1, v2, v3, v4, v5, ok; + int numPoints, numElements; + double len1, len2, delta1, delta2, x, y; + double *origin; + double *points; + double *params; + long *vertices, *elements; + PyObject *pyobj_Params; + PyObject *pyobj_Origin; + PyObject *pyobj_boundary; + PyObject *pyobj_points, *pyobj_elements; + PyObject *pyobj_tuple; + + ok = PyArg_ParseTuple( args, "OOOO", &pyobj_Params, &pyobj_Origin, &pyobj_points, &pyobj_elements ); + if( !ok ){ + fprintf( stderr, "RectangularCrossConstruct func: argument parsing error\n" ); + exit(1); + } + + origin = DDATA( pyobj_Origin ); + params = DDATA( pyobj_Params ); + points = DDATA( pyobj_points ); + elements = IDATA( pyobj_elements ); + + m = (int)params[0]; + n = (int)params[1]; + len1 = params[2]; + len2 = params[3]; + + vertices = malloc( (m+1)*(n+1)*sizeof(long) ); + + delta1 = len1/m; + delta2 = len2/n; + + numPoints = 0; + for(i=0; i + +#include "util_ext.h" + +#define DDATA(p) ((double*)(((PyArrayObject *)p)->data)) +#define IDATA(p) ((long*)(((PyArrayObject *)p)->data)) +#define DIMENSHAPE(p, d) (((PyArrayObject *)p)->dimensions[d]) + + +#ifndef NDEBUG +#define ASSERT(condition, message) \ + do {\ + if(!(condition)) { \ + printf("Assertion `%s` failed in %s line %d: %s\n", \ + #condition, __FILE__, __LINE__, message); \ + exit(EXIT_FAILURE); \ + } \ + } while (0) +#else +#define ASSERT(condition, message) do { } while (0) +#endif + +static PyObject *BoundaryDictionaryConstruct( PyObject *self, PyObject *args ) +{ + int aDimen, bDimen, ok, numTriangle, volID, edgeID; + char *defaultTag; + char errorMsg[50]; + long *neighbours; + PyObject *pyobj_dictKey, *pyobj_dictVal; + PyObject *pyobj_neighbours; + PyObject *pyobj_boundary; + Py_ssize_t pos; + + ok = PyArg_ParseTuple( args, "isOO", &numTriangle, &defaultTag, &pyobj_neighbours, &pyobj_boundary ); + if( !ok ){ + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + neighbours = IDATA( pyobj_neighbours ); + aDimen = DIMENSHAPE( pyobj_neighbours, 0 ); + bDimen = DIMENSHAPE( pyobj_neighbours, 1 ); + + pos = 0; + if( PyDict_Size( pyobj_boundary ) ){ + // iterate through dictionary entries + while( PyDict_Next( pyobj_boundary, &pos, &pyobj_dictKey, &pyobj_dictVal ) ){ + volID = PyLong_AsLong( PyTuple_GetItem( pyobj_dictKey, 0 ) ); + edgeID = PyLong_AsLong( PyTuple_GetItem( pyobj_dictKey, 1 ) ); + + if (!(volID /* gets */ #include /* atoi, malloc */ #include /* strcpy */ //#include /* math!!! */ -// Hack to avoid ::hypot error using mingw on windows -#define CYTHON_CCOMPLEX 0 - // This could be replaced with fast drop-inreplacements // that are around and open. like https://github.com/greg7mdp/sparsepp // TODO: But lets see if performance of unordered_map is any problem first. @@ -14,7 +14,7 @@ #include /* std::hash */ //Shared code snippets -//#include "util_ext.h" /* in utilities */ +#include "util_ext.h" /* in utilities */ // basic type used for keys and counters // should be the same type as triangle/coordinate ids @@ -208,3 +208,84 @@ int _build_neighbour_structure(keyint N, keyint M, return err; } + +//============================================================================== +// Python method Wrapper +//============================================================================== + +PyObject *build_neighbour_structure(PyObject *self, PyObject *args) { + + /* + * Update neighbours array using triangles array + * + * N is number of nodes (vertices) + * triangle nodes defining triangles + * neighbour across edge_id + * neighbour_edges edge_id of edge in neighbouring triangle + * number_of_boundaries + */ + + PyArrayObject *neighbours, *neighbour_edges, *number_of_boundaries; + PyArrayObject *triangles; + + keyint N; // Number of nodes (read in) + keyint M; // Number of triangles (calculated from triangle array) + int err; + + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "iOOOO", &N, + &triangles, + &neighbours, + &neighbour_edges, + &number_of_boundaries + )) { + PyErr_SetString(PyExc_RuntimeError, + "hashtable.c: create_neighbours could not parse input"); + return NULL; + } + + + CHECK_C_CONTIG(triangles); + CHECK_C_CONTIG(neighbours); + CHECK_C_CONTIG(neighbour_edges); + CHECK_C_CONTIG(number_of_boundaries); + + + M = triangles -> dimensions[0]; + + + err = _build_neighbour_structure(N, M, + (long*) triangles -> data, + (long*) neighbours -> data, + (long*) neighbour_edges -> data, + (long*) number_of_boundaries -> data); + + + if (err != 0) { + PyErr_SetString(PyExc_RuntimeError, + "Duplicate Edge"); + return NULL; + } + + + return Py_BuildValue(""); +} + + +//============================================================================== +// Structures to allow calling from python +//============================================================================== +extern "C" { +// Method table for python module +static struct PyMethodDef MethodTable[] = { + {"build_neighbour_structure", build_neighbour_structure, METH_VARARGS, "Print out"}, + {NULL, NULL, 0, NULL} // sentinel +}; + +// Module initialisation +void initneighbour_table_ext(void){ + Py_InitModule("neighbour_table_ext", MethodTable); + import_array(); // Necessary for handling of NumPY structures +} +}; diff --git a/anuga/abstract_2d_finite_volumes/neighbour_table_ext.pyx b/anuga/abstract_2d_finite_volumes/neighbour_table_ext.pyx deleted file mode 100644 index c7aff893a..000000000 --- a/anuga/abstract_2d_finite_volumes/neighbour_table_ext.pyx +++ /dev/null @@ -1,30 +0,0 @@ -#cython: wraparound=False, boundscheck=False, cdivision=True, profile=False, nonecheck=False, overflowcheck=False, cdivision_warnings=False, unraisable_tracebacks=False -import cython - -# import both numpy and the Cython declarations for numpy -import numpy as np -cimport numpy as np - -ctypedef long keyint - -# declare the interface to the C code -cdef extern from "neighbour_table.cpp": - int _build_neighbour_structure(keyint N, keyint M, long* triangles, long* neighbours, long* neighbour_edges, long* number_of_boundaries) - -def build_neighbour_structure(keyint N,\ - np.ndarray[long, ndim=2, mode="c"] triangles not None,\ - np.ndarray[long, ndim=2, mode="c"] neighbours not None,\ - np.ndarray[long, ndim=2, mode="c"] neighbour_edges not None,\ - np.ndarray[long, ndim=1, mode="c"] number_of_boundaries not None): - - cdef keyint M - cdef int err - - M = triangles.shape[0] - - err = _build_neighbour_structure(N, M, &triangles[0,0], &neighbours[0,0], &neighbour_edges[0,0], &number_of_boundaries[0]) - - assert err == 0, "Duplicate Edge" - - - diff --git a/anuga/abstract_2d_finite_volumes/pmesh2domain.c b/anuga/abstract_2d_finite_volumes/pmesh2domain.c deleted file mode 100644 index 001621a0f..000000000 --- a/anuga/abstract_2d_finite_volumes/pmesh2domain.c +++ /dev/null @@ -1,85 +0,0 @@ -#include /* gets */ -#include /* atoi, malloc */ -#include /* strcpy */ -#include - -//Shared code snippets - -#include "uthash.h" /* in utilities */ - -//============================================================================== -// hashtable code from uthash. Look at copyright info in "uthash.h in the -// utilities directory -//============================================================================== - -typedef struct { - int i; - int j; -} segment_key_t; - -typedef struct { - segment_key_t key; /* key of form i , j */ - int vol_id; /* id of vol containing this segement */ - int edge_id; /* edge_id of segement in this vol */ - UT_hash_handle hh; /* makes this structure hashable */ -} segment_t; - -segment_t *segment_table = NULL; - -void add_segment(segment_key_t key, int vol_id, int edge_id) { - segment_t *s; - - s = (segment_t*) malloc(sizeof (segment_t)); - memset(s, 0, sizeof (segment_t)); - s->key.i = key.i; - s->key.j = key.j; - s->vol_id = vol_id; - s->edge_id = edge_id; - HASH_ADD(hh, segment_table, key, sizeof (segment_key_t), s); /* key: name of key field */ -} - -segment_t *find_segment(segment_key_t key) { - segment_t *s=0; - - HASH_FIND(hh, segment_table, &key, sizeof (segment_key_t), s); /* s: output pointer */ - return s; -} - -void delete_segment(segment_t *segment) { - HASH_DEL(segment_table, segment); /* user: pointer to deletee */ - free(segment); -} - -void delete_segment_all(void) { /* note we need to use void here to suppress warning */ - segment_t *current_segment, *tmp; - - HASH_ITER(hh, segment_table, current_segment, tmp) { - HASH_DEL(segment_table, current_segment); /* delete it (segment_table advances to next) */ - free(current_segment); /* free it */ - } -} - -void print_segments(void) { - segment_t *s; - - for (s = segment_table; s != NULL; s = (segment_t*) (s->hh.next)) { - printf("segment key i %d j %d vol_id %d edge_id %d\n", - s->key.i, s->key.j, s->vol_id, s->edge_id); - } -} - -int vol_id_sort(segment_t *a, segment_t *b) { - return (a->vol_id - b->vol_id); -} - -int key_sort(segment_t *a, segment_t *b) { - return (a->key.i - b->key.i); -} - -void sort_by_vol_id(void) { - HASH_SORT(segment_table, vol_id_sort); -} - -void sort_by_key(void) { - HASH_SORT(segment_table, key_sort); -} diff --git a/anuga/abstract_2d_finite_volumes/pmesh2domain_ext.c b/anuga/abstract_2d_finite_volumes/pmesh2domain_ext.c new file mode 100644 index 000000000..ebb7adde5 --- /dev/null +++ b/anuga/abstract_2d_finite_volumes/pmesh2domain_ext.c @@ -0,0 +1,386 @@ +#include "Python.h" +#include "numpy/arrayobject.h" + +#include /* gets */ +#include /* atoi, malloc */ +#include /* strcpy */ +#include + +//Shared code snippets + +#include "util_ext.h" /* in utilities */ +#include "uthash.h" /* in utilities */ + + + +#define DDATA(p) ((double*)(((PyArrayObject *)p)->data)) +#define IDATA(p) ((long*)(((PyArrayObject *)p)->data)) +#define CDATA(p) ((char*)(((PyArrayObject *)p)->data)) +#define LENDATA(p) ((long)(((PyArrayObject *)p)->dimensions[0])) + +//============================================================================== +// hashtable code from uthash. Look at copyright info in "uthash.h in the +// utilities directory +//============================================================================== + +typedef struct { + int i; + int j; +} segment_key_t; + +typedef struct { + segment_key_t key; /* key of form i , j */ + int vol_id; /* id of vol containing this segement */ + int edge_id; /* edge_id of segement in this vol */ + UT_hash_handle hh; /* makes this structure hashable */ +} segment_t; + +segment_t *segment_table = NULL; + +void add_segment(segment_key_t key, int vol_id, int edge_id) { + segment_t *s; + + s = (segment_t*) malloc(sizeof (segment_t)); + memset(s, 0, sizeof (segment_t)); + s->key.i = key.i; + s->key.j = key.j; + s->vol_id = vol_id; + s->edge_id = edge_id; + HASH_ADD(hh, segment_table, key, sizeof (segment_key_t), s); /* key: name of key field */ +} + +segment_t *find_segment(segment_key_t key) { + segment_t *s=0; + + HASH_FIND(hh, segment_table, &key, sizeof (segment_key_t), s); /* s: output pointer */ + return s; +} + +void delete_segment(segment_t *segment) { + HASH_DEL(segment_table, segment); /* user: pointer to deletee */ + free(segment); +} + +void delete_segment_all() { + segment_t *current_segment, *tmp; + + HASH_ITER(hh, segment_table, current_segment, tmp) { + HASH_DEL(segment_table, current_segment); /* delete it (segment_table advances to next) */ + free(current_segment); /* free it */ + } +} + +void print_segments() { + segment_t *s; + + for (s = segment_table; s != NULL; s = (segment_t*) (s->hh.next)) { + printf("segment key i %d j %d vol_id %d edge_id %d\n", + s->key.i, s->key.j, s->vol_id, s->edge_id); + } +} + +int vol_id_sort(segment_t *a, segment_t *b) { + return (a->vol_id - b->vol_id); +} + +int key_sort(segment_t *a, segment_t *b) { + return (a->key.i - b->key.i); +} + +void sort_by_vol_id() { + HASH_SORT(segment_table, vol_id_sort); +} + +void sort_by_key() { + HASH_SORT(segment_table, key_sort); +} + + +//============================================================================== +// Python method Wrapper +//============================================================================== + +PyObject *build_boundary_dictionary(PyObject *self, PyObject *args) { + + /* + * Update neighbours array using triangles array + * + * N is number of nodes (vertices) + * triangle nodes defining triangles + * neighbour across edge_id + * neighbour_segments edge_id of segment in neighbouring triangle + * number_of_boundaries + */ + + PyArrayObject *pyobj_segments; + PyArrayObject *pyobj_triangles; + + PyObject *pyobj_segment_tags; // List of strings + PyObject *pyobj_tag_dict; + PyObject *pyobj_key; + PyObject *pyobj_tag; + + long *triangles; + long *segments; + + int M; // Number of triangles (calculated from triangle array) + int N; // Number of segments (calculated from segments array) + int err = 0; + + int k; + int k3; + int k2; + int a,b,c; + int vol_id; + int edge_id; + int len_tag; + char *string; + segment_t *s; + segment_key_t key; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "OOOO", + &pyobj_triangles, + &pyobj_segments, + &pyobj_segment_tags, + &pyobj_tag_dict + )) { + PyErr_SetString(PyExc_RuntimeError, + "pmesh2domain.c: build_boundary_dictionary could not parse input"); + return NULL; + } + + M = LENDATA(pyobj_triangles); + N = LENDATA(pyobj_segments); + + triangles = IDATA(pyobj_triangles); + segments = IDATA(pyobj_segments); + + //-------------------------------------------------------------------------- + // Step 1: + // Populate hashtable. We use a key based on the node_ids of the + // two nodes defining the segment + //-------------------------------------------------------------------------- + for (k = 0; k < M; k++) { + + // Run through triangles + k3 = 3 * k; + + a = triangles[k3 + 0]; + b = triangles[k3 + 1]; + c = triangles[k3 + 2]; + + + + // Add segments to hashtable + + //---------------------------------------------------------------------- + // Segment a,b + //---------------------------------------------------------------------- + key.i = a; + key.j = b; + vol_id = k; + edge_id = 2; + + // Error if duplicates + s = find_segment(key); + + //printf("k = %d segment %d %d \n",k,a,b); + if (s) { + err = 1; + break; + } + // Otherwise add segment + add_segment(key, vol_id, edge_id); + + //---------------------------------------------------------------------- + // segment b,c + //---------------------------------------------------------------------- + key.i = b; + key.j = c; + vol_id = k; + edge_id = 0; + + // Error if duplicates + s = find_segment(key); + //printf("k = %d segment %d %d \n",k,b,c); + if (s) { + err = 1; + break; + } + // Otherwise add segment + add_segment(key, vol_id, edge_id); + + //---------------------------------------------------------------------- + // segment c,a + //---------------------------------------------------------------------- + key.i = c; + key.j = a; + vol_id = k; + edge_id = 1; + + // Error if duplicates + s = find_segment(key); + + //printf("k = %d segment %d %d \n",k,c,a); + if (s) { + err = 1; + break; + } + // Otherwise add segment + add_segment(key, vol_id, edge_id); + + } + + //printf("err %d \n",err); + //-------------------------------------------------------------------------- + // return with an error code if duplicate key found + // Clean up hashtable + //-------------------------------------------------------------------------- + if (err) { + //printf("Duplicate Keys:\n"); + //printf("key.i %d key.j %d vol_id %d edge_id %d \n", + // s->key.i, s->key.j,s->vol_id,s->edge_id); + //printf("key.i %d key.j %d vol_id %d edge_id %d \n", + // key.i,key.j,vol_id,edge_id); + delete_segment_all(); + PyErr_SetString(PyExc_RuntimeError, + "pmesh2domain.c: build_boundary_dictionary Duplicate segments"); + return NULL; + } + + + //-------------------------------------------------------------------------- + //Step 2: + //Go through segments. Those with null tags are added to pyobj_tag_dict + //-------------------------------------------------------------------------- + + + for (k = 0; k < N; k++) { + + k2 = 2*k; + a = segments[k2+0]; + b = segments[k2+1]; + + // pyobj_tag should be a string + pyobj_tag = PyList_GetItem(pyobj_segment_tags, (Py_ssize_t) k ); + + string = PyString_AsString(pyobj_tag); + + len_tag = strlen(string); + + //printf("segment %d %d len %d, tag %s \n",a,b,len_tag, string); + + key.i = a; + key.j = b; + s = find_segment(key); + if ( s && len_tag>0 ) { + vol_id = s->vol_id; + edge_id = s->edge_id; + + pyobj_key = PyTuple_New(2); + PyTuple_SetItem(pyobj_key, 0, PyInt_FromLong( vol_id )); + PyTuple_SetItem(pyobj_key, 1, PyInt_FromLong( edge_id )); + + PyDict_SetItem(pyobj_tag_dict, pyobj_key, pyobj_tag ); + } + + key.i = b; + key.j = a; + s = find_segment(key); + if ( s && len_tag>0 ) { + vol_id = s->vol_id; + edge_id = s->edge_id; + + pyobj_key = PyTuple_New(2); + PyTuple_SetItem(pyobj_key, 0, PyInt_FromLong( vol_id )); + PyTuple_SetItem(pyobj_key, 1, PyInt_FromLong( edge_id )); + + PyDict_SetItem(pyobj_tag_dict, pyobj_key, pyobj_tag ); + } + + } + + delete_segment_all(); /* free any structures */ + + return Py_BuildValue("O", pyobj_tag_dict); +} + + +//============================================================================== +// Structures to allow calling from python +//============================================================================== + +static PyObject *build_sides_dictionary(PyObject *self, PyObject *args) { + long i, numTriangle; + int ok; + long a, b, c; + long *triangles; + PyObject *pyobj_key; + PyObject *pyobj_sides; + PyArrayObject *pyobj_triangles; + + + ok = PyArg_ParseTuple(args, "OO", &pyobj_triangles, &pyobj_sides); + if (!ok) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + + numTriangle = LENDATA(pyobj_triangles); + triangles = IDATA(pyobj_triangles); + + + + for (i = 0; i < numTriangle; i++) { + a = triangles[i * 3 + 0]; + b = triangles[i * 3 + 1]; + c = triangles[i * 3 + 2]; + + // sides[a,b] = (id, 2) #(id, face) + pyobj_key = PyTuple_New(2); + PyTuple_SetItem(pyobj_key, 0, PyInt_FromLong(a)); + PyTuple_SetItem(pyobj_key, 1, PyInt_FromLong(b)); + + PyDict_SetItem(pyobj_sides, pyobj_key, PyInt_FromLong(3 * i + 2)); + + Py_DECREF(pyobj_key); + + // sides[b,c] = (id, 0) #(id, face) + pyobj_key = PyTuple_New(2); + PyTuple_SetItem(pyobj_key, 0, PyInt_FromLong(b)); + PyTuple_SetItem(pyobj_key, 1, PyInt_FromLong(c)); + + PyDict_SetItem(pyobj_sides, pyobj_key, PyInt_FromLong(3 * i + 0)); + + Py_DECREF(pyobj_key); + + + // sides[c,a] = (id, 1) #(id, face) + pyobj_key = PyTuple_New(2); + PyTuple_SetItem(pyobj_key, 0, PyInt_FromLong(c)); + PyTuple_SetItem(pyobj_key, 1, PyInt_FromLong(a)); + + PyDict_SetItem(pyobj_sides, pyobj_key, PyInt_FromLong(3 * i + 1)); + + Py_DECREF(pyobj_key); + + + } + + return Py_BuildValue("O", pyobj_sides); +} + + +static PyMethodDef MF_module_methods[] = { +{"build_boundary_dictionary", build_boundary_dictionary, METH_VARARGS}, +{"build_sides_dictionary", build_sides_dictionary, METH_VARARGS}, + {NULL, NULL} //sentinel + }; + +void initpmesh2domain_ext() { + (void) Py_InitModule("pmesh2domain_ext", MF_module_methods); + + import_array(); +} diff --git a/anuga/abstract_2d_finite_volumes/pmesh2domain_ext.pyx b/anuga/abstract_2d_finite_volumes/pmesh2domain_ext.pyx deleted file mode 100644 index 14a7efce2..000000000 --- a/anuga/abstract_2d_finite_volumes/pmesh2domain_ext.pyx +++ /dev/null @@ -1,168 +0,0 @@ -#cython: wraparound=False, boundscheck=False, cdivision=True, profile=False, nonecheck=False, overflowcheck=False, cdivision_warnings=False, unraisable_tracebacks=False -import cython -from cython cimport typeof - -# import both numpy and the Cython declarations for numpy -import numpy as np -cimport numpy as np - -# declare the interface to the C code -cdef extern from "pmesh2domain.c": - # If the structs are defined using typedef in the C code, we have to use ctypedef here. - # Otherwise, it will lead to weird errors. - ctypedef struct UT_hash_handle: - pass - ctypedef struct segment_key_t: - int i - int j - ctypedef struct segment_t: - segment_key_t key - int vol_id - int edge_id - UT_hash_handle hh - void add_segment(segment_key_t key, int vol_id, int edge_id) - segment_t* find_segment(segment_key_t key) - void delete_segment(segment_t* segment) - void delete_segment_all() - void print_segments() - int vol_id_sort(segment_t* a, segment_t* b) - int key_sort(segment_t* a, segment_t* b) - void sort_by_vol_id() - void sort_by_key() - -def build_boundary_dictionary(np.ndarray[long, ndim=2, mode="c"] triangles not None,\ - np.ndarray[long, ndim=2, mode="c"] segments not None,\ - list segment_tags,\ - dict tag_dict): - """ - Update neighbours array using triangle - - N is number of nodes (vertices) - triangle nodes defining triangles - neighbour across edge_id - neighbour_segments edge_id of segment in neighbouring triangle - number_of_boundaries - """ - - cdef int M, N - cdef int err = 0 - cdef int k, a, b, c, vol_id, edge_id, len_tag - - cdef char* string - cdef segment_t* s - cdef segment_key_t key - - M = triangles.shape[0] - N = segments.shape[0] - - # Step 1: Populate hashtable. We use a key based on the node_ids of the two nodes defining the segment - for k in xrange(M): - - a = triangles[k,0] - b = triangles[k,1] - c = triangles[k,2] - - # Add segment a,b to hashtable - key.i = a - key.j = b - vol_id = k - edge_id = 2 - - s = find_segment(key) - - if s: - err = 1 - break - - add_segment(key, vol_id, edge_id) - - # Add segment b,c to hashtable - key.i = b - key.j = c - vol_id = k - edge_id = 0 - - s = find_segment(key) - - if s: - err = 1 - break - - add_segment(key, vol_id, edge_id) - - # Add segment c,a to hashtable - key.i = c - key.j = a - vol_id = k - edge_id = 1 - - s = find_segment(key) - - if s: - err = 1 - break - - add_segment(key, vol_id, edge_id) - - if err == 1: - delete_segment_all() - - assert err != 1, "pmesh2domain.c: build_boundary_dictionary Duplicate segments" - - # Step 2: Go through segments. Those with null tags are added to tag_dict - for k in xrange(N): - - a = segments[k,0] - b = segments[k,1] - - string = segment_tags[k] - len_tag = len(string) - - key.i = a - key.j = b - s = find_segment(key) - - if s and len_tag > 0: - vol_id = s.vol_id - edge_id = s.edge_id - tag_dict[(vol_id, edge_id)] = string - - key.i = b - key.j = a - s = find_segment(key) - - if s and len_tag > 0: - vol_id = s.vol_id - edge_id = s.edge_id - tag_dict[(vol_id, edge_id)] = string - - delete_segment_all() - return tag_dict - -def build_sides_dictionary(np.ndarray[long, ndim=2, mode="c"] triangles not None, dict sides): - - cdef long i, numTriangle, a, b, c - - numTriangle = triangles.shape[0] - - for i in xrange(numTriangle): - - a = triangles[i,0] - b = triangles[i,1] - c = triangles[i,2] - - sides[(a,b)] = 3*i + 2 # sides[a,b] = (id, 2) #(id, face) - sides[(b,c)] = 3*i + 0 # sides[b,c] = (id, 0) #(id, face) - sides[(c,a)] = 3*i + 1 # sides[c,a] = (id, 1) #(id, face) - - return sides - - - - - - - - - - diff --git a/anuga/abstract_2d_finite_volumes/quantity.c b/anuga/abstract_2d_finite_volumes/quantity.c deleted file mode 100644 index 1e58f4b16..000000000 --- a/anuga/abstract_2d_finite_volumes/quantity.c +++ /dev/null @@ -1,985 +0,0 @@ -// 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 "math.h" - -//Shared code snippets -#include "util_ext.h" - -typedef long keyint; - -//------------------------------------------- -// Low level routines (called from wrappers) -//------------------------------------------ - -int _compute_gradients(keyint N, - double* centroids, - double* centroid_values, - long* number_of_boundaries, - long* surrogate_neighbours, - double* a, - double* b){ - - keyint i, k, k0, k1, k2, index3; - double x0, x1, x2, y0, y1, y2, q0, q1, q2; //, det; - - - for (k=0; k 0.0) r = (qmax - qc)/dq; - if (dq < 0.0) r = (qmin - qc)/dq; - - phi[k] = min( min(r*beta, 1.0), phi[k]); - - } - - - - //Update gradient, edge and vertex values using phi limiter - x_gradient[k] = x_gradient[k]*phi[k]; - y_gradient[k] = y_gradient[k]*phi[k]; - - edge_values[k3+0] = qc + phi[k]*dqa[0]; - edge_values[k3+1] = qc + phi[k]*dqa[1]; - edge_values[k3+2] = qc + phi[k]*dqa[2]; - - - vertex_values[k3+0] = edge_values[k3+1] + edge_values[k3+2] - edge_values[k3+0]; - vertex_values[k3+1] = edge_values[k3+2] + edge_values[k3+0] - edge_values[k3+1]; - vertex_values[k3+2] = edge_values[k3+0] + edge_values[k3+1] - edge_values[k3+2]; - - - } - - return 0; - -} - - - - -int _limit_vertices_by_all_neighbours(keyint N, double beta, - double* centroid_values, - double* vertex_values, - double* edge_values, - long* neighbours, - double* x_gradient, - double* y_gradient) { - - - keyint i, k, k2, k3, k6; - keyint n; - double qmin, qmax, qn, qc; - double dq, dqa[3], phi, r; - - for (k=0; k= 0) { - qn = centroid_values[n]; //Neighbour's centroid value - - qmin = min(qmin, qn); - qmax = max(qmax, qn); - } - } - - phi = 1.0; - for (i=0; i<3; i++) { - r = 1.0; - - dq = vertex_values[k3+i] - qc; //Delta between vertex and centroid values - dqa[i] = dq; //Save dq for use in updating vertex values - - if (dq > 0.0) r = (qmax - qc)/dq; - if (dq < 0.0) r = (qmin - qc)/dq; - - - phi = min( min(r*beta, 1.0), phi); - } - - //Update gradient, vertex and edge values using phi limiter - x_gradient[k] = x_gradient[k]*phi; - y_gradient[k] = y_gradient[k]*phi; - - vertex_values[k3+0] = qc + phi*dqa[0]; - vertex_values[k3+1] = qc + phi*dqa[1]; - vertex_values[k3+2] = qc + phi*dqa[2]; - - edge_values[k3+0] = 0.5*(vertex_values[k3+1] + vertex_values[k3+2]); - edge_values[k3+1] = 0.5*(vertex_values[k3+2] + vertex_values[k3+0]); - edge_values[k3+2] = 0.5*(vertex_values[k3+0] + vertex_values[k3+1]); - - } - - return 0; -} - - - - -int _limit_edges_by_all_neighbours(keyint N, double beta, - double* centroid_values, - double* vertex_values, - double* edge_values, - long* neighbours, - double* x_gradient, - double* y_gradient) { - - keyint i, k, k2, k3, k6; - keyint n; - double qmin, qmax, qn, qc, sign; - double dq, dqa[3], phi, r; - - for (k=0; k= 0) { - qn = centroid_values[n]; //Neighbour's centroid value - - qmin = min(qmin, qn); - qmax = max(qmax, qn); - } - } - - sign = 0.0; - if (qmin > 0.0) { - sign = 1.0; - } else if (qmax < 0) { - sign = -1.0; - } - - phi = 1.0; - for (i=0; i<3; i++) { - dq = edge_values[k3+i] - qc; //Delta between edge and centroid values - dqa[i] = dq; //Save dq for use in updating vertex values - - - // Just limit non boundary edges so that we can reconstruct a linear function - // FIXME Problem with stability on edges - //if (neighbours[k3+i] >= 0) { - r = 1.0; - - if (dq > 0.0) r = (qmax - qc)/dq; - if (dq < 0.0) r = (qmin - qc)/dq; - - phi = min( min(r*beta, 1.0), phi); - // } - - // - /* if (neighbours[k3+i] < 0) { */ - /* r = 1.0; */ - - /* if (dq > 0.0 && (sign == -1.0 || sign == 0.0 )) r = (0.0 - qc)/dq; */ - /* if (dq < 0.0 && (sign == 1.0 || sign == 0.0 )) r = (0.0 - qc)/dq; */ - - /* phi = min( min(r*beta, 1.0), phi); */ - /* } */ - - } - - //Update gradient, vertex and edge values using phi limiter - x_gradient[k] = x_gradient[k]*phi; - y_gradient[k] = y_gradient[k]*phi; - - edge_values[k3+0] = qc + phi*dqa[0]; - edge_values[k3+1] = qc + phi*dqa[1]; - edge_values[k3+2] = qc + phi*dqa[2]; - - vertex_values[k3+0] = edge_values[k3+1] + edge_values[k3+2] - edge_values[k3+0]; - vertex_values[k3+1] = edge_values[k3+2] + edge_values[k3+0] - edge_values[k3+1]; - vertex_values[k3+2] = edge_values[k3+0] + edge_values[k3+1] - edge_values[k3+2]; - - } - - return 0; -} - - -int _limit_edges_by_neighbour(keyint N, double beta, - double* centroid_values, - double* vertex_values, - double* edge_values, - long* neighbours) { - - keyint i, k, k2, k3, k6; - keyint n; - double qmin, qmax, qn, qc; - double dq, dqa[3], phi, r; - - for (k=0; k= 0) qn = centroid_values[n]; //Neighbour's centroid value - - qmin = min(qc, qn); - qmax = max(qc, qn); - - r = 1.0; - - if (dq > 0.0) r = (qmax - qc)/dq; - if (dq < 0.0) r = (qmin - qc)/dq; - - phi = min( min(r*beta, 1.0), phi); - - } - - - //Update edge and vertex values using phi limiter - edge_values[k3+0] = qc + phi*dqa[0]; - edge_values[k3+1] = qc + phi*dqa[1]; - edge_values[k3+2] = qc + phi*dqa[2]; - - vertex_values[k3+0] = edge_values[k3+1] + edge_values[k3+2] - edge_values[k3+0]; - vertex_values[k3+1] = edge_values[k3+2] + edge_values[k3+0] - edge_values[k3+1]; - vertex_values[k3+2] = edge_values[k3+0] + edge_values[k3+1] - edge_values[k3+2]; - - } - - return 0; -} - - -int _limit_gradient_by_neighbour(keyint N, double beta, - double* centroid_values, - double* vertex_values, - double* edge_values, - double* x_gradient, - double* y_gradient, - long* neighbours) { - - keyint i, k, k2, k3, k6; - keyint n; - double qmin, qmax, qn, qc; - double dq, dqa[3], phi, r; - - for (k=0; k= 0) { - qn = centroid_values[n]; //Neighbour's centroid value - - qmin = min(qc, qn); - qmax = max(qc, qn); - - r = 1.0; - - if (dq > 0.0) r = (qmax - qc)/dq; - if (dq < 0.0) r = (qmin - qc)/dq; - - phi = min( min(r*beta, 1.0), phi); - } - } - - - //Update edge and vertex values using phi limiter - edge_values[k3+0] = qc + phi*dqa[0]; - edge_values[k3+1] = qc + phi*dqa[1]; - edge_values[k3+2] = qc + phi*dqa[2]; - - vertex_values[k3+0] = edge_values[k3+1] + edge_values[k3+2] - edge_values[k3+0]; - vertex_values[k3+1] = edge_values[k3+2] + edge_values[k3+0] - edge_values[k3+1]; - vertex_values[k3+2] = edge_values[k3+0] + edge_values[k3+1] - edge_values[k3+2]; - - } - - return 0; -} - -int _bound_vertices_below_by_constant(keyint N, double bound, - double* centroid_values, - double* vertex_values, - double* edge_values, - double* x_gradient, - double* y_gradient) { - - keyint i, k, k2, k3, k6; - double qmin, qc; - double dq, dqa[3], phi, r; - - for (k=0; k= 0) { - qn = qc[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]); - } - } - - return 0; - - -} - - - diff --git a/anuga/abstract_2d_finite_volumes/quantity_ext.c b/anuga/abstract_2d_finite_volumes/quantity_ext.c new file mode 100644 index 000000000..2c8a7f937 --- /dev/null +++ b/anuga/abstract_2d_finite_volumes/quantity_ext.c @@ -0,0 +1,2484 @@ +// 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 "numpy/arrayobject.h" +#include "math.h" + +//Shared code snippets +#include "util_ext.h" + +typedef long keyint; + +//------------------------------------------- +// Low level routines (called from wrappers) +//------------------------------------------ + +int _compute_gradients(keyint N, + double* centroids, + double* centroid_values, + long* number_of_boundaries, + long* surrogate_neighbours, + double* a, + double* b){ + + keyint i, k, k0, k1, k2, index3; + double x0, x1, x2, y0, y1, y2, q0, q1, q2; //, det; + + + for (k=0; k 0.0) r = (qmax - qc)/dq; + if (dq < 0.0) r = (qmin - qc)/dq; + + phi[k] = min( min(r*beta, 1.0), phi[k]); + + } + + + + //Update gradient, edge and vertex values using phi limiter + x_gradient[k] = x_gradient[k]*phi[k]; + y_gradient[k] = y_gradient[k]*phi[k]; + + edge_values[k3+0] = qc + phi[k]*dqa[0]; + edge_values[k3+1] = qc + phi[k]*dqa[1]; + edge_values[k3+2] = qc + phi[k]*dqa[2]; + + + vertex_values[k3+0] = edge_values[k3+1] + edge_values[k3+2] - edge_values[k3+0]; + vertex_values[k3+1] = edge_values[k3+2] + edge_values[k3+0] - edge_values[k3+1]; + vertex_values[k3+2] = edge_values[k3+0] + edge_values[k3+1] - edge_values[k3+2]; + + + } + + return 0; + +} + + + + +int _limit_vertices_by_all_neighbours(keyint N, double beta, + double* centroid_values, + double* vertex_values, + double* edge_values, + long* neighbours, + double* x_gradient, + double* y_gradient) { + + + keyint i, k, k2, k3, k6; + keyint n; + double qmin, qmax, qn, qc; + double dq, dqa[3], phi, r; + + for (k=0; k= 0) { + qn = centroid_values[n]; //Neighbour's centroid value + + qmin = min(qmin, qn); + qmax = max(qmax, qn); + } + } + + phi = 1.0; + for (i=0; i<3; i++) { + r = 1.0; + + dq = vertex_values[k3+i] - qc; //Delta between vertex and centroid values + dqa[i] = dq; //Save dq for use in updating vertex values + + if (dq > 0.0) r = (qmax - qc)/dq; + if (dq < 0.0) r = (qmin - qc)/dq; + + + phi = min( min(r*beta, 1.0), phi); + } + + //Update gradient, vertex and edge values using phi limiter + x_gradient[k] = x_gradient[k]*phi; + y_gradient[k] = y_gradient[k]*phi; + + vertex_values[k3+0] = qc + phi*dqa[0]; + vertex_values[k3+1] = qc + phi*dqa[1]; + vertex_values[k3+2] = qc + phi*dqa[2]; + + edge_values[k3+0] = 0.5*(vertex_values[k3+1] + vertex_values[k3+2]); + edge_values[k3+1] = 0.5*(vertex_values[k3+2] + vertex_values[k3+0]); + edge_values[k3+2] = 0.5*(vertex_values[k3+0] + vertex_values[k3+1]); + + } + + return 0; +} + + + + +int _limit_edges_by_all_neighbours(keyint N, double beta, + double* centroid_values, + double* vertex_values, + double* edge_values, + long* neighbours, + double* x_gradient, + double* y_gradient) { + + keyint i, k, k2, k3, k6; + keyint n; + double qmin, qmax, qn, qc, sign; + double dq, dqa[3], phi, r; + + for (k=0; k= 0) { + qn = centroid_values[n]; //Neighbour's centroid value + + qmin = min(qmin, qn); + qmax = max(qmax, qn); + } + } + + sign = 0.0; + if (qmin > 0.0) { + sign = 1.0; + } else if (qmax < 0) { + sign = -1.0; + } + + phi = 1.0; + for (i=0; i<3; i++) { + dq = edge_values[k3+i] - qc; //Delta between edge and centroid values + dqa[i] = dq; //Save dq for use in updating vertex values + + + // Just limit non boundary edges so that we can reconstruct a linear function + // FIXME Problem with stability on edges + //if (neighbours[k3+i] >= 0) { + r = 1.0; + + if (dq > 0.0) r = (qmax - qc)/dq; + if (dq < 0.0) r = (qmin - qc)/dq; + + phi = min( min(r*beta, 1.0), phi); + // } + + // + /* if (neighbours[k3+i] < 0) { */ + /* r = 1.0; */ + + /* if (dq > 0.0 && (sign == -1.0 || sign == 0.0 )) r = (0.0 - qc)/dq; */ + /* if (dq < 0.0 && (sign == 1.0 || sign == 0.0 )) r = (0.0 - qc)/dq; */ + + /* phi = min( min(r*beta, 1.0), phi); */ + /* } */ + + } + + //Update gradient, vertex and edge values using phi limiter + x_gradient[k] = x_gradient[k]*phi; + y_gradient[k] = y_gradient[k]*phi; + + edge_values[k3+0] = qc + phi*dqa[0]; + edge_values[k3+1] = qc + phi*dqa[1]; + edge_values[k3+2] = qc + phi*dqa[2]; + + vertex_values[k3+0] = edge_values[k3+1] + edge_values[k3+2] - edge_values[k3+0]; + vertex_values[k3+1] = edge_values[k3+2] + edge_values[k3+0] - edge_values[k3+1]; + vertex_values[k3+2] = edge_values[k3+0] + edge_values[k3+1] - edge_values[k3+2]; + + } + + return 0; +} + + +int _limit_edges_by_neighbour(keyint N, double beta, + double* centroid_values, + double* vertex_values, + double* edge_values, + long* neighbours) { + + keyint i, k, k2, k3, k6; + keyint n; + double qmin, qmax, qn, qc; + double dq, dqa[3], phi, r; + + for (k=0; k= 0) qn = centroid_values[n]; //Neighbour's centroid value + + qmin = min(qc, qn); + qmax = max(qc, qn); + + r = 1.0; + + if (dq > 0.0) r = (qmax - qc)/dq; + if (dq < 0.0) r = (qmin - qc)/dq; + + phi = min( min(r*beta, 1.0), phi); + + } + + + //Update edge and vertex values using phi limiter + edge_values[k3+0] = qc + phi*dqa[0]; + edge_values[k3+1] = qc + phi*dqa[1]; + edge_values[k3+2] = qc + phi*dqa[2]; + + vertex_values[k3+0] = edge_values[k3+1] + edge_values[k3+2] - edge_values[k3+0]; + vertex_values[k3+1] = edge_values[k3+2] + edge_values[k3+0] - edge_values[k3+1]; + vertex_values[k3+2] = edge_values[k3+0] + edge_values[k3+1] - edge_values[k3+2]; + + } + + return 0; +} + + +int _limit_gradient_by_neighbour(keyint N, double beta, + double* centroid_values, + double* vertex_values, + double* edge_values, + double* x_gradient, + double* y_gradient, + long* neighbours) { + + keyint i, k, k2, k3, k6; + keyint n; + double qmin, qmax, qn, qc; + double dq, dqa[3], phi, r; + + for (k=0; k= 0) { + qn = centroid_values[n]; //Neighbour's centroid value + + qmin = min(qc, qn); + qmax = max(qc, qn); + + r = 1.0; + + if (dq > 0.0) r = (qmax - qc)/dq; + if (dq < 0.0) r = (qmin - qc)/dq; + + phi = min( min(r*beta, 1.0), phi); + } + } + + + //Update edge and vertex values using phi limiter + edge_values[k3+0] = qc + phi*dqa[0]; + edge_values[k3+1] = qc + phi*dqa[1]; + edge_values[k3+2] = qc + phi*dqa[2]; + + vertex_values[k3+0] = edge_values[k3+1] + edge_values[k3+2] - edge_values[k3+0]; + vertex_values[k3+1] = edge_values[k3+2] + edge_values[k3+0] - edge_values[k3+1]; + vertex_values[k3+2] = edge_values[k3+0] + edge_values[k3+1] - edge_values[k3+2]; + + } + + return 0; +} + +int _bound_vertices_below_by_constant(keyint N, double bound, + double* centroid_values, + double* vertex_values, + double* edge_values, + double* x_gradient, + double* y_gradient) { + + keyint i, k, k2, k3, k6; + double qmin, qc; + double dq, dqa[3], phi, r; + + 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, + "quantity_ext.c: update, division by zero 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; + + keyint N; + int 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; + keyint N; + int 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 *set_vertex_values_c(PyObject *self, PyObject *args) { + + PyObject *quantity,*domain,*mesh; + PyArrayObject *vertex_values, *node_index, *A, *vertices; + PyArrayObject *number_of_triangles_per_node, *vertex_value_indices; + + keyint N; + int err; + keyint num_verts; + + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "OOO", &quantity, &vertices, &A)) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: set_vertex_values_c could not parse input"); + return NULL; + } + + domain = PyObject_GetAttrString(quantity, "domain"); + if (!domain) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: set_vertex_values_c could not obtain domain object from quantity"); + return NULL; + } + + mesh = PyObject_GetAttrString(domain, "mesh"); + if (!mesh) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: set_vertex_values_c could not obtain mesh object from domain"); + return NULL; + } + + vertex_values = get_consecutive_array(quantity, "vertex_values"); + node_index = get_consecutive_array(mesh,"node_index"); + number_of_triangles_per_node = get_consecutive_array(mesh,"number_of_triangles_per_node"); + vertex_value_indices = get_consecutive_array(mesh,"vertex_value_indices"); + + CHECK_C_CONTIG(vertices); + + CHECK_C_CONTIG(A); + + //N = centroid_values -> dimensions[0]; + + num_verts = vertices->dimensions[0]; + + err = _set_vertex_values_c(num_verts, + (long*) vertices->data, + (long*) node_index->data, + (long*) number_of_triangles_per_node->data, + (long*) vertex_value_indices->data, + (double*) vertex_values->data, + (double*) A->data); + + + // Release and return + Py_DECREF(vertex_values); + Py_DECREF(node_index); + Py_DECREF(number_of_triangles_per_node); + Py_DECREF(vertex_value_indices); + + return Py_BuildValue(""); +} + +PyObject *interpolate(PyObject *self, PyObject *args) { + // + //Compute edge and centroid values from vertex values using linear interpolation + // + + PyObject *quantity; + PyArrayObject *vertex_values, *edge_values, *centroid_values; + + keyint N;int err; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "O", &quantity)) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: interpolate could not parse input"); + return NULL; + } + + vertex_values = get_consecutive_array(quantity, "vertex_values"); + edge_values = get_consecutive_array(quantity, "edge_values"); + centroid_values = get_consecutive_array(quantity, "centroid_values"); + + N = vertex_values -> dimensions[0]; + + err = _interpolate(N, + (double*) vertex_values -> data, + (double*) edge_values -> data, + (double*) centroid_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); + Py_DECREF(centroid_values); + + return Py_BuildValue(""); + +} + + +PyObject *interpolate_from_vertices_to_edges(PyObject *self, PyObject *args) { + // + //Compute edge values from vertex values using linear interpolation + // + + PyObject *quantity; + PyArrayObject *vertex_values, *edge_values; + + keyint N;int 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_from_vertices_to_edges(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 *interpolate_from_edges_to_vertices(PyObject *self, PyObject *args) { + // + //Compute vertex values from edge values using linear interpolation + // + + PyObject *quantity; + PyArrayObject *vertex_values, *edge_values; + + keyint N;int err; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "O", &quantity)) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: interpolate_from_edges_to_vertices 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_from_edges_to_vertices(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; + + + keyint N;int 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; + } + + // check that numpy array objects arrays are C contiguous memory + CHECK_C_CONTIG(vertex_value_indices); + CHECK_C_CONTIG(number_of_triangles_per_node); + CHECK_C_CONTIG(vertex_values); + CHECK_C_CONTIG(A); + + 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 *average_centroid_values(PyObject *self, PyObject *args) { + + PyArrayObject + *vertex_value_indices, + *number_of_triangles_per_node, + *centroid_values, + *A; + + + keyint N;int err; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "OOOO", + &vertex_value_indices, + &number_of_triangles_per_node, + ¢roid_values, + &A)) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: average_centroid_values could not parse input"); + return NULL; + } + + // check that numpy array objects arrays are C contiguous memory + CHECK_C_CONTIG(vertex_value_indices); + CHECK_C_CONTIG(number_of_triangles_per_node); + CHECK_C_CONTIG(centroid_values); + CHECK_C_CONTIG(A); + + N = vertex_value_indices -> dimensions[0]; + // printf("Got parameters, N=%d\n", N); + err = _average_centroid_values(N, + (long*) vertex_value_indices -> data, + (long*) number_of_triangles_per_node -> data, + (double*) centroid_values -> data, + (double*) A -> data); + + //printf("Error %d", err); + if (err != 0) { + PyErr_SetString(PyExc_RuntimeError, + "average_centroid_values could not be computed"); + return NULL; + } + + return Py_BuildValue(""); +} + + +PyObject *extrapolate_from_gradient(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 + *edge_values, //Values at edges + *number_of_boundaries, //Number of boundaries for each triangle + *surrogate_neighbours, //True neighbours or - if one missing - self + *x_gradient, //x gradient + *y_gradient; //y gradient + + //keyint N;int err; + //int dimensions[1]; + keyint N;int err; + //double *a, *b; //Gradients + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "O", &quantity)) { + PyErr_SetString(PyExc_RuntimeError, + "extrapolate_gradient could not parse input"); + return NULL; + } + + domain = PyObject_GetAttrString(quantity, "domain"); + if (!domain) { + PyErr_SetString(PyExc_RuntimeError, + "extrapolate_gradient 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"); + edge_values = get_consecutive_array(quantity, "edge_values"); + x_gradient = get_consecutive_array(quantity, "x_gradient"); + y_gradient = get_consecutive_array(quantity, "y_gradient"); + + N = centroid_values -> dimensions[0]; + + // Release + Py_DECREF(domain); + + err = _extrapolate_from_gradient(N, + (double*) centroids -> data, + (double*) centroid_values -> data, + (double*) vertex_coordinates -> data, + (double*) vertex_values -> data, + (double*) edge_values -> data, + (double*) x_gradient -> data, + (double*) y_gradient -> 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(edge_values); + Py_DECREF(x_gradient); + Py_DECREF(y_gradient); + + return Py_BuildValue(""); +} + + + +PyObject *compute_local_gradients(PyObject *self, PyObject *args) { + + PyObject *quantity, *domain; + PyArrayObject + *vertex_coordinates, //Coordinates at vertices + *vertex_values, //Values at vertices + *x_gradient, //x gradient + *y_gradient; //y gradient + + //keyint N;int err; + //int dimensions[1]; + keyint N;int err; + //double *a, *b; //Gradients + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "O", &quantity)) { + PyErr_SetString(PyExc_RuntimeError, + "compute_local_gradient could not parse input"); + return NULL; + } + + domain = PyObject_GetAttrString(quantity, "domain"); + if (!domain) { + PyErr_SetString(PyExc_RuntimeError, + "compute_local_gradient could not obtain domain object from quantity"); + return NULL; + } + + // Get pertinent variables + vertex_coordinates = get_consecutive_array(domain, "vertex_coordinates"); + vertex_values = get_consecutive_array(quantity, "vertex_values"); + x_gradient = get_consecutive_array(quantity, "x_gradient"); + y_gradient = get_consecutive_array(quantity, "y_gradient"); + + N = vertex_values -> dimensions[0]; + + // Release + Py_DECREF(domain); + + err = _compute_local_gradients(N, + (double*) vertex_coordinates -> data, + (double*) vertex_values -> data, + (double*) x_gradient -> data, + (double*) y_gradient -> data); + + + if (err != 0) { + PyErr_SetString(PyExc_RuntimeError, + "Internal function _compute_local_gradient failed"); + return NULL; + } + + + + // Release + Py_DECREF(vertex_coordinates); + Py_DECREF(vertex_values); + Py_DECREF(x_gradient); + Py_DECREF(y_gradient); + + return Py_BuildValue(""); +} + + +PyObject *extrapolate_second_order_and_limit_by_edge(PyObject *self, PyObject *args) { + /* Compute edge values using second order approximation and limit values + so that edge values are limited by the two corresponding centroid values + + Python Call: + extrapolate_second_order_and_limit(domain,quantity,beta) + */ + + PyObject *quantity, *domain; + + PyArrayObject + *domain_centroids, //Coordinates at centroids + *domain_vertex_coordinates, //Coordinates at vertices + *domain_number_of_boundaries, //Number of boundaries for each triangle + *domain_surrogate_neighbours, //True neighbours or - if one missing - self + *domain_neighbours, //True neighbours, or if negative a link to boundary + + *quantity_centroid_values, //Values at centroids + *quantity_vertex_values, //Values at vertices + *quantity_edge_values, //Values at edges + *quantity_phi, //limiter phi values + *quantity_x_gradient, //x gradient + *quantity_y_gradient; //y gradient + + + // Local variables + keyint ntri; + double beta; + int err; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "O",&quantity)) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: extrapolate_second_order_and_limit_by_edge could not parse input"); + return NULL; + } + + domain = PyObject_GetAttrString(quantity, "domain"); + if (!domain) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: extrapolate_second_order_and_limit_by_edge could not obtain domain object from quantity"); + return NULL; + } + + + // Get pertinent variables + domain_centroids = get_consecutive_array(domain, "centroid_coordinates"); + domain_surrogate_neighbours = get_consecutive_array(domain, "surrogate_neighbours"); + domain_number_of_boundaries = get_consecutive_array(domain, "number_of_boundaries"); + domain_vertex_coordinates = get_consecutive_array(domain, "vertex_coordinates"); + domain_neighbours = get_consecutive_array(domain, "neighbours"); + + quantity_centroid_values = get_consecutive_array(quantity, "centroid_values"); + quantity_vertex_values = get_consecutive_array(quantity, "vertex_values"); + quantity_edge_values = get_consecutive_array(quantity, "edge_values"); + quantity_phi = get_consecutive_array(quantity, "phi"); + quantity_x_gradient = get_consecutive_array(quantity, "x_gradient"); + quantity_y_gradient = get_consecutive_array(quantity, "y_gradient"); + + beta = get_python_double(quantity,"beta"); + + ntri = quantity_centroid_values -> dimensions[0]; + + err = _compute_gradients(ntri, + (double*) domain_centroids -> data, + (double*) quantity_centroid_values -> data, + (long*) domain_number_of_boundaries -> data, + (long*) domain_surrogate_neighbours -> data, + (double*) quantity_x_gradient -> data, + (double*) quantity_y_gradient -> data); + + if (err != 0) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: Internal function _compute_gradient failed"); + return NULL; + } + + + err = _extrapolate_from_gradient(ntri, + (double*) domain_centroids -> data, + (double*) quantity_centroid_values -> data, + (double*) domain_vertex_coordinates -> data, + (double*) quantity_vertex_values -> data, + (double*) quantity_edge_values -> data, + (double*) quantity_x_gradient -> data, + (double*) quantity_y_gradient -> data); + + if (err != 0) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: Internal function _extrapolate_from_gradient failed"); + return NULL; + } + + + err = _limit_edges_by_all_neighbours(ntri, beta, + (double*) quantity_centroid_values -> data, + (double*) quantity_vertex_values -> data, + (double*) quantity_edge_values -> data, + (long*) domain_neighbours -> data, + (double*) quantity_x_gradient -> data, + (double*) quantity_y_gradient -> data); + + if (err != 0) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: Internal function _limit_edges_by_all_neighbours failed"); + return NULL; + } + + + // Release + Py_DECREF(domain); + Py_DECREF(domain_centroids); + Py_DECREF(domain_surrogate_neighbours); + Py_DECREF(domain_number_of_boundaries); + Py_DECREF(domain_vertex_coordinates); + + Py_DECREF(quantity_centroid_values); + Py_DECREF(quantity_vertex_values); + Py_DECREF(quantity_edge_values); + Py_DECREF(quantity_phi); + Py_DECREF(quantity_x_gradient); + Py_DECREF(quantity_y_gradient); + + return Py_BuildValue(""); +} + + +PyObject *extrapolate_second_order_and_limit_by_vertex(PyObject *self, PyObject *args) { + /* Compute edge values using second order approximation and limit values + so that edge values are limited by the two corresponding centroid values + + Python Call: + extrapolate_second_order_and_limit(domain,quantity,beta) + */ + + PyObject *quantity, *domain; + + PyArrayObject + *domain_centroids, //Coordinates at centroids + *domain_vertex_coordinates, //Coordinates at vertices + *domain_number_of_boundaries, //Number of boundaries for each triangle + *domain_surrogate_neighbours, //True neighbours or - if one missing - self + *domain_neighbours, //True neighbours, or if negative a link to boundary + + *quantity_centroid_values, //Values at centroids + *quantity_vertex_values, //Values at vertices + *quantity_edge_values, //Values at edges + *quantity_phi, //limiter phi values + *quantity_x_gradient, //x gradient + *quantity_y_gradient; //y gradient + + + // Local variables + keyint ntri; + double beta; + int err; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "O",&quantity)) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: extrapolate_second_order_and_limit could not parse input"); + return NULL; + } + + domain = PyObject_GetAttrString(quantity, "domain"); + if (!domain) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: extrapolate_second_order_and_limit could not obtain domain object from quantity"); + return NULL; + } + + + // Get pertinent variables + domain_centroids = get_consecutive_array(domain, "centroid_coordinates"); + domain_surrogate_neighbours = get_consecutive_array(domain, "surrogate_neighbours"); + domain_number_of_boundaries = get_consecutive_array(domain, "number_of_boundaries"); + domain_vertex_coordinates = get_consecutive_array(domain, "vertex_coordinates"); + domain_neighbours = get_consecutive_array(domain, "neighbours"); + + quantity_centroid_values = get_consecutive_array(quantity, "centroid_values"); + quantity_vertex_values = get_consecutive_array(quantity, "vertex_values"); + quantity_edge_values = get_consecutive_array(quantity, "edge_values"); + quantity_phi = get_consecutive_array(quantity, "phi"); + quantity_x_gradient = get_consecutive_array(quantity, "x_gradient"); + quantity_y_gradient = get_consecutive_array(quantity, "y_gradient"); + + beta = get_python_double(quantity,"beta"); + + ntri = quantity_centroid_values -> dimensions[0]; + + err = _compute_gradients(ntri, + (double*) domain_centroids -> data, + (double*) quantity_centroid_values -> data, + (long*) domain_number_of_boundaries -> data, + (long*) domain_surrogate_neighbours -> data, + (double*) quantity_x_gradient -> data, + (double*) quantity_y_gradient -> data); + + if (err != 0) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: Internal function _compute_gradient failed"); + return NULL; + } + + + err = _extrapolate_from_gradient(ntri, + (double*) domain_centroids -> data, + (double*) quantity_centroid_values -> data, + (double*) domain_vertex_coordinates -> data, + (double*) quantity_vertex_values -> data, + (double*) quantity_edge_values -> data, + (double*) quantity_x_gradient -> data, + (double*) quantity_y_gradient -> data); + + if (err != 0) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: Internal function _extrapolate_from_gradient failed"); + return NULL; + } + + + err = _limit_vertices_by_all_neighbours(ntri, beta, + (double*) quantity_centroid_values -> data, + (double*) quantity_vertex_values -> data, + (double*) quantity_edge_values -> data, + (long*) domain_neighbours -> data, + (double*) quantity_x_gradient -> data, + (double*) quantity_y_gradient -> data); + + if (err != 0) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: Internal function _limit_vertices_by_all_neighbours failed"); + return NULL; + } + + + // Release + Py_DECREF(domain_centroids); + Py_DECREF(domain_surrogate_neighbours); + Py_DECREF(domain_number_of_boundaries); + Py_DECREF(domain_vertex_coordinates); + + Py_DECREF(quantity_centroid_values); + Py_DECREF(quantity_vertex_values); + Py_DECREF(quantity_edge_values); + Py_DECREF(quantity_phi); + Py_DECREF(quantity_x_gradient); + Py_DECREF(quantity_y_gradient); + + return Py_BuildValue(""); +} + + + +PyObject *compute_gradients(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 + *edge_values, //Values at edges + *number_of_boundaries, //Number of boundaries for each triangle + *surrogate_neighbours, //True neighbours or - if one missing - self + *x_gradient, //x gradient + *y_gradient; //y gradient + + //keyint N;int err; + //int dimensions[1]; + keyint N;int err; + //double *a, *b; //Gradients + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "O", &quantity)) { + PyErr_SetString(PyExc_RuntimeError, + "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"); + vertex_coordinates = get_consecutive_array(domain, "vertex_coordinates"); + vertex_values = get_consecutive_array(quantity, "vertex_values"); + edge_values = get_consecutive_array(quantity, "edge_values"); + x_gradient = get_consecutive_array(quantity, "x_gradient"); + y_gradient = get_consecutive_array(quantity, "y_gradient"); + + N = centroid_values -> dimensions[0]; + + // Release + Py_DECREF(domain); + + + err = _compute_gradients(N, + (double*) centroids -> data, + (double*) centroid_values -> data, + (long*) number_of_boundaries -> data, + (long*) surrogate_neighbours -> data, + (double*) x_gradient -> data, + (double*) y_gradient -> 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); + Py_DECREF(vertex_coordinates); + Py_DECREF(vertex_values); + Py_DECREF(edge_values); + Py_DECREF(x_gradient); + Py_DECREF(y_gradient); + + return Py_BuildValue(""); +} + + + +PyObject *limit_old(PyObject *self, PyObject *args) { + //Limit slopes for each volume to eliminate artificial variance + //introduced by e.g. second order extrapolator + + //This is an unsophisticated limiter as it does not take into + //account dependencies among quantities. + + //precondition: + // vertex values are estimated from gradient + //postcondition: + // vertex values are updated + // + + PyObject *quantity, *domain, *Tmp; + PyArrayObject + *qv, //Conserved quantities at vertices + *qc, //Conserved quantities at centroids + *neighbours; + + keyint 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_old could not parse input"); + return NULL; + } + + domain = PyObject_GetAttrString(quantity, "domain"); + if (!domain) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: limit_old 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_old 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_old(N, beta_w, (double*) qc -> data, (double*) qv -> data, qmin, qmax); + + free(qmin); + free(qmax); + return Py_BuildValue(""); +} + + +PyObject *limit_vertices_by_all_neighbours(PyObject *self, PyObject *args) { + //Limit slopes for each volume to eliminate artificial variance + //introduced by e.g. second order extrapolator + + //This is an unsophisticated limiter as it does not take into + //account dependencies among quantities. + + //precondition: + // vertex values are estimated from gradient + //postcondition: + // vertex and edge values are updated + // + + PyObject *quantity, *domain, *Tmp; + PyArrayObject + *vertex_values, //Conserved quantities at vertices + *centroid_values, //Conserved quantities at centroids + *edge_values, //Conserved quantities at edges + *neighbours, + *x_gradient, + *y_gradient; + + double beta_w; //Safety factor + keyint N;int err; + + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "O", &quantity)) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: limit_by_vertex could not parse input"); + return NULL; + } + + domain = PyObject_GetAttrString(quantity, "domain"); + if (!domain) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: limit_by_vertex could not obtain domain object from quantity"); + + return NULL; + } + + // Get safety factor beta_w + Tmp = PyObject_GetAttrString(domain, "beta_w"); + if (!Tmp) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: limit_by_vertex could not obtain beta_w object from domain"); + + return NULL; + } + + + // Get pertinent variables + neighbours = get_consecutive_array(domain, "neighbours"); + centroid_values = get_consecutive_array(quantity, "centroid_values"); + vertex_values = get_consecutive_array(quantity, "vertex_values"); + edge_values = get_consecutive_array(quantity, "edge_values"); + x_gradient = get_consecutive_array(quantity, "x_gradient"); + y_gradient = get_consecutive_array(quantity, "y_gradient"); + beta_w = get_python_double(domain,"beta_w"); + + + + N = centroid_values -> dimensions[0]; + + err = _limit_vertices_by_all_neighbours(N, beta_w, + (double*) centroid_values -> data, + (double*) vertex_values -> data, + (double*) edge_values -> data, + (long*) neighbours -> data, + (double*) x_gradient -> data, + (double*) y_gradient -> data); + + + + if (err != 0) { + PyErr_SetString(PyExc_RuntimeError, + "Internal function _limit_by_vertex failed"); + return NULL; + } + + + // Release + Py_DECREF(neighbours); + Py_DECREF(centroid_values); + Py_DECREF(vertex_values); + Py_DECREF(edge_values); + Py_DECREF(x_gradient); + Py_DECREF(y_gradient); + Py_DECREF(Tmp); + + + return Py_BuildValue(""); +} + + + +PyObject *limit_edges_by_all_neighbours(PyObject *self, PyObject *args) { + //Limit slopes for each volume to eliminate artificial variance + //introduced by e.g. second order extrapolator + + //This is an unsophisticated limiter as it does not take into + //account dependencies among quantities. + + //precondition: + // vertex values are estimated from gradient + //postcondition: + // vertex and edge values are updated + // + + PyObject *quantity, *domain; + PyArrayObject + *vertex_values, //Conserved quantities at vertices + *centroid_values, //Conserved quantities at centroids + *edge_values, //Conserved quantities at edges + *x_gradient, + *y_gradient, + *neighbours; + + double beta_w; //Safety factor + keyint N;int err; + + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "O", &quantity)) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: limit_edges_by_all_neighbours could not parse input"); + return NULL; + } + + domain = get_python_object(quantity, "domain"); + + + // Get pertinent variables + neighbours = get_consecutive_array(domain, "neighbours"); + centroid_values = get_consecutive_array(quantity, "centroid_values"); + vertex_values = get_consecutive_array(quantity, "vertex_values"); + edge_values = get_consecutive_array(quantity, "edge_values"); + x_gradient = get_consecutive_array(quantity, "x_gradient"); + y_gradient = get_consecutive_array(quantity, "y_gradient"); + beta_w = get_python_double(domain,"beta_w"); + + + + N = centroid_values -> dimensions[0]; + + err = _limit_edges_by_all_neighbours(N, beta_w, + (double*) centroid_values -> data, + (double*) vertex_values -> data, + (double*) edge_values -> data, + (long*) neighbours -> data, + (double*) x_gradient -> data, + (double*) y_gradient -> data); + + if (err != 0) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ect.c: limit_edges_by_all_neighbours internal function _limit_edges_by_all_neighbours failed"); + return NULL; + } + + + // Release + Py_DECREF(neighbours); + Py_DECREF(centroid_values); + Py_DECREF(vertex_values); + Py_DECREF(edge_values); + Py_DECREF(x_gradient); + Py_DECREF(y_gradient); + + + + return Py_BuildValue(""); +} + +PyObject *bound_vertices_below_by_constant(PyObject *self, PyObject *args) { + //Bound a quantity below by a contant (useful for ensuring positivity + //precondition: + // vertex values are already calulated, gradient consistent + //postcondition: + // gradient, vertex and edge values are updated + // + + PyObject *quantity, *domain; + PyArrayObject + *vertex_values, //Conserved quantities at vertices + *centroid_values, //Conserved quantities at centroids + *edge_values, //Conserved quantities at edges + *x_gradient, + *y_gradient; + + double bound; //Safety factor + keyint N;int err; + + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "Od", &quantity, &bound)) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: bound_vertices_below_by_constant could not parse input"); + return NULL; + } + + domain = get_python_object(quantity, "domain"); + + // Get pertinent variables + centroid_values = get_consecutive_array(quantity, "centroid_values"); + vertex_values = get_consecutive_array(quantity, "vertex_values"); + edge_values = get_consecutive_array(quantity, "edge_values"); + x_gradient = get_consecutive_array(quantity, "x_gradient"); + y_gradient = get_consecutive_array(quantity, "y_gradient"); + + + + + N = centroid_values -> dimensions[0]; + + err = _bound_vertices_below_by_constant(N, bound, + (double*) centroid_values -> data, + (double*) vertex_values -> data, + (double*) edge_values -> data, + (double*) x_gradient -> data, + (double*) y_gradient -> data); + + if (err != 0) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ect.c: bound_vertices_below_by_constant internal function _bound_vertices_below_by_constant failed"); + return NULL; + } + + + // Release + Py_DECREF(centroid_values); + Py_DECREF(vertex_values); + Py_DECREF(edge_values); + Py_DECREF(x_gradient); + Py_DECREF(y_gradient); + + + + return Py_BuildValue(""); +} + + +PyObject *bound_vertices_below_by_quantity(PyObject *self, PyObject *args) { + //Bound a quantity below by a contant (useful for ensuring positivity + //precondition: + // vertex values are already calulated, gradient consistent + //postcondition: + // gradient, vertex and edge values are updated + // + + PyObject *quantity, *bounding_quantity, *domain; + PyArrayObject + *vertex_values, //Conserved quantities at vertices + *centroid_values, //Conserved quantities at centroids + *edge_values, //Conserved quantities at edges + *x_gradient, + *y_gradient, + *bound_vertex_values; + + keyint N;int err; + + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "OO", &quantity, &bounding_quantity)) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: bound_vertices_below_by_quantity could not parse input"); + return NULL; + } + + domain = get_python_object(quantity, "domain"); + + // Get pertinent variables + centroid_values = get_consecutive_array(quantity, "centroid_values"); + vertex_values = get_consecutive_array(quantity, "vertex_values"); + edge_values = get_consecutive_array(quantity, "edge_values"); + x_gradient = get_consecutive_array(quantity, "x_gradient"); + y_gradient = get_consecutive_array(quantity, "y_gradient"); + bound_vertex_values = get_consecutive_array(bounding_quantity, "vertex_values"); + + + + Py_DECREF(domain); + + N = centroid_values -> dimensions[0]; + + err = _bound_vertices_below_by_quantity(N, + (double*) bound_vertex_values -> data, + (double*) centroid_values -> data, + (double*) vertex_values -> data, + (double*) edge_values -> data, + (double*) x_gradient -> data, + (double*) y_gradient -> data); + + if (err != 0) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ect.c: bound_vertices_below_by_quantity internal function _bound_vertices_below_by_quantity failed"); + return NULL; + } + + + // Release + Py_DECREF(centroid_values); + Py_DECREF(vertex_values); + Py_DECREF(edge_values); + Py_DECREF(x_gradient); + Py_DECREF(y_gradient); + Py_DECREF(bound_vertex_values); + + + + return Py_BuildValue(""); +} + + +PyObject *limit_edges_by_neighbour(PyObject *self, PyObject *args) { + //Limit slopes for each volume to eliminate artificial variance + //introduced by e.g. second order extrapolator + + //This is an unsophisticated limiter as it does not take into + //account dependencies among quantities. + + //precondition: + // vertex values are estimated from gradient + //postcondition: + // vertex and edge values are updated + // + + PyObject *quantity, *domain, *Tmp; + PyArrayObject + *vertex_values, //Conserved quantities at vertices + *centroid_values, //Conserved quantities at centroids + *edge_values, //Conserved quantities at edges + *neighbours; + + double beta_w; //Safety factor + keyint N;int err; + + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "O", &quantity)) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: limit_edges_by_neighbour could not parse input"); + return NULL; + } + + domain = PyObject_GetAttrString(quantity, "domain"); + if (!domain) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: limit_edges_by_neighbour could not obtain domain object from quantity"); + + return NULL; + } + + // Get safety factor beta_w + Tmp = PyObject_GetAttrString(domain, "beta_w"); + if (!Tmp) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: limit_by_vertex could not obtain beta_w object from domain"); + + return NULL; + } + + + // Get pertinent variables + neighbours = get_consecutive_array(domain, "neighbours"); + centroid_values = get_consecutive_array(quantity, "centroid_values"); + vertex_values = get_consecutive_array(quantity, "vertex_values"); + edge_values = get_consecutive_array(quantity, "edge_values"); + beta_w = PyFloat_AsDouble(Tmp); + + + N = centroid_values -> dimensions[0]; + + err = _limit_edges_by_neighbour(N, beta_w, + (double*) centroid_values -> data, + (double*) vertex_values -> data, + (double*) edge_values -> data, + (long*) neighbours -> data); + + if (err != 0) { + PyErr_SetString(PyExc_RuntimeError, + "Internal function _limit_by_vertex failed"); + return NULL; + } + + + // Release + Py_DECREF(domain); + Py_DECREF(neighbours); + Py_DECREF(centroid_values); + Py_DECREF(vertex_values); + Py_DECREF(edge_values); + Py_DECREF(Tmp); + + + return Py_BuildValue(""); +} + + +PyObject *limit_gradient_by_neighbour(PyObject *self, PyObject *args) { + //Limit slopes for each volume to eliminate artificial variance + //introduced by e.g. second order extrapolator + + //This is an unsophisticated limiter as it does not take into + //account dependencies among quantities. + + //precondition: + // vertex values are estimated from gradient + //postcondition: + // vertex and edge values are updated + // + + PyObject *quantity, *domain, *Tmp; + PyArrayObject + *vertex_values, //Conserved quantities at vertices + *centroid_values, //Conserved quantities at centroids + *edge_values, //Conserved quantities at edges + *x_gradient, + *y_gradient, + *neighbours; + + double beta_w; //Safety factor + keyint N;int err; + + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "O", &quantity)) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: limit_gradient_by_neighbour could not parse input"); + return NULL; + } + + domain = PyObject_GetAttrString(quantity, "domain"); + if (!domain) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: limit_gradient_by_neighbour could not obtain domain object from quantity"); + + return NULL; + } + + // Get safety factor beta_w + Tmp = PyObject_GetAttrString(domain, "beta_w"); + if (!Tmp) { + PyErr_SetString(PyExc_RuntimeError, + "quantity_ext.c: limit_gradient_by_neighbour could not obtain beta_w object from domain"); + + return NULL; + } + + + // Get pertinent variables + neighbours = get_consecutive_array(domain, "neighbours"); + centroid_values = get_consecutive_array(quantity, "centroid_values"); + vertex_values = get_consecutive_array(quantity, "vertex_values"); + edge_values = get_consecutive_array(quantity, "edge_values"); + x_gradient = get_consecutive_array(quantity, "x_gradient"); + y_gradient = get_consecutive_array(quantity, "y_gradient"); + + beta_w = PyFloat_AsDouble(Tmp); + + + N = centroid_values -> dimensions[0]; + + err = _limit_gradient_by_neighbour(N, beta_w, + (double*) centroid_values -> data, + (double*) vertex_values -> data, + (double*) edge_values -> data, + (double*) x_gradient -> data, + (double*) y_gradient -> data, + (long*) neighbours -> data); + + if (err != 0) { + PyErr_SetString(PyExc_RuntimeError, + "Internal function _limit_gradient_by_neighbour failed"); + return NULL; + } + + + // Release + Py_DECREF(neighbours); + Py_DECREF(centroid_values); + Py_DECREF(vertex_values); + Py_DECREF(edge_values); + Py_DECREF(x_gradient); + Py_DECREF(y_gradient); + Py_DECREF(Tmp); + + + return Py_BuildValue(""); +} + + +// Method table for python module +static struct PyMethodDef MethodTable[] = { + {"limit_old", limit_old, METH_VARARGS, "Print out"}, + {"limit_vertices_by_all_neighbours", limit_vertices_by_all_neighbours, METH_VARARGS, "Print out"}, + {"limit_edges_by_all_neighbours", limit_edges_by_all_neighbours, METH_VARARGS, "Print out"}, + {"limit_edges_by_neighbour", limit_edges_by_neighbour, METH_VARARGS, "Print out"}, + {"limit_gradient_by_neighbour", limit_gradient_by_neighbour, METH_VARARGS, "Print out"}, + {"bound_vertices_below_by_constant", bound_vertices_below_by_constant, METH_VARARGS, "Print out"}, + {"bound_vertices_below_by_quantity", bound_vertices_below_by_quantity, 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"}, + {"compute_local_gradients", compute_gradients, METH_VARARGS, "Print out"}, + {"extrapolate_from_gradient", extrapolate_from_gradient, + METH_VARARGS, "Print out"}, + {"extrapolate_second_order_and_limit_by_edge", extrapolate_second_order_and_limit_by_edge, + METH_VARARGS, "Print out"}, + {"extrapolate_second_order_and_limit_by_vertex", extrapolate_second_order_and_limit_by_vertex, + METH_VARARGS, "Print out"}, + {"interpolate_from_vertices_to_edges", + interpolate_from_vertices_to_edges, + METH_VARARGS, "Print out"}, + {"interpolate_from_edges_to_vertices", + interpolate_from_edges_to_vertices, + METH_VARARGS, "Print out"}, + {"interpolate", interpolate, METH_VARARGS, "Print out"}, + {"average_vertex_values", average_vertex_values, METH_VARARGS, "Print out"}, + {"average_centroid_values", average_centroid_values, METH_VARARGS, "Print out"}, + {"set_vertex_values_c", set_vertex_values_c, 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 +} diff --git a/anuga/abstract_2d_finite_volumes/quantity_ext.pyx b/anuga/abstract_2d_finite_volumes/quantity_ext.pyx deleted file mode 100644 index 79a640a00..000000000 --- a/anuga/abstract_2d_finite_volumes/quantity_ext.pyx +++ /dev/null @@ -1,745 +0,0 @@ -#cython: wraparound=False, boundscheck=False, cdivision=True, profile=False, nonecheck=False, overflowcheck=False, cdivision_warnings=False, unraisable_tracebacks=False -import cython - -# import both numpy and the Cython declarations for numpy -import numpy as np -cimport numpy as np - -ctypedef long keyint - -# declare the interface to the C code -cdef extern from "quantity.c": - int _compute_gradients(keyint N, double* centroids, double* centroid_values, long* number_of_boundaries, long* surrogate_neighbours, double* a, double* b) - int _compute_local_gradients(keyint N, double* vertex_coordinates, double* vertex_values, double* a, double* b) - int _extrapolate_from_gradient(keyint N, double* centroids, double* centroid_values, double* vertex_coordinates, double* vertex_values, double* edge_values, double* a, double* b) - int _extrapolate_and_limit_from_gradient(keyint N, double beta, double* centroids, long* neighbours, double* centroid_values, double* vertex_coordinates, double* vertex_values, double* edge_values, double* phi, double* x_gradient, double* y_gradient) - int _limit_vertices_by_all_neighbours(keyint N, double beta, double* centroid_values, double* vertex_values, double* edge_values, long* neighbours, double* x_gradient, double* y_gradient) - int _limit_edges_by_all_neighbours(keyint N, double beta, double* centroid_values, double* vertex_values, double* edge_values, long* neighbours, double* x_gradient, double* y_gradient) - int _limit_edges_by_neighbour(keyint N, double beta, double* centroid_values, double* vertex_values, double* edge_values, long* neighbours) - int _limit_gradient_by_neighbour(keyint N, double beta, double* centroid_values, double* vertex_values, double* edge_values, double* x_gradient, double* y_gradient, long* neighbours) - int _bound_vertices_below_by_constant(keyint N, double bound, double* centroid_values, double* vertex_values, double* edge_values, double* x_gradient, double* y_gradient) - int _bound_vertices_below_by_quantity(keyint N, double* bound_vertex_values, double* centroid_values, double* vertex_values, double* edge_values, double* x_gradient, double* y_gradient) - int _interpolate(keyint N, double* vertex_values, double* edge_values, double* centroid_values) - int _interpolate_from_vertices_to_edges(keyint N, double* vertex_values, double* edge_values) - int _interpolate_from_edges_to_vertices(keyint N, double* vertex_values, double* edge_values) - int _backup_centroid_values(keyint N, double* centroid_values, double* centroid_backup_values) - int _saxpy_centroid_values(keyint N, double a, double b, double* centroid_values, double* centroid_backup_values) - int _update(keyint N, double timestep, double* centroid_values, double* explicit_update, double* semi_implicit_update) - int _average_vertex_values(keyint N, long* vertex_value_indices, long* number_of_triangles_per_node, double* vertex_values, double* A) - int _average_centroid_values(keyint N, long* vertex_value_indices, long* number_of_triangles_per_node, double* centroid_values, double* A) - int _set_vertex_values_c(keyint num_verts, long* vertices, long* node_index, long* number_of_triangles_per_node, long* vertex_value_indices, double* vertex_values, double* A) - int _min_and_max_centroid_values(keyint N, double* qc, double* qv, long* neighbours, double* qmin, double* qmax) - -cdef extern from "util_ext.h": - void _limit_old(int N, double beta, double* qc, double* qv, double* qmin, double* qmax) - - -def update(object quantity, double timestep): - """Update centroid values based on values stored in - explicit_update and semi_implicit_update as well as given timestep - - Function implementing forcing terms must take on argument - which is the domain and they must update either explicit - or implicit updates, e,g,: - - def gravity(domain): - .... - domain.quantities['xmomentum'].explicit_update = ... - domain.quantities['ymomentum'].explicit_update = ... - - - - Explicit terms must have the form - - G(q, t) - - and explicit scheme is - - q^{(n+1}) = q^{(n)} + delta_t G(q^{n}, n delta_t) - - - Semi implicit forcing terms are assumed to have the form - - G(q, t) = H(q, t) q - - and the semi implicit scheme will then be - - q^{(n+1}) = q^{(n)} + delta_t H(q^{n}, n delta_t) q^{(n+1})""" - - cdef np.ndarray[double, ndim=1, mode="c"] centroid_values - cdef np.ndarray[double, ndim=1, mode="c"] explicit_update - cdef np.ndarray[double, ndim=1, mode="c"] semi_implicit_update - - cdef keyint N - cdef int err - - centroid_values = quantity.centroid_values - explicit_update = quantity.explicit_update - semi_implicit_update = quantity.semi_implicit_update - - N = centroid_values.shape[0] - - err = _update(N, timestep, ¢roid_values[0], &explicit_update[0], &semi_implicit_update[0]) - - assert err == 0, "quantity_ext.c: update, division by zero in semi implicit update - call Stephen :)" - - -def backup_centroid_values(object quantity): - - cdef np.ndarray[double, ndim=1, mode="c"] centroid_values - cdef np.ndarray[double, ndim=1, mode="c"] centroid_backup_values - - cdef keyint N - cdef int err - - centroid_values = quantity.centroid_values - centroid_backup_values = quantity.centroid_backup_values - - N = centroid_values.shape[0] - - err = _backup_centroid_values(N, ¢roid_values[0], ¢roid_backup_values[0]) - -def saxpy_centroid_values(object quantity, double a, double b): - - cdef np.ndarray[double, ndim=1, mode="c"] centroid_values - cdef np.ndarray[double, ndim=1, mode="c"] centroid_backup_values - - cdef keyint N - cdef int err - - centroid_values = quantity.centroid_values - centroid_backup_values = quantity.centroid_backup_values - - N = centroid_values.shape[0] - - err = _saxpy_centroid_values(N, a, b, ¢roid_values[0], ¢roid_backup_values[0]) - - -def set_vertex_values_c(object quantity, np.ndarray[long, ndim=1, mode="c"] vertices not None, np.ndarray[double, ndim=1, mode="c"] A not None): - - cdef object domain - cdef object mesh - - cdef np.ndarray[double, ndim=2, mode="c"] vertex_values - cdef np.ndarray[long, ndim=1, mode="c"] node_index - cdef np.ndarray[long, ndim=1, mode="c"] number_of_triangles_per_node - cdef np.ndarray[long, ndim=1, mode="c"] vertex_value_indices - - cdef keyint N - cdef int err - cdef keyint num_verts - - domain = quantity.domain - mesh = domain.mesh - - vertex_values = quantity.vertex_values - node_index = mesh.node_index - number_of_triangles_per_node = mesh.number_of_triangles_per_node - vertex_value_indices = mesh.vertex_value_indices - - num_verts = vertices.shape[0] - - err = _set_vertex_values_c(num_verts, &vertices[0], &node_index[0], &number_of_triangles_per_node[0], &vertex_value_indices[0], &vertex_values[0,0], &A[0]) - - -def interpolate(object quantity): - - cdef np.ndarray[double, ndim=2, mode="c"] vertex_values - cdef np.ndarray[double, ndim=2, mode="c"] edge_values - cdef np.ndarray[double, ndim=1, mode="c"] centroid_values - - cdef keyint N - cdef int err - - vertex_values = quantity.vertex_values - edge_values = quantity.edge_values - centroid_values = quantity.centroid_values - - N = vertex_values.shape[0] - - err = _interpolate(N, &vertex_values[0,0], &edge_values[0,0], ¢roid_values[0]) - - assert err == 0, "Interpolate could not be computed" - -def interpolate_from_vertices_to_edges(object quantity): - - cdef np.ndarray[double, ndim=2, mode="c"] vertex_values - cdef np.ndarray[double, ndim=2, mode="c"] edge_values - - cdef keyint N - cdef int err - - vertex_values = quantity.vertex_values - edge_values = quantity.edge_values - - N = vertex_values.shape[0] - - err = _interpolate_from_vertices_to_edges(N, &vertex_values[0,0], &edge_values[0,0]) - - assert err == 0, "Interpolate could not be computed" - -def interpolate_from_edges_to_vertices(object quantity): - - cdef np.ndarray[double, ndim=2, mode="c"] vertex_values - cdef np.ndarray[double, ndim=2, mode="c"] edge_values - - cdef keyint N - cdef int err - - vertex_values = quantity.vertex_values - edge_values = quantity.edge_values - - N = vertex_values.shape[0] - - err = _interpolate_from_edges_to_vertices(N, &vertex_values[0,0], &edge_values[0,0]) - - assert err == 0, "Interpolate could not be computed" - -def average_vertex_values(np.ndarray[long, ndim=1, mode="c"] vertex_value_indices not None, np.ndarray[long, ndim=1, mode="c"] number_of_triangles_per_node not None, np.ndarray[double, ndim=2, mode="c"] vertex_values not None, np.ndarray[double, ndim=1, mode="c"] A not None): - - cdef keyint N - cdef int err - - N = vertex_value_indices.shape[0] - - err = _average_vertex_values(N, &vertex_value_indices[0], &number_of_triangles_per_node[0], &vertex_values[0,0], &A[0]) - - assert err == 0, "average_vertex_values could not be computed" - -def average_centroid_values(np.ndarray[long, ndim=1, mode="c"] vertex_value_indices not None, np.ndarray[long, ndim=1, mode="c"] number_of_triangles_per_node not None, np.ndarray[double, ndim=1, mode="c"] centroid_values not None, np.ndarray[double, ndim=1, mode="c"] A not None): - - cdef keyint N - cdef int err - - N = vertex_value_indices.shape[0] - - err = _average_centroid_values(N, &vertex_value_indices[0], &number_of_triangles_per_node[0], ¢roid_values[0], &A[0]) - - assert err == 0, "average_centroid_values could not be computed" - -def extrapolate_from_gradient(object quantity): - - cdef object domain - - cdef np.ndarray[double, ndim=2, mode="c"] centroids - cdef np.ndarray[double, ndim=1, mode="c"] centroid_values - cdef np.ndarray[double, ndim=2, mode="c"] vertex_coordinates - cdef np.ndarray[double, ndim=2, mode="c"] vertex_values - cdef np.ndarray[double, ndim=2, mode="c"] edge_values - cdef np.ndarray[long, ndim=1, mode="c"] number_of_boundaries - cdef np.ndarray[long, ndim=2, mode="c"] surrogate_neighbours - cdef np.ndarray[double, ndim=1, mode="c"] x_gradient - cdef np.ndarray[double, ndim=1, mode="c"] y_gradient - - cdef keyint N - cdef int err - - domain = quantity.domain - - centroids = domain.centroid_coordinates - centroid_values = quantity.centroid_values - surrogate_neighbours = domain.surrogate_neighbours - number_of_boundaries = domain.number_of_boundaries - vertex_coordinates = domain.vertex_coordinates - vertex_values = quantity.vertex_values - edge_values = quantity.edge_values - x_gradient = quantity.x_gradient - y_gradient = quantity.y_gradient - - N = centroid_values.shape[0] - - err = _extrapolate_from_gradient(N,\ - ¢roids[0,0],\ - ¢roid_values[0],\ - &vertex_coordinates[0,0],\ - &vertex_values[0,0],\ - &edge_values[0,0],\ - &x_gradient[0],\ - &y_gradient[0]) - - assert err == 0, "Internal function _extrapolate failed" - -def compute_local_gradients(object quantity): - - cdef object domain - - cdef np.ndarray[double, ndim=2, mode="c"] vertex_coordinates - cdef np.ndarray[double, ndim=2, mode="c"] vertex_values - cdef np.ndarray[double, ndim=1, mode="c"] x_gradient - cdef np.ndarray[double, ndim=1, mode="c"] y_gradient - - cdef keyint N - cdef int err - - domain = quantity.domain - - vertex_coordinates = domain.vertex_coordinates - vertex_values = quantity.vertex_values - x_gradient = quantity.x_gradient - y_gradient = quantity.y_gradient - - N = vertex_values.shape[0] - - err = _compute_local_gradients(N, &vertex_coordinates[0,0], &vertex_values[0,0], &x_gradient[0], &y_gradient[0]) - - assert err == 0, "Internal function _compute_local_gradient failed" - -def extrapolate_second_order_and_limit_by_edge(object quantity): - - cdef object domain - - cdef np.ndarray[double, ndim=2, mode="c"] domain_centroids - cdef np.ndarray[double, ndim=2, mode="c"] domain_vertex_coordinates - cdef np.ndarray[long, ndim=1, mode="c"] domain_number_of_boundaries - cdef np.ndarray[long, ndim=2, mode="c"] domain_surrogate_neighbours - cdef np.ndarray[long, ndim=2, mode="c"] domain_neighbours - - cdef np.ndarray[double, ndim=1, mode="c"] quantity_centroid_values - cdef np.ndarray[double, ndim=2, mode="c"] quantity_vertex_values - cdef np.ndarray[double, ndim=2, mode="c"] quantity_edge_values - cdef np.ndarray[double, ndim=1, mode="c"] quantity_phi - cdef np.ndarray[double, ndim=1, mode="c"] quantity_x_gradient - cdef np.ndarray[double, ndim=1, mode="c"] quantity_y_gradient - - cdef keyint ntri - cdef double beta - cdef int err - - domain = quantity.object - - domain_centroids = domain.centroid_coordinates - domain_surrogate_neighbours = domain.surrogate_neighbours - domain_number_of_boundaries = domain.number_of_boundaries - domain_vertex_coordinates = domain.vertex_coordinates - domain_neighbours = domain.neighbours - - quantity_centroid_values = quantity.centroid_values - quantity_vertex_values = quantity.vertex_values - quantity_edge_values = quantity.edge_values - quantity_phi = quantity.phi - quantity_x_gradient = quantity.x_gradient - quantity_y_gradient = quantity.y_gradient - - beta = quantity.beta - - ntri = quantity_centroid_values.shape[0] - - err = _compute_gradients(ntri,\ - &domain_centroids[0,0],\ - &quantity_centroid_values[0],\ - &domain_number_of_boundaries[0],\ - &domain_surrogate_neighbours[0,0],\ - &quantity_x_gradient[0],\ - &quantity_y_gradient[0]) - - assert err == 0, "Internal function _compute_gradient failed" - - err = _extrapolate_from_gradient(ntri,\ - &domain_centroids[0,0],\ - &quantity_centroid_values[0],\ - &domain_vertex_coordinates[0,0],\ - &quantity_vertex_values[0,0],\ - &quantity_edge_values[0,0],\ - &quantity_x_gradient[0],\ - &quantity_y_gradient[0]) - - assert err == 0, "Internal function _extrapolate_from_gradient failed" - - err = _limit_edges_by_all_neighbours(ntri, beta,\ - &quantity_centroid_values[0],\ - &quantity_vertex_values[0,0],\ - &quantity_edge_values[0,0],\ - &domain_neighbours[0,0],\ - &quantity_x_gradient[0],\ - &quantity_y_gradient[0]) - - assert err == 0, "Internal function _limit_edges_by_all_neighbours failed" - -def extrapolate_second_order_and_limit_by_vertex(object quantity): - - cdef object domain - - cdef np.ndarray[double, ndim=2, mode="c"] domain_centroids - cdef np.ndarray[double, ndim=2, mode="c"] domain_vertex_coordinates - cdef np.ndarray[long, ndim=1, mode="c"] domain_number_of_boundaries - cdef np.ndarray[long, ndim=2, mode="c"] domain_surrogate_neighbours - cdef np.ndarray[long, ndim=2, mode="c"] domain_neighbours - - cdef np.ndarray[double, ndim=1, mode="c"] quantity_centroid_values - cdef np.ndarray[double, ndim=2, mode="c"] quantity_vertex_values - cdef np.ndarray[double, ndim=2, mode="c"] quantity_edge_values - cdef np.ndarray[double, ndim=1, mode="c"] quantity_phi - cdef np.ndarray[double, ndim=1, mode="c"] quantity_x_gradient - cdef np.ndarray[double, ndim=1, mode="c"] quantity_y_gradient - - cdef keyint ntri - cdef double beta - cdef int err - - domain = quantity.object - - domain_centroids = domain.centroid_coordinates - domain_surrogate_neighbours = domain.surrogate_neighbours - domain_number_of_boundaries = domain.number_of_boundaries - domain_vertex_coordinates = domain.vertex_coordinates - domain_neighbours = domain.neighbours - - quantity_centroid_values = quantity.centroid_values - quantity_vertex_values = quantity.vertex_values - quantity_edge_values = quantity.edge_values - quantity_phi = quantity.phi - quantity_x_gradient = quantity.x_gradient - quantity_y_gradient = quantity.y_gradient - - beta = quantity.beta - - ntri = quantity_centroid_values.shape[0] - - err = _compute_gradients(ntri,\ - &domain_centroids[0,0],\ - &quantity_centroid_values[0],\ - &domain_number_of_boundaries[0],\ - &domain_surrogate_neighbours[0,0],\ - &quantity_x_gradient[0],\ - &quantity_y_gradient[0]) - - assert err == 0, "Internal function _compute_gradient failed" - - err = _extrapolate_from_gradient(ntri,\ - &domain_centroids[0,0],\ - &quantity_centroid_values[0],\ - &domain_vertex_coordinates[0,0],\ - &quantity_vertex_values[0,0],\ - &quantity_edge_values[0,0],\ - &quantity_x_gradient[0],\ - &quantity_y_gradient[0]) - - assert err == 0, "Internal function _extrapolate_from_gradient failed" - - err = _limit_vertices_by_all_neighbours(ntri, beta,\ - &quantity_centroid_values[0],\ - &quantity_vertex_values[0,0],\ - &quantity_edge_values[0,0],\ - &domain_neighbours[0,0],\ - &quantity_x_gradient[0],\ - &quantity_y_gradient[0]) - - assert err == 0, "Internal function _limit_edges_by_all_neighbours failed" - -def compute_gradients(object quantity): - - cdef object domain - - cdef np.ndarray[double, ndim=2, mode="c"] centroids - cdef np.ndarray[double, ndim=1, mode="c"] centroid_values - cdef np.ndarray[double, ndim=2, mode="c"] vertex_coordinates - cdef np.ndarray[double, ndim=2, mode="c"] vertex_values - cdef np.ndarray[double, ndim=2, mode="c"] edge_values - cdef np.ndarray[long, ndim=1, mode="c"] number_of_boundaries - cdef np.ndarray[long, ndim=2, mode="c"] surrogate_neighbours - cdef np.ndarray[double, ndim=1, mode="c"] x_gradient - cdef np.ndarray[double, ndim=1, mode="c"] y_gradient - - cdef keyint N - cdef int err - - domain = quantity.domain - - centroids = domain.centroid_coordinates - centroid_values = quantity.centroid_values - surrogate_neighbours = domain.surrogate_neighbours - number_of_boundaries = domain.number_of_boundaries - vertex_coordinates = domain.vertex_coordinates - vertex_values = quantity.vertex_values - edge_values = quantity.edge_values - x_gradient = quantity.x_gradient - y_gradient = quantity.y_gradient - - N = centroid_values.shape[0] - - err = _compute_gradients(N,\ - ¢roids[0,0],\ - ¢roid_values[0],\ - &number_of_boundaries[0],\ - &surrogate_neighbours[0,0],\ - &x_gradient[0],\ - &y_gradient[0]) - - assert err == 0, "Gradient could not be computed" - -def limit_old(object quantity): - - cdef object domain - - cdef np.ndarray[double, ndim=1, mode="c"] qc - cdef np.ndarray[double, ndim=2, mode="c"] qv - cdef np.ndarray[long, ndim=2, mode="c"] neighbours - - cdef keyint N - cdef double beta_w - cdef int err - - domain = quantity.domain - - neighbours = domain.neighbours - - beta_w = domain.beta_w - - qc = quantity.centroid_values - qv = quantity.vertex_values - - N = qc.shape[0] - - cdef np.ndarray[double, ndim=1, mode="c"] qmin = np.empty(N, dtype=np.float64) - cdef np.ndarray[double, ndim=1, mode="c"] qmax = np.empty(N, dtype=np.float64) - - err = _min_and_max_centroid_values(N, &qc[0], &qv[0,0], &neighbours[0,0], &qmin[0], &qmax[0]) - - assert err == 0, "Internal function _min_and_max_centroid_values failed" - - _limit_old(N, beta_w, &qc[0], &qv[0,0], &qmin[0], &qmax[0]) - -def limit_vertices_by_all_neighbours(object quantity): - - cdef object domain - - cdef np.ndarray[double, ndim=2, mode="c"] vertex_values - cdef np.ndarray[double, ndim=1, mode="c"] centroid_values - cdef np.ndarray[double, ndim=2, mode="c"] edge_values - cdef np.ndarray[long, ndim=2, mode="c"] neighbours - cdef np.ndarray[double, ndim=1, mode="c"] x_gradient - cdef np.ndarray[double, ndim=1, mode="c"] y_gradient - - cdef double beta_w - cdef keyint N - cdef int err - - domain = quantity.domain - - beta_w = domain.beta_w - - neighbours = domain.neighbours - centroid_values = quantity.centroid_values - vertex_values = quantity.vertex_values - edge_values = quantity.edge_values - x_gradient = quantity.x_gradient - y_gradient = quantity.y_gradient - beta_w = domain.beta_w - - N = centroid_values.shape[0] - - err = _limit_vertices_by_all_neighbours(N, beta_w,\ - ¢roid_values[0],\ - &vertex_values[0,0],\ - &edge_values[0,0],\ - &neighbours[0,0],\ - &x_gradient[0],\ - &y_gradient[0]) - - assert err == 0, "Internal function _limit_by_vertex failed" - -def limit_edges_by_all_neighbours(object quantity): - - cdef object domain - - cdef np.ndarray[double, ndim=2, mode="c"] vertex_values - cdef np.ndarray[double, ndim=1, mode="c"] centroid_values - cdef np.ndarray[double, ndim=2, mode="c"] edge_values - cdef np.ndarray[long, ndim=2, mode="c"] neighbours - cdef np.ndarray[double, ndim=1, mode="c"] x_gradient - cdef np.ndarray[double, ndim=1, mode="c"] y_gradient - - cdef double beta_w - cdef keyint N - cdef int err - - domain = quantity.domain - - beta_w = domain.beta_w - - neighbours = domain.neighbours - centroid_values = quantity.centroid_values - vertex_values = quantity.vertex_values - edge_values = quantity.edge_values - x_gradient = quantity.x_gradient - y_gradient = quantity.y_gradient - beta_w = domain.beta_w - - N = centroid_values.shape[0] - - err = _limit_edges_by_all_neighbours(N, beta_w,\ - ¢roid_values[0],\ - &vertex_values[0,0],\ - &edge_values[0,0],\ - &neighbours[0,0],\ - &x_gradient[0],\ - &y_gradient[0]) - - assert err == 0, "Internal function _limit_by_edges failed" - -def bound_vertices_below_by_constant(object quantity, double bound): - - cdef object domain - - cdef np.ndarray[double, ndim=2, mode="c"] vertex_values - cdef np.ndarray[double, ndim=1, mode="c"] centroid_values - cdef np.ndarray[double, ndim=2, mode="c"] edge_values - cdef np.ndarray[double, ndim=1, mode="c"] x_gradient - cdef np.ndarray[double, ndim=1, mode="c"] y_gradient - - cdef keyint N - cdef int err - - domain = quantity.domain - - centroid_values = quantity.centroid_values - vertex_values = quantity.vertex_values - edge_values = quantity.edge_values - x_gradient = quantity.x_gradient - y_gradient = quantity.y_gradient - - N = centroid_values.shape[0] - - err = _bound_vertices_below_by_constant(N, bound,\ - ¢roid_values[0],\ - &vertex_values[0,0],\ - &edge_values[0,0],\ - &x_gradient[0],\ - &y_gradient[0]) - - assert err == 0, "Internal function _bound_vertices_below_by_constant failed" - -def bound_vertices_below_by_quantity(object quantity, object bounding_quantity): - - cdef object domain - - cdef np.ndarray[double, ndim=2, mode="c"] vertex_values - cdef np.ndarray[double, ndim=1, mode="c"] centroid_values - cdef np.ndarray[double, ndim=2, mode="c"] edge_values - cdef np.ndarray[double, ndim=1, mode="c"] x_gradient - cdef np.ndarray[double, ndim=1, mode="c"] y_gradient - cdef np.ndarray[double, ndim=2, mode="c"] bound_vertex_values - - cdef keyint N - cdef int err - - domain = quantity.domain - - centroid_values = quantity.centroid_values - vertex_values = quantity.vertex_values - edge_values = quantity.edge_values - x_gradient = quantity.x_gradient - y_gradient = quantity.y_gradient - bound_vertex_values = bounding_quantity.vertex_values - - N = centroid_values.shape[0] - - err = _bound_vertices_below_by_quantity(N,\ - &bound_vertex_values[0,0],\ - ¢roid_values[0],\ - &vertex_values[0,0],\ - &edge_values[0,0],\ - &x_gradient[0],\ - &y_gradient[0]) - - assert err == 0, "Internal function _bound_vertices_below_by_quantity failed" - -def limit_edges_by_neighbour(object quantity): - - cdef object domain - - cdef np.ndarray[double, ndim=2, mode="c"] vertex_values - cdef np.ndarray[double, ndim=1, mode="c"] centroid_values - cdef np.ndarray[double, ndim=2, mode="c"] edge_values - cdef np.ndarray[long, ndim=2, mode="c"] neighbours - - cdef double beta_w - cdef keyint N - cdef int err - - domain = quantity.domain - - beta_w = domain.beta_w - - neighbours = domain.neighbours - centroid_values = quantity.centroid_values - vertex_values = quantity.vertex_values - edge_values = quantity.edge_values - - N = centroid_values.shape[0] - - err = _limit_edges_by_neighbour(N, beta_w,\ - ¢roid_values[0],\ - &vertex_values[0,0],\ - &edge_values[0,0],\ - &neighbours[0,0]) - - assert err == 0, "Internal function _limit_edges_by_neighbour failed" - -def limit_gradient_by_neighbour(object quantity): - - cdef object domain - - cdef np.ndarray[double, ndim=2, mode="c"] vertex_values - cdef np.ndarray[double, ndim=1, mode="c"] centroid_values - cdef np.ndarray[double, ndim=2, mode="c"] edge_values - cdef np.ndarray[double, ndim=1, mode="c"] x_gradient - cdef np.ndarray[double, ndim=1, mode="c"] y_gradient - cdef np.ndarray[long, ndim=2, mode="c"] neighbours - - cdef double beta_w - cdef keyint N - cdef int err - - domain = quantity.domain - - beta_w = domain.beta_w - - neighbours = domain.neighbours - centroid_values = quantity.centroid_values - vertex_values = quantity.vertex_values - edge_values = quantity.edge_values - x_gradient = quantity.x_gradient - y_gradient = quantity.y_gradient - - N = centroid_values.shape[0] - - err = _limit_gradient_by_neighbour(N, beta_w,\ - ¢roid_values[0],\ - &vertex_values[0,0],\ - &edge_values[0,0],\ - &x_gradient[0],\ - &y_gradient[0],\ - &neighbours[0,0]) - - assert err == 0, "Internal function _limit_gradient_by_neighbour failed" - - - - - - - - - -''' -@cython.boundscheck(False) -@cython.wraparound(False) -def multiply(np.ndarray[double, ndim=2, mode="c"] input not None, double value): - cdef int m, n - - m, n = input.shape[0], input.shape[1] - - c_multiply (&input[0,0], value, m, n) - - return None - -@cython.boundscheck(False) -@cython.wraparound(False) -def dot_product(np.ndarray[double, ndim=1, mode="c"] a not None, np.ndarray[double, ndim=1, mode="c"] b not None): - cdef int n; - - n = a.shape[0] - - return c_dot_product(&a[0], &b[0], n) -''' diff --git a/anuga/abstract_2d_finite_volumes/setup.py b/anuga/abstract_2d_finite_volumes/setup.py index 7e87d189f..16b686a32 100644 --- a/anuga/abstract_2d_finite_volumes/setup.py +++ b/anuga/abstract_2d_finite_volumes/setup.py @@ -4,51 +4,50 @@ import sys from os.path import join -from Cython.Build import cythonize -import Cython.Compiler.Options -Cython.Compiler.Options.annotate = True def local_fun(): pass + def configuration(parent_package='',top_path=None): - from numpy.distutils.misc_util import Configuration + + from numpy.distutils.misc_util import Configuration - config = Configuration('abstract_2d_finite_volumes', parent_package, top_path) + + config = Configuration('abstract_2d_finite_volumes', parent_package, top_path) - config.add_data_dir('tests') + config.add_data_dir('tests') - #util_dir = os.path.abspath(join(os.path.dirname(__file__),'..','utilities')) - #runtime_dir = os.path.abspath(join(os.path.dirname(__file__),'..','runtime_libs')) + #util_dir = os.path.abspath(join(os.path.dirname(__file__),'..','utilities')) + #runtime_dir = os.path.abspath(join(os.path.dirname(__file__),'..','runtime_libs')) - util_dir = join('..','utilities') + util_dir = join('..','utilities') - config.add_extension('neighbour_mesh_ext', - sources=['neighbour_mesh_ext.pyx'], - include_dirs=[util_dir]) + config.add_extension('neighbour_mesh_ext', + sources=['neighbour_mesh_ext.c'], + include_dirs=[util_dir]) - config.add_extension('mesh_factory_ext', - sources=['mesh_factory_ext.pyx'], - include_dirs=[util_dir]) - - config.add_extension('neighbour_table_ext', - sources=['neighbour_table_ext.pyx'], - extra_compile_args=["-std=c++11"], - language='c++', - include_dirs=[util_dir]) - - config.add_extension('pmesh2domain_ext', - sources=['pmesh2domain_ext.pyx'], - include_dirs=[util_dir]) - - config.add_extension('quantity_ext', - sources=['quantity_ext.pyx'], - include_dirs=[util_dir]) - - config.ext_modules = cythonize(config.ext_modules,annotate=True) + config.add_extension('mesh_factory_ext', + sources=['mesh_factory_ext.c'], + include_dirs=[util_dir]) + + config.add_extension('neighbour_table_ext', + sources=['neighbour_table_ext.cpp'], + extra_compile_args=["-std=c++11"], + language='c++', + include_dirs=[util_dir]) + + config.add_extension('pmesh2domain_ext', + sources=['pmesh2domain_ext.c'], + include_dirs=[util_dir]) + + config.add_extension('quantity_ext', + sources=['quantity_ext.c'], + include_dirs=[util_dir]) - return config + + return config if __name__ == '__main__': - from numpy.distutils.core import setup - setup(configuration=configuration) + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/anuga/advection/advection.c b/anuga/advection/advection.c deleted file mode 100644 index b49025be9..000000000 --- a/anuga/advection/advection.c +++ /dev/null @@ -1,114 +0,0 @@ -// Python - C extension module for advection.py -// -// To compile (Python2.X): -// use python ../utilities/compile.py to -// compile all C files within a directory -// -// -// Steve Roberts, ANU 2008 - - - -#include "math.h" -#include "stdio.h" - -//------------------------------------------- -// Low level routines (called from wrappers) -//------------------------------------------ - -double _compute_fluxes( - double* quantity_update, - double* quantity_edge, - double* quantity_bdry, - long* domain_neighbours, - long* domain_neighbour_edges, - double* domain_normals, - double* domain_areas, - double* domain_radii, - double* domain_edgelengths, - long* domain_tri_full_flag, - double* domain_velocity, - double huge_timestep, - double max_timestep, - int ntri, - int nbdry){ - - - //Local Variables - - double qr,ql; - double normal[2]; - double normal_velocity; - double flux, edgeflux; - double max_speed; - double optimal_timestep; - double timestep; - int k_i,n_m,k_i_j; - int k,i,j,n,m; - int k3; - - //Loop through triangles - - timestep = max_timestep; - - for (k=0; kdomain_radii[k]/max_speed) ? - domain_radii[k]/max_speed : optimal_timestep; - } - } - - } - - //Normalise by area and store for when all conserved - //quantities get updated - quantity_update[k] = flux/domain_areas[k]; - - timestep = (timestep>optimal_timestep) ? optimal_timestep : timestep; - - } - - return timestep; -} diff --git a/anuga/advection/advection_ext.c b/anuga/advection/advection_ext.c new file mode 100644 index 000000000..8930ece89 --- /dev/null +++ b/anuga/advection/advection_ext.c @@ -0,0 +1,248 @@ +// Python - C extension module for advection.py +// +// To compile (Python2.X): +// use python ../utilities/compile.py to +// compile all C files within a directory +// +// +// Steve Roberts, ANU 2008 + + +#include "Python.h" +#include "numpy/arrayobject.h" +#include "math.h" +#include "stdio.h" + +// Shared code snippets +#include "util_ext.h" + + +//------------------------------------------- +// Low level routines (called from wrappers) +//------------------------------------------ + +double _compute_fluxes( + double* quantity_update, + double* quantity_edge, + double* quantity_bdry, + long* domain_neighbours, + long* domain_neighbour_edges, + double* domain_normals, + double* domain_areas, + double* domain_radii, + double* domain_edgelengths, + long* domain_tri_full_flag, + double* domain_velocity, + double huge_timestep, + double max_timestep, + int ntri, + int nbdry){ + + + //Local Variables + + double qr,ql; + double normal[2]; + double normal_velocity; + double flux, edgeflux; + double max_speed; + double optimal_timestep; + double timestep; + int k_i,n_m,k_i_j; + int k,i,j,n,m; + int k3; + + //Loop through triangles + + timestep = max_timestep; + + for (k=0; kdomain_radii[k]/max_speed) ? + domain_radii[k]/max_speed : optimal_timestep; + } + } + + } + + //Normalise by area and store for when all conserved + //quantities get updated + quantity_update[k] = flux/domain_areas[k]; + + timestep = (timestep>optimal_timestep) ? optimal_timestep : timestep; + + } + + return timestep; +} + + +//----------------------------------------------------- +// Python method Wrappers +//----------------------------------------------------- + + + +PyObject *compute_fluxes(PyObject *self, PyObject *args) { + /*Compute all fluxes and the timestep suitable for all volumes + in domain. + + Fluxes across each edge are scaled by edgelengths and summed up + Resulting flux is then scaled by area and stored in + explicit_update for the conserved quantity stage. + + The maximal allowable speed computed for each volume + is converted to a timestep that must not be exceeded. The minimum of + those is computed as the next overall timestep. + + Python call: + timestep = advection_ext.compute_fluxes(domain,quantity,huge_timestep,max_timestep) + + Post conditions: + domain.explicit_update is reset to computed flux values + domain.timestep is set to the largest step satisfying all volumes. + + */ + + PyObject *domain, *quantity; + + PyArrayObject + * quantity_update, + * quantity_edge, + * quantity_bdry, + * domain_neighbours, + * domain_neighbour_edges, + * domain_normals, + * domain_areas, + * domain_radii, + * domain_edgelengths, + * domain_tri_full_flag, + * domain_velocity; + + + // Local variables + int ntri, nbdry; + double huge_timestep, max_timestep; + double timestep; + + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "OOdd", + &domain, + &quantity, + &huge_timestep, + &max_timestep)) { + PyErr_SetString(PyExc_RuntimeError, "advection_ext.c: compute_fluxes could not parse input"); + return NULL; + } + + quantity_edge = get_consecutive_array(quantity, "edge_values"); + quantity_bdry = get_consecutive_array(quantity, "boundary_values"); + quantity_update = get_consecutive_array(quantity, "explicit_update"); + domain_neighbours = get_consecutive_array(domain, "neighbours"); + domain_neighbour_edges = get_consecutive_array(domain, "neighbour_edges"); + domain_normals = get_consecutive_array(domain, "normals"); + domain_areas = get_consecutive_array(domain, "areas"); + domain_radii = get_consecutive_array(domain, "radii"); + domain_edgelengths = get_consecutive_array(domain, "edgelengths"); + domain_tri_full_flag = get_consecutive_array(domain, "tri_full_flag"); + domain_velocity = get_consecutive_array(domain, "velocity"); + + ntri = quantity_edge -> dimensions[0]; + nbdry = quantity_bdry -> dimensions[0]; + + timestep = _compute_fluxes((double*) quantity_update -> data, + (double*) quantity_edge -> data, + (double*) quantity_bdry -> data, + (long*) domain_neighbours -> data, + (long*) domain_neighbour_edges -> data, + (double*) domain_normals -> data, + (double*) domain_areas ->data, + (double*) domain_radii -> data, + (double*) domain_edgelengths -> data, + (long*) domain_tri_full_flag -> data, + (double*) domain_velocity -> data, + huge_timestep, + max_timestep, + ntri, + nbdry); + + // Release and return + Py_DECREF(quantity_update); + Py_DECREF(quantity_edge); + Py_DECREF(quantity_bdry); + Py_DECREF(domain_neighbours); + Py_DECREF(domain_neighbour_edges); + Py_DECREF(domain_normals); + Py_DECREF(domain_areas); + Py_DECREF(domain_radii); + Py_DECREF(domain_edgelengths); + Py_DECREF(domain_tri_full_flag); + Py_DECREF(domain_velocity); + + + return Py_BuildValue("d", timestep); +} + + + +//------------------------------- +// Method table for python module +//------------------------------- +static struct PyMethodDef MethodTable[] = { + /* The cast of the function is necessary since PyCFunction values + * only take two PyObject* parameters, and rotate() takes + * three. + */ + + {"compute_fluxes", compute_fluxes, METH_VARARGS, "Print out"}, + {NULL, NULL} +}; + +// Module initialisation +void initadvection_ext(void){ + Py_InitModule("advection_ext", MethodTable); + import_array(); // Necessary for handling of NumPY structures +} diff --git a/anuga/advection/advection_ext.pyx b/anuga/advection/advection_ext.pyx deleted file mode 100644 index 58f9e301c..000000000 --- a/anuga/advection/advection_ext.pyx +++ /dev/null @@ -1,61 +0,0 @@ -#cython: wraparound=False, boundscheck=False, cdivision=True, profile=False, nonecheck=False, overflowcheck=False, cdivision_warnings=False, unraisable_tracebacks=False -import cython - -# import both numpy and the Cython declarations for numpy -import numpy as np -cimport numpy as np - -# declare the interface to the C code -cdef extern from "advection.c": - double _compute_fluxes(double* quantity_update, double* quantity_edge, double* quantity_bdry, long* domain_neighbours, long* domain_neighbour_edges, double* domain_normals, double* domain_areas, double* domain_radii, double* domain_edgelengths, long* domain_tri_full_flag, double* domain_velocity, double huge_timestep, double max_timestep, int ntri, int nbdry) - -def compute_fluxes(object domain, object quantity, double huge_timestep, double max_timestep): - - cdef np.ndarray[double, ndim=2, mode="c"] quantity_edge - cdef np.ndarray[double, ndim=1, mode="c"] quantity_bdry - cdef np.ndarray[double, ndim=1, mode="c"] quantity_update - cdef np.ndarray[long, ndim=2, mode="c"] domain_neighbours - cdef np.ndarray[long, ndim=2, mode="c"] domain_neighbour_edges - cdef np.ndarray[double, ndim=2, mode="c"] domain_normals - cdef np.ndarray[double, ndim=1, mode="c"] domain_areas - cdef np.ndarray[double, ndim=1, mode="c"] domain_radii - cdef np.ndarray[double, ndim=2, mode="c"] domain_edgelengths - cdef np.ndarray[long, ndim=1, mode="c"] domain_tri_full_flag - cdef np.ndarray[double, ndim=1, mode="c"] domain_velocity - - cdef int ntri, nbdry - cdef double timestep - - quantity_edge = quantity.edge_values - quantity_bdry = quantity.boundary_values - quantity_update = quantity.explicit_update - domain_neighbours = domain.neighbours - domain_neighbour_edges = domain.neighbour_edges - domain_normals = domain.normals - domain_areas = domain.areas - domain_radii = domain.radii - domain_edgelengths = domain.edgelengths - domain_tri_full_flag = domain.tri_full_flag - domain_velocity = domain.velocity - - ntri = quantity_edge.shape[0] - nbdry = quantity_bdry.shape[0] - - timestep = _compute_fluxes(&quantity_update[0],\ - &quantity_edge[0,0],\ - &quantity_bdry[0],\ - &domain_neighbours[0,0],\ - &domain_neighbour_edges[0,0],\ - &domain_normals[0,0],\ - &domain_areas[0],\ - &domain_radii[0],\ - &domain_edgelengths[0,0],\ - &domain_tri_full_flag[0],\ - &domain_velocity[0],\ - huge_timestep,\ - max_timestep,\ - ntri,\ - nbdry) - - return timestep - diff --git a/anuga/advection/setup.py b/anuga/advection/setup.py index 0bf09cf28..01ff749c8 100644 --- a/anuga/advection/setup.py +++ b/anuga/advection/setup.py @@ -4,9 +4,6 @@ import sys from os.path import join -from Cython.Build import cythonize -import Cython.Compiler.Options -Cython.Compiler.Options.annotate = True def configuration(parent_package='',top_path=None): @@ -21,11 +18,9 @@ def configuration(parent_package='',top_path=None): util_dir = join('..','utilities') config.add_extension('advection_ext', - sources=['advection_ext.pyx'], + sources=['advection_ext.c'], include_dirs=[util_dir]) - - config.ext_modules = cythonize(config.ext_modules,annotate=True) - + return config if __name__ == '__main__': diff --git a/anuga/shallow_water/setup.py b/anuga/shallow_water/setup.py index 3ebc468f4..a2fceeb8b 100644 --- a/anuga/shallow_water/setup.py +++ b/anuga/shallow_water/setup.py @@ -4,12 +4,6 @@ import sys from os.path import join -from Cython.Build import cythonize -import Cython.Compiler.Options -Cython.Compiler.Options.annotate = True - -import Cython.Compiler.Options -Cython.Compiler.Options.annotate = True def configuration(parent_package='',top_path=None): @@ -23,20 +17,19 @@ def configuration(parent_package='',top_path=None): #util_dir = os.path.abspath(join(os.path.dirname(__file__),'..','utilities')) util_dir = join('..','utilities') - + config.add_extension('shallow_water_ext', - sources=['shallow_water_ext.pyx'], + sources=['shallow_water_ext.c'], include_dirs=[util_dir]) - + config.add_extension('swb2_domain_ext', - sources=['swb2_domain_ext.pyx'], + sources=['swb2_domain_ext.c'], include_dirs=[util_dir]) config.add_extension('swDE1_domain_ext', - sources=['swDE1_domain_ext.pyx'], + sources=['swDE1_domain_ext.c'], include_dirs=[util_dir]) - config.ext_modules = cythonize(config.ext_modules, annotate=True) return config diff --git a/anuga/shallow_water/shallow_water.c b/anuga/shallow_water/shallow_water_ext.c similarity index 73% rename from anuga/shallow_water/shallow_water.c rename to anuga/shallow_water/shallow_water_ext.c index 8bb416275..ae8001d63 100644 --- a/anuga/shallow_water/shallow_water.c +++ b/anuga/shallow_water/shallow_water_ext.c @@ -13,8 +13,11 @@ // Ole Nielsen, GA 2004 +#include "Python.h" +#include "numpy/arrayobject.h" #include "math.h" #include +#include "numpy_shim.h" // Shared code snippets #include "util_ext.h" @@ -1735,6 +1738,470 @@ int _assign_wind_field_values(int N, return 0; } + + +/////////////////////////////////////////////////////////////////// +// Gateways to Python + +PyObject *flux_function_central(PyObject *self, PyObject *args) { + // + // Gateway to innermost flux function. + // This is only used by the unit tests as the c implementation is + // normally called by compute_fluxes in this module. + + + PyArrayObject *normal, *ql, *qr, *edgeflux; + double g, epsilon, max_speed, H0, zl, zr; + double h0, limiting_threshold; + + if (!PyArg_ParseTuple(args, "OOOddOddd", + &normal, &ql, &qr, &zl, &zr, &edgeflux, + &epsilon, &g, &H0)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + + h0 = H0*H0; // This ensures a good balance when h approaches H0. + // But evidence suggests that h0 can be as little as + // epsilon! + + limiting_threshold = 10 * H0; // Avoid applying limiter below this + // threshold for performance reasons. + // See ANUGA manual under flux limiting + + _flux_function_central((double*) ql -> data, + (double*) qr -> data, + zl, + zr, + ((double*) normal -> data)[0], + ((double*) normal -> data)[1], + epsilon, h0, limiting_threshold, + g, + (double*) edgeflux -> data, + &max_speed); + + return Py_BuildValue("d", max_speed); +} + + + +/* +PyObject *gravity(PyObject *self, PyObject *args) { + // + // gravity(g, h, v, x, xmom, ymom) + // + + + PyArrayObject *h, *z, *x, *xmom, *ymom; + int k, N, k3, k6; + double g, avg_h, zx, zy; + double x0, y0, x1, y1, x2, y2, z0, z1, z2; + //double epsilon; + + if (!PyArg_ParseTuple(args, "dOOOOO", + &g, &h, &z, &x, + &xmom, &ymom)) { + //&epsilon)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // check that numpy array objects arrays are C contiguous memory + CHECK_C_CONTIG(h); + CHECK_C_CONTIG(z); + CHECK_C_CONTIG(x); + CHECK_C_CONTIG(xmom); + CHECK_C_CONTIG(ymom); + + N = h -> dimensions[0]; + for (k=0; k data)[k3 + 0]; + z1 = ((double*) z -> data)[k3 + 1]; + z2 = ((double*) z -> data)[k3 + 2]; + + //printf("z0 %g, z1 %g, z2 %g \n",z0,z1,z2); + + // Optimise for flat bed + // Note (Ole): This didn't produce measurable speed up. + // Revisit later + //if (fabs(z0-z1) data)[k]; + + //printf("avg_h %g \n",avg_h); + + // Compute bed slope + k6 = 6*k; // base index + + x0 = ((double*) x -> data)[k6 + 0]; + y0 = ((double*) x -> data)[k6 + 1]; + x1 = ((double*) x -> data)[k6 + 2]; + y1 = ((double*) x -> data)[k6 + 3]; + x2 = ((double*) x -> data)[k6 + 4]; + y2 = ((double*) x -> data)[k6 + 5]; + + //printf("x0 %g, y0 %g, x1 %g, y1 %g, x2 %g, y2 %g \n",x0,y0,x1,y1,x2,y2); + + _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy); + + //printf("zx %g, zy %g \n",zx,zy); + // Update momentum + ((double*) xmom -> data)[k] += -g*zx*avg_h; + ((double*) ymom -> data)[k] += -g*zy*avg_h; + } + + return Py_BuildValue(""); +} + */ + +//------------------------------------------------------------------------------- +// gravity term using new get_python_domain interface +// +// FIXME SR: Probably should do this calculation together with hte compute +// fluxes +//------------------------------------------------------------------------------- + +PyObject *gravity(PyObject *self, PyObject *args) { + // + // gravity(domain) + // + + + struct domain D; + PyObject *domain; + + int k, N, k3, k6; + double g, avg_h, zx, zy; + double x0, y0, x1, y1, x2, y2, z0, z1, z2; + //double h0,h1,h2; + //double epsilon; + + if (!PyArg_ParseTuple(args, "O", &domain)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // populate the C domain structure with pointers + // to the python domain data + get_python_domain(&D, domain); + + + g = D.g; + + N = D.number_of_elements; + for (k = 0; k < N; k++) { + k3 = 3 * k; // base index + + // Get bathymetry + z0 = D.bed_vertex_values[k3 + 0]; + z1 = D.bed_vertex_values[k3 + 1]; + z2 = D.bed_vertex_values[k3 + 2]; + + //printf("z0 %g, z1 %g, z2 %g \n",z0,z1,z2); + + // Get average depth from centroid values + avg_h = D.stage_centroid_values[k] - D.bed_centroid_values[k]; + + //printf("avg_h %g \n",avg_h); + // Compute bed slope + k6 = 6 * k; // base index + + x0 = D.vertex_coordinates[k6 + 0]; + y0 = D.vertex_coordinates[k6 + 1]; + x1 = D.vertex_coordinates[k6 + 2]; + y1 = D.vertex_coordinates[k6 + 3]; + x2 = D.vertex_coordinates[k6 + 4]; + y2 = D.vertex_coordinates[k6 + 5]; + + //printf("x0 %g, y0 %g, x1 %g, y1 %g, x2 %g, y2 %g \n",x0,y0,x1,y1,x2,y2); + _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy); + + //printf("zx %g, zy %g \n",zx,zy); + + // Update momentum + D.xmom_explicit_update[k] += -g * zx*avg_h; + D.ymom_explicit_update[k] += -g * zy*avg_h; + } + + + return Py_BuildValue(""); +} + + +//------------------------------------------------------------------------------- +// New well balanced gravity term using new get_python_domain interface +// +// FIXME SR: Probably should do this calculation together with hte compute +// fluxes +//------------------------------------------------------------------------------- + +PyObject *gravity_wb(PyObject *self, PyObject *args) { + // + // gravity_wb(domain) + // + + + struct domain D; + PyObject *domain; + + int i, k, N, k3, k6; + double g, avg_h, wx, wy, fact; + double x0, y0, x1, y1, x2, y2; + double hh[3]; + double w0, w1, w2; + double sidex, sidey, area; + double n0, n1; + //double epsilon; + + if (!PyArg_ParseTuple(args, "O", &domain)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // populate the C domain structure with pointers + // to the python domain data + get_python_domain(&D, domain); + + + g = D.g; + + N = D.number_of_elements; + for (k = 0; k < N; k++) { + k3 = 3 * k; // base index + + //------------------------------------ + // Calculate side terms -ghw_x term + //------------------------------------ + + // Get vertex stage values for gradient calculation + w0 = D.stage_vertex_values[k3 + 0]; + w1 = D.stage_vertex_values[k3 + 1]; + w2 = D.stage_vertex_values[k3 + 2]; + + // Compute stage slope + k6 = 6 * k; // base index + + x0 = D.vertex_coordinates[k6 + 0]; + y0 = D.vertex_coordinates[k6 + 1]; + x1 = D.vertex_coordinates[k6 + 2]; + y1 = D.vertex_coordinates[k6 + 3]; + x2 = D.vertex_coordinates[k6 + 4]; + y2 = D.vertex_coordinates[k6 + 5]; + + //printf("x0 %g, y0 %g, x1 %g, y1 %g, x2 %g, y2 %g \n",x0,y0,x1,y1,x2,y2); + _gradient(x0, y0, x1, y1, x2, y2, w0, w1, w2, &wx, &wy); + + avg_h = D.stage_centroid_values[k] - D.bed_centroid_values[k]; + + // Update using -ghw_x term + D.xmom_explicit_update[k] += -g * wx*avg_h; + D.ymom_explicit_update[k] += -g * wy*avg_h; + + //------------------------------------ + // Calculate side terms \sum_i 0.5 g l_i h_i^2 n_i + //------------------------------------ + + // Getself.stage_c = self.domain.quantities['stage'].centroid_values edge depths + hh[0] = D.stage_edge_values[k3 + 0] - D.bed_edge_values[k3 + 0]; + hh[1] = D.stage_edge_values[k3 + 1] - D.bed_edge_values[k3 + 1]; + hh[2] = D.stage_edge_values[k3 + 2] - D.bed_edge_values[k3 + 2]; + + + //printf("h0,1,2 %f %f %f\n",hh[0],hh[1],hh[2]); + + // Calculate the side correction term + sidex = 0.0; + sidey = 0.0; + for (i = 0; i < 3; i++) { + n0 = D.normals[k6 + 2 * i]; + n1 = D.normals[k6 + 2 * i + 1]; + + //printf("n0, n1 %i %g %g\n",i,n0,n1); + fact = -0.5 * g * hh[i] * hh[i] * D.edgelengths[k3 + i]; + sidex = sidex + fact*n0; + sidey = sidey + fact*n1; + } + + // Update momentum with side terms + area = D.areas[k]; + D.xmom_explicit_update[k] += -sidex / area; + D.ymom_explicit_update[k] += -sidey / area; + + } + + return Py_BuildValue(""); +} + +PyObject *manning_friction_sloped(PyObject *self, PyObject *args) { + // + // manning_friction_sloped(g, eps, x, h, uh, vh, z, eta, xmom_update, ymom_update) + // + + + PyArrayObject *x, *w, *z, *uh, *vh, *eta, *xmom, *ymom; + int N; + double g, eps; + + if (!PyArg_ParseTuple(args, "ddOOOOOOOO", + &g, &eps, &x, &w, &uh, &vh, &z, &eta, &xmom, &ymom)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // check that numpy array objects arrays are C contiguous memory + CHECK_C_CONTIG(x); + CHECK_C_CONTIG(w); + CHECK_C_CONTIG(z); + CHECK_C_CONTIG(uh); + CHECK_C_CONTIG(vh); + CHECK_C_CONTIG(eta); + CHECK_C_CONTIG(xmom); + CHECK_C_CONTIG(ymom); + + N = w -> dimensions[0]; + + _manning_friction_sloped(g, eps, N, + (double*) x -> data, + (double*) w -> data, + (double*) z -> data, + (double*) uh -> data, + (double*) vh -> data, + (double*) eta -> data, + (double*) xmom -> data, + (double*) ymom -> data); + + return Py_BuildValue(""); +} + +PyObject *chezy_friction(PyObject *self, PyObject *args) { + // + // chezy_friction(g, eps, x, h, uh, vh, z, chezy, xmom_update, ymom_update) + // + + + PyArrayObject *x, *w, *z, *uh, *vh, *chezy, *xmom, *ymom; + int N; + double g, eps; + + if (!PyArg_ParseTuple(args, "ddOOOOOOOO", + &g, &eps, &x, &w, &uh, &vh, &z, &chezy, &xmom, &ymom)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // check that numpy array objects arrays are C contiguous memory + CHECK_C_CONTIG(x); + CHECK_C_CONTIG(w); + CHECK_C_CONTIG(z); + CHECK_C_CONTIG(uh); + CHECK_C_CONTIG(vh); + CHECK_C_CONTIG(chezy); + CHECK_C_CONTIG(xmom); + CHECK_C_CONTIG(ymom); + + N = w -> dimensions[0]; + + _chezy_friction(g, eps, N, + (double*) x -> data, + (double*) w -> data, + (double*) z -> data, + (double*) uh -> data, + (double*) vh -> data, + (double*) chezy -> data, + (double*) xmom -> data, + (double*) ymom -> data); + + return Py_BuildValue(""); +} + +PyObject *manning_friction_flat(PyObject *self, PyObject *args) { + // + // manning_friction_flat(g, eps, h, uh, vh, z, eta, xmom_update, ymom_update) + // + + + PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom; + int N; + double g, eps; + + if (!PyArg_ParseTuple(args, "ddOOOOOOO", + &g, &eps, &w, &uh, &vh, &z, &eta, &xmom, &ymom)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // check that numpy array objects arrays are C contiguous memory + CHECK_C_CONTIG(w); + CHECK_C_CONTIG(z); + CHECK_C_CONTIG(uh); + CHECK_C_CONTIG(vh); + CHECK_C_CONTIG(eta); + CHECK_C_CONTIG(xmom); + CHECK_C_CONTIG(ymom); + + N = w -> dimensions[0]; + + _manning_friction_flat(g, eps, N, + (double*) w -> data, + (double*) z -> data, + (double*) uh -> data, + (double*) vh -> data, + (double*) eta -> data, + (double*) xmom -> data, + (double*) ymom -> data); + + return Py_BuildValue(""); +} + + +/* +PyObject *manning_friction_explicit(PyObject *self, PyObject *args) { + // + // manning_friction_explicit(g, eps, h, uh, vh, eta, xmom_update, ymom_update) + // + + + PyArrayObject *w, *z, *uh, *vh, *eta, *xmom, *ymom; + int N; + double g, eps; + + if (!PyArg_ParseTuple(args, "ddOOOOOOO", + &g, &eps, &w, &z, &uh, &vh, &eta, + &xmom, &ymom)) + return NULL; + + // check that numpy array objects arrays are C contiguous memory + CHECK_C_CONTIG(w); + CHECK_C_CONTIG(z); + CHECK_C_CONTIG(uh); + CHECK_C_CONTIG(vh); + CHECK_C_CONTIG(eta); + CHECK_C_CONTIG(xmom); + CHECK_C_CONTIG(ymom); + + N = w -> dimensions[0]; + _manning_friction_explicit(g, eps, N, + (double*) w -> data, + (double*) z -> data, + (double*) uh -> data, + (double*) vh -> data, + (double*) eta -> data, + (double*) xmom -> data, + (double*) ymom -> data); + + return Py_BuildValue(""); +} + */ + + + // Computational routine int _extrapolate_second_order_sw_old(int number_of_elements, @@ -3507,6 +3974,360 @@ int _extrapolate_second_order_edge_sw(struct domain *D) { return 0; } + + + + + + + +PyObject *extrapolate_second_order_sw_old(PyObject *self, PyObject *args) { + /*Compute the vertex values based on a linear reconstruction + on each triangle + + These values are calculated as follows: + 1) For each triangle not adjacent to a boundary, we consider the + auxiliary triangle formed by the centroids of its three + neighbours. + 2) For each conserved quantity, we integrate around the auxiliary + triangle's boundary the product of the quantity and the outward + normal vector. Dividing by the triangle area gives (a,b), the + average of the vector (q_x,q_y) on the auxiliary triangle. + We suppose that the linear reconstruction on the original + triangle has gradient (a,b). + 3) Provisional vertex jumps dqv[0,1,2] are computed and these are + then limited by calling the functions find_qmin_and_qmax and + limit_gradient + + Python call: + extrapolate_second_order_sw(domain.surrogate_neighbours, + domain.number_of_boundaries + domain.centroid_coordinates, + Stage.centroid_values + Xmom.centroid_values + Ymom.centroid_values + domain.vertex_coordinates, + Stage.vertex_values, + Xmom.vertex_values, + Ymom.vertex_values) + + Post conditions: + The vertices of each triangle have values from a + limited linear reconstruction + based on centroid values + + */ + PyArrayObject *surrogate_neighbours, + *number_of_boundaries, + *centroid_coordinates, + *stage_centroid_values, + *xmom_centroid_values, + *ymom_centroid_values, + *elevation_centroid_values, + *vertex_coordinates, + *stage_vertex_values, + *xmom_vertex_values, + *ymom_vertex_values, + *elevation_vertex_values; + + PyObject *domain; + + + double beta_w, beta_w_dry, beta_uh, beta_uh_dry, beta_vh, beta_vh_dry; + double minimum_allowed_height, epsilon; + int optimise_dry_cells, number_of_elements, e, extrapolate_velocity_second_order; + + // Provisional jumps from centroids to v'tices and safety factor re limiting + // by which these jumps are limited + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "OOOOOOOOOOOOOii", + &domain, + &surrogate_neighbours, + &number_of_boundaries, + ¢roid_coordinates, + &stage_centroid_values, + &xmom_centroid_values, + &ymom_centroid_values, + &elevation_centroid_values, + &vertex_coordinates, + &stage_vertex_values, + &xmom_vertex_values, + &ymom_vertex_values, + &elevation_vertex_values, + &optimise_dry_cells, + &extrapolate_velocity_second_order)) { + + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // check that numpy array objects arrays are C contiguous memory + CHECK_C_CONTIG(surrogate_neighbours); + CHECK_C_CONTIG(number_of_boundaries); + CHECK_C_CONTIG(centroid_coordinates); + CHECK_C_CONTIG(stage_centroid_values); + CHECK_C_CONTIG(xmom_centroid_values); + CHECK_C_CONTIG(ymom_centroid_values); + CHECK_C_CONTIG(elevation_centroid_values); + CHECK_C_CONTIG(vertex_coordinates); + CHECK_C_CONTIG(stage_vertex_values); + CHECK_C_CONTIG(xmom_vertex_values); + CHECK_C_CONTIG(ymom_vertex_values); + CHECK_C_CONTIG(elevation_vertex_values); + + // Get the safety factor beta_w, set in the config.py file. + // This is used in the limiting process + + + beta_w = get_python_double(domain, "beta_w"); + beta_w_dry = get_python_double(domain, "beta_w_dry"); + beta_uh = get_python_double(domain, "beta_uh"); + beta_uh_dry = get_python_double(domain, "beta_uh_dry"); + beta_vh = get_python_double(domain, "beta_vh"); + beta_vh_dry = get_python_double(domain, "beta_vh_dry"); + + minimum_allowed_height = get_python_double(domain, "minimum_allowed_height"); + epsilon = get_python_double(domain, "epsilon"); + + number_of_elements = stage_centroid_values -> dimensions[0]; + + // Call underlying computational routine + e = _extrapolate_second_order_sw_old(number_of_elements, + epsilon, + minimum_allowed_height, + beta_w, + beta_w_dry, + beta_uh, + beta_uh_dry, + beta_vh, + beta_vh_dry, + (long*) surrogate_neighbours -> data, + (long*) number_of_boundaries -> data, + (double*) centroid_coordinates -> data, + (double*) stage_centroid_values -> data, + (double*) xmom_centroid_values -> data, + (double*) ymom_centroid_values -> data, + (double*) elevation_centroid_values -> data, + (double*) vertex_coordinates -> data, + (double*) stage_vertex_values -> data, + (double*) xmom_vertex_values -> data, + (double*) ymom_vertex_values -> data, + (double*) elevation_vertex_values -> data, + optimise_dry_cells, + extrapolate_velocity_second_order); + + if (e == -1) { + // Use error string set inside computational routine + return NULL; + } + + + return Py_BuildValue(""); + +}// extrapolate_second-order_sw_old + +PyObject *extrapolate_second_order_sw(PyObject *self, PyObject *args) { + /*Compute the edge values based on a linear reconstruction + on each triangle + + Python call: + extrapolate_second_order_edge_sw(domain) + + Post conditions: + The edges of each triangle have values from a + limited linear reconstruction + based on centroid values + + */ + + struct domain D; + PyObject *domain; + int err; + + if (!PyArg_ParseTuple(args, "O", &domain)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // populate the C domain structure with pointers + // to the python domain data + get_python_domain(&D, domain); + + //print_domain_struct(&D); + + // Call underlying flux computation routine and update + // the explicit update arrays + err = _extrapolate_second_order_sw(&D); + + if (err == -1) { + // Use error string set inside computational routine + return NULL; + } + + return Py_BuildValue(""); + +}// extrapolate_second-order_sw + +PyObject *extrapolate_second_order_edge_sw(PyObject *self, PyObject *args) { + /*Compute the edge values based on a linear reconstruction + on each triangle + + Python call: + extrapolate_second_order_edge_sw(domain) + + Post conditions: + The edges of each triangle have values from a + limited linear reconstruction + based on centroid values + + */ + + struct domain D; + PyObject *domain; + int err; + + if (!PyArg_ParseTuple(args, "O", &domain)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // populate the C domain structure with pointers + // to the python domain data + get_python_domain(&D, domain); + + // Call underlying flux computation routine and update + // the explicit update arrays + err = _extrapolate_second_order_edge_sw(&D); + + if (err == -1) { + // Use error string set inside computational routine + return NULL; + } + + return Py_BuildValue(""); + +}// extrapolate_second-order_edge_sw + + + + + + +PyObject *rotate(PyObject *self, PyObject *args, PyObject *kwargs) { + // + // r = rotate(q, normal, direction=1) + // + // Where q is assumed to be a Float numeric array of length 3 and + // normal a Float numeric array of length 2. + + // FIXME(Ole): I don't think this is used anymore + + PyObject *Q, *Normal; + PyArrayObject *q, *r, *normal; + + static char *argnames[] = {"q", "normal", "direction", NULL}; + int dimensions[1], i, direction = 1; + double n1, n2; + + // Convert Python arguments to C + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", argnames, + &Q, &Normal, &direction)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // Input checks (convert sequences into numeric arrays) + q = (PyArrayObject *) + PyArray_ContiguousFromObject(Q, PyArray_DOUBLE, 0, 0); + normal = (PyArrayObject *) + PyArray_ContiguousFromObject(Normal, PyArray_DOUBLE, 0, 0); + + + if (normal -> dimensions[0] != 2) { + report_python_error(AT, "Normal vector must have 2 components"); + return NULL; + } + + // Allocate space for return vector r (don't DECREF) + dimensions[0] = 3; + r = (PyArrayObject *) anuga_FromDims(1, dimensions, PyArray_DOUBLE); + + // Copy + for (i = 0; i < 3; i++) { + ((double *) (r -> data))[i] = ((double *) (q -> data))[i]; + } + + // Get normal and direction + n1 = ((double *) normal -> data)[0]; + n2 = ((double *) normal -> data)[1]; + if (direction == -1) n2 = -n2; + + // Rotate + _rotate((double *) r -> data, n1, n2); + + // Release numeric arrays + Py_DECREF(q); + Py_DECREF(normal); + + // Return result using PyArray to avoid memory leak + return PyArray_Return(r); +} + + +PyObject *reflect_momentum_velocity(PyObject *self, PyObject *args) { + /*Rotate momentum and velcity for all edges in a segment + * + Python call: + reflect_momentum_velocity(domain, segment_ids) + + Post conditions: + The edges of each triangle have values from a + limited linear reconstruction + based on centroid values + + */ + + struct domain D; + PyObject *domain; + PyArrayObject *segment_ids; + + long *seg_ids; + + int err; + + if (!PyArg_ParseTuple(args, "OO", &domain, &segment_ids)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // populate the C domain structure with pointers + // to the python domain data + get_python_domain(&D, domain); + + + + + + + //print_domain_struct(&D); + + // Call underlying flux computation routine and update + // the explicit update arrays + err = _extrapolate_second_order_sw(&D); + + if (err == -1) { + // Use error string set inside computational routine + return NULL; + } + + return Py_BuildValue(""); + +}// extrapolate_second-order_sw + + + + + // Computational function for flux computation double _compute_fluxes_central(int number_of_elements, @@ -4319,125 +5140,867 @@ double _compute_fluxes_central_wb_3(struct domain *D) { return timestep; } -int _gravity(struct domain *D) { - int k, N, k3, k6; - double g, avg_h, zx, zy; - double x0, y0, x1, y1, x2, y2, z0, z1, z2; - g = D->g; - N = D->number_of_elements; +//========================================================================= +// Python Glue +//========================================================================= - for (k = 0; k < N; k++) { - k3 = 3 * k; // base index +PyObject *compute_fluxes_ext_central_new(PyObject *self, PyObject *args) { + /*Compute all fluxes and the timestep suitable for all volumes + in domain. - // Get bathymetry - z0 = (D->bed_vertex_values)[k3 + 0]; - z1 = (D->bed_vertex_values)[k3 + 1]; - z2 = (D->bed_vertex_values)[k3 + 2]; + Compute total flux for each conserved quantity using "flux_function_central" - //printf("z0 %g, z1 %g, z2 %g \n",z0,z1,z2); + Fluxes across each edge are scaled by edgelengths and summed up + Resulting flux is then scaled by area and stored in + explicit_update for each of the three conserved quantities + stage, xmomentum and ymomentum - // Get average depth from centroid values - avg_h = (D->stage_centroid_values)[k] - (D->bed_centroid_values)[k]; + The maximal allowable speed computed by the flux_function for each volume + is converted to a timestep that must not be exceeded. The minimum of + those is computed as the next overall timestep. - //printf("avg_h %g \n",avg_h); - // Compute bed slope - k6 = 6 * k; // base index + Python call: + timestep = compute_fluxes(timestep, domain, stage, xmom, ymom, bed) - x0 = (D->vertex_coordinates)[k6 + 0]; - y0 = (D->vertex_coordinates)[k6 + 1]; - x1 = (D->vertex_coordinates)[k6 + 2]; - y1 = (D->vertex_coordinates)[k6 + 3]; - x2 = (D->vertex_coordinates)[k6 + 4]; - y2 = (D->vertex_coordinates)[k6 + 5]; - //printf("x0 %g, y0 %g, x1 %g, y1 %g, x2 %g, y2 %g \n",x0,y0,x1,y1,x2,y2); - _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy); + Post conditions: + domain.explicit_update is reset to computed flux values + returns timestep which is the largest step satisfying all volumes. - //printf("zx %g, zy %g \n",zx,zy); - // Update momentum - (D->xmom_explicit_update)[k] += -g * zx*avg_h; - (D->ymom_explicit_update)[k] += -g * zy*avg_h; + */ + + PyObject + *domain, + *stage, + *xmom, + *ymom, + *bed; + + PyArrayObject + *neighbours, + *neighbour_edges, + *normals, + *edgelengths, + *radii, + *areas, + *tri_full_flag, + *stage_edge_values, + *xmom_edge_values, + *ymom_edge_values, + *bed_edge_values, + *stage_boundary_values, + *xmom_boundary_values, + *ymom_boundary_values, + *stage_explicit_update, + *xmom_explicit_update, + *ymom_explicit_update, + *already_computed_flux, //Tracks whether the flux across an edge has already been computed + *max_speed_array; //Keeps track of max speeds for each triangle + + + double timestep, epsilon, H0, g; + int optimise_dry_cells; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "dOOOO", ×tep, &domain, &stage, &xmom, &ymom, &bed)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; } - return 0; + + epsilon = get_python_double(domain, "epsilon"); + H0 = get_python_double(domain, "H0"); + g = get_python_double(domain, "g"); + optimise_dry_cells = get_python_integer(domain, "optimse_dry_cells"); + + neighbours = get_consecutive_array(domain, "neighbours"); + neighbour_edges = get_consecutive_array(domain, "neighbour_edges"); + normals = get_consecutive_array(domain, "normals"); + edgelengths = get_consecutive_array(domain, "edge_lengths"); + radii = get_consecutive_array(domain, "radii"); + areas = get_consecutive_array(domain, "areas"); + tri_full_flag = get_consecutive_array(domain, "tri_full_flag"); + already_computed_flux = get_consecutive_array(domain, "already_computed_flux"); + max_speed_array = get_consecutive_array(domain, "max_speed"); + + stage_edge_values = get_consecutive_array(stage, "edge_values"); + xmom_edge_values = get_consecutive_array(xmom, "edge_values"); + ymom_edge_values = get_consecutive_array(ymom, "edge_values"); + bed_edge_values = get_consecutive_array(bed, "edge_values"); + + stage_boundary_values = get_consecutive_array(stage, "boundary_values"); + xmom_boundary_values = get_consecutive_array(xmom, "boundary_values"); + ymom_boundary_values = get_consecutive_array(ymom, "boundary_values"); + + stage_explicit_update = get_consecutive_array(stage, "explicit_update"); + xmom_explicit_update = get_consecutive_array(xmom, "explicit_update"); + ymom_explicit_update = get_consecutive_array(ymom, "explicit_update"); + + + int number_of_elements = stage_edge_values -> dimensions[0]; + + // Call underlying flux computation routine and update + // the explicit update arrays + timestep = _compute_fluxes_central(number_of_elements, + timestep, + epsilon, + H0, + g, + (long*) neighbours -> data, + (long*) neighbour_edges -> data, + (double*) normals -> data, + (double*) edgelengths -> data, + (double*) radii -> data, + (double*) areas -> data, + (long*) tri_full_flag -> data, + (double*) stage_edge_values -> data, + (double*) xmom_edge_values -> data, + (double*) ymom_edge_values -> data, + (double*) bed_edge_values -> data, + (double*) stage_boundary_values -> data, + (double*) xmom_boundary_values -> data, + (double*) ymom_boundary_values -> data, + (double*) stage_explicit_update -> data, + (double*) xmom_explicit_update -> data, + (double*) ymom_explicit_update -> data, + (long*) already_computed_flux -> data, + (double*) max_speed_array -> data, + optimise_dry_cells); + + Py_DECREF(neighbours); + Py_DECREF(neighbour_edges); + Py_DECREF(normals); + Py_DECREF(edgelengths); + Py_DECREF(radii); + Py_DECREF(areas); + Py_DECREF(tri_full_flag); + Py_DECREF(already_computed_flux); + Py_DECREF(max_speed_array); + Py_DECREF(stage_edge_values); + Py_DECREF(xmom_edge_values); + Py_DECREF(ymom_edge_values); + Py_DECREF(bed_edge_values); + Py_DECREF(stage_boundary_values); + Py_DECREF(xmom_boundary_values); + Py_DECREF(ymom_boundary_values); + Py_DECREF(stage_explicit_update); + Py_DECREF(xmom_explicit_update); + Py_DECREF(ymom_explicit_update); + + + // Return updated flux timestep + return Py_BuildValue("d", timestep); } -int _gravity_wb(struct domain *D) { +PyObject *compute_fluxes_ext_central(PyObject *self, PyObject *args) { + /*Compute all fluxes and the timestep suitable for all volumes + in domain. + + Compute total flux for each conserved quantity using "flux_function_central" + + Fluxes across each edge are scaled by edgelengths and summed up + Resulting flux is then scaled by area and stored in + explicit_update for each of the three conserved quantities + stage, xmomentum and ymomentum + + The maximal allowable speed computed by the flux_function for each volume + is converted to a timestep that must not be exceeded. The minimum of + those is computed as the next overall timestep. + + Python call: + domain.timestep = compute_fluxes(timestep, + domain.epsilon, + domain.H0, + domain.g, + domain.neighbours, + domain.neighbour_edges, + domain.normals, + domain.edgelengths, + domain.radii, + domain.areas, + tri_full_flag, + Stage.edge_values, + Xmom.edge_values, + Ymom.edge_values, + Bed.edge_values, + Stage.boundary_values, + Xmom.boundary_values, + Ymom.boundary_values, + Stage.explicit_update, + Xmom.explicit_update, + Ymom.explicit_update, + already_computed_flux, + optimise_dry_cells) + + + Post conditions: + domain.explicit_update is reset to computed flux values + domain.timestep is set to the largest step satisfying all volumes. - int i, k, N, k3, k6; - double g, avg_h, wx, wy, fact; - double x0, y0, x1, y1, x2, y2; - double hh[3]; - double w0, w1, w2; - double sidex, sidey, area; - double n0, n1; - g = D->g; + */ - N = D->number_of_elements; - for (k = 0; k < N; k++) { - k3 = 3 * k; // base index - //------------------------------------ - // Calculate side terms -ghw_x term - //------------------------------------ + PyArrayObject *neighbours, *neighbour_edges, + *normals, *edgelengths, *radii, *areas, + *tri_full_flag, + *stage_edge_values, + *xmom_edge_values, + *ymom_edge_values, + *bed_edge_values, + *stage_boundary_values, + *xmom_boundary_values, + *ymom_boundary_values, + *stage_explicit_update, + *xmom_explicit_update, + *ymom_explicit_update, + *already_computed_flux, //Tracks whether the flux across an edge has already been computed + *max_speed_array; //Keeps track of max speeds for each triangle + + + double timestep, epsilon, H0, g; + long optimise_dry_cells; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "ddddOOOOOOOOOOOOOOOOOOOi", + ×tep, + &epsilon, + &H0, + &g, + &neighbours, + &neighbour_edges, + &normals, + &edgelengths, &radii, &areas, + &tri_full_flag, + &stage_edge_values, + &xmom_edge_values, + &ymom_edge_values, + &bed_edge_values, + &stage_boundary_values, + &xmom_boundary_values, + &ymom_boundary_values, + &stage_explicit_update, + &xmom_explicit_update, + &ymom_explicit_update, + &already_computed_flux, + &max_speed_array, + &optimise_dry_cells)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } - // Get vertex stage values for gradient calculation - w0 = (D->stage_vertex_values)[k3 + 0]; - w1 = (D->stage_vertex_values)[k3 + 1]; - w2 = (D->stage_vertex_values)[k3 + 2]; + // check that numpy array objects arrays are C contiguous memory + CHECK_C_CONTIG(neighbours); + CHECK_C_CONTIG(neighbour_edges); + CHECK_C_CONTIG(normals); + CHECK_C_CONTIG(edgelengths); + CHECK_C_CONTIG(radii); + CHECK_C_CONTIG(areas); + CHECK_C_CONTIG(tri_full_flag); + CHECK_C_CONTIG(stage_edge_values); + CHECK_C_CONTIG(xmom_edge_values); + CHECK_C_CONTIG(ymom_edge_values); + CHECK_C_CONTIG(bed_edge_values); + CHECK_C_CONTIG(stage_boundary_values); + CHECK_C_CONTIG(xmom_boundary_values); + CHECK_C_CONTIG(ymom_boundary_values); + CHECK_C_CONTIG(stage_explicit_update); + CHECK_C_CONTIG(xmom_explicit_update); + CHECK_C_CONTIG(ymom_explicit_update); + CHECK_C_CONTIG(already_computed_flux); + CHECK_C_CONTIG(max_speed_array); + + int number_of_elements = stage_edge_values -> dimensions[0]; + + // Call underlying flux computation routine and update + // the explicit update arrays + timestep = _compute_fluxes_central(number_of_elements, + timestep, + epsilon, + H0, + g, + (long*) neighbours -> data, + (long*) neighbour_edges -> data, + (double*) normals -> data, + (double*) edgelengths -> data, + (double*) radii -> data, + (double*) areas -> data, + (long*) tri_full_flag -> data, + (double*) stage_edge_values -> data, + (double*) xmom_edge_values -> data, + (double*) ymom_edge_values -> data, + (double*) bed_edge_values -> data, + (double*) stage_boundary_values -> data, + (double*) xmom_boundary_values -> data, + (double*) ymom_boundary_values -> data, + (double*) stage_explicit_update -> data, + (double*) xmom_explicit_update -> data, + (double*) ymom_explicit_update -> data, + (long*) already_computed_flux -> data, + (double*) max_speed_array -> data, + optimise_dry_cells); + + // Return updated flux timestep + return Py_BuildValue("d", timestep); +} - // Compute stage slope - k6 = 6 * k; // base index +PyObject *compute_fluxes_ext_central_structure(PyObject *self, PyObject *args) { + /*Compute all fluxes and the timestep suitable for all volumes + in domain. - x0 = (D->vertex_coordinates)[k6 + 0]; - y0 = (D->vertex_coordinates)[k6 + 1]; - x1 = (D->vertex_coordinates)[k6 + 2]; - y1 = (D->vertex_coordinates)[k6 + 3]; - x2 = (D->vertex_coordinates)[k6 + 4]; - y2 = (D->vertex_coordinates)[k6 + 5]; + Compute total flux for each conserved quantity using "flux_function_central" - //printf("x0 %g, y0 %g, x1 %g, y1 %g, x2 %g, y2 %g \n",x0,y0,x1,y1,x2,y2); - _gradient(x0, y0, x1, y1, x2, y2, w0, w1, w2, &wx, &wy); + Fluxes across each edge are scaled by edgelengths and summed up + Resulting flux is then scaled by area and stored in + explicit_update for each of the three conserved quantities + stage, xmomentum and ymomentum - avg_h = (D->stage_centroid_values)[k] - (D->bed_centroid_values)[k]; + The maximal allowable speed computed by the flux_function for each volume + is converted to a timestep that must not be exceeded. The minimum of + those is computed as the next overall timestep. - // Update using -ghw_x term - (D->xmom_explicit_update)[k] += -g * wx*avg_h; - (D->ymom_explicit_update)[k] += -g * wy*avg_h; + Python call: + domain.timestep = compute_fluxes_ext_central_structure(domain, timestep) - //------------------------------------ - // Calculate side terms \sum_i 0.5 g l_i h_i^2 n_i - //------------------------------------ - // Getself.stage_c = self.domain.quantities['stage'].centroid_values edge depths - hh[0] = (D->stage_edge_values)[k3 + 0] - (D->bed_edge_values)[k3 + 0]; - hh[1] = (D->stage_edge_values)[k3 + 1] - (D->bed_edge_values)[k3 + 1]; - hh[2] = (D->stage_edge_values)[k3 + 2] - (D->bed_edge_values)[k3 + 2]; + Post conditions: + domain.explicit_update is reset to computed flux values + domain.timestep is set to the largest step satisfying all volumes. - //printf("h0,1,2 %f %f %f\n",hh[0],hh[1],hh[2]); + */ - // Calculate the side correction term - sidex = 0.0; - sidey = 0.0; + struct domain D; + PyObject *domain; + double timestep; + + if (!PyArg_ParseTuple(args, "O", &domain)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // populate the C domain structure with pointers + // to the python domain data + get_python_domain(&D, domain); + + // Call underlying flux computation routine and update + // the explicit update arrays + timestep = _compute_fluxes_central_structure(&D); + + + return Py_BuildValue("d", timestep); +} + + +PyObject *compute_fluxes_ext_wb(PyObject *self, PyObject *args) { + /*Compute all fluxes and the timestep suitable for all volumes + in domain. + + Compute total flux for each conserved quantity using "flux_function_central" + + Fluxes across each edge are scaled by edgelengths and summed up + Resulting flux is then scaled by area and stored in + explicit_update for each of the three conserved quantities + stage, xmomentum and ymomentum + + The + + The maximal allowable speed computed by the flux_function for each volume + is converted to a timestep that must not be exceeded. The minimum of + those is computed as the next overall timestep. + + Python call: + domain.timestep = compute_fluxes_ext_wb(domain, timestep) + + + Post conditions: + domain.explicit_update is reset to computed flux values + + Returns: + timestep which is the largest step satisfying all volumes. + + + */ + + struct domain D; + PyObject *domain; + double timestep; + + if (!PyArg_ParseTuple(args, "O", &domain)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // populate the C domain structure with pointers + // to the python domain data + get_python_domain(&D, domain); + + // Call underlying flux computation routine and update + // the explicit update arrays + timestep = _compute_fluxes_central_wb(&D); + + + + return Py_BuildValue("d", timestep); +} + +PyObject *compute_fluxes_ext_wb_3(PyObject *self, PyObject *args) { + /*Compute all fluxes and the timestep suitable for all volumes + in domain. + + Compute total flux for each conserved quantity using "flux_function_central" + + Fluxes across each edge are scaled by edgelengths and summed up + Resulting flux is then scaled by area and stored in + explicit_update for each of the three conserved quantities + stage, xmomentum and ymomentum + + The maximal allowable speed computed by the flux_function for each volume + is converted to a timestep that must not be exceeded. The minimum of + those is computed as the next overall timestep. + + Python call: + domain.timestep = compute_fluxes_ext_wb_3(domain, timestep) + + + Post conditions: + domain.explicit_update is reset to computed flux values + + Returns: + timestep which is the largest step satisfying all volumes. + + + */ + + struct domain D; + PyObject *domain; + double timestep; + + if (!PyArg_ParseTuple(args, "O", &domain)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // populate the C domain structure with pointers + // to the python domain data + get_python_domain(&D, domain); + + // Call underlying flux computation routine and update + // the explicit update arrays + timestep = _compute_fluxes_central_wb_3(&D); + + + return Py_BuildValue("d", timestep); +} + +PyObject *compute_fluxes_ext_kinetic(PyObject *self, PyObject *args) { + /*Compute all fluxes and the timestep suitable for all volumes + in domain. + + THIS IS AN EXPERIMENTAL FUNCTION - NORMALLY flux_function_central IS USED. + + Compute total flux for each conserved quantity using "flux_function_kinetic" + + Fluxes across each edge are scaled by edgelengths and summed up + Resulting flux is then scaled by area and stored in + explicit_update for each of the three conserved quantities + stage, xmomentum and ymomentum + + The maximal allowable speed computed by the flux_function for each volume + is converted to a timestep that must not be exceeded. The minimum of + those is computed as the next overall timestep. + + Python call: + domain.timestep = compute_fluxes(timestep, + domain.epsilon, + domain.H0, + domain.g, + domain.neighbours, + domain.neighbour_edges, + domain.normals, + domain.edgelengths, + domain.radii, + domain.areas, + Stage.edge_values, + Xmom.edge_values, + Ymom.edge_values, + Bed.edge_values, + Stage.boundary_values, + Xmom.boundary_values, + Ymom.boundary_values, + Stage.explicit_update, + Xmom.explicit_update, + Ymom.explicit_update, + already_computed_flux) + + + Post conditions: + domain.explicit_update is reset to computed flux values + domain.timestep is set to the largest step satisfying all volumes. + + + */ + + + PyArrayObject *neighbours, *neighbour_edges, + *normals, *edgelengths, *radii, *areas, + *tri_full_flag, + *stage_edge_values, + *xmom_edge_values, + *ymom_edge_values, + *bed_edge_values, + *stage_boundary_values, + *xmom_boundary_values, + *ymom_boundary_values, + *stage_explicit_update, + *xmom_explicit_update, + *ymom_explicit_update, + *already_computed_flux; // Tracks whether the flux across an edge has already been computed + + + // Local variables + double timestep, max_speed, epsilon, g, H0; + double normal[2], ql[3], qr[3], zl, zr; + double edgeflux[3]; //Work arrays for summing up fluxes + + int number_of_elements, k, i, m, n; + int ki, nm = 0, ki2; //Index shorthands + static long call = 1; + + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "ddddOOOOOOOOOOOOOOOOOO", + ×tep, + &epsilon, + &H0, + &g, + &neighbours, + &neighbour_edges, + &normals, + &edgelengths, &radii, &areas, + &tri_full_flag, + &stage_edge_values, + &xmom_edge_values, + &ymom_edge_values, + &bed_edge_values, + &stage_boundary_values, + &xmom_boundary_values, + &ymom_boundary_values, + &stage_explicit_update, + &xmom_explicit_update, + &ymom_explicit_update, + &already_computed_flux)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + number_of_elements = stage_edge_values -> dimensions[0]; + call++; //a static local variable to which already_computed_flux is compared + //set explicit_update to zero for all conserved_quantities. + //This assumes compute_fluxes called before forcing terms + for (k = 0; k < number_of_elements; k++) { + ((double *) stage_explicit_update -> data)[k] = 0.0; + ((double *) xmom_explicit_update -> data)[k] = 0.0; + ((double *) ymom_explicit_update -> data)[k] = 0.0; + } + //Loop through neighbours and compute edge flux for each + for (k = 0; k < number_of_elements; k++) { for (i = 0; i < 3; i++) { - n0 = (D->normals)[k6 + 2 * i]; - n1 = (D->normals)[k6 + 2 * i + 1]; + ki = k * 3 + i; + if (((long *) already_computed_flux->data)[ki] == call)//we've already computed the flux across this edge + continue; + ql[0] = ((double *) stage_edge_values -> data)[ki]; + ql[1] = ((double *) xmom_edge_values -> data)[ki]; + ql[2] = ((double *) ymom_edge_values -> data)[ki]; + zl = ((double *) bed_edge_values -> data)[ki]; - //printf("n0, n1 %i %g %g\n",i,n0,n1); - fact = -0.5 * g * hh[i] * hh[i] * (D->edgelengths)[k3 + i]; - sidex = sidex + fact*n0; - sidey = sidey + fact*n1; - } + //Quantities at neighbour on nearest face + n = ((long *) neighbours -> data)[ki]; + if (n < 0) { + m = -n - 1; //Convert negative flag to index + qr[0] = ((double *) stage_boundary_values -> data)[m]; + qr[1] = ((double *) xmom_boundary_values -> data)[m]; + qr[2] = ((double *) ymom_boundary_values -> data)[m]; + zr = zl; //Extend bed elevation to boundary + } else { + m = ((long *) neighbour_edges -> data)[ki]; + nm = n * 3 + m; + qr[0] = ((double *) stage_edge_values -> data)[nm]; + qr[1] = ((double *) xmom_edge_values -> data)[nm]; + qr[2] = ((double *) ymom_edge_values -> data)[nm]; + zr = ((double *) bed_edge_values -> data)[nm]; + } + // Outward pointing normal vector + // normal = domain.normals[k, 2*i:2*i+2] + ki2 = 2 * ki; //k*6 + i*2 + normal[0] = ((double *) normals -> data)[ki2]; + normal[1] = ((double *) normals -> data)[ki2 + 1]; + //Edge flux computation + flux_function_kinetic(ql, qr, zl, zr, + normal[0], normal[1], + epsilon, H0, g, + edgeflux, &max_speed); + //update triangle k + ((long *) already_computed_flux->data)[ki] = call; + ((double *) stage_explicit_update -> data)[k] -= edgeflux[0]*((double *) edgelengths -> data)[ki]; + ((double *) xmom_explicit_update -> data)[k] -= edgeflux[1]*((double *) edgelengths -> data)[ki]; + ((double *) ymom_explicit_update -> data)[k] -= edgeflux[2]*((double *) edgelengths -> data)[ki]; + //update the neighbour n + if (n >= 0) { + ((long *) already_computed_flux->data)[nm] = call; + ((double *) stage_explicit_update -> data)[n] += edgeflux[0]*((double *) edgelengths -> data)[nm]; + ((double *) xmom_explicit_update -> data)[n] += edgeflux[1]*((double *) edgelengths -> data)[nm]; + ((double *) ymom_explicit_update -> data)[n] += edgeflux[2]*((double *) edgelengths -> data)[nm]; + } + ///for (j=0; j<3; j++) { + ///flux[j] -= edgeflux[j]*((double *) edgelengths -> data)[ki]; + ///} + //Update timestep + //timestep = min(timestep, domain.radii[k]/max_speed) + //FIXME: SR Add parameter for CFL condition + if (((long *) tri_full_flag -> data)[k] == 1) { + if (max_speed > epsilon) { + timestep = min(timestep, ((double *) radii -> data)[k] / max_speed); + //maxspeed in flux_function is calculated as max(|u+a|,|u-a|) + if (n >= 0) + timestep = min(timestep, ((double *) radii -> data)[n] / max_speed); + } + } + } // end for i + //Normalise by area and store for when all conserved + //quantities get updated + ((double *) stage_explicit_update -> data)[k] /= ((double *) areas -> data)[k]; + ((double *) xmom_explicit_update -> data)[k] /= ((double *) areas -> data)[k]; + ((double *) ymom_explicit_update -> data)[k] /= ((double *) areas -> data)[k]; + } //end for k + return Py_BuildValue("d", timestep); +} + +PyObject *protect(PyObject *self, PyObject *args) { + // + // protect(minimum_allowed_height, maximum_allowed_speed, wc, zc, xmomc, ymomc) + + + PyArrayObject + *wc, //Stage at centroids + *zc, //Elevation at centroids + *xmomc, //Momentums at centroids + *ymomc; - // Update momentum with side terms - area = (D->areas)[k]; - (D->xmom_explicit_update)[k] += -sidex / area; - (D->ymom_explicit_update)[k] += -sidey / area; + int N; + double minimum_allowed_height, maximum_allowed_speed, epsilon; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "dddOOOO", + &minimum_allowed_height, + &maximum_allowed_speed, + &epsilon, + &wc, &zc, &xmomc, &ymomc)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; } - return 0; -} \ No newline at end of file + + N = wc -> dimensions[0]; + + _protect(N, + minimum_allowed_height, + maximum_allowed_speed, + epsilon, + (double*) wc -> data, + (double*) zc -> data, + (double*) xmomc -> data, + (double*) ymomc -> data); + + return Py_BuildValue(""); +} + +PyObject *balance_deep_and_shallow(PyObject *self, PyObject *args) { + // Compute linear combination between stage as computed by + // gradient-limiters limiting using w, and stage computed by + // gradient-limiters limiting using h (h-limiter). + // The former takes precedence when heights are large compared to the + // bed slope while the latter takes precedence when heights are + // relatively small. Anything in between is computed as a balanced + // linear combination in order to avoid numerical disturbances which + // would otherwise appear as a result of hard switching between + // modes. + // + // balance_deep_and_shallow(wc, zc, wv, zv, + // xmomc, ymomc, xmomv, ymomv) + + + PyArrayObject + *wc, //Stage at centroids + *zc, //Elevation at centroids + *wv, //Stage at vertices + *zv, //Elevation at vertices + *hvbar, //h-Limited depths at vertices + *xmomc, //Momentums at centroids and vertices + *ymomc, + *xmomv, + *ymomv; + + PyObject *domain, *Tmp; + + double alpha_balance = 2.0; + double H0; + + int N, tight_slope_limiters, use_centroid_velocities; //, err; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "OOOOOOOOOO", + &domain, + &wc, &zc, + &wv, &zv, &hvbar, + &xmomc, &ymomc, &xmomv, &ymomv)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + + // FIXME (Ole): I tested this without GetAttrString and got time down + // marginally from 4.0s to 3.8s. Consider passing everything in + // through ParseTuple and profile. + + // Pull out parameters + Tmp = PyObject_GetAttrString(domain, "alpha_balance"); + if (!Tmp) { + report_python_error(AT, "could not obtain object alpha_balance from domain"); + return NULL; + } + alpha_balance = PyFloat_AsDouble(Tmp); + Py_DECREF(Tmp); + + + Tmp = PyObject_GetAttrString(domain, "H0"); + if (!Tmp) { + report_python_error(AT, "could not obtain object H0 from domain"); + return NULL; + } + H0 = PyFloat_AsDouble(Tmp); + Py_DECREF(Tmp); + + + Tmp = PyObject_GetAttrString(domain, "tight_slope_limiters"); + if (!Tmp) { + report_python_error(AT, "could not obtain object tight_slope_limiters from domain"); + return NULL; + } + tight_slope_limiters = PyInt_AsLong(Tmp); + Py_DECREF(Tmp); + + + Tmp = PyObject_GetAttrString(domain, "use_centroid_velocities"); + if (!Tmp) { + report_python_error(AT, "could not obtain object use_centroid_velocities from domain"); + return NULL; + } + use_centroid_velocities = PyInt_AsLong(Tmp); + Py_DECREF(Tmp); + + + + N = wc -> dimensions[0]; + _balance_deep_and_shallow(N, + (double*) wc -> data, + (double*) zc -> data, + (double*) wv -> data, + (double*) zv -> data, + (double*) hvbar -> data, + (double*) xmomc -> data, + (double*) ymomc -> data, + (double*) xmomv -> data, + (double*) ymomv -> data, + H0, + (int) tight_slope_limiters, + (int) use_centroid_velocities, + alpha_balance); + + + return Py_BuildValue(""); +} + +PyObject *assign_windfield_values(PyObject *self, PyObject *args) { + // + // assign_windfield_values(xmom_update, ymom_update, + // s_vec, phi_vec, self.const) + + + + PyArrayObject //(one element per triangle) + *s_vec, //Speeds + *phi_vec, //Bearings + *xmom_update, //Momentum updates + *ymom_update; + + + int N; + double cw; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "OOOOd", + &xmom_update, + &ymom_update, + &s_vec, &phi_vec, + &cw)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + + N = xmom_update -> dimensions[0]; + + _assign_wind_field_values(N, + (double*) xmom_update -> data, + (double*) ymom_update -> data, + (double*) s_vec -> data, + (double*) phi_vec -> data, + cw); + + return Py_BuildValue(""); +} + + + + +//------------------------------- +// Method table for python module +//------------------------------- +static struct PyMethodDef MethodTable[] = { + /* The cast of the function is necessary since PyCFunction values + * only take two PyObject* parameters, and rotate() takes + * three. + */ + + {"rotate", (PyCFunction) rotate, METH_VARARGS | METH_KEYWORDS, "Print out"}, + {"extrapolate_second_order_sw", extrapolate_second_order_sw, METH_VARARGS, "Print out"}, + {"extrapolate_second_order_sw_old", extrapolate_second_order_sw_old, METH_VARARGS, "Print out"}, + {"extrapolate_second_order_edge_sw", extrapolate_second_order_edge_sw, METH_VARARGS, "Print out"}, + {"compute_fluxes_ext_wb", compute_fluxes_ext_wb, METH_VARARGS, "Print out"}, + {"compute_fluxes_ext_wb_3", compute_fluxes_ext_wb_3, METH_VARARGS, "Print out"}, + {"compute_fluxes_ext_central", compute_fluxes_ext_central, METH_VARARGS, "Print out"}, + {"compute_fluxes_ext_central_structure", compute_fluxes_ext_central_structure, METH_VARARGS, "Print out"}, + {"compute_fluxes_ext_kinetic", compute_fluxes_ext_kinetic, METH_VARARGS, "Print out"}, + {"gravity", gravity, METH_VARARGS, "Print out"}, + {"gravity_wb", gravity_wb, METH_VARARGS, "Print out"}, + {"manning_friction_flat", manning_friction_flat, METH_VARARGS, "Print out"}, + {"manning_friction_sloped", manning_friction_sloped, METH_VARARGS, "Print out"}, + {"chezy_friction", chezy_friction, METH_VARARGS, "Print out"}, + {"flux_function_central", flux_function_central, METH_VARARGS, "Print out"}, + {"balance_deep_and_shallow", balance_deep_and_shallow, + METH_VARARGS, "Print out"}, + {"protect", protect, METH_VARARGS | METH_KEYWORDS, "Print out"}, + {"assign_windfield_values", assign_windfield_values, + METH_VARARGS | METH_KEYWORDS, "Print out"}, + {NULL, NULL} +}; + +// Module initialisation + +void initshallow_water_ext(void) { + Py_InitModule("shallow_water_ext", MethodTable); + + import_array(); // Necessary for handling of NumPY structures +} diff --git a/anuga/shallow_water/shallow_water_ext.pyx b/anuga/shallow_water/shallow_water_ext.pyx deleted file mode 100644 index 87d1c7ce7..000000000 --- a/anuga/shallow_water/shallow_water_ext.pyx +++ /dev/null @@ -1,526 +0,0 @@ -#cython: wraparound=False, boundscheck=False, cdivision=True, profile=False, nonecheck=False, overflowcheck=False, cdivision_warnings=False, unraisable_tracebacks=False -import cython - -# import both numpy and the Cython declarations for numpy -import numpy as np -cimport numpy as np - -cdef extern from "shallow_water.c": - struct domain: - long number_of_elements - double epsilon - double H0 - double g - long optimise_dry_cells - double evolve_max_timestep - long extrapolate_velocity_second_order - double minimum_allowed_height - double maximum_allowed_speed - long low_froude - long timestep_fluxcalls - double beta_w - double beta_w_dry - double beta_uh - double beta_uh_dry - double beta_vh - double beta_vh_dry - long max_flux_update_frequency - long ncol_riverwall_hydraulic_properties - long* neighbours - long* neighbour_edges - long* surrogate_neighbours - double* normals - double* edgelengths - double* radii - double* areas - long* edge_flux_type - long* tri_full_flag - long* already_computed_flux - double* max_speed - double* vertex_coordinates - double* edge_coordinates - double* centroid_coordinates - long* number_of_boundaries - double* stage_edge_values - double* xmom_edge_values - double* ymom_edge_values - double* bed_edge_values - double* height_edge_values - double* stage_centroid_values - double* xmom_centroid_values - double* ymom_centroid_values - double* bed_centroid_values - double* height_centroid_values - double* stage_vertex_values - double* xmom_vertex_values - double* ymom_vertex_values - double* bed_vertex_values - double* height_vertex_values - double* stage_boundary_values - double* xmom_boundary_values - double* ymom_boundary_values - double* bed_boundary_values - double* stage_explicit_update - double* xmom_explicit_update - double* ymom_explicit_update - long* flux_update_frequency - long* update_next_flux - long* update_extrapolation - double* edge_timestep - double* edge_flux_work - double* pressuregrad_work - double* x_centroid_work - double* y_centroid_work - double* boundary_flux_sum - long* allow_timestep_increase - double* riverwall_elevation - long* riverwall_rowIndex - double* riverwall_hydraulic_properties - struct edge: - pass - int _rotate(double *q, double n1, double n2) - int _flux_function_central(double* q_left, double* q_right, double z_left, double z_right, double n1, double n2, double epsilon, double h0, double limiting_threshold, double g, double* edgeflux, double* max_speed) - int _extrapolate_second_order_sw(domain* D) - double _compute_fluxes_central_structure(domain* D) - int _gravity(domain* D) - int _gravity_wb(domain* D) - double _compute_fluxes_central_wb(domain* D) - double _compute_fluxes_central_wb_3(domain* D) - int _protect(int N, double minimum_allowed_height, double maximum_allowed_speed, double epsilon, double* wc, double* zc, double* xmomc, double* ymomc) - int _balance_deep_and_shallow(int N, double* wc, double* zc, double* wv, double* zv, double* hvbar, double* xmomc, double* ymomc, double* xmomv, double* ymomv, double H0, int tight_slope_limiters, int use_centroid_velocities, double alpha_balance) - void _manning_friction_flat(double g, double eps, int N, double* w, double* zv, double* uh, double* vh, double* eta, double* xmom, double* ymom) - void _manning_friction_sloped(double g, double eps, int N, double* x, double* w, double* zv, double* uh, double* vh, double* eta, double* xmom_update, double* ymom_update) - -cdef inline get_python_domain(domain* D, object domain_object): - - cdef np.ndarray[long, ndim=2, mode="c"] neighbours - cdef np.ndarray[long, ndim=2, mode="c"] neighbour_edges - cdef np.ndarray[double, ndim=2, mode="c"] normals - cdef np.ndarray[double, ndim=2, mode="c"] edgelengths - cdef np.ndarray[double, ndim=1, mode="c"] radii - cdef np.ndarray[double, ndim=1, mode="c"] areas - cdef np.ndarray[long, ndim=1, mode="c"] edge_flux_type - cdef np.ndarray[long, ndim=1, mode="c"] tri_full_flag - cdef np.ndarray[long, ndim=2, mode="c"] already_computed_flux - cdef np.ndarray[double, ndim=2, mode="c"] vertex_coordinates - cdef np.ndarray[double, ndim=2, mode="c"] edge_coordinates - cdef np.ndarray[double, ndim=2, mode="c"] centroid_coordinates - cdef np.ndarray[long, ndim=1, mode="c"] number_of_boundaries - cdef np.ndarray[long, ndim=2, mode="c"] surrogate_neighbours - cdef np.ndarray[double, ndim=1, mode="c"] max_speed - cdef np.ndarray[long, ndim=1, mode="c"] flux_update_frequency - cdef np.ndarray[long, ndim=1, mode="c"] update_next_flux - cdef np.ndarray[long, ndim=1, mode="c"] update_extrapolation - cdef np.ndarray[long, ndim=1, mode="c"] allow_timestep_increase - cdef np.ndarray[double, ndim=1, mode="c"] edge_timestep - cdef np.ndarray[double, ndim=1, mode="c"] edge_flux_work - cdef np.ndarray[double, ndim=1, mode="c"] pressuregrad_work - cdef np.ndarray[double, ndim=1, mode="c"] x_centroid_work - cdef np.ndarray[double, ndim=1, mode="c"] y_centroid_work - cdef np.ndarray[double, ndim=1, mode="c"] boundary_flux_sum - cdef np.ndarray[double, ndim=1, mode="c"] riverwall_elevation - cdef np.ndarray[long, ndim=1, mode="c"] riverwall_rowIndex - cdef np.ndarray[double, ndim=2, mode="c"] riverwall_hydraulic_properties - - cdef np.ndarray[double, ndim=2, mode="c"] edge_values - cdef np.ndarray[double, ndim=1, mode="c"] centroid_values - cdef np.ndarray[double, ndim=2, mode="c"] vertex_values - cdef np.ndarray[double, ndim=1, mode="c"] boundary_values - cdef np.ndarray[double, ndim=1, mode="c"] explicit_update - - cdef object quantities - cdef object riverwallData - - D.number_of_elements = domain_object.number_of_elements - D.epsilon = domain_object.epsilon - D.H0 = domain_object.H0 - D.g = domain_object.g - D.optimise_dry_cells = domain_object.optimise_dry_cells - D.evolve_max_timestep = domain_object.evolve_max_timestep - D.minimum_allowed_height = domain_object.minimum_allowed_height - D.maximum_allowed_speed = domain_object.maximum_allowed_speed - D.timestep_fluxcalls = domain_object.timestep_fluxcalls - D.low_froude = domain_object.low_froude - D.extrapolate_velocity_second_order = domain_object.extrapolate_velocity_second_order - D.beta_w = domain_object.beta_w - D.beta_w_dry = domain_object.beta_w_dry - D.beta_uh = domain_object.beta_uh - D.beta_uh_dry = domain_object.beta_uh_dry - D.beta_vh = domain_object.beta_vh - D.beta_vh_dry = domain_object.beta_vh_dry - D.max_flux_update_frequency = domain_object.max_flux_update_frequency - - neighbours = domain_object.neighbours - D.neighbours = &neighbours[0,0] - - surrogate_neighbours = domain_object.surrogate_neighbours - D.surrogate_neighbours = &surrogate_neighbours[0,0] - - neighbour_edges = domain_object.neighbour_edges - D.neighbour_edges = &neighbour_edges[0,0] - - normals = domain_object.normals - D.normals = &normals[0,0] - - edgelengths = domain_object.edgelengths - D.edgelengths = &edgelengths[0,0] - - radii = domain_object.radii - D.radii = &radii[0] - - areas = domain_object.areas - D.areas = &areas[0] - - edge_flux_type = domain_object.edge_flux_type - D.edge_flux_type = &edge_flux_type[0] - - tri_full_flag = domain_object.tri_full_flag - D.tri_full_flag = &tri_full_flag[0] - - already_computed_flux = domain_object.already_computed_flux - D.already_computed_flux = &already_computed_flux[0,0] - - vertex_coordinates = domain_object.vertex_coordinates - D.vertex_coordinates = &vertex_coordinates[0,0] - - edge_coordinates = domain_object.edge_coordinates - D.edge_coordinates = &edge_coordinates[0,0] - - centroid_coordinates = domain_object.centroid_coordinates - D.centroid_coordinates = ¢roid_coordinates[0,0] - - max_speed = domain_object.max_speed - D.max_speed = &max_speed[0] - - number_of_boundaries = domain_object.number_of_boundaries - D.number_of_boundaries = &number_of_boundaries[0] - - flux_update_frequency = domain_object.flux_update_frequency - D.flux_update_frequency = &flux_update_frequency[0] - - update_next_flux = domain_object.update_next_flux - D.update_next_flux = &update_next_flux[0] - - update_extrapolation = domain_object.update_extrapolation - D.update_extrapolation = &update_extrapolation[0] - - allow_timestep_increase = domain_object.allow_timestep_increase - D.allow_timestep_increase = &allow_timestep_increase[0] - - edge_timestep = domain_object.edge_timestep - D.edge_timestep = &edge_timestep[0] - - edge_flux_work = domain_object.edge_flux_work - D.edge_flux_work = &edge_flux_work[0] - - pressuregrad_work = domain_object.pressuregrad_work - D.pressuregrad_work = &pressuregrad_work[0] - - x_centroid_work = domain_object.x_centroid_work - D.x_centroid_work = &x_centroid_work[0] - - y_centroid_work = domain_object.y_centroid_work - D.y_centroid_work = &y_centroid_work[0] - - boundary_flux_sum = domain_object.boundary_flux_sum - D.boundary_flux_sum = &boundary_flux_sum[0] - - quantities = domain_object.quantities - - edge_values = quantities["stage"].edge_values - D.stage_edge_values = &edge_values[0,0] - - edge_values = quantities["xmomentum"].edge_values - D.xmom_edge_values = &edge_values[0,0] - - edge_values = quantities["ymomentum"].edge_values - D.ymom_edge_values = &edge_values[0,0] - - edge_values = quantities["elevation"].edge_values - D.bed_edge_values = &edge_values[0,0] - - edge_values = quantities["height"].edge_values - D.height_edge_values = &edge_values[0,0] - - centroid_values = quantities["stage"].centroid_values - D.stage_centroid_values = ¢roid_values[0] - - centroid_values = quantities["xmomentum"].centroid_values - D.xmom_centroid_values = ¢roid_values[0] - - centroid_values = quantities["ymomentum"].centroid_values - D.ymom_centroid_values = ¢roid_values[0] - - centroid_values = quantities["elevation"].centroid_values - D.bed_centroid_values = ¢roid_values[0] - - centroid_values = quantities["height"].centroid_values - D.height_centroid_values = ¢roid_values[0] - - vertex_values = quantities["stage"].vertex_values - D.stage_vertex_values = &vertex_values[0,0] - - vertex_values = quantities["xmomentum"].vertex_values - D.xmom_vertex_values = &vertex_values[0,0] - - vertex_values = quantities["ymomentum"].vertex_values - D.ymom_vertex_values = &vertex_values[0,0] - - vertex_values = quantities["elevation"].vertex_values - D.bed_vertex_values = &vertex_values[0,0] - - vertex_values = quantities["height"].vertex_values - D.height_vertex_values = &vertex_values[0,0] - - boundary_values = quantities["stage"].boundary_values - D.stage_boundary_values = &boundary_values[0] - - boundary_values = quantities["xmomentum"].boundary_values - D.xmom_boundary_values = &boundary_values[0] - - boundary_values = quantities["ymomentum"].boundary_values - D.ymom_boundary_values = &boundary_values[0] - - boundary_values = quantities["elevation"].boundary_values - D.bed_boundary_values = &boundary_values[0] - - explicit_update = quantities["stage"].explicit_update - D.stage_explicit_update = &explicit_update[0] - - explicit_update = quantities["xmomentum"].explicit_update - D.xmom_explicit_update = &explicit_update[0] - - explicit_update = quantities["ymomentum"].explicit_update - D.ymom_explicit_update = &explicit_update[0] - - riverwallData = domain_object.riverwallData - - riverwall_elevation = riverwallData.riverwall_elevation - D.riverwall_elevation = &riverwall_elevation[0] - - riverwall_rowIndex = riverwallData.hydraulic_properties_rowIndex - D.riverwall_rowIndex = &riverwall_rowIndex[0] - - D.ncol_riverwall_hydraulic_properties = riverwallData.ncol_hydraulic_properties - - riverwall_hydraulic_properties = riverwallData.hydraulic_properties - D.riverwall_hydraulic_properties = &riverwall_hydraulic_properties[0,0] - -def rotate(np.ndarray[double, ndim=1, mode="c"] q not None, np.ndarray[double, ndim=1, mode="c"] normal not None, int direction): - - assert normal.shape[0] == 2, "Normal vector must have 2 components" - - cdef np.ndarray[double, ndim=1, mode="c"] r - cdef double n1, n2 - - n1 = normal[0] - n2 = normal[1] - - if direction == -1: - n2 = -n2 - - r = np.ascontiguousarray(np.copy(q)) - - _rotate(&r[0], n1, n2) - - return r - -def flux_function_central(np.ndarray[double, ndim=1, mode="c"] normal not None,\ - np.ndarray[double, ndim=1, mode="c"] ql not None,\ - np.ndarray[double, ndim=1, mode="c"] qr not None,\ - double zl,\ - double zr,\ - np.ndarray[double, ndim=1, mode="c"] edgeflux not None,\ - double epsilon,\ - double g,\ - double H0): - - cdef double h0, limiting_threshold, max_speed - - h0 = H0*H0 - limiting_threshold = 10*H0 - - _flux_function_central(&ql[0], &qr[0], zl, zr, normal[0], normal[1], epsilon, h0, limiting_threshold, g, &edgeflux[0], &max_speed) - - return max_speed - -def extrapolate_second_order_sw(object domain_object): - - cdef domain D - cdef int err - - get_python_domain(&D, domain_object) - - err = _extrapolate_second_order_sw(&D) - - if err == -1: - return None - -def compute_fluxes_ext_central_structure(object domain_object): - - cdef domain D - cdef double timestep - - get_python_domain(&D, domain_object) - - timestep = _compute_fluxes_central_structure(&D) - - return timestep - -def gravity(object domain_object): - - cdef domain D - - get_python_domain(&D, domain_object) - - err = _gravity(&D) - - if err == -1: - return None - -def gravity_wb(object domain_object): - - cdef domain D - - get_python_domain(&D, domain_object) - - err = _gravity_wb(&D) - - if err == -1: - return None - -def compute_fluxes_ext_wb(object domain_object): - - cdef domain D - cdef double timestep - - get_python_domain(&D, domain_object) - - timestep = _compute_fluxes_central_wb(&D) - - return timestep - -def compute_fluxes_ext_wb_3(object domain_object): - - cdef domain D - cdef double timestep - - get_python_domain(&D, domain_object) - - timestep = _compute_fluxes_central_wb_3(&D) - - return timestep - -def protect(double minimum_allowed_height,\ - double maximum_allowed_speed,\ - double epsilon,\ - np.ndarray[double, ndim=1, mode="c"] wc not None,\ - np.ndarray[double, ndim=1, mode="c"] zc not None,\ - np.ndarray[double, ndim=1, mode="c"] xmomc not None,\ - np.ndarray[double, ndim=1, mode="c"] ymomc not None): - - cdef int N - - N = wc.shape[0] - - _protect(N, minimum_allowed_height, maximum_allowed_speed, epsilon, &wc[0], &zc[0], &xmomc[0], &ymomc[0]) - -def balance_deep_and_shallow(object domain_object,\ - np.ndarray[double, ndim=1, mode="c"] wc not None,\ - np.ndarray[double, ndim=1, mode="c"] zc not None,\ - np.ndarray[double, ndim=2, mode="c"] wv not None,\ - np.ndarray[double, ndim=2, mode="c"] zv not None,\ - np.ndarray[double, ndim=1, mode="c"] hvbar not None,\ - np.ndarray[double, ndim=1, mode="c"] xmomc not None,\ - np.ndarray[double, ndim=1, mode="c"] ymomc not None,\ - np.ndarray[double, ndim=2, mode="c"] xmomv not None,\ - np.ndarray[double, ndim=2, mode="c"] ymomv not None): - - cdef double alpha_balance = 2.0 - cdef double H0 - cdef int N, tight_slope_limiters, use_centroid_velocities - - alpha_balance = domain_object.alpha_balance - H0 = domain_object.H0 - tight_slope_limiters = domain_object.tight_slope_limiters - use_centroid_velocities = domain_object.use_centroid_velocities - - N = wc.shape[0] - - _balance_deep_and_shallow(N,\ - &wc[0],\ - &zc[0],\ - &wv[0,0],\ - &zv[0,0],\ - &hvbar[0],\ - &xmomc[0],\ - &ymomc[0],\ - &xmomv[0,0],\ - &ymomv[0,0],\ - H0,\ - tight_slope_limiters,\ - use_centroid_velocities,\ - alpha_balance) - -def manning_friction_flat(double g,\ - double eps,\ - np.ndarray[double, ndim=1, mode="c"] w not None,\ - np.ndarray[double, ndim=1, mode="c"] uh not None,\ - np.ndarray[double, ndim=1, mode="c"] vh not None,\ - np.ndarray[double, ndim=2, mode="c"] z not None,\ - np.ndarray[double, ndim=1, mode="c"] eta not None,\ - np.ndarray[double, ndim=1, mode="c"] xmom not None,\ - np.ndarray[double, ndim=1, mode="c"] ymom not None): - - - cdef int N - - N = w.shape[0] - - _manning_friction_flat(g, eps, N,\ - &w[0],\ - &z[0,0],\ - &uh[0],\ - &vh[0],\ - &eta[0],\ - &xmom[0],\ - &ymom[0]) - -def manning_friction_sloped(double g,\ - double eps,\ - np.ndarray[double, ndim=2, mode="c"] x not None,\ - np.ndarray[double, ndim=1, mode="c"] w not None,\ - np.ndarray[double, ndim=1, mode="c"] uh not None,\ - np.ndarray[double, ndim=1, mode="c"] vh not None,\ - np.ndarray[double, ndim=2, mode="c"] z not None,\ - np.ndarray[double, ndim=1, mode="c"] eta not None,\ - np.ndarray[double, ndim=1, mode="c"] xmom not None,\ - np.ndarray[double, ndim=1, mode="c"] ymom not None): - - cdef int N - - N = w.shape[0] - - _manning_friction_sloped(g, eps, N,\ - &x[0,0],\ - &w[0],\ - &z[0,0],\ - &uh[0],\ - &vh[0],\ - &eta[0],\ - &xmom[0],\ - &ymom[0]) - - - - - - - - - - - - - - diff --git a/anuga/shallow_water/swDE1_domain.c b/anuga/shallow_water/swDE1_domain_ext.c similarity index 78% rename from anuga/shallow_water/swDE1_domain.c rename to anuga/shallow_water/swDE1_domain_ext.c index 385ddfe1e..e6901d4dd 100644 --- a/anuga/shallow_water/swDE1_domain.c +++ b/anuga/shallow_water/swDE1_domain_ext.c @@ -15,11 +15,17 @@ // Gareth Davies, GA 2011 +#include "Python.h" +#include "numpy/arrayobject.h" #include "math.h" #include -#include +//#include "numpy_shim.h" + +// Shared code snippets +#include "util_ext.h" #include "sw_domain.h" + const double pi = 3.14159265358979; // Trick to compute n modulo d (n%d in python) when d is a power of 2 @@ -126,12 +132,12 @@ water model for two-dimensional dam-break type. Journal of Computational Physics int i; - double uh_left, vh_left, u_left; - double uh_right, vh_right, u_right; + double w_left, uh_left, vh_left, u_left; + double w_right, uh_right, vh_right, u_right; double s_min, s_max, soundspeed_left, soundspeed_right; - double u_m, h_m, soundspeed_m; + double u_m, h_m, soundspeed_m, s_m; double denom, inverse_denominator; - double tmp; + double uint, t1, t2, t3, min_speed, tmp, local_fr2; // Workspace (allocate once, use many) static double q_left_rotated[3], q_right_rotated[3], flux_right[3], flux_left[3]; @@ -199,16 +205,16 @@ water model for two-dimensional dam-break type. Journal of Computational Physics if(h_left < 1.0e-10){ s_min = u_right - 2.0*soundspeed_right; s_max = u_right + soundspeed_right; - //s_m = s_min; + s_m = s_min; } else if (h_right < 1.0e-10){ s_min = u_left - soundspeed_left; s_max = u_left + 2.0*soundspeed_left; - //s_m = s_max; + s_m = s_max; } else { - s_max = fmax(u_right + soundspeed_right, u_m + soundspeed_right); - s_min = fmin(u_left - soundspeed_left, u_m - soundspeed_m); + s_max = max(u_right + soundspeed_right, u_m + soundspeed_right); + s_min = min(u_left - soundspeed_left, u_m - soundspeed_m); } if (s_max < 0.0) @@ -245,9 +251,9 @@ water model for two-dimensional dam-break type. Journal of Computational Physics else { // Maximal wavespeed - *max_speed = fmax(s_max, -s_min); + *max_speed = max(s_max, -s_min); - inverse_denominator = 1.0/fmax(denom,1.0e-100); + inverse_denominator = 1.0/max(denom,1.0e-100); for (i = 0; i < 3; i++) { edgeflux[i] = s_max*flux_left[i] - s_min*flux_right[i]; @@ -255,7 +261,7 @@ water model for two-dimensional dam-break type. Journal of Computational Physics // Standard smoothing term // edgeflux[i] += 1.0*(s_max*s_min)*(q_right_rotated[i] - q_left_rotated[i]); // Smoothing by stage alone can cause high velocities / slow draining for nearly dry cells - if(i==0) edgeflux[i] += (s_max*s_min)*(fmax(q_right_rotated[i],ze) - fmax(q_left_rotated[i],ze)); + if(i==0) edgeflux[i] += (s_max*s_min)*(max(q_right_rotated[i],ze) - max(q_left_rotated[i],ze)); if(i==1) edgeflux[i] += (s_max*s_min)*(uh_right - uh_left); if(i==2) edgeflux[i] += (s_max*s_min)*(vh_right - vh_left); @@ -306,11 +312,11 @@ int _flux_function_central(double *q_left, double *q_right, int i; - double uh_left, vh_left, u_left; - double uh_right, vh_right, u_right; + double w_left, uh_left, vh_left, u_left; + double w_right, uh_right, vh_right, u_right; double s_min, s_max, soundspeed_left, soundspeed_right; double denom, inverse_denominator; - double tmp, local_fr, v_right, v_left; + double uint, t1, t2, t3, min_speed, tmp, local_fr, v_right, v_left; // Workspace (allocate once, use many) static double q_left_rotated[3], q_right_rotated[3], flux_right[3], flux_left[3]; @@ -389,7 +395,7 @@ int _flux_function_central(double *q_left, double *q_right, if (low_froude == 1) { local_fr = sqrt( - fmax(0.001, fmin(1.0, + max(0.001, min(1.0, (u_right*u_right + u_left*u_left + v_right*v_right + v_left*v_left)/ (soundspeed_left*soundspeed_left + soundspeed_right*soundspeed_right + 1.0e-10)))); } @@ -397,7 +403,7 @@ int _flux_function_central(double *q_left, double *q_right, { local_fr = sqrt((u_right*u_right + u_left*u_left + v_right*v_right + v_left*v_left)/ (soundspeed_left*soundspeed_left + soundspeed_right*soundspeed_right + 1.0e-10)); - local_fr = sqrt(fmin(1.0, 0.01 + fmax(local_fr-0.01,0.0))); + local_fr = sqrt(min(1.0, 0.01 + max(local_fr-0.01,0.0))); } else { @@ -405,7 +411,7 @@ int _flux_function_central(double *q_left, double *q_right, } //printf("local_fr %e \n:", local_fr); - s_max = fmax(u_left + soundspeed_left, u_right + soundspeed_right); + s_max = max(u_left + soundspeed_left, u_right + soundspeed_right); if (s_max < 0.0) { s_max = 0.0; @@ -416,7 +422,7 @@ int _flux_function_central(double *q_left, double *q_right, //} - s_min = fmin(u_left - soundspeed_left, u_right - soundspeed_right); + s_min = min(u_left - soundspeed_left, u_right - soundspeed_right); if (s_min > 0.0) { s_min = 0.0; @@ -449,9 +455,9 @@ int _flux_function_central(double *q_left, double *q_right, else { // Maximal wavespeed - *max_speed = fmax(s_max, -s_min); + *max_speed = max(s_max, -s_min); - inverse_denominator = 1.0/fmax(denom,1.0e-100); + inverse_denominator = 1.0/max(denom,1.0e-100); for (i = 0; i < 3; i++) { edgeflux[i] = s_max*flux_left[i] - s_min*flux_right[i]; @@ -459,7 +465,7 @@ int _flux_function_central(double *q_left, double *q_right, // Standard smoothing term // edgeflux[i] += 1.0*(s_max*s_min)*(q_right_rotated[i] - q_left_rotated[i]); // Smoothing by stage alone can cause high velocities / slow draining for nearly dry cells - if(i==0) edgeflux[i] += (s_max*s_min)*(fmax(q_right_rotated[i],ze) - fmax(q_left_rotated[i],ze)); + if(i==0) edgeflux[i] += (s_max*s_min)*(max(q_right_rotated[i],ze) - max(q_left_rotated[i],ze)); //if(i==0) edgeflux[i] += (s_max*s_min)*(h_right - h_left); if(i==1) edgeflux[i] += local_fr*(s_max*s_min)*(uh_right - uh_left); if(i==2) edgeflux[i] += local_fr*(s_max*s_min)*(vh_right - vh_left); @@ -492,7 +498,7 @@ int _compute_flux_update_frequency(struct domain *D, double timestep){ // // // Local variables - int k, i, k3, ki, m, n, nm, ii, ii2; + int k, i, k3, ki, m, n, nm, ii, j, ii2; long fuf; double notSoFast=1.0; static int cyclic_number_of_steps=-1; @@ -546,10 +552,10 @@ int _compute_flux_update_frequency(struct domain *D, double timestep){ // notSoFast is ideally = 1.0, but in practice values < 1.0 can enhance stability // NOTE: edge_timestep[ki]/timestep can be very large [so int overflows]. // Do not pull the (int) inside the min term - fuf = (int)fmin((D->edge_timestep[ki]/timestep)*notSoFast,D->max_flux_update_frequency*1.); + fuf = (int)min((D->edge_timestep[ki]/timestep)*notSoFast,D->max_flux_update_frequency*1.); // Account for neighbour if(n>=0){ - fuf = fmin( (int)fmin(D->edge_timestep[nm]/timestep*notSoFast, D->max_flux_update_frequency*1.), fuf); + fuf = min( (int)min(D->edge_timestep[nm]/timestep*notSoFast, D->max_flux_update_frequency*1.), fuf); } // Deal with notSoFast<1.0 @@ -590,13 +596,13 @@ int _compute_flux_update_frequency(struct domain *D, double timestep){ // (But, it can result in the same edge having different flux_update_freq) for( k=0; k< D->number_of_elements; k++){ k3=3*k; - ii = 1*fmin(D->flux_update_frequency[k3], - fmin(D->flux_update_frequency[k3+1], + ii = 1*min(D->flux_update_frequency[k3], + min(D->flux_update_frequency[k3+1], D->flux_update_frequency[k3+2])); - D->flux_update_frequency[k3]=fmin(ii, D->flux_update_frequency[k3]); - D->flux_update_frequency[k3+1]=fmin(ii, D->flux_update_frequency[k3+1]); - D->flux_update_frequency[k3+2]=fmin(ii,D->flux_update_frequency[k3+2]); + D->flux_update_frequency[k3]=min(ii, D->flux_update_frequency[k3]); + D->flux_update_frequency[k3+1]=min(ii, D->flux_update_frequency[k3+1]); + D->flux_update_frequency[k3+2]=min(ii,D->flux_update_frequency[k3+2]); } @@ -615,7 +621,7 @@ int _compute_flux_update_frequency(struct domain *D, double timestep){ if(n>=0){ m = D->neighbour_edges[ki]; nm = n * 3 + m; // Linear index (triangle n, edge m) - D->flux_update_frequency[ki]=fmin(D->flux_update_frequency[ki], D->flux_update_frequency[nm]); + D->flux_update_frequency[ki]=min(D->flux_update_frequency[ki], D->flux_update_frequency[nm]); } // Do we need to update the extrapolation? // (We do if the next flux computation will actually compute a flux!) @@ -654,7 +660,7 @@ double adjust_edgeflux_with_weir(double *edgeflux, // the flow over the weir is much deeper than the weir, or the // upstream/downstream water elevations are too similar double rw, rw2; // 'Raw' weir fluxes - double rwRat, hdRat,hdWrRat, scaleFlux, minhd, maxhd; + double rwRat, hdRat,hdWrRat, scaleFlux, scaleFluxS, minhd, maxhd; double w1,w2; // Weights for averaging double newFlux; double twothirds = (2.0/3.0); @@ -665,18 +671,18 @@ double adjust_edgeflux_with_weir(double *edgeflux, //double h1=1.0; // At this (tailwater height above weir) / (weir height) ratio, begin blending with shallow water solution //double h2=1.5; // At this (tailwater height above weir) / (weir height) ratio, completely use the shallow water solution - minhd = fmin(h_left, h_right); - maxhd = fmax(h_left, h_right); + minhd = min(h_left, h_right); + maxhd = max(h_left, h_right); // 'Raw' weir discharge = Qfactor*2/3*H*(2/3*g*H)**0.5 rw = Qfactor * twothirds * maxhd * sqrt(twothirds * g * maxhd); // Factor for villemonte correction rw2 = Qfactor * twothirds * minhd * sqrt(twothirds * g * minhd); // Useful ratios - rwRat = rw2 / fmax(rw, 1.0e-100); - hdRat = minhd / fmax(maxhd, 1.0e-100); + rwRat = rw2 / max(rw, 1.0e-100); + hdRat = minhd / max(maxhd, 1.0e-100); // (tailwater height above weir)/weir_height ratio - hdWrRat = minhd / fmax(weir_height, 1.0e-100); + hdWrRat = minhd / max(weir_height, 1.0e-100); // Villemonte (1947) corrected weir flow with submergence // Q = Q1*(1-Q2/Q1)**0.385 @@ -698,10 +704,10 @@ double adjust_edgeflux_with_weir(double *edgeflux, // // Weighted average constants to transition to shallow water eqn flow - w1 = fmin( fmax(hdRat-s1, 0.) / (s2-s1), 1.0); + w1 = min( max(hdRat-s1, 0.) / (s2-s1), 1.0); // Adjust again when the head is too deep relative to the weir height - w2 = fmin( fmax(hdWrRat-h1,0.) / (h2-h1), 1.0); + w2 = min( max(hdWrRat-h1,0.) / (h2-h1), 1.0); newFlux = (rw*(1.0-w1)+w1*edgeflux[0])*(1.0-w2) + w2*edgeflux[0]; @@ -711,7 +717,7 @@ double adjust_edgeflux_with_weir(double *edgeflux, scaleFlux = 0.; } - scaleFlux = fmax(scaleFlux, 0.); + scaleFlux = max(scaleFlux, 0.); edgeflux[0] = newFlux; @@ -720,16 +726,16 @@ double adjust_edgeflux_with_weir(double *edgeflux, // those in a weighted average (rather than the rescaling trick here) // If we allow the scaling to momentum to be unbounded, // velocity spikes can arise for very-shallow-flooded walls - edgeflux[1] *= fmin(scaleFlux, 10.); - edgeflux[2] *= fmin(scaleFlux, 10.); + edgeflux[1] *= min(scaleFlux, 10.); + edgeflux[2] *= min(scaleFlux, 10.); } // Adjust the max speed if (fabs(edgeflux[0]) > 0.){ - *max_speed_local = sqrt(g*(maxhd+weir_height)) + fabs(edgeflux[0]/(maxhd + 1.0e-12)); + *max_speed_local = sqrt(g*(maxhd+weir_height)) + abs(edgeflux[0]/(maxhd + 1.0e-12)); } - //*max_speed_local += fabs(edgeflux[0])/(maxhd+1.0e-100); - //*max_speed_local *= fmax(scaleFlux, 1.0); + //*max_speed_local += abs(edgeflux[0])/(maxhd+1.0e-100); + //*max_speed_local *= max(scaleFlux, 1.0); return 0; } @@ -744,20 +750,22 @@ double _compute_fluxes_central(struct domain *D, double timestep){ double limiting_threshold = 10*D->H0; long low_froude = D->low_froude; // - int k, i, m, n, ii; - int ki, nm = 0, ki2,ki3, nm3; // Index shorthands + int k, i, m, n,j, ii; + int ki,k3, nm = 0, ki2,ki3, nm3; // Index shorthands // Workspace (making them static actually made function slightly slower (Ole)) double ql[3], qr[3], edgeflux[3]; // Work array for summing up fluxes + double stage_edges[3];//Work array double bedslope_work; static double local_timestep; + int neighbours_wet[3];//Work array long RiverWall_count, substep_count; double hle, hre, zc, zc_n, Qfactor, s1, s2, h1, h2; - double pressure_flux, hc, hc_n, tmp; + double stage_edge_lim, outgoing_mass_edges, pressure_flux, hc, hc_n, tmp, tmp2; double h_left_tmp, h_right_tmp; static long call = 0; // Static local variable flagging already computed flux static long timestep_fluxcalls=1; static long base_call = 1; - double speed_max_last, weir_height; + double speed_max_last, vol, weir_height; call++; // Flag 'id' of flux calculation for this timestep @@ -831,7 +839,7 @@ double _compute_fluxes_central(struct domain *D, double timestep){ qr[1] = D->xmom_boundary_values[m]; qr[2] = D->ymom_boundary_values[m]; zr = zl; // Extend bed elevation to boundary - hre= fmax(qr[0]-zr,0.);//hle; + hre= max(qr[0]-zr,0.);//hle; } else { // Neighbour is a real triangle hc_n = D->height_centroid_values[n]; @@ -848,7 +856,7 @@ double _compute_fluxes_central(struct domain *D, double timestep){ } // Audusse magic - z_half = fmax(zl, zr); + z_half = max(zl, zr); //// Account for riverwalls if(D->edge_flux_type[ki] == 1){ @@ -860,13 +868,13 @@ double _compute_fluxes_central(struct domain *D, double timestep){ RiverWall_count += 1; // Set central bed to riverwall elevation - z_half = fmax(D->riverwall_elevation[RiverWall_count-1], z_half) ; + z_half = max(D->riverwall_elevation[RiverWall_count-1], z_half) ; } // Define h left/right for Audusse flux method - h_left = fmax(hle+zl-z_half,0.); - h_right = fmax(hre+zr-z_half,0.); + h_left = max(hle+zl-z_half,0.); + h_right = max(hre+zr-z_half,0.); // Edge flux computation (triangle k, edge i) _flux_function_central(ql, qr, @@ -880,21 +888,21 @@ double _compute_fluxes_central(struct domain *D, double timestep){ // Force weir discharge to match weir theory // FIXME: Switched off at the moment if(D->edge_flux_type[ki]==1){ - weir_height = fmax(D->riverwall_elevation[RiverWall_count-1] - fmin(zl, zr), 0.); // Reference weir height + weir_height = max(D->riverwall_elevation[RiverWall_count-1] - min(zl, zr), 0.); // Reference weir height // If the weir is not higher than both neighbouring cells, then // do not try to match the weir equation. If we do, it seems we // can get mass conservation issues (caused by large weir // fluxes in such situations) - if(D->riverwall_elevation[RiverWall_count-1] > fmax(zc, zc_n)){ + if(D->riverwall_elevation[RiverWall_count-1] > max(zc, zc_n)){ //////////////////////////////////////////////////////////////////////////////////// // Use first-order h's for weir -- as the 'upstream/downstream' heads are // measured away from the weir itself - h_left_tmp = fmax(D->stage_centroid_values[k] - z_half, 0.); + h_left_tmp = max(D->stage_centroid_values[k] - z_half, 0.); if(n >= 0){ - h_right_tmp = fmax(D->stage_centroid_values[n] - z_half, 0.); + h_right_tmp = max(D->stage_centroid_values[n] - z_half, 0.); }else{ - h_right_tmp = fmax(hc_n + zr - z_half, 0.); + h_right_tmp = max(hc_n + zr - z_half, 0.); } if( (h_left_tmp > 0.) || (h_right_tmp > 0.)){ @@ -983,7 +991,7 @@ double _compute_fluxes_central(struct domain *D, double timestep){ if(substep_count==0){ // Compute the 'edge-timesteps' (useful for setting flux_update_frequency) - tmp = 1.0 / fmax(max_speed_local, D->epsilon); + tmp = 1.0 / max(max_speed_local, D->epsilon); D->edge_timestep[ki] = D->radii[k] * tmp ; if (n >= 0) { D->edge_timestep[nm] = D->radii[n] * tmp; @@ -992,17 +1000,17 @@ double _compute_fluxes_central(struct domain *D, double timestep){ // Update the timestep if ((D->tri_full_flag[k] == 1)) { - speed_max_last = fmax(speed_max_last, max_speed_local); + speed_max_last = max(speed_max_last, max_speed_local); if (max_speed_local > D->epsilon) { // Apply CFL condition for triangles joining this edge (triangle k and triangle n) // CFL for triangle k - local_timestep = fmin(local_timestep, D->edge_timestep[ki]); + local_timestep = min(local_timestep, D->edge_timestep[ki]); if (n >= 0) { // Apply CFL condition for neigbour n (which is on the ith edge of triangle k) - local_timestep = fmin(local_timestep, D->edge_timestep[nm]); + local_timestep = min(local_timestep, D->edge_timestep[nm]); } } } @@ -1071,7 +1079,7 @@ double _compute_fluxes_central(struct domain *D, double timestep){ // Now add up stage, xmom, ymom explicit updates for(k=0; k < D->number_of_elements; k++){ - hc = fmax(D->stage_centroid_values[k] - D->bed_centroid_values[k],0.); + hc = max(D->stage_centroid_values[k] - D->bed_centroid_values[k],0.); for(i=0;i<3;i++){ // FIXME: Make use of neighbours to efficiently set things @@ -1087,7 +1095,7 @@ double _compute_fluxes_central(struct domain *D, double timestep){ // If this cell is not a ghost, and the neighbour is a boundary // condition OR a ghost cell, then add the flux to the // boundary_flux_integral - if( ((n<0) & (D->tri_full_flag[k]==1)) | ( (n>=0) && ((D->tri_full_flag[k]==1) & (D->tri_full_flag[n]==0) )) ){ + if( (n<0 & D->tri_full_flag[k]==1) | ( n>=0 && (D->tri_full_flag[k]==1 & D->tri_full_flag[n]==0)) ){ // boundary_flux_sum is an array with length = timestep_fluxcalls // For each sub-step, we put the boundary flux sum in. D->boundary_flux_sum[substep_count] += D->edge_flux_work[ki3]; @@ -1130,13 +1138,14 @@ double _protect(int N, double* yc) { int k; - double hc, bmin; + double hc, bmin, bmax; + double u, v, reduced_speed; double mass_error = 0.; // This acts like minimum_allowed height, but scales with the vertical // distance between the bed_centroid_value and the max bed_edge_value of // every triangle. //double minimum_relative_height=0.05; - //int mass_added = 0; + int mass_added = 0; // Protect against inifintesimal and negative heights //if (maximum_allowed_speed < epsilon) { @@ -1153,7 +1162,7 @@ double _protect(int N, // WARNING: ADDING MASS if wc[k]minimum_allowed_height; + maximum_allowed_speed = D->maximum_allowed_speed; + epsilon = D->epsilon; wc = D->stage_centroid_values; zc = D->bed_centroid_values; @@ -1205,7 +1219,7 @@ double _protect_new(struct domain *D) { // distance between the bed_centroid_value and the max bed_edge_value of // every triangle. //double minimum_relative_height=0.05; - //int mass_added = 0; + int mass_added = 0; // Protect against inifintesimal and negative heights //if (maximum_allowed_speed < epsilon) { @@ -1222,7 +1236,7 @@ double _protect_new(struct domain *D) { // WARNING: ADDING MASS if wc[k] TINY) r0=qmax/dqv[i]; - r=fmin(r0,r); + r=min(r0,r); } - phi=fmin(r*beta_w,1.0); + phi=min(r*beta_w,1.0); //phi=1.; dqv[0]=dqv[0]*phi; dqv[1]=dqv[1]*phi; @@ -1343,12 +1357,12 @@ int _extrapolate_second_order_edge_sw(struct domain *D){ // Local variables double a, b; // Gradient vector used to calculate edge values from centroids - int k, k0, k1, k2, k3, k6, coord_index, i; + int k, k0, k1, k2, k3, k6, coord_index, i, ii, ktmp, k_wetdry; double x, y, x0, y0, x1, y1, x2, y2, xv0, yv0, xv1, yv1, xv2, yv2; // Vertices of the auxiliary triangle - double dx1, dx2, dy1, dy2, dxv0, dxv1, dxv2, dyv0, dyv1, dyv2, dq0, dq1, dq2, area2, inv_area2; - double dqv[3], qmin, qmax, hmin, hmax; - double hc, h0, h1, h2, beta_tmp, hfactor; - double dk, dk_inv, a_tmp, b_tmp, c_tmp,d_tmp; + double dx1, dx2, dy1, dy2, dxv0, dxv1, dxv2, dyv0, dyv1, dyv2, dq0, dq1, dq2, area2, inv_area2, dpth,momnorm; + double dqv[3], qmin, qmax, hmin, hmax, bedmax,bedmin, stagemin; + double hc, h0, h1, h2, beta_tmp, hfactor, xtmp, ytmp, weight, tmp; + double dk, dk_inv,dv0, dv1, dv2, de[3], demin, dcmax, r0scale, vel_norm, l1, l2, a_tmp, b_tmp, c_tmp,d_tmp; memset((char*) D->x_centroid_work, 0, D->number_of_elements * sizeof (double)); @@ -1367,7 +1381,7 @@ int _extrapolate_second_order_edge_sw(struct domain *D){ // extrapolation This will be changed back at the end of the routine for (k=0; k< D->number_of_elements; k++){ - D->height_centroid_values[k] = fmax(D->stage_centroid_values[k] - D->bed_centroid_values[k], 0.); + D->height_centroid_values[k] = max(D->stage_centroid_values[k] - D->bed_centroid_values[k], 0.); dk = D->height_centroid_values[k]; if(dk> D->minimum_allowed_height){ @@ -1398,14 +1412,15 @@ int _extrapolate_second_order_edge_sw(struct domain *D){ k1 = D->surrogate_neighbours[k3 + 1]; k2 = D->surrogate_neighbours[k3 + 2]; - if(( (D->height_centroid_values[k0] < D->minimum_allowed_height) | (k0==k) ) & - ( (D->height_centroid_values[k1] < D->minimum_allowed_height) | (k1==k) ) & - ( (D->height_centroid_values[k2] < D->minimum_allowed_height) | (k2==k) ) ) { + if(( (D->height_centroid_values[k0] < D->minimum_allowed_height) | k0==k) & + ( (D->height_centroid_values[k1] < D->minimum_allowed_height) | k1==k) & + ( (D->height_centroid_values[k2] < D->minimum_allowed_height) | k2==k)){ //printf("Surrounded by dry cells\n"); D->x_centroid_work[k] = 0.; D->xmom_centroid_values[k] = 0.; D->y_centroid_work[k] = 0.; D->ymom_centroid_values[k] = 0.; + } @@ -1557,8 +1572,8 @@ int _extrapolate_second_order_edge_sw(struct domain *D){ h1 = D->height_centroid_values[k1]; h2 = D->height_centroid_values[k2]; - hmin = fmin(fmin(h0, fmin(h1, h2)), hc); - hmax = fmax(fmax(h0, fmax(h1, h2)), hc); + hmin = min(min(h0, min(h1, h2)), hc); + hmax = max(max(h0, max(h1, h2)), hc); // Look for strong changes in cell depth as an indicator of near-wet-dry // Reduce hfactor linearly from 1-0 between depth ratio (hmin/hc) of [a_tmp , b_tmp] @@ -1567,12 +1582,12 @@ int _extrapolate_second_order_edge_sw(struct domain *D){ // but is also more 'artefacty' in important cases (tendency for high velocities, etc). // // So hfactor = depth_ratio*(c_tmp) + d_tmp, but is clipped between 0 and 1. - hfactor= fmax(0., fmin(c_tmp*fmax(hmin,0.0)/fmax(hc,1.0e-06)+d_tmp, - fmin(c_tmp*fmax(hc,0.)/fmax(hmax,1.0e-06)+d_tmp, 1.0)) + hfactor= max(0., min(c_tmp*max(hmin,0.0)/max(hc,1.0e-06)+d_tmp, + min(c_tmp*max(hc,0.)/max(hmax,1.0e-06)+d_tmp, 1.0)) ); // Set hfactor to zero smothly as hmin--> minimum_allowed_height. This // avoids some 'chatter' for very shallow flows - hfactor=fmin( 1.2*fmax(hmin- D->minimum_allowed_height,0.)/(fmax(hmin,0.)+1.* D->minimum_allowed_height), hfactor); + hfactor=min( 1.2*max(hmin- D->minimum_allowed_height,0.)/(max(hmin,0.)+1.* D->minimum_allowed_height), hfactor); inv_area2 = 1.0/area2; //----------------------------------- @@ -1792,7 +1807,7 @@ int _extrapolate_second_order_edge_sw(struct domain *D){ if ((k2 == k3 + 3)) { // If we didn't find an internal neighbour - //report_python_error(AT, "Internal neighbour not found"); + report_python_error(AT, "Internal neighbour not found"); return -1; } @@ -2023,3 +2038,472 @@ int _extrapolate_second_order_edge_sw(struct domain *D){ return 0; } + +//========================================================================= +// Python Glue +//========================================================================= + + +//======================================================================== +// Compute fluxes +//======================================================================== + +// Modified central flux function + +PyObject *swde1_compute_fluxes_ext_central(PyObject *self, PyObject *args) { + /*Compute all fluxes and the timestep suitable for all volumes + in domain. + + Compute total flux for each conserved quantity using "flux_function_central" + + Fluxes across each edge are scaled by edgelengths and summed up + Resulting flux is then scaled by area and stored in + explicit_update for each of the three conserved quantities + stage, xmomentum and ymomentum + + The maximal allowable speed computed by the flux_function for each volume + is converted to a timestep that must not be exceeded. The minimum of + those is computed as the next overall timestep. + */ + struct domain D; + PyObject *domain; + + + double timestep; + + if (!PyArg_ParseTuple(args, "Od", &domain, ×tep)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + get_python_domain(&D,domain); + + timestep=_compute_fluxes_central(&D,timestep); + + // Return updated flux timestep + return Py_BuildValue("d", timestep); +} + + +PyObject *swde1_flux_function_central(PyObject *self, PyObject *args) { + // + // Gateway to innermost flux function. + // This is only used by the unit tests as the c implementation is + // normally called by compute_fluxes in this module. + + + PyArrayObject *normal, *ql, *qr, *edgeflux; + double g, epsilon, max_speed, H0, zl, zr; + double h0, limiting_threshold, pressure_flux, smooth; + double hle, hre; + + if (!PyArg_ParseTuple(args, "OOOddOddd", + &normal, &ql, &qr, &zl, &zr, &edgeflux, + &epsilon, &g, &H0)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + printf("Warning: This interface is broken -- do not use \n"); + + h0 = H0; + hle=1.0; // Fake values to force this to compile + hre=1.0; // Fake values to force this to compile + limiting_threshold = 10*H0; // Avoid applying limiter below this + // threshold for performance reasons. + // See ANUGA manual under flux limiting + + pressure_flux = 0.0; // Store the water pressure related component of the flux + smooth = 1.0 ; // term to scale diffusion in riemann solver + + _flux_function_central((double*) ql -> data, + (double*) qr -> data, + zl, + zr, + hle, + hre, + ((double*) normal -> data)[0], + ((double*) normal -> data)[1], + epsilon, h0, limiting_threshold, + g, + (double*) edgeflux -> data, + &max_speed, + &pressure_flux, + ((double*) normal -> data)[0], + ((double*) normal -> data)[1], + 0.0 ); + + return Py_BuildValue("d", max_speed); +} + +//======================================================================== +// Gravity +//======================================================================== + +PyObject *swde1_gravity(PyObject *self, PyObject *args) { + // + // gravity(g, h, v, x, xmom, ymom) + // + + + PyArrayObject *h, *v, *x, *xmom, *ymom; + int k, N, k3, k6; + double g, avg_h, zx, zy; + double x0, y0, x1, y1, x2, y2, z0, z1, z2; + //double epsilon; + + if (!PyArg_ParseTuple(args, "dOOOOO", + &g, &h, &v, &x, + &xmom, &ymom)) { + //&epsilon)) { + PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: gravity could not parse input arguments"); + return NULL; + } + + // check that numpy array objects arrays are C contiguous memory + CHECK_C_CONTIG(h); + CHECK_C_CONTIG(v); + CHECK_C_CONTIG(x); + CHECK_C_CONTIG(xmom); + CHECK_C_CONTIG(ymom); + + N = h -> dimensions[0]; + for (k=0; k data)[k3 + 0]; + z1 = ((double*) v -> data)[k3 + 1]; + z2 = ((double*) v -> data)[k3 + 2]; + + // Optimise for flat bed + // Note (Ole): This didn't produce measurable speed up. + // Revisit later + //if (fabs(z0-z1) data)[k]; + + // Compute bed slope + k6 = 6*k; // base index + + x0 = ((double*) x -> data)[k6 + 0]; + y0 = ((double*) x -> data)[k6 + 1]; + x1 = ((double*) x -> data)[k6 + 2]; + y1 = ((double*) x -> data)[k6 + 3]; + x2 = ((double*) x -> data)[k6 + 4]; + y2 = ((double*) x -> data)[k6 + 5]; + + + _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy); + + // Update momentum + ((double*) xmom -> data)[k] += -g*zx*avg_h; + ((double*) ymom -> data)[k] += -g*zy*avg_h; + } + + return Py_BuildValue(""); +} + +PyObject *swde1_compute_flux_update_frequency(PyObject *self, PyObject *args) { + /* + + Compute how often we should update fluxes and extrapolations (perhaps not every timestep) + + */ + + struct domain D; + PyObject *domain; + + + double timestep; + + if (!PyArg_ParseTuple(args, "Od", &domain, ×tep)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + get_python_domain(&D,domain); + + _compute_flux_update_frequency(&D, timestep); + + // Return + return Py_BuildValue(""); +} + + +PyObject *swde1_extrapolate_second_order_edge_sw(PyObject *self, PyObject *args) { + /*Compute the edge values based on a linear reconstruction + on each triangle + + Post conditions: + The edges of each triangle have values from a + limited linear reconstruction + based on centroid values + + */ + + struct domain D; + PyObject *domain; + + int e; + + if (!PyArg_ParseTuple(args, "O", &domain)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + get_python_domain(&D, domain); + + // Call underlying flux computation routine and update + // the explicit update arrays + e = _extrapolate_second_order_edge_sw(&D); + + if (e == -1) { + // Use error string set inside computational routine + return NULL; + } + + + return Py_BuildValue(""); + +}// extrapolate_second-order_edge_sw + +//======================================================================== +// Protect -- to prevent the water level from falling below the minimum +// bed_edge_value +//======================================================================== + +PyObject *swde1_protect(PyObject *self, PyObject *args) { + // + // protect(minimum_allowed_height, maximum_allowed_speed, wc, zc, xmomc, ymomc) + + + PyArrayObject + *wc, //Stage at centroids + *wv, //Stage at vertices + *zc, //Elevation at centroids + *zv, //Elevation at vertices + *xmomc, //Momentums at centroids + *ymomc, + *areas, // Triangle areas + *xc, + *yc; + + int N; + double mass_error; + double minimum_allowed_height, maximum_allowed_speed, epsilon; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "dddOOOOOOOOO", + &minimum_allowed_height, + &maximum_allowed_speed, + &epsilon, + &wc, &wv, &zc, &zv, &xmomc, &ymomc, &areas, &xc, &yc)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + N = wc -> dimensions[0]; + + mass_error = _protect(N, + minimum_allowed_height, + maximum_allowed_speed, + epsilon, + (double*) wc -> data, + (double*) wv -> data, + (double*) zc -> data, + (double*) zv -> data, + (double*) xmomc -> data, + (double*) ymomc -> data, + (double*) areas -> data, + (double*) xc -> data, + (double*) yc -> data ); + + return Py_BuildValue("d", mass_error); +} + + +//======================================================================== +// Protect -- to prevent the water level from falling below the minimum +// bed_edge_value +//======================================================================== + +PyObject *swde1_protect_new(PyObject *self, PyObject *args) { + // + // protect(minimum_allowed_height, maximum_allowed_speed, wc, zc, xmomc, ymomc) + + struct domain D; + PyObject *domain; + + double mass_error; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "O", &domain)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + get_python_domain(&D, domain); + + mass_error = _protect_new(&D); + + return Py_BuildValue("d", mass_error); +} + + + + +//======================================================================== +// swde1_evolve_one_euler_step +//======================================================================== + +PyObject *swde1_evolve_one_euler_step(PyObject *self, PyObject *args) { + /* + * Implement one Euler step in C + */ + + + PyObject* domain; + PyObject* arglist; + PyObject* result; + + struct domain D; + + double yieldstep; + double finaltime; + double flux_timestep; + + int e; + double mass_error; + + + if (!PyArg_ParseTuple(args, "Odd", &domain, &yieldstep, &finaltime)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + + get_python_domain(&D, domain); + + //printf("In C_evolve %f %f \n", yieldstep, finaltime); + + + // From centroid values calculate edge and vertex values + //printf("distribute_to_vertices_and_edges\n"); +// result = PyObject_CallMethod(domain,"distribute_to_vertices_and_edges",NULL); +// if (result == NULL) { +// return NULL; +// } +// Py_DECREF(result); + + mass_error = _protect_new(&D); + + e = _extrapolate_second_order_edge_sw(&D); + if (e == -1) { + // Use error string set inside computational routine + return NULL; + } + + + // Apply boundary conditions + //printf("update_boundary\n"); + result = PyObject_CallMethod(domain,"update_boundary",NULL); + if (result == NULL) { + return NULL; + } + Py_DECREF(result); + + + + //Compute fluxes across each element edge + //printf("compute_fluxes\n"); +// result = PyObject_CallMethod(domain,"compute_fluxes",NULL); +// if (result == NULL) { +// return NULL; +// } +// Py_DECREF(result); + + + flux_timestep =_compute_fluxes_central(&D, D.evolve_max_timestep); + + + result = PyFloat_FromDouble(flux_timestep); + if (result == NULL) { + return NULL; + } + if (!PyFloat_Check(result)) { + return NULL; + } + e = PyObject_SetAttrString(domain, "flux_timestep", result); + if (e == -1) { + // Use error string set inside computational routine + return NULL; + } + Py_DECREF(result); + + + + + + //Compute forcing terms + //printf("compute_forcing_terms\n"); + result = PyObject_CallMethod(domain,"compute_forcing_terms",NULL); + if (result == NULL) { + return NULL; + } + Py_DECREF(result); + + //Update timestep to fit yieldstep and finaltime + //printf("update_timestep\n"); + result = PyObject_CallMethod(domain,"update_timestep","dd",yieldstep,finaltime); + if (result == NULL) { + return NULL; + } + Py_DECREF(result); + + //if self.max_flux_update_frequency is not 1: + // Update flux_update_frequency using the new timestep + // self.compute_flux_update_frequency() + + // Update conserved quantities + //printf("update_conserved_quantities\n"); + result = PyObject_CallMethod(domain,"update_conserved_quantities",NULL); + if (result == NULL) { + return NULL; + } + Py_DECREF(result); + + Py_RETURN_NONE; + +}// swde1_evolve_one_euler_step + +//======================================================================== +// Method table for python module +//======================================================================== + +static struct PyMethodDef MethodTable[] = { + /* The cast of the function is necessary since PyCFunction values + * only take two PyObject* parameters, and rotate() takes + * three. + */ + //{"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"}, + {"compute_fluxes_ext_central", swde1_compute_fluxes_ext_central, METH_VARARGS, "Print out"}, + {"gravity_c", swde1_gravity, METH_VARARGS, "Print out"}, + {"flux_function_central", swde1_flux_function_central, METH_VARARGS, "Print out"}, + {"extrapolate_second_order_edge_sw", swde1_extrapolate_second_order_edge_sw, METH_VARARGS, "Print out"}, + {"compute_flux_update_frequency", swde1_compute_flux_update_frequency, METH_VARARGS, "Print out"}, + {"protect", swde1_protect, METH_VARARGS | METH_KEYWORDS, "Print out"}, + {"protect_new", swde1_protect_new, METH_VARARGS | METH_KEYWORDS, "Print out"}, + {"evolve_one_euler_step", swde1_evolve_one_euler_step, METH_VARARGS | METH_KEYWORDS, "Print out"}, + {NULL, NULL, 0, NULL} +}; + +// Module initialisation +void initswDE1_domain_ext(void){ + Py_InitModule("swDE1_domain_ext", MethodTable); + + import_array(); // Necessary for handling of NumPY structures +} diff --git a/anuga/shallow_water/swDE1_domain_ext.pyx b/anuga/shallow_water/swDE1_domain_ext.pyx deleted file mode 100644 index 36517cf6e..000000000 --- a/anuga/shallow_water/swDE1_domain_ext.pyx +++ /dev/null @@ -1,371 +0,0 @@ -#cython: wraparound=False, boundscheck=False, cdivision=True, profile=False, nonecheck=False, overflowcheck=False, cdivision_warnings=False, unraisable_tracebacks=False -import cython - -# import both numpy and the Cython declarations for numpy -import numpy as np -cimport numpy as np - -cdef extern from "swDE1_domain.c" nogil: - struct domain: - long number_of_elements - double epsilon - double H0 - double g - long optimise_dry_cells - double evolve_max_timestep - long extrapolate_velocity_second_order - double minimum_allowed_height - double maximum_allowed_speed - long low_froude - long timestep_fluxcalls - double beta_w - double beta_w_dry - double beta_uh - double beta_uh_dry - double beta_vh - double beta_vh_dry - long max_flux_update_frequency - long ncol_riverwall_hydraulic_properties - long* neighbours - long* neighbour_edges - long* surrogate_neighbours - double* normals - double* edgelengths - double* radii - double* areas - long* edge_flux_type - long* tri_full_flag - long* already_computed_flux - double* max_speed - double* vertex_coordinates - double* edge_coordinates - double* centroid_coordinates - long* number_of_boundaries - double* stage_edge_values - double* xmom_edge_values - double* ymom_edge_values - double* bed_edge_values - double* height_edge_values - double* stage_centroid_values - double* xmom_centroid_values - double* ymom_centroid_values - double* bed_centroid_values - double* height_centroid_values - double* stage_vertex_values - double* xmom_vertex_values - double* ymom_vertex_values - double* bed_vertex_values - double* height_vertex_values - double* stage_boundary_values - double* xmom_boundary_values - double* ymom_boundary_values - double* bed_boundary_values - double* stage_explicit_update - double* xmom_explicit_update - double* ymom_explicit_update - long* flux_update_frequency - long* update_next_flux - long* update_extrapolation - double* edge_timestep - double* edge_flux_work - double* pressuregrad_work - double* x_centroid_work - double* y_centroid_work - double* boundary_flux_sum - long* allow_timestep_increase - double* riverwall_elevation - long* riverwall_rowIndex - double* riverwall_hydraulic_properties - - struct edge: - pass - - int _compute_flux_update_frequency(domain* D, double timestep) - double _compute_fluxes_central(domain* D, double timestep) - double _protect_new(domain* D) - int _extrapolate_second_order_edge_sw(domain* D) - - -cdef int pointer_flag = 0 -cdef int parameter_flag = 0 - -cdef inline get_python_domain_parameters(domain *D, object domain_object): - - D.number_of_elements = domain_object.number_of_elements - D.epsilon = domain_object.epsilon - D.H0 = domain_object.H0 - D.g = domain_object.g - D.optimise_dry_cells = domain_object.optimise_dry_cells - D.evolve_max_timestep = domain_object.evolve_max_timestep - D.minimum_allowed_height = domain_object.minimum_allowed_height - D.maximum_allowed_speed = domain_object.maximum_allowed_speed - D.timestep_fluxcalls = domain_object.timestep_fluxcalls - D.low_froude = domain_object.low_froude - D.extrapolate_velocity_second_order = domain_object.extrapolate_velocity_second_order - D.beta_w = domain_object.beta_w - D.beta_w_dry = domain_object.beta_w_dry - D.beta_uh = domain_object.beta_uh - D.beta_uh_dry = domain_object.beta_uh_dry - D.beta_vh = domain_object.beta_vh - D.beta_vh_dry = domain_object.beta_vh_dry - D.max_flux_update_frequency = domain_object.max_flux_update_frequency - - -cdef inline get_python_domain_pointers(domain *D, object domain_object): - - cdef long[:,::1] neighbours - cdef long[:,::1] neighbour_edges - cdef double[:,::1] normals - cdef double[:,::1] edgelengths - cdef double[::1] radii - cdef double[::1] areas - cdef long[::1] edge_flux_type - cdef long[::1] tri_full_flag - cdef long[:,::1] already_computed_flux - cdef double[:,::1] vertex_coordinates - cdef double[:,::1] edge_coordinates - cdef double[:,::1] centroid_coordinates - cdef long[::1] number_of_boundaries - cdef long[:,::1] surrogate_neighbours - cdef double[::1] max_speed - cdef long[::1] flux_update_frequency - cdef long[::1] update_next_flux - cdef long[::1] update_extrapolation - cdef long[::1] allow_timestep_increase - cdef double[::1] edge_timestep - cdef double[::1] edge_flux_work - cdef double[::1] pressuregrad_work - cdef double[::1] x_centroid_work - cdef double[::1] y_centroid_work - cdef double[::1] boundary_flux_sum - cdef double[::1] riverwall_elevation - cdef long[::1] riverwall_rowIndex - cdef double[:,::1] riverwall_hydraulic_properties - cdef double[:,::1] edge_values - cdef double[::1] centroid_values - cdef double[:,::1] vertex_values - cdef double[::1] boundary_values - cdef double[::1] explicit_update - - cdef object quantities - cdef object riverwallData - - #------------------------------------------------------ - # Domain structures - #------------------------------------------------------ - neighbours = domain_object.neighbours - D.neighbours = &neighbours[0,0] - - surrogate_neighbours = domain_object.surrogate_neighbours - D.surrogate_neighbours = &surrogate_neighbours[0,0] - - neighbour_edges = domain_object.neighbour_edges - D.neighbour_edges = &neighbour_edges[0,0] - - normals = domain_object.normals - D.normals = &normals[0,0] - - edgelengths = domain_object.edgelengths - D.edgelengths = &edgelengths[0,0] - - radii = domain_object.radii - D.radii = &radii[0] - - areas = domain_object.areas - D.areas = &areas[0] - - edge_flux_type = domain_object.edge_flux_type - D.edge_flux_type = &edge_flux_type[0] - - tri_full_flag = domain_object.tri_full_flag - D.tri_full_flag = &tri_full_flag[0] - - already_computed_flux = domain_object.already_computed_flux - D.already_computed_flux = &already_computed_flux[0,0] - - vertex_coordinates = domain_object.vertex_coordinates - D.vertex_coordinates = &vertex_coordinates[0,0] - - edge_coordinates = domain_object.edge_coordinates - D.edge_coordinates = &edge_coordinates[0,0] - - centroid_coordinates = domain_object.centroid_coordinates - D.centroid_coordinates = ¢roid_coordinates[0,0] - - max_speed = domain_object.max_speed - D.max_speed = &max_speed[0] - - number_of_boundaries = domain_object.number_of_boundaries - D.number_of_boundaries = &number_of_boundaries[0] - - flux_update_frequency = domain_object.flux_update_frequency - D.flux_update_frequency = &flux_update_frequency[0] - - update_next_flux = domain_object.update_next_flux - D.update_next_flux = &update_next_flux[0] - - update_extrapolation = domain_object.update_extrapolation - D.update_extrapolation = &update_extrapolation[0] - - allow_timestep_increase = domain_object.allow_timestep_increase - D.allow_timestep_increase = &allow_timestep_increase[0] - - edge_timestep = domain_object.edge_timestep - D.edge_timestep = &edge_timestep[0] - - edge_flux_work = domain_object.edge_flux_work - D.edge_flux_work = &edge_flux_work[0] - - pressuregrad_work = domain_object.pressuregrad_work - D.pressuregrad_work = &pressuregrad_work[0] - - x_centroid_work = domain_object.x_centroid_work - D.x_centroid_work = &x_centroid_work[0] - - y_centroid_work = domain_object.y_centroid_work - D.y_centroid_work = &y_centroid_work[0] - - boundary_flux_sum = domain_object.boundary_flux_sum - D.boundary_flux_sum = &boundary_flux_sum[0] - - #------------------------------------------------------ - # Quantity structures - #------------------------------------------------------ - quantities = domain_object.quantities - - edge_values = quantities["stage"].edge_values - D.stage_edge_values = &edge_values[0,0] - - edge_values = quantities["xmomentum"].edge_values - D.xmom_edge_values = &edge_values[0,0] - - edge_values = quantities["ymomentum"].edge_values - D.ymom_edge_values = &edge_values[0,0] - - edge_values = quantities["elevation"].edge_values - D.bed_edge_values = &edge_values[0,0] - - edge_values = quantities["height"].edge_values - D.height_edge_values = &edge_values[0,0] - - centroid_values = quantities["stage"].centroid_values - D.stage_centroid_values = ¢roid_values[0] - - centroid_values = quantities["xmomentum"].centroid_values - D.xmom_centroid_values = ¢roid_values[0] - - centroid_values = quantities["ymomentum"].centroid_values - D.ymom_centroid_values = ¢roid_values[0] - - centroid_values = quantities["elevation"].centroid_values - D.bed_centroid_values = ¢roid_values[0] - - centroid_values = quantities["height"].centroid_values - D.height_centroid_values = ¢roid_values[0] - - vertex_values = quantities["stage"].vertex_values - D.stage_vertex_values = &vertex_values[0,0] - - vertex_values = quantities["xmomentum"].vertex_values - D.xmom_vertex_values = &vertex_values[0,0] - - vertex_values = quantities["ymomentum"].vertex_values - D.ymom_vertex_values = &vertex_values[0,0] - - vertex_values = quantities["elevation"].vertex_values - D.bed_vertex_values = &vertex_values[0,0] - - vertex_values = quantities["height"].vertex_values - D.height_vertex_values = &vertex_values[0,0] - - boundary_values = quantities["stage"].boundary_values - D.stage_boundary_values = &boundary_values[0] - - boundary_values = quantities["xmomentum"].boundary_values - D.xmom_boundary_values = &boundary_values[0] - - boundary_values = quantities["ymomentum"].boundary_values - D.ymom_boundary_values = &boundary_values[0] - - boundary_values = quantities["elevation"].boundary_values - D.bed_boundary_values = &boundary_values[0] - - explicit_update = quantities["stage"].explicit_update - D.stage_explicit_update = &explicit_update[0] - - explicit_update = quantities["xmomentum"].explicit_update - D.xmom_explicit_update = &explicit_update[0] - - explicit_update = quantities["ymomentum"].explicit_update - D.ymom_explicit_update = &explicit_update[0] - - #------------------------------------------------------ - # Riverwall structures - #------------------------------------------------------ - riverwallData = domain_object.riverwallData - - riverwall_elevation = riverwallData.riverwall_elevation - D.riverwall_elevation = &riverwall_elevation[0] - - riverwall_rowIndex = riverwallData.hydraulic_properties_rowIndex - D.riverwall_rowIndex = &riverwall_rowIndex[0] - - D.ncol_riverwall_hydraulic_properties = riverwallData.ncol_hydraulic_properties - - riverwall_hydraulic_properties = riverwallData.hydraulic_properties - D.riverwall_hydraulic_properties = &riverwall_hydraulic_properties[0,0] - - -#=============================================================================== - -def compute_fluxes_ext_central(object domain_object, double timestep): - - cdef domain D - - get_python_domain_parameters(&D, domain_object) - get_python_domain_pointers(&D, domain_object) - - with nogil: - timestep = _compute_fluxes_central(&D, timestep) - - return timestep - -def extrapolate_second_order_edge_sw(object domain_object): - - cdef domain D - cdef int e - - get_python_domain_parameters(&D, domain_object) - get_python_domain_pointers(&D, domain_object) - - with nogil: - e = _extrapolate_second_order_edge_sw(&D) - - if e == -1: - return None - -def protect_new(object domain_object): - - cdef domain D - - cdef double mass_error - - get_python_domain_parameters(&D, domain_object) - get_python_domain_pointers(&D, domain_object) - - with nogil: - mass_error = _protect_new(&D) - - return mass_error - -def compute_flux_update_frequency(object domain_object, double timestep): - - cdef domain D - - get_python_domain_parameters(&D, domain_object) - get_python_domain_pointers(&D, domain_object) - - with nogil: - _compute_flux_update_frequency(&D, timestep) - - diff --git a/anuga/shallow_water/sw_domain.h b/anuga/shallow_water/sw_domain.h index c9a620525..944e38418 100644 --- a/anuga/shallow_water/sw_domain.h +++ b/anuga/shallow_water/sw_domain.h @@ -4,8 +4,9 @@ -#ifndef SW_DOMAIN_H -#define SW_DOMAIN_H +// Shared code snippets +#include "util_ext.h" + // structures struct domain { @@ -167,6 +168,218 @@ void get_edge_data(struct edge *E, struct domain *D, int k, int i) { } + +struct domain* get_python_domain(struct domain *D, PyObject *domain) { + PyArrayObject + *neighbours, + *neighbour_edges, + *normals, + *edgelengths, + *radii, + *areas, + *edge_flux_type, + *tri_full_flag, + *already_computed_flux, + *vertex_coordinates, + *edge_coordinates, + *centroid_coordinates, + *number_of_boundaries, + *surrogate_neighbours, + *max_speed, + *flux_update_frequency, + *update_next_flux, + *update_extrapolation, + *allow_timestep_increase, + *edge_timestep, + *edge_flux_work, + *pressuregrad_work, + *x_centroid_work, + *y_centroid_work, + *boundary_flux_sum, + *riverwall_elevation, + *riverwall_rowIndex, + *riverwall_hydraulic_properties; + + PyObject *quantities; + PyObject *riverwallData; + + D->number_of_elements = get_python_integer(domain, "number_of_elements"); + D->epsilon = get_python_double(domain, "epsilon"); + D->H0 = get_python_double(domain, "H0"); + D->g = get_python_double(domain, "g"); + D->optimise_dry_cells = get_python_integer(domain, "optimise_dry_cells"); + D->evolve_max_timestep = get_python_double(domain, "evolve_max_timestep"); + D->minimum_allowed_height = get_python_double(domain, "minimum_allowed_height"); + D->maximum_allowed_speed = get_python_double(domain, "maximum_allowed_speed"); + D->timestep_fluxcalls = get_python_integer(domain,"timestep_fluxcalls"); + D->low_froude = get_python_integer(domain,"low_froude"); + + + D->extrapolate_velocity_second_order = get_python_integer(domain, "extrapolate_velocity_second_order"); + + D->beta_w = get_python_double(domain, "beta_w");; + D->beta_w_dry = get_python_double(domain, "beta_w_dry"); + D->beta_uh = get_python_double(domain, "beta_uh"); + D->beta_uh_dry = get_python_double(domain, "beta_uh_dry"); + D->beta_vh = get_python_double(domain, "beta_vh"); + D->beta_vh_dry = get_python_double(domain, "beta_vh_dry"); + + D->max_flux_update_frequency = get_python_integer(domain,"max_flux_update_frequency"); + + neighbours = get_consecutive_array(domain, "neighbours"); + D->neighbours = (long *) neighbours->data; + + surrogate_neighbours = get_consecutive_array(domain, "surrogate_neighbours"); + D->surrogate_neighbours = (long *) surrogate_neighbours->data; + + neighbour_edges = get_consecutive_array(domain, "neighbour_edges"); + D->neighbour_edges = (long *) neighbour_edges->data; + + normals = get_consecutive_array(domain, "normals"); + D->normals = (double *) normals->data; + + edgelengths = get_consecutive_array(domain, "edgelengths"); + D->edgelengths = (double *) edgelengths->data; + + radii = get_consecutive_array(domain, "radii"); + D->radii = (double *) radii->data; + + areas = get_consecutive_array(domain, "areas"); + D->areas = (double *) areas->data; + + edge_flux_type = get_consecutive_array(domain, "edge_flux_type"); + D->edge_flux_type = (long *) edge_flux_type->data; + + + tri_full_flag = get_consecutive_array(domain, "tri_full_flag"); + D->tri_full_flag = (long *) tri_full_flag->data; + + already_computed_flux = get_consecutive_array(domain, "already_computed_flux"); + D->already_computed_flux = (long *) already_computed_flux->data; + + vertex_coordinates = get_consecutive_array(domain, "vertex_coordinates"); + D->vertex_coordinates = (double *) vertex_coordinates->data; + + edge_coordinates = get_consecutive_array(domain, "edge_coordinates"); + D->edge_coordinates = (double *) edge_coordinates->data; + + + centroid_coordinates = get_consecutive_array(domain, "centroid_coordinates"); + D->centroid_coordinates = (double *) centroid_coordinates->data; + + max_speed = get_consecutive_array(domain, "max_speed"); + D->max_speed = (double *) max_speed->data; + + number_of_boundaries = get_consecutive_array(domain, "number_of_boundaries"); + D->number_of_boundaries = (long *) number_of_boundaries->data; + + flux_update_frequency = get_consecutive_array(domain, "flux_update_frequency"); + D->flux_update_frequency = (long*) flux_update_frequency->data; + + update_next_flux = get_consecutive_array(domain, "update_next_flux"); + D->update_next_flux = (long*) update_next_flux->data; + + update_extrapolation = get_consecutive_array(domain, "update_extrapolation"); + D->update_extrapolation = (long*) update_extrapolation->data; + + allow_timestep_increase = get_consecutive_array(domain, "allow_timestep_increase"); + D->allow_timestep_increase = (long*) allow_timestep_increase->data; + + edge_timestep = get_consecutive_array(domain, "edge_timestep"); + D->edge_timestep = (double*) edge_timestep->data; + + edge_flux_work = get_consecutive_array(domain, "edge_flux_work"); + D->edge_flux_work = (double*) edge_flux_work->data; + + pressuregrad_work = get_consecutive_array(domain, "pressuregrad_work"); + D->pressuregrad_work = (double*) pressuregrad_work->data; + + x_centroid_work = get_consecutive_array(domain, "x_centroid_work"); + D->x_centroid_work = (double*) x_centroid_work->data; + + y_centroid_work = get_consecutive_array(domain, "y_centroid_work"); + D->y_centroid_work = (double*) y_centroid_work->data; + + boundary_flux_sum = get_consecutive_array(domain, "boundary_flux_sum"); + D->boundary_flux_sum = (double*) boundary_flux_sum->data; + + quantities = get_python_object(domain, "quantities"); + + D->stage_edge_values = get_python_array_data_from_dict(quantities, "stage", "edge_values"); + D->xmom_edge_values = get_python_array_data_from_dict(quantities, "xmomentum", "edge_values"); + D->ymom_edge_values = get_python_array_data_from_dict(quantities, "ymomentum", "edge_values"); + D->bed_edge_values = get_python_array_data_from_dict(quantities, "elevation", "edge_values"); + D->height_edge_values = get_python_array_data_from_dict(quantities, "height", "edge_values"); + + D->stage_centroid_values = get_python_array_data_from_dict(quantities, "stage", "centroid_values"); + D->xmom_centroid_values = get_python_array_data_from_dict(quantities, "xmomentum", "centroid_values"); + D->ymom_centroid_values = get_python_array_data_from_dict(quantities, "ymomentum", "centroid_values"); + D->bed_centroid_values = get_python_array_data_from_dict(quantities, "elevation", "centroid_values"); + D->height_centroid_values = get_python_array_data_from_dict(quantities, "height", "centroid_values"); + + D->stage_vertex_values = get_python_array_data_from_dict(quantities, "stage", "vertex_values"); + D->xmom_vertex_values = get_python_array_data_from_dict(quantities, "xmomentum", "vertex_values"); + D->ymom_vertex_values = get_python_array_data_from_dict(quantities, "ymomentum", "vertex_values"); + D->bed_vertex_values = get_python_array_data_from_dict(quantities, "elevation", "vertex_values"); + D->height_vertex_values = get_python_array_data_from_dict(quantities, "height", "vertex_values"); + + D->stage_boundary_values = get_python_array_data_from_dict(quantities, "stage", "boundary_values"); + D->xmom_boundary_values = get_python_array_data_from_dict(quantities, "xmomentum", "boundary_values"); + D->ymom_boundary_values = get_python_array_data_from_dict(quantities, "ymomentum", "boundary_values"); + D->bed_boundary_values = get_python_array_data_from_dict(quantities, "elevation", "boundary_values"); + + D->stage_explicit_update = get_python_array_data_from_dict(quantities, "stage", "explicit_update"); + D->xmom_explicit_update = get_python_array_data_from_dict(quantities, "xmomentum", "explicit_update"); + D->ymom_explicit_update = get_python_array_data_from_dict(quantities, "ymomentum", "explicit_update"); + + + riverwallData = get_python_object(domain,"riverwallData"); + + riverwall_elevation = get_consecutive_array(riverwallData, "riverwall_elevation"); + D->riverwall_elevation = (double*) riverwall_elevation->data; + + riverwall_rowIndex = get_consecutive_array(riverwallData, "hydraulic_properties_rowIndex"); + D->riverwall_rowIndex = (long*) riverwall_rowIndex->data; + + D->ncol_riverwall_hydraulic_properties = get_python_integer(riverwallData, "ncol_hydraulic_properties"); + + riverwall_hydraulic_properties = get_consecutive_array(riverwallData, "hydraulic_properties"); + D->riverwall_hydraulic_properties = (double*) riverwall_hydraulic_properties->data; + + Py_DECREF(quantities); + Py_DECREF(riverwallData); + + Py_DECREF(neighbours); + Py_DECREF(surrogate_neighbours); + Py_DECREF(neighbour_edges); + Py_DECREF(normals); + Py_DECREF(edgelengths); + Py_DECREF(radii); + Py_DECREF(areas); + Py_DECREF(edge_flux_type); + Py_DECREF(tri_full_flag); + Py_DECREF(already_computed_flux); + Py_DECREF(vertex_coordinates); + Py_DECREF(edge_coordinates); + Py_DECREF(centroid_coordinates); + Py_DECREF(max_speed); + Py_DECREF(number_of_boundaries); + Py_DECREF(flux_update_frequency); + Py_DECREF(update_next_flux); + Py_DECREF(update_extrapolation); + Py_DECREF(edge_timestep); + Py_DECREF(edge_flux_work); + Py_DECREF(pressuregrad_work); + Py_DECREF(x_centroid_work); + Py_DECREF(y_centroid_work); + Py_DECREF(boundary_flux_sum); + Py_DECREF(allow_timestep_increase); + + return D; +} + + + int print_domain_struct(struct domain *D) { @@ -227,5 +440,3 @@ int print_domain_struct(struct domain *D) { return 0; } - -#endif diff --git a/anuga/shallow_water/swb2_domain.c b/anuga/shallow_water/swb2_domain_ext.c similarity index 61% rename from anuga/shallow_water/swb2_domain.c rename to anuga/shallow_water/swb2_domain_ext.c index 7868ca424..999f91317 100644 --- a/anuga/shallow_water/swb2_domain.c +++ b/anuga/shallow_water/swb2_domain_ext.c @@ -14,8 +14,14 @@ // Ole Nielsen, GA 2004 // Gareth Davies, GA 2011 +#include "Python.h" +#include "numpy/arrayobject.h" #include "math.h" #include +//#include "numpy_shim.h" + +// Shared code snippets +#include "util_ext.h" const double pi = 3.14159265358979; @@ -60,7 +66,7 @@ double _compute_speed(double *uh, if (*h < limiting_threshold) { // Apply limiting of speeds according to the ANUGA manual if (*h < epsilon) { - //*h = fmax(0.0,*h); // Could have been negative + //*h = max(0.0,*h); // Could have been negative *h = 0.0; // Could have been negative u = 0.0; } else { @@ -107,7 +113,7 @@ int _flux_function_central(double *q_left, double *q_right, double w_right, h_right, uh_right, vh_right, u_right; double s_min, s_max, soundspeed_left, soundspeed_right; double denom, inverse_denominator, z; - double t3; + double uint, t1, t2, t3; // Workspace (allocate once, use many) static double q_left_rotated[3], q_right_rotated[3], flux_right[3], flux_left[3]; @@ -175,13 +181,13 @@ int _flux_function_central(double *q_left, double *q_right, //soundspeed_left = fast_squareroot_approximation(g*h_left); //soundspeed_right = fast_squareroot_approximation(g*h_right); - s_max = fmax(u_left + soundspeed_left, u_right + soundspeed_right); + s_max = max(u_left + soundspeed_left, u_right + soundspeed_right); if (s_max < 0.0) { s_max = 0.0; } - s_min = fmin(u_left - soundspeed_left, u_right - soundspeed_right); + s_min = min(u_left - soundspeed_left, u_right - soundspeed_right); if (s_min > 0.0) { s_min = 0.0; @@ -226,7 +232,7 @@ int _flux_function_central(double *q_left, double *q_right, *pressure_flux = 0.;//0.5*g*( s_max*h_left*h_left -s_min*h_right*h_right)*inverse_denominator; // Maximal wavespeed - *max_speed = fmax(fabs(s_max), fabs(s_min)); + *max_speed = max(fabs(s_max), fabs(s_min)); // Rotate back _rotate(edgeflux, n1, -n2); @@ -273,15 +279,19 @@ double _compute_fluxes_central(int number_of_elements, double limiting_threshold = 10 * H0; // Avoid applying limiter below this // threshold for performance reasons. // See ANUGA manual under flux limiting - int k, i, m, n; + int k, i, m, n,j; int ki, nm = 0, ki2; // Index shorthands // Workspace (making them static actually made function slightly slower (Ole)) double ql[3], qr[3], edgeflux[3]; // Work array for summing up fluxes + double stage_edges[3];//Work array double bedslope_work; - double pressure_flux, hc, hc_n; + int neighbours_wet[3];//Work array + int useint; + double stage_edge_lim, scale_factor_shallow, bedtop, bedbot, pressure_flux, hc, hc_n, tmp; static long call = 1; // Static local variable flagging already computed flux + double *max_bed_edgevalue, *min_bed_edgevalue; //max_bed_edgevalue = malloc(number_of_elements*sizeof(double)); //min_bed_edgevalue = malloc(number_of_elements*sizeof(double)); @@ -297,10 +307,10 @@ double _compute_fluxes_central(int number_of_elements, // Compute minimum bed edge value on each triangle //for (k = 0; k < number_of_elements; k++){ - // max_bed_edgevalue[k] = fmax(bed_edge_values[3*k], - // fmax(bed_edge_values[3*k+1], bed_edge_values[3*k+2])); - // min_bed_edgevalue[k] = fmin(bed_edge_values[3*k], - // fmin(bed_edge_values[3*k+1], bed_edge_values[3*k+2])); + // max_bed_edgevalue[k] = max(bed_edge_values[3*k], + // max(bed_edge_values[3*k+1], bed_edge_values[3*k+2])); + // min_bed_edgevalue[k] = min(bed_edge_values[3*k], + // min(bed_edge_values[3*k+1], bed_edge_values[3*k+2])); // //} @@ -321,7 +331,7 @@ double _compute_fluxes_central(int number_of_elements, ql[1] = xmom_edge_values[ki]; ql[2] = ymom_edge_values[ki]; zl = bed_edge_values[ki]; - hc = fmax(stage_centroid_values[k] - bed_centroid_values[k],0.0); + hc = max(stage_centroid_values[k] - bed_centroid_values[k],0.0); // Get right hand side values either from neighbouring triangle // or from boundary array (Quantities at neighbour on nearest face). @@ -338,7 +348,7 @@ double _compute_fluxes_central(int number_of_elements, } else { // Neighbour is a real triangle - hc_n = fmax(stage_centroid_values[n] - bed_centroid_values[n],0.0); + hc_n = max(stage_centroid_values[n] - bed_centroid_values[n],0.0); m = neighbour_edges[ki]; nm = n * 3 + m; // Linear index (triangle n, edge m) @@ -350,7 +360,7 @@ double _compute_fluxes_central(int number_of_elements, if (fabs(zl-zr)>1.0e-10) { - //report_python_error(AT,"Discontinuous Elevation"); + report_python_error(AT,"Discontinuous Elevation"); return 0.0; } @@ -368,20 +378,20 @@ double _compute_fluxes_central(int number_of_elements, // unless the local centroid value is smaller if(n>=0){ if(hc==0.0){ - //ql[0]=fmax(fmin(qr[0],stage_centroid_values[k]),zl); - //ql[0]=fmax(fmin(qr[0],0.5*(stage_centroid_values[k]+stage_centroid_values[n])),zl); - ql[0]=fmax(fmin(qr[0],stage_centroid_values[k]),zl); + //ql[0]=max(min(qr[0],stage_centroid_values[k]),zl); + //ql[0]=max(min(qr[0],0.5*(stage_centroid_values[k]+stage_centroid_values[n])),zl); + ql[0]=max(min(qr[0],stage_centroid_values[k]),zl); } if(hc_n==0.0){ - qr[0]=fmax(fmin(ql[0],stage_centroid_values[n]),zr); - //qr[0]=fmax(fmin(ql[0],0.5*(stage_centroid_values[n]+stage_centroid_values[k])),zr); + qr[0]=max(min(ql[0],stage_centroid_values[n]),zr); + //qr[0]=max(min(ql[0],0.5*(stage_centroid_values[n]+stage_centroid_values[k])),zr); //qr[0]=ql[0]; } }else{ // Treat the boundary case //if((hc==0.0)){ - // ql[0]=fmax(fmin(qr[0],stage_centroid_values[k]),zl); - //ql[0]=fmax(fmin(qr[0],ql[0]),zl); + // ql[0]=max(min(qr[0],stage_centroid_values[k]),zl); + //ql[0]=max(min(qr[0],ql[0]),zl); //} } @@ -400,8 +410,8 @@ double _compute_fluxes_central(int number_of_elements, //if((stage_centroid_values[k]<=max_bed_edgevalue[k])| // (ql[0]<=zl)){ // if(edgeflux[0]>0.0){ - // tmp=fmin(0.5*areas[k]*(hc+bed_centroid_values[k] - min_bed_edgevalue[k])/(edgelengths[ki]*fmax(timestep,epsilon)), 1.0); // 28/7 -- Right answer for channel flow problem. - // tmp = fmin(fmin(edgeflux[0], tmp)/edgeflux[0], 1.0); + // tmp=min(0.5*areas[k]*(hc+bed_centroid_values[k] - min_bed_edgevalue[k])/(edgelengths[ki]*max(timestep,epsilon)), 1.0); // 28/7 -- Right answer for channel flow problem. + // tmp = min(min(edgeflux[0], tmp)/edgeflux[0], 1.0); // edgeflux[0]*=tmp; // } //} @@ -409,8 +419,8 @@ double _compute_fluxes_central(int number_of_elements, // if((stage_centroid_values[n]<=max_bed_edgevalue[n])| // (qr[0]<=zr)){ // if(edgeflux[0]<0.0){ - // tmp=fmin(0.5*areas[n]*(hc_n+bed_centroid_values[n] - min_bed_edgevalue[n])/(edgelengths[ki]*fmax(timestep,epsilon)), 1.0); // 28/7 -- Right answer for channel flow problem. - // tmp = fmin( fmax(edgeflux[0], -tmp)/edgeflux[0], 1.0); + // tmp=min(0.5*areas[n]*(hc_n+bed_centroid_values[n] - min_bed_edgevalue[n])/(edgelengths[ki]*max(timestep,epsilon)), 1.0); // 28/7 -- Right answer for channel flow problem. + // tmp = min( max(edgeflux[0], -tmp)/edgeflux[0], 1.0); // edgeflux[0]*=tmp; // } // } @@ -430,26 +440,26 @@ double _compute_fluxes_central(int number_of_elements, // Compute bed slope term //if(hc>-9999.0){ //Bedslope approx 1: - bedslope_work = g*length*( hc*(ql[0])-0.5*fmax(ql[0]-zl,0.)*(ql[0]-zl) ); + bedslope_work = g*length*( hc*(ql[0])-0.5*max(ql[0]-zl,0.)*(ql[0]-zl) ); // // Bedslope approx 2 //stage_edge_lim = ql[0]; // Limit this to be between a constant stage and constant depth extrapolation - //if(stage_edge_lim > fmax(stage_centroid_values[k], zl +hc)){ - // stage_edge_lim = fmax(stage_centroid_values[k], zl+hc); + //if(stage_edge_lim > max(stage_centroid_values[k], zl +hc)){ + // stage_edge_lim = max(stage_centroid_values[k], zl+hc); //} - //if(stage_edge_lim < fmin(stage_centroid_values[k], zl +hc)){ - // stage_edge_lim = fmin(stage_centroid_values[k], zl+hc); + //if(stage_edge_lim < min(stage_centroid_values[k], zl +hc)){ + // stage_edge_lim = min(stage_centroid_values[k], zl+hc); //} - //bedslope_work = g*hc*(stage_edge_lim)*length-0.5*g*fmax(stage_edge_lim-zl,0.)*(stage_edge_lim-zl)*length; + //bedslope_work = g*hc*(stage_edge_lim)*length-0.5*g*max(stage_edge_lim-zl,0.)*(stage_edge_lim-zl)*length; // Bedslope approx 3 - //bedslope_work = -0.5*g*fmax(stage_centroid_values[k]-zl,0.)*(stage_centroid_values[k]-zl)*length; + //bedslope_work = -0.5*g*max(stage_centroid_values[k]-zl,0.)*(stage_centroid_values[k]-zl)*length; // xmom_explicit_update[k] -= normals[ki2]*bedslope_work; ymom_explicit_update[k] -= normals[ki2+1]*bedslope_work; //}else{ // // Treat nearly dry cells - // bedslope_work =-0.5*g*fmax(ql[0]-zl,0.)*(ql[0]-zl)*length; // + // bedslope_work =-0.5*g*max(ql[0]-zl,0.)*(ql[0]-zl)*length; // // // // //bedslope_work = -pressure_flux*length; // xmom_explicit_update[k] -= normals[ki2]*bedslope_work; @@ -471,26 +481,26 @@ double _compute_fluxes_central(int number_of_elements, //if(hc_n>-9999.0){ //if(stage_centroid_values[n] > max_bed_edgevalue[n]){ // Bedslope approx 1: - bedslope_work = g*length*(hc_n*(qr[0])-0.5*fmax(qr[0]-zr,0.)*(qr[0]-zr)); + bedslope_work = g*length*(hc_n*(qr[0])-0.5*max(qr[0]-zr,0.)*(qr[0]-zr)); // // Bedslope approx 2: //stage_edge_lim = qr[0]; - //if(stage_edge_lim > fmax(stage_centroid_values[n], zr +hc_n)){ - // stage_edge_lim = fmax(stage_centroid_values[n], zr+hc_n); + //if(stage_edge_lim > max(stage_centroid_values[n], zr +hc_n)){ + // stage_edge_lim = max(stage_centroid_values[n], zr+hc_n); //} - //if(stage_edge_lim < fmin(stage_centroid_values[n], zr +hc_n)){ - // stage_edge_lim = fmin(stage_centroid_values[n], zr+hc_n); + //if(stage_edge_lim < min(stage_centroid_values[n], zr +hc_n)){ + // stage_edge_lim = min(stage_centroid_values[n], zr+hc_n); //} - //bedslope_work = g*hc_n*(stage_edge_lim)*length-0.5*g*fmax(stage_edge_lim-zr,0.)*(stage_edge_lim-zr)*length; + //bedslope_work = g*hc_n*(stage_edge_lim)*length-0.5*g*max(stage_edge_lim-zr,0.)*(stage_edge_lim-zr)*length; // // Bedslope approx 3 - //bedslope_work = -0.5*g*fmax(stage_centroid_values[n]-zr,0.)*(stage_centroid_values[n]-zr)*length; + //bedslope_work = -0.5*g*max(stage_centroid_values[n]-zr,0.)*(stage_centroid_values[n]-zr)*length; // xmom_explicit_update[n] += normals[ki2]*bedslope_work; ymom_explicit_update[n] += normals[ki2+1]*bedslope_work; //}else{ // // Treat nearly dry cells - // bedslope_work = -0.5*g*fmax(qr[0]-zr,0.)*(qr[0]-zr)*length; //-pressure_flux*length; //-0.5*g*fmax(qr[0]-zr,0.)*(qr[0]-zr)*length; + // bedslope_work = -0.5*g*max(qr[0]-zr,0.)*(qr[0]-zr)*length; //-pressure_flux*length; //-0.5*g*max(qr[0]-zr,0.)*(qr[0]-zr)*length; // //bedslope_work = -pressure_flux*length; // xmom_explicit_update[n] += normals[ki2]*bedslope_work; // ymom_explicit_update[n] += normals[ki2+1]*bedslope_work; @@ -508,18 +518,18 @@ double _compute_fluxes_central(int number_of_elements, // Apply CFL condition for triangles joining this edge (triangle k and triangle n) // CFL for triangle k - timestep = fmin(timestep, radii[k] / max_speed); + timestep = min(timestep, radii[k] / max_speed); if (n >= 0) { // Apply CFL condition for neigbour n (which is on the ith edge of triangle k) - timestep = fmin(timestep, radii[n] / max_speed); + timestep = min(timestep, radii[n] / max_speed); } // Ted Rigby's suggested less conservative version //if(n>=0){ - // timestep = fmin(timestep, (radii[k]+radii[n])/max_speed); + // timestep = min(timestep, (radii[k]+radii[n])/max_speed); //}else{ - // timestep = fmin(timestep, radii[k]/max_speed); + // timestep = min(timestep, radii[k]/max_speed); //} } } @@ -561,21 +571,22 @@ double _protect(int N, int k; double hc, bmin, bmax; + double u, v, reduced_speed; double mass_error=0.; // This acts like minimum_allowed height, but scales with the vertical // distance between the bed_centroid_value and the max bed_edge_value of // every triangle. double minimum_relative_height=0.1; - //int mass_added=0; + int mass_added=0; // Protect against inifintesimal and negative heights //if (maximum_allowed_speed < epsilon) { for (k=0; kTINY) r0=qmax/dqv[i]; - r=fmin(r0,r); + r=min(r0,r); } - phi=fmin(r*beta_w,1.0); + phi=min(r*beta_w,1.0); //phi=1.; dqv[0]=dqv[0]*phi; dqv[1]=dqv[1]*phi; @@ -708,15 +719,15 @@ int _extrapolate_second_order_edge_sw(int number_of_elements, // Local variables double a, b; // Gradient vector used to calculate edge values from centroids - int k, k0, k1, k2, k3, k6, coord_index, i; + int k, k0, k1, k2, k3, k6, coord_index, i, ii, ktmp; double x, y, x0, y0, x1, y1, x2, y2, xv0, yv0, xv1, yv1, xv2, yv2; // Vertices of the auxiliary triangle double dx1, dx2, dy1, dy2, dxv0, dxv1, dxv2, dyv0, dyv1, dyv2, dq0, dq1, dq2, area2, inv_area2; - double dqv[3], qmin, qmax, hmin, bedmax, stagemin; - double hc, h0, h1, h2, beta_tmp, hfactor; - double dk, de[3]; + double dqv[3], qmin, qmax, hmin, hmax, bedmax, stagemin; + double hc, h0, h1, h2, beta_tmp, hfactor, xtmp, ytmp; + double dk, dv0, dv1, dv2, de[3], demin, dcmax, r0scale, vect_norm, l1, l2; - double *xmom_centroid_store, *ymom_centroid_store, *stage_centroid_store, *max_elevation_edgevalue; - //int *count_wet_neighbours; + double *xmom_centroid_store, *ymom_centroid_store, *stage_centroid_store, *min_elevation_edgevalue, *max_elevation_edgevalue; + int *count_wet_neighbours; // Use malloc to avoid putting these variables on the stack, which can cause // segfaults in large model runs @@ -732,18 +743,18 @@ int _extrapolate_second_order_edge_sw(int number_of_elements, // extrapolation This will be changed back at the end of the routine for (k=0; k 0.001) @@ -940,7 +951,7 @@ int _extrapolate_second_order_edge_sw(int number_of_elements, // Now we want to find min and max of the centroid and the // vertices of the auxiliary triangle and compute jumps // from the centroid to the min and max - find_qmin_and_qfmax(dq0, dq1, dq2, &qmin, &qmax); + find_qmin_and_qmax(dq0, dq1, dq2, &qmin, &qmax); beta_tmp = beta_w_dry + (beta_w - beta_w_dry) * hfactor; @@ -981,7 +992,7 @@ int _extrapolate_second_order_edge_sw(int number_of_elements, // vertices of the auxiliary triangle and compute jumps // from the centroid to the min and max // - find_qmin_and_qfmax(dq0, dq1, dq2, &qmin, &qmax); + find_qmin_and_qmax(dq0, dq1, dq2, &qmin, &qmax); beta_tmp = beta_uh_dry + (beta_uh - beta_uh_dry) * hfactor; @@ -1022,7 +1033,7 @@ int _extrapolate_second_order_edge_sw(int number_of_elements, // vertices of the auxiliary triangle and compute jumps // from the centroid to the min and max // - find_qmin_and_qfmax(dq0, dq1, dq2, &qmin, &qmax); + find_qmin_and_qmax(dq0, dq1, dq2, &qmin, &qmax); beta_tmp = beta_vh_dry + (beta_vh - beta_vh_dry) * hfactor; @@ -1058,7 +1069,7 @@ int _extrapolate_second_order_edge_sw(int number_of_elements, if ((k2 == k3 + 3)) { // If we didn't find an internal neighbour - // report_python_error(AT, "Internal neighbour not found"); + report_python_error(AT, "Internal neighbour not found"); return -1; } @@ -1234,14 +1245,14 @@ int _extrapolate_second_order_edge_sw(int number_of_elements, // Re-compute momenta at edges for (i=0; i<3; i++){ - de[i] = fmax(stage_edge_values[k3+i]-elevation_edge_values[k3+i],0.0); + de[i] = max(stage_edge_values[k3+i]-elevation_edge_values[k3+i],0.0); xmom_edge_values[k3+i]=xmom_edge_values[k3+i]*de[i]; ymom_edge_values[k3+i]=ymom_edge_values[k3+i]*de[i]; } // Re-compute momenta at vertices for (i=0; i<3; i++){ - de[i] = fmax(stage_vertex_values[k3+i]-elevation_vertex_values[k3+i],0.0); + de[i] = max(stage_vertex_values[k3+i]-elevation_vertex_values[k3+i],0.0); xmom_vertex_values[k3+i]=xmom_vertex_values[k3+i]*de[i]; ymom_vertex_values[k3+i]=ymom_vertex_values[k3+i]*de[i]; } @@ -1260,3 +1271,520 @@ int _extrapolate_second_order_edge_sw(int number_of_elements, return 0; } +//========================================================================= +// Python Glue +//========================================================================= + + +//======================================================================== +// Compute fluxes +//======================================================================== + +// Modified central flux function + +PyObject *swb2_compute_fluxes_ext_central(PyObject *self, PyObject *args) { + /*Compute all fluxes and the timestep suitable for all volumes + in domain. + + Compute total flux for each conserved quantity using "flux_function_central" + + Fluxes across each edge are scaled by edgelengths and summed up + Resulting flux is then scaled by area and stored in + explicit_update for each of the three conserved quantities + stage, xmomentum and ymomentum + + The maximal allowable speed computed by the flux_function for each volume + is converted to a timestep that must not be exceeded. The minimum of + those is computed as the next overall timestep. + + Python call: + domain.timestep = compute_fluxes(timestep, + domain.epsilon, + domain.H0, + domain.g, + domain.neighbours, + domain.neighbour_edges, + domain.normals, + domain.edgelengths, + domain.radii, + domain.areas, + tri_full_flag, + Stage.edge_values, + Xmom.edge_values, + Ymom.edge_values, + Bed.edge_values, + Stage.boundary_values, + Xmom.boundary_values, + Ymom.boundary_values, + Stage.explicit_update, + Xmom.explicit_update, + Ymom.explicit_update, + already_computed_flux, + optimise_dry_cells, + stage.centroid_values, + bed.centroid_values) + + + Post conditions: + domain.explicit_update is reset to computed flux values + domain.timestep is set to the largest step satisfying all volumes. + + + */ + + + PyArrayObject *neighbours, *neighbour_edges, + *normals, *edgelengths, *radii, *areas, + *tri_full_flag, + *stage_edge_values, + *xmom_edge_values, + *ymom_edge_values, + *bed_edge_values, + *stage_boundary_values, + *xmom_boundary_values, + *ymom_boundary_values, + *boundary_flux_type, + *stage_explicit_update, + *xmom_explicit_update, + *ymom_explicit_update, + *already_computed_flux, //Tracks whether the flux across an edge has already been computed + *max_speed_array, //Keeps track of max speeds for each triangle + *stage_centroid_values, + *bed_centroid_values, + *bed_vertex_values; + + double timestep, epsilon, H0, g; + int optimise_dry_cells; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "ddddOOOOOOOOOOOOOOOOOOOOiOOO", + ×tep, + &epsilon, + &H0, + &g, + &neighbours, + &neighbour_edges, + &normals, + &edgelengths, &radii, &areas, + &tri_full_flag, + &stage_edge_values, + &xmom_edge_values, + &ymom_edge_values, + &bed_edge_values, + &stage_boundary_values, + &xmom_boundary_values, + &ymom_boundary_values, + &boundary_flux_type, + &stage_explicit_update, + &xmom_explicit_update, + &ymom_explicit_update, + &already_computed_flux, + &max_speed_array, + &optimise_dry_cells, + &stage_centroid_values, + &bed_centroid_values, + &bed_vertex_values)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // check that numpy array objects arrays are C contiguous memory + CHECK_C_CONTIG(neighbours); + CHECK_C_CONTIG(neighbour_edges); + CHECK_C_CONTIG(normals); + CHECK_C_CONTIG(edgelengths); + CHECK_C_CONTIG(radii); + CHECK_C_CONTIG(areas); + CHECK_C_CONTIG(tri_full_flag); + CHECK_C_CONTIG(stage_edge_values); + CHECK_C_CONTIG(xmom_edge_values); + CHECK_C_CONTIG(ymom_edge_values); + CHECK_C_CONTIG(bed_edge_values); + CHECK_C_CONTIG(stage_boundary_values); + CHECK_C_CONTIG(xmom_boundary_values); + CHECK_C_CONTIG(ymom_boundary_values); + CHECK_C_CONTIG(boundary_flux_type); + CHECK_C_CONTIG(stage_explicit_update); + CHECK_C_CONTIG(xmom_explicit_update); + CHECK_C_CONTIG(ymom_explicit_update); + CHECK_C_CONTIG(already_computed_flux); + CHECK_C_CONTIG(max_speed_array); + CHECK_C_CONTIG(stage_centroid_values); + CHECK_C_CONTIG(bed_centroid_values); + CHECK_C_CONTIG(bed_vertex_values); + + int number_of_elements = stage_edge_values -> dimensions[0]; + + // Call underlying flux computation routine and update + // the explicit update arrays + timestep = _compute_fluxes_central(number_of_elements, + timestep, + epsilon, + H0, + g, + (long*) neighbours -> data, + (long*) neighbour_edges -> data, + (double*) normals -> data, + (double*) edgelengths -> data, + (double*) radii -> data, + (double*) areas -> data, + (long*) tri_full_flag -> data, + (double*) stage_edge_values -> data, + (double*) xmom_edge_values -> data, + (double*) ymom_edge_values -> data, + (double*) bed_edge_values -> data, + (double*) stage_boundary_values -> data, + (double*) xmom_boundary_values -> data, + (double*) ymom_boundary_values -> data, + (long*) boundary_flux_type -> data, + (double*) stage_explicit_update -> data, + (double*) xmom_explicit_update -> data, + (double*) ymom_explicit_update -> data, + (long*) already_computed_flux -> data, + (double*) max_speed_array -> data, + optimise_dry_cells, + (double*) stage_centroid_values -> data, + (double*) bed_centroid_values -> data, + (double*) bed_vertex_values -> data); + + // Return updated flux timestep + return Py_BuildValue("d", timestep); +} + + +PyObject *swb2_flux_function_central(PyObject *self, PyObject *args) { + // + // Gateway to innermost flux function. + // This is only used by the unit tests as the c implementation is + // normally called by compute_fluxes in this module. + + + PyArrayObject *normal, *ql, *qr, *edgeflux; + double g, epsilon, max_speed, H0, zl, zr; + double h0, limiting_threshold, pressure_flux; + + if (!PyArg_ParseTuple(args, "OOOddOddd", + &normal, &ql, &qr, &zl, &zr, &edgeflux, + &epsilon, &g, &H0)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + + h0 = H0*H0; // This ensures a good balance when h approaches H0. + // But evidence suggests that h0 can be as little as + // epsilon! + + limiting_threshold = 10*H0; // Avoid applying limiter below this + // threshold for performance reasons. + // See ANUGA manual under flux limiting + + pressure_flux = 0.0; // Store the water pressure related component of the flux + _flux_function_central((double*) ql -> data, + (double*) qr -> data, + zl, + zr, + ((double*) normal -> data)[0], + ((double*) normal -> data)[1], + epsilon, h0, limiting_threshold, + g, + (double*) edgeflux -> data, + &max_speed, + &pressure_flux); + + return Py_BuildValue("d", max_speed); +} + +//======================================================================== +// Gravity +//======================================================================== + +PyObject *swb2_gravity(PyObject *self, PyObject *args) { + // + // gravity(g, h, v, x, xmom, ymom) + // + + + PyArrayObject *h, *v, *x, *xmom, *ymom; + int k, N, k3, k6; + double g, avg_h, zx, zy; + double x0, y0, x1, y1, x2, y2, z0, z1, z2; + //double epsilon; + + if (!PyArg_ParseTuple(args, "dOOOOO", + &g, &h, &v, &x, + &xmom, &ymom)) { + //&epsilon)) { + PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: gravity could not parse input arguments"); + return NULL; + } + + // check that numpy array objects arrays are C contiguous memory + CHECK_C_CONTIG(h); + CHECK_C_CONTIG(v); + CHECK_C_CONTIG(x); + CHECK_C_CONTIG(xmom); + CHECK_C_CONTIG(ymom); + + N = h -> dimensions[0]; + for (k=0; k data)[k3 + 0]; + z1 = ((double*) v -> data)[k3 + 1]; + z2 = ((double*) v -> data)[k3 + 2]; + + // Optimise for flat bed + // Note (Ole): This didn't produce measurable speed up. + // Revisit later + //if (fabs(z0-z1) data)[k]; + + // Compute bed slope + k6 = 6*k; // base index + + x0 = ((double*) x -> data)[k6 + 0]; + y0 = ((double*) x -> data)[k6 + 1]; + x1 = ((double*) x -> data)[k6 + 2]; + y1 = ((double*) x -> data)[k6 + 3]; + x2 = ((double*) x -> data)[k6 + 4]; + y2 = ((double*) x -> data)[k6 + 5]; + + + _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy); + + // Update momentum + ((double*) xmom -> data)[k] += -g*zx*avg_h; + ((double*) ymom -> data)[k] += -g*zy*avg_h; + } + + return Py_BuildValue(""); +} + + +PyObject *swb2_extrapolate_second_order_edge_sw(PyObject *self, PyObject *args) { + /*Compute the edge values based on a linear reconstruction + on each triangle + + Python call: + extrapolate_second_order_sw(domain.surrogate_neighbours, + domain.number_of_boundaries + domain.centroid_coordinates, + Stage.centroid_values + Xmom.centroid_values + Ymom.centroid_values + domain.edge_coordinates, + Stage.edge_values, + Xmom.edge_values, + Ymom.edge_values) + + Post conditions: + The edges of each triangle have values from a + limited linear reconstruction + based on centroid values + + */ + PyArrayObject *surrogate_neighbours, + *number_of_boundaries, + *centroid_coordinates, + *stage_centroid_values, + *xmom_centroid_values, + *ymom_centroid_values, + *elevation_centroid_values, + *edge_coordinates, + *stage_edge_values, + *xmom_edge_values, + *ymom_edge_values, + *elevation_edge_values, + *stage_vertex_values, + *xmom_vertex_values, + *ymom_vertex_values, + *elevation_vertex_values; + + PyObject *domain; + + + double beta_w, beta_w_dry, beta_uh, beta_uh_dry, beta_vh, beta_vh_dry; + double minimum_allowed_height, epsilon; + int optimise_dry_cells, number_of_elements, extrapolate_velocity_second_order, e, e2; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "OOOOOOOOOOOOOOOOOii", + &domain, + &surrogate_neighbours, + &number_of_boundaries, + ¢roid_coordinates, + &stage_centroid_values, + &xmom_centroid_values, + &ymom_centroid_values, + &elevation_centroid_values, + &edge_coordinates, + &stage_edge_values, + &xmom_edge_values, + &ymom_edge_values, + &elevation_edge_values, + &stage_vertex_values, + &xmom_vertex_values, + &ymom_vertex_values, + &elevation_vertex_values, + &optimise_dry_cells, + &extrapolate_velocity_second_order)) { + + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + // check that numpy array objects arrays are C contiguous memory + CHECK_C_CONTIG(surrogate_neighbours); + CHECK_C_CONTIG(number_of_boundaries); + CHECK_C_CONTIG(centroid_coordinates); + CHECK_C_CONTIG(stage_centroid_values); + CHECK_C_CONTIG(xmom_centroid_values); + CHECK_C_CONTIG(ymom_centroid_values); + CHECK_C_CONTIG(elevation_centroid_values); + CHECK_C_CONTIG(edge_coordinates); + CHECK_C_CONTIG(stage_edge_values); + CHECK_C_CONTIG(xmom_edge_values); + CHECK_C_CONTIG(ymom_edge_values); + CHECK_C_CONTIG(elevation_edge_values); + CHECK_C_CONTIG(stage_vertex_values); + CHECK_C_CONTIG(xmom_vertex_values); + CHECK_C_CONTIG(ymom_vertex_values); + CHECK_C_CONTIG(elevation_vertex_values); + + // Get the safety factor beta_w, set in the config.py file. + // This is used in the limiting process + + + beta_w = get_python_double(domain,"beta_w"); + beta_w_dry = get_python_double(domain,"beta_w_dry"); + beta_uh = get_python_double(domain,"beta_uh"); + beta_uh_dry = get_python_double(domain,"beta_uh_dry"); + beta_vh = get_python_double(domain,"beta_vh"); + beta_vh_dry = get_python_double(domain,"beta_vh_dry"); + + minimum_allowed_height = get_python_double(domain,"minimum_allowed_height"); + epsilon = get_python_double(domain,"epsilon"); + + number_of_elements = stage_centroid_values -> dimensions[0]; + + //printf("In C before Extrapolate"); + //e=1; + // Call underlying computational routine + e = _extrapolate_second_order_edge_sw(number_of_elements, + epsilon, + minimum_allowed_height, + beta_w, + beta_w_dry, + beta_uh, + beta_uh_dry, + beta_vh, + beta_vh_dry, + (long*) surrogate_neighbours -> data, + (long*) number_of_boundaries -> data, + (double*) centroid_coordinates -> data, + (double*) stage_centroid_values -> data, + (double*) xmom_centroid_values -> data, + (double*) ymom_centroid_values -> data, + (double*) elevation_centroid_values -> data, + (double*) edge_coordinates -> data, + (double*) stage_edge_values -> data, + (double*) xmom_edge_values -> data, + (double*) ymom_edge_values -> data, + (double*) elevation_edge_values -> data, + (double*) stage_vertex_values -> data, + (double*) xmom_vertex_values -> data, + (double*) ymom_vertex_values -> data, + (double*) elevation_vertex_values -> data, + optimise_dry_cells, + extrapolate_velocity_second_order); + + if (e == -1) { + // Use error string set inside computational routine + return NULL; + } + + + return Py_BuildValue(""); + +}// extrapolate_second-order_edge_sw +//======================================================================== +// Protect -- to prevent the water level from falling below the minimum +// bed_edge_value +//======================================================================== + +PyObject *swb2_protect(PyObject *self, PyObject *args) { + // + // protect(minimum_allowed_height, maximum_allowed_speed, wc, zc, xmomc, ymomc) + + + PyArrayObject + *wc, //Stage at centroids + *wv, //Stage at vertices + *zc, //Elevation at centroids + *zv, //Elevation at vertices + *xmomc, //Momentums at centroids + *ymomc, + *areas; // Triangle areas + + + int N; + double minimum_allowed_height, maximum_allowed_speed, epsilon; + double mass_error; + + // Convert Python arguments to C + if (!PyArg_ParseTuple(args, "dddOOOOOOO", + &minimum_allowed_height, + &maximum_allowed_speed, + &epsilon, + &wc, &wv, &zc, &zv, &xmomc, &ymomc, &areas)) { + report_python_error(AT, "could not parse input arguments"); + return NULL; + } + + N = wc -> dimensions[0]; + + mass_error = _protect(N, + minimum_allowed_height, + maximum_allowed_speed, + epsilon, + (double*) wc -> data, + (double*) wv -> data, + (double*) zc -> data, + (double*) zv -> data, + (double*) xmomc -> data, + (double*) ymomc -> data, + (double*) areas -> data); + + return Py_BuildValue("d", mass_error); +} + +//======================================================================== +// Method table for python module +//======================================================================== + +static struct PyMethodDef MethodTable[] = { + /* The cast of the function is necessary since PyCFunction values + * only take two PyObject* parameters, and rotate() takes + * three. + */ + //{"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"}, + {"compute_fluxes_ext_central", swb2_compute_fluxes_ext_central, METH_VARARGS, "Print out"}, + {"gravity_c", swb2_gravity, METH_VARARGS, "Print out"}, + {"flux_function_central", swb2_flux_function_central, METH_VARARGS, "Print out"}, + {"extrapolate_second_order_edge_sw", swb2_extrapolate_second_order_edge_sw, METH_VARARGS, "Print out"}, + {"protect", swb2_protect, METH_VARARGS | METH_KEYWORDS, "Print out"}, + {NULL, NULL, 0, NULL} +}; + +// Module initialisation +void initswb2_domain_ext(void){ + Py_InitModule("swb2_domain_ext", MethodTable); + + import_array(); // Necessary for handling of NumPY structures +} diff --git a/anuga/shallow_water/swb2_domain_ext.pyx b/anuga/shallow_water/swb2_domain_ext.pyx deleted file mode 100644 index bb2545d59..000000000 --- a/anuga/shallow_water/swb2_domain_ext.pyx +++ /dev/null @@ -1,180 +0,0 @@ -#cython: wraparound=False, boundscheck=False, cdivision=True, profile=False, nonecheck=False, overflowcheck=False, cdivision_warnings=False, unraisable_tracebacks=False -import cython - -# import both numpy and the Cython declarations for numpy -import numpy as np -cimport numpy as np - -cdef extern from "swb2_domain.c": - double _compute_fluxes_central(int number_of_elements, double timestep, double epsilon, double H0, double g, long* neighbours, long* neighbour_edges, double* normals, double* edgelengths, double* radii, double* areas, long* tri_full_flag, double* stage_edge_values, double* xmom_edge_values, double* ymom_edge_values, double* bed_edge_values, double* stage_boundary_values, double* xmom_boundary_values, double* ymom_boundary_values, long* boundary_flux_type, double* stage_explicit_update, double* xmom_explicit_update, double* ymom_explicit_update, long* already_computed_flux, double* max_speed_array, int optimise_dry_cells, double* stage_centroid_values, double* bed_centroid_values, double* bed_vertex_values) - double _protect(int N, double minimum_allowed_height, double maximum_allowed_speed, double epsilon, double* wc, double* wv, double* zc, double* zv, double* xmomc, double* ymomc, double* areas) - int _extrapolate_second_order_edge_sw(int number_of_elements, double epsilon, double minimum_allowed_height, double beta_w, double beta_w_dry, double beta_uh, double beta_uh_dry, double beta_vh, double beta_vh_dry, long* surrogate_neighbours, long* number_of_boundaries, double* centroid_coordinates, double* stage_centroid_values, double* xmom_centroid_values, double* ymom_centroid_values, double* elevation_centroid_values, double* edge_coordinates, double* stage_edge_values, double* xmom_edge_values, double* ymom_edge_values, double* elevation_edge_values, double* stage_vertex_values, double* xmom_vertex_values, double* ymom_vertex_values, double* elevation_vertex_values, int optimise_dry_cells, int extrapolate_velocity_second_order) - -def compute_fluxes_ext_central(double timestep,\ - double epsilon,\ - double H0,\ - double g,\ - np.ndarray[long, ndim=2, mode="c"] neighbours not None,\ - np.ndarray[long, ndim=2, mode="c"] neighbour_edges not None,\ - np.ndarray[double, ndim=2, mode="c"] normals not None,\ - np.ndarray[double, ndim=2, mode="c"] edgelengths not None,\ - np.ndarray[double, ndim=1, mode="c"] radii not None,\ - np.ndarray[double, ndim=1, mode="c"] areas not None,\ - np.ndarray[long, ndim=1, mode="c"] tri_full_flag not None,\ - np.ndarray[double, ndim=2, mode="c"] stage_edge_values not None,\ - np.ndarray[double, ndim=2, mode="c"] xmom_edge_values not None,\ - np.ndarray[double, ndim=2, mode="c"] ymom_edge_values not None,\ - np.ndarray[double, ndim=2, mode="c"] bed_edge_values not None,\ - np.ndarray[double, ndim=1, mode="c"] stage_boundary_values not None,\ - np.ndarray[double, ndim=1, mode="c"] xmom_boundary_values not None,\ - np.ndarray[double, ndim=1, mode="c"] ymom_boundary_values not None,\ - np.ndarray[long, ndim=1, mode="c"] boundary_flux_type not None,\ - np.ndarray[double, ndim=1, mode="c"] stage_explicit_update not None,\ - np.ndarray[double, ndim=1, mode="c"] xmom_explicit_update not None,\ - np.ndarray[double, ndim=1, mode="c"] ymom_explicit_update not None,\ - np.ndarray[long, ndim=2, mode="c"] already_computed_flux not None,\ - np.ndarray[double, ndim=1, mode="c"] max_speed_array not None,\ - long optimise_dry_cells,\ - np.ndarray[double, ndim=1, mode="c"] stage_centroid_values not None,\ - np.ndarray[double, ndim=1, mode="c"] bed_centroid_values not None,\ - np.ndarray[double, ndim=2, mode="c"] bed_vertex_values not None): - - cdef int number_of_elements - - number_of_elements = stage_edge_values.shape[0] - - timestep = _compute_fluxes_central(number_of_elements,\ - timestep,\ - epsilon,\ - H0,\ - g,\ - &neighbours[0,0],\ - &neighbour_edges[0,0],\ - &normals[0,0],\ - &edgelengths[0,0],\ - &radii[0],\ - &areas[0],\ - &tri_full_flag[0],\ - &stage_edge_values[0,0],\ - &xmom_edge_values[0,0],\ - &ymom_edge_values[0,0],\ - &bed_edge_values[0,0],\ - &stage_boundary_values[0],\ - &xmom_boundary_values[0],\ - &ymom_boundary_values[0],\ - &boundary_flux_type[0],\ - &stage_explicit_update[0],\ - &xmom_explicit_update[0],\ - &ymom_explicit_update[0],\ - &already_computed_flux[0,0],\ - &max_speed_array[0],\ - optimise_dry_cells,\ - &stage_centroid_values[0],\ - &bed_centroid_values[0],\ - &bed_vertex_values[0,0]) - - return timestep - -def protect(double minimum_allowed_height,\ - double maximum_allowed_speed,\ - double epsilon,\ - np.ndarray[double, ndim=1, mode="c"] wc not None,\ - np.ndarray[double, ndim=2, mode="c"] wv not None,\ - np.ndarray[double, ndim=1, mode="c"] zc not None,\ - np.ndarray[double, ndim=2, mode="c"] zv not None,\ - np.ndarray[double, ndim=1, mode="c"] xmomc not None,\ - np.ndarray[double, ndim=1, mode="c"] ymomc not None,\ - np.ndarray[double, ndim=1, mode="c"] areas not None): - - cdef int N - - cdef double mass_error - - N = wc.shape[0] - - mass_error = _protect(N,\ - minimum_allowed_height,\ - maximum_allowed_speed,\ - epsilon,\ - &wc[0],\ - &wv[0,0],\ - &zc[0],\ - &zv[0,0],\ - &xmomc[0],\ - &ymomc[0],\ - &areas[0]) - - return mass_error - -def extrapolate_second_order_edge_sw(object domain,\ - np.ndarray[long, ndim=2, mode="c"] surrogate_neighbours not None,\ - np.ndarray[long, ndim=1, mode="c"] number_of_boundaries not None,\ - np.ndarray[double, ndim=2, mode="c"] centroid_coordinates not None,\ - np.ndarray[double, ndim=1, mode="c"] stage_centroid_values not None,\ - np.ndarray[double, ndim=1, mode="c"] xmom_centroid_values not None,\ - np.ndarray[double, ndim=1, mode="c"] ymom_centroid_values not None,\ - np.ndarray[double, ndim=1, mode="c"] elevation_centroid_values not None,\ - np.ndarray[double, ndim=2, mode="c"] edge_coordinates not None,\ - np.ndarray[double, ndim=2, mode="c"] stage_edge_values not None,\ - np.ndarray[double, ndim=2, mode="c"] xmom_edge_values not None,\ - np.ndarray[double, ndim=2, mode="c"] ymom_edge_values not None,\ - np.ndarray[double, ndim=2, mode="c"] elevation_edge_values not None,\ - np.ndarray[double, ndim=2, mode="c"] stage_vertex_values not None,\ - np.ndarray[double, ndim=2, mode="c"] xmom_vertex_values not None,\ - np.ndarray[double, ndim=2, mode="c"] ymom_vertex_values not None,\ - np.ndarray[double, ndim=2, mode="c"] elevation_vertex_values not None,\ - long optimise_dry_cells,\ - long extrapolate_velocity_second_order): - - - cdef double beta_w, beta_w_dry, beta_uh, beta_uh_dry, beta_vh, beta_vh_dry - cdef double minimum_allowed_height, epsilon - cdef int number_of_elements, e - - beta_w = domain.beta_w - beta_w_dry = domain.beta_w_dry - beta_uh = domain.beta_uh - beta_uh_dry = domain.beta_uh_dry - beta_vh = domain.beta_vh - beta_vh_dry = domain.beta_vh_dry - - minimum_allowed_height = domain.minimum_allowed_height - epsilon = domain.epsilon - - number_of_elements = stage_centroid_values.shape[0] - - e = _extrapolate_second_order_edge_sw(number_of_elements,\ - epsilon,\ - minimum_allowed_height,\ - beta_w,\ - beta_w_dry,\ - beta_uh,\ - beta_uh_dry,\ - beta_vh,\ - beta_vh_dry,\ - &surrogate_neighbours[0,0],\ - &number_of_boundaries[0],\ - ¢roid_coordinates[0,0],\ - &stage_centroid_values[0],\ - &xmom_centroid_values[0],\ - &ymom_centroid_values[0],\ - &elevation_centroid_values[0],\ - &edge_coordinates[0,0],\ - &stage_edge_values[0,0],\ - &xmom_edge_values[0,0],\ - &ymom_edge_values[0,0],\ - &elevation_edge_values[0,0],\ - &stage_vertex_values[0,0],\ - &xmom_vertex_values[0,0],\ - &ymom_vertex_values[0,0],\ - &elevation_vertex_values[0,0],\ - optimise_dry_cells,\ - extrapolate_velocity_second_order) - - if e == -1: - return None - - - - - diff --git a/anuga/structures/riverwall.py b/anuga/structures/riverwall.py index a56d31f44..38afb5b6a 100644 --- a/anuga/structures/riverwall.py +++ b/anuga/structures/riverwall.py @@ -114,7 +114,7 @@ def __init__(self, domain): default_int=-9e+20 self.riverwall_elevation=numpy.array([default_float]) - self.hydraulic_properties_rowIndex=numpy.array([default_int]).astype(int) + self.hydraulic_properties_rowIndex=numpy.array([default_int]) self.names=[ ] diff --git a/anuga/utilities/argparsing.py b/anuga/utilities/argparsing.py index 9b3347536..e0cf0f7da 100644 --- a/anuga/utilities/argparsing.py +++ b/anuga/utilities/argparsing.py @@ -20,10 +20,10 @@ def create_standard_parser(): #parser.add_argument('-cfl', type=float, default=default_cfl, # help='cfl condition') - parser.add_argument('-ft', '--finaltime', type=float, default=argparse.SUPPRESS, + parser.add_argument('-ft', '--finaltime', type=float, default=-1.0, help='finaltime') - parser.add_argument('-ys', '--yieldstep', type=float, default=argparse.SUPPRESS, + parser.add_argument('-ys', '--yieldstep', type=float, default=-1.0, help='yieldstep') parser.add_argument('-alg', type=str, default = default_alg, @@ -58,6 +58,7 @@ def parse_standard_args(): arguments. Returns values of alg + cfl """ diff --git a/appveyor.yml b/appveyor.yml index caf393f15..4cade5173 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,7 +22,7 @@ build_script: - CMD: SET - conda config --set always_yes yes - conda update conda - - conda install python=2.7.13 gdal=2.2.2 nose numpy cython scipy netcdf4 matplotlib dill libpython msys2::m2w64-toolchain + - conda install python=2.7.13 gdal=2.2.2 nose numpy scipy netcdf4 matplotlib dill libpython msys2::m2w64-toolchain - python setup.py install test_script: diff --git a/install_everything.sh b/install_everything.sh new file mode 100644 index 000000000..f06880576 --- /dev/null +++ b/install_everything.sh @@ -0,0 +1,27 @@ + + +# Install ANUGA as per docs + +# Install SWIMM as per Stephen's instructions + +git clone https://github.com/stoiver/Stormwater-Management-Model +cd Stormwater-Management-Model + +# Switch Branch +git checkout toolkitapi + +# Make shared library +cd build/Linux/ +make libswmm5.so +make swmm5 +sudo make install + + +# Install pyswmm + +git clone https://github.com/stoiver/pyswmm +cd pyswmm +git checkout linux +python setup.py install + + diff --git a/tools/install_conda.sh b/tools/install_conda.sh index 1ad96d1cc..f3b1df123 100644 --- a/tools/install_conda.sh +++ b/tools/install_conda.sh @@ -57,7 +57,7 @@ conda update --yes conda # Configure the conda environment and put it in the path using the # provided versions -conda create -n anuga_env -c conda-forge --yes python=$PYTHON_VERSION pip numpy scipy cython netcdf4 nose matplotlib gdal dill +conda create -n anuga_env -c conda-forge --yes python=$PYTHON_VERSION pip numpy scipy netcdf4 nose matplotlib gdal dill source activate anuga_env diff --git a/tools/install_conda_macos.sh b/tools/install_conda_macos.sh index 47893b27b..5d19c678f 100644 --- a/tools/install_conda_macos.sh +++ b/tools/install_conda_macos.sh @@ -35,7 +35,7 @@ conda update --yes conda # Configure the conda environment and put it in the path using the # provided versions -conda create -n anuga_env -c conda-forge --yes python=$PYTHON_VERSION pip numpy scipy cython netcdf4 \ +conda create -n anuga_env -c conda-forge --yes python=$PYTHON_VERSION pip numpy scipy netcdf4 \ nose matplotlib gdal dill source activate anuga_env diff --git a/tools/install_ubuntu.sh b/tools/install_ubuntu.sh index 41791cc8d..befdbf0d2 100644 --- a/tools/install_ubuntu.sh +++ b/tools/install_ubuntu.sh @@ -67,11 +67,6 @@ echo "| Using pip to install netCDF4 |" echo "+===============================================+" sudo pip install -q netCDF4 -echo "+===============================================+" -echo "| Using pip to install Cython |" -echo "+===============================================+" -sudo pip install -q Cython - echo "+===============================================+" echo "| Using pip to install pyproj |" echo "+===============================================+" diff --git a/validation_tests/experimental_data/okushiri/project.py b/validation_tests/experimental_data/okushiri/project.py index ccdf2468e..9c1a32cc1 100644 --- a/validation_tests/experimental_data/okushiri/project.py +++ b/validation_tests/experimental_data/okushiri/project.py @@ -19,10 +19,5 @@ # Model output output_filename = 'okushiri_auto_validation.sww' -# Evolve variables -finalTime = 25.0 -yieldStep = 0.05 - - diff --git a/validation_tests/experimental_data/okushiri/run_okushiri.py b/validation_tests/experimental_data/okushiri/run_okushiri.py index e3d7abb53..27249e821 100644 --- a/validation_tests/experimental_data/okushiri/run_okushiri.py +++ b/validation_tests/experimental_data/okushiri/run_okushiri.py @@ -24,23 +24,13 @@ from anuga import distribute, myid, numprocs, finalize, barrier -from project import * +import project import create_okushiri args = anuga.get_args() alg = args.alg verbose = args.verbose -if hasattr(args, 'finaltime'): - finalTime = args.finaltime - -if hasattr(args, 'yieldstep'): - yieldStep = args.yieldstep - -if myid == 0 and verbose: - print finalTime - print yieldStep - if verbose: print 'create mesh' elevation_in_mesh = False if myid == 0: @@ -62,7 +52,7 @@ #------------------------- if myid == 0: try: - domain = anuga.Domain(mesh_filename, use_cache=False, verbose=verbose) + domain = anuga.Domain(project.mesh_filename, use_cache=False, verbose=verbose) except: msg = 'ERROR reading in mesh file. Have you run create_okushiri.py?' raise Exception, msg @@ -78,18 +68,18 @@ if verbose: print 'set stage' if elevation_in_mesh is False: # domain.set_quantity('elevation', -# filename=bathymetry_filename_stem+'.pts', +# filename=project.bathymetry_filename_stem+'.pts', # alpha=0.02, # verbose=verbose, # use_cache=False) domain.set_quantity('elevation', - filename=bathymetry_filename_stem+'.asc', + filename=project.bathymetry_filename_stem+'.asc', verbose=verbose) #------------------------- # Set simulation parameters #------------------------- - domain.set_name(output_filename) # Name of output sww file + domain.set_name(project.output_filename) # Name of output sww file domain.set_minimum_storable_height(0.001) # Don't store w < 0.01m domain.set_store_vertices_smoothly(True) domain.set_flow_algorithm(alg) @@ -104,7 +94,7 @@ #------------------------- # Create boundary function from timeseries provided in file -wave_function = anuga.file_function(boundary_filename, +wave_function = anuga.file_function(project.boundary_filename, domain, verbose=verbose) # Create and assign boundary objects @@ -125,12 +115,12 @@ import time t0 = time.time() -for t in domain.evolve(yieldstep = yieldStep, finaltime = finalTime): +for t in domain.evolve(yieldstep = 0.05, finaltime = 25.0): if myid == 0 and verbose: domain.write_time() domain.sww_merge(delete_old=True) -if myid == 0 and verbose : print 'That took %.2f seconds' %(time.time()-t0) +if myid == 0 and verbose: print 'That took %.2f seconds' %(time.time()-t0) finalize()