def _prepare_for_compose(self, reflections, skip_derivatives=False):
        """Add columns to the reflection table to hold the varying state matrices
    or vectors for the experimental models, if required. Also prepare the cache
    for the derivatives of states that are scan-varying"""

        nref = len(reflections)
        # set columns if needed
        if 'u_matrix' not in reflections:
            reflections['u_matrix'] = flex.mat3_double(nref)
        if 'b_matrix' not in reflections:
            reflections['b_matrix'] = flex.mat3_double(nref)
        if 's0_vector' not in reflections:
            reflections['s0_vector'] = flex.vec3_double(nref)
        if 'd_matrix' not in reflections:
            reflections['d_matrix'] = flex.mat3_double(nref)
        if 'D_matrix' not in reflections:
            reflections['D_matrix'] = flex.mat3_double(nref)
        if 'S_matrix' not in reflections:
            reflections['S_matrix'] = flex.mat3_double(nref)

        # Clear the state derivative cache and set the number of reflections needed
        # to reconstruct the derivative arrays later
        self._derivative_cache.clear()
        self._derivative_cache.nref = nref

        return
Пример #2
0
def test_scan_varying_results_are_close_to_static_prediction_when_model_is_static(
        static_test,  # noqa: F811, not a redefinition
):
    """Test that various modes of scan-varying prediction produce results
    close to static prediction when the supplied models are indeed static"""

    # Get static predictor results

    scan = static_test.experiments[0].scan
    crystal = static_test.experiments[0].crystal
    beam = static_test.experiments[0].beam
    goniometer = static_test.experiments[0].goniometer
    n_scan_points = scan.get_num_images() + 1
    static_preds = static_test.predict_new()
    static_preds.sort("miller_index")

    # Set up scan-varying predictor
    from dials.algorithms.spot_prediction import ScanVaryingReflectionPredictor
    from dials.array_family import flex

    predict = ScanVaryingReflectionPredictor(static_test.experiments[0])

    def compare(refs1, refs2):
        assert len(refs1) == len(refs2)
        for r1, r2 in zip(refs1.rows(), refs2.rows()):
            assert r1["miller_index"] == r2["miller_index"]
            # differences less than one hundredth of a pixel/image
            for e1, e2 in zip(r1["xyzcal.px"], r2["xyzcal.px"]):
                assert e1 == pytest.approx(e2, abs=0.01)

    # Prediction for UB matrix expressed as array of static UB
    A = [crystal.get_A() for i in range(n_scan_points)]
    result1 = predict.for_ub(flex.mat3_double(A))
    result1.sort("miller_index")
    compare(static_preds, result1)

    # Prediction for UB matrix, s0 vectors and goniometer setting rotation
    # matrices expressed as arrays of static model states
    s0 = [beam.get_s0() for i in range(n_scan_points)]
    S = [goniometer.get_setting_rotation() for i in range(n_scan_points)]
    result2 = predict.for_varying_models(flex.mat3_double(A),
                                         flex.vec3_double(s0),
                                         flex.mat3_double(S))
    result2.sort("miller_index")
    compare(static_preds, result2)

    # First frame only, start and end UB
    _, _, z = static_preds["xyzcal.px"].parts()
    static_preds_frame0 = static_preds.select((z >= 0) & (z < 1))
    A = crystal.get_A()
    result3 = predict.for_ub_on_single_image(0, A, A)
    result3.sort("miller_index")
    compare(static_preds_frame0, result3)

    # First frame only, start and end UB, s0 and S
    s0 = beam.get_s0()
    S = goniometer.get_setting_rotation()
    result4 = predict.for_varying_models_on_single_image(0, A, A, s0, s0, S, S)
    result4.sort("miller_index")
    compare(static_preds_frame0, result4)
Пример #3
0
def test_for_reflection_table(data):
    from dials.algorithms.spot_prediction import (
        ScanStaticReflectionPredictor,
        ScanVaryingReflectionPredictor,
    )
    from dials.array_family import flex

    predict = ScanStaticReflectionPredictor(data.experiments[0])
    preds = predict.for_ub(data.experiments[0].crystal.get_A())

    preds["ub_matrix"] = flex.mat3_double(len(preds),
                                          data.experiments[0].crystal.get_A())
    preds["s0"] = flex.vec3_double(len(preds),
                                   data.experiments[0].beam.get_s0())
    preds["d_matrix"] = flex.mat3_double(len(preds))
    preds["S_matrix"] = flex.mat3_double(
        len(preds), data.experiments[0].goniometer.get_setting_rotation())
    for ipanel, panel in enumerate(data.experiments[0].detector):
        sel = preds["panel"] == ipanel
        D = panel.get_d_matrix()
        preds["d_matrix"].set_selected(sel, D)
    predict = ScanVaryingReflectionPredictor(data.experiments[0])
    old_preds = copy.deepcopy(preds)
    predict.for_reflection_table(preds, preds["ub_matrix"], preds["s0"],
                                 preds["d_matrix"], preds["S_matrix"])

    # Because UB, s0, d and S values are the same for all reflections, the new
    # reflections should be approx equal to those produced by the scan static
    # predictor
    old_x, old_y, old_z = old_preds["xyzcal.px"].parts()
    new_x, new_y, new_z = preds["xyzcal.px"].parts()
    assert old_x.all_approx_equal(new_x)
    assert old_y.all_approx_equal(new_y)
    assert old_z.all_approx_equal(new_z)
    def jacobian_callable(self,values):
      PB = self.get_partiality_array(values)
      EXP = flex.exp(-2.*values.BFACTOR*self.DSSQ)
      G_terms = (EXP * PB * self.ICALCVEC)
      B_terms = (values.G * EXP * PB * self.ICALCVEC)*(-2.*self.DSSQ)
      P_terms = (values.G * EXP * self.ICALCVEC)

      thetax = values.thetax; thetay = values.thetay;
      Rx = matrix.col((1,0,0)).axis_and_angle_as_r3_rotation_matrix(thetax)
      dRx_dthetax = matrix.col((1,0,0)).axis_and_angle_as_r3_derivative_wrt_angle(thetax)
      Ry = matrix.col((0,1,0)).axis_and_angle_as_r3_rotation_matrix(thetay)
      dRy_dthetay = matrix.col((0,1,0)).axis_and_angle_as_r3_derivative_wrt_angle(thetay)
      ref_ori = matrix.sqr(self.ORI.reciprocal_matrix())
      miller_vec = self.MILLER.as_vec3_double()
      ds1_dthetax = flex.mat3_double(len(self.MILLER),Ry * dRx_dthetax * ref_ori) * miller_vec
      ds1_dthetay = flex.mat3_double(len(self.MILLER),dRy_dthetay * Rx * ref_ori) * miller_vec

      s1vec = self.get_s1_array(values)
      s1lenvec = flex.sqrt(s1vec.dot(s1vec))
      dRh_dthetax = s1vec.dot(ds1_dthetax)/s1lenvec
      dRh_dthetay = s1vec.dot(ds1_dthetay)/s1lenvec
      rs = values.RS
      Rh = self.get_Rh_array(values)
      rs_sq = rs*rs
      denomin = (2. * Rh * Rh + rs_sq)
      dPB_dRh = -PB * 4. * Rh / denomin
      dPB_dthetax = dPB_dRh * dRh_dthetax
      dPB_dthetay = dPB_dRh * dRh_dthetay
      Px_terms = P_terms * dPB_dthetax; Py_terms = P_terms * dPB_dthetay

      dPB_drs = 4 * rs * Rh * Rh / (denomin * denomin)
      Prs_terms = P_terms * dPB_drs

      return [G_terms,B_terms,Prs_terms,Px_terms,Py_terms]
Пример #5
0
    def jacobian_callable(self,values):
      PB = self.get_partiality_array(values)
      EXP = flex.exp(-2.*values.BFACTOR*self.DSSQ)
      G_terms = (EXP * PB * self.ICALCVEC)
      B_terms = (values.G * EXP * PB * self.ICALCVEC)*(-2.*self.DSSQ)
      P_terms = (values.G * EXP * self.ICALCVEC)

      thetax = values.thetax; thetay = values.thetay;
      Rx = matrix.col((1,0,0)).axis_and_angle_as_r3_rotation_matrix(thetax)
      dRx_dthetax = matrix.col((1,0,0)).axis_and_angle_as_r3_derivative_wrt_angle(thetax)
      Ry = matrix.col((0,1,0)).axis_and_angle_as_r3_rotation_matrix(thetay)
      dRy_dthetay = matrix.col((0,1,0)).axis_and_angle_as_r3_derivative_wrt_angle(thetay)
      ref_ori = matrix.sqr(self.ORI.reciprocal_matrix())
      miller_vec = self.MILLER.as_vec3_double()
      ds1_dthetax = flex.mat3_double(len(self.MILLER),Ry * dRx_dthetax * ref_ori) * miller_vec
      ds1_dthetay = flex.mat3_double(len(self.MILLER),dRy_dthetay * Rx * ref_ori) * miller_vec

      s1vec = self.get_s1_array(values)
      s1lenvec = flex.sqrt(s1vec.dot(s1vec))
      dRh_dthetax = s1vec.dot(ds1_dthetax)/s1lenvec
      dRh_dthetay = s1vec.dot(ds1_dthetay)/s1lenvec
      rs = values.RS
      Rh = self.get_Rh_array(values)
      rs_sq = rs*rs
      denomin = (2. * Rh * Rh + rs_sq)
      dPB_dRh = { "lorentzian": -PB * 4. * Rh / denomin,
                  "gaussian": -PB * 4. * math.log(2) * Rh / rs_sq }[self.profile_shape]
      dPB_dthetax = dPB_dRh * dRh_dthetax
      dPB_dthetay = dPB_dRh * dRh_dthetay
      Px_terms = P_terms * dPB_dthetax; Py_terms = P_terms * dPB_dthetay

      return [G_terms,B_terms,0,Px_terms,Py_terms]
def merging_crystal_table(postrefinement_columns=False):
    table = flex.reflection_table()
    table['u_matrix'] = flex.mat3_double()
    table['b_matrix'] = flex.mat3_double()
    table['wavelength'] = flex.double()
    if postrefinement_columns:
        table['G'] = flex.double()
        table['B'] = flex.double()
        table['RS'] = flex.double()
        table['thetax'] = flex.double()
        table['thetay'] = flex.double()
    table['ETA'] = flex.double()
    table['DEFF'] = flex.double()
    table['n_refl'] = flex.size_t()
    return table
Пример #7
0
  def get_gradients(self, reflections, callback=None):
    """
    Calculate gradients of the prediction formula with respect to each
    of the parameters of the contained models, for all of the reflections.

    To be implemented by a derived class, which determines the space of the
    prediction formula (e.g. we calculate dX/dp, dY/dp, dphi/dp for the
    prediction formula for a rotation scan expressed in detector space, but
    components of d\vec{r}/dp for the prediction formula in reciprocal space

    """

    ### Calculate various quantities of interest for the reflections

    # Set up arrays of values for each reflection
    n = len(reflections)
    D = flex.mat3_double(n)
    s0 = flex.vec3_double(n)
    U = flex.mat3_double(n)
    B = flex.mat3_double(n)
    axis = flex.vec3_double(n)
    fixed_rotation = flex.mat3_double(n)

    for iexp, exp in enumerate(self._experiments):

      sel = reflections['id'] == iexp
      isel = sel.iselection()

      # D matrix array
      panels = reflections['panel'].select(isel)
      for ipanel, D_mat in enumerate([p.get_D_matrix() for p in exp.detector]):
        subsel = isel.select(panels == ipanel)
        D.set_selected(subsel, D_mat)

      # s0 array
      s0.set_selected(isel, exp.beam.get_s0())

      # U and B arrays
      exp_U, exp_B = self._get_U_B_for_experiment(exp.crystal, reflections, isel)
      U.set_selected(isel, exp_U)
      B.set_selected(isel, exp_B)

      # axis array
      if exp.goniometer:
        axis.set_selected(isel, exp.goniometer.get_rotation_axis())
        fixed_rotation.set_selected(isel, exp.goniometer.get_fixed_rotation())

    return self._get_gradients_core(reflections, D, s0, U, B, axis, fixed_rotation, callback)
Пример #8
0
 def get_Rh_array(self, values):
     eff_Astar = self.get_eff_Astar(values)
     h = self.MILLER.as_vec3_double()
     x = flex.mat3_double(len(self.MILLER), eff_Astar) * h
     Svec = x + self.BEAM
     Rh = Svec.norms() - (1. / self.WAVE)
     return Rh
Пример #9
0
    def _detector_derivatives(self,
                              isel,
                              panel_id,
                              parameterisation=None,
                              dd_ddet_p=None,
                              reflections=None):
        """Helper function to convert derivatives of the detector state to
    derivatives of the vector pv. Derivatives that would all be null vectors
    are replaced with None"""

        # Get required data
        pv = self._pv.select(isel)
        D = self._D.select(isel)

        if dd_ddet_p is None:

            # get the derivatives of detector d matrix for this panel
            dd_ddet_p = parameterisation.get_ds_dp(multi_state_elt=panel_id,
                                                   use_none_as_null=True)

            # replace explicit null derivatives with None
            dd_ddet_p = [None if e is None else \
                         flex.mat3_double(len(D), e.elems) for e in dd_ddet_p]

        # calculate the derivative of pv for this parameter
        dpv_ddet_p = [
            der if der is None else (D * (der * -1.)) * pv for der in dd_ddet_p
        ]

        return dpv_ddet_p
Пример #10
0
  def _xl_orientation_derivatives(self, xlop, axis, fixed_rotation, phi_calc, h, s1, e_X_r, e_r_s0, B, D):
    """helper function to extend the derivatives lists by
    derivatives of the crystal orientation parameterisations"""

    # get derivatives of the U matrix wrt the parameters
    dU_dxlo_p = xlop.get_ds_dp()

    dphi_dp = []
    dpv_dp = []

    # loop through the parameters
    for der in dU_dxlo_p:

      der_mat = flex.mat3_double(len(B), der.elems)
      # calculate the derivative of r for this parameter
      # FIXME COULD DO THIS BETTER WITH __rmul__?!
      tmp = fixed_rotation * (der_mat * B * h)
      dr = tmp.rotate_around_origin(axis, phi_calc)

      # calculate the derivative of phi for this parameter
      dphi = -1.0 * dr.dot(s1) / e_r_s0
      dphi_dp.append(dphi)

      # calculate the derivative of pv for this parameter
      dpv_dp.append(D * (dr + e_X_r * dphi))

    return dpv_dp, dphi_dp
Пример #11
0
  def _xl_unit_cell_derivatives(self, xlucp, axis, fixed_rotation, phi_calc, h, s1, e_X_r, e_r_s0, U, D):
    """helper function to extend the derivatives lists by
    derivatives of the crystal unit cell parameterisations"""

    # get derivatives of the B matrix wrt the parameters
    dB_dxluc_p = xlucp.get_ds_dp()

    dphi_dp = []
    dpv_dp = []

    # loop through the parameters
    for der in dB_dxluc_p:

      der_mat = flex.mat3_double(len(U), der.elems)
      # calculate the derivative of r for this parameter
      tmp = fixed_rotation * (U * der_mat * h)
      dr = tmp.rotate_around_origin(axis, phi_calc)

      # calculate the derivative of phi for this parameter
      dphi = -1.0 * dr.dot(s1) / e_r_s0
      dphi_dp.append(dphi)

      # calculate the derivative of pv for this parameter
      dpv_dp.append(D * (dr + e_X_r * dphi))

    return dpv_dp, dphi_dp
Пример #12
0
    def predict_reflections(self, experiment, dmin=None, dmax=None, **kwargs):
        """Predict the reflections."""
        from dials.algorithms.spot_prediction import ScanVaryingReflectionPredictor
        from dials.array_family import flex

        # Create the scan varying reflection predictor
        predictor = ScanVaryingReflectionPredictor(experiment,
                                                   dmin=dmin,
                                                   margin=1)

        # Get length of scan
        scan_len = experiment.scan.get_num_images()
        crystal = experiment.crystal

        # Get the A matrices
        if crystal.num_scan_points == 0:
            A = [crystal.get_A() for i in range(scan_len + 1)]
        else:
            assert (crystal.num_scan_points) == scan_len + 1
            A = [crystal.get_A_at_scan_point(i) for i in range(scan_len + 1)]

        # Do the prediction
        result = predictor.for_ub(flex.mat3_double(A))
        if dmax is not None:
            assert dmax > 0
            result.compute_d_single(experiment)
            mask = result["d"] > dmax
            result.del_selected(mask)

        # Return the reflections
        return result
Пример #13
0
  def _xl_unit_cell_derivatives(self, isel, parameterisation=None,
    reflections=None):

    # Get required data
    h = self._h.select(isel)
    B = self._B.select(isel)
    wl = self._wavelength.select(isel)

    # get derivatives of the B matrix wrt the parameters
    dB_dxluc_p = [None if der is None else flex.mat3_double(len(isel), der.elems) \
                  for der in parameterisation.get_ds_dp(use_none_as_null=True)]

    d2theta_dp = []

    # loop through the parameters
    for der in dB_dxluc_p:

      if der is None:
        d2theta_dp.append(None)
        continue

      r0 = B * h
      dr0 = der * h
      r0len = r0.norms()
      dr0len = dr0.dot(r0) / r0len

      # 2theta = 2 * arcsin( |r0| / (2 * |s0| ) )
      sintheta = 0.5 * r0len * wl
      fac = 1.0 / flex.sqrt(flex.double(len(wl), 1.0) - sintheta**2)
      val = fac * wl * dr0len

      d2theta_dp.append(val)

    return d2theta_dp
Пример #14
0
    def _xl_unit_cell_derivatives(self, isel, parameterisation=None, reflections=None):

        # Get required data
        h = self._h.select(isel)
        B = self._B.select(isel)
        wl = self._wavelength.select(isel)

        # get derivatives of the B matrix wrt the parameters
        dB_dxluc_p = [
            None if der is None else flex.mat3_double(len(isel), der.elems)
            for der in parameterisation.get_ds_dp(use_none_as_null=True)
        ]

        d2theta_dp = []

        # loop through the parameters
        for der in dB_dxluc_p:

            if der is None:
                d2theta_dp.append(None)
                continue

            r0 = B * h
            dr0 = der * h
            r0len = r0.norms()
            dr0len = dr0.dot(r0) / r0len

            # 2theta = 2 * arcsin( |r0| / (2 * |s0| ) )
            sintheta = 0.5 * r0len * wl
            fac = 1.0 / flex.sqrt(flex.double(len(wl), 1.0) - flex.pow2(sintheta))
            val = fac * wl * dr0len

            d2theta_dp.append(val)

        return d2theta_dp
Пример #15
0
  def run(self, experiments, reflections):
    result = flex.reflection_table()

    for expt_id, experiment in enumerate(experiments):
      refls = reflections.select(reflections['id'] == expt_id)

      A = flex.mat3_double(len(refls), experiment.crystal.get_A())
      s0 = flex.vec3_double(len(refls), experiment.beam.get_s0())
      q = A * refls['miller_index'].as_vec3_double()
      rh = (q + s0).norms() - 1/experiment.beam.get_wavelength()
      eta = 2*math.pi/180 * experiment.crystal.get_half_mosaicity_deg()
      rs = (1/experiment.crystal.get_domain_size_ang()) + (eta/2/refls['d'])

      p_G = flex.exp(-2*ln2*rh**2/rs**2)

      dp_G_drs = p_G * 4 * ln2 * rh**2 / rs**2

      refls['rh'] = rh
      refls['rs'] = rs
      refls['p_G'] = p_G
      refls['dp_G_drs'] = dp_G_drs

      result.extend(refls)

    return experiments, result
Пример #16
0
    def _get_model_data_for_experiment(self, experiment, reflections):
        """Helper function to return model data s0, U, B, D and S for a particular
        experiment. D is always returned as an array the same length as the
        reflections for the experiment, whereas here s0, U, B and S are returned as
        single matrices or vectors. In the scan-varying overload these will all be
        arrays."""

        # D matrix array
        D = flex.mat3_double(len(reflections))
        panels = reflections["panel"]
        for ipanel, D_mat in enumerate(
            [p.get_D_matrix() for p in experiment.detector]):
            sel = panels == ipanel
            D.set_selected(sel, D_mat)

        result = {
            "s0": experiment.beam.get_s0(),
            "U": matrix.sqr(experiment.crystal.get_U()),
            "B": matrix.sqr(experiment.crystal.get_B()),
            "D": D,
        }

        # If a goniometer is present, get the setting matrix too
        if experiment.goniometer:
            result["S"] = matrix.sqr(
                experiment.goniometer.get_setting_rotation())

        return result
Пример #17
0
def mosaic_blocks(mos_spread_deg,
                  mos_domains,
                  twister_seed=None,
                  random_seed=None):
    """
    Code from LS49 for adjusting mosaicity of simulation
    :param mos_spread_deg: spread in degrees
    :param mos_domains: number of mosaic domains
    :param twister_seed: default from ls49 code
    :param random_seed: default from ls49 code
    :return:
    """
    UMAT_nm = flex.mat3_double()
    if twister_seed is None:
        twister_seed = 777
    if random_seed is None:
        random_seed = 777
    mersenne_twister = flex.mersenne_twister(seed=twister_seed)
    scitbx.random.set_random_seed(random_seed)
    rand_norm = scitbx.random.normal_distribution(mean=0,
                                                  sigma=mos_spread_deg *
                                                  np.pi / 180.)
    g = scitbx.random.variate(rand_norm)
    mosaic_rotation = g(mos_domains)
    for m in mosaic_rotation:
        site = col(mersenne_twister.random_double_point_on_sphere())
        UMAT_nm.append(site.axis_and_angle_as_r3_rotation_matrix(m, deg=False))
        UMAT_nm.append(site.axis_and_angle_as_r3_rotation_matrix(
            -m, deg=False))  # NOTE: make symmetric dist
    return UMAT_nm
Пример #18
0
def test_auto_reduction_parameter_extension_modules_part2(setup_test_sorting):
    # Cut-down original algorithm for AutoReduce._unit_cell_surplus_reflections

    from dials_refinement_helpers_ext import uc_surpl_iter as uc_surpl

    r, r_sorted, exp_ids = setup_test_sorting
    isel = flex.size_t()
    for exp_id in exp_ids:
        isel.extend((r["id"] == exp_id).iselection())
    ref = r.select(isel)
    h = ref["miller_index"].as_vec3_double()
    dB_dp = flex.mat3_double([(1, 2, 3, 4, 5, 6, 7, 8, 9),
                              (0, 1, 0, 1, 0, 1, 0, 1, 0)])
    nref_each_param = []
    for der in dB_dp:
        tst = (der * h).norms()
        nref_each_param.append((tst > 0.0).count(True))
    res0 = min(nref_each_param)

    # Updated algorithm for _unit_cell_surplus_reflections
    res1_unsrt_int = uc_surpl(r["id"], r["miller_index"], exp_ids,
                              dB_dp).result
    res1_int = uc_surpl(r_sorted["id"], r_sorted["miller_index"], exp_ids,
                        dB_dp).result
    res1_sizet = uc_surpl(flex.size_t(list(r_sorted["id"])),
                          r_sorted["miller_index"], exp_ids, dB_dp).result
    assert res0 != res1_unsrt_int
    assert res0 == res1_int
    assert res0 == res1_sizet
    def get_beam_gradients(self, reflections):

        ds0_dbeam_p = self.beam_parameterisation.get_ds_dp()
        p_names = self.beam_parameterisation.get_param_names()

        n = len(reflections)
        U = flex.mat3_double(n, self.U)
        B = flex.mat3_double(n, self.B)
        UB = U * B

        # q is the reciprocal lattice vector, in the lab frame
        h = reflections['miller_index'].as_vec3_double()
        q = (UB * h)
        qlen = q.norms()
        qlen2 = q.dot(q)

        q_s0 = q + self.s0
        s1 = reflections['s1']
        ss = qlen2 + 2 * q.dot(self.s0) + self.s0len2
        assert (ss > 0.0).all_eq(True)
        s = flex.sqrt(ss)
        sss = s * ss
        inv_s = 1.0 / s
        inv_sss = 1.0 / sss

        # check equation 10
        tmp = self.s0len * (q_s0) / s
        for a, b in zip(s1, tmp):
            assert a == pytest.approx(b, abs=1e-7)

        ds1_dp = {}

        # loop through the parameters
        for name, der in zip(p_names, ds0_dbeam_p):

            # term1
            term1 = self.us0.dot(der) * q_s0 + self.s0len * (der)
            term1 = term1 * inv_s

            # term2
            term2 = self.s0len * q_s0 * q_s0.dot(der)
            term2 = term2 * inv_sss

            name = 'Beam1' + name  # XXXX Hack to get matching keys
            ds1_dp[name] = {'ds1': (term1 - term2)}

        return ds1_dp
  def get_beam_gradients(self, reflections):

    ds0_dbeam_p = self.beam_parameterisation.get_ds_dp()
    p_names = self.beam_parameterisation.get_param_names()

    n = len(reflections)
    U = flex.mat3_double(n, self.U)
    B = flex.mat3_double(n, self.B)
    UB = U*B

    # q is the reciprocal lattice vector, in the lab frame
    h = reflections['miller_index'].as_vec3_double()
    q = (UB * h)
    qlen = q.norms()
    qlen2 = q.dot(q)

    q_s0 = q + self.s0
    s1 = reflections['s1']
    ss = qlen2 + 2 * q.dot(self.s0) + self.s0len2
    assert (ss > 0.0).all_eq(True)
    s = flex.sqrt(ss)
    sss = s * ss
    inv_s = 1.0 / s
    inv_sss = 1.0 / sss

    # check equation 10
    tmp = self.s0len * (q_s0) / s
    for a, b in zip(s1, tmp): assert approx_equal(a, b)

    ds1_dp = {}

    # loop through the parameters
    for name, der in zip(p_names, ds0_dbeam_p):

      # term1
      term1 = self.us0.dot(der) * q_s0 + self.s0len * (der)
      term1 = term1 * inv_s

      # term2
      term2 = self.s0len * q_s0 * q_s0.dot(der)
      term2 = term2 * inv_sss

      name = 'Beam1' + name # XXXX Hack to get matching keys
      ds1_dp[name] = {'ds1':(term1 - term2)}

    return ds1_dp
    def get_crystal_unit_cell_gradients(self, reflections):

        # get derivatives of the B matrix wrt the parameters
        dB_dxluc_p = self.xl_unit_cell_parameterisation.get_ds_dp()
        p_names = self.xl_unit_cell_parameterisation.get_param_names()

        n = len(reflections)
        U = flex.mat3_double(n, self.U)
        B = flex.mat3_double(n, self.B)
        UB = U * B

        # q is the reciprocal lattice vector, in the lab frame
        h = reflections['miller_index'].as_vec3_double()
        q = (UB * h)
        qlen = q.norms()
        qlen2 = q.dot(q)

        q_s0 = q + self.s0
        s1 = reflections['s1']
        ss = qlen2 + 2 * q.dot(self.s0) + self.s0len2
        assert (ss > 0.0).all_eq(True)
        s = flex.sqrt(ss)
        sss = s * ss
        inv_s = 1.0 / s
        inv_sss = 1.0 / sss

        ds1_dp = {}

        # loop through the parameters
        for name, der in zip(p_names, dB_dxluc_p):

            # calculate the derivative of q for this parameter
            dq = U * flex.mat3_double(n, der.elems) * h

            # term1
            term1 = self.s0len * dq
            term1 = term1 * inv_s

            # term2
            term2 = self.s0len * q_s0 * q_s0.dot(dq)
            term2 = term2 * inv_sss

            name = 'Crystal1' + name  # XXXX Hack to get matching keys
            ds1_dp[name] = {'ds1': (term1 - term2)}

        return ds1_dp
Пример #22
0
 def get_s1_array(self, values):
   miller_vec = self.MILLER.as_vec3_double()
   ref_ori = matrix.sqr(self.ORI.reciprocal_matrix())
   Rx = matrix.col((1,0,0)).axis_and_angle_as_r3_rotation_matrix(values.thetax)
   Ry = matrix.col((0,1,0)).axis_and_angle_as_r3_rotation_matrix(values.thetay)
   s_array = flex.mat3_double(len(self.MILLER),Ry * Rx * ref_ori) * miller_vec
   s1_array = s_array + flex.vec3_double(len(self.MILLER), self.BEAM)
   return s1_array
  def get_crystal_unit_cell_gradients(self, reflections):

    # get derivatives of the B matrix wrt the parameters
    dB_dxluc_p = self.xl_unit_cell_parameterisation.get_ds_dp()
    p_names = self.xl_unit_cell_parameterisation.get_param_names()

    n = len(reflections)
    U = flex.mat3_double(n, self.U)
    B = flex.mat3_double(n, self.B)
    UB = U*B

    # q is the reciprocal lattice vector, in the lab frame
    h = reflections['miller_index'].as_vec3_double()
    q = (UB * h)
    qlen = q.norms()
    qlen2 = q.dot(q)

    q_s0 = q + self.s0
    s1 = reflections['s1']
    ss = qlen2 + 2 * q.dot(self.s0) + self.s0len2
    assert (ss > 0.0).all_eq(True)
    s = flex.sqrt(ss)
    sss = s * ss
    inv_s = 1.0 / s
    inv_sss = 1.0 / sss

    ds1_dp = {}

    # loop through the parameters
    for name, der in zip(p_names, dB_dxluc_p):

      # calculate the derivative of q for this parameter
      dq = U * flex.mat3_double(n, der.elems) * h

      # term1
      term1 = self.s0len * dq
      term1 = term1 * inv_s

      # term2
      term2 = self.s0len * q_s0 * q_s0.dot(dq)
      term2 = term2 * inv_sss

      name = 'Crystal1' + name # XXXX Hack to get matching keys
      ds1_dp[name] = {'ds1':(term1 - term2)}

    return ds1_dp
 def get_s1_array(self, values):
   miller_vec = self.MILLER.as_vec3_double()
   ref_ori = matrix.sqr(self.ORI.reciprocal_matrix())
   Rx = matrix.col((1,0,0)).axis_and_angle_as_r3_rotation_matrix(values.thetax)
   Ry = matrix.col((0,1,0)).axis_and_angle_as_r3_rotation_matrix(values.thetay)
   s_array = flex.mat3_double(len(self.MILLER),Ry * Rx * ref_ori) * miller_vec
   s1_array = s_array + flex.vec3_double(len(self.MILLER), self.BEAM)
   return s1_array
    def _xl_unit_cell_derivatives(self,
                                  isel,
                                  parameterisation=None,
                                  reflections=None):
        """helper function to extend the derivatives lists by
        derivatives of the crystal unit cell parameterisations"""

        # Get required data
        U = self._U.select(isel)
        h = self._h.select(isel)
        e1 = self._e1.select(isel)
        DeltaPsi = self._DeltaPsi.select(isel)
        s1 = self._s1.select(isel)
        nu = self._nu.select(isel)
        q_s0 = self._q_s0.select(isel)
        inv_s = self._inv_s.select(isel)
        inv_sss = self._inv_sss.select(isel)
        r = self._r.select(isel)
        s0 = self._s0.select(isel)
        D = self._D.select(isel)

        # get derivatives of the B matrix wrt the parameters
        dB_dxluc_p = parameterisation.get_ds_dp(use_none_as_null=True)

        dDeltaPsi_dp = []
        dpv_dp = []

        # loop through the parameters
        for der in dB_dxluc_p:

            if der is None:
                dpv_dp.append(None)
                dDeltaPsi_dp.append(None)
                continue

            der_mat = flex.mat3_double(len(U), der.elems)

            # calculate the derivative of q for this parameter
            dq = U * der_mat * h

            # calculate the derivative of r for this parameter
            dr = dq.rotate_around_origin(e1, DeltaPsi)

            # calculate the derivative of DeltaPsi for this parameter
            dDeltaPsi = -1.0 * (dr.dot(s1)) / (e1.cross(r).dot(s0))
            dDeltaPsi_dp.append(dDeltaPsi)

            # term 1
            term1 = (nu * dq) * inv_s

            # term 2
            term2 = (nu * q_s0 * q_s0.dot(dq)) * inv_sss

            # calculate the derivative of pv for this parameter
            dpv = D * (term1 - term2)
            dpv_dp.append(dpv)

        return dpv_dp, dDeltaPsi_dp
Пример #26
0
def rotate_mat3_double(R, A):
    """
    Helper function to rotate a flex.mat3_double array of matrices

    """
    accessor = A.accessor()
    RAR = flex.mat3_double([R * matrix.sqr(a) * R.transpose() for a in A])
    RAR.reshape(accessor)
    return RAR
Пример #27
0
    def _xl_derivatives(self,
                        isel,
                        derivatives,
                        b_matrix,
                        parameterisation=None):
        """helper function to extend the derivatives lists by derivatives of
        generic parameterisations."""

        # Get required data
        axis = self._axis.select(isel)
        fixed_rotation = self._fixed_rotation.select(isel)
        setting_rotation = self._setting_rotation.select(isel)
        phi_calc = self._phi_calc.select(isel)
        h = self._h.select(isel)
        s1 = self._s1.select(isel)
        e_X_r = self._e_X_r.select(isel)
        e_r_s0 = self._e_r_s0.select(isel)
        if b_matrix:
            B = self._B.select(isel)
        else:
            U = self._U.select(isel)
        D = self._D.select(isel)

        if derivatives is None:
            # get derivatives of the B/U matrix wrt the parameters
            derivatives = [
                None if der is None else flex.mat3_double(
                    len(isel), der.elems)
                for der in parameterisation.get_ds_dp(use_none_as_null=True)
            ]

        dphi_dp = []
        dpv_dp = []

        # loop through the parameters
        for der in derivatives:
            if der is None:
                dphi_dp.append(None)
                dpv_dp.append(None)
                continue

            # calculate the derivative of r for this parameter
            if b_matrix:
                tmp = fixed_rotation * (der * B * h)
            else:
                tmp = fixed_rotation * (U * der * h)
            dr = setting_rotation * tmp.rotate_around_origin(axis, phi_calc)

            # calculate the derivative of phi for this parameter
            dphi = -1.0 * dr.dot(s1) / e_r_s0
            dphi_dp.append(dphi)

            # calculate the derivative of pv for this parameter
            dpv_dp.append(D * (dr + e_X_r * dphi))

        return dpv_dp, dphi_dp
Пример #28
0
  def _xl_unit_cell_derivatives(self, isel, parameterisation=None,
    reflections=None):
    """helper function to extend the derivatives lists by
    derivatives of the crystal unit cell parameterisations"""

    # Get required data
    U = self._U.select(isel)
    h = self._h.select(isel)
    e1 = self._e1.select(isel)
    DeltaPsi = self._DeltaPsi.select(isel)
    s1 = self._s1.select(isel)
    nu = self._nu.select(isel)
    q_s0 = self._q_s0.select(isel)
    inv_s = self._inv_s.select(isel)
    inv_sss = self._inv_sss.select(isel)
    r = self._r.select(isel)
    s0 = self._s0.select(isel)
    D = self._D.select(isel)

    # get derivatives of the B matrix wrt the parameters
    dB_dxluc_p = parameterisation.get_ds_dp(use_none_as_null=True)

    dDeltaPsi_dp = []
    dpv_dp = []

    # loop through the parameters
    for der in dB_dxluc_p:

      if der is None:
        dpv_dp.append(None)
        dDeltaPsi_dp.append(None)
        continue

      der_mat = flex.mat3_double(len(U), der.elems)

      # calculate the derivative of q for this parameter
      dq = U * der_mat * h

      # calculate the derivative of r for this parameter
      dr = dq.rotate_around_origin(e1, DeltaPsi)

      # calculate the derivative of DeltaPsi for this parameter
      dDeltaPsi = -1.0 * (dr.dot(s1)) / (e1.cross(r).dot(s0))
      dDeltaPsi_dp.append(dDeltaPsi)

      # term 1
      term1 = (nu * dq) * inv_s

      # term 2
      term2 = (nu * q_s0 * q_s0.dot(dq)) * inv_sss

      # calculate the derivative of pv for this parameter
      dpv = D * (term1 - term2)
      dpv_dp.append(dpv)

    return dpv_dp, dDeltaPsi_dp
Пример #29
0
    def first_derivatives(self):
        """
        Compute the first derivatives of Sigma w.r.t the parameters

        """
        (b1, ) = self.params

        dSdb1 = (2 * b1, 0, 0, 0, 2 * b1, 0, 0, 0, 2 * b1)

        return flex.mat3_double([dSdb1])
Пример #30
0
    def first_derivatives(self):
        """
        Compute the first derivatives of Sigma w.r.t the parameters

        """
        l1 = self.params[0]

        dSdl1 = (0, 0, 0, 0, 0, 0, 0, 0, 2 * l1)

        return flex.mat3_double([dSdl1])
Пример #31
0
    def first_derivatives(self):
        """
        Compute the first derivatives of Sigma w.r.t the parameters
        """
        b1, b2 = self.params

        d1 = (2 * b1, 0, 0, 0, 2 * b1, 0, 0, 0, 0)

        d2 = (0, 0, 0, 0, 0, 0, 0, 0, 2 * b2)

        return flex.mat3_double([d1, d2])
Пример #32
0
    def _xl_orientation_derivatives(self,
                                    isel,
                                    parameterisation=None,
                                    dU_dxlo_p=None,
                                    reflections=None):
        """helper function to extend the derivatives lists by derivatives of the
        crystal orientation parameterisations"""

        # Get required data
        axis = self._axis.select(isel)
        fixed_rotation = self._fixed_rotation.select(isel)
        setting_rotation = self._setting_rotation.select(isel)
        phi_calc = self._phi_calc.select(isel)
        h = self._h.select(isel)
        s1 = self._s1.select(isel)
        e_X_r = self._e_X_r.select(isel)
        e_r_s0 = self._e_r_s0.select(isel)
        B = self._B.select(isel)
        D = self._D.select(isel)

        if dU_dxlo_p is None:

            # get derivatives of the U matrix wrt the parameters
            dU_dxlo_p = [
                None if der is None else flex.mat3_double(
                    len(isel), der.elems)
                for der in parameterisation.get_ds_dp(use_none_as_null=True)
            ]

        dphi_dp = []
        dpv_dp = []

        # loop through the parameters
        for der in dU_dxlo_p:

            if der is None:
                dphi_dp.append(None)
                dpv_dp.append(None)
                continue

            # calculate the derivative of r for this parameter
            # FIXME COULD DO THIS BETTER WITH __rmul__?!
            tmp = fixed_rotation * (der * B * h)
            dr = setting_rotation * tmp.rotate_around_origin(axis, phi_calc)

            # calculate the derivative of phi for this parameter
            dphi = -1.0 * dr.dot(s1) / e_r_s0
            dphi_dp.append(dphi)

            # calculate the derivative of pv for this parameter
            dpv_dp.append(D * (dr + e_X_r * dphi))

        return dpv_dp, dphi_dp
Пример #33
0
    def _predict_one_experiment(self, experiment, reflections):

        B = flex.mat3_double(len(reflections), experiment.crystal.get_B())
        r0 = B * reflections["miller_index"].as_vec3_double()
        r0len = r0.norms()
        wl = experiment.beam.get_wavelength()

        # 2theta = 2 * arcsin( |r0| / (2 * |s0| ) )
        reflections["2theta_cal.rad"] = 2.0 * flex.asin(0.5 * r0len * wl)

        reflections.set_flags(flex.size_t(len(reflections)),
                              reflections.flags.predicted)
Пример #34
0
    def second_derivatives(self):
        """
        Compute the second derivatives of Sigma w.r.t the parameters

        """
        l1 = self.params[0]

        d11 = (0, 0, 0, 0, 0, 0, 0, 0, 2)

        d2 = flex.mat3_double([d11])
        d2.reshape(flex.grid(1, 1))

        return d2
Пример #35
0
  def tst_for_reflection_table(self):
    from libtbx.test_utils import approx_equal
    from dials.algorithms.spot_prediction import \
      ScanVaryingReflectionPredictor, ScanStaticReflectionPredictor
    from dials.array_family import flex

    predict = ScanStaticReflectionPredictor(self.experiments[0])
    preds = predict.for_ub(self.experiments[0].crystal.get_A())

    preds['ub_matrix'] = flex.mat3_double(len(preds), self.experiments[0].crystal.get_A())
    preds['s0'] = flex.vec3_double(len(preds), self.experiments[0].beam.get_s0())
    preds['d_matrix'] = flex.mat3_double(len(preds))
    preds['S_matrix'] = flex.mat3_double(len(preds),
        self.experiments[0].goniometer.get_setting_rotation())
    for ipanel, panel in enumerate(self.experiments[0].detector):
      sel = preds['panel'] == ipanel
      D = panel.get_d_matrix()
      preds['d_matrix'].set_selected(sel, D)
    predict = ScanVaryingReflectionPredictor(self.experiments[0])
    from copy import deepcopy
    old_preds = deepcopy(preds)
    predict.for_reflection_table(preds,
                                 preds['ub_matrix'],
                                 preds['s0'],
                                 preds['d_matrix'],
                                 preds['S_matrix'])

    # Because UB, s0, d and S values are the same for all reflections, the new
    # reflections should be approx equal to those produced by the scan static
    # predictor
    old_x, old_y, old_z = old_preds['xyzcal.px'].parts()
    new_x, new_y, new_z = preds['xyzcal.px'].parts()
    assert old_x.all_approx_equal(new_x)
    assert old_y.all_approx_equal(new_y)
    assert old_z.all_approx_equal(new_z)

    print "OK"

    return
Пример #36
0
    def _goniometer_derivatives(self,
                                isel,
                                parameterisation=None,
                                dS_dgon_p=None,
                                reflections=None):
        """helper function to extend the derivatives lists by
        derivatives of the goniometer parameterisations"""

        # Get required data
        axis = self._axis.select(isel)
        fixed_rotation = self._fixed_rotation.select(isel)
        phi_calc = self._phi_calc.select(isel)
        h = self._h.select(isel)
        s1 = self._s1.select(isel)
        e_X_r = self._e_X_r.select(isel)
        e_r_s0 = self._e_r_s0.select(isel)
        UB = self._UB.select(isel)
        D = self._D.select(isel)

        if dS_dgon_p is None:

            # get derivatives of the setting matrix S wrt the parameters
            dS_dgon_p = [
                None if der is None else flex.mat3_double(
                    len(isel), der.elems)
                for der in parameterisation.get_ds_dp(use_none_as_null=True)
            ]

        dphi_dp = []
        dpv_dp = []

        # loop through the parameters
        for der in dS_dgon_p:

            if der is None:
                dphi_dp.append(None)
                dpv_dp.append(None)
                continue

            # calculate the derivative of r for this parameter
            tmp = fixed_rotation * (UB * h)
            dr = der * tmp.rotate_around_origin(axis, phi_calc)

            # calculate the derivative of phi for this parameter
            dphi = -1.0 * dr.dot(s1) / e_r_s0
            dphi_dp.append(dphi)

            # calculate the derivative of pv for this parameter
            dpv_dp.append(D * (dr + e_X_r * dphi))

        return dpv_dp, dphi_dp
Пример #37
0
    def _prepare_for_compose(self, reflections, skip_derivatives=False):
        """Add columns to the reflection table to hold the varying state matrices
    or vectors for the experimental models, if required. Also add columns for
    the derivatives of states that are scan-varying"""

        nref = len(reflections)
        # set columns if needed
        if 'u_matrix' not in reflections:
            reflections['u_matrix'] = flex.mat3_double(nref)
        if 'b_matrix' not in reflections:
            reflections['b_matrix'] = flex.mat3_double(nref)
        if 's0_vector' not in reflections:
            reflections['s0_vector'] = flex.vec3_double(nref)
        if 'd_matrix' not in reflections:
            reflections['d_matrix'] = flex.mat3_double(nref)
        if 'D_matrix' not in reflections:
            reflections['D_matrix'] = flex.mat3_double(nref)

        # set columns in the reflection table to store the derivative of state for
        # each reflection, if needed
        if not skip_derivatives:
            null9 = (0., 0., 0., 0., 0., 0., 0., 0., 0.)
            null3 = (0., 0., 0.)
            if self._varying_xl_orientations and "dU_dp0" not in reflections:
                max_free_params = max([
                    e.num_free()
                    for e in self._xl_orientation_parameterisations
                ])
                for i in range(max_free_params):
                    colname = "dU_dp{0}".format(i)
                    reflections[colname] = flex.mat3_double(nref, null9)
            if self._varying_xl_unit_cells and "dB_dp0" not in reflections:
                max_free_params = max([
                    e.num_free() for e in self._xl_unit_cell_parameterisations
                ])
                for i in range(max_free_params):
                    colname = "dB_dp{0}".format(i)
                    reflections[colname] = flex.mat3_double(nref, null9)
            if self._varying_detectors and "dd_dp0" not in reflections:
                max_free_params = max(
                    [e.num_free() for e in self._detector_parameterisations])
                for i in range(max_free_params):
                    colname = "dd_dp{0}".format(i)
                    reflections[colname] = flex.mat3_double(nref, null9)
            if self._varying_beams and "ds0_dp0" not in reflections:
                max_free_params = max(
                    [e.num_free() for e in self._beam_parameterisations])
                for i in range(max_free_params):
                    colname = "ds0_dp{0}".format(i)
                    reflections[colname] = flex.vec3_double(nref, null3)

        return
  def tst_for_reflection_table(self):
    from libtbx.test_utils import approx_equal
    from dials.algorithms.spot_prediction import \
      ScanVaryingReflectionPredictor, ScanStaticReflectionPredictor
    from dials.array_family import flex

    predict = ScanStaticReflectionPredictor(self.experiments[0])
    preds = predict.for_ub(self.experiments[0].crystal.get_A())

    preds['ub_matrix'] = flex.mat3_double(len(preds), self.experiments[0].crystal.get_A())
    preds['s0'] = flex.vec3_double(len(preds), self.experiments[0].beam.get_s0())
    preds['d_matrix'] = flex.mat3_double(len(preds))
    for ipanel, panel in enumerate(self.experiments[0].detector):
      sel = preds['panel'] == ipanel
      D = panel.get_d_matrix()
      preds['d_matrix'].set_selected(sel, D)
    predict = ScanVaryingReflectionPredictor(self.experiments[0])
    from copy import deepcopy
    old_preds = deepcopy(preds)
    predict.for_reflection_table(preds,
                                 preds['ub_matrix'],
                                 preds['s0'],
                                 preds['d_matrix'])

    # Because UB, s0 and d values are the same for all reflections, the new
    # reflections should be approx equal to those produced by the scan static
    # predictor
    old_x, old_y, old_z = old_preds['xyzcal.px'].parts()
    new_x, new_y, new_z = preds['xyzcal.px'].parts()
    assert old_x.all_approx_equal(new_x)
    assert old_y.all_approx_equal(new_y)
    assert old_z.all_approx_equal(new_z)

    print "OK"

    return
Пример #39
0
    def first_derivatives(self):
        """
        Compute the first derivatives of Sigma w.r.t the parameters
        """
        b1, b2, b3, b4 = self.params

        d1 = (2 * b1, b2, 0, b2, 0, 0, 0, 0, 0)

        d2 = (0, b1, 0, b1, 2 * b2, 0, 0, 0, 0)

        d3 = (0, 0, 0, 0, 2 * b3, 0, 0, 0, 0)

        d4 = (0, 0, 0, 0, 0, 0, 0, 0, 2 * b4)

        return flex.mat3_double([d1, d2, d3, d4])
  def _prepare_for_compose(self, reflections):

    nref = len(reflections)
    # set columns for U and B if needed
    if not reflections.has_key('u_matrix'):
      reflections['u_matrix'] = flex.mat3_double(nref)
    if not reflections.has_key('b_matrix'):
      reflections['b_matrix'] = flex.mat3_double(nref)

    # set columns in the reflection table to store the derivative of state for
    # each reflection, if needed
    null = (0., 0., 0., 0., 0., 0., 0., 0., 0.)
    if self._xl_orientation_parameterisations and not reflections.has_key("dU_dp0"):
      max_free_U_params = max([e.num_free() for e in self._xl_orientation_parameterisations])
      for i in range(max_free_U_params):
        colname = "dU_dp{0}".format(i)
        reflections[colname] = flex.mat3_double(nref, null)
    if self._xl_unit_cell_parameterisations and not reflections.has_key("dB_dp0"):
      max_free_B_params = max([e.num_free() for e in self._xl_unit_cell_parameterisations])
      for i in range(max_free_B_params):
        colname = "dB_dp{0}".format(i)
        reflections[colname] = flex.mat3_double(nref, null)

    return
 def _predict_new(self, hkl=None, frame=None, panel=None):
     from dials.algorithms.spot_prediction import ScanVaryingReflectionPredictor
     from dials.array_family import flex
     predict = ScanVaryingReflectionPredictor(self.experiments[0])
     #if hkl is None:
     A = [
         self.experiments[0].crystal.get_A_at_scan_point(i)
         for i in range(self.experiments[0].crystal.num_scan_points)
     ]
     result = predict.for_ub(flex.mat3_double(A))
     #else:
     #if panel is None:
     #result = predict(hkl, frame)
     #else:
     #result = predict(hkl, frame, panel)
     return result
Пример #42
0
  def _xl_orientation_derivatives(self, isel, parameterisation=None,
    dU_dxlo_p=None, reflections=None):
    """helper function to extend the derivatives lists by derivatives of the
    crystal orientation parameterisations"""

    # Get required data
    axis = self._axis.select(isel)
    fixed_rotation = self._fixed_rotation.select(isel)
    setting_rotation = self._setting_rotation.select(isel)
    phi_calc = self._phi_calc.select(isel)
    h = self._h.select(isel)
    s1 = self._s1.select(isel)
    e_X_r = self._e_X_r.select(isel)
    e_r_s0 = self._e_r_s0.select(isel)
    B = self._B.select(isel)
    D = self._D.select(isel)

    if dU_dxlo_p is None:

      # get derivatives of the U matrix wrt the parameters
      dU_dxlo_p = [None if der is None else flex.mat3_double(len(isel), der.elems) \
                   for der in parameterisation.get_ds_dp(use_none_as_null=True)]

    dphi_dp = []
    dpv_dp = []

    # loop through the parameters
    for der in dU_dxlo_p:

      if der is None:
        dphi_dp.append(None)
        dpv_dp.append(None)
        continue

      # calculate the derivative of r for this parameter
      # FIXME COULD DO THIS BETTER WITH __rmul__?!
      tmp = fixed_rotation * (der * B * h)
      dr = setting_rotation * tmp.rotate_around_origin(axis, phi_calc)

      # calculate the derivative of phi for this parameter
      dphi = -1.0 * dr.dot(s1) / e_r_s0
      dphi_dp.append(dphi)

      # calculate the derivative of pv for this parameter
      dpv_dp.append(D * (dr + e_X_r * dphi))

    return dpv_dp, dphi_dp
  def predict_new(self, hkl=None, frame=None, panel=None):
    from dials.algorithms.spot_prediction import ScanVaryingReflectionPredictor
    from time import time
    from dials.array_family import flex
    st = time()
    predict = ScanVaryingReflectionPredictor(self.experiments[0])
    #if hkl is None:
    A = [self.experiments[0].crystal.get_A_at_scan_point(i) for i in
           range(self.experiments[0].crystal.num_scan_points)]
    result = predict.for_ub(flex.mat3_double(A))
    #else:
      #if panel is None:
        #result = predict(hkl, frame)
      #else:
        #result = predict(hkl, frame, panel)

    #print "New Time: ", time() - st
    return result
Пример #44
0
  def _get_model_data_for_experiment(self, experiment, reflections):
    """Helper function to return model data s0, U, B and D for a particular
    experiment. D is always returned as an array the same length as the
    reflections for the experiment, whereas here U, B and s0 are returned as
    single matrices or vectors. In the scan-varying overload these will all be
    arrays."""

    # D matrix array
    D = flex.mat3_double(len(reflections))
    panels = reflections['panel']
    for ipanel, D_mat in enumerate([p.get_D_matrix() for p in experiment.detector]):
      sel = panels == ipanel
      D.set_selected(sel, D_mat)

    return {'s0':experiment.beam.get_s0(),
            'U':experiment.crystal.get_U(),
            'B':experiment.crystal.get_B(),
            'D':D}
  def _prepare_for_compose(self, reflections, skip_derivatives=False):
    """Add columns to the reflection table to hold the varying state matrices
    or vectors for the experimental models, if required. Also add columns for
    the derivatives of states that are scan-varying"""

    nref = len(reflections)
    # set columns if needed
    if 'u_matrix' not in reflections:
      reflections['u_matrix'] = flex.mat3_double(nref)
    if 'b_matrix' not in reflections:
      reflections['b_matrix'] = flex.mat3_double(nref)
    if 's0_vector' not in reflections:
      reflections['s0_vector'] = flex.vec3_double(nref)
    if 'd_matrix' not in reflections:
      reflections['d_matrix'] = flex.mat3_double(nref)
    if 'D_matrix' not in reflections:
      reflections['D_matrix'] = flex.mat3_double(nref)

    # set columns in the reflection table to store the derivative of state for
    # each reflection, if needed
    if not skip_derivatives:
      null9 = (0., 0., 0., 0., 0., 0., 0., 0., 0.)
      null3 = (0., 0., 0.)
      if self._varying_xl_orientations and "dU_dp0" not in reflections:
        max_free_params = max([e.num_free() for e in self._xl_orientation_parameterisations])
        for i in range(max_free_params):
          colname = "dU_dp{0}".format(i)
          reflections[colname] = flex.mat3_double(nref, null9)
      if self._varying_xl_unit_cells and "dB_dp0" not in reflections:
        max_free_params = max([e.num_free() for e in self._xl_unit_cell_parameterisations])
        for i in range(max_free_params):
          colname = "dB_dp{0}".format(i)
          reflections[colname] = flex.mat3_double(nref, null9)
      if self._varying_detectors and "dd_dp0" not in reflections:
        max_free_params = max([e.num_free() for e in self._detector_parameterisations])
        for i in range(max_free_params):
          colname = "dd_dp{0}".format(i)
          reflections[colname] = flex.mat3_double(nref, null9)
      if self._varying_beams and "ds0_dp0" not in reflections:
        max_free_params = max([e.num_free() for e in self._beam_parameterisations])
        for i in range(max_free_params):
          colname = "ds0_dp{0}".format(i)
          reflections[colname] = flex.vec3_double(nref, null3)

    return
Пример #46
0
  def get_gradients(self, reflections, callback=None):
    """
    Calculate gradients of the prediction formula with respect to each
    of the parameters of the detector, for all of the reflections.

    """

    ### Calculate various quantities of interest for the reflections

    # Set up arrays of values for each reflection
    n = len(reflections)
    D = flex.mat3_double(n)
    #s0 = flex.vec3_double(n)
    #U = flex.mat3_double(n)
    #B = flex.mat3_double(n)
    #axis = flex.vec3_double(n)

    for iexp, exp in enumerate(self._experiments):

      sel = reflections['id'] == iexp
      isel = sel.iselection()

      # D matrix array
      panels = reflections['panel'].select(isel)
      for ipanel, D_mat in enumerate([p.get_D_matrix() for p in exp.detector]):
        subsel = isel.select(panels == ipanel)
        D.set_selected(subsel, D_mat)

      # s0 array
      #s0.set_selected(isel, exp.beam.get_s0())

      # U and B arrays
      #exp_U, exp_B = self._get_U_B_for_experiment(exp.crystal, reflections, isel)
      #U.set_selected(isel, exp_U)
      #B.set_selected(isel, exp_B)

      # axis array
      #if exp.goniometer:
      #  axis.set_selected(isel, exp.goniometer.get_rotation_axis())
    return self._get_gradients_core(reflections, D, callback)
Пример #47
0
  def __call__(self, reflections):
    """Predict 2theta angles for all reflections at the current model geometry"""

    for iexp, e in enumerate(self._experiments):

      # select the reflections for this experiment only
      sel = reflections['id'] == iexp
      refs = reflections.select(sel)

      B = flex.mat3_double(len(reflections), e.crystal.get_B())
      r0 = B * reflections['miller_index'].as_vec3_double()
      r0len = r0.norms()
      wl = e.beam.get_wavelength()

      # 2theta = 2 * arcsin( |r0| / (2 * |s0| ) )
      twotheta = 2.0 * flex.asin(0.5 * r0len * wl)

      # write predictions back to overall reflections
      reflections['2theta_cal.rad'].set_selected(sel, twotheta)

      # set predicted flag
      reflections.set_flags(sel, reflections.flags.predicted)

    return reflections
Пример #48
0
  def _detector_derivatives(self, isel, panel_id, parameterisation=None,
                            dd_ddet_p=None, reflections=None):
    """Helper function to convert derivatives of the detector state to
    derivatives of the vector pv. Derivatives that would all be null vectors
    are replaced with None"""

    # Get required data
    pv = self._pv.select(isel)
    D = self._D.select(isel)

    if dd_ddet_p is None:

      # get the derivatives of detector d matrix for this panel
      dd_ddet_p = parameterisation.get_ds_dp(multi_state_elt=panel_id,
                                             use_none_as_null=True)

      # replace explicit null derivatives with None
      dd_ddet_p = [None if e is None else \
                   flex.mat3_double(len(D), e.elems) for e in dd_ddet_p]

    # calculate the derivative of pv for this parameter
    dpv_ddet_p = [der if der is None else (D * (der * -1.)) * pv for der in dd_ddet_p]

    return dpv_ddet_p
Пример #49
0
  def _xl_unit_cell_derivatives(self, isel, parameterisation=None,
    reflections=None):
    """helper function to extend the derivatives lists by derivatives of the
    crystal unit cell parameterisations"""

    # Get required data
    U = self._U.select(isel)
    h = self._h.select(isel)
    e1 = self._e1.select(isel)
    DeltaPsi = self._DeltaPsi.select(isel)
    s1 = self._s1.select(isel)
    q = self._q.select(isel)
    q_scalar = self._q_scalar.select(isel)
    qq = self._qq.select(isel)
    q0 = self._q0.select(isel)
    r = self._r.select(isel)
    s0 = self._s0.select(isel)
    s0u = self._s0u.select(isel)
    D = self._D.select(isel)

    # get derivatives of the B matrix wrt the parameters
    dB_dxluc_p = parameterisation.get_ds_dp(use_none_as_null=True)

    dDeltaPsi_dp = []
    dpv_dp = []

    # loop through the parameters
    for der in dB_dxluc_p:

      if der is None:
        dpv_dp.append(None)
        dDeltaPsi_dp.append(None)
        continue

      der_mat = flex.mat3_double(len(U), der.elems)

      # calculate the derivative of q for this parameter
      dq = U * der_mat * h

      # calculate the derivative of r for this parameter
      dr = dq.rotate_around_origin(e1, DeltaPsi)

      # calculate the derivative of DeltaPsi for this parameter
      dDeltaPsi = -1.0 * (dr.dot(s1)) / (e1.cross(r).dot(s0))
      dDeltaPsi_dp.append(dDeltaPsi)

      # derivative of the axis e1
      q_dot_dq = q.dot(dq)
      dq0 = (q_scalar * dq - (q_dot_dq * q0)) / qq
      de1_dp = dq0.cross(s0u)

      # calculate (d[r]/d[e1])(d[e1]/dp)
      dr_de1 = dRq_de(DeltaPsi, e1, q)
      drde_dedp = dr_de1 * de1_dp

      # calculate the partial derivative of r wrt change in rotation
      # axis e1 by finite differences
      dp = 1.e-8
      del_e1 = de1_dp * dp
      e1f = e1 + del_e1 * 0.5
      rfwd = q.rotate_around_origin(e1f , DeltaPsi)
      e1r = e1 - del_e1 * 0.5
      rrev = q.rotate_around_origin(e1r , DeltaPsi)
      drde_dedp = (rfwd - rrev) * (1 / dp)

      # calculate the derivative of pv for this parameter
      dpv = D * (dr + e1.cross(r) * dDeltaPsi + drde_dedp)
      dpv_dp.append(dpv)

    return dpv_dp, dDeltaPsi_dp
Пример #50
0
  def __init__(self,
               experiment,
               dmin=None,
               dmax=None,
               margin=1,
               force_static=False):
    '''
    Initialise a predictor for each experiment.

    :param experiment: The experiment to predict for
    :param dmin: The maximum resolution
    :param dmax: The minimum resolution
    :param margin: The margin of hkl to predict
    :param force_static: force scan varying prediction to be static

    '''
    from dials.algorithms.spot_prediction import ScanStaticReflectionPredictor
    from dials.algorithms.spot_prediction import ScanVaryingReflectionPredictor
    from dials.algorithms.spot_prediction import StillsReflectionPredictor
    from dxtbx.imageset import ImageSweep
    from dials.array_family import flex

    class Predictor(object):
      def __init__(self, name, func):
        self.name = name
        self.func = func
      def __call__(self):
        result = self.func()
        if dmax is not None:
          assert(dmax > 0)
          result.compute_d_single(experiment)
          mask = result['d'] > dmax
          result.del_selected(mask)
        return result

    # Select the predictor class
    if isinstance(experiment.imageset, ImageSweep):
      nsp = experiment.crystal.num_scan_points
      nim = experiment.scan.get_num_images()
      if not force_static and nsp == nim + 1:
        predictor = ScanVaryingReflectionPredictor(
          experiment,
          dmin=dmin,
          margin=margin)
        A = [experiment.crystal.get_A_at_scan_point(i) for i in
               range(experiment.crystal.num_scan_points)]
        predict = Predictor(
          "scan varying prediction",
          lambda: predictor.for_ub(flex.mat3_double(A)))
      else:
        predictor = ScanStaticReflectionPredictor(
          experiment,
          dmin=dmin)
        predict = Predictor(
          "scan static prediction",
          lambda: predictor.for_ub(experiment.crystal.get_A()))
    else:
      predictor = StillsReflectionPredictor(
        experiment,
        dmin=dmin)

      predict = Predictor(
        "stills prediction",
        lambda: predictor.for_ub(experiment.crystal.get_A()))

    # Create and add the predictor class
    self._predict = predict
Пример #51
0
  def get_gradients(self, reflections, callback=None):
    """Calculate gradients of the prediction formula with respect to each
    of the parameters of the contained models, for all of the reflections.
    This method sets up required quantities relevant to the current step of
    refinement and then loops over the parameterisations of each type extending
    a results list each time."""

    # Set up arrays of quantities of interest for each reflection
    self._nref = len(reflections)
    self._D = flex.mat3_double(self._nref)
    self._s0 = flex.vec3_double(self._nref)
    self._U = flex.mat3_double(self._nref)
    self._B = flex.mat3_double(self._nref)
    self._axis = flex.vec3_double(self._nref)
    self._fixed_rotation = flex.mat3_double(self._nref)
    self._setting_rotation = flex.mat3_double(self._nref)

    # Set up experiment to index mapping
    self._experiment_to_idx = []

    # Populate values in these arrays
    for iexp, exp in enumerate(self._experiments):

      sel = reflections['id'] == iexp
      isel = sel.iselection()
      self._experiment_to_idx.append(isel)
      subref = reflections.select(sel)
      states = self._get_model_data_for_experiment(exp, subref)

      self._D.set_selected(sel, states['D'])
      self._s0.set_selected(sel, states['s0'])
      self._U.set_selected(sel, states['U'])
      self._B.set_selected(sel, states['B'])
      if exp.goniometer:
        self._axis.set_selected(sel, exp.goniometer.get_rotation_axis_datum())
        self._fixed_rotation.set_selected(sel, exp.goniometer.get_fixed_rotation())
        self._setting_rotation.set_selected(sel, exp.goniometer.get_setting_rotation())

    # Other derived values
    self._h = reflections['miller_index'].as_vec3_double()
    self._UB = self._U * self._B
    self._s1 = reflections['s1']
    self._pv = self._D * self._s1 # 'projection vector' for the ray along s1.

    # Quantities derived from pv, precalculated for efficiency
    u, v, w = self._pv.parts()
    self._w_inv = 1./w
    self._u_w_inv = u * self._w_inv
    self._v_w_inv = v * self._w_inv

    # Reset a pointer to the parameter number
    self._iparam = 0

    # Do additional setup specified by derived classes
    self._local_setup(reflections)

    # Set up empty list in which to store gradients
    results = []

    # loop over detector parameterisations and extend results
    results = self._grads_detector_loop(reflections, results, callback)

    # loop over the beam parameterisations and extend results
    results = self._grads_beam_loop(reflections, results, callback)

    # loop over the crystal orientation parameterisations and extend results
    results = self._grads_xl_orientation_loop(reflections, results, callback)

    # loop over the crystal unit cell parameterisations and extend results
    results = self._grads_xl_unit_cell_loop(reflections, results, callback)

    return results