Source code for qDNA.hamiltonian.tb_matrices

from itertools import product

import numpy as np

from ..model import get_eh_distance

# ----------------------------------------------------------------------


[docs] def set_matrix_element( matrix, tb_value, new_state, old_state, basis, ): """Sets the matrix element for the Hamiltonian matrix ensuring hermiticity. Parameters ---------- matrix : np.ndarray The Hamiltonian matrix. tb_value : float The tight-binding value to set. new_state : str The new state in the basis. old_state : str The old state in the basis. basis : List[str] The list of basis states. Returns ------- np.ndarray The updated Hamiltonian matrix. Examples -------- >>> set_matrix_element(np.zeros((2, 2)), 1, "(0, 0)", "(1, 0)", ["(0, 0)", "(1, 0)"]) array([[0., 1.], [1., 0.]]) """ old_state_idx = basis.index(old_state) new_state_idx = basis.index(new_state) matrix[new_state_idx][old_state_idx] += tb_value # ensure hermiticity if old_state != new_state: matrix[old_state_idx][new_state_idx] += tb_value return matrix
[docs] def tb_ham_1P( tb_dims, tb_config, tb_basis, tb_param_dict, tb_basis_sites_dict, ): """Constructs the particle tight-binding Hamiltonian matrix. Parameters ---------- tb_dims : Tuple[int, int] Dimensions of the tight-binding model grid. tb_config : List[Tuple[str, str, str]] Configuration of tight-binding connections. tb_basis : List[str] List of basis states. tb_param_dict : Dict[str, float] Dictionary of tight-binding parameters. tb_basis_sites_dict : Dict[str, str] Dictionary mapping the TB basis to the TB sites. Returns ------- np.ndarray The tight-binding Hamiltonian matrix. Examples -------- >>> tb_dims = (2, 2) >>> tb_config = [("C", "(0, 0)", "(1, 0)"), ("E", "(0, 0)", "(0, 0)")] >>> tb_basis = ["(0, 0)", "(1, 0)", "(0, 1)", "(1, 1)"] >>> tb_param_dict = {"E_G": 1.0, "C_G_C": 0.5} >>> tb_basis_sites_dict = {"(0, 0)": "G", "(1, 0)": "C"} >>> tb_ham_1P(tb_dims, tb_config, tb_basis, tb_param_dict, tb_basis_sites_dict) array([[1. , 0.5, 0. , 0. ], [0.5, 0. , 0. , 0. ], [0. , 0. , 0. , 0. ], [0. , 0. , 0. , 0. ]]) """ n = tb_dims[0] * tb_dims[1] matrix = np.zeros((n, n)) if tb_param_dict == {}: # empty dictionary return matrix for tb_str, old_state, new_state in tb_config: old_state, new_state = str(old_state), str(new_state) if tb_str == "E": tb_str = f"E_{tb_basis_sites_dict[old_state]}" else: tb_str = f"{tb_str}_{tb_basis_sites_dict[old_state]}_{tb_basis_sites_dict[new_state]}" # for interstrand hopping the direction is not imporant if tb_str[0] in ["h", "r"] and tb_str not in tb_param_dict: tb_str = f"{tb_str.split('_')[0]}_{tb_str.split('_')[2]}_{tb_str.split('_')[1]}" if tb_str not in tb_param_dict: raise ValueError( f"Tight-binding parameter '{tb_str}' not found in the parameter dictionary." ) tb_val = tb_param_dict[tb_str] matrix = set_matrix_element(matrix, tb_val, new_state, old_state, tb_basis) return matrix
[docs] def tb_ham_2P( tb_dims, tb_config, tb_basis, tb_params, tb_basis_sites_dict, ): """Constructs the electron-hole tight-binding Hamiltonian matrix. Parameters ---------- tb_dims : Tuple[int, int] Dimensions of the tight-binding model grid. tb_config : List[Tuple[str, str, str]] Configuration of tight-binding connections. tb_basis : List[str] List of basis states. tb_params : Dict[str, Dict[str, float]] Dictionary containing electron, hole, and optionally exciton tight-binding parameters. tb_basis_sites_dict : Dict[str, str] Dictionary mapping the TB basis to the TB sites. Returns ------- np.ndarray The electron-hole tight-binding Hamiltonian matrix. """ matrix_electron = tb_ham_1P( tb_dims, tb_config, tb_basis, tb_params["electron"], tb_basis_sites_dict ) matrix_hole = tb_ham_1P(tb_dims, tb_config, tb_basis, tb_params["hole"], tb_basis_sites_dict) dim = matrix_hole.shape[0] matrix = np.zeros((dim**2, dim**2)) # exciton matrix only if tb_params["exciton"] exists. if "exciton" in tb_params: matrix_exciton = tb_ham_1P( tb_dims, tb_config, tb_basis, tb_params["exciton"], tb_basis_sites_dict ) # exciton matrix if not np.allclose(matrix_exciton, np.zeros((dim, dim))): for i, j in product(range(dim), repeat=2): basis_matrix = np.zeros((dim, dim)) basis_matrix[i, j] = 1 matrix += matrix_exciton[i, j] * np.kron(basis_matrix, basis_matrix) num_sites = tb_dims[0] * tb_dims[1] matrix += np.kron(np.eye(num_sites), matrix_hole) matrix += np.kron(matrix_electron, np.eye(num_sites)) return matrix
[docs] def add_groundstate(matrix): """Adds a dimension to the matrix to include the ground state. Parameters ---------- matrix : np.ndarray Input matrix. Returns ------- np.ndarray Matrix with an additional dimension for the ground state. Examples -------- >>> add_groundstate(np.array([[1, 2], [3, 4]])) array([[0., 0., 0.], [0., 1., 2.], [0., 3., 4.]]) """ N = matrix.shape[0] matrix = np.r_[np.zeros((1, N)), matrix] matrix = np.c_[np.zeros((N + 1, 1)), matrix] return matrix
[docs] def delete_groundstate(matrix): """Removes the ground state dimension from the matrix. Parameters ---------- matrix : np.ndarray Input matrix with ground state dimension. Returns ------- np.ndarray Matrix without the ground state dimension. Examples -------- >>> delete_groundstate(np.array([[0., 0., 0.], [0., 1., 2.], [0., 3., 4.]])) array([[1., 2.], [3., 4.]]) """ return matrix[1:, 1:]
[docs] def add_interaction( matrix, eh_basis, interaction_param, interaction_type, nn_cutoff=False, ): """Adds interaction terms to the Hamiltonian based on the distance between electron and hole. Parameters ---------- matrix : np.ndarray The initial Hamiltonian matrix. eh_basis : List[Tuple[str, str]] List of electron and hole positions as tuples of strings. interaction_param : float The interaction parameter. interaction_type : str The type of interaction. Either 'Coulomb' or 'Exchange'. nn_cutoff : bool, optional If True, only nearest neighbor interactions are considered. Returns ------- np.ndarray Hamiltonian matrix with interaction terms added. Notes ----- .. note:: This works only for a Hamiltonian without the additional basis element accounting for relaxation. Therefore the interaction should always be added before the relaxation. Examples -------- >>> Hamiltonian = np.array([[0, 1], [1, 0]]) >>> eh_basis = [("(0, 0)", "(1, 1)"), ("(1, 0)", "(0, 0)")] >>> add_interaction(Hamiltonian, eh_basis, 1.0, "Coulomb", True) array([[0. , 1.17639077], [1.17639077, 0. ]]) """ distance_list = get_eh_distance(eh_basis) assert interaction_type in [ "Coulomb", "Exchange", ], "Interaction type not supported." # as used by Bittner interaction_strength_list = [] if interaction_type == "Coulomb": interaction_strength_list = interaction_param / (1 + 3.4 / 1 * distance_list) elif interaction_type == "Exchange": interaction_strength_list = interaction_param * np.exp(-3.4 / 0.5 * distance_list) # nearest neighbor cutoff if nn_cutoff: for i in np.where(distance_list > 1): interaction_strength_list[i] = 0 # add interaction terms on the diagonal for exciton states for eh_basis_state_idx, interaction_strength in enumerate(interaction_strength_list): eh_basis_state = eh_basis[eh_basis_state_idx] matrix = set_matrix_element( matrix, interaction_strength, eh_basis_state, eh_basis_state, eh_basis ) return matrix
# ----------------------------------------------------------------------