def change_of_basis_ops_to_minimum_cell( experiments, max_delta, relative_length_tolerance, absolute_angle_tolerance ): """ Compute change of basis ops to map experiments to the minimum cell Map to the minimum cell via the best cell, which appears to guarantee that the resulting minimum cells are consistent. Args: experiments (ExperimentList): a list of experiments. reflections (list): a list of reflection tables Returns: The experiments and reflections mapped to the minimum cell """ median_cell = median_unit_cell(experiments) unit_cells_are_similar = unit_cells_are_similar_to( experiments, median_cell, relative_length_tolerance, absolute_angle_tolerance ) centring_symbols = [ bravais_lattice(group=expt.crystal.get_space_group()).centring_symbol for expt in experiments ] if unit_cells_are_similar and len(set(centring_symbols)) == 1: groups = metric_subgroups( experiments[0] .crystal.get_crystal_symmetry() .customized_copy(unit_cell=median_cell), max_delta, enforce_max_delta_for_generated_two_folds=True, ) group = groups.result_groups[0] cb_op_best_to_min = group["best_subsym"].change_of_basis_op_to_minimum_cell() cb_ops = [cb_op_best_to_min * group["cb_op_inp_best"]] * len(experiments) else: cb_ops = [] for expt in experiments: groups = metric_subgroups( expt.crystal.get_crystal_symmetry(), max_delta, best_monoclinic_beta=False, enforce_max_delta_for_generated_two_folds=True, ) group = groups.result_groups[0] cb_ops.append(group["cb_op_inp_best"]) ref_expts = experiments.change_basis(cb_ops) cb_op_ref_min = ( ref_expts[0] .crystal.get_crystal_symmetry() .customized_copy(unit_cell=median_unit_cell(ref_expts)) .change_of_basis_op_to_minimum_cell() ) cb_ops = [cb_op_ref_min * cb_op for cb_op in cb_ops] return cb_ops
def tst_instability_on_the_lepage_tolerance(): """Basic idea: we introduced the Lepage tolerance to solve the problem that numerically-determined or experimentally-determined twofolds do not fall at exact positions. However, when the input is exact, we expect to be able to reduce the tolerance to zero.""" def give_cases(): from cctbx import crystal from cctbx.uctbx import unit_cell from cctbx.sgtbx import space_group_info pdb =["1vjg/P 32 2 1/(56.192, 56.192, 129.318, 90, 90, 120)/16", "1vjz/P 43 21 2/(64.684, 64.684, 202.189, 90, 90, 90)/10", "1vl6/P 65/(143.963, 143.963, 163.428, 90, 90, 120)/16", "1vlc/P 3 2 1/(118.78, 118.78, 56.699, 90, 90, 120)/16", "2ash/C 1 2 1/(169.467, 99.422, 124.163, 90, 123.8, 90)/2", "2etj/P 31/(51.821, 51.821, 76.293, 90, 90, 120)/16", "2qyv/P 21 21 2/(173.922, 84.293, 123.204, 90, 90, 90)/5"] for header in pdb: tokens=header.split("/") case = {"pdb_code":tokens[0],"centring_type":tokens[1][0], "unit_cell":unit_cell(eval(tokens[2])), "expected_centrosymmetric_subgroups_of_metric":int(tokens[3])} case["symmetry"]=crystal.symmetry(space_group_info= space_group_info(tokens[1]), unit_cell=case["unit_cell"]) yield case from cctbx.sgtbx.lattice_symmetry import metric_subgroups for small_max_delta in [1.E-6, 0.0]: for case in give_cases(): G = metric_subgroups(case["symmetry"], max_delta=small_max_delta,bravais_types_only=False) assert len(G.result_groups)==case["expected_centrosymmetric_subgroups_of_metric"] return True
def run(args): command_line = (option_parser( usage="iotbx.lattice_symmetry [options] [centring_type_symbol]", description="Example: iotbx.lattice_symmetry" + " --unit_cell=12,12,12.1,89,90,92 F").enable_symmetry_comprehensive( ).option(None, "--delta", action="store", type="float", default=3., help="angular tolerance in degrees")).process(args=args, max_nargs=1) # Pick up symmetry object input_symmetry = command_line.symmetry # Check that we have what we need if (input_symmetry.unit_cell() is None): print() print("***********************************") print("Please specify unit cell parameters") print("***********************************") print() command_line.parser.show_help() return if (len(command_line.args) > 0): input_symmetry = crystal.symmetry(unit_cell=input_symmetry.unit_cell(), space_group_symbol="Hall: %s 1" % command_line.args[0]) elif (input_symmetry.space_group_info() is None): input_symmetry = crystal.symmetry(unit_cell=input_symmetry.unit_cell(), space_group_symbol="P 1") # Do it groups = metric_subgroups(input_symmetry, command_line.options.delta, enforce_max_delta_for_generated_two_folds=True) groups.show()
def run(args): command_line = (option_parser( usage="iotbx.lattice_symmetry [options] [centring_type_symbol]", description="Example: iotbx.lattice_symmetry" +" --unit_cell=12,12,12.1,89,90,92 F") .enable_symmetry_comprehensive() .option(None, "--delta", action="store", type="float", default=3., help="angular tolerance in degrees") ).process(args=args, max_nargs=1) # Pick up symmetry object input_symmetry = command_line.symmetry # Check that we have what we need if (input_symmetry.unit_cell() is None): print print "***********************************" print "Please specify unit cell parameters" print "***********************************" print command_line.parser.show_help() return if (len(command_line.args) > 0): input_symmetry = crystal.symmetry( unit_cell=input_symmetry.unit_cell(), space_group_symbol="Hall: %s 1" % command_line.args[0]) elif (input_symmetry.space_group_info() is None): input_symmetry = crystal.symmetry( unit_cell=input_symmetry.unit_cell(), space_group_symbol="P 1") # Do it groups = metric_subgroups(input_symmetry, command_line.options.delta, enforce_max_delta_for_generated_two_folds=True) groups.show()
def get_metric_symmetry_subgroups(self): subgroup_list = lattice_symmetry.metric_subgroups( self.symmetry, 3.0, bravais_types_only=False, best_monoclinic_beta=False).result_groups return subgroup_list
def test_combinations(setup_rlp): max_cell = 1.3 * max( setup_rlp["crystal_symmetry"].unit_cell().parameters()[:3]) strategy = FFT1D(max_cell) basis_vectors, used = strategy.find_basis_vectors(setup_rlp["rlp"]) target_symmetry_primitive = ( setup_rlp["crystal_symmetry"].primitive_setting().customized_copy( space_group_info=sgtbx.space_group().info())) target_symmetry_sg_only = ( setup_rlp["crystal_symmetry"].primitive_setting().customized_copy( unit_cell=None)) target_symmetry_ref = setup_rlp["crystal_symmetry"].as_reference_setting() for target_symmetry in ( setup_rlp["crystal_symmetry"], target_symmetry_primitive, target_symmetry_sg_only, target_symmetry_ref, ): crystal_models = combinations.candidate_orientation_matrices( basis_vectors, max_combinations=50) crystal_models = list(crystal_models) filtered_crystal_models = combinations.filter_known_symmetry( crystal_models, target_symmetry=target_symmetry) filtered_crystal_models = list(filtered_crystal_models) assert filtered_crystal_models for model in filtered_crystal_models: best_subgroup = find_matching_symmetry( model.get_unit_cell(), target_symmetry.space_group()) if target_symmetry.unit_cell() is not None: assert best_subgroup["best_subsym"].unit_cell().is_similar_to( setup_rlp["crystal_symmetry"].as_reference_setting(). best_cell().unit_cell(), relative_length_tolerance=0.1, absolute_angle_tolerance=5, ) or best_subgroup["best_subsym"].minimum_cell().unit_cell( ).is_similar_to( setup_rlp["crystal_symmetry"].as_reference_setting(). best_cell().minimum_cell().unit_cell(), relative_length_tolerance=0.1, absolute_angle_tolerance=5, ) else: target_sg = (target_symmetry.space_group_info(). reference_setting().group()) from cctbx.sgtbx.lattice_symmetry import metric_subgroups subgroups = metric_subgroups(model.get_crystal_symmetry(), max_delta=5, bravais_types_only=False) if not target_sg.build_derived_patterson_group() in [ g["ref_subsym"].space_group() for g in subgroups.result_groups ]: assert 0
def _setup_target_unit_cell_and_space_group(self, target_unit_cell, target_space_group): target_bravais_t = bravais_lattice( group=target_space_group.info().reference_setting().group()) best_subgroup = None best_angular_difference = 1e8 space_groups = [target_space_group] if target_space_group.conventional_centring_type_symbol() != "P": space_groups.append(sgtbx.space_group()) for target in space_groups: cs = crystal.symmetry( unit_cell=target_unit_cell, space_group=target, assert_is_compatible_unit_cell=False, ) target_best_cell = cs.best_cell().unit_cell() subgroups = lattice_symmetry.metric_subgroups(cs, max_delta=0.1) for subgroup in subgroups.result_groups: bravais_t = bravais_lattice( group=subgroup["ref_subsym"].space_group()) if bravais_t == target_bravais_t: # allow for the cell to be given as best cell, reference setting # primitive settings, or minimum cell best_subsym = subgroup["best_subsym"] ref_subsym = best_subsym.as_reference_setting() if not (best_subsym.unit_cell().is_similar_to( target_unit_cell) or ref_subsym.unit_cell( ).is_similar_to(target_unit_cell) or ref_subsym.primitive_setting().unit_cell( ).is_similar_to(target_unit_cell) or best_subsym.primitive_setting().unit_cell( ).is_similar_to(target_unit_cell) or best_subsym.minimum_cell().unit_cell( ).is_similar_to(target_unit_cell.minimum_cell()) or best_subsym.unit_cell().is_similar_to( target_best_cell)): continue if subgroup[ "max_angular_difference"] < best_angular_difference: best_subgroup = subgroup best_angular_difference = subgroup[ "max_angular_difference"] if best_subgroup is None: raise DialsIndexError("Unit cell incompatible with space group") cb_op_inp_best = best_subgroup["cb_op_inp_best"] best_subsym = best_subgroup["best_subsym"] cb_op_best_ref = best_subsym.change_of_basis_op_to_reference_setting() self.cb_op_inp_ref = cb_op_best_ref * cb_op_inp_best self.target_symmetry_reference_setting = crystal.symmetry( unit_cell=target_unit_cell.change_basis(self.cb_op_inp_ref), space_group=target_space_group.info().as_reference_setting().group( ), )
def test_score_symmetry_element_subgroup(space_group): sgi = sgtbx.space_group_info(symbol=space_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() subgroups = metric_subgroups( intensities.crystal_symmetry(), max_delta=2.0, bravais_types_only=False ) intensities = intensities.change_basis(subgroups.cb_op_inp_minimum) cs = cs.change_basis(subgroups.cb_op_inp_minimum) cb_op_inp_best = subgroups.result_groups[0]["cb_op_inp_best"] lattice_group = subgroups.result_groups[0]["best_subsym"].space_group() lattice_group = lattice_group.change_basis(cb_op_inp_best.inverse()) lattice_group = subgroups.result_groups[0]["subsym"].space_group() sym_op_scores = [] for sym_op in lattice_group.smx(): if sym_op.r().info().sense() < 0: continue score = ScoreSymmetryElement(intensities, sym_op, 1.0, 1.0) sym_op_scores.append(score) if sym_op in cs.space_group(): assert score.likelihood > 0.9 assert score.cc.coefficient() > 0.9 else: assert score.likelihood < 0.2 assert score.cc.coefficient() < 0.3 subgroup_scores = [ ScoreSubGroup(subgrp, sym_op_scores) for subgrp in subgroups.result_groups ] total_likelihood = sum(score.likelihood for score in subgroup_scores) for score in subgroup_scores: score.likelihood /= total_likelihood true_patterson_group = ( cs.space_group_info() .as_reference_setting() .group() .build_derived_patterson_group() ) for score in subgroup_scores: if score.subgroup["best_subsym"].space_group() == true_patterson_group: assert score.likelihood > 0.8 else: assert score.likelihood < 0.1
def __init__(self,input_index_engine,input_dictionary,horizon_phil, opt_rawframes=None,opt_target=False,reduce_target=True): from libtbx import adopt_init_args adopt_init_args(self,locals()) if self.horizon_phil.target_cell!=None: # change target to primitive centering type from cctbx import crystal input_symmetry = crystal.symmetry( unit_cell=self.horizon_phil.target_cell, space_group_symbol="Hall: %s 1" % self.horizon_phil.target_cell_centring_type) from cctbx.sgtbx.lattice_symmetry import metric_subgroups groups = metric_subgroups(input_symmetry, 0.0, enforce_max_delta_for_generated_two_folds=True) #groups.show() primitive_target_cell = groups.result_groups[-1]["best_subsym"].unit_cell() from rstbx.indexing_api.force_cell import force_cell best = force_cell(self.input_index_engine,primitive_target_cell) try: #print "Best score %.1f, triangle %12s"%(best["score"],str(best["triangle"])),best["orientation"].unit_cell() self.input_index_engine.setOrientation(best["orientation"]) except Exception: raise Sorry("""Cannot index with the target_cell. It is possible the target cell is wrong; try indexing without one. It may be necessary to change the beam position, distance, or two theta angle on the command line. See the http://cci.lbl.gov/labelit usage primer.""") # originally implemented with default conversion to niggli cell (reduce_target=True). # Added this as a configurable option in the context of indexing for sparse # nanocrystal stills, since we want to restrain to the originally-input target # setting, not necessarily the reduced cell: if reduce_target: self.input_index_engine.niggli() return #initial search all_sol = select_best_combo_of(input_index_engine, better_than=0.36, candidates=25, opt_inputs=(self.input_dictionary,opt_rawframes)) best_combo = all_sol.best_combo() if best_combo!=None: self.evaluate_combo(best_combo) # XXX revisit the question of codecamp maxcell and whether this test should be functional #if self.horizon_phil.codecamp.maxcell != None: return if opt_rawframes == None or best_combo['lattice_likelihood'] > 3.0: return # quick abort to test out indexing 10/16/13 raise Exception("""No autoindexing solution. Possible: incorrect beam center; multiple lattices; too few spots.""")
def __init__(self, intensities, normalisation='ml_aniso', lattice_symmetry_max_delta=2.0, d_min=libtbx.Auto, min_i_mean_over_sigma_mean=4, min_cc_half=0.6): self.intensities = intensities self.input_intensities = intensities.deep_copy() self.lattice_symmetry_max_delta = lattice_symmetry_max_delta self.cb_op_inp_min = self.intensities.change_of_basis_op_to_niggli_cell() self.intensities = self.intensities.change_basis( self.cb_op_inp_min).customized_copy( space_group_info=sgtbx.space_group_info('P1')).map_to_asu().set_info( self.intensities.info()) self.subgroups = metric_subgroups( self.intensities.crystal_symmetry(), max_delta=self.lattice_symmetry_max_delta, bravais_types_only=False) self.cb_op_min_best = self.subgroups.result_groups[0]['cb_op_inp_best'] self.lattice_group = self.subgroups.result_groups[0]['best_subsym'].space_group() self.lattice_group = self.lattice_group.change_basis(self.cb_op_min_best.inverse()) self.patterson_group = self.lattice_group.build_derived_patterson_group() sel = self.patterson_group.epsilon(self.intensities.indices()) == 1 self.intensities = self.intensities.select(sel).set_info( self.intensities.info()) if d_min is not None or d_min is libtbx.Auto: self.resolution_filter(d_min, min_i_mean_over_sigma_mean, min_cc_half) # Correct SDs by "typical" SD factors self.correct_sigmas(sd_fac=2.0, sd_b=0.0, sd_add=0.03) if normalisation == 'kernel': self.kernel_normalisation() elif normalisation == 'quasi': self.quasi_normalisation() elif normalisation == 'ml_iso': self.ml_normalisation(aniso=False) elif normalisation == 'ml_aniso': self.ml_normalisation(aniso=True) self.estimate_cc_sig_fac() self.estimate_cc_true() self.score_symmetry_elements() self.score_laue_groups() self.show()
def run(self, iterable): # with Capturing() as junk_output: errors = [] try: ucs = Cluster.from_iterable(iterable=iterable) clusters, _ = ucs.ab_cluster(5000, log=False, write_file_lists=False, schnell=True, doplot=False) except Exception as e: print("IOTA ERROR (CLUSTERING): ", e) clusters = [] errors.append(str(e)) info = [] if clusters: for cluster in clusters: uc_init = unit_cell(cluster.medians) symmetry = crystal.symmetry(unit_cell=uc_init, space_group_symbol="P1") groups = lattice_symmetry.metric_subgroups( input_symmetry=symmetry, max_delta=3) top_group = groups.result_groups[0] best_sg = str(groups.lattice_group_info()).split("(")[0] best_uc = top_group["best_subsym"].unit_cell().parameters() uc_no_stdev = ("{:<6.2f} {:<6.2f} {:<6.2f} " "{:<6.2f} {:<6.2f} {:<6.2f} " "".format( best_uc[0], best_uc[1], best_uc[2], best_uc[3], best_uc[4], best_uc[5], )) cluster_info = { "number": len(cluster.members), "pg": str(best_sg), "uc": uc_no_stdev, } info.append(cluster_info) return info, errors
def generate_lattice_options(unit_cell, space_group_name): cs = crystal.symmetry( unit_cell = unit_cell, space_group_symbol = space_group_name) original_reindex = cs.change_of_basis_op_to_minimum_cell() groups = metric_subgroups(input_symmetry = cs, max_delta = 0.0) result = [] for item in groups.result_groups: cs = item['ref_subsym'] convert_to_best_cell = True if convert_to_best_cell: cb = cs.change_of_basis_op_to_best_cell( best_monoclinic_beta = False) cs_best = cs.change_basis(cb) o_unit_cell = cs_best.unit_cell().parameters() sg = cs_best.space_group().build_derived_acentric_group() o_space_group_name = sg.type().universal_hermann_mauguin_symbol() reindex = (cb * item['subsym'].space_group_info().type().cb_op( ) * original_reindex).c().r().as_double() result.append((o_space_group_name, o_unit_cell, reindex)) else: o_unit_cell = cs.unit_cell().parameters() sg = cs.space_group().build_derived_acentric_group() o_space_group_name = sg.type().universal_hermann_mauguin_symbol() reindex = (item['subsym'].space_group_info().type().cb_op( ) * original_reindex).c().r().as_double() result.append((o_space_group_name, o_unit_cell, reindex)) return result
def run(self, iterable): with Capturing() as junk_output: try: ucs = Cluster.from_iterable(iterable=iterable) clusters, _ = ucs.ab_cluster(5000, log=False, write_file_lists=False, schnell=True, doplot=False) except Exception: clusters = [] if len(clusters) > 0: info = [] for cluster in clusters: uc_init = unit_cell(cluster.medians) symmetry = crystal.symmetry(unit_cell=uc_init, space_group_symbol='P1') groups = lattice_symmetry.metric_subgroups( input_symmetry=symmetry, max_delta=3) top_group = groups.result_groups[0] best_uc = top_group['best_subsym'].unit_cell().parameters() best_sg = top_group['best_subsym'].space_group_info() uc_no_stdev = "{:<6.2f} {:<6.2f} {:<6.2f} " \ "{:<6.2f} {:<6.2f} {:<6.2f} " \ "".format(best_uc[0], best_uc[1], best_uc[2], best_uc[3], best_uc[4], best_uc[5]) cluster_info = { 'number': len(cluster.members), 'pg': str(best_sg), 'uc': uc_no_stdev } info.append(cluster_info) else: info = None return info
def counterexamples(): for example in [ # Stated example known to be hR, Table lookup gives mC (143.11386252141878, 143.60212158695211, 191.65636462983394, 90.01331794194698, 111.85072371897915, 119.88503851099796), # Stated examples known to be oC, Table lookup gives mP # ...but applying sign correction produces oC. (121.48, 122.45, 144.06, 89.94, 65.09, 89.99), (121.39, 122.16, 143.98, 89.94, 65.24, 89.97), # Stated examples known to be hP, Table lookup gives oC # ...but applying sign correction produces hP (81.003144781582421, 81.130355147032134, 169.50959209067071, 89.896542797449115, 89.999041351249176, 60.10397864241261), (81.88, 81.92, 170.38, 89.95, 89.98, 60.04), (81.84, 81.85, 169.28, 89.94, 89.97, 60.02), (149.74, 149.89, 154.90, 89.96, 89.77, 60.10), # Stated example known to be tP, Table lookup gives oP (64.5259, 65.5211, 140.646, 90.0599, 90.0254, 90.0023), # Stated example known to be tI, Table lookup gives oI (100.66, 100.78, 101.00, 116.96, 95.54, 116.63), ]: uc = unit_cell(example) assert uc.is_niggli_cell() print "Input Niggli cell:", uc print "BZW Table lookup:" LatticeCharacter(uc, 3.0).show_summary() input_symmetry = crystal.symmetry(unit_cell=uc, space_group_symbol="P 1") Groups = metric_subgroups(input_symmetry, 3.0) Groups.show() print print
def run_once(crystal_symmetry): cs = crystal_symmetry #print cs.show_summary() from cctbx.sgtbx import lattice_symmetry subgroups = lattice_symmetry.metric_subgroups(cs, max_delta=5) for op in ('x,y,z', 'z,x,y', 'y,z,x', '-x,z,y', 'y,x,-z', 'z,-y,x')[:]: cb_op = sgtbx.change_of_basis_op(op) uc_inp = cs.unit_cell().change_basis(cb_op) for ref_uc, ref_sg in [(cs.unit_cell(), cs.space_group()), (None, cs.space_group())][:]: best_subgroup = symmetry.find_matching_symmetry( uc_inp, target_space_group=ref_sg) cb_op_inp_best = best_subgroup['cb_op_inp_best'] assert uc_inp.change_basis(cb_op_inp_best).is_similar_to( cs.as_reference_setting().best_cell().unit_cell())
def test_reindex_experiments(): # See also https://github.com/cctbx/cctbx_project/issues/424 cs = sgtbx.space_group_info("I23").any_compatible_crystal_symmetry( volume=100000) B = scitbx.matrix.sqr( cs.unit_cell().fractionalization_matrix()).transpose() cryst = Crystal(B, cs.space_group()) n_scan_points = 10 A_at_scan_points = [(1, 0, 0, 0, 1, 0, 0, 0, 1)] * n_scan_points cryst.set_A_at_scan_points(A_at_scan_points) groups = metric_subgroups(cs, max_delta=5) for group in groups.result_groups: best_subsym = group["best_subsym"] cb_op = group["cb_op_inp_best"] expts = ExperimentList([Experiment(crystal=cryst)]) reindexed_expts = reindex_experiments( experiments=expts, cb_op=cb_op, space_group=best_subsym.space_group()) assert (reindexed_expts[0].crystal.get_crystal_symmetry(). is_similar_symmetry(best_subsym)) # Check that the scan-varying A matrices have been copied as well assert cryst.num_scan_points == n_scan_points
def counterexamples(): for example in [ # Stated example known to be hR, Table lookup gives mC (143.11386252141878, 143.60212158695211, 191.65636462983394, 90.01331794194698, 111.85072371897915, 119.88503851099796), # Stated examples known to be oC, Table lookup gives mP # ...but applying sign correction produces oC. (121.48, 122.45, 144.06, 89.94, 65.09, 89.99), (121.39, 122.16, 143.98, 89.94, 65.24, 89.97), # Stated examples known to be hP, Table lookup gives oC # ...but applying sign correction produces hP (81.003144781582421, 81.130355147032134, 169.50959209067071, 89.896542797449115, 89.999041351249176, 60.10397864241261), (81.88, 81.92, 170.38, 89.95, 89.98, 60.04), (81.84, 81.85, 169.28, 89.94, 89.97, 60.02), (149.74, 149.89, 154.90, 89.96, 89.77, 60.10), # Stated example known to be tP, Table lookup gives oP (64.5259, 65.5211, 140.646, 90.0599, 90.0254, 90.0023), # Stated example known to be tI, Table lookup gives oI (100.66, 100.78, 101.00, 116.96, 95.54, 116.63), ]: uc = unit_cell(example) assert uc.is_niggli_cell() print "Input Niggli cell:",uc print "BZW Table lookup:" LatticeCharacter(uc,3.0).show_summary() input_symmetry = crystal.symmetry( unit_cell=uc,space_group_symbol="P 1") Groups = metric_subgroups(input_symmetry, 3.0) Groups.show() print;print
print "Best cell -> niggli cell" cs.best_cell().niggli_cell().show_summary() print "Reference setting -> minimum cell" cs.as_reference_setting().minimum_cell().show_summary() print "Reference setting -> niggli cell" cs.as_reference_setting().niggli_cell().show_summary() print print "Reference settings (via minimum/niggli cell):" print "Input -> minimum cell -> reference setting" cs.minimum_cell().as_reference_setting().show_summary() print "Input -> niggli cell -> reference setting" cs.niggli_cell().as_reference_setting().show_summary() print "Best cell -> minimum cell -> reference setting" cs.best_cell().minimum_cell().as_reference_setting().show_summary() print "Best cell -> niggli cell -> reference setting" cs.best_cell().niggli_cell().as_reference_setting().show_summary() print "Reference setting -> minimum cell -> reference setting" cs.as_reference_setting().minimum_cell().as_reference_setting().show_summary() print "Reference setting -> niggli cell -> reference setting" cs.as_reference_setting().niggli_cell().as_reference_setting().show_summary() print subgroups = lattice_symmetry.metric_subgroups(cs, max_delta=0.1) for subgroup in subgroups.result_groups: bravais_t = bravais_lattice( group=subgroup['ref_subsym'].space_group()) if bravais_t == 'mC': print subgroup['ref_subsym'].unit_cell() print subgroup['best_subsym'].as_reference_setting().unit_cell()
def __init__( self, intensities, normalisation="ml_aniso", lattice_symmetry_max_delta=2.0, d_min=libtbx.Auto, min_i_mean_over_sigma_mean=4, min_cc_half=0.6, relative_length_tolerance=None, absolute_angle_tolerance=None, ): """Initialise a symmetry_base object. Args: intensities (cctbx.miller.array): The intensities on which to perform symmetry anaylsis. normalisation (str): The normalisation method to use. Possible choices are 'kernel', 'quasi', 'ml_iso' and 'ml_aniso'. Set to None to switch off normalisation altogether. lattice_symmetry_max_delta (float): The maximum value of delta for determining the lattice symmetry using the algorithm of Le Page (1982). d_min (float): Optional resolution cutoff to be applied to the input intensities. If set to :data:`libtbx.Auto` then d_min will be automatically determined according to the parameters ``min_i_mean_over_sigma_mean`` and ``min_cc_half``. min_i_mean_over_sigma_mean (float): minimum value of |I|/|sigma(I)| for automatic determination of resolution cutoff. min_cc_half (float): minimum value of CC1/2 for automatic determination of resolution cutoff. relative_length_tolerance (float): Relative length tolerance in checking consistency of input unit cells against the median unit cell. absolute_angle_tolerance (float): Absolute angle tolerance in checking consistency of input unit cells against the median unit cell. """ self.input_intensities = intensities uc_params = [flex.double() for i in range(6)] for d in self.input_intensities: for i, p in enumerate(d.unit_cell().parameters()): uc_params[i].append(p) self.median_unit_cell = uctbx.unit_cell( parameters=[flex.median(p) for p in uc_params]) self._check_unit_cell_consistency(relative_length_tolerance, absolute_angle_tolerance) self.intensities = self.input_intensities[0] self.dataset_ids = flex.double(self.intensities.size(), 0) for i, d in enumerate(self.input_intensities[1:]): self.intensities = self.intensities.concatenate( d, assert_is_similar_symmetry=False) self.dataset_ids.extend(flex.double(d.size(), i + 1)) self.intensities = self.intensities.customized_copy( unit_cell=self.median_unit_cell) self.intensities.set_observation_type_xray_intensity() sys_absent_flags = self.intensities.sys_absent_flags( integral_only=True).data() self.intensities = self.intensities.select(~sys_absent_flags) self.dataset_ids = self.dataset_ids.select(~sys_absent_flags) self.lattice_symmetry_max_delta = lattice_symmetry_max_delta self.subgroups = metric_subgroups( self.intensities.crystal_symmetry(), max_delta=self.lattice_symmetry_max_delta, bravais_types_only=False, ) self.cb_op_inp_min = self.subgroups.cb_op_inp_minimum self.intensities = (self.intensities.change_basis( self.cb_op_inp_min).customized_copy( space_group_info=sgtbx.space_group_info( "P1")).map_to_asu().set_info(self.intensities.info())) self.lattice_group = (self.subgroups.result_groups[0] ["subsym"].space_group().make_tidy()) self.patterson_group = ( self.lattice_group.build_derived_patterson_group().make_tidy()) logger.info("Patterson group: %s" % self.patterson_group.info()) sel = self.patterson_group.epsilon(self.intensities.indices()) == 1 self.intensities = self.intensities.select(sel) self.dataset_ids = self.dataset_ids.select(sel) # Correct SDs by "typical" SD factors self._correct_sigmas(sd_fac=2.0, sd_b=0.0, sd_add=0.03) self._normalise(normalisation) self._resolution_filter(d_min, min_i_mean_over_sigma_mean, min_cc_half)
def change_of_basis_ops_to_minimum_cell(experiments, max_delta, relative_length_tolerance, absolute_angle_tolerance): """ Compute change of basis ops to map experiments to the minimum cell Map to the minimum cell via the best cell, which appears to guarantee that the resulting minimum cells are consistent. Args: experiments (ExperimentList): a list of experiments. reflections (list): a list of reflection tables Returns: The experiments and reflections mapped to the minimum cell """ median_cell = median_unit_cell(experiments) unit_cells_are_similar = unit_cells_are_similar_to( experiments, median_cell, relative_length_tolerance, absolute_angle_tolerance) centring_symbols = [ bravais_lattice(group=expt.crystal.get_space_group()).centring_symbol for expt in experiments ] if unit_cells_are_similar and len(set(centring_symbols)) == 1: groups = metric_subgroups( experiments[0].crystal.get_crystal_symmetry().customized_copy( unit_cell=median_cell), max_delta, enforce_max_delta_for_generated_two_folds=True, ) group = groups.result_groups[0] cb_op_best_to_min = group[ "best_subsym"].change_of_basis_op_to_minimum_cell() cb_ops = [cb_op_best_to_min * group["cb_op_inp_best"] ] * len(experiments) else: groups = [ metric_subgroups( expt.crystal.get_crystal_symmetry(), max_delta, best_monoclinic_beta=False, enforce_max_delta_for_generated_two_folds=True, ) for expt in experiments ] counter = collections.Counter( g.result_groups[0]["best_subsym"].space_group() for g in groups) target_group = counter.most_common()[0][0] cb_ops = [] for expt in experiments: groups = metric_subgroups( expt.crystal.get_crystal_symmetry(), max_delta, best_monoclinic_beta=False, enforce_max_delta_for_generated_two_folds=True, ) group = None for g in groups.result_groups: if g["best_subsym"].space_group() == target_group: group = g if group: cb_ops.append(group["cb_op_inp_best"]) else: cb_ops.append(None) logger.info(f"Couldn't match unit cell to target symmetry:\n" f"{expt.crystal.get_crystal_symmetry()}\n" f"{target_group}") ref_expts = ExperimentList([ expt for expt, cb_op in zip(experiments, cb_ops) if cb_op ]).change_basis(list(filter(None, cb_ops))) cb_op_ref_min = ( ref_expts[0].crystal.get_crystal_symmetry().customized_copy( unit_cell=median_unit_cell( ref_expts)).change_of_basis_op_to_minimum_cell()) cb_ops = [cb_op_ref_min * cb_op if cb_op else None for cb_op in cb_ops] return cb_ops
def unit_cell_info(sub_clusters): """ Print unit cell information for a list of clusters. :param sub_clusters: a list of cluster objects :return: a string containing median unit cells, standard deviations and point group composition of each cluster. """ from libtbx.utils import plural_s # 3. print out some information that is useful. out_str = "\n\n{:<16} {:<8} {:<13} {:<13} {:<13} {:<12} {:<12} {:<12}{:<8}\n".format( "Cluster_id", "N_xtals", "Med_a", "Med_b", "Med_c", "Med_alpha", "Med_beta", "Med_gamma", "Delta(deg)") singletons = [] for cluster in sub_clusters: if len(cluster.members) != 1: # New approach, takes niggli setting of the cluster median and converts # back to reference setting for cluster report. Fixes cctbx#97. from cctbx import crystal from cctbx.uctbx import unit_cell from cctbx.sgtbx.lattice_symmetry import metric_subgroups input_symmetry = crystal.symmetry(unit_cell=unit_cell( cluster.medians[0:6]), space_group_symbol="P 1") groups = metric_subgroups( input_symmetry, 3.00, enforce_max_delta_for_generated_two_folds=True) group = groups.result_groups[0] # suppress stdout output for now from StringIO import StringIO SS = StringIO() import sys sys.stdout = SS group['best_subsym'].space_group_info().show_summary() sys.stdout = sys.__stdout__ print " Unit cell:", group[ 'best_subsym'].unit_cell() uc_params_conv = group['best_subsym'].unit_cell().parameters() sorted_pg_comp = sorted(cluster.pg_composition.items(), key=lambda x: -1 * x[1]) pg_strings = [ "{} in {}".format(pg[1], pg[0]) for pg in sorted_pg_comp ] point_group_string = ", ".join(pg_strings) + "." out_str += point_group_string out_str += ("\n{:<16} {:<8} {:<6.2f}({:<5.2f}) {:<6.2f}({:<5.2f})" " {:<6.2f}({:<5.2f}) {:<6.2f}({:<4.2f}) {:<6.2f}" "({:<4.2f}) {:<6.2f}({:<4.2f})").format( cluster.cname, len(cluster.members), cluster.medians[0], cluster.stdevs[0], cluster.medians[1], cluster.stdevs[1], cluster.medians[2], cluster.stdevs[2], cluster.medians[3], cluster.stdevs[3], cluster.medians[4], cluster.stdevs[4], cluster.medians[5], cluster.stdevs[5]) out_str += ("\n{:>24} {:<6.2f}{:<7} {:<6.2f}{:<7}" " {:<6.2f}{:<7} {:<6.2f}{:<6} {:<6.2f}" "{:<6} {:<6.2f}{:<6} {:<6.2}").format( SS.getvalue().strip()[13:], uc_params_conv[0], "", uc_params_conv[1], "", uc_params_conv[2], "", uc_params_conv[3], "", uc_params_conv[4], "", uc_params_conv[5], "", group["max_angular_difference"]) + "\n\n" else: singletons.append("".join([ ("{:<14} {:<11.2f} {:<11.2f} {:<11.2f}" "{:<12.1f} {:<12.1f} {:<12.1f}").format( cluster.pg_composition.keys()[0], cluster.members[0].uc[0], cluster.members[0].uc[1], cluster.members[0].uc[2], cluster.members[0].uc[3], cluster.members[0].uc[4], cluster.members[0].uc[5]), '\n' ])) out_str += "\nStandard deviations are in brackets." explanation = """\nEach cluster: Input lattice count, with integration Bravais setting space group. Cluster median with Niggli cell parameters (std dev in brackets). Highest possible metric symmetry and unit cell using LePage (J Appl Cryst 1982, 15:255) method, maximum delta 3deg.""" out_str += explanation singleton_str = "\n%i singleton%s:" % plural_s(len(singletons)) singleton_str += "\n\n{:<14} {:<11} {:<11} {:<11}{:<12} {:<12} {:<12}\n".format( "Point group", "a", "b", "c", "alpha", "beta", "gamma") singleton_str += "".join(singletons) n_clusters = len(sub_clusters) - len(singletons) out_str = "\n%i cluster%s:" % plural_s(n_clusters) + out_str return singleton_str + out_str
class TrackerWindow(wx.Frame): def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, size=(1500, 600)) self.parent = parent self.term_file = os.path.join(os.curdir, '.terminate_image_tracker') self.spf_backend = 'mosflm' self.run_indexing = False self.run_integration = False self.reset_spotfinder() # Status bar self.sb = self.CreateStatusBar() self.sb.SetFieldsCount(2) self.sb.SetStatusWidths([100, -1]) # Setup main sizer self.main_sizer = wx.BoxSizer(wx.VERTICAL) # Setup toolbar self.toolbar = self.CreateToolBar(style=wx.TB_3DBUTTONS | wx.TB_TEXT) quit_bmp = bitmaps.fetch_icon_bitmap('actions', 'exit') self.tb_btn_quit = self.toolbar.AddLabelTool(wx.ID_EXIT, label='Quit', bitmap=quit_bmp, shortHelp='Quit', longHelp='Quit image tracker') self.toolbar.AddSeparator() # pref_bmp = bitmaps.fetch_icon_bitmap('apps', 'advancedsettings') # self.tb_btn_prefs = self.toolbar.AddLabelTool(wx.ID_ANY, # label='Preferences', # bitmap=pref_bmp, # shortHelp='Preferences', # longHelp='IOTA image tracker preferences') # self.toolbar.AddSeparator() open_bmp = bitmaps.fetch_icon_bitmap('actions', 'open') self.tb_btn_open = self.toolbar.AddLabelTool(wx.ID_ANY, label='Open', bitmap=open_bmp, shortHelp='Open', longHelp='Open folder') run_bmp = bitmaps.fetch_icon_bitmap('actions', 'run') self.tb_btn_run = self.toolbar.AddLabelTool(wx.ID_ANY, label='Run', bitmap=run_bmp, shortHelp='Run', longHelp='Run Spotfinding') stop_bmp = bitmaps.fetch_icon_bitmap('actions', 'stop') self.tb_btn_stop = self.toolbar.AddLabelTool(wx.ID_ANY, label='Stop', bitmap=stop_bmp, shortHelp='Stop', longHelp='Stop Spotfinding') self.toolbar.AddSeparator() span_view = bitmaps.fetch_custom_icon_bitmap('zoom_list') self.tb_btn_view = self.toolbar.AddLabelTool(wx.ID_ANY, label='View', bitmap=span_view, kind=wx.ITEM_RADIO, shortHelp='Select to View', longHelp='Select images to view') span_zoom = bitmaps.fetch_custom_icon_bitmap('zoom_view') self.tb_btn_zoom = self.toolbar.AddLabelTool(wx.ID_ANY, label='Zoom In', bitmap=span_zoom, kind=wx.ITEM_RADIO, shortHelp='Zoom In', longHelp='Zoom in on chart') self.toolbar.ToggleTool(self.tb_btn_zoom.GetId(), True) self.toolbar.EnableTool(self.tb_btn_run.GetId(), False) self.toolbar.EnableTool(self.tb_btn_stop.GetId(), False) self.toolbar.Realize() # Setup timers self.spf_timer = wx.Timer(self) self.uc_timer = wx.Timer(self) self.ff_timer = wx.Timer(self) self.tracker_panel = TrackerPanel(self) self.data_dict = self.tracker_panel.image_list.image_list.ctr.data.copy() self.img_list_initialized = False self.main_sizer.Add(self.tracker_panel, 1, wx.EXPAND) # Bindings self.Bind(wx.EVT_TOOL, self.onQuit, self.tb_btn_quit) self.Bind(wx.EVT_TOOL, self.onGetImages, self.tb_btn_open) self.Bind(wx.EVT_TOOL, self.onRunSpotfinding, self.tb_btn_run) self.Bind(wx.EVT_TOOL, self.onStop, self.tb_btn_stop) self.Bind(wx.EVT_BUTTON, self.onSelView, self.tracker_panel.btn_view_sel) self.Bind(wx.EVT_BUTTON, self.onWrtFile, self.tracker_panel.btn_wrt_file) self.Bind(wx.EVT_BUTTON, self.onAllView, self.tracker_panel.btn_view_all) self.Bind(wx.EVT_TOOL, self.onZoom, self.tb_btn_zoom) self.Bind(wx.EVT_TOOL, self.onList, self.tb_btn_view) # Spotfinder / timer bindings self.Bind(thr.EVT_SPFDONE, self.onSpfOneDone) self.Bind(thr.EVT_SPFALLDONE, self.onSpfAllDone) self.Bind(thr.EVT_SPFTERM, self.onSpfTerminated) self.Bind(wx.EVT_TIMER, self.onSpfTimer, id=self.spf_timer.GetId()) self.Bind(wx.EVT_TIMER, self.onUCTimer, id=self.uc_timer.GetId()) self.Bind(wx.EVT_TIMER, self.onPlotOnlyTimer, id=self.ff_timer.GetId()) # Settings bindings self.Bind(wx.EVT_SPINCTRL, self.onMinBragg, self.tracker_panel.min_bragg.ctr) self.Bind(wx.EVT_SPINCTRL, self.onChartRange, self.tracker_panel.chart_window.ctr) self.Bind(wx.EVT_CHECKBOX, self.onChartRange, self.tracker_panel.chart_window.toggle) # Read arguments if any self.args, self.phil_args = parse_command_args('').parse_known_args() # Generate DIALS PHIL file if self.args.paramfile is None: default_phil = ip.parse(default_target) self.phil = phil_scope.fetch(source=default_phil) else: with open(self.args.paramfile, 'r') as phil_file: phil_string = phil_file.read() user_phil = ip.parse(phil_string) self.phil = phil_scope.fetch(source=user_phil) self.params = self.phil.extract() # Set backend self.spf_backend = self.args.backend # Determine how far the DIALS processing will go if 'index' in self.args.action: self.run_indexing = True elif 'int' in self.args.action: self.run_indexing = True self.run_integration = True self.tracker_panel.min_bragg.ctr.SetValue(self.args.bragg) # Determine how the tracker will track images: from file output by # iota.single_image, or by turning over actual files. If the latter, # determine at what point the tracker will start the tracking if self.args.file is not None: self.results_file = self.args.file self.start_spotfinding(from_file=True) elif self.args.path is not None: path = os.path.abspath(self.args.path) self.open_images_and_get_ready(path=path) if self.args.start: print 'IMAGE_TRACKER: STARTING FROM FIRST RECORDED IMAGE' self.start_spotfinding() elif self.args.proceed: print 'IMAGE_TRACKER: STARTING FROM IMAGE RECORDED 1 MIN AGO' self.start_spotfinding(min_back=-1) elif self.args.time > 0: min_back = -self.args.time[0] print 'IMAGE_TRACKER: STARTING FROM IMAGE RECORDED {} MIN AGO' \ ''.format(min_back) self.start_spotfinding(min_back=min_back) def onZoom(self, e): if self.tb_btn_zoom.IsToggled(): self.toolbar.ToggleTool(self.tb_btn_view.GetId(), False) def onList(self, e): if self.tb_btn_view.IsToggled(): self.toolbar.ToggleTool(self.tb_btn_zoom.GetId(), False) def reset_spotfinder(self): self.done_list = [] self.data_list = [] self.spotfinding_info = [] self.plot_idx = 0 self.bookmark = 0 self.all_info = [] self.current_min_bragg = 0 self.waiting = False self.submit_new_images = False self.terminated = False def onWrtFile(self, e): idxs = [] listctrl = self.tracker_panel.image_list.image_list.ctr if listctrl.GetSelectedItemCount() == 0: for index in range(listctrl.GetItemCount()): idxs.append(index) else: index = listctrl.GetFirstSelected() idxs.append(index) while len(idxs) != listctrl.GetSelectedItemCount(): index = listctrl.GetNextSelected(index) idxs.append(index) self.write_images_to_file(idxs=idxs) def onSelView(self, e): idxs = [] listctrl = self.tracker_panel.image_list.image_list.ctr if listctrl.GetSelectedItemCount() == 0: return index = listctrl.GetFirstSelected() idxs.append(index) while len(idxs) != listctrl.GetSelectedItemCount(): index = listctrl.GetNextSelected(index) idxs.append(index) self.view_images(idxs=idxs) def onAllView(self, e): listctrl = self.tracker_panel.image_list.image_list.ctr idxs = range(listctrl.GetItemCount()) self.view_images(idxs=idxs) def write_images_to_file(self, idxs): # Determine param filepath save_dlg = wx.FileDialog(self, message="Save Image Paths to File", defaultDir=os.curdir, defaultFile="*.lst", wildcard="*", style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT ) if save_dlg.ShowModal() == wx.ID_OK: script_filepath = save_dlg.GetPath() file_list = [self.data_dict[idx][1] for idx in idxs] with open(script_filepath, 'w') as img_file: file_list_string = '\n'.join(file_list) img_file.write(file_list_string) def view_images(self, idxs): file_list = [self.data_dict[idx][1] for idx in idxs] file_string = ' '.join(file_list) viewer = thr.ImageViewerThread(self, file_string=file_string) viewer.start() def onStop(self, e): self.terminated = True self.toolbar.EnableTool(self.tb_btn_run.GetId(), False) self.toolbar.EnableTool(self.tb_btn_stop.GetId(), False) with open(self.term_file, 'w') as tf: tf.write('') self.msg = 'Stopping...' def remove_term_file(self): try: os.remove(self.term_file) except Exception: pass def onGetImages(self, e): ''' Select folder to watch for incoming images ''' open_dlg = wx.DirDialog(self, "Choose the data folder:", style=wx.DD_DEFAULT_STYLE) if open_dlg.ShowModal() == wx.ID_OK: self.data_folder = open_dlg.GetPath() open_dlg.Destroy() self.open_images_and_get_ready() else: open_dlg.Destroy() return def open_images_and_get_ready(self, path=None): if path is not None: self.data_folder = path self.remove_term_file() self.reset_spotfinder() self.tracker_panel.chart.reset_chart() self.toolbar.EnableTool(self.tb_btn_run.GetId(), True) timer_txt = '[ ------ ]' self.msg = 'Ready to track images in {}'.format(self.data_folder) self.sb.SetStatusText('{} {}'.format(timer_txt, self.msg), 1) def onMinBragg(self, e): self.tracker_panel.chart.draw_bragg_line() def onChartRange(self, e): if self.tracker_panel.chart_window.toggle.GetValue(): chart_range = self.tracker_panel.chart_window.ctr.GetValue() self.tracker_panel.chart.plot_zoom = True self.tracker_panel.chart.chart_range = chart_range self.tracker_panel.chart.max_lock = True else: self.tracker_panel.chart.plot_zoom = False self.tracker_panel.chart.draw_plot() def onSpfOptions(self, e): spf_dlg = DIALSSpfDialog(self, phil=self.phil, title='DIALS Spotfinding Options') if (spf_dlg.ShowModal() == wx.ID_OK): self.phil = self.phil.fetch(source=spf_dlg.spf_phil) spf_dlg.Destroy() def onRunSpotfinding(self, e): self.start_spotfinding() def start_spotfinding(self, min_back=None, from_file=False): ''' Start timer and perform spotfinding on found images ''' self.terminated = False self.tracker_panel.chart.draw_bragg_line() self.tracker_panel.chart.select_span.set_active(True) self.tracker_panel.chart.zoom_span.set_active(True) self.toolbar.EnableTool(self.tb_btn_stop.GetId(), True) self.toolbar.EnableTool(self.tb_btn_run.GetId(), False) self.toolbar.EnableTool(self.tb_btn_open.GetId(), False) self.params = self.phil.extract() self.spin_update = 0 if self.args.file is not None: self.sb.SetStatusText('{}'.format('FILE'), 0) else: self.sb.SetStatusText('{}'.format(self.spf_backend.upper()), 0) if from_file: self.ff_timer.Start(1000) self.uc_timer.Start(15000) else: self.submit_new_images = True self.spf_timer.Start(1000) self.uc_timer.Start(15000) def stop_run(self): timer_txt = '[ xxxxxx ]' self.msg = 'STOPPED SPOTFINDING!' self.sb.SetStatusText('{} {}'.format(timer_txt, self.msg), 1) if self.spf_timer.IsRunning(): self.spf_timer.Stop() if self.ff_timer.IsRunning(): self.ff_timer.Stop() if self.uc_timer.IsRunning(): self.uc_timer.Stop() def run_spotfinding(self, submit_list=None): ''' Generate the spot-finder thread and run it ''' if submit_list is not None and len(submit_list) > 0: self.spf_thread = thr.SpotFinderThread(self, data_list=submit_list, term_file=self.term_file, proc_params=self.params, backend=self.spf_backend, n_proc=self.args.nproc, run_indexing=self.run_indexing, run_integration=self.run_integration) self.spf_thread.start() def onSpfOneDone(self, e): ''' Occurs on every wx.PostEvent instance; updates lists of images with spotfinding results ''' if not self.terminated: info = e.GetValue() if info is not None: idx = int(info[0]) + len(self.done_list) obs_count = info[1] img_path = info[2] self.spotfinding_info.append([idx, obs_count, img_path, info[3], info[4]]) self.all_info.append([idx, obs_count, img_path]) def onSpfAllDone(self, e): self.done_list.extend(e.GetValue()) self.submit_new_images = True def onSpfTerminated(self, e): self.stop_run() self.toolbar.EnableTool(self.tb_btn_open.GetId(), True) def find_new_images(self, min_back=None, last_file=None): found_files = ginp.make_input_list([self.data_folder], filter=True, filter_type='image', last=last_file, min_back=min_back) # Sometimes duplicate files are found anyway; clean that up found_files = list(set(found_files) - set(self.data_list)) # Add new files to the data list & clean up self.data_list.extend(found_files) self.data_list = sorted(self.data_list, key=lambda i:i) if self.waiting: if len(found_files) > 0: self.waiting = False self.msg = 'Tracking new images in {} ...'.format(self.data_folder) self.start_spotfinding() else: if len(found_files) == 0: self.msg = 'Waiting for new images in {} ...'.format(self.data_folder) self.waiting = True def update_spinner(self): ''' Update spotfinding chart ''' if self.spin_update == 4: self.spin_update = 0 else: self.spin_update += 1 tick = ['-o-----', '--o----', '---o---', '----o--', '-----o-'] timer_txt = '[ {0} ]'.format(tick[self.spin_update]) self.sb.SetStatusText('{} {}'.format(timer_txt, self.msg), 1) def onPlotOnlyTimer(self, e): if self.terminated: self.stop_run() else: if self.results_file is not None and os.path.isfile(self.results_file): st = time.time() with open(self.results_file, 'r') as rf: rf.seek(self.bookmark) split_info = [i.replace('\n','').split(' ') for i in rf.readlines()] self.bookmark = rf.tell() if self.args.reorder: idx_offset = len(self.spotfinding_info) new_info = [ [split_info.index(i) + idx_offset, int(i[1]), i[2], i[3], tuple(i[4:10])] if len(i) > 5 else [split_info.index(i) + idx_offset, int(i[1]), i[2], misc.makenone(i[3]), misc.makenone(i[4])] for i in split_info] else: new_info = [ [int(i[0]), int(i[1]), i[2], i[3], tuple(i[4:10])] if len(i) > 5 else [int(i[0]), int(i[1]), i[2], misc.makenone(i[3]), misc.makenone(i[4])] for i in split_info] if len(new_info) > 0: self.msg = 'Tracking new images in {} ...'.format(self.results_file) self.spotfinding_info.extend(new_info) if len(self.spotfinding_info) > 0: indexed = [i for i in self.spotfinding_info if i[4] is not None] self.tracker_panel.idx_count_txt.SetLabel(str(len(indexed))) self.plot_results() else: self.msg = 'Waiting for new images in {} ...'.format(self.results_file) else: self.msg = 'Waiting for new run to initiate...' self.update_spinner() def onSpfTimer(self, e): self.update_spinner() if not self.terminated: if len(self.spotfinding_info) > 0: indexed = [i for i in self.spotfinding_info if i[3] is not None] self.tracker_panel.idx_count_txt.SetLabel(str(len(indexed))) self.plot_results() if self.data_list != []: last_file = self.data_list[-1] else: last_file = None self.find_new_images(last_file=last_file) if self.submit_new_images: unproc_images = list(set(self.data_list) - set(self.done_list)) unproc_images = sorted(unproc_images, key=lambda i:i) if len(unproc_images) > 0: self.submit_new_images = False self.run_spotfinding(submit_list=unproc_images) else: self.stop_run() def update_image_list(self): listctrl = self.tracker_panel.image_list.image_list.ctr if self.tracker_panel.chart.bracket_set: try: first_img = self.tracker_panel.chart.patch_x last_img = self.tracker_panel.chart.patch_x_last new_data_dict = {} sel_img_list = self.spotfinding_info[first_img:last_img] for img in sel_img_list: idx = sel_img_list.index(img) if img[3] is not None: idxd = 'X' else: idxd = '' new_data_dict[idx] = (img[0], img[2], img[1], idxd) self.data_dict = new_data_dict listctrl.InitializeDataMap(self.data_dict) self.tracker_panel.btn_view_all.Enable() self.tracker_panel.btn_wrt_file.Enable() except TypeError: pass else: self.data_dict = {} self.tracker_panel.btn_view_all.Disable() self.tracker_panel.btn_view_sel.Disable() listctrl.InitializeDataMap(self.data_dict) def plot_results(self): if self.plot_idx <= len(self.spotfinding_info): new_frames = [i[0] for i in self.spotfinding_info[self.plot_idx:]] new_counts = [i[1] for i in self.spotfinding_info[self.plot_idx:]] idx_counts = [i[1] if i[3] is not None else np.nan for i in self.spotfinding_info[self.plot_idx:]] # Try finding where data comes from a new folder new_paths = [] for info in self.spotfinding_info[self.plot_idx:]: cur_dir = os.path.dirname(info[2]) cur_idx = self.spotfinding_info.index(info) if cur_idx > 0: prev_idx = cur_idx - 1 prev_dir = os.path.dirname(self.spotfinding_info[prev_idx][2]) if cur_dir != prev_dir: new_paths.append((info[0], cur_dir)) else: new_paths.append((info[0], cur_dir)) self.tracker_panel.chart.draw_plot(new_x=new_frames, new_y=new_counts, new_i=idx_counts, new_p=new_paths) self.plot_idx = self.spotfinding_info.index(self.spotfinding_info[-1]) + 1 def onUCTimer(self, e): self.cluster_unit_cells() def cluster_unit_cells(self): input = [] for item in self.spotfinding_info: if item[4] is not None: try: if type(item[4]) in (tuple, list): uc = item[4] else: uc = item[4].rsplit() info_line = [float(i) for i in uc] info_line.append(item[3]) input.append(info_line) except ValueError: pass with misc.Capturing() as junk_output: try: ucs = Cluster.from_iterable(iterable=input) clusters, _ = ucs.ab_cluster(5000, log=False, write_file_lists=False, schnell=True, doplot=False) except Exception, e: print e clusters = [] if len(clusters) > 0: uc_summary = [] for cluster in clusters: sorted_pg_comp = sorted(cluster.pg_composition.items(), key=lambda x: -1 * x[1]) pg_nums = [pg[1] for pg in sorted_pg_comp] cons_pg = sorted_pg_comp[np.argmax(pg_nums)] uc_info = [len(cluster.members), cons_pg[0], cluster.medians, cluster.stdevs] uc_summary.append(uc_info) # select the most prevalent unit cell (most members in cluster) uc_freqs = [i[0] for i in uc_summary] uc_pick = uc_summary[np.argmax(uc_freqs)] cons_uc = uc_pick[2] # Here will determine the best symmetry for the given unit cell (better # than previous method of picking the "consensus" point group from list) uc_init = unit_cell(cons_uc) symmetry = crystal.symmetry(unit_cell=uc_init, space_group_symbol='P1') groups = lattice_symmetry.metric_subgroups(input_symmetry=symmetry, max_delta=3) top_group = groups.result_groups[0] best_uc = top_group['best_subsym'].unit_cell().parameters() best_sg = top_group['best_subsym'].space_group_info() uchr = misc.UnicodeCharacters() uc_line = "a = {:<6.2f}, b = {:<6.2f}, c ={:<6.2f}, " \ "{} = {:<6.2f}, {} = {:<6.2f}, {} = {:<6.2f}" \ "".format(best_uc[0], best_uc[1], best_uc[2], uchr.alpha, best_uc[3], uchr.beta, best_uc[4], uchr.gamma, best_uc[5]) sg_line = str(best_sg) self.tracker_panel.pg_txt.SetLabel(sg_line) self.tracker_panel.uc_txt.SetLabel(uc_line) self.tracker_panel.chart.draw_plot()
( 4.807294085194974, 12.822386757910516, 16.560411742466663, 106.43185845358086, 90.02067929544215, 100.79522302759383, ), ] sgs_1 = ["P1"] * 4 print("Test case 1:") for uc, sg in zip(ucs_1, sgs_1): cs = crystal.symmetry(unit_cell=uc, space_group_symbol=sg) groups = metric_subgroups(cs, max_delta=5, enforce_max_delta_for_generated_two_folds=True) group = groups.result_groups[0] print(cs) print("Minimum cell:", cs.minimum_cell().unit_cell()) print("Best cell:", group["best_subsym"].unit_cell()) print("Minimum cell (via best):", group["best_subsym"].minimum_cell().unit_cell()) print() ucs_2 = [ (39.7413, 183.767, 140.649, 90, 90, 90), (40.16, 142.899, 92.4167, 90, 102.48, 90), (180.613, 40.1558, 142.737, 90, 90.0174, 90), ] sgs_2 = ["C 2 2 21", "P 1 2 1", "C 1 2 1"]
cs.best_cell().minimum_cell().show_summary() print("Best cell -> niggli cell") cs.best_cell().niggli_cell().show_summary() print("Reference setting -> minimum cell") cs.as_reference_setting().minimum_cell().show_summary() print("Reference setting -> niggli cell") cs.as_reference_setting().niggli_cell().show_summary() print() print("Reference settings (via minimum/niggli cell):") print("Input -> minimum cell -> reference setting") cs.minimum_cell().as_reference_setting().show_summary() print("Input -> niggli cell -> reference setting") cs.niggli_cell().as_reference_setting().show_summary() print("Best cell -> minimum cell -> reference setting") cs.best_cell().minimum_cell().as_reference_setting().show_summary() print("Best cell -> niggli cell -> reference setting") cs.best_cell().niggli_cell().as_reference_setting().show_summary() print("Reference setting -> minimum cell -> reference setting") cs.as_reference_setting().minimum_cell().as_reference_setting().show_summary() print("Reference setting -> niggli cell -> reference setting") cs.as_reference_setting().niggli_cell().as_reference_setting().show_summary() print() subgroups = lattice_symmetry.metric_subgroups(cs, max_delta=0.1) for subgroup in subgroups.result_groups: bravais_t = bravais_lattice(group=subgroup["ref_subsym"].space_group()) if bravais_t == "mC": print(subgroup["ref_subsym"].unit_cell()) print(subgroup["best_subsym"].as_reference_setting().unit_cell())
def test_symmetry_analysis(): coords = flex.double([ [0.835, 0.158], [0.772, 0.104], [0.108, 0.907], [0.058, 0.76], [0.926, 0.189], [0.221, 0.888], [0.957, 0.137], [0.958, 0.143], [-0.015, 0.726], [-0.066, 0.29], [0.135, 0.848], [0.085, 0.788], [0.897, 0.126], [0.749, 0.073], [0.166, 0.943], [0.871, 0.248], [0.116, 0.968], [0.116, 0.973], [0.706, 0.007], [0.288, -0.055], [0.137, 0.848], [0.089, 0.78], [0.893, 0.122], [0.749, 0.077], [0.165, 0.941], [0.877, 0.242], [0.114, 0.968], [0.12, 0.971], [0.716, 0.002], [0.292, -0.062], [0.841, 0.162], [0.774, 0.104], [0.1, 0.909], [0.054, 0.761], [0.927, 0.184], [0.227, 0.88], [0.957, 0.137], [0.961, 0.143], [-0.007, 0.716], [-0.061, 0.287], [0.13, 0.848], [0.084, 0.783], [0.898, 0.124], [0.749, 0.075], [0.169, 0.94], [0.871, 0.247], [0.114, 0.969], [0.12, 0.969], [0.717, 0.0], [0.296, -0.066], [0.84, 0.154], [0.776, 0.103], [0.104, 0.908], [0.057, 0.755], [0.925, 0.19], [0.227, 0.883], [0.958, 0.136], [0.962, 0.143], [-0.017, 0.724], [-0.067, 0.295], ]) sym_ops = [ sgtbx.rt_mx(s) for s in ("-z,-y,-x", "y,z,x", "x,y,z", "-x,-z,-y", "z,x,y", "-y,-x,-z") ] crystal_symmetry = crystal.symmetry( unit_cell=uctbx.unit_cell((98.33, 98.33, 135.99, 90, 90, 120)), space_group_info=sgtbx.space_group_info("R3:H"), ).minimum_cell() from cctbx.sgtbx.lattice_symmetry import metric_subgroups subgroups = metric_subgroups(crystal_symmetry, max_delta=5, bravais_types_only=False) cb_op_inp_min = sgtbx.change_of_basis_op() from dials.algorithms.symmetry.cosym import SymmetryAnalysis analysis = SymmetryAnalysis(coords, sym_ops, subgroups, cb_op_inp_min) assert analysis.best_solution.likelihood > 0.99 assert analysis.best_solution.confidence > 0.98 assert (analysis.best_solution.subgroup["best_subsym"].space_group().type( ).number() == 148) # R -3 :H assert (str(analysis) == """\ Scoring individual symmetry elements ---------------------------------------------- likelihood Z-CC CC Operator ---------------------------------------------- 0.087 1.96 0.20 2 |(0, -1, 1) 0.087 1.96 0.20 2 |(-1, 0, 1) 0.949 10.00 1.00 *** 3^-1 |(1, 1, 1) 0.087 1.96 0.20 2 |(-1, 1, 0) 0.949 10.00 1.00 *** 3 |(1, 1, 1) ---------------------------------------------- Scoring all possible sub-groups -------------------------------------------------------------------------------- Patterson group Likelihood NetZcc Zcc+ Zcc- delta Reindex operator -------------------------------------------------------------------------------- R -3 :H *** 0.995 8.04 10.00 1.96 0.0 b-c,-a+c,a+b+c P -1 0.003 -6.50 0.00 6.50 0.0 a,b,c R -3 m :H 0.001 6.50 6.50 0.00 0.0 b-c,-a+c,a+b+c C 1 2/m 1 0.000 -5.24 1.96 7.21 0.0 -a-b,a-b,c C 1 2/m 1 0.000 -5.24 1.96 7.21 0.0 -b-c,b-c,a C 1 2/m 1 0.000 -5.24 1.96 7.21 0.0 -a-c,-a+c,b -------------------------------------------------------------------------------- Best solution: R -3 :H Unit cell: (98.33, 98.33, 135.99, 90, 90, 120) Reindex operator: b-c,-a+c,a+b+c Laue group probability: 0.995 Laue group confidence: 0.994""") d = analysis.as_dict() assert d["sym_op_scores"][0] == { "cc": pytest.approx(0.19620531091685714), "operator": "-x,-z,-y", "likelihood": pytest.approx(0.08665625555575088), "stars": "", "z_cc": pytest.approx(1.9620531091685713), } assert d["subgroup_scores"][0] == { "confidence": pytest.approx(0.9940687431995551), "z_cc_for": pytest.approx(9.999725360190128), "stars": "***", "patterson_group": "-R 3", "max_angular_difference": 0.0, "likelihood": pytest.approx(0.995493024305035), "cb_op": "-1/3*x+2/3*y-1/3*z,-2/3*x+1/3*y+1/3*z,1/3*x+1/3*y+1/3*z", "z_cc_against": pytest.approx(1.9620621986200772), "unit_cell": pytest.approx(( 98.32999999999998, 98.32999999999998, 135.99, 90.0, 90.0, 119.99999999999999, )), "z_cc_net": pytest.approx(8.037663161570052), }
def get_metric_symmetry_subgroups(self): subgroup_list = lattice_symmetry.metric_subgroups( self.symmetry,3.0,bravais_types_only=False, best_monoclinic_beta=False).result_groups return subgroup_list
def unit_cell_analysis(self): """ Calls unit cell analysis module, which uses hierarchical clustering (Zeldin, et al, Acta D, 2015) to split integration results according to detected morphological groupings (if any). Most useful with preliminary integration without target unit cell specified. """ # Will not run clustering if only one integration result found or if turned off if not self.info.categories['integrated']: util.main_log(self.info.logfile, "\n\n{:-^80}\n".format(' UNIT CELL ANALYSIS '), True) util.main_log(self.info.logfile, '\n UNIT CELL CANNOT BE DETERMINED!', True) elif len(self.info.categories['integrated']) == 1: unit_cell = (self.info.cluster_iterable[0][:5]) point_group = self.info.cluster_iterable[0][6] util.main_log(self.info.logfile, "\n\n{:-^80}\n".format(' UNIT CELL ANALYSIS '), True) uc_line = "{:<6} {:^4}: {:<6.2f}, {:<6.2f}, {:<6.2f}, {:<6.2f}, " \ "{:<6.2f}, {:<6.2f}".format('(1)', point_group, unit_cell[0], unit_cell[1], unit_cell[2], unit_cell[3], unit_cell[4], unit_cell[5]) util.main_log(self.info.logfile, uc_line, True) self.info.best_pg = str(point_group) self.info.best_uc = unit_cell else: uc_table = [] uc_summary = [] if self.params.analysis.clustering.flag_on: # run hierarchical clustering analysis from xfel.clustering.cluster import Cluster counter = 0 self.info.clusters = [] threshold = self.params.analysis.clustering.threshold cluster_limit = self.params.analysis.clustering.limit final_pickles = self.info.categories['integrated'][0] pickles = [] if self.params.analysis.clustering.n_images > 0: import random for i in range( len(self.params.analysis.clustering.n_images)): random_number = random.randrange(0, len(final_pickles)) if final_pickles[random_number] in pickles: while final_pickles[random_number] in pickles: random_number = random.randrange( 0, len(final_pickles)) pickles.append(final_pickles[random_number]) else: pickles = final_pickles # Cluster from files (slow, but will keep for now) ucs = Cluster.from_files(pickle_list=pickles) # Do clustering clusters, _ = ucs.ab_cluster(threshold=threshold, log=False, write_file_lists=False, schnell=False, doplot=False) uc_table.append("\n\n{:-^80}\n" \ "".format(' UNIT CELL ANALYSIS ')) # extract clustering info and add to summary output list if cluster_limit is None: if len(pickles) / 10 >= 10: cluster_limit = 10 else: cluster_limit = len(pickles) / 10 for cluster in clusters: sorted_pg_comp = sorted(cluster.pg_composition.items(), key=lambda x: -1 * x[1]) pg_nums = [pg[1] for pg in sorted_pg_comp] cons_pg = sorted_pg_comp[np.argmax(pg_nums)] if len(cluster.members) > cluster_limit: counter += 1 # Write to file cluster_filenames = [j.path for j in cluster.members] if self.params.analysis.clustering.write_files: output_file = os.path.join( self.info.int_base, "uc_cluster_{}.lst".format(counter)) for fn in cluster_filenames: with open(output_file, 'a') as scf: scf.write('{}\n'.format(fn)) mark_output = os.path.basename(output_file) else: mark_output = '*' output_file = None else: mark_output = '' output_file = None # Populate clustering info for GUI display uc_init = uctbx.unit_cell(cluster.medians) symmetry = crystal.symmetry(unit_cell=uc_init, space_group_symbol='P1') groups = metric_subgroups(input_symmetry=symmetry, max_delta=3) top_group = groups.result_groups[0] best_sg = str(groups.lattice_group_info()).split('(')[0] best_uc = top_group['best_subsym'].unit_cell().parameters() # best_sg = str(top_group['best_subsym'].space_group_info()) uc_no_stdev = "{:<6.2f} {:<6.2f} {:<6.2f} " \ "{:<6.2f} {:<6.2f} {:<6.2f} " \ "".format(best_uc[0], best_uc[1], best_uc[2], best_uc[3], best_uc[4], best_uc[5]) cluster_info = { 'number': len(cluster.members), 'pg': best_sg, 'uc': uc_no_stdev, 'filename': mark_output } self.info.clusters.append(cluster_info) # format and record output # TODO: How to propagate stdevs after conversion from Niggli? # uc_line = "{:<6} {:^4}: {:<6.2f} ({:>5.2f}), {:<6.2f} ({:>5.2f}), "\ # "{:<6.2f} ({:>5.2f}), {:<6.2f} ({:>5.2f}), "\ # "{:<6.2f} ({:>5.2f}), {:<6.2f} ({:>5.2f}) "\ # "{}".format('({})'.format(len(cluster.members)), cons_pg[0], # cluster.medians[0], cluster.stdevs[0], # cluster.medians[1], cluster.stdevs[1], # cluster.medians[2], cluster.stdevs[2], # cluster.medians[3], cluster.stdevs[3], # cluster.medians[4], cluster.stdevs[4], # cluster.medians[5], cluster.stdevs[5], # mark_output) # uc_table.append(uc_line) uc_table.append("{:<6}: {} {}".format( len(cluster.members), uc_no_stdev, mark_output)) lattices = ', '.join( ['{} ({})'.format(i[0], i[1]) for i in sorted_pg_comp]) # uc_info = [len(cluster.members), cons_pg[0], cluster.medians, # output_file, uc_line, lattices] uc_info = [ len(cluster.members), best_sg, best_uc, output_file, uc_no_stdev, lattices ] uc_summary.append(uc_info) else: # generate average unit cell uc_table.append("\n\n{:-^80}\n" \ "".format(' UNIT CELL AVERAGING (no clustering) ')) uc_a, uc_b, uc_c, uc_alpha, \ uc_beta, uc_gamma, uc_sg = list(zip(*self.info.cluster_iterable)) cons_pg = Counter(uc_sg).most_common(1)[0][0] all_pgs = Counter(uc_sg).most_common() unit_cell = (np.median(uc_a), np.median(uc_b), np.median(uc_c), np.median(uc_alpha), np.median(uc_beta), np.median(uc_gamma)) # Populate clustering info for GUI display uc_init = uctbx.unit_cell(unit_cell) symmetry = crystal.symmetry(unit_cell=uc_init, space_group_symbol='P1') groups = metric_subgroups(input_symmetry=symmetry, max_delta=3) top_group = groups.result_groups[0] best_sg = str(groups.lattice_group_info()).split('(')[0] best_uc = top_group['best_subsym'].unit_cell().parameters() # best_sg = str(top_group['best_subsym'].space_group_info()) uc_no_stdev = "{:<6.2f} {:<6.2f} {:<6.2f} " \ "{:<6.2f} {:<6.2f} {:<6.2f} " \ "".format(best_uc[0], best_uc[1], best_uc[2], best_uc[3], best_uc[4], best_uc[5]) cluster_info = { 'number': len(self.info.cluster_iterable), 'pg': best_sg, 'uc': uc_no_stdev, 'filename': None } self.info.clusters.append(cluster_info) # uc_line = "{:<6} {:^4}: {:<6.2f} ({:>5.2f}), {:<6.2f} ({:>5.2f}), " \ # "{:<6.2f} ({:>5.2f}), {:<6.2f} ({:>5.2f}), " \ # "{:<6.2f} ({:>5.2f}), {:<6.2f} ({:>5.2f}) " \ # "{}".format('({})'.format(len(self.final_objects)), cons_pg, # np.median(uc_a), np.std(uc_a), # np.median(uc_b), np.std(uc_b), # np.median(uc_c), np.std(uc_c), # np.median(uc_alpha), np.std(uc_alpha), # np.median(uc_beta), np.std(uc_beta), # np.median(uc_gamma), np.std(uc_gamma), '') # # uc_table.append(uc_line) uc_table.append(uc_no_stdev) lattices = ', '.join( ['{} ({})'.format(i[0], i[1]) for i in all_pgs]) # uc_info = [len(self.final_objects), cons_pg, unit_cell, None, # uc_line, lattices] uc_info = [ len(self.info.cluster_iterable), best_sg, best_uc, None, uc_no_stdev, lattices ] uc_summary.append(uc_info) uc_table.append('\nMost common unit cell:\n') # select the most prevalent unit cell (most members in cluster) uc_freqs = [i[0] for i in uc_summary] uc_pick = uc_summary[np.argmax(uc_freqs)] uc_table.append(uc_pick[4]) uc_table.append('\nBravais Lattices in Biggest Cluster: {}' ''.format(uc_pick[5])) self.info.best_pg = str(uc_pick[1]) self.info.best_uc = uc_pick[2] if uc_pick[3] is not None: self.prime_data_path = uc_pick[3] for item in uc_table: util.main_log(self.info.logfile, item, False) self.info.update(uc_table=uc_table) if self.gui_mode: return self.info.clusters
if __name__ == "__main__": uc_min = uctbx.unit_cell(( 44.66208170999999, 53.12629402999999, 62.53397660267584, 115.13670293012744, 101.7265610491002, 90.0, )) cs_min = crystal.symmetry(unit_cell=uc_min, space_group=sgtbx.space_group()) from cctbx.sgtbx.lattice_symmetry import metric_subgroups subgroups = metric_subgroups(cs_min, max_delta=5) best_subgroup = subgroups.result_groups[0] print(f"best_sybsym {best_subgroup['best_subsym']}\n") print(f"ref_sybsym {best_subgroup['ref_subsym']}\n") cs_ref = crystal.symmetry( # unit_cell=(113.2236274, 53.12629403, 44.66208171, 90, 102.9736126, 90), unit_cell=(112.90, 53.14, 44.39, 90.00, 103.04, 90.00), space_group_symbol="C 1 2/m 1", ) cs_best = cs_ref.best_cell() cb_ref_best = cs_ref.change_of_basis_op_to_best_cell() cb_ref_primitive = cs_ref.change_of_basis_op_to_primitive_setting() cb_best_primitive = cs_best.change_of_basis_op_to_primitive_setting() cb_best_ref = cs_best.change_of_basis_op_to_reference_setting()
from cctbx.sgtbx.lattice_symmetry import metric_subgroups from cctbx import crystal input_symmetry = crystal.symmetry( unit_cell=(20, 20, 20, 90, 90, 90), space_group_symbol = "P23") groups = metric_subgroups(input_symmetry=input_symmetry, max_delta = 0.0) for item in groups.result_groups: cell = item['ref_subsym'].unit_cell().parameters() spacegroup_name = item['ref_subsym'].space_group().type( ).universal_hermann_mauguin_symbol() reindex = item['cb_op_inp_best'].as_hkl() print '%20s' % spacegroup_name, '%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f' % \ cell, reindex print '%6.3f %6.3f %6.3f\n%6.3f %6.3f %6.3f\n%6.3f %6.3f %6.3f' % \ item['cb_op_inp_best'].c().r().as_double()