def calculate_dynmat_derivatives(self, direction): q_point = self.q_point is_amorphous = self.is_amorphous distance_threshold = self.distance_threshold atoms = self.atoms list_of_replicas = self.second.list_of_replicas replicated_cell = self.second.replicated_atoms.cell replicated_cell_inv = self.second._replicated_cell_inv cell_inv = self.second.cell_inv dynmat = self.second.dynmat positions = self.atoms.positions n_unit_cell = atoms.positions.shape[0] n_modes = n_unit_cell * 3 n_replicas = np.prod(self.supercell) shape = (1, n_unit_cell * 3, n_unit_cell * 3) if is_amorphous: type = np.float else: type = np.complex dir = ['_x', '_y', '_z'] log_size(shape, type, name='dynamical_matrix_derivative_' + dir[direction]) if is_amorphous: distance = positions[:, np.newaxis, :] - positions[np.newaxis, :, :] distance = wrap_coordinates(distance, replicated_cell, replicated_cell_inv) dynmat_derivatives = contract('ij,ibjc->ibjc', tf.convert_to_tensor(distance[..., direction]), dynmat[0, :, :, 0, :, :], backend='tensorflow') else: distance = positions[:, np.newaxis, np.newaxis, :] - ( positions[np.newaxis, np.newaxis, :, :] + list_of_replicas[np.newaxis, :, np.newaxis, :]) if distance_threshold is not None: distance_to_wrap = positions[:, np.newaxis, np.newaxis, :] - ( self.second.replicated_atoms.positions.reshape(n_replicas, n_unit_cell, 3)[ np.newaxis, :, :, :]) shape = (n_unit_cell, 3, n_unit_cell, 3) type = np.complex dynmat_derivatives = np.zeros(shape, dtype=type) for l in range(n_replicas): wrapped_distance = wrap_coordinates(distance_to_wrap[:, l, :, :], replicated_cell, replicated_cell_inv) mask = (np.linalg.norm(wrapped_distance, axis=-1) < distance_threshold) id_i, id_j = np.argwhere(mask).T dynmat_derivatives[id_i, :, id_j, :] += contract('f,fbc->fbc', distance[id_i, l, id_j, direction], \ dynmat.numpy()[0, id_i, :, 0, id_j, :] * chi(q_point, list_of_replicas, cell_inv)[l]) else: dynmat_derivatives = contract('ilj,ibljc,l->ibjc', tf.convert_to_tensor(distance.astype(np.complex)[..., direction]), tf.cast(dynmat[0], tf.complex128), tf.convert_to_tensor(chi(q_point, list_of_replicas, cell_inv).flatten().astype(np.complex)), backend='tensorflow') dynmat_derivatives = tf.reshape(dynmat_derivatives, (n_modes, n_modes)) return dynmat_derivatives
def calculate_dynmat_fourier(self): q_point = self.q_point distance_threshold = self.distance_threshold atoms = self.atoms n_unit_cell = atoms.positions.shape[0] n_replicas = np.prod(self.supercell) dynmat = self.second.dynmat cell_inv = self.second.cell_inv replicated_cell_inv = self.second._replicated_cell_inv is_at_gamma = (q_point == (0, 0, 0)).all() is_amorphous = (n_replicas == 1) list_of_replicas = self.second.list_of_replicas log_size((self.n_modes, self.n_modes), np.complex, name='dynmat_fourier') if distance_threshold is not None: shape = (n_unit_cell, 3, n_unit_cell, 3) type = np.complex dyn_s = np.zeros(shape, dtype=type) replicated_cell = self.second.replicated_atoms.cell for l in range(n_replicas): distance_to_wrap = atoms.positions[:, np.newaxis, :] - ( self.second.replicated_atoms.positions.reshape( n_replicas, n_unit_cell, 3)[np.newaxis, l, :, :]) distance_to_wrap = wrap_coordinates(distance_to_wrap, replicated_cell, replicated_cell_inv) mask = np.linalg.norm(distance_to_wrap, axis=-1) < distance_threshold id_i, id_j = np.argwhere(mask).T dyn_s[id_i, :, id_j, :] += dynmat.numpy()[0, id_i, :, 0, id_j, :] * chi( q_point, list_of_replicas, cell_inv)[l] else: if is_at_gamma: if is_amorphous: dyn_s = dynmat[0] else: dyn_s = contract('ialjb->iajb', dynmat[0], backend='tensorflow') else: dyn_s = contract('ialjb,l->iajb', tf.cast(dynmat[0], tf.complex128), tf.convert_to_tensor( chi(q_point, list_of_replicas, cell_inv).flatten()), backend='tensorflow') dyn_s = tf.reshape(dyn_s, (self.n_modes, self.n_modes)) return dyn_s
def unfold_third_order(self, reduced_third=None, distance_threshold=None): """ This method extrapolates a third order force constant matrix from a unit cell into a matrix for a larger supercell. Parameters ---------- reduced_third : array, optional The third order force constant matrix. Default is `self.third` distance_threshold : float, optional When calculating force constants, contributions from atoms further than the distance threshold will be ignored. Default is self.distance_threshold """ logging.info('Unfolding third order matrix') if distance_threshold is None: if self.distance_threshold is not None: distance_threshold = self.distance_threshold else: raise ValueError( 'Please specify a distance threshold in Angstrom') logging.info('Distance threshold: ' + str(distance_threshold) + ' A') if (self.atoms.cell[0, 0] / 2 < distance_threshold) | \ (self.atoms.cell[1, 1] / 2 < distance_threshold) | \ (self.atoms.cell[2, 2] / 2 < distance_threshold): logging.warning( 'The cell size should be at least twice the distance threshold' ) if reduced_third is None: reduced_third = self.third.value n_unit_atoms = self.n_atoms atoms = self.atoms n_replicas = self.n_replicas replicated_cell_inv = np.linalg.inv(self.third.replicated_atoms.cell) reduced_third = reduced_third.reshape( (n_unit_atoms, 3, n_replicas, n_unit_atoms, 3, n_replicas, n_unit_atoms, 3)) replicated_positions = self.third.replicated_atoms.positions.reshape( (n_replicas, n_unit_atoms, 3)) dxij_reduced = wrap_coordinates( atoms.positions[:, np.newaxis, np.newaxis, :] - replicated_positions[np.newaxis, :, :, :], self.third.replicated_atoms.cell, replicated_cell_inv) indices = np.argwhere( np.linalg.norm(dxij_reduced, axis=-1) < distance_threshold) coords = [] values = [] for index in indices: for l in range(n_replicas): for j in range(n_unit_atoms): dx2 = dxij_reduced[index[0], l, j] is_storing = (np.linalg.norm(dx2) < distance_threshold) if is_storing: for alpha in range(3): for beta in range(3): for gamma in range(3): coords.append([ index[0], alpha, index[1], index[2], beta, l, j, gamma ]) values.append(reduced_third[index[0], alpha, 0, index[2], beta, 0, j, gamma]) logging.info('Created unfolded third order') shape = (n_unit_atoms, 3, n_replicas, n_unit_atoms, 3, n_replicas, n_unit_atoms, 3) expanded_third = COO(np.array(coords).T, np.array(values), shape) expanded_third = expanded_third.reshape( (n_unit_atoms * 3, n_replicas * n_unit_atoms * 3, n_replicas * n_unit_atoms * 3)) return expanded_third