def get_detector_size_from_sans_file(state, detector): instrument_file = get_instrument_paths_for_sans_file(state.data.sample_scatter) if detector == DetectorType.HAB: x_dim = get_named_elements_from_ipf_file(instrument_file[1], "high-angle-detector-num-columns", float)['high-angle-detector-num-columns'] y_dim = get_named_elements_from_ipf_file(instrument_file[1], "high-angle-detector-num-rows", float)['high-angle-detector-num-rows'] else: x_dim = get_named_elements_from_ipf_file(instrument_file[1], "low-angle-detector-num-columns", float)[ 'low-angle-detector-num-columns'] y_dim = get_named_elements_from_ipf_file(instrument_file[1], "low-angle-detector-num-rows", float)[ 'low-angle-detector-num-rows'] return x_dim, y_dim
def reset_to_defaults_for_instrument(self, file_information = None): r_range = {} instrument = None if file_information: instrument_file_path = get_instrument_paths_for_sans_file(file_information=file_information) r_range = get_named_elements_from_ipf_file(instrument_file_path[1], ["beam_centre_radius_min", "beam_centre_radius_max"], float) instrument = file_information.get_instrument() self._max_iterations = 10 self._r_min = r_range["beam_centre_radius_min"] if "beam_centre_radius_min" in r_range else 60 self._r_max = r_range["beam_centre_radius_max"] if "beam_centre_radius_max" in r_range else 280 self._left_right = True self._up_down = True self._tolerance = 0.0001251 self._lab_pos_1 = '' self._lab_pos_2 = '' self._hab_pos_2 = '' self._hab_pos_1 = '' self.scale_1 = 1000 self.scale_2 = 1000 self.COM = False self.verbose = False self.q_min = 0.01 self.q_max = 0.1 self._component = DetectorType.LAB self.update_lab = True self.update_hab = True if instrument == SANSInstrument.LARMOR: self.scale_1 = 1.0
def set_detector_names(state, ipf_path): """ Sets the detectors names on a State object which has a `detector` map entry, e.g. StateMask @param state: the state object @param ipf_path: the path to the Instrument Parameter File """ lab_keyword = DetectorType.to_string(DetectorType.LAB) hab_keyword = DetectorType.to_string(DetectorType.HAB) detector_names = {lab_keyword: "low-angle-detector-name", hab_keyword: "high-angle-detector-name"} detector_names_short = {lab_keyword: "low-angle-detector-short-name", hab_keyword: "high-angle-detector-short-name"} names_to_search = [] names_to_search.extend(detector_names.values()) names_to_search.extend(detector_names_short.values()) found_detector_names = get_named_elements_from_ipf_file(ipf_path, names_to_search, str) for detector_type in state.detectors: try: detector_name_tag = detector_names[detector_type] detector_name_short_tag = detector_names_short[detector_type] detector_name = found_detector_names[detector_name_tag] detector_name_short = found_detector_names[detector_name_short_tag] except KeyError: continue state.detectors[detector_type].detector_name = detector_name state.detectors[detector_type].detector_name_short = detector_name_short
def get_position_steps(self, state): instrument_file = get_instrument_paths_for_sans_file(state.data.sample_scatter) position_1_step = get_named_elements_from_ipf_file( instrument_file[1], ["centre-finder-step-size"], float)['centre-finder-step-size'] try: position_2_step = get_named_elements_from_ipf_file( instrument_file[1], ["centre-finder-step-size2"], float)['centre-finder-step-size2'] except: position_2_step = position_1_step find_direction = self.getProperty("Direction").value if find_direction == FindDirectionEnum.LEFT_RIGHT.value: position_2_step = 0.0 elif find_direction == FindDirectionEnum.UP_DOWN.value: position_1_step = 0.0 return position_1_step, position_2_step
def set_default_incident_monitor(normalize_monitor_info, data_info): """ The default incident monitor is stored on the IPF. :param normalize_monitor_info: a StateNormalizeMonitor object on which we set the default value :param data_info: a StateData object """ ipf_file_path = data_info.ipf_file_path named_element = "default-incident-monitor-spectrum" monitor_spectrum_tag_to_search = [named_element] found_monitor_spectrum = get_named_elements_from_ipf_file(ipf_file_path, monitor_spectrum_tag_to_search, int) if named_element in found_monitor_spectrum: normalize_monitor_info.incident_monitor = found_monitor_spectrum[named_element]
def set_default_incident_monitor(normalize_monitor_info, data_info): """ The default incident monitor is stored on the IPF. :param normalize_monitor_info: a StateNormalizeMonitor object on which we set the default value :param data_info: a StateData object """ ipf_file_path = data_info.ipf_file_path named_element = "default-incident-monitor-spectrum" monitor_spectrum_tag_to_search = [named_element] found_monitor_spectrum = get_named_elements_from_ipf_file( ipf_file_path, monitor_spectrum_tag_to_search, int) if named_element in found_monitor_spectrum: normalize_monitor_info.incident_monitor = found_monitor_spectrum[ named_element]
def set_default_monitors(calculate_transmission_info, data_info): """ The default incident monitor is stored on the IPF. :param calculate_transmission_info: a StateCalculateTransmission object on which we set the default value :param data_info: a StateData object """ ipf_file_path = data_info.ipf_file_path incident_tag = "default-incident-monitor-spectrum" transmission_tag = "default-transmission-monitor-spectrum" monitors_to_search = [incident_tag, transmission_tag] found_monitor_spectrum = get_named_elements_from_ipf_file(ipf_file_path, monitors_to_search, int) if incident_tag in found_monitor_spectrum: calculate_transmission_info.default_incident_monitor = found_monitor_spectrum[incident_tag] if transmission_tag in found_monitor_spectrum: calculate_transmission_info.default_transmission_monitor = found_monitor_spectrum[transmission_tag]
def setup_detectors_from_ipf(reduction_info, data_info): ipf_file_path = data_info.ipf_file_path detector_names = {DetectorType.to_string(DetectorType.LAB): "low-angle-detector-name", DetectorType.to_string(DetectorType.HAB): "high-angle-detector-name"} names_to_search = [] names_to_search.extend(list(detector_names.values())) found_detector_names = get_named_elements_from_ipf_file(ipf_file_path, names_to_search, str) for detector_type in list(reduction_info.detector_names.keys()): try: detector_name_tag = detector_names[detector_type] detector_name = found_detector_names[detector_name_tag] except KeyError: continue reduction_info.detector_names[detector_type] = detector_name
def test_that_named_entries_in_instrument_parameter_file_can_be_retrieved(self): # Arrange test_file = "LARMOR00003368" file_information_factory = SANSFileInformationFactory() file_information = file_information_factory.create_sans_file_information(test_file) full_file_path = file_information.get_file_name() _, ipf = get_instrument_paths_for_sans_file(full_file_path) to_search = ["low-angle-detector-name", "high-angle-detector-short-name"] # Act results = get_named_elements_from_ipf_file(ipf, to_search, str) # Assert self.assertTrue(len(results) == 2) self.assertTrue(results["low-angle-detector-name"] == "DetectorBench") self.assertTrue(results["high-angle-detector-short-name"] == "front")
def set_detector_names(state, ipf_path, invalid_detector_types=None): """ Sets the detectors names on a State object which has a `detector` map entry, e.g. StateMask :param state: the state object :param ipf_path: the path to the Instrument Parameter File :param invalid_detector_types: a list of invalid detector types which don't exist for the instrument """ if invalid_detector_types is None: invalid_detector_types = [] lab_keyword = DetectorType.to_string(DetectorType.LAB) hab_keyword = DetectorType.to_string(DetectorType.HAB) detector_names = { lab_keyword: "low-angle-detector-name", hab_keyword: "high-angle-detector-name" } detector_names_short = { lab_keyword: "low-angle-detector-short-name", hab_keyword: "high-angle-detector-short-name" } names_to_search = [] names_to_search.extend(list(detector_names.values())) names_to_search.extend(list(detector_names_short.values())) found_detector_names = get_named_elements_from_ipf_file( ipf_path, names_to_search, str) for detector_type in state.detectors: try: if DetectorType.from_string( detector_type) in invalid_detector_types: continue detector_name_tag = detector_names[detector_type] detector_name_short_tag = detector_names_short[detector_type] detector_name = found_detector_names[detector_name_tag] detector_name_short = found_detector_names[detector_name_short_tag] except KeyError: continue state.detectors[detector_type].detector_name = detector_name state.detectors[ detector_type].detector_name_short = detector_name_short
def setup_detectors_from_ipf(reduction_info, data_info): file_name = data_info.sample_scatter _, ipf_path = get_instrument_paths_for_sans_file(file_name) detector_names = {DetectorType.to_string(DetectorType.LAB): "low-angle-detector-name", DetectorType.to_string(DetectorType.HAB): "high-angle-detector-name"} names_to_search = [] names_to_search.extend(detector_names.values()) found_detector_names = get_named_elements_from_ipf_file(ipf_path, names_to_search, str) for detector_type in reduction_info.detector_names.keys(): try: detector_name_tag = detector_names[detector_type] detector_name = found_detector_names[detector_name_tag] except KeyError: continue reduction_info.detector_names[detector_type] = detector_name
def reset_to_defaults_for_instrument(self, file_information=None): r_range = {} instrument = None if file_information: instrument_file_path = get_instrument_paths_for_sans_file( file_information=file_information) r_range = get_named_elements_from_ipf_file( instrument_file_path[1], ["beam_centre_radius_min", "beam_centre_radius_max"], float) instrument = file_information.get_instrument() self._max_iterations = 10 self._r_min = r_range[ "beam_centre_radius_min"] if "beam_centre_radius_min" in r_range else 60 self._r_max = r_range[ "beam_centre_radius_max"] if "beam_centre_radius_max" in r_range else 280 self._left_right = True self._up_down = True self._tolerance = 0.0001251 self._lab_pos_1 = '' self._lab_pos_2 = '' self._hab_pos_2 = '' self._hab_pos_1 = '' self.scale_1 = 1000 self.scale_2 = 1000 self.COM = False self.verbose = False self.q_min = 0.01 self.q_max = 0.1 self._component = DetectorType.LAB self.update_lab = True self.update_hab = True if instrument == SANSInstrument.LARMOR: self.scale_1 = 1.0
def set_detector_names(state, ipf_path, invalid_detector_types=None): """ Sets the detectors names on a State object which has a `detector` map entry, e.g. StateMask :param state: the state object :param ipf_path: the path to the Instrument Parameter File :param invalid_detector_types: a list of invalid detector types which don't exist for the instrument """ if invalid_detector_types is None: invalid_detector_types = [] lab_keyword = DetectorType.to_string(DetectorType.LAB) hab_keyword = DetectorType.to_string(DetectorType.HAB) detector_names = {lab_keyword: "low-angle-detector-name", hab_keyword: "high-angle-detector-name"} detector_names_short = {lab_keyword: "low-angle-detector-short-name", hab_keyword: "high-angle-detector-short-name"} names_to_search = [] names_to_search.extend(list(detector_names.values())) names_to_search.extend(list(detector_names_short.values())) found_detector_names = get_named_elements_from_ipf_file(ipf_path, names_to_search, str) for detector_type in state.detectors: try: if DetectorType.from_string(detector_type) in invalid_detector_types: continue detector_name_tag = detector_names[detector_type] detector_name_short_tag = detector_names_short[detector_type] detector_name = found_detector_names[detector_name_tag] detector_name_short = found_detector_names[detector_name_short_tag] except KeyError: continue state.detectors[detector_type].detector_name = detector_name state.detectors[detector_type].detector_name_short = detector_name_short
def get_geometry_information(ipf_path, detector_type): """ This function extracts geometry information for the detector benches. The information requested is: 1. Are we dealing with a rectangular detector 2. What is the width 3. What is the height 4. If the detector has a hole in somewhere then the total number of pixels cannot be solely determined by height and width. This provides an override for the number of pixels :param ipf_path: The path to the Instrument Parameter File. :param detector_type: The type of detector for which we should get the information. :return: Geometry information for LAB and HAB as well as the firs """ def create_detector_shape_bundle(num_columns, non_rectangle_width, num_rows, non_rectangle_height, num_pixels): cols_data = num_columns if len(cols_data) > 0: rectangular_shape = True width = int(cols_data[0]) else: rectangular_shape = False width = int(non_rectangle_width[0]) rows_data = num_rows if len(rows_data) > 0: height = int(rows_data[0]) else: rectangular_shape = False height = int(non_rectangle_height[0]) number_of_pixels = num_pixels if len(number_of_pixels) > 0: number_of_pixels_override = int(number_of_pixels[0]) else: number_of_pixels_override = None return detector_shape_bundle( rectangular_shape=rectangular_shape, width=width, height=height, number_of_pixels_override=number_of_pixels_override) # Determine the prefix for the detector if detector_type is DetectorType.LAB: prefix = "low-angle-detector-" elif detector_type is DetectorType.HAB: prefix = "high-angle-detector-" else: raise RuntimeError( "MaskingParser: Tyring to get information for unknown " "detector {0}".format(str(detector_type))) search_items_for_detectors = [ "num-columns", "non-rectangle-width", "num-rows", "non-rectangle-height", "num-pixels" ] search_items = [prefix + item for item in search_items_for_detectors] search_items.append("first-low-angle-spec-number") found_items = get_named_elements_from_ipf_file(ipf_path, search_items, int) # Some items might not have been found, it they are not in the dictionary, then add an empty list not_found_items = [ item for item in search_items if item not in list(found_items.keys()) ] for not_found_item in not_found_items: found_items.update({not_found_item: []}) # The old code assumed that we have an iterable value, which is not normally true, hence make it iterable for key, value in list(found_items.items()): if not isinstance(value, Sequence): found_items[key] = [value] shape = create_detector_shape_bundle( num_columns=found_items[prefix + "num-columns"], non_rectangle_width=found_items[prefix + "non-rectangle-width"], num_rows=found_items[prefix + "num-rows"], non_rectangle_height=found_items[prefix + "non-rectangle-height"], num_pixels=found_items[prefix + "num-pixels"]) return geometry_bundle( shape=shape, first_low_angle_spec_number=found_items["first-low-angle-spec-number"])
def PyExec(self): state = self._get_state() state_serialized = state.property_manager logger = Logger("CentreFinder") logger.notice("Starting centre finder routine...") progress = self._get_progress() self.scale_1 = 1000 self.scale_2 = 1000 verbose = self.getProperty('Verbose').value x_start = self.getProperty("Position1Start").value y_start = self.getProperty("Position2Start").value sample_scatter = self._get_cloned_workspace("SampleScatterWorkspace") sample_scatter_monitor = self._get_cloned_workspace("SampleScatterMonitorWorkspace") sample_transmission = self._get_cloned_workspace("SampleTransmissionWorkspace") sample_direct = self._get_cloned_workspace("SampleDirectWorkspace") instrument = sample_scatter.getInstrument() if instrument.getName() == 'LARMOR': self.scale_1 = 1.0 can_scatter = self._get_cloned_workspace("CanScatterWorkspace") can_scatter_monitor = self._get_cloned_workspace("CanScatterMonitorWorkspace") can_transmission = self._get_cloned_workspace("CanTransmissionWorkspace") can_direct = self._get_cloned_workspace("CanDirectWorkspace") component = self.getProperty("Component").value tolerance = self.getProperty("Tolerance").value max_iterations = self.getProperty("Iterations").value r_min = self.getProperty("RMin").value r_max = self.getProperty("RMax").value instrument_file = get_instrument_paths_for_sans_file(state.data.sample_scatter) position_1_step = get_named_elements_from_ipf_file( instrument_file[1], ["centre-finder-step-size"], float)['centre-finder-step-size'] try: position_2_step = get_named_elements_from_ipf_file( instrument_file[1], ["centre-finder-step-size2"], float)['centre-finder-step-size2'] except: position_2_step = position_1_step find_direction = self.getProperty("Direction").value if find_direction == FindDirectionEnum.to_string(FindDirectionEnum.Left_Right): position_2_step = 0.0 elif find_direction == FindDirectionEnum.to_string(FindDirectionEnum.Up_Down): position_1_step = 0.0 centre1 = x_start centre2 = y_start residueLR = [] residueTB = [] centre_1_hold = x_start centre_2_hold = y_start for j in range(0, max_iterations + 1): if(j != 0): centre1 += position_1_step centre2 += position_2_step progress.report("Reducing ... Pos1 " + str(centre1) + " Pos2 " + str(centre2)) sample_quartiles = self._run_quartile_reduction(sample_scatter, sample_transmission, sample_direct, "Sample", sample_scatter_monitor, component, state_serialized, centre1, centre2, r_min, r_max) if can_scatter: can_quartiles = self._run_quartile_reduction(can_scatter, can_transmission, can_direct, "Can", can_scatter_monitor, component, state_serialized, centre1, centre2, r_min, r_max) for key in sample_quartiles: sample_quartiles[key] = perform_can_subtraction(sample_quartiles[key], can_quartiles[key], self) if mantidplot: output_workspaces = self._publish_to_ADS(sample_quartiles) if verbose: self._rename_and_group_workspaces(j, output_workspaces) residueLR.append(self._calculate_residuals(sample_quartiles[MaskingQuadrant.Left], sample_quartiles[MaskingQuadrant.Right])) residueTB.append(self._calculate_residuals(sample_quartiles[MaskingQuadrant.Top], sample_quartiles[MaskingQuadrant.Bottom])) if(j == 0): logger.notice("Itr {0}: ( {1}, {2} ) SX={3:.5g} SY={4:.5g}". format(j, self.scale_1 * centre1, self.scale_2 * centre2, residueLR[j], residueTB[j])) if mantidplot: self._plot_quartiles(output_workspaces, state.data.sample_scatter) else: # have we stepped across the y-axis that goes through the beam center? if residueLR[j] > residueLR[j-1]: # yes with stepped across the middle, reverse direction and half the step size position_1_step = - position_1_step / 2 if residueTB[j] > residueTB[j-1]: position_2_step = - position_2_step / 2 logger.notice("Itr {0}: ( {1}, {2} ) SX={3:.5g} SY={4:.5g}". format(j, self.scale_1 * centre1, self.scale_2 * centre2, residueLR[j], residueTB[j])) if (residueLR[j]+residueTB[j]) < (residueLR[j-1]+residueTB[j-1]) or state.compatibility.use_compatibility_mode: centre_1_hold = centre1 centre_2_hold = centre2 if abs(position_1_step) < tolerance and abs(position_2_step) < tolerance: # this is the success criteria, we've close enough to the center logger.notice("Converged - check if stuck in local minimum! ") break if j == max_iterations: logger.notice("Out of iterations, new coordinates may not be the best") self.setProperty("Centre1", centre_1_hold) self.setProperty("Centre2", centre_2_hold) logger.notice("Centre coordinates updated: [{}, {}]".format(centre_1_hold*self.scale_1, centre_2_hold*self.scale_2))
def PyExec(self): state = self._get_state() state_serialized = state.property_manager logger = Logger("CentreFinder") logger.notice("Starting centre finder routine...") progress = self._get_progress() self.scale_1 = 1000 self.scale_2 = 1000 verbose = self.getProperty('Verbose').value x_start = self.getProperty("Position1Start").value y_start = self.getProperty("Position2Start").value sample_scatter = self._get_cloned_workspace("SampleScatterWorkspace") sample_scatter_monitor = self._get_cloned_workspace( "SampleScatterMonitorWorkspace") sample_transmission = self._get_cloned_workspace( "SampleTransmissionWorkspace") sample_direct = self._get_cloned_workspace("SampleDirectWorkspace") instrument = sample_scatter.getInstrument() if instrument.getName() == 'LARMOR': self.scale_1 = 1.0 can_scatter = self._get_cloned_workspace("CanScatterWorkspace") can_scatter_monitor = self._get_cloned_workspace( "CanScatterMonitorWorkspace") can_transmission = self._get_cloned_workspace( "CanTransmissionWorkspace") can_direct = self._get_cloned_workspace("CanDirectWorkspace") component = self.getProperty("Component").value tolerance = self.getProperty("Tolerance").value max_iterations = self.getProperty("Iterations").value r_min = self.getProperty("RMin").value r_max = self.getProperty("RMax").value instrument_file = get_instrument_paths_for_sans_file( state.data.sample_scatter) position_1_step = get_named_elements_from_ipf_file( instrument_file[1], "centre-finder-step-size", float)['centre-finder-step-size'] try: position_2_step = get_named_elements_from_ipf_file( instrument_file[1], "centre-finder-step-size2", float)['centre-finder-step-size2'] except: position_2_step = position_1_step find_direction = self.getProperty("Direction").value if find_direction == FindDirectionEnum.to_string( FindDirectionEnum.Left_Right): position_2_step = 0.0 elif find_direction == FindDirectionEnum.to_string( FindDirectionEnum.Up_Down): position_1_step = 0.0 centre1 = x_start centre2 = y_start residueLR = [] residueTB = [] centre_1_hold = x_start centre_2_hold = y_start for j in range(0, max_iterations + 1): if (j != 0): centre1 += position_1_step centre2 += position_2_step progress.report("Reducing ... Pos1 " + str(centre1) + " Pos2 " + str(centre2)) sample_quartiles = self._run_quartile_reduction( sample_scatter, sample_transmission, sample_direct, "Sample", sample_scatter_monitor, component, state_serialized, centre1, centre2, r_min, r_max) if can_scatter: can_quartiles = self._run_quartile_reduction( can_scatter, can_transmission, can_direct, "Can", can_scatter_monitor, component, state_serialized, centre1, centre2, r_min, r_max) for key in sample_quartiles: sample_quartiles[key] = perform_can_subtraction( sample_quartiles[key], can_quartiles[key], self) if mantidplot: output_workspaces = self._publish_to_ADS(sample_quartiles) if verbose: self._rename_and_group_workspaces(j, output_workspaces) residueLR.append( self._calculate_residuals( sample_quartiles[MaskingQuadrant.Left], sample_quartiles[MaskingQuadrant.Right])) residueTB.append( self._calculate_residuals( sample_quartiles[MaskingQuadrant.Top], sample_quartiles[MaskingQuadrant.Bottom])) if (j == 0): logger.notice("Itr " + str(j) + ": (" + str(self.scale_1 * centre1) + ", " + str(self.scale_2 * centre2) + ") SX=" + str(residueLR[j]) + " SY=" + str(residueTB[j])) if mantidplot: self._plot_quartiles(output_workspaces, state.data.sample_scatter) else: # have we stepped across the y-axis that goes through the beam center? if residueLR[j] > residueLR[j - 1]: # yes with stepped across the middle, reverse direction and half the step size position_1_step = -position_1_step / 2 if residueTB[j] > residueTB[j - 1]: position_2_step = -position_2_step / 2 logger.notice("Itr " + str(j) + ": (" + str(self.scale_1 * centre1) + ", " + str(self.scale_2 * centre2) + ") SX=" + str(residueLR[j]) + " SY=" + str(residueTB[j])) if (residueLR[j] + residueTB[j]) < ( residueLR[j - 1] + residueTB[j - 1] ) or state.compatibility.use_compatibility_mode: centre_1_hold = centre1 centre_2_hold = centre2 if abs(position_1_step) < tolerance and abs( position_2_step) < tolerance: # this is the success criteria, we've close enough to the center logger.notice( "Converged - check if stuck in local minimum! ") break if j == max_iterations: logger.notice( "Out of iterations, new coordinates may not be the best") self.setProperty("Centre1", centre_1_hold) self.setProperty("Centre2", centre_2_hold) logger.notice("Centre coordinates updated: [{}, {}]".format( centre_1_hold * self.scale_1, centre_2_hold * self.scale_2))
def get_geometry_information(ipf_path, detector_type): """ This function extracts geometry information for the detector benches. The information requested is: 1. Are we dealing with a rectangular detector 2. What is the width 3. What is the height 4. If the detector has a hole in somewhere then the total number of pixels cannot be solely determined by height and width. This provides an override for the number of pixels :param ipf_path: The path to the Instrument Parameter File. :param detector_type: The type of detector for which we should get the information. :return: Geometry information for LAB and HAB as well as the firs """ def create_detector_shape_bundle(num_columns, non_rectangle_width, num_rows, non_rectangle_height, num_pixels): cols_data = num_columns if len(cols_data) > 0: rectangular_shape = True width = int(cols_data[0]) else: rectangular_shape = False width = int(non_rectangle_width[0]) rows_data = num_rows if len(rows_data) > 0: height = int(rows_data[0]) else: rectangular_shape = False height = int(non_rectangle_height[0]) number_of_pixels = num_pixels if len(number_of_pixels) > 0: number_of_pixels_override = int(number_of_pixels[0]) else: number_of_pixels_override = None return detector_shape_bundle(rectangular_shape=rectangular_shape, width=width, height=height, number_of_pixels_override=number_of_pixels_override) # Determine the prefix for the detector if detector_type is DetectorType.LAB: prefix = "low-angle-detector-" elif detector_type is DetectorType.HAB: prefix = "high-angle-detector-" else: raise RuntimeError("MaskingParser: Tyring to get information for unknown " "detector {0}".format(str(detector_type))) search_items_for_detectors = ["num-columns", "non-rectangle-width", "num-rows", "non-rectangle-height", "num-pixels"] search_items = [prefix + item for item in search_items_for_detectors] search_items.append("first-low-angle-spec-number") found_items = get_named_elements_from_ipf_file(ipf_path, search_items, int) # Some items might not have been found, it they are not in the dictionary, then add an empty list not_found_items = [item for item in search_items if item not in list(found_items.keys())] for not_found_item in not_found_items: found_items.update({not_found_item: []}) # The old code assumed that we have an iterable value, which is not normally true, hence make it iterable for key, value in list(found_items.items()): if not isinstance(value, Sequence): found_items[key] = [value] shape = create_detector_shape_bundle(num_columns=found_items[prefix + "num-columns"], non_rectangle_width=found_items[prefix + "non-rectangle-width"], num_rows=found_items[prefix + "num-rows"], non_rectangle_height=found_items[prefix + "non-rectangle-height"], num_pixels=found_items[prefix + "num-pixels"]) return geometry_bundle(shape=shape, first_low_angle_spec_number=found_items["first-low-angle-spec-number"])