source: trunk/anuga_core/source/anuga/fit_interpolate/fitsmooth.c @ 8709

Last change on this file since 8709 was 8709, checked in by wilsonp, 11 years ago

Changes to fitsmooth.c to use PyCObject when Python version is detected as lower than 2.7.3. Also, small fixes to caching of quad tree.

File size: 33.3 KB
Line 
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
40int _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.
73int _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
108int _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.
223quad_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.
259int _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).
345int _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.
412void _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.
428static 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.
449static 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
479void 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".
489void 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
503void 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
511void 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.
527PyObject *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.
575PyObject *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.
636PyObject *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.
712PyObject *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.
798PyObject *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.
863PyObject *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.
890PyObject *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.
925PyObject *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.
967PyObject *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.
1028PyObject *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
1093static 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
1109void initfitsmooth(void){
1110  Py_InitModule("fitsmooth", MethodTable);
1111  import_array(); // Necessary for handling of NumPY structures
1112
1113}
1114
1115// --------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.