def map_points_to_reciprocal_space(self):
    goniometer = self.imagesets[0].get_goniometer()
    if self.goniometer_orig is not None and not self.settings.reverse_phi:
      self.imagesets[0].set_goniometer(self.goniometer_orig)
      self.goniometer_orig = None
    elif goniometer is not None and self.settings.reverse_phi:
      self.goniometer_orig = copy.deepcopy(goniometer)
      goniometer.set_rotation_axis([-i for i in goniometer.get_rotation_axis()])
    from dials.algorithms.indexing import indexer

    from dials.array_family import flex
    reflections = flex.reflection_table()
    for i, imageset in enumerate(self.imagesets):
      if 'imageset_id' in self.reflections_input:
        sel = (self.reflections_input['imageset_id'] == i)
      else:
        sel = (self.reflections_input['id'] == i)
      if isinstance(self.reflections_input['id'], flex.size_t):
        self.reflections_input['id'] = self.reflections_input['id'].as_int()
      refl = indexer.indexer_base.map_spots_pixel_to_mm_rad(
        self.reflections_input.select(sel),
        imageset.get_detector(), imageset.get_scan())

      indexer.indexer_base.map_centroids_to_reciprocal_space(
        refl, imageset.get_detector(), imageset.get_beam(),
        imageset.get_goniometer())
      reflections.extend(refl)
      self.reflections = reflections
예제 #2
0
def generate_reflections(detector, beam, scan, experiment, num):
    from random import randint, seed
    from scitbx import matrix
    from dials.array_family import flex
    from dials.algorithms.shoebox import MaskCode

    seed(0)
    assert len(detector) == 1
    beam_vector = flex.vec3_double(num)
    xyzcal_px = flex.vec3_double(num)
    xyzcal_mm = flex.vec3_double(num)
    panel = flex.size_t(num)
    s0_length = matrix.col(beam.get_s0()).length()
    for i in range(num):
        x = randint(0, 2000)
        y = randint(0, 2000)
        z = randint(0, 8)
        s1 = detector[0].get_pixel_lab_coord((x, y))
        s1 = matrix.col(s1).normalize() * s0_length
        phi = scan.get_angle_from_array_index(z, deg=False)
        beam_vector[i] = s1
        xyzcal_px[i] = (x, y, z)
        (x, y) = detector[0].pixel_to_millimeter((x, y))
        xyzcal_mm[i] = (x, y, phi)
        panel[i] = 0

    sigma_b = experiment[0].beam.get_sigma_divergence(deg=False)
    try:
        sigma_m = experiment[0].crystal.get_mosaicity(deg=False)
    except AttributeError:
        sigma_m = 0

    rlist = flex.reflection_table()
    rlist["id"] = flex.int(len(beam_vector), 0)
    rlist["s1"] = beam_vector
    rlist["panel"] = panel
    rlist["xyzcal.px"] = xyzcal_px
    rlist["xyzcal.mm"] = xyzcal_mm
    rlist["bbox"] = rlist.compute_bbox(experiment)
    index = []
    image_size = experiment[0].detector[0].get_image_size()
    array_range = experiment[0].scan.get_array_range()
    bbox = rlist["bbox"]
    for i in range(len(rlist)):
        x0, x1, y0, y1, z0, z1 = bbox[i]
        if (
            x0 < 0
            or x1 > image_size[0]
            or y0 < 0
            or y1 > image_size[1]
            or z0 < array_range[0]
            or z1 > array_range[1]
        ):
            index.append(i)
    rlist.del_selected(flex.size_t(index))
    rlist["shoebox"] = flex.shoebox(rlist["panel"], rlist["bbox"])
    rlist["shoebox"].allocate_with_value(MaskCode.Valid)
    return rlist
예제 #3
0
  def index_with_known_orientation(self, datablock, reflections):
    ''' Copy of the index function from stills_process to force IOTA to use stills_indexer during known_orientation '''
    from dials.algorithms.indexing.stills_indexer import stills_indexer
    from time import time
    import copy
    st = time()

    imagesets = datablock.extract_imagesets()

    params = copy.deepcopy(self.params)
    # don't do scan-varying refinement during indexing
    params.refinement.parameterisation.scan_varying = False

    if hasattr(self, 'known_crystal_models'):
      known_crystal_models = self.known_crystal_models
    else:
      known_crystal_models = None
    if params.indexing.stills.method_list is None:
      idxr = stills_indexer.from_parameters(
        reflections, imagesets, known_crystal_models=known_crystal_models,
        params=params)
      idxr.index()
    else:
      indexing_error = None
      for method in params.indexing.stills.method_list:
        params.indexing.method = method
        try:
          idxr = stills_indexer.from_parameters(
            reflections, imagesets,
            params=params)
          idxr.index()
        except Exception as e:
          logger.info("Couldn't index using method %s"%method)
          if indexing_error is None:
            if e is None:
              e = Exception("Couldn't index using method %s"%method)
            indexing_error = e
        else:
          indexing_error = None
          break
      if indexing_error is not None:
        raise indexing_error

    indexed = idxr.refined_reflections
    experiments = idxr.refined_experiments

    if known_crystal_models is not None:
      from dials.array_family import flex
      filtered = flex.reflection_table()
      for idx in set(indexed['miller_index']):
        sel = indexed['miller_index'] == idx
        if sel.count(True) == 1:
          filtered.extend(indexed.select(sel))
      print("Filtered duplicate reflections, %d out of %d remaining"%(len(filtered),len(indexed)))
      indexed = filtered

    return experiments, indexed
예제 #4
0
  def generate_reflections(self, num):
    from random import randint, seed
    from scitbx import matrix
    from dials.array_family import flex
    from dials.algorithms.shoebox import MaskCode
    seed(0)
    assert(len(self.detector) == 1)
    beam_vector = flex.vec3_double(num)
    xyzcal_px = flex.vec3_double(num)
    xyzcal_mm = flex.vec3_double(num)
    panel = flex.size_t(num)
    s0_length = matrix.col(self.beam.get_s0()).length()
    for i in range(num):
      x = randint(0, 2000)
      y = randint(0, 2000)
      z = randint(0, 8)
      s1 = self.detector[0].get_pixel_lab_coord((x, y))
      s1 = matrix.col(s1).normalize() * s0_length
      phi = self.scan.get_angle_from_array_index(z, deg=False)
      beam_vector[i] = s1
      xyzcal_px[i] = (x, y, z)
      (x, y)  = self.detector[0].pixel_to_millimeter((x, y))
      xyzcal_mm[i] = (x, y, phi)
      panel[i] = 0

    sigma_b = self.experiment[0].beam.get_sigma_divergence(deg=False)
    sigma_m = self.experiment[0].crystal.get_mosaicity(deg=False)

    rlist = flex.reflection_table()
    rlist['id'] = flex.int(len(beam_vector), 0)
    rlist['s1'] = beam_vector
    rlist['panel'] = panel
    rlist['xyzcal.px'] = xyzcal_px
    rlist['xyzcal.mm'] = xyzcal_mm
    rlist['bbox'] = rlist.compute_bbox(self.experiment)
    index = []
    image_size = self.experiment[0].detector[0].get_image_size()
    array_range = self.experiment[0].scan.get_array_range()
    bbox = rlist['bbox']
    for i in range(len(rlist)):
      x0, x1, y0, y1, z0, z1 = bbox[i]
      if (x0 < 0 or x1 > image_size[0] or
          y0 < 0 or y1 > image_size[1] or
          z0 < array_range[0] or z1 > array_range[1]):
        index.append(i)
    rlist.del_selected(flex.size_t(index))
    rlist['shoebox'] = flex.shoebox(
      rlist['panel'], rlist['bbox'])
    rlist['shoebox'].allocate_with_value(MaskCode.Valid)
    return rlist
예제 #5
0
    def generate_single_central_non_negative_profiles(self):
        from dials.array_family import flex
        rlist = flex.reflection_table(1)

        profile = gaussian(self.grid_size, 1000, (4, 4, 4), (1.5, 1.5, 1.5))

        x = 500
        y = 500
        z = 5
        xyz = flex.vec3_double(1)
        xyz[0] = (x, y, z)
        profiles = [profile.deep_copy()]
        rlist['xyzcal.px'] = xyz

        return rlist, profiles, profile
예제 #6
0
    def map_points_to_reciprocal_space(self):

        from dials.algorithms.indexing import indexer
        from dials.array_family import flex
        import copy

        reflections = flex.reflection_table()
        for i, imageset in enumerate(self.imagesets):
            if 'imageset_id' in self.reflections_input:
                sel = (self.reflections_input['imageset_id'] == i)
            else:
                sel = (self.reflections_input['id'] == i)
            if isinstance(self.reflections_input['id'], flex.size_t):
                self.reflections_input['id'] = self.reflections_input[
                    'id'].as_int()

            # 155 handle data from predictions *only* if that is what we have
            if 'xyzobs.px.value' in self.reflections_input:
                refl = indexer.indexer_base.map_spots_pixel_to_mm_rad(
                    self.reflections_input.select(sel),
                    imageset.get_detector(), imageset.get_scan())

                goniometer = copy.deepcopy(imageset.get_goniometer())
                if self.settings.reverse_phi:
                    goniometer.set_rotation_axis(
                        [-i for i in goniometer.get_rotation_axis()])
                indexer.indexer_base.map_centroids_to_reciprocal_space(
                    refl, imageset.get_detector(), imageset.get_beam(),
                    goniometer)

            else:
                # work on xyzcal.mm
                refl = self.reflections_input.select(sel)

                goniometer = copy.deepcopy(imageset.get_goniometer())
                if self.settings.reverse_phi:
                    goniometer.set_rotation_axis(
                        [-i for i in goniometer.get_rotation_axis()])

                indexer.indexer_base.map_centroids_to_reciprocal_space(
                    refl,
                    imageset.get_detector(),
                    imageset.get_beam(),
                    goniometer,
                    calculated=True)

            reflections.extend(refl)
            self.reflections = reflections
예제 #7
0
    def generate_identical_non_negative_profiles(self):
        from dials.array_family import flex
        from random import uniform
        rlist = flex.reflection_table(1000)

        profile = gaussian(self.grid_size, 1000, (4, 4, 4), (1.5, 1.5, 1.5))

        xyz = flex.vec3_double(1000)
        profiles = []
        for i in range(1000):
            x = uniform(0, 1000)
            y = uniform(0, 1000)
            z = uniform(0, 10)
            xyz[i] = (x, y, z)
            profiles.append(profile.deep_copy())
        rlist['xyzcal.px'] = xyz

        return rlist, profiles, profile
예제 #8
0
  def map_points_to_reciprocal_space(self):

    from dials.algorithms.indexing import indexer
    from dials.array_family import flex
    import copy

    reflections = flex.reflection_table()
    for i, imageset in enumerate(self.imagesets):
      if 'imageset_id' in self.reflections_input:
        sel = (self.reflections_input['imageset_id'] == i)
      else:
        sel = (self.reflections_input['id'] == i)
      if isinstance(self.reflections_input['id'], flex.size_t):
        self.reflections_input['id'] = self.reflections_input['id'].as_int()

      # 155 handle data from predictions *only* if that is what we have
      if 'xyzobs.px.value' in self.reflections_input:
        refl = indexer.indexer_base.map_spots_pixel_to_mm_rad(
          self.reflections_input.select(sel),
          imageset.get_detector(), imageset.get_scan())

        goniometer = copy.deepcopy(imageset.get_goniometer())
        if self.settings.reverse_phi:
          goniometer.set_rotation_axis(
            [-i for i in goniometer.get_rotation_axis()])
        indexer.indexer_base.map_centroids_to_reciprocal_space(
          refl, imageset.get_detector(), imageset.get_beam(),
          goniometer)

      else:
        # work on xyzcal.mm
        refl = self.reflections_input.select(sel)

        goniometer = copy.deepcopy(imageset.get_goniometer())
        if self.settings.reverse_phi:
          goniometer.set_rotation_axis(
            [-i for i in goniometer.get_rotation_axis()])

        indexer.indexer_base.map_centroids_to_reciprocal_space(
          refl, imageset.get_detector(), imageset.get_beam(),
          goniometer, calculated=True)

      reflections.extend(refl)
      self.reflections = reflections
예제 #9
0
def _select_reflections_for_sigma_calc(reflections, min_number_of_refl=10000):
    """Determine a subset of reflections to use for sigma_m calculation."""
    from dials.array_family import flex

    n_ref = reflections.size()
    if n_ref > min_number_of_refl:
        # ideally use well-sampled selection from refinement
        used_in_ref = reflections.get_flags(
            reflections.flags.used_in_refinement)
        n_used_in_ref = used_in_ref.count(True)
        if n_used_in_ref > min_number_of_refl:
            selected_reflections = reflections.select(used_in_ref)
            logger.debug(
                "Using %s reflections with used_in_refinement flag for sigma calculation",
                n_used_in_ref,
            )

        # handle case where used_in_refl not set/data not refined
        else:
            # more than min_no of refls, but refinement didn't use more than
            # min_no: still use the ones from refinement and 'top up'
            if n_used_in_ref:
                selected_reflections = reflections.select(used_in_ref)
                other_refls = reflections.select(~used_in_ref)
            else:
                selected_reflections = flex.reflection_table()
                other_refls = reflections
            # top up with every nth reflection needed to make up the number needed
            n_sel = selected_reflections.size()
            n_other = other_refls.size()
            step_size = int(math.floor(n_other / (min_number_of_refl - n_sel)))
            sel = flex.size_t(i for i in range(0, n_other, step_size))
            selected_reflections.extend(other_refls.select(sel))
            logger.debug(
                "Using %s reflections for sigma calculation",
                selected_reflections.size(),
            )
        return selected_reflections

    logger.debug("Using all suitable reflections for sigma calculation")
    return reflections
예제 #10
0
    def generate_systematically_offset_profiles(self):
        from dials.array_family import flex
        from random import uniform
        rlist = flex.reflection_table(1000)

        xyz = flex.vec3_double(1000)
        profiles = []
        for i in range(1000):
            x = uniform(0, 1000)
            y = uniform(0, 1000)
            z = uniform(0, 10)

            offset = -4.5 + 9 * x / 1000.0

            profile = gaussian(self.grid_size, 1000, (4 + offset, 4, 4),
                               (1.5, 1.5, 1.5))
            xyz[i] = (x, y, z)
            profiles.append(profile)

        rlist['xyzcal.px'] = xyz
        return rlist, profiles
예제 #11
0
  def run(self, flags, sweep=None, shoeboxes=None, **kwargs):
    from dials.array_family import flex
    from dials.algorithms.shoebox import MaskCode
    from dials.algorithms.background.simple import Linear2dModeller
    bg_code = MaskCode.Valid | MaskCode.BackgroundUsed
    fg_code = MaskCode.Valid | MaskCode.Foreground
    strong_code = MaskCode.Valid | MaskCode.Strong

    modeller = Linear2dModeller()
    expanded_shoeboxes = flex.shoebox()
    detector = sweep.get_detector()

    zoffset = 0
    if sweep.get_scan() is not None:
      zoffset = sweep.get_scan().get_array_range()[0]

    from libtbx.containers import OrderedDict
    class image_data_cache(object):
      def __init__(self, imageset, size=10):
        self.imageset = imageset
        self.size = size
        self._image_data = OrderedDict()

      def __getitem__(self, i):
        image_data = self._image_data.get(i)
        if image_data is None:
          image_data = self.imageset.get_raw_data(i)
          if len(self._image_data) >= self.size:
            # remove the oldest entry in the cache
            del self._image_data[self._image_data.keys()[0]]
          self._image_data[i] = image_data
        return image_data

    cache = image_data_cache(sweep)
    #cache = sweep

    # sort shoeboxes by centroid z
    frame = shoeboxes.centroid_all().position_frame()
    perm = flex.sort_permutation(frame)
    shoeboxes = shoeboxes.select(perm)
    buffer_size = 1
    bg_plus_buffer = self.background_size + buffer_size

    import time
    t0 = time.time()
    for i, shoebox in enumerate(shoeboxes):
      if not flags[perm[i]]:
        continue
      panel = detector[shoebox.panel]
      trusted_range = panel.get_trusted_range()
      max_x, max_y = panel.get_image_size()
      bbox = shoebox.bbox
      x1, x2, y1, y2, z1, z2 = bbox
      # expand the bbox with a background region around the spotfinder shoebox
      # perhaps also should use a buffer zone between the shoebox and the
      # background region
      expanded_bbox = (max(0, x1-bg_plus_buffer),
                       min(max_x, x2+bg_plus_buffer),
                       max(0, y1-bg_plus_buffer),
                       min(max_y, y2+bg_plus_buffer),
                       z1, z2)
      shoebox.bbox = expanded_bbox
    t1 = time.time()
    info("Time expand_shoebox: %s" %(t1-t0))

    rlist = flex.reflection_table()
    rlist['shoebox'] = shoeboxes
    rlist['shoebox'].allocate()
    rlist['panel'] = shoeboxes.panels()
    rlist['bbox'] = shoeboxes.bounding_boxes()

    t0 = time.time()
    rlist.extract_shoeboxes(sweep)
    t1 = time.time()

    shoeboxes = rlist['shoebox']
    shoeboxes.flatten()

    t0 = time.time()
    for i, shoebox in enumerate(shoeboxes):
      if not flags[perm[i]]: continue
      panel = detector[shoebox.panel]
      trusted_range = panel.get_trusted_range()
      max_x, max_y = panel.get_image_size()
      ex1, ex2, ey1, ey2, ez1, ez2 = shoebox.bbox
      data = shoebox.data
      mask = flex.bool(data.accessor(), False)
      for i_y, y in enumerate(range(ey1, ey2)):
        for i_x, x in enumerate(range(ex1, ex2)):
          value = data[0, i_y, i_x]
          if (y >= (ey1+buffer_size) and y < (ey2-buffer_size) and
              x >= (ex1+buffer_size) and x < (ex2-buffer_size)):
            mask[0, i_y, i_x] = False # foreground
          elif (value > trusted_range[0] and value < trusted_range[1]):
            mask[0, i_y, i_x] = True # background

      model = modeller.create(data.as_double(), mask)
      d, a, b = model.params()[:3]
      c = -1

      if abs(a) > self.gradient_cutoff or abs(b) > self.gradient_cutoff:
        flags[perm[i]] = False

      # FIXME should this commented out section be removed?
      #if abs(a) < self.gradient_cutoff and abs(b) < self.gradient_cutoff:
        #flags[i] = False

      #if x2-x1 > 10 or y2-y1 > 10:
        #print a, b, d, flags[perm[i]]
        #bg = flex.double(data.accessor())
        #for x in range(ex2-ex1):
          #for y in range(ey2-ey1):
            #z = a * x + b * y + d
            #bg[0,y,x] = z

        #model = modeller.create(data-bg, mask)
        #d, a, b = model.params()[:3]
        #c = -1

        #bg2 = flex.double(data.accessor())
        #for x in range(ex2-ex1):
          #for y in range(ey2-ey1):
            #z = a * x + b * y + d
            #bg2[0,y,x] = z
        ##print a, b, d

        #from matplotlib import pyplot
        #fig, axes = pyplot.subplots(nrows=1, ncols=5)
        #im0 = axes[0].imshow(data.as_numpy_array()[i_z,:,:], interpolation='none')
        #im1 = axes[1].imshow(mask.as_numpy_array()[i_z,:,:], interpolation='none')
        #im2 = axes[2].imshow(bg.as_numpy_array()[i_z,:,:], interpolation='none')
        #im3 = axes[3].imshow((data-bg).as_numpy_array()[i_z,:,:], interpolation='none')
        #im4 = axes[4].imshow(bg2.as_numpy_array()[i_z,:,:], interpolation='none')
        ##pyplot.colorbar(im0)
        ##pyplot.colorbar(im1)
        ##pyplot.colorbar(im2)
        ##pyplot.colorbar(im3)
        #pyplot.show()

      #from matplotlib import pyplot
      #fig, axes = pyplot.subplots(nrows=1, ncols=2)
      #im0 = axes[0].imshow(data.as_numpy_array()[i_z,:,:], interpolation='none')
      #im1 = axes[1].imshow(bg.as_numpy_array()[i_z,:,:], interpolation='none')
      #pyplot.colorbar(im1)
      #pyplot.show()

    t1 = time.time()
    #print "Time fit_bg: %s" %(t1-t0)

    return flags
예제 #12
0
    def run(self, flags, sweep=None, shoeboxes=None, **kwargs):
        from dials.array_family import flex
        from dials.algorithms.shoebox import MaskCode
        from dials.algorithms.background.simple import Linear2dModeller
        bg_code = MaskCode.Valid | MaskCode.BackgroundUsed
        fg_code = MaskCode.Valid | MaskCode.Foreground
        strong_code = MaskCode.Valid | MaskCode.Strong

        modeller = Linear2dModeller()
        expanded_shoeboxes = flex.shoebox()
        detector = sweep.get_detector()

        zoffset = 0
        if sweep.get_scan() is not None:
            zoffset = sweep.get_scan().get_array_range()[0]

        from libtbx.containers import OrderedDict

        class image_data_cache(object):
            def __init__(self, imageset, size=10):
                self.imageset = imageset
                self.size = size
                self._image_data = OrderedDict()

            def __getitem__(self, i):
                image_data = self._image_data.get(i)
                if image_data is None:
                    image_data = self.imageset.get_raw_data(i)
                    if len(self._image_data) >= self.size:
                        # remove the oldest entry in the cache
                        del self._image_data[self._image_data.keys()[0]]
                    self._image_data[i] = image_data
                return image_data

        cache = image_data_cache(sweep)
        #cache = sweep

        # sort shoeboxes by centroid z
        frame = shoeboxes.centroid_all().position_frame()
        perm = flex.sort_permutation(frame)
        shoeboxes = shoeboxes.select(perm)
        buffer_size = 1
        bg_plus_buffer = self.background_size + buffer_size

        import time
        t0 = time.time()
        for i, shoebox in enumerate(shoeboxes):
            if not flags[perm[i]]:
                continue
            panel = detector[shoebox.panel]
            trusted_range = panel.get_trusted_range()
            max_x, max_y = panel.get_image_size()
            bbox = shoebox.bbox
            x1, x2, y1, y2, z1, z2 = bbox
            # expand the bbox with a background region around the spotfinder shoebox
            # perhaps also should use a buffer zone between the shoebox and the
            # background region
            expanded_bbox = (max(0, x1 - bg_plus_buffer),
                             min(max_x, x2 + bg_plus_buffer),
                             max(0, y1 - bg_plus_buffer),
                             min(max_y, y2 + bg_plus_buffer), z1, z2)
            shoebox.bbox = expanded_bbox
        t1 = time.time()
        logger.info("Time expand_shoebox: %s" % (t1 - t0))

        rlist = flex.reflection_table()
        rlist['shoebox'] = shoeboxes
        rlist['shoebox'].allocate()
        rlist['panel'] = shoeboxes.panels()
        rlist['bbox'] = shoeboxes.bounding_boxes()

        t0 = time.time()
        rlist.extract_shoeboxes(sweep)
        t1 = time.time()

        shoeboxes = rlist['shoebox']
        shoeboxes.flatten()

        t0 = time.time()
        for i, shoebox in enumerate(shoeboxes):
            if not flags[perm[i]]: continue
            panel = detector[shoebox.panel]
            trusted_range = panel.get_trusted_range()
            max_x, max_y = panel.get_image_size()
            ex1, ex2, ey1, ey2, ez1, ez2 = shoebox.bbox
            data = shoebox.data
            mask = flex.bool(data.accessor(), False)
            for i_y, y in enumerate(range(ey1, ey2)):
                for i_x, x in enumerate(range(ex1, ex2)):
                    value = data[0, i_y, i_x]
                    if (y >= (ey1 + buffer_size) and y < (ey2 - buffer_size)
                            and x >= (ex1 + buffer_size) and x <
                        (ex2 - buffer_size)):
                        mask[0, i_y, i_x] = False  # foreground
                    elif value > trusted_range[0] and value < trusted_range[1]:
                        mask[0, i_y, i_x] = True  # background

            model = modeller.create(data.as_double(), mask)
            d, a, b = model.params()[:3]
            c = -1

            if abs(a) > self.gradient_cutoff or abs(b) > self.gradient_cutoff:
                flags[perm[i]] = False

        t1 = time.time()

        return flags
예제 #13
0
파일: factory.py 프로젝트: dials/dials
  def run(self, flags, sweep=None, shoeboxes=None, **kwargs):
    from dials.array_family import flex
    from dials.algorithms.shoebox import MaskCode
    from dials.algorithms.background.simple import Linear2dModeller
    bg_code = MaskCode.Valid | MaskCode.BackgroundUsed
    fg_code = MaskCode.Valid | MaskCode.Foreground
    strong_code = MaskCode.Valid | MaskCode.Strong

    modeller = Linear2dModeller()
    expanded_shoeboxes = flex.shoebox()
    detector = sweep.get_detector()

    zoffset = 0
    if sweep.get_scan() is not None:
      zoffset = sweep.get_scan().get_array_range()[0]

    from libtbx.containers import OrderedDict
    class image_data_cache(object):
      def __init__(self, imageset, size=10):
        self.imageset = imageset
        self.size = size
        self._image_data = OrderedDict()

      def __getitem__(self, i):
        image_data = self._image_data.get(i)
        if image_data is None:
          image_data = self.imageset.get_raw_data(i)
          if len(self._image_data) >= self.size:
            # remove the oldest entry in the cache
            del self._image_data[self._image_data.keys()[0]]
          self._image_data[i] = image_data
        return image_data

    cache = image_data_cache(sweep)
    #cache = sweep

    # sort shoeboxes by centroid z
    frame = shoeboxes.centroid_all().position_frame()
    perm = flex.sort_permutation(frame)
    shoeboxes = shoeboxes.select(perm)
    buffer_size = 1
    bg_plus_buffer = self.background_size + buffer_size

    import time
    t0 = time.time()
    for i, shoebox in enumerate(shoeboxes):
      if not flags[perm[i]]:
        continue
      panel = detector[shoebox.panel]
      trusted_range = panel.get_trusted_range()
      max_x, max_y = panel.get_image_size()
      bbox = shoebox.bbox
      x1, x2, y1, y2, z1, z2 = bbox
      # expand the bbox with a background region around the spotfinder shoebox
      # perhaps also should use a buffer zone between the shoebox and the
      # background region
      expanded_bbox = (max(0, x1-bg_plus_buffer),
                       min(max_x, x2+bg_plus_buffer),
                       max(0, y1-bg_plus_buffer),
                       min(max_y, y2+bg_plus_buffer),
                       z1, z2)
      shoebox.bbox = expanded_bbox
    t1 = time.time()
    logger.info("Time expand_shoebox: %s" %(t1-t0))

    rlist = flex.reflection_table()
    rlist['shoebox'] = shoeboxes
    rlist['shoebox'].allocate()
    rlist['panel'] = shoeboxes.panels()
    rlist['bbox'] = shoeboxes.bounding_boxes()

    t0 = time.time()
    rlist.extract_shoeboxes(sweep)
    t1 = time.time()

    shoeboxes = rlist['shoebox']
    shoeboxes.flatten()

    t0 = time.time()
    for i, shoebox in enumerate(shoeboxes):
      if not flags[perm[i]]: continue
      panel = detector[shoebox.panel]
      trusted_range = panel.get_trusted_range()
      max_x, max_y = panel.get_image_size()
      ex1, ex2, ey1, ey2, ez1, ez2 = shoebox.bbox
      data = shoebox.data
      mask = flex.bool(data.accessor(), False)
      for i_y, y in enumerate(range(ey1, ey2)):
        for i_x, x in enumerate(range(ex1, ex2)):
          value = data[0, i_y, i_x]
          if (y >= (ey1+buffer_size) and y < (ey2-buffer_size) and
              x >= (ex1+buffer_size) and x < (ex2-buffer_size)):
            mask[0, i_y, i_x] = False # foreground
          elif value > trusted_range[0] and value < trusted_range[1]:
            mask[0, i_y, i_x] = True # background

      model = modeller.create(data.as_double(), mask)
      d, a, b = model.params()[:3]
      c = -1

      if abs(a) > self.gradient_cutoff or abs(b) > self.gradient_cutoff:
        flags[perm[i]] = False

    t1 = time.time()

    return flags