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

[WIP] Defects CP2K #280

Open
wants to merge 104 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
acc8553
Merge branch 'main' of https://github.com/materialsproject/atomate2 i…
nwinner Oct 17, 2022
6969c91
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 20, 2022
e9cd2e1
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 24, 2022
7991c62
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 25, 2022
9ba402b
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 25, 2022
aa7a68c
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 25, 2022
9944e27
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 25, 2022
d7a3e6b
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 25, 2022
e3569ac
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 25, 2022
a932173
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 26, 2022
c83cf57
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 26, 2022
9ea326d
Re-add defects
nwinner Oct 26, 2022
ce6d990
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 26, 2022
cb72376
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 26, 2022
3ff04da
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 26, 2022
545b86c
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 26, 2022
e559aa8
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 27, 2022
5be4ac3
Defect updates
nwinner Oct 28, 2022
6b39a44
Defect updates
nwinner Oct 29, 2022
2951a96
Working on defects with builder
nwinner Oct 31, 2022
684204f
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 31, 2022
132a6d4
Don't perturb when bulk
nwinner Oct 31, 2022
3cff959
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 31, 2022
a3feadd
More robust for some reason
nwinner Oct 31, 2022
ab4cc6a
Expand parents
nwinner Oct 31, 2022
99e3a55
Ugly but functional
nwinner Oct 31, 2022
f451660
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 31, 2022
3794167
Merge branch 'cp2k' into cp2k-defects
nwinner Oct 31, 2022
8daf86d
Updates for cluster testing
nwinner Nov 3, 2022
9072e9d
Merge branch 'cp2k' into cp2k-defects
nwinner Nov 3, 2022
b839368
Merge branch 'cp2k' into cp2k-defects
nwinner Nov 5, 2022
92cdd2a
Merge branch 'cp2k' into cp2k-defects
nwinner Nov 7, 2022
4c2ad99
Merge branch 'cp2k' into cp2k-defects
nwinner Nov 7, 2022
62b4394
Merge branch 'cp2k' into cp2k-defects
nwinner Nov 7, 2022
5fb95be
Merge branch 'cp2k' into cp2k-defects
nwinner Nov 8, 2022
2d301f9
Merge branch 'cp2k' into cp2k-defects
nwinner Nov 8, 2022
804f4bb
copy info
nwinner Nov 8, 2022
f3150b8
Merge branch 'cp2k' into cp2k-defects
nwinner Nov 8, 2022
cebc98c
Merge branch 'cp2k' into cp2k-defects
nwinner Nov 8, 2022
3e705a1
Merge branch 'cp2k' into cp2k-defects
nwinner Nov 8, 2022
f65552c
Merge branch 'cp2k' into cp2k-defects
nwinner Nov 9, 2022
a5d126b
Merge branch 'cp2k' into cp2k-defects
nwinner Nov 21, 2022
74cbd27
Merge branch 'cp2k' into cp2k-defects
nwinner Nov 21, 2022
41a2504
Defects
nwinner Nov 27, 2022
a9fcc37
Charge
nwinner Nov 28, 2022
a0725aa
Def Builder
nwinner Nov 29, 2022
725f7ca
DefectDoc
nwinner Nov 29, 2022
441c4f8
DefectiveMat
nwinner Nov 29, 2022
1ddeec5
Print PDOS
nwinner Nov 29, 2022
17c50eb
Merge branch 'cp2k' into cp2k-defects
nwinner Nov 29, 2022
9f2f7ec
Defects
nwinner Nov 29, 2022
a4e3b01
Builder
nwinner Dec 1, 2022
c2064b8
Defect
nwinner Dec 6, 2022
e6826ba
Merge branch 'cp2k' into cp2k-defects
nwinner Dec 6, 2022
3b7b41c
Defects
nwinner Dec 8, 2022
f0bcb84
Merge branch 'cp2k' into cp2k-defects
nwinner Dec 8, 2022
9c8b977
Round sc_matrix
nwinner Dec 14, 2022
c2adb56
Merge branch 'cp2k' into cp2k-defects
nwinner Dec 14, 2022
1009f18
Module import
nwinner Dec 14, 2022
4566e9d
defect
nwinner Dec 16, 2022
8a2eb09
task_ids
nwinner Dec 16, 2022
c92f11d
task_ids
nwinner Dec 16, 2022
e1d5873
Fix
nwinner Dec 19, 2022
302cff8
defects
nwinner Dec 19, 2022
0abd29d
No upper
nwinner Dec 19, 2022
a4656d4
Merge branch 'cp2k' into cp2k-defects
nwinner Dec 19, 2022
ddfc8ac
Merge branch 'cp2k' into cp2k-defects
nwinner Dec 19, 2022
e4e456a
builder test
nwinner Dec 20, 2022
66ef793
2d debug
nwinner Dec 20, 2022
abf89aa
task ids
nwinner Dec 22, 2022
a852fcb
First pass at defect validation schema
nwinner Dec 23, 2022
32a83e9
Store bulk defect pair drop others
nwinner Dec 23, 2022
eaa6361
Defects
nwinner Dec 24, 2022
a9388e8
Updates
nwinner Dec 31, 2022
09002c5
Merge branch 'cp2k' into cp2k-defects
nwinner Dec 31, 2022
90bcf7a
Merge branch 'cp2k' into cp2k-defects
nwinner Dec 31, 2022
38862bb
Make list
nwinner Jan 3, 2023
d3639ed
Merge branch 'cp2k' into cp2k-defects
nwinner Jan 3, 2023
a52a676
basic def test
nwinner Jan 6, 2023
802308e
Use __post_init__ instead
nwinner Jan 6, 2023
a75ac75
Merge branch 'cp2k' into cp2k-defects
nwinner Jan 6, 2023
1f46844
Merge branch 'cp2k' into cp2k-defects
nwinner Jan 6, 2023
791381c
whitespace
nwinner Jan 9, 2023
d6da377
Merge branch 'cp2k' into cp2k-defects
nwinner Jan 9, 2023
2928336
Defect jobs
nwinner Jan 10, 2023
4d51095
lint
nwinner Jan 10, 2023
7317dab
dfct
nwinner Jan 12, 2023
7e79c82
Remove endline
nwinner Jan 17, 2023
570771a
Merge branch 'cp2k' into cp2k-defects
nwinner Jan 17, 2023
8f8e86f
trim
nwinner Jan 17, 2023
bc3e377
Temporary v_hartree solution for 2d
nwinner Jan 20, 2023
e41ee3d
lint
nwinner Jan 20, 2023
ce540a6
Merge branch 'cp2k' into cp2k-defects
nwinner Jan 20, 2023
7a39234
updates
nwinner Jan 20, 2023
df48455
lint
nwinner Jan 20, 2023
c2dfd4b
Merge branch 'cp2k' into cp2k-defects
nwinner Jan 20, 2023
d17ec26
defects
nwinner Mar 7, 2023
c57f90f
Merge branch 'cp2k' into cp2k-defects
nwinner Mar 7, 2023
8854fac
Merge branch 'cp2k' into cp2k-defects
nwinner Mar 7, 2023
5c3396b
Merge branch 'cp2k' into cp2k-defects
nwinner Mar 10, 2023
7e3333c
Merge branch 'cp2k' into cp2k-defects
nwinner Mar 13, 2023
e856206
freysoldt
nwinner Mar 26, 2023
377fd20
Merge branch 'main' into cp2k-defects
nwinner Mar 26, 2023
038bd38
Merge branch 'main' into cp2k-defects
JaGeo May 11, 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
1,130 changes: 1,130 additions & 0 deletions src/atomate2/cp2k/builders/defect.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/atomate2/cp2k/drones.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Drones for parsing VASP calculations and related outputs."""
"""Drones for parsing CP2K calculations and related outputs."""

from __future__ import annotations

Expand Down
311 changes: 311 additions & 0 deletions src/atomate2/cp2k/flows/defect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
"""Flows used in the calculation of defect properties."""

from __future__ import annotations

import logging
from copy import deepcopy
from dataclasses import dataclass, field
from pathlib import Path
from typing import Iterable, Literal, Mapping

from jobflow import Flow, Maker, OutputReference, job
from numpy.typing import NDArray
from pymatgen.analysis.defects.core import Defect
from pymatgen.analysis.defects.supercells import get_sc_fromstruct
from pymatgen.analysis.defects.thermo import DefectEntry
from pymatgen.entries.computed_entries import ComputedStructureEntry
from pymatgen.io.common import VolumetricData

from atomate2.cp2k.flows.core import (
HybridCellOptFlowMaker,
HybridRelaxFlowMaker,
HybridStaticFlowMaker,
)
from atomate2.cp2k.jobs.base import BaseCp2kMaker
from atomate2.cp2k.jobs.defect import (
DefectCellOptMaker,
DefectHybridCellOptMaker,
DefectHybridRelaxMaker,
DefectHybridStaticMaker,
DefectRelaxMaker,
DefectStaticMaker,
)

logger = logging.getLogger(__name__)


@dataclass
class DefectHybridStaticFlowMaker(HybridStaticFlowMaker):

pbe_maker: BaseCp2kMaker = field(default_factory=DefectStaticMaker)
hybrid_maker: BaseCp2kMaker = field(
default=DefectHybridStaticMaker(
copy_cp2k_kwargs={"additional_cp2k_files": ("info.json",)}
)
)


@dataclass
class DefectHybridRelaxFlowMaker(HybridRelaxFlowMaker):

pbe_maker: BaseCp2kMaker = field(default_factory=DefectStaticMaker)
hybrid_maker: BaseCp2kMaker = field(
default=DefectHybridRelaxMaker(
copy_cp2k_kwargs={"additional_cp2k_files": ("info.json",)}
)
)


@dataclass
class DefectHybridCellOptFlowMaker(HybridCellOptFlowMaker):

pbe_maker: BaseCp2kMaker = field(default_factory=DefectStaticMaker)
hybrid_maker: BaseCp2kMaker = field(
default=DefectHybridCellOptMaker(
copy_cp2k_kwargs={"additional_cp2k_files": ("info.json",)}
)
)


# TODO close to being able to put this in common. Just need a switch that decides
# which core flow/job to use based on software
@dataclass
class FormationEnergyMaker(Maker):
"""
Run a collection of defect jobs and (possibly) the bulk supercell
for determination of defect formation energies.

Parameters
----------
name: This flow's name. i.e. "defect formation energy"
run_bulk: whether to run the bulk supercell as a static ("static")
calculation, a full relaxation ("relax"), or to skip it (False)
hybrid_functional: If provided, this activates hybrid version of the
workflow. Provide functional as a parameter that the input set
can recognize. e.g. "PBE0" or "HSE06"
initialize_with_pbe: If hybrid functional is provided, this enables
the use of a static PBE run before the hybrid calc to provide a
starting guess for CP2K HF module.
supercell_matrix: If provided, the defect supercell will be created
by this 3x3 matrix. Else other parameters will be used.
max_atoms: Maximum number of atoms allowed in the supercell.
min_atoms: Minimum number of atoms allowed in the supercell.
min_length: Minimum length of the smallest supercell lattice
vector.
force_diagonal: If True, return a transformation with a
diagonal transformation matrix.
"""

name: str = "defect formation energy"
run_bulk: Literal["static", "relax"] | bool = field(default="static")
hybrid_functional: str | None = field(default=None)
initialize_with_pbe: bool = field(default=True)

supercell_matrix: NDArray = field(default=None)
min_atoms: int = field(default=80)
max_atoms: int = field(default=240)
min_length: int = field(default=10)
force_diagonal: bool = field(default=False)

def __post_init__(self):
if self.run_bulk == "relax":
if self.hybrid_functional:
self.bulk_maker = DefectHybridCellOptMaker(
name="bulk hybrid relax",
transformations=None,
initialize_with_pbe=self.initialize_with_pbe,
hybrid_functional=self.hybrid_functional,
)
else:
self.bulk_maker = DefectCellOptMaker(
name="bulk relax", transformations=None
)

elif self.run_bulk == "static":
if self.hybrid_functional:
self.bulk_maker = DefectHybridStaticFlowMaker(
name="bulk hybrid static",
initialize_with_pbe=self.initialize_with_pbe,
hybrid_functional=self.hybrid_functional,
)
else:
self.bulk_maker = DefectStaticMaker(name="bulk static")

if self.hybrid_functional:
self.def_maker = DefectHybridRelaxFlowMaker(
hybrid_functional=self.hybrid_functional,
initialize_with_pbe=self.initialize_with_pbe,
)
self.def_maker.pbe_maker.supercell_matrix = self.supercell_matrix
self.def_maker.hybrid_maker.supercell_matrix = self.supercell_matrix

self.def_maker.pbe_maker.max_atoms = self.max_atoms
self.def_maker.hybrid_maker.max_atoms = self.max_atoms

self.def_maker.pbe_maker.min_atoms = self.min_atoms
self.def_maker.hybrid_maker.min_atoms = self.min_atoms

self.def_maker.pbe_maker.min_length = self.min_length
self.def_maker.hybrid_maker.min_length = self.min_length

self.def_maker.pbe_maker.force_diagonal = self.force_diagonal
self.def_maker.hybrid_maker.force_diagonal = self.force_diagonal

else:
self.def_maker = DefectRelaxMaker()
self.def_maker.supercell_matrix = self.supercell_matrix
self.def_maker.max_atoms = self.max_atoms
self.def_maker.min_atoms = self.min_atoms
self.def_maker.min_length = self.min_length
self.def_maker.force_diagonal = self.force_diagonal

def make(
self,
defects: Iterable[Defect],
charges: bool | Iterable[int] = False,
dielectric: NDArray | int | float | None = None,
prev_cp2k_dir: str | Path | None = None,
collect_outputs: bool = True,
):
"""Make a flow to run multiple defects in order to calculate their formation
energy diagram.

Parameters
----------
defects: list[Defect]
List of defects objects to calculate the formation energy diagram for.
prev_cp2k_dir: str | Path | None
If provided, this acts as prev_dir for the bulk calculation only
Returns
-------
flow: Flow
The workflow to calculate the formation energy diagram.
"""
jobs = []
defect_outputs: dict[str, dict[int, tuple[Defect, OutputReference]]] = {
defect.name: {} for defect in defects
} # TODO DEFECT NAMES ARE NOT UNIQUE HASHES
bulk_structure = ensure_defects_same_structure(defects)

sc_mat = (
self.supercell_matrix
if self.supercell_matrix
else get_sc_fromstruct(
bulk_structure,
self.min_atoms,
self.max_atoms,
self.min_length,
self.force_diagonal,
)
)

if self.run_bulk:
s = bulk_structure.copy()
s.make_supercell(sc_mat)
bulk_job = self.bulk_maker.make(
bulk_structure * sc_mat, prev_cp2k_dir=prev_cp2k_dir
)
jobs.append(bulk_job)

for defect in defects:
if charges is True:
chgs = defect.get_charge_states()
else:
chgs = charges if charges else [0]
for charge in chgs:
dfct = deepcopy(defect)
dfct.user_charges = [charge]
defect_job = self.def_maker.make(dfct)
jobs.append(defect_job)
defect_outputs[defect.name][int(charge)] = (defect, defect_job.output)

if self.run_bulk and defects and collect_outputs:
collect_job = collect_defect_outputs(
defect_outputs=defect_outputs,
bulk_output=bulk_job.output if self.run_bulk else None,
dielectric=dielectric,
)
jobs.append(collect_job)
else:
collect_job = None
return Flow(
jobs=jobs,
name=self.name,
output=jobs[-1].output if collect_job else None,
)


# TODO this is totally code agnostic and should be in common
@job
def collect_defect_outputs(
defect_outputs: Mapping[str, Mapping[int, OutputReference]],
bulk_output: OutputReference,
dielectric: NDArray | int | float | None,
) -> dict:
"""Collect all the outputs from the defect calculations.
This job will combine the structure and entry fields to create a
ComputerStructureEntry object.
Parameters
----------
defects_output:
The output from the defect calculations.
bulk_sc_dir:
The directory containing the bulk supercell calculation.
dielectric:
The dielectric constant used to construct the formation energy diagram.
"""
outputs: dict[str, dict[str, dict]] = {"results": {}}
if not dielectric:
logger.warn(
"Dielectric constant not provided. Defect formation energies will be uncorrected."
)
for defect_name, defects_with_charges in defect_outputs.items():
defect_entries = []
fnv_plots = {}
for charge, defect_and_output in defects_with_charges.items():
defect, output_with_charge = defect_and_output
logger.info(f"Processing {defect_name} with charge state={charge}")
defect_entry = DefectEntry(
defect=defect,
charge_state=charge,
sc_entry=ComputedStructureEntry(
structure=bulk_output.structure,
energy=output_with_charge.output.energy - bulk_output.output.energy,
),
)
defect_entries.append(defect_entry)
plot_data = defect_entry.get_freysoldt_correction(
defect_locpot=VolumetricData.from_dict(
output_with_charge.cp2k_objects["v_hartree"]
),
bulk_locpot=VolumetricData.from_dict(
output_with_charge.cp2k_objects["v_hartree"]
),
dielectric=dielectric,
)
fnv_plots[int(charge)] = plot_data
outputs["results"][defect_name] = dict(
defect=defect, defect_entries=defect_entries, fnv_plots=fnv_plots
)
return outputs


# TODO should be in common
def ensure_defects_same_structure(defects: Iterable[Defect]):
"""Ensure that the defects are valid.
Parameters
----------
defects
The defects to check.
Raises
------
ValueError
If any defect is invalid.
"""
struct = None
for defect in defects:
if struct is None:
struct = defect.structure
elif struct != defect.structure:
raise ValueError("All defects must have the same host structure.")
return struct
Loading
Loading