def make_efnv_correction(charge: int, calc_results: CalcResults, perfect_calc_results: CalcResults, dielectric_tensor: np.array, accuracy: float = defaults.ewald_accuracy, unit_conversion: float = 180.95128169876497): """ Notes: (1) The formula written in YK2014 need to be divided by 4pi in the SI unit. (2) When assuming an element charge locate at the defect_coords and angstrom for length, relative dielectric tensor, Multiply elementary_charge * 1e10 / epsilon_0 = 180.95128169876497 to make potential in V. """ assert calc_results.structure.lattice == perfect_calc_results.structure.lattice structure_analyzer = DefectStructureAnalyzer( calc_results.structure, perfect_calc_results.structure) defect_coords = structure_analyzer.defect_center_coord lattice = calc_results.structure.lattice ewald = Ewald(lattice.matrix, dielectric_tensor, accuracy=accuracy) point_charge_correction = \ 0.0 if not charge else - ewald.lattice_energy * charge ** 2 defect_region_radius = calc_max_sphere_radius(lattice.matrix) sites = [] for d, p in structure_analyzer.atom_mapping.items(): specie = str(calc_results.structure[d].specie) distance = structure_analyzer.distance_from_center(d) pot = calc_results.potentials[d] - perfect_calc_results.potentials[p] coord = calc_results.structure[d].frac_coords rel_coord = [x - y for x, y in zip(coord, defect_coords)] if distance <= defect_region_radius: pc_potential = None else: if charge == 0: pc_potential = 0 else: pc_potential = ewald.atomic_site_potential(rel_coord) * charge pc_potential *= unit_conversion sites.append(PotentialSite(specie, distance, pot, pc_potential)) return ExtendedFnvCorrection( charge=charge, point_charge_correction=point_charge_correction * unit_conversion, defect_region_radius=defect_region_radius, sites=sites, defect_coords=tuple(defect_coords))
def make_scene_dicts_json(parchg_list: List[str], calc_results: CalcResults, perfect_calc_results: CalcResults, scene_level): structure_analyzer = DefectStructureAnalyzer( calc_results.structure, perfect_calc_results.structure) defect_pos = structure_analyzer.defect_center_coord scene_dicts = make_scene_dicts(parchg_list, defect_pos, level=scene_level) scene_dicts.to_json_file()
def make_defect_entry(name: str, charge: int, perfect_structure: IStructure, defect_structure: IStructure): analyzer = DefectStructureAnalyzer(perfect_structure, defect_structure) species = [] frac_coords = [] for d, p in enumerate(analyzer.p_to_d): if p is None: site = defect_structure[d] else: site = perfect_structure[p] species.append(site.specie) frac_coords.append(site.frac_coords) initial_structure = IStructure(perfect_structure.lattice, species, frac_coords) symmetrizer = StructureSymmetrizer(initial_structure) return DefectEntry(name, charge, initial_structure, None, site_symmetry=symmetrizer.point_group, defect_center=tuple(analyzer.defect_center_coord))
def structure_analyzer(): cu2o_perfect = IStructure(Lattice.cubic(5), species=["Cu"] * 4 + ["O"] * 2, coords=[[0.25, 0.25, 0.25], [0.25, 0.74, 0.74], [0.75, 0.75, 0.25], [0.75, 0.25, 0.75], [0, 0, 0], [0.5, 0.5, 0.5]]) # add [0.1, -0.1, 0] # 3rd -- 6th # [0.85, 0.65, 0.25] - [0.76, 0.73, 0.24] = [0.09, -0.08, 0.01] # [0.85, 0.15, 0.75] - [0.75, 0.25, 0.73] = [0.10, -0.10, 0.02] # [0.1, -0.1, 0] -[0.1, -0.1, 0] = [0, 0, 0] # [0.6, 0.4, 0.5] - [0.5, 0.5, 0.5] = [0.1, -0.1, 0] cu2o_defect = IStructure( Lattice.cubic(5), species=["Cu"] * 3 + ["O"] * 2 + ["H"], coords=[ [0.25, 0.5, 0.5], # defect [0.76, 0.73, 0.24], [0.75, 0.25, 0.73], [0.1, 0.9, 0], [0.5, 0.5, 0.5], [0.25] * 3 ]) # defect return DefectStructureAnalyzer(defective_structure=cu2o_defect, perfect_structure=cu2o_perfect)
def test_neighboring_atom_indices(cubic_supercell): structure: Structure = cubic_supercell.copy() structure.pop(32) # [0.25, 0, 0] structure.pop(0) # [0, 0, 0] structure.append(species="Li", coords=[0.124, 0, 0]) structure.to(filename="POSCAR") structure_analyzer = DefectStructureAnalyzer(structure, cubic_supercell) assert structure_analyzer.neighboring_atom_indices == sorted( [25, 15, 16, 23, 54, 47, 46, 56, 62])
def test_actual_files(vasp_files): d = vasp_files / "KInO2_Va_O_2" calc_results: CalcResults = loadfn(d / "Va_O1_2/calc_results.json") perfect_calc_results: CalcResults = loadfn(d / "perfect_calc_results.json") dsa = DefectStructureAnalyzer(calc_results.structure, perfect_calc_results.structure) a = list(range(192)) a.pop(96) expected = dict(zip(range(191), a)) assert dsa.inserted_indices == [] assert dsa.vacancy_indices == [96] assert dsa.atom_mapping == expected
def make_edge_characters(args): for d in args.dirs: logger.info(f"Parsing data in {d} ...") vasprun = Vasprun(d / defaults.vasprun) procar = Procar(d / defaults.procar) outcar = Outcar(d / defaults.outcar) calc_results = loadfn(d / "calc_results.json") structure_analyzer = DefectStructureAnalyzer( calc_results.structure, args.perfect_calc_results.structure) edge_characters = MakeEdgeCharacters( procar, vasprun, outcar, structure_analyzer.neighboring_atom_indices).edge_characters edge_characters.to_json_file(d / "edge_characters.json")
def structure_analyzer_periodic_issue(): cu2o_perfect = IStructure(Lattice.cubic(5), species=["Cu"] * 4 + ["O"] * 2, coords=[[0.25, 0.25, 0.25], [0.25, 0.75, 0.75], [0.75, 0.75, 0.25], [0.75, 0.25, 0.75], [0, 0, 0], [0.5, 0.5, 0.5]]) # defect center is ([1.0, 1.0, 1.0] + [0.99, 0.99, 0.99]) / 2 = [0.995]*3 cu2o_defect = IStructure(Lattice.cubic(5), species=["Cu"] * 4 + ["O"] + ["H"], coords=[[0.25, 0.25, 0.25], [0.25, 0.75, 0.75], [0.75, 0.75, 0.25], [0.75, 0.25, 0.75], [0.5, 0.5, 0.5], [0.99, 0.99, 0.99]]) return DefectStructureAnalyzer(defective_structure=cu2o_defect, perfect_structure=cu2o_perfect)