Ejemplo n.º 1
0
def create_multipanel_detector(offset, ncols=3, nrows=2):
    reference_detector = create_detector(offset)
    reference_panel = reference_detector[0]
    panel_npix = reference_panel.get_image_size()
    panel_npix = int(panel_npix[0] / ncols), int(panel_npix[1] / nrows)

    multi_panel_detector = Detector()
    for i in range(ncols):
        for j in range(nrows):
            origin_pix = i * panel_npix[0], j * panel_npix[1]
            origin = reference_panel.get_pixel_lab_coord(origin_pix)
            new_panel = Panel(
                reference_panel.get_type(),
                reference_panel.get_name() + str(j + i * nrows),
                reference_panel.get_fast_axis(),
                reference_panel.get_slow_axis(),
                origin,
                reference_panel.get_pixel_size(),
                panel_npix,
                reference_panel.get_trusted_range(),
                reference_panel.get_thickness(),
                reference_panel.get_material(),
                identifier=reference_panel.get_identifier(),
            )
            multi_panel_detector.add_panel(new_panel)

    return multi_panel_detector
Ejemplo n.º 2
0
def get_optimized_detector(x, SIM):
    from dxtbx.model import Detector, Panel
    new_det = Detector()
    for pid in range(len(SIM.detector)):
        panel = SIM.detector[pid]
        panel_dict = panel.to_dict()
        group_id = SIM.panel_group_from_id[pid]
        if group_id in SIM.panel_groups_refined:
            Oang = x["group%d_RotOrth" % group_id].value
            Fang = x["group%d_RotFast" % group_id].value
            Sang = x["group%d_RotSlow" % group_id].value
            Xdist = x["group%d_ShiftX" % group_id].value
            Ydist = x["group%d_ShiftY" % group_id].value
            Zdist = x["group%d_ShiftZ" % group_id].value

            origin_of_rotation = SIM.panel_reference_from_id[pid]
            SIM.D.reference_origin = origin_of_rotation
            SIM.D.update_dxtbx_geoms(SIM.detector, SIM.beam.nanoBragg_constructor_beam, pid,
                                     Oang, Fang, Sang, Xdist, Ydist, Zdist,
                                     force=False)
            fdet = SIM.D.fdet_vector
            sdet = SIM.D.sdet_vector
            origin = SIM.D.get_origin()
        else:
            fdet = panel.get_fast_axis()
            sdet = panel.get_slow_axis()
            origin = panel.get_origin()
        panel_dict["fast_axis"] = fdet
        panel_dict["slow_axis"] = sdet
        panel_dict["origin"] = origin

        new_det.add_panel(Panel.from_dict(panel_dict))

    return new_det
Ejemplo n.º 3
0
def get_multi_panel_eiger(detdist_mm=200,
                          pixsize_mm=0.075,
                          as_single_panel=False):
    """

    :param detdist_mm: sample to detector in mm
    :param pixsize_mm: pix in mm
    :param as_single_panel: whether to return as just a large single panel camera
    :return: dxtbx detector
    """
    # load a file specifying the gap positions
    # this is a 2D array
    # usually -1 is a gap, so you can create this array by doing
    # is_a_gap = np.array(eiger_image)==-1  (pseudo)
    is_a_gap = h5py.File("eiger_gaps.h5", "r")["is_a_gap"][()]

    # to view:
    #import pylab as plt
    #plt.imshow( is_a_gap)
    #plt.show()
    # its not perfect, some small regions are also flagged, we shall filter them though

    ydim, xdim = is_a_gap.shape

    center_x = xdim / 2. * pixsize_mm
    center_y = ydim / 2. * pixsize_mm
    master_panel_dict = {
        'type': 'SENSOR_PAD',
        'fast_axis': (1.0, 0.0, 0.0),
        'slow_axis': (0.0, -1.0, 0.0),
        'origin': (-center_x, center_y, -detdist_mm),
        'raw_image_offset': (0, 0),
        'image_size': (xdim, ydim),
        'pixel_size':
        (pixsize_mm, pixsize_mm),  # NOTE this will depend on your model
        'trusted_range': (-1.0, 65535.0),
        'thickness': 0.45,
        'material': 'Si',
        'mu': 3.969545947994824,
        'identifier': '',
        'mask': [],
        'gain': 1.0,
        'pedestal': 0.0,
        'px_mm_strategy': {
            'type': 'SimplePxMmStrategy'
        }
    }

    master_panel = Panel.from_dict(master_panel_dict)
    master_det = Detector()
    master_det.add_panel(master_panel)

    if as_single_panel:
        return master_det
    else:
        return panelize_eiger(master_det, is_a_gap)
def get_optimized_detector(x, ref_params, SIM):
    new_det = Detector()
    for pid in range(len(SIM.detector)):
        panel = SIM.detector[pid]
        panel_dict = panel.to_dict()
        group_id = SIM.panel_group_from_id[pid]
        if group_id in SIM.panel_groups_refined:

            Oang_p = ref_params["group%d_RotOrth" % group_id]
            Fang_p = ref_params["group%d_RotFast" % group_id]
            Sang_p = ref_params["group%d_RotSlow" % group_id]
            Xdist_p = ref_params["group%d_ShiftX" % group_id]
            Ydist_p = ref_params["group%d_ShiftY" % group_id]
            Zdist_p = ref_params["group%d_ShiftZ" % group_id]

            Oang = Oang_p.get_val(x[Oang_p.xpos])
            Fang = Fang_p.get_val(x[Fang_p.xpos])
            Sang = Sang_p.get_val(x[Sang_p.xpos])
            Xdist = Xdist_p.get_val(x[Xdist_p.xpos])
            Ydist = Ydist_p.get_val(x[Ydist_p.xpos])
            Zdist = Zdist_p.get_val(x[Zdist_p.xpos])

            origin_of_rotation = SIM.panel_reference_from_id[pid]
            SIM.D.reference_origin = origin_of_rotation
            SIM.D.update_dxtbx_geoms(SIM.detector,
                                     SIM.beam.nanoBragg_constructor_beam,
                                     pid,
                                     Oang,
                                     Fang,
                                     Sang,
                                     Xdist,
                                     Ydist,
                                     Zdist,
                                     force=False)
            fdet = SIM.D.fdet_vector
            sdet = SIM.D.sdet_vector
            origin = SIM.D.get_origin()
        else:
            fdet = panel.get_fast_axis()
            sdet = panel.get_slow_axis()
            origin = panel.get_origin()
        panel_dict["fast_axis"] = fdet
        panel_dict["slow_axis"] = sdet
        panel_dict["origin"] = origin

        new_det.add_panel(Panel.from_dict(panel_dict))

    return new_det
Ejemplo n.º 5
0
    def __call__(self):

        from dxtbx.model import Detector, Panel  # import dependency

        d1 = Detector()
        p = d1.add_panel()
        p.set_name("p1")
        p.set_type("panel")
        p.set_pixel_size((0.1, 0.1))
        p.set_image_size((100, 100))
        p.set_trusted_range((0, 1000))
        p.set_local_frame((1, 0, 0), (0, 1, 0), (0, 0, 1))

        p = d1.add_panel()
        p.set_name("p2")
        p.set_type("panel")
        p.set_pixel_size((0.2, 0.2))
        p.set_image_size((200, 200))
        p.set_trusted_range((0, 2000))
        p.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 1))

        root = d1.hierarchy()
        g = root.add_group()
        g.set_name("g1")
        g.set_type("group")
        g.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 2))
        g.add_panel(d1[0])

        g = root.add_group()
        g.set_name("g2")
        g.set_type("group")
        g.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 4))
        g.add_panel(d1[1])

        d = d1.to_dict()
        d2 = Detector.from_dict(d)
        assert (len(d1) == len(d2))
        for p1, p2 in zip(d1, d2):
            assert (p1 == p2)
        assert (d1.hierarchy() == d2.hierarchy())
        assert (d1 == d2)

        print 'OK'
Ejemplo n.º 6
0
  def __call__(self):

    from dxtbx.model import Detector, Panel # import dependency

    d1 = Detector()
    p = d1.add_panel()
    p.set_name("p1")
    p.set_type("panel")
    p.set_pixel_size((0.1, 0.1))
    p.set_image_size((100, 100))
    p.set_trusted_range((0, 1000))
    p.set_local_frame((1, 0, 0), (0, 1, 0), (0, 0, 1))

    p = d1.add_panel()
    p.set_name("p2")
    p.set_type("panel")
    p.set_pixel_size((0.2, 0.2))
    p.set_image_size((200, 200))
    p.set_trusted_range((0, 2000))
    p.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 1))

    root = d1.hierarchy()
    g = root.add_group()
    g.set_name("g1")
    g.set_type("group")
    g.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 2))
    g.add_panel(d1[0])

    g = root.add_group()
    g.set_name("g2")
    g.set_type("group")
    g.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 4))
    g.add_panel(d1[1])

    d = d1.to_dict()
    d2 = Detector.from_dict(d)
    assert(len(d1) == len(d2))
    for p1, p2 in zip(d1, d2):
      assert(p1 == p2)
    assert(d1.hierarchy() == d2.hierarchy())
    assert(d1 == d2)

    print 'OK'
Ejemplo n.º 7
0
def downsample_detector(det, downsamp=1):
    newD = Detector()
    for panel in det:
        fast = panel.get_fast_axis()
        slow = panel.get_slow_axis()
        orig = panel.get_origin()
        panel_dict = panel.to_dict()
        panel_dict['fast'] = fast
        panel_dict['slow'] = slow
        panel_dict['origin'] = orig
        fast_dim, slow_dim = panel.get_image_size()
        panel_dict['image_size'] = int(fast_dim / float(downsamp)), int(
            slow_dim / float(downsamp))
        pixsize = panel.get_pixel_size()[0]
        panel_dict['pixel_size'] = pixsize * downsamp, pixsize * downsamp
        newpanel = Panel.from_dict(panel_dict)
        newD.add_panel(newpanel)

    return newD
Ejemplo n.º 8
0
        def create_kapton_face(ori, fast, slow, image_size, pixel_size, name):
            """Create a face of the kapton as a dxtbx detector object"""
            from dxtbx.model import Detector

            d = Detector()
            p = d.add_panel()
            p.set_local_frame(fast.elems, slow.elems, ori.elems)
            p.set_pixel_size((pixel_size, pixel_size))
            p.set_image_size(image_size)
            p.set_trusted_range((-1, 2e6))
            p.set_name("KAPTON_%s" % name)
            return d
Ejemplo n.º 9
0
def make_multi_panel(single_panel_detector):
  """Create a 3x3 multi-panel detector filling the same space as
  a supplied single panel detector"""

  from dials.test.algorithms.refinement.tst_multi_panel_detector_parameterisation \
      import make_panel_in_array
  from dials.test.algorithms.refinement.setup_geometry import \
      random_vector_close_to

  multi_panel_detector = Detector()
  for x in range(3):
    for y in range(3):
      new_panel = make_panel_in_array(
                      (x, y), single_panel_detector[0])
      multi_panel_detector.add_panel(new_panel)

  # apply small random shifts & rotations to each panel
  for p in multi_panel_detector:

    # perturb origin vector
    o_multiplier = random.gauss(1.0, 0.01)
    new_origin = random_vector_close_to(p.get_origin(), sd=0.1)
    new_origin *= o_multiplier

    # perturb fast direction vector
    new_dir1 = random_vector_close_to(p.get_fast_axis(), sd=0.5)

    # create vector in the plane of dir1-dir2
    dir1_dir2 = random_vector_close_to(p.get_slow_axis(), sd=0.5)

    # find normal to panel plane and thus new slow direction vector
    dn = new_dir1.cross(dir1_dir2)
    new_dir2 = dn.cross(new_dir1)

    # set panel frame
    p.set_frame(new_dir1, new_dir2, new_origin)

  return multi_panel_detector
Ejemplo n.º 10
0
def test_detector():
    d1 = Detector()
    p = d1.add_panel()
    p.set_name("p1")
    p.set_type("panel")
    p.set_pixel_size((0.1, 0.1))
    p.set_image_size((100, 100))
    p.set_trusted_range((0, 1000))
    p.set_local_frame((1, 0, 0), (0, 1, 0), (0, 0, 1))

    p = d1.add_panel()
    p.set_name("p2")
    p.set_type("panel")
    p.set_pixel_size((0.2, 0.2))
    p.set_image_size((200, 200))
    p.set_trusted_range((0, 2000))
    p.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 1))

    root = d1.hierarchy()
    g = root.add_group()
    g.set_name("g1")
    g.set_type("group")
    g.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 2))
    g.add_panel(d1[0])

    g = root.add_group()
    g.set_name("g2")
    g.set_type("group")
    g.set_local_frame((0, 1, 0), (1, 0, 0), (0, 0, 4))
    g.add_panel(d1[1])

    d = d1.to_dict()
    d2 = Detector.from_dict(d)
    assert len(d1) == len(d2)
    for p1, p2 in zip(d1, d2):
        assert p1 == p2
    assert d1.hierarchy() == d2.hierarchy()
    assert d1 == d2
Ejemplo n.º 11
0
def panelize_eiger(eiger_dxtbx_model, is_a_gap):
    """
  :param eiger_dxtbx_model: dxtbx geometry for the eiger (single node model)
  :param is_a_gap: a 2D numpy array the same shape as the eiger image (4371, 4150)
    True means the pixel is a gap, False means the pixel is a mask
    Make this by loading an eiger image and selecting all pixels that are equal to -1
    is_a_gap = np.array(eiger_image)==-1
  :return: dxtbx multi panel model for eiger 16M
  """
    multiEiger = Detector()
    # we will make a new detector where wach panel has its own origin, but all share the same fast,slow scan directions
    detector_origin = np.array(eiger_dxtbx_model[0].get_origin())
    F = np.array(eiger_dxtbx_model[0].get_fast_axis())
    S = np.array(eiger_dxtbx_model[0].get_slow_axis())
    pixsize = eiger_dxtbx_model[0].get_pixel_size()[0]
    panel_dict = eiger_dxtbx_model[0].to_dict()

    is_a_panel = np.logical_not(is_a_gap)
    labs, nlabs = label(is_a_panel)

    for i in range(nlabs + 1):
        region = labs == i
        npixels = np.sum(region)
        # there might be some other connected regions that are not panels (bad regions for example)
        if 200000 < npixels < 530000:  # panel size is 529420 pixels, I think
            ypos, xpos = np.where(region)
            jmin, imin = min(ypos), min(
                xpos)  # location of first pixel in the region
            jmax, imax = max(ypos), max(xpos)
            panel_shape = (int(imax - imin), int(jmax - jmin))
            panel_origin = detector_origin + F * imin * pixsize + S * jmin * pixsize
            panel_dict["origin"] = tuple(panel_origin)
            panel_dict["image_size"] = panel_shape
            panel = Panel.from_dict(panel_dict)
            multiEiger.add_panel(panel)

    return multiEiger
Ejemplo n.º 12
0
def test_check_and_remove():

    test = _Test()

    # Override the single panel model and parameterisation. This test function
    # exercises the code for non-hierarchical multi-panel detectors. The
    # hierarchical detector version is tested via test_cspad_refinement.py
    multi_panel_detector = Detector()
    for x in range(3):
        for y in range(3):
            new_panel = make_panel_in_array((x, y), test.detector[0])
            multi_panel_detector.add_panel(new_panel)
    test.detector = multi_panel_detector
    test.stills_experiments[0].detector = multi_panel_detector
    test.det_param = DetectorParameterisationMultiPanel(multi_panel_detector, test.beam)

    # update the generated reflections
    test.generate_reflections()

    # Predict the reflections in place and put in a reflection manager
    ref_predictor = StillsExperimentsPredictor(test.stills_experiments)
    ref_predictor(test.reflections)
    test.refman = ReflectionManagerFactory.from_parameters_reflections_experiments(
        refman_phil_scope.extract(),
        test.reflections,
        test.stills_experiments,
        do_stills=True,
    )
    test.refman.finalise()

    # Build a prediction parameterisation for the stills experiment
    test.pred_param = StillsPredictionParameterisation(
        test.stills_experiments,
        detector_parameterisations=[test.det_param],
        beam_parameterisations=[test.s0_param],
        xl_orientation_parameterisations=[test.xlo_param],
        xl_unit_cell_parameterisations=[test.xluc_param],
    )

    # A non-hierarchical detector does not have panel groups, thus panels are
    # not treated independently wrt which reflections affect their parameters.
    # As before, setting 792 reflections as the minimum should leave all
    # parameters free, and should not remove any reflections
    options = ar_phil_scope.extract()
    options.min_nref_per_parameter = 792
    ar = AutoReduce(options, pred_param=test.pred_param, reflection_manager=test.refman)
    ar.check_and_remove()

    det_params = test.pred_param.get_detector_parameterisations()
    beam_params = test.pred_param.get_beam_parameterisations()
    xl_ori_params = test.pred_param.get_crystal_orientation_parameterisations()
    xl_uc_params = test.pred_param.get_crystal_unit_cell_parameterisations()
    assert det_params[0].num_free() == 6
    assert beam_params[0].num_free() == 3
    assert xl_ori_params[0].num_free() == 3
    assert xl_uc_params[0].num_free() == 6
    assert len(test.refman.get_obs()) == 823

    # Setting 793 reflections as the minimum fixes 3 unit cell parameters,
    # and removes all those reflections. There are then too few reflections
    # for any parameterisation and all will be fixed, leaving no free
    # parameters for refinement. This fails within PredictionParameterisation,
    # during update so the final 31 reflections are not removed.
    options = ar_phil_scope.extract()
    options.min_nref_per_parameter = 793
    ar = AutoReduce(options, pred_param=test.pred_param, reflection_manager=test.refman)
    with pytest.raises(
        DialsRefineConfigError, match="There are no free parameters for refinement"
    ):
        ar.check_and_remove()

    det_params = test.pred_param.get_detector_parameterisations()
    beam_params = test.pred_param.get_beam_parameterisations()
    xl_ori_params = test.pred_param.get_crystal_orientation_parameterisations()
    xl_uc_params = test.pred_param.get_crystal_unit_cell_parameterisations()
    assert det_params[0].num_free() == 0
    assert beam_params[0].num_free() == 0
    assert xl_ori_params[0].num_free() == 0
    assert xl_uc_params[0].num_free() == 0
    assert len(test.refman.get_obs()) == 823 - 792
Ejemplo n.º 13
0
    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 import Detector
        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 = Detector()

        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
Ejemplo n.º 14
0
class DetectorFactory(object):
  '''
  A class to create a detector model from NXmx stuff

  '''

  def __init__(self, obj, beam):
    from dxtbx.model import Detector, Panel
    from cctbx.eltbx import attenuation_coefficient
    from dxtbx.model import ParallaxCorrectedPxMmStrategy
    from scitbx import matrix

    # Get the handles
    nx_file = obj.handle.file
    nx_detector = obj.handle
    nx_module = obj.modules[0].handle

    # Get the detector name and type
    detector_type = str(nx_detector['type'][()])
    detector_name = str(nx_detector.name)

    # Get the trusted range of pixel values
    trusted_range = (-1, float(nx_detector['saturation_value'][()]))

    # Get the detector thickness
    thickness = nx_detector['sensor_thickness']
    thickness_value = float(thickness[()])
    thickness_units = thickness.attrs['units']
    thickness_value = float(convert_units(
      thickness_value,
      thickness_units,
      "mm"))

    # Get the detector material
    material = str(nx_detector['sensor_material'][()])

    # Get the fast pixel size and vector
    fast_pixel_direction = nx_module['fast_pixel_direction']
    fast_pixel_direction_value = float(fast_pixel_direction[()])
    fast_pixel_direction_units = fast_pixel_direction.attrs['units']
    fast_pixel_direction_vector = fast_pixel_direction.attrs['vector']
    fast_pixel_direction_value = convert_units(
      fast_pixel_direction_value,
      fast_pixel_direction_units,
      "mm")
    fast_axis = matrix.col(fast_pixel_direction_vector).normalize()

    # Get the slow pixel size and vector
    slow_pixel_direction = nx_module['slow_pixel_direction']
    slow_pixel_direction_value = float(slow_pixel_direction[()])
    slow_pixel_direction_units = slow_pixel_direction.attrs['units']
    slow_pixel_direction_vector = slow_pixel_direction.attrs['vector']
    slow_pixel_direction_value = convert_units(
      slow_pixel_direction_value,
      slow_pixel_direction_units,
      "mm")
    slow_axis = matrix.col(slow_pixel_direction_vector).normalize()

    # Get the origin vector
    module_offset = nx_module['module_offset']
    origin = construct_vector(
      nx_file,
      module_offset.name)

    # Ensure that fast and slow axis are orthogonal
    normal = fast_axis.cross(slow_axis)
    slow_axis = -fast_axis.cross(normal)

    # Compute the attenuation coefficient.
    # This will fail for undefined composite materials
    # mu_at_angstrom returns cm^-1, but need mu in mm^-1
    if material == 'Si':
      pass
    elif material == 'Silicon':
      material = 'Si'
    elif material == 'Sillicon':
      material = 'Si'
    elif material == 'CdTe':
      pass
    elif material == 'GaAs':
      pass
    else:
      raise RuntimeError('Unknown material: %s' % material)
    table = attenuation_coefficient.get_table(material)
    wavelength = beam.get_wavelength()
    mu = table.mu_at_angstrom(wavelength) / 10.0

    # Construct the detector model
    pixel_size = (fast_pixel_direction_value, slow_pixel_direction_value)
    image_size = tuple(map(int, nx_module['data_size']))

    self.model = Detector()
    self.model.add_panel(
      Panel(
        detector_type,
        detector_name,
        tuple(fast_axis),
        tuple(slow_axis),
        tuple(origin),
        pixel_size,
        image_size,
        trusted_range,
        thickness_value,
        material,
        mu))

    # Set the parallax correction
    for panel in self.model:
      panel.set_px_mm_strategy(ParallaxCorrectedPxMmStrategy(mu, thickness_value))
      panel.set_type('SENSOR_PAD')
Ejemplo n.º 15
0
def test(args=[]):
    #############################
    # Setup experimental models #
    #############################
    master_phil = parse(
        """
      include scope dials.test.algorithms.refinement.geometry_phil
      include scope dials.test.algorithms.refinement.minimiser_phil
      """,
        process_includes=True,
    )

    models = setup_geometry.Extract(master_phil, cmdline_args=args)

    single_panel_detector = models.detector
    mygonio = models.goniometer
    mycrystal = models.crystal
    mybeam = models.beam

    # Make a 3x3 multi panel detector filling the same space as the existing
    # single panel detector. Each panel of the multi-panel detector has pixels with
    # 1/3 the length dimensions of the single panel.

    multi_panel_detector = Detector()
    for x in range(3):
        for y in range(3):
            new_panel = make_panel_in_array((x, y), single_panel_detector[0])
            multi_panel_detector.add_panel(new_panel)

    # Build a mock scan for a 180 degree sweep
    sf = ScanFactory()
    myscan = sf.make_scan(
        image_range=(1, 1800),
        exposure_times=0.1,
        oscillation=(0, 0.1),
        epochs=list(range(1800)),
        deg=True,
    )
    sweep_range = myscan.get_oscillation_range(deg=False)
    im_width = myscan.get_oscillation(deg=False)[1]
    assert sweep_range == (0.0, pi)
    assert approx_equal(im_width, 0.1 * pi / 180.0)

    # Build ExperimentLists
    experiments_single_panel = ExperimentList()
    experiments_multi_panel = ExperimentList()
    experiments_single_panel.append(
        Experiment(
            beam=mybeam,
            detector=single_panel_detector,
            goniometer=mygonio,
            scan=myscan,
            crystal=mycrystal,
            imageset=None,
        ))
    experiments_multi_panel.append(
        Experiment(
            beam=mybeam,
            detector=multi_panel_detector,
            goniometer=mygonio,
            scan=myscan,
            crystal=mycrystal,
            imageset=None,
        ))

    ###########################
    # Parameterise the models #
    ###########################

    det_param = DetectorParameterisationSinglePanel(single_panel_detector)
    s0_param = BeamParameterisation(mybeam, mygonio)
    xlo_param = CrystalOrientationParameterisation(mycrystal)
    xluc_param = CrystalUnitCellParameterisation(mycrystal)

    multi_det_param = DetectorParameterisationMultiPanel(
        multi_panel_detector, mybeam)

    # Fix beam to the X-Z plane (imgCIF geometry), fix wavelength
    s0_param.set_fixed([True, False, True])

    # Fix crystal parameters
    # xluc_param.set_fixed([True, True, True, True, True, True])

    ########################################################################
    # Link model parameterisations together into a parameterisation of the #
    # prediction equation                                                  #
    ########################################################################

    pred_param = XYPhiPredictionParameterisation(experiments_single_panel,
                                                 [det_param], [s0_param],
                                                 [xlo_param], [xluc_param])

    pred_param2 = XYPhiPredictionParameterisation(
        experiments_multi_panel,
        [multi_det_param],
        [s0_param],
        [xlo_param],
        [xluc_param],
    )

    ################################
    # Apply known parameter shifts #
    ################################

    # shift detectors by 1.0 mm each translation and 2 mrad each rotation
    det_p_vals = det_param.get_param_vals()
    p_vals = [
        a + b for a, b in zip(det_p_vals, [1.0, 1.0, 1.0, 2.0, 2.0, 2.0])
    ]
    det_param.set_param_vals(p_vals)

    multi_det_p_vals = multi_det_param.get_param_vals()
    p_vals = [
        a + b for a, b in zip(multi_det_p_vals, [1.0, 1.0, 1.0, 2.0, 2.0, 2.0])
    ]
    multi_det_param.set_param_vals(p_vals)

    # shift beam by 2 mrad in free axis
    s0_p_vals = s0_param.get_param_vals()
    p_vals = list(s0_p_vals)

    p_vals[0] += 2.0
    s0_param.set_param_vals(p_vals)

    # rotate crystal a bit (=2 mrad each rotation)
    xlo_p_vals = xlo_param.get_param_vals()
    p_vals = [a + b for a, b in zip(xlo_p_vals, [2.0, 2.0, 2.0])]
    xlo_param.set_param_vals(p_vals)

    # change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of
    # gamma angle)
    xluc_p_vals = xluc_param.get_param_vals()
    cell_params = mycrystal.get_unit_cell().parameters()
    cell_params = [
        a + b for a, b in zip(cell_params, [0.1, 0.1, 0.1, 0.0, 0.0, 0.1])
    ]
    new_uc = unit_cell(cell_params)
    newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
    S = symmetrize_reduce_enlarge(mycrystal.get_space_group())
    S.set_orientation(orientation=newB)
    X = tuple([e * 1.0e5 for e in S.forward_independent_parameters()])
    xluc_param.set_param_vals(X)

    #############################
    # Generate some reflections #
    #############################

    # All indices in a 2.0 Angstrom sphere
    resolution = 2.0
    index_generator = IndexGenerator(
        mycrystal.get_unit_cell(),
        space_group(space_group_symbols(1).hall()).type(),
        resolution,
    )
    indices = index_generator.to_array()

    # for the reflection predictor, it doesn't matter which experiment list is
    # passed, as the detector is not used
    ref_predictor = ScansRayPredictor(experiments_single_panel, sweep_range)

    # get two sets of identical reflections
    obs_refs = ref_predictor(indices)
    obs_refs2 = ref_predictor(indices)
    for r1, r2 in zip(obs_refs, obs_refs2):
        assert r1["s1"] == r2["s1"]

    # get the panel intersections
    sel = ray_intersection(single_panel_detector, obs_refs)
    obs_refs = obs_refs.select(sel)
    sel = ray_intersection(multi_panel_detector, obs_refs2)
    obs_refs2 = obs_refs2.select(sel)
    assert len(obs_refs) == len(obs_refs2)

    # Set 'observed' centroids from the predicted ones
    obs_refs["xyzobs.mm.value"] = obs_refs["xyzcal.mm"]
    obs_refs2["xyzobs.mm.value"] = obs_refs2["xyzcal.mm"]

    # Invent some variances for the centroid positions of the simulated data
    im_width = 0.1 * pi / 180.0
    px_size = single_panel_detector[0].get_pixel_size()
    var_x = flex.double(len(obs_refs), (px_size[0] / 2.0)**2)
    var_y = flex.double(len(obs_refs), (px_size[1] / 2.0)**2)
    var_phi = flex.double(len(obs_refs), (im_width / 2.0)**2)

    # set the variances and frame numbers
    obs_refs["xyzobs.mm.variance"] = flex.vec3_double(var_x, var_y, var_phi)
    obs_refs2["xyzobs.mm.variance"] = flex.vec3_double(var_x, var_y, var_phi)

    # Add in flags and ID columns by copying into standard reflection tables
    tmp = flex.reflection_table.empty_standard(len(obs_refs))
    tmp.update(obs_refs)
    obs_refs = tmp
    tmp = flex.reflection_table.empty_standard(len(obs_refs2))
    tmp.update(obs_refs2)
    obs_refs2 = tmp

    ###############################
    # Undo known parameter shifts #
    ###############################

    s0_param.set_param_vals(s0_p_vals)
    det_param.set_param_vals(det_p_vals)
    multi_det_param.set_param_vals(det_p_vals)
    xlo_param.set_param_vals(xlo_p_vals)
    xluc_param.set_param_vals(xluc_p_vals)

    #####################################
    # Select reflections for refinement #
    #####################################

    refman = ReflectionManager(obs_refs, experiments_single_panel)
    refman2 = ReflectionManager(obs_refs, experiments_multi_panel)

    ###############################
    # Set up the target functions #
    ###############################

    mytarget = LeastSquaresPositionalResidualWithRmsdCutoff(
        experiments_single_panel,
        ScansExperimentsPredictor(experiments_single_panel),
        refman,
        pred_param,
        restraints_parameterisation=None,
    )
    mytarget2 = LeastSquaresPositionalResidualWithRmsdCutoff(
        experiments_multi_panel,
        ScansExperimentsPredictor(experiments_multi_panel),
        refman2,
        pred_param2,
        restraints_parameterisation=None,
    )

    #################################
    # Set up the refinement engines #
    #################################

    refiner = setup_minimiser.Extract(master_phil,
                                      mytarget,
                                      pred_param,
                                      cmdline_args=args).refiner
    refiner2 = setup_minimiser.Extract(master_phil,
                                       mytarget2,
                                       pred_param2,
                                       cmdline_args=args).refiner

    refiner.run()

    # reset parameters and run refinement with the multi panel detector
    s0_param.set_param_vals(s0_p_vals)
    multi_det_param.set_param_vals(det_p_vals)
    xlo_param.set_param_vals(xlo_p_vals)
    xluc_param.set_param_vals(xluc_p_vals)

    refiner2.run()

    # same number of steps
    assert refiner.get_num_steps() == refiner2.get_num_steps()

    # same rmsds
    for rmsd, rmsd2 in zip(refiner.history["rmsd"], refiner2.history["rmsd"]):
        assert approx_equal(rmsd, rmsd2)

    # same parameter values each step
    for params, params2 in zip(refiner.history["parameter_vector"],
                               refiner.history["parameter_vector"]):
        assert approx_equal(params, params2)
Ejemplo n.º 16
0
from __future__ import print_function

from dxtbx.model import Detector

d = Detector()
p1 = d.add_panel()
p2 = d.add_panel()
p3 = d.add_panel()
p4 = d.add_panel()

root = d.hierarchy()
g = root.add_group()
g.add_panel(d[0])
g.add_panel(d[1])
root.add_panel(d[2])
root.add_panel(d[3])
print(d.to_dict())
Ejemplo n.º 17
0
def test_check_and_remove():

    test = _Test()

    # Override the single panel model and parameterisation. This test function
    # exercises the code for non-hierarchical multi-panel detectors. The
    # hierarchical detector version is tested via test_cspad_refinement.py
    from dxtbx.model import Detector
    from dials.algorithms.refinement.parameterisation.detector_parameters import (
        DetectorParameterisationMultiPanel, )
    from dials.test.algorithms.refinement.test_multi_panel_detector_parameterisation import (
        make_panel_in_array, )

    multi_panel_detector = Detector()
    for x in range(3):
        for y in range(3):
            new_panel = make_panel_in_array((x, y), test.detector[0])
            multi_panel_detector.add_panel(new_panel)
    test.detector = multi_panel_detector
    test.stills_experiments[0].detector = multi_panel_detector
    test.det_param = DetectorParameterisationMultiPanel(
        multi_panel_detector, test.beam)

    # update the generated reflections
    test.generate_reflections()

    # Predict the reflections in place and put in a reflection manager
    ref_predictor = StillsExperimentsPredictor(test.stills_experiments)
    ref_predictor(test.reflections)
    test.refman = ReflectionManagerFactory.from_parameters_reflections_experiments(
        refman_phil_scope.extract(),
        test.reflections,
        test.stills_experiments,
        do_stills=True,
    )
    test.refman.finalise()

    # A non-hierarchical detector does not have panel groups, thus panels are
    # not treated independently wrt which reflections affect their parameters.
    # As before, setting 137 reflections as the minimum should leave all
    # parameters free, and should not remove any reflections
    options = ar_phil_scope.extract()
    options.min_nref_per_parameter = 137
    ar = AutoReduce(
        options,
        [test.det_param],
        [test.s0_param],
        [test.xlo_param],
        [test.xluc_param],
        gon_params=[],
        reflection_manager=test.refman,
    )
    ar.check_and_remove()

    assert ar.det_params[0].num_free() == 6
    assert ar.beam_params[0].num_free() == 3
    assert ar.xl_ori_params[0].num_free() == 3
    assert ar.xl_uc_params[0].num_free() == 6
    assert len(ar.reflection_manager.get_obs()) == 823

    # Setting reflections as the minimum should fix the detector parameters,
    # which removes that parameterisation. Because all reflections are recorded
    # on that detector, they will all be removed as well. This then affects all
    # other parameterisations, which will be removed.
    options = ar_phil_scope.extract()
    options.min_nref_per_parameter = 138
    ar = AutoReduce(
        options,
        [test.det_param],
        [test.s0_param],
        [test.xlo_param],
        [test.xluc_param],
        gon_params=[],
        reflection_manager=test.refman,
    )
    ar.check_and_remove()

    assert not ar.det_params
    assert not ar.beam_params
    assert not ar.xl_ori_params
    assert not ar.xl_uc_params
    assert len(ar.reflection_manager.get_obs()) == 0
Ejemplo n.º 18
0
def init_test():

    models = setup_geometry.Extract(master_phil)

    single_panel_detector = models.detector
    gonio = models.goniometer
    crystal = models.crystal
    beam = models.beam

    # Make a 3x3 multi panel detector filling the same space as the existing
    # single panel detector. Each panel of the multi-panel detector has pixels
    # with 1/3 the length dimensions of the single panel.
    multi_panel_detector = Detector()
    for x in range(3):
        for y in range(3):
            new_panel = make_panel_in_array((x, y), single_panel_detector[0])
            multi_panel_detector.add_panel(new_panel)

    # Build a mock scan for a 180 degree sequence
    sf = ScanFactory()
    scan = sf.make_scan(
        image_range=(1, 1800),
        exposure_times=0.1,
        oscillation=(0, 0.1),
        epochs=list(range(1800)),
        deg=True,
    )
    sequence_range = scan.get_oscillation_range(deg=False)
    im_width = scan.get_oscillation(deg=False)[1]
    assert sequence_range == (0.0, pi)
    assert approx_equal(im_width, 0.1 * pi / 180.0)

    # Build ExperimentLists
    experiments_single_panel = ExperimentList()
    experiments_multi_panel = ExperimentList()
    experiments_single_panel.append(
        Experiment(
            beam=beam,
            detector=single_panel_detector,
            goniometer=gonio,
            scan=scan,
            crystal=crystal,
            imageset=None,
        )
    )
    experiments_multi_panel.append(
        Experiment(
            beam=beam,
            detector=multi_panel_detector,
            goniometer=gonio,
            scan=scan,
            crystal=crystal,
            imageset=None,
        )
    )

    # Generate some reflections

    # All indices in a 2.0 Angstrom sphere
    resolution = 2.0
    index_generator = IndexGenerator(
        crystal.get_unit_cell(),
        space_group(space_group_symbols(1).hall()).type(),
        resolution,
    )
    indices = index_generator.to_array()

    # for the reflection predictor, it doesn't matter which experiment list is
    # passed, as the detector is not used
    ref_predictor = ScansRayPredictor(
        experiments_single_panel, scan.get_oscillation_range(deg=False)
    )

    # get two sets of identical reflections
    obs_refs_single = ref_predictor(indices)
    obs_refs_multi = ref_predictor(indices)
    for r1, r2 in zip(obs_refs_single.rows(), obs_refs_multi.rows()):
        assert r1["s1"] == r2["s1"]

    # get the panel intersections
    sel = ray_intersection(single_panel_detector, obs_refs_single)
    obs_refs_single = obs_refs_single.select(sel)
    sel = ray_intersection(multi_panel_detector, obs_refs_multi)
    obs_refs_multi = obs_refs_multi.select(sel)
    assert len(obs_refs_single) == len(obs_refs_multi)

    # Set 'observed' centroids from the predicted ones
    obs_refs_single["xyzobs.mm.value"] = obs_refs_single["xyzcal.mm"]
    obs_refs_multi["xyzobs.mm.value"] = obs_refs_multi["xyzcal.mm"]

    # Invent some variances for the centroid positions of the simulated data
    im_width = 0.1 * pi / 180.0
    px_size = single_panel_detector[0].get_pixel_size()
    var_x = flex.double(len(obs_refs_single), (px_size[0] / 2.0) ** 2)
    var_y = flex.double(len(obs_refs_single), (px_size[1] / 2.0) ** 2)
    var_phi = flex.double(len(obs_refs_single), (im_width / 2.0) ** 2)

    # set the variances and frame numbers
    obs_refs_single["xyzobs.mm.variance"] = flex.vec3_double(var_x, var_y, var_phi)
    obs_refs_multi["xyzobs.mm.variance"] = flex.vec3_double(var_x, var_y, var_phi)

    # Add in flags and ID columns by copying into standard reflection tables
    tmp = flex.reflection_table.empty_standard(len(obs_refs_single))
    tmp.update(obs_refs_single)
    obs_refs_single = tmp
    tmp = flex.reflection_table.empty_standard(len(obs_refs_multi))
    tmp.update(obs_refs_multi)
    obs_refs_multi = tmp

    test_data = namedtuple(
        "test_data",
        [
            "experiments_single_panel",
            "experiments_multi_panel",
            "observations_single_panel",
            "observations_multi_panel",
        ],
    )

    return test_data(
        experiments_single_panel,
        experiments_multi_panel,
        obs_refs_single,
        obs_refs_multi,
    )
  models = setup_geometry.Extract(master_phil, cmdline_args = args)

  single_panel_detector = models.detector
  mygonio = models.goniometer
  mycrystal = models.crystal
  mybeam = models.beam

  # Make a 3x3 multi panel detector filling the same space as the existing
  # single panel detector. Each panel of the multi-panel detector has pixels with
  # 1/3 the length dimensions of the single panel.

  multi_panel_detector = Detector()
  for x in range(3):
    for y in range(3):
      new_panel = make_panel_in_array((x, y), single_panel_detector[0])
      multi_panel_detector.add_panel(new_panel)

  # Build a mock scan for a 180 degree sweep
  sf = ScanFactory()
  myscan = sf.make_scan(image_range = (1,1800),
                        exposure_times = 0.1,
                        oscillation = (0, 0.1),
                        epochs = range(1800),
                        deg = True)
  sweep_range = myscan.get_oscillation_range(deg=False)
  im_width = myscan.get_oscillation(deg=False)[1]
  assert sweep_range == (0., pi)
  assert approx_equal(im_width, 0.1 * pi / 180.)

  # Build ExperimentLists
  experiments_single_panel = ExperimentList()
Ejemplo n.º 20
0
  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 import Detector
    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 = Detector()

    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
Ejemplo n.º 21
0



from dxtbx.model import Detector
d = Detector()
p1 = d.add_panel()
p2 = d.add_panel()
p3 = d.add_panel()
p4 = d.add_panel()


root = d.hierarchy()
g = root.add_group()
g.add_panel(d[0])
g.add_panel(d[1])
root.add_panel(d[2])
root.add_panel(d[3])
print d.to_dict()
def update_detector(x, ref_params, SIM, save=None):
    """
    Update the internal geometry of the diffBragg instance
    :param x: refinement parameters as seen by scipy.optimize (e.g. rescaled floats)
    :param ref_params: diffBragg.refiners.Parameters (dict of RangedParameters)
    :param SIM: SIM instance (instance of nanoBragg.sim_data.SimData)
    :param save: optional name to save the detector
    """
    det = SIM.detector
    if save is not None:
        new_det = Detector()
    for pid in range(len(det)):
        panel = det[pid]
        panel_dict = panel.to_dict()

        group_id = SIM.panel_group_from_id[pid]
        if group_id not in SIM.panel_groups_refined:
            fdet = panel.get_fast_axis()
            sdet = panel.get_slow_axis()
            origin = panel.get_origin()
        else:

            Oang_p = ref_params["group%d_RotOrth" % group_id]
            Fang_p = ref_params["group%d_RotFast" % group_id]
            Sang_p = ref_params["group%d_RotSlow" % group_id]
            Xdist_p = ref_params["group%d_ShiftX" % group_id]
            Ydist_p = ref_params["group%d_ShiftY" % group_id]
            Zdist_p = ref_params["group%d_ShiftZ" % group_id]

            Oang = Oang_p.get_val(x[Oang_p.xpos])
            Fang = Fang_p.get_val(x[Fang_p.xpos])
            Sang = Sang_p.get_val(x[Sang_p.xpos])
            Xdist = Xdist_p.get_val(x[Xdist_p.xpos])
            Ydist = Ydist_p.get_val(x[Ydist_p.xpos])
            Zdist = Zdist_p.get_val(x[Zdist_p.xpos])

            origin_of_rotation = SIM.panel_reference_from_id[pid]
            SIM.D.reference_origin = origin_of_rotation
            SIM.D.update_dxtbx_geoms(det,
                                     SIM.beam.nanoBragg_constructor_beam,
                                     pid,
                                     Oang,
                                     Fang,
                                     Sang,
                                     Xdist,
                                     Ydist,
                                     Zdist,
                                     force=False)
            fdet = SIM.D.fdet_vector
            sdet = SIM.D.sdet_vector
            origin = SIM.D.get_origin()

        if save is not None:
            panel_dict["fast_axis"] = fdet
            panel_dict["slow_axis"] = sdet
            panel_dict["origin"] = origin
            new_det.add_panel(Panel.from_dict(panel_dict))

    if save is not None and COMM.rank == 0:
        t = time.time()
        El = ExperimentList()
        E = Experiment()
        E.detector = new_det
        El.append(E)
        El.as_file(save)
        t = time.time() - t
        print("Saved detector model to %s (took %.4f sec)" % (save, t),
              flush=True)
Ejemplo n.º 23
0
class DetectorFactory(object):
    '''
  A class to create a detector model from NXmx stuff

  '''
    def __init__(self, obj, beam):
        from dxtbx.model import Detector, Panel
        from cctbx.eltbx import attenuation_coefficient
        from dxtbx.model import ParallaxCorrectedPxMmStrategy
        from scitbx import matrix

        # Get the handles
        nx_file = obj.handle.file
        nx_detector = obj.handle
        nx_module = obj.modules[0].handle

        # Get the detector name and type
        detector_type = str(nx_detector['type'][()])
        detector_name = str(nx_detector.name)

        # Get the trusted range of pixel values
        trusted_range = (-1, float(nx_detector['saturation_value'][()]))

        # Get the detector thickness
        thickness = nx_detector['sensor_thickness']
        thickness_value = float(thickness[()])
        thickness_units = thickness.attrs['units']
        thickness_value = float(
            convert_units(thickness_value, thickness_units, "mm"))

        # Get the detector material
        material = str(nx_detector['sensor_material'][()])

        # Get the fast pixel size and vector
        fast_pixel_direction = nx_module['fast_pixel_direction']
        fast_pixel_direction_value = float(fast_pixel_direction[()])
        fast_pixel_direction_units = fast_pixel_direction.attrs['units']
        fast_pixel_direction_vector = fast_pixel_direction.attrs['vector']
        fast_pixel_direction_value = convert_units(fast_pixel_direction_value,
                                                   fast_pixel_direction_units,
                                                   "mm")
        fast_axis = matrix.col(fast_pixel_direction_vector).normalize()

        # Get the slow pixel size and vector
        slow_pixel_direction = nx_module['slow_pixel_direction']
        slow_pixel_direction_value = float(slow_pixel_direction[()])
        slow_pixel_direction_units = slow_pixel_direction.attrs['units']
        slow_pixel_direction_vector = slow_pixel_direction.attrs['vector']
        slow_pixel_direction_value = convert_units(slow_pixel_direction_value,
                                                   slow_pixel_direction_units,
                                                   "mm")
        slow_axis = matrix.col(slow_pixel_direction_vector).normalize()

        # Get the origin vector
        module_offset = nx_module['module_offset']
        origin = construct_vector(nx_file, module_offset.name)

        # Ensure that fast and slow axis are orthogonal
        normal = fast_axis.cross(slow_axis)
        slow_axis = -fast_axis.cross(normal)

        # Compute the attenuation coefficient.
        # This will fail for undefined composite materials
        # mu_at_angstrom returns cm^-1, but need mu in mm^-1
        if material == 'Si':
            pass
        elif material == 'Silicon':
            material = 'Si'
        elif material == 'Sillicon':
            material = 'Si'
        elif material == 'CdTe':
            pass
        elif material == 'GaAs':
            pass
        else:
            raise RuntimeError('Unknown material: %s' % material)
        table = attenuation_coefficient.get_table(material)
        wavelength = beam.get_wavelength()
        mu = table.mu_at_angstrom(wavelength) / 10.0

        # Construct the detector model
        pixel_size = (fast_pixel_direction_value, slow_pixel_direction_value)
        image_size = tuple(map(int, nx_module['data_size']))

        self.model = Detector()
        self.model.add_panel(
            Panel(detector_type, detector_name, tuple(fast_axis),
                  tuple(slow_axis), tuple(origin), pixel_size, image_size,
                  trusted_range, thickness_value, material, mu))

        # Set the parallax correction
        for panel in self.model:
            panel.set_px_mm_strategy(
                ParallaxCorrectedPxMmStrategy(mu, thickness_value))
            panel.set_type('SENSOR_PAD')
Ejemplo n.º 24
0
def load_detector(entry):
  from dxtbx.model import Detector
  from scitbx import matrix

  # Get the detector module object
  nx_instrument = get_nx_instrument(entry, "instrument")
  nx_detector = get_nx_detector(nx_instrument, "detector")
  assert(nx_detector['depends_on'].value == '.')
  material = nx_detector['sensor_material'].value
  det_type = nx_detector['type'].value
  thickness = nx_detector['sensor_thickness'].value
  trusted_range = (nx_detector['underload'].value, nx_detector['saturation_value'].value)


  # The detector model
  detector = Detector()

  i = 0
  while True:
    try:
      module = get_nx_detector_module(nx_detector, "module%d" % i)
    except Exception:
      break
    # Set the data size
    image_size = module['data_size']

    # Set the module offset
    offset_length = module['module_offset'].value
    assert(module['module_offset'].attrs['depends_on'] == '.')
    assert(module['module_offset'].attrs['transformation_type'] == 'translation')
    assert(tuple(module['module_offset'].attrs['offset']) == (0, 0, 0))
    offset_vector = matrix.col(module['module_offset'].attrs['vector'])
    origin = offset_vector * offset_length

    # Write the fast pixel direction
    module_offset_path = str(module['module_offset'].name)
    pixel_size_x = module['fast_pixel_direction'].value
    assert(module['fast_pixel_direction'].attrs['depends_on'] == module_offset_path)
    assert(module['fast_pixel_direction'].attrs['transformation_type'] == 'translation')
    assert(tuple(module['fast_pixel_direction'].attrs['offset']) == (0, 0, 0))
    fast_axis = tuple(module['fast_pixel_direction'].attrs['vector'])

    # Write the slow pixel direction
    pixel_size_y = module['slow_pixel_direction'].value
    assert(module['slow_pixel_direction'].attrs['depends_on'] == module_offset_path)
    assert(module['slow_pixel_direction'].attrs['transformation_type'] == 'translation')
    assert(tuple(module['slow_pixel_direction'].attrs['offset']) == (0, 0, 0))
    slow_axis = tuple(module['slow_pixel_direction'].attrs['vector'])

    # Get the pixel size and axis vectors
    pixel_size = (pixel_size_x, pixel_size_y)

    # Create the panel
    panel = detector.add_panel()
    panel.set_frame(fast_axis, slow_axis, origin)
    panel.set_pixel_size(pixel_size)
    panel.set_image_size(image_size)
    panel.set_type(det_type)
    panel.set_thickness(thickness)
    panel.set_material(material)
    panel.set_trusted_range(trusted_range)
    i += 1

  # Return the detector and panel
  return detector
Ejemplo n.º 25
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
Ejemplo n.º 26
0
def convert_crystfel_to_dxtbx(geom_filename,
                              output_filename,
                              detdist_override=None):
    """
  :param geom_filename: a crystfel geometry file https://www.desy.de/~twhite/crystfel/manual-crystfel_geometry.html
  :param output_filename: filename for a dxtbx experiment containing a single detector model (this is a json file)
  :param detdist_override: alter the detector distance stored in the crystfel geometry to this value (in millimeters)
  """
    geom = load_crystfel_geometry(geom_filename)

    dxtbx_det = Detector()

    for panel_name in geom['panels'].keys():
        P = geom['panels'][panel_name]
        FAST = P['fsx'], P['fsy'], P['fsz']
        SLOW = P['ssx'], P['ssy'], P['ssz']

        # dxtbx uses millimeters
        pixsize = 1 / P['res']  # meters
        pixsize_mm = pixsize * 1000
        detdist = P['coffset'] + P['clen']  # meters
        detdist_mm = detdist * 1000
        if detdist_override is not None:
            detdist_mm = detdist_override
        # dxtbx and crystfel both identify the outer corner of the first pixel in memory as the origin of the panel
        origin = P['cnx'] * pixsize_mm, P[
            'cny'] * pixsize_mm, -detdist_mm  # dxtbx assumes crystal as at point 0,0,0

        num_fast_pix = P["max_fs"] - P['min_fs'] + 1
        num_slow_pix = P["max_ss"] - P['min_ss'] + 1

        panel_description = {
            'fast_axis': FAST,
            'gain': 1.0,  # I dont think nanoBragg cares about this parameter
            'identifier': '',
            'image_size': (num_fast_pix, num_slow_pix),
            'mask': [],
            'material': 'Si',
            'mu': 0,  # NOTE for a thick detector set this to appropriate value
            'name': panel_name,
            'origin': origin,
            'pedestal':
            0.0,  # I dont think nanoBragg cares about this parameter
            'pixel_size': (pixsize_mm, pixsize_mm),
            'px_mm_strategy': {
                'type': 'SimplePxMmStrategy'
            },
            'raw_image_offset': (0, 0),  # not sure what this is
            'slow_axis': SLOW,
            'thickness':
            0,  # note for a thick detector set this to appropriate value
            'trusted_range': (-1.0, 1e6),  # set as you wish
            'type': 'SENSOR_PAD'
        }
        dxtbx_node = Panel.from_dict(panel_description)
        dxtbx_det.add_panel(dxtbx_node)

    E = Experiment()
    E.detector = dxtbx_det
    El = ExperimentList()
    El.append(E)
    El.as_file(output_filename)  # this can be loaded into nanoBragg
Ejemplo n.º 27
0
def load_detector(entry):
    from dxtbx.model import Detector

    # Get the detector module object
    nx_instrument = get_nx_instrument(entry, "instrument")
    nx_detector = get_nx_detector(nx_instrument, "detector")
    assert nx_detector["depends_on"][()] == "."
    material = nx_detector["sensor_material"][()]
    det_type = nx_detector["type"][()]
    thickness = nx_detector["sensor_thickness"][()]
    trusted_range = (nx_detector["underload"][()],
                     nx_detector["saturation_value"][()])

    # The detector model
    detector = Detector()

    i = 0
    while True:
        try:
            module = get_nx_detector_module(nx_detector, "module%d" % i)
        except Exception:
            break
        # Set the data size
        image_size = module["data_size"]

        # Set the module offset
        offset_length = module["module_offset"][()]
        assert module["module_offset"].attrs["depends_on"] == "."
        assert module["module_offset"].attrs[
            "transformation_type"] == "translation"
        assert tuple(module["module_offset"].attrs["offset"]) == (0, 0, 0)
        offset_vector = matrix.col(module["module_offset"].attrs["vector"])
        origin = offset_vector * offset_length

        # Write the fast pixel direction
        module_offset_path = str(module["module_offset"].name)
        pixel_size_x = module["fast_pixel_direction"][()]
        assert module["fast_pixel_direction"].attrs[
            "depends_on"] == module_offset_path
        assert (module["fast_pixel_direction"].attrs["transformation_type"] ==
                "translation")
        assert tuple(module["fast_pixel_direction"].attrs["offset"]) == (0, 0,
                                                                         0)
        fast_axis = tuple(module["fast_pixel_direction"].attrs["vector"])

        # Write the slow pixel direction
        pixel_size_y = module["slow_pixel_direction"][()]
        assert module["slow_pixel_direction"].attrs[
            "depends_on"] == module_offset_path
        assert (module["slow_pixel_direction"].attrs["transformation_type"] ==
                "translation")
        assert tuple(module["slow_pixel_direction"].attrs["offset"]) == (0, 0,
                                                                         0)
        slow_axis = tuple(module["slow_pixel_direction"].attrs["vector"])

        # Get the pixel size and axis vectors
        pixel_size = (pixel_size_x, pixel_size_y)

        # Create the panel
        panel = detector.add_panel()
        panel.set_frame(fast_axis, slow_axis, origin)
        panel.set_pixel_size(pixel_size)
        panel.set_image_size([int(x) for x in image_size])
        panel.set_type(det_type)
        panel.set_thickness(thickness)
        panel.set_material(material)
        panel.set_trusted_range([float(x) for x in trusted_range])
        i += 1

    # Return the detector and panel
    return detector
Ejemplo n.º 28
0
class FormatNexusJungfrauHack(FormatNexus):
    @staticmethod
    def understand(image_file):
        try:
            with h5py.File(image_file, "r") as handle:
                return "/entry/instrument/JF1M" in handle
        except OSError:
            return False

    def _start(self):

        # Read the file structure
        self._reader = reader = NXmxReader(self._image_file)

        # Only support 1 set of models at the moment
        assert len(reader.entries) == 1, "Currently only supports 1 NXmx entry"
        assert len(reader.entries[0].data) == 1, "Currently only supports 1 NXdata"
        assert (
            len(reader.entries[0].instruments) == 1
        ), "Currently only supports 1 NXinstrument"
        assert len(reader.entries[0].samples) == 1, "Currently only supports 1 NXsample"
        assert (
            len(reader.entries[0].samples[0].beams) == 1
            or len(reader.entries[0].instruments[0].beams) == 1
        ), "Currently only supports 1 NXbeam"

        # Get the NXmx model objects
        entry = reader.entries[0]
        self.instrument = instrument = entry.instruments[0]
        detector = instrument.detectors[0]
        sample = entry.samples[0]
        beam = sample.beams[0] if sample.beams else instrument.beams[0]
        data = entry.data[0]

        # Construct the models
        self._beam_factory = BeamFactory(beam)
        self._beam_factory.load_model(0)

        self._setup_detector(detector, self._beam_factory.model)
        self._setup_gonio_and_scan(sample, detector)

        if self._scan_model:
            array_range = self._scan_model.get_array_range()
            num_images = array_range[1] - array_range[0]
        else:
            num_images = 0

        self._raw_data = DataFactory(data, max_size=num_images)

    def _setup_detector(self, detector, beam):
        nx_detector = detector.handle
        nx_module = detector.modules[0].handle

        # Get the detector name and type
        if "type" in nx_detector:
            detector_type = str(nx_detector["type"][()])
        else:
            detector_type = "unknown"
        detector_name = str(nx_detector.name)

        # Get the trusted range of pixel values
        if "saturation_value" in nx_detector:
            trusted_range = (-1, float(nx_detector["saturation_value"][()]))
        else:
            trusted_range = (-1, 99999999)

        # Get the detector thickness
        thickness = nx_detector["sensor_thickness"]
        thickness_value = float(thickness[()])
        thickness_units = thickness.attrs["units"]
        thickness_value = float(convert_units(thickness_value, thickness_units, "mm"))

        # Get the detector material
        material = nx_detector["sensor_material"][()]
        if hasattr(material, "shape"):
            material = "".join(m.decode() for m in material)
        detector_material = clean_string(str(material))
        material = {
            "Si": "Si",
            np.string_("Si"): "Si",
            np.string_("Silicon"): "Si",
            np.string_("Sillicon"): "Si",
            np.string_("CdTe"): "CdTe",
            np.string_("GaAs"): "GaAs",
        }.get(detector_material)
        if not material:
            raise RuntimeError("Unknown material: %s" % detector_material)

        try:
            x_pixel = nx_detector["x_pixel_size"][()] * 1000.0
            y_pixel = nx_detector["y_pixel_size"][()] * 1000.0

            legacy_beam_x = float(x_pixel * nx_detector["beam_center_x"][()])
            legacy_beam_y = float(y_pixel * nx_detector["beam_center_y"][()])
            legacy_distance = float(1000 * nx_detector["detector_distance"][()])
        except KeyError:
            legacy_beam_x = 0
            legacy_beam_y = 0

        # Get the fast pixel size and vector
        fast_pixel_direction = nx_module["fast_pixel_direction"]
        fast_pixel_direction_value = float(fast_pixel_direction[()])
        fast_pixel_direction_units = fast_pixel_direction.attrs["units"]
        fast_pixel_direction_vector = fast_pixel_direction.attrs["vector"]
        fast_pixel_direction_value = convert_units(
            fast_pixel_direction_value, fast_pixel_direction_units, "mm"
        )
        fast_axis = matrix.col(fast_pixel_direction_vector).normalize()

        # Get the slow pixel size and vector
        slow_pixel_direction = nx_module["slow_pixel_direction"]
        slow_pixel_direction_value = float(slow_pixel_direction[()])
        slow_pixel_direction_units = slow_pixel_direction.attrs["units"]
        slow_pixel_direction_vector = slow_pixel_direction.attrs["vector"]
        slow_pixel_direction_value = convert_units(
            slow_pixel_direction_value, slow_pixel_direction_units, "mm"
        )
        slow_axis = matrix.col(slow_pixel_direction_vector).normalize()

        origin = matrix.col((0.0, 0.0, -legacy_distance))
        if origin.elems[0] == 0.0 and origin.elems[1] == 0:
            origin = -(origin + legacy_beam_x * fast_axis + legacy_beam_y * slow_axis)

        # Change of basis to convert from NeXus to IUCr/ImageCIF convention
        cob = matrix.sqr((-1, 0, 0, 0, 1, 0, 0, 0, -1))
        origin = cob * matrix.col(origin)
        fast_axis = cob * fast_axis
        slow_axis = cob * slow_axis

        # Ensure that fast and slow axis are orthogonal
        normal = fast_axis.cross(slow_axis)
        slow_axis = -fast_axis.cross(normal)

        # 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 = beam.get_wavelength()
        mu = table.mu_at_angstrom(wavelength) / 10.0

        # Construct the detector model
        pixel_size = (fast_pixel_direction_value, slow_pixel_direction_value)
        # image size stored slow to fast but dxtbx needs fast to slow
        image_size = tuple(int(x) for x in reversed(nx_module["data_size"][-2:]))
        image_size = (1030, 1064)

        self.model = Detector()
        self.model.add_panel(
            Panel(
                detector_type,
                detector_name,
                tuple(fast_axis),
                tuple(slow_axis),
                tuple(origin),
                pixel_size,
                image_size,
                trusted_range,
                thickness_value,
                material,
                mu,
            )
        )

        # Set the parallax correction
        for panel in self.model:
            panel.set_px_mm_strategy(ParallaxCorrectedPxMmStrategy(mu, thickness_value))
            panel.set_type("SENSOR_PAD")

        self._detector_model = self.model

    def _setup_gonio_and_scan(self, sample, detector):
        with h5py.File(self._image_file, "r") as handle:
            phi = handle["/entry/sample/goniometer/omega"][()]
        image_range = (1, len(phi))
        oscillation = (float(phi[0]), float(phi[1] - phi[0]))

        # Get the exposure time
        num_images = len(phi)
        exposure_time = flex.double(num_images, 0)
        epochs = flex.double(num_images, 0.0)
        for i in range(1, len(epochs)):
            epochs[i] = epochs[i - 1] + exposure_time[i - 1]

        self._scan_model = Scan(image_range, oscillation, exposure_time, epochs)
        self._goniometer_model = self._goniometer_factory.known_axis((-1, 0, 0))

    def _end(self):
        return

    def _goniometer(self):
        return self._goniometer_model

    def _detector(self):
        return self._detector_model

    def _scan(self):
        return self._scan_model

    def get_goniometer(self, index=None):
        return self._goniometer()

    def get_detector(self, index=None):
        return self._detector()

    def get_beam(self, index=None):
        return self._beam(index)

    def get_scan(self, index=None):
        if index is None:
            return self._scan()
        scan = self._scan()
        if scan is not None:
            return scan[index]
        return scan

    def get_raw_data(self, index):
        return self._raw_data[index]

    def get_static_mask(self, index=None, goniometer=None):
        return MaskFactory(self.instrument.detectors, index).mask

    def get_num_images(self):
        if self._scan() is not None:
            return self._scan().get_num_images()
        return len(self._raw_data)

    def get_image_file(self, index=None):
        return self._image_file

    def get_detectorbase(self, index=None):
        raise NotImplementedError

    @staticmethod
    def get_instrument_name(handle):
        if "short_name" in handle["/entry/instrument"].attrs:
            name = handle["/entry/instrument"].attrs["short_name"]
        elif "/entry/instrument/name" in handle:
            if "short_name" in handle["/entry/instrument/name"].attrs:
                name = handle["/entry/instrument/name"].attrs["short_name"]
            else:
                name = handle["/entry/instrument/name"][()]
        else:
            name = None
        return name