File Coverage

pdlperlfunc.c
Criterion Covered Total %
statement 85 89 95.5
branch 15 28 53.5
condition n/a
subroutine n/a
pod n/a
total 100 117 85.4


line stmt bran cond sub pod time code
1             #include "pdlperlfunc.h"
2              
3             #define PDL PDL_Fit_Levmar
4             extern Core *PDL;
5              
6             typedef void (*DelMagic)(pdl *, Size_t param);
7 0           static void default_magic(pdl *p, Size_t pa) { p->data = 0; }
8              
9             // Don't free data, it is allocated inside liblevmar
10 40           static void delete_levmar_pdls(pdl* p, Size_t param)
11             {
12 40           if (p->data) {
13             // free(p->data);
14             }
15             else {
16             }
17 40           p->data = 0;
18 40           }
19              
20             // Code from PDL::API docs. For creating a pdl and giving it
21             // data storage allocated elswhere.
22 40           static pdl* pdl_wrap(void *data, int datatype, PDL_Indx dims[],
23             int ndims, DelMagic delete_magic, int delparam)
24             {
25 40           pdl* npdl = PDL->pdlnew(); /* get the empty container */
26 40           PDL->setdims(npdl,dims,ndims); /* set dims */
27 40           npdl->datatype = datatype; /* and data type */
28 40           npdl->data = data; /* point it to your data */
29             /* make sure the core doesn't meddle with your data */
30 40           npdl->state |= PDL_DONTTOUCHDATA | PDL_ALLOCATED;
31 40 50         if (delete_magic != NULL) {
32 40           PDL->add_deletedata_magic(npdl, delete_magic, delparam);
33             } else
34 0           PDL->add_deletedata_magic(npdl, default_magic, 0);
35 40           return npdl;
36             }
37              
38             /* We use a struct holding data for the wrapper functions to
39             * perl fit code, LEVFUNC, and JLEVFUNC. liblevmar uses fit
40             * functions whose the last argument is a pointer to
41             * unpecified data. When fitting data it is normally used
42             * for the ordinate data (t). We pass a DFP struct instead.
43             * These functions are all re-entrant, i hope. The DFP
44             * struct holds pdls which are created once at the start of
45             * a fit and destroyed when it is finished. Data is not put
46             * in the pdls here. The fit routines send different arrays
47             * on different calls, so the pdl pointer to the data must
48             * be set in the wrapper functions at each call. t is an
49             * exception-- it is set by the user just once. levmar calls
50             * DFP_check() (below) which either sets t, or points the
51             * DFP *dat directly to t, if the wrapper functions are not
52             * used (ie for pure C fit functions).
53             */
54 10           static void DFP_create_pdls( DFP *dat, int data_type, int m, int n, int nt) {
55             pdl *p_pdl, *x_pdl, *d_pdl, *t_pdl;
56             SV *p_sv, *x_sv, *d_sv, *t_sv;
57 10           PDL_Indx mf_dims[] = {m};
58 10           int num_mf_dims = 1;
59 10           PDL_Indx mjac_dims[] = {m,n}; // for jacobian 'd' variable
60 10           int num_mjac_dims = 2;
61 10           PDL_Indx n_dims[] = {n};
62 10           int num_n_dims = 1;
63 10           PDL_Indx nt_dims[] = {nt};
64 10           int num_nt_dims = 1;
65             // create pdls, but with no data;
66 10           p_pdl = pdl_wrap(NULL, data_type, mf_dims, num_mf_dims, delete_levmar_pdls, 0);
67 10           d_pdl = pdl_wrap(NULL, data_type, mjac_dims, num_mjac_dims, delete_levmar_pdls, 0);
68 10           x_pdl = pdl_wrap(NULL, data_type, n_dims, num_n_dims, delete_levmar_pdls, 0);
69 10           t_pdl = pdl_wrap(NULL, data_type, nt_dims, num_nt_dims, delete_levmar_pdls, 0);
70             // otherwise we get a memory leak
71 10           p_sv = sv_newmortal();
72 10           d_sv = sv_newmortal();
73 10           x_sv = sv_newmortal();
74 10           t_sv = sv_newmortal();
75 10           PDL->SetSV_PDL(p_sv, p_pdl);
76 10           PDL->SetSV_PDL(d_sv, d_pdl);
77 10           PDL->SetSV_PDL(x_sv, x_pdl);
78 10           PDL->SetSV_PDL(t_sv, t_pdl);
79 10           dat->p_pdl = p_pdl;
80 10           dat->d_pdl = d_pdl;
81 10           dat->t_pdl = t_pdl;
82 10           dat->x_pdl = x_pdl;
83 10           dat->p_sv = p_sv;
84 10           dat->d_sv = d_sv;
85 10           dat->t_sv = t_sv;
86 10           dat->x_sv = x_sv;
87 10           }
88              
89             /* If dat is null then no DFP struct was created because we
90             * are using a C function and it will expect t as the last
91             * argument (and dat is passed as the last argument). If
92             * dat is non-null, it will hold a struct with all the pdls
93             * and we must put t in its proper place.
94             */
95 94           void DFP_check(DFP **dat, int data_type, int m, int n, int nt, void *t ) {
96 94 100         if ( *dat != NULL) {
97 10           DFP_create_pdls( *dat, data_type, m, n, nt);
98 10           (*dat)->t_pdl->data = t;
99             }
100             else { // Pure C routine that don't need this wrapper, expect t as last arg
101 84           *dat = (DFP *)t; // cast in case compiler complains.
102             }
103 94           }
104              
105             //-----------------------------------------------------
106             // Modified Function from pdl gsl interp code
107             // It follows the perlembed doc example closely
108              
109 77754           void LEVFUNC(double *p, double *x, int m, int n, DFP *dat) {
110             int count;
111 77754           dSP;
112              
113 77754           dat->p_pdl->data = p;
114 77754           dat->x_pdl->data = x;
115              
116 77754           ENTER;
117 77754           SAVETMPS;
118              
119 77754 50         PUSHMARK(SP);
120              
121             // Dont make mortal, they come from outside this routine
122 77754 50         XPUSHs(dat->p_sv);
123 77754 50         XPUSHs(dat->x_sv);
124 77754 50         XPUSHs(dat->t_sv);
125              
126 77754           PUTBACK;
127 77754           count=call_sv(dat->perl_fit_func,G_SCALAR);
128 77754           SPAGAIN;
129 77754 50         if (count!=1)
130 0           croak("error calling perl function\n");
131              
132 77754           PUTBACK;
133 77754 50         FREETMPS;
134 77754           LEAVE;
135              
136 77754           }
137              
138 15224           void JLEVFUNC(double *p, double *d, int m, int n, DFP *dat) {
139             int count;
140 15224           dat->p_pdl->data = p;
141 15224           dat->d_pdl->data = d;
142              
143 15224           dSP;
144 15224           ENTER;
145 15224           SAVETMPS;
146 15224 50         PUSHMARK(SP);
147 15224 50         XPUSHs(dat->p_sv);
148 15224 50         XPUSHs(dat->d_sv);
149 15224 50         XPUSHs(dat->t_sv);
150 15224           PUTBACK;
151 15224           count=call_sv(dat->perl_jac_func,G_SCALAR);
152 15224           SPAGAIN;
153 15224 50         if (count!=1)
154 0           croak("error calling perl function\n");
155 15224           PUTBACK;
156 15224 50         FREETMPS;
157 15224           LEAVE;
158 15224           }