source: trunk/anuga_work/shallow_water_balanced_steve/swb_domain_ext.c @ 8383

Last change on this file since 8383 was 8374, checked in by steve, 13 years ago

Still working on channel flow

File size: 21.7 KB
Line 
1// Python - C extension module for shallow_water.py
2//
3// To compile (Python2.6):
4//  gcc -c swb_domain_ext.c -I/usr/include/python2.6 -o domain_ext.o -Wall -O
5//  gcc -shared swb_domain_ext.o  -o swb_domain_ext.so
6//
7// or use python compile.py
8//
9// See the module swb_domain.py for more documentation on
10// how to use this module
11//
12//
13// Stephen Roberts, ANU 2009
14// Ole Nielsen, GA 2004
15
16
17#include "Python.h"
18#include "numpy/arrayobject.h"
19#include "math.h"
20#include <stdio.h>
21//#include "numpy_shim.h"
22
23// Shared code snippets
24#include "util_ext.h"
25
26
27const double pi = 3.14159265358979;
28
29// Computational function for rotation
30int _rotate(double *q, double n1, double n2) {
31  /*Rotate the last  2 coordinates of q (q[1], q[2])
32    from x,y coordinates to coordinates based on normal vector (n1, n2).
33
34    Result is returned in array 2x1 r
35    To rotate in opposite direction, call rotate with (q, n1, -n2)
36
37    Contents of q are changed by this function */
38
39
40  double q1, q2;
41
42  // Shorthands
43  q1 = q[1];  // x coordinate
44  q2 = q[2];  // y coordinate
45
46  // Rotate
47  q[1] =  n1*q1 + n2*q2;
48  q[2] = -n2*q1 + n1*q2;
49
50  return 0;
51}
52
53// Innermost flux function
54int _flux_function(double *q_inside, double *q_outside,
55                   double n1, double n2, 
56                   double g,
57                   double *edgeflux, double *local_max_speed) 
58{
59
60  /*Compute fluxes between volumes for the shallow water wave equation
61    cast in terms of the 'stage', w = h+z using
62    the 'central scheme' as described in
63
64    Kurganov, Noelle, Petrova. 'Semidiscrete Central-Upwind Schemes For
65    Hyperbolic Conservation Laws and Hamilton-Jacobi Equations'.
66    Siam J. Sci. Comput. Vol. 23, No. 3, pp. 707-740.
67
68    The implemented formula is given in equation (3.15) on page 714
69  */
70
71  int i;
72
73  double z_star, h_inside_star, h_outside_star;
74  double w_inside,  h_inside,  u_inside,  v_inside,  z_inside;
75  double w_outside, h_outside, u_outside, v_outside, z_outside;
76  double s_min, s_max, soundspeed_inside, soundspeed_outside;
77  double epsilon, denom, inverse_denominator;
78
79  // Workspace
80  double cons_inside[3], cons_outside[3], flux_outside[3], flux_inside[3];
81
82  epsilon = 1.0e-15;
83
84  // Setup aliases
85  w_inside = q_inside[0]; 
86  h_inside = q_inside[3];
87  z_inside = q_inside[4];
88  u_inside = q_inside[5];
89  v_inside = q_inside[6];
90
91  w_outside = q_outside[0]; 
92  h_outside = q_outside[3];
93  z_outside = q_outside[4];
94  u_outside = q_outside[5];
95  v_outside = q_outside[6];
96
97
98  // Rotate the velocity terms and update. Setup cons_ to hold conservative rotated
99  // variables
100  cons_inside[0] = w_inside;
101  cons_inside[1] = u_inside;
102  cons_inside[2] = v_inside;
103
104  _rotate(cons_inside, n1, n2);
105
106  u_inside = cons_inside[1];
107  v_inside = cons_inside[2];
108  cons_inside[1] = u_inside*h_inside;
109  cons_inside[2] = v_inside*h_inside;
110
111  cons_outside[0] = w_outside;
112  cons_outside[1] = u_outside;
113  cons_outside[2] = v_outside;
114
115  _rotate(cons_outside, n1, n2);
116
117  u_outside = cons_outside[1];
118  v_outside = cons_outside[2];
119  cons_outside[1] = u_outside*h_outside;
120  cons_outside[2] = v_outside*h_outside;
121
122
123
124  // Deal with discontinuous z
125  z_star = max(z_inside, z_outside);
126  h_inside_star  = max(0.0, w_inside-z_star);
127  h_outside_star = max(0.0, w_outside-z_star);
128                   
129
130  // Maximal and minimal wave speeds
131  soundspeed_inside  = sqrt(g*h_inside_star);
132  soundspeed_outside = sqrt(g*h_outside_star); 
133 
134  s_max = max(u_inside + soundspeed_inside, u_outside + soundspeed_outside);
135  s_max = max(0.0, s_max);
136
137  s_min = min(u_inside - soundspeed_inside, u_outside - soundspeed_outside);
138  s_min = min(0.0, s_min);
139 
140  // Flux formulas
141  flux_inside[0] = u_inside*h_inside_star;
142  flux_inside[1] = u_inside*u_inside*h_inside_star + 0.5*g*h_inside_star*h_inside_star;
143  flux_inside[2] = u_inside*v_inside*h_inside_star;
144
145  flux_outside[0] = u_outside*h_outside_star;
146  flux_outside[1] = u_outside*u_outside*h_outside_star + 0.5*g*h_outside_star*h_outside_star;
147  flux_outside[2] = u_outside*v_outside*h_outside_star;
148
149  // Flux computation
150  denom = s_max - s_min;
151
152  edgeflux[0] = 0.0;
153  edgeflux[1] = 0.0;
154  edgeflux[2] = 0.0;
155 
156  if (denom < epsilon) 
157    {     
158      *local_max_speed = 0.0;
159      //printf("here %g\n",h_inside);
160      // Add in edge pressure term due to discontinuous bed
161      if ( h_inside > 0.0 ) edgeflux[1] = 0.5*g*h_inside*h_inside ;
162    } 
163  else 
164    {
165      inverse_denominator = 1.0/denom;
166      for (i = 0; i < 3; i++) 
167        {
168          edgeflux[i] = s_max*flux_inside[i] - s_min*flux_outside[i];
169          edgeflux[i] += s_max*s_min*(cons_outside[i] - cons_inside[i]);
170          edgeflux[i] *= inverse_denominator;
171        }
172
173      // Balance the pressure term
174      // FIXME SR: I think we need to add a term which uses simpson's rule.
175      //edgeflux[1] += 0.5*g*h_inside*h_inside - 0.5*g*h_inside_star*h_inside_star;
176      edgeflux[1] -=  0.5*g*h_inside_star*h_inside_star;
177     
178    }
179 
180// Maximal wavespeed
181  *local_max_speed = max(fabs(s_max), fabs(s_min));
182  //printf("local speed % g  h_inside %g \n",*local_max_speed, h_inside);
183  // Rotate back
184  _rotate(edgeflux, n1, -n2);
185 
186  return 0;
187}
188
189
190
191//=========================================================================
192// Python Glue
193//=========================================================================
194
195
196//========================================================================
197// Compute fluxes
198//========================================================================
199
200PyObject *compute_fluxes(PyObject *self, PyObject *args) {
201  /*Compute all fluxes and the timestep suitable for all volumes
202    in domain.
203
204    Compute total flux for each conserved quantity using "flux_function_central"
205
206    Fluxes across each edge are scaled by edgelengths and summed up
207    Resulting flux is then scaled by area and stored in
208    explicit_update for each of the three conserved quantities
209    stage, xmomentum and ymomentum
210
211    The maximal allowable speed computed by the flux_function for each volume
212    is converted to a timestep that must not be exceeded. The minimum of
213    those is computed as the next overall timestep.
214
215    Python call:
216    timestep = compute_fluxes(timestep, domain, stage, xmom, ymom, height, bed, xvel, yvel)
217
218
219    Post conditions:
220      domain.explicit_update is reset to computed flux values
221      returns timestep which is the largest step satisfying all volumes.
222
223
224  */
225
226  PyObject
227    *domain,
228    *stage, 
229    *xmom, 
230    *ymom,
231    *height,
232    *bed,
233    *xvel,
234    *yvel;
235
236    PyArrayObject
237      *num_neighbours          ,
238      *num_neighbour_edges     ,
239      *num_normals             ,
240      *num_edgelengths         ,     
241      *num_radii               ,   
242      *num_areas               ,
243      *num_tri_full_flag       ,
244      *num_max_speed           ,
245      *num_stage_edge_values   ,
246      *num_xmom_edge_values    ,
247      *num_ymom_edge_values    ,
248      *num_height_edge_values  ,
249      *num_bed_edge_values     ,
250      *num_xvel_edge_values    ,
251      *num_yvel_edge_values    ,
252      *num_stage_boundary_values ,
253      *num_xmom_boundary_values  ,
254      *num_ymom_boundary_values  ,
255      *num_height_boundary_values,
256      *num_bed_boundary_values   ,
257      *num_xvel_boundary_values  ,
258      *num_yvel_boundary_values  ,
259      *num_stage_explicit_update ,
260      *num_xmom_explicit_update  ,
261      *num_ymom_explicit_update ;
262
263    long
264      *neighbours          ,
265      *neighbour_edges     ,
266      *tri_full_flag       ; 
267
268    double
269      *normals             ,
270      *edgelengths         ,     
271      *radii               ,   
272      *areas               ,
273      *max_speed           ,
274      *stage_edge_values   ,
275      *xmom_edge_values    ,
276      *ymom_edge_values    ,
277      *height_edge_values  ,
278      *bed_edge_values     ,
279      *xvel_edge_values    ,
280      *yvel_edge_values    ,
281      *stage_boundary_values ,
282      *xmom_boundary_values  ,
283      *ymom_boundary_values  ,
284      *height_boundary_values,
285      *bed_boundary_values   ,
286      *xvel_boundary_values  ,
287      *yvel_boundary_values  ,
288      *stage_explicit_update ,
289      *xmom_explicit_update  ,
290      *ymom_explicit_update ;
291
292   
293
294    double flux_timestep, g;
295    double local_max_speed, length, inv_area;
296
297    int k, i, m, n;
298    int ki, nm=0, ki2; // Index shorthands
299   
300    double ql[7], qr[7]; // Work arrays for storing local evolving quantities
301    double edgeflux[3];  // Work array for summing up fluxes
302
303   
304    //======================================================================
305    // Convert Python arguments to C
306    //======================================================================
307    if (!PyArg_ParseTuple(args, "dOOOOOOOO", 
308                          &flux_timestep, 
309                          &domain, 
310                          &stage, 
311                          &xmom, 
312                          &ymom, 
313                          &height,
314                          &bed,
315                          &xvel, 
316                          &yvel)) {
317      PyErr_SetString(PyExc_RuntimeError, "Input arguments failed");
318      return NULL;
319    }
320   
321    //======================================================================
322    // Extract data from python objects
323    //======================================================================
324    g = get_python_double(domain,"g");
325   
326    num_neighbours             = get_consecutive_array(domain, "neighbours");
327    num_neighbour_edges        = get_consecutive_array(domain, "neighbour_edges"); 
328    num_normals                = get_consecutive_array(domain, "normals");
329    num_edgelengths            = get_consecutive_array(domain, "edgelengths");   
330    num_radii                  = get_consecutive_array(domain, "radii");   
331    num_areas                  = get_consecutive_array(domain, "areas");   
332    num_tri_full_flag          = get_consecutive_array(domain, "tri_full_flag");
333    num_max_speed              = get_consecutive_array(domain, "max_speed");
334   
335    num_stage_edge_values      = get_consecutive_array(stage, "edge_values");   
336    num_xmom_edge_values       = get_consecutive_array(xmom, "edge_values");   
337    num_ymom_edge_values       = get_consecutive_array(ymom, "edge_values"); 
338    num_height_edge_values     = get_consecutive_array(height, "edge_values"); 
339    num_bed_edge_values        = get_consecutive_array(bed, "edge_values");       
340    num_xvel_edge_values       = get_consecutive_array(xvel, "edge_values");   
341    num_yvel_edge_values       = get_consecutive_array(yvel, "edge_values");   
342   
343    num_stage_boundary_values  = get_consecutive_array(stage, "boundary_values");   
344    num_xmom_boundary_values   = get_consecutive_array(xmom, "boundary_values");   
345    num_ymom_boundary_values   = get_consecutive_array(ymom, "boundary_values"); 
346    num_height_boundary_values = get_consecutive_array(height, "boundary_values"); 
347    num_bed_boundary_values    = get_consecutive_array(bed, "boundary_values"); 
348    num_xvel_boundary_values   = get_consecutive_array(xvel, "boundary_values"); 
349    num_yvel_boundary_values   = get_consecutive_array(yvel, "boundary_values"); 
350   
351    num_stage_explicit_update  = get_consecutive_array(stage, "explicit_update");   
352    num_xmom_explicit_update   = get_consecutive_array(xmom, "explicit_update");   
353    num_ymom_explicit_update   = get_consecutive_array(ymom, "explicit_update"); 
354   
355    //---------------------------------------------------------------------------
356   
357    neighbours         = (long *) num_neighbours-> data;
358    neighbour_edges    = (long *) num_neighbour_edges-> data;
359    normals            = (double *) num_normals -> data;
360    edgelengths        = (double *) num_edgelengths -> data;
361    radii              = (double *) num_radii -> data;
362    areas              = (double *) num_areas -> data; 
363    tri_full_flag      = (long *) num_tri_full_flag -> data; 
364    max_speed          = (double *) num_max_speed -> data;
365   
366    stage_edge_values       = (double *) num_stage_edge_values -> data;   
367    xmom_edge_values        = (double *) num_xmom_edge_values -> data;
368    ymom_edge_values        = (double *) num_ymom_edge_values -> data;
369    height_edge_values      = (double *) num_height_edge_values -> data;
370    bed_edge_values         = (double *) num_bed_edge_values -> data;
371    xvel_edge_values        = (double *) num_xvel_edge_values -> data;
372    yvel_edge_values        = (double *) num_yvel_edge_values -> data;
373   
374    stage_boundary_values      = (double *) num_stage_boundary_values -> data; 
375    xmom_boundary_values       = (double *) num_xmom_boundary_values -> data;
376    ymom_boundary_values       = (double *) num_ymom_boundary_values -> data;
377    height_boundary_values     = (double *) num_height_boundary_values -> data;
378    bed_boundary_values        = (double *) num_bed_boundary_values -> data;
379    xvel_boundary_values       = (double *) num_xvel_boundary_values -> data;
380    yvel_boundary_values       = (double *) num_yvel_boundary_values -> data;
381   
382    stage_explicit_update      = (double *) num_stage_explicit_update -> data;
383    xmom_explicit_update       = (double *) num_xmom_explicit_update -> data;
384    ymom_explicit_update       = (double *) num_ymom_explicit_update -> data;
385   
386   
387    int number_of_elements = num_stage_edge_values -> dimensions[0];
388
389    //======================================================================
390    // Flux computation routine and update the explicit update arrays
391    //======================================================================
392
393    // Set explicit_update to zero for all conserved_quantities.
394    // This assumes compute_fluxes called before forcing terms
395
396    memset((char*) stage_explicit_update, 0, number_of_elements*sizeof(double));
397    memset((char*) xmom_explicit_update, 0, number_of_elements*sizeof(double));
398    memset((char*) ymom_explicit_update, 0, number_of_elements*sizeof(double));   
399 
400    // For all triangles
401    for (k = 0; k < number_of_elements; k++) 
402      { 
403        max_speed[k] = 0.0;
404
405        // Loop through neighbours and compute edge flux for each  epsilon
406        for (i = 0; i < 3; i++) 
407          {
408            ki = k*3 + i; // Linear index to edge i of triangle k
409     
410            // Get left hand side values from triangle k, edge i
411            ql[0] = stage_edge_values[ki];
412            ql[1] = xmom_edge_values[ki];
413            ql[2] = ymom_edge_values[ki];
414            ql[3] = height_edge_values[ki];
415            ql[4] = bed_edge_values[ki];
416            ql[5] = xvel_edge_values[ki];
417            ql[6] = yvel_edge_values[ki];
418
419            // Get right hand side values either from neighbouring triangle
420            // or from boundary array (Quantities at neighbour on nearest face).
421            n = neighbours[ki];
422            if (n < 0) 
423              {
424                // Neighbour is a boundary condition
425                m = -n - 1; // Convert negative flag to boundary index
426               
427                qr[0] = stage_boundary_values[m];
428                qr[1] = xmom_boundary_values[m];
429                qr[2] = ymom_boundary_values[m];
430                qr[3] = height_boundary_values[m];
431                qr[4] = bed_boundary_values[m];
432                qr[5] = xvel_boundary_values[m];
433                qr[6] = yvel_boundary_values[m];
434               
435              } 
436            else 
437              {
438                // Neighbour is a real triangle
439                m = neighbour_edges[ki];
440                nm = n*3 + m; // Linear index (triangle n, edge m)
441               
442                qr[0] = stage_edge_values[nm];
443                qr[1] = xmom_edge_values[nm];
444                qr[2] = ymom_edge_values[nm];
445                qr[3] = height_edge_values[nm];
446                qr[4] = bed_edge_values[nm];
447                qr[5] = xvel_edge_values[nm];
448                qr[6] = yvel_edge_values[nm];
449               
450              }
451           
452            // Now we have values for this edge - both from left and right side.
453
454            // Outward pointing normal vector (domain.normals[k, 2*i:2*i+2])
455            ki2 = 2*ki; //k*6 + i*2
456
457            // Edge flux computation (triangle k, edge i)
458            _flux_function(ql,
459                           qr,
460                           normals[ki2], 
461                           normals[ki2+1],
462                           g,
463                           edgeflux, 
464                           &local_max_speed);
465           
466           
467            // Multiply edgeflux by edgelength
468            length = edgelengths[ki];
469            edgeflux[0] *= length;           
470            edgeflux[1] *= length;           
471            edgeflux[2] *= length;                       
472     
473     
474            // Update triangle k with flux from edge i
475            stage_explicit_update[k] -= edgeflux[0];
476            xmom_explicit_update[k]  -= edgeflux[1];
477            ymom_explicit_update[k]  -= edgeflux[2];
478     
479
480            // Update flux_timestep based on edge i and possibly neighbour n
481            if (tri_full_flag[k] == 1) 
482              {
483                if (local_max_speed > 1.0e-15) 
484                  {
485                    // Calculate safe timestep based on local_max_speed and size of triangle k
486                    // A reduction of timestep based on domain.CFL is applied in update_timestep
487                    flux_timestep = min(flux_timestep, radii[k]/local_max_speed);
488                   
489                  }
490              }
491           
492          } // End edge i
493       
494       
495        // Normalise triangle k by area and store for when all conserved
496        // quantities get updated
497        inv_area = 1.0/areas[k];
498        stage_explicit_update[k] *= inv_area;
499        xmom_explicit_update[k]  *= inv_area;
500        ymom_explicit_update[k]  *= inv_area;
501       
502       
503        // Keep track of maximal speeds
504        max_speed[k] = max(max_speed[k],local_max_speed);
505       
506      } // End triangle k
507   
508   
509    //======================================================================
510    // Cleanup
511    //======================================================================
512
513    Py_DECREF(num_neighbours            );
514    Py_DECREF(num_neighbour_edges       );
515    Py_DECREF(num_normals               );
516    Py_DECREF(num_edgelengths           );     
517    Py_DECREF(num_radii                 );   
518    Py_DECREF(num_areas                 );
519    Py_DECREF(num_tri_full_flag         );
520    Py_DECREF(num_max_speed             );
521    Py_DECREF(num_stage_edge_values     );
522    Py_DECREF(num_xmom_edge_values      );
523    Py_DECREF(num_ymom_edge_values      );
524    Py_DECREF(num_height_edge_values    );
525    Py_DECREF(num_bed_edge_values       );
526    Py_DECREF(num_xvel_edge_values      );
527    Py_DECREF(num_yvel_edge_values      );
528    Py_DECREF(num_stage_boundary_values );
529    Py_DECREF(num_xmom_boundary_values  );
530    Py_DECREF(num_ymom_boundary_values  );
531    Py_DECREF(num_height_boundary_values);
532    Py_DECREF(num_bed_boundary_values   );
533    Py_DECREF(num_xvel_boundary_values  );
534    Py_DECREF(num_yvel_boundary_values  );
535    Py_DECREF(num_stage_explicit_update );
536    Py_DECREF(num_xmom_explicit_update  );
537    Py_DECREF(num_ymom_explicit_update  );
538
539    //======================================================================
540    // Return updated flux flux_timestep
541    //======================================================================
542    return Py_BuildValue("d", flux_timestep);
543}
544
545//========================================================================
546// Flux Function
547//========================================================================
548
549PyObject *flux_function(PyObject *self, PyObject *args) {
550  //
551  // Gateway to innermost flux function.
552  // This is only used by the unit tests as the c implementation is
553  // normally called by compute_fluxes in this module.
554
555
556  PyArrayObject *normal, *ql, *qr,  *edgeflux;
557  double g, local_max_speed;
558
559  if (!PyArg_ParseTuple(args, "OOOOd",
560            &normal, &ql, &qr, &edgeflux, &g)) {
561    PyErr_SetString(PyExc_RuntimeError, 
562                    "swb_domain_ext.c: flux_function could not parse input arguments");
563    return NULL;
564  }
565
566 
567  _flux_function((double*) ql -> data, 
568                 (double*) qr -> data, 
569                 ((double*) normal -> data)[0],
570                 ((double*) normal -> data)[1],         
571                 g,
572                 (double*) edgeflux -> data, 
573                 &local_max_speed);
574 
575  return Py_BuildValue("d", local_max_speed); 
576}
577
578
579//========================================================================
580// Gravity
581//========================================================================
582
583PyObject *gravity(PyObject *self, PyObject *args) {
584  //
585  //  gravity(g, h, v, x, xmom, ymom)
586  //
587 
588 
589  PyArrayObject *w, *z, *x, *xmom, *ymom;
590  int k, N, k3, k6;
591  double g, avg_h, wx, wy;
592  double x0, y0, x1, y1, x2, y2, w0, w1, w2, h0, h1, h2;
593  //double epsilon;
594 
595  if (!PyArg_ParseTuple(args, "dOOOOO",
596                        &g, &w, &z, &x,
597                        &xmom, &ymom)) {
598    //&epsilon)) {
599    PyErr_SetString(PyExc_RuntimeError, "swb_domain_ext.c: gravity could not parse input arguments");
600    return NULL;
601  }
602 
603  // check that numpy array objects arrays are C contiguous memory
604  CHECK_C_CONTIG(w);
605  CHECK_C_CONTIG(z);
606  CHECK_C_CONTIG(x);
607  CHECK_C_CONTIG(xmom);
608  CHECK_C_CONTIG(ymom);
609 
610  N = z -> dimensions[0];
611  for (k=0; k<N; k++) {
612    k3 = 3*k;  // base index
613   
614    // Get stage centroid values
615    w0 = ((double*) w -> data)[k3 + 0];
616    w1 = ((double*) w -> data)[k3 + 1];
617    w2 = ((double*) w -> data)[k3 + 2];
618
619    // Get water depth
620    h0 = ((double*) w -> data)[k3 + 0] - ((double*) z -> data)[k3 + 0];
621    h1 = ((double*) w -> data)[k3 + 1] - ((double*) z -> data)[k3 + 1];
622    h2 = ((double*) w -> data)[k3 + 2] - ((double*) z -> data)[k3 + 2];
623   
624    // Optimise for flat bed
625    // Note (Ole): This didn't produce measurable speed up.
626    // Revisit later
627    //if (fabs(z0-z1)<epsilon && fabs(z1-z2)<epsilon) {
628    //  continue;
629    //}
630   
631    // Get average depth from centroid values
632    avg_h = 1.0/3.0*( h0 + h1 +h2 );
633   
634    // Compute bed slope
635    k6 = 6*k;  // base index
636   
637    x0 = ((double*) x -> data)[k6 + 0];
638    y0 = ((double*) x -> data)[k6 + 1];
639    x1 = ((double*) x -> data)[k6 + 2];
640    y1 = ((double*) x -> data)[k6 + 3];
641    x2 = ((double*) x -> data)[k6 + 4];
642    y2 = ((double*) x -> data)[k6 + 5];
643   
644   
645    _gradient(x0, y0, x1, y1, x2, y2, w0, w1, w2, &wx, &wy);
646   
647    // Update momentum
648    ((double*) xmom -> data)[k] += -g*wx*avg_h;
649    ((double*) ymom -> data)[k] += -g*wy*avg_h;
650  }
651 
652  return Py_BuildValue("");
653}
654
655
656
657//========================================================================
658// Method table for python module
659//========================================================================
660
661static struct PyMethodDef MethodTable[] = {
662  /* The cast of the function is necessary since PyCFunction values
663   * only take two PyObject* parameters, and rotate() takes
664   * three.
665   */
666  {"compute_fluxes_c", compute_fluxes,     METH_VARARGS, "Print out"},
667  {"gravity_c",        gravity,            METH_VARARGS, "Print out"},
668  {"flux_function_c",  flux_function,      METH_VARARGS, "Print out"},
669  {NULL, NULL, 0, NULL}
670};
671
672// Module initialisation
673void initswb_domain_ext(void){
674  Py_InitModule("swb_domain_ext", MethodTable);
675
676  import_array(); // Necessary for handling of NumPY structures
677}
Note: See TracBrowser for help on using the repository browser.