예제 #1
0
    def get_kpath(self):
        """Returns the special path in k-space for the seed configuration of this group.

        Returns:
            tuple: special path in k-space. First term is a list of special point labels; second is the list of points corresponding to those labels.
        """
        if self._kpath is None:
            from matdb.kpoints import parsed_kpath
            self._kpath = parsed_kpath(self.atoms)

        return self._kpath
예제 #2
0
def test_kpath():
    """Performs a simple test to extract the kpath for an alloy.
    """
    from matdb.atoms import Atoms
    from matdb.kpoints import parsed_kpath
    from matdb.utility import relpath
    filepath = relpath("tests/files/POSCAR-AgPd-50")
    at0 = Atoms(filepath, format="vasp")
    model = {
        'band': [[0.0, 0.0, 0.0], [0.0, 0.0, 0.5], [0.25, 0.25, 0.25],
                 [0.0, 0.5, 0.0], [0.0, 0.0, 0.0], [0.5, 0.5, -0.5],
                 [0.3126058432665583, 0.6873941567334416, -0.3126058432665583],
                 [0.0, 0.0, 0.0],
                 [-0.12521168653311662, 0.12521168653311662, 0.5],
                 [0.5, 0.5, -0.5]],
        'labels': [
            '\\Gamma', 'X', 'P', 'N', '\\Gamma', 'M', 'S|S_0', '\\Gamma|X',
            'R|G', 'M'
        ]
    }

    labels, band = parsed_kpath(at0)
    assert labels == model["labels"]
    assert band == model["band"]
예제 #3
0
def band_plot(dbs,
              fits=None,
              npts=100,
              title="{} Phonon Spectrum",
              save=None,
              figsize=(10, 8),
              nbands=None,
              delta=0.01,
              quick=True,
              **kwargs):
    """Plots the phonon bands for the specified CLI args.

    Args:
        dbs (list): list of :class:`matdb.database.hessian.Hessian` `phonopy`
          calculation database instances that have DFT-accurate band
          information.
        fits (list): list of :class:`~matdb.fitting.basic.Trainer` to calculate bands
          for.
        dim (list): list of `int`; supercell dimensions for the phonon calculations.
        npts (int): number of points to sample along the special path in
          k-space.
        title (str): Override the default title for plotting; use `{}` for
          formatting chemical formula.
        save (str): name of a file to save the plot to; otherwise the plot is
          shown in a window.
        figsize (tuple): tuple of `float`; the size of the figure in inches.
        delta (float): size of displacement for finite difference derivative.
        nbands (int): number of bands to plot.
        quick (bool): when True, use symmetry to speed up the Hessian
          calculation for the specified potentials.
        kwargs (dict): additional "dummy" arguments so that this method can be
          called with arguments to other functions.
    """
    if len(dbs) == 0:
        raise ValueError("Must specify at least one Hessian group "
                         "to plot phonons for.")

    db = dbs[0]
    if db.atoms is not None:
        ratoms = db.atoms
    else:
        #Use the parent group; this one must have been one of the sub-sequence
        #recursively generated groups.
        ratoms = db.parent.atoms
    title = title.format(ratoms.get_chemical_formula())

    nlines = len(dbs) + (0 if fits is None else len(fits))
    colors = plt.cm.nipy_spectral(np.linspace(0, 1, nlines))

    bands, style = {}, {}
    names, kpath = parsed_kpath(ratoms)
    #matplotlib needs the $ signs for latex if we are using special
    #characters. We only get names out from the first configuration; all
    #the others have to use the same one.
    names = ["${}$".format(n) if '\\' in n or '_' in n else n for n in names]

    for dbi, db in enumerate(dbs):
        db.calc_bands()
        bands[db.key] = db.bands
        style[db.key] = {"color": colors[dbi], "lw": 2}

    #All of the phonon calculations use the same base atoms configuration. The
    #last `phondb` in the enumerated list is as good as any other.
    if fits is not None:
        for fiti, fit in enumerate(tqdm(fits)):
            gi = len(dbs) + fiti
            ai = ratoms.copy()
            ai.set_calculator(fit.calculator)
            H = phon_calc(ai, supercell=db.supercell, delta=delta, quick=quick)
            bands[fit.fqn] = _calc_bands(db.atoms, H, db.supercell)
            style[fit.fqn] = {"color": colors[gi], "lw": 2}

    savefile = None
    if save:
        savefile = path.join(db.database.parent.plotdir, save)

    bandplot(bands,
             names,
             title=title,
             outfile=savefile,
             figsize=figsize,
             style=style,
             nbands=nbands)
예제 #4
0
def band_raw(primitive,
             bandfiles=None,
             pots=None,
             supercell=None,
             npts=100,
             title="{} Phonon Spectrum",
             save=None,
             figsize=(10, 8),
             nbands=4,
             line_names=None,
             delta=0.01,
             quick=True,
             **kwargs):
    """Plots the phonon bands from raw `band.yaml` files.

    Args:
        primitive (str): path to the atoms file for the *primitive* to plot
          bands for. Use the ASE format string as a prefix,
          e.g. `vasp-xml:vasprun.xml` or `extxyz:atoms.xyz`. Default assumes
          `vasp:{}` if no format is specified.
        bandfiles (list): list of `str` file paths to the plain `band.yaml` files.
        supercell (list): list of `int`; supercell dimensions for the phonon
          calculations.
        npts (int): number of points to sample along the special path in
          k-space.
        title (str): Override the default title for plotting; use `{}` for
          formatting chemical formula.
        save (str): name of a file to save the plot to; otherwise the plot is
          shown in a window.
        figsize (tuple): tuple of `float`; the size of the figure in inches.
        nbands (int): number of bands to plot.
        delta (float): size of displacement for finite difference derivative.
        quick (bool): when True, use symmetry to speed up the Hessian
          calculation for the specified potentials.
        kwargs (dict): additional "dummy" arguments so that this method can be
          called with arguments to other functions.
    """
    nlines = len(bandfiles) + (0 if pots is None else len(pots))
    colors = plt.cm.nipy_spectral(np.linspace(0, 1, nlines))
    bands, style = {}, {}

    #Handle DSL format import on the file path for the primitive cell.
    if ':' not in primitive:
        atoms = Atoms(primitive, format="vasp")
    else:
        fmt, atpath = primitive.split(':')
        atoms = Atoms(atpath, format=fmt)

    names, kpath = parsed_kpath(atoms)

    #matplotlib needs the $ signs for latex if we are using special
    #characters. We only get names out from the first configuration; all
    #the others have to use the same one.
    names = ["${}$".format(n) if '\\' in n or '_' in n else n for n in names]

    for ifile, fpath in enumerate(bandfiles):
        if line_names is not None:
            key = line_names[ifile]
        else:
            key = "File {}".format(ifile)

        bands[key] = from_yaml(fpath)
        style[key] = {"color": colors[ifile], "lw": 2}

    if pots is not None:
        for fiti, fit in enumerate(tqdm(pots)):
            gi = len(bandfiles) + fiti
            atoms.set_calculator(fit)
            H = phon_calc(atoms, supercell=supercell, delta=delta, quick=quick)
            bands[line_names[gi]] = _calc_bands(atoms, H, supercell)
            style[line_names[gi]] = {"color": colors[gi], "lw": 2}

    title = title.format(atoms.get_chemical_formula())
    savefile = None
    if save:
        savefile = save

    bandplot(bands,
             names,
             title=title,
             outfile=savefile,
             figsize=figsize,
             style=style,
             nbands=nbands)
예제 #5
0
def _calc_bands(atoms, hessian, supercell=(1, 1, 1), outfile=None, grid=None):
    """Calculates the band structure for the given Hessian matrix.

    Args:
        atoms (matdb.atoms.Atoms): atoms object corresponding to the *primitive*
          cell. The specified supercell matrix should  result in a number
          of atoms that matches the dimensionality of the Hessian.
        supercell (tuple): tuple of `int` supercell matrix components; can have either
          3 or 9 components.
        hessian (numpy.ndarray): with shape `(natoms*3, natoms*3)`.
        grid (list): list of `int` specifying the number of divisions in k-space
          along each reciprocal unit vector.
        outfile (str): path to the output `band.yaml` file that should be
          created by this function.

    Returns:
        If `outfile` is None, then this method returns a dictionary that has the
        same format as :func:`from_yaml`.
    """
    #Create a temporary directory in which to work.
    target = mkdtemp()
    bandfile = path.join(target, "band.yaml")

    if grid is None:
        grid = [13, 13, 13]
    if isinstance(supercell, np.ndarray):
        supercell = supercell.flatten()

    #First, roll up the Hessian and write it as a FORCE_CONSTANTS file.
    with chdir(target):
        HR = roll(hessian)
        write_FORCE_CONSTANTS(HR)
        atoms.write("POSCAR", format="vasp")

        #We need to create the band.conf file and write the special
        #paths in k-space at which the phonons should be calculated.
        atom_types = _ordered_unique(atoms.get_chemical_symbols())
        settings = [("FORCE_CONSTANTS", "READ"),
                    ("ATOM_NAME", ' '.join(atom_types)),
                    ("DIM", ' '.join(map(str, supercell))),
                    ("MP", ' '.join(map(str, grid)))]

        labels, bands = parsed_kpath(atoms)
        bandfmt = "{0:.3f} {1:.3f} {2:.3f}"
        sband = []
        for Q in bands:
            sband.append(bandfmt.format(*Q))

        settings.append(("BAND", "  ".join(sband)))
        settings.append(("BAND_LABELS", ' '.join(labels)))

        with open("band.conf", 'w') as f:
            for k, v in settings:
                f.write("{} = {}\n".format(k, v))

    sargs = ["phonopy", "band.conf"]
    xres = execute(sargs, target, venv=True)

    if not path.isfile(bandfile):  #pragma: no cover
        msg.err("could not calculate phonon bands; see errors.")
        msg.std(''.join(xres["output"]))

    result = None
    if outfile is not None:
        #Move the band.yaml file to the new target location.
        from shutil import move
        move(bandfile, outfile)
    else:
        result = from_yaml(bandfile)

    #Remove the temporary directory that we created and return the result.
    rmtree(target)
    return result