-
Notifications
You must be signed in to change notification settings - Fork 101
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
VASP/Phonopy Phonon Workflow #137
Changes from 4 commits
4c898a5
28f8b43
56b0643
c707bd3
63f338d
ce74c41
b113c70
762c86c
4aac6c1
02e3a8d
39aa228
26fe95b
3af674b
393d287
92e1bf8
b9a8eae
2bbe493
23ac9c4
56076a4
acf2732
c55ce30
64952df
e019110
3eca76a
5bc1ece
0c60d63
33a01e5
bc42d03
b8ff4db
faf4b4c
7cd525f
55a4ec7
2833caf
ee40f85
abbcca4
aef6006
091e366
7f38751
3086982
c506b03
0b31cdf
0549052
3b55be2
b4b685a
2806b3b
f13ffce
c5375a5
98bcc48
b345293
925f4c8
68c64aa
4426a82
67d120f
c2841d8
05f4ea5
6b47048
cfb7255
a5d570c
67d7c9a
98fd063
0cf7937
8708677
dbdad2c
70b05fe
0d67c62
94b341c
1e01005
52ad56c
10aa4a0
724a471
4a44736
7fc36d4
50793f9
131a1ae
514eb16
9a4e98c
faf9515
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,163 @@ | ||||||||||
"""Flows for calculating elastic constants.""" | ||||||||||
|
||||||||||
from __future__ import annotations | ||||||||||
|
||||||||||
from dataclasses import dataclass, field | ||||||||||
from pathlib import Path | ||||||||||
|
||||||||||
from jobflow import Flow, Maker | ||||||||||
from pymatgen.core.structure import Structure | ||||||||||
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer | ||||||||||
|
||||||||||
from atomate2 import SETTINGS | ||||||||||
from atomate2.vasp.flows.core import DoubleRelaxMaker | ||||||||||
from atomate2.vasp.jobs.base import BaseVaspMaker | ||||||||||
from atomate2.vasp.jobs.core import StaticMaker | ||||||||||
from atomate2.vasp.jobs.core import TightRelaxMaker | ||||||||||
from atomate2.vasp.jobs.phonons import PhononDisplacementMaker, generate_phonon_displacements, \ | ||||||||||
run_phonon_displacements, generate_frequencies_eigenvectors | ||||||||||
from atomate2.vasp.sets.core import StaticSetGenerator | ||||||||||
|
||||||||||
__all__ = ["PhononMaker"] | ||||||||||
|
||||||||||
|
||||||||||
@dataclass | ||||||||||
class PhononMaker(Maker): | ||||||||||
""" | ||||||||||
Maker to calculate harmonic phonons with VASP and Phonopy. | ||||||||||
|
||||||||||
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. | ||||||||||
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. | ||||||||||
displacement: float | ||||||||||
displacement distance for phonons | ||||||||||
min_length: float | ||||||||||
min length of the supercell that will be build | ||||||||||
conventional: bool | ||||||||||
if true, the supercell will be built from the conventional cell and all properties will be related | ||||||||||
to the conventional cell | ||||||||||
bulk_relax_maker : .BaseVaspMaker or None | ||||||||||
A maker to perform a tight relaxation on the bulk. Set to ``None`` to skip the | ||||||||||
bulk relaxation | ||||||||||
generate_phonon_diplsacements_kwargs: dict | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will remove this and the next kwargs as they are not further used in the code. |
||||||||||
keyword arguments paseed to :oj: enerate_phonon_displacements | ||||||||||
run_phonon_displacements_kwargs : dict | ||||||||||
Keyword arguments passed to :obj:`run_phonon_displacements__kwargs`. | ||||||||||
born_maker: .BaseVaspMaker or None | ||||||||||
Maker to compute the BORN charges. | ||||||||||
phonon_displacement_maker : .BaseVaspMaker or None | ||||||||||
Maker used to compute the forces for a supercell. | ||||||||||
generate_frequencies_eigenvectors_kwargs : dict | ||||||||||
Keyword arguments passed to :obj:`generate_frequencies_eigenvectors`. | ||||||||||
""" | ||||||||||
|
||||||||||
name: str = "phonon" | ||||||||||
sym_reduce: bool = True | ||||||||||
symprec: float = SETTINGS.SYMPREC | ||||||||||
displacement: float = 0.01 | ||||||||||
min_length: float = 20.0 | ||||||||||
conventional: bool = False | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a little bit iffy about converting the structure to the primitive cell without any option to disable this. Could you turn option into something more sophisticated. E.g., something like "symmetrize" where they options could be "primitive", "conventional", None. Where None disables any structure modification. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed but then we should probably also make the computation of the band structure optional? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potentially? Although it might be possible to use the AUTO option for PRIMITIVE_AXIS to automatically align the band structure whatever input structure you use? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, true. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I know this option. Need to check. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would like to be able to use the kpath options from pymatgen. I am not sure phonopy uses the same convention for the primitive cell (actually think it does not). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have thought about it further: |
||||||||||
bulk_relax_maker: BaseVaspMaker | None = field( | ||||||||||
default_factory=lambda: DoubleRelaxMaker.from_relax_maker(TightRelaxMaker()) | ||||||||||
) | ||||||||||
# is the generaor here correct? | ||||||||||
static_energy_maker: BaseVaspMaker | None = field(default_factory=StaticSetGenerator) | ||||||||||
generate_phonon_displacements_kwargs: dict = field(default_factory=dict) | ||||||||||
run_phonon_displacements_kwargs: dict = field(default_factory=dict) | ||||||||||
born_maker: BaseVaspMaker = field(default_factory=StaticSetGenerator) | ||||||||||
phonon_displacement_maker: BaseVaspMaker = field(default_factory=PhononDisplacementMaker) | ||||||||||
generate_frequencies_eigenvectors_kwargs: dict = field(default_factory=dict) | ||||||||||
|
||||||||||
def make( | ||||||||||
self, | ||||||||||
structure: Structure, | ||||||||||
prev_vasp_dir: str | Path | None = None, | ||||||||||
): | ||||||||||
""" | ||||||||||
Make flow to calculate the elastic constant. | ||||||||||
|
||||||||||
Parameters | ||||||||||
---------- | ||||||||||
structure : .Structure | ||||||||||
A pymatgen structure. | ||||||||||
prev_vasp_dir : str or Path or None | ||||||||||
A previous vasp calculation directory to use for copying outputs. | ||||||||||
""" | ||||||||||
jobs = [] | ||||||||||
|
||||||||||
# convert to primitive cell | ||||||||||
sga = SpacegroupAnalyzer(structure, symprec=self.symprec) | ||||||||||
structure = sga.get_primitive_standard_structure() | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The make function should be designed so that it accepts OutputReferences as well as the actual structure objects. This allows you to use the Maker in the middle of a flow. E.g. initial_relax_job = MyCustomRelaxMaker().make(structure)
phonon_flow = PhononMaker().make(initial_relax_job.output.structure) The way the workflow is currently written, this will fail as The way around this is doing everything that actually needs the real objects inside a job. E.g., you should make a new job that just converts the structure to the primitive cell and returns that. Something like: @job
def structure_to_primitive(structure, symprec):
sga = SpacegroupAnalyzer(structure, symprec=symprec)
return sga.get_primitive_standard_structure() And then inside the make function:
Suggested change
|
||||||||||
|
||||||||||
if self.bulk_relax_maker is not None: | ||||||||||
# optionally relax the structure | ||||||||||
bulk = self.bulk_relax_maker.make(structure, prev_vasp_dir=prev_vasp_dir) | ||||||||||
jobs.append(bulk) | ||||||||||
structure = bulk.output.structure | ||||||||||
if self.conventional: | ||||||||||
sga = SpacegroupAnalyzer(structure, symprec=self.symprec) | ||||||||||
structure = sga.get_conventional_standard_structure() | ||||||||||
|
||||||||||
# generate the displacements | ||||||||||
displacements = generate_phonon_displacements(structure=structure, symprec=self.symprec, | ||||||||||
sym_reduce=self.sym_reduce, displacement=self.displacement, | ||||||||||
min_length=self.min_length, | ||||||||||
conventional=self.conventional, | ||||||||||
**self.generate_phonon_displacements_kwargs) | ||||||||||
jobs.append(displacements) | ||||||||||
|
||||||||||
# perform the phonon displacement calculations | ||||||||||
vasp_displacement_calcs = run_phonon_displacements(displacements.output, | ||||||||||
phonon_maker=self.phonon_displacement_maker, | ||||||||||
**self.run_phonon_displacements_kwargs) | ||||||||||
jobs.append(vasp_displacement_calcs) | ||||||||||
|
||||||||||
# Computation of BORN charges | ||||||||||
if self.born_maker is None: | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have two comments about this point:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for pointing this out. I will add this option by using |
||||||||||
self.born_maker = StaticSetGenerator(lepsilon=True) | ||||||||||
if not self.born_maker.lepsilon: | ||||||||||
raise ValueError("born_maker must include lepsilon=True") | ||||||||||
born_job = StaticMaker(input_set_generator=self.born_maker).make(structure=structure) | ||||||||||
jobs.append(born_job) | ||||||||||
|
||||||||||
# Computation of BORN charges | ||||||||||
if self.static_energy_maker is None: | ||||||||||
self.static_energy_maker = StaticSetGenerator(lepsilon=True) | ||||||||||
static_job = StaticMaker(input_set_generator=self.static_energy_maker).make(structure=structure) | ||||||||||
jobs.append(static_job) | ||||||||||
|
||||||||||
# Currently we access forces via filepathes to avoid large data transfer | ||||||||||
|
||||||||||
phonon_collect = generate_frequencies_eigenvectors(structure=structure, | ||||||||||
displacement_data=vasp_displacement_calcs.output, | ||||||||||
symprec=self.symprec, sym_reduce=self.sym_reduce, | ||||||||||
displacement=self.displacement, | ||||||||||
min_length=self.min_length, | ||||||||||
conventional=self.conventional, | ||||||||||
born_data=born_job.output.dir_name, | ||||||||||
total_energy=static_job.output.output.energy, | ||||||||||
**self.generate_frequencies_eigenvectors_kwargs) | ||||||||||
jobs.append(phonon_collect) | ||||||||||
# # create a flow including all jobs for a phonon computation | ||||||||||
my_flow = Flow(jobs, phonon_collect.output) | ||||||||||
return my_flow |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.