Exemple #1
0
  def __call__(self, experiments, reflections, add_correction_column=False):
    result = flex.reflection_table()

    for expt_id, experiment in enumerate(experiments):
      refls = reflections.select(reflections['id'] == expt_id)
      beam = experiment.beam
      # Remove the need for pixel size within cxi.merge.  Allows multipanel detector with dissimilar panels.
      # Relies on new frame extractor code called by dials.stills_process that writes s0, s1 and polarization normal
      # vectors all to the integration pickle.  Future path (IE THIS CODE): use dials json and reflection file.
      s0_vec = matrix.col(beam.get_s0()).normalize()
      s0_polar_norm = beam.get_polarization_normal()
      s1_vec = refls['s1']
      Ns1 = len(s1_vec)
      # project the s1_vector onto the plane normal to s0.  Get result by subtracting the
      # projection of s1 onto s0, which is (s1.dot.s0_norm)s0_norm
      s0_norm = flex.vec3_double(Ns1,s0_vec)
      s1_proj = (s1_vec.dot(s0_norm))*s0_norm
      s1_in_normal_plane = s1_vec - s1_proj
      # Now want the polar angle between the projected s1 and the polarization normal
      s0_polar_norms = flex.vec3_double(Ns1,s0_polar_norm)
      dotprod = (s1_in_normal_plane.dot(s0_polar_norms))
      costheta = dotprod/(s1_in_normal_plane.norms())
      theta = flex.acos(costheta)
      cos_two_polar_angle = flex.cos(2.0*theta)
      # gives same as old answer to ~1% but not exact.  Not sure why, should not matter.

      tt_vec = experiment.crystal.get_unit_cell().two_theta(miller_indices = refls['miller_index'],
                                                            wavelength = beam.get_wavelength())
      cos_tt_vec = flex.cos(tt_vec)
      sin_tt_vec = flex.sin(tt_vec)
      cos_sq_tt_vec = cos_tt_vec * cos_tt_vec
      sin_sq_tt_vec = sin_tt_vec * sin_tt_vec
      P_nought_vec = 0.5 * (1. + cos_sq_tt_vec)

      F_prime = -1.0 # Hard-coded value defines the incident polarization axis
      P_prime = 0.5 * F_prime * cos_two_polar_angle * sin_sq_tt_vec

      # added as a diagnostic
      #prange=P_nought_vec - P_prime
      #other_F_prime = 1.0
      #otherP_prime = 0.5 * other_F_prime * cos_two_polar_angle * sin_sq_tt_vec
      #otherprange=P_nought_vec - otherP_prime
      #diff2 = flex.abs(prange - otherprange)
      #print >> out, "mean diff is",flex.mean(diff2), "range",flex.min(diff2), flex.max(diff2)
      # done

      correction = 1 / ( P_nought_vec - P_prime )
      refls['intensity.sum.value'] = refls['intensity.sum.value'] * correction
      refls['intensity.sum.variance'] = refls['intensity.sum.variance'] * correction**2 # propagated error
      # This corrects observations for polarization assuming 100% polarization on
      # one axis (thus the F_prime = -1.0 rather than the perpendicular axis, 1.0)
      # Polarization model as described by Kahn, Fourme, Gadet, Janin, Dumas & Andre
      # (1982) J. Appl. Cryst. 15, 330-337, equations 13 - 15.

      if add_correction_column:
        refls['polarization_correction'] = correction

      result.extend(refls)

    return result
def test2():
    """Test on simulated data"""

    # Get models for reflection prediction
    import dials.test.algorithms.refinement.setup_geometry as setup_geometry

    from libtbx.phil import parse

    overrides = """geometry.parameters.crystal.a.length.value = 77
  geometry.parameters.crystal.b.length.value = 77
  geometry.parameters.crystal.c.length.value = 37"""

    master_phil = parse(
        """
      include scope dials.test.algorithms.refinement.geometry_phil
      """,
        process_includes=True,
    )

    from dxtbx.model import Crystal

    models = setup_geometry.Extract(master_phil)
    crystal = Crystal(
        real_space_a=(2.62783398111729, -63.387215823567125,
                      -45.751375737456975),
        real_space_b=(15.246640559660356, -44.48254330406616,
                      62.50501032727026),
        real_space_c=(-76.67246874451074, -11.01804131886244,
                      10.861322446352226),
        space_group_symbol="I 2 3",
    )
    detector = models.detector
    goniometer = models.goniometer
    beam = models.beam

    # Build a mock scan for a 180 degree sweep
    from dxtbx.model import ScanFactory

    sf = ScanFactory()
    scan = sf.make_scan(
        image_range=(1, 1800),
        exposure_times=0.1,
        oscillation=(0, 0.1),
        epochs=range(1800),
        deg=True,
    )

    # Build an experiment list
    from dxtbx.model.experiment_list import ExperimentList, Experiment

    experiments = ExperimentList()
    experiments.append(
        Experiment(
            beam=beam,
            detector=detector,
            goniometer=goniometer,
            scan=scan,
            crystal=crystal,
            imageset=None,
        ))

    # Generate all indices in a 1.5 Angstrom sphere
    from dials.algorithms.spot_prediction import IndexGenerator
    from cctbx.sgtbx import space_group, space_group_symbols

    resolution = 1.5
    index_generator = IndexGenerator(
        crystal.get_unit_cell(),
        space_group(space_group_symbols(1).hall()).type(),
        resolution,
    )
    indices = index_generator.to_array()

    # Predict rays within the sweep range
    from dials.algorithms.refinement.prediction import ScansRayPredictor

    sweep_range = scan.get_oscillation_range(deg=False)
    ray_predictor = ScansRayPredictor(experiments, sweep_range)
    obs_refs = ray_predictor(indices)

    # Take only those rays that intersect the detector
    from dials.algorithms.spot_prediction import ray_intersection

    intersects = ray_intersection(detector, obs_refs)
    obs_refs = obs_refs.select(intersects)

    # Make a reflection predictor and re-predict for all these reflections. The
    # result is the same, but we gain also the flags and xyzcal.px columns
    from dials.algorithms.refinement.prediction import ExperimentsPredictor

    ref_predictor = ExperimentsPredictor(experiments)
    obs_refs["id"] = flex.int(len(obs_refs), 0)
    obs_refs = ref_predictor(obs_refs)

    # Copy 'observed' centroids from the predicted ones, applying sinusoidal
    # offsets
    obs_x, obs_y, obs_z = obs_refs["xyzcal.mm"].parts()

    # obs_z is in range (0, pi). Calculate offsets for phi at twice that
    # frequency
    im_width = scan.get_oscillation(deg=False)[1]
    z_off = flex.sin(2 * obs_z) * im_width
    obs_z += z_off

    # Calculate offsets for x
    pixel_size = detector[0].get_pixel_size()
    x_off = flex.sin(20 * obs_z) * pixel_size[0]

    # Calculate offsets for y with a phase-shifted sine wave
    from math import pi

    y_off = flex.sin(4 * obs_z + pi / 6) * pixel_size[1]

    # Incorporate the offsets into the 'observed' centroids
    obs_z += z_off
    obs_x += x_off
    obs_y += y_off
    obs_refs["xyzobs.mm.value"] = flex.vec3_double(obs_x, obs_y, obs_z)

    # Now do centroid analysis of the residuals
    results = CentroidAnalyser(obs_refs, debug=True)()

    # FIXME this test shows that the suggested interval width heuristic is not
    # yet robust. This simulation function seems a useful direction to proceed
    # in though
    raise RuntimeError("test2 failed")

    print("OK")
    return
Exemple #3
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")
Exemple #4
0
  def compute_intensity_parameters(self):
    """ Create a new reflection table with all the derived parameters needed
    to apply corrections from RS postrefinement """
    refls = self.scaler.ISIGI
    ct = self.scaler.crystal_table

    rx = flex.mat3_double() # crystal rotation around x
    ry = flex.mat3_double() # crystal rotation around y
    u = flex.mat3_double()  # U matrix (orientation)
    b = flex.mat3_double()  # B matrix (cell parameters)
    wavelength = flex.double()
    G = flex.double()       # scaling gfactor
    B = flex.double()       # wilson B factor
    s0 = flex.vec3_double() # beam vector
    deff = flex.double()    # effective domain size
    eta = flex.double()     # effective mosaic domain misorientation angle

    ex = col((1,0,0))       # crystal rotation x axis
    ey = col((0,1,0))       # crystal rotation y axis

    for i in xrange(len(ct)):
      # Need to copy crystal specific terms for each reflection. Equivalent to a JOIN in SQL.
      n_refl = ct['n_refl'][i]
      rx.extend(flex.mat3_double(n_refl, ex.axis_and_angle_as_r3_rotation_matrix(ct['thetax'][i])))
      ry.extend(flex.mat3_double(n_refl, ey.axis_and_angle_as_r3_rotation_matrix(ct['thetay'][i])))
      u.extend(flex.mat3_double(n_refl, ct['u_matrix'][i]))
      b.extend(flex.mat3_double(n_refl, ct['b_matrix'][i]))
      wavelength.extend(flex.double(n_refl, ct['wavelength'][i]))
      G.extend(flex.double(n_refl, ct['G'][i]))
      B.extend(flex.double(n_refl, ct['B'][i]))
      s0.extend(flex.vec3_double(n_refl, (0,0,-1)) * (1/ct['wavelength'][i]))
      deff.extend(flex.double(n_refl, ct['deff'][i]))
      eta.extend(flex.double(n_refl, ct['eta'][i]))

    iobs       = refls['iobs']
    h          = refls['miller_index_original'].as_vec3_double()
    q          = ry * rx * u * b * h                  # vector pointing from origin of reciprocal space to RLP
    qlen       = q.norms()                            # length of q
    d          = 1/q.norms()                          # resolution
    #rs         = (1/deff)+(eta/(2*d))                # proper formulation of RS
    rs         = 1/deff                               # assumes eta is zero
    rs_sq      = rs*rs                                # square of rs
    s          = (s0+q)                               # vector from center of Ewald sphere to RLP
    slen       = s.norms()                            # length of s
    rh         = slen-(1/wavelength)                  # distance from RLP to Ewald sphere
    p_n        = rs_sq                                # numerator of partiality lorenzian expression
    p_d        = (2. * (rh * rh)) + rs_sq             # denominator of partiality lorenzian expression
    partiality = p_n/p_d
    theta      = flex.asin(wavelength/(2*d))
    epsilon    = -8*B*(flex.sin(theta)/wavelength)**2 # exponential term in partiality
    eepsilon   = flex.exp(epsilon)                    # e^epsilon
    D          = partiality * G * eepsilon            # denominator of partiality lorenzian expression
    thetah     = flex.asin(wavelength/(2*d))          # reflecting angle
    sinthetah  = flex.sin(thetah)
    er         = sinthetah/wavelength                 # ratio term in epsilon

    # save all the columns
    r = flex.reflection_table()
    r['rx']         = rx
    r['ry']         = ry
    r['u']          = u
    r['b']          = b
    r['h']          = h
    r['q']          = q
    r['qlen']       = qlen
    r['D']          = D
    r['rs']         = rs
    r['eta']        = eta
    r['deff']       = deff
    r['d']          = d
    r['s']          = s
    r['slen']       = slen
    r['wavelength'] = wavelength
    r['p_n']        = p_n
    r['p_d']        = p_d
    r['partiality'] = partiality
    r['G']          = G
    r['B']          = B
    r['eepsilon']   = eepsilon
    r['thetah']     = thetah
    r['sinthetah']  = sinthetah
    r['er']         = er

    return r
  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")
    def run(self, experiments, reflections):

        self.logger.log_step_time("POLARIZATION_CORRECTION")

        result = flex.reflection_table()

        for experiment in experiments:
            refls = reflections.select(
                reflections['exp_id'] == experiment.identifier)
            if len(refls) == 0: continue
            beam = experiment.beam
            # Remove the need for pixel size within cxi.merge.  Allows multipanel detector with dissimilar panels.
            # Relies on new frame extractor code called by dials.stills_process that writes s0, s1 and polarization normal
            # vectors all to the integration pickle.  Future path (IE THIS CODE): use dials json and reflection file.
            s0_vec = matrix.col(beam.get_s0()).normalize()
            s0_polar_norm = beam.get_polarization_normal()
            s1_vec = refls['s1']
            Ns1 = len(s1_vec)
            # project the s1_vector onto the plane normal to s0.  Get result by subtracting the
            # projection of s1 onto s0, which is (s1.dot.s0_norm)s0_norm
            s0_norm = flex.vec3_double(Ns1, s0_vec)
            s1_proj = (s1_vec.dot(s0_norm)) * s0_norm
            s1_in_normal_plane = s1_vec - s1_proj
            # Now want the polar angle between the projected s1 and the polarization normal
            s0_polar_norms = flex.vec3_double(Ns1, s0_polar_norm)
            dotprod = (s1_in_normal_plane.dot(s0_polar_norms))
            costheta = dotprod / (s1_in_normal_plane.norms())
            theta = flex.acos(costheta)
            cos_two_polar_angle = flex.cos(2.0 * theta)
            # gives same as old answer to ~1% but not exact.  Not sure why, should not matter.

            tt_vec = experiment.crystal.get_unit_cell().two_theta(
                miller_indices=refls['miller_index'],
                wavelength=beam.get_wavelength())
            cos_tt_vec = flex.cos(tt_vec)
            sin_tt_vec = flex.sin(tt_vec)
            cos_sq_tt_vec = cos_tt_vec * cos_tt_vec
            sin_sq_tt_vec = sin_tt_vec * sin_tt_vec
            P_nought_vec = 0.5 * (1. + cos_sq_tt_vec)

            F_prime = -1.0  # Hard-coded value defines the incident polarization axis
            P_prime = 0.5 * F_prime * cos_two_polar_angle * sin_sq_tt_vec

            # added as a diagnostic
            #prange=P_nought_vec - P_prime
            #other_F_prime = 1.0
            #otherP_prime = 0.5 * other_F_prime * cos_two_polar_angle * sin_sq_tt_vec
            #otherprange=P_nought_vec - otherP_prime
            #diff2 = flex.abs(prange - otherprange)
            #print >> out, "mean diff is",flex.mean(diff2), "range",flex.min(diff2), flex.max(diff2)
            # done

            correction = 1 / (P_nought_vec - P_prime)
            refls['intensity.sum.value'] = refls[
                'intensity.sum.value'] * correction
            refls['intensity.sum.variance'] = refls[
                'intensity.sum.variance'] * correction**2  # propagated error
            # This corrects observations for polarization assuming 100% polarization on
            # one axis (thus the F_prime = -1.0 rather than the perpendicular axis, 1.0)
            # Polarization model as described by Kahn, Fourme, Gadet, Janin, Dumas & Andre
            # (1982) J. Appl. Cryst. 15, 330-337, equations 13 - 15.

            result.extend(refls)

        if len(reflections) > 0:
            self.logger.log(
                "Applied polarization correction. Mean intensity changed from %.2f to %.2f"
                % (flex.mean(reflections['intensity.sum.value']),
                   flex.mean(result['intensity.sum.value'])))

        self.logger.log_step_time("POLARIZATION_CORRECTION", True)
        self.logger.log("Memory usage: %d MB" % get_memory_usage())

        # Remove 's1' column from the reflection table
        from xfel.merging.application.reflection_table_utils import reflection_table_utils
        reflections = reflection_table_utils.prune_reflection_table_keys(
            reflections=result, keys_to_delete=['s1'])
        self.logger.log("Pruned reflection table")
        self.logger.log("Memory usage: %d MB" % get_memory_usage())

        return experiments, reflections
Exemple #7
0
def background(imageset, indx, n_bins, corrected=False, mask_params=None):
    if mask_params is None:
        # Default mask params for trusted range
        mask_params = phil_scope.fetch(parse("")).extract().masking

    detector = imageset.get_detector()
    beam = imageset.get_beam()

    # Only working with single panel detector for now
    assert len(detector) == 1
    panel = detector[0]
    imageset_mask = imageset.get_mask(indx)[0]
    mask = dials.util.masking.generate_mask(imageset, mask_params)[0]
    mask = imageset_mask & mask

    n = matrix.col(panel.get_normal()).normalize()
    b = matrix.col(beam.get_s0()).normalize()
    wavelength = beam.get_wavelength()

    if math.fabs(b.dot(n)) < 0.95:
        raise Sorry("Detector not perpendicular to beam")

    # Use corrected data to determine signal and background regions
    corrected_data = imageset.get_corrected_data(indx)
    assert len(corrected_data) == 1
    corrected_data = corrected_data[0].as_double()

    # Use choice of raw or corrected data to evaluate the background values
    if corrected:
        data = corrected_data
    else:
        data = imageset.get_raw_data(indx)[0].as_double()

    spot_params = spot_phil.fetch(source=parse("")).extract()
    threshold_function = SpotFinderFactory.configure_threshold(spot_params)
    peak_pixels = threshold_function.compute_threshold(corrected_data, mask)
    signal = data.select(peak_pixels.iselection())
    background_pixels = mask & ~peak_pixels
    background = data.select(background_pixels.iselection())

    # print some summary information
    print(f"Mean background: {flex.sum(background) / background.size():.3f}")
    if len(signal) > 0:
        print(
            f"Max/total signal pixels: {flex.max(signal):.0f} / {flex.sum(signal):.0f}"
        )
    else:
        print("No signal pixels on this image")
    print("Peak/background/masked pixels: %d / %d / %d" %
          (peak_pixels.count(True), background.size(), mask.count(False)))

    # compute histogram of two-theta values, then same weighted
    # by pixel values, finally divide latter by former to get
    # the radial profile out, need to set the number of bins
    # sensibly; inspired by method in PyFAI

    two_theta_array = panel.get_two_theta_array(beam.get_s0())
    two_theta_array = two_theta_array.as_1d().select(
        background_pixels.iselection())

    # Use flex.weighted_histogram
    h0 = flex.weighted_histogram(two_theta_array, n_slots=n_bins)
    h1 = flex.weighted_histogram(two_theta_array, background, n_slots=n_bins)
    h2 = flex.weighted_histogram(two_theta_array,
                                 background * background,
                                 n_slots=n_bins)

    d0 = h0.slots()
    d1 = h1.slots()
    d2 = h2.slots()

    I = d1 / d0
    I2 = d2 / d0
    sig = flex.sqrt(I2 - flex.pow2(I))

    tt = h0.slot_centers()
    d_spacings = wavelength / (2.0 * flex.sin(0.5 * tt))

    return d_spacings, I, sig
def run(args):
    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()  # each process in MPI has a unique id, 0-indexed
    size = comm.Get_size()  # size: number of processes running in this job

    if "-h" in args or "--help" in args:
        if rank == 0:
            print(help_str)
        return

    if rank == 0:
        from dxtbx.command_line.image_average import splitit
        filenames = []
        for arg in sys.argv[1:]:
            filenames.extend(glob.glob(arg))
        if not filenames:
            sys.exit("No data found")
        filenames = splitit(filenames, size)
    else:
        filenames = None

    filenames = comm.scatter(filenames, root=0)

    x, y = flex.double(), flex.double()
    det = None
    for fn in filenames:
        print(fn)
        try:
            refls = flex.reflection_table.from_file(
                fn.split('_strong.expt')[0] + "_strong.refl")
        except OSError:
            continue
        expts = ExperimentList.from_file(fn, check_format=False)
        for expt_id, expt in enumerate(expts):
            subset = refls.select(expt_id == refls['id'])
            if len(subset) > 200: continue
            det = expt.detector
            for panel_id, panel in enumerate(det):
                r = subset.select(subset['panel'] == panel_id)
                x_, y_, _ = r['xyzobs.px.value'].parts()
                pix = panel.pixel_to_millimeter(flex.vec2_double(x_, y_))
                c = panel.get_lab_coord(pix)
                x.extend(c.parts()[0])
                y.extend(c.parts()[1])

    if det:
        z = flex.double(len(x),
                        sum([p.get_origin()[2] for p in det]) / len(det))
        coords = flex.vec3_double(x, y, z)
        two_theta = coords.angle((0, 0, -1))
        d = expts[0].beam.get_wavelength() / 2 / flex.sin(two_theta / 2)
        azi = flex.vec3_double(x, y, flex.double(len(x), 0)).angle((0, 1, 0),
                                                                   deg=True)
        azi.set_selected(x < 0, 180 + (180 - azi.select(x < 0)))
    else:
        d = flex.double()
        azi = flex.double()

    if rank == 0:

        def saveit():
            np.save(f, x.as_numpy_array())
            np.save(f, y.as_numpy_array())
            np.save(f, d.as_numpy_array())
            np.save(f, azi.as_numpy_array())

        import numpy as np
        with open('cake.npy', 'wb') as f:
            saveit()
            for i in range(1, size):
                print('waiting for', i)
                x, y, d, azi = comm.recv(source=i)
                saveit()
    else:
        print('rank', rank, 'sending')
        comm.send((x, y, d, azi), dest=0)