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)
def trimer(pot, atoms, elements, folder=None, base64=False, index=None, nsamples=50): """Plots the potential behavior as the angle between three atoms changes in a trimer. .. note:: This produces a *dict* of all possible 3-body interactions between distinct element types. Args: elements (list): list of chemical symbols in the system. pot (matdb.calculators.basic.AsyncCalculator): IP to calculate properties with. atoms (matdb.atoms.AtomsList): list of atoms from which to calculate correlations. folder (str): path to the folder where the saved image should be stored. base64 (bool): when True, use a base-64 encoded `src` for the output of this image; otherwise, the image is saved to `folder` and only its name is returned. index (int): integer index of this plot in the parent collection. nsamples (int): number of samples to take along the trajectory. Returns: dict: keys are concatenated element names (e.g. `AgPd`) and values are :class:`PointDetailImage` instances. """ #First, determine the set of unique element pairs in the list. from itertools import product possible = list(product(elements, repeat=3)) target = list(set(map(lambda l: tuple(sorted(l)), possible))) subplot_kw = {"xlabel": "Angle (Rad)", "ylabel": "IP Energy (eV)"} result = {} for elements in target: #Look up the lattice parameters for each of the elements. Use Vegard's #law to get a decent domain to plot the energy over. from matdb.data import vegard uelements = list(set(elements)) concdict = [elements.count(e) / 3. for e in uelements] rvegard = vegard(uelements, concdict) trimer = Atoms(positions=np.zeros((3, 3)), cell=np.eye(3) * 100) trimer.positions = 0. trimer.set_chemical_symbols(elements) trimer.set_calculator(pot) #Set the position of the second atom to be at equilibrium with respect #to the Vegard's law calculation. trimer.positions[1, 2] = rvegard #Now, vary the angle of the third atom with respect to the original two #and see how the angle changes. theta = np.linspace(np.pi / 6, np.pi, nsamples) energy = [] for t in theta: x = rvegard * np.cos(t) y = rvegard * np.sin(t) trimer.positions[1, 2] = x trimer.positions[1, 2] = y energy.append(trimer.get_potential_energy()) elemstr = trimer.get_chemical_formula() img = PDI(theta, np.array(energy), "plot", subplot_kw=subplot_kw, index=index, base64=base64, name=elemstr, imgtype=elemstr, folder=folder) result[elemstr] = img return result