From a8e672162a88313a5477254a4f891d31a1606d1b Mon Sep 17 00:00:00 2001 From: Valerio Mariani <valerio.mariani@desy.de> Date: Tue, 16 May 2017 17:16:18 +0200 Subject: [PATCH] Fixed bugs int the cfel_crystfel module --- cfel_crystfel.py | 536 ++++++++++++++++++++++++----------------------- 1 file changed, 273 insertions(+), 263 deletions(-) diff --git a/cfel_crystfel.py b/cfel_crystfel.py index d258807..911b63c 100644 --- a/cfel_crystfel.py +++ b/cfel_crystfel.py @@ -28,305 +28,307 @@ from math import inf, sqrt import re -def load_crystfel_geometry(filename): - - def assplode_algebraic(v): - items = [item for item in re.split('([+-])', v.strip()) if item != ''] - - if len(items) != 0 and items[0] not in ('+', '-'): - items.insert(0, '+') - - return [''.join((items[x], items[x + 1])) for x in range(0, len(items), 2)] - - def dir_conv(direction_x, direction_y, direction_z): - - direction = [direction_x, direction_y, direction_z] +def _assplode_algebraic(value): + items = [item for item in re.split('([+-])', value.strip()) if item != ''] - items = assplode_algebraic(value) + if len(items) != 0 and items[0] not in ('+', '-'): + items.insert(0, '+') - if len(items) == 0: - raise RuntimeError('Invalid direction: {}.'.format(value)) + return [''.join((items[x], items[x + 1])) for x in range(0, len(items), 2)] - for item in items: - axis = item[-1] - if axis != 'x' and axis != 'y' and axis != 'z': - raise RuntimeError('Invalid Symbol: {} (must be x, y or z).'.format(axis)) +def _dir_conv(direction_x, direction_y, direction_z, value): + direction = [direction_x, direction_y, direction_z] - if item[:-1] == '+': - v = '1.0' - elif item[:-1] == '-': - v = '-1.0' - else: - v = item[-1] - - if axis == 'x': - direction[0] = float(v) - elif axis == 'y': - direction[1] = float(v) - elif axis == 'z': - direction[2] = float(v) - - return direction + items = _assplode_algebraic(value) - def set_dim_structure_entry(k, v, pan): + if len(items) == 0: + raise RuntimeError('Invalid direction: {}.'.format(value)) - if pan['dim_structure'] is not None: - dim = pan['dim_structure'] - else: - dim = [] - - dim_index = int(k[3]) + for item in items: + axis = item[-1] - if dim_index > len(dim)-1: - for index in range(len(dim), dim_index + 1): - dim.append(None) + if axis != 'x' and axis != 'y' and axis != 'z': + raise RuntimeError('Invalid Symbol: {} (must be x, y or z).'.format(axis)) - if v == 'ss' or v == 'fs' or v == '%': - dim[dim_index] = v - elif v.isdigit(): - dim[dim_index] = int(v) + if item[:-1] == '+': + v = '1.0' + elif item[:-1] == '-': + v = '-1.0' else: - raise RuntimeError('Invalid dim entry: {}.'.format(v)) - - def parse_field_for_panel(k, v, pan): - - if k == 'min_fs': - pan['origin_min_fs'] = int(v) - pan['min_fs'] = int(v) - - elif k == 'max_fs': - pan['origin_max_fs'] = int(v) - pan['max_fs'] = int(v) - - elif k == 'min_ss': - pan['origin_min_ss'] = int(v) - pan['min_ss'] = int(v) - - elif k == 'max_ss': - pan['origin_max_ss'] = int(v) - pan['max_ss'] = int(v) - - elif k == 'corner_x': - pan['cnx'] = float(v) - - elif k == 'corner_y': - pan['cny'] = float(v) - - elif k == 'rail_direction': - try: - pan['rail_x'], pan['rail_y'], pan['rail_z'] = dir_conv(pan['rail_x'], - pan['rail_y'], - pan['rail_z']) - except RuntimeError as e: - raise RuntimeError('Invalid rail direction. ', e) - - elif k == 'clen_for_centering': - pan['clen_for_centering'] = float(v) - - elif k == 'adu_per_eV': - pan['adu_per_eV'] = float(v) - - elif k == 'adu_per_photon': - pan['adu_per_photon'] = float(v) - - elif k == 'rigid_group': - pan['rigid_group'] = v - - elif k == 'clen': - try: - pan['clen'] = float(v) - pan['clen_from'] = None - except ValueError: - pan['clen'] = -1 - pan['clen_from'] = v - - elif k == 'data': - if not v.startswith('/'): - raise RuntimeError('Invalid data location: {}'.format(v)) - pan['data'] = v - - elif k == 'mask': - if not v.startswith('/'): - raise RuntimeError('Invalid data location: {}'.format(v)) - pan['mask'] = v - - elif k == 'mask_file': - pan['mask_file'] = v - - elif k == 'saturation_map': - pan['saturation_map'] = v - - elif k == 'saturation_map_file': - pan['saturation_map_file'] = v - - elif k == 'coffset': - pan['coffset'] = float(v) - - elif k == 'res': - pan['res'] = float(v) - - elif k == 'max_adu': - pan['max_adu'] = v - - elif k == 'badrow_direction': - if v == 'x': - pan['badrow'] = 'f' - elif v == 'y': - pan['badrow'] = 's' - elif v == 'f': - pan['badrow'] = 'f' - elif v == 's': - pan['badrow'] = 's' - elif v == '-': - pan['badrow'] = '-' - else: - print('badrow_direction must be x, t, f, s, or \'-\'') - print('Assuming \'-\'.') - pan['badrow'] = '-' + v = item[-1] - elif k == 'no_index': - pan['no_index'] = bool(v) + if axis == 'x': + direction[0] = float(v) + elif axis == 'y': + direction[1] = float(v) + elif axis == 'z': + direction[2] = float(v) - elif k == 'fs': - try: - pan['fsx'], pan['fsy'], pan['fsz'] = dir_conv(pan['fsx'], pan['fsy'], - pan['fsz']) + return direction - except RuntimeError as e: - raise RuntimeError('Invalid fast scan direction. ', e) - elif k == 'ss': - try: - pan['ssx'], pan['ssy'], pan['ssz'] = dir_conv(pan['ssx'], pan['ssy'], - pan['ssz']) +def _set_dim_structure_entry(key, value, panel): + if panel['dim_structure'] is not None: + dim = panel['dim_structure'] + else: + dim = [] - except RuntimeError as e: - raise RuntimeError('Invalid slow scan direction. ', e) - - elif k.startswith('dim'): - set_dim_structure_entry(k, v, pan) + dim_index = int(key[3]) + + if dim_index > len(dim) - 1: + for index in range(len(dim), dim_index + 1): + dim.append(None) + + if value == 'ss' or value == 'fs' or value == '%': + dim[dim_index] = value + elif value.isdigit(): + dim[dim_index] = int(value) + else: + raise RuntimeError('Invalid dim entry: {}.'.format(value)) + + +def _parse_field_for_panel(key, value, panel): + if key == 'min_fs': + panel['origin_min_fs'] = int(value) + panel['min_fs'] = int(value) + + elif key == 'max_fs': + panel['origin_max_fs'] = int(value) + panel['max_fs'] = int(value) + + elif key == 'min_ss': + panel['origin_min_ss'] = int(value) + panel['min_ss'] = int(value) + + elif key == 'max_ss': + panel['origin_max_ss'] = int(value) + panel['max_ss'] = int(value) + + elif key == 'corner_x': + panel['cnx'] = float(value) + + elif key == 'corner_y': + panel['cny'] = float(value) + + elif key == 'rail_direction': + try: + panel['rail_x'], panel['rail_y'], panel['rail_z'] = _dir_conv(panel['rail_x'], + panel['rail_y'], + panel['rail_z'], + value) + except RuntimeError as e: + raise RuntimeError('Invalid rail direction. ', e) + + elif key == 'clen_for_centering': + panel['clen_for_centering'] = float(value) + + elif key == 'adu_per_eV': + panel['adu_per_eV'] = float(value) + + elif key == 'adu_per_photon': + panel['adu_per_photon'] = float(value) + + elif key == 'rigid_group': + panel['rigid_group'] = value + + elif key == 'clen': + try: + panel['clen'] = float(value) + panel['clen_from'] = None + except ValueError: + panel['clen'] = -1 + panel['clen_from'] = value + + elif key == 'data': + if not value.startswith('/'): + raise RuntimeError('Invalid data location: {}'.format(value)) + panel['data'] = value + + elif key == 'mask': + if not value.startswith('/'): + raise RuntimeError('Invalid data location: {}'.format(value)) + panel['mask'] = value + + elif key == 'mask_file': + panel['mask_file'] = value + + elif key == 'saturation_map': + panel['saturation_map'] = value + + elif key == 'saturation_map_file': + panel['saturation_map_file'] = value + + elif key == 'coffset': + panel['coffset'] = float(value) + + elif key == 'res': + panel['res'] = float(value) + elif key == 'max_adu': + panel['max_adu'] = value + + elif key == 'badrow_direction': + if value == 'x': + panel['badrow'] = 'f' + elif value == 'y': + panel['badrow'] = 's' + elif value == 'f': + panel['badrow'] = 'f' + elif value == 's': + panel['badrow'] = 's' + elif value == '-': + panel['badrow'] = '-' else: - raise RuntimeError('Unrecognised field: {}'.format(k)) - - def parse_top_level(k, v, det, b, pan): - - if k == 'mask_bad': - try: - det['mask_bad'] = int(v) - except ValueError: - det['mask_bad'] = int(v, 16) + print('badrow_direction must be x, t, f, s, or \'-\'') + print('Assuming \'-\'.') + panel['badrow'] = '-' - elif k == 'mask_good': - try: - det['mask_good'] = int(v) - except ValueError: - det['mask_good'] = int(v, 16) + elif key == 'no_index': + panel['no_index'] = bool(value) - elif k == 'coffset': - pan['coffset'] = float(v) + elif key == 'fs': + try: + panel['fsx'], panel['fsy'], panel['fsz'] = _dir_conv(panel['fsx'], panel['fsy'], + panel['fsz'], value) - elif k == 'photon_energy': - if v.startswith('/'): - b['photon_energy'] = 0.0 - b['photon_energy_from'] = v - else: - b['photon_energy'] = float(v) - b['photon_energy_from'] = None - - elif k == 'photon_energy_scale': - b['photon_energy_scale'] = float(v) + except RuntimeError as e: + raise RuntimeError('Invalid fast scan direction. ', e) - elif k == 'peak_info_location': - det['peak_info_location'] = v + elif key == 'ss': + try: + panel['ssx'], panel['ssy'], panel['ssz'] = _dir_conv(panel['ssx'], panel['ssy'], + panel['ssz'], value) - elif k.startswith('rigid_group') and not k.startswith('rigid_group_collection'): - det['rigid_groups'][k[12:]] = v.split(',') + except RuntimeError as e: + raise RuntimeError('Invalid slow scan direction. ', e) - elif k.startswith('rigid_group_collection'): - det['rigid_group_collections'][k[23:]] = v.split(',') + elif key.startswith('dim'): + _set_dim_structure_entry(key, value, panel) - else: - parse_field_for_panel(k, v, pan) + else: + raise RuntimeError('Unrecognised field: {}'.format(key)) - def check_bad_fsss(bad, is_fsss): - if bad['is_fsss'] == 99: - bad['is_fsss'] = is_fsss - return +def _parse_top_level(key, value, detector, beam, panel): + if key == 'mask_bad': + try: + detector['mask_bad'] = int(value) + except ValueError: + detector['mask_bad'] = int(value, 16) - if is_fsss != bad['is_fsss']: - raise RuntimeError("You can't mix x/y and fs/ss in a bad region") + elif key == 'mask_good': + try: + detector['mask_good'] = int(value) + except ValueError: + detector['mask_good'] = int(value, 16) - return + elif key == 'coffset': + panel['coffset'] = float(value) - def parse_field_bad(k, v, bad): - - if k == 'min_x': - bad['min_x'] = float(v) - check_bad_fsss(bad, False) - elif k == 'max_x': - bad['max_x'] = float(v) - check_bad_fsss(bad, False) - elif k == 'min_y': - bad['min_y'] = float(v) - check_bad_fsss(bad, False) - elif k == 'max_y': - bad['max_y'] = float(v) - check_bad_fsss(bad, False) - elif k == 'min_fs': - bad['min_fs'] = int(v) - check_bad_fsss(bad, True) - elif k == 'max_fs': - bad['max_fs'] = int(v) - check_bad_fsss(bad, True) - elif k == 'min_ss': - bad['min_ss'] = int(v) - check_bad_fsss(bad, True) - elif k == 'max_ss': - bad['max_ss'] = int(v) - check_bad_fsss(bad, True) - elif k == 'panel': - bad['panel'] = v + elif key == 'photon_energy': + if value.startswith('/'): + beam['photon_energy'] = 0.0 + beam['photon_energy_from'] = value else: - raise RuntimeError('Unrecognised field: {}'.format(k)) + beam['photon_energy'] = float(value) + beam['photon_energy_from'] = None - return + elif key == 'photon_energy_scale': + beam['photon_energy_scale'] = float(value) - def check_point(n, pan, fs, ss, min_d, max_d, det): + elif key == 'peak_info_location': + detector['peak_info_location'] = value - xs = fs * pan['fsx'] + ss * pan['ssx'] - ys = fs * pan['fsy'] + ss * pan['ssy'] + elif key.startswith('rigid_group') and not key.startswith('rigid_group_collection'): + detector['rigid_groups'][key[12:]] = value.split(',') - rx = (xs + pan['cnx']) / pan['res'] - ry = (ys + pan['cny']) / pan['res'] + elif key.startswith('rigid_group_collection'): + detector['rigid_group_collections'][key[23:]] = value.split(',') - dist = sqrt(rx * rx + ry * ry) + else: + _parse_field_for_panel(key, value, panel) - if dist > max_d: - det['furthest_out_panel'] = n - det['furthest_out_fs'] = fs - det['furthest_out_ss'] = ss - max_d = dist - elif dist < min_d: - det['furthest_in_panel'] = n - det['furthest_in_fs'] = fs - det['furthest_in_ss'] = ss - min_d = dist - return min_d, max_d +def _check_bad_fsss(bad_region, is_fsss): + if bad_region['is_fsss'] == 99: + bad_region['is_fsss'] = is_fsss + return - def find_min_max_d(det): + if is_fsss != bad_region['is_fsss']: + raise RuntimeError("You can't mix x/y and fs/ss in a bad region") + + return + + +def _parse_field_bad(key, value, bad): + if key == 'min_x': + bad['min_x'] = float(value) + _check_bad_fsss(bad, False) + elif key == 'max_x': + bad['max_x'] = float(value) + _check_bad_fsss(bad, False) + elif key == 'min_y': + bad['min_y'] = float(value) + _check_bad_fsss(bad, False) + elif key == 'max_y': + bad['max_y'] = float(value) + _check_bad_fsss(bad, False) + elif key == 'min_fs': + bad['min_fs'] = int(value) + _check_bad_fsss(bad, True) + elif key == 'max_fs': + bad['max_fs'] = int(value) + _check_bad_fsss(bad, True) + elif key == 'min_ss': + bad['min_ss'] = int(value) + _check_bad_fsss(bad, True) + elif key == 'max_ss': + bad['max_ss'] = int(value) + _check_bad_fsss(bad, True) + elif key == 'panel': + bad['panel'] = value + else: + raise RuntimeError('Unrecognised field: {}'.format(key)) + + return + + +def _check_point(name, panel, fs, ss, min_d, max_d, detector): + xs = fs * panel['fsx'] + ss * panel['ssx'] + ys = fs * panel['fsy'] + ss * panel['ssy'] + + rx = (xs + panel['cnx']) / panel['res'] + ry = (ys + panel['cny']) / panel['res'] + + dist = sqrt(rx * rx + ry * ry) + + if dist > max_d: + detector['furthest_out_panel'] = name + detector['furthest_out_fs'] = fs + detector['furthest_out_ss'] = ss + max_d = dist + elif dist < min_d: + detector['furthest_in_panel'] = name + detector['furthest_in_fs'] = fs + detector['furthest_in_ss'] = ss + min_d = dist + + return min_d, max_d + + +def _find_min_max_d(detector): + min_d = inf + max_d = 0.0 + + for name, panel in detector['panels'].items(): + min_d, max_d = _check_point(name, panel, 0, 0, min_d, max_d, detector) + min_d, max_d = _check_point(name, panel, panel['w'], 0, min_d, max_d, detector) + min_d, max_d = _check_point(name, panel, 0, panel['h'], min_d, max_d, detector) + min_d, max_d = _check_point(name, panel, panel['w'], panel['h'], min_d, max_d, detector) - min_d = inf - max_d = 0.0 - for n, pan in det['panels'].items(): - min_d, max_d = check_point(n, pan, 0, 0, min_d, max_d, det) - min_d, max_d = check_point(n, pan, pan['w'], 0, min_d, max_d, det) - min_d, max_d = check_point(n, pan, 0, pan['h'], min_d, max_d, det) - min_d, max_d = check_point(n, pan, pan['w'], pan['h'], min_d, max_d, det) +def load_crystfel_geometry(filename): fh = open(filename, 'r') @@ -413,7 +415,7 @@ def load_crystfel_geometry(filename): path = [item for item in path if item not in '/'] if len(path) < 2: - parse_top_level(line_items[0], value, detector, beam, default_panel) + _parse_top_level(line_items[0], value, detector, beam, default_panel) continue curr_bad = None @@ -436,9 +438,9 @@ def load_crystfel_geometry(filename): detector['panels'][path[0]] = curr_panel if curr_panel is not None: - parse_field_for_panel(path[1], value, curr_panel) + _parse_field_for_panel(path[1], value, curr_panel) else: - parse_field_bad(path[1], value, curr_bad) + _parse_field_bad(path[1], value, curr_bad) if len(detector['panels']) == 0: raise RuntimeError("No panel descriptions in geometry file.") @@ -506,6 +508,14 @@ def load_crystfel_geometry(filename): else: found_placeholder = True + if dim_length is None: + dim_length = len(panel['dim_structure']) + elif dim_length != len(panel['dim_structure']): + raise RuntimeError('Number of dim coordinates must be the same for all panels.') + + if len(dim_length) == 1: + raise RuntimeError('Number of dim coordinates must be at least two.') + for panel in detector['panels'].values(): if panel['origin_min_fs'] < 0: @@ -574,7 +584,7 @@ def load_crystfel_geometry(filename): panel['xss'] = panel['fsy'] / d panel['yss'] = panel['fsx'] / d - find_min_max_d(detector) + _find_min_max_d(detector) fh.close() return detector -- GitLab