diff --git a/.gitignore b/.gitignore index ee77c3f..b8b8850 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.py~ *_Definition*.xml *.vtp +.idea/ diff --git a/hb2b_geometry.py b/hb2b_geometry.py new file mode 100644 index 0000000..c5c3fc9 --- /dev/null +++ b/hb2b_geometry.py @@ -0,0 +1,218 @@ +import sys +import datetime +import helper + +# Definition of constants +HB3A_L1 = 2. + + +HB2B_SETUP = {'L1': 2.678898, + 'L2': 0.95, # arm length + 'PixelNumber': {'1K': (1024, 1024), '2K': (2048, 2048)}, + 'PixelSize': {'1K': 0.00029296875, '2K': 0.00029296875*0.5} + } + + +HZB_SETUP = {'L1': 2.678898, + 'L2': 1.13268, # arm length + 'PixelNumber': {'1K': (1024, 1024), '2K': (2048, 2048), '256': (256, 256)}, + 'PixelSize': {'1K': 0.00029296875, '2K': 0.00029296875*0.5, '256': 0.00029296875*4} + } + +XRAY_SETUP = {'L1': 2.678898, + 'L2': 0.416, # arm length + 'PixelNumber': {'1K': (1024, 1024), '2K': (2048, 2048)}, + 'PixelSize': {'1K': 0.0004000, '2K': 0.0004000*0.5} + } + + +class ResidualStressGeometry(helper.MantidGeom): + """ + HB3A geometry extended from MantidGeom + """ + def __init__(self, instname, comment=None, valid_from=None, valid_to=None): + """ + initialization + :param instname: name of instrument + :param comment: comment + :param valid_from: beginning date + :param valid_to: end date + """ + super(ResidualStressGeometry, self).__init__(instname, comment, valid_from, valid_to) + + return + + +# END-DEF-HB3A + + +def generate_1bank_2d_idf(instrument_name, geom_setup_dict, pixel_setup, output_idf_name): + """ Generate the general HB2B (or similar X-Ray) IDF file from 2018.12.01 + :param instrument_name: + :param geom_setup_dict: + :param pixel_setup: + :param output_idf_name: + :return: + """ + # generate instrument geometry object + authors = ["Wenduo Zhou"] + begin_date = '2018-12-01 00:00:01' + end_date = '2100-10-20 23:59:59' + + # boiler plate stuff + hb2b = ResidualStressGeometry(instrument_name, + comment="Created by " + ", ".join(authors), + valid_from=begin_date, + valid_to=end_date) + + # TODO/FIXME - NO HFIR Default + # hb2b.addComment('DEFAULTS') + # hb2b.addHfirDefaults() + + # source + hb2b.addComment("SOURCE") + hb2b.addModerator(geom_setup_dict['L1']) + # sample + hb2b.addComment("SAMPLE") + hb2b.addSamplePosition() + + # TODO/FIXME - NO Default + # monitor + # hb2b.addComment("MONITORS") + # hb2b.add_monitor_type() + + # Build 'arm'/panel/shiftpanel + hb2b.addComment("PANEL") + + # TODO - the following part is refactored to method add_panel in hb3a_geometry + # define arm - component + pixel_row_count, pixel_column_count = geom_setup_dict['PixelNumber'][pixel_setup] + arm_loc_dict = dict() + arm_loc_dict['r-position'] = {'value': 0.0} + arm_loc_dict['t-position'] = {'value': 0.0} + arm_loc_dict['p-position'] = {'value': 0.0} + arm_loc_dict['roty'] = {'logfile': 'value+0.0', 'id': '2theta'} # roty works as 2theta with experiment + arm_node = hb2b.add_component(type_name='arm', idfillbyfirst='x', idstart=1, idstepbyrow=pixel_column_count) + arm_loc_node = hb2b.add_location('bank1', arm_node, arm_loc_dict) + + # define type: arm + arm_type_node = hb2b.add_component_type(type_name='arm') + + # define component panel under type arm + arm_loc_dict = {'z': {'logfile': 'value+{}'.format(geom_setup_dict['L2']), 'id': 'cal::arm'}, + 'rotx': {'logfile': 'value+0.0', 'id': 'cal::flip'}, + 'roty': {'logfile': 'value+0.0', 'id': 'cal::roty'}, + 'rotz': {'logfile': 'value+0.0', 'id': 'cal::spin'}, + } + arm_node = hb2b.add_component(type_name='panel', idfillbyfirst=None, idstart=None, + idstepbyrow=None, root=arm_type_node) + hb2b.add_location(None, arm_node, arm_loc_dict) + + # add panel + panel_loc_dict = {'x': {'logfile': 'value', 'id': 'cal::deltax'}, + 'y': {'logfile': 'value', 'id': 'cal::deltay'}} + panel_type_node = hb2b.add_component_type('panel') + panel_node = hb2b.add_component(type_name='shiftpanel', idfillbyfirst=None, idstart=None, + idstepbyrow=None, root=panel_type_node) + hb2b.add_location(None, panel_node, panel_loc_dict) + + # generate rectangular detector based on 'shiftpanel' + pixel_size_x = pixel_size_y = geom_setup_dict['PixelSize'][pixel_setup] + x_start = (float(pixel_column_count)*0.5 - 0.5) * pixel_size_x + x_step = - pixel_size_x + y_start = -(float(pixel_row_count)*0.5 - 0.5) * pixel_size_y + y_step = pixel_size_y + hb2b.add_rectangular_detector(x_start=x_start, x_step=x_step, x_pixels=pixel_column_count, + y_start=y_start, y_step=y_step, y_pixels=pixel_row_count, + pixel_size_x=pixel_size_x, pixel_size_y=pixel_size_y, + pixel_size_z=0.0001) + + hb2b.write_terminal() + hb2b.writeGeom(output_idf_name) + + return + + +def generate_2d_configure(instrument_name, geom_setup_dict, pixel_setup, hydra_idf_name): + """ Generate an ASCII file for the instrument configuration + Here is the example: + ``` + # ASCII instrument configuration file for 2K detector (2048 x 2048) + arm = 0.416 + rows = 2048 + columns = 2048 + pixel_size_x = 0.0002 + pixel_size_y = 0.0002 + ``` + :param instrument_name: + :param geom_setup_dict: + :param pixel_setup: + :param hydra_idf_name: + :return: + """ + pixel_row_count, pixel_column_count = geom_setup_dict['PixelNumber'][pixel_setup] + + config_str = '# Instrument configuration file for {} ({})\n'.format(instrument_name, pixel_setup) + config_str += 'arm = {}\n'.format(geom_setup_dict['L2']) + config_str += 'rows = {}\n'.format(pixel_row_count) + config_str += 'columns = {}\n'.format(pixel_column_count) + config_str += 'pixel_size_x = {}\n'.format(geom_setup_dict['PixelSize'][pixel_setup]) + config_str += 'pixel_size_y = {}\n'.format(geom_setup_dict['PixelSize'][pixel_setup]) + + # write out + idf_file = open(hydra_idf_name, 'w') + idf_file.write(config_str) + idf_file.close() + + return + + +def main(argv): + """ Main + :param argv: + :return: + """ + if len(argv) < 3: + print ('Generate HB2B IDF: {} [hb2b [xray, hzb]] [1k [2k]]'.format(argv[0])) + sys.exit(0) + + instrument = argv[1] + if instrument == 'hb2b': + geom_setup_dict = HB2B_SETUP + instrument_name = 'HB2B' + elif instrument == 'xray': + geom_setup_dict = XRAY_SETUP + instrument_name = 'XRAY' + elif instrument == 'hzb': + geom_setup_dict = HZB_SETUP + instrument_name = 'HZB' + else: + print ('[ERROR] Instrument {} is not supported.'.format(instrument)) + sys.exit(-1) + + # about the number of pixels setup + pixel_setup = argv[2] + if pixel_setup == '1k': + pixel_setup = '1K' + elif pixel_setup == '2k': + pixel_setup = '2K' + else: + print ('[ERROR] Pixel setup {} is not supported.'.format(pixel_setup)) + + # create instrument + now = datetime.datetime.now() + + output_idf_name = '{}_Definition_{:04}{:02}{:02}_{:02}{:02}.xml' \ + ''.format(instrument_name, now.year, now.month, now.day, + now.hour, now.minute) + output_config_name = '{}_Definition_{:04}{:02}{:02}_{:02}{:02}.txt' \ + ''.format(instrument_name, now.year, now.month, now.day, + now.hour, now.minute) + generate_1bank_2d_idf(instrument_name, geom_setup_dict, pixel_setup, output_idf_name) + generate_2d_configure(instrument_name, geom_setup_dict, pixel_setup, output_config_name) + + return + + +if __name__ == '__main__': + main(sys.argv) diff --git a/hb3a_geometry.py b/hb3a_geometry.py new file mode 100644 index 0000000..ceb1dc9 --- /dev/null +++ b/hb3a_geometry.py @@ -0,0 +1,328 @@ +import sys +import datetime +import helper + +# Definition of constants +HB3A_L1 = 2. + +# TODO - Need to separate FourCircle_256_SETUP and FourCircle_512_SETUP +# TODO - Unify the dictioanry layout! +FourCircle_256_SETUP = {'L1': 2.0, + 'L2': 0.3750, # arm length + 'PixelNumber': {1: (256, 256)}, # bank: (row, col) + 'PixelSize': {1: 0.0001984375}, # bank: pixel size + 'Panel Center': {1: (0, 0)} + } + +FourCircle_512_SETUP = {'L1': 2.0, + 'L2': 0.3750, # arm length + 'PixelNumber': {1: (512, 512)}, # bank: (row, col) + 'PixelSize': {1: 0.0002265625}, + 'Panel Center': {1: (0, 0)} + } + +ZEBRA_SETUP = {'L1': 2.0, + 'L2': 0.3750, # arm length + 'PixelNumber': {1: (256, 256)}, + 'PixelSize': {1: 0.01234567}} + +Y = 0.120 # distance between two panels = 512 * 0.0002265625 = 0.116 +DEMAND_SETUP = {'L1': 2.0, + 'L2': 0.3750, + 'Panel Center': {1: (0, -Y), 2: (0, 0), 3: (0, Y)}, + 'PixelNumber': {1: (512, 512), 2: (512, 512), 3: (512, 512)}, + 'PixelSize': {1: 0.0002265625, 2: 0.0002265625, 3: 0.0002265625} + } + + +class DemandGeometry(helper.MantidGeom): + """ + HB3A geometry extended from MantidGeom + """ + def __init__(self, instname, comment=None, valid_from=None, valid_to=None): + """ + initialization + :param instname: name of instrument + :param comment: comment + :param valid_from: beginning date + :param valid_to: end date + """ + super(DemandGeometry, self).__init__(instname, comment, valid_from, valid_to) + + return + + def add_panel(self, bank_id, geom_setup_dict, cal_shift_x, cal_shift_y, cal_shift_z, + cal_rotx, cal_roty, cal_rotz, component_use_bank_id, start_pixel_id=1): + """ Add 1 2D detector panel + Code is somehow shared with hb2b_geometry.generate_1bank_2d_idf + For Mantid IDF, the logic of applying shift to a detector is from bottom to top as + - shift X and Y + - shift Z, rotX, rotY, rotZ + - shift 2theta + In the same level, rotation shift is applied in a higher priority than linear shift + Args: + bank_id: + geom_setup_dict: dictionary for geometry parameters such as L2, panel center position (Y) + cal_shift_x: String, name of calibration shift along X-axis + cal_shift_y: String, name of calibration shift along Y-axis + cal_shift_z: String + log name of calibration shift along Z-axis + cal_rotx: Log name of shift of rotation along X axis + cal_roty: Log name of shift of rotation along Y axis + cal_rotz: Log name of shift of rotation along Z axis + component_use_bank_id: boolean + If true, then all the component name containing bank number + start_pixel_id: integer + starting pixel ID + + Returns: + Integer + number of pixels in this panel + """ + # Define arm component - component with roty as 2theta + pixel_row_count, pixel_column_count = geom_setup_dict['PixelNumber'][bank_id] + arm_loc_dict = dict() + arm_loc_dict['r-position'] = {'value': 0.0} + arm_loc_dict['t-position'] = {'value': 0.0} + arm_loc_dict['p-position'] = {'value': 0.0} + arm_loc_dict['roty'] = {'logfile': 'value+0.0', 'id': '2theta'} # roty works as 2theta with experiment + + # generate arm node name + arm_node_name = 'arm' + if component_use_bank_id: + arm_node_name += '{}'.format(bank_id) + + arm_node = self.add_component(type_name=arm_node_name, idfillbyfirst=None, idstart=None, + idstepbyrow=None) + self.add_location('bank{}'.format(bank_id), arm_node, arm_loc_dict) + + # Define arm node type: arm + arm_type_node = self.add_component_type(type_name=arm_node_name) + + # Define component panel installed on the arm + # rotation along x-, y- and z- axis and shift along arm will be defined from log + arm_loc_dict = {'z': {'logfile': 'value+{}'.format(geom_setup_dict['L2']), 'id': cal_shift_z}, + 'rotx': {'logfile': 'value+0.0', 'id': cal_rotx}, + 'roty': {'logfile': 'value+0.0', 'id': cal_roty}, + 'rotz': {'logfile': 'value+0.0', 'id': cal_rotz}, + } + # Add component-panel to arm-type-node + # generate name for panel + panel_node_name = 'panel' + if component_use_bank_id: + panel_node_name += '{}'.format(bank_id) + # add panel as a component + panel_node = self.add_component(type_name=panel_node_name, idfillbyfirst=None, idstart=None, + idstepbyrow=None, root=arm_type_node) + # Add location to panel node + self.add_location(None, panel_node, arm_loc_dict) + + # Add another layer: shift-panel on to panel for shift in X- and Y- direction + center_y = geom_setup_dict['Panel Center'][bank_id][1] + panel_loc_dict = {'x': {'logfile': 'value', 'id': cal_shift_x}, + 'y': {'logfile': '{}+value'.format(center_y), 'id': cal_shift_y}} + # add panel as component type + panel_type_node = self.add_component_type(panel_node_name) + + # Add component shift_panel + shift_panel_node = self.add_component(type_name='shiftpanel', idfillbyfirst='x', idstart=start_pixel_id, + idstepbyrow=pixel_column_count, root=panel_type_node) + self.add_location(None, shift_panel_node, panel_loc_dict) + + return pixel_row_count * pixel_column_count + +# END-DEF-HB3A + + +def generate_1_panel_idf(is_zebra, idf_name, config_name, linear_pixel_size): + """ Generate the 1 panel (256 X 256) IDF valid to October 2018 + :param is_zebra: + :param idf_name: + :param config_name: + :param linear_pixel_size: + :return: + """ + if is_zebra: + instrument_name = 'ZEBRA' + geom_setup_dict = ZEBRA_SETUP + else: + instrument_name = 'HB3A' + if linear_pixel_size == 256: + geom_setup_dict = FourCircle_256_SETUP + elif linear_pixel_size == 512: + geom_setup_dict = FourCircle_512_SETUP + else: + raise RuntimeError('HB3A-1-Panel with {0} x {0} does not exist'.format(linear_pixel_size)) + + # generate instrument geometry object + authors = ["Wenduo Zhou"] + begin_date = '2018-12-01 00:00:01' + end_date = '2100-10-20 23:59:59' + + # boiler plate stuff + scx_instrument = DemandGeometry(instrument_name, + comment="Created by " + ", ".join(authors), + valid_from=begin_date, + valid_to=end_date) + + # source + scx_instrument.addComment("SOURCE") + scx_instrument.addModerator(geom_setup_dict['L1']) + # sample + scx_instrument.addComment("SAMPLE") + scx_instrument.addSamplePosition() + + # Build 'arm'/panel/shiftpanel + scx_instrument.addComment("PANEL") + scx_instrument.add_panel(bank_id=1, geom_setup_dict=geom_setup_dict, + cal_shift_x='cal::diffx', cal_shift_y='cal::diffy', + cal_shift_z='cal::diffz', cal_rotx='cal::rotx', + cal_roty='cal::roty', cal_rotz='cal::rotz', + component_use_bank_id=False, start_pixel_id=1) + + # Generate rectangular detector based on 'shiftpanel' + # TODO - refactor this to a method (not ASAP) + pixel_size_x = pixel_size_y = geom_setup_dict['PixelSize'][1] + pixel_row_count, pixel_column_count = geom_setup_dict['PixelNumber'][1] + x_start = (float(pixel_column_count)*0.5 - 0.5) * pixel_size_x + x_step = - pixel_size_x + y_start = -(float(pixel_row_count)*0.5 - 0.5) * pixel_size_y + y_step = pixel_size_y + scx_instrument.add_rectangular_detector(x_start=x_start, x_step=x_step, x_pixels=pixel_column_count, + y_start=y_start, y_step=y_step, y_pixels=pixel_row_count, + pixel_size_x=pixel_size_x, pixel_size_y=pixel_size_y, + pixel_size_z=0.0001) # pixel size Z is not concerned + + scx_instrument.write_terminal() + scx_instrument.writeGeom(idf_name) + + return + + +def generate_3_panel_idf(out_file_name): + """ + generate 3 panel (3 x 4 x 256 x 256) instrument definition for 2018 October + upgrade + :return: + """ + # generate instrument geometry object + instrument_name = 'HB3A' + authors = ["Wenduo Zhou"] + begin_date = '2018-10-20 23:59:59' + end_date = '3018-10-20 23:59:59' + + # boiler plate stuff + hb3a = DemandGeometry(instrument_name, + comment="Created by " + ", ".join(authors), + valid_from=begin_date, + valid_to=end_date) + + # source + hb3a.addComment("SOURCE") + hb3a.addModerator(HB3A_L1) + # sample + hb3a.addComment("SAMPLE") + hb3a.addSamplePosition() + # monitor: No monitor + # hb3a.addComment("MONITORS") + # hb3a.add_monitor_type() + # self._vulcan.addMonitors(distance=[-1.5077], names=["monitor1"]) + + # Build 'arm'/panel/shiftpanel + # TODO FIXME - shall be: 1 arm, 3 panel + hb3a.addComment("PANEL Lower") + bank1_num_pixels = hb3a.add_panel(bank_id=1, geom_setup_dict=DEMAND_SETUP, + cal_shift_x='cal::diffx1', cal_shift_y='cal::diffy1', + cal_shift_z='cal::diffz1', cal_rotx='cal::rotx1', + cal_roty='cal::roty1', cal_rotz='cal::rotz1', + component_use_bank_id=True, start_pixel_id=1) + + hb3a.addComment("PANEL Middle") + bank2_num_pixels = hb3a.add_panel(bank_id=2, geom_setup_dict=DEMAND_SETUP, + cal_shift_x='cal::diffx2', cal_shift_y='cal::diffy2', + cal_shift_z='cal::diffz2', cal_rotx='cal::rotx2', + cal_roty='cal::roty2', cal_rotz='cal::rotz2', + component_use_bank_id=True, start_pixel_id=1+bank1_num_pixels) + + hb3a.addComment("PANEL Upper") + hb3a.add_panel(bank_id=3, geom_setup_dict=DEMAND_SETUP, + cal_shift_x='cal::diffx3', cal_shift_y='cal::diffy3', + cal_shift_z='cal::diffz3', cal_rotx='cal::rotx3', + cal_roty='cal::roty3', cal_rotz='cal::rotz3', + component_use_bank_id=True, start_pixel_id=1 + bank1_num_pixels + bank2_num_pixels) + + # Generate rectangular detector based on 'shiftpanel' + # TODO - refactor this to a method (not ASAP) + pixel_size_x = pixel_size_y = DEMAND_SETUP['PixelSize'][1] + pixel_row_count, pixel_column_count = DEMAND_SETUP['PixelNumber'][1] + x_start = (float(pixel_column_count)*0.5 - 0.5) * pixel_size_x + x_step = - pixel_size_x + y_start = -(float(pixel_row_count)*0.5 - 0.5) * pixel_size_y + y_step = pixel_size_y + hb3a.add_rectangular_detector(x_start=x_start, x_step=x_step, x_pixels=pixel_column_count, + y_start=y_start, y_step=y_step, y_pixels=pixel_row_count, + pixel_size_x=pixel_size_x, pixel_size_y=pixel_size_y, + pixel_size_z=0.0001) # pixel size Z is not concerned + + # Write out HB3A + hb3a.write_terminal() + hb3a.writeGeom(out_file_name) + + return + + +def main(argv): + """ Main + :param argv: + :return: + """ + if len(argv) < 2: + print ('Generate HB3A IDF: {} [number of panel [1, 3, zebra] [pixel size (default)]'.format(argv[0])) + sys.exit(0) + else: + is_zebra = argv[1].lower() == 'zebra' + if is_zebra: + instrument_name = 'ZEBRA' + else: + instrument_name = 'HB3A' + + # about output file + now = datetime.datetime.now() + output_idf_name = '{}_Definition_{:04}{:02}{:02}_{:02}{:02}.xml' \ + ''.format(instrument_name, now.year, now.month, now.day, + now.hour, now.minute) + instrument_config_name = '{}_Definition_{:04}{:02}{:02}_{:02}{:02}.txt' \ + ''.format(instrument_name, now.year, now.month, now.day, now.hour, now.minute) + + if is_zebra: + generate_1_panel_idf(is_zebra, output_idf_name, instrument_config_name, None) + else: + num_panel = int(argv[1]) + + if num_panel == 1: + # 1 panel case: need to find out if it is 256 x 256 + if len(argv) == 3: + linear_pixel_number = int(argv[2]) + if linear_pixel_number not in [256, 512]: + print ('[ERROR] HB3A 1-panel only supports 256(x256) and 512(x512) but not {}(x{})' + ''.format(linear_pixel_number, linear_pixel_number)) + + generate_1_panel_idf(is_zebra, output_idf_name, instrument_config_name, linear_pixel_number) + elif num_panel == 3: + # 3 panels: DEMAND + generate_3_panel_idf(output_idf_name) + else: + # Non-support + print ('Panel configuration {} is not supported'.format(argv[1])) + sys.exit(-1) + # END-IF-ELSE + + print ('[REPORT] {} and {} are generated for {}'.format(output_idf_name, instrument_config_name, instrument_name)) + + return + + +if __name__ == '__main__': + main(sys.argv) + + diff --git a/helper.py b/helper.py index 7ff426f..32383e6 100644 --- a/helper.py +++ b/helper.py @@ -11,7 +11,8 @@ XSI = "http://www.w3.org/2001/XMLSchema-instance" SCHEMA_LOC = "http://www.mantidproject.org/IDF/1.0 http://schema.mantidproject.org/IDF/1.0/IDFSchema.xsd" -class MantidGeom: + +class MantidGeom(object): def __init__(self, instname, comment=None, valid_from=None, valid_to=None): from datetime import datetime @@ -36,6 +37,15 @@ def __init__(self, instname, comment=None, valid_from=None, valid_to=None): else: self.__root.append(le.Comment(comment)) + def write_terminal(self): + """ + write the current content to terminal + :return: + """ + print (le.tostring(self.__root, pretty_print=True, xml_declaration=True)) + + return + def writeGeom(self, filename): """ Write the XML geometry to the given filename @@ -246,15 +256,138 @@ def addComponent(self, type_name, idlist=None, root=None, blank_location=True): root = self.__root if idlist is not None: - comp = le.SubElement(root, "component", type=type_name, - idlist=idlist) + comp = le.SubElement(root, "component", type=type_name, idlist=idlist) else: comp = le.SubElement(root, "component", type=type_name) + l=comp if blank_location: l = le.SubElement(comp, "location") return l + def add_component(self, type_name, idfillbyfirst, idstart, idstepbyrow, root=None): + """ add an component + :param type_name: + :param idfillbyfirst: + :param idstart: + :param idstepbyrow: + :param root: + :return: + """ + if root is None: + root = self.__root + + if idfillbyfirst is None: + comp = le.SubElement(root, 'component', type=type_name) + else: + comp = le.SubElement(root, 'component', type=type_name, + idfillbyfirst='{}'.format(idfillbyfirst), + idstart='{}'.format(idstart), + idstepbyrow='{}'.format(idstepbyrow)) + + return comp + + def add_location(self, location_name, node, location_param_dict): + """ add location to a component + :param location_name: + :param node: node where location is belonged to + :param location_param_dict: dictionary for position parameters including parameters + :return: + """ + arg_dict = dict() + if location_name is None: + pass + # location_node = le.SubElement(node, 'location') + else: + arg_dict['name'] = location_name + # location_node = le.SubElement(node, 'location', name=location_name) + + # Create location node with "location name" as an option + location_node = le.SubElement(node, 'location', **arg_dict) + + for param_name in sorted(location_param_dict.keys()): + if 'value' in location_param_dict[param_name]: + # write location parameter value directly + param_value = location_param_dict[param_name]['value'] + self.add_parameter(param_name, param_value, location_node) + elif 'logfile' in location_param_dict[param_name]: + # write location parameter with value associated with log in workspace's run object: logfile + log_equation = location_param_dict[param_name]['logfile'] + log_name = location_param_dict[param_name]['id'] + self.add_log_file(param_name, log_equation, log_name, location_node) + else: + raise RuntimeError('Either value or logfile must be in location parameter dict') + # END-IF-ELSE + # END-FOR + + return location_node + + def add_parameter(self, par_name, par_value, node): + + param_node = le.SubElement(node, 'parameter', name=par_name) + le.SubElement(param_node, 'value', val='{}'.format(par_value)) + + return param_node + + def add_log_file(self, par_name, log_equation, log_id, root_node): + + log_file_node = le.SubElement(root_node, 'parameter', name=par_name) + le.SubElement(log_file_node, 'logfile', eq=log_equation, id=log_id) + + return log_file_node + + def add_component_type(self, type_name): + """ Add panel + """ + # TODO - TONIGHT 0 - Merge with add_type + type_node = self.add_type({'name': type_name}) + + return type_node + + def add_rectangular_detector(self, x_start, x_step, x_pixels, + y_start, y_step, y_pixels, + pixel_size_x, pixel_size_y, pixel_size_z, + panel_name='shiftpanel'): + """ + Add an angular detector in rectangular shape + :param x_start: + :param x_step: + :param x_pixels: + :param y_start: + :param y_step: + :param y_pixels: + :param pixel_size_x: + :param pixel_size_y: + :param pixel_size_z: + :param panel_name: name in the XML for panel + :return: + """ + # add detector panel + self.addRectangularDetector(name=panel_name, type='pixel', + xstart='{}'.format(x_start), xstep='{}'.format(x_step), + xpixels='{}'.format(x_pixels), + ystart='{}'.format(y_start), ystep='{}'.format(y_step), + ypixels='{}'.format(y_pixels)) + + # add pixels + self.addCuboidPixel(name='pixel', shape_id='pixel-shape', + lfb_pt=(pixel_size_x*0.5, -pixel_size_y*0.5, 0), # left-front-bottom + lft_pt=(pixel_size_x*0.5, pixel_size_y*0.5, 0), # left-front-top + lbb_pt=(pixel_size_x*0.5, -pixel_size_y*0.5, -pixel_size_z), # left-back-bottom + rfb_pt=(-pixel_size_x*0.5, -pixel_size_y*0.5, 0) # right-front-bottom + ) + + return + + def add_type(self, type_info_dict, root_node=None): + + if root_node is None: + root_node = self.__root + + type_node = le.SubElement(root_node, 'type', name=type_info_dict['name']) + + return type_node + def addComponentILL(self, type_name, x, y, z, isType=None, root=None): """ Add a component with location to the XML definition.