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

Last change on this file since 9648 was 9648, checked in by steve, 10 years ago

Cleaning up fitsmooth to remove VC++ errors

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