Exemple #1
0
def test_ScanVaryingCrystalOrientationParameterisation_random(plots=False):
    """Test a ScanVaryingCrystalOrientationParameterisation with
    random initial orientations, random parameter shifts and random times"""

    vmp = _TestScanVaryingModelParameterisation()

    attempts = 100
    failures = 0
    null_mat = matrix.sqr((0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0))

    for i in range(attempts):
        # make a new P1 random crystal and parameterise it
        a = random.uniform(10, 50) * vmp.random_direction_close_to(
            matrix.col((1, 0, 0)))
        b = random.uniform(10, 50) * vmp.random_direction_close_to(
            matrix.col((0, 1, 0)))
        c = random.uniform(10, 50) * vmp.random_direction_close_to(
            matrix.col((0, 0, 1)))
        xl = Crystal(a, b, c, space_group_symbol="P 1")

        xl_op = _TestOrientationModel(50, xl, vmp.image_range, 5)

        # How many parameters?
        num_param = xl_op.num_free()

        # apply random parameter shifts to the orientation (2.0 mrad each
        # checkpoint)
        p_vals = xl_op.get_param_vals()
        sigmas = [2.0] * len(p_vals)
        new_vals = random_param_shift(p_vals, sigmas)
        xl_op.set_param_vals(new_vals)

        # select random time point at which to make comparisons
        t = random.uniform(*vmp.image_range)
        xl_op.set_time_point(t)

        # compare analytical and finite difference derivatives
        xl_op_an_ds_dp = xl_op.get_ds_dp()
        xl_op_fd_ds_dp = get_fd_gradients(xl_op,
                                          [1.0e-6 * math.pi / 180] * num_param)

        for j in range(num_param):
            assert approx_equal((xl_op_fd_ds_dp[j] - xl_op_an_ds_dp[j]),
                                null_mat,
                                eps=1.0e-6), textwrap.dedent("""\
        Failure in try {i}
        failure for parameter number {j}
        of the orientation parameterisation
        with fd_ds_dp =
        {fd}
        and an_ds_dp =
        {an}
        so that difference fd_ds_dp - an_ds_dp =
        {diff}
        """).format(
                                    i=i,
                                    j=j,
                                    fd=xl_op_fd_ds_dp[j],
                                    an=xl_op_an_ds_dp[j],
                                    diff=xl_op_fd_ds_dp[j] - xl_op_an_ds_dp[j],
                                )
from cctbx import uctbx
from dxtbx.model import Crystal

from simtbx.nanoBragg.nanoBragg_crystal import NBcrystal
import numpy as np
import sys
if "--cuda" in sys.argv:
    import os
    os.environ["DIFFBRAGG_USE_CUDA"] = "1"

ucell = (70, 60, 50, 90.0, 110, 90.0)
symbol = "C121"
a_real, b_real, c_real = sqr(
    uctbx.unit_cell(
        ucell).orthogonalization_matrix()).transpose().as_list_of_lists()
C = Crystal(a_real, b_real, c_real, symbol)

nbr = NBcrystal()
nbr.dxtbx_crystal = C

S = sim_data.SimData(use_default_crystal=True)
S.crystal = nbr
S.instantiate_diffBragg(auto_set_spotscale=True)
S.D.add_diffBragg_spots()
img = S.D.raw_pixels.as_numpy_array()

# simulate the primitive cell directly
to_p1 = C.get_space_group().info().change_of_basis_op_to_primitive_setting()
Cp1 = C.change_basis(to_p1)
nbr2 = NBcrystal()
nbr2.dxtbx_crystal = Cp1
Exemple #3
0
def dump(experiments, directory):
    """
    Dump the experiments in mosflm format

    :param experiments: The experiments to dump
    :param directory: The directory to write to
    """
    for i, experiment in enumerate(experiments):
        suffix = ""
        if len(experiments) > 1:
            suffix = "_%i" % (i + 1)

        sub_dir = f"{directory}{suffix}"
        if not os.path.isdir(sub_dir):
            os.makedirs(sub_dir)
        detector = experiment.detector
        beam = experiment.beam
        goniometer = experiment.goniometer

        # XXX imageset is getting the experimental geometry from the image files
        # rather than the input models.expt file
        imageset = experiment.imageset

        R_to_mosflm = align_reference_frame(
            beam.get_s0(),
            (1.0, 0.0, 0.0),
            goniometer.get_rotation_axis(),
            (0.0, 0.0, 1.0),
        )

        cryst = experiment.crystal
        cryst = cryst.change_basis(
            cryst.get_space_group().info().change_of_basis_op_to_reference_setting()
        )
        A = matrix.sqr(cryst.get_A())
        A_inv = A.inverse()

        real_space_a = R_to_mosflm * A_inv.elems[:3]
        real_space_b = R_to_mosflm * A_inv.elems[3:6]
        real_space_c = R_to_mosflm * A_inv.elems[6:9]

        cryst_mosflm = Crystal(
            real_space_a,
            real_space_b,
            real_space_c,
            space_group=cryst.get_space_group(),
        )
        A_mosflm = matrix.sqr(cryst_mosflm.get_A())
        U_mosflm = matrix.sqr(cryst_mosflm.get_U())
        assert U_mosflm.is_r3_rotation_matrix(), U_mosflm
        w = beam.get_wavelength()

        index_mat = os.path.join(sub_dir, "index.mat")
        mosflm_in = os.path.join(sub_dir, "mosflm.in")
        print(f"Exporting experiment to {index_mat} and {mosflm_in}")

        with open(index_mat, "w") as f:
            f.write(format_mosflm_mat(w * A_mosflm, U_mosflm, cryst.get_unit_cell()))

        img_dir, template = os.path.split(imageset.get_template())
        symmetry = cryst_mosflm.get_space_group().type().number()
        beam_centre = tuple(reversed(detector[0].get_beam_centre(beam.get_s0())))
        distance = detector[0].get_directed_distance()

        with open(mosflm_in, "w") as f:
            f.write(
                write_mosflm_input(
                    directory=img_dir,
                    template=template,
                    symmetry=symmetry,
                    beam_centre=beam_centre,
                    distance=distance,
                    mat_file="index.mat",
                )
            )
Exemple #4
0
def test_stills_indexer_multi_lattice_bug_MosaicSauter2014(
        dials_regression, tmpdir):
    """Problem: In stills_indexer, before calling the refine function, the
    experiment list contains a list of dxtbx crystal models (that are not
    MosaicSauter2014 models). The conversion to MosaicSauter2014 is made
    during the refine step when functions from nave_parameters is called.
    If the experiment list contains more than 1 experiment, for eg.
    multiple lattices, only the first crystal gets assigned mosaicity. In
    actuality, all crystal models should be assigned mosaicity. This test
    only compares whether or not all crystal models have been assigned a
    MosaicSauter2014 model."""

    import dxtbx.model
    from dxtbx.model import Crystal
    from dxtbx.model.experiment_list import (
        Experiment,
        ExperimentList,
        ExperimentListFactory,
    )

    from dials.algorithms.indexing.stills_indexer import StillsIndexer
    from dials.array_family import flex
    from dials.command_line.stills_process import (
        phil_scope as stills_process_phil_scope, )

    experiment_data = os.path.join(
        dials_regression,
        "refinement_test_data",
        "cspad_refinement",
        "cspad_refined_experiments_step6_level2_300.json",
    )
    reflection_data = os.path.join(
        dials_regression,
        "refinement_test_data",
        "cspad_refinement",
        "cspad_reflections_step7_300.pickle",
    )

    refl = flex.reflection_table.from_file(reflection_data)
    explist = ExperimentListFactory.from_json_file(experiment_data,
                                                   check_format=False)[0:2]
    reflist = refl.select(
        refl["id"] < 2)  # Only use the first 2 for convenience
    # Construct crystal models that don't have mosaicity. These A,B,C values are the same
    # as read in from the dials_regression folder
    # Crystal-0
    cs0 = Crystal(explist[0].crystal)
    exp0 = Experiment(
        imageset=explist[0].imageset,
        beam=explist[0].beam,
        detector=explist[0].detector,
        goniometer=None,
        scan=None,
        crystal=cs0,
    )

    # Crystal-1
    cs1 = Crystal(explist[1].crystal)
    exp1 = Experiment(
        imageset=explist[1].imageset,
        beam=explist[1].beam,
        detector=explist[1].detector,
        goniometer=None,
        scan=None,
        crystal=cs1,
    )
    # Construct a new experiment_list that will be passed on for refinement
    unrefined_explist = ExperimentList([exp0, exp1])
    # Get default params from stills_process and construct StillsIndexer, then run refinement
    params = stills_process_phil_scope.extract()
    SI = StillsIndexer(reflist, unrefined_explist, params=params)
    refined_explist, new_reflist = SI.refine(unrefined_explist, reflist)
    # Now check whether the models have mosaicity after stills_indexer refinement
    # Also check that mosaicity values are within expected limits
    for ii, crys in enumerate(refined_explist.crystals()):
        assert isinstance(crys, dxtbx.model.MosaicCrystalSauter2014)
        if ii == 0:
            assert crys.get_domain_size_ang() == pytest.approx(2242.0, rel=0.1)
        if ii == 1:
            assert crys.get_domain_size_ang() == pytest.approx(2689.0, rel=0.1)
Exemple #5
0
    def __init__(self, test_nave_model=False):
        # Set up experimental models with regular geometry
        from dxtbx.model import BeamFactory, DetectorFactory, GoniometerFactory

        # Beam along the Z axis
        self.beam = BeamFactory.make_beam(unit_s0=matrix.col((0, 0, 1)),
                                          wavelength=1.0)

        # Goniometer (used only for index generation) along X axis
        self.goniometer = GoniometerFactory.known_axis(matrix.col((1, 0, 0)))

        # Detector fast, slow along X, -Y; beam in the centre, 200 mm distance
        dir1 = matrix.col((1, 0, 0))
        dir2 = matrix.col((0, -1, 0))
        centre = matrix.col((0, 0, 200))
        npx_fast = npx_slow = 1000
        pix_size = 0.2
        origin = centre - (0.5 * npx_fast * pix_size * dir1 +
                           0.5 * npx_slow * pix_size * dir2)
        self.detector = DetectorFactory.make_detector(
            "PAD",
            dir1,
            dir2,
            origin,
            (pix_size, pix_size),
            (npx_fast, npx_slow),
            (0, 1.0e6),
        )

        # Cubic 100 A^3 crystal
        a = matrix.col((100, 0, 0))
        b = matrix.col((0, 100, 0))
        c = matrix.col((0, 0, 100))

        if test_nave_model:
            from dxtbx.model import MosaicCrystalSauter2014

            self.crystal = MosaicCrystalSauter2014(a,
                                                   b,
                                                   c,
                                                   space_group_symbol="P 1")
            self.crystal.set_half_mosaicity_deg(500)
            self.crystal.set_domain_size_ang(0.2)
        else:
            from dxtbx.model import Crystal

            self.crystal = Crystal(a, b, c, space_group_symbol="P 1")

        # Collect these models in an Experiment (ignoring the goniometer)
        from dxtbx.model.experiment_list import Experiment

        self.experiment = Experiment(
            beam=self.beam,
            detector=self.detector,
            goniometer=None,
            scan=None,
            crystal=self.crystal,
            imageset=None,
        )

        # Generate some reflections
        self.reflections = self.generate_reflections()
Exemple #6
0
class Model:
    def __init__(self, test_nave_model=False):
        # Set up experimental models with regular geometry
        from dxtbx.model import BeamFactory, DetectorFactory, GoniometerFactory

        # Beam along the Z axis
        self.beam = BeamFactory.make_beam(unit_s0=matrix.col((0, 0, 1)),
                                          wavelength=1.0)

        # Goniometer (used only for index generation) along X axis
        self.goniometer = GoniometerFactory.known_axis(matrix.col((1, 0, 0)))

        # Detector fast, slow along X, -Y; beam in the centre, 200 mm distance
        dir1 = matrix.col((1, 0, 0))
        dir2 = matrix.col((0, -1, 0))
        centre = matrix.col((0, 0, 200))
        npx_fast = npx_slow = 1000
        pix_size = 0.2
        origin = centre - (0.5 * npx_fast * pix_size * dir1 +
                           0.5 * npx_slow * pix_size * dir2)
        self.detector = DetectorFactory.make_detector(
            "PAD",
            dir1,
            dir2,
            origin,
            (pix_size, pix_size),
            (npx_fast, npx_slow),
            (0, 1.0e6),
        )

        # Cubic 100 A^3 crystal
        a = matrix.col((100, 0, 0))
        b = matrix.col((0, 100, 0))
        c = matrix.col((0, 0, 100))

        if test_nave_model:
            from dxtbx.model import MosaicCrystalSauter2014

            self.crystal = MosaicCrystalSauter2014(a,
                                                   b,
                                                   c,
                                                   space_group_symbol="P 1")
            self.crystal.set_half_mosaicity_deg(500)
            self.crystal.set_domain_size_ang(0.2)
        else:
            from dxtbx.model import Crystal

            self.crystal = Crystal(a, b, c, space_group_symbol="P 1")

        # Collect these models in an Experiment (ignoring the goniometer)
        from dxtbx.model.experiment_list import Experiment

        self.experiment = Experiment(
            beam=self.beam,
            detector=self.detector,
            goniometer=None,
            scan=None,
            crystal=self.crystal,
            imageset=None,
        )

        # Generate some reflections
        self.reflections = self.generate_reflections()

    def generate_reflections(self):
        """Use reeke_model to generate indices of reflections near to the Ewald
        sphere that might be observed on a still image. Build a reflection_table
        of these."""
        from cctbx.sgtbx import space_group_info

        space_group_type = space_group_info("P 1").group().type()

        # create a ReekeIndexGenerator
        UB = self.crystal.get_A()
        axis = self.goniometer.get_rotation_axis()
        s0 = self.beam.get_s0()
        # use the same UB at the beginning and end - the margin parameter ensures
        # we still have indices close to the Ewald sphere generated
        from dials.algorithms.spot_prediction import ReekeIndexGenerator

        r = ReekeIndexGenerator(UB,
                                UB,
                                space_group_type,
                                axis,
                                s0,
                                dmin=1.5,
                                margin=1)

        # generate indices
        hkl = r.to_array()
        nref = len(hkl)

        # create a reflection table
        from dials.array_family import flex

        table = flex.reflection_table()
        table["flags"] = flex.size_t(nref, 0)
        table["id"] = flex.int(nref, 0)
        table["panel"] = flex.size_t(nref, 0)
        table["miller_index"] = flex.miller_index(hkl)
        table["entering"] = flex.bool(nref, True)
        table["s1"] = flex.vec3_double(nref)
        table["xyzcal.mm"] = flex.vec3_double(nref)
        table["xyzcal.px"] = flex.vec3_double(nref)

        return table
Exemple #7
0
class Test(object):

  def __init__(self, test_nave_model = False):

    # Set up experimental models with regular geometry
    from dxtbx.model import BeamFactory
    from dxtbx.model import GoniometerFactory
    from dxtbx.model import DetectorFactory

    # Beam along the Z axis
    self.beam = BeamFactory.make_beam(unit_s0 = matrix.col((0, 0, 1)),
                                       wavelength = 1.0)

    # Goniometer (used only for index generation) along X axis
    self.goniometer = GoniometerFactory.known_axis(matrix.col((1, 0, 0)))

    # Detector fast, slow along X, -Y; beam in the centre, 200 mm distance
    dir1 = matrix.col((1, 0, 0))
    dir2 = matrix.col((0, -1, 0))
    n = matrix.col((0, 0, 1))
    centre = matrix.col((0, 0, 200))
    npx_fast = npx_slow = 1000
    pix_size = 0.2
    origin = centre - (0.5 * npx_fast * pix_size * dir1 +
                       0.5 * npx_slow * pix_size * dir2)
    self.detector = DetectorFactory.make_detector("PAD",
                        dir1, dir2, origin,
                        (pix_size, pix_size),
                        (npx_fast, npx_slow),
                        (0, 1.e6))

    # Cubic 100 A^3 crystal
    a = matrix.col((100, 0, 0))
    b = matrix.col((0, 100, 0))
    c = matrix.col((0, 0, 100))

    if test_nave_model:
      from dxtbx.model import MosaicCrystalSauter2014
      self.crystal = MosaicCrystalSauter2014(a, b, c, space_group_symbol = "P 1")
      self.crystal.set_half_mosaicity_deg(500)
      self.crystal.set_domain_size_ang(0.2)
    else:
      from dxtbx.model import Crystal
      self.crystal = Crystal(a, b, c, space_group_symbol = "P 1")

    # Collect these models in an Experiment (ignoring the goniometer)
    from dxtbx.model.experiment_list import Experiment
    self.experiment = Experiment(beam=self.beam, detector=self.detector,
      goniometer=None, scan=None, crystal=self.crystal, imageset=None)

    # Generate some reflections
    self.reflections = self.generate_reflections()

    return

  def generate_reflections(self):
    """Use reeke_model to generate indices of reflections near to the Ewald
    sphere that might be observed on a still image. Build a reflection_table
    of these."""
    from cctbx.sgtbx import space_group_info

    space_group_type = space_group_info("P 1").group().type()

    # create a ReekeIndexGenerator
    UB = self.crystal.get_A()
    axis = self.goniometer.get_rotation_axis()
    s0 = self.beam.get_s0()
    dmin = 1.5
    # use the same UB at the beginning and end - the margin parameter ensures
    # we still have indices close to the Ewald sphere generated
    from dials.algorithms.spot_prediction import ReekeIndexGenerator
    r = ReekeIndexGenerator(UB, UB, space_group_type, axis, s0, dmin=1.5, margin=1)

    # generate indices
    hkl = r.to_array()
    nref = len(hkl)

    # create a reflection table
    from dials.array_family import flex
    table = flex.reflection_table()
    table['flags'] = flex.size_t(nref, 0)
    table['id']    = flex.int(nref, 0)
    table['panel'] = flex.size_t(nref, 0)
    table['miller_index'] = flex.miller_index(hkl)
    table['entering']     = flex.bool(nref, True)
    table['s1']           = flex.vec3_double(nref)
    table['xyzcal.mm']    = flex.vec3_double(nref)
    table['xyzcal.px']    = flex.vec3_double(nref)

    return table

  def run(self):

    # cache objects from the model
    UB = matrix.sqr(self.crystal.get_A())
    s0 = matrix.col(self.beam.get_s0())
    es_radius = s0.length()

    # create the predictor and predict for reflection table
    from dials.algorithms.spot_prediction import StillsReflectionPredictor
    predictor = StillsReflectionPredictor(self.experiment)
    predictor.for_reflection_table(self.reflections, UB)

    # for every reflection, reconstruct relp rotated to the Ewald sphere (vector
    # r) and unrotated relp (vector q), calculate the angle between them and
    # compare with delpsical.rad
    from libtbx.test_utils import approx_equal
    for ref in self.reflections:
      r = matrix.col(ref['s1']) - s0
      q = UB * matrix.col(ref['miller_index'])
      tst_radius = (s0 + q).length()
      sgn = -1 if tst_radius > es_radius else 1
      delpsi = sgn*r.accute_angle(q)
      assert approx_equal(delpsi, ref['delpsical.rad'])

    print "OK"

  def spherical_relp(self):

    # cache objects from the model
    UB = matrix.sqr(self.crystal.get_A())
    s0 = matrix.col(self.beam.get_s0())
    es_radius = s0.length()

    # create the predictor and predict for reflection table
    from dials.algorithms.spot_prediction import StillsReflectionPredictor
    predictor = StillsReflectionPredictor(self.experiment, spherical_relp=True)
    predictor.for_reflection_table(self.reflections, UB)

    # for every reflection, reconstruct relp centre q, calculate s1 according
    # to the formula in stills_prediction_nave3.pdf and compare
    from libtbx.test_utils import approx_equal
    for ref in self.reflections:
      q = UB * matrix.col(ref['miller_index'])
      radicand = q.length_sq() + 2.0 * q.dot(s0) + s0.length_sq()
      assert radicand > 0.0
      denom = sqrt(radicand)
      s1 = es_radius * (q + s0) / denom
      assert approx_equal(s1, ref['s1'])

    print "OK"
def test_crystal_with_scan_points():
  from dxtbx.model import Crystal, CrystalFactory
  from scitbx import matrix

  real_space_a = matrix.col((35.2402102454, -7.60002142787, 22.080026774))
  real_space_b = matrix.col((22.659572494, 1.47163505925, -35.6586361881))
  real_space_c = matrix.col((5.29417246554, 38.9981792999, 4.97368666613))

  c1 = Crystal(
      real_space_a=real_space_a,
      real_space_b=real_space_b,
      real_space_c=real_space_c,
      space_group_symbol="P 1 2/m 1")

  A = c1.get_A()
  c1.set_A_at_scan_points([A for i in range(5)])

  # Set the B covariance. The values are nonsense, just ensure they are
  # all different
  from scitbx.array_family import flex
  cov_B = flex.double(range((9*9))) * 1e-5
  c1.set_B_covariance(cov_B)
  cov_B.reshape(flex.grid(1, 9, 9))
  cov_B_array = flex.double(flex.grid(5, 9, 9))
  for i in range(5):
    cov_B_array[i:(i+1), :, :] = cov_B
  c1.set_B_covariance_at_scan_points(cov_B_array)
  cov_B = c1.get_B_covariance()

  d = c1.to_dict()
  c2 = CrystalFactory.from_dict(d)
  eps = 1e-9
  for Acomp in d['A_at_scan_points']:
    for e1, e2 in zip(A, Acomp):
      assert abs(e1 - e2) <= eps
  for covBcomp in d['B_covariance_at_scan_points']:
    for e1, e2 in zip(cov_B, covBcomp):
      assert abs(e1 - e2) <= eps

  assert c1 == c2
Exemple #9
0
def test_map_to_minimum_cell():
    # Input and expected output
    input_ucs = [
        (39.7413, 183.767, 140.649, 90, 90, 90),
        (40.16, 142.899, 92.4167, 90, 102.48, 90),
        (180.613, 40.1558, 142.737, 90, 90.0174, 90),
    ]
    input_sgs = ["C 2 2 21", "P 1 2 1", "C 1 2 1"]
    input_hkl = [
        [(1, -75, -71), (1, -73, -70), (1, -71, -69)],
        [(14, -37, -36), (-2, -35, -46), (-3, -34, -47)],
        [(-31, -5, -3), (-25, -3, -3), (-42, -8, -2)],
    ]
    expected_ucs = [
        (39.7413, 94.00755450320204, 140.649, 90.0, 90.0, 77.79717980856927),
        (40.16, 92.46399390642911, 142.899, 90.0, 90.0, 77.3882749092846),
        (
            40.1558,
            92.51154528306184,
            142.73699999999997,
            89.9830147351441,
            90.0,
            77.46527404307477,
        ),
    ]
    expected_output_hkl = [
        [(-1, 37, -71), (-1, 36, -70), (-1, 35, -69)],
        [(-14, 22, 37), (2, 48, 35), (3, 50, 34)],
        [(-5, 13, -3), (-3, 11, -3), (-8, 17, -2)],
    ]

    # Setup the input experiments and reflection tables
    expts = ExperimentList()
    reflections = []
    for uc, sg, hkl in zip(input_ucs, input_sgs, input_hkl):
        uc = uctbx.unit_cell(uc)
        sg = sgtbx.space_group_info(sg).group()
        B = scitbx.matrix.sqr(uc.fractionalization_matrix()).transpose()
        expts.append(
            Experiment(crystal=Crystal(B, space_group=sg, reciprocal=True)))
        refl = flex.reflection_table()
        refl["miller_index"] = flex.miller_index(hkl)
        reflections.append(refl)

    # Actually run the method we are testing
    cb_ops = change_of_basis_ops_to_minimum_cell(
        expts,
        max_delta=5,
        relative_length_tolerance=0.05,
        absolute_angle_tolerance=2)
    cb_ops_as_xyz = [cb_op.as_xyz() for cb_op in cb_ops]
    # Actual cb_ops are machine dependent (sigh)
    assert (cb_ops_as_xyz == [
        "-x+y,-2*y,z",
        "-x+z,-z,-y",
        "x+y,-2*x,z",
    ] or cb_ops_as_xyz == ["x-y,2*y,z", "x-z,z,-y", "-x-y,2*x,z"])

    expts_min, reflections = apply_change_of_basis_ops(expts, reflections,
                                                       cb_ops)
    # Verify that the unit cells have been transformed as expected
    for expt, uc in zip(expts, expected_ucs):
        assert expt.crystal.get_unit_cell().parameters() == pytest.approx(
            uc, abs=4e-2)

    # Space group should be set to P1
    assert [
        expt.crystal.get_space_group().type().number() for expt in expts_min
    ] == [
        1,
        1,
        1,
    ]

    # Verify that the reflections have been reindexed as expected
    # Because the exact choice of minimum cell can be platform-dependent,
    # compare the magnitude, but not the sign of the output hkl values
    for refl, expected_hkl in zip(reflections, expected_output_hkl):
        for hkl, e_hkl in zip(refl["miller_index"], expected_hkl):
            assert [abs(h) for h in hkl] == [abs(eh) for eh in e_hkl]
Exemple #10
0
def test_change_of_basis_ops_to_minimum_cell_1037(mocker):
    # See https://github.com/dials/dials/issues/1037

    input_ucs = [
        (
            4.805202948916906,
            12.808064769657364,
            16.544899201125446,
            106.45808502003258,
            90.0065567098825,
            100.77735674275475,
        ),
        (
            4.808011343212577,
            12.821894835790472,
            16.557339561965573,
            106.48431244651402,
            90.0252848479048,
            100.77252933676507,
        ),
        (
            4.8096632137789985,
            12.815648858527567,
            16.55931712239122,
            106.48990701341536,
            90.01703141314147,
            100.80397887485773,
        ),
        (
            4.807294085194974,
            12.822386757910516,
            16.560411742466663,
            106.43185845358086,
            90.02067929544215,
            100.79522302759383,
        ),
    ]

    # Setup the input experiments and reflection tables
    expts = ExperimentList()
    for uc in input_ucs:
        uc = uctbx.unit_cell(uc)
        sg = sgtbx.space_group_info("P1").group()
        B = scitbx.matrix.sqr(uc.fractionalization_matrix()).transpose()
        expts.append(
            Experiment(crystal=Crystal(B, space_group=sg, reciprocal=True)))

    # We want to spy on the return value of this function
    mocker.spy(symmetry, "unit_cells_are_similar_to")

    # Actually run the method we are testing
    cb_ops = change_of_basis_ops_to_minimum_cell(
        expts,
        max_delta=5,
        relative_length_tolerance=0.05,
        absolute_angle_tolerance=2)
    import pytest_mock

    if getattr(pytest_mock, "version", "").startswith("1."):
        assert symmetry.unit_cells_are_similar_to.return_value is True
    else:
        assert symmetry.unit_cells_are_similar_to.spy_return is True
    cb_ops_as_xyz = [cb_op.as_xyz() for cb_op in cb_ops]
    assert len(set(cb_ops_as_xyz)) == 1
    # Actual cb_ops are machine dependent (sigh)
    assert cb_ops_as_xyz[0] in ("x,y,z", "-x,y,-z", "x-y,-y,-z")
Exemple #11
0
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 |
+-------------------------------------+----------+-------------+--------------------+--------------+"""
            )
Exemple #12
0
class Simulation:
    def __init__(self, override_fdp=None):

        # Set up detector
        distance = 100
        pixel_size = 0.1
        image_size = (1000, 1000)
        beam_centre_mm = (
            pixel_size * image_size[0] / 2,
            pixel_size * image_size[1] / 2,
        )
        self.detector = DetectorFactory().simple(
            "CCD",
            distance,
            beam_centre_mm,
            "+x",
            "-y",
            (pixel_size, pixel_size),
            image_size,
        )

        # Set up beam
        self.beam = BeamFactory().simple(wavelength=1)

        # Set up scan
        sequence_width = 90.0
        osc_start = 0.0
        image_width = 0.2
        oscillation = (osc_start, image_width)

        nframes = int(math.ceil(sequence_width / image_width))
        image_range = (1, nframes)
        exposure_times = 0.0
        epochs = [0] * nframes
        self.scan = ScanFactory().make_scan(
            image_range, exposure_times, oscillation, epochs, deg=True
        )

        # Set up goniometer
        self.goniometer = GoniometerFactory.known_axis(self.detector[0].get_fast_axis())

        # Set up simulated structure factors
        self.sfall = self.fcalc_from_pdb(
            resolution=1.6, algorithm="direct", override_fdp=override_fdp
        )

        # Set up crystal
        self.crystal = Crystal(
            real_space_a=(50, 0, 0),
            real_space_b=(0, 60, 0),
            real_space_c=(0, 0, 70),
            space_group_symbol="P1",
        )
        axis = matrix.col(
            elems=(-0.14480368275412925, -0.6202131724405818, -0.7709523423610766)
        )
        self.crystal.set_U(
            axis.axis_and_angle_as_r3_rotation_matrix(angle=0.625126343998969)
        )

    def fcalc_from_pdb(self, resolution, algorithm=None, override_fdp=None):
        pdb_inp = pdb.input(source_info=None, lines=_pdb_lines)
        xray_structure = pdb_inp.xray_structure_simple()
        wavelength = self.beam.get_wavelength()
        #
        # take a detour to calculate anomalous contribution of every atom
        scatterers = xray_structure.scatterers()
        for sc in scatterers:
            expected_henke = henke.table(sc.element_symbol()).at_angstrom(wavelength)
            sc.fp = expected_henke.fp()
            sc.fdp = override_fdp if override_fdp is not None else expected_henke.fdp()

        # how do we do bulk solvent?
        primitive_xray_structure = xray_structure.primitive_setting()
        P1_primitive_xray_structure = primitive_xray_structure.expand_to_p1()
        fcalc = P1_primitive_xray_structure.structure_factors(
            d_min=resolution, anomalous_flag=True, algorithm=algorithm
        ).f_calc()
        return fcalc.amplitudes()

    def set_varying_beam(self, along="fast", npixels_drift=5):
        assert along in ["fast", "slow", "both"]
        num_scan_points = self.scan.get_num_images() + 1
        s0 = matrix.col(self.beam.get_s0())
        beam_centre_px = self.detector[0].get_beam_centre_px(s0)
        if along == "fast":
            start_beam_centre = (
                beam_centre_px[0] - npixels_drift / 2,
                beam_centre_px[1],
            )
            end_beam_centre = (beam_centre_px[0] + npixels_drift / 2, beam_centre_px[1])
        elif along == "slow":
            start_beam_centre = (
                beam_centre_px[0],
                beam_centre_px[1] - npixels_drift / 2,
            )
            end_beam_centre = (beam_centre_px[0], beam_centre_px[1] + npixels_drift / 2)
        elif along == "both":
            offset = math.sqrt(2.0) * npixels_drift / 4.0
            start_beam_centre = (beam_centre_px[0] - offset, beam_centre_px[1] - offset)
            end_beam_centre = (beam_centre_px[0] + offset, beam_centre_px[1] + offset)

        start_lab = matrix.col(self.detector[0].get_pixel_lab_coord(start_beam_centre))
        end_lab = matrix.col(self.detector[0].get_pixel_lab_coord(end_beam_centre))
        axis = start_lab.cross(end_lab).normalize()
        full_angle = start_lab.angle(end_lab)
        angle_step = full_angle / self.scan.get_num_images()
        angles = [e * angle_step for e in range(num_scan_points)]

        start_s0 = start_lab.normalize() * s0.length()
        s0_list = [start_s0.rotate_around_origin(axis=axis, angle=e) for e in angles]

        self.beam.set_s0_at_scan_points(s0_list)
Exemple #13
0
# Thermolysin
# uc = unit_cell((93,93,131,90,90,120.0))
# sg = space_group_info("P 61 2 2").group()

# Lysozyme
uc = unit_cell((77, 77, 37, 90, 90, 90))
sg = space_group_info("P 43 21 2").group()

print(uc)
print(sg.info())

direct_matrix = sqr(uc.orthogonalization_matrix()).transpose()
crystal = Crystal(
    direct_matrix * col((1, 0, 0)),
    direct_matrix * col((0, 1, 0)),
    direct_matrix * col((0, 0, 1)),
    sg,
)

co = crystal_orientation(crystal.get_A(), basis_type.reciprocal)

print(crystal)
print(co)

ok_ops = []
bad_ops = []


def test_op(op):
    print("=" * 80)
    print("COB:", op)
    os.environ["DIFFBRAGG_USE_CUDA"]="1"

import numpy as np
import pylab as plt
from scipy.stats import linregress
from scipy.spatial.transform import Rotation
from simtbx.nanoBragg import sim_data
from scitbx.matrix import sqr, rec
from cctbx import uctbx
from dxtbx.model import Crystal

ucell = (70, 60, 50, 90.0, 110, 90.0)
symbol = "C121"

a_real, b_real, c_real = sqr(uctbx.unit_cell(ucell).orthogonalization_matrix()).transpose().as_list_of_lists()
C = Crystal(a_real, b_real, c_real, symbol)

# random raotation
rotation = Rotation.random(num=1, random_state=101)[0]
Q = rec(rotation.as_quat(), n=(4, 1))
rot_ang, rot_axis = Q.unit_quaternion_as_axis_and_angle()
C.rotate_around_origin(rot_axis, rot_ang)

S = sim_data.SimData(use_default_crystal=True)
S.crystal.dxtbx_crystal = C
S.detector = sim_data.SimData.simple_detector(180, 0.1, (1024, 1024))
S.instantiate_diffBragg(verbose=0, oversample=0, auto_set_spotscale=True)
S.D.spot_scale = 100000
#S.D.oversample = 5

Ncells_def_id = 21
Exemple #15
0
def test_scale_script_prepare_input():
    """Test prepare_input method of scaling script."""

    # test the components of the scaling script directly with a test reflection
    # table, experiments list and params.

    params, exp, reflections = generate_test_input()
    # try to pass in unequal number of reflections and experiments
    reflections.append(generate_test_reflections())
    with pytest.raises(Sorry):
        _ = Script(params, exp, reflections)

    params, exp, reflections = generate_test_input()
    # Try to use use_datasets when not identifiers set
    params.dataset_selection.use_datasets = ["0"]
    with pytest.raises(Sorry):
        _ = Script(params, exp, reflections)
    # Try to use use_datasets when not identifiers set
    params.dataset_selection.use_datasets = None
    params.dataset_selection.exclude_datasets = ["0"]
    with pytest.raises(Sorry):
        _ = Script(params, exp, reflections)

    # Now make two experiments with identifiers and select on them
    params, exp, reflections = generate_test_input(n=2)
    exp[0].identifier = "0"
    reflections[0].experiment_identifiers()[0] = "0"
    exp[1].identifier = "1"
    reflections[1].experiment_identifiers()[0] = "1"
    list1 = ExperimentList().append(exp[0])
    list2 = ExperimentList().append(exp[1])
    reflections[0].assert_experiment_identifiers_are_consistent(list1)
    reflections[1].assert_experiment_identifiers_are_consistent(list2)
    params.dataset_selection.use_datasets = ["0"]
    params, exp, script_reflections = Script.prepare_input(
        params, exp, reflections)

    assert len(script_reflections) == 1

    # Try again, this time excluding
    params, exp, reflections = generate_test_input(n=2)
    exp[0].identifier = "0"
    reflections[0].experiment_identifiers()[0] = "0"
    exp[1].identifier = "1"
    reflections[1].experiment_identifiers()[0] = "1"
    params.dataset_selection.exclude_datasets = ["0"]
    params, exp, script_reflections = Script.prepare_input(
        params, exp, reflections)

    assert len(script_reflections) == 1
    assert script_reflections[0] is reflections[1]

    # Try having two unequal space groups
    params, exp, reflections = generate_test_input(n=2)
    exp_dict = {
        "__id__": "crystal",
        "real_space_a": [1.0, 0.0, 0.0],
        "real_space_b": [0.0, 1.0, 0.0],
        "real_space_c": [0.0, 0.0, 2.0],
        "space_group_hall_symbol": " P 1",
    }
    crystal = Crystal.from_dict(exp_dict)
    exp[0].crystal = crystal
    with pytest.raises(Sorry):
        _ = Script.prepare_input(params, exp, reflections)

    # Test cutting data
    params, exp, reflections = generate_test_input(n=1)
    params.cut_data.d_min = 1.5
    params, _, script_reflections = Script.prepare_input(
        params, exp, reflections)
    r = script_reflections[0]
    assert list(r.get_flags(r.flags.user_excluded_in_scaling)) == [
        False,
        False,
        True,
        True,
    ]
    params.cut_data.d_max = 2.25
    params, _, script_reflections = Script.prepare_input(
        params, exp, reflections)
    r = script_reflections[0]
    assert list(r.get_flags(r.flags.user_excluded_in_scaling)) == [
        False,
        False,
        True,
        True,
    ]

    params, exp, reflections = generate_test_input(n=1)
    reflections[0]["partiality"] = flex.double([0.5, 0.8, 1.0, 1.0])
    params.cut_data.partiality_cutoff = 0.75
    _, __, script_reflections = Script.prepare_input(params, exp, reflections)
    r = script_reflections[0]
    assert list(r.get_flags(r.flags.user_excluded_in_scaling)) == [
        True,
        False,
        False,
        False,
    ]
Exemple #16
0
def test_compare_orientation_matrices():
    # try and see if we can get back the original rotation matrix and euler angles
    real_space_a = matrix.col((10, 0, 0))
    real_space_b = matrix.col((0, 10, 10))
    real_space_c = matrix.col((0, 0, 10))
    euler_angles = (1.3, 5.6, 7.8)
    R = matrix.sqr(
        euler.xyz_matrix(euler_angles[0], euler_angles[1], euler_angles[2]))
    crystal_a = Crystal(real_space_a,
                        real_space_b,
                        real_space_c,
                        space_group=sgtbx.space_group("P 1"))
    crystal_b = Crystal(
        R * real_space_a,
        R * real_space_b,
        R * real_space_c,
        space_group=sgtbx.space_group("P 1"),
    )
    assert (matrix.sqr(crystal_b.get_U()) *
            matrix.sqr(crystal_a.get_U()).transpose()).elems == pytest.approx(
                R.elems)
    (
        best_R_ab,
        best_axis,
        best_angle,
        best_cb_op,
    ) = compare_orientation_matrices.difference_rotation_matrix_axis_angle(
        crystal_a, crystal_b)
    best_euler_angles = euler.xyz_angles(best_R_ab)
    assert best_euler_angles == pytest.approx(euler_angles)
    assert best_cb_op.is_identity_op()
    assert best_R_ab.elems == pytest.approx(R.elems)

    # now see if we can deconvolute the original euler angles after applying
    # a change of basis to one of the crystals
    crystal_a = Crystal(real_space_a,
                        real_space_b,
                        real_space_c,
                        space_group=sgtbx.space_group("I 2 3"))
    cb_op = sgtbx.change_of_basis_op("z,x,y")
    crystal_b = Crystal(
        R * real_space_a,
        R * real_space_b,
        R * real_space_c,
        space_group=sgtbx.space_group("I 2 3"),
    ).change_basis(cb_op)
    (
        best_R_ab,
        best_axis,
        best_angle,
        best_cb_op,
    ) = compare_orientation_matrices.difference_rotation_matrix_axis_angle(
        crystal_a, crystal_b)
    best_euler_angles = euler.xyz_angles(best_R_ab)
    assert best_euler_angles == pytest.approx(euler_angles)
    assert best_cb_op.c() == cb_op.inverse().c()
    assert best_R_ab.elems == pytest.approx(R.elems)

    crystal_c = crystal_b.change_basis(sgtbx.change_of_basis_op("-y,-z,x"))
    assert crystal_c != crystal_b

    s = compare_orientation_matrices.rotation_matrix_differences(
        [crystal_a, crystal_b, crystal_c], comparison="pairwise")
    s = "\n".join(s.splitlines()[:-1]).replace("-0.000", "0.000")
    print(s)
    assert (s == """\
Change of basis op: b,c,a
Rotation matrix to transform crystal 1 to crystal 2:
{{0.986, -0.135, 0.098},
 {0.138, 0.990, -0.023},
 {-0.094, 0.036, 0.995}}
Rotation of 9.738 degrees about axis (0.172, 0.565, 0.807)

Change of basis op: -a,-b,c
Rotation matrix to transform crystal 1 to crystal 3:
{{0.986, -0.135, 0.098},
 {0.138, 0.990, -0.023},
 {-0.094, 0.036, 0.995}}
Rotation of 9.738 degrees about axis (0.172, 0.565, 0.807)

Change of basis op: c,-a,-b
Rotation matrix to transform crystal 2 to crystal 3:
{{1.000, 0.000, 0.000},
 {0.000, 1.000, 0.000},
 {0.000, 0.000, 1.000}}""")

    s = compare_orientation_matrices.rotation_matrix_differences(
        [crystal_a, crystal_b, crystal_c], comparison="sequential")
    s = "\n".join(s.splitlines()[:-1]).replace("-0.000", "0.000")
    print(s)
    assert (s == """\
Change of basis op: b,c,a
Rotation matrix to transform crystal 1 to crystal 2:
{{0.986, -0.135, 0.098},
 {0.138, 0.990, -0.023},
 {-0.094, 0.036, 0.995}}
Rotation of 9.738 degrees about axis (0.172, 0.565, 0.807)

Change of basis op: c,-a,-b
Rotation matrix to transform crystal 2 to crystal 3:
{{1.000, 0.000, 0.000},
 {0.000, 1.000, 0.000},
 {0.000, 0.000, 1.000}}""")

    s = compare_orientation_matrices.rotation_matrix_differences(
        (crystal_a, crystal_b), miller_indices=((1, 0, 0), (1, 1, 0)))
    assert (s == """\
Change of basis op: b,c,a
Rotation matrix to transform crystal 1 to crystal 2:
{{0.986, -0.135, 0.098},
 {0.138, 0.990, -0.023},
 {-0.094, 0.036, 0.995}}
Rotation of 9.738 degrees about axis (0.172, 0.565, 0.807)
(1,0,0): 15.26 deg
(1,1,0): 9.12 deg
""")
Exemple #17
0
def load_crystal(entry):
    from dxtbx.model import Crystal
    from scitbx.array_family import flex
    from cctbx import uctbx
    import numpy

    # Get the sample
    nx_sample = get_nx_sample(entry, "sample")

    # Set the space group
    space_group_symbol = nx_sample["unit_cell_group"][()]

    # Get depends on
    if nx_sample["depends_on"][()] != ".":
        assert nx_sample["depends_on"][()] == str(
            nx_sample["transformations/phi"].name)

    # Read the average unit cell data
    average_unit_cell = flex.double(numpy.array(
        nx_sample["average_unit_cell"]))
    assert nx_sample["average_unit_cell"].attrs["angles_units"] == "deg"
    assert nx_sample["average_unit_cell"].attrs["length_units"] == "angstrom"
    assert len(average_unit_cell.all()) == 1
    assert len(average_unit_cell) == 6
    average_orientation_matrix = flex.double(
        numpy.array(nx_sample["average_orientation_matrix"]))
    assert len(average_orientation_matrix.all()) == 2
    assert average_orientation_matrix.all()[0] == 3
    assert average_orientation_matrix.all()[1] == 3

    # Get the real space vectors
    uc = uctbx.unit_cell(tuple(average_unit_cell))
    U = matrix.sqr(average_orientation_matrix)
    B = matrix.sqr(uc.fractionalization_matrix()).transpose()
    A = U * B
    A = A.inverse()
    real_space_a = A[0:3]
    real_space_b = A[3:6]
    real_space_c = A[6:9]

    # Read the unit cell data
    unit_cell = flex.double(numpy.array(nx_sample["unit_cell"]))
    assert nx_sample["unit_cell"].attrs["angles_units"] == "deg"
    assert nx_sample["unit_cell"].attrs["length_units"] == "angstrom"

    # Read the orientation matrix
    orientation_matrix = flex.double(
        numpy.array(nx_sample["orientation_matrix"]))
    assert len(unit_cell.all()) == 2
    assert len(orientation_matrix.all()) == 3
    assert unit_cell.all()[0] == orientation_matrix.all()[0]
    assert unit_cell.all()[1] == 6
    assert orientation_matrix.all()[1] == 3
    assert orientation_matrix.all()[2] == 3

    # Construct the crystal model
    crystal = Crystal(real_space_a, real_space_b, real_space_c,
                      space_group_symbol)

    # Sort out scan points
    if unit_cell.all()[0] > 1:
        A_list = []
        for i in range(unit_cell.all()[0]):
            uc = uctbx.unit_cell(tuple(unit_cell[i:i + 1, :]))
            U = matrix.sqr(tuple(orientation_matrix[i:i + 1, :, :]))
            B = matrix.sqr(uc.fractionalization_matrix()).transpose()
            A_list.append(U * B)
        crystal.set_A_at_scan_points(A_list)
    else:
        assert unit_cell.all_eq(average_unit_cell)
        assert orientation_matrix.all_eq(average_orientation_matrix)

    # Return the crystal
    return crystal