1 | |
---|
2 | #include "Python.h" |
---|
3 | |
---|
4 | #include <stdio.h> /* gets */ |
---|
5 | #include <stdlib.h> /* atoi, malloc */ |
---|
6 | #include <string.h> /* strcpy */ |
---|
7 | #include "numpy/arrayobject.h" |
---|
8 | #include "math.h" |
---|
9 | |
---|
10 | #include "util_ext.h" /* in utilities */ |
---|
11 | #include "sparse_dok.h" /*in utilities */ |
---|
12 | #include "quad_tree.h" |
---|
13 | #include <netcdf.h> |
---|
14 | #include "omp.h" |
---|
15 | |
---|
16 | // Errors defined for netcdf reading |
---|
17 | #define ERRCODE 2 |
---|
18 | #define ERR(e) {printf("Error: %s\n", nc_strerror(e)); exit(ERRCODE);} |
---|
19 | |
---|
20 | #include "patchlevel.h" |
---|
21 | |
---|
22 | // PYVERSION273 used to check python version for use of PyCapsule |
---|
23 | #if PY_MAJOR_VERSION>=2 && PY_MINOR_VERSION>=7 && PY_MICRO_VERSION>=3 |
---|
24 | #define PYVERSION273 |
---|
25 | #endif |
---|
26 | |
---|
27 | //------------------------ NET CDF READING ---------------------------- |
---|
28 | |
---|
29 | // Note Padarn 06/12/12: I am removing the use of these functions from |
---|
30 | // the workflow of the new code. I think they should be reintroduced, but |
---|
31 | // to make sure all the unit tests work properly more checking of filetypes |
---|
32 | // etc needs to be done. |
---|
33 | // Note Padarn 12/12/12: These have been moved back into the workflow, |
---|
34 | // but still there is no way of handling .csv or .txt files efficiently. |
---|
35 | |
---|
36 | |
---|
37 | // Reads a block of a netcdf file into the arrays 'point_coordiantes' and 'point_values'. The |
---|
38 | // block is specified by a start point (np_start) and and an end point (np_end) |
---|
39 | // NOTE PADARN: FIX - only reads elevation at the moment |
---|
40 | int _read_net_cdf_points_block(char * filename, char * attribute_name, int np_start,int np_end,double *point_coordinates,double *point_values){ |
---|
41 | |
---|
42 | //point_coordinates and _values are intitialised outside |
---|
43 | int np=np_end-np_start+1; |
---|
44 | int status; /* error status */ |
---|
45 | int ncid; /* netCDF ID */ |
---|
46 | int rh_id; /* variable ID */ |
---|
47 | size_t start_points[] = {np_start, 0}; /* start at first value */ |
---|
48 | size_t count_points[] = {np, 2}; |
---|
49 | size_t start[] = {np_start}; |
---|
50 | size_t count[] = {np}; |
---|
51 | |
---|
52 | if ((status = nc_open(filename, NC_NOWRITE, &ncid))) ERR(status); |
---|
53 | |
---|
54 | if ((status = nc_inq_varid(ncid, "points", &rh_id))) ERR(status); |
---|
55 | |
---|
56 | /* read coordinates from netCDF variable */ |
---|
57 | if ((status = nc_get_vara_double(ncid, rh_id, start_points, count_points, point_coordinates))) ERR(status); |
---|
58 | |
---|
59 | if ((status = nc_inq_varid(ncid, attribute_name, &rh_id))) ERR(status); |
---|
60 | |
---|
61 | /* read values from netCDF variable */ |
---|
62 | if ((status = nc_get_vara_double(ncid, rh_id, start, count, point_values))) ERR(status); |
---|
63 | |
---|
64 | if ((status = nc_close(ncid))) ERR(status); |
---|
65 | |
---|
66 | return 0; |
---|
67 | |
---|
68 | } |
---|
69 | |
---|
70 | // Takes a netcdf file and gets the number of points stored in it (also the number of values for |
---|
71 | // attributes specified) |
---|
72 | // NOTE PADARN: FIX - uses 'points' to get points, this may be a problem. |
---|
73 | int _read_net_cdf_entries(char * filename,int * x){ |
---|
74 | |
---|
75 | int status; /* error status */ |
---|
76 | int ncid; |
---|
77 | int p_id; |
---|
78 | int ndims; |
---|
79 | size_t length = {0}; |
---|
80 | |
---|
81 | if ((status = nc_open(filename, NC_NOWRITE, &ncid))) ERR(status); |
---|
82 | |
---|
83 | if ((status = nc_inq_varid(ncid, "points", &p_id))) ERR(status); |
---|
84 | |
---|
85 | if((status = nc_inq_varndims(ncid, p_id, &ndims))) ERR(status); |
---|
86 | |
---|
87 | int * ndimsize = malloc(sizeof(int)*ndims); |
---|
88 | |
---|
89 | if((status = nc_inq_vardimid(ncid, p_id, ndimsize))) ERR(status); |
---|
90 | |
---|
91 | if((status = nc_inq_dimlen(ncid, ndimsize[0], &length))) ERR(status); |
---|
92 | |
---|
93 | *x = (int)length; |
---|
94 | |
---|
95 | if ((status = nc_close(ncid))) ERR(status); |
---|
96 | |
---|
97 | return 0; |
---|
98 | |
---|
99 | } |
---|
100 | |
---|
101 | //-------------------------------------------------------------------------- |
---|
102 | |
---|
103 | //-------------------------- QUANTITY FITTING ------------------------------ |
---|
104 | |
---|
105 | |
---|
106 | // Builds the matrix D used to smooth the interpolation |
---|
107 | // of a variables from scattered data points to a mesh. See fit.py for more details.s |
---|
108 | int _build_smoothing_matrix(int n, |
---|
109 | long* triangles, |
---|
110 | double* areas, |
---|
111 | double* vertex_coordinates, |
---|
112 | int* strides, |
---|
113 | sparse_dok * smoothing_mat) |
---|
114 | { |
---|
115 | |
---|
116 | |
---|
117 | int k; |
---|
118 | int k3,k6; |
---|
119 | int err = 0; |
---|
120 | edge_key_t key; |
---|
121 | |
---|
122 | double det,area,x0,x1,x2,y0,y1,y2; |
---|
123 | double a0,b0,a1,b1,a2,b2,e01,e12,e20; |
---|
124 | int v0,v1,v2; |
---|
125 | double smoothing_val; |
---|
126 | |
---|
127 | |
---|
128 | for(k=0; k<n; k++) { |
---|
129 | // multiple k by 3 to give index for triangles which store in 3-blocks |
---|
130 | k3=k*3; |
---|
131 | k6=k*6; |
---|
132 | // store the area for the current triangle |
---|
133 | area = areas[k]; |
---|
134 | // store current triangles global vertex indicies |
---|
135 | v0 = triangles[k3]; |
---|
136 | v1 = triangles[k3+1]; |
---|
137 | v2 = triangles[k3+2]; |
---|
138 | // store the locations of the three verticies |
---|
139 | x0 = vertex_coordinates[k6]; |
---|
140 | y0 = vertex_coordinates[k6+1]; |
---|
141 | x1 = vertex_coordinates[k6+2]; |
---|
142 | y1 = vertex_coordinates[k6+3]; |
---|
143 | x2 = vertex_coordinates[k6+4]; |
---|
144 | y2 = vertex_coordinates[k6+5]; |
---|
145 | |
---|
146 | // calculate gradients (move to external function?) |
---|
147 | |
---|
148 | det = (y2-y0)*(x1-x0) - (y1-y0)*(x2-x0); |
---|
149 | a0 = (y2-y0)*(0-1) - (y1-y0)*(0-1); |
---|
150 | a0 /= det; |
---|
151 | |
---|
152 | b0 = (x1-x0)*(0-1) - (x2-x0)*(0-1); |
---|
153 | b0 /= det; |
---|
154 | |
---|
155 | a1 = (y2-y0)*(1-0) - (y1-y0)*(0-0); |
---|
156 | a1 /= det; |
---|
157 | |
---|
158 | b1 = (x1-x0)*(0-0) - (x2-x0)*(1-0); |
---|
159 | b1 /= det; |
---|
160 | |
---|
161 | a2 = (y2-y0)*(0-0) - (y1-y0)*(1-0); |
---|
162 | a2 /= det; |
---|
163 | |
---|
164 | b2 = (x1-x0)*(1-0) - (x2-x0)*(0-0); |
---|
165 | b2 /= det; |
---|
166 | |
---|
167 | // insert diagonal contributions |
---|
168 | |
---|
169 | // v0,v0 |
---|
170 | key.i = v0; |
---|
171 | key.j = v0; |
---|
172 | smoothing_val = (a0*a0 + b0*b0)*area; |
---|
173 | add_dok_entry(smoothing_mat,key,smoothing_val); |
---|
174 | |
---|
175 | // v1,v1 |
---|
176 | key.i = v1; |
---|
177 | key.j = v1; |
---|
178 | smoothing_val = (a1*a1 + b1*b1)*area; |
---|
179 | add_dok_entry(smoothing_mat,key,smoothing_val); |
---|
180 | |
---|
181 | // v2,v2 |
---|
182 | key.i = v2; |
---|
183 | key.j = v2; |
---|
184 | smoothing_val = (a2*a2 + b2*b2)*area; |
---|
185 | add_dok_entry(smoothing_mat,key,smoothing_val); |
---|
186 | |
---|
187 | |
---|
188 | // insert off diagonal contributions |
---|
189 | e01 = (a0*a1 + b0*b1)*area; |
---|
190 | // v0,v1 (v1,v0) |
---|
191 | key.i = v0; |
---|
192 | key.j = v1; |
---|
193 | add_dok_entry(smoothing_mat,key,e01); |
---|
194 | key.i = v1; |
---|
195 | key.j = v0; |
---|
196 | add_dok_entry(smoothing_mat,key,e01); |
---|
197 | |
---|
198 | e12 = (a1*a2 + b1*b2)*area; |
---|
199 | // v1,v2 (v2,v1) |
---|
200 | key.i = v1; |
---|
201 | key.j = v2; |
---|
202 | add_dok_entry(smoothing_mat,key,e12); |
---|
203 | key.i = v2; |
---|
204 | key.j = v1; |
---|
205 | add_dok_entry(smoothing_mat,key,e12); |
---|
206 | |
---|
207 | e20 = (a2*a0 + b2*b0)*area; |
---|
208 | // v2,v0 (v0,v2) |
---|
209 | key.i = v2; |
---|
210 | key.j = v0; |
---|
211 | add_dok_entry(smoothing_mat,key,e20); |
---|
212 | key.i = v0; |
---|
213 | key.j = v2; |
---|
214 | add_dok_entry(smoothing_mat,key,e20); |
---|
215 | } |
---|
216 | |
---|
217 | return err; |
---|
218 | |
---|
219 | } |
---|
220 | |
---|
221 | // Builds a quad tree out of a list of triangles for quick |
---|
222 | // searching. |
---|
223 | quad_tree * _build_quad_tree(int n, |
---|
224 | long* triangles, |
---|
225 | double* vertex_coordinates, |
---|
226 | double* extents) |
---|
227 | { |
---|
228 | |
---|
229 | int k,k6; |
---|
230 | double x0,y0,x1,y1,x2,y2; |
---|
231 | |
---|
232 | // set up quad tree and allocate memory |
---|
233 | quad_tree * tree = new_quad_tree(extents[0],extents[1],extents[2],extents[3]); |
---|
234 | |
---|
235 | // iterate through triangles |
---|
236 | for(k=0; k<n; k++) { |
---|
237 | // multiple k by 3 to give index for triangles which store in 3-blocks |
---|
238 | k6=k*6; |
---|
239 | // store the locations of the three verticies |
---|
240 | x0 = vertex_coordinates[k6]; |
---|
241 | y0 = vertex_coordinates[k6 + 1]; |
---|
242 | x1 = vertex_coordinates[k6 + 2]; |
---|
243 | y1 = vertex_coordinates[k6 + 3]; |
---|
244 | x2 = vertex_coordinates[k6 + 4]; |
---|
245 | y2 = vertex_coordinates[k6 + 5]; |
---|
246 | triangle * T = new_triangle(k,x0,y0,x1,y1,x2,y2); |
---|
247 | quad_tree_insert_triangle(tree,T); |
---|
248 | } |
---|
249 | |
---|
250 | // return pointer to new tree struct |
---|
251 | return tree; |
---|
252 | |
---|
253 | } |
---|
254 | |
---|
255 | // Builds the AtA and Atz interpolation matrix |
---|
256 | // and residual. Uses a quad_tree for fast access to the triangles of the mesh. |
---|
257 | // This function takes a filename and an attribute name, in netcdf format .pts, |
---|
258 | // and reads the attribute value and point location from this file. |
---|
259 | int _build_matrix_AtA_Atz_fileread(int N, long * triangles, |
---|
260 | char * filename, |
---|
261 | char * attribute_name, |
---|
262 | int blocksize, |
---|
263 | sparse_dok * AtA, |
---|
264 | double * Atz,quad_tree * quadtree) |
---|
265 | { |
---|
266 | |
---|
267 | |
---|
268 | int np; |
---|
269 | _read_net_cdf_entries(filename,&np); |
---|
270 | //n=10; |
---|
271 | |
---|
272 | double * point_coordinates = malloc(2*sizeof(double)*blocksize); |
---|
273 | double * point_values = malloc(sizeof(double)*blocksize); |
---|
274 | int k; |
---|
275 | int left; |
---|
276 | |
---|
277 | int i; |
---|
278 | for(i=0;i<N;i++){ |
---|
279 | Atz[i]=0; |
---|
280 | } |
---|
281 | |
---|
282 | edge_key_t key; |
---|
283 | int w; |
---|
284 | int start = 0; |
---|
285 | left = np; |
---|
286 | |
---|
287 | |
---|
288 | while(left > 0){ |
---|
289 | if(left-blocksize<=0){ |
---|
290 | blocksize = left; |
---|
291 | } |
---|
292 | |
---|
293 | // Read data into arrays |
---|
294 | _read_net_cdf_points_block(filename,attribute_name,start, |
---|
295 | start+blocksize-1,point_coordinates,point_values); |
---|
296 | |
---|
297 | start = start + blocksize; |
---|
298 | |
---|
299 | #pragma omp parallel for private(k,i,key,w) |
---|
300 | for(k=0;k<blocksize;k++){ |
---|
301 | |
---|
302 | |
---|
303 | double x = point_coordinates[2*k]; |
---|
304 | double y = point_coordinates[2*k+1]; |
---|
305 | triangle * T = search(quadtree,x,y); |
---|
306 | |
---|
307 | if(T!=NULL){ |
---|
308 | double * sigma = calculate_sigma(T,x,y); |
---|
309 | int js[3]; |
---|
310 | for(i=0;i<3;i++){ |
---|
311 | js[i]=triangles[3*(T->index)+i]; |
---|
312 | } |
---|
313 | |
---|
314 | #pragma omp critical |
---|
315 | { |
---|
316 | for(i=0;i<3;i++){ |
---|
317 | |
---|
318 | Atz[js[i]] += sigma[i]*point_values[k]; |
---|
319 | |
---|
320 | for(w=0;w<3;w++){ |
---|
321 | |
---|
322 | key.i=js[i]; |
---|
323 | key.j=js[w]; |
---|
324 | |
---|
325 | add_dok_entry(AtA,key,sigma[i]*sigma[w]); |
---|
326 | } |
---|
327 | } |
---|
328 | } |
---|
329 | free(sigma); |
---|
330 | sigma=NULL; |
---|
331 | } |
---|
332 | |
---|
333 | } |
---|
334 | |
---|
335 | left=left-blocksize; |
---|
336 | } |
---|
337 | |
---|
338 | return 0; |
---|
339 | } |
---|
340 | |
---|
341 | // Builds the AtA and Atz interpolation matrix |
---|
342 | // and residual. Uses a quad_tree for fast access to the triangles of the mesh. |
---|
343 | // This function takes a list of point coordinates, and associated point values |
---|
344 | // (for any number of attributes). |
---|
345 | int _build_matrix_AtA_Atz_points(int N, long * triangles, |
---|
346 | double * point_coordinates, double * point_values, |
---|
347 | int zdims, int npts, |
---|
348 | sparse_dok * AtA, |
---|
349 | double ** Atz,quad_tree * quadtree) |
---|
350 | { |
---|
351 | |
---|
352 | |
---|
353 | |
---|
354 | int k; |
---|
355 | |
---|
356 | |
---|
357 | |
---|
358 | int i,w; |
---|
359 | for(w=0;w<zdims;w++){ |
---|
360 | for(i=0;i<N;i++){ |
---|
361 | Atz[w][i]=0; |
---|
362 | } |
---|
363 | } |
---|
364 | |
---|
365 | edge_key_t key; |
---|
366 | |
---|
367 | |
---|
368 | |
---|
369 | |
---|
370 | //#pragma omp parallel for private(k,i,key,w) |
---|
371 | for(k=0;k<npts;k++){ |
---|
372 | |
---|
373 | |
---|
374 | double x = point_coordinates[2*k]; |
---|
375 | double y = point_coordinates[2*k+1]; |
---|
376 | triangle * T = search(quadtree,x,y); |
---|
377 | |
---|
378 | if(T!=NULL){ |
---|
379 | double * sigma = calculate_sigma(T,x,y); |
---|
380 | int js[3]; |
---|
381 | for(i=0;i<3;i++){ |
---|
382 | js[i]=triangles[3*(T->index)+i]; |
---|
383 | } |
---|
384 | |
---|
385 | #pragma omp critical |
---|
386 | { |
---|
387 | for(i=0;i<3;i++){ |
---|
388 | |
---|
389 | for(w=0;w<zdims;w++){ |
---|
390 | Atz[w][js[i]] += sigma[i]*point_values[zdims*k+w]; |
---|
391 | } |
---|
392 | |
---|
393 | for(w=0;w<3;w++){ |
---|
394 | |
---|
395 | key.i=js[i]; |
---|
396 | key.j=js[w]; |
---|
397 | |
---|
398 | add_dok_entry(AtA,key,sigma[i]*sigma[w]); |
---|
399 | } |
---|
400 | } |
---|
401 | } |
---|
402 | free(sigma); |
---|
403 | sigma=NULL; |
---|
404 | |
---|
405 | } |
---|
406 | } |
---|
407 | |
---|
408 | return 0; |
---|
409 | } |
---|
410 | |
---|
411 | // Combines two sparse_dok matricies and two vectors of doubles. |
---|
412 | void _combine_partial_AtA_Atz(sparse_dok * dok_AtA1,sparse_dok * dok_AtA2, |
---|
413 | double* Atz1, |
---|
414 | double* Atz2, |
---|
415 | int n, int zdim){ |
---|
416 | |
---|
417 | add_sparse_dok(dok_AtA1,1,dok_AtA2,1); |
---|
418 | |
---|
419 | int i; |
---|
420 | for(i=0;i<n*zdim;i++){ |
---|
421 | Atz1[i]+=Atz2[i]; |
---|
422 | } |
---|
423 | } |
---|
424 | |
---|
425 | // --------------------------- Utilities ----------------------------------- |
---|
426 | |
---|
427 | // Converts a double array into a PyList object for return to python. |
---|
428 | static PyObject *c_double_array_to_list(double * mat,int cols){ |
---|
429 | |
---|
430 | int j; |
---|
431 | |
---|
432 | PyObject *lst; |
---|
433 | |
---|
434 | lst = PyList_New(cols); |
---|
435 | if (!lst) return NULL; |
---|
436 | for (j = 0; j < cols; j++) { |
---|
437 | PyObject *num = PyFloat_FromDouble(mat[j]); |
---|
438 | if (!num) { |
---|
439 | Py_DECREF(lst); |
---|
440 | return NULL; |
---|
441 | } |
---|
442 | PyList_SET_ITEM(lst, j, num); // reference to num stolen |
---|
443 | } |
---|
444 | |
---|
445 | return lst; |
---|
446 | } |
---|
447 | |
---|
448 | // Converts a int array into a PyList object for return to python. |
---|
449 | static PyObject *c_int_array_to_list(int * mat,int cols){ |
---|
450 | |
---|
451 | int j; |
---|
452 | |
---|
453 | PyObject *lst; |
---|
454 | |
---|
455 | lst = PyList_New(cols); |
---|
456 | if (!lst) return NULL; |
---|
457 | for (j = 0; j < cols; j++) { |
---|
458 | PyObject *num = PyInt_FromLong(mat[j]); |
---|
459 | if (!num) { |
---|
460 | Py_DECREF(lst); |
---|
461 | return NULL; |
---|
462 | } |
---|
463 | PyList_SET_ITEM(lst, j, num); // reference to num stolen |
---|
464 | } |
---|
465 | |
---|
466 | return lst; |
---|
467 | } |
---|
468 | |
---|
469 | // ---------------------------------------------------------------------------- |
---|
470 | |
---|
471 | // If using python 2.7.3 or later, build with PyCapsules |
---|
472 | |
---|
473 | // Delete capsule containing a quad tree - name of capsule must be exactly |
---|
474 | // "quad tree". |
---|
475 | |
---|
476 | #ifdef PYVERSION273 |
---|
477 | |
---|
478 | |
---|
479 | void delete_quad_tree_cap(PyObject * cap){ |
---|
480 | quad_tree * kill = (quad_tree*) PyCapsule_GetPointer(cap,"quad tree"); |
---|
481 | if(kill!=NULL){ |
---|
482 | delete_quad_tree(kill); |
---|
483 | } else{ |
---|
484 | } |
---|
485 | } |
---|
486 | |
---|
487 | // Delete capsule containing a sparse_dok - name of capsule must be exactly |
---|
488 | // "sparse dok". |
---|
489 | void delete_dok_cap(PyObject *cap){ |
---|
490 | |
---|
491 | sparse_dok * kill = (sparse_dok*) PyCapsule_GetPointer(cap,"sparse dok"); |
---|
492 | if(kill!=NULL){ |
---|
493 | delete_dok_matrix(kill); |
---|
494 | } |
---|
495 | |
---|
496 | } |
---|
497 | |
---|
498 | #else |
---|
499 | |
---|
500 | // If using python earlier version, build with PyCObject |
---|
501 | |
---|
502 | // Delete cobj containing a quad tree |
---|
503 | void delete_quad_tree_cobj(void * cobj){ |
---|
504 | quad_tree * kill = (quad_tree*) cobj; |
---|
505 | if(kill!=NULL){ |
---|
506 | delete_quad_tree(kill); |
---|
507 | } |
---|
508 | } |
---|
509 | |
---|
510 | // Delete cobj containing a sparse_dok |
---|
511 | void delete_dok_cobj(void *cobj){ |
---|
512 | |
---|
513 | sparse_dok * kill = (sparse_dok*) cobj; |
---|
514 | if(kill!=NULL){ |
---|
515 | delete_dok_matrix(kill); |
---|
516 | } |
---|
517 | |
---|
518 | } |
---|
519 | |
---|
520 | #endif |
---|
521 | |
---|
522 | //----------------------- PYTHON WRAPPER FUNCTION ----------------------------- |
---|
523 | |
---|
524 | // Parses python information about triangles |
---|
525 | // and vertex coordiantes to build a quad tree for efficient location of points in |
---|
526 | // the triangle mesh. |
---|
527 | PyObject *build_quad_tree(PyObject *self, PyObject *args) { |
---|
528 | |
---|
529 | |
---|
530 | |
---|
531 | PyArrayObject *triangles; |
---|
532 | PyArrayObject *vertex_coordinates; |
---|
533 | PyArrayObject *extents; |
---|
534 | |
---|
535 | |
---|
536 | // Convert Python arguments to C |
---|
537 | if (!PyArg_ParseTuple(args, "OOO", |
---|
538 | &triangles, |
---|
539 | &vertex_coordinates, |
---|
540 | &extents |
---|
541 | )) { |
---|
542 | PyErr_SetString(PyExc_RuntimeError, |
---|
543 | "fitsmooth.c: could not parse input"); |
---|
544 | return NULL; |
---|
545 | } |
---|
546 | |
---|
547 | CHECK_C_CONTIG(triangles); |
---|
548 | CHECK_C_CONTIG(vertex_coordinates); |
---|
549 | CHECK_C_CONTIG(extents); |
---|
550 | |
---|
551 | int n = triangles->dimensions[0]; |
---|
552 | |
---|
553 | #ifdef PYVERSION273 |
---|
554 | |
---|
555 | return PyCapsule_New((void*) _build_quad_tree(n, |
---|
556 | (long*) triangles -> data, |
---|
557 | (double*) vertex_coordinates -> data, |
---|
558 | (double*) extents -> data), |
---|
559 | "quad tree", |
---|
560 | &delete_quad_tree_cap); |
---|
561 | |
---|
562 | #else |
---|
563 | |
---|
564 | return PyCObject_FromVoidPtr((void*) _build_quad_tree(n, |
---|
565 | (long*) triangles -> data, |
---|
566 | (double*) vertex_coordinates -> data, |
---|
567 | (double*) extents -> data), |
---|
568 | &delete_quad_tree_cobj); |
---|
569 | #endif |
---|
570 | } |
---|
571 | |
---|
572 | // Builds the smoothing matrix D. Parses |
---|
573 | // input mesh information from python and then builds a sparse_dok, returning |
---|
574 | // a capsule object wrapping a pointer to this struct. |
---|
575 | PyObject *build_smoothing_matrix(PyObject *self, PyObject *args) { |
---|
576 | |
---|
577 | |
---|
578 | PyArrayObject *triangles; |
---|
579 | PyArrayObject *areas; |
---|
580 | PyArrayObject *vertex_coordinates; |
---|
581 | int err; |
---|
582 | |
---|
583 | // Convert Python arguments to C |
---|
584 | if (!PyArg_ParseTuple(args, "OOO" , |
---|
585 | &triangles, |
---|
586 | &areas, |
---|
587 | &vertex_coordinates |
---|
588 | )) { |
---|
589 | PyErr_SetString(PyExc_RuntimeError, |
---|
590 | "fitsmooth.c: could not parse input"); |
---|
591 | return NULL; |
---|
592 | } |
---|
593 | |
---|
594 | CHECK_C_CONTIG(triangles); |
---|
595 | CHECK_C_CONTIG(areas); |
---|
596 | CHECK_C_CONTIG(vertex_coordinates); |
---|
597 | |
---|
598 | int n = triangles->dimensions[0]; |
---|
599 | |
---|
600 | |
---|
601 | sparse_dok * smoothing_mat; // Should be an input argument? |
---|
602 | smoothing_mat = make_dok(); |
---|
603 | |
---|
604 | err = _build_smoothing_matrix(n, |
---|
605 | (long*) triangles -> data, |
---|
606 | (double*) areas -> data, |
---|
607 | (double*) vertex_coordinates -> data, |
---|
608 | (int *) vertex_coordinates -> strides, |
---|
609 | smoothing_mat); |
---|
610 | |
---|
611 | |
---|
612 | if (err != 0) { |
---|
613 | PyErr_SetString(PyExc_RuntimeError, |
---|
614 | "Unknown Error"); |
---|
615 | return NULL; |
---|
616 | } |
---|
617 | |
---|
618 | #ifdef PYVERSION273 |
---|
619 | |
---|
620 | return PyCapsule_New((void*) smoothing_mat, |
---|
621 | "sparse dok", |
---|
622 | &delete_dok_cap); |
---|
623 | |
---|
624 | #else |
---|
625 | |
---|
626 | return PyCObject_FromVoidPtr((void*) smoothing_mat, |
---|
627 | &delete_dok_cobj); |
---|
628 | |
---|
629 | #endif |
---|
630 | |
---|
631 | } |
---|
632 | |
---|
633 | // Read a data file (netcdf format) to build |
---|
634 | // AtA and Atz. Returns a pointer to the sparse dok matrix AtA wrapped in a capsule |
---|
635 | // object and a python list for the array Atz. |
---|
636 | PyObject *build_matrix_AtA_Atz_fileread(PyObject *self, PyObject *args) { |
---|
637 | |
---|
638 | |
---|
639 | PyArrayObject *triangles; |
---|
640 | char * file_name; |
---|
641 | char * attribute_name; |
---|
642 | int block_size; |
---|
643 | int N; // Number of triangles |
---|
644 | int err; |
---|
645 | PyObject *tree; |
---|
646 | |
---|
647 | // Convert Python arguments to C |
---|
648 | if (!PyArg_ParseTuple(args, "OiOssi",&tree, &N, |
---|
649 | &triangles, |
---|
650 | &file_name, |
---|
651 | &attribute_name, |
---|
652 | &block_size |
---|
653 | )) { |
---|
654 | PyErr_SetString(PyExc_RuntimeError, |
---|
655 | "fitsmooth.c: could not parse input"); |
---|
656 | return NULL; |
---|
657 | } |
---|
658 | |
---|
659 | |
---|
660 | |
---|
661 | CHECK_C_CONTIG(triangles); |
---|
662 | |
---|
663 | #ifdef PYVERSION273 |
---|
664 | quad_tree * quadtree = (quad_tree*) PyCapsule_GetPointer(tree,"quad tree"); |
---|
665 | #else |
---|
666 | quad_tree * quadtree = (quad_tree*) PyCObject_AsVoidPtr(tree); |
---|
667 | #endif |
---|
668 | |
---|
669 | sparse_dok * dok_AtA; // Should be an input argument? |
---|
670 | dok_AtA = make_dok(); |
---|
671 | double * Atz = malloc(sizeof(double)*N); |
---|
672 | |
---|
673 | err = _build_matrix_AtA_Atz_fileread(N,(long*) triangles->data, |
---|
674 | file_name, |
---|
675 | attribute_name, |
---|
676 | block_size, |
---|
677 | dok_AtA, |
---|
678 | Atz, |
---|
679 | quadtree); |
---|
680 | |
---|
681 | if (err != 0) { |
---|
682 | PyErr_SetString(PyExc_RuntimeError, |
---|
683 | "Unknown Error"); |
---|
684 | return NULL; |
---|
685 | } |
---|
686 | |
---|
687 | #ifdef PYVERSION273 |
---|
688 | PyObject * AtA_cap = PyCapsule_New((void*) dok_AtA, |
---|
689 | "sparse dok", |
---|
690 | &delete_dok_cap); |
---|
691 | #else |
---|
692 | PyObject * AtA_cap = PyCObject_FromVoidPtr((void*) dok_AtA, |
---|
693 | &delete_dok_cobj); |
---|
694 | #endif |
---|
695 | |
---|
696 | PyObject *Atz_ret = c_double_array_to_list(Atz,N); |
---|
697 | |
---|
698 | int npts; |
---|
699 | err = _read_net_cdf_entries(file_name, &npts); |
---|
700 | |
---|
701 | PyObject *lst = PyList_New(3); |
---|
702 | PyList_SET_ITEM(lst, 0, AtA_cap); |
---|
703 | PyList_SET_ITEM(lst, 1, Atz_ret); |
---|
704 | PyList_SET_ITEM(lst, 2, PyInt_FromLong((long)npts)); |
---|
705 | return lst; |
---|
706 | |
---|
707 | } |
---|
708 | |
---|
709 | // Builds AtA and Atz directly from a list of |
---|
710 | // points and values Returns a pointer to the sparse dok matrix AtA wrapped in |
---|
711 | // a capsule object and a python list for the array Atz. |
---|
712 | PyObject *build_matrix_AtA_Atz_points(PyObject *self, PyObject *args) { |
---|
713 | |
---|
714 | |
---|
715 | PyArrayObject *triangles; |
---|
716 | PyArrayObject *point_coordinates; |
---|
717 | PyArrayObject *z; |
---|
718 | int N; // Number of triangles |
---|
719 | int err; |
---|
720 | int npts; |
---|
721 | int zdims; |
---|
722 | PyObject *tree; |
---|
723 | |
---|
724 | // Convert Python arguments to C |
---|
725 | if (!PyArg_ParseTuple(args, "OiOOOii",&tree, &N, |
---|
726 | &triangles, |
---|
727 | &point_coordinates, |
---|
728 | &z, |
---|
729 | &zdims, |
---|
730 | &npts |
---|
731 | )) { |
---|
732 | PyErr_SetString(PyExc_RuntimeError, |
---|
733 | "fitsmooth.c: could not parse input"); |
---|
734 | return NULL; |
---|
735 | } |
---|
736 | |
---|
737 | |
---|
738 | CHECK_C_CONTIG(triangles); |
---|
739 | CHECK_C_CONTIG(point_coordinates); |
---|
740 | CHECK_C_CONTIG(z); |
---|
741 | |
---|
742 | #ifdef PYVERSION273 |
---|
743 | quad_tree * quadtree = (quad_tree*) PyCapsule_GetPointer(tree,"quad tree"); |
---|
744 | #else |
---|
745 | quad_tree * quadtree = (quad_tree*) PyCObject_AsVoidPtr(tree); |
---|
746 | #endif |
---|
747 | |
---|
748 | sparse_dok * dok_AtA; // Should be an input argument? |
---|
749 | dok_AtA = make_dok(); |
---|
750 | double ** Atz = malloc(sizeof(double*)*zdims); |
---|
751 | int i; |
---|
752 | for(i=0;i<zdims;i++){ |
---|
753 | Atz[i] = malloc(sizeof(double)*N); |
---|
754 | } |
---|
755 | |
---|
756 | err = _build_matrix_AtA_Atz_points(N,(long*) triangles->data, |
---|
757 | (double*) point_coordinates->data, |
---|
758 | (double*) z->data, |
---|
759 | zdims, |
---|
760 | npts, |
---|
761 | dok_AtA, |
---|
762 | Atz, |
---|
763 | quadtree); |
---|
764 | |
---|
765 | |
---|
766 | if (err != 0) { |
---|
767 | PyErr_SetString(PyExc_RuntimeError, |
---|
768 | "Unknown Error"); |
---|
769 | return NULL; |
---|
770 | } |
---|
771 | |
---|
772 | #ifdef PYVERSION273 |
---|
773 | PyObject * AtA_cap = PyCapsule_New((void*) dok_AtA, |
---|
774 | "sparse dok", |
---|
775 | &delete_dok_cap); |
---|
776 | #else |
---|
777 | PyObject * AtA_cap = PyCObject_FromVoidPtr((void*) dok_AtA, |
---|
778 | &delete_dok_cobj); |
---|
779 | #endif |
---|
780 | PyObject * Atz_ret = PyList_New(zdims); |
---|
781 | for(i=0;i<zdims;i++){ |
---|
782 | PyList_SET_ITEM(Atz_ret,i,c_double_array_to_list(Atz[i],N)); |
---|
783 | free(Atz[i]); |
---|
784 | } |
---|
785 | free(Atz); |
---|
786 | |
---|
787 | PyObject *lst = PyList_New(2); |
---|
788 | PyList_SET_ITEM(lst, 0, AtA_cap); |
---|
789 | PyList_SET_ITEM(lst, 1, Atz_ret); |
---|
790 | return lst; |
---|
791 | |
---|
792 | } |
---|
793 | |
---|
794 | // Searches a quad tree struct for the triangle containing a given point, |
---|
795 | // returns the sigma values produced by this point and the triangle found, |
---|
796 | // and the triangle index. Found is returned as 0 if no triangle is found |
---|
797 | // and 1 otherwise. |
---|
798 | PyObject *individual_tree_search(PyObject *self, PyObject *args) { |
---|
799 | |
---|
800 | // Setting up variables to parse input |
---|
801 | PyObject *tree; |
---|
802 | PyArrayObject *point; |
---|
803 | |
---|
804 | // Convert Python arguments to C |
---|
805 | if (!PyArg_ParseTuple(args, "OO",&tree, &point |
---|
806 | )) { |
---|
807 | PyErr_SetString(PyExc_RuntimeError, |
---|
808 | "fitsmooth.c: could not parse input"); |
---|
809 | return NULL; |
---|
810 | } |
---|
811 | |
---|
812 | CHECK_C_CONTIG(point); |
---|
813 | |
---|
814 | #ifdef PYVERSION273 |
---|
815 | quad_tree * quadtree = (quad_tree*) PyCapsule_GetPointer(tree,"quad tree"); |
---|
816 | #else |
---|
817 | quad_tree * quadtree = (quad_tree*) PyCObject_AsVoidPtr(tree); |
---|
818 | #endif |
---|
819 | |
---|
820 | double xp,yp; |
---|
821 | if(PyArray_TYPE(point)==7){ |
---|
822 | int *pointd = (int*)point->data; |
---|
823 | xp = (double)(pointd[0]); |
---|
824 | yp = (double)(pointd[1]); |
---|
825 | } |
---|
826 | else{ |
---|
827 | double *pointd = (double*)point->data; |
---|
828 | xp = pointd[0]; |
---|
829 | yp = pointd[1]; |
---|
830 | } |
---|
831 | |
---|
832 | triangle * T = search(quadtree,xp,yp); |
---|
833 | PyObject * sigmalist = PyList_New(3); |
---|
834 | long found; |
---|
835 | long index; |
---|
836 | |
---|
837 | if(T!=NULL){ |
---|
838 | double * sigma = calculate_sigma(T,xp,yp); |
---|
839 | sigmalist = c_double_array_to_list(sigma,3); |
---|
840 | free(sigma); |
---|
841 | found = 1; |
---|
842 | index = (long)T->index; |
---|
843 | }else{ |
---|
844 | double sigma[3]; |
---|
845 | sigma[0]=sigma[1]=sigma[2]=-1; |
---|
846 | sigmalist = c_double_array_to_list(sigma,3); |
---|
847 | index = -10; |
---|
848 | found = 0; |
---|
849 | } |
---|
850 | PyObject * retlist = PyList_New(3); |
---|
851 | PyList_SET_ITEM(retlist,0,PyInt_FromLong(found)); |
---|
852 | PyList_SET_ITEM(retlist,1,sigmalist); |
---|
853 | PyList_SET_ITEM(retlist,2,PyInt_FromLong(index)); |
---|
854 | return retlist; |
---|
855 | } |
---|
856 | |
---|
857 | // Returns the total number of triangles stored in quad_tree. |
---|
858 | // Takes a capsule object holding a pointer to the quad_tree as input. |
---|
859 | // |
---|
860 | // PADARN NOTE: This function was only added for the purpose of passing unit |
---|
861 | // tests. Perhaps this, and other tree functions, should be moved to another |
---|
862 | // file to provide a more comprehensive python interface to the tree structure. |
---|
863 | PyObject *items_in_tree(PyObject *self, PyObject *args) { |
---|
864 | |
---|
865 | // Setting up variables to parse input |
---|
866 | PyObject *tree; // capsule to hold quad_tree pointer |
---|
867 | |
---|
868 | // Convert Python arguments to C |
---|
869 | if (!PyArg_ParseTuple(args, "O",&tree |
---|
870 | )) { |
---|
871 | PyErr_SetString(PyExc_RuntimeError, |
---|
872 | "fitsmooth.c: could not parse input"); |
---|
873 | return NULL; |
---|
874 | } |
---|
875 | |
---|
876 | // Extract quad_tree pointer from capsule |
---|
877 | #ifdef PYVERSION273 |
---|
878 | quad_tree * quadtree = (quad_tree*) PyCapsule_GetPointer(tree,"quad tree"); |
---|
879 | #else |
---|
880 | quad_tree * quadtree = (quad_tree*) PyCObject_AsVoidPtr(tree); |
---|
881 | #endif; |
---|
882 | |
---|
883 | // Return the number of elements in the tree (stored in struct) |
---|
884 | return PyInt_FromLong((long)quadtree->count); |
---|
885 | |
---|
886 | } |
---|
887 | |
---|
888 | // Returns the total number of nodes stored in quad_tree. |
---|
889 | // Takes a capsule object holding a pointer to the quad_tree as input. |
---|
890 | PyObject *nodes_in_tree(PyObject *self, PyObject *args) { |
---|
891 | |
---|
892 | // Setting up variables to parse input |
---|
893 | PyObject *tree; // capsule to hold quad_tree pointer |
---|
894 | |
---|
895 | // Convert Python arguments to C |
---|
896 | if (!PyArg_ParseTuple(args, "O",&tree |
---|
897 | )) { |
---|
898 | PyErr_SetString(PyExc_RuntimeError, |
---|
899 | "fitsmooth.c: could not parse input"); |
---|
900 | return NULL; |
---|
901 | } |
---|
902 | |
---|
903 | // Extract quad_tree pointer from capsule |
---|
904 | #ifdef PYVERSION273 |
---|
905 | quad_tree * quadtree = (quad_tree*) PyCapsule_GetPointer(tree,"quad tree"); |
---|
906 | #else |
---|
907 | quad_tree * quadtree = (quad_tree*) PyCObject_AsVoidPtr(tree); |
---|
908 | #endif |
---|
909 | |
---|
910 | // Return the number of elements in the tree (stored in struct) |
---|
911 | return PyInt_FromLong((long)quad_tree_node_count(quadtree)); |
---|
912 | |
---|
913 | } |
---|
914 | |
---|
915 | // Combines two sparse_dok and two double arrays together |
---|
916 | // which represent partial completion of the AtA and Atz matrices, when they are build |
---|
917 | // in parts due to points being read in blocks in python. Result is stored in the first |
---|
918 | // sparse_dok and double array. |
---|
919 | // Function takes as arguments two capsule objects holding pointers to the sparse_dok |
---|
920 | // structs, and two numpy double arrays. Aslo the size of the double arrays, and the number |
---|
921 | // of columns (variables) for the array Atz are passed as arguments. |
---|
922 | // |
---|
923 | // PADARN NOTE: Blocking the points in python is far slower than reading them directly |
---|
924 | // in c and bypassing the need for this. |
---|
925 | PyObject *combine_partial_AtA_Atz(PyObject *self, PyObject *args) { |
---|
926 | |
---|
927 | // Setting up variables to parse input |
---|
928 | PyObject *AtA_cap1, *AtA_cap2; |
---|
929 | PyArrayObject *Atz1, *Atz2; |
---|
930 | int n,zdim; // number of nodes |
---|
931 | |
---|
932 | // Convert Python arguments to C |
---|
933 | if (!PyArg_ParseTuple(args, "OOOOii",&AtA_cap1, &AtA_cap2, |
---|
934 | &Atz1, &Atz2, &zdim, &n |
---|
935 | )) { |
---|
936 | PyErr_SetString(PyExc_RuntimeError, |
---|
937 | "fitsmooth.c: could not parse input"); |
---|
938 | return NULL; |
---|
939 | } |
---|
940 | |
---|
941 | // Get pointers to sparse_dok objects from capsules |
---|
942 | #ifdef PYVERSION273 |
---|
943 | sparse_dok * dok_AtA1 = (sparse_dok*) PyCapsule_GetPointer(AtA_cap1,"sparse dok"); |
---|
944 | sparse_dok * dok_AtA2 = (sparse_dok*) PyCapsule_GetPointer(AtA_cap2,"sparse dok"); |
---|
945 | #else |
---|
946 | sparse_dok * dok_AtA1 = (sparse_dok*) PyCObject_AsVoidPtr(AtA_cap1); |
---|
947 | sparse_dok * dok_AtA2 = (sparse_dok*) PyCObject_AsVoidPtr(AtA_cap2); |
---|
948 | #endif |
---|
949 | |
---|
950 | // Combine the partial AtA and Atz |
---|
951 | _combine_partial_AtA_Atz(dok_AtA1,dok_AtA2, |
---|
952 | (double*) Atz1->data, |
---|
953 | (double*) Atz2->data, |
---|
954 | n, zdim); |
---|
955 | |
---|
956 | // Return nothing interesting |
---|
957 | return Py_BuildValue(""); |
---|
958 | } |
---|
959 | |
---|
960 | // Converts a sparse_dok matrix to a full non-compressed matrix expressed |
---|
961 | // as a list of lists (python). Takes as input a capsule object containing a pointer to the |
---|
962 | // sparse_dok object. Also takes an integer n as input, specifying the (n x n) size of the |
---|
963 | // matrix. Matrix is assumed square. |
---|
964 | // |
---|
965 | // PADARN NOTE: This function does not seem particularly sensible, but was required for the |
---|
966 | // purposes of passing unit tests. |
---|
967 | PyObject *return_full_D(PyObject *self, PyObject *args) { |
---|
968 | |
---|
969 | // Setting up variables to parse input |
---|
970 | PyObject *D_cap; // capsule object holding sparse_dok pointer |
---|
971 | int n; // number of matrix columns/rows |
---|
972 | |
---|
973 | // Convert Python arguments to C |
---|
974 | if (!PyArg_ParseTuple(args, "Oi",&D_cap, &n |
---|
975 | )) { |
---|
976 | PyErr_SetString(PyExc_RuntimeError, |
---|
977 | "fitsmooth.return_full_D: could not parse input"); |
---|
978 | return NULL; |
---|
979 | } |
---|
980 | |
---|
981 | // Get pointer to spars_dok struct |
---|
982 | #ifdef PYVERSION273 |
---|
983 | sparse_dok * D_mat = (sparse_dok*) PyCapsule_GetPointer(D_cap,"sparse dok"); |
---|
984 | #else |
---|
985 | sparse_dok * D_mat = (sparse_dok*) PyCObject_AsVoidPtr(D_cap); |
---|
986 | #endif |
---|
987 | |
---|
988 | // Check to make sure that the specified size of the matrix is at least as big |
---|
989 | // as the entries stored in the sparse_dok. |
---|
990 | if (D_mat->num_rows>n || get_dok_rows(D_mat)>n){ |
---|
991 | PyErr_SetString(PyExc_RuntimeError, |
---|
992 | "fitsmooth.return_full_D: sparse_dok is bigger than size specified for return."); |
---|
993 | return NULL; |
---|
994 | } |
---|
995 | |
---|
996 | // Build new python list containing the full matrix to return |
---|
997 | PyObject *ret_D = PyList_New(n); |
---|
998 | int i,j; |
---|
999 | edge_key_t key; |
---|
1000 | edge_t *s; |
---|
1001 | for(i=0;i<n;i++) |
---|
1002 | { |
---|
1003 | PyObject *temp = PyList_New(n); |
---|
1004 | for(j=0;j<n;j++) |
---|
1005 | { |
---|
1006 | key.i=i; |
---|
1007 | key.j=j; |
---|
1008 | s = find_dok_entry(D_mat,key); |
---|
1009 | if (s){ |
---|
1010 | PyList_SET_ITEM(temp,j,PyFloat_FromDouble(s->entry)); |
---|
1011 | }else{ |
---|
1012 | PyList_SET_ITEM(temp,j,PyFloat_FromDouble(0)); |
---|
1013 | } |
---|
1014 | PyList_SET_ITEM(ret_D,i,temp); |
---|
1015 | } |
---|
1016 | } |
---|
1017 | |
---|
1018 | return ret_D; |
---|
1019 | } |
---|
1020 | |
---|
1021 | // Takes as input two capsule objects corresponding to the two matricies |
---|
1022 | // D and AtA, along with a regularization coefficient alpha. |
---|
1023 | // Returns three matricies corresponding to the CSR format storage of the matrix resulting |
---|
1024 | // from the computation B = AtA + alpha * D. |
---|
1025 | // |
---|
1026 | // Capsule objects are not freed and are left alone to be freed as they naturally go out of |
---|
1027 | // scope in Python. The temporary CSR matrix created is cleaned up. |
---|
1028 | PyObject *build_matrix_B(PyObject *self, PyObject *args) { |
---|
1029 | |
---|
1030 | |
---|
1031 | // Setting up variables to parse input |
---|
1032 | double alpha; // Regularization coefficient |
---|
1033 | PyObject *smoothing_mat_cap; // Capsule storing D pointer (sparse_dok struct) |
---|
1034 | PyObject *AtA_cap; // Capsule storing AtA pointer (sparse_dok struct) |
---|
1035 | |
---|
1036 | // Convert Python arguments to C |
---|
1037 | if (!PyArg_ParseTuple(args, "OOd",&smoothing_mat_cap, &AtA_cap, &alpha |
---|
1038 | )) { |
---|
1039 | PyErr_SetString(PyExc_RuntimeError, |
---|
1040 | "fitsmooth.build_matrix_B: could not parse input"); |
---|
1041 | return NULL; |
---|
1042 | } |
---|
1043 | |
---|
1044 | // Extract pointers to c structs from capsules |
---|
1045 | #ifdef PYVERSION273 |
---|
1046 | sparse_dok * smoothing_mat = (sparse_dok*) PyCapsule_GetPointer(smoothing_mat_cap,"sparse dok"); |
---|
1047 | sparse_dok * dok_AtA = (sparse_dok*) PyCapsule_GetPointer(AtA_cap,"sparse dok"); |
---|
1048 | #else |
---|
1049 | sparse_dok * smoothing_mat = (sparse_dok*) PyCObject_AsVoidPtr(smoothing_mat_cap); |
---|
1050 | sparse_dok * dok_AtA = (sparse_dok*) PyCObject_AsVoidPtr(AtA_cap); |
---|
1051 | #endif |
---|
1052 | |
---|
1053 | // Add two sparse_dok matrices |
---|
1054 | add_sparse_dok(smoothing_mat,alpha,dok_AtA,1); |
---|
1055 | |
---|
1056 | // Create sparse_csr matrix and convert result to this format |
---|
1057 | sparse_csr * B; |
---|
1058 | B = make_csr(); |
---|
1059 | convert_to_csr_ptr(B,smoothing_mat); |
---|
1060 | |
---|
1061 | // Extract the sparse_csr data to be returned as python lists |
---|
1062 | PyObject *data = c_double_array_to_list(B->data, |
---|
1063 | B->num_entries); |
---|
1064 | PyObject *colind = c_int_array_to_list(B->colind, |
---|
1065 | B->num_entries); |
---|
1066 | PyObject *row_ptr = c_int_array_to_list(B->row_ptr, |
---|
1067 | B->num_rows); |
---|
1068 | |
---|
1069 | // Build python list for return |
---|
1070 | PyObject *lst = PyList_New(3); |
---|
1071 | PyList_SET_ITEM(lst, 0, data); |
---|
1072 | PyList_SET_ITEM(lst, 1, colind); |
---|
1073 | PyList_SET_ITEM(lst, 2, row_ptr); |
---|
1074 | |
---|
1075 | // Clean up |
---|
1076 | delete_csr_matrix(B); |
---|
1077 | |
---|
1078 | return lst; |
---|
1079 | |
---|
1080 | |
---|
1081 | |
---|
1082 | } |
---|
1083 | //------------------------------------------------------------------------------ |
---|
1084 | |
---|
1085 | |
---|
1086 | // ------------------------------ PYTHON GLUE ---------------------------------- |
---|
1087 | |
---|
1088 | //============================================================================== |
---|
1089 | // Structures to allow calling from python |
---|
1090 | //============================================================================== |
---|
1091 | |
---|
1092 | // Method table for python module |
---|
1093 | static struct PyMethodDef MethodTable[] = { |
---|
1094 | {"items_in_tree",items_in_tree, METH_VARARGS, "Print out"}, |
---|
1095 | {"nodes_in_tree",nodes_in_tree, METH_VARARGS, "Print out"}, |
---|
1096 | {"return_full_D",return_full_D, METH_VARARGS, "Print out"}, |
---|
1097 | {"build_matrix_B",build_matrix_B, METH_VARARGS, "Print out"}, |
---|
1098 | {"build_quad_tree",build_quad_tree, METH_VARARGS, "Print out"}, |
---|
1099 | {"build_smoothing_matrix",build_smoothing_matrix, METH_VARARGS, "Print out"}, |
---|
1100 | {"build_matrix_AtA_Atz_fileread",build_matrix_AtA_Atz_fileread, METH_VARARGS, "Print out"}, |
---|
1101 | {"build_matrix_AtA_Atz_points",build_matrix_AtA_Atz_points, METH_VARARGS, "Print out"}, |
---|
1102 | {"combine_partial_AtA_Atz",combine_partial_AtA_Atz, METH_VARARGS, "Print out"}, |
---|
1103 | {"individual_tree_search",individual_tree_search, METH_VARARGS, "Print out"}, |
---|
1104 | {NULL, NULL, 0, NULL} // sentinel |
---|
1105 | }; |
---|
1106 | |
---|
1107 | |
---|
1108 | // Module initialisation |
---|
1109 | void initfitsmooth(void){ |
---|
1110 | Py_InitModule("fitsmooth", MethodTable); |
---|
1111 | import_array(); // Necessary for handling of NumPY structures |
---|
1112 | |
---|
1113 | } |
---|
1114 | |
---|
1115 | // -------------------------------------------------------------------------------- |
---|