Beispiel #1
0
  def __init__(self, crystal, experiment_ids=None):

    # The state of a crystal orientation parameterisation is an orientation
    # matrix '[U]'. The initial state is a snapshot of the crystal
    # orientation at the time of initialisation '[U0]'. Future states are
    # composed by rotations around axes of the phi-axis frame by Tait-Bryan
    # angles.
    #
    # [U] = [Phi3][Phi2][Phi1][U0]

    # set up the initial state
    if experiment_ids is None:
      experiment_ids = [0]
    istate = matrix.sqr(crystal.get_U())

    # build the parameter list
    p_list = self._build_p_list()

    # set up the base class
    ModelParameterisation.__init__(self, crystal, istate, p_list,
                                   experiment_ids=experiment_ids)

    # call compose to calculate all the derivatives
    self.compose()

    return
    def __init__(
        self,
        model,
        initial_state,
        param_sets,
        smoother,
        experiment_ids,
        is_multi_state=False,
    ):

        ModelParameterisation.__init__(
            self, model, initial_state, param_sets, experiment_ids, is_multi_state
        )

        self._num_sets = len(self._param)
        self._num_samples = len(param_sets[0])
        self._total_len = self._num_samples * self._num_sets

        # ensure all internal parameter sets have the same number of parameters
        for param in self._param[1:]:
            assert len(param) == self._num_samples

        # Link up with an object that will perform the smoothing.
        self._smoother = smoother
        assert self._smoother.num_values() == self._num_samples

        # define an attribute for caching the variance-covariance matrix of
        # parameters
        self._var_cov = None

        return
Beispiel #3
0
  def __init__(self, crystal, experiment_ids=None):

    # The state of the unit cell parameterisation is the reciprocal space
    # orthogonalisation matrix 'B'. The initial state is irrelevant for
    # this model, as composition of a new B matrix and derivatives can be
    # done with just the values of 6 unit cell parameters, without
    # defining axial directions (which are selected by choice of the PDB
    # convention). For this reason also, the axes of the
    # parameters are irrelevant and are set here to None.

    ### Set up the initial state
    if experiment_ids is None:
      experiment_ids = [0]
    istate = None

    # build the parameter list
    p_list = self._build_p_list(crystal)

    # set up the base class
    ModelParameterisation.__init__(self, crystal, istate, p_list,
                                   experiment_ids=experiment_ids)

    # call compose to calculate all the derivatives
    self.compose()

    return
Beispiel #4
0
    def __init__(self, beam, goniometer=None, experiment_ids=None):
        """Initialise the BeamParameterisation object

        Args:
            beam: A dxtbx Beam object to be parameterised.
            goniometer: An optional dxtbx Goniometer object. Defaults to None.
            experiment_ids (list): The experiment IDs affected by this
                parameterisation. Defaults to None, which is replaced by [0].
        """
        # The state of the beam model consists of the s0 vector that it is
        # modelling. The initial state is the direction of this vector at the point
        # of initialisation. Future states are composed by rotations around axes
        # perpendicular to that direction and normalisation specified by the
        # wavenumber (inverse wavelength).

        # Set up the initial state
        if experiment_ids is None:
            experiment_ids = [0]
        s0 = matrix.col(beam.get_s0())
        s0dir = matrix.col(beam.get_unit_s0())
        istate = s0dir

        # build the parameter list
        p_list = self._build_p_list(s0, goniometer)

        # set up the base class
        ModelParameterisation.__init__(
            self, beam, istate, p_list, experiment_ids=experiment_ids
        )

        # call compose to calculate all the derivatives
        self.compose()

        return
    def __init__(self, goniometer, beam=None, experiment_ids=None):

        # The state of the goniometer model consists of the setting matrix [S] that
        # determines the orientation of the rotation axis in the laboratory frame
        # e_lab = [S] e_datum.
        # This parameters are orientation angles around two axes orthogonal to the
        # initial direction of e_lab. If a beam is supplied, one of these axes will
        # be within the plane containing s0 and e_lab.

        # Set up the initial state
        if experiment_ids is None:
            experiment_ids = [0]
        e_lab = matrix.col(goniometer.get_rotation_axis())
        istate = matrix.sqr(goniometer.get_setting_rotation())

        # build the parameter list
        p_list = self._build_p_list(e_lab, beam)

        # set up the base class
        ModelParameterisation.__init__(self,
                                       goniometer,
                                       istate,
                                       p_list,
                                       experiment_ids=experiment_ids)

        # call compose to calculate all the derivatives
        self.compose()

        return
Beispiel #6
0
    def __init__(self, crystal, experiment_ids=None):
        """Initialise the CrystalOrientationParameterisation object

        Args:
            crystal: A dxtbx Crystal object to be parameterised.
            experiment_ids (list): The experiment IDs affected by this
                parameterisation. Defaults to None, which is replaced by [0].
        """

        # The state of a crystal orientation parameterisation is an orientation
        # matrix '[U]'. The initial state is a snapshot of the crystal
        # orientation at the time of initialisation '[U0]'. Future states are
        # composed by rotations around axes of the phi-axis frame by Tait-Bryan
        # angles.
        #
        # [U] = [Phi3][Phi2][Phi1][U0]

        # set up the initial state
        if experiment_ids is None:
            experiment_ids = [0]
        istate = matrix.sqr(crystal.get_U())

        # build the parameter list
        p_list = self._build_p_list()

        # set up the base class
        ModelParameterisation.__init__(
            self, crystal, istate, p_list, experiment_ids=experiment_ids
        )

        # call compose to calculate all the derivatives
        self.compose()

        return
    def __init__(self, goniometer, beam=None, experiment_ids=None):
        """Initialise the GoniometerParameterisation object

        Args:
            goniometer: A dxtbx Beam object to be parameterised.
            beam: An optional dxtbx Beam object. Defaults to None.
            experiment_ids (list): The experiment IDs affected by this
                parameterisation. Defaults to None, which is replaced by [0].
        """
        # The state of the goniometer model consists of the setting matrix [S] that
        # determines the orientation of the rotation axis in the laboratory frame
        # e_lab = [S] e_datum.
        # This parameters are orientation angles around two axes orthogonal to the
        # initial direction of e_lab. If a beam is supplied, one of these axes will
        # be within the plane containing s0 and e_lab.

        # Set up the initial state
        if experiment_ids is None:
            experiment_ids = [0]
        e_lab = matrix.col(goniometer.get_rotation_axis())
        istate = matrix.sqr(goniometer.get_setting_rotation())

        # build the parameter list
        p_list = self._build_p_list(e_lab, beam)

        # set up the base class
        ModelParameterisation.__init__(
            self, goniometer, istate, p_list, experiment_ids=experiment_ids
        )

        # call compose to calculate all the derivatives
        self.compose()

        return
Beispiel #8
0
    def __init__(self, beam, goniometer=None, experiment_ids=None):

        # The state of the beam model consists of the s0 vector that it is
        # modelling. The initial state is the direction of this vector at the point
        # of initialisation. Future states are composed by rotations around axes
        # perpendicular to that direction and normalisation specified by the
        # wavenumber (inverse wavelength).

        # Set up the initial state
        if experiment_ids is None:
            experiment_ids = [0]
        s0 = matrix.col(beam.get_s0())
        s0dir = matrix.col(beam.get_unit_s0())
        istate = s0dir

        # build the parameter list
        p_list = self._build_p_list(s0, goniometer)

        # set up the base class
        ModelParameterisation.__init__(self,
                                       beam,
                                       istate,
                                       p_list,
                                       experiment_ids=experiment_ids)

        # call compose to calculate all the derivatives
        self.compose()

        return
    def __init__(self, detector, experiment_ids=None):
        """Initialise the DetectorParameterisationSinglePanel object

        Args:
            detector: A dxtbx Detector object to be parameterised.
            experiment_ids (list): The experiment IDs affected by this
                parameterisation. Defaults to None, which is replaced by [0].
        """
        # The state of a single Panel is its detector matrix d = (d1|d2|d0).
        # However, for the purposes of parameterisation we choose a different
        # vector than d0 to locate the Panel. That's because we want to perform
        # rotations around a point on the detector surface, and d0 points to the
        # corner of the Panel. To avoid excess correlations between 'tilt' and
        # 'twist' angles with the detector distance, we prefer to perform
        # rotations around a point located at the centre of the Panel. This is
        # usually close to point of intersection with the plane normal drawn
        # from the origin of the laboratory frame.
        #
        # Therefore we define:
        #
        # * a vector 'dorg' locating the centre of the single Panel
        # * a pair of orthogonal unit directions 'd1' and 'd2' forming a plane
        #   with its origin at the end of the vector dorg
        # * a third unit direction 'dn', orthogonal to both 'd1' & 'd2'.
        # * offsets to locate the origin d0 of the Panel frame from the
        #   tip of the dorg vector, in terms of the coordinate system
        #   formed by d1, d2 and dn.
        #
        # Held separately in attribute 'models' are:
        # * references to the detector objects contained in this model
        #
        # For this simplified class there is only a single Panel frame
        # and the vector dn is not actually required, because the plane formed
        # by d1 and d2 is coplanar with the sensor plane. Therefore the
        # offset is fully in terms of d1 and d2

        # set up the initial state of the detector parameterisation from the
        # orientation of the single Panel it contains, in terms of the vectors
        # dorg, d1 and d2.

        if experiment_ids is None:
            experiment_ids = [0]

        dat = self._init_core(detector)

        # set up the base class
        ModelParameterisation.__init__(self,
                                       detector,
                                       dat["istate"],
                                       dat["p_list"],
                                       experiment_ids=experiment_ids)

        # call compose to calculate all the derivatives
        self.compose()
  def __init__(self, model, initial_state, param_sets, smoother,
               experiment_ids, is_multi_state=False):

    ModelParameterisation.__init__(self, model, initial_state, param_sets,
      experiment_ids, is_multi_state)

    self._num_sets = len(self._param)
    self._set_len = len(param_sets[0])
    self._total_len = self._set_len * self._num_sets

    # ensure all internal parameter sets have the same number of parameters
    for param in self._param[1:]: assert len(param) == self._set_len

    # Link up with an object that will perform the smoothing.
    self._smoother = smoother
    assert self._smoother.num_values() == self._set_len

    # define an attribute for caching the variance-covariance matrix of
    # parameters
    self._var_cov = None

    return
    def __init__(self, detector, experiment_ids=None, level=0):
        """Initialise the DetectorParameterisationHierarchical object

        Args:
            detector: A dxtbx Detector object to be parameterised.
            experiment_ids (list): The experiment IDs affected by this
                parameterisation. Defaults to None, which is replaced by [0].
            level (int): Select level of the detector hierarchy to determine panel
                groupings that are treated as separate rigid blocks.
        """

        if experiment_ids is None:
            experiment_ids = [0]

        try:
            h = detector.hierarchy()
        except AttributeError:
            print("This detector does not have a hierarchy")
            raise

        # list the panel groups at the chosen level
        try:
            self._groups = get_panel_groups_at_depth(h, level)
        except AttributeError:
            print("Cannot access the hierarchy at the depth level={}".format(
                level))
            raise

        # collect the panel ids for each Panel within the groups
        panels = list(detector)
        self._panel_ids_by_group = [
            get_panel_ids_at_root(panels, g) for g in self._groups
        ]

        p_list = []
        self._group_ids_by_parameter = []
        istate = []
        self._offsets = []
        self._dir1s = []
        self._dir2s = []

        # loop over the groups, collecting initial parameters and states
        for igp, pnl_ids in enumerate(self._panel_ids_by_group):

            panel_centres_in_lab_frame = []
            for i in pnl_ids:
                pnl = detector[i]
                im_size = pnl.get_image_size_mm()
                cntr = (matrix.col(pnl.get_origin()) +
                        0.5 * matrix.col(pnl.get_fast_axis()) * im_size[0] +
                        0.5 * matrix.col(pnl.get_slow_axis()) * im_size[1])
                panel_centres_in_lab_frame.append(cntr)

            # get some vectors we need from the group
            go = matrix.col(self._groups[igp].get_origin())
            d1 = matrix.col(self._groups[igp].get_fast_axis())
            d2 = matrix.col(self._groups[igp].get_slow_axis())
            dn = matrix.col(self._groups[igp].get_normal())

            # we choose the dorg vector for this group to terminate on the group's
            # frame, at a point that we consider close to the centre of the group of
            # panels. This point is defined by taking the 3D centroid of the panel
            # centres then projecting that point onto the group frame.
            centroid = reduce(
                lambda a, b: a + b,
                panel_centres_in_lab_frame) / len(panel_centres_in_lab_frame)
            try:
                gp_centroid = matrix.col(
                    self._groups[igp].get_bidirectional_ray_intersection(
                        centroid))
                dorg = go + gp_centroid[0] * d1 + gp_centroid[1] * d2
            except RuntimeError:  # workaround for a group frame that passes through
                # the origin
                dorg = matrix.col((0.0, 0.0, 0.0))

            # The offset between the end of the dorg vector and
            # each Panel origin is a coordinate matrix with elements in the basis d1,
            # d2, dn. We need also each Panel's plane directions dir1 and dir2 in
            # terms of d1, d2 and dn.
            offsets, dir1s, dir2s = [], [], []
            # FIXME these dot products would be more efficiently done using a change of
            # basis matrix instead
            for p in [detector[i] for i in pnl_ids]:
                offset = matrix.col(p.get_origin()) - dorg
                offsets.append(
                    matrix.col(
                        (offset.dot(d1), offset.dot(d2), offset.dot(dn))))
                dir1 = matrix.col(p.get_fast_axis())
                dir1_new_basis = matrix.col(
                    (dir1.dot(d1), dir1.dot(d2), dir1.dot(dn)))
                dir1s.append(dir1_new_basis)
                dir2 = matrix.col(p.get_slow_axis())
                dir2_new_basis = matrix.col(
                    (dir2.dot(d1), dir2.dot(d2), dir2.dot(dn)))
                dir2s.append(dir2_new_basis)

            # The offsets and directions in the d1, d2, dn basis are fixed
            # quantities, not dependent on parameter values. Keep these as separate
            # sub-lists for each group
            self._offsets.append(offsets)
            self._dir1s.append(dir1s)
            self._dir2s.append(dir2s)

            # Set up the initial state for this group. This is the basis d1, d2, dn,
            # plus the offset locating the origin of the initial group frame
            gp_offset = go - dorg  # lab frame basis
            # FIXME another set of dot products better done by a matrix multiplication
            gp_offset = matrix.col((gp_offset.dot(d1), gp_offset.dot(d2),
                                    gp_offset.dot(dn)))  # d1,d2,dn basis
            istate.append({
                "d1": d1,
                "d2": d2,
                "dn": dn,
                "gp_offset": gp_offset
            })

            # set up the parameters.
            # distance from lab origin to ref_panel plane along its normal,
            # in initial orientation
            distance = self._groups[igp].get_directed_distance()
            dist = Parameter(distance, dn, "length (mm)",
                             "Group{}Dist".format(igp + 1))

            # shift in the detector model plane to locate dorg, in initial
            # orientation
            shift = dorg - dn * distance
            shift1 = Parameter(shift.dot(d1), d1, "length (mm)",
                               "Group{}Shift1".format(igp + 1))
            shift2 = Parameter(shift.dot(d2), d2, "length (mm)",
                               "Group{}Shift2".format(igp + 1))

            # rotations of the plane through its origin about:
            # 1) axis normal to initial orientation
            # 2) d1 axis of initial orientation
            # 3) d2 axis of initial orientation
            tau1 = Parameter(0, dn, "angle (mrad)",
                             "Group{}Tau1".format(igp + 1))
            tau2 = Parameter(0, d1, "angle (mrad)",
                             "Group{}Tau2".format(igp + 1))
            tau3 = Parameter(0, d2, "angle (mrad)",
                             "Group{}Tau3".format(igp + 1))

            # extend the parameter list with those pertaining to this group
            p_list.extend([dist, shift1, shift2, tau1, tau2, tau3])
            self._group_ids_by_parameter.extend([igp] * 6)

        # set up the base class
        ModelParameterisation.__init__(
            self,
            detector,
            istate,
            p_list,
            experiment_ids=experiment_ids,
            is_multi_state=True,
        )

        # call compose to calculate all the derivatives
        self.compose()
    def __init__(self, detector, beam, experiment_ids=None):
        """Initialise the DetectorParameterisationMultiPanel object

        Args:
            detector: A dxtbx Detector object to be parameterised.
            beam: An dxtbx beam object used to calculate the closest panel.
            experiment_ids (list): The experiment IDs affected by this
                parameterisation. Defaults to None, which is replaced by [0].
        """
        # The state of each Panel in the detector model is its matrix
        # d = (d1|d2|d0). We need to define a new coordinate system rigidly
        # attached to the detector model in which to express the
        # parameterisation and compose each of the Panel states.
        #
        # We define:
        #
        # * a vector 'dorg' locating a point in laboratory space that moves with
        #   the rigid body of the detector and thus is fixed wrt each of the
        #   Panels.
        # * A pair of orthogonal unit directions 'd1' and 'd2' forming a plane
        #   with its origin at the end of the vector dorg.
        # * a third unit direction 'dn', orthogonal to both 'd1' & 'd2'.
        # * offsets to locate the origin of each panel frame from the
        #   tip of the dorg vector, in terms of the coordinate system
        #   formed by d1, d2 and dn.
        #
        # Held separately in attribute 'models' are:
        # * references to detector objects contained in this model

        # set up the initial state of the detector model from the
        # orientation of whichever Panel has its centre most closely
        # located to the direct beam intersection. Call this 'mid_panel'

        if experiment_ids is None:
            experiment_ids = [0]
        beam_centres = [
            matrix.col(p.get_beam_centre(beam.get_unit_s0())) for p in detector
        ]
        panel_centres = [
            0.5 * matrix.col(p.get_image_size_mm()) for p in detector
        ]
        beam_to_centres = [(a - b).length()
                           for a, b in zip(beam_centres, panel_centres)]
        mid_panel_id = beam_to_centres.index(min(beam_to_centres))
        mid_panel = detector[mid_panel_id]

        # get some vectors we need from the mid_panel
        so = matrix.col(mid_panel.get_origin())
        d1 = matrix.col(mid_panel.get_fast_axis())
        d2 = matrix.col(mid_panel.get_slow_axis())
        dn = matrix.col(mid_panel.get_normal())

        # we choose the dorg vector to terminate in the centre of the mid_panel,
        # and the offset between the end of the dorg vector and each Panel
        # origin is a coordinate matrix with elements in the basis d1, d2, dn.
        # We need also each Panel's plane directions dir1 and dir2 in terms of
        # d1, d2 and dn.
        mid_panel_centre = panel_centres[mid_panel_id]
        dorg = so + mid_panel_centre[0] * d1 + mid_panel_centre[1] * d2

        offsets, dir1s, dir2s = [], [], []
        for p in detector:
            offset = matrix.col(p.get_origin()) - dorg
            offsets.append(
                matrix.col((offset.dot(d1), offset.dot(d2), offset.dot(dn))))
            dir1 = matrix.col(p.get_fast_axis())
            dir1_new_basis = matrix.col(
                (dir1.dot(d1), dir1.dot(d2), dir1.dot(dn)))
            dir1s.append(dir1_new_basis)
            dir2 = matrix.col(p.get_slow_axis())
            dir2_new_basis = matrix.col(
                (dir2.dot(d1), dir2.dot(d2), dir2.dot(dn)))
            dir2s.append(dir2_new_basis)

        # The offsets and directions in the d1, d2, dn basis are fixed
        # quantities, not dependent on parameter values.
        self._offsets = offsets
        self._dir1s = dir1s
        self._dir2s = dir2s

        # Set up the initial state. This is the basis d1, d2, dn.
        istate = {"d1": d1, "d2": d2, "dn": dn}

        # set up the parameters.
        # distance from lab origin to mid_panel plane along its normal,
        # in initial orientation
        distance = mid_panel.get_directed_distance()
        dist = Parameter(distance, dn, "length (mm)", "Dist")

        # shift in the detector model plane to locate dorg, in initial
        # orientation
        shift = dorg - dn * distance
        shift1 = Parameter(shift.dot(d1), d1, "length (mm)", "Shift1")
        shift2 = Parameter(shift.dot(d2), d2, "length (mm)", "Shift2")

        # rotations of the plane through its origin about:
        # 1) axis normal to initial orientation
        # 2) d1 axis of initial orientation
        # 3) d2 axis of initial orientation
        tau1 = Parameter(0, dn, "angle (mrad)", "Tau1")
        tau2 = Parameter(0, d1, "angle (mrad)", "Tau2")
        tau3 = Parameter(0, d2, "angle (mrad)", "Tau3")

        # build the parameter list in a specific,  maintained order
        p_list = [dist, shift1, shift2, tau1, tau2, tau3]

        # set up the base class
        ModelParameterisation.__init__(
            self,
            detector,
            istate,
            p_list,
            experiment_ids=experiment_ids,
            is_multi_state=True,
        )

        # call compose to calculate all the derivatives
        self.compose()