def test_electrostatics(self): """Tests that the results are consistent with the electrostatic interpretation. Each matrix [i, j] element should correspond to the Coulomb energy of a system consisting of the pair of atoms i, j. """ system = H2O n_atoms = len(system) a = 0.5 desc = EwaldSumMatrix(n_atoms_max=3, permutation="none", flatten=False) # The Ewald matrix contains the electrostatic interaction between atoms # i and j. Here we construct the total electrostatic energy for a # system consisting of atoms i and j. matrix = desc.create(system, a=a, rcut=rcut, gcut=gcut) energy_matrix = np.zeros(matrix.shape) for i in range(n_atoms): for j in range(n_atoms): if i == j: energy_matrix[i, j] = matrix[i, j] else: energy_matrix[i, j] = matrix[i, j] + matrix[i, i] + matrix[j, j] # Converts unit of q*q/r into eV conversion = 1e10 * scipy.constants.e / (4 * math.pi * scipy.constants.epsilon_0) energy_matrix *= conversion # The value in each matrix element should correspond to the Coulomb # energy of a system with with only those atoms. Here the energies from # the Ewald matrix are compared against the Ewald energy calculated # with pymatgen. positions = system.get_positions() atomic_num = system.get_atomic_numbers() for i in range(n_atoms): for j in range(n_atoms): if i == j: pos = [positions[i]] sym = [atomic_num[i]] else: pos = [positions[i], positions[j]] sym = [atomic_num[i], atomic_num[j]] i_sys = Atoms( cell=system.get_cell(), positions=pos, symbols=sym, pbc=True, ) structure = Structure( lattice=i_sys.get_cell(), species=i_sys.get_atomic_numbers(), coords=i_sys.get_scaled_positions(), ) structure.add_oxidation_state_by_site(i_sys.get_atomic_numbers()) ewald = EwaldSummation(structure, eta=a, real_space_cut=rcut, recip_space_cut=gcut) energy = ewald.total_energy # Check that the energy given by the pymatgen implementation is # the same as given by the descriptor self.assertTrue(np.allclose(energy_matrix[i, j], energy, atol=0.00001, rtol=0))
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 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)
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)
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)
rcut = 40 gcut = 40 a = 3 # Calculate Ewald sum matrix with DScribe ems = EwaldSumMatrix(n_atoms_max=3, permutation="none", flatten=False) ems_out = ems.create(al, a=a, rcut=rcut, gcut=gcut) # Calculate the total electrostatic energy of the crystal total_energy = ems_out[0, 0] + ems_out[1, 1] + ems_out[0, 1] # Converts unit of q*q/r into eV conversion = 1e10 * scipy.constants.e / (4 * math.pi * scipy.constants.epsilon_0) total_energy *= conversion print(total_energy) # Test against implementation in pymatgen structure = Structure( lattice=al.get_cell(), species=al.get_atomic_numbers(), coords=al.get_scaled_positions(), ) structure.add_oxidation_state_by_site(al.get_atomic_numbers()) ewald = EwaldSummation(structure, eta=a, real_space_cut=rcut, recip_space_cut=gcut) energy = ewald.total_energy print(energy)
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)