def handle_unparsablespecies(cif_string): """ Handles CIF parsing errors arising from unrecognizable species :param cif_string: (str) cif file :return: pymatgen structure object with appended unparsable species """ cif_string_new = '' symbols = [] coords = [] occupancies = [] cif = CifFile.from_string(cif_string).data for block in cif: if 'standardized' in block: cif_stdblock = cif[block] break for i, sym in enumerate(cif_stdblock['_atom_site_type_symbol']): if 'OH' in sym: symbols.append(sym) coords.append([ float(cif_stdblock['_atom_site_fract_x'][i]), float(cif_stdblock['_atom_site_fract_y'][i]), float(cif_stdblock['_atom_site_fract_z'][i]) ]) occupancies.append(float(cif_stdblock['_atom_site_occupancy'][i])) for key in cif: cif_string_new += str(cif[key]) + '\n' cif_string_new += '\n' new_struct = CifParser.from_string(cif_string_new).get_structures()[0] for specie_no in range(len(symbols)): new_struct.append({DummySpecie('X'): occupancies[specie_no]}, coords[specie_no], properties={"molecule": [symbols[specie_no]]}) return new_struct
def get_scene_and_legend(self) -> Tuple[Scene, Dict[str, str]]: legend = Legend(self.graph.structure, color_scheme="VESTA", cmap_range=None) legend.uniform_radius = 0.3 scene = get_structure_graph_scene( self.graph, draw_image_atoms=True, bonded_sites_outside_unit_cell=False, hide_incomplete_edges=True, explicitly_calculate_polyhedra_hull=False, group_by_symmetry=True, draw_polyhedra=False, legend=legend) scene.name = "DefectStructureComponentScene" lattice: Lattice = self.graph.structure.lattice origin = -self.graph.structure.lattice.get_cartesian_coords( [0.5, 0.5, 0.5]) scene_json = scene.to_json() for idx, i in enumerate(self.interstitials, 1): site = Site(species=DummySpecie(), coords=lattice.get_cartesian_coords(i.frac_coords)) interstitial_scene = site.get_scene(origin=origin) interstitial_scene.name = f"i{idx}" interstitial_scene.contents[0].contents[0].tooltip = f"i{idx}" scene_json["contents"].append(interstitial_scene.to_json()) return scene_json, legend.get_legend()
def test_specie_cifwriter(self): si4 = Specie("Si", 4) si3 = Specie("Si", 3) n = DummySpecie("X", -3) coords = list() coords.append(np.array([0.5, 0.5, 0.5])) coords.append(np.array([0.75, 0.5, 0.75])) coords.append(np.array([0, 0, 0])) lattice = Lattice( np.array([[3.8401979337, 0.00, 0.00], [1.9200989668, 3.3257101909, 0.00], [0.00, -2.2171384943, 3.1355090603]])) struct = Structure(lattice, [n, {si3: 0.5, n: 0.5}, si4], coords) writer = CifWriter(struct) ans = """# generated using pymatgen data_X1.5Si1.5 _symmetry_space_group_name_H-M 'P 1' _cell_length_a 3.84019793 _cell_length_b 3.84019899 _cell_length_c 3.84019793 _cell_angle_alpha 119.99999086 _cell_angle_beta 90.00000000 _cell_angle_gamma 60.00000914 _symmetry_Int_Tables_number 1 _chemical_formula_structural X1.5Si1.5 _chemical_formula_sum 'X1.5 Si1.5' _cell_volume 40.04479464 _cell_formula_units_Z 1 loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, y, z' loop_ _atom_type_symbol _atom_type_oxidation_number X3- -3.0 Si3+ 3.0 Si4+ 4.0 loop_ _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 X3- X1 1 0.500000 0.500000 0.500000 1 X3- X2 1 0.750000 0.500000 0.750000 0.5 Si3+ Si3 1 0.750000 0.500000 0.750000 0.5 Si4+ Si4 1 0.000000 0.000000 0.000000 1 """ for l1, l2 in zip(str(writer).split("\n"), ans.split("\n")): self.assertEqual(l1.strip(), l2.strip()) # test that mixed valence works properly s2 = Structure.from_str(ans, "cif") self.assertEqual(struct.composition, s2.composition)
def get_scene_and_legend(self, scene_additions=None ) -> Tuple[Scene, Dict[str, str]]: legend = Legend(self.graph.structure, color_scheme="VESTA", radius_scheme="uniform", cmap_range=None) legend.uniform_radius = 0.2 scene = get_structure_graph_scene( self.graph, draw_image_atoms=True, bonded_sites_outside_unit_cell=False, hide_incomplete_edges=True, explicitly_calculate_polyhedra_hull=False, group_by_symmetry=False, legend=legend) scene.name = "DefectStructureComponentScene" # axes = graph.structure.lattice._axes_from_lattice() # axes.visible = True # scene.contents.append(axes) scene = scene.to_json() if scene_additions: scene["contents"].append(scene_additions) lattice = self.graph.structure.lattice origin = -self.graph.structure.lattice.get_cartesian_coords( [0.5, 0.5, 0.5]) for name, frac_coords in self.vacancy_sites: site = Site(species=DummySpecie(name), coords=lattice.get_cartesian_coords(frac_coords)) vac_scene = site.get_scene(origin=origin) vac_scene.name = f"{name}_{frac_coords}" vac_scene.contents[0].contents[0].tooltip = name scene["contents"].append(vac_scene.to_json()) return scene, legend.get_legend()
def structure_from_string(data): """ Parses a rndstr.in or lat.in file into pymatgen's Structure format. :param data: contents of a rndstr.in or lat.in file :return: Structure object """ data = data.splitlines() data = [x.split() for x in data if x] # remove empty lines # following specification/terminology given in manual if len(data[0]) == 6: # lattice parameters a, b, c, alpha, beta, gamma = map(float, data[0]) coord_system = Lattice.from_parameters(a, b, c, alpha, beta, gamma).matrix lattice_vecs = np.array([ [data[1][0], data[1][1], data[1][2]], [data[2][0], data[2][1], data[2][2]], [data[3][0], data[3][1], data[3][2]] ], dtype=float) first_species_line = 4 else: coord_system = np.array([ [data[0][0], data[0][1], data[0][2]], [data[1][0], data[1][1], data[1][2]], [data[2][0], data[2][1], data[2][2]] ], dtype=float) lattice_vecs = np.array([ [data[3][0], data[3][1], data[3][2]], [data[4][0], data[4][1], data[4][2]], [data[5][0], data[5][1], data[5][2]] ], dtype=float) first_species_line = 6 scaled_matrix = np.matmul(coord_system, lattice_vecs) lattice = Lattice(scaled_matrix) all_coords = [] all_species = [] for l in data[first_species_line:]: all_coords.append(np.array([l[0], l[1], l[2]], dtype=float)) species_strs = "".join(l[3:]) # join multiple strings back together species_strs = species_strs.replace(" ", "") # trim any white space species_strs = species_strs.split(",") # comma-delimited species = {} for species_str in species_strs: species_str = species_str.split('=') if len(species_str) == 1: # assume occupancy is 1.0 species_str = [species_str[0], 1.0] try: species[Specie(species_str[0])] = float(species_str[1]) except Exception: species[DummySpecie(species_str[0])] = float(species_str[1]) all_species.append(species) return Structure(lattice, all_species, all_coords)