def electronic_coupling_direction(initial, final, couplings=None): """ Allows transfer along a single direction :param initial: initial states list :param final: final states list :param couplings: coupling list :return: rate constant """ r_vector = initial[1].get_center().get_coordinates( ) - initial[0].get_center().get_coordinates() cell_incr = initial[0].cell_state - final[0].cell_state r = distance_vector_periodic(r_vector, initial[0].supercell, cell_incr) norm = np.linalg.norm(r) dot_a = np.abs(np.dot(r, [1, 0])) / np.linalg.norm([1, 0]) / norm dot_ab_1 = np.abs(np.dot(r, [1, 1])) / np.linalg.norm([1, 1]) / norm dot_ab_2 = np.abs(np.dot(r, [1, -1])) / np.linalg.norm([1, -1]) / norm dot_b = np.abs(np.dot(r, [0, 1])) / np.linalg.norm([0, 1]) / norm #print('->', dot_a, dot_ab_1, dot_ab_1, dot_b) ichosen = int(np.argmax([dot_a, dot_ab_1, dot_ab_2, dot_b])) # print('coup: ', ['a', 'ab', 'ab', 'b'][ichosen]) return couplings[ichosen] # eV
def get_neighbours_num(self, center): radius = self.cutoff_radius center_position = self.molecules[center].get_coordinates() def get_supercell_increments(supercell, radius): # TODO: This function can be optimized as a function of the particular molecule coordinates v = np.array(radius/np.linalg.norm(supercell, axis=1), dtype=int) + 1 # here extensive approximation return list(itertools.product(*[range(-i, i+1) for i in v])) cell_increments = get_supercell_increments(self.supercell, radius) if not '{}_{}'.format(center, radius) in self.neighbors: neighbours = [] jumps = [] for i, molecule in enumerate(self.molecules): coordinates = molecule.get_coordinates() for cell_increment in cell_increments: r_vec = distance_vector_periodic(coordinates - center_position, self.supercell, cell_increment) if 0 < np.linalg.norm(r_vec) < radius: neighbours.append(i) jumps.append(cell_increment) neighbours = np.array(neighbours) jumps = np.array(jumps) self.neighbors['{}_{}'.format(center, radius)] = [neighbours, jumps] return self.neighbors['{}_{}'.format(center, radius)]
def get_state_neighbors(self, ref_state): if ref_state not in self._state_neighbors: radius = self.cutoff_radius center_position = ref_state.get_coordinates_relative(self.supercell) def get_supercell_increments(supercell, radius): # TODO: This function can be optimized as a function of the particular molecule coordinates v = np.array(radius/np.linalg.norm(supercell, axis=1), dtype=int) + 1 # here extensive approximation return list(itertools.product(*[range(-i, i+1) for i in v])) cell_increments = get_supercell_increments(self.supercell, radius) # Get neighbor non ground states state_neighbors = [] state_cell_incr = [] # for state in self.get_ground_states() + self.get_states(): for state in self.get_states(): coordinates = state.get_coordinates() for cell_increment in cell_increments: r_vec = distance_vector_periodic(coordinates - center_position, self.supercell, cell_increment) if 0 < np.linalg.norm(r_vec) < radius: state_neighbors.append(state) state_cell_incr.append(list(cell_increment)) # Include neighbor ground states state_neighbors_gs, state_cell_incr_gs = self.get_ground_states_improved(ref_state) state_cell_incr = state_cell_incr_gs + state_cell_incr state_neighbors = state_neighbors_gs + state_neighbors self._state_neighbors[ref_state] = [state_neighbors, state_cell_incr] return self._state_neighbors[ref_state]
def get_state_neighbors_copy(self, ref_state): """ Not used for now. To be deprecated in the future :param ref_state: :return: """ radius = self.cutoff_radius center_position = ref_state.get_coordinates_relative(self.supercell) def get_supercell_increments(supercell, radius): # TODO: This function can be optimized as a function of the particular molecule coordinates v = np.array(radius/np.linalg.norm(supercell, axis=1), dtype=int) + 1 # here extensive approximation return list(itertools.product(*[range(-i, i+1) for i in v])) cell_increments = get_supercell_increments(self.supercell, radius) neighbours = [] for state in self.get_ground_states(): coordinates = state.get_coordinates() for cell_increment in cell_increments: r_vec = distance_vector_periodic(coordinates - center_position, self.supercell, cell_increment) if 0 < np.linalg.norm(r_vec) < radius: state = state.copy() state.cell_state = ref_state.cell_state + cell_increment neighbours.append(state) return neighbours
def intermolecular_vector(molecule_1, molecule_2, supercell, cell_incr): """ :param molecule_1: donor :param molecule_2: acceptor :return: the distance between the donor and the acceptor """ position_d = molecule_1.get_coordinates() position_a = molecule_2.get_coordinates() r_vector = position_a - position_d r = distance_vector_periodic(r_vector, supercell, cell_incr) return r
def distance_matrix(molecules_list, supercell, max_distance=1): # Set maximum possible distance everywhere distances = np.ones( (len(molecules_list), len(molecules_list))) * np.product( np.diag(supercell)) for i, mol_i in enumerate(molecules_list): for j, mol_j in enumerate(molecules_list): coordinates = mol_i.get_coordinates() center_position = mol_j.get_coordinates() cell_increments = get_supercell_increments(supercell, max_distance) for cell_increment in cell_increments: r_vec = distance_vector_periodic(coordinates - center_position, supercell, cell_increment) d = np.linalg.norm(r_vec) if distances[i, j] > d: distances[i, j] = d return distances