def setUp(self): with open(os.path.join(test_dir, "NaCl_phonon_bandstructure.json"), "r", encoding='utf-8') as f: d = json.load(f) self.bs = PhononBandStructureSymmLine.from_dict(d) with open(os.path.join(test_dir, "Si_phonon_bandstructure.json"), "r", encoding='utf-8') as f: d = json.load(f) self.bs2 = PhononBandStructureSymmLine.from_dict(d)
def setUp(self): with open( os.path.join(PymatgenTest.TEST_FILES_DIR, "NaCl_phonon_bandstructure.json"), encoding="utf-8", ) as f: d = json.load(f) self.bs = PhononBandStructureSymmLine.from_dict(d) with open( os.path.join(PymatgenTest.TEST_FILES_DIR, "Si_phonon_bandstructure.json"), encoding="utf-8", ) as f: d = json.load(f) self.bs2 = PhononBandStructureSymmLine.from_dict(d)
def setUp(self) -> None: self.phonopyfinite = PhonopyFiniteDisplacements( filename=os.path.join(testfile_dir, "phonopy.yaml")) self.phonopyfinite.run_all() self.phonopyfinite2 = PhonopyFiniteDisplacements( filename=os.path.join(testfile_dir, "phonopy.yaml")) self.phonopyfinite2.run_all() self.phonopyfinite3 = PhonopyFiniteDisplacements( filename=os.path.join(testfile_dir, "phonopy_manipulated.yaml")) self.phonopyfinite3.run_all() self.compare = ComparePhononBS( self.phonopyfinite.phonon_band_structure_pymatgen, self.phonopyfinite2.phonon_band_structure_pymatgen) self.compare2 = ComparePhononBS( self.phonopyfinite.phonon_band_structure_pymatgen, self.phonopyfinite3.phonon_band_structure_pymatgen) self.band1_dict = self.phonopyfinite2.phonon_band_structure_pymatgen.as_dict( ) new_bands = [] for iband, band in enumerate(self.band1_dict["bands"]): new_bands.append([]) for frequency in band: new_bands[iband].append(frequency + 0.1) self.band1_dict["bands"] = new_bands self.bandnew = PhononBandStructureSymmLine.from_dict(self.band1_dict) self.compare3 = ComparePhononBS( self.phonopyfinite.phonon_band_structure_pymatgen, self.bandnew)
def setUp(self): with open( os.path.join(PymatgenTest.TEST_FILES_DIR, "NaCl_phonon_bandstructure.json")) as f: d = json.loads(f.read()) self.bs = PhononBandStructureSymmLine.from_dict(d) self.plotter = PhononBSPlotter(self.bs)
def phonon_bandplot( filename, poscar=None, prefix=None, directory=None, dim=None, born=None, qmesh=None, spg=None, primitive_axis=None, line_density=60, units="THz", symprec=0.01, mode="bradcrack", kpt_list=None, eigenvectors=None, labels=None, height=6.0, width=6.0, style=None, no_base_style=False, ymin=None, ymax=None, image_format="pdf", dpi=400, plt=None, fonts=None, dos=None, to_json=None, from_json=None, to_web=None, legend=None, ): """A script to plot phonon band structure diagrams. Args: filename (str): Path to phonopy output. Can be a band structure yaml file, ``FORCE_SETS``, ``FORCE_CONSTANTS``, or ``force_constants.hdf5``. poscar (:obj:`str`, optional): Path to POSCAR file of unitcell. Not required if plotting the phonon band structure from a yaml file. If not specified, the script will search for a POSCAR file in the current directory. prefix (:obj:`str`, optional): Prefix for file names. directory (:obj:`str`, optional): The directory in which to save files. dim (:obj:`list`, optional): supercell matrix born (:obj:`str`, optional): Path to file containing Born effective charges. Should be in the same format as the file produced by the ``phonopy-vasp-born`` script provided by phonopy. qmesh (:obj:`list` of :obj:`int`, optional): Q-point mesh to use for calculating the density of state. Formatted as a 3x1 :obj:`list` of :obj:`int`. spg (:obj:`str` or :obj:`int`, optional): The space group international number or symbol to override the symmetry determined by spglib. This is not recommended and only provided for testing purposes. This option will only take effect when ``mode = 'bradcrack'``. primitive_axis (:obj:`list` or :obj:`str`, optional): The transformation matrix from the conventional to primitive cell. Only required when the conventional cell was used as the starting structure. Should be provided as a 3x3 :obj:`list` of :obj:`float`. Alternatively the string 'auto' may be used to request that a primitive matrix is determined automatically. line_density (:obj:`int`, optional): Density of k-points along the path. units (:obj:`str`, optional): Units of phonon frequency. Accepted (case-insensitive) values are Thz, cm-1, eV, meV. symprec (:obj:`float`, optional): Tolerance for space-group-finding operations mode (:obj:`str`, optional): Method used for calculating the high-symmetry path. The options are: bradcrack Use the paths from Bradley and Cracknell. See [brad]_. pymatgen Use the paths from pymatgen. See [curt]_. seekpath Use the paths from SeeK-path. See [seek]_. kpt_list (:obj:`list`, optional): List of k-points to use, formatted as a list of subpaths, each containing a list of fractional k-points. For example:: [ [[0., 0., 0.], [0., 0., 0.5]], [[0.5, 0., 0.], [0.5, 0.5, 0.]] ] Will return points along ``0 0 0 -> 0 0 1/2 | 1/2 0 0 -> 1/2 1/2 0`` labels (:obj:`list`, optional): The k-point labels. These should be provided as a :obj:`list` of :obj:`str` for each subpath of the overall path. For example:: [ ['Gamma', 'Z'], ['X', 'M'] ] combined with the above example for ``kpt_list`` would indicate the path: Gamma -> Z | X -> M. If no labels are provided, letters from A -> Z will be used instead. eigenvectors (:obj:`bool`, optional): Write the eigenvectors to the yaml file. (Always True if to_web is set.) dos (str): Path to Phonopy total dos .dat file height (:obj:`float`, optional): The height of the plot. width (:obj:`float`, optional): The width of the plot. ymin (:obj:`float`, optional): The minimum energy on the y-axis. ymax (:obj:`float`, optional): The maximum energy on the y-axis. style (:obj:`list` or :obj:`str`, optional): (List of) matplotlib style specifications, to be composed on top of Sumo base style. no_base_style (:obj:`bool`, optional): Prevent use of sumo base style. This can make alternative styles behave more predictably. image_format (:obj:`str`, optional): The image file format. Can be any format supported by matplotlib, including: png, jpg, pdf, and svg. Defaults to pdf. dpi (:obj:`int`, optional): The dots-per-inch (pixel density) for the image. plt (:obj:`matplotlib.pyplot`, optional): A :obj:`matplotlib.pyplot` object to use for plotting. fonts (:obj:`list`, optional): Fonts to use in the plot. Can be a a single font, specified as a :obj:`str`, or several fonts, specified as a :obj:`list` of :obj:`str`. to_json (:obj:`str`, optional): JSON file to dump the Pymatgen band path object. from_json (:obj:`list` or :obj:`str`, optional): (List of) JSON bandpath data filename(s) to import and overlay. to_web (:obj:`str`, optional): JSON file to write data for visualisation with http://henriquemiranda.github.io/phononwebsite legend (:obj:`list` or :obj:`None`, optional): Legend labels. If None, don't add a legend. With a list length equal to from_json, label json inputs only. With one extra list entry, label all lines beginning with new plot. Returns: A matplotlib pyplot object. """ save_files = False if plt else True # don't save if pyplot object provided if isinstance(from_json, str): from_json = [from_json] if eigenvectors is None: if to_web is None: eigenvectors = False else: eigenvectors = True elif not eigenvectors and to_web is not None: raise ValueError("Cannot set eigenvectors=False and write web JSON") if filename is None: if from_json is None: filename = "FORCE_SETS" bs, phonon = _bs_from_filename( filename, poscar, dim, symprec, spg, kpt_list, labels, primitive_axis, units, born, mode, eigenvectors, line_density, ) else: logging.info( f"No input data, using file {from_json[0]} to construct plot") with open(from_json[0]) as f: bs = PhononBandStructureSymmLine.from_dict(json.load(f)) from_json = from_json[1:] phonon = None else: bs, phonon = _bs_from_filename( filename, poscar, dim, symprec, spg, kpt_list, labels, primitive_axis, units, born, mode, eigenvectors, line_density, ) if to_json is not None: logging.info(f"Writing symmetry lines to {to_json}") with open(to_json, "wt") as f: f.write(bs.to_json()) if to_web is not None: logging.info(f"Writing visualisation JSON to {to_web}") bs.write_phononwebsite(to_web) # Replace dos filename with data array if dos is not None: if phonon is None: logging.error("Cannot use phonon DOS without Phonopy") sys.exit() if isfile(dos): dos = np.genfromtxt(dos, comments="#") elif dos: phonon.set_mesh( qmesh, is_gamma_center=False, is_eigenvectors=True, is_mesh_symmetry=False, ) phonon.set_total_DOS() dos_freq, dos_val = phonon.get_total_DOS() dos = np.zeros((len(dos_freq), 2)) dos[:, 0], dos[:, 1] = dos_freq, dos_val plotter = SPhononBSPlotter(bs) plt = plotter.get_plot( units=units, ymin=ymin, ymax=ymax, height=height, width=width, plt=plt, fonts=fonts, dos=dos, style=style, no_base_style=no_base_style, from_json=from_json, legend=legend, ) if save_files: basename = f"phonon_band.{image_format}" filename = f"{prefix}_{basename}" if prefix else basename if directory: filename = os.path.join(directory, filename) if dpi is None: dpi = rcParams["figure.dpi"] plt.savefig(filename, format=image_format, dpi=dpi, bbox_inches="tight") filename = save_data_files(bs, prefix=prefix, directory=directory) return filename else: return plt
def setUp(self): with open(os.path.join(test_dir, "NaCl_phonon_bandstructure.json"), "r") as f: d = json.loads(f.read()) self.bs = PhononBandStructureSymmLine.from_dict(d) self.plotter = PhononBSPlotter(self.bs)
def get_plot(self, units='THz', ymin=None, ymax=None, width=None, height=None, dpi=None, plt=None, fonts=None, dos=None, dos_aspect=3, color=None, style=None, no_base_style=False, from_json=None, legend=None): """Get a :obj:`matplotlib.pyplot` object of the phonon band structure. Args: units (:obj:`str`, optional): Units of phonon frequency. Accepted (case-insensitive) values are Thz, cm-1, eV, meV. ymin (:obj:`float`, optional): The minimum energy on the y-axis. ymax (:obj:`float`, optional): The maximum energy on the y-axis. width (:obj:`float`, optional): The width of the plot. height (:obj:`float`, optional): The height of the plot. dpi (:obj:`int`, optional): The dots-per-inch (pixel density) for the image. fonts (:obj:`list`, optional): Fonts to use in the plot. Can be a a single font, specified as a :obj:`str`, or several fonts, specified as a :obj:`list` of :obj:`str`. plt (:obj:`matplotlib.pyplot`, optional): A :obj:`matplotlib.pyplot` object to use for plotting. dos (:obj:`np.ndarray`): 2D Numpy array of total DOS data dos_aspect (float): Width division for vertical DOS color (:obj:`str` or :obj:`tuple`, optional): Line/fill colour in any matplotlib-accepted format style (:obj:`list`, :obj:`str`, or :obj:`dict`): Any matplotlib style specifications, to be composed on top of Sumo base style. no_base_style (:obj:`bool`, optional): Prevent use of sumo base style. This can make alternative styles behave more predictably. from_json (:obj:`list` or :obj:`None`, optional): List of paths to :obj:`pymatgen.phonon.bandstructure.PhononBandStructureSymmline` JSON dump files. These are used to generate additional plots displayed under the data attached to this plotter. The k-point path should be the same as the main plot; the reciprocal lattice is adjusted to fit the scaling of the main data input. Returns: :obj:`matplotlib.pyplot`: The phonon band structure plot. """ if from_json is None: from_json = [] if legend is None: legend = [''] * (len(from_json) + 1) else: if len(legend) == 1 + len(from_json): pass elif len(legend) == len(from_json): legend = [''] + list(legend) else: raise ValueError('Inappropriate number of legend entries') if color is None: color = 'C0' # Default to first colour in matplotlib series if dos is not None: plt = pretty_subplot(1, 2, width=width, height=height, sharex=False, sharey=True, dpi=dpi, plt=plt, gridspec_kw={'width_ratios': [dos_aspect, 1], 'wspace': 0}) ax = plt.gcf().axes[0] else: plt = pretty_plot(width, height, dpi=dpi, plt=plt) ax = plt.gca() def _plot_lines(data, ax, color=None, alpha=1, zorder=1): """Pull data from any PhononBSPlotter and add to axis""" dists = data['distances'] freqs = data['frequency'] # nd is branch index, nb is band index, nk is kpoint index for nd, nb in itertools.product(range(len(data['distances'])), range(self._nb_bands)): f = freqs[nd][nb] # plot band data ax.plot(dists[nd], f, ls='-', c=color, zorder=zorder) data = self.bs_plot_data() _plot_lines(data, ax, color=color) for i, bs_json in enumerate(from_json): with open(bs_json, 'rt') as f: json_data = json.load(f) json_data['lattice_rec'] = json.loads( self._bs.lattice_rec.to_json()) bs = PhononBandStructureSymmLine.from_dict(json_data) # bs.lattice_rec = self._bs.lattice_rec # raise Exception(bs.qpoints) json_plotter = PhononBSPlotter(bs) json_data = json_plotter.bs_plot_data() if json_plotter._nb_bands != self._nb_bands: raise Exception('Number of bands in {} does not match ' 'main plot'.format(bs_json)) _plot_lines(json_data, ax, color='C{}'.format(i + 1), zorder=0.5) if any(legend): # Don't show legend if all entries are empty string from matplotlib.lines import Line2D ax.legend([Line2D([0], [0], color='C{}'.format(i)) for i in range(len(legend))], legend) self._maketicks(ax, units=units) self._makeplot(ax, plt.gcf(), data, width=width, height=height, ymin=ymin, ymax=ymax, dos=dos, color=color) plt.tight_layout() plt.subplots_adjust(wspace=0) return plt