def _detector(self): '''Return a working detector instance.''' if self._panel_origin is not None: from dxtbx.model.detector import HierarchicalDetector detector = HierarchicalDetector() 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 = detector.add_panel() root.add_panel(p) 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): '''The _detector() function returns a model for a CSPAD detector as used at LCLS's CXI and XPP endstations. It converts the metrology information in the pure Python object extracted from the image pickle to DXTBX-style transformation vectors. Only ASIC:s are considered, since DXTBX metrology is not concerned with hierarchies. Merged from xfel.cftbx.detector.cspad_detector.readHeader() and xfel.cftbx.detector.metrology.metrology_as_dxtbx_vectors(). ''' from dxtbx.model import SimplePxMmStrategy from dxtbx.model.detector import HierarchicalDetector from scitbx.matrix import col # XXX Introduces dependency on cctbx.xfel! Should probably be # merged into the code here! from xfel.cftbx.detector.metrology import \ _transform, get_projection_matrix # Apply the detector distance to the translation of the root # detector object. d = self._metrology_params.detector Tb_d = _transform( col(d.orientation).normalize(), col(d.translation) + col((0, 0, -self._metrology_params.distance * 1e-3)))[1] self._raw_data = [] detector = HierarchicalDetector() for p in d.panel: Tb_p = Tb_d * _transform( col(p.orientation).normalize(), col(p.translation))[1] for s in p.sensor: Tb_s = Tb_p * _transform( col(s.orientation).normalize(), col(s.translation))[1] for a in s.asic: Tb_a = Tb_s * _transform( col(a.orientation).normalize(), col(a.translation))[1] Pb = get_projection_matrix(a.pixel_size, a.dimension)[1] # The DXTBX-style metrology description consists of three # vectors for each ASIC. The origin vector locates the # (0, 0)-pixel in the laboratory frame in units of mm. # The second and third vectors give the directions to the # pixels immediately next to (0, 0) in the fast and slow # directions, respectively, in arbitrary units. origin = Tb_a * Pb * col((0, 0, 1)) fast = Tb_a * Pb * col((0, a.dimension[0], 1)) - origin slow = Tb_a * Pb * col((a.dimension[1], 0, 1)) - origin # Convert vector units from meter to millimeter. The # default, SimplePxMmStrategy applies here. XXX Due to # dark subtraction, a valid pixel intensity may be # negative, and this is currently not reflected by # trusted_range. key = (d.serial, p.serial, s.serial, a.serial) panel = detector.add_panel() panel.set_type("PAD") panel.set_name('%d:%d:%d:%d' % key) panel.set_local_frame( [t * 1e3 for t in fast.elems[0:3]], [t * 1e3 for t in slow.elems[0:3]], [t * 1e3 for t in origin.elems[0:3]]) panel.set_pixel_size([t * 1e3 for t in a.pixel_size]) panel.set_image_size(a.dimension) panel.set_trusted_range((0, a.saturation)) self._raw_data.append(self._tiles[key]) return detector
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 single_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(table.mu_at_angstrom(wavelength)) return detector # got to here means 60-panel version from dxtbx.model.detector import HierarchicalDetector from scitbx import matrix d = HierarchicalDetector() 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 = d.add_panel() 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_local_frame(fast.elems, slow.elems, origin_panel.elems) self.coords[panel_name] = (xmin, ymin, xmax, ymax) root.add_panel(p) 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.detector import HierarchicalDetector 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 detector = HierarchicalDetector() root = detector.hierarchy() root.set_frame( (1, 0, 0), (0, 1, 0), (0, 0, - (250 + distance))) 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) for j in range(24): 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) # 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 if group_rows: origin = 250.0 * normal - off_x * fast - 16.8 * slow + 250 * z + \ beam_shift_y * y p = detector.add_panel() # OBS! you need to set the panel to a root before set local frame... root.add_panel(p) p.set_name('row-%02d' % j) 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, origin.elems) p.set_px_mm_strategy(px_mm) else: row_origin = 250.0 * normal - off_x * fast - 16.8 * slow + 250 * z + \ beam_shift_y * y for i in range(5): p = detector.add_panel() origin = row_origin + i * (487+7) * 0.172 * fast # OBS! you need to set the panel to a root before set local frame... root.add_panel(p) p.set_name('row-%02d' % j) 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_px_mm_strategy(px_mm) return detector
def _detector(self, index=None): from dxtbx.model.detector import HierarchicalDetector from scitbx import matrix import math # Ignore this for now. # TODO: must consider when a new MPCCD with 300um thickness # is released. self.wavelength = 1.77 # A, this must be got from _beam # thickness = 60 # um # # 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) detector = HierarchicalDetector() root = detector.hierarchy() root.set_frame( (1, 0, 0), (0, 1, 0), (0, 0, - self.distance)) if self.RECONST_MODE: return self._detector_factory.simple( sensor = 'PAD', distance = self.distance, beam_centre = (self.RECONST_SIZE * self.pixel_size / 2, self.RECONST_SIZE * self.pixel_size / 2), fast_direction = '+x', slow_direction = '-y', pixel_size = (self.pixel_size, self.pixel_size), image_size = (self.RECONST_SIZE, self.RECONST_SIZE), trusted_range = (-1, 1000000), mask = []) # a list of dead rectangles for i in range(8): angle = math.pi * self.panel_rotations[i] / 180.0 fast = matrix.col((math.cos(angle), math.sin(angle), 0)) slow = matrix.col((-math.sin(angle), math.cos(angle), 0)) normal = fast.cross(slow) origin = matrix.col((-self.panel_origins[i][0], self.panel_origins[i][1], self.panel_origins[i][2])) / 1000.0 p = detector.add_panel() # OBS! you need to set the panel to a root before set local frame... root.add_panel(p) p.set_name('panel-%01d' % i) p.set_image_size((512, 1024)) p.set_trusted_range((-1, 1000000)) p.set_pixel_size((self.pixel_size, self.pixel_size)) p.set_local_frame( fast.elems, slow.elems, origin.elems) xmin, ymin = 0, i * 1024 p.set_raw_image_offset((xmin, ymin)) # p.set_px_mm_strategy(px_mm) return detector