Example #1
0
  def __init__(self, crystal, experiment_ids=[0]):

    # The state of the unit cell parameterisation is the reciprocal space
    # orthogonalisation matrix 'B'. The initial state is irrelevant for
    # this model, as composition of a new B matrix and derivatives can be
    # done with just the values of 6 unit cell parameters, without
    # defining axial directions (which are selected by choice of the PDB
    # convention). For this reason also, the axes of the
    # parameters are irrelevant and are set here to None.

    ### Set up the initial state
    istate = None

    ### Set up symmetrizing object
    self._S = symmetrize_reduce_enlarge(crystal.get_space_group())
    self._S.set_orientation(orientation=crystal.get_B())
    X = self._S.forward_independent_parameters()
    dB_dp = self._S.forward_gradients()
    B = self._S.backward_orientation(independent=X).reciprocal_matrix()

    ### Set up the independent parameters, with a change of scale
    p_list = [Parameter(e * 1.e5, name = "g_param_%d" % i) \
              for i, e in enumerate(X)]

    # set up the base class
    ModelParameterisation.__init__(self, crystal, istate, p_list,
                                   experiment_ids=experiment_ids)

    # call compose to calculate all the derivatives
    self.compose()

    return
  def __init__(self, crystal, t_range, num_intervals, experiment_ids=[0]):

    # The state of a scan-varying unit cell parameterisation is the
    # reciprocal space orthogonalisation matrix '[B](t)', expressed as a
    # function of image number 't' in a sequential scan.

    # Other comments from CrystalUnitCellParameterisation are relevant here

    # Set up the smoother
    smoother = GaussianSmoother(t_range, num_intervals)
    nv = smoother.num_values()

    ### Set up the initial state
    istate = None

    ### Set up symmetrizing object
    self._S = symmetrize_reduce_enlarge(crystal.get_space_group())
    self._S.set_orientation(orientation=crystal.get_B())
    X = self._S.forward_independent_parameters()
    dB_dp = self._S.forward_gradients()
    B = self._S.backward_orientation(independent=X).reciprocal_matrix()

    ### Set up the independent parameters, with a change of scale
    p_list = [ScanVaryingParameterSet(e * 1.e5, nv, name = "g_param_%d" % i) \
              for i, e in enumerate(X)]

    # Set up the base class
    ScanVaryingModelParameterisation.__init__(self, crystal, istate,
                                              p_list, smoother,
                                              experiment_ids=experiment_ids)

    return
Example #3
0
  def _build_p_list(self, crystal, parameter_type=Parameter):
    """Build the list of parameters, using the parameter_type callback to
    select between versions of the Parameter class"""

    # Set up symmetrizing object
    self._S = symmetrize_reduce_enlarge(crystal.get_space_group())
    self._S.set_orientation(orientation=crystal.get_B())
    X = self._S.forward_independent_parameters()
    dB_dp = self._S.forward_gradients()
    B = self._S.backward_orientation(independent=X).reciprocal_matrix()

    # Set up the independent parameters, with a change of scale
    p_list = [parameter_type(e * 1.e5, name = "g_param_%d" % i) \
              for i, e in enumerate(X)]

    return p_list
 def __init__(pfh):
     pass
     from rstbx.symmetry.constraints.parameter_reduction import symmetrize_reduce_enlarge
     pfh.convert = symmetrize_reduce_enlarge(
         space_group=OO.space_group)
     pfh.convert.set_orientation(orientation=OO.input_orientation)
def test_refinement():
    '''Test a refinement run'''

    dials_regression = libtbx.env.find_in_repositories(
        relative_path="dials_regression", test=os.path.isdir)

    # Get a beam and detector from a datablock. This one has a CS-PAD, but that
    # is irrelevant
    data_dir = os.path.join(dials_regression, "refinement_test_data",
                            "hierarchy_test")
    datablock_path = os.path.join(data_dir, "datablock.json")
    assert os.path.exists(datablock_path)

    # load models
    from dxtbx.datablock import DataBlockFactory
    datablock = DataBlockFactory.from_serialized_format(datablock_path,
                                                        check_format=False)
    im_set = datablock[0].extract_imagesets()[0]
    from copy import deepcopy
    detector = deepcopy(im_set.get_detector())
    beam = im_set.get_beam()

    # Invent a crystal, goniometer and scan for this test
    from dxtbx.model import Crystal
    crystal = Crystal((40., 0., 0.), (0., 40., 0.), (0., 0., 40.),
                      space_group_symbol="P1")
    orig_xl = deepcopy(crystal)

    from dxtbx.model import GoniometerFactory
    goniometer = GoniometerFactory.known_axis((1., 0., 0.))

    # Build a mock scan for a 180 degree sweep
    from dxtbx.model import ScanFactory
    sf = ScanFactory()
    scan = sf.make_scan(image_range=(1, 1800),
                        exposure_times=0.1,
                        oscillation=(0, 0.1),
                        epochs=range(1800),
                        deg=True)
    sweep_range = scan.get_oscillation_range(deg=False)
    im_width = scan.get_oscillation(deg=False)[1]
    assert sweep_range == (0., pi)
    assert approx_equal(im_width, 0.1 * pi / 180.)

    from dxtbx.model.experiment_list import ExperimentList, Experiment

    # Build an experiment list
    experiments = ExperimentList()
    experiments.append(
        Experiment(beam=beam,
                   detector=detector,
                   goniometer=goniometer,
                   scan=scan,
                   crystal=crystal,
                   imageset=None))

    # simulate some reflections
    refs, _ = generate_reflections(experiments)

    # change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of
    # alpha and beta angles)
    from dials.algorithms.refinement.parameterisation.crystal_parameters import \
      CrystalUnitCellParameterisation
    xluc_param = CrystalUnitCellParameterisation(crystal)
    xluc_p_vals = xluc_param.get_param_vals()
    cell_params = crystal.get_unit_cell().parameters()
    cell_params = [
        a + b for a, b in zip(cell_params, [0.1, -0.1, 0.1, 0.1, -0.1, 0.0])
    ]
    from cctbx.uctbx import unit_cell
    from rstbx.symmetry.constraints.parameter_reduction import \
        symmetrize_reduce_enlarge
    from scitbx import matrix
    new_uc = unit_cell(cell_params)
    newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
    S = symmetrize_reduce_enlarge(crystal.get_space_group())
    S.set_orientation(orientation=newB)
    X = tuple([e * 1.e5 for e in S.forward_independent_parameters()])
    xluc_param.set_param_vals(X)

    # reparameterise the crystal at the perturbed geometry
    xluc_param = CrystalUnitCellParameterisation(crystal)

    # Dummy parameterisations for other models
    beam_param = None
    xlo_param = None
    det_param = None

    # parameterisation of the prediction equation
    from dials.algorithms.refinement.parameterisation.parameter_report import \
        ParameterReporter
    pred_param = TwoThetaPredictionParameterisation(experiments, det_param,
                                                    beam_param, xlo_param,
                                                    [xluc_param])
    param_reporter = ParameterReporter(det_param, beam_param, xlo_param,
                                       [xluc_param])

    # reflection manager
    refman = TwoThetaReflectionManager(refs,
                                       experiments,
                                       nref_per_degree=20,
                                       verbosity=2)

    # reflection predictor
    ref_predictor = TwoThetaExperimentsPredictor(experiments)

    # target function
    target = TwoThetaTarget(experiments, ref_predictor, refman, pred_param)

    # minimisation engine
    from dials.algorithms.refinement.engine \
      import LevenbergMarquardtIterations as Refinery
    refinery = Refinery(target=target,
                        prediction_parameterisation=pred_param,
                        log=None,
                        verbosity=0,
                        track_step=False,
                        track_gradient=False,
                        track_parameter_correlation=False,
                        max_iterations=20)

    # Refiner
    from dials.algorithms.refinement.refiner import Refiner
    refiner = Refiner(reflections=refs,
                      experiments=experiments,
                      pred_param=pred_param,
                      param_reporter=param_reporter,
                      refman=refman,
                      target=target,
                      refinery=refinery,
                      verbosity=1)

    history = refiner.run()

    # compare crystal with original crystal
    refined_xl = refiner.get_experiments()[0].crystal

    #print refined_xl
    assert refined_xl.is_similar_to(orig_xl,
                                    uc_rel_length_tolerance=0.001,
                                    uc_abs_angle_tolerance=0.01)

    #print "Unit cell esds:"
    #print refined_xl.get_cell_parameter_sd()

    return
Example #6
0
def test(init_test):

    single_panel_detector = init_test.experiments_single_panel.detectors()[0]
    multi_panel_detector = init_test.experiments_multi_panel.detectors()[0]
    beam = init_test.experiments_single_panel.beams()[0]
    gonio = init_test.experiments_single_panel.goniometers()[0]
    crystal = init_test.experiments_single_panel.crystals()[0]

    # Parameterise the models
    det_param = DetectorParameterisationSinglePanel(single_panel_detector)
    s0_param = BeamParameterisation(beam, gonio)
    xlo_param = CrystalOrientationParameterisation(crystal)
    xluc_param = CrystalUnitCellParameterisation(crystal)

    multi_det_param = DetectorParameterisationMultiPanel(
        multi_panel_detector, beam)

    # Fix beam to the X-Z plane (imgCIF geometry), fix wavelength
    s0_param.set_fixed([True, False, True])

    # Link model parameterisations together into a parameterisation of the
    # prediction equation, first for the single panel detector
    pred_param = XYPhiPredictionParameterisation(
        init_test.experiments_single_panel,
        [det_param],
        [s0_param],
        [xlo_param],
        [xluc_param],
    )

    # ... and now for the multi-panel detector
    pred_param2 = XYPhiPredictionParameterisation(
        init_test.experiments_multi_panel,
        [multi_det_param],
        [s0_param],
        [xlo_param],
        [xluc_param],
    )

    ################################
    # Apply known parameter shifts #
    ################################

    # shift detectors by 1.0 mm each translation and 2 mrad each rotation
    det_p_vals = det_param.get_param_vals()
    p_vals = [
        a + b for a, b in zip(det_p_vals, [1.0, 1.0, 1.0, 2.0, 2.0, 2.0])
    ]
    det_param.set_param_vals(p_vals)

    multi_det_p_vals = multi_det_param.get_param_vals()
    p_vals = [
        a + b for a, b in zip(multi_det_p_vals, [1.0, 1.0, 1.0, 2.0, 2.0, 2.0])
    ]
    multi_det_param.set_param_vals(p_vals)

    # shift beam by 2 mrad in free axis
    s0_p_vals = s0_param.get_param_vals()
    p_vals = list(s0_p_vals)

    p_vals[0] += 2.0
    s0_param.set_param_vals(p_vals)

    # rotate crystal a bit (=2 mrad each rotation)
    xlo_p_vals = xlo_param.get_param_vals()
    p_vals = [a + b for a, b in zip(xlo_p_vals, [2.0, 2.0, 2.0])]
    xlo_param.set_param_vals(p_vals)

    # change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of
    # gamma angle)
    xluc_p_vals = xluc_param.get_param_vals()
    cell_params = crystal.get_unit_cell().parameters()
    cell_params = [
        a + b for a, b in zip(cell_params, [0.1, 0.1, 0.1, 0.0, 0.0, 0.1])
    ]
    new_uc = unit_cell(cell_params)
    newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
    S = symmetrize_reduce_enlarge(crystal.get_space_group())
    S.set_orientation(orientation=newB)
    X = tuple([e * 1.0e5 for e in S.forward_independent_parameters()])
    xluc_param.set_param_vals(X)

    ###############################
    # Undo known parameter shifts #
    ###############################

    s0_param.set_param_vals(s0_p_vals)
    det_param.set_param_vals(det_p_vals)
    multi_det_param.set_param_vals(det_p_vals)
    xlo_param.set_param_vals(xlo_p_vals)
    xluc_param.set_param_vals(xluc_p_vals)

    #####################################
    # Select reflections for refinement #
    #####################################

    refman = ReflectionManager(init_test.observations_single_panel,
                               init_test.experiments_single_panel)
    refman2 = ReflectionManager(init_test.observations_multi_panel,
                                init_test.experiments_multi_panel)

    ###############################
    # Set up the target functions #
    ###############################

    target = LeastSquaresPositionalResidualWithRmsdCutoff(
        init_test.experiments_single_panel,
        ScansExperimentsPredictor(init_test.experiments_single_panel),
        refman,
        pred_param,
        restraints_parameterisation=None,
    )
    target2 = LeastSquaresPositionalResidualWithRmsdCutoff(
        init_test.experiments_multi_panel,
        ScansExperimentsPredictor(init_test.experiments_multi_panel),
        refman2,
        pred_param2,
        restraints_parameterisation=None,
    )

    #################################
    # Set up the refinement engines #
    #################################

    refiner = setup_minimiser.Extract(master_phil, target, pred_param).refiner
    refiner2 = setup_minimiser.Extract(master_phil, target2,
                                       pred_param2).refiner

    refiner.run()

    # reset parameters and run refinement with the multi panel detector
    s0_param.set_param_vals(s0_p_vals)
    multi_det_param.set_param_vals(det_p_vals)
    xlo_param.set_param_vals(xlo_p_vals)
    xluc_param.set_param_vals(xluc_p_vals)

    refiner2.run()

    # same number of steps
    assert refiner.get_num_steps() == refiner2.get_num_steps()

    # same rmsds
    for rmsd, rmsd2 in zip(refiner.history["rmsd"], refiner2.history["rmsd"]):
        assert approx_equal(rmsd, rmsd2)

    # same parameter values each step
    for params, params2 in zip(refiner.history["parameter_vector"],
                               refiner.history["parameter_vector"]):
        assert approx_equal(params, params2)
Example #7
0
def test():
    import random
    import textwrap
    from libtbx.test_utils import approx_equal
    from cctbx.uctbx import unit_cell

    def random_direction_close_to(vector):
        return vector.rotate_around_origin(
            matrix.col((random.random(), random.random(),
                        random.random())).normalize(),
            random.gauss(0, 1.0),
            deg=True,
        )

    # make a random P1 crystal and parameterise it
    a = random.uniform(10, 50) * random_direction_close_to(
        matrix.col((1, 0, 0)))
    b = random.uniform(10, 50) * random_direction_close_to(
        matrix.col((0, 1, 0)))
    c = random.uniform(10, 50) * random_direction_close_to(
        matrix.col((0, 0, 1)))
    xl = Crystal(a, b, c, space_group_symbol="P 1")

    xl_op = CrystalOrientationParameterisation(xl)
    xl_ucp = CrystalUnitCellParameterisation(xl)

    null_mat = matrix.sqr((0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0))

    # compare analytical and finite difference derivatives
    an_ds_dp = xl_op.get_ds_dp()
    fd_ds_dp = get_fd_gradients(xl_op, [1.0e-6 * pi / 180] * 3)
    for e, f in zip(an_ds_dp, fd_ds_dp):
        assert approx_equal((e - f), null_mat, eps=1.0e-6)

    an_ds_dp = xl_ucp.get_ds_dp()
    fd_ds_dp = get_fd_gradients(xl_ucp, [1.0e-7] * xl_ucp.num_free())
    for e, f in zip(an_ds_dp, fd_ds_dp):
        assert approx_equal((e - f), null_mat, eps=1.0e-6)

    # random initial orientations with a random parameter shift at each
    attempts = 100
    failures = 0
    for i in range(attempts):

        # make a random P1 crystal and parameterise it
        a = random.uniform(10, 50) * random_direction_close_to(
            matrix.col((1, 0, 0)))
        b = random.uniform(10, 50) * random_direction_close_to(
            matrix.col((0, 1, 0)))
        c = random.uniform(10, 50) * random_direction_close_to(
            matrix.col((0, 0, 1)))
        xl = Crystal(a, b, c, space_group_symbol="P 1")
        xl_op = CrystalOrientationParameterisation(xl)
        xl_uc = CrystalUnitCellParameterisation(xl)

        # apply a random parameter shift to the orientation
        p_vals = xl_op.get_param_vals()
        p_vals = random_param_shift(
            p_vals, [1000 * pi / 9, 1000 * pi / 9, 1000 * pi / 9])
        xl_op.set_param_vals(p_vals)

        # 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-5 * pi / 180] * 3)

        # apply a random parameter shift to the unit cell. We have to
        # do this in a way that is respectful to metrical constraints,
        # so don't modify the parameters directly; modify the cell
        # constants and extract the new parameters
        cell_params = xl.get_unit_cell().parameters()
        cell_params = random_param_shift(cell_params, [1.0] * 6)
        new_uc = unit_cell(cell_params)
        newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
        S = symmetrize_reduce_enlarge(xl.get_space_group())
        S.set_orientation(orientation=newB)
        X = S.forward_independent_parameters()
        xl_uc.set_param_vals(X)

        xl_uc_an_ds_dp = xl_ucp.get_ds_dp()

        # now doing finite differences about each parameter in turn
        xl_uc_fd_ds_dp = get_fd_gradients(xl_ucp, [1.0e-7] * xl_ucp.num_free())

        for j in range(3):
            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],
                                )

        for j in range(xl_ucp.num_free()):
            assert approx_equal((xl_uc_fd_ds_dp[j] - xl_uc_an_ds_dp[j]),
                                null_mat,
                                eps=1.0e-6), textwrap.dedent("""\
        Failure in try {i}
        failure for parameter number {j}
        of the unit cell 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_uc_fd_ds_dp[j],
                                    an=xl_uc_an_ds_dp[j],
                                    diff=xl_uc_fd_ds_dp[j] - xl_uc_an_ds_dp[j],
                                )
  xlo_p_vals.append(p_vals)
  new_p_vals = [a + b for a, b in zip(p_vals, [2., 2., 2.])]
  xlo.set_param_vals(new_p_vals)

# change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of
# gamma angle)
xluc_p_vals = []
for xluc, xl in ((xl1uc_param, crystal1),((xl2uc_param, crystal2))):
  p_vals = xluc.get_param_vals()
  xluc_p_vals.append(p_vals)
  cell_params = xl.get_unit_cell().parameters()
  cell_params = [a + b for a, b in zip(cell_params, [0.1, 0.1, 0.1, 0.0,
                                                     0.0, 0.1])]
  new_uc = unit_cell(cell_params)
  newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
  S = symmetrize_reduce_enlarge(xl.get_space_group())
  S.set_orientation(orientation=newB)
  X = tuple([e * 1.e5 for e in S.forward_independent_parameters()])
  xluc.set_param_vals(X)

#############################
# Generate some reflections #
#############################

#print "Reflections will be generated with the following geometry:"
#print mybeam
#print mydetector
#print crystal1
#print crystal2

# All indices in a 2.0 Angstrom sphere for crystal1
Example #9
0
    new_p_vals = [a + b for a, b in zip(p_vals, [2., 2., 2.])]
    xlo.set_param_vals(new_p_vals)

# change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of
# gamma angle)
xluc_p_vals = []
for xluc, xl in ((xl1uc_param, crystal1), ((xl2uc_param, crystal2))):
    p_vals = xluc.get_param_vals()
    xluc_p_vals.append(p_vals)
    cell_params = xl.get_unit_cell().parameters()
    cell_params = [
        a + b for a, b in zip(cell_params, [0.1, 0.1, 0.1, 0.0, 0.0, 0.1])
    ]
    new_uc = unit_cell(cell_params)
    newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
    S = symmetrize_reduce_enlarge(xl.get_space_group())
    S.set_orientation(orientation=newB)
    X = tuple([e * 1.e5 for e in S.forward_independent_parameters()])
    xluc.set_param_vals(X)

#############################
# Generate some reflections #
#############################

#print "Reflections will be generated with the following geometry:"
#print mybeam
#print mydetector
#print crystal1
#print crystal2

# All indices in a 2.0 Angstrom sphere for crystal1
Example #10
0
def test(args=[]):
    from math import pi

    from cctbx.sgtbx import space_group, space_group_symbols

    # Symmetry constrained parameterisation for the unit cell
    from cctbx.uctbx import unit_cell

    # We will set up a mock scan and a mock experiment list
    from dxtbx.model import ScanFactory
    from dxtbx.model.experiment_list import Experiment, ExperimentList
    from libtbx.phil import parse
    from libtbx.test_utils import approx_equal
    from rstbx.symmetry.constraints.parameter_reduction import symmetrize_reduce_enlarge
    from scitbx import matrix
    from scitbx.array_family import flex

    # Get modules to build models and minimiser using PHIL
    import dials.tests.algorithms.refinement.setup_geometry as setup_geometry
    import dials.tests.algorithms.refinement.setup_minimiser as setup_minimiser
    from dials.algorithms.refinement.parameterisation.beam_parameters import (
        BeamParameterisation,
    )
    from dials.algorithms.refinement.parameterisation.crystal_parameters import (
        CrystalOrientationParameterisation,
        CrystalUnitCellParameterisation,
    )

    # Model parameterisations
    from dials.algorithms.refinement.parameterisation.detector_parameters import (
        DetectorParameterisationSinglePanel,
    )

    # Parameterisation of the prediction equation
    from dials.algorithms.refinement.parameterisation.prediction_parameters import (
        XYPhiPredictionParameterisation,
    )
    from dials.algorithms.refinement.prediction.managed_predictors import (
        ScansExperimentsPredictor,
        ScansRayPredictor,
    )
    from dials.algorithms.refinement.reflection_manager import ReflectionManager

    # Imports for the target function
    from dials.algorithms.refinement.target import (
        LeastSquaresPositionalResidualWithRmsdCutoff,
    )

    # Reflection prediction
    from dials.algorithms.spot_prediction import IndexGenerator, ray_intersection

    #############################
    # Setup experimental models #
    #############################

    master_phil = parse(
        """
      include scope dials.tests.algorithms.refinement.geometry_phil
      include scope dials.tests.algorithms.refinement.minimiser_phil
      """,
        process_includes=True,
    )

    models = setup_geometry.Extract(master_phil, cmdline_args=args)

    mydetector = models.detector
    mygonio = models.goniometer
    mycrystal = models.crystal
    mybeam = models.beam

    # Build a mock scan for a 180 degree sequence
    sf = ScanFactory()
    myscan = sf.make_scan(
        image_range=(1, 1800),
        exposure_times=0.1,
        oscillation=(0, 0.1),
        epochs=list(range(1800)),
        deg=True,
    )
    sequence_range = myscan.get_oscillation_range(deg=False)
    im_width = myscan.get_oscillation(deg=False)[1]
    assert sequence_range == (0.0, pi)
    assert approx_equal(im_width, 0.1 * pi / 180.0)

    # Build an experiment list
    experiments = ExperimentList()
    experiments.append(
        Experiment(
            beam=mybeam,
            detector=mydetector,
            goniometer=mygonio,
            scan=myscan,
            crystal=mycrystal,
            imageset=None,
        )
    )

    ###########################
    # Parameterise the models #
    ###########################

    det_param = DetectorParameterisationSinglePanel(mydetector)
    s0_param = BeamParameterisation(mybeam, mygonio)
    xlo_param = CrystalOrientationParameterisation(mycrystal)
    xluc_param = CrystalUnitCellParameterisation(mycrystal)

    # Fix beam to the X-Z plane (imgCIF geometry), fix wavelength
    s0_param.set_fixed([True, False, True])

    # Fix crystal parameters
    # xluc_param.set_fixed([True, True, True, True, True, True])

    ########################################################################
    # Link model parameterisations together into a parameterisation of the #
    # prediction equation                                                  #
    ########################################################################

    pred_param = XYPhiPredictionParameterisation(
        experiments, [det_param], [s0_param], [xlo_param], [xluc_param]
    )

    ################################
    # Apply known parameter shifts #
    ################################

    # shift detector by 1.0 mm each translation and 2 mrad each rotation
    det_p_vals = det_param.get_param_vals()
    p_vals = [a + b for a, b in zip(det_p_vals, [1.0, 1.0, 1.0, 2.0, 2.0, 2.0])]
    det_param.set_param_vals(p_vals)

    # shift beam by 2 mrad in free axis
    s0_p_vals = s0_param.get_param_vals()
    p_vals = list(s0_p_vals)

    p_vals[0] += 2.0
    s0_param.set_param_vals(p_vals)

    # rotate crystal a bit (=2 mrad each rotation)
    xlo_p_vals = xlo_param.get_param_vals()
    p_vals = [a + b for a, b in zip(xlo_p_vals, [2.0, 2.0, 2.0])]
    xlo_param.set_param_vals(p_vals)

    # change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of
    # gamma angle)
    xluc_p_vals = xluc_param.get_param_vals()
    cell_params = mycrystal.get_unit_cell().parameters()
    cell_params = [a + b for a, b in zip(cell_params, [0.1, 0.1, 0.1, 0.0, 0.0, 0.1])]
    new_uc = unit_cell(cell_params)
    newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
    S = symmetrize_reduce_enlarge(mycrystal.get_space_group())
    S.set_orientation(orientation=newB)
    X = tuple([e * 1.0e5 for e in S.forward_independent_parameters()])
    xluc_param.set_param_vals(X)

    #############################
    # Generate some reflections #
    #############################

    print("Reflections will be generated with the following geometry:")
    print(mybeam)
    print(mydetector)
    print(mycrystal)
    print("Target values of parameters are")
    msg = "Parameters: " + "%.5f " * len(pred_param)
    print(msg % tuple(pred_param.get_param_vals()))
    print()

    # All indices in a 2.0 Angstrom sphere
    resolution = 2.0
    index_generator = IndexGenerator(
        mycrystal.get_unit_cell(),
        space_group(space_group_symbols(1).hall()).type(),
        resolution,
    )
    indices = index_generator.to_array()

    # Predict rays within the sequence range
    ray_predictor = ScansRayPredictor(experiments, sequence_range)
    obs_refs = ray_predictor(indices)

    print("Total number of reflections excited", len(obs_refs))

    # Take only those rays that intersect the detector
    intersects = ray_intersection(mydetector, obs_refs)
    obs_refs = obs_refs.select(intersects)

    # Make a reflection predictor and re-predict for all these reflections. The
    # result is the same, but we gain also the flags and xyzcal.px columns
    ref_predictor = ScansExperimentsPredictor(experiments)
    obs_refs["id"] = flex.int(len(obs_refs), 0)
    obs_refs = ref_predictor(obs_refs)

    # Set 'observed' centroids from the predicted ones
    obs_refs["xyzobs.mm.value"] = obs_refs["xyzcal.mm"]

    # Invent some variances for the centroid positions of the simulated data
    im_width = 0.1 * pi / 180.0
    px_size = mydetector[0].get_pixel_size()
    var_x = flex.double(len(obs_refs), (px_size[0] / 2.0) ** 2)
    var_y = flex.double(len(obs_refs), (px_size[1] / 2.0) ** 2)
    var_phi = flex.double(len(obs_refs), (im_width / 2.0) ** 2)
    obs_refs["xyzobs.mm.variance"] = flex.vec3_double(var_x, var_y, var_phi)

    print("Total number of observations made", len(obs_refs))

    ###############################
    # Undo known parameter shifts #
    ###############################

    s0_param.set_param_vals(s0_p_vals)
    det_param.set_param_vals(det_p_vals)
    xlo_param.set_param_vals(xlo_p_vals)
    xluc_param.set_param_vals(xluc_p_vals)

    print("Initial values of parameters are")
    msg = "Parameters: " + "%.5f " * len(pred_param)
    print(msg % tuple(pred_param.get_param_vals()))
    print()

    #####################################
    # Select reflections for refinement #
    #####################################

    refman = ReflectionManager(obs_refs, experiments)

    ##############################
    # Set up the target function #
    ##############################

    # The current 'achieved' criterion compares RMSD against 1/3 the pixel size and
    # 1/3 the image width in radians. For the simulated data, these are just made up

    mytarget = LeastSquaresPositionalResidualWithRmsdCutoff(
        experiments, ref_predictor, refman, pred_param, restraints_parameterisation=None
    )

    ################################
    # Set up the refinement engine #
    ################################

    refiner = setup_minimiser.Extract(
        master_phil, mytarget, pred_param, cmdline_args=args
    ).refiner

    print("Prior to refinement the experimental model is:")
    print(mybeam)
    print(mydetector)
    print(mycrystal)

    refiner.run()

    print()
    print("Refinement has completed with the following geometry:")
    print(mybeam)
    print(mydetector)
    print(mycrystal)
def test(args=[]):
    #############################
    # Setup experimental models #
    #############################
    master_phil = parse("""
      include scope dials.test.algorithms.refinement.geometry_phil
      include scope dials.test.algorithms.refinement.minimiser_phil
      """,
                        process_includes=True)

    models = setup_geometry.Extract(master_phil, cmdline_args=args)

    single_panel_detector = models.detector
    mygonio = models.goniometer
    mycrystal = models.crystal
    mybeam = models.beam

    # Make a 3x3 multi panel detector filling the same space as the existing
    # single panel detector. Each panel of the multi-panel detector has pixels with
    # 1/3 the length dimensions of the single panel.

    multi_panel_detector = Detector()
    for x in range(3):
        for y in range(3):
            new_panel = make_panel_in_array((x, y), single_panel_detector[0])
            multi_panel_detector.add_panel(new_panel)

    # Build a mock scan for a 180 degree sweep
    sf = ScanFactory()
    myscan = sf.make_scan(image_range=(1, 1800),
                          exposure_times=0.1,
                          oscillation=(0, 0.1),
                          epochs=range(1800),
                          deg=True)
    sweep_range = myscan.get_oscillation_range(deg=False)
    im_width = myscan.get_oscillation(deg=False)[1]
    assert sweep_range == (0., pi)
    assert approx_equal(im_width, 0.1 * pi / 180.)

    # Build ExperimentLists
    experiments_single_panel = ExperimentList()
    experiments_multi_panel = ExperimentList()
    experiments_single_panel.append(
        Experiment(beam=mybeam,
                   detector=single_panel_detector,
                   goniometer=mygonio,
                   scan=myscan,
                   crystal=mycrystal,
                   imageset=None))
    experiments_multi_panel.append(
        Experiment(beam=mybeam,
                   detector=multi_panel_detector,
                   goniometer=mygonio,
                   scan=myscan,
                   crystal=mycrystal,
                   imageset=None))

    ###########################
    # Parameterise the models #
    ###########################

    det_param = DetectorParameterisationSinglePanel(single_panel_detector)
    s0_param = BeamParameterisation(mybeam, mygonio)
    xlo_param = CrystalOrientationParameterisation(mycrystal)
    xluc_param = CrystalUnitCellParameterisation(mycrystal)

    multi_det_param = DetectorParameterisationMultiPanel(
        multi_panel_detector, mybeam)

    # Fix beam to the X-Z plane (imgCIF geometry), fix wavelength
    s0_param.set_fixed([True, False, True])

    # Fix crystal parameters
    #xluc_param.set_fixed([True, True, True, True, True, True])

    ########################################################################
    # Link model parameterisations together into a parameterisation of the #
    # prediction equation                                                  #
    ########################################################################

    pred_param = XYPhiPredictionParameterisation(experiments_single_panel,
                                                 [det_param], [s0_param],
                                                 [xlo_param], [xluc_param])

    pred_param2 = XYPhiPredictionParameterisation(experiments_multi_panel,
                                                  [multi_det_param],
                                                  [s0_param], [xlo_param],
                                                  [xluc_param])

    ################################
    # Apply known parameter shifts #
    ################################

    # shift detectors by 1.0 mm each translation and 2 mrad each rotation
    det_p_vals = det_param.get_param_vals()
    p_vals = [a + b for a, b in zip(det_p_vals, [1.0, 1.0, 1.0, 2., 2., 2.])]
    det_param.set_param_vals(p_vals)

    multi_det_p_vals = multi_det_param.get_param_vals()
    p_vals = [
        a + b for a, b in zip(multi_det_p_vals, [1.0, 1.0, 1.0, 2., 2., 2.])
    ]
    multi_det_param.set_param_vals(p_vals)

    # shift beam by 2 mrad in free axis
    s0_p_vals = s0_param.get_param_vals()
    p_vals = list(s0_p_vals)

    p_vals[0] += 2.
    s0_param.set_param_vals(p_vals)

    # rotate crystal a bit (=2 mrad each rotation)
    xlo_p_vals = xlo_param.get_param_vals()
    p_vals = [a + b for a, b in zip(xlo_p_vals, [2., 2., 2.])]
    xlo_param.set_param_vals(p_vals)

    # change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of
    # gamma angle)
    xluc_p_vals = xluc_param.get_param_vals()
    cell_params = mycrystal.get_unit_cell().parameters()
    cell_params = [
        a + b for a, b in zip(cell_params, [0.1, 0.1, 0.1, 0.0, 0.0, 0.1])
    ]
    new_uc = unit_cell(cell_params)
    newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
    S = symmetrize_reduce_enlarge(mycrystal.get_space_group())
    S.set_orientation(orientation=newB)
    X = tuple([e * 1.e5 for e in S.forward_independent_parameters()])
    xluc_param.set_param_vals(X)

    #############################
    # Generate some reflections #
    #############################

    # All indices in a 2.0 Angstrom sphere
    resolution = 2.0
    index_generator = IndexGenerator(
        mycrystal.get_unit_cell(),
        space_group(space_group_symbols(1).hall()).type(), resolution)
    indices = index_generator.to_array()

    # for the reflection predictor, it doesn't matter which experiment list is
    # passed, as the detector is not used
    ref_predictor = ScansRayPredictor(experiments_single_panel, sweep_range)

    # get two sets of identical reflections
    obs_refs = ref_predictor(indices)
    obs_refs2 = ref_predictor(indices)
    for r1, r2 in zip(obs_refs, obs_refs2):
        assert r1['s1'] == r2['s1']

    # get the panel intersections
    sel = ray_intersection(single_panel_detector, obs_refs)
    obs_refs = obs_refs.select(sel)
    sel = ray_intersection(multi_panel_detector, obs_refs2)
    obs_refs2 = obs_refs2.select(sel)
    assert len(obs_refs) == len(obs_refs2)

    # Set 'observed' centroids from the predicted ones
    obs_refs['xyzobs.mm.value'] = obs_refs['xyzcal.mm']
    obs_refs2['xyzobs.mm.value'] = obs_refs2['xyzcal.mm']

    # Invent some variances for the centroid positions of the simulated data
    im_width = 0.1 * pi / 180.
    px_size = single_panel_detector[0].get_pixel_size()
    var_x = flex.double(len(obs_refs), (px_size[0] / 2.)**2)
    var_y = flex.double(len(obs_refs), (px_size[1] / 2.)**2)
    var_phi = flex.double(len(obs_refs), (im_width / 2.)**2)

    # set the variances and frame numbers
    obs_refs['xyzobs.mm.variance'] = flex.vec3_double(var_x, var_y, var_phi)
    obs_refs2['xyzobs.mm.variance'] = flex.vec3_double(var_x, var_y, var_phi)

    # Add in flags and ID columns by copying into standard reflection tables
    tmp = flex.reflection_table.empty_standard(len(obs_refs))
    tmp.update(obs_refs)
    obs_refs = tmp
    tmp = flex.reflection_table.empty_standard(len(obs_refs2))
    tmp.update(obs_refs2)
    obs_refs2 = tmp

    ###############################
    # Undo known parameter shifts #
    ###############################

    s0_param.set_param_vals(s0_p_vals)
    det_param.set_param_vals(det_p_vals)
    multi_det_param.set_param_vals(det_p_vals)
    xlo_param.set_param_vals(xlo_p_vals)
    xluc_param.set_param_vals(xluc_p_vals)

    #####################################
    # Select reflections for refinement #
    #####################################

    refman = ReflectionManager(obs_refs, experiments_single_panel)
    refman2 = ReflectionManager(obs_refs, experiments_multi_panel)

    ###############################
    # Set up the target functions #
    ###############################

    mytarget = LeastSquaresPositionalResidualWithRmsdCutoff(
        experiments_single_panel,
        ExperimentsPredictor(experiments_single_panel),
        refman,
        pred_param,
        restraints_parameterisation=None)
    mytarget2 = LeastSquaresPositionalResidualWithRmsdCutoff(
        experiments_multi_panel,
        ExperimentsPredictor(experiments_multi_panel),
        refman2,
        pred_param2,
        restraints_parameterisation=None)

    #################################
    # Set up the refinement engines #
    #################################

    refiner = setup_minimiser.Extract(master_phil,
                                      mytarget,
                                      pred_param,
                                      cmdline_args=args).refiner
    refiner2 = setup_minimiser.Extract(master_phil,
                                       mytarget2,
                                       pred_param2,
                                       cmdline_args=args).refiner

    refiner.run()

    # reset parameters and run refinement with the multi panel detector
    s0_param.set_param_vals(s0_p_vals)
    multi_det_param.set_param_vals(det_p_vals)
    xlo_param.set_param_vals(xlo_p_vals)
    xluc_param.set_param_vals(xluc_p_vals)

    refiner2.run()

    # same number of steps
    assert refiner.get_num_steps() == refiner2.get_num_steps()

    # same rmsds
    for rmsd, rmsd2 in zip(refiner.history["rmsd"], refiner2.history["rmsd"]):
        assert approx_equal(rmsd, rmsd2)

    # same parameter values each step
    for params, params2 in zip(refiner.history["parameter_vector"],
                               refiner.history["parameter_vector"]):
        assert approx_equal(params, params2)
def test(args=[]):
    # Python and cctbx imports
    from math import pi
    from scitbx import matrix
    from scitbx.array_family import flex
    from libtbx.phil import parse
    from libtbx.test_utils import approx_equal

    # Get module to build models using PHIL
    import dials.test.algorithms.refinement.setup_geometry as setup_geometry

    # We will set up a mock scan and a mock experiment list
    from dxtbx.model import ScanFactory
    from dxtbx.model.experiment_list import ExperimentList, Experiment

    # Model parameterisations
    from dials.algorithms.refinement.parameterisation.detector_parameters import (
        DetectorParameterisationSinglePanel, )
    from dials.algorithms.refinement.parameterisation.beam_parameters import (
        BeamParameterisation, )
    from dials.algorithms.refinement.parameterisation.crystal_parameters import (
        CrystalOrientationParameterisation,
        CrystalUnitCellParameterisation,
    )

    # Symmetry constrained parameterisation for the unit cell
    from cctbx.uctbx import unit_cell
    from rstbx.symmetry.constraints.parameter_reduction import symmetrize_reduce_enlarge

    # Reflection prediction
    from dials.algorithms.spot_prediction import IndexGenerator
    from dials.algorithms.refinement.prediction.managed_predictors import (
        ScansRayPredictor,
        ScansExperimentsPredictor,
    )
    from dials.algorithms.spot_prediction import ray_intersection
    from cctbx.sgtbx import space_group, space_group_symbols

    #############################
    # Setup experimental models #
    #############################

    master_phil = parse(
        """
      include scope dials.test.algorithms.refinement.geometry_phil
      include scope dials.test.algorithms.refinement.minimiser_phil
      """,
        process_includes=True,
    )

    models = setup_geometry.Extract(
        master_phil,
        cmdline_args=args,
        local_overrides="geometry.parameters.random_seed = 1",
    )

    crystal1 = models.crystal

    models = setup_geometry.Extract(
        master_phil,
        cmdline_args=args,
        local_overrides="geometry.parameters.random_seed = 2",
    )

    mydetector = models.detector
    mygonio = models.goniometer
    crystal2 = models.crystal
    mybeam = models.beam

    # Build a mock scan for a 180 degree sweep
    sf = ScanFactory()
    myscan = sf.make_scan(
        image_range=(1, 1800),
        exposure_times=0.1,
        oscillation=(0, 0.1),
        epochs=list(range(1800)),
        deg=True,
    )
    sweep_range = myscan.get_oscillation_range(deg=False)
    im_width = myscan.get_oscillation(deg=False)[1]
    assert sweep_range == (0.0, pi)
    assert approx_equal(im_width, 0.1 * pi / 180.0)

    # Build an experiment list
    experiments = ExperimentList()
    experiments.append(
        Experiment(
            beam=mybeam,
            detector=mydetector,
            goniometer=mygonio,
            scan=myscan,
            crystal=crystal1,
            imageset=None,
        ))
    experiments.append(
        Experiment(
            beam=mybeam,
            detector=mydetector,
            goniometer=mygonio,
            scan=myscan,
            crystal=crystal2,
            imageset=None,
        ))

    assert len(experiments.detectors()) == 1

    ##########################################################
    # Parameterise the models (only for perturbing geometry) #
    ##########################################################

    det_param = DetectorParameterisationSinglePanel(mydetector)
    s0_param = BeamParameterisation(mybeam, mygonio)
    xl1o_param = CrystalOrientationParameterisation(crystal1)
    xl1uc_param = CrystalUnitCellParameterisation(crystal1)
    xl2o_param = CrystalOrientationParameterisation(crystal2)
    xl2uc_param = CrystalUnitCellParameterisation(crystal2)

    # Fix beam to the X-Z plane (imgCIF geometry), fix wavelength
    s0_param.set_fixed([True, False, True])

    # Fix crystal parameters
    # xluc_param.set_fixed([True, True, True, True, True, True])

    ########################################################################
    # Link model parameterisations together into a parameterisation of the #
    # prediction equation                                                  #
    ########################################################################

    # pred_param = XYPhiPredictionParameterisation(experiments,
    #  [det_param], [s0_param], [xlo_param], [xluc_param])

    ################################
    # Apply known parameter shifts #
    ################################

    # shift detector by 1.0 mm each translation and 2 mrad each rotation
    det_p_vals = det_param.get_param_vals()
    p_vals = [
        a + b for a, b in zip(det_p_vals, [1.0, 1.0, 1.0, 2.0, 2.0, 2.0])
    ]
    det_param.set_param_vals(p_vals)

    # shift beam by 2 mrad in free axis
    s0_p_vals = s0_param.get_param_vals()
    p_vals = list(s0_p_vals)

    p_vals[0] += 2.0
    s0_param.set_param_vals(p_vals)

    # rotate crystal a bit (=2 mrad each rotation)
    xlo_p_vals = []
    for xlo in (xl1o_param, xl2o_param):
        p_vals = xlo.get_param_vals()
        xlo_p_vals.append(p_vals)
        new_p_vals = [a + b for a, b in zip(p_vals, [2.0, 2.0, 2.0])]
        xlo.set_param_vals(new_p_vals)

    # change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of
    # gamma angle)
    xluc_p_vals = []
    for xluc, xl in ((xl1uc_param, crystal1), ((xl2uc_param, crystal2))):
        p_vals = xluc.get_param_vals()
        xluc_p_vals.append(p_vals)
        cell_params = xl.get_unit_cell().parameters()
        cell_params = [
            a + b for a, b in zip(cell_params, [0.1, 0.1, 0.1, 0.0, 0.0, 0.1])
        ]
        new_uc = unit_cell(cell_params)
        newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
        S = symmetrize_reduce_enlarge(xl.get_space_group())
        S.set_orientation(orientation=newB)
        X = tuple([e * 1.0e5 for e in S.forward_independent_parameters()])
        xluc.set_param_vals(X)

    #############################
    # Generate some reflections #
    #############################

    # print "Reflections will be generated with the following geometry:"
    # print mybeam
    # print mydetector
    # print crystal1
    # print crystal2

    # All indices in a 2.0 Angstrom sphere for crystal1
    resolution = 2.0
    index_generator = IndexGenerator(
        crystal1.get_unit_cell(),
        space_group(space_group_symbols(1).hall()).type(),
        resolution,
    )
    indices1 = index_generator.to_array()

    # All indices in a 2.0 Angstrom sphere for crystal2
    resolution = 2.0
    index_generator = IndexGenerator(
        crystal2.get_unit_cell(),
        space_group(space_group_symbols(1).hall()).type(),
        resolution,
    )
    indices2 = index_generator.to_array()

    # Predict rays within the sweep range. Set experiment IDs
    ray_predictor = ScansRayPredictor(experiments, sweep_range)
    obs_refs1 = ray_predictor(indices1, experiment_id=0)
    obs_refs1["id"] = flex.int(len(obs_refs1), 0)
    obs_refs2 = ray_predictor(indices2, experiment_id=1)
    obs_refs2["id"] = flex.int(len(obs_refs2), 1)

    # Take only those rays that intersect the detector
    intersects = ray_intersection(mydetector, obs_refs1)
    obs_refs1 = obs_refs1.select(intersects)
    intersects = ray_intersection(mydetector, obs_refs2)
    obs_refs2 = obs_refs2.select(intersects)

    # Make a reflection predictor and re-predict for all these reflections. The
    # result is the same, but we gain also the flags and xyzcal.px columns
    ref_predictor = ScansExperimentsPredictor(experiments)
    obs_refs1 = ref_predictor(obs_refs1)
    obs_refs2 = ref_predictor(obs_refs2)

    # Set 'observed' centroids from the predicted ones
    obs_refs1["xyzobs.mm.value"] = obs_refs1["xyzcal.mm"]
    obs_refs2["xyzobs.mm.value"] = obs_refs2["xyzcal.mm"]

    # Invent some variances for the centroid positions of the simulated data
    im_width = 0.1 * pi / 180.0
    px_size = mydetector[0].get_pixel_size()
    var_x = flex.double(len(obs_refs1), (px_size[0] / 2.0)**2)
    var_y = flex.double(len(obs_refs1), (px_size[1] / 2.0)**2)
    var_phi = flex.double(len(obs_refs1), (im_width / 2.0)**2)
    obs_refs1["xyzobs.mm.variance"] = flex.vec3_double(var_x, var_y, var_phi)
    var_x = flex.double(len(obs_refs2), (px_size[0] / 2.0)**2)
    var_y = flex.double(len(obs_refs2), (px_size[1] / 2.0)**2)
    var_phi = flex.double(len(obs_refs2), (im_width / 2.0)**2)
    obs_refs2["xyzobs.mm.variance"] = flex.vec3_double(var_x, var_y, var_phi)

    # print "Total number of reflections excited for crystal1", len(obs_refs1)
    # print "Total number of reflections excited for crystal2", len(obs_refs2)

    # concatenate reflection lists
    obs_refs1.extend(obs_refs2)
    obs_refs = obs_refs1

    ###############################
    # Undo known parameter shifts #
    ###############################

    s0_param.set_param_vals(s0_p_vals)
    det_param.set_param_vals(det_p_vals)
    xl1o_param.set_param_vals(xlo_p_vals[0])
    xl2o_param.set_param_vals(xlo_p_vals[1])
    xl1uc_param.set_param_vals(xluc_p_vals[0])
    xl2uc_param.set_param_vals(xluc_p_vals[1])

    # print "Initial values of parameters are"
    # msg = "Parameters: " + "%.5f " * len(pred_param)
    # print msg % tuple(pred_param.get_param_vals())
    # print

    # make a refiner
    from dials.algorithms.refinement.refiner import phil_scope

    params = phil_scope.fetch(source=parse("")).extract()

    # in case we want a plot
    params.refinement.refinery.journal.track_parameter_correlation = True

    # scan static first
    from dials.algorithms.refinement.refiner import RefinerFactory

    refiner = RefinerFactory.from_parameters_data_experiments(
        params, obs_refs, experiments)
    refiner.run()

    # scan varying
    params.refinement.parameterisation.scan_varying = True
    refiner = RefinerFactory.from_parameters_data_experiments(
        params, obs_refs, experiments)
    refiner.run()

    # Ensure all models have scan-varying state set
    # (https://github.com/dials/dials/issues/798)
    refined_experiments = refiner.get_experiments()
    sp = [xl.get_num_scan_points() for xl in refined_experiments.crystals()]
    assert sp.count(1801) == 2
Example #13
0
def run(args):

    parser = OptionParser(
        #usage=usage,
        phil=phil_scope,
        read_reflections=True,
        read_datablocks=False,
        read_experiments=True,
        check_format=False,
        #epilog=help_message
    )

    params, options, args = parser.parse_args(show_diff_phil=False,
                                              return_unhandled=True)

    # Configure the logging
    log.config(params.verbosity,
               info=params.output.log,
               debug=params.output.debug_log)

    from dials.util.version import dials_version
    logger.info(dials_version())

    # 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)

    datasets_input = []

    experiments = flatten_experiments(params.input.experiments)
    reflections = flatten_reflections(params.input.reflections)

    if len(experiments) or len(reflections):
        if len(reflections) == 1:
            reflections_input = reflections[0]
            reflections = []
            for i in range(len(experiments)):
                reflections.append(
                    reflections_input.select(reflections_input['id'] == i))

        assert len(experiments) == len(reflections)

        from cctbx import crystal, miller
        for expt, refl in zip(experiments, reflections):
            crystal_symmetry = crystal.symmetry(
                unit_cell=expt.crystal.get_unit_cell(),
                space_group=expt.crystal.get_space_group())

            # filtering of intensities similar to that done in export_mtz
            # FIXME this function should be renamed/moved elsewhere
            from dials.util.export_mtz import _apply_data_filters
            refl = _apply_data_filters(refl,
                                       ignore_profile_fitting=False,
                                       filter_ice_rings=False,
                                       min_isigi=-5,
                                       include_partials=False,
                                       keep_partials=False,
                                       scale_partials=True)

            assert 'intensity.sum.value' in refl
            sel = refl.get_flags(refl.flags.integrated_sum)
            data = refl['intensity.sum.value']
            variances = refl['intensity.sum.variance']
            if 'intensity.prf.value' in refl:
                prf_sel = refl.get_flags(refl.flags.integrated_prf)
                data.set_selected(prf_sel, refl['intensity.prf.value'])
                variances.set_selected(prf_sel, refl['intensity.prf.variance'])
                sel |= prf_sel
            refl = refl.select(sel)
            data = data.select(sel)
            variances = variances.select(sel)

            if 'lp' in refl and 'qe' in refl:
                lp = refl['lp']
                qe = refl['qe']
                assert qe.all_gt(0)
                scale = lp / qe
                data *= scale
                variances *= (flex.pow2(scale))
            miller_indices = refl['miller_index']
            assert variances.all_gt(0)
            sigmas = flex.sqrt(variances)

            miller_set = miller.set(crystal_symmetry,
                                    miller_indices,
                                    anomalous_flag=True)
            intensities = miller.array(miller_set, data=data, sigmas=sigmas)
            intensities.set_observation_type_xray_intensity()
            intensities.set_info(
                miller.array_info(source='DIALS', source_type='pickle'))
            datasets_input.append(intensities)

    files = args
    for file_name in files:
        reader = any_reflection_file(file_name)
        assert reader.file_type() == 'ccp4_mtz'

        as_miller_arrays = reader.as_miller_arrays(merge_equivalents=False)
        intensities_prf = [
            ma for ma in as_miller_arrays
            if ma.info().labels == ['IPR', 'SIGIPR']
        ]
        intensities_sum = [
            ma for ma in as_miller_arrays if ma.info().labels == ['I', 'SIGI']
        ]
        if len(intensities_prf):
            intensities = intensities_prf[0]
        else:
            assert len(intensities_sum), 'No intensities found in input file.'
            intensities = intensities_sum[0]
        batches = [
            ma for ma in as_miller_arrays if ma.info().labels == ['BATCH']
        ]
        if len(batches):
            batches = batches[0]
        else:
            batches = None
        mtz_object = reader.file_content()
        intensities = intensities.customized_copy(
            anomalous_flag=True,
            indices=mtz_object.extract_original_index_miller_indices(
            )).set_info(intensities.info())

        intensities.set_observation_type_xray_intensity()
        if params.batch is not None:
            assert batches is not None
            bmin, bmax = params.batch
            assert bmax >= bmin
            sel = (batches.data() >= bmin) & (batches.data() <= bmax)
            assert sel.count(True) > 0
            intensities = intensities.select(sel)

        datasets_input.append(intensities)

    datasets = datasets_input
    assert len(datasets) == 1
    result = determine_space_group(
        datasets[0],
        normalisation=params.normalisation,
        d_min=params.d_min,
        min_i_mean_over_sigma_mean=params.min_i_mean_over_sigma_mean)

    if (len(experiments) and len(reflections)
            and params.output.reflections is not None
            and params.output.experiments is not None):
        from dxtbx.serialize import dump
        from rstbx.symmetry.constraints import parameter_reduction
        reindexed_experiments = copy.deepcopy(experiments)
        reindexed_reflections = copy.deepcopy(reflections[0])
        cb_op_inp_best = result.best_solution.subgroup[
            'cb_op_inp_best'] * result.cb_op_inp_min
        best_subsym = result.best_solution.subgroup['best_subsym']
        for expt in reindexed_experiments:
            expt.crystal = expt.crystal.change_basis(cb_op_inp_best)
            expt.crystal.set_space_group(
                best_subsym.space_group().build_derived_acentric_group())
            S = parameter_reduction.symmetrize_reduce_enlarge(
                expt.crystal.get_space_group())
            S.set_orientation(expt.crystal.get_B())
            S.symmetrize()
            expt.crystal.set_B(S.orientation.reciprocal_matrix())
            reindexed_reflections['miller_index'] = cb_op_inp_best.apply(
                reindexed_reflections['miller_index'])
        logger.info('Saving reindexed experiments to %s' %
                    params.output.experiments)
        dump.experiment_list(reindexed_experiments, params.output.experiments)
        logger.info('Saving reindexed reflections to %s' %
                    params.output.reflections)
        reindexed_reflections.as_pickle(params.output.reflections)

    elif params.output.suffix is not None:
        cb_op_inp_best = result.best_solution.subgroup[
            'cb_op_inp_best'] * result.cb_op_inp_min
        best_subsym = result.best_solution.subgroup['best_subsym']
        space_group = best_subsym.space_group().build_derived_acentric_group()
        for file_name in files:
            basename = os.path.basename(file_name)
            out_name = os.path.splitext(
                basename)[0] + params.output.suffix + ".mtz"
            reader = any_reflection_file(file_name)
            assert reader.file_type() == 'ccp4_mtz'
            mtz_object = reader.file_content()
            if not cb_op_inp_best.is_identity_op():
                mtz_object.change_basis_in_place(cb_op_inp_best)
            mtz_object.set_space_group_info(space_group.info())
            for crystal in mtz_object.crystals():
                crystal.set_unit_cell_parameters(
                    best_subsym.unit_cell().parameters())
            mtz_object.write(out_name)
            logger.info('Saving reindexed reflections to %s' % out_name)
s0_param.set_param_vals(p_vals)

# rotate crystal a bit (=3 mrad each rotation)
xlo_p_vals = xlo_param.get_param_vals()
p_vals = [a + b for a, b in zip(xlo_p_vals, [3., 3., 3.])]
xlo_param.set_param_vals(p_vals)

# change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of
# alpha and beta angles)
xluc_p_vals = xluc_param.get_param_vals()
cell_params = mycrystal.get_unit_cell().parameters()
cell_params = [a + b for a, b in zip(cell_params, [0.1, -0.1, 0.1, 0.1,
                                                   -0.1, 0.0])]
new_uc = unit_cell(cell_params)
newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
S = symmetrize_reduce_enlarge(mycrystal.get_space_group())
S.set_orientation(orientation=newB)
X = tuple([e * 1.e5 for e in S.forward_independent_parameters()])
xluc_param.set_param_vals(X)

#############################
# Generate some reflections #
#############################

# All indices in a 2.0 Angstrom sphere
resolution = 2.0
index_generator = IndexGenerator(mycrystal.get_unit_cell(),
                space_group(space_group_symbols(1).hall()).type(), resolution)
indices = index_generator.to_array()

sweep_range = myscan.get_oscillation_range(deg=False)
Example #15
0
  def dI_derrorterms(self):
    refls = self.scaler.ISIGI
    ct = self.scaler.crystal_table

    # notation: dP1_dP2 is derivative of parameter 1 with respect to parameter 2. Here,
    # for example, is the derivative of rx wrt thetax
    drx_dthetax = flex.mat3_double()
    dry_dthetay = flex.mat3_double()
    s0hat = flex.vec3_double(len(refls), (0,0,-1))

    ex = col((1,0,0))
    ey = col((0,1,0))

    # Compute derivatives
    sre = symmetrize_reduce_enlarge(self.scaler.params.target_space_group.group())
    gstar_params = None
    gstar_derivatives = None

    for i in range(len(ct)):
      n_refl = ct['n_refl'][i]

      # Derivatives of rx/y wrt thetax/y come from cctbx
      drx_dthetax.extend(flex.mat3_double(n_refl, ex.axis_and_angle_as_r3_derivative_wrt_angle(ct['thetax'][i])))
      dry_dthetay.extend(flex.mat3_double(n_refl, ey.axis_and_angle_as_r3_derivative_wrt_angle(ct['thetay'][i])))

      # Derivatives of the B matrix wrt to the unit cell parameters also come from cctbx
      sre.set_orientation(orientation=ct['b_matrix'][i])
      p = sre.forward_independent_parameters()
      dB_dp = sre.forward_gradients()
      if gstar_params is None:
        assert gstar_derivatives is None
        gstar_params = [flex.double() for j in range(len(p))]
        gstar_derivatives = [flex.mat3_double() for j in range(len(p))]
      assert len(p) == len(dB_dp) == len(gstar_params) == len(gstar_derivatives)
      for j in range(len(p)):
        gstar_params[j].extend(flex.double(n_refl, p[j]))
        gstar_derivatives[j].extend(flex.mat3_double(n_refl, tuple(dB_dp[j])))

    # Compute the scalar terms used while computing derivatives
    self.r = r = self.compute_intensity_parameters()

    # Begin computing derivatives
    sigma_Iobs = refls['scaled_intensity']/refls['isigi']
    dI_dIobs = 1/r['D']

    def compute_dI_dp(dq_dp):
      """ Deriviatives of the scaled intensity I wrt to thetax, thetay and the unit cell parameters
      are computed the same, starting with the deriviatives of those parameters wrt to q """
      dqlen_dp = r['q'].dot(dq_dp)/r['qlen']
      dd_dp    = -(1/(r['qlen']**2)) * dqlen_dp
      drs_dp   = -(r['eta']/(2 * r['d']**2)) * dd_dp
      dslen_dp = r['s'].dot(dq_dp)/r['slen']
      drhsq_dp = 2 * (r['slen'] - (1/r['wavelength'])) * dslen_dp
      dPn_dp   = 2 * r['rs'] * drs_dp
      dPd_dp   = 2 * ((r['rs'] * drs_dp) + drhsq_dp)
      dP_dp    = ((r['p_d'] * dPn_dp)-(r['p_n'] * dPd_dp))/(r['p_d']**2)
      dI_dp    = -(refls['iobs']/(r['partiality']**2 * r['G'] * r['eepsilon'])) * dP_dp
      return dI_dp

    # Derivatives wrt the unit cell parameters
    dI_dgstar = []
    for j in range(len(gstar_params)):
      dI_dgstar.append(compute_dI_dp(r['ry'] * r['rx'] * r['u'] * gstar_derivatives[j] * r['h']))

    # Derivatives wrt the crystal orientation
    dI_dthetax = compute_dI_dp(r['ry'] * drx_dthetax * r['u'] * r['b'] * r['h'])
    dI_dthetay = compute_dI_dp(dry_dthetay * r['rx'] * r['u'] * r['b'] * r['h'])

    # Derivatives wrt to the wavelength
    dthetah_dlambda  = 1/(flex.sqrt(1 - ((r['wavelength']/(2 * r['d']))**2)) * 2 * r['d'])
    den_dlambda      = flex.cos(r['thetah']) * dthetah_dlambda
    der_dlambda      = ((r['wavelength'] * den_dlambda) - r['sinthetah'])/r['wavelength']**2
    depsilon_dlambda = -16 * r['B'] * r['er'] * der_dlambda
    ds0_dlambda      = s0hat*(-1/r['wavelength']**2)
    dslen_dlambda    = r['s'].dot(ds0_dlambda)/r['slen']
    drhsq_dlambda    = 2*(r['slen']-(1/r['wavelength']))*(dslen_dlambda+(1/r['wavelength']**2))
    dP_dlambda       = -2*(r['p_n']/r['p_d']**2) * drhsq_dlambda
    dD_dlambda       = (r['G'] * r['eepsilon'] * dP_dlambda) + (r['partiality'] * r['G'] * r['eepsilon'] * depsilon_dlambda)
    dI_dlambda       = -(refls['iobs']/r['D']**2) * dD_dlambda

    # Derivatives wrt to the deff
    drs_deff = -1/(r['deff']**2)
    dPn_deff = 2 * r['rs'] * drs_deff
    dPd_deff = 2 * r['rs'] * drs_deff
    dP_deff  = ((r['p_d'] * dPn_deff)-(r['p_n'] * dPd_deff))/(r['p_d']**2)
    dI_deff  = -(refls['iobs']/(r['partiality']**2 * r['G'] * r['eepsilon'])) * dP_deff

    # Derivatives wrt to eta (unused for RS refinement)
    # drs_deta = 1/(2*r['d'])
    # dPn_deta = 2 * r['rs'] * drs_deta
    # dPd_deta = 2 * r['rs'] * drs_deta
    # dP_deta  = ((r['p_d']*dPn_deta)-(r['p_n']*dPd_deta))/(r['p_d']**2)
    # dI_deta  = -(refls['iobs']/(r['partiality']**2 * r['G'] * r['eepsilon'])) * dP_deta

    if self.verbose:
      # Show comparisons to finite differences
      n_cryst_params = sre.constraints.n_independent_params()
      print("Showing finite differences and derivatives for each parameter (first few reflections only)")
      for parameter_name, table, derivatives, delta, in zip(['iobs', 'thetax', 'thetay', 'wavelength', 'deff'] + ['c%d'%cp for cp in range(n_cryst_params)],
                                                    [refls, ct, ct, ct, ct] + [ct]*n_cryst_params,
                                                    [dI_dIobs, dI_dthetax, dI_dthetay, dI_dlambda, dI_deff] + dI_dgstar,
                                                    [1e-7]*5 + [1e-11]*n_cryst_params):
        finite_g = self.finite_difference(parameter_name, table, delta)
        print(parameter_name)
        for refl_id in range(min(10, len(refls))):
          print("%d % 21.1f % 21.1f"%(refl_id, finite_g[refl_id], derivatives[refl_id]))
        stats = flex.mean_and_variance(finite_g-derivatives)
        stats_finite = flex.mean_and_variance(finite_g)
        percent = 0 if stats_finite.mean() == 0 else 100*stats.mean()/stats_finite.mean()
        print("Mean difference between finite and analytical: % 24.4f +/- % 24.4f (%8.3f%% of finite d.)"%( \
            stats.mean(), stats.unweighted_sample_standard_deviation(), percent))
        print()

    return [dI_dIobs, dI_dthetax, dI_dthetay, dI_dlambda, dI_deff] + dI_dgstar
Example #16
0
 def __init__(pfh):
   pass
   from rstbx.symmetry.constraints.parameter_reduction import symmetrize_reduce_enlarge
   pfh.convert = symmetrize_reduce_enlarge(space_group=OO.space_group)
   pfh.convert.set_orientation(orientation=OO.input_orientation)
Example #17
0
def test():
    # Python and cctbx imports
    from math import pi
    from scitbx import matrix
    from scitbx.array_family import flex
    from libtbx.phil import parse
    from libtbx.test_utils import approx_equal

    # Get modules to build models and minimiser using PHIL
    import dials.test.algorithms.refinement.setup_geometry as setup_geometry
    import dials.test.algorithms.refinement.setup_minimiser as setup_minimiser

    # We will set up a mock scan and a mock experiment list
    from dxtbx.model import ScanFactory
    from dxtbx.model.experiment_list import ExperimentList, Experiment

    # Model parameterisations
    from dials.algorithms.refinement.parameterisation.detector_parameters import \
        DetectorParameterisationSinglePanel
    from dials.algorithms.refinement.parameterisation.beam_parameters import \
        BeamParameterisation
    from dials.algorithms.refinement.parameterisation.crystal_parameters import \
        CrystalOrientationParameterisation, CrystalUnitCellParameterisation

    # Symmetry constrained parameterisation for the unit cell
    from cctbx.uctbx import unit_cell
    from rstbx.symmetry.constraints.parameter_reduction import \
        symmetrize_reduce_enlarge

    # Reflection prediction
    from dials.algorithms.spot_prediction import IndexGenerator, ray_intersection
    from dials.algorithms.refinement.prediction import ScansRayPredictor, \
      ExperimentsPredictor
    from cctbx.sgtbx import space_group, space_group_symbols

    # Parameterisation of the prediction equation
    from dials.algorithms.refinement.parameterisation.prediction_parameters import \
        XYPhiPredictionParameterisation

    # Imports for the target function
    from dials.algorithms.refinement.target import \
        LeastSquaresPositionalResidualWithRmsdCutoff
    from dials.algorithms.refinement.reflection_manager import ReflectionManager

    #############################
    # Setup experimental models #
    #############################

    override = """geometry.parameters
  {
    beam.wavelength.random=False
    beam.wavelength.value=1.0
    beam.direction.inclination.random=False
    crystal.a.length.random=False
    crystal.a.length.value=12.0
    crystal.a.direction.method=exactly
    crystal.a.direction.exactly.direction=1.0 0.002 -0.004
    crystal.b.length.random=False
    crystal.b.length.value=14.0
    crystal.b.direction.method=exactly
    crystal.b.direction.exactly.direction=-0.002 1.0 0.002
    crystal.c.length.random=False
    crystal.c.length.value=13.0
    crystal.c.direction.method=exactly
    crystal.c.direction.exactly.direction=0.002 -0.004 1.0
    detector.directions.method=exactly
    detector.directions.exactly.dir1=0.99 0.002 -0.004
    detector.directions.exactly.norm=0.002 -0.001 0.99
    detector.centre.method=exactly
    detector.centre.exactly.value=1.0 -0.5 199.0
  }"""

    master_phil = parse("""
  include scope dials.test.algorithms.refinement.geometry_phil
  include scope dials.test.algorithms.refinement.minimiser_phil
  """,
                        process_includes=True)

    models = setup_geometry.Extract(master_phil,
                                    local_overrides=override,
                                    verbose=False)

    mydetector = models.detector
    mygonio = models.goniometer
    mycrystal = models.crystal
    mybeam = models.beam

    ###########################
    # Parameterise the models #
    ###########################

    det_param = DetectorParameterisationSinglePanel(mydetector)
    s0_param = BeamParameterisation(mybeam, mygonio)
    xlo_param = CrystalOrientationParameterisation(mycrystal)
    xluc_param = CrystalUnitCellParameterisation(mycrystal)

    # Fix beam to the X-Z plane (imgCIF geometry), fix wavelength
    s0_param.set_fixed([True, False, True])

    ########################################################################
    # Link model parameterisations together into a parameterisation of the #
    # prediction equation                                                  #
    ########################################################################

    # Build a mock scan for a 180 degree sweep
    sf = ScanFactory()
    myscan = sf.make_scan(image_range=(1, 1800),
                          exposure_times=0.1,
                          oscillation=(0, 0.1),
                          epochs=range(1800),
                          deg=True)

    # Build an ExperimentList
    experiments = ExperimentList()
    experiments.append(
        Experiment(beam=mybeam,
                   detector=mydetector,
                   goniometer=mygonio,
                   scan=myscan,
                   crystal=mycrystal,
                   imageset=None))

    # Create the PredictionParameterisation
    pred_param = XYPhiPredictionParameterisation(experiments, [det_param],
                                                 [s0_param], [xlo_param],
                                                 [xluc_param])

    ################################
    # Apply known parameter shifts #
    ################################

    # shift detector by 1.0 mm each translation and 4 mrad each rotation
    det_p_vals = det_param.get_param_vals()
    p_vals = [a + b for a, b in zip(det_p_vals, [1.0, 1.0, 1.0, 4., 4., 4.])]
    det_param.set_param_vals(p_vals)

    # shift beam by 4 mrad in free axis
    s0_p_vals = s0_param.get_param_vals()
    p_vals = list(s0_p_vals)

    p_vals[0] += 4.
    s0_param.set_param_vals(p_vals)

    # rotate crystal a bit (=3 mrad each rotation)
    xlo_p_vals = xlo_param.get_param_vals()
    p_vals = [a + b for a, b in zip(xlo_p_vals, [3., 3., 3.])]
    xlo_param.set_param_vals(p_vals)

    # change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of
    # alpha and beta angles)
    xluc_p_vals = xluc_param.get_param_vals()
    cell_params = mycrystal.get_unit_cell().parameters()
    cell_params = [
        a + b for a, b in zip(cell_params, [0.1, -0.1, 0.1, 0.1, -0.1, 0.0])
    ]
    new_uc = unit_cell(cell_params)
    newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
    S = symmetrize_reduce_enlarge(mycrystal.get_space_group())
    S.set_orientation(orientation=newB)
    X = tuple([e * 1.e5 for e in S.forward_independent_parameters()])
    xluc_param.set_param_vals(X)

    #############################
    # Generate some reflections #
    #############################

    # All indices in a 2.0 Angstrom sphere
    resolution = 2.0
    index_generator = IndexGenerator(
        mycrystal.get_unit_cell(),
        space_group(space_group_symbols(1).hall()).type(), resolution)
    indices = index_generator.to_array()

    sweep_range = myscan.get_oscillation_range(deg=False)
    im_width = myscan.get_oscillation(deg=False)[1]
    assert sweep_range == (0., pi)
    assert approx_equal(im_width, 0.1 * pi / 180.)

    # Predict rays within the sweep range
    ray_predictor = ScansRayPredictor(experiments, sweep_range)
    obs_refs = ray_predictor(indices)

    # Take only those rays that intersect the detector
    intersects = ray_intersection(mydetector, obs_refs)
    obs_refs = obs_refs.select(intersects)

    # Make a reflection predictor and re-predict for all these reflections. The
    # result is the same, but we gain also the flags and xyzcal.px columns
    ref_predictor = ExperimentsPredictor(experiments)
    obs_refs['id'] = flex.int(len(obs_refs), 0)
    obs_refs = ref_predictor(obs_refs)

    # Set 'observed' centroids from the predicted ones
    obs_refs['xyzobs.mm.value'] = obs_refs['xyzcal.mm']

    # Invent some variances for the centroid positions of the simulated data
    im_width = 0.1 * pi / 180.
    px_size = mydetector[0].get_pixel_size()
    var_x = flex.double(len(obs_refs), (px_size[0] / 2.)**2)
    var_y = flex.double(len(obs_refs), (px_size[1] / 2.)**2)
    var_phi = flex.double(len(obs_refs), (im_width / 2.)**2)
    obs_refs['xyzobs.mm.variance'] = flex.vec3_double(var_x, var_y, var_phi)

    # The total number of observations should be 1128
    assert len(obs_refs) == 1128

    ###############################
    # Undo known parameter shifts #
    ###############################

    s0_param.set_param_vals(s0_p_vals)
    det_param.set_param_vals(det_p_vals)
    xlo_param.set_param_vals(xlo_p_vals)
    xluc_param.set_param_vals(xluc_p_vals)

    #####################################
    # Select reflections for refinement #
    #####################################

    refman = ReflectionManager(obs_refs,
                               experiments,
                               outlier_detector=None,
                               close_to_spindle_cutoff=0.1)

    ##############################
    # Set up the target function #
    ##############################

    # The current 'achieved' criterion compares RMSD against 1/3 the pixel size and
    # 1/3 the image width in radians. For the simulated data, these are just made up
    mytarget = LeastSquaresPositionalResidualWithRmsdCutoff(
        experiments,
        ref_predictor,
        refman,
        pred_param,
        restraints_parameterisation=None)

    ######################################
    # Set up the LSTBX refinement engine #
    ######################################

    overrides = """minimiser.parameters.engine=GaussNewton
  minimiser.parameters.verbosity=0
  minimiser.parameters.logfile=None"""
    refiner = setup_minimiser.Extract(master_phil,
                                      mytarget,
                                      pred_param,
                                      local_overrides=overrides).refiner

    refiner.run()

    assert mytarget.achieved()
    assert refiner.get_num_steps() == 1
    assert approx_equal(
        mytarget.rmsds(),
        (0.00508252354876, 0.00420954552156, 8.97303428289e-05))

    ###############################
    # Undo known parameter shifts #
    ###############################

    s0_param.set_param_vals(s0_p_vals)
    det_param.set_param_vals(det_p_vals)
    xlo_param.set_param_vals(xlo_p_vals)
    xluc_param.set_param_vals(xluc_p_vals)

    ######################################################
    # Set up the LBFGS with curvatures refinement engine #
    ######################################################

    overrides = """minimiser.parameters.engine=LBFGScurvs
  minimiser.parameters.verbosity=0
  minimiser.parameters.logfile=None"""
    refiner = setup_minimiser.Extract(master_phil,
                                      mytarget,
                                      pred_param,
                                      local_overrides=overrides).refiner

    refiner.run()

    assert mytarget.achieved()
    assert refiner.get_num_steps() == 9
    assert approx_equal(mytarget.rmsds(),
                        (0.0558857700305, 0.0333446685335, 0.000347402754278))
Example #18
0
def test_refinement():
  '''Test a refinement run'''

  dials_regression = libtbx.env.find_in_repositories(
    relative_path="dials_regression",
    test=os.path.isdir)

  # Get a beam and detector from a datablock. This one has a CS-PAD, but that
  # is irrelevant
  data_dir = os.path.join(dials_regression, "refinement_test_data",
                          "hierarchy_test")
  datablock_path = os.path.join(data_dir, "datablock.json")
  assert os.path.exists(datablock_path)

  # load models
  from dxtbx.datablock import DataBlockFactory
  datablock = DataBlockFactory.from_serialized_format(datablock_path, check_format=False)
  im_set = datablock[0].extract_imagesets()[0]
  from copy import deepcopy
  detector = deepcopy(im_set.get_detector())
  beam = im_set.get_beam()

  # Invent a crystal, goniometer and scan for this test
  from dxtbx.model.crystal import crystal_model
  crystal = crystal_model((40.,0.,0.) ,(0.,40.,0.), (0.,0.,40.),
                          space_group_symbol = "P1")
  orig_xl = deepcopy(crystal)

  from dxtbx.model.experiment import goniometer_factory
  goniometer = goniometer_factory.known_axis((1., 0., 0.))

  # Build a mock scan for a 180 degree sweep
  from dxtbx.model.scan import scan_factory
  sf = scan_factory()
  scan = sf.make_scan(image_range = (1,1800),
                      exposure_times = 0.1,
                      oscillation = (0, 0.1),
                      epochs = range(1800),
                      deg = True)
  sweep_range = scan.get_oscillation_range(deg=False)
  im_width = scan.get_oscillation(deg=False)[1]
  assert sweep_range == (0., pi)
  assert approx_equal(im_width, 0.1 * pi / 180.)

  from dxtbx.model.experiment.experiment_list import ExperimentList, Experiment

  # Build an experiment list
  experiments = ExperimentList()
  experiments.append(Experiment(
        beam=beam, detector=detector, goniometer=goniometer,
        scan=scan, crystal=crystal, imageset=None))

  # simulate some reflections
  refs, _ = generate_reflections(experiments)

  # change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of
  # alpha and beta angles)
  from dials.algorithms.refinement.parameterisation.crystal_parameters import \
    CrystalUnitCellParameterisation
  xluc_param = CrystalUnitCellParameterisation(crystal)
  xluc_p_vals = xluc_param.get_param_vals()
  cell_params = crystal.get_unit_cell().parameters()
  cell_params = [a + b for a, b in zip(cell_params, [0.1, -0.1, 0.1, 0.1,
                                                     -0.1, 0.0])]
  from cctbx.uctbx import unit_cell
  from rstbx.symmetry.constraints.parameter_reduction import \
      symmetrize_reduce_enlarge
  from scitbx import matrix
  new_uc = unit_cell(cell_params)
  newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
  S = symmetrize_reduce_enlarge(crystal.get_space_group())
  S.set_orientation(orientation=newB)
  X = tuple([e * 1.e5 for e in S.forward_independent_parameters()])
  xluc_param.set_param_vals(X)

  # reparameterise the crystal at the perturbed geometry
  xluc_param = CrystalUnitCellParameterisation(crystal)

  # Dummy parameterisations for other models
  beam_param = None
  xlo_param = None
  det_param = None

  # parameterisation of the prediction equation
  from dials.algorithms.refinement.parameterisation.parameter_report import \
      ParameterReporter
  pred_param = TwoThetaPredictionParameterisation(experiments,
    det_param, beam_param, xlo_param, [xluc_param])
  param_reporter = ParameterReporter(det_param, beam_param,
                                     xlo_param, [xluc_param])

  # reflection manager
  refman = TwoThetaReflectionManager(refs, experiments, nref_per_degree=20,
    verbosity=2)

  # reflection predictor
  ref_predictor = TwoThetaExperimentsPredictor(experiments)

  # target function
  target = TwoThetaTarget(experiments, ref_predictor, refman, pred_param)

  # minimisation engine
  from dials.algorithms.refinement.engine \
    import LevenbergMarquardtIterations as Refinery
  refinery = Refinery(target = target,
                      prediction_parameterisation = pred_param,
                      log = None,
                      verbosity = 0,
                      track_step = False,
                      track_gradient = False,
                      track_parameter_correlation = False,
                      max_iterations = 20)

  # Refiner
  from dials.algorithms.refinement.refiner import Refiner
  refiner = Refiner(reflections=refs,
                    experiments=experiments,
                    pred_param=pred_param,
                    param_reporter=param_reporter,
                    refman=refman,
                    target=target,
                    refinery=refinery,
                    verbosity=1)

  history = refiner.run()

  # compare crystal with original crystal
  refined_xl = refiner.get_experiments()[0].crystal

  #print refined_xl
  assert refined_xl.is_similar_to(orig_xl, uc_rel_length_tolerance=0.001,
    uc_abs_angle_tolerance=0.01)

  #print "Unit cell esds:"
  #print refined_xl.get_cell_parameter_sd()

  return
Example #19
0
def test(args=[]):
    # Python and cctbx imports
    from math import pi

    from cctbx.sgtbx import space_group, space_group_symbols

    # Symmetry constrained parameterisation for the unit cell
    from cctbx.uctbx import unit_cell

    # We will set up a mock scan and a mock experiment list
    from dxtbx.model import ScanFactory
    from dxtbx.model.experiment_list import Experiment, ExperimentList
    from libtbx.phil import parse
    from libtbx.test_utils import approx_equal
    from rstbx.symmetry.constraints.parameter_reduction import symmetrize_reduce_enlarge
    from scitbx import matrix

    # Get module to build models using PHIL
    import dials.test.algorithms.refinement.setup_geometry as setup_geometry

    # Crystal parameterisations
    from dials.algorithms.refinement.parameterisation.crystal_parameters import (
        CrystalOrientationParameterisation,
        CrystalUnitCellParameterisation,
    )
    from dials.algorithms.refinement.prediction.managed_predictors import (
        ScansRayPredictor,
        StillsExperimentsPredictor,
    )

    # Reflection prediction
    from dials.algorithms.spot_prediction import IndexGenerator, ray_intersection

    # Import for surgery on reflection_tables
    from dials.array_family import flex

    #############################
    # Setup experimental models #
    #############################

    master_phil = parse(
        """
      include scope dials.test.algorithms.refinement.geometry_phil
      include scope dials.test.algorithms.refinement.minimiser_phil
      """,
        process_includes=True,
    )

    # build models, with a larger crystal than default in order to get enough
    # reflections on the 'still' image
    param = """
  geometry.parameters.crystal.a.length.range=40 50;
  geometry.parameters.crystal.b.length.range=40 50;
  geometry.parameters.crystal.c.length.range=40 50;
  geometry.parameters.random_seed = 42"""
    models = setup_geometry.Extract(master_phil,
                                    cmdline_args=args,
                                    local_overrides=param)

    crystal = models.crystal
    mydetector = models.detector
    mygonio = models.goniometer
    mybeam = models.beam

    # Build a mock scan for a 1.5 degree wedge. Only used for generating indices near
    # the Ewald sphere
    sf = ScanFactory()
    myscan = sf.make_scan(
        image_range=(1, 1),
        exposure_times=0.1,
        oscillation=(0, 1.5),
        epochs=list(range(1)),
        deg=True,
    )
    sequence_range = myscan.get_oscillation_range(deg=False)
    im_width = myscan.get_oscillation(deg=False)[1]
    assert approx_equal(im_width, 1.5 * pi / 180.0)

    # Build experiment lists
    stills_experiments = ExperimentList()
    stills_experiments.append(
        Experiment(beam=mybeam,
                   detector=mydetector,
                   crystal=crystal,
                   imageset=None))
    scans_experiments = ExperimentList()
    scans_experiments.append(
        Experiment(
            beam=mybeam,
            detector=mydetector,
            crystal=crystal,
            goniometer=mygonio,
            scan=myscan,
            imageset=None,
        ))

    ##########################################################
    # Parameterise the models (only for perturbing geometry) #
    ##########################################################

    xlo_param = CrystalOrientationParameterisation(crystal)
    xluc_param = CrystalUnitCellParameterisation(crystal)

    ################################
    # Apply known parameter shifts #
    ################################

    # rotate crystal (=5 mrad each rotation)
    xlo_p_vals = []
    p_vals = xlo_param.get_param_vals()
    xlo_p_vals.append(p_vals)
    new_p_vals = [a + b for a, b in zip(p_vals, [5.0, 5.0, 5.0])]
    xlo_param.set_param_vals(new_p_vals)

    # change unit cell (=1.0 Angstrom length upsets, 0.5 degree of
    # gamma angle)
    xluc_p_vals = []
    p_vals = xluc_param.get_param_vals()
    xluc_p_vals.append(p_vals)
    cell_params = crystal.get_unit_cell().parameters()
    cell_params = [
        a + b for a, b in zip(cell_params, [1.0, 1.0, -1.0, 0.0, 0.0, 0.5])
    ]
    new_uc = unit_cell(cell_params)
    newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
    S = symmetrize_reduce_enlarge(crystal.get_space_group())
    S.set_orientation(orientation=newB)
    X = tuple([e * 1.0e5 for e in S.forward_independent_parameters()])
    xluc_param.set_param_vals(X)

    # keep track of the target crystal model to compare with refined
    from copy import deepcopy

    target_crystal = deepcopy(crystal)

    #############################
    # Generate some reflections #
    #############################

    # All indices in a 2.0 Angstrom sphere for crystal
    resolution = 2.0
    index_generator = IndexGenerator(
        crystal.get_unit_cell(),
        space_group(space_group_symbols(1).hall()).type(),
        resolution,
    )
    indices = index_generator.to_array()

    # Build a ray predictor and predict rays close to the Ewald sphere by using
    # the narrow rotation scan
    ref_predictor = ScansRayPredictor(scans_experiments, sequence_range)
    obs_refs = ref_predictor(indices, experiment_id=0)

    # Take only those rays that intersect the detector
    intersects = ray_intersection(mydetector, obs_refs)
    obs_refs = obs_refs.select(intersects)

    # Add in flags and ID columns by copying into standard reflection table
    tmp = flex.reflection_table.empty_standard(len(obs_refs))
    tmp.update(obs_refs)
    obs_refs = tmp

    # Invent some variances for the centroid positions of the simulated data
    im_width = 0.1 * pi / 180.0
    px_size = mydetector[0].get_pixel_size()
    var_x = flex.double(len(obs_refs), (px_size[0] / 2.0)**2)
    var_y = flex.double(len(obs_refs), (px_size[1] / 2.0)**2)
    var_phi = flex.double(len(obs_refs), (im_width / 2.0)**2)
    obs_refs["xyzobs.mm.variance"] = flex.vec3_double(var_x, var_y, var_phi)

    # Re-predict using the stills reflection predictor
    stills_ref_predictor = StillsExperimentsPredictor(stills_experiments)
    obs_refs_stills = stills_ref_predictor(obs_refs)

    # Set 'observed' centroids from the predicted ones
    obs_refs_stills["xyzobs.mm.value"] = obs_refs_stills["xyzcal.mm"]

    ###############################
    # Undo known parameter shifts #
    ###############################

    xlo_param.set_param_vals(xlo_p_vals[0])
    xluc_param.set_param_vals(xluc_p_vals[0])

    # make a refiner
    from dials.algorithms.refinement.refiner import phil_scope

    params = phil_scope.fetch(source=parse("")).extract()

    # Change this to get a plot
    do_plot = False
    if do_plot:
        params.refinement.refinery.journal.track_parameter_correlation = True

    from dials.algorithms.refinement.refiner import RefinerFactory

    # decrease bin_size_fraction to terminate on RMSD convergence
    params.refinement.target.bin_size_fraction = 0.01
    params.refinement.parameterisation.beam.fix = "all"
    params.refinement.parameterisation.detector.fix = "all"
    refiner = RefinerFactory.from_parameters_data_experiments(
        params, obs_refs_stills, stills_experiments)

    # run refinement
    history = refiner.run()

    # regression tests
    assert len(history["rmsd"]) == 9

    refined_crystal = refiner.get_experiments()[0].crystal
    uc1 = refined_crystal.get_unit_cell()
    uc2 = target_crystal.get_unit_cell()
    assert uc1.is_similar_to(uc2)

    if do_plot:
        plt = refiner.parameter_correlation_plot(
            len(history["parameter_correlation"]) - 1)
        plt.show()
s0_param.set_param_vals(p_vals)

# rotate crystal a bit (=2 mrad each rotation)
xlo_p_vals = xlo_param.get_param_vals()
p_vals = [a + b for a, b in zip(xlo_p_vals, [2., 2., 2.])]
xlo_param.set_param_vals(p_vals)

# change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of
# gamma angle)
xluc_p_vals = xluc_param.get_param_vals()
cell_params = mycrystal.get_unit_cell().parameters()
cell_params = [a + b for a, b in zip(cell_params, [0.1, 0.1, 0.1, 0.0,
                                                   0.0, 0.1])]
new_uc = unit_cell(cell_params)
newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
S = symmetrize_reduce_enlarge(mycrystal.get_space_group())
S.set_orientation(orientation=newB)
X = tuple([e * 1.e5 for e in S.forward_independent_parameters()])
xluc_param.set_param_vals(X)

#############################
# Generate some reflections #
#############################

print "Reflections will be generated with the following geometry:"
print mybeam
print mydetector
print mycrystal
print "Target values of parameters are"
msg = "Parameters: " + "%.5f " * len(pred_param)
print msg % tuple(pred_param.get_param_vals())
def test(args=[]):

    #############################
    # Setup experimental models #
    #############################

    master_phil = parse(
        """
        include scope dials.tests.algorithms.refinement.geometry_phil
        include scope dials.tests.algorithms.refinement.minimiser_phil
        """,
        process_includes=True,
    )

    models = setup_geometry.Extract(
        master_phil,
        cmdline_args=args,
        local_overrides="geometry.parameters.random_seed = 1",
    )

    crystal1 = models.crystal

    models = setup_geometry.Extract(
        master_phil,
        cmdline_args=args,
        local_overrides="geometry.parameters.random_seed = 2",
    )

    mydetector = models.detector
    mygonio = models.goniometer
    crystal2 = models.crystal
    mybeam = models.beam

    # Build a mock scan for an 18 degree sequence
    sf = ScanFactory()
    myscan = sf.make_scan(
        image_range=(1, 180),
        exposure_times=0.1,
        oscillation=(0, 0.1),
        epochs=list(range(180)),
        deg=True,
    )
    sequence_range = myscan.get_oscillation_range(deg=False)
    im_width = myscan.get_oscillation(deg=False)[1]
    assert sequence_range == (0.0, pi / 10)
    assert approx_equal(im_width, 0.1 * pi / 180.0)

    # Build an experiment list
    experiments = ExperimentList()
    experiments.append(
        Experiment(
            beam=mybeam,
            detector=mydetector,
            goniometer=mygonio,
            scan=myscan,
            crystal=crystal1,
            imageset=None,
        ))
    experiments.append(
        Experiment(
            beam=mybeam,
            detector=mydetector,
            goniometer=mygonio,
            scan=myscan,
            crystal=crystal2,
            imageset=None,
        ))

    assert len(experiments.detectors()) == 1

    ##########################################################
    # Parameterise the models (only for perturbing geometry) #
    ##########################################################

    det_param = DetectorParameterisationSinglePanel(mydetector)
    s0_param = BeamParameterisation(mybeam, mygonio)
    xl1o_param = CrystalOrientationParameterisation(crystal1)
    xl1uc_param = CrystalUnitCellParameterisation(crystal1)
    xl2o_param = CrystalOrientationParameterisation(crystal2)
    xl2uc_param = CrystalUnitCellParameterisation(crystal2)

    # Fix beam to the X-Z plane (imgCIF geometry), fix wavelength
    s0_param.set_fixed([True, False, True])

    ################################
    # Apply known parameter shifts #
    ################################

    # shift detector by 1.0 mm each translation and 2 mrad each rotation
    det_p_vals = det_param.get_param_vals()
    p_vals = [
        a + b for a, b in zip(det_p_vals, [1.0, 1.0, 1.0, 2.0, 2.0, 2.0])
    ]
    det_param.set_param_vals(p_vals)

    # shift beam by 2 mrad in free axis
    s0_p_vals = s0_param.get_param_vals()
    p_vals = list(s0_p_vals)

    p_vals[0] += 2.0
    s0_param.set_param_vals(p_vals)

    # rotate crystal a bit (=2 mrad each rotation)
    xlo_p_vals = []
    for xlo in (xl1o_param, xl2o_param):
        p_vals = xlo.get_param_vals()
        xlo_p_vals.append(p_vals)
        new_p_vals = [a + b for a, b in zip(p_vals, [2.0, 2.0, 2.0])]
        xlo.set_param_vals(new_p_vals)

    # change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of
    # gamma angle)
    xluc_p_vals = []
    for xluc, xl in ((xl1uc_param, crystal1), ((xl2uc_param, crystal2))):
        p_vals = xluc.get_param_vals()
        xluc_p_vals.append(p_vals)
        cell_params = xl.get_unit_cell().parameters()
        cell_params = [
            a + b for a, b in zip(cell_params, [0.1, 0.1, 0.1, 0.0, 0.0, 0.1])
        ]
        new_uc = unit_cell(cell_params)
        newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose()
        S = symmetrize_reduce_enlarge(xl.get_space_group())
        S.set_orientation(orientation=newB)
        X = tuple([e * 1.0e5 for e in S.forward_independent_parameters()])
        xluc.set_param_vals(X)

    #############################
    # Generate some reflections #
    #############################

    # All indices in a 2.5 Angstrom sphere for crystal1
    resolution = 2.5
    index_generator = IndexGenerator(
        crystal1.get_unit_cell(),
        space_group(space_group_symbols(1).hall()).type(),
        resolution,
    )
    indices1 = index_generator.to_array()

    # All indices in a 2.5 Angstrom sphere for crystal2
    resolution = 2.5
    index_generator = IndexGenerator(
        crystal2.get_unit_cell(),
        space_group(space_group_symbols(1).hall()).type(),
        resolution,
    )
    indices2 = index_generator.to_array()

    # Predict rays within the sequence range. Set experiment IDs
    ray_predictor = ScansRayPredictor(experiments, sequence_range)
    obs_refs1 = ray_predictor(indices1, experiment_id=0)
    obs_refs1["id"] = flex.int(len(obs_refs1), 0)
    obs_refs2 = ray_predictor(indices2, experiment_id=1)
    obs_refs2["id"] = flex.int(len(obs_refs2), 1)

    # Take only those rays that intersect the detector
    intersects = ray_intersection(mydetector, obs_refs1)
    obs_refs1 = obs_refs1.select(intersects)
    intersects = ray_intersection(mydetector, obs_refs2)
    obs_refs2 = obs_refs2.select(intersects)

    # Make a reflection predictor and re-predict for all these reflections. The
    # result is the same, but we gain also the flags and xyzcal.px columns
    ref_predictor = ScansExperimentsPredictor(experiments)
    obs_refs1 = ref_predictor(obs_refs1)
    obs_refs2 = ref_predictor(obs_refs2)

    # Set 'observed' centroids from the predicted ones
    obs_refs1["xyzobs.mm.value"] = obs_refs1["xyzcal.mm"]
    obs_refs2["xyzobs.mm.value"] = obs_refs2["xyzcal.mm"]

    # Invent some variances for the centroid positions of the simulated data
    im_width = 0.1 * pi / 18.0
    px_size = mydetector[0].get_pixel_size()
    var_x = flex.double(len(obs_refs1), (px_size[0] / 2.0)**2)
    var_y = flex.double(len(obs_refs1), (px_size[1] / 2.0)**2)
    var_phi = flex.double(len(obs_refs1), (im_width / 2.0)**2)
    obs_refs1["xyzobs.mm.variance"] = flex.vec3_double(var_x, var_y, var_phi)
    var_x = flex.double(len(obs_refs2), (px_size[0] / 2.0)**2)
    var_y = flex.double(len(obs_refs2), (px_size[1] / 2.0)**2)
    var_phi = flex.double(len(obs_refs2), (im_width / 2.0)**2)
    obs_refs2["xyzobs.mm.variance"] = flex.vec3_double(var_x, var_y, var_phi)

    # concatenate reflection lists
    obs_refs1.extend(obs_refs2)
    obs_refs = obs_refs1

    ###############################
    # Undo known parameter shifts #
    ###############################

    s0_param.set_param_vals(s0_p_vals)
    det_param.set_param_vals(det_p_vals)
    xl1o_param.set_param_vals(xlo_p_vals[0])
    xl2o_param.set_param_vals(xlo_p_vals[1])
    xl1uc_param.set_param_vals(xluc_p_vals[0])
    xl2uc_param.set_param_vals(xluc_p_vals[1])

    # scan static first
    params = phil_scope.fetch(source=parse("")).extract()
    refiner = RefinerFactory.from_parameters_data_experiments(
        params, obs_refs, experiments)
    refiner.run()

    # scan varying
    params.refinement.parameterisation.scan_varying = True
    refiner = RefinerFactory.from_parameters_data_experiments(
        params, obs_refs, experiments)
    refiner.run()

    # Ensure all models have scan-varying state set
    # (https://github.com/dials/dials/issues/798)
    refined_experiments = refiner.get_experiments()
    sp = [xl.get_num_scan_points() for xl in refined_experiments.crystals()]

    assert sp.count(181) == 2