def get_spacegroup(facet, parent_sg, O): """ Get reduced symmetry spacegroup for crystal aligned on `facet`. """ e_field_direction = np.linalg.inv(O) @ (np.linalg.inv(O).T @ facet) e_field_unit_vector = np.array(e_field_direction) / np.linalg.norm( e_field_direction) parent = sgtbx.space_group_info(parent_sg) subgrs = subgroups.subgroups(parent).groups_parent_setting() possible = [] for subgroup in subgrs: subgroup_info = sgtbx.space_group_info(group=subgroup) valid = True for op in subgroup.smx(): rot_mat = np.array(op.r().as_double()).reshape((3, 3)) valid &= np.allclose(rot_mat @ e_field_unit_vector, e_field_unit_vector) if valid: possible.append([ subgroup.n_smx(), subgroup_info.symbol_and_number(), subgroup ]) possible = sorted(possible) return possible[-1][1], possible[-1][0]
def generate_mtz_files(space_group_info, anomalous_flag): crystal_symmetry = crystal.symmetry( unit_cell=space_group_info.any_compatible_unit_cell(volume=1000), space_group_info=space_group_info) miller_set = miller.build_set(crystal_symmetry=crystal_symmetry, anomalous_flag=anomalous_flag, d_min=1) miller_array = miller.array( miller_set=miller_set, data=flex.random_double(size=miller_set.indices().size())) miller_array_p1 = miller_array.expand_to_p1() miller_arrays = [] file_names = [] subgrs = subgroups.subgroups(space_group_info).groups_parent_setting() for i_subgroup, subgroup in enumerate(subgrs): subgroup_miller_array = miller_array_p1.customized_copy( space_group_info=sgtbx.space_group_info(group=subgroup)) \ .merge_equivalents() \ .array() \ .as_reference_setting() \ .set_observation_type_xray_intensity() file_name = "tmp_refl_stats%d.mtz" % i_subgroup mtz_object = subgroup_miller_array.as_mtz_dataset( column_root_label="FOBS").mtz_object().write(file_name=file_name) miller_arrays.append( subgroup_miller_array.f_sq_as_f().expand_to_p1().map_to_asu()) file_names.append(file_name) return miller_arrays, file_names
def generate_mtz_files(space_group_info, anomalous_flag): crystal_symmetry = crystal.symmetry( unit_cell=space_group_info.any_compatible_unit_cell(volume=1000), space_group_info=space_group_info) miller_set = miller.build_set( crystal_symmetry=crystal_symmetry, anomalous_flag=anomalous_flag, d_min=1) miller_array = miller.array( miller_set=miller_set, data=flex.random_double(size=miller_set.indices().size())) miller_array_p1 = miller_array.expand_to_p1() miller_arrays = [] file_names = [] subgrs = subgroups.subgroups(space_group_info).groups_parent_setting() for i_subgroup, subgroup in enumerate(subgrs): subgroup_miller_array = miller_array_p1.customized_copy( space_group_info=sgtbx.space_group_info(group=subgroup)) \ .merge_equivalents() \ .array() \ .as_reference_setting() \ .set_observation_type_xray_intensity() file_name = "tmp_refl_stats%d.mtz" % i_subgroup mtz_object = subgroup_miller_array.as_mtz_dataset( column_root_label="FOBS").mtz_object().write(file_name=file_name) miller_arrays.append( subgroup_miller_array.f_sq_as_f().expand_to_p1().map_to_asu()) file_names.append(file_name) return miller_arrays, file_names
def update_space_group_choices(self): if self.viewer.miller_array is None or \ self.params.NGL_HKLviewer.using_space_subgroup: return current_miller_array_idx = self.viewer.hkl_scenes_info[ self.viewer.scene_id][1] matching_valid_array = self.valid_arrays[current_miller_array_idx] from cctbx.sgtbx.subgroups import subgroups from cctbx import sgtbx sg_info = matching_valid_array.space_group_info() subgrs = subgroups(sg_info).groups_parent_setting() self.spacegroup_choices = [] for i, subgroup in enumerate(subgrs): subgroup_info = sgtbx.space_group_info(group=subgroup) self.spacegroup_choices.append(subgroup_info) if (sg_info in self.spacegroup_choices): self.current_spacegroup = self.spacegroup_choices.index(sg_info) else: self.spacegroup_choices.insert(0, sg_info) self.current_spacegroup = sg_info mydict = { "spacegroups": [e.symbol_and_number() for e in self.spacegroup_choices] } self.SendInfoToGUI(mydict)
def update_space_group_choices(self, col=None) : if (self.viewer.miller_array is None and col is None) or \ self.params.using_space_subgroup: return if col is None: current_miller_array_idx = self.viewer.HKLInfo_from_dict()[1] else: current_miller_array_idx = col matching_valid_array = self.procarrays[ current_miller_array_idx ] from cctbx.sgtbx.subgroups import subgroups from cctbx import sgtbx sg_info = matching_valid_array.space_group_info() subgrs = subgroups(sg_info).groups_parent_setting() self.spacegroup_choices = [] for i,subgroup in enumerate(subgrs) : subgroup_info = sgtbx.space_group_info(group=subgroup) self.spacegroup_choices.append(subgroup_info) for i,e in enumerate(self.spacegroup_choices): c = None if str(sg_info) == str(e): self.current_spacegroup = self.spacegroup_choices[i] c = i break if c is None: c = 0 self.spacegroup_choices.insert(c, sg_info) self.current_spacegroup = sg_info self.params.spacegroup_choice = c spglst = [e.symbol_and_number() for e in self.spacegroup_choices] + ["original spacegroup"] mydict = { "spacegroups": spglst } self.SendInfoToGUI(mydict)
def __init__(self, parent_group_info): self.subgroups = subgroups.subgroups( parent_group_info).groups_parent_setting() self.n_non_centric = 0 self.n_chiral = 0 for subgroup in self.subgroups: if (not subgroup.is_centric()): self.n_non_centric += 1 if (subgroup.is_chiral()): self.n_chiral += 1
def test_double_coset_decomposition(): from cctbx.sgtbx import subgroups for space_group_number in xrange(17, 44): parent_group_info = sgtbx.space_group_info(space_group_number) subgrs = subgroups.subgroups(parent_group_info).groups_parent_setting() g = parent_group_info.group() for h1 in subgrs: for h2 in subgrs: tmp_new = double_cosets(g, h1, h2) assert not tmp_new.have_duplicates()
def test_double_coset_decomposition(): from cctbx.sgtbx import subgroups for space_group_number in xrange(17,44): parent_group_info = sgtbx.space_group_info(space_group_number) subgrs = subgroups.subgroups(parent_group_info).groups_parent_setting() g = parent_group_info.group() for h1 in subgrs: for h2 in subgrs: tmp_new = double_cosets(g, h1, h2) assert not tmp_new.have_duplicates()
def exercise_quick(): for space_group_symbol in ("P-1", "P2/m", "C2/m", "Pmmm", "Cmmm", "Fmmm", "Immm", "P4/mmm", "I4/mmm", "R-3m", "P6/mmm", "Pm-3m", "Im-3m", "Fm-3m"): parent_group_info = sgtbx.space_group_info(space_group_symbol) non_centric = sgtbx.space_group() for i_ltr in xrange(parent_group_info.group().n_ltr()): for i_smx in xrange(parent_group_info.group().n_smx()): s = parent_group_info.group()(i_ltr,0,i_smx) non_centric.expand_smx(s) assert non_centric.f_inv() == 1 assert non_centric.order_z() * 2 == parent_group_info.group().order_z() non_centric_info = sgtbx.space_group_info(group=non_centric) unit_cell = non_centric_info.any_compatible_unit_cell(volume=1000) crystal_symmetry = crystal.symmetry( unit_cell=unit_cell, space_group_info=non_centric_info) minimum_symmetry = crystal_symmetry.minimum_cell() lattice_group = lattice_symmetry.group( minimum_symmetry.unit_cell(), max_delta=0.5) lattice_group_info = sgtbx.space_group_info(group=lattice_group) assert lattice_group_info.group() == minimum_symmetry.space_group() subgrs = subgroups.subgroups(lattice_group_info).groups_parent_setting() for group in subgrs: subsym = crystal.symmetry( unit_cell=minimum_symmetry.unit_cell(), space_group=group, assert_is_compatible_unit_cell=False) assert subsym.unit_cell().is_similar_to(minimum_symmetry.unit_cell()) assert lattice_symmetry.find_max_delta( reduced_cell=minimum_symmetry.unit_cell(), space_group=group) < 0.6 minimum_symmetry = crystal.symmetry( unit_cell="106.04, 181.78, 110.12, 90, 90, 90", space_group_symbol="P 1").minimum_cell() for max_delta in xrange(10,100,10): lattice_group = lattice_symmetry.group( minimum_symmetry.unit_cell(), max_delta=max_delta) lattice_group_info = sgtbx.space_group_info(group=lattice_group) assert str(lattice_group_info) == "P 4 2 2"
def update_space_group_choices(self): from cctbx.sgtbx.subgroups import subgroups from cctbx import sgtbx sg_info = self.miller_array.space_group_info() subgrs = subgroups(sg_info).groups_parent_setting() self.spacegroup_choices = [] for i, subgroup in enumerate(subgrs): subgroup_info = sgtbx.space_group_info(group=subgroup) self.spacegroup_choices.append(subgroup_info) self.mprint("%d, %s" % (i, subgroup_info.symbol_and_number())) if (sg_info in self.spacegroup_choices): self.current_spacegroup = self.spacegroup_choices.index(sg_info) else: self.spacegroup_choices.insert(0, sg_info) self.current_spacegroup = sg_info
def update_space_group_choices(self, miller_array): from cctbx.sgtbx.subgroups import subgroups from cctbx import sgtbx sg_info = miller_array.space_group_info() subgrs = subgroups(sg_info).groups_parent_setting() choices = [] for subgroup in subgrs: subgroup_info = sgtbx.space_group_info(group=subgroup) choices.append(str(subgroup_info)) if (str(sg_info) in choices): current = choices.index(str(sg_info)) else: choices.insert(0, str(sg_info)) current = 0 self.sg_ctrl.SetItems(choices) self.sg_ctrl.SetSelection(current) self._last_sg_sel = str(sg_info)
def update_space_group_choices (self, miller_array) : from cctbx.sgtbx.subgroups import subgroups from cctbx import sgtbx sg_info = miller_array.space_group_info() subgrs = subgroups(sg_info).groups_parent_setting() choices = [] for subgroup in subgrs : subgroup_info = sgtbx.space_group_info(group=subgroup) choices.append(str(subgroup_info)) if (str(sg_info) in choices) : current = choices.index(str(sg_info)) else : choices.insert(0, str(sg_info)) current = 0 self.sg_ctrl.SetItems(choices) self.sg_ctrl.SetSelection(current) self._last_sg_sel = str(sg_info)
def exercise_quick(): for space_group_symbol in ("P-1", "P2/m", "C2/m", "Pmmm", "Cmmm", "Fmmm", "Immm", "P4/mmm", "I4/mmm", "R-3m", "P6/mmm", "Pm-3m", "Im-3m", "Fm-3m"): parent_group_info = sgtbx.space_group_info(space_group_symbol) non_centric = sgtbx.space_group() for i_ltr in range(parent_group_info.group().n_ltr()): for i_smx in range(parent_group_info.group().n_smx()): s = parent_group_info.group()(i_ltr, 0, i_smx) non_centric.expand_smx(s) assert non_centric.f_inv() == 1 assert non_centric.order_z() * 2 == parent_group_info.group().order_z() non_centric_info = sgtbx.space_group_info(group=non_centric) unit_cell = non_centric_info.any_compatible_unit_cell(volume=1000) crystal_symmetry = crystal.symmetry(unit_cell=unit_cell, space_group_info=non_centric_info) minimum_symmetry = crystal_symmetry.minimum_cell() lattice_group = lattice_symmetry.group(minimum_symmetry.unit_cell(), max_delta=0.5) lattice_group_info = sgtbx.space_group_info(group=lattice_group) assert lattice_group_info.group() == minimum_symmetry.space_group() subgrs = subgroups.subgroups( lattice_group_info).groups_parent_setting() for group in subgrs: subsym = crystal.symmetry(unit_cell=minimum_symmetry.unit_cell(), space_group=group, assert_is_compatible_unit_cell=False) assert subsym.unit_cell().is_similar_to( minimum_symmetry.unit_cell()) assert lattice_symmetry.find_max_delta( reduced_cell=minimum_symmetry.unit_cell(), space_group=group) < 0.6 minimum_symmetry = crystal.symmetry( unit_cell="106.04, 181.78, 110.12, 90, 90, 90", space_group_symbol="P 1").minimum_cell() for max_delta in range(10, 100, 10): lattice_group = lattice_symmetry.group(minimum_symmetry.unit_cell(), max_delta=max_delta) lattice_group_info = sgtbx.space_group_info(group=lattice_group) assert str(lattice_group_info) == "P 4 2 2"
def tst_bravais_types(verbose): from cctbx import sgtbx from cctbx.sgtbx.subgroups import subgroups bravais_types_reference = {"aP":2,"mP":8,"mC":5,"mA":0,"mI":0,"mB":0,"oP":30,"oC":11, "oA":4,"oB":0,"oI":9,"oF":5,"tP":49,"tI":19,"hP":45,"hR":7, "cP":15,"cI":10,"cF":11} bravais_types_tally = {} for key in bravais_types_reference: bravais_types_tally[key]=0 crystal_systems_reference = {"Triclinic":2,"Monoclinic":13,"Orthorhombic":59,"Tetragonal":68, "Trigonal":25,"Hexagonal":27,"Cubic":36} crystal_systems_tally = {} for key in crystal_systems_reference: crystal_systems_tally[key]=0 for space_group_number in xrange(1,231): space_group_info = sgtbx.space_group_info(number=space_group_number) GC = bravais_lattice(number=space_group_number) GC_1 = bravais_lattice(group=space_group_info.group()) GC_2 = bravais_lattice(symbol=str(space_group_info)) assert GC == GC_1 assert GC == GC_2 bravais_types_tally[str(GC)]+=1 crystal_systems_tally[GC.crystal_system]+=1 if verbose: GC.space_group_info.show_summary() print str(GC), GC.crystal_system # idea, not fully implemented--more extensive testing by generating all subgroups if False: subgrs = subgroups(parent_group_info).groups_parent_setting() for subgroup in subgrs: subgroup_info = sgtbx.space_group_info(group=subgroup) subgroup_info.show_summary() bravais_lattice(subgroup_info.type().lookup_symbol()) return (bravais_types_tally==bravais_types_reference and crystal_systems_tally==crystal_systems_reference)
def tst_bravais_types(verbose): from cctbx import sgtbx from cctbx.sgtbx.subgroups import subgroups bravais_types_reference = { "aP": 2, "mP": 8, "mC": 5, "mA": 0, "mI": 0, "mB": 0, "oP": 30, "oC": 11, "oA": 4, "oB": 0, "oI": 9, "oF": 5, "tP": 49, "tI": 19, "hP": 45, "hR": 7, "cP": 15, "cI": 10, "cF": 11 } bravais_types_tally = {} for key in bravais_types_reference: bravais_types_tally[key] = 0 crystal_systems_reference = { "Triclinic": 2, "Monoclinic": 13, "Orthorhombic": 59, "Tetragonal": 68, "Trigonal": 25, "Hexagonal": 27, "Cubic": 36 } crystal_systems_tally = {} for key in crystal_systems_reference: crystal_systems_tally[key] = 0 for space_group_number in xrange(1, 231): space_group_info = sgtbx.space_group_info(number=space_group_number) GC = bravais_lattice(number=space_group_number) GC_1 = bravais_lattice(group=space_group_info.group()) GC_2 = bravais_lattice(symbol=str(space_group_info)) assert GC == GC_1 assert GC == GC_2 bravais_types_tally[str(GC)] += 1 crystal_systems_tally[GC.crystal_system] += 1 if verbose: GC.space_group_info.show_summary() print str(GC), GC.crystal_system # idea, not fully implemented--more extensive testing by generating all subgroups if False: subgrs = subgroups(parent_group_info).groups_parent_setting() for subgroup in subgrs: subgroup_info = sgtbx.space_group_info(group=subgroup) subgroup_info.show_summary() bravais_lattice(subgroup_info.type().lookup_symbol()) return (bravais_types_tally == bravais_types_reference and crystal_systems_tally == crystal_systems_reference)
def generate_test_data( space_group, lattice_group=None, unit_cell=None, unit_cell_volume=1000, seed=0, d_min=1, sigma=0.1, sample_size=100, map_to_p1=False, twin_fractions=None, map_to_minimum=True, ): import random if seed is not None: flex.set_random_seed(seed) random.seed(seed) assert [unit_cell, lattice_group].count(None) > 0 sgi = space_group.info() if unit_cell is not None: cs = crystal.symmetry(unit_cell=unit_cell, space_group_info=sgi) elif lattice_group is not None: subgrps = subgroups(lattice_group).groups_parent_setting() assert space_group in subgrps cs = lattice_group.any_compatible_crystal_symmetry( volume=unit_cell_volume).customized_copy(space_group_info=sgi) else: cs = sgi.any_compatible_crystal_symmetry(volume=unit_cell_volume) if map_to_minimum: cs = cs.minimum_cell() intensities = generate_intensities(cs, d_min=d_min) intensities.show_summary() twin_ops = generate_twin_operators(intensities) twin_ops = [ sgtbx.change_of_basis_op(op.operator.as_xyz()) for op in twin_ops ] if twin_fractions is not None: assert len(twin_fractions) == len(twin_ops) assert len( twin_fractions) == 1, "Only 1 twin component currently supported" twin_op = twin_ops[0] twin_fraction = twin_fractions[0] intensities, intensities_twin = intensities.common_sets( intensities.change_basis(twin_op).map_to_asu()) twinned_miller = intensities.customized_copy( data=(1.0 - twin_fraction) * intensities.data() + twin_fraction * intensities_twin.data(), sigmas=flex.sqrt( flex.pow2((1.0 - twin_fraction) * intensities.sigmas()) + flex.pow2(twin_fraction * intensities_twin.sigmas())), ) intensities = twinned_miller cb_ops = twin_ops cb_ops.insert(0, sgtbx.change_of_basis_op()) reindexing_ops = {} datasets = [] rand_norm = scitbx.random.normal_distribution(mean=0, sigma=sigma) g = scitbx.random.variate(rand_norm) for i in range(sample_size): cb_op = random.choice(cb_ops) if cb_op.as_xyz() not in reindexing_ops: reindexing_ops[cb_op.as_xyz()] = set() reindexing_ops[cb_op.as_xyz()].add(i) d = intensities.change_basis(cb_op).customized_copy( crystal_symmetry=intensities.crystal_symmetry()) if map_to_p1: cb_op_to_primitive = d.change_of_basis_op_to_primitive_setting() d = d.change_basis(cb_op_to_primitive) d = d.expand_to_p1() d = d.customized_copy(data=d.data() + g(d.size())) datasets.append(d) return datasets, reindexing_ops
def derive_result_group_list_original_input(self,group_of_interest): # more-or-less a capitulation to code duplication. Don't want to copy code # from cctbx.sgtbx.lattice_symmetry but can't figure out a quick way around it. # Get list of sub-spacegroups subgrs = subgroups.subgroups(group_of_interest).groups_parent_setting() # Order sub-groups sort_values = flex.double() for group in subgrs: order_z = group.order_z() space_group_number = sgtbx.space_group_type(group, False).number() assert 1 <= space_group_number <= 230 sort_values.append(order_z*1000+space_group_number) perm = flex.sort_permutation(sort_values, True) for i_subgr in perm: acentric_subgroup = subgrs[i_subgr] acentric_supergroup = metric_supergroup(acentric_subgroup) # Add centre of inversion to acentric lattice symmetry centric_group = sgtbx.space_group(acentric_subgroup) # Make symmetry object: unit-cell + space-group # The unit cell is potentially modified to be exactly compatible # with the space group symmetry. subsym = crystal.symmetry( unit_cell=self.minimum_symmetry.unit_cell(), space_group=centric_group, assert_is_compatible_unit_cell=False) supersym = crystal.symmetry( unit_cell=self.minimum_symmetry.unit_cell(), space_group=acentric_supergroup, assert_is_compatible_unit_cell=False) # Convert subgroup to reference setting cb_op_minimum_ref = subsym.space_group_info().type().cb_op() ref_subsym = subsym.change_basis(cb_op_minimum_ref) # Ignore unwanted groups if (self.bravais_types_only and not str(ref_subsym.space_group_info()) in bravais_types.centric): continue # Choose best setting for monoclinic and orthorhombic systems cb_op_best_cell = self.change_of_basis_op_to_best_cell(ref_subsym) best_subsym = ref_subsym.change_basis(cb_op_best_cell) # Total basis transformation cb_op_best_cell = change_of_basis_op(str(cb_op_best_cell),stop_chars='',r_den=144,t_den=144) cb_op_minimum_ref=change_of_basis_op(str(cb_op_minimum_ref),stop_chars='',r_den=144,t_den=144) self.cb_op_inp_minimum=change_of_basis_op(str(self.cb_op_inp_minimum),stop_chars='',r_den=144,t_den=144) cb_op_inp_best = cb_op_best_cell * (cb_op_minimum_ref * self.cb_op_inp_minimum) # Use identity change-of-basis operator if possible if (best_subsym.unit_cell().is_similar_to(self.input_symmetry.unit_cell())): cb_op_corr = cb_op_inp_best.inverse() try: best_subsym_corr = best_subsym.change_basis(cb_op_corr) except RuntimeError, e: if (str(e).find("Unsuitable value for rational rotation matrix.") < 0): raise else: if (best_subsym_corr.space_group() == best_subsym.space_group()): cb_op_inp_best = cb_op_corr * cb_op_inp_best """Note: The following call does not work if n_ltr >1 for the space group""" if acentric_subgroup.n_ltr() == 1: m_a_d = find_max_delta( reduced_cell=self.minimum_symmetry.unit_cell(), space_group=acentric_subgroup) else: m_a_d = 0.0 self.result_groups.append({'subsym':subsym, 'supersym':supersym, 'ref_subsym':ref_subsym, 'best_subsym':best_subsym, 'cb_op_inp_best':cb_op_inp_best, 'max_angular_difference':m_a_d })
def find_matching_symmetry(unit_cell, target_space_group, max_delta=5): cs = crystal.symmetry(unit_cell=unit_cell, space_group=sgtbx.space_group()) target_bravais_t = bravais_types.bravais_lattice( group=target_space_group.info().reference_setting().group()) best_subgroup = None best_angular_difference = 1e8 # code based on cctbx/sgtbx/lattice_symmetry.py but optimised to only # look at subgroups with the correct bravais type input_symmetry = cs # Get cell reduction operator cb_op_inp_minimum = input_symmetry.change_of_basis_op_to_minimum_cell() # New symmetry object with changed basis minimum_symmetry = input_symmetry.change_basis(cb_op_inp_minimum) # Get highest symmetry compatible with lattice lattice_group = sgtbx.lattice_symmetry_group( minimum_symmetry.unit_cell(), max_delta=max_delta, enforce_max_delta_for_generated_two_folds=True) # Get list of sub-spacegroups subgrs = subgroups.subgroups(lattice_group.info()).groups_parent_setting() # Order sub-groups sort_values = flex.double() for group in subgrs: order_z = group.order_z() space_group_number = sgtbx.space_group_type(group, False).number() assert 1 <= space_group_number <= 230 sort_values.append(order_z * 1000 + space_group_number) perm = flex.sort_permutation(sort_values, True) for i_subgr in perm: acentric_subgroup = subgrs[i_subgr] acentric_supergroup = metric_supergroup(acentric_subgroup) ## Add centre of inversion to acentric lattice symmetry #centric_group = sgtbx.space_group(acentric_subgroup) #centric_group.expand_inv(sgtbx.tr_vec((0,0,0))) # Make symmetry object: unit-cell + space-group # The unit cell is potentially modified to be exactly compatible # with the space group symmetry. subsym = crystal.symmetry(unit_cell=minimum_symmetry.unit_cell(), space_group=acentric_subgroup, assert_is_compatible_unit_cell=False) #supersym = crystal.symmetry( #unit_cell=minimum_symmetry.unit_cell(), #space_group=acentric_supergroup, #assert_is_compatible_unit_cell=False) # Convert subgroup to reference setting cb_op_minimum_ref = subsym.space_group_info().type().cb_op() ref_subsym = subsym.change_basis(cb_op_minimum_ref) # Ignore unwanted groups bravais_t = bravais_types.bravais_lattice( group=ref_subsym.space_group()) if bravais_t != target_bravais_t: continue # Choose best setting for monoclinic and orthorhombic systems cb_op_best_cell = ref_subsym.change_of_basis_op_to_best_cell( best_monoclinic_beta=True) best_subsym = ref_subsym.change_basis(cb_op_best_cell) # Total basis transformation cb_op_best_cell = change_of_basis_op(str(cb_op_best_cell), stop_chars='', r_den=144, t_den=144) cb_op_minimum_ref = change_of_basis_op(str(cb_op_minimum_ref), stop_chars='', r_den=144, t_den=144) cb_op_inp_minimum = change_of_basis_op(str(cb_op_inp_minimum), stop_chars='', r_den=144, t_den=144) cb_op_inp_best = cb_op_best_cell * cb_op_minimum_ref * cb_op_inp_minimum # Use identity change-of-basis operator if possible if best_subsym.unit_cell().is_similar_to(input_symmetry.unit_cell()): cb_op_corr = cb_op_inp_best.inverse() try: best_subsym_corr = best_subsym.change_basis(cb_op_corr) except RuntimeError as e: if str(e).find( "Unsuitable value for rational rotation matrix.") < 0: raise else: if best_subsym_corr.space_group() == best_subsym.space_group(): cb_op_inp_best = cb_op_corr * cb_op_inp_best max_angular_difference = find_max_delta( reduced_cell=minimum_symmetry.unit_cell(), space_group=acentric_supergroup) if max_angular_difference < best_angular_difference: #best_subgroup = subgroup best_angular_difference = max_angular_difference best_subgroup = { 'subsym': subsym, #'supersym':supersym, 'ref_subsym': ref_subsym, 'best_subsym': best_subsym, 'cb_op_inp_best': cb_op_inp_best, 'max_angular_difference': max_angular_difference } if best_subgroup is not None: return best_subgroup
def derive_result_group_list(self, group_of_interest): # Get list of sub-spacegroups subgrs = subgroups.subgroups(group_of_interest).groups_parent_setting() # Order sub-groups sort_values = flex.double() for group in subgrs: order_z = group.order_z() space_group_number = sgtbx.space_group_type(group, False).number() assert 1 <= space_group_number <= 230 sort_values.append(order_z * 1000 + space_group_number) perm = flex.sort_permutation(sort_values, True) for i_subgr in perm: acentric_subgroup = subgrs[i_subgr] acentric_supergroup = metric_supergroup(acentric_subgroup) # Add centre of inversion to acentric lattice symmetry centric_group = sgtbx.space_group(acentric_subgroup) centric_group.expand_inv(sgtbx.tr_vec((0, 0, 0))) # Make symmetry object: unit-cell + space-group # The unit cell is potentially modified to be exactly compatible # with the space group symmetry. subsym = crystal.symmetry( unit_cell=self.minimum_symmetry.unit_cell(), space_group=centric_group, assert_is_compatible_unit_cell=False) supersym = crystal.symmetry( unit_cell=self.minimum_symmetry.unit_cell(), space_group=acentric_supergroup, assert_is_compatible_unit_cell=False) # Convert subgroup to reference setting cb_op_minimum_ref = subsym.space_group_info().type().cb_op() ref_subsym = subsym.change_basis(cb_op_minimum_ref) # Ignore unwanted groups if (self.bravais_types_only and not str( ref_subsym.space_group_info()) in bravais_types.centric): continue # Choose best setting for monoclinic and orthorhombic systems cb_op_best_cell = self.change_of_basis_op_to_best_cell(ref_subsym) best_subsym = ref_subsym.change_basis(cb_op_best_cell) # Total basis transformation cb_op_best_cell = change_of_basis_op(str(cb_op_best_cell), stop_chars='', r_den=144, t_den=144) cb_op_minimum_ref = change_of_basis_op(str(cb_op_minimum_ref), stop_chars='', r_den=144, t_den=144) self.cb_op_inp_minimum = change_of_basis_op(str( self.cb_op_inp_minimum), stop_chars='', r_den=144, t_den=144) cb_op_inp_best = cb_op_best_cell * cb_op_minimum_ref * self.cb_op_inp_minimum # Use identity change-of-basis operator if possible if (best_subsym.unit_cell().is_similar_to( self.input_symmetry.unit_cell())): cb_op_corr = cb_op_inp_best.inverse() try: best_subsym_corr = best_subsym.change_basis(cb_op_corr) except RuntimeError, e: if (str(e).find( "Unsuitable value for rational rotation matrix.") < 0): raise else: if (best_subsym_corr.space_group() == best_subsym.space_group()): cb_op_inp_best = cb_op_corr * cb_op_inp_best self.result_groups.append({ 'subsym': subsym, 'supersym': supersym, 'ref_subsym': ref_subsym, 'best_subsym': best_subsym, 'cb_op_inp_best': cb_op_inp_best, 'max_angular_difference': find_max_delta(reduced_cell=self.minimum_symmetry.unit_cell(), space_group=acentric_supergroup) })
def find_matching_symmetry(unit_cell, target_space_group, max_delta=5): cs = crystal.symmetry(unit_cell=unit_cell, space_group=sgtbx.space_group()) target_bravais_t = bravais_types.bravais_lattice( group=target_space_group.info().reference_setting().group()) best_subgroup = None best_angular_difference = 1e8 # code based on cctbx/sgtbx/lattice_symmetry.py but optimised to only # look at subgroups with the correct bravais type input_symmetry = cs # Get cell reduction operator cb_op_inp_minimum = input_symmetry.change_of_basis_op_to_minimum_cell() # New symmetry object with changed basis minimum_symmetry = input_symmetry.change_basis(cb_op_inp_minimum) # Get highest symmetry compatible with lattice lattice_group = sgtbx.lattice_symmetry_group( minimum_symmetry.unit_cell(), max_delta=max_delta, enforce_max_delta_for_generated_two_folds=True) # Get list of sub-spacegroups subgrs = subgroups.subgroups(lattice_group.info()).groups_parent_setting() # Order sub-groups sort_values = flex.double() for group in subgrs: order_z = group.order_z() space_group_number = sgtbx.space_group_type(group, False).number() assert 1 <= space_group_number <= 230 sort_values.append(order_z*1000+space_group_number) perm = flex.sort_permutation(sort_values, True) for i_subgr in perm: acentric_subgroup = subgrs[i_subgr] acentric_supergroup = metric_supergroup(acentric_subgroup) ## Add centre of inversion to acentric lattice symmetry #centric_group = sgtbx.space_group(acentric_subgroup) #centric_group.expand_inv(sgtbx.tr_vec((0,0,0))) # Make symmetry object: unit-cell + space-group # The unit cell is potentially modified to be exactly compatible # with the space group symmetry. subsym = crystal.symmetry( unit_cell=minimum_symmetry.unit_cell(), space_group=acentric_subgroup, assert_is_compatible_unit_cell=False) #supersym = crystal.symmetry( #unit_cell=minimum_symmetry.unit_cell(), #space_group=acentric_supergroup, #assert_is_compatible_unit_cell=False) # Convert subgroup to reference setting cb_op_minimum_ref = subsym.space_group_info().type().cb_op() ref_subsym = subsym.change_basis(cb_op_minimum_ref) # Ignore unwanted groups bravais_t = bravais_types.bravais_lattice( group=ref_subsym.space_group()) if bravais_t != target_bravais_t: continue # Choose best setting for monoclinic and orthorhombic systems cb_op_best_cell = ref_subsym.change_of_basis_op_to_best_cell( best_monoclinic_beta=True) best_subsym = ref_subsym.change_basis(cb_op_best_cell) # Total basis transformation cb_op_best_cell = change_of_basis_op(str(cb_op_best_cell),stop_chars='',r_den=144,t_den=144) cb_op_minimum_ref=change_of_basis_op(str(cb_op_minimum_ref),stop_chars='',r_den=144,t_den=144) cb_op_inp_minimum=change_of_basis_op(str(cb_op_inp_minimum),stop_chars='',r_den=144,t_den=144) cb_op_inp_best = cb_op_best_cell * cb_op_minimum_ref * cb_op_inp_minimum # Use identity change-of-basis operator if possible if (best_subsym.unit_cell().is_similar_to(input_symmetry.unit_cell())): cb_op_corr = cb_op_inp_best.inverse() try: best_subsym_corr = best_subsym.change_basis(cb_op_corr) except RuntimeError, e: if (str(e).find("Unsuitable value for rational rotation matrix.") < 0): raise else: if (best_subsym_corr.space_group() == best_subsym.space_group()): cb_op_inp_best = cb_op_corr * cb_op_inp_best max_angular_difference = find_max_delta( reduced_cell=minimum_symmetry.unit_cell(), space_group=acentric_supergroup) if max_angular_difference < best_angular_difference: #best_subgroup = subgroup best_angular_difference = max_angular_difference best_subgroup = {'subsym':subsym, #'supersym':supersym, 'ref_subsym':ref_subsym, 'best_subsym':best_subsym, 'cb_op_inp_best':cb_op_inp_best, 'max_angular_difference':max_angular_difference }