def test_empty(self): # single line cb = CifBlock.from_string("data_mwe\nloop_\n_tag\n ''") self.assertEqual(cb.data['_tag'][0], '') # multi line cb = CifBlock.from_string("data_mwe\nloop_\n_tag\n;\n;") self.assertEqual(cb.data['_tag'][0], '') cb2 = CifBlock.from_string(str(cb)) self.assertEqual(cb, cb2)
def test_double_quotes_and_underscore_data(self): cif_str = """data_test _symmetry_space_group_name_H-M "P -3 m 1" _thing '_annoying_data'""" cb = CifBlock.from_string(cif_str) self.assertEqual(cb["_symmetry_space_group_name_H-M"], "P -3 m 1") self.assertEqual(cb["_thing"], "_annoying_data") self.assertEqual(str(cb), cif_str.replace('"', "'"))
def test_double_quoted_data(self): cif_str = """data_test _thing ' '_annoying_data'' _other " "_more_annoying_data"" _more ' "even more" ' """ cb = CifBlock.from_string(cif_str) self.assertEqual(cb["_thing"], " '_annoying_data'") self.assertEqual(cb["_other"], ' "_more_annoying_data"') self.assertEqual(cb["_more"], ' "even more" ')
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_nested_fake_multiline_quotes(self): cif_str = """data_test _thing ; long quotes ; still in the quote ; actually going to end now ;""" cb = CifBlock.from_string(cif_str) self.assertEqual(cb["_thing"], " long quotes ; still in the quote" " ; actually going to end now")
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 test_to_string(self): with open(self.TEST_FILES_DIR / 'Graphite.cif') as f: s = f.read() c = CifBlock.from_string(s) cif_str_2 = str(CifBlock.from_string(str(c))) cif_str = """data_53781-ICSD _database_code_ICSD 53781 _audit_creation_date 2003-04-01 _audit_update_record 2013-02-01 _chemical_name_systematic Carbon _chemical_formula_structural C _chemical_formula_sum C1 _chemical_name_structure_type Graphite(2H) _chemical_name_mineral 'Graphite 2H' _exptl_crystal_density_diffrn 2.22 _publ_section_title 'Structure of graphite' loop_ _citation_id _citation_journal_full _citation_year _citation_journal_volume _citation_page_first _citation_page_last _citation_journal_id_ASTM primary 'Physical Review (1,1893-132,1963/141,1966-188,1969)' 1917 10 661 696 PHRVAO loop_ _publ_author_name 'Hull, A.W.' _cell_length_a 2.47 _cell_length_b 2.47 _cell_length_c 6.8 _cell_angle_alpha 90. _cell_angle_beta 90. _cell_angle_gamma 120. _cell_volume 35.93 _cell_formula_units_Z 4 _symmetry_space_group_name_H-M 'P 63/m m c' _symmetry_Int_Tables_number 194 loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, x-y, -z+1/2' 2 '-x+y, y, -z+1/2' 3 '-y, -x, -z+1/2' 4 '-x+y, -x, -z+1/2' 5 '-y, x-y, -z+1/2' 6 'x, y, -z+1/2' 7 '-x, -x+y, z+1/2' 8 'x-y, -y, z+1/2' 9 'y, x, z+1/2' 10 'x-y, x, z+1/2' 11 'y, -x+y, z+1/2' 12 '-x, -y, z+1/2' 13 '-x, -x+y, -z' 14 'x-y, -y, -z' 15 'y, x, -z' 16 'x-y, x, -z' 17 'y, -x+y, -z' 18 '-x, -y, -z' 19 'x, x-y, z' 20 '-x+y, y, z' 21 '-y, -x, z' 22 '-x+y, -x, z' 23 '-y, x-y, z' 24 'x, y, z' loop_ _atom_type_symbol _atom_type_oxidation_number C0+ 0 loop_ _atom_site_label _atom_site_type_symbol _atom_site_symmetry_multiplicity _atom_site_Wyckoff_symbol _atom_site_fract_x _atom_site_fract_y _atom_site_fract_z _atom_site_B_iso_or_equiv _atom_site_occupancy _atom_site_attached_hydrogens C1 C0+ 2 b 0 0 0.25 . 1. 0 C2 C0+ 2 c 0.3333 0.6667 0.25 . 1. 0""" for l1, l2, l3 in zip( str(c).split("\n"), cif_str.split("\n"), cif_str_2.split("\n")): self.assertEqual(l1.strip(), l2.strip()) self.assertEqual(l2.strip(), l3.strip())
def test_to_string(self): with open(self.TEST_FILES_DIR / 'Graphite.cif') as f: s = f.read() c = CifBlock.from_string(s) cif_str_2 = str(CifBlock.from_string(str(c))) cif_str = """data_53781-ICSD _database_code_ICSD 53781 _audit_creation_date 2003-04-01 _audit_update_record 2013-02-01 _chemical_name_systematic Carbon _chemical_formula_structural C _chemical_formula_sum C1 _chemical_name_structure_type Graphite(2H) _chemical_name_mineral 'Graphite 2H' _exptl_crystal_density_diffrn 2.22 _publ_section_title 'Structure of graphite' loop_ _citation_id _citation_journal_full _citation_year _citation_journal_volume _citation_page_first _citation_page_last _citation_journal_id_ASTM primary 'Physical Review (1,1893-132,1963/141,1966-188,1969)' 1917 10 661 696 PHRVAO loop_ _publ_author_name 'Hull, A.W.' _cell_length_a 2.47 _cell_length_b 2.47 _cell_length_c 6.8 _cell_angle_alpha 90. _cell_angle_beta 90. _cell_angle_gamma 120. _cell_volume 35.93 _cell_formula_units_Z 4 _symmetry_space_group_name_H-M 'P 63/m m c' _symmetry_Int_Tables_number 194 loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, x-y, -z+1/2' 2 '-x+y, y, -z+1/2' 3 '-y, -x, -z+1/2' 4 '-x+y, -x, -z+1/2' 5 '-y, x-y, -z+1/2' 6 'x, y, -z+1/2' 7 '-x, -x+y, z+1/2' 8 'x-y, -y, z+1/2' 9 'y, x, z+1/2' 10 'x-y, x, z+1/2' 11 'y, -x+y, z+1/2' 12 '-x, -y, z+1/2' 13 '-x, -x+y, -z' 14 'x-y, -y, -z' 15 'y, x, -z' 16 'x-y, x, -z' 17 'y, -x+y, -z' 18 '-x, -y, -z' 19 'x, x-y, z' 20 '-x+y, y, z' 21 '-y, -x, z' 22 '-x+y, -x, z' 23 '-y, x-y, z' 24 'x, y, z' loop_ _atom_type_symbol _atom_type_oxidation_number C0+ 0 loop_ _atom_site_label _atom_site_type_symbol _atom_site_symmetry_multiplicity _atom_site_Wyckoff_symbol _atom_site_fract_x _atom_site_fract_y _atom_site_fract_z _atom_site_B_iso_or_equiv _atom_site_occupancy _atom_site_attached_hydrogens C1 C0+ 2 b 0 0 0.25 . 1. 0 C2 C0+ 2 c 0.3333 0.6667 0.25 . 1. 0""" for l1, l2, l3 in zip(str(c).split("\n"), cif_str.split("\n"), cif_str_2.split("\n")): self.assertEqual(l1.strip(), l2.strip()) self.assertEqual(l2.strip(), l3.strip())
outputFilePath = str(sys.argv[3]) #loading a poscar object we handle .structure.composition, .structure.formula, and .structure.lattice #validate the POSCAR that is not well-defined and/or ambiguous. if Poscar.from_file(inputFileFullPath).true_names: ps = Poscar.from_file(inputFileFullPath).structure # #casting poscar structure to dict and cif format files ps_dict = ps.composition.as_dict() ps_reduced_dict, ps_reduced_factor = ps.composition.get_reduced_formula_and_factor( ) ps_cif = ps.to("cif") #cif_sample[0] = "# generated using pymatgen\ndata_Ga2CoS4\n_symmetry_space_group_name_H-M 'P 1'\n_cell_length_a 5.29198729\n_cell_length_b 5.29198728\n_cell_length_c 6.45268046\n_cell_angle_alpha 114.20867693\n_cell_angle_beta 114.20867699\n_cell_angle_gamma 89.99999995\n_symmetry_Int_Tables_number 1\n_chemical_formula_structural Ga2CoS4\n_chemical_formula_sum 'Ga2 Co1 S4'\n_cell_volume 147.218893696\n_cell_formula_units_Z 1\nloop_\n _symmetry_equiv_pos_site_id\n _symmetry_equiv_pos_as_xyz\n 1 'x, y, z'\nloop_\n _atom_site_type_symbol\n _atom_site_label\n _atom_site_symmetry_multiplicity\n _atom_site_fract_x\n _atom_site_fract_y\n _atom_site_fract_z\n _atom_site_occupancy\n S S1 1 0.874869 0.886340 0.253531 1\n S S2 1 0.632808 0.125131 0.746469 1\n S S3 1 0.113660 0.621337 0.746469 1\n S S4 1 0.378663 0.367192 0.253531 1\n Co Co5 1 0.000000 0.000000 0.000000 1\n Ga Ga6 1 0.500000 0.500000 0.000000 1\n Ga Ga7 1 0.250000 0.750000 0.500000 1\n" cif_sample_from_the_ps_sample_0_structure = CifBlock.from_string(ps_cif).data ## 20170911 battery properties calculation added by Jclee IS_BATTERY = False ps_dict_battery_working_ion = dict() IF_for_working_ion = 0 for keys in ps_dict.keys(): #if the key is an working ion if keys == 'Li' or keys == 'Na' or keys == 'K': IS_BATTERY = True ps_dict_battery_others = ps_dict.copy() ps_dict_battery_working_ion = {keys: ps_dict_battery_others.pop(keys)} IF_for_working_ion = 1 elif keys == 'Mg': # or keys == 'Ca': IS_BATTERY = True
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)