source: sasview/pr_inversion/c_extensions/Cinvertor.c @ 47f695c9

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 47f695c9 was 9e8dc22, checked in by Mathieu Doucet <doucetm@…>, 17 years ago

Initial import.

  • Property mode set to 100644
File size: 11.5 KB
Line 
1
2#include <Python.h>
3#include "structmember.h"
4#include <stdio.h>
5#include <stdlib.h>
6#include <math.h>
7#include <time.h>
8
9#include "invertor.h"
10
11
12/// Error object for raised exceptions
13static PyObject * CinvertorError = NULL;
14
15#define INVECTOR(obj,buf,len)                                                                           \
16    do { \
17        int err = PyObject_AsReadBuffer(obj, (const void **)(&buf), &len); \
18        if (err < 0) return NULL; \
19        len /= sizeof(*buf); \
20    } while (0)
21   
22#define OUTVECTOR(obj,buf,len) \
23    do { \
24        int err = PyObject_AsWriteBuffer(obj, (void **)(&buf), &len); \
25        if (err < 0) return NULL; \
26        len /= sizeof(*buf); \
27    } while (0)
28
29
30// Class definition
31typedef struct {
32    PyObject_HEAD   
33    Invertor_params params; 
34} Cinvertor;
35
36
37static void
38Cinvertor_dealloc(Cinvertor* self)
39{
40    invertor_dealloc(&(self->params));
41     
42    self->ob_type->tp_free((PyObject*)self);
43
44}
45
46static PyObject *
47Cinvertor_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
48{
49    Cinvertor *self;
50   
51    self = (Cinvertor *)type->tp_alloc(type, 0);
52   
53    return (PyObject *)self;
54}
55
56static int
57Cinvertor_init(Cinvertor *self, PyObject *args, PyObject *kwds)
58{
59    if (self != NULL) {         
60        // Create parameters
61        invertor_init(&(self->params));
62    }
63    return 0;
64}
65
66static PyMemberDef Cinvertor_members[] = {
67    //{"params", T_OBJECT, offsetof(Cinvertor, params), 0,
68    // "Parameters"},
69    {NULL}  /* Sentinel */
70};
71
72
73/**
74 * Function to set the x data
75 * Takes an array of doubles as input
76 * Returns the number of entries found
77 */
78static PyObject * set_x(Cinvertor *self, PyObject *args) {
79        PyObject *data_obj;
80        Py_ssize_t ndata;
81        double *data;
82 
83        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
84        OUTVECTOR(data_obj,data,ndata);
85        self->params.x = data;
86        self->params.npoints = ndata;
87        return Py_BuildValue("i", self->params.npoints);       
88}
89
90static PyObject * get_x(Cinvertor *self, PyObject *args) {
91        PyObject *data_obj;
92        Py_ssize_t ndata;
93        double *data;
94    int i;
95   
96        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
97        INVECTOR(data_obj, data, ndata);
98       
99        // Check that the input array is large enough
100        if (ndata < self->params.npoints) {
101            PyErr_SetString(CinvertorError, 
102                "Cinvertor.get_x: input array too short for data.");
103                return NULL;           
104        }
105       
106        for(i=0; i<self->params.npoints; i++){
107                data[i] = self->params.x[i];
108        }
109       
110        return Py_BuildValue("i", self->params.npoints);       
111}
112
113/**
114 * Function to set the y data
115 * Takes an array of doubles as input
116 * Returns the number of entries found
117 */
118static PyObject * set_y(Cinvertor *self, PyObject *args) {
119        PyObject *data_obj;
120        Py_ssize_t ndata;
121        double *data;
122 
123        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
124        OUTVECTOR(data_obj,data,ndata);
125        self->params.y = data;
126        self->params.ny = ndata;
127        return Py_BuildValue("i", self->params.ny);     
128}
129
130static PyObject * get_y(Cinvertor *self, PyObject *args) {
131        PyObject *data_obj;
132        Py_ssize_t ndata;
133        double *data;
134    int i;
135   
136        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
137        INVECTOR(data_obj, data, ndata);
138       
139        // Check that the input array is large enough
140        if (ndata < self->params.ny) {
141            PyErr_SetString(CinvertorError, 
142                "Cinvertor.get_y: input array too short for data.");
143                return NULL;           
144        }
145       
146        for(i=0; i<self->params.ny; i++){
147                data[i] = self->params.y[i];
148        }
149       
150        return Py_BuildValue("i", self->params.npoints);       
151}
152
153/**
154 * Function to set the x data
155 * Takes an array of doubles as input
156 * Returns the number of entries found
157 */
158static PyObject * set_err(Cinvertor *self, PyObject *args) {
159        PyObject *data_obj;
160        Py_ssize_t ndata;
161        double *data;
162 
163        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
164        OUTVECTOR(data_obj,data,ndata);
165        self->params.err = data;
166        self->params.nerr = ndata;
167        return Py_BuildValue("i", self->params.nerr);   
168}
169
170static PyObject * get_err(Cinvertor *self, PyObject *args) {
171        PyObject *data_obj;
172        Py_ssize_t ndata;
173        double *data;
174    int i;
175   
176        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
177        INVECTOR(data_obj, data, ndata);
178       
179        // Check that the input array is large enough
180        if (ndata < self->params.nerr) {
181            PyErr_SetString(CinvertorError, 
182                "Cinvertor.get_err: input array too short for data.");
183                return NULL;           
184        }
185       
186        for(i=0; i<self->params.nerr; i++){
187                data[i] = self->params.err[i];
188        }
189       
190        return Py_BuildValue("i", self->params.npoints);       
191}
192
193/**
194 * Check the validity of the stored data
195 * Returns the number of points if it's all good, -1 otherwise
196 */
197static PyObject * is_valid(Cinvertor *self, PyObject *args) {
198        if(self->params.npoints==self->params.ny &&
199                        self->params.npoints==self->params.nerr) {
200                return Py_BuildValue("i", self->params.npoints);
201        } else {
202                return Py_BuildValue("i", -1);
203        }       
204}
205
206/**
207 * Sets the maximum distance
208 */
209static PyObject * set_dmax(Cinvertor *self, PyObject *args) {
210        double d_max;
211 
212        if (!PyArg_ParseTuple(args, "d", &d_max)) return NULL;
213        self->params.d_max = d_max;
214        return Py_BuildValue("d", self->params.d_max); 
215}
216
217/**
218 * Gets the maximum distance
219 */
220static PyObject * get_dmax(Cinvertor *self, PyObject *args) {
221        return Py_BuildValue("d", self->params.d_max); 
222}
223
224/**
225 * Gets the number of x points
226 */
227static PyObject * get_nx(Cinvertor *self, PyObject *args) {
228        return Py_BuildValue("i", self->params.npoints);       
229}
230
231/**
232 * Gets the number of y points
233 */
234static PyObject * get_ny(Cinvertor *self, PyObject *args) {
235        return Py_BuildValue("i", self->params.ny);     
236}
237
238/**
239 * Gets the number of error points
240 */
241static PyObject * get_nerr(Cinvertor *self, PyObject *args) {
242        return Py_BuildValue("i", self->params.nerr);   
243}
244
245
246/**
247 * Function to call to evaluate the residuals
248 * @param args: input q or [q,phi]
249 * @return: function value
250 */
251static PyObject * residuals(Cinvertor *self, PyObject *args) {
252        double *pars;
253        PyObject* residuals;
254        PyObject* temp;
255        double *res;
256        int i;
257        double residual, diff;
258        // Regularization factor
259        double lmult = 0.0;
260       
261        PyObject *data_obj;
262        Py_ssize_t npars;
263         
264        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
265       
266        OUTVECTOR(data_obj,pars,npars);
267               
268        //printf("npars: %i", npars);
269    // PyList of residuals
270        // Should create this list only once and refill it
271    residuals = PyList_New(self->params.npoints);
272   
273    for(i=0; i<self->params.npoints; i++) {
274        //printf("\n%i: ", i);
275        diff = self->params.y[i] - iq(pars, self->params.d_max, npars, self->params.x[i]);
276        residual = diff*diff / (self->params.err[i]*self->params.err[i]);
277        //printf("%i %g\n", i, residual);
278        if (PyList_SetItem(residuals, i, Py_BuildValue("d",residual) ) < 0){
279            PyErr_SetString(CinvertorError, 
280                "Cinvertor.residuals: error setting residual.");
281                return NULL;
282        };
283               
284    }
285   
286        return residuals;
287}
288
289/**
290 * Function to call to evaluate the scattering intensity
291 * @param args: c-parameters, and q
292 * @return: I(q)
293 */
294static PyObject * get_iq(Cinvertor *self, PyObject *args) {
295        double *pars;
296        double q, iq_value;
297        PyObject *data_obj;
298        Py_ssize_t npars;
299         
300        if (!PyArg_ParseTuple(args, "Od", &data_obj, &q)) return NULL;
301        OUTVECTOR(data_obj,pars,npars);
302               
303        iq_value = iq(pars, self->params.d_max, npars, q);
304        return Py_BuildValue("f", iq_value);   
305}
306
307/**
308 * Function to call to evaluate P(r)
309 * @param args: c-parameters and r
310 * @return: P(r)
311 */
312static PyObject * get_pr(Cinvertor *self, PyObject *args) {
313        double *pars;
314        double r, pr_value;
315        PyObject *data_obj;
316        Py_ssize_t npars;
317         
318        if (!PyArg_ParseTuple(args, "Od", &data_obj, &r)) return NULL;
319        OUTVECTOR(data_obj,pars,npars);
320               
321        pr_value = pr(pars, self->params.d_max, npars, r);
322        return Py_BuildValue("f", pr_value);   
323}
324
325
326static PyMethodDef Cinvertor_methods[] = {
327                   {"residuals", (PyCFunction)residuals, METH_VARARGS, "Get the list of residuals"},
328                   {"set_x", (PyCFunction)set_x, METH_VARARGS, ""},
329                   {"get_x", (PyCFunction)get_x, METH_VARARGS, ""},
330                   {"set_y", (PyCFunction)set_y, METH_VARARGS, ""},
331                   {"get_y", (PyCFunction)get_y, METH_VARARGS, ""},
332                   {"set_err", (PyCFunction)set_err, METH_VARARGS, ""},
333                   {"get_err", (PyCFunction)get_err, METH_VARARGS, ""},
334                   {"set_dmax", (PyCFunction)set_dmax, METH_VARARGS, ""},
335                   {"get_dmax", (PyCFunction)get_dmax, METH_VARARGS, ""},
336                   {"get_nx", (PyCFunction)get_nx, METH_VARARGS, ""},
337                   {"get_ny", (PyCFunction)get_ny, METH_VARARGS, ""},
338                   {"get_nerr", (PyCFunction)get_nerr, METH_VARARGS, ""},
339                   {"iq", (PyCFunction)get_iq, METH_VARARGS, ""},
340                   {"pr", (PyCFunction)get_pr, METH_VARARGS, ""},
341                   {"is_valid", (PyCFunction)is_valid, METH_VARARGS, ""},
342   
343   {NULL}
344};
345
346static PyTypeObject CinvertorType = {
347    PyObject_HEAD_INIT(NULL)
348    0,                         /*ob_size*/
349    "Cinvertor",             /*tp_name*/
350    sizeof(Cinvertor),             /*tp_basicsize*/
351    0,                         /*tp_itemsize*/
352    (destructor)Cinvertor_dealloc, /*tp_dealloc*/
353    0,                         /*tp_print*/
354    0,                         /*tp_getattr*/
355    0,                         /*tp_setattr*/
356    0,                         /*tp_compare*/
357    0,                         /*tp_repr*/
358    0,                         /*tp_as_number*/
359    0,                         /*tp_as_sequence*/
360    0,                         /*tp_as_mapping*/
361    0,                         /*tp_hash */
362    0,                         /*tp_call*/
363    0,                         /*tp_str*/
364    0,                         /*tp_getattro*/
365    0,                         /*tp_setattro*/
366    0,                         /*tp_as_buffer*/
367    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
368    "Cinvertor objects",           /* tp_doc */
369    0,                         /* tp_traverse */
370    0,                         /* tp_clear */
371    0,                         /* tp_richcompare */
372    0,                         /* tp_weaklistoffset */
373    0,                         /* tp_iter */
374    0,                         /* tp_iternext */
375    Cinvertor_methods,             /* tp_methods */
376    Cinvertor_members,             /* tp_members */
377    0,                         /* tp_getset */
378    0,                         /* tp_base */
379    0,                         /* tp_dict */
380    0,                         /* tp_descr_get */
381    0,                         /* tp_descr_set */
382    0,                         /* tp_dictoffset */
383    (initproc)Cinvertor_init,      /* tp_init */
384    0,                         /* tp_alloc */
385    Cinvertor_new,                 /* tp_new */
386};
387
388
389static PyMethodDef module_methods[] = {
390    {NULL} 
391};
392
393/**
394 * Function used to add the model class to a module
395 * @param module: module to add the class to
396 */ 
397void addCinvertor(PyObject *module) {
398        PyObject *d;
399       
400    if (PyType_Ready(&CinvertorType) < 0)
401        return;
402
403    Py_INCREF(&CinvertorType);
404    PyModule_AddObject(module, "Cinvertor", (PyObject *)&CinvertorType);
405   
406    d = PyModule_GetDict(module);
407    CinvertorError = PyErr_NewException("Cinvertor.error", NULL, NULL);
408    PyDict_SetItemString(d, "CinvertorError", CinvertorError);
409}
410
411
412#ifndef PyMODINIT_FUNC  /* declarations for DLL import/export */
413#define PyMODINIT_FUNC void
414#endif
415PyMODINIT_FUNC
416initpr_inversion(void) 
417{
418    PyObject* m;
419
420    m = Py_InitModule3("pr_inversion", module_methods,
421                       "C extension module for inversion to P(r).");
422                       
423    addCinvertor(m);
424}
Note: See TracBrowser for help on using the repository browser.