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 25 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
7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ classifiers = [
"Topic :: Scientific/Engineering",
]
requires-python = '>="3.8"'
dependencies = [
'pymatgen>=2022.7.8',
dependencies =[
"pymatgen>=2022.8.23",
'custodian>=2019.8.24',
"pydantic",
"monty",
Expand Down Expand Up @@ -55,7 +55,8 @@ tests = [
]
strict = [
"pydantic==1.9.0",
"pymatgen==2022.7.8",
"pymatgen==2022.8.23",
"pymatgen-analysis-defects==2022.8.24",
Copy link
Member

Choose a reason for hiding this comment

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

Please remove this! This will be an option dependency.

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

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 updated the non-strict installation part as well. I hope this is fine.

"custodian==2022.2.13",
"monty==2022.4.26",
"jobflow==0.1.8",
Expand Down
Empty file.
318 changes: 318 additions & 0 deletions src/atomate2/vasp/flows/phonons.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,318 @@
"""Flows for calculating elastic constants."""

from __future__ import annotations

from dataclasses import dataclass, field
from pathlib import Path
from typing import List

from jobflow import Flow, Maker
from pymatgen.core.structure import Structure

from atomate2.common.schemas.math import Matrix3D
from atomate2.vasp.flows.core import DoubleRelaxMaker
from atomate2.vasp.jobs.base import BaseVaspMaker
from atomate2.vasp.jobs.core import DielectricMaker, StaticMaker, TightRelaxMaker
from atomate2.vasp.jobs.phonons import (
PhononDisplacementMaker,
generate_frequencies_eigenvectors,
generate_phonon_displacements,
get_supercell_size,
run_phonon_displacements,
structure_to_conventional,
structure_to_primitive,
)

__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 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_kwargs: additional arguments
to determine supercell
Copy link
Member

Choose a reason for hiding this comment

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

This the type for this parameter is wrong, it should be dict. Also can you list the function which these parameters will be passed to. That way the user can look this function up to see what options are supported.

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
JaGeo marked this conversation as resolved.
Show resolved Hide resolved
bulk_relax_maker : .BaseVaspMaker or None
A maker to perform a tight relaxation on the bulk.
Set to ``None`` to skip the
bulk relaxation
static_energy_maker : .BaseVaspMaker or None
A maker to perform the computation of the DFT energy on the bulk.
Set to ``None`` to skip the
static energy computation
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`.
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",
"all". "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
"""

name: str = "phonon"
sym_reduce: bool = True
symprec: float = 1e-4
displacement: float = 0.01
min_length: float | None = 20.0
prefer_90_degrees: bool = True
get_supercell_size_kwargs: dict = field(default_factory=dict)
use_symmetrized_structure: str | None = None
bulk_relax_maker: BaseVaspMaker | None = field(
default_factory=lambda: DoubleRelaxMaker.from_relax_maker(TightRelaxMaker())
)
static_energy_maker: BaseVaspMaker | None = field(default_factory=StaticMaker)
born_maker: BaseVaspMaker | None = field(default_factory=DielectricMaker)
phonon_displacement_maker: BaseVaspMaker = field(
default_factory=PhononDisplacementMaker
)
create_thermal_displacements: bool = True
generate_frequencies_eigenvectors_kwargs: dict = field(default_factory=dict)
kpath_scheme: str = "seekpath"
code: str = "vasp"

def make(
self,
structure: Structure,
prev_vasp_dir: str | Path | None = None,
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 trying to think of a mechanism where you could supply the Born effective charges and epsilon_static, without needing to calculate them again if they're already available. I can imagine this would be useful if you're checking for supercell convergence.

One option is to add optional arguments to the make function which would override the born_maker.

I'll try think about this a bit more.

Copy link
Member

Choose a reason for hiding this comment

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

I guess it might also be useful to be able to specify the supercell directly, rather than relying on the automatic generation. I'll think this over more!

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 agree with you. I am also not completely happy with the CubicSupercellTransformation a the moment. It prefers similar lattice parameters over 90 degree angles and I am not really sure this is optimal for these kind of phonon computations.

Copy link
Member

Choose a reason for hiding this comment

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

ASE has a better scheme for generating a cubic supercell. See the function here https://wiki.fysik.dtu.dk/ase/ase/build/tools.html#ase.build.find_optimal_cell_shape

And the explanation here: https://wiki.fysik.dtu.dk/ase/tutorials/defects/defects.html#algorithm-for-finding-optimal-supercell-shapes

Perhaps we could use these ase functions instead?

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 think I would need to test this in much more detail but it does look very useful especially with access to the optimality measure.

utf marked this conversation as resolved.
Show resolved Hide resolved
born: List[Matrix3D] | None = None,
epsilon_static: Matrix3D | None = None,
total_dft_energy: float | None = None,
supercell_matrix: Matrix3D | None = None,
):
"""
Make flow to calculate the phonon properties.

Parameters
----------
structure : .Structure
A pymatgen structure.
prev_vasp_dir : str or Path or None
A previous vasp calculation directory to use for copying outputs.
born: Matrix3D
Instead of recomputing born charges and epsilon,
these values can also be provided manually.
if born, epsilon_static are provided, the born
run will be skipped
this matrix can be provided in the phonopy convention
with born charges for symmetrically
inequivalent atoms only or
it can be provided in the VASP convention with information for
every atom in unit cell. Please be careful when converting
structures within in this workflow as this could lead to errors
epsilon_static: Matrix3D
The high-frequency dielectric constant
Instead of recomputing born charges and epsilon,
these values can also be provided.
if born, epsilon_static are provided, the born
run will be skipped
total_dft_energy: float
Instead of recomputing the energy of the bulk structure every time,
this value can also be provided in eV. If it is provided,
the static run will be skipped. Please make sure that
it fits to the cell you are generating within this workflow
supercell_matrix: list
instead of min_length, also a supercell_matrix can
be given, e.g. [[1.0,0.0,0.0],[0.0,1.0,0.0],[0.0,0.0,1.0]
"""
if self.use_symmetrized_structure not in [None, "primitive", "conventional"]:
raise ValueError(
"use_symmetrized_structure can only be primitive, conventional," "None"
)

if (
not self.use_symmetrized_structure == "primitive"
and self.kpath_scheme != "seekpath"
):
raise ValueError(
"You can only use other kpath schemes with the primitive standard structure"
)

if self.kpath_scheme not in [
"seekpath",
"hinuma",
"setyawan_curtarolo",
"latimer_munro",
"all",
]:
raise ValueError("kpath scheme is not implemented")

jobs = []

if self.use_symmetrized_structure == "primitive":
# These structures are compatible with many
# of the kpath algorithms that are used for Materials Project
prim_job = structure_to_primitive(structure, self.symprec)
jobs.append(prim_job)
structure = prim_job.output
elif self.use_symmetrized_structure == "conventional":
# it could be beneficial to use conventional
# standard structures to arrive faster at supercells with right
# angels
JaGeo marked this conversation as resolved.
Show resolved Hide resolved
conv_job = structure_to_conventional(structure, self.symprec)
jobs.append(conv_job)
structure = conv_job.output

# if supercell_matrix is None, supercell size will be determined
if supercell_matrix is None:
supercell_job = get_supercell_size(
structure,
self.min_length,
self.prefer_90_degrees,
**self.get_supercell_size_kwargs,
)
jobs.append(supercell_job)
supercell_matrix = supercell_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

# get a phonon object from phonopy
displacements = generate_phonon_displacements(
structure=structure,
supercell_matrix=supercell_matrix,
displacement=self.displacement,
sym_reduce=self.sym_reduce,
symprec=self.symprec,
use_symmetrized_structure=self.use_symmetrized_structure,
kpath_scheme=self.kpath_scheme,
code=self.code,
)
jobs.append(displacements)

# perform the phonon displacement calculations
vasp_displacement_calcs = run_phonon_displacements(
displacements=displacements.output,
structure=structure,
supercell_matrix=supercell_matrix,
phonon_maker=self.phonon_displacement_maker,
)
jobs.append(vasp_displacement_calcs)

# Computation of static energy
if self.static_energy_maker is not None and total_dft_energy is None:
static_job = self.static_energy_maker.make(structure=structure)
jobs.append(static_job)
total_energy = static_job.output.output.energy
JaGeo marked this conversation as resolved.
Show resolved Hide resolved
static_run_job_dir = static_job.output.dir_name
static_run_uuid = static_job.output.uuid
else:
total_energy = total_dft_energy
Copy link
Member

Choose a reason for hiding this comment

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

And then you can remove this line

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks. Will also change all other side effects of this change. I should probably run some of the automatic systems already now to spot such things. I wanted to wait until the unit tests are implemented as I always suspect potential problems.

static_run_job_dir = None
static_run_uuid = None

# Computation of BORN charges
if self.born_maker is not None and (born is None or epsilon_static is None):
born_job = self.born_maker.make(structure)
jobs.append(born_job)

# I am not happy how we currently access "born" charges
# This is very vasp specific code
epsilon_static = born_job.output.calcs_reversed[0].output.epsilon_static
born = born_job.output.calcs_reversed[0].output.outcar["born"]
born_run_job_dir = born_job.output.dir_name
born_run_uuid = born_job.output.uuid
else:
epsilon_static = epsilon_static
born = born
Copy link
Member

Choose a reason for hiding this comment

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

Remove these lines

Copy link
Member Author

Choose a reason for hiding this comment

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

In Germany, we call this "betriebsblind". Thanks.

Copy link
Member

Choose a reason for hiding this comment

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

That's a great word!

born_run_job_dir = None
born_run_uuid = None

phonon_collect = generate_frequencies_eigenvectors(
supercell_matrix=supercell_matrix,
displacement=self.displacement,
sym_reduce=self.sym_reduce,
symprec=self.symprec,
use_symmetrized_structure=self.use_symmetrized_structure,
kpath_scheme=self.kpath_scheme,
code=self.code,
structure=structure,
displacement_data=vasp_displacement_calcs.output,
epsilon_static=epsilon_static,
born=born,
total_energy=total_energy,
static_run_job_dir=static_run_job_dir,
static_run_uuid=static_run_uuid,
born_run_job_dir=born_run_job_dir,
born_run_uuid=born_run_uuid,
create_thermal_displacements=self.create_thermal_displacements,
**self.generate_frequencies_eigenvectors_kwargs,
)

jobs.append(phonon_collect)
# create a flow including all jobs for a phonon computation
flow = Flow(jobs, phonon_collect.output)
return flow
1 change: 0 additions & 1 deletion src/atomate2/vasp/jobs/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ def make(self, structure: Structure, prev_vasp_dir: str | Path | None = None):

if "from_prev" not in self.write_input_set_kwargs:
self.write_input_set_kwargs["from_prev"] = from_prev

Copy link
Member

Choose a reason for hiding this comment

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

Can you add this back in?

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, of course.

# write vasp input files
write_vasp_input_set(
structure, self.input_set_generator, **self.write_input_set_kwargs
Expand Down
Loading