def phonopy_dos(filename, poscar='POSCAR', atoms=None): """Loads phonopy DoS and collates data per atom and as a total. By default reads atom names from a POSCAR, but can be overridden to allow for separation of environments. Arguments --------- filename : str path to phonopy projected_dos.dat or similar. poscar : str, optional path to POSCAR. Ignored if atoms specified. Default: POSCAR. atoms : str or array-like, optional atoms in POSCAR order. Atom names can be repeated, in which case their contributions are summed. Numbers can indicate repetition in the manner of a chemical formula, so the following are all acceptable and equivalent: "Ba 1 Sn 2 O 3", "Ba Sn Sn O O O", "Ba Sn O 3". Different environments can be distinguised with different atom names. Default: read from POSCAR. Returns ------- dict frequency, DoS per atom and total. """ # load data data = np.transpose(np.loadtxt(filename)) units = tp.settings.units() data2 = { 'frequency': data[0], 'meta': { 'phonon_dos_source': 'phonopy', 'units': { 'frequency': units['frequency'] } } } conversions = settings.phonopy_conversions() if 'frequency' in conversions: data2['frequency'] *= conversions['frequency'] if atoms is None: from pymatgen.io.vasp.inputs import Poscar poscar = Poscar.from_file(poscar, check_for_POTCAR=False, read_velocities=False).as_dict() atoms = [p['label'] for p in poscar['structure']['sites']] elif isinstance(atoms, str): atoms = atoms.split() # combine atoms contributions i = 0 n = 1 while i < len(atoms): try: atoms[i + 1] = int(atoms[i + 1]) if atoms[i] in data2: data2[atoms[i]] += np.sum(data[n:n + atoms[i + 1]], axis=0) else: data2[atoms[i]] = np.sum(data[n:n + atoms[i + 1]], axis=0) n += atoms[i + 1] i += 2 except Exception: if atoms[i] in data2: data2[atoms[i]] += data[n] else: data2[atoms[i]] = data[n] n += 1 i += 1 data2['total'] = np.sum(data[1:], axis=0) return data2
def phonopy_dispersion(filename, xdata=None): """Loads phonopy dispersion, and can scale the x values. Scaling the x values is necessary to plot multiple dispersions on the same axes. Arguments --------- filename : str filepath. xdata : dict, optional data for the dispersion to scale this to. Should have the same path, must have the same number of labels. Not necessary if using tp.plot.phonons.add_multi. Default: None. Returns ------- dict dispersion data. """ import yaml # load data with open(filename, 'r') as f: data = yaml.safe_load(f) x = [d['distance'] for d in data['phonon']] qp = [q['q-position'] for q in data['phonon']] d2, ticks = get_path(data) eigs = [[b['frequency'] for b in p['band']] for p in data['phonon']] # scale data to other path if xdata is not None: d1 = xdata['tick_position'] n = 0 for i, d0 in enumerate(x): while n <= len(d2) and not (d0 >= d2[n] and d0 <= d2[n + 1]): n += 1 x[i] = d1[n] + ((d0 - d2[n]) * (d1[n+1] - d1[n]) / \ (d2[n+1] - d2[n])) else: d1 = d2 conversions = settings.phonopy_conversions() if 'frequency' in conversions: eigs *= conversions['frequency'] units = tp.settings.units() data2 = { 'x': x, 'qpoint': qp, 'frequency': eigs, 'tick_position': d1, 'tick_label': ticks, 'meta': { 'phonon_dispersion_source': 'phonopy', 'units': { 'frequency': units['frequency'] } } } return data2