mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2026-02-21 09:38:40 +01:00
Dev/stuff from pyctbgui (#273)
Matterhorn10 Transform some other Transformations from pyctbGUI added method get_reading_mode for easier error handling in decoders ## TODO: - proper error handling for all other decoders - proper documentation for all other decoders - refactoring all other decoders to store hard coded values in a Struct ChipSpecification
This commit is contained in:
@@ -18,6 +18,9 @@ class CtbRawFile(_aare.CtbRawFile):
|
||||
super().__init__(fname)
|
||||
self._chunk_size = chunk_size
|
||||
self._transform = transform
|
||||
if self._transform:
|
||||
if hasattr(self._transform, "compatibility") and callable(getattr(self._transform, "compatibility")):
|
||||
self._transform.compatibility(self.master.reading_mode)
|
||||
|
||||
|
||||
def read_frame(self, frame_index: int | None = None ) -> tuple:
|
||||
@@ -45,7 +48,6 @@ class CtbRawFile(_aare.CtbRawFile):
|
||||
if header.shape == (1,):
|
||||
header = header[0]
|
||||
|
||||
|
||||
if self._transform:
|
||||
res = self._transform(data)
|
||||
if isinstance(res, tuple):
|
||||
|
||||
@@ -5,7 +5,7 @@ from . import _aare
|
||||
|
||||
from ._aare import File, RawMasterFile, RawSubFile, JungfrauDataFile
|
||||
from ._aare import Pedestal_d, Pedestal_f, ClusterFinder_Cluster3x3i, VarClusterFinder
|
||||
from ._aare import DetectorType
|
||||
from ._aare import DetectorType, ReadoutMode
|
||||
from ._aare import hitmap
|
||||
from ._aare import ROI
|
||||
from ._aare import corner
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
import numpy as np
|
||||
from . import _aare
|
||||
|
||||
from aare import ReadoutMode
|
||||
from aare._aare import Matterhorn10
|
||||
|
||||
class AdcSar04Transform64to16:
|
||||
def __call__(self, data):
|
||||
@@ -24,6 +25,14 @@ class Moench05Transform:
|
||||
return np.take(data.view(np.uint16), self.pixel_map)
|
||||
|
||||
|
||||
class Moench03Transform:
|
||||
def __init__(self):
|
||||
self.pixel_map = _aare.GenerateMoench03PixelMap()
|
||||
|
||||
def __call__(self, data):
|
||||
return np.take(data.view(np.uint16), self.pixel_map)
|
||||
|
||||
|
||||
class Moench05Transform1g:
|
||||
#Could be moved to C++ without changing the interface
|
||||
def __init__(self):
|
||||
@@ -40,19 +49,81 @@ class Moench05TransformOld:
|
||||
|
||||
def __call__(self, data):
|
||||
return np.take(data.view(np.uint16), self.pixel_map)
|
||||
|
||||
|
||||
class Matterhorn02Transform:
|
||||
|
||||
class Moench04AnalogTransform:
|
||||
#Could be moved to C++ without changing the interface
|
||||
def __init__(self):
|
||||
self.pixel_map = _aare.GenerateMH02FourCounterPixelMap()
|
||||
self.pixel_map = _aare.GenerateMoench04AnalogPixelMap()
|
||||
|
||||
def __call__(self, data):
|
||||
counters = int(data.size / 48**2 / 2)
|
||||
if counters == 1:
|
||||
return np.take(data.view(np.uint16), self.pixel_map[0])
|
||||
else:
|
||||
return np.take(data.view(np.uint16), self.pixel_map[0:counters])
|
||||
return np.take(data.view(np.uint16), self.pixel_map)
|
||||
|
||||
class Matterhorn02TransceiverTransform:
|
||||
#Could be moved to C++ without changing the interface
|
||||
def __init__(self):
|
||||
self.pixel_map = _aare.GenerateMH02SingleCounterPixelMap()
|
||||
|
||||
def __call__(self, data):
|
||||
return np.take(data.view(np.uint16), self.pixel_map)
|
||||
|
||||
class Matterhorn10Transform:
|
||||
"""
|
||||
Transforms Matterhorn10 chip data from a buffer of bytes (uint8_t)
|
||||
to a numpy array of uint8, uint16 depending on dynamic range.
|
||||
Assumes data taken with transceiver samples only.
|
||||
|
||||
:param dynamic_range: How many bits a pixel is encoded dynamic range (4, 8, or 16)
|
||||
:type dynamic_range: int
|
||||
:param num_counters: num counters used (1 to 4)
|
||||
:type num_counters: int
|
||||
|
||||
.. note::
|
||||
A matterhorn chip has 256 columns and 256 rows.
|
||||
A matterhornchip with dynamic range 16 and 2 counters thus requires
|
||||
256*256*16*2/(2*64) = 1024 transceiver samples. (Per default 2 channels are enabled per transceiver sample, each channel storing 64 bits)
|
||||
"""
|
||||
def __init__(self, dynamic_range : int, num_counters : int):
|
||||
self.pixel_map = _aare.GenerateMatterhorn10PixelMap(dynamic_range, num_counters)
|
||||
self.dynamic_range = dynamic_range
|
||||
self.num_counters = num_counters
|
||||
|
||||
def compatibility(self, readingmode : ReadoutMode):
|
||||
"""
|
||||
checks if Matterhorn10Transform is compatible with given parameters
|
||||
|
||||
:param readingmode: Reading mode set
|
||||
:type readingmode: ReadoutMode
|
||||
:raises ValueError: if not compatible
|
||||
"""
|
||||
if(readingmode != ReadoutMode.TRANSCEIVER_ONLY):
|
||||
raise ValueError(f"Incompatible Transformation. Matterhorn10Transform only requires transceiver samples. However reading mode is {readingmode}.")
|
||||
|
||||
pass
|
||||
|
||||
def data_compatibility(self, data):
|
||||
"""
|
||||
checks if data is compatible for transformation
|
||||
|
||||
:param data: data to be transformed, expected to be a 1D numpy array of uint8
|
||||
:type data: np.ndarray
|
||||
:raises ValueError: if not compatible
|
||||
"""
|
||||
expected_size = (Matterhorn10.nRows*Matterhorn10.nCols*self.num_counters*self.dynamic_range)//8 # read_frame returns data in uint8_t
|
||||
|
||||
if(data.size != expected_size):
|
||||
raise ValueError(f"Data size {data.size} does not match expected size {expected_size} for Matterhorn10 with dynamic range {self.dynamic_range} and num_counters {self.num_counters}.")
|
||||
|
||||
pass
|
||||
|
||||
def __call__(self, data):
|
||||
self.data_compatibility(data)
|
||||
if self.dynamic_range == 16:
|
||||
return np.take(data.view(np.uint16), self.pixel_map)
|
||||
elif self.dynamic_range == 8:
|
||||
return np.take(data.view(np.uint8), self.pixel_map)
|
||||
else: #dynamic range 4
|
||||
return np.take(_aare.expand4to8bit(data.view(np.uint8)), self.pixel_map)
|
||||
|
||||
class Mythen302Transform:
|
||||
"""
|
||||
Transform Mythen 302 test chip data from a buffer of bytes (uint8_t)
|
||||
@@ -95,7 +166,7 @@ class Mythen302Transform:
|
||||
moench05 = Moench05Transform()
|
||||
moench05_1g = Moench05Transform1g()
|
||||
moench05_old = Moench05TransformOld()
|
||||
matterhorn02 = Matterhorn02Transform()
|
||||
matterhorn02 = Matterhorn02TransceiverTransform()
|
||||
adc_sar_04_64to16 = AdcSar04Transform64to16()
|
||||
adc_sar_05_64to16 = AdcSar05Transform64to16()
|
||||
adc_sar_05_06_07_08_64to16 = AdcSar05060708Transform64to16()
|
||||
25
python/src/bind_Defs.hpp
Normal file
25
python/src/bind_Defs.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
#include "aare/defs.hpp"
|
||||
|
||||
namespace py = pybind11;
|
||||
using namespace aare;
|
||||
|
||||
void define_defs_bindings(py::module &m) {
|
||||
auto matterhorn10 = py::class_<Matterhorn10>(m, "Matterhorn10");
|
||||
matterhorn10.attr("nRows") = Matterhorn10::nRows;
|
||||
matterhorn10.attr("nCols") = Matterhorn10::nCols;
|
||||
|
||||
auto matterhorn02 = py::class_<Matterhorn02>(m, "Matterhorn02");
|
||||
matterhorn02.attr("nRows") = Matterhorn02::nRows;
|
||||
matterhorn02.attr("nCols") = Matterhorn02::nCols;
|
||||
matterhorn02.attr("nHalfCols") = Matterhorn02::nHalfCols;
|
||||
|
||||
auto moench04 = py::class_<Moench04>(m, "Moench04");
|
||||
moench04.attr("nRows") = Moench04::nRows;
|
||||
moench04.attr("nCols") = Moench04::nCols;
|
||||
moench04.attr("nPixelsPerSuperColumn") = Moench04::nPixelsPerSuperColumn;
|
||||
moench04.attr("superColumnWidth") = Moench04::superColumnWidth;
|
||||
moench04.attr("adcNumbers") = Moench04::adcNumbers;
|
||||
}
|
||||
@@ -33,15 +33,35 @@ void define_pixel_map_bindings(py::module &m) {
|
||||
new NDArray<ssize_t, 2>(GenerateMoench05PixelMapOld());
|
||||
return return_image_data(ptr);
|
||||
})
|
||||
|
||||
.def("GenerateMoench04AnalogPixelMap",
|
||||
[]() {
|
||||
auto ptr =
|
||||
new NDArray<ssize_t, 2>(GenerateMoench04AnalogPixelMap());
|
||||
return return_image_data(ptr);
|
||||
})
|
||||
|
||||
.def("GenerateMH02SingleCounterPixelMap",
|
||||
[]() {
|
||||
auto ptr = new NDArray<ssize_t, 2>(
|
||||
GenerateMH02SingleCounterPixelMap());
|
||||
return return_image_data(ptr);
|
||||
})
|
||||
.def("GenerateMH02FourCounterPixelMap", []() {
|
||||
auto ptr =
|
||||
new NDArray<ssize_t, 3>(GenerateMH02FourCounterPixelMap());
|
||||
return return_image_data(ptr);
|
||||
});
|
||||
.def("GenerateMH02FourCounterPixelMap",
|
||||
[]() {
|
||||
auto ptr =
|
||||
new NDArray<ssize_t, 3>(GenerateMH02FourCounterPixelMap());
|
||||
return return_image_data(ptr);
|
||||
})
|
||||
|
||||
.def(
|
||||
"GenerateMatterhorn10PixelMap",
|
||||
[](const size_t dynamic_range, const size_t n_counters) {
|
||||
auto ptr = new NDArray<ssize_t, 2>(
|
||||
GenerateMatterhorn10PixelMap(dynamic_range, n_counters));
|
||||
return return_image_data(ptr);
|
||||
},
|
||||
py::arg("dynamic_range") = 16, py::arg("n_counters") = 1,
|
||||
R"(
|
||||
Generate pixel map for Matterhorn02 detector)");
|
||||
}
|
||||
@@ -139,6 +139,22 @@ void define_ctb_raw_file_io_bindings(py::module &m) {
|
||||
return output;
|
||||
});
|
||||
|
||||
m.def("expand4to8bit",
|
||||
[](py::array_t<uint8_t, py::array::c_style | py::array::forcecast>
|
||||
&input) {
|
||||
py::buffer_info buf = input.request();
|
||||
|
||||
py::array_t<uint8_t> output(buf.size * 2);
|
||||
|
||||
NDView<uint8_t, 1> input_view(input.mutable_data(),
|
||||
{input.size()});
|
||||
NDView<uint8_t, 1> output_view(output.mutable_data(),
|
||||
{output.size()});
|
||||
|
||||
aare::expand4to8bit(input_view, output_view);
|
||||
return output;
|
||||
});
|
||||
|
||||
m.def("decode_my302",
|
||||
[](py::array_t<uint8_t, py::array::c_style | py::array::forcecast>
|
||||
&input,
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
#include "bind_ClusterFinder.hpp"
|
||||
#include "bind_ClusterFinderMT.hpp"
|
||||
#include "bind_ClusterVector.hpp"
|
||||
#include "bind_Defs.hpp"
|
||||
#include "bind_Eta.hpp"
|
||||
#include "bind_Interpolator.hpp"
|
||||
#include "bind_PixelMap.hpp"
|
||||
#include "bind_RawFile.hpp"
|
||||
#include "bind_calibration.hpp"
|
||||
|
||||
@@ -20,7 +22,6 @@
|
||||
#include "fit.hpp"
|
||||
#include "jungfrau_data_file.hpp"
|
||||
#include "pedestal.hpp"
|
||||
#include "pixel_map.hpp"
|
||||
#include "raw_master_file.hpp"
|
||||
#include "raw_sub_file.hpp"
|
||||
#include "var_cluster.hpp"
|
||||
@@ -140,6 +141,8 @@ PYBIND11_MODULE(_aare, m) {
|
||||
register_calculate_3x3eta<float, 3, 3, uint16_t>(m);
|
||||
register_calculate_3x3eta<int16_t, 3, 3, uint16_t>(m);
|
||||
|
||||
define_defs_bindings(m);
|
||||
|
||||
using Sum_index_pair_d = Sum_index_pair<double, corner>;
|
||||
PYBIND11_NUMPY_DTYPE(Sum_index_pair_d, sum, index);
|
||||
using Sum_index_pair_f = Sum_index_pair<float, corner>;
|
||||
|
||||
@@ -23,6 +23,16 @@ namespace py = pybind11;
|
||||
using namespace ::aare;
|
||||
|
||||
void define_raw_master_file_bindings(py::module &m) {
|
||||
|
||||
py::enum_<ReadoutMode>(m, "ReadoutMode")
|
||||
.value("ANALOG_ONLY", ReadoutMode::ANALOG_ONLY)
|
||||
.value("DIGITAL_ONLY", ReadoutMode::DIGITAL_ONLY)
|
||||
.value("ANALOG_AND_DIGITAL", ReadoutMode::ANALOG_AND_DIGITAL)
|
||||
.value("TRANSCEIVER_ONLY", ReadoutMode::TRANSCEIVER_ONLY)
|
||||
.value("DIGITAL_AND_TRANSCEIVER", ReadoutMode::DIGITAL_AND_TRANSCEIVER)
|
||||
.value("UNKNOWN", ReadoutMode::UNKNOWN)
|
||||
.export_values();
|
||||
|
||||
py::class_<RawMasterFile>(m, "RawMasterFile")
|
||||
.def(py::init<const std::filesystem::path &>())
|
||||
.def("data_fname", &RawMasterFile::data_fname, R"(
|
||||
@@ -81,6 +91,7 @@ void define_raw_master_file_bindings(py::module &m) {
|
||||
|
||||
.def_property_readonly("transceiver_samples",
|
||||
&RawMasterFile::transceiver_samples)
|
||||
.def_property_readonly("reading_mode", &RawMasterFile::get_reading_mode)
|
||||
.def_property_readonly("number_of_rows", &RawMasterFile::number_of_rows)
|
||||
.def_property_readonly("quad", &RawMasterFile::quad)
|
||||
.def_property_readonly("scan_parameters",
|
||||
|
||||
@@ -14,6 +14,9 @@ def test_read_rawfile_with_roi_spanning_over_one_module(test_data_path):
|
||||
assert headers.size == 10100
|
||||
assert frames.shape == (10100, 256, 256)
|
||||
|
||||
assert headers.size == 10100
|
||||
assert frames.shape == (10100, 256, 256)
|
||||
|
||||
@pytest.mark.withdata
|
||||
def test_read_rawfile_with_multiple_rois(test_data_path):
|
||||
with RawFile(test_data_path / "raw/ROITestData/MultipleROIs/run_master_0.json") as f:
|
||||
@@ -44,6 +47,8 @@ def test_read_rawfile_with_multiple_rois(test_data_path):
|
||||
assert frame[0].shape == (301, 101)
|
||||
assert f.tell() == 2
|
||||
|
||||
|
||||
|
||||
@pytest.mark.withdata
|
||||
def test_read_rawfile_quad_eiger_and_compare_to_numpy(test_data_path):
|
||||
|
||||
@@ -68,7 +73,6 @@ def test_read_rawfile_quad_eiger_and_compare_to_numpy(test_data_path):
|
||||
|
||||
assert (image == image1).all()
|
||||
|
||||
|
||||
@pytest.mark.withdata
|
||||
def test_read_rawfile_eiger_and_compare_to_numpy(test_data_path):
|
||||
d0 = test_data_path/'raw/eiger/Lab6_20500eV_2deg_20240629_d0_f0_7.raw'
|
||||
|
||||
14
python/tests/test_RawMasterFile.py
Normal file
14
python/tests/test_RawMasterFile.py
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
import pytest
|
||||
from aare import RawMasterFile, ReadoutMode, DetectorType
|
||||
|
||||
|
||||
@pytest.mark.withdata
|
||||
def test_read_rawfile_quad_eiger_and_compare_to_numpy(test_data_path):
|
||||
|
||||
file_name = test_data_path/'raw/jungfrau/jungfrau_single_master_0.json'
|
||||
|
||||
f = RawMasterFile(file_name)
|
||||
assert(f.reading_mode == ReadoutMode.UNKNOWN)
|
||||
assert(f.detector_type == DetectorType.Jungfrau)
|
||||
Reference in New Issue
Block a user