def get_propagation(self, ham, psi_init, steps, dz, norm=False): """ Get the time evolution. :param ham: sparse.csr_matrix. Tight-Binding Hamilonian. :param psi_init: np.ndarray. Initial state. :param steps: Positive Integer. Number of steps. :param dz: Positive number. Step. :param norm: Boolean. Default value True. Normalize the norm to 1 at each step. """ error_handling.empty_ham(ham) error_handling.ndarray(psi_init, "psi_init", self.lat.sites) error_handling.positive_int(steps, "steps") error_handling.positive_real(dz, "dz") error_handling.boolean(norm, "norm") self.steps = steps self.dz = dz self.prop = np.empty((self.lat.sites, self.steps), "c16") self.prop[:, 0] = psi_init diag = 1j * np.ones(self.lat.sites, "c16") A = (sparse.diags(diag, 0) - 0.5 * self.dz * ham).toarray() B = (sparse.diags(diag, 0) + 0.5 * self.dz * ham).toarray() mat = np.dot(LA.inv(A), B) for i in range(1, self.steps): self.prop[:, i] = np.dot(mat, self.prop[:, i - 1]) if norm: self.prop[:, i] /= np.abs(self.prop[:, i]).sum()
def get_propagation(self, ham, psi_init, steps, dz, norm=False): ''' Get the time evolution. :param ham: sparse.csr_matrix. Tight-Binding Hamilonian. :param psi_init: np.ndarray. Initial state. :param steps: Positive Integer. Number of steps. :param dz: Positive number. Step. :param norm: Boolean. Default value True. Normalize the norm to 1 at each step. ''' error_handling.empty_ham(ham) error_handling.ndarray(psi_init, 'psi_init', self.lat.sites) error_handling.positive_int(steps, 'steps') error_handling.positive_real(dz, 'dz') error_handling.boolean(norm, 'norm') self.steps = steps self.dz = dz self.prop = np.empty((self.lat.sites, self.steps), 'c16') self.prop[:, 0] = psi_init diag = 1j*np.ones(self.lat.sites, 'c16') A = (sparse.diags(diag, 0) - 0.5 * self.dz * ham).toarray() B = (sparse.diags(diag, 0) + 0.5 * self.dz * ham).toarray() mat = (np.dot(LA.inv(A), B)) for i in range(1, self.steps): self.prop[:, i] = np.dot(mat, self.prop[:, i-1]) if norm: self.prop[:, i] /= np.abs(self.prop[:, i]).sum()
def intensity_area(self, intensity, s=1000., lw=1., fs=20., plt_hop=False, figsize=None, title=r'$|\psi|^2$'): ''' Plot the intensity. Intensity propotional to disk shape. :param intensity: np.array. Intensity. :param s: Positive Float. Default value 1000. Circle size given by s * intensity. :param lw: Positive Float. Default value 1. Hopping linewidths. :param fs: Positive Float. Default value 20. Fontsize. :param plt_hop: Boolean. Default value False. Plot hoppings. :param figsize: Tuple. Default value None. Figure size. :param title: String. Default value '$|\psi_{ij}|^2$'. Figure title. :returns: * **fig** -- Figure. ''' error_handling.empty_ndarray(self.sys.lat.coor, 'sys.get_lattice') error_handling.ndarray(intensity, 'intensity', self.sys.lat.sites) error_handling.positive_real(s, 's') error_handling.positive_real(fs, 'fs') error_handling.boolean(plt_hop, 'plt_hop') error_handling.tuple_2elem(figsize, 'figsize') error_handling.string(title, 'title') fig, ax = plt.subplots() ax.set_xlabel('$i$', fontsize=fs) ax.set_ylabel('$j$', fontsize=fs) ax.set_title(title, fontsize=fs) if plt_hop: plt.plot([self.sys.lat.coor['x'][self.sys.hop['i'][:]], self.sys.lat.coor['x'][self.sys.hop['j'][:]]], [self.sys.lat.coor['y'][self.sys.hop['i'][:]], self.sys.lat.coor['y'][self.sys.hop['j'][:]]], 'k', lw=lw) for tag, color in zip(self.sys.lat.tags, self.colors): plt.scatter(self.sys.lat.coor['x'][self.sys.lat.coor['tag'] == tag], self.sys.lat.coor['y'][self.sys.lat.coor['tag'] == tag], s=100*s*intensity[self.sys.lat.coor['tag'] == tag], c=color, alpha=0.5) ax.set_aspect('equal') ax.axis('off') x_lim = [np.min(self.sys.lat.coor['x'])-2., np.max(self.sys.lat.coor['x'])+2.] y_lim = [np.min(self.sys.lat.coor['y'])-2., np.max(self.sys.lat.coor['y'])+2.] ax.set_xlim(x_lim) ax.set_ylim(y_lim) fig.set_tight_layout(True) plt.draw() return fig
def get_pumping(self, hams, psi_init, steps, dz, norm=True): ''' Get the time evolution with adiabatic pumpings. :param hams: List of sparse.csr_matrices. Tight-Binding Hamilonians. :param psi_init: np.ndarray. Initial state. :param steps: Positive integer. Number of steps. :param dz: Positive number. Step. :param norm: Boolean. Default value True. Normalize the norm to 1 at each step. ''' error_handling.get_pump(hams) error_handling.ndarray(psi_init, 'psi_init', self.lat.sites) error_handling.positive_int(steps, 'steps') error_handling.positive_real(dz, 'dz') error_handling.boolean(norm, 'norm') self.steps = steps self.dz = dz no = len(hams) self.prop = np.empty((self.lat.sites, self.steps), 'c16') self.prop[:, 0] = psi_init diag = 1j * np.ones(self.lat.sites, 'c16') delta = self.steps // (1 + no) A = (sparse.diags(diag, 0) - 0.5 * self.dz * hams[0]).toarray() B = (sparse.diags(diag, 0) + 0.5 * self.dz * hams[0]).toarray() mat = (np.dot(LA.inv(A), B)) # before pumping for i in range(1, delta): self.prop[:, i] = np.dot(mat, self.prop[:, i-1]) if norm: self.prop[:, i] /= np.abs(self.prop[:, i]).sum() # pumping c = np.linspace(0, 1, delta) for j in range(0, no-1): for i in range(0, delta): ham = (1-c[i])*hams[j]+c[i]*hams[j+1] A = (sparse.diags(diag, 0) - 0.5 * self.dz * ham).toarray() B = (sparse.diags(diag, 0) + 0.5 * self.dz * ham).toarray() mat = (np.dot(LA.inv(A), B)) self.prop[:, (j+1)*delta+i] = np.dot(mat, self.prop[:, (j+1)*delta+i-1]) if norm: self.prop[:, (j+1)*delta+i] /= \ np.abs(self.prop[:, (j+1)*delta+i]).sum() # after pumping j = no for i in range(0, self.steps - no*delta): self.prop[:, no*delta+i] = np.dot(mat, self.prop[:, no*delta+i-1]) if norm: self.prop[:, no*delta+i] /= np.abs(self.prop[:, no*delta+i]).sum()
def plot(self, ms=20, fs=20, plt_index=False, axis=False, figsize=None): """ Plot lattice in hopping space. :param ms: Positive number. Default value 20. Markersize. :param fs: Positve number. Default value 20. Fontsize. :param plt_index: Boolean. Default value False. Plot site labels. :param axis: Boolean. Default value False. Plot axis. :param figsize: Tuple. Default value None. Figsize. :returns: * **fig** -- Figure. """ error_handling.empty_coor(self.coor) error_handling.positive_real(ms, "ms") error_handling.positive_real(fs, "fs") error_handling.boolean(plt_index, "plt_index") error_handling.boolean(axis, "axis") if figsize is None: figsize = (5, 5) error_handling.list_tuple_2elem(figsize, "figsize") error_handling.positive_real(figsize[0], "figsize[0]") error_handling.positive_real(figsize[1], "figsize[1]") fig, ax = plt.subplots(figsize=figsize) # plot sites colors = ["b", "r", "g", "y", "m", "k"] for color, tag in zip(colors, self.tags): plt.plot( self.coor["x"][self.coor["tag"] == tag], self.coor["y"][self.coor["tag"] == tag], "o", color=color, ms=ms, markeredgecolor="none", ) ax.set_aspect("equal") ax.set_xlim([np.min(self.coor["x"]) - 1.0, np.max(self.coor["x"]) + 1.0]) ax.set_ylim([np.min(self.coor["y"]) - 1.0, np.max(self.coor["y"]) + 1.0]) if not axis: ax.axis("off") # plot indices if plt_index: indices = ["{}".format(i) for i in range(self.sites)] for l, x, y in zip(indices, self.coor["x"], self.coor["y"]): plt.annotate(l, xy=(x, y), xytext=(0, 0), textcoords="offset points", ha="right", va="bottom", size=fs) plt.draw() return fig
def get_pumping(self, hams, psi_init, steps, dz, norm=True): """ Get the time evolution with adiabatic pumpings. :param hams: List of sparse.csr_matrices. Tight-Binding Hamilonians. :param psi_init: np.ndarray. Initial state. :param steps: Positive integer. Number of steps. :param dz: Positive number. Step. :param norm: Boolean. Default value True. Normalize the norm to 1 at each step. """ error_handling.get_pump(hams) error_handling.ndarray(psi_init, "psi_init", self.lat.sites) error_handling.positive_int(steps, "steps") error_handling.positive_real(dz, "dz") error_handling.boolean(norm, "norm") self.steps = steps self.dz = dz no = len(hams) self.prop = np.empty((self.lat.sites, self.steps), "c16") self.prop[:, 0] = psi_init diag = 1j * np.ones(self.lat.sites, "c16") delta = self.steps // (1 + no) A = (sparse.diags(diag, 0) - 0.5 * self.dz * hams[0]).toarray() B = (sparse.diags(diag, 0) + 0.5 * self.dz * hams[0]).toarray() mat = np.dot(LA.inv(A), B) # before pumping for i in range(1, delta): self.prop[:, i] = np.dot(mat, self.prop[:, i - 1]) if norm: self.prop[:, i] /= np.abs(self.prop[:, i]).sum() # pumping c = np.linspace(0, 1, delta) for j in range(0, no - 1): for i in range(0, delta): ham = (1 - c[i]) * hams[j] + c[i] * hams[j + 1] A = (sparse.diags(diag, 0) - 0.5 * self.dz * ham).toarray() B = (sparse.diags(diag, 0) + 0.5 * self.dz * ham).toarray() mat = np.dot(LA.inv(A), B) self.prop[:, (j + 1) * delta + i] = np.dot(mat, self.prop[:, (j + 1) * delta + i - 1]) if norm: self.prop[:, (j + 1) * delta + i] /= np.abs(self.prop[:, (j + 1) * delta + i]).sum() # after pumping j = no for i in range(0, self.steps - no * delta): self.prop[:, no * delta + i] = np.dot(mat, self.prop[:, no * delta + i - 1]) if norm: self.prop[:, no * delta + i] /= np.abs(self.prop[:, no * delta + i]).sum()
def plot(self, ms=20, fs=20, plt_index=False, axis=False, figsize=None): ''' Plot lattice in hopping space. :param ms: Positive number. Default value 20. Markersize. :param fs: Positve number. Default value 20. Fontsize. :param plt_index: Boolean. Default value False. Plot site labels. :param axis: Boolean. Default value False. Plot axis. :param figsize: Tuple. Default value None. Figsize. :returns: * **fig** -- Figure. ''' error_handling.empty_coor(self.coor) error_handling.positive_real(ms, 'ms') error_handling.positive_real(fs, 'fs') error_handling.boolean(plt_index, 'plt_index') error_handling.boolean(axis, 'axis') if figsize is None: figsize = (5, 5) error_handling.list_tuple_2elem(figsize, 'figsize') error_handling.positive_real(figsize[0], 'figsize[0]') error_handling.positive_real(figsize[1], 'figsize[1]') fig, ax = plt.subplots(figsize=figsize) # plot sites colors = ['b', 'r', 'g', 'y', 'm', 'k'] for color, tag in zip(colors, self.tags): plt.plot(self.coor['x'][self.coor['tag'] == tag], self.coor['y'][self.coor['tag'] == tag], 'o', color=color, ms=ms, markeredgecolor='none') ax.set_aspect('equal') ax.set_xlim([np.min(self.coor['x'])-1., np.max(self.coor['x'])+1.]) ax.set_ylim([np.min(self.coor['y'])-1., np.max(self.coor['y'])+1.]) if not axis: ax.axis('off') # plot indices if plt_index: indices = ['{}'.format(i) for i in range(self.sites)] for l, x, y in zip(indices, self.coor['x'], self.coor['y']): plt.annotate(l, xy=(x, y), xytext=(0, 0), textcoords='offset points', ha='right', va='bottom', size=fs) plt.draw() return fig
def get_eig(self, eigenvec=False, left=False): ''' Get the eigenergies, eigenvectors and polarisation. :param eigenvec: Boolean. Default value False. If True, get the eigenvectors. :param left: Boolean. Default value False. If True, get the left eigenvectors too. Relevant for non-Hermitian matrices. ''' error_handling.empty_ham(self.ham) error_handling.boolean(eigenvec, 'eigenvec') error_handling.boolean(left, 'left') if eigenvec: if (self.ham.H != self.ham).nnz: if not left: self.en, self.rn = LA.eig(self.ham.toarray()) else: self.en, self.rn, self.ln = LA.eig(self.ham.toarray(), left=left) ind = np.argsort(self.en.real) self.en = self.en[ind] self.rn = self.rn[:, ind] if self.ln.size: self.ln = self.ln[:, ind] else: self.en, self.rn = LA.eigh(self.ham.toarray()) self.intensity = np.abs(self.rn)**2 self.pola = np.zeros((self.lat.sites, len(self.lat.tags))) for i, tag in enumerate(self.lat.tags): self.pola[:, i] = np.sum( self.intensity[self.lat.coor['tag'] == tag, :], axis=0) else: if (self.ham.H != self.ham).nnz: self.en = LA.eigvals(self.ham.toarray()) ind = np.argsort(self.en.real) self.en = self.en[ind] else: self.en = LA.eigvalsh(self.ham.toarray())
def lattice_generic(self, coor, ms, lw, c, fs, axis, plt_hop, plt_hop_low, plt_index, figsize): ''' Private method called by *lattice* and *lattice_hop*. ''' error_handling.positive_real(ms, 'ms') error_handling.positive_real(lw, 'lw') error_handling.positive_real(c, 'c') error_handling.positive_real(fs, 'fs') error_handling.boolean(axis, 'axis') error_handling.boolean(plt_hop, 'plt_hop') error_handling.boolean(plt_hop_low, 'plt_hop_low') error_handling.boolean(plt_index, 'plt_index') error_handling.tuple_2elem(figsize, 'figsize') fig, ax = plt.subplots(figsize=figsize) # hoppings if plt_hop: error_handling.empty_ndarray(self.sys.hop, 'sys.hop') self.plt_hopping(coor, self.sys.hop[self.sys.hop['ang'] >= 0], c) if plt_hop_low: error_handling.empty_ndarray(self.sys.hop, 'sys.hop') self.plt_hopping(coor, self.sys.hop[self.sys.hop['ang'] < 0], c) # plot sites for color, tag in zip(self.colors, self.sys.lat.tags): plt.plot(coor['x'][coor['tag'] == tag], coor['y'][coor['tag'] == tag], 'o', color=color, ms=ms, markeredgecolor='none') ax.set_aspect('equal') ax.set_xlim([np.min(coor['x']) - 1., np.max(coor['x']) + 1.]) ax.set_ylim([np.min(coor['y']) - 1., np.max(coor['y']) + 1.]) if not axis: ax.axis('off') # plot indices if plt_index: indices = ['{}'.format(i) for i in range(self.sys.lat.sites)] for l, x, y in zip(indices, coor['x'], coor['y']): plt.annotate(l, xy=(x, y), xytext=(0, 0), textcoords='offset points', ha='right', va='bottom', size=fs) plt.draw() return fig
def get_eig(self, eigenvec=False, left=False): ''' Get the eigenergies, eigenvectors and polarisation. :param eigenvec: Boolean. Default value False. If True, get the eigenvectors. :param left: Boolean. Default value False. If True, get the left eigenvectors too. Relevant for non-Hermitian matrices. ''' error_handling.empty_ham(self.ham) error_handling.boolean(eigenvec, 'eigenvec') error_handling.boolean(left, 'left') if eigenvec: if (self.ham.H != self.ham).nnz: if not left: self.en, self.rn = LA.eig(self.ham.toarray()) else: self.en, self.rn, self.ln = LA.eig(self.ham.toarray(), left=left) ind = np.argsort(self.en.real) self.en = self.en[ind] self.rn = self.rn[:, ind] if self.ln.size: self.ln = self.ln[:, ind] else: self.en, self.rn = LA.eigh(self.ham.toarray()) self.intensity = np.abs(self.rn) ** 2 self.pola = np.zeros((self.lat.sites, len(self.lat.tags))) for i, tag in enumerate(self.lat.tags): self.pola[:, i] = np.sum(self.intensity[self.lat.coor['tag'] == tag, :], axis=0) else: if (self.ham.H != self.ham).nnz: self.en = LA.eigvals(self.ham.toarray()) ind = np.argsort(self.en.real) self.en = self.en[ind] else: self.en = LA.eigvalsh(self.ham.toarray())
def lattice_generic(self, coor, ms, lw, c, fs, axis, plt_hop, plt_hop_low, plt_index, figsize): ''' Private method called by *lattice* and *lattice_hop*. ''' error_handling.positive_real(ms, 'ms') error_handling.positive_real(lw, 'lw') error_handling.positive_real(c, 'c') error_handling.positive_real(fs, 'fs') error_handling.boolean(axis, 'axis') error_handling.boolean(plt_hop, 'plt_hop') error_handling.boolean(plt_hop_low, 'plt_hop_low') error_handling.boolean(plt_index, 'plt_index') error_handling.tuple_2elem(figsize, 'figsize') fig, ax = plt.subplots(figsize=figsize) # hoppings if plt_hop: error_handling.empty_ndarray(self.sys.hop, 'sys.hop') self.plt_hopping(coor, self.sys.hop[self.sys.hop['ang']>=0], c) if plt_hop_low: error_handling.empty_ndarray(self.sys.hop, 'sys.hop') self.plt_hopping(coor, self.sys.hop[self.sys.hop['ang']<0], c) # plot sites for color, tag in zip(self.colors, self.sys.lat.tags): plt.plot(coor['x'][coor['tag'] == tag], coor['y'][coor['tag'] == tag], 'o', color=color, ms=ms, markeredgecolor='none') ax.set_aspect('equal') ax.set_xlim([np.min(coor['x'])-1., np.max(coor['x'])+1.]) ax.set_ylim([np.min(coor['y'])-1., np.max(coor['y'])+1.]) if not axis: ax.axis('off') # plot indices if plt_index: indices = ['{}'.format(i) for i in range(self.sys.lat.sites)] for l, x, y in zip(indices, coor['x'], coor['y']): plt.annotate(l, xy=(x, y), xytext=(0, 0), textcoords='offset points', ha='right', va='bottom', size=fs) plt.draw() return fig
def set_hopping(self, list_hop, upper_part=True): ''' Set lattice hoppings. :param list_hop: List of Dictionaries. Dictionary with keys ('n', 'ang', 'tag', 't') where: * 'n' Positive integer, type of hoppings: * 'n': 1 for nearest neighbours. * 'n': 2 for next-nearest neighbours. * 'n': 3 for next-next-nearest neighbours. * etc... * 'ang' value, float, angle, in deg, of the hoppings. (optional). Hopping angles are given by the method *print_distances*. * If :math:`ang \in[0, 180)`, fill the Hamiltonian upper part. * If :math:`ang \in[-180, 0)`, fill the Hamiltonian lower part. * 'tag' binary string of length 2 (optional). Hopping tags. * 't' Complex number. Hopping value. :param upper_part: Boolean. Default value True. * True get hoppings with (:math:`i<j`) *i.e.* fill the Hamiltonian lower part. * False get hoppings with (:math:`i>j`) *i.e.* fill the Hamiltonian upper part. Example usage:: # fill upper part: sys.set_hopping([{'n': 1, t: 1.}]) # fill lower part: sys.set_hopping([{'n': 1, t: 1.}], upper_part=False) # fill upper part: specifying the angles: sys.set_hopping([{'n': 1, 'ang': 0., t: 1.}, {'n': 1, 'ang': 90, t: 2.}]) # fill lower part: sys.set_hopping([{'n': 1, 'ang': -180., t: 1.}, {'n': 1, 'ang': -90, t: 2.}], upper_part=False) # fill upper part: specifying the tags: sys.set_hopping([{'n': 1, 'tag': b'ab', t: 1.}, {'n': 1, 'tag': b'ba', t: 2.}]) # fill lower part: sys.set_hopping([{'n': 1, 'tag': b'ab', t: 1.}, {'n': 1, 'tag': b'ba', t: 2.}], upper_part=False) # fill upper part: specifying the angles and tags: sys.set_hopping([{'n': 1, 'ang': 0., 'tag': b'ab', t: 1.}, {'n': 1, 'ang': 0., 'tag': b'ba', t: 2.}, {'n': 1, 'ang': 90., 'tag': b'ab', t: 3.}, {'n': 1, 'ang': 90., 'tag': b'ba', t: 4.}]) # fill lower part: sys.set_hopping([{'n': 1, 'ang': 0., 'tag': b'ab', t: 1.}, {'n': 1, 'ang': 0., 'tag': b'ba', t: 2.}, {'n': 1, 'ang': 90., 'tag': b'ab', t: 3.}, {'n': 1, 'ang': 90., 'tag': b'ba', t: 4.}]), upper_part=False) .. note:: A Hermitian hopping matrix can be build-up only using its upper part OR only using its lower part. The full matrix is then automatic built by Hermitian conjugaison. If both upper AND lower parts are used to build up the hopping matrix. non Hermitian conjugaison is not performed *i.e.* non-Hermitian hopping matrix can be built. ''' error_handling.sites(self.lat.sites) error_handling.boolean(upper_part, 'upper_part') self.get_distances() self.nmax = len(self.dist_uni) - 1 error_handling.set_hopping(list_hop, self.nmax) list_n = np.unique([dic['n'] for dic in list_hop]) # fill, if needed self.store_hop self.check_sites() for n in list_n: if n not in self.store_hop: self.fill_store_hop(n) # fill self.hop for dic in list_hop: if len(dic) == 2: size = len(self.store_hop[dic['n']]) if upper_part: mask = (self.hop['n'] == dic['n']) & (self.hop['i'] < self.hop['j']) else: mask = (self.hop['n'] == dic['n']) & (self.hop['i'] > self.hop['j']) if np.sum(mask): self.hop = self.hop[np.logical_not(mask)] ind = np.ones(size, bool) hop = self.set_given_hopping(dic['n'], size, dic, ind, upper_part=upper_part) elif len(dic) == 3 and 'ang' in dic: error_handling.angle(dic['ang'], np.unique(self.store_hop[dic['n']]['ang']), upper_part) if dic['ang'] >= 0: ang_store = dic['ang'] else: ang_store = dic['ang'] + 180. size = np.sum(np.isclose(ang_store, self.store_hop[dic['n']]['ang'], atol=ATOL)) mask = (self.hop['n'] == dic['n']) & np.isclose(self.hop['ang'], dic['ang'], atol=ATOL) if np.sum(mask): self.hop = self.hop[np.logical_not(mask)] ind = np.isclose(ang_store, self.store_hop[dic['n']]['ang'], atol=ATOL) error_handling.index(ind, dic) hop = self.set_given_hopping(dic['n'], size, dic, ind, upper_part=upper_part) elif len(dic) == 3 and 'tag' in dic: if upper_part: tag_store = dic['tag'] else: tag_store = dic['tag'][::-1] size = np.sum(self.store_hop[dic['n']]['tag'] == tag_store) mask = (self.hop['n'] == dic['n']) & (self.hop['tag'] == dic['tag']) if upper_part: mask = self.hop['n'] == dic['n'] & (self.hop['tag'] == dic['tag']) & (self.hop['i'] < self.hop['j']) else: mask = self.hop['n'] == dic['n'] & (self.hop['tag'] == dic['tag']) & (self.hop['i'] > self.hop['j']) if np.sum(mask): self.hop = self.hop[np.logical_not(mask)] ind = self.store_hop[dic['n']]['tag'] == tag_store error_handling.index(ind, dic) hop = self.set_given_hopping(dic['n'], size, dic, ind, upper_part=upper_part) else: error_handling.angle(dic['ang'], np.unique(self.store_hop[dic['n']]['ang']), upper_part=upper_part) error_handling.tag(dic['tag'], np.unique(self.store_hop[dic['n']]['tag'])) if dic['ang'] >= 0: ang_store = dic['ang'] else: ang_store = dic['ang'] + 180. if upper_part: tag_store = dic['tag'] else: tag_store = dic['tag'][::-1] size = np.sum((self.store_hop[dic['n']]['tag'] == tag_store) & (np.isclose(ang_store, self.store_hop[dic['n']]['ang'], atol=ATOL))) bool1 = (self.hop['n'] == dic['n']) & (self.hop['tag'] == dic['tag']) bool2 = np.isclose(self.hop['ang'], dic['ang'], atol=ATOL) mask = bool1 & bool2 if np.sum(mask): self.hop = self.hop[np.logical_not(mask)] ind = ((self.store_hop[dic['n']]['tag'] == tag_store) & (np.isclose(ang_store, self.store_hop[dic['n']]['ang'], atol=1))) error_handling.index(ind, dic) hop = self.set_given_hopping(dic['n'], size, dic, ind, upper_part=upper_part) self.hop = np.concatenate([self.hop, hop])
def set_hopping(self, list_hop, upper_part=True): ''' Set lattice hoppings. :param list_hop: List of Dictionaries. Dictionary with keys ('n', 'ang', 'tag', 't') where: * 'n' Positive integer, type of hoppings: * 'n': 1 for nearest neighbours. * 'n': 2 for next-nearest neighbours. * 'n': 3 for next-next-nearest neighbours. * etc... * 'ang' value, float, angle, in deg, of the hoppings. (optional). Hopping angles are given by the method *print_distances*. * If :math:`ang \in[0, 180)`, fill the Hamiltonian upper part. * If :math:`ang \in[-180, 0)`, fill the Hamiltonian lower part. * 'tag' binary string of length 2 (optional). Hopping tags. * 't' Complex number. Hopping value. :param upper_part: Boolean. Default value True. * True get hoppings with (:math:`i<j`) *i.e.* fill the Hamiltonian lower part. * False get hoppings with (:math:`i>j`) *i.e.* fill the Hamiltonian upper part. Example usage:: # fill upper part: sys.set_hopping([{'n': 1, t: 1.}]) # fill lower part: sys.set_hopping([{'n': 1, t: 1.}], upper_part=False) # fill upper part: specifying the angles: sys.set_hopping([{'n': 1, 'ang': 0., t: 1.}, {'n': 1, 'ang': 90, t: 2.}]) # fill lower part: sys.set_hopping([{'n': 1, 'ang': -180., t: 1.}, {'n': 1, 'ang': -90, t: 2.}], upper_part=False) # fill upper part: specifying the tags: sys.set_hopping([{'n': 1, 'tag': b'ab', t: 1.}, {'n': 1, 'tag': b'ba', t: 2.}]) # fill lower part: sys.set_hopping([{'n': 1, 'tag': b'ab', t: 1.}, {'n': 1, 'tag': b'ba', t: 2.}], upper_part=False) # fill upper part: specifying the angles and tags: sys.set_hopping([{'n': 1, 'ang': 0., 'tag': b'ab', t: 1.}, {'n': 1, 'ang': 0., 'tag': b'ba', t: 2.}, {'n': 1, 'ang': 90., 'tag': b'ab', t: 3.}, {'n': 1, 'ang': 90., 'tag': b'ba', t: 4.}]) # fill lower part: sys.set_hopping([{'n': 1, 'ang': 0., 'tag': b'ab', t: 1.}, {'n': 1, 'ang': 0., 'tag': b'ba', t: 2.}, {'n': 1, 'ang': 90., 'tag': b'ab', t: 3.}, {'n': 1, 'ang': 90., 'tag': b'ba', t: 4.}]), upper_part=False) .. note:: A Hermitian hopping matrix can be build-up only using its upper part OR only using its lower part. The full matrix is then automatic built by Hermitian conjugaison. If both upper AND lower parts are used to build up the hopping matrix. non Hermitian conjugaison is not performed *i.e.* non-Hermitian hopping matrix can be built. ''' error_handling.sites(self.lat.sites) error_handling.boolean(upper_part, 'upper_part') self.get_distances() self.nmax = len(self.dist_uni) - 1 error_handling.set_hopping(list_hop, self.nmax) list_n = np.unique([dic['n'] for dic in list_hop]) # fill, if needed self.store_hop self.check_sites() for n in list_n: if n not in self.store_hop: self.fill_store_hop(n) # fill self.hop for dic in list_hop: if len(dic) == 2: size = len(self.store_hop[dic['n']]) if upper_part: mask = (self.hop['n'] == dic['n']) & (self.hop['i'] < self.hop['j']) else: mask = (self.hop['n'] == dic['n']) & (self.hop['i'] > self.hop['j']) if np.sum(mask): self.hop = self.hop[np.logical_not(mask)] ind = np.ones(size, bool) hop = self.set_given_hopping(dic['n'], size, dic, ind, upper_part=upper_part) elif len(dic) == 3 and 'ang' in dic: error_handling.angle( dic['ang'], np.unique(self.store_hop[dic['n']]['ang']), upper_part) if dic['ang'] >= 0: ang_store = dic['ang'] else: ang_store = dic['ang'] + 180. size = np.sum( np.isclose(ang_store, self.store_hop[dic['n']]['ang'], atol=ATOL)) mask = (self.hop['n'] == dic['n']) & np.isclose( self.hop['ang'], dic['ang'], atol=ATOL) if np.sum(mask): self.hop = self.hop[np.logical_not(mask)] ind = np.isclose(ang_store, self.store_hop[dic['n']]['ang'], atol=ATOL) error_handling.index(ind, dic) hop = self.set_given_hopping(dic['n'], size, dic, ind, upper_part=upper_part) elif len(dic) == 3 and 'tag' in dic: if upper_part: tag_store = dic['tag'] else: tag_store = dic['tag'][::-1] size = np.sum(self.store_hop[dic['n']]['tag'] == tag_store) mask = (self.hop['n'] == dic['n']) & (self.hop['tag'] == dic['tag']) if upper_part: mask = self.hop['n'] == dic['n'] & ( self.hop['tag'] == dic['tag']) & (self.hop['i'] < self.hop['j']) else: mask = self.hop['n'] == dic['n'] & ( self.hop['tag'] == dic['tag']) & (self.hop['i'] > self.hop['j']) if np.sum(mask): self.hop = self.hop[np.logical_not(mask)] ind = self.store_hop[dic['n']]['tag'] == tag_store error_handling.index(ind, dic) hop = self.set_given_hopping(dic['n'], size, dic, ind, upper_part=upper_part) else: error_handling.angle(dic['ang'], np.unique( self.store_hop[dic['n']]['ang']), upper_part=upper_part) error_handling.tag(dic['tag'], np.unique(self.store_hop[dic['n']]['tag'])) if dic['ang'] >= 0: ang_store = dic['ang'] else: ang_store = dic['ang'] + 180. if upper_part: tag_store = dic['tag'] else: tag_store = dic['tag'][::-1] size = np.sum((self.store_hop[dic['n']]['tag'] == tag_store) & (np.isclose(ang_store, self.store_hop[dic['n']]['ang'], atol=ATOL))) bool1 = (self.hop['n'] == dic['n']) & (self.hop['tag'] == dic['tag']) bool2 = np.isclose(self.hop['ang'], dic['ang'], atol=ATOL) mask = bool1 & bool2 if np.sum(mask): self.hop = self.hop[np.logical_not(mask)] ind = ( (self.store_hop[dic['n']]['tag'] == tag_store) & (np.isclose( ang_store, self.store_hop[dic['n']]['ang'], atol=1))) error_handling.index(ind, dic) hop = self.set_given_hopping(dic['n'], size, dic, ind, upper_part=upper_part) self.hop = np.concatenate([self.hop, hop])
def intensity_area(self, intensity, s=1000., lw=1., fs=20., plt_hop=False, figsize=None, title=r'$|\psi|^2$'): ''' Plot the intensity. Intensity propotional to disk shape. :param intensity: np.array. Intensity. :param s: Positive Float. Default value 1000. Circle size given by s * intensity. :param lw: Positive Float. Default value 1. Hopping linewidths. :param fs: Positive Float. Default value 20. Fontsize. :param plt_hop: Boolean. Default value False. Plot hoppings. :param figsize: Tuple. Default value None. Figure size. :param title: String. Default value '$|\psi_{ij}|^2$'. Figure title. :returns: * **fig** -- Figure. ''' error_handling.empty_ndarray(self.sys.lat.coor, 'sys.get_lattice') error_handling.ndarray(intensity, 'intensity', self.sys.lat.sites) error_handling.positive_real(s, 's') error_handling.positive_real(fs, 'fs') error_handling.boolean(plt_hop, 'plt_hop') error_handling.tuple_2elem(figsize, 'figsize') error_handling.string(title, 'title') fig, ax = plt.subplots() ax.set_xlabel('$i$', fontsize=fs) ax.set_ylabel('$j$', fontsize=fs) ax.set_title(title, fontsize=fs) if plt_hop: plt.plot([ self.sys.lat.coor['x'][self.sys.hop['i'][:]], self.sys.lat.coor['x'][self.sys.hop['j'][:]] ], [ self.sys.lat.coor['y'][self.sys.hop['i'][:]], self.sys.lat.coor['y'][self.sys.hop['j'][:]] ], 'k', lw=lw) for tag, color in zip(self.sys.lat.tags, self.colors): plt.scatter( self.sys.lat.coor['x'][self.sys.lat.coor['tag'] == tag], self.sys.lat.coor['y'][self.sys.lat.coor['tag'] == tag], s=100 * s * intensity[self.sys.lat.coor['tag'] == tag], c=color, alpha=0.5) ax.set_aspect('equal') ax.axis('off') x_lim = [ np.min(self.sys.lat.coor['x']) - 2., np.max(self.sys.lat.coor['x']) + 2. ] y_lim = [ np.min(self.sys.lat.coor['y']) - 2., np.max(self.sys.lat.coor['y']) + 2. ] ax.set_xlim(x_lim) ax.set_ylim(y_lim) fig.set_tight_layout(True) plt.draw() return fig