From 30c48ab5a26d42ba5d7cb522f5909590f9de40ca Mon Sep 17 00:00:00 2001 From: Mathieu Doucet Date: Tue, 7 Jan 2025 17:06:55 -0500 Subject: [PATCH] Document template reader --- reduction/lr_reduction/event_reduction.py | 2 +- .../lr_reduction/reduction_template_reader.py | 196 ++++++++++-------- 2 files changed, 115 insertions(+), 83 deletions(-) diff --git a/reduction/lr_reduction/event_reduction.py b/reduction/lr_reduction/event_reduction.py index 8ade183..12c5660 100644 --- a/reduction/lr_reduction/event_reduction.py +++ b/reduction/lr_reduction/event_reduction.py @@ -254,7 +254,7 @@ def apply_dead_time_correction(ws, template_data): return ws -class EventReflectivity(object): +class EventReflectivity(): """ Data reduction for the Liquids Reflectometer. List of items to be taken care of outside this class: diff --git a/reduction/lr_reduction/reduction_template_reader.py b/reduction/lr_reduction/reduction_template_reader.py index d8a064c..abe2bbe 100644 --- a/reduction/lr_reduction/reduction_template_reader.py +++ b/reduction/lr_reduction/reduction_template_reader.py @@ -1,7 +1,8 @@ """ - RefRed template reader. - Adapted from Mantid code. +RefRed template reader. +Adapted from Mantid code. """ + import time import xml.dom.minidom @@ -10,12 +11,16 @@ # Get the mantid version being used, if available try: import mantid + MANTID_VERSION = mantid.__version__ except: MANTID_VERSION = "None" -class ReductionParameters(object): +class ReductionParameters(): + """ + Class that hold the parameters for the reduction of a single data set. + """ def __init__(self): # Signal selection @@ -23,11 +28,11 @@ def __init__(self): self.subtract_background = True self.two_backgrounds: bool = False self.background_roi = [137, 153, 0, 0] - self.tof_range = [9600., 21600.] + self.tof_range = [9600.0, 21600.0] self.select_tof_range = True self.data_x_range_flag = True - self.data_x_range = [115,210] + self.data_x_range = [115, 210] # Normalization self.apply_normalization = True @@ -35,7 +40,7 @@ def __init__(self): self.subtract_norm_background = True self.norm_background_roi = [137, 153] self.norm_x_range_flag = True - self.norm_x_range = [115,210] + self.norm_x_range = [115, 210] # Data files self.data_files = [0] @@ -57,30 +62,30 @@ def __init__(self): self.angle_offset_error = 0.0 # Scaling factor file - self.scaling_factor_file = '' + self.scaling_factor_file = "" self.scaling_factor_flag = True self.slits_width_flag = True # Incident medium list and selected value - self.incident_medium_list = ['air'] + self.incident_medium_list = ["air"] self.incident_medium_index_selected = 0 # Dead time correction - self.dead_time:bool = False - self.paralyzable:bool = True + self.dead_time: bool = False + self.paralyzable: bool = True self.dead_time_value = 4.2 self.dead_time_tof_step = 100 # Calculate emission time delay instead of using an effective distance for all wavelengths - self.use_emission_time:bool = True + self.use_emission_time: bool = True def from_dict(self, data_dict, permissible=True): - r""" + """ Update object's attributes with a dictionary with entries of the type attribute_name: attribute_value. Parameters ---------- - permissible: bool + permissible : bool allow keys in data_dict that are not attribute names of ReductionParameters instances. Reading from `data_dict` will result in this instance having new attributes not defined in `__init__()` @@ -100,9 +105,9 @@ def from_dict(self, data_dict, permissible=True): def to_xml(self): """ - Create XML from the current data. + Create XML from the current data. """ - _xml = "\n" + _xml = "\n" _xml += "narrow\n" _xml += "%s\n" % str(self.data_peak_range[0]) _xml += "%s\n" % str(self.data_peak_range[1]) @@ -116,7 +121,7 @@ def to_xml(self): _xml += "%s\n" % str(self.select_tof_range) _xml += "%s\n" % str(self.tof_range[0]) _xml += "%s\n" % str(self.tof_range[1]) - _xml += "%s\n" % ','.join([str(i) for i in self.data_files]) + _xml += "%s\n" % ",".join([str(i) for i in self.data_files]) _xml += "%s\n" % str(self.data_x_range[0]) _xml += "%s\n" % str(self.data_x_range[1]) _xml += "%s\n" % str(self.data_x_range_flag) @@ -170,73 +175,71 @@ def to_xml(self): def from_xml_element(self, instrument_dom): """ - Read in data from XML - @param xml_str: text to read the data from + Read in data from XML + + Parameters + ---------- + instrument_dom : xml.dom.Document """ - #Peak from/to pixels - self.data_peak_range = [getIntElement(instrument_dom, "from_peak_pixels"), - getIntElement(instrument_dom, "to_peak_pixels")] + # Peak from/to pixels + self.data_peak_range = [getIntElement(instrument_dom, "from_peak_pixels"), getIntElement(instrument_dom, "to_peak_pixels")] - #data metadata + # data metadata _tthd_value = getStringElement(instrument_dom, "tthd_value") - if _tthd_value == '': - _tthd_value = 'N/A' + if _tthd_value == "": + _tthd_value = "N/A" self.tthd_value = _tthd_value _ths_value = getStringElement(instrument_dom, "ths_value") - if _ths_value == '': - _ths_value = 'N/A' + if _ths_value == "": + _ths_value = "N/A" self.ths_value = _ths_value - #low resolution range - self.data_x_range_flag = getBoolElement(instrument_dom, "x_range_flag", - default=self.data_x_range_flag) + # low resolution range + self.data_x_range_flag = getBoolElement(instrument_dom, "x_range_flag", default=self.data_x_range_flag) - self.data_x_range = [getIntElement(instrument_dom, "x_min_pixel"), - getIntElement(instrument_dom, "x_max_pixel")] + self.data_x_range = [getIntElement(instrument_dom, "x_min_pixel"), getIntElement(instrument_dom, "x_max_pixel")] - self.norm_x_range_flag = getBoolElement(instrument_dom, "norm_x_range_flag", - default=self.norm_x_range_flag) + self.norm_x_range_flag = getBoolElement(instrument_dom, "norm_x_range_flag", default=self.norm_x_range_flag) - self.norm_x_range = [getIntElement(instrument_dom, "norm_x_min"), - getIntElement(instrument_dom, "norm_x_max")] + self.norm_x_range = [getIntElement(instrument_dom, "norm_x_min"), getIntElement(instrument_dom, "norm_x_max")] # background flag - self.subtract_background = getBoolElement(instrument_dom, "background_flag", - default=self.subtract_background) + self.subtract_background = getBoolElement(instrument_dom, "background_flag", default=self.subtract_background) # use two backgrounds flag - self.two_backgrounds = getBoolElement(instrument_dom, "two_backgrounds", - default=self.two_backgrounds) + self.two_backgrounds = getBoolElement(instrument_dom, "two_backgrounds", default=self.two_backgrounds) # background from/to pixels - self.background_roi = [getIntElement(instrument_dom, "back_roi1_from"), - getIntElement(instrument_dom, "back_roi1_to"), - getIntElement(instrument_dom, "back_roi2_from"), - getIntElement(instrument_dom, "back_roi2_to")] + self.background_roi = [ + getIntElement(instrument_dom, "back_roi1_from"), + getIntElement(instrument_dom, "back_roi1_to"), + getIntElement(instrument_dom, "back_roi2_from"), + getIntElement(instrument_dom, "back_roi2_to"), + ] # TOF range - self.select_tof_range = getBoolElement(instrument_dom, "tof_range_flag", - default=self.select_tof_range) - self.tof_range = [getFloatElement(instrument_dom, "from_tof_range"), - getFloatElement(instrument_dom, "to_tof_range")] + self.select_tof_range = getBoolElement(instrument_dom, "tof_range_flag", default=self.select_tof_range) + self.tof_range = [getFloatElement(instrument_dom, "from_tof_range"), getFloatElement(instrument_dom, "to_tof_range")] self.data_files = getIntList(instrument_dom, "data_sets") - #with or without norm - self.apply_normalization = getBoolElement(instrument_dom, "norm_flag", - default=self.apply_normalization) + # with or without norm + self.apply_normalization = getBoolElement(instrument_dom, "norm_flag", default=self.apply_normalization) - #Peak from/to pixels - self.norm_peak_range = [getIntElement(instrument_dom, "norm_from_peak_pixels"), - getIntElement(instrument_dom, "norm_to_peak_pixels")] + # Peak from/to pixels + self.norm_peak_range = [ + getIntElement(instrument_dom, "norm_from_peak_pixels"), + getIntElement(instrument_dom, "norm_to_peak_pixels"), + ] # Background subtraction option - self.subtract_norm_background = getBoolElement(instrument_dom, "norm_background_flag", - default=self.subtract_norm_background) + self.subtract_norm_background = getBoolElement(instrument_dom, "norm_background_flag", default=self.subtract_norm_background) - self.norm_background_roi = [getIntElement(instrument_dom, "norm_from_back_pixels"), - getIntElement(instrument_dom, "norm_to_back_pixels")] + self.norm_background_roi = [ + getIntElement(instrument_dom, "norm_from_back_pixels"), + getIntElement(instrument_dom, "norm_to_back_pixels"), + ] self.norm_file = getIntElement(instrument_dom, "norm_dataset") @@ -249,8 +252,7 @@ def from_xml_element(self, instrument_dom): # Angle offset self.angle_offset = getFloatElement(instrument_dom, "angle_offset", default=self.angle_offset) - self.angle_offset_error = getFloatElement(instrument_dom, "angle_offset_error", - default=self.angle_offset_error) + self.angle_offset_error = getFloatElement(instrument_dom, "angle_offset_error", default=self.angle_offset_error) # Scaling factor file and options self.scaling_factor_file = getStringElement(instrument_dom, "scaling_factor_file") @@ -262,67 +264,74 @@ def from_xml_element(self, instrument_dom): self.incident_medium_list = getStringList(instrument_dom, "incident_medium_list") self.incident_medium_index_selected = getIntElement(instrument_dom, "incident_medium_index_selected") else: - self.incident_medium_list = ['H2O'] + self.incident_medium_list = ["H2O"] self.incident_medium_index_selected = 0 # Dead time correction - self.dead_time = getBoolElement(instrument_dom, "dead_time_correction", - default=self.dead_time) - self.paralyzable = getBoolElement(instrument_dom, "dead_time_paralyzable", - default=self.paralyzable) - self.dead_time_value = getFloatElement(instrument_dom, "dead_time_value", - default=self.dead_time_value) - self.dead_time_tof_step = getFloatElement(instrument_dom, "dead_time_tof_step", - default=self.dead_time_tof_step) + self.dead_time = getBoolElement(instrument_dom, "dead_time_correction", default=self.dead_time) + self.paralyzable = getBoolElement(instrument_dom, "dead_time_paralyzable", default=self.paralyzable) + self.dead_time_value = getFloatElement(instrument_dom, "dead_time_value", default=self.dead_time_value) + self.dead_time_tof_step = getFloatElement(instrument_dom, "dead_time_tof_step", default=self.dead_time_tof_step) # Emission time # Defaults to True, but will be skipped if the necessary meta data is not found - self.use_emission_time = getBoolElement(instrument_dom, "use_emission_time", - default=True) + self.use_emission_time = getBoolElement(instrument_dom, "use_emission_time", default=True) ###### Utility functions to read XML content ######################## def getText(nodelist): - """ - Utility method to extract text out of an XML node - """ + """Utility method to extract text out of an XML node""" rc = "" for node in nodelist: if node.nodeType == node.TEXT_NODE: rc = rc + node.data return rc + def getContent(dom, tag): + """Returns the content of a tag within a dom object""" element_list = dom.getElementsByTagName(tag) return getText(element_list[0].childNodes) if len(element_list) > 0 else None + def getIntElement(dom, tag, default=None): + """Parse an integer element from the dom object""" value = getContent(dom, tag) return int(value) if value is not None else default + def getIntList(dom, tag, default=[]): + """Parse a list of integers from the dom object""" value = getContent(dom, tag) if value is not None and len(value.strip()) > 0: - return list(map(int, value.split(','))) + return list(map(int, value.split(","))) else: return default + def getFloatElement(dom, tag, default=None): + """Parse a float element from the dom object""" value = getContent(dom, tag) return float(value) if value is not None else default + def getFloatList(dom, tag, default=[]): + """Parse a list of floats from the dom object""" value = getContent(dom, tag) if value is not None and len(value.strip()) > 0: - return list(map(float, value.split(','))) + return list(map(float, value.split(","))) else: return default -def getStringElement(dom, tag, default=''): + +def getStringElement(dom, tag, default=""): + """Parse a string element from the dom object""" value = getContent(dom, tag) return value if value is not None else default + def getStringList(dom, tag, _default=[]): + """Parse a list of strings from the dom object""" elem_list = [] element_list = dom.getElementsByTagName(tag) if len(element_list) > 0: @@ -330,7 +339,9 @@ def getStringList(dom, tag, _default=[]): elem_list.append(getText(l.childNodes).strip()) return elem_list -def getBoolElement(dom, tag, true_tag='true', default=False): + +def getBoolElement(dom, tag, true_tag="true", default=False): + """Parse a boolean element from the dom object""" value = getContent(dom, tag) return value.lower() == true_tag.lower() if value is not None else default @@ -338,7 +349,17 @@ def getBoolElement(dom, tag, true_tag='true', default=False): ###### Functions to read/write a template file ###################### def to_xml(data_sets): """ - Create XML from the current data. + Create XML from the current data. + + Parameters + ---------- + data_sets : list + List of ReductionParameters instances + + Returns + ------- + str + XML string """ _xml = "\n" _xml += " REFL\n" @@ -346,25 +367,36 @@ def to_xml(data_sets): _xml += " %s\n" % VERSION _xml += " %s\n" % MANTID_VERSION _xml += " lr_reduction-%s\n" % VERSION - _xml += "\n" + _xml += "\n" for item in data_sets: _xml += item.to_xml() _xml += "\n" _xml += "\n" return _xml + def from_xml(xml_str): """ - Read in data from XML string + Read in data from XML string + + Parameters + ---------- + xml_str : str + String representation of a list of ReductionParameters instances + + Returns + ------- + list + List of ReductionParameters instances """ data_sets = [] dom = xml.dom.minidom.parseString(xml_str) element_list = dom.getElementsByTagName("Data") - if len(element_list)==0: + if len(element_list) == 0: element_list = dom.getElementsByTagName("RefLData") - if len(element_list)>0: + if len(element_list) > 0: for item in element_list: if item is not None: data_set = ReductionParameters()