class DopantPredictionTest(unittest.TestCase): def setUp(self): self.tin_dioxide = Structure( [3.24, 0, 0, 0, 4.83, 0, 0, 0, 4.84], ["O", "O", "O", "O", "Sn", "Sn"], [ [0.5, 0.19, 0.80], [0.5, 0.80, 0.19], [0, 0.30, 0.30], [0, 0.69, 0.69], [0.5, 0.50, 0.50], [0, 0, 0], ], ) self.tin_dioxide.add_oxidation_state_by_element({"Sn": 4, "O": -2}) def test_dopants_from_substitution_probabilities(self): dopants = get_dopants_from_substitution_probabilities(self.tin_dioxide, num_dopants=5) self.assertTrue("n_type" in dopants) self.assertTrue("p_type" in dopants) self.assertTrue(len(dopants["n_type"]) <= 5) self.assertTrue(len(dopants["p_type"]) <= 5) self.assertAlmostEqual(dopants["n_type"][0]["probability"], 0.06692682583342474) self.assertEqual(dopants["n_type"][0]["dopant_species"], Species("F", -1)) self.assertEqual(dopants["n_type"][0]["original_species"], Species("O", -2)) self.assertAlmostEqual(dopants["p_type"][0]["probability"], 0.023398867249112935) self.assertEqual(dopants["p_type"][0]["dopant_species"], Species("Co", 2)) self.assertEqual(dopants["p_type"][0]["original_species"], Species("Sn", 4)) # test oxidation sign matching dopants = get_dopants_from_substitution_probabilities(self.tin_dioxide, num_dopants=15, match_oxi_sign=False) self.assertEqual(dopants["n_type"][14]["dopant_species"], Species("Li", 1)) self.assertEqual(dopants["n_type"][14]["original_species"], Species("O", -2)) dopants = get_dopants_from_substitution_probabilities(self.tin_dioxide, num_dopants=15, match_oxi_sign=True) self.assertNotEqual(dopants["n_type"][14]["dopant_species"], Species("Li", 1)) def test_dopants_from_shannon_radii(self): bonded_structure = CrystalNN().get_bonded_structure(self.tin_dioxide) dopants = get_dopants_from_shannon_radii(bonded_structure, num_dopants=5) self.assertTrue("n_type" in dopants) self.assertTrue("p_type" in dopants) self.assertTrue(len(dopants["n_type"]) <= 5) self.assertTrue(len(dopants["p_type"]) <= 5) self.assertAlmostEqual(dopants["n_type"][0]["radii_diff"], 0.04) self.assertEqual(dopants["n_type"][0]["dopant_species"], Species("U", 6)) self.assertEqual(dopants["n_type"][0]["original_species"], Species("Sn", 4)) self.assertAlmostEqual(dopants["p_type"][0]["radii_diff"], 0.0) self.assertEqual(dopants["p_type"][0]["dopant_species"], Species("Ni", 2)) self.assertEqual(dopants["p_type"][0]["original_species"], Species("Sn", 4))
def get_tasker2_slabs(self): # The uneven distribution of ions on the (111) facets of Halite # type slabs are typical examples of Tasker 3 structures. We # will test this algo to generate a Tasker 2 structure instead 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'] MgO = Structure(lattice, species, frac_coords) MgO.add_oxidation_state_by_element({"Mg": 2, "O": -6}) slabgen = SlabGenerator(MgO, (1, 1, 1), 10, 10, max_normal_search=1) # We generate the Tasker 3 structure first slab = slabgen.get_slabs()[0] self.assertFalse(slab.is_symmetric()) self.assertTrue(slab.is_polar()) # Now to generate the Tasker 2 structure, we must # ensure there are enough ions on top to move around slab.make_supercell([2, 1, 1]) slabs = slab.get_tasker2_slabs() # Check if our Tasker 2 slab is nonpolar and symmetric for slab in slabs: self.assertTrue(slab.is_symmetric()) self.assertFalse(slab.is_polar())
def setUp(self): 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'] MgO = Structure(lattice, species, frac_coords) self.MgO = MgO.add_oxidation_state_by_element({"Mg": 2, "O": -6})
class SlabGeneratorTest(PymatgenTest): def setUp(self): 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) self.MgO.add_oxidation_state_by_element({"Mg": 2, "O": -6}) lattice_Dy = Lattice.hexagonal(3.58, 25.61) frac_coords_Dy = [[0.00000, 0.00000, 0.00000], [0.66667, 0.33333, 0.11133], [0.00000, 0.00000, 0.222], [0.66667, 0.33333, 0.33333], [0.33333, 0.66666, 0.44467], [0.66667, 0.33333, 0.55533], [0.33333, 0.66667, 0.66667], [0.00000, 0.00000, 0.778], [0.33333, 0.66667, 0.88867]] species_Dy = ['Dy', 'Dy', 'Dy', 'Dy', 'Dy', 'Dy', 'Dy', 'Dy', 'Dy'] self.Dy = Structure(lattice_Dy, species_Dy, frac_coords_Dy) def test_get_slab(self): s = self.get_structure("LiFePO4") gen = SlabGenerator(s, [0, 0, 1], 10, 10) s = gen.get_slab(0.25) self.assertAlmostEqual(s.lattice.abc[2], 20.820740000000001) fcc = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3), ["Fe"], [[0, 0, 0]]) gen = SlabGenerator(fcc, [1, 1, 1], 10, 10) slab = gen.get_slab() gen = SlabGenerator(fcc, [1, 1, 1], 10, 10, primitive=False) slab_non_prim = gen.get_slab() self.assertEqual(len(slab), 6) self.assertEqual(len(slab_non_prim), len(slab) * 4) # Some randomized testing of cell vectors for i in range(1, 231): i = random.randint(1, 230) sg = SpaceGroup.from_int_number(i) if sg.crystal_system == "hexagonal" or (sg.crystal_system == \ "trigonal" and (sg.symbol.endswith("H") or sg.int_number in [143, 144, 145, 147, 149, 150, 151, 152, 153, 154, 156, 157, 158, 159, 162, 163, 164, 165])): latt = Lattice.hexagonal(5, 10) else: # Cubic lattice is compatible with all other space groups. latt = Lattice.cubic(5) s = Structure.from_spacegroup(i, latt, ["H"], [[0, 0, 0]]) miller = (0, 0, 0) while miller == (0, 0, 0): miller = (random.randint(0, 6), random.randint(0, 6), random.randint(0, 6)) gen = SlabGenerator(s, miller, 10, 10) a, b, c = gen.oriented_unit_cell.lattice.matrix self.assertAlmostEqual(np.dot(a, gen._normal), 0) self.assertAlmostEqual(np.dot(b, gen._normal), 0) def test_normal_search(self): fcc = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3), ["Fe"], [[0, 0, 0]]) for miller in [(1, 0, 0), (1, 1, 0), (1, 1, 1), (2, 1, 1)]: gen = SlabGenerator(fcc, miller, 10, 10) gen_normal = SlabGenerator(fcc, miller, 10, 10, max_normal_search=max(miller)) slab = gen_normal.get_slab() self.assertAlmostEqual(slab.lattice.alpha, 90) self.assertAlmostEqual(slab.lattice.beta, 90) self.assertGreaterEqual(len(gen_normal.oriented_unit_cell), len(gen.oriented_unit_cell)) graphite = self.get_structure("Graphite") for miller in [(1, 0, 0), (1, 1, 0), (0, 0, 1), (2, 1, 1)]: gen = SlabGenerator(graphite, miller, 10, 10) gen_normal = SlabGenerator(graphite, miller, 10, 10, max_normal_search=max(miller)) self.assertGreaterEqual(len(gen_normal.oriented_unit_cell), len(gen.oriented_unit_cell)) sc = Structure(Lattice.hexagonal(3.32, 5.15), ["Sc", "Sc"], [[1 / 3, 2 / 3, 0.25], [2 / 3, 1 / 3, 0.75]]) gen = SlabGenerator(sc, (1, 1, 1), 10, 10, max_normal_search=1) self.assertAlmostEqual(gen.oriented_unit_cell.lattice.angles[1], 90) def test_get_slabs(self): gen = SlabGenerator(self.get_structure("CsCl"), [0, 0, 1], 10, 10) #Test orthogonality of some internal variables. a, b, c = gen.oriented_unit_cell.lattice.matrix self.assertAlmostEqual(np.dot(a, gen._normal), 0) self.assertAlmostEqual(np.dot(b, gen._normal), 0) self.assertEqual(len(gen.get_slabs()), 1) s = self.get_structure("LiFePO4") gen = SlabGenerator(s, [0, 0, 1], 10, 10) self.assertEqual(len(gen.get_slabs()), 5) self.assertEqual(len(gen.get_slabs(bonds={("P", "O"): 3})), 2) # There are no slabs in LFP that does not break either P-O or Fe-O # bonds for a miller index of [0, 0, 1]. self.assertEqual( len(gen.get_slabs(bonds={ ("P", "O"): 3, ("Fe", "O"): 3 })), 0) #If we allow some broken bonds, there are a few slabs. self.assertEqual( len( gen.get_slabs(bonds={ ("P", "O"): 3, ("Fe", "O"): 3 }, max_broken_bonds=2)), 2) # At this threshold, only the origin and center Li results in # clustering. All other sites are non-clustered. So the of # slabs is of sites in LiFePO4 unit cell - 2 + 1. self.assertEqual(len(gen.get_slabs(tol=1e-4)), 15) LiCoO2 = Structure.from_file(get_path("icsd_LiCoO2.cif"), primitive=False) gen = SlabGenerator(LiCoO2, [0, 0, 1], 10, 10) lco = gen.get_slabs(bonds={("Co", "O"): 3}) self.assertEqual(len(lco), 1) a, b, c = gen.oriented_unit_cell.lattice.matrix self.assertAlmostEqual(np.dot(a, gen._normal), 0) self.assertAlmostEqual(np.dot(b, gen._normal), 0) scc = Structure.from_spacegroup("Pm-3m", Lattice.cubic(3), ["Fe"], [[0, 0, 0]]) gen = SlabGenerator(scc, [0, 0, 1], 10, 10) slabs = gen.get_slabs() self.assertEqual(len(slabs), 1) gen = SlabGenerator(scc, [1, 1, 1], 10, 10, max_normal_search=1) slabs = gen.get_slabs() self.assertEqual(len(slabs), 1) # Test whether using units of hkl planes instead of Angstroms for # min_slab_size and min_vac_size will give us the same number of atoms natoms = [] for a in [1, 1.4, 2.5, 3.6]: s = Structure.from_spacegroup("Im-3m", Lattice.cubic(a), ["Fe"], [[0, 0, 0]]) slabgen = SlabGenerator(s, (1, 1, 1), 10, 10, in_unit_planes=True, max_normal_search=2) natoms.append(len(slabgen.get_slab())) n = natoms[0] for i in natoms: self.assertEqual(n, i) def test_triclinic_TeI(self): # Test case for a triclinic structure of TeI. Only these three # Miller indices are used because it is easier to identify which # atoms should be in a surface together. The closeness of the sites # in other Miller indices can cause some ambiguity when choosing a # higher tolerance. numb_slabs = {(0, 0, 1): 5, (0, 1, 0): 3, (1, 0, 0): 7} TeI = Structure.from_file(get_path("icsd_TeI.cif"), primitive=False) for k, v in numb_slabs.items(): trclnc_TeI = SlabGenerator(TeI, k, 10, 10) TeI_slabs = trclnc_TeI.get_slabs() self.assertEqual(v, len(TeI_slabs)) def test_get_orthogonal_c_slab(self): TeI = Structure.from_file(get_path("icsd_TeI.cif"), primitive=False) trclnc_TeI = SlabGenerator(TeI, (0, 0, 1), 10, 10) TeI_slabs = trclnc_TeI.get_slabs() slab = TeI_slabs[0] norm_slab = slab.get_orthogonal_c_slab() self.assertAlmostEqual(norm_slab.lattice.angles[0], 90) self.assertAlmostEqual(norm_slab.lattice.angles[1], 90) def test_get_tasker2_slabs(self): # The uneven distribution of ions on the (111) facets of Halite # type slabs are typical examples of Tasker 3 structures. We # will test this algo to generate a Tasker 2 structure instead slabgen = SlabGenerator(self.MgO, (1, 1, 1), 10, 10, max_normal_search=1) # We generate the Tasker 3 structure first slab = slabgen.get_slabs()[0] self.assertFalse(slab.is_symmetric()) self.assertTrue(slab.is_polar()) # Now to generate the Tasker 2 structure, we must # ensure there are enough ions on top to move around slab.make_supercell([2, 1, 1]) slabs = slab.get_tasker2_slabs() # Check if our Tasker 2 slab is nonpolar and symmetric for slab in slabs: self.assertTrue(slab.is_symmetric()) self.assertFalse(slab.is_polar()) def test_nonstoichiometric_symmetrized_slab(self): # For the (111) halite slab, sometimes a nonstoichiometric # system is preferred over the stoichiometric Tasker 2. slabgen = SlabGenerator(self.MgO, (1, 1, 1), 10, 10, max_normal_search=1) slabs = slabgen.get_slabs(symmetrize=True) # We should end up with two terminations, one with # an Mg rich surface and another O rich surface self.assertEqual(len(slabs), 2) for slab in slabs: self.assertTrue(slab.is_symmetric()) # For a low symmetry primitive_elemental system such as # R-3m, there should be some nonsymmetric slabs # without using nonstoichiometric_symmetrized_slab slabs = generate_all_slabs(self.Dy, 1, 30, 30, center_slab=True, symmetrize=True) for s in slabs: self.assertTrue(s.is_symmetric()) self.assertGreater(len(s), len(self.Dy)) def test_move_to_other_side(self): # Tests to see if sites are added to opposite side s = self.get_structure("LiFePO4") slabgen = SlabGenerator(s, (0, 0, 1), 10, 10, center_slab=True) slab = slabgen.get_slab() surface_sites = slab.get_surface_sites() # check if top sites are moved to the bottom top_index = [ss[1] for ss in surface_sites["top"]] slab = slabgen.move_to_other_side(slab, top_index) all_bottom = [ slab[i].frac_coords[2] < slab.center_of_mass[2] for i in top_index ] self.assertTrue(all(all_bottom)) # check if bottom sites are moved to the top bottom_index = [ss[1] for ss in surface_sites["bottom"]] slab = slabgen.move_to_other_side(slab, bottom_index) all_top = [ slab[i].frac_coords[2] > slab.center_of_mass[2] for i in bottom_index ] self.assertTrue(all(all_top))
class StructureTest(PymatgenTest): def setUp(self): 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]]) self.structure = Structure(lattice, ["Si", "Si"], coords) def test_mutable_sequence_methods(self): s = self.structure s[0] = "Fe" self.assertEqual(s.formula, "Fe1 Si1") s[0] = "Fe", [0.5, 0.5, 0.5] self.assertEqual(s.formula, "Fe1 Si1") self.assertArrayAlmostEqual(s[0].frac_coords, [0.5, 0.5, 0.5]) s.reverse() self.assertEqual(s[0].specie, Element("Si")) self.assertArrayAlmostEqual(s[0].frac_coords, [0.75, 0.5, 0.75]) s[0] = {"Mn": 0.5} self.assertEqual(s.formula, "Mn0.5 Fe1") del s[1] self.assertEqual(s.formula, "Mn0.5") s[0] = "Fe", [0.9, 0.9, 0.9], {"magmom": 5} self.assertEqual(s.formula, "Fe1") self.assertEqual(s[0].magmom, 5) def test_non_hash(self): self.assertRaises(TypeError, dict, [(self.structure, 1)]) def test_sort(self): s = self.structure s[0] = "F" s.sort() self.assertEqual(s[0].species_string, "Si") self.assertEqual(s[1].species_string, "F") s.sort(key=lambda site: site.species_string) self.assertEqual(s[0].species_string, "F") self.assertEqual(s[1].species_string, "Si") s.sort(key=lambda site: site.species_string, reverse=True) self.assertEqual(s[0].species_string, "Si") self.assertEqual(s[1].species_string, "F") def test_append_insert_remove_replace(self): s = self.structure s.insert(1, "O", [0.5, 0.5, 0.5]) self.assertEqual(s.formula, "Si2 O1") self.assertTrue(s.ntypesp == 2) self.assertTrue(s.symbol_set == ("Si", "O")) self.assertTrue(s.indices_from_symbol("Si") == (0,2)) self.assertTrue(s.indices_from_symbol("O") == (1,)) del s[2] self.assertEqual(s.formula, "Si1 O1") self.assertTrue(s.indices_from_symbol("Si") == (0,)) self.assertTrue(s.indices_from_symbol("O") == (1,)) s.append("N", [0.25, 0.25, 0.25]) self.assertEqual(s.formula, "Si1 N1 O1") self.assertTrue(s.ntypesp == 3) self.assertTrue(s.symbol_set == ("Si", "O", "N")) self.assertTrue(s.indices_from_symbol("Si") == (0,)) self.assertTrue(s.indices_from_symbol("O") == (1,)) self.assertTrue(s.indices_from_symbol("N") == (2,)) s[0] = "Ge" self.assertEqual(s.formula, "Ge1 N1 O1") self.assertTrue(s.symbol_set == ("Ge", "O", "N")) s.replace_species({"Ge": "Si"}) self.assertEqual(s.formula, "Si1 N1 O1") self.assertTrue(s.ntypesp == 3) s.replace_species({"Si": {"Ge": 0.5, "Si": 0.5}}) self.assertEqual(s.formula, "Si0.5 Ge0.5 N1 O1") #this should change the .5Si .5Ge sites to .75Si .25Ge s.replace_species({"Ge": {"Ge": 0.5, "Si": 0.5}}) self.assertEqual(s.formula, "Si0.75 Ge0.25 N1 O1") # In this case, s.ntypesp is ambiguous. # for the time being, we raise AttributeError. with self.assertRaises(AttributeError): s.ntypesp s.remove_species(["Si"]) self.assertEqual(s.formula, "Ge0.25 N1 O1") s.remove_sites([1, 2]) self.assertEqual(s.formula, "Ge0.25") def test_add_site_property(self): s = self.structure s.add_site_property("charge", [4.1, -5]) self.assertEqual(s[0].charge, 4.1) self.assertEqual(s[1].charge, -5) s.add_site_property("magmom", [3, 2]) self.assertEqual(s[0].charge, 4.1) self.assertEqual(s[0].magmom, 3) def test_propertied_structure(self): #Make sure that site properties are set to None for missing values. s = self.structure s.add_site_property("charge", [4.1, -5]) s.append("Li", [0.3, 0.3 ,0.3]) self.assertEqual(len(s.site_properties["charge"]), 3) def test_perturb(self): d = 0.1 pre_perturbation_sites = self.structure.sites[:] self.structure.perturb(distance=d) post_perturbation_sites = self.structure.sites for i, x in enumerate(pre_perturbation_sites): self.assertAlmostEqual(x.distance(post_perturbation_sites[i]), d, 3, "Bad perturbation distance") def test_add_oxidation_states(self): oxidation_states = {"Si": -4} self.structure.add_oxidation_state_by_element(oxidation_states) for site in self.structure: for k in site.species_and_occu.keys(): self.assertEqual(k.oxi_state, oxidation_states[k.symbol], "Wrong oxidation state assigned!") oxidation_states = {"Fe": 2} self.assertRaises(ValueError, self.structure.add_oxidation_state_by_element, oxidation_states) self.structure.add_oxidation_state_by_site([2, -4]) self.assertEqual(self.structure[0].specie.oxi_state, 2) self.assertRaises(ValueError, self.structure.add_oxidation_state_by_site, [1]) def test_remove_oxidation_states(self): co_elem = Element("Co") o_elem = Element("O") co_specie = Specie("Co", 2) o_specie = Specie("O", -2) coords = list() coords.append([0, 0, 0]) coords.append([0.75, 0.5, 0.75]) lattice = Lattice.cubic(10) s_elem = Structure(lattice, [co_elem, o_elem], coords) s_specie = Structure(lattice, [co_specie, o_specie], coords) s_specie.remove_oxidation_states() self.assertEqual(s_elem, s_specie, "Oxidation state remover " "failed") def test_apply_operation(self): op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 90) s = self.structure.copy() s.apply_operation(op) self.assertArrayAlmostEqual( s.lattice.matrix, [[0.000000, 3.840198, 0.000000], [-3.325710, 1.920099, 0.000000], [2.217138, -0.000000, 3.135509]], 5) op = SymmOp([[1, 1, 0, 0.5], [1, 0, 0, 0.5], [0, 0, 1, 0.5], [0, 0, 0, 1]]) s = self.structure.copy() s.apply_operation(op, fractional=True) self.assertArrayAlmostEqual( s.lattice.matrix, [[5.760297, 3.325710, 0.000000], [3.840198, 0.000000, 0.000000], [0.000000, -2.217138, 3.135509]], 5) def test_apply_strain(self): s = self.structure initial_coord = s[1].coords s.apply_strain(0.01) self.assertAlmostEqual( s.lattice.abc, (3.8785999130369997, 3.878600984287687, 3.8785999130549516)) self.assertArrayAlmostEqual(s[1].coords, initial_coord * 1.01) a1, b1, c1 = s.lattice.abc s.apply_strain([0.1, 0.2, 0.3]) a2, b2, c2 = s.lattice.abc self.assertAlmostEqual(a2 / a1, 1.1) self.assertAlmostEqual(b2 / b1, 1.2) self.assertAlmostEqual(c2 / c1, 1.3) def test_scale_lattice(self): initial_coord = self.structure[1].coords self.structure.scale_lattice(self.structure.volume * 1.01 ** 3) self.assertArrayAlmostEqual( self.structure.lattice.abc, (3.8785999130369997, 3.878600984287687, 3.8785999130549516)) self.assertArrayAlmostEqual(self.structure[1].coords, initial_coord * 1.01) def test_translate_sites(self): self.structure.translate_sites([0, 1], [0.5, 0.5, 0.5], frac_coords=True) self.assertArrayEqual(self.structure.frac_coords[0], [0.5, 0.5, 0.5]) self.structure.translate_sites([0], [0.5, 0.5, 0.5], frac_coords=False) self.assertArrayAlmostEqual(self.structure.cart_coords[0], [3.38014845, 1.05428585, 2.06775453]) self.structure.translate_sites([0], [0.5, 0.5, 0.5], frac_coords=True, to_unit_cell=False) self.assertArrayAlmostEqual(self.structure.frac_coords[0], [1.00187517, 1.25665291, 1.15946374]) def test_mul(self): self.structure *= [2, 1, 1] self.assertEqual(self.structure.formula, "Si4") s = [2, 1, 1] * self.structure self.assertEqual(s.formula, "Si8") self.assertIsInstance(s, Structure) s = self.structure * [[1, 0, 0], [2, 1, 0], [0, 0, 2]] self.assertEqual(s.formula, "Si8") self.assertArrayAlmostEqual(s.lattice.abc, [7.6803959, 17.5979979, 7.6803959]) def test_make_supercell(self): self.structure.make_supercell([2, 1, 1]) self.assertEqual(self.structure.formula, "Si4") self.structure.make_supercell([[1, 0, 0], [2, 1, 0], [0, 0, 1]]) self.assertEqual(self.structure.formula, "Si4") self.structure.make_supercell(2) self.assertEqual(self.structure.formula, "Si32") self.assertArrayAlmostEqual(self.structure.lattice.abc, [15.360792, 35.195996, 7.680396], 5) def test_disordered_supercell_primitive_cell(self): l = Lattice.cubic(2) f = [[0.5, 0.5, 0.5]] sp = [{'Si': 0.54738}] s = Structure(l, sp, f) #this supercell often breaks things s.make_supercell([[0,-1,1],[-1,1,0],[1,1,1]]) self.assertEqual(len(s.get_primitive_structure()), 1) def test_another_supercell(self): #this is included b/c for some reason the old algo was failing on it s = self.structure.copy() s.make_supercell([[0, 2, 2], [2, 0, 2], [2, 2, 0]]) self.assertEqual(s.formula, "Si32") s = self.structure.copy() s.make_supercell([[0, 2, 0], [1, 0, 0], [0, 0, 1]]) self.assertEqual(s.formula, "Si4") def test_to_from_dict(self): d = self.structure.as_dict() s2 = Structure.from_dict(d) self.assertEqual(type(s2), Structure) def test_to_from_file_string(self): for fmt in ["cif", "json", "poscar", "cssr", "yaml", "xsf"]: s = self.structure.to(fmt=fmt) self.assertIsNotNone(s) ss = Structure.from_str(s, fmt=fmt) self.assertArrayAlmostEqual( ss.lattice.lengths_and_angles, self.structure.lattice.lengths_and_angles, decimal=5) self.assertArrayAlmostEqual(ss.frac_coords, self.structure.frac_coords) self.assertIsInstance(ss, Structure) self.structure.to(filename="POSCAR.testing") self.assertTrue(os.path.exists("POSCAR.testing")) os.remove("POSCAR.testing") self.structure.to(filename="structure_testing.json") self.assertTrue(os.path.exists("structure_testing.json")) s = Structure.from_file("structure_testing.json") self.assertEqual(s, self.structure) os.remove("structure_testing.json") def test_from_spacegroup(self): s1 = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3), ["Li", "O"], [[0.25, 0.25, 0.25], [0, 0, 0]]) self.assertEqual(s1.formula, "Li8 O4") s2 = Structure.from_spacegroup(225, Lattice.cubic(3), ["Li", "O"], [[0.25, 0.25, 0.25], [0, 0, 0]]) self.assertEqual(s1, s2) s2 = Structure.from_spacegroup(225, Lattice.cubic(3), ["Li", "O"], [[0.25, 0.25, 0.25], [0, 0, 0]], site_properties={"charge": [1, -2]}) self.assertEqual(sum(s2.site_properties["charge"]), 0) s = Structure.from_spacegroup("Pm-3m", Lattice.cubic(3), ["Cs", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]]) self.assertEqual(s.formula, "Cs1 Cl1") self.assertRaises(ValueError, Structure.from_spacegroup, "Pm-3m", Lattice.tetragonal(1, 3), ["Cs", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]]) def test_merge_sites(self): species = [{'Ag': 0.5}, {'Cl': 0.25}, {'Cl': 0.1}, {'Ag': 0.5}, {'F': 0.15}, {'F': 0.1}] coords = [[0, 0, 0], [0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [0, 0, 0], [0.5, 0.5, 1.501], [0.5, 0.5, 1.501]] s = Structure(Lattice.cubic(1), species, coords) s.merge_sites() self.assertEqual(s[0].specie.symbol, 'Ag') self.assertEqual(s[1].species_and_occu, Composition({'Cl': 0.35, 'F': 0.25})) self.assertArrayAlmostEqual(s[1].frac_coords, [.5, .5, .5005]) def test_properties(self): self.assertEqual(self.structure.num_sites, len(self.structure)) self.structure.make_supercell(2) self.structure[1] = "C" sites = list(self.structure.group_by_types()) self.assertEqual(sites[-1].specie.symbol, "C") self.structure.add_oxidation_state_by_element({"Si": 4, "C": 2}) self.assertEqual(self.structure.charge, 62) def test_init_error(self): self.assertRaises(StructureError, Structure, Lattice.cubic(3), ["Si"], [[0, 0, 0], [0.5, 0.5, 0.5]]) def test_from_sites(self): self.structure.add_site_property("hello", [1, 2]) s = Structure.from_sites(self.structure, to_unit_cell=True) self.assertEqual(s.site_properties["hello"][1], 2) def test_magic(self): s = Structure.from_sites(self.structure) self.assertEqual(s, self.structure) self.assertNotEqual(s, None) s.apply_strain(0.5) self.assertNotEqual(s, self.structure) self.assertNotEqual(self.structure * 2, self.structure)
class StructureTest(PymatgenTest): def setUp(self): 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]]) self.structure = Structure(lattice, ["Si", "Si"], coords) def test_mutable_sequence_methods(self): s = self.structure s[0] = "Fe" self.assertEqual(s.formula, "Fe1 Si1") s[0] = "Fe", [0.5, 0.5, 0.5] self.assertEqual(s.formula, "Fe1 Si1") self.assertArrayAlmostEqual(s[0].frac_coords, [0.5, 0.5, 0.5]) s.reverse() self.assertEqual(s[0].specie, Element("Si")) self.assertArrayAlmostEqual(s[0].frac_coords, [0.75, 0.5, 0.75]) s[0] = {"Mn": 0.5} self.assertEqual(s.formula, "Mn0.5 Fe1") del s[1] self.assertEqual(s.formula, "Mn0.5") s[0] = "Fe", [0.9, 0.9, 0.9], {"magmom": 5} self.assertEqual(s.formula, "Fe1") self.assertEqual(s[0].magmom, 5) def test_non_hash(self): self.assertRaises(TypeError, dict, [(self.structure, 1)]) def test_sort(self): s = self.structure s[0] = "F" s.sort() self.assertEqual(s[0].species_string, "Si") self.assertEqual(s[1].species_string, "F") s.sort(key=lambda site: site.species_string) self.assertEqual(s[0].species_string, "F") self.assertEqual(s[1].species_string, "Si") s.sort(key=lambda site: site.species_string, reverse=True) self.assertEqual(s[0].species_string, "Si") self.assertEqual(s[1].species_string, "F") def test_append_insert_remove_replace(self): s = self.structure s.insert(1, "O", [0.5, 0.5, 0.5]) self.assertEqual(s.formula, "Si2 O1") self.assertTrue(s.ntypesp == 2) self.assertTrue(s.symbol_set == ("Si", "O")) self.assertTrue(s.indices_from_symbol("Si") == (0, 2)) self.assertTrue(s.indices_from_symbol("O") == (1, )) s.remove(2) self.assertEqual(s.formula, "Si1 O1") self.assertTrue(s.indices_from_symbol("Si") == (0, )) self.assertTrue(s.indices_from_symbol("O") == (1, )) s.append("N", [0.25, 0.25, 0.25]) self.assertEqual(s.formula, "Si1 N1 O1") self.assertTrue(s.ntypesp == 3) self.assertTrue(s.symbol_set == ("Si", "O", "N")) self.assertTrue(s.indices_from_symbol("Si") == (0, )) self.assertTrue(s.indices_from_symbol("O") == (1, )) self.assertTrue(s.indices_from_symbol("N") == (2, )) s.replace(0, "Ge") self.assertEqual(s.formula, "Ge1 N1 O1") self.assertTrue(s.symbol_set == ("Ge", "O", "N")) s.replace_species({"Ge": "Si"}) self.assertEqual(s.formula, "Si1 N1 O1") self.assertTrue(s.ntypesp == 3) s.replace_species({"Si": {"Ge": 0.5, "Si": 0.5}}) self.assertEqual(s.formula, "Si0.5 Ge0.5 N1 O1") #this should change the .5Si .5Ge sites to .75Si .25Ge s.replace_species({"Ge": {"Ge": 0.5, "Si": 0.5}}) self.assertEqual(s.formula, "Si0.75 Ge0.25 N1 O1") # In this case, s.ntypesp is ambiguous. # for the time being, we raise AttributeError. with self.assertRaises(AttributeError): s.ntypesp s.remove_species(["Si"]) self.assertEqual(s.formula, "Ge0.25 N1 O1") s.remove_sites([1, 2]) self.assertEqual(s.formula, "Ge0.25") def test_add_site_property(self): s = self.structure s.add_site_property("charge", [4.1, -5]) self.assertEqual(s[0].charge, 4.1) self.assertEqual(s[1].charge, -5) s.add_site_property("magmom", [3, 2]) self.assertEqual(s[0].charge, 4.1) self.assertEqual(s[0].magmom, 3) def test_perturb(self): d = 0.1 pre_perturbation_sites = self.structure.sites[:] self.structure.perturb(distance=d) post_perturbation_sites = self.structure.sites for i, x in enumerate(pre_perturbation_sites): self.assertAlmostEqual(x.distance(post_perturbation_sites[i]), d, 3, "Bad perturbation distance") def test_add_oxidation_states(self): oxidation_states = {"Si": -4} self.structure.add_oxidation_state_by_element(oxidation_states) for site in self.structure: for k in site.species_and_occu.keys(): self.assertEqual(k.oxi_state, oxidation_states[k.symbol], "Wrong oxidation state assigned!") oxidation_states = {"Fe": 2} self.assertRaises(ValueError, self.structure.add_oxidation_state_by_element, oxidation_states) self.structure.add_oxidation_state_by_site([2, -4]) self.assertEqual(self.structure[0].specie.oxi_state, 2) self.assertRaises(ValueError, self.structure.add_oxidation_state_by_site, [1]) def test_remove_oxidation_states(self): co_elem = Element("Co") o_elem = Element("O") co_specie = Specie("Co", 2) o_specie = Specie("O", -2) coords = list() coords.append([0, 0, 0]) coords.append([0.75, 0.5, 0.75]) lattice = Lattice.cubic(10) s_elem = Structure(lattice, [co_elem, o_elem], coords) s_specie = Structure(lattice, [co_specie, o_specie], coords) s_specie.remove_oxidation_states() self.assertEqual(s_elem, s_specie, "Oxidation state remover " "failed") def test_apply_operation(self): op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 90) self.structure.apply_operation(op) self.assertArrayAlmostEqual( self.structure.lattice.matrix, [[0.000000, 3.840198, 0.000000], [-3.325710, 1.920099, 0.000000], [2.217138, -0.000000, 3.135509]], 5) def test_apply_strain(self): s = self.structure initial_coord = s[1].coords s.apply_strain(0.01) self.assertAlmostEqual( s.lattice.abc, (3.8785999130369997, 3.878600984287687, 3.8785999130549516)) self.assertArrayAlmostEqual(s[1].coords, initial_coord * 1.01) a1, b1, c1 = s.lattice.abc s.apply_strain([0.1, 0.2, 0.3]) a2, b2, c2 = s.lattice.abc self.assertAlmostEqual(a2 / a1, 1.1) self.assertAlmostEqual(b2 / b1, 1.2) self.assertAlmostEqual(c2 / c1, 1.3) def test_scale_lattice(self): initial_coord = self.structure[1].coords self.structure.scale_lattice(self.structure.volume * 1.01**3) self.assertArrayAlmostEqual( self.structure.lattice.abc, (3.8785999130369997, 3.878600984287687, 3.8785999130549516)) self.assertArrayAlmostEqual(self.structure[1].coords, initial_coord * 1.01) def test_translate_sites(self): self.structure.translate_sites([0, 1], [0.5, 0.5, 0.5], frac_coords=True) self.assertArrayEqual(self.structure.frac_coords[0], [0.5, 0.5, 0.5]) self.structure.translate_sites([0], [0.5, 0.5, 0.5], frac_coords=False) self.assertArrayAlmostEqual(self.structure.cart_coords[0], [3.38014845, 1.05428585, 2.06775453]) self.structure.translate_sites([0], [0.5, 0.5, 0.5], frac_coords=True, to_unit_cell=False) self.assertArrayAlmostEqual(self.structure.frac_coords[0], [1.00187517, 1.25665291, 1.15946374]) def test_make_supercell(self): self.structure.make_supercell([2, 1, 1]) self.assertEqual(self.structure.formula, "Si4") self.structure.make_supercell([[1, 0, 0], [2, 1, 0], [0, 0, 1]]) self.assertEqual(self.structure.formula, "Si4") self.structure.make_supercell(2) self.assertEqual(self.structure.formula, "Si32") self.assertArrayAlmostEqual(self.structure.lattice.abc, [15.360792, 35.195996, 7.680396], 5) def test_disordered_supercell_primitive_cell(self): l = Lattice.cubic(2) f = [[0.5, 0.5, 0.5]] sp = [{'Si': 0.54738}] s = Structure(l, sp, f) #this supercell often breaks things s.make_supercell([[0, -1, 1], [-1, 1, 0], [1, 1, 1]]) self.assertEqual(len(s.get_primitive_structure()), 1) def test_another_supercell(self): #this is included b/c for some reason the old algo was failing on it s = self.structure.copy() s.make_supercell([[0, 2, 2], [2, 0, 2], [2, 2, 0]]) self.assertEqual(s.formula, "Si32") s = self.structure.copy() s.make_supercell([[0, 2, 0], [1, 0, 0], [0, 0, 1]]) self.assertEqual(s.formula, "Si4") def test_to_from_dict(self): d = self.structure.to_dict s2 = Structure.from_dict(d) self.assertEqual(type(s2), Structure) def test_propertied_structure_mod(self): prop_structure = Structure(self.structure.lattice, ["Si"] * 2, self.structure.frac_coords, site_properties={'magmom': [5, -5]}) prop_structure.append("C", [0.25, 0.25, 0.25]) d = prop_structure.to_dict with warnings.catch_warnings(record=True) as w: # Cause all warnings to always be triggered. warnings.simplefilter("always") s2 = Structure.from_dict(d) self.assertEqual(len(w), 1) self.assertEqual( str(w[0].message), 'Not all sites have property magmom. Missing values are set ' 'to None.')
class DopantPredictionTest(unittest.TestCase): def setUp(self): self.tin_dioxide = Structure( [3.24, 0, 0, 0, 4.83, 0, 0, 0, 4.84], ['O', 'O', 'O', 'O', 'Sn', 'Sn'], [[0.5, 0.19, 0.80], [0.5, 0.80, 0.19], [0, 0.30, 0.30], [0, 0.69, 0.69], [0.5, 0.50, 0.50], [0, 0, 0]]) self.tin_dioxide.add_oxidation_state_by_element({'Sn': 4, 'O': -2}) def test_dopants_from_substitution_probabilities(self): dopants = get_dopants_from_substitution_probabilities(self.tin_dioxide, num_dopants=5) self.assertTrue("n_type" in dopants) self.assertTrue("p_type" in dopants) self.assertTrue(len(dopants['n_type']) <= 5) self.assertTrue(len(dopants['p_type']) <= 5) self.assertAlmostEqual(dopants['n_type'][0]['probability'], 0.06692682583342474) self.assertEqual(dopants['n_type'][0]['dopant_species'], Specie('F', -1)) self.assertEqual(dopants['n_type'][0]['original_species'], Specie('O', -2)) self.assertAlmostEqual(dopants['p_type'][0]['probability'], 0.023398867249112935) self.assertEqual(dopants['p_type'][0]['dopant_species'], Specie('Co', 2)) self.assertEqual(dopants['p_type'][0]['original_species'], Specie('Sn', 4)) # test oxidation sign matching dopants = get_dopants_from_substitution_probabilities( self.tin_dioxide, num_dopants=15, match_oxi_sign=False) self.assertEqual(dopants['n_type'][14]['dopant_species'], Specie('Li', 1)) self.assertEqual(dopants['n_type'][14]['original_species'], Specie('O', -2)) dopants = get_dopants_from_substitution_probabilities( self.tin_dioxide, num_dopants=15, match_oxi_sign=True) self.assertNotEqual(dopants['n_type'][14]['dopant_species'], Specie('Li', 1)) def test_dopants_from_shannon_radii(self): bonded_structure = CrystalNN().get_bonded_structure(self.tin_dioxide) dopants = get_dopants_from_shannon_radii(bonded_structure, num_dopants=5) self.assertTrue("n_type" in dopants) self.assertTrue("p_type" in dopants) self.assertTrue(len(dopants['n_type']) <= 5) self.assertTrue(len(dopants['p_type']) <= 5) self.assertAlmostEqual(dopants['n_type'][0]['radii_diff'], 0.04) self.assertEqual(dopants['n_type'][0]['dopant_species'], Specie('U', 6)) self.assertEqual(dopants['n_type'][0]['original_species'], Specie('Sn', 4)) self.assertAlmostEqual(dopants['p_type'][0]['radii_diff'], 0.) self.assertEqual(dopants['p_type'][0]['dopant_species'], Specie('Ni', 2)) self.assertEqual(dopants['p_type'][0]['original_species'], Specie('Sn', 4))
class SlabGeneratorTest(PymatgenTest): def setUp(self): 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) self.MgO.add_oxidation_state_by_element({"Mg": 2, "O": -6}) lattice_Dy = Lattice.hexagonal(3.58, 25.61) frac_coords_Dy = [[0.00000, 0.00000, 0.00000], [0.66667, 0.33333, 0.11133], [0.00000, 0.00000, 0.222], [0.66667, 0.33333, 0.33333], [0.33333, 0.66666, 0.44467], [0.66667, 0.33333, 0.55533], [0.33333, 0.66667, 0.66667], [0.00000, 0.00000, 0.778], [0.33333, 0.66667, 0.88867]] species_Dy = ['Dy', 'Dy', 'Dy', 'Dy', 'Dy', 'Dy', 'Dy', 'Dy', 'Dy'] self.Dy = Structure(lattice_Dy, species_Dy, frac_coords_Dy) def test_get_slab(self): s = self.get_structure("LiFePO4") gen = SlabGenerator(s, [0, 0, 1], 10, 10) s = gen.get_slab(0.25) self.assertAlmostEqual(s.lattice.abc[2], 20.820740000000001) fcc = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3), ["Fe"], [[0, 0, 0]]) gen = SlabGenerator(fcc, [1, 1, 1], 10, 10, max_normal_search=1) slab = gen.get_slab() self.assertEqual(len(slab), 6) gen = SlabGenerator(fcc, [1, 1, 1], 10, 10, primitive=False, max_normal_search=1) slab_non_prim = gen.get_slab() self.assertEqual(len(slab_non_prim), len(slab) * 4) # Some randomized testing of cell vectors for i in range(1, 231): i = random.randint(1, 230) sg = SpaceGroup.from_int_number(i) if sg.crystal_system == "hexagonal" or (sg.crystal_system == \ "trigonal" and ( sg.symbol.endswith( "H") or sg.int_number in [ 143, 144, 145, 147, 149, 150, 151, 152, 153, 154, 156, 157, 158, 159, 162, 163, 164, 165])): latt = Lattice.hexagonal(5, 10) else: # Cubic lattice is compatible with all other space groups. latt = Lattice.cubic(5) s = Structure.from_spacegroup(i, latt, ["H"], [[0, 0, 0]]) miller = (0, 0, 0) while miller == (0, 0, 0): miller = (random.randint(0, 6), random.randint(0, 6), random.randint(0, 6)) gen = SlabGenerator(s, miller, 10, 10) a, b, c = gen.oriented_unit_cell.lattice.matrix self.assertAlmostEqual(np.dot(a, gen._normal), 0) self.assertAlmostEqual(np.dot(b, gen._normal), 0) def test_normal_search(self): fcc = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3), ["Fe"], [[0, 0, 0]]) for miller in [(1, 0, 0), (1, 1, 0), (1, 1, 1), (2, 1, 1)]: gen = SlabGenerator(fcc, miller, 10, 10) gen_normal = SlabGenerator(fcc, miller, 10, 10, max_normal_search=max(miller)) slab = gen_normal.get_slab() self.assertAlmostEqual(slab.lattice.alpha, 90) self.assertAlmostEqual(slab.lattice.beta, 90) self.assertGreaterEqual(len(gen_normal.oriented_unit_cell), len(gen.oriented_unit_cell)) graphite = self.get_structure("Graphite") for miller in [(1, 0, 0), (1, 1, 0), (0, 0, 1), (2, 1, 1)]: gen = SlabGenerator(graphite, miller, 10, 10) gen_normal = SlabGenerator(graphite, miller, 10, 10, max_normal_search=max(miller)) self.assertGreaterEqual(len(gen_normal.oriented_unit_cell), len(gen.oriented_unit_cell)) sc = Structure(Lattice.hexagonal(3.32, 5.15), ["Sc", "Sc"], [[1 / 3, 2 / 3, 0.25], [2 / 3, 1 / 3, 0.75]]) gen = SlabGenerator(sc, (1, 1, 1), 10, 10, max_normal_search=1) self.assertAlmostEqual(gen.oriented_unit_cell.lattice.angles[1], 90) def test_get_slabs(self): gen = SlabGenerator(self.get_structure("CsCl"), [0, 0, 1], 10, 10) # Test orthogonality of some internal variables. a, b, c = gen.oriented_unit_cell.lattice.matrix self.assertAlmostEqual(np.dot(a, gen._normal), 0) self.assertAlmostEqual(np.dot(b, gen._normal), 0) self.assertEqual(len(gen.get_slabs()), 1) s = self.get_structure("LiFePO4") gen = SlabGenerator(s, [0, 0, 1], 10, 10) self.assertEqual(len(gen.get_slabs()), 5) self.assertEqual(len(gen.get_slabs(bonds={("P", "O"): 3})), 2) # There are no slabs in LFP that does not break either P-O or Fe-O # bonds for a miller index of [0, 0, 1]. self.assertEqual(len(gen.get_slabs( bonds={("P", "O"): 3, ("Fe", "O"): 3})), 0) # If we allow some broken bonds, there are a few slabs. self.assertEqual(len(gen.get_slabs( bonds={("P", "O"): 3, ("Fe", "O"): 3}, max_broken_bonds=2)), 2) # At this threshold, only the origin and center Li results in # clustering. All other sites are non-clustered. So the of # slabs is of sites in LiFePO4 unit cell - 2 + 1. self.assertEqual(len(gen.get_slabs(tol=1e-4, ftol=1e-4)), 15) LiCoO2 = Structure.from_file(get_path("icsd_LiCoO2.cif"), primitive=False) gen = SlabGenerator(LiCoO2, [0, 0, 1], 10, 10) lco = gen.get_slabs(bonds={("Co", "O"): 3}) self.assertEqual(len(lco), 1) a, b, c = gen.oriented_unit_cell.lattice.matrix self.assertAlmostEqual(np.dot(a, gen._normal), 0) self.assertAlmostEqual(np.dot(b, gen._normal), 0) scc = Structure.from_spacegroup("Pm-3m", Lattice.cubic(3), ["Fe"], [[0, 0, 0]]) gen = SlabGenerator(scc, [0, 0, 1], 10, 10) slabs = gen.get_slabs() self.assertEqual(len(slabs), 1) gen = SlabGenerator(scc, [1, 1, 1], 10, 10, max_normal_search=1) slabs = gen.get_slabs() self.assertEqual(len(slabs), 1) # Test whether using units of hkl planes instead of Angstroms for # min_slab_size and min_vac_size will give us the same number of atoms natoms = [] for a in [1, 1.4, 2.5, 3.6]: s = Structure.from_spacegroup("Im-3m", Lattice.cubic(a), ["Fe"], [[0, 0, 0]]) slabgen = SlabGenerator(s, (1, 1, 1), 10, 10, in_unit_planes=True, max_normal_search=2) natoms.append(len(slabgen.get_slab())) n = natoms[0] for i in natoms: self.assertEqual(n, i) def test_triclinic_TeI(self): # Test case for a triclinic structure of TeI. Only these three # Miller indices are used because it is easier to identify which # atoms should be in a surface together. The closeness of the sites # in other Miller indices can cause some ambiguity when choosing a # higher tolerance. numb_slabs = {(0, 0, 1): 5, (0, 1, 0): 3, (1, 0, 0): 7} TeI = Structure.from_file(get_path("icsd_TeI.cif"), primitive=False) for k, v in numb_slabs.items(): trclnc_TeI = SlabGenerator(TeI, k, 10, 10) TeI_slabs = trclnc_TeI.get_slabs() self.assertEqual(v, len(TeI_slabs)) def test_get_orthogonal_c_slab(self): TeI = Structure.from_file(get_path("icsd_TeI.cif"), primitive=False) trclnc_TeI = SlabGenerator(TeI, (0, 0, 1), 10, 10) TeI_slabs = trclnc_TeI.get_slabs() slab = TeI_slabs[0] norm_slab = slab.get_orthogonal_c_slab() self.assertAlmostEqual(norm_slab.lattice.angles[0], 90) self.assertAlmostEqual(norm_slab.lattice.angles[1], 90) def test_get_tasker2_slabs(self): # The uneven distribution of ions on the (111) facets of Halite # type slabs are typical examples of Tasker 3 structures. We # will test this algo to generate a Tasker 2 structure instead slabgen = SlabGenerator(self.MgO, (1, 1, 1), 10, 10, max_normal_search=1) # We generate the Tasker 3 structure first slab = slabgen.get_slabs()[0] self.assertFalse(slab.is_symmetric()) self.assertTrue(slab.is_polar()) # Now to generate the Tasker 2 structure, we must # ensure there are enough ions on top to move around slab.make_supercell([2, 1, 1]) slabs = slab.get_tasker2_slabs() # Check if our Tasker 2 slab is nonpolar and symmetric for slab in slabs: self.assertTrue(slab.is_symmetric()) self.assertFalse(slab.is_polar()) def test_nonstoichiometric_symmetrized_slab(self): # For the (111) halite slab, sometimes a nonstoichiometric # system is preferred over the stoichiometric Tasker 2. slabgen = SlabGenerator(self.MgO, (1, 1, 1), 10, 10, max_normal_search=1) slabs = slabgen.get_slabs(symmetrize=True) # We should end up with two terminations, one with # an Mg rich surface and another O rich surface self.assertEqual(len(slabs), 2) for slab in slabs: self.assertTrue(slab.is_symmetric()) # For a low symmetry primitive_elemental system such as # R-3m, there should be some nonsymmetric slabs # without using nonstoichiometric_symmetrized_slab slabs = generate_all_slabs(self.Dy, 1, 30, 30, center_slab=True, symmetrize=True) for s in slabs: self.assertTrue(s.is_symmetric()) self.assertGreater(len(s), len(self.Dy)) def test_move_to_other_side(self): # Tests to see if sites are added to opposite side s = self.get_structure("LiFePO4") slabgen = SlabGenerator(s, (0, 0, 1), 10, 10, center_slab=True) slab = slabgen.get_slab() surface_sites = slab.get_surface_sites() # check if top sites are moved to the bottom top_index = [ss[1] for ss in surface_sites["top"]] slab = slabgen.move_to_other_side(slab, top_index) all_bottom = [slab[i].frac_coords[2] < slab.center_of_mass[2] for i in top_index] self.assertTrue(all(all_bottom)) # check if bottom sites are moved to the top bottom_index = [ss[1] for ss in surface_sites["bottom"]] slab = slabgen.move_to_other_side(slab, bottom_index) all_top = [slab[i].frac_coords[2] > slab.center_of_mass[2] for i in bottom_index] self.assertTrue(all(all_top))
class StructureTest(PymatgenTest): def setUp(self): 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]]) self.structure = Structure(lattice, ["Si", "Si"], coords) def test_mutable_sequence_methods(self): s = self.structure s[0] = "Fe" self.assertEqual(s.formula, "Fe1 Si1") s[0] = "Fe", [0.5, 0.5, 0.5] self.assertEqual(s.formula, "Fe1 Si1") self.assertArrayAlmostEqual(s[0].frac_coords, [0.5, 0.5, 0.5]) s.reverse() self.assertEqual(s[0].specie, Element("Si")) self.assertArrayAlmostEqual(s[0].frac_coords, [0.75, 0.5, 0.75]) s[0] = {"Mn": 0.5} self.assertEqual(s.formula, "Mn0.5 Fe1") del s[1] self.assertEqual(s.formula, "Mn0.5") s[0] = "Fe", [0.9, 0.9, 0.9], {"magmom": 5} self.assertEqual(s.formula, "Fe1") self.assertEqual(s[0].magmom, 5) # Test atomic replacement. s["Fe"] = "Mn" self.assertEqual(s.formula, "Mn1") # Test slice replacement. s = PymatgenTest.get_structure("Li2O") s[1:3] = "S" self.assertEqual(s.formula, "Li1 S2") def test_non_hash(self): self.assertRaises(TypeError, dict, [(self.structure, 1)]) def test_sort(self): s = self.structure s[0] = "F" s.sort() self.assertEqual(s[0].species_string, "Si") self.assertEqual(s[1].species_string, "F") s.sort(key=lambda site: site.species_string) self.assertEqual(s[0].species_string, "F") self.assertEqual(s[1].species_string, "Si") s.sort(key=lambda site: site.species_string, reverse=True) self.assertEqual(s[0].species_string, "Si") self.assertEqual(s[1].species_string, "F") def test_append_insert_remove_replace(self): s = self.structure s.insert(1, "O", [0.5, 0.5, 0.5]) self.assertEqual(s.formula, "Si2 O1") self.assertTrue(s.ntypesp == 2) self.assertTrue(s.symbol_set == ("Si", "O")) self.assertTrue(s.indices_from_symbol("Si") == (0, 2)) self.assertTrue(s.indices_from_symbol("O") == (1, )) del s[2] self.assertEqual(s.formula, "Si1 O1") self.assertTrue(s.indices_from_symbol("Si") == (0, )) self.assertTrue(s.indices_from_symbol("O") == (1, )) s.append("N", [0.25, 0.25, 0.25]) self.assertEqual(s.formula, "Si1 N1 O1") self.assertTrue(s.ntypesp == 3) self.assertTrue(s.symbol_set == ("Si", "O", "N")) self.assertTrue(s.indices_from_symbol("Si") == (0, )) self.assertTrue(s.indices_from_symbol("O") == (1, )) self.assertTrue(s.indices_from_symbol("N") == (2, )) s[0] = "Ge" self.assertEqual(s.formula, "Ge1 N1 O1") self.assertTrue(s.symbol_set == ("Ge", "O", "N")) s.replace_species({"Ge": "Si"}) self.assertEqual(s.formula, "Si1 N1 O1") self.assertTrue(s.ntypesp == 3) s.replace_species({"Si": {"Ge": 0.5, "Si": 0.5}}) self.assertEqual(s.formula, "Si0.5 Ge0.5 N1 O1") #this should change the .5Si .5Ge sites to .75Si .25Ge s.replace_species({"Ge": {"Ge": 0.5, "Si": 0.5}}) self.assertEqual(s.formula, "Si0.75 Ge0.25 N1 O1") # In this case, s.ntypesp is ambiguous. # for the time being, we raise AttributeError. with self.assertRaises(AttributeError): s.ntypesp s.remove_species(["Si"]) self.assertEqual(s.formula, "Ge0.25 N1 O1") s.remove_sites([1, 2]) self.assertEqual(s.formula, "Ge0.25") def test_add_site_property(self): s = self.structure s.add_site_property("charge", [4.1, -5]) self.assertEqual(s[0].charge, 4.1) self.assertEqual(s[1].charge, -5) s.add_site_property("magmom", [3, 2]) self.assertEqual(s[0].charge, 4.1) self.assertEqual(s[0].magmom, 3) def test_propertied_structure(self): #Make sure that site properties are set to None for missing values. s = self.structure s.add_site_property("charge", [4.1, -5]) s.append("Li", [0.3, 0.3, 0.3]) self.assertEqual(len(s.site_properties["charge"]), 3) def test_perturb(self): d = 0.1 pre_perturbation_sites = self.structure.sites[:] self.structure.perturb(distance=d) post_perturbation_sites = self.structure.sites for i, x in enumerate(pre_perturbation_sites): self.assertAlmostEqual(x.distance(post_perturbation_sites[i]), d, 3, "Bad perturbation distance") def test_add_oxidation_states(self): oxidation_states = {"Si": -4} self.structure.add_oxidation_state_by_element(oxidation_states) for site in self.structure: for k in site.species_and_occu.keys(): self.assertEqual(k.oxi_state, oxidation_states[k.symbol], "Wrong oxidation state assigned!") oxidation_states = {"Fe": 2} self.assertRaises(ValueError, self.structure.add_oxidation_state_by_element, oxidation_states) self.structure.add_oxidation_state_by_site([2, -4]) self.assertEqual(self.structure[0].specie.oxi_state, 2) self.assertRaises(ValueError, self.structure.add_oxidation_state_by_site, [1]) def test_remove_oxidation_states(self): co_elem = Element("Co") o_elem = Element("O") co_specie = Specie("Co", 2) o_specie = Specie("O", -2) coords = list() coords.append([0, 0, 0]) coords.append([0.75, 0.5, 0.75]) lattice = Lattice.cubic(10) s_elem = Structure(lattice, [co_elem, o_elem], coords) s_specie = Structure(lattice, [co_specie, o_specie], coords) s_specie.remove_oxidation_states() self.assertEqual(s_elem, s_specie, "Oxidation state remover " "failed") def test_apply_operation(self): op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 90) s = self.structure.copy() s.apply_operation(op) self.assertArrayAlmostEqual( s.lattice.matrix, [[0.000000, 3.840198, 0.000000], [-3.325710, 1.920099, 0.000000], [2.217138, -0.000000, 3.135509]], 5) op = SymmOp([[1, 1, 0, 0.5], [1, 0, 0, 0.5], [0, 0, 1, 0.5], [0, 0, 0, 1]]) s = self.structure.copy() s.apply_operation(op, fractional=True) self.assertArrayAlmostEqual( s.lattice.matrix, [[5.760297, 3.325710, 0.000000], [3.840198, 0.000000, 0.000000], [0.000000, -2.217138, 3.135509]], 5) def test_apply_strain(self): s = self.structure initial_coord = s[1].coords s.apply_strain(0.01) self.assertAlmostEqual( s.lattice.abc, (3.8785999130369997, 3.878600984287687, 3.8785999130549516)) self.assertArrayAlmostEqual(s[1].coords, initial_coord * 1.01) a1, b1, c1 = s.lattice.abc s.apply_strain([0.1, 0.2, 0.3]) a2, b2, c2 = s.lattice.abc self.assertAlmostEqual(a2 / a1, 1.1) self.assertAlmostEqual(b2 / b1, 1.2) self.assertAlmostEqual(c2 / c1, 1.3) def test_scale_lattice(self): initial_coord = self.structure[1].coords self.structure.scale_lattice(self.structure.volume * 1.01**3) self.assertArrayAlmostEqual( self.structure.lattice.abc, (3.8785999130369997, 3.878600984287687, 3.8785999130549516)) self.assertArrayAlmostEqual(self.structure[1].coords, initial_coord * 1.01) def test_translate_sites(self): self.structure.translate_sites([0, 1], [0.5, 0.5, 0.5], frac_coords=True) self.assertArrayEqual(self.structure.frac_coords[0], [0.5, 0.5, 0.5]) self.structure.translate_sites([0], [0.5, 0.5, 0.5], frac_coords=False) self.assertArrayAlmostEqual(self.structure.cart_coords[0], [3.38014845, 1.05428585, 2.06775453]) self.structure.translate_sites([0], [0.5, 0.5, 0.5], frac_coords=True, to_unit_cell=False) self.assertArrayAlmostEqual(self.structure.frac_coords[0], [1.00187517, 1.25665291, 1.15946374]) def test_mul(self): self.structure *= [2, 1, 1] self.assertEqual(self.structure.formula, "Si4") s = [2, 1, 1] * self.structure self.assertEqual(s.formula, "Si8") self.assertIsInstance(s, Structure) s = self.structure * [[1, 0, 0], [2, 1, 0], [0, 0, 2]] self.assertEqual(s.formula, "Si8") self.assertArrayAlmostEqual(s.lattice.abc, [7.6803959, 17.5979979, 7.6803959]) def test_make_supercell(self): self.structure.make_supercell([2, 1, 1]) self.assertEqual(self.structure.formula, "Si4") self.structure.make_supercell([[1, 0, 0], [2, 1, 0], [0, 0, 1]]) self.assertEqual(self.structure.formula, "Si4") self.structure.make_supercell(2) self.assertEqual(self.structure.formula, "Si32") self.assertArrayAlmostEqual(self.structure.lattice.abc, [15.360792, 35.195996, 7.680396], 5) def test_disordered_supercell_primitive_cell(self): l = Lattice.cubic(2) f = [[0.5, 0.5, 0.5]] sp = [{'Si': 0.54738}] s = Structure(l, sp, f) #this supercell often breaks things s.make_supercell([[0, -1, 1], [-1, 1, 0], [1, 1, 1]]) self.assertEqual(len(s.get_primitive_structure()), 1) def test_another_supercell(self): #this is included b/c for some reason the old algo was failing on it s = self.structure.copy() s.make_supercell([[0, 2, 2], [2, 0, 2], [2, 2, 0]]) self.assertEqual(s.formula, "Si32") s = self.structure.copy() s.make_supercell([[0, 2, 0], [1, 0, 0], [0, 0, 1]]) self.assertEqual(s.formula, "Si4") def test_to_from_dict(self): d = self.structure.as_dict() s2 = Structure.from_dict(d) self.assertEqual(type(s2), Structure) def test_to_from_abivars(self): """Test as_dict, from_dict with fmt == abivars.""" d = self.structure.as_dict(fmt="abivars") s2 = Structure.from_dict(d, fmt="abivars") self.assertEqual(s2, self.structure) self.assertEqual(type(s2), Structure) def test_to_from_file_string(self): for fmt in ["cif", "json", "poscar", "cssr", "yaml", "xsf"]: s = self.structure.to(fmt=fmt) self.assertIsNotNone(s) ss = Structure.from_str(s, fmt=fmt) self.assertArrayAlmostEqual( ss.lattice.lengths_and_angles, self.structure.lattice.lengths_and_angles, decimal=5) self.assertArrayAlmostEqual(ss.frac_coords, self.structure.frac_coords) self.assertIsInstance(ss, Structure) self.structure.to(filename="POSCAR.testing") self.assertTrue(os.path.exists("POSCAR.testing")) os.remove("POSCAR.testing") self.structure.to(filename="structure_testing.json") self.assertTrue(os.path.exists("structure_testing.json")) s = Structure.from_file("structure_testing.json") self.assertEqual(s, self.structure) os.remove("structure_testing.json") def test_from_spacegroup(self): s1 = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3), ["Li", "O"], [[0.25, 0.25, 0.25], [0, 0, 0]]) self.assertEqual(s1.formula, "Li8 O4") s2 = Structure.from_spacegroup(225, Lattice.cubic(3), ["Li", "O"], [[0.25, 0.25, 0.25], [0, 0, 0]]) self.assertEqual(s1, s2) s2 = Structure.from_spacegroup(225, Lattice.cubic(3), ["Li", "O"], [[0.25, 0.25, 0.25], [0, 0, 0]], site_properties={"charge": [1, -2]}) self.assertEqual(sum(s2.site_properties["charge"]), 0) s = Structure.from_spacegroup("Pm-3m", Lattice.cubic(3), ["Cs", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]]) self.assertEqual(s.formula, "Cs1 Cl1") self.assertRaises(ValueError, Structure.from_spacegroup, "Pm-3m", Lattice.tetragonal(1, 3), ["Cs", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]]) self.assertRaises(ValueError, Structure.from_spacegroup, "Pm-3m", Lattice.cubic(3), ["Cs"], [[0, 0, 0], [0.5, 0.5, 0.5]]) def test_from_magnetic_spacegroup(self): # AFM MnF s1 = Structure.from_magnetic_spacegroup( "P4_2'/mnm'", Lattice.tetragonal(4.87, 3.30), ["Mn", "F"], [[0, 0, 0], [0.30, 0.30, 0.00]], {'magmom': [4, 0]}) self.assertEqual(s1.formula, "Mn2 F4") self.assertEqual(sum(map(float, s1.site_properties['magmom'])), 0) self.assertEqual(max(map(float, s1.site_properties['magmom'])), 4) self.assertEqual(min(map(float, s1.site_properties['magmom'])), -4) # AFM LaMnO3, ordered on (001) planes s2 = Structure.from_magnetic_spacegroup( "Pn'ma'", Lattice.orthorhombic(5.75, 7.66, 5.53), ["La", "Mn", "O", "O"], [[0.05, 0.25, 0.99], [0.00, 0.00, 0.50], [0.48, 0.25, 0.08], [0.31, 0.04, 0.72]], {'magmom': [0, Magmom([4, 0, 0]), 0, 0]}) self.assertEqual(s2.formula, "La4 Mn4 O12") self.assertEqual(sum(map(float, s2.site_properties['magmom'])), 0) self.assertEqual(max(map(float, s2.site_properties['magmom'])), 4) self.assertEqual(min(map(float, s2.site_properties['magmom'])), -4) def test_merge_sites(self): species = [{ 'Ag': 0.5 }, { 'Cl': 0.25 }, { 'Cl': 0.1 }, { 'Ag': 0.5 }, { 'F': 0.15 }, { 'F': 0.1 }] coords = [[0, 0, 0], [0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [0, 0, 0], [0.5, 0.5, 1.501], [0.5, 0.5, 1.501]] s = Structure(Lattice.cubic(1), species, coords) s.merge_sites(mode="s") self.assertEqual(s[0].specie.symbol, 'Ag') self.assertEqual(s[1].species_and_occu, Composition({ 'Cl': 0.35, 'F': 0.25 })) self.assertArrayAlmostEqual(s[1].frac_coords, [.5, .5, .5005]) # Test for TaS2 with spacegroup 166 in 160 setting. l = Lattice.from_lengths_and_angles([3.374351, 3.374351, 20.308941], [90.000000, 90.000000, 120.000000]) species = ["Ta", "S", "S"] coords = [[0.000000, 0.000000, 0.944333], [0.333333, 0.666667, 0.353424], [0.666667, 0.333333, 0.535243]] tas2 = Structure.from_spacegroup(160, l, species, coords) assert len(tas2) == 13 tas2.merge_sites(mode="d") assert len(tas2) == 9 l = Lattice.from_lengths_and_angles([3.587776, 3.587776, 19.622793], [90.000000, 90.000000, 120.000000]) species = ["Na", "V", "S", "S"] coords = [[0.333333, 0.666667, 0.165000], [0.000000, 0.000000, 0.998333], [0.333333, 0.666667, 0.399394], [0.666667, 0.333333, 0.597273]] navs2 = Structure.from_spacegroup(160, l, species, coords) assert len(navs2) == 18 navs2.merge_sites(mode="d") assert len(navs2) == 12 def test_properties(self): self.assertEqual(self.structure.num_sites, len(self.structure)) self.structure.make_supercell(2) self.structure[1] = "C" sites = list(self.structure.group_by_types()) self.assertEqual(sites[-1].specie.symbol, "C") self.structure.add_oxidation_state_by_element({"Si": 4, "C": 2}) self.assertEqual(self.structure.charge, 62) def test_set_item(self): s = self.structure.copy() s[0] = "C" self.assertEqual(s.formula, "Si1 C1") s[(0, 1)] = "Ge" self.assertEqual(s.formula, "Ge2") s[0:2] = "Sn" self.assertEqual(s.formula, "Sn2") s = self.structure.copy() s["Si"] = "C" self.assertEqual(s.formula, "C2") s["C"] = "C0.25Si0.5" self.assertEqual(s.formula, "Si1 C0.5") s["C"] = "C0.25Si0.5" self.assertEqual(s.formula, "Si1.25 C0.125") def test_init_error(self): self.assertRaises(StructureError, Structure, Lattice.cubic(3), ["Si"], [[0, 0, 0], [0.5, 0.5, 0.5]]) def test_from_sites(self): self.structure.add_site_property("hello", [1, 2]) s = Structure.from_sites(self.structure, to_unit_cell=True) self.assertEqual(s.site_properties["hello"][1], 2) def test_magic(self): s = Structure.from_sites(self.structure) self.assertEqual(s, self.structure) self.assertNotEqual(s, None) s.apply_strain(0.5) self.assertNotEqual(s, self.structure) self.assertNotEqual(self.structure * 2, self.structure)
class StructureTest(PymatgenTest): def setUp(self): 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]]) self.structure = Structure(lattice, ["Si", "Si"], coords) def test_non_hash(self): self.assertRaises(TypeError, dict, [(self.structure, 1)]) def test_append_insert_remove_replace(self): s = self.structure s.insert(1, "O", [0.5, 0.5, 0.5]) self.assertEqual(s.formula, "Si2 O1") self.assertTrue(s.ntypesp == 2) self.assertTrue(s.symbol_set == ("Si", "O")) self.assertTrue(s.indices_from_symbol("Si") == (0,2)) self.assertTrue(s.indices_from_symbol("O") == (1,)) s.remove(2) self.assertEqual(s.formula, "Si1 O1") self.assertTrue(s.indices_from_symbol("Si") == (0,)) self.assertTrue(s.indices_from_symbol("O") == (1,)) s.append("N", [0.25, 0.25, 0.25]) self.assertEqual(s.formula, "Si1 N1 O1") self.assertTrue(s.ntypesp == 3) self.assertTrue(s.symbol_set == ("Si", "O", "N")) self.assertTrue(s.indices_from_symbol("Si") == (0,)) self.assertTrue(s.indices_from_symbol("O") == (1,)) self.assertTrue(s.indices_from_symbol("N") == (2,)) s.replace(0, "Ge") self.assertEqual(s.formula, "Ge1 N1 O1") self.assertTrue(s.symbol_set == ("Ge", "O", "N")) s.replace_species({"Ge": "Si"}) self.assertEqual(s.formula, "Si1 N1 O1") self.assertTrue(s.ntypesp == 3) s.replace_species({"Si": {"Ge": 0.5, "Si": 0.5}}) self.assertEqual(s.formula, "Si0.5 Ge0.5 N1 O1") #this should change the .5Si .5Ge sites to .75Si .25Ge s.replace_species({"Ge": {"Ge": 0.5, "Si": 0.5}}) self.assertEqual(s.formula, "Si0.75 Ge0.25 N1 O1") # In this case, s.ntypesp is ambiguous. # for the time being, we raise AttributeError. with self.assertRaises(AttributeError): s.ntypesp s.remove_species(["Si"]) self.assertEqual(s.formula, "Ge0.25 N1 O1") s.remove_sites([1, 2]) self.assertEqual(s.formula, "Ge0.25") def test_add_site_property(self): s = self.structure s.add_site_property("charge", [4.1, -5]) self.assertEqual(s[0].charge, 4.1) self.assertEqual(s[1].charge, -5) s.add_site_property("magmom", [3, 2]) self.assertEqual(s[0].charge, 4.1) self.assertEqual(s[0].magmom, 3) def test_perturb(self): d = 0.1 pre_perturbation_sites = self.structure.sites[:] self.structure.perturb(distance=d) post_perturbation_sites = self.structure.sites for i, x in enumerate(pre_perturbation_sites): self.assertAlmostEqual(x.distance(post_perturbation_sites[i]), d, 3, "Bad perturbation distance") def test_add_oxidation_states(self): oxidation_states = {"Si": -4} self.structure.add_oxidation_state_by_element(oxidation_states) for site in self.structure: for k in site.species_and_occu.keys(): self.assertEqual(k.oxi_state, oxidation_states[k.symbol], "Wrong oxidation state assigned!") oxidation_states = {"Fe": 2} self.assertRaises(ValueError, self.structure.add_oxidation_state_by_element, oxidation_states) self.structure.add_oxidation_state_by_site([2, -4]) self.assertEqual(self.structure[0].specie.oxi_state, 2) self.assertRaises(ValueError, self.structure.add_oxidation_state_by_site, [1]) def test_remove_oxidation_states(self): co_elem = Element("Co") o_elem = Element("O") co_specie = Specie("Co", 2) o_specie = Specie("O", -2) coords = list() coords.append([0, 0, 0]) coords.append([0.75, 0.5, 0.75]) lattice = Lattice.cubic(10) s_elem = Structure(lattice, [co_elem, o_elem], coords) s_specie = Structure(lattice, [co_specie, o_specie], coords) s_specie.remove_oxidation_states() self.assertEqual(s_elem, s_specie, "Oxidation state remover " "failed") def test_apply_operation(self): op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 90) self.structure.apply_operation(op) self.assertArrayAlmostEqual( self.structure.lattice.matrix, [[0.000000, 3.840198, 0.000000], [-3.325710, 1.920099, 0.000000], [2.217138, -0.000000, 3.135509]], 5) def test_apply_strain(self): self.structure.apply_strain(0.01) self.assertAlmostEqual( self.structure.lattice.abc, (3.8785999130369997, 3.878600984287687, 3.8785999130549516)) def test_translate_sites(self): self.structure.translate_sites([0, 1], [0.5, 0.5, 0.5], frac_coords=True) self.assertArrayEqual(self.structure.frac_coords[0], [0.5, 0.5, 0.5]) self.structure.translate_sites([0], [0.5, 0.5, 0.5], frac_coords=False) self.assertArrayAlmostEqual(self.structure.cart_coords[0], [3.38014845, 1.05428585, 2.06775453]) def test_make_supercell(self): self.structure.make_supercell([2, 1, 1]) self.assertEqual(self.structure.formula, "Si4") self.structure.make_supercell([[1, 0, 0], [2, 1, 0], [0, 0, 1]]) self.assertEqual(self.structure.formula, "Si4") self.structure.make_supercell(2) self.assertEqual(self.structure.formula, "Si32") self.assertArrayAlmostEqual(self.structure.lattice.abc, [15.360792, 35.195996, 7.680396], 5) def test_to_from_dict(self): d = self.structure.to_dict s2 = Structure.from_dict(d) self.assertEqual(type(s2), Structure)
class StructureTest(PymatgenTest): def setUp(self): 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]]) self.structure = Structure(lattice, ["Si", "Si"], coords) def test_mutable_sequence_methods(self): s = self.structure s[0] = "Fe" self.assertEqual(s.formula, "Fe1 Si1") s[0] = "Fe", [0.5, 0.5, 0.5] self.assertEqual(s.formula, "Fe1 Si1") self.assertArrayAlmostEqual(s[0].frac_coords, [0.5, 0.5, 0.5]) s.reverse() self.assertEqual(s[0].specie, Element("Si")) self.assertArrayAlmostEqual(s[0].frac_coords, [0.75, 0.5, 0.75]) s[0] = {"Mn": 0.5} self.assertEqual(s.formula, "Mn0.5 Fe1") del s[1] self.assertEqual(s.formula, "Mn0.5") s[0] = "Fe", [0.9, 0.9, 0.9], {"magmom": 5} self.assertEqual(s.formula, "Fe1") self.assertEqual(s[0].magmom, 5) def test_non_hash(self): self.assertRaises(TypeError, dict, [(self.structure, 1)]) def test_append_insert_remove_replace(self): s = self.structure s.insert(1, "O", [0.5, 0.5, 0.5]) self.assertEqual(s.formula, "Si2 O1") self.assertTrue(s.ntypesp == 2) self.assertTrue(s.symbol_set == ("Si", "O")) self.assertTrue(s.indices_from_symbol("Si") == (0,2)) self.assertTrue(s.indices_from_symbol("O") == (1,)) s.remove(2) self.assertEqual(s.formula, "Si1 O1") self.assertTrue(s.indices_from_symbol("Si") == (0,)) self.assertTrue(s.indices_from_symbol("O") == (1,)) s.append("N", [0.25, 0.25, 0.25]) self.assertEqual(s.formula, "Si1 N1 O1") self.assertTrue(s.ntypesp == 3) self.assertTrue(s.symbol_set == ("Si", "O", "N")) self.assertTrue(s.indices_from_symbol("Si") == (0,)) self.assertTrue(s.indices_from_symbol("O") == (1,)) self.assertTrue(s.indices_from_symbol("N") == (2,)) s.replace(0, "Ge") self.assertEqual(s.formula, "Ge1 N1 O1") self.assertTrue(s.symbol_set == ("Ge", "O", "N")) s.replace_species({"Ge": "Si"}) self.assertEqual(s.formula, "Si1 N1 O1") self.assertTrue(s.ntypesp == 3) s.replace_species({"Si": {"Ge": 0.5, "Si": 0.5}}) self.assertEqual(s.formula, "Si0.5 Ge0.5 N1 O1") #this should change the .5Si .5Ge sites to .75Si .25Ge s.replace_species({"Ge": {"Ge": 0.5, "Si": 0.5}}) self.assertEqual(s.formula, "Si0.75 Ge0.25 N1 O1") # In this case, s.ntypesp is ambiguous. # for the time being, we raise AttributeError. with self.assertRaises(AttributeError): s.ntypesp s.remove_species(["Si"]) self.assertEqual(s.formula, "Ge0.25 N1 O1") s.remove_sites([1, 2]) self.assertEqual(s.formula, "Ge0.25") def test_add_site_property(self): s = self.structure s.add_site_property("charge", [4.1, -5]) self.assertEqual(s[0].charge, 4.1) self.assertEqual(s[1].charge, -5) s.add_site_property("magmom", [3, 2]) self.assertEqual(s[0].charge, 4.1) self.assertEqual(s[0].magmom, 3) def test_perturb(self): d = 0.1 pre_perturbation_sites = self.structure.sites[:] self.structure.perturb(distance=d) post_perturbation_sites = self.structure.sites for i, x in enumerate(pre_perturbation_sites): self.assertAlmostEqual(x.distance(post_perturbation_sites[i]), d, 3, "Bad perturbation distance") def test_add_oxidation_states(self): oxidation_states = {"Si": -4} self.structure.add_oxidation_state_by_element(oxidation_states) for site in self.structure: for k in site.species_and_occu.keys(): self.assertEqual(k.oxi_state, oxidation_states[k.symbol], "Wrong oxidation state assigned!") oxidation_states = {"Fe": 2} self.assertRaises(ValueError, self.structure.add_oxidation_state_by_element, oxidation_states) self.structure.add_oxidation_state_by_site([2, -4]) self.assertEqual(self.structure[0].specie.oxi_state, 2) self.assertRaises(ValueError, self.structure.add_oxidation_state_by_site, [1]) def test_remove_oxidation_states(self): co_elem = Element("Co") o_elem = Element("O") co_specie = Specie("Co", 2) o_specie = Specie("O", -2) coords = list() coords.append([0, 0, 0]) coords.append([0.75, 0.5, 0.75]) lattice = Lattice.cubic(10) s_elem = Structure(lattice, [co_elem, o_elem], coords) s_specie = Structure(lattice, [co_specie, o_specie], coords) s_specie.remove_oxidation_states() self.assertEqual(s_elem, s_specie, "Oxidation state remover " "failed") def test_apply_operation(self): op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 90) self.structure.apply_operation(op) self.assertArrayAlmostEqual( self.structure.lattice.matrix, [[0.000000, 3.840198, 0.000000], [-3.325710, 1.920099, 0.000000], [2.217138, -0.000000, 3.135509]], 5) def test_apply_strain(self): s = self.structure initial_coord = s[1].coords s.apply_strain(0.01) self.assertAlmostEqual( s.lattice.abc, (3.8785999130369997, 3.878600984287687, 3.8785999130549516)) self.assertArrayAlmostEqual(s[1].coords, initial_coord * 1.01) a1, b1, c1 = s.lattice.abc s.apply_strain([0.1, 0.2, 0.3]) a2, b2, c2 = s.lattice.abc self.assertAlmostEqual(a2 / a1, 1.1) self.assertAlmostEqual(b2 / b1, 1.2) self.assertAlmostEqual(c2 / c1, 1.3) def test_scale_lattice(self): initial_coord = self.structure[1].coords self.structure.scale_lattice(self.structure.volume * 1.01 ** 3) self.assertArrayAlmostEqual( self.structure.lattice.abc, (3.8785999130369997, 3.878600984287687, 3.8785999130549516)) self.assertArrayAlmostEqual(self.structure[1].coords, initial_coord * 1.01) def test_translate_sites(self): self.structure.translate_sites([0, 1], [0.5, 0.5, 0.5], frac_coords=True) self.assertArrayEqual(self.structure.frac_coords[0], [0.5, 0.5, 0.5]) self.structure.translate_sites([0], [0.5, 0.5, 0.5], frac_coords=False) self.assertArrayAlmostEqual(self.structure.cart_coords[0], [3.38014845, 1.05428585, 2.06775453]) self.structure.translate_sites([0], [0.5, 0.5, 0.5], frac_coords=True, to_unit_cell=False) self.assertArrayAlmostEqual(self.structure.frac_coords[0], [1.00187517, 1.25665291, 1.15946374]) def test_make_supercell(self): self.structure.make_supercell([2, 1, 1]) self.assertEqual(self.structure.formula, "Si4") self.structure.make_supercell([[1, 0, 0], [2, 1, 0], [0, 0, 1]]) self.assertEqual(self.structure.formula, "Si4") self.structure.make_supercell(2) self.assertEqual(self.structure.formula, "Si32") self.assertArrayAlmostEqual(self.structure.lattice.abc, [15.360792, 35.195996, 7.680396], 5) def test_disordered_supercell_primitive_cell(self): l = Lattice.cubic(2) f = [[0.5, 0.5, 0.5]] sp = [{'Si': 0.54738}] s = Structure(l, sp, f) #this supercell often breaks things s.make_supercell([[0,-1,1],[-1,1,0],[1,1,1]]) self.assertEqual(len(s.get_primitive_structure()), 1) def test_another_supercell(self): #this is included b/c for some reason the old algo was failing on it s = self.structure.copy() s.make_supercell([[0, 2, 2], [2, 0, 2], [2, 2, 0]]) self.assertEqual(s.formula, "Si32") s = self.structure.copy() s.make_supercell([[0, 2, 0], [1, 0, 0], [0, 0, 1]]) self.assertEqual(s.formula, "Si4") def test_to_from_dict(self): d = self.structure.to_dict s2 = Structure.from_dict(d) self.assertEqual(type(s2), Structure)
class StructureTest(PymatgenTest): def setUp(self): 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]]) self.structure = Structure(lattice, ["Si", "Si"], coords) def test_mutable_sequence_methods(self): s = self.structure s[0] = "Fe" self.assertEqual(s.formula, "Fe1 Si1") s[0] = "Fe", [0.5, 0.5, 0.5] self.assertEqual(s.formula, "Fe1 Si1") self.assertArrayAlmostEqual(s[0].frac_coords, [0.5, 0.5, 0.5]) s.reverse() self.assertEqual(s[0].specie, Element("Si")) self.assertArrayAlmostEqual(s[0].frac_coords, [0.75, 0.5, 0.75]) s[0] = {"Mn": 0.5} self.assertEqual(s.formula, "Mn0.5 Fe1") del s[1] self.assertEqual(s.formula, "Mn0.5") s[0] = "Fe", [0.9, 0.9, 0.9], {"magmom": 5} self.assertEqual(s.formula, "Fe1") self.assertEqual(s[0].magmom, 5) def test_non_hash(self): self.assertRaises(TypeError, dict, [(self.structure, 1)]) def test_sort(self): s = self.structure s[0] = "F" s.sort() self.assertEqual(s[0].species_string, "Si") self.assertEqual(s[1].species_string, "F") s.sort(key=lambda site: site.species_string) self.assertEqual(s[0].species_string, "F") self.assertEqual(s[1].species_string, "Si") s.sort(key=lambda site: site.species_string, reverse=True) self.assertEqual(s[0].species_string, "Si") self.assertEqual(s[1].species_string, "F") def test_append_insert_remove_replace(self): s = self.structure s.insert(1, "O", [0.5, 0.5, 0.5]) self.assertEqual(s.formula, "Si2 O1") self.assertTrue(s.ntypesp == 2) self.assertTrue(s.symbol_set == ("Si", "O")) self.assertTrue(s.indices_from_symbol("Si") == (0, 2)) self.assertTrue(s.indices_from_symbol("O") == (1, )) del s[2] self.assertEqual(s.formula, "Si1 O1") self.assertTrue(s.indices_from_symbol("Si") == (0, )) self.assertTrue(s.indices_from_symbol("O") == (1, )) s.append("N", [0.25, 0.25, 0.25]) self.assertEqual(s.formula, "Si1 N1 O1") self.assertTrue(s.ntypesp == 3) self.assertTrue(s.symbol_set == ("Si", "O", "N")) self.assertTrue(s.indices_from_symbol("Si") == (0, )) self.assertTrue(s.indices_from_symbol("O") == (1, )) self.assertTrue(s.indices_from_symbol("N") == (2, )) s[0] = "Ge" self.assertEqual(s.formula, "Ge1 N1 O1") self.assertTrue(s.symbol_set == ("Ge", "O", "N")) s.replace_species({"Ge": "Si"}) self.assertEqual(s.formula, "Si1 N1 O1") self.assertTrue(s.ntypesp == 3) s.replace_species({"Si": {"Ge": 0.5, "Si": 0.5}}) self.assertEqual(s.formula, "Si0.5 Ge0.5 N1 O1") #this should change the .5Si .5Ge sites to .75Si .25Ge s.replace_species({"Ge": {"Ge": 0.5, "Si": 0.5}}) self.assertEqual(s.formula, "Si0.75 Ge0.25 N1 O1") # In this case, s.ntypesp is ambiguous. # for the time being, we raise AttributeError. with self.assertRaises(AttributeError): s.ntypesp s.remove_species(["Si"]) self.assertEqual(s.formula, "Ge0.25 N1 O1") s.remove_sites([1, 2]) self.assertEqual(s.formula, "Ge0.25") def test_add_site_property(self): s = self.structure s.add_site_property("charge", [4.1, -5]) self.assertEqual(s[0].charge, 4.1) self.assertEqual(s[1].charge, -5) s.add_site_property("magmom", [3, 2]) self.assertEqual(s[0].charge, 4.1) self.assertEqual(s[0].magmom, 3) def test_propertied_structure(self): #Make sure that site properties are set to None for missing values. s = self.structure s.add_site_property("charge", [4.1, -5]) s.append("Li", [0.3, 0.3, 0.3]) self.assertEqual(len(s.site_properties["charge"]), 3) def test_perturb(self): d = 0.1 pre_perturbation_sites = self.structure.sites[:] self.structure.perturb(distance=d) post_perturbation_sites = self.structure.sites for i, x in enumerate(pre_perturbation_sites): self.assertAlmostEqual(x.distance(post_perturbation_sites[i]), d, 3, "Bad perturbation distance") def test_add_oxidation_states(self): oxidation_states = {"Si": -4} self.structure.add_oxidation_state_by_element(oxidation_states) for site in self.structure: for k in site.species_and_occu.keys(): self.assertEqual(k.oxi_state, oxidation_states[k.symbol], "Wrong oxidation state assigned!") oxidation_states = {"Fe": 2} self.assertRaises(ValueError, self.structure.add_oxidation_state_by_element, oxidation_states) self.structure.add_oxidation_state_by_site([2, -4]) self.assertEqual(self.structure[0].specie.oxi_state, 2) self.assertRaises(ValueError, self.structure.add_oxidation_state_by_site, [1]) def test_remove_oxidation_states(self): co_elem = Element("Co") o_elem = Element("O") co_specie = Specie("Co", 2) o_specie = Specie("O", -2) coords = list() coords.append([0, 0, 0]) coords.append([0.75, 0.5, 0.75]) lattice = Lattice.cubic(10) s_elem = Structure(lattice, [co_elem, o_elem], coords) s_specie = Structure(lattice, [co_specie, o_specie], coords) s_specie.remove_oxidation_states() self.assertEqual(s_elem, s_specie, "Oxidation state remover " "failed") def test_apply_operation(self): op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 90) s = self.structure.copy() s.apply_operation(op) self.assertArrayAlmostEqual( s.lattice.matrix, [[0.000000, 3.840198, 0.000000], [-3.325710, 1.920099, 0.000000], [2.217138, -0.000000, 3.135509]], 5) op = SymmOp([[1, 1, 0, 0.5], [1, 0, 0, 0.5], [0, 0, 1, 0.5], [0, 0, 0, 1]]) s = self.structure.copy() s.apply_operation(op, fractional=True) self.assertArrayAlmostEqual( s.lattice.matrix, [[5.760297, 3.325710, 0.000000], [3.840198, 0.000000, 0.000000], [0.000000, -2.217138, 3.135509]], 5) def test_apply_strain(self): s = self.structure initial_coord = s[1].coords s.apply_strain(0.01) self.assertAlmostEqual( s.lattice.abc, (3.8785999130369997, 3.878600984287687, 3.8785999130549516)) self.assertArrayAlmostEqual(s[1].coords, initial_coord * 1.01) a1, b1, c1 = s.lattice.abc s.apply_strain([0.1, 0.2, 0.3]) a2, b2, c2 = s.lattice.abc self.assertAlmostEqual(a2 / a1, 1.1) self.assertAlmostEqual(b2 / b1, 1.2) self.assertAlmostEqual(c2 / c1, 1.3) def test_scale_lattice(self): initial_coord = self.structure[1].coords self.structure.scale_lattice(self.structure.volume * 1.01**3) self.assertArrayAlmostEqual( self.structure.lattice.abc, (3.8785999130369997, 3.878600984287687, 3.8785999130549516)) self.assertArrayAlmostEqual(self.structure[1].coords, initial_coord * 1.01) def test_translate_sites(self): self.structure.translate_sites([0, 1], [0.5, 0.5, 0.5], frac_coords=True) self.assertArrayEqual(self.structure.frac_coords[0], [0.5, 0.5, 0.5]) self.structure.translate_sites([0], [0.5, 0.5, 0.5], frac_coords=False) self.assertArrayAlmostEqual(self.structure.cart_coords[0], [3.38014845, 1.05428585, 2.06775453]) self.structure.translate_sites([0], [0.5, 0.5, 0.5], frac_coords=True, to_unit_cell=False) self.assertArrayAlmostEqual(self.structure.frac_coords[0], [1.00187517, 1.25665291, 1.15946374]) def test_mul(self): self.structure *= [2, 1, 1] self.assertEqual(self.structure.formula, "Si4") s = [2, 1, 1] * self.structure self.assertEqual(s.formula, "Si8") self.assertIsInstance(s, Structure) s = self.structure * [[1, 0, 0], [2, 1, 0], [0, 0, 2]] self.assertEqual(s.formula, "Si8") self.assertArrayAlmostEqual(s.lattice.abc, [7.6803959, 17.5979979, 7.6803959]) def test_make_supercell(self): self.structure.make_supercell([2, 1, 1]) self.assertEqual(self.structure.formula, "Si4") self.structure.make_supercell([[1, 0, 0], [2, 1, 0], [0, 0, 1]]) self.assertEqual(self.structure.formula, "Si4") self.structure.make_supercell(2) self.assertEqual(self.structure.formula, "Si32") self.assertArrayAlmostEqual(self.structure.lattice.abc, [15.360792, 35.195996, 7.680396], 5) def test_disordered_supercell_primitive_cell(self): l = Lattice.cubic(2) f = [[0.5, 0.5, 0.5]] sp = [{'Si': 0.54738}] s = Structure(l, sp, f) #this supercell often breaks things s.make_supercell([[0, -1, 1], [-1, 1, 0], [1, 1, 1]]) self.assertEqual(len(s.get_primitive_structure()), 1) def test_another_supercell(self): #this is included b/c for some reason the old algo was failing on it s = self.structure.copy() s.make_supercell([[0, 2, 2], [2, 0, 2], [2, 2, 0]]) self.assertEqual(s.formula, "Si32") s = self.structure.copy() s.make_supercell([[0, 2, 0], [1, 0, 0], [0, 0, 1]]) self.assertEqual(s.formula, "Si4") def test_to_from_dict(self): d = self.structure.as_dict() s2 = Structure.from_dict(d) self.assertEqual(type(s2), Structure) def test_to_from_file_string(self): for fmt in ["cif", "json", "poscar", "cssr", "yaml", "xsf"]: s = self.structure.to(fmt=fmt) self.assertIsNotNone(s) ss = Structure.from_str(s, fmt=fmt) self.assertArrayAlmostEqual( ss.lattice.lengths_and_angles, self.structure.lattice.lengths_and_angles, decimal=5) self.assertArrayAlmostEqual(ss.frac_coords, self.structure.frac_coords) self.assertIsInstance(ss, Structure) self.structure.to(filename="POSCAR.testing") self.assertTrue(os.path.exists("POSCAR.testing")) os.remove("POSCAR.testing") self.structure.to(filename="structure_testing.json") self.assertTrue(os.path.exists("structure_testing.json")) s = Structure.from_file("structure_testing.json") self.assertEqual(s, self.structure) os.remove("structure_testing.json") def test_from_spacegroup(self): s1 = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3), ["Li", "O"], [[0.25, 0.25, 0.25], [0, 0, 0]]) self.assertEqual(s1.formula, "Li8 O4") s2 = Structure.from_spacegroup(225, Lattice.cubic(3), ["Li", "O"], [[0.25, 0.25, 0.25], [0, 0, 0]]) self.assertEqual(s1, s2) s2 = Structure.from_spacegroup(225, Lattice.cubic(3), ["Li", "O"], [[0.25, 0.25, 0.25], [0, 0, 0]], site_properties={"charge": [1, -2]}) self.assertEqual(sum(s2.site_properties["charge"]), 0) s = Structure.from_spacegroup("Pm-3m", Lattice.cubic(3), ["Cs", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]]) self.assertEqual(s.formula, "Cs1 Cl1") self.assertRaises(ValueError, Structure.from_spacegroup, "Pm-3m", Lattice.tetragonal(1, 3), ["Cs", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]]) def test_merge_sites(self): species = [{ 'Ag': 0.5 }, { 'Cl': 0.25 }, { 'Cl': 0.1 }, { 'Ag': 0.5 }, { 'F': 0.15 }, { 'F': 0.1 }] coords = [[0, 0, 0], [0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [0, 0, 0], [0.5, 0.5, 1.501], [0.5, 0.5, 1.501]] s = Structure(Lattice.cubic(1), species, coords) s.merge_sites() self.assertEqual(s[0].specie.symbol, 'Ag') self.assertEqual(s[1].species_and_occu, Composition({ 'Cl': 0.35, 'F': 0.25 })) self.assertArrayAlmostEqual(s[1].frac_coords, [.5, .5, .5005])
class StructureTest(PymatgenTest): def setUp(self): 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]]) self.structure = Structure(lattice, ["Si", "Si"], coords) def test_non_hash(self): self.assertRaises(TypeError, dict, [(self.structure, 1)]) def test_append_insert_remove_replace(self): s = self.structure s.insert(1, "O", [0.5, 0.5, 0.5]) self.assertEqual(s.formula, "Si2 O1") self.assertTrue(s.ntypesp == 2) self.assertTrue(s.symbol_set == ("Si", "O")) self.assertTrue(s.indices_from_symbol("Si") == (0, 2)) self.assertTrue(s.indices_from_symbol("O") == (1, )) s.remove(2) self.assertEqual(s.formula, "Si1 O1") self.assertTrue(s.indices_from_symbol("Si") == (0, )) self.assertTrue(s.indices_from_symbol("O") == (1, )) s.append("N", [0.25, 0.25, 0.25]) self.assertEqual(s.formula, "Si1 N1 O1") self.assertTrue(s.ntypesp == 3) self.assertTrue(s.symbol_set == ("Si", "O", "N")) self.assertTrue(s.indices_from_symbol("Si") == (0, )) self.assertTrue(s.indices_from_symbol("O") == (1, )) self.assertTrue(s.indices_from_symbol("N") == (2, )) s.replace(0, "Ge") self.assertEqual(s.formula, "Ge1 N1 O1") self.assertTrue(s.symbol_set == ("Ge", "O", "N")) s.replace_species({"Ge": "Si"}) self.assertEqual(s.formula, "Si1 N1 O1") self.assertTrue(s.ntypesp == 3) s.replace_species({"Si": {"Ge": 0.5, "Si": 0.5}}) self.assertEqual(s.formula, "Si0.5 Ge0.5 N1 O1") #this should change the .5Si .5Ge sites to .75Si .25Ge s.replace_species({"Ge": {"Ge": 0.5, "Si": 0.5}}) self.assertEqual(s.formula, "Si0.75 Ge0.25 N1 O1") # In this case, s.ntypesp is ambiguous. # for the time being, we raise AttributeError. with self.assertRaises(AttributeError): s.ntypesp s.remove_species(["Si"]) self.assertEqual(s.formula, "Ge0.25 N1 O1") s.remove_sites([1, 2]) self.assertEqual(s.formula, "Ge0.25") def test_add_site_property(self): s = self.structure s.add_site_property("charge", [4.1, -5]) self.assertEqual(s[0].charge, 4.1) self.assertEqual(s[1].charge, -5) s.add_site_property("magmom", [3, 2]) self.assertEqual(s[0].charge, 4.1) self.assertEqual(s[0].magmom, 3) def test_perturb(self): d = 0.1 pre_perturbation_sites = self.structure.sites[:] self.structure.perturb(distance=d) post_perturbation_sites = self.structure.sites for i, x in enumerate(pre_perturbation_sites): self.assertAlmostEqual(x.distance(post_perturbation_sites[i]), d, 3, "Bad perturbation distance") def test_add_oxidation_states(self): oxidation_states = {"Si": -4} self.structure.add_oxidation_state_by_element(oxidation_states) for site in self.structure: for k in site.species_and_occu.keys(): self.assertEqual(k.oxi_state, oxidation_states[k.symbol], "Wrong oxidation state assigned!") oxidation_states = {"Fe": 2} self.assertRaises(ValueError, self.structure.add_oxidation_state_by_element, oxidation_states) self.structure.add_oxidation_state_by_site([2, -4]) self.assertEqual(self.structure[0].specie.oxi_state, 2) self.assertRaises(ValueError, self.structure.add_oxidation_state_by_site, [1]) def test_remove_oxidation_states(self): co_elem = Element("Co") o_elem = Element("O") co_specie = Specie("Co", 2) o_specie = Specie("O", -2) coords = list() coords.append([0, 0, 0]) coords.append([0.75, 0.5, 0.75]) lattice = Lattice.cubic(10) s_elem = Structure(lattice, [co_elem, o_elem], coords) s_specie = Structure(lattice, [co_specie, o_specie], coords) s_specie.remove_oxidation_states() self.assertEqual(s_elem, s_specie, "Oxidation state remover " "failed") def test_apply_operation(self): op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 90) self.structure.apply_operation(op) self.assertArrayAlmostEqual( self.structure.lattice.matrix, [[0.000000, 3.840198, 0.000000], [-3.325710, 1.920099, 0.000000], [2.217138, -0.000000, 3.135509]], 5) def test_apply_strain(self): self.structure.apply_strain(0.01) self.assertAlmostEqual( self.structure.lattice.abc, (3.8785999130369997, 3.878600984287687, 3.8785999130549516)) def test_translate_sites(self): self.structure.translate_sites([0, 1], [0.5, 0.5, 0.5], frac_coords=True) self.assertArrayEqual(self.structure.frac_coords[0], [0.5, 0.5, 0.5]) self.structure.translate_sites([0], [0.5, 0.5, 0.5], frac_coords=False) self.assertArrayAlmostEqual(self.structure.cart_coords[0], [3.38014845, 1.05428585, 2.06775453]) def test_make_supercell(self): self.structure.make_supercell([2, 1, 1]) self.assertEqual(self.structure.formula, "Si4") self.structure.make_supercell([[1, 0, 0], [2, 1, 0], [0, 0, 1]]) self.assertEqual(self.structure.formula, "Si4") self.structure.make_supercell(2) self.assertEqual(self.structure.formula, "Si32") self.assertArrayAlmostEqual(self.structure.lattice.abc, [15.360792, 35.195996, 7.680396], 5) def test_to_from_dict(self): d = self.structure.to_dict s2 = Structure.from_dict(d) self.assertEqual(type(s2), Structure)