Skip to content

phonons

Common workflows for phonons.

has_deps module-attribute

has_deps = (
    find_spec("phonopy") is not None
    and find_spec("seekpath") is not None
)

phonon_subflow

phonon_subflow(
    atoms: Atoms,
    force_job: Job,
    symprec: float = 0.0001,
    min_lengths: (
        float | tuple[float, float, float] | None
    ) = 20.0,
    supercell_matrix: (
        tuple[
            tuple[int, int, int],
            tuple[int, int, int],
            tuple[int, int, int],
        ]
        | None
    ) = None,
    displacement: float = 0.01,
    t_step: float = 10,
    t_min: float = 0,
    t_max: float = 1000,
    phonopy_kwargs: dict[str, Any] | None = None,
    additional_fields: dict[str, Any] | None = None,
) -> PhononSchema

Calculate phonon properties.

Parameters:

  • atoms (Atoms) –

    Atoms object with calculator attached.

  • force_job (Job) –

    The static job to calculate the forces.

  • symprec (float, default: 0.0001 ) –

    Precision for symmetry detection.

  • min_lengths (float | tuple[float, float, float] | None, default: 20.0 ) –

    Minimum length of each lattice dimension (A).

  • supercell_matrix (tuple[tuple[int, int, int], tuple[int, int, int], tuple[int, int, int]] | None, default: None ) –

    The supercell matrix to use. If specified, it will override any value specified by min_lengths.

  • displacement (float, default: 0.01 ) –

    Atomic displacement (A).

  • t_step (float, default: 10 ) –

    Temperature step (K).

  • t_min (float, default: 0 ) –

    Min temperature (K).

  • t_max (float, default: 1000 ) –

    Max temperature (K).

  • phonopy_kwargs (dict[str, Any] | None, default: None ) –

    Additional kwargs to pass to the Phonopy class.

  • additional_fields (dict[str, Any] | None, default: None ) –

    Additional fields to add to the output schema.

Returns:

Source code in quacc/recipes/common/phonons.py
@subflow
@requires(
    has_deps, "Phonopy and seekpath must be installed. Run `pip install quacc[phonons]`"
)
def phonon_subflow(
    atoms: Atoms,
    force_job: Job,
    symprec: float = 1e-4,
    min_lengths: float | tuple[float, float, float] | None = 20.0,
    supercell_matrix: (
        tuple[tuple[int, int, int], tuple[int, int, int], tuple[int, int, int]] | None
    ) = None,
    displacement: float = 0.01,
    t_step: float = 10,
    t_min: float = 0,
    t_max: float = 1000,
    phonopy_kwargs: dict[str, Any] | None = None,
    additional_fields: dict[str, Any] | None = None,
) -> PhononSchema:
    """
    Calculate phonon properties.

    Parameters
    ----------
    atoms
        Atoms object with calculator attached.
    force_job
        The static job to calculate the forces.
    symprec
        Precision for symmetry detection.
    min_lengths
        Minimum length of each lattice dimension (A).
    supercell_matrix
        The supercell matrix to use. If specified, it will override any
        value specified by `min_lengths`.
    displacement
        Atomic displacement (A).
    t_step
        Temperature step (K).
    t_min
        Min temperature (K).
    t_max
        Max temperature (K).
    phonopy_kwargs
        Additional kwargs to pass to the Phonopy class.
    additional_fields
        Additional fields to add to the output schema.

    Returns
    -------
    PhononSchema
        Dictionary of results from [quacc.schemas.phonons.summarize_phonopy][]
    """

    @subflow
    def _get_forces_subflow(supercells: list[Atoms]) -> list[dict]:
        return [
            force_job(supercell) for supercell in supercells if supercell is not None
        ]

    @job
    def _thermo_job(
        atoms: Atoms,
        phonopy: Phonopy,
        force_job_results: list[dict],
        t_step: float,
        t_min: float,
        t_max: float,
        additional_fields: dict[str, Any] | None,
    ) -> PhononSchema:
        parameters = force_job_results[-1].get("parameters")
        forces = [output["results"]["forces"] for output in force_job_results]
        phonopy_results = run_phonopy(
            phonopy, forces, t_step=t_step, t_min=t_min, t_max=t_max
        )

        return summarize_phonopy(
            phonopy,
            atoms,
            phonopy_results.directory,
            parameters=parameters,
            additional_fields=additional_fields,
        )

    phonopy = get_phonopy(
        atoms,
        min_lengths=min_lengths,
        supercell_matrix=supercell_matrix,
        symprec=symprec,
        displacement=displacement,
        phonopy_kwargs=phonopy_kwargs,
    )
    supercells = [
        phonopy_atoms_to_ase_atoms(s) for s in phonopy.supercells_with_displacements
    ]
    force_job_results = _get_forces_subflow(supercells)
    return _thermo_job(
        atoms, phonopy, force_job_results, t_step, t_min, t_max, additional_fields
    )