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:
2024-09-10 16:00:04 +02:00
committed by GitHub
parent c6477e0ed6
commit 5b61ff24bb
93 changed files with 25399 additions and 7292 deletions

179
pyctbgui/src/decoder.c Normal file
View 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
View 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
View 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);

View 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;