Source code for pwtools.kpath

import numpy as np
from pwtools import num, pwscf, common, mpl

[docs] def kpath(vecs, N=10): """Simple k-path. Given a set of K vectors (special points in the BZ), generate a "fine path" of N*(K-1)+1 vectors along the path defined by the vectors in `vecs`. The K vectors are the "vertices" of the k-path and we construct the fine path by connecting the vertices by their distance vectors and placing N points on each connection edge. Parameters ---------- vecs : array (K,M) Array with K vectors of the Brillouin zone (so M = 3 usually :) N : int Returns ------- new_vecs : array (N*(K-1)+1,M) Array with a fine grid of vectors along the path defined by `vecs`. Notes ----- This is the simplest method one can think of. Points on the "fine path" are not equally distributed. The distance between 2 vertices (k-points) doesn't matter, you will always get N points between them. For a smooth dispersion plot, you need N=20 or more. """ K = vecs.shape[0] new_vecs = np.empty(((K-1)*N+1, vecs.shape[1]), dtype=float) for i in range(1, K): new_vecs[(i-1)*N:i*N, :] = num.vlinspace(vecs[i-1,:], vecs[i,:], N, endpoint=False) new_vecs[-1,:] = vecs[-1,:] return new_vecs
[docs] def get_path_norm(ks): """Like in QE's ``plotband.f90``, path_norm = kx there. Return a sequence of cumulative norms of the difference vectors which connect each two adjacent k-points. Parameters ---------- ks : array (nks, 3) array with `nks` k-points on the path """ dnorms = np.empty(ks.shape[0], dtype=float) dnorms[0] = np.linalg.norm(ks[0,:]) # diff(...): array with difference vecs, norm of each of them dnorms[1:] = np.sqrt((np.diff(ks, axis=0)**2.0).sum(axis=1)) # cumulative sum path_norm = dnorms.cumsum(axis=0) return path_norm
[docs] class SpecialPointsPath: r"""Sequence of special points. Calculate their path norm and store symbols such as "K" or "$\\Gamma$"."""
[docs] def __init__(self, ks=None, ks_frac=None, symbols=None): """ Parameters ---------- ks : (nks,3) cartesian k-points ks_frac : (nks,3), optional fractional k-points, used only in :func:`plot_dis`, not for path norm calculation symbols : sequence of strings (nks,), optional special point symbol each point in `ks` """ assert (ks is not None) and (ks_frac is not None), ("use either ks or ks_frac") self.ks = ks self.ks_frac = ks_frac self.symbols = symbols # 1d array (nks,) of cumulative norms self.path_norm = get_path_norm(self.ks)
[docs] def plot_dis(path_norm, freqs, special_points_path=None, show_coords=None, dos=None, ax=None, ylim=None, **kwargs): """Plot dispersion. See ``bin/plot_dispersion.py`` for a usage example. This lives here (and not in :mod:`~pwtools.pwscf`) b/c it is not PWscf-specific. It can be used for any dispersion data (band structure). See :func:`~pwtools.pwscf.read_matdyn_freq` for how to get `freqs` in the case of phonon dispersions. This function is a convenience function, which can even plot the DOS as well. We do not expose many matplotlib parameters here. If you want to tweak your plot much, then operate on the returned `fig`, `ax` (dispersion) and `axdos` (dos), or copy and hack the function, which might be actually the easiest way. Parameters ---------- path_norm : array (nks,) x-axis with cumulative norms of points along the k-path, see :func:`get_path_norm` freqs : array (nks, nbnd) `nbnd` frequencies for each band at each k-point special_points_path : optional, :class:`SpecialPointsPath` instance used for pretty-printing the x-axis (set special point labels) show_coords : 'cart', 'frac', None Show the cartesian or fractional coordinates of special points in the x-axis label, on neither if None. dos : array (N,2) or None array with phonon dos to plot: ``dos[:,0]=freq``, ``dos[:,1]=phdos`` ax : matplotlib AxesSubplot (e.g. from ``fig,ax=pwtools.mpl.fig_ax()``) automatically created if None ylim : tuple (2,) frequency axis limits **kwargs : keywords passed to plot() Returns ------- fig, ax, axdos fig : matplotlib Figure to ax ax : matplotlib AxesSubplot with dispersion axdos : matplotlib AxesSubplot with dos, or None if `dos=None` Examples -------- >>> spp = kpath.SpecialPointsPath(ks=np.array([[0,0,0], [1.5,0,0], [2.3,0,0]]), symbols=['A', 'B', 'C']) >>> path_norm = np.linspace(0,2.5,100) >>> freqs = np.random.rand(100,5)*500 >>> # create fig,ax inside, returned axdos=None >>> fig,ax,axdos = kpath.plot_dis(path_norm, freqs, spp) >>> # pass ax from outside, returns fig,ax but we don't use that b/c ax >>> # is in-place modified >>> fig,ax = mpl.fig_ax() >>> kpath.plot_dis(path_norm, freqs, spp, ax=ax) >>> # plot also DOS >>> dos = np.empty((30,2)); dos[:,0]=np.linspace(0,500,30); dos[:,1]=rand(30) >>> fig,ax,axdos = kpath.plot_dis(path_norm, freqs, spp, dos=dos) See Also -------- :func:`get_path_norm` :func:`pwtools.pwscf.read_matdyn_freq` :ref:`dispersion_example` """ if ax is None: fig,ax = mpl.fig_ax() else: fig = ax.get_figure() # Plot columns of `freq` against q points (path_norm) ax.plot(path_norm, freqs, **kwargs) if special_points_path is not None: ylim = ax.get_ylim() if ylim is None else ylim ks, ks_frac, nrm, symbols = \ special_points_path.ks, \ special_points_path.ks_frac, \ special_points_path.path_norm, \ special_points_path.symbols ax.vlines(nrm, ylim[0], ylim[1]) fmtfunc = lambda x: "%.2g" %x if show_coords is None: labels = symbols else: if show_coords == 'cart': ks_plot = ks elif show_coords == 'frac': ks_plot = ks_frac else: raise Exception("show_coords = 'cart', 'frac' or " "None needed") labels = ['%s\n[%s]' %(sym, common.seq2str(kk, func=fmtfunc,sep=','))\ for sym,kk in zip(symbols, ks_plot)] ax.set_xticks(nrm) ax.set_xticklabels(labels) ax.set_xlim(path_norm[0], path_norm[-1]) ax.set_ylabel("frequency (cm$^{-1}$)") if dos is not None: # http://matplotlib.org/examples/axes_grid/scatter_hist.html from mpl_toolkits.axes_grid1 import make_axes_locatable divider = make_axes_locatable(ax) axdos = divider.append_axes("right", 1.2, pad=0.1, sharey=ax) axdos.plot(dos[:,1], dos[:,0], 'b') mpl.plt.setp(axdos.get_yticklabels(), visible=False) mpl.plt.setp(axdos.get_xticklabels(), visible=False) axdos.xaxis.set_tick_params(size=0) else: axdos = None return fig, ax, axdos