Пример #1
0
def find_nearest_neighbour(image, mask, reflections):
    from annlib_ext import AnnAdaptor
    from scitbx.array_family import flex
    from math import sqrt
    import numpy

    # Get the predicted coords
    pred_xyz = []
    for r in reflections:
        x = r.image_coord_px[0]
        y = r.image_coord_px[1]
        z = r.frame_number
        pred_xyz.append((x, y, z))

    # Create the KD Tree
    ann = AnnAdaptor(flex.double(pred_xyz).as_1d(), 3)

    pixel_xyz = []
    ind = numpy.where(mask != 0)
    z = ind[0]
    y = ind[1]
    x = ind[2]

    ann.query(flex.double(zip(x, y, z)).as_1d())

    #    for i in xrange(len(ann.nn)):
    #        print "Neighbor of {0}, index {1} distance {2}".format(
    #        obs_xyz[i], ann.nn[i], sqrt(ann.distances[i]))

    owner = numpy.zeros(shape=mask.shape, dtype=numpy.int32)
    owner[ind] = ann.nn.as_numpy_array()

    return owner
Пример #2
0
def find_pixel_nearest_neighbour(image, mask, reflections):
  from annlib_ext import AnnAdaptor
  from scitbx.array_family import flex
  from math import sqrt
  import numpy

  # Get the predicted coords
  pred_xyz = []
  for r in reflections:
    x = r.image_coord_px[0] * 0.172
    y = r.image_coord_px[1] * 0.172
    z = r.frame_number * 0.2
    pred_xyz.append((x, y, z))

  # Create the KD Tree
  ann = AnnAdaptor(flex.double(pred_xyz).as_1d(), 3)

  pixel_xyz = []
  ind = numpy.where(mask != 0)
  z = ind[0] * 0.2
  y = ind[1] * 0.172
  x = ind[2] * 0.172

  ann.query(flex.double(zip(x, y, z)).as_1d())

#    for i in xrange(len(ann.nn)):
#        print "Neighbor of {0}, index {1} distance {2}".format(
#        obs_xyz[i], ann.nn[i], sqrt(ann.distances[i]))

  owner = numpy.zeros(shape=mask.shape, dtype=numpy.int32)
  owner[ind] = ann.nn.as_numpy_array()

  return owner
Пример #3
0
def find_nearest_neighbour(obs_xyz, reflections):
  from annlib_ext import AnnAdaptor
  from scitbx.array_family import flex
  from math import sqrt

  # Get the predicted coords
  pred_xyz = []
  for r in reflections:
    x = r.image_coord_px[0]# * 0.172
    y = r.image_coord_px[1]# * 0.172
    z = r.frame_number# * 0.2
    pred_xyz.append((x, y, z))

  # Create the KD Tree
  ann = AnnAdaptor(flex.double(pred_xyz).as_1d(), 3)

#    obs_xyz2 = []
#    for x, y, z in obs_xyz:
#        x = x * 0.172
#        y = y * 0.172
#        z = z * 0.2
#        obs_xyz2.append((x, y, z))

  ann.query(flex.double(obs_xyz).as_1d())

#    for i in xrange(len(ann.nn)):
#        print "Neighbor of {0}, index {1} distance {2}".format(
#        obs_xyz[i], ann.nn[i], sqrt(ann.distances[i]))

  return ann.nn, ann.distances
Пример #4
0
 def interpolate_x_value(self, y):
     #    return np.random.normal(1000., 10)
     #    if self.N < 20:
     lookup_table_cdf, lookup_table_x = self.create_exgauss_lookup_table()
     #    else:
     #lookup_table_cdf, lookup_table_x = self.create_smarter_lookup_table(y)
     lookup_table_cdf = flex.double(lookup_table_cdf)
     #    print 'Length of lookup table = ', len(lookup_table_cdf)
     #    del(lookup_table_cdf)
     #    del(lookup_table_x)
     #    return np.random.normal(1000., 10)
     from annlib_ext import AnnAdaptor
     A = AnnAdaptor(lookup_table_cdf, 1)
     A.query([y])
     idx = A.nn[0]
     try:
         y1 = lookup_table_cdf[idx]
         x1 = lookup_table_x[idx]
         if y > y1:
             y2 = lookup_table_cdf[idx + 1]
             x2 = lookup_table_x[idx + 1]
         else:
             y2 = lookup_table_cdf[idx - 1]
             x2 = lookup_table_x[idx - 1]
         x = ((x2 - x1) / (y2 - y1)) * (y - y1) + x1
         #      print 'true cdf value from interpol',self.exgauss_cdf(x)
         return x
     except:
         print 'in the except block', y
         #      print 'true cdf value from interpol',self.exgauss_cdf(x)
         return lookup_table_x[idx]
Пример #5
0
def find_nearest_neighbour(obs_xyz, reflections):
    from annlib_ext import AnnAdaptor
    from scitbx.array_family import flex
    from math import sqrt

    # Get the predicted coords
    pred_xyz = []
    for r in reflections:
        x = r.image_coord_px[0]  # * 0.172
        y = r.image_coord_px[1]  # * 0.172
        z = r.frame_number  # * 0.2
        pred_xyz.append((x, y, z))

    # Create the KD Tree
    ann = AnnAdaptor(flex.double(pred_xyz).as_1d(), 3)

    #    obs_xyz2 = []
    #    for x, y, z in obs_xyz:
    #        x = x * 0.172
    #        y = y * 0.172
    #        z = z * 0.2
    #        obs_xyz2.append((x, y, z))

    ann.query(flex.double(obs_xyz).as_1d())

    #    for i in xrange(len(ann.nn)):
    #        print "Neighbor of {0}, index {1} distance {2}".format(
    #        obs_xyz[i], ann.nn[i], sqrt(ann.distances[i]))

    return ann.nn, ann.distances
  def _find_nearest_neighbours(self, observed, predicted):
    '''Find the nearest predicted spot to the observed spot.

    Params:
        observed The observed reflections
        predicted The predicted reflections

    Returns:
        (nearest neighbours, distance)

    '''
    from annlib_ext import AnnAdaptor
    from scitbx.array_family import flex
    from math import sqrt

    # Get the predicted coordinates
    predicted_xyz = []
    for r in predicted:
      x, y = r.image_coord_px
      z = r.frame_number
      predicted_xyz.append((x, y, z))

    # Create the KD Tree
    ann = AnnAdaptor(flex.double(predicted_xyz).as_1d(), 3)

    # Get the observed coordinates
    observed_xyz = [r.centroid_position for r in observed]

    # Query to find all the nearest neighbours
    ann.query(flex.double(observed_xyz).as_1d())

    # Return the nearest neighbours and distances
    return ann.nn, flex.sqrt(ann.distances)
Пример #7
0
 def find_x_from_expdata_annlib(self, data, y):
     ''' find the corresponding x value of a desired y_cdf value, given exp data
 '''
     exgauss_rand = []
     lookup_table_x = np.sort(data)
     lookup_table_cdf = np.array(range(1,
                                       len(lookup_table_x) + 1)) / float(
                                           len(lookup_table_x))
     lookup_table_cdf[:] = [
         z - 0.5 / len(lookup_table_cdf) for z in lookup_table_cdf
     ]
     y_cdf = lookup_table_cdf
     lookup_table_cdf = flex.double(lookup_table_cdf)
     from annlib_ext import AnnAdaptor
     A = AnnAdaptor(lookup_table_cdf, 1)
     A.query([y])
     idx = A.nn[0]
     try:
         y1 = lookup_table_cdf[idx]
         x1 = lookup_table_x[idx]
         if y > y1:
             y2 = lookup_table_cdf[idx + 1]
             x2 = lookup_table_x[idx + 1]
         else:
             y2 = lookup_table_cdf[idx - 1]
             x2 = lookup_table_x[idx - 1]
         x = ((x2 - x1) / (y2 - y1)) * (y - y1) + x1
         #      print 'true cdf value from interpol',self.exgauss_cdf(x)
         return (x, y_cdf)
     except:
         print 'in the except block of find_x_from_expdata_annlib', y
         #      print 'true cdf value from interpol',self.exgauss_cdf(x)
         return (lookup_table_x[idx], y_cdf)
Пример #8
0
  def __init__(self, params, exlist, reference=None,
               predicted=None, shoeboxes=None):
    '''Initialise the script.'''

    assert reference is not None

    # Load the extractor based on the input
    if shoeboxes is not None:
      extractor = self._load_extractor(shoeboxes, params, exlist)
    else:
      if predicted is None:
        predicted = self._predict_reflections(params, exlist)
        #predicted = self._filter_reflections(params, exlist, predicted) # FIXME

      predicted = self._match_with_reference(predicted, reference)

      from annlib_ext import AnnAdaptor
      from dials.array_family import flex
      import math
      matcheddata = predicted.select(predicted.get_flags(predicted.flags.reference_spot))

      A = AnnAdaptor(matcheddata['xyzcal.mm'].as_double(), 3, 10)
      A.query(predicted['xyzcal.mm'].as_double())

      bboxes = flex.int6()
      for i, ref in enumerate(predicted):
        nn_pred = [matcheddata[A.nn[i*10+j]] for j in xrange(10)]
        nn_ref = [reference[reference['miller_index'].first_index(r['miller_index'])] for r in nn_pred]

        max_x = max([r['bbox'][1]-r['bbox'][0] for r in nn_ref])
        max_y = max([r['bbox'][3]-r['bbox'][2] for r in nn_ref])
        max_z = max([r['bbox'][5]-r['bbox'][4] for r in nn_ref])

        panel = exlist[ref['id']].detector[ref['panel']]
        imgsize_x, imgsize_y = panel.get_image_size()

        x1 = int(math.floor(ref['xyzcal.px'][0] - (max_x / 2)))
        x2 = int(math.ceil (ref['xyzcal.px'][0] + (max_x / 2)))
        y1 = int(math.floor(ref['xyzcal.px'][1] - (max_y / 2)))
        y2 = int(math.ceil (ref['xyzcal.px'][1] + (max_y / 2)))

        if x1 < 0: x1 = 0
        if y1 < 0: y1 = 0

        if x2 > imgsize_x: x2 = imgsize_x
        if y2 > imgsize_y: y2 = imgsize_y

        bboxes.append((x1,x2,y1,y2,0,1))

      predicted['bbox'] = bboxes

      extractor = self._create_extractor(params, exlist, predicted)

    # Initialise the integrator
    self._integrator = ReflectionBlockIntegratorStills(params, exlist, reference, extractor)
Пример #9
0
  def __init__(self, params, exlist, reference=None,
               predicted=None, shoeboxes=None):
    '''Initialise the script.'''

    assert reference is not None

    # Load the extractor based on the input
    if shoeboxes is not None:
      extractor = self._load_extractor(shoeboxes, params, exlist)
    else:
      if predicted is None:
        predicted = self._predict_reflections(params, exlist)
        #predicted = self._filter_reflections(params, exlist, predicted) # FIXME

      predicted = self._match_with_reference(predicted, reference)

      from annlib_ext import AnnAdaptor
      from dials.array_family import flex
      import math
      matcheddata = predicted.select(predicted.get_flags(predicted.flags.reference_spot))

      A = AnnAdaptor(matcheddata['xyzcal.mm'].as_double(), 3, 10)
      A.query(predicted['xyzcal.mm'].as_double())

      bboxes = flex.int6()
      for i, ref in enumerate(predicted):
        nn_pred = [matcheddata[A.nn[i*10+j]] for j in xrange(10)]
        nn_ref = [reference[reference['miller_index'].first_index(r['miller_index'])] for r in nn_pred]

        max_x = max([r['bbox'][1]-r['bbox'][0] for r in nn_ref])
        max_y = max([r['bbox'][3]-r['bbox'][2] for r in nn_ref])
        max_z = max([r['bbox'][5]-r['bbox'][4] for r in nn_ref])

        panel = exlist[ref['id']].detector[ref['panel']]
        imgsize_x, imgsize_y = panel.get_image_size()

        x1 = int(math.floor(ref['xyzcal.px'][0] - (max_x / 2)))
        x2 = int(math.ceil (ref['xyzcal.px'][0] + (max_x / 2)))
        y1 = int(math.floor(ref['xyzcal.px'][1] - (max_y / 2)))
        y2 = int(math.ceil (ref['xyzcal.px'][1] + (max_y / 2)))

        if x1 < 0: x1 = 0
        if y1 < 0: y1 = 0

        if x2 > imgsize_x: x2 = imgsize_x
        if y2 > imgsize_y: y2 = imgsize_y

        bboxes.append((x1,x2,y1,y2,0,1))

      predicted['bbox'] = bboxes

      extractor = self._create_extractor(params, exlist, predicted)

    # Initialise the integrator
    self._integrator = ReflectionBlockIntegratorStills(params, exlist, reference, extractor)
Пример #10
0
    def __init__(self, rs_vectors, percentile=0.05):
        from scitbx.array_family import flex
        NEAR = 10
        self.NNBIN = 5  # target number of neighbors per histogram bin

        # nearest neighbor analysis
        from annlib_ext import AnnAdaptor
        query = flex.double()
        for spot in rs_vectors:  # spots, in reciprocal space xyz
            query.append(spot[0])
            query.append(spot[1])
            query.append(spot[2])

        assert len(
            rs_vectors) > NEAR  # Can't do nearest neighbor with too few spots

        IS_adapt = AnnAdaptor(data=query, dim=3, k=1)
        IS_adapt.query(query)

        direct = flex.double()
        for i in range(len(rs_vectors)):
            direct.append(1.0 / math.sqrt(IS_adapt.distances[i]))

        # determine the most probable nearest neighbor distance (direct space)
        hst = flex.histogram(direct, n_slots=int(len(rs_vectors) / self.NNBIN))
        centers = hst.slot_centers()
        islot = hst.slots()
        highest_bin_height = flex.max(islot)
        most_probable_neighbor = centers[list(islot).index(highest_bin_height)]

        if False:  # to print out the histogramming analysis
            smin, smax = flex.min(direct), flex.max(direct)
            stats = flex.mean_and_variance(direct)
            import sys
            out = sys.stdout
            print("     range:     %6.2f - %.2f" % (smin, smax), file=out)
            print("     mean:      %6.2f +/- %6.2f on N = %d" %
                  (stats.mean(), stats.unweighted_sample_standard_deviation(),
                   direct.size()),
                  file=out)
            hst.show(f=out, prefix="    ", format_cutoffs="%6.2f")
            print("", file=out)

        # determine the 5th-percentile direct-space distance
        perm = flex.sort_permutation(direct, reverse=True)
        percentile = direct[perm[int(percentile * len(rs_vectors))]]

        MAXTOL = 1.5  # Margin of error for max unit cell estimate
        self.max_cell = max(MAXTOL * most_probable_neighbor,
                            MAXTOL * percentile)

        if False:
            self.plot(direct)
Пример #11
0
def excercise_nearest_neighbor():

  data,query = data_from_files()
  S = StringIO()

  A = AnnAdaptor(data,2)       # construct k-d tree for reference set
  A.query(query)               # find nearest neighbors of query points

  for i in range(len(A.nn)):
    print >>S,"Neighbor of (%7.1f,%7.1f), index %6d distance %4.1f"%(
    query[2*i],query[2*i+1],A.nn[i],math.sqrt(A.distances[i]))

  return S.getvalue()
Пример #12
0
def excercise_nearest_neighbor():

  data,query = data_from_files()
  S = StringIO.StringIO()

  A = AnnAdaptor(data,2)       # construct k-d tree for reference set
  A.query(query)               # find nearest neighbors of query points

  for i in xrange(len(A.nn)):
    print >>S,"Neighbor of (%7.1f,%7.1f), index %6d distance %4.1f"%(
    query[2*i],query[2*i+1],A.nn[i],math.sqrt(A.distances[i]))

  return S.getvalue()
Пример #13
0
  def __init__(self, rs_vectors, percentile=0.05):
    from scitbx.array_family import flex
    NEAR = 10
    self.NNBIN = 5 # target number of neighbors per histogram bin

    # nearest neighbor analysis
    from annlib_ext import AnnAdaptor
    query = flex.double()
    for spot in rs_vectors: # spots, in reciprocal space xyz
      query.append(spot[0])
      query.append(spot[1])
      query.append(spot[2])

    assert len(rs_vectors)>NEAR # Can't do nearest neighbor with too few spots

    IS_adapt = AnnAdaptor(data=query,dim=3,k=1)
    IS_adapt.query(query)

    direct = flex.double()
    for i in xrange(len(rs_vectors)):
       direct.append(1.0/math.sqrt(IS_adapt.distances[i]))

    # determine the most probable nearest neighbor distance (direct space)
    hst = flex.histogram(direct, n_slots=int(len(rs_vectors)/self.NNBIN))
    centers = hst.slot_centers()
    islot = hst.slots()
    highest_bin_height = flex.max(islot)
    most_probable_neighbor = centers[list(islot).index(highest_bin_height)]

    if False:  # to print out the histogramming analysis
      smin, smax = flex.min(direct), flex.max(direct)
      stats = flex.mean_and_variance(direct)
      import sys
      out = sys.stdout
      print >> out, "     range:     %6.2f - %.2f" % (smin, smax)
      print >> out, "     mean:      %6.2f +/- %6.2f on N = %d" % (
        stats.mean(), stats.unweighted_sample_standard_deviation(), direct.size())
      hst.show(f=out, prefix="    ", format_cutoffs="%6.2f")
      print >> out, ""

    # determine the 5th-percentile direct-space distance
    perm = flex.sort_permutation(direct, reverse=True)
    percentile = direct[perm[int(percentile * len(rs_vectors))]]

    MAXTOL = 1.5 # Margin of error for max unit cell estimate
    self.max_cell = max( MAXTOL * most_probable_neighbor,
                         MAXTOL * percentile)

    if False:
      self.plot(direct)
Пример #14
0
  def __init__(self,IT):
    from scitbx import matrix
    self.IT = IT
    from annlib_ext import AnnAdaptor

    reference = flex.double()

    for i in range(len(IT)//4):
      UL = matrix.col((float(IT[4*i]),float(IT[4*i+1])))
      LR = matrix.col((float(IT[4*i+2]),float(IT[4*i+3])))
      center = (UL+LR)/2.
      reference.append(center[0])
      reference.append(center[1])
    self.adapt = AnnAdaptor(data=reference,dim=2,k=self.NEAR)
Пример #15
0
class active_area_filter:
    NEAR = 2

    def __init__(self, IT):
        from scitbx import matrix

        self.IT = IT
        from annlib_ext import AnnAdaptor

        reference = flex.double()

        for i in xrange(len(IT) // 4):
            UL = matrix.col((float(IT[4 * i]), float(IT[4 * i + 1])))
            LR = matrix.col((float(IT[4 * i + 2]), float(IT[4 * i + 3])))
            center = (UL + LR) / 2.0
            reference.append(center[0])
            reference.append(center[1])
        self.adapt = AnnAdaptor(data=reference, dim=2, k=self.NEAR)

    def __call__(self, predictions, hkllist, pxlsz):
        if len(self.IT) == 4:
            # We have only one tile, AnnAdaptor chokes in this case but then there is
            # only one choice of nearest neighbour anyway!
            nearest_neighbours = flex.int(len(predictions) * self.NEAR, 0)
        else:
            query = flex.double()
            for pred in predictions:
                query.append(pred[0] / pxlsz)
                query.append(pred[1] / pxlsz)
            self.adapt.query(query)
            assert len(self.adapt.nn) == len(predictions) * self.NEAR
            nearest_neighbours = self.adapt.nn
        selection = flex.bool()
        self.tile_id = flex.int()
        for p in xrange(len(predictions)):
            is_in_active_area = False
            for n in xrange(self.NEAR):
                itile = nearest_neighbours[p * self.NEAR + n]
                if (
                    self.IT[4 * itile] < predictions[p][0] / pxlsz < self.IT[4 * itile + 2]
                    and self.IT[4 * itile + 1] < predictions[p][1] / pxlsz < self.IT[4 * itile + 3]
                ):
                    is_in_active_area = True
                    break
            if is_in_active_area:
                self.tile_id.append(itile)
            selection.append(is_in_active_area)
        assert selection.count(True) == len(self.tile_id)
        return predictions.select(selection), hkllist.select(selection)
Пример #16
0
    def restrict_target_angles_to_quick_winners(self, quick_sampling):

        # find which target_grid directions are near neighbors to
        # the quick_sampling winners from the first round of testing.
        # in the second round, restrict the calculation of FFTs to those directions

        self.restricted = flex.Direction()
        target = flex.double()
        for iz in self.angles:
            # fairly inefficient in Python; expect big improvement in C++
            v = iz.dvec
            target.append(v[0])
            target.append(v[1])
            target.append(v[2])
        kn = int(2 * self.second_round_sampling)

        #construct k-d tree for the reference set
        A = AnnAdaptor(data=target, dim=3, k=kn)

        query = flex.double()
        for j in quick_sampling:
            v = j.dvec
            query.append(v[0])
            query.append(v[1])
            query.append(v[2])
            if abs((math.pi / 2.) -
                   j.psi) < 0.0001:  #take care of equatorial boundary
                query.append(-v[0])
                query.append(-v[1])
                query.append(-v[2])

        A.query(query)  #find nearest neighbors of query points
        neighbors = flex.sqrt(A.distances)
        neighborid = A.nn

        accept_flag = flex.bool(len(self.angles))
        for idx in range(len(neighbors)):
            # use small angle approximation to test if target is within desired radius
            if neighbors[idx] < self.quick_grid:
                accept_flag[neighborid[idx]] = True

        #go through all of the original target angles
        for iz in range(len(self.angles)):
            if accept_flag[iz]:
                self.restricted.append(self.angles[iz])

        self.angles = self.restricted
Пример #17
0
class active_area_filter:
    NEAR = 2

    def __init__(self, IT):
        from scitbx import matrix
        self.IT = IT
        from annlib_ext import AnnAdaptor

        reference = flex.double()

        for i in range(len(IT) // 4):
            UL = matrix.col((float(IT[4 * i]), float(IT[4 * i + 1])))
            LR = matrix.col((float(IT[4 * i + 2]), float(IT[4 * i + 3])))
            center = (UL + LR) / 2.
            reference.append(center[0])
            reference.append(center[1])
        self.adapt = AnnAdaptor(data=reference, dim=2, k=self.NEAR)

    def __call__(self, predictions, hkllist, pxlsz):
        if len(self.IT) == 4:
            # We have only one tile, AnnAdaptor chokes in this case but then there is
            # only one choice of nearest neighbour anyway!
            nearest_neighbours = flex.int(len(predictions) * self.NEAR, 0)
        else:
            query = flex.double()
            for pred in predictions:
                query.append(pred[0] / pxlsz)
                query.append(pred[1] / pxlsz)
            self.adapt.query(query)
            assert len(self.adapt.nn) == len(predictions) * self.NEAR
            nearest_neighbours = self.adapt.nn
        selection = flex.bool()
        self.tile_id = flex.int()
        for p in range(len(predictions)):
            is_in_active_area = False
            for n in range(self.NEAR):
                itile = nearest_neighbours[p * self.NEAR + n]
                if self.IT[4*itile]<predictions[p][0]/pxlsz<self.IT[4*itile+2] and\
                   self.IT[4*itile+1]<predictions[p][1]/pxlsz<self.IT[4*itile+3]:
                    is_in_active_area = True
                    break
            if is_in_active_area:
                self.tile_id.append(itile)
            selection.append(is_in_active_area)
        assert selection.count(True) == len(self.tile_id)
        return predictions.select(selection), hkllist.select(selection)
Пример #18
0
    def _find_nearest_neighbours_single(self, oxyz, pxyz):
        """
        Find the nearest predicted spot to the observed spot.

        :param observed: The observed reflections
        :param predicted: The predicted reflections

        :returns: (nearest neighbours, distance)
        """
        from annlib_ext import AnnAdaptor

        # Create the KD Tree
        ann = AnnAdaptor(pxyz.as_double().as_1d(), 3)

        # Query to find all the nearest neighbours
        ann.query(oxyz.as_double().as_1d())

        # Return the nearest neighbours and distances
        return ann.nn, flex.sqrt(ann.distances)
Пример #19
0
 def rand_annlib(self, seed):
     exgauss_rand = []
     np.random.seed(seed)
     query = np.random.rand(self.N)
     lookup_table_cdf, lookup_table_x = self.create_exgauss_lookup_table()
     lookup_table_cdf = flex.double(lookup_table_cdf)
     #    t1 = time.time()
     from annlib_ext import AnnAdaptor
     A = AnnAdaptor(lookup_table_cdf, 1)
     A.query(query)
     # ================== If you want to test timing comment out below ================
     #    for i in xrange(len(A.nn)):
     #      print "Neighbor of (%12.7f), index %6d distance %12.5f"%(
     #      query[i],A.nn[i],math.sqrt(A.distances[i]))
     #    t2 = time.time()
     #    print 'Time Taken by Annlib = %12.7f'%(t2-t1)
     #    lookup_table_cdf = lookup_table_cdf.as_numpy_array().tolist()
     #    t1 = time.time()
     #    for y in query:
     #      idx = lookup_table_cdf.index(min(lookup_table_cdf, key=lambda y0:abs(y0-y)))
     #      print 'From Naive Search (%12.7f), index %6d'%(y, idx)
     #    t2 = time.time()
     #    print 'Time taken by Naive = %12.7f'%(t2-t1)
     ## ====================== Test Over ================================================
     for i in xrange(len(A.nn)):
         idx = A.nn[i]
         y = query[i]
         try:
             y1 = lookup_table_cdf[idx]
             x1 = lookup_table_x[idx]
             if y > y1:
                 y2 = lookup_table_cdf[idx + 1]
                 x2 = lookup_table_x[idx + 1]
             else:
                 y2 = lookup_table_cdf[idx - 1]
                 x2 = lookup_table_x[idx - 1]
             x = ((x2 - x1) / (y2 - y1)) * (y - y1) + x1
             exgauss_rand.append(x)
         except:
             print 'in the except block'
             exgauss_rand.append(lookup_table_x[idx])
     return exgauss_rand
 def interpolate_x_value(self, y):
     lookup_table_cdf, lookup_table_x = self.create_exgauss_lookup_table()
     lookup_table_cdf = flex.double(lookup_table_cdf)
     A = AnnAdaptor(lookup_table_cdf, 1)
     A.query([y])
     idx = A.nn[0]
     try:
         y1 = lookup_table_cdf[idx]
         x1 = lookup_table_x[idx]
         if y > y1:
             y2 = lookup_table_cdf[idx + 1]
             x2 = lookup_table_x[idx + 1]
         else:
             y2 = lookup_table_cdf[idx - 1]
             x2 = lookup_table_x[idx - 1]
         x = ((x2 - x1) / (y2 - y1)) * (y - y1) + x1
         return x
     except:
         print 'in the except block', y
         return lookup_table_x[idx]
Пример #21
0
  def _find_nearest_neighbours_single(self, oxyz, pxyz):
    '''
    Find the nearest predicted spot to the observed spot.

    :param observed: The observed reflections
    :param predicted: The predicted reflections

    :returns: (nearest neighbours, distance)

    '''
    from annlib_ext import AnnAdaptor
    from scitbx.array_family import flex

    # Create the KD Tree
    ann = AnnAdaptor(pxyz.as_double().as_1d(), 3)

    # Query to find all the nearest neighbours
    ann.query(oxyz.as_double().as_1d())

    # Return the nearest neighbours and distances
    return ann.nn, flex.sqrt(ann.distances)
Пример #22
0
  def restrict_target_angles_to_quick_winners(self,quick_sampling):

    # find which target_grid directions are near neighbors to
    # the quick_sampling winners from the first round of testing.
    # in the second round, restrict the calculation of FFTs to those directions

    self.restricted = flex.Direction()
    target = flex.double()
    for iz in self.angles:
      # fairly inefficient in Python; expect big improvement in C++
      v = iz.dvec
      target.append(v[0]);target.append(v[1]);target.append(v[2]);
    kn = int(2 *self.second_round_sampling)

    #construct k-d tree for the reference set
    A = AnnAdaptor(data = target, dim = 3, k = kn)

    query = flex.double()
    for j in quick_sampling:
      v = j.dvec
      query.append(v[0]);query.append(v[1]); query.append(v[2]);
      if abs((math.pi/2.) - j.psi) < 0.0001: #take care of equatorial boundary
        query.append(-v[0]);query.append(-v[1]); query.append(-v[2]);

    A.query(query) #find nearest neighbors of query points
    neighbors = flex.sqrt(A.distances)
    neighborid = A.nn

    accept_flag = flex.bool(len(self.angles))
    for idx in xrange(len(neighbors)):
      # use small angle approximation to test if target is within desired radius
      if neighbors[idx] < self.quick_grid:
        accept_flag[neighborid[idx]] = True

    #go through all of the original target angles
    for iz in xrange(len(self.angles)):
      if accept_flag[iz]:
        self.restricted.append(self.angles[iz])

    self.angles = self.restricted
Пример #23
0
def specific_libann_cluster(data, intensity_cutoff=25, distance_cutoff=17):
    from annlib_ext import AnnAdaptor
    #construct a new data structure containing only pixels > intensity_cutoff
    #input data structure is a flex array
    info = {}
    shape = data.accessor().focus()
    for slow in range(shape[0]):
        for fast in range(shape[1]):
            if data[(slow, fast)] > intensity_cutoff:
                info[(slow, fast)] = data[(slow, fast)]

    Ktree = int(distance_cutoff * distance_cutoff * pi)
    Sq_cut = distance_cutoff * distance_cutoff  # distance < distance_cutoff => the two points are clustered

    all_pixels = flex.double()
    all_keys = info.keys()
    for key in info.keys():
        all_pixels.append(key[0])
        all_pixels.append(key[1])

    distance_tree = AnnAdaptor(data=all_pixels, dim=2, k=Ktree)
    distance_tree.query(all_pixels)
    clusters = []
    membership_lookup = {}

    for i_query_pt in range(len(all_keys)):
        query_coords = all_keys[i_query_pt]
        query_ok = True
        for i_target_pt in range(Ktree):
            target_coords = all_keys[distance_tree.nn[Ktree * i_query_pt +
                                                      i_target_pt]]
            if distance_tree.distances[Ktree * i_query_pt +
                                       i_target_pt] < Sq_cut:
                if info[query_coords] < info[target_coords]:
                    query_ok = False
                    break
        if query_ok:
            membership_lookup[query_coords] = info[query_coords]

    return membership_lookup
Пример #24
0
def specific_libann_cluster(data,intensity_cutoff = 25,distance_cutoff=17):
  from annlib_ext import AnnAdaptor
  #construct a new data structure containing only pixels > intensity_cutoff
  #input data structure is a flex array
  info = {}
  shape = data.accessor().focus()
  for slow in xrange(shape[0]):
    for fast in xrange(shape[1]):
      if data[(slow,fast)] > intensity_cutoff:
        info[(slow,fast)] = data[(slow,fast)]

  Ktree = int(distance_cutoff*distance_cutoff*pi)
  Sq_cut = distance_cutoff*distance_cutoff # distance < distance_cutoff => the two points are clustered

  all_pixels = flex.double()
  all_keys = info.keys()
  for key in info.keys():
    all_pixels.append(key[0]); all_pixels.append(key[1])

  distance_tree = AnnAdaptor(data=all_pixels,dim=2,k=Ktree)
  distance_tree.query(all_pixels)
  clusters = []
  membership_lookup = {}

  for i_query_pt in xrange(len(all_keys)):
      query_coords = all_keys[i_query_pt]
      query_ok = True
      for i_target_pt in xrange(Ktree):
        target_coords = all_keys[distance_tree.nn[Ktree*i_query_pt+i_target_pt]]
        if distance_tree.distances[Ktree*i_query_pt+i_target_pt] < Sq_cut:
          if info[query_coords] < info[target_coords]:
            query_ok = False
            break
      if query_ok:
        membership_lookup[query_coords]=info[query_coords]

  return membership_lookup
Пример #25
0
    def __init__(self, IT):
        from scitbx import matrix

        self.IT = IT
        from annlib_ext import AnnAdaptor

        reference = flex.double()

        for i in xrange(len(IT) // 4):
            UL = matrix.col((float(IT[4 * i]), float(IT[4 * i + 1])))
            LR = matrix.col((float(IT[4 * i + 2]), float(IT[4 * i + 3])))
            center = (UL + LR) / 2.0
            reference.append(center[0])
            reference.append(center[1])
        self.adapt = AnnAdaptor(data=reference, dim=2, k=self.NEAR)
Пример #26
0
def excercise_nearest_neighbor():

    data = data_from_files()

    A = AnnAdaptor(data, 2)  # construct k-d tree for reference set
    A.query(data)  # find nearest neighbors of query points

    for i in range(len(A.nn)):
        #print "Neighbor of (%7.1f,%7.1f), index %6d distance %4.1f"%(
        #data[2*i],data[2*i+1],A.nn[i],math.sqrt(A.distances[i]))
        assert A.nn[i] != i

    A = AnnAdaptorSelfInclude(data, 2)  # construct k-d tree for reference set
    A.query(data)  # find nearest neighbors of query points

    for i in range(len(A.nn)):
        #print "Neighbor of (%7.1f,%7.1f), index %6d distance %4.1f"%(
        #data[2*i],data[2*i+1],A.nn[i],math.sqrt(A.distances[i]))
        assert A.nn[i] == i
Пример #27
0
def excercise_nearest_neighbor():

  data = data_from_files()

  A = AnnAdaptor(data,2)# construct k-d tree for reference set
  A.query(data)               # find nearest neighbors of query points

  for i in range(len(A.nn)):
    #print "Neighbor of (%7.1f,%7.1f), index %6d distance %4.1f"%(
    #data[2*i],data[2*i+1],A.nn[i],math.sqrt(A.distances[i]))
    assert A.nn[i]!=i

  A = AnnAdaptorSelfInclude(data,2)# construct k-d tree for reference set
  A.query(data)               # find nearest neighbors of query points

  for i in range(len(A.nn)):
    #print "Neighbor of (%7.1f,%7.1f), index %6d distance %4.1f"%(
    #data[2*i],data[2*i+1],A.nn[i],math.sqrt(A.distances[i]))
    assert A.nn[i]==i
Пример #28
0
def test3(dials_regression, tmpdir):
    """Strict check for scan-varying refinement using automated outlier rejection
    block width and interval width setting"""

    # use the i04_weak_data for this test
    data_dir = os.path.join(dials_regression, "refinement_test_data",
                            "centroid")
    experiments_path = os.path.join(data_dir,
                                    "experiments_XPARM_REGULARIZED.json")
    pickle_path = os.path.join(data_dir, "spot_all_xds.pickle")

    for pth in (experiments_path, pickle_path):
        assert os.path.exists(pth)

    result = procrunner.run(
        (
            "dials.refine",
            experiments_path,
            pickle_path,
            "scan_varying=true",
            "max_iterations=5",
            "output.history=history.json",
            "crystal.orientation.smoother.interval_width_degrees=auto",
            "crystal.unit_cell.smoother.interval_width_degrees=auto",
        ),
        working_directory=tmpdir,
    )
    assert not result.returncode and not result.stderr

    # load and check results
    history = Journal.from_json_file(tmpdir.join("history.json").strpath)

    expected_rmsds = [
        [0.619507829, 0.351326044, 0.006955399],
        [0.174024575, 0.113486044, 0.004704006],
        [0.098351363, 0.084052519, 0.002660408],
        [0.069202909, 0.072796782, 0.001451734],
        [0.064305277, 0.071560831, 0.001165639],
        [0.062955462, 0.071315612, 0.001074453],
    ]
    for a, b in zip(history["rmsd"], expected_rmsds):
        assert a == pytest.approx(b, abs=1e-6)

    # check the refined unit cell
    ref_exp = ExperimentListFactory.from_json_file(
        tmpdir.join("refined.expt").strpath, check_format=False)[0]
    unit_cell = ref_exp.crystal.get_unit_cell().parameters()
    assert unit_cell == pytest.approx(
        [42.27482, 42.27482, 39.66893, 90.00000, 90.00000, 90.00000], abs=1e-3)

    refined_refl = flex.reflection_table.from_file(
        tmpdir.join("refined.refl").strpath)
    # re-predict reflections using the refined experiments
    predicted = flex.reflection_table.from_predictions_multi([ref_exp])

    matched, reference, unmatched = predicted.match_with_reference(
        refined_refl)
    # assert most refined reflections are matched with predictions
    assert reference.size() > (0.997 * refined_refl.size())

    # second check with nearest neighbour matching that the predictions match up
    ann = AnnAdaptor(data=predicted["xyzcal.px"].as_double(), dim=3, k=1)
    ann.query(refined_refl["xyzcal.px"].as_double())
    assert (ann.distances < 0.5).count(True) > (0.998 * refined_refl.size())
Пример #29
0
    def __init__(self,
                 reflections,
                 step_size=45,
                 tolerance=1.5,
                 max_height_fraction=0.25,
                 percentile=None,
                 histogram_binning='linear',
                 nn_per_bin=5):
        self.tolerance = tolerance  # Margin of error for max unit cell estimate
        from scitbx.array_family import flex
        NEAR = 10
        self.NNBIN = nn_per_bin  # target number of neighbors per histogram bin
        self.histogram_binning = histogram_binning

        direct = flex.double()

        if 'entering' in reflections:
            entering_flags = reflections['entering']
        else:
            entering_flags = flex.bool(reflections.size(), True)
        rs_vectors = reflections['rlp']
        phi_deg = reflections['xyzobs.mm.value'].parts()[2] * (180 / math.pi)

        d_spacings = flex.double()
        # nearest neighbor analysis
        from annlib_ext import AnnAdaptor
        for imageset_id in range(flex.max(reflections['imageset_id']) + 1):
            sel_imageset = reflections['imageset_id'] == imageset_id
            if sel_imageset.count(True) == 0:
                continue
            phi_min = flex.min(phi_deg.select(sel_imageset))
            phi_max = flex.max(phi_deg.select(sel_imageset))
            d_phi = phi_max - phi_min
            n_steps = max(int(math.ceil(d_phi / step_size)), 1)

            for n in range(n_steps):
                sel_step = sel_imageset & (phi_deg >=
                                           (phi_min + n * step_size)) & (
                                               phi_deg <
                                               (phi_min + (n + 1) * step_size))

                for entering in (True, False):
                    sel_entering = sel_step & (entering_flags == entering)
                    if sel_entering.count(True) == 0:
                        continue

                    query = flex.double()
                    query.extend(rs_vectors.select(sel_entering).as_double())

                    if query.size() == 0:
                        continue

                    IS_adapt = AnnAdaptor(data=query, dim=3, k=1)
                    IS_adapt.query(query)

                    direct.extend(1 / flex.sqrt(IS_adapt.distances))
                    d_spacings.extend(1 / rs_vectors.norms())

        assert len(direct) > NEAR, (
            "Too few spots (%d) for nearest neighbour analysis." % len(direct))

        perm = flex.sort_permutation(direct)
        direct = direct.select(perm)
        d_spacings = d_spacings.select(perm)

        # eliminate nonsensical direct space distances
        sel = direct > 1
        direct = direct.select(sel)
        d_spacings = d_spacings.select(sel)

        if percentile is None:
            # reject top 1% of longest distances to hopefully get rid of any outliers
            n = int(math.floor(0.99 * len(direct)))
            direct = direct[:n]
            d_spacings = d_spacings[:n]

        # determine the most probable nearest neighbor distance (direct space)
        if self.histogram_binning == 'log':
            hst = flex.histogram(flex.log10(direct),
                                 n_slots=int(len(direct) / self.NNBIN))
        else:
            hst = flex.histogram(direct, n_slots=int(len(direct) / self.NNBIN))
        centers = hst.slot_centers()
        if self.histogram_binning == 'log':
            self.slot_start = flex.double(
                [10**(s - 0.5 * hst.slot_width()) for s in hst.slot_centers()])
            self.slot_end = flex.double(
                [10**(s + 0.5 * hst.slot_width()) for s in hst.slot_centers()])
            self.slot_width = self.slot_end - self.slot_start
        else:
            self.slot_start = hst.slot_centers() - 0.5 * hst.slot_width()
            self.slot_end = hst.slot_centers() + 0.5 * hst.slot_width()
            self.slot_width = hst.slot_width()
        self.relative_frequency = hst.slots().as_double() / self.slot_width
        highest_bin_height = flex.max(self.relative_frequency)

        if False:  # to print out the histogramming analysis
            smin, smax = flex.min(direct), flex.max(direct)
            stats = flex.mean_and_variance(direct)
            import sys
            out = sys.stdout
            print >> out, "     range:     %6.2f - %.2f" % (smin, smax)
            print >> out, "     mean:      %6.2f +/- %6.2f on N = %d" % (
                stats.mean(), stats.unweighted_sample_standard_deviation(),
                direct.size())
            hst.show(f=out, prefix="    ", format_cutoffs="%6.2f")
            print >> out, ""

        if percentile is not None:
            # determine the nth-percentile direct-space distance
            perm = flex.sort_permutation(direct, reverse=True)
            self.max_cell = self.tolerance * direct[perm[int(
                (1 - percentile) * len(direct))]]

        else:
            # choose a max cell based on bins above a given fraction of the highest bin height
            # given multiple
            isel = (self.relative_frequency.as_double() >
                    (max_height_fraction * highest_bin_height)).iselection()
            self.max_cell = (self.tolerance *
                             self.slot_end[int(flex.max(isel.as_double()))])

        self.reciprocal_lattice_vectors = rs_vectors
        self.d_spacings = d_spacings
        self.direct = direct
        self.histogram = hst
Пример #30
0
    def integration_concept(self,
                            image_number=0,
                            cb_op_to_primitive=None,
                            verbose=False,
                            **kwargs):
        self.image_number = image_number
        NEAR = 10
        pxlsz = self.pixel_size
        self.get_predictions_accounting_for_centering(cb_op_to_primitive,
                                                      **kwargs)
        FWMOSAICITY = self.inputai.getMosaicity()
        DOMAIN_SZ_ANG = kwargs.get("domain_size_ang",
                                   self.__dict__.get("actual", 0))
        refineflag = {True: 0, False: 1}[kwargs.get("domain_size_ang", 0) == 0]
        self.inputpd["symmetry"].show_summary(
            prefix="EXCURSION%1d REPORT FWMOS= %6.4f DOMAIN= %6.1f " %
            (refineflag, FWMOSAICITY, DOMAIN_SZ_ANG))
        from annlib_ext import AnnAdaptor
        self.cell = self.inputai.getOrientation().unit_cell()
        query = flex.double()
        for pred in self.predicted:  # predicted spot coord in pixels
            query.append(pred[0] / pxlsz)
            query.append(pred[1] / pxlsz)
        self.reserve_hkllist_for_signal_search = self.hkllist

        reference = flex.double()
        spots = self.get_observations_with_outlier_removal()

        assert len(
            spots) > NEAR  # Can't do spot/pred matching with too few spots
        for spot in spots:
            reference.append(spot.ctr_mass_x())
            reference.append(spot.ctr_mass_y())

        IS_adapt = AnnAdaptor(data=reference, dim=2, k=NEAR)
        IS_adapt.query(query)
        print "Calculate correction vectors for %d observations & %d predictions" % (
            len(spots), len(self.predicted))
        indexed_pairs_provisional = []
        correction_vectors_provisional = []
        c_v_p_flex = flex.vec3_double()
        idx_cutoff = float(min(self.mask_focus[image_number]))
        if verbose:
            print "idx_cutoff distance in pixels", idx_cutoff
        if not self.horizons_phil.integration.enable_one_to_one_safeguard:
            # legacy code, no safeguard against many-to-one predicted-to-observation mapping
            for i in range(len(self.predicted)):  # loop over predicteds
                #for n in range(NEAR): # loop over near spotfinder spots
                for n in range(1):  # only consider the nearest spotfinder spot
                    Match = dict(spot=IS_adapt.nn[i * NEAR + n], pred=i)
                    if n == 0 and math.sqrt(
                            IS_adapt.distances[i * NEAR + n]) < idx_cutoff:
                        indexed_pairs_provisional.append(Match)

                        vector = matrix.col([
                            spots[Match["spot"]].ctr_mass_x() -
                            self.predicted[Match["pred"]][0] / pxlsz,
                            spots[Match["spot"]].ctr_mass_y() -
                            self.predicted[Match["pred"]][1] / pxlsz
                        ])
                        correction_vectors_provisional.append(vector)
                        c_v_p_flex.append((vector[0], vector[1], 0.))
        else:
            one_to_one = {}
            for i in range(len(self.predicted)):  # loop over predicteds
                annresultidx = i * NEAR
                obsidx = IS_adapt.nn[annresultidx]
                this_distancesq = IS_adapt.distances[annresultidx]
                if obsidx not in one_to_one or \
                   this_distancesq < one_to_one[obsidx]["distancesq"]:
                    if math.sqrt(this_distancesq) < idx_cutoff:
                        one_to_one[obsidx] = dict(spot=obsidx,
                                                  pred=i,
                                                  distancesq=this_distancesq)
            for key, value in one_to_one.items():
                indexed_pairs_provisional.append(value)
                vector = matrix.col([
                    spots[value["spot"]].ctr_mass_x() -
                    self.predicted[value["pred"]][0] / pxlsz,
                    spots[value["spot"]].ctr_mass_y() -
                    self.predicted[value["pred"]][1] / pxlsz
                ])
                correction_vectors_provisional.append(vector)
                c_v_p_flex.append((vector[0], vector[1], 0.))

        print "... %d provisional matches" % len(
            correction_vectors_provisional),
        print "r.m.s.d. in pixels: %5.2f" % (math.sqrt(
            flex.mean(c_v_p_flex.dot(c_v_p_flex))))

        if self.horizons_phil.integration.enable_residual_scatter:
            from matplotlib import pyplot as plt
            fig = plt.figure()
            for cv in correction_vectors_provisional:
                plt.plot([cv[1]], [-cv[0]], "b.")
            plt.title(" %d matches, r.m.s.d. %5.2f pixels" %
                      (len(correction_vectors_provisional),
                       math.sqrt(flex.mean(c_v_p_flex.dot(c_v_p_flex)))))
            plt.axes().set_aspect("equal")
            self.show_figure(plt, fig, "res")
            plt.close()

        if self.horizons_phil.integration.enable_residual_map:
            from matplotlib import pyplot as plt
            fig = plt.figure()
            for match, cv in zip(indexed_pairs_provisional,
                                 correction_vectors_provisional):
                plt.plot([spots[match["spot"]].ctr_mass_y()],
                         [-spots[match["spot"]].ctr_mass_x()], "r.")
                plt.plot([self.predicted[match["pred"]][1] / pxlsz],
                         [-self.predicted[match["pred"]][0] / pxlsz], "g.")
                plt.plot([
                    spots[match["spot"]].ctr_mass_y(),
                    spots[match["spot"]].ctr_mass_y() + 10. * cv[1]
                ], [
                    -spots[match["spot"]].ctr_mass_x(),
                    -spots[match["spot"]].ctr_mass_x() - 10. * cv[0]
                ], 'b-')
            plt.xlim([0, float(self.inputpd["size2"])])
            plt.ylim([-float(self.inputpd["size1"]), 0])
            plt.title(" %d matches, r.m.s.d. %5.2f pixels" %
                      (len(correction_vectors_provisional),
                       math.sqrt(flex.mean(c_v_p_flex.dot(c_v_p_flex)))))
            plt.axes().set_aspect("equal")
            self.show_figure(plt, fig, "map")
            plt.close()
        # insert code here to remove correction length outliers...
        # they are causing terrible
        # problems for finding legitimate correction vectors (print out the list)
        # also remove outliers for the purpose of reporting RMS
        outlier_rejection = True
        cache_refinement_spots = getattr(slip_callbacks.slip_callback,
                                         "requires_refinement_spots", False)
        if outlier_rejection:
            correction_lengths = flex.double(
                [v.length() for v in correction_vectors_provisional])
            clorder = flex.sort_permutation(correction_lengths)
            sorted_cl = correction_lengths.select(clorder)

            ACCEPTABLE_LIMIT = 2
            limit = int(
                0.33 * len(sorted_cl)
            )  # best 1/3 of data are assumed to be correctly modeled.
            if (limit <= ACCEPTABLE_LIMIT):
                raise Sorry(
                    "Not enough indexed spots to reject outliers; have %d need >%d"
                    % (limit, ACCEPTABLE_LIMIT))

            y_data = flex.double(len(sorted_cl))
            for i in range(len(y_data)):
                y_data[i] = float(i) / float(len(y_data))

            # ideas are explained in Sauter & Poon (2010) J Appl Cryst 43, 611-616.
            from rstbx.outlier_spots.fit_distribution import fit_cdf, rayleigh
            fitted_rayleigh = fit_cdf(x_data=sorted_cl[0:limit],
                                      y_data=y_data[0:limit],
                                      distribution=rayleigh)

            inv_cdf = [
                fitted_rayleigh.distribution.inv_cdf(cdf) for cdf in y_data
            ]

            #print "SORTED LIST OF ",len(sorted_cl), "with sigma",fitted_rayleigh.distribution.sigma
            indexed_pairs = []
            correction_vectors = []
            self.correction_vectors = []
            for icand in range(len(sorted_cl)):
                # somewhat arbitrary sigma = 1.0 cutoff for outliers
                if (sorted_cl[icand] - inv_cdf[icand]
                    ) / fitted_rayleigh.distribution.sigma > 1.0:
                    break
                indexed_pairs.append(indexed_pairs_provisional[clorder[icand]])
                correction_vectors.append(
                    correction_vectors_provisional[clorder[icand]])
                if cache_refinement_spots:
                    self.spotfinder.images[self.frame_numbers[
                        self.image_number]]["refinement_spots"].append(
                            spots[indexed_pairs[-1]["spot"]])
                if kwargs.get("verbose_cv") == True:
                    print "CV OBSCENTER %7.2f %7.2f REFINEDCENTER %7.2f %7.2f" % (
                        float(self.inputpd["size1"]) / 2.,
                        float(self.inputpd["size2"]) / 2.,
                        self.inputai.xbeam() / pxlsz,
                        self.inputai.ybeam() / pxlsz),
                    print "OBSSPOT %7.2f %7.2f PREDSPOT %7.2f %7.2f" % (
                        spots[indexed_pairs[-1]["spot"]].ctr_mass_x(),
                        spots[indexed_pairs[-1]["spot"]].ctr_mass_y(),
                        self.predicted[indexed_pairs[-1]["pred"]][0] / pxlsz,
                        self.predicted[indexed_pairs[-1]["pred"]][1] / pxlsz),
                    the_hkl = self.hkllist[indexed_pairs[-1]["pred"]]
                    print "HKL %4d %4d %4d" % the_hkl, "%2d" % self.setting_id,
                    radial, azimuthal = spots[indexed_pairs[-1][
                        "spot"]].get_radial_and_azimuthal_size(
                            self.inputai.xbeam() / pxlsz,
                            self.inputai.ybeam() / pxlsz)
                    print "RADIALpx %5.3f AZIMUTpx %5.3f" % (radial, azimuthal)

                # Store a list of correction vectors in self.
                radial, azimuthal = spots[
                    indexed_pairs[-1]['spot']].get_radial_and_azimuthal_size(
                        self.inputai.xbeam() / pxlsz,
                        self.inputai.ybeam() / pxlsz)
                self.correction_vectors.append(
                    dict(obscenter=(float(self.inputpd['size1']) / 2,
                                    float(self.inputpd['size2']) / 2),
                         refinedcenter=(self.inputai.xbeam() / pxlsz,
                                        self.inputai.ybeam() / pxlsz),
                         obsspot=(
                             spots[indexed_pairs[-1]['spot']].ctr_mass_x(),
                             spots[indexed_pairs[-1]['spot']].ctr_mass_y()),
                         predspot=(
                             self.predicted[indexed_pairs[-1]['pred']][0] /
                             pxlsz,
                             self.predicted[indexed_pairs[-1]['pred']][1] /
                             pxlsz),
                         hkl=(self.hkllist[indexed_pairs[-1]['pred']][0],
                              self.hkllist[indexed_pairs[-1]['pred']][1],
                              self.hkllist[indexed_pairs[-1]['pred']][2]),
                         setting_id=self.setting_id,
                         radial=radial,
                         azimuthal=azimuthal))

            print "After outlier rejection %d indexed spotfinder spots remain." % len(
                indexed_pairs)
            if False:
                rayleigh_cdf = [
                    fitted_rayleigh.distribution.cdf(x=sorted_cl[c])
                    for c in range(len(sorted_cl))
                ]
                from matplotlib import pyplot as plt
                plt.plot(sorted_cl, y_data, "r+")
                #plt.plot(sorted_cl,rayleigh_cdf,"g.")
                plt.plot(inv_cdf, y_data, "b.")
                plt.show()
        else:
            indexed_pairs = indexed_pairs_provisional
            correction_vectors = correction_vectors_provisional
        ########### finished with outlier rejection

        self.inputpd["symmetry"].show_summary(prefix="SETTING ")

        is_triclinic = (self.setting_id == 1)
        if is_triclinic:
            self.triclinic_pairs = [
                dict(pred=self.hkllist[a["pred"]], spot=a["spot"])
                for a in indexed_pairs
            ]

        if self.horizons_phil.integration.model == "user_supplied":
            if kwargs.get("user-reentrant", None) == None:
                from cxi_user import post_outlier_rejection
                self.indexed_pairs = indexed_pairs
                self.spots = spots
                post_outlier_rejection(self, image_number, cb_op_to_primitive,
                                       self.horizons_phil, kwargs)
                return

        ########### finished with user-supplied code

        if self.horizons_phil.integration.spot_shape_verbose:
            from rstbx.new_horizons.spot_shape import spot_shape_verbose
            spot_shape_verbose(rawdata=self.imagefiles.images[
                self.image_number].linearintdata,
                               beam_center_pix=matrix.col(
                                   (self.inputai.xbeam() / pxlsz,
                                    self.inputai.ybeam() / pxlsz)),
                               indexed_pairs=indexed_pairs,
                               spotfinder_observations=spots,
                               distance_mm=self.inputai.distance(),
                               mm_per_pixel=pxlsz,
                               hkllist=self.hkllist,
                               unit_cell=self.cell,
                               wavelength_ang=self.inputai.wavelength)

        #Other checks to be implemented (future):
        # spot is within active area of detector on a circular detector such as the Mar IP
        # integration masks do not overlap; or deconvolute

        correction_lengths = flex.double(
            [v.length() for v in correction_vectors])
        if verbose:
            print "average correction %5.2f over %d vectors" % (
                flex.mean(correction_lengths), len(correction_lengths)),
            print "or %5.2f mm." % (pxlsz * flex.mean(correction_lengths))
        self.r_residual = pxlsz * flex.mean(correction_lengths)

        #assert len(indexed_pairs)>NEAR # must have enough indexed spots
        if (len(indexed_pairs) <= NEAR):
            raise Sorry("Not enough indexed spots, only found %d, need %d" %
                        (len(indexed_pairs), NEAR))

        reference = flex.double()
        for item in indexed_pairs:
            reference.append(spots[item["spot"]].ctr_mass_x())
            reference.append(spots[item["spot"]].ctr_mass_y())

        PS_adapt = AnnAdaptor(data=reference, dim=2, k=NEAR)
        PS_adapt.query(query)

        self.BSmasks = []
        #self.null_correction_mapping( predicted=self.predicted,
        #                                    correction_vectors = correction_vectors,
        #                                    IS_adapt = IS_adapt,
        #                                    spots = spots)
        self.positional_correction_mapping(
            predicted=self.predicted,
            correction_vectors=correction_vectors,
            PS_adapt=PS_adapt,
            IS_adapt=IS_adapt,
            spots=spots)

        # which spots are close enough to interfere with background?
        MAXOVER = 6
        OS_adapt = AnnAdaptor(data=query, dim=2, k=MAXOVER)  #six near nbrs
        OS_adapt.query(query)
        if self.mask_focus[image_number] is None:
            raise Sorry(
                "No observed/predicted spot agreement; no Spotfinder masks; skip integration"
            )
        nbr_cutoff = 2.0 * max(self.mask_focus[image_number])
        FRAME = int(nbr_cutoff / 2)
        #print "The overlap cutoff is %d pixels"%nbr_cutoff
        nbr_cutoff_sq = nbr_cutoff * nbr_cutoff

        #print "Optimized C++ section...",
        self.set_frame(FRAME)
        self.set_background_factor(kwargs["background_factor"])
        self.set_nbr_cutoff_sq(nbr_cutoff_sq)
        self.set_guard_width_sq(self.horizons_phil.integration.guard_width_sq)
        self.set_detector_gain(self.horizons_phil.integration.detector_gain)
        flex_sorted = flex.int()
        for item in self.sorted:
            flex_sorted.append(item[0])
            flex_sorted.append(item[1])

        if self.horizons_phil.integration.mask_pixel_value is not None:
            self.set_mask_pixel_val(
                self.horizons_phil.integration.mask_pixel_value)

        image_obj = self.imagefiles.imageindex(
            self.frame_numbers[self.image_number])
        image_obj.read()
        rawdata = image_obj.linearintdata  # assume image #1

        if self.inputai.active_areas != None:
            self.detector_xy_draft = self.safe_background(
                rawdata=rawdata,
                predicted=self.predicted,
                OS_adapt=OS_adapt,
                sorted=flex_sorted,
                tiles=self.inputai.active_areas.IT,
                tile_id=self.inputai.active_areas.tile_id)
        else:
            self.detector_xy_draft = self.safe_background(
                rawdata=rawdata,
                predicted=self.predicted,
                OS_adapt=OS_adapt,
                sorted=flex_sorted)
        for i in range(len(self.predicted)):  # loop over predicteds
            B_S_mask = {}
            keys = self.get_bsmask(i)
            for k in range(0, len(keys), 2):
                B_S_mask[(keys[k], keys[k + 1])] = True
            self.BSmasks.append(B_S_mask)
        #print "Done"
        return
Пример #31
0
    def oneImage(self, framenumber, pd, image):
        self.reporters[framenumber] = []
        # The only way to get pixel size & pixel dimensions (currently) is from header
        pimage = image
        pimage.read()
        #print "Detector type",type(pimage)
        if 'endstation' not in pd:
            from iotbx.detectors.context import endstation
            pd['endstation'] = endstation.EndStation_from_ImageObject(
                pimage, self.phil_params)
            for key in pd['endstation'].mosflm():
                pd[key] = pd['endstation'].mosflm()[key]
        pd['vendortype'] = pimage.vendortype
        pd['binning'] = "%d" % pimage.bin
        pd['pixel_size'] = "%f" % pimage.pixel_size
        self.pixel_size = float(pd['pixel_size'])

        pd['size1'] = "%d" % pimage.size1
        self.size1 = float(pd['size1'])
        pd['size2'] = "%d" % pimage.size2
        self.size2 = float(pd['size2'])
        if 'osc_start' not in pd: pd['osc_start'] = {}
        pd['osc_start'][framenumber] = "%f" % pimage.osc_start
        if 'file' not in pd: pd['file'] = {}
        pd['file'][framenumber] = pimage.filename
        self.two_theta_degrees = float(pd['twotheta'])

        if 'xbeam' not in pd or 'ybeam' not in pd:
            raise SpotfinderError(
                "Deprecation warning: inputs had no beam position", pd)
        self.complex_nominal_center = complex(float(pd["xbeam"]),
                                              float(pd["ybeam"]))

        arguments = ""  # distl_aggressive no longer supported, eg "-s2 5 -s3 8"

        #allow for self.phil_params.distl_highres_limit
        if self.phil_params.distl_highres_limit != None:
            arguments = arguments + " -ro %.3f" % self.phil_params.distl_highres_limit

        #  test implementation of parallel processing for spotfinder
        #from labelit.webice_support import parallel_distl
        #pimage,pd = parallel_distl.split_image(pimage,pd)

        try:
            sf = Distl(
                arguments,
                pimage,
                pd,
                report_overloads=self.phil_params.distl_report_overloads,
                params=self.phil_params)
        except Sorry as e:
            raise e
        except Exception as e:
            raise SpotfinderError("Spotfinder cannot analyze image %s :" %
                                  pimage.filename + e.message)

        #To support sublattice detection, make pixel-wise Z-scores persistent
        if self.phil_params.distl_keep_Zdata:
            pimage.linear_Z_data = sf.Z_data(
            )  #potentially uses a lot of memory

        #************************************************************
        #
        #  Very important.  For the mar image plate (and allother circular detectors,
        #  must specify that these are embedded circular detectors and so adjust the
        #  percentage underloads.  Or else libdistl must be changed so as not to
        # search in these regions:  yes, this would be better because I propose to
        # change the search loop anyway.  However, the getUnderload function must
        # also be modified!!!
        #
        #  ice ring search must also be modified to take this into account, but this
        #  part must be more precise than the above.
        #
        #************************************************************

        if self.two_theta_degrees == 0.0:
            mm_minimum_radius = resol_to_radius(
                self.phil_params.distl_lowres_limit, pd)

        sfa = SpotFilterAgent(
            pixel_size=pimage.pixel_size,
            xbeam=float(pd["xbeam"]),
            ybeam=float(pd["ybeam"]),
            distance=float(pd['distance']),
            wavelength=float(pd['wavelength']),
            icerings=sf.icerings,
        )
        #from libtbx import easy_pickle
        #easy_pickle.dump("file.dmp",sfa)
        #easy_pickle.load("file.dmp")

        fstats = ListManager(masterlist=sf.spots,
                             masterkey='spots_total',
                             spotfilter=sfa)

        fstats['distl_resolution'] = sf.imgresol()

        # 1. Get all spots

        fstats.alias(oldkey='spots_total', newkey='goodspots')
        if VERBOSE_COUNT: print "total DISTL spots", fstats['N_spots_total']

        fstats.c_spot_filter('goodspots', 'spots_non-ice', 'ice_ring_test')
        fstats['ice-ring_impact'] = sf.nicerings()
        fstats['ice-ring_bounds'] = [
            (sf.icerings[i].lowerresol, sf.icerings[i].upperresol)
            for i in xrange(fstats['ice-ring_impact'])
        ]

        #**********************************************************************
        #  Known parts of code that are inefficient: use 35000-spot HK97 example
        #  1. 3.8 seconds: sorting the resolution spots (item #4 in tnear2) (Corrected)
        #  2. 9.7 seconds: spreadsheet bookkeeping; method2_resolution.py, xrow loop (Partly corrected 5/09)
        #  3. 4.4 seconds: ice2::RingFinder::filtered()  (Corrected)

        # 3. omit spots too close to the beamstop
        if self.two_theta_degrees == 0.0:
            fstats.c_spot_filter('spots_non-ice',
                                 'hi_pass_resolution_spots',
                                 'resolution_test',
                                 arguments=[
                                     mm_minimum_radius,
                                 ])
        else:
            fstats.precompute_resolution(
                self.two_theta_degrees * math.pi / 180.,  #two theta radians
                pd['endstation'].rotation_axis(),
                pd['endstation'].camera_convention())

            fstats.c_spot_filter(
                'spots_non-ice',
                'hi_pass_resolution_spots',
                'resolution_test_nztt',
                arguments=[self.phil_params.distl_lowres_limit])

        if VERBOSE_COUNT:
            print "after lowres filter", fstats["N_hi_pass_resolution_spots"]


#start here.
#In the end, make sure these work:
#interface with mosflm: "TWOTHETA" keyword fails; "TILT" fix works with fudge factor
#James Holton's spots index (make unit test); anything with resolution_mm
#diffimage display!:  ring_markup() method of webice_support/__init__
#report the two theta value in stats index
# 4. Calculate resolution cutoff
        if self.two_theta_degrees == 0.0:
            sorted_order, sorted_resolutions = fstats.resolution_sort(
                "hi_pass_resolution_spots")
        else:
            sorted_order, sorted_resolutions = fstats.resolution_sort_nztt(
                "hi_pass_resolution_spots")
        # targetBinNumber: first try number of candidate Bragg spots per bin
        targetBinNumber = max(self.BinMin, len(sorted_order) // 20)

        # cutoff threshhold: expected number spots in highest resolution bin
        cutoff_ratio = 100. / self.phil_params.distl.method2_cutoff_percentage
        fstats['resolution_divisor'] = cutoff_ratio
        lowerCutoffBinNumber = targetBinNumber / cutoff_ratio

        if len(sorted_order) < targetBinNumber:
            # So few spots that there is only one bin
            # no resolution determination possible
            fstats['resolution'] = None
            fstats['resolution_detail'] = len(sorted_order)

        elif False and sorted_resolutions[self.BinMin - 1] < 4.0:
            '''This filter (that essentially says you must have low
      resolution spots) hindered the ability to index the case
      ana/procrun0000084148/sphN1_*.mar2300.  Further investigation
      showed that not a single one of the 94 reference cases in the
      regression database was affected by this test, so the test is
      being provisionally removed.  It is not known if the test has a
      beneficial effect on cases with no protein diffraction, i.e., just
      ice rings.'''
            # This test indicates that there are so few spots at low
            #  resolution that the first bin extends past 4.0 Angstroms,
            #  into the region where ice rings might be found
            #  since there are too few low resolution data
            #  conclude that these are false Bragg spots
            fstats['resolution'] = None
            sorted_resolutions = []
            # deprecated; would need to be recoded:
            fstats['N_spots_resolution'] = 0

        else:
            from spotfinder.diffraction.geometry import Geom2d
            frac_calc = Geom2d(pd)
            #spot-based ice-ring filtering, added Aug 2004
            '''The case ana/procrun0000084148/sphN1_*.mar2300 (image 090) shows the
      limits of this filter as presently implemented.  In that particular
      case, this ice-ring filter eliminates spots from a large area in the
      2-3 Angstrom resolution range.  However, to be believed, the purported
      ice-spots should define a circle or ellipse centered at the beam position
      with a resolution spread that is very narrow.  Code could be
      written much more effectively to search and elimate these rings'''
            from spotfinder.applications.heuristic_tbx.ice2 import RingFinder
            from spotfinder.applications.heuristic_tbx.ice_nztt import RingFinder_nztt

            if (abs(float(pd['twotheta'])) > 0.0):
                # Very inefficient--8 seconds per call; will need to be optimized
                #PP = Profiler("nztt")
                Ring = RingFinder_nztt(sorted_resolutions, targetBinNumber,
                                       frac_calc, image)
                #del PP
            else:
                Ring = RingFinder(sorted_resolutions, targetBinNumber,
                                  frac_calc)

            fstats.add_child("hi_pass_resolution_spots",
                             "ice_free_resolution_spots",
                             Ring.filtered(sorted_order))
            fstats['ice-ring_impact'] += Ring.ice_ring_impact()
            fstats['ice-ring_bounds'] += Ring.ice_ring_bounds()

            #*************************the filtering of existing spots

            if VERBOSE_COUNT:
                print "after spot_based ice-ring filter", fstats[
                    'N_ice_free_resolution_spots']

            if fstats['N_ice_free_resolution_spots'] < targetBinNumber:
                # So few spots that there is only one bin
                # no resolution determination possible
                fstats['resolution'] = None
                fstats['resolution_detail'] = fstats[
                    'N_ice_free_resolution_spots']
            else:
                from spotfinder.applications.heuristic_tbx.method2_resolution\
                  import ResolutionShells
                sorted_resolutions = fstats.spotfilter.get_resolution(
                    fstats.master,
                    fstats.get_indices('ice_free_resolution_spots'))

                Shell = ResolutionShells(
                    sorted_resolutions,
                    sorted_resolutions[targetBinNumber - 1], frac_calc)
                #Shell.show()

                if self.phil_params.distl.bins.verbose:
                    ShellR = spotreporter(
                        sorted_resolutions,
                        self.phil_params,
                        sorted_resolutions[targetBinNumber - 1],
                        wavelength=float(pd['wavelength']),
                        max_total_rows=self.phil_params.distl.bins.N,
                        fractionCalculator=frac_calc,
                        use_binning_of=self)
                    ShellR.total_signal(
                        fstats,
                        fstats.get_indices('ice_free_resolution_spots'))
                    ShellR.background(sf)
                    ShellR.sigma_analysis()
                    print
                    ShellR.show(
                        message=
                        "Analysis of spots after ice removal, but prior to resolution cutoff, for image \n%s"
                        % pimage.filename)
                    self.reporters[framenumber].append(ShellR)

                # slight adjustment so that we don't focus on the lowest
                #  resolution data shell (spends too much time in Ewald sphere)
                #  But don't make this adjustment if we are limited by low spot count
                if Shell.rows() > 2 and \
                    Shell.Population[1] > 2*lowerCutoffBinNumber and \
                    Shell.Population[1] > self.BinMin:
                    lowerCutoffBinNumber = Shell.Population[1] / cutoff_ratio

                # first determination of cutoff ignoring corner effect
                for x in xrange(Shell.rows()):
                    idx = Shell.rows() - x - 1
                    if Shell.Population[idx] > lowerCutoffBinNumber:
                        lastshell = idx
                        break

                # eliminate pathological case where there are a lot of low resolution
                # spots and then some ice rings at high resolution.  If there are ten
                # empty shells in a row (empty defined as having fewer than
                # VetterCut spots), redetermine lastshell.
                #
                # Originally, VetterCut := lowerCutoffBinNumber
                # Modify the heuristic to cover two extremes:
                # Case 1.  Based on the HK97 virus work; there is a class of diffraction
                #    cases showing a distinct dip in diffraction intensity in the
                #    5-Angstrom regime.  If lowerCutoffBinNumber is used (usually
                #    20% of the spot count in the 2nd bin), the algorithm can
                #    misbehave and reject all the high-resolution Bragg spots.
                #    For one case in particular a tiny change in beam position
                #    flips the resolution cutoff from a 6.5- to 4.4-Angstrom.
                # Case 2.  There are many cases where the diffraction clearly
                #    drops off, and at higher resolutions there are random-signal
                #    spots plus ice rings.  The spot count in these high-res bins
                #    is typically small, <20.  Use "20" as a heuristic cutoff
                #    between Case 1 & Case 2.
                # In future, it may be productive to focus on smarter algorithms to
                # execute ellipse recognition in the "Ringfinder" section above

                if lowerCutoffBinNumber <= 20:
                    VetterCut = lowerCutoffBinNumber
                else:
                    VetterCut = 20 + lowerCutoffBinNumber // 5
                lastshell = Shell.vetter(VetterCut, lastshell)

                #option for overriding the resolution analysis based on falloff
                # of spot count.  Force spots at least this far out
                if self.phil_params.force_method2_resolution_limit is not None:
                    for x in xrange(Shell.rows()):
                        if Shell.Limit[
                                x] < self.phil_params.force_method2_resolution_limit and lastshell < x:
                            lastshell = x
                            break

                # extend resolution cutoff taking into account corner cutoff
                while Shell.Fract[
                        lastshell] < 1.0 and lastshell + 1 < Shell.rows():
                    nextshell = lastshell + 1
                    if Shell.adjustPop[nextshell] > lowerCutoffBinNumber:
                        lastshell += 1
                    else:
                        break

                fstats['resolution'] = Shell.Limit[lastshell]
                if self.phil_params.distl_highres_limit != None:
                    fstats['resolution'] = max(
                        fstats['resolution'],
                        self.phil_params.distl_highres_limit)

                for x in xrange(lastshell + 1):
                    if self.phil_params.spotfinder_verbose:
                        print "(%.2f,%d)" % (Shell.Limit[x],
                                             Shell.Population[x])

                if self.two_theta_degrees == 0.0:
                    fstats.c_spot_filter(  #hi-resolution radius
                        'ice_free_resolution_spots',
                        'lo_pass_resolution_spots',
                        'lo_pass_resolution_test',
                        arguments=[
                            resol_to_radius(fstats['resolution'], self.pd),
                        ])
                else:
                    fstats.c_spot_filter(  #hi-resolution radius
                        'ice_free_resolution_spots',
                        'lo_pass_resolution_spots',
                        'lo_pass_resolution_test_nztt',
                        arguments=[
                            fstats['resolution'],
                        ])

                if VERBOSE_COUNT:
                    print "ice_free_resolution_spots ", fstats[
                        'N_ice_free_resolution_spots']

                fstats['shells'] = Shell

                if VERBOSE_COUNT:
                    print "after resolution-shell cutoff", fstats[
                        'N_lo_pass_resolution_spots']
                fstats['resolution_mm'] = resol_to_radius(
                    fstats['resolution'], pd)

        fstats['saturation'] = self.calculate_saturation(fstats, image)

        if self.phil_params.distl.bins.verbose:
            try:
                subset = fstats.spotfilter.get_resolution(
                    fstats.master,
                    fstats.get_indices('lo_pass_resolution_spots'))
                ShellR = spotreporter(subset,
                                      self.phil_params,
                                      use_binning_of=self)
                ShellR.total_signal(
                    fstats, fstats.get_indices('lo_pass_resolution_spots'))
                ShellR.background(sf)
                ShellR.sigma_analysis()
                print
                ShellR.show(
                    message=
                    "Analysis of spots after resolution filtering, but prior to spot quality heuristics, for image \n%s"
                    % pimage.filename)
                self.reporters[framenumber].append(ShellR)

            except Exception:  # in case the low-pass filter step was skipped; e.g., blank image.
                pass

        # 5. eliminate multi-modal spots & punctate spots
        fstats.c_spot_filter(fstats.most_recent_child(),
                             'spots_unimodal',
                             'modal_test',
                             arguments=[
                                 self.phil_params.distl_profile_bumpiness,
                                 self.phil_params.distl.minimum_spot_area
                                 or sf.spotbasesize()
                             ])
        # parameters are bumpiness(max number of local maxima in peak),minimum pixels

        if VERBOSE_COUNT:
            print "not bumpy & not punctate", fstats['N_spots_unimodal']

        # 6. Compute distributions for outlier rejection
        #Y = Timer("Inliers")#try to get this down from 232 seconds to 8 seconds
        #(For HK97 sz=4)

        inlier_idx_raw = flex.int()
        inlier_neigh = []
        unimodal_spots = fstats['spots_unimodal']

        if fstats[
                'N_spots_unimodal'] > 2:  # avoids divide-by-zero error in stats calls, below
            intensities = flex.double([s.intensity() for s in unimodal_spots])
            areas = flex.double([s.bodypixels.size() for s in unimodal_spots])
            # Deprecate shapes because code is unstable; in rare cases spots can have
            # body pixels but no border pixels ( RAW/APS_07_2005/pEI4/pEI4_8_1.0001 )
            #shapes      = flex.double([s.shape() for s in unimodal_spots])
            eccentricity = flex.double(
                [s.model_eccentricity() for s in unimodal_spots])
            skewness = fstats.get_property(fstats.most_recent_child(),
                                           'skewness')

            fstats['intensity'] = (i_ave, i_std) = scitbx_stats(intensities)
            fstats['area'] = (a_ave, a_std) = scitbx_stats(areas)
            #fstats['shape']     = (s_ave,s_std) = scitbx_stats(shapes)
            fstats['eccen'] = (e_ave, e_std) = scitbx_stats(eccentricity)
            fstats['skewness'] = (k_ave, k_std) = scitbx_stats(skewness)

            #Filtering on skewness is important when using center-of-mass positions
            # for autoindexing.  The goal is to eliminate pairs of unresolved Bragg
            # spots.  Condition is flagged when the max_pixel to center-of-mass
            # vector is more than 45% of the semi-major axis
            fstats.c_spot_filter(fstats.most_recent_child(),
                                 'spots_low_skew',
                                 'low_skew',
                                 arguments=[
                                     min(0.45, 2.0 * k_std + k_ave),
                                 ])

            #Filter on the intensity distribution.
            fstats.c_spot_filter(fstats.most_recent_child(),
                                 'spots_good_intensity',
                                 'intensity_inlier',
                                 arguments=[
                                     i_ave - 5.0 * i_std,
                                     i_ave + 5.0 * i_std,
                                     image.saturation,
                                 ])

            #special code for expecting a high MOSFLM RESID based on the
            # presence of very high signal/noise ratio (essentially lysozyme strength).
            # This is all just a supposition based on one dataset, offset_1 from Ana.
            # The assumption may be wrong; e.g. the high resid may be due to very low
            # background instead of high s/n; or due to some geometrical distortion.
            #This breaks encapsulation and will have to be re-organized in the future.
            if 'special_resid' not in pd: pd['special_resid'] = ''
            if fstats['intensity'][0] > 160.:
                pd['special_resid'] = 'RESID 10.0 #High s/n'
            #The most unusual thing about the procrun0000077831/TMC114_WT2_run77831_1_001
            #dataset is its large differential between spot areas of the largest spots
            # and the smallest spots.  Hypothesize that this also leads to high
            # weighted residuals.
            if stats_profile(areas) > 10.:
                pd['special_resid'] = 'RESID 10.0 #High s/n'

            from annlib_ext import AnnAdaptor
            data = fstats.get_property(
                'goodspots', self.phil_params.distl_spotcenter_algorithm)
            query = fstats.get_property(
                fstats.most_recent_child(),
                self.phil_params.distl_spotcenter_algorithm)

            A = AnnAdaptor(data, 2)  # construct k-d tree for reference set
            A.query(query)  # find nearest neighbors of query points

            neighbors = (self.pixel_size) * flex.sqrt(A.distances)
            """Explanation: Distance to the nearest neighbor is math.sqrt(A.distances[i]), in
         units of pixels.  The vector to the nearest neighbor, in units of pixels, is
         ( fstats.master[A.nn[i]].x()-query[2*i], fstats.master[A.nn[i]].y()-query[2*i+1])
      """

            fstats['neighbor'] = (n_ave, n_std) = scitbx_stats(neighbors)

            sep_input_spots = fstats[fstats.most_recent_child()]
            sep_input_indices = fstats.get_indices(fstats.most_recent_child())

            overlapping_count = 0
            for idx in xrange(len(sep_input_spots)):
                try:
                    if float(pd['pixel_size'])*sep_input_spots[idx].majoraxis() * \
                       self.phil_params.overlapping_spot_criterion > neighbors[idx]:
                        overlapping_count += 1
                except Exception:
                    pass
            if len(sep_input_spots) == 0: percent_overlap = 0
            else:
                percent_overlap = 100 * overlapping_count / len(
                    sep_input_spots)
            #print "overlap %2.0f%% vs. cutoff %2.0f%%"%(percent_overlap,self.phil_params.percent_overlap_forcing_detail)

            from spotfinder.core_toolbox.close_spots_detail import NearNeighborVectors
            Afull = AnnAdaptor(data, 2)
            Afull.query(data)
            NV = NearNeighborVectors(ave_area=a_ave,
                                     query_centers=data,
                                     fstats=fstats,
                                     ann_adaptor=Afull)
            #NV.show_vector_map()
            #NV.show_maxima()

            DEVELOP_ASSERT = True
            self.force_detail = percent_overlap > self.phil_params.percent_overlap_forcing_detail
            if DEVELOP_ASSERT or self.force_detail:
                self.overlapping = True
                #extraordinary procedure, when many spots are close.  Include closely
                #  spaced spots in autoindexing, if it appears that they truly
                #  reflect lattice spacing.
                if self.phil_params.spotfinder_verbose:
                    print len(sep_input_spots
                              ), "spot count before close neighbor analysis;",
                    print overlapping_count, "(%2.0f%%) rejected on neighbors;" % (
                        percent_overlap)

                pmax = NV.vectors()
                #filter out spots that are potentially large enough to contain
                #two spots, now that we know a candidate projected unit-cell vector
                # expect big time savings if this section is pushed down to C++
                compact_idx = []

                if 0 < len(pmax) <= 3:
                    sq_vectors = [v[0] * v[0] + v[1] * v[1] for v in pmax]
                    for idx in xrange(len(sep_input_spots)):
                        spot_compact = True
                        for iv, vector in enumerate(pmax):
                            thisspot = sep_input_spots[idx]
                            #more efficient code--disallowed spots (based on nearest neighbor
                            # vector) are now flagged based on the width of the ellipse model
                            # rather than a more time-consuming body-pixel match:

                            #calculate angle theta between major axis and neighbor vector
                            dot = thisspot.eigenvector(1)[0] * vector[
                                0] + thisspot.eigenvector(1)[1] * vector[1]
                            costheta = dot / math.sqrt(sq_vectors[iv])
                            costhetasq = min(costheta * costheta, 1.0)
                            sintheta = math.sqrt(1 - costhetasq)
                            spota = thisspot.a()
                            spotb = thisspot.b()
                            a_sin_theta = spota * sintheta
                            b_cos_theta = spotb * costheta
                            #evaluate the ellipse full width along neighbor vector direction
                            width_sq = 4. * (spota * spota * spotb * spotb /
                                             (a_sin_theta * a_sin_theta +
                                              b_cos_theta * b_cos_theta))
                            if width_sq >= sq_vectors[iv]:
                                spot_compact = False
                                break

                        if spot_compact: compact_idx.append(idx)
                        else:
                            pass  #print "eliminate the spot at",thisspot.x(),thisspot.y()
                else:
                    compact_idx = xrange(len(sep_input_spots))
                if self.phil_params.spotfinder_verbose:
                    print len(sep_input_spots) - len(
                        compact_idx), "large spots rejected"

                # finally, allow certain close spots (but not all of them) to be included
                for idx in compact_idx:
                    try:
                        S = (int(fstats.master[A.nn[idx]].max_pxl_x() -
                                 query[2 * idx]),
                             int(fstats.master[A.nn[idx]].max_pxl_y() -
                                 query[2 * idx + 1]))
                        #accept spot by default
                        reject_spot = False
                        #if close to nearest neighbor reject
                        if sep_input_spots[idx].majoraxis() * \
                           self.phil_params.overlapping_spot_criterion > math.sqrt(S[0]*S[0]+S[1]*S[1]):
                            # with normal procedure, spot would be rejected at this point
                            reject_spot = True
                            if len(pmax) <= 3:
                                for vector in pmax:
                                    if abs(vector[0] - S[0]) <= 1 and abs(
                                            vector[1] - S[1]) <= 1:
                                        #but allow if the proximity is to a candidate cell near neighbor
                                        reject_spot = False
                                        break
                        if reject_spot: continue

                        inlier_idx_raw.append(sep_input_indices[idx])
                        inlier_neigh.append(neighbors[idx])
                    except Exception:
                        pass

                if self.phil_params.spotfinder_verbose:
                    print len(compact_idx) - len(
                        inlier_idx_raw), "close spots rejected"
                    print len(sep_input_spots
                              ), "input for spot separation analysis;",
                    jj = len(sep_input_spots) - len(inlier_idx_raw)
                    print jj, "(%2.0f%%) rejected on special criteria;" % (
                        100. * jj / len(sep_input_spots))

            else:  #normal procedure, assuming not too many close spots
                for idx in xrange(len(sep_input_spots)):
                    try:
                        if math.fabs(intensities[idx]-i_ave) <= 5.0*i_std and \
                           intensities[idx]<image.saturation and \
                           float(pd['pixel_size'])*sep_input_spots[idx].majoraxis() * \
                           self.phil_params.overlapping_spot_criterion<=neighbors[idx]:
                            inlier_idx_raw.append(sep_input_indices[idx])
                            inlier_neigh.append(neighbors[idx])
                    except Exception:
                        #print "REJECT spot on exception"
                        pass  #sometimes throw an error when majoraxis is requested (edge spots)

                if len(inlier_idx_raw) < self.NspotMin:
                    for idx in xrange(len(sep_input_spots)):
                        try:
                            proximal_radius = 2.0 * self.phil_params.overlapping_spot_criterion * float(
                                pd['pixel_size']
                            ) * sep_input_spots[idx].majoraxis()
                            if math.fabs(intensities[idx]-i_ave) <= 5.0*i_std and \
                               intensities[idx]<image.saturation and \
                               float(pd['pixel_size'])*sep_input_spots[idx].majoraxis() *self.phil_params.overlapping_spot_criterion > neighbors[idx] and \
                               sf.isIsolated(sep_input_spots[idx],proximal_radius):
                                #print "Very few Bragg spots; forced to accept spot with neighbor distance",neighbors[idx]/(float(pd['pixel_size'])*sep_input_spots[idx].majoraxis())
                                inlier_idx_raw.append(sep_input_indices[idx])
                                inlier_neigh.append(neighbors[idx])
                        except Exception:
                            print "REJECT spot on exception"
                            pass  #sometimes throw an error when majoraxis is requested (edge spots)

        if fstats.has_extended_key('lo_pass_resolution_spots'):
            fstats.alias('lo_pass_resolution_spots', 'spots_resolution')
        elif fstats.has_extended_key('ice_free_resolution_spots'):
            fstats.alias('ice_free_resolution_spots', 'spots_resolution')
        else:
            fstats.alias('hi_pass_resolution_spots', 'spots_resolution')

        fstats.add_child('spots_unimodal', 'spots_separated', inlier_idx_raw)

        fstats.alias(fstats.most_recent_child(), 'spots_inlier')
        fstats.alias('spots_inlier',
                     'inlier_spots')  #for backward compatibility

        if self.phil_params.distl.bins.verbose:
            try:
                subset = fstats.spotfilter.get_resolution(
                    fstats.master, fstats.get_indices('inlier_spots'))
                ShellR = spotreporter(subset,
                                      self.phil_params,
                                      use_binning_of=self)
                ShellR.total_signal(fstats, fstats.get_indices('inlier_spots'))
                ShellR.background(sf)
                ShellR.sigma_analysis()
                print
                ShellR.show(
                    message=
                    "Analysis of good Bragg spots after quality heuristics, for image \n%s"
                    % pimage.filename)
                self.reporters[framenumber].append(ShellR)

            except Exception:
                pass  #if there aren't enough spots, just skip the tabular printout

        if 'masks' not in pd: pd['masks'] = {}
        pd['masks'][framenumber] = None
        if fstats['N_spots_inlier'] > (  #guard against C++ hard-coded minimum
                self.phil_params.codecamp.minimum_spot_count or 25):
            Msk = fstats.single_mask('inlier_spots', self.phil_params)
            pd['masks'][framenumber] = [Msk.x, Msk.y]

        if VERBOSE_COUNT: print "inlier spots", fstats["N_inlier_spots"]

        #need this for later calculation of maxcell
        fstats['neighbors'] = flex.double(inlier_neigh)

        return fstats
    def integration_concept_detail(self, experiments, reflections, spots,
                                   image_number, cb_op_to_primitive, **kwargs):
        detector = experiments[0].detector
        crystal = experiments[0].crystal
        from cctbx.crystal import symmetry
        c_symmetry = symmetry(space_group=crystal.get_space_group(),
                              unit_cell=crystal.get_unit_cell())

        self.image_number = image_number
        NEAR = 10
        pxlsz = detector[0].get_pixel_size()

        Predicted = self.get_predictions_accounting_for_centering(
            experiments, reflections, cb_op_to_primitive, **kwargs)

        FWMOSAICITY = self.inputai.getMosaicity()
        self.DOMAIN_SZ_ANG = kwargs.get("domain_size_ang",
                                        self.__dict__.get("actual", 0))
        refineflag = {True: 0, False: 1}[kwargs.get("domain_size_ang", 0) == 0]
        c_symmetry.show_summary(
            prefix="EXCURSION%1d REPORT FWMOS= %6.4f DOMAIN= %6.1f " %
            (refineflag, FWMOSAICITY, self.DOMAIN_SZ_ANG))
        from annlib_ext import AnnAdaptor
        self.cell = c_symmetry.unit_cell()

        query = flex.double()
        print len(self.predicted)

        for pred in self.predicted:  # predicted spot coord in pixels
            query.append(pred[0] / pxlsz[0])
            query.append(pred[1] / pxlsz[1])

        self.reserve_hkllist_for_signal_search = self.hkllist

        reference = flex.double()

        assert self.length > NEAR  # Can't do spot/pred matching with too few spots
        for spot in spots:
            reference.append(spot.ctr_mass_x())
            reference.append(spot.ctr_mass_y())

        IS_adapt = AnnAdaptor(data=reference, dim=2, k=NEAR)
        IS_adapt.query(query)
        idx_cutoff = float(min(self.mask_focus[image_number]))

        from rstbx.apps.slip_helpers import slip_callbacks
        cache_refinement_spots = getattr(slip_callbacks.slip_callback,
                                         "requires_refinement_spots", False)

        indexed_pairs_provisional = []
        correction_vectors_provisional = []
        c_v_p_flex = flex.vec3_double()
        this_setting_matched_indices = reflections["miller_index"]
        for j, item in enumerate(this_setting_matched_indices):
            this_setting_index = self.hkllist.first_index(item)
            if this_setting_index:
                Match = dict(spot=j, pred=this_setting_index)
                indexed_pairs_provisional.append(Match)
                vector = matrix.col([
                    reflections["xyzobs.px.value"][j][0] -
                    self.predicted[Match["pred"]][0] / pxlsz[0],
                    reflections["xyzobs.px.value"][j][1] -
                    self.predicted[Match["pred"]][1] / pxlsz[1]
                ])
                correction_vectors_provisional.append(vector)
                c_v_p_flex.append((vector[0], vector[1], 0.))
        self.N_correction_vectors = len(correction_vectors_provisional)
        self.rmsd_px = math.sqrt(flex.mean(c_v_p_flex.dot(c_v_p_flex)))
        print "... %d provisional matches" % self.N_correction_vectors,
        print "r.m.s.d. in pixels: %6.3f" % (self.rmsd_px)

        if self.horizons_phil.integration.enable_residual_scatter:
            from matplotlib import pyplot as plt
            fig = plt.figure()
            for cv in correction_vectors_provisional:
                plt.plot([cv[1]], [-cv[0]], "r.")
            plt.title(" %d matches, r.m.s.d. %5.2f pixels" %
                      (len(correction_vectors_provisional),
                       math.sqrt(flex.mean(c_v_p_flex.dot(c_v_p_flex)))))
            plt.axes().set_aspect("equal")
            self.show_figure(plt, fig, "res")
            plt.close()

        if self.horizons_phil.integration.enable_residual_map:
            from matplotlib import pyplot as plt
            PX = reflections["xyzobs.px.value"]
            fig = plt.figure()
            for match, cv in zip(indexed_pairs_provisional,
                                 correction_vectors_provisional):
                plt.plot([PX[match["spot"]][1]], [-PX[match["spot"]][0]], "r.")
                plt.plot([self.predicted[match["pred"]][1] / pxlsz[1]],
                         [-self.predicted[match["pred"]][0] / pxlsz[0]], "g.")
                plt.plot(
                    [PX[match["spot"]][1], PX[match["spot"]][1] + 10. * cv[1]],
                    [
                        -PX[match["spot"]][0],
                        -PX[match["spot"]][0] - 10. * cv[0]
                    ], 'r-')
            if kwargs.get("user-reentrant") != None and self.horizons_phil.integration.spot_prediction == "dials" \
                   and self.horizons_phil.integration.enable_residual_map_deltapsi:
                from rstbx.apps.stills.util import residual_map_special_deltapsi_add_on
                residual_map_special_deltapsi_add_on(
                    reflections=self.dials_spot_prediction,
                    matches=indexed_pairs_provisional,
                    experiments=experiments,
                    hkllist=self.hkllist,
                    predicted=self.predicted,
                    plot=plt,
                    eta_deg=FWMOSAICITY,
                    deff=self.DOMAIN_SZ_ANG)
            plt.xlim([0, detector[0].get_image_size()[1]])
            plt.ylim([-detector[0].get_image_size()[0], 0])
            plt.title(" %d matches, r.m.s.d. %5.2f pixels" %
                      (len(correction_vectors_provisional),
                       math.sqrt(flex.mean(c_v_p_flex.dot(c_v_p_flex)))))
            plt.axes().set_aspect("equal")
            self.show_figure(plt, fig, "map")
            plt.close()

        indexed_pairs = indexed_pairs_provisional
        correction_vectors = correction_vectors_provisional
        ########### skip outlier rejection for this derived class

        ### However must retain the ability to write out correction vectiors.
        if True:  # at Aaron's request; test later
            correction_lengths = flex.double(
                [v.length() for v in correction_vectors_provisional])
            clorder = flex.sort_permutation(correction_lengths)
            sorted_cl = correction_lengths.select(clorder)
            indexed_pairs = []
            correction_vectors = []
            self.correction_vectors = []
            for icand in xrange(len(sorted_cl)):
                # somewhat arbitrary sigma = 1.0 cutoff for outliers
                indexed_pairs.append(indexed_pairs_provisional[clorder[icand]])
                correction_vectors.append(
                    correction_vectors_provisional[clorder[icand]])
                if cache_refinement_spots:
                    self.spotfinder.images[self.frame_numbers[
                        self.image_number]]["refinement_spots"].append(
                            spots[reflections[indexed_pairs[-1]["spot"]]
                                  ['spotfinder_lookup']])
                if kwargs.get("verbose_cv") == True:
                    print "CV OBSCENTER %7.2f %7.2f REFINEDCENTER %7.2f %7.2f" % (
                        float(self.inputpd["size1"]) / 2.,
                        float(self.inputpd["size2"]) / 2.,
                        self.inputai.xbeam() / pxlsz[0],
                        self.inputai.ybeam() / pxlsz[1]),
                    print "OBSSPOT %7.2f %7.2f PREDSPOT %7.2f %7.2f" % (
                        reflections[indexed_pairs[-1]["spot"]]
                        ['xyzobs.px.value'][0], reflections[
                            indexed_pairs[-1]["spot"]]['xyzobs.px.value'][1],
                        self.predicted[indexed_pairs[-1]["pred"]][0] /
                        pxlsz[0], self.predicted[indexed_pairs[-1]["pred"]][1]
                        / pxlsz[1]),
                    the_hkl = self.hkllist[indexed_pairs[-1]["pred"]]
                    print "HKL %4d %4d %4d" % the_hkl, "%2d" % self.setting_id,
                    radial, azimuthal = spots[indexed_pairs[-1][
                        "spot"]].get_radial_and_azimuthal_size(
                            self.inputai.xbeam() / pxlsz[0],
                            self.inputai.ybeam() / pxlsz[1])
                    print "RADIALpx %5.3f AZIMUTpx %5.3f" % (radial, azimuthal)

                # Store a list of correction vectors in self.
                radial, azimuthal = spots[
                    indexed_pairs[-1]['spot']].get_radial_and_azimuthal_size(
                        self.inputai.xbeam() / pxlsz[0],
                        self.inputai.ybeam() / pxlsz[1])
                self.correction_vectors.append(
                    dict(obscenter=(float(self.inputpd['size1']) / 2,
                                    float(self.inputpd['size2']) / 2),
                         refinedcenter=(self.inputai.xbeam() / pxlsz[0],
                                        self.inputai.ybeam() / pxlsz[1]),
                         obsspot=(reflections[indexed_pairs[-1]
                                              ['spot']]['xyzobs.px.value'][0],
                                  reflections[indexed_pairs[-1]
                                              ['spot']]['xyzobs.px.value'][1]),
                         predspot=(
                             self.predicted[indexed_pairs[-1]['pred']][0] /
                             pxlsz[0],
                             self.predicted[indexed_pairs[-1]['pred']][1] /
                             pxlsz[1]),
                         hkl=(self.hkllist[indexed_pairs[-1]['pred']][0],
                              self.hkllist[indexed_pairs[-1]['pred']][1],
                              self.hkllist[indexed_pairs[-1]['pred']][2]),
                         setting_id=self.setting_id,
                         radial=radial,
                         azimuthal=azimuthal))

        self.inputpd["symmetry"] = c_symmetry
        self.inputpd["symmetry"].show_summary(prefix="SETTING ")

        if self.horizons_phil.integration.model == "user_supplied":
            # Not certain of whether the reentrant_* dictionary keys create a memory leak
            if kwargs.get("user-reentrant", None) == None:
                kwargs["reentrant_experiments"] = experiments
                kwargs["reentrant_reflections"] = reflections
                from cxi_user import post_outlier_rejection
                self.indexed_pairs = indexed_pairs
                self.spots = spots
                post_outlier_rejection(self, image_number, cb_op_to_primitive,
                                       self.horizons_phil, kwargs)
                return
        ########### finished with user-supplied code

        correction_lengths = flex.double(
            [v.length() for v in correction_vectors])

        self.r_residual = pxlsz[0] * flex.mean(correction_lengths)

        #assert len(indexed_pairs)>NEAR # must have enough indexed spots
        if (len(indexed_pairs) <= NEAR):
            raise Sorry("Not enough indexed spots, only found %d, need %d" %
                        (len(indexed_pairs), NEAR))

        reference = flex.double()
        for item in indexed_pairs:
            reference.append(spots[item["spot"]].ctr_mass_x())
            reference.append(spots[item["spot"]].ctr_mass_y())

        PS_adapt = AnnAdaptor(data=reference, dim=2, k=NEAR)
        PS_adapt.query(query)

        self.BSmasks = []
        # do not use null: self.null_correction_mapping( predicted=self.predicted,
        self.positional_correction_mapping(
            predicted=self.predicted,
            correction_vectors=correction_vectors,
            PS_adapt=PS_adapt,
            IS_adapt=IS_adapt,
            spots=spots)

        # which spots are close enough to interfere with background?
        MAXOVER = 6
        OS_adapt = AnnAdaptor(data=query, dim=2, k=MAXOVER)  #six near nbrs
        OS_adapt.query(query)
        if self.mask_focus[image_number] is None:
            raise Sorry(
                "No observed/predicted spot agreement; no Spotfinder masks; skip integration"
            )
        nbr_cutoff = 2.0 * max(self.mask_focus[image_number])
        FRAME = int(nbr_cutoff / 2)
        #print "The overlap cutoff is %d pixels"%nbr_cutoff
        nbr_cutoff_sq = nbr_cutoff * nbr_cutoff

        #print "Optimized C++ section...",
        self.set_frame(FRAME)
        self.set_background_factor(kwargs["background_factor"])
        self.set_nbr_cutoff_sq(nbr_cutoff_sq)
        self.set_guard_width_sq(self.horizons_phil.integration.guard_width_sq)
        self.set_detector_gain(self.horizons_phil.integration.detector_gain)
        flex_sorted = flex.int()
        for item in self.sorted:
            flex_sorted.append(item[0])
            flex_sorted.append(item[1])

        if self.horizons_phil.integration.mask_pixel_value is not None:
            self.set_mask_pixel_val(
                self.horizons_phil.integration.mask_pixel_value)

        image_obj = self.imagefiles.imageindex(
            self.frame_numbers[self.image_number])
        image_obj.read()
        rawdata = image_obj.linearintdata  # assume image #1

        if self.inputai.active_areas != None:
            self.detector_xy_draft = self.safe_background(
                rawdata=rawdata,
                predicted=self.predicted,
                OS_adapt=OS_adapt,
                sorted=flex_sorted,
                tiles=self.inputai.active_areas.IT,
                tile_id=self.inputai.active_areas.tile_id)
        else:
            self.detector_xy_draft = self.safe_background(
                rawdata=rawdata,
                predicted=self.predicted,
                OS_adapt=OS_adapt,
                sorted=flex_sorted)
        for i in xrange(len(self.predicted)):  # loop over predicteds
            B_S_mask = {}
            keys = self.get_bsmask(i)
            for k in xrange(0, len(keys), 2):
                B_S_mask[(keys[k], keys[k + 1])] = True
            self.BSmasks.append(B_S_mask)
        #print "Done"
        return
Пример #33
0
    def __init__(self,
                 reflections,
                 step_size=45,
                 tolerance=1.5,
                 max_height_fraction=0.25,
                 percentile=0.05):
        self.tolerance = tolerance  # Margin of error for max unit cell estimate
        from scitbx.array_family import flex
        NEAR = 10
        self.NNBIN = 5  # target number of neighbors per histogram bin

        direct = flex.double()

        if 'entering' in reflections:
            entering_flags = reflections['entering']
        else:
            entering_flags = flex.bool(reflections.size(), True)
        rs_vectors = reflections['rlp']
        phi_deg = reflections['xyzobs.mm.value'].parts()[2] * (180 / math.pi)

        # nearest neighbor analysis
        from annlib_ext import AnnAdaptor
        for imageset_id in range(flex.max(reflections['imageset_id']) + 1):
            sel = reflections['imageset_id'] == imageset_id
            phi_min = flex.min(phi_deg.select(sel))
            phi_max = flex.max(phi_deg.select(sel))
            d_phi = phi_max - phi_min
            n_steps = max(int(math.ceil(d_phi / step_size)), 1)

            for n in range(n_steps):
                sel &= (phi_deg >=
                        (phi_min + n * step_size)) & (phi_deg <
                                                      (phi_min +
                                                       (n + 1) * step_size))

                for entering in (True, False):
                    sel &= entering_flags == entering
                    if sel.count(True) == 0:
                        continue

                    query = flex.double()
                    query.extend(rs_vectors.select(sel).as_double())

                    if query.size() == 0:
                        continue

                    IS_adapt = AnnAdaptor(data=query, dim=3, k=1)
                    IS_adapt.query(query)

                    direct.extend(1 / flex.sqrt(IS_adapt.distances))

        assert len(direct) > NEAR, (
            "Too few spots (%d) for nearest neighbour analysis." % len(direct))

        # reject top 1% of longest distances to hopefully get rid of any outliers
        direct = direct.select(
            flex.sort_permutation(direct)[:int(math.floor(0.99 *
                                                          len(direct)))])

        # determine the most probable nearest neighbor distance (direct space)
        hst = flex.histogram(direct, n_slots=int(len(direct) / self.NNBIN))
        centers = hst.slot_centers()
        islot = hst.slots()
        highest_bin_height = flex.max(islot)
        most_probable_neighbor = centers[list(islot).index(highest_bin_height)]

        if False:  # to print out the histogramming analysis
            smin, smax = flex.min(direct), flex.max(direct)
            stats = flex.mean_and_variance(direct)
            import sys
            out = sys.stdout
            print >> out, "     range:     %6.2f - %.2f" % (smin, smax)
            print >> out, "     mean:      %6.2f +/- %6.2f on N = %d" % (
                stats.mean(), stats.unweighted_sample_standard_deviation(),
                direct.size())
            hst.show(f=out, prefix="    ", format_cutoffs="%6.2f")
            print >> out, ""

        # choose a max cell based on bins above a given fraction of the highest bin height
        # given multiple
        isel = (islot.as_double() >
                (max_height_fraction * highest_bin_height)).iselection()
        self.max_cell = (
            self.tolerance * centers[int(flex.max(isel.as_double()))] +
            0.5 * hst.slot_width())

        # determine the 5th-percentile direct-space distance
        perm = flex.sort_permutation(direct, reverse=True)
        self.percentile = direct[perm[int(percentile * len(direct))]]

        #MAXTOL = 1.5 # Margin of error for max unit cell estimate
        #self.max_cell = max(MAXTOL * most_probable_neighbor,
        #MAXTOL * self.percentile)

        if False:
            self.plot(direct)
Пример #34
0
def check_memory():
  data,query = data_from_files()
  for x in xrange(1000):
    AnnAdaptor(data,2).query(query)
Пример #35
0
      #This breaks encapsulation and will have to be re-organized in the future.
      if not pd.has_key('special_resid'): pd['special_resid']=''
      if fstats['intensity'][0]>160.: pd['special_resid']='RESID 10.0 #High s/n'
      #The most unusual thing about the procrun0000077831/TMC114_WT2_run77831_1_001
      #dataset is its large differential between spot areas of the largest spots
      # and the smallest spots.  Hypothesize that this also leads to high
      # weighted residuals.
      if stats_profile(areas)>10.: pd['special_resid']='RESID 10.0 #High s/n'

      from annlib_ext import AnnAdaptor
      data = fstats.get_property('goodspots',
             self.phil_params.distl_spotcenter_algorithm)
      query = fstats.get_property(fstats.most_recent_child(),
              self.phil_params.distl_spotcenter_algorithm)

      A = AnnAdaptor(data,2)       # construct k-d tree for reference set
      A.query(query)               # find nearest neighbors of query points

      neighbors = (self.pixel_size) * flex.sqrt(A.distances)

      """Explanation: Distance to the nearest neighbor is math.sqrt(A.distances[i]), in
         units of pixels.  The vector to the nearest neighbor, in units of pixels, is
         ( fstats.master[A.nn[i]].x()-query[2*i], fstats.master[A.nn[i]].y()-query[2*i+1])
      """

      fstats['neighbor']  = (n_ave,n_std) = scitbx_stats(neighbors)

      sep_input_spots = fstats[fstats.most_recent_child()]
      sep_input_indices = fstats.get_indices(fstats.most_recent_child())

      overlapping_count = 0
def do_connected_components(
        experiments,  # type: ExperimentList
        reflection_tables,  # type: flex.reflection_table
        min_component_size=50,  # type: int
):  # type: (...) -> [{}]
    """
    Write the behaviour of the program as functions and classes outside run().

    Don't include file output here, remember that this function may be re-used
    elsewhere by someone who doesn't need the output written immediately to file.

    It can be especially helpful to document any expected exceptions that might be
    raised, in order to keep track of what needs to be handled in any code that
    re-uses this function.

    Args:
        experiments:  An experiment list.
        reflections:  A reflection table.
    """

    miller_array = scaled_data_as_miller_array(
        reflection_tables, experiments,
        anomalous_flag=False).primitive_setting()
    unique = miller_array.unique_under_symmetry().map_to_asu()
    unique = unique.generate_bijvoet_mates()
    complete_set = unique.complete_set()
    missing_set = complete_set.lone_set(unique)
    missing_set = missing_set.expand_to_p1().customized_copy(
        crystal_symmetry=missing_set.crystal_symmetry())

    mi = missing_set.indices().as_vec3_double().as_double()
    k = 6
    ann = AnnAdaptor(data=mi, dim=3, k=k)
    ann.query(mi)

    G = nx.Graph()
    distance_cutoff = 2**0.5
    for i in range(missing_set.size()):
        ik = i * k
        for i_ann in range(k):
            if ann.distances[ik + i_ann] <= distance_cutoff:
                j = ann.nn[ik + i_ann]
                G.add_edge(i, j)

    conn = sorted(nx.connected_components(G), key=len, reverse=True)
    unique_mi = []
    unique_ms = []
    for i, c in enumerate(conn):
        ms = (missing_set.select(flex.size_t(list(c))).customized_copy(
            crystal_symmetry=miller_array).as_non_anomalous_set().map_to_asu())
        ms = ms.unique_under_symmetry()
        mi = set(ms.indices())
        if mi not in unique_mi:
            unique_ms.append(ms)
            unique_mi.append(mi)

    n_expected = unique.as_non_anomalous_set().complete_set().size()
    unique_ms = sorted(unique_ms, key=lambda ms: ms.size(), reverse=True)
    unique_ms = [ms for ms in unique_ms if ms.size() > min_component_size]
    for ms in unique_ms:
        d_max, d_min = (uctbx.d_star_sq_as_d(ds2)
                        for ds2 in ms.min_max_d_star_sq())
        logger.info("%i reflections (%.1f%%): %.2f-%.2f Å" %
                    (ms.size(), 100 * ms.size() / n_expected, d_max, d_min))
    return unique_ms
  def integration_concept_detail(self, experiments, reflections, spots,image_number,cb_op_to_primitive,**kwargs):
    detector = experiments[0].detector
    crystal = experiments[0].crystal
    from cctbx.crystal import symmetry
    c_symmetry = symmetry(space_group = crystal.get_space_group(), unit_cell = crystal.get_unit_cell())

    self.image_number = image_number
    NEAR = 10
    pxlsz = detector[0].get_pixel_size()

    Predicted = self.get_predictions_accounting_for_centering(experiments,reflections,cb_op_to_primitive,**kwargs)

    FWMOSAICITY = self.inputai.getMosaicity()
    self.DOMAIN_SZ_ANG = kwargs.get("domain_size_ang",  self.__dict__.get("actual",0)  )
    refineflag = {True:0,False:1}[kwargs.get("domain_size_ang",0)==0]
    c_symmetry.show_summary(prefix="EXCURSION%1d REPORT FWMOS= %6.4f DOMAIN= %6.1f "%(refineflag,FWMOSAICITY,self.DOMAIN_SZ_ANG))
    from annlib_ext import AnnAdaptor
    self.cell = c_symmetry.unit_cell()

    query = flex.double()
    print len(self.predicted)

    for pred in self.predicted: # predicted spot coord in pixels
      query.append(pred[0]/pxlsz[0])
      query.append(pred[1]/pxlsz[1])

    self.reserve_hkllist_for_signal_search = self.hkllist

    reference = flex.double()

    assert self.length>NEAR# Can't do spot/pred matching with too few spots
    for spot in spots:
      reference.append(spot.ctr_mass_x())
      reference.append(spot.ctr_mass_y())

    IS_adapt = AnnAdaptor(data=reference,dim=2,k=NEAR)
    IS_adapt.query(query)
    idx_cutoff = float(min(self.mask_focus[image_number]))

    from rstbx.apps.slip_helpers import slip_callbacks
    cache_refinement_spots = getattr(slip_callbacks.slip_callback,"requires_refinement_spots",False)

    indexed_pairs_provisional = []
    correction_vectors_provisional = []
    c_v_p_flex = flex.vec3_double()
    this_setting_matched_indices = reflections["miller_index"]
    for j,item in enumerate(this_setting_matched_indices):
      this_setting_index = self.hkllist.first_index(item)
      if this_setting_index:
        Match = dict(spot=j,pred=this_setting_index)
        indexed_pairs_provisional.append(Match)
        vector = matrix.col(
            [reflections["xyzobs.px.value"][j][0] - self.predicted[Match["pred"]][0]/pxlsz[0],
             reflections["xyzobs.px.value"][j][1] - self.predicted[Match["pred"]][1]/pxlsz[1]])
        correction_vectors_provisional.append(vector)
        c_v_p_flex.append((vector[0],vector[1],0.))
    self.N_correction_vectors = len(correction_vectors_provisional)
    self.rmsd_px = math.sqrt(flex.mean(c_v_p_flex.dot(c_v_p_flex)))
    print "... %d provisional matches"%self.N_correction_vectors,
    print "r.m.s.d. in pixels: %6.3f"%(self.rmsd_px)

    if self.horizons_phil.integration.enable_residual_scatter:
      from matplotlib import pyplot as plt
      fig = plt.figure()
      for cv in correction_vectors_provisional:
        plt.plot([cv[1]],[-cv[0]],"r.")
      plt.title(" %d matches, r.m.s.d. %5.2f pixels"%(len(correction_vectors_provisional),math.sqrt(flex.mean(c_v_p_flex.dot(c_v_p_flex)))))
      plt.axes().set_aspect("equal")
      self.show_figure(plt,fig,"res")
      plt.close()

    if self.horizons_phil.integration.enable_residual_map:
      from matplotlib import pyplot as plt
      PX = reflections["xyzobs.px.value"]
      fig = plt.figure()
      for match,cv in zip(indexed_pairs_provisional,correction_vectors_provisional):
        plt.plot([PX[match["spot"]][1]],[-PX[match["spot"]][0]],"r.")
        plt.plot([self.predicted[match["pred"]][1]/pxlsz[1]],[-self.predicted[match["pred"]][0]/pxlsz[0]],"g.")
        plt.plot([PX[match["spot"]][1], PX[match["spot"]][1] + 10.*cv[1]],
                 [-PX[match["spot"]][0], -PX[match["spot"]][0] - 10.*cv[0]],'r-')
      if kwargs.get("user-reentrant") != None and self.horizons_phil.integration.spot_prediction == "dials" \
             and self.horizons_phil.integration.enable_residual_map_deltapsi:
        from rstbx.apps.stills.util import residual_map_special_deltapsi_add_on
        residual_map_special_deltapsi_add_on(
          reflections = self.dials_spot_prediction,
          matches = indexed_pairs_provisional, experiments=experiments,
          hkllist = self.hkllist,
          predicted = self.predicted, plot=plt, eta_deg=FWMOSAICITY, deff=self.DOMAIN_SZ_ANG
          )
      plt.xlim([0,detector[0].get_image_size()[1]])
      plt.ylim([-detector[0].get_image_size()[0],0])
      plt.title(" %d matches, r.m.s.d. %5.2f pixels"%(len(correction_vectors_provisional),math.sqrt(flex.mean(c_v_p_flex.dot(c_v_p_flex)))))
      plt.axes().set_aspect("equal")
      self.show_figure(plt,fig,"map")
      plt.close()

    indexed_pairs = indexed_pairs_provisional
    correction_vectors = correction_vectors_provisional
    ########### skip outlier rejection for this derived class

    ### However must retain the ability to write out correction vectiors.
    if True: # at Aaron's request; test later
      correction_lengths = flex.double([v.length() for v in correction_vectors_provisional])
      clorder = flex.sort_permutation(correction_lengths)
      sorted_cl = correction_lengths.select(clorder)
      indexed_pairs = []
      correction_vectors = []
      self.correction_vectors = []
      for icand in xrange(len(sorted_cl)):
        # somewhat arbitrary sigma = 1.0 cutoff for outliers
        indexed_pairs.append(indexed_pairs_provisional[clorder[icand]])
        correction_vectors.append(correction_vectors_provisional[clorder[icand]])
        if cache_refinement_spots:
          self.spotfinder.images[self.frame_numbers[self.image_number]]["refinement_spots"].append(
          spots[reflections[indexed_pairs[-1]["spot"]]['spotfinder_lookup']])
        if kwargs.get("verbose_cv")==True:
            print "CV OBSCENTER %7.2f %7.2f REFINEDCENTER %7.2f %7.2f"%(
              float(self.inputpd["size1"])/2.,float(self.inputpd["size2"])/2.,
              self.inputai.xbeam()/pxlsz[0], self.inputai.ybeam()/pxlsz[1]),
            print "OBSSPOT %7.2f %7.2f PREDSPOT %7.2f %7.2f"%(
              reflections[indexed_pairs[-1]["spot"]]['xyzobs.px.value'][0],
              reflections[indexed_pairs[-1]["spot"]]['xyzobs.px.value'][1],
              self.predicted[indexed_pairs[-1]["pred"]][0]/pxlsz[0],
              self.predicted[indexed_pairs[-1]["pred"]][1]/pxlsz[1]),
            the_hkl = self.hkllist[indexed_pairs[-1]["pred"]]
            print "HKL %4d %4d %4d"%the_hkl,"%2d"%self.setting_id,
            radial, azimuthal = spots[indexed_pairs[-1]["spot"]].get_radial_and_azimuthal_size(
              self.inputai.xbeam()/pxlsz[0], self.inputai.ybeam()/pxlsz[1])
            print "RADIALpx %5.3f AZIMUTpx %5.3f"%(radial,azimuthal)

        # Store a list of correction vectors in self.
        radial, azimuthal = spots[indexed_pairs[-1]['spot']].get_radial_and_azimuthal_size(
          self.inputai.xbeam()/pxlsz[0], self.inputai.ybeam()/pxlsz[1])
        self.correction_vectors.append(
          dict(obscenter=(float(self.inputpd['size1']) / 2,
                          float(self.inputpd['size2']) / 2),
               refinedcenter=(self.inputai.xbeam() / pxlsz[0],
                              self.inputai.ybeam() / pxlsz[1]),
               obsspot=(reflections[indexed_pairs[-1]['spot']]['xyzobs.px.value'][0],
                        reflections[indexed_pairs[-1]['spot']]['xyzobs.px.value'][1]),
               predspot=(self.predicted[indexed_pairs[-1]['pred']][0] / pxlsz[0],
                         self.predicted[indexed_pairs[-1]['pred']][1] / pxlsz[1]),
               hkl=(self.hkllist[indexed_pairs[-1]['pred']][0],
                    self.hkllist[indexed_pairs[-1]['pred']][1],
                    self.hkllist[indexed_pairs[-1]['pred']][2]),
               setting_id=self.setting_id,
               radial=radial,
               azimuthal=azimuthal))


    self.inputpd["symmetry"] = c_symmetry
    self.inputpd["symmetry"].show_summary(prefix="SETTING ")


    if self.horizons_phil.integration.model == "user_supplied":
      # Not certain of whether the reentrant_* dictionary keys create a memory leak
      if kwargs.get("user-reentrant",None)==None:
        kwargs["reentrant_experiments"] = experiments
        kwargs["reentrant_reflections"] = reflections
        from cxi_user import post_outlier_rejection
        self.indexed_pairs = indexed_pairs
        self.spots = spots
        post_outlier_rejection(self,image_number,cb_op_to_primitive,self.horizons_phil,kwargs)
        return
    ########### finished with user-supplied code


    correction_lengths=flex.double([v.length() for v in correction_vectors])

    self.r_residual = pxlsz[0]*flex.mean(correction_lengths)

    #assert len(indexed_pairs)>NEAR # must have enough indexed spots
    if (len(indexed_pairs) <= NEAR):
      raise Sorry("Not enough indexed spots, only found %d, need %d" % (len(indexed_pairs), NEAR))

    reference = flex.double()
    for item in indexed_pairs:
      reference.append(spots[item["spot"]].ctr_mass_x())
      reference.append(spots[item["spot"]].ctr_mass_y())

    PS_adapt = AnnAdaptor(data=reference,dim=2,k=NEAR)
    PS_adapt.query(query)

    self.BSmasks = []
    # do not use null: self.null_correction_mapping( predicted=self.predicted,
    self.positional_correction_mapping( predicted=self.predicted,
                                        correction_vectors = correction_vectors,
                                        PS_adapt = PS_adapt,
                                        IS_adapt = IS_adapt,
                                        spots = spots)

    # which spots are close enough to interfere with background?
    MAXOVER=6
    OS_adapt = AnnAdaptor(data=query,dim=2,k=MAXOVER) #six near nbrs
    OS_adapt.query(query)
    if self.mask_focus[image_number] is None:
      raise Sorry("No observed/predicted spot agreement; no Spotfinder masks; skip integration")
    nbr_cutoff = 2.0* max(self.mask_focus[image_number])
    FRAME = int(nbr_cutoff/2)
    #print "The overlap cutoff is %d pixels"%nbr_cutoff
    nbr_cutoff_sq = nbr_cutoff * nbr_cutoff

    #print "Optimized C++ section...",
    self.set_frame(FRAME)
    self.set_background_factor(kwargs["background_factor"])
    self.set_nbr_cutoff_sq(nbr_cutoff_sq)
    self.set_guard_width_sq(self.horizons_phil.integration.guard_width_sq)
    self.set_detector_gain(self.horizons_phil.integration.detector_gain)
    flex_sorted = flex.int()
    for item in self.sorted:
      flex_sorted.append(item[0]);flex_sorted.append(item[1]);

    if self.horizons_phil.integration.mask_pixel_value is not None:
      self.set_mask_pixel_val(self.horizons_phil.integration.mask_pixel_value)

    image_obj = self.imagefiles.imageindex(self.frame_numbers[self.image_number])
    image_obj.read()
    rawdata = image_obj.linearintdata # assume image #1

    if self.inputai.active_areas != None:
      self.detector_xy_draft = self.safe_background( rawdata=rawdata,
                          predicted=self.predicted,
                          OS_adapt=OS_adapt,
                          sorted=flex_sorted,
                          tiles=self.inputai.active_areas.IT,
                          tile_id=self.inputai.active_areas.tile_id);
    else:
      self.detector_xy_draft = self.safe_background( rawdata=rawdata,
                          predicted=self.predicted,
                          OS_adapt=OS_adapt,
                          sorted=flex_sorted);
    for i in xrange(len(self.predicted)): # loop over predicteds
      B_S_mask = {}
      keys = self.get_bsmask(i)
      for k in xrange(0,len(keys),2):
        B_S_mask[(keys[k],keys[k+1])]=True
      self.BSmasks.append(B_S_mask)
    #print "Done"
    return
Пример #38
0
def connected_components(miller_array: cctbx.miller.array, ) -> [{}]:
    """
    Identify connected regions of missing reflections in the asymmetric unit.

    This is achieved by first generating the complete set of possible miller indices,
    then performing connected components analysis on a graph of nearest neighbours in
    the list of missing reflections.

    Args:
        miller_array:  The input list of reflections.

    Returns:
        The list of miller sets for each connected region of missing reflections. The
        first item in the list will be the complete set of all possible miller indices.
    """

    # Map to primitive setting for centred cells, otherwise true missing reflections
    # won't be identified as connected as a result of being separated by systematically
    # absent reflections.
    cb_op_to_primitive = miller_array.change_of_basis_op_to_primitive_setting()
    miller_array = miller_array.change_basis(cb_op_to_primitive)

    # First generate the missing_set of reflections. We want the full sphere of missing
    # reflections to allow us to find connected regions that cross the boundary of the
    # asu.
    unique = miller_array.unique_under_symmetry().map_to_asu()
    unique = unique.generate_bijvoet_mates()
    complete_set = unique.complete_set()
    missing_set = complete_set.lone_set(unique)
    missing_set = missing_set.expand_to_p1().customized_copy(
        crystal_symmetry=missing_set.crystal_symmetry())

    if missing_set.size() == 0:
        return complete_set, []

    # Now find the nearest neighbours.
    mi = missing_set.indices().as_vec3_double().as_double()
    k = 6
    ann = AnnAdaptor(data=mi, dim=3, k=k)
    ann.query(mi)

    # Construct the graph of connected missing reflections
    g = graph.adjacency_list(
        graph_type="undirected",
        vertex_type="vector",
        edge_type="set",
    )
    distance_cutoff = 2**0.5
    for i in range(missing_set.size()):
        ik = i * k
        for i_ann in range(k):
            if ann.distances[ik + i_ann] <= distance_cutoff:
                j = ann.nn[ik + i_ann]
                g.add_edge(i, j)

    # Now do the connected components analysis, filtering out lone missing reflections
    components = [c for c in cca.connected_components(graph=g) if len(c) > 1]

    # Determine the unique miller indices for each component within the asu
    unique_mi = []
    unique_ms = []
    for i, c in enumerate(components):
        ms = (missing_set.select(flex.size_t(list(c))).customized_copy(
            crystal_symmetry=miller_array).as_non_anomalous_set().map_to_asu())
        ms = ms.unique_under_symmetry()
        mi = set(ms.indices())
        if mi not in unique_mi:
            unique_ms.append(ms)
            unique_mi.append(mi)

    # Sort connected regions by size
    unique_ms = sorted(unique_ms, key=lambda ms: ms.size(), reverse=True)

    # Map indices back to input setting
    cb_op_primitive_inp = cb_op_to_primitive.inverse()
    return (
        unique.as_non_anomalous_set().complete_set().change_basis(
            cb_op_primitive_inp),
        [ms.change_basis(cb_op_primitive_inp) for ms in unique_ms],
    )
Пример #39
0
  def __init__(self, reflections, step_size=45, tolerance=1.5,
               max_height_fraction=0.25, percentile=0.05,
               histogram_binning='linear'):
    self.tolerance = tolerance # Margin of error for max unit cell estimate
    from scitbx.array_family import flex
    NEAR = 10
    self.NNBIN = 5 # target number of neighbors per histogram bin
    self.histogram_binning = histogram_binning

    direct = flex.double()

    if 'entering' in reflections:
      entering_flags = reflections['entering']
    else:
      entering_flags = flex.bool(reflections.size(), True)
    rs_vectors = reflections['rlp']
    phi_deg = reflections['xyzobs.mm.value'].parts()[2] * (180/math.pi)

    d_spacings = flex.double()
    # nearest neighbor analysis
    from annlib_ext import AnnAdaptor
    for imageset_id in range(flex.max(reflections['imageset_id'])+1):
      sel = reflections['imageset_id'] == imageset_id
      if sel.count(True) == 0:
        continue
      phi_min = flex.min(phi_deg.select(sel))
      phi_max = flex.max(phi_deg.select(sel))
      d_phi = phi_max - phi_min
      n_steps = max(int(math.ceil(d_phi / step_size)), 1)

      for n in range(n_steps):
        sel &= (phi_deg >= (phi_min+n*step_size)) & (phi_deg < (phi_min+(n+1)*step_size))

        for entering in (True, False):
          sel  &= entering_flags == entering
          if sel.count(True) == 0:
            continue

          query = flex.double()
          query.extend(rs_vectors.select(sel).as_double())

          if query.size() == 0:
            continue

          IS_adapt = AnnAdaptor(data=query,dim=3,k=1)
          IS_adapt.query(query)

          direct.extend(1/flex.sqrt(IS_adapt.distances))
          d_spacings.extend(1/rs_vectors.norms())

    assert len(direct)>NEAR, (
      "Too few spots (%d) for nearest neighbour analysis." %len(direct))

    perm = flex.sort_permutation(direct)
    direct = direct.select(perm)
    d_spacings = d_spacings.select(perm)

    # reject top 1% of longest distances to hopefully get rid of any outliers
    n = int(math.floor(0.99*len(direct)))
    direct = direct[:n]
    d_spacings = d_spacings[:n]

    # determine the most probable nearest neighbor distance (direct space)
    if self.histogram_binning == 'log':
      hst = flex.histogram(
        flex.log10(direct), n_slots=int(len(direct)/self.NNBIN))
    else:
      hst = flex.histogram(direct, n_slots=int(len(direct)/self.NNBIN))
    centers = hst.slot_centers()
    if self.histogram_binning == 'log':
      self.slot_start = flex.double(
        [10**s for s in hst.slot_centers() - 0.5 * hst.slot_width()])
      self.slot_end = flex.double(
        [10**s for s in hst.slot_centers() + 0.5 * hst.slot_width()])
      self.slot_width = self.slot_end - self.slot_start
    else:
      self.slot_start = hst.slot_centers() - 0.5 * hst.slot_width()
      self.slot_end = hst.slot_centers() + 0.5 * hst.slot_width()
      self.slot_width = hst.slot_width()
    self.relative_frequency = hst.slots().as_double()/self.slot_width
    highest_bin_height = flex.max(self.relative_frequency)

    if False:  # to print out the histogramming analysis
      smin, smax = flex.min(direct), flex.max(direct)
      stats = flex.mean_and_variance(direct)
      import sys
      out = sys.stdout
      print >> out, "     range:     %6.2f - %.2f" % (smin, smax)
      print >> out, "     mean:      %6.2f +/- %6.2f on N = %d" % (
        stats.mean(), stats.unweighted_sample_standard_deviation(), direct.size())
      hst.show(f=out, prefix="    ", format_cutoffs="%6.2f")
      print >> out, ""

    # choose a max cell based on bins above a given fraction of the highest bin height
    # given multiple
    isel = (self.relative_frequency.as_double() > (
      max_height_fraction * highest_bin_height)).iselection()
    self.max_cell = (
      self.tolerance * self.slot_end[int(flex.max(isel.as_double()))])

    # determine the 5th-percentile direct-space distance
    perm = flex.sort_permutation(direct, reverse=True)
    self.percentile = direct[perm[int(percentile * len(direct))]]

    self.reciprocal_lattice_vectors = rs_vectors
    self.d_spacings = d_spacings
    self.direct = direct
    self.histogram = hst
Пример #40
0
  def integration_concept(self,image_number=0,cb_op_to_primitive=None,verbose=False,**kwargs):
    self.image_number = image_number
    NEAR = 10
    pxlsz = self.pixel_size
    self.get_predictions_accounting_for_centering(cb_op_to_primitive,**kwargs)
    FWMOSAICITY = self.inputai.getMosaicity()
    DOMAIN_SZ_ANG = kwargs.get("domain_size_ang",  self.__dict__.get("actual",0)  )
    refineflag = {True:0,False:1}[kwargs.get("domain_size_ang",0)==0]
    self.inputpd["symmetry"].show_summary(prefix="EXCURSION%1d REPORT FWMOS= %6.4f DOMAIN= %6.1f "%(refineflag,FWMOSAICITY,DOMAIN_SZ_ANG))
    from annlib_ext import AnnAdaptor
    self.cell = self.inputai.getOrientation().unit_cell()
    query = flex.double()
    for pred in self.predicted: # predicted spot coord in pixels
      query.append(pred[0]/pxlsz)
      query.append(pred[1]/pxlsz)
    self.reserve_hkllist_for_signal_search = self.hkllist

    reference = flex.double()
    spots = self.get_observations_with_outlier_removal()

    assert len(spots)>NEAR# Can't do spot/pred matching with too few spots
    for spot in spots:
      reference.append(spot.ctr_mass_x())
      reference.append(spot.ctr_mass_y())

    IS_adapt = AnnAdaptor(data=reference,dim=2,k=NEAR)
    IS_adapt.query(query)
    print "Calculate correction vectors for %d observations & %d predictions"%(len(spots),len(self.predicted))
    indexed_pairs_provisional = []
    correction_vectors_provisional = []
    c_v_p_flex = flex.vec3_double()
    idx_cutoff = float(min(self.mask_focus[image_number]))
    if verbose:
      print "idx_cutoff distance in pixels",idx_cutoff
    if not self.horizons_phil.integration.enable_one_to_one_safeguard:
     # legacy code, no safeguard against many-to-one predicted-to-observation mapping
     for i in xrange(len(self.predicted)): # loop over predicteds
      #for n in xrange(NEAR): # loop over near spotfinder spots
      for n in xrange(1): # only consider the nearest spotfinder spot
        Match = dict(spot=IS_adapt.nn[i*NEAR+n],pred=i)
        if n==0 and math.sqrt(IS_adapt.distances[i*NEAR+n]) < idx_cutoff:
          indexed_pairs_provisional.append(Match)

          vector = matrix.col(
            [spots[Match["spot"]].ctr_mass_x() - self.predicted[Match["pred"]][0]/pxlsz,
             spots[Match["spot"]].ctr_mass_y() - self.predicted[Match["pred"]][1]/pxlsz])
          correction_vectors_provisional.append(vector)
          c_v_p_flex.append((vector[0],vector[1],0.))
    else:
      one_to_one = {}
      for i in xrange(len(self.predicted)): # loop over predicteds
        annresultidx = i*NEAR
        obsidx = IS_adapt.nn[annresultidx]
        this_distancesq = IS_adapt.distances[annresultidx]
        if not one_to_one.has_key(obsidx) or \
           this_distancesq < one_to_one[obsidx]["distancesq"]:
           if math.sqrt(this_distancesq) < idx_cutoff:
             one_to_one[obsidx] = dict(spot=obsidx,pred=i,distancesq=this_distancesq)
      for key,value in one_to_one.items():
        indexed_pairs_provisional.append(value)
        vector = matrix.col(
            [spots[value["spot"]].ctr_mass_x() - self.predicted[value["pred"]][0]/pxlsz,
             spots[value["spot"]].ctr_mass_y() - self.predicted[value["pred"]][1]/pxlsz])
        correction_vectors_provisional.append(vector)
        c_v_p_flex.append((vector[0],vector[1],0.))

    print "... %d provisional matches"%len(correction_vectors_provisional),
    print "r.m.s.d. in pixels: %5.2f"%(math.sqrt(flex.mean(c_v_p_flex.dot(c_v_p_flex))))

    if self.horizons_phil.integration.enable_residual_scatter:
      from matplotlib import pyplot as plt
      fig = plt.figure()
      for cv in correction_vectors_provisional:
        plt.plot([cv[1]],[-cv[0]],"b.")
      plt.title(" %d matches, r.m.s.d. %5.2f pixels"%(len(correction_vectors_provisional),math.sqrt(flex.mean(c_v_p_flex.dot(c_v_p_flex)))))
      plt.axes().set_aspect("equal")
      self.show_figure(plt,fig,"res")
      plt.close()

    if self.horizons_phil.integration.enable_residual_map:
      from matplotlib import pyplot as plt
      fig = plt.figure()
      for match,cv in zip(indexed_pairs_provisional,correction_vectors_provisional):
        plt.plot([spots[match["spot"]].ctr_mass_y()],[-spots[match["spot"]].ctr_mass_x()],"r.")
        plt.plot([self.predicted[match["pred"]][1]/pxlsz],[-self.predicted[match["pred"]][0]/pxlsz],"g.")
        plt.plot([spots[match["spot"]].ctr_mass_y(), spots[match["spot"]].ctr_mass_y() + 10.*cv[1]],
                 [-spots[match["spot"]].ctr_mass_x(), -spots[match["spot"]].ctr_mass_x() - 10.*cv[0]],'b-')
      plt.xlim([0,float(self.inputpd["size2"])])
      plt.ylim([-float(self.inputpd["size1"]),0])
      plt.title(" %d matches, r.m.s.d. %5.2f pixels"%(len(correction_vectors_provisional),math.sqrt(flex.mean(c_v_p_flex.dot(c_v_p_flex)))))
      plt.axes().set_aspect("equal")
      self.show_figure(plt,fig,"map")
      plt.close()
    # insert code here to remove correction length outliers...
    # they are causing terrible
    # problems for finding legitimate correction vectors (print out the list)
    # also remove outliers for the purpose of reporting RMS
    outlier_rejection = True
    cache_refinement_spots = getattr(slip_callbacks.slip_callback,"requires_refinement_spots",False)
    if outlier_rejection:
      correction_lengths = flex.double([v.length() for v in correction_vectors_provisional])
      clorder = flex.sort_permutation(correction_lengths)
      sorted_cl = correction_lengths.select(clorder)

      ACCEPTABLE_LIMIT = 2
      limit = int(0.33 * len(sorted_cl)) # best 1/3 of data are assumed to be correctly modeled.
      if (limit <= ACCEPTABLE_LIMIT):
        raise Sorry("Not enough indexed spots to reject outliers; have %d need >%d" % (limit, ACCEPTABLE_LIMIT))

      y_data = flex.double(len(sorted_cl))
      for i in xrange(len(y_data)):
        y_data[i] = float(i)/float(len(y_data))

      # ideas are explained in Sauter & Poon (2010) J Appl Cryst 43, 611-616.
      from rstbx.outlier_spots.fit_distribution import fit_cdf,rayleigh
      fitted_rayleigh = fit_cdf(x_data = sorted_cl[0:limit],
                                y_data = y_data[0:limit],
                                distribution=rayleigh)

      inv_cdf = [fitted_rayleigh.distribution.inv_cdf(cdf) for cdf in y_data]

      #print "SORTED LIST OF ",len(sorted_cl), "with sigma",fitted_rayleigh.distribution.sigma
      indexed_pairs = []
      correction_vectors = []
      self.correction_vectors = []
      for icand in xrange(len(sorted_cl)):
        # somewhat arbitrary sigma = 1.0 cutoff for outliers
        if (sorted_cl[icand]-inv_cdf[icand])/fitted_rayleigh.distribution.sigma > 1.0:
          break
        indexed_pairs.append(indexed_pairs_provisional[clorder[icand]])
        correction_vectors.append(correction_vectors_provisional[clorder[icand]])
        if cache_refinement_spots:
          self.spotfinder.images[self.frame_numbers[self.image_number]]["refinement_spots"].append(
          spots[indexed_pairs[-1]["spot"]])
        if kwargs.get("verbose_cv")==True:
            print "CV OBSCENTER %7.2f %7.2f REFINEDCENTER %7.2f %7.2f"%(
              float(self.inputpd["size1"])/2.,float(self.inputpd["size2"])/2.,
              self.inputai.xbeam()/pxlsz, self.inputai.ybeam()/pxlsz),
            print "OBSSPOT %7.2f %7.2f PREDSPOT %7.2f %7.2f"%(
              spots[indexed_pairs[-1]["spot"]].ctr_mass_x(),
              spots[indexed_pairs[-1]["spot"]].ctr_mass_y(),
              self.predicted[indexed_pairs[-1]["pred"]][0]/pxlsz,
              self.predicted[indexed_pairs[-1]["pred"]][1]/pxlsz),
            the_hkl = self.hkllist[indexed_pairs[-1]["pred"]]
            print "HKL %4d %4d %4d"%the_hkl,"%2d"%self.setting_id,
            radial, azimuthal = spots[indexed_pairs[-1]["spot"]].get_radial_and_azimuthal_size(
              self.inputai.xbeam()/pxlsz, self.inputai.ybeam()/pxlsz)
            print "RADIALpx %5.3f AZIMUTpx %5.3f"%(radial,azimuthal)

        # Store a list of correction vectors in self.
        radial, azimuthal = spots[indexed_pairs[-1]['spot']].get_radial_and_azimuthal_size(
          self.inputai.xbeam()/pxlsz, self.inputai.ybeam()/pxlsz)
        self.correction_vectors.append(
          dict(obscenter=(float(self.inputpd['size1']) / 2,
                          float(self.inputpd['size2']) / 2),
               refinedcenter=(self.inputai.xbeam() / pxlsz,
                              self.inputai.ybeam() / pxlsz),
               obsspot=(spots[indexed_pairs[-1]['spot']].ctr_mass_x(),
                        spots[indexed_pairs[-1]['spot']].ctr_mass_y()),
               predspot=(self.predicted[indexed_pairs[-1]['pred']][0] / pxlsz,
                         self.predicted[indexed_pairs[-1]['pred']][1] / pxlsz),
               hkl=(self.hkllist[indexed_pairs[-1]['pred']][0],
                    self.hkllist[indexed_pairs[-1]['pred']][1],
                    self.hkllist[indexed_pairs[-1]['pred']][2]),
               setting_id=self.setting_id,
               radial=radial,
               azimuthal=azimuthal))

      print "After outlier rejection %d indexed spotfinder spots remain."%len(indexed_pairs)
      if False:
        rayleigh_cdf = [
          fitted_rayleigh.distribution.cdf(x=sorted_cl[c]) for c in xrange(len(sorted_cl))]
        from matplotlib import pyplot as plt
        plt.plot(sorted_cl,y_data,"r+")
        #plt.plot(sorted_cl,rayleigh_cdf,"g.")
        plt.plot(inv_cdf,y_data,"b.")
        plt.show()
    else:
      indexed_pairs = indexed_pairs_provisional
      correction_vectors = correction_vectors_provisional
    ########### finished with outlier rejection

    self.inputpd["symmetry"].show_summary(prefix="SETTING ")

    is_triclinic = (self.setting_id==1)
    if is_triclinic:
      self.triclinic_pairs = [ dict(pred=self.hkllist[a["pred"]],spot=a["spot"])
        for a in indexed_pairs ]

    if self.horizons_phil.integration.model == "user_supplied":
      if kwargs.get("user-reentrant",None)==None:
        from cxi_user import post_outlier_rejection
        self.indexed_pairs = indexed_pairs
        self.spots = spots
        post_outlier_rejection(self,image_number,cb_op_to_primitive,self.horizons_phil,kwargs)
        return

    ########### finished with user-supplied code

    if self.horizons_phil.integration.spot_shape_verbose:
        from rstbx.new_horizons.spot_shape import spot_shape_verbose
        spot_shape_verbose(rawdata = self.imagefiles.images[self.image_number].linearintdata,
           beam_center_pix = matrix.col((self.inputai.xbeam()/pxlsz, self.inputai.ybeam()/pxlsz)),
           indexed_pairs = indexed_pairs,
           spotfinder_observations = spots,
           distance_mm = self.inputai.distance(),
           mm_per_pixel = pxlsz,
           hkllist = self.hkllist,
           unit_cell = self.cell,
           wavelength_ang = self.inputai.wavelength
        )

    #Other checks to be implemented (future):
    # spot is within active area of detector on a circular detector such as the Mar IP
    # integration masks do not overlap; or deconvolute

    correction_lengths=flex.double([v.length() for v in correction_vectors])
    if verbose:
      print "average correction %5.2f over %d vectors"%(flex.mean(correction_lengths),
      len(correction_lengths)),
      print "or %5.2f mm."%(pxlsz*flex.mean(correction_lengths))
    self.r_residual = pxlsz*flex.mean(correction_lengths)

    #assert len(indexed_pairs)>NEAR # must have enough indexed spots
    if (len(indexed_pairs) <= NEAR):
      raise Sorry("Not enough indexed spots, only found %d, need %d" % (len(indexed_pairs), NEAR))

    reference = flex.double()
    for item in indexed_pairs:
      reference.append(spots[item["spot"]].ctr_mass_x())
      reference.append(spots[item["spot"]].ctr_mass_y())

    PS_adapt = AnnAdaptor(data=reference,dim=2,k=NEAR)
    PS_adapt.query(query)

    self.BSmasks = []
    #self.null_correction_mapping( predicted=self.predicted,
    #                                    correction_vectors = correction_vectors,
    #                                    IS_adapt = IS_adapt,
    #                                    spots = spots)
    self.positional_correction_mapping( predicted=self.predicted,
                                        correction_vectors = correction_vectors,
                                        PS_adapt = PS_adapt,
                                        IS_adapt = IS_adapt,
                                        spots = spots)

    # which spots are close enough to interfere with background?
    MAXOVER=6
    OS_adapt = AnnAdaptor(data=query,dim=2,k=MAXOVER) #six near nbrs
    OS_adapt.query(query)
    if self.mask_focus[image_number] is None:
      raise Sorry("No observed/predicted spot agreement; no Spotfinder masks; skip integration")
    nbr_cutoff = 2.0* max(self.mask_focus[image_number])
    FRAME = int(nbr_cutoff/2)
    #print "The overlap cutoff is %d pixels"%nbr_cutoff
    nbr_cutoff_sq = nbr_cutoff * nbr_cutoff

    #print "Optimized C++ section...",
    self.set_frame(FRAME)
    self.set_background_factor(kwargs["background_factor"])
    self.set_nbr_cutoff_sq(nbr_cutoff_sq)
    self.set_guard_width_sq(self.horizons_phil.integration.guard_width_sq)
    self.set_detector_gain(self.horizons_phil.integration.detector_gain)
    flex_sorted = flex.int()
    for item in self.sorted:
      flex_sorted.append(item[0]);flex_sorted.append(item[1]);

    if self.horizons_phil.integration.mask_pixel_value is not None:
      self.set_mask_pixel_val(self.horizons_phil.integration.mask_pixel_value)

    image_obj = self.imagefiles.imageindex(self.frame_numbers[self.image_number])
    image_obj.read()
    rawdata = image_obj.linearintdata # assume image #1

    if self.inputai.active_areas != None:
      self.detector_xy_draft = self.safe_background( rawdata=rawdata,
                          predicted=self.predicted,
                          OS_adapt=OS_adapt,
                          sorted=flex_sorted,
                          tiles=self.inputai.active_areas.IT,
                          tile_id=self.inputai.active_areas.tile_id);
    else:
      self.detector_xy_draft = self.safe_background( rawdata=rawdata,
                          predicted=self.predicted,
                          OS_adapt=OS_adapt,
                          sorted=flex_sorted);
    for i in xrange(len(self.predicted)): # loop over predicteds
      B_S_mask = {}
      keys = self.get_bsmask(i)
      for k in xrange(0,len(keys),2):
        B_S_mask[(keys[k],keys[k+1])]=True
      self.BSmasks.append(B_S_mask)
    #print "Done"
    return