def test_determine_space_group(space_group): sgi = sgtbx.space_group_info(symbol=space_group) sg = sgi.group() cs = sgi.any_compatible_crystal_symmetry(volume=10000) cs = cs.best_cell() cs = cs.minimum_cell() intensities = ( generate_intensities(cs, d_min=1.0) .generate_bijvoet_mates() .set_observation_type_xray_intensity() ) intensities = intensities.expand_to_p1() # needed to give vaguely sensible E_cc_true values intensities = intensities.customized_copy(sigmas=intensities.data() / 50) intensities.set_info(miller.array_info(source="fake", source_type="mtz")) result = LaueGroupAnalysis([intensities], normalisation=None) print(result) assert ( result.best_solution.subgroup["best_subsym"].space_group() == sg.build_derived_patterson_group() ) assert result.best_solution.likelihood > 0.8 for score in result.subgroup_scores[1:]: assert score.likelihood < 0.1
def test_determine_space_group(space_group): sgi = sgtbx.space_group_info(symbol=space_group) sg = sgi.group() cs = sgi.any_compatible_crystal_symmetry(volume=10000) cs = cs.best_cell() cs = cs.minimum_cell() intensities = generate_fake_intensities(cs) result = LaueGroupAnalysis([intensities], normalisation=None) print(result) assert (result.best_solution.subgroup["best_subsym"].space_group() == sg.build_derived_patterson_group()) assert result.best_solution.likelihood > 0.8 for score in result.subgroup_scores[1:]: assert score.likelihood < 0.1
def test_determine_space_group_best_monoclinic_beta(): cs = crystal.symmetry( unit_cell=(44.66208171, 53.12629403, 62.53397661, 64.86329707, 78.27343894, 90), space_group_symbol="C 1 2/m 1 (z,x+y,-2*x)", ) cs = cs.best_cell().primitive_setting() intensities = generate_fake_intensities(cs) result = LaueGroupAnalysis([intensities], normalisation=None) print(result) assert result.best_solution.subgroup["best_subsym"].is_similar_symmetry( crystal.symmetry( unit_cell=(44.66208171, 53.12629403, 111.9989451, 90, 99.89337396, 90), space_group_symbol="I 1 2/m 1", )) d = result.as_dict() assert cs.change_basis( sgtbx.change_of_basis_op( d["subgroup_scores"][0]["cb_op"])).is_similar_symmetry( result.best_solution.subgroup["best_subsym"]) result = LaueGroupAnalysis([intensities], best_monoclinic_beta=False, normalisation=None) print(result) assert result.best_solution.subgroup["best_subsym"].is_similar_symmetry( crystal.symmetry( unit_cell=(113.2236274, 53.12629403, 44.66208171, 90, 102.9736126, 90), space_group_symbol="C 1 2/m 1", )) d = result.as_dict() assert cs.change_basis( sgtbx.change_of_basis_op( d["subgroup_scores"][0]["cb_op"])).is_similar_symmetry( result.best_solution.subgroup["best_subsym"])
def symmetry(experiments, reflection_tables, params=None): """ Run symmetry analysis Args: experiments: An experiment list. reflection_tables: A list of reflection tables. params: The dials.symmetry phil scope. """ result = None if params is None: params = phil_scope.extract() refls_for_sym = [] if params.laue_group is Auto: logger.info("=" * 80) logger.info("") logger.info("Performing Laue group analysis") logger.info("") # Transform models into miller arrays n_datasets = len(experiments) # Map experiments and reflections to minimum cell # Eliminate reflections that are systematically absent due to centring # of the lattice, otherwise they would lead to non-integer miller indices # when reindexing to a primitive setting cb_ops = change_of_basis_ops_to_minimum_cell( experiments, params.lattice_symmetry_max_delta, params.relative_length_tolerance, params.absolute_angle_tolerance, ) reflection_tables = eliminate_sys_absent(experiments, reflection_tables) experiments, reflection_tables = apply_change_of_basis_ops( experiments, reflection_tables, cb_ops) refls_for_sym = get_subset_for_symmetry(experiments, reflection_tables, params.exclude_images) datasets = filtered_arrays_from_experiments_reflections( experiments, refls_for_sym, outlier_rejection_after_filter=True, partiality_threshold=params.partiality_threshold, ) if len(datasets) != n_datasets: raise ValueError( """Some datasets have no reflection after prefiltering, please check input data and filtering settings e.g partiality_threshold""") datasets = [ ma.as_anomalous_array().merge_equivalents().array() for ma in datasets ] result = LaueGroupAnalysis( datasets, normalisation=params.normalisation, d_min=params.d_min, min_i_mean_over_sigma_mean=params.min_i_mean_over_sigma_mean, lattice_symmetry_max_delta=params.lattice_symmetry_max_delta, relative_length_tolerance=params.relative_length_tolerance, absolute_angle_tolerance=params.absolute_angle_tolerance, best_monoclinic_beta=params.best_monoclinic_beta, ) logger.info("") logger.info(result) if params.output.json is not None: d = result.as_dict() d["cb_op_inp_min"] = [str(cb_op) for cb_op in cb_ops] # Copy the "input_symmetry" to "min_cell_symmetry" as it isn't technically # the input symmetry to dials.symmetry d["min_cell_symmetry"] = d["input_symmetry"] del d["input_symmetry"] json_str = json.dumps(d, indent=2) with open(params.output.json, "w") as f: f.write(json_str) # Change of basis operator from input unit cell to best unit cell cb_op_inp_best = result.best_solution.subgroup["cb_op_inp_best"] # Get the best space group. best_subsym = result.best_solution.subgroup["best_subsym"] best_space_group = best_subsym.space_group( ).build_derived_acentric_group() logger.info( tabulate( [[ str(best_subsym.space_group_info()), str(best_space_group.info()) ]], ["Patterson group", "Corresponding MX group"], )) # Reindex the input data experiments, reflection_tables = _reindex_experiments_reflections( experiments, reflection_tables, best_space_group, cb_op_inp_best) elif params.laue_group is not None: if params.change_of_basis_op is not None: cb_op = sgtbx.change_of_basis_op(params.change_of_basis_op) else: cb_op = sgtbx.change_of_basis_op() # Reindex the input data experiments, reflection_tables = _reindex_experiments_reflections( experiments, reflection_tables, params.laue_group.group(), cb_op) if params.systematic_absences.check: logger.info("=" * 80) logger.info("") logger.info("Analysing systematic absences") logger.info("") # Get the laue class from the current space group. space_group = experiments[0].crystal.get_space_group() laue_group = str(space_group.build_derived_patterson_group().info()) logger.info("Laue group: %s", laue_group) if laue_group in ("I m -3", "I m m m"): if laue_group == "I m -3": logger.info( """Space groups I 2 3 & I 21 3 cannot be distinguished with systematic absence analysis, due to lattice centering. Using space group I 2 3, space group I 21 3 is equally likely.\n""") if laue_group == "I m m m": logger.info( """Space groups I 2 2 2 & I 21 21 21 cannot be distinguished with systematic absence analysis, due to lattice centering. Using space group I 2 2 2, space group I 21 21 21 is equally likely.\n""") elif laue_group not in laue_groups_for_absence_analysis: logger.info("No absences to check for this laue group\n") else: if not refls_for_sym: refls_for_sym = get_subset_for_symmetry( experiments, reflection_tables, params.exclude_images) if (params.d_min is Auto) and (result is not None): d_min = result.intensities.resolution_range()[1] elif params.d_min is Auto: d_min = resolution_filter_from_reflections_experiments( refls_for_sym, experiments, params.min_i_mean_over_sigma_mean, params.min_cc_half, ) else: d_min = params.d_min # combine before sys abs test - only triggers if laue_group=None and # multiple input files. if len(reflection_tables) > 1: joint_reflections = flex.reflection_table() for table in refls_for_sym: joint_reflections.extend(table) else: joint_reflections = refls_for_sym[0] merged_reflections = prepare_merged_reflection_table( experiments, joint_reflections, d_min) run_systematic_absences_checks( experiments, merged_reflections, float(params.systematic_absences.significance_level), ) logger.info( "Saving reindexed experiments to %s in space group %s", params.output.experiments, str(experiments[0].crystal.get_space_group().info()), ) experiments.as_file(params.output.experiments) if params.output.reflections is not None: if len(reflection_tables) > 1: joint_reflections = flex.reflection_table() for table in reflection_tables: joint_reflections.extend(table) else: joint_reflections = reflection_tables[0] logger.info( "Saving %s reindexed reflections to %s", len(joint_reflections), params.output.reflections, ) joint_reflections.as_file(params.output.reflections) if params.output.html and params.systematic_absences.check: ScrewAxisObserver().generate_html_report(params.output.html)