def _detector(self): '''Return a working detector instance.''' if self._panel_origin is not None: from dxtbx.model import Detector detector = Detector() root = detector.hierarchy() root.set_frame(self._fast_axis, self._slow_axis, self._detector_origin) i_panel = 0 for p_offset, p_size, origin, fast, slow in zip( self._panel_offset, self._panel_size, self._panel_origin, self._panel_fast, self._panel_slow): # ensure mutual orthogonality in presence of numerical rounding errors normal = fast.cross(slow) slow = normal.cross(fast) p = root.add_panel() p.set_type('unknown') p.set_raw_image_offset(p_offset) p.set_image_size(p_size) p.set_name('Panel%d' % i_panel) p.set_pixel_size(self._pixel_size) p.set_frame(fast.elems, slow.elems, origin.elems) i_panel += 1 return detector return self._detector_factory.complex( self._detector_factory.sensor('unknown'), self._detector_origin, self._fast_axis, self._slow_axis, self._pixel_size, self._image_size, (0, 1.e9))
def _detector(self): '''Return a working detector instance.''' if self._panel_origin is not None: from dxtbx.model import Detector detector = Detector() root = detector.hierarchy() root.set_frame(self._fast_axis, self._slow_axis, self._detector_origin) i_panel = 0 for p_offset, p_size, origin, fast, slow in zip( self._panel_offset, self._panel_size, self._panel_origin, self._panel_fast, self._panel_slow): # ensure mutual orthogonality in presence of numerical rounding errors normal = fast.cross(slow) slow = normal.cross(fast) p = root.add_panel() p.set_type('unknown') p.set_raw_image_offset(p_offset) p.set_image_size(p_size) p.set_name('Panel%d' %i_panel) p.set_pixel_size(self._pixel_size) p.set_frame(fast.elems, slow.elems, origin.elems) i_panel += 1 return detector return self._detector_factory.complex( self._detector_factory.sensor('unknown'), self._detector_origin, self._fast_axis, self._slow_axis, self._pixel_size, self._image_size, (0, 1.e9))
def _detector(self, index=None): from dxtbx.model import Detector if index is None: index = 0 d = Detector() root = d.hierarchy() all_addresses = self._src def recursive_add_node(a, b): # add a to b if a.is_panel(): b.add_panel(a) else: g = b.add_group(a) for child in a: recursive_add_node(child, g) for address in all_addresses: self._src = [address] sub_d = None try: if 'rayonix' in address.lower(): sub_d = FormatXTCRayonix._detector(self) elif 'cspad' in address.lower(): sub_d = FormatXTCCspad._detector(self, index) elif 'jungfrau' in address.lower(): sub_d = FormatXTCJungfrau._detector(self, index) except Exception: continue assert sub_d is not None, address recursive_add_node(sub_d.hierarchy(), root) self._src = all_addresses return d
def detector(): detector = Detector() root = detector.hierarchy() root.set_name("D1") root.set_type("D") quad1 = root.add_group() quad1.set_name("Q1") quad1.set_type("Q") panel1 = quad1.add_panel() panel1.set_name("P1") panel1.set_type("P") panel2 = quad1.add_panel() panel2.set_name("P2") panel2.set_type("P") quad2 = root.add_group() quad2.set_name("Q2") quad2.set_type("Q") panel3 = quad2.add_panel() panel3.set_name("P3") panel3.set_type("P") panel4 = quad2.add_panel() panel4.set_name("P4") panel4.set_type("P") return detector
def __init__(self): detector = Detector() root = detector.hierarchy() root.set_name("D1") root.set_type("D") quad1 = root.add_group() quad1.set_name("Q1") quad1.set_type("Q") panel1 = quad1.add_panel() panel1.set_name("P1") panel1.set_type("P") panel2 = quad1.add_panel() panel2.set_name("P2") panel2.set_type("P") quad2 = root.add_group() quad2.set_name("Q2") quad2.set_type("Q") panel3 = quad2.add_panel() panel3.set_name("P3") panel3.set_type("P") panel4 = quad2.add_panel() panel4.set_name("P4") panel4.set_type("P") self.detector = detector
def _detector(self, index=None): if index is None: index = 0 d = Detector() root = d.hierarchy() all_addresses = self.params.detector_address def recursive_add_node(a, b): # add a to b if a.is_panel(): b.add_panel(a) else: g = b.add_group(a) for child in a: recursive_add_node(child, g) for address in all_addresses: self.params.detector_address = [address] sub_d = None try: if "rayonix" in address.lower(): sub_d = FormatXTCRayonix._detector(self) elif "cspad" in address.lower(): sub_d = FormatXTCCspad._detector(self, index) elif "jungfrau" in address.lower(): sub_d = FormatXTCJungfrau._detector(self, index) except Exception: continue assert sub_d is not None, address recursive_add_node(sub_d.hierarchy(), root) self.params.detector_address = all_addresses return d
def __call__(self): from dxtbx.model import Detector, Panel # import dependency d1 = Detector() p = d1.add_panel() p.set_name("p1") p.set_type("panel") p.set_pixel_size((0.1, 0.1)) p.set_image_size((100, 100)) p.set_trusted_range((0, 1000)) p.set_local_frame((1, 0, 0), (0, 1, 0), (0, 0, 1)) p = d1.add_panel() p.set_name("p2") p.set_type("panel") p.set_pixel_size((0.2, 0.2)) p.set_image_size((200, 200)) p.set_trusted_range((0, 2000)) p.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 1)) root = d1.hierarchy() g = root.add_group() g.set_name("g1") g.set_type("group") g.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 2)) g.add_panel(d1[0]) g = root.add_group() g.set_name("g2") g.set_type("group") g.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 4)) g.add_panel(d1[1]) d = d1.to_dict() d2 = Detector.from_dict(d) assert (len(d1) == len(d2)) for p1, p2 in zip(d1, d2): assert (p1 == p2) assert (d1.hierarchy() == d2.hierarchy()) assert (d1 == d2) print 'OK'
def __call__(self): from dxtbx.model import Detector, Panel # import dependency d1 = Detector() p = d1.add_panel() p.set_name("p1") p.set_type("panel") p.set_pixel_size((0.1, 0.1)) p.set_image_size((100, 100)) p.set_trusted_range((0, 1000)) p.set_local_frame((1, 0, 0), (0, 1, 0), (0, 0, 1)) p = d1.add_panel() p.set_name("p2") p.set_type("panel") p.set_pixel_size((0.2, 0.2)) p.set_image_size((200, 200)) p.set_trusted_range((0, 2000)) p.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 1)) root = d1.hierarchy() g = root.add_group() g.set_name("g1") g.set_type("group") g.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 2)) g.add_panel(d1[0]) g = root.add_group() g.set_name("g2") g.set_type("group") g.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 4)) g.add_panel(d1[1]) d = d1.to_dict() d2 = Detector.from_dict(d) assert(len(d1) == len(d2)) for p1, p2 in zip(d1, d2): assert(p1 == p2) assert(d1.hierarchy() == d2.hierarchy()) assert(d1 == d2) print 'OK'
def test_hierarchical_detector(): '''Test pickling the detector object.''' p = Panel() p.set_local_frame((1, 0, 0), (0, 1, 0), (0, 0, 1)) obj1 = Detector() root = obj1.hierarchy() root.add_panel(p) root.add_group() obj2 = pickle_then_unpickle(obj1) assert obj2.hierarchy()[0] == obj2[0] assert obj2.hierarchy()[0] in obj2 assert obj2.hierarchy()[1].is_group() assert obj1 == obj2
def test_detector(): d1 = Detector() p = d1.add_panel() p.set_name("p1") p.set_type("panel") p.set_pixel_size((0.1, 0.1)) p.set_image_size((100, 100)) p.set_trusted_range((0, 1000)) p.set_local_frame((1, 0, 0), (0, 1, 0), (0, 0, 1)) p = d1.add_panel() p.set_name("p2") p.set_type("panel") p.set_pixel_size((0.2, 0.2)) p.set_image_size((200, 200)) p.set_trusted_range((0, 2000)) p.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 1)) root = d1.hierarchy() g = root.add_group() g.set_name("g1") g.set_type("group") g.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 2)) g.add_panel(d1[0]) g = root.add_group() g.set_name("g2") g.set_type("group") g.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 4)) g.add_panel(d1[1]) d = d1.to_dict() d2 = Detector.from_dict(d) assert len(d1) == len(d2) for p1, p2 in zip(d1, d2): assert p1 == p2 assert d1.hierarchy() == d2.hierarchy() assert d1 == d2
def tst_hierarchical_detector(): '''Test pickling the detector object.''' p = Panel() p.set_local_frame((1, 0, 0), (0, 1, 0), (0, 0, 1)) obj1 = Detector() root = obj1.hierarchy() root.add_panel(p) root.add_group() obj2 = pickle_then_unpickle(obj1) assert(obj2.hierarchy()[0] == obj2[0]) assert(obj2.hierarchy()[0] in obj2) assert(obj2.hierarchy()[1].is_group()) assert(obj1 == obj2) print "OK"
def _detector(self, index=None): import psana from xfel.cftbx.detector.cspad_cbf_tbx import read_slac_metrology from dxtbx.model import Detector from scitbx.matrix import col from dxtbx.model import ParallaxCorrectedPxMmStrategy if index is None: index = 0 self._env = self._ds.env() self._det = psana.Detector(self._src, self._env) geom = self._det.pyda.geoaccess(self.events_list[index]) cob = read_slac_metrology(geometry=geom, include_asic_offset=True) d = Detector() pg0 = d.hierarchy() # first deal with D0 det_num = 0 origin = col((cob[(0, )] * col((0, 0, 0, 1)))[0:3]) fast = col((cob[(0, )] * col((1, 0, 0, 1)))[0:3]) - origin slow = col((cob[(0, )] * col((0, 1, 0, 1)))[0:3]) - origin origin += col((0., 0., -100.)) pg0.set_local_frame(fast.elems, slow.elems, origin.elems) pg0.set_name('D%d' % (det_num)) for quad_num in xrange(4): # Now deal with Qx pg1 = pg0.add_group() origin = col((cob[(0, quad_num)] * col((0, 0, 0, 1)))[0:3]) fast = col((cob[(0, quad_num)] * col((1, 0, 0, 1)))[0:3]) - origin slow = col((cob[(0, quad_num)] * col((0, 1, 0, 1)))[0:3]) - origin pg1.set_local_frame(fast.elems, slow.elems, origin.elems) pg1.set_name('D%dQ%d' % (det_num, quad_num)) for sensor_num in xrange(8): # Now deal with Sy pg2 = pg1.add_group() origin = col((cob[(0, quad_num, sensor_num)] * col( (0, 0, 0, 1)))[0:3]) fast = col((cob[(0, quad_num, sensor_num)] * col( (1, 0, 0, 1)))[0:3]) - origin slow = col((cob[(0, quad_num, sensor_num)] * col( (0, 1, 0, 1)))[0:3]) - origin pg2.set_local_frame(fast.elems, slow.elems, origin.elems) pg2.set_name('D%dQ%dS%d' % (det_num, quad_num, sensor_num)) # Now deal with Az for asic_num in xrange(2): val = 'ARRAY_D0Q%dS%dA%d' % (quad_num, sensor_num, asic_num) p = pg2.add_panel() origin = col( (cob[(0, quad_num, sensor_num, asic_num)] * col( (0, 0, 0, 1)))[0:3]) fast = col((cob[(0, quad_num, sensor_num, asic_num)] * col( (1, 0, 0, 1)))[0:3]) - origin slow = col((cob[(0, quad_num, sensor_num, asic_num)] * col( (0, 1, 0, 1)))[0:3]) - origin p.set_local_frame(fast.elems, slow.elems, origin.elems) p.set_pixel_size( (cspad_cbf_tbx.pixel_size, cspad_cbf_tbx.pixel_size)) p.set_image_size(cspad_cbf_tbx.asic_dimension) p.set_trusted_range((cspad_tbx.cspad_min_trusted_value, cspad_tbx.cspad_saturated_value)) p.set_name(val) try: beam = self._beam(index) except Exception: print 'No beam object initialized. Returning CSPAD detector without parallax corrections' return d # take into consideration here the thickness of the sensor also the # wavelength of the radiation (which we have in the same file...) wavelength = beam.get_wavelength() thickness = 0.5 # mm, see Hart et al. 2012 from cctbx.eltbx import attenuation_coefficient table = attenuation_coefficient.get_table("Si") # mu_at_angstrom returns cm^-1 mu = table.mu_at_angstrom(wavelength) / 10.0 # mu: mm^-1 t0 = thickness for panel in d: panel.set_px_mm_strategy(ParallaxCorrectedPxMmStrategy(mu, t0)) return d
from __future__ import print_function from dxtbx.model import Detector d = Detector() p1 = d.add_panel() p2 = d.add_panel() p3 = d.add_panel() p4 = d.add_panel() root = d.hierarchy() g = root.add_group() g.add_panel(d[0]) g.add_panel(d[1]) root.add_panel(d[2]) root.add_panel(d[3]) print(d.to_dict())
def _detector(self): '''Detector model, allowing for small offsets in the positions of 60 detector modules''' # Module positional offsets in x, y, in pixels - for the moment ignoring the # rotational offsets as these are not well defined. To be honest these # positional offsets are also not well defined as I do not know how they # should be applied... x = { (0, 0): -0.477546, (0, 1): 0.130578, (0, 2): 0.045041, (0, 3): -0.439872, (0, 4): -0.382077, (1, 0): 0.087405, (1, 1): 0.249597, (1, 2): 0.184265, (1, 3): 0.158342, (1, 4): 0.025225, (2, 0): -0.179892, (2, 1): -0.010974, (2, 2): -0.139207, (2, 3): 0.282851, (2, 4): -0.442219, (3, 0): -0.185027, (3, 1): 0.218601, (3, 2): 0.092585, (3, 3): 0.35862, (3, 4): -0.29161, (4, 0): 0.145368, (4, 1): 0.609289, (4, 2): 0.396265, (4, 3): 0.41625, (4, 4): 0.07152, (5, 0): 0.247142, (5, 1): 0.046563, (5, 2): 0.248714, (5, 3): -0.044628, (5, 4): -0.391509, (6, 0): 0.516643, (6, 1): 0.358453, (6, 2): 0.069219, (6, 3): 0.095861, (6, 4): -0.167403, (7, 0): -0.381352, (7, 1): -0.35338, (7, 2): 0.348656, (7, 3): 0.024543, (7, 4): 0.328706, (8, 0): 0.150886, (8, 1): 0.244987, (8, 2): -0.102911, (8, 3): 0.16633, (8, 4): 0.386622, (9, 0): 0.037924, (9, 1): 0.314392, (9, 2): 0.238818, (9, 3): 0.815028, (9, 4): -0.048818, (10, 0): -0.670524, (10, 1): -0.304119, (10, 2): 0.252284, (10, 3): -0.05485, (10, 4): -0.355264, (11, 0): -0.404947, (11, 1): -0.020622, (11, 2): 0.648473, (11, 3): -0.277175, (11, 4): -0.711951 } y = { (0, 0): -0.494797, (0, 1): -0.212976, (0, 2): 0.085351, (0, 3): 0.35494, (0, 4): 0.571189, (1, 0): -0.421708, (1, 1): 0.061914, (1, 2): 0.238996, (1, 3): 0.146692, (1, 4): 0.407145, (2, 0): -0.313212, (2, 1): -0.225025, (2, 2): 0.031613, (2, 3): -0.047839, (2, 4): 0.42716, (3, 0): -0.361193, (3, 1): 0.057663, (3, 2): 0.022357, (3, 3): 0.062717, (3, 4): 0.150611, (4, 0): 0.035511, (4, 1): -0.271567, (4, 2): 0.007761, (4, 3): -0.124021, (4, 4): 0.093017, (5, 0): -0.238897, (5, 1): -0.179724, (5, 2): -0.113608, (5, 3): 0.017841, (5, 4): -0.012933, (6, 0): -0.166337, (6, 1): -0.272922, (6, 2): -0.194665, (6, 3): -0.058535, (6, 4): -0.405404, (7, 0): -0.318824, (7, 1): -0.311276, (7, 2): -0.205223, (7, 3): -0.292664, (7, 4): -0.474762, (8, 0): -0.039504, (8, 1): -0.239887, (8, 2): -0.343485, (8, 3): -0.459429, (8, 4): -0.426901, (9, 0): -0.187805, (9, 1): 0.282727, (9, 2): -0.601164, (9, 3): -0.467605, (9, 4): -0.589271, (10, 0): 0.028311, (10, 1): -0.391571, (10, 2): -0.463112, (10, 3): -0.358092, (10, 4): -0.285396, (11, 0): 0.01863, (11, 1): -0.380099, (11, 2): -0.234953, (11, 3): -0.593992, (11, 4): -0.801247 } distance = float( self._cif_header_dictionary['Detector_distance'].split()[0]) beam_xy = self._cif_header_dictionary['Beam_xy'].replace( '(', '').replace(')', '').replace(',', '').split()[:2] beam_x, beam_y = map(float, beam_xy) wavelength = float( self._cif_header_dictionary['Wavelength'].split()[0]) pixel_xy = self._cif_header_dictionary['Pixel_size'].replace( 'm', '').replace('x', '').split() pixel_x, pixel_y = map(float, pixel_xy) thickness = float( self._cif_header_dictionary['Silicon'].split()[2]) * 1000.0 nx = int( self._cif_header_dictionary['X-Binary-Size-Fastest-Dimension']) ny = int(self._cif_header_dictionary['X-Binary-Size-Second-Dimension']) overload = int(self._cif_header_dictionary['Count_cutoff'].split()[0]) underload = -1 # take into consideration here the thickness of the sensor also the # wavelength of the radiation (which we have in the same file...) from cctbx.eltbx import attenuation_coefficient table = attenuation_coefficient.get_table("Si") mu = table.mu_at_angstrom(wavelength) / 10.0 t0 = thickness # FIXME would also be very nice to be able to take into account the # misalignment of the individual modules given the calibration... # single detector or multi-module detector pixel_x *= 1000.0 pixel_y *= 1000.0 distance *= 1000.0 if not self._multi_panel: detector = self._detector_factory.simple( 'PAD', distance, (beam_x * pixel_x, beam_y * pixel_y), '+x', '-y', (pixel_x, pixel_y), (nx, ny), (underload, overload), [], ParallaxCorrectedPxMmStrategy(mu, t0)) for f0, f1, s0, s1 in determine_pilatus_mask(detector): detector[0].add_mask(f0 - 1, s0 - 1, f1, s1) detector[0].set_thickness(thickness) detector[0].set_material('Si') detector[0].set_mu(mu) return detector # got to here means 60-panel version from dxtbx.model import Detector from scitbx import matrix d = Detector() beam_centre = matrix.col((beam_x * pixel_x, beam_y * pixel_y, 0)) fast = matrix.col((1.0, 0.0, 0.0)) slow = matrix.col((0.0, -1.0, 0.0)) s0 = matrix.col((0, 0, -1)) origin = (distance * s0) - (fast * beam_centre[0]) - \ (slow * beam_centre[1]) root = d.hierarchy() root.set_local_frame(fast.elems, slow.elems, origin.elems) xmins = [0, 494, 988, 1482, 1976] xmaxes = [487, 981, 1475, 1969, 2463] ymins = [ 0, 212, 424, 636, 848, 1060, 1272, 1484, 1696, 1908, 2120, 2332 ] ymaxes = [ 195, 407, 619, 831, 1043, 1255, 1467, 1679, 1891, 2103, 2315, 2527 ] self.coords = {} fast = matrix.col((1.0, 0.0, 0.0)) slow = matrix.col((0.0, 1.0, 0.0)) panel_idx = 0 for ymin, ymax in zip(ymins, ymaxes): for xmin, xmax in zip(xmins, xmaxes): xmin_mm = xmin * pixel_x ymin_mm = ymin * pixel_y origin_panel = fast * xmin_mm + slow * ymin_mm panel_name = "Panel%d" % panel_idx panel_idx += 1 p = root.add_panel() p.set_type("SENSOR_PAD") p.set_px_mm_strategy(ParallaxCorrectedPxMmStrategy(mu, t0)) p.set_name(panel_name) p.set_image_size((xmax - xmin, ymax - ymin)) p.set_trusted_range((underload, overload)) p.set_pixel_size((pixel_x, pixel_y)) p.set_thickness(thickness) p.set_material('Si') p.set_mu(mu) p.set_local_frame(fast.elems, slow.elems, origin_panel.elems) p.set_raw_image_offset((xmin, ymin)) self.coords[panel_name] = (xmin, ymin, xmax, ymax) return d
def _detector(self, index=None): from PSCalib.SegGeometryStore import sgs from xfel.cftbx.detector.cspad_cbf_tbx import basis_from_geo run = self.get_run_from_index(index) if run.run() in self._cached_detector: return self._cached_detector[run.run()] if index is None: index = 0 self._env = self._ds.env() assert len(self.params.detector_address) == 1 self._det = psana.Detector(self.params.detector_address[0], self._env) geom = self._det.pyda.geoaccess(self._get_event(index).run()) pixel_size = (self._det.pixel_size(self._get_event(index)) / 1000.0 ) # convert to mm d = Detector() pg0 = d.hierarchy() # first deal with D0 det_num = 0 root = geom.get_top_geo() root_basis = basis_from_geo(root) while len(root.get_list_of_children()) == 1: sub = root.get_list_of_children()[0] sub_basis = basis_from_geo(sub) root = sub root_basis = root_basis * sub_basis t = root_basis.translation root_basis.translation = col((t[0], t[1], -t[2])) origin = col((root_basis * col((0, 0, 0, 1)))[0:3]) fast = col((root_basis * col((1, 0, 0, 1)))[0:3]) - origin slow = col((root_basis * col((0, 1, 0, 1)))[0:3]) - origin pg0.set_local_frame(fast.elems, slow.elems, origin.elems) pg0.set_name("D%d" % (det_num)) # Now deal with modules for module_num in range(len(root.get_list_of_children())): module = root.get_list_of_children()[module_num] module_basis = basis_from_geo(module) origin = col((module_basis * col((0, 0, 0, 1)))[0:3]) fast = col((module_basis * col((1, 0, 0, 1)))[0:3]) - origin slow = col((module_basis * col((0, 1, 0, 1)))[0:3]) - origin pg1 = pg0.add_group() pg1.set_local_frame(fast.elems, slow.elems, origin.elems) pg1.set_name("D%dM%d" % (det_num, module_num)) # Read the known layout of the Jungfrau 2x4 module sg = sgs.Create(segname=module.oname) xx, yy = sg.get_seg_xy_maps_um() xx = xx / 1000 yy = yy / 1000 # Now deal with ASICs for asic_num in range(8): val = "ARRAY_D0M%dA%d" % (module_num, asic_num) dim_slow = xx.shape[0] dim_fast = xx.shape[1] sensor_id = asic_num // 4 # There are 2X4 asics per module asic_in_sensor_id = asic_num % 4 # this number will be 0,1,2 or 3 id_slow = sensor_id * (dim_slow // 2) id_fast = asic_in_sensor_id * (dim_fast // 4) origin = col((xx[id_slow][id_fast], yy[id_slow][id_fast], 0)) fp = col( (xx[id_slow][id_fast + 1], yy[id_slow][id_fast + 1], 0)) sp = col( (xx[id_slow + 1][id_fast], yy[id_slow + 1][id_fast], 0)) fast = (fp - origin).normalize() slow = (sp - origin).normalize() p = pg1.add_panel() p.set_local_frame(fast.elems, slow.elems, origin.elems) p.set_pixel_size((pixel_size, pixel_size)) p.set_trusted_range((-10, 2e6)) p.set_name(val) thickness, material = 0.32, "Si" p.set_thickness(thickness) # mm p.set_material(material) # Compute the attenuation coefficient. # This will fail for undefined composite materials # mu_at_angstrom returns cm^-1, but need mu in mm^-1 table = attenuation_coefficient.get_table(material) wavelength = self.get_beam(index).get_wavelength() mu = table.mu_at_angstrom(wavelength) / 10.0 p.set_mu(mu) p.set_px_mm_strategy( ParallaxCorrectedPxMmStrategy(mu, thickness)) if (self.params.jungfrau.use_big_pixels and os.environ.get("DONT_USE_BIG_PIXELS_JUNGFRAU") is None): p.set_image_size((1030, 514)) break else: p.set_image_size((dim_fast // 4, dim_slow // 2)) if (self.params.jungfrau.use_big_pixels and os.environ.get("DONT_USE_BIG_PIXELS_JUNGFRAU") is None): assert len(d) == 8 self._cached_detector[run.run()] = d return d
from dxtbx.model import Detector d = Detector() p1 = d.add_panel() p2 = d.add_panel() p3 = d.add_panel() p4 = d.add_panel() root = d.hierarchy() g = root.add_group() g.add_panel(d[0]) g.add_panel(d[1]) root.add_panel(d[2]) root.add_panel(d[3]) print d.to_dict()
class DetectorFactoryFromGroup(object): ''' A class to create a detector model from a NXdetector_group ''' def __init__(self, instrument, beam, idx = None): from dxtbx.model import Detector, Panel from cctbx.eltbx import attenuation_coefficient from dxtbx.model import ParallaxCorrectedPxMmStrategy from scitbx import matrix import os if idx is None: idx = 0 assert len(instrument.detector_groups) == 1, "Multiple detectors not supported" nx_group = instrument.detector_groups[0].handle group_names = nx_group['group_names'] group_indices = nx_group['group_index'] group_parent = nx_group['group_parent'] # Verify the NXdetector objects specified by the detector group are present expected_detectors = [] root_name = None for i, parent_id in enumerate(group_parent): assert parent_id in [-1, 1], "Hierarchy of detectors not supported. Hierarchy of module components within detector elements is supported" if parent_id == -1: assert root_name is None, "Multiple roots not supported" root_name = group_names[i] else: expected_detectors.append(group_names[i]) assert root_name is not None, "Detector root not found" assert sorted([os.path.basename(d.handle.name) for d in instrument.detectors]) == sorted(expected_detectors), \ "Mismatch between detector group names and detectors available" root = None def set_frame(pg, transformation): ''' Function to set the local frame of a panel/panel group given an NXtransformation ''' parent, cob = get_cummulative_change_of_basis(transformation) # set up the dxtbx d matrix. Note use of homogenous coordinates. origin = matrix.col((cob * matrix.col((0,0,0,1)))[0:3]) fast = matrix.col((cob * matrix.col((1,0,0,1)))[0:3]) - origin slow = matrix.col((cob * matrix.col((0,1,0,1)))[0:3]) - origin pg.set_local_frame( fast.elems, slow.elems, origin.elems) name = str(os.path.basename(transformation.name)) pg.set_name(name) self.model = Detector() for nx_detector in instrument.detectors: # Get the detector type if 'type' in nx_detector.handle: detector_type = str(nx_detector.handle['type'][()]) else: detector_type = "unknown" # get the set of leaf modules (handles nested modules) modules = [] for nx_detector_module in nx_detector.modules: if len(find_class(nx_detector_module.handle, "NXdetector_module")) == 0: modules.append(nx_detector_module) n_modules = len(modules) # depends_on field for a detector will have NxM entries in it, where # N = number of images and M = number of detector modules assert len(nx_detector.handle['depends_on']) % n_modules == 0, "Couldn't find NXdetector_modules matching the list of dependencies for this detector" for module_number, nx_detector_module in enumerate(modules): # Get the depends_on starting point for this module and for this image depends_on = nx_detector.handle[nx_detector.handle['depends_on'][(idx//n_modules)+module_number]] panel_name = str(os.path.basename(nx_detector_module.handle.name)) px_fast = int(nx_detector_module.handle['data_size'][0]) px_slow = int(nx_detector_module.handle['data_size'][1]) image_size = px_fast, px_slow fast_pixel_size = nx_detector_module.handle['fast_pixel_size'][()] slow_pixel_size = nx_detector_module.handle['slow_pixel_size'][()] pixel_size = fast_pixel_size, slow_pixel_size # XXX no units for pixel size in nx example file, plus fast_pixel_size isn't a standardized NXdetector_module field #fast_pixel_direction_units = fast_pixel_direction.attrs['units'] #fast_pixel_size = convert_units( # fast_pixel_direction_value, # fast_pixel_direction_units, # "mm") # Get the trusted range of pixel values underload = float(nx_detector['undefined_value'][()]) if 'undefined_value' in nx_detector.handle else -400 overload = float(nx_detector['saturation_value'][()]) if 'saturation_value' in nx_detector.handle else 90000 trusted_range = underload, overload # Set up the hierarchical detector by iteraing through the dependencies, # starting at the root chain = get_depends_on_chain_using_equipment_components(depends_on) pg = None for transform in reversed(chain): name = str(os.path.basename(transform.name)) if pg is None: # The first transform will be the root of the hiearchy if root is None: root = self.model.hierarchy() set_frame(root, transform) else: assert root.get_name() == name, "Found multiple roots" pg = root continue # subsequent times through the loop, pg will be the parent of the # current transform pg_names = [child.get_name() for child in pg] if name in pg_names: pg = pg[pg_names.index(name)] else: pg = pg.add_group() set_frame(pg, transform) # pg is now this panel's parent p = pg.add_panel() fast = depends_on.attrs['vector'] fast = matrix.col([-fast[0], fast[1], -fast[2]]) slow = nx_detector_module.handle[depends_on.attrs['depends_on']].attrs['vector'] slow = matrix.col([-slow[0], slow[1], -slow[2]]) parent, cob = get_cummulative_change_of_basis(depends_on) origin = matrix.col((cob * matrix.col((0,0,0,1)))[0:3]) p.set_local_frame( fast.elems, slow.elems, origin.elems) p.set_name(panel_name) p.set_pixel_size(pixel_size) p.set_image_size(image_size) p.set_type(detector_type) p.set_trusted_range(trusted_range) if 'sensor_thickness' in nx_detector.handle: # Get the detector thickness thickness = nx_detector.handle['sensor_thickness'] thickness_value = float(thickness[()]) thickness_units = thickness.attrs['units'] thickness_value = float(convert_units( thickness_value, thickness_units, "mm")) p.set_thickness(thickness_value) # Get the detector material if 'sensor_material' in nx_detector.handle: material = str(nx_detector.handle['sensor_material'][()]) p.set_material(material) # Compute the attenuation coefficient. # This will fail for undefined composite materials # mu_at_angstrom returns cm^-1, but need mu in mm^-1 if material == 'Si': pass elif material == 'Silicon': material = 'Si' elif material == 'Sillicon': material = 'Si' elif material == 'CdTe': pass elif material == 'GaAs': pass else: raise RuntimeError('Unknown material: %s' % material) table = attenuation_coefficient.get_table(material) wavelength = beam.get_wavelength() p.set_mu(table.mu_at_angstrom(wavelength) / 10.0) if 'sensor_thickness' in nx_detector.handle and 'sensor_material' in nx_detector.handle: p.set_px_mm_strategy(ParallaxCorrectedPxMmStrategy(mu, thickness_value))
def _detector(self): """Return a model for a simple detector, presuming no one has one of these on a two-theta stage. Assert that the beam centre is provided in the Mosflm coordinate frame.""" if not self._multi_panel: detector = FormatCBFMini._detector(self) for f0, f1, s0, s1 in determine_pilatus_mask(detector): detector[0].add_mask(f0 - 1, s0 - 1, f1, s1) return detector # got to here means 60-panel version d = Detector() distance = float( self._cif_header_dictionary["Detector_distance"].split()[0]) beam_xy = (self._cif_header_dictionary["Beam_xy"].replace( "(", "").replace(")", "").replace(",", "").split()[:2]) beam_x, beam_y = map(float, beam_xy) wavelength = float( self._cif_header_dictionary["Wavelength"].split()[0]) pixel_xy = (self._cif_header_dictionary["Pixel_size"].replace( "m", "").replace("x", "").split()) pixel_x, pixel_y = map(float, pixel_xy) thickness = float( self._cif_header_dictionary["Silicon"].split()[2]) * 1000.0 nx = int( self._cif_header_dictionary["X-Binary-Size-Fastest-Dimension"]) ny = int(self._cif_header_dictionary["X-Binary-Size-Second-Dimension"]) overload = int(self._cif_header_dictionary["Count_cutoff"].split()[0]) underload = -1 # take into consideration here the thickness of the sensor also the # wavelength of the radiation (which we have in the same file...) table = attenuation_coefficient.get_table("Si") mu = table.mu_at_angstrom(wavelength) / 10.0 t0 = thickness # FIXME would also be very nice to be able to take into account the # misalignment of the individual modules given the calibration... # single detector or multi-module detector pixel_x *= 1000.0 pixel_y *= 1000.0 distance *= 1000.0 beam_centre = matrix.col((beam_x * pixel_x, beam_y * pixel_y, 0)) fast = matrix.col((1.0, 0.0, 0.0)) slow = matrix.col((0.0, -1.0, 0.0)) s0 = matrix.col((0, 0, -1)) origin = (distance * s0) - (fast * beam_centre[0]) - (slow * beam_centre[1]) root = d.hierarchy() root.set_local_frame(fast.elems, slow.elems, origin.elems) det = _DetectorDatabase["Pilatus"] # Edge dead areas not included, only gaps between modules matter n_fast, remainder = divmod(nx, det.module_size_fast) assert (n_fast - 1) * det.gap_fast == remainder n_slow, remainder = divmod(ny, det.module_size_slow) assert (n_slow - 1) * det.gap_slow == remainder mx = det.module_size_fast my = det.module_size_slow dx = det.gap_fast dy = det.gap_slow xmins = [(mx + dx) * i for i in range(n_fast)] xmaxes = [mx + (mx + dx) * i for i in range(n_fast)] ymins = [(my + dy) * i for i in range(n_slow)] ymaxes = [my + (my + dy) * i for i in range(n_slow)] self.coords = {} fast = matrix.col((1.0, 0.0, 0.0)) slow = matrix.col((0.0, 1.0, 0.0)) panel_idx = 0 for ymin, ymax in zip(ymins, ymaxes): for xmin, xmax in zip(xmins, xmaxes): xmin_mm = xmin * pixel_x ymin_mm = ymin * pixel_y origin_panel = fast * xmin_mm + slow * ymin_mm panel_name = "Panel%d" % panel_idx panel_idx += 1 p = d.add_panel() p.set_type("SENSOR_PAD") p.set_name(panel_name) p.set_raw_image_offset((xmin, ymin)) p.set_image_size((xmax - xmin, ymax - ymin)) p.set_trusted_range((underload, overload)) p.set_pixel_size((pixel_x, pixel_y)) p.set_thickness(thickness) p.set_material("Si") p.set_mu(mu) p.set_px_mm_strategy(ParallaxCorrectedPxMmStrategy(mu, t0)) p.set_local_frame(fast.elems, slow.elems, origin_panel.elems) p.set_raw_image_offset((xmin, ymin)) self.coords[panel_name] = (xmin, ymin, xmax, ymax) return d
def _detector(self): # module positions from detector blueprints - modelling at the moment as # 24 modules, each consisting of 5 sensors (the latter is ignored) from dxtbx.model import Detector from scitbx import matrix import math x = matrix.col((-1, 0, 0)) y = matrix.col((0, 1, 0)) z = matrix.col((0, 0, 1)) beam_xy = self._cif_header_dictionary['Beam_xy'] beam_xy = beam_xy.replace('(', '').replace(')', '').replace(',', '').split()[:2] obs_beam_x, obs_beam_y = [float(f) for f in beam_xy] ideal_beam_x = 1075 ideal_beam_y = 2594 beam_shift_x = 0.172 * (ideal_beam_x - obs_beam_x) beam_shift_y = 0.172 * (ideal_beam_y - obs_beam_y) distance = float(self._cif_header_dictionary['Detector_distance']. split()[0]) * 1000.0 wavelength = float( self._cif_header_dictionary['Wavelength'].split()[0]) thickness = float( self._cif_header_dictionary['Silicon'].split()[2]) * 1000.0 off_x = 184.9 detector = Detector() root = detector.hierarchy() root.set_frame(x.elems, y.elems, (-distance * z + (beam_shift_x * x) + (beam_shift_y * y)).elems) from cctbx.eltbx import attenuation_coefficient table = attenuation_coefficient.get_table("Si") mu = table.mu_at_angstrom(wavelength) / 10.0 t0 = thickness px_mm = ParallaxCorrectedPxMmStrategy(mu, t0) self.coords = {} for j in range(24): shift_y = 195 + 17 ymin, ymax = j * shift_y, j * shift_y + 195 angle = math.pi * (-12.2 + 0.5 * 7.903 + j * (7.903 + 0.441)) / 180.0 fast = matrix.col((1, 0, 0)) slow = matrix.col((0, math.sin(angle), math.cos(angle))) normal = fast.cross(slow) row_origin = 250.0 * normal - off_x * fast - 16.8 * slow if not self._multi_panel: xmin, xmax = 0, 2463 # OK two calls to add_panel here for detector like things => two # copies of the panel then? https://github.com/dials/dials/issues/189 # ... this is also not the source of the leak # OBS! you need to set the panel to a root before set local frame... p = root.add_panel() p.set_type('SENSOR_PAD') p.set_name('row-%02d' % j) p.set_raw_image_offset((xmin, ymin)) p.set_image_size((2463, 195)) p.set_trusted_range((-1, 1000000)) p.set_pixel_size((0.172, 0.172)) p.set_local_frame(fast.elems, slow.elems, row_origin.elems) p.set_thickness(thickness) p.set_material('Si') p.set_mu(mu) p.set_px_mm_strategy(px_mm) p.set_raw_image_offset((xmin, ymin)) self.coords[p.get_name()] = (xmin, ymin, xmax, ymax) else: shift_x = 487 + 7 for i in range(5): xmin, xmax = i * shift_x, i * shift_x + 487 origin = row_origin + i * (487 + 7) * 0.172 * fast # OBS! you need to set the panel to a root before set local frame... p = root.add_panel() p.set_type('SENSOR_PAD') p.set_name('row-%02d-col-%02d' % (j, i)) p.set_raw_image_offset((xmin, ymin)) p.set_image_size((487, 195)) p.set_trusted_range((-1, 1000000)) p.set_pixel_size((0.172, 0.172)) p.set_local_frame(fast.elems, slow.elems, origin.elems) p.set_thickness(thickness) p.set_material('Si') p.set_mu(mu) p.set_px_mm_strategy(px_mm) p.set_raw_image_offset((xmin, ymin)) self.coords[p.get_name()] = (xmin, ymin, xmax, ymax) return detector
def _detector(self, index=None): if index is None: index = 0 run = self.get_run_from_index(index) det = self._get_psana_detector(run) geom = det.pyda.geoaccess(run.run()) cob = read_slac_metrology(geometry=geom, include_asic_offset=True) distance = env_distance( self.params.detector_address[0], run.env(), self.params.cspad.detz_offset ) d = Detector() pg0 = d.hierarchy() # first deal with D0 det_num = 0 origin = col((cob[(0,)] * col((0, 0, 0, 1)))[0:3]) fast = col((cob[(0,)] * col((1, 0, 0, 1)))[0:3]) - origin slow = col((cob[(0,)] * col((0, 1, 0, 1)))[0:3]) - origin origin += col((0.0, 0.0, -distance)) pg0.set_local_frame(fast.elems, slow.elems, origin.elems) pg0.set_name("D%d" % (det_num)) for quad_num in range(4): # Now deal with Qx pg1 = pg0.add_group() origin = col((cob[(0, quad_num)] * col((0, 0, 0, 1)))[0:3]) fast = col((cob[(0, quad_num)] * col((1, 0, 0, 1)))[0:3]) - origin slow = col((cob[(0, quad_num)] * col((0, 1, 0, 1)))[0:3]) - origin pg1.set_local_frame(fast.elems, slow.elems, origin.elems) pg1.set_name("D%dQ%d" % (det_num, quad_num)) for sensor_num in range(8): # Now deal with Sy pg2 = pg1.add_group() origin = col((cob[(0, quad_num, sensor_num)] * col((0, 0, 0, 1)))[0:3]) fast = ( col((cob[(0, quad_num, sensor_num)] * col((1, 0, 0, 1)))[0:3]) - origin ) slow = ( col((cob[(0, quad_num, sensor_num)] * col((0, 1, 0, 1)))[0:3]) - origin ) pg2.set_local_frame(fast.elems, slow.elems, origin.elems) pg2.set_name("D%dQ%dS%d" % (det_num, quad_num, sensor_num)) # Now deal with Az for asic_num in range(2): val = "ARRAY_D0Q%dS%dA%d" % (quad_num, sensor_num, asic_num) p = pg2.add_panel() origin = col( (cob[(0, quad_num, sensor_num, asic_num)] * col((0, 0, 0, 1)))[ 0:3 ] ) fast = ( col( ( cob[(0, quad_num, sensor_num, asic_num)] * col((1, 0, 0, 1)) )[0:3] ) - origin ) slow = ( col( ( cob[(0, quad_num, sensor_num, asic_num)] * col((0, 1, 0, 1)) )[0:3] ) - origin ) p.set_local_frame(fast.elems, slow.elems, origin.elems) p.set_pixel_size( (cspad_cbf_tbx.pixel_size, cspad_cbf_tbx.pixel_size) ) p.set_image_size(cspad_cbf_tbx.asic_dimension) p.set_trusted_range( ( cspad_tbx.cspad_min_trusted_value, cspad_tbx.cspad_saturated_value, ) ) p.set_name(val) try: beam = self._beam(index) except Exception: print( "No beam object initialized. Returning CSPAD detector without parallax corrections" ) return d # take into consideration here the thickness of the sensor also the # wavelength of the radiation (which we have in the same file...) wavelength = beam.get_wavelength() thickness = 0.5 # mm, see Hart et al. 2012 table = attenuation_coefficient.get_table("Si") # mu_at_angstrom returns cm^-1 mu = table.mu_at_angstrom(wavelength) / 10.0 # mu: mm^-1 t0 = thickness for panel in d: panel.set_px_mm_strategy(ParallaxCorrectedPxMmStrategy(mu, t0)) return d
def _detector(self, index=None): from PSCalib.SegGeometryStore import sgs from xfel.cftbx.detector.cspad_cbf_tbx import basis_from_geo run = self.get_run_from_index(index) if run.run() in self._cached_detector: return self._cached_detector[run.run()] if index is None: index = 0 assert len(self.params.detector_address) == 1 wavelength = self.get_beam(index).get_wavelength() det = self._get_psana_detector(run) geom = det.pyda.geoaccess(self._get_event(index).run()) pixel_size = det.pixel_size(self._get_event(index)) / 1000.0 # convert to mm d = Detector() pg0 = d.hierarchy() # first deal with D0 det_num = 0 root = geom.get_top_geo() root_basis = basis_from_geo(root) while len(root.get_list_of_children()) == 1: sub = root.get_list_of_children()[0] sub_basis = basis_from_geo(sub) root = sub root_basis = root_basis * sub_basis t = root_basis.translation root_basis.translation = col((t[0], t[1], -abs(t[2]))) origin = col((root_basis * col((0, 0, 0, 1)))[0:3]) fast = col((root_basis * col((1, 0, 0, 1)))[0:3]) - origin slow = col((root_basis * col((0, 1, 0, 1)))[0:3]) - origin pg0.set_local_frame(fast.elems, slow.elems, origin.elems) pg0.set_name("D%d" % (det_num)) # Modules next for module_num in range(len(root.get_list_of_children())): pg1 = pg0.add_group() module = root.get_list_of_children()[module_num] module_basis = basis_from_geo(module) origin = col((module_basis * col((0, 0, 0, 1)))[0:3]) fast = col((module_basis * col((1, 0, 0, 1)))[0:3]) - origin slow = col((module_basis * col((0, 1, 0, 1)))[0:3]) - origin pg1.set_local_frame(fast.elems, slow.elems, origin.elems) pg1.set_name("D%dM%d" % (det_num, module_num)) # Read the known layout of the Epix 2x2 module sg = sgs.Create(segname=module.oname) xx, yy = sg.get_seg_xy_maps_um() xx = xx / 1000 yy = yy / 1000 # Now deal with ASICs for asic_num in range(4): val = "ARRAY_D0M%dA%d" % (module_num, asic_num) p = pg1.add_panel() dim_slow = xx.shape[0] dim_fast = xx.shape[1] sensor_id = asic_num // 2 # There are 2X2 asics per module asic_in_sensor_id = asic_num % 2 # this number will be 0 or 1 id_slow = sensor_id * (dim_slow // 2) id_fast = asic_in_sensor_id * (dim_fast // 2) origin = col((xx[id_slow][id_fast], yy[id_slow][id_fast], 0)) fp = col((xx[id_slow][id_fast + 1], yy[id_slow][id_fast + 1], 0)) sp = col((xx[id_slow + 1][id_fast], yy[id_slow + 1][id_fast], 0)) fast = (fp - origin).normalize() slow = (sp - origin).normalize() p.set_local_frame(fast.elems, slow.elems, origin.elems) p.set_pixel_size((pixel_size, pixel_size)) p.set_image_size((dim_fast // 2, dim_slow // 2)) p.set_trusted_range((-1, 2e6)) p.set_gain(factor_kev_angstrom / wavelength) p.set_name(val) self._cached_detector[run.run()] = d return d
def _detector(self, index=None): run = self.get_run_from_index(index) if run.run() in self._cached_detector: return self._cached_detector[run.run()] import psana from dxtbx.model import Detector from scitbx.matrix import col if index is None: index = 0 self._env = self._ds.env() assert len(self.params.detector_address) == 1 self._det = psana.Detector(self.params.detector_address[0], self._env) geom = self._det.pyda.geoaccess(self._get_event(index).run()) pixel_size = ( self._det.pixel_size(self._get_event(index)) / 1000.0 ) # convert to mm d = Detector() pg0 = d.hierarchy() # first deal with D0 det_num = 0 D0 = geom.get_top_geo().get_list_of_children()[0] xx, yy, zz = D0.get_pixel_coords() xx = xx / 1000.0 # to mm yy = yy / 1000.0 # to mm zz = zz / 1000.0 # to mm oriD0 = col((np.mean(xx), np.mean(yy), -np.mean(zz))) fp = col((xx[0][0][1], yy[0][0][1], zz[0][0][1])) sp = col((xx[0][1][0], yy[0][1][0], zz[0][1][0])) op = col((xx[0][0][0], yy[0][0][0], zz[0][0][0])) origin = oriD0 fast = (fp - op).normalize() slow = (sp - op).normalize() pg0.set_local_frame(fast.elems, slow.elems, origin.elems) pg0.set_name("D%d" % (det_num)) # Now deal with Qx for quad_num in range(2): pg1 = pg0.add_group() Qx = D0.get_list_of_children()[quad_num] xx, yy, zz = Qx.get_pixel_coords() xx = xx / 1000.0 # to mm yy = yy / 1000.0 # to mm zz = zz / 1000.0 # to mm oriQx = col((np.mean(xx), np.mean(yy), np.mean(zz))) fp = col((xx[0][1], yy[0][1], zz[0][1])) sp = col((xx[1][0], yy[1][0], zz[1][0])) op = col((xx[0][0], yy[0][0], zz[0][0])) origin = oriQx fast = (fp - op).normalize() slow = (sp - op).normalize() pg1.set_local_frame(fast.elems, slow.elems, origin.elems) pg1.set_name("D%dQ%d" % (det_num, quad_num)) # Now deal with Az for asic_num in range(8): val = "ARRAY_D0Q%dA%d" % (quad_num, asic_num) p = pg1.add_panel() dim_slow = xx.shape[0] dim_fast = xx.shape[1] sensor_id = asic_num // 4 # There are 2X4 asics per quadrant asic_in_sensor_id = asic_num % 4 # this number will be 0,1,2 or 3 id_slow = sensor_id * (dim_slow // 2) id_fast = asic_in_sensor_id * (dim_fast // 4) oriAy = col( (xx[id_slow][id_fast], yy[id_slow][id_fast], zz[id_slow][id_fast]) ) fp = col( ( xx[id_slow][id_fast + 1], yy[id_slow][id_fast + 1], zz[id_slow][id_fast + 1], ) ) sp = col( ( xx[id_slow + 1][id_fast], yy[id_slow + 1][id_fast], zz[id_slow + 1][id_fast], ) ) origin = oriAy - oriQx fast = (fp - oriAy).normalize() slow = (sp - oriAy).normalize() p.set_local_frame(fast.elems, slow.elems, origin.elems) p.set_pixel_size((pixel_size, pixel_size)) p.set_image_size((dim_fast // 4, dim_slow // 2)) p.set_trusted_range((-1, 2e6)) p.set_name(val) self._cached_detector[run.run()] = d return d
def _detector(self): # module positions from detector blueprints - modelling at the moment as # 24 modules, each consisting of 5 sensors (the latter is ignored) from dxtbx.model import Detector from scitbx import matrix import math x = matrix.col((-1, 0, 0)) y = matrix.col((0, 1, 0)) z = matrix.col((0, 0, 1)) obs_beam_y = 2587 ideal_beam_y = 2594 beam_shift_y = 0.172 * (2594 - 2587) distance = float( self._cif_header_dictionary['Detector_distance'].split()[0]) * 1000.0 wavelength = float( self._cif_header_dictionary['Wavelength'].split()[0]) thickness = float( self._cif_header_dictionary['Silicon'].split()[2]) * 1000.0 # for longer wavelength data sets move 192.3 below to 184.9 if wavelength < 1.128: off_x = 191.9 else: off_x = 184.9 z += beam_shift_y * y detector = Detector() root = detector.hierarchy() root.set_frame( x.elems, y.elems, (-distance * z).elems) from cctbx.eltbx import attenuation_coefficient table = attenuation_coefficient.get_table("Si") mu = table.mu_at_angstrom(wavelength) / 10.0 t0 = thickness px_mm = ParallaxCorrectedPxMmStrategy(mu, t0) self.coords = {} for j in range(24): shift_y = 195 + 17 ymin, ymax = j * shift_y, j * shift_y + 195 angle = math.pi * (-12.2 + 0.5 * 7.903 + j * (7.903 + 0.441)) / 180.0 fast = matrix.col((1, 0, 0)) slow = matrix.col((0, math.sin(angle), math.cos(angle))) normal = fast.cross(slow) row_origin = 250.0 * normal - off_x * fast - 16.8 * slow if not self._multi_panel: xmin, xmax = 0, 2463 # OK two calls to add_panel here for detector like things => two # copies of the panel then? https://github.com/dials/dials/issues/189 # ... this is also not the source of the leak # OBS! you need to set the panel to a root before set local frame... p = root.add_panel() p.set_type('SENSOR_PAD') p.set_name('row-%02d' % j) p.set_raw_image_offset((xmin, ymin)) p.set_image_size((2463, 195)) p.set_trusted_range((-1, 1000000)) p.set_pixel_size((0.172, 0.172)) p.set_local_frame( fast.elems, slow.elems, row_origin.elems) p.set_thickness(thickness) p.set_material('Si') p.set_mu(mu) p.set_px_mm_strategy(px_mm) p.set_raw_image_offset((xmin,ymin)) self.coords[p.get_name()] = (xmin,ymin,xmax,ymax) else: shift_x = 487 + 7 for i in range(5): xmin, xmax = i * shift_x, i * shift_x + 487 origin = row_origin + i * (487+7) * 0.172 * fast # OBS! you need to set the panel to a root before set local frame... p = root.add_panel() p.set_type('SENSOR_PAD') p.set_name('row-%02d-col-%02d' % (j, i)) p.set_raw_image_offset((xmin, ymin)) p.set_image_size((487, 195)) p.set_trusted_range((-1, 1000000)) p.set_pixel_size((0.172, 0.172)) p.set_local_frame( fast.elems, slow.elems, origin.elems) p.set_thickness(thickness) p.set_material('Si') p.set_mu(mu) p.set_px_mm_strategy(px_mm) p.set_raw_image_offset((xmin,ymin)) self.coords[p.get_name()] = (xmin,ymin,xmax,ymax) return detector
def _detector(self): """Detector model, allowing for small offsets in the positions of 60 detector modules""" distance = float( self._cif_header_dictionary["Detector_distance"].split()[0]) beam_xy = (self._cif_header_dictionary["Beam_xy"].replace( "(", "").replace(")", "").replace(",", "").split()[:2]) beam_x, beam_y = map(float, beam_xy) wavelength = float( self._cif_header_dictionary["Wavelength"].split()[0]) pixel_xy = (self._cif_header_dictionary["Pixel_size"].replace( "m", "").replace("x", "").split()) pixel_x, pixel_y = map(float, pixel_xy) thickness = float( self._cif_header_dictionary["Silicon"].split()[2]) * 1000.0 nx = int( self._cif_header_dictionary["X-Binary-Size-Fastest-Dimension"]) ny = int(self._cif_header_dictionary["X-Binary-Size-Second-Dimension"]) overload = int(self._cif_header_dictionary["Count_cutoff"].split()[0]) underload = -1 # take into consideration here the thickness of the sensor also the # wavelength of the radiation (which we have in the same file...) from cctbx.eltbx import attenuation_coefficient table = attenuation_coefficient.get_table("Si") mu = table.mu_at_angstrom(wavelength) / 10.0 t0 = thickness # FIXME would also be very nice to be able to take into account the # misalignment of the individual modules given the calibration... # single detector or multi-module detector pixel_x *= 1000.0 pixel_y *= 1000.0 distance *= 1000.0 if not self._multi_panel: detector = self._detector_factory.simple( "PAD", distance, (beam_x * pixel_x, beam_y * pixel_y), "+x", "-y", (pixel_x, pixel_y), (nx, ny), (underload, overload), [], ParallaxCorrectedPxMmStrategy(mu, t0), ) for f0, f1, s0, s1 in determine_pilatus_mask(detector): detector[0].add_mask(f0 - 1, s0 - 1, f1, s1) detector[0].set_thickness(thickness) detector[0].set_material("Si") detector[0].set_mu(mu) return detector # got to here means 60-panel version from dxtbx.model import Detector from scitbx import matrix d = Detector() beam_centre = matrix.col((beam_x * pixel_x, beam_y * pixel_y, 0)) fast = matrix.col((1.0, 0.0, 0.0)) slow = matrix.col((0.0, -1.0, 0.0)) s0 = matrix.col((0, 0, -1)) origin = (distance * s0) - (fast * beam_centre[0]) - (slow * beam_centre[1]) root = d.hierarchy() root.set_local_frame(fast.elems, slow.elems, origin.elems) xmins = [0, 494, 988, 1482, 1976] xmaxes = [487, 981, 1475, 1969, 2463] ymins = [ 0, 212, 424, 636, 848, 1060, 1272, 1484, 1696, 1908, 2120, 2332 ] ymaxes = [ 195, 407, 619, 831, 1043, 1255, 1467, 1679, 1891, 2103, 2315, 2527 ] self.coords = {} fast = matrix.col((1.0, 0.0, 0.0)) slow = matrix.col((0.0, 1.0, 0.0)) panel_idx = 0 for ymin, ymax in zip(ymins, ymaxes): for xmin, xmax in zip(xmins, xmaxes): xmin_mm = xmin * pixel_x ymin_mm = ymin * pixel_y origin_panel = fast * xmin_mm + slow * ymin_mm panel_name = "Panel%d" % panel_idx panel_idx += 1 p = root.add_panel() p.set_type("SENSOR_PAD") p.set_px_mm_strategy(ParallaxCorrectedPxMmStrategy(mu, t0)) p.set_name(panel_name) p.set_image_size((xmax - xmin, ymax - ymin)) p.set_trusted_range((underload, overload)) p.set_pixel_size((pixel_x, pixel_y)) p.set_thickness(thickness) p.set_material("Si") p.set_mu(mu) p.set_local_frame(fast.elems, slow.elems, origin_panel.elems) p.set_raw_image_offset((xmin, ymin)) self.coords[panel_name] = (xmin, ymin, xmax, ymax) return d
def _detector(self): '''Detector model, allowing for small offsets in the positions of 60 detector modules''' # Module positional offsets in x, y, in pixels - for the moment ignoring the # rotational offsets as these are not well defined. To be honest these # positional offsets are also not well defined as I do not know how they # should be applied... x = { (0, 0): -0.477546, (0, 1): 0.130578, (0, 2): 0.045041, (0, 3): -0.439872, (0, 4): -0.382077, (1, 0): 0.087405, (1, 1): 0.249597, (1, 2): 0.184265, (1, 3): 0.158342, (1, 4): 0.025225, (2, 0): -0.179892, (2, 1): -0.010974, (2, 2): -0.139207, (2, 3): 0.282851, (2, 4): -0.442219, (3, 0): -0.185027, (3, 1): 0.218601, (3, 2): 0.092585, (3, 3): 0.35862, (3, 4): -0.29161, (4, 0): 0.145368, (4, 1): 0.609289, (4, 2): 0.396265, (4, 3): 0.41625, (4, 4): 0.07152, (5, 0): 0.247142, (5, 1): 0.046563, (5, 2): 0.248714, (5, 3): -0.044628, (5, 4): -0.391509, (6, 0): 0.516643, (6, 1): 0.358453, (6, 2): 0.069219, (6, 3): 0.095861, (6, 4): -0.167403, (7, 0): -0.381352, (7, 1): -0.35338, (7, 2): 0.348656, (7, 3): 0.024543, (7, 4): 0.328706, (8, 0): 0.150886, (8, 1): 0.244987, (8, 2): -0.102911, (8, 3): 0.16633, (8, 4): 0.386622, (9, 0): 0.037924, (9, 1): 0.314392, (9, 2): 0.238818, (9, 3): 0.815028, (9, 4): -0.048818, (10, 0): -0.670524, (10, 1): -0.304119, (10, 2): 0.252284, (10, 3): -0.05485, (10, 4): -0.355264, (11, 0): -0.404947, (11, 1): -0.020622, (11, 2): 0.648473, (11, 3): -0.277175, (11, 4): -0.711951 } y = { (0, 0): -0.494797, (0, 1): -0.212976, (0, 2): 0.085351, (0, 3): 0.35494, (0, 4): 0.571189, (1, 0): -0.421708, (1, 1): 0.061914, (1, 2): 0.238996, (1, 3): 0.146692, (1, 4): 0.407145, (2, 0): -0.313212, (2, 1): -0.225025, (2, 2): 0.031613, (2, 3): -0.047839, (2, 4): 0.42716, (3, 0): -0.361193, (3, 1): 0.057663, (3, 2): 0.022357, (3, 3): 0.062717, (3, 4): 0.150611, (4, 0): 0.035511, (4, 1): -0.271567, (4, 2): 0.007761, (4, 3): -0.124021, (4, 4): 0.093017, (5, 0): -0.238897, (5, 1): -0.179724, (5, 2): -0.113608, (5, 3): 0.017841, (5, 4): -0.012933, (6, 0): -0.166337, (6, 1): -0.272922, (6, 2): -0.194665, (6, 3): -0.058535, (6, 4): -0.405404, (7, 0): -0.318824, (7, 1): -0.311276, (7, 2): -0.205223, (7, 3): -0.292664, (7, 4): -0.474762, (8, 0): -0.039504, (8, 1): -0.239887, (8, 2): -0.343485, (8, 3): -0.459429, (8, 4): -0.426901, (9, 0): -0.187805, (9, 1): 0.282727, (9, 2): -0.601164, (9, 3): -0.467605, (9, 4): -0.589271, (10, 0): 0.028311, (10, 1): -0.391571, (10, 2): -0.463112, (10, 3): -0.358092, (10, 4): -0.285396, (11, 0): 0.01863, (11, 1): -0.380099, (11, 2): -0.234953, (11, 3): -0.593992, (11, 4): -0.801247 } distance = float( self._cif_header_dictionary['Detector_distance'].split()[0]) beam_xy = self._cif_header_dictionary['Beam_xy'].replace( '(', '').replace(')', '').replace(',', '').split()[:2] beam_x, beam_y = map(float, beam_xy) wavelength = float( self._cif_header_dictionary['Wavelength'].split()[0]) pixel_xy = self._cif_header_dictionary['Pixel_size'].replace( 'm', '').replace('x', '').split() pixel_x, pixel_y = map(float, pixel_xy) thickness = float( self._cif_header_dictionary['Silicon'].split()[2]) * 1000.0 nx = int( self._cif_header_dictionary['X-Binary-Size-Fastest-Dimension']) ny = int( self._cif_header_dictionary['X-Binary-Size-Second-Dimension']) overload = int( self._cif_header_dictionary['Count_cutoff'].split()[0]) underload = -1 # take into consideration here the thickness of the sensor also the # wavelength of the radiation (which we have in the same file...) from cctbx.eltbx import attenuation_coefficient table = attenuation_coefficient.get_table("Si") mu = table.mu_at_angstrom(wavelength) / 10.0 t0 = thickness # FIXME would also be very nice to be able to take into account the # misalignment of the individual modules given the calibration... # single detector or multi-module detector pixel_x *= 1000.0 pixel_y *= 1000.0 distance *= 1000.0 if not self._multi_panel: detector = self._detector_factory.simple( 'PAD', distance, (beam_x * pixel_x, beam_y * pixel_y), '+x', '-y', (pixel_x, pixel_y), (nx, ny), (underload, overload), [], ParallaxCorrectedPxMmStrategy(mu, t0)) for f0, s0, f1, s1 in determine_pilatus_mask(detector): detector[0].add_mask(f0, s0, f1, s1) detector[0].set_thickness(thickness) detector[0].set_material('Si') detector[0].set_mu(mu) return detector # got to here means 60-panel version from dxtbx.model import Detector from scitbx import matrix d = Detector() beam_centre = matrix.col((beam_x * pixel_x, beam_y * pixel_y, 0)) fast = matrix.col((1.0, 0.0, 0.0)) slow = matrix.col((0.0,-1.0, 0.0)) s0 = matrix.col((0, 0, -1)) origin = (distance * s0) - (fast * beam_centre[0]) - \ (slow * beam_centre[1]) root = d.hierarchy() root.set_local_frame( fast.elems, slow.elems, origin.elems) xmins = [0, 494, 988, 1482, 1976] xmaxes = [487, 981, 1475, 1969, 2463] ymins = [0, 212, 424, 636, 848, 1060, 1272, 1484, 1696, 1908, 2120, 2332] ymaxes = [195, 407, 619, 831, 1043, 1255, 1467, 1679, 1891, 2103, 2315, 2527] self.coords = {} fast = matrix.col((1.0, 0.0, 0.0)) slow = matrix.col((0.0, 1.0, 0.0)) panel_idx = 0 for ymin, ymax in zip(ymins, ymaxes): for xmin, xmax in zip(xmins, xmaxes): xmin_mm = xmin * pixel_x ymin_mm = ymin * pixel_y origin_panel = fast * xmin_mm + slow * ymin_mm panel_name = "Panel%d" % panel_idx panel_idx += 1 p = root.add_panel() p.set_type("SENSOR_PAD") p.set_px_mm_strategy(ParallaxCorrectedPxMmStrategy(mu, t0)) p.set_name(panel_name) p.set_image_size((xmax-xmin, ymax-ymin)) p.set_trusted_range((underload, overload)) p.set_pixel_size((pixel_x,pixel_y)) p.set_thickness(thickness) p.set_material('Si') p.set_mu(mu) p.set_local_frame( fast.elems, slow.elems, origin_panel.elems) p.set_raw_image_offset((xmin, ymin)) self.coords[panel_name] = (xmin,ymin,xmax,ymax) return d