outline python class a bit

This commit is contained in:
2026-07-01 18:46:38 +02:00
parent 8834b59069
commit edc8cfa5fd
6 changed files with 145 additions and 95 deletions
+3 -1
View File
@@ -47,8 +47,10 @@ add_library(jungfraucalibration STATIC ${SourceFiles} ${PUBLICHEADERS})
target_include_directories(
jungfraucalibration PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>")
target_link_libraries(jungfraucalibration PRIVATE aare_core) # TODO: should it be public?
target_link_libraries(jungfraucalibration PUBLIC aare_core) # TODO: should it be public?
# TODO: add other compile options?
target_compile_features(jungfraucalibration PRIVATE cxx_std_17)
#add_subdirectory(examples)
+3 -3
View File
@@ -1,14 +1,14 @@
#include "aare/JungfrauDataFile.hpp"
#include "aare/utils/SparseMask.hpp"
#include "aare/NDArray.hpp"
using namespace aare;
namespace jungfraucalibration
{
SparseMask CreateBadChannelPixelMask(JungfrauDataFile &pedestal_file, const size_t num_pedestals_g0, const size_t num_pedestals_g1, const size_t num_pedestals_g2);
NDArray<bool, 2> CreateBadChannelPixelMask(JungfrauDataFile &pedestal_file, const size_t num_pedestals_g0, const size_t num_pedestals_g1, const size_t num_pedestals_g2);
SparseMask CreateBadChannelPixelMask(JungfrauDataFile &pedestals_g0_file, const JungfrauDataFile &pedestals_g1_file, const JungfrauDataFile &pedestal_g2_file);
NDArray<bool, 2> CreateBadChannelPixelMask(JungfrauDataFile &pedestals_g0_file, const JungfrauDataFile &pedestals_g1_file, const JungfrauDataFile &pedestal_g2_file);
} // namespace jungfraucalibration
View File
+54 -82
View File
@@ -1,108 +1,77 @@
from pathlib import Path
import JungfrauCalibrationParameters
from aare import JungfrauDataFile
from helpers import get_first_file
import numpy as np
class JungfrauCalibrationParameters:
"""
A class to hold calibration parameters for the Jungfrau detector.
"""
from aare.calibration import get_gain
@property
def pedestal_file_dir(self) -> Path:
return self._pedestal_file_dir
@pedestal_file_dir.setter
def pedestal_file_dir(self, filepath : Path):
if not filepath.exists():
raise ValueError(f"Pedestal file directory {filepath} does not exist.")
self._pedestal_file_dir = filepath
class JungfrauCalibration:
@property
def pedestal_g0_file_prefix(self) -> str:
return self._pedestal_g0_file_prefix
def __init__(self, calibration_params: JungfrauCalibrationParameters):
self.calibration_params = calibration_params
self.bad_channel_mask : np.ndarray
self.histogram : np.ndarray
@pedestal_g0_file_prefix.setter
def pedestal_g0_file_prefix(self, file_prefix : str):
self._pedestal_g0_file_prefix = file_prefix
# TODO: add deprecated decorator
@property
def pedestal_file_prefix(self) -> str:
return self._pedestal_file_prefix
@pedestal_file_prefix.setter
def pedestal_file_prefix(self, file_prefix : str):
self._pedestal_file_prefix = file_prefix
@property
def num_pedestals_g0(self) -> int:
return self._num_pedestals_g0
@num_pedestals_g0.setter
def num_pedestals_g0(self, num_pedestals : int):
self._num_pedestals_g0 = num_pedestals
# TODO: maybe pass num pedestals, pedestal file instead of calibration params?
def calculate_bad_pixels_mask(self) -> np.ndarray:
"""
Calculate the bad pixels mask for the Jungfrau detector.
@property
def num_pedestals_g1(self) -> int:
return self._num_pedestals_g1
@num_pedestals_g1.setter
def num_pedestals_g1(self, num_pedestals : int):
self._num_pedestals_g1 = num_pedestals
Returns:
np.ndarray: A boolean array where True indicates a bad pixel.
"""
if(self.calibration_params.num_pedestals_g0 is not None and self.calibration_params.num_pedestals_g1 is not None and self.calibration_params.num_pedestals_g2 is not None):
jungfrau_file = JungfrauDataFile(get_first_file(self.calibration_params.pedestal_file_dir, self.calibration_params.pedestal_file_prefix))
@property
def num_pedestals_g2(self) -> int:
return self._num_pedestals_g2
@num_pedestals_g2.setter
def num_pedestals_g2(self, num_pedestals : int):
self._num_pedestals_g2 = num_pedestals
g0_pedestal_frames = jungfrau_file.read_n(self.calibration_params.num_pedestals_g0) # TODO: option to only read gain? - mmh reading things twice from filesystem also bad
g1_pedestal_frames = jungfrau_file.read_n(self.calibration_params.num_pedestals_g1)
@property
def raw_file_dir(self) -> Path:
return self._raw_file_dir
@raw_file_dir.setter
def raw_file_dir(self, filepath : Path):
if not filepath.exists():
raise ValueError(f"Raw file directory {filepath} does not exist.")
self._raw_file_dir = filepath
g2_pedestal_frames = jungfrau_file.read_n(self.calibration_params.num_pedestals_g2)
@property
def raw_file_prefix(self) -> str:
return self._raw_file_prefix
@raw_file_prefix.setter
def raw_file_prefix(self, file_prefix : str):
self._raw_file_prefix = file_prefix
# get gain from each pixel - update mask
max_frames = max(self.calibration_params.num_pedestals_g0, self.calibration_params.num_pedestals_g1, self.calibration_params.num_pedestals_g2)
bad_channel_mask = np.zeros((jungfrau_file.rows(), jungfrau_file.cols()), dtype=bool) # bad channels pixel mask
# TODO add a read_config method
def calculate_bad_pixels_mask(calibration_params: JungfrauCalibrationParameters):
"""
Calculate the bad pixels mask for the Jungfrau detector.
Returns:
np.ndarray: A boolean array where True indicates a bad pixel.
"""
if(calibration_params.num_pedestals_g0 is not None and calibration_params.num_pedestals_g1 is not None and calibration_params.num_pedestals_g2 is not None):
# TODO loop to etensive
return bad_channel_mask
jungfrau_file = JungfrauDataFile(get_first_file(calibration_params.pedestal_file_dir, calibration_params.pedestal_file_prefix))
g0_pedestal_frames = jungfrau_file.read_n(calibration_params.num_pedestals_g0) # TODO: option to only read gain? - mmh reading things twice from filesystem also bad
def calculate_histogram(self):
"""
Calculate the histogram of each pixel.
g1_pedestal_frames = jungfrau_file.read_n(calibration_params.num_pedestals_g1)
Returns:
np.ndarray: The histogram for each pixel value
"""
g2_pedestal_frames = jungfrau_file.read_n(calibration_params.num_pedestals_g2)
def fit_function(self):
"""
Fit a Gaussian to the histogram of each pixel.
Returns:
np.ndarray: The fitted Gaussian parameters for each pixel.
"""
def calibrate_G0(self):
"""
Calibrate the G0 gain of the Jungfrau detector.
# Placeholder for actual implementation
# This function should analyze the detector data and identify bad pixels
pass
Returns:
np.ndarray: The calibrated G0 gain values for each pixel.
"""
self.calculate_bad_pixels_mask()
self.calculate_histogram()
self.fit_function()
## additional plot methods for visualizing the histogram and fitted Gaussian parameters can be added here - depens how fast not neccessary to compute on the fly
def main():
calibration_params = JungfrauCalibrationParameters()
@@ -114,6 +83,9 @@ def main():
calibration_params.num_pedestals_g0 = 1000
calibration_params.num_pedestals_g1 = 1000
calibration_params.num_pedestals_g2 = 1000
@@ -0,0 +1,77 @@
from pathlib import Path
class JungfrauCalibrationParameters:
"""
A class to hold calibration parameters for the Jungfrau detector.
"""
@property
def pedestal_file_dir(self) -> Path:
return self._pedestal_file_dir
@pedestal_file_dir.setter
def pedestal_file_dir(self, filepath : Path):
if not filepath.exists():
raise ValueError(f"Pedestal file directory {filepath} does not exist.")
self._pedestal_file_dir = filepath
@property
def pedestal_g0_file_prefix(self) -> str:
return self._pedestal_g0_file_prefix
@pedestal_g0_file_prefix.setter
def pedestal_g0_file_prefix(self, file_prefix : str):
self._pedestal_g0_file_prefix = file_prefix
# TODO: add deprecated decorator
@property
def pedestal_file_prefix(self) -> str:
return self._pedestal_file_prefix
@pedestal_file_prefix.setter
def pedestal_file_prefix(self, file_prefix : str):
self._pedestal_file_prefix = file_prefix
@property
def num_pedestals_g0(self) -> int:
return self._num_pedestals_g0
@num_pedestals_g0.setter
def num_pedestals_g0(self, num_pedestals : int):
self._num_pedestals_g0 = num_pedestals
@property
def num_pedestals_g1(self) -> int:
return self._num_pedestals_g1
@num_pedestals_g1.setter
def num_pedestals_g1(self, num_pedestals : int):
self._num_pedestals_g1 = num_pedestals
@property
def num_pedestals_g2(self) -> int:
return self._num_pedestals_g2
@num_pedestals_g2.setter
def num_pedestals_g2(self, num_pedestals : int):
self._num_pedestals_g2 = num_pedestals
@property
def raw_file_dir(self) -> Path:
return self._raw_file_dir
@raw_file_dir.setter
def raw_file_dir(self, filepath : Path):
if not filepath.exists():
raise ValueError(f"Raw file directory {filepath} does not exist.")
self._raw_file_dir = filepath
@property
def raw_file_prefix(self) -> str:
return self._raw_file_prefix
@raw_file_prefix.setter
def raw_file_prefix(self, file_prefix : str):
self._raw_file_prefix = file_prefix
# TODO add a read_config method
+8 -9
View File
@@ -7,7 +7,7 @@ using namespace aare;
namespace jungfraucalibration
{
SparseMask CreateBadChannelPixelMask(JungfrauDataFile &pedestal_file, const size_t num_pedestals_g0, const size_t num_pedestals_g1, const size_t num_pedestals_g2)
NDArray<bool, 2> CreateBadChannelPixelMask(JungfrauDataFile &pedestal_file, const size_t num_pedestals_g0, const size_t num_pedestals_g1, const size_t num_pedestals_g2)
{
auto pedestals_g0 = pedestal_file.read_n(num_pedestals_g0);
auto pedestals_g1 = pedestal_file.read_n(num_pedestals_g1);
@@ -17,30 +17,29 @@ namespace jungfraucalibration
const size_t cols = pedestal_file.cols();
// get gain from each pixel - update mask
SparseMask bad_channel_mask(STORAGEFORMAT::ROWMAJOR, rows, cols); // bad channels pixel mask
NDArray<bool, 2> bad_channel_mask({static_cast<ssize_t>(rows), static_cast<ssize_t>(cols)}, false); // bad channels pixel mask
size_t max_frames = std::max({num_pedestals_g0, num_pedestals_g1, num_pedestals_g2});
// TODO is this more efficient e.g. all three frames fit into cache instead of doing one file at the time?
for (size_t frame_idx = 0; frame_idx < max_frames; ++frame_idx)
{
for (size_t row = 0; row < rows; ++row)
{
for (size_t col = 0; col < cols; ++col)
{
// TODO: nicer to access element from frame directly instead of view()? What is the type?
if (frame_idx < num_pedestals_g0 && get_gain(pedestals_g0[frame_idx].view<uint32_t>()(row, col)) != 0)
if (frame_idx < num_pedestals_g0 && get_gain(pedestals_g0[frame_idx].view<uint16_t>()(row, col)) != 0)
{
bad_channel_mask.insert(row, col);
bad_channel_mask(row, col) = true;
}
if (frame_idx < num_pedestals_g1 && get_gain(pedestals_g1[frame_idx].view<uint32_t>()(row, col)) != 1)
if (frame_idx < num_pedestals_g1 && get_gain(pedestals_g1[frame_idx].view<uint16_t>()(row, col)) != 1)
{
bad_channel_mask.insert(row, col);
bad_channel_mask(row, col) = true;
}
if (frame_idx < num_pedestals_g2 && get_gain(pedestals_g2[frame_idx].view<uint32_t>()(row, col)) != 2)
if (frame_idx < num_pedestals_g2 && get_gain(pedestals_g2[frame_idx].view<uint16_t>()(row, col)) != 2)
{
bad_channel_mask.insert(row, col);
bad_channel_mask(row, col) = true;
}
}
}