def test_init(self): filepath = self.TEST_FILES_DIR / "POSCAR" poscar = Poscar.from_file(filepath, check_for_POTCAR=False) comp = poscar.structure.composition self.assertEqual(comp, Composition("Fe4P4O16")) # Vasp 4 type with symbols at the end. poscar_string = """Test1 1.0 3.840198 0.000000 0.000000 1.920099 3.325710 0.000000 0.000000 -2.217138 3.135509 1 1 direct 0.000000 0.000000 0.000000 Si 0.750000 0.500000 0.750000 F """ poscar = Poscar.from_string(poscar_string) self.assertEqual(poscar.structure.composition, Composition("SiF")) poscar_string = "" self.assertRaises(ValueError, Poscar.from_string, poscar_string) # Vasp 4 tyle file with default names, i.e. no element symbol found. poscar_string = """Test2 1.0 3.840198 0.000000 0.000000 1.920099 3.325710 0.000000 0.000000 -2.217138 3.135509 1 1 direct 0.000000 0.000000 0.000000 0.750000 0.500000 0.750000 """ with warnings.catch_warnings(): warnings.simplefilter("ignore") poscar = Poscar.from_string(poscar_string) self.assertEqual(poscar.structure.composition, Composition("HHe")) # Vasp 4 tyle file with default names, i.e. no element symbol found. poscar_string = """Test3 1.0 3.840198 0.000000 0.000000 1.920099 3.325710 0.000000 0.000000 -2.217138 3.135509 1 1 Selective dynamics direct 0.000000 0.000000 0.000000 T T T Si 0.750000 0.500000 0.750000 F F F O """ poscar = Poscar.from_string(poscar_string) self.assertEqual( poscar.selective_dynamics, [[True, True, True], [False, False, False]] ) self.selective_poscar = poscar
def test_init(self): filepath = os.path.join(test_dir, 'POSCAR') poscar = Poscar.from_file(filepath,check_for_POTCAR=False) comp = poscar.structure.composition self.assertEqual(comp, Composition("Fe4P4O16")) # Vasp 4 type with symbols at the end. poscar_string = """Test1 1.0 3.840198 0.000000 0.000000 1.920099 3.325710 0.000000 0.000000 -2.217138 3.135509 1 1 direct 0.000000 0.000000 0.000000 Si 0.750000 0.500000 0.750000 F """ poscar = Poscar.from_string(poscar_string) self.assertEqual(poscar.structure.composition, Composition("SiF")) poscar_string = "" self.assertRaises(ValueError, Poscar.from_string, poscar_string) # Vasp 4 tyle file with default names, i.e. no element symbol found. poscar_string = """Test2 1.0 3.840198 0.000000 0.000000 1.920099 3.325710 0.000000 0.000000 -2.217138 3.135509 1 1 direct 0.000000 0.000000 0.000000 0.750000 0.500000 0.750000 """ with warnings.catch_warnings(): warnings.simplefilter("ignore") poscar = Poscar.from_string(poscar_string) self.assertEqual(poscar.structure.composition, Composition("HHe")) # Vasp 4 tyle file with default names, i.e. no element symbol found. poscar_string = """Test3 1.0 3.840198 0.000000 0.000000 1.920099 3.325710 0.000000 0.000000 -2.217138 3.135509 1 1 Selective dynamics direct 0.000000 0.000000 0.000000 T T T Si 0.750000 0.500000 0.750000 F F F O """ poscar = Poscar.from_string(poscar_string) self.assertEqual(poscar.selective_dynamics, [[True, True, True], [False, False, False]]) self.selective_poscar = poscar
def load_dielectric_constant(include_metadata=False): """ References: Petousis, I., Mrdjenovich, D., Ballouz, E., Liu, M., Winston, D., Chen, W., Graf, T., Schladt, T. D., Persson, K. A. & Prinz, F. B. High-throughput screening of inorganic compounds for the discovery of novel dielectric and optical materials. Sci. Data 4, 160134 (2017). Args: include_metadata (bool): whether to return cif, meta, poscar Returns (pd.DataFrame) """ df = pandas.read_csv(os.path.join(module_dir, "dielectric_constant.csv"), comment="#") df['cif'] = df['structure'] df['structure'] = pandas.Series( [Poscar.from_string(s).structure for s in df['poscar']]) new_columns = [ 'material_id', 'formula', 'nsites', 'space_group', 'volume', 'structure', 'band_gap', 'e_electronic', 'e_total', 'n', 'poly_electronic', 'poly_total', 'pot_ferroelectric' ] if include_metadata: new_columns += ['cif', 'meta', 'poscar'] return df[new_columns]
def __init__(self, structure, data, dos=None, vbm=None, cbm=None): """ Arguments: structure (pymatgen.core.structure.Structure): crystal structure data: Whatever data is stored dos (pymatgen.electronic_structure.dos.DOS or list, None): A pymatgen density of states or a list containing: 1) energies, 2) density of states values at those energies, 3) the Fermi level. vbm (float, None): valence band maximum cbm (float, None): conduction band minimum """ if type(structure) == str: structure = Poscar.from_string(structure).structure if dos is None: self.energies = None self.densities = None self.efermi = None elif type(dos) == list: self.energies = dos[0] self.densities = dos[1] self.efermi = dos[2] else: self.energies = dos.energies self.densities = (dos.densities[Spin.up] + dos.densities[Spin.down]) / 2 self.efermi = dos.efermi self.structure = structure self.data = data self.cbm = cbm self.vbm = vbm if (not (cbm is None)) and (not (vbm is None)): self.bandgap = max(0, cbm - vbm) else: self.bandgap = None
def Read_POSCARS(filename): """ Read POSCARS in a single file and convert it to Pymatgen structure object """ # Read INPUT file Struc = [] f = open(filename, 'rb') input_content = f.readlines() f.close() POSCAR_content = [] N_atom = 0 for str1 in input_content: POSCAR_content.append(str(str1, 'utf-8')) if len(POSCAR_content) == 7: N_atom = sum(int(f) for f in str1.split()) elif len(POSCAR_content) == 8 + N_atom: pos_str = ''.join(POSCAR_content) try: p = Poscar.from_string(pos_str) Struc.append(p.structure) except: print('strucuture is wrong', pos_str) raise POSCAR_content = [] return Struc
def load_elastic_tensor(include_metadata=False): # ref: Jong, M. De, Chen, W., Angsten, T., Jain, A., Notestine, R., Gamst, # A., Sluiter, M., Ande, C. K., Zwaag, S. Van Der, Plata, J. J., Toher, # C., Curtarolo, S., Ceder, G., Persson, K. a & Asta, M. Charting the # complete elastic properties of inorganic crystalline compounds. Sci. # Data 2, 150009 (2015). df = pandas.read_csv(os.path.join(module_dir, "elastic_tensor.csv"), comment="#") for i in list(df.index): for c in [ 'compliance_tensor', 'elastic_tensor', 'elastic_tensor_original' ]: df.at[(i, c)] = np.array(ast.literal_eval(df.at[(i, c)])) df['cif'] = df['structure'] df['structure'] = pandas.Series( [Poscar.from_string(s).structure for s in df['poscar']]) new_columns = [ 'material_id', 'formula', 'nsites', 'space_group', 'volume', 'structure', 'elastic_anisotropy', 'G_Reuss', 'G_VRH', 'G_Voigt', 'K_Reuss', 'K_VRH', 'K_Voigt', 'poisson_ratio', 'compliance_tensor', 'elastic_tensor', 'elastic_tensor_original' ] if include_metadata: new_columns += ['cif', 'kpoint_density', 'poscar'] return df[new_columns]
def load_piezoelectric_tensor(include_metadata=False): """ References: de Jong, M., Chen, W., Geerlings, H., Asta, M. & Persson, K. A. A database to enable discovery and design of piezoelectric materials. Sci. Data 2, 150053 (2015) Args: include_metadata (bool): whether to return cif, meta, poscar Returns (pd.DataFrame) """ df = pandas.read_csv(os.path.join(module_dir, "piezoelectric_tensor.csv"), comment="#") for i in list(df.index): c = 'piezoelectric_tensor' df.at[(i, c)] = np.array(ast.literal_eval(df.at[(i, c)])) df['cif'] = df['structure'] df['structure'] = pandas.Series( [Poscar.from_string(s).structure for s in df['poscar']]) new_columns = [ 'material_id', 'formula', 'nsites', 'point_group', 'space_group', 'volume', 'structure', 'eij_max', 'v_max', 'piezoelectric_tensor' ] if include_metadata: new_columns += ['cif', 'meta', 'poscar'] return df[new_columns]
def get_prim_struct(structure): """ Get standard primitive """ output = run_aconvasp_command(["aconvasp", "--std_prim"], structure) if "ERROR" in output[1]: raise AconvaspError(output[1]) tmp = Poscar.from_string(output[0]) return {'struct': tmp.structure, 'comm': tmp.comment}
def get_prim_struct(structure): """ Get standard primitive """ output = run_aconvasp_command(["aconvasp", "--std_prim"], structure) if "ERROR" in output[1]: raise AconvaspError(output[1]) tmp = Poscar.from_string(output[0]) return {"struct": tmp.structure, "comm": tmp.comment}
def get_conv_struct(structure): """ Get a minkowski reduced structure """ output = run_aconvasp_command(["aconvasp", "--std_conv"], structure) if "ERROR" in output[1]: raise AconvaspError(output[1]) tmp = Poscar.from_string(output[0]) return {"struct": tmp.structure, "comm": tmp.comment}
def get_conv_struct(structure): """ Get a minkowski reduced structure """ output = run_aconvasp_command(["aconvasp", "--std_conv"], structure) if "ERROR" in output[1]: raise AconvaspError(output[1]) tmp = Poscar.from_string(output[0]) return {'struct': tmp.structure, 'comm': tmp.comment}
def _get_structures(self, num_structs): structs = [] rs = subprocess.Popen( [makestr_cmd, "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 # Need to strip sites of site_properties, which would otherwise # result in an index error. Hence Structure is reconstructed in # the next step. ordered_structure = Structure( original_latt, [site.species_and_occu for site in self.ordered_sites], [site.frac_coords for site in 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(r'scale factor', "1", data) data = re.sub(r'(\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 = ordered_structure * 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 _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 # Need to strip sites of site_properties, which would otherwise # result in an index error. Hence Structure is reconstructed in # the next step. ordered_structure = Structure( original_latt, [site.species_and_occu for site in self.ordered_sites], [site.frac_coords for site in 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_str(self): si = 14 coords = list() coords.append([0, 0, 0]) coords.append([0.75, 0.5, 0.75]) # Silicon structure for testing. latt = [ [3.8401979337, 0.00, 0.00], [1.9200989668, 3.3257101909, 0.00], [0.00, -2.2171384943, 3.1355090603], ] struct = Structure(latt, [si, si], coords) poscar = Poscar(struct) expected_str = """Si2 1.0 3.840198 0.000000 0.000000 1.920099 3.325710 0.000000 0.000000 -2.217138 3.135509 Si 2 direct 0.000000 0.000000 0.000000 Si 0.750000 0.500000 0.750000 Si """ self.assertEqual(str(poscar), expected_str, "Wrong POSCAR output!") # Vasp 4 type with symbols at the end. poscar_string = """Test1 1.0 -3.840198 0.000000 0.000000 1.920099 3.325710 0.000000 0.000000 -2.217138 3.135509 1 1 direct 0.000000 0.000000 0.000000 Si 0.750000 0.500000 0.750000 F """ expected = """Test1 1.0 3.840198 -0.000000 -0.000000 -1.920099 -3.325710 -0.000000 -0.000000 2.217138 -3.135509 Si F 1 1 direct 0.000000 0.000000 0.000000 Si 0.750000 0.500000 0.750000 F """ poscar = Poscar.from_string(poscar_string) self.assertEqual(str(poscar), expected)
def test_automatic_kpoint(self): # s = PymatgenTest.get_structure("Li2O") p = Poscar.from_string("""Al1 1.0 2.473329 0.000000 1.427977 0.824443 2.331877 1.427977 0.000000 0.000000 2.855955 Al 1 direct 0.000000 0.000000 0.000000 Al""") kpoints = Kpoints.automatic_density(p.structure, 1000) self.assertArrayAlmostEqual(kpoints.kpts[0], [10, 10, 10])
def test_str(self): si = 14 coords = list() coords.append([0, 0, 0]) coords.append([0.75, 0.5, 0.75]) # Silicon structure for testing. latt = [[3.8401979337, 0.00, 0.00], [1.9200989668, 3.3257101909, 0.00], [0.00, -2.2171384943, 3.1355090603]] struct = Structure(latt, [si, si], coords) poscar = Poscar(struct) expected_str = '''Si2 1.0 3.840198 0.000000 0.000000 1.920099 3.325710 0.000000 0.000000 -2.217138 3.135509 Si 2 direct 0.000000 0.000000 0.000000 Si 0.750000 0.500000 0.750000 Si ''' self.assertEqual(str(poscar), expected_str, "Wrong POSCAR output!") # Vasp 4 type with symbols at the end. poscar_string = """Test1 1.0 -3.840198 0.000000 0.000000 1.920099 3.325710 0.000000 0.000000 -2.217138 3.135509 1 1 direct 0.000000 0.000000 0.000000 Si 0.750000 0.500000 0.750000 F """ expected = """Test1 1.0 3.840198 -0.000000 -0.000000 -1.920099 -3.325710 -0.000000 -0.000000 2.217138 -3.135509 Si F 1 1 direct 0.000000 0.000000 0.000000 Si 0.750000 0.500000 0.750000 F """ poscar = Poscar.from_string(poscar_string) self.assertEqual(str(poscar), expected)
def test_cart_scale(self): poscar_string = """Test1 1.1 3.840198 0.000000 0.000000 1.920099 3.325710 0.000000 0.000000 -2.217138 3.135509 Si F 1 1 cart 0.000000 0.00000000 0.00000000 3.840198 1.50000000 2.35163175 """ p = Poscar.from_string(poscar_string) site = p.structure[1] self.assertArrayAlmostEqual(site.coords, np.array([3.840198, 1.5, 2.35163175]) * 1.1)
def get_minkowski_red(structure): """ Get a minkowski reduced structure """ output = run_aconvasp_command(["aconvasp", "--kpath"], structure) started = False poscar_string = "" if "ERROR" in output[1]: raise AconvaspError(output[1]) for line in output[0].split("\n"): if started or line.find("KPOINTS TO RUN") != -1: poscar_string = poscar_string + line + "\n" if line.find("STRUCTURE TO RUN") != -1: started = True if line.find("KPOINTS TO RUN") != -1: started = False return Poscar.from_string(poscar_string).structure
def test_to_from_dict(self): poscar_string = """Test3 1.0 3.840198 0.000000 0.000000 1.920099 3.325710 0.000000 0.000000 -2.217138 3.135509 1 1 Selective dynamics direct 0.000000 0.000000 0.000000 T T T Si 0.750000 0.500000 0.750000 F F F O """ poscar = Poscar.from_string(poscar_string) d = poscar.as_dict() poscar2 = Poscar.from_dict(d) self.assertEqual(poscar2.comment, "Test3") self.assertTrue(all(poscar2.selective_dynamics[0])) self.assertFalse(all(poscar2.selective_dynamics[1]))
def _preprocess_dielectric_constant(df): """ Preprocessor used to convert the dielectric_constant dataset to the dataframe desired for JSON conversion Args: df (pandas.DataFrame) Returns: (pandas.DataFrame) """ df['cif'] = df['structure'] df['structure'] = pandas.Series([Poscar.from_string(s).structure for s in df['poscar']]) new_columns = ['material_id', 'formula', 'nsites', 'space_group', 'volume', 'structure', 'band_gap', 'e_electronic', 'e_total', 'n', 'poly_electronic', 'poly_total', 'pot_ferroelectric', 'cif', 'meta', 'poscar'] return df[new_columns]
def from_poscar_string(poscar_string, transformations=None): """ Generates TransformedStructure from a poscar string. Args: poscar_string (str): Input POSCAR string. transformations ([Transformations]): Sequence of transformations to be applied to the input structure. """ p = Poscar.from_string(poscar_string) if not p.true_names: raise ValueError("Transformation can be craeted only from POSCAR " "strings with proper VASP5 element symbols.") raw_string = re.sub("'", "\"", poscar_string) s = p.structure source_info = {"source": "POSCAR", "datetime": str(datetime.datetime.now()), "original_file": raw_string} return TransformedStructure(s, transformations, history=[source_info])
def from_poscar_string(poscar_string, transformations=None): """ Generates TransformedStructure from a poscar string. Args: poscar_string (str): Input POSCAR string. transformations ([Transformations]): Sequence of transformations to be applied to the input structure. """ p = Poscar.from_string(poscar_string) if not p.true_names: raise ValueError("Transformation can be craeted only from POSCAR " "strings with proper VASP5 element symbols.") raw_string = re.sub(r"'", "\"", poscar_string) s = p.structure source_info = {"source": "POSCAR", "datetime": str(datetime.datetime.now()), "original_file": raw_string} return TransformedStructure(s, transformations, history=[source_info])
def _preprocess_piezoelectric_tensor(df): """ Preprocessor used to convert the piezoelectric_constant dataset to the dataframe desired for JSON conversion Args: df (pandas.DataFrame) Returns: (pandas.DataFrame) """ for i in list(df.index): c = 'piezoelectric_tensor' df.at[(i, c)] = np.array(ast.literal_eval(df.at[(i, c)])) df['cif'] = df['structure'] df['structure'] = pandas.Series([Poscar.from_string(s).structure for s in df['poscar']]) new_columns = ['material_id', 'formula', 'nsites', 'point_group', 'space_group', 'volume', 'structure', 'eij_max', 'v_max', 'piezoelectric_tensor', 'cif', 'meta', 'poscar'] return df[new_columns]
def test_poscar_string(kind): base_structure = get_lattice(kind) num_type = 2 index = 4 species = [Element("Cu"), Element("Au")] se = StructureEnumerator( base_structure, index, num_type, species, color_exchange=True, remove_superperiodic=True, ) list_ds_mg = se.generate(output="pymatgen") list_ds_pc = se.generate(output="poscar") assert len(list_ds_mg) == len(list_ds_pc) for expect, poscar_str in zip(list_ds_mg, list_ds_pc): actual = Poscar.from_string(poscar_str).structure assert expect == actual
def _preprocess_elastic_tensor_2015(df): """ Preprocessor used to convert the elastic_tensor_2015 dataset to the dataframe desired for JSON conversion Args: df (pandas.DataFrame) Returns: (pandas.DataFrame) """ for i in list(df.index): for c in ['compliance_tensor', 'elastic_tensor', 'elastic_tensor_original']: df.at[(i, c)] = np.array(ast.literal_eval(df.at[(i, c)])) df['cif'] = df['structure'] df['structure'] = pandas.Series([Poscar.from_string(s).structure for s in df['poscar']]) new_columns = ['material_id', 'formula', 'nsites', 'space_group', 'volume', 'structure', 'elastic_anisotropy', 'G_Reuss', 'G_VRH', 'G_Voigt', 'K_Reuss', 'K_VRH', 'K_Voigt', 'poisson_ratio', 'compliance_tensor', 'elastic_tensor', 'elastic_tensor_original', 'cif', 'kpoint_density', 'poscar'] return df[new_columns]
def _get_structures(self, num_structs): structs = [] if ".py" in makestr_cmd: options = ["-input", "struct_enum.out", str(1), str(num_structs)] else: options = ["struct_enum.out", str(0), str(num_structs - 1)] rs = subprocess.Popen([makestr_cmd] + options, stdout=subprocess.PIPE, stdin=subprocess.PIPE, close_fds=True) stdout, stderr = rs.communicate() if stderr: logger.warning(stderr.decode()) if len(self.ordered_sites) > 0: original_latt = self.ordered_sites[0].lattice # Need to strip sites of site_properties, which would otherwise # result in an index error. Hence Structure is reconstructed in # the next step. site_properties = {} for site in self.ordered_sites: for k, v in site.properties.items(): if k in site_properties: site_properties[k].append(v) else: site_properties[k] = [v] ordered_structure = Structure( original_latt, [site.species_and_occu for site in self.ordered_sites], [site.frac_coords for site in self.ordered_sites], site_properties=site_properties ) inv_org_latt = np.linalg.inv(original_latt.matrix) for file in glob.glob('vasp.*'): with open(file) as f: data = f.read() data = re.sub(r'scale factor', "1", data) data = re.sub(r'(\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 = ordered_structure * 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) else: warnings.warn("Skipping sites that include species X.") structs.append(Structure.from_sites(sorted(sites))) logger.debug("Read in a total of {} structures.".format(num_structs)) return structs
def _getStruct(system_data,space_data,structure_data,args): """Writes a vasp POSCAR style file for the input structure and system data. :arg system_data: a dictionary of the system_data :arg space_data: a dictionary containing the spacial data :arg structure_data: a dictionary of the data for this structure :arg args: Dictionary of user supplied input. """ from numpy import array from random import uniform # Get the labeling, group index, structure number and arrow labels # from the input data structure. labeling = structure_data["labeling"] gIndx = space_data["gIndx"] arrows = structure_data["directions"] struct_n = structure_data["strN"] # The arrow basis. arrow_directions = [[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]] directions = [] # Construct the concentrations of the atoms from the labeling by # counting the number of each type of atom present in the # labeling. concs = {} for i in args["id_mapping"].keys(): this_conc = 0 for atom in range(structure_data["n"]*system_data["nD"]): if labeling[gIndx[atom]] == str(i): this_conc += 1 concs[i] = this_conc def_title = "{} str #: {}\n".format(str(system_data["title"]),str(structure_data["strN"])) # Get the lattice parameter for the atomic species provided by the # user. num_vac = 0 if args["vacancy"] != None: num_vac = 1 lattice_parameter, title = _get_lattice_parameter(args["id_mapping"],concs,system_data["plattice"], system_data["nD"],def_title,args["scale_factor"], args["remove_zeros"],args["vegards"]) # Find out the directions for each arrow. for arrow in arrows: directions.append(array(arrow_directions[int(arrow)])) sLV = space_data["sLV"] # First write the title and the lattice parameter. poscar = title poscar += "{0:.3f}\n".format(lattice_parameter) # Then write out the lattice vectors. for i in range(3): poscar += " {}\n".format(" ".join( ["{0: .9f}".format(j) for j in sLV[i]])) # Write the concentrations to the output file. If the species # strings were passed in by the user and the user requests # there be no zeros in the concentration string then we should # remove them from the file. Otherwise we default to leaving # them in. if (args["remove_zeros"] and args["id_mapping"] is not None): types = "" amounts = "" for ic in concs.keys(): if concs[ic] != 0: types += "{} ".format(args["id_mapping"][ic]) amounts += "{} ".format(str(concs[ic])) poscar += " {}\n".format(types) poscar += " {}".format(amounts) else: keys = concs.keys() poscar += " {}\n".format(" ".join([args["id_mapping"][key] for key in keys])) poscar += " " for ic in keys: poscar += "{} ".format(str(concs[ic])) poscar += "\n" poscar += "D\n" # Now write out the atomic positions to the file. for ilab in args["id_mapping"].keys(): for iAt in range(structure_data["n"]*system_data["nD"]): rattle = uniform(-args["rattle"],args["rattle"]) displace = directions[iAt]*args["displace"]*lattice_parameter # If the displacement is non zero and we're `rattling` # the system then we need to modify the displacement # by the amount being rattled. displace += displace*rattle if labeling[gIndx[iAt]] == str(ilab): # The final atomic position is the position from # the basis plus the total displacement. out_array = array(space_data["aBas"][iAt]) + displace poscar += " {}\n".format( " ".join(["{0: .9f}".format(i) for i in out_array.tolist()])) return Poscar.from_string(poscar).structure
def _get_structures(self, num_structs): structs = [] if ".py" in makestr_cmd: options = ["-input", "struct_enum.out", str(1), str(num_structs)] else: options = ["struct_enum.out", str(0), str(num_structs - 1)] rs = subprocess.Popen([makestr_cmd] + options, stdout=subprocess.PIPE, stdin=subprocess.PIPE, close_fds=True) stdout, stderr = rs.communicate() if stderr: logger.warning(stderr.decode()) # sites retrieved from enumlib will lack site properties # to ensure consistency, we keep track of what site properties # are missing and set them to None # TODO: improve this by mapping ordered structure to original # disorded structure, and retrieving correct site properties disordered_site_properties = {} if len(self.ordered_sites) > 0: original_latt = self.ordered_sites[0].lattice # Need to strip sites of site_properties, which would otherwise # result in an index error. Hence Structure is reconstructed in # the next step. site_properties = {} for site in self.ordered_sites: for k, v in site.properties.items(): disordered_site_properties[k] = None if k in site_properties: site_properties[k].append(v) else: site_properties[k] = [v] ordered_structure = Structure( original_latt, [site.species for site in self.ordered_sites], [site.frac_coords for site in self.ordered_sites], site_properties=site_properties) inv_org_latt = np.linalg.inv(original_latt.matrix) for file in glob.glob('vasp.*'): with open(file) as f: data = f.read() data = re.sub(r'scale factor', "1", data) data = re.sub(r'(\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 = ordered_structure * 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, site.frac_coords, super_latt, to_unit_cell=True, properties=disordered_site_properties)) else: logger.debug("Skipping sites that include species X.") structs.append(Structure.from_sites(sorted(sites))) logger.debug("Read in a total of {} structures.".format(num_structs)) return structs