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)