1 | // Python - C extension module for shallow_water.py |
---|
2 | // |
---|
3 | // To compile (Python2.3): |
---|
4 | // gcc -c swb_domain_ext.c -I/usr/include/python2.3 -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 | |
---|
27 | const double pi = 3.14159265358979; |
---|
28 | |
---|
29 | // Computational function for rotation |
---|
30 | int _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 |
---|
54 | int _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 | memset(edgeflux, 0, 3*sizeof(double)); |
---|
153 | |
---|
154 | if (denom < epsilon) |
---|
155 | { |
---|
156 | *local_max_speed = 0.0; |
---|
157 | //printf("here %g\n",h_inside); |
---|
158 | // Add in edge pressure term due to discontinuous bed |
---|
159 | if ( h_inside > 0.0 ) edgeflux[1] = 0.5*g*h_inside*h_inside ; |
---|
160 | } |
---|
161 | else |
---|
162 | { |
---|
163 | inverse_denominator = 1.0/denom; |
---|
164 | for (i = 0; i < 3; i++) |
---|
165 | { |
---|
166 | edgeflux[i] = s_max*flux_inside[i] - s_min*flux_outside[i]; |
---|
167 | edgeflux[i] += s_max*s_min*(cons_outside[i] - cons_inside[i]); |
---|
168 | edgeflux[i] *= inverse_denominator; |
---|
169 | } |
---|
170 | |
---|
171 | // Balance the pressure term |
---|
172 | edgeflux[1] += 0.5*g*h_inside*h_inside - 0.5*g*h_inside_star*h_inside_star; |
---|
173 | |
---|
174 | } |
---|
175 | |
---|
176 | // Maximal wavespeed |
---|
177 | *local_max_speed = max(fabs(s_max), fabs(s_min)); |
---|
178 | //printf("local speed % g h_inside %g \n",*local_max_speed, h_inside); |
---|
179 | // Rotate back |
---|
180 | _rotate(edgeflux, n1, -n2); |
---|
181 | |
---|
182 | return 0; |
---|
183 | } |
---|
184 | |
---|
185 | |
---|
186 | |
---|
187 | //========================================================================= |
---|
188 | // Python Glue |
---|
189 | //========================================================================= |
---|
190 | |
---|
191 | |
---|
192 | //======================================================================== |
---|
193 | // Compute fluxes |
---|
194 | //======================================================================== |
---|
195 | |
---|
196 | PyObject *compute_fluxes(PyObject *self, PyObject *args) { |
---|
197 | /*Compute all fluxes and the timestep suitable for all volumes |
---|
198 | in domain. |
---|
199 | |
---|
200 | Compute total flux for each conserved quantity using "flux_function_central" |
---|
201 | |
---|
202 | Fluxes across each edge are scaled by edgelengths and summed up |
---|
203 | Resulting flux is then scaled by area and stored in |
---|
204 | explicit_update for each of the three conserved quantities |
---|
205 | stage, xmomentum and ymomentum |
---|
206 | |
---|
207 | The maximal allowable speed computed by the flux_function for each volume |
---|
208 | is converted to a timestep that must not be exceeded. The minimum of |
---|
209 | those is computed as the next overall timestep. |
---|
210 | |
---|
211 | Python call: |
---|
212 | timestep = compute_fluxes(timestep, domain, stage, xmom, ymom, height, bed, xvel, yvel) |
---|
213 | |
---|
214 | |
---|
215 | Post conditions: |
---|
216 | domain.explicit_update is reset to computed flux values |
---|
217 | returns timestep which is the largest step satisfying all volumes. |
---|
218 | |
---|
219 | |
---|
220 | */ |
---|
221 | |
---|
222 | PyObject |
---|
223 | *domain, |
---|
224 | *stage, |
---|
225 | *xmom, |
---|
226 | *ymom, |
---|
227 | *height, |
---|
228 | *bed, |
---|
229 | *xvel, |
---|
230 | *yvel; |
---|
231 | |
---|
232 | PyArrayObject |
---|
233 | *num_neighbours , |
---|
234 | *num_neighbour_edges , |
---|
235 | *num_normals , |
---|
236 | *num_edgelengths , |
---|
237 | *num_radii , |
---|
238 | *num_areas , |
---|
239 | *num_tri_full_flag , |
---|
240 | *num_max_speed , |
---|
241 | *num_stage_edge_values , |
---|
242 | *num_xmom_edge_values , |
---|
243 | *num_ymom_edge_values , |
---|
244 | *num_height_edge_values , |
---|
245 | *num_bed_edge_values , |
---|
246 | *num_xvel_edge_values , |
---|
247 | *num_yvel_edge_values , |
---|
248 | *num_stage_boundary_values , |
---|
249 | *num_xmom_boundary_values , |
---|
250 | *num_ymom_boundary_values , |
---|
251 | *num_height_boundary_values, |
---|
252 | *num_bed_boundary_values , |
---|
253 | *num_xvel_boundary_values , |
---|
254 | *num_yvel_boundary_values , |
---|
255 | *num_stage_explicit_update , |
---|
256 | *num_xmom_explicit_update , |
---|
257 | *num_ymom_explicit_update ; |
---|
258 | |
---|
259 | long |
---|
260 | *neighbours , |
---|
261 | *neighbour_edges , |
---|
262 | *tri_full_flag ; |
---|
263 | |
---|
264 | double |
---|
265 | *normals , |
---|
266 | *edgelengths , |
---|
267 | *radii , |
---|
268 | *areas , |
---|
269 | *max_speed , |
---|
270 | *stage_edge_values , |
---|
271 | *xmom_edge_values , |
---|
272 | *ymom_edge_values , |
---|
273 | *height_edge_values , |
---|
274 | *bed_edge_values , |
---|
275 | *xvel_edge_values , |
---|
276 | *yvel_edge_values , |
---|
277 | *stage_boundary_values , |
---|
278 | *xmom_boundary_values , |
---|
279 | *ymom_boundary_values , |
---|
280 | *height_boundary_values, |
---|
281 | *bed_boundary_values , |
---|
282 | *xvel_boundary_values , |
---|
283 | *yvel_boundary_values , |
---|
284 | *stage_explicit_update , |
---|
285 | *xmom_explicit_update , |
---|
286 | *ymom_explicit_update ; |
---|
287 | |
---|
288 | |
---|
289 | |
---|
290 | double flux_timestep, g; |
---|
291 | double local_max_speed, length, inv_area; |
---|
292 | |
---|
293 | int k, i, m, n; |
---|
294 | int ki, nm=0, ki2; // Index shorthands |
---|
295 | |
---|
296 | double ql[7], qr[7]; // Work arrays for storing local evolving quantities |
---|
297 | double edgeflux[3]; // Work array for summing up fluxes |
---|
298 | |
---|
299 | |
---|
300 | //====================================================================== |
---|
301 | // Convert Python arguments to C |
---|
302 | //====================================================================== |
---|
303 | if (!PyArg_ParseTuple(args, "dOOOOOOOO", |
---|
304 | &flux_timestep, |
---|
305 | &domain, |
---|
306 | &stage, |
---|
307 | &xmom, |
---|
308 | &ymom, |
---|
309 | &height, |
---|
310 | &bed, |
---|
311 | &xvel, |
---|
312 | &yvel)) { |
---|
313 | PyErr_SetString(PyExc_RuntimeError, "Input arguments failed"); |
---|
314 | return NULL; |
---|
315 | } |
---|
316 | |
---|
317 | //====================================================================== |
---|
318 | // Extract data from python objects |
---|
319 | //====================================================================== |
---|
320 | g = get_python_double(domain,"g"); |
---|
321 | |
---|
322 | num_neighbours = get_consecutive_array(domain, "neighbours"); |
---|
323 | num_neighbour_edges = get_consecutive_array(domain, "neighbour_edges"); |
---|
324 | num_normals = get_consecutive_array(domain, "normals"); |
---|
325 | num_edgelengths = get_consecutive_array(domain, "edgelengths"); |
---|
326 | num_radii = get_consecutive_array(domain, "radii"); |
---|
327 | num_areas = get_consecutive_array(domain, "areas"); |
---|
328 | num_tri_full_flag = get_consecutive_array(domain, "tri_full_flag"); |
---|
329 | num_max_speed = get_consecutive_array(domain, "max_speed"); |
---|
330 | |
---|
331 | num_stage_edge_values = get_consecutive_array(stage, "edge_values"); |
---|
332 | num_xmom_edge_values = get_consecutive_array(xmom, "edge_values"); |
---|
333 | num_ymom_edge_values = get_consecutive_array(ymom, "edge_values"); |
---|
334 | num_height_edge_values = get_consecutive_array(height, "edge_values"); |
---|
335 | num_bed_edge_values = get_consecutive_array(bed, "edge_values"); |
---|
336 | num_xvel_edge_values = get_consecutive_array(xvel, "edge_values"); |
---|
337 | num_yvel_edge_values = get_consecutive_array(yvel, "edge_values"); |
---|
338 | |
---|
339 | num_stage_boundary_values = get_consecutive_array(stage, "boundary_values"); |
---|
340 | num_xmom_boundary_values = get_consecutive_array(xmom, "boundary_values"); |
---|
341 | num_ymom_boundary_values = get_consecutive_array(ymom, "boundary_values"); |
---|
342 | num_height_boundary_values = get_consecutive_array(height, "boundary_values"); |
---|
343 | num_bed_boundary_values = get_consecutive_array(bed, "boundary_values"); |
---|
344 | num_xvel_boundary_values = get_consecutive_array(xvel, "boundary_values"); |
---|
345 | num_yvel_boundary_values = get_consecutive_array(yvel, "boundary_values"); |
---|
346 | |
---|
347 | num_stage_explicit_update = get_consecutive_array(stage, "explicit_update"); |
---|
348 | num_xmom_explicit_update = get_consecutive_array(xmom, "explicit_update"); |
---|
349 | num_ymom_explicit_update = get_consecutive_array(ymom, "explicit_update"); |
---|
350 | |
---|
351 | //--------------------------------------------------------------------------- |
---|
352 | |
---|
353 | neighbours = (long *) num_neighbours-> data; |
---|
354 | neighbour_edges = (long *) num_neighbour_edges-> data; |
---|
355 | normals = (double *) num_normals -> data; |
---|
356 | edgelengths = (double *) num_edgelengths -> data; |
---|
357 | radii = (double *) num_radii -> data; |
---|
358 | areas = (double *) num_areas -> data; |
---|
359 | tri_full_flag = (long *) num_tri_full_flag -> data; |
---|
360 | max_speed = (double *) num_max_speed -> data; |
---|
361 | |
---|
362 | stage_edge_values = (double *) num_stage_edge_values -> data; |
---|
363 | xmom_edge_values = (double *) num_xmom_edge_values -> data; |
---|
364 | ymom_edge_values = (double *) num_ymom_edge_values -> data; |
---|
365 | height_edge_values = (double *) num_height_edge_values -> data; |
---|
366 | bed_edge_values = (double *) num_bed_edge_values -> data; |
---|
367 | xvel_edge_values = (double *) num_xvel_edge_values -> data; |
---|
368 | yvel_edge_values = (double *) num_yvel_edge_values -> data; |
---|
369 | |
---|
370 | stage_boundary_values = (double *) num_stage_boundary_values -> data; |
---|
371 | xmom_boundary_values = (double *) num_xmom_boundary_values -> data; |
---|
372 | ymom_boundary_values = (double *) num_ymom_boundary_values -> data; |
---|
373 | height_boundary_values = (double *) num_height_boundary_values -> data; |
---|
374 | bed_boundary_values = (double *) num_bed_boundary_values -> data; |
---|
375 | xvel_boundary_values = (double *) num_xvel_boundary_values -> data; |
---|
376 | yvel_boundary_values = (double *) num_yvel_boundary_values -> data; |
---|
377 | |
---|
378 | stage_explicit_update = (double *) num_stage_explicit_update -> data; |
---|
379 | xmom_explicit_update = (double *) num_xmom_explicit_update -> data; |
---|
380 | ymom_explicit_update = (double *) num_ymom_explicit_update -> data; |
---|
381 | |
---|
382 | |
---|
383 | int number_of_elements = num_stage_edge_values -> dimensions[0]; |
---|
384 | |
---|
385 | //====================================================================== |
---|
386 | // Flux computation routine and update the explicit update arrays |
---|
387 | //====================================================================== |
---|
388 | |
---|
389 | // Set explicit_update to zero for all conserved_quantities. |
---|
390 | // This assumes compute_fluxes called before forcing terms |
---|
391 | |
---|
392 | memset((char*) stage_explicit_update, 0, number_of_elements*sizeof(double)); |
---|
393 | memset((char*) xmom_explicit_update, 0, number_of_elements*sizeof(double)); |
---|
394 | memset((char*) ymom_explicit_update, 0, number_of_elements*sizeof(double)); |
---|
395 | |
---|
396 | // For all triangles |
---|
397 | for (k = 0; k < number_of_elements; k++) |
---|
398 | { |
---|
399 | max_speed[k] = 0.0; |
---|
400 | |
---|
401 | // Loop through neighbours and compute edge flux for each epsilon |
---|
402 | for (i = 0; i < 3; i++) |
---|
403 | { |
---|
404 | ki = k*3 + i; // Linear index to edge i of triangle k |
---|
405 | |
---|
406 | // Get left hand side values from triangle k, edge i |
---|
407 | ql[0] = stage_edge_values[ki]; |
---|
408 | ql[1] = xmom_edge_values[ki]; |
---|
409 | ql[2] = ymom_edge_values[ki]; |
---|
410 | ql[3] = height_edge_values[ki]; |
---|
411 | ql[4] = bed_edge_values[ki]; |
---|
412 | ql[5] = xvel_edge_values[ki]; |
---|
413 | ql[6] = yvel_edge_values[ki]; |
---|
414 | |
---|
415 | // Get right hand side values either from neighbouring triangle |
---|
416 | // or from boundary array (Quantities at neighbour on nearest face). |
---|
417 | n = neighbours[ki]; |
---|
418 | if (n < 0) |
---|
419 | { |
---|
420 | // Neighbour is a boundary condition |
---|
421 | m = -n - 1; // Convert negative flag to boundary index |
---|
422 | |
---|
423 | qr[0] = stage_boundary_values[m]; |
---|
424 | qr[1] = xmom_boundary_values[m]; |
---|
425 | qr[2] = ymom_boundary_values[m]; |
---|
426 | qr[3] = height_boundary_values[m]; |
---|
427 | qr[4] = bed_boundary_values[m]; |
---|
428 | qr[5] = xvel_boundary_values[m]; |
---|
429 | qr[6] = yvel_boundary_values[m]; |
---|
430 | |
---|
431 | } |
---|
432 | else |
---|
433 | { |
---|
434 | // Neighbour is a real triangle |
---|
435 | m = neighbour_edges[ki]; |
---|
436 | nm = n*3 + m; // Linear index (triangle n, edge m) |
---|
437 | |
---|
438 | qr[0] = stage_edge_values[nm]; |
---|
439 | qr[1] = xmom_edge_values[nm]; |
---|
440 | qr[2] = ymom_edge_values[nm]; |
---|
441 | qr[3] = height_edge_values[nm]; |
---|
442 | qr[4] = bed_edge_values[nm]; |
---|
443 | qr[5] = xvel_edge_values[nm]; |
---|
444 | qr[6] = yvel_edge_values[nm]; |
---|
445 | |
---|
446 | } |
---|
447 | |
---|
448 | // Now we have values for this edge - both from left and right side. |
---|
449 | |
---|
450 | // Outward pointing normal vector (domain.normals[k, 2*i:2*i+2]) |
---|
451 | ki2 = 2*ki; //k*6 + i*2 |
---|
452 | |
---|
453 | // Edge flux computation (triangle k, edge i) |
---|
454 | _flux_function(ql, |
---|
455 | qr, |
---|
456 | normals[ki2], |
---|
457 | normals[ki2+1], |
---|
458 | g, |
---|
459 | edgeflux, |
---|
460 | &local_max_speed); |
---|
461 | |
---|
462 | |
---|
463 | // Multiply edgeflux by edgelength |
---|
464 | length = edgelengths[ki]; |
---|
465 | edgeflux[0] *= length; |
---|
466 | edgeflux[1] *= length; |
---|
467 | edgeflux[2] *= length; |
---|
468 | |
---|
469 | |
---|
470 | // Update triangle k with flux from edge i |
---|
471 | stage_explicit_update[k] -= edgeflux[0]; |
---|
472 | xmom_explicit_update[k] -= edgeflux[1]; |
---|
473 | ymom_explicit_update[k] -= edgeflux[2]; |
---|
474 | |
---|
475 | |
---|
476 | // Update flux_timestep based on edge i and possibly neighbour n |
---|
477 | if (tri_full_flag[k] == 1) |
---|
478 | { |
---|
479 | if (local_max_speed > 1.0e-15) |
---|
480 | { |
---|
481 | // Calculate safe timestep based on local_max_speed and size of triangle k |
---|
482 | // A reduction of timestep based on domain.CFL is applied in update_timestep |
---|
483 | flux_timestep = min(flux_timestep, radii[k]/local_max_speed); |
---|
484 | |
---|
485 | } |
---|
486 | } |
---|
487 | |
---|
488 | } // End edge i |
---|
489 | |
---|
490 | |
---|
491 | // Normalise triangle k by area and store for when all conserved |
---|
492 | // quantities get updated |
---|
493 | inv_area = 1.0/areas[k]; |
---|
494 | stage_explicit_update[k] *= inv_area; |
---|
495 | xmom_explicit_update[k] *= inv_area; |
---|
496 | ymom_explicit_update[k] *= inv_area; |
---|
497 | |
---|
498 | |
---|
499 | // Keep track of maximal speeds |
---|
500 | max_speed[k] = max(max_speed[k],local_max_speed); |
---|
501 | |
---|
502 | } // End triangle k |
---|
503 | |
---|
504 | |
---|
505 | //====================================================================== |
---|
506 | // Cleanup |
---|
507 | //====================================================================== |
---|
508 | |
---|
509 | Py_DECREF(num_neighbours ); |
---|
510 | Py_DECREF(num_neighbour_edges ); |
---|
511 | Py_DECREF(num_normals ); |
---|
512 | Py_DECREF(num_edgelengths ); |
---|
513 | Py_DECREF(num_radii ); |
---|
514 | Py_DECREF(num_areas ); |
---|
515 | Py_DECREF(num_tri_full_flag ); |
---|
516 | Py_DECREF(num_max_speed ); |
---|
517 | Py_DECREF(num_stage_edge_values ); |
---|
518 | Py_DECREF(num_xmom_edge_values ); |
---|
519 | Py_DECREF(num_ymom_edge_values ); |
---|
520 | Py_DECREF(num_height_edge_values ); |
---|
521 | Py_DECREF(num_bed_edge_values ); |
---|
522 | Py_DECREF(num_xvel_edge_values ); |
---|
523 | Py_DECREF(num_yvel_edge_values ); |
---|
524 | Py_DECREF(num_stage_boundary_values ); |
---|
525 | Py_DECREF(num_xmom_boundary_values ); |
---|
526 | Py_DECREF(num_ymom_boundary_values ); |
---|
527 | Py_DECREF(num_height_boundary_values); |
---|
528 | Py_DECREF(num_bed_boundary_values ); |
---|
529 | Py_DECREF(num_xvel_boundary_values ); |
---|
530 | Py_DECREF(num_yvel_boundary_values ); |
---|
531 | Py_DECREF(num_stage_explicit_update ); |
---|
532 | Py_DECREF(num_xmom_explicit_update ); |
---|
533 | Py_DECREF(num_ymom_explicit_update ); |
---|
534 | |
---|
535 | //====================================================================== |
---|
536 | // Return updated flux flux_timestep |
---|
537 | //====================================================================== |
---|
538 | return Py_BuildValue("d", flux_timestep); |
---|
539 | } |
---|
540 | |
---|
541 | //======================================================================== |
---|
542 | // Flux Function |
---|
543 | //======================================================================== |
---|
544 | |
---|
545 | PyObject *flux_function(PyObject *self, PyObject *args) { |
---|
546 | // |
---|
547 | // Gateway to innermost flux function. |
---|
548 | // This is only used by the unit tests as the c implementation is |
---|
549 | // normally called by compute_fluxes in this module. |
---|
550 | |
---|
551 | |
---|
552 | PyArrayObject *normal, *ql, *qr, *edgeflux; |
---|
553 | double g, local_max_speed; |
---|
554 | |
---|
555 | if (!PyArg_ParseTuple(args, "OOOOd", |
---|
556 | &normal, &ql, &qr, &edgeflux, &g)) { |
---|
557 | PyErr_SetString(PyExc_RuntimeError, |
---|
558 | "swb_domain_ext.c: flux_function could not parse input arguments"); |
---|
559 | return NULL; |
---|
560 | } |
---|
561 | |
---|
562 | |
---|
563 | _flux_function((double*) ql -> data, |
---|
564 | (double*) qr -> data, |
---|
565 | ((double*) normal -> data)[0], |
---|
566 | ((double*) normal -> data)[1], |
---|
567 | g, |
---|
568 | (double*) edgeflux -> data, |
---|
569 | &local_max_speed); |
---|
570 | |
---|
571 | return Py_BuildValue("d", local_max_speed); |
---|
572 | } |
---|
573 | |
---|
574 | |
---|
575 | //======================================================================== |
---|
576 | // Gravity |
---|
577 | //======================================================================== |
---|
578 | |
---|
579 | PyObject *gravity(PyObject *self, PyObject *args) { |
---|
580 | // |
---|
581 | // gravity(g, h, v, x, xmom, ymom) |
---|
582 | // |
---|
583 | |
---|
584 | |
---|
585 | PyArrayObject *h, *v, *x, *xmom, *ymom; |
---|
586 | int k, N, k3, k6; |
---|
587 | double g, avg_h, zx, zy; |
---|
588 | double x0, y0, x1, y1, x2, y2, z0, z1, z2; |
---|
589 | //double epsilon; |
---|
590 | |
---|
591 | if (!PyArg_ParseTuple(args, "dOOOOO", |
---|
592 | &g, &h, &v, &x, |
---|
593 | &xmom, &ymom)) { |
---|
594 | //&epsilon)) { |
---|
595 | PyErr_SetString(PyExc_RuntimeError, "shallow_water_ext.c: gravity could not parse input arguments"); |
---|
596 | return NULL; |
---|
597 | } |
---|
598 | |
---|
599 | // check that numpy array objects arrays are C contiguous memory |
---|
600 | CHECK_C_CONTIG(h); |
---|
601 | CHECK_C_CONTIG(v); |
---|
602 | CHECK_C_CONTIG(x); |
---|
603 | CHECK_C_CONTIG(xmom); |
---|
604 | CHECK_C_CONTIG(ymom); |
---|
605 | |
---|
606 | N = h -> dimensions[0]; |
---|
607 | for (k=0; k<N; k++) { |
---|
608 | k3 = 3*k; // base index |
---|
609 | |
---|
610 | // Get bathymetry |
---|
611 | z0 = ((double*) v -> data)[k3 + 0]; |
---|
612 | z1 = ((double*) v -> data)[k3 + 1]; |
---|
613 | z2 = ((double*) v -> data)[k3 + 2]; |
---|
614 | |
---|
615 | // Optimise for flat bed |
---|
616 | // Note (Ole): This didn't produce measurable speed up. |
---|
617 | // Revisit later |
---|
618 | //if (fabs(z0-z1)<epsilon && fabs(z1-z2)<epsilon) { |
---|
619 | // continue; |
---|
620 | //} |
---|
621 | |
---|
622 | // Get average depth from centroid values |
---|
623 | avg_h = ((double *) h -> data)[k]; |
---|
624 | |
---|
625 | // Compute bed slope |
---|
626 | k6 = 6*k; // base index |
---|
627 | |
---|
628 | x0 = ((double*) x -> data)[k6 + 0]; |
---|
629 | y0 = ((double*) x -> data)[k6 + 1]; |
---|
630 | x1 = ((double*) x -> data)[k6 + 2]; |
---|
631 | y1 = ((double*) x -> data)[k6 + 3]; |
---|
632 | x2 = ((double*) x -> data)[k6 + 4]; |
---|
633 | y2 = ((double*) x -> data)[k6 + 5]; |
---|
634 | |
---|
635 | |
---|
636 | _gradient(x0, y0, x1, y1, x2, y2, z0, z1, z2, &zx, &zy); |
---|
637 | |
---|
638 | // Update momentum |
---|
639 | ((double*) xmom -> data)[k] += -g*zx*avg_h; |
---|
640 | ((double*) ymom -> data)[k] += -g*zy*avg_h; |
---|
641 | } |
---|
642 | |
---|
643 | return Py_BuildValue(""); |
---|
644 | } |
---|
645 | |
---|
646 | |
---|
647 | |
---|
648 | //======================================================================== |
---|
649 | // Method table for python module |
---|
650 | //======================================================================== |
---|
651 | |
---|
652 | static struct PyMethodDef MethodTable[] = { |
---|
653 | /* The cast of the function is necessary since PyCFunction values |
---|
654 | * only take two PyObject* parameters, and rotate() takes |
---|
655 | * three. |
---|
656 | */ |
---|
657 | {"compute_fluxes_c", compute_fluxes, METH_VARARGS, "Print out"}, |
---|
658 | {"gravity_c", gravity, METH_VARARGS, "Print out"}, |
---|
659 | {"flux_function_c", flux_function, METH_VARARGS, "Print out"}, |
---|
660 | {NULL, NULL, 0, NULL} |
---|
661 | }; |
---|
662 | |
---|
663 | // Module initialisation |
---|
664 | void initswb_domain_ext(void){ |
---|
665 | Py_InitModule("swb_domain_ext", MethodTable); |
---|
666 | |
---|
667 | import_array(); // Necessary for handling of NumPY structures |
---|
668 | } |
---|