Пример #1
0
def test_correct(space_group_symbol):

    sgi = sgtbx.space_group_info(space_group_symbol)
    cs = sgi.any_compatible_crystal_symmetry(volume=1000)
    ms = cs.build_miller_set(anomalous_flag=True, d_min=1).expand_to_p1()

    # the reciprocal matrix
    B = scitbx.matrix.sqr(cs.unit_cell().fractionalization_matrix()).transpose()
    crystal = Crystal(B, sgtbx.space_group())
    expts = ExperimentList([Experiment(crystal=crystal)])

    refl = flex.reflection_table()
    refl["miller_index"] = ms.indices()
    refl["rlp"] = B.elems * ms.indices().as_vec3_double()
    refl["imageset_id"] = flex.int(len(refl))
    refl["xyzobs.mm.value"] = flex.vec3_double(len(refl))

    non_primitive_basis.correct(expts, refl, assign_indices.AssignIndicesGlobal())

    cs_corrected = expts.crystals()[0].get_crystal_symmetry()
    assert cs_corrected.change_of_basis_op_to_primitive_setting().is_identity_op()
    assert (
        cs.change_of_basis_op_to_primitive_setting().apply(ms.indices())
        == refl["miller_index"]
    )
Пример #2
0
    def __init__(self, reflections, experiments, params):
        self.reflections = reflections
        self.experiments = experiments

        self.params = params.indexing
        self.all_params = params
        self.refined_experiments = None
        self.hkl_offset = None

        if self.params.index_assignment.method == "local":
            self._assign_indices = assign_indices.AssignIndicesLocal(
                epsilon=self.params.index_assignment.local.epsilon,
                delta=self.params.index_assignment.local.delta,
                l_min=self.params.index_assignment.local.l_min,
                nearest_neighbours=self.params.index_assignment.local.
                nearest_neighbours,
            )
        else:
            self._assign_indices = assign_indices.AssignIndicesGlobal(
                tolerance=self.params.index_assignment.simple.hkl_tolerance)

        if self.all_params.refinement.reflections.outlier.algorithm in (
                "auto",
                libtbx.Auto,
        ):
            if self.experiments[0].goniometer is None:
                self.all_params.refinement.reflections.outlier.algorithm = "sauter_poon"
            else:
                # different default to dials.refine
                # tukey is faster and more appropriate at the indexing step
                self.all_params.refinement.reflections.outlier.algorithm = "tukey"

        for expt in self.experiments[1:]:
            if expt.detector.is_similar_to(self.experiments[0].detector):
                expt.detector = self.experiments[0].detector
            if expt.goniometer is not None and expt.goniometer.is_similar_to(
                    self.experiments[0].goniometer):
                expt.goniometer = self.experiments[0].goniometer
                # can only share a beam if we share a goniometer?
                if expt.beam.is_similar_to(self.experiments[0].beam):
                    expt.beam = self.experiments[0].beam
                if self.params.combine_scans and expt.scan == self.experiments[
                        0].scan:
                    expt.scan = self.experiments[0].scan

        if "flags" in self.reflections:
            strong_sel = self.reflections.get_flags(
                self.reflections.flags.strong)
            if strong_sel.count(True) > 0:
                self.reflections = self.reflections.select(strong_sel)
        if "flags" not in self.reflections or strong_sel.count(True) == 0:
            # backwards compatibility for testing
            self.reflections.set_flags(
                flex.size_t_range(len(self.reflections)),
                self.reflections.flags.strong)

        self._setup_symmetry()
        self.d_min = None

        self.setup_indexing()
Пример #3
0
 def prep_relfs_for_tiltalization(predicted_refls, exper):
     predicted_refls['id'] = flex.int(len(predicted_refls), -1)
     predicted_refls['imageset_id'] = flex.int(len(predicted_refls), 0)
     El = ExperimentList()
     El.append(exper)
     predicted_refls.centroid_px_to_mm(El)
     predicted_refls.map_centroids_to_reciprocal_space(El)
     idx_assign = assign_indices.AssignIndicesGlobal(tolerance=0.333)
     idx_assign(predicted_refls, El)
     return predicted_refls
Пример #4
0
def index_reflections(reflections, experiments, d_min=None, tolerance=0.3):
    from dials.algorithms.indexing import assign_indices

    warnings.warn(
        "index_reflections is deprecated, use "
        "dials.algorithms.indexing.assign_indices.AssignIndicesGlobal instead",
        DeprecationWarning,
        stacklevel=2,
    )
    index = assign_indices.AssignIndicesGlobal(tolerance=tolerance)
    index(reflections, experiments)
Пример #5
0
def tilt_fit(imgs, is_bg_pix, delta_q, photon_gain, sigma_rdout, zinger_zscore,
             exper, predicted_refls, sb_pad=0, filter_boundary_spots=False,
             minsnr=None, mintilt=None, plot=False, verbose=False, is_BAD_pix=None,
             min_strong=None, min_bg=10, min_dist_to_bad_pix=7, **kwargs):

    if is_BAD_pix is None:
        is_BAD_pix = np.zeros(np.array(is_bg_pix).shape, np.bool)

    predicted_refls['id'] = flex.int(len(predicted_refls), -1)
    predicted_refls['imageset_id'] = flex.int(len(predicted_refls), 0)
    El = ExperimentList()
    El.append(exper)
    predicted_refls.centroid_px_to_mm(El)
    predicted_refls.map_centroids_to_reciprocal_space(El)
    ss_dim, fs_dim = imgs[0].shape
    n_refl = len(predicted_refls)
    integrations = []
    variances = []
    coeffs = []
    new_shoeboxes = []
    tilt_error = []
    boundary = []
    detdist = exper.detector[0].get_distance()
    pixsize = exper.detector[0].get_pixel_size()[0]
    ave_wave = exper.beam.get_wavelength()

    bad_trees = {}
    unique_panels = set(predicted_refls["panel"])
    for p in unique_panels:
        panel_bad_pix = is_BAD_pix[p]
        ybad, xbad = np.where(is_BAD_pix[0])
        if ybad.size:
            bad_pts = zip(ybad, xbad)
            bad_trees[p] = cKDTree(bad_pts)
        else:
            bad_trees[p] = None

    sel = []
    for i_ref in range(len(predicted_refls)):
        ref = predicted_refls[i_ref]
        i_com, j_com, _ = ref['xyzobs.px.value']

        # which detector panel am I on ?
        i_panel = ref['panel']

        if bad_trees[i_panel] is not None:
            if bad_trees[i_panel].query_ball_point((i_com, j_com), r=min_dist_to_bad_pix):
                sel.append(False)
                integrations.append(None)
                variances.append(None)
                coeffs.append(None)
                new_shoeboxes.append(None)
                tilt_error.append(None)
                boundary.append(None)
                continue

        i1_a, i2_a, j1_a, j2_a, _, _ = ref['bbox']  # bbox of prediction

        i1_ = max(i1_a, 0)
        i2_ = min(i2_a, fs_dim-1)
        j1_ = max(j1_a, 0)
        j2_ = min(j2_a, ss_dim-1)

        # get the number of pixels spanning the box in pixels
        Qmag = 2*np.pi*np.linalg.norm(ref['rlp'])  # magnitude momentum transfer of the RLP in physicist convention
        rad1 = (detdist/pixsize) * np.tan(2*np.arcsin((Qmag-delta_q*.5)*ave_wave/4/np.pi))
        rad2 = (detdist/pixsize) * np.tan(2*np.arcsin((Qmag+delta_q*.5)*ave_wave/4/np.pi))
        bbox_extent = (rad2-rad1) / np.sqrt(2)   # rad2 - rad1 is the diagonal across the bbox
        i_com = i_com - 0.5
        j_com = j_com - 0.5
        i_low = int(i_com - bbox_extent/2.)
        i_high = int(i_com + bbox_extent/2.)
        j_low = int(j_com - bbox_extent/2.)
        j_high = int(j_com + bbox_extent/2.)

        i1_orig = max(i_low, 0)
        i2_orig = min(i_high, fs_dim-1)
        j1_orig = max(j_low, 0)
        j2_orig = min(j_high, ss_dim-1)

        i_low = i_low - sb_pad
        i_high = i_high + sb_pad
        j_low = j_low - sb_pad
        j_high = j_high + sb_pad

        i1 = max(i_low, 0)
        i2 = min(i_high, fs_dim-1)
        j1 = max(j_low, 0)
        j2 = min(j_high, ss_dim-1)

        i1_p = i1_orig - i1
        i2_p = i1_p + i2_orig-i1_orig
        j1_p = j1_orig - j1
        j2_p = j1_p + j2_orig-j1_orig

        if i1 == 0 or i2 == fs_dim or j1 == 0 or j2 == ss_dim:
            boundary.append(True)
            if filter_boundary_spots:
                sel.append(False)
                integrations.append(None)
                variances.append(None)
                coeffs.append(None)
                new_shoeboxes.append(None)
                tilt_error.append(None)
                continue
        else:
            boundary.append(False)

        # get the iamge and mask
        shoebox_img = imgs[i_panel][j1:j2, i1:i2] / photon_gain  # NOTE: gain is imortant here!
        dials_mask = np.zeros(shoebox_img.shape).astype(np.int32)

        # initially all pixels are valid
        dials_mask += MaskCode.Valid
        shoebox_mask = is_bg_pix[i_panel][j1:j2, i1:i2]
        badpix_mask = is_BAD_pix[i_panel][j1:j2, i1:i2]


        dials_mask[shoebox_mask] = dials_mask[shoebox_mask] + MaskCode.Background

        new_shoebox = Shoebox((i1_orig, i2_orig, j1_orig, j2_orig, 0, 1))
        new_shoebox.allocate()
        new_shoebox.data = flex.float(np.ascontiguousarray(shoebox_img[None, j1_p:j2_p, i1_p: i2_p]))
        #new_shoebox.data = flex.float(shoebox_img[None,])

        # get coordinates arrays of the image
        Y, X = np.indices(shoebox_img.shape)

        # determine if any more outliers are present in background pixels
        img1d = shoebox_img.ravel()
        mask1d = shoebox_mask.ravel()  # mask specifies which pixels are bg
        # out1d specifies which bg pixels are outliers (zingers)
        out1d = np.zeros(mask1d.shape, bool)
        out1d[mask1d] = is_outlier(img1d[mask1d].ravel(), zinger_zscore)
        out2d = out1d.reshape(shoebox_img.shape)

        # combine bad2d with badpix mask
        out2d = np.logical_or(out2d, badpix_mask)

        # these are points we fit to: both zingers and original mask
        fit_sel = np.logical_and(~out2d, shoebox_mask)  # fit plane to these points, no outliers, no masked

        if np.sum(fit_sel) < min_bg:
            integrations.append(None)
            variances.append(None)
            coeffs.append(None)
            new_shoeboxes.append(None)
            tilt_error.append(None)
            sel.append(False)
            continue

        # update the dials mask...
        dials_mask[fit_sel] = dials_mask[fit_sel] + MaskCode.BackgroundUsed

        # fast scan pixels, slow scan pixels, pixel values (corrected for gain)
        fast, slow, rho_bg = X[fit_sel], Y[fit_sel], shoebox_img[fit_sel]

        # do the fit of the background plane
        A = np.array([fast, slow, np.ones_like(fast)]).T
        # weights matrix:
        W = np.diag(1 / (sigma_rdout ** 2 + rho_bg))
        AWA = np.dot(A.T, np.dot(W, A))
        try:
            AWA_inv = np.linalg.inv(AWA)
        except np.linalg.LinAlgError:
            print ("WARNING: Fit did not work.. investigate reflection")
            print (ref)
            integrations.append(None)
            variances.append(None)
            coeffs.append(None)
            new_shoeboxes.append(None)
            tilt_error.append(None)
            sel.append(False)
            continue


        AtW = np.dot(A.T, W)
        a, b, c = np.dot(np.dot(AWA_inv, AtW), rho_bg)
        coeffs.append((a, b, c))

        # fit of the tilt plane background
        X1d = np.ravel(X)
        Y1d = np.ravel(Y)
        background = (X1d * a + Y1d * b + c).reshape(shoebox_img.shape)
        new_shoebox.background = flex.float(np.ascontiguousarray(background[None, j1_p: j2_p, i1_p:i2_p]))

        # vector of residuals
        r = rho_bg - np.dot(A, (a, b, c))
        Nbg = len(rho_bg)
        Nparam = 3
        r_fact = np.dot(r.T, np.dot(W, r)) / (Nbg - Nparam)
        var_covar = AWA_inv * r_fact
        abc_var = var_covar[0][0], var_covar[1][1], var_covar[2][2]

        # place the strong spot mask in the expanded shoebox
        peak_mask = ref['shoebox'].mask.as_numpy_array()[0] == MaskCode.Valid + MaskCode.Foreground
        peak_mask_valid = peak_mask[j1_-j1_a:- j1_a + j2_, i1_-i1_a:-i1_a + i2_]
        peak_mask_expanded = np.zeros_like(shoebox_mask)

        # overlap region
        i1_o = max(i1_, i1)
        i2_o = min(i2_, i2)
        j1_o = max(j1_, j1)
        j2_o = min(j2_, j2)

        pk_mask_istart = i1_o - i1_
        pk_mask_jstart = j1_o - j1_
        pk_mask_istop = peak_mask_valid.shape[1] - (i2_ - i2_o)
        pk_mask_jstop = peak_mask_valid.shape[0] - (j2_ - j2_o)
        peak_mask_overlap = peak_mask_valid[pk_mask_jstart: pk_mask_jstop, pk_mask_istart: pk_mask_istop]

        pk_mask_exp_i1 = i1_o - i1
        pk_mask_exp_j1 = j1_o - j1
        pk_mask_exp_i2 = peak_mask_expanded.shape[1] - (i2 - i2_o)
        pk_mask_exp_j2 = peak_mask_expanded.shape[0] - (j2 - j2_o)
        peak_mask_expanded[pk_mask_exp_j1: pk_mask_exp_j2, pk_mask_exp_i1: pk_mask_exp_i2] = peak_mask_overlap

        # update the dials mask
        dials_mask[peak_mask_expanded] = dials_mask[peak_mask_expanded] + MaskCode.Foreground

        p = X[peak_mask_expanded]  # fast scan coords
        q = Y[peak_mask_expanded]  # slow scan coords
        rho_peak = shoebox_img[peak_mask_expanded]  # pixel values

        Isum = np.sum(rho_peak - a*p - b*q - c)  # summed spot intensity

        var_rho_peak = sigma_rdout ** 2 + rho_peak  # include readout noise in the variance
        Ns = len(rho_peak)  # number of integrated peak pixels

        # variance propagated from tilt plane constants
        var_a_term = abc_var[0] * ((np.sum(p))**2)
        var_b_term = abc_var[1] * ((np.sum(q))**2)
        var_c_term = abc_var[2] * (Ns**2)
        tilt_error.append(var_a_term + var_b_term + var_c_term)

        # total variance of the spot
        var_Isum = np.sum(var_rho_peak) + var_a_term + var_b_term + var_c_term

        integrations.append(Isum)
        variances.append(var_Isum)
        new_shoebox.mask = flex.int(np.ascontiguousarray(dials_mask[None, j1_p:j2_p, i1_p:i2_p]))
        new_shoeboxes.append(new_shoebox)
        sel.append(True)

        if i_ref % 50 == 0 and verbose:
            print("Integrated refls %d / %d" % (i_ref+1, n_refl))


    #if filter_boundary_spots:
    #    sel = flex.bool([I is not None for I in integrations])
    boundary = np.array(boundary)[sel].astype(bool)
    integrations = np.array([I for I in integrations if I is not None])
    variances = np.array([v for v in variances if v is not None])
    coeffs = np.array([c for c in coeffs if c is not None])
    tilt_error = np.array([te for te in tilt_error if te is not None])

    #boundary = np.zeros(tilt_error.shape).astype(np.bool)

    predicted_refls = predicted_refls.select(flex.bool(sel))

    predicted_refls['resolution'] = flex.double( 1/ np.linalg.norm(predicted_refls['rlp'], axis=1))
    predicted_refls['boundary'] = flex.bool(boundary)
    predicted_refls["intensity.sum.value.Leslie99"] = flex.double(integrations)
    predicted_refls["intensity.sum.variance.Leslie99"] = flex.double(variances)
    predicted_refls['shoebox'] = flex.shoebox([sb for sb in new_shoeboxes if sb is not None])
    idx_assign = assign_indices.AssignIndicesGlobal(tolerance=0.333)
    idx_assign(predicted_refls, El)
    
    return predicted_refls, coeffs, tilt_error, integrations, variances
def run(experiments, reflections, random_seed=42):
    scitbx.random.set_random_seed(random_seed)
    random.seed(random_seed)

    reflections["id"] = flex.int(len(reflections), 0)
    reflections = reflections.select(
        reflections.get_flags(reflections.flags.indexed))

    beam = experiments[0].beam
    detector = experiments[0].detector
    p_id, (x, y) = detector.get_ray_intersection(beam.get_s0())

    g = scitbx.random.variate(
        scitbx.random.normal_distribution(mean=0, sigma=2))

    n = 100
    shift_x = g(n)
    shift_y = g(n)

    expected_miller_indices = reflections["miller_index"]
    non_zero_sel = expected_miller_indices != (0, 0, 0)

    misindexed_global = flex.size_t()
    correct_global = flex.size_t()
    misindexed_local = flex.size_t()
    correct_local = flex.size_t()

    global_timer = time_log("global")
    local_timer = time_log("local")

    for d_x, d_y in zip(shift_x, shift_y):
        set_slow_fast_beam_centre_mm(detector, beam, (y + d_y, x + d_x), p_id)

        refl = Indexer.map_centroids_to_reciprocal_space(
            experiments, reflections)

        refl_global = copy.deepcopy(refl)
        refl_global["id"] = flex.int(len(refl), -1)
        global_timer.start()
        assign_indices.AssignIndicesGlobal()(refl_global, experiments)
        global_timer.stop()

        misindexed_global.append(
            (expected_miller_indices == refl_global["miller_index"]
             ).select(non_zero_sel).count(False))
        correct_global.append(
            (expected_miller_indices == refl_global["miller_index"]
             ).select(non_zero_sel).count(True))

        refl_local = copy.deepcopy(refl)
        refl_local["id"] = flex.int(len(refl), -1)
        local_timer.start()
        assign_indices.AssignIndicesLocal()(refl_local, experiments)
        local_timer.stop()

        misindexed_local.append(
            (expected_miller_indices == refl_local["miller_index"]
             ).select(non_zero_sel).count(False))
        correct_local.append(
            (expected_miller_indices == refl_local["miller_index"]
             ).select(non_zero_sel).count(True))

        print("Beam centre shift: (%.2f, %.2f)" % (d_x, d_y))
        print("Misindexed global: %i" % misindexed_global[-1])
        print("Correct global: %i" % correct_global[-1])
        print("Misindexed local: %i" % misindexed_local[-1])
        print("Correct local: %i" % correct_local[-1])
        print()

    print(global_timer.legend)
    print(global_timer.report())
    print(local_timer.report())

    vmax = max(flex.max(correct_global), flex.max(correct_local))

    import matplotlib

    matplotlib.use("Agg")
    from matplotlib import pyplot as plt

    fig, axes = plt.subplots(ncols=2, sharey=True, figsize=(15, 10))
    sc = axes[0].scatter(
        shift_x,
        shift_y,
        vmin=0,
        vmax=1,
        c=correct_global.as_double() / vmax,
        cmap="viridis",
    )
    sc = axes[1].scatter(
        shift_x,
        shift_y,
        vmin=0,
        vmax=1,
        c=correct_local.as_double() / vmax,
        cmap="viridis",
    )
    axes[0].set_title("global")
    axes[1].set_title("local")
    for ax in axes:
        ax.set_aspect("equal")
        ax.set_xlabel("beam centre shift (mm)")
    axes[0].set_ylabel("beam centre shift (mm)")

    cbar = plt.colorbar(sc, ax=axes, shrink=0.5)
    cbar.set_label("Fraction correctly indexed")
    plt.savefig("correctly_indexed.png")