def make_band_edge_states(orbital_infos: BandEdgeOrbitalInfos, p_edge_state: PerfectBandEdgeState, defect_charge_info: DefectChargeInfo = None ) -> BandEdgeStates: vbm_k_idx = orbital_infos.kpt_idx(p_edge_state.vbm_info.kpt_coord) cbm_k_idx = orbital_infos.kpt_idx(p_edge_state.cbm_info.kpt_coord) vbm_info = p_edge_state.vbm_info cbm_info = p_edge_state.cbm_info states = [] lowest_idx = orbital_infos.lowest_band_index for spin_idx, orb_info_by_spin in enumerate(orbital_infos.orbital_infos): if defect_charge_info: localized_orbs = defect_charge_info.localized_orbitals()[spin_idx] localized_orbs = [i - lowest_idx for i in localized_orbs] else: localized_orbs = None vbm_idx, vbm_diff = get_similar_orb_idx(orb_info_by_spin[vbm_k_idx], vbm_info, localized_orbs, _reversed=True) vbm_info = EdgeInfo(band_idx=vbm_idx + lowest_idx, kpt_coord=vbm_info.kpt_coord, orbital_info=orb_info_by_spin[vbm_k_idx][vbm_idx]) cbm_idx, cbm_diff = get_similar_orb_idx(orb_info_by_spin[cbm_k_idx], cbm_info, localized_orbs) cbm_info = EdgeInfo(band_idx=cbm_idx + lowest_idx, kpt_coord=cbm_info.kpt_coord, orbital_info=orb_info_by_spin[cbm_k_idx][cbm_idx]) loc_idx_range = [vbm_info.band_idx + 1, cbm_info.band_idx - 1] localized_orbs = get_localized_orbs(orb_info_by_spin, loc_idx_range, orbital_infos.lowest_band_index, orbital_infos.kpt_weights) vbm_hole = num_hole_in_vbm(orb_info_by_spin, vbm_idx=vbm_idx, weights=orbital_infos.kpt_weights) cbm_electron = num_electron_in_cbm(orb_info_by_spin, cbm_idx=cbm_idx, weights=orbital_infos.kpt_weights) states.append(BandEdgeState(vbm_info=vbm_info, cbm_info=cbm_info, vbm_orbital_diff=vbm_diff, cbm_orbital_diff=cbm_diff, localized_orbitals=localized_orbs, vbm_hole_occupation=vbm_hole, cbm_electron_occupation=cbm_electron)) return BandEdgeStates(states=states)
def test_plot_wo_spin(): be_orbital_info = BandEdgeOrbitalInfos(orbital_infos=[orb], kpt_coords=[(0.0, 0.0, 0.0), (0.25, 0.0, 0.0)], kpt_weights=[0.5, 0.5], lowest_band_index=10, fermi_level=0.5) plotter = EigenvalueMplPlotter(title="test", band_edge_orb_infos=be_orbital_info, supercell_vbm=0.1, supercell_cbm=0.9) plotter.construct_plot() plotter.plt.show()
def test_band_edge_orbital_info_repr(): orbital_info_1 = OrbitalInfo(energy=1.23456789, orbitals={ "Mn": [0.5, 0.4, 0.0, 0.0], "Fe": [0.0, 0.0, 0.0, 0.0] }, occupation=0.99998, participation_ratio=0.1111111) orbital_info_2 = OrbitalInfo(energy=2.34567890, orbitals={ "Mn": [0.1, 0.1, 0.0, 0.0], "Fe": [0.0, 0.0, 0.0, 0.0] }, occupation=0.0001, participation_ratio=0.2222222) band_edge_orbital_infos = \ BandEdgeOrbitalInfos(orbital_infos=[[[orbital_info_1, orbital_info_2]]], kpt_coords=[(0.0, 0.0, 0.0)], kpt_weights=[1.0], lowest_band_index=10, fermi_level=0.5) actual = band_edge_orbital_infos.__str__() print(actual) expected = """ -- band-edge orbitals info K-points info Index Coords Weight 1 ( 0.000, 0.000, 0.000) 1.000 Band info near band edges Index Kpoint index Energy Occupation P-ratio Orbital 11 1 1.23 1.0 0.1 Mn-s: 0.50, Mn-p: 0.40 -- 12 1 2.35 0.0 0.2 -- """ assert actual == expected
def orb_infos(): orbital_infos = [[[ OrbitalInfo(energy=-1.1, orbitals={ "Mn": [0.5, 0.6, 0.0, 0.0], "O": [0.0, 0.0, 0.0, 0.0] }, occupation=1.0, participation_ratio=0.1), OrbitalInfo(energy=-0.9, orbitals={ "Mn": [0.5, 0.7, 0.0, 0.0], "O": [0.0, 0.0, 0.0, 0.0] }, occupation=1.0, participation_ratio=0.1), # vbm OrbitalInfo(energy=0.0, orbitals={ "Mn": [0.1, 0.2, 0.0, 0.0], "O": [0.3, 0.4, 0.0, 0.0] }, occupation=1.0, participation_ratio=0.1), # in-gap OrbitalInfo(energy=1.0, orbitals={ "Mn": [0.5, 0.8, 0.0, 0.0], "O": [0.0, 0.0, 0.0, 0.0] }, occupation=0.05, participation_ratio=0.1), # in-gap OrbitalInfo(energy=1.2, orbitals={ "Mn": [0.0, 0.0, 0.0, 0.0], "O": [0.1, 0.3, 0.0, 0.0] }, occupation=0.02, participation_ratio=0.1), OrbitalInfo(energy=1.2, orbitals={ "Mn": [0.0, 0.0, 0.0, 0.0], "O": [0.1, 0.3, 0.0, 0.0] }, occupation=0.01, participation_ratio=0.1) ]]] # cbm return BandEdgeOrbitalInfos(kpt_coords=[(0.0, 0.0, 0.0)], kpt_weights=[1.0], orbital_infos=orbital_infos, lowest_band_index=8, fermi_level=0.5)
def make_band_edge_orbital_infos(procar: Procar, vasprun: Vasprun, vbm: float, cbm: float, str_info: DefectStructureInfo): eigval_range = defaults.eigval_range kpt_coords = [tuple(coord) for coord in vasprun.actual_kpoints] max_energy_by_spin, min_energy_by_spin = [], [] neighbors = str_info.neighbor_atom_indices for e in vasprun.eigenvalues.values(): max_energy_by_spin.append(np.amax(e[:, :, 0], axis=0)) min_energy_by_spin.append(np.amin(e[:, :, 0], axis=0)) max_energy_by_band = np.amax(np.vstack(max_energy_by_spin), axis=0) min_energy_by_band = np.amin(np.vstack(min_energy_by_spin), axis=0) lower_idx = np.argwhere(max_energy_by_band > vbm - eigval_range)[0][0] upper_idx = np.argwhere(min_energy_by_band < cbm + eigval_range)[-1][-1] orbs, s = procar.data, vasprun.final_structure orb_infos = [] for spin, eigvals in vasprun.eigenvalues.items(): orb_infos.append([]) for k_idx in range(len(kpt_coords)): orb_infos[-1].append([]) for b_idx in range(lower_idx, upper_idx + 1): e, occ = eigvals[k_idx, b_idx, :] orbitals = calc_orbital_character(orbs, s, spin, k_idx, b_idx) p_ratio = calc_participation_ratio(orbs, spin, k_idx, b_idx, neighbors) orb_infos[-1][-1].append(OrbitalInfo(e, orbitals, occ, p_ratio)) return BandEdgeOrbitalInfos( orbital_infos=orb_infos, kpt_coords=kpt_coords, kpt_weights=vasprun.actual_kpoints_weights, # need to convert numpy.int64 to int for mongoDB. lowest_band_index=int(lower_idx), fermi_level=vasprun.efermi)
orbitals={}, occupation=1.0, participation_ratio=0.3), OrbitalInfo(0.5, orbitals={}, occupation=0.5, participation_ratio=0.3), OrbitalInfo(1.0, orbitals={}, occupation=0.0, participation_ratio=0.3) ]] orbital_infos = BandEdgeOrbitalInfos(orbital_infos=[orb, orb], kpt_coords=[(0.0, 0.0, 0.0), (0.25, 0.0, 0.0)], kpt_weights=[0.5, 0.5], lowest_band_index=10, fermi_level=0.5) @pytest.fixture def eigenvalue_mpl_plotter(): return EigenvalueMplPlotter(title="test", band_edge_orb_infos=orbital_infos, supercell_vbm=0.1, supercell_cbm=0.9) def test_plot(eigenvalue_mpl_plotter): eigenvalue_mpl_plotter.construct_plot() eigenvalue_mpl_plotter.plt.show()
def band_edge_orbital_infos(orbital_info): return BandEdgeOrbitalInfos(orbital_infos=[[[orbital_info]]], kpt_coords=[(0.0, 0.0, 0.0)], kpt_weights=[1.0], lowest_band_index=10, fermi_level=0.5)
def test_make_band_edge_orbital_infos(mocker): mock_procar = mocker.Mock(spec=Procar, autospec=True) mock_vasprun = mocker.Mock(spec=Vasprun, autospec=True) mock_str_info = mocker.Mock(spec=DefectStructureInfo, autospec=True) mock_vasprun.actual_kpoints = [[0.0, 0.0, 0.0]] mock_vasprun.actual_kpoints_weights = [1.0] mock_vasprun.final_structure = Structure(Lattice.cubic(1), species=["H", "H", "He"], coords=[[0] * 3] * 3) mock_vasprun.eigenvalues = { Spin.up: np.array([ [ [-3.01, 1.], [-2.90, 1.], # vbm [8.01, 0.] ], [[-3.01, 1.], [-2.99, 1.], [7.90, 0.]] ]), # cbm # shift one band for testing magnetization Spin.down: np.array([[[-2.99, 1.], [7.99, 0.], [10.00, 0.]], [[-3.01, 1.], [8.00, 0.], [10.00, 0.]]]) } mock_vasprun.efermi = 20.0 # s: 1, p: 3, d: 5, f: 7 = 16 orbitals mock_procar.data = { Spin.up: np.array([ [ [ [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], # 1st kpt, 0th band, 1st atom [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], # 1st kpt, 0th band, 2nd atom [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] ], # 1st kpt, 0th band, 3rd atom [ [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], # 1st kpt, 1st band, 1st atom [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] ], [[1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]] ], [ [ [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], # 2nd kpt, 0th band, 1st atom [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] ], [[1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]], [[1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]] ] ]), Spin.down: np.array([ [ [ [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], # 1st kpt, 0th band, 1st atom [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], # 1st kpt, 0th band, 2nd atom [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] ], # 1st kpt, 0th band, 3rd atom [ [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], # 1st kpt, 1st band, 1st atom [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] ], [[1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]] ], [ [ [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], # 2nd kpt, 0th band, 1st atom [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] ], [[1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]], [[1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]] ] ]), } mock_str_info.neighbor_atom_indices = [0] actual = make_band_edge_orbital_infos(mock_procar, mock_vasprun, vbm=0.0, cbm=5.0, str_info=mock_str_info) expected = BandEdgeOrbitalInfos( orbital_infos=[[[ OrbitalInfo(energy=-2.9, orbitals={ "H": [1.0, 0.0, 0.0, 0.0], "He": [0.0, 0.0, 0.0, 0.0] }, occupation=1.0, participation_ratio=1.0), OrbitalInfo(energy=8.01, orbitals={ "H": [1.0, 0.0, 0.0, 0.0], "He": [0.0, 0.0, 0.0, 0.0] }, occupation=0.0, participation_ratio=1.0) ], [ OrbitalInfo(energy=-2.99, orbitals={ "H": [1.0, 0.0, 0.0, 0.0], "He": [0.0, 0.0, 0.0, 0.0] }, occupation=1.0, participation_ratio=1.0), OrbitalInfo(energy=7.90, orbitals={ "H": [1.0, 0.0, 0.0, 0.0], "He": [0.0, 0.0, 0.0, 0.0] }, occupation=0.0, participation_ratio=1.0) ]], [[ OrbitalInfo(energy=7.99, orbitals={ "H": [1.0, 0.0, 0.0, 0.0], "He": [0.0, 0.0, 0.0, 0.0] }, occupation=0.0, participation_ratio=1.0), OrbitalInfo(energy=10.00, orbitals={ "H": [1.0, 0.0, 0.0, 0.0], "He": [0.0, 0.0, 0.0, 0.0] }, occupation=0.0, participation_ratio=1.0) ], [ OrbitalInfo(energy=8.00, orbitals={ "H": [1.0, 0.0, 0.0, 0.0], "He": [0.0, 0.0, 0.0, 0.0] }, occupation=0.0, participation_ratio=1.0), OrbitalInfo(energy=10.00, orbitals={ "H": [1.0, 0.0, 0.0, 0.0], "He": [0.0, 0.0, 0.0, 0.0] }, occupation=0.0, participation_ratio=1.0) ]]], kpt_coords=[(0.0, 0.0, 0.0)], kpt_weights=[1.0], lowest_band_index=1, fermi_level=20.0) assert_dataclass_almost_equal(actual, expected)