source: anuga_core/source/anuga/abstract_2d_finite_volumes/quantity_ext.c @ 4886

Last change on this file since 4886 was 4886, checked in by steve, 16 years ago

Working towards an edge limiter (at least in quantity)

File size: 28.9 KB
Line 
1// Python - C extension for quantity module.
2//
3// To compile (Python2.3):
4//  gcc -c util_ext.c -I/usr/include/python2.3 -o util_ext.o -Wall -O
5//  gcc -shared util_ext.o  -o util_ext.so
6//
7// See the module quantity.py
8//
9//
10// Ole Nielsen, GA 2004
11
12#include "Python.h"
13#include "Numeric/arrayobject.h"
14#include "math.h"
15
16//Shared code snippets
17#include "util_ext.h"
18//#include "quantity_ext.h" //Obsolete
19
20
21
22int _compute_gradients(int N,
23                        double* centroids,
24                        double* centroid_values,
25                        long* number_of_boundaries,
26                        long* surrogate_neighbours,
27                        double* a,
28                        double* b){
29
30        int i, k, k0, k1, k2, index3;
31        double x0, x1, x2, y0, y1, y2, q0, q1, q2; //, det;
32
33
34        for (k=0; k<N; k++) {
35                index3 = 3*k;
36
37                if (number_of_boundaries[k] < 2) {
38                        // Two or three true neighbours
39
40                        // Get indices of neighbours (or self when used as surrogate)
41                        // k0, k1, k2 = surrogate_neighbours[k,:]
42
43                        k0 = surrogate_neighbours[index3 + 0];
44                        k1 = surrogate_neighbours[index3 + 1];
45                        k2 = surrogate_neighbours[index3 + 2];
46
47
48                        if (k0 == k1 || k1 == k2) return -1;
49
50                        // Get data
51                        q0 = centroid_values[k0];
52                        q1 = centroid_values[k1];
53                        q2 = centroid_values[k2];
54
55                        x0 = centroids[k0*2]; y0 = centroids[k0*2+1];
56                        x1 = centroids[k1*2]; y1 = centroids[k1*2+1];
57                        x2 = centroids[k2*2]; y2 = centroids[k2*2+1];
58
59                        // Gradient
60                        _gradient(x0, y0, x1, y1, x2, y2, q0, q1, q2, &a[k], &b[k]);
61
62                } else if (number_of_boundaries[k] == 2) {
63                        // One true neighbour
64
65                        // Get index of the one neighbour
66                        i=0; k0 = k;
67                        while (i<3 && k0==k) {
68                                k0 = surrogate_neighbours[index3 + i];
69                                i++;
70                        }
71                        if (k0 == k) return -1;
72
73                        k1 = k; //self
74
75                        // Get data
76                        q0 = centroid_values[k0];
77                        q1 = centroid_values[k1];
78
79                        x0 = centroids[k0*2]; y0 = centroids[k0*2+1];
80                        x1 = centroids[k1*2]; y1 = centroids[k1*2+1];
81
82                        // Two point gradient
83                        _gradient2(x0, y0, x1, y1, q0, q1, &a[k], &b[k]);
84
85                }
86                //    else:
87                //        #No true neighbours -
88                //        #Fall back to first order scheme
89        }
90        return 0;
91}
92
93
94
95int _extrapolate(int N,
96                 double* centroids,
97                 double* centroid_values,
98                 double* vertex_coordinates,
99                 double* vertex_values,
100                 double* edge_values,
101                 double* a,
102                 double* b) {
103
104        int k, k2, k3, k6;
105        double x, y, x0, y0, x1, y1, x2, y2;
106
107        for (k=0; k<N; k++){
108                k6 = 6*k;
109                k3 = 3*k;
110                k2 = 2*k;
111
112                // Centroid coordinates
113                x = centroids[k2]; y = centroids[k2+1];
114
115                // vertex coordinates
116                // x0, y0, x1, y1, x2, y2 = X[k,:]
117                x0 = vertex_coordinates[k6 + 0];
118                y0 = vertex_coordinates[k6 + 1];
119                x1 = vertex_coordinates[k6 + 2];
120                y1 = vertex_coordinates[k6 + 3];
121                x2 = vertex_coordinates[k6 + 4];
122                y2 = vertex_coordinates[k6 + 5];
123
124                // Extrapolate to Vertices
125                vertex_values[k3+0] = centroid_values[k] + a[k]*(x0-x) + b[k]*(y0-y);
126                vertex_values[k3+1] = centroid_values[k] + a[k]*(x1-x) + b[k]*(y1-y);
127                vertex_values[k3+2] = centroid_values[k] + a[k]*(x2-x) + b[k]*(y2-y);
128
129                // Extrapolate to Edges (midpoints)
130                edge_values[k3+0] = 0.5*(vertex_values[k3 + 1]+vertex_values[k3 + 2]);
131                edge_values[k3+1] = 0.5*(vertex_values[k3 + 2]+vertex_values[k3 + 0]);
132                edge_values[k3+2] = 0.5*(vertex_values[k3 + 0]+vertex_values[k3 + 1]);
133
134        }
135        return 0;
136}
137
138
139int _limit_by_vertex(int N, double beta,
140                     double* centroid_values,
141                     double* vertex_values,
142                     double* edge_values,
143                     long*   neighbours) {
144
145        int i, k, k2, k3, k6;
146        long n;
147        double qmin, qmax, qn, qc;
148        double dq, dqa[3], phi, r;
149
150        for (k=0; k<N; k++){
151                k6 = 6*k;
152                k3 = 3*k;
153                k2 = 2*k;
154
155                qc = centroid_values[k];
156                qmin = qc;
157                qmax = qc;
158
159                for (i=0; i<3; i++) {
160                    n = neighbours[k3+i];
161                    if (n >= 0) {
162                        qn = centroid_values[n]; //Neighbour's centroid value
163
164                        qmin = min(qmin, qn);
165                        qmax = max(qmax, qn);
166                    }
167                }
168
169                phi = 1.0;
170                for (i=0; i<3; i++) {   
171                    r = 1.0;
172     
173                    dq = vertex_values[k3+i] - qc;    //Delta between vertex and centroid values
174                    dqa[i] = dq;                      //Save dq for use in updating vertex values
175     
176                    if (dq > 0.0) r = (qmax - qc)/dq;
177                    if (dq < 0.0) r = (qmin - qc)/dq;     
178 
179                   
180                    phi = min( min(r*beta, 1.0), phi);   
181                }
182   
183                //Update vertex and edge values using phi limiter
184                vertex_values[k3+0] = qc + phi*dqa[0];
185                vertex_values[k3+1] = qc + phi*dqa[1];
186                vertex_values[k3+2] = qc + phi*dqa[2];
187               
188                edge_values[k3+0] = 0.5*(vertex_values[k3+1] + vertex_values[k3+2]);
189                edge_values[k3+1] = 0.5*(vertex_values[k3+2] + vertex_values[k3+0]);
190                edge_values[k3+2] = 0.5*(vertex_values[k3+0] + vertex_values[k3+1]);
191
192        }
193
194        return 0;
195}
196
197int _limit_by_edge(int N, double beta,
198                     double* centroid_values,
199                     double* vertex_values,
200                     double* edge_values,
201                     long*   neighbours) {
202
203        int i, k, k2, k3, k6;
204        long n;
205        double qmin, qmax, qn, qc;
206        double dq, dqa[3], phi, r;
207
208        for (k=0; k<N; k++){
209                k6 = 6*k;
210                k3 = 3*k;
211                k2 = 2*k;
212
213                qc = centroid_values[k];
214                qmin = qc;
215                qmax = qc;
216
217                for (i=0; i<3; i++) {
218                    n = neighbours[k3+i];
219                    if (n >= 0) {
220                        qn = centroid_values[n]; //Neighbour's centroid value
221
222                        qmin = min(qmin, qn);
223                        qmax = max(qmax, qn);
224                    }
225                }
226
227                phi = 1.0;
228                for (i=0; i<3; i++) {   
229                    r = 1.0;
230     
231                    dq = edge_values[k3+i] - qc;     //Delta between edge and centroid values
232                    dqa[i] = dq;                      //Save dq for use in updating vertex values
233     
234                    if (dq > 0.0) r = (qmax - qc)/dq;
235                    if (dq < 0.0) r = (qmin - qc)/dq;     
236 
237                   
238                    phi = min( min(r*beta, 1.0), phi);   
239                }
240   
241                //Update vertex and edge values using phi limiter
242                edge_values[k3+0] = qc + phi*dqa[0];
243                edge_values[k3+1] = qc + phi*dqa[1];
244                edge_values[k3+2] = qc + phi*dqa[2];
245               
246                vertex_values[k3+0] = edge_values[k3+1] + edge_values[k3+2] - edge_values[k3+0];
247                vertex_values[k3+1] = edge_values[k3+2] + edge_values[k3+0] - edge_values[k3+1];
248                vertex_values[k3+2] = edge_values[k3+0] + edge_values[k3+1] - edge_values[k3+2];
249
250        }
251
252        return 0;
253}
254
255
256
257int _interpolate_from_vertices_to_edges(int N,
258                 double* vertex_values,
259                 double* edge_values) {
260
261        int k, k3;
262        double q0, q1, q2;
263
264
265        for (k=0; k<N; k++) {
266                k3 = 3*k;
267
268                q0 = vertex_values[k3 + 0];
269                q1 = vertex_values[k3 + 1];
270                q2 = vertex_values[k3 + 2];
271
272                edge_values[k3 + 0] = 0.5*(q1+q2);
273                edge_values[k3 + 1] = 0.5*(q0+q2);
274                edge_values[k3 + 2] = 0.5*(q0+q1);
275        }
276        return 0;
277}
278
279
280int _interpolate_from_edges_to_vertices(int N,
281                 double* vertex_values,
282                 double* edge_values) {
283
284        int k, k3;
285        double e0, e1, e2;
286
287
288        for (k=0; k<N; k++) {
289                k3 = 3*k;
290
291                e0 = edge_values[k3 + 0];
292                e1 = edge_values[k3 + 1];
293                e2 = edge_values[k3 + 2];
294
295                vertex_values[k3 + 0] = e1 + e2 - e0;
296                vertex_values[k3 + 1] = e2 + e0 - e1;
297                vertex_values[k3 + 2] = e0 + e1 - e2;
298        }
299        return 0;
300}
301
302int _backup_centroid_values(int N,
303                            double* centroid_values,
304                            double* centroid_backup_values) {
305    // Backup centroid values
306
307
308    int k;
309
310    for (k=0; k<N; k++) {
311        centroid_backup_values[k] = centroid_values[k];
312    }
313
314
315    return 0;
316}
317
318
319int _saxpy_centroid_values(int N,
320                           double a,
321                           double b,
322                           double* centroid_values,
323                           double* centroid_backup_values) {
324    // Saxby centroid values
325
326
327    int k;
328
329
330    for (k=0; k<N; k++) {
331        centroid_values[k] = a*centroid_values[k] + b*centroid_backup_values[k];
332    }
333
334
335    return 0;
336}
337
338
339int _update(int N,
340            double timestep,
341            double* centroid_values,
342            double* explicit_update,
343            double* semi_implicit_update) {
344        // Update centroid values based on values stored in
345        // explicit_update and semi_implicit_update as well as given timestep
346
347
348        int k;
349        double denominator, x;
350
351
352        // Divide semi_implicit update by conserved quantity
353        for (k=0; k<N; k++) {
354                x = centroid_values[k];
355                if (x == 0.0) {
356                        semi_implicit_update[k] = 0.0;
357                } else {
358                        semi_implicit_update[k] /= x;
359                }
360        }
361
362
363        // Semi implicit updates
364        for (k=0; k<N; k++) {
365                denominator = 1.0 - timestep*semi_implicit_update[k];
366                if (denominator == 0.0) {
367                        return -1;
368                } else {
369                        //Update conserved_quantities from semi implicit updates
370                        centroid_values[k] /= denominator;
371                }
372        }
373
374
375        // Explicit updates
376        for (k=0; k<N; k++) {
377                centroid_values[k] += timestep*explicit_update[k];
378        }
379
380
381        // MH080605 set semi_implicit_update[k] to 0.0 here, rather than in update_conserved_quantities.py
382        for (k=0;k<N;k++){
383                semi_implicit_update[k]=0.0;
384        }
385
386        return 0;
387}
388
389
390int _average_vertex_values(int N,
391                           long* vertex_value_indices,
392                           long* number_of_triangles_per_node,
393                           double* vertex_values, 
394                           double* A) {
395  // Average vertex values to obtain one value per node
396
397  int i, index; 
398  int k = 0; //Track triangles touching each node
399  int current_node = 0;
400  double total = 0.0;
401
402  for (i=0; i<N; i++) {
403 
404    // if (current_node == N) {
405    //   printf("Current node exceeding number of nodes (%d)", N);   
406    //   return 1;
407    // }
408   
409    index = vertex_value_indices[i];
410    k += 1;
411           
412    // volume_id = index / 3
413    // vertex_id = index % 3
414    // total += self.vertex_values[volume_id, vertex_id]
415    total += vertex_values[index];
416     
417    // printf("current_node=%d, index=%d, k=%d, total=%f\n", current_node, index, k, total);
418    if (number_of_triangles_per_node[current_node] == k) {
419      A[current_node] = total/k;
420               
421      // Move on to next node
422      total = 0.0;
423      k = 0;
424      current_node += 1;
425    }
426  }
427                           
428  return 0;
429}
430
431
432/////////////////////////////////////////////////
433// Gateways to Python
434PyObject *update(PyObject *self, PyObject *args) {
435  // FIXME (Ole): It would be great to turn this text into a Python DOC string
436
437  /*"""Update centroid values based on values stored in
438    explicit_update and semi_implicit_update as well as given timestep
439
440    Function implementing forcing terms must take on argument
441    which is the domain and they must update either explicit
442    or implicit updates, e,g,:
443
444    def gravity(domain):
445        ....
446        domain.quantities['xmomentum'].explicit_update = ...
447        domain.quantities['ymomentum'].explicit_update = ...
448
449
450
451    Explicit terms must have the form
452
453        G(q, t)
454
455    and explicit scheme is
456
457       q^{(n+1}) = q^{(n)} + delta_t G(q^{n}, n delta_t)
458
459
460    Semi implicit forcing terms are assumed to have the form
461
462       G(q, t) = H(q, t) q
463
464    and the semi implicit scheme will then be
465
466      q^{(n+1}) = q^{(n)} + delta_t H(q^{n}, n delta_t) q^{(n+1})
467
468  */
469
470        PyObject *quantity;
471        PyArrayObject *centroid_values, *explicit_update, *semi_implicit_update;
472
473        double timestep;
474        int N, err;
475
476
477        // Convert Python arguments to C
478        if (!PyArg_ParseTuple(args, "Od", &quantity, &timestep)) {
479          PyErr_SetString(PyExc_RuntimeError, 
480                          "quantity_ext.c: update could not parse input");
481          return NULL;
482        }
483
484        centroid_values = get_consecutive_array(quantity, "centroid_values");
485        explicit_update = get_consecutive_array(quantity, "explicit_update");
486        semi_implicit_update = get_consecutive_array(quantity, "semi_implicit_update");
487
488        N = centroid_values -> dimensions[0];
489
490        err = _update(N, timestep,
491                      (double*) centroid_values -> data,
492                      (double*) explicit_update -> data,
493                      (double*) semi_implicit_update -> data);
494
495
496        if (err != 0) {
497          PyErr_SetString(PyExc_RuntimeError,
498                          "Zero division in semi implicit update - call Stephen :)");
499          return NULL;
500        }
501
502        // Release and return
503        Py_DECREF(centroid_values);
504        Py_DECREF(explicit_update);
505        Py_DECREF(semi_implicit_update);
506
507        return Py_BuildValue("");
508}
509
510
511PyObject *backup_centroid_values(PyObject *self, PyObject *args) {
512
513        PyObject *quantity;
514        PyArrayObject *centroid_values, *centroid_backup_values;
515
516        int N, err;
517
518
519        // Convert Python arguments to C
520        if (!PyArg_ParseTuple(args, "O", &quantity)) {
521          PyErr_SetString(PyExc_RuntimeError, 
522                          "quantity_ext.c: backup_centroid_values could not parse input");
523          return NULL;
524        }
525
526        centroid_values        = get_consecutive_array(quantity, "centroid_values");
527        centroid_backup_values = get_consecutive_array(quantity, "centroid_backup_values");
528
529        N = centroid_values -> dimensions[0];
530
531        err = _backup_centroid_values(N,
532                      (double*) centroid_values -> data,
533                      (double*) centroid_backup_values -> data);
534
535
536        // Release and return
537        Py_DECREF(centroid_values);
538        Py_DECREF(centroid_backup_values);
539
540        return Py_BuildValue("");
541}
542
543PyObject *saxpy_centroid_values(PyObject *self, PyObject *args) {
544
545        PyObject *quantity;
546        PyArrayObject *centroid_values, *centroid_backup_values;
547
548        double a,b;
549        int N, err;
550
551
552        // Convert Python arguments to C
553        if (!PyArg_ParseTuple(args, "Odd", &quantity, &a, &b)) {
554          PyErr_SetString(PyExc_RuntimeError, 
555                          "quantity_ext.c: saxpy_centroid_values could not parse input");
556          return NULL;
557        }
558
559        centroid_values        = get_consecutive_array(quantity, "centroid_values");
560        centroid_backup_values = get_consecutive_array(quantity, "centroid_backup_values");
561
562        N = centroid_values -> dimensions[0];
563
564        err = _saxpy_centroid_values(N,a,b,
565                      (double*) centroid_values -> data,
566                      (double*) centroid_backup_values -> data);
567
568
569        // Release and return
570        Py_DECREF(centroid_values);
571        Py_DECREF(centroid_backup_values);
572
573        return Py_BuildValue("");
574}
575
576
577PyObject *interpolate_from_vertices_to_edges(PyObject *self, PyObject *args) {
578        //
579        //Compute edge values from vertex values using linear interpolation
580        //
581       
582        PyObject *quantity;
583        PyArrayObject *vertex_values, *edge_values;
584
585        int N, err;
586
587        // Convert Python arguments to C
588        if (!PyArg_ParseTuple(args, "O", &quantity)) {
589          PyErr_SetString(PyExc_RuntimeError, 
590                          "quantity_ext.c: interpolate_from_vertices_to_edges could not parse input");
591          return NULL;
592        }
593       
594        vertex_values = get_consecutive_array(quantity, "vertex_values");
595        edge_values = get_consecutive_array(quantity, "edge_values");
596
597        N = vertex_values -> dimensions[0];
598
599        err = _interpolate_from_vertices_to_edges(N,
600                           (double*) vertex_values -> data,
601                           (double*) edge_values -> data);
602
603        if (err != 0) {
604          PyErr_SetString(PyExc_RuntimeError, 
605                          "Interpolate could not be computed");
606          return NULL;
607        }
608
609        // Release and return
610        Py_DECREF(vertex_values);
611        Py_DECREF(edge_values);
612
613        return Py_BuildValue("");
614}
615
616
617PyObject *interpolate_from_edges_to_vertices(PyObject *self, PyObject *args) {
618        //
619        //Compute vertex values from edge values using linear interpolation
620        //
621       
622        PyObject *quantity;
623        PyArrayObject *vertex_values, *edge_values;
624
625        int N, err;
626
627        // Convert Python arguments to C
628        if (!PyArg_ParseTuple(args, "O", &quantity)) {
629          PyErr_SetString(PyExc_RuntimeError, 
630                          "quantity_ext.c: interpolate_from_edges_to_vertices could not parse input");
631          return NULL;
632        }
633       
634        vertex_values = get_consecutive_array(quantity, "vertex_values");
635        edge_values = get_consecutive_array(quantity, "edge_values");
636
637        N = vertex_values -> dimensions[0];
638
639        err = _interpolate_from_edges_to_vertices(N,
640                           (double*) vertex_values -> data,
641                           (double*) edge_values -> data);
642
643        if (err != 0) {
644          PyErr_SetString(PyExc_RuntimeError, 
645                          "Interpolate could not be computed");
646          return NULL;
647        }
648
649        // Release and return
650        Py_DECREF(vertex_values);
651        Py_DECREF(edge_values);
652
653        return Py_BuildValue("");
654}
655
656
657PyObject *average_vertex_values(PyObject *self, PyObject *args) {
658
659        PyArrayObject
660          *vertex_value_indices, 
661          *number_of_triangles_per_node,
662          *vertex_values,
663          *A;
664       
665
666        int N, err;
667
668        // Convert Python arguments to C
669        if (!PyArg_ParseTuple(args, "OOOO",
670                              &vertex_value_indices, 
671                              &number_of_triangles_per_node,
672                              &vertex_values, 
673                              &A)) {
674          PyErr_SetString(PyExc_RuntimeError, 
675                          "quantity_ext.c: average_vertex_values could not parse input");
676          return NULL;
677        }
678       
679        N = vertex_value_indices -> dimensions[0];
680        // printf("Got parameters, N=%d\n", N);
681        err = _average_vertex_values(N,
682                                     (long*) vertex_value_indices -> data,
683                                     (long*) number_of_triangles_per_node -> data,
684                                     (double*) vertex_values -> data, 
685                                     (double*) A -> data);
686
687        //printf("Error %d", err);
688        if (err != 0) {
689          PyErr_SetString(PyExc_RuntimeError, 
690                          "average_vertex_values could not be computed");
691          return NULL;
692        }
693
694        return Py_BuildValue("");
695}
696
697
698
699PyObject *compute_gradients(PyObject *self, PyObject *args) {
700  //"""Compute gradients of triangle surfaces defined by centroids of
701  //neighbouring volumes.
702  //If one edge is on the boundary, use own centroid as neighbour centroid.
703  //If two or more are on the boundary, fall back to first order scheme.
704  //"""
705
706
707        PyObject *quantity, *domain, *R;
708        PyArrayObject
709                *centroids,            //Coordinates at centroids
710                *centroid_values,      //Values at centroids
711                *number_of_boundaries, //Number of boundaries for each triangle
712                *surrogate_neighbours, //True neighbours or - if one missing - self
713                *a, *b;                //Return values
714
715        int dimensions[1], N, err;
716
717        // Convert Python arguments to C
718        if (!PyArg_ParseTuple(args, "O", &quantity)) {
719          PyErr_SetString(PyExc_RuntimeError, 
720                          "quantity_ext.c: compute_gradients could not parse input");   
721          return NULL;
722        }
723
724        domain = PyObject_GetAttrString(quantity, "domain");
725        if (!domain) {
726          PyErr_SetString(PyExc_RuntimeError, 
727                          "compute_gradients could not obtain domain object from quantity");
728          return NULL;
729        }
730
731        // Get pertinent variables
732
733        centroids = get_consecutive_array(domain, "centroid_coordinates");
734        centroid_values = get_consecutive_array(quantity, "centroid_values");
735        surrogate_neighbours = get_consecutive_array(domain, "surrogate_neighbours");
736        number_of_boundaries = get_consecutive_array(domain, "number_of_boundaries");
737
738        N = centroid_values -> dimensions[0];
739
740        // Release
741        Py_DECREF(domain);
742
743        // Allocate space for return vectors a and b (don't DECREF)
744        dimensions[0] = N;
745        a = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
746        b = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
747
748
749
750        err = _compute_gradients(N,
751                        (double*) centroids -> data,
752                        (double*) centroid_values -> data,
753                        (long*) number_of_boundaries -> data,
754                        (long*) surrogate_neighbours -> data,
755                        (double*) a -> data,
756                        (double*) b -> data);
757
758        if (err != 0) {
759          PyErr_SetString(PyExc_RuntimeError, "Gradient could not be computed");
760          return NULL;
761        }
762
763        // Release
764        Py_DECREF(centroids);
765        Py_DECREF(centroid_values);
766        Py_DECREF(number_of_boundaries);
767        Py_DECREF(surrogate_neighbours);
768
769        // Build result, release and return
770        R = Py_BuildValue("OO", PyArray_Return(a), PyArray_Return(b));
771        Py_DECREF(a);
772        Py_DECREF(b);
773        return R;
774}
775
776
777
778PyObject *extrapolate_second_order(PyObject *self, PyObject *args) {
779
780        PyObject *quantity, *domain;
781        PyArrayObject
782            *centroids,            //Coordinates at centroids
783            *centroid_values,      //Values at centroids
784            *vertex_coordinates,   //Coordinates at vertices
785            *vertex_values,        //Values at vertices
786            *edge_values,          //Values at edges
787            *number_of_boundaries, //Number of boundaries for each triangle
788            *surrogate_neighbours, //True neighbours or - if one missing - self
789            *a, *b;                //Gradients
790
791        //int N, err;
792        int dimensions[1], N, err;
793        //double *a, *b;  //Gradients
794
795        // Convert Python arguments to C
796        if (!PyArg_ParseTuple(args, "O", &quantity)) {
797          PyErr_SetString(PyExc_RuntimeError, 
798                          "extrapolate_second_order could not parse input");   
799          return NULL;
800        }
801
802        domain = PyObject_GetAttrString(quantity, "domain");
803        if (!domain) {
804          PyErr_SetString(PyExc_RuntimeError, 
805                          "extrapolate_second_order could not obtain domain object from quantity");     
806          return NULL;
807        }
808
809        // Get pertinent variables
810        centroids            = get_consecutive_array(domain,   "centroid_coordinates");
811        centroid_values      = get_consecutive_array(quantity, "centroid_values");
812        surrogate_neighbours = get_consecutive_array(domain,   "surrogate_neighbours");
813        number_of_boundaries = get_consecutive_array(domain,   "number_of_boundaries");
814        vertex_coordinates   = get_consecutive_array(domain,   "vertex_coordinates");
815        vertex_values        = get_consecutive_array(quantity, "vertex_values");
816        edge_values          = get_consecutive_array(quantity, "edge_values");
817
818        N = centroid_values -> dimensions[0];
819
820        // Release
821        Py_DECREF(domain);
822
823        //Allocate space for return vectors a and b (don't DECREF)
824        dimensions[0] = N;
825        a = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
826        b = (PyArrayObject *) PyArray_FromDims(1, dimensions, PyArray_DOUBLE);
827
828        //FIXME: Odd that I couldn't use normal arrays
829        //Allocate space for return vectors a and b (don't DECREF)
830        //a = (double*) malloc(N * sizeof(double));
831        //if (!a) return NULL;
832        //b = (double*) malloc(N * sizeof(double));
833        //if (!b) return NULL;
834
835
836        err = _compute_gradients(N,
837                        (double*) centroids -> data,
838                        (double*) centroid_values -> data,
839                        (long*) number_of_boundaries -> data,
840                        (long*) surrogate_neighbours -> data,
841                        (double*) a -> data,
842                        (double*) b -> data);
843
844        if (err != 0) {
845          PyErr_SetString(PyExc_RuntimeError, "Gradient could not be computed");
846          return NULL;
847        }
848
849        err = _extrapolate(N,
850                        (double*) centroids -> data,
851                        (double*) centroid_values -> data,
852                        (double*) vertex_coordinates -> data,
853                        (double*) vertex_values -> data,
854                        (double*) edge_values -> data,
855                        (double*) a -> data,
856                        (double*) b -> data);
857
858
859        if (err != 0) {
860          PyErr_SetString(PyExc_RuntimeError,
861                          "Internal function _extrapolate failed");
862          return NULL;
863        }
864
865
866
867        // Release
868        Py_DECREF(centroids);
869        Py_DECREF(centroid_values);
870        Py_DECREF(number_of_boundaries);
871        Py_DECREF(surrogate_neighbours);
872        Py_DECREF(vertex_coordinates);
873        Py_DECREF(vertex_values);
874        Py_DECREF(edge_values);
875        Py_DECREF(a);
876        Py_DECREF(b);
877
878        return Py_BuildValue("");
879}
880
881
882
883PyObject *limit_old(PyObject *self, PyObject *args) {
884  //Limit slopes for each volume to eliminate artificial variance
885  //introduced by e.g. second order extrapolator
886
887  //This is an unsophisticated limiter as it does not take into
888  //account dependencies among quantities.
889
890  //precondition:
891  //  vertex values are estimated from gradient
892  //postcondition:
893  //  vertex values are updated
894  //
895
896        PyObject *quantity, *domain, *Tmp;
897        PyArrayObject
898            *qv, //Conserved quantities at vertices
899            *qc, //Conserved quantities at centroids
900            *neighbours;
901
902        int k, i, n, N, k3;
903        double beta_w; //Safety factor
904        double *qmin, *qmax, qn;
905
906        // Convert Python arguments to C
907        if (!PyArg_ParseTuple(args, "O", &quantity)) {
908          PyErr_SetString(PyExc_RuntimeError, 
909                          "quantity_ext.c: limit_old could not parse input");
910          return NULL;
911        }
912
913        domain = PyObject_GetAttrString(quantity, "domain");
914        if (!domain) {
915          PyErr_SetString(PyExc_RuntimeError, 
916                          "quantity_ext.c: limit_old could not obtain domain object from quantity");                   
917         
918          return NULL;
919        }
920
921        //neighbours = (PyArrayObject*) PyObject_GetAttrString(domain, "neighbours");
922        neighbours = get_consecutive_array(domain, "neighbours");
923
924        // Get safety factor beta_w
925        Tmp = PyObject_GetAttrString(domain, "beta_w");
926        if (!Tmp) {
927          PyErr_SetString(PyExc_RuntimeError, 
928                          "quantity_ext.c: limit_old could not obtain beta_w object from domain");                     
929         
930          return NULL;
931        }       
932
933        beta_w = PyFloat_AsDouble(Tmp);
934
935        Py_DECREF(Tmp);
936        Py_DECREF(domain);
937
938
939        qc = get_consecutive_array(quantity, "centroid_values");
940        qv = get_consecutive_array(quantity, "vertex_values");
941
942
943        N = qc -> dimensions[0];
944
945        // Find min and max of this and neighbour's centroid values
946        qmin = malloc(N * sizeof(double));
947        qmax = malloc(N * sizeof(double));
948        for (k=0; k<N; k++) {
949                k3=k*3;
950
951                qmin[k] = ((double*) qc -> data)[k];
952                qmax[k] = qmin[k];
953
954                for (i=0; i<3; i++) {
955                        n = ((long*) neighbours -> data)[k3+i];
956                        if (n >= 0) {
957                                qn = ((double*) qc -> data)[n]; //Neighbour's centroid value
958
959                                qmin[k] = min(qmin[k], qn);
960                                qmax[k] = max(qmax[k], qn);
961                        }
962                        //qmin[k] = max(qmin[k],0.5*((double*) qc -> data)[k]);
963                        //qmax[k] = min(qmax[k],2.0*((double*) qc -> data)[k]);
964                }
965        }
966
967        // Call underlying routine
968        _limit_old(N, beta_w, (double*) qc -> data, (double*) qv -> data, qmin, qmax);
969
970        free(qmin);
971        free(qmax);
972        return Py_BuildValue("");
973}
974
975
976PyObject *limit_by_vertex(PyObject *self, PyObject *args) {
977  //Limit slopes for each volume to eliminate artificial variance
978  //introduced by e.g. second order extrapolator
979
980  //This is an unsophisticated limiter as it does not take into
981  //account dependencies among quantities.
982
983  //precondition:
984  //  vertex values are estimated from gradient
985  //postcondition:
986  //  vertex and edge values are updated
987  //
988
989        PyObject *quantity, *domain, *Tmp;
990        PyArrayObject
991            *vertex_values,   //Conserved quantities at vertices
992            *centroid_values, //Conserved quantities at centroids
993            *edge_values,     //Conserved quantities at edges
994            *neighbours;
995
996        double beta_w; //Safety factor
997        int N, err;
998
999
1000        // Convert Python arguments to C
1001        if (!PyArg_ParseTuple(args, "O", &quantity)) {
1002          PyErr_SetString(PyExc_RuntimeError, 
1003                          "quantity_ext.c: limit_by_vertex could not parse input");
1004          return NULL;
1005        }
1006
1007        domain = PyObject_GetAttrString(quantity, "domain");
1008        if (!domain) {
1009          PyErr_SetString(PyExc_RuntimeError, 
1010                          "quantity_ext.c: limit_by_vertex could not obtain domain object from quantity");                     
1011         
1012          return NULL;
1013        }
1014
1015        // Get safety factor beta_w
1016        Tmp = PyObject_GetAttrString(domain, "beta_w");
1017        if (!Tmp) {
1018          PyErr_SetString(PyExc_RuntimeError, 
1019                          "quantity_ext.c: limit_by_vertex could not obtain beta_w object from domain");                       
1020         
1021          return NULL;
1022        }       
1023
1024
1025        // Get pertinent variables
1026        neighbours       = get_consecutive_array(domain, "neighbours");
1027        centroid_values  = get_consecutive_array(quantity, "centroid_values");
1028        vertex_values    = get_consecutive_array(quantity, "vertex_values");
1029        edge_values      = get_consecutive_array(quantity, "edge_values");
1030        beta_w           = PyFloat_AsDouble(Tmp);
1031
1032
1033        N = centroid_values -> dimensions[0];
1034
1035        err = _limit_by_vertex(N, beta_w,
1036                               (double*) centroid_values -> data,
1037                               (double*) vertex_values -> data,
1038                               (double*) edge_values -> data,
1039                               (long*)   neighbours -> data);
1040
1041        if (err != 0) {
1042          PyErr_SetString(PyExc_RuntimeError,
1043                          "Internal function _limit_by_vertex failed");
1044          return NULL;
1045        }       
1046
1047
1048        // Release
1049        Py_DECREF(neighbours);
1050        Py_DECREF(centroid_values);
1051        Py_DECREF(vertex_values);
1052        Py_DECREF(edge_values);
1053        Py_DECREF(Tmp);
1054
1055
1056        return Py_BuildValue("");
1057}
1058
1059
1060
1061PyObject *limit_by_edge(PyObject *self, PyObject *args) {
1062  //Limit slopes for each volume to eliminate artificial variance
1063  //introduced by e.g. second order extrapolator
1064
1065  //This is an unsophisticated limiter as it does not take into
1066  //account dependencies among quantities.
1067
1068  //precondition:
1069  //  vertex values are estimated from gradient
1070  //postcondition:
1071  //  vertex and edge values are updated
1072  //
1073
1074        PyObject *quantity, *domain, *Tmp;
1075        PyArrayObject
1076            *vertex_values,   //Conserved quantities at vertices
1077            *centroid_values, //Conserved quantities at centroids
1078            *edge_values,     //Conserved quantities at edges
1079            *neighbours;
1080
1081        double beta_w; //Safety factor
1082        int N, err;
1083
1084
1085        // Convert Python arguments to C
1086        if (!PyArg_ParseTuple(args, "O", &quantity)) {
1087          PyErr_SetString(PyExc_RuntimeError, 
1088                          "quantity_ext.c: limit_by_edge could not parse input");
1089          return NULL;
1090        }
1091
1092        domain = PyObject_GetAttrString(quantity, "domain");
1093        if (!domain) {
1094          PyErr_SetString(PyExc_RuntimeError, 
1095                          "quantity_ext.c: limit_by_edge could not obtain domain object from quantity");                       
1096         
1097          return NULL;
1098        }
1099
1100        // Get safety factor beta_w
1101        Tmp = PyObject_GetAttrString(domain, "beta_w");
1102        if (!Tmp) {
1103          PyErr_SetString(PyExc_RuntimeError, 
1104                          "quantity_ext.c: limit_by_edge could not obtain beta_w object from domain");                 
1105         
1106          return NULL;
1107        }       
1108
1109
1110        // Get pertinent variables
1111        neighbours       = get_consecutive_array(domain, "neighbours");
1112        centroid_values  = get_consecutive_array(quantity, "centroid_values");
1113        vertex_values    = get_consecutive_array(quantity, "vertex_values");
1114        edge_values      = get_consecutive_array(quantity, "edge_values");
1115        beta_w           = PyFloat_AsDouble(Tmp);
1116
1117
1118        N = centroid_values -> dimensions[0];
1119
1120        err = _limit_by_edge(N, beta_w,
1121                               (double*) centroid_values -> data,
1122                               (double*) vertex_values -> data,
1123                               (double*) edge_values -> data,
1124                               (long*)   neighbours -> data);
1125
1126        if (err != 0) {
1127          PyErr_SetString(PyExc_RuntimeError,
1128                          "Internal function _limit_by_vertex failed");
1129          return NULL;
1130        }       
1131
1132
1133        // Release
1134        Py_DECREF(neighbours);
1135        Py_DECREF(centroid_values);
1136        Py_DECREF(vertex_values);
1137        Py_DECREF(edge_values);
1138        Py_DECREF(Tmp);
1139
1140
1141        return Py_BuildValue("");
1142}
1143
1144
1145
1146// Method table for python module
1147static struct PyMethodDef MethodTable[] = {
1148        {"limit_old", limit_old, METH_VARARGS, "Print out"},
1149        {"limit_by_vertex", limit_by_vertex, METH_VARARGS, "Print out"},
1150        {"limit_by_edge", limit_by_edge, METH_VARARGS, "Print out"},
1151        {"update", update, METH_VARARGS, "Print out"},
1152        {"backup_centroid_values", backup_centroid_values, METH_VARARGS, "Print out"},
1153        {"saxpy_centroid_values", saxpy_centroid_values, METH_VARARGS, "Print out"},
1154        {"compute_gradients", compute_gradients, METH_VARARGS, "Print out"},
1155        {"extrapolate_second_order", extrapolate_second_order,
1156                METH_VARARGS, "Print out"},
1157        {"interpolate_from_vertices_to_edges",
1158                interpolate_from_vertices_to_edges,
1159                METH_VARARGS, "Print out"},
1160        {"interpolate_from_edges_to_vertices",
1161                interpolate_from_edges_to_vertices,
1162                METH_VARARGS, "Print out"},
1163        {"average_vertex_values", average_vertex_values, METH_VARARGS, "Print out"},           
1164        {NULL, NULL, 0, NULL}   // sentinel
1165};
1166
1167// Module initialisation
1168void initquantity_ext(void){
1169  Py_InitModule("quantity_ext", MethodTable);
1170
1171  import_array(); // Necessary for handling of NumPY structures
1172}
Note: See TracBrowser for help on using the repository browser.