diff --git a/src/calng/AgipdCorrection.py b/src/calng/AgipdCorrection.py index b07bca2b9c9f7332f5271747cd75af73a47739e0..599e0f28aae01151c7daf55efdc8029ce1393e27 100644 --- a/src/calng/AgipdCorrection.py +++ b/src/calng/AgipdCorrection.py @@ -15,7 +15,7 @@ from karabo.common.states import State from . import utils from ._version import version as deviceVersion -from .agipd_gpu import AgipdGpuRunner, BadPixelValues, CorrectionFlags +from .agipd_gpu import AgipdGainMode, AgipdGpuRunner, BadPixelValues, CorrectionFlags from .base_correction import BaseCorrection @@ -111,6 +111,15 @@ class AgipdCorrection(BaseCorrection): .reconfigurable() .commit(), ) + ( + STRING_ELEMENT(expected) + .key("gainMode") + .displayedName("Gain mode") + .assignmentOptional() + .defaultValue("ADAPTIVE_GAIN") + .options("ADAPTIVE_GAIN,FIXED_HIGH_GAIN,FIXED_MEDIUM_GAIN,FIXED_LOW_GAIN") + .commit() + ) # TODO: hook this up to actual correction done bad_pixel_selection_schema = Schema() ( @@ -157,6 +166,10 @@ class AgipdCorrection(BaseCorrection): ) def __init__(self, config): + # TODO: different gpu runner for fixed gain mode + self.gain_mode = AgipdGainMode[config.get("gainMode")] + self._gpu_runner_init_args = {"gain_mode": self.gain_mode} + super().__init__(config) output_axis_order = config.get("dataFormat.outputAxisOrder") if output_axis_order == "pixels-fast": @@ -297,6 +310,9 @@ class AgipdCorrection(BaseCorrection): def _load_constant_to_gpu(self, constant_name, constant_data): if constant_name == "ThresholdsDark": + if self.gain_mode is not AgipdGainMode.ADAPTIVE_GAIN: + self.log.INFO("Loaded ThresholdsDark ignored due to fixed gain mode") + return self.gpu_runner.load_thresholds(constant_data) # TODO: encode correction / constant dependencies in a clever way if not self.get("corrections.available.thresholding"): @@ -344,16 +360,12 @@ class AgipdCorrection(BaseCorrection): assert np.max(new_filter) < self.get("dataFormat.memoryCells") self.pulse_filter = new_filter - def preReconfigure(self, config): - super().preReconfigure(config) - if config.has("corrections.overrideMdAdditionalOffset"): - if config.get("corrections.overrideMdAdditionalOffset"): - md_additional_offset = self.get("corrections.mdAdditionalOffset") - if config.has("corrections.mdAdditionalOffset"): - md_additional_offset = config.get("corrections.mdAdditionalOffset") - self._override_md_additional_offset = md_additional_offset - self.gpu_runner.md_additional_offset_gpu.fill( - self._override_md_additional_offset - ) - else: - self._override_md_additional_offset = None + def postReconfigure(self): + super().postReconfigure() + if self.get("corrections.overrideMdAdditionalOffset"): + self._override_md_additional_offset = self.get("corrections.mdAdditionalOffset") + self.gpu_runner.md_additional_offset_gpu.fill( + self._override_md_additional_offset + ) + else: + self._override_md_additional_offset = None diff --git a/src/calng/agipd_gpu.py b/src/calng/agipd_gpu.py index 4ec912cb48fe1f65a91753e288d53df07b848ef2..f6080742f953bd49af7570896cf45975aaf11be8 100644 --- a/src/calng/agipd_gpu.py +++ b/src/calng/agipd_gpu.py @@ -16,6 +16,14 @@ class CorrectionFlags(enum.IntFlag): BPMASK = 32 +# from pycalibration's enum.py +class AgipdGainMode(enum.IntEnum): + ADAPTIVE_GAIN = 0 + FIXED_HIGH_GAIN = 1 + FIXED_MEDIUM_GAIN = 2 + FIXED_LOW_GAIN = 3 + + class AgipdGpuRunner(base_gpu.BaseGpuRunner): _kernel_source_filename = "agipd_gpu_kernels.cpp" @@ -29,7 +37,13 @@ class AgipdGpuRunner(base_gpu.BaseGpuRunner): input_data_dtype=np.uint16, output_data_dtype=np.float32, badpixel_mask_value=np.float32(np.nan), + gain_mode=AgipdGainMode.ADAPTIVE_GAIN, ): + self.gain_mode = gain_mode + if self.gain_mode is AgipdGainMode.ADAPTIVE_GAIN: + self.default_gain = np.uint8(gain_mode) + else: + self.default_gain = np.uint8(gain_mode - 1) self.input_shape = (memory_cells, 2, pixels_x, pixels_y) self.processed_shape = (memory_cells, pixels_x, pixels_y) super().__init__( @@ -162,6 +176,10 @@ class AgipdGpuRunner(base_gpu.BaseGpuRunner): def correct(self, flags): if flags & CorrectionFlags.BLSHIFT: raise NotImplementedError("Baseline shift not implemented yet") + if self.gain_mode is not AgipdGainMode.ADAPTIVE_GAIN and ( + flags & CorrectionFlags.THRESHOLD + ): + raise ValueError("Cannot do gain thresholding in fixed gain mode") self.correction_kernel( self.full_grid, self.full_block, @@ -169,6 +187,7 @@ class AgipdGpuRunner(base_gpu.BaseGpuRunner): self.input_data_gpu, self.cell_table_gpu, np.uint8(flags), + self.default_gain, self.gain_thresholds_gpu, self.offset_map_gpu, self.rel_gain_pc_map_gpu, diff --git a/src/calng/agipd_gpu_kernels.cpp b/src/calng/agipd_gpu_kernels.cpp index 357c82a8b8270f9dfee94af3957c7a8d0a40f469..2d701d981d467ac4d9486114ca93656f47b45d58 100644 --- a/src/calng/agipd_gpu_kernels.cpp +++ b/src/calng/agipd_gpu_kernels.cpp @@ -12,14 +12,16 @@ extern "C" { */ __global__ void correct(const {{input_data_dtype}}* data, const unsigned short* cell_table, - const unsigned char corr_flags, + const unsigned char corr_flags, + // default_gain can be 0, 1, or 2, and is relevant for fixed gain mode (no THRESHOLD) + const unsigned char default_gain, const float* threshold_map, const float* offset_map, const float* rel_gain_pc_map, - const float* md_additional_offset, - const float* rel_gain_xray_map, + const float* md_additional_offset, + const float* rel_gain_xray_map, const unsigned int* bad_pixel_map, - const float bad_pixel_mask_value, + const float bad_pixel_mask_value, unsigned char* gain_map, {{output_data_dtype}}* output) { const size_t X = {{pixels_x}}; @@ -77,7 +79,7 @@ extern "C" { const size_t map_cell = cell_table[cell]; if (map_cell < map_cells) { - unsigned char gain = 0; + unsigned char gain = default_gain; if (corr_flags & THRESHOLD) { const float threshold_0 = threshold_map[0 * threshold_map_stride_threshold + map_cell * threshold_map_stride_cell + diff --git a/src/calng/base_correction.py b/src/calng/base_correction.py index 1f87b97322fa94c981f346fcaa33beeea5b28f71..11746d858a3ce98a3a7f605b8968ce9466166b6a 100644 --- a/src/calng/base_correction.py +++ b/src/calng/base_correction.py @@ -32,6 +32,8 @@ from . import shmem_utils, utils class BaseCorrection(calibrationBase.CalibrationReceiverBaseDevice): _correction_flag_class = None # subclass must override this with some enum class + _gpu_runner_class = None # subclass must set this + _gpu_runner_init_args = {} # subclass can set this (TODO: remove, design better) _schema_cache_slots = { "doAnything", "dataFormat.memoryCells", @@ -387,6 +389,7 @@ class BaseCorrection(calibrationBase.CalibrationReceiverBaseDevice): self.input_data_dtype = np.dtype(config.get("dataFormat.inputImageDtype")) self.output_data_dtype = np.dtype(config.get("dataFormat.outputImageDtype")) + self.gpu_runner = None # must call _update_shapes() in subclass init self._correction_flag_enabled = self._correction_flag_class.NONE self._correction_flag_preview = self._correction_flag_class.NONE @@ -590,6 +593,7 @@ class BaseCorrection(calibrationBase.CalibrationReceiverBaseDevice): output_transpose=self._output_transpose, input_data_dtype=self.input_data_dtype, output_data_dtype=self.output_data_dtype, + **self._gpu_runner_init_args, ) for constant_name, constant_data in self._cached_constants.items():