Esempio n. 1
0
def generate_spots(crystal_model, detector, beam, goniometer=None, scan=None,
                   sel_fraction=1.0):
  import math

  experiment = Experiment(beam=beam,
                          detector=detector,
                          goniometer=goniometer,
                          scan=scan,
                          crystal=crystal_model)

  # if we don't set the imageset then from_predictions uses the StillsReflectionPredictor :-(
  from dxtbx.imageset import NullReader, ImageSweep
  imageset = ImageSweep(NullReader, indices=range(len(scan.get_epochs())), beam=beam, goniometer=goniometer,
                        detector=detector, scan=scan)
  experiment.imageset = imageset

  predicted = flex.reflection_table.from_predictions(experiment)

  sel = flex.random_selection(len(predicted),
                              int(math.floor(sel_fraction*len(predicted))))
  predicted = predicted.select(sel)
  predicted['imageset_id'] = flex.size_t(len(predicted), 0)
  predicted['xyzobs.px.value'] = predicted['xyzcal.px']
  predicted['xyzobs.px.variance'] = flex.vec3_double(
    len(predicted), (0.5,0.5,0.5))
  return predicted
Esempio n. 2
0
def generate_spots(crystal_model,
                   detector,
                   beam,
                   goniometer=None,
                   scan=None,
                   sel_fraction=1.0):

    experiment = Experiment(beam=beam,
                            detector=detector,
                            goniometer=goniometer,
                            scan=scan,
                            crystal=crystal_model)

    # if we don't set the imageset then from_predictions uses the StillsReflectionPredictor :-(
    filenames = [""] * len(scan)
    reader = Reader(filenames)
    masker = Masker(filenames)
    data = ImageSetData(reader, masker)
    imageset = ImageSweep(data, beam, detector, goniometer, scan)
    experiment.imageset = imageset

    predicted = flex.reflection_table.from_predictions(experiment)

    sel = flex.random_selection(len(predicted),
                                int(math.floor(sel_fraction * len(predicted))))
    predicted = predicted.select(sel)
    predicted['imageset_id'] = flex.size_t(len(predicted), 0)
    predicted['xyzobs.px.value'] = predicted['xyzcal.px']
    predicted['xyzobs.px.variance'] = flex.vec3_double(len(predicted),
                                                       (0.5, 0.5, 0.5))
    return predicted
Esempio n. 3
0
def generate_spots(crystal_model,
                   detector,
                   beam,
                   goniometer=None,
                   scan=None,
                   sel_fraction=1.0):
    import math

    experiment = Experiment(beam=beam,
                            detector=detector,
                            goniometer=goniometer,
                            scan=scan,
                            crystal=crystal_model)

    # if we don't set the imageset then from_predictions uses the StillsReflectionPredictor :-(
    from dxtbx.imageset import NullReader, ImageSweep
    imageset = ImageSweep(NullReader,
                          indices=range(len(scan.get_epochs())),
                          beam=beam,
                          goniometer=goniometer,
                          detector=detector,
                          scan=scan)
    experiment.imageset = imageset

    predicted = flex.reflection_table.from_predictions(experiment)

    sel = flex.random_selection(len(predicted),
                                int(math.floor(sel_fraction * len(predicted))))
    predicted = predicted.select(sel)
    predicted['imageset_id'] = flex.size_t(len(predicted), 0)
    predicted['xyzobs.px.value'] = predicted['xyzcal.px']
    predicted['xyzobs.px.variance'] = flex.vec3_double(len(predicted),
                                                       (0.5, 0.5, 0.5))
    return predicted
Esempio n. 4
0
def _average_bbox_size(reflections):
    """Calculate the average bbox size for debugging"""

    bbox = reflections["bbox"]
    sel = flex.random_selection(len(bbox), min(len(bbox), 1000))
    subset_bbox = bbox.select(sel)
    xmin, xmax, ymin, ymax, zmin, zmax = subset_bbox.parts()
    xsize = flex.mean((xmax - xmin).as_double())
    ysize = flex.mean((ymax - ymin).as_double())
    zsize = flex.mean((zmax - zmin).as_double())
    return xsize, ysize, zsize
Esempio n. 5
0
def sample_predictions(experiments, predicted, params):
    """
    Select a random sample of the predicted reflections to integrate.

    Args:
        experiments: The experiment list
        predicted: A reflection table of predicted reflections
        params: The integration phil parameters

    Returns:
        A subset of the original predicted table.
    """

    if params.sampling.random_seed:
        flex.set_random_seed(params.sampling.random_seed)

    nref_per_degree = params.sampling.reflections_per_degree
    min_sample_size = params.sampling.minimum_sample_size
    max_sample_size = params.sampling.maximum_sample_size

    # this code is very similar to David's code in algorithms/refinement/reflection_manager.py!

    working_isel = flex.size_t()
    for iexp, exp in enumerate(experiments):

        sel = predicted["id"] == iexp
        isel = sel.iselection()
        nrefs = sample_size = len(isel)

        # set sample size according to nref_per_degree (per experiment)
        if exp.scan and nref_per_degree:
            sequence_range_rad = exp.scan.get_oscillation_range(deg=False)
            width = math.degrees(abs(sequence_range_rad[1] - sequence_range_rad[0]))
            sample_size = int(nref_per_degree * width)
        else:
            sequence_range_rad = None

        # adjust sample size if below the chosen limit
        sample_size = max(sample_size, min_sample_size)

        # set maximum sample size if requested
        if max_sample_size:
            sample_size = min(sample_size, max_sample_size)

        # determine subset and collect indices
        if sample_size < nrefs:
            isel = isel.select(flex.random_selection(nrefs, sample_size))
        working_isel.extend(isel)

    # create subset
    return predicted.select(working_isel)
Esempio n. 6
0
    def sample_predictions(self, experiments, predicted, params):
        """ Select a random sample of the predicted reflections to integrate. """
        from dials.array_family import flex

        nref_per_degree = params.sampling.reflections_per_degree
        min_sample_size = params.sampling.minimum_sample_size
        max_sample_size = params.sampling.maximum_sample_size

        # this code is very similar to David's code in algorithms/refinement/reflection_manager.py!

        # constants
        from math import pi

        RAD2DEG = 180.0 / pi
        DEG2RAD = pi / 180.0

        working_isel = flex.size_t()
        for iexp, exp in enumerate(experiments):

            sel = predicted["id"] == iexp
            isel = sel.iselection()
            # refs = self._reflections.select(sel)
            nrefs = sample_size = len(isel)

            # set sample size according to nref_per_degree (per experiment)
            if exp.scan and nref_per_degree:
                sweep_range_rad = exp.scan.get_oscillation_range(deg=False)
                width = abs(sweep_range_rad[1] - sweep_range_rad[0]) * RAD2DEG
                sample_size = int(nref_per_degree * width)
            else:
                sweep_range_rad = None

            # adjust sample size if below the chosen limit
            sample_size = max(sample_size, min_sample_size)

            # set maximum sample size if requested
            if max_sample_size:
                sample_size = min(sample_size, max_sample_size)

            # determine subset and collect indices
            if sample_size < nrefs:
                isel = isel.select(flex.random_selection(nrefs, sample_size))
            working_isel.extend(isel)

        # create subset
        return predicted.select(working_isel)
Esempio n. 7
0
    def sample_predictions(self, experiments, predicted, params):
        """Select a random sample of the predicted reflections to integrate."""

        nref_per_degree = params.sampling.reflections_per_degree
        min_sample_size = params.sampling.minimum_sample_size
        max_sample_size = params.sampling.maximum_sample_size

        # this code is very similar to David's code in algorithms/refinement/reflection_manager.py!

        # constants
        from math import pi

        RAD2DEG = 180.0 / pi

        working_isel = flex.size_t()
        for iexp, exp in enumerate(experiments):

            sel = predicted["id"] == iexp
            isel = sel.iselection()
            # refs = self._reflections.select(sel)
            nrefs = sample_size = len(isel)

            # set sample size according to nref_per_degree (per experiment)
            if exp.scan and nref_per_degree:
                sequence_range_rad = exp.scan.get_oscillation_range(deg=False)
                width = abs(sequence_range_rad[1] -
                            sequence_range_rad[0]) * RAD2DEG
                sample_size = int(nref_per_degree * width)
            else:
                sequence_range_rad = None

            # adjust sample size if below the chosen limit
            sample_size = max(sample_size, min_sample_size)

            # set maximum sample size if requested
            if max_sample_size:
                sample_size = min(sample_size, max_sample_size)

            # determine subset and collect indices
            if sample_size < nrefs:
                isel = isel.select(flex.random_selection(nrefs, sample_size))
            working_isel.extend(isel)

        # create subset
        return predicted.select(working_isel)
Esempio n. 8
0
    def _create_working_set(self):
        """Make a subset of the indices of reflections to use in refinement"""

        working_isel = flex.size_t()
        for iexp, exp in enumerate(self._experiments):

            sel = self._reflections["id"] == iexp
            isel = sel.iselection()
            # refs = self._reflections.select(sel)
            nrefs = sample_size = len(isel)

            # set sample size according to nref_per_degree (per experiment)
            if exp.scan and self._nref_per_degree:
                sequence_range_rad = exp.scan.get_oscillation_range(deg=False)
                width = abs(sequence_range_rad[1] -
                            sequence_range_rad[0]) * RAD2DEG
                if self._nref_per_degree is libtbx.Auto:
                    # For multi-turn, set sample size to the greater of the approx nref
                    # in a single turn and 100 reflections per degree
                    turns = width / 360.0
                    if turns > 1:
                        approx_nref_1_turn = int(math.ceil(nrefs / turns))
                        sample_size = int(
                            max(approx_nref_1_turn, 100.0 * width))
                else:
                    sample_size = int(self._nref_per_degree * width)

            # adjust sample size if below the chosen limit
            sample_size = max(sample_size, self._min_sample_size)

            # set maximum sample size if requested
            if self._max_sample_size:
                sample_size = min(sample_size, self._max_sample_size)

            # determine subset and collect indices
            if sample_size < nrefs:
                isel = isel.select(flex.random_selection(nrefs, sample_size))
            working_isel.extend(isel)

        # create subsets
        free_sel = flex.bool(len(self._reflections), True)
        free_sel.set_selected(working_isel, False)
        self._free_reflections = self._reflections.select(free_sel)
        self._reflections = self._reflections.select(working_isel)
Esempio n. 9
0
  def _create_working_set(self):
    """Make a subset of the indices of reflections to use in refinement"""

    working_isel = flex.size_t()
    for iexp, exp in enumerate(self._experiments):

      sel = self._reflections['id'] == iexp
      isel = sel.iselection()
      #refs = self._reflections.select(sel)
      nrefs = sample_size = len(isel)

      # set sample size according to nref_per_degree (per experiment)
      if exp.scan and self._nref_per_degree:
        sweep_range_rad = exp.scan.get_oscillation_range(deg=False)
        width = abs(sweep_range_rad[1] -
                    sweep_range_rad[0]) * RAD2DEG
        sample_size = int(self._nref_per_degree * width)
      else: sweep_range_rad = None

      # adjust sample size if below the chosen limit
      sample_size = max(sample_size, self._min_sample_size)

      # set maximum sample size if requested
      if self._max_sample_size:
        sample_size = min(sample_size, self._max_sample_size)

      # determine subset and collect indices
      if sample_size < nrefs:
        isel = isel.select(flex.random_selection(nrefs, sample_size))
      working_isel.extend(isel)

    # create subsets
    free_sel = flex.bool(len(self._reflections), True)
    free_sel.set_selected(working_isel, False)
    self._free_reflections = self._reflections.select(free_sel)
    self._reflections = self._reflections.select(working_isel)

    return
Esempio n. 10
0
    def _create_working_set(self):
        """Make a subset of the indices of reflections to use in refinement"""

        working_isel = flex.size_t()
        for iexp, exp in enumerate(self._experiments):

            sel = self._reflections['id'] == iexp
            isel = sel.iselection()
            #refs = self._reflections.select(sel)
            nrefs = sample_size = len(isel)

            # set sample size according to nref_per_degree (per experiment)
            if exp.scan and self._nref_per_degree:
                sweep_range_rad = exp.scan.get_oscillation_range(deg=False)
                width = abs(sweep_range_rad[1] - sweep_range_rad[0]) * RAD2DEG
                sample_size = int(self._nref_per_degree * width)
            else:
                sweep_range_rad = None

            # adjust sample size if below the chosen limit
            sample_size = max(sample_size, self._min_sample_size)

            # set maximum sample size if requested
            if self._max_sample_size:
                sample_size = min(sample_size, self._max_sample_size)

            # determine subset and collect indices
            if sample_size < nrefs:
                isel = isel.select(flex.random_selection(nrefs, sample_size))
            working_isel.extend(isel)

        # create subsets
        free_sel = flex.bool(len(self._reflections), True)
        free_sel.set_selected(working_isel, False)
        self._free_reflections = self._reflections.select(free_sel)
        self._reflections = self._reflections.select(working_isel)

        return
Esempio n. 11
0
def test_assign_indices(space_group_symbol, experiment, crystal_factory):
    cryst_model = crystal_factory(space_group_symbol)
    experiment.crystal = cryst_model

    predicted_reflections = flex.reflection_table.from_predictions(experiment)
    use_fraction = 0.3
    use_sel = flex.random_selection(
        len(predicted_reflections),
        int(use_fraction * len(predicted_reflections)))
    predicted_reflections = predicted_reflections.select(use_sel)
    miller_indices = predicted_reflections["miller_index"]
    predicted_reflections["xyzobs.mm.value"] = predicted_reflections[
        "xyzcal.mm"]
    predicted_reflections["id"] = flex.int(len(predicted_reflections), 0)
    predicted_reflections.map_centroids_to_reciprocal_space(
        ExperimentList([experiment]))

    # check that local and global indexing worked equally well in absence of errors
    result = CompareGlobalLocal(experiment, predicted_reflections,
                                miller_indices)
    assert result.misindexed_local == 0
    assert result.misindexed_global == 0

    a, b, c = map(matrix.col, experiment.crystal.get_real_space_vectors())
    relative_error = 0.02
    a *= 1 + relative_error
    b *= 1 + relative_error
    c *= 1 + relative_error

    cryst_model2 = Crystal(a, b, c, space_group=cryst_model.get_space_group())
    experiment.crystal = cryst_model2

    result = CompareGlobalLocal(experiment, predicted_reflections,
                                miller_indices)

    # check that the local indexing did a better job given the errors in the basis vectors
    # assert result.misindexed_local < result.misindexed_global
    assert result.misindexed_local == 0
    assert result.correct_local > result.correct_global
    # usually the number misindexed is much smaller than this
    assert result.misindexed_local < (0.001 * len(result.reflections_local))

    # the reciprocal matrix
    A = matrix.sqr(cryst_model.get_A())
    A = random_rotation(angle_max=0.5) * A

    direct_matrix = A.inverse()
    cryst_model2 = Crystal(
        direct_matrix[0:3],
        direct_matrix[3:6],
        direct_matrix[6:9],
        space_group=cryst_model.get_space_group(),
    )
    experiment.crystal = cryst_model2

    result = CompareGlobalLocal(experiment, predicted_reflections,
                                miller_indices)

    # check that the local indexing did a better job given the errors in the basis vectors
    assert result.misindexed_local <= result.misindexed_global, (
        result.misindexed_local,
        result.misindexed_global,
    )
    assert result.misindexed_local < 0.01 * result.correct_local
    assert result.correct_local >= result.correct_global
    # usually the number misindexed is much smaller than this
    assert result.misindexed_local < (0.001 * len(result.reflections_local))
Esempio n. 12
0
def run(space_group_info):
    datablock_json = os.path.join(dials_regression, "indexing_test_data",
                                  "i04_weak_data", "datablock_orig.json")

    datablock = load.datablock(datablock_json, check_format=False)[0]
    sweep = datablock.extract_imagesets()[0]

    sweep._indices = sweep._indices[:20]
    sweep.set_scan(sweep.get_scan()[:20])

    import random
    space_group = space_group_info.group()
    unit_cell = space_group_info.any_compatible_unit_cell(
        volume=random.uniform(1e4, 1e6))

    crystal_symmetry = crystal.symmetry(unit_cell=unit_cell,
                                        space_group=space_group)
    crystal_symmetry.show_summary()

    # the reciprocal matrix
    B = matrix.sqr(unit_cell.fractionalization_matrix()).transpose()
    U = random_rotation()
    A = U * B

    direct_matrix = A.inverse()
    cryst_model = Crystal(direct_matrix[0:3],
                          direct_matrix[3:6],
                          direct_matrix[6:9],
                          space_group=space_group)
    experiment = Experiment(imageset=sweep,
                            beam=sweep.get_beam(),
                            detector=sweep.get_detector(),
                            goniometer=sweep.get_goniometer(),
                            scan=sweep.get_scan(),
                            crystal=cryst_model)
    predicted_reflections = flex.reflection_table.from_predictions(experiment)
    use_fraction = 0.3
    use_sel = flex.random_selection(
        len(predicted_reflections),
        int(use_fraction * len(predicted_reflections)))
    predicted_reflections = predicted_reflections.select(use_sel)
    miller_indices = predicted_reflections['miller_index']
    miller_set = miller.set(crystal_symmetry,
                            miller_indices,
                            anomalous_flag=True)
    predicted_reflections['xyzobs.mm.value'] = predicted_reflections[
        'xyzcal.mm']
    predicted_reflections['id'] = flex.int(len(predicted_reflections), 0)
    from dials.algorithms.indexing.indexer import indexer_base
    indexer_base.map_centroids_to_reciprocal_space(predicted_reflections,
                                                   sweep.get_detector(),
                                                   sweep.get_beam(),
                                                   sweep.get_goniometer())

    # check that local and global indexing worked equally well in absence of errors
    result = compare_global_local(experiment, predicted_reflections,
                                  miller_indices)
    assert result.misindexed_local == 0
    assert result.misindexed_global == 0

    a, b, c = map(matrix.col, cryst_model.get_real_space_vectors())
    relative_error = 0.02
    a *= (1 + relative_error)
    b *= (1 + relative_error)
    c *= (1 + relative_error)

    cryst_model2 = Crystal(a, b, c, space_group=space_group)
    experiment.crystal = cryst_model2

    result = compare_global_local(experiment, predicted_reflections,
                                  miller_indices)

    # check that the local indexing did a better job given the errors in the basis vectors
    #assert result.misindexed_local < result.misindexed_global
    assert result.misindexed_local == 0
    assert result.correct_local > result.correct_global
    # usually the number misindexed is much smaller than this
    assert result.misindexed_local < (0.001 * len(result.reflections_local))

    # the reciprocal matrix
    A = matrix.sqr(cryst_model.get_A())
    A = random_rotation(angle_max=0.03) * A

    direct_matrix = A.inverse()
    cryst_model2 = Crystal(direct_matrix[0:3],
                           direct_matrix[3:6],
                           direct_matrix[6:9],
                           space_group=space_group)
    experiment.crystal = cryst_model2

    result = compare_global_local(experiment, predicted_reflections,
                                  miller_indices)

    # check that the local indexing did a better job given the errors in the basis vectors
    assert result.misindexed_local <= result.misindexed_global, (
        result.misindexed_local, result.misindexed_global)
    assert result.misindexed_local < 0.01 * result.correct_local
    assert result.correct_local > result.correct_global
    # usually the number misindexed is much smaller than this
    assert result.misindexed_local < (0.001 * len(result.reflections_local))
Esempio n. 13
0
def run(space_group_info):
  datablock_json = os.path.join(
    dials_regression, "indexing_test_data",
    "i04_weak_data", "datablock_orig.json")

  datablock = load.datablock(datablock_json, check_format=False)[0]
  sweep = datablock.extract_imagesets()[0]

  sweep._indices = sweep._indices[:20]
  sweep.set_scan(sweep.get_scan()[:20])

  import random
  space_group = space_group_info.group()
  unit_cell = space_group_info.any_compatible_unit_cell(volume=random.uniform(1e4,1e6))

  crystal_symmetry = crystal.symmetry(unit_cell=unit_cell,
                                      space_group=space_group)
  crystal_symmetry.show_summary()

  # the reciprocal matrix
  B = matrix.sqr(unit_cell.fractionalization_matrix()).transpose()
  U = random_rotation()
  A = U * B

  direct_matrix = A.inverse()
  cryst_model = crystal_model(direct_matrix[0:3],
                              direct_matrix[3:6],
                              direct_matrix[6:9],
                              space_group=space_group)
  experiment = Experiment(imageset=sweep,
                          beam=sweep.get_beam(),
                          detector=sweep.get_detector(),
                          goniometer=sweep.get_goniometer(),
                          scan=sweep.get_scan(),
                          crystal=cryst_model)
  predicted_reflections = flex.reflection_table.from_predictions(
    experiment)
  use_fraction = 0.3
  use_sel = flex.random_selection(
    len(predicted_reflections), int(use_fraction*len(predicted_reflections)))
  predicted_reflections = predicted_reflections.select(use_sel)
  miller_indices = predicted_reflections['miller_index']
  miller_set = miller.set(
    crystal_symmetry, miller_indices, anomalous_flag=True)
  predicted_reflections['xyzobs.mm.value'] = predicted_reflections['xyzcal.mm']
  predicted_reflections['id'] = flex.int(len(predicted_reflections), 0)
  from dials.algorithms.indexing.indexer import indexer_base
  indexer_base.map_centroids_to_reciprocal_space(
    predicted_reflections, sweep.get_detector(), sweep.get_beam(),
    sweep.get_goniometer())


  # check that local and global indexing worked equally well in absence of errors
  result = compare_global_local(experiment, predicted_reflections,
                                miller_indices)
  assert result.misindexed_local == 0
  assert result.misindexed_global == 0

  a, b, c = cryst_model.get_real_space_vectors()
  relative_error = 0.02
  a *= (1+relative_error)
  b *= (1+relative_error)
  c *= (1+relative_error)

  cryst_model2 = crystal_model(a, b, c, space_group=space_group)
  experiment.crystal = cryst_model2

  result = compare_global_local(experiment, predicted_reflections,
                                miller_indices)

  # check that the local indexing did a better job given the errors in the basis vectors
  #assert result.misindexed_local < result.misindexed_global
  assert result.misindexed_local == 0
  assert result.correct_local > result.correct_global
  # usually the number misindexed is much smaller than this
  assert result.misindexed_local < (0.001 * len(result.reflections_local))

  # the reciprocal matrix
  A = cryst_model.get_A()
  A = random_rotation(angle_max=0.03) * A

  direct_matrix = A.inverse()
  cryst_model2 = crystal_model(direct_matrix[0:3],
                               direct_matrix[3:6],
                               direct_matrix[6:9],
                               space_group=space_group)
  experiment.crystal = cryst_model2

  result = compare_global_local(experiment, predicted_reflections,
                                miller_indices)

  # check that the local indexing did a better job given the errors in the basis vectors
  assert result.misindexed_local <= result.misindexed_global, (
    result.misindexed_local, result.misindexed_global)
  assert result.misindexed_local < 0.01 * result.correct_local
  assert result.correct_local > result.correct_global
  # usually the number misindexed is much smaller than this
  assert result.misindexed_local < (0.001 * len(result.reflections_local))
Esempio n. 14
0
def test_assign_indices(dials_regression, space_group_symbol):
    experiments_json = os.path.join(dials_regression, "indexing_test_data",
                                    "i04_weak_data", "datablock_orig.json")

    experiments = load.experiment_list(experiments_json, check_format=False)
    sweep = experiments.imagesets()[0]

    sweep = sweep[:20]

    # set random seeds so tests more reliable
    seed = 54321
    random.seed(seed)
    flex.set_random_seed(seed)

    space_group_info = sgtbx.space_group_info(symbol=space_group_symbol)
    space_group = space_group_info.group()
    unit_cell = space_group_info.any_compatible_unit_cell(
        volume=random.uniform(1e4, 1e6))

    crystal_symmetry = crystal.symmetry(unit_cell=unit_cell,
                                        space_group=space_group)
    crystal_symmetry.show_summary()

    # the reciprocal matrix
    B = matrix.sqr(unit_cell.fractionalization_matrix()).transpose()
    U = random_rotation()
    A = U * B

    direct_matrix = A.inverse()
    cryst_model = Crystal(
        direct_matrix[0:3],
        direct_matrix[3:6],
        direct_matrix[6:9],
        space_group=space_group,
    )
    experiment = Experiment(
        imageset=sweep,
        beam=sweep.get_beam(),
        detector=sweep.get_detector(),
        goniometer=sweep.get_goniometer(),
        scan=sweep.get_scan(),
        crystal=cryst_model,
    )
    predicted_reflections = flex.reflection_table.from_predictions(experiment)
    use_fraction = 0.3
    use_sel = flex.random_selection(
        len(predicted_reflections),
        int(use_fraction * len(predicted_reflections)))
    predicted_reflections = predicted_reflections.select(use_sel)
    miller_indices = predicted_reflections["miller_index"]
    predicted_reflections["xyzobs.mm.value"] = predicted_reflections[
        "xyzcal.mm"]
    predicted_reflections["id"] = flex.int(len(predicted_reflections), 0)
    predicted_reflections.map_centroids_to_reciprocal_space(
        sweep.get_detector(), sweep.get_beam(), sweep.get_goniometer())

    # check that local and global indexing worked equally well in absence of errors
    result = CompareGlobalLocal(experiment, predicted_reflections,
                                miller_indices)
    assert result.misindexed_local == 0
    assert result.misindexed_global == 0

    a, b, c = map(matrix.col, cryst_model.get_real_space_vectors())
    relative_error = 0.02
    a *= 1 + relative_error
    b *= 1 + relative_error
    c *= 1 + relative_error

    cryst_model2 = Crystal(a, b, c, space_group=space_group)
    experiment.crystal = cryst_model2

    result = CompareGlobalLocal(experiment, predicted_reflections,
                                miller_indices)

    # check that the local indexing did a better job given the errors in the basis vectors
    # assert result.misindexed_local < result.misindexed_global
    assert result.misindexed_local == 0
    assert result.correct_local > result.correct_global
    # usually the number misindexed is much smaller than this
    assert result.misindexed_local < (0.001 * len(result.reflections_local))

    # the reciprocal matrix
    A = matrix.sqr(cryst_model.get_A())
    A = random_rotation(angle_max=0.5) * A

    direct_matrix = A.inverse()
    cryst_model2 = Crystal(
        direct_matrix[0:3],
        direct_matrix[3:6],
        direct_matrix[6:9],
        space_group=space_group,
    )
    experiment.crystal = cryst_model2

    result = CompareGlobalLocal(experiment, predicted_reflections,
                                miller_indices)

    # check that the local indexing did a better job given the errors in the basis vectors
    assert result.misindexed_local <= result.misindexed_global, (
        result.misindexed_local,
        result.misindexed_global,
    )
    assert result.misindexed_local < 0.01 * result.correct_local
    assert result.correct_local >= result.correct_global
    # usually the number misindexed is much smaller than this
    assert result.misindexed_local < (0.001 * len(result.reflections_local))