def make_cif(self): """ Generates a pymatgen CifFile object using structure info parsed from SPuDS output.txt. Returns: cf: pymatgen CifFile object """ # SPuDS ouput structure info site_list,a_lat,b_lat,c_lat,alp,bet,gam = parse_spuds_out(self) # Mapped lattice parameters to .cif compatibility a,b,c,alpha,beta,gamma = map_lattice_menu_1(self, a_lat,b_lat,c_lat, alp,bet,gam) symd = self.symops_dict[self.symops_key] # symops dict data # Create dict of .cif parameters data = {} data['_cell_length_a'] = a data['_cell_length_b'] = b data['_cell_length_c'] = c data['_cell_angle_alpha'] = alpha data['_cell_angle_beta'] = beta data['_cell_angle_gamma'] = gamma data['_space_group_name_H-M_alt'] = symd['name'] data['_symmetry_Int_tables_number'] = symd['number'] data['_symmetry_cell_setting'] = symd['latsym'] data['_space_group_symop_operation_xyz'] = symd['symops'] data['_atom_type_symbol'] = self.ellist data['_atom_type_oxidation_number'] = self.oxilist data['_atom_site_label'] = [d[0] for d in site_list] data['_atom_site_type_symbol'] = [d[1] for d in site_list] data['_atom_site_symmetry_multiplicity'] = [d[2] for d in site_list] data['_atom_site_Wycoff_symbol'] = [d[3] for d in site_list] data['_atom_site_fract_x'] = [d[4] for d in site_list] data['_atom_site_fract_y'] = [d[5] for d in site_list] data['_atom_site_fract_z'] = [d[6] for d in site_list] data['_atom_site_occupancy'] = [d[7] for d in site_list] # .cif file header cif_header = 'SPuDS' # .cif file loops cif_loops = [['_space_group_symop_operation_xyz'], ['_atom_type_symbol','_atom_type_oxidation_number'], ['_atom_site_label','_atom_site_type_symbol', '_atom_site_symmetry_multiplicity', '_atom_site_Wycoff_symbol','_atom_site_fract_x', '_atom_site_fract_y','_atom_site_fract_z', '_atom_site_occupancy']] # Create CifFile object d = OrderedDict() d[self.formula] = CifBlock(data,cif_loops,cif_header) cf = CifFile(d) return cf
def test_long_loop(self): data = {'_stuff1': ['A' * 30] * 2, '_stuff2': ['B' * 30] * 2, '_stuff3': ['C' * 30] * 2} loops = [['_stuff1', '_stuff2', '_stuff3']] cif_str = """data_test loop_ _stuff1 _stuff2 _stuff3 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC""" self.assertEqual(str(CifBlock(data, loops, 'test')), cif_str)
def test_long_loop(self): data = { "_stuff1": ["A" * 30] * 2, "_stuff2": ["B" * 30] * 2, "_stuff3": ["C" * 30] * 2, } loops = [["_stuff1", "_stuff2", "_stuff3"]] cif_str = """data_test loop_ _stuff1 _stuff2 _stuff3 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC""" self.assertEqual(str(CifBlock(data, loops, "test")), cif_str)
def clear_cif_from_crystalmaker(s): identifier, d = get_pmg_dict(s) if any('generated by CrystalMaker' in v for v in d.values()): k = '_atom_site_occupancy' try: lenk = len(d[k]) except KeyError: return s for i in range(lenk): d[k][i] = 1.0 loops = [[], []] for key in d.keys(): if '_symmetry_equiv_pos_as_xyz' in key: loops[0].append(key) elif '_atom_' in key: loops[1].append(key) s = CifBlock(d, loops, identifier).__str__() return s
def __init__(self, struct, symprec=None, charges=None): """ A wrapper around CifFile to write CIF files from pymatgen structures. Args: struct (Structure): structure to write symprec (float): If not none, finds the symmetry of the structure and writes the cif with symmetry information. Passes symprec to the SpacegroupAnalyzer write_magmoms (bool): If True, will write magCIF file. Incompatible with symprec """ format_str = "{:.8f}" block = OrderedDict() loops = [] spacegroup = ("P 1", 1) if symprec is not None: sf = SpacegroupAnalyzer(struct, symprec) spacegroup = (sf.get_space_group_symbol(), sf.get_space_group_number()) # Needs the refined struture when using symprec. This converts # primitive to conventional structures, the standard for CIF. struct = sf.get_refined_structure() latt = struct.lattice comp = struct.composition no_oxi_comp = comp.element_composition block["_symmetry_space_group_name_H-M"] = spacegroup[0] for cell_attr in ['a', 'b', 'c']: block["_cell_length_" + cell_attr] = format_str.format( getattr(latt, cell_attr)) for cell_attr in ['alpha', 'beta', 'gamma']: block["_cell_angle_" + cell_attr] = format_str.format( getattr(latt, cell_attr)) block["_symmetry_Int_Tables_number"] = spacegroup[1] block["_chemical_formula_structural"] = no_oxi_comp.reduced_formula block["_chemical_formula_sum"] = no_oxi_comp.formula block["_cell_volume"] = "%.8f" % latt.volume reduced_comp, fu = no_oxi_comp.get_reduced_composition_and_factor() block["_cell_formula_units_Z"] = str(int(fu)) if symprec is None: block["_symmetry_equiv_pos_site_id"] = ["1"] block["_symmetry_equiv_pos_as_xyz"] = ["x, y, z"] else: sf = SpacegroupAnalyzer(struct, symprec) symmops = [] for op in sf.get_symmetry_operations(): v = op.translation_vector symmops.append( SymmOp.from_rotation_and_translation( op.rotation_matrix, v)) ops = [op.as_xyz_string() for op in symmops] block["_symmetry_equiv_pos_site_id"] = \ ["%d" % i for i in range(1, len(ops) + 1)] block["_symmetry_equiv_pos_as_xyz"] = ops loops.append( ["_symmetry_equiv_pos_site_id", "_symmetry_equiv_pos_as_xyz"]) try: symbol_to_oxinum = OrderedDict([(el.__str__(), float(el.oxi_state)) for el in sorted(comp.elements)]) block["_atom_type_symbol"] = symbol_to_oxinum.keys() block["_atom_type_oxidation_number"] = symbol_to_oxinum.values() loops.append(["_atom_type_symbol", "_atom_type_oxidation_number"]) except (TypeError, AttributeError): symbol_to_oxinum = OrderedDict([(el.symbol, 0) for el in sorted(comp.elements)]) atom_site_type_symbol = [] atom_site_symmetry_multiplicity = [] atom_site_fract_x = [] atom_site_fract_y = [] atom_site_fract_z = [] atom_site_label = [] atom_site_occupancy = [] atom_site_charge_label = [] count = 1 if symprec is None: for site in struct: for sp, occu in sorted(site.species_and_occu.items()): atom_site_type_symbol.append(sp.__str__()) atom_site_symmetry_multiplicity.append("1") atom_site_fract_x.append("{0:f}".format(site.a)) atom_site_fract_y.append("{0:f}".format(site.b)) atom_site_fract_z.append("{0:f}".format(site.c)) atom_site_label.append("{}{}".format(sp.symbol, count)) atom_site_occupancy.append(occu.__str__()) count += 1 else: # The following just presents a deterministic ordering. unique_sites = [ (sorted(sites, key=lambda s: tuple([abs(x) for x in s.frac_coords]))[0], len(sites)) for sites in sf.get_symmetrized_structure().equivalent_sites ] for site, mult in sorted(unique_sites, key=lambda t: (t[0].species_and_occu.average_electroneg, -t[1], t[0].a, t[0].b, t[0].c)): for sp, occu in site.species_and_occu.items(): atom_site_type_symbol.append(sp.__str__()) atom_site_symmetry_multiplicity.append("%d" % mult) atom_site_fract_x.append("{0:f}".format(site.a)) atom_site_fract_y.append("{0:f}".format(site.b)) atom_site_fract_z.append("{0:f}".format(site.c)) atom_site_label.append("{}{}".format(sp.symbol, count)) atom_site_occupancy.append(occu.__str__()) count += 1 block["_atom_site_type_symbol"] = atom_site_type_symbol block["_atom_site_label"] = atom_site_label block["_atom_site_symmetry_multiplicity"] = \ atom_site_symmetry_multiplicity block["_atom_site_fract_x"] = atom_site_fract_x block["_atom_site_fract_y"] = atom_site_fract_y block["_atom_site_fract_z"] = atom_site_fract_z block["_atom_site_occupancy"] = atom_site_occupancy block["_atom_site_charge"] = charges loops.append([ "_atom_site_type_symbol", "_atom_site_label", "_atom_site_symmetry_multiplicity", "_atom_site_fract_x", "_atom_site_fract_y", "_atom_site_fract_z", "_atom_site_occupancy", "_atom_site_charge", ]) d = OrderedDict() d[comp.reduced_formula] = CifBlock(block, loops, comp.reduced_formula) self._cf = CifFile(d)