source: sasview/src/sans/pr/c_extensions/Cinvertor.c @ 64aa49e

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 64aa49e was 5777106, checked in by Mathieu Doucet <doucetm@…>, 11 years ago

Moving things around. Will definitely not build.

  • Property mode set to 100644
File size: 32.0 KB
RevLine 
[896abb3]1/**
2 * C implementation of the P(r) inversion
3 * Cinvertor is the base class for the Invertor class
4 * and provides the underlying computations.
[9a23253e]5 *
[896abb3]6 */
[9e8dc22]7#include <Python.h>
8#include "structmember.h"
9#include <stdio.h>
10#include <stdlib.h>
11#include <math.h>
12#include <time.h>
13
14#include "invertor.h"
15
16
17/// Error object for raised exceptions
[ea59943]18PyObject * CinvertorError;
[9e8dc22]19
20#define INVECTOR(obj,buf,len)                                                                           \
21    do { \
22        int err = PyObject_AsReadBuffer(obj, (const void **)(&buf), &len); \
23        if (err < 0) return NULL; \
24        len /= sizeof(*buf); \
25    } while (0)
[bd30f4a5]26
[9e8dc22]27#define OUTVECTOR(obj,buf,len) \
28    do { \
29        int err = PyObject_AsWriteBuffer(obj, (void **)(&buf), &len); \
30        if (err < 0) return NULL; \
31        len /= sizeof(*buf); \
32    } while (0)
33
34
35// Class definition
[896abb3]36/**
37 * C implementation of the P(r) inversion
38 * Cinvertor is the base class for the Invertor class
39 * and provides the underlying computations.
[9a23253e]40 *
[896abb3]41 */
[9e8dc22]42typedef struct {
[9a23253e]43    PyObject_HEAD
[896abb3]44    /// Internal data structure
[9a23253e]45    Invertor_params params;
[9e8dc22]46} Cinvertor;
47
48
49static void
50Cinvertor_dealloc(Cinvertor* self)
51{
52    invertor_dealloc(&(self->params));
[9a23253e]53
[9e8dc22]54    self->ob_type->tp_free((PyObject*)self);
55
56}
57
58static PyObject *
59Cinvertor_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
60{
61    Cinvertor *self;
[9a23253e]62
[9e8dc22]63    self = (Cinvertor *)type->tp_alloc(type, 0);
[9a23253e]64
[9e8dc22]65    return (PyObject *)self;
66}
67
68static int
69Cinvertor_init(Cinvertor *self, PyObject *args, PyObject *kwds)
70{
[9a23253e]71    if (self != NULL) {
[9e8dc22]72        // Create parameters
73        invertor_init(&(self->params));
74    }
75    return 0;
76}
77
78static PyMemberDef Cinvertor_members[] = {
79    //{"params", T_OBJECT, offsetof(Cinvertor, params), 0,
80    // "Parameters"},
81    {NULL}  /* Sentinel */
82};
83
[9a23253e]84const char set_x_doc[] =
[896abb3]85        "Function to set the x data\n"
86        "Takes an array of doubles as input.\n"
87        " @return: number of entries found";
[9e8dc22]88
89/**
90 * Function to set the x data
91 * Takes an array of doubles as input
92 * Returns the number of entries found
93 */
94static PyObject * set_x(Cinvertor *self, PyObject *args) {
95        PyObject *data_obj;
96        Py_ssize_t ndata;
97        double *data;
[2d06beb]98        int i;
[9a23253e]99
[9e8dc22]100        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
101        OUTVECTOR(data_obj,data,ndata);
[9a23253e]102
[2d06beb]103        free(self->params.x);
104        self->params.x = (double*) malloc(ndata*sizeof(double));
[9a23253e]105
[2d06beb]106        if(self->params.x==NULL) {
[9a23253e]107            PyErr_SetString(CinvertorError,
[2d06beb]108                "Cinvertor.set_x: problem allocating memory.");
[9a23253e]109                return NULL;
[2d06beb]110        }
[9a23253e]111
[2d06beb]112        for (i=0; i<ndata; i++) {
113                self->params.x[i] = data[i];
114        }
[9a23253e]115
[2d06beb]116        //self->params.x = data;
[9e8dc22]117        self->params.npoints = ndata;
[9a23253e]118        return Py_BuildValue("i", self->params.npoints);
[9e8dc22]119}
120
[9a23253e]121const char get_x_doc[] =
[896abb3]122        "Function to get the x data\n"
123        "Takes an array of doubles as input.\n"
124        " @return: number of entries found";
125
[9e8dc22]126static PyObject * get_x(Cinvertor *self, PyObject *args) {
127        PyObject *data_obj;
128        Py_ssize_t ndata;
129        double *data;
130    int i;
[9a23253e]131
[9e8dc22]132        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
[2d06beb]133        OUTVECTOR(data_obj, data, ndata);
[9a23253e]134
[9e8dc22]135        // Check that the input array is large enough
136        if (ndata < self->params.npoints) {
[9a23253e]137            PyErr_SetString(CinvertorError,
[9e8dc22]138                "Cinvertor.get_x: input array too short for data.");
[9a23253e]139                return NULL;
[9e8dc22]140        }
[9a23253e]141
[9e8dc22]142        for(i=0; i<self->params.npoints; i++){
143                data[i] = self->params.x[i];
144        }
[9a23253e]145
146        return Py_BuildValue("i", self->params.npoints);
[9e8dc22]147}
148
[9a23253e]149const char set_y_doc[] =
[896abb3]150        "Function to set the y data\n"
151        "Takes an array of doubles as input.\n"
152        " @return: number of entries found";
153
[9e8dc22]154/**
155 * Function to set the y data
156 * Takes an array of doubles as input
157 * Returns the number of entries found
158 */
159static PyObject * set_y(Cinvertor *self, PyObject *args) {
160        PyObject *data_obj;
161        Py_ssize_t ndata;
162        double *data;
[2d06beb]163        int i;
[9a23253e]164
[9e8dc22]165        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
166        OUTVECTOR(data_obj,data,ndata);
[9a23253e]167
[2d06beb]168        free(self->params.y);
169        self->params.y = (double*) malloc(ndata*sizeof(double));
[9a23253e]170
[2d06beb]171        if(self->params.y==NULL) {
[9a23253e]172            PyErr_SetString(CinvertorError,
[2d06beb]173                "Cinvertor.set_y: problem allocating memory.");
[9a23253e]174                return NULL;
[2d06beb]175        }
[9a23253e]176
[2d06beb]177        for (i=0; i<ndata; i++) {
178                self->params.y[i] = data[i];
[9a23253e]179        }
180
[2d06beb]181        //self->params.y = data;
[9e8dc22]182        self->params.ny = ndata;
[9a23253e]183        return Py_BuildValue("i", self->params.ny);
[9e8dc22]184}
185
[9a23253e]186const char get_y_doc[] =
[896abb3]187        "Function to get the y data\n"
188        "Takes an array of doubles as input.\n"
189        " @return: number of entries found";
190
[9e8dc22]191static PyObject * get_y(Cinvertor *self, PyObject *args) {
192        PyObject *data_obj;
193        Py_ssize_t ndata;
194        double *data;
195    int i;
[9a23253e]196
[9e8dc22]197        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
[2d06beb]198        OUTVECTOR(data_obj, data, ndata);
[9a23253e]199
[9e8dc22]200        // Check that the input array is large enough
201        if (ndata < self->params.ny) {
[9a23253e]202            PyErr_SetString(CinvertorError,
[9e8dc22]203                "Cinvertor.get_y: input array too short for data.");
[9a23253e]204                return NULL;
[9e8dc22]205        }
[9a23253e]206
[9e8dc22]207        for(i=0; i<self->params.ny; i++){
208                data[i] = self->params.y[i];
209        }
[9a23253e]210
211        return Py_BuildValue("i", self->params.npoints);
[9e8dc22]212}
213
[9a23253e]214const char set_err_doc[] =
[896abb3]215        "Function to set the err data\n"
216        "Takes an array of doubles as input.\n"
217        " @return: number of entries found";
218
[9e8dc22]219/**
220 * Function to set the x data
221 * Takes an array of doubles as input
222 * Returns the number of entries found
223 */
224static PyObject * set_err(Cinvertor *self, PyObject *args) {
225        PyObject *data_obj;
226        Py_ssize_t ndata;
227        double *data;
[2d06beb]228        int i;
[9a23253e]229
[9e8dc22]230        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
231        OUTVECTOR(data_obj,data,ndata);
[9a23253e]232
[2d06beb]233        free(self->params.err);
234        self->params.err = (double*) malloc(ndata*sizeof(double));
[9a23253e]235
[2d06beb]236        if(self->params.err==NULL) {
[9a23253e]237            PyErr_SetString(CinvertorError,
[2d06beb]238                "Cinvertor.set_err: problem allocating memory.");
[9a23253e]239                return NULL;
[2d06beb]240        }
[9a23253e]241
[2d06beb]242        for (i=0; i<ndata; i++) {
243                self->params.err[i] = data[i];
244        }
[9a23253e]245
[2d06beb]246        //self->params.err = data;
[9e8dc22]247        self->params.nerr = ndata;
[9a23253e]248        return Py_BuildValue("i", self->params.nerr);
[9e8dc22]249}
250
[9a23253e]251const char get_err_doc[] =
[896abb3]252        "Function to get the err data\n"
253        "Takes an array of doubles as input.\n"
254        " @return: number of entries found";
255
[9e8dc22]256static PyObject * get_err(Cinvertor *self, PyObject *args) {
257        PyObject *data_obj;
258        Py_ssize_t ndata;
259        double *data;
260    int i;
[9a23253e]261
[9e8dc22]262        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
[2d06beb]263        OUTVECTOR(data_obj, data, ndata);
[9a23253e]264
[9e8dc22]265        // Check that the input array is large enough
266        if (ndata < self->params.nerr) {
[9a23253e]267            PyErr_SetString(CinvertorError,
[9e8dc22]268                "Cinvertor.get_err: input array too short for data.");
[9a23253e]269                return NULL;
[9e8dc22]270        }
[9a23253e]271
[9e8dc22]272        for(i=0; i<self->params.nerr; i++){
273                data[i] = self->params.err[i];
274        }
[9a23253e]275
276        return Py_BuildValue("i", self->params.npoints);
[9e8dc22]277}
278
[9a23253e]279const char is_valid_doc[] =
[896abb3]280        "Check the validity of the stored data\n"
281        " @return: Returns the number of points if it's all good, -1 otherwise";
282
[9e8dc22]283/**
284 * Check the validity of the stored data
285 * Returns the number of points if it's all good, -1 otherwise
286 */
287static PyObject * is_valid(Cinvertor *self, PyObject *args) {
288        if(self->params.npoints==self->params.ny &&
289                        self->params.npoints==self->params.nerr) {
290                return Py_BuildValue("i", self->params.npoints);
291        } else {
292                return Py_BuildValue("i", -1);
[9a23253e]293        }
294}
295
296const char set_has_bck_doc[] =
297        "Sets background flag\n";
298
299/**
300 * Sets the maximum distance
301 */
302static PyObject * set_has_bck(Cinvertor *self, PyObject *args) {
303        int has_bck;
304
305        if (!PyArg_ParseTuple(args, "i", &has_bck)) return NULL;
306        self->params.has_bck = has_bck;
307        return Py_BuildValue("i", self->params.has_bck);
[9e8dc22]308}
309
[9a23253e]310const char get_has_bck_doc[] =
311        "Gets background flag\n";
312
313/**
314 * Gets the maximum distance
315 */
316static PyObject * get_has_bck(Cinvertor *self, PyObject *args) {
317        return Py_BuildValue("i", self->params.has_bck);
318}
319
320const char set_dmax_doc[] =
[896abb3]321        "Sets the maximum distance\n";
322
[9e8dc22]323/**
324 * Sets the maximum distance
325 */
326static PyObject * set_dmax(Cinvertor *self, PyObject *args) {
327        double d_max;
[9a23253e]328
[9e8dc22]329        if (!PyArg_ParseTuple(args, "d", &d_max)) return NULL;
330        self->params.d_max = d_max;
[9a23253e]331        return Py_BuildValue("d", self->params.d_max);
[9e8dc22]332}
333
[9a23253e]334const char get_dmax_doc[] =
[896abb3]335        "Gets the maximum distance\n";
336
[9e8dc22]337/**
338 * Gets the maximum distance
339 */
340static PyObject * get_dmax(Cinvertor *self, PyObject *args) {
[9a23253e]341        return Py_BuildValue("d", self->params.d_max);
342}
343
344const char set_slit_height_doc[] =
345        "Sets the slit height in units of q [A-1]\n";
346
347/**
348 * Sets the slit height
349 */
350static PyObject * set_slit_height(Cinvertor *self, PyObject *args) {
351        double slit_height;
352
353        if (!PyArg_ParseTuple(args, "d", &slit_height)) return NULL;
354        self->params.slit_height = slit_height;
355        return Py_BuildValue("d", self->params.slit_height);
[9e8dc22]356}
357
[9a23253e]358const char get_slit_height_doc[] =
359        "Gets the slit height\n";
360
361/**
362 * Gets the slit height
363 */
364static PyObject * get_slit_height(Cinvertor *self, PyObject *args) {
365        return Py_BuildValue("d", self->params.slit_height);
366}
367
368const char set_slit_width_doc[] =
369        "Sets the slit width in units of q [A-1]\n";
370
371/**
372 * Sets the slit width
373 */
374static PyObject * set_slit_width(Cinvertor *self, PyObject *args) {
375        double slit_width;
376
377        if (!PyArg_ParseTuple(args, "d", &slit_width)) return NULL;
378        self->params.slit_width = slit_width;
379        return Py_BuildValue("d", self->params.slit_width);
380}
381
382const char get_slit_width_doc[] =
383        "Gets the slit width\n";
384
385/**
386 * Gets the slit width
387 */
388static PyObject * get_slit_width(Cinvertor *self, PyObject *args) {
389        return Py_BuildValue("d", self->params.slit_width);
390}
391
392
393const char set_qmin_doc[] =
[896abb3]394        "Sets the minimum q\n";
395
[f71287f4]396/**
397 * Sets the minimum q
398 */
399static PyObject * set_qmin(Cinvertor *self, PyObject *args) {
400        double q_min;
[9a23253e]401
[f71287f4]402        if (!PyArg_ParseTuple(args, "d", &q_min)) return NULL;
403        self->params.q_min = q_min;
[9a23253e]404        return Py_BuildValue("d", self->params.q_min);
[f71287f4]405}
406
[9a23253e]407const char get_qmin_doc[] =
[896abb3]408        "Gets the minimum q\n";
409
[f71287f4]410/**
411 * Gets the minimum q
412 */
413static PyObject * get_qmin(Cinvertor *self, PyObject *args) {
[9a23253e]414        return Py_BuildValue("d", self->params.q_min);
[f71287f4]415}
416
[9a23253e]417const char set_qmax_doc[] =
[896abb3]418        "Sets the maximum q\n";
[f71287f4]419
420/**
421 * Sets the maximum q
422 */
423static PyObject * set_qmax(Cinvertor *self, PyObject *args) {
424        double q_max;
[9a23253e]425
[f71287f4]426        if (!PyArg_ParseTuple(args, "d", &q_max)) return NULL;
427        self->params.q_max = q_max;
[9a23253e]428        return Py_BuildValue("d", self->params.q_max);
[f71287f4]429}
430
[9a23253e]431const char get_qmax_doc[] =
[896abb3]432        "Gets the maximum q\n";
433
[f71287f4]434/**
435 * Gets the maximum q
436 */
437static PyObject * get_qmax(Cinvertor *self, PyObject *args) {
[9a23253e]438        return Py_BuildValue("d", self->params.q_max);
[f71287f4]439}
440
[9a23253e]441const char set_alpha_doc[] =
[896abb3]442        "Sets the alpha parameter\n";
[f71287f4]443
[eca05c8]444static PyObject * set_alpha(Cinvertor *self, PyObject *args) {
445        double alpha;
[9a23253e]446
[eca05c8]447        if (!PyArg_ParseTuple(args, "d", &alpha)) return NULL;
448        self->params.alpha = alpha;
[9a23253e]449        return Py_BuildValue("d", self->params.alpha);
[eca05c8]450}
451
[9a23253e]452const char get_alpha_doc[] =
[896abb3]453        "Gets the alpha parameter\n";
454
[eca05c8]455/**
456 * Gets the maximum distance
457 */
458static PyObject * get_alpha(Cinvertor *self, PyObject *args) {
[9a23253e]459        return Py_BuildValue("d", self->params.alpha);
[eca05c8]460}
461
[9a23253e]462const char get_nx_doc[] =
[896abb3]463        "Gets the number of x points\n";
464
[9e8dc22]465/**
466 * Gets the number of x points
467 */
468static PyObject * get_nx(Cinvertor *self, PyObject *args) {
[9a23253e]469        return Py_BuildValue("i", self->params.npoints);
[9e8dc22]470}
471
[9a23253e]472const char get_ny_doc[] =
[896abb3]473        "Gets the number of y points\n";
474
[9e8dc22]475/**
476 * Gets the number of y points
477 */
478static PyObject * get_ny(Cinvertor *self, PyObject *args) {
[9a23253e]479        return Py_BuildValue("i", self->params.ny);
[9e8dc22]480}
481
[9a23253e]482const char get_nerr_doc[] =
[896abb3]483        "Gets the number of err points\n";
484
[9e8dc22]485/**
486 * Gets the number of error points
487 */
488static PyObject * get_nerr(Cinvertor *self, PyObject *args) {
[9a23253e]489        return Py_BuildValue("i", self->params.nerr);
[9e8dc22]490}
491
492
[9a23253e]493const char residuals_doc[] =
[896abb3]494        "Function to call to evaluate the residuals\n"
495        "for P(r) inversion\n"
496        " @param args: input parameters\n"
497        " @return: list of residuals";
498
[9e8dc22]499/**
500 * Function to call to evaluate the residuals
[eca05c8]501 * @param args: input parameters
502 * @return: list of residuals
[9e8dc22]503 */
504static PyObject * residuals(Cinvertor *self, PyObject *args) {
505        double *pars;
506        PyObject* residuals;
507        int i;
508        double residual, diff;
509        // Regularization factor
[eca05c8]510        double regterm = 0.0;
511        double tmp = 0.0;
[abad620]512        // Number of slices in regularization term estimate
513        int nslice = 25;
[9a23253e]514
[9e8dc22]515        PyObject *data_obj;
516        Py_ssize_t npars;
[9a23253e]517
[9e8dc22]518        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
[9a23253e]519
[9e8dc22]520        OUTVECTOR(data_obj,pars,npars);
[9a23253e]521
[9e8dc22]522    // PyList of residuals
523        // Should create this list only once and refill it
524    residuals = PyList_New(self->params.npoints);
[eca05c8]525
[abad620]526    regterm = reg_term(pars, self->params.d_max, npars, nslice);
[9a23253e]527
[9e8dc22]528    for(i=0; i<self->params.npoints; i++) {
529        diff = self->params.y[i] - iq(pars, self->params.d_max, npars, self->params.x[i]);
530        residual = diff*diff / (self->params.err[i]*self->params.err[i]);
[eca05c8]531        tmp = residual;
[9a23253e]532
[eca05c8]533        // regularization term
534        residual += self->params.alpha * regterm;
[9a23253e]535
[eca05c8]536        if (PyList_SetItem(residuals, i, Py_BuildValue("d",residual) ) < 0){
[9a23253e]537            PyErr_SetString(CinvertorError,
[eca05c8]538                "Cinvertor.residuals: error setting residual.");
539                return NULL;
540        };
[9a23253e]541
[eca05c8]542    }
[9a23253e]543
[eca05c8]544        return residuals;
545}
[896abb3]546
[9a23253e]547const char pr_residuals_doc[] =
[896abb3]548        "Function to call to evaluate the residuals\n"
549        "for P(r) minimization (for testing purposes)\n"
550        " @param args: input parameters\n"
551        " @return: list of residuals";
552
[eca05c8]553/**
554 * Function to call to evaluate the residuals
555 * for P(r) minimization (for testing purposes)
556 * @param args: input parameters
557 * @return: list of residuals
558 */
559static PyObject * pr_residuals(Cinvertor *self, PyObject *args) {
560        double *pars;
561        PyObject* residuals;
562        int i;
563        double residual, diff;
564        // Regularization factor
565        double regterm = 0.0;
566        double tmp = 0.0;
[abad620]567        // Number of slices in regularization term estimate
568        int nslice = 25;
[9a23253e]569
[eca05c8]570        PyObject *data_obj;
571        Py_ssize_t npars;
[9a23253e]572
[eca05c8]573        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
[9a23253e]574
[eca05c8]575        OUTVECTOR(data_obj,pars,npars);
[9a23253e]576
[eca05c8]577        // Should create this list only once and refill it
578    residuals = PyList_New(self->params.npoints);
579
[abad620]580    regterm = reg_term(pars, self->params.d_max, npars, nslice);
[eca05c8]581
[9a23253e]582
[eca05c8]583    for(i=0; i<self->params.npoints; i++) {
584        diff = self->params.y[i] - pr(pars, self->params.d_max, npars, self->params.x[i]);
585        residual = diff*diff / (self->params.err[i]*self->params.err[i]);
586        tmp = residual;
[9a23253e]587
[eca05c8]588        // regularization term
589        residual += self->params.alpha * regterm;
[9a23253e]590
[9e8dc22]591        if (PyList_SetItem(residuals, i, Py_BuildValue("d",residual) ) < 0){
[9a23253e]592            PyErr_SetString(CinvertorError,
[9e8dc22]593                "Cinvertor.residuals: error setting residual.");
594                return NULL;
595        };
[9a23253e]596
[9e8dc22]597    }
[9a23253e]598
[9e8dc22]599        return residuals;
600}
601
[9a23253e]602const char get_iq_doc[] =
[896abb3]603        "Function to call to evaluate the scattering intensity\n"
604        " @param args: c-parameters, and q\n"
605        " @return: I(q)";
606
[9e8dc22]607/**
608 * Function to call to evaluate the scattering intensity
609 * @param args: c-parameters, and q
610 * @return: I(q)
611 */
612static PyObject * get_iq(Cinvertor *self, PyObject *args) {
613        double *pars;
614        double q, iq_value;
615        PyObject *data_obj;
616        Py_ssize_t npars;
[9a23253e]617
[9e8dc22]618        if (!PyArg_ParseTuple(args, "Od", &data_obj, &q)) return NULL;
619        OUTVECTOR(data_obj,pars,npars);
[9a23253e]620
[9e8dc22]621        iq_value = iq(pars, self->params.d_max, npars, q);
[9a23253e]622        return Py_BuildValue("f", iq_value);
[9e8dc22]623}
624
[f168d02]625const char get_iq_smeared_doc[] =
626        "Function to call to evaluate the scattering intensity.\n"
627        "The scattering intensity is slit-smeared."
628        " @param args: c-parameters, and q\n"
629        " @return: I(q)";
630
631/**
632 * Function to call to evaluate the scattering intensity
633 * The scattering intensity is slit-smeared.
634 * @param args: c-parameters, and q
635 * @return: I(q)
636 */
637static PyObject * get_iq_smeared(Cinvertor *self, PyObject *args) {
638        double *pars;
639        double q, iq_value;
640        PyObject *data_obj;
641        Py_ssize_t npars;
642
643        if (!PyArg_ParseTuple(args, "Od", &data_obj, &q)) return NULL;
644        OUTVECTOR(data_obj,pars,npars);
645
646        iq_value = iq_smeared(pars, self->params.d_max, npars,
647                                                        self->params.slit_height, self->params.slit_width,
648                                                        q, 21);
649        return Py_BuildValue("f", iq_value);
650}
651
[9a23253e]652const char get_pr_doc[] =
[896abb3]653        "Function to call to evaluate P(r)\n"
654        " @param args: c-parameters and r\n"
655        " @return: P(r)";
656
[9e8dc22]657/**
658 * Function to call to evaluate P(r)
659 * @param args: c-parameters and r
660 * @return: P(r)
661 */
662static PyObject * get_pr(Cinvertor *self, PyObject *args) {
663        double *pars;
664        double r, pr_value;
665        PyObject *data_obj;
666        Py_ssize_t npars;
[9a23253e]667
[9e8dc22]668        if (!PyArg_ParseTuple(args, "Od", &data_obj, &r)) return NULL;
669        OUTVECTOR(data_obj,pars,npars);
[9a23253e]670
[9e8dc22]671        pr_value = pr(pars, self->params.d_max, npars, r);
[9a23253e]672        return Py_BuildValue("f", pr_value);
[9e8dc22]673}
674
[9a23253e]675const char get_pr_err_doc[] =
[896abb3]676        "Function to call to evaluate P(r) with errors\n"
677        " @param args: c-parameters and r\n"
678        " @return: (P(r),dP(r))";
679
[eca05c8]680/**
681 * Function to call to evaluate P(r) with errors
682 * @param args: c-parameters and r
683 * @return: P(r)
684 */
685static PyObject * get_pr_err(Cinvertor *self, PyObject *args) {
686        double *pars;
687        double *pars_err;
688        double pr_err_value;
689        double r, pr_value;
690        PyObject *data_obj;
691        Py_ssize_t npars;
692        PyObject *err_obj;
693        Py_ssize_t npars2;
[9a23253e]694
[eca05c8]695        if (!PyArg_ParseTuple(args, "OOd", &data_obj, &err_obj, &r)) return NULL;
[9a23253e]696        OUTVECTOR(data_obj,pars,npars);
[43c0a8e]697
[007f9b3]698        if (err_obj == Py_None) {
699                pr_value = pr(pars, self->params.d_max, npars, r);
700                pr_err_value = 0.0;
701        } else {
702                OUTVECTOR(err_obj,pars_err,npars2);
703                pr_err(pars, pars_err, self->params.d_max, npars, r, &pr_value, &pr_err_value);
704        }
[9a23253e]705        return Py_BuildValue("ff", pr_value, pr_err_value);
[eca05c8]706}
707
[9a23253e]708const char basefunc_ft_doc[] =
[896abb3]709        "Returns the value of the nth Fourier transofrmed base function\n"
710        " @param args: c-parameters, n and q\n"
711        " @return: nth Fourier transformed base function, evaluated at q";
712
[2d06beb]713static PyObject * basefunc_ft(Cinvertor *self, PyObject *args) {
714        double d_max, q;
715        int n;
[9a23253e]716
[2d06beb]717        if (!PyArg_ParseTuple(args, "did", &d_max, &n, &q)) return NULL;
[9a23253e]718        return Py_BuildValue("f", ortho_transformed(d_max, n, q));
719
[2d06beb]720}
[9e8dc22]721
[9a23253e]722const char oscillations_doc[] =
[896abb3]723        "Returns the value of the oscillation figure of merit for\n"
724        "the given set of coefficients. For a sphere, the oscillation\n"
725        "figure of merit is 1.1.\n"
726        " @param args: c-parameters\n"
727        " @return: oscillation figure of merit";
728
[abad620]729static PyObject * oscillations(Cinvertor *self, PyObject *args) {
730        double *pars;
731        PyObject *data_obj;
732        Py_ssize_t npars;
733        double oscill, norm;
[9a23253e]734
[abad620]735        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
736        OUTVECTOR(data_obj,pars,npars);
[9a23253e]737
[abad620]738        oscill = reg_term(pars, self->params.d_max, npars, 100);
739        norm   = int_p2(pars, self->params.d_max, npars, 100);
[9a23253e]740        return Py_BuildValue("f", sqrt(oscill/norm)/acos(-1.0)*self->params.d_max );
741
[abad620]742}
743
[9a23253e]744const char get_peaks_doc[] =
[896abb3]745        "Returns the number of peaks in the output P(r) distrubution\n"
746        "for the given set of coefficients.\n"
747        " @param args: c-parameters\n"
748        " @return: number of P(r) peaks";
749
[4f63160]750static PyObject * get_peaks(Cinvertor *self, PyObject *args) {
751        double *pars;
752        PyObject *data_obj;
753        Py_ssize_t npars;
754        int count;
[9a23253e]755
[4f63160]756        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
757        OUTVECTOR(data_obj,pars,npars);
[9a23253e]758
[4f63160]759        count = npeaks(pars, self->params.d_max, npars, 100);
760
[9a23253e]761        return Py_BuildValue("i", count );
762
[4f63160]763}
764
[9a23253e]765const char get_positive_doc[] =
[896abb3]766        "Returns the fraction of P(r) that is positive over\n"
767        "the full range of r for the given set of coefficients.\n"
768        " @param args: c-parameters\n"
769        " @return: fraction of P(r) that is positive";
770
[43c0a8e]771static PyObject * get_positive(Cinvertor *self, PyObject *args) {
772        double *pars;
773        PyObject *data_obj;
774        Py_ssize_t npars;
775        double fraction;
[9a23253e]776
[43c0a8e]777        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
778        OUTVECTOR(data_obj,pars,npars);
[9a23253e]779
[43c0a8e]780        fraction = positive_integral(pars, self->params.d_max, npars, 100);
781
[9a23253e]782        return Py_BuildValue("f", fraction );
783
[43c0a8e]784}
785
[9a23253e]786const char get_pos_err_doc[] =
[896abb3]787        "Returns the fraction of P(r) that is 1 standard deviation\n"
788        "above zero over the full range of r for the given set of coefficients.\n"
789        " @param args: c-parameters\n"
790        " @return: fraction of P(r) that is positive";
791
[43c0a8e]792static PyObject * get_pos_err(Cinvertor *self, PyObject *args) {
793        double *pars;
794        double *pars_err;
795        PyObject *data_obj;
796        PyObject *err_obj;
797        Py_ssize_t npars;
798        Py_ssize_t npars2;
799        double fraction;
[9a23253e]800
[43c0a8e]801        if (!PyArg_ParseTuple(args, "OO", &data_obj, &err_obj)) return NULL;
[9a23253e]802        OUTVECTOR(data_obj,pars,npars);
[43c0a8e]803        OUTVECTOR(err_obj,pars_err,npars2);
[9a23253e]804
[43c0a8e]805        fraction = positive_errors(pars, pars_err, self->params.d_max, npars, 51);
806
[9a23253e]807        return Py_BuildValue("f", fraction );
808
809}
810
811const char get_rg_doc[] =
812        "Returns the value of the radius of gyration Rg.\n"
813        " @param args: c-parameters\n"
814        " @return: Rg";
815
816static PyObject * get_rg(Cinvertor *self, PyObject *args) {
817        double *pars;
818        PyObject *data_obj;
819        Py_ssize_t npars;
820        double value;
821
822        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
823        OUTVECTOR(data_obj,pars,npars);
824
825        value = rg(pars, self->params.d_max, npars, 101);
826
827        return Py_BuildValue("f", value );
828
[43c0a8e]829}
830
[9a23253e]831const char get_iq0_doc[] =
832        "Returns the value of I(q=0).\n"
833        " @param args: c-parameters\n"
834        " @return: I(q=0)";
835
836static PyObject * get_iq0(Cinvertor *self, PyObject *args) {
837        double *pars;
838        PyObject *data_obj;
839        Py_ssize_t npars;
840        double value;
841
842        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
843        OUTVECTOR(data_obj,pars,npars);
844
845        value = 4.0*acos(-1.0)*int_pr(pars, self->params.d_max, npars, 101);
846
847        return Py_BuildValue("f", value );
848
849}
850
851/**
852 * Check whether a q-value is within acceptabel limits
853 * Return 1 if accepted, 0 if rejected.
854 */
855int accept_q(Cinvertor *self, double q) {
856    if (self->params.q_min>0 && q<self->params.q_min) return 0;
857    if (self->params.q_max>0 && q>self->params.q_max) return 0;
858    return 1;
859}
860
861const char get_matrix_doc[] =
862        "Returns A matrix and b vector for least square problem.\n"
863        " @param nfunc: number of base functions\n"
864        " @param nr: number of r-points used when evaluating reg term.\n"
865        " @param a: A array to fill\n"
866        " @param b: b vector to fill\n"
867        " @return: 0";
868
869static PyObject * get_matrix(Cinvertor *self, PyObject *args) {
870        double *a;
871        double *b;
872        PyObject *a_obj;
873        PyObject *b_obj;
874        Py_ssize_t n_a;
875        Py_ssize_t n_b;
876        // Number of bins for regularization term evaluation
877        int nr, nfunc;
878        int i, j, i_r;
879        double r, sqrt_alpha, pi;
880        double tmp;
881        int offset;
882
883        if (!PyArg_ParseTuple(args, "iiOO", &nfunc, &nr, &a_obj, &b_obj)) return NULL;
884        OUTVECTOR(a_obj,a,n_a);
885        OUTVECTOR(b_obj,b,n_b);
886
887        assert(n_b>=nfunc);
[bd30f4a5]888        assert(n_a>=nfunc*(nr+self->params.npoints));
[9a23253e]889
890        sqrt_alpha = sqrt(self->params.alpha);
891        pi = acos(-1.0);
892        offset = (self->params.has_bck==1) ? 0 : 1;
893
894    for (j=0; j<nfunc; j++) {
895        for (i=0; i<self->params.npoints; i++) {
[ea59943]896            if (self->params.err[i]==0.0) {
897              PyErr_SetString(CinvertorError,
898                "Cinvertor.get_matrix: Some I(Q) points have no error.");
899              return NULL;
900            }
[9a23253e]901            if (accept_q(self, self->params.x[i])){
902                if (self->params.has_bck==1 && j==0) {
903                    a[i*nfunc+j] = 1.0/self->params.err[i];
904                } else {
[f168d02]905                        if (self->params.slit_width>0 || self->params.slit_height>0) {
906                                a[i*nfunc+j] = ortho_transformed_smeared(self->params.d_max,
907                                                j+offset, self->params.slit_height, self->params.slit_width,
908                                                self->params.x[i], 21)/self->params.err[i];
909                        } else {
910                                a[i*nfunc+j] = ortho_transformed(self->params.d_max, j+offset, self->params.x[i])/self->params.err[i];
911                        }
[9a23253e]912                }
913            }
914        }
915        for (i_r=0; i_r<nr; i_r++){
916            if (self->params.has_bck==1 && j==0) {
917                a[(i_r+self->params.npoints)*nfunc+j] = 0.0;
918            } else {
919                    r = self->params.d_max/nr*i_r;
920                    tmp = pi*(j+offset)/self->params.d_max;
921                    a[(i_r+self->params.npoints)*nfunc+j] = sqrt_alpha * 1.0/nr*self->params.d_max*2.0*
922                    (2.0*pi*(j+offset)/self->params.d_max*cos(pi*(j+offset)*r/self->params.d_max) +
923                    tmp*tmp*r * sin(pi*(j+offset)*r/self->params.d_max));
924                }
925        }
926    }
927
928    for (i=0; i<self->params.npoints; i++) {
929        if (accept_q(self, self->params.x[i])){
930            b[i] = self->params.y[i]/self->params.err[i];
931         }
932        }
933
934        return Py_BuildValue("i", 0);
935
936}
937
938const char get_invcov_matrix_doc[] =
939        " Compute the inverse covariance matrix, defined as inv_cov = a_transposed x a.\n"
940        " @param nfunc: number of base functions\n"
941        " @param nr: number of r-points used when evaluating reg term.\n"
942        " @param a: A array to fill\n"
943        " @param inv_cov: inverse covariance array to be filled\n"
944        " @return: 0";
945
946static PyObject * get_invcov_matrix(Cinvertor *self, PyObject *args) {
947        double *a;
948        PyObject *a_obj;
949        Py_ssize_t n_a;
950        double *inv_cov;
951        PyObject *cov_obj;
952        Py_ssize_t n_cov;
953        int nr, nfunc;
954        int i, j, k;
955
956        if (!PyArg_ParseTuple(args, "iiOO", &nfunc, &nr, &a_obj, &cov_obj)) return NULL;
957        OUTVECTOR(a_obj,a,n_a);
958        OUTVECTOR(cov_obj,inv_cov,n_cov);
959
960        assert(n_cov>=nfunc*nfunc);
961        assert(n_a>=nfunc*(nr+self->params.npoints));
962
963        for (i=0; i<nfunc; i++) {
964                for (j=0; j<nfunc; j++) {
965                        inv_cov[i*nfunc+j] = 0.0;
966                        for (k=0; k<nr+self->params.npoints; k++) {
967                                inv_cov[i*nfunc+j] += a[k*nfunc+i]*a[k*nfunc+j];
968                        }
969                }
970        }
971        return Py_BuildValue("i", 0);
972}
973
974const char get_reg_size_doc[] =
975        " Compute the covariance matrix, defined as inv_cov = a_transposed x a.\n"
976        " @param nfunc: number of base functions\n"
977        " @param nr: number of r-points used when evaluating reg term.\n"
978        " @param a: A array to fill\n"
979        " @param inv_cov: inverse covariance array to be filled\n"
980        " @return: 0";
981
982static PyObject * get_reg_size(Cinvertor *self, PyObject *args) {
983        double *a;
984        PyObject *a_obj;
985        Py_ssize_t n_a;
986        int nr, nfunc;
987        int i, j;
988        double sum_sig, sum_reg;
989
990        if (!PyArg_ParseTuple(args, "iiO", &nfunc, &nr, &a_obj)) return NULL;
991        OUTVECTOR(a_obj,a,n_a);
992
993        assert(n_a>=nfunc*(nr+self->params.npoints));
994
995    sum_sig = 0.0;
996    sum_reg = 0.0;
997    for (j=0; j<nfunc; j++){
998        for (i=0; i<self->params.npoints; i++){
999            if (accept_q(self, self->params.x[i])==1)
1000                sum_sig += (a[i*nfunc+j])*(a[i*nfunc+j]);
1001        }
1002        for (i=0; i<nr; i++){
1003            sum_reg += (a[(i+self->params.npoints)*nfunc+j])*(a[(i+self->params.npoints)*nfunc+j]);
1004        }
1005    }
1006    return Py_BuildValue("ff", sum_sig, sum_reg);
1007}
[896abb3]1008
1009const char eeeget_qmin_doc[] = "\
1010This is a multiline doc string.\n\
1011\n\
1012This is the second line.";
[9a23253e]1013const char eeeset_qmin_doc[] =
[896abb3]1014        "This is a multiline doc string.\n"
1015        "\n"
1016        "This is the second line.";
1017
[9e8dc22]1018static PyMethodDef Cinvertor_methods[] = {
[896abb3]1019                   {"residuals", (PyCFunction)residuals, METH_VARARGS, residuals_doc},
1020                   {"pr_residuals", (PyCFunction)pr_residuals, METH_VARARGS, pr_residuals_doc},
1021                   {"set_x", (PyCFunction)set_x, METH_VARARGS, set_x_doc},
1022                   {"get_x", (PyCFunction)get_x, METH_VARARGS, get_x_doc},
1023                   {"set_y", (PyCFunction)set_y, METH_VARARGS, set_y_doc},
1024                   {"get_y", (PyCFunction)get_y, METH_VARARGS, get_y_doc},
1025                   {"set_err", (PyCFunction)set_err, METH_VARARGS, set_err_doc},
1026                   {"get_err", (PyCFunction)get_err, METH_VARARGS, get_err_doc},
1027                   {"set_dmax", (PyCFunction)set_dmax, METH_VARARGS, set_dmax_doc},
1028                   {"get_dmax", (PyCFunction)get_dmax, METH_VARARGS, get_dmax_doc},
1029                   {"set_qmin", (PyCFunction)set_qmin, METH_VARARGS, set_qmin_doc},
1030                   {"get_qmin", (PyCFunction)get_qmin, METH_VARARGS, get_qmin_doc},
1031                   {"set_qmax", (PyCFunction)set_qmax, METH_VARARGS, set_qmax_doc},
1032                   {"get_qmax", (PyCFunction)get_qmax, METH_VARARGS, get_qmax_doc},
1033                   {"set_alpha", (PyCFunction)set_alpha, METH_VARARGS, set_alpha_doc},
1034                   {"get_alpha", (PyCFunction)get_alpha, METH_VARARGS, get_alpha_doc},
[9a23253e]1035                   {"set_slit_width", (PyCFunction)set_slit_width, METH_VARARGS, set_slit_width_doc},
1036                   {"get_slit_width", (PyCFunction)get_slit_width, METH_VARARGS, get_slit_width_doc},
1037                   {"set_slit_height", (PyCFunction)set_slit_height, METH_VARARGS, set_slit_height_doc},
1038                   {"get_slit_height", (PyCFunction)get_slit_height, METH_VARARGS, get_slit_height_doc},
1039                   {"set_has_bck", (PyCFunction)set_has_bck, METH_VARARGS, set_has_bck_doc},
1040                   {"get_has_bck", (PyCFunction)get_has_bck, METH_VARARGS, get_has_bck_doc},
[896abb3]1041                   {"get_nx", (PyCFunction)get_nx, METH_VARARGS, get_nx_doc},
1042                   {"get_ny", (PyCFunction)get_ny, METH_VARARGS, get_ny_doc},
1043                   {"get_nerr", (PyCFunction)get_nerr, METH_VARARGS, get_nerr_doc},
1044                   {"iq", (PyCFunction)get_iq, METH_VARARGS, get_iq_doc},
[f168d02]1045                   {"iq_smeared", (PyCFunction)get_iq_smeared, METH_VARARGS, get_iq_smeared_doc},
[896abb3]1046                   {"pr", (PyCFunction)get_pr, METH_VARARGS, get_pr_doc},
1047                   {"get_pr_err", (PyCFunction)get_pr_err, METH_VARARGS, get_pr_err_doc},
1048                   {"is_valid", (PyCFunction)is_valid, METH_VARARGS, is_valid_doc},
1049                   {"basefunc_ft", (PyCFunction)basefunc_ft, METH_VARARGS, basefunc_ft_doc},
1050                   {"oscillations", (PyCFunction)oscillations, METH_VARARGS, oscillations_doc},
1051                   {"get_peaks", (PyCFunction)get_peaks, METH_VARARGS, get_peaks_doc},
1052                   {"get_positive", (PyCFunction)get_positive, METH_VARARGS, get_positive_doc},
1053                   {"get_pos_err", (PyCFunction)get_pos_err, METH_VARARGS, get_pos_err_doc},
[9a23253e]1054                   {"rg", (PyCFunction)get_rg, METH_VARARGS, get_rg_doc},
1055                   {"iq0", (PyCFunction)get_iq0, METH_VARARGS, get_iq0_doc},
1056                   {"_get_matrix", (PyCFunction)get_matrix, METH_VARARGS, get_matrix_doc},
1057                   {"_get_invcov_matrix", (PyCFunction)get_invcov_matrix, METH_VARARGS, get_invcov_matrix_doc},
1058                   {"_get_reg_size", (PyCFunction)get_reg_size, METH_VARARGS, get_reg_size_doc},
1059
[9e8dc22]1060   {NULL}
1061};
1062
1063static PyTypeObject CinvertorType = {
1064    PyObject_HEAD_INIT(NULL)
1065    0,                         /*ob_size*/
1066    "Cinvertor",             /*tp_name*/
1067    sizeof(Cinvertor),             /*tp_basicsize*/
1068    0,                         /*tp_itemsize*/
1069    (destructor)Cinvertor_dealloc, /*tp_dealloc*/
1070    0,                         /*tp_print*/
1071    0,                         /*tp_getattr*/
1072    0,                         /*tp_setattr*/
1073    0,                         /*tp_compare*/
1074    0,                         /*tp_repr*/
1075    0,                         /*tp_as_number*/
1076    0,                         /*tp_as_sequence*/
1077    0,                         /*tp_as_mapping*/
1078    0,                         /*tp_hash */
1079    0,                         /*tp_call*/
1080    0,                         /*tp_str*/
1081    0,                         /*tp_getattro*/
1082    0,                         /*tp_setattro*/
1083    0,                         /*tp_as_buffer*/
1084    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1085    "Cinvertor objects",           /* tp_doc */
1086    0,                         /* tp_traverse */
1087    0,                         /* tp_clear */
1088    0,                         /* tp_richcompare */
1089    0,                         /* tp_weaklistoffset */
1090    0,                         /* tp_iter */
1091    0,                         /* tp_iternext */
1092    Cinvertor_methods,             /* tp_methods */
1093    Cinvertor_members,             /* tp_members */
1094    0,                         /* tp_getset */
1095    0,                         /* tp_base */
1096    0,                         /* tp_dict */
1097    0,                         /* tp_descr_get */
1098    0,                         /* tp_descr_set */
1099    0,                         /* tp_dictoffset */
1100    (initproc)Cinvertor_init,      /* tp_init */
1101    0,                         /* tp_alloc */
1102    Cinvertor_new,                 /* tp_new */
1103};
1104
1105
1106static PyMethodDef module_methods[] = {
[9a23253e]1107    {NULL}
[9e8dc22]1108};
1109
1110/**
1111 * Function used to add the model class to a module
1112 * @param module: module to add the class to
[9a23253e]1113 */
[9e8dc22]1114void addCinvertor(PyObject *module) {
1115        PyObject *d;
[9a23253e]1116
[9e8dc22]1117    if (PyType_Ready(&CinvertorType) < 0)
1118        return;
1119
1120    Py_INCREF(&CinvertorType);
1121    PyModule_AddObject(module, "Cinvertor", (PyObject *)&CinvertorType);
[9a23253e]1122
[9e8dc22]1123    d = PyModule_GetDict(module);
[ea59943]1124    CinvertorError = PyErr_NewException("sans.pr.invertor.Cinvertor.InvertorError", PyExc_RuntimeError, NULL);
[9e8dc22]1125    PyDict_SetItemString(d, "CinvertorError", CinvertorError);
1126}
1127
1128
1129#ifndef PyMODINIT_FUNC  /* declarations for DLL import/export */
1130#define PyMODINIT_FUNC void
1131#endif
1132PyMODINIT_FUNC
[9a23253e]1133initpr_inversion(void)
[9e8dc22]1134{
1135    PyObject* m;
1136
1137    m = Py_InitModule3("pr_inversion", module_methods,
1138                       "C extension module for inversion to P(r).");
[9a23253e]1139
[9e8dc22]1140    addCinvertor(m);
1141}
Note: See TracBrowser for help on using the repository browser.