Spaces:
Running
Running
""" | |
This module has been adapted from Quacc (https://github.com/Quantum-Accelerators/quacc). By using this software, you agree to the Quacc license agreement: https://github.com/Quantum-Accelerators/quacc/blob/main/LICENSE.md | |
BSD 3-Clause License | |
Copyright (c) 2025, Andrew S. Rosen. | |
All rights reserved. | |
Redistribution and use in source and binary forms, with or without | |
modification, are permitted provided that the following conditions are met: | |
- Redistributions of source code must retain the above copyright notice, this | |
list of conditions and the following disclaimer. | |
- Redistributions in binary form must reproduce the above copyright notice, | |
this list of conditions and the following disclaimer in the documentation | |
and/or other materials provided with the distribution. | |
- Neither the name of the copyright holder nor the names of its | |
contributors may be used to endorse or promote products derived from | |
this software without specific prior written permission. | |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
""" | |
from pathlib import Path | |
import numpy as np | |
from phonopy import Phonopy | |
from phonopy.structure.atoms import PhonopyAtoms | |
from prefect import task | |
from prefect.cache_policies import INPUTS, TASK_SOURCE | |
from prefect.runtime import task_run | |
from ase import Atoms | |
from ase.calculators.calculator import BaseCalculator | |
def get_phonopy( | |
atoms: Atoms, | |
supercell_matrix: list[int] | None = None, | |
min_lengths: float | tuple[float, float, float] | None = None, | |
symprec: float = 1e-5, | |
distance: float = 0.01, | |
phonopy_kwargs: dict = {}, | |
) -> Phonopy: | |
if supercell_matrix is None and min_lengths is not None: | |
supercell_matrix = np.diag( | |
np.round(np.ceil(min_lengths / atoms.cell.lengths())) | |
) | |
phonon = Phonopy( | |
PhonopyAtoms( | |
symbols=atoms.get_chemical_symbols(), | |
cell=atoms.get_cell(), | |
scaled_positions=atoms.get_scaled_positions(wrap=True), | |
masses=atoms.get_masses(), | |
), | |
symprec=symprec, | |
supercell_matrix=supercell_matrix, | |
**phonopy_kwargs, | |
) | |
phonon.generate_displacements(distance=distance) | |
return phonon | |
def _get_forces( | |
phononpy_atoms: PhonopyAtoms, | |
calculator: BaseCalculator, | |
) -> np.ndarray: | |
atoms = Atoms( | |
symbols=phononpy_atoms.symbols, | |
cell=phononpy_atoms.cell, | |
scaled_positions=phononpy_atoms.scaled_positions, | |
pbc=True, | |
) | |
atoms.calc = calculator | |
return atoms.get_forces() | |
def _generate_task_run_name(): | |
task_name = task_run.task_name | |
parameters = task_run.parameters | |
atoms = parameters["atoms"] | |
calculator = parameters["calculator"] | |
return ( | |
f"{task_name}: {atoms.get_chemical_formula()} - {calculator.__class__.__name__}" | |
) | |
def run( | |
atoms: Atoms, | |
calculator: BaseCalculator, | |
supercell_matrix: list[int] | None = None, | |
min_lengths: float | tuple[float, float, float] | None = None, | |
symprec: float = 1e-5, | |
distance: float = 0.01, | |
phonopy_kwargs: dict = {}, | |
symmetry: bool = False, | |
t_min: float = 0.0, | |
t_max: float = 1000.0, | |
t_step: float = 10.0, | |
outdir: str | None = None, | |
): | |
phonon = get_phonopy( | |
atoms=atoms, | |
supercell_matrix=supercell_matrix, | |
min_lengths=min_lengths, | |
symprec=symprec, | |
distance=distance, | |
phonopy_kwargs=phonopy_kwargs, | |
) | |
supercells_with_displacements = phonon.supercells_with_displacements | |
phonon.forces = [ | |
_get_forces(supercell, calculator) | |
for supercell in supercells_with_displacements | |
if supercell is not None | |
] | |
phonon.produce_force_constants() | |
if symmetry: | |
phonon.symmetrize_force_constants() | |
phonon.symmetrize_force_constants_by_space_group() | |
phonon.run_mesh(with_eigenvectors=True) | |
phonon.run_total_dos() | |
phonon.run_thermal_properties(t_step=t_step, t_max=t_max, t_min=t_min) # type: ignore | |
phonon.auto_band_structure( | |
write_yaml=True if outdir is not None else False, | |
filename=Path(outdir, "band.yaml") if outdir is not None else "band.yaml", | |
) | |
if outdir: | |
phonon.save( | |
Path(outdir, "phonopy.yaml"), settings={"force_constants": True} | |
) | |
return { | |
"phonon": phonon, | |
} | |