source: sasview/sansmodels/src/sans/models/c_models/CCylinder_bck.cpp @ eba9885

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 eba9885 was 0f5bc9f, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

Update of all C models to the new style of C++ models

  • Property mode set to 100644
File size: 14.9 KB
Line 
1/**
2        This software was developed by the University of Tennessee as part of the
3        Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
4        project funded by the US National Science Foundation.
5
6        If you use DANSE applications to do scientific research that leads to
7        publication, we ask that you acknowledge the use of the software with the
8        following sentence:
9
10        "This work benefited from DANSE software developed under NSF award DMR-0520547."
11
12        copyright 2008, University of Tennessee
13 */
14
15/** CCylinderModel
16 *
17 * Base python class for cylinder model
18 *
19 */
20extern "C" {
21#include <Python.h>
22#include "structmember.h"
23#include <stdio.h>
24#include <stdlib.h>
25#include <math.h>
26#include <time.h>
27#include "cylinder.h"
28}
29
30
31#include "models.hh"
32#include "dispersion_visitor.hh"
33
34/// Error object for raised exceptions
35static PyObject * CCylinderModelError = NULL;
36
37
38// Class definition
39typedef struct {
40    PyObject_HEAD
41    /// Parameters
42    PyObject * params;
43    PyObject * dispersion;
44    CylinderModel * model;
45    /// Log for unit testing
46    PyObject * log;
47} CCylinderModel;
48
49
50static void
51CCylinderModel_dealloc(CCylinderModel* self)
52{
53    self->ob_type->tp_free((PyObject*)self);
54
55
56}
57
58static PyObject *
59CCylinderModel_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
60{
61    CCylinderModel *self;
62
63    self = (CCylinderModel *)type->tp_alloc(type, 0);
64
65    return (PyObject *)self;
66}
67
68static int
69CCylinderModel_init(CCylinderModel *self, PyObject *args, PyObject *kwds)
70{
71    if (self != NULL) {
72        printf("Hello cylinder\n");
73        // Create parameters
74        self->params = PyDict_New();
75        self->dispersion = PyDict_New();
76        self->model = new CylinderModel();
77
78        // Initialize parameter dictionary
79        PyDict_SetItemString(self->params,"scale",     Py_BuildValue("d", self->model->scale()));
80        PyDict_SetItemString(self->params,"length",    Py_BuildValue("d", self->model->length()));
81        PyDict_SetItemString(self->params,"cyl_theta", Py_BuildValue("d", self->model->cyl_theta()));
82        PyDict_SetItemString(self->params,"background",Py_BuildValue("d", self->model->background()));
83        PyDict_SetItemString(self->params,"radius",    Py_BuildValue("d", self->model->radius()));
84        PyDict_SetItemString(self->params,"contrast",  Py_BuildValue("d", self->model->contrast()));
85        PyDict_SetItemString(self->params,"cyl_phi",   Py_BuildValue("d", self->model->cyl_phi()));
86
87        // Initialize dispersion / averaging parameter dict
88        DispersionVisitor* visitor = new DispersionVisitor();
89        PyObject * disp_dict = PyDict_New();
90        self->model->radius.dispersion->accept_as_source(visitor, self->model->radius.dispersion, disp_dict);
91        PyDict_SetItemString(self->dispersion, "radius", disp_dict);
92
93        disp_dict = PyDict_New();
94        self->model->length.dispersion->accept_as_source(visitor, self->model->length.dispersion, disp_dict);
95        PyDict_SetItemString(self->dispersion, "length", disp_dict);
96
97        disp_dict = PyDict_New();
98        self->model->cyl_phi.dispersion->accept_as_source(visitor, self->model->cyl_phi.dispersion, disp_dict);
99        PyDict_SetItemString(self->dispersion, "cyl_phi", disp_dict);
100
101        disp_dict = PyDict_New();
102        self->model->cyl_theta.dispersion->accept_as_source(visitor, self->model->cyl_theta.dispersion, disp_dict);
103        PyDict_SetItemString(self->dispersion, "cyl_theta", disp_dict);
104
105        // Create empty log
106        self->log = PyDict_New();
107
108    }
109    return 0;
110}
111
112static PyMemberDef CCylinderModel_members[] = {
113        {"params", T_OBJECT, offsetof(CCylinderModel, params), 0,
114         "Parameters"},
115        {"dispersion", T_OBJECT, offsetof(CCylinderModel, dispersion), 0,
116          "Dispersion parameters"},
117    {"log", T_OBJECT, offsetof(CCylinderModel, log), 0,
118     "Log"},
119    {NULL}  /* Sentinel */
120};
121
122/** Read double from PyObject
123    @param p PyObject
124    @return double
125*/
126double CCylinderModel_readDouble(PyObject *p) {
127    if (PyFloat_Check(p)==1) {
128        return (double)(((PyFloatObject *)(p))->ob_fval);
129    } else if (PyInt_Check(p)==1) {
130        return (double)(((PyIntObject *)(p))->ob_ival);
131    } else if (PyLong_Check(p)==1) {
132        return (double)PyLong_AsLong(p);
133    } else {
134        return 0.0;
135    }
136}
137
138/**
139 * Method to set the dispersion model for a parameter.
140 * We need to update the dispersion object of the parameter
141 * on the C++ side and update the dispersion dictionary on the python side.
142 *
143 * TODO: define read-only integers that will be data members of this
144 * class and allow the user to specify which model is needed with a code name.
145 *
146 * This method should take in a code name (FLAT, GAUSSIAN) and a string
147 * that represent the parameter to attach the dispersion model to.
148 *
149 */
150static PyObject * set_dispersion_model(CCylinderModel *self, PyObject *args) {
151
152}
153
154/**
155 * Function to call to evaluate model
156 * @param args: input q or [q,phi]
157 * @return: function value
158 */
159static PyObject * run(CCylinderModel *self, PyObject *args) {
160        double q_value, phi_value;
161        PyObject* pars;
162        int npars;
163
164        // Get parameters
165
166        // Reader parameter dictionary
167    self->model->scale = PyFloat_AsDouble( PyDict_GetItemString(self->params, "scale") );
168    self->model->length = PyFloat_AsDouble( PyDict_GetItemString(self->params, "length") );
169    self->model->cyl_theta = PyFloat_AsDouble( PyDict_GetItemString(self->params, "cyl_theta") );
170    self->model->background = PyFloat_AsDouble( PyDict_GetItemString(self->params, "background") );
171    self->model->radius = PyFloat_AsDouble( PyDict_GetItemString(self->params, "radius") );
172    self->model->contrast = PyFloat_AsDouble( PyDict_GetItemString(self->params, "contrast") );
173    self->model->cyl_phi = PyFloat_AsDouble( PyDict_GetItemString(self->params, "cyl_phi") );
174
175    // Read in dispersion parameters
176    PyObject* disp_dict;
177
178    DispersionVisitor* visitor = new DispersionVisitor();
179    disp_dict = PyDict_GetItemString(self->dispersion, "radius");
180    self->model->radius.dispersion->accept_as_destination(visitor, self->model->radius.dispersion, disp_dict);
181
182    disp_dict = PyDict_GetItemString(self->dispersion, "length");
183    self->model->length.dispersion->accept_as_destination(visitor, self->model->length.dispersion, disp_dict);
184
185    disp_dict = PyDict_GetItemString(self->dispersion, "cyl_theta");
186    self->model->cyl_theta.dispersion->accept_as_destination(visitor, self->model->cyl_theta.dispersion, disp_dict);
187
188    disp_dict = PyDict_GetItemString(self->dispersion, "cyl_phi");
189    self->model->cyl_phi.dispersion->accept_as_destination(visitor, self->model->cyl_phi.dispersion, disp_dict);
190
191
192        // Get input and determine whether we have to supply a 1D or 2D return value.
193        if ( !PyArg_ParseTuple(args,"O",&pars) ) {
194            PyErr_SetString(CCylinderModelError,
195                "CCylinderModel.run expects a q value.");
196                return NULL;
197        }
198
199        // Check params
200        if( PyList_Check(pars)==1) {
201
202                // Length of list should be 2 for I(q,phi)
203            npars = PyList_GET_SIZE(pars);
204            if(npars!=2) {
205                PyErr_SetString(CCylinderModelError,
206                        "CCylinderModel.run expects a double or a list of dimension 2.");
207                return NULL;
208            }
209            // We have a vector q, get the q and phi values at which
210            // to evaluate I(q,phi)
211            q_value = CCylinderModel_readDouble(PyList_GET_ITEM(pars,0));
212            phi_value = CCylinderModel_readDouble(PyList_GET_ITEM(pars,1));
213            // Skip zero
214            if (q_value==0) {
215                return Py_BuildValue("d",0.0);
216            }
217                return Py_BuildValue("d",(*(self->model)).evaluate_rphi(q_value,phi_value));
218
219        } else {
220
221                // We have a scalar q, we will evaluate I(q)
222                q_value = CCylinderModel_readDouble(pars);
223
224                return Py_BuildValue("d",(*(self->model))(q_value));
225        }
226}
227
228/**
229 * Function to call to evaluate model in cartesian coordinates
230 * @param args: input q or [qx, qy]]
231 * @return: function value
232 */
233static PyObject * runXY(CCylinderModel *self, PyObject *args) {
234        double qx_value, qy_value;
235        PyObject* pars;
236        int npars;
237
238        // Get parameters
239
240        // Reader parameter dictionary
241    self->model->scale = PyFloat_AsDouble( PyDict_GetItemString(self->params, "scale") );
242    self->model->length = PyFloat_AsDouble( PyDict_GetItemString(self->params, "length") );
243    self->model->cyl_theta = PyFloat_AsDouble( PyDict_GetItemString(self->params, "cyl_theta") );
244    self->model->background = PyFloat_AsDouble( PyDict_GetItemString(self->params, "background") );
245    self->model->radius = PyFloat_AsDouble( PyDict_GetItemString(self->params, "radius") );
246    self->model->contrast = PyFloat_AsDouble( PyDict_GetItemString(self->params, "contrast") );
247    self->model->cyl_phi = PyFloat_AsDouble( PyDict_GetItemString(self->params, "cyl_phi") );
248
249    // Read in dispersion parameters
250    DispersionVisitor* visitor = new DispersionVisitor();
251    PyObject* disp_dict = PyDict_New();
252    disp_dict = PyDict_GetItemString(self->dispersion, "radius");
253    self->model->radius.dispersion->accept_as_destination(visitor, self->model->radius.dispersion, disp_dict);
254
255    disp_dict = PyDict_GetItemString(self->dispersion, "length");
256    self->model->length.dispersion->accept_as_destination(visitor, self->model->length.dispersion, disp_dict);
257
258    disp_dict = PyDict_GetItemString(self->dispersion, "cyl_theta");
259    self->model->cyl_theta.dispersion->accept_as_destination(visitor, self->model->cyl_theta.dispersion, disp_dict);
260
261    disp_dict = PyDict_GetItemString(self->dispersion, "cyl_phi");
262    self->model->cyl_phi.dispersion->accept_as_destination(visitor, self->model->cyl_phi.dispersion, disp_dict);
263
264        // Get input and determine whether we have to supply a 1D or 2D return value.
265        if ( !PyArg_ParseTuple(args,"O",&pars) ) {
266            PyErr_SetString(CCylinderModelError,
267                "CCylinderModel.run expects a q value.");
268                return NULL;
269        }
270
271        // Check params
272        if( PyList_Check(pars)==1) {
273
274                // Length of list should be 2 for I(qx, qy))
275            npars = PyList_GET_SIZE(pars);
276            if(npars!=2) {
277                PyErr_SetString(CCylinderModelError,
278                        "CCylinderModel.run expects a double or a list of dimension 2.");
279                return NULL;
280            }
281            // We have a vector q, get the qx and qy values at which
282            // to evaluate I(qx,qy)
283            qx_value = CCylinderModel_readDouble(PyList_GET_ITEM(pars,0));
284            qy_value = CCylinderModel_readDouble(PyList_GET_ITEM(pars,1));
285            return Py_BuildValue("d",(*(self->model))(qx_value,qy_value));
286
287        } else {
288
289                // We have a scalar q, we will evaluate I(q)
290                qx_value = CCylinderModel_readDouble(pars);
291                return Py_BuildValue("d",(*(self->model))(qx_value));
292        }
293}
294
295static PyObject * reset(CCylinderModel *self, PyObject *args) {
296
297
298    return Py_BuildValue("d",0.0);
299}
300
301static PyObject * set_dispersion(CCylinderModel *self, PyObject *args) {
302        PyObject * disp;
303        const char * par_name;
304
305        if ( !PyArg_ParseTuple(args,"sO", &par_name, &disp) ) {
306            PyErr_SetString(CCylinderModelError,
307                "CCylinderModel.set_dispersion expects a DispersionModel object.");
308                return NULL;
309        }
310        void *temp = PyCObject_AsVoidPtr(disp);
311        DispersionModel * dispersion = static_cast<DispersionModel *>(temp);
312
313
314        // Ugliness necessary to go from python to C
315        if (!strcmp(par_name, "radius")) {
316                self->model->radius.dispersion = dispersion;
317        } else if (!strcmp(par_name, "length")) {
318                self->model->length.dispersion = dispersion;
319        } else if (!strcmp(par_name, "cyl_theta")) {
320                self->model->cyl_theta.dispersion = dispersion;
321        } else if (!strcmp(par_name, "cyl_phi")) {
322                self->model->cyl_phi.dispersion = dispersion;
323        } else {
324            PyErr_SetString(CCylinderModelError,
325                "CCylinderModel.set_dispersion expects a valid parameter name.");
326                return NULL;
327        }
328
329        DispersionVisitor* visitor = new DispersionVisitor();
330        PyObject * disp_dict = PyDict_New();
331        dispersion->accept_as_source(visitor, dispersion, disp_dict);
332        PyDict_SetItemString(self->dispersion, par_name, disp_dict);
333    return Py_BuildValue("i",1);
334}
335
336
337static PyMethodDef CCylinderModel_methods[] = {
338    {"run",      (PyCFunction)run     , METH_VARARGS,
339      "Evaluate the model at a given Q or Q, phi"},
340    {"runXY",      (PyCFunction)runXY     , METH_VARARGS,
341      "Evaluate the model at a given Q or Qx, Qy"},
342    {"reset",    (PyCFunction)reset   , METH_VARARGS,
343      "Reset pair correlation"},
344    {"set_dispersion",      (PyCFunction)set_dispersion     , METH_VARARGS,
345      "Set the dispersion model for a given parameter"},
346   {NULL}
347};
348
349static PyTypeObject CCylinderModelType = {
350    PyObject_HEAD_INIT(NULL)
351    0,                         /*ob_size*/
352    "CCylinderModel",             /*tp_name*/
353    sizeof(CCylinderModel),             /*tp_basicsize*/
354    0,                         /*tp_itemsize*/
355    (destructor)CCylinderModel_dealloc, /*tp_dealloc*/
356    0,                         /*tp_print*/
357    0,                         /*tp_getattr*/
358    0,                         /*tp_setattr*/
359    0,                         /*tp_compare*/
360    0,                         /*tp_repr*/
361    0,                         /*tp_as_number*/
362    0,                         /*tp_as_sequence*/
363    0,                         /*tp_as_mapping*/
364    0,                         /*tp_hash */
365    0,                         /*tp_call*/
366    0,                         /*tp_str*/
367    0,                         /*tp_getattro*/
368    0,                         /*tp_setattro*/
369    0,                         /*tp_as_buffer*/
370    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
371    "CCylinderModel objects",           /* tp_doc */
372    0,                         /* tp_traverse */
373    0,                         /* tp_clear */
374    0,                         /* tp_richcompare */
375    0,                         /* tp_weaklistoffset */
376    0,                         /* tp_iter */
377    0,                         /* tp_iternext */
378    CCylinderModel_methods,             /* tp_methods */
379    CCylinderModel_members,             /* tp_members */
380    0,                         /* tp_getset */
381    0,                         /* tp_base */
382    0,                         /* tp_dict */
383    0,                         /* tp_descr_get */
384    0,                         /* tp_descr_set */
385    0,                         /* tp_dictoffset */
386    (initproc)CCylinderModel_init,      /* tp_init */
387    0,                         /* tp_alloc */
388    CCylinderModel_new,                 /* tp_new */
389};
390
391
392static PyMethodDef module_methods[] = {
393    {NULL}
394};
395
396/**
397 * Function used to add the model class to a module
398 * @param module: module to add the class to
399 */
400void addCCylinderModel(PyObject *module) {
401        PyObject *d;
402
403    if (PyType_Ready(&CCylinderModelType) < 0)
404        return;
405
406    Py_INCREF(&CCylinderModelType);
407    PyModule_AddObject(module, "CCylinderModel", (PyObject *)&CCylinderModelType);
408
409    d = PyModule_GetDict(module);
410    CCylinderModelError = PyErr_NewException("CCylinderModel.error", NULL, NULL);
411    PyDict_SetItemString(d, "CCylinderModelError", CCylinderModelError);
412}
413
Note: See TracBrowser for help on using the repository browser.