Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Phonons for forcefields #398

Merged
merged 63 commits into from
Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
817c579
First extremely patchy implementation of phonons for forcefields
JaGeo Jun 23, 2023
c9e4521
Update kwargs
JaGeo Jul 21, 2023
9fee276
Fix force constants
JaGeo Jul 21, 2023
f53ec6c
Fix documentation
JaGeo Jul 21, 2023
0b55561
Make fmax smaller
JaGeo Jul 21, 2023
011b12c
Fix data types
JaGeo Jul 21, 2023
517707c
Fix linting
JaGeo Jul 21, 2023
1c9c8fc
Fix linting
JaGeo Jul 21, 2023
1010da0
Add doc
JaGeo Jul 21, 2023
7b3ad5f
Add doc
JaGeo Jul 21, 2023
ae043eb
Add doc
JaGeo Jul 21, 2023
a42608a
Revert changes
JaGeo Jul 24, 2023
4dfc596
Merge branch 'materialsproject:main' into forcefield-phonons
JaGeo Jul 24, 2023
31f9ec1
Add a test
JaGeo Jul 24, 2023
cb5e7e1
linting
JaGeo Jul 24, 2023
a969977
fix test
JaGeo Jul 24, 2023
e9620b6
Update linting
JaGeo Jul 24, 2023
a380473
refactor
JaGeo Jul 24, 2023
a4f9ba7
Merge branch 'materialsproject:main' into forcefield-phonons
JaGeo Jul 26, 2023
effcd18
Update flows
JaGeo Jul 27, 2023
5c79c65
Merge branch 'forcefield-phonons' of github.com:JaGeo/atomate2 into f…
JaGeo Jul 27, 2023
71faee3
Fix more code
JaGeo Jul 27, 2023
45762a0
Fix tests
JaGeo Jul 27, 2023
1014f3c
Add gap relaxer and static evaluator
JaGeo Jul 28, 2023
2ec07a8
Linting
JaGeo Jul 28, 2023
c6c7f9b
precommit
JaGeo Jul 28, 2023
f05628a
precommit
JaGeo Jul 28, 2023
29fab75
precommit
JaGeo Jul 28, 2023
0c675bd
precommit
JaGeo Jul 28, 2023
66cd6be
precommit
JaGeo Jul 28, 2023
f341960
precommit
JaGeo Jul 28, 2023
dc54b1a
Fix precommit
JaGeo Jul 28, 2023
6673af8
Add tests for GAP jobs
JaGeo Jul 28, 2023
74d72f9
Update pyproject
JaGeo Jul 28, 2023
7f61206
fix doc
JaGeo Jul 28, 2023
abea19b
precommit
JaGeo Jul 28, 2023
05237a3
precommit
JaGeo Jul 28, 2023
027257c
precommit
JaGeo Jul 28, 2023
b615a0d
precommit
JaGeo Jul 28, 2023
8c0ab2a
Update schemas.py
JaGeo Jul 29, 2023
bff9228
Merge branch 'forcefield-phonons' of https://github.com/JaGeo/atomate…
Jul 31, 2023
bbe3d41
add structure list to datastore
JaGeo Aug 4, 2023
59c4efc
Merge branch 'forcefield-phonons' of github.com:JaGeo/atomate2 into f…
JaGeo Aug 4, 2023
a761a95
Merge branch 'main' of https://github.com/materialsproject/atomate2 i…
JaGeo Aug 4, 2023
bf8e2e4
linting
JaGeo Aug 4, 2023
28abdf6
Merge pull request #4 from JaGeo/forcefield-phonons
QuantumChemist Aug 7, 2023
565959a
minor edit
QuantumChemist Aug 7, 2023
21b4fc6
Merge branch 'main' into forcefield-phonons
JaGeo Aug 7, 2023
f66438f
fix format
JaGeo Aug 7, 2023
cd69212
Merge pull request #5 from JaGeo/forcefield-phonons
QuantumChemist Aug 9, 2023
9501fb1
Merge pull request #6 from QuantumChemist/phononforcefield
JaGeo Aug 9, 2023
af4af8e
Empty commit
JaGeo Aug 9, 2023
ec5c6be
adjusted some small things
QuantumChemist Aug 10, 2023
7b0b5e6
remove structure output to avoid overflowing json
JaGeo Aug 10, 2023
465ccac
Merge branch 'forcefield-phonons' of github.com:JaGeo/atomate2 into f…
JaGeo Aug 10, 2023
326b7f8
fix linting
JaGeo Aug 10, 2023
e1a34e2
Merge pull request #7 from QuantumChemist/phononforcefield
JaGeo Aug 11, 2023
f6ede44
Fix linting
JaGeo Aug 11, 2023
fce25c1
Fix linting
JaGeo Aug 11, 2023
98ffa8e
Address review comments
JaGeo Aug 14, 2023
ad16092
Address merge conflicts
JaGeo Aug 14, 2023
97fcf9a
Fix linting
JaGeo Aug 14, 2023
57fa7a4
fix linting
JaGeo Aug 14, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ mp = ["mp-api>=0.27.5"]
phonons = ["phonopy>=1.10.8", "seekpath"]
lobster = ["lobsterpy>=0.3.0"]
defects = ["dscribe>=1.2.0", "pymatgen-analysis-defects>=2022.11.30"]
forcefields = ["chgnet==0.2.0", "matgl==0.8.2"]
forcefields = ["chgnet==0.2.0", "matgl==0.8.2", "quippy-ase==0.9.14"]
docs = [
"FireWorks==2.0.3",
"autodoc_pydantic==1.9.0",
Expand Down Expand Up @@ -75,6 +75,7 @@ strict = [
"pydantic==1.10.9",
"pymatgen-analysis-defects==2023.7.31",
"pymatgen==2023.8.10",
"quippy-ase==0.9.14",
"seekpath==2.1.0",
"typing-extensions==4.7.1",
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,33 @@

from __future__ import annotations

import contextlib
import logging
from dataclasses import dataclass, field
from typing import TYPE_CHECKING

from jobflow import Flow, Response, job
from phonopy import Phonopy
from phonopy.units import VaspToTHz
from pymatgen.core import Structure
from pymatgen.io.phonopy import get_phonopy_structure, get_pmg_structure
from pymatgen.phonon.bandstructure import PhononBandStructureSymmLine
from pymatgen.phonon.dos import PhononDos
from pymatgen.transformations.advanced_transformations import (
CubicSupercellTransformation,
)

from atomate2.common.schemas.phonons import ForceConstants, PhononBSDOSDoc
from atomate2.vasp.jobs.base import BaseVaspMaker
from atomate2.vasp.schemas.phonons import PhononBSDOSDoc
from atomate2.vasp.sets.core import StaticSetGenerator

if TYPE_CHECKING:
from pathlib import Path

import numpy as np
from emmet.core.math import Matrix3D
from pymatgen.core import Structure

from atomate2.forcefields.jobs import ForceFieldStaticMaker

Check warning on line 31 in src/atomate2/common/jobs/phonons.py

View check run for this annotation

Codecov / codecov/patch

src/atomate2/common/jobs/phonons.py#L31

Added line #L31 was not covered by tests
from atomate2.vasp.sets.base import VaspInputGenerator

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -124,7 +126,7 @@
return transformation.transformation_matrix.tolist()


@job
@job(data=[Structure])
def generate_phonon_displacements(
structure: Structure,
supercell_matrix: np.array,
Expand Down Expand Up @@ -185,7 +187,10 @@
return [get_pmg_structure(cell) for cell in supercells]


@job(output_schema=PhononBSDOSDoc, data=[PhononDos, PhononBandStructureSymmLine])
@job(
output_schema=PhononBSDOSDoc,
data=[PhononDos, PhononBandStructureSymmLine, ForceConstants],
)
def generate_frequencies_eigenvectors(
structure: Structure,
supercell_matrix: np.array,
Expand Down Expand Up @@ -251,12 +256,12 @@
)


@job
@job(data=["forces", "displaced_structures"])
def run_phonon_displacements(
displacements,
structure: Structure,
supercell_matrix,
phonon_maker: BaseVaspMaker = None,
phonon_maker: BaseVaspMaker | ForceFieldStaticMaker = None,
prev_vasp_dir: str | Path = None,
):
"""
Expand All @@ -268,7 +273,7 @@
----------
displacements
structure: Structure object
Fully optimized structure used for phonon computations
Fully optimized structure used for phonon computations.
supercell_matrix: Matrix3D
supercell matrix for meta data
phonon_maker : .BaseVaspMaker
Expand All @@ -284,11 +289,13 @@
"forces": [],
"uuids": [],
"dirs": [],
"displaced_structures": [],
}

for i, displacement in enumerate(displacements):
phonon_job = phonon_maker.make(displacement, prev_vasp_dir=prev_vasp_dir)
if prev_vasp_dir is not None:
phonon_job = phonon_maker.make(displacement, prev_vasp_dir=prev_vasp_dir)
else:
phonon_job = phonon_maker.make(displacement)
phonon_job.append_name(f" {i + 1}/{len(displacements)}")

# we will add some meta data
Expand All @@ -298,15 +305,17 @@
"supercell_matrix": supercell_matrix,
"displaced_structure": displacement,
}
phonon_job.update_maker_kwargs(
{"_set": {"write_additional_data->phonon_info:json": info}}, dict_mod=True
)
with contextlib.suppress(Exception):
phonon_job.update_maker_kwargs(
{"_set": {"write_additional_data->phonon_info:json": info}},
dict_mod=True,
)

phonon_jobs.append(phonon_job)
outputs["displacement_number"].append(i)
outputs["uuids"].append(phonon_job.output.uuid)
outputs["dirs"].append(phonon_job.output.dir_name)
outputs["forces"].append(phonon_job.output.output.forces)
outputs["displaced_structures"].append(displacement)

displacement_flow = Flow(phonon_jobs, outputs)
return Response(replace=displacement_flow)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import numpy as np
from emmet.core.math import Matrix3D
from monty.json import MSONable
from phonopy import Phonopy
from phonopy.phonon.band_structure import get_band_qpoints_and_path_connections
from phonopy.structure.symmetry import symmetrize_borns_and_epsilon
Expand Down Expand Up @@ -80,19 +81,26 @@
born_run_uuid: str = Field(None, description="born run uuid")


class ForceConstants(MSONable):
"""A force constants class."""

def __init__(self, force_constants: List[List[Matrix3D]]):
self.force_constants = force_constants


class PhononJobDirs(BaseModel):
"""Collection to save all job directories relevant for the phonon run."""

displacements_job_dirs: List[str] = Field(
displacements_job_dirs: List[Optional[str]] = Field(
None, description="The directories where the displacement jobs were run."
)
static_run_job_dir: str = Field(
static_run_job_dir: Optional[str] = Field(
None, description="Directory where static run was performed."
)
born_run_job_dir: str = Field(
born_run_job_dir: Optional[str] = Field(
None, description="Directory where born run was performed."
)
optimization_run_job_dir: str = Field(
optimization_run_job_dir: Optional[str] = Field(
None, description="Directory where optimization run was performed."
)

Expand Down Expand Up @@ -152,7 +160,7 @@
)

# needed, e.g. to compute Grueneisen parameter etc
force_constants: List[List[Matrix3D]] = Field(
force_constants: ForceConstants = Field(
None, description="Force constants between every pair of atoms in the structure"
)

Expand Down Expand Up @@ -181,7 +189,9 @@
"Includes all data of the computation of the thermal displacements"
)

jobdirs: PhononJobDirs = Field("Field including all relevant job directories")
jobdirs: Optional[PhononJobDirs] = Field(
"Field including all relevant job directories"
)

uuids: PhononUUIDs = Field("Field including all relevant uuids")

Expand Down Expand Up @@ -223,7 +233,7 @@
code: str
which code was used for computation
displacement_data:
output of the VASP displacement data
output of the VASP displacement runs
total_dft_energy: float
total energy in eV per cell
epsilon_static: Matrix3D
Expand Down Expand Up @@ -258,7 +268,6 @@
)
phonon.generate_displacements(distance=displacement)
set_of_forces = [np.array(forces) for forces in displacement_data["forces"]]

if born is not None and epsilon_static is not None:
if len(structure) == len(born):
borns, epsilon = symmetrize_borns_and_epsilon(
Expand Down Expand Up @@ -305,8 +314,13 @@

# phonon band structures will always be cmouted
filename_band_yaml = "phonon_band_structure.yaml"

# TODO: potentially add kwargs to avoid computation of eigenvectors
phonon.run_band_structure(
qpoints, path_connections=connections, with_eigenvectors=True
qpoints,
path_connections=connections,
with_eigenvectors=kwargs.get("band_structure_eigenvectors", False),
is_band_connection=kwargs.get("band_structure_eigenvectors", False),
)
phonon.write_yaml_band_structure(filename=filename_band_yaml)
bs_symm_line = get_ph_bs_symm_line(
Expand All @@ -326,7 +340,8 @@
)

# gets data for visualization on website - yaml is also enough
bs_symm_line.write_phononwebsite("phonon_website.json")
if kwargs.get("band_structure_eigenvectors", False):
bs_symm_line.write_phononwebsite("phonon_website.json")

Check warning on line 344 in src/atomate2/common/schemas/phonons.py

View check run for this annotation

Codecov / codecov/patch

src/atomate2/common/schemas/phonons.py#L344

Added line #L344 was not covered by tests

# get phonon density of states
filename_dos_yaml = "phonon_dos.yaml"
Expand Down Expand Up @@ -381,7 +396,7 @@
# will compute thermal displacement matrices
# for the primitive cell (phonon.primitive!)
# only this is available in phonopy
if kwargs["create_thermal_displacements"]:
if kwargs.get("create_thermal_displacements", False):
phonon.run_mesh(
kpoint.kpts[0], with_eigenvectors=True, is_mesh_symmetry=False
)
Expand Down Expand Up @@ -438,7 +453,7 @@
temperatures=temperature_range.tolist(),
total_dft_energy=total_dft_energy_per_formula_unit,
has_imaginary_modes=imaginary_modes,
force_constants=phonon.force_constants.tolist()
force_constants={"force_constants": phonon.force_constants.tolist()}
if kwargs["store_force_constants"]
else None,
born=borns.tolist() if borns is not None else None,
Expand All @@ -452,7 +467,7 @@
"thermal_displacement_matrix": tdisp_mat,
"freq_min_thermal_displacements": freq_min_thermal_displacements,
}
if kwargs["create_thermal_displacements"]
if kwargs.get("create_thermal_displacements", False)
else None,
jobdirs={
"displacements_job_dirs": displacement_data["dirs"],
Expand Down
1 change: 1 addition & 0 deletions src/atomate2/forcefields/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Tools and functions common to all forcefields."""
2 changes: 2 additions & 0 deletions src/atomate2/forcefields/flows/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"""Flows for forcefields."""
from .relax import CHGNetVaspRelaxMaker, M3GNetVaspRelaxMaker
Loading
Loading