diff --git a/src/calng/AgipdCorrection.py b/src/calng/AgipdCorrection.py index fa8e074be01a36c4d7005450b2274d3d6c0453aa..548f00f2e9fcdaff14c57b3cdf55e0e261858f82 100644 --- a/src/calng/AgipdCorrection.py +++ b/src/calng/AgipdCorrection.py @@ -88,9 +88,9 @@ class AgipdCorrection(BaseCorrection): .defaultValue(0) .reconfigurable() .commit(), - NODE_ELEMENT(expected) - .key("corrections.badPixels.subsetToUse") - .displayedName("Bad pixel flags to use") + FLOAT_ELEMENT(expected) + .key("corrections.relGainXray.gGainValue") + .displayedName("G_gain_value") .description( "The booleans under this node allow for selecting a subset of bad " "pixel types to take into account when doing bad pixel masking. " @@ -98,20 +98,16 @@ class AgipdCorrection(BaseCorrection): "be ANDed with this selection. Therefore, if you want to toggle a " "disabled flag back on, please reload constants for this to take " "effect (will be triggered automatically in future version)." + "Modern X-ray gain correction constants are absolute. The default " + "G_gain_value of 1 means that output is expected to be in keV. If " + "this is not desired, one can here specify the mean X-ray gain value " + "over all modules to get ADU values out - operator must manually " + "find this mean value." ) + .assignmentOptional() + .defaultValue(1) + .reconfigurable() .commit(), - ) - # TODO: DRY / encapsulate - for field in BadPixelValues: - ( - BOOL_ELEMENT(expected) - .key(f"corrections.badPixels.subsetToUse.{field.name}") - .assignmentOptional() - .defaultValue(True) - .reconfigurable() - .commit() - ) - ( STRING_ELEMENT(expected) .key("corrections.badPixels.maskingValue") .displayedName("Bad pixel masking value") @@ -123,8 +119,22 @@ class AgipdCorrection(BaseCorrection): .assignmentOptional() .defaultValue("float('nan')") .reconfigurable() - .commit() + .commit(), + NODE_ELEMENT(expected) + .key("corrections.badPixels.subsetToUse") + .displayedName("Bad pixel flags to use") + .commit(), ) + # TODO: DRY / encapsulate + for field in BadPixelValues: + ( + BOOL_ELEMENT(expected) + .key(f"corrections.badPixels.subsetToUse.{field.name}") + .assignmentOptional() + .defaultValue(True) + .reconfigurable() + .commit() + ) @property def input_data_shape(self): @@ -156,6 +166,7 @@ class AgipdCorrection(BaseCorrection): self._gpu_runner_init_args = { "gain_mode": self.gain_mode, "bad_pixel_mask_value": self.bad_pixel_mask_value, + "g_gain_value": config.get("corrections.relGainXray.gGainValue"), } self._output_transpose = { @@ -339,18 +350,14 @@ class AgipdCorrection(BaseCorrection): for path in config.getPaths() ): self._has_updated_bad_pixel_selection = False - if config.has("corrections.badPixels.maskingValue"): - self.bad_pixel_mask_value = eval( - config.get("corrections.badPixels.maskingValue") - ) - self.gpu_runner.set_bad_pixel_mask_value(self.bad_pixel_mask_value) def postReconfigure(self): + # TODO: keep track of which things actually need updating super().postReconfigure() - if self.get("corrections.overrideMdAdditionalOffset"): + if self.get("corrections.relGainPc.overrideMdAdditionalOffset"): self._override_md_additional_offset = self.get( - "corrections.mdAdditionalOffset" + "corrections.relGainPc.mdAdditionalOffset" ) self.gpu_runner.md_additional_offset_gpu.override_md_additional_offset( self._override_md_additional_offset @@ -358,6 +365,13 @@ class AgipdCorrection(BaseCorrection): else: self._override_md_additional_offset = None + self.gpu_runner.set_g_gain_value(self.get("corrections.relGainXray.gGainValue")) + self._gpu_runner_init_args["g_gain_value"] = self.get("corrections.relGainXray.gGainValue") + + self.bad_pixel_mask_value = eval(self.get("corrections.badPixels.maskingValue")) + self.gpu_runner.set_bad_pixel_mask_value(self.bad_pixel_mask_value) + self._gpu_runner_init_args["bad_pixel_mask_value"] = self.bad_pixel_mask_value + if not self._has_updated_bad_pixel_selection: self._update_bad_pixel_selection() self.gpu_runner.override_bad_pixel_flags_to_use( diff --git a/src/calng/agipd_gpu.py b/src/calng/agipd_gpu.py index 8526836f66141e16d70bb1b1ee275cb7031bc0b0..fd935ebade2ff0ea9794bc2018271f320f4e0a37 100644 --- a/src/calng/agipd_gpu.py +++ b/src/calng/agipd_gpu.py @@ -38,6 +38,7 @@ class AgipdGpuRunner(base_gpu.BaseGpuRunner): output_data_dtype=cupy.float32, bad_pixel_mask_value=cupy.nan, gain_mode=AgipdGainMode.ADAPTIVE_GAIN, + g_gain_value=1, ): self.gain_mode = gain_mode if self.gain_mode is AgipdGainMode.ADAPTIVE_GAIN: @@ -71,6 +72,7 @@ class AgipdGpuRunner(base_gpu.BaseGpuRunner): self.rel_gain_xray_map_gpu = cupy.ones(self.map_shape, dtype=cupy.float32) self.bad_pixel_map_gpu = cupy.zeros(self.gm_map_shape, dtype=cupy.uint32) self.set_bad_pixel_mask_value(bad_pixel_mask_value) + self.set_g_gain_value(g_gain_value) self.update_block_size((1, 1, 64)) @@ -144,6 +146,7 @@ class AgipdGpuRunner(base_gpu.BaseGpuRunner): # constant shape: y, x, memory cell if slopes_ff_map.shape[2] == 2: # old format, is per pixel only (shape is y, x, 2) + # note: we should not support this in online slopes_ff_map = np.broadcast_to( slopes_ff_map[..., 0][..., np.newaxis], (self.pixels_y, self.pixels_x, self.constant_memory_cells), @@ -154,6 +157,9 @@ class AgipdGpuRunner(base_gpu.BaseGpuRunner): ... self.rel_gain_xray_map_gpu.set(np.transpose(slopes_ff_map).astype(np.float32)) + def set_g_gain_value(self, override_value): + self.g_gain_value = cupy.float32(override_value) + def load_bad_pixels_map(self, bad_pixels_map, override_flags_to_use=None): print(f"Loading bad pixels with shape: {bad_pixels_map.shape}") # will simply OR with already loaded, does not take into account which ones @@ -233,6 +239,7 @@ class AgipdGpuRunner(base_gpu.BaseGpuRunner): self.rel_gain_pc_map_gpu, self.md_additional_offset_gpu, self.rel_gain_xray_map_gpu, + self.g_gain_value, self.bad_pixel_map_gpu, self.bad_pixel_mask_value, self.gain_map_gpu, diff --git a/src/calng/agipd_gpu_kernels.cpp b/src/calng/agipd_gpu_kernels.cpp index 7c8a65fe61a04796fdeed06736feb287af5d0568..192b71930c358246386dbfecba50a05741add959 100644 --- a/src/calng/agipd_gpu_kernels.cpp +++ b/src/calng/agipd_gpu_kernels.cpp @@ -114,6 +114,7 @@ extern "C" { } else { if (corr_flags & OFFSET) { corrected -= offset_map[gm_map_index]; + // TODO: optionally reassign gain stage for this pixel based on new value } // TODO: baseline shift if (corr_flags & REL_GAIN_PC) { @@ -123,9 +124,7 @@ extern "C" { } } if (corr_flags & REL_GAIN_XRAY) { - // TODO - //corrected *= rel_gain_xray_map[map_index]; - // TODO: G_gain_value + corrected = (corrected / rel_gain_xray_map[map_index]) * g_gain_value; } } diff --git a/src/calng/base_correction.py b/src/calng/base_correction.py index 12d4a96e68333b11d2f01831215c489cdbb4a537..68573a3eb99864f66eb089a243778123ed1a6cf6 100644 --- a/src/calng/base_correction.py +++ b/src/calng/base_correction.py @@ -582,9 +582,6 @@ class BaseCorrection(PythonDevice): self._has_updated_shapes = True def _update_rate_and_state(self): - if not self.get("state") is State.PROCESSING: - return - self._buffered_status_update.set("performance.rate", self._rate_tracker.get()) self._buffered_status_update.set( "performance.processingDuration", self._processing_time_ema.get() * 1000