def plot_eelf(self, ax=None, xlims=None, fontsize=12, **kwargs): r""" Plot electron energy loss function. Args: ax: |matplotlib-Axes| or None if a new figure should be created. xlims: Set the data limits for the x-axis in eV. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used fontsize: Legend and label fontsize: Returns: |matplotlib-Figure| """ eelf = self.reader.read_eelf() xx, yy = eelf.mesh * pmgu.Ha_to_eV, eelf.values ax, fig, plt = get_ax_fig_plt(ax=ax) ax.plot(xx, yy, linewidth=kwargs.get("linewidth", 2), linestyle=kwargs.get("linestyle", "solid"), label="EELF") set_axlims(ax, xlims, "x") ax.grid(True) ax.set_xlabel(r"$\omega$ [eV]") ax.legend(loc="best", fontsize=fontsize, shadow=True) return fig
def plot_eelf(self, ax=None, xlims=None, fontsize=12, **kwargs): r""" Plot electron energy loss function. Args: ax: |matplotlib-Axes| or None if a new figure should be created. xlims: Set the data limits for the x-axis in eV. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used fontsize: Legend and label fontsize: Returns: |matplotlib-Figure| """ eelf = self.reader.read_eelf() xx, yy = eelf.mesh * pmgu.Ha_to_eV, eelf.values ax, fig, plt = get_ax_fig_plt(ax=ax) ax.plot(xx, yy, linewidth=kwargs.get("linewidth", 2), linestyle=kwargs.get("linestyle", "solid"), label="EELF") set_axlims(ax, xlims, "x") ax.grid(True) ax.set_xlabel(r"$\omega$ (eV)") ax.legend(loc="best", fontsize=fontsize, shadow=True) return fig
def plot_emacro(self, cplx_mode="re-im", ax=None, xlims=None, fontsize=12, **kwargs): r""" Plot the macroscopic dielectric function with local-field effects. Args: cplx_mode: string defining the data to print. Possible choices are (case-insensitive): "re" for the real part. "im" for the imaginary part. "abs" for the absolute value. "angle" will display the phase of the complex number in radians. Options can be concatenated with ``-`` e.g. ``re-im``. xlims: Set the data limits for the x-axis in eV. Accept tuple e.g. (left, right) or scalar e.g. left. If left (right) is None, default values are used. ax: |matplotlib-Axes| or None if a new figure should be created. fontsize: Legend and title fontsize. Returns: |matplotlib-Figure| """ emlf = self.reader.read_emacro_lf() xx, yy = emlf.mesh * pmgu.Ha_to_eV, emlf.values ax, fig, plt = get_ax_fig_plt(ax=ax) for c in cplx_mode.lower().split("-"): ax.plot(xx, data_from_cplx_mode(c, yy), color=_COLOR_CMODE[c], linewidth=kwargs.get("linewidth", 2), linestyle=kwargs.get("linestyle", "solid"), label=_latex_symbol_cplxmode(r"\varepsilon_{M}", c)) set_axlims(ax, xlims, "x") ax.grid(True) ax.set_xlabel(r"$\omega$ (eV)") ax.legend(loc="best", shadow=True, fontsize=fontsize) return fig
def plot_linear_epsilon(self, components="all", what="im", itemp=0, ax=None, xlims=None, with_xlabel=True, label=None, fontsize=12, **kwargs): """ Plot components of the linear dielectric function. Args: components: List of cartesian tensor components to plot e.g. ["xx", "xy"]. "all" if all components available on file should be plotted on the same ax. what: quantity to plot. "re" for real part, "im" for imaginary. Accepts also "abs", "angle". itemp: Temperature index. ax: |matplotlib-Axes| or None if a new figure should be created. xlims: Set the data limits for the x-axis. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used. with_xlabel: True if x-label should be added. label: True to add legend label to each curve. fontsize: Legend and label fontsize. Returns: |matplotlib-Figure| """ comp2eps = self.reader.read_lineps(components, itemp=itemp) ax, fig, plt = get_ax_fig_plt(ax=ax) for comp, eps in comp2eps.items(): values = LINEPS_WHAT2EFUNC[what](eps) # Note: I'm skipping the first point at w=0 because optic does not compute it! # The same trick is used in the other plots. ax.plot(self.wmesh[1:], values[1:], label=self.get_linopt_latex_label(what, comp) if label is None else label) ax.grid(True) if with_xlabel: ax.set_xlabel('Photon Energy (eV)') set_axlims(ax, xlims, "x") ax.legend(loc="best", fontsize=fontsize, shadow=True) return fig
def plot_unfolded(self, kbounds, klabels, ylims=None, dist_tol=1e-12, verbose=0, colormap="afmhot", facecolor="black", ax=None, fontsize=12, **kwargs): r""" Plot unfolded band structure with spectral weights. Args: klabels: dictionary whose keys are tuple with the reduced coordinates of the k-points. The values are the labels. e.g. ``klabels = {(0.0,0.0,0.0): "$\Gamma$", (0.5,0,0): "L"}``. ylims: Set the data limits for the y-axis. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used dist_tol: A point is considered to be on the path if its distance from the line is less than dist_tol. verbose: Verbosity level. colormap: Have a look at the colormaps here and decide which one you like: http://matplotlib.sourceforge.net/examples/pylab_examples/show_colormaps.html facecolor: ax: |matplotlib-Axes| or None if a new figure should be created. fontsize: Legend and title fontsize. Returns: |matplotlib-Figure| """ cart_bounds = [self.pc_lattice.reciprocal_lattice.get_cartesian_coords(c) for c in np.reshape(kbounds, (-1, 3))] uf_cart = self.uf_kpoints.get_cart_coords() p = find_points_along_path(cart_bounds, uf_cart, dist_tol) if len(p.ikfound) == 0: cprint("Warning: find_points_along_path returned zero points along the path. Try to increase dist_tol.", "yellow") return None if verbose: uf_frac_coords = np.reshape([k.frac_coords for k in self.uf_kpoints], (-1, 3)) fcoords = uf_frac_coords[p.ikfound] print("Found %d points along input k-path" % len(fcoords)) print("k-points of path in reduced coordinates:") print(fcoords) fact = 8.0 e0 = self.ebands.fermie ax, fig, plt = get_ax_fig_plt(ax=ax) ax.set_facecolor(facecolor) xs = np.tile(p.dist_list, self.nband) marker_spin = {0: "^", 1: "v"} if self.nss == 2 else {0: "o"} for spin in range(self.nss): ys = self.uf_eigens[spin, p.ikfound, :] - e0 ws = self.uf_weights[spin, p.ikfound, :] s = ax.scatter(xs, ys.T, s=fact * ws.T, c=ws.T, marker=marker_spin[spin], label=None if self.nss == 1 else "spin %s" % spin, linewidth=1, edgecolors='none', cmap=plt.get_cmap(colormap)) plt.colorbar(s, ax=ax, orientation='vertical') ax.set_xticks(p.path_ticks, minor=False) ax.set_xticklabels(klabels, fontdict=None, minor=False, size=kwargs.pop("klabel_size", "large")) ax.grid(True) ax.set_ylabel('Energy (eV)') set_axlims(ax, ylims, "y") if self.nss == 2: ax.legend(loc="best", fontsize=fontsize, shadow=True) return fig
def plot_unfolded(self, kbounds, klabels, ylims=None, dist_tol=1e-12, verbose=0, colormap="afmhot", facecolor="black", ax=None, fontsize=12, **kwargs): r""" Plot unfolded band structure with spectral weights. Args: klabels: dictionary whose keys are tuple with the reduced coordinates of the k-points. The values are the labels. e.g. ``klabels = {(0.0,0.0,0.0): "$\Gamma$", (0.5,0,0): "L"}``. ylims: Set the data limits for the y-axis. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used dist_tol: A point is considered to be on the path if its distance from the line is less than dist_tol. verbose: Verbosity level. colormap: Have a look at the colormaps here and decide which one you like: http://matplotlib.sourceforge.net/examples/pylab_examples/show_colormaps.html facecolor: ax: |matplotlib-Axes| or None if a new figure should be created. fontsize: Legend and title fontsize. Returns: |matplotlib-Figure| """ cart_bounds = [self.pc_lattice.reciprocal_lattice.get_cartesian_coords(c) for c in np.reshape(kbounds, (-1, 3))] uf_cart = self.uf_kpoints.get_cart_coords() klines, xs, ticks = find_points_along_path(cart_bounds, uf_cart, dist_tol) if len(klines) == 0: return None if verbose: uf_frac_coords = np.reshape([k.frac_coords for k in self.uf_kpoints], (-1, 3)) fcoords = uf_frac_coords[klines] print("Found %d points along input k-path" % len(fcoords)) print("k-points of path in reduced coordinates:") print(fcoords) fact = 8.0 e0 = self.ebands.fermie ax, fig, plt = get_ax_fig_plt(ax=ax) ax.set_facecolor(facecolor) xs = np.tile(xs, self.nband) marker_spin = {0: "^", 1: "v"} if self.nss == 2 else {0: "o"} for spin in range(self.nss): ys = self.uf_eigens[spin, klines, :] - e0 ws = self.uf_weights[spin, klines, :] s = ax.scatter(xs, ys.T, s=fact * ws.T, c=ws.T, marker=marker_spin[spin], label=None if self.nss == 1 else "spin %s" % spin, linewidth=1, edgecolors='none', cmap=plt.get_cmap(colormap)) plt.colorbar(s, ax=ax, orientation='vertical') ax.set_xticks(ticks, minor=False) ax.set_xticklabels(klabels, fontdict=None, minor=False, size=kwargs.pop("klabel_size", "large")) ax.grid(True) ax.set_ylabel('Energy [eV]') set_axlims(ax, ylims, "y") if self.nss == 2: ax.legend(loc="best", fontsize=fontsize, shadow=True) return fig
def plot_chi2(self, key, components="all", what="abs", itemp=0, decompose=False, ax=None, xlims=None, with_xlabel=True, label=None, fontsize=12, **kwargs): """ Low-level function to plot chi2 tensor. Args: key: components: List of cartesian tensor components to plot e.g. ["xxx", "xyz"]. "all" if all components available on file should be plotted on the same ax. what: quantity to plot. "re" for real part, "im" for imaginary, Accepts also "abs", "angle". itemp: Temperature index. decompose: True to plot individual contributions. ax: |matplotlib-Axes| or None if a new figure should be created. xlims: Set the data limits for the x-axis. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used. with_xlabel: True to add x-label. label: True to add legend label to each curve. fontsize: Legend and label fontsize. Returns: |matplotlib-Figure| """ if not self.reader.computed_components[key]: return None comp2terms = self.reader.read_tensor3_terms(key, components, itemp=itemp) ax, fig, plt = get_ax_fig_plt(ax=ax) for comp, terms in comp2terms.items(): for name, values in terms.items(): if not decompose and not name.endswith("tot"): continue values = data_from_cplx_mode(what, values) ax.plot( self.wmesh[1:], values[1:], label=self.get_chi2_latex_label(key, what, comp) if label is None else label, ) ax.grid(True) if with_xlabel: ax.set_xlabel('Photon Energy [eV]') set_axlims(ax, xlims, "x") ax.legend(loc="best", fontsize=fontsize, shadow=True) return fig
def plot_mdftype_cplx(self, mdf_type, cplx_mode, qpoint=None, ax=None, xlims=None, ylims=None, with_legend=True, with_xlabel=True, with_ylabel=True, fontsize=8, **kwargs): """ Helper function to plot data corresponds to ``mdf_type``, ``cplx_mode``, ``qpoint``. Args: ax: |matplotlib-Axes| or None if a new figure should be created. mdf_type: cplx_mode: string defining the data to print (case-insensitive). Possible choices are `re` for the real part, `im` for imaginary part only. `abs` for the absolute value. qpoint: index of the q-point or :class:`Kpoint` object or None to plot emacro_avg. xlims: Set the data limits for the y-axis. Accept tuple e.g. `(left, right)` or scalar e.g. `left`. If left (right) is None, default values are used ylims: Same meaning as `ylims` but for the y-axis with_legend: True if legend should be added with_xlabel: with_ylabel: fontsize: Legend and label fontsize. Return: |matplotlib-Figure| """ ax, fig, plt = get_ax_fig_plt(ax=ax) ax.grid(True) if with_xlabel: ax.set_xlabel("Frequency (eV)") if with_ylabel: ax.set_ylabel(self.MDF_TYPECPLX2TEX[mdf_type][cplx_mode.lower()]) can_use_basename = self._can_use_basenames_as_labels() qtag = "avg" if qpoint is None else repr(qpoint) lines, legends = [], [] for label, mdf_dict in self._mdfs.items(): mdf = mdf_dict[mdf_type] # Plot the average value l = mdf.plot_ax(ax, qpoint, cplx_mode=cplx_mode, **kwargs)[0] lines.append(l) if can_use_basename: label = os.path.basename(label) else: # Use relative paths if label is a file. if os.path.isfile(label): label = os.path.relpath(label) legends.append(r"%s: %s, %s $\varepsilon$" % (cplx_mode, qtag, label)) set_axlims(ax, xlims, "x") set_axlims(ax, ylims, "y") # Set legends. if with_legend: ax.legend(lines, legends, loc='best', fontsize=fontsize, shadow=True) return fig
def plot_doses(self, xlims=None, dos_names="all", with_idos=True, **kwargs): r""" Plot the different doses stored in the GRUNS.nc file. Args: xlims: Set the data limits for the x-axis in eV. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used dos_names: List of strings defining the DOSes to plot. Use "all" to plot all DOSes available. with_idos: True to display integrated doses. Return: |matplotlib-Figure| """ if not self.doses: return None dos_names = _ALL_DOS_NAMES.keys( ) if dos_names == "all" else list_strings(dos_names) wmesh = self.doses["wmesh"] nrows, ncols = len(dos_names), 1 ax_list, fig, plt = get_axarray_fig_plt(None, nrows=nrows, ncols=ncols, sharex=True, sharey=False, squeeze=False) ax_list = ax_list.ravel() for i, (name, ax) in enumerate(zip(dos_names, ax_list)): dos, idos = self.doses[name][0], self.doses[name][1] ax.plot(wmesh, dos, color="k") ax.grid(True) set_axlims(ax, xlims, "x") ax.set_ylabel(_ALL_DOS_NAMES[name]["latex"]) #ax.yaxis.set_ticks_position("right") if with_idos: other_ax = ax.twinx() other_ax.plot(wmesh, idos, color="k") other_ax.set_ylabel(_ALL_DOS_NAMES[name]["latex"].replace( "DOS", "IDOS")) if i == len(dos_names) - 1: ax.set_xlabel(r"$\omega$ (eV)") #ax.legend(loc="best", fontsize=fontsize, shadow=True) return fig
def plot(self, ax=None, cplx_mode="Im", qpoint=None, xlims=None, ylims=None, fontsize=12, **kwargs): """ Get a matplotlib plot showing the MDFs. Args: ax: |matplotlib-Axes| or None if a new figure should be created. cplx_mode: string defining the data to print (case-insensitive). Possible choices are ``re`` for the real part, ``im`` for imaginary part only. ``abs`` for the absolute value. Options can be concated with "-". qpoint: index of the q-point or :class:`Kpoint` object or None to plot emacro_avg. xlims: Set the data limits for the y-axis. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used ylims: Same meaning as ``ylims`` but for the y-axis fontsize: Legend and label fontsize. Return: |matplotlib-Figure| """ ax, fig, plt = get_ax_fig_plt(ax=ax) ax.grid(True) ax.set_xlabel('Frequency (eV)') ax.set_ylabel('Macroscopic DF') cmodes = cplx_mode.split("-") qtag = "avg" if qpoint is None else repr(qpoint) lines, legends = [], [] for label, mdf in self._mdfs.items(): for cmode in cmodes: # Plot the average value l = mdf.plot_ax(ax, qpoint, cplx_mode=cmode, **kwargs)[0] lines.append(l) legends.append(r"%s: %s, %s $\varepsilon$" % (cmode, qtag, label)) # Set legends. ax.legend(lines, legends, loc='best', fontsize=fontsize, shadow=True) set_axlims(ax, xlims, "x") set_axlims(ax, ylims, "y") return fig
def plot(self, eb_ylims=None, **kwargs): """ Plot electrons with possible (phonon-mediated) scattering channels for the CBM and VBM. Also plot phonon band structure and phonon PJDOS. Args: eb_ylims: Set the data limits for the y-axis of the electron band. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If None, limits are selected automatically. Return: |matplotlib-Figure| """ # Build grid. Share y-axis for Phbands and Phdos import matplotlib.pyplot as plt fig = plt.figure() ax0 = plt.subplot2grid((3, 3), (0, 0), colspan=3, rowspan=2) ax1 = plt.subplot2grid((3, 3), (2, 0), colspan=2, rowspan=1) ax2 = plt.subplot2grid((3, 3), (2, 2), colspan=1, rowspan=1) ax1.get_shared_y_axes().join(ax1, ax2) # Plot electrons with possible e-ph scattering channels. self.eb_kpath.plot(ax=ax0, with_gaps=True, ylims=eb_ylims, max_phfreq=self.phb_qpath.maxfreq, show=False) # Plot phonon bands self.phb_qpath.plot(ax=ax1, show=False) #ax1.yaxis.set_visible(False) #set_visible(ax1, False, "ylabel") # Plot phonon PJDOS self.phdos_file.plot_pjdos_type(ax=ax2, fontsize=8, exchange_xy=True, show=False) set_visible(ax2, False, "ylabel") ax2.tick_params("y", left=False, labelleft=False) ax2.tick_params("y", right=True, labelright=True) # Adjust y-limits for phonons ylims = self.phb_qpath.minfreq, self.phb_qpath.maxfreq + 0.1 * abs( self.phb_qpath.maxfreq) for ax in (ax1, ax2): set_axlims(ax, ylims, "y") return fig
def plot_doses(self, xlims=None, dos_names="all", with_idos=True, **kwargs): r""" Plot the different doses stored in the GRUNS.nc file. Args: xlims: Set the data limits for the x-axis in eV. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used dos_names: List of strings defining the DOSes to plot. Use "all" to plot all DOSes available. with_idos: True to display integrated doses. Return: |matplotlib-Figure| """ if not self.doses: return None dos_names = _ALL_DOS_NAMES.keys() if dos_names == "all" else list_strings(dos_names) wmesh = self.doses["wmesh"] nrows, ncols = len(dos_names), 1 ax_list, fig, plt = get_axarray_fig_plt(None, nrows=nrows, ncols=ncols, sharex=True, sharey=False, squeeze=False) ax_list = ax_list.ravel() for i, (name, ax) in enumerate(zip(dos_names, ax_list)): dos, idos = self.doses[name][0], self.doses[name][1] ax.plot(wmesh, dos, color="k") ax.grid(True) set_axlims(ax, xlims, "x") ax.set_ylabel(_ALL_DOS_NAMES[name]["latex"]) #ax.yaxis.set_ticks_position("right") if with_idos: other_ax = ax.twinx() other_ax.plot(wmesh, idos, color="k") other_ax.set_ylabel(_ALL_DOS_NAMES[name]["latex"].replace("DOS", "IDOS")) if i == len(dos_names) - 1: ax.set_xlabel(r"$\omega$ (eV)") #ax.legend(loc="best", fontsize=fontsize, shadow=True) return fig
def plot_chi2(self, key, components="all", what="abs", itemp=0, decompose=False, ax=None, xlims=None, with_xlabel=True, label=None, fontsize=12, **kwargs): """ Low-level function to plot chi2 tensor. Args: key: components: List of cartesian tensor components to plot e.g. ["xxx", "xyz"]. "all" if all components available on file should be plotted on the same ax. what: quantity to plot. "re" for real part, "im" for imaginary, Accepts also "abs", "angle". itemp: Temperature index. decompose: True to plot individual contributions. ax: |matplotlib-Axes| or None if a new figure should be created. xlims: Set the data limits for the x-axis. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used. with_xlabel: True to add x-label. label: True to add legend label to each curve. fontsize: Legend and label fontsize. Returns: |matplotlib-Figure| """ if not self.reader.computed_components[key]: return None comp2terms = self.reader.read_tensor3_terms(key, components, itemp=itemp) ax, fig, plt = get_ax_fig_plt(ax=ax) for comp, terms in comp2terms.items(): for name, values in terms.items(): if not decompose and not name.endswith("tot"): continue values = data_from_cplx_mode(what, values) ax.plot(self.wmesh[1:], values[1:], label=self.get_chi2_latex_label(key, what, comp) if label is None else label, ) ax.grid(True) if with_xlabel: ax.set_xlabel('Photon Energy (eV)') set_axlims(ax, xlims, "x") ax.legend(loc="best", fontsize=fontsize, shadow=True) return fig
def plot_phbands_with_gruns(self, fill_with="gruns", gamma_fact=1, alpha=0.6, with_doses="all", units="eV", ylims=None, match_bands=False, qlabels=None, branch_range=None, **kwargs): r""" Plot the phonon bands corresponding to ``V0`` (the central point) with markers showing the value and the sign of the Grunesein parameters. Args: fill_with: Define the quantity used to plot stripes. "gruns" for Grunesein parameters, "gruns_fd" for Grunesein parameters calculated with finite differences, "groupv" for phonon group velocities. gamma_fact: Scaling factor for Grunesein parameters. Up triangle for positive values, down triangles for negative values. alpha: The alpha blending value for the markers between 0 (transparent) and 1 (opaque). with_doses: "all" to plot all DOSes available, ``None`` to disable DOS plotting, else list of strings with the name of the DOSes to plot. units: Units for phonon plots. Possible values in ("eV", "meV", "Ha", "cm-1", "Thz"). Case-insensitive. ylims: Set the data limits for the y-axis in eV. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used match_bands: if True tries to follow the band along the path based on the scalar product of the eigenvectors. qlabels: dictionary whose keys are tuples with the reduced coordinates of the q-points. The values are the labels. e.g. ``qlabels = {(0.0,0.0,0.0): "$\Gamma$", (0.5,0,0): "L"}``. branch_range: Tuple specifying the minimum and maximum branch index to plot (default: all branches are plotted). Returns: |matplotlib-Figure|. """ if not self.phbands_qpath_vol: return None phbands = self.phbands_qpath_vol[self.iv0] factor = phbands.phfactor_ev2units(units) gamma_fact *= factor # Build axes (ax_bands and ax_doses) if with_doses is None: ax_bands, fig, plt = get_ax_fig_plt(ax=None) else: import matplotlib.pyplot as plt from matplotlib.gridspec import GridSpec dos_names = list(_ALL_DOS_NAMES.keys()) if with_doses == "all" else list_strings(with_doses) ncols = 1 + len(dos_names) fig = plt.figure() width_ratios = [2] + len(dos_names) * [0.2] gspec = GridSpec(1, ncols, width_ratios=width_ratios, wspace=0.05) ax_bands = plt.subplot(gspec[0]) ax_doses = [] for i in range(len(dos_names)): ax_doses.append(plt.subplot(gspec[i + 1], sharey=ax_bands)) # Plot phonon bands. phbands.plot(ax=ax_bands, units=units, match_bands=match_bands, show=False, qlabels=qlabels, branch_range=branch_range) if fill_with == "gruns": max_gamma = np.abs(phbands.grun_vals).max() values = phbands.grun_vals elif fill_with == "groupv": # TODO: units? dwdq_qpath = self.reader.read_value("gruns_dwdq_qpath") values = np.linalg.norm(dwdq_qpath, axis=-1) max_gamma = np.abs(values).max() elif fill_with == "gruns_fd": max_gamma = np.abs(self.grun_vals_finite_differences(match_eigv=True)).max() values = self.grun_vals_finite_differences(match_eigv=True) else: raise ValueError("Unsupported fill_with: `%s`" % fill_with) # Plot gruneisen markers on top of band structure. xvals = np.arange(len(phbands.phfreqs)) max_omega = np.abs(phbands.phfreqs).max() # Select the band range. if branch_range is None: branch_range = range(phbands.num_branches) else: branch_range = range(branch_range[0], branch_range[1], 1) for nu in branch_range: omegas = phbands.phfreqs[:, nu].copy() * factor if fill_with.startswith("gruns"): # Must handle positive-negative values sizes = values[:, nu].copy() * (gamma_fact * 0.02 * max_omega / max_gamma) yup = omegas + np.where(sizes >= 0, sizes, 0) ydown = omegas + np.where(sizes < 0, sizes, 0) ax_bands.fill_between(xvals, omegas, yup, alpha=alpha, facecolor="red") ax_bands.fill_between(xvals, ydown, omegas, alpha=alpha, facecolor="blue") elif fill_with == "groupv": sizes = values[:, nu].copy() * (gamma_fact * 0.04 * max_omega / max_gamma) ydown, yup = omegas - sizes / 2, omegas + sizes / 2 ax_bands.fill_between(xvals, ydown, yup, alpha=alpha, facecolor="red") set_axlims(ax_bands, ylims, "x") if with_doses is None: return fig # Plot Doses. wmesh = self.doses["wmesh"] * factor for i, (name, ax) in enumerate(zip(dos_names, ax_doses)): dos, idos = self.doses[name][0], self.doses[name][1] ax.plot(dos, wmesh, label=name, color="k") set_axlims(ax, ylims, "x") ax.grid(True) ax.set_ylabel("") ax.tick_params(labelbottom=False) if i == len(dos_names) - 1: ax.yaxis.set_ticks_position("right") else: ax.tick_params(labelleft=False) ax.set_title(_ALL_DOS_NAMES[name]["latex"]) return fig
def plot_phbands_with_gruns(self, fill_with="gruns", gamma_fact=1, alpha=0.6, with_doses="all", units="eV", ylims=None, match_bands=False, qlabels=None, branch_range=None, **kwargs): """ Plot the phonon bands corresponding to ``V0`` (the central point) with markers showing the value and the sign of the Grunesein parameters. Args: fill_with: Define the quantity used to plot stripes. "gruns" for Grunesein parameters, "gruns_fd" for Grunesein parameters calculated with finite differences, "groupv" for phonon group velocities. gamma_fact: Scaling factor for Grunesein parameters. Up triangle for positive values, down triangles for negative values. alpha: The alpha blending value for the markers between 0 (transparent) and 1 (opaque). with_doses: "all" to plot all DOSes available, ``None`` to disable DOS plotting, else list of strings with the name of the DOSes to plot. units: Units for phonon plots. Possible values in ("eV", "meV", "Ha", "cm-1", "Thz"). Case-insensitive. ylims: Set the data limits for the y-axis in eV. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used match_bands: if True tries to follow the band along the path based on the scalar product of the eigenvectors. qlabels: dictionary whose keys are tuples with the reduced coordinates of the q-points. The values are the labels. e.g. ``qlabels = {(0.0,0.0,0.0): "$\Gamma$", (0.5,0,0): "L"}``. branch_range: Tuple specifying the minimum and maximum branch index to plot (default: all branches are plotted). Returns: |matplotlib-Figure|. """ if not self.phbands_qpath_vol: return None phbands = self.phbands_qpath_vol[self.iv0] factor = phbands.phfactor_ev2units(units) gamma_fact *= factor # Build axes (ax_bands and ax_doses) if with_doses is None: ax_bands, fig, plt = get_ax_fig_plt(ax=None) else: import matplotlib.pyplot as plt from matplotlib.gridspec import GridSpec dos_names = list(_ALL_DOS_NAMES.keys()) if with_doses == "all" else list_strings(with_doses) ncols = 1 + len(dos_names) fig = plt.figure() width_ratios = [2] + len(dos_names) * [0.2] gspec = GridSpec(1, ncols, width_ratios=width_ratios, wspace=0.05) ax_bands = plt.subplot(gspec[0]) ax_doses = [] for i in range(len(dos_names)): ax_doses.append(plt.subplot(gspec[i + 1], sharey=ax_bands)) # Plot phonon bands. phbands.plot(ax=ax_bands, units=units, match_bands=match_bands, show=False, qlabels=qlabels, branch_range=branch_range) if fill_with == "gruns": max_gamma = np.abs(phbands.grun_vals).max() values = phbands.grun_vals elif fill_with == "groupv": # TODO: units? dwdq_qpath = self.reader.read_value("gruns_dwdq_qpath") values = np.linalg.norm(dwdq_qpath, axis=-1) max_gamma = np.abs(values).max() elif fill_with == "gruns_fd": max_gamma = np.abs(self.grun_vals_finite_differences(match_eigv=True)).max() values = self.grun_vals_finite_differences(match_eigv=True) else: raise ValueError("Unsupported fill_with: `%s`" % fill_with) # Plot gruneisen markers on top of band structure. xvals = np.arange(len(phbands.phfreqs)) max_omega = np.abs(phbands.phfreqs).max() # Select the band range. if branch_range is None: branch_range = range(phbands.num_branches) else: branch_range = range(branch_range[0], branch_range[1], 1) for nu in branch_range: omegas = phbands.phfreqs[:, nu].copy() * factor if fill_with.startswith("gruns"): # Must handle positive-negative values sizes = values[:, nu].copy() * (gamma_fact * 0.02 * max_omega / max_gamma) yup = omegas + np.where(sizes >= 0, sizes, 0) ydown = omegas + np.where(sizes < 0, sizes, 0) ax_bands.fill_between(xvals, omegas, yup, alpha=alpha, facecolor="red") ax_bands.fill_between(xvals, ydown, omegas, alpha=alpha, facecolor="blue") elif fill_with == "groupv": sizes = values[:, nu].copy() * (gamma_fact * 0.04 * max_omega / max_gamma) ydown, yup = omegas - sizes / 2, omegas + sizes / 2 ax_bands.fill_between(xvals, ydown, yup, alpha=alpha, facecolor="red") set_axlims(ax_bands, ylims, "x") if with_doses is None: return fig # Plot Doses. wmesh = self.doses["wmesh"] * factor for i, (name, ax) in enumerate(zip(dos_names, ax_doses)): dos, idos = self.doses[name][0], self.doses[name][1] ax.plot(dos, wmesh, label=name, color="k") set_axlims(ax, ylims, "x") ax.grid(True) ax.set_ylabel("") ax.tick_params(labelbottom=False) if i == len(dos_names) - 1: ax.yaxis.set_ticks_position("right") else: ax.tick_params(labelleft=False) ax.set_title(_ALL_DOS_NAMES[name]["latex"]) return fig
def plot_tensor(self, tstart=0, tstop=600, num=50, components="all", what="displ", view="inequivalent", select_symbols=None, colormap="jet", xlims=None, ylims=None, fontsize=10, verbose=0, **kwargs): """ Plot tensor(T) for each atom in the unit cell. One subplot for each component, each subplot show all inequivalent sites. By default, only "inequivalent" atoms are shown. Args: tstart: The starting value (in Kelvin) of the temperature mesh. tstop: The end value (in Kelvin) of the mesh. num: int, optional Number of samples to generate. components: "all" for all components. "diag" for diagonal elements, "offdiag" for off-diagonal terms only. what: "displ" for displament, "vel" for velocity. view: "inequivalent" to show only inequivalent atoms. "all" for all sites. select_symbols: String or list of strings with chemical symbols. Used to select only atoms of this type. colormap: matplotlib colormap. xlims: Set the data limits for the x-axis. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used. ylims: Set the data limits for the y-axis. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used fontsize: Legend and title fontsize. verbose: Verbosity level. Returns: |matplotlib-Figure| """ # Select atoms. aview = self._get_atomview(view, select_symbols=select_symbols, verbose=verbose) # One subplot for each component diag = ["xx", "yy", "zz"] offdiag = ["xy", "xz", "yz"] components = { "all": diag + offdiag, "diag": diag, "offdiag": offdiag, }[components] components = self._get_components(components) shape = np.reshape(components, (-1, 3)).shape nrows, ncols = shape[0], shape[1] ax_list, fig, plt = get_axarray_fig_plt(None, nrows=nrows, ncols=ncols, sharex=True, sharey=True, squeeze=True) ax_list = np.reshape(ax_list, (nrows, ncols)).ravel() cmap = plt.get_cmap(colormap) # Compute U(T) tmesh = np.linspace(tstart, tstop, num=num) msq = self.get_msq_tmesh(tmesh, iatom_list=aview.iatom_list, what_list=what) # [natom,3,3,nt] array values = getattr(msq, what) for ix, (ax, comp) in enumerate(zip(ax_list, components)): irow, icol = divmod(ix, ncols) ax.grid(True) set_axlims(ax, xlims, "x") set_axlims(ax, ylims, "y") ylabel = comp.get_tavg_label(what, with_units=True) ax.set_ylabel(ylabel, fontsize=fontsize) # Plot this component for all inequivalent atoms on the same subplot. for ii, (iatom, site_label) in enumerate( zip(aview.iatom_list, aview.site_labels)): color = cmap(float(ii) / max((len(aview.iatom_list) - 1), 1)) ys = comp.eval33w(values[iatom]) ax.plot(msq.tmesh, ys, label=site_label if ix == 0 else None, color=color) #, marker="o") if ix == 0: ax.legend(loc="best", fontsize=fontsize, shadow=True) if irow == 1: ax.set_xlabel('Temperature (K)') else: set_visible(ax, False, "xlabel", "xticklabels") return fig
def plot_uiso(self, tstart=0, tstop=600, num=50, what="displ", view="inequivalent", select_symbols=None, colormap="jet", xlims=None, ylims=None, sharey=False, fontsize=10, verbose=0, **kwargs): """ Plot phonon PJDOS for each atom in the unit cell. One subplot for each component, each subplot show all inequivalent sites. By default, only "inequivalent" atoms are shown. comparison of Ueq values, which are calculated as the mean of the diagonal elements of the harmonic ADP tensor, (d) comparison of the ADP anisotropy factor, which is defined as the ratio between maximum Uii and minimum Uii values. A ratio of 1 would correspond to an isotropic displacement. Args: tstart: The starting value (in Kelvin) of the temperature mesh. tstop: The end value (in Kelvin) of the mesh. num: int, optional Number of samples to generate. components: "all" for all components. "diag" for diagonal elements, "offdiag" for off-diagonal terms only. what: "displ" for displament, "vel" for velocity. view: "inequivalent" to show only inequivalent atoms. "all" for all sites. select_symbols: String or list of strings with chemical symbols. Used to select only atoms of this type. colormap: matplotlib colormap. xlims: Set the data limits for the x-axis. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used. ylims: Set the data limits for the y-axis. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used sharey: True if y-axis should be shared. fontsize: Legend and title fontsize. verbose: Verbosity level. Returns: |matplotlib-Figure| """ # Select atoms. aview = self._get_atomview(view, select_symbols=select_symbols, verbose=verbose) ax_list, fig, plt = get_axarray_fig_plt(None, nrows=2, ncols=1, sharex=True, sharey=sharey, squeeze=True) cmap = plt.get_cmap(colormap) # Compute U(T) tmesh = np.linspace(tstart, tstop, num=num) msq = self.get_msq_tmesh(tmesh, iatom_list=aview.iatom_list, what_list=what) # [natom, 3, 3, nt] values = getattr(msq, what) ntemp = len(msq.tmesh) for ix, ax in enumerate(ax_list): ax.grid(True) set_axlims(ax, xlims, "x") set_axlims(ax, ylims, "y") if what == "displ": ylabel = r"$U_{iso}\;(\AA^2)$" if ix == 0 else \ r"Anisotropy factor ($\dfrac{\epsilon_{max}}{\epsilon_{min}}}$)" elif what == "vel": ylabel = r"$V_{iso}\;(m/s)^2$" if ix == 0 else \ r"Anisotropy factor ($\dfrac{\epsilon_{max}}{\epsilon_{min}}}$)" else: raise ValueError("Unknown value for what: `%s`" % str(what)) ax.set_ylabel(ylabel, fontsize=fontsize) # Plot this component for all inequivalent atoms on the same subplot. for ii, (iatom, site_label) in enumerate( zip(aview.iatom_list, aview.site_labels)): color = cmap(float(ii) / max((len(aview.iatom_list) - 1), 1)) #msq.displ[iatom, 3, 3, nt] if ix == 0: # ISO calculated as the mean of the diagonal elements of the harmonic ADP tensor ys = np.trace(values[iatom]) / 3.0 elif ix == 1: # Ratio between maximum Uii and minimum Uii values. # A ratio of 1 would correspond to an isotropic displacement. ys = np.empty(ntemp) for itemp in range(ntemp): eigs = np.linalg.eigvalsh(values[iatom, :, :, itemp], UPLO='U') ys[itemp] = eigs.max() / eigs.min() else: raise ValueError("Invalid ix index: `%s" % ix) ax.plot(msq.tmesh, ys, label=site_label if ix == 0 else None, color=color) #, marker="o") if ix == 0: ax.legend(loc="best", fontsize=fontsize, shadow=True) if ix == len(ax_list) - 1: ax.set_xlabel("Temperature (K)") else: set_visible(ax, False, "xlabel", "xticklabels") return fig
def plot(self, components="upper", view="inequivalent", units="eV", select_symbols=None, xlims=None, ylims=None, sharey=False, fontsize=8, verbose=0, **kwargs): """ Plot the generalized phonon DOS g_ij(omega, atom) for each atom in the unit cell. One subplot per atom. Each subplot shows the 9 independent components of the symmetric tensor. as a function of frequency. By default, only "inequivalent" atoms are shown. Args: view: "inequivalent" to show only inequivalent atoms. "all" for all sites. components: List of cartesian tensor components to plot e.g. ["xx", "xy"]. "all" for all components. "upper" for the upper triangle, "diag" for diagonal elements. units: Units energy axis. Possible values in ("eV", "meV", "Ha", "cm-1", "Thz"). Case-insensitive. select_symbols: String or list of strings with chemical symbols. Used to select only atoms of this type. xlims: Set the data limits for the x-axis. Accept tuple e.g. ``(left, right)`` or scalar e.g. ``left``. If left (right) is None, default values are used. ylims: Set the data limits for the y-axis. sharey: True if y-axis should be shared. fontsize: Legend and title fontsize. verbose: Verbosity level. Returns: |matplotlib-Figure| """ # TODO Decide units for internal arrays. factor = abu.phfactor_ev2units(units) # Select atoms. aview = self._get_atomview(view, select_symbols, verbose=verbose) num_plots = len(aview.iatom_list) nrows, ncols = 1, 1 if num_plots > 1: ncols = 2 nrows = num_plots // ncols + num_plots % ncols ax_list, fig, plt = get_axarray_fig_plt(None, nrows=nrows, ncols=ncols, sharex=True, sharey=sharey, squeeze=True) ax_list = np.reshape(ax_list, (nrows, ncols)).ravel() # don't show the last ax if num_plots is odd. if num_plots % ncols != 0: ax_list[-1].axis("off") xx = self.wmesh * factor components = self._get_components(components) # For each atom in the view. for ix, (ax, iatom, site_label) in enumerate( zip(ax_list, aview.iatom_list, aview.site_labels)): irow, icol = divmod(ix, ncols) ax.grid(True) set_axlims(ax, xlims, "x") set_axlims(ax, ylims, "y") ax.set_title(site_label, fontsize=fontsize) #site = self.structure[iatom] #color = cmap(float(iatom) / max((len(iatom_list) - 1), 1)) # Plot components for this atom on the same ax. for c in components: yw = c.eval33w(self.values[iatom]) label = r"$G_{%s}$" % c.name if ix == 0 else None ax.plot(xx, yw / factor, label=label, **c.plot_kwargs) # Handle labels. if irow == nrows - 1: ax.set_xlabel('Frequency %s' % abu.phunit_tag(units)) else: set_visible(ax, False, "xlabel", "xticklabels") if ix == 0: ax.set_ylabel(r"$g_{ij}(\omega)$ 1/%s (Cart coords)" % abu.phunit_tag(units)) ax.legend(loc="best", fontsize=fontsize, shadow=True) return fig