def run(args):
  import libtbx.load_env
  usage = "%s experiments.json indexed.pickle [options]" %libtbx.env.dispatcher_name

  parser = OptionParser(
    usage=usage,
    phil=phil_scope,
    read_experiments=True,
    read_reflections=True,
    check_format=False,
    epilog=help_message)

  params, options = parser.parse_args(show_diff_phil=True)
  experiments = flatten_experiments(params.input.experiments)
  reflections = flatten_reflections(params.input.reflections)
  if len(experiments) == 0:
    parser.print_help()
    return
  elif len(experiments) > 1:
    raise Sorry("More than one experiment present")

  experiment = experiments[0]
  assert(len(reflections) == 1)
  reflections = reflections[0]

  intensities = reflections['intensity.sum.value']
  variances = reflections['intensity.sum.variance']
  if 'intensity.prf.value' in reflections:
    intensities = reflections['intensity.prf.value']
    variances = reflections['intensity.prf.variance']
  sel = (variances > 0)
  intensities = intensities.select(sel)
  variances = variances.select(sel)
  sigmas = flex.sqrt(variances)
  indices = reflections['miller_index'].select(sel)

  from cctbx import crystal, miller
  crystal_symmetry = crystal.symmetry(
    space_group=experiment.crystal.get_space_group(),
    unit_cell=experiment.crystal.get_unit_cell())

  miller_set = miller.set(
    crystal_symmetry=crystal_symmetry,
    anomalous_flag=True,
    indices=indices)
  miller_array = miller.array(
    miller_set=miller_set,
    data=intensities,
    sigmas=sigmas).set_observation_type_xray_intensity()

  #miller_array.setup_binner(n_bins=50, reflections_per_bin=100)
  miller_array.setup_binner(auto_binning=True, n_bins=20)
  result = miller_array.i_over_sig_i(use_binning=True)
  result.show()

  from cctbx import uctbx
  d_star_sq_centre = result.binner.bin_centers(2)
  i_over_sig_i = flex.double(
    [d if d is not None else 0 for d in result.data[1:-1]])
  sel = (i_over_sig_i > 0)
  d_star_sq_centre = d_star_sq_centre.select(sel)
  i_over_sig_i = i_over_sig_i.select(sel)
  log_i_over_sig_i = flex.log(i_over_sig_i)
  weights = result.binner.counts()[1:-1].as_double().select(sel)
  fit = flex.linear_regression(
    d_star_sq_centre, log_i_over_sig_i, weights=weights)

  m = fit.slope()
  c = fit.y_intercept()

  import math
  y_cutoff = math.log(params.i_sigi_cutoff)
  x_cutoff = (y_cutoff - c)/m

  estimated_d_min = uctbx.d_star_sq_as_d(x_cutoff)
  print "estimated d_min: %.2f" %estimated_d_min

  if params.plot:
    from matplotlib import pyplot
    fig = pyplot.figure()
    ax = fig.add_subplot(1,1,1)

    ax.plot(
      list(d_star_sq_centre),
      list(log_i_over_sig_i),
      label=r"ln(I/sigI)")
    ax.plot(pyplot.xlim(), [(m * x + c) for x in pyplot.xlim()], color='red')
    ax.plot([x_cutoff, x_cutoff], pyplot.ylim(), color='grey', linestyle='dashed')
    ax.plot(pyplot.xlim(), [y_cutoff, y_cutoff], color='grey', linestyle='dashed')
    ax.set_xlabel("d_star_sq")
    ax.set_ylabel("ln(I/sigI)")

    ax_ = ax.twiny() # ax2 is responsible for "top" axis and "right" axis
    xticks = ax.get_xticks()
    xlim = ax.get_xlim()
    xticks_d = [
      uctbx.d_star_sq_as_d(ds2) if ds2 > 0 else 0 for ds2 in xticks ]
    xticks_ = [ds2/(xlim[1]-xlim[0]) for ds2 in xticks]
    ax_.set_xticks(xticks)
    ax_.set_xlim(ax.get_xlim())
    ax_.set_xlabel(r"Resolution ($\AA$)")
    ax_.set_xticklabels(["%.1f" %d for d in xticks_d])
    pyplot.savefig("estimate_resolution_limit.png")
    pyplot.clf()
예제 #2
0
    def __call__(self):
        """Determine optimal mosaicity and domain size model (monochromatic)"""
        if self.refinery is None:
            RR = self.reflections
        else:
            RR = self.refinery.predict_for_reflection_table(self.reflections)

        all_crystals = []
        self.nv_acceptance_flags = flex.bool(len(self.reflections["id"]))
        from dxtbx.model import MosaicCrystalSauter2014

        for iid, experiment in enumerate(self.experiments):
            excursion_rad = RR["delpsical.rad"].select(RR["id"] == iid)
            delta_psi_deg = excursion_rad * 180.0 / math.pi
            logger.info("")
            logger.info("%s %s", flex.max(delta_psi_deg),
                        flex.min(delta_psi_deg))
            mean_excursion = flex.mean(delta_psi_deg)
            logger.info(
                "The mean excursion is %7.3f degrees, r.m.s.d %7.3f",
                mean_excursion,
                math.sqrt(flex.mean(RR["delpsical2"].select(RR["id"] == iid))),
            )

            crystal = MosaicCrystalSauter2014(self.experiments[iid].crystal)
            self.experiments[iid].crystal = crystal
            beam = self.experiments[iid].beam
            miller_indices = self.reflections["miller_index"].select(
                self.reflections["id"] == iid)

            # FIXME XXX revise this formula so as to use a different wavelength potentially for each reflection
            two_thetas = crystal.get_unit_cell().two_theta(
                miller_indices, beam.get_wavelength(), deg=True)
            dspacings = crystal.get_unit_cell().d(miller_indices)

            # First -- try to get a reasonable envelope for the observed excursions.
            # minimum of three regions; maximum of 50 measurements in each bin
            logger.info("fitting parameters on %d spots", len(excursion_rad))
            n_bins = min(max(3, len(excursion_rad) // 25), 50)
            bin_sz = len(excursion_rad) // n_bins
            logger.info("nbins %s bin_sz %s", n_bins, bin_sz)
            order = flex.sort_permutation(two_thetas)
            two_thetas_env = flex.double()
            dspacings_env = flex.double()
            excursion_rads_env = flex.double()
            for x in range(0, n_bins):
                subset = order[x * bin_sz:(x + 1) * bin_sz]
                two_thetas_env.append(flex.mean(two_thetas.select(subset)))
                dspacings_env.append(flex.mean(dspacings.select(subset)))
                excursion_rads_env.append(
                    flex.max(flex.abs(excursion_rad.select(subset))))

            # Second -- parameter fit
            # solve the normal equations
            sum_inv_u_sq = flex.sum(dspacings_env * dspacings_env)
            sum_inv_u = flex.sum(dspacings_env)
            sum_te_u = flex.sum(dspacings_env * excursion_rads_env)
            sum_te = flex.sum(excursion_rads_env)
            Normal_Mat = sqr(
                (sum_inv_u_sq, sum_inv_u, sum_inv_u, len(dspacings_env)))
            Vector = col((sum_te_u, sum_te))
            solution = Normal_Mat.inverse() * Vector
            s_ang = 1.0 / (2 * solution[0])
            logger.info("Best LSQ fit Scheerer domain size is %9.2f ang",
                        s_ang)

            k_degrees = solution[1] * 180.0 / math.pi
            logger.info(
                "The LSQ full mosaicity is %8.5f deg; half-mosaicity %9.5f",
                2 * k_degrees,
                k_degrees,
            )

            from xfel.mono_simulation.max_like import minimizer

            # coerce the estimates to be positive for max-likelihood
            lower_limit_domain_size = (
                math.pow(crystal.get_unit_cell().volume(), 1.0 / 3.0) * 3
            )  # params.refinement.domain_size_lower_limit

            d_estimate = max(s_ang, lower_limit_domain_size)
            M = minimizer(
                d_i=dspacings,
                psi_i=excursion_rad,
                eta_rad=abs(2.0 * solution[1]),
                Deff=d_estimate,
            )
            logger.info(
                "ML: mosaicity FW=%4.2f deg, Dsize=%5.0fA on %d spots",
                M.x[1] * 180.0 / math.pi,
                2.0 / M.x[0],
                len(two_thetas),
            )
            tan_phi_rad_ML = dspacings / (2.0 / M.x[0])
            tan_phi_deg_ML = tan_phi_rad_ML * 180.0 / math.pi
            tan_outer_deg_ML = tan_phi_deg_ML + 0.5 * M.x[1] * 180.0 / math.pi

            # Only set the flags for those reflections that were indexed for this lattice
            self.nv_acceptance_flags.set_selected(
                self.reflections["id"] == iid,
                flex.abs(delta_psi_deg) < tan_outer_deg_ML,
            )

            if (
                    self.graph_verbose
            ):  # params.refinement.mosaic.enable_AD14F7B: # Excursion vs resolution fit
                AD1TF7B_MAX2T = 30.0
                AD1TF7B_MAXDP = 1.0
                from matplotlib import pyplot as plt

                plt.plot(two_thetas, delta_psi_deg, "bo")
                minplot = flex.min(two_thetas)
                plt.plot([0, minplot], [mean_excursion, mean_excursion], "k-")
                LR = flex.linear_regression(two_thetas, delta_psi_deg)
                model_y = LR.slope() * two_thetas + LR.y_intercept()
                plt.plot(two_thetas, model_y, "k-")

                plt.title(
                    "ML: mosaicity FW=%4.2f deg, Dsize=%5.0fA on %d spots" %
                    (M.x[1] * 180.0 / math.pi, 2.0 / M.x[0], len(two_thetas)))
                plt.plot(two_thetas, tan_phi_deg_ML, "r.")
                plt.plot(two_thetas, -tan_phi_deg_ML, "r.")
                plt.plot(two_thetas, tan_outer_deg_ML, "g.")
                plt.plot(two_thetas, -tan_outer_deg_ML, "g.")
                plt.xlim([0, AD1TF7B_MAX2T])
                plt.ylim([-AD1TF7B_MAXDP, AD1TF7B_MAXDP])
                plt.show()
                plt.close()

            from xfel.mono_simulation.util import green_curve_area

            self.green_curve_area = green_curve_area(two_thetas,
                                                     tan_outer_deg_ML)
            logger.info("The green curve area is %s", self.green_curve_area)

            crystal.set_half_mosaicity_deg(M.x[1] * 180.0 / (2.0 * math.pi))
            crystal.set_domain_size_ang(2.0 / M.x[0])
            self._ML_full_mosaicity_rad = M.x[1]
            self._ML_domain_size_ang = 2.0 / M.x[0]

            # params.refinement.mosaic.model_expansion_factor
            """The expansion factor should be initially set to 1, then expanded so that the # reflections matched becomes
        as close as possible to # of observed reflections input, in the last integration call.  Determine this by
        inspecting the output log file interactively.  Do not exceed the bare minimum threshold needed.
        The intention is to find an optimal value, global for a given dataset."""
            model_expansion_factor = 1.4
            crystal.set_half_mosaicity_deg(crystal.get_half_mosaicity_deg() *
                                           model_expansion_factor)
            crystal.set_domain_size_ang(crystal.get_domain_size_ang() /
                                        model_expansion_factor)

            if (self.ewald_proximal_volume(iid) >
                    self.params.indexing.stills.ewald_proximal_volume_max):
                raise DialsIndexError("Ewald proximity volume too high, %f" %
                                      self.ewald_proximal_volume(iid))

            all_crystals.append(crystal)
        return all_crystals
예제 #3
0
def estimate_resolution_limit(reflections, ice_sel=None, plot_filename=None):
    if ice_sel is None:
        ice_sel = flex.bool(len(reflections), False)

    d_star_sq = flex.pow2(reflections["rlp"].norms())
    d_spacings = uctbx.d_star_sq_as_d(d_star_sq)

    intensities = reflections["intensity.sum.value"]
    variances = reflections["intensity.sum.variance"]

    sel = variances > 0
    intensities = intensities.select(sel)
    variances = variances.select(sel)
    ice_sel = ice_sel.select(sel)

    i_over_sigi = intensities / flex.sqrt(variances)
    log_i_over_sigi = flex.log(i_over_sigi)

    fit = flex.linear_regression(d_star_sq.select(~ice_sel),
                                 log_i_over_sigi.select(~ice_sel))
    m = fit.slope()
    c = fit.y_intercept()

    log_i_sigi_lower = flex.double()
    d_star_sq_lower = flex.double()
    log_i_sigi_upper = flex.double()
    d_star_sq_upper = flex.double()

    binner = binner_equal_population(d_star_sq,
                                     target_n_per_bin=20,
                                     max_slots=20,
                                     min_slots=5)

    outliers_all = flex.bool(len(reflections), False)

    low_percentile_limit = 0.1
    upper_percentile_limit = 1 - low_percentile_limit
    for i_slot, slot in enumerate(binner.bins):
        sel_all = (d_spacings < slot.d_max) & (d_spacings >= slot.d_min)
        sel = ~(ice_sel) & sel_all

        if sel.count(True) == 0:
            continue

        outliers = wilson_outliers(reflections.select(sel_all),
                                   ice_sel=ice_sel.select(sel_all))
        outliers_all.set_selected(sel_all, outliers)

        isel = sel_all.iselection().select(~(outliers)
                                           & ~(ice_sel).select(sel_all))
        log_i_over_sigi_sel = log_i_over_sigi.select(isel)
        d_star_sq_sel = d_star_sq.select(isel)

        perm = flex.sort_permutation(log_i_over_sigi_sel)
        i_lower = perm[int(math.floor(low_percentile_limit * len(perm)))]
        i_upper = perm[int(math.floor(upper_percentile_limit * len(perm)))]
        log_i_sigi_lower.append(log_i_over_sigi_sel[i_lower])
        log_i_sigi_upper.append(log_i_over_sigi_sel[i_upper])
        d_star_sq_upper.append(d_star_sq_sel[i_lower])
        d_star_sq_lower.append(d_star_sq_sel[i_upper])

    fit_upper = flex.linear_regression(d_star_sq_upper, log_i_sigi_upper)
    m_upper = fit_upper.slope()
    c_upper = fit_upper.y_intercept()
    fit_lower = flex.linear_regression(d_star_sq_lower, log_i_sigi_lower)
    m_lower = fit_lower.slope()
    c_lower = fit_lower.y_intercept()

    if m_upper == m_lower:
        intersection = (-1, -1)
        resolution_estimate = -1
        inside = flex.bool(len(d_star_sq), False)

    else:
        # http://en.wikipedia.org/wiki/Line%E2%80%93line_intersection#Given_the_equations_of_the_lines
        # with:
        # a_ = m_upper
        # b_ = m_lower
        # c_ = c_upper
        # d_ = c_lower
        # intersection == ((d_ - c_) / (a_ - b_), (a_ * d_ - b_ * c_) / (a_ - b_))
        intersection = (
            (c_lower - c_upper) / (m_upper - m_lower),
            (m_upper * c_lower - m_lower * c_upper) / (m_upper - m_lower),
        )

        inside = points_below_line(d_star_sq, log_i_over_sigi, m_upper,
                                   c_upper)
        inside = inside & ~outliers_all & ~ice_sel

        if inside.count(True) > 0:
            d_star_sq_estimate = flex.max(d_star_sq.select(inside))
            resolution_estimate = uctbx.d_star_sq_as_d(d_star_sq_estimate)
        else:
            resolution_estimate = -1

    if plot_filename is not None:
        from matplotlib import pyplot

        fig = pyplot.figure()
        ax = fig.add_subplot(1, 1, 1)
        ax.scatter(d_star_sq, log_i_over_sigi, marker="+")
        ax.scatter(
            d_star_sq.select(inside),
            log_i_over_sigi.select(inside),
            marker="+",
            color="green",
        )
        ax.scatter(
            d_star_sq.select(ice_sel),
            log_i_over_sigi.select(ice_sel),
            marker="+",
            color="black",
        )
        ax.scatter(
            d_star_sq.select(outliers_all),
            log_i_over_sigi.select(outliers_all),
            marker="+",
            color="grey",
        )
        ax.scatter(d_star_sq_upper, log_i_sigi_upper, marker="+", color="red")
        ax.scatter(d_star_sq_lower, log_i_sigi_lower, marker="+", color="red")

        if intersection[0] <= ax.get_xlim(
        )[1] and intersection[1] <= ax.get_ylim()[1]:
            ax.scatter([intersection[0]], [intersection[1]],
                       marker="x",
                       s=50,
                       color="b")
        xlim = pyplot.xlim()
        ax.plot(xlim, [(m * x + c) for x in xlim])
        ax.plot(xlim, [(m_upper * x + c_upper) for x in xlim], color="red")
        ax.plot(xlim, [(m_lower * x + c_lower) for x in xlim], color="red")
        ax.set_xlabel("d_star_sq")
        ax.set_ylabel("ln(I/sigI)")
        ax.set_xlim((max(-xlim[1], -0.05), xlim[1]))
        ax.set_ylim((0, ax.get_ylim()[1]))

        for i_slot, slot in enumerate(binner.bins):
            if i_slot == 0:
                ax.vlines(
                    uctbx.d_as_d_star_sq(slot.d_max),
                    0,
                    ax.get_ylim()[1],
                    linestyle="dotted",
                    color="grey",
                )
            ax.vlines(
                uctbx.d_as_d_star_sq(slot.d_min),
                0,
                ax.get_ylim()[1],
                linestyle="dotted",
                color="grey",
            )

        ax_ = ax.twiny()  # ax2 is responsible for "top" axis and "right" axis
        xticks = ax.get_xticks()
        xticks_d = [
            uctbx.d_star_sq_as_d(ds2) if ds2 > 0 else 0 for ds2 in xticks
        ]
        ax_.set_xticks(xticks)
        ax_.set_xlim(ax.get_xlim())
        ax_.set_xlabel(r"Resolution ($\AA$)")
        ax_.set_xticklabels(["%.1f" % d for d in xticks_d])
        pyplot.savefig(plot_filename)
        pyplot.close()

    return resolution_estimate
예제 #4
0
    def __call__(self):
        """Determine optimal mosaicity and domain size model (monochromatic)"""
        RR = self.refinery.predict_for_reflection_table(self.reflections)
        excursion_rad = RR["delpsical.rad"]
        delta_psi_deg = excursion_rad * 180. / math.pi
        print
        print flex.max(delta_psi_deg), flex.min(delta_psi_deg)
        mean_excursion = flex.mean(delta_psi_deg)
        print "The mean excursion is %7.3f degrees, r.m.s.d %7.3f" % (
            mean_excursion, math.sqrt(flex.mean(RR["delpsical2"])))

        crystal = self.experiments[0].crystal
        beam = self.experiments[0].beam
        miller_indices = self.reflections["miller_index"]

        # FIXME XXX revise this formula so as to use a different wavelength potentially for each reflection
        two_thetas = crystal.get_unit_cell().two_theta(miller_indices,
                                                       beam.get_wavelength(),
                                                       deg=True)
        dspacings = crystal.get_unit_cell().d(miller_indices)
        dspace_sq = dspacings * dspacings

        #  First -- try to get a reasonable envelope for the observed excursions.
        ## minimum of three regions; maximum of 50 measurements in each bin
        print "fitting parameters on %d spots" % len(excursion_rad)
        n_bins = min(max(3, len(excursion_rad) // 25), 50)
        bin_sz = len(excursion_rad) // n_bins
        print "nbins", n_bins, "bin_sz", bin_sz
        order = flex.sort_permutation(two_thetas)
        two_thetas_env = flex.double()
        dspacings_env = flex.double()
        excursion_rads_env = flex.double()
        for x in xrange(0, n_bins):
            subset = order[x * bin_sz:(x + 1) * bin_sz]
            two_thetas_env.append(flex.mean(two_thetas.select(subset)))
            dspacings_env.append(flex.mean(dspacings.select(subset)))
            excursion_rads_env.append(
                flex.max(flex.abs(excursion_rad.select(subset))))

        #  Second -- parameter fit
        ## solve the normal equations
        sum_inv_u_sq = flex.sum(dspacings_env * dspacings_env)
        sum_inv_u = flex.sum(dspacings_env)
        sum_te_u = flex.sum(dspacings_env * excursion_rads_env)
        sum_te = flex.sum(excursion_rads_env)
        Normal_Mat = sqr(
            (sum_inv_u_sq, sum_inv_u, sum_inv_u, len(dspacings_env)))
        Vector = col((sum_te_u, sum_te))
        solution = Normal_Mat.inverse() * Vector
        s_ang = 1. / (2 * solution[0])
        print "Best LSQ fit Scheerer domain size is %9.2f ang" % (s_ang)

        tan_phi_rad = dspacings / (2. * s_ang)
        tan_phi_deg = tan_phi_rad * 180. / math.pi
        k_degrees = solution[1] * 180. / math.pi
        print "The LSQ full mosaicity is %8.5f deg; half-mosaicity %9.5f" % (
            2 * k_degrees, k_degrees)
        tan_outer_deg = tan_phi_deg + k_degrees

        from xfel.mono_simulation.max_like import minimizer
        # coerce the estimates to be positive for max-likelihood
        lower_limit_domain_size = math.pow(
            crystal.get_unit_cell().volume(),
            1. / 3.) * 3  # params.refinement.domain_size_lower_limit

        d_estimate = max(s_ang, lower_limit_domain_size)
        M = minimizer(d_i=dspacings,
                      psi_i=excursion_rad,
                      eta_rad=abs(2. * solution[1]),
                      Deff=d_estimate)
        print "ML: mosaicity FW=%4.2f deg, Dsize=%5.0fA on %d spots" % (
            M.x[1] * 180. / math.pi, 2. / M.x[0], len(two_thetas))
        tan_phi_rad_ML = dspacings / (2. / M.x[0])
        tan_phi_deg_ML = tan_phi_rad_ML * 180. / math.pi
        tan_outer_deg_ML = tan_phi_deg_ML + 0.5 * M.x[1] * 180. / math.pi

        self.nv_acceptance_flags = flex.abs(delta_psi_deg) < tan_outer_deg_ML

        if self.graph_verbose:  #params.refinement.mosaic.enable_AD14F7B: # Excursion vs resolution fit
            AD1TF7B_MAX2T = 30.
            AD1TF7B_MAXDP = 1.
            from matplotlib import pyplot as plt
            plt.plot(two_thetas, delta_psi_deg, "bo")
            minplot = flex.min(two_thetas)
            plt.plot([0, minplot], [mean_excursion, mean_excursion], "k-")
            LR = flex.linear_regression(two_thetas, delta_psi_deg)
            model_y = LR.slope() * two_thetas + LR.y_intercept()
            plt.plot(two_thetas, model_y, "k-")

            plt.title("ML: mosaicity FW=%4.2f deg, Dsize=%5.0fA on %d spots" %
                      (M.x[1] * 180. / math.pi, 2. / M.x[0], len(two_thetas)))
            plt.plot(two_thetas, tan_phi_deg_ML, "r.")
            plt.plot(two_thetas, -tan_phi_deg_ML, "r.")
            plt.plot(two_thetas, tan_outer_deg_ML, "g.")
            plt.plot(two_thetas, -tan_outer_deg_ML, "g.")
            plt.xlim([0, AD1TF7B_MAX2T])
            plt.ylim([-AD1TF7B_MAXDP, AD1TF7B_MAXDP])
            plt.show()
            plt.close()

        from xfel.mono_simulation.util import green_curve_area
        self.green_curve_area = green_curve_area(two_thetas, tan_outer_deg_ML)
        print "The green curve area is ", self.green_curve_area

        crystal._ML_half_mosaicity_deg = M.x[1] * 180. / (2. * math.pi)
        crystal._ML_domain_size_ang = 2. / M.x[0]
        self._ML_full_mosaicity_rad = M.x[1]
        self._ML_domain_size_ang = 2. / M.x[0]

        #params.refinement.mosaic.model_expansion_factor
        """The expansion factor should be initially set to 1, then expanded so that the # reflections matched becomes
    as close as possible to # of observed reflections input, in the last integration call.  Determine this by
    inspecting the output log file interactively.  Do not exceed the bare minimum threshold needed.
    The intention is to find an optimal value, global for a given dataset."""
        model_expansion_factor = 1.4
        crystal._ML_half_mosaicity_deg *= model_expansion_factor
        crystal._ML_domain_size_ang /= model_expansion_factor

        return crystal
예제 #5
0
    def plot_one_model(self, nrow, out):
        fig = plt.subplot(self.gs[nrow * self.ncols])
        two_thetas = self.reduction.get_two_theta_deg()
        degrees = self.reduction.get_delta_psi_deg()

        if self.color_encoding == "conventional":
            positive = (self.reduction.i_sigi >= 0.)
            fig.plot(two_thetas.select(positive), degrees.select(positive),
                     "bo")
            fig.plot(two_thetas.select(~positive), degrees.select(~positive),
                     "r+")
        elif self.color_encoding == "I/sigma":
            positive = (self.reduction.i_sigi >= 0.)
            tt_selected = two_thetas.select(positive)
            dp_selected = degrees.select(positive)
            i_sigi_select = self.reduction.i_sigi.select(positive)
            order = flex.sort_permutation(i_sigi_select)
            tt_selected = tt_selected.select(order)
            dp_selected = dp_selected.select(order)
            i_sigi_selected = i_sigi_select.select(order)
            from matplotlib.colors import Normalize
            dnorm = Normalize()
            dcolors = i_sigi_selected.as_numpy_array()
            dnorm.autoscale(dcolors)
            N = len(dcolors)
            CMAP = plt.get_cmap("rainbow")
            if self.refined.get("partiality_array", None) is None:
                for n in xrange(N):
                    fig.plot([tt_selected[n]], [dp_selected[n]],
                             color=CMAP(dnorm(dcolors[n])),
                             marker=".",
                             markersize=10)
            else:
                partials = self.refined.get("partiality_array")
                partials_select = partials.select(positive)
                partials_selected = partials_select.select(order)
                assert len(partials) == len(positive)
                for n in xrange(N):
                    fig.plot([tt_selected[n]], [dp_selected[n]],
                             color=CMAP(dnorm(dcolors[n])),
                             marker=".",
                             markersize=20 * partials_selected[n])
                    # change the markersize to indicate partiality.
            negative = (self.reduction.i_sigi < 0.)
            fig.plot(two_thetas.select(negative),
                     degrees.select(negative),
                     "r+",
                     linewidth=1)
        else:
            strong = (self.reduction.i_sigi >= 10.)
            positive = ((~strong) & (self.reduction.i_sigi >= 0.))
            negative = (self.reduction.i_sigi < 0.)
            assert (strong.count(True) + positive.count(True) +
                    negative.count(True) == len(self.reduction.i_sigi))
            fig.plot(two_thetas.select(positive), degrees.select(positive),
                     "bo")
            fig.plot(two_thetas.select(strong),
                     degrees.select(strong),
                     marker='.',
                     linestyle='None',
                     markerfacecolor='#00ee00',
                     markersize=10)
            fig.plot(two_thetas.select(negative), degrees.select(negative),
                     "r+")

        # indicate the imposed resolution filter
        wavelength = self.reduction.experiment.beam.get_wavelength()
        imposed_res_filter = self.reduction.get_imposed_res_filter(out)
        resolution_markers = [
            a
            for a in [imposed_res_filter,
                      self.reduction.measurements.d_min()] if a is not None
        ]
        for RM in resolution_markers:
            two_th = (180. / math.pi) * 2. * math.asin(wavelength / (2. * RM))
            plt.plot([two_th, two_th],
                     [self.AD1TF7B_MAXDP * -0.8, self.AD1TF7B_MAXDP * 0.8],
                     'k-')
            plt.text(two_th, self.AD1TF7B_MAXDP * -0.9, "%4.2f" % RM)

        #indicate the linefit
        mean = flex.mean(degrees)
        minplot = flex.min(two_thetas)
        plt.plot([0, minplot], [mean, mean], "k-")
        LR = flex.linear_regression(two_thetas, degrees)
        model_y = LR.slope() * two_thetas + LR.y_intercept()
        plt.plot(two_thetas, model_y, "k-")

        #Now let's take care of the red and green lines.
        half_mosaic_rotation_deg = self.refined["half_mosaic_rotation_deg"]
        mosaic_domain_size_ang = self.refined["mosaic_domain_size_ang"]
        red_curve_domain_size_ang = self.refined.get(
            "red_curve_domain_size_ang", mosaic_domain_size_ang)
        a_step = self.AD1TF7B_MAX2T / 50.
        a_range = flex.double([a_step * x for x in xrange(1, 50)
                               ])  # domain two-theta array
        #Bragg law [d=L/2sinTH]
        d_spacing = (wavelength / (2. * flex.sin(math.pi * a_range / 360.)))
        # convert two_theta to a delta-psi.  Formula for Deffective [Dpsi=d/2Deff]
        inner_phi_deg = flex.asin(
            (d_spacing / (2. * red_curve_domain_size_ang))) * (180. / math.pi)
        outer_phi_deg = flex.asin((d_spacing / (2.*mosaic_domain_size_ang)) + \
          half_mosaic_rotation_deg*math.pi/180. )*(180./math.pi)
        plt.title("ML: mosaicity FW=%4.2f deg, Dsize=%5.0fA on %d spots\n%s" %
                  (2. * half_mosaic_rotation_deg, mosaic_domain_size_ang,
                   len(two_thetas), os.path.basename(self.reduction.filename)))
        plt.plot(a_range, inner_phi_deg, "r-")
        plt.plot(a_range, -inner_phi_deg, "r-")
        plt.plot(a_range, outer_phi_deg, "g-")
        plt.plot(a_range, -outer_phi_deg, "g-")
        plt.xlim([0, self.AD1TF7B_MAX2T])
        plt.ylim([-self.AD1TF7B_MAXDP, self.AD1TF7B_MAXDP])

        #second plot shows histogram
        fig = plt.subplot(self.gs[1 + nrow * self.ncols])
        plt.xlim([-self.AD1TF7B_MAXDP, self.AD1TF7B_MAXDP])
        nbins = 50
        n, bins, patches = plt.hist(
            dp_selected,
            nbins,
            range=(-self.AD1TF7B_MAXDP, self.AD1TF7B_MAXDP),
            weights=self.reduction.i_sigi.select(positive),
            normed=0,
            facecolor="orange",
            alpha=0.75)
        #ersatz determine the median i_sigi point:
        isi_positive = self.reduction.i_sigi.select(positive)
        isi_order = flex.sort_permutation(isi_positive)
        reordered = isi_positive.select(isi_order)
        isi_median = reordered[int(len(isi_positive) * 0.9)]
        isi_top_half_selection = (isi_positive > isi_median)
        n, bins, patches = plt.hist(
            dp_selected.select(isi_top_half_selection),
            nbins,
            range=(-self.AD1TF7B_MAXDP, self.AD1TF7B_MAXDP),
            weights=isi_positive.select(isi_top_half_selection),
            normed=0,
            facecolor="#ff0000",
            alpha=0.75)
        plt.xlabel("(degrees)")
        plt.title("Weighted histogram of Delta-psi")
예제 #6
0
  def plot_one_model(self,nrow,out):
    fig = plt.subplot(self.gs[nrow*self.ncols])
    two_thetas = self.reduction.get_two_theta_deg()
    degrees = self.reduction.get_delta_psi_deg()

    if self.color_encoding=="conventional":
          positive = (self.reduction.i_sigi>=0.)
          fig.plot(two_thetas.select(positive), degrees.select(positive), "bo")
          fig.plot(two_thetas.select(~positive), degrees.select(~positive), "r+")
    elif self.color_encoding=="I/sigma":
          positive = (self.reduction.i_sigi>=0.)
          tt_selected = two_thetas.select(positive)
          dp_selected = degrees.select(positive)
          i_sigi_select = self.reduction.i_sigi.select(positive)
          order = flex.sort_permutation(i_sigi_select)
          tt_selected = tt_selected.select(order)
          dp_selected = dp_selected.select(order)
          i_sigi_selected = i_sigi_select.select(order)
          from matplotlib.colors import Normalize
          dnorm = Normalize()
          dcolors = i_sigi_selected.as_numpy_array()
          dnorm.autoscale(dcolors)
          N = len(dcolors)
          CMAP = plt.get_cmap("rainbow")
          if self.refined.get("partiality_array",None) is None:
            for n in xrange(N):
              fig.plot([tt_selected[n]],[dp_selected[n]],
              color=CMAP(dnorm(dcolors[n])),marker=".", markersize=10)
          else:
            partials = self.refined.get("partiality_array")
            partials_select = partials.select(positive)
            partials_selected = partials_select.select(order)
            assert len(partials)==len(positive)
            for n in xrange(N):
              fig.plot([tt_selected[n]],[dp_selected[n]],
              color=CMAP(dnorm(dcolors[n])),marker=".", markersize=20*partials_selected[n])
              # change the markersize to indicate partiality.
          negative = (self.reduction.i_sigi<0.)
          fig.plot(two_thetas.select(negative), degrees.select(negative), "r+", linewidth=1)
    else:
          strong = (self.reduction.i_sigi>=10.)
          positive = ((~strong) & (self.reduction.i_sigi>=0.))
          negative = (self.reduction.i_sigi<0.)
          assert (strong.count(True)+positive.count(True)+negative.count(True) ==
                  len(self.reduction.i_sigi))
          fig.plot(two_thetas.select(positive), degrees.select(positive), "bo")
          fig.plot(two_thetas.select(strong), degrees.select(strong), marker='.',linestyle='None',
           markerfacecolor='#00ee00', markersize=10)
          fig.plot(two_thetas.select(negative), degrees.select(negative), "r+")

    # indicate the imposed resolution filter
    wavelength = self.reduction.experiment.beam.get_wavelength()
    imposed_res_filter = self.reduction.get_imposed_res_filter(out)
    resolution_markers = [
      a for a in [imposed_res_filter,self.reduction.measurements.d_min()] if a is not None]
    for RM in resolution_markers:
          two_th = (180./math.pi)*2.*math.asin(wavelength/(2.*RM))
          plt.plot([two_th, two_th],[self.AD1TF7B_MAXDP*-0.8,self.AD1TF7B_MAXDP*0.8],'k-')
          plt.text(two_th,self.AD1TF7B_MAXDP*-0.9,"%4.2f"%RM)

    #indicate the linefit
    mean = flex.mean(degrees)
    minplot = flex.min(two_thetas)
    plt.plot([0,minplot],[mean,mean],"k-")
    LR = flex.linear_regression(two_thetas, degrees)
    model_y = LR.slope()*two_thetas + LR.y_intercept()
    plt.plot(two_thetas, model_y, "k-")

    #Now let's take care of the red and green lines.
    half_mosaic_rotation_deg = self.refined["half_mosaic_rotation_deg"]
    mosaic_domain_size_ang = self.refined["mosaic_domain_size_ang"]
    red_curve_domain_size_ang = self.refined.get("red_curve_domain_size_ang",mosaic_domain_size_ang)
    a_step = self.AD1TF7B_MAX2T / 50.
    a_range = flex.double([a_step*x for x in xrange(1,50)]) # domain two-theta array
    #Bragg law [d=L/2sinTH]
    d_spacing = (wavelength/(2.*flex.sin(math.pi*a_range/360.)))
    # convert two_theta to a delta-psi.  Formula for Deffective [Dpsi=d/2Deff]
    inner_phi_deg = flex.asin((d_spacing / (2.*red_curve_domain_size_ang)) )*(180./math.pi)
    outer_phi_deg = flex.asin((d_spacing / (2.*mosaic_domain_size_ang)) + \
      half_mosaic_rotation_deg*math.pi/180. )*(180./math.pi)
    plt.title("ML: mosaicity FW=%4.2f deg, Dsize=%5.0fA on %d spots\n%s"%(
          2.*half_mosaic_rotation_deg, mosaic_domain_size_ang, len(two_thetas),
          os.path.basename(self.reduction.filename)))
    plt.plot(a_range, inner_phi_deg, "r-")
    plt.plot(a_range,-inner_phi_deg, "r-")
    plt.plot(a_range, outer_phi_deg, "g-")
    plt.plot(a_range, -outer_phi_deg, "g-")
    plt.xlim([0,self.AD1TF7B_MAX2T])
    plt.ylim([-self.AD1TF7B_MAXDP,self.AD1TF7B_MAXDP])

    #second plot shows histogram
    fig = plt.subplot(self.gs[1+nrow*self.ncols])
    plt.xlim([-self.AD1TF7B_MAXDP,self.AD1TF7B_MAXDP])
    nbins = 50
    n,bins,patches = plt.hist(dp_selected, nbins,
           range=(-self.AD1TF7B_MAXDP,self.AD1TF7B_MAXDP),
           weights=self.reduction.i_sigi.select(positive),
           normed=0, facecolor="orange", alpha=0.75)
    #ersatz determine the median i_sigi point:
    isi_positive = self.reduction.i_sigi.select(positive)
    isi_order = flex.sort_permutation(isi_positive)
    reordered = isi_positive.select(isi_order)
    isi_median = reordered[int(len(isi_positive)*0.9)]
    isi_top_half_selection = (isi_positive>isi_median)
    n,bins,patches = plt.hist(dp_selected.select(isi_top_half_selection), nbins,
           range=(-self.AD1TF7B_MAXDP,self.AD1TF7B_MAXDP),
           weights=isi_positive.select(isi_top_half_selection),
           normed=0, facecolor="#ff0000", alpha=0.75)
    plt.xlabel("(degrees)")
    plt.title("Weighted histogram of Delta-psi")
예제 #7
0
def run(args):
    import libtbx.load_env
    usage = "%s experiments.json indexed.pickle [options]" % libtbx.env.dispatcher_name

    parser = OptionParser(usage=usage,
                          phil=phil_scope,
                          read_experiments=True,
                          read_reflections=True,
                          check_format=False,
                          epilog=help_message)

    params, options = parser.parse_args(show_diff_phil=True)
    experiments = flatten_experiments(params.input.experiments)
    reflections = flatten_reflections(params.input.reflections)
    if len(experiments) == 0:
        parser.print_help()
        return
    elif len(experiments) > 1:
        raise Sorry("More than one experiment present")

    experiment = experiments[0]
    assert (len(reflections) == 1)
    reflections = reflections[0]

    intensities = reflections['intensity.sum.value']
    variances = reflections['intensity.sum.variance']
    if 'intensity.prf.value' in reflections:
        intensities = reflections['intensity.prf.value']
        variances = reflections['intensity.prf.variance']
    sel = (variances > 0)
    intensities = intensities.select(sel)
    variances = variances.select(sel)
    sigmas = flex.sqrt(variances)
    indices = reflections['miller_index'].select(sel)

    from cctbx import crystal, miller
    crystal_symmetry = crystal.symmetry(
        space_group=experiment.crystal.get_space_group(),
        unit_cell=experiment.crystal.get_unit_cell())

    miller_set = miller.set(crystal_symmetry=crystal_symmetry,
                            anomalous_flag=True,
                            indices=indices)
    miller_array = miller.array(
        miller_set=miller_set, data=intensities,
        sigmas=sigmas).set_observation_type_xray_intensity()

    #miller_array.setup_binner(n_bins=50, reflections_per_bin=100)
    miller_array.setup_binner(auto_binning=True, n_bins=20)
    result = miller_array.i_over_sig_i(use_binning=True)
    result.show()

    from cctbx import uctbx
    d_star_sq_centre = result.binner.bin_centers(2)
    i_over_sig_i = flex.double(
        [d if d is not None else 0 for d in result.data[1:-1]])
    sel = (i_over_sig_i > 0)
    d_star_sq_centre = d_star_sq_centre.select(sel)
    i_over_sig_i = i_over_sig_i.select(sel)
    log_i_over_sig_i = flex.log(i_over_sig_i)
    weights = result.binner.counts()[1:-1].as_double().select(sel)
    fit = flex.linear_regression(d_star_sq_centre,
                                 log_i_over_sig_i,
                                 weights=weights)

    m = fit.slope()
    c = fit.y_intercept()

    import math
    y_cutoff = math.log(params.i_sigi_cutoff)
    x_cutoff = (y_cutoff - c) / m

    estimated_d_min = uctbx.d_star_sq_as_d(x_cutoff)
    print "estimated d_min: %.2f" % estimated_d_min

    if params.plot:
        from matplotlib import pyplot
        fig = pyplot.figure()
        ax = fig.add_subplot(1, 1, 1)

        ax.plot(list(d_star_sq_centre),
                list(log_i_over_sig_i),
                label=r"ln(I/sigI)")
        ax.plot(pyplot.xlim(), [(m * x + c) for x in pyplot.xlim()],
                color='red')
        ax.plot([x_cutoff, x_cutoff],
                pyplot.ylim(),
                color='grey',
                linestyle='dashed')
        ax.plot(pyplot.xlim(), [y_cutoff, y_cutoff],
                color='grey',
                linestyle='dashed')
        ax.set_xlabel("d_star_sq")
        ax.set_ylabel("ln(I/sigI)")

        ax_ = ax.twiny()  # ax2 is responsible for "top" axis and "right" axis
        xticks = ax.get_xticks()
        xlim = ax.get_xlim()
        xticks_d = [
            uctbx.d_star_sq_as_d(ds2) if ds2 > 0 else 0 for ds2 in xticks
        ]
        xticks_ = [ds2 / (xlim[1] - xlim[0]) for ds2 in xticks]
        ax_.set_xticks(xticks)
        ax_.set_xlim(ax.get_xlim())
        ax_.set_xlabel(r"Resolution ($\AA$)")
        ax_.set_xticklabels(["%.1f" % d for d in xticks_d])
        pyplot.savefig("estimate_resolution_limit.png")
        pyplot.clf()
예제 #8
0
def estimate_resolution_limit(reflections,
                              imageset,
                              ice_sel=None,
                              plot_filename=None):

    if ice_sel is None:
        ice_sel = flex.bool(len(reflections), False)

    d_star_sq = flex.pow2(reflections['rlp'].norms())
    d_spacings = uctbx.d_star_sq_as_d(d_star_sq)

    intensities = reflections['intensity.sum.value']
    variances = reflections['intensity.sum.variance']

    sel = variances > 0
    intensities = intensities.select(sel)
    variances = variances.select(sel)
    ice_sel = ice_sel.select(sel)

    i_over_sigi = intensities / flex.sqrt(variances)
    log_i_over_sigi = flex.log(i_over_sigi)

    fit = flex.linear_regression(d_star_sq.select(~ice_sel),
                                 log_i_over_sigi.select(~ice_sel))
    m = fit.slope()
    c = fit.y_intercept()

    log_i_sigi_lower = flex.double()
    d_star_sq_lower = flex.double()
    log_i_sigi_upper = flex.double()
    d_star_sq_upper = flex.double()

    binner = binner_equal_population(d_star_sq,
                                     target_n_per_bin=20,
                                     max_slots=20,
                                     min_slots=5)

    outliers_all = flex.bool(len(reflections), False)

    low_percentile_limit = 0.1
    upper_percentile_limit = 1 - low_percentile_limit
    d_spacings = uctbx.d_star_sq_as_d(d_star_sq)
    for i_slot, slot in enumerate(binner.bins):
        sel_all = (d_spacings < slot.d_max) & (d_spacings >= slot.d_min)
        sel = ~(ice_sel) & sel_all
        #sel = ~(ice_sel) & (d_spacings < slot.d_max) & (d_spacings >= slot.d_min)

        #print "%.2f" %(sel.count(True)/sel_all.count(True))

        if sel.count(True) == 0:
            #outliers_all.set_selected(sel_all & ice_sel, True)
            continue
            #if i_slot > i_slot_max:
            #break
            #else:
            #continue

        outliers = wilson_outliers(reflections.select(sel_all),
                                   ice_sel=ice_sel.select(sel_all))
        #print "rejecting %d wilson outliers" %outliers.count(True)
        outliers_all.set_selected(sel_all, outliers)

        #if sel.count(True)/sel_all.count(True) < 0.25:
        #outliers_all.set_selected(sel_all & ice_sel, True)

        #from scitbx.math import median_statistics
        #intensities_sel = intensities.select(sel)
        #stats = median_statistics(intensities_sel)
        #z_score = 0.6745 * (intensities_sel - stats.median)/stats.median_absolute_deviation
        #outliers = z_score > 3.5
        #perm = flex.sort_permutation(intensities_sel)
        ##print ' '.join('%.2f' %v for v in intensities_sel.select(perm))
        ##print ' '.join('%.2f' %v for v in z_score.select(perm))
        ##print

        isel = sel_all.iselection().select(~(outliers)
                                           & ~(ice_sel).select(sel_all))
        log_i_over_sigi_sel = log_i_over_sigi.select(isel)
        d_star_sq_sel = d_star_sq.select(isel)

        perm = flex.sort_permutation(log_i_over_sigi_sel)
        i_lower = perm[int(math.floor(low_percentile_limit * len(perm)))]
        i_upper = perm[int(math.floor(upper_percentile_limit * len(perm)))]
        log_i_sigi_lower.append(log_i_over_sigi_sel[i_lower])
        log_i_sigi_upper.append(log_i_over_sigi_sel[i_upper])
        d_star_sq_upper.append(d_star_sq_sel[i_lower])
        d_star_sq_lower.append(d_star_sq_sel[i_upper])

    fit_upper = flex.linear_regression(d_star_sq_upper, log_i_sigi_upper)
    m_upper = fit_upper.slope()
    c_upper = fit_upper.y_intercept()
    fit_lower = flex.linear_regression(d_star_sq_lower, log_i_sigi_lower)
    m_lower = fit_lower.slope()
    c_lower = fit_lower.y_intercept()

    #fit_upper.show_summary()
    #fit_lower.show_summary()

    if m_upper == m_lower:
        intersection = (-1, -1)
        resolution_estimate = -1
        inside = flex.bool(len(d_star_sq), False)

    else:
        # http://en.wikipedia.org/wiki/Line%E2%80%93line_intersection#Given_the_equations_of_the_lines
        intersection = ((c_lower - c_upper) / (m_upper - m_lower),
                        (m_upper * c_lower - m_lower * c_upper) /
                        (m_upper - m_lower))

        a = m_upper
        c_ = c_upper
        b = m_lower
        d = c_lower
        assert intersection == ((d - c_) / (a - b), (a * d - b * c_) / (a - b))

        #inside = points_inside_envelope(
        #d_star_sq, log_i_over_sigi, m_upper, c_upper, m_lower, c_lower)

        inside = points_below_line(d_star_sq, log_i_over_sigi, m_upper,
                                   c_upper)
        inside = inside & ~outliers_all

        if inside.count(True) > 0:
            d_star_sq_estimate = flex.max(d_star_sq.select(inside))
            #d_star_sq_estimate = intersection[0]
            resolution_estimate = uctbx.d_star_sq_as_d(d_star_sq_estimate)
        else:
            resolution_estimate = -1

    #resolution_estimate = max(resolution_estimate, flex.min(d_spacings))

    if plot_filename is not None:
        if pyplot is None:
            raise Sorry("matplotlib must be installed to generate a plot.")
        fig = pyplot.figure()
        ax = fig.add_subplot(1, 1, 1)
        ax.scatter(d_star_sq, log_i_over_sigi, marker='+')
        ax.scatter(d_star_sq.select(inside),
                   log_i_over_sigi.select(inside),
                   marker='+',
                   color='green')
        ax.scatter(d_star_sq.select(ice_sel),
                   log_i_over_sigi.select(ice_sel),
                   marker='+',
                   color='black')
        ax.scatter(d_star_sq.select(outliers_all),
                   log_i_over_sigi.select(outliers_all),
                   marker='+',
                   color='grey')
        ax.scatter(d_star_sq_upper, log_i_sigi_upper, marker='+', color='red')
        ax.scatter(d_star_sq_lower, log_i_sigi_lower, marker='+', color='red')

        if (intersection[0] <= ax.get_xlim()[1]
                and intersection[1] <= ax.get_ylim()[1]):
            ax.scatter([intersection[0]], [intersection[1]],
                       marker='x',
                       s=50,
                       color='b')
        #ax.hexbin(d_star_sq, log_i_over_sigi, gridsize=30)
        xlim = pyplot.xlim()
        ax.plot(xlim, [(m * x + c) for x in xlim])
        ax.plot(xlim, [(m_upper * x + c_upper) for x in xlim], color='red')
        ax.plot(xlim, [(m_lower * x + c_lower) for x in xlim], color='red')
        ax.set_xlabel('d_star_sq')
        ax.set_ylabel('ln(I/sigI)')
        ax.set_xlim((max(-xlim[1], -0.05), xlim[1]))
        ax.set_ylim((0, ax.get_ylim()[1]))

        for i_slot, slot in enumerate(binner.bins):
            if i_slot == 0:
                ax.vlines(uctbx.d_as_d_star_sq(slot.d_max),
                          0,
                          ax.get_ylim()[1],
                          linestyle='dotted',
                          color='grey')
            ax.vlines(uctbx.d_as_d_star_sq(slot.d_min),
                      0,
                      ax.get_ylim()[1],
                      linestyle='dotted',
                      color='grey')

        ax_ = ax.twiny()  # ax2 is responsible for "top" axis and "right" axis
        xticks = ax.get_xticks()
        xlim = ax.get_xlim()
        xticks_d = [
            uctbx.d_star_sq_as_d(ds2) if ds2 > 0 else 0 for ds2 in xticks
        ]
        xticks_ = [ds2 / (xlim[1] - xlim[0]) for ds2 in xticks]
        ax_.set_xticks(xticks)
        ax_.set_xlim(ax.get_xlim())
        ax_.set_xlabel(r"Resolution ($\AA$)")
        ax_.set_xticklabels(["%.1f" % d for d in xticks_d])
        #pyplot.show()
        pyplot.savefig(plot_filename)
        pyplot.close()

    return resolution_estimate
예제 #9
0
def estimate_resolution_limit(reflections, imageset, ice_sel=None,
                              plot_filename=None):

  if ice_sel is None:
    ice_sel = flex.bool(len(reflections), False)

  d_star_sq = flex.pow2(reflections['rlp'].norms())
  d_spacings = uctbx.d_star_sq_as_d(d_star_sq)

  intensities = reflections['intensity.sum.value']
  variances = reflections['intensity.sum.variance']

  sel = variances > 0
  intensities = intensities.select(sel)
  variances = variances.select(sel)
  ice_sel = ice_sel.select(sel)

  i_over_sigi = intensities/flex.sqrt(variances)
  log_i_over_sigi = flex.log(i_over_sigi)

  fit = flex.linear_regression(
    d_star_sq.select(~ice_sel), log_i_over_sigi.select(~ice_sel))
  m = fit.slope()
  c = fit.y_intercept()

  log_i_sigi_lower = flex.double()
  d_star_sq_lower = flex.double()
  log_i_sigi_upper = flex.double()
  d_star_sq_upper = flex.double()

  binner = binner_equal_population(
    d_star_sq, target_n_per_bin=20, max_slots=20, min_slots=5)

  outliers_all = flex.bool(len(reflections), False)

  low_percentile_limit = 0.1
  upper_percentile_limit = 1-low_percentile_limit
  d_spacings = uctbx.d_star_sq_as_d(d_star_sq)
  for i_slot, slot in enumerate(binner.bins):
    sel_all = (d_spacings < slot.d_max) & (d_spacings >= slot.d_min)
    sel = ~(ice_sel) & sel_all
    #sel = ~(ice_sel) & (d_spacings < slot.d_max) & (d_spacings >= slot.d_min)

    #print "%.2f" %(sel.count(True)/sel_all.count(True))

    if sel.count(True) == 0:
      #outliers_all.set_selected(sel_all & ice_sel, True)
      continue
      #if i_slot > i_slot_max:
        #break
      #else:
        #continue

    outliers = wilson_outliers(
      reflections.select(sel_all), ice_sel=ice_sel.select(sel_all))
    #print "rejecting %d wilson outliers" %outliers.count(True)
    outliers_all.set_selected(sel_all, outliers)

    #if sel.count(True)/sel_all.count(True) < 0.25:
      #outliers_all.set_selected(sel_all & ice_sel, True)

    #from scitbx.math import median_statistics
    #intensities_sel = intensities.select(sel)
    #stats = median_statistics(intensities_sel)
    #z_score = 0.6745 * (intensities_sel - stats.median)/stats.median_absolute_deviation
    #outliers = z_score > 3.5
    #perm = flex.sort_permutation(intensities_sel)
    ##print ' '.join('%.2f' %v for v in intensities_sel.select(perm))
    ##print ' '.join('%.2f' %v for v in z_score.select(perm))
    ##print

    isel = sel_all.iselection().select(~(outliers) & ~(ice_sel).select(sel_all))
    log_i_over_sigi_sel = log_i_over_sigi.select(isel)
    d_star_sq_sel = d_star_sq.select(isel)

    perm = flex.sort_permutation(log_i_over_sigi_sel)
    i_lower = perm[int(math.floor(low_percentile_limit * len(perm)))]
    i_upper = perm[int(math.floor(upper_percentile_limit * len(perm)))]
    log_i_sigi_lower.append(log_i_over_sigi_sel[i_lower])
    log_i_sigi_upper.append(log_i_over_sigi_sel[i_upper])
    d_star_sq_upper.append(d_star_sq_sel[i_lower])
    d_star_sq_lower.append(d_star_sq_sel[i_upper])

  fit_upper = flex.linear_regression(d_star_sq_upper, log_i_sigi_upper)
  m_upper = fit_upper.slope()
  c_upper = fit_upper.y_intercept()
  fit_lower = flex.linear_regression(d_star_sq_lower, log_i_sigi_lower)
  m_lower = fit_lower.slope()
  c_lower = fit_lower.y_intercept()

  #fit_upper.show_summary()
  #fit_lower.show_summary()

  if m_upper == m_lower:
    intersection = (-1,-1)
    resolution_estimate = -1
    inside = flex.bool(len(d_star_sq), False)

  else:
    # http://en.wikipedia.org/wiki/Line%E2%80%93line_intersection#Given_the_equations_of_the_lines
    intersection = (
      (c_lower-c_upper)/(m_upper-m_lower),
      (m_upper*c_lower-m_lower*c_upper)/(m_upper-m_lower))

    a = m_upper
    c_ = c_upper
    b = m_lower
    d = c_lower
    assert intersection == ((d-c_)/(a-b), (a*d-b*c_)/(a-b))

    #inside = points_inside_envelope(
      #d_star_sq, log_i_over_sigi, m_upper, c_upper, m_lower, c_lower)

    inside = points_below_line(d_star_sq, log_i_over_sigi, m_upper, c_upper)
    inside = inside & ~outliers_all

    if inside.count(True) > 0:
      d_star_sq_estimate = flex.max(d_star_sq.select(inside))
      #d_star_sq_estimate = intersection[0]
      resolution_estimate = uctbx.d_star_sq_as_d(d_star_sq_estimate)
    else:
      resolution_estimate = -1

  #resolution_estimate = max(resolution_estimate, flex.min(d_spacings))

  if plot_filename is not None:
    if pyplot is None:
      raise Sorry("matplotlib must be installed to generate a plot.")
    fig = pyplot.figure()
    ax = fig.add_subplot(1,1,1)
    ax.scatter(d_star_sq, log_i_over_sigi, marker='+')
    ax.scatter(d_star_sq.select(inside), log_i_over_sigi.select(inside),
               marker='+', color='green')
    ax.scatter(d_star_sq.select(ice_sel),
               log_i_over_sigi.select(ice_sel),
               marker='+', color='black')
    ax.scatter(d_star_sq.select(outliers_all),
               log_i_over_sigi.select(outliers_all),
               marker='+', color='grey')
    ax.scatter(d_star_sq_upper, log_i_sigi_upper, marker='+', color='red')
    ax.scatter(d_star_sq_lower, log_i_sigi_lower, marker='+', color='red')

    if (intersection[0] <= ax.get_xlim()[1] and
        intersection[1] <= ax.get_ylim()[1]):
      ax.scatter([intersection[0]], [intersection[1]], marker='x', s=50, color='b')
    #ax.hexbin(d_star_sq, log_i_over_sigi, gridsize=30)
    xlim = pyplot.xlim()
    ax.plot(xlim, [(m * x + c) for x in xlim])
    ax.plot(xlim, [(m_upper * x + c_upper) for x in xlim], color='red')
    ax.plot(xlim, [(m_lower * x + c_lower) for x in xlim], color='red')
    ax.set_xlabel('d_star_sq')
    ax.set_ylabel('ln(I/sigI)')
    ax.set_xlim((max(-xlim[1], -0.05), xlim[1]))
    ax.set_ylim((0, ax.get_ylim()[1]))

    for i_slot, slot in enumerate(binner.bins):
      if i_slot == 0:
        ax.vlines(uctbx.d_as_d_star_sq(slot.d_max), 0, ax.get_ylim()[1],
                  linestyle='dotted', color='grey')
      ax.vlines(uctbx.d_as_d_star_sq(slot.d_min), 0, ax.get_ylim()[1],
                linestyle='dotted', color='grey')

    ax_ = ax.twiny() # ax2 is responsible for "top" axis and "right" axis
    xticks = ax.get_xticks()
    xlim = ax.get_xlim()
    xticks_d = [
      uctbx.d_star_sq_as_d(ds2) if ds2 > 0 else 0 for ds2 in xticks ]
    xticks_ = [ds2/(xlim[1]-xlim[0]) for ds2 in xticks]
    ax_.set_xticks(xticks)
    ax_.set_xlim(ax.get_xlim())
    ax_.set_xlabel(r"Resolution ($\AA$)")
    ax_.set_xticklabels(["%.1f" %d for d in xticks_d])
    #pyplot.show()
    pyplot.savefig(plot_filename)
    pyplot.close()

  return resolution_estimate
예제 #10
0
  def __call__(self):
    """Determine optimal mosaicity and domain size model (monochromatic)"""
    RR = self.refinery.predict_for_reflection_table(self.reflections)
    excursion_rad = RR["delpsical.rad"]
    delta_psi_deg = excursion_rad * 180./math.pi
    print
    print flex.max(delta_psi_deg), flex.min(delta_psi_deg)
    mean_excursion = flex.mean(delta_psi_deg)
    print "The mean excursion is %7.3f degrees, r.m.s.d %7.3f"%(mean_excursion, math.sqrt(flex.mean(RR["delpsical2"])))

    crystal = self.experiments[0].crystal
    beam = self.experiments[0].beam
    miller_indices = self.reflections["miller_index"]

    # FIXME XXX revise this formula so as to use a different wavelength potentially for each reflection
    two_thetas = crystal.get_unit_cell().two_theta(miller_indices,beam.get_wavelength(),deg=True)
    dspacings = crystal.get_unit_cell().d(miller_indices)
    dspace_sq = dspacings * dspacings

    #  First -- try to get a reasonable envelope for the observed excursions.
        ## minimum of three regions; maximum of 50 measurements in each bin
    print "fitting parameters on %d spots"%len(excursion_rad)
    n_bins = min(max(3, len(excursion_rad)//25),50)
    bin_sz = len(excursion_rad)//n_bins
    print "nbins",n_bins,"bin_sz",bin_sz
    order = flex.sort_permutation(two_thetas)
    two_thetas_env = flex.double()
    dspacings_env = flex.double()
    excursion_rads_env = flex.double()
    for x in xrange(0,n_bins):
      subset = order[x*bin_sz:(x+1)*bin_sz]
      two_thetas_env.append(flex.mean(two_thetas.select(subset)))
      dspacings_env.append(flex.mean(dspacings.select(subset)))
      excursion_rads_env.append(flex.max(flex.abs(excursion_rad.select(subset))))

    #  Second -- parameter fit
        ## solve the normal equations
    sum_inv_u_sq = flex.sum(dspacings_env * dspacings_env)
    sum_inv_u    = flex.sum(dspacings_env)
    sum_te_u     = flex.sum(dspacings_env * excursion_rads_env)
    sum_te       = flex.sum(excursion_rads_env)
    Normal_Mat   = sqr((sum_inv_u_sq, sum_inv_u, sum_inv_u, len(dspacings_env)))
    Vector       = col((sum_te_u, sum_te))
    solution     = Normal_Mat.inverse() * Vector
    s_ang = 1./(2*solution[0])
    print "Best LSQ fit Scheerer domain size is %9.2f ang"%(
      s_ang)

    tan_phi_rad = dspacings / (2. * s_ang)
    tan_phi_deg = tan_phi_rad * 180./math.pi
    k_degrees = solution[1]* 180./math.pi
    print "The LSQ full mosaicity is %8.5f deg; half-mosaicity %9.5f"%(2*k_degrees, k_degrees)
    tan_outer_deg = tan_phi_deg + k_degrees

    from xfel.mono_simulation.max_like import minimizer
    # coerce the estimates to be positive for max-likelihood
    lower_limit_domain_size = math.pow(crystal.get_unit_cell().volume(),
     1./3.)*3 # params.refinement.domain_size_lower_limit

    d_estimate = max(s_ang, lower_limit_domain_size)
    M = minimizer(d_i = dspacings, psi_i = excursion_rad, eta_rad = abs(2. * solution[1]),
                  Deff = d_estimate)
    print "ML: mosaicity FW=%4.2f deg, Dsize=%5.0fA on %d spots"%(M.x[1]*180./math.pi, 2./M.x[0], len(two_thetas))
    tan_phi_rad_ML = dspacings / (2. / M.x[0])
    tan_phi_deg_ML = tan_phi_rad_ML * 180./math.pi
    tan_outer_deg_ML = tan_phi_deg_ML + 0.5*M.x[1]*180./math.pi

    self.nv_acceptance_flags = flex.abs(delta_psi_deg) < tan_outer_deg_ML

    if self.graph_verbose: #params.refinement.mosaic.enable_AD14F7B: # Excursion vs resolution fit
      AD1TF7B_MAX2T = 30.
      AD1TF7B_MAXDP = 1.
      from matplotlib import pyplot as plt
      plt.plot(two_thetas, delta_psi_deg, "bo")
      minplot = flex.min(two_thetas)
      plt.plot([0,minplot],[mean_excursion,mean_excursion],"k-")
      LR = flex.linear_regression(two_thetas, delta_psi_deg)
      model_y = LR.slope()*two_thetas + LR.y_intercept()
      plt.plot(two_thetas, model_y, "k-")

      plt.title("ML: mosaicity FW=%4.2f deg, Dsize=%5.0fA on %d spots"%(M.x[1]*180./math.pi, 2./M.x[0], len(two_thetas)))
      plt.plot(two_thetas, tan_phi_deg_ML, "r.")
      plt.plot(two_thetas, -tan_phi_deg_ML, "r.")
      plt.plot(two_thetas, tan_outer_deg_ML, "g.")
      plt.plot(two_thetas, -tan_outer_deg_ML, "g.")
      plt.xlim([0,AD1TF7B_MAX2T])
      plt.ylim([-AD1TF7B_MAXDP,AD1TF7B_MAXDP])
      plt.show()
      plt.close()

    from xfel.mono_simulation.util import green_curve_area
    self.green_curve_area = green_curve_area(two_thetas, tan_outer_deg_ML)
    print "The green curve area is ", self.green_curve_area

    crystal._ML_half_mosaicity_deg = M.x[1]*180./(2.*math.pi)
    crystal._ML_domain_size_ang = 2./M.x[0]
    self._ML_full_mosaicity_rad = M.x[1]
    self._ML_domain_size_ang = 2./M.x[0]

    #params.refinement.mosaic.model_expansion_factor
    """The expansion factor should be initially set to 1, then expanded so that the # reflections matched becomes
    as close as possible to # of observed reflections input, in the last integration call.  Determine this by
    inspecting the output log file interactively.  Do not exceed the bare minimum threshold needed.
    The intention is to find an optimal value, global for a given dataset."""
    model_expansion_factor = 1.4
    crystal._ML_half_mosaicity_deg *= model_expansion_factor
    crystal._ML_domain_size_ang /= model_expansion_factor

    return crystal