def ase_phonon_calc( struct, calc=None, kpoints=[1, 1, 1], ftol=0.01, force_clean=False, name="asephonon", ): """Calculate phonon modes of a molecule using ASE and a given calculator. The system will be geometry optimized before calculating the modes. A report of the phonon modes will be written to a file and arrays of the eigenvectors and eigenvalues returned. | Args: | struct (ase.Atoms): Atoms object with to calculate modes for. | calc (ase.Calculator): Calculator for energies and forces (if not | present, use the one from struct) | kpoints (np.ndarray): Kpoint grid for phonon calculation. If None, just | do a Vibration modes calculation (default is [1,1,1]) | ftol (float): Tolerance for geometry optimisation (default | is 0.01 eV/Ang) | force_clean (bool): If True, force a deletion of all phonon files | and recalculate them | Returns: | evals (float[k-points][modes]): Eigenvalues of phonon modes | evecs (float[k-points][modes][ions][3]): Eigenvectors of phonon modes | struct (ase.Atoms): Optimised structure """ N = len(struct) if calc is None: calc = struct.calc struct = struct.copy() calc.atoms = struct struct.calc = calc dyn = BFGS(struct, trajectory="geom_opt.traj") dyn.run(fmax=ftol) # Calculate phonon modes vib_pbc = kpoints is not None if vib_pbc: vib = Phonons(struct, calc, name=name) else: vib = Vibrations(struct, name=name) if force_clean: vib.clean() vib.run() if vib_pbc: vib.read(acoustic=True) path = monkhorst_pack(kpoints) evals, evecs = vib.band_structure(path, True) else: vib.read() path = np.zeros((1, 3)) # One axis added since it's like the gamma point evals = np.real(vib.get_energies()[None]) evecs = np.array([vib.get_mode(i) for i in range(3 * N)])[None] # eV to cm^-1 evals *= ((cnst.electron_volt / cnst.h) / cnst.c) / 100.0 # Normalise eigenvectors evecs /= np.linalg.norm(evecs, axis=(2, 3))[:, :, None, None] return ASEPhononData(evals, evecs, path, struct)