mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-06-12 12:57:13 +02:00
Dev/pyctbgui merge (#960)
* added empty c extension * added rotation to the decoding * added color map, options and findex * minor * move checks to before acquisition * added pixel map based decoder * cleanup * no thread creation for single thread processing * added rotation and test to compare * allow high and low water mark for zmq (also buffer size) for fast readouts * removed roatation during decoding * added Transpose to image and invert Y False to invert it * retains the zoomed state after the first image of gui, catch and display exception if no detector connected * moved start frame to dockable widget, removed extra frame number label, moved current measurement also to dockable widget, hide frame plot entirely when showing patternviewer * first image dependin on which plot * remember settings of main window size and position, dockewidget if docked, its size and posisiotn as well, then update it next time the gui is opened * change in comment * using c decoder for moench 04 and matterhorn * catch exception from invalid image from decoder * clean up * update row and col when choosing image type, neeeded to show values * fix for previous PR * disable resetting colormap values keep the range selected for every new acquisition * fix typos + tested on virtual matterhorn * minor print * refactored Slow ADCs Tab * refactored DAC tab * refactored power supplies * refactored signals tab * refactored transceiver tab * fix typo * fix typo2 * remove commented code * delete commented code * delete commented code * delete commented signals code * remove commented code for transceiver tab * refactor adc tab * refactor Pattern Tab * Refactor transceivers tab (PR#5) (#118) * refactored transceiver tab * remove commented code for transceiver tab --------- Co-authored-by: Erik Frojdh <erik.frojdh@gmail.com> * refactor adc tab (PR#6) (#119) * refactor adc tab * refactored Plot and Acquisition Tabs * fix the regression issue * restructure project files * applying singleton and renaming tabs to services * working install using pip * applies singleton to tab classes and remove CI erros * added pyzmq and pillow * remove the singleton implementation and keep changes * fix merge errors in mainWindow * moved misplaced init file * rename service to tab * reorganize imports * iterate over tabs * reorder tabs * add slowadc to the list * saving changes (buggy) power supply ui not showing in the gui * split power supply tab * fixed tests * add hardcoded values to defines file * fix error * separate power supply * fix errors for powerSuppliesTab * split dacs * split slow adcs * split signals tab * added tests for bit_utils * add slowAdc class to defines * split transceiver ui file * split adc.ui * split pattern ui file * split plot and acquisition ui file * added basic test for parsing bit names * removed redundant code in read_alias_file * fix dacs ui position * testing for correct exception * cmd and args at split * group radio buttons * fix comments from PR#1 * show legend * added python version and dev requirements to setup.py * fix dac issue * moved _decoder into pkg * added inplace build * removed clear * fixed dependencies * make tests run without slsdet * updated name of action * define colcount * fixed loading of alias file * add yapf and ruff * apply formatting * fix E and F rules * add more ruff rules * change variable name * squashing gh debugging commits and add pre-commit * update label values to mv units * add hook for yapf * reconfigure yapf precommit hook * add format and check_format to makefile * change gh actions * update readme * added check_format * WIP * added linting in github action * updated readme] * add more control for color choice * remove useless file * fix un-updated line after refactoring Defines BIT0_31_MASK is not found in Defines.signals * visually improve the interface * fix last commit * add only selected plots for legend * add hide legend button * change hide legend to show legend checkbox show legend is checked by default * add support for saving in numpy * solve conversations * fix acq index offset * fix browse button in pattern error * fix other browse button errors * finish tests and add usage.md * remove buffer * add file,numpy-like interface and tests * remove useless .npy files * subscriptible npz files * remove useless files * remove repetetive tests * save changes * add mode r+, add with support,remove logging * remove offset of acqIndex between raw and numpy saving * fix only saving last frame * save signals of multiple devices * add comments and move condition for clearer code * fix bug when vieweing pattern file * iterate over enabled and plotted plots * add padestal substraction to transceiver and analog data * init pedestal frames to detector.frames * restore old exception * add pedestal substraction for digital signals * remove frames spinbox from plotTab * remove comments and use str instead of Path * avoid saving all frames * correct exception and log error's trace * add gui tests * add waveform test * add pedestal test * refactor by using fixtures * add tests for moench analog and pattern * add pytest-qt to dependencies * add save and load gui parameters * remove nohup file * fix old bug IndexError * save plot type * a * handle canceling load, loading matterhorn pedestal for moench * remove comparing .png files for pattern test * save plot type * red error on status bar when shape mismatch for loaded pedestal * fix makefile and docstrings * fix PRs conversation * move code into different function * fix wrong function names for power supply * removed old ctbgui * removed unnecessary files --------- Co-authored-by: Erik Frojdh <erik.frojdh@gmail.com> Co-authored-by: Braham Bechir <braham_b@pc11979.psi.ch> Co-authored-by: Bechir <bechir.braham@psi.ch> Co-authored-by: Bechir <bechir.brahem420@gmail.com>
This commit is contained in:
179
pyctbgui/src/decoder.c
Normal file
179
pyctbgui/src/decoder.c
Normal file
@ -0,0 +1,179 @@
|
||||
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include <numpy/arrayobject.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "pm_decode.h"
|
||||
#include "thread_utils.h"
|
||||
|
||||
/*Decode various types of CTB data using a pixel map. Works on single frames and
|
||||
on stacks of frames*/
|
||||
static PyObject *decode(PyObject *Py_UNUSED(self), PyObject *args,
|
||||
PyObject *kwds) {
|
||||
// Function arguments to be parsed
|
||||
PyObject *raw_data_obj = NULL;
|
||||
PyObject *data_obj = NULL;
|
||||
PyObject *pm_obj = NULL;
|
||||
size_t n_threads = 1;
|
||||
|
||||
static char *kwlist[] = {"raw_data", "pixel_map", "out", "n_threads", NULL};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|On", kwlist, &raw_data_obj,
|
||||
&pm_obj, &data_obj, &n_threads)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create a handle to the numpy array from the generic python object
|
||||
PyObject *raw_data = PyArray_FROM_OTF(
|
||||
raw_data_obj, NPY_UINT16,
|
||||
NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ENSUREARRAY | NPY_ARRAY_ALIGNED);
|
||||
if (!raw_data) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Handle to the pixel map
|
||||
PyObject *pixel_map = PyArray_FROM_OTF(
|
||||
pm_obj, NPY_UINT32, NPY_ARRAY_C_CONTIGUOUS); // Make 64bit?
|
||||
if (!pixel_map) {
|
||||
return NULL;
|
||||
}
|
||||
if (PyArray_NDIM((PyArrayObject *)pixel_map) != 2) {
|
||||
PyErr_SetString(PyExc_TypeError, "The pixel map needs to be 2D");
|
||||
return NULL;
|
||||
}
|
||||
npy_intp n_rows = PyArray_DIM((PyArrayObject *)pixel_map, 0);
|
||||
npy_intp n_cols = PyArray_DIM((PyArrayObject *)pixel_map, 1);
|
||||
|
||||
// If called with an output array get an handle to it, otherwise allocate
|
||||
// the output array
|
||||
PyObject *data_out = NULL;
|
||||
if (data_obj) {
|
||||
data_out =
|
||||
PyArray_FROM_OTF(data_obj, NPY_UINT16, NPY_ARRAY_C_CONTIGUOUS);
|
||||
} else {
|
||||
int ndim = PyArray_NDIM((PyArrayObject *)raw_data) + 1;
|
||||
npy_intp dims_arr[3] = {PyArray_DIM((PyArrayObject *)raw_data, 0),
|
||||
n_rows, n_cols};
|
||||
npy_intp *dims = NULL;
|
||||
if (ndim == 2)
|
||||
dims = &dims_arr[1];
|
||||
else
|
||||
dims = &dims_arr[0];
|
||||
// Allocate output array
|
||||
data_out = PyArray_SimpleNew(ndim, dims, NPY_UINT16);
|
||||
}
|
||||
|
||||
// Check that raw_data has one less dimension than frame
|
||||
// eg raw_data[n_frames, pixels] frame[nframes, nrows, ncols]
|
||||
// raw data is an array of values and data_out is 2/3D
|
||||
int rd_dim = PyArray_NDIM((PyArrayObject *)raw_data);
|
||||
int f_dim = PyArray_NDIM((PyArrayObject *)data_out);
|
||||
|
||||
if (rd_dim != (f_dim - 1)) {
|
||||
PyErr_SetString(
|
||||
PyExc_TypeError,
|
||||
"Raw data and data needs to have the one less dim"); // eg -1
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint16_t *src = (uint16_t *)PyArray_DATA((PyArrayObject *)raw_data);
|
||||
uint16_t *dst = (uint16_t *)PyArray_DATA((PyArrayObject *)data_out);
|
||||
uint32_t *pm = (uint32_t *)PyArray_DATA((PyArrayObject *)pixel_map);
|
||||
|
||||
// Check sizes
|
||||
npy_intp rd_size = PyArray_SIZE((PyArrayObject *)raw_data);
|
||||
npy_intp fr_size = PyArray_SIZE((PyArrayObject *)data_out);
|
||||
npy_intp pm_size = PyArray_SIZE((PyArrayObject *)pixel_map);
|
||||
|
||||
// TODO! Add exceptions
|
||||
if (rd_size != fr_size) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Raw data size and data size needs to match");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int64_t n_frames = 1;
|
||||
if (rd_dim == 2)
|
||||
n_frames = PyArray_DIM((PyArrayObject *)raw_data, 0);
|
||||
// printf("n_frames: %lu\n", n_frames);
|
||||
|
||||
// do the correct size check
|
||||
if (rd_size / n_frames != pm_size) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Pixel map size needs to match with frame size");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (n_threads == 1){
|
||||
pm_decode(src, dst, pm, n_frames, n_rows * n_cols);
|
||||
}else{
|
||||
// Multithreaded processing
|
||||
pthread_t *threads = malloc(sizeof(pthread_t *) * n_threads);
|
||||
thread_args *arguments = malloc(sizeof(thread_args) * n_threads);
|
||||
|
||||
size_t frames_per_thread = n_frames / n_threads;
|
||||
size_t assigned_frames = 0;
|
||||
for (size_t i = 0; i < n_threads; i++) {
|
||||
arguments[i].src = src + (i * frames_per_thread * pm_size);
|
||||
arguments[i].dst = dst + (i * frames_per_thread * pm_size);
|
||||
arguments[i].pm = pm;
|
||||
arguments[i].n_frames = frames_per_thread; // TODO! not matching frames.
|
||||
arguments[i].n_pixels = n_rows * n_cols;
|
||||
assigned_frames += frames_per_thread;
|
||||
}
|
||||
arguments[n_threads - 1].n_frames += n_frames - assigned_frames;
|
||||
|
||||
for (size_t i = 0; i < n_threads; i++) {
|
||||
pthread_create(&threads[i], NULL, (void *)thread_pmdecode,
|
||||
&arguments[i]);
|
||||
}
|
||||
for (size_t i = 0; i < n_threads; i++) {
|
||||
pthread_join(threads[i], NULL);
|
||||
}
|
||||
free(threads);
|
||||
free(arguments);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Py_DECREF(raw_data);
|
||||
Py_DECREF(pixel_map);
|
||||
|
||||
return data_out;
|
||||
}
|
||||
|
||||
// Module docstring, shown as a part of help(creader)
|
||||
static char module_docstring[] = "C functions decode CTB data";
|
||||
|
||||
// Module methods
|
||||
static PyMethodDef creader_methods[] = {
|
||||
{"decode", (PyCFunction)(void (*)(void))decode,
|
||||
METH_VARARGS | METH_KEYWORDS, "Decode analog data using a pixel map"},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
// Module defenition
|
||||
static struct PyModuleDef decoder_def = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_decoder",
|
||||
module_docstring,
|
||||
-1,
|
||||
creader_methods, // m_methods
|
||||
NULL, // m_slots
|
||||
NULL, // m_traverse
|
||||
NULL, // m_clear
|
||||
NULL // m_free
|
||||
};
|
||||
|
||||
// Initialize module and add classes
|
||||
PyMODINIT_FUNC PyInit__decoder(void) {
|
||||
|
||||
PyObject *m = PyModule_Create(&decoder_def);
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
import_array(); // Needed for numpy
|
||||
return m;
|
||||
}
|
17
pyctbgui/src/pm_decode.c
Normal file
17
pyctbgui/src/pm_decode.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include "pm_decode.h"
|
||||
#include "thread_utils.h"
|
||||
|
||||
void thread_pmdecode(void* args){
|
||||
thread_args* a;
|
||||
a = (thread_args *) args;
|
||||
pm_decode(a->src, a->dst, a->pm, a->n_frames, a->n_pixels);
|
||||
}
|
||||
|
||||
void pm_decode(uint16_t* src, uint16_t* dst, uint32_t* pm, size_t n_frames, size_t n_pixels){
|
||||
for(size_t i = 0; i<n_frames; i++){
|
||||
for(size_t j=0; j<n_pixels; j++){
|
||||
*dst++ = src[pm[j]];
|
||||
}
|
||||
src += n_pixels;
|
||||
}
|
||||
}
|
8
pyctbgui/src/pm_decode.h
Normal file
8
pyctbgui/src/pm_decode.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
//Wrapper to be used with pthreads
|
||||
void thread_pmdecode(void* args);
|
||||
|
||||
|
||||
void pm_decode(uint16_t* src, uint16_t* dst, uint32_t* pm, size_t n_frames, size_t n_pixels);
|
10
pyctbgui/src/thread_utils.h
Normal file
10
pyctbgui/src/thread_utils.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
typedef struct{
|
||||
uint16_t* src;
|
||||
uint16_t* dst;
|
||||
uint32_t* pm;
|
||||
size_t n_frames;
|
||||
size_t n_pixels;
|
||||
}thread_args;
|
Reference in New Issue
Block a user