source: sasview/src/sas/sascalc/file_converter/c_ext/bsl_loader.c @ 2b3eb3d

ticket-1094-headlessticket-1243
Last change on this file since 2b3eb3d was 952ea1f, checked in by Paul Kienzle <pkienzle@…>, 6 years ago

move c extensions from core/module.so to _module.so

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