Skip to content

Commit 9c84108

Browse files
naik-aakashJaGeojoabustamante
authored
Add workflow to compute Gruneisen parameters (#752)
* add draft for gruneisen workflow * update gruneisen workflow * add draft schema and simplify compute grunesien job, add kwargs * fix wrong field name * add preliminary tests, custom bandstructure plotting with gruneisen weighted * comment out low accuracy derived property value test * comment out low accuracy derived property value test * fix doc-string description for phonopy_yaml_paths_dict * add high accuracy ref gruneisen data from vasp * add test for compute_gruneisen_param * removed comment * remove leftover commented code * fix custom gruneisen plotter color bar * clean up min and max gruneisen parameter extraction * add names to jobs * fix files * add correct files * fix output_schema * add tests, switch to double relax * change to different init of phonon workflow * add missing doc * add prevdir * add documentation * change mesh * change mesh * fix linting * fix linting * add gruneisen * fix workflow tests * fix linting * add gridd * change how document works and a bit more documentation * add documentation * fix logger * fix linting * fix linting * add missing docstrings * fix mesh type * fix classmethod * Introduce constant volume relax maker * switch to PhononMaker * fix linting * switch to imperative mode * fix text * fix mypy issues * fix symprec * fix symprec * fix constant volume relax makr --------- Co-authored-by: J. George <[email protected]> Co-authored-by: joabustamante <[email protected]> Co-authored-by: jpineda <[email protected]> Co-authored-by: JaGeo <[email protected]>
1 parent fad9396 commit 9c84108

File tree

125 files changed

+60920
-40
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

125 files changed

+60920
-40
lines changed

docs/user/codes/vasp.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,19 @@ adjust them if necessary. The default might not be strict enough
247247
for your specific case.
248248
```
249249

250+
### Gruneisen parameter workflow
251+
252+
Calculates mode-dependent Grüneisen parameters with the help of Phonopy.
253+
254+
Initially, a tight structural relaxation is performed to obtain a structure without
255+
forces on the atoms. The optimized structure (ground state) is further expanded and
256+
shrunk by 1 % (default) of its volume.
257+
Subsequently, supercells with one displaced atom are generated for all the three structures
258+
(ground state, expanded and shrunk volume) and accurate forces are computed for these structures.
259+
With the help of phonopy, these forces are then converted into a dynamical matrix.
260+
The dynamical matrices of three structures are then used as an input to the phonopy Grueneisen api
261+
to compute mode-dependent Grueneisen parameters.
262+
250263
### LOBSTER
251264

252265
Perform bonding analysis with [LOBSTER](http://cohp.de/) and [LobsterPy](https://github.com/jageo/lobsterpy)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ strict = [
9090
"dscribe==2.1.1",
9191
"emmet-core==0.82.2",
9292
"ijson==3.3.0",
93-
"jobflow==0.1.17",
93+
"jobflow==0.1.18",
9494
"lobsterpy==0.4.5",
9595
"mace-torch>=0.3.3",
9696
"matgl==1.1.2",

src/atomate2/aims/flows/phonons.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from dataclasses import dataclass, field
66
from typing import TYPE_CHECKING
77

8+
from atomate2 import SETTINGS
89
from atomate2.aims.jobs.core import RelaxMaker, StaticMaker
910
from atomate2.aims.jobs.phonons import (
1011
PhononDisplacementMaker,
@@ -112,7 +113,7 @@ class PhononMaker(BasePhononMaker):
112113

113114
name: str = "phonon"
114115
sym_reduce: bool = True
115-
symprec: float = 1e-4
116+
symprec: float = SETTINGS.PHONON_SYMPREC
116117
displacement: float = 0.01
117118
min_length: float | None = 20.0
118119
prefer_90_degrees: bool = True
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
"""Flows for calculating Grueneisen-Parameters."""
2+
3+
from __future__ import annotations
4+
5+
import warnings
6+
from abc import ABC, abstractmethod
7+
from dataclasses import dataclass, field
8+
from typing import TYPE_CHECKING
9+
10+
from jobflow import Flow, Maker
11+
12+
from atomate2 import SETTINGS
13+
from atomate2.common.jobs.gruneisen import (
14+
compute_gruneisen_param,
15+
run_phonon_jobs,
16+
shrink_expand_structure,
17+
)
18+
19+
if TYPE_CHECKING:
20+
from pathlib import Path
21+
22+
from pymatgen.core.structure import Structure
23+
24+
from atomate2.aims.jobs.base import BaseAimsMaker
25+
from atomate2.common.flows.phonons import BasePhononMaker
26+
from atomate2.forcefields.jobs import ForceFieldRelaxMaker
27+
from atomate2.vasp.jobs.base import BaseVaspMaker
28+
29+
30+
@dataclass
31+
class BaseGruneisenMaker(Maker, ABC):
32+
"""
33+
Maker to calculate Grueneisen parameters with DFT/force field code and Phonopy.
34+
35+
Calculate Grueneisen parameters by a finite volume change approach based on
36+
harmonic phonons.
37+
Initially, a tight structural relaxation is performed to obtain a structure without
38+
forces on the atoms. The optimized structure (ground state) is further expanded and
39+
shrunk by 1 % of its volume. Subsequently, supercells with one displaced atom are
40+
generated for all the three structures (ground state, expanded and shrunk volume)
41+
and accurate forces are computed for these structures. With the help of phonopy,
42+
these forces are then converted into a dynamical matrix. This dynamical matrix of
43+
three structures is then used as an input for the phonopy Grueneisen api
44+
to compute Grueneisen parameters.
45+
46+
47+
48+
Parameters
49+
----------
50+
name : str
51+
Name of the flows produced by this maker.
52+
bulk_relax_maker: .ForceFieldRelaxMaker, .BaseAimsMaker, .BaseVaspMaker, or None
53+
A maker to perform an initial tight relaxation on the bulk.
54+
code: str
55+
determines the dft or force field code.
56+
const_vol_relax_maker: .ForceFieldRelaxMaker, .BaseAimsMaker,
57+
.BaseVaspMaker, or None. A maker to perform a tight relaxation
58+
on the expanded and shrunk structures at constant volume.
59+
kpath_scheme: str
60+
scheme to generate kpoints. Please be aware that
61+
you can only use seekpath with any kind of cell
62+
Otherwise, please use the standard primitive structure
63+
Available schemes are:
64+
"seekpath", "hinuma", "setyawan_curtarolo", "latimer_munro".
65+
"seekpath" and "hinuma" are the same definition but
66+
seekpath can be used with any kind of unit cell as
67+
it relies on phonopy to handle the relationship
68+
to the primitive cell and not pymatgen
69+
mesh: tuple or float
70+
Mesh numbers along a, b, c axes used for Grueneisen parameter computation.
71+
Or an int or float to indicate a kpoint density.
72+
phonon_maker: .BasePhononMaker
73+
PhononMaker to run the phonon workflow.
74+
perc_vol: float
75+
Percent volume to shrink and expand ground state structure
76+
compute_gruneisen_param_kwargs: dict
77+
Keyword arguments passed to :obj:`compute_gruneisen_param`.
78+
symprec: float
79+
Symmetry precision for symmetry checks and phonon runs.
80+
"""
81+
82+
name: str = "Gruneisen"
83+
bulk_relax_maker: ForceFieldRelaxMaker | BaseVaspMaker | BaseAimsMaker | None = None
84+
code: str = None
85+
const_vol_relax_maker: ForceFieldRelaxMaker | BaseVaspMaker | BaseAimsMaker = None
86+
kpath_scheme: str = "seekpath"
87+
phonon_maker: BasePhononMaker = None
88+
perc_vol: float = 0.01
89+
mesh: tuple[float, float, float] | float = 7_000
90+
compute_gruneisen_param_kwargs: dict = field(default_factory=dict)
91+
symprec: float = SETTINGS.PHONON_SYMPREC
92+
93+
def make(self, structure: Structure, prev_dir: str | Path | None = None) -> Flow:
94+
"""
95+
Optimizes structure and runs phonon computations.
96+
97+
Phonon computations are run for ground state, expanded and shrunk
98+
volume structures. Then, Grueneisen parameters are computed from
99+
this three phonon runs.
100+
101+
Parameters
102+
----------
103+
structure : Structure
104+
A pymatgen structure object. Please start with a structure
105+
that is nearly fully optimized as the internal optimizers
106+
have very strict settings!
107+
prev_dir : str or Path or None
108+
A previous calculation directory to use for copying outputs.
109+
"""
110+
jobs = [] # initialize an empty list for jobs to be run
111+
112+
# initialize an dict to store optimized structures
113+
opt_struct = dict.fromkeys(("ground", "plus", "minus"), None)
114+
prev_dir_dict = dict.fromkeys(("ground", "plus", "minus"), None)
115+
if (
116+
self.bulk_relax_maker is not None
117+
): # Optional job to relax the initial structure
118+
bulk_kwargs = {}
119+
if self.prev_calc_dir_argname is not None:
120+
bulk_kwargs[self.prev_calc_dir_argname] = prev_dir
121+
bulk = self.bulk_relax_maker.make(structure, **bulk_kwargs)
122+
jobs.append(bulk)
123+
opt_struct["ground"] = bulk.output.structure
124+
prev_dir = bulk.output.dir_name
125+
prev_dir_dict["ground"] = bulk.output.dir_name
126+
else:
127+
opt_struct["ground"] = structure
128+
prev_dir_dict["ground"] = prev_dir
129+
130+
# Add job to get expanded and shrunk volume structures
131+
struct_dict = shrink_expand_structure(
132+
structure=bulk.output.structure, perc_vol=self.perc_vol
133+
)
134+
jobs.append(struct_dict)
135+
const_vol_relax_maker_kwargs = {}
136+
if self.prev_calc_dir_argname is not None:
137+
const_vol_relax_maker_kwargs[self.prev_calc_dir_argname] = prev_dir
138+
139+
# get expanded structure
140+
const_vol_struct_plus = self.const_vol_relax_maker.make(
141+
structure=struct_dict.output["plus"], **const_vol_relax_maker_kwargs
142+
)
143+
const_vol_struct_plus.append_name(" plus")
144+
# add relax job at constant volume for expanded structure
145+
jobs.append(const_vol_struct_plus)
146+
147+
opt_struct["plus"] = (
148+
const_vol_struct_plus.output.structure
149+
) # store opt struct of expanded volume
150+
151+
# get shrunk structure
152+
const_vol_struct_minus = self.const_vol_relax_maker.make(
153+
structure=struct_dict.output["minus"], **const_vol_relax_maker_kwargs
154+
)
155+
const_vol_struct_minus.append_name(" minus")
156+
# add relax job at constant volume for shrunk structure
157+
jobs.append(const_vol_struct_minus)
158+
159+
opt_struct["minus"] = (
160+
const_vol_struct_minus.output.structure
161+
) # store opt struct of expanded volume
162+
prev_dir_dict["plus"] = const_vol_struct_plus.output.dir_name
163+
prev_dir_dict["minus"] = const_vol_struct_minus.output.dir_name
164+
# go over a dict of prev_dir and use it in the maker
165+
phonon_jobs = run_phonon_jobs(
166+
opt_struct,
167+
self.phonon_maker,
168+
symprec=self.symprec,
169+
prev_calc_dir_argname=self.prev_calc_dir_argname,
170+
prev_dir_dict=prev_dir_dict,
171+
)
172+
jobs.append(phonon_jobs)
173+
# might not work well, put this into a job
174+
175+
# get Gruneisen parameter from phonon runs yaml with phonopy api
176+
get_gru = compute_gruneisen_param(
177+
code=self.code,
178+
kpath_scheme=self.kpath_scheme,
179+
mesh=self.mesh,
180+
phonopy_yaml_paths_dict=phonon_jobs.output["phonon_yaml"],
181+
structure=opt_struct["ground"],
182+
symprec=self.symprec,
183+
phonon_imaginary_modes_info=phonon_jobs.output["imaginary_modes"],
184+
**self.compute_gruneisen_param_kwargs,
185+
)
186+
187+
jobs.append(get_gru)
188+
189+
return Flow(jobs, output=get_gru.output)
190+
191+
@property
192+
@abstractmethod
193+
def prev_calc_dir_argname(self) -> str | None:
194+
"""Name of argument informing static maker of previous calculation directory.
195+
196+
As this differs between different DFT codes (e.g., VASP, CP2K), it
197+
has been left as a property to be implemented by the inheriting class.
198+
199+
Note: this is only applicable if a relax_maker is specified; i.e., two
200+
calculations are performed for each ordering (relax -> static)
201+
"""
202+
203+
def __post_init__(self) -> None:
204+
"""Test settings during the initialisation."""
205+
if self.phonon_maker.bulk_relax_maker is not None:
206+
warnings.warn(
207+
"An additional bulk_relax_maker has been added "
208+
"to the phonon workflow. Please be aware "
209+
"that the volume needs to be kept fixed.",
210+
stacklevel=2,
211+
)
212+
if self.phonon_maker.symprec != self.symprec:
213+
warnings.warn(
214+
"You are using different symmetry precisions "
215+
"in the phonon makers and other parts of the "
216+
"Grüneisen workflow.",
217+
stacklevel=2,
218+
)
219+
if self.phonon_maker.static_energy_maker is not None:
220+
warnings.warn(
221+
"The static energy maker " "is not needed for " "this workflow.",
222+
stacklevel=2,
223+
)

src/atomate2/common/flows/phonons.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from jobflow import Flow, Maker
1010

11+
from atomate2 import SETTINGS
1112
from atomate2.common.jobs.phonons import (
1213
generate_frequencies_eigenvectors,
1314
generate_phonon_displacements,
@@ -127,7 +128,7 @@ class BasePhononMaker(Maker, ABC):
127128

128129
name: str = "phonon"
129130
sym_reduce: bool = True
130-
symprec: float = 1e-4
131+
symprec: float = SETTINGS.PHONON_SYMPREC
131132
displacement: float = 0.01
132133
min_length: float | None = 20.0
133134
prefer_90_degrees: bool = True

0 commit comments

Comments
 (0)