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

VASP/Phonopy Phonon Workflow #137

Merged
merged 77 commits into from
Sep 6, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
4c898a5
first rough implemenation phonon workflow
JaGeo May 16, 2022
28f8b43
Further additions to free energy part
JaGeo May 18, 2022
56b0643
add more flexibility
JaGeo May 20, 2022
c707bd3
further fixes along the workflow
JaGeo May 23, 2022
63f338d
make born optional and precommit
JaGeo May 30, 2022
ce74c41
switch to transfer via output
JaGeo May 31, 2022
b113c70
pass precommit
JaGeo Jun 9, 2022
762c86c
fixes
JaGeo Jun 9, 2022
4aac6c1
more bug fixing and typo removal
JaGeo Jun 10, 2022
02e3a8d
Fix born charge bug
JaGeo Jun 10, 2022
39aa228
new PhononBSDoc and inclusion of thermal matrices
JaGeo Jun 17, 2022
26fe95b
Fix parameters
JaGeo Jul 7, 2022
3af674b
Fix kwargs
JaGeo Jul 7, 2022
393d287
Fix failures
JaGeo Jul 7, 2022
92e1bf8
precommit
JaGeo Aug 3, 2022
b9a8eae
clean up document
JaGeo Aug 3, 2022
2bbe493
Fix thermal displacement computation
JaGeo Aug 5, 2022
23ac9c4
Merge branch 'main' of github.com:materialsproject/atomate2
JaGeo Aug 5, 2022
56076a4
Add different supercell algorithm
JaGeo Aug 6, 2022
acf2732
Clean up documentation
JaGeo Aug 10, 2022
c55ce30
Merge branch 'main' of github.com:materialsproject/atomate2
JaGeo Aug 27, 2022
64952df
review comments
JaGeo Aug 27, 2022
e019110
Fix symmetrized structure
JaGeo Aug 28, 2022
3eca76a
Fix further side effects
JaGeo Aug 29, 2022
5bc1ece
Fixing some logic
JaGeo Aug 29, 2022
0c60d63
resolve pyproject toml
JaGeo Aug 30, 2022
33a01e5
Update documentation according to review suggestions
JaGeo Aug 30, 2022
bc42d03
commit renaming as suggestion by review
JaGeo Aug 30, 2022
b8ff4db
move to kwargs
JaGeo Aug 30, 2022
faf4b4c
move more to kwargs
JaGeo Aug 30, 2022
7cd525f
Fix formatting of comment
JaGeo Aug 30, 2022
55a4ec7
Update documentation
JaGeo Aug 30, 2022
2833caf
fix parameter
JaGeo Aug 30, 2022
ee40f85
Fix missing parameter
JaGeo Aug 30, 2022
abbcca4
Fix kwarg implementation
JaGeo Aug 30, 2022
aef6006
correct kwargs passing again
JaGeo Aug 30, 2022
091e366
Fix total_dft_energy
JaGeo Aug 30, 2022
7f38751
Fix total_dft_energy
JaGeo Aug 30, 2022
3086982
Fix further side effect kwargs
JaGeo Aug 30, 2022
c506b03
hopefully last side effects kwargs
JaGeo Aug 30, 2022
0b31cdf
fix type error
JaGeo Aug 30, 2022
0549052
fix type error2
JaGeo Aug 30, 2022
3b55be2
Fix pydantic error
JaGeo Aug 30, 2022
b4b685a
Add first two tests and remove inconsistencies
JaGeo Aug 31, 2022
2806b3b
fix kpath schemes
JaGeo Aug 31, 2022
f13ffce
change total_dft_energy to energy per formula unit
JaGeo Aug 31, 2022
c5375a5
add test of supply born, epsilon
JaGeo Aug 31, 2022
98bcc48
add more outputs phonopy
JaGeo Aug 31, 2022
b345293
Add more cell definitions
JaGeo Aug 31, 2022
925f4c8
Change default number of free energies
JaGeo Aug 31, 2022
68c64aa
add complete run
JaGeo Aug 31, 2022
4426a82
test commit
JaGeo Sep 1, 2022
67d120f
add last test
JaGeo Sep 2, 2022
c2841d8
Fix test names
JaGeo Sep 2, 2022
05f4ea5
fix documentation
JaGeo Sep 2, 2022
6b47048
Update structures
JaGeo Sep 2, 2022
cfb7255
Fix docstring
JaGeo Sep 2, 2022
a5d570c
Fix docstring
JaGeo Sep 2, 2022
67d7c9a
More docstring fixes
JaGeo Sep 2, 2022
98fd063
Fix doc
JaGeo Sep 2, 2022
0cf7937
change test workflow
JaGeo Sep 2, 2022
8708677
add it to correct workflow
JaGeo Sep 2, 2022
dbdad2c
Add seekpath
JaGeo Sep 2, 2022
70b05fe
Update src/atomate2/vasp/flows/phonons.py
JaGeo Sep 5, 2022
0d67c62
Remove useless lines from test
JaGeo Sep 5, 2022
94b341c
Merge branch 'main' of github.com:JaGeo/atomate2
JaGeo Sep 5, 2022
1e01005
Update installation and test config
JaGeo Sep 5, 2022
52ad56c
Fix first documentation issues
JaGeo Sep 5, 2022
10aa4a0
Move functions to common
JaGeo Sep 5, 2022
724a471
Move functions to common
JaGeo Sep 5, 2022
4a44736
extend documentation
JaGeo Sep 5, 2022
7fc36d4
Add further metadata
JaGeo Sep 5, 2022
50793f9
add further data
JaGeo Sep 5, 2022
131a1ae
One last tiny change on the documentation
JaGeo Sep 5, 2022
514eb16
add blank line
JaGeo Sep 5, 2022
9a4e98c
Add a t to hat
JaGeo Sep 5, 2022
faf9515
Fix identation issue
JaGeo Sep 5, 2022
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
Empty file.
163 changes: 163 additions & 0 deletions src/atomate2/vasp/flows/phonons.py
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
min length of the supercell that will be build
min length of the supercell that will be built

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
generate_phonon_diplsacements_kwargs: dict
generate_phonon_displacements_kwargs: dict

Copy link
Member Author

Choose a reason for hiding this comment

The 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
Copy link
Member

Choose a reason for hiding this comment

The 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.

Copy link
Member Author

Choose a reason for hiding this comment

The 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?

Copy link
Member

@utf utf Jun 8, 2022

Choose a reason for hiding this comment

The 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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, true.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I know this option. Need to check.

Copy link
Member Author

@JaGeo JaGeo Jun 8, 2022

Choose a reason for hiding this comment

The 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).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have thought about it further:
what we could do is allowing to switch to another kpath scheme than seekpath when the primitive cell in the corresponding convention is chosen for the phonon run. We could use seekpath as a default though.

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()
Copy link
Member

Choose a reason for hiding this comment

The 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 SpacegroupAnalyzer will get passed an OutputReference object.

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
sga = SpacegroupAnalyzer(structure, symprec=self.symprec)
structure = sga.get_primitive_standard_structure()
prim_job = structure_to_primitive(structure, self.symprec)
structure = prim_job.output


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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have two comments about this point:

  1. Maybe you already planned to update this later, but for how it is written now the BECs are always calculated. However there are good reasons to skip this step (e.g. metals). It would be good that None means that BECs are not calculated.
  2. with the born_maker: BaseVaspMaker = field(default_factory=StaticSetGenerator) it will enter this if only if born_maker is explicitly set to None. Also the default of the of born_maker will not include lepsilon. An option would be to define the born_maker:
    born_maker: BaseVaspMaker = field(default_factory=lambda: StaticSetGenerator(lepsilon=True))

Copy link
Member Author

Choose a reason for hiding this comment

The 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 born_maker: BaseVaspMaker |None = field(default_factory=lambda: StaticSetGenerator(lepsilon=True)) similar to what is done for the bulk_relax_maker. I was actually thinking about doing this but somehow did not completely implement this option ...

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
Loading