def add_resolution_to_reflections(reflections, datablock): '''Add column d to reflection list''' # will assume everything from the first detector at the moment - clearly this # could be incorrect, will have to do something a little smarter, later from dials.algorithms.indexing.indexer import indexer_base imageset = datablock.extract_imagesets()[0] if 'imageset_id' not in reflections: reflections['imageset_id'] = reflections['id'] spots_mm = indexer_base.map_spots_pixel_to_mm_rad( spots=reflections, detector=imageset.get_detector(), scan=imageset.get_scan()) indexer_base.map_centroids_to_reciprocal_space( spots_mm, detector=imageset.get_detector(), beam=imageset.get_beam(), goniometer=imageset.get_goniometer()) d_spacings = 1 / spots_mm['rlp'].norms() reflections['d'] = d_spacings
def run(self): ''' Parse the options. ''' from dials.util.options import flatten_experiments, flatten_reflections # Parse the command line arguments params, options = self.parser.parse_args(show_diff_phil=True) self.params = params experiments = flatten_experiments(params.input.experiments) reflections = flatten_reflections(params.input.reflections) assert len(reflections) == len(experiments) == 1 reflections = reflections[0] exp = experiments[0] from dials.algorithms.indexing import index_reflections from dials.algorithms.indexing.indexer import indexer_base reflections['id'] = flex.int(len(reflections), -1) reflections['imageset_id'] = flex.int(len(reflections), 0) reflections = indexer_base.map_spots_pixel_to_mm_rad(reflections, exp.detector, exp.scan) indexer_base.map_centroids_to_reciprocal_space( reflections, exp.detector, exp.beam, exp.goniometer,) index_reflections(reflections, experiments, params.d_min, tolerance=0.3) indexed_reflections = reflections.select(reflections['miller_index'] != (0,0,0)) print "Indexed %d reflections out of %d"%(len(indexed_reflections), len(reflections)) easy_pickle.dump("indexedstrong.pickle", indexed_reflections)
def get_origin_offset_score(self, trial_origin_offset, solutions, amax, spots_mm, imageset): from rstbx.indexing_api import lattice # import dependency from rstbx.indexing_api import dps_extended trial_detector = dps_extended.get_new_detector(imageset.get_detector(), trial_origin_offset) from dials.algorithms.indexing.indexer import indexer_base indexer_base.map_centroids_to_reciprocal_space( spots_mm, trial_detector, imageset.get_beam(), imageset.get_goniometer()) return self.sum_score_detail(spots_mm['rlp'], solutions, amax=amax)
def get_origin_offset_score(self, trial_origin_offset, solutions, amax, spots_mm, imageset): from rstbx.indexing_api import lattice # import dependency from rstbx.indexing_api import dps_extended trial_detector = dps_extended.get_new_detector(imageset.get_detector(), trial_origin_offset) from dials.algorithms.indexing.indexer import indexer_base # Key point for this is that the spots must correspond to detector # positions not to the correct RS position => reset any fixed rotation # to identity - copy in case called from elsewhere import copy gonio = copy.deepcopy(imageset.get_goniometer()) gonio.set_fixed_rotation((1, 0, 0, 0, 1, 0, 0, 0, 1)) indexer_base.map_centroids_to_reciprocal_space( spots_mm, trial_detector, imageset.get_beam(), gonio) return self.sum_score_detail(spots_mm['rlp'], solutions, amax=amax)
def get_origin_offset_score(self, trial_origin_offset, solutions, amax, spots_mm, imageset): from rstbx.indexing_api import lattice # import dependency from rstbx.indexing_api import dps_extended trial_detector = dps_extended.get_new_detector(imageset.get_detector(), trial_origin_offset) from dials.algorithms.indexing.indexer import indexer_base # Key point for this is that the spots must correspond to detector # positions not to the correct RS position => reset any fixed rotation # to identity - copy in case called from elsewhere import copy gonio = copy.deepcopy(imageset.get_goniometer()) gonio.set_fixed_rotation((1, 0, 0, 0, 1, 0, 0, 0, 1)) indexer_base.map_centroids_to_reciprocal_space( spots_mm, trial_detector, imageset.get_beam(), gonio) return self.sum_score_detail(spots_mm['rlp'], solutions, amax=amax)
def discover_better_experimental_model(imagesets, spot_lists, params, dps_params, nproc=1, wide_search_binning=1): assert len(imagesets) == len(spot_lists) assert len(imagesets) > 0 # XXX should check that all the detector and beam objects are the same from dials.algorithms.indexing.indexer import indexer_base spot_lists_mm = [ indexer_base.map_spots_pixel_to_mm_rad(spots, imageset.get_detector(), imageset.get_scan()) for spots, imageset in zip(spot_lists, imagesets) ] spot_lists_mm = [] max_cell_list = [] detector = imagesets[0].get_detector() beam = imagesets[0].get_beam() beam_panel = detector.get_panel_intersection(beam.get_s0()) if beam_panel == -1: from libtbx.utils import Sorry raise Sorry('input beam does not intersect detector') for imageset, spots in zip(imagesets, spot_lists): if 'imageset_id' not in spots: spots['imageset_id'] = spots['id'] spots_mm = indexer_base.map_spots_pixel_to_mm_rad( spots=spots, detector=imageset.get_detector(), scan=imageset.get_scan()) indexer_base.map_centroids_to_reciprocal_space( spots_mm, detector=imageset.get_detector(), beam=imageset.get_beam(), goniometer=imageset.get_goniometer()) if dps_params.d_min is not None: d_spacings = 1 / spots_mm['rlp'].norms() sel = d_spacings > dps_params.d_min spots_mm = spots_mm.select(sel) # derive a max_cell from mm spots if params.max_cell is None: from dials.algorithms.indexing.indexer import find_max_cell max_cell = find_max_cell(spots_mm, max_cell_multiplier=1.3, step_size=45).max_cell max_cell_list.append(max_cell) if (params.max_reflections is not None and spots_mm.size() > params.max_reflections): logger.info('Selecting subset of %i reflections for analysis' % params.max_reflections) perm = flex.random_permutation(spots_mm.size()) sel = perm[:params.max_reflections] spots_mm = spots_mm.select(sel) spot_lists_mm.append(spots_mm) if params.max_cell is None: max_cell = flex.median(flex.double(max_cell_list)) else: max_cell = params.max_cell args = [(imageset, spots, max_cell, dps_params) for imageset, spots in zip(imagesets, spot_lists_mm)] from libtbx import easy_mp results = easy_mp.parallel_map(func=run_dps, iterable=args, processes=nproc, method="multiprocessing", preserve_order=True, asynchronous=True, preserve_exception_message=True) solution_lists = [r["solutions"] for r in results] amax_list = [r["amax"] for r in results] assert len(solution_lists) > 0 detector = imagesets[0].get_detector() beam = imagesets[0].get_beam() # perform calculation if dps_params.indexing.improve_local_scope == "origin_offset": discoverer = better_experimental_model_discovery( imagesets, spot_lists_mm, solution_lists, amax_list, dps_params, wide_search_binning=wide_search_binning) new_detector = discoverer.optimize_origin_offset_local_scope() old_panel, old_beam_centre = detector.get_ray_intersection( beam.get_s0()) new_panel, new_beam_centre = new_detector.get_ray_intersection( beam.get_s0()) old_beam_centre_px = detector[old_panel].millimeter_to_pixel( old_beam_centre) new_beam_centre_px = new_detector[new_panel].millimeter_to_pixel( new_beam_centre) logger.info("Old beam centre: %.2f, %.2f mm" % old_beam_centre + " (%.1f, %.1f px)" % old_beam_centre_px) logger.info("New beam centre: %.2f, %.2f mm" % new_beam_centre + " (%.1f, %.1f px)" % new_beam_centre_px) logger.info( "Shift: %.2f, %.2f mm" % (matrix.col(old_beam_centre) - matrix.col(new_beam_centre)).elems + " (%.1f, %.1f px)" % (matrix.col(old_beam_centre_px) - matrix.col(new_beam_centre_px)).elems) return new_detector, beam elif dps_params.indexing.improve_local_scope == "S0_vector": raise NotImplementedError()
def run(args): import libtbx.load_env from dials.util import log usage = "%s [options] datablock.json strong.pickle" % libtbx.env.dispatcher_name parser = OptionParser(usage=usage, phil=phil_scope, read_datablocks=True, read_reflections=True, check_format=False, epilog=help_message) params, options = parser.parse_args(show_diff_phil=False) datablocks = flatten_datablocks(params.input.datablock) reflections = flatten_reflections(params.input.reflections) if len(datablocks) == 0 or len(reflections) == 0: parser.print_help() exit(0) imagesets = [] for db in datablocks: imagesets.extend(db.extract_imagesets()) spots = [] for reflection in reflections: unique_ids = set(reflection['id']) for unique_id in sorted(unique_ids): spots.append(reflection.select(reflection['id'] == unique_id)) assert len(imagesets) == len(spots) if params.output.compress: import gzip fout = gzip.GzipFile(params.output.csv, 'w') else: fout = open(params.output.csv, 'w') fout.write('# x,y,z,experiment_id,imageset_id\n') dp = params.output.dp if dp <= 0: fmt = '%f,%f,%f,%d,%d\n' else: fmt = '%%.%df,%%.%df,%%.%df,%%d,%%d\n' % (dp, dp, dp) print 'Using format:', fmt.strip() for k, (imageset, refl) in enumerate(zip(imagesets, spots)): if 'imageset_id' not in refl: refl['imageset_id'] = refl['id'] reflmm = indexer_base.map_spots_pixel_to_mm_rad( spots=refl, detector=imageset.get_detector(), scan=imageset.get_scan()) indexer_base.map_centroids_to_reciprocal_space( reflmm, detector=imageset.get_detector(), beam=imageset.get_beam(), goniometer=imageset.get_goniometer()) rlp = reflmm['rlp'] for _rlp in rlp: fout.write(fmt % (_rlp[0], _rlp[1], _rlp[2], k, k)) print 'Appended %d spots to %s' % (len(rlp), params.output.csv) fout.close()
e = Experiment() e.beam = beamA e.crystal = optCrystal e.detector = detector e2 = deepcopy(e) e2.beam = beamB e2.crystal = e.crystal e3 = deepcopy(e) beamAB = deepcopy(beamA) waveAB = beamA.get_wavelength()*.5 + beamB.get_wavelength()*.5 beamAB.set_wavelength( waveAB) e3.beam = beamAB e3.crystal = e.crystal el = ExperimentList() el.append(e) el.append(e2) el.append(e3) #### # make the rlps refls_w_mm = indexer_base.map_spots_pixel_to_mm_rad(refls, detector, scan=None) indexer_base.map_centroids_to_reciprocal_space(refls_w_mm, detector, beamA, goniometer=None) rlps1 = refls_w_mm['rlp'] indexer_base.map_centroids_to_reciprocal_space(refls_w_mm, detector, beamB, goniometer=None) rlps2 = refls_w_mm['rlp'] for i in range(len(refls_w_mm)): refls_w_mm['id'][i] = -1 spot_utils.as_single_shot_reflections(refls_w_mm) index_reflections_detail(None, el, refls_w_mm, detector, rlps1, rlps2)
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))
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))
def run(args): from dials.util.options import OptionParser from dials.util.options import flatten_datablocks from dials.util.options import flatten_experiments from dials.util.options import flatten_reflections from dials.util import log import libtbx.load_env usage = "%s [options] datablock.json reflections.pickle" % ( libtbx.env.dispatcher_name) parser = OptionParser(usage=usage, phil=phil_scope, read_datablocks=True, read_experiments=True, read_reflections=True, check_format=False, epilog=help_message) params, options = parser.parse_args() datablocks = flatten_datablocks(params.input.datablock) experiments = flatten_experiments(params.input.experiments) reflections = flatten_reflections(params.input.reflections) if (len(datablocks) == 0 and len(experiments) == 0) or len(reflections) == 0: parser.print_help() exit(0) # Configure the logging log.config(info='dials.rl_png.log') # Log the diff phil diff_phil = parser.diff_phil.as_str() if diff_phil is not '': logger.info('The following parameters have been modified:\n') logger.info(diff_phil) reflections = reflections[0] if len(datablocks) == 0 and len(experiments) > 0: imagesets = experiments.imagesets() else: imagesets = [] for datablock in datablocks: imagesets.extend(datablock.extract_imagesets()) f = ReciprocalLatticePng(settings=params) f.load_models(imagesets, reflections, None) imageset = imagesets[0] rotation_axis = matrix.col(imageset.get_goniometer().get_rotation_axis()) s0 = matrix.col(imageset.get_beam().get_s0()) e1 = rotation_axis.normalize() e2 = s0.normalize() e3 = e1.cross(e2).normalize() #print e1 #print e2 #print e3 f.viewer.plot('rl_rotation_axis.png', n=e1.elems) f.viewer.plot('rl_beam_vector', n=e2.elems) f.viewer.plot('rl_e3.png', n=e3.elems) n_solutions = params.basis_vector_search.n_solutions if len(experiments): for i, c in enumerate(experiments.crystals()): A = matrix.sqr(c.get_A()) astar = A[:3] bstar = A[3:6] cstar = A[6:9] direct_matrix = A.inverse() a = direct_matrix[:3] b = direct_matrix[3:6] c = direct_matrix[6:9] prefix = '' if len(experiments.crystals()) > 1: prefix = '%i_' % (i + 1) f.viewer.plot('rl_%sa.png' % prefix, n=a) f.viewer.plot('rl_%sb.png' % prefix, n=b) f.viewer.plot('rl_%sc.png' % prefix, n=c) elif n_solutions: from dials.command_line.search_beam_position \ import run_dps, dps_phil_scope hardcoded_phil = dps_phil_scope.extract() hardcoded_phil.d_min = params.d_min imageset = imagesets[0] from dials.algorithms.indexing.indexer import indexer_base if 'imageset_id' not in reflections: reflections['imageset_id'] = reflections['id'] spots_mm = indexer_base.map_spots_pixel_to_mm_rad( spots=reflections, detector=imageset.get_detector(), scan=imageset.get_scan()) indexer_base.map_centroids_to_reciprocal_space( spots_mm, detector=imageset.get_detector(), beam=imageset.get_beam(), goniometer=imageset.get_goniometer()) if params.d_min is not None: d_spacings = 1 / spots_mm['rlp'].norms() sel = d_spacings > params.d_min spots_mm = spots_mm.select(sel) # derive a max_cell from mm spots from dials.algorithms.indexing.indexer import find_max_cell max_cell = find_max_cell(spots_mm, max_cell_multiplier=1.3, step_size=45).max_cell result = run_dps((imageset, spots_mm, max_cell, hardcoded_phil)) solutions = [matrix.col(v) for v in result['solutions']] for i in range(min(n_solutions, len(solutions))): v = solutions[i] #if i > 0: #for v1 in solutions[:i-1]: #angle = v.angle(v1, deg=True) #print angle f.viewer.plot('rl_solution_%s.png' % (i + 1), n=v.elems)
def discover_better_experimental_model( imagesets, spot_lists, params, dps_params, nproc=1, wide_search_binning=1): assert len(imagesets) == len(spot_lists) assert len(imagesets) > 0 # XXX should check that all the detector and beam objects are the same from dials.algorithms.indexing.indexer import indexer_base spot_lists_mm = [ indexer_base.map_spots_pixel_to_mm_rad( spots, imageset.get_detector(), imageset.get_scan()) for spots, imageset in zip(spot_lists, imagesets)] spot_lists_mm = [] max_cell_list = [] detector = imagesets[0].get_detector() beam = imagesets[0].get_beam() beam_panel = detector.get_panel_intersection(beam.get_s0()) if beam_panel == -1: from libtbx.utils import Sorry raise Sorry, 'input beam does not intersect detector' for imageset, spots in zip(imagesets, spot_lists): if 'imageset_id' not in spots: spots['imageset_id'] = spots['id'] spots_mm = indexer_base.map_spots_pixel_to_mm_rad( spots=spots, detector=imageset.get_detector(), scan=imageset.get_scan()) indexer_base.map_centroids_to_reciprocal_space( spots_mm, detector=imageset.get_detector(), beam=imageset.get_beam(), goniometer=imageset.get_goniometer()) if dps_params.d_min is not None: d_spacings = 1/spots_mm['rlp'].norms() sel = d_spacings > dps_params.d_min spots_mm = spots_mm.select(sel) # derive a max_cell from mm spots if params.max_cell is None: from dials.algorithms.indexing.indexer import find_max_cell max_cell = find_max_cell(spots_mm, max_cell_multiplier=1.3, step_size=45, nearest_neighbor_percentile=0.05).max_cell max_cell_list.append(max_cell) if (params.max_reflections is not None and spots_mm.size() > params.max_reflections): logger.info('Selecting subset of %i reflections for analysis' %params.max_reflections) perm = flex.random_permutation(spots_mm.size()) sel = perm[:params.max_reflections] spots_mm = spots_mm.select(sel) spot_lists_mm.append(spots_mm) if params.max_cell is None: max_cell = flex.median(flex.double(max_cell_list)) else: max_cell = params.max_cell args = [(imageset, spots, max_cell, dps_params) for imageset, spots in zip(imagesets, spot_lists_mm)] from libtbx import easy_mp results = easy_mp.parallel_map( func=run_dps, iterable=args, processes=nproc, method="multiprocessing", preserve_order=True, asynchronous=True, preserve_exception_message=True) solution_lists = [r["solutions"] for r in results] amax_list = [r["amax"] for r in results] assert len(solution_lists) > 0 detector = imagesets[0].get_detector() beam = imagesets[0].get_beam() # perform calculation if dps_params.indexing.improve_local_scope == "origin_offset": discoverer = better_experimental_model_discovery( imagesets, spot_lists_mm, solution_lists, amax_list, dps_params, wide_search_binning=wide_search_binning) new_detector = discoverer.optimize_origin_offset_local_scope() old_beam_centre = detector.get_ray_intersection(beam.get_s0())[1] new_beam_centre = new_detector.get_ray_intersection(beam.get_s0())[1] logger.info("Old beam centre: %.2f mm, %.2f mm" %old_beam_centre) logger.info("New beam centre: %.2f mm, %.2f mm" %new_beam_centre) logger.info("Shift: %.2f mm, %.2f mm" %( matrix.col(old_beam_centre)-matrix.col(new_beam_centre)).elems) return new_detector, beam elif dps_params.indexing.improve_local_scope=="S0_vector": raise NotImplementedError()