def test_single_crystal_restraints_gradients():
    """Simple test with a single triclinic crystal restrained to a target unit cell"""

    from dxtbx.model.experiment_list import Experiment, ExperimentList

    from dials.algorithms.refinement.parameterisation.beam_parameters import (
        BeamParameterisation, )
    from dials.algorithms.refinement.parameterisation.crystal_parameters import (
        CrystalOrientationParameterisation,
        CrystalUnitCellParameterisation,
    )
    from dials.algorithms.refinement.parameterisation.detector_parameters import (
        DetectorParameterisationSinglePanel, )
    from dials.algorithms.refinement.parameterisation.prediction_parameters import (
        XYPhiPredictionParameterisation, )
    from dials.test.algorithms.refinement.setup_geometry import Extract

    overrides = """geometry.parameters.crystal.a.length.range = 10 50
  geometry.parameters.crystal.b.length.range = 10 50
  geometry.parameters.crystal.c.length.range = 10 50"""

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

    models = Extract(master_phil, overrides)

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

    # Build a mock scan for a 72 degree sequence
    from dxtbx.model import ScanFactory

    sf = ScanFactory()
    myscan = sf.make_scan(
        image_range=(1, 720),
        exposure_times=0.1,
        oscillation=(0, 0.1),
        epochs=list(range(720)),
        deg=True,
    )

    # Create parameterisations of these models
    det_param = DetectorParameterisationSinglePanel(mydetector)
    s0_param = BeamParameterisation(mybeam, mygonio)
    xlo_param = CrystalOrientationParameterisation(mycrystal)
    xluc_param = CrystalUnitCellParameterisation(mycrystal)

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

    # Build a prediction parameterisation
    pred_param = XYPhiPredictionParameterisation(
        experiments,
        detector_parameterisations=[det_param],
        beam_parameterisations=[s0_param],
        xl_orientation_parameterisations=[xlo_param],
        xl_unit_cell_parameterisations=[xluc_param],
    )

    # Build a restraints parameterisation
    rp = RestraintsParameterisation(
        detector_parameterisations=[det_param],
        beam_parameterisations=[s0_param],
        xl_orientation_parameterisations=[xlo_param],
        xl_unit_cell_parameterisations=[xluc_param],
    )

    # make a unit cell target
    sigma = 1.0
    uc = mycrystal.get_unit_cell().parameters()
    target_uc = [random.gauss(e, sigma) for e in uc]

    rp.add_restraints_to_target_xl_unit_cell(experiment_id=0,
                                             values=target_uc,
                                             sigma=[sigma] * 6)

    # get analytical values and gradients
    vals, grads, weights = rp.get_residuals_gradients_and_weights()
    assert len(vals) == rp.num_residuals

    # get finite difference gradients
    p_vals = pred_param.get_param_vals()
    deltas = [1.0e-7] * len(p_vals)

    fd_grad = []

    for i, delta in enumerate(deltas):
        val = p_vals[i]

        p_vals[i] -= delta / 2.0
        pred_param.set_param_vals(p_vals)

        rev_state, foo, bar = rp.get_residuals_gradients_and_weights()
        rev_state = flex.double(rev_state)

        p_vals[i] += delta
        pred_param.set_param_vals(p_vals)

        fwd_state, foo, bar = rp.get_residuals_gradients_and_weights()
        fwd_state = flex.double(fwd_state)

        p_vals[i] = val

        fd = (fwd_state - rev_state) / delta
        fd_grad.append(fd)

    # for comparison, fd_grad is a list of flex.doubles, each of which corresponds
    # to a column of the sparse matrix grads.
    for i, fd in enumerate(fd_grad):
        # extract dense column from the sparse matrix
        an = grads.col(i).as_dense_vector()

        assert an == pytest.approx(fd, abs=1e-5)
Exemple #2
0
    def config_restraints(params, pred_param):
        """Given a set of user parameters plus a model parameterisation, create
        restraints plus a parameterisation of these restraints

        Params:
            params: The input PHIL parameters
            pred_param: A PredictionParameters object

        Returns:
            A restraints parameterisation or None
        """

        if not any([
                params.crystal.unit_cell.restraints.tie_to_target,
                params.crystal.unit_cell.restraints.tie_to_group,
        ]):
            return None
        if params.scan_varying:
            logger.warning("Restraints will be ignored for scan_varying=True")
            return None

        det_params = pred_param.get_detector_parameterisations()
        beam_params = pred_param.get_beam_parameterisations()
        xl_ori_params = pred_param.get_crystal_orientation_parameterisations()
        xl_uc_params = pred_param.get_crystal_unit_cell_parameterisations()
        gon_params = pred_param.get_goniometer_parameterisations()

        from dials.algorithms.refinement.restraints import RestraintsParameterisation

        rp = RestraintsParameterisation(
            detector_parameterisations=det_params,
            beam_parameterisations=beam_params,
            xl_orientation_parameterisations=xl_ori_params,
            xl_unit_cell_parameterisations=xl_uc_params,
            goniometer_parameterisations=gon_params,
        )

        # Shorten params path
        # FIXME Only unit cell restraints currently supported
        # beam_r = params.beam.restraints
        cell_r = params.crystal.unit_cell.restraints
        # orientation_r = params.crystal.orientation.restraints
        # detector_r = params.detector.restraints

        for tie in cell_r.tie_to_target:
            if len(tie.values) != 6:
                raise DialsRefineConfigError(
                    "6 cell parameters must be provided as the tie_to_target.values."
                )
            if len(tie.sigmas) != 6:
                raise DialsRefineConfigError(
                    "6 sigmas must be provided as the tie_to_target.sigmas. "
                    "Note that individual sigmas of 0.0 will remove "
                    "the restraint for the corresponding cell parameter.")
            if tie.id is None:
                # get one experiment id for each parameterisation to apply to all
                tie.id = [e.get_experiment_ids()[0] for e in xl_uc_params]
            for exp_id in tie.id:
                rp.add_restraints_to_target_xl_unit_cell(
                    exp_id, tie.values, tie.sigmas)

        for tie in cell_r.tie_to_group:
            if len(tie.sigmas) != 6:
                raise DialsRefineConfigError(
                    "6 sigmas must be provided as the tie_to_group.sigmas. "
                    "Note that individual sigmas of 0.0 will remove "
                    "the restraint for the corresponding cell parameter.")
            if tie.id is None:
                rp.add_restraints_to_group_xl_unit_cell(
                    tie.target, "all", tie.sigmas)
            else:
                rp.add_restraints_to_group_xl_unit_cell(
                    tie.target, tie.id, tie.sigmas)

        return rp
Exemple #3
0
def test2():
    '''Simple test with two triclinic crystals restrained to a target unit cell'''

    from math import pi
    from random import gauss
    from dials.test.algorithms.refinement.setup_geometry import Extract
    from dxtbx.model.experiment.experiment_list import ExperimentList, Experiment

    #### Import model parameterisations

    from dials.algorithms.refinement.parameterisation.prediction_parameters import \
        XYPhiPredictionParameterisation
    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

    overrides = """geometry.parameters.crystal.a.length.range = 10 50
  geometry.parameters.crystal.b.length.range = 10 50
  geometry.parameters.crystal.c.length.range = 10 50"""

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

    models = Extract(master_phil, overrides)

    mydetector = models.detector
    mygonio = models.goniometer
    mycrystal = models.crystal
    # duplicate the crystal
    from copy import deepcopy
    mycrystal2 = deepcopy(mycrystal)
    mybeam = models.beam

    # Build a mock scan for a 72 degree sweep
    sweep_range = (0., pi / 5.)
    from dxtbx.model.scan import scan_factory
    sf = scan_factory()
    myscan = sf.make_scan(image_range=(1, 720),
                          exposure_times=0.1,
                          oscillation=(0, 0.1),
                          epochs=range(720),
                          deg=True)

    # Create parameterisations of these models
    det_param = DetectorParameterisationSinglePanel(mydetector)
    s0_param = BeamParameterisation(mybeam, mygonio)
    xlo_param = CrystalOrientationParameterisation(mycrystal)
    xluc_param = CrystalUnitCellParameterisation(mycrystal)
    xluc_param2 = CrystalUnitCellParameterisation(mycrystal2,
                                                  experiment_ids=[1])

    # Create an ExperimentList with the crystal duplicated
    experiments = ExperimentList()
    experiments.append(
        Experiment(beam=mybeam,
                   detector=mydetector,
                   goniometer=mygonio,
                   scan=myscan,
                   crystal=mycrystal,
                   imageset=None))
    experiments.append(
        Experiment(beam=mybeam,
                   detector=mydetector,
                   goniometer=mygonio,
                   scan=myscan,
                   crystal=mycrystal2,
                   imageset=None))

    # Build a prediction parameterisation
    pred_param = XYPhiPredictionParameterisation(
        experiments,
        detector_parameterisations=[det_param],
        beam_parameterisations=[s0_param],
        xl_orientation_parameterisations=[xlo_param],
        xl_unit_cell_parameterisations=[xluc_param, xluc_param2])

    # Build a restraints parameterisation
    rp = RestraintsParameterisation(
        detector_parameterisations=[det_param],
        beam_parameterisations=[s0_param],
        xl_orientation_parameterisations=[xlo_param],
        xl_unit_cell_parameterisations=[xluc_param, xluc_param2])

    # make a unit cell target
    sigma = 1.
    uc = mycrystal.get_unit_cell().parameters()
    target_uc = [gauss(e, sigma) for e in uc]

    rp.add_restraints_to_target_xl_unit_cell(experiment_id=0,
                                             values=target_uc,
                                             sigma=[sigma] * 6)
    rp.add_restraints_to_target_xl_unit_cell(experiment_id=1,
                                             values=target_uc,
                                             sigma=[sigma] * 6)

    # get analytical values and gradients
    vals, grads, weights = rp.get_residuals_gradients_and_weights()

    # get finite difference gradients
    p_vals = pred_param.get_param_vals()
    deltas = [1.e-7] * len(p_vals)

    fd_grad = []
    for i in range(len(deltas)):

        val = p_vals[i]

        p_vals[i] -= deltas[i] / 2.
        pred_param.set_param_vals(p_vals)

        rev_state, foo, bar = rp.get_residuals_gradients_and_weights()
        rev_state = flex.double(rev_state)

        p_vals[i] += deltas[i]
        pred_param.set_param_vals(p_vals)

        fwd_state, foo, bar = rp.get_residuals_gradients_and_weights()
        fwd_state = flex.double(fwd_state)

        p_vals[i] = val

        fd = (fwd_state - rev_state) / deltas[i]
        fd_grad.append(fd)

    # for comparison, fd_grad is a list of flex.doubles, each of which corresponds
    # to a column of the sparse matrix grads.
    for i, fd in enumerate(fd_grad):
        # extract dense column from the sparse matrix
        an = grads.col(i).as_dense_vector()
        assert approx_equal(an, fd, eps=1e-5)

    print "OK"