def test_px_mm_strategy_equality():
    simple = SimplePxMmStrategy()
    assert simple == SimplePxMmStrategy()

    parallax_corrected = ParallaxCorrectedPxMmStrategy(1, 1)
    assert parallax_corrected == ParallaxCorrectedPxMmStrategy(1, 1)
    assert parallax_corrected != ParallaxCorrectedPxMmStrategy(1, 2)
    assert parallax_corrected != ParallaxCorrectedPxMmStrategy(2, 1)
    assert parallax_corrected != simple

    dx = flex.double(flex.grid(10, 10), 1)
    dy = flex.double(flex.grid(10, 10), 1)

    offset = OffsetPxMmStrategy(dx, dy)
    assert offset == OffsetPxMmStrategy(dx, dy)
    assert offset != simple
    assert offset != parallax_corrected

    offset_parallax_corrected = OffsetParallaxCorrectedPxMmStrategy(
        1, 1, dx, dy)
    assert offset_parallax_corrected == OffsetParallaxCorrectedPxMmStrategy(
        1, 1, dx, dy)
    assert offset_parallax_corrected != OffsetParallaxCorrectedPxMmStrategy(
        1, 2, dx, dy)
    assert offset_parallax_corrected != OffsetParallaxCorrectedPxMmStrategy(
        2, 1, dx, dy)
    assert offset_parallax_corrected != simple
    assert offset_parallax_corrected != parallax_corrected
    assert offset_parallax_corrected != offset
Example #2
0
def test_panel_equality():
    panel = create_detector(offset=0)[0]
    panel2 = copy.deepcopy(panel)
    assert panel == panel2

    panel2.set_px_mm_strategy(ParallaxCorrectedPxMmStrategy(1, 1))
    assert panel != panel2

    panel.set_px_mm_strategy(ParallaxCorrectedPxMmStrategy(1, 1))
    assert panel == panel2
def test_correction_on_random_coordinates(model):
    convert = ParallaxCorrectedPxMmStrategy(model["mu"], model["t0"])
    for i in range(10000):
        xy = matrix.col((random.uniform(-1000, 1000), random.uniform(-1000, 1000)))

        # Do the forward and reverse corrections
        xy_corr_gold = matrix.col(correct_gold(model, xy))
        xy_corr = matrix.col(convert.to_pixel(model["detector"], xy))
        xy_corr_inv = matrix.col(convert.to_millimeter(model["detector"], xy_corr))

        # Check the values
        assert abs(xy_corr_gold - xy_corr) < 1e-7
        assert abs(xy_corr_inv - xy) < 1e-3
Example #4
0
    def _detector(self):
        """Partly dummy detector"""
        from scitbx import matrix

        # Get the detector geometry
        entry = self._h5_handle["entry"]
        instrument = entry["instrument"]
        detector = instrument["detector"]

        # Initialise detector frame - origin at 0,0,0
        fast = matrix.col((1.0, 0.0, 0.0))
        slow = matrix.col((0.0, 1.0, 0.0))
        orig = matrix.col((0.0, 0.0, 0.0))

        # Get the pixel and image size
        pixel_size = (
            1.0e-3 * detector["x_pixel_size"].value,
            1.0e-3 * detector["y_pixel_size"].value,
        )
        layout = detector["layout"].value[0].split("X")
        image_size = int(layout[0]), int(layout[1])
        trusted_range = (-1, detector["saturation_value"][0])
        thickness = float(detector["sensor_thickness"].value) / 1000.0
        material = str(detector["sensor_material"].value[0])

        # Make the detector
        detector = self._detector_factory.make_detector(
            "PAD",
            fast,
            slow,
            orig,
            pixel_size,
            image_size,
            trusted_range,
            name="Panel",
            thickness=thickness,
            material=material,
        )

        # At the moment, beam is a dummy object because wavelength is not set in
        # the header. Therefore, the px<-->mm strategy will generally be
        # incorrect. Set it anyway, to override later.
        beam = self._beam()
        wavelength = beam.get_wavelength()

        from cctbx.eltbx import attenuation_coefficient
        from dxtbx.model import ParallaxCorrectedPxMmStrategy

        # this will fail for undefined composite materials
        table = attenuation_coefficient.get_table(material)

        # mu_at_angstrom returns cm^-1, but need mu in mm^-1
        mu = table.mu_at_angstrom(wavelength) / 10.0

        for panel in detector:
            panel.set_mu(mu)
            panel.set_px_mm_strategy(
                ParallaxCorrectedPxMmStrategy(mu, thickness))

        return detector
Example #5
0
    def _detector(self):
        """Return a working detector instance, with added mask regions."""

        detector = self._detector_factory.imgCIF_H(self._get_cbf_handle(), "PAD")

        for f0, f1, s0, s1 in determine_pilatus_mask(detector):
            detector[0].add_mask(f0 - 1, s0 - 1, f1, s1)

        m = re.search(
            r"^#\s*(\S+)\ssensor, thickness\s*([0-9.]+)\s*m\s*$",
            self._cif_header,
            re.MULTILINE,
        )
        if m:
            # header gives thickness in metres, we store mm
            thickness = float(m.group(2)) * 1000
            material = m.group(1)

            if material == "Silicon":
                material = "Si"

            for panel in detector:
                panel.set_thickness(thickness)
                panel.set_material(material)

            try:
                # a header only CBF file will not have a beam object
                beam = self._beam()

            except Exception:
                beam = None

            if beam:
                # attenuation coefficient depends on the beam wavelength
                wavelength = beam.get_wavelength()

                # this will fail for undefined composite materials
                table = attenuation_coefficient.get_table(material)
                # mu_at_angstrom returns cm^-1
                mu = table.mu_at_angstrom(wavelength) / 10.0

                for panel in detector:
                    panel.set_px_mm_strategy(
                        ParallaxCorrectedPxMmStrategy(mu, thickness)
                    )
                    panel.set_mu(mu)

        m = re.search(r"^#\s*Detector:\s+(.*?)\s*$", self._cif_header, re.MULTILINE)
        if m and m.group(1):
            panel.set_identifier(m.group(1).encode())

        size = detector[0].get_image_size()
        if size == (2463, 2527):
            self.vendortype = "Pilatus-6M"
        elif size == (1475, 1679):
            self.vendortype = "Pilatus-2M"
        elif size == (487, 619):
            self.vendortype = "Pilatus-300K"

        return detector
Example #6
0
        def get_values(invert_y):

            from dxtbx.model.beam import beam_factory
            beam = beam_factory.simple(wavelength=1)

            if invert_y:
                y_direction = "-y"
            else:
                y_direction = "+y"

            from dxtbx.model.detector import detector_factory
            detector = detector_factory.simple(
                sensor=detector_factory.sensor("PAD"),
                distance=100,
                beam_centre=[50, 50],
                fast_direction="+x",
                slow_direction=y_direction,
                pixel_size=[0.1, 0.1],
                image_size=[1000, 1000])

            from dxtbx.model import ParallaxCorrectedPxMmStrategy
            from cctbx.eltbx import attenuation_coefficient
            wavelength = beam.get_wavelength()
            thickness = 0.5
            table = attenuation_coefficient.get_table("Si")
            mu = table.mu_at_angstrom(wavelength) / 10.0
            t0 = thickness

            for panel in detector:
                panel.set_px_mm_strategy(ParallaxCorrectedPxMmStrategy(mu, t0))
            v1 = detector[0].pixel_to_millimeter((0, 0))
            v2 = detector[0].pixel_to_millimeter((1000, 1000))

            return v1, v2
Example #7
0
def test_parallax_correction():
    # Attenuation length
    table = attenuation_coefficient.get_table("Si")
    mu = table.mu_at_angstrom(1) / 10.0
    t0 = 0.320

    # Create the detector
    detector = Detector(
        Panel(
            "",  # Type
            "",  # Name
            (10, 0, 0),  # Fast axis
            (0, 10, 0),  # Slow axis
            (0, 0, 200),  # Origin
            (0.172, 0.172),  # Pixel size
            (512, 512),  # Image size
            (0, 1000),  # Trusted range
            0.0,  # Thickness
            "",  # Material
            ParallaxCorrectedPxMmStrategy(mu, t0),
        )
    )
    for i in range(10000):
        mm = (random.uniform(-1000, 1000), random.uniform(-1000, 1000))
        px = detector[0].millimeter_to_pixel(mm)
        mm2 = detector[0].pixel_to_millimeter(px)
        assert abs(matrix.col(mm) - matrix.col(mm2)) < 1e-3
Example #8
0
    def _detector(self):
        d = FormatCBFMultiTileHierarchyStill._detector(self)

        try:
            # a header only CBF file will not have a beam object
            beam = self._beam()
        except Exception as e:
            if "CBF_NOTFOUND" not in str(e):
                raise e
            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
Example #9
0
    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.'''

        distance = float(
            self._cif_header_dictionary['Detector_distance'].split()[0])

        beam_xy = self._cif_header_dictionary['Beam_xy'].replace(
            '(', '').replace(')', '').replace(',', '').split()[:2]

        wavelength = float(
            self._cif_header_dictionary['Wavelength'].split()[0])

        beam_x, beam_y = map(float, beam_xy)

        pixel_xy = self._cif_header_dictionary['Pixel_size'].replace(
            'm', '').replace('x', '').split()

        pixel_x, pixel_y = map(float, pixel_xy)

        if 'Silicon' in self._cif_header_dictionary:
            thickness = float(
                self._cif_header_dictionary['Silicon'].split()[2]) * 1000.0
            material = 'Si'
        elif 'CdTe' in self._cif_header_dictionary:
            thickness = float(
                self._cif_header_dictionary['CdTe'].split()[2]) * 1000.0
            material = 'CdTe'
        else:
            thickness = 0.450
            material = 'Si'

        nx = int(
            self._cif_header_dictionary['X-Binary-Size-Fastest-Dimension'])
        ny = int(self._cif_header_dictionary['X-Binary-Size-Second-Dimension'])

        overload = dxtbx_overload_scale * 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(material)
        mu = table.mu_at_angstrom(wavelength) / 10.0
        t0 = thickness

        detector = self._detector_factory.simple(
            'PAD', distance * 1000.0,
            (beam_x * pixel_x * 1000.0, beam_y * pixel_y * 1000.0), '+x', '-y',
            (1000 * pixel_x, 1000 * pixel_y), (nx, ny), (underload, overload),
            [], ParallaxCorrectedPxMmStrategy(mu, t0))

        detector[0].set_thickness(thickness)
        detector[0].set_material(material)
        detector[0].set_mu(mu)

        return detector
Example #10
0
    def _detector(self):
        """ Create an Eiger detector profile (taken from FormatCBFMiniEiger) """
        configuration = self.header["configuration"]
        info = self.header["info"]

        distance = configuration["detector_distance"]
        wavelength = configuration["wavelength"]
        beam_x = configuration["beam_center_x"]
        beam_y = configuration["beam_center_y"]

        pixel_x = configuration["x_pixel_size"]
        pixel_y = configuration["y_pixel_size"]

        material = configuration["sensor_material"]
        thickness = configuration["sensor_thickness"] * 1000

        nx = configuration["x_pixels_in_detector"]
        ny = configuration["y_pixels_in_detector"]

        if "count_rate_correction_count_cutoff" in configuration:
            overload = configuration["count_rate_correction_count_cutoff"]
        else:
            # hard-code if missing from Eiger stream header
            overload = 4001400
        underload = -1

        try:
            identifier = configuration["description"]
        except KeyError:
            identifier = "Unknown Eiger"

        table = attenuation_coefficient.get_table(material)
        mu = table.mu_at_angstrom(wavelength) / 10.0
        t0 = thickness

        detector = self._detector_factory.simple(
            sensor="PAD",
            distance=distance * 1000.0,
            beam_centre=(beam_x * pixel_x * 1000.0, beam_y * pixel_y * 1000.0),
            fast_direction="+x",
            slow_direction="-y",
            pixel_size=(1000 * pixel_x, 1000 * pixel_y),
            image_size=(nx, ny),
            trusted_range=(underload, overload),
            mask=[],
            px_mm=ParallaxCorrectedPxMmStrategy(mu, t0),
            mu=mu,
        )

        for f0, f1, s0, s1 in determine_eiger_mask(detector):
            detector[0].add_mask(f0 - 1, s0 - 1, f1, s1)

        for panel in detector:
            panel.set_thickness(thickness)
            panel.set_material(material)
            panel.set_identifier(identifier)
            panel.set_mu(mu)

        return detector
Example #11
0
    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."""

        distance = float(
            self._cif_header_dictionary["Detector_distance"].split()[0])

        beam_xy = (self._cif_header_dictionary["Beam_xy"].replace(
            "(", "").replace(")", "").replace(",", "").split()[:2])

        wavelength = float(
            self._cif_header_dictionary["Wavelength"].split()[0])

        beam_x, beam_y = map(float, beam_xy)

        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 information...

        detector = self._detector_factory.simple(
            "PAD",
            distance * 1000.0,
            (beam_x * pixel_x * 1000.0, beam_y * pixel_y * 1000.0),
            "+x",
            "-y",
            (1000 * pixel_x, 1000 * 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)
    """
        return detector
Example #12
0
    def _detector(self, index=None):
        from dxtbx.model.detector import Detector
        from scitbx import matrix
        import math

        wavelength = self.get_beam(index).get_wavelength()

        from dxtbx.model import ParallaxCorrectedPxMmStrategy
        from cctbx.eltbx import attenuation_coefficient

        table = attenuation_coefficient.get_table("Si")
        mu = table.mu_at_angstrom(wavelength) / 10.0
        px_mm = ParallaxCorrectedPxMmStrategy(mu, self.thickness)

        if self.RECONST_MODE:
            return self._detector_factory.simple(
                sensor="PAD",
                distance=self.distance,
                beam_centre=(
                    self.RECONST_SIZE / 2 * self.PIXEL_SIZE,
                    self.RECONST_SIZE / 2 * self.PIXEL_SIZE,
                ),
                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, 65535),
                mask=[],
            )  # TODO: add gaps

        detector = Detector()
        root = detector.hierarchy()
        root.set_frame((-1, 0, 0), (0, 1, 0), (0, 0, -self.distance))

        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 = root.add_panel()
            p.set_type("SENSOR_PAD")
            p.set_name("Panel%d" % i)
            p.set_image_size((512, 1024))
            p.set_trusted_range((-1, 65535))
            p.set_pixel_size((self.PIXEL_SIZE, self.PIXEL_SIZE))
            p.set_thickness(self.thickness)
            p.set_local_frame(fast.elems, slow.elems, origin.elems)
            p.set_px_mm_strategy(px_mm)
            p.set_gain(10)

        return detector
    def _detector(self):
        '''Return a working detector instance, with added mask regions.'''

        detector = self._detector_factory.imgCIF_H(self._get_cbf_handle(),
                                                   'PAD')

        for f0, s0, f1, s1 in determine_pilatus_mask(detector):
            detector[0].add_mask(f0, s0, f1, s1)

        import re
        m = re.search('^#\s*(\S+)\ssensor, thickness\s*([0-9.]+)\s*m\s*$', \
                      self._cif_header, re.MULTILINE)
        if m:
            # header gives thickness in metres, we store mm
            thickness = float(m.group(2)) * 1000
            material = m.group(1)

            if material == 'Silicon':
                material = 'Si'

            for panel in detector:
                panel.set_thickness(thickness)
                panel.set_material(material)

            try:
                # a header only CBF file will not have a beam object
                beam = self._beam()

            except Exception:
                beam = None

            if beam:
                # attenuation coefficient depends on the beam wavelength
                wavelength = beam.get_wavelength()

                from cctbx.eltbx import attenuation_coefficient
                from dxtbx.model import ParallaxCorrectedPxMmStrategy
                # this will fail for undefined composite materials
                table = attenuation_coefficient.get_table(material)
                # mu_at_angstrom returns cm^-1
                mu = table.mu_at_angstrom(wavelength) / 10.0

                for panel in detector:
                    panel.set_px_mm_strategy(
                        ParallaxCorrectedPxMmStrategy(mu, thickness))
                    panel.set_mu(mu)

        m = re.search('^#\s*Detector:\s+(.*?)\s*$', \
                      self._cif_header, re.MULTILINE)
        if m and m.group(1):
            panel.set_identifier(m.group(1))

        return detector
Example #14
0
  def _detector(self):
    distance = float(
        self._cif_header_dictionary['Detector_distance'].split()[0])

    beam_xy = self._cif_header_dictionary['Beam_xy'].replace(
        '(', '').replace(')', '').replace(',', '').split()[:2]

    wavelength = float(
        self._cif_header_dictionary['Wavelength'].split()[0])

    beam_x, beam_y = map(float, beam_xy)

    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

    from cctbx.eltbx import attenuation_coefficient
    table = attenuation_coefficient.get_table("Si")
    mu = table.mu_at_angstrom(wavelength) / 10.0
    t0 = thickness

    detector = self._detector_factory.simple(
        'PAD', distance * 1000.0, (beam_x * pixel_x * 1000.0,
                                   beam_y * pixel_y * 1000.0), '+x', '-y',
        (1000 * pixel_x, 1000 * pixel_y),
        (nx, ny), (underload, overload), [],
        ParallaxCorrectedPxMmStrategy(mu, t0))

    for f0, s0, f1, s1 in [(0, 513, 1030, 550)]:
      detector[0].add_mask(f0, s0, f1, s1)

    return detector
Example #15
0
class FormatCBFCspad(FormatCBFMultiTileHierarchy, FormatStill):
    '''An image reading class CSPAD CBF files'''
    @staticmethod
    def understand(image_file):
        '''Check to see if this looks like an CSPD CBF format image, i.e. we can
    make sense of it.'''

        cbf_handle = pycbf.cbf_handle_struct()
        cbf_handle.read_widefile(image_file, pycbf.MSG_DIGEST)

        cbf_handle.find_category("diffrn_detector")
        if cbf_handle.count_rows() > 1:
            return False  # support 1 detector per file for now

        cbf_handle.find_column("type")

        return cbf_handle.get_value() == "CS PAD"

    def _detector(self):
        d = FormatCBFMultiTileHierarchy._detector(self)

        try:
            # a header only CBF file will not have a beam object
            beam = self._beam()
        except Exception, e:
            if "CBF_NOTFOUND" not in str(e): raise e
            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
        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
        t0 = thickness

        for panel in d:
            panel.set_px_mm_strategy(ParallaxCorrectedPxMmStrategy(mu, t0))
        return d
Example #16
0
    def _detector(self):
        """Return a model for the detector, allowing for two-theta offsets
        and the detector position. This will be rather more complex..."""

        detector_name = self._header_dictionary["DETECTOR_NAMES"].split()[0].strip()

        detector_axes = self.get_detector_axes(detector_name)
        fast = matrix.col(tuple(detector_axes[:3]))
        slow = matrix.col(tuple(detector_axes[3:]))
        distortion = self.get_distortion(detector_name)

        # multiply through by the distortion to get the true detector fast, slow

        detector_fast, detector_slow = (
            distortion[0] * fast + distortion[1] * slow,
            distortion[2] * fast + distortion[3] * slow,
        )

        beam_pixels = self.get_beam_pixels(detector_name)
        pixel_size = self.get_pixel_size(detector_name)
        image_size = self.get_image_size(detector_name)

        detector_origin = -(
            beam_pixels[0] * pixel_size[0] * detector_fast
            + beam_pixels[1] * pixel_size[1] * detector_slow
        )

        gonio_axes = self.get_gonio_axes(detector_name)
        gonio_values = self.get_gonio_values(detector_name)
        gonio_units = self._header_dictionary["%sGONIO_UNITS" % detector_name].split()
        gonio_num_axes = int(
            self._header_dictionary["%sGONIO_NUM_VALUES" % detector_name]
        )

        rotations = []
        translations = []

        for j, unit in enumerate(gonio_units):
            axis = matrix.col(gonio_axes[3 * j : 3 * (j + 1)])
            if unit == "deg":
                rotations.append(
                    axis.axis_and_angle_as_r3_rotation_matrix(gonio_values[j], deg=True)
                )
                translations.append(matrix.col((0.0, 0.0, 0.0)))
            elif unit == "mm":
                rotations.append(
                    matrix.sqr((1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0))
                )
                translations.append(gonio_values[j] * axis)
            else:
                raise RuntimeError("unknown axis unit %s" % unit)

        rotations.reverse()
        translations.reverse()

        for j in range(gonio_num_axes):
            detector_fast = rotations[j] * detector_fast
            detector_slow = rotations[j] * detector_slow
            detector_origin = rotations[j] * detector_origin
            detector_origin = translations[j] + detector_origin

        overload = int(float(self._header_dictionary["SATURATED_VALUE"]))
        underload = -1

        # Unfortunately thickness and material are not stored in the header. Set
        # to sensible defaults.
        t0 = 0.450
        material = "Si"

        table = attenuation_coefficient.get_table(material)
        wavelength = float(self._header_dictionary["SCAN_WAVELENGTH"])
        mu = table.mu_at_angstrom(wavelength) / 10.0

        detector = self._detector_factory.complex(
            "PAD",
            detector_origin.elems,
            detector_fast.elems,
            detector_slow.elems,
            pixel_size,
            image_size,
            (underload, overload),
            px_mm=ParallaxCorrectedPxMmStrategy(mu, t0),
            mu=mu,
        )

        for panel in detector:
            panel.set_thickness(t0)
            panel.set_material(material)

        return detector
Example #17
0
from __future__ import division

import sys
from dxtbx.serialize import load
from dxtbx.model import ParallaxCorrectedPxMmStrategy, SimplePxMmStrategy
from scitbx.array_family import flex
from matplotlib import pylab
convert = ParallaxCorrectedPxMmStrategy(0.252500934883)
convert2 = SimplePxMmStrategy()

sweep = load.imageset(sys.argv[1])

detector = sweep.get_detector()

#print detector[0].pixel_to_millimeter((0, 1))

image_size = sweep[0].all()
image = flex.double(flex.grid(image_size))
for j in range(image_size[0]):
  for i in range(image_size[1]):
    mm1 = convert2.to_millimeter(detector[0], (i, j))
    px2 = convert.to_pixel(detector[0], mm1)
    image[j,i] = j - px2[1]


print flex.max(image), flex.min(image)

pylab.imshow(image.as_numpy_array())
pylab.show()
Example #18
0
    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
Example #19
0
    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
Example #20
0
def test_detector():
    from dxtbx.model import ParallaxCorrectedPxMmStrategy

    def create_detector(offset=0):
        # Create the detector
        detector = Detector(
            Panel(
                "",  # Type
                "Panel",  # Name
                (10, 0, 0),  # Fast axis
                (0, 10, 0),  # Slow axis
                (0 + offset, 0 + offset, 200 - offset),
                # Origin
                (0.172, 0.172),  # Pixel size
                (512, 512),  # Image size
                (0, 1000),  # Trusted range
                0.1,  # Thickness
                "Si",  # Material
                identifier="123"))  # Identifier
        return detector

    detector = create_detector()

    # Perform some tests
    tst_get_identifier(detector)
    tst_get_gain(detector)
    tst_set_mosflm_beam_centre(detector)
    tst_get_pixel_lab_coord(detector)
    tst_get_image_size_mm(detector)
    tst_is_value_in_trusted_range(detector)
    tst_is_coord_valid(detector)
    tst_pixel_to_millimeter_to_pixel(detector)
    tst_get_names(detector)
    tst_get_thickness(detector)
    tst_get_material(detector)
    tst_resolution(detector)
    tst_panel_mask()

    # Attenuation length
    from cctbx.eltbx import attenuation_coefficient
    table = attenuation_coefficient.get_table("Si")
    mu = table.mu_at_angstrom(1) / 10.0
    t0 = 0.320

    # Create another detector with different origin
    detector_moved = create_detector(offset=100)
    tst_detectors_are_different(detector, detector_moved)

    detector_moved_copy = create_detector(offset=100)
    tst_detectors_are_same(detector_moved, detector_moved_copy)

    # Create the detector
    detector = Detector(
        Panel(
            "",  # Type
            "",  # Name
            (10, 0, 0),  # Fast axis
            (0, 10, 0),  # Slow axis
            (0, 0, 200),  # Origin
            (0.172, 0.172),  # Pixel size
            (512, 512),  # Image size
            (0, 1000),  # Trusted range
            0.0,  # Thickness
            "",  # Material
            ParallaxCorrectedPxMmStrategy(mu, t0)))

    tst_parallax_correction(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 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
Example #22
0
 def correct_inv(self, xy):
     from dxtbx.model import ParallaxCorrectedPxMmStrategy
     convert = ParallaxCorrectedPxMmStrategy(self.mu, self.t0)
     return convert.to_millimeter(self.detector[0], xy)
Example #23
0
    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
Example #24
0
    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."""

        distance = float(self._cif_header_dictionary["Detector_distance"].split()[0])

        beam_xy = (
            self._cif_header_dictionary["Beam_xy"]
            .replace("(", "")
            .replace(")", "")
            .replace(",", "")
            .split()[:2]
        )

        wavelength = float(self._cif_header_dictionary["Wavelength"].split()[0])

        beam_x, beam_y = map(float, beam_xy)

        pixel_xy = (
            self._cif_header_dictionary["Pixel_size"]
            .replace("m", "")
            .replace("x", "")
            .split()
        )

        pixel_x, pixel_y = map(float, pixel_xy)

        if "Silicon" in self._cif_header_dictionary:
            thickness = (
                float(self._cif_header_dictionary["Silicon"].split()[2]) * 1000.0
            )
            material = "Si"
            sensor = "PAD"
        elif "CdTe" in self._cif_header_dictionary:
            thickness = float(self._cif_header_dictionary["CdTe"].split()[2]) * 1000.0
            material = "CdTe"
            sensor = "PAD"
        elif "CCD" in self._cif_header_dictionary:
            thickness = 0
            material = None
            sensor = "CCD"
        else:
            thickness = 0
            material = None
            sensor = None

        nx = int(self._cif_header_dictionary["X-Binary-Size-Fastest-Dimension"])
        ny = int(self._cif_header_dictionary["X-Binary-Size-Second-Dimension"])

        overload = dxtbx_overload_scale * int(
            self._cif_header_dictionary["Count_cutoff"].split()[0]
        )
        underload = -1

        if material is not None:
            # 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(material)
            mu = table.mu_at_angstrom(wavelength) / 10.0
            t0 = thickness
            px_mm = ParallaxCorrectedPxMmStrategy(mu, t0)
        else:
            px_mm = SimplePxMmStrategy()

        detector = self._detector_factory.simple(
            sensor,
            distance * 1000.0,
            (beam_x * pixel_x * 1000.0, beam_y * pixel_y * 1000.0),
            "+x",
            "-y",
            (1000 * pixel_x, 1000 * pixel_y),
            (nx, ny),
            (underload, overload),
            [],
            px_mm=px_mm,
        )

        if material is not None:
            detector[0].set_thickness(thickness)
            detector[0].set_material(material)
            detector[0].set_mu(mu)

        return detector
Example #25
0
    def _detector(self):
        '''Return a model for the detector, allowing for two-theta offsets
    and the detector position. This will be rather more complex...'''

        detector_name = self._header_dictionary['DETECTOR_NAMES'].split(
        )[0].strip()

        detector_axes = map(
            float, self._header_dictionary['%sDETECTOR_VECTORS' %
                                           detector_name].split())

        fast = matrix.col(tuple(detector_axes[:3]))
        slow = matrix.col(tuple(detector_axes[3:]))

        distortion = map(
            int, self._header_dictionary['%sSPATIAL_DISTORTION_VECTORS' %
                                         detector_name].split())

        # multiply through by the distortion to get the true detector fast, slow

        detector_fast, detector_slow = distortion[0] * fast + distortion[1] * slow, \
          distortion[2] * fast + distortion[3] * slow

        beam_pixels = map(
            float, self._header_dictionary['%sSPATIAL_DISTORTION_INFO' %
                                           detector_name].split()[:2])
        pixel_size = map(
            float, self._header_dictionary['%sSPATIAL_DISTORTION_INFO' %
                                           detector_name].split()[2:])
        image_size = map(
            int, self._header_dictionary['%sDETECTOR_DIMENSIONS' %
                                         detector_name].split())

        detector_origin = - (beam_pixels[0] * pixel_size[0] * detector_fast + \
                             beam_pixels[1] * pixel_size[1] * detector_slow)

        gonio_axes = map(
            float,
            self._header_dictionary['%sGONIO_VECTORS' % detector_name].split())
        gonio_values = map(
            float,
            self._header_dictionary['%sGONIO_VALUES' % detector_name].split())
        gonio_units = self._header_dictionary['%sGONIO_UNITS' %
                                              detector_name].split()
        gonio_num_axes = int(self._header_dictionary['%sGONIO_NUM_VALUES' %
                                                     detector_name])

        rotations = []
        translations = []

        for j, unit in enumerate(gonio_units):
            axis = matrix.col(gonio_axes[3 * j:3 * (j + 1)])
            if unit == 'deg':
                rotations.append(
                    axis.axis_and_angle_as_r3_rotation_matrix(gonio_values[j],
                                                              deg=True))
                translations.append(matrix.col((0.0, 0.0, 0.0)))
            elif unit == 'mm':
                rotations.append(
                    matrix.sqr((1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)))
                translations.append(gonio_values[j] * axis)
            else:
                raise RuntimeError('unknown axis unit %s' % unit)

        rotations.reverse()
        translations.reverse()

        for j in range(gonio_num_axes):
            detector_fast = rotations[j] * detector_fast
            detector_slow = rotations[j] * detector_slow
            detector_origin = rotations[j] * detector_origin
            detector_origin = translations[j] + detector_origin

        overload = int(float(self._header_dictionary['SATURATED_VALUE']))
        underload = -1

        # Unfortunately thickness and material are not stored in the header. Set
        # to sensible defaults.
        t0 = 0.450
        material = 'Si'
        from cctbx.eltbx import attenuation_coefficient
        table = attenuation_coefficient.get_table(material)
        wavelength = float(self._header_dictionary['SCAN_WAVELENGTH'])
        mu = table.mu_at_angstrom(wavelength) / 10.0

        detector = self._detector_factory.complex(
            'PAD',
            detector_origin.elems,
            detector_fast.elems,
            detector_slow.elems,
            pixel_size,
            image_size, (underload, overload),
            px_mm=ParallaxCorrectedPxMmStrategy(mu, t0),
            mu=mu)

        for panel in detector:
            panel.set_thickness(t0)
            panel.set_material(material)

        return detector
Example #26
0
    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
Example #27
0
    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
    def _detector(self):
        distance = float(
            self._cif_header_dictionary['Detector_distance'].split()[0])

        beam_xy = self._cif_header_dictionary['Beam_xy'].replace(
            '(', '').replace(')', '').replace(',', '').split()[:2]

        wavelength = float(
            self._cif_header_dictionary['Wavelength'].split()[0])

        beam_x, beam_y = map(float, beam_xy)

        pixel_xy = self._cif_header_dictionary['Pixel_size'].replace(
            'm', '').replace('x', '').split()

        pixel_x, pixel_y = map(float, pixel_xy)

        # extract sensor thickness, assume < 10mm; default to 450 microns unfound
        try:
            thickness = float(
                self._cif_header_dictionary['Silicon'].split()[-2]) * 1000.0
            material = 'Si'
            if thickness > 10:
                thickness = thickness / 1000.0
        except KeyError:
            thickness = 0.450
            material = 'Si'

        nx = int(
            self._cif_header_dictionary['X-Binary-Size-Fastest-Dimension'])
        ny = int(self._cif_header_dictionary['X-Binary-Size-Second-Dimension'])

        if 'Count_cutoff' in self._cif_header_dictionary:
            overload = int(
                self._cif_header_dictionary['Count_cutoff'].split()[0])
        else:
            # missing from data transformed with GPhL converter - dials#376
            overload = 100000000
        underload = -1

        try:
            identifier = self._cif_header_dictionary['Detector']
        except KeyError:
            identifier = 'Unknown Eiger'

        from cctbx.eltbx import attenuation_coefficient
        table = attenuation_coefficient.get_table("Si")
        mu = table.mu_at_angstrom(wavelength) / 10.0
        t0 = thickness

        detector = self._detector_factory.simple(
            'PAD', distance * 1000.0,
            (beam_x * pixel_x * 1000.0, beam_y * pixel_y * 1000.0), '+x', '-y',
            (1000 * pixel_x, 1000 * pixel_y), (nx, ny), (underload, overload),
            [], ParallaxCorrectedPxMmStrategy(mu, t0))

        for f0, f1, s0, s1 in determine_eiger_mask(detector):
            detector[0].add_mask(f0 - 1, s0 - 1, f1, s1)

        for panel in detector:
            panel.set_thickness(thickness)
            panel.set_material(material)
            panel.set_identifier(identifier)
            panel.set_mu(mu)

        return detector
    def _detector(self):
        '''Return a working detector instance, with added mask regions.'''

        cif_header = FormatCBFFullPilatus.get_cbf_header(self._image_file)

        self._cif_header_dictionary = {}

        for record in cif_header.split('\n'):
            if not '#' in record[:1]:
                continue

            if len(record[1:].split()) <= 2 and record.count(':') == 2:
                self._cif_header_dictionary['timestamp'] = record[1:].strip()
                continue

            tokens = record.replace('=', '').replace(':', '').split()[1:]

            self._cif_header_dictionary[tokens[0]] = ' '.join(tokens[1:])

        for record in self._mime_header.split('\n'):
            if not record.strip():
                continue
            token, value = record.split(':')
            self._cif_header_dictionary[token.strip()] = value.strip()

        distance = float(
            self._cif_header_dictionary['Detector_distance'].split()[0])

        beam_xy = self._cif_header_dictionary['Beam_xy'].replace(
            '(', '').replace(')', '').replace(',', '').split()[:2]

        wavelength = float(
            self._cif_header_dictionary['Wavelength'].split()[0])

        beam_x, beam_y = map(float, beam_xy)

        pixel_xy = self._cif_header_dictionary['Pixel_size'].replace(
            'm', '').replace('x', '').split()

        pixel_x, pixel_y = map(float, pixel_xy)

        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

        two_theta = float(
            self._cif_header_dictionary['Detector_2theta'].split()[0])

        # hard code "correct" values for these
        distance = 0.11338
        beam_x = 222.0
        beam_y = 383.0

        detector = self._detector_factory.two_theta(
            'PAD', distance * 1000.0,
            (beam_x * pixel_x * 1000.0, beam_y * pixel_y * 1000.0), '+x', '-y',
            '+x', two_theta, (1000 * pixel_x, 1000 * pixel_y), (nx, ny),
            (underload, overload), [], None)

        import re
        m = re.search('^#\s*(\S+)\ssensor, thickness\s*([0-9.]+)\s*m\s*$', \
                      self._cif_header, re.MULTILINE)

        if m:
            # header gives thickness in metres, we store mm
            thickness = float(m.group(2)) * 1000
            material = m.group(1)

            if material == 'Silicon':
                material = 'Si'

            for panel in detector:
                panel.set_thickness(thickness)
                panel.set_material(material)

            try:
                # a header only CBF file will not have a beam object
                beam = self._beam()

            except Exception:
                pass

            if beam:
                # attenuation coefficient depends on the beam wavelength
                wavelength = beam.get_wavelength()

                from cctbx.eltbx import attenuation_coefficient
                from dxtbx.model import ParallaxCorrectedPxMmStrategy
                # this will fail for undefined composite materials
                table = attenuation_coefficient.get_table(material)
                # mu_at_angstrom returns cm^-1, but need mu in mm^-1
                mu = table.mu_at_angstrom(wavelength) / 10.0

                for panel in detector:
                    panel.set_mu(mu)
                    panel.set_px_mm_strategy(
                        ParallaxCorrectedPxMmStrategy(mu, thickness))

        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 information...

        detector = self._detector_factory.simple(
            'PAD', distance * 1000.0,
            (beam_x * pixel_x * 1000.0, beam_y * pixel_y * 1000.0), '+x', '-y',
            (1000 * pixel_x, 1000 * 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)

        return detector
Example #31
0
    def _detector(self):
        distance = float(self._cif_header_dictionary["Detector_distance"].split()[0])

        beam_xy = (
            self._cif_header_dictionary["Beam_xy"]
            .replace("(", "")
            .replace(")", "")
            .replace(",", "")
            .split()[:2]
        )

        wavelength = float(self._cif_header_dictionary["Wavelength"].split()[0])

        beam_x, beam_y = map(float, beam_xy)

        pixel_xy = (
            self._cif_header_dictionary["Pixel_size"]
            .replace("m", "")
            .replace("x", "")
            .split()
        )

        pixel_x, pixel_y = map(float, pixel_xy)

        if "Silicon" in self._cif_header_dictionary:
            thickness = (
                float(self._cif_header_dictionary["Silicon"].split()[2]) * 1000.0
            )
            material = "Si"
        elif "CdTe" in self._cif_header_dictionary:
            thickness = float(self._cif_header_dictionary["CdTe"].split()[2]) * 1000.0
            material = "CdTe"
        else:
            thickness = 0.450
            material = "Si"

        nx = int(self._cif_header_dictionary["X-Binary-Size-Fastest-Dimension"])
        ny = int(self._cif_header_dictionary["X-Binary-Size-Second-Dimension"])

        if "Count_cutoff" in self._cif_header_dictionary:
            overload = int(self._cif_header_dictionary["Count_cutoff"].split()[0])
        else:
            # missing from data transformed with GPhL converter - dials#376
            overload = 100000000
        underload = -1

        try:
            identifier = self._cif_header_dictionary["Detector"]
        except KeyError:
            identifier = "Unknown Eiger"

        from cctbx.eltbx import attenuation_coefficient

        table = attenuation_coefficient.get_table(material)
        mu = table.mu_at_angstrom(wavelength) / 10.0
        t0 = thickness

        detector = self._detector_factory.simple(
            "PAD",
            distance * 1000.0,
            (beam_x * pixel_x * 1000.0, beam_y * pixel_y * 1000.0),
            "+x",
            "-y",
            (1000 * pixel_x, 1000 * pixel_y),
            (nx, ny),
            (underload, overload),
            [],
            px_mm=ParallaxCorrectedPxMmStrategy(mu, t0),
            mu=mu,
        )

        for f0, f1, s0, s1 in determine_eiger_mask(detector):
            detector[0].add_mask(f0 - 1, s0 - 1, f1, s1)

        for panel in detector:
            panel.set_thickness(thickness)
            panel.set_material(material)
            panel.set_identifier(identifier)
            panel.set_mu(mu)

        return detector