def get_parameter_correlation_matrix(self, step, col_select=None): """Return the correlation matrix between columns of the Jacobian at the specified refinement step. The parameter col_select can be used to select subsets of the full number of columns. The column labels are also returned as a list of strings""" corrmats = self._refinery.get_correlation_matrix_for_step(step) if corrmats is None: return None, None all_labels = self._pred_param.get_param_names() from dials.algorithms.refinement.refinement_helpers import string_sel if col_select is None: col_select = list(range(len(all_labels))) sel = string_sel(col_select, all_labels) labels = [e for e, s in zip(all_labels, sel) if s] num_cols = len(labels) if num_cols == 0: return None, None for k, corrmat in corrmats.items(): assert corrmat.is_square_matrix() idx = flex.bool(sel).iselection() sub_corrmat = flex.double(flex.grid(num_cols, num_cols)) for (i, x) in enumerate(idx): for (j, y) in enumerate(idx): sub_corrmat[i, j] = corrmat[x, y] corrmats[k] = sub_corrmat return (corrmats, labels)
def _parameterise_goniometers(options, experiments, analysis): gon_params = [] sv_gon = options.scan_varying and not options.goniometer.force_static for igoniometer, goniometer in enumerate(experiments.goniometers()): if goniometer is None: continue # A Goniometer is parameterised with reference to the beam axis. # Use the first Beam this Goniometer is associated with. exp_ids = experiments.indices(goniometer) assoc_models = [(experiments[i].beam, experiments[i].scan) for i in exp_ids] beam, scan = assoc_models[0] if sv_gon: # If a goniometer is scan-varying, then it must always be found # alongside the same Scan in any Experiments in which it appears if not scan: raise DialsRefineConfigError( "A scan-varying goniometer model cannot be created " "because a scan model is missing") if not all(s is scan for (g, s) in assoc_models): raise DialsRefineConfigError( "A single scan-varying goniometer model cannot be " "refined when associated with more than one scan") array_range = scan.get_array_range() n_intervals = _set_n_intervals(options.goniometer.smoother, analysis, scan, exp_ids) gon_param = ScanVaryingGoniometerParameterisation( goniometer, array_range, n_intervals, beam=beam, experiment_ids=exp_ids) else: # force model to be static gon_param = GoniometerParameterisation(goniometer, beam, experiment_ids=exp_ids) # Set the model identifier to name the parameterisation gon_param.model_identifier = "Goniometer{}".format(igoniometer + 1) # get number of fixable units, either parameters or parameter sets in # the scan-varying case num_gon = getattr(gon_param, "num_sets", getattr(gon_param, "num_total"))() fix_list = [] if options.goniometer.fix_list: fix_list.extend(options.goniometer.fix_list) if options.goniometer.fix: if "all" in options.goniometer.fix: gon_param.set_fixed([True] * num_gon) if "in_beam_plane" in options.goniometer.fix: fix_list.append("Gamma1") if "out_beam_plane" in options.goniometer.fix: fix_list.append("Gamma2") if fix_list: names = _filter_parameter_names(gon_param) assert len(names) == num_gon to_fix = string_sel(fix_list, names, gon_param.model_identifier) gon_param.set_fixed(to_fix) if gon_param.num_free() > 0: gon_params.append(gon_param) return gon_params
def _parameterise_crystals(options, experiments, analysis): xl_ori_params = [] xl_uc_params = [] sv_xl_ori = options.scan_varying and not options.crystal.orientation.force_static sv_xl_uc = options.scan_varying and not options.crystal.unit_cell.force_static for icrystal, crystal in enumerate(experiments.crystals()): # This crystal can only ever appear either in scans or in stills # (otherwise it requires a different crystal model) exp_ids = experiments.indices(crystal) assoc_models = [(experiments[i].goniometer, experiments[i].scan) for i in exp_ids] goniometer, scan = assoc_models[0] if goniometer is None: # There should be no associated goniometer and scan models if any(g or s for (g, s) in assoc_models): raise DialsRefineConfigError( "A crystal model appears in a mixture of scan and still " "experiments, which is not supported") if sv_xl_ori or sv_xl_uc: if not all((goniometer, scan)): raise DialsRefineConfigError( "A scan-varying crystal model cannot be created because " "a scan or goniometer model is missing") # If a crystal is scan-varying, then it must always be found alongside # the same Scan and Goniometer in any Experiments in which it appears if not all(g is goniometer and s is scan for (g, s) in assoc_models): raise DialsRefineConfigError( "A single scan-varying crystal model cannot be refined " "when associated with more than one scan or goniometer") array_range = scan.get_array_range() # orientation parameterisation if sv_xl_ori: n_intervals = _set_n_intervals( options.crystal.orientation.smoother, analysis, scan, exp_ids) xl_ori_param = ScanVaryingCrystalOrientationParameterisation( crystal, array_range, n_intervals, experiment_ids=exp_ids) else: # force model to be static xl_ori_param = CrystalOrientationParameterisation( crystal, experiment_ids=exp_ids) # Set the model identifier to name the parameterisation xl_ori_param.model_identifier = "Crystal{}".format(icrystal + 1) # unit cell parameterisation if sv_xl_uc: n_intervals = _set_n_intervals(options.crystal.unit_cell.smoother, analysis, scan, exp_ids) set_errors = options.set_scan_varying_errors xl_uc_param = ScanVaryingCrystalUnitCellParameterisation( crystal, array_range, n_intervals, experiment_ids=exp_ids, set_state_uncertainties=set_errors, ) else: # force model to be static xl_uc_param = CrystalUnitCellParameterisation( crystal, experiment_ids=exp_ids) # Set the model identifier to name the parameterisation xl_uc_param.model_identifier = "Crystal{}".format(icrystal + 1) # get number of fixable units, either parameters or parameter sets in # the scan-varying case num_ori = getattr(xl_ori_param, "num_sets", getattr(xl_ori_param, "num_total"))() num_uc = getattr(xl_uc_param, "num_sets", getattr(xl_uc_param, "num_total"))() ori_fix_list = [] if options.crystal.orientation.fix_list: ori_fix_list.extend(options.crystal.orientation.fix_list) cell_fix_list = [] if options.crystal.unit_cell.fix_list: cell_fix_list.extend(options.crystal.unit_cell.fix_list) if options.crystal.fix: if options.crystal.fix == "all": xl_ori_param.set_fixed([True] * num_ori) xl_uc_param.set_fixed([True] * num_uc) elif options.crystal.fix == "cell": xl_uc_param.set_fixed([True] * num_uc) elif options.crystal.fix == "orientation": xl_ori_param.set_fixed([True] * num_ori) else: # can only get here if refinement.phil is broken raise RuntimeError("crystal.fix value not recognised") if cell_fix_list: names = _filter_parameter_names(xl_uc_param) assert len(names) == num_uc to_fix = string_sel(cell_fix_list, names, xl_uc_param.model_identifier) xl_uc_param.set_fixed(to_fix) if ori_fix_list: names = _filter_parameter_names(xl_ori_param) assert len(names) == num_ori to_fix = string_sel(ori_fix_list, names, xl_ori_param.model_identifier) xl_ori_param.set_fixed(to_fix) if xl_ori_param.num_free() > 0: xl_ori_params.append(xl_ori_param) if xl_uc_param.num_free() > 0: xl_uc_params.append(xl_uc_param) return xl_ori_params, xl_uc_params
def _parameterise_detectors(options, experiments, analysis): det_params = [] sv_det = options.scan_varying and not options.detector.force_static for idetector, detector in enumerate(experiments.detectors()): # keep associated gonio and scan in case we are scan-varying exp_ids = experiments.indices(detector) assoc_models = [(experiments[i].goniometer, experiments[i].scan) for i in exp_ids] goniometer, scan = assoc_models[0] if sv_det: if not all((goniometer, scan)): raise DialsRefineConfigError( "A scan-varying detector model cannot be created " "because a scan or goniometer model is missing") # If a detector is scan-varying, then it must always be found alongside # the same Scan and Goniometer in any Experiments in which it appears if not all(g is goniometer and s is scan for (g, s) in assoc_models): raise DialsRefineConfigError( "A single scan-varying detector model cannot be " "refined when associated with more than one scan or goniometer" ) # Additional checks on whether a scan-varying parameterisation is allowed if options.detector.panels == "automatic" and len(detector) > 1: raise DialsRefineConfigError( "Scan-varying multiple panel detectors are not " "currently supported") if options.detector.panels == "multiple": raise DialsRefineConfigError( "Scan-varying multiple panel detectors are not " "currently supported") if options.detector.panels == "hierarchical": raise DialsRefineConfigError( "Scan-varying hierarchical detectors are not " "currently supported") array_range = scan.get_array_range() n_intervals = _set_n_intervals(options.detector.smoother, analysis, scan, exp_ids) det_param = ScanVaryingDetectorParameterisationSinglePanel( detector, array_range, n_intervals, experiment_ids=exp_ids) else: # Convert automatic into correct specific option if options.detector.panels == "automatic": if len(detector) > 1: if hasattr(detector, "hierarchy"): options.detector.panels = "hierarchical" else: options.detector.panels = "multiple" else: options.detector.panels = "single" # Construct parameterisation based on panels choice if options.detector.panels == "single": if len(detector) > 1: raise DialsRefineConfigError( "A single panel parameterisation cannot be created " "for a multiple panel detector") det_param = DetectorParameterisationSinglePanel( detector, experiment_ids=exp_ids) elif options.detector.panels == "multiple": # Take first associated beam model beam = experiments[exp_ids[0]].beam det_param = DetectorParameterisationMultiPanel( detector, beam, experiment_ids=exp_ids) elif options.detector.panels == "hierarchical": try: # Use hierarchy in parameterisation if the detector has one detector.hierarchy() det_param = DetectorParameterisationHierarchical( detector, experiment_ids=exp_ids, level=options.detector.hierarchy_level, ) except AttributeError: raise DialsRefineConfigError( "A hierarchical detector parameterisation cannot be " "created for a detector without a hierarchy") # Set the model identifier to name the parameterisation det_param.model_identifier = "Detector{}".format(idetector + 1) # get number of fixable units, either parameters or parameter sets in # the scan-varying case num_det = getattr(det_param, "num_sets", getattr(det_param, "num_total"))() fix_list = [] if options.detector.fix_list: fix_list.extend(options.detector.fix_list) if options.detector.fix: if options.detector.fix == "all": det_param.set_fixed([True] * num_det) elif options.detector.fix == "position": fix_list.extend(["Dist", "Shift1", "Shift2"]) elif options.detector.fix == "orientation": fix_list.extend(["Tau"]) elif options.detector.fix == "distance": fix_list.extend(["Dist", "Tau2", "Tau3"]) else: # can only get here if refinement.phil is broken raise RuntimeError("detector.fix value not recognised") if fix_list: names = _filter_parameter_names(det_param) assert len(names) == num_det to_fix = string_sel(fix_list, names, det_param.model_identifier) det_param.set_fixed(to_fix) if det_param.num_free() > 0: det_params.append(det_param) return det_params
def _parameterise_beams(options, experiments, analysis): beam_params = [] sv_beam = options.scan_varying and not options.beam.force_static for ibeam, beam in enumerate(experiments.beams()): # The Beam is parameterised with reference to a goniometer axis (or None). # Use the first (if any) Goniometers this Beam is associated with. exp_ids = experiments.indices(beam) assoc_models = [(experiments[i].goniometer, experiments[i].scan) for i in exp_ids] goniometer, scan = assoc_models[0] if sv_beam: if not all((goniometer, scan)): raise DialsRefineConfigError( "A scan-varying beam model cannot be created because " "a scan or goniometer model is missing") # If a beam is scan-varying, then it must always be found alongside # the same Scan and Goniometer in any Experiments in which it appears if not all(g is goniometer and s is scan for (g, s) in assoc_models): raise DialsRefineConfigError( "A single scan-varying beam model cannot be refined " "when associated with more than one scan or goniometer") array_range = scan.get_array_range() n_intervals = _set_n_intervals(options.beam.smoother, analysis, scan, exp_ids) beam_param = ScanVaryingBeamParameterisation( beam, array_range, n_intervals, goniometer=goniometer, experiment_ids=exp_ids, ) else: # Parameterise scan static beam, passing the goniometer beam_param = BeamParameterisation(beam, goniometer, experiment_ids=exp_ids) # Set the model identifier to name the parameterisation beam_param.model_identifier = "Beam{}".format(ibeam + 1) # get number of fixable units, either parameters or parameter sets in # the scan-varying case num_beam = getattr(beam_param, "num_sets", getattr(beam_param, "num_total"))() fix_list = [] if options.beam.fix_list: fix_list.extend(options.beam.fix_list) if options.beam.fix: if "all" in options.beam.fix: beam_param.set_fixed([True] * num_beam) if "in_spindle_plane" in options.beam.fix: fix_list.append("Mu1") if "out_spindle_plane" in options.beam.fix: fix_list.append("Mu2") if "wavelength" in options.beam.fix: fix_list.append("nu") if fix_list: names = _filter_parameter_names(beam_param) assert len(names) == num_beam to_fix = string_sel(fix_list, names, beam_param.model_identifier) beam_param.set_fixed(to_fix) if beam_param.num_free() > 0: beam_params.append(beam_param) return beam_params