def test(): # 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 from scitbx.array_family import flex # 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 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 # ############################# 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 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, ) # 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.0, 4.0, 4.0])] 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.0 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.0, 3.0, 3.0])] 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.0e5 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() 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) # Predict rays within the sequence range ray_predictor = ScansRayPredictor(experiments, sequence_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 = 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) # 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.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.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) )
def test(args=[]): 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 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 # 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 # ############################# 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) mydetector = models.detector mygonio = models.goniometer mycrystal = 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=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 sweep range ray_predictor = ScansRayPredictor(experiments, sweep_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(): from cctbx.sgtbx import space_group, space_group_symbols from dxtbx.model.experiment_list import Experiment, ExperimentList from libtbx.phil import parse from scitbx.array_family import flex 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.goniometer_parameters import ( GoniometerParameterisation, ) #### Import model parameterisations from dials.algorithms.refinement.parameterisation.prediction_parameters import ( XYPhiPredictionParameterisation, ) from dials.algorithms.refinement.prediction.managed_predictors import ( ScansExperimentsPredictor, ScansRayPredictor, ) ##### Imports for reflection prediction from dials.algorithms.spot_prediction import IndexGenerator, ray_intersection ##### Import model builder from dials.tests.algorithms.refinement.setup_geometry import Extract #### Create models 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.tests.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 sequence_range = (0.0, math.pi / 5.0) 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) gon_param = GoniometerParameterisation(mygonio, mybeam) # Create an ExperimentList experiments = ExperimentList() experiments.append( Experiment( beam=mybeam, detector=mydetector, goniometer=mygonio, scan=myscan, crystal=mycrystal, imageset=None, )) #### Unit tests # 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], goniometer_parameterisations=[gon_param], ) # Generate reflections 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) # 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 * math.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) # use a ReflectionManager to exclude reflections too close to the spindle from dials.algorithms.refinement.reflection_manager import ReflectionManager refman = ReflectionManager(obs_refs, experiments, outlier_detector=None) refman.finalise() # Redefine the reflection predictor to use the type expected by the Target class ref_predictor = ScansExperimentsPredictor(experiments) # keep only those reflections that pass inclusion criteria and have predictions reflections = refman.get_matches() # get analytical gradients an_grads = pred_param.get_gradients(reflections) # get finite difference gradients p_vals = pred_param.get_param_vals() deltas = [1.0e-7] * len(p_vals) for i, delta in enumerate(deltas): val = p_vals[i] p_vals[i] -= delta / 2.0 pred_param.set_param_vals(p_vals) ref_predictor(reflections) rev_state = reflections["xyzcal.mm"].deep_copy() p_vals[i] += delta pred_param.set_param_vals(p_vals) ref_predictor(reflections) fwd_state = reflections["xyzcal.mm"].deep_copy() p_vals[i] = val fd = fwd_state - rev_state x_grads, y_grads, phi_grads = fd.parts() x_grads /= delta y_grads /= delta phi_grads /= delta # compare with analytical calculation assert x_grads == pytest.approx(an_grads[i]["dX_dp"], abs=5.0e-6) assert y_grads == pytest.approx(an_grads[i]["dY_dp"], abs=5.5e-6) assert phi_grads == pytest.approx(an_grads[i]["dphi_dp"], abs=5.0e-6) # return to the initial state pred_param.set_param_vals(p_vals)
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 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=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 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 / 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