def test_get_symmetry_operations(self): for sg, structure in [(self.sg, self.structure), (self.sg4, self.structure4)]: pgops = sg.get_point_group_operations() fracsymmops = sg.get_symmetry_operations() symmops = sg.get_symmetry_operations(True) latt = structure.lattice for fop, op, pgop in zip(fracsymmops, symmops, pgops): self.assertArrayAlmostEqual(fop.rotation_matrix, pgop.rotation_matrix) for site in structure: newfrac = fop.operate(site.frac_coords) newcart = op.operate(site.coords) self.assertTrue(np.allclose(latt.get_fractional_coords(newcart), newfrac)) found = False newsite = PeriodicSite(site.species_and_occu, newcart, latt, coords_are_cartesian=True) for testsite in structure: if newsite.is_periodic_image(testsite, 1e-3): found = True break self.assertTrue(found) # Make sure this works for any position, not just the atomic # ones. random_fcoord = np.random.uniform(size=(3)) random_ccoord = latt.get_cartesian_coords(random_fcoord) newfrac = fop.operate(random_fcoord) newcart = op.operate(random_ccoord) self.assertTrue(np.allclose(latt.get_fractional_coords(newcart), newfrac))
def setUp(self): self.lattice = Lattice.cubic(10.0) self.si = Element("Si") self.site = PeriodicSite("Fe", [0.25, 0.35, 0.45], self.lattice) self.site2 = PeriodicSite({"Si": 0.5}, [0, 0, 0], self.lattice) self.assertEqual(self.site2.species_and_occu, Composition({Element("Si"): 0.5}), "Inconsistent site created!") self.propertied_site = PeriodicSite( Specie("Fe", 2), [0.25, 0.35, 0.45], self.lattice, properties={"magmom": 5.1, "charge": 4.2} ) self.dummy_site = PeriodicSite("X", [0, 0, 0], self.lattice)
def test_to_from_dict(self): d = self.site2.to_dict site = PeriodicSite.from_dict(d) self.assertEqual(site, self.site2) self.assertNotEqual(site, self.site) d = self.propertied_site.to_dict site = Site.from_dict(d) self.assertEqual(site.magmom, 5.1) self.assertEqual(site.charge, 4.2) site3 = PeriodicSite({"Si": 0.5, "Fe": 0.5}, [0, 0, 0], self.lattice) d = site3.to_dict site = PeriodicSite.from_dict(d) self.assertEqual(site.species_and_occu, site3.species_and_occu)
def test_as_from_dict(self): d = self.site2.as_dict() site = PeriodicSite.from_dict(d) self.assertEqual(site, self.site2) self.assertNotEqual(site, self.site) d = self.propertied_site.as_dict() site3 = PeriodicSite({"Si": 0.5, "Fe": 0.5}, [0, 0, 0], self.lattice) d = site3.as_dict() site = PeriodicSite.from_dict(d) self.assertEqual(site.species_and_occu, site3.species_and_occu) d = self.dummy_site.as_dict() site = PeriodicSite.from_dict(d) self.assertEqual(site.species_and_occu, self.dummy_site.species_and_occu)
def _supercell_with_defect(self, scaling_matrix, defect_site): sc = self._structure.copy() sc.make_supercell(scaling_matrix) oldf_coords = defect_site.frac_coords coords = defect_site.lattice.get_cartesian_coords(oldf_coords) newf_coords = sc.lattice.get_fractional_coords(coords) sc_defect_site = PeriodicSite( defect_site.species_and_occu, newf_coords, sc.lattice, properties=defect_site.properties ) for i in range(len(sc.sites)): # if sc_defect_site == sc.sites[i]: if sc_defect_site.distance(sc.sites[i]) < 1e-3: del sc[i] return sc raise ValueError("Something wrong if reached here")
def test_distance_and_image(self): other_site = PeriodicSite("Fe", np.array([1, 1, 1]), self.lattice) (distance, image) = self.site.distance_and_image(other_site) self.assertAlmostEqual(distance, 6.22494979899, 5) self.assertTrue(([-1, -1, -1] == image).all()) (distance, image) = self.site.distance_and_image(other_site, [1, 0, 0]) self.assertAlmostEqual(distance, 19.461500456028563, 5) # Test that old and new distance algo give the same ans for # "standard lattices" lattice = Lattice(np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])) site1 = PeriodicSite("Fe", np.array([0.01, 0.02, 0.03]), lattice) site2 = PeriodicSite("Fe", np.array([0.99, 0.98, 0.97]), lattice) self.assertAlmostEqual(get_distance_and_image_old(site1, site2)[0], site1.distance_and_image(site2)[0]) lattice = Lattice.from_parameters(1, 0.01, 1, 10, 10, 10) site1 = PeriodicSite("Fe", np.array([0.01, 0.02, 0.03]), lattice) site2 = PeriodicSite("Fe", np.array([0.99, 0.98, 0.97]), lattice) self.assertTrue(get_distance_and_image_old(site1, site2)[0] > site1.distance_and_image(site2)[0]) site2 = PeriodicSite("Fe", np.random.rand(3), lattice) (dist_old, jimage_old) = get_distance_and_image_old(site1, site2) (dist_new, jimage_new) = site1.distance_and_image(site2) self.assertTrue(dist_old - dist_new > -1e-8, "New distance algo should give smaller answers!") self.assertFalse((abs(dist_old - dist_new) < 1e-8) ^ (jimage_old == jimage_new).all(), "If old dist == new dist, images must be the same!") latt = Lattice.from_parameters(3.0, 3.1, 10.0, 2.96, 2.0, 1.0) site = PeriodicSite("Fe", [0.1, 0.1, 0.1], latt) site2 = PeriodicSite("Fe", [0.99, 0.99, 0.99], latt) (dist, img) = site.distance_and_image(site2) self.assertAlmostEqual(dist, 0.15495358379511573) self.assertEqual(list(img), [-11, 6, 0])
def from_dict(cls, d): lattice = Lattice.from_dict(d["lattice"]) sites = [PeriodicSite.from_dict(sd, lattice) for sd in d["sites"]] s = Structure.from_sites(sites) return Slab( lattice=lattice, species=s.species_and_occu, coords=s.frac_coords, miller_index=d["miller_index"], oriented_unit_cell=Structure.from_dict(d["oriented_unit_cell"]), shift=d["shift"], scale_factor=d["scale_factor"], site_properties=s.site_properties, energy=d["energy"] )
def test_get_symmetry_operations(self): for sg, structure in [(self.sg, self.structure), (self.sg4, self.structure4)]: pgops = sg.get_point_group_operations() fracsymmops = sg.get_symmetry_operations() symmops = sg.get_symmetry_operations(True) latt = structure.lattice for fop, op, pgop in zip(fracsymmops, symmops, pgops): # translation vector values should all be 0 or 0.5 t = fop.translation_vector * 2 self.assertArrayAlmostEqual(t - np.round(t), 0) self.assertArrayAlmostEqual(fop.rotation_matrix, pgop.rotation_matrix) for site in structure: newfrac = fop.operate(site.frac_coords) newcart = op.operate(site.coords) self.assertTrue( np.allclose(latt.get_fractional_coords(newcart), newfrac) ) found = False newsite = PeriodicSite( site.species, newcart, latt, coords_are_cartesian=True ) for testsite in structure: if newsite.is_periodic_image(testsite, 1e-3): found = True break self.assertTrue(found) # Make sure this works for any position, not just the atomic # ones. random_fcoord = np.random.uniform(size=(3)) random_ccoord = latt.get_cartesian_coords(random_fcoord) newfrac = fop.operate(random_fcoord) newcart = op.operate(random_ccoord) self.assertTrue( np.allclose(latt.get_fractional_coords(newcart), newfrac) )
def test_structures(self): import itertools import numpy as np from pymatgen.core.structure import Structure from pymatgen.core.lattice import Lattice from pymatgen.core.sites import PeriodicSite from supercellor.supercell import make_supercell NTESTS = 100 #100 RADIUS = 100.0 EPS = 1e-3 DIAG = 4 NOISE_R = 2 tests_run = 0 np.random.seed(10) while (tests_run < NTESTS): R = DIAG * np.eye(3, dtype=int) - np.random.randint( NOISE_R, size=(3, 3)) + NOISE_R #np.random.randint(10, size=(3,3)) -5 S = RADIUS * np.eye(3) try: P = np.dot(np.linalg.inv(R), S) except np.linalg.LinAlgError: continue lattice = Lattice(P) if lattice.volume < 0.01 * RADIUS**3 / DIAG: print('skipping', lattice.volume) continue sites = [] try: for pos in itertools.product([-0.5, 0.5], repeat=3): sites.append( PeriodicSite("H", pos, lattice, coords_are_cartesian=True)) except np.linalg.LinAlgError: continue structure = Structure.from_sites(sites) supercell, scale = make_supercell(structure, distance=RADIUS - EPS, verbosity=0, wrap=True, standardize=True, do_niggli_first=True) self.assertTrue( np.sum(np.abs(supercell._lattice.matrix - S)) < EPS) tests_run += 1
def _get_structures(self, num_structs): structs = [] rs = subprocess.Popen( ["makestr.x", "struct_enum.out", str(0), str(num_structs - 1)], stdout=subprocess.PIPE, stdin=subprocess.PIPE, close_fds=True) rs.communicate() if len(self.ordered_sites) > 0: original_latt = self.ordered_sites[0].lattice ordered_structure = Structure.from_sites(self.ordered_sites) inv_org_latt = np.linalg.inv(original_latt.matrix) for n in range(1, num_structs + 1): with open("vasp.{:06d}".format(n)) as f: data = f.read() data = re.sub("scale factor", "1", data) data = re.sub("(\d+)-(\d+)", r"\1 -\2", data) poscar = Poscar.from_string(data, self.index_species) sub_structure = poscar.structure #Enumeration may have resulted in a super lattice. We need to #find the mapping from the new lattice to the old lattice, and #perform supercell construction if necessary. new_latt = sub_structure.lattice sites = [] if len(self.ordered_sites) > 0: transformation = np.dot(new_latt.matrix, inv_org_latt) transformation = [[int(round(cell)) for cell in row] for row in transformation] logger.debug("Supercell matrix: {}".format(transformation)) s = Structure.from_sites(ordered_structure) s.make_supercell(transformation) sites.extend([site.to_unit_cell for site in s]) super_latt = sites[-1].lattice else: super_latt = new_latt for site in sub_structure: if site.specie.symbol != "X": # We exclude vacancies. sites.append( PeriodicSite(site.species_and_occu, site.frac_coords, super_latt).to_unit_cell) structs.append(Structure.from_sites(sorted(sites))) logger.debug("Read in a total of {} structures.".format(num_structs)) return structs
def test_vacancy(self): struc = PymatgenTest.get_structure("VO2") V_index = struc.indices_from_symbol("V")[0] vac = Vacancy(struc, struc[V_index]) # test generation and super cell vac_struc = vac.generate_defect_structure(1) self.assertEqual(vac_struc.composition.as_dict(), {"V": 1, "O": 4}) vac_struc = vac.generate_defect_structure(2) self.assertEqual(vac_struc.composition.as_dict(), {"V": 15, "O": 32}) vac_struc = vac.generate_defect_structure(3) self.assertEqual(vac_struc.composition.as_dict(), {"V": 53, "O": 108}) vac_struc = vac.generate_defect_structure([[2.0, 0, 0], [0, 0, -3.0], [0, 2.0, 0]]) self.assertEqual(vac_struc.composition.as_dict(), {"V": 23, "O": 48}) # test charge vac = Vacancy(struc, struc[V_index]) vac_struc = vac.generate_defect_structure(1) self.assertEqual(vac_struc.charge, 0.0) vac = Vacancy(struc, struc[V_index], charge=1.0) vac_struc = vac.generate_defect_structure(1) self.assertEqual(vac_struc.charge, 1.0) vac = Vacancy(struc, struc[V_index], charge=-1.0) vac_struc = vac.generate_defect_structure(1) self.assertEqual(vac_struc.charge, -1.0) # test multiplicity vac = Vacancy(struc, struc[V_index]) self.assertEqual(vac.multiplicity, 2) O_index = struc.indices_from_symbol("O")[0] vac = Vacancy(struc, struc[O_index]) self.assertEqual(vac.multiplicity, 4) # Test composition self.assertEqual(dict(vac.defect_composition.as_dict()), {"V": 2, "O": 3}) # test lattice value error occurs for different lattices sc_scaled_struc = struc.copy() sc_scaled_struc.make_supercell(2) self.assertRaises(ValueError, Vacancy, struc, sc_scaled_struc[V_index]) self.assertRaises(ValueError, Vacancy, sc_scaled_struc, struc[V_index]) # test value error raised for site not in the structure non_site = PeriodicSite("V", struc[V_index].frac_coords + [0.0, 0.0, 0.1], struc.lattice) self.assertRaises(ValueError, Vacancy, struc, non_site)
def setUp(self): self.lattice = Lattice.cubic(10.0) self.si = Element("Si") self.site = PeriodicSite("Fe", [0.25, 0.35, 0.45], self.lattice) self.site2 = PeriodicSite({"Si": 0.5}, [0, 0, 0], self.lattice) self.assertEqual(self.site2.species, Composition({Element('Si'): 0.5}), "Inconsistent site created!") self.propertied_site = PeriodicSite(Specie("Fe", 2), [0.25, 0.35, 0.45], self.lattice, properties={ 'magmom': 5.1, 'charge': 4.2 }) self.dummy_site = PeriodicSite("X", [0, 0, 0], self.lattice)
def _supercell_with_defect(self, scaling_matrix, defect_site): sc = self._structure.copy() sc.make_supercell(scaling_matrix) oldf_coords = defect_site.frac_coords coords = defect_site.lattice.get_cartesian_coords(oldf_coords) newf_coords = sc.lattice.get_fractional_coords(coords) sc_defect_site = PeriodicSite(defect_site.species_and_occu, newf_coords, sc.lattice, properties=defect_site.properties) for i in range(len(sc.sites)): if sc_defect_site == sc.sites[i]: sc.remove(i) return sc
def apply_tags(self): """ Apply tags. """ tags = {} for tag in self.tags: istruct = tag.get('istruct', 'all') if istruct != 'all': if istruct != self.istruct: continue site_index = tag['site_index'] color = tag.get('color', [0.5, 0.5, 0.5]) opacity = tag.get('opacity', 0.5) if site_index == 'unit_cell_all': struct_radii = self.all_vis_radii[self.istruct] for isite, site in enumerate(self.current_structure): vis_radius = 1.5 * tag.get('radius', struct_radii[isite]) tags[(isite, (0, 0, 0))] = {'radius': vis_radius, 'color': color, 'opacity': opacity} continue cell_index = tag['cell_index'] if 'radius' in tag: vis_radius = tag['radius'] elif 'radius_factor' in tag: vis_radius = tag['radius_factor'] * self.all_vis_radii[self.istruct][site_index] else: vis_radius = 1.5 * self.all_vis_radii[self.istruct][site_index] tags[(site_index, cell_index)] = {'radius': vis_radius, 'color': color, 'opacity': opacity} for site_and_cell_index, tag_style in tags.items(): isite, cell_index = site_and_cell_index site = self.current_structure[isite] if cell_index == (0, 0, 0): coords = site.coords else: fcoords = site.frac_coords + np.array(cell_index) site_image = PeriodicSite(site.species, fcoords, self.current_structure.lattice, to_unit_cell=False, coords_are_cartesian=False, properties=site.properties) self.add_site(site_image) coords = site_image.coords vis_radius = tag_style['radius'] color = tag_style['color'] opacity = tag_style['opacity'] self.add_partial_sphere(coords=coords, radius=vis_radius, color=color, start=0, end=360, opacity=opacity)
def from_dict(cls, d): lattice = Lattice.from_dict(d["lattice"]) sites = [PeriodicSite.from_dict(sd, lattice) for sd in d["sites"]] s = Structure.from_sites(sites) return Interface( lattice=lattice, species=s.species_and_occu, coords=s.frac_coords, sub_plane=d["sub_plane"], film_plane=d["film_plane"], sub_init_cell=d["sub_init_cell"], film_init_cell=d["film_init_cell"], modified_sub_structure=d["modified_sub_structure"], modified_film_structure=d["modified_film_structure"], strained_sub_structure=d["strained_sub_structure"], strained_film_structure=d["strained_film_structure"], site_properties=s.site_properties, init_inplane_shift=d["init_inplane_shift"] )
def replace_site(self, index, species_n_occu): """ Replace a single site. Takes either a species or a dict of species and occupations. Args: index: The index of the site in the _sites list. species: A species object. """ self._sites[index] = PeriodicSite( species_n_occu, self._sites[index].frac_coords, self._lattice, properties=self._sites[index].properties)
def get_sitej(self, site_index, image_index): """ Assuming there is some value in the connectivity array at indices (1, 3, 12). sitei can be obtained directly from the input structure (structure[1]). sitej can be obtained by passing 3, 12 to this function Args: site_index (int): index of the site (3 in the example) image_index (int): index of the image (12 in the example) """ atoms_n_occu = self.s[site_index].species lattice = self.s.lattice coords = self.s[site_index].frac_coords + self.offsets[image_index] return PeriodicSite(atoms_n_occu, coords, lattice)
def test_niggli(self): from pymatgen.symmetry.analyzer import SpacegroupAnalyzer from pymatgen.core.structure import Structure from pymatgen.core.lattice import Lattice from pymatgen.core.sites import PeriodicSite from supercellor.supercell import make_supercell import numpy as np import itertools np.random.seed(4) DIST = 0.99 lattice = Lattice(1 * np.eye(3) + 0.5 * (np.random.random((3, 3)) - 0.5)) sites = [] for pos in itertools.product([-0.5, 0.5], repeat=3): sites.append( PeriodicSite("H", pos, lattice, coords_are_cartesian=True)) structure = Structure.from_sites(sites) supercell1, scale1 = make_supercell(structure, distance=DIST, verbosity=1, wrap=True, standardize=True, do_niggli_first=False) supercell2, scale2 = make_supercell(structure, distance=DIST, verbosity=1, wrap=True, standardize=True, do_niggli_first=True) sa = SpacegroupAnalyzer(supercell1, symprec=1e-21, angle_tolerance=-1) supercell_refine = sa.get_refined_structure() for i in range(3): for j in range(3): self.assertTrue( abs(supercell1._lattice.matrix[i, j] - supercell2._lattice.matrix[i, j]) < 1e-1, '{} != {} for i,j={},{}'.format( supercell1._lattice.matrix[i, j], supercell2._lattice.matrix[i, j], i, j)) self.assertTrue( abs(supercell1._lattice.matrix[i, j] - supercell_refine._lattice.matrix[i, j]) < 1e-1, '{} != {} for i,j={},{}'.format( supercell1._lattice.matrix[i, j], supercell_refine._lattice.matrix[i, j], i, j))
def test_equivalence_fort_py(self): from datetime import datetime import itertools import numpy as np from pymatgen.core.structure import Structure from pymatgen.core.lattice import Lattice from pymatgen.core.sites import PeriodicSite from supercellor.supercell import make_supercell NTESTS = 10 #100 VERBOSITY = 0 for radius in np.arange(1.0, 3.1, 1.0): #RADIUS = 5.0 tests_run = 0 np.random.seed(10) # reinitialize seed! timings_f = 0.0 timings_p = 0.0 while (tests_run < NTESTS): P = np.eye(3)+ 0.1*(np.random.random((3,3)) -0.5) lattice = Lattice(P) if lattice.volume < 0.1: print('skipping', lattice.volume) continue sites = [] try: for pos in itertools.product([-0.5,0.5], repeat=3): sites.append(PeriodicSite("H", pos, lattice, coords_are_cartesian=True)) except np.linalg.LinAlgError: continue structure = Structure.from_sites(sites) n = datetime.now() supercell_p, scale_p = make_supercell(structure, distance=radius, verbosity=VERBOSITY, wrap=True, standardize=True, do_niggli_first=True, implementation='pyth') timings_p += (datetime.now()-n).microseconds n = datetime.now() supercell_f, scale_f = make_supercell(structure, distance=radius, verbosity=VERBOSITY, wrap=True, standardize=True, do_niggli_first=True, implementation='fort') timings_f += (datetime.now()-n).microseconds self.assertTrue(np.sum((scale_p-scale_f)**2) ==0) self.assertTrue(np.sum((supercell_f._lattice.matrix -supercell_p._lattice.matrix)**2) < 1e-6) #~ self.assertTrue(np.sum(np.abs(supercell._lattice.matrix - S))< EPS) tests_run += 1 print('Avg timing fortran impl rad={} {:.2e}'.format(radius, 1e-6*timings_f/ tests_run)) print('Avg timing python impl rad={} {:.2e}'.format(radius, 1e-6*timings_p/ tests_run))
def setUp(self): self.epsilon = 15. struc = PymatgenTest.get_structure("VO2") struc.make_supercell(3) vac = Vacancy(struc, struc.sites[0], charge=-3) # load neccessary parameters for defect_entry to make use # of Freysoldt and Kumagai corrections p = {} ids = vac.generate_defect_structure(1) abc = struc.lattice.abc axisdata = [np.arange(0., lattval, 0.2) for lattval in abc] bldata = [np.array([1. for u in np.arange(0., lattval, 0.2)]) for lattval in abc] dldata = [ np.array([(-1 - np.cos(2 * np.pi * u / lattval)) for u in np.arange(0., lattval, 0.2)]) for lattval in abc ] p.update({'axis_grid': axisdata, 'bulk_planar_averages': bldata, 'defect_planar_averages': dldata, 'initial_defect_structure': ids, 'defect_frac_sc_coords': struc.sites[0].frac_coords, 'bulk_sc_structure': struc}) bulk_atomic_site_averages, defect_atomic_site_averages = [], [] defect_site_with_sc_lattice = PeriodicSite( struc.sites[0].specie, struc.sites[0].coords, struc.lattice, coords_are_cartesian = True) max_dist = 9.6 pert_amnt = 1. for site_ind, site in enumerate(struc.sites): if site.specie.symbol == "O": Oval = -30.6825 bulk_atomic_site_averages.append( Oval) if site_ind: dist_to_defect = site.distance_and_image( defect_site_with_sc_lattice)[0] defect_site_val = Oval - .3 + pert_amnt * ((max_dist - dist_to_defect)/max_dist)**2 defect_atomic_site_averages.append( defect_site_val) else: Vval = -51.6833 bulk_atomic_site_averages.append( Vval) if site_ind: dist_to_defect = site.distance_and_image( defect_site_with_sc_lattice)[0] defect_site_val = Vval - .3 + pert_amnt * ((max_dist - dist_to_defect)/max_dist)**2 defect_atomic_site_averages.append( defect_site_val) site_matching_indices = [[ind, ind-1] for ind in range(len(struc.sites)) if ind != 0] p.update({ "bulk_atomic_site_averages": bulk_atomic_site_averages, "defect_atomic_site_averages": defect_atomic_site_averages, "site_matching_indices": site_matching_indices}) self.defect_entry = DefectEntry( vac, 0., parameters = p)
def mod_site(site): new_atom_occu = collections.defaultdict(int) for sp, amt in site.species_and_occu.items(): if sp in species_mapping: if isinstance(species_mapping[sp], (Element, Specie)): new_atom_occu[species_mapping[sp]] += amt elif isinstance(species_mapping[sp], dict): for new_sp, new_amt in species_mapping[sp].items(): new_atom_occu[new_sp] += amt * new_amt else: new_atom_occu[sp] += amt return PeriodicSite(new_atom_occu, site.frac_coords, self._lattice, properties=site.properties)
def remove_oxidation_states(self): """ Removes oxidation states from a structure. """ for i, site in enumerate(self._sites): new_sp = collections.defaultdict(float) for el, occu in site.species_and_occu.items(): sym = el.symbol new_sp[Element(sym)] += occu new_site = PeriodicSite(new_sp, site.frac_coords, self._lattice, coords_are_cartesian=False, properties=site.properties) self._sites[i] = new_site
def get_defect_site(self, initdef): ## this is relatively simple for vacancies and substitutionals ## which by definition are a pre-existing site in the structure if initdef["type"][0] == "v" or initdef["type"][0] == "s": siteind_new = self.get_site_ind(initdef["index"], initdef["species"], initdef["index_offset_n1"], initdef["index_offset_n2"], initdef["index_offset_n1n2"]) defect_site = structure_bulk[siteind_new] ## for interstitials/adatoms, the defect site coords are defined ## by the center (average) of the user-provided list of sites if initdef["type"][0] == "i" or initdef["type"][0] == "a": if len(initdef["index"]) != len(initdef["species"]): raise ValueError( "inconsistency between index and species lists") for offset in [ "index_offset_n1", "index_offset_n2", "index_offset_n1n2" ]: if initdef[offset] == 0: initdef[offset] = [0] * len(initdef["index"]) defect_coords = np.array([0., 0., 0.]) ## loop through the list of sites for ind, sp, offset_n1, offset_n2, offset_n1n2 in zip( initdef["index"], initdef["species"], initdef["index_offset_n1"], initdef["index_offset_n2"], initdef["index_offset_n1n2"]): siteind_new = self.get_site_ind(ind, sp, offset_n1, offset_n2, offset_n1n2) defect_coords += np.array( structure_bulk[siteind_new].frac_coords) ## get the averaged position defect_coords = defect_coords / len(initdef["index"]) if initdef.get("shift_z") != None: # if initdef["shift_z"]:; ## we may want to shift the z position, e.g. in the case of an adatom defect_coords[2] += float( initdef["shift_z"]) / self.structure.lattice.c ## create the defect_site as a PeriodicSite object defect_site = PeriodicSite(initdef["species_new"], defect_coords, lattice=self.structure.lattice, coords_are_cartesian=False) return defect_site
def cube_read_structure_mesh_data(file): with open(file, 'r') as fh: # The two first lines are comments for ii in range(2): fh.readline() # Number of atoms natoms = int(fh.readline().split()[0]) # The next three lines give the mesh and the vectors sp = fh.readline().split() nx = int(sp[0]) dvx = np.array([float(sp[ii]) for ii in range(1, 4)]) * bohr_to_angstrom sp = fh.readline().split() ny = int(sp[0]) dvy = np.array([float(sp[ii]) for ii in range(1, 4)]) * bohr_to_angstrom sp = fh.readline().split() nz = int(sp[0]) dvz = np.array([float(sp[ii]) for ii in range(1, 4)]) * bohr_to_angstrom uc_matrix = np.array([nx * dvx, ny * dvy, nz * dvz]) sites = [] lattice = Lattice(uc_matrix) for ii in range(natoms): sp = fh.readline().split() cc = np.array([float(sp[ii]) for ii in range(2, 5)]) * bohr_to_angstrom sites.append( PeriodicSite(int(sp[0]), coords=cc, lattice=lattice, to_unit_cell=False, coords_are_cartesian=True)) data = np.zeros((nx, ny, nz)) ii = 0 for line in fh: for val in line.split(): data[ii // (ny * nz), (ii // nz) % ny, ii % nz] = float(val) ii += 1 data = data / (bohr_to_angstrom**3) if ii != nx * ny * nz: raise ValueError('Wrong number of data points ...') from abipy.core.structure import Structure structure = Structure.from_sites(sites=sites) from abipy.core.mesh3d import Mesh3D mesh = Mesh3D(shape=[nx, ny, nz], vectors=uc_matrix) return structure, mesh, data
def plot_images(self, outfile): """ Generates a POSCAR with the calculated diffusion path with respect to the first endpoint. :param outfile: Output file for the POSCAR """ sum_struct = self.__images[0].sites for image in self.__images: for site_i in self.__relax_sites: sum_struct.append(PeriodicSite(image.sites[site_i].specie, image.sites[site_i].frac_coords, self.__images[0].lattice, to_unit_cell=True, coords_are_cartesian=False)) sum_struct = Structure.from_sites(sum_struct, validate_proximity=False) p = Poscar(sum_struct) p.write_file(outfile)
def setUp(self): entry_file = os.path.join(file_loc, 'vac_cr2o3_struct_entry.json') entry = loadfn(entry_file, cls=MontyDecoder) lattice = Lattice([[9.995004137201189, -2.1469568e-08, 0.0], [-4.997501105922451, 8.655927903729987, 0.0], [0.0, 0.0, 13.67956098598296]]) coords = [0.1666665000000016, 0.3333334999999984, 0.014505185117094302] site_in_bulk = PeriodicSite('Cr', coords, lattice) multiplicity = 12 supercell_size = [2, 2, 1] q = -2 q_corr = 0.98716 o_corr = 0.39139821874799996 name = "vac_1_Cr" self.com_def = ComputedDefect(entry, site_in_bulk, multiplicity, supercell_size, q, q_corr, o_corr, name)
def test_interstitial(self): struc = PymatgenTest.get_structure("VO2") V_index = struc.indices_from_symbol("V")[0] int_site = PeriodicSite("V", struc[V_index].coords + [0.1, 0.1, 0.1], struc.lattice) interstitial = Interstitial(struc, int_site) # test generation and super cell int_struc = interstitial.generate_defect_structure(1) self.assertEqual(int_struc.composition.as_dict(), {"V": 3, "O": 4}) # Ensure the site is in the right place self.assertEqual( int_site, int_struc.get_sites_in_sphere(int_site.coords, 0.1)[0][0]) int_struc = interstitial.generate_defect_structure(2) self.assertEqual(int_struc.composition.as_dict(), {"V": 17, "O": 32}) int_struc = interstitial.generate_defect_structure(3) self.assertEqual(int_struc.composition.as_dict(), {"V": 55, "O": 108}) # test charge interstitial = Interstitial(struc, int_site) int_struc = interstitial.generate_defect_structure(1) self.assertEqual(int_struc.charge, 0.0) interstitial = Interstitial(struc, int_site, charge=1.0) int_struc = interstitial.generate_defect_structure(1) self.assertEqual(int_struc.charge, 1.0) interstitial = Interstitial(struc, int_site, charge=-1.0) int_struc = interstitial.generate_defect_structure(1) self.assertEqual(int_struc.charge, -1.0) # test multiplicity interstitial = Interstitial(struc, int_site) self.assertEqual(interstitial.multiplicity, 1.0) interstitial = Interstitial(struc, int_site, multiplicity=4.0) self.assertEqual(interstitial.multiplicity, 4.0) # Test composoition self.assertEqual(dict(interstitial.defect_composition.as_dict()), { "V": 3, "O": 4 })
def write_input(self, output_dir, make_dir_if_not_present=True, write_cif=False, write_path_cif=False, write_endpoint_inputs=False): """ NEB inputs has a special directory structure where inputs are in 00, 01, 02, .... Args: output_dir (str): Directory to output the VASP input files make_dir_if_not_present (bool): Set to True if you want the directory (and the whole path) to be created if it is not present. write_cif (bool): If true, writes a cif along with each POSCAR. write_path_cif (bool): If true, writes a cif for each image. write_endpoint_inputs (bool): If true, writes input files for running endpoint calculations. """ if make_dir_if_not_present and not os.path.exists(output_dir): os.makedirs(output_dir) self.incar.write_file(os.path.join(output_dir, 'INCAR')) self.kpoints.write_file(os.path.join(output_dir, 'KPOINTS')) self.potcar.write_file(os.path.join(output_dir, 'POTCAR')) for i, p in enumerate(self.poscars): d = os.path.join(output_dir, str(i).zfill(2)) if not os.path.exists(d): os.makedirs(d) p.write_file(os.path.join(d, 'POSCAR')) if write_cif: p.structure.to(filename=os.path.join(d, '{}.cif'.format(i))) if write_endpoint_inputs: end_point_param = MPRelaxSet( self.structures[0], user_incar_settings=self.user_incar_settings) for image in ['00', str(len(self.structures) - 1).zfill(2)]: end_point_param.incar.write_file(os.path.join(output_dir, image, 'INCAR')) end_point_param.kpoints.write_file(os.path.join(output_dir, image, 'KPOINTS')) end_point_param.potcar.write_file(os.path.join(output_dir, image, 'POTCAR')) if write_path_cif: sites = set() l = self.structures[0].lattice for site in chain(*(s.sites for s in self.structures)): sites.add(PeriodicSite(site.species_and_occu, site.frac_coords, l)) path = Structure.from_sites(sorted(sites)) path.to(filename=os.path.join(output_dir, 'path.cif'))
def makeNewPos(specs, frac_coords, new_latt, dim): """ Make a new POSCAR file using input species, coordinates, and lattice. Used in conjunction with functions "getNewLattice","alignMono", "alignChains" inputs -------- specs (list): List of species associated with each coordinate frac_coords (list): List of fractional coordinates of each species, relative to the new lattice new_latt (list): List of vectors representing the new lattice vectors of the low-dimensional material dim (int): Number of periodic directions in the crystal outputs -------- new_struct (Structure): Structure object for low-dimensional material with non-periodic directions being orthogonal to the periodic directions """ a, b, c = magni(new_latt[0]), magni(new_latt[1]), magni(new_latt[2]) if dim == 2: ang = getAngle(new_latt[0], new_latt[1]) / 2 new_latt = [[np.cos(ang) * a, -np.sin(ang) * a, 0], [np.cos(ang) * b, np.sin(ang) * b, 0], [0, 0, c]] elif dim == 1: new_latt = [[a, 0, 0], [0, b, 0], [0, 0, c]] i = 0 new_sites = [] for site in frac_coords: p = PeriodicSite(species=Element(specs[i]), lattice=Lattice(new_latt), coords=np.dot(site, new_latt), coords_are_cartesian=True) new_sites.append(p) i += 1 new_struct = Structure.from_sites(new_sites) return (new_struct)
def modify_lattice(self, new_lattice): """ Modify the lattice of the structure. Mainly used for changing the basis. Args: new_lattice: New lattice """ self._lattice = new_lattice new_sites = [] for site in self._sites: new_sites.append( PeriodicSite(site.species_and_occu, site.frac_coords, self._lattice, properties=site.properties)) self._sites = new_sites
def __init__(self, structure, scaling_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1))): """ Create a supercell. Args: structure: pymatgen.core.structure Structure object. scaling_matrix: a matrix of transforming the lattice vectors. Defaults to the identity matrix. Has to be all integers. e.g., [[2,1,0],[0,3,0],[0,0,1]] generates a new structure with lattice vectors a' = 2a + b, b' = 3b, c' = c where a, b, and c are the lattice vectors of the original structure. """ self._original_structure = structure old_lattice = structure.lattice scale_matrix = np.array(scaling_matrix) new_lattice = Lattice(np.dot(scale_matrix, old_lattice.matrix)) new_sites = [] def range_vec(i): return range( max(scale_matrix[:][:, i]) - min(scale_matrix[:][:, i]) + 1) for site in structure.sites: for (i, j, k) in itertools.product(range_vec(0), range_vec(1), range_vec(2)): fcoords = site.frac_coords + np.array([i, j, k]) coords = old_lattice.get_cartesian_coords(fcoords) new_coords = new_lattice.get_fractional_coords(coords) new_site = PeriodicSite(site.species_and_occu, new_coords, new_lattice, properties=site.properties) contains_site = False for s in new_sites: if s.is_periodic_image(new_site): contains_site = True break if not contains_site: new_sites.append(new_site) self._modified_structure = Structure.from_sites(new_sites)
def are_symmetrically_equivalent(self, sites1, sites2, symm_prec=1e-3): """ Given two sets of PeriodicSites, test if they are actually symmetrically equivalent under this space group. Useful, for example, if you want to test if selecting atoms 1 and 2 out of a set of 4 atoms are symmetrically the same as selecting atoms 3 and 4, etc. One use is in PartialRemoveSpecie transformation to return only symmetrically distinct arrangements of atoms. Args: sites1: 1st set of sites sites2: 2nd set of sites symm_prec: The tolerance in atomic distance to test if atoms are symmetrically similar. Returns: Boolean indicating whether the two sets of sites are symmetrically equivalent. """ def in_sites(site): for test_site in sites1: if test_site.is_periodic_image(site, symm_prec, False): return True return False for op in self.symmops: newsites2 = [ PeriodicSite(site.species_and_occu, op.operate(site.frac_coords), site.lattice) for site in sites2 ] ismapping = True for site in newsites2: if not in_sites(site): ismapping = False break if ismapping: return True return False
def test_as_from_dict(self): d = self.site2.as_dict() site = PeriodicSite.from_dict(d) self.assertEqual(site, self.site2) self.assertNotEqual(site, self.site) d = self.propertied_site.as_dict() site3 = PeriodicSite({"Si": 0.5, "Fe": 0.5}, [0, 0, 0], self.lattice) d = site3.as_dict() site = PeriodicSite.from_dict(d) self.assertEqual(site.species, site3.species) d = self.dummy_site.as_dict() site = PeriodicSite.from_dict(d) self.assertEqual(site.species, self.dummy_site.species)
def test_hnf_dmpi(self): import json, numpy as np, itertools, os from pymatgen.core.structure import Structure from pymatgen.core.lattice import Lattice from pymatgen.core.sites import PeriodicSite from supercellor.supercell import make_supercell np.random.seed(50) N = 1 RMIN = 2 RMAX = 3 for trial in range(N): #~ for implementation in ('pyth', ): for implementation in ('fort', ): lattice = Lattice(1.0 * np.eye(3) + 0.2 * (np.random.random((3, 3)) - 0.5)) sites = [] for pos in itertools.product([-0.5, 0.5], repeat=3): sites.append( PeriodicSite("H", pos, lattice, coords_are_cartesian=True)) structure = Structure.from_sites(sites) for rad in range(RMIN, RMAX): supercell1, scale1 = make_supercell( structure, distance=rad, method='hnf', implementation=implementation, verbosity=0, wrap=True, standardize=False, do_niggli_first=False) reduced_supercell1 = supercell1.get_reduced_structure( reduction_algo=u'LLL') for dim in range(3): self.assertTrue( np.linalg.norm(reduced_supercell1._lattice. matrix[dim]) >= rad)
def from_bson_voronoi_list(bson_nb_voro_list, structure): """ Returns the voronoi_list needed for the VoronoiContainer object from a bson-encoded voronoi_list (composed of vlist and bson_nb_voro_list). :param vlist: List of voronoi objects :param bson_nb_voro_list: List of periodic sites involved in the Voronoi :return: The voronoi_list needed for the VoronoiContainer (with PeriodicSites as keys of the dictionary - not allowed in the BSON format) """ voronoi_list = [None] * len(bson_nb_voro_list) for isite, voro in enumerate(bson_nb_voro_list): if voro is None or voro == 'None': continue voronoi_list[isite] = [] for psd, dd in voro: struct_site = structure[dd['index']] periodic_site = PeriodicSite(struct_site._species, struct_site.frac_coords + psd[1], struct_site._lattice, properties=struct_site._properties) voronoi_list[isite].append((periodic_site, dd)) return voronoi_list
def test_symmetrized_structure(self): t = OrderDisorderedStructureTransformation(symmetrized_structures=True) c = [] sp = [] c.append([0.5, 0.5, 0.5]) sp.append("Si4+") c.append([0.45, 0.45, 0.45]) sp.append({"Si4+": 0.5}) c.append([0.56, 0.56, 0.56]) sp.append({"Si4+": 0.5}) c.append([0.25, 0.75, 0.75]) sp.append({"Si4+": 0.5}) c.append([0.75, 0.25, 0.25]) sp.append({"Si4+": 0.5}) l = Lattice.cubic(5) s = Structure(l, sp, c) test_site = PeriodicSite("Si4+", c[2], l) s = SymmetrizedStructure(s, "not_real", [0, 1, 1, 2, 2], ["a", "b", "b", "c", "c"]) output = t.apply_transformation(s) self.assertTrue(test_site in output.sites)