def choose_best_orientation_matrix(self, candidate_orientation_matrices): from dials.algorithms.indexing import model_evaluation solution_scorer = self.params.basis_vector_combinations.solution_scorer if solution_scorer == "weighted": weighted_params = self.params.basis_vector_combinations.weighted solutions = model_evaluation.ModelRankWeighted( power=weighted_params.power, volume_weight=weighted_params.volume_weight, n_indexed_weight=weighted_params.n_indexed_weight, rmsd_weight=weighted_params.rmsd_weight, ) else: filter_params = self.params.basis_vector_combinations.filter solutions = model_evaluation.ModelRankFilter( check_doubled_cell=filter_params.check_doubled_cell, likelihood_cutoff=filter_params.likelihood_cutoff, volume_cutoff=filter_params.volume_cutoff, n_indexed_cutoff=filter_params.n_indexed_cutoff, ) args = [] for cm in candidate_orientation_matrices: sel = self.reflections["id"] == -1 if self.d_min is not None: sel &= 1 / self.reflections["rlp"].norms() > self.d_min xo, yo, zo = self.reflections["xyzobs.mm.value"].parts() imageset_id = self.reflections["imageset_id"] experiments = ExperimentList() for i_expt, expt in enumerate(self.experiments): # XXX Not sure if we still need this loop over self.experiments if expt.scan is not None: start, end = expt.scan.get_oscillation_range() if (end - start) > 360: # only use reflections from the first 360 degrees of the scan sel.set_selected( (imageset_id == i_expt) & (zo > ((start * math.pi / 180) + 2 * math.pi)), False, ) experiments.append( Experiment( imageset=expt.imageset, beam=expt.beam, detector=expt.detector, goniometer=expt.goniometer, scan=expt.scan, crystal=cm, ) ) refl = self.reflections.select(sel) self.index_reflections(experiments, refl) if refl.get_flags(refl.flags.indexed).count(True) == 0: continue from rstbx.dps_core.cell_assessment import SmallUnitCellVolume from dials.algorithms.indexing import non_primitive_basis threshold = self.params.basis_vector_combinations.sys_absent_threshold if threshold and ( self._symmetry_handler.target_symmetry_primitive is None or self._symmetry_handler.target_symmetry_primitive.unit_cell() is None ): try: non_primitive_basis.correct( experiments, refl, self._assign_indices, threshold ) if refl.get_flags(refl.flags.indexed).count(True) == 0: continue except SmallUnitCellVolume: logger.debug( "correct_non_primitive_basis SmallUnitCellVolume error for unit cell %s:", experiments[0].crystal.get_unit_cell(), ) continue except RuntimeError as e: if "Krivy-Gruber iteration limit exceeded" in str(e): logger.debug( "correct_non_primitive_basis Krivy-Gruber iteration limit exceeded error for unit cell %s:", experiments[0].crystal.get_unit_cell(), ) continue raise if ( experiments[0].crystal.get_unit_cell().volume() < self.params.min_cell_volume ): continue if self.params.known_symmetry.space_group is not None: new_crystal, _ = self._symmetry_handler.apply_symmetry( experiments[0].crystal ) if new_crystal is None: continue experiments[0].crystal.update(new_crystal) args.append((experiments, refl)) if len(args) == self.params.basis_vector_combinations.max_refine: break from libtbx import easy_mp evaluator = model_evaluation.ModelEvaluation(self.all_params) results = easy_mp.parallel_map( evaluator.evaluate, args, iterable_type=easy_mp.posiargs, processes=self.params.nproc, preserve_exception_message=True, ) for soln in results: if soln is None: continue solutions.append(soln) if len(solutions): logger.info("Candidate solutions:") logger.info(str(solutions)) best_model = solutions.best_model() logger.debug("best model_likelihood: %.2f", best_model.model_likelihood) logger.debug("best n_indexed: %i", best_model.n_indexed) self.hkl_offset = best_model.hkl_offset return best_model.crystal, best_model.n_indexed else: return None, None
def test_ModelRank(): results = [ model_evaluation.Result( rmsds=(0.0269546226916153, 0.03159452239902618, 0.004208711548775884), fraction_indexed=0.9683976336148051, model_likelihood=0.95846970346759, n_indexed=19152, crystal=Crystal.from_dict( dict( [ ("__id__", "crystal"), ( "real_space_a", ( -45.031874961773504, -14.833784919966813, -48.766092343826806, ), ), ( "real_space_b", (-32.15263553253188, 3.8725711269478085, 59.82290857456796), ), ( "real_space_c", (29.6683003477066, 59.732569113301565, -13.880892871529552), ), ("space_group_hall_symbol", " P 1"), ] ) ), hkl_offset=None, ), model_evaluation.Result( rmsds=(0.0341397658828684, 0.027401396596305812, 0.00427723439147068), fraction_indexed=0.9849825554937554, model_likelihood=0.9562237490188447, n_indexed=19480, crystal=Crystal.from_dict( dict( [ ("__id__", "crystal"), ( "real_space_a", (29.66830034770662, 59.73256911330157, -13.880892871529573), ), ( "real_space_b", (47.516210146598816, -48.77135532028254, 2.824076640788394), ), ( "real_space_c", ( -45.036407933560845, -14.950807536025826, -49.06808637024198, ), ), ("space_group_hall_symbol", " P 1"), ] ) ), hkl_offset=None, ), model_evaluation.Result( rmsds=(0.30456791867888355, 0.15679214175133024, 0.009635577811258947), fraction_indexed=0.33629974212469027, model_likelihood=0.6574428619874397, n_indexed=6651, crystal=Crystal.from_dict( dict( [ ("__id__", "crystal"), ( "real_space_a", ( -11.907050303571122, 34.85499418820148, 30.689745759790572, ), ), ( "real_space_b", (-56.943458237132, 19.90418665217566, -18.37834061045143), ), ( "real_space_c", (-41.63267941211685, -24.82747139443437, 44.5508337593274), ), ("space_group_hall_symbol", " P 1"), ] ) ), hkl_offset=None, ), ] ranker = model_evaluation.ModelRankWeighted() ranker.extend(results) assert list(ranker.score_by_fraction_indexed()) == pytest.approx( [0.02449862002620243, 0.0, 1.550350501381241] ) assert list(ranker.score_by_rmsd_xy()) == pytest.approx( [0.0, 0.07598423386955666, 3.044108569529155] ) assert list(ranker.score_by_volume()) == pytest.approx( [0.44207271296753703, 0.45026641813391066, 0.0] ) assert list(ranker.combined_scores()) == pytest.approx( [0.19602846593366663, 0.20851345109588518, 11.670183660213905] ) assert ( str(ranker) == """\ +-------------------------------------+----------+----------------+------------+-------------+-------------------+-----------+-----------------+-----------------+ | unit_cell | volume | volume score | #indexed | % indexed | % indexed score | rmsd_xy | rmsd_xy score | overall score | |-------------------------------------+----------+----------------+------------+-------------+-------------------+-----------+-----------------+-----------------| | 68.02 68.03 68.12 109.6 109.5 109.3 | 242890 | 0.44 | 19152 | 97 | 0.02 | 0.04 | 0 | 0.2 | | 68.12 68.15 68.26 109.5 109.4 109.4 | 244274 | 0.45 | 19480 | 98 | 0 | 0.04 | 0.08 | 0.21 | | 47.94 63.06 65.84 75.2 71.6 74.5 | 178786 | 0 | 6651 | 34 | 1.55 | 0.34 | 3.04 | 11.67 | +-------------------------------------+----------+----------------+------------+-------------+-------------------+-----------+-----------------+-----------------+""" ) best = ranker.best_model() assert best.n_indexed == 19152 ranker = model_evaluation.ModelRankFilter() ranker.extend(results) best = ranker.best_model() assert best.n_indexed == 19152 assert ( str(ranker) == """\ +-------------------------------------+----------+-------------+--------------------+--------------+ | unit_cell | volume | n_indexed | fraction_indexed | likelihood | |-------------------------------------+----------+-------------+--------------------+--------------| | 68.02 68.03 68.12 109.6 109.5 109.3 | 242890 | 19152 | 97 | 0.96 | | 68.12 68.15 68.26 109.5 109.4 109.4 | 244274 | 19480 | 98 | 0.96 | | 47.94 63.06 65.84 75.2 71.6 74.5 | 178786 | 6651 | 34 | 0.66 | +-------------------------------------+----------+-------------+--------------------+--------------+""" )