Skip to content

Commit

Permalink
Merge pull request #23 from JaGeo/adapted_static_maker
Browse files Browse the repository at this point in the history
add adapted makers
  • Loading branch information
JaGeo authored Jan 28, 2024
2 parents 2159ba8 + a95e1b4 commit e9f22e3
Show file tree
Hide file tree
Showing 7 changed files with 335 additions and 61 deletions.
57 changes: 33 additions & 24 deletions autoplex/auto/flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,11 @@ def make(
)
flows.append(add_data_fit)

bm_outputs=[]
bm_outputs = []

for ibenchmark_structure, benchmark_structure in enumerate(benchmark_structures):
for ibenchmark_structure, benchmark_structure in enumerate(
benchmark_structures
):
# not sure if it would make sense to put everything from here in its own flow?
add_data_ml_phonon = get_phonon_ml_calculation_jobs(
structure=benchmark_structure,
Expand All @@ -163,29 +165,36 @@ def make(
flows.append(add_data_ml_phonon)

if dft_references is None and benchmark_mp_ids is not None:
if (benchmark_mp_ids[ibenchmark_structure] in mp_ids) and self.add_dft_phonon_struct:
dft_references = fit_input[benchmark_mp_ids[ibenchmark_structure]]["phonon_data"]["001"]
elif (benchmark_mp_ids[ibenchmark_structure] not in mp_ids) or ( # else?
self.add_dft_phonon_struct is False
):
dft_phonons = DFTPhononMaker(
symprec=self.symprec,
phonon_displacement_maker=self.phonon_displacement_maker,
born_maker=None,
min_length=self.min_length,
).make(structure=benchmark_structure)
dft_phonons = update_user_incar_settings(
dft_phonons, {"NPAR": 4, "ISPIN": 1, "LAECHG": False, "ISMEAR": 0}
)
flows.append(dft_phonons)
dft_references = dft_phonons.output

add_data_bm = PhononDFTMLBenchmarkFlow(name="addDataBM").make(
structure=benchmark_structure,
benchmark_mp_id=benchmark_mp_ids[ibenchmark_structure],
ml_phonon_task_doc=add_data_ml_phonon.output,
dft_phonon_task_doc=dft_references,
if (
benchmark_mp_ids[ibenchmark_structure] in mp_ids
) and self.add_dft_phonon_struct:
dft_references = fit_input[benchmark_mp_ids[ibenchmark_structure]][
"phonon_data"
]["001"]
elif (
benchmark_mp_ids[ibenchmark_structure] not in mp_ids
) or ( # else?
self.add_dft_phonon_struct is False
):
dft_phonons = DFTPhononMaker(
symprec=self.symprec,
phonon_displacement_maker=self.phonon_displacement_maker,
born_maker=None,
min_length=self.min_length,
).make(structure=benchmark_structure)
dft_phonons = update_user_incar_settings(
dft_phonons,
{"NPAR": 4, "ISPIN": 1, "LAECHG": False, "ISMEAR": 0},
)
flows.append(dft_phonons)
dft_references = dft_phonons.output

add_data_bm = PhononDFTMLBenchmarkFlow(name="addDataBM").make(
structure=benchmark_structure,
benchmark_mp_id=benchmark_mp_ids[ibenchmark_structure],
ml_phonon_task_doc=add_data_ml_phonon.output,
dft_phonon_task_doc=dft_references,
)
else:
add_data_bm = PhononDFTMLBenchmarkFlow(name="addDataBM").make(
structure=benchmark_structure,
Expand Down
152 changes: 150 additions & 2 deletions autoplex/auto/jobs.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
"""General AutoPLEX automation jobs."""
from __future__ import annotations

from dataclasses import dataclass, field
from typing import TYPE_CHECKING

from atomate2.forcefields.flows.phonons import PhononMaker
from atomate2.forcefields.jobs import GAPRelaxMaker, GAPStaticMaker
from atomate2.forcefields.jobs import (
ForceFieldRelaxMaker,
ForceFieldStaticMaker,
GAPRelaxMaker,
GAPStaticMaker,
)
from atomate2.vasp.flows.phonons import PhononMaker as DFTPhononMaker
from atomate2.vasp.powerups import (
update_user_incar_settings,
Expand All @@ -17,7 +23,149 @@

from autoplex.data.flows import IsoAtomMaker, RandomStructuresDataGenerator

# This should be a maker rather than a job in a job

@dataclass
class MLPhononMaker(PhononMaker):
"""
Maker to calculate harmonic phonons with a force field.
Calculate the harmonic phonons of a material. Initially, a tight structural
relaxation is performed to obtain a structure without forces on the atoms.
Subsequently, supercells with one displaced atom are generated and accurate
forces are computed for these structures. With the help of phonopy, these
forces are then converted into a dynamical matrix. To correct for polarization
effects, a correction of the dynamical matrix based on BORN charges can
be performed. The BORN charges can be supplied manually.
Finally, phonon densities of states, phonon band structures
and thermodynamic properties are computed.
.. Note::
It is heavily recommended to symmetrize the structure before passing it to
this flow. Otherwise, a different space group might be detected and too
many displacement calculations will be generated.
It is recommended to check the convergence parameters here and
adjust them if necessary. The default might not be strict enough
for your specific case.
Parameters
----------
name : str
Name of the flows produced by this maker.
sym_reduce : bool
Whether to reduce the number of deformations using symmetry.
symprec : float
Symmetry precision to use in the
reduction of symmetry to find the primitive/conventional cell
(use_primitive_standard_structure, use_conventional_standard_structure)
and to handle all symmetry-related tasks in phonopy
displacement: float
displacement distance for phonons
min_length: float
min length of the supercell that will be built
prefer_90_degrees: bool
if set to True, supercell algorithm will first try to find a supercell
with 3 90 degree angles
get_supercell_size_kwargs: dict
kwargs that will be passed to get_supercell_size to determine supercell size
use_symmetrized_structure: str
allowed strings: "primitive", "conventional", None
- "primitive" will enforce to start the phonon computation
from the primitive standard structure
according to Setyawan, W., & Curtarolo, S. (2010).
High-throughput electronic band structure calculations:
Challenges and tools. Computational Materials Science,
49(2), 299-312. doi:10.1016/j.commatsci.2010.05.010.
This makes it possible to use certain k-path definitions
with this workflow. Otherwise, we must rely on seekpath
- "conventional" will enforce to start the phonon computation
from the conventional standard structure
according to Setyawan, W., & Curtarolo, S. (2010).
High-throughput electronic band structure calculations:
Challenges and tools. Computational Materials Science,
49(2), 299-312. doi:10.1016/j.commatsci.2010.05.010.
We will however use seekpath and primitive structures
as determined by from phonopy to compute the phonon band structure
bulk_relax_maker : .ForceFieldRelaxMaker or None
A maker to perform a tight relaxation on the bulk.
Set to ``None`` to skip the
bulk relaxation
static_energy_maker : .ForceFieldStaticMaker or None
A maker to perform the computation of the DFT energy on the bulk.
Set to ``None`` to skip the
static energy computation
phonon_displacement_maker : .ForceFieldStaticMaker or None
Maker used to compute the forces for a supercell.
generate_frequencies_eigenvectors_kwargs : dict
Keyword arguments passed to :obj:`generate_frequencies_eigenvectors`.
create_thermal_displacements: bool
Bool that determines if thermal_displacement_matrices are computed
kpath_scheme: str
scheme to generate kpoints. Please be aware that
you can only use seekpath with any kind of cell
Otherwise, please use the standard primitive structure
Available schemes are:
"seekpath", "hinuma", "setyawan_curtarolo", "latimer_munro".
"seekpath" and "hinuma" are the same definition but
seekpath can be used with any kind of unit cell as
it relies on phonopy to handle the relationship
to the primitive cell and not pymatgen
code: str
determines the DFT code. currently only vasp is implemented.
This keyword might enable the implementation of other codes
in the future
store_force_constants: bool
if True, force constants will be stored
"""

ml_dir: str = field(default="gapfit.xml")
min_length: float | None = 20.0
bulk_relax_maker: ForceFieldRelaxMaker | None = field(
default_factory=lambda: GAPRelaxMaker(
relax_cell=True, relax_kwargs={"interval": 500}
)
)
phonon_displacement_maker: ForceFieldStaticMaker | None = field(
default_factory=lambda: GAPStaticMaker()
)
static_energy_maker: ForceFieldStaticMaker | None = field(
default_factory=lambda: GAPStaticMaker()
)
store_force_constants: bool = False
generate_frequencies_eigenvectors_kwargs: dict = field(
default_factory=lambda: {"units": "THz"}
)
relax_maker_kwargs: dict = field(default_factory=dict)
static_maker_kwargs: dict = field(default_factory=dict)

def __post_init__(self):
"""Update potential file path and keyword args if any."""
if self.bulk_relax_maker is not None:
br = self.bulk_relax_maker
self.bulk_relax_maker = br.update_kwargs(
update={
"potential_param_file_name": self.ml_dir,
**self.relax_maker_kwargs,
}
)
if self.phonon_displacement_maker is not None:
ph_disp = self.phonon_displacement_maker
self.phonon_displacement_maker = ph_disp.update_kwargs(
update={
"potential_param_file_name": self.ml_dir,
**self.static_maker_kwargs,
}
)
if self.static_energy_maker is not None:
stat_en = self.static_energy_maker
self.static_energy_maker = stat_en.update_kwargs(
update={
"potential_param_file_name": self.ml_dir,
**self.static_maker_kwargs,
}
)


@job
def get_phonon_ml_calculation_jobs(
ml_dir: str,
Expand Down
1 change: 0 additions & 1 deletion autoplex/benchmark/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ def compute_bandstructure_benchmark_metrics(
ml_bs=ml_phonon_bs,
dft_bs=dft_phonon_bs,
file_name=file_name,
img_format="eps",
)

return Response(output=overall_rmse) # TODO TaskDoc
Expand Down
7 changes: 2 additions & 5 deletions autoplex/benchmark/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,7 @@ def rmse_kdep_plot(
def compare_plot(
ml_bs: PhononBandStructureSymmLine,
dft_bs: PhononBandStructureSymmLine,
file_name="band_comparison.eps",
img_format="eps",
file_name: str = "band_comparison.eps",
):
"""
Save DFT and ML phonon band-structure overlay plot for visual comparison.
Expand All @@ -106,8 +105,6 @@ def compare_plot(
DFT generated pymatgen phonon band-structure object
file_name: str.
Name of the saved plot
img_format: str
File extension of plot to be saved, default is eps
Returns
-------
Expand All @@ -117,6 +114,6 @@ def compare_plot(
plotter = PhononBSPlotter(bs=ml_bs)
plotter2 = PhononBSPlotter(bs=dft_bs)
new_plotter = plotter.plot_compare(plotter2)
new_plotter.figure.savefig(file_name, format=img_format)
new_plotter.figure.savefig(file_name)

return new_plotter.figure
96 changes: 96 additions & 0 deletions autoplex/data/flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

if TYPE_CHECKING:
from atomate2.vasp.jobs.base import BaseVaspMaker
from atomate2.vasp.sets.base import VaspInputGenerator
from emmet.core.math import Matrix3D
from pymatgen.core.structure import Species, Structure
from atomate2.common.jobs.phonons import (
Expand All @@ -28,6 +29,100 @@
__all__ = ["RandomStructuresDataGenerator", "IsoAtomMaker"]


@dataclass
class TightDFTStaticMaker(PhononDisplacementMaker):
"""Adapted phonon displacement maker for static calculation.
The input set used is same as PhononDisplacementMaker.
Only difference is Spin polarization is switched off and Gaussian smearing is used
Parameters
----------
name : str
The job name.
input_set_generator : .VaspInputGenerator
A generator used to make the input set.
write_input_set_kwargs : dict
Keyword arguments that will get passed to :obj:`.write_vasp_input_set`.
copy_vasp_kwargs : dict
Keyword arguments that will get passed to :obj:`.copy_vasp_outputs`.
run_vasp_kwargs : dict
Keyword arguments that will get passed to :obj:`.run_vasp`.
task_document_kwargs : dict
Keyword arguments that will get passed to :obj:`.TaskDoc.from_directory`.
stop_children_kwargs : dict
Keyword arguments that will get passed to :obj:`.should_stop_children`.
write_additional_data : dict
Additional data to write to the current directory. Given as a dict of
{filename: data}. Note that if using FireWorks, dictionary keys cannot contain
the "." character which is typically used to denote file extensions. To avoid
this, use the ":" character, which will automatically be converted to ".". E.g.
``{"my_file:txt": "contents of the file"}``.
"""

input_set_generator: VaspInputGenerator = field(
default_factory=lambda: StaticSetGenerator(
user_kpoints_settings={"reciprocal_density": 100},
user_incar_settings={
"IBRION": 2,
"ISPIN": 1,
"ISMEAR": 0,
"ISIF": 3,
"ENCUT": 700,
"EDIFF": 1e-7,
"LAECHG": False,
"LREAL": False,
"ALGO": "Normal",
"NSW": 0,
"LCHARG": False,
},
auto_ispin=False,
)
)


@dataclass
class IsoAtomStaticMaker(StaticMaker):
"""
Maker to create Isolated atoms static jobs.
Parameters
----------
name : str
The job name.
input_set_generator : .VaspInputGenerator
A generator used to make the input set.
write_input_set_kwargs : dict
Keyword arguments that will get passed to :obj:`.write_vasp_input_set`.
copy_vasp_kwargs : dict
Keyword arguments that will get passed to :obj:`.copy_vasp_outputs`.
run_vasp_kwargs : dict
Keyword arguments that will get passed to :obj:`.run_vasp`.
task_document_kwargs : dict
Keyword arguments that will get passed to :obj:`.TaskDoc.from_directory`.
stop_children_kwargs : dict
Keyword arguments that will get passed to :obj:`.should_stop_children`.
write_additional_data : dict
Additional data to write to the current directory. Given as a dict of
{filename: data}. Note that if using FireWorks, dictionary keys cannot contain
the "." character which is typically used to denote file extensions. To avoid
this, use the ":" character, which will automatically be converted to ".". E.g.
``{"my_file:txt": "contents of the file"}``.
"""

name: str = "static"
input_set_generator: VaspInputGenerator = field(
default_factory=lambda: StaticSetGenerator(
user_kpoints_settings={"reciprocal_density": 1},
user_incar_settings={
"ISPIN": 1,
"LAECHG": False,
"ISMEAR": 0,
},
)
)


@dataclass
class RandomStructuresDataGenerator(Maker):
"""
Expand Down Expand Up @@ -163,6 +258,7 @@ def make(self, all_species: list[Species]):
user_kpoints_settings={"grid_density": 1},
),
).make(iso_atom)

isoatom_calcs = update_user_incar_settings(
isoatom_calcs,
{"NPAR": 4, "ISPIN": 1, "LAECHG": False, "ISMEAR": 0},
Expand Down
Loading

0 comments on commit e9f22e3

Please sign in to comment.