Source code for dials.algorithms.symmetry.reindex_to_reference

"""Functions to help with reindexing against a reference dataset."""

from __future__ import annotations

import copy
import logging

from cctbx import sgtbx
from mmtbx.scaling.twin_analyses import twin_laws

import dials.util
from dials.util import Sorry

logger = logging.getLogger(__name__)


[docs] def determine_reindex_operator_against_reference(test_miller_set, reference_miller_set): """Reindex a miller set to match a reference miller set. This function takes two miller arrays, a reference and a test array. The space group is checked to see if any reindexing may be required to give consistent indexing between both datasets. If possible twin operators exist, the different indexing options are tested against the reference set, using the correlation between datasets as the test. Args: test_miller_set (cctbx.miller.array): The input miller set to be reindexed. reference_miller_set (cctbx.miller.array): The reference miller set. Returns: cctbx.sgtbx.change_of_basis_op: The change of basis operator which should be applied to the test dataset to give consistent indexing with the reference. """ if ( reference_miller_set.space_group().type().number() != test_miller_set.space_group().type().number() ): raise Sorry( """Space groups are not equal. Can only reindex against a reference dataset if both dataset are in the same spacegroup.""" ) # Work around surprising behaviour of common_sets, as reported in # https://github.com/dials/dials/issues/2451 if test_miller_set is reference_miller_set: test_miller_set = copy.deepcopy(reference_miller_set) twin_ops = twin_laws(miller_array=test_miller_set.eliminate_sys_absent()).operators twin_ops = [sgtbx.change_of_basis_op(op.operator.as_xyz()) for op in twin_ops] if twin_ops: correlations = [] logger.info( "Possible twin operators identified for space group %s:" % test_miller_set.space_group().info() ) for op in twin_ops: logger.info(op) # Loop through twin operators, calculating cc between two datasets cc = test_miller_set.correlation( reference_miller_set, assert_is_similar_symmetry=False ) correlations.append(cc.coefficient()) for op in twin_ops: reindexed = test_miller_set.change_basis(op) cc = reindexed.correlation( reference_miller_set, assert_is_similar_symmetry=False ) correlations.append(cc.coefficient()) # print out table of results and choose best header = ["Reindex op", "CC to reference"] rows = [["a, b, c (no reindex)", f"{correlations[0]:.5f}"]] for i, op in enumerate(twin_ops): rows.append([str(op), f"{correlations[i + 1]:.5f}"]) logger.info(dials.util.tabulate(rows, header)) best_solution_idx = correlations.index(max(correlations)) logger.info("\nOutcome of analysis against reference dataset:") if best_solution_idx == 0: logger.info("No reindexing required \n") change_of_basis_op = sgtbx.change_of_basis_op("a,b,c") else: logger.info( f"Reindexing required with the twin operator:{twin_ops[best_solution_idx - 1].as_hkl()}\n" ) change_of_basis_op = twin_ops[best_solution_idx - 1] else: logger.info("No twin operators found, no reindexing required \n") change_of_basis_op = sgtbx.change_of_basis_op("a,b,c") return change_of_basis_op