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

Improve types for electronic_structure.{bandstructure/cohp} #3873

Merged
merged 63 commits into from
Aug 3, 2024
Merged
Changes from 1 commit
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
2a55e45
add types for bandstructure
DanielYang59 Jun 10, 2024
6444064
Merge branch 'master' into type-elec-struct
DanielYang59 Jun 10, 2024
1cd0037
relocate magic methods to top
DanielYang59 Jun 10, 2024
79e8868
add some types
DanielYang59 Jun 10, 2024
d00912c
Merge branch 'type-elec-struct' of https://github.com/DanielYang59/py…
DanielYang59 Jun 10, 2024
8a4c4b5
fix type errors in bandstructure
DanielYang59 Jun 10, 2024
51ffc18
temp save
DanielYang59 Jun 11, 2024
0298442
Merge branch 'master' into type-elec-struct
DanielYang59 Jun 11, 2024
09d62ad
Merge branch 'master' into type-elec-struct
DanielYang59 Jun 12, 2024
0d0615c
first run of cohp, mypy errors to fix
DanielYang59 Jun 12, 2024
319dfa8
fix collection generation
DanielYang59 Jun 12, 2024
a29ef98
add type `SpinLike` and case tweaks
DanielYang59 Jun 12, 2024
d47008c
reduce repetition for `__str__` of `IcohpValue`
DanielYang59 Jun 12, 2024
0407f52
simplify condition
DanielYang59 Jun 12, 2024
3dd5d7c
reduce indentation level
DanielYang59 Jun 12, 2024
0e75e0d
clarify `translation`
DanielYang59 Jun 12, 2024
b7c03da
clarify `list_num` and other docstrings
DanielYang59 Jun 12, 2024
7732736
clarify `label` as str
DanielYang59 Jun 12, 2024
aaf9f29
more type and docstring improvements
DanielYang59 Jun 12, 2024
950eb10
fix unit test
DanielYang59 Jun 12, 2024
5a2ec9f
fix most mypy errors
DanielYang59 Jun 12, 2024
0afb7c2
fix remaining mypy errors
DanielYang59 Jun 12, 2024
5fcf236
add DEBUG tag
DanielYang59 Jun 12, 2024
796c379
reduce code repetition
DanielYang59 Jun 12, 2024
9551db2
Need Confirm: set `translation` as tuple
DanielYang59 Jun 12, 2024
c188030
pre-commit auto-fixes
pre-commit-ci[bot] Jun 12, 2024
e21c5ed
more type clarify
DanielYang59 Jun 12, 2024
3ae88d0
Merge branch 'master' into type-elec-struct
DanielYang59 Jun 13, 2024
5b81360
clarify `num` argument
DanielYang59 Jun 13, 2024
5f760df
clarify docstring of `bandstructure`
DanielYang59 Jun 13, 2024
e558ac7
more minor tweaks
DanielYang59 Jun 13, 2024
4c0bb04
clarify type of labels_dict
DanielYang59 Jun 13, 2024
8e25238
replace unnecessary single-item list extend with append
DanielYang59 Jun 13, 2024
00b7134
fix typo
DanielYang59 Jun 13, 2024
952e206
relocate magic method
DanielYang59 Jun 13, 2024
4ee908d
clarify type of `list_icohp`
DanielYang59 Jun 13, 2024
3aef211
remove unused type alias
DanielYang59 Jun 13, 2024
61379c1
revert undesired rename
DanielYang59 Jun 14, 2024
92e7df8
replace more single item extend with append
DanielYang59 Jun 14, 2024
c397e1c
simplify dict generation
DanielYang59 Jun 14, 2024
8cfaa33
fix downstream lobsterpy error
DanielYang59 Jun 14, 2024
4641d88
Merge branch 'master' into type-elec-struct
DanielYang59 Jun 15, 2024
60f9aa6
Merge branch 'master' into type-elec-struct
DanielYang59 Jun 15, 2024
5eefb53
tweak module docstring
DanielYang59 Jun 16, 2024
132b9bb
Merge branch 'master' into type-elec-struct
DanielYang59 Jun 16, 2024
bbfbaa2
Merge branch 'master' into type-elec-struct
DanielYang59 Jun 17, 2024
629b480
Merge branch 'master' into type-elec-struct
DanielYang59 Jun 18, 2024
9cd7df8
Merge branch 'master' into type-elec-struct
DanielYang59 Jun 19, 2024
7200a3a
Merge branch 'master' into type-elec-struct
DanielYang59 Jun 19, 2024
c3fe9c6
merge master
DanielYang59 Jun 22, 2024
eb36650
need confirm: allow efermi to be None
DanielYang59 Jun 22, 2024
61bc066
Merge branch 'master' into type-elec-struct
DanielYang59 Jun 26, 2024
94ea368
Merge branch 'master' into type-elec-struct
DanielYang59 Jun 26, 2024
1da7359
Merge branch 'master' into type-elec-struct
DanielYang59 Jul 2, 2024
220a398
pre-commit auto-fixes
pre-commit-ci[bot] Jul 2, 2024
6a8abba
Merge branch 'master' into type-elec-struct
DanielYang59 Jul 12, 2024
db89e19
Merge branch 'master' into type-elec-struct
DanielYang59 Jul 15, 2024
217144a
Merge branch 'master' into type-elec-struct
DanielYang59 Jul 17, 2024
84b7313
Merge branch 'master' into type-elec-struct
DanielYang59 Jul 18, 2024
480699b
Merge branch 'master' into type-elec-struct
DanielYang59 Jul 24, 2024
662f653
Merge branch 'master' into type-elec-struct
DanielYang59 Jul 28, 2024
3e59252
Merge branch 'master' into type-elec-struct
DanielYang59 Jul 31, 2024
03c0612
Merge branch 'master' into type-elec-struct
DanielYang59 Aug 3, 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
98 changes: 41 additions & 57 deletions pymatgen/electronic_structure/cohp.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,16 @@

if TYPE_CHECKING:
from collections.abc import Sequence
from typing import Any, Literal
from typing import Any, Literal, Union

from numpy.typing import NDArray
from typing_extensions import Self

from pymatgen.util.typing import PathLike, SpinLike

# TODO: double check and clarify this custom type
CohpLabel = Union[str, int]

__author__ = "Marco Esters, Janine George"
__copyright__ = "Copyright 2017, The Materials Project"
__version__ = "0.2"
Expand Down Expand Up @@ -323,16 +326,16 @@ def as_dict(self) -> dict[str, Any]:
dct["ICOHP"] = {"average": {str(spin): pops.tolist() for spin, pops in self.icohp.items()}}

for label in self.all_cohps:
dct["COHP"].update({label: {str(spin): pops.tolist() for spin, pops in self.all_cohps[label].cohp.items()}})
dct["COHP"] |= {label: {str(spin): pops.tolist() for spin, pops in self.all_cohps[label].cohp.items()}}
if self.all_cohps[label].icohp is not None:
if "ICOHP" not in dct:
dct["ICOHP"] = {
label: {str(spin): pops.tolist() for spin, pops in self.all_cohps[label].icohp.items()}
}
else:
dct["ICOHP"].update(
{label: {str(spin): pops.tolist() for spin, pops in self.all_cohps[label].icohp.items()}}
)
dct["ICOHP"] |= {
label: {str(spin): pops.tolist() for spin, pops in self.all_cohps[label].icohp.items()}
}

if False in [bond_dict == {} for bond_dict in self.bonds.values()]:
dct["bonds"] = {
Expand Down Expand Up @@ -360,13 +363,13 @@ def as_dict(self) -> dict[str, Any]:

def get_cohp_by_label(
self,
label: str | float, # TODO (DanielYang): double-check type of label, perhaps add custom type
label: CohpLabel,
summed_spin_channels: bool = False,
) -> Cohp:
"""Get specific Cohp object by label.

Args:
label: string (for newer LOBSTER versions: a number) # TODO: check arg label type
label: string (for newer LOBSTER versions: int)
summed_spin_channels (bool): Sum the spin channels and return the sum in Spin.up.

Returns:
Expand Down Expand Up @@ -523,7 +526,7 @@ def get_summed_cohp_by_label_and_orbital_list(

def get_orbital_resolved_cohp(
self,
label: str | float,
label: CohpLabel,
orbitals: str | list | tuple,
summed_spin_channels: bool = False,
) -> Cohp | None:
Expand Down Expand Up @@ -597,7 +600,7 @@ def get_orbital_resolved_cohp(
def from_dict(cls, dct: dict[str, Any]) -> Self:
"""Get CompleteCohp object from dict representation.

TODO: clean that up
TODO: clean this up
"""
cohp_dict = {}
efermi = dct["efermi"]
Expand Down Expand Up @@ -719,10 +722,7 @@ def from_file(
are_cobis: bool = False,
are_multi_center_cobis: bool = False,
) -> Self:
"""
Create a CompleteCohp object from an output file of a COHP
calculation. Valid formats are either LMTO (for the Stuttgart
LMTO-ASA code) or LOBSTER (for the LOBSTER code).
"""Create CompleteCohp from an output file of a COHP calculation.

Args:
fmt (Literal["LMTO", "LOBSTER"]): The code used to calculate COHPs.
Expand Down Expand Up @@ -916,25 +916,25 @@ class IcohpValue(MSONable):
"""Information for an ICOHP or ICOOP value.

Attributes:
energies (ndarray): Energy values for the COHP/ICOHP/COOP/ICOOP.
densities (ndarray): Density of states values for the COHP/ICOHP/COOP/ICOOP.
energies_are_cartesian (bool): Whether the energies are cartesian or not.
are_coops (bool): Whether the object is a COOP/ICOOP or not.
are_cobis (bool): Whether the object is a COBIS/ICOBIS or not.
icohp (dict): A dictionary of the ICOHP/COHP values. The keys are Spin.up and Spin.down.
energies (NDArray): Energy values for the COHP/ICOHP/COOP/ICOOP.
densities (NDArray): Density of states for the COHP/ICOHP/COOP/ICOOP.
energies_are_cartesian (bool): Whether the energies are cartesian.
are_coops (bool): Whether the object is COOP/ICOOP.
are_cobis (bool): Whether the object is COBIS/ICOBIS.
icohp (dict): The ICOHP/COHP values, whose keys are Spin.up and Spin.down.
summed_icohp (float): The summed ICOHP/COHP values.
num_bonds (int): The number of bonds used for the average COHP (relevant for LOBSTER versions <3.0).
num_bonds (int): The number of bonds used for the average COHP (for LOBSTER versions <3.0).
"""

def __init__(
self,
label: str | float,
label: CohpLabel,
atom1: str,
atom2: str,
length: float,
translation,
translation, # TODO: DanielYang: use tuple3float?
num: int,
icohp,
icohp: dict, # more specific type
are_coops: bool = False,
are_cobis: bool = False,
orbitals: dict | None = None, # TODO: DanielYang: more specific type
Expand All @@ -945,8 +945,8 @@ def __init__(
atom1 (str): The first atom that contributes to the bond.
atom2 (str): The second atom that contributes to the bond.
length (float): Bond length.
translation: translation list, e.g. [0, 0, 0]. # TODO: DanielYang: use tuple3float?
num (int): How often the bond exists.
translation: translation list, e.g. [0, 0, 0].
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's a bit unclear to me what is translation? Is it a 3D vector?

Copy link
Member

Choose a reason for hiding this comment

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

Same wording is used as in Lobster. It describes the unit cell in which the atom is in. [0 0 0] is the normal cell, but the atom might be translated to the neighboring cell

Copy link
Contributor Author

@DanielYang59 DanielYang59 Jun 12, 2024

Choose a reason for hiding this comment

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

Thanks for clarifying! I just searched the wrong documentation ;) I searched Lobster_FAQ_5.0.0 instead of Lobster_Users_Guide_5.0.0.

If atoms are not located in the original unit cell, the corresponding translation vector can be added by the keyword "cell" like this:
cobiBetween atom 1 atom 2 atom 3 cell 1 0 0

Update: clarified in 0e75e0d

num (int): How often the bond exists. # TODO: DanielYang: clarify this description
DanielYang59 marked this conversation as resolved.
Show resolved Hide resolved
icohp: dict={Spin.up: IcohpValue for spin.up, Spin.down: IcohpValue for spin.down}
are_coops (bool): If True, this are COOPs
are_cobis (bool): If True, this are COBIs
Expand All @@ -971,40 +971,24 @@ def __init__(
def __str__(self) -> str:
DanielYang59 marked this conversation as resolved.
Show resolved Hide resolved
"""String representation of the ICOHP/ICOOP."""
if not self._are_coops and not self._are_cobis:
if self._is_spin_polarized:
return (
f"ICOHP {self._label} between {self._atom1} and {self._atom2} ({self._translation}): "
f"{self._icohp[Spin.up]} eV (Spin up) and {self._icohp[Spin.down]} eV (Spin down)"
)
return (
f"ICOHP {self._label} between {self._atom1} and {self._atom2} ({self._translation}): "
f"{self._icohp[Spin.up]} eV (Spin up)"
)
header = "ICOHP"
elif self._are_coops and not self._are_cobis:
header = "ICOOP"
else:
header = "ICOBI"

if self._are_coops and not self._are_cobis:
if self._is_spin_polarized:
return (
f"ICOOP {self._label} between {self._atom1} and {self._atom2} ({self._translation}): "
f"{self._icohp[Spin.up]} eV (Spin up) and {self._icohp[Spin.down]} eV (Spin down)"
)
if self._is_spin_polarized:
return (
f"ICOOP {self._label} between {self._atom1} and {self._atom2} ({self._translation}): "
f"{self._icohp[Spin.up]} eV (Spin up)"
f"{header} {self._label} between {self._atom1} and {self._atom2} ({self._translation}): "
f"{self._icohp[Spin.up]} eV (Spin up) and {self._icohp[Spin.down]} eV (Spin down)"
)

if not self._are_coops and self._are_cobis:
if self._is_spin_polarized:
return (
f"ICOBI {self._label} between {self._atom1} and {self._atom2} ({self._translation}): "
f"{self._icohp[Spin.up]} eV (Spin up) and {self._icohp[Spin.down]} eV (Spin down)"
)
else:
return (
f"ICOBI {self._label} between {self._atom1} and {self._atom2} ({self._translation}): "
f"{header} {self._label} between {self._atom1} and {self._atom2} ({self._translation}): "
f"{self._icohp[Spin.up]} eV (Spin up)"
)

return ""

@property
def num_bonds(self) -> int:
"""The number of bonds for which the ICOHP value is an average.
Expand All @@ -1016,7 +1000,7 @@ def num_bonds(self) -> int:

@property
def are_coops(self) -> bool:
"""Whether is ICOOPs.
"""Whether are ICOOPs.

Returns:
bool
Expand All @@ -1025,7 +1009,7 @@ def are_coops(self) -> bool:

@property
def are_cobis(self) -> bool:
"""Whether is ICOBIs.
"""Whether are ICOBIs.

Returns:
bool
Expand Down Expand Up @@ -1081,7 +1065,7 @@ def icohp(self) -> dict[Spin, IcohpValue]:

@property
def summed_icohp(self) -> float:
"""Sum ICOHPs of both spin channels for spin polarized compounds.
"""Summed ICOHPs of both spin channels if spin polarized.

Returns:
float: ICOHP value in eV.
Expand All @@ -1090,7 +1074,7 @@ def summed_icohp(self) -> float:

@property
def summed_orbital_icohp(self) -> dict[str, float]:
"""Sum orbital-resolved ICOHPs of both spin channels for spin-polarized compounds.
"""Summed orbital-resolved ICOHPs of both spin channels if spin-polarized.

Returns:
dict[str, float]: "str(Orbital1)-str(Ortibal2)" mapped to ICOHP value in eV.
Expand Down Expand Up @@ -1176,7 +1160,7 @@ def __str__(self) -> str:

def get_icohp_by_label(
self,
label: str,
label: CohpLabel,
summed_spin_channels: bool = True,
spin: Spin = Spin.up,
orbitals: str | list[Orbital] | None = None, # TODO: change to tuple of 2
Expand Down Expand Up @@ -1365,7 +1349,7 @@ def are_cobis(self) -> bool:

def get_integrated_cohp_in_energy_range(
cohp: CompleteCohp,
label: str | float,
label: CohpLabel,
orbital: Orbital | None = None,
energy_range: float | list[float] | None = None,
relative_E_Fermi: bool = True,
Expand Down
Loading