def gkfo_correction(efnv_correction): s1 = PotentialSite(specie="H", distance=1.999, potential=10, pc_potential=None) s2 = PotentialSite(specie="He", distance=2.0001, potential=15, pc_potential=2) s3 = PotentialSite(specie="He", distance=3.0, potential=20, pc_potential=3) return GkfoCorrection(init_efnv_correction=efnv_correction, additional_charge=1, pc_2nd_term=10.0, gkfo_sites=[s1, s2, s3], ave_dielectric_tensor=4.0, ave_electronic_dielectric_tensor=2.0)
def efnv_correction(): s1 = PotentialSite(specie="H", distance=1.999, potential=1.0, pc_potential=None) s2 = PotentialSite(specie="He", distance=2.0001, potential=1.5, pc_potential=0.2) s3 = PotentialSite(specie="He", distance=3.0, potential=2.0, pc_potential=0.3) return ExtendedFnvCorrection(charge=10, point_charge_correction=1.0, defect_region_radius=2.0, sites=[s1, s2, s3], defect_coords=(0.0, 0.0, 0.0))
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. """ if calc_results.structure.lattice != perfect_calc_results.structure.lattice: raise SupercellError("The lattice constants for defect and perfect " "models are different") structure_analyzer = DefectStructureComparator( 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) frac_coords = calc_results.structure[d].frac_coords distance, _ = lattice.get_distance_and_image(defect_coords, frac_coords) 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 test_make_efnv_correction(mocker): mock_perfect = mocker.Mock(spec=CalcResults, autospec=True) mock_defect = mocker.Mock(spec=CalcResults, autospec=True) mock_perfect.structure = IStructure(Lattice.cubic(10), species=["H"] + ["He"] * 3 + ["Li"], coords=[[0, 0, 0], [1 / 2, 1 / 2, 0], [1 / 2, 0, 1 / 2], [0, 1 / 2, 1 / 2], [0, 0, 1 / 2]]) mock_defect.structure = IStructure(Lattice.cubic(10), species=["He"] * 3 + ["Li"], coords=[[1 / 2, 1 / 2, 0], [1 / 2, 0, 1 / 2], [0, 1 / 2, 1 / 2], [0, 0, 1 / 2]]) mock_perfect.potentials = [3.0, 4.0, 5.0, 6.0, 7.0] mock_defect.potentials = [14.0, 25.0, 36.0, 47.0] mock_ewald = mocker.patch("pydefect.cli.vasp.make_efnv_correction.Ewald") ewald = mocker.Mock() ewald.lattice_energy = 1e3 ewald.atomic_site_potential.return_value = 1e4 mock_ewald.return_value = ewald efnvc = make_efnv_correction(charge=2, calc_results=mock_defect, perfect_calc_results=mock_perfect, dielectric_tensor=np.eye(3)) unit_conversion = 180.95128169876497 assert efnvc.charge == 2 assert efnvc.point_charge_correction == -4e3 * unit_conversion assert efnvc.defect_region_radius == 5.0 assert efnvc.sites == [ PotentialSite("He", 5 * np.sqrt(2), 10.0, 2e4 * unit_conversion), PotentialSite("He", 5 * np.sqrt(2), 20.0, 2e4 * unit_conversion), PotentialSite("He", 5 * np.sqrt(2), 30.0, 2e4 * unit_conversion), PotentialSite("Li", 5.0, 40.0, None), ]
def efnv_cor(): return ExtendedFnvCorrection(charge=1, point_charge_correction=0.0, defect_region_radius=2.8, sites=[ PotentialSite(specie="H", distance=1.0, potential=-4, pc_potential=None), PotentialSite(specie="H", distance=2.0, potential=-3, pc_potential=None), PotentialSite(specie="He", distance=3.0, potential=-2, pc_potential=-3), PotentialSite(specie="He", distance=4.0, potential=-1, pc_potential=-2) ], defect_coords=(0.0, 0.0, 0.0))
def make_gkfo_correction( efnv_correction: ExtendedFnvCorrection, additional_charge: int, final_calc_results: CalcResults, initial_calc_results: CalcResults, diele_tensor: np.array, ion_clamped_diele_tensor: np.array, accuracy: float = defaults.ewald_accuracy, unit_conversion: float = 180.95128169876497) -> GkfoCorrection: assert final_calc_results.structure == initial_calc_results.structure assert abs(additional_charge) == 1 defect_coords = efnv_correction.defect_coords lattice = initial_calc_results.structure.lattice ewald_ele = Ewald(lattice.matrix, ion_clamped_diele_tensor, accuracy=accuracy) defect_region_radius = efnv_correction.defect_region_radius pc_2nd_term = -ewald_ele.lattice_energy gkfo_sites = [] for index, site in enumerate(initial_calc_results.structure): specie = site.specie dist, _ = lattice.get_distance_and_image(site.frac_coords, defect_coords) pot = (final_calc_results.potentials[index] - initial_calc_results.potentials[index]) rel_coord = [x - y for x, y in zip(site.frac_coords, defect_coords)] if dist <= defect_region_radius: pc_potential = None else: pc_potential = (ewald_ele.atomic_site_potential(rel_coord) * additional_charge * unit_conversion) gkfo_sites.append(PotentialSite(specie, dist, pot, pc_potential)) return GkfoCorrection( init_efnv_correction=efnv_correction, additional_charge=additional_charge, pc_2nd_term=pc_2nd_term * unit_conversion, gkfo_sites=gkfo_sites, ave_dielectric_tensor=np.trace(diele_tensor) / 3, ave_electronic_dielectric_tensor=np.trace(ion_clamped_diele_tensor) / 3)
def test_defect_site_msonable(efnv_correction): assert_msonable( PotentialSite(specie="H", distance=1.999, potential=1.0, pc_potential=0.1))
def test_defect_site_diff_pot(): s = PotentialSite("H", distance=1.999, potential=1.0, pc_potential=0.1) assert s.diff_pot == 1.0 - 0.1