source: sasview/src/sas/sascalc/file_converter/c_ext/bsl_loader.c @ 369ed11d

magnetic_scattrelease-4.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249unittest-saveload
Last change on this file since 369ed11d was d5aeaa3, checked in by Paul Kienzle <pkienzle@…>, 7 years ago

add CLoader to the correct module

  • Property mode set to 100644
File size: 11.0 KB
Line 
1#include <Python.h>
2#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
3#include <numpy/arrayobject.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include "structmember.h"
7#include "bsl_loader.h"
8
9typedef struct {
10    PyObject_HEAD
11    CLoader_params params;
12} CLoader;
13
14static PyObject *CLoader_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
15    CLoader *self;
16
17    self = (CLoader *)type->tp_alloc(type, 0);
18
19    return (PyObject *)self;
20}
21
22static PyObject *CLoader_init(CLoader *self, PyObject *args, PyObject *kwds) {
23    const char *filename;
24    int n_frames;
25    int n_pixels;
26    int n_rasters;
27    int swap_bytes;
28
29    if (self != NULL) {
30        if (!PyArg_ParseTuple(args, "siiii", &filename, &n_frames, &n_pixels, &n_rasters, &swap_bytes))
31            Py_RETURN_NONE;
32        if (!(self->params.filename = malloc(strlen(filename) + 1)))
33            Py_RETURN_NONE;
34        strcpy(self->params.filename, filename);
35        self->params.n_frames = n_frames;
36        self->params.n_pixels = n_pixels;
37        self->params.n_rasters = n_rasters;
38        self->params.swap_bytes = swap_bytes;
39    }
40
41    return 0;
42}
43
44static void CLoader_dealloc(CLoader *self) {
45    free(self->params.filename);
46    Py_TYPE(self)->tp_free((PyObject *)self);
47}
48
49static PyObject *to_string(CLoader *self, PyObject *params) {
50    char str[100];
51    sprintf(str,
52        "Filename: %s\nn_frames: %d\nframe: %d\nn_pixels: %d\nn_rasters: %d\nswap_bytes: %d",
53        self->params.filename,
54        self->params.n_frames,
55        self->params.frame,
56        self->params.n_pixels,
57        self->params.n_rasters,
58        self->params.swap_bytes);
59    return Py_BuildValue("s", str);
60}
61
62/*                    ----- Setters and Getters -----                        */
63
64static PyObject *get_filename(CLoader *self, PyObject *args) {
65    return Py_BuildValue("s", self->params.filename);
66}
67
68static PyObject *set_filename(CLoader *self, PyObject *args) {
69    const char *new_filename;
70    if (!PyArg_ParseTuple(args, "s", &new_filename))
71        return NULL;
72    strcpy(self->params.filename, new_filename);
73
74    return Py_BuildValue("s", self->params.filename);
75}
76
77static PyObject *get_n_frames(CLoader *self, PyObject *args) {
78    return Py_BuildValue("i", self->params.n_frames);
79}
80
81static PyObject *set_n_frames(CLoader *self, PyObject *args) {
82    int new_frames;
83    if (!PyArg_ParseTuple(args, "i", &new_frames))
84        return NULL;
85    self->params.n_frames = new_frames;
86
87    return Py_BuildValue("i", self->params.n_frames);
88}
89
90static PyObject *get_frame(CLoader *self, PyObject *args) {
91    return Py_BuildValue("i", self->params.frame);
92}
93
94static PyObject *set_frame(CLoader *self, PyObject *args) {
95    int new_frame;
96    if (!PyArg_ParseTuple(args, "i", &new_frame))
97        return NULL;
98    self->params.frame = new_frame;
99
100    return Py_BuildValue("i", self->params.frame);
101}
102
103static PyObject *get_n_pixels(CLoader *self, PyObject *args) {
104    return Py_BuildValue("i", self->params.n_pixels);
105}
106
107static PyObject *set_n_pixels(CLoader *self, PyObject *args) {
108    int new_pixels;
109    if (!PyArg_ParseTuple(args, "i", &new_pixels))
110        return NULL;
111    self->params.n_pixels = new_pixels;
112
113    return Py_BuildValue("i", self->params.n_pixels);
114}
115
116static PyObject *get_n_rasters(CLoader *self, PyObject *args) {
117    return Py_BuildValue("i", self->params.n_rasters);
118}
119
120static PyObject *set_n_rasters(CLoader *self, PyObject *args) {
121    int new_rasters;
122    if (!PyArg_ParseTuple(args, "i", &new_rasters))
123        return NULL;
124    self->params.n_rasters = new_rasters;
125
126    return Py_BuildValue("i", self->params.n_rasters);
127}
128
129static PyObject *get_swap_bytes(CLoader *self, PyObject *args) {
130    return Py_BuildValue("i", self->params.swap_bytes);
131}
132
133static PyObject *set_swap_bytes(CLoader *self, PyObject *args) {
134    int new_swap;
135    if (!PyArg_ParseTuple(args, "i", &new_swap))
136        return NULL;
137    self->params.swap_bytes = new_swap;
138
139    return Py_BuildValue("i", self->params.swap_bytes);
140}
141
142/*                        ----- Instance Methods -----                       */
143
144float reverse_float(const float in_float) {
145    // Reverse the order of the bytes of a float
146    float retval;
147    char *to_convert = (char *)&in_float;
148    char *return_float = (char *)&retval;
149
150    return_float[0] = to_convert[3];
151    return_float[1] = to_convert[2];
152    return_float[2] = to_convert[1];
153    return_float[3] = to_convert[0];
154
155    return retval;
156}
157
158static PyObject *load_data(CLoader *self, PyObject *args) {
159    int raster;
160    int pixel;
161    int frame_pos;
162    npy_intp size[2] = {self->params.n_rasters, self->params.n_pixels};
163    float cur_val;
164    FILE *input_file;
165    PyArrayObject *data;
166
167    // Create a new numpy array to store the data in
168    data = (PyArrayObject *)PyArray_SimpleNew(2, size, NPY_FLOAT);
169
170    // Attempt to open the file specified
171    input_file = fopen(self->params.filename, "rb");
172    if (!input_file) {
173        // BSL filenames are 10 characters long
174        // Filename validity checked in bsl_loader.py
175        size_t filename_start = strlen(self->params.filename) - 10;
176        char *filename = self->params.filename + filename_start;
177        char *err_msg = (char *)malloc(sizeof(char) * 32);
178
179        sprintf(err_msg, "Unable to open file: %s", filename);
180
181        PyErr_SetString(PyExc_RuntimeError, err_msg);
182        free(err_msg);
183        return NULL;
184    }
185
186    // Move the file cursor the the position where the data we're interested
187    // in begins
188    frame_pos = self->params.n_pixels * self->params.n_rasters * self->params.frame;
189    fseek(input_file, frame_pos*sizeof(float), SEEK_SET);
190
191    for (raster = 0; raster < self->params.n_rasters; raster++) {
192        for (pixel = 0; pixel < self->params.n_pixels; pixel++) {
193            // Try reading the file
194            if (fread(&cur_val, sizeof(float), 1, input_file) == 0) {
195                PyErr_SetString(PyExc_RuntimeError, "Error reading file or EOF reached.");
196                return NULL;
197            }
198
199            // Swap the order of the bytes read, if specified that we should do
200            // so in the header file
201            if (self->params.swap_bytes == 0)
202                cur_val = reverse_float(cur_val);
203
204            // Add the read value to the numpy array
205            PyArray_SETITEM(data, PyArray_GETPTR2(data, raster, pixel), PyFloat_FromDouble(cur_val));
206        }
207    }
208
209    fclose(input_file);
210
211    return Py_BuildValue("N", data);
212}
213
214/*                           ----- Class Registration -----                  */
215
216static PyMethodDef CLoader_methods[] = {
217    { "to_string", (PyCFunction)to_string, METH_VARARGS, "Print the objects params" },
218    { "get_filename", (PyCFunction)get_filename, METH_VARARGS, "Get the filename" },
219    { "set_filename", (PyCFunction)set_filename, METH_VARARGS, "Set the filename" },
220    { "get_n_frames", (PyCFunction)get_n_frames, METH_VARARGS, "Get n_frames" },
221    { "set_n_frames", (PyCFunction)set_n_frames, METH_VARARGS, "Set n_frames" },
222    { "get_frame", (PyCFunction)get_frame, METH_VARARGS, "Get the frame that will be loaded" },
223    { "set_frame", (PyCFunction)set_frame, METH_VARARGS, "Set the frame that will be loaded" },
224    { "get_n_pixels", (PyCFunction)get_n_pixels, METH_VARARGS, "Get n_pixels" },
225    { "set_n_pixels", (PyCFunction)set_n_pixels, METH_VARARGS, "Set n_pixels" },
226    { "get_n_rasters", (PyCFunction)get_n_rasters, METH_VARARGS, "Get n_rasters" },
227    { "set_n_rasters", (PyCFunction)set_n_rasters, METH_VARARGS, "Set n_rasters" },
228    { "get_swap_bytes", (PyCFunction)get_swap_bytes, METH_VARARGS, "Get swap_bytes" },
229    { "set_swap_bytes", (PyCFunction)set_swap_bytes, METH_VARARGS, "Set swap_bytes" },
230    { "load_data", (PyCFunction)load_data, METH_VARARGS, "Load the data into a numpy array" },
231    {NULL}
232};
233
234static PyMemberDef CLoader_members[] = {
235    {NULL}
236};
237
238static PyTypeObject CLoaderType = {
239    //PyObject_HEAD_INIT(NULL)
240    //0,                         /*ob_size*/
241    PyVarObject_HEAD_INIT(NULL, 0)
242    "CLoader",             /*tp_name*/
243    sizeof(CLoader),             /*tp_basicsize*/
244    0,                         /*tp_itemsize*/
245    (destructor)CLoader_dealloc, /*tp_dealloc*/
246    0,                         /*tp_print*/
247    0,                         /*tp_getattr*/
248    0,                         /*tp_setattr*/
249    0,                         /*tp_compare*/
250    0,                         /*tp_repr*/
251    0,                         /*tp_as_number*/
252    0,                         /*tp_as_sequence*/
253    0,                         /*tp_as_mapping*/
254    0,                         /*tp_hash */
255    0,                         /*tp_call*/
256    0,                         /*tp_str*/
257    0,                         /*tp_getattro*/
258    0,                         /*tp_setattro*/
259    0,                         /*tp_as_buffer*/
260    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
261    "CLoader objects",           /* tp_doc */
262    0,                         /* tp_traverse */
263    0,                         /* tp_clear */
264    0,                         /* tp_richcompare */
265    0,                         /* tp_weaklistoffset */
266    0,                         /* tp_iter */
267    0,                         /* tp_iternext */
268    CLoader_methods,             /* tp_methods */
269    CLoader_members,             /* tp_members */
270    0,                         /* tp_getset */
271    0,                         /* tp_base */
272    0,                         /* tp_dict */
273    0,                         /* tp_descr_get */
274    0,                         /* tp_descr_set */
275    0,                         /* tp_dictoffset */
276    (initproc)CLoader_init,      /* tp_init */
277    0,                         /* tp_alloc */
278    CLoader_new,                 /* tp_new */
279};
280
281/**
282 * Function used to add the model class to a module
283 * @param module: module to add the class to
284 */
285void addCLoader(PyObject *module)
286{
287    if (PyType_Ready(&CLoaderType) < 0)
288        return;
289    Py_INCREF(&CLoaderType);
290    PyModule_AddObject(module, "CLoader", (PyObject *)&CLoaderType);
291}
292
293#define MODULE_DOC "C module for loading bsl."
294#define MODULE_NAME "bsl_loader"
295#define MODULE_INIT2 initbsl_loader
296#define MODULE_INIT3 PyInit_bsl_loader
297#define MODULE_METHODS module_methods
298
299/* ==== boilerplate python 2/3 interface bootstrap ==== */
300
301
302#if defined(WIN32) && !defined(__MINGW32__)
303    #define DLL_EXPORT __declspec(dllexport)
304#else
305    #define DLL_EXPORT
306#endif
307
308#if PY_MAJOR_VERSION >= 3
309
310  static PyMethodDef module_methods[] = {
311      {NULL}
312  };
313
314  DLL_EXPORT PyMODINIT_FUNC MODULE_INIT3(void)
315  {
316    static struct PyModuleDef moduledef = {
317      PyModuleDef_HEAD_INIT,
318      MODULE_NAME,         /* m_name */
319      MODULE_DOC,          /* m_doc */
320      -1,                  /* m_size */
321      MODULE_METHODS,      /* m_methods */
322      NULL,                /* m_reload */
323      NULL,                /* m_traverse */
324      NULL,                /* m_clear */
325      NULL,                /* m_free */
326    };
327    PyObject* m = PyModule_Create(&moduledef);
328    import_array();
329    addCLoader(m);
330    return m;
331  }
332
333#else /* !PY_MAJOR_VERSION >= 3 */
334
335  DLL_EXPORT PyMODINIT_FUNC MODULE_INIT2(void)
336  {
337    PyObject* m = Py_InitModule(MODULE_NAME, NULL);
338    import_array();
339    addCLoader(m);
340  }
341
342#endif /* !PY_MAJOR_VERSION >= 3 */
Note: See TracBrowser for help on using the repository browser.