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

Anharmonicity Quantification workflow #901

Merged
merged 70 commits into from
Aug 24, 2024
Merged
Show file tree
Hide file tree
Changes from 66 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
7f81eaf
Generated displaced structures
4kevinbeck5 Mar 8, 2024
bdde707
Implemented sigma_A oneshot calculations
4kevinbeck5 Mar 19, 2024
eb1daed
Added some needed object attributes
4kevinbeck5 Mar 29, 2024
8ae8b48
Added some object attributes
4kevinbeck5 Mar 29, 2024
074a01c
Added pieces to flow to utilize PhononBSDOSDoc
4kevinbeck5 Apr 16, 2024
fd614ef
Added a prefactor method to find dynamical matrix
4kevinbeck5 Apr 16, 2024
3647bc6
Fixed issue with prefactor method
4kevinbeck5 Apr 16, 2024
d1146b8
Made creation of dynamical matrix indep of phonon
4kevinbeck5 Apr 20, 2024
005491f
Added helper function to make Phonopy objects
4kevinbeck5 Apr 20, 2024
44970cc
Finished writing flow
4kevinbeck5 May 17, 2024
87d72df
Made all functions independent of passing Phonopy
4kevinbeck5 May 17, 2024
9bbf8d5
Code for anharmonicity code and starter for test
4kevinbeck5 May 21, 2024
bbca6ce
o
tpurcell90 May 22, 2024
dcd436f
Update anharmonicity tests
tpurcell90 May 22, 2024
0272e0e
Use pymatgen.core.units.kb
tpurcell90 May 22, 2024
e2634dd
Fixed assert statement
4kevinbeck5 May 22, 2024
a78b29a
Merge branch 'anharm_quant_cp' of github.com:tpurcell90/atomate2 into…
tpurcell90 May 22, 2024
069d693
The phonon supercell now determined to from phonon document
tpurcell90 May 23, 2024
aa5172d
Modification for mock_aims to work
tpurcell90 May 24, 2024
1f524eb
Add the test data for mock aims
tpurcell90 May 24, 2024
2a93c33
Add an aims only workflow and generalize the common one
tpurcell90 May 24, 2024
2a1ac95
Add functionality to create an anharmonicity flow from a PhononBSDOSDoc
tpurcell90 May 24, 2024
3219df2
Actually add Aims workflow for anharm
tpurcell90 May 30, 2024
e4bda6a
Made to work with anharmonicity schema doc
4kevinbeck5 Jun 3, 2024
0b26d5a
Added function to make anharmonicity doc
4kevinbeck5 Jun 3, 2024
f4a7fa0
Cleaned up anharmonicity flow test
4kevinbeck5 Jun 6, 2024
ff5d73e
Wrote tests for anharm schema
4kevinbeck5 Jun 7, 2024
9c28b84
Added fields to anharm schema
4kevinbeck5 Jun 7, 2024
b1f9fee
Added flag and function for full sigma^A
4kevinbeck5 Jun 7, 2024
4b98029
Added files for mock_aims
4kevinbeck5 Jun 9, 2024
e19a432
Added test for full sigma A with mock_aims
4kevinbeck5 Jun 9, 2024
efef913
Added capability to pass a seed for rng
4kevinbeck5 Jun 9, 2024
788b7fa
Added files for mock aims
4kevinbeck5 Jun 12, 2024
8517851
Added pytest fixture for NaCl structure
4kevinbeck5 Jun 12, 2024
f461970
Added atom-resolved sigma A calculation and test
4kevinbeck5 Jun 12, 2024
3655cf3
Fixed bug when atom_resolved was False
4kevinbeck5 Jun 12, 2024
8bbe510
Added mock_aims files for mode_resolved sigma^A
4kevinbeck5 Jun 18, 2024
66898e3
Added mode resolved sigma^A test w/ mock_aims
4kevinbeck5 Jun 18, 2024
0ee443a
Implemented mode resolved sigma^A calcs
4kevinbeck5 Jun 18, 2024
51b5156
Made tests work with sigma_dict
4kevinbeck5 Jun 18, 2024
834ff22
Returns a dictionary with computed sigma values
4kevinbeck5 Jun 18, 2024
5294e4c
Cleaned up code with pre-commit
4kevinbeck5 Jun 18, 2024
686adf5
Fixed bug in test_anharmonicity.py
4kevinbeck5 Jun 18, 2024
f737143
Fixed anharm quant one-shot socket test
4kevinbeck5 Jun 20, 2024
0944c2a
Fixed typo in docstring
4kevinbeck5 Jun 20, 2024
c809817
Added return info to docstrings
4kevinbeck5 Jun 21, 2024
e7f3072
Refactored code to make cleaner
4kevinbeck5 Jun 24, 2024
9146c3d
Merge branch 'main' into anharm_quant_cp
tpurcell90 Jun 25, 2024
cbd0b29
Fix lint errors in tests
4kevinbeck5 Jun 25, 2024
d74b64a
Remove typing.Self call
4kevinbeck5 Jun 25, 2024
51cf3f7
Merge branch 'anharm_quant_cp' of https://github.com/tpurcell90/atoma…
4kevinbeck5 Jun 25, 2024
339db13
Fixed lint and typing errors.
4kevinbeck5 Jun 25, 2024
625f3b0
Fixed tests to pass on github.
4kevinbeck5 Jun 25, 2024
c4aea40
Merge branch 'main' into anharm_quant_cp
4kevinbeck5 Jul 2, 2024
05866c6
Update src/atomate2/aims/flows/anharmonicity.py
tpurcell90 Jul 19, 2024
da6e20f
Changed omega_to_THz to be imported from atomate2
4kevinbeck5 Jul 19, 2024
7206e06
Merge branch 'anharm_quant_cp' of https://github.com/tpurcell90/atoma…
4kevinbeck5 Jul 19, 2024
0cd50bf
Merge branch 'main' into anharm_quant_cp
4kevinbeck5 Jul 19, 2024
08f1474
Made separate eigenvec/val solver for dynamical matrix and added clea…
4kevinbeck5 Aug 5, 2024
f36d17f
Merge branch 'anharm_quant_cp' of https://github.com/tpurcell90/atoma…
4kevinbeck5 Aug 5, 2024
5e4dddb
Merge branch 'main' into anharm_quant_cp
4kevinbeck5 Aug 5, 2024
242c181
Fixed torchdata version
4kevinbeck5 Aug 6, 2024
2573685
Merge branch 'anharm_quant_cp' of https://github.com/tpurcell90/atoma…
4kevinbeck5 Aug 6, 2024
0166ccd
Re-implemented get_phonon_supercell
4kevinbeck5 Aug 14, 2024
43c8f4d
Added mode-resolved sigma^A calculation
4kevinbeck5 Aug 21, 2024
164366b
Merge branch 'main' into anharm_quant_cp
4kevinbeck5 Aug 21, 2024
c9c4886
Fixed linting issues
4kevinbeck5 Aug 22, 2024
f2669c6
Add @4kevinbeck5 to contributors.md file
4kevinbeck5 Aug 23, 2024
3dee37a
remove dict initalisation
JaGeo Aug 24, 2024
d661858
test if pip on torch data is really needed
JaGeo Aug 24, 2024
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
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ forcefields = [
"calorine<=2.2.1",
"chgnet>=0.2.2",
"mace-torch>=0.3.3",
"torchdata<=0.7.1", # TODO: remove when issue fixed
"matgl>=1.1.3",
"quippy-ase>=0.9.14",
"sevenn>=0.9.3",
Expand Down Expand Up @@ -92,6 +93,7 @@ strict = [
"jobflow==0.1.18",
"lobsterpy==0.4.5",
"mace-torch>=0.3.3",
"torchdata==0.7.1", # TODO: remove when issue fixed
"matgl==1.1.3",
"monty==2024.7.30",
"mp-api==0.41.2",
Expand Down
44 changes: 44 additions & 0 deletions src/atomate2/aims/flows/anharmonicity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""Defines the anharmonicity quantification workflows for FHI-aims."""

from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING

from atomate2.common.flows.anharmonicity import BaseAnharmonicityMaker

if TYPE_CHECKING:
from atomate2.aims.flows.phonons import PhononMaker


@dataclass
class AnharmonicityMaker(BaseAnharmonicityMaker):
"""
Maker to calculate the anharmonicity score of a material.

Calculate sigma^A as defined in doi.org/10.1103/PhysRevMaterials.4.083809, by
first calculating the phonons for a material and then generating the one-shot
sample and calculating the DFT and harmonic forces.

Parameters
----------
name : str
Name of the flows produced by this maker.
phonon_maker: BasePhononMaker
The maker to generate the phonon model
"""

name: str = "anharmonicity"
phonon_maker: PhononMaker = None

@property
def prev_calc_dir_argname(self) -> str:
"""Name of argument informing static maker of previous calculation directory.

As this differs between different DFT codes (e.g., VASP, CP2K), it
has been left as a property to be implemented by the inheriting class.

Note: this is only applicable if a relax_maker is specified; i.e., two
calculations are performed for each ordering (relax -> static)
"""
return "prev_dir"
18 changes: 15 additions & 3 deletions src/atomate2/aims/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,29 @@ def run_aims_socket(
aims_cmd: str
The aims command to use (defaults to SETTINGS.AIMS_CMD).
"""
if aims_cmd is None:
aims_cmd = SETTINGS.AIMS_CMD

ase_adaptor = AseAtomsAdaptor()
atoms_to_calculate = [
ase_adaptor.get_atoms(structure) for structure in structures_to_calculate
]

with open("parameters.json") as param_file:
parameters = json.load(param_file, cls=MontyDecoder)

del_keys = []
for key, val in parameters.items():
if val is None:
del_keys.append(key)

for key in del_keys:
parameters.pop(key)

if aims_cmd:
parameters["aims_command"] = aims_cmd
elif "aims_command" not in parameters:
parameters["aims_command"] = SETTINGS.AIMS_CMD
parameters["command"] = aims_cmd
elif "command" not in parameters:
parameters["command"] = SETTINGS.AIMS_CMD

calculator = Aims(**parameters)
port = parameters["use_pimd_wrapper"][1]
Expand Down
283 changes: 283 additions & 0 deletions src/atomate2/common/flows/anharmonicity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
"""A workflow to evaluate the anharmonicity of a material with sigma^A.

For details see: doi.org/10.1103/PhysRevMaterials.4.083809
"""
4kevinbeck5 marked this conversation as resolved.
Show resolved Hide resolved

from __future__ import annotations

from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import TYPE_CHECKING
from warnings import warn

from jobflow import Flow, Maker

from atomate2.common.jobs.anharmonicity import (
displace_structure,
get_forces,
get_phonon_supercell,
get_sigmas,
run_displacements,
store_results,
)

if TYPE_CHECKING:
from pathlib import Path

from emmet.core.math import Matrix3D
from pymatgen.core.structure import Structure

from atomate2.common.flows.phonons import BasePhononMaker
from atomate2.common.schemas.phonons import PhononBSDOSDoc

SUPPORTED_CODES = ["aims"]


@dataclass
class BaseAnharmonicityMaker(Maker, ABC):
"""
Maker to calculate the anharmonicity score of a material.

Calculate sigma^A as defined in doi.org/10.1103/PhysRevMaterials.4.083809, by
first calculating the phonons for a material and then generating the one-shot
sample and calculating the DFT and harmonic forces.

Parameters
----------
name: str
Name of the flows produced by this maker.
phonon_maker: BasePhononMaker
The maker to generate the phonon model
"""

name: str = "anharmonicity"
phonon_maker: BasePhononMaker = None

def make(
self,
structure: Structure,
prev_dir: str | Path | None = None,
born: list[Matrix3D] | None = None,
epsilon_static: Matrix3D | None = None,
total_dft_energy_per_formula_unit: float | None = None,
supercell_matrix: Matrix3D | None = None,
temperature: float = 300,
one_shot_approx: bool = True,
seed: int | None = None,
element_resolved: bool = False,
mode_resolved: bool = False,
site_resolved: bool = False,
n_samples: int = 1,
) -> Flow:
"""Make the anharmonicity calculation flow.

Parameters
----------
structure: Structure
A pymatgen structure object. Please start with a structure
that is nearly fully optimized as the internal optimizers
have very strict settings!
prev_dir: Optional[str | Path]
A previous calculation directory to use for copying outputs.
Default is None.
born: Optional[list[Matrix3D]]
Instead of recomputing born charges and epsilon, these values can also be
provided manually. If born and epsilon_static are provided, the born run
will be skipped 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. The default for this
field is None.
epsilon_static: Optional[Matrix3D]
The high-frequency dielectric constant to use instead of recomputing born
charges and epsilon. If born, epsilon_static are provided, the born run
will be skipped. The default for this field is None.
total_dft_energy_per_formula_unit: Optional[float]
It has to be given per formula unit (as a result in corresponding Doc).
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. This energy is the typical output dft energy of the dft workflow.
No conversion needed. It is set to 0 by default.
supercell_matrix: Optional[Matrix3D]
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]]. By default, this matrix is
set to None.
temperature: float
The temperature for the anharmonicity calculation. The default temp is 300.
one_shot_approx: bool
If true, finds the one shot approximation of sigma^A and if false, finds
the full sigma^A. The default is True.
seed: Optional[int]
Seed to use for the random number generator
(only used if one_shot_approx == False). Set to None by default.
element_resolved: bool
If true, calculate the atom-resolved sigma^A. This is false by default.
mode_resolved: bool
If true, calculate the mode-resolved sigma^A. This is false by default.
site_resolved: bool
If true, resolve sigma^A to the different sites.
Default is false.
n_samples: int
Number of times displaced structures are sampled.
Must be >= 1 and cannot be used when one_shot_approx == True.
It is set to 1 by default.

Returns
-------
Flow
The workflow for the anharmonicity calculations
"""
phonon_flow = self.phonon_maker.make(
structure,
prev_dir,
born,
epsilon_static,
total_dft_energy_per_formula_unit,
supercell_matrix,
)

phonon_doc = phonon_flow.output
anharmon_flow = self.make_from_phonon_doc(
phonon_doc,
prev_dir,
temperature,
one_shot_approx,
seed,
element_resolved,
mode_resolved,
site_resolved,
n_samples,
)

results = store_results(
sigma_dict=anharmon_flow.output,
phonon_doc=phonon_flow.output,
one_shot=one_shot_approx,
temp=temperature,
n_samples=n_samples,
seed=seed,
)

jobs = [phonon_flow, anharmon_flow, results]
return Flow(jobs, results.output)

def make_from_phonon_doc(
self,
phonon_doc: PhononBSDOSDoc,
prev_dir: str | Path | None = None,
temperature: float = 300,
one_shot_approx: bool = True,
seed: int | None = None,
element_resolved: bool = False,
mode_resolved: bool = False,
site_resolved: bool = False,
n_samples: int = 1,
) -> Flow:
"""Create an anharmonicity workflow from a phonon calculation.

Parameters
----------
phonon_doc: PhononBSDOSDoc
The document to get the anharmonicity for
prev_dir: Optional[str | Path]
A previous calculation directory to use for copying outputs.
Default is None.
temperature: float
The temperature for the anharmonicity calculation. Default is 300.
one_shot_approx: bool
If true, finds the one shot approximation of sigma^A and if false,
finds the full sigma^A. The default is True.
seed: Optional[int]
Seed to use for the random number generator
(only used if one_shot_approx == False). Default is None.
element_resolved: bool
If true, calculate the atom-resolved sigma^A. This is false by default.
mode_resolved: bool
If true, calculate the mode-resolved sigma^A. This is false by default.
site_resolved: bool
If true, resolve sigma^A to the different sites.
Default is false.
n_samples: int
Number of times displaced structures are sampled.
Must be >= 1 and cannot be used when one_shot_approx == True.
It is set to 1 by default.

Returns
-------
Flow
The anharmonicity quantification workflow
"""
# KB: Not always an error. There could be negative acoustic modes from
# unconverged phonon calculations.
if phonon_doc.has_imaginary_modes:
warn(
"The phonon model has imaginary modes, sampling maybe incorrect.",
stacklevel=1,
)

jobs = []
phonon_supercell_job = get_phonon_supercell(
phonon_doc.structure,
phonon_doc.supercell_matrix,
)
jobs.append(phonon_supercell_job)

phonon_supercell = phonon_supercell_job.output

displace_supercell = displace_structure(
phonon_supercell=phonon_supercell,
force_constants=phonon_doc.force_constants,
temp=temperature,
one_shot=one_shot_approx,
seed=seed,
n_samples=n_samples,
)
jobs.append(displace_supercell)

force_eval_maker = self.phonon_maker.phonon_displacement_maker
displacement_calcs = run_displacements(
displacements=displace_supercell.output,
phonon_supercell=phonon_supercell,
force_eval_maker=force_eval_maker,
socket=self.phonon_maker.socket,
prev_dir_argname=self.prev_calc_dir_argname,
prev_dir=prev_dir,
)
jobs.append(displacement_calcs)

# Get DFT and harmonic forces
force_calcs = get_forces(
phonon_doc.force_constants,
phonon_supercell,
displacement_calcs.output,
)
jobs.append(force_calcs)

sigma_a_vals = {}
Copy link
Member

Choose a reason for hiding this comment

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

This can be removed.


# Calculate all desired sigma^A types
sigma_calcs = get_sigmas(
force_calcs.output[0],
force_calcs.output[1],
phonon_doc.force_constants,
phonon_supercell,
one_shot_approx,
element_resolved,
mode_resolved,
site_resolved,
)
jobs.append(sigma_calcs)
sigma_a_vals = sigma_calcs.output

return Flow(jobs, sigma_a_vals)

@property
@abstractmethod
def prev_calc_dir_argname(self) -> str | None:
"""Name of argument informing static maker of previous calculation directory.

As this differs between different DFT codes (e.g., VASP, CP2K), it
has been left as a property to be implemented by the inheriting class.

Note: this is only applicable if a relax_maker is specified; i.e., two
calculations are performed for each ordering (relax -> static)
"""
Loading
Loading