def test_disordered_primitive_to_ordered_supercell(self): sm_atoms = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=False, scale=True, attempt_supercell=True, allow_subset=True, supercell_size='num_atoms', comparator=OrderDisorderElementComparator()) sm_sites = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=False, scale=True, attempt_supercell=True, allow_subset=True, supercell_size='num_sites', comparator=OrderDisorderElementComparator()) lp = Lattice.orthorhombic(10, 20, 30) pcoords = [[0, 0, 0], [0.5, 0.5, 0.5]] ls = Lattice.orthorhombic(20, 20, 30) scoords = [[0, 0, 0], [0.75, 0.5, 0.5]] prim = Structure(lp, [{'Na': 0.5}, {'Cl': 0.5}], pcoords) supercell = Structure(ls, ['Na', 'Cl'], scoords) supercell.make_supercell([[-1, 1, 0], [0, 1, 1], [1, 0, 0]]) self.assertFalse(sm_sites.fit(prim, supercell)) self.assertTrue(sm_atoms.fit(prim, supercell)) self.assertRaises(ValueError, sm_atoms.get_s2_like_s1, prim, supercell) self.assertEqual(len(sm_atoms.get_s2_like_s1(supercell, prim)), 4)
def setUp(self): self.structure = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3.5), ["Ni"], [[0, 0, 0]]) lattice = Lattice.cubic(3.010) frac_coords = [[0.00000, 0.00000, 0.00000], [0.00000, 0.50000, 0.50000], [0.50000, 0.00000, 0.50000], [0.50000, 0.50000, 0.00000], [0.50000, 0.00000, 0.00000], [0.50000, 0.50000, 0.50000], [0.00000, 0.00000, 0.50000], [0.00000, 0.50000, 0.00000]] species = ['Mg', 'Mg', 'Mg', 'Mg', 'O', 'O', 'O', 'O'] self.MgO = Structure(lattice, species, frac_coords) slabs = generate_all_slabs(self.structure, max_index=2, min_slab_size=6.0, min_vacuum_size=15.0, max_normal_search=1, center_slab=True) self.slab_dict = {''.join([str(i) for i in slab.miller_index]): slab for slab in slabs} self.asf_211 = AdsorbateSiteFinder(self.slab_dict["211"]) self.asf_100 = AdsorbateSiteFinder(self.slab_dict["100"]) self.asf_111 = AdsorbateSiteFinder(self.slab_dict["111"]) self.asf_110 = AdsorbateSiteFinder(self.slab_dict["110"]) self.asf_struct = AdsorbateSiteFinder( Structure.from_sites(self.slab_dict["111"].sites))
def test_get_supercell_size(self): l = Lattice.cubic(1) l2 = Lattice.cubic(0.9) s1 = Structure(l, ['Mg', 'Cu', 'Ag', 'Cu', 'Ag'], [[0] * 3] * 5) s2 = Structure(l2, ['Cu', 'Cu', 'Ag'], [[0] * 3] * 3) sm = StructureMatcher(supercell_size='volume') self.assertEqual(sm._get_supercell_size(s1, s2), (1, True)) self.assertEqual(sm._get_supercell_size(s2, s1), (1, True)) sm = StructureMatcher(supercell_size='num_sites') self.assertEqual(sm._get_supercell_size(s1, s2), (2, False)) self.assertEqual(sm._get_supercell_size(s2, s1), (2, True)) sm = StructureMatcher(supercell_size='Ag') self.assertEqual(sm._get_supercell_size(s1, s2), (2, False)) self.assertEqual(sm._get_supercell_size(s2, s1), (2, True)) sm = StructureMatcher(supercell_size='wfieoh') self.assertRaises(ValueError, sm._get_supercell_size, s1, s2)
def test_lattice_2_lmpbox(self): matrix = np.diag(np.random.randint(5, 14, size=(3,))) \ + np.random.rand(3, 3) * 0.2 - 0.1 init_latt = Lattice(matrix) frac_coords = np.random.rand(10, 3) init_structure = Structure(init_latt, ["H"] * 10, frac_coords) origin = np.random.rand(3) * 10 - 5 box, symmop = lattice_2_lmpbox(lattice=init_latt, origin=origin) boxed_latt = box.to_lattice() np.testing.assert_array_almost_equal(init_latt.abc, boxed_latt.abc) np.testing.assert_array_almost_equal(init_latt.angles, boxed_latt.angles) cart_coords = symmop.operate_multi(init_structure.cart_coords) \ - origin boxed_structure = Structure(boxed_latt, ["H"] * 10, cart_coords, coords_are_cartesian=True) np.testing.assert_array_almost_equal(boxed_structure.frac_coords, frac_coords) tetra_latt = Lattice.tetragonal(5, 5) tetra_box, _ = lattice_2_lmpbox(tetra_latt) self.assertIsNone(tetra_box.tilt) ortho_latt = Lattice.orthorhombic(5, 5, 5) ortho_box, _ = lattice_2_lmpbox(ortho_latt) self.assertIsNone(ortho_box.tilt) rot_tetra_latt = Lattice([[5, 0, 0], [0, 2, 2], [0, -2, 2]]) _, rotop = lattice_2_lmpbox(rot_tetra_latt) np.testing.\ assert_array_almost_equal(rotop.rotation_matrix, [[1, 0, 0], [0, 2 ** 0.5 / 2, 2 ** 0.5 / 2], [0, -2 ** 0.5 / 2, 2 ** 0.5 / 2]])
def test_ordered_primitive_to_disordered_supercell(self): sm_atoms = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=False, scale=True, attempt_supercell=True, allow_subset=True, supercell_size='num_atoms', comparator=OrderDisorderElementComparator()) sm_sites = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=False, scale=True, attempt_supercell=True, allow_subset=True, supercell_size='num_sites', comparator=OrderDisorderElementComparator()) lp = Lattice.orthorhombic(10, 20, 30) pcoords = [[0, 0, 0], [0.5, 0.5, 0.5]] ls = Lattice.orthorhombic(20, 20, 30) scoords = [[0, 0, 0], [0.5, 0, 0], [0.25, 0.5, 0.5], [0.75, 0.5, 0.5]] s1 = Structure(lp, ['Na', 'Cl'], pcoords) s2 = Structure(ls, [{'Na': 0.5}, {'Na': 0.5}, {'Cl': 0.5}, {'Cl': 0.5}], scoords) self.assertTrue(sm_sites.fit(s1, s2)) self.assertFalse(sm_atoms.fit(s1, s2))
def test_structure(self): quartz = self.quartz.structure np.testing.assert_array_equal(quartz.lattice.matrix, [[4.913400, 0, 0], [-2.456700, 4.255129, 0], [0, 0, 5.405200]]) self.assertEqual(quartz.formula, "Si3 O6") self.assertNotIn("molecule-ID", self.quartz.atoms.columns) ethane = self.ethane.structure np.testing.assert_array_equal(ethane.lattice.matrix, np.diag([10.0] * 3)) lbounds = np.array(self.ethane.box.bounds)[:, 0] coords = self.ethane.atoms[["x", "y", "z"]].values - lbounds np.testing.assert_array_equal(ethane.cart_coords, coords) np.testing.assert_array_equal(ethane.site_properties["charge"], self.ethane.atoms["q"]) tatb = self.tatb.structure frac_coords = tatb.frac_coords[381] real_frac_coords = frac_coords - np.floor(frac_coords) np.testing.assert_array_almost_equal(real_frac_coords, [0.01553397, 0.71487872, 0.14134139]) co = Structure.from_spacegroup(194, Lattice.hexagonal(2.50078, 4.03333), ["Co"], [[1/3, 2/3, 1/4]]) ld_co = LammpsData.from_structure(co) self.assertEqual(ld_co.structure.composition.reduced_formula, "Co") ni = Structure.from_spacegroup(225, Lattice.cubic(3.50804), ["Ni"], [[0, 0, 0]]) ld_ni = LammpsData.from_structure(ni) self.assertEqual(ld_ni.structure.composition.reduced_formula, "Ni")
def test_fit(self): """ Take two known matched structures 1) Ensure match 2) Ensure match after translation and rotations 3) Ensure no-match after large site translation 4) Ensure match after site shuffling """ sm = StructureMatcher() self.assertTrue(sm.fit(self.struct_list[0], self.struct_list[1])) # Test rotational/translational invariance op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 30, False, np.array([0.4, 0.7, 0.9])) self.struct_list[1].apply_operation(op) self.assertTrue(sm.fit(self.struct_list[0], self.struct_list[1])) # Test failure under large atomic translation self.struct_list[1].translate_sites([0], [.4, .4, .2], frac_coords=True) self.assertFalse(sm.fit(self.struct_list[0], self.struct_list[1])) self.struct_list[1].translate_sites([0], [-.4, -.4, -.2], frac_coords=True) # random.shuffle(editor._sites) self.assertTrue(sm.fit(self.struct_list[0], self.struct_list[1])) # Test FrameworkComporator sm2 = StructureMatcher(comparator=FrameworkComparator()) lfp = self.get_structure("LiFePO4") nfp = self.get_structure("NaFePO4") self.assertTrue(sm2.fit(lfp, nfp)) self.assertFalse(sm.fit(lfp, nfp)) # Test anonymous fit. self.assertEqual(sm.fit_anonymous(lfp, nfp), True) self.assertAlmostEqual(sm.get_rms_anonymous(lfp, nfp)[0], 0.060895871160262717) # Test partial occupancies. s1 = Structure(Lattice.cubic(3), [{"Fe": 0.5}, {"Fe": 0.5}, {"Fe": 0.5}, {"Fe": 0.5}], [[0, 0, 0], [0.25, 0.25, 0.25], [0.5, 0.5, 0.5], [0.75, 0.75, 0.75]]) s2 = Structure(Lattice.cubic(3), [{"Fe": 0.25}, {"Fe": 0.5}, {"Fe": 0.5}, {"Fe": 0.75}], [[0, 0, 0], [0.25, 0.25, 0.25], [0.5, 0.5, 0.5], [0.75, 0.75, 0.75]]) self.assertFalse(sm.fit(s1, s2)) self.assertFalse(sm.fit(s2, s1)) s2 = Structure(Lattice.cubic(3), [{"Mn": 0.5}, {"Mn": 0.5}, {"Mn": 0.5}, {"Mn": 0.5}], [[0, 0, 0], [0.25, 0.25, 0.25], [0.5, 0.5, 0.5], [0.75, 0.75, 0.75]]) self.assertEqual(sm.fit_anonymous(s1, s2), True) self.assertAlmostEqual(sm.get_rms_anonymous(s1, s2)[0], 0)
def setUp(self): c1 = [[0.5] * 3, [0.9] * 3] c2 = [[0.5] * 3, [0.9, 0.1, 0.1]] s1 = Structure(Lattice.cubic(5), ['Si', 'Si'], c1) s2 = Structure(Lattice.cubic(5), ['Si', 'Si'], c2) structs = [] for s in s1.interpolate(s2, 3, pbc=True): structs.append(Structure.from_sites(s.sites, to_unit_cell=True)) self.structures = structs self.vis = MITNEBSet(self.structures)
def test_write_inputs(self): c1 = [[0.5] * 3, [0.9] * 3] c2 = [[0.5] * 3, [0.9, 0.1, 0.1]] s1 = Structure(Lattice.cubic(5), ['Si', 'Si'], c1) s2 = Structure(Lattice.cubic(5), ['Si', 'Si'], c2) structs = [] for s in s1.interpolate(s2, 3, pbc=True): structs.append(Structure.from_sites(s.sites, to_unit_cell=True)) fc = self.vis._process_structures(structs)[2].frac_coords self.assertTrue(np.allclose(fc, [[0.5]*3,[0.9, 1.033333, 1.0333333]]))
def setUp(self): # trivial example, simple square lattice for testing structure = Structure(Lattice.tetragonal(5.0, 50.0), ['H'], [[0, 0, 0]]) self.square_sg = StructureGraph.with_empty_graph(structure, edge_weight_name="", edge_weight_units="") self.square_sg.add_edge(0, 0, from_jimage=(0, 0, 0), to_jimage=(1, 0, 0)) self.square_sg.add_edge(0, 0, from_jimage=(0, 0, 0), to_jimage=(-1, 0, 0)) self.square_sg.add_edge(0, 0, from_jimage=(0, 0, 0), to_jimage=(0, 1, 0)) self.square_sg.add_edge(0, 0, from_jimage=(0, 0, 0), to_jimage=(0, -1, 0)) # body-centered square lattice for testing structure = Structure(Lattice.tetragonal(5.0, 50.0), ['H', 'He'], [[0, 0, 0], [0.5, 0.5, 0.5]]) self.bc_square_sg = StructureGraph.with_empty_graph(structure, edge_weight_name="", edge_weight_units="") self.bc_square_sg.add_edge(0, 0, from_jimage=(0, 0, 0), to_jimage=(1, 0, 0)) self.bc_square_sg.add_edge(0, 0, from_jimage=(0, 0, 0), to_jimage=(-1, 0, 0)) self.bc_square_sg.add_edge(0, 0, from_jimage=(0, 0, 0), to_jimage=(0, 1, 0)) self.bc_square_sg.add_edge(0, 0, from_jimage=(0, 0, 0), to_jimage=(0, -1, 0)) self.bc_square_sg.add_edge(0, 1, from_jimage=(0, 0, 0), to_jimage=(0, 0, 0)) self.bc_square_sg.add_edge(0, 1, from_jimage=(0, 0, 0), to_jimage=(-1, 0, 0)) self.bc_square_sg.add_edge(0, 1, from_jimage=(0, 0, 0), to_jimage=(-1, -1, 0)) self.bc_square_sg.add_edge(0, 1, from_jimage=(0, 0, 0), to_jimage=(0, -1, 0)) # body-centered square lattice for testing # directions reversed, should be equivalent to as bc_square structure = Structure(Lattice.tetragonal(5.0, 50.0), ['H', 'He'], [[0, 0, 0], [0.5, 0.5, 0.5]]) self.bc_square_sg_r = StructureGraph.with_empty_graph(structure, edge_weight_name="", edge_weight_units="") self.bc_square_sg_r.add_edge(0, 0, from_jimage=(0, 0, 0), to_jimage=(1, 0, 0)) self.bc_square_sg_r.add_edge(0, 0, from_jimage=(0, 0, 0), to_jimage=(-1, 0, 0)) self.bc_square_sg_r.add_edge(0, 0, from_jimage=(0, 0, 0), to_jimage=(0, 1, 0)) self.bc_square_sg_r.add_edge(0, 0, from_jimage=(0, 0, 0), to_jimage=(0, -1, 0)) self.bc_square_sg_r.add_edge(0, 1, from_jimage=(0, 0, 0), to_jimage=(0, 0, 0)) self.bc_square_sg_r.add_edge(1, 0, from_jimage=(-1, 0, 0), to_jimage=(0, 0, 0)) self.bc_square_sg_r.add_edge(1, 0, from_jimage=(-1, -1, 0), to_jimage=(0, 0, 0)) self.bc_square_sg_r.add_edge(1, 0, from_jimage=(0, -1, 0), to_jimage=(0, 0, 0)) # MoS2 example, structure graph obtained from critic2 # (not ground state, from mp-1023924, single layer) stdout_file = os.path.join(os.path.dirname(__file__), "..", "..", "..", 'test_files/critic2/MoS2_critic2_stdout.txt') with open(stdout_file, 'r') as f: reference_stdout = f.read() self.structure = Structure.from_file(os.path.join(os.path.dirname(__file__), "..", "..", "..", 'test_files/critic2/MoS2.cif')) c2o = Critic2Output(self.structure, reference_stdout) self.mos2_sg = c2o.structure_graph(edge_weight="bond_length", edge_weight_units="Å") latt = Lattice.cubic(4.17) species = ["Ni", "O"] coords = [[0, 0, 0], [0.5, 0.5, 0.5]] self.NiO = Structure.from_spacegroup(225, latt, species, coords).get_primitive_structure()
def test_aqueous_compat(self): el_li = Element("Li") el_o = Element("O") el_h = Element("H") latt = Lattice.from_parameters(3.565276, 3.565276, 4.384277, 90.000000, 90.000000, 90.000000) elts = [el_h, el_h, el_li, el_li, el_o, el_o] coords = [[0.000000, 0.500000, 0.413969], [0.500000, 0.000000, 0.586031], [0.000000, 0.000000, 0.000000], [0.500000, 0.500000, 0.000000], [0.000000, 0.500000, 0.192672], [0.500000, 0.000000, 0.807328]] struct = Structure(latt, elts, coords) lioh_entry = ComputedStructureEntry(struct, -3, parameters={'is_hubbard': False, 'hubbards': None, 'run_type': 'GGA', 'potcar_spec': [{'titel':'PAW_PBE Li 17Jan2003', 'hash': '9658a0ffb28da97ee7b36709966a0d1c'}, {'titel': 'PAW_PBE O 08Apr2002', 'hash': '7af704ddff29da5354831c4609f1cbc5'}, {"titel": 'PAW_PBE H 15Jun2001', 'hash': "57732e53d8a424e5b3721d0277f14ef0"}]}) lioh_entry_compat = self.compat.process_entry(lioh_entry) lioh_entry_compat_aqcorr = self.aqcorr.correct_entry(lioh_entry_compat) lioh_entry_aqcompat = self.aqcompat.process_entry(lioh_entry) self.assertAlmostEqual(lioh_entry_compat_aqcorr.energy, lioh_entry_aqcompat.energy, 4)
def test_from_structure_NPT( self ): from pymatgen import Structure, Lattice coords1 = np.array([[0.0, 0.0, 0.0], [0.5, 0.5, 0.5]] ) coords2 = np.array([[0.0, 0.0, 0.0], [0.6, 0.6, 0.6]] ) coords3 = np.array([[0.0, 0.0, 0.0], [0.7, 0.7, 0.7]] ) lattice1 = Lattice.from_parameters(a=2.0, b=2.0, c=2.0, alpha=90, beta=90, gamma=90) lattice2 = Lattice.from_parameters(a=2.1, b=2.1, c=2.1, alpha=90, beta=90, gamma=90) lattice3 = Lattice.from_parameters(a=2.0, b=2.0, c=2.0, alpha=90, beta=90, gamma=90) s1 = Structure(coords=coords1, lattice=lattice1, species=['F', 'Li']) s2 = Structure(coords=coords2, lattice=lattice2, species=['F', 'Li']) s3 = Structure(coords=coords3, lattice=lattice3, species=['F', 'Li']) structures = [s1, s2, s3] d = DiffusionAnalyzer.from_structures( structures, specie='Li', temperature=500.0, time_step=2.0, step_skip=1, smoothed=None ) self.assertArrayAlmostEqual(d.disp[1], np.array([[0., 0., 0. ], [0.21, 0.21, 0.21], [0.40, 0.40, 0.40]]))
def test_peroxide_energy_corr(self): latt = Lattice.from_parameters(3.159597, 3.159572, 7.685205, 89.999884, 89.999674, 60.000510) el_li = Element("Li") el_o = Element("O") elts = [el_li, el_li, el_li, el_li, el_o, el_o, el_o, el_o] coords = [[0.666656, 0.666705, 0.750001], [0.333342, 0.333378, 0.250001], [0.000001, 0.000041, 0.500001], [0.000001, 0.000021, 0.000001], [0.333347, 0.333332, 0.649191], [0.333322, 0.333353, 0.850803], [0.666666, 0.666686, 0.350813], [0.666665, 0.666684, 0.149189]] struct = Structure(latt, elts, coords) li2o2_entry = ComputedStructureEntry(struct, -3, parameters={'is_hubbard': False, 'hubbards': None, 'run_type': 'GGA', 'potcar_spec': [{'titel':'PAW_PBE Li 17Jan2003', 'hash': '65e83282d1707ec078c1012afbd05be8'}, {'titel': 'PAW_PBE O 08Apr2002', 'hash': '7a25bc5b9a5393f46600a4939d357982'}]}) li2o2_entry_corrected = self.compat.process_entry(li2o2_entry) self.assertRaises(AssertionError, self.assertAlmostEqual, *(li2o2_entry_corrected.energy, -3 - 0.44317 * 4, 4)) self.assertAlmostEqual(li2o2_entry_corrected.energy, -3 - 0.66975 * 4, 4)
def test_apply_transformation(self): l = Lattice.cubic(4) s_orig = Structure(l, [{"Li": 0.19, "Na": 0.19, "K": 0.62}, {"O": 1}], [[0, 0, 0], [0.5, 0.5, 0.5]]) dot = DiscretizeOccupanciesTransformation(max_denominator=5, tol=0.5) s = dot.apply_transformation(s_orig) self.assertEqual(dict(s[0].species_and_occu), {Element("Li"): 0.2, Element("Na"): 0.2, Element("K"): 0.6}) dot = DiscretizeOccupanciesTransformation(max_denominator=5, tol=0.01) self.assertRaises(RuntimeError, dot.apply_transformation, s_orig) s_orig_2 = Structure(l, [{"Li": 0.5, "Na": 0.25, "K": 0.25}, {"O": 1}], [[0, 0, 0], [0.5, 0.5, 0.5]]) dot = DiscretizeOccupanciesTransformation(max_denominator=9, tol=0.25, fix_denominator=False) s = dot.apply_transformation(s_orig_2) self.assertEqual(dict(s[0].species_and_occu), {Element("Li"): Fraction(1/2), Element("Na"): Fraction(1/4), Element("K"): Fraction(1/4)}) dot = DiscretizeOccupanciesTransformation(max_denominator=9, tol=0.05, fix_denominator=True) self.assertRaises(RuntimeError, dot.apply_transformation, s_orig_2)
def test_aqueous_compat(self): el_li = Element("Li") el_o = Element("O") el_h = Element("H") latt = Lattice.from_parameters(3.565276, 3.565276, 4.384277, 90.000000, 90.000000, 90.000000) elts = [el_h, el_h, el_li, el_li, el_o, el_o] coords = [[0.000000, 0.500000, 0.413969], [0.500000, 0.000000, 0.586031], [0.000000, 0.000000, 0.000000], [0.500000, 0.500000, 0.000000], [0.000000, 0.500000, 0.192672], [0.500000, 0.000000, 0.807328]] struct = Structure(latt, elts, coords) lioh_entry = ComputedStructureEntry(struct, -3, parameters={'is_hubbard': False, 'hubbards': None, 'run_type': 'GGA', 'potcar_spec': [{'titel':'PAW_PBE Li 17Jan2003', 'hash': '65e83282d1707ec078c1012afbd05be8'}, {'titel': 'PAW_PBE O 08Apr2002', 'hash': '7a25bc5b9a5393f46600a4939d357982'}, {"titel": 'PAW_PBE H 15Jun2001', 'hash': "bb43c666e3d36577264afe07669e9582"}]}) lioh_entry_compat = self.compat.process_entry(lioh_entry) lioh_entry_compat_aqcorr = self.aqcorr.correct_entry(lioh_entry_compat) lioh_entry_aqcompat = self.aqcompat.process_entry(lioh_entry) self.assertAlmostEqual(lioh_entry_compat_aqcorr.energy, lioh_entry_aqcompat.energy, 4)
def test_get_mapping(self): sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=False, scale=True, attempt_supercell=False, allow_subset=True) l = Lattice.orthorhombic(1, 2, 3) s1 = Structure(l, ['Ag', 'Si', 'Si'], [[.7, .4, .5], [0, 0, 0.1], [0, 0, 0.2]]) s1.make_supercell([2, 1, 1]) s2 = Structure(l, ['Si', 'Si', 'Ag'], [[0, 0.1, -0.95], [0, 0.1, 0], [-.7, .5, .375]]) shuffle = [2, 0, 1, 3, 5, 4] s1 = Structure.from_sites([s1[i] for i in shuffle]) # test the mapping s2.make_supercell([2, 1, 1]) # equal sizes for i, x in enumerate(sm.get_mapping(s1, s2)): self.assertEqual(s1[x].species, s2[i].species) del s1[0] # s1 is subset of s2 for i, x in enumerate(sm.get_mapping(s2, s1)): self.assertEqual(s1[i].species, s2[x].species) # s2 is smaller than s1 del s2[0] del s2[1] self.assertRaises(ValueError, sm.get_mapping, s2, s1)
def test_apply_transformation(self): l = Lattice.cubic(4) s_orig = Structure(l, [{"Li": 0.19, "Na": 0.19, "K": 0.62}, {"O": 1}], [[0, 0, 0], [0.5, 0.5, 0.5]]) cct = ChargedCellTransformation(charge=3) s = cct.apply_transformation(s_orig) self.assertEqual(s.charge, 3)
def test_get_supercell_matrix(self): sm = StructureMatcher(ltol=0.1, stol=0.3, angle_tol=2, primitive_cell=False, scale=True, attempt_supercell=True) l = Lattice.orthorhombic(1, 2, 3) s1 = Structure(l, ['Si', 'Si', 'Ag'], [[0, 0, 0.1], [0, 0, 0.2], [.7, .4, .5]]) s1.make_supercell([2, 1, 1]) s2 = Structure(l, ['Si', 'Si', 'Ag'], [[0, 0.1, 0], [0, 0.1, -0.95], [-.7, .5, .375]]) result = sm.get_supercell_matrix(s1, s2) self.assertTrue((result == [[-2, 0, 0], [0, 1, 0], [0, 0, 1]]).all()) s1 = Structure(l, ['Si', 'Si', 'Ag'], [[0, 0, 0.1], [0, 0, 0.2], [.7, .4, .5]]) s1.make_supercell([[1, -1, 0], [0, 0, -1], [0, 1, 0]]) s2 = Structure(l, ['Si', 'Si', 'Ag'], [[0, 0.1, 0], [0, 0.1, -0.95], [-.7, .5, .375]]) result = sm.get_supercell_matrix(s1, s2) self.assertTrue((result == [[-1, -1, 0], [0, 0, -1], [0, 1, 0]]).all()) # test when the supercell is a subset sm = StructureMatcher(ltol=0.1, stol=0.3, angle_tol=2, primitive_cell=False, scale=True, attempt_supercell=True, allow_subset=True) del s1[0] result = sm.get_supercell_matrix(s1, s2) self.assertTrue((result == [[-1, -1, 0], [0, 0, -1], [0, 1, 0]]).all())
def test_process_entry_peroxide(self): latt = Lattice.from_parameters(3.159597, 3.159572, 7.685205, 89.999884, 89.999674, 60.000510) el_li = Element("Li") el_o = Element("O") elts = [el_li, el_li, el_li, el_li, el_o, el_o, el_o, el_o] coords = [[0.666656, 0.666705, 0.750001], [0.333342, 0.333378, 0.250001], [0.000001, 0.000041, 0.500001], [0.000001, 0.000021, 0.000001], [0.333347, 0.333332, 0.649191], [0.333322, 0.333353, 0.850803], [0.666666, 0.666686, 0.350813], [0.666665, 0.666684, 0.149189]] struct = Structure(latt, elts, coords) li2o2_entry = ComputedStructureEntry(struct, -3, parameters={'is_hubbard': False, 'hubbards': None, 'run_type': 'GGA', 'potcar_spec': [{'titel':'PAW_PBE Li 17Jan2003', 'hash': '9658a0ffb28da97ee7b36709966a0d1c'}, {'titel': 'PAW_PBE O 08Apr2002', 'hash': '7af704ddff29da5354831c4609f1cbc5'}]}) li2o2_entry_corrected = self.compat.process_entry(li2o2_entry) self.assertAlmostEqual(li2o2_entry_corrected.energy, -3 - 0.44317 * 4, 4)
def test_unique_structure_substitutions_in_two_steps_gives_full_degeneracies( self ): # integration test # Create a pymatgen structure with 16 sites in a 4x4 square grid coords = np.array( [ [ 0.0, 0.0, 0.0 ], [ 0.25, 0.0, 0.0 ], [ 0.5, 0., 0.0 ], [ 0.75, 0.0, 0.0 ], [ 0.0, 0.25, 0.0 ], [ 0.25, 0.25, 0.0 ], [ 0.5, 0.25, 0.0 ], [ 0.75, 0.25, 0.0 ], [ 0.0, 0.5, 0.0 ], [ 0.25, 0.5, 0.0 ], [ 0.5, 0.5, 0.0 ], [ 0.75, 0.5, 0.0 ], [ 0.0, 0.75, 0.0 ], [ 0.25, 0.75, 0.0 ], [ 0.5, 0.75, 0.0 ], [ 0.75, 0.75, 0.0 ] ] ) atom_list = [ 'Li' ] * len( coords ) lattice = Lattice.from_parameters( a = 3.0, b=3.0, c=3.0, alpha=90, beta=90, gamma=90 ) parent_structure = Structure( lattice, atom_list, coords ) us = unique_structure_substitutions( parent_structure, 'Li', { 'Na':1, 'Li':15 } ) ns = unique_structure_substitutions( us[0], 'Li', { 'Mg':1, 'Li':14 } ) self.assertEqual( len( ns ), 5 ) distances = np.array( sorted( [ s.get_distance( s.indices_from_symbol('Mg')[0], s.indices_from_symbol('Na')[0] ) for s in ns ] ) ) np.testing.assert_array_almost_equal( distances, np.array( [ 0.75 , 1.06066 , 1.5 , 1.677051, 2.12132 ] ) ) np.testing.assert_array_equal( np.array( sorted( [ s.number_of_equivalent_configurations for s in ns ] ) ), np.array( [ 1, 2, 4, 4, 4 ] ) ) np.testing.assert_array_equal( np.array( sorted( [ s.full_configuration_degeneracy for s in ns ] ) ), np.array( [ 16, 32, 64, 64, 64 ] ) )
def test_sulfide_type(self): # NaS2 -> polysulfide latt = Lattice.tetragonal(9.59650, 11.78850) species = ["Na"] * 2 + ["S"] * 2 coords = [[0.00000, 0.00000, 0.17000], [0.27600, 0.25000, 0.12500], [0.03400, 0.25000, 0.29600], [0.14700, 0.11600, 0.40000]] struct = Structure.from_spacegroup(122, latt, species, coords) self.assertEqual(sulfide_type(struct), "polysulfide") # NaCl type NaS -> sulfide latt = Lattice.cubic(5.75) species = ["Na", "S"] coords = [[0.00000, 0.00000, 0.00000], [0.50000, 0.50000, 0.50000]] struct = Structure.from_spacegroup(225, latt, species, coords) self.assertEqual(sulfide_type(struct), "sulfide") # Na2S2O3 -> None (sulfate) latt = Lattice.monoclinic(6.40100, 8.10000, 8.47400, 96.8800) species = ["Na"] * 2 + ["S"] * 2 + ["O"] * 3 coords = [[0.29706, 0.62396, 0.08575], [0.37673, 0.30411, 0.45416], [0.52324, 0.10651, 0.21126], [0.29660, -0.04671, 0.26607], [0.17577, 0.03720, 0.38049], [0.38604, -0.20144, 0.33624], [0.16248, -0.08546, 0.11608]] struct = Structure.from_spacegroup(14, latt, species, coords) self.assertEqual(sulfide_type(struct), None) # Na3PS3O -> sulfide latt = Lattice.orthorhombic(9.51050, 11.54630, 5.93230) species = ["Na"] * 2 + ["S"] * 2 + ["P", "O"] coords = [[0.19920, 0.11580, 0.24950], [0.00000, 0.36840, 0.29380], [0.32210, 0.36730, 0.22530], [0.50000, 0.11910, 0.27210], [0.50000, 0.29400, 0.35500], [0.50000, 0.30300, 0.61140]] struct = Structure.from_spacegroup(36, latt, species, coords) self.assertEqual(sulfide_type(struct), "sulfide") # test for unphysical cells struct.scale_lattice(struct.volume*10) self.assertEqual(sulfide_type(struct), "sulfide")
def test_max_disordered_sites(self): l = Lattice.cubic(4) s_orig = Structure(l, [{"Li": 0.2, "Na": 0.2, "K": 0.6}, {"O": 1}], [[0, 0, 0], [0.5, 0.5, 0.5]]) est = EnumerateStructureTransformation(max_cell_size=None, max_disordered_sites=5) s = est.apply_transformation(s_orig) self.assertEqual(len(s), 8)
def test_get_lattices(self): sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=True, scale=True, attempt_supercell=False) l1 = Lattice.from_lengths_and_angles([1, 2.1, 1.9], [90, 89, 91]) l2 = Lattice.from_lengths_and_angles([1.1, 2, 2], [89, 91, 90]) s1 = Structure(l1, [], []) s2 = Structure(l2, [], []) lattices = list(sm._get_lattices(s=s1, target_lattice=s2.lattice)) self.assertEqual(len(lattices), 16) l3 = Lattice.from_lengths_and_angles([1.1, 2, 20], [89, 91, 90]) s3 = Structure(l3, [], []) lattices = list(sm._get_lattices(s=s1, target_lattice=s3.lattice)) self.assertEqual(len(lattices), 0)
def test_out_of_cell_s2_like_s1(self): l = Lattice.cubic(5) s1 = Structure(l, ['Si', 'Ag', 'Si'], [[0,0,-0.02],[0,0,0.001],[.7,.4,.5]]) s2 = Structure(l, ['Si', 'Ag', 'Si'], [[0,0,0.98],[0,0,0.99],[.7,.4,.5]]) new_s2 = StructureMatcher(primitive_cell=False).get_s2_like_s1(s1, s2) dists = np.sum((s1.cart_coords - new_s2.cart_coords) ** 2, axis=-1) ** 0.5 self.assertLess(np.max(dists), 0.1)
def from_string(header_str): """ Reads Header string and returns Header object if header was generated by pymatgen. Note: Checks to see if generated by pymatgen, if not it is impossible to generate structure object so it is not possible to generate header object and routine ends Args: header_str: pymatgen generated feff.inp header Returns: Structure object. """ lines = tuple(clean_lines(header_str.split("\n"), False)) comment1 = lines[0] feffpmg = comment1.find("pymatgen") if feffpmg: comment2 = ' '.join(lines[1].split()[2:]) source = ' '.join(lines[2].split()[2:]) basis_vec = lines[6].split(":")[-1].split() # a, b, c a = float(basis_vec[0]) b = float(basis_vec[1]) c = float(basis_vec[2]) lengths = [a, b, c] # alpha, beta, gamma basis_ang = lines[7].split(":")[-1].split() alpha = float(basis_ang[0]) beta = float(basis_ang[1]) gamma = float(basis_ang[2]) angles = [alpha, beta, gamma] lattice = Lattice.from_lengths_and_angles(lengths, angles) natoms = int(lines[8].split(":")[-1].split()[0]) atomic_symbols = [] for i in range(9, 9 + natoms): atomic_symbols.append(lines[i].split()[2]) # read the atomic coordinates coords = [] for i in range(natoms): toks = lines[i + 9].split() coords.append([float(s) for s in toks[3:]]) struct = Structure(lattice, atomic_symbols, coords, False, False, False) h = Header(struct, source, comment2) return h else: return "Header not generated by pymatgen, cannot return header object"
def test_max_disordered_sites(self): l = Lattice.cubic(4) s_orig = Structure(l, [{"Li": 0.2, "Na": 0.2, "K": 0.6}, {"O": 1}], [[0, 0, 0], [0.5, 0.5, 0.5]]) est = EnumerateStructureTransformation(max_cell_size=None, max_disordered_sites=5) dd = est.apply_transformation(s_orig, return_ranked_list=100) self.assertEqual(len(dd), 9) for d in dd: self.assertEqual(len(d["structure"]), 10)
def test_get_supercells(self): sm = StructureMatcher(comparator=ElementComparator()) l = Lattice.cubic(1) l2 = Lattice.cubic(0.5) s1 = Structure(l, ['Mg', 'Cu', 'Ag', 'Cu'], [[0] * 3] * 4) s2 = Structure(l2, ['Cu', 'Cu', 'Ag'], [[0] * 3] * 3) scs = list(sm._get_supercells(s1, s2, 8, False)) for x in scs: self.assertAlmostEqual(abs(np.linalg.det(x[3])), 8) self.assertEqual(len(x[0]), 4) self.assertEqual(len(x[1]), 24) self.assertEqual(len(scs), 48) scs = list(sm._get_supercells(s2, s1, 8, True)) for x in scs: self.assertAlmostEqual(abs(np.linalg.det(x[3])), 8) self.assertEqual(len(x[0]), 24) self.assertEqual(len(x[1]), 4) self.assertEqual(len(scs), 48)
def test_get_s2_large_s2(self): sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=False, scale=False, attempt_supercell=True, allow_subset=False, supercell_size='volume') l = Lattice.orthorhombic(1, 2, 3) s1 = Structure(l, ['Ag', 'Si', 'Si'], [[.7, .4, .5], [0, 0, 0.1], [0, 0, 0.2]]) l2 = Lattice.orthorhombic(1.01, 2.01, 3.01) s2 = Structure(l2, ['Si', 'Si', 'Ag'], [[0, 0.1, -0.95], [0, 0.1, 0], [-.7, .5, .375]]) s2.make_supercell([[0, -1, 0], [1, 0, 0], [0, 0, 1]]) result = sm.get_s2_like_s1(s1, s2) for x, y in zip(s1, result): self.assertLess(x.distance(y), 0.08)
def test_nelect(self): coords = [[0]*3, [0.5]*3, [0.75]*3] lattice = Lattice.cubic(4) s = Structure(lattice, ['Si', 'Si', 'Fe'], coords) self.assertAlmostEqual(MITRelaxSet(s).nelect, 16) # Check that it works even when oxidation states are present. Was a bug # previously. s = Structure(lattice, ['Si4+', 'Si4+', 'Fe2+'], coords) self.assertAlmostEqual(MITRelaxSet(s).nelect, 16) self.assertAlmostEqual(MPRelaxSet(s).nelect, 22)
def test_get_mask(self): sm = StructureMatcher(comparator=ElementComparator()) l = Lattice.cubic(1) s1 = Structure(l, ['Mg', 'Cu', 'Ag', 'Cu'], [[0] * 3] * 4) s2 = Structure(l, ['Cu', 'Cu', 'Ag'], [[0] * 3] * 3) result = [[True, False, True, False], [True, False, True, False], [True, True, False, True]] m, inds, i = sm._get_mask(s1, s2, 1, True) self.assertTrue(np.all(m == result)) self.assertTrue(i == 2) self.assertEqual(inds, [2]) # test supercell with match result = [[1, 1, 0, 0, 1, 1, 0, 0], [1, 1, 0, 0, 1, 1, 0, 0], [1, 1, 1, 1, 0, 0, 1, 1]] m, inds, i = sm._get_mask(s1, s2, 2, True) self.assertTrue(np.all(m == result)) self.assertTrue(i == 2) self.assertTrue(np.allclose(inds, np.array([4]))) # test supercell without match result = [[1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 1], [1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 1, 1]] m, inds, i = sm._get_mask(s2, s1, 2, True) self.assertTrue(np.all(m == result)) self.assertTrue(i == 0) self.assertTrue(np.allclose(inds, np.array([]))) # test s2_supercell result = [[1, 1, 1], [1, 1, 1], [0, 0, 1], [0, 0, 1], [1, 1, 0], [1, 1, 0], [0, 0, 1], [0, 0, 1]] m, inds, i = sm._get_mask(s2, s1, 2, False) self.assertTrue(np.all(m == result)) self.assertTrue(i == 0) self.assertTrue(np.allclose(inds, np.array([]))) # test for multiple translation indices s1 = Structure(l, ['Cu', 'Ag', 'Cu', 'Ag', 'Ag'], [[0] * 3] * 5) s2 = Structure(l, ['Ag', 'Cu', 'Ag'], [[0] * 3] * 3) result = [[1, 0, 1, 0, 0], [0, 1, 0, 1, 1], [1, 0, 1, 0, 0]] m, inds, i = sm._get_mask(s1, s2, 1, True) self.assertTrue(np.all(m == result)) self.assertTrue(i == 1) self.assertTrue(np.allclose(inds, [0, 2]))
def build_gb(self, vacuum=0.0, add_if_dist=0.0, to_primitive=True, delete_layer="0b0t0b0t", tol=0.25): """ Build the GB based on the given crystal, uc of grain A and B, if_model, vacuum thickness, distance between two grains and tolerance factor. Args: vacuum (float), Angstrom: Vacuum thickness for GB. Default to 0.0 add_if_dist (float), Angstrom: Add extra distance at the interface between two grains. Default to 0.0 to_primitive (bool): Whether to get primitive structure of GB. Default to true. delete_layer (str): Delete interface layers on both sides of each grain. 8 characters in total. The first 4 characters is for grain A and the other 4 is for grain B. "b" means bottom layer and "t" means top layer. Integer represents the number of layers to be deleted. Default to "0b0t0b0t", which means no deletion of layers. The direction of top and bottom layers is based on gb_direction. tol (float), Angstrom: Tolerance factor to determine whether two atoms are at the same plane. Default to 0.25 Returns: GB structure (Grain) """ ind = self.gb_direction delete_layer = delete_layer.lower() delete = re.findall('(\d+)(\w)', delete_layer) if len(delete) != 4: raise ValueError( "'%s' is not supported. Please make sure the format " "is 0b0t0b0t.") for i, v in enumerate(delete): for j in range(int(v[0])): if i <= 1: self.grain_a.delete_bt_layer(v[1], tol, ind) else: self.grain_b.delete_bt_layer(v[1], tol, ind) abc_a = list(self.grain_a.lattice.abc) abc_b, angles = self.grain_b.lattice.lengths_and_angles if ind == 1: l = (abc_a[ind] + add_if_dist) * sin(radians(angles[2])) else: l = abc_a[ind] + add_if_dist abc_a[ind] += abc_b[ind] + 2 * add_if_dist + vacuum new_lat = Lattice.from_lengths_and_angles(abc_a, angles) a_fcoords = new_lat.get_fractional_coords(self.grain_a.cart_coords) grain_a = Grain(new_lat, self.grain_a.species, a_fcoords) l_vector = [0, 0] l_vector.insert(ind, l) b_fcoords = new_lat.get_fractional_coords(self.grain_b.cart_coords + l_vector) grain_b = Grain(new_lat, self.grain_b.species, b_fcoords) gb = Grain.from_sites(grain_a[:] + grain_b[:]) gb = gb.get_sorted_structure() if to_primitive: gb = gb.get_primitive_structure() return gb
def get_dipole_in_basis(dipole, basis_dipole, basis_new): return np.dot(np.array(basis_new).T, np.dot(basis_dipole, dipole)) def print_xyz(coordinates, symbols): print('{}\n'.format(len(coordinates))) for s, c in zip(symbols, coordinates): print('{:3}'.format(s) + '{:10.5f} {:10.5f} {:10.5f}'.format(*c)) # define lattice lattice = Lattice.from_parameters(a=7.6778, b=5.7210, c=8.395, alpha=90.0, beta=124.55, gamma=90.0) #import csv #with open('molecules.csv', newline='') as csvfile: # spamreader = csv.DictReader(csvfile, delimiter=',') # scaled_coord = [] # for row in spamreader: # scaled_coord.append([float(row['Xfrac + ESD'].split('(')[0]), float(row['Yfrac + ESD'].split('(')[0]), float(row['Zfrac + ESD'].split('(')[0])]) # #print(np.array(scaled_coord)) # coordinates of the molecules in scaled coordinates (10 molecules) scaled_coord = [[0.0842, 0.0203, 0.3373], [0.1272, 0.063, 0.4615], [0.1147, 0.1718, 0.228], [0.179, 0.3157, 0.2791],
# Calculation the Elastic Constants from given deformations import os import subprocess from pymatgen import Structure, Lattice, Specie from pymatgen.analysis.elasticity import DeformedStructureSet, Strain, Stress, ElasticTensor from pmg_lammps import RelaxSet, LammpsLog, LammpsData, LammpsPotentials supercell = (5, 5, 5) a = 4.1990858 # From evaluation of potential lattice = Lattice.from_parameters(a, a, a, 90, 90, 90) mg = Specie('Mg', 1.4) o = Specie('O', -1.4) atoms = [mg, o] sites = [[0, 0, 0], [0.5, 0.5, 0.5]] structure = Structure.from_spacegroup(225, lattice, atoms, sites) initial_structure = structure * supercell directory = 'runs/elastic' num_normal = 10 num_shear = 10 max_normal = 0.03 max_shear = 0.08 lammps_potentials = LammpsPotentials( pair={ (mg, mg): '1309362.2766468062 0.104 0.0', (mg, o): '9892.357 0.20199 0.0', (o, o): '2145.7345 0.3 30.2222' })
def elongated_tetragonal(): lattice = Lattice.tetragonal(a=1, c=3 * sqrt(2)) coords = [[0.0, 0.0, 0.0]] return IStructure(lattice=lattice, species=["H"], coords=coords)
def monoclinic(): lattice = Lattice.monoclinic(3, 4, 5, 100) coords = [[0.0, 0.0, 0.0]] return IStructure(lattice=lattice, species=["H"], coords=coords)
def read_poscar(poscar_path): lattice = Lattice.cubic(4.2) struct_temp = Structure(lattice, ["Cs", "Cl"],[[0, 0, 0], [0.5, 0.5, 0.5]]) poscar = Poscar(struct_temp).from_file(poscar_path,check_for_POTCAR=False) struct = poscar.structure return struct
def c_centered_monoclinic(): lattice = Lattice.monoclinic(3, 4, 5, 100) coords = [[0.0, 0.0, 0.0], [0.5, 0.5, 0.0]] return IStructure(lattice=lattice, species=["H", "H"], coords=coords)
def setUp(self): self.s1 = Structure.from_spacegroup(225, Lattice.cubic(5.69169), ["Na", "Cl"], [[0, 0, 0], [0, 0, 0.5]]) self.s2 = Structure.from_dict( { "@class": "Structure", "@module": "pymatgen.core.structure", "charge": None, "lattice": { "a": 5.488739045730133, "alpha": 60.0000000484055, "b": 5.488739048031658, "beta": 60.00000003453459, "c": 5.48873905, "gamma": 60.000000071689925, "matrix": [ [4.75338745, 0.0, 2.74436952], [1.58446248, 4.48153667, 2.74436952], [0.0, 0.0, 5.48873905], ], "volume": 116.92375473740876, }, "sites": [ { "abc": [0.5, 0.5, 0.5], "label": "Al", "properties": {"coordination_no": 10, "forces": [0.0, 0.0, 0.0]}, "species": [{"element": "Al", "occu": 1}], "xyz": [3.168924965, 2.240768335, 5.488739045], }, { "abc": [0.5, 0.5, 0.0], "label": "Al", "properties": {"coordination_no": 10, "forces": [0.0, 0.0, 0.0]}, "species": [{"element": "Al", "occu": 1}], "xyz": [3.168924965, 2.240768335, 2.74436952], }, { "abc": [0.0, 0.5, 0.5], "label": "Al", "properties": {"coordination_no": 10, "forces": [0.0, 0.0, 0.0]}, "species": [{"element": "Al", "occu": 1}], "xyz": [0.79223124, 2.240768335, 4.116554285], }, { "abc": [0.5, 0.0, 0.5], "label": "Al", "properties": {"coordination_no": 10, "forces": [0.0, 0.0, 0.0]}, "species": [{"element": "Al", "occu": 1}], "xyz": [2.376693725, 0.0, 4.116554285], }, { "abc": [0.875, 0.875, 0.875], "label": "Lu", "properties": {"coordination_no": 16, "forces": [0.0, 0.0, 0.0]}, "species": [{"element": "Lu", "occu": 1}], "xyz": [5.54561868875, 3.9213445862499996, 9.60529332875], }, { "abc": [0.125, 0.125, 0.125], "label": "Lu", "properties": {"coordination_no": 16, "forces": [0.0, 0.0, 0.0]}, "species": [{"element": "Lu", "occu": 1}], "xyz": [0.79223124125, 0.56019208375, 1.37218476125], }, ], } )
fws.append( FireWork([VaspToDBTaskEx()], spec, name=get_name(structure, spec['task_type']), fw_id=2)) connections[1] = [2] # 3rd FireWork - static run. # VaspCopyTask - copy output from previous run to this directory # SetupStaticRunTask - override old parameters for static run # CustodianTaskEx - run VASP within a custodian spec = {'task_type': 'GGA static example'} copytask = VaspCopyTask({'use_CONTCAR': True, 'skip_CHGCAR': True}) setuptask = SetupStaticRunTask() custodiantask = VaspCustodianTaskEx({'jobs': [VaspJob('', auto_npar=False).to_dict], 'handlers': [h.to_dict for h in handlers], 'max_errors': 5}) fws.append(FireWork([copytask, setuptask, custodiantask], spec, name=get_name(structure, spec['task_type']), fw_id=3)) connections[2] = [3] # 4th FireWork - insert previous run into DB spec = {'task_type': 'VASP db insertion example'} fws.append( FireWork([VaspToDBTaskEx()], spec, name=get_name(structure, spec['task_type']), fw_id=4)) connections[3] = [4] return Workflow(fws, connections, name=get_slug(structure.formula)) if __name__ == '__main__': l = Lattice.from_parameters(3.866, 3.866, 3.866, 60, 60, 60) s = Structure(l, ['Si', 'Si'], [[0.125,0.125,0.125], [0.875,0.875,0.875]]) my_wf = structure_to_wf(s) pprint(my_wf.to_dict(), indent=2) my_wf.to_file("Si_wf.json")
def EF_H2O_wannier(structure_in, core_charges, verbose=True): #-# from copy import deepcopy from ase.neighborlist import NeighborList from ase import Atom, Atoms from pymatgen import Lattice, Structure from pymatgen.analysis import ewald structure = deepcopy(structure_in) index_Ow = get_indexes_Ow(structure) if "WANNIER_xyz" in structure.row.data.keys(): nwannier = len(structure.row.data["WANNIER_xyz"]) structure.extend( Atoms(symbols="W" * nwannier, positions=structure.row.data["WANNIER_xyz"], cell=structure.get_cell())) else: print("ERROR: Missing WANNIER_xyz") sys.exit() nl = NeighborList([1.2 / 2] * len(structure), skin=0, self_interaction=False, bothways=True) nl.update(structure) indexH = [ i for i, x in enumerate(structure.get_chemical_symbols()) if x == 'H' ] # H indexes indexW = [ i for i, x in enumerate(structure.get_chemical_symbols()) if x == 'W' ] # W indexes # Run Ewald print("Running Ewald ...") lattice = Lattice(structure.get_cell()) coords = structure.get_scaled_positions() structure.charges = [ core_charges[x] for x in structure.get_chemical_symbols() ] struct = Structure(lattice, structure.get_chemical_symbols(), coords, site_properties={"charge": structure.charges}) Ew = ewald.EwaldSummation(struct, compute_forces=True) print("Done") for iOw in index_Ow: print(" Ow idx:", iOw) print("=" * 50) vCENTER = ( structure.get_cell()[0] + structure.get_cell()[1] + structure.get_cell()[2] ) / 2. # get translation vector to put the O in the center of the box structure.translate(-structure.get_positions()[iOw] + vCENTER) # center the O in the box structure.set_scaled_positions( structure.get_scaled_positions()) # put back everything in the box neighbors = nl.get_neighbors(iOw)[0] indexH_loc = np.intersect1d(neighbors, indexH) vOH1 = structure.get_positions()[ indexH_loc[0]] - structure.get_positions()[iOw] vOH2 = structure.get_positions()[ indexH_loc[1]] - structure.get_positions()[iOw] vMid = (vOH1 / np.linalg.norm(vOH1) + vOH2 / np.linalg.norm(vOH2)) vMid = vMid / np.linalg.norm(vMid) for j in indexH_loc: vOH = structure.get_positions()[j] - structure.get_positions()[iOw] uOH = vOH / np.linalg.norm(vOH) OH = structure.get_distance(iOw, j, mic=True) # Total EF at H position EF_H = Ew.forces[j] / structure.charges[j] * eV_a2au print( " {:>2}{:<4}{:>2}{:<4} dist: {:.6f} chg{:<4} {:7.4f}".format( structure.get_chemical_symbols()[j], j, structure.get_chemical_symbols()[j], j, 0, j, structure.charges[j])) # O contribution at the H EF_OatH = structure.charges[iOw] / (4. * np.pi * e0 * (OH)**2) * (vOH / OH) * eV_a2au # Contribution from the other H indexHother = np.setdiff1d(indexH_loc, j) # the index of the other H vHH = structure.get_positions()[j] - structure.get_positions()[ indexHother[0]] HH = structure.get_distance(indexHother[0], j, mic=True) EF_HatH = structure.charges[indexHother[0]] / ( 4. * np.pi * e0 * (HH)**2) * (vHH / HH) * eV_a2au print( " {:>2}{:<4}{:>2}{:<4} dist: {:.6f} chg{:<4} {:7.4f}".format( structure.get_chemical_symbols()[j], j, structure.get_chemical_symbols()[indexHother[0]], indexHother[0], HH, indexHother[0], structure.charges[indexHother[0]])) EF_H = EF_H - EF_OatH - EF_HatH # Wannier centers indexW_loc = np.intersect1d(neighbors, indexW) for k in indexW_loc: vXH = structure.get_positions()[j] - structure.get_positions( )[k] XH = structure.get_distance(j, k, mic=True) print(" {:>2}{:<4}{:>2}{:<4} dist: {:.6f} chg{:<4} {:7.4f}". format(structure.get_chemical_symbols()[j], j, structure.get_chemical_symbols()[k], k, XH, k, structure.charges[k])) EF_XatH = structure.charges[k] / (4. * np.pi * e0 * (XH)**2) * (vXH / XH) * eV_a2au EF_H = EF_H - EF_XatH print("-" * 50) print(" H{0:<4} rOH= {1:9.6f} EF@H_along_bisector= {2:3f} a.u.". format(j, OH, np.dot(EF_H, vMid))) print(" EF@H_along_OH_bond= {0:3f} a.u.\n". format(np.dot(EF_H, uOH)))
def setUp(self): ## simple toy structure for preliminary testing self.a0 = 3.0 self.c = 20.0 self.structure = Structure( Lattice.from_parameters(a=self.a0, b=self.a0, c=self.c, alpha=90, beta=90, gamma=90), ["O", "O"], [[0.0, 0.0, 0.1], [0.5, 0.5, 0.3]]) self.nvecs = [3, 3, 1] self.vacuum = 20 self.q = 0 self.structure.make_supercell(self.nvecs) self.structure_bulk = self.structure.copy() self.initdef_list = [] self.initdef_list.append( {"def1": { "type": "vac", "species": "O", "index": 0 }}) self.initdef_list.append({ "def1": { "type": "sub", "index": -1, "species": "O", "species_new": "N" } }) self.initdef_list.append({ "def1": { "type": "sub", "index": -1, "species": "O", "species_new": "N" }, "def2": { "type": "vac", "index": -1, "species": "O", "index_offset_n1n2": -1 } }) self.initdef_list.append({ "def1": { "type": "ad", "index": [-1], "species": ["O"], "species_new": "N", "shift_z": "3.0" } }) self.initdef_list.append({ "def1": { "type": "int", "index": [0, 0, 0, 0], "index_offset_n1": [0, 1, 0, 0], "index_offset_n2": [0, 0, 0, 2], "index_offset_n1n2": [0, 0, 1, 1], "species": 4 * ["O"], "species_new": "N" } }) self.create_defects() self.siteinds_list = [[0], [17], [17, 8], [[17]], [[0, 3, 9, 11]]] self.defcoords_list = [[[0.0, 0.0, 0.1]], [[0.833333, 0.833333, 0.3]], [[0.833333, 0.833333, 0.3], [0.666667, 0.666667, 0.1]], [[0.833333, 0.833333, 0.45]], [[0.166667, 0.0, 0.2]]] self.natoms_list = [17, 18, 17, 19, 19]
def test_get_nelect(self): coords = [[0] * 3, [0.5] * 3, [0.75] * 3] lattice = Lattice.cubic(4) s = Structure(lattice, ['Si', 'Si', 'Fe'], coords) self.assertAlmostEqual(MITVaspInputSet().get_nelect(s), 16)
def test_oxide_type(self): el_li = Element("Li") el_o = Element("O") latt = Lattice( [[3.985034, 0.0, 0.0], [0.0, 4.881506, 0.0], [0.0, 0.0, 2.959824]] ) elts = [el_li, el_li, el_o, el_o, el_o, el_o] coords = list() coords.append([0.500000, 0.500000, 0.500000]) coords.append([0.0, 0.0, 0.0]) coords.append([0.632568, 0.085090, 0.500000]) coords.append([0.367432, 0.914910, 0.500000]) coords.append([0.132568, 0.414910, 0.000000]) coords.append([0.867432, 0.585090, 0.000000]) struct = Structure(latt, elts, coords) self.assertEqual(oxide_type(struct, 1.1), "superoxide") el_li = Element("Li") el_o = Element("O") elts = [el_li, el_o, el_o, el_o] latt = Lattice.from_parameters( 3.999911, 3.999911, 3.999911, 133.847504, 102.228244, 95.477342 ) coords = [ [0.513004, 0.513004, 1.000000], [0.017616, 0.017616, 0.000000], [0.649993, 0.874790, 0.775203], [0.099587, 0.874790, 0.224797], ] struct = Structure(latt, elts, coords) self.assertEqual(oxide_type(struct, 1.1), "ozonide") latt = Lattice.from_parameters( 3.159597, 3.159572, 7.685205, 89.999884, 89.999674, 60.000510 ) el_li = Element("Li") el_o = Element("O") elts = [el_li, el_li, el_li, el_li, el_o, el_o, el_o, el_o] coords = [ [0.666656, 0.666705, 0.750001], [0.333342, 0.333378, 0.250001], [0.000001, 0.000041, 0.500001], [0.000001, 0.000021, 0.000001], [0.333347, 0.333332, 0.649191], [0.333322, 0.333353, 0.850803], [0.666666, 0.666686, 0.350813], [0.666665, 0.666684, 0.149189], ] struct = Structure(latt, elts, coords) self.assertEqual(oxide_type(struct, 1.1), "peroxide") el_li = Element("Li") el_o = Element("O") el_h = Element("H") latt = Lattice.from_parameters( 3.565276, 3.565276, 4.384277, 90.000000, 90.000000, 90.000000 ) elts = [el_h, el_h, el_li, el_li, el_o, el_o] coords = [ [0.000000, 0.500000, 0.413969], [0.500000, 0.000000, 0.586031], [0.000000, 0.000000, 0.000000], [0.500000, 0.500000, 0.000000], [0.000000, 0.500000, 0.192672], [0.500000, 0.000000, 0.807328], ] struct = Structure(latt, elts, coords) self.assertEqual(oxide_type(struct, 1.1), "hydroxide") el_li = Element("Li") el_n = Element("N") el_h = Element("H") latt = Lattice.from_parameters( 3.565276, 3.565276, 4.384277, 90.000000, 90.000000, 90.000000 ) elts = [el_h, el_h, el_li, el_li, el_n, el_n] coords = [ [0.000000, 0.500000, 0.413969], [0.500000, 0.000000, 0.586031], [0.000000, 0.000000, 0.000000], [0.500000, 0.500000, 0.000000], [0.000000, 0.500000, 0.192672], [0.500000, 0.000000, 0.807328], ] struct = Structure(latt, elts, coords) self.assertEqual(oxide_type(struct, 1.1), "None") el_o = Element("O") latt = Lattice.from_parameters( 4.389828, 5.369789, 5.369789, 70.786622, 69.244828, 69.244828 ) elts = [el_o, el_o, el_o, el_o, el_o, el_o, el_o, el_o] coords = [ [0.844609, 0.273459, 0.786089], [0.155391, 0.213911, 0.726541], [0.155391, 0.726541, 0.213911], [0.844609, 0.786089, 0.273459], [0.821680, 0.207748, 0.207748], [0.178320, 0.792252, 0.792252], [0.132641, 0.148222, 0.148222], [0.867359, 0.851778, 0.851778], ] struct = Structure(latt, elts, coords) self.assertEqual(oxide_type(struct, 1.1), "None")
def setUp(self): self.lattice = Lattice.cubic(10.0) self.kpoint = Kpoint([0.1, 0.4, -0.5], self.lattice, label="X")
def _parse(self): float_patt = re.compile(r"[+-]?\d+\.\d+[EFD]?[+-]?\d+") # -9.3892E+02 start_patt = re.compile(r"^\s*EEEEEEEEEE STARTING DATE \d+") coord_patt = re.compile( r"^\s+(\d+)\s+(?P<aunit>[TF])\s+(?P<Z>\d+)\s+" r"(?P<specie>\w+)\s+(?P<x>[+-]?\d+\.\d+E[+-]?\d+)" r"\s+(?P<y>[+-]?\d+\.\d+E[+-]?\d+)\s+" r"(?P<z>[+-]?\d+\.\d+E[+-]?\d+)") coord_nanotube_patt = re.compile( r"^\s+(\d+)\s+(?P<aunit>[TF])\s+(?P<Z>\d+)\s+" r"(?P<specie>\w+)\s+(?P<x>[+-]?\d+\.\d+E[+-]?\d+)" r"\s+(?P<y>[+-]?\d+\.\d+E[+-]?\d+)\s+" r"(?P<z>[+-]?\d+\.\d+E[+-]?\d+)\s+" r"(?P<radius>\d+\.\d+)") forces_patt = re.compile(r"^\s+(?P<iat>\d+)\s+(?P<Z>\d+)\s+" r"(?P<x>[+-]?\d+\.\d+E[+-]?\d+)\s+" r"(?P<y>[+-]?\d+\.\d+E[+-]?\d+)\s+" r"(?P<z>[+-]?\d+\.\d+E[+-]?\d+)") max_grad_patt = re.compile( r"^\sMAX GRADIENT\s+(?P<max_grad>\d+\.\d+)" r"\s+THRESHOLD\s+(?P<max_grad_thr>\d+\.\d+)") rms_grad_patt = re.compile( r"^\sRMS GRADIENT\s+(?P<rms_grad>\d+\.\d+)" r"\s+THRESHOLD\s+(?P<rms_grad_thr>\d+\.\d+)") max_displac_patt = re.compile( r"^\sMAX DISPLAC\.\s+(?P<max_displac>\d+\.\d+)" r"\s+THRESHOLD\s+(?P<max_displac_thr>\d+\.\d+)") rms_displac_patt = re.compile( r"^\sRMS DISPLAC\.\s+(?P<rms_displac>\d+\.\d+)" r"\s+THRESHOLD\s+(?P<rms_displac_thr>\d+\.\d+)") norm_grad_patt = re.compile( r"^\s+GRADIENT NORM\s+(?P<norm_grad>\d+\.\d+)" r"\s+GRADIENT THRESHOLD\s+(?P<norm_grad_thr>\d+\.\d+)") self.title = "" self.system = "" self.group = "" self.slab = False self.nanotube = False self.volumes = list() self.energies = list() self.forces = list() self.convergence_data = list() self.geometry_converge = False self.scf_converge = False external_geometry = False with open(self.filename, "r", encoding=self.encoding) as f: # look for starting message for line in f: if start_patt.match(line): self.title = f.readline().strip() break # ------------------------------------------------------------------ # first, read the initial geometry & identify the type of structure # ------------------------------------------------------------------ for line in f: if re.match(r"^\sGEOMETRY INPUT FROM EXTERNAL FILE", line): external_geometry = True line = f.readline() if "SLAB" in line: self.slab = True if "NANOTUBE" in line: self.nanotube = True print("WARNING: Geometry from an external file.") break if re.match(r"^\sSLAB CALCULATION", line): self.slab = True system_patt = re.compile(r"^\sSYSTEM AND LATTICE") group_patt = re.compile(r" PLANE GROUP N.") break if re.match(r"^\sCRYSTAL CALCULATION", line): system_patt = re.compile(r"^\sCRYSTAL FAMILY") group_patt = re.compile(r"^\sSPACE GROUP") break # look for initial geometry: GEOMETRY FOR WAVEFUNCTION # read group and crystallographic system # check if a SLAB or NANOTUBE is built by GEOMETRY EDITING geom_for_wf = False for line in f: if not external_geometry and system_patt.search(line): self.system = line.split(":")[1].strip() if not external_geometry and group_patt.search(line): self.group = line.split(":")[1].strip() if " SLAB GENERATED " in line: self.slab = True # group and system no more relevant self.group = "" self.system = "" if "CONSTRUCTION OF A NANOTUBE FROM A SLAB" in line: self.nanotube = True self.slab = False # group and system no more relevant self.group = "" self.system = "" if re.match(r"^\sGEOMETRY FOR WAVE FUNCTION", line): geom_for_wf = True break if line == "": # end of file, geometry for wavefunction not found break if not geom_for_wf: # STOP case, add TESTGEOM to d12 raise ValueError("GEOMETRY FOR WAVEFUNCTION NOT FOUND.\n" "Please, add TESTGEOM in the d12 input file.") # read until calculation start # read starting geometry and look for PRIMITIVE or CRYSTALLOGRAPHIC read_geom = False while "CRYSTAL - SCF - TYPE OF CALCULATION" not in line: line = f.readline() if line == "": raise ValueError("End of file.") # search PRIMITIVE CELL if re.match(r"^\sPRIMITIVE CELL", line): read_geom = True geom_patt = re.compile(r"^\sPRIMITIVE CELL") # search CRYSTALLOGRAPHIC CELL if exist if re.match(r"^\sCRYSTALLOGRAPHIC CELL", line): read_geom = True geom_patt = re.compile(r"^\sCRYSTALLOGRAPHIC CELL") if read_geom: if not self.slab and not self.nanotube: volume = float( line.split("=")[1].split()[0].strip(")")) self.volumes.append(volume) f.readline() # lattice parameters line = f.readline() params = [ float(val) for val in re.findall(r"\d+\.\d+", line) ] lattice = Lattice.from_lengths_and_angles( params[0:3], params[3:]) # step on for 4 lines [f.readline() for _ in range(4)] # read coordinates species = list() # atom names uniq = list() # True if atom belong to the asymmetric unit radius = list() # distance from the axes of the nanotube coords = list() while line != "\n": read = False line = f.readline() if self.nanotube and coord_nanotube_patt.match(line): data = coord_nanotube_patt.match(line).groupdict() read = True elif coord_patt.match(line): data = coord_patt.match(line).groupdict() read = True if read: specie = data["specie"] specie = specie if len( specie ) == 1 else specie[0] + specie[1].lower() species.append(specie) coord = [float(data[k]) for k in "xyz"] uniq.append(True if data["aunit"] == "T" else False) if self.slab: coord[2] /= lattice.c elif self.nanotube: coord[1] /= lattice.b coord[2] /= lattice.c radius.append(float(data["radius"])) coords.append(coord) self.structures = [ Structure(lattice, species, coords, site_properties={"aunit": uniq}) ] read_geom = False # ------------------------------------------------------------------ # from that point, SCF, or structure optimization start ! # continue up to the end of file # ------------------------------------------------------------------ n_geom = 0 cvg_data = dict() while line != "": line = f.readline() if " TOTAL ENERGY" in line: self.energies.append(float(float_patt.findall(line)[0])) self.scf_converge = True if "CARTESIAN FORCES IN HARTREE/BOHR" in line: # WARNING: Forces are not printed at each geom step line = f.readline() forces = list() for _ in range(self.initial_structure.num_sites): data = forces_patt.match(f.readline()).groupdict() forces.append([float(data[c]) for c in "xyz"]) self.forces.append(np.array(forces)) if max_grad_patt.match(line): cvg_data.update(max_grad_patt.match(line).groupdict()) if rms_grad_patt.match(line): cvg_data.update(rms_grad_patt.match(line).groupdict()) if max_displac_patt.match(line): cvg_data.update(max_displac_patt.match(line).groupdict()) if rms_displac_patt.match(line): cvg_data.update(rms_displac_patt.match(line).groupdict()) if norm_grad_patt.match(line): cvg_data.update(norm_grad_patt.match(line).groupdict()) if line == "": # end of file ? break if "COORDINATE AND CELL OPTIMIZATION" in line: cvg_data = {k: float(v) for k, v in cvg_data.items()} # end of optimization cycle self.convergence_data.append(cvg_data) n_geom += 1 cvg_data = dict() if "FINAL OPTIMIZED GEOMETRY" in line: self.geometry_converge = True n_geom += 1 # search structure data if geom_patt.match(line): # PRIMITVE or CRYSTALLOGRAPHIC depending on what is present read_geom = True if read_geom: if not self.slab and not self.nanotube: volume = float( line.split("=")[1].split()[0].strip(")")) self.volumes.append(volume) f.readline() # lattice parameters line = f.readline() params = [ float(val) for val in re.findall(r"\d+\.\d+", line) ] lattice = Lattice.from_lengths_and_angles( params[0:3], params[3:]) # step on for 4 lines [f.readline() for _ in range(4)] # read coordinates species = list() # atom names uniq = list() # True if atom belong to the asymmetric unit radius = list() # distance from the axes of the nanotube coords = list() while line != "\n": read = False line = f.readline() if self.nanotube and coord_nanotube_patt.match(line): data = coord_nanotube_patt.match(line).groupdict() read = True elif coord_patt.match(line): data = coord_patt.match(line).groupdict() read = True if read: specie = data["specie"] specie = specie if len( specie ) == 1 else specie[0] + specie[1].lower() species.append(specie) coord = [float(data[k]) for k in "xyz"] uniq.append(True if data["aunit"] == "T" else False) if self.slab: coord[2] /= lattice.c elif self.nanotube: coord[1] /= lattice.b coord[2] /= lattice.c radius.append(float(data["radius"])) coords.append(coord) self.structures.append( Structure(lattice, species, coords, site_properties={"aunit": uniq})) read_geom = False
def test_specie_cifwriter(self): si4 = Specie("Si", 4) si3 = Specie("Si", 3) n = Specie("N", -3) coords = list() coords.append(np.array([0, 0, 0])) coords.append(np.array([0.75, 0.5, 0.75])) coords.append(np.array([0.5, 0.5, 0.5])) 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, [si4, {si3: 0.5, n: 0.5}, n], coords) writer = CifWriter(struct) ans = """#\#CIF1.1 ########################################################################## # Crystallographic Information Format file # Produced by PyCifRW module # # This is a CIF file. CIF has been adopted by the International # Union of Crystallography as the standard for data archiving and # transmission. # # For information on this file format, follow the CIF links at # http://www.iucr.org ########################################################################## data_Si1.5N1.5 _symmetry_space_group_name_H-M 'P 1' _cell_length_a 3.8401979337 _cell_length_b 3.84019899434 _cell_length_c 3.84019793372 _cell_angle_alpha 119.999990864 _cell_angle_beta 90.0 _cell_angle_gamma 60.0000091373 _chemical_name_systematic 'Generated by pymatgen' _symmetry_Int_Tables_number 1 _chemical_formula_structural Si1.5N1.5 _chemical_formula_sum 'Si1.5 N1.5' _cell_volume 40.0447946443 _cell_formula_units_Z 0 loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, y, z' loop_ _atom_type_symbol _atom_type_oxidation_number Si4+ 4.0 N3- -3.0 Si3+ 3.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_attached_hydrogens _atom_site_B_iso_or_equiv _atom_site_occupancy Si4+ Si1 1 0.000000 0.000000 0.000000 0 . 1 N3- N2 1 0.750000 0.500000 0.750000 0 . 0.5 Si3+ Si3 1 0.750000 0.500000 0.750000 0 . 0.5 N3- N4 1 0.500000 0.500000 0.500000 0 . 1 """ for l1, l2 in zip(str(writer).split("\n"), ans.split("\n")): self.assertEqual(l1.strip(), l2.strip())
def test_apply_transformation(self): t = OrderDisorderedStructureTransformation() coords = list() coords.append([0, 0, 0]) coords.append([0.75, 0.75, 0.75]) coords.append([0.5, 0.5, 0.5]) coords.append([0.25, 0.25, 0.25]) lattice = Lattice([ [3.8401979337, 0.00, 0.00], [1.9200989668, 3.3257101909, 0.00], [0.00, -2.2171384943, 3.1355090603], ]) struct = Structure( lattice, [ { "Si4+": 0.5, "O2-": 0.25, "P5+": 0.25 }, { "Si4+": 0.5, "O2-": 0.25, "P5+": 0.25 }, { "Si4+": 0.5, "O2-": 0.25, "P5+": 0.25 }, { "Si4+": 0.5, "O2-": 0.25, "P5+": 0.25 }, ], coords, ) output = t.apply_transformation(struct, return_ranked_list=50) self.assertEqual(len(output), 12) self.assertIsInstance(output[0]["structure"], Structure) struct = Structure( lattice, [ { "Si4+": 0.5 }, { "Si4+": 0.5 }, { "P5+": 0.5, "O2-": 0.5 }, { "P5+": 0.5, "O2-": 0.5 }, ], coords, ) output = t.apply_transformation(struct, return_ranked_list=50) self.assertIsInstance(output, list) self.assertEqual(len(output), 4) self.assertEqual(t.lowest_energy_structure, output[0]["structure"]) struct = Structure(lattice, [{ "Si4+": 0.5 }, { "Si4+": 0.5 }, { "O2-": 0.5 }, { "O2-": 0.5 }], coords) allstructs = t.apply_transformation(struct, 50) self.assertEqual(len(allstructs), 4) struct = Structure(lattice, [{ "Si4+": 0.333 }, { "Si4+": 0.333 }, { "Si4+": 0.333 }, "O2-"], coords) allstructs = t.apply_transformation(struct, 50) self.assertEqual(len(allstructs), 3) d = t.as_dict() self.assertEqual( type(OrderDisorderedStructureTransformation.from_dict(d)), OrderDisorderedStructureTransformation, )
def test_write(self): cw_ref_string = """# generated using pymatgen data_GdB4 _symmetry_space_group_name_H-M 'P 1' _cell_length_a 7.13160000 _cell_length_b 7.13160000 _cell_length_c 4.05050000 _cell_angle_alpha 90.00000000 _cell_angle_beta 90.00000000 _cell_angle_gamma 90.00000000 _symmetry_Int_Tables_number 1 _chemical_formula_structural GdB4 _chemical_formula_sum 'Gd4 B16' _cell_volume 206.00729003 _cell_formula_units_Z 4 loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, y, z' 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 Gd Gd0 1 0.31746000 0.81746000 0.00000000 1.0 Gd Gd1 1 0.18254000 0.31746000 0.00000000 1.0 Gd Gd2 1 0.81746000 0.68254000 0.00000000 1.0 Gd Gd3 1 0.68254000 0.18254000 0.00000000 1.0 B B4 1 0.00000000 0.00000000 0.20290000 1.0 B B5 1 0.50000000 0.50000000 0.79710000 1.0 B B6 1 0.00000000 0.00000000 0.79710000 1.0 B B7 1 0.50000000 0.50000000 0.20290000 1.0 B B8 1 0.17590000 0.03800000 0.50000000 1.0 B B9 1 0.96200000 0.17590000 0.50000000 1.0 B B10 1 0.03800000 0.82410000 0.50000000 1.0 B B11 1 0.67590000 0.46200000 0.50000000 1.0 B B12 1 0.32410000 0.53800000 0.50000000 1.0 B B13 1 0.82410000 0.96200000 0.50000000 1.0 B B14 1 0.53800000 0.67590000 0.50000000 1.0 B B15 1 0.46200000 0.32410000 0.50000000 1.0 B B16 1 0.08670000 0.58670000 0.50000000 1.0 B B17 1 0.41330000 0.08670000 0.50000000 1.0 B B18 1 0.58670000 0.91330000 0.50000000 1.0 B B19 1 0.91330000 0.41330000 0.50000000 1.0 loop_ _atom_site_moment_label _atom_site_moment_crystalaxis_x _atom_site_moment_crystalaxis_y _atom_site_moment_crystalaxis_z Gd0 5.05000000 5.05000000 0.00000000 Gd1 -5.05000000 5.05000000 0.00000000 Gd2 5.05000000 -5.05000000 0.00000000 Gd3 -5.05000000 -5.05000000 0.00000000 """ s_ncl = self.mcif_ncl.get_structures(primitive=False)[0] cw = CifWriter(s_ncl, write_magmoms=True) self.assertEqual(cw.__str__(), cw_ref_string) # from list-type magmoms list_magmoms = [list(m) for m in s_ncl.site_properties["magmom"]] # float magmoms (magnitude only) float_magmoms = [float(m) for m in s_ncl.site_properties["magmom"]] s_ncl.add_site_property("magmom", list_magmoms) cw = CifWriter(s_ncl, write_magmoms=True) self.assertEqual(cw.__str__(), cw_ref_string) s_ncl.add_site_property("magmom", float_magmoms) cw = CifWriter(s_ncl, write_magmoms=True) cw_ref_string_magnitudes = """# generated using pymatgen data_GdB4 _symmetry_space_group_name_H-M 'P 1' _cell_length_a 7.13160000 _cell_length_b 7.13160000 _cell_length_c 4.05050000 _cell_angle_alpha 90.00000000 _cell_angle_beta 90.00000000 _cell_angle_gamma 90.00000000 _symmetry_Int_Tables_number 1 _chemical_formula_structural GdB4 _chemical_formula_sum 'Gd4 B16' _cell_volume 206.00729003 _cell_formula_units_Z 4 loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, y, z' 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 Gd Gd0 1 0.31746000 0.81746000 0.00000000 1.0 Gd Gd1 1 0.18254000 0.31746000 0.00000000 1.0 Gd Gd2 1 0.81746000 0.68254000 0.00000000 1.0 Gd Gd3 1 0.68254000 0.18254000 0.00000000 1.0 B B4 1 0.00000000 0.00000000 0.20290000 1.0 B B5 1 0.50000000 0.50000000 0.79710000 1.0 B B6 1 0.00000000 0.00000000 0.79710000 1.0 B B7 1 0.50000000 0.50000000 0.20290000 1.0 B B8 1 0.17590000 0.03800000 0.50000000 1.0 B B9 1 0.96200000 0.17590000 0.50000000 1.0 B B10 1 0.03800000 0.82410000 0.50000000 1.0 B B11 1 0.67590000 0.46200000 0.50000000 1.0 B B12 1 0.32410000 0.53800000 0.50000000 1.0 B B13 1 0.82410000 0.96200000 0.50000000 1.0 B B14 1 0.53800000 0.67590000 0.50000000 1.0 B B15 1 0.46200000 0.32410000 0.50000000 1.0 B B16 1 0.08670000 0.58670000 0.50000000 1.0 B B17 1 0.41330000 0.08670000 0.50000000 1.0 B B18 1 0.58670000 0.91330000 0.50000000 1.0 B B19 1 0.91330000 0.41330000 0.50000000 1.0 loop_ _atom_site_moment_label _atom_site_moment_crystalaxis_x _atom_site_moment_crystalaxis_y _atom_site_moment_crystalaxis_z Gd0 0.00000000 0.00000000 7.14177849 Gd1 0.00000000 0.00000000 7.14177849 Gd2 0.00000000 0.00000000 -7.14177849 Gd3 0.00000000 0.00000000 -7.14177849 """ self.assertEqual(cw.__str__().strip(), cw_ref_string_magnitudes.strip()) # test we're getting correct magmoms in ncl case s_ncl2 = self.mcif_ncl2.get_structures()[0] list_magmoms = [list(m) for m in s_ncl2.site_properties["magmom"]] self.assertEqual(list_magmoms[0][0], 0.0) self.assertAlmostEqual(list_magmoms[0][1], 5.9160793408726366) self.assertAlmostEqual(list_magmoms[1][0], -5.1234749999999991) self.assertAlmostEqual(list_magmoms[1][1], 2.9580396704363183) # test creating an structure without oxidation state doesn't raise errors s_manual = Structure(Lattice.cubic(4.2), ["Cs", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]]) s_manual.add_spin_by_site([1, -1]) cw = CifWriter(s_manual, write_magmoms=True) # check oxidation state cw_manual_oxi_string = """# generated using pymatgen data_CsCl _symmetry_space_group_name_H-M 'P 1' _cell_length_a 4.20000000 _cell_length_b 4.20000000 _cell_length_c 4.20000000 _cell_angle_alpha 90.00000000 _cell_angle_beta 90.00000000 _cell_angle_gamma 90.00000000 _symmetry_Int_Tables_number 1 _chemical_formula_structural CsCl _chemical_formula_sum 'Cs1 Cl1' _cell_volume 74.08800000 _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 Cs+ 1.0 Cl+ 1.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 Cs+ Cs0 1 0.00000000 0.00000000 0.00000000 1 Cl+ Cl1 1 0.50000000 0.50000000 0.50000000 1 loop_ _atom_site_moment_label _atom_site_moment_crystalaxis_x _atom_site_moment_crystalaxis_y _atom_site_moment_crystalaxis_z """ s_manual.add_oxidation_state_by_site([1, 1]) cw = CifWriter(s_manual, write_magmoms=True) self.assertEqual(cw.__str__(), cw_manual_oxi_string)
{ 'http-equiv': 'X-UA-Compatible', 'content': 'IE=edge' }, # needed for iframe resizer { 'name': 'viewport', 'content': 'width=device-width, initial-scale=1' }, ], ) server = app.server # pylint:disable=invalid-name app.title = 'mofcolorizer' STRUCTURE = Structure(Lattice.cubic(4.2), ['Na', 'K'], [[0, 0, 0], [0.5, 0.5, 0.5]]) structure_component = ctc.StructureMoleculeComponent( # pylint:disable=invalid-name STRUCTURE, id='structure', bonding_strategy='JmolNN', color_scheme='Jmol', ) layout = html.Div( # pylint:disable=invalid-name [ dcc.Store(id='memorystore'), html.Div( [ html.Div( [
def simple_cubic_2x1x1(): lattice = Lattice.orthorhombic(2.0, 1.0, 1.0) coords = [[0.0, 0.0, 0.0], [0.5, 0.0, 0.0]] return IStructure(lattice=lattice, species=["H", "H"], coords=coords)
def a_centered_orthorhombic(): lattice = Lattice([[1, 0, 0], [0, 2, 3], [0, -2, 3]]) coords = [[0.5, 0.8, 0.8], [0.0, 0.3, 0.0], [0.0, 0.0, 0.3]] return IStructure(lattice=lattice, species=["H"] * 3, coords=coords)
def setUp(self): ## hexagonal WSe2 unitcell self.a0 = 3.287596 self.c = 23.360843 self.structure = Structure( Lattice.from_parameters(a=self.a0, b=self.a0, c=self.c, alpha=90, beta=90, gamma=120), ["W", "Se", "Se"], [[0.0, 0.0, 0.5], [0.333333, 0.666667, 0.571091], [0.333333, 0.666667, 0.428909]]) self.nvecs = [4, 4, 1] self.vacuum = 20 self.q = 0 self.structure.make_supercell(self.nvecs) self.structure_bulk = self.structure.copy() self.initdef_list = [] self.initdef_list.append( {"def1": { "type": "vac", "species": "Se", "index": 0 }}) self.initdef_list.append({ "def1": { "type": "sub", "index": -1, "species": "W", "species_new": "Re" } }) self.initdef_list.append({ "def1": { "type": "sub", "index": -1, "species": "W", "species_new": "Re" }, "def2": { "type": "vac", "index": -1, "species": "Se", "index_offset_n1n2": -1 } }) self.initdef_list.append({ "def1": { "type": "ad-W", "index": [-1], "species": ["W"], "species_new": "Re", "shift_z": "3.36" } }) self.initdef_list.append({ "def1": { "type": "int-hex", "index": [0, 1, 0], "index_offset_n1": [1, 1, 0], "species": 3 * ["W"], "species_new": "Re" } }) self.create_defects() self.siteinds_list = [[16], [15], [15, 31], [[15]], [[4, 5, 0]]] self.defcoords_list = [[[0.083333, 0.166667, 0.571091]], [[0.75, 0.75, 0.5]], [[0.75, 0.75, 0.5], [0.833333, 0.916667, 0.571091]], [[0.75, 0.75, 0.643830]], [[0.166667, 0.083333, 0.5]]] self.natoms_list = [47, 48, 47, 49, 49]
def rhombohedral(): lattice = Lattice.rhombohedral(a=1, alpha=45) coords = [[0.0, 0.0, 0.0]] return IStructure(lattice=lattice, species=["H"], coords=coords)
app = dash.Dash(__name__) app.config["suppress_callback_exceptions"] = True app.scripts.config.serve_locally = True app.css.config.serve_locally = True app.title = "Crystal Toolkit Example Components" # so that Crystal Toolkit can create callbacks # ctc.register_app(app) # StructureMoleculeComponent example_struct = Structure.from_spacegroup( "P6_3mc", Lattice.hexagonal(3.22, 5.24), ["Ga", "N"], [[1 / 3, 2 / 3, 0], [1 / 3, 2 / 3, 3 / 8]], ) # instantiate a component to view structures struct_component = ctc.StructureMoleculeComponent( example_struct # this is a pymatgen Structure ) # for a custom-sized component, use `struct_component.struct_layout` and put # it inside a Div of the required size app.layout = html.Div([ ctc.MPComponent.all_app_stores( ), # not required in this minimal example, but usually necessary for interactivity struct_component.standard_layout
def test_get_incar(self): incar = self.mpset.incar self.assertEqual(incar['LDAUU'], [5.3, 0, 0]) self.assertAlmostEqual(incar['EDIFF'], 0.0012) incar = self.mitset.incar self.assertEqual(incar['LDAUU'], [4.0, 0, 0]) self.assertAlmostEqual(incar['EDIFF'], 0.0012) si = 14 coords = list() coords.append(np.array([0, 0, 0])) coords.append(np.array([0.75, 0.5, 0.75])) #Silicon structure for testing. latt = Lattice( np.array([[3.8401979337, 0.00, 0.00], [1.9200989668, 3.3257101909, 0.00], [0.00, -2.2171384943, 3.1355090603]])) struct = Structure(latt, [si, si], coords) incar = MPRelaxSet(struct).incar self.assertNotIn("LDAU", incar) coords = list() coords.append([0, 0, 0]) coords.append([0.75, 0.5, 0.75]) lattice = Lattice([[3.8401979337, 0.00, 0.00], [1.9200989668, 3.3257101909, 0.00], [0.00, -2.2171384943, 3.1355090603]]) struct = Structure(lattice, ["Fe", "Mn"], coords) incar = MPRelaxSet(struct).incar self.assertNotIn('LDAU', incar) #check fluorides struct = Structure(lattice, ["Fe", "F"], coords) incar = MPRelaxSet(struct).incar self.assertEqual(incar['LDAUU'], [5.3, 0]) self.assertEqual(incar['MAGMOM'], [5, 0.6]) struct = Structure(lattice, ["Fe", "F"], coords) incar = MITRelaxSet(struct).incar self.assertEqual(incar['LDAUU'], [4.0, 0]) #Make sure this works with species. struct = Structure(lattice, ["Fe2+", "O2-"], coords) incar = MPRelaxSet(struct).incar self.assertEqual(incar['LDAUU'], [5.3, 0]) struct = Structure(lattice, ["Fe", "Mn"], coords, site_properties={'magmom': (5.2, -4.5)}) incar = MPRelaxSet(struct).incar self.assertEqual(incar['MAGMOM'], [-4.5, 5.2]) incar = MITRelaxSet(struct, sort_structure=False).incar self.assertEqual(incar['MAGMOM'], [5.2, -4.5]) struct = Structure(lattice, [Specie("Fe", 2, {'spin': 4.1}), "Mn"], coords) incar = MPRelaxSet(struct).incar self.assertEqual(incar['MAGMOM'], [5, 4.1]) struct = Structure(lattice, ["Mn3+", "Mn4+"], coords) incar = MITRelaxSet(struct).incar self.assertEqual(incar['MAGMOM'], [4, 3]) userset = MPRelaxSet( struct, user_incar_settings={'MAGMOM': { "Fe": 10, "S": -5, "Mn3+": 100 }}) self.assertEqual(userset.incar['MAGMOM'], [100, 0.6]) #sulfide vs sulfate test coords = list() coords.append([0, 0, 0]) coords.append([0.75, 0.5, 0.75]) coords.append([0.25, 0.5, 0]) struct = Structure(lattice, ["Fe", "Fe", "S"], coords) incar = MITRelaxSet(struct).incar self.assertEqual(incar['LDAUU'], [1.9, 0]) #Make sure Matproject sulfides are ok. self.assertNotIn('LDAUU', MPRelaxSet(struct).incar) struct = Structure(lattice, ["Fe", "S", "O"], coords) incar = MITRelaxSet(struct).incar self.assertEqual(incar['LDAUU'], [4.0, 0, 0]) #Make sure Matproject sulfates are ok. self.assertEqual(MPRelaxSet(struct).incar['LDAUU'], [5.3, 0, 0])
def test_num_atom_diff(): s1 = IStructure(Lattice.cubic(1), ["H", "He"], [[0] * 3] * 2) s2 = IStructure(Lattice.cubic(1), ["H", "Li"], [[0] * 3] * 2) assert num_atom_differences(s1, s2) == {Element.He: 1, Element.Li: -1}
def simple_cubic(): lattice = Lattice.cubic(1.0) coords = [[0.0, 0.0, 0.0]] return IStructure(lattice=lattice, species=["H"], coords=coords)
def test_nelect(self): coords = [[0] * 3, [0.5] * 3, [0.75] * 3] lattice = Lattice.cubic(4) s = Structure(lattice, ['Si', 'Si', 'Fe'], coords) self.assertAlmostEqual(MITRelaxSet(s).nelect, 16)
def test_get_incar(self): incar = self.paramset.get_incar(self.struct) self.assertEqual(incar['LDAUU'], [5.3, 0, 0]) self.assertAlmostEqual(incar['EDIFF'], 0.0012) incar = self.mitparamset.get_incar(self.struct) self.assertEqual(incar['LDAUU'], [4.0, 0, 0]) self.assertAlmostEqual(incar['EDIFF'], 0.0012) incar_gga = self.mitggaparam.get_incar(self.struct) self.assertNotIn("LDAU", incar_gga) incar_static = self.mpstaticparamset.get_incar(self.struct) self.assertEqual(incar_static["NSW"], 0) incar_nscfl = self.mpnscfparamsetl.get_incar(self.struct) self.assertEqual(incar_nscfl["NBANDS"], 60) incar_nscfu = self.mpnscfparamsetu.get_incar(self.struct) self.assertEqual(incar_nscfu["ISYM"], 0) incar_hse = self.mphseparamset.get_incar(self.struct) self.assertEqual(incar_hse['LHFCALC'], True) self.assertEqual(incar_hse['HFSCREEN'], 0.2) incar_hse_bsl = self.mpbshseparamsetl.get_incar(self.struct) self.assertEqual(incar_hse_bsl['LHFCALC'], True) self.assertEqual(incar_hse_bsl['HFSCREEN'], 0.2) self.assertEqual(incar_hse_bsl['NSW'], 0) incar_hse_bsu = self.mpbshseparamsetu.get_incar(self.struct) self.assertEqual(incar_hse_bsu['LHFCALC'], True) self.assertEqual(incar_hse_bsu['HFSCREEN'], 0.2) self.assertEqual(incar_hse_bsu['NSW'], 0) incar_diel = self.mpdielparamset.get_incar(self.struct) self.assertEqual(incar_diel['IBRION'], 8) self.assertEqual(incar_diel['LEPSILON'], True) si = 14 coords = list() coords.append(np.array([0, 0, 0])) coords.append(np.array([0.75, 0.5, 0.75])) #Silicon structure for testing. latt = Lattice( np.array([[3.8401979337, 0.00, 0.00], [1.9200989668, 3.3257101909, 0.00], [0.00, -2.2171384943, 3.1355090603]])) struct = Structure(latt, [si, si], coords) incar = self.paramset.get_incar(struct) self.assertNotIn("LDAU", incar) incar = self.mithseparamset.get_incar(self.struct) self.assertTrue(incar['LHFCALC']) coords = list() coords.append([0, 0, 0]) coords.append([0.75, 0.5, 0.75]) lattice = Lattice([[3.8401979337, 0.00, 0.00], [1.9200989668, 3.3257101909, 0.00], [0.00, -2.2171384943, 3.1355090603]]) struct = Structure(lattice, ["Fe", "Mn"], coords) incar = self.paramset.get_incar(struct) self.assertNotIn('LDAU', incar) #check fluorides struct = Structure(lattice, ["Fe", "F"], coords) incar = self.paramset.get_incar(struct) self.assertEqual(incar['LDAUU'], [5.3, 0]) self.assertEqual(incar['MAGMOM'], [5, 0.6]) struct = Structure(lattice, ["Fe", "F"], coords) incar = self.mitparamset.get_incar(struct) self.assertEqual(incar['LDAUU'], [4.0, 0]) #Make sure this works with species. struct = Structure(lattice, ["Fe2+", "O2-"], coords) incar = self.paramset.get_incar(struct) self.assertEqual(incar['LDAUU'], [5.3, 0]) struct = Structure(lattice, ["Fe", "Mn"], coords, site_properties={'magmom': (5.2, -4.5)}) incar = self.paramset.get_incar(struct) self.assertEqual(incar['MAGMOM'], [-4.5, 5.2]) incar = self.mpstaticparamset.get_incar(struct) self.assertEqual(incar['MAGMOM'], [-4.5, 5.2]) incar = self.mitparamset_unsorted.get_incar(struct) self.assertEqual(incar['MAGMOM'], [5.2, -4.5]) struct = Structure(lattice, [Specie("Fe", 2, {'spin': 4.1}), "Mn"], coords) incar = self.paramset.get_incar(struct) self.assertEqual(incar['MAGMOM'], [5, 4.1]) incar = self.mpnscfparamsetl.get_incar(struct) self.assertEqual(incar.get('MAGMOM', None), None) struct = Structure(lattice, ["Mn3+", "Mn4+"], coords) incar = self.mitparamset.get_incar(struct) self.assertEqual(incar['MAGMOM'], [4, 3]) incar = self.mpnscfparamsetu.get_incar(struct) self.assertEqual(incar.get('MAGMOM', None), None) self.assertEqual( self.userparamset.get_incar(struct)['MAGMOM'], [100, 0.6]) #sulfide vs sulfate test coords = list() coords.append([0, 0, 0]) coords.append([0.75, 0.5, 0.75]) coords.append([0.25, 0.5, 0]) struct = Structure(lattice, ["Fe", "Fe", "S"], coords) incar = self.mitparamset.get_incar(struct) self.assertEqual(incar['LDAUU'], [1.9, 0]) #Make sure Matproject sulfides are ok. self.assertNotIn('LDAUU', self.paramset.get_incar(struct)) self.assertNotIn('LDAUU', self.mpstaticparamset.get_incar(struct)) struct = Structure(lattice, ["Fe", "S", "O"], coords) incar = self.mitparamset.get_incar(struct) self.assertEqual(incar['LDAUU'], [4.0, 0, 0]) #Make sure Matproject sulfates are ok. self.assertEqual(self.paramset.get_incar(struct)['LDAUU'], [5.3, 0, 0]) self.assertEqual( self.mpnscfparamsetl.get_incar(struct)['LDAUU'], [5.3, 0, 0]) self.assertEqual( self.userparamset.get_incar(struct)['MAGMOM'], [10, -5, 0.6])
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: species[DummySpecie(species_str[0])] = float( species_str[1]) all_species.append(species) return Structure(lattice, all_species, all_coords)