diff --git a/hb2b_geometry.py b/hb2b_geometry.py new file mode 100644 index 0000000..5e35392 --- /dev/null +++ b/hb2b_geometry.py @@ -0,0 +1,166 @@ +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} + } + +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 HB2BGeometry(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(HB2BGeometry, 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 = HB2BGeometry(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() + + # arm - component + pixel_row_count, pixel_column_count = geom_setup_dict['PixelNumber'][pixel_setup] + arm_loc_dict = {'r-position': {'value': 0.0}, + 't-position': {'logfile': 'value+0.0', 'id': 'cal::2theta'}, + 'p-position': {'value': 0.0}, + 'roty': {'logfile': 'value+0.0', 'id': 'cal::roty'}} + + 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) + hb2b.add_parameter('r-position', 0.0, arm_loc_node) + + # generate rectangular detector + 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.addRectangularDetector(name='panel', type='pixel', + xstart='{}'.format(x_start), xstep='{}'.format(x_step), + xpixels='{}'.format(pixel_column_count), + ystart='{}'.format(y_start), ystep='{}'.format(y_step), + ypixels='{}'.format(pixel_row_count)) + + hb2b.write_terminal() + + return + + # add detectors + hb2b.addComment('Define detector banks') + hb2b.addComponent(type_name='detectors', idlist='detectors') + # define detector type + hb2b.add_banks_type(name='detectors', + components=['bank1']) + + # define center bank + hb2b.addComment('Define Centre Bank') + hb2b.add_bank(name='bank1', component_name='square256detector', + x=2.0, y=0., z=0., rot=90) + + # 20 x 8 packs + hb2b.addComment('256 x 256 pack') + hb2b.angler_detector(name='square256detector', num_linear_pixel=256, tube_x=0.01) + + # write file + hb2b.writeGeom(output_idf_name) + + return + + +def main(argv): + """ Main + :param argv: + :return: + """ + if len(argv) < 3: + print ('Generate HB2B IDF: {} [hb2b [xray]] [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' + 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) + generate_1bank_2d_idf(instrument_name, geom_setup_dict, pixel_setup, output_idf_name) + + return + + +if __name__ == '__main__': + main(sys.argv) diff --git a/helper.py b/helper.py index 7ff426f..c137707 100644 --- a/helper.py +++ b/helper.py @@ -11,7 +11,7 @@ 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 +36,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 +255,95 @@ 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 + + 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 an location + :param location_name: + :param node + :return: + """ + location_node = le.SubElement(node, 'location', name=location_name) + + for param_name in location_param_dict: + if 'value' in location_param_dict[param_name]: + # write parameter value + 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 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 addComponentILL(self, type_name, x, y, z, isType=None, root=None): """ Add a component with location to the XML definition.