mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2026-09-11 20:12:37 +02:00
python bindings for strixel remap
This commit is contained in:
@@ -46,6 +46,8 @@ set(PYTHON_FILES
|
||||
aare/RawFile.py
|
||||
aare/transform.py
|
||||
aare/ScanParameters.py
|
||||
aare/strixelremap/__init__.py
|
||||
aare/strixelremap/SensorConfig.py
|
||||
aare/utils.py)
|
||||
|
||||
# Copy the python files to the build directory
|
||||
|
||||
@@ -67,3 +67,5 @@ from ._aare import (
|
||||
PixelHistogram_u32,
|
||||
PixelHistogram_u64,
|
||||
)
|
||||
|
||||
from . import strixelremap
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
from .._aare import strixelremap
|
||||
|
||||
|
||||
def SensorConfig(sensor_geometry, group_configs):
|
||||
"""
|
||||
Helper function to create a sensor configuration from a sensor geometry and a list of group configurations
|
||||
|
||||
Args:
|
||||
sensor_geometry (SensorPixelGeometry): The sensor geometry
|
||||
group_configs (list[GroupConfig]): The list of group configurations
|
||||
"""
|
||||
|
||||
if(len(group_configs) == 0):
|
||||
raise ValueError("group_configs must contain at least one group configuration")
|
||||
|
||||
N = len(group_configs)
|
||||
|
||||
if N > 4:
|
||||
raise ValueError("sensor configs with more than 4 groups are not bound in Python")
|
||||
|
||||
sensor_config_cls = getattr(strixelremap, f"SensorConfig_{N}PixelGroups")
|
||||
return sensor_config_cls(sensor_geometry, group_configs)
|
||||
@@ -0,0 +1,4 @@
|
||||
from .SensorConfig import SensorConfig
|
||||
|
||||
from .._aare.strixelremap import *
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
#include "aare/InclusiveROI.hpp"
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
// TODO: How to import like aare import StrixelPixelRemap
|
||||
|
||||
void define_InclusiveROI(py::module &m) {
|
||||
py::class_<aare::InclusiveROI>(m, "InclusiveROI")
|
||||
.def(py::init<int, int, int, int>(), py::arg("xmin"), py::arg("xmax"),
|
||||
py::arg("ymin"), py::arg("ymax"))
|
||||
.def_readwrite("xmin", &aare::InclusiveROI::xmin,
|
||||
"minimum x coordinate (inclusive)")
|
||||
.def_readwrite("xmax", &aare::InclusiveROI::xmax,
|
||||
"maximum x coordinate (inclusive)")
|
||||
.def_readwrite("ymin", &aare::InclusiveROI::ymin,
|
||||
"minimum y coordinate (inclusive)")
|
||||
.def_readwrite("ymax", &aare::InclusiveROI::ymax,
|
||||
"maximum y coordinate (inclusive)")
|
||||
|
||||
.def_property_readonly("width", &aare::InclusiveROI::width,
|
||||
"width of the ROI")
|
||||
|
||||
.def_property_readonly("height", &aare::InclusiveROI::height,
|
||||
"height of the ROI")
|
||||
|
||||
.def_property_readonly("size", &aare::InclusiveROI::size,
|
||||
"number of pixels in the ROI")
|
||||
|
||||
.def("is_empty", &aare::InclusiveROI::is_empty,
|
||||
"check if the ROI is empty")
|
||||
|
||||
.def(
|
||||
"contains",
|
||||
[](const aare::InclusiveROI &self, int x, int y) {
|
||||
return self.contains(x, y);
|
||||
},
|
||||
R"(
|
||||
check if a point is contained in the ROI
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : int
|
||||
x coordinate of the point
|
||||
y : int
|
||||
y coordinate of the point
|
||||
|
||||
Returns
|
||||
-------
|
||||
bool
|
||||
True if the point is contained in the ROI, False otherwise
|
||||
)")
|
||||
|
||||
.def(
|
||||
"fits_in",
|
||||
[](const aare::InclusiveROI &self, int ncols, int nrows) {
|
||||
return self.fits_in(ncols, nrows);
|
||||
},
|
||||
R"(
|
||||
check if the ROI fits within a given number of columns and rows
|
||||
Parameters
|
||||
----------
|
||||
ncols : int
|
||||
number of columns
|
||||
nrows : int
|
||||
number of rows
|
||||
Returns
|
||||
-------
|
||||
bool
|
||||
True if the ROI fits within the given dimensions, False otherwise
|
||||
)")
|
||||
|
||||
.def("__eq__", &aare::InclusiveROI::operator==, py::is_operator(),
|
||||
"check if two InclusiveROI objects are equal")
|
||||
|
||||
.def_static("emptyROI", &aare::InclusiveROI::emptyROI,
|
||||
"create an empty InclusiveROI");
|
||||
|
||||
m.def("toInclusiveROI", &toInclusiveROI, py::arg("roi").noconvert(),
|
||||
R"(
|
||||
Convert a half-open ROI to an inclusive ROI
|
||||
|
||||
Parameters
|
||||
----------
|
||||
roi : ROI
|
||||
Half-open ROI to be converted
|
||||
|
||||
Returns
|
||||
-------
|
||||
InclusiveROI
|
||||
Inclusive ROI with the same physical extent
|
||||
)");
|
||||
|
||||
m.def("toHalfopenROI", &toHalfopenROI, py::arg("roi").noconvert(),
|
||||
R"(
|
||||
Convert an inclusive ROI to a half-open ROI
|
||||
|
||||
Parameters
|
||||
----------
|
||||
roi : InclusiveROI
|
||||
Inclusive ROI to be converted
|
||||
|
||||
Returns
|
||||
-------
|
||||
ROI
|
||||
Half-open ROI with the same physical extent
|
||||
)");
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
#include "aare/StrixelPixelRemapConfig.hpp"
|
||||
#include "aare/StrixelPixelRemapGenerate.hpp"
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
void define_predefinedConfigs(py::module &m) {
|
||||
|
||||
// Predefined strixel geometries
|
||||
m.attr("StrxP25") = aare::remap::config::jungfrau::StrxP25;
|
||||
// Strixel geometry for 25 µm pitch strixels on iLGAD sensors (multiplicity
|
||||
// = 3)
|
||||
|
||||
m.attr("StrxP15") = aare::remap::config::jungfrau::StrxP15;
|
||||
//"Strixel geometry for 15 µm pitch strixels on iLGAD sensors "
|
||||
//"(multiplicity = 5)";
|
||||
m.attr("StrxP18") = aare::remap::config::jungfrau::StrxP18;
|
||||
//"Strixel geometry for 18 µm pitch strixels on iLGAD sensors "
|
||||
//"(multiplicity = 4)";
|
||||
m.attr("StrxP37") = aare::remap::config::jungfrau::StrxP37;
|
||||
//"Strixel geometry for 37 µm pitch strixels on iLGAD sensors "
|
||||
//"(multiplicity = 2)";
|
||||
|
||||
// Predefined sensor placements
|
||||
m.attr("Chip1") = aare::remap::config::jungfrau::Chip1;
|
||||
// Placement of the 2x2cm iLGAD sensor on the second chip (Chip1) of the
|
||||
// Jungfrau module with no rotation applied.
|
||||
|
||||
m.attr("Chip6") = aare::remap::config::jungfrau::Chip6;
|
||||
//"Placement of the 2x2cm iLGAD sensor on the seventh chip (Chip6) of "
|
||||
//"the Jungfrau module"
|
||||
//"with a 180-degree rotation applied.";
|
||||
m.attr("Quad") = aare::remap::config::jungfrau::Quad;
|
||||
//"Placement of the 4x4cm iLGAD sensor on the quad "
|
||||
//"(Chip1+Chip2+Chip5+Chip6) of the Jungfrau module"
|
||||
//"with no rotation applied.";
|
||||
|
||||
// Predefined sensor geometries
|
||||
m.attr("SingleChipMP_iLGAD_pix") =
|
||||
aare::remap::config::jungfrau::SingleChipMP_iLGAD_pix;
|
||||
// "Pixel geometry of the 2x2 cm iLGAD sensor";
|
||||
m.attr("Quad_iLGAD_pix") = aare::remap::config::jungfrau::Quad_iLGAD_pix;
|
||||
// "Pixel geometry of the 4x4 cm iLGAD sensor";
|
||||
m.attr("SingleChipMP_TEW_pix") =
|
||||
aare::remap::config::jungfrau::SingleChipMP_TEW_pix;
|
||||
// "Pixel geometry of the 2x2 cm TEW sensor";
|
||||
|
||||
// Predefined strixel groups
|
||||
m.attr("SingleChipMP_iLGAD_P25") =
|
||||
aare::remap::config::jungfrau::SingleChipMP_iLGAD_P25;
|
||||
|
||||
// "Strixel group of 25 µm pitch strixels on the 2x2 cm iLGAD sensor";
|
||||
m.attr("SingleChipMP_iLGAD_P15") =
|
||||
aare::remap::config::jungfrau::SingleChipMP_iLGAD_P15;
|
||||
|
||||
// "Strixel group of 15 µm pitch strixels on the 2x2 cm iLGAD sensor";
|
||||
m.attr("SingleChipMP_iLGAD_P18") =
|
||||
aare::remap::config::jungfrau::SingleChipMP_iLGAD_P18;
|
||||
|
||||
// "Strixel group of 18.75 µm pitch strixels on the 2x2 cm iLGAD sensor";
|
||||
m.attr("SingleChipMP_TEW_P25") =
|
||||
aare::remap::config::jungfrau::SingleChipMP_TEW_P25;
|
||||
|
||||
// "Strixel group of 25 µm pitch strixels on the 2x2 cm TEW sensor";
|
||||
m.attr("SingleChipMP_TEW_P15") =
|
||||
aare::remap::config::jungfrau::SingleChipMP_TEW_P15;
|
||||
// "Strixel group of 15 µm pitch strixels on the 2x2 cm TEW sensor";
|
||||
m.attr("SingleChipMP_TEW_P18") =
|
||||
aare::remap::config::jungfrau::SingleChipMP_TEW_P18;
|
||||
// "Strixel group of 18.75 µm pitch strixels on the 2x2 cm TEW sensor";
|
||||
m.attr("Quad_iLGAD_bottomhalf") =
|
||||
aare::remap::config::jungfrau::Quad_iLGAD_bottomhalf;
|
||||
// "Strixel group of 25 µm pitch strixels located on the bottom half of "
|
||||
// "4x4 cm iLGAD sensor";
|
||||
m.attr("Quad_iLGAD_tophalf") =
|
||||
aare::remap::config::jungfrau::Quad_iLGAD_tophalf;
|
||||
// "Strixel group of 25 µm pitch strixels located on the top half of 4x4 "
|
||||
// "cm iLGAD sensor";
|
||||
|
||||
// Predefined sensor configurations
|
||||
m.attr("SingleChipMP_iLGAD") =
|
||||
aare::remap::config::jungfrau::SingleChipMP_iLGAD;
|
||||
// "Sensor configuration of the 2x2 cm iLGAD sensor with all strixel
|
||||
// groups";
|
||||
m.attr("SingleChipMP_TEW") =
|
||||
aare::remap::config::jungfrau::SingleChipMP_TEW;
|
||||
// "Sensor configuration of the 2x2 cm TEW sensor with all strixel groups";
|
||||
m.attr("Quad_iLGAD") = aare::remap::config::jungfrau::Quad_iLGAD;
|
||||
// "Sensor configuration of the 4x4 cm iLGAD sensor with all strixel "
|
||||
// "groups";
|
||||
}
|
||||
|
||||
void define_predefinedStrixelPixelMaps(py::module &m) {
|
||||
m.attr("jungfrau_ilgad_singlechip_25um_strixel_map") = py::cpp_function(
|
||||
&aare::remap::generate::jungfrau_ilgad_singlechip_25um_strixel_map,
|
||||
py::arg("user_roi").noconvert(), py::arg("placement").noconvert(),
|
||||
py::arg("bond_shift").noconvert() = aare::remap::defs::BondShift{0, 0},
|
||||
R"(
|
||||
Generates a strixel-to-pixel remapping map for the Strx25 strixel group on a Jungfrau ILGAD sensor
|
||||
Parameters
|
||||
----------
|
||||
user_roi : InclusiveROI
|
||||
ROI in global module coordinate system.
|
||||
placement : SensorModulePlacement
|
||||
Placement and orientation of the sensor on the module.
|
||||
bond_shift : BondShift, optional
|
||||
Bonding shift applied before the configured sensor placement rotation. Default is (0, 0).
|
||||
Returns
|
||||
-------
|
||||
StrixelGroupToPixelMap
|
||||
map(row, col) contains the flattened pixel index of the corresponding source pixel in the user-provided input ROI for strixel defined at (row, col).
|
||||
An entry of -1 indicates that the corresponding strixel position has no valid source pixel.
|
||||
)");
|
||||
|
||||
m.attr("jungfrau_ilgad_singlechip_15um_strixel_map") = py::cpp_function(
|
||||
&aare::remap::generate::jungfrau_ilgad_singlechip_15um_strixel_map,
|
||||
py::arg("user_roi").noconvert(), py::arg("placement").noconvert(),
|
||||
py::arg("bond_shift").noconvert() = aare::remap::defs::BondShift{0, 0},
|
||||
R"(
|
||||
Generates a strixel-to-pixel remapping map for the Strx15 strixel group on a Jungfrau ILGAD sensor
|
||||
Parameters
|
||||
----------
|
||||
user_roi : InclusiveROI
|
||||
ROI in global module coordinate system.
|
||||
placement : SensorModulePlacement
|
||||
Placement and orientation of the sensor on the module.
|
||||
bond_shift : BondShift, optional
|
||||
Bonding shift applied before the configured sensor placement rotation. Default is (0, 0).
|
||||
Returns
|
||||
-------
|
||||
StrixelGroupToPixelMap
|
||||
map(row, col) contains the flattened pixel index of the corresponding source pixel in the user-provided input ROI for strixel defined at (row, col).
|
||||
An entry of -1 indicates that the corresponding strixel position has no valid source pixel.
|
||||
)");
|
||||
|
||||
m.attr("jungfrau_ilgad_singlechip_18um_strixel_map") = py::cpp_function(
|
||||
&aare::remap::generate::jungfrau_ilgad_singlechip_18um_strixel_map,
|
||||
py::arg("user_roi").noconvert(), py::arg("placement").noconvert(),
|
||||
py::arg("bond_shift").noconvert() = aare::remap::defs::BondShift{0, 0},
|
||||
R"(
|
||||
Generates a strixel-to-pixel remapping map for the Strx18 strixel group on a Jungfrau ILGAD sensor
|
||||
Parameters
|
||||
----------
|
||||
user_roi : InclusiveROI
|
||||
ROI in global module coordinate system.
|
||||
placement : SensorModulePlacement
|
||||
Placement and orientation of the sensor on the module.
|
||||
bond_shift : BondShift, optional
|
||||
Bonding shift applied before the configured sensor placement rotation. Default is (0, 0).
|
||||
Returns
|
||||
-------
|
||||
StrixelGroupToPixelMap
|
||||
map(row, col) contains the flattened pixel index of the corresponding source pixel in the user-provided input ROI for strixel defined at (row, col).
|
||||
An entry of -1 indicates that the corresponding strixel position has no valid source pixel.
|
||||
)");
|
||||
|
||||
m.attr("jungfrau_ilgad_strixel_maps") = py::cpp_function(
|
||||
&aare::remap::generate::jungfrau_ilgad_quad_25um_strixel_map,
|
||||
py::arg("user_roi").noconvert(), py::arg("placement").noconvert(),
|
||||
py::arg("bond_shift").noconvert() = aare::remap::defs::BondShift{0, 0},
|
||||
R"(
|
||||
Generates a list of strixel-to-pixel remapping map for each strixel group on a Jungfrau ILGAD quad sensor
|
||||
Parameters
|
||||
----------
|
||||
user_roi : InclusiveROI
|
||||
ROI in global module coordinate system.
|
||||
placement : SensorModulePlacement
|
||||
Placement and orientation of the sensor on the module.
|
||||
bond_shift : BondShift, optional
|
||||
Bonding shift applied before the configured sensor placement rotation. Default is (0, 0).
|
||||
Returns
|
||||
-------
|
||||
list[StrixelGroupToPixelMap]
|
||||
A list of StrixelGroupToPixelMap, one for each strixel group on the sensor.
|
||||
Each map(row, col) contains the flattened pixel index of the corresponding source pixel in the user-provided input ROI for strixel defined at (row, col).
|
||||
An entry of -1 indicates that the corresponding strixel position has no valid source pixel.
|
||||
)");
|
||||
|
||||
// TEW sensor strixel maps
|
||||
m.attr("jungfrau_tew_singlechip_25um_strixel_map") = py::cpp_function(
|
||||
&aare::remap::generate::jungfrau_tew_singlechip_25um_strixel_map,
|
||||
py::arg("user_roi").noconvert(), py::arg("placement").noconvert(),
|
||||
py::arg("bond_shift").noconvert() = aare::remap::defs::BondShift{0, 0},
|
||||
R"(
|
||||
Generates a strixel-to-pixel remapping map for the Strx25 strixel group on a Jungfrau TEW sensor
|
||||
Parameters
|
||||
----------
|
||||
user_roi : InclusiveROI
|
||||
ROI in global module coordinate system.
|
||||
placement : SensorModulePlacement
|
||||
Placement and orientation of the sensor on the module.
|
||||
bond_shift : BondShift, optional
|
||||
Bonding shift applied before the configured sensor placement rotation. Default is (0, 0).
|
||||
Returns
|
||||
-------
|
||||
StrixelGroupToPixelMap
|
||||
map(row, col) contains the flattened pixel index of the corresponding source pixel in the user-provided input ROI for strixel defined at (row, col).
|
||||
An entry of -1 indicates that the corresponding strixel position has no valid source pixel.
|
||||
)");
|
||||
|
||||
m.attr("jungfrau_tew_singlechip_15um_strixel_map") = py::cpp_function(
|
||||
&aare::remap::generate::jungfrau_tew_singlechip_15um_strixel_map,
|
||||
py::arg("user_roi").noconvert(), py::arg("placement").noconvert(),
|
||||
py::arg("bond_shift").noconvert() = aare::remap::defs::BondShift{0, 0},
|
||||
R"(
|
||||
Generates a strixel-to-pixel remapping map for the Strx15 strixel group on a Jungfrau TEW sensor
|
||||
Parameters
|
||||
----------
|
||||
user_roi : InclusiveROI
|
||||
ROI in global module coordinate system.
|
||||
placement : SensorModulePlacement
|
||||
Placement and orientation of the sensor on the module.
|
||||
bond_shift : BondShift, optional
|
||||
Bonding shift applied before the configured sensor placement rotation. Default is (0, 0).
|
||||
Returns
|
||||
-------
|
||||
StrixelGroupToPixelMap
|
||||
map(row, col) contains the flattened pixel index of the corresponding source pixel in the user-provided input ROI for strixel defined at (row, col).
|
||||
An entry of -1 indicates that the corresponding strixel position has no valid source pixel.
|
||||
)");
|
||||
|
||||
m.attr("jungfrau_tew_singlechip_18um_strixel_map") = py::cpp_function(
|
||||
&aare::remap::generate::jungfrau_tew_singlechip_18um_strixel_map,
|
||||
py::arg("user_roi").noconvert(), py::arg("placement").noconvert(),
|
||||
py::arg("bond_shift").noconvert() = aare::remap::defs::BondShift{0, 0},
|
||||
R"(
|
||||
Generates a strixel-to-pixel remapping map for the Strx18 strixel group on a Jungfrau TEW sensor
|
||||
Parameters
|
||||
----------
|
||||
user_roi : InclusiveROI
|
||||
ROI in global module coordinate system.
|
||||
placement : SensorModulePlacement
|
||||
Placement and orientation of the sensor on the module.
|
||||
bond_shift : BondShift, optional
|
||||
Bonding shift applied before the configured sensor placement rotation. Default is (0, 0).
|
||||
Returns
|
||||
-------
|
||||
StrixelGroupToPixelMap
|
||||
map(row, col) contains the flattened pixel index of the corresponding source pixel in the user-provided input ROI for strixel defined at (row, col).
|
||||
An entry of -1 indicates that the corresponding strixel position has no valid source pixel.
|
||||
)");
|
||||
|
||||
m.attr("jungfrau_tew_strixel_maps") = py::cpp_function(
|
||||
&aare::remap::generate::jungfrau_tew_singlechip_multipitch_strixel_maps,
|
||||
py::arg("user_roi").noconvert(), py::arg("placement").noconvert(),
|
||||
py::arg("bond_shift").noconvert() = aare::remap::defs::BondShift{0, 0},
|
||||
R"(
|
||||
Generates a list of strixel-to-pixel remapping map for each strixel group on a Jungfrau TEW sensor
|
||||
Parameters
|
||||
----------
|
||||
user_roi : InclusiveROI
|
||||
ROI in global module coordinate system.
|
||||
placement : SensorModulePlacement
|
||||
Placement and orientation of the sensor on the module.
|
||||
bond_shift : BondShift, optional
|
||||
Bonding shift applied before the configured sensor placement rotation. Default is (0, 0).
|
||||
Returns
|
||||
-------
|
||||
list[StrixelGroupToPixelMap]
|
||||
A list of StrixelGroupToPixelMap, one for each strixel group on the sensor.
|
||||
Each map(row, col) contains the flattened pixel index of the corresponding source pixel in the user-provided input ROI for strixel defined at (row, col).
|
||||
An entry of -1 indicates that the corresponding strixel position has no valid source pixel.
|
||||
)");
|
||||
|
||||
// Jungfrau quad sensor strixel maps
|
||||
m.attr("jungfrau_ilgad_quadbottom_25um_strixel_map") = py::cpp_function(
|
||||
&aare::remap::generate::jungfrau_ilgad_quadbottom_25um_strixel_map,
|
||||
py::arg("user_roi").noconvert(), py::arg("placement").noconvert(),
|
||||
py::arg("bond_shift").noconvert() = aare::remap::defs::BondShift{0, 0},
|
||||
R"(
|
||||
Generates a strixel-to-pixel remapping map for the bottom half of the Strx25 strixel group on a Jungfrau ILGAD quad sensor
|
||||
Parameters
|
||||
----------
|
||||
user_roi : InclusiveROI
|
||||
ROI in global module coordinate system.
|
||||
placement : SensorModulePlacement
|
||||
Placement and orientation of the sensor on the module.
|
||||
bond_shift : BondShift, optional
|
||||
Bonding shift applied before the configured sensor placement rotation. Default is (0, 0).
|
||||
Returns
|
||||
-------
|
||||
StrixelGroupToPixelMap
|
||||
map(row, col) contains the flattened pixel index of the corresponding source pixel in the user-provided input ROI for strixel defined at (row, col).
|
||||
An entry of -1 indicates that the corresponding strixel position has no valid source pixel.
|
||||
)");
|
||||
|
||||
m.attr("jungfrau_ilgad_quadtop_25um_strixel_map") = py::cpp_function(
|
||||
&aare::remap::generate::jungfrau_ilgad_quadtop_25um_strixel_map,
|
||||
py::arg("user_roi").noconvert(), py::arg("placement").noconvert(),
|
||||
py::arg("bond_shift").noconvert() = aare::remap::defs::BondShift{0, 0},
|
||||
R"(
|
||||
Generates a strixel-to-pixel remapping map for the top half of the Strx25 strixel group on a Jungfrau ILGAD quad sensor
|
||||
Parameters
|
||||
----------
|
||||
user_roi : InclusiveROI
|
||||
ROI in global module coordinate system.
|
||||
placement : SensorModulePlacement
|
||||
Placement and orientation of the sensor on the module.
|
||||
bond_shift : BondShift, optional
|
||||
Bonding shift applied before the configured sensor placement rotation. Default is (0, 0).
|
||||
Returns
|
||||
-------
|
||||
StrixelGroupToPixelMap
|
||||
map(row, col) contains the flattened pixel index of the corresponding source pixel in the user-provided input ROI for strixel defined at (row, col).
|
||||
An entry of -1 indicates that the corresponding strixel position has no valid source pixel.
|
||||
)");
|
||||
|
||||
m.attr("jungfrau_ilgad_quad_25um_strixel_map") = py::cpp_function(
|
||||
&aare::remap::generate::jungfrau_ilgad_quad_25um_strixel_map,
|
||||
py::arg("user_roi").noconvert(), py::arg("placement").noconvert(),
|
||||
py::arg("bond_shift").noconvert() = aare::remap::defs::BondShift{0, 0},
|
||||
R"(
|
||||
Generates a strixel-to-pixel remapping map for the entire Strx25 strixel group on a Jungfrau ILGAD quad sensor
|
||||
Parameters
|
||||
----------
|
||||
user_roi : InclusiveROI
|
||||
ROI in global module coordinate system.
|
||||
placement : SensorModulePlacement
|
||||
Placement and orientation of the sensor on the module.
|
||||
bond_shift : BondShift, optional
|
||||
Bonding shift applied before the configured sensor placement rotation. Default is (0, 0).
|
||||
Returns
|
||||
-------
|
||||
StrixelGroupToPixelMap
|
||||
combined maps of the bottom and top halves of the Strx25 strixel group on a Jungfrau ILGAD quad sensor.
|
||||
map(row, col) contains the flattened pixel index of the corresponding source pixel in the user-provided input ROI for strixel defined at (row, col).
|
||||
An entry of -1 indicates that the corresponding strixel position has no valid source pixel.
|
||||
)");
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
#include "aare/StrixelPixelRemapDefs.hpp"
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
// TODO: How to import like aare import StrixelPixelRemap
|
||||
|
||||
void define_PixelStrixelMapDefs(py::module &m) {
|
||||
|
||||
py::enum_<aare::remap::defs::Rotation>(m, "Rotation")
|
||||
.value("Identity", aare::remap::defs::Rotation::Identity)
|
||||
.value("Rotate180", aare::remap::defs::Rotation::Rotate180)
|
||||
.export_values();
|
||||
|
||||
py::enum_<aare::remap::defs::ModuloOrdering>(m, "ModuloOrdering")
|
||||
.value("Forward", aare::remap::defs::ModuloOrdering::Forward)
|
||||
.value("Reverse", aare::remap::defs::ModuloOrdering::Reverse)
|
||||
.export_values();
|
||||
|
||||
py::class_<aare::remap::defs::Guardring>(m, "Guardring")
|
||||
.def(py::init<int, int>(), py::arg("x"), py::arg("y"))
|
||||
.def_readwrite("x", &aare::remap::defs::Guardring::x,
|
||||
"ring width in pixels")
|
||||
.def_readwrite("y", &aare::remap::defs::Guardring::y,
|
||||
"ring height in pixels")
|
||||
.def(
|
||||
"__eq__",
|
||||
[](const aare::remap::defs::Guardring &self,
|
||||
const aare::remap::defs::Guardring &other) {
|
||||
return self.x == other.x && self.y == other.y;
|
||||
},
|
||||
py::is_operator())
|
||||
|
||||
.def("__repr__", [](const aare::remap::defs::Guardring &self) {
|
||||
return fmt::format("Guardring(x={}, y={})", self.x, self.y);
|
||||
});
|
||||
|
||||
py::class_<aare::remap::defs::BondShift>(m, "BondShift")
|
||||
.def(py::init<int, int>(), py::arg("x"), py::arg("y"))
|
||||
.def_readwrite("x", &aare::remap::defs::BondShift::x,
|
||||
"bond shift in x direction (pixels)")
|
||||
.def_readwrite("y", &aare::remap::defs::BondShift::y,
|
||||
"bond shift in y direction (pixels)");
|
||||
|
||||
py::class_<aare::remap::defs::SensorPixelGeometry>(m, "SensorPixelGeometry")
|
||||
.def(py::init<int, int, aare::remap::defs::Guardring>(),
|
||||
py::arg("num_pix_x"), py::arg("num_pix_y"),
|
||||
py::arg("guardring") = aare::remap::defs::Guardring{0, 0})
|
||||
.def_readwrite("num_pix_x",
|
||||
&aare::remap::defs::SensorPixelGeometry::num_pix_x,
|
||||
"number of pixels in x direction")
|
||||
.def_readwrite("num_pix_y",
|
||||
&aare::remap::defs::SensorPixelGeometry::num_pix_y,
|
||||
"number of pixels in y direction")
|
||||
.def_readwrite(
|
||||
"guardring", &aare::remap::defs::SensorPixelGeometry::guardring,
|
||||
"physical guardring around the sensor (default Guardring(0,0))");
|
||||
|
||||
py::class_<aare::remap::defs::GroupStrixelGeometry>(m,
|
||||
"GroupStrixelGeometry")
|
||||
.def(py::init<int, double>(), py::arg("multiplicity"),
|
||||
py::arg("pitch_um"))
|
||||
.def_readwrite("multiplicity",
|
||||
&aare::remap::defs::GroupStrixelGeometry::multiplicity,
|
||||
"maximum number of pixels a strixel covers")
|
||||
.def_readwrite("pitch_um",
|
||||
&aare::remap::defs::GroupStrixelGeometry::pitch_um,
|
||||
"effective minimal strixel pitch [µm]");
|
||||
|
||||
py::class_<aare::remap::defs::GroupRouting>(m, "GroupRouting")
|
||||
.def(py::init<aare::remap::defs::ModuloOrdering>(),
|
||||
py::arg("mod_order") = aare::remap::defs::ModuloOrdering::Forward)
|
||||
.def_readwrite(
|
||||
"mod_order", &aare::remap::defs::GroupRouting::mod_order,
|
||||
"modulo ordering of pixels within each strixel multiplicity group "
|
||||
"default(ModuloOrdering::Forward)");
|
||||
|
||||
py::class_<aare::remap::defs::GroupConfig>(m, "GroupConfig")
|
||||
.def(py::init<aare::remap::defs::GroupStrixelGeometry,
|
||||
aare::remap::defs::GroupRouting, aare::InclusiveROI>(),
|
||||
py::arg("strixel"), py::arg("routing"),
|
||||
py::arg("placement_on_sensor"))
|
||||
|
||||
.def(py::init([](const aare::remap::defs::GroupStrixelGeometry &strixel,
|
||||
const aare::remap::defs::ModuloOrdering &mod_order,
|
||||
const aare::InclusiveROI &placement_on_sensor) {
|
||||
return aare::remap::defs::GroupConfig{
|
||||
strixel, {mod_order}, placement_on_sensor};
|
||||
}),
|
||||
py::arg("strixel"), py::arg("routing"),
|
||||
py::arg("placement_on_sensor"))
|
||||
.def_readwrite("strixel", &aare::remap::defs::GroupConfig::strixel,
|
||||
"strixel geometry of the group")
|
||||
.def_readwrite("routing", &aare::remap::defs::GroupConfig::routing,
|
||||
"pixel-to-strixel routing pattern")
|
||||
.def_readwrite(
|
||||
"placement_on_sensor",
|
||||
&aare::remap::defs::GroupConfig::placement_on_sensor,
|
||||
"placement of the strixel group on the sensor (sensor-local "
|
||||
"coordinates)");
|
||||
|
||||
py::class_<aare::remap::defs::SensorModulePlacement>(
|
||||
m, "SensorModulePlacement")
|
||||
.def(py::init<aare::InclusiveROI, aare::remap::defs::Rotation>(),
|
||||
py::arg("placement_on_module"), py::arg("rotation"))
|
||||
.def_readwrite(
|
||||
"placement_on_module",
|
||||
&aare::remap::defs::SensorModulePlacement::placement_on_module,
|
||||
"sensor bounds in module coordinates")
|
||||
.def_readwrite(
|
||||
"rotation", &aare::remap::defs::SensorModulePlacement::rotation,
|
||||
"physical orientation of the mounted sensor-ASIC assembly with "
|
||||
"respect to the module reference frame");
|
||||
|
||||
py::class_<aare::remap::defs::StrixelGroupToPixelMap>(
|
||||
m, "StrixelGroupToPixelMap")
|
||||
.def(py::init<>())
|
||||
.def_readonly("effective_roi",
|
||||
&aare::remap::defs::StrixelGroupToPixelMap::effective_roi,
|
||||
"effective pixel ROI covered by this map (InclusiveROI)")
|
||||
|
||||
.def_property_readonly(
|
||||
"map",
|
||||
[](const aare::remap::defs::StrixelGroupToPixelMap &self)
|
||||
-> py::array {
|
||||
return py::array_t<ssize_t>(
|
||||
self.map.shape(), self.map.data(),
|
||||
py::cast(&self, py::return_value_policy::reference));
|
||||
});
|
||||
}
|
||||
|
||||
template <std::size_t N> void define_SensorConfig(py::module &m) {
|
||||
const auto class_name = fmt::format("SensorConfig_{}PixelGroups", N);
|
||||
py::class_<aare::remap::defs::SensorConfig<N>>(m, class_name.c_str())
|
||||
.def(py::init<aare::remap::defs::SensorPixelGeometry,
|
||||
std::array<aare::remap::defs::GroupConfig, N>>(),
|
||||
py::arg("pixel"), py::arg("group_configs"))
|
||||
.def_readwrite("pixel", &aare::remap::defs::SensorConfig<N>::pixel,
|
||||
"sensor pixel geometry (SensorPixelGeometry)")
|
||||
.def_readwrite("group_configs",
|
||||
&aare::remap::defs::SensorConfig<N>::group_configs,
|
||||
"[list] of strixel group configurations");
|
||||
}
|
||||
|
||||
void define_RemapAlgorithm(py::module &m) {
|
||||
|
||||
m.def("strixel_to_pixel_map", &aare::remap::algo::strixel_to_pixel_map,
|
||||
py::arg("group_config").noconvert(), py::arg("pixel").noconvert(),
|
||||
py::arg("placement").noconvert(), py::arg("user_roi").noconvert(),
|
||||
py::arg("bond_shift").noconvert() =
|
||||
aare::remap::defs::BondShift{0, 0},
|
||||
R"(
|
||||
Creates a StrixeltoPixelMap for a specific GroupConfig
|
||||
|
||||
Parameters
|
||||
----------
|
||||
group_config : GroupConfig
|
||||
Configuration of the strixel group.
|
||||
pixel : SensorPixelGeometry
|
||||
Pixel geometry of the sensor.
|
||||
placement : SensorModulePlacement
|
||||
Placement and orientation of the sensor on the module.
|
||||
user_roi : InclusiveROI
|
||||
User-defined region of interest. (in global module coordinates)
|
||||
bond_shift : BondShift, optional
|
||||
Shift applied to the bond positions. Default is (0, 0).
|
||||
|
||||
Returns
|
||||
-------
|
||||
StrixelGroupToPixelMap
|
||||
map(row, col) contains the flattened pixel index of the corresponding source pixel in the user-provided input ROI for strixel defined at (row, col).
|
||||
An entry of -1 indicates that the corresponding strixel position has no valid source pixel.
|
||||
|
||||
)");
|
||||
|
||||
// cant use np.take or have to mask -1 indices
|
||||
m.def(
|
||||
"ApplyRemap",
|
||||
[](py::array input,
|
||||
py::array_t<ssize_t, py::array::c_style | py::array::forcecast>
|
||||
order_map,
|
||||
py::array output) {
|
||||
if (!(input.flags() & py::array::c_style) ||
|
||||
!(output.flags() & py::array::c_style)) {
|
||||
throw std::runtime_error("Arrays must be C-contiguous");
|
||||
}
|
||||
|
||||
if (input.ndim() != 2 || output.ndim() != 2) {
|
||||
throw std::runtime_error("Input and output arrays must be 2D");
|
||||
}
|
||||
|
||||
auto i_dtype = input.dtype();
|
||||
auto o_dtype = output.dtype();
|
||||
|
||||
if (!input.dtype().is(output.dtype())) {
|
||||
throw std::runtime_error(
|
||||
"Input and output arrays must have the same dtype");
|
||||
}
|
||||
|
||||
auto input_array =
|
||||
py::array_t<uint16_t, py::array::c_style |
|
||||
py::array::forcecast>::ensure(input);
|
||||
auto output_array =
|
||||
py::array_t<uint16_t, py::array::c_style |
|
||||
py::array::forcecast>::ensure(output);
|
||||
|
||||
aare::remap::algo::ApplyRemap(
|
||||
make_view_2d(input_array), // TODO expecting uint16_t for now
|
||||
make_view_2d(order_map), make_view_2d(output_array));
|
||||
},
|
||||
py::arg("input").noconvert(), py::arg("order_map").noconvert(),
|
||||
py::arg("output").noconvert(),
|
||||
R"(
|
||||
Applies a given remapping rule to an input array.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
input : np.array
|
||||
Original array
|
||||
order_map : np.array[ssize_t, 2]
|
||||
Rule for remapping
|
||||
output : np.array
|
||||
Remapped array
|
||||
|
||||
)");
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
void define_RemapAlgorithmforSensorConfig(py::module &m) {
|
||||
|
||||
m.def("strixel_to_pixel_maps", &aare::remap::algo::strixel_to_pixel_maps<N>,
|
||||
py::arg("sensor_config").noconvert(),
|
||||
py::arg("placement").noconvert(), py::arg("user_roi").noconvert(),
|
||||
py::arg("bond_shift").noconvert() =
|
||||
aare::remap::defs::BondShift{0, 0},
|
||||
R"(
|
||||
Creates a StrixeltoPixelMap for all GroupConfigs in a SensorConfig
|
||||
|
||||
Parameters
|
||||
----------
|
||||
sensor_config : SensorConfig
|
||||
Configuration of the sensor, including all configurations of the strixel groups.
|
||||
placement : SensorModulePlacement
|
||||
Placement and orientation of the sensor on the module.
|
||||
user_roi : InclusiveROI
|
||||
User-defined region of interest. (in global module coordinates)
|
||||
bond_shift : BondShift, optional
|
||||
Shift applied to the bond positions. Default is (0, 0).
|
||||
|
||||
Returns
|
||||
-------
|
||||
list of StrixelGroupToPixelMap
|
||||
map(row, col) contains the flattened pixel index of the corresponding source pixel in the user-provided input ROI for strixel defined at (row, col).
|
||||
An entry of -1 indicates that the corresponding strixel position has no valid source pixel.
|
||||
|
||||
)");
|
||||
}
|
||||
@@ -22,6 +22,10 @@
|
||||
#include "bind_RawFile.hpp"
|
||||
#include "bind_calibration.hpp"
|
||||
|
||||
#include "StrixelRemap/bind_InclusiveROI.hpp"
|
||||
#include "StrixelRemap/bind_PredefinedVariables.hpp"
|
||||
#include "StrixelRemap/bind_StrixelRemap.hpp"
|
||||
|
||||
// TODO! migrate the other names
|
||||
#include "ctb_raw_file.hpp"
|
||||
#include "file.hpp"
|
||||
@@ -63,6 +67,10 @@ double, 'f' for float)
|
||||
define_ClusterFileSink<T, N, M, U>(m, "Cluster" #N "x" #M #TYPE_CODE); \
|
||||
define_ClusterCollector<T, N, M, U>(m, "Cluster" #N "x" #M #TYPE_CODE);
|
||||
|
||||
#define DEFINE_BINDINGS_SENSORCONFIG(N) \
|
||||
define_SensorConfig<N>(strixelremap); \
|
||||
define_RemapAlgorithmforSensorConfig<N>(strixelremap);
|
||||
|
||||
PYBIND11_MODULE(_aare, m) {
|
||||
auto experimental = m.def_submodule(
|
||||
"experimental", "Experimental APIs that may change without notice");
|
||||
@@ -182,4 +190,17 @@ PYBIND11_MODULE(_aare, m) {
|
||||
define_eta<double>(m, "d");
|
||||
define_eta<int>(m, "i");
|
||||
define_eta<int16_t>(m, "i16");
|
||||
|
||||
auto strixelremap =
|
||||
m.def_submodule("strixelremap", "Strixel remapping utilities.");
|
||||
|
||||
define_InclusiveROI(strixelremap);
|
||||
define_PixelStrixelMapDefs(strixelremap);
|
||||
define_RemapAlgorithm(strixelremap);
|
||||
DEFINE_BINDINGS_SENSORCONFIG(1);
|
||||
DEFINE_BINDINGS_SENSORCONFIG(2);
|
||||
DEFINE_BINDINGS_SENSORCONFIG(4);
|
||||
DEFINE_BINDINGS_SENSORCONFIG(3);
|
||||
define_predefinedConfigs(strixelremap);
|
||||
define_predefinedStrixelPixelMaps(strixelremap);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import pytest
|
||||
|
||||
import numpy as np
|
||||
|
||||
from aare import strixelremap
|
||||
from aare import ROI
|
||||
|
||||
def test_roimappings():
|
||||
""" Test exclusive to inclusive roi mapping and vice versa """
|
||||
|
||||
roi = ROI(0, 10, 0, 5)
|
||||
|
||||
inclusive_roi = strixelremap.toInclusiveROI(roi)
|
||||
|
||||
assert inclusive_roi.xmin == 0
|
||||
assert inclusive_roi.xmax == 9
|
||||
assert inclusive_roi.ymin == 0
|
||||
assert inclusive_roi.ymax == 4
|
||||
|
||||
exclusive_roi = strixelremap.toHalfopenROI(inclusive_roi)
|
||||
|
||||
assert exclusive_roi.xmin == 0
|
||||
assert exclusive_roi.xmax == 10
|
||||
assert exclusive_roi.ymin == 0
|
||||
assert exclusive_roi.ymax == 5
|
||||
|
||||
def test_emptyROI():
|
||||
""" Test creation of an empty ROI """
|
||||
|
||||
empty_roi = strixelremap.InclusiveROI.emptyROI()
|
||||
|
||||
assert empty_roi.xmin == 0
|
||||
assert empty_roi.xmax == -1
|
||||
assert empty_roi.ymin == 0
|
||||
assert empty_roi.ymax == -1
|
||||
|
||||
def test_customSensorConfiguration():
|
||||
""" Test that a custom sensor configuration can be created and used to remap strixel pixels """
|
||||
|
||||
my_strixel_group = strixelremap.GroupStrixelGeometry(multiplicity=2, pitch_um=25.0)
|
||||
|
||||
assert my_strixel_group.multiplicity == 2
|
||||
assert my_strixel_group.pitch_um == 25.0
|
||||
|
||||
my_sensor_geometry = strixelremap.SensorPixelGeometry(num_pix_x = 10, num_pix_y = 5)
|
||||
|
||||
assert my_sensor_geometry.num_pix_x == 10
|
||||
assert my_sensor_geometry.num_pix_y == 5
|
||||
assert my_sensor_geometry.guardring == strixelremap.Guardring(0,0)
|
||||
|
||||
my_group_config = strixelremap.GroupConfig(strixel = my_strixel_group, routing = strixelremap.ModuloOrdering.Forward,placement_on_sensor = strixelremap.InclusiveROI(0,9,0,4))
|
||||
|
||||
my_sensor_config = strixelremap.SensorConfig(sensor_geometry = my_sensor_geometry, group_configs = [my_group_config])
|
||||
|
||||
# rebase
|
||||
user_roi = strixelremap.InclusiveROI(strixelremap.Chip1.placement_on_module.xmin + 0, strixelremap.Chip1.placement_on_module.xmin + 9, strixelremap.Chip1.placement_on_module.ymin + 0, strixelremap.Chip1.placement_on_module.ymin + 4)
|
||||
|
||||
strixelpixelmap = strixelremap.strixel_to_pixel_maps(sensor_config = my_sensor_config, placement = strixelremap.Chip1, user_roi = user_roi)
|
||||
|
||||
assert len(strixelpixelmap) == 1
|
||||
|
||||
assert strixelpixelmap[0].effective_roi == my_group_config.placement_on_sensor
|
||||
|
||||
map = strixelpixelmap[0].map
|
||||
assert map.shape == (10 ,5)
|
||||
|
||||
assert np.array_equal(map, np.array([[0, 2, 4, 6, 8], [1, 3, 5, 7, 9], [10, 12, 14, 16, 18], [11, 13, 15, 17, 19], [20, 22, 24, 26, 28], [21, 23, 25, 27, 29], [30, 32, 34, 36, 38], [31, 33, 35, 37, 39], [40, 42, 44, 46, 48], [41, 43, 45, 47, 49]]))
|
||||
|
||||
def test_predefinedRemap():
|
||||
""" Test predefined maps API """
|
||||
|
||||
user_roi = strixelremap.InclusiveROI(strixelremap.Chip1.placement_on_module.xmin + 5, strixelremap.Chip1.placement_on_module.xmin + 9, strixelremap.Chip1.placement_on_module.ymin + 5, strixelremap.Chip1.placement_on_module.ymin + 7)
|
||||
strixelpixelmap = strixelremap.jungfrau_tew_singlechip_25um_strixel_map(user_roi = user_roi, placement = strixelremap.Chip1)
|
||||
|
||||
print(strixelpixelmap.map)
|
||||
|
||||
assert strixelpixelmap.map.shape == (9, 2)
|
||||
|
||||
assert np.array_equal(strixelpixelmap.map, np.array([[-1, 2], [0, 3], [1, 4], [-1, 7], [5,8], [6,9], [-1,12], [10,13], [11,14]]))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# test apply remap
|
||||
|
||||
|
||||
# Documenation, Example
|
||||
Reference in New Issue
Block a user