From cbd0ba4f8f67ebd134a6365cbe3185ee9d9978e5 Mon Sep 17 00:00:00 2001 From: Ross Whitfield Date: Fri, 22 Mar 2024 14:54:06 +1100 Subject: [PATCH 1/3] Move options to new global/per run groups --- reflectivity_ui/ui/ui_main_window.ui | 508 +++++++++++++-------------- 1 file changed, 254 insertions(+), 254 deletions(-) diff --git a/reflectivity_ui/ui/ui_main_window.ui b/reflectivity_ui/ui/ui_main_window.ui index 4fd998ca..6971d378 100644 --- a/reflectivity_ui/ui/ui_main_window.ui +++ b/reflectivity_ui/ui/ui_main_window.ui @@ -384,7 +384,7 @@ 0 - 300 + 200 @@ -396,7 +396,7 @@ 1 - + 0 @@ -406,7 +406,7 @@ - Reflectivity Extraction (Basic) + Reflectivity Extraction (Global) @@ -424,6 +424,239 @@ 1 + + + + Check for apply a final Q rebinning + + + Final rebin + + + true + + + + + + + Q steps + + + + + + + Step size in Q for rebinning. Negative number produce a logarithmic binning + + + 1/A + + + 3 + + + -0.100000000000000 + + + 0.100000000000000 + + + 0.001000000000000 + + + -0.010000000000000 + + + + + + + Normalize the total reflectivity plateau to unity when stitching + + + Normalize to unity when stitching + + + true + + + + + + + Critical Q cutoff + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Q-value below which the reflectivity should be 1. + + + 3 + + + 0.001000000000000 + + + 0.010000000000000 + + + + + + + Global fit when stitching + + + Perform stitching fit using all cross-sections + + + + + + + 3 + + + + + + + Polynomial fit when stitching + + + Use polynomial function to determine scaling factors + + + + + + + Polynomial degree + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Points outside overlap + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 3 + + + + + + + <html><head/><body><p>Evaluate Q for each X line of the reflectivity and combine these measurements.</p><p>Can be used with a large X-width of e.g. 15 for samples scattering to a large 2θ area.</p></body></html> + + + Constant-Q binning + + + + + + + + 130 + 0 + + + + Sample size: + + + + + + + mm + + + 1 + + + 10000.000000000000000 + + + 10.000000000000000 + + + + + + + Bandwidth: + + + + + + + Bandwidth to use to select the TOF range when loading data. + + + A + + + 1 + + + 0.100000000000000 + + + 3.200000000000000 + + + + + + + + + 0 + 0 + 484 + 386 + + + + Reflectivity Extraction (Per Run) + + + + 2 + + + 2 + + + 2 + + + 2 + + + 0 + @@ -665,82 +898,7 @@ - - - - Check for apply a final Q rebinning - - - Final rebin - - - true - - - - - - - Q steps - - - - - - - Step size in Q for rebinning. Negative number produce a logarithmic binning - - - 1/A - - - 3 - - - -0.100000000000000 - - - 0.100000000000000 - - - 0.001000000000000 - - - -0.010000000000000 - - - - - - - - - 0 - 0 - 484 - 386 - - - - Reflectivity Extraction (Advanced) - - - - 2 - - - 2 - - - 2 - - - 2 - - - 0 - - + @@ -768,7 +926,7 @@ - + @@ -781,7 +939,7 @@ - + @@ -797,7 +955,7 @@ - + @@ -813,31 +971,21 @@ - - - - <html><head/><body><p>Evaluate Q for each X line of the reflectivity and combine these measurements.</p><p>Can be used with a large X-width of e.g. 15 for samples scattering to a large 2θ area.</p></body></html> - - - Constant-Q binning - - - - + Set Dangle0 - + Set Direct Pixel - + @@ -856,154 +1004,6 @@ - - - - Normalize the total reflectivity plateau to unity when stitching - - - Normalize to unity when stitching - - - true - - - - - - - Critical Q cutoff - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Q-value below which the reflectivity should be 1. - - - 3 - - - 0.001000000000000 - - - 0.010000000000000 - - - - - - - - 130 - 0 - - - - Sample size: - - - - - - - mm - - - 1 - - - 10000.000000000000000 - - - 10.000000000000000 - - - - - - - Bandwidth: - - - - - - - Bandwidth to use to select the TOF range when loading data. - - - A - - - 1 - - - 0.100000000000000 - - - 3.200000000000000 - - - - - - - Global fit when stitching - - - Perform stitching fit using all cross-sections - - - - - - - 3 - - - - - - - Polynomial fit when stitching - - - Use polynomial function to determine scaling factors - - - - - - - Polynomial degree - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Points outside overlap - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 3 - - - trustSANGLE trustDANGLE @@ -1055,14 +1055,14 @@ 0 - + Meta data background ROI - + Once the reflected peak ROI is selected, you can try to fine tune this ROI by fitting for a peak within that region and updating the ROI according to the location found. Check the following box if you want to find a peak within the ROI and redefine the ROI afterwards. @@ -1075,7 +1075,7 @@ - + Indicate whether the peak ROI was actually used when loading the data. @@ -1085,14 +1085,14 @@ - + Meta data ROI peak - + ROI a in the meta-data @@ -1102,7 +1102,7 @@ - + ROI a in the meta-data @@ -1112,14 +1112,14 @@ - + Was meta ROI used? - + As an alternative to using the 2nd ROI, you can use a region around the reflected peak to estimate the background. Check the following box if you want to use the region on each side of the peak to estimate your background. @@ -1129,7 +1129,7 @@ - + The ROI in the data file is used to determine the reflectivity peak position. If this ROI is invalid, the system will try to find an appropriate region to use. @@ -1142,14 +1142,14 @@ - + 5 - + A second ROI is available in the data file and can be used to define the background. Check the following box if you want to use the 2nd ROI for your background, otherwise a default region will be used. From 86180c7002aa749320d4d61450423b829f58f201 Mon Sep 17 00:00:00 2001 From: Ross Whitfield Date: Tue, 26 Mar 2024 11:32:03 +1100 Subject: [PATCH 2/3] Make global variables common between different run configurations --- reflectivity_ui/interfaces/configuration.py | 56 ++++++++++--------- .../interfaces/data_handling/quicknxs_io.py | 2 +- .../interfaces/event_handlers/main_handler.py | 24 ++++---- 3 files changed, 42 insertions(+), 40 deletions(-) diff --git a/reflectivity_ui/interfaces/configuration.py b/reflectivity_ui/interfaces/configuration.py index 2dbc1893..40adb0cd 100644 --- a/reflectivity_ui/interfaces/configuration.py +++ b/reflectivity_ui/interfaces/configuration.py @@ -20,6 +20,24 @@ class Configuration(object): KZI_VS_KZF = 1 DELTA_KZ_VS_QZ = 3 + # Global variables + + wl_bandwidth = 3.2 + use_constant_q = False + sample_size = 10 + # Final Q rebin + do_final_rebin = True + final_rebin_step = -0.01 + # Normalize to unity when stitching + normalize_to_unity = True + total_reflectivity_q_cutoff = 0.01 + # Use all cross-sections when stitching + global_stitching = False + # Use a polynomial curve fit when stitching + polynomial_stitching = False + polynomial_stitching_degree = 3 + polynomial_stitching_points = 3 + def __init__(self, settings=None): self.instrument = Instrument() # Number of TOF bins @@ -30,7 +48,6 @@ def __init__(self, settings=None): # 1 = Constant Q bin width # 2 = Constant 1/wavelength bin width self.tof_bin_type = 0 - self.wl_bandwidth = 3.2 # Threshold under which we skip a cross-section, as fraction of the max count self.count_threshold = 0.01 @@ -44,8 +61,6 @@ def __init__(self, settings=None): self.set_direct_angle_offset = False self.direct_angle_offset_overwrite = 0 self.use_dangle = False - self.use_constant_q = False - self.sample_size = 10 # Update the specular peak range after finding the peak # within the ROI @@ -75,24 +90,11 @@ def __init__(self, settings=None): self.scaling_factor = 1.0 # Error in the scaling factor self.scaling_error = 0.0 - # Normalize to unity when stitching - self.normalize_to_unity = True - self.total_reflectivity_q_cutoff = 0.01 - # Use all cross-sections when stitching - self.global_stitching = False - # Use a polynomial curve fit when stitching - self.polynomial_stitching = False - self.polynomial_stitching_degree = 3 - self.polynomial_stitching_points = 3 # Cut first and last N points self.cut_first_n_points = 1 self.cut_last_n_points = 1 - # Final Q rebin - self.do_final_rebin = True - self.final_rebin_step = -0.01 - # UI elements self.normalize_x_tof = False self.x_wl_map = False @@ -272,7 +274,7 @@ def _verify_true(parameter, default): self.use_roi_bck = _verify_true("use_roi_bck", self.use_roi_bck) self.use_tight_bck = _verify_true("use_tight_bck", self.use_tight_bck) self.bck_offset = int(settings.value("bck_offset", self.bck_offset)) - self.wl_bandwidth = float(settings.value("wl_bandwidth", self.wl_bandwidth)) + Configuration.wl_bandwidth = float(settings.value("wl_bandwidth", self.wl_bandwidth)) self.force_peak_roi = _verify_true("force_peak_roi", self.force_peak_roi) self.force_low_res_roi = _verify_true("force_low_res_roi", self.force_low_res_roi) @@ -292,16 +294,16 @@ def _verify_true(parameter, default): self.cut_last_n_points = int(settings.value("cut_last_n_points", self.cut_last_n_points)) # Normalize to unity when stitching - self.normalize_to_unity = _verify_true("normalize_to_unity", self.normalize_to_unity) - self.total_reflectivity_q_cutoff = float( + Configuration.normalize_to_unity = _verify_true("normalize_to_unity", self.normalize_to_unity) + Configuration.total_reflectivity_q_cutoff = float( settings.value("total_reflectivity_q_cutoff", self.total_reflectivity_q_cutoff) ) - self.global_stitching = _verify_true("global_stitching", self.global_stitching) - self.polynomial_stitching = _verify_true("polynomial_stitching", self.polynomial_stitching) - self.polynomial_stitching_degree = int( + Configuration.global_stitching = _verify_true("global_stitching", self.global_stitching) + Configuration.polynomial_stitching = _verify_true("polynomial_stitching", self.polynomial_stitching) + Configuration.polynomial_stitching_degree = int( settings.value("polynomial_stitching_degree", self.polynomial_stitching_degree) ) - self.polynomial_stitching_points = int( + Configuration.polynomial_stitching_points = int( settings.value("polynomial_stitching_points", self.polynomial_stitching_points) ) @@ -311,7 +313,7 @@ def _verify_true(parameter, default): self.log_1d = _verify_true("log_1d", self.log_1d) self.log_2d = _verify_true("log_2d", self.log_2d) - self.use_constant_q = _verify_true("use_constant_q", self.use_constant_q) + Configuration.use_constant_q = _verify_true("use_constant_q", self.use_constant_q) self.use_dangle = _verify_true("use_dangle", self.use_dangle) self.set_direct_pixel = _verify_true("set_direct_pixel", self.set_direct_pixel) self.direct_pixel_overwrite = float(settings.value("direct_pixel_overwrite", self.direct_pixel_overwrite)) @@ -319,9 +321,9 @@ def _verify_true(parameter, default): self.direct_angle_offset_overwrite = float( settings.value("direct_angle_offset_overwrite", self.direct_angle_offset_overwrite) ) - self.sample_size = float(settings.value("sample_size", self.sample_size)) - self.do_final_rebin = _verify_true("do_final_rebin", self.do_final_rebin) - self.final_rebin_step = float(settings.value("final_rebin_step", self.final_rebin_step)) + Configuration.sample_size = float(settings.value("sample_size", self.sample_size)) + Configuration.do_final_rebin = _verify_true("do_final_rebin", self.do_final_rebin) + Configuration.final_rebin_step = float(settings.value("final_rebin_step", self.final_rebin_step)) # Off-specular options self.off_spec_x_axis = int(settings.value("off_spec_x_axis", self.off_spec_x_axis)) diff --git a/reflectivity_ui/interfaces/data_handling/quicknxs_io.py b/reflectivity_ui/interfaces/data_handling/quicknxs_io.py index 41b903c4..5a047fab 100644 --- a/reflectivity_ui/interfaces/data_handling/quicknxs_io.py +++ b/reflectivity_ui/interfaces/data_handling/quicknxs_io.py @@ -335,7 +335,7 @@ def read_reduced_file(file_path, configuration=None): conf.low_res_width = float(toks[7]) conf.bck_position = float(toks[8]) conf.bck_width = float(toks[9]) - conf.use_constant_q = toks[10].strip().lower() == "true" + Configuration.use_constant_q = toks[10].strip().lower() == "true" conf.direct_pixel_overwrite = float(toks[11]) if int(toks[14]) > 0 and len(direct_beam_runs) > int(toks[14]) - 1: conf.normalization = direct_beam_runs[int(toks[14]) - 1][0] diff --git a/reflectivity_ui/interfaces/event_handlers/main_handler.py b/reflectivity_ui/interfaces/event_handlers/main_handler.py index 900ac6f3..84b92ab5 100644 --- a/reflectivity_ui/interfaces/event_handlers/main_handler.py +++ b/reflectivity_ui/interfaces/event_handlers/main_handler.py @@ -1203,23 +1203,23 @@ def get_configuration(self): configuration.scaling_factor = scale configuration.cut_first_n_points = self.ui.rangeStart.value() configuration.cut_last_n_points = self.ui.rangeEnd.value() - configuration.normalize_to_unity = self.ui.normalize_to_unity_checkbox.isChecked() - configuration.total_reflectivity_q_cutoff = self.ui.normalization_q_cutoff_spinbox.value() - configuration.global_stitching = self.ui.global_fit_checkbox.isChecked() - configuration.polynomial_stitching = self.ui.polynomial_stitching_checkbox.isChecked() - configuration.polynomial_stitching_degree = self.ui.polynomial_stitching_degree_spinbox.value() - configuration.polynomial_stitching_points = self.ui.polynomial_stitching_points_spinbox.value() - configuration.wl_bandwidth = self.ui.bandwidth_spinbox.value() - - configuration.use_constant_q = self.ui.fanReflectivity.isChecked() + Configuration.normalize_to_unity = self.ui.normalize_to_unity_checkbox.isChecked() + Configuration.total_reflectivity_q_cutoff = self.ui.normalization_q_cutoff_spinbox.value() + Configuration.global_stitching = self.ui.global_fit_checkbox.isChecked() + Configuration.polynomial_stitching = self.ui.polynomial_stitching_checkbox.isChecked() + Configuration.polynomial_stitching_degree = self.ui.polynomial_stitching_degree_spinbox.value() + Configuration.polynomial_stitching_points = self.ui.polynomial_stitching_points_spinbox.value() + Configuration.wl_bandwidth = self.ui.bandwidth_spinbox.value() + + Configuration.use_constant_q = self.ui.fanReflectivity.isChecked() configuration.use_dangle = self.ui.trustDANGLE.isChecked() configuration.set_direct_pixel = self.ui.set_dirpix_checkbox.isChecked() configuration.set_direct_angle_offset = self.ui.set_dangle0_checkbox.isChecked() configuration.direct_pixel_overwrite = self.ui.directPixelOverwrite.value() configuration.direct_angle_offset_overwrite = self.ui.dangle0Overwrite.value() - configuration.sample_size = self.ui.sample_size_spinbox.value() - configuration.do_final_rebin = self.ui.final_rebin_checkbox.isChecked() - configuration.final_rebin_step = self.ui.q_rebin_spinbox.value() + Configuration.sample_size = self.ui.sample_size_spinbox.value() + Configuration.do_final_rebin = self.ui.final_rebin_checkbox.isChecked() + Configuration.final_rebin_step = self.ui.q_rebin_spinbox.value() # UI elements configuration.normalize_x_tof = self.ui.normalizeXTof.isChecked() From f01c8ab809fcdd5fa836966d042bb6dea947bb68 Mon Sep 17 00:00:00 2001 From: Ross Whitfield Date: Thu, 28 Mar 2024 14:25:20 +1100 Subject: [PATCH 3/3] Add UI test checking that Global properties apply to all runs while "Per Run" properties do not --- test/ui/test_main_window.py | 178 ++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) diff --git a/test/ui/test_main_window.py b/test/ui/test_main_window.py index 6c9fb51a..a714c086 100644 --- a/test/ui/test_main_window.py +++ b/test/ui/test_main_window.py @@ -89,6 +89,184 @@ def handle_menu(): pos = QtCore.QPoint() table.customContextMenuRequested.emit(pos) + def test_global_vs_per_run(self, qtbot, mocker): + """Test the global vs per run reduction variables""" + + # mock updating the plots + mocker.patch("reflectivity_ui.interfaces.main_window.MainWindow.plotActiveTab", return_value=True) + mocker.patch("reflectivity_ui.interfaces.plotting.PlotManager.plot_refl", return_value=True) + mocker.patch("reflectivity_ui.interfaces.plotting.PlotManager.plot_projections", return_value=True) + + window_main = MainWindow() + qtbot.addWidget(window_main) + + # set up data objects for two files + configuration = Configuration() + # make sure these global properties start as the defult + Configuration.wl_bandwidth = 3.2 + Configuration.use_constant_q = False + Configuration.sample_size = 10 + Configuration.do_final_rebin = True + Configuration.final_rebin_step = -0.01 + Configuration.normalize_to_unity = True + Configuration.total_reflectivity_q_cutoff = 0.01 + Configuration.global_stitching = False + Configuration.polynomial_stitching = False + Configuration.polynomial_stitching_degree = 3 + Configuration.polynomial_stitching_points = 3 + + channel1 = CrossSectionData("On_Off", configuration) + nexus_data1 = NexusData("filepath1", configuration) + nexus_data1.cross_sections = {channel1.name: channel1, channel1.name: channel1} + channel2 = CrossSectionData("On_Off", configuration) + nexus_data2 = NexusData("filepath2", configuration) + nexus_data2.cross_sections = {channel2.name: channel2, channel2.name: channel2} + + window_main.data_manager.reduction_list.append(nexus_data1) + window_main.data_manager.reduction_list.append(nexus_data2) + window_main.data_manager.set_active_data_from_reduction_list(0) + assert window_main.data_manager.current_file == "filepath1" + + # check that the configuration is the default + conf1 = window_main.data_manager.active_channel.configuration + + # Reflectivity Extraction (Global) + assert conf1.do_final_rebin is True + assert conf1.final_rebin_step == -0.01 + assert conf1.normalize_to_unity is True + assert conf1.total_reflectivity_q_cutoff == 0.01 + assert conf1.global_stitching is False + assert conf1.polynomial_stitching is False + assert conf1.polynomial_stitching_degree == 3 + assert conf1.polynomial_stitching_points == 3 + assert conf1.use_constant_q is False + assert conf1.sample_size == 10 + assert conf1.wl_bandwidth == 3.2 + + # Reflectivity Extraction (Per Run) + + assert conf1.low_res_position == 130 + assert conf1.low_res_width == 20 + assert conf1.peak_position == 130 + assert conf1.peak_width == 20 + assert conf1.subtract_background is True + assert conf1.bck_position == 30 + assert conf1.bck_width == 20 + assert conf1.scaling_factor == 1.0 + assert conf1.cut_first_n_points == 1 + assert conf1.cut_last_n_points == 1 + assert conf1.set_direct_pixel is False + assert conf1.direct_pixel_overwrite == 0 + assert conf1.set_direct_angle_offset is False + assert conf1.direct_angle_offset_overwrite == 0 + assert conf1.use_dangle is False + + # set UI elements to non-default + + # global + window_main.ui.final_rebin_checkbox.setChecked(False) + window_main.ui.q_rebin_spinbox.setValue(-0.02) + window_main.ui.normalize_to_unity_checkbox.setChecked(False) + window_main.ui.normalization_q_cutoff_spinbox.setValue(0.02) + window_main.ui.global_fit_checkbox.setChecked(True) + window_main.ui.polynomial_stitching_checkbox.setChecked(True) + window_main.ui.polynomial_stitching_degree_spinbox.setValue(4) + window_main.ui.polynomial_stitching_points_spinbox.setValue(5) + window_main.ui.fanReflectivity.setChecked(True) + window_main.ui.sample_size_spinbox.setValue(12) + window_main.ui.bandwidth_spinbox.setValue(2.3) + # per run + window_main.ui.refYPos.setValue(120) + window_main.ui.refYWidth.setValue(30) + window_main.ui.refXPos.setValue(120) + window_main.ui.refXWidth.setValue(30) + window_main.ui.bgActive.setChecked(False) + window_main.ui.bgCenter.setValue(20) + window_main.ui.bgWidth.setValue(15) + window_main.ui.refScale.setValue(1.0) + window_main.ui.rangeStart.setValue(2) + window_main.ui.rangeEnd.setValue(3) + window_main.ui.set_dirpix_checkbox.setChecked(True) + window_main.ui.directPixelOverwrite.setValue(1.0) + window_main.ui.set_dangle0_checkbox.setChecked(True) + window_main.ui.dangle0Overwrite.setValue(2.0) + window_main.ui.trustDANGLE.setChecked(True) + + window_main.file_handler.get_configuration() # to update configuration from UI + + # check that the current config has been updated for both global and per run + conf1 = window_main.data_manager.active_channel.configuration + + # Reflectivity Extraction (Global) + assert conf1.do_final_rebin is False + assert conf1.final_rebin_step == -0.02 + assert conf1.normalize_to_unity is False + assert conf1.total_reflectivity_q_cutoff == 0.02 + assert conf1.global_stitching is True + assert conf1.polynomial_stitching is True + assert conf1.polynomial_stitching_degree == 4 + assert conf1.polynomial_stitching_points == 5 + assert conf1.use_constant_q is True + assert conf1.sample_size == 12 + assert conf1.wl_bandwidth == 2.3 + + # Reflectivity Extraction (Per Run) + + assert conf1.low_res_position == 120 + assert conf1.low_res_width == 30 + assert conf1.peak_position == 120 + assert conf1.peak_width == 30 + assert conf1.subtract_background is False + assert conf1.bck_position == 20 + assert conf1.bck_width == 15 + assert conf1.scaling_factor == 10.0 + assert conf1.cut_first_n_points == 2 + assert conf1.cut_last_n_points == 3 + assert conf1.set_direct_pixel is True + assert conf1.direct_pixel_overwrite == 1.0 + assert conf1.set_direct_angle_offset is True + assert conf1.direct_angle_offset_overwrite == 2.0 + assert conf1.use_dangle is True + + # change selected data and check that global variables are carried over but not the per run ones + + window_main.data_manager.set_active_data_from_reduction_list(1) + assert window_main.data_manager.current_file == "filepath2" + + # check that the configuration is the default + conf2 = window_main.data_manager.active_channel.configuration + + # Reflectivity Extraction (Global) + assert conf2.do_final_rebin is False + assert conf2.final_rebin_step == -0.02 + assert conf2.normalize_to_unity is False + assert conf2.total_reflectivity_q_cutoff == 0.02 + assert conf2.global_stitching is True + assert conf2.polynomial_stitching is True + assert conf2.polynomial_stitching_degree == 4 + assert conf2.polynomial_stitching_points == 5 + assert conf2.use_constant_q is True + assert conf2.sample_size == 12 + assert conf2.wl_bandwidth == 2.3 + + # Reflectivity Extraction (Per Run) + + assert conf2.low_res_position == 130 + assert conf2.low_res_width == 20 + assert conf2.peak_position == 130 + assert conf2.peak_width == 20 + assert conf2.subtract_background is True + assert conf2.bck_position == 30 + assert conf2.bck_width == 20 + assert conf2.scaling_factor == 1.0 + assert conf2.cut_first_n_points == 1 + assert conf2.cut_last_n_points == 1 + assert conf2.set_direct_pixel is False + assert conf2.direct_pixel_overwrite == 0 + assert conf2.set_direct_angle_offset is False + assert conf2.direct_angle_offset_overwrite == 0 + assert conf2.use_dangle is False + if __name__ == "__main__": pytest.main([__file__])