diff --git a/src/calng/agipd_gpu.py b/src/calng/agipd_gpu.py index 56a36ac1560e938e11a7205cf33dc8a27e840c65..8cfbdd0f429fafb504dfb79f479e285645fb49f9 100644 --- a/src/calng/agipd_gpu.py +++ b/src/calng/agipd_gpu.py @@ -80,21 +80,27 @@ class AgipdGpuRunner(base_gpu.BaseGpuRunner): # pc has funny shape (11, 352, 128, 512) from file # this is (fi, memory cell, y, x) slopes_pc_map = slopes_pc_map.astype(np.float32) - pc_high_m = slopes_pc_map[0] - pc_high_I = slopes_pc_map[1] - pc_med_m = slopes_pc_map[3] - pc_med_I = slopes_pc_map[4] - frac_high_med = pc_high_m / pc_med_m - # TODO: handle NaN somehow? - if np.isnan(frac_high_med).any(): - ... - # TODO: verify formula - md_additional_offset = (pc_high_I - pc_med_I * frac_high_med).astype(np.float32) + # the following may contain NaNs, though... + hg_slope = slopes_pc_map[0] + hg_intercept = slopes_pc_map[1] + mg_slope = slopes_pc_map[3] + mg_intercept = slopes_pc_map[4] + # from agipdlib.py: replace NaN with median (per memory cell) + # note: suffixes in agipdlib are "_m" and "_l", should probably be "_I" + for naughty_array in (hg_slope, hg_intercept, mg_slope, mg_intercept): + medians = np.nanmedian(naughty_array, axis=(1, 2)) + nan_bool = np.isnan(naughty_array) + nan_cell, _, _ = np.where(nan_bool) + naughty_array[nan_bool] = medians[nan_cell] + # TODO: clamp values outside range (0.8 to 1.2) * median to median + + frac_hg_mg = hg_slope / mg_slope + md_additional_offset = (hg_intercept - mg_intercept * frac_hg_mg).astype(np.float32) rel_gain_map = np.ones( (3, self.constant_memory_cells, self.pixels_y, self.pixels_x), dtype=np.float32, ) - rel_gain_map[1] = rel_gain_map[0] * frac_high_med + rel_gain_map[1] = rel_gain_map[0] * frac_hg_mg rel_gain_map[2] = rel_gain_map[1] * 4.48 # TODO: enable overriding this based on user input self.rel_gain_pc_map_gpu.set(np.transpose(rel_gain_map, (1, 3, 2, 0))) diff --git a/src/calng/agipd_gpu_kernels.cpp b/src/calng/agipd_gpu_kernels.cpp index e5fc623de00e232fffc7325712c18c08e45b2a69..898e0b87866457a7d57ba4fdc379b6c3f52fde17 100644 --- a/src/calng/agipd_gpu_kernels.cpp +++ b/src/calng/agipd_gpu_kernels.cpp @@ -5,10 +5,11 @@ extern "C" { /* - Perform correction: offset - Take cell_table into account when getting correction values - Converting to float for doing the correction - Converting to output dtype at the end + Perform corrections; see agipd_gpu.CorrectionFlags + Note that THRESHOLD and OFFSET should for any later corrections to make sense + Will take cell_table into account when getting correction values + Will convert from input dtype to float for correction + Will convert to output dtype for output */ __global__ void correct(const {{input_data_dtype}}* data, const unsigned short* cell_table, @@ -140,12 +141,4 @@ extern "C" { {% endif %} } } - - /* - Same as correction, except don't do any correction - */ - __global__ void only_cast(const {{input_data_dtype}}* data, - unsigned char* gain_map, - {{output_data_dtype}}* output) { - } } diff --git a/src/calng/base_correction.py b/src/calng/base_correction.py index 6bdc4d377d265b4b302bd550876f0f81f0c6c5b0..a7076c485c3096dc360411c0f4171418a9742236 100644 --- a/src/calng/base_correction.py +++ b/src/calng/base_correction.py @@ -553,7 +553,8 @@ class BaseCorrection(calibrationBase.CalibrationReceiverBaseDevice): enabled &= self._correction_flag_class.NONE self._correction_flag_enabled = enabled self._correction_flag_preview = preview - self.log.INFO(str(enabled)) + self.log.INFO(f"Corrections for dataOutput: {str(enabled)}") + self.log.INFO(f"Corrections for preview: {str(preview)}") def _update_output_schema(self, data): """Updates the schema of dataOutput based on parameter data (a Hash) diff --git a/src/calng/dssc_gpu_kernels.cpp b/src/calng/dssc_gpu_kernels.cpp index b82159c0885ca6026fddc7e813f96b0c8eb9c1b4..a5bf8d8e1193cef39575d44a265dfbc57db792d7 100644 --- a/src/calng/dssc_gpu_kernels.cpp +++ b/src/calng/dssc_gpu_kernels.cpp @@ -4,12 +4,14 @@ extern "C" { /* - Perform correction: offset + Perform corrections: NONE or OFFSET Take cell_table into account when getting correction values - Converting to float for doing the correction + Converting to float while correcting Converting to output dtype at the end + Shape of input data: memory cell, 1, y, x + Shape of offset constant: x, y, memory cell */ - __global__ void correct(const {{input_data_dtype}}* data, + __global__ void correct(const {{input_data_dtype}}* data, // shape: memory cell, 1, y, x const unsigned short* cell_table, const unsigned char corr_flags, const float* offset_map, diff --git a/src/tests/test_dssc_kernels.py b/src/tests/test_dssc_kernels.py index 02369c9892a4380f2aed68578cb721afe3150401..1ed780620c06583a4935b83e924b9e0ae89e475c 100644 --- a/src/tests/test_dssc_kernels.py +++ b/src/tests/test_dssc_kernels.py @@ -43,28 +43,28 @@ kernel_runner = dssc_gpu.DsscGpuRunner( def test_only_cast(): kernel_runner.load_data(raw_data) - kernel_runner.only_cast() + kernel_runner.correct(dssc_gpu.CorrectionFlags.NONE) assert np.allclose( kernel_runner.processed_data_gpu.get(), raw_data.astype(output_dtype) ) def test_correct(): - kernel_runner.load_constants(offset_map) + kernel_runner.load_offset_map(offset_map) kernel_runner.load_data(raw_data) kernel_runner.load_cell_table(cell_table) - kernel_runner.correct() + kernel_runner.correct(dssc_gpu.CorrectionFlags.OFFSET) assert np.allclose(kernel_runner.processed_data_gpu.get(), corrected_data) def test_correct_oob_cells(): - kernel_runner.load_constants(offset_map) + kernel_runner.load_offset_map(offset_map) kernel_runner.load_data(raw_data) # here, half the cell IDs will be out of bounds wild_cell_table = cell_table * 2 kernel_runner.load_cell_table(wild_cell_table) # should not crash - kernel_runner.correct() + kernel_runner.correct(dssc_gpu.CorrectionFlags.OFFSET) # should correct as much as possible assert np.allclose( kernel_runner.processed_data_gpu.get(),